summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /drivers
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acorn/block/fd1772.c8
-rw-r--r--drivers/acorn/block/mfmhd.c6
-rw-r--r--drivers/acorn/char/keyb_ps2.c3
-rw-r--r--drivers/acorn/net/ether1.c214
-rw-r--r--drivers/acorn/net/ether1.h7
-rw-r--r--drivers/acorn/net/ether3.c224
-rw-r--r--drivers/acorn/net/ether3.h9
-rw-r--r--drivers/acorn/net/etherh.c61
-rw-r--r--drivers/block/Config.in4
-rw-r--r--drivers/block/DAC960.c68
-rw-r--r--drivers/block/Makefile15
-rw-r--r--drivers/block/README.lvm8
-rw-r--r--drivers/block/acsi.c24
-rw-r--r--drivers/block/acsi_slm.c13
-rw-r--r--drivers/block/amiflop.c4
-rw-r--r--drivers/block/ataflop.c10
-rw-r--r--drivers/block/cpqarray.c17
-rw-r--r--drivers/block/cs5530.c4
-rw-r--r--drivers/block/floppy.c83
-rw-r--r--drivers/block/genhd.c2
-rw-r--r--drivers/block/hd.c20
-rw-r--r--drivers/block/icside.c2
-rw-r--r--drivers/block/ide-cd.c8
-rw-r--r--drivers/block/ide-disk.c11
-rw-r--r--drivers/block/ide-dma.c11
-rw-r--r--drivers/block/ide-floppy.c9
-rw-r--r--drivers/block/ide-probe.c21
-rw-r--r--drivers/block/ide-tape.c22
-rw-r--r--drivers/block/ide.c49
-rw-r--r--drivers/block/ll_rw_blk.c396
-rw-r--r--drivers/block/loop.c342
-rw-r--r--drivers/block/lvm-snap.c434
-rw-r--r--drivers/block/lvm.c2556
-rw-r--r--drivers/block/md.c14
-rw-r--r--drivers/block/nbd.c82
-rw-r--r--drivers/block/paride/pcd.c2
-rw-r--r--drivers/block/paride/pd.c18
-rw-r--r--drivers/block/paride/pf.c6
-rw-r--r--drivers/block/paride/pg.c13
-rw-r--r--drivers/block/paride/pt.c17
-rw-r--r--drivers/block/ps2esdi.c24
-rw-r--r--drivers/block/raid1.c12
-rw-r--r--drivers/block/rd.c45
-rw-r--r--drivers/block/swim3.c2
-rw-r--r--drivers/block/swim_iop.c2
-rw-r--r--drivers/block/xd.c36
-rw-r--r--drivers/cdrom/aztcd.c11
-rw-r--r--drivers/cdrom/cdrom.c33
-rw-r--r--drivers/cdrom/cdu31a.c11
-rw-r--r--drivers/cdrom/cm206.c7
-rw-r--r--drivers/cdrom/gscd.c14
-rw-r--r--drivers/cdrom/mcd.c7
-rw-r--r--drivers/cdrom/mcdx.c11
-rw-r--r--drivers/cdrom/optcd.c13
-rw-r--r--drivers/cdrom/sbpcd.c43
-rw-r--r--drivers/cdrom/sjcd.c11
-rw-r--r--drivers/cdrom/sonycd535.c14
-rw-r--r--drivers/char/Config.in2
-rw-r--r--drivers/char/Makefile18
-rw-r--r--drivers/char/agp/agp.h2
-rw-r--r--drivers/char/amikeyb.c7
-rw-r--r--drivers/char/amiserial.c2264
-rw-r--r--drivers/char/console.c161
-rw-r--r--drivers/char/dsp56k.c13
-rw-r--r--drivers/char/dtlk.c12
-rw-r--r--drivers/char/dz.c1
-rw-r--r--drivers/char/esp.c22
-rw-r--r--drivers/char/ftape/lowlevel/ftape-buffer.c18
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c59
-rw-r--r--drivers/char/h8.c10
-rw-r--r--drivers/char/isicom.c3
-rw-r--r--drivers/char/istallion.c17
-rw-r--r--drivers/char/joystick/joystick.c20
-rw-r--r--drivers/char/keyboard.c3
-rw-r--r--drivers/char/lp.c191
-rw-r--r--drivers/char/mac_SCC.c1529
-rw-r--r--drivers/char/mac_SCC.h321
-rw-r--r--drivers/char/mem.c48
-rw-r--r--drivers/char/misc.c16
-rw-r--r--drivers/char/nvram.c2
-rw-r--r--drivers/char/pc_keyb.c9
-rw-r--r--drivers/char/pcxx.c1
-rw-r--r--drivers/char/ppdev.c13
-rw-r--r--drivers/char/pty.c23
-rw-r--r--drivers/char/rtc.c30
-rw-r--r--drivers/char/serial.c30
-rw-r--r--drivers/char/serial167.c2
-rw-r--r--drivers/char/stallion.c15
-rw-r--r--drivers/char/sysrq.c3
-rw-r--r--drivers/char/tpqic02.c69
-rw-r--r--drivers/char/tty_io.c127
-rw-r--r--drivers/char/vc_screen.c473
-rw-r--r--drivers/char/videodev.c20
-rw-r--r--drivers/char/vme_scc.c1
-rw-r--r--drivers/char/vt.c12
-rw-r--r--drivers/char/zr36120_mem.c15
-rw-r--r--drivers/fc4/fc.c68
-rw-r--r--drivers/i2o/i2o_block.c5
-rw-r--r--drivers/ieee1394/hosts.c27
-rw-r--r--drivers/ieee1394/hosts.h11
-rw-r--r--drivers/ieee1394/ieee1394_core.c94
-rw-r--r--drivers/ieee1394/ieee1394_syms.c6
-rw-r--r--drivers/ieee1394/ohci1394.c1754
-rw-r--r--drivers/ieee1394/ohci1394.h136
-rw-r--r--drivers/ieee1394/pcilynx.h8
-rw-r--r--drivers/ieee1394/raw1394.c11
-rw-r--r--drivers/isdn/Config.in127
-rw-r--r--drivers/isdn/Makefile6
-rw-r--r--drivers/isdn/avmb1/Makefile11
-rw-r--r--drivers/isdn/avmb1/avmcard.h31
-rw-r--r--drivers/isdn/avmb1/b1.c16
-rw-r--r--drivers/isdn/avmb1/b1dma.c984
-rw-r--r--drivers/isdn/avmb1/b1isa.c41
-rw-r--r--drivers/isdn/avmb1/b1pci.c295
-rw-r--r--drivers/isdn/avmb1/b1pcmcia.c36
-rw-r--r--drivers/isdn/avmb1/c4.c1326
-rw-r--r--drivers/isdn/avmb1/capi.c58
-rw-r--r--drivers/isdn/avmb1/capidrv.c47
-rw-r--r--drivers/isdn/avmb1/kcapi.c120
-rw-r--r--drivers/isdn/avmb1/t1isa.c28
-rw-r--r--drivers/isdn/avmb1/t1pci.c964
-rw-r--r--drivers/isdn/divert/divert_procfs.c474
-rw-r--r--drivers/isdn/eicon/eicon.h32
-rw-r--r--drivers/isdn/eicon/eicon_dsp.h12
-rw-r--r--drivers/isdn/eicon/eicon_idi.c224
-rw-r--r--drivers/isdn/eicon/eicon_idi.h21
-rw-r--r--drivers/isdn/eicon/eicon_io.c23
-rw-r--r--drivers/isdn/eicon/eicon_isa.c111
-rw-r--r--drivers/isdn/eicon/eicon_isa.h18
-rw-r--r--drivers/isdn/eicon/eicon_mod.c87
-rw-r--r--drivers/isdn/eicon/eicon_pci.c16
-rw-r--r--drivers/isdn/eicon/eicon_pci.h12
-rw-r--r--drivers/isdn/hisax/Makefile4
-rw-r--r--drivers/isdn/hisax/arcofi.c17
-rw-r--r--drivers/isdn/hisax/arcofi.h7
-rw-r--r--drivers/isdn/hisax/asuscom.c12
-rw-r--r--drivers/isdn/hisax/avm_pci.c37
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c16
-rw-r--r--drivers/isdn/hisax/bkm_a8.c12
-rw-r--r--drivers/isdn/hisax/callc.c584
-rw-r--r--drivers/isdn/hisax/config.c38
-rw-r--r--drivers/isdn/hisax/diva.c20
-rw-r--r--drivers/isdn/hisax/elsa.c14
-rw-r--r--drivers/isdn/hisax/fsm.c7
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c7
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.h7
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c186
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.h7
-rw-r--r--drivers/isdn/hisax/hfc_pci.c65
-rw-r--r--drivers/isdn/hisax/hfc_sx.c1583
-rw-r--r--drivers/isdn/hisax/hfc_sx.h216
-rw-r--r--drivers/isdn/hisax/hfcscard.c14
-rw-r--r--drivers/isdn/hisax/hisax.h63
-rw-r--r--drivers/isdn/hisax/hscx.h7
-rw-r--r--drivers/isdn/hisax/ipac.h7
-rw-r--r--drivers/isdn/hisax/isac.h7
-rw-r--r--drivers/isdn/hisax/isar.c700
-rw-r--r--drivers/isdn/hisax/isar.h36
-rw-r--r--drivers/isdn/hisax/isdnl1.c27
-rw-r--r--drivers/isdn/hisax/isurf.c12
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c8
-rw-r--r--drivers/isdn/hisax/l3dss1.c79
-rw-r--r--drivers/isdn/hisax/l3dss1.h7
-rw-r--r--drivers/isdn/hisax/netjet.c12
-rw-r--r--drivers/isdn/hisax/rawhdlc.c4
-rw-r--r--drivers/isdn/hisax/saphir.c12
-rw-r--r--drivers/isdn/hisax/sedlbauer.c31
-rw-r--r--drivers/isdn/hisax/sportster.c17
-rw-r--r--drivers/isdn/hisax/teleint.c12
-rw-r--r--drivers/isdn/hisax/teles0.c9
-rw-r--r--drivers/isdn/hisax/teles3.c22
-rw-r--r--drivers/isdn/hisax/telespci.c9
-rw-r--r--drivers/isdn/hysdn/.cvsignore2
-rw-r--r--drivers/isdn/hysdn/Makefile24
-rw-r--r--drivers/isdn/hysdn/boardergo.c467
-rw-r--r--drivers/isdn/hysdn/boardergo.h117
-rw-r--r--drivers/isdn/hysdn/hysdn_boot.c420
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h229
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c243
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c378
-rw-r--r--drivers/isdn/hysdn/hysdn_pof.h95
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c485
-rw-r--r--drivers/isdn/hysdn/hysdn_procfs.c502
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c481
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c202
-rw-r--r--drivers/isdn/hysdn/ince1pc.h132
-rw-r--r--drivers/isdn/isdn_common.c229
-rw-r--r--drivers/isdn/isdn_common.h7
-rw-r--r--drivers/isdn/isdn_net.c320
-rw-r--r--drivers/isdn/isdn_ppp.c35
-rw-r--r--drivers/isdn/isdn_tty.c108
-rw-r--r--drivers/isdn/isdn_tty.h14
-rw-r--r--drivers/isdn/isdn_ttyfax.c1118
-rw-r--r--drivers/macintosh/Makefile4
-rw-r--r--drivers/macintosh/adb-iop.c283
-rw-r--r--drivers/macintosh/adb.c8
-rw-r--r--drivers/macintosh/mac_keyb.c5
-rw-r--r--drivers/macintosh/macserial.c1
-rw-r--r--drivers/macintosh/via-macii.c679
-rw-r--r--drivers/macintosh/via-maciisi.c486
-rw-r--r--drivers/macintosh/via-pmu68k.c1063
-rw-r--r--drivers/net/3c505.c183
-rw-r--r--drivers/net/3c505.h1
-rw-r--r--drivers/net/3c507.c99
-rw-r--r--drivers/net/3c509.c17
-rw-r--r--drivers/net/3c515.c1195
-rw-r--r--drivers/net/3c523.c6
-rw-r--r--drivers/net/3c527.c4
-rw-r--r--drivers/net/3c59x.c41
-rw-r--r--drivers/net/8139too.c1879
-rw-r--r--drivers/net/82596.c135
-rw-r--r--drivers/net/8390.c21
-rw-r--r--drivers/net/Config.in51
-rw-r--r--drivers/net/Makefile17
-rw-r--r--drivers/net/Space.c4
-rw-r--r--drivers/net/a2065.c147
-rw-r--r--drivers/net/acenic.c1112
-rw-r--r--drivers/net/acenic.h175
-rw-r--r--drivers/net/acenic_firmware.h8499
-rw-r--r--drivers/net/arcnet/arc-rimi.c13
-rw-r--r--drivers/net/arcnet/arcnet.c137
-rw-r--r--drivers/net/arcnet/com20020-isa.c7
-rw-r--r--drivers/net/arcnet/com20020-pci.c8
-rw-r--r--drivers/net/arcnet/com90io.c11
-rw-r--r--drivers/net/arcnet/com90xx.c45
-rw-r--r--drivers/net/arcnet/rfc1201.c8
-rw-r--r--drivers/net/ariadne.c20
-rw-r--r--drivers/net/at1700.c177
-rw-r--r--drivers/net/atp.c258
-rw-r--r--drivers/net/atp.h6
-rw-r--r--drivers/net/bmac.c327
-rw-r--r--drivers/net/cops.c166
-rw-r--r--drivers/net/cs89x0.c159
-rw-r--r--drivers/net/de4x5.c53
-rw-r--r--drivers/net/de600.c38
-rw-r--r--drivers/net/de620.c134
-rw-r--r--drivers/net/defxx.c50
-rw-r--r--drivers/net/depca.c200
-rw-r--r--drivers/net/dmfe.c58
-rw-r--r--drivers/net/eepro.c10
-rw-r--r--drivers/net/eepro100.c852
-rw-r--r--drivers/net/eexpress.c105
-rw-r--r--drivers/net/epic100.c697
-rw-r--r--drivers/net/eth16i.c347
-rw-r--r--drivers/net/ewrk3.c342
-rw-r--r--drivers/net/fc/iph5526.c94
-rw-r--r--drivers/net/fmv18x.c215
-rw-r--r--drivers/net/gmac.c106
-rw-r--r--drivers/net/hamradio/6pack.c143
-rw-r--r--drivers/net/hamradio/baycom_epp.c202
-rw-r--r--drivers/net/hamradio/baycom_par.c64
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c29
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c25
-rw-r--r--drivers/net/hamradio/bpqether.c41
-rw-r--r--drivers/net/hamradio/dmascc.c43
-rw-r--r--drivers/net/hamradio/hdlcdrv.c91
-rw-r--r--drivers/net/hamradio/scc.c133
-rw-r--r--drivers/net/hamradio/soundmodem/sm.c31
-rw-r--r--drivers/net/hamradio/yam.c27
-rw-r--r--drivers/net/hydra.c9
-rw-r--r--drivers/net/ioc3-eth.c3
-rw-r--r--drivers/net/irda/irport.c71
-rw-r--r--drivers/net/irda/irtty.c26
-rw-r--r--drivers/net/irda/nsc-ircc.c40
-rw-r--r--drivers/net/irda/toshoboe.c35
-rw-r--r--drivers/net/irda/w83977af_ir.c35
-rw-r--r--drivers/net/lance.c128
-rw-r--r--drivers/net/ltpc.c18
-rw-r--r--drivers/net/mace.c110
-rw-r--r--drivers/net/myri_sbus.c18
-rw-r--r--drivers/net/ncr885e.c46
-rw-r--r--drivers/net/ne2.c15
-rw-r--r--drivers/net/net_init.c4
-rw-r--r--drivers/net/ni5010.c98
-rw-r--r--drivers/net/ni52.c138
-rw-r--r--drivers/net/ni65.c82
-rw-r--r--drivers/net/pcmcia/3c574_cs.c199
-rw-r--r--drivers/net/pcmcia/3c575_cb.c250
-rw-r--r--drivers/net/pcmcia/3c589_cs.c89
-rw-r--r--drivers/net/pcmcia/Config.in1
-rw-r--r--drivers/net/pcmcia/Makefile4
-rw-r--r--drivers/net/pcmcia/aironet4500_cs.c15
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c124
-rw-r--r--drivers/net/pcmcia/netwave_cs.c86
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c100
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c29
-rw-r--r--drivers/net/pcmcia/ray_cs.c13
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c101
-rw-r--r--drivers/net/pcmcia/tulip_cb.c126
-rw-r--r--drivers/net/pcmcia/wavelan_cs.c224
-rw-r--r--drivers/net/pcmcia/wavelan_cs.h5
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c88
-rw-r--r--drivers/net/pcnet32.c6
-rw-r--r--drivers/net/plip.c49
-rw-r--r--drivers/net/ppp_generic.c12
-rw-r--r--drivers/net/rcpci45.c39
-rw-r--r--drivers/net/rtl8129.c (renamed from drivers/net/rtl8139.c)64
-rw-r--r--drivers/net/sb1000.c15
-rw-r--r--drivers/net/seeq8005.c95
-rw-r--r--drivers/net/setup.c8
-rw-r--r--drivers/net/sgiseeq.c5
-rw-r--r--drivers/net/sis900.c50
-rw-r--r--drivers/net/sk98lin/skge.c79
-rw-r--r--drivers/net/sk_g16.c39
-rw-r--r--drivers/net/sk_mca.c1428
-rw-r--r--drivers/net/skeleton.c5
-rw-r--r--drivers/net/skfp/.cvsignore10
-rw-r--r--drivers/net/skfp/Makefile39
-rw-r--r--drivers/net/skfp/can.c83
-rw-r--r--drivers/net/skfp/cfm.c642
-rw-r--r--drivers/net/skfp/drvfbi.c1612
-rw-r--r--drivers/net/skfp/ecm.c547
-rw-r--r--drivers/net/skfp/ess.c732
-rw-r--r--drivers/net/skfp/fplustm.c1645
-rw-r--r--drivers/net/skfp/h/cmtdef.h801
-rw-r--r--drivers/net/skfp/h/fddi.h69
-rw-r--r--drivers/net/skfp/h/fddimib.h349
-rw-r--r--drivers/net/skfp/h/fplustm.h274
-rw-r--r--drivers/net/skfp/h/hwmtm.h424
-rw-r--r--drivers/net/skfp/h/lnkstat.h84
-rw-r--r--drivers/net/skfp/h/mbuf.h54
-rw-r--r--drivers/net/skfp/h/osdef1st.h118
-rw-r--r--drivers/net/skfp/h/sba.h142
-rw-r--r--drivers/net/skfp/h/sba_def.h76
-rw-r--r--drivers/net/skfp/h/skfbi.h1920
-rw-r--r--drivers/net/skfp/h/skfbiinc.h123
-rw-r--r--drivers/net/skfp/h/smc.h471
-rw-r--r--drivers/net/skfp/h/smt.h882
-rw-r--r--drivers/net/skfp/h/smt_p.h326
-rw-r--r--drivers/net/skfp/h/smtstate.h100
-rw-r--r--drivers/net/skfp/h/supern_2.h1059
-rw-r--r--drivers/net/skfp/h/targethw.h173
-rw-r--r--drivers/net/skfp/h/targetos.h163
-rw-r--r--drivers/net/skfp/h/types.h48
-rw-r--r--drivers/net/skfp/hwmtm.c2261
-rw-r--r--drivers/net/skfp/hwt.c314
-rw-r--r--drivers/net/skfp/lnkstat.c209
-rw-r--r--drivers/net/skfp/pcmplc.c2094
-rw-r--r--drivers/net/skfp/pmf.c1701
-rw-r--r--drivers/net/skfp/queue.c185
-rw-r--r--drivers/net/skfp/rmt.c674
-rw-r--r--drivers/net/skfp/skfddi.c2495
-rw-r--r--drivers/net/skfp/smt.c2225
-rw-r--r--drivers/net/skfp/smtdef.c371
-rw-r--r--drivers/net/skfp/smtinit.c126
-rw-r--r--drivers/net/skfp/smtparse.c475
-rw-r--r--drivers/net/skfp/smttimer.c173
-rw-r--r--drivers/net/skfp/srf.c441
-rw-r--r--drivers/net/slip.c12
-rw-r--r--drivers/net/smc-mca.c5
-rw-r--r--drivers/net/smc-ultra.c3
-rw-r--r--drivers/net/smc-ultra32.c5
-rw-r--r--drivers/net/smc9194.c241
-rw-r--r--drivers/net/starfire.c22
-rw-r--r--drivers/net/strip.c28
-rw-r--r--drivers/net/sunbmac.c30
-rw-r--r--drivers/net/sunhme.c108
-rw-r--r--drivers/net/sunhme.h8
-rw-r--r--drivers/net/sunlance.c37
-rw-r--r--drivers/net/sunqe.c4
-rw-r--r--drivers/net/tlan.c43
-rw-r--r--drivers/net/tokenring/ibmtr.c77
-rw-r--r--drivers/net/tokenring/olympic.c37
-rw-r--r--drivers/net/tokenring/smctr.c65
-rw-r--r--drivers/net/tokenring/tms380tr.c73
-rw-r--r--drivers/net/tulip.c3205
-rw-r--r--drivers/net/via-rhine.c8
-rw-r--r--drivers/net/wan/cosa.c19
-rw-r--r--drivers/net/wan/cycx_x25.c62
-rw-r--r--drivers/net/wan/dlci.c67
-rw-r--r--drivers/net/wan/hostess_sv11.c7
-rw-r--r--drivers/net/wan/lapbether.c15
-rw-r--r--drivers/net/wan/sbni.c73
-rw-r--r--drivers/net/wan/sbni.h2
-rw-r--r--drivers/net/wan/sdla.c163
-rw-r--r--drivers/net/wan/sdla_chdlc.c3
-rw-r--r--drivers/net/wan/sdla_fr.c137
-rw-r--r--drivers/net/wan/sdla_ppp.c3
-rw-r--r--drivers/net/wan/sdla_x25.c62
-rw-r--r--drivers/net/wan/sealevel.c7
-rw-r--r--drivers/net/wan/x25_asy.c63
-rw-r--r--drivers/net/wan/z85230.c389
-rw-r--r--drivers/net/wan/z85230.h6
-rw-r--r--drivers/net/wavelan.c6044
-rw-r--r--drivers/net/yellowfin.c845
-rw-r--r--drivers/net/znet.c90
-rw-r--r--drivers/parport/parport_pc.c5
-rw-r--r--drivers/pci/pcisyms.c2
-rw-r--r--drivers/pcmcia/cs.c38
-rw-r--r--drivers/pcmcia/cs_internal.h2
-rw-r--r--drivers/pcmcia/i82365.c26
-rw-r--r--drivers/pcmcia/tcic.c21
-rw-r--r--drivers/sbus/audio/audio.c8
-rw-r--r--drivers/sbus/audio/cs4231.c66
-rw-r--r--drivers/sbus/audio/dbri.c31
-rw-r--r--drivers/sbus/char/bpp.c12
-rw-r--r--drivers/sbus/char/pcikbd.c5
-rw-r--r--drivers/sbus/char/sunkbd.c15
-rw-r--r--drivers/sbus/char/vfc.h3
-rw-r--r--drivers/sbus/char/vfc_dev.c15
-rw-r--r--drivers/sbus/dvma.c3
-rw-r--r--drivers/scsi/Config.in7
-rw-r--r--drivers/scsi/Makefile10
-rw-r--r--drivers/scsi/README.aic7xxx21
-rw-r--r--drivers/scsi/aha152x.c8
-rw-r--r--drivers/scsi/aic7xxx.c1240
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.reg3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.seq48
-rw-r--r--drivers/scsi/aic7xxx_proc.c22
-rw-r--r--drivers/scsi/aic7xxx_reg.h18
-rw-r--r--drivers/scsi/aic7xxx_seq.c466
-rw-r--r--drivers/scsi/constants.c30
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/eata_dma_proc.c2
-rw-r--r--drivers/scsi/esp.c26
-rw-r--r--drivers/scsi/fdomain.c4
-rw-r--r--drivers/scsi/hosts.c59
-rw-r--r--drivers/scsi/hosts.h40
-rw-r--r--drivers/scsi/mac_esp.c5
-rw-r--r--drivers/scsi/mac_scsi.c85
-rw-r--r--drivers/scsi/mesh.c4
-rw-r--r--drivers/scsi/mvme16x.c2
-rw-r--r--drivers/scsi/pci2000.c81
-rw-r--r--drivers/scsi/pci2000.h28
-rw-r--r--drivers/scsi/pci2220i.c1652
-rw-r--r--drivers/scsi/pci2220i.h286
-rw-r--r--drivers/scsi/pcmcia/.cvsignore10
-rw-r--r--drivers/scsi/pcmcia/Config.in23
-rw-r--r--drivers/scsi/pcmcia/Makefile67
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c437
-rw-r--r--drivers/scsi/pcmcia/apa1480_stub.c174
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c398
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c428
-rw-r--r--drivers/scsi/psi_dale.h498
-rw-r--r--drivers/scsi/qla1280.c5
-rw-r--r--drivers/scsi/qlogicfas.c3
-rw-r--r--drivers/scsi/qlogicfc.c19
-rw-r--r--drivers/scsi/qlogicpti.c17
-rw-r--r--drivers/scsi/scsi.c429
-rw-r--r--drivers/scsi/scsi.h112
-rw-r--r--drivers/scsi/scsi_error.c7
-rw-r--r--drivers/scsi/scsi_ioctl.c18
-rw-r--r--drivers/scsi/scsi_lib.c215
-rw-r--r--drivers/scsi/scsi_merge.c327
-rw-r--r--drivers/scsi/scsi_obsolete.c16
-rw-r--r--drivers/scsi/scsi_scan.c10
-rw-r--r--drivers/scsi/scsi_syms.c17
-rw-r--r--drivers/scsi/sd.c50
-rw-r--r--drivers/scsi/sg.c14
-rw-r--r--drivers/scsi/sr.c62
-rw-r--r--drivers/scsi/sr.h2
-rw-r--r--drivers/scsi/sr_ioctl.c63
-rw-r--r--drivers/scsi/sr_vendor.c12
-rw-r--r--drivers/scsi/st.c733
-rw-r--r--drivers/scsi/st.h9
-rw-r--r--drivers/scsi/sun3_NCR5380.c3012
-rw-r--r--drivers/scsi/sun3_scsi.c366
-rw-r--r--drivers/scsi/sun3_scsi.h262
-rw-r--r--drivers/sgi/char/shmiq.c12
-rw-r--r--drivers/sound/ac97_codec.c155
-rw-r--r--drivers/sound/ac97_codec.h9
-rw-r--r--drivers/sound/dmasound.c109
-rw-r--r--drivers/sound/es1370.c14
-rw-r--r--drivers/sound/es1371.c14
-rw-r--r--drivers/sound/esssolo1.c35
-rw-r--r--drivers/sound/sb_card.c417
-rw-r--r--drivers/sound/sonicvibes.c14
-rw-r--r--drivers/sound/sound_core.c97
-rw-r--r--drivers/sound/soundcard.c68
-rw-r--r--drivers/usb/Config.in10
-rw-r--r--drivers/usb/Makefile8
-rw-r--r--drivers/usb/acm.c43
-rw-r--r--drivers/usb/hid-debug.h27
-rw-r--r--drivers/usb/hid.c106
-rw-r--r--drivers/usb/hid.h3
-rw-r--r--drivers/usb/hub.c2
-rw-r--r--drivers/usb/inode.c1
-rw-r--r--drivers/usb/input.c2
-rw-r--r--drivers/usb/keybdev.c19
-rw-r--r--drivers/usb/plusb.c632
-rw-r--r--drivers/usb/plusb.h48
-rw-r--r--drivers/usb/printer.c12
-rw-r--r--drivers/usb/scanner.c130
-rw-r--r--drivers/usb/scanner.h2
-rw-r--r--drivers/usb/uhci-debug.h2
-rw-r--r--drivers/usb/usb-core.c33
-rw-r--r--drivers/usb/usb-serial.c248
-rw-r--r--drivers/usb/usb-serial.h108
-rw-r--r--drivers/usb/usb-storage-debug.h (renamed from drivers/usb/usb_storage_debug.c)24
-rw-r--r--drivers/usb/usb-storage.c (renamed from drivers/usb/usb_storage.c)40
-rw-r--r--drivers/usb/usb-storage.h (renamed from drivers/usb/usb_storage.h)0
-rw-r--r--drivers/usb/usb-uhci.c213
-rw-r--r--drivers/usb/usb-uhci.h5
-rw-r--r--drivers/usb/usb.c5
-rw-r--r--drivers/video/Config.in9
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/aty128fb.c32
-rw-r--r--drivers/video/atyfb.c8
-rw-r--r--drivers/video/bwtwofb.c6
-rw-r--r--drivers/video/cgsixfb.c4
-rw-r--r--drivers/video/fbcon-mac.c3
-rw-r--r--drivers/video/fbmem.c29
-rw-r--r--drivers/video/igafb.c8
-rw-r--r--drivers/video/macfb.c1431
-rw-r--r--drivers/video/matroxfb.c172
-rw-r--r--drivers/video/sun3fb.c729
507 files changed, 82517 insertions, 26869 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index def2731d2..1c99a05a7 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -52,7 +52,7 @@ SUB_DIRS += video
MOD_SUB_DIRS += video
endif
-ifdef CONFIG_PPC
+ifdef CONFIG_MAC
SUB_DIRS += macintosh
MOD_SUB_DIRS += macintosh
endif
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
index 54ed9ac6b..95836eb29 100644
--- a/drivers/acorn/block/fd1772.c
+++ b/drivers/acorn/block/fd1772.c
@@ -591,7 +591,7 @@ static void fd_error(void)
{
printk("FDC1772: fd_error\n");
/*panic("fd1772: fd_error"); *//* DAG tmp */
- if (!CURRENT)
+ if (QUEUE_EMPTY)
return;
CURRENT->errors++;
if (CURRENT->errors >= MAX_ERRORS) {
@@ -1230,14 +1230,14 @@ static void redo_fd_request(void)
DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->rq_dev=%04x CURRENT->sector=%ld\n",
(unsigned long) CURRENT, CURRENT ? CURRENT->rq_dev : 0,
- CURRENT ? CURRENT->sector : 0));
+ !QUEUE_EMPTY ? CURRENT->sector : 0));
- if (CURRENT && CURRENT->rq_status == RQ_INACTIVE)
+ if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE)
goto the_end;
repeat:
- if (!CURRENT)
+ if (QUEUE_EMPTY)
goto the_end;
if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index d30251fbb..0d65a1493 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -758,7 +758,7 @@ static void request_done(int uptodate)
/* No - its the end of the line */
/* end_request's should have happened at the end of sector DMAs */
/* Turns Drive LEDs off - may slow it down? */
- if (!CURRENT)
+ if (QUEUE_EMPTY)
issue_command(CMD_CKV, block, 2);
Busy = 0;
@@ -891,7 +891,7 @@ static void mfm_request(void)
{
DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
- if (!CURRENT) {
+ if (QUEUE_EMPTY) {
DBG("mfm_request: Exited due to NULL Current 1\n");
return;
}
@@ -918,7 +918,7 @@ static void mfm_request(void)
DBG("mfm_request: before INIT_REQUEST\n");
- if (!CURRENT) {
+ if (QUEUE_EMPTY) {
printk("mfm_request: Exiting due to !CURRENT (pre)\n");
CLEAR_INTR;
Busy = 0;
diff --git a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c
index d915a4291..306feb2e9 100644
--- a/drivers/acorn/char/keyb_ps2.c
+++ b/drivers/acorn/char/keyb_ps2.c
@@ -28,6 +28,7 @@
#include <asm/iomd.h>
#include <asm/system.h>
+extern struct tasklet_struct keyboard_tasklet;
extern void kbd_reset_kdown(void);
int kbd_read_mask;
@@ -318,7 +319,7 @@ static void ps2kbd_rx(int irq, void *dev_id, struct pt_regs *regs)
while (inb(IOMD_KCTRL) & (1 << 5))
handle_rawcode(inb(IOMD_KARTRX));
- mark_bh(KEYBOARD_BH);
+ tasklet_schedule(&keyboard_tasklet);
}
static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c
index 5c8b0e26d..7a12ee4a9 100644
--- a/drivers/acorn/net/ether1.c
+++ b/drivers/acorn/net/ether1.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/drivers/net/ether1.c
*
- * (C) Copyright 1996,1997,1998 Russell King
+ * (C) Copyright 1996-2000 Russell King
*
* Acorn ether1 driver (82586 chip)
* for Acorn machines
@@ -28,6 +28,7 @@
* TDR now only reports failure when chip reports non-zero
* TDR time-distance.
* 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1
+ * 1.06 RMK 10/02/2000 Updated for 2.3.43
*/
#include <linux/module.h>
@@ -64,9 +65,16 @@ static unsigned int net_debug = NET_DEBUG;
#define RX_AREA_START 0x05000
#define RX_AREA_END 0x0fc00
-#define tx_done(dev) 0
+static int ether1_open(struct net_device *dev);
+static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
+static void ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int ether1_close(struct net_device *dev);
+static struct enet_statistics *ether1_getstats(struct net_device *dev);
+static void ether1_setmulticastlist(struct net_device *dev);
+static void ether1_timeout(struct net_device *dev);
+
/* ------------------------------------------------------------------------- */
-static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.05\n";
+static char *version = "ether1 ethernet driver (c) 2000 Russell King v1.06\n";
#define BUS_16 16
#define BUS_8 8
@@ -636,12 +644,12 @@ ether1_probe1(struct net_device *dev)
if (net_debug && version_printed++ == 0)
printk (KERN_INFO "%s", version);
- printk (KERN_INFO "%s: ether1 found [%d, %04lx, %d]", dev->name, priv->bus_type,
- dev->base_addr, dev->irq);
-
request_region (dev->base_addr, 16, "ether1");
request_region (dev->base_addr + 0x800, 4096, "ether1(ram)");
+ printk (KERN_INFO "%s: ether1 at %lx, IRQ%d, ether address ",
+ dev->name, dev->base_addr, dev->irq);
+
for (i = 0; i < 6; i++)
printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]);
@@ -650,11 +658,13 @@ ether1_probe1(struct net_device *dev)
return 1;
}
- dev->open = ether1_open;
- dev->stop = ether1_close;
+ dev->open = ether1_open;
+ dev->stop = ether1_close;
dev->hard_start_xmit = ether1_sendpacket;
- dev->get_stats = ether1_getstats;
+ dev->get_stats = ether1_getstats;
dev->set_multicast_list = ether1_setmulticastlist;
+ dev->tx_timeout = ether1_timeout;
+ dev->watchdog_timeo = 5 * HZ / 100;
/* Fill in the fields of the device structure with ethernet values */
ether_setup (dev);
@@ -727,38 +737,18 @@ ether1_txalloc (struct net_device *dev, int size)
return start;
}
-static void
-ether1_restart (struct net_device *dev, char *reason)
-{
- struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
- priv->stats.tx_errors ++;
-
- if (reason)
- printk (KERN_WARNING "%s: %s - resetting device\n", dev->name, reason);
- else
- printk (" - resetting device\n");
-
- ether1_reset (dev);
-
- dev->start = 0;
- dev->tbusy = 0;
-
- if (ether1_init_for_open (dev))
- printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
-
- dev->start = 1;
-}
-
static int
ether1_open (struct net_device *dev)
{
struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
- if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev))
- return -EAGAIN;
-
MOD_INC_USE_COUNT;
+ if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EAGAIN;
+ }
+
memset (&priv->stats, 0, sizeof (struct enet_statistics));
if (ether1_init_for_open (dev)) {
@@ -767,95 +757,94 @@ ether1_open (struct net_device *dev)
return -EAGAIN;
}
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
return 0;
}
-static int
-ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
+static void
+ether1_timeout(struct net_device *dev)
{
struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
- if (priv->restart)
- ether1_restart (dev, NULL);
-
- if (dev->tbusy) {
- /*
- * If we get here, some higher level has decided that we are broken.
- * There should really be a "kick me" function call instead.
- */
- int tickssofar = jiffies - dev->trans_start;
+ printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
+ dev->name);
+ printk(KERN_WARNING "%s: resetting device\n", dev->name);
- if (tickssofar < 5)
- return 1;
-
- /* Try to restart the adapter. */
- ether1_restart (dev, "transmit timeout, network cable problem?");
- dev->trans_start = jiffies;
- }
+ ether1_reset (dev);
- /*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
- if (test_and_set_bit (0, (void *)&dev->tbusy) != 0)
- printk (KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
- else {
- int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
- int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
- unsigned long flags;
- tx_t tx;
- tbd_t tbd;
- nop_t nop;
-
- /*
- * insert packet followed by a nop
- */
- txaddr = ether1_txalloc (dev, TX_SIZE);
- tbdaddr = ether1_txalloc (dev, TBD_SIZE);
- dataddr = ether1_txalloc (dev, len);
- nopaddr = ether1_txalloc (dev, NOP_SIZE);
-
- tx.tx_status = 0;
- tx.tx_command = CMD_TX | CMD_INTR;
- tx.tx_link = nopaddr;
- tx.tx_tbdoffset = tbdaddr;
- tbd.tbd_opts = TBD_EOL | len;
- tbd.tbd_link = I82586_NULL;
- tbd.tbd_bufl = dataddr;
- tbd.tbd_bufh = 0;
- nop.nop_status = 0;
- nop.nop_command = CMD_NOP;
- nop.nop_link = nopaddr;
+ if (ether1_init_for_open (dev))
+ printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
- save_flags_cli (flags);
- ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
- ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
- ether1_writebuffer (dev, skb->data, dataddr, len);
- ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
- tmp = priv->tx_link;
- priv->tx_link = nopaddr;
+ priv->stats.tx_errors++;
+ netif_wake_queue(dev);
+}
- /* now reset the previous nop pointer */
- ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
+static int
+ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
+{
+ struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+ int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+ int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
+ unsigned long flags;
+ tx_t tx;
+ tbd_t tbd;
+ nop_t nop;
- restore_flags (flags);
+ if (priv->restart) {
+ printk(KERN_WARNING "%s: resetting device\n", dev->name);
- /* handle transmit */
- dev->trans_start = jiffies;
+ ether1_reset(dev);
- /* check to see if we have room for a full sized ether frame */
- tmp = priv->tx_head;
- tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
- priv->tx_head = tmp;
- if (tst != -1)
- dev->tbusy = 0;
+ if (ether1_init_for_open(dev))
+ printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
}
+
+ /*
+ * insert packet followed by a nop
+ */
+ txaddr = ether1_txalloc (dev, TX_SIZE);
+ tbdaddr = ether1_txalloc (dev, TBD_SIZE);
+ dataddr = ether1_txalloc (dev, len);
+ nopaddr = ether1_txalloc (dev, NOP_SIZE);
+
+ tx.tx_status = 0;
+ tx.tx_command = CMD_TX | CMD_INTR;
+ tx.tx_link = nopaddr;
+ tx.tx_tbdoffset = tbdaddr;
+ tbd.tbd_opts = TBD_EOL | len;
+ tbd.tbd_link = I82586_NULL;
+ tbd.tbd_bufl = dataddr;
+ tbd.tbd_bufh = 0;
+ nop.nop_status = 0;
+ nop.nop_command = CMD_NOP;
+ nop.nop_link = nopaddr;
+
+ save_flags_cli(flags);
+ ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
+ ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
+ ether1_writebuffer (dev, skb->data, dataddr, len);
+ ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
+ tmp = priv->tx_link;
+ priv->tx_link = nopaddr;
+
+ /* now reset the previous nop pointer */
+ ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
+
+ restore_flags(flags);
+
+ /* handle transmit */
+ dev->trans_start = jiffies;
+
+ /* check to see if we have room for a full sized ether frame */
+ tmp = priv->tx_head;
+ tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+ priv->tx_head = tmp;
dev_kfree_skb (skb);
+ if (tst == -1)
+ netif_stop_queue(dev);
+
return 0;
}
@@ -957,9 +946,7 @@ again:
tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
priv->tx_head = caddr;
if (tst != -1)
- dev->tbusy = 0;
-
- mark_bh (NET_BH);
+ netif_wake_queue(dev);
}
static void
@@ -1024,8 +1011,6 @@ ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
int status;
- dev->interrupt = 1;
-
status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
if (status) {
@@ -1065,8 +1050,6 @@ ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
}
} else
outb (CTRL_ACK, REG_CONTROL);
-
- dev->interrupt = 0;
}
static int
@@ -1076,9 +1059,6 @@ ether1_close (struct net_device *dev)
free_irq(dev->irq, dev);
- dev->start = 0;
- dev->tbusy = 0;
-
MOD_DEC_USE_COUNT;
return 0;
@@ -1110,7 +1090,7 @@ ether1_setmulticastlist (struct net_device *dev)
static struct ether_dev {
struct expansion_card *ec;
char name[9];
- struct net_device dev;
+ struct net_device dev;
} ether_devs[MAX_ECARDS];
int
diff --git a/drivers/acorn/net/ether1.h b/drivers/acorn/net/ether1.h
index 53f2cd8bf..db64114f1 100644
--- a/drivers/acorn/net/ether1.h
+++ b/drivers/acorn/net/ether1.h
@@ -43,13 +43,6 @@ struct ether1_priv {
unsigned char restart : 1;
};
-static int ether1_open (struct net_device *dev);
-static int ether1_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static int ether1_close (struct net_device *dev);
-static struct enet_statistics *ether1_getstats (struct net_device *dev);
-static void ether1_setmulticastlist (struct net_device *dev);
-
#define I82586_NULL (-1)
typedef struct { /* tdr */
diff --git a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c
index 3b30dc5b4..03cc064c4 100644
--- a/drivers/acorn/net/ether3.c
+++ b/drivers/acorn/net/ether3.c
@@ -36,9 +36,10 @@
* 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing.
* 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy
* hardware.
+ * 1.16 RMK 10/02/2000 Updated for 2.3.43
*/
-static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.15\n";
+static char *version = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.16\n";
#include <linux/module.h>
#include <linux/kernel.h>
@@ -74,9 +75,17 @@ static const card_ids __init ether3_cids[] = {
{ 0xffff, 0xffff }
};
-static void ether3_setmulticastlist(struct net_device *dev);
-static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
-static void ether3_tx(struct net_device *dev, struct dev_priv *priv);
+static void ether3_setmulticastlist(struct net_device *dev);
+static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
+static void ether3_tx(struct net_device *dev, struct dev_priv *priv);
+static int ether3_probe1 (struct net_device *dev);
+static int ether3_open (struct net_device *dev);
+static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
+static void ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static int ether3_close (struct net_device *dev);
+static struct enet_statistics *ether3_getstats (struct net_device *dev);
+static void ether3_setmulticastlist (struct net_device *dev);
+static void ether3_timeout(struct net_device *dev);
#define BUS_16 2
#define BUS_8 1
@@ -406,6 +415,7 @@ ether3_probe1(struct net_device *dev)
static unsigned version_printed = 0;
struct dev_priv *priv;
unsigned int i, bus_type, error = ENODEV;
+ const char *name = "ether3";
if (net_debug && version_printed++ == 0)
printk(version);
@@ -421,7 +431,7 @@ ether3_probe1(struct net_device *dev)
priv = (struct dev_priv *) dev->priv;
memset(priv, 0, sizeof(struct dev_priv));
- request_region(dev->base_addr, 128, "ether3");
+ request_region(dev->base_addr, 128, name);
/* Reset card...
*/
@@ -443,33 +453,38 @@ ether3_probe1(struct net_device *dev)
switch (bus_type) {
case BUS_UNKNOWN:
- printk(KERN_ERR "%s: unable to identify podule bus width\n", dev->name);
+ printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
goto failed;
case BUS_8:
- printk(KERN_ERR "%s: ether3 found, but is an unsupported 8-bit card\n", dev->name);
+ printk(KERN_ERR "%s: %s found, but is an unsupported "
+ "8-bit card\n", dev->name, name);
goto failed;
default:
break;
}
- printk("%s: ether3 found at %lx, IRQ%d, ether address ", dev->name, dev->base_addr, dev->irq);
+ printk("%s: %s at %lx, IRQ%d, ether address ",
+ dev->name, name, dev->base_addr, dev->irq);
for (i = 0; i < 6; i++)
printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]);
- if (!ether3_init_2(dev)) {
- dev->open = ether3_open;
- dev->stop = ether3_close;
- dev->hard_start_xmit = ether3_sendpacket;
- dev->get_stats = ether3_getstats;
- dev->set_multicast_list = ether3_setmulticastlist;
+ if (ether3_init_2(dev))
+ goto failed;
- /* Fill in the fields of the device structure with ethernet values. */
- ether_setup(dev);
+ dev->open = ether3_open;
+ dev->stop = ether3_close;
+ dev->hard_start_xmit = ether3_sendpacket;
+ dev->get_stats = ether3_getstats;
+ dev->set_multicast_list = ether3_setmulticastlist;
+ dev->tx_timeout = ether3_timeout;
+ dev->watchdog_timeo = 5 * HZ / 100;
- return 0;
- }
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+
+ return 0;
failed:
kfree(dev->priv);
@@ -535,12 +550,10 @@ ether3_open(struct net_device *dev)
return -EAGAIN;
}
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
ether3_init_for_open(dev);
+ netif_start_queue(dev);
+
return 0;
}
@@ -552,8 +565,7 @@ ether3_close(struct net_device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
disable_irq(dev->irq);
@@ -602,6 +614,34 @@ static void ether3_setmulticastlist(struct net_device *dev)
ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
}
+static void
+ether3_timeout(struct net_device *dev)
+{
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ unsigned long flags;
+
+ del_timer(&priv->timer);
+
+ save_flags_cli(flags);
+ printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
+ printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name,
+ ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
+ printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
+ ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
+ printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
+ priv->tx_head, priv->tx_tail);
+ ether3_setbuffer(dev, buffer_read, priv->tx_tail);
+ printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
+ restore_flags(flags);
+
+ priv->regs.config2 |= CFG2_CTRLO;
+ priv->stats.tx_errors += 1;
+ ether3_outw(priv->regs.config2, REG_CONFIG2);
+ priv->tx_head = priv->tx_tail = 0;
+
+ netif_wake_queue(dev);
+}
+
/*
* Transmit a packet
*/
@@ -609,102 +649,61 @@ static int
ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
-retry:
- if (!dev->tbusy) {
- /* Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
- if (!test_and_set_bit(0, (void *)&dev->tbusy)) {
- unsigned long flags;
- unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned int ptr, next_ptr;
-
- length = (length + 1) & ~1;
-
- if (priv->broken) {
- dev_kfree_skb(skb);
- priv->stats.tx_dropped ++;
- dev->tbusy = 0;
- return 0;
- }
+ unsigned long flags;
+ unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned int ptr, next_ptr;
- next_ptr = (priv->tx_head + 1) & 15;
+ length = (length + 1) & ~1;
- save_flags_cli(flags);
+ if (priv->broken) {
+ dev_kfree_skb(skb);
+ priv->stats.tx_dropped ++;
+ netif_start_queue(dev);
+ return 0;
+ }
- if (priv->tx_tail == next_ptr) {
- restore_flags(flags);
- return 1; /* unable to queue */
- }
+ next_ptr = (priv->tx_head + 1) & 15;
- dev->trans_start = jiffies;
- ptr = 0x600 * priv->tx_head;
- priv->tx_head = next_ptr;
- next_ptr *= 0x600;
+ save_flags_cli(flags);
-#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
+ if (priv->tx_tail == next_ptr) {
+ restore_flags(flags);
+ return 1; /* unable to queue */
+ }
- ether3_setbuffer(dev, buffer_write, next_ptr);
- ether3_writelong(dev, 0);
- ether3_setbuffer(dev, buffer_write, ptr);
- ether3_writelong(dev, 0);
- ether3_writebuffer(dev, skb->data, length);
- ether3_writeword(dev, htons(next_ptr));
- ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
- ether3_setbuffer(dev, buffer_write, ptr);
- ether3_writeword(dev, htons((ptr + length + 4)));
- ether3_writeword(dev, TXHDR_FLAGS >> 16);
- ether3_ledon(dev, priv);
-
- if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
- ether3_outw(ptr, REG_TRANSMITPTR);
- ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
- }
+ dev->trans_start = jiffies;
+ ptr = 0x600 * priv->tx_head;
+ priv->tx_head = next_ptr;
+ next_ptr *= 0x600;
- next_ptr = (priv->tx_head + 1) & 15;
- if (priv->tx_tail != next_ptr)
- dev->tbusy = 0;
+#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
- restore_flags(flags);
+ ether3_setbuffer(dev, buffer_write, next_ptr);
+ ether3_writelong(dev, 0);
+ ether3_setbuffer(dev, buffer_write, ptr);
+ ether3_writelong(dev, 0);
+ ether3_writebuffer(dev, skb->data, length);
+ ether3_writeword(dev, htons(next_ptr));
+ ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
+ ether3_setbuffer(dev, buffer_write, ptr);
+ ether3_writeword(dev, htons((ptr + length + 4)));
+ ether3_writeword(dev, TXHDR_FLAGS >> 16);
+ ether3_ledon(dev, priv);
- dev_kfree_skb(skb);
+ if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
+ ether3_outw(ptr, REG_TRANSMITPTR);
+ ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
+ }
- return 0;
- } else {
- printk("%s: transmitter access conflict.\n", dev->name);
- return 1;
- }
- } else {
- /* If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- int tickssofar = jiffies - dev->trans_start;
- unsigned long flags;
+ next_ptr = (priv->tx_head + 1) & 15;
+ restore_flags(flags);
- if (tickssofar < 5)
- return 1;
- del_timer(&priv->timer);
-
- save_flags_cli(flags);
- printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
- printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name,
- ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
- printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
- ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
- printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
- priv->tx_head, priv->tx_tail);
- ether3_setbuffer(dev, buffer_read, priv->tx_tail);
- printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
- restore_flags(flags);
+ dev_kfree_skb(skb);
- dev->tbusy = 0;
- priv->regs.config2 |= CFG2_CTRLO;
- priv->stats.tx_errors += 1;
- ether3_outw(priv->regs.config2, REG_CONFIG2);
- dev->trans_start = jiffies;
- priv->tx_head = priv->tx_tail = 0;
- goto retry;
- }
+ if (priv->tx_tail == next_ptr)
+ netif_stop_queue(dev);
+
+ return 0;
}
static void
@@ -721,8 +720,6 @@ ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
priv = (struct dev_priv *)dev->priv;
- dev->interrupt = 1;
-
status = ether3_inw(REG_STATUS);
if (status & STAT_INTRX) {
@@ -735,8 +732,6 @@ ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ether3_tx(dev, priv);
}
- dev->interrupt = 0;
-
#if NET_DEBUG > 1
if(net_debug & DEBUG_INT)
printk("done\n");
@@ -904,8 +899,7 @@ ether3_tx(struct net_device *dev, struct dev_priv *priv)
if (priv->tx_tail != tx_tail) {
priv->tx_tail = tx_tail;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev);
}
}
@@ -914,7 +908,7 @@ ether3_tx(struct net_device *dev, struct dev_priv *priv)
static struct ether_dev {
struct expansion_card *ec;
char name[9];
- struct net_device dev;
+ struct net_device dev;
} ether_devs[MAX_ECARDS];
int
diff --git a/drivers/acorn/net/ether3.h b/drivers/acorn/net/ether3.h
index ee4802b2d..45dfd82a1 100644
--- a/drivers/acorn/net/ether3.h
+++ b/drivers/acorn/net/ether3.h
@@ -159,13 +159,4 @@ struct dev_priv {
int broken; /* 0 = ok, 1 = something went wrong */
};
-extern int ether3_probe (struct net_device *dev);
-static int ether3_probe1 (struct net_device *dev);
-static int ether3_open (struct net_device *dev);
-static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static int ether3_close (struct net_device *dev);
-static struct enet_statistics *ether3_getstats (struct net_device *dev);
-static void ether3_setmulticastlist (struct net_device *dev);
-
#endif
diff --git a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c
index 0610005d1..71dcbbdbc 100644
--- a/drivers/acorn/net/etherh.c
+++ b/drivers/acorn/net/etherh.c
@@ -13,6 +13,7 @@
* RMK 1.03 Added support for EtherLan500 cards
* 23-11-1997 RMK 1.04 Added media autodetection
* 16-04-1998 RMK 1.05 Improved media autodetection
+ * 10-02-2000 RMK 1.06 Updated for 2.3.43
*
* Insmod Module Parameters
* ------------------------
@@ -61,7 +62,7 @@ static const card_ids __init etherh_cids[] = {
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("i3 EtherH driver");
-static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n";
+static char *version = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.06\n";
#define ETHERH500_DATAPORT 0x200 /* MEMC */
#define ETHERH500_NS8390 0x000 /* MEMC */
@@ -190,8 +191,8 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf
if (ei_status.dmaing) {
printk ("%s: DMAing conflict in etherh_block_input: "
- " DMAstat %d irqlock %d intr %ld\n", dev->name,
- ei_status.dmaing, ei_status.irqlock, dev->interrupt);
+ " DMAstat %d irqlock %d\n", dev->name,
+ ei_status.dmaing, ei_status.irqlock);
return;
}
@@ -248,8 +249,8 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int
if (ei_status.dmaing) {
printk ("%s: DMAing conflict in etherh_block_input: "
- " DMAstat %d irqlock %d intr %ld\n", dev->name,
- ei_status.dmaing, ei_status.irqlock, dev->interrupt);
+ " DMAstat %d irqlock %d\n", dev->name,
+ ei_status.dmaing, ei_status.irqlock);
return;
}
@@ -287,8 +288,8 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p
if (ei_status.dmaing) {
printk ("%s: DMAing conflict in etherh_get_header: "
- " DMAstat %d irqlock %d intr %ld\n", dev->name,
- ei_status.dmaing, ei_status.irqlock, dev->interrupt);
+ " DMAstat %d irqlock %d\n", dev->name,
+ ei_status.dmaing, ei_status.irqlock);
return;
}
@@ -359,6 +360,7 @@ etherh_probe1(struct net_device *dev)
unsigned int addr, i, reg0, tmp;
const char *dev_type;
const char *if_type;
+ const char *name = "etherh";
addr = dev->base_addr;
@@ -367,13 +369,13 @@ etherh_probe1(struct net_device *dev)
switch (dev->mem_end) {
case PROD_I3_ETHERLAN500:
- dev_type = "500 ";
+ dev_type = "500";
break;
case PROD_I3_ETHERLAN600:
- dev_type = "600 ";
+ dev_type = "600";
break;
case PROD_I3_ETHERLAN600A:
- dev_type = "600A ";
+ dev_type = "600A";
break;
default:
dev_type = "";
@@ -382,7 +384,8 @@ etherh_probe1(struct net_device *dev)
reg0 = inb (addr);
if (reg0 == 0xff) {
if (net_debug & DEBUG_INIT)
- printk ("%s: etherh error: NS8390 command register wrong\n", dev->name);
+ printk("%s: %s error: NS8390 command register wrong\n",
+ dev->name, name);
return -ENODEV;
}
@@ -393,34 +396,35 @@ etherh_probe1(struct net_device *dev)
inb (addr + EN0_COUNTER0);
if (inb (addr + EN0_COUNTER0) != 0) {
if (net_debug & DEBUG_INIT)
- printk ("%s: etherh error: NS8390 not found\n", dev->name);
+ printk("%s: %s error: NS8390 not found\n",
+ dev->name, name);
outb (reg0, addr);
outb (tmp, addr + 13);
return -ENODEV;
}
- if (ethdev_init (dev))
+ if (ethdev_init(dev))
return -ENOMEM;
- request_region (addr, 16, "etherh");
+ request_region(addr, 16, name);
- printk("%s: etherh %sfound at %lx, IRQ%d, ether address ",
- dev->name, dev_type, dev->base_addr, dev->irq);
+ printk("%s: %s %s at %lx, IRQ%d, ether address ",
+ dev->name, name, dev_type, dev->base_addr, dev->irq);
for (i = 0; i < 6; i++)
printk (i == 5 ? "%2.2x " : "%2.2x:", dev->dev_addr[i]);
- ei_status.name = "etherh";
- ei_status.word16 = 1;
- ei_status.tx_start_page = ETHERH_TX_START_PAGE;
- ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES;
- ei_status.stop_page = ETHERH_STOP_PAGE;
- ei_status.reset_8390 = etherh_reset;
- ei_status.block_input = etherh_block_input;
- ei_status.block_output = etherh_block_output;
- ei_status.get_8390_hdr = etherh_get_header;
- dev->open = etherh_open;
- dev->stop = etherh_close;
+ ei_status.name = name;
+ ei_status.word16 = 1;
+ ei_status.tx_start_page = ETHERH_TX_START_PAGE;
+ ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES;
+ ei_status.stop_page = ETHERH_STOP_PAGE;
+ ei_status.reset_8390 = etherh_reset;
+ ei_status.block_input = etherh_block_input;
+ ei_status.block_output = etherh_block_output;
+ ei_status.get_8390_hdr = etherh_get_header;
+ dev->open = etherh_open;
+ dev->stop = etherh_close;
/* select 10bT */
ei_status.interface_num = 0;
@@ -567,7 +571,8 @@ init_all_cards(void)
my_ethers[i] = dev;
if (register_netdev(dev) != 0) {
- printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr);
+ printk(KERN_ERR "No etherh card found at %08lX\n",
+ dev->base_addr);
if (ec[i]) {
ecard_release(ec[i]);
ec[i] = NULL;
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index 79bd8078e..01fc28943 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -206,8 +206,8 @@ bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
tristate ' Linear (append) mode' CONFIG_MD_LINEAR
tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED
- tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
- tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5
+# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
+# tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5
fi
if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
bool ' Boot support (linear, striped)' CONFIG_MD_BOOT
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 45e86000a..d912f8c08 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1009,37 +1009,58 @@ static boolean DAC960_ReportDeviceConfiguration(DAC960_Controller_T *Controller)
}
-static int DAC_merge_fn(request_queue_t *q, struct request *req,
- struct buffer_head *bh)
+static inline int DAC_new_segment(request_queue_t *q, struct request *req,
+ int __max_segments)
{
int max_segments;
DAC960_Controller_T * Controller = q->queuedata;
max_segments = Controller->MaxSegmentsPerRequest[MINOR(req->rq_dev)];
+ if (__max_segments < max_segments)
+ max_segments = __max_segments;
- if (req->bhtail->b_data + req->bhtail->b_size != bh->b_data) {
- if (req->nr_segments < max_segments) {
- req->nr_segments++;
- return 1;
- }
- return 0;
+ if (req->nr_segments < max_segments) {
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
}
+ return 0;
+}
- return 1;
+static int DAC_back_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int __max_segments)
+{
+ if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+ return 1;
+ return DAC_new_segment(q, req, __max_segments);
+}
+
+static int DAC_front_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int __max_segments)
+{
+ if (bh->b_data + bh->b_size == req->bh->b_data)
+ return 1;
+ return DAC_new_segment(q, req, __max_segments);
}
static int DAC_merge_requests_fn(request_queue_t *q,
struct request *req,
- struct request *next)
+ struct request *next,
+ int __max_segments)
{
int max_segments;
DAC960_Controller_T * Controller = q->queuedata;
int total_segments = req->nr_segments + next->nr_segments;
max_segments = Controller->MaxSegmentsPerRequest[MINOR(req->rq_dev)];
+ if (__max_segments < max_segments)
+ max_segments = __max_segments;
if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+ {
total_segments--;
+ q->nr_segments--;
+ }
if (total_segments > max_segments)
return 0;
@@ -1068,7 +1089,7 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
/*
Register the Block Device Major Number for this DAC960 Controller.
*/
- if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0)
+ if (devfs_register_blkdev(MajorNumber, "dac960", &DAC960_FileOperations) < 0)
{
DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
Controller, MajorNumber);
@@ -1080,7 +1101,8 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
q = BLK_DEFAULT_QUEUE(MajorNumber);
blk_init_queue(q, RequestFunctions[Controller->ControllerNumber]);
blk_queue_headactive(q, 0);
- q->merge_fn = DAC_merge_fn;
+ q->back_merge_fn = DAC_back_merge_fn;
+ q->front_merge_fn = DAC_front_merge_fn;
q->merge_requests_fn = DAC_merge_requests_fn;
q->queuedata = (void *) Controller;
@@ -1108,12 +1130,13 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
Complete initialization of the Generic Disk Information structure.
*/
Controller->GenericDiskInfo.major = MajorNumber;
- Controller->GenericDiskInfo.major_name = "rd";
+ Controller->GenericDiskInfo.major_name = "dac960";
Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
Controller->GenericDiskInfo.real_devices = Controller;
Controller->GenericDiskInfo.next = NULL;
+ Controller->GenericDiskInfo.fops = &DAC960_FileOperations;
/*
Install the Generic Disk Information structure at the end of the list.
*/
@@ -1142,7 +1165,7 @@ static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
/*
Unregister the Block Device Major Number for this DAC960 Controller.
*/
- unregister_blkdev(MajorNumber, "rd");
+ devfs_unregister_blkdev(MajorNumber, "dac960");
/*
Remove the I/O Request Function.
*/
@@ -1156,7 +1179,6 @@ static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
blk_size[MajorNumber] = NULL;
blksize_size[MajorNumber] = NULL;
max_sectors[MajorNumber] = NULL;
- max_segments[MajorNumber] = NULL;
/*
Remove the Generic Disk Information structure from the list.
*/
@@ -1305,15 +1327,17 @@ static int DAC960_Finalize(NotifierBlock_T *NotifierBlock,
static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
boolean WaitForCommand)
{
- IO_Request_T **RequestQueuePointer =
- &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].request_queue.current_request;
+ struct list_head * queue_head;
IO_Request_T *Request;
DAC960_Command_T *Command;
char *RequestBuffer;
+
+ queue_head = &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].request_queue.queue_head;
while (true)
{
- Request = *RequestQueuePointer;
- if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
+ if (list_empty(queue_head)) return false;
+ Request = blkdev_entry_next_request(queue_head);
+ if (Request->rq_status == RQ_INACTIVE) return false;
Command = DAC960_AllocateCommand(Controller);
if (Command != NULL) break;
if (!WaitForCommand) return false;
@@ -1335,7 +1359,7 @@ static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
Command->BufferHeader = Request->bh;
RequestBuffer = Request->buffer;
Request->rq_status = RQ_INACTIVE;
- *RequestQueuePointer = Request->next;
+ blkdev_dequeue_request(Request);
wake_up(&wait_for_request);
if (Command->SegmentCount == 1)
{
@@ -2565,8 +2589,8 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
(long *) Argument);
case BLKRAGET:
/* Get Read-Ahead. */
- if ((int *) Argument == NULL) return -EINVAL;
- return put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument);
+ if ((long *) Argument == NULL) return -EINVAL;
+ return put_user(read_ahead[MAJOR(Inode->i_rdev)], (long *) Argument);
case BLKRASET:
/* Set Read-Ahead. */
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 3f9c5f85b..9f313de8f 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -326,6 +326,14 @@ else
endif
endif
+ifeq ($(CONFIG_BLK_DEV_LVM),y)
+L_OBJS += lvm.o lvm-snap.o
+else
+ ifeq ($(CONFIG_BLK_DEV_LVM),m)
+ M_OBJS += lvm-mod.o
+ endif
+endif
+
ifeq ($(CONFIG_BLK_DEV_MD),y)
LX_OBJS += md.o
@@ -354,13 +362,9 @@ else
endif
ifeq ($(CONFIG_MD_RAID5),y)
-LX_OBJS += xor.o
-CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer
L_OBJS += raid5.o
else
ifeq ($(CONFIG_MD_RAID5),m)
- LX_OBJS += xor.o
- CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer
M_OBJS += raid5.o
endif
endif
@@ -407,3 +411,6 @@ ide-mod.o: ide.o ide-features.o $(IDE_OBJS)
ide-probe-mod.o: ide-probe.o ide-geometry.o
$(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
+
+lvm-mod.o: lvm.o lvm-snap.o
+ $(LD) -r -o $@ lvm.o lvm-snap.o
diff --git a/drivers/block/README.lvm b/drivers/block/README.lvm
new file mode 100644
index 000000000..3d652457f
--- /dev/null
+++ b/drivers/block/README.lvm
@@ -0,0 +1,8 @@
+
+This is the Logical Volume Manager driver for Linux,
+
+Tools, library that manage logical volumes can be found
+at <http://linux.msede.com/lvm>.
+
+There you can obtain actual driver versions too.
+
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index ef9e3fa7c..f2a102cf2 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -54,6 +54,7 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/genhd.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/major.h>
@@ -769,7 +770,7 @@ static void unexpected_acsi_interrupt( void )
static void bad_rw_intr( void )
{
- if (!CURRENT)
+ if (QUEUE_EMPTY)
return;
if (++CURRENT->errors >= MAX_ERRORS)
@@ -843,7 +844,7 @@ static void acsi_times_out( unsigned long dummy )
DEVICE_INTR = NULL;
printk( KERN_ERR "ACSI timeout\n" );
- if (!CURRENT) return;
+ if (QUEUE_EMPTY) return;
if (++CURRENT->errors >= MAX_ERRORS) {
#ifdef DEBUG
printk( KERN_ERR "ACSI: too many errors.\n" );
@@ -953,7 +954,7 @@ static void redo_acsi_request( void )
unsigned long pbuffer;
struct buffer_head *bh;
- if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) {
+ if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) {
if (!DEVICE_INTR) {
ENABLE_IRQ();
stdma_release();
@@ -969,7 +970,7 @@ static void redo_acsi_request( void )
/* Another check here: An interrupt or timer event could have
* happened since the last check!
*/
- if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) {
+ if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) {
if (!DEVICE_INTR) {
ENABLE_IRQ();
stdma_release();
@@ -979,7 +980,7 @@ static void redo_acsi_request( void )
if (DEVICE_INTR)
return;
- if (!CURRENT) {
+ if (QUEUE_EMPTY) {
CLEAR_INTR;
ENABLE_IRQ();
stdma_release();
@@ -1385,6 +1386,8 @@ static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd )
********************************************************************/
+extern struct block_device_operations acsi_fops;
+
static struct gendisk acsi_gendisk = {
MAJOR_NR, /* Major number */
"ad", /* Major name */
@@ -1394,7 +1397,8 @@ static struct gendisk acsi_gendisk = {
acsi_sizes, /* block sizes */
0, /* number */
(void *)acsi_info, /* internal */
- NULL /* next */
+ NULL, /* next */
+ &acsi_fops, /* file operations */
};
#define MAX_SCSI_DEVICE_CODE 10
@@ -1776,16 +1780,14 @@ int acsi_init( void )
int err = 0;
if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ACSI))
return 0;
-
- if (register_blkdev( MAJOR_NR, "ad", &acsi_fops )) {
+ if (devfs_register_blkdev( MAJOR_NR, "ad", &acsi_fops )) {
printk( KERN_ERR "Unable to get major %d for ACSI\n", MAJOR_NR );
return -EBUSY;
}
-
if (!(acsi_buffer =
(char *)atari_stram_alloc( ACSI_BUFFER_SIZE, NULL, "acsi" ))) {
printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" );
- unregister_blkdev( MAJOR_NR, "ad" );
+ devfs_unregister_blkdev( MAJOR_NR, "ad" );
return -ENOMEM;
}
phys_acsi_buffer = virt_to_phys( acsi_buffer );
@@ -1824,7 +1826,7 @@ void cleanup_module(void)
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
atari_stram_free( acsi_buffer );
- if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
+ if (devfs_unregister_blkdev( MAJOR_NR, "ad" ) != 0)
printk( KERN_ERR "acsi: cleanup_module failed\n");
for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index e4d343be3..88fa04ac6 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -65,6 +65,7 @@ not be guaranteed. There are several ways to assure this:
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -987,23 +988,28 @@ int attach_slm( int target, int lun )
return( 1 );
}
+static devfs_handle_t devfs_handle = NULL;
int slm_init( void )
{
- if (register_chrdev( MAJOR_NR, "slm", &slm_fops )) {
+ if (devfs_register_chrdev( MAJOR_NR, "slm", &slm_fops )) {
printk( KERN_ERR "Unable to get major %d for ACSI SLM\n", MAJOR_NR );
return -EBUSY;
}
if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, NULL, "SLM" ))) {
printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" );
- unregister_chrdev( MAJOR_NR, "slm" );
+ devfs_unregister_chrdev( MAJOR_NR, "slm" );
return -ENOMEM;
}
BufferP = SLMBuffer;
SLMState = IDLE;
+ devfs_handle = devfs_mk_dir (NULL, "slm", 3, NULL);
+ devfs_register_series (devfs_handle, "%u", MAX_SLM, DEVFS_FL_DEFAULT,
+ MAJOR_NR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &slm_fops, NULL);
return 0;
}
@@ -1026,7 +1032,8 @@ int init_module(void)
void cleanup_module(void)
{
- if (unregister_chrdev( MAJOR_NR, "slm" ) != 0)
+ devfs_unregister (devfs_handle);
+ if (devfs_unregister_chrdev( MAJOR_NR, "slm" ) != 0)
printk( KERN_ERR "acsi_slm: cleanup_module failed\n");
atari_stram_free( SLMBuffer );
}
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index e6bf5fa0c..0c7af176e 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1385,12 +1385,12 @@ static void redo_fd_request(void)
char *data;
unsigned long flags;
- if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
+ if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE){
return;
}
repeat:
- if (!CURRENT) {
+ if (QUEUE_EMPTY) {
/* Nothing left to do */
return;
}
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index b1e20b7d3..b7aa4241e 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -624,7 +624,7 @@ static void fd_error( void )
return;
}
- if (!CURRENT) return;
+ if (QUEUE_EMPTY) return;
CURRENT->errors++;
if (CURRENT->errors >= MAX_ERRORS) {
printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
@@ -1450,18 +1450,18 @@ static void redo_fd_request(void)
int device, drive, type;
DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->dev=%04x CURRENT->sector=%ld\n",
- (unsigned long)CURRENT, CURRENT ? CURRENT->rq_dev : 0,
- CURRENT ? CURRENT->sector : 0 ));
+ (unsigned long)CURRENT, !QUEUE_EMPTY ? CURRENT->rq_dev : 0,
+ !QUEUE_EMPTY ? CURRENT->sector : 0 ));
IsFormatting = 0;
- if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
+ if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE){
return;
}
repeat:
- if (!CURRENT)
+ if (QUEUE_EMPTY)
goto the_end;
if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 78269edf3..47291bef1 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -880,14 +880,16 @@ static void do_ida_request(int ctlr)
cmdlist_t *c;
int seg, sect;
char *lastdataend;
- request_queue_t * q;
+ struct list_head * queue_head;
struct buffer_head *bh;
struct request *creq;
- q = &blk_dev[MAJOR_NR+ctlr].request_queue;
+ queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head;
- creq = q->current_request;
- if (creq == NULL || creq->rq_status == RQ_INACTIVE)
+ if (list_empty(queue_head))
+ goto doreq_done;
+ creq = blkdev_entry_next_request(queue_head);
+ if (creq->rq_status == RQ_INACTIVE)
goto doreq_done;
if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ||
@@ -961,10 +963,9 @@ DBGPX(
bh->b_reqnext = NULL;
DBGPX( printk("More to do on same request %p\n", creq); );
} else {
-DBGPX( printk("Done with %p, queueing %p\n", creq, creq->next); );
- creq->rq_status = RQ_INACTIVE;
- q->current_request = creq->next;
- wake_up(&wait_for_request);
+DBGPX( printk("Done with %p\n", creq); );
+ blkdev_dequeue_request(creq);
+ end_that_request_last(creq);
}
c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE;
diff --git a/drivers/block/cs5530.c b/drivers/block/cs5530.c
index cf8b5fdda..3e26b8006 100644
--- a/drivers/block/cs5530.c
+++ b/drivers/block/cs5530.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cs5530.c Version 0.2 Jan 30, 2000
+ * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000
*
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -285,8 +285,6 @@ static int cs5530_config_dma (ide_drive_t *drive)
}
outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */
- if (!strcmp(drive->name, "hdc")) /* FIXME */
- return 0;
/*
* Finally, turn DMA on in software, and exit.
*/
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 7b956dfae..be7e25879 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -144,6 +144,10 @@ static int irqdma_allocated = 0;
#define FDPATCHES
#include <linux/fdreg.h>
+/*
+ * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
+ */
+
#include <linux/fd.h>
#include <linux/hdreg.h>
@@ -158,6 +162,7 @@ static int irqdma_allocated = 0;
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
/*
* PS/2 floppies have much slower step rates than regular floppies.
@@ -196,7 +201,9 @@ static int use_virtual_dma=0;
static unsigned short virtual_dma_port=0x3f0;
void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static int set_dor(int fdc, char mask, char data);
-static inline int __get_order(unsigned long size);
+static void register_devfs_entries (int drive);
+static devfs_handle_t devfs_handle = NULL;
+
#define K_64 0x10000 /* 64KB */
#include <asm/floppy.h>
@@ -213,26 +220,12 @@ static inline int __get_order(unsigned long size);
/* Dma Memory related stuff */
-/* Pure 2^n version of get_order */
-static inline int __get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
#ifndef fd_dma_mem_free
-#define fd_dma_mem_free(addr, size) free_pages(addr, __get_order(size))
+#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
#endif
#ifndef fd_dma_mem_alloc
-#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size))
+#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size))
#endif
static inline void fallback_on_nodma_alloc(char **addr, size_t l)
@@ -2276,7 +2269,7 @@ static void request_done(int uptodate)
probing = 0;
reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
- if (!CURRENT){
+ if (QUEUE_EMPTY){
DPRINT("request list destroyed in floppy request done\n");
return;
}
@@ -2290,14 +2283,14 @@ static void request_done(int uptodate)
DRS->maxtrack = 1;
/* unlock chained buffers */
- while (current_count_sectors && CURRENT &&
+ while (current_count_sectors && !QUEUE_EMPTY &&
current_count_sectors >= CURRENT->current_nr_sectors){
current_count_sectors -= CURRENT->current_nr_sectors;
CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
CURRENT->sector += CURRENT->current_nr_sectors;
end_request(1);
}
- if (current_count_sectors && CURRENT){
+ if (current_count_sectors && !QUEUE_EMPTY){
/* "unlock" last subsector */
CURRENT->buffer += current_count_sectors <<9;
CURRENT->current_nr_sectors -= current_count_sectors;
@@ -2306,7 +2299,7 @@ static void request_done(int uptodate)
return;
}
- if (current_count_sectors && !CURRENT)
+ if (current_count_sectors && QUEUE_EMPTY)
DPRINT("request list destroyed in floppy request done\n");
} else {
@@ -2869,14 +2862,14 @@ static void redo_fd_request(void)
if (current_drive < N_DRIVE)
floppy_off(current_drive);
- if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
+ if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE){
CLEAR_INTR;
unlock_fdc();
return;
}
while(1){
- if (!CURRENT) {
+ if (QUEUE_EMPTY) {
CLEAR_INTR;
unlock_fdc();
return;
@@ -3631,6 +3624,7 @@ static void config_types(void)
first = 0;
}
printk("%s fd%d is %s", prepend, drive, name);
+ register_devfs_entries (drive);
}
*UDP = *params;
}
@@ -3844,6 +3838,37 @@ static struct block_device_operations floppy_fops = {
revalidate: floppy_revalidate,
};
+static void register_devfs_entries (int drive)
+{
+ int base_minor, i;
+ static char *table[] =
+ {"", "d360", "h1200", "u360", "u720", "h360", "h720",
+ "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410",
+ "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743",
+ "h880", "u1040", "u1120", "h1600", "u1760", "u1920",
+ "u3200", "u3520", "u3840", "u1840", "u800", "u1600",
+ NULL
+ };
+ static int t360[] = {1,0}, t1200[] = {2,5,6,10,12,14,16,18,20,23,0},
+ t3in[] = {8,9,26,27,28, 7,11,15,19,24,25,29,31, 3,4,13,17,21,22,30,0};
+ static int *table_sup[] =
+ {NULL, t360, t1200, t3in+5+8, t3in+5, t3in, t3in};
+
+ base_minor = (drive < 4) ? drive : (124 + drive);
+ if (UDP->cmos <= NUMBER(default_drive_params)) {
+ i = 0;
+ do {
+ char name[16];
+
+ sprintf (name, "%d%s", drive, table[table_sup[UDP->cmos][i]]);
+ devfs_register (devfs_handle, name, 0, DEVFS_FL_DEFAULT, MAJOR_NR,
+ base_minor + (table_sup[UDP->cmos][i] << 2),
+ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP,
+ 0, 0, &floppy_fops, NULL);
+ } while (table_sup[UDP->cmos][i++]);
+ }
+}
+
/*
* Floppy Driver initialization
* =============================
@@ -4066,7 +4091,8 @@ int __init floppy_init(void)
raw_cmd = 0;
- if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
+ devfs_handle = devfs_mk_dir (NULL, "floppy", 0, NULL);
+ if (devfs_register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
printk("Unable to get major %d for floppy\n",MAJOR_NR);
return -EBUSY;
}
@@ -4097,7 +4123,7 @@ int __init floppy_init(void)
use_virtual_dma = can_use_virtual_dma & 1;
fdc_state[0].address = FDC1;
if (fdc_state[0].address == -1) {
- unregister_blkdev(MAJOR_NR,"fd");
+ devfs_unregister_blkdev(MAJOR_NR,"fd");
del_timer(&fd_timeout);
return -ENODEV;
}
@@ -4109,7 +4135,7 @@ int __init floppy_init(void)
if (floppy_grab_irq_and_dma()){
del_timer(&fd_timeout);
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
- unregister_blkdev(MAJOR_NR,"fd");
+ devfs_unregister_blkdev(MAJOR_NR,"fd");
del_timer(&fd_timeout);
return -EBUSY;
}
@@ -4175,7 +4201,7 @@ int __init floppy_init(void)
if (usage_count)
floppy_release_irq_and_dma();
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
- unregister_blkdev(MAJOR_NR,"fd");
+ devfs_unregister_blkdev(MAJOR_NR,"fd");
}
for (drive = 0; drive < N_DRIVE; drive++) {
@@ -4413,7 +4439,8 @@ void cleanup_module(void)
{
int dummy;
- unregister_blkdev(MAJOR_NR, "fd");
+ devfs_unregister (devfs_handle);
+ devfs_unregister_blkdev(MAJOR_NR, "fd");
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
/* eject disk, if any */
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 95999e273..3f3237e87 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -4,6 +4,8 @@
*
* Copyright (C) 1991-1998 Linus Torvalds
*
+ * devfs support - jj, rgooch, 980122
+ *
* Moved partition checking code to fs/partitions* - Russell King
* (linux@arm.uk.linux.org)
*/
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index 05a17a0c1..5520c17b0 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -32,6 +32,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/kernel.h>
#include <linux/hdreg.h>
#include <linux/genhd.h>
@@ -145,7 +146,7 @@ static void dump_status (const char *msg, unsigned int stat)
unsigned long flags;
char devc;
- devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+ devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
save_flags (flags);
sti();
#ifdef VERBOSE_ERRORS
@@ -174,7 +175,7 @@ static void dump_status (const char *msg, unsigned int stat)
if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
- if (CURRENT)
+ if (!QUEUE_EMPTY)
printk(", sector=%ld", CURRENT->sector);
}
printk("\n");
@@ -351,7 +352,7 @@ static void bad_rw_intr(void)
{
int dev;
- if (!CURRENT)
+ if (QUEUE_EMPTY)
return;
dev = DEVICE_NR(CURRENT->rq_dev);
if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
@@ -414,7 +415,7 @@ ok_to_read:
#if (HD_DELAY > 0)
last_req = read_timer();
#endif
- if (CURRENT)
+ if (!QUEUE_EMPTY)
hd_request();
return;
}
@@ -475,7 +476,7 @@ static void hd_times_out(void)
unsigned int dev;
DEVICE_INTR = NULL;
- if (!CURRENT)
+ if (QUEUE_EMPTY)
return;
disable_irq(HD_IRQ);
sti();
@@ -522,7 +523,7 @@ static void hd_request(void)
{
unsigned int dev, block, nsect, sec, track, head, cyl;
- if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) return;
+ if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
if (DEVICE_INTR)
return;
repeat:
@@ -662,6 +663,8 @@ static int hd_release(struct inode * inode, struct file * file)
return 0;
}
+extern struct block_device_operations hd_fops;
+
static struct gendisk hd_gendisk = {
MAJOR_NR, /* Major number */
"hd", /* Major name */
@@ -671,7 +674,8 @@ static struct gendisk hd_gendisk = {
hd_sizes, /* block sizes */
0, /* number */
NULL, /* internal use, not presently used */
- NULL /* next */
+ NULL, /* next */
+ &hd_fops, /* file operations */
};
static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -800,7 +804,7 @@ static void hd_geninit(void)
int __init hd_init(void)
{
- if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
return -1;
}
diff --git a/drivers/block/icside.c b/drivers/block/icside.c
index 166d29abf..d0e8f8328 100644
--- a/drivers/block/icside.c
+++ b/drivers/block/icside.c
@@ -24,6 +24,8 @@
#include <asm/ecard.h>
#include <asm/io.h>
+extern char *ide_xfer_verbose (byte xfer_rate);
+
/*
* Maximum number of interfaces per card
*/
diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c
index 48cf87c81..0f032ac8c 100644
--- a/drivers/block/ide-cd.c
+++ b/drivers/block/ide-cd.c
@@ -299,7 +299,6 @@
* Generic packet command support and error handling routines.
*/
-
/* Mark that we've seen a media change, and invalidate our internal
buffers. */
static void cdrom_saw_media_change (ide_drive_t *drive)
@@ -2270,7 +2269,12 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
devinfo->mask |= CDC_PLAY_AUDIO;
if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
devinfo->mask |= CDC_CLOSE_TRAY;
-
+
+ devinfo->de = devfs_register (drive->de, "cd", 2, DEVFS_FL_DEFAULT,
+ HWIF(drive)->major, minor,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ ide_fops, NULL);
+
return register_cdrom (devinfo);
}
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index 1209aa82a..e62295241 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -744,6 +744,8 @@ static int idedisk_cleanup (ide_drive_t *drive)
static void idedisk_setup (ide_drive_t *drive)
{
+ int i;
+
struct hd_driveid *id = drive->id;
unsigned long capacity;
@@ -764,6 +766,15 @@ static void idedisk_setup (ide_drive_t *drive)
drive->doorlocking = 1;
}
}
+ for (i = 0; i < MAX_DRIVES; ++i) {
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (drive != &hwif->drives[i]) continue;
+ hwif->gd->de_arr[i] = drive->de;
+ if (drive->removable)
+ hwif->gd->flags[i] |= GENHD_FL_REMOVABLE;
+ break;
+ }
/* Extract geometry if we did not already have one for the drive */
if (!drive->cyl || !drive->head || !drive->sect) {
diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c
index 1e450b7e6..3b6f5e56a 100644
--- a/drivers/block/ide-dma.c
+++ b/drivers/block/ide-dma.c
@@ -214,6 +214,10 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
struct scatterlist *sg = hwif->sg_table;
int nents = 0;
+ if (rq->cmd == READ)
+ hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+ else
+ hwif->sg_dma_direction = PCI_DMA_TODEVICE;
bh = rq->bh;
do {
unsigned char *virt_addr = bh->b_data;
@@ -230,7 +234,7 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
nents++;
} while (bh != NULL);
- return pci_map_sg(hwif->pci_dev, sg, nents);
+ return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
}
/*
@@ -265,7 +269,8 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
printk("%s: DMA table too small\n", drive->name);
pci_unmap_sg(HWIF(drive)->pci_dev,
HWIF(drive)->sg_table,
- HWIF(drive)->sg_nents);
+ HWIF(drive)->sg_nents,
+ HWIF(drive)->sg_dma_direction);
return 0; /* revert to PIO for this request */
} else {
u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
@@ -301,7 +306,7 @@ void ide_destroy_dmatable (ide_drive_t *drive)
struct scatterlist *sg = HWIF(drive)->sg_table;
int nents = HWIF(drive)->sg_nents;
- pci_unmap_sg(dev, sg, nents);
+ pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
}
/*
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index b24933637..e2977c754 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -1549,6 +1549,15 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
(void) idefloppy_get_capacity (drive);
idefloppy_add_settings(drive);
+ for (i = 0; i < MAX_DRIVES; ++i) {
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (drive != &hwif->drives[i]) continue;
+ hwif->gd->de_arr[i] = drive->de;
+ if (drive->removable)
+ hwif->gd->flags[i] |= GENHD_FL_REMOVABLE;
+ break;
+ }
}
static int idefloppy_cleanup (ide_drive_t *drive)
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index 33ca2900b..b57fa28da 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -406,7 +406,7 @@ static void probe_hwif (ide_hwif_t *hwif)
ide_ioreg_t ide_control_reg = hwif->io_ports[IDE_CONTROL_OFFSET];
ide_ioreg_t region_low = hwif->io_ports[IDE_DATA_OFFSET];
ide_ioreg_t region_high = region_low;
- ide_ioreg_t region_request = 8;
+ unsigned int region_request = 8;
int i;
if (hwif->noprobe)
@@ -699,13 +699,28 @@ static void init_gendisk (ide_hwif_t *hwif)
gd->nr_real = units; /* current num real drives */
gd->real_devices= hwif; /* ptr to internal data */
gd->next = NULL; /* linked list of major devs */
+ gd->fops = ide_fops; /* file operations */
+ gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
+ gd->flags = kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+ if (gd->de_arr)
+ memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+ if (gd->flags)
+ memset (gd->flags, 0, sizeof *gd->flags * units);
for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ;
hwif->gd = *gdp = gd; /* link onto tail of list */
for (unit = 0; unit < units; ++unit) {
- if (hwif->drives[unit].present)
+ if (hwif->drives[unit].present) {
+ char name[64];
+
ide_add_generic_settings(hwif->drives + unit);
+ sprintf (name, "ide/host%d/bus%d/target%d/lun%d",
+ hwif->channel ? hwif->mate->index : hwif->index,
+ hwif->channel, unit, 0);
+ hwif->drives[unit].de =
+ devfs_mk_dir (NULL, name, 0, NULL);
+ }
}
}
@@ -764,7 +779,7 @@ static int hwif_init (ide_hwif_t *hwif)
printk("%s: request_fn NOT DEFINED\n", hwif->name);
return (hwif->present = 0);
}
- if (register_blkdev (hwif->major, hwif->name, ide_fops)) {
+ if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
return (hwif->present = 0);
}
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index 9d2bc216f..1e1b6e44e 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -396,6 +396,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/major.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/errno.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
@@ -794,6 +795,7 @@ typedef struct {
*/
typedef struct {
ide_drive_t *drive;
+ devfs_handle_t de_r, de_n;
/*
* Since a typical character device operation requires more
@@ -5770,11 +5772,13 @@ static int idetape_cleanup (ide_drive_t *drive)
DRIVER(drive)->busy = 0;
(void) ide_unregister_subdriver (drive);
drive->driver_data = NULL;
+ devfs_unregister (tape->de_r);
+ devfs_unregister (tape->de_n);
kfree (tape);
for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
if (idetape_chrdevs[minor].drive != NULL)
return 0;
- unregister_chrdev (IDETAPE_MAJOR, "ht");
+ devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
idetape_chrdev_present = 0;
return 0;
}
@@ -5871,7 +5875,8 @@ int idetape_init (void)
#endif
return 0;
}
- if (!idetape_chrdev_present && register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
+ if (!idetape_chrdev_present &&
+ devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
MOD_DEC_USE_COUNT;
#if ONSTREAM_DEBUG
@@ -5905,10 +5910,21 @@ int idetape_init (void)
for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
idetape_setup (drive, tape, minor);
idetape_chrdevs[minor].drive = drive;
+ tape->de_r =
+ devfs_register (drive->de, "mt", 2, DEVFS_FL_DEFAULT,
+ HWIF(drive)->major, minor,
+ S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ &idetape_fops, NULL);
+ tape->de_n =
+ devfs_register (drive->de, "mtn", 3, DEVFS_FL_DEFAULT,
+ HWIF(drive)->major, minor + 128,
+ S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ &idetape_fops, NULL);
+ devfs_register_tape (tape->de_r);
supported++; failed--;
} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
if (!idetape_chrdev_present && !supported) {
- unregister_chrdev (IDETAPE_MAJOR, "ht");
+ devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
} else
idetape_chrdev_present = 1;
ide_register_module (&idetape_module);
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 06e1bbcc6..93da9bea2 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -501,8 +501,7 @@ void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
add_blkdev_randomness(MAJOR(rq->rq_dev));
- hwgroup->drive->queue.current_request = rq->next;
- blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL;
+ blkdev_dequeue_request(rq);
hwgroup->rq = NULL;
end_that_request_last(rq);
}
@@ -772,8 +771,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
}
}
spin_lock_irqsave(&io_request_lock, flags);
- drive->queue.current_request = rq->next;
- blk_dev[MAJOR(rq->rq_dev)].request_queue.current_request = NULL;
+ blkdev_dequeue_request(rq);
HWGROUP(drive)->rq = NULL;
rq->rq_status = RQ_INACTIVE;
spin_unlock_irqrestore(&io_request_lock, flags);
@@ -1076,7 +1074,7 @@ static ide_startstop_t start_request (ide_drive_t *drive)
{
ide_startstop_t startstop;
unsigned long block, blockend;
- struct request *rq = drive->queue.current_request;
+ struct request *rq = blkdev_entry_next_request(&drive->queue.queue_head);
unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
ide_hwif_t *hwif = HWIF(drive);
@@ -1159,13 +1157,12 @@ repeat:
best = NULL;
drive = hwgroup->drive;
do {
- if (drive->queue.current_request && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
+ if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
if (!best
|| (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
|| (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
{
- struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major];
- if( !bdev->request_queue.plugged )
+ if( !drive->queue.plugged )
best = drive;
}
}
@@ -1229,7 +1226,6 @@ repeat:
*/
static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
{
- struct blk_dev_struct *bdev;
ide_drive_t *drive;
ide_hwif_t *hwif;
ide_startstop_t startstop;
@@ -1246,9 +1242,6 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
hwgroup->rq = NULL;
drive = hwgroup->drive;
do {
- bdev = &blk_dev[HWIF(drive)->major];
- if( !bdev->request_queue.plugged )
- bdev->request_queue.current_request = NULL; /* (broken since patch-2.1.15) */
if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
sleep = drive->sleep;
} while ((drive = drive->next) != hwgroup->drive);
@@ -1285,10 +1278,9 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
drive->sleep = 0;
drive->service_start = jiffies;
- bdev = &blk_dev[hwif->major];
- if ( bdev->request_queue.plugged ) /* FIXME: paranoia */
+ if ( drive->queue.plugged ) /* paranoia */
printk("%s: Huh? nuking plugged queue\n", drive->name);
- bdev->request_queue.current_request = hwgroup->rq = drive->queue.current_request;
+ hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
/*
* Some systems have trouble with IDE IRQs arriving while
* the driver is still setting things up. So, here we disable
@@ -1670,7 +1662,7 @@ void ide_init_drive_cmd (struct request *rq)
rq->sem = NULL;
rq->bh = NULL;
rq->bhtail = NULL;
- rq->next = NULL;
+ rq->q = NULL;
}
/*
@@ -1703,7 +1695,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
unsigned int major = HWIF(drive)->major;
- struct request *cur_rq;
+ struct list_head * queue_head;
DECLARE_MUTEX_LOCKED(sem);
#ifdef CONFIG_BLK_DEV_PDC4030
@@ -1716,20 +1708,17 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
if (action == ide_wait)
rq->sem = &sem;
spin_lock_irqsave(&io_request_lock, flags);
- cur_rq = drive->queue.current_request;
- if (cur_rq == NULL || action == ide_preempt) {
- rq->next = cur_rq;
- drive->queue.current_request = rq;
+ queue_head = &drive->queue.queue_head;
+ if (list_empty(queue_head) || action == ide_preempt) {
if (action == ide_preempt)
hwgroup->rq = NULL;
} else {
if (action == ide_wait || action == ide_end) {
- while (cur_rq->next != NULL) /* find end of list */
- cur_rq = cur_rq->next;
- }
- rq->next = cur_rq->next;
- cur_rq->next = rq;
+ queue_head = queue_head->prev;
+ } else
+ queue_head = queue_head->next;
}
+ list_add(&rq->queue, queue_head);
ide_do_request(hwgroup, 0);
spin_unlock_irqrestore(&io_request_lock, flags);
if (action == ide_wait) {
@@ -1989,6 +1978,10 @@ void ide_unregister (unsigned int index)
d = hwgroup->drive;
for (i = 0; i < MAX_DRIVES; ++i) {
drive = &hwif->drives[i];
+ if (drive->de) {
+ devfs_unregister (drive->de);
+ drive->de = NULL;
+ }
if (!drive->present)
continue;
while (hwgroup->drive->next != drive)
@@ -2037,6 +2030,10 @@ void ide_unregister (unsigned int index)
gd = *gdp; *gdp = gd->next;
kfree(gd->sizes);
kfree(gd->part);
+ if (gd->de_arr)
+ kfree (gd->de_arr);
+ if (gd->flags)
+ kfree (gd->flags);
kfree(gd);
}
old_hwif = *hwif;
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 3ed507694..808878b3e 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994, Karl Keyte: Added support for disk statistics
+ * Elevator latency, (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
*/
/*
@@ -27,6 +28,8 @@
#include <linux/module.h>
+#define DEBUG_ELEVATOR
+
/*
* MAC Floppy IWM hooks
*/
@@ -147,6 +150,18 @@ request_queue_t * blk_get_queue (kdev_t dev)
return ret;
}
+static inline int get_request_latency(elevator_t * elevator, int rw)
+{
+ int latency;
+
+ if (rw != READ)
+ latency = elevator->write_latency;
+ else
+ latency = elevator->read_latency;
+
+ return latency;
+}
+
void blk_cleanup_queue(request_queue_t * q)
{
memset(q, 0, sizeof(*q));
@@ -167,55 +182,49 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
q->make_request_fn = mfn;
}
-static int ll_merge_fn(request_queue_t *q, struct request *req,
- struct buffer_head *bh)
+static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments)
{
- if (req->bhtail->b_data + req->bhtail->b_size != bh->b_data) {
- if (req->nr_segments < MAX_SEGMENTS) {
- req->nr_segments++;
- return 1;
- }
- return 0;
+ if (req->nr_segments < max_segments) {
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
}
- return 1;
+ return 0;
+}
+
+static int ll_back_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+ return 1;
+ return ll_new_segment(q, req, max_segments);
+}
+
+static int ll_front_merge_fn(request_queue_t *q, struct request *req,
+ struct buffer_head *bh, int max_segments)
+{
+ if (bh->b_data + bh->b_size == req->bh->b_data)
+ return 1;
+ return ll_new_segment(q, req, max_segments);
}
static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
- struct request *next)
+ struct request *next, int max_segments)
{
int total_segments = req->nr_segments + next->nr_segments;
- if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+ if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) {
total_segments--;
+ q->nr_segments--;
+ }
- if (total_segments > MAX_SEGMENTS)
+ if (total_segments > max_segments)
return 0;
req->nr_segments = total_segments;
return 1;
}
-void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
-{
- q->request_fn = rfn;
- q->current_request = NULL;
- q->merge_fn = ll_merge_fn;
- q->merge_requests_fn = ll_merge_requests_fn;
- q->make_request_fn = NULL;
- q->plug_tq.sync = 0;
- q->plug_tq.routine = &generic_unplug_device;
- q->plug_tq.data = q;
- q->plugged = 0;
- /*
- * These booleans describe the queue properties. We set the
- * default (and most common) values here. Other drivers can
- * use the appropriate functions to alter the queue properties.
- * as appropriate.
- */
- q->plug_device_fn = NULL;
- q->head_active = 1;
-}
-
/*
* "plug" the device if there are no outstanding requests: this will
* force the transfer to start only after we have put all the requests
@@ -224,19 +233,44 @@ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
* This is called with interrupts off and no requests on the queue.
* (and with the request spinlock aquired)
*/
-inline void generic_plug_device (request_queue_t *q, kdev_t dev)
+static void generic_plug_device (request_queue_t *q, kdev_t dev)
{
+#ifdef CONFIG_BLK_DEV_MD
if (MAJOR(dev) == MD_MAJOR) {
spin_unlock_irq(&io_request_lock);
BUG();
}
- if (q->current_request)
+#endif
+ if (!list_empty(&q->queue_head))
return;
q->plugged = 1;
queue_task(&q->plug_tq, &tq_disk);
}
+void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
+{
+ INIT_LIST_HEAD(&q->queue_head);
+ q->elevator = ELEVATOR_DEFAULTS;
+ q->request_fn = rfn;
+ q->back_merge_fn = ll_back_merge_fn;
+ q->front_merge_fn = ll_front_merge_fn;
+ q->merge_requests_fn = ll_merge_requests_fn;
+ q->make_request_fn = NULL;
+ q->plug_tq.sync = 0;
+ q->plug_tq.routine = &generic_unplug_device;
+ q->plug_tq.data = q;
+ q->plugged = 0;
+ /*
+ * These booleans describe the queue properties. We set the
+ * default (and most common) values here. Other drivers can
+ * use the appropriate functions to alter the queue properties.
+ * as appropriate.
+ */
+ q->plug_device_fn = generic_plug_device;
+ q->head_active = 1;
+}
+
/*
* remove the plug and let it rip..
*/
@@ -248,7 +282,7 @@ void generic_unplug_device(void * data)
spin_lock_irqsave(&io_request_lock,flags);
if (q->plugged) {
q->plugged = 0;
- if (q->current_request)
+ if (!list_empty(&q->queue_head))
(q->request_fn)(q);
}
spin_unlock_irqrestore(&io_request_lock,flags);
@@ -388,6 +422,119 @@ static inline void drive_stat_acct(struct request *req,
printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
}
+/* elevator */
+
+#define elevator_sequence_after(a,b) ((int)((b)-(a)) < 0)
+#define elevator_sequence_before(a,b) elevator_sequence_after(b,a)
+#define elevator_sequence_after_eq(a,b) ((int)((b)-(a)) <= 0)
+#define elevator_sequence_before_eq(a,b) elevator_sequence_after_eq(b,a)
+
+static inline struct list_head * seek_to_not_starving_chunk(request_queue_t * q,
+ int * lat, int * starving)
+{
+ int sequence = q->elevator.sequence;
+ struct list_head * entry = q->queue_head.prev;
+ int pos = 0;
+
+ do {
+ struct request * req = blkdev_entry_to_request(entry);
+ if (elevator_sequence_before(req->elevator_sequence, sequence)) {
+ *lat -= q->nr_segments - pos;
+ *starving = 1;
+ return entry;
+ }
+ pos += req->nr_segments;
+ } while ((entry = entry->prev) != &q->queue_head);
+
+ *starving = 0;
+
+ return entry->next;
+}
+
+static inline void elevator_merge_requests(elevator_t * e, struct request * req, struct request * next)
+{
+ if (elevator_sequence_before(next->elevator_sequence, req->elevator_sequence))
+ req->elevator_sequence = next->elevator_sequence;
+ if (req->cmd == READ)
+ e->read_pendings--;
+
+}
+
+static inline int elevator_sequence(elevator_t * e, int latency)
+{
+ return latency + e->sequence;
+}
+
+#define elevator_merge_before(q, req, lat) __elevator_merge((q), (req), (lat), 0)
+#define elevator_merge_after(q, req, lat) __elevator_merge((q), (req), (lat), 1)
+static inline void __elevator_merge(request_queue_t * q, struct request * req, int latency, int after)
+{
+ int sequence = elevator_sequence(&q->elevator, latency);
+ if (after)
+ sequence -= req->nr_segments;
+ if (elevator_sequence_before(sequence, req->elevator_sequence)) {
+ if (!after)
+ printk(KERN_WARNING __FUNCTION__
+ ": req latency %d req latency %d\n",
+ req->elevator_sequence - q->elevator.sequence,
+ sequence - q->elevator.sequence);
+ req->elevator_sequence = sequence;
+ }
+}
+
+static inline void elevator_queue(request_queue_t * q,
+ struct request * req,
+ struct list_head * entry,
+ int latency, int starving)
+{
+ struct request * tmp, * __tmp;
+ int __latency = latency;
+
+ __tmp = tmp = blkdev_entry_to_request(entry);
+
+ for (;; tmp = blkdev_next_request(tmp))
+ {
+ if ((latency -= tmp->nr_segments) <= 0)
+ {
+ tmp = __tmp;
+ latency = __latency;
+
+ if (starving)
+ break;
+
+ if (q->head_active && !q->plugged)
+ {
+ latency -= tmp->nr_segments;
+ break;
+ }
+
+ list_add(&req->queue, &q->queue_head);
+ goto after_link;
+ }
+
+ if (tmp->queue.next == &q->queue_head)
+ break;
+
+ {
+ const int after_current = IN_ORDER(tmp,req);
+ const int before_next = IN_ORDER(req,blkdev_next_request(tmp));
+
+ if (!IN_ORDER(tmp,blkdev_next_request(tmp))) {
+ if (after_current || before_next)
+ break;
+ } else {
+ if (after_current && before_next)
+ break;
+ }
+ }
+ }
+
+ list_add(&req->queue, &tmp->queue);
+
+ after_link:
+ req->elevator_sequence = elevator_sequence(&q->elevator, latency);
+}
+
/*
* add-request adds a request to the linked list.
* It disables interrupts (aquires the request spinlock) so that it can muck
@@ -398,32 +545,20 @@ static inline void drive_stat_acct(struct request *req,
* which is important for drive_stat_acct() above.
*/
-static inline void __add_request(request_queue_t * q, struct request * req)
+static inline void __add_request(request_queue_t * q, struct request * req,
+ int empty, struct list_head * entry,
+ int latency, int starving)
{
- int major = MAJOR(req->rq_dev);
- struct request * tmp;
+ int major;
drive_stat_acct(req, req->nr_sectors, 1);
- req->next = NULL;
- if (!(tmp = q->current_request)) {
- q->current_request = req;
+ if (empty) {
+ req->elevator_sequence = elevator_sequence(&q->elevator, latency);
+ list_add(&req->queue, &q->queue_head);
return;
}
- for ( ; tmp->next ; tmp = tmp->next) {
- const int after_current = IN_ORDER(tmp,req);
- const int before_next = IN_ORDER(req,tmp->next);
-
- if (!IN_ORDER(tmp,tmp->next)) {
- if (after_current || before_next)
- break;
- } else {
- if (after_current && before_next)
- break;
- }
- }
- req->next = tmp->next;
- tmp->next = req;
+ elevator_queue(q, req, entry, latency, starving);
/*
* FIXME(eric) I don't understand why there is a need for this
@@ -432,6 +567,7 @@ static inline void __add_request(request_queue_t * q, struct request * req)
* I am leaving this in here until I hear back from the COMPAQ
* people.
*/
+ major = MAJOR(req->rq_dev);
if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7)
{
(q->request_fn)(q);
@@ -448,12 +584,14 @@ static inline void __add_request(request_queue_t * q, struct request * req)
*/
static inline void attempt_merge (request_queue_t * q,
struct request *req,
- int max_sectors)
+ int max_sectors,
+ int max_segments)
{
- struct request *next = req->next;
-
- if (!next)
+ struct request *next;
+
+ if (req->queue.next == &q->queue_head)
return;
+ next = blkdev_next_request(req);
if (req->sector + req->nr_sectors != next->sector)
return;
if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors)
@@ -464,25 +602,79 @@ static inline void attempt_merge (request_queue_t * q,
* will have been updated to the appropriate number,
* and we shouldn't do it here too.
*/
- if(!(q->merge_requests_fn)(q, req, next))
+ if(!(q->merge_requests_fn)(q, req, next, max_segments))
return;
+ elevator_merge_requests(&q->elevator, req, next);
req->bhtail->b_reqnext = next->bh;
req->bhtail = next->bhtail;
req->nr_sectors += next->nr_sectors;
next->rq_status = RQ_INACTIVE;
- req->next = next->next;
+ list_del(&next->queue);
wake_up (&wait_for_request);
}
+static inline void elevator_debug(request_queue_t * q, kdev_t dev)
+{
+#ifdef DEBUG_ELEVATOR
+ int read_pendings = 0, nr_segments = 0;
+ elevator_t * elevator = &q->elevator;
+ struct list_head * entry = &q->queue_head;
+ static int counter;
+
+ if (counter++ % 100)
+ return;
+
+ while ((entry = entry->next) != &q->queue_head)
+ {
+ struct request * req;
+
+ req = blkdev_entry_to_request(entry);
+ if (!req->q)
+ continue;
+ if (req->cmd == READ)
+ read_pendings++;
+ nr_segments += req->nr_segments;
+ }
+
+ if (read_pendings != elevator->read_pendings)
+ {
+ printk(KERN_WARNING
+ "%s: elevator read_pendings %d should be %d\n",
+ kdevname(dev), elevator->read_pendings,
+ read_pendings);
+ elevator->read_pendings = read_pendings;
+ }
+ if (nr_segments != q->nr_segments)
+ {
+ printk(KERN_WARNING
+ "%s: elevator nr_segments %d should be %d\n",
+ kdevname(dev), q->nr_segments,
+ nr_segments);
+ q->nr_segments = nr_segments;
+ }
+#endif
+}
+
+static inline void elevator_account_request(request_queue_t * q, struct request * req)
+{
+ q->elevator.sequence++;
+ if (req->cmd == READ)
+ q->elevator.read_pendings++;
+ q->nr_segments++;
+}
+
static inline void __make_request(request_queue_t * q, int rw,
struct buffer_head * bh)
{
int major = MAJOR(bh->b_rdev);
unsigned int sector, count;
- struct request * req;
+ int max_segments = MAX_SEGMENTS;
+ struct request * req, * prev;
int rw_ahead, max_req, max_sectors;
unsigned long flags;
+ int orig_latency, latency, __latency, starving, __starving, empty;
+ struct list_head * entry, * __entry = NULL;
count = bh->b_size >> 9;
sector = bh->b_rsector;
@@ -569,21 +761,33 @@ static inline void __make_request(request_queue_t * q, int rw,
*/
max_sectors = get_max_sectors(bh->b_rdev);
+ __latency = orig_latency = get_request_latency(&q->elevator, rw);
+
/*
* Now we acquire the request spinlock, we have to be mega careful
* not to schedule or do something nonatomic
*/
spin_lock_irqsave(&io_request_lock,flags);
- req = q->current_request;
- if (!req) {
- /* MD and loop can't handle plugging without deadlocking */
- if (q->plug_device_fn)
- q->plug_device_fn(q, bh->b_rdev); /* is atomic */
- else
- generic_plug_device(q, bh->b_rdev); /* is atomic */
+ elevator_debug(q, bh->b_rdev);
+
+ empty = 0;
+ if (list_empty(&q->queue_head)) {
+ empty = 1;
+ q->plug_device_fn(q, bh->b_rdev); /* is atomic */
goto get_rq;
}
+ /* avoid write-bombs to not hurt iteractiveness of reads */
+ if (rw != READ && q->elevator.read_pendings)
+ max_segments = q->elevator.max_bomb_segments;
+
+ entry = seek_to_not_starving_chunk(q, &__latency, &starving);
+
+ __entry = entry;
+ __starving = starving;
+
+ latency = __latency;
+
if (q->head_active && !q->plugged) {
/*
* The scsi disk and cdrom drivers completely remove the request
@@ -595,11 +799,18 @@ static inline void __make_request(request_queue_t * q, int rw,
* entry may be busy being processed and we thus can't change
* it.
*/
- if ((req = req->next) == NULL)
- goto get_rq;
+ if (entry == q->queue_head.next) {
+ latency -= blkdev_entry_to_request(entry)->nr_segments;
+ if ((entry = entry->next) == &q->queue_head)
+ goto get_rq;
+ starving = 0;
+ }
}
+ prev = NULL;
do {
+ req = blkdev_entry_to_request(entry);
+
if (req->sem)
continue;
if (req->cmd != rw)
@@ -610,6 +821,8 @@ static inline void __make_request(request_queue_t * q, int rw,
continue;
/* Can we add it to the end of this request? */
if (req->sector + req->nr_sectors == sector) {
+ if (latency - req->nr_segments < 0)
+ break;
/*
* The merge_fn is a more advanced way
* of accomplishing the same task. Instead
@@ -622,16 +835,21 @@ static inline void __make_request(request_queue_t * q, int rw,
* may suggest that we shouldn't merge
* this
*/
- if(!(q->merge_fn)(q, req, bh))
+ if(!(q->back_merge_fn)(q, req, bh, max_segments))
continue;
req->bhtail->b_reqnext = bh;
req->bhtail = bh;
req->nr_sectors += count;
drive_stat_acct(req, count, 0);
+
+ elevator_merge_after(q, req, latency);
+
/* Can we now merge this req with the next? */
- attempt_merge(q, req, max_sectors);
+ attempt_merge(q, req, max_sectors, max_segments);
/* or to the beginning? */
} else if (req->sector - count == sector) {
+ if (!prev && starving)
+ continue;
/*
* The merge_fn is a more advanced way
* of accomplishing the same task. Instead
@@ -644,7 +862,7 @@ static inline void __make_request(request_queue_t * q, int rw,
* may suggest that we shouldn't merge
* this
*/
- if(!(q->merge_fn)(q, req, bh))
+ if(!(q->front_merge_fn)(q, req, bh, max_segments))
continue;
bh->b_reqnext = req->bh;
req->bh = bh;
@@ -653,13 +871,21 @@ static inline void __make_request(request_queue_t * q, int rw,
req->sector = sector;
req->nr_sectors += count;
drive_stat_acct(req, count, 0);
+
+ elevator_merge_before(q, req, latency);
+
+ if (prev)
+ attempt_merge(q, prev, max_sectors, max_segments);
} else
continue;
+ q->elevator.sequence++;
spin_unlock_irqrestore(&io_request_lock,flags);
return;
- } while ((req = req->next) != NULL);
+ } while (prev = req,
+ (latency -= req->nr_segments) >= 0 &&
+ (entry = entry->next) != &q->queue_head);
/* find an unused request. */
get_rq:
@@ -675,6 +901,14 @@ get_rq:
goto end_io;
req = __get_request_wait(max_req, bh->b_rdev);
spin_lock_irqsave(&io_request_lock,flags);
+
+ /* lock got dropped so revalidate elevator */
+ empty = 1;
+ if (!list_empty(&q->queue_head)) {
+ empty = 0;
+ __latency = orig_latency;
+ __entry = seek_to_not_starving_chunk(q, &__latency, &__starving);
+ }
}
/*
* Dont start the IO if the buffer has been
@@ -707,8 +941,10 @@ get_rq:
req->sem = NULL;
req->bh = bh;
req->bhtail = bh;
- req->next = NULL;
- __add_request(q, req);
+ req->q = q;
+ __add_request(q, req, empty, __entry, __latency, __starving);
+ elevator_account_request(q, req);
+
spin_unlock_irqrestore(&io_request_lock, flags);
return;
@@ -867,6 +1103,8 @@ int end_that_request_first (struct request *req, int uptodate, char *name)
void end_that_request_last(struct request *req)
{
+ if (req->q)
+ BUG();
if (req->sem != NULL)
up(req->sem);
req->rq_status = RQ_INACTIVE;
@@ -886,7 +1124,6 @@ int __init blk_dev_init(void)
req = all_requests + NR_REQUEST;
while (--req >= all_requests) {
req->rq_status = RQ_INACTIVE;
- req->next = NULL;
}
memset(ro_bits,0,sizeof(ro_bits));
memset(max_readahead, 0, sizeof(max_readahead));
@@ -1001,4 +1238,5 @@ EXPORT_SYMBOL(blk_init_queue);
EXPORT_SYMBOL(blk_cleanup_queue);
EXPORT_SYMBOL(blk_queue_headactive);
EXPORT_SYMBOL(blk_queue_pluggable);
+EXPORT_SYMBOL(blk_queue_make_request);
EXPORT_SYMBOL(generic_make_request);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 587156935..3209aa46b 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -14,6 +14,8 @@
*
* Fixed do_loop_request() re-entrancy - Vincent.Renardias@waw.com Mar 20, 1997
*
+ * Added devfs support - Richard Gooch <rgooch@atnf.csiro.au> 16-Jan-1998
+ *
* Handle sparse backing files correctly - Kenn Humborg, Jun 28, 1998
*
* Loadable modules and other fixes by AK, 1998
@@ -40,6 +42,10 @@
* it passes the underlying device's block number instead of the
* offset. This makes it change for a given block when the file is
* moved/restored/copied and also doesn't work over NFS.
+ * AV, Feb 12, 2000: we pass the logical block number now. It fixes the
+ * problem above. Encryption modules that used to rely on the old scheme
+ * should just call ->i_mapping->bmap() to calculate the physical block
+ * number.
*/
#include <linux/module.h>
@@ -52,6 +58,7 @@
#include <linux/major.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
@@ -73,14 +80,11 @@ static int max_loop = 8;
static struct loop_device *loop_dev;
static int *loop_sizes;
static int *loop_blksizes;
+static devfs_handle_t devfs_handle = NULL; /* For the directory */
#define FALSE 0
#define TRUE (!FALSE)
-/* Forward declaration of function to create missing blocks in the
- backing file (can happen if the backing file is sparse) */
-static int create_missing_block(struct loop_device *lo, int block, int blksize);
-
/*
* Transfer functions
*/
@@ -164,24 +168,133 @@ static void figure_loop_size(struct loop_device *lo)
loop_sizes[lo->lo_number] = size;
}
+static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos,
+ int blksize)
+{
+ struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
+ struct address_space *mapping = lo->lo_dentry->d_inode->i_mapping;
+ struct address_space_operations *aops = mapping->a_ops;
+ struct page *page;
+ char *kaddr;
+ unsigned long index;
+ unsigned size, offset;
+
+ index = pos >> PAGE_CACHE_SHIFT;
+ offset = pos & (PAGE_CACHE_SIZE - 1);
+ while (len > 0) {
+ int IV = index * (PAGE_CACHE_SIZE/blksize) + offset/blksize;
+ size = PAGE_CACHE_SIZE - offset;
+ if (size > len)
+ size = len;
+
+ page = grab_cache_page(mapping, index);
+ if (!page)
+ goto fail;
+ if (aops->prepare_write(page, offset, offset+size))
+ goto unlock;
+ kaddr = (char*)page_address(page);
+ if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV))
+ goto write_fail;
+ if (aops->commit_write(file, page, offset, offset+size))
+ goto unlock;
+ data += size;
+ len -= size;
+ offset = 0;
+ index++;
+ pos += size;
+ UnlockPage(page);
+ page_cache_release(page);
+ }
+ return 0;
+
+write_fail:
+ printk(KERN_ERR "loop: transfer error block %ld\n", index);
+ ClearPageUptodate(page);
+ kunmap(page);
+unlock:
+ UnlockPage(page);
+ page_cache_release(page);
+fail:
+ return -1;
+}
+
+struct lo_read_data {
+ struct loop_device *lo;
+ char *data;
+ int blksize;
+};
+
+static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
+{
+ char *kaddr;
+ unsigned long count = desc->count;
+ struct lo_read_data *p = (struct lo_read_data*)desc->buf;
+ struct loop_device *lo = p->lo;
+ int IV = page->index * (PAGE_CACHE_SIZE/p->blksize) + offset/p->blksize;
+
+ if (size > count)
+ size = count;
+
+ kaddr = (char*)kmap(page);
+ if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) {
+ size = 0;
+ printk(KERN_ERR "loop: transfer error block %ld\n",page->index);
+ desc->error = -EINVAL;
+ }
+ kunmap(page);
+
+ desc->count = count - size;
+ desc->written += size;
+ p->data += size;
+ return size;
+}
+
+static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos,
+ int blksize)
+{
+ struct file *file = lo->lo_backing_file;
+ struct lo_read_data cookie;
+ read_descriptor_t desc;
+
+ cookie.lo = lo;
+ cookie.data = data;
+ cookie.blksize = blksize;
+ desc.written = 0;
+ desc.count = len;
+ desc.buf = (char*)&cookie;
+ desc.error = 0;
+ do_generic_file_read(file, &pos, &desc, lo_read_actor);
+ return desc.error;
+}
+
static void do_lo_request(request_queue_t * q)
{
- int real_block, block, offset, len, blksize, size;
+ int block, offset, len, blksize, size;
char *dest_addr;
struct loop_device *lo;
struct buffer_head *bh;
struct request *current_request;
- int block_present;
+ loff_t pos;
repeat:
INIT_REQUEST;
current_request=CURRENT;
- CURRENT=current_request->next;
+ blkdev_dequeue_request(current_request);
if (MINOR(current_request->rq_dev) >= max_loop)
goto error_out;
lo = &loop_dev[MINOR(current_request->rq_dev)];
if (!lo->lo_dentry || !lo->transfer)
goto error_out;
+ if (current_request->cmd == WRITE) {
+ if (lo->lo_flags & LO_FLAGS_READ_ONLY)
+ goto error_out;
+ } else if (current_request->cmd != READ) {
+ printk(KERN_ERR "unknown loop device command (%d)?!?", current_request->cmd);
+ goto error_out;
+ }
+
+ dest_addr = current_request->buffer;
+ len = current_request->current_nr_sectors << 9;
blksize = BLOCK_SIZE;
if (blksize_size[MAJOR(lo->lo_device)]) {
@@ -190,8 +303,9 @@ repeat:
blksize = BLOCK_SIZE;
}
- dest_addr = current_request->buffer;
-
+ if (lo->lo_flags & LO_FLAGS_DO_BMAP)
+ goto file_backed;
+
if (blksize < 512) {
block = current_request->sector * (512/blksize);
offset = 0;
@@ -201,155 +315,79 @@ repeat:
}
block += lo->lo_offset / blksize;
offset += lo->lo_offset % blksize;
- if (offset > blksize) {
+ if (offset >= blksize) {
block++;
offset -= blksize;
}
- len = current_request->current_nr_sectors << 9;
-
- if (current_request->cmd == WRITE) {
- if (lo->lo_flags & LO_FLAGS_READ_ONLY)
- goto error_out;
- } else if (current_request->cmd != READ) {
- printk(KERN_ERR "unknown loop device command (%d)?!?", current_request->cmd);
- goto error_out;
- }
spin_unlock_irq(&io_request_lock);
+
while (len > 0) {
size = blksize - offset;
if (size > len)
size = len;
- real_block = block;
- block_present = TRUE;
-
- if (lo->lo_flags & LO_FLAGS_DO_BMAP) {
- real_block = bmap(lo->lo_dentry->d_inode, block);
- if (!real_block) {
-
- /* The backing file is a sparse file and this block
- doesn't exist. If reading, return zeros. If
- writing, force the underlying FS to create
- the block */
- if (current_request->cmd == READ) {
- memset(dest_addr, 0, size);
- block_present = FALSE;
- } else {
- if (!create_missing_block(lo, block, blksize)) {
- goto error_out_lock;
- }
- real_block = bmap(lo->lo_dentry->d_inode, block);
- }
-
- }
+ bh = getblk(lo->lo_device, block, blksize);
+ if (!bh) {
+ printk(KERN_ERR "loop: device %s: getblk(-, %d, %d) returned NULL",
+ kdevname(lo->lo_device),
+ block, blksize);
+ goto error_out_lock;
}
-
- if (block_present) {
- bh = getblk(lo->lo_device, real_block, blksize);
- if (!bh) {
- printk(KERN_ERR "loop: device %s: getblk(-, %d, %d) returned NULL",
- kdevname(lo->lo_device),
- block, blksize);
- goto error_out_lock;
- }
- if (!buffer_uptodate(bh) && ((current_request->cmd == READ) ||
- (offset || (len < blksize)))) {
- ll_rw_block(READ, 1, &bh);
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh)) {
- brelse(bh);
- goto error_out_lock;
- }
- }
-
- if ((lo->transfer)(lo, current_request->cmd, bh->b_data + offset,
- dest_addr, size, real_block)) {
- printk(KERN_ERR "loop: transfer error block %d\n", block);
+ if (!buffer_uptodate(bh) && ((current_request->cmd == READ) ||
+ (offset || (len < blksize)))) {
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
brelse(bh);
goto error_out_lock;
}
+ }
- if (current_request->cmd == WRITE) {
- mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
- }
+ if ((lo->transfer)(lo, current_request->cmd, bh->b_data + offset,
+ dest_addr, size, block)) {
+ printk(KERN_ERR "loop: transfer error block %d\n", block);
brelse(bh);
+ goto error_out_lock;
+ }
+
+ if (current_request->cmd == WRITE) {
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ brelse(bh);
dest_addr += size;
len -= size;
offset = 0;
block++;
}
+ goto done;
+
+file_backed:
+ pos = ((loff_t)current_request->sector << 9) + lo->lo_offset;
+ spin_unlock_irq(&io_request_lock);
+ if (current_request->cmd == WRITE) {
+ if (lo_send(lo, dest_addr, len, pos, blksize))
+ goto error_out_lock;
+ } else {
+ if (lo_receive(lo, dest_addr, len, pos, blksize))
+ goto error_out_lock;
+ }
+done:
spin_lock_irq(&io_request_lock);
- current_request->next=CURRENT;
- CURRENT=current_request;
+ current_request->sector += current_request->current_nr_sectors;
+ current_request->nr_sectors -= current_request->current_nr_sectors;
+ list_add(&current_request->queue, &q->queue_head);
end_request(1);
goto repeat;
error_out_lock:
spin_lock_irq(&io_request_lock);
error_out:
- current_request->next=CURRENT;
- CURRENT=current_request;
+ list_add(&current_request->queue, &q->queue_head);
end_request(0);
goto repeat;
}
-static int create_missing_block(struct loop_device *lo, int block, int blksize)
-{
- struct file *file;
- loff_t new_offset;
- char zero_buf[1] = { 0 };
- ssize_t retval;
- mm_segment_t old_fs;
- struct inode *inode;
-
- file = lo->lo_backing_file;
- if (file == NULL) {
- printk(KERN_WARNING "loop: cannot create block - no backing file\n");
- return FALSE;
- }
-
- if (file->f_op == NULL) {
- printk(KERN_WARNING "loop: cannot create block - no file ops\n");
- return FALSE;
- }
-
- new_offset = block * blksize;
-
- if (file->f_op->llseek != NULL) {
- file->f_op->llseek(file, new_offset, 0);
- } else {
- /* Do what the default llseek() code would have done */
- file->f_pos = new_offset;
- file->f_reada = 0;
- file->f_version = ++event;
- }
-
- if (file->f_op->write == NULL) {
- printk(KERN_WARNING "loop: cannot create block - file not writeable\n");
- return FALSE;
- }
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- inode = file->f_dentry->d_inode;
- down(&inode->i_sem);
- retval = file->f_op->write(file, zero_buf, 1, &file->f_pos);
- up(&inode->i_sem);
-
- set_fs(old_fs);
-
- if (retval < 0) {
- printk(KERN_WARNING "loop: cannot create block - FS write failed: code %Zi\n",
- retval);
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
{
struct file *file;
@@ -386,22 +424,13 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
a file structure */
lo->lo_backing_file = NULL;
} else if (S_ISREG(inode->i_mode)) {
- /*
- * Total crap. We should just use pagecache instead of trying
- * to redirect on block level.
- */
- if (!inode->i_mapping->a_ops->bmap) {
- printk(KERN_ERR "loop: device has no block access/not implemented\n");
- goto out_putf;
- }
-
- /* Backed by a regular file - we need to hold onto
- a file structure for this file. We'll use it to
- write to blocks that are not already present in
- a sparse file. We create a new file structure
- based on the one passed to us via 'arg'. This is
- to avoid changing the file structure that the
- caller is using */
+ struct address_space_operations *aops;
+ /* Backed by a regular file - we need to hold onto a file
+ structure for this file. Friggin' NFS can't live without
+ it on write and for reading we use do_generic_file_read(),
+ so... We create a new file structure based on the one
+ passed to us via 'arg'. This is to avoid changing the file
+ structure that the caller is using */
lo->lo_device = inode->i_dev;
lo->lo_flags = LO_FLAGS_DO_BMAP;
@@ -424,17 +453,23 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
lo->lo_backing_file = NULL;
}
}
+ aops = inode->i_mapping->a_ops;
+ /*
+ * If we can't read - sorry. If we only can't write - well,
+ * it's going to be read-only.
+ */
+ if (!aops->readpage)
+ error = -EINVAL;
+ else if (!aops->prepare_write || !aops->commit_write)
+ lo->lo_flags |= LO_FLAGS_READ_ONLY;
}
if (error)
goto out_putf;
- if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) {
+ if (IS_RDONLY (inode) || is_read_only(lo->lo_device))
lo->lo_flags |= LO_FLAGS_READ_ONLY;
- set_device_ro(dev, 1);
- } else {
- vmtruncate (inode, 0);
- set_device_ro(dev, 0);
- }
+
+ set_device_ro(dev, (lo->lo_flags & LO_FLAGS_READ_ONLY)!=0);
lo->lo_dentry = dget(file->f_dentry);
lo->transfer = NULL;
@@ -719,11 +754,16 @@ int __init loop_init(void)
{
int i;
- if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
printk(KERN_WARNING "Unable to get major number %d for loop device\n",
MAJOR_NR);
return -EIO;
}
+ devfs_handle = devfs_mk_dir (NULL, "loop", 0, NULL);
+ devfs_register_series (devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
+ MAJOR_NR, 0,
+ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ &lo_fops, NULL);
if ((max_loop < 1) || (max_loop > 255)) {
printk (KERN_WARNING "loop: invalid max_loop (must be between 1 and 255), using default (8)\n");
@@ -755,6 +795,7 @@ int __init loop_init(void)
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
for (i=0; i < max_loop; i++) {
memset(&loop_dev[i], 0, sizeof(struct loop_device));
loop_dev[i].lo_number = i;
@@ -772,7 +813,8 @@ int __init loop_init(void)
#ifdef MODULE
void cleanup_module(void)
{
- if (unregister_blkdev(MAJOR_NR, "loop") != 0)
+ devfs_unregister (devfs_handle);
+ if (devfs_unregister_blkdev(MAJOR_NR, "loop") != 0)
printk(KERN_WARNING "loop: cannot unregister blkdev\n");
kfree (loop_dev);
diff --git a/drivers/block/lvm-snap.c b/drivers/block/lvm-snap.c
new file mode 100644
index 000000000..77500cc43
--- /dev/null
+++ b/drivers/block/lvm-snap.c
@@ -0,0 +1,434 @@
+/*
+ * kernel/lvm-snap.c
+ *
+ * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ *
+ * LVM snapshot driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * LVM driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/blkdev.h>
+#include <linux/smp_lock.h>
+#include <linux/types.h>
+#include <linux/iobuf.h>
+#include <linux/lvm.h>
+
+
+static char *lvm_snap_version = "LVM 0.8final (15/02/2000)\n";
+
+extern const char *const lvm_name;
+extern int lvm_blocksizes[];
+
+void lvm_snapshot_release(lv_t *);
+
+#define hashfn(dev,block,mask,chunk_size) \
+ ((HASHDEV(dev)^((block)/(chunk_size))) & (mask))
+
+static inline lv_block_exception_t *
+lvm_find_exception_table(kdev_t org_dev, unsigned long org_start, lv_t * lv)
+{
+ struct list_head * hash_table = lv->lv_snapshot_hash_table, * next;
+ unsigned long mask = lv->lv_snapshot_hash_mask;
+ int chunk_size = lv->lv_chunk_size;
+ lv_block_exception_t * ret;
+ int i = 0;
+
+ hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
+ ret = NULL;
+ for (next = hash_table->next; next != hash_table; next = next->next)
+ {
+ lv_block_exception_t * exception;
+
+ exception = list_entry(next, lv_block_exception_t, hash);
+ if (exception->rsector_org == org_start &&
+ exception->rdev_org == org_dev)
+ {
+ if (i)
+ {
+ /* fun, isn't it? :) */
+ list_del(next);
+ list_add(next, hash_table);
+ }
+ ret = exception;
+ break;
+ }
+ i++;
+ }
+ return ret;
+}
+
+static inline void lvm_hash_link(lv_block_exception_t * exception,
+ kdev_t org_dev, unsigned long org_start,
+ lv_t * lv)
+{
+ struct list_head * hash_table = lv->lv_snapshot_hash_table;
+ unsigned long mask = lv->lv_snapshot_hash_mask;
+ int chunk_size = lv->lv_chunk_size;
+
+ hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
+ list_add(&exception->hash, hash_table);
+}
+
+int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector,
+ unsigned long pe_start, lv_t * lv)
+{
+ int ret;
+ unsigned long pe_off, pe_adjustment, __org_start;
+ kdev_t __org_dev;
+ int chunk_size = lv->lv_chunk_size;
+ lv_block_exception_t * exception;
+
+ pe_off = pe_start % chunk_size;
+ pe_adjustment = (*org_sector-pe_off) % chunk_size;
+ __org_start = *org_sector - pe_adjustment;
+ __org_dev = *org_dev;
+
+ ret = 0;
+ exception = lvm_find_exception_table(__org_dev, __org_start, lv);
+ if (exception)
+ {
+ *org_dev = exception->rdev_new;
+ *org_sector = exception->rsector_new + pe_adjustment;
+ ret = 1;
+ }
+ return ret;
+}
+
+static void lvm_drop_snapshot(lv_t * lv_snap, const char * reason)
+{
+ kdev_t last_dev;
+ int i;
+
+ /* no exception storage space available for this snapshot
+ or error on this snapshot --> release it */
+ invalidate_buffers(lv_snap->lv_dev);
+
+ for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) {
+ if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) {
+ last_dev = lv_snap->lv_block_exception[i].rdev_new;
+ invalidate_buffers(last_dev);
+ }
+ }
+
+ lvm_snapshot_release(lv_snap);
+
+ printk(KERN_INFO
+ "%s -- giving up to snapshot %s on %s due %s\n",
+ lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name,
+ reason);
+}
+
+static inline void lvm_snapshot_prepare_blocks(unsigned long * blocks,
+ unsigned long start,
+ int nr_sectors,
+ int blocksize)
+{
+ int i, sectors_per_block, nr_blocks;
+
+ sectors_per_block = blocksize >> 9;
+ nr_blocks = nr_sectors / sectors_per_block;
+ start /= sectors_per_block;
+
+ for (i = 0; i < nr_blocks; i++)
+ blocks[i] = start++;
+}
+
+static inline int get_blksize(kdev_t dev)
+{
+ int correct_size = BLOCK_SIZE, i, major;
+
+ major = MAJOR(dev);
+ if (blksize_size[major])
+ {
+ i = blksize_size[major][MINOR(dev)];
+ if (i)
+ correct_size = i;
+ }
+ return correct_size;
+}
+
+#ifdef DEBUG_SNAPSHOT
+static inline void invalidate_snap_cache(unsigned long start, unsigned long nr,
+ kdev_t dev)
+{
+ struct buffer_head * bh;
+ int sectors_per_block, i, blksize, minor;
+
+ minor = MINOR(dev);
+ blksize = lvm_blocksizes[minor];
+ sectors_per_block = blksize >> 9;
+ nr /= sectors_per_block;
+ start /= sectors_per_block;
+
+ for (i = 0; i < nr; i++)
+ {
+ bh = get_hash_table(dev, start++, blksize);
+ if (bh)
+ bforget(bh);
+ }
+}
+#endif
+
+/*
+ * copy on write handler for one snapshot logical volume
+ *
+ * read the original blocks and store it/them on the new one(s).
+ * if there is no exception storage space free any longer --> release snapshot.
+ *
+ * this routine gets called for each _first_ write to a physical chunk.
+ */
+int lvm_snapshot_COW(kdev_t org_phys_dev,
+ unsigned long org_phys_sector,
+ unsigned long org_pe_start,
+ unsigned long org_virt_sector,
+ lv_t * lv_snap)
+{
+ const char * reason;
+ unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off;
+ int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size;
+ struct kiobuf * iobuf;
+ unsigned long blocks[KIO_MAX_SECTORS];
+ int blksize_snap, blksize_org, min_blksize, max_blksize;
+ int max_sectors, nr_sectors;
+
+ /* check if we are out of snapshot space */
+ if (idx >= lv_snap->lv_remap_end)
+ goto fail_out_of_space;
+
+ /* calculate physical boundaries of source chunk */
+ pe_off = org_pe_start % chunk_size;
+ org_start = org_phys_sector - ((org_phys_sector-pe_off) % chunk_size);
+ virt_start = org_virt_sector - (org_phys_sector - org_start);
+
+ /* calculate physical boundaries of destination chunk */
+ snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
+ snap_start = lv_snap->lv_block_exception[idx].rsector_new;
+
+#ifdef DEBUG_SNAPSHOT
+ printk(KERN_INFO
+ "%s -- COW: "
+ "org %02d:%02d faulting %lu start %lu, "
+ "snap %02d:%02d start %lu, "
+ "size %d, pe_start %lu pe_off %lu, virt_sec %lu\n",
+ lvm_name,
+ MAJOR(org_phys_dev), MINOR(org_phys_dev), org_phys_sector,
+ org_start,
+ MAJOR(snap_phys_dev), MINOR(snap_phys_dev), snap_start,
+ chunk_size,
+ org_pe_start, pe_off,
+ org_virt_sector);
+#endif
+
+ iobuf = lv_snap->lv_iobuf;
+
+ blksize_org = get_blksize(org_phys_dev);
+ blksize_snap = get_blksize(snap_phys_dev);
+ max_blksize = max(blksize_org, blksize_snap);
+ min_blksize = min(blksize_org, blksize_snap);
+ max_sectors = KIO_MAX_SECTORS * (min_blksize>>9);
+
+ if (chunk_size % (max_blksize>>9))
+ goto fail_blksize;
+
+ while (chunk_size)
+ {
+ nr_sectors = min(chunk_size, max_sectors);
+ chunk_size -= nr_sectors;
+
+ iobuf->length = nr_sectors << 9;
+
+ lvm_snapshot_prepare_blocks(blocks, org_start,
+ nr_sectors, blksize_org);
+ if (brw_kiovec(READ, 1, &iobuf, org_phys_dev,
+ blocks, blksize_org) != (nr_sectors<<9))
+ goto fail_raw_read;
+
+ lvm_snapshot_prepare_blocks(blocks, snap_start,
+ nr_sectors, blksize_snap);
+ if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev,
+ blocks, blksize_snap) != (nr_sectors<<9))
+ goto fail_raw_write;
+ }
+
+#ifdef DEBUG_SNAPSHOT
+ /* invalidate the logcial snapshot buffer cache */
+ invalidate_snap_cache(virt_start, lv_snap->lv_chunk_size,
+ lv_snap->lv_dev);
+#endif
+
+ /* the original chunk is now stored on the snapshot volume
+ so update the execption table */
+ lv_snap->lv_block_exception[idx].rdev_org = org_phys_dev;
+ lv_snap->lv_block_exception[idx].rsector_org = org_start;
+ lvm_hash_link(lv_snap->lv_block_exception + idx,
+ org_phys_dev, org_start, lv_snap);
+ lv_snap->lv_remap_ptr = idx + 1;
+ return 0;
+
+ /* slow path */
+ out:
+ lvm_drop_snapshot(lv_snap, reason);
+ return 1;
+
+ fail_out_of_space:
+ reason = "out of space";
+ goto out;
+ fail_raw_read:
+ reason = "read error";
+ goto out;
+ fail_raw_write:
+ reason = "write error";
+ goto out;
+ fail_blksize:
+ reason = "blocksize error";
+ goto out;
+}
+
+static int lvm_snapshot_alloc_iobuf_pages(struct kiobuf * iobuf, int sectors)
+{
+ int bytes, nr_pages, err, i;
+
+ bytes = sectors << 9;
+ nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT;
+ err = expand_kiobuf(iobuf, nr_pages);
+ if (err)
+ goto out;
+
+ err = -ENOMEM;
+ iobuf->locked = 1;
+ iobuf->nr_pages = 0;
+ for (i = 0; i < nr_pages; i++)
+ {
+ struct page * page;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)
+ page = alloc_page(GFP_KERNEL);
+ if (!page)
+ goto out;
+#else
+ {
+ unsigned long addr = __get_free_page(GFP_USER);
+ if (!addr)
+ goto out;
+ iobuf->pagelist[i] = addr;
+ page = mem_map + MAP_NR(addr);
+ }
+#endif
+
+ iobuf->maplist[i] = page;
+ /* the only point to lock the page here is to be allowed
+ to share unmap_kiobuf() in the fail-path */
+#ifndef LockPage
+#define LockPage(map) set_bit(PG_locked, &(map)->flags)
+#endif
+ LockPage(page);
+ iobuf->nr_pages++;
+ }
+ iobuf->offset = 0;
+
+ err = 0;
+ out:
+ return err;
+}
+
+static int calc_max_buckets(void)
+{
+ unsigned long mem;
+
+ mem = num_physpages << PAGE_SHIFT;
+ mem /= 100;
+ mem *= 2;
+ mem /= sizeof(struct list_head);
+
+ return mem;
+}
+
+static int lvm_snapshot_alloc_hash_table(lv_t * lv)
+{
+ int err;
+ unsigned long buckets, max_buckets, size;
+ struct list_head * hash;
+
+ buckets = lv->lv_remap_end;
+ max_buckets = calc_max_buckets();
+ buckets = min(buckets, max_buckets);
+ while (buckets & (buckets-1))
+ buckets &= (buckets-1);
+
+ size = buckets * sizeof(struct list_head);
+
+ err = -ENOMEM;
+ hash = vmalloc(size);
+ lv->lv_snapshot_hash_table = hash;
+
+ if (!hash)
+ goto out;
+
+ lv->lv_snapshot_hash_mask = buckets-1;
+ while (buckets--)
+ INIT_LIST_HEAD(hash+buckets);
+ err = 0;
+ out:
+ return err;
+}
+
+int lvm_snapshot_alloc(lv_t * lv_snap)
+{
+ int err, blocksize, max_sectors;
+
+ err = alloc_kiovec(1, &lv_snap->lv_iobuf);
+ if (err)
+ goto out;
+
+ blocksize = lvm_blocksizes[MINOR(lv_snap->lv_dev)];
+ max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9);
+
+ err = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors);
+ if (err)
+ goto out_free_kiovec;
+
+ err = lvm_snapshot_alloc_hash_table(lv_snap);
+ if (err)
+ goto out_free_kiovec;
+ out:
+ return err;
+
+ out_free_kiovec:
+ unmap_kiobuf(lv_snap->lv_iobuf);
+ free_kiovec(1, &lv_snap->lv_iobuf);
+ goto out;
+}
+
+void lvm_snapshot_release(lv_t * lv)
+{
+ if (lv->lv_block_exception)
+ {
+ vfree(lv->lv_block_exception);
+ lv->lv_block_exception = NULL;
+ }
+ if (lv->lv_snapshot_hash_table)
+ {
+ vfree(lv->lv_snapshot_hash_table);
+ lv->lv_snapshot_hash_table = NULL;
+ }
+ if (lv->lv_iobuf)
+ {
+ free_kiovec(1, &lv->lv_iobuf);
+ lv->lv_iobuf = NULL;
+ }
+}
diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c
new file mode 100644
index 000000000..6d2f2743e
--- /dev/null
+++ b/drivers/block/lvm.c
@@ -0,0 +1,2556 @@
+/*
+ * kernel/lvm.c
+ *
+ * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Germany
+ *
+ * February-November 1997
+ * April-May,July-August,November 1998
+ * January-March,May,July,September,October 1999
+ * January,February 2000
+ *
+ *
+ * LVM driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * LVM driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+/*
+ * Changelog
+ *
+ * 09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT
+ * and VG_STATUS_GET_NAMELIST
+ * 18/01/1998 - change lvm_chr_open/close lock handling
+ * 30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and
+ * - added LV_STATUS_BYINDEX ioctl
+ * - used lvm_status_byname_req_t and
+ * lvm_status_byindex_req_t vars
+ * 04/05/1998 - added multiple device support
+ * 08/05/1998 - added support to set/clear extendable flag in volume group
+ * 09/05/1998 - changed output of lvm_proc_get_info() because of
+ * support for free (eg. longer) logical volume names
+ * 12/05/1998 - added spin_locks (thanks to Pascal van Dam
+ * <pascal@ramoth.xs4all.nl>)
+ * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl()
+ * 26/05/1998 - reactivated verify_area by access_ok
+ * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go
+ * beyond 128/256 KB max allocation limit per call
+ * - #ifdef blocked spin_lock calls to avoid compile errors
+ * with 2.0.x
+ * 11/06/1998 - another enhancement to spinlock code in lvm_chr_open()
+ * and use of LVM_VERSION_CODE instead of my own macros
+ * (thanks to Michael Marxmeier <mike@msede.com>)
+ * 07/07/1998 - added statistics in lvm_map()
+ * 08/07/1998 - saved statistics in lvm_do_lv_extend_reduce()
+ * 25/07/1998 - used __initfunc macro
+ * 02/08/1998 - changes for official char/block major numbers
+ * 07/08/1998 - avoided init_module() and cleanup_module() to be static
+ * 30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters
+ * to sum of LVs open (no matter how often each is)
+ * 01/09/1998 - fixed lvm_gendisk.part[] index error
+ * 07/09/1998 - added copying of lv_current_pe-array
+ * in LV_STATUS_BYINDEX ioctl
+ * 17/11/1998 - added KERN_* levels to printk
+ * 13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename
+ * 07/02/1999 - fixed spinlock handling bug in case of LVM_RESET
+ * by moving spinlock code from lvm_chr_open()
+ * to lvm_chr_ioctl()
+ * - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl()
+ * - allowed LVM_RESET and retrieval commands to go ahead;
+ * only other update ioctls are blocked now
+ * - fixed pv->pe to NULL for pv_status
+ * - using lv_req structure in lvm_chr_ioctl() now
+ * - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce()
+ * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE)
+ * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to
+ * handle lgoical volume private read ahead sector
+ * - implemented LV read_ahead handling with lvm_blk_read()
+ * and lvm_blk_write()
+ * 10/02/1999 - implemented 2.[12].* support function lvm_hd_name()
+ * to be used in drivers/block/genhd.c by disk_name()
+ * 12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO
+ * - enhanced gendisk insert/remove handling
+ * 16/02/1999 - changed to dynamic block minor number allocation to
+ * have as much as 99 volume groups with 256 logical volumes
+ * as the grand total; this allows having 1 volume group with
+ * up to 256 logical volumes in it
+ * 21/02/1999 - added LV open count information to proc filesystem
+ * - substituted redundant LVM_RESET code by calls
+ * to lvm_do_vg_remove()
+ * 22/02/1999 - used schedule_timeout() to be more responsive
+ * in case of lvm_do_vg_remove() with lots of logical volumes
+ * 19/03/1999 - fixed NULL pointer bug in module_init/lvm_init
+ * 17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0)
+ * - enhanced lvm_hd_name support
+ * 03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and
+ * memcpy_tofs/memcpy_fromfs macro redefinitions
+ * 06/07/1999 - corrected reads/writes statistic counter copy in case
+ * of striped logical volume
+ * 28/07/1999 - implemented snapshot logical volumes
+ * - lvm_chr_ioctl
+ * - LV_STATUS_BYINDEX
+ * - LV_STATUS_BYNAME
+ * - lvm_do_lv_create
+ * - lvm_do_lv_remove
+ * - lvm_map
+ * - new lvm_snapshot_remap_block
+ * - new lvm_snapshot_remap_new_block
+ * 08/10/1999 - implemented support for multiple snapshots per
+ * original logical volume
+ * 12/10/1999 - support for 2.3.19
+ * 11/11/1999 - support for 2.3.28
+ * 21/11/1999 - changed lvm_map() interface to buffer_head based
+ * 19/12/1999 - support for 2.3.33
+ * 01/01/2000 - changed locking concept in lvm_map(),
+ * lvm_do_vg_create() and lvm_do_lv_remove()
+ * 15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl()
+ * 24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc.
+ * 29/01/2000 - used kmalloc/kfree again for all small structures
+ * 20/01/2000 - cleaned up lvm_chr_ioctl by moving code
+ * to seperated functions
+ * - avoided "/dev/" in proc filesystem output
+ * - avoided inline strings functions lvm_strlen etc.
+ * 14/02/2000 - support for 2.3.43
+ * - integrated Andrea Arcagnelli's snapshot code
+ *
+ */
+
+
+static char *lvm_version = "LVM version 0.8final by Heinz Mauelshagen (15/02/2000)\n";
+static char *lvm_short_version = "version 0.8final (15/02/2000)";
+
+#define MAJOR_NR LVM_BLK_MAJOR
+#define DEVICE_OFF(device)
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#ifdef MODVERSIONS
+#undef MODULE
+#define MODULE
+#include <linux/modversions.h>
+#endif
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <linux/hdreg.h>
+#include <linux/stat.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+#include <linux/locks.h>
+#include <linux/smp_lock.h>
+#include <asm/ioctl.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+
+#include <linux/errno.h>
+#include <linux/lvm.h>
+
+#define LVM_CORRECT_READ_AHEAD( a) \
+ if ( a < LVM_MIN_READ_AHEAD || \
+ a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD;
+
+#ifndef WRITEA
+# define WRITEA WRITE
+#endif
+
+/*
+ * External function prototypes
+ */
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#else
+extern int lvm_init(void);
+#endif
+
+static void lvm_dummy_device_request(request_queue_t *);
+#define DEVICE_REQUEST lvm_dummy_device_request
+
+static void lvm_make_request_fn(int, struct buffer_head*);
+
+static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
+static int lvm_blk_open(struct inode *, struct file *);
+
+static ssize_t lvm_blk_read(struct file *, char *, size_t, loff_t *);
+static ssize_t lvm_blk_write(struct file *, const char *, size_t, loff_t *);
+
+static int lvm_chr_open(struct inode *, struct file *);
+
+static int lvm_chr_close(struct inode *, struct file *);
+static int lvm_blk_close(struct inode *, struct file *);
+
+static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong);
+
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+static int lvm_proc_get_info(char *, char **, off_t, int);
+static int (*lvm_proc_get_info_ptr) (char *, char **, off_t, int) =
+&lvm_proc_get_info;
+#endif
+
+#ifdef LVM_HD_NAME
+void lvm_hd_name(char *, int);
+#endif
+/* End external function prototypes */
+
+
+/*
+ * Internal function prototypes
+ */
+static void lvm_init_vars(void);
+
+/* external snapshot calls */
+int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *);
+int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *);
+int lvm_snapshot_alloc(lv_t *);
+void lvm_snapshot_release(lv_t *);
+
+#ifdef LVM_HD_NAME
+extern void (*lvm_hd_name_ptr) (char *, int);
+#endif
+static int lvm_map(struct buffer_head *, int);
+static int lvm_do_lock_lvm(void);
+static int lvm_do_le_remap(vg_t *, void *);
+static int lvm_do_pe_lock_unlock(vg_t *r, void *);
+static int lvm_do_vg_create(int, void *);
+static int lvm_do_vg_extend(vg_t *, void *);
+static int lvm_do_vg_reduce(vg_t *, void *);
+static int lvm_do_vg_remove(int);
+static int lvm_do_lv_create(int, char *, lv_t *);
+static int lvm_do_lv_remove(int, char *, int);
+static int lvm_do_lv_extend_reduce(int, char *, lv_t *);
+static int lvm_do_lv_status_byname(vg_t *r, void *);
+static int lvm_do_lv_status_byindex(vg_t *, void *arg);
+static int lvm_do_pv_change(vg_t*, void*);
+static int lvm_do_pv_status(vg_t *, void *);
+static void lvm_geninit(struct gendisk *);
+#ifdef LVM_GET_INODE
+static struct inode *lvm_get_inode(int);
+void lvm_clear_inode(struct inode *);
+#endif
+/* END Internal function prototypes */
+
+
+/* volume group descriptor area pointers */
+static vg_t *vg[ABS_MAX_VG];
+static pv_t *pvp = NULL;
+static lv_t *lvp = NULL;
+static pe_t *pep = NULL;
+static pe_t *pep1 = NULL;
+
+
+/* map from block minor number to VG and LV numbers */
+typedef struct {
+ int vg_number;
+ int lv_number;
+} vg_lv_map_t;
+static vg_lv_map_t vg_lv_map[ABS_MAX_LV];
+
+
+/* Request structures (lvm_chr_ioctl()) */
+static pv_change_req_t pv_change_req;
+static pv_flush_req_t pv_flush_req;
+static pv_status_req_t pv_status_req;
+static pe_lock_req_t pe_lock_req;
+static le_remap_req_t le_remap_req;
+static lv_req_t lv_req;
+
+#ifdef LVM_TOTAL_RESET
+static int lvm_reset_spindown = 0;
+#endif
+
+static char pv_name[NAME_LEN];
+/* static char rootvg[NAME_LEN] = { 0, }; */
+static uint lv_open = 0;
+static const char *const lvm_name = LVM_NAME;
+static int lock = 0;
+static int loadtime = 0;
+static uint vg_count = 0;
+static long lvm_chr_open_count = 0;
+static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
+static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lvm_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait);
+
+static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
+
+static struct file_operations lvm_chr_fops =
+{
+ open: lvm_chr_open,
+ release: lvm_chr_close,
+ ioctl: lvm_chr_ioctl,
+};
+
+static struct file_operations lvm_blk_fops =
+{
+ open: lvm_blk_open,
+ release: blkdev_close,
+ read: lvm_blk_read,
+ write: lvm_blk_write,
+ ioctl: lvm_blk_ioctl,
+ fsync: block_fsync,
+};
+
+#define BLOCK_DEVICE_OPERATIONS
+/* block device operations structure needed for 2.3.38? and above */
+static struct block_device_operations lvm_blk_dops =
+{
+ open: lvm_blk_open,
+ release: lvm_blk_close,
+ ioctl: lvm_blk_ioctl
+};
+
+/* gendisk structures */
+static struct hd_struct lvm_hd_struct[MAX_LV];
+static int lvm_blocksizes[MAX_LV] =
+{0,};
+static int lvm_size[MAX_LV] =
+{0,};
+static struct gendisk lvm_gendisk =
+{
+ MAJOR_NR, /* major # */
+ LVM_NAME, /* name of major */
+ 0, /* number of times minor is shifted
+ to get real minor */
+ 1, /* maximum partitions per device */
+ lvm_hd_struct, /* partition table */
+ lvm_size, /* device size in blocks, copied
+ to block_size[] */
+ MAX_LV, /* number or real devices */
+ NULL, /* internal */
+ NULL, /* pointer to next gendisk struct (internal) */
+};
+
+
+#ifdef MODULE
+/*
+ * Module initialization...
+ */
+int init_module(void)
+#else
+/*
+ * Driver initialization...
+ */
+#ifdef __initfunc
+__initfunc(int lvm_init(void))
+#else
+int __init lvm_init(void)
+#endif
+#endif /* #ifdef MODULE */
+{
+ struct gendisk *gendisk_ptr = NULL;
+
+ if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) {
+ printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name);
+ return -EIO;
+ }
+#ifdef BLOCK_DEVICE_OPERATIONS
+ if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0)
+#else
+ if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0)
+#endif
+ {
+ printk("%s -- register_blkdev failed\n", lvm_name);
+ if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0)
+ printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
+ return -EIO;
+ }
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+ create_proc_info_entry(LVM_NAME, S_IFREG | S_IRUGO,
+ &proc_root, lvm_proc_get_info_ptr);
+#endif
+
+ lvm_init_vars();
+ lvm_geninit(&lvm_gendisk);
+
+ /* insert our gendisk at the corresponding major */
+ if (gendisk_head != NULL) {
+ gendisk_ptr = gendisk_head;
+ while (gendisk_ptr->next != NULL &&
+ gendisk_ptr->major > lvm_gendisk.major) {
+ gendisk_ptr = gendisk_ptr->next;
+ }
+ lvm_gendisk.next = gendisk_ptr->next;
+ gendisk_ptr->next = &lvm_gendisk;
+ } else {
+ gendisk_head = &lvm_gendisk;
+ lvm_gendisk.next = NULL;
+ }
+
+#ifdef LVM_HD_NAME
+ /* reference from drivers/block/genhd.c */
+ lvm_hd_name_ptr = lvm_hd_name;
+#endif
+
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+ blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);
+ /* optional read root VGDA */
+/*
+ if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg);
+*/
+
+ printk(KERN_INFO
+ "%s%s -- "
+#ifdef MODULE
+ "Module"
+#else
+ "Driver"
+#endif
+ " successfully initialized\n",
+ lvm_version, lvm_name);
+
+ return 0;
+} /* init_module() / lvm_init() */
+
+
+#ifdef MODULE
+/*
+ * Module cleanup...
+ */
+void cleanup_module(void)
+{
+ struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL;
+
+ if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) {
+ printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
+ }
+ if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) {
+ printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name);
+ }
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+
+ gendisk_ptr = gendisk_ptr_prev = gendisk_head;
+ while (gendisk_ptr != NULL) {
+ if (gendisk_ptr == &lvm_gendisk)
+ break;
+ gendisk_ptr_prev = gendisk_ptr;
+ gendisk_ptr = gendisk_ptr->next;
+ }
+ /* delete our gendisk from chain */
+ if (gendisk_ptr == &lvm_gendisk)
+ gendisk_ptr_prev->next = gendisk_ptr->next;
+
+ blk_size[MAJOR_NR] = NULL;
+ blksize_size[MAJOR_NR] = NULL;
+
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+ remove_proc_entry(LVM_NAME, &proc_root);
+#endif
+
+#ifdef LVM_HD_NAME
+ /* reference from linux/drivers/block/genhd.c */
+ lvm_hd_name_ptr = NULL;
+#endif
+
+ printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
+
+ return;
+} /* void cleanup_module() */
+#endif /* #ifdef MODULE */
+
+
+/*
+ * support function to initialize lvm variables
+ */
+#ifdef __initfunc
+__initfunc(void lvm_init_vars(void))
+#else
+void __init lvm_init_vars(void)
+#endif
+{
+ int v;
+
+ loadtime = CURRENT_TIME;
+
+ lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
+
+ pe_lock_req.lock = UNLOCK_PE;
+ pe_lock_req.data.lv_dev = \
+ pe_lock_req.data.pv_dev = \
+ pe_lock_req.data.pv_offset = 0;
+
+ /* Initialize VG pointers */
+ for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL;
+
+ /* Initialize LV -> VG association */
+ for (v = 0; v < ABS_MAX_LV; v++) {
+ /* index ABS_MAX_VG never used for real VG */
+ vg_lv_map[v].vg_number = ABS_MAX_VG;
+ vg_lv_map[v].lv_number = -1;
+ }
+
+ return;
+} /* lvm_init_vars() */
+
+
+/********************************************************************
+ *
+ * Character device functions
+ *
+ ********************************************************************/
+
+/*
+ * character device open routine
+ */
+static int lvm_chr_open(struct inode *inode,
+ struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+
+#ifdef DEBUG
+ printk(KERN_DEBUG
+ "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n",
+ lvm_name, minor, VG_CHR(minor), file->f_mode, lock);
+#endif
+
+ /* super user validation */
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+ /* Group special file open */
+ if (VG_CHR(minor) > MAX_VG) return -ENXIO;
+
+ MOD_INC_USE_COUNT;
+
+ lvm_chr_open_count++;
+ return 0;
+} /* lvm_chr_open() */
+
+
+/*
+ * character device i/o-control routine
+ *
+ * Only one changing process can do changing ioctl at one time,
+ * others will block.
+ *
+ */
+static int lvm_chr_ioctl(struct inode *inode, struct file *file,
+ uint command, ulong a)
+{
+ int minor = MINOR(inode->i_rdev);
+ uint extendable, l, v;
+ void *arg = (void *) a;
+ lv_t lv;
+ vg_t* vg_ptr = vg[VG_CHR(minor)];
+
+ /* otherwise cc will complain about unused variables */
+ (void) lvm_lock;
+
+
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d "
+ "VG#: %d mode: 0x%X\n",
+ lvm_name, command, minor, VG_CHR(minor), file->f_mode);
+#endif
+
+#ifdef LVM_TOTAL_RESET
+ if (lvm_reset_spindown > 0) return -EACCES;
+#endif
+
+ /* Main command switch */
+ switch (command) {
+ case LVM_LOCK_LVM:
+ /* lock the LVM */
+ return lvm_do_lock_lvm();
+
+ case LVM_GET_IOP_VERSION:
+ /* check lvm version to ensure driver/tools+lib
+ interoperability */
+ if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0)
+ return -EFAULT;
+ return 0;
+
+#ifdef LVM_TOTAL_RESET
+ case LVM_RESET:
+ /* lock reset function */
+ lvm_reset_spindown = 1;
+ for (v = 0; v < ABS_MAX_VG; v++) {
+ if (vg[v] != NULL) lvm_do_vg_remove(v);
+ }
+
+#ifdef MODULE
+ while (GET_USE_COUNT(&__this_module) < 1)
+ MOD_INC_USE_COUNT;
+ while (GET_USE_COUNT(&__this_module) > 1)
+ MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+ lock = 0; /* release lock */
+ wake_up_interruptible(&lvm_wait);
+ return 0;
+#endif /* LVM_TOTAL_RESET */
+
+
+ case LE_REMAP:
+ /* remap a logical extent (after moving the physical extent) */
+ return lvm_do_le_remap(vg_ptr,arg);
+
+ case PE_LOCK_UNLOCK:
+ /* lock/unlock i/o to a physical extent to move it to another
+ physical volume (move's done in user space's pvmove) */
+ return lvm_do_pe_lock_unlock(vg_ptr,arg);
+
+ case VG_CREATE:
+ /* create a VGDA */
+ return lvm_do_vg_create(minor, arg);
+
+ case VG_REMOVE:
+ /* remove an inactive VGDA */
+ return lvm_do_vg_remove(minor);
+
+ case VG_EXTEND:
+ /* extend a volume group */
+ return lvm_do_vg_extend(vg_ptr,arg);
+
+ case VG_REDUCE:
+ /* reduce a volume group */
+ return lvm_do_vg_reduce(vg_ptr,arg);
+
+
+ case VG_SET_EXTENDABLE:
+ /* set/clear extendability flag of volume group */
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0)
+ return -EFAULT;
+
+ if (extendable == VG_EXTENDABLE ||
+ extendable == ~VG_EXTENDABLE) {
+ if (extendable == VG_EXTENDABLE)
+ vg_ptr->vg_status |= VG_EXTENDABLE;
+ else
+ vg_ptr->vg_status &= ~VG_EXTENDABLE;
+ } else return -EINVAL;
+ return 0;
+
+
+ case VG_STATUS:
+ /* get volume group data (only the vg_t struct) */
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0)
+ return -EFAULT;
+ return 0;
+
+
+ case VG_STATUS_GET_COUNT:
+ /* get volume group count */
+ if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0)
+ return -EFAULT;
+ return 0;
+
+
+ case VG_STATUS_GET_NAMELIST:
+ /* get volume group count */
+ for (l = v = 0; v < ABS_MAX_VG; v++) {
+ if (vg[v] != NULL) {
+ if (copy_to_user(arg + l++ * NAME_LEN,
+ vg[v]->vg_name,
+ NAME_LEN) != 0)
+ return -EFAULT;
+ }
+ }
+ return 0;
+
+
+ case LV_CREATE:
+ case LV_REMOVE:
+ case LV_EXTEND:
+ case LV_REDUCE:
+ /* create, remove, extend or reduce a logical volume */
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0)
+ return -EFAULT;
+
+ if (command != LV_REMOVE) {
+ if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0)
+ return -EFAULT;
+ }
+ switch (command) {
+ case LV_CREATE:
+ return lvm_do_lv_create(minor, lv_req.lv_name, &lv);
+
+ case LV_REMOVE:
+ return lvm_do_lv_remove(minor, lv_req.lv_name, -1);
+
+ case LV_EXTEND:
+ case LV_REDUCE:
+ return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv);
+ }
+
+
+ case LV_STATUS_BYNAME:
+ /* get status of a logical volume by name */
+ return lvm_do_lv_status_byname(vg_ptr,arg);
+
+ case LV_STATUS_BYINDEX:
+ /* get status of a logical volume by index */
+ return lvm_do_lv_status_byindex(vg_ptr,arg);
+
+ case PV_CHANGE:
+ /* change a physical volume */
+ return lvm_do_pv_change(vg_ptr,arg);
+
+ case PV_STATUS:
+ /* get physical volume data (pv_t structure only) */
+ return lvm_do_pv_status(vg_ptr,arg);
+
+ case PV_FLUSH:
+ /* physical volume buffer flush/invalidate */
+ if (copy_from_user(&pv_flush_req, arg,
+ sizeof(pv_flush_req)) != 0)
+ return -EFAULT;
+
+ fsync_dev(pv_flush_req.pv_dev);
+ invalidate_buffers(pv_flush_req.pv_dev);
+ return 0;
+
+ default:
+ printk(KERN_WARNING
+ "%s -- lvm_chr_ioctl: unknown command %x\n",
+ lvm_name, command);
+ return -EINVAL;
+ }
+
+ return 0;
+} /* lvm_chr_ioctl */
+
+
+/*
+ * character device close routine
+ */
+static int lvm_chr_close(struct inode *inode, struct file *file)
+{
+#ifdef DEBUG
+ int minor = MINOR(inode->i_rdev);
+ printk(KERN_DEBUG
+ "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor));
+#endif
+
+#ifdef LVM_TOTAL_RESET
+ if (lvm_reset_spindown > 0) {
+ lvm_reset_spindown = 0;
+ lvm_chr_open_count = 1;
+ }
+#endif
+
+ if (lvm_chr_open_count > 0) lvm_chr_open_count--;
+ if (lock == current->pid) {
+ lock = 0; /* release lock */
+ wake_up_interruptible(&lvm_wait);
+ }
+
+#ifdef MODULE
+ if (GET_USE_COUNT(&__this_module) > 0) MOD_DEC_USE_COUNT;
+#endif
+
+ return 0;
+} /* lvm_chr_close() */
+
+
+
+/********************************************************************
+ *
+ * Block device functions
+ *
+ ********************************************************************/
+
+/*
+ * block device open routine
+ */
+static int lvm_blk_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ lv_t *lv_ptr;
+ vg_t *vg_ptr = vg[VG_BLK(minor)];
+
+#ifdef DEBUG_LVM_BLK_OPEN
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n",
+ lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode);
+#endif
+
+#ifdef LVM_TOTAL_RESET
+ if (lvm_reset_spindown > 0)
+ return -EPERM;
+#endif
+
+ if (vg_ptr != NULL &&
+ (vg_ptr->vg_status & VG_ACTIVE) &&
+ (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL &&
+ LV_BLK(minor) >= 0 &&
+ LV_BLK(minor) < vg_ptr->lv_max) {
+
+ /* Check parallel LV spindown (LV remove) */
+ if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM;
+
+ /* Check inactive LV and open for read/write */
+ if (file->f_mode & O_RDWR) {
+ if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM;
+ if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES;
+ }
+
+#ifdef BLOCK_DEVICE_OPERATIONS
+ file->f_op = &lvm_blk_fops;
+#endif
+
+ /* be sure to increment VG counter */
+ if (lv_ptr->lv_open == 0) vg_ptr->lv_open++;
+ lv_ptr->lv_open++;
+
+ MOD_INC_USE_COUNT;
+
+#ifdef DEBUG_LVM_BLK_OPEN
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n",
+ lvm_name, minor, VG_BLK(minor), LV_BLK(minor),
+ lv_ptr->lv_size);
+#endif
+
+ return 0;
+ }
+ return -ENXIO;
+} /* lvm_blk_open() */
+
+
+/*
+ * block device read
+ */
+static ssize_t lvm_blk_read(struct file *file, char *buffer,
+ size_t size, loff_t * offset)
+{
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] =
+ vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead;
+ return block_read(file, buffer, size, offset);
+}
+
+
+/*
+ * block device write
+ */
+static ssize_t lvm_blk_write(struct file *file, const char *buffer,
+ size_t size, loff_t * offset)
+{
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] =
+ vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead;
+ return block_write(file, buffer, size, offset);
+}
+
+
+/*
+ * block device i/o-control routine
+ */
+static int lvm_blk_ioctl(struct inode *inode, struct file *file,
+ uint command, ulong a)
+{
+ int minor = MINOR(inode->i_rdev);
+ vg_t *vg_ptr = vg[VG_BLK(minor)];
+ lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
+ void *arg = (void *) a;
+ struct hd_geometry *hd = (struct hd_geometry *) a;
+
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X "
+ "VG#: %dl LV#: %d\n",
+ lvm_name, minor, command, (ulong) arg,
+ VG_BLK(minor), LV_BLK(minor));
+#endif
+
+ switch (command) {
+ case BLKGETSIZE:
+ /* return device size */
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n",
+ lvm_name, lv_ptr->lv_size);
+#endif
+ copy_to_user((long *) arg, &lv_ptr->lv_size,
+ sizeof(lv_ptr->lv_size));
+ break;
+
+
+ case BLKFLSBUF:
+ /* flush buffer cache */
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name);
+#endif
+ fsync_dev(inode->i_rdev);
+ break;
+
+
+ case BLKRASET:
+ /* set read ahead for block device */
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n",
+ lvm_name, (long) arg, MAJOR(inode->i_rdev), minor);
+#endif
+ if ((long) arg < LVM_MIN_READ_AHEAD ||
+ (long) arg > LVM_MAX_READ_AHEAD)
+ return -EINVAL;
+ lv_ptr->lv_read_ahead = (long) arg;
+ break;
+
+
+ case BLKRAGET:
+ /* get current read ahead setting */
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
+#endif
+ copy_to_user((long *) arg, &lv_ptr->lv_read_ahead,
+ sizeof(lv_ptr->lv_read_ahead));
+ break;
+
+
+ case HDIO_GETGEO:
+ /* get disk geometry */
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
+#endif
+ if (hd == NULL)
+ return -EINVAL;
+ {
+ unsigned char heads = 64;
+ unsigned char sectors = 32;
+ long start = 0;
+ short cylinders = lv_ptr->lv_size / heads / sectors;
+
+ if (copy_to_user((char *) &hd->heads, &heads,
+ sizeof(heads)) != 0 ||
+ copy_to_user((char *) &hd->sectors, &sectors,
+ sizeof(sectors)) != 0 ||
+ copy_to_user((short *) &hd->cylinders,
+ &cylinders, sizeof(cylinders)) != 0 ||
+ copy_to_user((long *) &hd->start, &start,
+ sizeof(start)) != 0)
+ return -EFAULT;
+ }
+
+#ifdef DEBUG_IOCTL
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_ioctl -- cylinders: %d\n",
+ lvm_name, lv_ptr->lv_size / heads / sectors);
+#endif
+ break;
+
+
+ case LV_SET_ACCESS:
+ /* set access flags of a logical volume */
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ lv_ptr->lv_access = (ulong) arg;
+ break;
+
+
+ case LV_SET_STATUS:
+ /* set status flags of a logical volume */
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
+ return -EPERM;
+ lv_ptr->lv_status = (ulong) arg;
+ break;
+
+
+ case LV_SET_ALLOCATION:
+ /* set allocation flags of a logical volume */
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ lv_ptr->lv_allocation = (ulong) arg;
+ break;
+
+
+ default:
+ printk(KERN_WARNING
+ "%s -- lvm_blk_ioctl: unknown command %d\n",
+ lvm_name, command);
+ return -EINVAL;
+ }
+
+ return 0;
+} /* lvm_blk_ioctl() */
+
+
+/*
+ * block device close routine
+ */
+static int lvm_blk_close(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ vg_t *vg_ptr = vg[VG_BLK(minor)];
+ lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
+
+#ifdef DEBUG
+ printk(KERN_DEBUG
+ "%s -- lvm_blk_close MINOR: %d VG#: %d LV#: %d\n",
+ lvm_name, minor, VG_BLK(minor), LV_BLK(minor));
+#endif
+
+ sync_dev(inode->i_rdev);
+ if (lv_ptr->lv_open == 1) vg_ptr->lv_open--;
+ lv_ptr->lv_open--;
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+} /* lvm_blk_close() */
+
+
+#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
+/*
+ * Support function /proc-Filesystem
+ */
+#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz])
+
+static int lvm_proc_get_info(char *page, char **start, off_t pos, int count)
+{
+ int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter,
+ lv_open_total, pe_t_bytes, lv_block_exception_t_bytes, seconds;
+ static off_t sz;
+ off_t sz_last;
+ char allocation_flag, inactive_flag, rw_flag, stripes_flag;
+ char *lv_name, *pv_name;
+ static char *buf = NULL;
+ static char dummy_buf[160]; /* sized for 2 lines */
+ vg_t *vg_ptr;
+ lv_t *lv_ptr;
+ pv_t *pv_ptr;
+
+
+#ifdef DEBUG_LVM_PROC_GET_INFO
+ printk(KERN_DEBUG
+ "%s - lvm_proc_get_info CALLED pos: %lu count: %d whence: %d\n",
+ lvm_name, pos, count, whence);
+#endif
+
+ if (pos == 0 || buf == NULL) {
+ sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \
+ lv_open_total = pe_t_bytes = lv_block_exception_t_bytes = 0;
+
+ /* search for activity */
+ for (v = 0; v < ABS_MAX_VG; v++) {
+ if ((vg_ptr = vg[v]) != NULL) {
+ vg_counter++;
+ pv_counter += vg_ptr->pv_cur;
+ lv_counter += vg_ptr->lv_cur;
+ if (vg_ptr->lv_cur > 0) {
+ for (l = 0; l < vg[v]->lv_max; l++) {
+ if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
+ pe_t_bytes += lv_ptr->lv_allocated_le;
+ if (lv_ptr->lv_block_exception != NULL)
+ lv_block_exception_t_bytes += lv_ptr->lv_remap_end;
+ if (lv_ptr->lv_open > 0) {
+ lv_open_counter++;
+ lv_open_total += lv_ptr->lv_open;
+ }
+ }
+ }
+ }
+ }
+ }
+ pe_t_bytes *= sizeof(pe_t);
+ lv_block_exception_t_bytes *= sizeof(lv_block_exception_t);
+
+ if (buf != NULL) {
+#ifdef DEBUG_KFREE
+ printk(KERN_DEBUG
+ "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+ kfree(buf);
+ buf = NULL;
+ }
+ /* 2 times: first to get size to allocate buffer,
+ 2nd to fill the malloced buffer */
+ for (i = 0; i < 2; i++) {
+ sz = 0;
+ sz += sprintf(LVM_PROC_BUF,
+ "LVM "
+#ifdef MODULE
+ "module"
+#else
+ "driver"
+#endif
+ " %s\n\n"
+ "Total: %d VG%s %d PV%s %d LV%s ",
+ lvm_short_version,
+ vg_counter, vg_counter == 1 ? "" : "s",
+ pv_counter, pv_counter == 1 ? "" : "s",
+ lv_counter, lv_counter == 1 ? "" : "s");
+ sz += sprintf(LVM_PROC_BUF,
+ "(%d LV%s open",
+ lv_open_counter,
+ lv_open_counter == 1 ? "" : "s");
+ if (lv_open_total > 0)
+ sz += sprintf(LVM_PROC_BUF,
+ " %d times)\n",
+ lv_open_total);
+ else
+ sz += sprintf(LVM_PROC_BUF, ")");
+ sz += sprintf(LVM_PROC_BUF,
+ "\nGlobal: %lu bytes malloced IOP version: %d ",
+ vg_counter * sizeof(vg_t) +
+ pv_counter * sizeof(pv_t) +
+ lv_counter * sizeof(lv_t) +
+ pe_t_bytes + lv_block_exception_t_bytes + sz_last,
+ lvm_iop_version);
+
+ seconds = CURRENT_TIME - loadtime;
+ if (seconds < 0)
+ loadtime = CURRENT_TIME + seconds;
+ if (seconds / 86400 > 0) {
+ sz += sprintf(LVM_PROC_BUF, "%d day%s ",
+ seconds / 86400,
+ seconds / 86400 == 0 ||
+ seconds / 86400 > 1 ? "s" : "");
+ }
+ sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
+ (seconds % 86400) / 3600,
+ (seconds % 3600) / 60,
+ seconds % 60);
+
+ if (vg_counter > 0) {
+ for (v = 0; v < ABS_MAX_VG; v++) {
+ /* volume group */
+ if ((vg_ptr = vg[v]) != NULL) {
+ inactive_flag = ' ';
+ if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I';
+ sz += sprintf(LVM_PROC_BUF,
+ "\nVG: %c%s [%d PV, %d LV/%d open] "
+ " PE Size: %d KB\n"
+ " Usage [KB/PE]: %d /%d total "
+ "%d /%d used %d /%d free",
+ inactive_flag,
+ vg_ptr->vg_name,
+ vg_ptr->pv_cur,
+ vg_ptr->lv_cur,
+ vg_ptr->lv_open,
+ vg_ptr->pe_size >> 1,
+ vg_ptr->pe_size * vg_ptr->pe_total >> 1,
+ vg_ptr->pe_total,
+ vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
+ vg_ptr->pe_allocated,
+ (vg_ptr->pe_total - vg_ptr->pe_allocated) *
+ vg_ptr->pe_size >> 1,
+ vg_ptr->pe_total - vg_ptr->pe_allocated);
+
+ /* physical volumes */
+ sz += sprintf(LVM_PROC_BUF,
+ "\n PV%s ",
+ vg_ptr->pv_cur == 1 ? ": " : "s:");
+ c = 0;
+ for (p = 0; p < vg_ptr->pv_max; p++) {
+ if ((pv_ptr = vg_ptr->pv[p]) != NULL) {
+ inactive_flag = 'A';
+ if (!(pv_ptr->pv_status & PV_ACTIVE))
+ inactive_flag = 'I';
+ allocation_flag = 'A';
+ if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE))
+ allocation_flag = 'N';
+ pv_name = strchr(pv_ptr->pv_name+1,'/');
+ if ( pv_name == 0) pv_name = pv_ptr->pv_name;
+ else pv_name++;
+ sz += sprintf(LVM_PROC_BUF,
+ "[%c%c] %-21s %8d /%-6d "
+ "%8d /%-6d %8d /%-6d",
+ inactive_flag,
+ allocation_flag,
+ pv_name,
+ pv_ptr->pe_total *
+ pv_ptr->pe_size >> 1,
+ pv_ptr->pe_total,
+ pv_ptr->pe_allocated *
+ pv_ptr->pe_size >> 1,
+ pv_ptr->pe_allocated,
+ (pv_ptr->pe_total -
+ pv_ptr->pe_allocated) *
+ pv_ptr->pe_size >> 1,
+ pv_ptr->pe_total -
+ pv_ptr->pe_allocated);
+ c++;
+ if (c < vg_ptr->pv_cur)
+ sz += sprintf(LVM_PROC_BUF,
+ "\n ");
+ }
+ }
+
+ /* logical volumes */
+ sz += sprintf(LVM_PROC_BUF,
+ "\n LV%s ",
+ vg_ptr->lv_cur == 1 ? ": " : "s:");
+ c = 0;
+ for (l = 0; l < vg[v]->lv_max; l++) {
+ if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
+ inactive_flag = 'A';
+ if (!(lv_ptr->lv_status & LV_ACTIVE))
+ inactive_flag = 'I';
+ rw_flag = 'R';
+ if (lv_ptr->lv_access & LV_WRITE)
+ rw_flag = 'W';
+ allocation_flag = 'D';
+ if (lv_ptr->lv_allocation & LV_CONTIGUOUS)
+ allocation_flag = 'C';
+ stripes_flag = 'L';
+ if (lv_ptr->lv_stripes > 1)
+ stripes_flag = 'S';
+ sz += sprintf(LVM_PROC_BUF,
+ "[%c%c%c%c",
+ inactive_flag,
+ rw_flag,
+ allocation_flag,
+ stripes_flag);
+ if (lv_ptr->lv_stripes > 1)
+ sz += sprintf(LVM_PROC_BUF, "%-2d",
+ lv_ptr->lv_stripes);
+ else
+ sz += sprintf(LVM_PROC_BUF, " ");
+ lv_name = strrchr(lv_ptr->lv_name, '/');
+ if ( lv_name == 0) lv_name = lv_ptr->lv_name;
+ else lv_name++;
+ sz += sprintf(LVM_PROC_BUF, "] %-25s", lv_name);
+ if (strlen(lv_name) > 25)
+ sz += sprintf(LVM_PROC_BUF,
+ "\n ");
+ sz += sprintf(LVM_PROC_BUF, "%9d /%-6d ",
+ lv_ptr->lv_size >> 1,
+ lv_ptr->lv_size / vg[v]->pe_size);
+
+ if (lv_ptr->lv_open == 0)
+ sz += sprintf(LVM_PROC_BUF, "close");
+ else
+ sz += sprintf(LVM_PROC_BUF, "%dx open",
+ lv_ptr->lv_open);
+ c++;
+ if (c < vg_ptr->lv_cur)
+ sz += sprintf(LVM_PROC_BUF,
+ "\n ");
+ }
+ }
+ if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none");
+ sz += sprintf(LVM_PROC_BUF, "\n");
+ }
+ }
+ }
+ if (buf == NULL) {
+ if ((buf = vmalloc(sz)) == NULL) {
+ sz = 0;
+ return sprintf(page, "%s - vmalloc error at line %d\n",
+ lvm_name, __LINE__);
+ }
+ }
+ sz_last = sz;
+ }
+ }
+ if (pos > sz - 1) {
+ vfree(buf);
+ buf = NULL;
+ return 0;
+ }
+ *start = &buf[pos];
+ if (sz - pos < count)
+ return sz - pos;
+ else
+ return count;
+} /* lvm_proc_get_info() */
+#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */
+
+
+/*
+ * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c
+ * (see init_module/lvm_init)
+ */
+static int lvm_map(struct buffer_head *bh, int rw)
+{
+ int minor = MINOR(bh->b_dev);
+ int ret = 0;
+ ulong index;
+ ulong pe_start;
+ ulong size = bh->b_size >> 9;
+ ulong rsector_tmp = bh->b_blocknr * size;
+ ulong rsector_sav;
+ kdev_t rdev_tmp = bh->b_dev;
+ kdev_t rdev_sav;
+ lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)];
+
+
+ if (!(lv->lv_status & LV_ACTIVE)) {
+ printk(KERN_ALERT
+ "%s - lvm_map: ll_rw_blk for inactive LV %s\n",
+ lvm_name, lv->lv_name);
+ return -1;
+ }
+/*
+ if ( lv->lv_access & LV_SNAPSHOT)
+ printk ( "%s -- %02d:%02d block: %lu rw: %d\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), bh->b_blocknr, rw);
+ */
+
+ /* take care of snapshot chunk writes before
+ check for writable logical volume */
+ if ((lv->lv_access & LV_SNAPSHOT) &&
+ MAJOR(bh->b_rdev) != 0 &&
+ MAJOR(bh->b_rdev) != MAJOR_NR &&
+ (rw == WRITEA || rw == WRITE))
+ {
+ printk ( "%s -- doing snapshot write for %02d:%02d[%02d:%02d] b_blocknr: %lu b_rsector: %lu\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), MAJOR ( bh->b_rdev), MINOR ( bh->b_rdev), bh->b_blocknr, bh->b_rsector);
+ return 0;
+ }
+
+ if ((rw == WRITE || rw == WRITEA) &&
+ !(lv->lv_access & LV_WRITE)) {
+ printk(KERN_CRIT
+ "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
+ lvm_name, lv->lv_name);
+ return -1;
+ }
+#ifdef DEBUG_MAP
+ printk(KERN_DEBUG
+ "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu "
+ "size:%lu\n",
+ lvm_name, minor,
+ MAJOR(rdev_tmp),
+ MINOR(rdev_tmp),
+ rsector_tmp, size);
+#endif
+
+ if (rsector_tmp + size > lv->lv_size) {
+ printk(KERN_ALERT
+ "%s - lvm_map *rsector: %lu or size: %lu wrong for"
+ " minor: %2d\n", lvm_name, rsector_tmp, size, minor);
+ return -1;
+ }
+ rsector_sav = rsector_tmp;
+ rdev_sav = rdev_tmp;
+
+lvm_second_remap:
+ /* linear mapping */
+ if (lv->lv_stripes < 2) {
+ /* get the index */
+ index = rsector_tmp / vg[VG_BLK(minor)]->pe_size;
+ pe_start = lv->lv_current_pe[index].pe;
+ rsector_tmp = lv->lv_current_pe[index].pe +
+ (rsector_tmp % vg[VG_BLK(minor)]->pe_size);
+ rdev_tmp = lv->lv_current_pe[index].dev;
+
+#ifdef DEBUG_MAP
+ printk(KERN_DEBUG
+ "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n",
+ index,
+ lv->lv_current_pe[index].pe,
+ MAJOR(rdev_tmp),
+ MINOR(rdev_tmp),
+ rsector_tmp);
+#endif
+
+ /* striped mapping */
+ } else {
+ ulong stripe_index;
+ ulong stripe_length;
+
+ stripe_length = vg[VG_BLK(minor)]->pe_size * lv->lv_stripes;
+ stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize;
+ index = rsector_tmp / stripe_length +
+ (stripe_index % lv->lv_stripes) *
+ (lv->lv_allocated_le / lv->lv_stripes);
+ pe_start = lv->lv_current_pe[index].pe;
+ rsector_tmp = lv->lv_current_pe[index].pe +
+ (rsector_tmp % stripe_length) -
+ (stripe_index % lv->lv_stripes) * lv->lv_stripesize -
+ stripe_index / lv->lv_stripes *
+ (lv->lv_stripes - 1) * lv->lv_stripesize;
+ rdev_tmp = lv->lv_current_pe[index].dev;
+ }
+
+#ifdef DEBUG_MAP
+ printk(KERN_DEBUG
+ "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n"
+ "stripe_length: %ld stripe_index: %ld\n",
+ index,
+ lv->lv_current_pe[index].pe,
+ MAJOR(rdev_tmp),
+ MINOR(rdev_tmp),
+ rsector_tmp,
+ stripe_length,
+ stripe_index);
+#endif
+
+ /* handle physical extents on the move */
+ if (pe_lock_req.lock == LOCK_PE) {
+ if (rdev_tmp == pe_lock_req.data.pv_dev &&
+ rsector_tmp >= pe_lock_req.data.pv_offset &&
+ rsector_tmp < (pe_lock_req.data.pv_offset +
+ vg[VG_BLK(minor)]->pe_size)) {
+ sleep_on(&lvm_map_wait);
+ rsector_tmp = rsector_sav;
+ rdev_tmp = rdev_sav;
+ goto lvm_second_remap;
+ }
+ }
+ /* statistic */
+ if (rw == WRITE || rw == WRITEA)
+ lv->lv_current_pe[index].writes++;
+ else
+ lv->lv_current_pe[index].reads++;
+
+ /* snapshot volume exception handling on physical device address base */
+ if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) {
+ /* original logical volume */
+ if (lv->lv_access & LV_SNAPSHOT_ORG) {
+ if (rw == WRITE || rw == WRITEA)
+ {
+ lv_t *lv_ptr;
+
+ /* start with first snapshot and loop thrugh all of them */
+ for (lv_ptr = lv->lv_snapshot_next;
+ lv_ptr != NULL;
+ lv_ptr = lv_ptr->lv_snapshot_next) {
+ down(&lv->lv_snapshot_org->lv_snapshot_sem);
+ /* do we still have exception storage for this snapshot free? */
+ if (lv_ptr->lv_block_exception != NULL) {
+ rdev_sav = rdev_tmp;
+ rsector_sav = rsector_tmp;
+ if (!lvm_snapshot_remap_block(&rdev_tmp,
+ &rsector_tmp,
+ pe_start,
+ lv_ptr)) {
+ /* create a new mapping */
+ ret = lvm_snapshot_COW(rdev_tmp,
+ rsector_tmp,
+ pe_start,
+ rsector_sav,
+ lv_ptr);
+ }
+ rdev_tmp = rdev_sav;
+ rsector_tmp = rsector_sav;
+ }
+ up(&lv->lv_snapshot_org->lv_snapshot_sem);
+ }
+ }
+ } else {
+ /* remap snapshot logical volume */
+ down(&lv->lv_snapshot_sem);
+ if (lv->lv_block_exception != NULL)
+ lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv);
+ up(&lv->lv_snapshot_sem);
+ }
+ }
+ bh->b_rdev = rdev_tmp;
+ bh->b_rsector = rsector_tmp;
+
+ return ret;
+} /* lvm_map() */
+
+
+/*
+ * internal support functions
+ */
+
+#ifdef LVM_HD_NAME
+/*
+ * generate "hard disk" name
+ */
+void lvm_hd_name(char *buf, int minor)
+{
+ int len = 0;
+ lv_t *lv_ptr;
+
+ if (vg[VG_BLK(minor)] == NULL ||
+ (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL)
+ return;
+ len = strlen(lv_ptr->lv_name) - 5;
+ memcpy(buf, &lv_ptr->lv_name[5], len);
+ buf[len] = 0;
+ return;
+}
+#endif
+
+
+/*
+ * this one never should be called...
+ */
+static void lvm_dummy_device_request(request_queue_t * t)
+{
+ printk(KERN_EMERG
+ "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n",
+ lvm_name,
+ MAJOR(CURRENT->rq_dev),
+ MINOR(CURRENT->rq_dev),
+ CURRENT->sector);
+ return;
+}
+
+
+/*
+ * make request function
+ */
+static void lvm_make_request_fn(int rw, struct buffer_head *bh)
+{
+ lvm_map(bh, rw);
+ if (bh->b_rdev != MD_MAJOR) generic_make_request(rw, bh);
+ return;
+}
+
+
+/********************************************************************
+ *
+ * Character device support functions
+ *
+ ********************************************************************/
+/*
+ * character device support function logical volume manager lock
+ */
+static int lvm_do_lock_lvm(void)
+{
+lock_try_again:
+ spin_lock(&lvm_lock);
+ if (lock != 0 && lock != current->pid) {
+#ifdef DEBUG_IOCTL
+ printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n",
+ lvm_name, lock);
+#endif
+ spin_unlock(&lvm_lock);
+ interruptible_sleep_on(&lvm_wait);
+ if (current->sigpending != 0)
+ return -EINTR;
+#ifdef LVM_TOTAL_RESET
+ if (lvm_reset_spindown > 0)
+ return -EACCES;
+#endif
+ goto lock_try_again;
+ }
+ lock = current->pid;
+ spin_unlock(&lvm_lock);
+ return 0;
+} /* lvm_do_lock_lvm */
+
+
+/*
+ * character device support function lock/unlock physical extend
+ */
+static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg)
+{
+ uint p;
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&pe_lock_req, arg,
+ sizeof(pe_lock_req_t)) != 0) return -EFAULT;
+
+ switch (pe_lock_req.lock) {
+ case LOCK_PE:
+ for (p = 0; p < vg_ptr->pv_max; p++) {
+ if (vg_ptr->pv[p] != NULL &&
+ pe_lock_req.data.pv_dev ==
+ vg_ptr->pv[p]->pv_dev)
+ break;
+ }
+ if (p == vg_ptr->pv_max) return -ENXIO;
+
+ pe_lock_req.lock = UNLOCK_PE;
+ fsync_dev(pe_lock_req.data.lv_dev);
+ pe_lock_req.lock = LOCK_PE;
+ break;
+
+ case UNLOCK_PE:
+ pe_lock_req.lock = UNLOCK_PE;
+ pe_lock_req.data.lv_dev = \
+ pe_lock_req.data.pv_dev = \
+ pe_lock_req.data.pv_offset = 0;
+ wake_up(&lvm_map_wait);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+/*
+ * character device support function logical extend remap
+ */
+static int lvm_do_le_remap(vg_t *vg_ptr, void *arg)
+{
+ uint l, le;
+ lv_t *lv_ptr;
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&le_remap_req, arg,
+ sizeof(le_remap_req_t)) != 0)
+ return -EFAULT;
+
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ lv_ptr = vg_ptr->lv[l];
+ if (lv_ptr != NULL &&
+ strcmp(lv_ptr->lv_name,
+ le_remap_req.lv_name) == 0) {
+ for (le = 0; le < lv_ptr->lv_allocated_le;
+ le++) {
+ if (lv_ptr->lv_current_pe[le].dev ==
+ le_remap_req.old_dev &&
+ lv_ptr->lv_current_pe[le].pe ==
+ le_remap_req.old_pe) {
+ lv_ptr->lv_current_pe[le].dev =
+ le_remap_req.new_dev;
+ lv_ptr->lv_current_pe[le].pe =
+ le_remap_req.new_pe;
+ return 0;
+ }
+ }
+ return -EINVAL;
+ }
+ }
+ return -ENXIO;
+} /* lvm_do_le_remap() */
+
+
+/*
+ * character device support function VGDA create
+ */
+int lvm_do_vg_create(int minor, void *arg)
+{
+ int snaporg_minor = 0;
+ ulong l, p;
+ lv_t lv;
+ vg_t *vg_ptr;
+ pv_t *pv_ptr;
+ lv_t *lv_ptr;
+
+ if (vg[VG_CHR(minor)] != NULL) return -EPERM;
+
+ if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
+ printk(KERN_CRIT
+ "%s -- VG_CREATE: kmalloc error VG at line %d\n",
+ lvm_name, __LINE__);
+ return -ENOMEM;
+ }
+ /* get the volume group structure */
+ if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
+ kfree(vg_ptr);
+ return -EFAULT;
+ }
+ /* we are not that active so far... */
+ vg_ptr->vg_status &= ~VG_ACTIVE;
+ vg[VG_CHR(minor)] = vg_ptr;
+
+ vg[VG_CHR(minor)]->pe_allocated = 0;
+ if (vg_ptr->pv_max > ABS_MAX_PV) {
+ printk(KERN_WARNING
+ "%s -- Can't activate VG: ABS_MAX_PV too small\n",
+ lvm_name);
+ kfree(vg_ptr);
+ vg[VG_CHR(minor)] = NULL;
+ return -EPERM;
+ }
+ if (vg_ptr->lv_max > ABS_MAX_LV) {
+ printk(KERN_WARNING
+ "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
+ lvm_name, vg_ptr->lv_max);
+ kfree(vg_ptr);
+ vg_ptr = NULL;
+ return -EPERM;
+ }
+ /* get the physical volume structures */
+ vg_ptr->pv_act = vg_ptr->pv_cur = 0;
+ for (p = 0; p < vg_ptr->pv_max; p++) {
+ /* user space address */
+ if ((pvp = vg_ptr->pv[p]) != NULL) {
+ pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL);
+ if (pv_ptr == NULL) {
+ printk(KERN_CRIT
+ "%s -- VG_CREATE: kmalloc error PV at line %d\n",
+ lvm_name, __LINE__);
+ lvm_do_vg_remove(minor);
+ return -ENOMEM;
+ }
+ if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) {
+ lvm_do_vg_remove(minor);
+ return -EFAULT;
+ }
+ /* We don't need the PE list
+ in kernel space as with LVs pe_t list (see below) */
+ pv_ptr->pe = NULL;
+ pv_ptr->pe_allocated = 0;
+ pv_ptr->pv_status = PV_ACTIVE;
+ vg_ptr->pv_act++;
+ vg_ptr->pv_cur++;
+
+#ifdef LVM_GET_INODE
+ /* insert a dummy inode for fs_may_mount */
+ pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev);
+#endif
+ }
+ }
+
+ /* get the logical volume structures */
+ vg_ptr->lv_cur = 0;
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ /* user space address */
+ if ((lvp = vg_ptr->lv[l]) != NULL) {
+ if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
+ lvm_do_vg_remove(minor);
+ return -EFAULT;
+ }
+ vg_ptr->lv[l] = NULL;
+ if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
+ lvm_do_vg_remove(minor);
+ return -EFAULT;
+ }
+ }
+ }
+
+ /* Second path to correct snapshot logical volumes which are not
+ in place during first path above */
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ if ((lv_ptr = vg_ptr->lv[l]) != NULL &&
+ vg_ptr->lv[l]->lv_access & LV_SNAPSHOT) {
+ snaporg_minor = lv_ptr->lv_snapshot_minor;
+ if (vg_ptr->lv[LV_BLK(snaporg_minor)] != NULL) {
+ /* get pointer to original logical volume */
+ lv_ptr = vg_ptr->lv[l]->lv_snapshot_org =
+ vg_ptr->lv[LV_BLK(snaporg_minor)];
+
+ /* set necessary fields of original logical volume */
+ lv_ptr->lv_access |= LV_SNAPSHOT_ORG;
+ lv_ptr->lv_snapshot_minor = 0;
+ lv_ptr->lv_snapshot_org = lv_ptr;
+ lv_ptr->lv_snapshot_prev = NULL;
+
+ /* find last snapshot logical volume in the chain */
+ while (lv_ptr->lv_snapshot_next != NULL)
+ lv_ptr = lv_ptr->lv_snapshot_next;
+
+ /* set back pointer to this last one in our new logical volume */
+ vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr;
+
+ /* last logical volume now points to our new snapshot volume */
+ lv_ptr->lv_snapshot_next = vg_ptr->lv[l];
+
+ /* now point to the new one */
+ lv_ptr = lv_ptr->lv_snapshot_next;
+
+ /* set necessary fields of new snapshot logical volume */
+ lv_ptr->lv_snapshot_next = NULL;
+ lv_ptr->lv_current_pe =
+ vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_pe;
+ lv_ptr->lv_allocated_le =
+ vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_allocated_le;
+ lv_ptr->lv_current_le =
+ vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_le;
+ lv_ptr->lv_size =
+ vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_size;
+ }
+ }
+ }
+
+ vg_count++;
+
+ /* let's go active */
+ vg_ptr->vg_status |= VG_ACTIVE;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+} /* lvm_do_vg_create() */
+
+
+/*
+ * character device support function VGDA extend
+ */
+static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg)
+{
+ uint p;
+ pv_t *pv_ptr;
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (vg_ptr->pv_cur < vg_ptr->pv_max) {
+ for (p = 0; p < vg_ptr->pv_max; p++) {
+ if (vg_ptr->pv[p] == NULL) {
+ if ((pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL)) == NULL) {
+ printk(KERN_CRIT
+ "%s -- VG_EXTEND: kmalloc error PV at line %d\n",
+ lvm_name, __LINE__);
+ return -ENOMEM;
+ }
+ if (copy_from_user(pv_ptr, arg, sizeof(pv_t)) != 0) {
+ kfree(pv_ptr);
+ vg_ptr->pv[p] = NULL;
+ return -EFAULT;
+ }
+
+ pv_ptr->pv_status = PV_ACTIVE;
+ /* We don't need the PE list
+ in kernel space like LVs pe_t list */
+ pv_ptr->pe = NULL;
+ vg_ptr->pv_cur++;
+ vg_ptr->pv_act++;
+ vg_ptr->pe_total +=
+ pv_ptr->pe_total;
+#ifdef LVM_GET_INODE
+ /* insert a dummy inode for fs_may_mount */
+ pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev);
+#endif
+ return 0;
+ }
+ }
+ }
+return -EPERM;
+} /* lvm_do_vg_extend() */
+
+
+/*
+ * character device support function VGDA reduce
+ */
+static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg)
+{
+ uint p;
+ pv_t *pv_ptr;
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0)
+ return -EFAULT;
+
+ for (p = 0; p < vg_ptr->pv_max; p++) {
+ pv_ptr = vg_ptr->pv[p];
+ if (pv_ptr != NULL &&
+ strcmp(pv_ptr->pv_name,
+ pv_name) == 0) {
+ if (pv_ptr->lv_cur > 0) return -EPERM;
+ vg_ptr->pe_total -=
+ pv_ptr->pe_total;
+ vg_ptr->pv_cur--;
+ vg_ptr->pv_act--;
+#ifdef LVM_GET_INODE
+ lvm_clear_inode(pv_ptr->inode);
+#endif
+ kfree(pv_ptr);
+ /* Make PV pointer array contiguous */
+ for (; p < vg_ptr->pv_max - 1; p++)
+ vg_ptr->pv[p] = vg_ptr->pv[p + 1];
+ vg_ptr->pv[p + 1] = NULL;
+ return 0;
+ }
+ }
+ return -ENXIO;
+} /* lvm_do_vg_reduce */
+
+
+/*
+ * character device support function VGDA remove
+ */
+static int lvm_do_vg_remove(int minor)
+{
+ int i;
+ vg_t *vg_ptr = vg[VG_CHR(minor)];
+ pv_t *pv_ptr;
+
+ if (vg_ptr == NULL) return -ENXIO;
+
+#ifdef LVM_TOTAL_RESET
+ if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0)
+#else
+ if (vg_ptr->lv_open > 0)
+#endif
+ return -EPERM;
+
+ /* let's go inactive */
+ vg_ptr->vg_status &= ~VG_ACTIVE;
+
+ /* free LVs */
+ /* first free snapshot logical volumes */
+ for (i = 0; i < vg_ptr->lv_max; i++) {
+ if (vg_ptr->lv[i] != NULL &&
+ vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) {
+ lvm_do_lv_remove(minor, NULL, i);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ }
+ /* then free the rest of the LVs */
+ for (i = 0; i < vg_ptr->lv_max; i++) {
+ if (vg_ptr->lv[i] != NULL) {
+ lvm_do_lv_remove(minor, NULL, i);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ }
+
+ /* free PVs */
+ for (i = 0; i < vg_ptr->pv_max; i++) {
+ if ((pv_ptr = vg_ptr->pv[i]) != NULL) {
+#ifdef DEBUG_KFREE
+ printk(KERN_DEBUG
+ "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+#ifdef LVM_GET_INODE
+ lvm_clear_inode(pv_ptr->inode);
+#endif
+ kfree(pv_ptr);
+ vg[VG_CHR(minor)]->pv[i] = NULL;
+ }
+ }
+
+#ifdef DEBUG_KFREE
+ printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+ kfree(vg_ptr);
+ vg[VG_CHR(minor)] = NULL;
+
+ vg_count--;
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+} /* lvm_do_vg_remove() */
+
+
+/*
+ * character device support function logical volume create
+ */
+static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
+{
+ int l, le, l_new, p, size;
+ ulong lv_status_save;
+ lv_block_exception_t *lvbe = lv->lv_block_exception;
+ vg_t *vg_ptr = vg[VG_CHR(minor)];
+ lv_t *lv_ptr = NULL;
+
+ if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
+ if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK)
+ return -EINVAL;
+
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ if (vg_ptr->lv[l] != NULL &&
+ strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
+ return -EEXIST;
+ }
+
+ /* in case of lv_remove(), lv_create() pair; for eg. lvrename does this */
+ l_new = -1;
+ if (vg_ptr->lv[lv->lv_number] == NULL)
+ l_new = lv->lv_number;
+ else {
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ if (vg_ptr->lv[l] == NULL)
+ if (l_new == -1) l_new = l;
+ }
+ }
+ if (l_new == -1) return -EPERM;
+ else l = l_new;
+
+ if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {;
+ printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n",
+ lvm_name, __LINE__);
+ return -ENOMEM;
+ }
+ /* copy preloaded LV */
+ memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
+
+ lv_status_save = lv_ptr->lv_status;
+ lv_ptr->lv_status &= ~LV_ACTIVE;
+ lv_ptr->lv_snapshot_org = \
+ lv_ptr->lv_snapshot_prev = \
+ lv_ptr->lv_snapshot_next = NULL;
+ lv_ptr->lv_block_exception = NULL;
+ init_MUTEX(&lv_ptr->lv_snapshot_sem);
+ vg_ptr->lv[l] = lv_ptr;
+
+ /* get the PE structures from user space if this
+ is no snapshot logical volume */
+ if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
+ size = lv_ptr->lv_allocated_le * sizeof(pe_t);
+ if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) {
+ printk(KERN_CRIT
+ "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte "
+ "at line %d\n",
+ lvm_name, size, __LINE__);
+#ifdef DEBUG_KFREE
+ printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+ kfree(lv_ptr);
+ vg[VG_CHR(minor)]->lv[l] = NULL;
+ return -ENOMEM;
+ }
+ if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) {
+ vfree(lv_ptr->lv_current_pe);
+ kfree(lv_ptr);
+ vg_ptr->lv[l] = NULL;
+ return -EFAULT;
+ }
+ /* correct the PE count in PVs */
+ for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+ vg_ptr->pe_allocated++;
+ for (p = 0; p < vg_ptr->pv_cur; p++) {
+ if (vg_ptr->pv[p]->pv_dev ==
+ lv_ptr->lv_current_pe[le].dev)
+ vg_ptr->pv[p]->pe_allocated++;
+ }
+ }
+ } else {
+ /* Get snapshot exception data and block list */
+ if (lvbe != NULL) {
+ lv_ptr->lv_snapshot_org =
+ vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
+ if (lv_ptr->lv_snapshot_org != NULL) {
+ size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
+ if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) {
+ printk(KERN_CRIT
+ "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION "
+ "of %d byte at line %d\n",
+ lvm_name, size, __LINE__);
+#ifdef DEBUG_KFREE
+ printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+ kfree(lv_ptr);
+ vg_ptr->lv[l] = NULL;
+ return -ENOMEM;
+ }
+ if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) {
+ vfree(lv_ptr->lv_block_exception);
+ kfree(lv_ptr);
+ vg[VG_CHR(minor)]->lv[l] = NULL;
+ return -EFAULT;
+ }
+ /* get pointer to original logical volume */
+ lv_ptr = lv_ptr->lv_snapshot_org;
+
+ lv_ptr->lv_snapshot_minor = 0;
+ lv_ptr->lv_snapshot_org = lv_ptr;
+ lv_ptr->lv_snapshot_prev = NULL;
+ /* walk thrugh the snapshot list */
+ while (lv_ptr->lv_snapshot_next != NULL)
+ lv_ptr = lv_ptr->lv_snapshot_next;
+ /* now lv_ptr points to the last existing snapshot in the chain */
+ vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr;
+ /* our new one now back points to the previous last in the chain */
+ lv_ptr = vg_ptr->lv[l];
+ /* now lv_ptr points to our new last snapshot logical volume */
+ lv_ptr->lv_snapshot_org = lv_ptr->lv_snapshot_prev->lv_snapshot_org;
+ lv_ptr->lv_snapshot_next = NULL;
+ lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
+ lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
+ lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
+ lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
+ lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes;
+ lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize;
+ {
+ int err = lvm_snapshot_alloc(lv_ptr);
+ if (err)
+ {
+ vfree(lv_ptr->lv_block_exception);
+ kfree(lv_ptr);
+ vg[VG_CHR(minor)]->lv[l] = NULL;
+ return err;
+ }
+ }
+ } else {
+ vfree(lv_ptr->lv_block_exception);
+ kfree(lv_ptr);
+ vg_ptr->lv[l] = NULL;
+ return -EFAULT;
+ }
+ } else {
+ kfree(vg_ptr->lv[l]);
+ vg_ptr->lv[l] = NULL;
+ return -EINVAL;
+ }
+ } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
+
+ lv_ptr = vg_ptr->lv[l];
+ lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
+ lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
+ lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
+ vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number;
+ vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number;
+ LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
+ vg_ptr->lv_cur++;
+ lv_ptr->lv_status = lv_status_save;
+
+ /* optionally add our new snapshot LV */
+ if (lv_ptr->lv_access & LV_SNAPSHOT) {
+ /* sync the original logical volume */
+ fsync_dev(lv_ptr->lv_snapshot_org->lv_dev);
+ /* put ourselve into the chain */
+ lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr;
+ lv_ptr->lv_snapshot_org->lv_access |= LV_SNAPSHOT_ORG;
+ }
+ return 0;
+} /* lvm_do_lv_create() */
+
+
+/*
+ * character device support function logical volume remove
+ */
+static int lvm_do_lv_remove(int minor, char *lv_name, int l)
+{
+ uint le, p;
+ vg_t *vg_ptr = vg[VG_CHR(minor)];
+ lv_t *lv_ptr;
+
+ if (l == -1) {
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ if (vg_ptr->lv[l] != NULL &&
+ strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) {
+ break;
+ }
+ }
+ }
+ if (l == vg_ptr->lv_max) return -ENXIO;
+
+ lv_ptr = vg_ptr->lv[l];
+#ifdef LVM_TOTAL_RESET
+ if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0)
+#else
+ if (lv_ptr->lv_open > 0)
+#endif
+ return -EBUSY;
+
+ /* check for deletion of snapshot source while
+ snapshot volume still exists */
+ if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) &&
+ lv_ptr->lv_snapshot_next != NULL)
+ return -EPERM;
+
+ lv_ptr->lv_status |= LV_SPINDOWN;
+
+ /* sync the buffers */
+ fsync_dev(lv_ptr->lv_dev);
+
+ lv_ptr->lv_status &= ~LV_ACTIVE;
+
+ /* invalidate the buffers */
+ invalidate_buffers(lv_ptr->lv_dev);
+
+ /* reset generic hd */
+ lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1;
+ lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0;
+ lvm_size[MINOR(lv_ptr->lv_dev)] = 0;
+
+ /* reset VG/LV mapping */
+ vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG;
+ vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1;
+
+ /* correct the PE count in PVs if this is no snapshot logical volume */
+ if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
+ /* only if this is no snapshot logical volume because
+ we share the lv_current_pe[] structs with the
+ original logical volume */
+ for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+ vg_ptr->pe_allocated--;
+ for (p = 0; p < vg_ptr->pv_cur; p++) {
+ if (vg_ptr->pv[p]->pv_dev ==
+ lv_ptr->lv_current_pe[le].dev)
+ vg_ptr->pv[p]->pe_allocated--;
+ }
+ }
+ vfree(lv_ptr->lv_current_pe);
+ /* LV_SNAPSHOT */
+ } else {
+ /* remove this snapshot logical volume from the chain */
+ lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next;
+ if (lv_ptr->lv_snapshot_next != NULL) {
+ lv_ptr->lv_snapshot_next->lv_snapshot_prev =
+ lv_ptr->lv_snapshot_prev;
+ }
+ /* no more snapshots? */
+ if (lv_ptr->lv_snapshot_org->lv_snapshot_next == NULL)
+ lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG;
+ lvm_snapshot_release(lv_ptr);
+ }
+
+#ifdef DEBUG_KFREE
+ printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
+#endif
+ kfree(lv_ptr);
+ vg_ptr->lv[l] = NULL;
+ vg_ptr->lv_cur--;
+ return 0;
+} /* lvm_do_lv_remove() */
+
+
+/*
+ * character device support function logical volume extend / reduce
+ */
+static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv)
+{
+ int l, le, p, size, old_allocated_le;
+ uint32_t end, lv_status_save;
+ vg_t *vg_ptr = vg[VG_CHR(minor)];
+ lv_t *lv_ptr;
+ pe_t *pe;
+
+ if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
+
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ if (vg_ptr->lv[l] != NULL &&
+ strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
+ break;
+ }
+ if (l == vg_ptr->lv_max) return -ENXIO;
+ lv_ptr = vg_ptr->lv[l];
+
+ /* check for active snapshot */
+ if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) return -EPERM;
+
+ if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) {
+ printk(KERN_CRIT
+ "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE "
+ "of %d Byte at line %d\n",
+ lvm_name, size, __LINE__);
+ return -ENOMEM;
+ }
+ /* get the PE structures from user space */
+ if (copy_from_user(pe, pep, size)) {
+ vfree(pe);
+ return -EFAULT;
+ }
+
+#ifdef DEBUG
+ printk(KERN_DEBUG
+ "%s -- fsync_dev and "
+ "invalidate_buffers for %s [%s] in %s\n",
+ lvm_name, lv_ptr->lv_name,
+ kdevname(lv_ptr->lv_dev),
+ vg_ptr->vg_name);
+#endif
+
+ lv_ptr->lv_status |= LV_SPINDOWN;
+ fsync_dev(lv_ptr->lv_dev);
+ lv_ptr->lv_status &= ~LV_ACTIVE;
+ invalidate_buffers(lv_ptr->lv_dev);
+
+ /* reduce allocation counters on PV(s) */
+ for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+ vg_ptr->pe_allocated--;
+ for (p = 0; p < vg_ptr->pv_cur; p++) {
+ if (vg_ptr->pv[p]->pv_dev ==
+ lv_ptr->lv_current_pe[le].dev) {
+ vg_ptr->pv[p]->pe_allocated--;
+ break;
+ }
+ }
+ }
+
+
+ /* save pointer to "old" lv/pe pointer array */
+ pep1 = lv_ptr->lv_current_pe;
+ end = lv_ptr->lv_current_le;
+
+ /* save open counter */
+ lv_open = lv_ptr->lv_open;
+
+ /* save # of old allocated logical extents */
+ old_allocated_le = lv_ptr->lv_allocated_le;
+
+ /* copy preloaded LV */
+ lv_status_save = lv->lv_status;
+ lv->lv_status |= LV_SPINDOWN;
+ lv->lv_status &= ~LV_ACTIVE;
+ memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
+ lv_ptr->lv_current_pe = pe;
+ lv_ptr->lv_open = lv_open;
+
+ /* save availiable i/o statistic data */
+ /* linear logical volume */
+ if (lv_ptr->lv_stripes < 2) {
+ /* Check what last LE shall be used */
+ if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le;
+ for (le = 0; le < end; le++) {
+ lv_ptr->lv_current_pe[le].reads = pep1[le].reads;
+ lv_ptr->lv_current_pe[le].writes = pep1[le].writes;
+ }
+ /* striped logical volume */
+ } else {
+ uint i, j, source, dest, end, old_stripe_size, new_stripe_size;
+
+ old_stripe_size = old_allocated_le / lv_ptr->lv_stripes;
+ new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes;
+ end = old_stripe_size;
+ if (end > new_stripe_size) end = new_stripe_size;
+ for (i = source = dest = 0;
+ i < lv_ptr->lv_stripes; i++) {
+ for (j = 0; j < end; j++) {
+ lv_ptr->lv_current_pe[dest + j].reads =
+ pep1[source + j].reads;
+ lv_ptr->lv_current_pe[dest + j].writes =
+ pep1[source + j].writes;
+ }
+ source += old_stripe_size;
+ dest += new_stripe_size;
+ }
+ }
+ vfree(pep1);
+ pep1 = NULL;
+
+
+ /* extend the PE count in PVs */
+ for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+ vg_ptr->pe_allocated++;
+ for (p = 0; p < vg_ptr->pv_cur; p++) {
+ if (vg_ptr->pv[p]->pv_dev ==
+ vg_ptr->lv[l]->lv_current_pe[le].dev) {
+ vg_ptr->pv[p]->pe_allocated++;
+ break;
+ }
+ }
+ }
+
+ lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
+ lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
+ lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
+ /* vg_lv_map array doesn't have to be changed here */
+
+ LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
+ lv_ptr->lv_status = lv_status_save;
+
+ return 0;
+} /* lvm_do_lv_extend_reduce() */
+
+
+/*
+ * character device support function logical volume status by name
+ */
+static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg)
+{
+ uint l;
+ ulong size;
+ lv_t lv;
+ lv_t *lv_ptr;
+ lv_status_byname_req_t lv_status_byname_req;
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&lv_status_byname_req, arg,
+ sizeof(lv_status_byname_req_t)) != 0)
+ return -EFAULT;
+
+ if (lv_status_byname_req.lv == NULL) return -EINVAL;
+ if (copy_from_user(&lv, lv_status_byname_req.lv,
+ sizeof(lv_t)) != 0)
+ return -EFAULT;
+
+ for (l = 0; l < vg_ptr->lv_max; l++) {
+ lv_ptr = vg_ptr->lv[l];
+ if (lv_ptr != NULL &&
+ strcmp(lv_ptr->lv_name,
+ lv_status_byname_req.lv_name) == 0) {
+ if (copy_to_user(lv_status_byname_req.lv,
+ lv_ptr,
+ sizeof(lv_t)) != 0)
+ return -EFAULT;
+
+ if (lv.lv_current_pe != NULL) {
+ size = lv_ptr->lv_allocated_le *
+ sizeof(pe_t);
+ if (copy_to_user(lv.lv_current_pe,
+ lv_ptr->lv_current_pe,
+ size) != 0)
+ return -EFAULT;
+ }
+ return 0;
+ }
+ }
+ return -ENXIO;
+} /* lvm_do_lv_status_byname() */
+
+
+/*
+ * character device support function logical volume status by index
+ */
+static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg)
+{
+ ulong size;
+ lv_t lv;
+ lv_t *lv_ptr;
+ lv_status_byindex_req_t lv_status_byindex_req;
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&lv_status_byindex_req, arg,
+ sizeof(lv_status_byindex_req)) != 0)
+ return -EFAULT;
+
+ if ((lvp = lv_status_byindex_req.lv) == NULL)
+ return -EINVAL;
+ if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
+ return -ENXIO;
+
+ if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0)
+ return -EFAULT;
+
+ if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0)
+ return -EFAULT;
+
+ if (lv.lv_current_pe != NULL) {
+ size = lv_ptr->lv_allocated_le * sizeof(pe_t);
+ if (copy_to_user(lv.lv_current_pe,
+ lv_ptr->lv_current_pe,
+ size) != 0)
+ return -EFAULT;
+ }
+ return 0;
+} /* lvm_do_lv_status_byindex() */
+
+
+/*
+ * character device support function physical volume change
+ */
+static int lvm_do_pv_change(vg_t *vg_ptr, void *arg)
+{
+ uint p;
+ pv_t *pv_ptr;
+#ifdef LVM_GET_INODE
+ struct inode *inode_sav;
+#endif
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&pv_change_req, arg,
+ sizeof(pv_change_req)) != 0)
+ return -EFAULT;
+
+ for (p = 0; p < vg_ptr->pv_max; p++) {
+ pv_ptr = vg_ptr->pv[p];
+ if (pv_ptr != NULL &&
+ strcmp(pv_ptr->pv_name,
+ pv_change_req.pv_name) == 0) {
+#ifdef LVM_GET_INODE
+ inode_sav = pv_ptr->inode;
+#endif
+ if (copy_from_user(pv_ptr,
+ pv_change_req.pv,
+ sizeof(pv_t)) != 0)
+ return -EFAULT;
+
+ /* We don't need the PE list
+ in kernel space as with LVs pe_t list */
+ pv_ptr->pe = NULL;
+#ifdef LVM_GET_INODE
+ pv_ptr->inode = inode_sav;
+#endif
+ return 0;
+ }
+ }
+ return -ENXIO;
+} /* lvm_do_pv_change() */
+
+/*
+ * character device support function get physical volume status
+ */
+static int lvm_do_pv_status(vg_t *vg_ptr, void *arg)
+{
+ uint p;
+ pv_t *pv_ptr;
+
+ if (vg_ptr == NULL) return -ENXIO;
+ if (copy_from_user(&pv_status_req, arg,
+ sizeof(pv_status_req)) != 0)
+ return -EFAULT;
+
+ for (p = 0; p < vg_ptr->pv_max; p++) {
+ pv_ptr = vg_ptr->pv[p];
+ if (pv_ptr != NULL &&
+ strcmp(pv_ptr->pv_name,
+ pv_status_req.pv_name) == 0) {
+ if (copy_to_user(pv_status_req.pv,
+ pv_ptr,
+ sizeof(pv_t)) != 0)
+ return -EFAULT;
+ return 0;
+ }
+ }
+ return -ENXIO;
+} /* lvm_do_pv_status() */
+
+
+/*
+ * support function initialize gendisk variables
+ */
+#ifdef __initfunc
+__initfunc(void lvm_geninit(struct gendisk *lvm_gdisk))
+#else
+void __init
+ lvm_geninit(struct gendisk *lvm_gdisk)
+#endif
+{
+ int i = 0;
+
+#ifdef DEBUG_GENDISK
+ printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name);
+#endif
+
+ for (i = 0; i < MAX_LV; i++) {
+ lvm_gendisk.part[i].start_sect = -1; /* avoid partition check */
+ lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0;
+ lvm_blocksizes[i] = BLOCK_SIZE;
+ }
+
+ blksize_size[MAJOR_NR] = lvm_blocksizes;
+ blk_size[MAJOR_NR] = lvm_size;
+
+ return;
+} /* lvm_gen_init() */
+
+
+#ifdef LVM_GET_INODE
+/*
+ * support function to get an empty inode
+ *
+ * Gets an empty inode to be inserted into the inode hash,
+ * so that a physical volume can't be mounted.
+ * This is analog to drivers/block/md.c
+ *
+ * Is this the real thing?
+ *
+ */
+struct inode *lvm_get_inode(int dev)
+{
+ struct inode *inode_this = NULL;
+
+ /* Lock the device by inserting a dummy inode. */
+ inode_this = get_empty_inode();
+ inode_this->i_dev = dev;
+ insert_inode_hash(inode_this);
+ return inode_this;
+}
+
+
+/*
+ * support function to clear an inode
+ *
+ */
+void lvm_clear_inode(struct inode *inode)
+{
+#ifdef I_FREEING
+ inode->i_state |= I_FREEING;
+#endif
+ clear_inode(inode);
+ return;
+}
+#endif /* #ifdef LVM_GET_INODE */
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 752c7b0ab..b258fc6c5 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -11,6 +11,7 @@
- kerneld support by Boris Tobotras <boris@xtalk.msk.su>
- kmod support by: Cyrus Durgin
- RAID0 bugfixes: Mark Anthony Lisher <markal@iname.com>
+ - Devfs support by Richard Gooch <rgooch@atnf.csiro.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,6 +25,7 @@
#include <linux/config.h>
#include <linux/raid/md.h>
+#include <linux/devfs_fs_kernel.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -68,6 +70,9 @@ static mdk_thread_t *md_recovery_thread = NULL;
int md_size[MAX_MD_DEVS] = {0, };
+extern struct block_device_operations md_fops;
+static devfs_handle_t devfs_handle = NULL;
+
static struct gendisk md_gendisk=
{
MD_MAJOR,
@@ -78,7 +83,8 @@ static struct gendisk md_gendisk=
md_size,
MAX_MD_DEVS,
NULL,
- NULL
+ NULL,
+ &md_fops,
};
void md_plug_device (request_queue_t *mdqueue, kdev_t dev)
@@ -3302,11 +3308,15 @@ int md__init md_init (void)
MD_MAJOR_VERSION, MD_MINOR_VERSION,
MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MAX_REAL);
- if (register_blkdev (MD_MAJOR, "md", &md_fops))
+ if (devfs_register_blkdev (MD_MAJOR, "md", &md_fops))
{
printk (KERN_ALERT "Unable to get major %d for md\n", MD_MAJOR);
return (-1);
}
+ devfs_handle = devfs_mk_dir (NULL, "md", 0, NULL);
+ devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT,
+ MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
+ &md_fops, NULL);
blk_dev[MD_MAJOR].queue = md_get_queue;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 0efcce8ed..abecb27c4 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -184,10 +184,10 @@ struct request *nbd_read_stat(struct nbd_device *lo)
DEBUG("reading control, ");
reply.magic = 0;
result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply));
- req = lo->tail;
if (result <= 0)
HARDFAIL("Recv control failed.");
memcpy(&xreq, reply.handle, sizeof(xreq));
+ req = blkdev_entry_prev_request(&lo->queue_head);
if (xreq != req)
FAIL("Unexpected handle received.\n");
@@ -216,47 +216,41 @@ void nbd_do_it(struct nbd_device *lo)
{
struct request *req;
- while (1) {
+ down (&lo->queue_lock);
+ while (!list_empty(&lo->queue_head)) {
req = nbd_read_stat(lo);
if (!req)
- return;
- down (&lo->queue_lock);
+ goto out;
#ifdef PARANOIA
- if (req != lo->tail) {
+ if (req != blkdev_entry_prev_request(&lo->queue_head)) {
printk(KERN_ALERT "NBD: I have problem...\n");
}
if (lo != &nbd_dev[MINOR(req->rq_dev)]) {
printk(KERN_ALERT "NBD: request corrupted!\n");
- goto next;
+ continue;
}
if (lo->magic != LO_MAGIC) {
printk(KERN_ALERT "NBD: nbd_dev[] corrupted: Not enough magic\n");
- up (&lo->queue_lock);
- return;
+ goto out;
}
#endif
- nbd_end_request(req);
- if (lo->tail == lo->head) {
-#ifdef PARANOIA
- if (lo->tail->next)
- printk(KERN_ERR "NBD: I did not expect this\n");
-#endif
- lo->head = NULL;
- }
- lo->tail = lo->tail->next;
- next:
+ list_del(&req->queue);
up (&lo->queue_lock);
+
+ nbd_end_request(req);
+
+ down (&lo->queue_lock);
}
+ out:
+ up (&lo->queue_lock);
}
void nbd_clear_que(struct nbd_device *lo)
{
struct request *req;
- while (1) {
- req = lo->tail;
- if (!req)
- return;
+ while (!list_empty(&lo->queue_head)) {
+ req = blkdev_entry_prev_request(&lo->queue_head);
#ifdef PARANOIA
if (lo != &nbd_dev[MINOR(req->rq_dev)]) {
printk(KERN_ALERT "NBD: request corrupted when clearing!\n");
@@ -268,15 +262,12 @@ void nbd_clear_que(struct nbd_device *lo)
}
#endif
req->errors++;
+ list_del(&req->queue);
+ up(&lo->queue_lock);
+
nbd_end_request(req);
- if (lo->tail == lo->head) {
-#ifdef PARANOIA
- if (lo->tail->next)
- printk(KERN_ERR "NBD: I did not assume this\n");
-#endif
- lo->head = NULL;
- }
- lo->tail = lo->tail->next;
+
+ down(&lo->queue_lock);
}
}
@@ -296,7 +287,7 @@ static void do_nbd_request(request_queue_t * q)
int dev;
struct nbd_device *lo;
- while (CURRENT) {
+ while (!QUEUE_EMPTY) {
req = CURRENT;
dev = MINOR(req->rq_dev);
#ifdef PARANOIA
@@ -314,28 +305,23 @@ static void do_nbd_request(request_queue_t * q)
requests_in++;
#endif
req->errors = 0;
- CURRENT = CURRENT->next;
- req->next = NULL;
-
+ blkdev_dequeue_request(req);
spin_unlock_irq(&io_request_lock);
- down (&lo->queue_lock);
- if (lo->head == NULL) {
- lo->head = req;
- lo->tail = req;
- } else {
- lo->head->next = req;
- lo->head = req;
- }
+ down (&lo->queue_lock);
+ list_add(&req->queue, &lo->queue_head);
nbd_send_req(lo->sock, req); /* Why does this block? */
up (&lo->queue_lock);
+
spin_lock_irq(&io_request_lock);
continue;
error_out:
req->errors++;
+ blkdev_dequeue_request(req);
+ spin_unlock(&io_request_lock);
nbd_end_request(req);
- CURRENT = CURRENT->next;
+ spin_lock(&io_request_lock);
}
return;
}
@@ -359,11 +345,14 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
lo = &nbd_dev[dev];
switch (cmd) {
case NBD_CLEAR_SOCK:
+ down(&lo->queue_lock);
nbd_clear_que(lo);
- if (lo->head || lo->tail) {
+ if (!list_empty(&lo->queue_head)) {
+ up(&lo->queue_lock);
printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
return -EBUSY;
}
+ up(&lo->queue_lock);
file = lo->file;
if (!file)
return -EINVAL;
@@ -415,8 +404,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
return 0;
#ifdef PARANOIA
case NBD_PRINT_DEBUG:
- printk(KERN_INFO "NBD device %d: head = %lx, tail = %lx. Global: in %d, out %d\n",
- dev, (long) lo->head, (long) lo->tail, requests_in, requests_out);
+ printk(KERN_INFO "NBD device %d: next = %p, prev = %p. Global: in %d, out %d\n",
+ dev, lo->queue_head.next, lo->queue_head.prev, requests_in, requests_out);
return 0;
#endif
case BLKGETSIZE:
@@ -480,6 +469,7 @@ int nbd_init(void)
blksize_size[MAJOR_NR] = nbd_blksizes;
blk_size[MAJOR_NR] = nbd_sizes;
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request);
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
for (i = 0; i < MAX_NBD; i++) {
nbd_dev[i].refcnt = 0;
nbd_dev[i].file = NULL;
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 7db6626f4..878709944 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -756,7 +756,7 @@ static void do_pcd_request (request_queue_t * q)
if (pcd_busy) return;
while (1) {
- if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
+ if (QUEUE_EMPTY || (CURRENT->rq_status == RQ_INACTIVE)) return;
INIT_REQUEST;
if (CURRENT->cmd == READ) {
unit = MINOR(CURRENT->rq_dev);
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 577d1354c..f40958ecd 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -156,6 +156,7 @@ static int pd_drive_count;
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/genhd.h>
@@ -339,6 +340,8 @@ static char *pd_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR",
/* kernel glue structures */
+extern struct block_device_operations pd_fops;
+
static struct gendisk pd_gendisk = {
PD_MAJOR, /* Major number */
PD_NAME, /* Major name */
@@ -348,7 +351,8 @@ static struct gendisk pd_gendisk = {
pd_sizes, /* block sizes */
0, /* number */
NULL, /* internal */
- NULL /* next */
+ NULL, /* next */
+ &pd_fops, /* block device operations */
};
static struct block_device_operations pd_fops = {
@@ -386,8 +390,7 @@ int pd_init (void)
{ int i;
if (disable) return -1;
-
- if (register_blkdev(MAJOR_NR,name,&pd_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) {
printk("%s: unable to get major number %d\n",
name,major);
return -1;
@@ -592,8 +595,7 @@ void cleanup_module(void)
{ struct gendisk **gdp;
int unit;
- unregister_blkdev(MAJOR_NR,name);
-
+ devfs_unregister_blkdev(MAJOR_NR,name);
for(gdp=&gendisk_head;*gdp;gdp=&((*gdp)->next))
if (*gdp == &pd_gendisk) break;
if (*gdp) *gdp = (*gdp)->next;
@@ -868,7 +870,7 @@ static void do_pd_request (request_queue_t * q)
if (pd_busy) return;
repeat:
- if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
+ if (QUEUE_EMPTY || (CURRENT->rq_status == RQ_INACTIVE)) return;
INIT_REQUEST;
pd_dev = MINOR(CURRENT->rq_dev);
@@ -890,7 +892,7 @@ repeat:
pd_cmd = CURRENT->cmd;
pd_run = pd_count;
while ((pd_run <= cluster) &&
- (req = req->next) &&
+ (req = blkdev_next_request(req)) &&
(pd_block+pd_run == req->sector) &&
(pd_cmd == req->cmd) &&
(pd_dev == MINOR(req->rq_dev)))
@@ -922,7 +924,7 @@ static void pd_next_buf( int unit )
/* paranoia */
- if ((!CURRENT) ||
+ if (QUEUE_EMPTY ||
(CURRENT->cmd != pd_cmd) ||
(MINOR(CURRENT->rq_dev) != pd_dev) ||
(CURRENT->rq_status == RQ_INACTIVE) ||
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index d658a0369..4e7a5aaf4 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -854,7 +854,7 @@ static void do_pf_request (request_queue_t * q)
if (pf_busy) return;
repeat:
- if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
+ if (QUEUE_EMPTY || (CURRENT->rq_status == RQ_INACTIVE)) return;
INIT_REQUEST;
pf_unit = unit = DEVICE_NR(CURRENT->rq_dev);
@@ -874,7 +874,7 @@ repeat:
pf_cmd = CURRENT->cmd;
pf_run = pf_count;
while ((pf_run <= cluster) &&
- (req = req->next) &&
+ (req = blkdev_next_request(req)) &&
(pf_block+pf_run == req->sector) &&
(pf_cmd == req->cmd) &&
(pf_unit == DEVICE_NR(req->rq_dev)))
@@ -904,7 +904,7 @@ static void pf_next_buf( int unit )
/* paranoia */
- if ((!CURRENT) ||
+ if (QUEUE_EMPTY ||
(CURRENT->cmd != pf_cmd) ||
(DEVICE_NR(CURRENT->rq_dev) != pf_unit) ||
(CURRENT->rq_status == RQ_INACTIVE) ||
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 434fac029..b4e36726c 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -164,6 +164,7 @@ static int pg_drive_count;
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/malloc.h>
@@ -286,6 +287,8 @@ void pg_init_units( void )
}
}
+static devfs_handle_t devfs_handle = NULL;
+
int pg_init (void) /* preliminary initialisation */
{ int unit;
@@ -296,14 +299,17 @@ int pg_init (void) /* preliminary initialisation */
if (pg_detect()) return -1;
- if (register_chrdev(major,name,&pg_fops)) {
+ if (devfs_register_chrdev(major,name,&pg_fops)) {
printk("pg_init: unable to get major number %d\n",
major);
for (unit=0;unit<PG_UNITS;unit++)
if (PG.present) pi_release(PI);
return -1;
}
-
+ devfs_handle = devfs_mk_dir (NULL, "pg", 2, NULL);
+ devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
+ major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &pg_fops, NULL);
return 0;
}
@@ -332,7 +338,8 @@ void cleanup_module(void)
{ int unit;
- unregister_chrdev(major,name);
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev(major,name);
for (unit=0;unit<PG_UNITS;unit++)
if (PG.present) pi_release(PI);
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index ba24c9956..459ef7237 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -143,6 +143,7 @@ static int pt_drive_count;
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/malloc.h>
@@ -290,6 +291,8 @@ void pt_init_units( void )
}
}
+static devfs_handle_t devfs_handle = NULL;
+
int pt_init (void) /* preliminary initialisation */
{ int unit;
@@ -300,7 +303,7 @@ int pt_init (void) /* preliminary initialisation */
if (pt_detect()) return -1;
- if (register_chrdev(major,name,&pt_fops)) {
+ if (devfs_register_chrdev(major,name,&pt_fops)) {
printk("pt_init: unable to get major number %d\n",
major);
for (unit=0;unit<PT_UNITS;unit++)
@@ -308,6 +311,13 @@ int pt_init (void) /* preliminary initialisation */
return -1;
}
+ devfs_handle = devfs_mk_dir (NULL, "pt", 2, NULL);
+ devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
+ major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &pt_fops, NULL);
+ devfs_register_series (devfs_handle, "%un", 4, DEVFS_FL_DEFAULT,
+ major, 128, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &pt_fops, NULL);
return 0;
}
@@ -334,9 +344,10 @@ int init_module(void)
void cleanup_module(void)
-{ int unit;
+{ int unit;
- unregister_chrdev(major,name);
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev(major,name);
for (unit=0;unit<PT_UNITS;unit++)
if (PT.present) pi_release(PI);
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 9f68ebbfc..305c89a00 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -41,6 +41,7 @@
#include <linux/kernel.h>
#include <linux/genhd.h>
#include <linux/ps2esdi.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/blk.h>
#include <linux/blkpg.h>
#include <linux/mca.h>
@@ -164,7 +165,8 @@ static struct gendisk ps2esdi_gendisk =
ps2esdi_sizes, /* block sizes */
0, /* number */
(void *) ps2esdi_info, /* internal */
- NULL /* next */
+ NULL, /* next */
+ &ps2esdi_fops, /* file operations */
};
/* initialization routine called by ll_rw_blk.c */
@@ -173,7 +175,7 @@ int __init ps2esdi_init(void)
/* register the device - pass the name, major number and operations
vector . */
- if (register_blkdev(MAJOR_NR, "ed", &ps2esdi_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR, "ed", &ps2esdi_fops)) {
printk("%s: Unable to get major number %d\n", DEVICE_NAME, MAJOR_NR);
return -1;
}
@@ -229,7 +231,7 @@ cleanup_module(void)
release_region(io_base, 4);
free_dma(dma_arb_level);
free_irq(PS2ESDI_IRQ, NULL)
- unregister_blkdev(MAJOR_NR, "ed");
+ devfs_unregister_blkdev(MAJOR_NR, "ed");
}
#endif /* MODULE */
@@ -476,7 +478,7 @@ static void do_ps2esdi_request(request_queue_t * q)
if (virt_to_bus(CURRENT->buffer + CURRENT->nr_sectors * 512) > 16 * MB) {
printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
end_request(FAIL);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(q);
return;
} /* check for above 16Mb dmas */
@@ -510,7 +512,7 @@ static void do_ps2esdi_request(request_queue_t * q)
default:
printk("%s: Unknown command\n", DEVICE_NAME);
end_request(FAIL);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(q);
break;
} /* handle different commands */
@@ -520,7 +522,7 @@ static void do_ps2esdi_request(request_queue_t * q)
printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives,
CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects);
end_request(FAIL);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(q);
}
@@ -591,7 +593,7 @@ static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count)
return do_ps2esdi_request(NULL);
else {
end_request(FAIL);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(NULL);
}
}
@@ -894,7 +896,7 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
do_ps2esdi_request(NULL);
else {
end_request(FAIL);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(NULL);
}
break;
@@ -940,7 +942,7 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
do_ps2esdi_request(NULL);
else {
end_request(FAIL);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(NULL);
}
break;
@@ -950,7 +952,7 @@ static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
end_request(FAIL);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(NULL);
break;
@@ -986,7 +988,7 @@ static void ps2esdi_continue_request(void)
do_ps2esdi_request(NULL);
} else {
end_request(SUCCES);
- if (CURRENT)
+ if (!QUEUE_EMPTY)
do_ps2esdi_request(NULL);
}
}
diff --git a/drivers/block/raid1.c b/drivers/block/raid1.c
index 6671f83e8..057be0d64 100644
--- a/drivers/block/raid1.c
+++ b/drivers/block/raid1.c
@@ -211,7 +211,11 @@ raid1_make_request (struct md_dev *mddev, int rw, struct buffer_head * bh)
while (!( /* FIXME: now we are rather fault tolerant than nice */
r1_bh = kmalloc (sizeof (struct raid1_bh), GFP_KERNEL)
) )
+ {
printk ("raid1_make_request(#1): out of memory\n");
+ current->policy |= SCHED_YIELD;
+ schedule();
+ }
memset (r1_bh, 0, sizeof (struct raid1_bh));
/*
@@ -298,7 +302,11 @@ raid1_make_request (struct md_dev *mddev, int rw, struct buffer_head * bh)
while (!( /* FIXME: now we are rather fault tolerant than nice */
mirror_bh[i] = kmalloc (sizeof (struct buffer_head), GFP_KERNEL)
) )
+ {
printk ("raid1_make_request(#2): out of memory\n");
+ current->policy |= SCHED_YIELD;
+ schedule();
+ }
memset (mirror_bh[i], 0, sizeof (struct buffer_head));
/*
@@ -710,7 +718,11 @@ static int raid1_run (int minor, struct md_dev *mddev)
while (!( /* FIXME: now we are rather fault tolerant than nice */
mddev->private = kmalloc (sizeof (struct raid1_data), GFP_KERNEL)
) )
+ {
printk ("raid1_run(): out of memory\n");
+ current->policy |= SCHED_YIELD;
+ schedule();
+ }
raid_conf = mddev->private;
memset(raid_conf, 0, sizeof(*raid_conf));
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 17a745d5b..19f485df0 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -58,6 +58,7 @@
#include <linux/fd.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -97,6 +98,7 @@ static unsigned long rd_length[NUM_RAMDISKS]; /* Size of RAM disks in bytes */
static int rd_hardsec[NUM_RAMDISKS]; /* Size of real blocks in bytes */
static int rd_blocksizes[NUM_RAMDISKS]; /* Size of 1024 byte blocks :) */
static int rd_kbsize[NUM_RAMDISKS]; /* Size in blocks of 1024 bytes */
+static devfs_handle_t devfs_handle = NULL;
/*
* Parameters for the boot-loading of the RAM disk. These are set by
@@ -180,6 +182,8 @@ __setup("ramdisk_size=", ramdisk_size2);
* deleted, and make that my Ramdisk. If the request is outside of the
* allocated size, we must get rid of it...
*
+ * 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Added devfs support
+ *
*/
static void rd_request(request_queue_t * q)
{
@@ -362,6 +366,7 @@ static int rd_open(struct inode * inode, struct file * filp)
if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
return -ENXIO;
+ filp->f_op = &def_blk_fops;
MOD_INC_USE_COUNT;
return 0;
@@ -387,6 +392,7 @@ static void __exit rd_cleanup (void)
for (i = 0 ; i < NUM_RAMDISKS; i++)
destroy_buffers(MKDEV(MAJOR_NR, i));
+ devfs_unregister (devfs_handle);
unregister_blkdev( MAJOR_NR, "ramdisk" );
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
}
@@ -418,6 +424,11 @@ int __init rd_init (void)
rd_blocksizes[i] = rd_blocksize;
rd_kbsize[i] = rd_size;
}
+ devfs_handle = devfs_mk_dir (NULL, "rd", 0, NULL);
+ devfs_register_series (devfs_handle, "%u", NUM_RAMDISKS,
+ DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
+ &fd_fops, NULL);
hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */
blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */
@@ -560,7 +571,7 @@ done:
*/
static void __init rd_load_image(kdev_t device, int offset, int unit)
{
- struct inode inode, out_inode;
+ struct inode *inode, *out_inode;
struct file infile, outfile;
struct dentry in_dentry, out_dentry;
mm_segment_t fs;
@@ -574,25 +585,27 @@ static void __init rd_load_image(kdev_t device, int offset, int unit)
ram_device = MKDEV(MAJOR_NR, unit);
memset(&infile, 0, sizeof(infile));
- memset(&inode, 0, sizeof(inode));
memset(&in_dentry, 0, sizeof(in_dentry));
- inode.i_rdev = device;
- init_waitqueue_head(&inode.i_wait);
+ inode = get_empty_inode();
+ inode->i_rdev = device;
+ inode->i_bdev = bdget(kdev_t_to_nr(device));
infile.f_mode = 1; /* read only */
infile.f_dentry = &in_dentry;
- in_dentry.d_inode = &inode;
+ in_dentry.d_inode = inode;
memset(&outfile, 0, sizeof(outfile));
- memset(&out_inode, 0, sizeof(out_inode));
memset(&out_dentry, 0, sizeof(out_dentry));
- out_inode.i_rdev = ram_device;
- init_waitqueue_head(&out_inode.i_wait);
+ out_inode = get_empty_inode();
+ out_inode->i_rdev = ram_device;
+ out_inode->i_bdev = bdget(kdev_t_to_nr(ram_device));
outfile.f_mode = 3; /* read/write */
outfile.f_dentry = &out_dentry;
- out_dentry.d_inode = &out_inode;
+ out_dentry.d_inode = out_inode;
- if (blkdev_open(&inode, &infile) != 0) return;
- if (blkdev_open(&out_inode, &outfile) != 0) return;
+ if (blkdev_open(inode, &infile) != 0)
+ goto free_inodes;
+ if (blkdev_open(out_inode, &outfile) != 0)
+ goto free_inodes;
fs = get_fs();
set_fs(KERNEL_DS);
@@ -655,10 +668,10 @@ static void __init rd_load_image(kdev_t device, int offset, int unit)
rotate = 0;
invalidate_buffers(device);
if (infile.f_op->release)
- infile.f_op->release(&inode, &infile);
+ infile.f_op->release(inode, &infile);
printk("Please insert disk #%d and press ENTER\n", i/devblocks+1);
wait_for_keypress();
- if (blkdev_open(&inode, &infile) != 0) {
+ if (blkdev_open(inode, &infile) != 0) {
printk("Error opening disk.\n");
goto done;
}
@@ -678,11 +691,15 @@ static void __init rd_load_image(kdev_t device, int offset, int unit)
successful_load:
invalidate_buffers(device);
ROOT_DEV = MKDEV(MAJOR_NR, unit);
+ if (ROOT_DEVICE_NAME != NULL) strcpy (ROOT_DEVICE_NAME, "rd/0");
done:
if (infile.f_op->release)
- infile.f_op->release(&inode, &infile);
+ infile.f_op->release(inode, &infile);
set_fs(fs);
+free_inodes:
+ iput(inode);
+ iput(out_inode);
}
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 911bafe23..f38e10209 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -305,7 +305,7 @@ static void start_request(struct floppy_state *fs)
wake_up(&fs->wait);
return;
}
- while (CURRENT && fs->state == idle) {
+ while (!QUEUE_EMPTY && fs->state == idle) {
if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
panic(DEVICE_NAME ": request list destroyed");
if (CURRENT->bh && !buffer_locked(CURRENT->bh))
diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
index 467cda26d..d37059d38 100644
--- a/drivers/block/swim_iop.c
+++ b/drivers/block/swim_iop.c
@@ -550,7 +550,7 @@ static void start_request(struct floppy_state *fs)
wake_up(&fs->wait);
return;
}
- while (CURRENT && fs->state == idle) {
+ while (!QUEUE_EMPTY && fs->state == idle) {
if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
panic(DEVICE_NAME ": request list destroyed");
if (CURRENT->bh && !buffer_locked(CURRENT->bh))
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index b4c52d6a2..fde487ecd 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -41,6 +41,7 @@
#include <linux/hdreg.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -87,21 +88,8 @@ XD_INFO xd_info[XD_MAXDRIVES];
should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
#include <asm/page.h>
-/* coppied from floppy.c */
-static inline int __get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size))
-#define xd_dma_mem_free(addr, size) free_pages(addr, __get_order(size))
+#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size))
+#define xd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
static char *xd_dma_buffer = 0;
static XD_SIGNATURE xd_sigs[] __initdata = {
@@ -130,6 +118,9 @@ static unsigned int xd_bases[] __initdata =
static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES] = { 0, 0 };
static int xd_blocksizes[XD_MAXDRIVES << 6];
+
+extern struct block_device_operations xd_fops;
+
static struct gendisk xd_gendisk = {
MAJOR_NR, /* Major number */
"xd", /* Major name */
@@ -139,7 +130,8 @@ static struct gendisk xd_gendisk = {
xd_sizes, /* block sizes */
0, /* number */
(void *) xd_info, /* internal */
- NULL /* next */
+ NULL, /* next */
+ &xd_fops, /* file operations */
};
static struct block_device_operations xd_fops = {
open: xd_open,
@@ -164,13 +156,16 @@ static struct timer_list xd_timer = { NULL, NULL, 0, 0, (timeout_fn) xd_wakeup }
static volatile u_char xd_error;
static int nodma = XD_DONT_USE_DMA;
+static devfs_handle_t devfs_handle = NULL;
+
/* xd_init: register the block device number and set up pointer tables */
int __init xd_init (void)
{
- if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
printk("xd: Unable to get major number %d\n",MAJOR_NR);
return -1;
}
+ devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, 0, NULL);
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
xd_gendisk.next = gendisk_head;
@@ -287,7 +282,7 @@ static void do_xd_request (request_queue_t * q)
sti();
if (xdc_busy)
return;
- while (code = 0, CURRENT) {
+ while (code = 0, !QUEUE_EMPTY) {
INIT_REQUEST; /* do some checking on the request structure */
if (CURRENT_DEV < xd_drives
@@ -1162,7 +1157,7 @@ int init_module(void)
printk(KERN_INFO "XD: Loaded as a module.\n");
if (!xd_drives) {
/* no drives detected - unload module */
- unregister_blkdev(MAJOR_NR, "xd");
+ devfs_unregister_blkdev(MAJOR_NR, "xd");
xd_done();
return (-1);
}
@@ -1174,7 +1169,7 @@ void cleanup_module(void)
{
int partition,dev,start;
- unregister_blkdev(MAJOR_NR, "xd");
+ devfs_unregister_blkdev(MAJOR_NR, "xd");
for (dev = 0; dev < xd_drives; dev++) {
start = dev << xd_gendisk.minor_shift;
for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
@@ -1186,6 +1181,7 @@ void cleanup_module(void)
}
}
xd_done();
+ devfs_unregister (devfs_handle);
if (xd_drives) {
free_irq(xd_irq, NULL);
free_dma(xd_dma);
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index ef9cbd398..e7df93ac6 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -183,6 +183,7 @@
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/major.h>
+#include <linux/devfs_fs_kernel.h>
#ifndef AZT_KERNEL_PRIOR_2_1
#include <linux/init.h>
@@ -234,7 +235,7 @@ static int aztcd_blocksizes[1] = {2048};
#endif
#define CURRENT_VALID \
- (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
+ (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
&& CURRENT -> sector != -1)
#define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
@@ -1785,7 +1786,9 @@ int __init aztcd_init(void)
return -EIO;
}
}
- if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0)
+ devfs_register (NULL, "aztcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &azt_fops, NULL);
+ if (devfs_register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0)
{
printk("aztcd: Unable to get major %d for Aztech CD-ROM\n",
MAJOR_NR);
@@ -1811,7 +1814,9 @@ int __init aztcd_init(void)
void __exit aztcd_exit(void)
{
- if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL))
+ devfs_unregister(devfs_find_handle(NULL, "aztcd", 0, 0, 0, DEVFS_SPECIAL_BLK,
+ 0));
+ if ((devfs_unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL))
{ printk("What's that: can't unregister aztcd\n");
return;
}
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index c40e0ae28..c20ce1b93 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -291,6 +291,7 @@ int cdrom_get_next_writable(kdev_t dev, long *next_writable);
static void cdrom_sysctl_register(void);
#endif /* CONFIG_SYSCTL */
static struct cdrom_device_info *topCdromPtr = NULL;
+static devfs_handle_t devfs_handle = NULL;
struct block_device_operations cdrom_fops =
{
@@ -313,6 +314,8 @@ int register_cdrom(struct cdrom_device_info *cdi)
int major = MAJOR(cdi->dev);
struct cdrom_device_ops *cdo = cdi->ops;
int *change_capability = (int *)&cdo->capability; /* hack */
+ char vname[16];
+ static unsigned int cdrom_counter = 0;
cdinfo(CD_OPEN, "entering register_cdrom\n");
@@ -351,6 +354,31 @@ int register_cdrom(struct cdrom_device_info *cdi)
if (check_media_type==1)
cdi->options |= (int) CDO_CHECK_TYPE;
+ if (!devfs_handle)
+ devfs_handle = devfs_mk_dir (NULL, "cdroms", 6, NULL);
+ sprintf (vname, "cdrom%u", cdrom_counter++);
+ if (cdi->de) {
+ int pos;
+ devfs_handle_t slave;
+ char rname[64];
+
+ pos = devfs_generate_path (cdi->de, rname + 3,
+ sizeof rname - 3);
+ if (pos >= 0) {
+ strncpy (rname + pos, "../", 3);
+ devfs_mk_symlink (devfs_handle, vname, 0,
+ DEVFS_FL_DEFAULT,
+ rname + pos, 0, &slave, NULL);
+ devfs_auto_unregister (cdi->de, slave);
+ }
+ }
+ else {
+ cdi->de =
+ devfs_register (devfs_handle, vname, 0, DEVFS_FL_DEFAULT,
+ MAJOR (cdi->dev), MINOR (cdi->dev),
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ &cdrom_fops, NULL);
+ }
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
cdi->next = topCdromPtr;
topCdromPtr = cdi;
@@ -382,6 +410,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
else
topCdromPtr = cdi->next;
cdi->ops->n_minors--;
+ devfs_unregister (cdi->de);
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
return 0;
}
@@ -2483,6 +2512,7 @@ int init_module(void)
#ifdef CONFIG_SYSCTL
cdrom_sysctl_register();
#endif
+ devfs_handle = devfs_mk_dir (NULL, "cdroms", 6, NULL);
return 0;
}
@@ -2491,7 +2521,8 @@ void cleanup_module(void)
printk(KERN_INFO "Uniform CD-ROM driver unloaded\n");
#ifdef CONFIG_SYSCTL
cdrom_sysctl_unregister();
-#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_SYSCTL */
+ devfs_unregister (devfs_handle);
}
#endif /* endif MODULE */
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 24e7a5c26..0b8d942b4 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -162,6 +162,7 @@
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/ioport.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/init.h>
@@ -1672,7 +1673,7 @@ do_cdu31a_request(request_queue_t * q)
if (signal_pending(current))
{
restore_flags(flags);
- if (CURRENT && CURRENT->rq_status != RQ_INACTIVE)
+ if (!QUEUE_EMPTY && CURRENT->rq_status != RQ_INACTIVE)
{
end_request(0);
}
@@ -1705,7 +1706,7 @@ cdu31a_request_startover:
* The beginning here is stolen from the hard disk driver. I hope
* it's right.
*/
- if (!(CURRENT) || CURRENT->rq_status == RQ_INACTIVE)
+ if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE)
{
goto end_do_cdu31a_request;
}
@@ -3441,7 +3442,7 @@ cdu31a_init(void)
request_region(cdu31a_port, 4,"cdu31a");
- if (register_blkdev(MAJOR_NR,"cdu31a",&cdrom_fops))
+ if (devfs_register_blkdev(MAJOR_NR,"cdu31a",&cdrom_fops))
{
printk("Unable to get major %d for CDU-31a\n", MAJOR_NR);
goto errout2;
@@ -3543,7 +3544,7 @@ cdu31a_init(void)
}
errout0:
printk("Unable to register CDU-31a with Uniform cdrom driver\n");
- if (unregister_blkdev(MAJOR_NR, "cdu31a"))
+ if (devfs_unregister_blkdev(MAJOR_NR, "cdu31a"))
{
printk("Can't unregister block device for cdu31a\n");
}
@@ -3562,7 +3563,7 @@ cdu31a_exit(void)
printk("Can't unregister cdu31a from Uniform cdrom driver\n");
return;
}
- if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL))
+ if ((devfs_unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL))
{
printk("Can't unregister cdu31a\n");
return;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index e600d81d0..05aff4b59 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -187,6 +187,7 @@ History:
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/cdrom.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
@@ -816,7 +817,7 @@ static void do_cm206_request(request_queue_t * q)
while(1) { /* repeat until all requests have been satisfied */
INIT_REQUEST;
- if (CURRENT == NULL || CURRENT->rq_status == RQ_INACTIVE)
+ if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE)
return;
if (CURRENT->cmd != READ) {
debug(("Non-read command %d on cdrom\n", CURRENT->cmd));
@@ -1277,7 +1278,7 @@ static void cleanup(int level)
printk("Can't unregister cdrom cm206\n");
return;
}
- if (unregister_blkdev(MAJOR_NR, "cm206")) {
+ if (devfs_unregister_blkdev(MAJOR_NR, "cm206")) {
printk("Can't unregister major cm206\n");
return;
}
@@ -1390,7 +1391,7 @@ int __init cm206_init(void)
return -EIO;
}
printk(".\n");
- if (register_blkdev(MAJOR_NR, "cm206", &cdrom_fops) != 0) {
+ if (devfs_register_blkdev(MAJOR_NR, "cm206", &cdrom_fops) != 0) {
printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR);
cleanup(3);
return -EIO;
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index 6047df0c7..f563a16c0 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -63,6 +63,7 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -279,13 +280,13 @@ unsigned int block,dev;
unsigned int nsect;
repeat:
- if (!(CURRENT) || CURRENT->rq_status == RQ_INACTIVE) return;
+ if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE) return;
INIT_REQUEST;
dev = MINOR(CURRENT->rq_dev);
block = CURRENT->sector;
nsect = CURRENT->nr_sectors;
- if (CURRENT == NULL || CURRENT -> sector == -1)
+ if (QUEUE_EMPTY || CURRENT -> sector == -1)
return;
if (CURRENT -> cmd != READ)
@@ -991,12 +992,13 @@ long err;
void __exit exit_gscd(void)
{
- if ((unregister_blkdev(MAJOR_NR, "gscd" ) == -EINVAL))
+ devfs_unregister(devfs_find_handle(NULL, "gscd", 0, 0, 0, DEVFS_SPECIAL_BLK,
+ 0));
+ if ((devfs_unregister_blkdev(MAJOR_NR, "gscd" ) == -EINVAL))
{
printk("What's that: can't unregister GoldStar-module\n" );
return;
}
-
release_region (gscd_port,4);
printk(KERN_INFO "GoldStar-module released.\n" );
}
@@ -1067,12 +1069,14 @@ int result;
i++;
}
- if (register_blkdev(MAJOR_NR, "gscd", &gscd_fops) != 0)
+ if (devfs_register_blkdev(MAJOR_NR, "gscd", &gscd_fops) != 0)
{
printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
MAJOR_NR);
return -EIO;
}
+ devfs_register (NULL, "gscd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &gscd_fops, NULL);
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
blksize_size[MAJOR_NR] = gscd_blocksizes;
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
index c882ae30a..44cde3738 100644
--- a/drivers/cdrom/mcd.c
+++ b/drivers/cdrom/mcd.c
@@ -86,6 +86,7 @@
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
#include <linux/string.h>
@@ -134,7 +135,7 @@ static int mcdPresent = 0;
/* #define DOUBLE_QUICK_ONLY */
#define CURRENT_VALID \
-(CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
+(!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
&& CURRENT -> sector != -1)
#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
@@ -1156,7 +1157,7 @@ static void cleanup(int level)
case 2:
release_region(mcd_port,4);
case 1:
- if (unregister_blkdev(MAJOR_NR, "mcd")) {
+ if (devfs_unregister_blkdev(MAJOR_NR, "mcd")) {
printk(KERN_WARNING "Can't unregister major mcd\n");
return;
}
@@ -1181,7 +1182,7 @@ int __init mcd_init(void)
return -EIO;
}
- if (register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0)
+ if (devfs_register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0)
{
printk("Unable to get major %d for Mitsumi CD-ROM\n",
MAJOR_NR);
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index 32ae52497..805044841 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -74,6 +74,7 @@ static const char *mcdx_c_version
#include <linux/major.h>
#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
#include <linux/blk.h>
+#include <linux/devfs_fs_kernel.h>
/* for compatible parameter passing with "insmod" */
#define mcdx_drive_map mcdx
@@ -530,7 +531,7 @@ void do_mcdx_request(request_queue_t * q)
again:
- if (CURRENT == NULL) {
+ if (QUEUE_EMPTY) {
xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
return;
}
@@ -995,7 +996,7 @@ void __exit mcdx_exit(void)
for (i = 0; i < MCDX_NDRIVES; i++) {
struct s_drive_stuff *stuffp;
- if (unregister_cdrom(&mcdx_info)) {
+ if (unregister_cdrom(&mcdx_info)) {
printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
return;
}
@@ -1012,7 +1013,7 @@ void __exit mcdx_exit(void)
kfree(stuffp);
}
- if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
+ if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
xwarn("cleanup() unregister_blkdev() failed\n");
}
#if !MCDX_QUIET
@@ -1123,7 +1124,7 @@ int __init mcdx_init_drive(int drive)
}
xtrace(INIT, "init() register blkdev\n");
- if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) {
+ if (devfs_register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) {
xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
MCDX,
stuffp->wreg_data, stuffp->irq, MAJOR_NR);
@@ -1181,7 +1182,7 @@ int __init mcdx_init_drive(int drive)
MCDX_IO_SIZE);
free_irq(stuffp->irq, NULL);
kfree(stuffp);
- if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
+ if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0)
xwarn("cleanup() unregister_blkdev() failed\n");
return 2;
}
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index b0bdc833a..9a1672037 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -71,6 +71,8 @@
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+
#include <asm/io.h>
#define MAJOR_NR OPTICS_CDROM_MAJOR
@@ -980,7 +982,7 @@ static int update_toc(void)
#define CURRENT_VALID \
- (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
+ (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
&& CURRENT -> cmd == READ && CURRENT -> sector != -1)
@@ -2061,12 +2063,13 @@ int __init optcd_init(void)
DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
return -EIO;
}
- if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
+ if (devfs_register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
{
printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
return -EIO;
}
-
+ devfs_register (NULL, "optcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &opt_fops, NULL);
hardsect_size[MAJOR_NR] = &hsecsize;
blksize_size[MAJOR_NR] = &blksize;
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
@@ -2081,7 +2084,9 @@ int __init optcd_init(void)
void __exit optcd_exit(void)
{
- if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
+ devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0, 0,
+ DEVFS_SPECIAL_BLK, 0));
+ if (devfs_unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
printk(KERN_ERR "optcd: what's that: can't unregister\n");
return;
}
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 42fa4d62b..4c88dacc2 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -338,6 +338,7 @@
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
@@ -4791,9 +4792,7 @@ static void sbp_transfer(struct request *req)
*/
#undef DEBUG_GTL
static inline void sbpcd_end_request(struct request *req, int uptodate) {
- req->next=CURRENT;
- CURRENT=req;
- up(&ioctl_read_sem);
+ list_add(&req->queue, &req->q->queue_head);
end_request(uptodate);
}
/*==========================================================================*/
@@ -4815,7 +4814,7 @@ static void DO_SBPCD_REQUEST(request_queue_t * q)
#ifdef DEBUG_GTL
xnr=++xx_nr;
- if(!CURRENT)
+ if(QUEUE_EMPTY)
{
printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n",
xnr, current->pid, jiffies);
@@ -4830,15 +4829,15 @@ static void DO_SBPCD_REQUEST(request_queue_t * q)
#endif
INIT_REQUEST;
req=CURRENT; /* take out our request so no other */
- CURRENT=req->next; /* task can fuck it up GTL */
- spin_unlock_irq(&io_request_lock); /* FIXME!!!! */
+ blkdev_dequeue_request(req); /* task can fuck it up GTL */
- down(&ioctl_read_sem);
if (req->rq_status == RQ_INACTIVE)
sbpcd_end_request(req, 0);
if (req -> sector == -1)
sbpcd_end_request(req, 0);
+ spin_unlock_irq(&io_request_lock);
+ down(&ioctl_read_sem);
if (req->cmd != READ)
{
msg(DBG_INF, "bad cmd %d\n", req->cmd);
@@ -4875,8 +4874,9 @@ static void DO_SBPCD_REQUEST(request_queue_t * q)
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
+ up(&ioctl_read_sem);
+ spin_lock_irq(&io_request_lock);
sbpcd_end_request(req, 1);
- spin_lock_irq(&io_request_lock); /* FIXME!!!! */
goto request_loop;
}
@@ -4915,8 +4915,9 @@ static void DO_SBPCD_REQUEST(request_queue_t * q)
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
+ up(&ioctl_read_sem);
+ spin_lock_irq(&io_request_lock);
sbpcd_end_request(req, 1);
- spin_lock_irq(&io_request_lock); /* FIXME!!!! */
goto request_loop;
}
}
@@ -4929,9 +4930,10 @@ static void DO_SBPCD_REQUEST(request_queue_t * q)
printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n",
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
- sbpcd_end_request(req, 0);
+ up(&ioctl_read_sem);
sbp_sleep(0); /* wait a bit, try again */
- spin_lock_irq(&io_request_lock); /* FIXME!!!! */
+ spin_lock_irq(&io_request_lock);
+ sbpcd_end_request(req, 0);
goto request_loop;
}
/*==========================================================================*/
@@ -5583,12 +5585,16 @@ static int __init config_spea(void)
* Test for presence of drive and initialize it.
* Called once at boot or load time.
*/
+
+static devfs_handle_t devfs_handle = NULL;
+
#ifdef MODULE
int __init __SBPCD_INIT(void)
#else
int __init SBPCD_INIT(void)
#endif MODULE
{
+ char nbuff[16];
int i=0, j=0;
int addr[2]={1, CDROM_PORT};
int port_index;
@@ -5731,7 +5737,7 @@ int __init SBPCD_INIT(void)
OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */
#endif SOUND_BASE
- if (register_blkdev(MAJOR_NR, major_name, &cdrom_fops) != 0)
+ if (devfs_register_blkdev(MAJOR_NR, major_name, &cdrom_fops) != 0)
{
msg(DBG_INF, "Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR);
#ifdef MODULE
@@ -5741,10 +5747,12 @@ int __init SBPCD_INIT(void)
#endif MODULE
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
read_ahead[MAJOR_NR] = buffers * (CD_FRAMESIZE / 512);
request_region(CDo_command,4,major_name);
+ devfs_handle = devfs_mk_dir (NULL, "sbp", 0, NULL);
for (j=0;j<NR_SBPCD;j++)
{
struct cdrom_device_info * sbpcd_infop;
@@ -5766,7 +5774,7 @@ int __init SBPCD_INIT(void)
if (D_S[j].sbp_buf==NULL)
{
msg(DBG_INF,"data buffer (%d frames) not available.\n",D_S[j].sbp_bufsiz);
- if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
+ if ((devfs_unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
{
printk("Can't unregister %s\n", major_name);
}
@@ -5793,11 +5801,15 @@ int __init SBPCD_INIT(void)
sbpcd_infop->dev = MKDEV(MAJOR_NR, j);
strncpy(sbpcd_infop->name,major_name, sizeof(sbpcd_infop->name));
+ sprintf (nbuff, "c%dt%d/cd", SBPCD_ISSUE - 1, D_S[j].drv_id);
+ sbpcd_infop->de =
+ devfs_register (devfs_handle, nbuff, 0, DEVFS_FL_DEFAULT,
+ MAJOR_NR, j, S_IFBLK | S_IRUGO | S_IWUGO,
+ 0, 0, &cdrom_fops, NULL);
if (register_cdrom(sbpcd_infop))
{
printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n");
}
-
/*
* set the block size
*/
@@ -5827,13 +5839,14 @@ void sbpcd_exit(void)
{
int j;
- if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
+ if ((devfs_unregister_blkdev(MAJOR_NR, major_name) == -EINVAL))
{
msg(DBG_INF, "What's that: can't unregister %s.\n", major_name);
return;
}
release_region(CDo_command,4);
+ devfs_unregister (devfs_handle);
for (j=0;j<NR_SBPCD;j++)
{
if (D_S[j].drv_id==-1) continue;
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index f13deeac8..5182d415d 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -73,6 +73,7 @@
#include <linux/string.h>
#include <linux/major.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -938,7 +939,7 @@ static void sjcd_invalidate_buffers( void ){
*/
#define CURRENT_IS_VALID \
- ( CURRENT != NULL && MAJOR( CURRENT->rq_dev ) == MAJOR_NR && \
+ ( !QUEUE_EMPTY && MAJOR( CURRENT->rq_dev ) == MAJOR_NR && \
CURRENT->cmd == READ && CURRENT->sector != -1 )
static void sjcd_transfer( void ){
@@ -1471,7 +1472,7 @@ int __init sjcd_init( void ){
hardsect_size[MAJOR_NR] = &secsize;
blksize_size[MAJOR_NR] = &blksize;
- if( register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){
+ if( devfs_register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){
printk( "SJCD: Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR );
return( -EIO );
}
@@ -1563,6 +1564,8 @@ int __init sjcd_init( void ){
}
printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base);
+ devfs_register (NULL, "sjcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &sjcd_fops, NULL);
sjcd_present++;
return( 0 );
@@ -1571,7 +1574,7 @@ int __init sjcd_init( void ){
static int
sjcd_cleanup(void)
{
- if( (unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL) )
+ if( (devfs_unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL) )
printk( "SJCD: cannot unregister device.\n" );
else
release_region( sjcd_base, 4 );
@@ -1582,6 +1585,8 @@ sjcd_cleanup(void)
void __exit sjcd_exit(void)
{
+ devfs_unregister(devfs_find_handle(NULL, "sjcd", 0, 0, 0, DEVFS_SPECIAL_BLK,
+ 0));
if ( sjcd_cleanup() )
printk( "SJCD: module: cannot be removed.\n" );
else
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index a9b82571e..1f5fea7b9 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -124,6 +124,7 @@
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
@@ -803,7 +804,7 @@ do_cdu535_request(request_queue_t * q)
* The beginning here is stolen from the hard disk driver. I hope
* it's right.
*/
- if (!(CURRENT) || CURRENT->rq_status == RQ_INACTIVE) {
+ if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE) {
return;
}
INIT_REQUEST;
@@ -1586,7 +1587,12 @@ sony535_init(void)
printk("IRQ%d, ", tmp_irq);
printk("using %d byte buffer\n", sony_buffer_size);
- if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
+ devfs_register (NULL, CDU535_HANDLE, 0,
+ DEVFS_FL_DEFAULT,
+ MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO,
+ 0, 0, &cdu_fops, NULL);
+ if (devfs_register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
printk("Unable to get major %d for %s\n",
MAJOR_NR, CDU535_MESSAGE_NAME);
return -EIO;
@@ -1684,7 +1690,9 @@ sony535_exit(void)
kfree_s(sony_buffer, 4 * sony_buffer_sectors);
kfree_s(last_sony_subcode, sizeof *last_sony_subcode);
kfree_s(sony_toc, sizeof *sony_toc);
- if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
+ devfs_unregister(devfs_find_handle(NULL, CDU535_HANDLE, 0, 0, 0,
+ DEVFS_SPECIAL_BLK, 0));
+ if (devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
else
printk(KERN_INFO CDU535_HANDLE " module released\n");
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 42cbaab55..c34978479 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -228,7 +228,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_AGP" != "n" ]; then
bool ' Intel 440LX/BX/GX support' CONFIG_AGP_INTEL
bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810
- bool ' VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA
+ bool ' VIA chipset support' CONFIG_AGP_VIA
bool ' AMD Irongate support' CONFIG_AGP_AMD
bool ' Generic SiS support' CONFIG_AGP_SIS
bool ' ALI M1541 support' CONFIG_AGP_ALI
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 42aef1cc1..4667e1fa3 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -36,8 +36,9 @@ obj-y += tty_io.o n_tty.o tty_ioctl.o mem.o raw.o pty.o misc.o random.o
# All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
-export-objs := busmouse.o console.o i2c-old.o keyboard.o \
- misc.o pty.o random.o selection.o serial.o videodev.o
+export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \
+ misc.o pty.o random.o selection.o serial.o videodev.o \
+ tty_io.o
KEYMAP =defkeymap.o
KEYBD =pc_keyb.o
@@ -45,8 +46,12 @@ CONSOLE =console.o
SERIAL =serial.o
ifeq ($(ARCH),m68k)
- KEYBD =
- SERIAL =
+ ifdef CONFIG_AMIGA
+ KEYBD = amikeyb.o
+ else
+ KEYBD =
+ endif
+ SERIAL =
endif
ifeq ($(ARCH),arm)
@@ -70,6 +75,7 @@ ifneq ($(CONFIG_SUN_SERIAL),)
SERIAL =
endif
+
obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
obj-$(CONFIG_SERIAL) += $(SERIAL)
obj-$(CONFIG_SERIAL_21285) += serial_21285.o
@@ -106,6 +112,7 @@ obj-$(CONFIG_ESPSERIAL) += esp.o
obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_SPECIALIX) += specialix.o
+obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
ifeq ($(CONFIG_SX),y)
obj-y += sx.o generic_serial.o
@@ -147,13 +154,14 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
-obj-$(CONFIG_ADBMOUSE) += adbmouse.o
+obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o
obj-$(CONFIG_PC110_PAD) += pc110pad.o
obj-$(CONFIG_WDT) += wdt.o
obj-$(CONFIG_RTC) += rtc.o
ifeq ($(CONFIG_PPC),)
obj-$(CONFIG_NVRAM) += nvram.o
endif
+obj-$(CONFIG_I810_RNG) += i810_rng.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index ca7f76aa3..31f481065 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -27,8 +27,6 @@
#ifndef _AGP_BACKEND_PRIV_H
#define _AGP_BACKEND_PRIV_H 1
-#include <linux/config.h>
-
enum aper_size_type {
U8_APER_SIZE,
U16_APER_SIZE,
diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c
index 42e1ea7c8..41bb7ac15 100644
--- a/drivers/char/amikeyb.c
+++ b/drivers/char/amikeyb.c
@@ -17,13 +17,14 @@
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/keyboard.h>
+#include <linux/kd.h>
+#include <linux/kbd_ll.h>
#include <linux/delay.h>
#include <linux/timer.h>
-#include <linux/kd.h>
#include <linux/random.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/kbd_ll.h>
+#include <linux/kbd_kern.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
@@ -230,7 +231,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
/* switch CIA serial port to input mode */
ciaa.cra &= ~0x40;
- mark_bh(KEYBOARD_BH);
+ tasklet_schedule(&keyboard_tasklet);
/* rotate scan code to get up/down bit in proper position */
scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80);
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
new file mode 100644
index 000000000..ea828cc24
--- /dev/null
+++ b/drivers/char/amiserial.c
@@ -0,0 +1,2264 @@
+/*
+ * linux/drivers/char/amiserial.c
+ *
+ * Serial driver for the amiga builtin port.
+ *
+ * This code was created by taking serial.c version 4.30 from kernel
+ * release 2.3.22, replacing all hardware related stuff with the
+ * corresponding amiga hardware actions, and removing all irrelevant
+ * code. As a consequence, it uses many of the constants and names
+ * associated with the registers and bits of 16550 compatible UARTS -
+ * but only to keep track of status, etc in the state variables. It
+ * was done this was to make it easier to keep the code in line with
+ * (non hardware specific) changes to serial.c.
+ *
+ * The port is registered with the tty driver as minor device 64, and
+ * therefore other ports should should only use 65 upwards.
+ *
+ * Richard Lucock 28/12/99
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
+ * 1998, 1999 Theodore Ts'o
+ *
+ */
+
+/*
+ * Serial driver configuration section. Here are the various options:
+ *
+ * SERIAL_PARANOIA_CHECK
+ * Check the magic number for the async_structure where
+ * ever possible.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef SERIAL_PARANOIA_CHECK
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+/* Sanity checks */
+
+#define SERIAL_INLINE
+
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
+#endif
+
+/*
+ * End of serial driver configuration section.
+ */
+
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+static char *serial_version = "4.30";
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
+static char *serial_name = "Amiga-builtin serial driver";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#endif
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+static struct async_struct *IRQ_ports;
+
+static unsigned char current_ctl_bits;
+
+static void change_speed(struct async_struct *info, struct termios *old);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+
+static struct serial_state rs_table[1];
+
+#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
+
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static DECLARE_MUTEX(tmp_buf_sem);
+
+#include <asm/uaccess.h>
+
+#define serial_isroot() (capable(CAP_SYS_ADMIN))
+
+
+static inline int serial_paranoia_check(struct async_struct *info,
+ kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+ static const char *badmagic =
+ "Warning: bad magic number for serial struct (%s) in %s\n";
+ static const char *badinfo =
+ "Warning: null async_struct for (%s) in %s\n";
+
+ if (!info) {
+ printk(badinfo, kdevname(device), routine);
+ return 1;
+ }
+ if (info->magic != SERIAL_MAGIC) {
+ printk(badmagic, kdevname(device), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/* some serial hardware definitions */
+#define SDR_OVRUN (1<<15)
+#define SDR_RBF (1<<14)
+#define SDR_TBE (1<<13)
+#define SDR_TSRE (1<<12)
+
+#define SERPER_PARENB (1<<15)
+
+#define AC_SETCLR (1<<15)
+#define AC_UARTBRK (1<<11)
+
+#define SER_DTR (1<<7)
+#define SER_RTS (1<<6)
+#define SER_DCD (1<<5)
+#define SER_CTS (1<<4)
+#define SER_DSR (1<<3)
+
+static __inline__ void rtsdtr_ctrl(int bits)
+{
+ ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR));
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_stop"))
+ return;
+
+ save_flags(flags); cli();
+ if (info->IER & UART_IER_THRI) {
+ info->IER &= ~UART_IER_THRI;
+ /* disable Tx interrupt and remove any pending interrupts */
+ custom.intena = IF_TBE;
+ mb();
+ custom.intreq = IF_TBE;
+ mb();
+ }
+ restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_start"))
+ return;
+
+ save_flags(flags); cli();
+ if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+ info->IER |= UART_IER_THRI;
+ custom.intena = IF_SETCLR | IF_TBE;
+ mb();
+ /* set a pending Tx Interrupt, transmitter should restart now */
+ custom.intreq = IF_SETCLR | IF_TBE;
+ mb();
+ }
+ restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off. People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible. After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct async_struct *info,
+ int event)
+{
+ info->event |= 1 << event;
+ queue_task(&info->tqueue, &tq_serial);
+ mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct async_struct *info)
+{
+ int status;
+ int serdatr;
+ struct tty_struct *tty = info->tty;
+ unsigned char ch;
+ struct async_icount *icount;
+
+ icount = &info->state->icount;
+
+ status = UART_LSR_DR; /* We obviously have a character! */
+ serdatr = custom.serdatr;
+ mb();
+ custom.intreq = IF_RBF;
+ mb();
+
+ if((serdatr & 0x1ff) == 0)
+ status |= UART_LSR_BI;
+ if(serdatr & SDR_OVRUN)
+ status |= UART_LSR_OE;
+
+ ch = serdatr & 0xff;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ *tty->flip.char_buf_ptr = ch;
+ icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+ printk("DR%02x:%02x...", ch, status);
+#endif
+ *tty->flip.flag_buf_ptr = 0;
+
+ /*
+ * We don't handle parity or frame errors - but I have left
+ * the code in, since I'm not sure that the errors can't be
+ * detected.
+ */
+
+ if (status & (UART_LSR_BI | UART_LSR_PE |
+ UART_LSR_FE | UART_LSR_OE)) {
+ /*
+ * For statistics only
+ */
+ if (status & UART_LSR_BI) {
+ status &= ~(UART_LSR_FE | UART_LSR_PE);
+ icount->brk++;
+ } else if (status & UART_LSR_PE)
+ icount->parity++;
+ else if (status & UART_LSR_FE)
+ icount->frame++;
+ if (status & UART_LSR_OE)
+ icount->overrun++;
+
+ /*
+ * Now check to see if character should be
+ * ignored, and mask off conditions which
+ * should be ignored.
+ */
+ if (status & info->ignore_status_mask)
+ goto ignore_char;
+
+ status &= info->read_status_mask;
+
+ if (status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+ printk("handling break....");
+#endif
+ *tty->flip.flag_buf_ptr = TTY_BREAK;
+ if (info->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (status & UART_LSR_PE)
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ else if (status & UART_LSR_FE)
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ if (status & UART_LSR_OE) {
+ /*
+ * Overrun is special, since it's
+ * reported immediately, and doesn't
+ * affect the current character
+ */
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ }
+ }
+ }
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ ignore_char:
+
+ tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void transmit_chars(struct async_struct *info)
+{
+ custom.intreq = IF_TBE;
+ mb();
+ if (info->x_char) {
+ custom.serdat = info->x_char | 0x100;
+ mb();
+ info->state->icount.tx++;
+ info->x_char = 0;
+ return;
+ }
+ if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+ info->tty->hw_stopped) {
+ info->IER &= ~UART_IER_THRI;
+ custom.intena = IF_TBE;
+ mb();
+ return;
+ }
+
+ custom.serdat = info->xmit_buf[info->xmit_tail++] | 0x100;
+ mb();
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->state->icount.tx++;
+ --info->xmit_cnt;
+
+ if (info->xmit_cnt < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+ printk("THRE...");
+#endif
+ if (info->xmit_cnt <= 0) {
+ custom.intena = IF_TBE;
+ mb();
+ info->IER &= ~UART_IER_THRI;
+ }
+}
+
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+ unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
+ unsigned char dstatus;
+ struct async_icount *icount;
+
+ /* Determine bits that have changed */
+ dstatus = status ^ current_ctl_bits;
+ current_ctl_bits = status;
+
+ if (dstatus) {
+ icount = &info->state->icount;
+ /* update input line counters */
+ if (dstatus & SER_DSR)
+ icount->dsr++;
+ if (dstatus & SER_DCD) {
+ icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+ if ((info->flags & ASYNC_HARDPPS_CD) &&
+ !(status & SER_DCD))
+ hardpps();
+#endif
+ }
+ if (dstatus & SER_CTS)
+ icount->cts++;
+ wake_up_interruptible(&info->delta_msr_wait);
+ }
+
+ if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+ printk("ttyS%02d CD now %s...", info->line,
+ (!(status & SER_DCD)) ? "on" : "off");
+#endif
+ if (!(status & SER_DCD))
+ wake_up_interruptible(&info->open_wait);
+ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("doing serial hangup...");
+#endif
+ if (info->tty)
+ tty_hangup(info->tty);
+ }
+ }
+ if (info->flags & ASYNC_CTS_FLOW) {
+ if (info->tty->hw_stopped) {
+ if (!(status & SER_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+ printk("CTS tx start...");
+#endif
+ info->tty->hw_stopped = 0;
+ info->IER |= UART_IER_THRI;
+ custom.intena = IF_SETCLR | IF_TBE;
+ mb();
+ /* set a pending Tx Interrupt, transmitter should restart now */
+ custom.intreq = IF_SETCLR | IF_TBE;
+ mb();
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+ return;
+ }
+ } else {
+ if ((status & SER_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+ printk("CTS tx stop...");
+#endif
+ info->tty->hw_stopped = 1;
+ info->IER &= ~UART_IER_THRI;
+ /* disable Tx interrupt and remove any pending interrupts */
+ custom.intena = IF_TBE;
+ mb();
+ custom.intreq = IF_TBE;
+ mb();
+ }
+ }
+ }
+}
+
+static void ser_vbl_int( int irq, void *data, struct pt_regs *regs)
+{
+ /* vbl is just a periodic interrupt we tie into to update modem status */
+ struct async_struct * info = IRQ_ports;
+ /*
+ * TBD - is it better to unregister from this interrupt or to
+ * ignore it if MSI is clear ?
+ */
+ if(info->IER & UART_IER_MSI)
+ check_modem_status(info);
+}
+
+static void ser_rx_int(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct async_struct * info;
+
+#ifdef SERIAL_DEBUG_INTR
+ printk("ser_rx_int...");
+#endif
+
+ info = IRQ_ports;
+ if (!info || !info->tty)
+ return;
+
+ receive_chars(info);
+ info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+ printk("end.\n");
+#endif
+}
+
+static void ser_tx_int(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct async_struct * info;
+
+ if (custom.serdatr & SDR_TBE) {
+#ifdef SERIAL_DEBUG_INTR
+ printk("ser_tx_int...");
+#endif
+
+ info = IRQ_ports;
+ if (!info || !info->tty)
+ return;
+
+ transmit_chars(info);
+ info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+ printk("end.\n");
+#endif
+ }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+ run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+ struct async_struct *info = (struct async_struct *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver: routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port. Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+static int startup(struct async_struct * info)
+{
+ unsigned long flags;
+ int retval=0;
+ unsigned long page;
+
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ save_flags(flags); cli();
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ goto errout;
+ }
+
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttys%d ...", info->line);
+#endif
+
+ /* Clear anything in the input buffer */
+
+ custom.intreq = IF_RBF;
+ mb();
+
+ retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info);
+ if (retval) {
+ if (serial_isroot()) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR,
+ &info->tty->flags);
+ retval = 0;
+ }
+ goto errout;
+ }
+
+ /* enable both Rx and Tx interrupts */
+ custom.intena = IF_SETCLR | IF_RBF | IF_TBE;
+ mb();
+ info->IER = UART_IER_MSI;
+
+ /* remember current state of the DCD and CTS bits */
+ current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
+
+ IRQ_ports = info;
+
+ info->MCR = 0;
+ if (info->tty->termios->c_cflag & CBAUD)
+ info->MCR = SER_DTR | SER_RTS;
+ rtsdtr_ctrl(info->MCR);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ }
+
+ /*
+ * and set the speed of the serial port
+ */
+ change_speed(info, 0);
+
+ info->flags |= ASYNC_INITIALIZED;
+ restore_flags(flags);
+ return 0;
+
+errout:
+ restore_flags(flags);
+ return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+ unsigned long flags;
+ struct serial_state *state;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("Shutting down serial port %d ....\n", info->line);
+#endif
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be waken up
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ IRQ_ports = NULL;
+
+ /*
+ * Free the IRQ, if necessary
+ */
+ free_irq(IRQ_AMIGA_VERTB, info);
+
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = 0;
+ }
+
+ info->IER = 0;
+ custom.intena = IF_RBF | IF_TBE;
+ mb();
+
+ /* disable break condition */
+ custom.adkcon = AC_UARTBRK;
+ mb();
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ info->MCR &= ~(SER_DTR|SER_RTS);
+ rtsdtr_ctrl(info->MCR);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+}
+
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct async_struct *info,
+ struct termios *old_termios)
+{
+ int quot = 0, baud_base, baud;
+ unsigned cflag, cval = 0;
+ int bits;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ cflag = info->tty->termios->c_cflag;
+
+ /* Byte size is always 8 bits plus parity bit if requested */
+
+ cval = 3; bits = 10;
+ if (cflag & CSTOPB) {
+ cval |= 0x04;
+ bits++;
+ }
+ if (cflag & PARENB) {
+ cval |= UART_LCR_PARITY;
+ bits++;
+ }
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+ if (cflag & CMSPAR)
+ cval |= UART_LCR_SPAR;
+#endif
+
+ /* Determine divisor based on baud rate */
+ baud = tty_get_baud_rate(info->tty);
+ if (!baud)
+ baud = 9600; /* B0 transition handled in rs_set_termios */
+ baud_base = info->state->baud_base;
+ if (baud == 38400 &&
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ quot = info->state->custom_divisor;
+ else {
+ if (baud == 134)
+ /* Special case since 134 is really 134.5 */
+ quot = (2*baud_base / 269);
+ else if (baud)
+ quot = baud_base / baud;
+ }
+ /* If the quotient is zero refuse the change */
+ if (!quot && old_termios) {
+ info->tty->termios->c_cflag &= ~CBAUD;
+ info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ baud = tty_get_baud_rate(info->tty);
+ if (!baud)
+ baud = 9600;
+ if (baud == 38400 &&
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ quot = info->state->custom_divisor;
+ else {
+ if (baud == 134)
+ /* Special case since 134 is really 134.5 */
+ quot = (2*baud_base / 269);
+ else if (baud)
+ quot = baud_base / baud;
+ }
+ }
+ /* As a last resort, if the quotient is zero, default to 9600 bps */
+ if (!quot)
+ quot = baud_base / 9600;
+ info->quot = quot;
+ info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+ info->timeout += HZ/50; /* Add .02 seconds of slop */
+
+ /* CTS flow control flag and modem status interrupts */
+ info->IER &= ~UART_IER_MSI;
+ if (info->flags & ASYNC_HARDPPS_CD)
+ info->IER |= UART_IER_MSI;
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->IER |= UART_IER_MSI;
+ } else
+ info->flags &= ~ASYNC_CTS_FLOW;
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else {
+ info->flags |= ASYNC_CHECK_CD;
+ info->IER |= UART_IER_MSI;
+ }
+ /* TBD:
+ * Does clearing IER_MSI imply that we should disbale the VBL interrupt ?
+ */
+
+ /*
+ * Set up parity check flag
+ */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+ info->read_status_mask = UART_LSR_OE | UART_LSR_DR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= UART_LSR_BI;
+
+ /*
+ * Characters to ignore
+ */
+ info->ignore_status_mask = 0;
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= UART_LSR_OE;
+ }
+ /*
+ * !!! ignore all characters if CREAD is not set
+ */
+ if ((cflag & CREAD) == 0)
+ info->ignore_status_mask |= UART_LSR_DR;
+ save_flags(flags); cli();
+
+ {
+ short serper;
+
+ /* Set up the baud rate */
+ serper = quot - 1;
+
+ /* Enable or disable parity bit */
+
+ if(cval & UART_LCR_PARITY)
+ serper |= (SERPER_PARENB);
+
+ custom.serper = serper;
+ mb();
+ }
+
+ info->LCR = cval; /* Save LCR */
+ restore_flags(flags);
+}
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+ return;
+
+ if (!tty || !info->xmit_buf)
+ return;
+
+ save_flags(flags); cli();
+ if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+ restore_flags(flags);
+ return;
+ }
+
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= SERIAL_XMIT_SIZE-1;
+ info->xmit_cnt++;
+ restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !info->xmit_buf)
+ return;
+
+ save_flags(flags); cli();
+ info->IER |= UART_IER_THRI;
+ custom.intena = IF_SETCLR | IF_TBE;
+ mb();
+ /* set a pending Tx Interrupt, transmitter should restart now */
+ custom.intreq = IF_SETCLR | IF_TBE;
+ mb();
+ restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, ret = 0;
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write"))
+ return 0;
+
+ if (!tty || !info->xmit_buf || !tmp_buf)
+ return 0;
+
+ save_flags(flags);
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = MIN(count,
+ MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ cli();
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ info->xmit_head = ((info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = MIN(count,
+ MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = ((info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ }
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+ !(info->IER & UART_IER_THRI)) {
+ info->IER |= UART_IER_THRI;
+ cli();
+ custom.intena = IF_SETCLR | IF_TBE;
+ mb();
+ /* set a pending Tx Interrupt, transmitter should restart now */
+ custom.intreq = IF_SETCLR | IF_TBE;
+ mb();
+ restore_flags(flags);
+ }
+ return ret;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ int ret;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+ return 0;
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+ return 0;
+ return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+ return;
+ save_flags(flags); cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ restore_flags(flags);
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+ return;
+
+ info->x_char = ch;
+ if (ch) {
+ /* Make sure transmit interrupts are on */
+
+ /* Check this ! */
+ save_flags(flags);
+ cli();
+ if(!(custom.intenar & IF_TBE)) {
+ custom.intena = IF_SETCLR | IF_TBE;
+ mb();
+ /* set a pending Tx Interrupt, transmitter should restart now */
+ custom.intreq = IF_SETCLR | IF_TBE;
+ mb();
+ }
+ restore_flags(flags);
+
+ info->IER |= UART_IER_THRI;
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("throttle %s: %d....\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+ return;
+
+ if (I_IXOFF(tty))
+ rs_send_xchar(tty, STOP_CHAR(tty));
+
+ if (tty->termios->c_cflag & CRTSCTS)
+ info->MCR &= ~SER_RTS;
+
+ save_flags(flags); cli();
+ rtsdtr_ctrl(info->MCR);
+ restore_flags(flags);
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+ return;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ rs_send_xchar(tty, START_CHAR(tty));
+ }
+ if (tty->termios->c_cflag & CRTSCTS)
+ info->MCR |= SER_RTS;
+ save_flags(flags); cli();
+ rtsdtr_ctrl(info->MCR);
+ restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct async_struct * info,
+ struct serial_struct * retinfo)
+{
+ struct serial_struct tmp;
+ struct serial_state *state = info->state;
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = state->type;
+ tmp.line = state->line;
+ tmp.port = state->port;
+ tmp.irq = state->irq;
+ tmp.flags = state->flags;
+ tmp.xmit_fifo_size = state->xmit_fifo_size;
+ tmp.baud_base = state->baud_base;
+ tmp.close_delay = state->close_delay;
+ tmp.closing_wait = state->closing_wait;
+ tmp.custom_divisor = state->custom_divisor;
+ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_serial_info(struct async_struct * info,
+ struct serial_struct * new_info)
+{
+ struct serial_struct new_serial;
+ struct serial_state old_state, *state;
+ unsigned int change_irq,change_port;
+ int retval = 0;
+
+ if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ return -EFAULT;
+ state = info->state;
+ old_state = *state;
+
+ change_irq = new_serial.irq != state->irq;
+ change_port = (new_serial.port != state->port);
+ if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size))
+ return -EINVAL;
+
+ if (!serial_isroot()) {
+ if ((new_serial.baud_base != state->baud_base) ||
+ (new_serial.close_delay != state->close_delay) ||
+ (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ (state->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ state->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ if (new_serial.baud_base < 9600)
+ return -EINVAL;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ state->baud_base = new_serial.baud_base;
+ state->flags = ((state->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+ (info->flags & ASYNC_INTERNAL_FLAGS));
+ state->custom_divisor = new_serial.custom_divisor;
+ state->close_delay = new_serial.close_delay * HZ/100;
+ state->closing_wait = new_serial.closing_wait * HZ/100;
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+check_and_exit:
+ if (info->flags & ASYNC_INITIALIZED) {
+ if (((old_state.flags & ASYNC_SPD_MASK) !=
+ (state->flags & ASYNC_SPD_MASK)) ||
+ (old_state.custom_divisor != state->custom_divisor)) {
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ change_speed(info, 0);
+ }
+ } else
+ retval = startup(info);
+ return retval;
+}
+
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ status = custom.serdatr;
+ mb();
+ restore_flags(flags);
+ result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+ unsigned char control, status;
+ unsigned int result;
+ unsigned long flags;
+
+ control = info->MCR;
+ save_flags(flags); cli();
+ status = ciab.pra;
+ restore_flags(flags);
+ result = ((control & SER_RTS) ? TIOCM_RTS : 0)
+ | ((control & SER_DTR) ? TIOCM_DTR : 0)
+ | (!(status & SER_DCD) ? TIOCM_CAR : 0)
+ | (!(status & SER_DSR) ? TIOCM_DSR : 0)
+ | (!(status & SER_CTS) ? TIOCM_CTS : 0);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_modem_info(struct async_struct * info, unsigned int cmd,
+ unsigned int *value)
+{
+ unsigned int arg;
+ unsigned long flags;
+
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ info->MCR |= SER_RTS;
+ if (arg & TIOCM_DTR)
+ info->MCR |= SER_DTR;
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ info->MCR &= ~SER_RTS;
+ if (arg & TIOCM_DTR)
+ info->MCR &= ~SER_DTR;
+ break;
+ case TIOCMSET:
+ info->MCR = ((info->MCR & ~(SER_RTS | SER_DTR))
+ | ((arg & TIOCM_RTS) ? SER_RTS : 0)
+ | ((arg & TIOCM_DTR) ? SER_DTR : 0));
+ break;
+ default:
+ return -EINVAL;
+ }
+ save_flags(flags); cli();
+ rtsdtr_ctrl(info->MCR);
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_break"))
+ return;
+
+ save_flags(flags); cli();
+ if (break_state == -1)
+ custom.adkcon = AC_SETCLR | AC_UARTBRK;
+ else
+ custom.adkcon = AC_UARTBRK;
+ mb();
+ restore_flags(flags);
+}
+
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct icount;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+ return -ENODEV;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+ (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TIOCMGET:
+ return get_modem_info(info, (unsigned int *) arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(info, cmd, (unsigned int *) arg);
+ case TIOCGSERIAL:
+ return get_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSERCONFIG:
+ return 0;
+
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ if (copy_to_user((struct async_struct *) arg,
+ info, sizeof(struct async_struct)))
+ return -EFAULT;
+ return 0;
+
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ save_flags(flags); cli();
+ /* note the counters on entry */
+ cprev = info->state->icount;
+ restore_flags(flags);
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ save_flags(flags); cli();
+ cnow = info->state->icount; /* atomic copy */
+ restore_flags(flags);
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ save_flags(flags); cli();
+ cnow = info->state->icount;
+ restore_flags(flags);
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+ return -EFAULT;
+ return 0;
+ case TIOCSERGWILD:
+ case TIOCSERSWILD:
+ /* "setserial -W" is called in Debian boot */
+ printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+ unsigned int cflag = tty->termios->c_cflag;
+
+ if ( (cflag == old_termios->c_cflag)
+ && ( RELEVANT_IFLAG(tty->termios->c_iflag)
+ == RELEVANT_IFLAG(old_termios->c_iflag)))
+ return;
+
+ change_speed(info, old_termios);
+
+ /* Handle transition to B0 status */
+ if ((old_termios->c_cflag & CBAUD) &&
+ !(cflag & CBAUD)) {
+ info->MCR &= ~(SER_DTR|SER_RTS);
+ save_flags(flags); cli();
+ rtsdtr_ctrl(info->MCR);
+ restore_flags(flags);
+ }
+
+ /* Handle transition away from B0 status */
+ if (!(old_termios->c_cflag & CBAUD) &&
+ (cflag & CBAUD)) {
+ info->MCR |= SER_DTR;
+ if (!(tty->termios->c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags)) {
+ info->MCR |= SER_RTS;
+ }
+ save_flags(flags); cli();
+ rtsdtr_ctrl(info->MCR);
+ restore_flags(flags);
+ }
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ rs_start(tty);
+ }
+
+#if 0
+ /*
+ * No need to wake up processes in open wait, since they
+ * sample the CLOCAL flag once, and don't recheck it.
+ * XXX It's not clear whether the current behavior is correct
+ * or not. Hence, this may change.....
+ */
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ struct serial_state *state;
+ unsigned long flags;
+
+ if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+ return;
+
+ state = info->state;
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ DBG_CNT("before DEC-hung");
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+ if ((tty->count == 1) && (state->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. state->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("rs_close: bad serial port count; tty->count is 1, "
+ "state->count is %d\n", state->count);
+ state->count = 1;
+ }
+ if (--state->count < 0) {
+ printk("rs_close: bad serial port count for ttys%d: %d\n",
+ info->line, state->count);
+ state->count = 0;
+ }
+ if (state->count) {
+ DBG_CNT("before DEC-2");
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->state->normal_termios = *tty->termios;
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ info->state->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+ info->read_status_mask &= ~UART_LSR_DR;
+ if (info->flags & ASYNC_INITIALIZED) {
+ /* disable receive interrupts */
+ custom.intena = IF_RBF;
+ mb();
+ /* clear any pending receive interrupt */
+ custom.intreq = IF_RBF;
+ mb();
+
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ rs_wait_until_sent(tty, info->timeout);
+ }
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(info->close_delay);
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+ int lsr;
+
+ if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+ return;
+
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout)
+ char_time = MIN(char_time, timeout);
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2*info->timeout)
+ timeout = 2*info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+#endif
+ while(!((lsr = custom.serdatr) & SDR_TSRE)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("serdatr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(char_time);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+ current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_hangup(struct tty_struct *tty)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ struct serial_state *state = info->state;
+
+ if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+ return;
+
+ state = info->state;
+
+ rs_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ state->count = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct async_struct *info)
+{
+#ifdef DECLARE_WAITQUEUE
+ DECLARE_WAITQUEUE(wait, current);
+#else
+ struct wait_queue wait = { current, NULL };
+#endif
+ struct serial_state *state = info->state;
+ int retval;
+ int do_clocal = 0, extra_count = 0;
+ unsigned long flags;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (state->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, state->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttys%d, count = %d\n",
+ state->line, state->count);
+#endif
+ save_flags(flags); cli();
+ if (!tty_hung_up_p(filp)) {
+ extra_count = 1;
+ state->count--;
+ }
+ restore_flags(flags);
+ info->blocked_open++;
+ while (1) {
+ save_flags(flags); cli();
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD))
+ rtsdtr_ctrl(SER_DTR|SER_RTS);
+ restore_flags(flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(info->flags & ASYNC_CLOSING) &&
+ (do_clocal || (!(ciab.pra & SER_DCD)) ))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, state->count);
+#endif
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (extra_count)
+ state->count++;
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ info->line, state->count);
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+ struct async_struct *info;
+ struct serial_state *sstate;
+
+ sstate = rs_table + line;
+ sstate->count++;
+ if (sstate->info) {
+ *ret_info = sstate->info;
+ return 0;
+ }
+ info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+ if (!info) {
+ sstate->count--;
+ return -ENOMEM;
+ }
+ memset(info, 0, sizeof(struct async_struct));
+#ifdef DECLARE_WAITQUEUE
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+#endif
+ info->magic = SERIAL_MAGIC;
+ info->port = sstate->port;
+ info->flags = sstate->flags;
+ info->xmit_fifo_size = sstate->xmit_fifo_size;
+ info->line = line;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->state = sstate;
+ if (sstate->info) {
+ kfree_s(info, sizeof(struct async_struct));
+ *ret_info = sstate->info;
+ return 0;
+ }
+ *ret_info = sstate->info = info;
+ return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+ struct async_struct *info;
+ int retval, line;
+ unsigned long page;
+
+ MOD_INC_USE_COUNT;
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if ((line < 0) || (line >= NR_PORTS)) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+ retval = get_async_struct(line, &info);
+ if (retval) {
+ MOD_DEC_USE_COUNT;
+ return retval;
+ }
+ tty->driver_data = info;
+ info->tty = tty;
+ if (serial_paranoia_check(info, tty->device, "rs_open"))
+ return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ info->state->count);
+#endif
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ if (!tmp_buf) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ return -ENOMEM;
+ }
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
+ }
+
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval) {
+ return retval;
+ }
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ if ((info->state->count == 1) &&
+ (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->state->normal_termios;
+ else
+ *tty->termios = info->state->callout_termios;
+ change_speed(info, 0);
+ }
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open ttys%d successful...", info->line);
+#endif
+ return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+ struct async_struct *info = state->info, scr_info;
+ char stat_buf[30], control, status;
+ int ret;
+ unsigned long flags;
+
+ ret = sprintf(buf, "%d: uart:amiga_builtin",state->line);
+
+ /*
+ * Figure out the current RS-232 lines
+ */
+ if (!info) {
+ info = &scr_info; /* This is just for serial_{in,out} */
+
+ info->magic = SERIAL_MAGIC;
+ info->flags = state->flags;
+ info->quot = 0;
+ info->tty = 0;
+ }
+ save_flags(flags); cli();
+ status = ciab.pra;
+ control = info ? info->MCR : status;
+ restore_flags(flags);
+
+ stat_buf[0] = 0;
+ stat_buf[1] = 0;
+ if(!(control & SER_RTS))
+ strcat(stat_buf, "|RTS");
+ if(!(status & SER_CTS))
+ strcat(stat_buf, "|CTS");
+ if(!(control & SER_DTR))
+ strcat(stat_buf, "|DTR");
+ if(!(status & SER_DSR))
+ strcat(stat_buf, "|DSR");
+ if(!(status & SER_DCD))
+ strcat(stat_buf, "|CD");
+
+ if (info->quot) {
+ ret += sprintf(buf+ret, " baud:%d",
+ state->baud_base / info->quot);
+ }
+
+ ret += sprintf(buf+ret, " tx:%d rx:%d",
+ state->icount.tx, state->icount.rx);
+
+ if (state->icount.frame)
+ ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+
+ if (state->icount.parity)
+ ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+
+ if (state->icount.brk)
+ ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
+
+ if (state->icount.overrun)
+ ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+ /*
+ * Last thing is the RS-232 status lines
+ */
+ ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+ return ret;
+}
+
+int rs_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int len = 0, l;
+ off_t begin = 0;
+
+ len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+ l = line_info(page + len, &rs_table[0]);
+ len += l;
+ if (len+begin > off+count)
+ goto done;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ *eof = 1;
+done:
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+ printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+
+int register_serial(struct serial_struct *req);
+void unregister_serial(int line);
+
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+int __init rs_init(void)
+{
+ unsigned long flags;
+ struct serial_state * state;
+
+ if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL))
+ return -ENODEV;
+
+ init_bh(SERIAL_BH, do_serial_bh);
+
+ IRQ_ports = NULL;
+
+ show_serial_version();
+
+ /* Initialize the tty_driver structure */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.driver_name = "amiserial";
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = 1;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+ serial_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = rs_open;
+ serial_driver.close = rs_close;
+ serial_driver.write = rs_write;
+ serial_driver.put_char = rs_put_char;
+ serial_driver.flush_chars = rs_flush_chars;
+ serial_driver.write_room = rs_write_room;
+ serial_driver.chars_in_buffer = rs_chars_in_buffer;
+ serial_driver.flush_buffer = rs_flush_buffer;
+ serial_driver.ioctl = rs_ioctl;
+ serial_driver.throttle = rs_throttle;
+ serial_driver.unthrottle = rs_unthrottle;
+ serial_driver.set_termios = rs_set_termios;
+ serial_driver.stop = rs_stop;
+ serial_driver.start = rs_start;
+ serial_driver.hangup = rs_hangup;
+ serial_driver.break_ctl = rs_break;
+ serial_driver.send_xchar = rs_send_xchar;
+ serial_driver.wait_until_sent = rs_wait_until_sent;
+ serial_driver.read_proc = rs_read_proc;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ callout_driver.read_proc = 0;
+ callout_driver.proc_entry = 0;
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ state = rs_table;
+ state->magic = SSTATE_MAGIC;
+ state->port = (int)&custom.serdatr; /* Just to give it a value */
+ state->line = 0;
+ state->custom_divisor = 0;
+ state->close_delay = 5*HZ/10;
+ state->closing_wait = 30*HZ;
+ state->callout_termios = callout_driver.init_termios;
+ state->normal_termios = serial_driver.init_termios;
+ state->icount.cts = state->icount.dsr =
+ state->icount.rng = state->icount.dcd = 0;
+ state->icount.rx = state->icount.tx = 0;
+ state->icount.frame = state->icount.parity = 0;
+ state->icount.overrun = state->icount.brk = 0;
+ /*
+ if(state->port && check_region(state->port,REGION_LENGTH(state)))
+ continue;
+ */
+
+ printk(KERN_INFO "ttyS%02d is the amiga builtin serial port\n",
+ state->line);
+
+ /* Hardware set up */
+
+ state->baud_base = amiga_colorclock;
+ state->xmit_fifo_size = 1;
+
+ save_flags (flags);
+ cli();
+
+ /* set ISRs, and then disable the rx interrupts */
+ request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state);
+ request_irq(IRQ_AMIGA_RBF, ser_rx_int, SA_INTERRUPT, "serial RX", state);
+
+ /* turn off Rx and Tx interrupts */
+ custom.intena = IF_RBF | IF_TBE;
+ mb();
+
+ /* clear any pending interrupt */
+ custom.intreq = IF_RBF | IF_TBE;
+ mb();
+
+ restore_flags (flags);
+
+ /*
+ * set the appropriate directions for the modem control flags,
+ * and clear RTS and DTR
+ */
+ ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */
+ ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */
+
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return rs_init();
+}
+
+void cleanup_module(void)
+{
+ unsigned long flags;
+ int e1, e2;
+ struct async_struct *info;
+
+ /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+ save_flags(flags);
+ cli();
+ remove_bh(SERIAL_BH);
+ if ((e1 = tty_unregister_driver(&serial_driver)))
+ printk("SERIAL: failed to unregister serial driver (%d)\n",
+ e1);
+ if ((e2 = tty_unregister_driver(&callout_driver)))
+ printk("SERIAL: failed to unregister callout driver (%d)\n",
+ e2);
+ restore_flags(flags);
+
+ info = rs_table[0].info;
+ if (info) {
+ rs_table[0].info = NULL;
+ kfree_s(info, sizeof(struct async_struct));
+ }
+
+ if (tmp_buf) {
+ free_page((unsigned long) tmp_buf);
+ tmp_buf = NULL;
+ }
+}
+#endif /* MODULE */
+
+/*
+ Local variables:
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
+ End:
+*/
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 85c638ef2..a1c9f3cf3 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -81,6 +81,7 @@
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/console_struct.h>
@@ -120,6 +121,10 @@ struct consw *conswitchp = NULL;
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
+extern int tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned int minor);
+extern void vcs_make_devfs (unsigned int index, int unregister);
+
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
@@ -177,12 +182,13 @@ static struct vc_data *master_display_fg = NULL;
* Unfortunately, we need to delay tty echo when we're currently writing to the
* console since the code is (and always was) not re-entrant, so we insert
* all filp requests to con_task_queue instead of tq_timer and run it from
- * the console_bh.
+ * the console_tasklet. The console_tasklet is protected by the IRQ
+ * protected console_lock.
*/
DECLARE_TASK_QUEUE(con_task_queue);
/*
- * For the same reason, we defer scrollback to the console_bh.
+ * For the same reason, we defer scrollback to the console tasklet.
*/
static int scrollback_delta = 0;
@@ -224,7 +230,7 @@ static inline unsigned short *screenpos(int currcons, int offset, int viewed)
static inline void scrolldelta(int lines)
{
scrollback_delta += lines;
- mark_bh(CONSOLE_BH);
+ tasklet_schedule(&console_tasklet);
}
static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
@@ -546,16 +552,12 @@ void redraw_screen(int new_console, int is_switch)
{
int redraw = 1;
int currcons, old_console;
- static int lock = 0;
- if (lock)
- return;
if (!vc_cons_allocated(new_console)) {
/* strange ... */
- printk("redraw_screen: tty %d not allocated ??\n", new_console+1);
+ /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
return;
}
- lock = 1;
if (is_switch) {
currcons = fg_console;
@@ -591,7 +593,6 @@ void redraw_screen(int new_console, int is_switch)
set_leds();
compute_shiftstate();
}
- lock = 0;
}
/*
@@ -1785,6 +1786,19 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
}
}
+/* This is a temporary buffer used to prepare a tty console write
+ * so that we can easily avoid touching user space while holding the
+ * console spinlock. It is allocated in con_init and is shared by
+ * this code and the vc_screen read/write tty calls.
+ *
+ * We have to allocate this statically in the kernel data section
+ * since console_init (and thus con_init) are called before any
+ * kernel memory allocation is available.
+ */
+char con_buf[PAGE_SIZE];
+#define CON_BUF_SIZE PAGE_SIZE
+DECLARE_MUTEX(con_buf_sem);
+
static int do_con_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
@@ -1802,6 +1816,8 @@ static int do_con_write(struct tty_struct * tty, int from_user,
unsigned long draw_from = 0, draw_to = 0;
struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
u16 himask, charmask;
+ const unsigned char *orig_buf = NULL;
+ int orig_count;
currcons = vt->vc_num;
if (!vc_cons_allocated(currcons)) {
@@ -1814,12 +1830,32 @@ static int do_con_write(struct tty_struct * tty, int from_user,
return 0;
}
+ orig_buf = buf;
+ orig_count = count;
+
if (from_user) {
- /* just to make sure that noone lurks at places he shouldn't see. */
- if (verify_area(VERIFY_READ, buf, count))
- return 0; /* ?? are error codes legal here ?? */
+ down(&con_buf_sem);
+
+again:
+ if (count > CON_BUF_SIZE)
+ count = CON_BUF_SIZE;
+ if (copy_from_user(con_buf, buf, count)) {
+ n = 0; /* ?? are error codes legal here ?? */
+ goto out;
+ }
+
+ buf = con_buf;
}
+ /* At this point 'buf' is guarenteed to be a kernel buffer
+ * and therefore no access to userspace (and therefore sleeping)
+ * will be needed. The con_buf_sem serializes all tty based
+ * console rendering and vcs write/read operations. We hold
+ * the console spinlock during the entire write.
+ */
+
+ spin_lock_irq(&console_lock);
+
himask = hi_font_mask;
charmask = himask ? 0x1ff : 0xff;
@@ -1827,15 +1863,11 @@ static int do_con_write(struct tty_struct * tty, int from_user,
if (IS_FG)
hide_cursor(currcons);
- disable_bh(CONSOLE_BH);
while (!tty->stopped && count) {
- enable_bh(CONSOLE_BH);
- if (from_user)
- __get_user(c, buf);
- else
- c = *buf;
- buf++; n++; count--;
- disable_bh(CONSOLE_BH);
+ c = *buf;
+ buf++;
+ n++;
+ count--;
if (utf) {
/* Combine UTF-8 into Unicode */
@@ -1940,23 +1972,48 @@ static int do_con_write(struct tty_struct * tty, int from_user,
do_con_trol(tty, currcons, c);
}
FLUSH
- enable_bh(CONSOLE_BH);
+ spin_unlock_irq(&console_lock);
+
+out:
+ if (from_user) {
+ /* If the user requested something larger than
+ * the CON_BUF_SIZE, and the tty is not stopped,
+ * keep going.
+ */
+ if ((orig_count > CON_BUF_SIZE) && !tty->stopped) {
+ orig_count -= CON_BUF_SIZE;
+ orig_buf += CON_BUF_SIZE;
+ count = orig_count;
+ buf = orig_buf;
+ goto again;
+ }
+
+ up(&con_buf_sem);
+ }
+
return n;
#undef FLUSH
}
/*
- * This is the console switching bottom half handler.
+ * This is the console switching tasklet.
*
- * Doing console switching in a bottom half handler allows
+ * Doing console switching in a tasklet allows
* us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt), while still giving
- * us the option to easily disable it to avoid races when we
- * need to write to the console.
+ * to switch due to a keyboard interrupt). Synchronization
+ * with other console code and prevention of re-entrancy is
+ * ensured with console_lock.
*/
-static void console_bh(void)
+static void console_softint(unsigned long ignored)
{
+ /* Runs the task queue outside of the console lock. These
+ * callbacks can come back into the console code and thus
+ * will perform their own locking.
+ */
run_task_queue(&con_task_queue);
+
+ spin_lock_irq(&console_lock);
+
if (want_console >= 0) {
if (want_console != fg_console && vc_cons_allocated(want_console)) {
hide_cursor(fg_console);
@@ -1978,6 +2035,8 @@ static void console_bh(void)
sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
scrollback_delta = 0;
}
+
+ spin_unlock_irq(&console_lock);
}
#ifdef CONFIG_VT_CONSOLE
@@ -1985,10 +2044,7 @@ static void console_bh(void)
/*
* Console on virtual terminal
*
- * NOTE NOTE NOTE! This code can do no global locking. In particular,
- * we can't disable interrupts or bottom half handlers globally, because
- * we can be called from contexts that hold critical spinlocks, and
- * trying do get a global lock at this point will lead to deadlocks.
+ * The console_lock must be held when we get here.
*/
void vt_console_print(struct console *co, const char * b, unsigned count)
@@ -2015,7 +2071,7 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
if (!vc_cons_allocated(currcons)) {
/* impossible */
- printk("vt_console_print: tty %d not allocated ??\n", currcons+1);
+ /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
goto quit;
}
@@ -2263,13 +2319,18 @@ static int con_open(struct tty_struct *tty, struct file * filp)
tty->winsize.ws_row = video_num_lines;
tty->winsize.ws_col = video_num_columns;
}
+ if (tty->count == 1)
+ vcs_make_devfs (currcons, 0);
return 0;
}
static void con_close(struct tty_struct *tty, struct file * filp)
{
- if (tty->count == 1)
- tty->driver_data = 0;
+ if (!tty)
+ return;
+ if (tty->count != 1) return;
+ vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1);
+ tty->driver_data = 0;
}
static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
@@ -2305,6 +2366,8 @@ static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols,
struct tty_driver console_driver;
static int console_refcount;
+DECLARE_TASKLET_DISABLED(console_tasklet, console_softint, 0);
+
void __init con_init(void)
{
const char *display_desc = NULL;
@@ -2319,7 +2382,7 @@ void __init con_init(void)
memset(&console_driver, 0, sizeof(struct tty_driver));
console_driver.magic = TTY_DRIVER_MAGIC;
- console_driver.name = "tty";
+ console_driver.name = "vc/%d";
console_driver.name_base = 1;
console_driver.major = TTY_MAJOR;
console_driver.minor_start = 1;
@@ -2327,6 +2390,11 @@ void __init con_init(void)
console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
console_driver.init_termios = tty_std_termios;
console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+ /* Tell tty_register_driver() to skip consoles because they are
+ * registered before kmalloc() is ready. We'll patch them in later.
+ * See comments at console_init(); see also con_init_devfs().
+ */
+ console_driver.flags |= TTY_DRIVER_NO_DEVFS;
console_driver.refcount = &console_refcount;
console_driver.table = console_table;
console_driver.termios = console_termios;
@@ -2393,7 +2461,8 @@ void __init con_init(void)
register_console(&vt_console_driver);
#endif
- init_bh(CONSOLE_BH, console_bh);
+ tasklet_enable(&console_tasklet);
+ tasklet_schedule(&console_tasklet);
}
#ifndef VT_SINGLE_DRIVER
@@ -2486,6 +2555,19 @@ static void set_vesa_blanking(unsigned long arg)
vesa_blank_mode = (mode < 4) ? mode : 0;
}
+/* We can't register the console with devfs during con_init(), because it
+ * is called before kmalloc() works. This function is called later to
+ * do the registration.
+ */
+void __init con_init_devfs (void)
+{
+ int i;
+
+ for (i = 0; i < console_driver.num; i++)
+ tty_register_devfs (&console_driver, 0,
+ console_driver.minor_start + i);
+}
+
static void vesa_powerdown(void)
{
struct vc_data *c = vc_cons[fg_console].d;
@@ -2744,9 +2826,11 @@ int con_font_op(int currcons, struct console_font_op *op)
}
op->data = temp;
}
- disable_bh(CONSOLE_BH);
+
+ spin_lock_irq(&console_lock);
rc = sw->con_font_op(vc_cons[currcons].d, op);
- enable_bh(CONSOLE_BH);
+ spin_unlock_irq(&console_lock);
+
op->data = old_op.data;
if (!rc && !set) {
int c = (op->width+7)/8 * 32 * op->charcount;
@@ -2847,6 +2931,7 @@ EXPORT_SYMBOL(video_font_height);
EXPORT_SYMBOL(video_scan_lines);
EXPORT_SYMBOL(vc_resize);
EXPORT_SYMBOL(fg_console);
+EXPORT_SYMBOL(console_blank_hook);
#ifndef VT_SINGLE_DRIVER
EXPORT_SYMBOL(take_over_console);
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index ff41c0fdd..8ed17fd71 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -34,6 +34,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/segment.h>
#include <asm/atarihw.h>
@@ -510,6 +511,9 @@ static struct file_operations dsp56k_fops = {
/****** Init and module functions ******/
+
+static devfs_handle_t devfs_handle = NULL;
+
int __init dsp56k_init(void)
{
if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
@@ -517,10 +521,14 @@ int __init dsp56k_init(void)
return -ENODEV;
}
- if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
+ if(devfs_register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
printk("DSP56k driver: Unable to register driver\n");
return -ENODEV;
}
+ devfs_handle = devfs_register (NULL, "dsp56k", 0, DEVFS_FL_NONE,
+ DSP56K_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &dsp56k_fops, NULL);
dsp56k.in_use = 0;
@@ -537,6 +545,7 @@ int init_module(void)
void cleanup_module(void)
{
- unregister_chrdev(DSP56K_MAJOR, "dsp56k");
+ devfs_unregister_chrdev(DSP56K_MAJOR, "dsp56k");
+ devfs_unregister (devfs_handle);
}
#endif /* MODULE */
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index ac913935b..58ce08712 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -64,6 +64,7 @@
#include <linux/init.h> /* for __init, module_{init,exit} */
#include <linux/poll.h> /* for POLLIN, etc. */
#include <linux/dtlk.h> /* local header file for DoubleTalk values */
+#include <linux/devfs_fs_kernel.h>
#ifdef TRACING
#define TRACE_TEXT(str) printk(str);
@@ -352,19 +353,25 @@ static int dtlk_release(struct inode *inode, struct file *file)
return 0;
}
+static devfs_handle_t devfs_handle;
+
static int __init dtlk_init(void)
{
dtlk_port_lpc = 0;
dtlk_port_tts = 0;
dtlk_busy = 0;
dtlk_timer_active = 0;
- dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
+ dtlk_major = devfs_register_chrdev(0, "dtlk", &dtlk_fops);
if (dtlk_major == 0) {
printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
return 0;
}
if (dtlk_dev_probe() == 0)
printk(", MAJOR %d\n", dtlk_major);
+ devfs_handle = devfs_register (NULL, "dtlk", 0, DEVFS_FL_NONE,
+ dtlk_major, DTLK_MINOR,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &dtlk_fops, NULL);
init_timer(&dtlk_timer);
dtlk_timer.function = dtlk_timer_tick;
@@ -383,7 +390,8 @@ static void __exit dtlk_cleanup (void)
signals... */
dtlk_write_tts(DTLK_CLEAR);
- unregister_chrdev(dtlk_major, "dtlk");
+ devfs_unregister_chrdev(dtlk_major, "dtlk");
+ devfs_unregister(devfs_handle);
release_region(dtlk_port_lpc, DTLK_IO_EXTENT);
}
diff --git a/drivers/char/dz.c b/drivers/char/dz.c
index 13b19bb6c..35f6b0379 100644
--- a/drivers/char/dz.c
+++ b/drivers/char/dz.c
@@ -1433,6 +1433,7 @@ static void dz_console_put_char (unsigned char ch)
* dz_console_print ()
*
* dz_console_print is registered for printk.
+ * The console_lock must be held when we get here.
* -------------------------------------------------------------------
*/
static void dz_console_print (struct console *cons,
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index ff800e6c4..e3cea9e5d 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -203,20 +203,6 @@ static inline void serial_out(struct esp_struct *info, int offset,
outb(value, info->port+offset);
}
-static inline int __get_order(unsigned long size)
-{
- int order;
-
- size = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
-
- return order;
-}
-
/*
* ------------------------------------------------------------
* rs_stop() and rs_start()
@@ -965,14 +951,14 @@ static int startup(struct esp_struct * info)
if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) {
dma_buffer = (char *)__get_dma_pages(
- GFP_KERNEL, __get_order(DMA_BUFFER_SZ));
+ GFP_KERNEL, get_order(DMA_BUFFER_SZ));
/* use PIO mode if DMA buf/chan cannot be allocated */
if (!dma_buffer)
info->stat_flags |= ESP_STAT_USE_PIO;
else if (request_dma(dma, "esp serial")) {
free_pages((unsigned int)dma_buffer,
- __get_order(DMA_BUFFER_SZ));
+ get_order(DMA_BUFFER_SZ));
dma_buffer = 0;
info->stat_flags |= ESP_STAT_USE_PIO;
}
@@ -1076,7 +1062,7 @@ static void shutdown(struct esp_struct * info)
if (!current_port) {
free_dma(dma);
free_pages((unsigned int)dma_buffer,
- __get_order(DMA_BUFFER_SZ));
+ get_order(DMA_BUFFER_SZ));
dma_buffer = 0;
}
}
@@ -2785,7 +2771,7 @@ void cleanup_module(void)
if (dma_buffer)
free_pages((unsigned int)dma_buffer,
- __get_order(DMA_BUFFER_SZ));
+ get_order(DMA_BUFFER_SZ));
if (tmp_buf)
free_page((unsigned long)tmp_buf);
diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c
index 8de980562..d7d31dbbb 100644
--- a/drivers/char/ftape/lowlevel/ftape-buffer.c
+++ b/drivers/char/ftape/lowlevel/ftape-buffer.c
@@ -39,20 +39,6 @@
/* DMA'able memory allocation stuff.
*/
-/* Pure 2^n version of get_order */
-static inline int __get_order(size_t size)
-{
- unsigned long order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
static inline void *dmaalloc(size_t size)
{
unsigned long addr;
@@ -60,7 +46,7 @@ static inline void *dmaalloc(size_t size)
if (size == 0) {
return NULL;
}
- addr = __get_dma_pages(GFP_KERNEL, __get_order(size));
+ addr = __get_dma_pages(GFP_KERNEL, get_order(size));
if (addr) {
int i;
@@ -80,7 +66,7 @@ static inline void dmafree(void *addr, size_t size)
i < MAP_NR((unsigned long)addr+size); i++) {
mem_map_unreserve (i);
}
- free_pages((unsigned long) addr, __get_order(size));
+ free_pages((unsigned long) addr, get_order(size));
}
}
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index 4795eafdc..883f4a106 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -35,6 +35,7 @@
#endif
#include <linux/fcntl.h>
#include <linux/wrapper.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/zftape.h>
#if LINUX_VERSION_CODE >=KERNEL_VER(2,1,16)
@@ -403,6 +404,7 @@ extern int zft_compressor_init(void);
*/
int __init zft_init(void)
{
+ int i;
TRACE_FUN(ft_t_flow);
#ifdef MODULE
@@ -431,7 +433,43 @@ KERN_INFO
TRACE(ft_t_info, "zft_init @ 0x%p", zft_init);
TRACE(ft_t_info,
"installing zftape VFS interface for ftape driver ...");
- TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
+ TRACE_CATCH(devfs_register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
+
+ for (i = 0; i < 4; i++) {
+ char devname[9];
+
+ sprintf (devname, "qft%i", i);
+ devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ QIC117_TAPE_MAJOR, i,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &zft_cdev, NULL);
+ sprintf (devname, "nqft%i", i);
+ devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ QIC117_TAPE_MAJOR, i + 4,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &zft_cdev, NULL);
+ sprintf (devname, "zqft%i", i);
+ devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ QIC117_TAPE_MAJOR, i + 16,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &zft_cdev, NULL);
+ sprintf (devname, "nzqft%i", i);
+ devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ QIC117_TAPE_MAJOR, i + 20,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &zft_cdev, NULL);
+ sprintf (devname, "rawqft%i", i);
+ devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ QIC117_TAPE_MAJOR, i + 32,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &zft_cdev, NULL);
+ sprintf (devname, "nrawqft%i", i);
+ devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ QIC117_TAPE_MAJOR, i + 36,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &zft_cdev, NULL);
+ }
+
#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
register_symtab(&zft_symbol_table); /* add global zftape symbols */
#endif
@@ -471,13 +509,30 @@ int init_module(void)
*/
void cleanup_module(void)
{
+ int i;
+ char devname[9];
+
TRACE_FUN(ft_t_flow);
- if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) {
+ if (devfs_unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) {
TRACE(ft_t_warn, "failed");
} else {
TRACE(ft_t_info, "successful");
}
+ for (i = 0; i < 4; i++) {
+ sprintf(devname, "qft%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i, DEVFS_SPECIAL_CHR, 0));
+ sprintf(devname, "nqft%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 4, DEVFS_SPECIAL_CHR, 0));
+ sprintf(devname, "zqft%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 16, DEVFS_SPECIAL_CHR, 0));
+ sprintf(devname, "nzqft%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 20, DEVFS_SPECIAL_CHR, 0));
+ sprintf(devname, "rawqft%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 32, DEVFS_SPECIAL_CHR, 0));
+ sprintf(devname, "nrawqft%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 36, DEVFS_SPECIAL_CHR, 0));
+ }
zft_uninit_mem(); /* release remaining memory, if any */
printk(KERN_INFO "zftape successfully unloaded.\n");
TRACE_EXIT;
diff --git a/drivers/char/h8.c b/drivers/char/h8.c
index 99b157833..0583923d9 100644
--- a/drivers/char/h8.c
+++ b/drivers/char/h8.c
@@ -260,7 +260,7 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
return;
} else if (data_reg == H8_SYNC_BYTE) {
h8_state = H8_IDLE;
- if (!QUEUE_EMPTY(&h8_actq, link))
+ if (!QUEUE_IS_EMPTY(&h8_actq, link))
h8_send_next_cmd_byte();
} else {
Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
@@ -279,7 +279,7 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
QUEUE_REMOVE(&h8_actq, qp, link);
h8_cmd_done (qp);
/* More commands to send over? */
- if (!QUEUE_EMPTY(&h8_cmdq, link))
+ if (!QUEUE_IS_EMPTY(&h8_cmdq, link))
h8_start_new_cmd();
}
return;
@@ -458,7 +458,7 @@ h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
/* get cmd buf */
save_flags(flags); cli();
- while (QUEUE_EMPTY(&h8_freeq, link)) {
+ while (QUEUE_IS_EMPTY(&h8_freeq, link)) {
Dprintk("H8: need to allocate more cmd buffers\n");
restore_flags(flags);
h8_alloc_queues();
@@ -500,13 +500,13 @@ h8_start_new_cmd(void)
return;
}
- if (!QUEUE_EMPTY(&h8_actq, link)) {
+ if (!QUEUE_IS_EMPTY(&h8_actq, link)) {
Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
restore_flags(flags);
return;
}
- if (QUEUE_EMPTY(&h8_cmdq, link)) {
+ if (QUEUE_IS_EMPTY(&h8_cmdq, link)) {
Dprintk("h8_start_new_cmd: no command to dequeue\n");
restore_flags(flags);
return;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index a9634ad91..77dc4625b 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -2051,7 +2051,8 @@ void cleanup_module(void)
re_schedule = 0;
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ);
- disable_bh(ISICOM_BH);
+
+ remove_bh(ISICOM_BH);
#ifdef ISICOM_DEBUG
printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count);
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 494fbc260..0b1ab10e1 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -39,6 +39,7 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -829,12 +830,14 @@ int init_module()
/*****************************************************************************/
+static devfs_handle_t devfs_handle = NULL;
+
void cleanup_module()
{
stlibrd_t *brdp;
stliport_t *portp;
unsigned long flags;
- int i, j;
+ int i, j, k;
#if DEBUG
printk("cleanup_module()\n");
@@ -863,10 +866,10 @@ void cleanup_module()
restore_flags(flags);
return;
}
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
+ devfs_unregister (devfs_handle);
+ if ((i = devfs_unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
printk("STALLION: failed to un-register serial memory device, "
"errno=%d\n", -i);
-
if (stli_tmpwritebuf != (char *) NULL)
kfree_s(stli_tmpwritebuf, STLI_TXBUFSIZE);
if (stli_txcookbuf != (char *) NULL)
@@ -5321,9 +5324,15 @@ int __init stli_init(void)
* Set up a character driver for the shared memory region. We need this
* to down load the slave code image. Also it is a useful debugging tool.
*/
- if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
+ if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
printk("STALLION: failed to register serial memory device\n");
+ devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
+ devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
+ STL_SIOMEMMAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &stli_fsiomem, NULL);
+
/*
* Set up the tty driver structure and register us as a driver.
* Also setup the callout tty device.
diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c
index 48af4c713..cfd0f2e82 100644
--- a/drivers/char/joystick/joystick.c
+++ b/drivers/char/joystick/joystick.c
@@ -38,6 +38,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/joystick.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/malloc.h>
@@ -694,6 +695,10 @@ struct js_port *js_unregister_port(struct js_port *port)
return prev;
}
+extern struct file_operations js_fops;
+
+static devfs_handle_t devfs_handle = NULL;
+
int js_register_device(struct js_port *port, int number, int axes, int buttons, char *name,
js_ops_func open, js_ops_func close)
{
@@ -702,6 +707,7 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
void *all;
int i = 0;
unsigned long flags;
+ char devfs_name[8];
if (!(all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
2 * (((buttons - 1) >> 5) + 1) * sizeof(int) +
@@ -745,6 +751,13 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
spin_unlock_irqrestore(&js_lock, flags);
+ sprintf(devfs_name, "js%d", i);
+ curd->devfs_handle = devfs_register(devfs_handle, devfs_name, 0,
+ DEVFS_FL_DEFAULT,
+ JOYSTICK_MAJOR, i,
+ S_IFCHR | S_IRUGO | S_IWUSR, 0, 0,
+ &js_fops, NULL);
+
return i;
}
@@ -760,6 +773,7 @@ void js_unregister_device(struct js_dev *dev)
spin_unlock_irqrestore(&js_lock, flags);
+ devfs_unregister(dev->devfs_handle);
kfree(dev);
}
@@ -788,10 +802,11 @@ int __init js_init(void)
#endif
{
- if (register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
+ if (devfs_register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
return -EBUSY;
}
+ devfs_handle = devfs_mk_dir(NULL, "joysticks", 9, NULL);
printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik <vojtech@suse.cz>\n",
JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
@@ -871,7 +886,8 @@ int __init js_init(void)
void cleanup_module(void)
{
del_timer(&js_timer);
- if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
+ devfs_unregister(devfs_handle);
+ if (devfs_unregister_chrdev(JOYSTICK_MAJOR, "js"))
printk(KERN_ERR "js: can't unregister device\n");
}
#endif
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index c02a6db08..7e5a654c2 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -208,7 +208,7 @@ void handle_scancode(unsigned char scancode, int down)
pm_access(pm_kbd);
do_poke_blanked_console = 1;
- mark_bh(CONSOLE_BH);
+ tasklet_schedule(&console_tasklet);
add_keyboard_randomness(scancode | up_flag);
tty = ttytab? ttytab[fg_console]: NULL;
@@ -925,6 +925,7 @@ static void kbd_bh(unsigned long dummy)
}
}
+EXPORT_SYMBOL(keyboard_tasklet);
DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
int __init kbd_init(void)
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 4f6004f1c..bb00a32fa 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -16,6 +16,7 @@
* Parport sharing hacking by Andrea Arcangeli
* Fixed kernel_(to/from)_user memory copy to check for errors
* by Riccardo Facchetti <fizban@tin.it>
+ * 22-JAN-1998 Added support for devfs Richard Gooch <rgooch@atnf.csiro.au>
* Redesigned interrupt handling for handle printers with buggy handshake
* by Andrea Arcangeli, 11 May 1998
* Full efficient handling of printer with buggy irq handshake (now I have
@@ -118,6 +119,7 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/malloc.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
@@ -138,6 +140,8 @@
/* ROUND_UP macro from fs/select.c */
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
+static devfs_handle_t devfs_handle = NULL;
+
struct lp_struct lp_table[LP_NO];
static unsigned int lp_count = 0;
@@ -151,72 +155,6 @@ static unsigned int lp_count = 0;
#undef LP_DEBUG
-/* If you want to see if you can get lp_poll working, define this. */
-#undef SUPPORT_POLL
-
-/* --- parport support ----------------------------------------- */
-
-static int lp_preempt(void *handle)
-{
- struct lp_struct *lps = (struct lp_struct *)handle;
-
- if (!(lps->flags & LP_PORT_BUSY)) {
- /* Let the port go. */
- clear_bit (LP_HAVE_PORT_BIT, &lps->flags);
- return 0;
- }
-
- if (!(lps->flags & LP_PORT_BUSY)) {
- /* Let the port go. */
- clear_bit (LP_HAVE_PORT_BIT, &lps->flags);
- return 0;
- }
-
- /* Don't actually release the port now */
- return 1;
-}
-
-static void lp_check_data (struct lp_struct *lp)
-{
-#if !defined(CONFIG_PARPORT_1284) || !defined (SUPPORT_POLL)
- return;
-#else
- struct pardevice *dev = lp->dev;
- if (!(lp->flags & LP_NO_REVERSE)) {
- int err = parport_negotiate (dev->port, IEEE1284_MODE_NIBBLE);
- if (err)
- lp->flags |= LP_NO_REVERSE;
- else {
- unsigned char s = parport_read_status (dev->port);
- if (s & PARPORT_STATUS_ERROR)
- lp->flags &= ~LP_DATA_AVAIL;
- else {
- lp->flags |= LP_DATA_AVAIL;
- if (waitqueue_active (&lp->dataq))
- wake_up_interruptible (&lp->dataq);
- }
- }
- }
-#endif /* IEEE 1284 support */
-}
-
-static void lp_parport_release (int minor)
-{
- lp_check_data (&lp_table[minor]);
- if (test_and_clear_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags))
- parport_release (lp_table[minor].dev);
-
- lp_table[minor].flags &= ~LP_PORT_BUSY;
-}
-
-static void lp_parport_claim (int minor)
-{
- if (!test_and_set_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags))
- parport_claim_or_block (lp_table[minor].dev);
-
- lp_table[minor].flags |= LP_PORT_BUSY;
-}
-
/* --- low-level port access ----------------------------------- */
#define r_dtr(x) (parport_read_data(lp_table[(x)].dev->port))
@@ -227,42 +165,15 @@ static void lp_parport_claim (int minor)
static int lp_reset(int minor)
{
int retval;
- lp_parport_claim (minor);
+ parport_claim_or_block (lp_table[minor].dev);
w_ctr(minor, LP_PSELECP);
udelay (LP_DELAY);
w_ctr(minor, LP_PSELECP | LP_PINITP);
retval = r_str(minor);
- lp_parport_release (minor);
+ parport_release (lp_table[minor].dev);
return retval;
}
-static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
- if (!(lp_dev->flags & LP_PORT_BUSY))
- /* We must have the port since we got an interrupt. */
- lp_check_data (lp_dev);
- if (waitqueue_active (&lp_dev->waitq))
- wake_up_interruptible (&lp_dev->waitq);
-}
-
-static void lp_wakeup (void *handle)
-{
- struct lp_struct *lp_dev = handle;
-
- if (lp_dev->flags & LP_PORT_BUSY)
- return;
-
- /* Grab the port if it can help (i.e. reverse mode is possible). */
- if (!(lp_dev->flags & LP_NO_REVERSE)) {
- parport_claim (lp_dev->dev);
- set_bit (LP_HAVE_PORT_BIT, &lp_dev->flags);
- lp_check_data (lp_dev);
- if (waitqueue_active (&lp_dev->waitq))
- wake_up_interruptible (&lp_dev->waitq);
- }
-}
-
static void lp_error (int minor)
{
int polling;
@@ -271,10 +182,10 @@ static void lp_error (int minor)
return;
polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE;
- if (polling) lp_parport_release (minor);
+ if (polling) parport_release (lp_table[minor].dev);
interruptible_sleep_on_timeout (&lp_table[minor].waitq,
LP_TIMEOUT_POLLED);
- if (polling) lp_parport_claim (minor);
+ if (polling) parport_claim_or_block (lp_table[minor].dev);
else parport_yield_blocking (lp_table[minor].dev);
}
@@ -326,7 +237,6 @@ static ssize_t lp_write(struct file * file, const char * buf,
ssize_t retv = 0;
ssize_t written;
size_t copy_size = count;
- long old_to;
#ifdef LP_STATS
if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
@@ -347,13 +257,13 @@ static ssize_t lp_write(struct file * file, const char * buf,
/* Claim Parport or sleep until it becomes available
*/
- lp_parport_claim (minor);
+ parport_claim_or_block (lp_table[minor].dev);
/* Go to compatibility mode. */
parport_negotiate (port, IEEE1284_MODE_COMPAT);
- old_to = parport_set_timeout (lp_table[minor].dev,
- lp_table[minor].timeout);
+ parport_set_timeout (lp_table[minor].dev,
+ lp_table[minor].timeout);
do {
/* Write the data. */
@@ -399,21 +309,13 @@ static ssize_t lp_write(struct file * file, const char * buf,
}
} while (count > 0);
- /* Not really necessary, but polite. */
- parport_set_timeout (lp_table[minor].dev, old_to);
-
- lp_parport_release (minor);
+ parport_release (lp_table[minor].dev);
up (&lp_table[minor].port_mutex);
return retv;
}
-static long long lp_lseek(struct file * file, long long offset, int origin)
-{
- return -ESPIPE;
-}
-
#ifdef CONFIG_PARPORT_1284
/* Status readback conforming to ieee1284 */
@@ -431,7 +333,7 @@ static ssize_t lp_read(struct file * file, char * buf,
if (down_interruptible (&lp_table[minor].port_mutex))
return -EINTR;
- lp_parport_claim (minor);
+ parport_claim_or_block (lp_table[minor].dev);
for (;;) {
retval = parport_read (port, kbuf, count);
@@ -452,7 +354,7 @@ static ssize_t lp_read(struct file * file, char * buf,
}
}
- lp_parport_release (minor);
+ parport_release (lp_table[minor].dev);
if (retval > 0 && copy_to_user (buf, kbuf, retval))
retval = -EFAULT;
@@ -484,9 +386,9 @@ static int lp_open(struct inode * inode, struct file * file)
should most likely only ever be used by the tunelp application. */
if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
int status;
- lp_parport_claim (minor);
+ parport_claim_or_block (lp_table[minor].dev);
status = r_str(minor);
- lp_parport_release (minor);
+ parport_release (lp_table[minor].dev);
if (status & LP_POUTPA) {
printk(KERN_INFO "lp%d out of paper\n", minor);
MOD_DEC_USE_COUNT;
@@ -578,9 +480,9 @@ static int lp_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
break;
case LPGETSTATUS:
- lp_parport_claim(minor);
+ parport_claim_or_block (lp_table[minor].dev);
status = r_str(minor);
- lp_parport_release(minor);
+ parport_release (lp_table[minor].dev);
if (copy_to_user((int *) arg, &status, sizeof(int)))
return -EFAULT;
@@ -629,21 +531,6 @@ static int lp_ioctl(struct inode *inode, struct file *file,
return retval;
}
-#ifdef CONFIG_PARPORT_1284
-static unsigned int lp_poll (struct file *filp, struct poll_table_struct *wait)
-{
- unsigned int minor = MINOR (filp->f_dentry->d_inode->i_rdev);
- unsigned int mask = POLLOUT | POLLWRNORM; /* always writable */
-
- poll_wait (filp, &lp_table[minor].dataq, wait);
-
- if (lp_table[minor].flags & LP_DATA_AVAIL)
- mask |= POLLIN | POLLRDNORM;
-
- return mask;
-}
-#endif /* IEEE 1284 support */
-
static struct file_operations lp_fops = {
write: lp_write,
ioctl: lp_ioctl,
@@ -651,7 +538,6 @@ static struct file_operations lp_fops = {
release: lp_release,
#ifdef CONFIG_PARPORT_1284
read: lp_read,
- poll: lp_poll,
#endif
};
@@ -666,22 +552,20 @@ static struct file_operations lp_fops = {
* non-zero to get the latter behaviour. */
#define CONSOLE_LP_STRICT 1
+/* The console_lock must be held when we get here. */
+
static void lp_console_write (struct console *co, const char *s,
unsigned count)
{
struct pardevice *dev = lp_table[CONSOLE_LP].dev;
struct parport *port = dev->port;
ssize_t written;
- signed long old_to;
- if (!(lp_table[CONSOLE_LP].flags & (1<<LP_HAVE_PORT_BIT))) {
- if (parport_claim (dev))
- /* Nothing we can do. */
- return;
- set_bit (LP_HAVE_PORT_BIT, &lp_table[CONSOLE_LP].flags);
- }
+ if (parport_claim (dev))
+ /* Nothing we can do. */
+ return;
- old_to = parport_set_timeout (dev, 0);
+ parport_set_timeout (dev, 0);
/* Go to compatibility mode. */
parport_negotiate (port, IEEE1284_MODE_COMPAT);
@@ -719,7 +603,7 @@ static void lp_console_write (struct console *co, const char *s,
}
} while (count > 0 && (CONSOLE_LP_STRICT || written > 0));
- parport_set_timeout (dev, old_to);
+ parport_release (dev);
}
static kdev_t lp_console_device (struct console *c)
@@ -790,10 +674,10 @@ void __init lp_setup(char *str, int *ints)
static int lp_register(int nr, struct parport *port)
{
+ char name[8];
+
lp_table[nr].dev = parport_register_device(port, "lp",
- lp_preempt, lp_wakeup,
- lp_interrupt,
- 0,
+ NULL, NULL, NULL, 0,
(void *) &lp_table[nr]);
if (lp_table[nr].dev == NULL)
return 1;
@@ -802,6 +686,12 @@ static int lp_register(int nr, struct parport *port)
if (reset)
lp_reset(nr);
+ sprintf (name, "%d", nr);
+ devfs_register (devfs_handle, name, 0,
+ DEVFS_FL_DEFAULT, LP_MAJOR, nr,
+ S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ &lp_fops, NULL);
+
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
(port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -888,7 +778,7 @@ int __init lp_init (void)
lp_table[i].timeout = 10 * HZ;
}
- if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) {
+ if (devfs_register_chrdev (LP_MAJOR, "lp", &lp_fops)) {
printk ("lp: unable to get major %d\n", LP_MAJOR);
return -EIO;
}
@@ -898,11 +788,13 @@ int __init lp_init (void)
return -EIO;
}
+ devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL);
+
if (!lp_count) {
printk (KERN_INFO "lp: driver loaded but no devices found\n");
-#ifndef CONFIG_PARPORT_12843
+#ifndef CONFIG_PARPORT_1284
if (parport_nr[0] == LP_PARPORT_AUTO)
- printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n");
+ printk (KERN_INFO "lp: (is IEEE 1284 support enabled?)\n");
#endif
}
@@ -948,12 +840,11 @@ void cleanup_module(void)
unregister_console (&lpcons);
#endif
- unregister_chrdev(LP_MAJOR, "lp");
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev(LP_MAJOR, "lp");
for (offset = 0; offset < LP_NO; offset++) {
if (lp_table[offset].dev == NULL)
continue;
- if (lp_table[offset].flags & (1<<LP_HAVE_PORT_BIT))
- parport_release (lp_table[offset].dev);
parport_unregister_device(lp_table[offset].dev);
}
}
diff --git a/drivers/char/mac_SCC.c b/drivers/char/mac_SCC.c
deleted file mode 100644
index c20e7a9f0..000000000
--- a/drivers/char/mac_SCC.c
+++ /dev/null
@@ -1,1529 +0,0 @@
-/*
- * mac_SCC.c: m68k version of
- *
- * macserial.c: Serial port driver for Power Macintoshes.
- * Extended for the 68K mac by Alan Cox.
- * Rewritten to m68k serial design by Michael Schmitz
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/*
- * Design note for the m68k rewrite:
- * The structure of the m68k serial code requires separation of the low-level
- * functions that talk directly to the hardware from the Linux serial driver
- * code interfacing to the tty layer. The reason for this separation is simply
- * the fact that the m68k serial hardware is, unlike the i386, based on a
- * variety of chips, and the rs_* serial routines need to be shared.
- *
- * I've tried to make consistent use of the async_struct info populated in the
- * midlevel code, and introduced an async_private struct to hold the Macintosh
- * SCC internals (this was added to the async_struct for the PowerMac driver).
- * Exception: the console and kgdb hooks still use the zs_soft[] data, and this
- * is still filled in by the probe_sccs() routine, which provides some data
- * for mac_SCC_init as well. Interrupts are registered in mac_SCC_init, so
- * the console/kgdb stuff probably won't work before proper serial init, and
- * I have to rely on keeping info and zs_soft consistent at least for the
- * console/kgdb port.
- *
- * Update (16-11-97): The SCC interrupt handling was suffering from the problem
- * that the autovector SCC interrupt was registered only once, hence only one
- * async_struct was passed to the interrupt function and only interrupts from
- * the corresponding channel could be handled (yes, major design flaw).
- * The autovector interrupt is now registered by the main interrupt initfunc,
- * and uses a handler that will call the registered SCC specific interrupts in
- * turn. The SCC init has to register these as machspec interrupts now, as is
- * done for the VIA interrupts elsewhere.
- */
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/config.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-
-#include <asm/uaccess.h>
-#include <asm/setup.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/macints.h>
-#ifndef CONFIG_MAC
-#include <asm/prom.h>
-#endif
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/bitops.h>
-#include <asm/hwtest.h>
-
-#include "mac_SCC.h"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL 2 /* Max number of ZS chips supported */
-#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
-
-#ifdef CONFIG_MAC
-/*
- * All the Macintosh 68K boxes that have an MMU also have hardware
- * recovery delays.
- */
-#define RECOVERY_DELAY
-#else
-/* On PowerMacs, the hardware takes care of the SCC recovery time,
- but we need the eieio to make sure that the accesses occur
- in the order we want. */
-#define RECOVERY_DELAY eieio()
-#endif
-
-struct mac_zschannel *zs_kgdbchan;
-struct mac_zschannel zs_channels[NUM_CHANNELS];
-
-struct m68k_async_struct zs_soft[NUM_CHANNELS];
-struct m68k_async_private zs_soft_private[NUM_CHANNELS];
-int zs_channels_found;
-struct m68k_async_struct *zs_chain; /* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-/** struct tty_struct *zs_constty; **/
-
-/* Console hooks... */
-static int zs_cons_chanout = 0;
-static int zs_cons_chanin = 0;
-struct m68k_async_struct *zs_consinfo = 0;
-struct mac_zschannel *zs_conschan;
-
-static unsigned char kgdb_regs[16] = {
- 0, 0, 0, /* write 0, 1, 2 */
- (Rx8 | RxENABLE), /* write 3 */
- (X16CLK | SB1 | PAR_EVEN), /* write 4 */
- (Tx8 | TxENAB), /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- (NV), /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 1, 0, /* 38400 baud divisor, write 12 + 13 */
- (BRENABL), /* write 14 */
- (DCDIE) /* write 15 */
-};
-
-#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
-
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-#define _INLINE_ inline
-
-static void probe_sccs(void);
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-
-/***************************** Prototypes *****************************/
-
-static void SCC_init_port( struct m68k_async_struct *info, int type, int channel );
-#if 0
-#ifdef MODULE
-static void SCC_deinit_port( struct m68k_async_struct *info, int channel );
-#endif
-#endif
-
-/* FIXME !!! Currently, only autovector interrupt used! */
-#if 0
-static void SCC_rx_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_tx_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_stat_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_ri_int (int irq, void *data, struct pt_regs *fp);
-#endif
-
-static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct
- *tty, struct file *file );
-static void SCC_init( struct m68k_async_struct *info );
-static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr );
-static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag );
-static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base,
- int divisor );
-static void SCC_change_speed( struct m68k_async_struct *info );
-#if 0
-static int SCC_clocksrc( unsigned baud_base, unsigned channel );
-#endif
-static void SCC_throttle( struct m68k_async_struct *info, int status );
-static void SCC_set_break( struct m68k_async_struct *info, int break_flag );
-static void SCC_get_serial_info( struct m68k_async_struct *info, struct
- serial_struct *retinfo );
-static unsigned int SCC_get_modem_info( struct m68k_async_struct *info );
-static int SCC_set_modem_info( struct m68k_async_struct *info, int new_dtr, int
- new_rts );
-static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct
- m68k_async_struct *info, unsigned int cmd, unsigned long arg );
-static void SCC_stop_receive (struct m68k_async_struct *info);
-static int SCC_trans_empty (struct m68k_async_struct *info);
-
-/************************* End of Prototypes **************************/
-
-
-static SERIALSWITCH SCC_switch = {
- SCC_init, SCC_deinit, SCC_enab_tx_int,
- SCC_check_custom_divisor, SCC_change_speed,
- SCC_throttle, SCC_set_break,
- SCC_get_serial_info, SCC_get_modem_info,
- SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty,
- SCC_check_open
-};
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
-
-/*
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char read_zsreg(struct mac_zschannel *channel,
- unsigned char reg)
-{
- unsigned char retval;
-
- if (reg != 0) {
- *channel->control = reg;
- RECOVERY_DELAY;
- }
- retval = *channel->control;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsreg(struct mac_zschannel *channel,
- unsigned char reg, unsigned char value)
-{
- if (reg != 0) {
- *channel->control = reg;
- RECOVERY_DELAY;
- }
- *channel->control = value;
- RECOVERY_DELAY;
- return;
-}
-
-static inline unsigned char read_zsdata(struct mac_zschannel *channel)
-{
- unsigned char retval;
-
- retval = *channel->data;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsdata(struct mac_zschannel *channel,
- unsigned char value)
-{
- *channel->data = value;
- RECOVERY_DELAY;
- return;
-}
-
-static inline void load_zsregs(struct mac_zschannel *channel,
- unsigned char *regs)
-{
- ZS_CLEARERR(channel);
- ZS_CLEARFIFO(channel);
- /* Load 'em up */
- write_zsreg(channel, R4, regs[R4]);
- write_zsreg(channel, R10, regs[R10]);
- write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
- write_zsreg(channel, R5, regs[R5] & ~TxENAB);
- write_zsreg(channel, R1, regs[R1]);
- write_zsreg(channel, R9, regs[R9]);
- write_zsreg(channel, R11, regs[R11]);
- write_zsreg(channel, R12, regs[R12]);
- write_zsreg(channel, R13, regs[R13]);
- write_zsreg(channel, R14, regs[R14]);
- write_zsreg(channel, R15, regs[R15]);
- write_zsreg(channel, R3, regs[R3]);
- write_zsreg(channel, R5, regs[R5]);
- return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct m68k_async_struct *ss, int set)
-{
- if (set)
- ss->private->curregs[5] |= (RTS | DTR);
- else
- ss->private->curregs[5] &= ~(RTS | DTR);
- write_zsreg(ss->private->zs_channel, 5, ss->private->curregs[5]);
- return;
-}
-
-static inline void kgdb_chaninit(struct m68k_async_struct *ss, int intson, int bps)
-{
- int brg;
-
- if (intson) {
- kgdb_regs[R1] = INT_ALL_Rx;
- kgdb_regs[R9] |= MIE;
- } else {
- kgdb_regs[R1] = 0;
- kgdb_regs[R9] &= ~MIE;
- }
- brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
- kgdb_regs[R12] = brg;
- kgdb_regs[R13] = brg >> 8;
- load_zsregs(ss->private->zs_channel, kgdb_regs);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct m68k_async_struct *ss)
-{
- struct mac_zschannel *channel = ss->private->zs_channel;
- int brg;
-
- /* The baud rate is split up between two 8-bit registers in
- * what is termed 'BRG time constant' format in my docs for
- * the chip, it is a function of the clk rate the chip is
- * receiving which happens to be constant.
- */
- brg = (read_zsreg(channel, 13) << 8);
- brg |= read_zsreg(channel, 12);
- return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->private->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void SCC_recv_clear(struct mac_zschannel *zsc)
-{
- write_zsreg(zsc, 0, ERR_RES);
- write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-extern void breakpoint(void); /* For the KGDB frame character */
-
-static /*_INLINE_*/ void receive_chars(struct m68k_async_struct *info,
- struct pt_regs *regs)
-{
- struct tty_struct *tty = info->tty;
- unsigned char ch, stat, flag;
-
- while ((read_zsreg(info->private->zs_channel, 0) & Rx_CH_AV) != 0) {
-
- stat = read_zsreg(info->private->zs_channel, R1);
- ch = read_zsdata(info->private->zs_channel);
-
-#ifdef SCC_DEBUG
- printk("mac_SCC: receive_chars stat=%X char=%X \n", stat, ch);
-#endif
-
-#if 0 /* KGDB not yet supported */
- /* Look for kgdb 'stop' character, consult the gdb documentation
- * for remote target debugging and arch/sparc/kernel/sparc-stub.c
- * to see how all this works.
- */
- if ((info->kgdb_channel) && (ch =='\003')) {
- breakpoint();
- continue;
- }
-#endif
-
- if (!tty)
- continue;
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- tty_flip_buffer_push(tty);
-
- if (stat & Rx_OVR) {
- flag = TTY_OVERRUN;
- /* reset the error indication */
- write_zsreg(info->private->zs_channel, 0, ERR_RES);
- } else if (stat & FRM_ERR) {
- /* this error is not sticky */
- flag = TTY_FRAME;
- } else if (stat & PAR_ERR) {
- flag = TTY_PARITY;
- /* reset the error indication */
- write_zsreg(info->private->zs_channel, 0, ERR_RES);
- } else
- flag = 0;
-
- if (tty->flip.buf_num
- && tty->flip.count >= TTY_FLIPBUF_SIZE) {
-#ifdef SCC_DEBUG_OVERRUN
- printk("mac_SCC: flip buffer overrun!\n");
-#endif
- return;
- }
-
- if (!tty->flip.buf_num
- && tty->flip.count >= 2*TTY_FLIPBUF_SIZE) {
- printk("mac_SCC: double flip buffer overrun!\n");
- return;
- }
-
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = flag;
- *tty->flip.char_buf_ptr++ = ch;
- info->icount.rx++;
- tty_flip_buffer_push(tty);
- }
-#if 0
-clear_and_exit:
- SCC_recv_clear(info->private->zs_channel);
-#endif
-}
-
-/* that's SCC_enable_tx_int, basically */
-
-static void transmit_chars(struct m68k_async_struct *info)
-{
- if ((read_zsreg(info->private->zs_channel, 0) & Tx_BUF_EMP) == 0)
- return;
- info->private->tx_active = 0;
-
- if (info->x_char) {
- /* Send next char */
- write_zsdata(info->private->zs_channel, info->x_char);
- info->x_char = 0;
- info->private->tx_active = 1;
- return;
- }
-
- if ((info->xmit_cnt <= 0) || info->tty->stopped
- || info->private->tx_stopped) {
- write_zsreg(info->private->zs_channel, 0, RES_Tx_P);
- return;
- }
-
- /* Send char */
- write_zsdata(info->private->zs_channel, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->icount.tx++;
- info->xmit_cnt--;
- info->private->tx_active = 1;
-
- if (info->xmit_cnt < WAKEUP_CHARS)
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static /*_INLINE_*/ void status_handle(struct m68k_async_struct *info)
-{
- unsigned char status;
-
- /* Get status from Read Register 0 */
- status = read_zsreg(info->private->zs_channel, 0);
-
- /* Check for DCD transitions */
- if (((status ^ info->private->read_reg_zero) & DCD) != 0
- && info->tty && C_CLOCAL(info->tty)) {
- if (status & DCD) {
- wake_up_interruptible(&info->open_wait);
- } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
- if (info->tty)
- tty_hangup(info->tty);
- }
- }
-
- /* Check for CTS transitions */
- if (info->tty && C_CRTSCTS(info->tty)) {
- /*
- * For some reason, on the Power Macintosh,
- * it seems that the CTS bit is 1 when CTS is
- * *negated* and 0 when it is asserted.
- * The DCD bit doesn't seem to be inverted
- * like this.
- */
- if ((status & CTS) == 0) {
- if (info->private->tx_stopped) {
- info->private->tx_stopped = 0;
- if (!info->private->tx_active)
- transmit_chars(info);
- }
- } else {
- info->private->tx_stopped = 1;
- }
- }
-
- /* Clear status condition... */
- write_zsreg(info->private->zs_channel, 0, RES_EXT_INT);
- info->private->read_reg_zero = status;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-void mac_SCC_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
- struct m68k_async_struct *info = (struct m68k_async_struct *) dev_id;
- unsigned char zs_intreg;
- int shift;
-
- /* NOTE: The read register 3, which holds the irq status,
- * does so for both channels on each chip. Although
- * the status value itself must be read from the A
- * channel and is only valid when read from channel A.
- * Yes... broken hardware...
- */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
-#ifdef SCC_DEBUG
- printk("mac_SCC: interrupt; port: %lx channel: %lx \n",
- info->port, info->private->zs_channel);
-#endif
-
- if (info->private->zs_chan_a == info->private->zs_channel)
- shift = 3; /* Channel A */
- else
- shift = 0; /* Channel B */
-
- for (;;) {
- zs_intreg = read_zsreg(info->private->zs_chan_a, 3);
-#ifdef SCC_DEBUG
- printk("mac_SCC: status %x shift %d shifted %x \n",
- zs_intreg, shift, zs_intreg >> shift);
-#endif
- zs_intreg = zs_intreg >> shift;
- if ((zs_intreg & CHAN_IRQMASK) == 0)
- break;
-
- if (zs_intreg & CHBRxIP)
- receive_chars(info, regs);
- if (zs_intreg & CHBTxIP)
- transmit_chars(info);
- if (zs_intreg & CHBEXT)
- status_handle(info);
- }
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-
-static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag )
-{
- unsigned long flags;
-
- if (enab_flag) {
-#if 0
- save_flags(flags); cli();
- if (info->private->curregs[5] & TxENAB) {
- info->private->curregs[5] &= ~TxENAB;
- info->private->pendregs[5] &= ~TxENAB;
- write_zsreg(info->private->zs_channel, 5,
- info->private->curregs[5]);
- }
- restore_flags(flags);
-#endif
- /* FIXME: should call transmit_chars here ??? */
- transmit_chars(info);
- } else {
- save_flags(flags); cli();
-#if 0
- if ( info->xmit_cnt && info->xmit_buf &&
- !(info->private->curregs[5] & TxENAB)) {
- info->private->curregs[5] |= TxENAB;
- info->private->pendregs[5] = info->private->curregs[5];
- write_zsreg(info->private->zs_channel, 5,
- info->private->curregs[5]);
- }
-#else
- if ( info->xmit_cnt && info->xmit_buf &&
- !info->private->tx_active) {
- transmit_chars(info);
- }
-#endif
- restore_flags(flags);
- }
-
-}
-
-#if 0
-/*
- * leftover from original driver ...
- */
-static int SCC_startup(struct m68k_async_struct * info)
-{
- unsigned long flags;
-
- save_flags(flags); cli();
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
-#endif
-
- /*
- * Clear the receive FIFO.
- */
- ZS_CLEARFIFO(info->private->zs_channel);
- info->xmit_fifo_size = 1;
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->private->zs_channel, 0, ERR_RES);
- write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
-
- /*
- * Turn on RTS and DTR.
- */
- zs_rtsdtr(info, 1);
-
- /*
- * Finally, enable sequencing and interrupts
- */
- info->private->curregs[1] = (info->private->curregs[1] & ~0x18)
- | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
- info->private->pendregs[1] = info->private->curregs[1];
- info->private->curregs[3] |= (RxENABLE | Rx8);
- info->private->pendregs[3] = info->private->curregs[3];
- info->private->curregs[5] |= (TxENAB | Tx8);
- info->private->pendregs[5] = info->private->curregs[5];
- info->private->curregs[9] |= (NV | MIE);
- info->private->pendregs[9] = info->private->curregs[9];
- write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
- write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
- write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
-
- /*
- * Set the speed of the serial port
- */
- SCC_change_speed(info);
-
- /* Save the current value of RR0 */
- info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
-
- restore_flags(flags);
- return 0;
-}
-#endif
-
-/* FIXME: are these required ?? */
-static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty,
- struct file *file )
-{
- /* check on the basis of info->whatever ?? */
- if (info->private->kgdb_channel || info->private->is_cons)
- return -EBUSY;
- return( 0 );
-}
-
-static void SCC_init( struct m68k_async_struct *info )
-{
- /* FIXME: init currently done in probe_sccs() */
-
- /* BUT: startup part needs to be done here! */
-
-#ifdef SCC_DEBUG
- printk("mac_SCC: init, info %lx, info->port %lx \n", info, info->port);
-#endif
- /*
- * Clear the receive FIFO.
- */
- ZS_CLEARFIFO(info->private->zs_channel);
- info->xmit_fifo_size = 1;
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->private->zs_channel, 0, ERR_RES);
- write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
-
- /*
- * Turn on RTS and DTR.
- */
- zs_rtsdtr(info, 1);
-
- /*
- * Finally, enable sequencing and interrupts
- */
- info->private->curregs[1] = (info->private->curregs[1] & ~0x18)
- | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
- info->private->pendregs[1] = info->private->curregs[1];
- info->private->curregs[3] |= (RxENABLE | Rx8);
- info->private->pendregs[3] = info->private->curregs[3];
- info->private->curregs[5] |= (TxENAB | Tx8);
- info->private->pendregs[5] = info->private->curregs[5];
- info->private->curregs[9] |= (NV | MIE);
- info->private->pendregs[9] = info->private->curregs[9];
- write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
- write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
- write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
-
- /*
- * Set the speed of the serial port - done in startup() !!
- */
-#if 0
- SCC_change_speed(info);
-#endif
-
- /* Save the current value of RR0 */
- info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
-
-}
-
-static void SCC_init_port( struct m68k_async_struct *info, int type, int channel )
-{
- static int got_autovector = 0;
-
-#ifdef SCC_DEBUG
- printk("mac_SCC: init_port, info %x \n", info);
-#endif
- info->sw = &SCC_switch;
- info->private = &zs_soft_private[channel];
- info->private->zs_channel = &zs_channels[channel];
- info->irq = IRQ4;
- info->private->clk_divisor = 16;
- info->private->zs_baud = get_zsbaud(info);
- info->port = (int) info->private->zs_channel->control;
-
- /*
- * MSch: Extended interrupt scheme:
- * The generic m68k interrupt code can't use multiple handlers for
- * the same interrupt source (no chained interrupts).
- * We have to plug in a 'master' interrupt handler instead, calling
- * mac_SCC_interrupt with the proper arguments ...
- */
-
- if (!got_autovector) {
- if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info))
- panic("macserial: can't get irq %d", IRQ4);
-#ifdef SCC_DEBUG
- printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n",
- IRQ4, channel, info);
-#endif
- got_autovector = 1;
- }
-
- if (info->private->zs_chan_a == info->private->zs_channel) {
- /* Channel A */
- if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info))
- panic("mac_SCC: can't get irq %d", IRQ_SCCA);
-#ifdef SCC_DEBUG
- printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n",
- IRQ_SCCA, channel, info);
-#endif
- } else {
- /* Channel B */
- if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info))
- panic("mac_SCC: can't get irq %d", IRQ_SCCB);
-#ifdef SCC_DEBUG
- printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n",
- IRQ_SCCB, channel, info);
-#endif
- }
-
- /* If console serial line, then enable interrupts. */
- if (info->private->is_cons) {
- printk("mac_SCC: console line %d; enabling interrupt!\n", info->line);
- write_zsreg(info->private->zs_channel, R1,
- (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
- write_zsreg(info->private->zs_channel, R9, (NV | MIE));
- write_zsreg(info->private->zs_channel, R10, (NRZ));
- write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE));
- write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB));
- }
- /* If this is the kgdb line, enable interrupts because we
- * now want to receive the 'control-c' character from the
- * client attached to us asynchronously.
- */
- if (info->private->kgdb_channel) {
- printk("mac_SCC: kgdb line %d; enabling interrupt!\n", info->line);
- kgdb_chaninit(info, 1, info->private->zs_baud);
- }
- /* Report settings (in m68kserial.c) */
-#ifndef CONFIG_MAC
- printk("ttyS%d at 0x%08x (irq = %d)", info->line,
- info->port, info->irq);
- printk(" is a Z8530 SCC\n");
-#endif
-
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr)
-{
- unsigned long flags;
-
- save_flags(flags); cli(); /* Disable interrupts */
-
- info->private->pendregs[1] = info->private->curregs[1] = 0;
- write_zsreg(info->private->zs_channel, 1, 0); /* no interrupts */
-
- info->private->curregs[3] &= ~RxENABLE;
- info->private->pendregs[3] = info->private->curregs[3];
- write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
-
- info->private->curregs[5] &= ~TxENAB;
-
- if (!leave_dtr)
- info->private->curregs[5] &= ~(DTR | RTS);
- else
- info->private->curregs[5] &= ~(RTS);
-
- info->private->pendregs[5] = info->private->curregs[5];
- write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
-
- restore_flags(flags);
-}
-
-/* FIXME !!! */
-static int SCC_check_custom_divisor( struct m68k_async_struct *info,
- int baud_base, int divisor )
-{
- return 0;
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void SCC_change_speed(struct m68k_async_struct *info)
-{
- unsigned short port;
- unsigned cflag;
- int i;
- int brg;
- unsigned long flags;
-
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
- if (!(port = info->port))
- return;
- i = cflag & CBAUD;
-
- if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) {
- /* speed == 0 -> drop DTR */
- save_flags(flags);
- cli();
- info->private->curregs[5] &= ~(DTR | RTS);
- write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
- restore_flags(flags);
- return;
- }
-
-
- if (i & CBAUDEX) {
- /* XXX CBAUDEX is not obeyed.
- * It is impossible at a 32bits PPC. XXX??
- * But we have to report this to user ... someday.
- */
- i = B9600;
- }
-
- save_flags(flags); cli();
- info->private->zs_baud = baud_table[i];
- info->private->clk_divisor = 16;
-
- info->private->curregs[4] = X16CLK;
- info->private->curregs[11] = TCBR | RCBR;
- brg = BPS_TO_BRG(info->private->zs_baud,
- ZS_CLOCK/info->private->clk_divisor);
- info->private->curregs[12] = (brg & 255);
- info->private->curregs[13] = ((brg >> 8) & 255);
- info->private->curregs[14] = BRENABL;
-
- /* byte size and parity */
- info->private->curregs[3] &= ~RxNBITS_MASK;
- info->private->curregs[5] &= ~TxNBITS_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- info->private->curregs[3] |= Rx5;
- info->private->curregs[5] |= Tx5;
- break;
- case CS6:
- info->private->curregs[3] |= Rx6;
- info->private->curregs[5] |= Tx6;
- break;
- case CS7:
- info->private->curregs[3] |= Rx7;
- info->private->curregs[5] |= Tx7;
- break;
- case CS8:
- default: /* defaults to 8 bits */
- info->private->curregs[3] |= Rx8;
- info->private->curregs[5] |= Tx8;
- break;
- }
- info->private->pendregs[3] = info->private->curregs[3];
- info->private->pendregs[5] = info->private->curregs[5];
-
- info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
- if (cflag & CSTOPB) {
- info->private->curregs[4] |= SB2;
- } else {
- info->private->curregs[4] |= SB1;
- }
- if (cflag & PARENB) {
- info->private->curregs[4] |= PAR_ENA;
- }
- if (!(cflag & PARODD)) {
- info->private->curregs[4] |= PAR_EVEN;
- }
- info->private->pendregs[4] = info->private->curregs[4];
-
- info->private->curregs[15] &= ~(DCDIE | CTSIE);
- if (!(cflag & CLOCAL)) {
- info->private->curregs[15] |= DCDIE;
- }
- if (cflag & CRTSCTS) {
- info->private->curregs[15] |= CTSIE;
- if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0)
- info->private->tx_stopped = 1;
- } else
- info->private->tx_stopped = 0;
- info->private->pendregs[15] = info->private->curregs[15];
-
- /* Load up the new values */
- load_zsregs(info->private->zs_channel, info->private->curregs);
-
- restore_flags(flags);
-}
-
-/* This is for console output over ttya/ttyb */
-static void SCC_put_char(char ch)
-{
- struct mac_zschannel *chan = zs_conschan;
- int loops = 0;
- unsigned long flags;
-
- if(!chan)
- return;
-
- save_flags(flags); cli();
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) {
- loops++;
- udelay(5);
- }
- write_zsdata(chan, ch);
- restore_flags(flags);
-}
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
-
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- udelay(5);
- write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
-
- while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- udelay(5);
- return read_zsdata(chan);
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void SCC_fair_output(void)
-{
- int left; /* Output no more than that */
- unsigned long flags;
- struct m68k_async_struct *info = zs_consinfo;
- char c;
-
- if (info == 0) return;
- if (info->xmit_buf == 0) return;
-
- save_flags(flags); cli();
- left = info->xmit_cnt;
- while (left != 0) {
- c = info->xmit_buf[info->xmit_tail];
- info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- restore_flags(flags);
-
- SCC_put_char(c);
-
- save_flags(flags); cli();
- left = MIN(info->xmit_cnt, left-1);
- }
-
- restore_flags(flags);
- return;
-}
-
-/*
- * zs_console_print is registered for printk.
- */
-static void zs_console_print(const char *p)
-{
- char c;
-
- while ((c = *(p++)) != 0) {
- if (c == '\n')
- SCC_put_char('\r');
- SCC_put_char(c);
- }
-
- /* Comment this if you want to have a strict interrupt-driven output */
- SCC_fair_output();
-}
-
-/* FIXME: check with SCC_enab_tx_int!! */
-#if 0
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
- return;
-
- if (info->xmit_cnt <= 0 || tty->stopped || info->private->tx_stopped ||
- !info->xmit_buf)
- return;
-
- /* Enable transmitter */
- save_flags(flags); cli();
- transmit_chars(info);
- restore_flags(flags);
-}
-
-static int rs_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
-{
- int c, total = 0;
- struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf)
- return 0;
-
- save_flags(flags);
- while (1) {
- cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
-
- if (from_user) {
- down(&tmp_buf_sem);
- memcpy_fromfs(tmp_buf, buf, c);
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- up(&tmp_buf_sem);
- } else
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
- }
- if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
- && !info->tx_active)
- transmit_chars(info);
- restore_flags(flags);
- return total;
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void SCC_throttle(struct m68k_async_struct *info, int status)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- if (status) {
- /*
- * Here we want to turn off the RTS line. On Macintoshes,
- * we only get the DTR line, which goes to both DTR and
- * RTS on the modem. RTS doesn't go out to the serial
- * port socket. So you should make sure your modem is
- * set to ignore DTR if you're using CRTSCTS.
- */
- info->private->curregs[5] &= ~(DTR | RTS);
- info->private->pendregs[5] &= ~(DTR | RTS);
- write_zsreg(info->private->zs_channel, 5,
- info->private->curregs[5]);
- } else {
- /* Assert RTS and DTR lines */
- info->private->curregs[5] |= DTR | RTS;
- info->private->pendregs[5] |= DTR | RTS;
- write_zsreg(info->private->zs_channel, 5,
- info->private->curregs[5]);
- }
-
- restore_flags(flags);
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static void SCC_get_serial_info(struct m68k_async_struct * info,
- struct serial_struct * retinfo)
-{
- retinfo->baud_base = info->baud_base;
- retinfo->custom_divisor = info->custom_divisor;
-}
-
-/* FIXME: set_serial_info needs check_custom_divisor !!! */
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int SCC_get_lsr_info(struct m68k_async_struct * info, unsigned int *value)
-{
- unsigned char status;
-
- cli();
- status = read_zsreg(info->private->zs_channel, 0);
- sti();
- return status;
-}
-
-static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
-{
- unsigned char control, status;
- unsigned int result;
-
- cli();
- control = info->private->curregs[5];
- status = read_zsreg(info->private->zs_channel, 0);
- sti();
- result = ((control & RTS) ? TIOCM_RTS: 0)
- | ((control & DTR) ? TIOCM_DTR: 0)
- | ((status & DCD) ? TIOCM_CAR: 0)
- | ((status & CTS) ? 0: TIOCM_CTS);
- return result;
-}
-
-/* FIXME: zs_setdtr was used in rs_open ... */
-
-static int SCC_set_modem_info(struct m68k_async_struct *info,
- int new_dtr, int new_rts)
-{
- unsigned int bits;
-
- bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
- info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
- info->private->pendregs[5] = info->private->curregs[5];
- write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
- sti();
- return 0;
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void SCC_set_break(struct m68k_async_struct * info, int break_flag)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- if (break_flag) {
- info->private->curregs[5] |= SND_BRK;
- write_zsreg(info->private->zs_channel, 5,
- info->private->curregs[5]);
- } else {
- info->private->curregs[5] &= ~SND_BRK;
- write_zsreg(info->private->zs_channel, 5,
- info->private->curregs[5]);
- }
-
- restore_flags(flags);
-}
-
-/* FIXME: these have to be enabled in rs_ioctl !! */
-
-static int SCC_ioctl(struct tty_struct *tty, struct file * file,
- struct m68k_async_struct * info, unsigned int cmd,
- unsigned long arg)
-{
- int error;
-
- switch (cmd) {
- case TIOCSERGETLSR: /* Get line status register */
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
- else
- return SCC_get_lsr_info(info, (unsigned int *) arg);
-
- case TIOCSERGSTRUCT:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct m68k_async_struct));
- if (error)
- return error;
- copy_to_user((struct m68k_async_struct *) arg,
- info, sizeof(struct m68k_async_struct));
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void SCC_stop_receive (struct m68k_async_struct *info)
-{
- /* disable Rx */
- info->private->curregs[3] &= ~RxENABLE;
- info->private->pendregs[3] = info->private->curregs[3];
- write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
- /* disable Rx interrupts */
- info->private->curregs[1] &= ~(0x18); /* disable any rx ints */
- info->private->pendregs[1] = info->private->curregs[1];
- write_zsreg(info->private->zs_channel, 1, info->private->curregs[1]);
- ZS_CLEARFIFO(info->private->zs_channel);
-}
-
-static int SCC_trans_empty (struct m68k_async_struct *info)
-{
- return (read_zsreg(info->private->zs_channel, 1) & ALL_SNT) != 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-#ifdef CONFIG_MAC
-
-/*
- * Mac: use boot_info data; assume 2 channels
- */
-
-static void probe_sccs(void)
-{
- int n;
-
-#define ZS_CONTROL 0x50F04000
-#define ZS_DATA (ZS_CONTROL+4)
-#define ZS_IRQ 5
-#define ZS_MOVE -2
-#define ZS_DATA_MOVE 4
-#define ZS_CH_A_FIRST 2
-
- /* last-ditch fixup for NetBSD booter case */
- if (mac_bi_data.sccbase == 0)
- mac_bi_data.sccbase = ZS_CONTROL;
-
- /* testing: fix up broken 24 bit addresses (ClassicII) */
- if ((mac_bi_data.sccbase & 0x00FFFFFF) == mac_bi_data.sccbase)
- mac_bi_data.sccbase |= 0x50000000;
-
- if ( !hwreg_present((void *)mac_bi_data.sccbase))
- {
- printk(KERN_WARNING "z8530: Serial devices not accessible. Check serial switch.\n");
- return;
- }
-
- for(n=0;n<2;n++)
- {
-#if 0
- zs_channels[n].control = (volatile unsigned char *)
- ZS_CONTROL+ZS_MOVE*n;
- zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n;
-#else
- zs_channels[n].control = (volatile unsigned char *) /* 2, 0 */
- (mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
- zs_channels[n].data = (volatile unsigned char *) /* 6, 4 */
- (mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
-#endif
- zs_soft[n].private = &zs_soft_private[n];
- zs_soft[n].private->zs_channel = &zs_channels[n];
- zs_soft[n].irq = IRQ4;
-#if 0
- if (request_irq(ch->intrs[0], rs_interrupt, 0,
- "SCC", &zs_soft[n]))
- panic("macserial: can't get irq %d",
- ch->intrs[0]);
-#endif
- if (n & 1)
- zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
- else
- zs_soft[n].private->zs_chan_a = &zs_channels[n];
- }
-
- zs_channels_found=2;
-}
-
-#else
-
-/*
- * PowerMAC - query the PROM
- */
-
-static void show_serial_version(void)
-{
- printk("PowerMac Z8530 serial driver version 1.00\n");
-}
-
-/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
-static void
-probe_sccs()
-{
- struct device_node *dev, *ch;
- struct m68k_async_struct **pp;
- int n;
-
- n = 0;
- pp = &zs_chain;
- for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
- if (n >= NUM_CHANNELS) {
- printk("Sorry, can't use %s: no more channels\n",
- dev->full_name);
- continue;
- }
- for (ch = dev->child; ch != 0; ch = ch->sibling) {
- if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
- printk("Can't use %s: %d addrs %d intrs\n",
- ch->full_name, ch->n_addrs, ch->n_intrs);
- continue;
- }
- zs_channels[n].control = (volatile unsigned char *)
- ch->addrs[0].address;
- zs_channels[n].data = zs_channels[n].control
- + ch->addrs[0].size / 2;
- zs_soft[n].private = &zs_soft_private[n];
- zs_soft[n].private->zs_channel = &zs_channels[n];
- zs_soft[n].irq = ch->intrs[0];
- if (request_irq(ch->intrs[0], mac_SCC_interrupt, 0,
- "SCC", &zs_soft[n]))
- panic("macserial: can't get irq %d",
- ch->intrs[0]);
- /* XXX this assumes the prom puts chan A before B */
- if (n & 1)
- zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
- else
- zs_soft[n].private->zs_chan_a = &zs_channels[n];
-
- *pp = &zs_soft[n];
- pp = &zs_soft[n].private->zs_next;
- ++n;
- }
- }
- *pp = 0;
- zs_channels_found = n;
-}
-
-#endif
-
-extern void register_console(void (*proc)(const char *));
-
-static inline void
-rs_cons_check(struct m68k_async_struct *ss, int channel)
-{
- int i, o, io;
- static int consout_registered = 0;
- static int msg_printed = 0;
-
- i = o = io = 0;
-
- /* Is this one of the serial console lines? */
- if ((zs_cons_chanout != channel) &&
- (zs_cons_chanin != channel))
- return;
- zs_conschan = ss->private->zs_channel;
- zs_consinfo = ss;
-
- /* Register the console output putchar, if necessary */
- if (zs_cons_chanout == channel) {
- o = 1;
- /* double whee.. */
- if (!consout_registered) {
- register_console(zs_console_print);
- consout_registered = 1;
- }
- }
-
- if (zs_cons_chanin == channel) {
- i = 1;
- }
- if (o && i)
- io = 1;
- if (ss->private->zs_baud != 9600)
- panic("Console baud rate weirdness");
-
- /* Set flag variable for this port so that it cannot be
- * opened for other uses by accident.
- */
- ss->private->is_cons = 1;
-
- if (io) {
- if(!msg_printed) {
- printk("zs%d: console I/O\n", ((channel>>1)&1));
- msg_printed = 1;
- }
- } else {
- printk("zs%d: console %s\n", ((channel>>1)&1),
- (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
- }
-
- /* FIXME : register interrupt here??? */
-}
-
-volatile int test_done;
-
-/* rs_init inits the driver */
-int mac_SCC_init(void)
-{
- int channel, line, nr = 0;
- unsigned long flags;
- struct serial_struct req;
-
- printk("Mac68K Z8530 serial driver version 1.01\n");
-
- /* SCC present at all? */
- if (!MACH_IS_MAC)
- return( -ENODEV );
-
- if (zs_chain == 0)
- probe_sccs();
-
- save_flags(flags);
- cli();
-
- /*
- * FIXME: init of rs_table entry and register_serial now done,
- * but possible clash of zs_soft[channel] and rs_table[channel]!!
- * zs_soft initialized in probe_sccs(), some settings copied to
- * info = &rs_table[channel], which is used by the mid-level code.
- * The info->private part is shared among both!
- */
-
- for (channel = 0; channel < zs_channels_found; ++channel) {
- req.line = channel;
- req.type = SER_SCC_MAC;
- req.port = (int) zs_soft[channel].private->zs_channel->control;
-
- if ((line = register_serial( &req )) >= 0) {
- SCC_init_port( &rs_table[line], req.type, line );
- ++nr;
- }
- else
- printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line );
- }
-
- restore_flags(flags);
-
- return( nr > 0 ? 0 : -ENODEV );
-}
-
-/* Hooks for running a serial console. con_init() calls this if the
- * console is being run over one of the serial ports.
- * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored.
- */
-void
-rs_cons_hook(int chip, int out, int channel)
-{
- if (zs_chain == 0)
- probe_sccs();
- zs_soft[channel].private->clk_divisor = 16;
- zs_soft[channel].private->zs_baud = get_zsbaud(&zs_soft[channel]);
- rs_cons_check(&zs_soft[channel], channel);
- if (out)
- zs_cons_chanout = channel;
- else
- zs_cons_chanin = channel;
-
- /* FIXME : register interrupt here??? */
-}
-
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1
- * for /dev/ttyS1 which is determined in setup_arch() from the
- * boot command line flags.
- */
-void
-rs_kgdb_hook(int tty_num)
-{
- if (zs_chain == 0)
- probe_sccs();
- zs_kgdbchan = zs_soft[tty_num].private->zs_channel;
- zs_soft[tty_num].private->clk_divisor = 16;
- zs_soft[tty_num].private->zs_baud = get_zsbaud(&zs_soft[tty_num]);
- zs_soft[tty_num].private->kgdb_channel = 1; /* This runs kgdb */
- zs_soft[tty_num ^ 1].private->kgdb_channel = 0; /* This does not */
- /* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
- ZS_CLEARERR(zs_kgdbchan);
- ZS_CLEARFIFO(zs_kgdbchan);
-
- /* FIXME : register interrupt here??? */
-}
-
diff --git a/drivers/char/mac_SCC.h b/drivers/char/mac_SCC.h
deleted file mode 100644
index 5e903e1db..000000000
--- a/drivers/char/mac_SCC.h
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _MAC_SCC_H
-#define _MAC_SCC_H
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF 0
-#define ZILOG_CLOSING_WAIT_NONE 65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
- on the callout port */
-#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK 0x0030
-#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
- * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-/* MSch: gone to <asm/serial.h> */
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define FLAG 0x7e
-
-/* Write Register 0 */
-#define R0 0 /* Register selects */
-#define R1 1
-#define R2 2
-#define R3 3
-#define R4 4
-#define R5 5
-#define R6 6
-#define R7 7
-#define R8 8
-#define R9 9
-#define R10 10
-#define R11 11
-#define R12 12
-#define R13 13
-#define R14 14
-#define R15 15
-
-#define NULLCODE 0 /* Null Code */
-#define POINT_HIGH 0x8 /* Select upper half of registers */
-#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
-#define SEND_ABORT 0x18 /* HDLC Abort */
-#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
-#define RES_Tx_P 0x28 /* Reset TxINT Pending */
-#define ERR_RES 0x30 /* Error Reset */
-#define RES_H_IUS 0x38 /* Reset highest IUS */
-
-#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
-#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
-#define RES_EOM_L 0xC0 /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
-#define TxINT_ENAB 0x2 /* Tx Int Enable */
-#define PAR_SPEC 0x4 /* Parity is special condition */
-
-#define RxINT_DISAB 0 /* Rx Int Disable */
-#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
-#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
-#define INT_ERR_Rx 0x18 /* Int on error only */
-
-#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
-#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
-#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define RxENABLE 0x1 /* Rx Enable */
-#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
-#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
-#define ENT_HM 0x10 /* Enter Hunt Mode */
-#define AUTO_ENAB 0x20 /* Auto Enables */
-#define Rx5 0x0 /* Rx 5 Bits/Character */
-#define Rx7 0x40 /* Rx 7 Bits/Character */
-#define Rx6 0x80 /* Rx 6 Bits/Character */
-#define Rx8 0xc0 /* Rx 8 Bits/Character */
-#define RxNBITS_MASK 0xc0
-
-/* Write Register 4 */
-
-#define PAR_ENA 0x1 /* Parity Enable */
-#define PAR_EVEN 0x2 /* Parity Even/Odd* */
-
-#define SYNC_ENAB 0 /* Sync Modes Enable */
-#define SB1 0x4 /* 1 stop bit/char */
-#define SB15 0x8 /* 1.5 stop bits/char */
-#define SB2 0xc /* 2 stop bits/char */
-#define SB_MASK 0xc
-
-#define MONSYNC 0 /* 8 Bit Sync character */
-#define BISYNC 0x10 /* 16 bit sync character */
-#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC 0x30 /* External Sync Mode */
-
-#define X1CLK 0x0 /* x1 clock mode */
-#define X16CLK 0x40 /* x16 clock mode */
-#define X32CLK 0x80 /* x32 clock mode */
-#define X64CLK 0xC0 /* x64 clock mode */
-#define XCLK_MASK 0xC0
-
-/* Write Register 5 */
-
-#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
-#define RTS 0x2 /* RTS */
-#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
-#define TxENAB 0x8 /* Tx Enable */
-#define SND_BRK 0x10 /* Send Break */
-#define Tx5 0x0 /* Tx 5 bits (or less)/character */
-#define Tx7 0x20 /* Tx 7 bits/character */
-#define Tx6 0x40 /* Tx 6 bits/character */
-#define Tx8 0x60 /* Tx 8 bits/character */
-#define TxNBITS_MASK 0x60
-#define DTR 0x80 /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define VIS 1 /* Vector Includes Status */
-#define NV 2 /* No Vector */
-#define DLC 4 /* Disable Lower Chain */
-#define MIE 8 /* Master Interrupt Enable */
-#define STATHI 0x10 /* Status high */
-#define NORESET 0 /* No reset on write to R9 */
-#define CHRB 0x40 /* Reset channel B */
-#define CHRA 0x80 /* Reset channel A */
-#define FHWRES 0xc0 /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define BIT6 1 /* 6 bit/8bit sync */
-#define LOOPMODE 2 /* SDLC Loop mode */
-#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE 8 /* Mark/flag on idle */
-#define GAOP 0x10 /* Go active on poll */
-#define NRZ 0 /* NRZ mode */
-#define NRZI 0x20 /* NRZI mode */
-#define FM1 0x40 /* FM1 (transition = 1) */
-#define FM0 0x60 /* FM0 (transition = 0) */
-#define CRCPS 0x80 /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define TRxCXT 0 /* TRxC = Xtal output */
-#define TRxCTC 1 /* TRxC = Transmit clock */
-#define TRxCBR 2 /* TRxC = BR Generator Output */
-#define TRxCDP 3 /* TRxC = DPLL output */
-#define TRxCOI 4 /* TRxC O/I */
-#define TCRTxCP 0 /* Transmit clock = RTxC pin */
-#define TCTRxCP 8 /* Transmit clock = TRxC pin */
-#define TCBR 0x10 /* Transmit clock = BR Generator output */
-#define TCDPLL 0x18 /* Transmit clock = DPLL output */
-#define RCRTxCP 0 /* Receive clock = RTxC pin */
-#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
-#define RCBR 0x40 /* Receive clock = BR Generator output */
-#define RCDPLL 0x60 /* Receive clock = DPLL output */
-#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define BRENABL 1 /* Baud rate generator enable */
-#define BRSRC 2 /* Baud rate generator source */
-#define DTRREQ 4 /* DTR/Request function */
-#define AUTOECHO 8 /* Auto Echo */
-#define LOOPBAK 0x10 /* Local loopback */
-#define SEARCH 0x20 /* Enter search mode */
-#define RMC 0x40 /* Reset missing clock */
-#define DISDPLL 0x60 /* Disable DPLL */
-#define SSBR 0x80 /* Set DPLL source = BR generator */
-#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
-#define SFMM 0xc0 /* Set FM mode */
-#define SNRZI 0xe0 /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define ZCIE 2 /* Zero count IE */
-#define DCDIE 8 /* DCD IE */
-#define SYNCIE 0x10 /* Sync/hunt IE */
-#define CTSIE 0x20 /* CTS IE */
-#define TxUIE 0x40 /* Tx Underrun/EOM IE */
-#define BRKIE 0x80 /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define Rx_CH_AV 0x1 /* Rx Character Available */
-#define ZCOUNT 0x2 /* Zero count */
-#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
-#define DCD 0x8 /* DCD */
-#define SYNC_HUNT 0x10 /* Sync/hunt */
-#define CTS 0x20 /* CTS */
-#define TxEOM 0x40 /* Tx underrun */
-#define BRK_ABRT 0x80 /* Break/Abort */
-
-/* Read Register 1 */
-#define ALL_SNT 0x1 /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3 0x8 /* 0/3 */
-#define RES4 0x4 /* 0/4 */
-#define RES5 0xc /* 0/5 */
-#define RES6 0x2 /* 0/6 */
-#define RES7 0xa /* 0/7 */
-#define RES8 0x6 /* 0/8 */
-#define RES18 0xe /* 1/8 */
-#define RES28 0x0 /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR 0x10 /* Parity error */
-#define Rx_OVR 0x20 /* Rx Overrun Error */
-#define FRM_ERR 0x40 /* CRC/Framing Error */
-#define END_FR 0x80 /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
-#define CHBTxIP 0x2 /* Channel B Tx IP */
-#define CHBRxIP 0x4 /* Channel B Rx IP */
-#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
-#define CHATxIP 0x10 /* Channel A Tx IP */
-#define CHARxIP 0x20 /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10 (misc status bits) */
-#define ONLOOP 2 /* On loop */
-#define LOOPSEND 0x10 /* Loop sending */
-#define CLK2MIS 0x40 /* Two clocks missing */
-#define CLK1MIS 0x80 /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- } while(0)
-
-#endif /* !(_MAC_SCC_H) */
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 09c12be26..e70860ea9 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -2,6 +2,9 @@
* linux/drivers/char/mem.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Added devfs support.
+ * Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
*/
#include <linux/config.h>
@@ -58,9 +61,6 @@ extern void mda_console_init(void);
#if defined(CONFIG_ADB)
extern void adbdev_init(void);
#endif
-#ifdef CONFIG_USB
-extern void usb_init(void);
-#endif
#ifdef CONFIG_PHONE
extern void telephony_init(void);
#endif
@@ -248,14 +248,16 @@ static ssize_t read_kmem(struct file *file, char *buf,
if (p < PAGE_SIZE && read > 0) {
size_t tmp = PAGE_SIZE - p;
if (tmp > read) tmp = read;
- clear_user(buf, tmp);
+ if (clear_user(buf, tmp))
+ return -EFAULT;
buf += tmp;
p += tmp;
read -= tmp;
count -= tmp;
}
#endif
- copy_to_user(buf, (char *)p, read);
+ if (copy_to_user(buf, (char *)p, read))
+ return -EFAULT;
p += read;
buf += read;
count -= read;
@@ -574,19 +576,47 @@ static int memory_open(struct inode * inode, struct file * filp)
return 0;
}
+void __init memory_devfs_register (void)
+{
+ /* These are never unregistered */
+ static const struct {
+ unsigned short minor;
+ char *name;
+ umode_t mode;
+ struct file_operations *fops;
+ } list[] = { /* list of minor devices */
+ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
+ {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
+ {3, "null", S_IRUGO | S_IWUGO, &null_fops},
+#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \
+ defined(CONFIG_HAVE_IO_PORTS)
+ {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
+#endif
+ {5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
+ {7, "full", S_IRUGO | S_IWUGO, &full_fops},
+ {8, "random", S_IRUGO | S_IWUSR, &random_fops},
+ {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}
+ };
+ int i;
+
+ for (i=0; i<(sizeof(list)/sizeof(*list)); i++)
+ devfs_register (NULL, list[i].name, 0, DEVFS_FL_NONE,
+ MEM_MAJOR, list[i].minor,
+ list[i].mode | S_IFCHR, 0, 0,
+ list[i].fops, NULL);
+}
+
static struct file_operations memory_fops = {
open: memory_open, /* just a selector for the real open */
};
int __init chr_dev_init(void)
{
- if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
+ if (devfs_register_chrdev(MEM_MAJOR,"mem",&memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
+ memory_devfs_register();
rand_initialize();
raw_init();
-#ifdef CONFIG_USB
- usb_init();
-#endif
#ifdef CONFIG_I2C
i2c_init_all();
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 0e3f17fe6..99884a00a 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -29,6 +29,8 @@
*
* Changes for kmod (from kerneld):
* Cyrus Durgin <cider@speakeasy.org>
+ *
+ * Added devfs support. Richard Gooch <rgooch@atnf.csiro.au> 10-Jan-1998
*/
#include <linux/module.h>
@@ -41,6 +43,7 @@
#include <linux/major.h>
#include <linux/malloc.h>
#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/stat.h>
#include <linux/init.h>
@@ -120,6 +123,8 @@ static struct file_operations misc_fops = {
int misc_register(struct miscdevice * misc)
{
+ static devfs_handle_t devfs_handle = NULL;
+
if (misc->next || misc->prev)
return -EBUSY;
if (misc->minor == MISC_DYNAMIC_MINOR) {
@@ -132,6 +137,13 @@ int misc_register(struct miscdevice * misc)
}
if (misc->minor < DYNAMIC_MINORS)
misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
+ if (!devfs_handle)
+ devfs_handle = devfs_mk_dir (NULL, "misc", 4, NULL);
+ misc->devfs_handle =
+ devfs_register (devfs_handle, misc->name, 0, DEVFS_FL_NONE,
+ MISC_MAJOR, misc->minor,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ misc->fops, NULL);
/*
* Add it to the front, so that later devices can "override"
@@ -153,6 +165,7 @@ int misc_deregister(struct miscdevice * misc)
misc->next->prev = misc->prev;
misc->next = NULL;
misc->prev = NULL;
+ devfs_unregister (misc->devfs_handle);
if (i < DYNAMIC_MINORS && i>0) {
misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
}
@@ -219,11 +232,10 @@ int __init misc_init(void)
#ifdef CONFIG_SGI
streamable_init ();
#endif
- if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
+ if (devfs_register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
return -EIO;
}
-
return 0;
}
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index e49144c1a..c61a6e6a9 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -38,7 +38,7 @@
/* select machine configuration */
#if defined(CONFIG_ATARI)
#define MACH ATARI
-#elif defined(__i386__) /* and others?? */
+#elif defined(__i386__) || defined(__arm__) /* and others?? */
#define MACH PC
#else
#error Cannot build nvram driver for this machine configuration.
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 68dbeff21..6ae0ab71c 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -413,9 +413,12 @@ static inline void handle_mouse_event(unsigned char scancode)
#endif
}
+static unsigned char kbd_exists = 1;
+
static inline void handle_keyboard_event(unsigned char scancode)
{
#ifdef CONFIG_VT
+ kbd_exists = 1;
if (do_acknowledge(scancode))
handle_scancode(scancode, !(scancode & 0x80));
#endif
@@ -512,8 +515,10 @@ static int send_data(unsigned char data)
void pckbd_leds(unsigned char leds)
{
- if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))
- send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */
+ if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) {
+ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */
+ kbd_exists = 0;
+ }
}
/*
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index 75f27e830..2e451ce17 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -1198,7 +1198,6 @@ int __init pcxe_init(void)
memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs);
init_bh(DIGI_BH,do_pcxe_bh);
- enable_bh(DIGI_BH);
timer_table[DIGI_TIMER].fn = pcxxpoll;
timer_table[DIGI_TIMER].expires = 0;
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 6a6ff8081..d73c09695 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -45,6 +45,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/ioctl.h>
#include <linux/parport.h>
#include <linux/ctype.h>
@@ -579,13 +580,20 @@ static struct file_operations pp_fops = {
release: pp_release,
};
+static devfs_handle_t devfs_handle = NULL;
+
static int __init ppdev_init (void)
{
- if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
+ if (devfs_register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
PP_MAJOR);
return -EIO;
}
+ devfs_handle = devfs_mk_dir (NULL, "parports", 0, NULL);
+ devfs_register_series (devfs_handle, "%u", PARPORT_MAX,
+ DEVFS_FL_DEFAULT, PP_MAJOR, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ &pp_fops, NULL);
printk (KERN_INFO PP_VERSION "\n");
return 0;
@@ -594,7 +602,8 @@ static int __init ppdev_init (void)
static void __exit ppdev_cleanup (void)
{
/* Clean up all parport stuff */
- unregister_chrdev (PP_MAJOR, CHRDEV);
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev (PP_MAJOR, CHRDEV);
}
module_init(ppdev_init);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 5f35b24ad..77cdb7a51 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -20,6 +20,7 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -28,6 +29,10 @@
#define BUILDING_PTY_C 1
#include <linux/devpts_fs.h>
+extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned int minor);
+extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
+
struct pty_struct {
int magic;
wait_queue_head_t open_wait;
@@ -94,6 +99,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
}
}
#endif
+ tty_unregister_devfs (&tty->link->driver, MINOR (tty->device));
tty_vhangup(tty->link);
}
}
@@ -323,6 +329,11 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
wake_up_interruptible(&pty->open_wait);
set_bit(TTY_THROTTLED, &tty->flags);
+ /* register a slave for the master */
+ if (tty->driver.major == PTY_MASTER_MAJOR)
+ tty_register_devfs(&tty->link->driver, DEVFS_FL_WAIT,
+ tty->link->driver.minor_start +
+ MINOR(tty->device)-tty->driver.minor_start);
retval = 0;
out:
return retval;
@@ -346,7 +357,7 @@ int __init pty_init(void)
memset(&pty_driver, 0, sizeof(struct tty_driver));
pty_driver.magic = TTY_DRIVER_MAGIC;
pty_driver.driver_name = "pty_master";
- pty_driver.name = "pty";
+ pty_driver.name = "pty/m%d";
pty_driver.major = PTY_MASTER_MAJOR;
pty_driver.minor_start = 0;
pty_driver.num = NR_PTYS;
@@ -377,12 +388,16 @@ int __init pty_init(void)
pty_slave_driver = pty_driver;
pty_slave_driver.driver_name = "pty_slave";
pty_slave_driver.proc_entry = 0;
- pty_slave_driver.name = "ttyp";
+ pty_slave_driver.name = "pty/s%d";
pty_slave_driver.subtype = PTY_TYPE_SLAVE;
pty_slave_driver.major = PTY_SLAVE_MAJOR;
pty_slave_driver.minor_start = 0;
pty_slave_driver.init_termios = tty_std_termios;
pty_slave_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
+ /* Slave ptys are registered when their corresponding master pty
+ * is opened, and unregistered when the pair is closed.
+ */
+ pty_slave_driver.flags |= TTY_DRIVER_NO_DEVFS;
pty_slave_driver.table = ttyp_table;
pty_slave_driver.termios = ttyp_termios;
pty_slave_driver.termios_locked = ttyp_termios_locked;
@@ -403,6 +418,7 @@ int __init pty_init(void)
/* Unix98 devices */
#ifdef CONFIG_UNIX98_PTYS
+ devfs_mk_dir (NULL, "pts", 3, NULL);
printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS);
for ( i = 0 ; i < UNIX98_NR_MAJORS ; i++ ) {
int j;
@@ -415,6 +431,7 @@ int __init pty_init(void)
ptm_driver[i].name_base = i*NR_PTYS;
ptm_driver[i].num = NR_PTYS;
ptm_driver[i].other = &pts_driver[i];
+ ptm_driver[i].flags |= TTY_DRIVER_NO_DEVFS;
ptm_driver[i].table = ptm_table[i];
ptm_driver[i].termios = ptm_termios[i];
ptm_driver[i].termios_locked = ptm_termios_locked[i];
@@ -424,7 +441,7 @@ int __init pty_init(void)
init_waitqueue_head(&ptm_state[i][j].open_wait);
pts_driver[i] = pty_slave_driver;
- pts_driver[i].name = "pts";
+ pts_driver[i].name = "pts/%d";
pts_driver[i].proc_entry = 0;
pts_driver[i].major = UNIX98_PTY_SLAVE_MAJOR+i;
pts_driver[i].minor_start = 0;
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 95c188e83..6296e789b 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -97,14 +97,18 @@ static ssize_t rtc_read(struct file *file, char *buf,
static int rtc_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
+#ifndef __alpha__
static unsigned int rtc_poll(struct file *file, poll_table *wait);
+#endif
static void get_rtc_time (struct rtc_time *rtc_tm);
static void get_rtc_alm_time (struct rtc_time *alm_tm);
+#ifndef __alpha__
static void rtc_dropped_irq(unsigned long data);
static void set_rtc_irq_bit(unsigned char bit);
static void mask_rtc_irq_bit(unsigned char bit);
+#endif
static inline unsigned char rtc_is_updating(void);
@@ -132,6 +136,7 @@ static unsigned long epoch = 1900; /* year corresponding to 0x00 */
static const unsigned char days_in_mo[] =
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+#ifndef __alpha__
/*
* A very tiny interrupt handler. It runs with SA_INTERRUPT set,
* so that there is no possibility of conflicting with the
@@ -162,6 +167,7 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (atomic_read(&rtc_status) & RTC_TIMER_ON)
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
}
+#endif
/*
* Now all the various file operations that we export.
@@ -175,6 +181,9 @@ static long long rtc_llseek(struct file *file, loff_t offset, int origin)
static ssize_t rtc_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
+#ifdef __alpha__
+ return -EIO;
+#else
DECLARE_WAITQUEUE(wait, current);
unsigned long data;
ssize_t retval;
@@ -206,6 +215,7 @@ static ssize_t rtc_read(struct file *file, char *buf,
remove_wait_queue(&rtc_wait, &wait);
return retval;
+#endif
}
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -216,6 +226,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct rtc_time wtime;
switch (cmd) {
+#ifndef __alpha__
case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
{
mask_rtc_irq_bit(RTC_AIE);
@@ -265,6 +276,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
set_rtc_irq_bit(RTC_UIE);
return 0;
}
+#endif
case RTC_ALM_READ: /* Read the present alarm time */
{
/*
@@ -398,6 +410,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
+#ifndef __alpha__
case RTC_IRQP_READ: /* Read the periodic IRQ rate. */
{
return put_user(rtc_freq, (unsigned long *)arg);
@@ -437,7 +450,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
-#if defined(__alpha__) || defined(__mips__)
case RTC_EPOCH_READ: /* Read the epoch. */
{
return put_user (epoch, (unsigned long *)arg);
@@ -494,13 +506,14 @@ static int rtc_fasync (int fd, struct file *filp, int on)
static int rtc_release(struct inode *inode, struct file *file)
{
+ unsigned long flags;
+#ifndef __alpha__
/*
* Turn off all interrupts once the device is no longer
* in use, and clear the data.
*/
unsigned char tmp;
- unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
tmp = CMOS_READ(RTC_CONTROL);
@@ -520,6 +533,7 @@ static int rtc_release(struct inode *inode, struct file *file)
rtc_fasync (-1, file, 0);
}
+#endif
MOD_DEC_USE_COUNT;
spin_lock_irqsave (&rtc_lock, flags);
@@ -529,6 +543,7 @@ static int rtc_release(struct inode *inode, struct file *file)
return 0;
}
+#ifndef __alpha__
static unsigned int rtc_poll(struct file *file, poll_table *wait)
{
unsigned long l, flags;
@@ -543,6 +558,7 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
return POLLIN | POLLRDNORM;
return 0;
}
+#endif
/*
* The various file operations we support.
@@ -551,7 +567,9 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
static struct file_operations rtc_fops = {
llseek: rtc_llseek,
read: rtc_read,
+#ifndef __alpha__
poll: rtc_poll,
+#endif
ioctl: rtc_ioctl,
open: rtc_open,
release: rtc_release,
@@ -612,12 +630,14 @@ found:
return -EIO;
}
+#ifndef __alpha__
if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
{
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
return -EIO;
}
+#endif
request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
#endif /* __sparc__ vs. others */
@@ -657,12 +677,14 @@ found:
#ifdef CONFIG_MIPS_JAZZ
epoch = 1980;
#endif
+#ifndef __alpha__
init_timer(&rtc_irq_timer);
rtc_irq_timer.function = rtc_dropped_irq;
spin_lock_irqsave(&rtc_lock, flags);
/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
spin_unlock_irqrestore(&rtc_lock, flags);
+#endif
rtc_freq = 1024;
printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
@@ -692,6 +714,7 @@ module_init(rtc_init);
module_exit(rtc_exit);
EXPORT_NO_SYMBOLS;
+#ifndef __alpha__
/*
* At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
* (usually during an IDE disk interrupt, with IRQ unmasking off)
@@ -717,6 +740,7 @@ static void rtc_dropped_irq(unsigned long data)
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
spin_unlock_irqrestore(&rtc_lock, flags);
}
+#endif
/*
* Info exported via "/proc/driver/rtc".
@@ -905,6 +929,7 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm)
}
}
+#ifndef __alpha__
/*
* Used to disable/enable interrupts for any one of UIE, AIE, PIE.
* Rumour has it that if you frob the interrupt enable/disable
@@ -942,3 +967,4 @@ static void set_rtc_irq_bit(unsigned char bit)
rtc_irq_data = 0;
spin_unlock_irqrestore(&rtc_lock, flags);
}
+#endif
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index eeb82a033..3b9a71f9e 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -217,7 +217,12 @@ static char *serial_revdate = "2000-1-27";
#else
#define _INLINE_
#endif
-
+
+extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned int minor);
+extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
+
+
static char *serial_name = "Serial driver";
static DECLARE_TASK_QUEUE(tq_serial);
@@ -4406,7 +4411,7 @@ int __init rs_init(void)
#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
#endif
- serial_driver.name = "ttyS";
+ serial_driver.name = "tts/%d";
serial_driver.major = TTY_MAJOR;
serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
serial_driver.num = NR_PORTS;
@@ -4415,7 +4420,7 @@ int __init rs_init(void)
serial_driver.init_termios = tty_std_termios;
serial_driver.init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
serial_driver.refcount = &serial_refcount;
serial_driver.table = serial_table;
serial_driver.termios = serial_termios;
@@ -4450,7 +4455,7 @@ int __init rs_init(void)
* major number and the subtype code.
*/
callout_driver = serial_driver;
- callout_driver.name = "cua";
+ callout_driver.name = "cua/%d";
callout_driver.major = TTYAUX_MAJOR;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
#if (LINUX_VERSION_CODE >= 131343)
@@ -4497,6 +4502,10 @@ int __init rs_init(void)
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
state->port, state->irq,
uart_config[state->type].name);
+ tty_register_devfs(&serial_driver, 0,
+ serial_driver.minor_start + state->line);
+ tty_register_devfs(&callout_driver, 0,
+ callout_driver.minor_start + state->line);
}
#ifdef ENABLE_SERIAL_PCI
probe_serial_pci();
@@ -4574,6 +4583,10 @@ int register_serial(struct serial_struct *req)
state->iomem_base ? (unsigned long)state->iomem_base :
(unsigned long)state->port,
state->irq, uart_config[state->type].name);
+ tty_register_devfs(&serial_driver, 0,
+ serial_driver.minor_start + state->line);
+ tty_register_devfs(&callout_driver, 0,
+ callout_driver.minor_start + state->line);
return state->line + SERIAL_DEV_OFFSET;
}
@@ -4588,6 +4601,13 @@ void unregister_serial(int line)
tty_hangup(state->info->tty);
state->type = PORT_UNKNOWN;
printk(KERN_INFO "tty%02d unloaded\n", state->line);
+ /* These will be hidden, because they are devices that will no longer
+ * be available to the system. (ie, PCMCIA modems, once ejected)
+ */
+ tty_unregister_devfs(&serial_driver,
+ serial_driver.minor_start + state->line);
+ tty_unregister_devfs(&callout_driver,
+ callout_driver.minor_start + state->line);
restore_flags(flags);
}
@@ -4676,6 +4696,8 @@ static inline void wait_for_xmitr(struct async_struct *info)
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
+ *
+ * The console_lock must be held when we get here.
*/
static void serial_console_write(struct console *co, const char *s,
unsigned count)
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 885b236fd..35b480a1c 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2729,6 +2729,8 @@ void console_setup(char *str, int *ints)
*
* Of course, once the console has been registered, we had better ensure
* that serial167_init() doesn't leave the chip non-functional.
+ *
+ * The console_lock must be held when we get here.
*/
void serial167_console_write(struct console *co, const char *str, unsigned count)
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index d936eef41..18fa8c645 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -40,6 +40,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -750,6 +751,8 @@ static struct file_operations stl_fsiomem = {
/*****************************************************************************/
+static devfs_handle_t devfs_handle = NULL;
+
#ifdef MODULE
/*
@@ -780,7 +783,7 @@ void cleanup_module()
stlpanel_t *panelp;
stlport_t *portp;
unsigned long flags;
- int i, j, k;
+ int i, j, k, l;
#if DEBUG
printk("cleanup_module()\n");
@@ -806,7 +809,8 @@ void cleanup_module()
restore_flags(flags);
return;
}
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
+ devfs_unregister (devfs_handle);
+ if ((i = devfs_unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
printk("STALLION: failed to un-register serial memory device, "
"errno=%d\n", -i);
@@ -3213,8 +3217,13 @@ int __init stl_init(void)
* Set up a character driver for per board stuff. This is mainly used
* to do stats ioctls on the ports.
*/
- if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
+ if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
printk("STALLION: failed to register serial board device\n");
+ devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
+ devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
+ STL_SIOMEMMAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &stl_fsiomem, NULL);
/*
* Set up the tty driver structure and register us as a driver.
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 6fece9470..7fcbfbb52 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -21,6 +21,7 @@
#include <linux/kbd_kern.h>
#include <linux/quotaops.h>
#include <linux/smp_lock.h>
+#include <linux/module.h>
#include <asm/ptrace.h>
@@ -32,6 +33,8 @@ extern struct vfsmount *vfsmntlist;
/* Machine specific power off function */
void (*sysrq_power_off)(void) = NULL;
+EXPORT_SYMBOL(sysrq_power_off);
+
/* Send a signal to all user processes */
static void send_sig_all(int sig, int even_init)
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 7a9257ae9..d29c63407 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -89,7 +89,8 @@
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/init.h>
-
+#include <linux/devfs_fs_kernel.h>
+
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -2774,23 +2775,6 @@ static struct file_operations qic02_tape_fops = {
};
-/* Why is this not is one place? */
-/* Pure 2^n version of get_order */
-static inline int __get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do
- {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
-
static void qic02_release_resources(void)
{
free_irq(QIC02_TAPE_IRQ, NULL);
@@ -2798,7 +2782,7 @@ static void qic02_release_resources(void)
release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
if (buffaddr)
{
- free_pages(buffaddr, __get_order(TPQBUF_SIZE));
+ free_pages(buffaddr, get_order(TPQBUF_SIZE));
}
buffaddr = 0; /* Better to cause a panic than overwite someone else */
status_zombie = YES;
@@ -2850,7 +2834,7 @@ static int qic02_get_resources(void)
/* Setup the page-address for the dma transfer. */
/*** TODO: does _get_dma_pages() really return the physical address?? ****/
- buffaddr = __get_dma_pages(GFP_KERNEL,__get_order(TPQBUF_SIZE));
+ buffaddr = __get_dma_pages(GFP_KERNEL,get_order(TPQBUF_SIZE));
if (!buffaddr)
{
@@ -2919,7 +2903,7 @@ int __init qic02_tape_init(void)
#endif
printk(TPQIC02_NAME ": DMA buffers: %u blocks\n", NR_BLK_BUF);
/* If we got this far, install driver functions */
- if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops))
+ if (devfs_register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops))
{
printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", QIC02_TAPE_MAJOR);
#ifndef CONFIG_QIC02_DYNCONF
@@ -2927,7 +2911,38 @@ int __init qic02_tape_init(void)
#endif
return -ENODEV;
}
-
+ devfs_register (NULL, "ntpqic11", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 2,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
+ devfs_register (NULL, "tpqic11", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 3,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
+ devfs_register (NULL, "ntpqic24", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 4,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
+ devfs_register (NULL, "tpqic24", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 5,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
+ devfs_register (NULL, "ntpqic120", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 6,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
+ devfs_register (NULL, "tpqic120", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 7,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
+ devfs_register (NULL, "ntpqic150", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 8,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
+ devfs_register (NULL, "tpqic150", 0, DEVFS_FL_NONE,
+ QIC02_TAPE_MAJOR, 9,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ &qic02_tape_fops, NULL);
init_waitqueue_head(&qic02_tape_transfer);
/* prepare timer */
TIMEROFF;
@@ -2974,7 +2989,15 @@ void cleanup_module(void)
{
qic02_release_resources();
}
- unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
+ devfs_unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic11", 0, QIC02_TAPE_MAJOR, 2, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic11", 0, QIC02_TAPE_MAJOR, 3, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic24", 0, QIC02_TAPE_MAJOR, 4, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic24", 0, QIC02_TAPE_MAJOR, 5, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic120", 0, QIC02_TAPE_MAJOR, 6, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic120", 0, QIC02_TAPE_MAJOR, 7, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic150", 0, QIC02_TAPE_MAJOR, 8, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic150", 0, QIC02_TAPE_MAJOR, 9, DEVFS_SPECIAL_CHR, 0));
}
int init_module(void)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index abc27bb91..705d876b3 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -52,6 +52,9 @@
* Rewrote init_dev and release_dev to eliminate races.
* -- Bill Hawes <whawes@star.net>, June 97
*
+ * Added devfs support.
+ * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
+ *
* Added support for a Unix98-style ptmx device.
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
*/
@@ -79,6 +82,7 @@
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -88,9 +92,17 @@
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/kmod.h>
+#ifdef CONFIG_VT
+extern void con_init_devfs (void);
+#endif
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned minor);
+void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
+
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
@@ -107,6 +119,7 @@ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
+extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */
#endif
/*
@@ -149,16 +162,26 @@ extern int rs_8xx_init(void);
/*
* This routine returns the name of tty.
*/
+static char *
+_tty_make_name(struct tty_struct *tty, const char *name, char *buf)
+{
+ int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
+
+ if (!tty) /* Hmm. NULL pointer. That's fun. */
+ strcpy(buf, "NULL tty");
+ else
+ sprintf(buf, name,
+ idx + tty->driver.name_base);
+
+ return buf;
+}
+
#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
(tty)->driver.name_base)
-
+
char *tty_name(struct tty_struct *tty, char *buf)
{
- if (tty)
- sprintf(buf, "%s%d", tty->driver.name, TTY_NUMBER(tty));
- else
- strcpy(buf, "NULL tty");
- return buf;
+ return _tty_make_name(tty, (tty)?tty->driver.name:NULL, buf);
}
inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
@@ -1298,6 +1321,8 @@ retry_open:
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
minor -= driver->minor_start;
devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
+ tty_register_devfs(&pts_driver[major], 0,
+ pts_driver[major].minor_start + minor);
noctty = 1;
goto init_dev_done;
@@ -1966,16 +1991,86 @@ void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
}
/*
+ * Register a tty device described by <driver>, with minor number <minor>.
+ */
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
+ unsigned int minor)
+{
+#ifdef CONFIG_DEVFS_FS
+ umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
+ uid_t uid = 0;
+ gid_t gid = 0;
+ struct tty_struct tty;
+ char buf[32];
+
+ flags |= DEVFS_FL_DEFAULT;
+ tty.driver = *driver;
+ tty.device = MKDEV (driver->major, minor);
+ switch (tty.device) {
+ case TTY_DEV:
+ case PTMX_DEV:
+ mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ break;
+ default:
+ flags |= DEVFS_FL_AUTO_OWNER;
+ break;
+ }
+ if ((minor < driver->minor_start) ||
+ (minor >= driver->minor_start + driver->num)) {
+ printk(KERN_ERR "Attempt to register invalid minor number "
+ "with devfs (%d:%d).\n", (int)driver->major,(int)minor);
+ return;
+ }
+ if (driver->type == TTY_DRIVER_TYPE_CONSOLE) {
+ flags |= DEVFS_FL_AOPEN_NOTIFY;
+ flags &= ~DEVFS_FL_AUTO_OWNER;
+ }
+# ifdef CONFIG_UNIX98_PTYS
+ if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) &&
+ (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) {
+ flags &= ~DEVFS_FL_AUTO_OWNER;
+ uid = current->uid;
+ gid = current->gid;
+ }
+# endif
+ devfs_register (NULL, tty_name (&tty, buf), 0, flags,
+ driver->major, minor, mode, uid, gid,
+ &tty_fops, NULL);
+#endif /* CONFIG_DEVFS_FS */
+}
+
+void tty_unregister_devfs (struct tty_driver *driver, unsigned minor)
+{
+#ifdef CONFIG_DEVFS_FS
+ void * handle;
+ struct tty_struct tty;
+ char buf[32];
+
+ tty.driver = *driver;
+ tty.device = MKDEV(driver->major, minor);
+
+ handle = devfs_find_handle (NULL, tty_name (&tty, buf), 0,
+ driver->major, minor,
+ DEVFS_SPECIAL_CHR, 0);
+ devfs_unregister (handle);
+#endif /* CONFIG_DEVFS_FS */
+}
+
+EXPORT_SYMBOL(tty_register_devfs);
+EXPORT_SYMBOL(tty_unregister_devfs);
+
+/*
* Called by a tty driver to register itself.
*/
int tty_register_driver(struct tty_driver *driver)
{
int error;
+ int i;
if (driver->flags & TTY_DRIVER_INSTALLED)
return 0;
- error = register_chrdev(driver->major, driver->name, &tty_fops);
+ error = devfs_register_chrdev(driver->major, driver->name, &tty_fops);
if (error < 0)
return error;
else if(driver->major == 0)
@@ -1989,6 +2084,10 @@ int tty_register_driver(struct tty_driver *driver)
if (tty_drivers) tty_drivers->prev = driver;
tty_drivers = driver;
+ if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
+ for(i = 0; i < driver->num; i++)
+ tty_register_devfs(driver, 0, driver->minor_start + i);
+ }
proc_tty_register_driver(driver);
return error;
}
@@ -2018,11 +2117,11 @@ int tty_unregister_driver(struct tty_driver *driver)
return -ENOENT;
if (othername == NULL) {
- retval = unregister_chrdev(driver->major, driver->name);
+ retval = devfs_unregister_chrdev(driver->major, driver->name);
if (retval)
return retval;
} else
- register_chrdev(driver->major, othername, &tty_fops);
+ devfs_register_chrdev(driver->major, othername, &tty_fops);
if (driver->prev)
driver->prev->next = driver->next;
@@ -2048,6 +2147,7 @@ int tty_unregister_driver(struct tty_driver *driver)
driver->termios_locked[i] = NULL;
kfree_s(tp, sizeof(struct termios));
}
+ tty_unregister_devfs(driver, driver->minor_start + i);
}
proc_tty_unregister_driver(driver);
return 0;
@@ -2148,6 +2248,13 @@ void __init tty_init(void)
if (tty_register_driver(&dev_syscons_driver))
panic("Couldn't register /dev/console driver\n");
+ /* console calls tty_register_driver() before kmalloc() works.
+ * Thus, we can't devfs_register() then. Do so now, instead.
+ */
+#ifdef CONFIG_VT
+ con_init_devfs();
+#endif
+
#ifdef CONFIG_UNIX98_PTYS
dev_ptmx_driver = dev_tty_driver;
dev_ptmx_driver.driver_name = "/dev/ptmx";
@@ -2163,7 +2270,7 @@ void __init tty_init(void)
#ifdef CONFIG_VT
dev_console_driver = dev_tty_driver;
- dev_console_driver.driver_name = "/dev/tty0";
+ dev_console_driver.driver_name = "/dev/vc/0";
dev_console_driver.name = dev_console_driver.driver_name + 5;
dev_console_driver.major = TTY_MAJOR;
dev_console_driver.type = TTY_DRIVER_TYPE_SYSTEM;
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index e099b4ac3..1da60703e 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -21,10 +21,12 @@
* - making it shorter - scr_readw are macros which expand in PRETTY long code
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/tty.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
@@ -32,8 +34,11 @@
#include <linux/vt_kern.h>
#include <linux/console_struct.h>
#include <linux/selection.h>
+#include <linux/kbd_kern.h>
+#include <linux/console.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#undef attr
#undef org
@@ -80,21 +85,34 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
return file->f_pos;
}
-#define RETURN(x) { enable_bh(CONSOLE_BH); return x; }
+/* We share this temporary buffer with the console write code
+ * so that we can easily avoid touching user space while holding the
+ * console spinlock.
+ */
+extern char con_buf[PAGE_SIZE];
+#define CON_BUF_SIZE PAGE_SIZE
+extern struct semaphore con_buf_sem;
+
static ssize_t
vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
unsigned int currcons = MINOR(inode->i_rdev);
- long p = *ppos;
- long viewed, attr, size, read;
- char *buf0;
+ long pos = *ppos;
+ long viewed, attr, read;
int col, maxcol;
unsigned short *org = NULL;
+ ssize_t ret;
+
+ down(&con_buf_sem);
+
+ /* Select the proper current console and verify
+ * sanity of the situation under the console lock.
+ */
+ spin_lock_irq(&console_lock);
attr = (currcons & 128);
currcons = (currcons & 127);
- disable_bh(CONSOLE_BH);
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
@@ -102,78 +120,143 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
currcons--;
viewed = 0;
}
+ ret = -ENXIO;
if (!vc_cons_allocated(currcons))
- RETURN( -ENXIO );
+ goto unlock_out;
- size = vcs_size(inode);
- if (p < 0 || p > size)
- RETURN( -EINVAL );
- if (count > size - p)
- count = size - p;
-
- buf0 = buf;
- maxcol = video_num_columns;
- if (!attr) {
- org = screen_pos(currcons, p, viewed);
- col = p % maxcol;
- p += maxcol - col;
- while (count-- > 0) {
- put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
- if (++col == maxcol) {
- org = screen_pos(currcons, p, viewed);
- col = 0;
- p += maxcol;
- }
- }
- } else {
- if (p < HEADER_SIZE) {
- char header[HEADER_SIZE];
- header[0] = (char) video_num_lines;
- header[1] = (char) video_num_columns;
- getconsxy(currcons, header+2);
- while (p < HEADER_SIZE && count > 0)
- { count--; put_user(header[p++], buf++); }
- }
- p -= HEADER_SIZE;
- col = (p/2) % maxcol;
- if (count > 0) {
- org = screen_pos(currcons, p/2, viewed);
- if ((p & 1) && count > 0) {
- count--;
-#ifdef __BIG_ENDIAN
- put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
-#else
- put_user(vcs_scr_readw(currcons, org++) >> 8, buf++);
-#endif
- p++;
+ ret = -EINVAL;
+ if (pos < 0)
+ goto unlock_out;
+ read = 0;
+ ret = 0;
+ while (count) {
+ char *con_buf0, *con_buf_start;
+ long this_round, size;
+ ssize_t orig_count;
+ long p = pos;
+
+ /* Check whether we are above size each round,
+ * as copy_to_user at the end of this loop
+ * could sleep.
+ */
+ size = vcs_size(inode);
+ if (pos >= size)
+ break;
+ if (count > size - pos)
+ count = size - pos;
+
+ this_round = count;
+ if (this_round > CON_BUF_SIZE)
+ this_round = CON_BUF_SIZE;
+
+ /* Perform the whole read into the local con_buf.
+ * Then we can drop the console spinlock and safely
+ * attempt to move it to userspace.
+ */
+
+ con_buf_start = con_buf0 = con_buf;
+ orig_count = this_round;
+ maxcol = video_num_columns;
+ if (!attr) {
+ org = screen_pos(currcons, p, viewed);
+ col = p % maxcol;
+ p += maxcol - col;
+ while (this_round-- > 0) {
+ *con_buf0++ = (vcs_scr_readw(currcons, org++) & 0xff);
if (++col == maxcol) {
- org = screen_pos(currcons, p/2, viewed);
+ org = screen_pos(currcons, p, viewed);
col = 0;
+ p += maxcol;
}
}
- p /= 2;
- p += maxcol - col;
- }
- while (count > 1) {
- put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf);
- buf += 2;
- count -= 2;
- if (++col == maxcol) {
+ } else {
+ if (p < HEADER_SIZE) {
+ size_t tmp_count;
+
+ con_buf0[0] = (char) video_num_lines;
+ con_buf0[1] = (char) video_num_columns;
+ getconsxy(currcons, con_buf0 + 2);
+
+ con_buf_start += p;
+ this_round += p;
+ if (this_round > CON_BUF_SIZE) {
+ this_round = CON_BUF_SIZE;
+ orig_count = this_round - p;
+ }
+
+ tmp_count = HEADER_SIZE;
+ if (tmp_count > this_round)
+ tmp_count = this_round;
+
+ /* Advance state pointers and move on. */
+ this_round -= tmp_count;
+ p = HEADER_SIZE;
+ con_buf0 = con_buf + HEADER_SIZE;
+ /* If this_round >= 0, then p is even... */
+ } else if (p & 1) {
+ /* Skip first byte for output if start address is odd
+ * Update region sizes up/down depending on free
+ * space in buffer.
+ */
+ con_buf_start++;
+ if (this_round < CON_BUF_SIZE)
+ this_round++;
+ else
+ orig_count--;
+ }
+ if (this_round > 0) {
+ unsigned short *tmp_buf = (unsigned short *)con_buf0;
+
+ p -= HEADER_SIZE;
+ p /= 2;
+ col = p % maxcol;
+
org = screen_pos(currcons, p, viewed);
- col = 0;
- p += maxcol;
+ p += maxcol - col;
+
+ /* Buffer has even length, so we can always copy
+ * character + attribute. We do not copy last byte
+ * to userspace if this_round is odd.
+ */
+ this_round = (this_round + 1) >> 1;
+
+ while (this_round) {
+ *tmp_buf++ = vcs_scr_readw(currcons, org++);
+ this_round --;
+ if (++col == maxcol) {
+ org = screen_pos(currcons, p, viewed);
+ col = 0;
+ p += maxcol;
+ }
+ }
}
}
- if (count > 0)
-#ifdef __BIG_ENDIAN
- put_user(vcs_scr_readw(currcons, org) >> 8, buf++);
-#else
- put_user(vcs_scr_readw(currcons, org) & 0xff, buf++);
-#endif
+
+ /* Finally, temporarily drop the console lock and push
+ * all the data to userspace from our temporary buffer.
+ */
+
+ spin_unlock_irq(&console_lock);
+ ret = copy_to_user(buf, con_buf_start, orig_count);
+ spin_lock_irq(&console_lock);
+
+ if (ret) {
+ read += (orig_count - ret);
+ ret = -EFAULT;
+ break;
+ }
+ buf += orig_count;
+ pos += orig_count;
+ read += orig_count;
+ count -= orig_count;
}
- read = buf - buf0;
*ppos += read;
- RETURN( read );
+ if (read)
+ ret = read;
+unlock_out:
+ spin_unlock_irq(&console_lock);
+ up(&con_buf_sem);
+ return ret;
}
static ssize_t
@@ -181,15 +264,23 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
unsigned int currcons = MINOR(inode->i_rdev);
- long p = *ppos;
+ long pos = *ppos;
long viewed, attr, size, written;
- const char *buf0;
+ char *con_buf0;
int col, maxcol;
u16 *org0 = NULL, *org = NULL;
+ size_t ret;
+
+ down(&con_buf_sem);
+
+ /* Select the proper current console and verify
+ * sanity of the situation under the console lock.
+ */
+ spin_lock_irq(&console_lock);
attr = (currcons & 128);
currcons = (currcons & 127);
- disable_bh(CONSOLE_BH);
+
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
@@ -197,94 +288,159 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
currcons--;
viewed = 0;
}
+ ret = -ENXIO;
if (!vc_cons_allocated(currcons))
- RETURN( -ENXIO );
+ goto unlock_out;
size = vcs_size(inode);
- if (p < 0 || p > size)
- RETURN( -EINVAL );
- if (count > size - p)
- count = size - p;
-
- buf0 = buf;
- maxcol = video_num_columns;
- if (!attr) {
- org0 = org = screen_pos(currcons, p, viewed);
- col = p % maxcol;
- p += maxcol - col;
- while (count > 0) {
- unsigned char c;
- count--;
- get_user(c, (const unsigned char*)buf++);
- vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
- org++;
- if (++col == maxcol) {
- org = screen_pos(currcons, p, viewed);
- col = 0;
- p += maxcol;
+ ret = -EINVAL;
+ if (pos < 0 || pos > size)
+ goto unlock_out;
+ if (count > size - pos)
+ count = size - pos;
+ written = 0;
+ while (count) {
+ long this_round = count;
+ size_t orig_count;
+ long p;
+
+ if (this_round > CON_BUF_SIZE)
+ this_round = CON_BUF_SIZE;
+
+ /* Temporarily drop the console lock so that we can read
+ * in the write data from userspace safely.
+ */
+ spin_unlock_irq(&console_lock);
+ ret = copy_from_user(con_buf, buf, this_round);
+ spin_lock_irq(&console_lock);
+
+ if (ret) {
+ this_round -= ret;
+ if (!this_round) {
+ /* Abort loop if no data were copied. Otherwise
+ * fail with -EFAULT.
+ */
+ if (written)
+ break;
+ ret = -EFAULT;
+ goto unlock_out;
}
}
- } else {
- if (p < HEADER_SIZE) {
- char header[HEADER_SIZE];
- getconsxy(currcons, header+2);
- while (p < HEADER_SIZE && count > 0)
- { count--; get_user(header[p++], buf++); }
- if (!viewed)
- putconsxy(currcons, header+2);
- }
- p -= HEADER_SIZE;
- col = (p/2) % maxcol;
- if (count > 0) {
- org0 = org = screen_pos(currcons, p/2, viewed);
- if ((p & 1) && count > 0) {
- char c;
- count--;
- get_user(c,buf++);
+
+ /* The vcs_size might have changed while we slept to grab
+ * the user buffer, so recheck.
+ * Return data written up to now on failure.
+ */
+ size = vcs_size(inode);
+ if (pos >= size)
+ break;
+ if (this_round > size - pos)
+ this_round = size - pos;
+
+ /* OK, now actually push the write to the console
+ * under the lock using the local kernel buffer.
+ */
+
+ con_buf0 = con_buf;
+ orig_count = this_round;
+ maxcol = video_num_columns;
+ p = pos;
+ if (!attr) {
+ org0 = org = screen_pos(currcons, p, viewed);
+ col = p % maxcol;
+ p += maxcol - col;
+
+ while (this_round > 0) {
+ unsigned char c = *con_buf0++;
+
+ this_round--;
+ vcs_scr_writew(currcons,
+ (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
+ org++;
+ if (++col == maxcol) {
+ org = screen_pos(currcons, p, viewed);
+ col = 0;
+ p += maxcol;
+ }
+ }
+ } else {
+ if (p < HEADER_SIZE) {
+ char header[HEADER_SIZE];
+
+ getconsxy(currcons, header + 2);
+ while (p < HEADER_SIZE && this_round > 0) {
+ this_round--;
+ header[p++] = *con_buf0++;
+ }
+ if (!viewed)
+ putconsxy(currcons, header + 2);
+ }
+ p -= HEADER_SIZE;
+ col = (p/2) % maxcol;
+ if (this_round > 0) {
+ org0 = org = screen_pos(currcons, p/2, viewed);
+ if ((p & 1) && this_round > 0) {
+ char c;
+
+ this_round--;
+ c = *con_buf0++;
#ifdef __BIG_ENDIAN
- vcs_scr_writew(currcons, c |
- (vcs_scr_readw(currcons, org) & 0xff00), org);
+ vcs_scr_writew(currcons, c |
+ (vcs_scr_readw(currcons, org) & 0xff00), org);
#else
- vcs_scr_writew(currcons, (c << 8) |
- (vcs_scr_readw(currcons, org) & 0xff), org);
+ vcs_scr_writew(currcons, (c << 8) |
+ (vcs_scr_readw(currcons, org) & 0xff), org);
#endif
- org++;
- p++;
+ org++;
+ p++;
+ if (++col == maxcol) {
+ org = screen_pos(currcons, p/2, viewed);
+ col = 0;
+ }
+ }
+ p /= 2;
+ p += maxcol - col;
+ }
+ while (this_round > 1) {
+ unsigned short w;
+
+ w = get_unaligned(((const unsigned short *)con_buf0));
+ vcs_scr_writew(currcons, w, org++);
+ con_buf0 += 2;
+ this_round -= 2;
if (++col == maxcol) {
- org = screen_pos(currcons, p/2, viewed);
+ org = screen_pos(currcons, p, viewed);
col = 0;
+ p += maxcol;
}
}
- p /= 2;
- p += maxcol - col;
- }
- while (count > 1) {
- unsigned short w;
- get_user(w, (const unsigned short *) buf);
- vcs_scr_writew(currcons, w, org++);
- buf += 2;
- count -= 2;
- if (++col == maxcol) {
- org = screen_pos(currcons, p, viewed);
- col = 0;
- p += maxcol;
- }
- }
- if (count > 0) {
- unsigned char c;
- get_user(c, (const unsigned char*)buf++);
+ if (this_round > 0) {
+ unsigned char c;
+
+ c = *con_buf0++;
#ifdef __BIG_ENDIAN
- vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org);
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org);
#else
- vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
#endif
+ }
}
+ count -= orig_count;
+ written += orig_count;
+ buf += orig_count;
+ pos += orig_count;
+ if (org0)
+ update_region(currcons, (unsigned long)(org0), org-org0);
}
- if (org0)
- update_region(currcons, (unsigned long)(org0), org-org0);
- written = buf - buf0;
*ppos += written;
- RETURN( written );
+ ret = written;
+
+unlock_out:
+ spin_unlock_irq(&console_lock);
+
+ up(&con_buf_sem);
+
+ return ret;
}
static int
@@ -303,12 +459,49 @@ static struct file_operations vcs_fops = {
open: vcs_open,
};
+static devfs_handle_t devfs_handle = NULL;
+
+void vcs_make_devfs (unsigned int index, int unregister)
+{
+#ifdef CONFIG_DEVFS_FS
+ char name[8];
+
+ sprintf (name, "a%u", index + 1);
+ if (unregister)
+ {
+ devfs_unregister ( devfs_find_handle (devfs_handle, name + 1, 0, 0, 0,
+ DEVFS_SPECIAL_CHR, 0) );
+ devfs_unregister ( devfs_find_handle (devfs_handle, name, 0, 0, 0,
+ DEVFS_SPECIAL_CHR, 0) );
+ }
+ else
+ {
+ devfs_register (devfs_handle, name + 1, 0, DEVFS_FL_DEFAULT,
+ VCS_MAJOR, index + 1,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+ devfs_register (devfs_handle, name, 0, DEVFS_FL_DEFAULT,
+ VCS_MAJOR, index + 129,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+ }
+#endif /* CONFIG_DEVFS_FS */
+}
+
int __init vcs_init(void)
{
int error;
- error = register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
+ error = devfs_register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
+
if (error)
printk("unable to get major %d for vcs device", VCS_MAJOR);
+
+ devfs_handle = devfs_mk_dir (NULL, "vcc", 3, NULL);
+ devfs_register (devfs_handle, "0", 1, DEVFS_FL_DEFAULT,
+ VCS_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+ devfs_register (devfs_handle, "a", 1, DEVFS_FL_DEFAULT,
+ VCS_MAJOR, 128,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+
return error;
}
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index d10182d29..cfcdbfcde 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -229,6 +229,8 @@ static int video_mmap(struct inode * ino, struct file * file,
return -EINVAL;
}
+extern struct file_operations video_fops;
+
/*
* Video For Linux device drivers request registration here.
*/
@@ -239,24 +241,29 @@ int video_register_device(struct video_device *vfd, int type)
int base;
int err;
int end;
+ char *name_base;
switch(type)
{
case VFL_TYPE_GRABBER:
base=0;
end=64;
+ name_base = "video";
break;
case VFL_TYPE_VTX:
base=192;
end=224;
+ name_base = "vtx";
break;
case VFL_TYPE_VBI:
base=224;
end=240;
+ name_base = "vbi";
break;
case VFL_TYPE_RADIO:
base=64;
end=128;
+ name_base = "radio";
break;
default:
return -1;
@@ -266,6 +273,8 @@ int video_register_device(struct video_device *vfd, int type)
{
if(video_device[i]==NULL)
{
+ char name[16];
+
video_device[i]=vfd;
vfd->minor=i;
/* The init call may sleep so we book the slot out
@@ -281,6 +290,12 @@ int video_register_device(struct video_device *vfd, int type)
return err;
}
}
+ sprintf (name, "v4l/%s%d", name_base, i - base);
+ vfd->devfs_handle =
+ devfs_register (NULL, name, 0, DEVFS_FL_DEFAULT,
+ VIDEO_MAJOR, vfd->minor,
+ S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ &video_fops, NULL);
return 0;
}
}
@@ -295,6 +310,7 @@ void video_unregister_device(struct video_device *vfd)
{
if(video_device[vfd->minor]!=vfd)
panic("vfd: bad unregister");
+ devfs_unregister (vfd->devfs_handle);
video_device[vfd->minor]=NULL;
MOD_DEC_USE_COUNT;
}
@@ -323,7 +339,7 @@ int videodev_init(void)
struct video_init *vfli = video_init_list;
printk(KERN_INFO "Linux video capture interface: v1.00\n");
- if(register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops))
+ if(devfs_register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops))
{
printk("video_dev: unable to get major %d\n", VIDEO_MAJOR);
return -EIO;
@@ -349,7 +365,7 @@ int init_module(void)
void cleanup_module(void)
{
- unregister_chrdev(VIDEO_MAJOR, "video_capture");
+ devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture");
}
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 15232f832..b6b2263a0 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -1045,6 +1045,7 @@ static void scc_ch_write (char ch)
*p = ch;
}
+/* The console_lock must be held when we get here. */
static void scc_console_write (struct console *co, const char *str, unsigned count)
{
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 59b204554..8425e64da 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -22,6 +22,7 @@
#include <linux/malloc.h>
#include <linux/major.h>
#include <linux/fs.h>
+#include <linux/console.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -105,12 +106,13 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
{
static struct timer_list sound_timer = { NULL, NULL, 0, 0,
kd_nosound };
-
unsigned int count = 0;
+ unsigned long flags;
if (hz > 20 && hz < 32767)
count = 1193180 / hz;
+ save_flags(flags);
cli();
del_timer(&sound_timer);
if (count) {
@@ -128,7 +130,7 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
}
} else
kd_nosound(0);
- sti();
+ restore_flags(flags);
return;
}
@@ -804,12 +806,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* When we actually do the console switch,
* make sure we are atomic with respect to
* other console switches..
- *
- * Damn! Was it difficult to make this clean?
*/
- disable_bh(CONSOLE_BH);
+ spin_lock_irq(&console_lock);
complete_change_console(newvt);
- enable_bh(CONSOLE_BH);
+ spin_unlock_irq(&console_lock);
}
}
diff --git a/drivers/char/zr36120_mem.c b/drivers/char/zr36120_mem.c
index 5e81049eb..082cfee06 100644
--- a/drivers/char/zr36120_mem.c
+++ b/drivers/char/zr36120_mem.c
@@ -35,17 +35,6 @@
/* Memory management functions */
/*******************************/
-inline int __get_order(unsigned long size)
-{
- int order = 0;
- size = (size+PAGE_SIZE-1)/PAGE_SIZE;
- while (size) {
- size /= 2;
- order++;
- }
- return order;
-}
-
void* bmalloc(unsigned long size)
{
void* mem;
@@ -56,7 +45,7 @@ void* bmalloc(unsigned long size)
* The following function got a lot of memory at boottime,
* so we know its always there...
*/
- mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,__get_order(size));
+ mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,get_order(size));
#endif
if (mem) {
unsigned long adr = (unsigned long)mem;
@@ -82,7 +71,7 @@ void bfree(void* mem, unsigned long size)
#ifdef CONFIG_BIGPHYS_AREA
bigphysarea_free_pages(mem);
#else
- free_pages((unsigned long)mem,__get_order(size));
+ free_pages((unsigned long)mem,get_order(size));
#endif
}
}
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
index 4b96ae1d3..4123a7364 100644
--- a/drivers/fc4/fc.c
+++ b/drivers/fc4/fc.c
@@ -56,17 +56,21 @@
#ifdef __sparc__
#define dma_alloc_consistent(d,s,p) sbus_alloc_consistent(d,s,p)
#define dma_free_consistent(d,s,v,h) sbus_free_consistent(d,s,v,h)
-#define dma_map_single(d,v,s) sbus_map_single(d,v,s)
-#define dma_unmap_single(d,h,s) sbus_unmap_single(d,h,s)
-#define dma_map_sg(d,s,n) sbus_map_sg(d,s,n)
-#define dma_unmap_sg(d,s,n) sbus_unmap_sg(d,s,n)
+#define dma_map_single(d,v,s,dir) sbus_map_single(d,v,s,dir)
+#define dma_unmap_single(d,h,s,dir) sbus_unmap_single(d,h,s,dir)
+#define dma_map_sg(d,s,n,dir) sbus_map_sg(d,s,n,dir)
+#define dma_unmap_sg(d,s,n,dir) sbus_unmap_sg(d,s,n,dir)
+#define scsi_to_fc_dma_dir(dir) scsi_to_sbus_dma_dir(dir)
+#define FC_DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL
#else
#define dma_alloc_consistent(d,s,p) pci_alloc_consistent(d,s,p)
#define dma_free_consistent(d,s,v,h) pci_free_consistent(d,s,v,h)
-#define dma_map_single(d,v,s) pci_map_single(d,v,s)
-#define dma_unmap_single(d,h,s) pci_unmap_single(d,h,s)
-#define dma_map_sg(d,s,n) pci_map_sg(d,s,n)
-#define dma_unmap_sg(d,s,n) pci_unmap_sg(d,s,n)
+#define dma_map_single(d,v,s,dir) pci_map_single(d,v,s,dir)
+#define dma_unmap_single(d,h,s,dir) pci_unmap_single(d,h,s,dir)
+#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir)
+#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir)
+#define scsi_to_fc_dma_dir(dir) scsi_to_pci_dma_dir(dir)
+#define FC_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
#endif
#define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp))
@@ -163,7 +167,8 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
fc->state = FC_STATE_FPORT_OK;
fcmd = l->fcmds + i;
plogi = l->logi + 3 * i;
- dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi));
+ dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
plogi->code = LS_PLOGI;
memcpy (&plogi->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn));
memcpy (&plogi->node_wwn, &fc->wwn_node, sizeof(fc_wwn));
@@ -183,7 +188,8 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
printk ("\n");
}
#endif
- fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi));
+ fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
fcmd->rsp = fcmd->cmd + 2 * sizeof(logi);
if (fc->hw_enque (fc, fcmd))
printk ("FC: Cannot enque PLOGI packet on %s\n", fc->name);
@@ -206,7 +212,8 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
switch (status) {
case FC_STATUS_OK:
plogi = l->logi + 3 * i;
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+ dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
if (!fc->wwn_dest.lo && !fc->wwn_dest.hi) {
memcpy (&fc->wwn_dest, &plogi[1].node_wwn, sizeof(fc_wwn));
FCD(("Dest WWN %08x%08x\n", *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo))
@@ -224,7 +231,8 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
break;
case FC_STATUS_ERR_OFFLINE:
fc->state = FC_STATE_OFFLINE;
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+ dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
printk ("%s: FC is offline\n", fc->name);
if (atomic_dec_and_test (&l->todo))
up(&l->sem);
@@ -248,7 +256,8 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status)
FCD(("Report map done %d %d\n", i, status))
switch (status) {
case FC_STATUS_OK: /* Ok, let's have a fun on a loop */
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+ dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
p = (fc_al_posmap *)(l->logi + 3 * i);
#ifdef FCDEBUG
{
@@ -297,7 +306,8 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status)
case FC_STATUS_POINTTOPOINT: /* We're Point-to-Point, no AL... */
FCD(("SID %d DID %d\n", fc->sid, fc->did))
fcmd = l->fcmds + i;
- dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi));
+ dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
fch = &fcmd->fch;
memset(l->logi + 3 * i, 0, 3 * sizeof(logi));
FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT);
@@ -307,7 +317,8 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status)
FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
fch->param = 0;
l->logi [3 * i].code = LS_FLOGI;
- fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi));
+ fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
fcmd->rsp = fcmd->cmd + sizeof(logi);
fcmd->cmdlen = sizeof(logi);
fcmd->rsplen = sizeof(logi);
@@ -424,9 +435,11 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
if (fcmd->data) {
if (SCpnt->use_sg)
- dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg);
+ dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg,
+ scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
else
- dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen);
+ dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen,
+ scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
}
break;
default:
@@ -565,7 +578,8 @@ int fcp_initialize(fc_channel *fcchain, int count)
fc->login = fcmd;
fc->ls = (void *)l;
/* Assumes sizeof(fc_al_posmap) < 3 * sizeof(logi), which is true */
- fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi));
+ fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi),
+ FC_DMA_BIDIRECTIONAL);
fcmd->proto = PROTO_REPORT_AL_MAP;
fcmd->token = i;
fcmd->fc = fc;
@@ -584,7 +598,7 @@ int fcp_initialize(fc_channel *fcchain, int count)
} else {
fc->state = FC_STATE_OFFLINE;
enable_irq(fc->irq);
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+ dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
if (atomic_dec_and_test (&l->todo))
goto all_done;
}
@@ -601,7 +615,7 @@ int fcp_initialize(fc_channel *fcchain, int count)
FCD(("SID %d DID %d\n", fc->sid, fc->did))
fcmd = l->fcmds + i;
- dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi));
+ dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
fch = &fcmd->fch;
FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT);
FILL_FCHDR_SID(fch, 0);
@@ -610,7 +624,7 @@ int fcp_initialize(fc_channel *fcchain, int count)
FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
fch->param = 0;
l->logi [3 * i].code = LS_FLOGI;
- fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi));
+ fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
fcmd->rsp = fcmd->cmd + sizeof(logi);
fcmd->cmdlen = sizeof(logi);
fcmd->rsplen = sizeof(logi);
@@ -638,7 +652,7 @@ all_done:
switch (fc->state) {
case FC_STATE_ONLINE: break;
case FC_STATE_OFFLINE: break;
- default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi));
+ default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL);
break;
}
}
@@ -801,13 +815,15 @@ static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, i
if (!SCpnt->use_sg) {
cmd->fcp_data_len = SCpnt->request_bufflen;
fcmd->data = dma_map_single (fc->dev, (char *)SCpnt->request_buffer,
- SCpnt->request_bufflen);
+ SCpnt->request_bufflen,
+ scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
} else {
struct scatterlist *sg = (struct scatterlist *)SCpnt->buffer;
int nents;
FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length))
- nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg);
+ nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg,
+ scsi_to_fc_dma_dir(SCpnt->sc_data_direction));
if (nents > 1) printk ("%s: SG for nents %d (use_sg %d) not handled yet\n", fc->name, nents, SCpnt->use_sg);
fcmd->data = sg_dma_address(sg);
cmd->fcp_data_len = sg_dma_len(sg);
@@ -1048,7 +1064,7 @@ static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len)
FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
fch->param = 0;
- fcmd->cmd = dma_map_single (fc->dev, data, 2 * len);
+ fcmd->cmd = dma_map_single (fc->dev, data, 2 * len, FC_DMA_BIDIRECTIONAL);
fcmd->rsp = fcmd->cmd + len;
fcmd->cmdlen = len;
fcmd->rsplen = len;
@@ -1083,7 +1099,7 @@ static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len)
clear_bit(fcmd->token, fc->scsi_bitmap);
fc->scsi_free++;
- dma_unmap_single (fc->dev, fcmd->cmd, 2 * len);
+ dma_unmap_single (fc->dev, fcmd->cmd, 2 * len, FC_DMA_BIDIRECTIONAL);
return l.status;
}
diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c
index a0cab3015..8afad596f 100644
--- a/drivers/i2o/i2o_block.c
+++ b/drivers/i2o/i2o_block.c
@@ -461,7 +461,7 @@ static void i2ob_request(request_queue_t * q)
struct i2ob_device *dev;
u32 m;
- while (CURRENT) {
+ while (!QUEUE_EMPTY) {
/*
* On an IRQ completion if there is an inactive
* request on the queue head it means it isnt yet
@@ -515,8 +515,7 @@ static void i2ob_request(request_queue_t * q)
}
}
req->errors = 0;
- CURRENT = CURRENT->next;
- req->next = NULL;
+ blkdev_dequeue_request(req);
req->sem = NULL;
ireq = i2ob_qhead;
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 1ac6a9595..9a9951204 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -23,31 +23,6 @@
static struct hpsb_host_template *templates = NULL;
spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * The following function is exported for module usage. It will
- * be called from high-level drivers such as the raw driver.
- */
-int hpsb_get_host_list(struct hpsb_host *list[], int list_size)
-{
- struct hpsb_host *host, **ptr;
- struct hpsb_host_template *tmpl;
- int count=0;
-
- ptr = list;
-
- for (tmpl = templates ; tmpl != NULL; tmpl = tmpl->next) {
- for (host = tmpl->hosts; (host != NULL) && (count < list_size);
- host = host->next) {
- *ptr = host;
- ptr++;
- count++;
- }
- }
-
- return count;
-}
-
/*
* This function calls the add_host/remove_host hooks for every host currently
* registered. Init == TRUE means add_host.
@@ -131,7 +106,7 @@ struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl,
h->timeout_tq.data = h;
h->topology_map = h->csr.topology_map + 3;
- h->speed_map = h->csr.speed_map + 2;
+ h->speed_map = (u8 *)(h->csr.speed_map + 2);
h->template = tmpl;
if (hd_size) {
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index d516e7f8c..3465f27d7 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -27,7 +27,8 @@ struct hpsb_host {
wait_queue_head_t tlabel_wait;
int reset_retries;
- quadlet_t *topology_map, *speed_map;
+ quadlet_t *topology_map;
+ u8 *speed_map;
struct csr_control csr;
unsigned char iso_listen_count[64];
@@ -174,14 +175,6 @@ struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl,
size_t hostdata_size);
/*
- * Write pointers to all available hpsb_hosts into list.
- * Return number of host adapters (i.e. elements in list).
- *
- * DEPRECATED - register with highlevel instead.
- */
-int hpsb_get_host_list(struct hpsb_host *list[], int max_list_size);
-
-/*
* Increase / decrease host usage counter. Increase function will return true
* only if successful (host still existed). Decrease function expects host to
* exist.
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index eccbe8933..771189f0b 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -4,7 +4,7 @@
* Core support: hpsb_packet management, packet handling and forwarding to
* csr or lowlevel code
*
- * Copyright (C) 1999 Andreas E. Bombe
+ * Copyright (C) 1999, 2000 Andreas E. Bombe
*/
#include <linux/kernel.h>
@@ -191,6 +191,74 @@ static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
return nodeid + 1;
}
+static void build_speed_map(struct hpsb_host *host, int nodecount)
+{
+ char speedcap[nodecount];
+ char cldcnt[nodecount];
+ u8 *map = host->speed_map;
+ quadlet_t *sidp;
+ int i, j, n;
+
+ for (i = 0; i < (nodecount * 64); i += 64) {
+ for (j = 0; j < nodecount; j++) {
+ map[i+j] = SPEED_400;
+ }
+ }
+
+ for (i = 0; i < nodecount; i++) {
+ cldcnt[i] = 0;
+ }
+
+ /* find direct children count and speed */
+ for (sidp = &host->topology_map[host->selfid_count-1],
+ n = nodecount - 1;
+ sidp >= host->topology_map; sidp--) {
+ if (*sidp & 0x00800000 /* extended */) {
+ for (i = 2; i < 18; i += 2) {
+ if ((*sidp & (0x3 << i)) == (0x3 << i)) {
+ cldcnt[n]++;
+ }
+ }
+ } else {
+ for (i = 2; i < 8; i += 2) {
+ if ((*sidp & (0x3 << i)) == (0x3 << i)) {
+ cldcnt[n]++;
+ }
+ }
+ speedcap[n] = (*sidp >> 14) & 0x3;
+ n--;
+ }
+ }
+
+ /* set self mapping */
+ for (i = nodecount - 1; i; i--) {
+ map[64*i + i] = speedcap[i];
+ }
+
+ /* fix up direct children count to total children count;
+ * also fix up speedcaps for sibling and parent communication */
+ for (i = 1; i < nodecount; i++) {
+ for (j = cldcnt[i], n = i - 1; j > 0; j--) {
+ cldcnt[i] += cldcnt[n];
+ speedcap[n] = MIN(speedcap[n], speedcap[i]);
+ n -= cldcnt[n] + 1;
+ }
+ }
+
+ for (n = 0; n < nodecount; n++) {
+ for (i = n - cldcnt[n]; i <= n; i++) {
+ for (j = 0; j < (n - cldcnt[n]); j++) {
+ map[j*64 + i] = map[i*64 + j] =
+ MIN(map[i*64 + j], speedcap[n]);
+ }
+ for (j = n + 1; j < nodecount; j++) {
+ map[j*64 + i] = map[i*64 + j] =
+ MIN(map[i*64 + j], speedcap[n]);
+ }
+ }
+ }
+}
+
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{
if (host->in_bus_reset) {
@@ -204,8 +272,6 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
{
-
-
host->node_id = 0xffc0 | phyid;
host->in_bus_reset = 0;
host->is_root = isroot;
@@ -219,9 +285,11 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
return;
} else {
HPSB_NOTICE("stopping out-of-control reset loop");
- HPSB_NOTICE("warning - topology map will therefore not "
- "be valid");
+ HPSB_NOTICE("warning - topology map and speed map will "
+ "therefore not be valid");
}
+ } else {
+ build_speed_map(host, host->node_count);
}
/* irm_id is kept up to date by check_selfids() */
@@ -275,8 +343,22 @@ int hpsb_send_packet(struct hpsb_packet *packet)
}
packet->state = queued;
+ packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64
+ + (packet->node_id & NODE_MASK)];
- dump_packet("send packet:", packet->header, packet->header_size);
+ switch (packet->speed_code) {
+ case 2:
+ dump_packet("send packet 400:", packet->header,
+ packet->header_size);
+ break;
+ case 1:
+ dump_packet("send packet 200:", packet->header,
+ packet->header_size);
+ break;
+ default:
+ dump_packet("send packet 100:", packet->header,
+ packet->header_size);
+ }
return host->template->transmit_packet(host, packet);
}
diff --git a/drivers/ieee1394/ieee1394_syms.c b/drivers/ieee1394/ieee1394_syms.c
index ee4bde182..3a99b0923 100644
--- a/drivers/ieee1394/ieee1394_syms.c
+++ b/drivers/ieee1394/ieee1394_syms.c
@@ -19,7 +19,6 @@
EXPORT_SYMBOL(hpsb_register_lowlevel);
EXPORT_SYMBOL(hpsb_unregister_lowlevel);
EXPORT_SYMBOL(hpsb_get_host);
-EXPORT_SYMBOL(hpsb_get_host_list);
EXPORT_SYMBOL(hpsb_inc_host_usage);
EXPORT_SYMBOL(hpsb_dec_host_usage);
@@ -53,8 +52,3 @@ EXPORT_SYMBOL(highlevel_read);
EXPORT_SYMBOL(highlevel_write);
EXPORT_SYMBOL(highlevel_lock);
EXPORT_SYMBOL(highlevel_lock64);
-
-/*
-EXPORT_SYMBOL(hpsb_dispatch_event);
-EXPORT_SYMBOL(hpsb_reg_event_handler);
-*/
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 4da40f6c4..b8fae7ee2 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -18,6 +18,28 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+/*
+ * Things known to be working:
+ * . Async Request Transmit
+ * . Async Response Receive
+ * . Async Request Receive
+ * . Async Response Transmit
+ * . Iso Receive
+ *
+ * Things not implemented:
+ * . Iso Transmit
+ * . DMA to user's space in iso receive mode
+ * . DMA error recovery
+ *
+ * Things to be fixed:
+ * . Config ROM
+ *
+ * Known bugs:
+ * . Self-id are not received properly if card
+ * is initialized with no other nodes on the
+ * bus.
+ */
+
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -35,12 +57,31 @@
#include <linux/proc_fs.h>
#include <linux/tqueue.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "hosts.h"
#include "ieee1394_core.h"
#include "ohci1394.h"
+#ifdef DBGMSG
+#undef DBGMSG
+#endif
+
+#if OHCI1394_DEBUG
+#define DBGMSG(card, fmt, args...) \
+printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args)
+#else
+#define DBGMSG(card, fmt, args...)
+#endif
+
/* print general (card independent) information */
#define PRINT_G(level, fmt, args...) \
printk(level "ohci1394: " fmt "\n" , ## args)
@@ -49,11 +90,18 @@ printk(level "ohci1394: " fmt "\n" , ## args)
#define PRINT(level, card, fmt, args...) \
printk(level "ohci1394_%d: " fmt "\n" , card , ## args)
+#define FAIL(fmt, args...) \
+ PRINT_G(KERN_ERR, fmt , ## args); \
+ num_of_cards--; \
+ remove_card(ohci); \
+ return 1;
+
int supported_chips[][2] = {
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
- { -1, -1 }
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
+ { PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 },
+ { -1, -1 }
};
static struct ti_ohci cards[MAX_OHCI1394_CARDS];
@@ -62,6 +110,8 @@ static int num_of_cards = 0;
static int add_card(struct pci_dev *dev);
static void remove_card(struct ti_ohci *ohci);
static int init_driver(void);
+static void dma_trm_bh(void *data);
+static void dma_trm_reset(struct dma_trm_ctx *d);
/***********************************
* IEEE-1394 functionality section *
@@ -87,7 +137,7 @@ static int get_phy_reg(struct ti_ohci *ohci, int addr)
/* wait */
while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
- timeout--;
+ timeout--;
if (!timeout) {
@@ -120,7 +170,7 @@ static int set_phy_reg(struct ti_ohci *ohci, int addr, unsigned char data) {
/* wait */
while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
- timeout--;
+ timeout--;
spin_unlock(&ohci->phy_reg_lock);
@@ -150,31 +200,34 @@ inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
if ((self_id_count&0x80000000) ||
((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) {
PRINT(KERN_ERR, ohci->id,
- "Error in reception of self-id packets");
+ "Error in reception of self-id packets"
+ "Self-id count: %08x q[0]: %08x",
+ self_id_count, q[0]);
return -1;
- }
-
+ }
+
size = ((self_id_count&0x0000EFFC)>>2) - 1;
q++;
while (size > 0) {
if (q[0] == ~q[1]) {
- printk("-%d- selfid packet 0x%x rcvd\n",
- ohci->id, q[0]);
+ PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd",
+ q[0]);
hpsb_selfid_received(host, q[0]);
if (((q[0]&0x3f000000)>>24)==phyid) {
lsid=q[0];
- printk("This node self-id is 0x%08x\n",lsid);
+ PRINT(KERN_INFO, ohci->id,
+ "This node self-id is 0x%08x", lsid);
}
} else {
- printk("-%d- inconsistent selfid 0x%x/0x%x\n", ohci->id,
- q[0], q[1]);
+ PRINT(KERN_ERR, ohci->id,
+ "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
}
q += 2;
size -= 2;
}
- printk(" calling self-id complete\n");
+ PRINT(KERN_INFO, ohci->id, "calling self-id complete");
hpsb_selfid_complete(host, phyid, isroot);
return 0;
@@ -206,7 +259,7 @@ static int ohci_soft_reset(struct ti_ohci *ohci) {
reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout)
- timeout--;
+ timeout--;
if (!timeout) {
PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!");
return -EFAULT;
@@ -215,6 +268,108 @@ static int ohci_soft_reset(struct ti_ohci *ohci) {
return 0;
}
+static int run_context(struct ti_ohci *ohci, int reg, char *msg)
+{
+ u32 nodeId;
+
+ /* check that the node id is valid */
+ nodeId = reg_read(ohci, OHCI1394_NodeID);
+ if (!(nodeId&0x80000000)) {
+ PRINT(KERN_ERR, ohci->id,
+ "Running dma failed because Node ID not valid");
+ return -1;
+ }
+
+ /* check that the node number != 63 */
+ if ((nodeId&0x3f)==63) {
+ PRINT(KERN_ERR, ohci->id,
+ "Running dma failed because Node ID == 63");
+ return -1;
+ }
+
+ /* Run the dma context */
+ reg_write(ohci, reg, 0x8000);
+
+ if (msg) PRINT(KERN_INFO, ohci->id, "%s", msg);
+
+ return 0;
+}
+
+static void stop_context(struct ti_ohci *ohci, int reg, char *msg)
+{
+ int i=0;
+
+ /* stop the channel program if it's still running */
+ reg_write(ohci, reg, 0x8000);
+
+ /* Wait until it effectively stops */
+ while (reg_read(ohci, reg) & 0x400) {
+ i++;
+ if (i>5000) {
+ PRINT(KERN_ERR, ohci->id,
+ "runaway loop while stopping context...");
+ break;
+ }
+ }
+ if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg);
+}
+
+/* Generate the dma receive prgs and start the context */
+static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d)
+{
+ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+ int i;
+
+ stop_context(ohci, d->ctrlClear, NULL);
+
+ for (i=0; i<d->num_desc; i++) {
+
+ /* end of descriptor list? */
+ if ((i+1) < d->num_desc) {
+ d->prg[i]->control = (0x283C << 16) | d->buf_size;
+ d->prg[i]->branchAddress =
+ (virt_to_bus(d->prg[i+1]) & 0xfffffff0) | 0x1;
+ } else {
+ d->prg[i]->control = (0x283C << 16) | d->buf_size;
+ d->prg[i]->branchAddress =
+ (virt_to_bus(d->prg[0]) & 0xfffffff0);
+ }
+
+ d->prg[i]->address = virt_to_bus(d->buf[i]);
+ d->prg[i]->status = d->buf_size;
+ }
+
+ d->buf_ind = 0;
+ d->buf_offset = 0;
+
+ /* Tell the controller where the first AR program is */
+ reg_write(ohci, d->cmdPtr, virt_to_bus(d->prg[0]) | 0x1);
+
+ /* Run AR context */
+ reg_write(ohci, d->ctrlSet, 0x00008000);
+
+ PRINT(KERN_INFO, ohci->id, "Receive DMA ctx=%d initialized", d->ctx);
+}
+
+/* Initialize the dma transmit context */
+static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
+{
+ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+
+ /* Stop the context */
+ stop_context(ohci, d->ctrlClear, NULL);
+
+ d->prg_ind = 0;
+ d->sent_ind = 0;
+ d->free_prgs = d->num_desc;
+ d->branchAddrPtr = NULL;
+ d->first = NULL;
+ d->last = NULL;
+
+ PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
+}
+
+/* Global initialization */
static int ohci_initialize(struct hpsb_host *host)
{
struct ti_ohci *ohci=host->hostdata;
@@ -255,109 +410,64 @@ static int ohci_initialize(struct hpsb_host *host)
reg_write(ohci, OHCI1394_ConfigROMmap,
virt_to_bus(ohci->csr_config_rom));
-#if 1 /* Why is this step necessary ? */
/* Write the config ROM header */
- reg_write(ohci, OHCI1394_ConfigROMhdr,0x04040000);
+ reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->csr_config_rom[0]);
/* Set bus options */
- reg_write(ohci, OHCI1394_BusOptions, 0xf064A002);
-#endif
+ reg_write(ohci, OHCI1394_BusOptions, ohci->csr_config_rom[2]);
-#if 1
- /* Accept phy packets into AR request context */
- reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
-#endif
+ /* Write the GUID into the csr config rom */
+ ohci->csr_config_rom[3] = reg_read(ohci, OHCI1394_GUIDHi);
+ ohci->csr_config_rom[4] = reg_read(ohci, OHCI1394_GUIDLo);
+
+ /* Don't accept phy packets into AR request context */
+ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
/* Initialize IR dma */
+ for (i=0;i<4;i++) { /* FIXME : how many contexts are available ? */
+ reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i,
+ 0xffffffff);
+ reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0);
+ reg_write(ohci, OHCI1394_IrRcvCommandPtr+32*i, 0);
+ }
- /* make sure the context isn't running, dead, or active */
- if (!(reg_read(ohci, OHCI1394_IrRcvContextControlSet) & 0x00008F00)) {
-
- /* initialize IR program */
- for (i= 0; i < IR_NUM_DESC; i++) {
-
- /* end of descriptor list? */
- if ((i + 1) < IR_NUM_DESC) {
- ohci->IR_recv_prg[i]->control=
- (0x283C << 16) | IR_RECV_BUF_SIZE;
- ohci->IR_recv_prg[i]->branchAddress=
- (virt_to_bus(ohci->IR_recv_prg[i + 1])
- & 0xfffffff0) | 0x1;
- } else {
- ohci->IR_recv_prg[i]->control=
- (0x283C << 16) | IR_RECV_BUF_SIZE;
- ohci->IR_recv_prg[i]->branchAddress=
- (virt_to_bus(ohci->IR_recv_prg[0])
- & 0xfffffff0) | 0x1;
- }
-
- ohci->IR_recv_prg[i]->address=
- virt_to_bus(ohci->IR_recv_buf[i]);
- ohci->IR_recv_prg[i]->status= IR_RECV_BUF_SIZE;
- }
-
- /* Tell the controller where the first IR program is */
- reg_write(ohci, OHCI1394_IrRcvCommandPtr,
- virt_to_bus(ohci->IR_recv_prg[0]) | 0x1 );
-
- /* Set bufferFill, isochHeader, multichannel for IR context */
- reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000);
+ /* Set bufferFill, isochHeader, multichannel for IR context */
+ reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000);
+
+ /* Set the context match register to match on all tags */
+ reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000);
- /* Set the context match register to match on all tags */
- reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000);
+ /* Clear the multi channel mask high and low registers */
+ reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
+ reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
- /* Clear the multi channel mask high and low registers */
- reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
+ /* Clear the interrupt mask */
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- /* Set up isoRecvIntMask to generate interrupts for context 0
- (thanks to Michael Greger for seeing that I forgot this) */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);
+ /* Set up isoRecvIntMask to generate interrupts for context 0
+ (thanks to Michael Greger for seeing that I forgot this) */
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);
- /* Run IR context */
- reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0x00008000);
- }
+ initialize_dma_rcv_ctx(ohci->ir_context);
/* Initialize AR dma */
- /* make sure the context isn't running, dead, or active */
- if (!(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x00008F00)) {
-
- /* initialize AR program */
- for (i= 0; i < AR_RESP_NUM_DESC; i++) {
-
- /* end of descriptor list? */
- if ((i + 1) < AR_RESP_NUM_DESC) {
- ohci->AR_resp_prg[i]->control=
- (0x283C << 16) | AR_RESP_BUF_SIZE;
- ohci->AR_resp_prg[i]->branchAddress=
- (virt_to_bus(ohci->AR_resp_prg[i + 1])
- & 0xfffffff0) | 0x1;
- } else {
- ohci->AR_resp_prg[i]->control=
- (0x283C << 16) | AR_RESP_BUF_SIZE;
- ohci->AR_resp_prg[i]->branchAddress=
- (virt_to_bus(ohci->AR_resp_prg[0])
- & 0xfffffff0) | 0x1;
- }
-
- ohci->AR_resp_prg[i]->address=
- virt_to_bus(ohci->AR_resp_buf[i]);
- ohci->AR_resp_prg[i]->status= AR_RESP_BUF_SIZE;
- }
+ initialize_dma_rcv_ctx(ohci->ar_req_context);
+ initialize_dma_rcv_ctx(ohci->ar_resp_context);
- /* Tell the controller where the first AR program is */
- reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
- virt_to_bus(ohci->AR_resp_prg[0]) | 0x1 );
+ /* Initialize AT dma */
+ initialize_dma_trm_ctx(ohci->at_req_context);
+ initialize_dma_trm_ctx(ohci->at_resp_context);
- /* Accept phy packets into AR request context */
- reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
-
- /* Run AR context */
- reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
- }
+ /*
+ * Accept AT requests from all nodes. This probably
+ * will have to be controlled from the subsystem
+ * on a per node basis.
+ * (Tip by Emilie Chung <emilie.chung@axis.com>)
+ */
+ reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
/* Specify AT retries */
reg_write(ohci, OHCI1394_ATRetries,
@@ -384,7 +494,7 @@ static int ohci_initialize(struct hpsb_host *host)
OHCI1394_respTxComplete |
OHCI1394_reqTxComplete |
OHCI1394_isochRx
- );
+ );
return 1;
}
@@ -399,126 +509,144 @@ static void ohci_remove(struct hpsb_host *host)
}
}
-
-/* This must be called with the async_queue_lock held. */
-static void send_next_async(struct ti_ohci *ohci)
+/* Insert a packet in the AT DMA fifo and generate the DMA prg */
+static void insert_packet(struct ti_ohci *ohci,
+ struct dma_trm_ctx *d, struct hpsb_packet *packet)
{
- int i=0;
- struct hpsb_packet *packet = ohci->async_queue;
- struct dma_cmd prg;
-#if 0
- quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg;
-#endif
- //HPSB_TRACE();
-
- /* stop the channel program if it's still running */
- reg_write(ohci, OHCI1394_AsReqTrContextControlClear, 0x8000);
-
- /* Wait until it effectively stops */
- while (reg_read(ohci, OHCI1394_AsReqTrContextControlSet)
- & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR, ohci->id,
- "runaway loop in DmaAT. bailing out...");
- break;
- }
- };
-
- if (packet->type == async)
- {
-
- /* re-format packet header according to ohci specification */
- packet->header[1] = (packet->header[1] & 0xFFFF) |
- (packet->header[0] & 0xFFFF0000);
- packet->header[0] = DMA_SPEED_200 |
- (packet->header[0] & 0xFFFF);
-
- if (packet->data_size) { /* block transmit */
- prg.control = OUTPUT_MORE_IMMEDIATE | 0x10;
- prg.address = 0;
- prg.branchAddress = 0;
- prg.status = 0;
- memcpy(ohci->AT_req_prg, &prg, 16);
- memcpy(ohci->AT_req_prg + 1, packet->header, 16);
- prg.control = OUTPUT_LAST | packet->data_size;
- prg.address = virt_to_bus(packet->data);
- memcpy(ohci->AT_req_prg + 2, &prg, 16);
-
- reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
- virt_to_bus(ohci->AT_req_prg)|0x3);
- }
- else { /* quadlet transmit */
- prg.control = OUTPUT_LAST_IMMEDIATE |
- packet->header_size;
- prg.address = 0;
- prg.branchAddress = 0;
- prg.status = 0;
- memcpy(ohci->AT_req_prg, &prg, 16);
- memcpy(ohci->AT_req_prg + 1, packet->header, 16);
-#if 0
- PRINT(KERN_INFO, ohci->id,
- "dma_cmd: %08x %08x %08x %08x",
- *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
- PRINT(KERN_INFO, ohci->id,
- "header: %08x %08x %08x %08x",
- *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7));
-#endif
- reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
- virt_to_bus(ohci->AT_req_prg)|0x2);
- }
-
- }
- else if (packet->type == raw)
- {
- prg.control = OUTPUT_LAST | packet->data_size;
- prg.address = virt_to_bus(packet->data);
- prg.branchAddress = 0;
- prg.status = 0;
- memcpy(ohci->AT_req_prg, &prg, 16);
-#if 0
- PRINT(KERN_INFO, ohci->id,
- "dma_cmd: %08x %08x %08x %08x",
- *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
-#endif
- reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
- virt_to_bus(ohci->AT_req_prg)|0x2);
- }
+ u32 cycleTimer;
+ int idx = d->prg_ind;
+
+ d->prg[idx].begin.address = 0;
+ d->prg[idx].begin.branchAddress = 0;
+ if (d->ctx==1) {
+ /*
+ * For response packets, we need to put a timeout value in
+ * the 16 lower bits of the status... let's try 1 sec timeout
+ */
+ cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ d->prg[idx].begin.status =
+ (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
+ ((cycleTimer&0x01fff000)>>12);
+
+ DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x",
+ cycleTimer, d->prg[idx].begin.status);
+ }
+ else
+ d->prg[idx].begin.status = 0;
+
+ d->prg[idx].data[0] = packet->speed_code<<16 |
+ (packet->header[0] & 0xFFFF);
+ d->prg[idx].data[1] = (packet->header[1] & 0xFFFF) |
+ (packet->header[0] & 0xFFFF0000);
+ d->prg[idx].data[2] = packet->header[2];
+ d->prg[idx].data[3] = packet->header[3];
+
+ if (packet->data_size) { /* block transmit */
+ d->prg[idx].begin.control = OUTPUT_MORE_IMMEDIATE | 0x10;
+ d->prg[idx].end.control = OUTPUT_LAST | packet->data_size;
+ d->prg[idx].end.address = virt_to_bus(packet->data);
+ d->prg[idx].end.branchAddress = 0;
+ d->prg[idx].end.status = 0x4000;
+ if (d->branchAddrPtr)
+ *(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x3;
+ d->branchAddrPtr = &(d->prg[idx].end.branchAddress);
+ }
+ else { /* quadlet transmit */
+ d->prg[idx].begin.control =
+ OUTPUT_LAST_IMMEDIATE | packet->header_size;
+ if (d->branchAddrPtr)
+ *(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x2;
+ d->branchAddrPtr = &(d->prg[idx].begin.branchAddress);
+ }
+ d->free_prgs--;
- /* run program */
- reg_write(ohci, OHCI1394_AsReqTrContextControlSet, 0x00008000);
+ /* queue the packet in the appropriate context queue */
+ if (d->last) {
+ d->last->xnext = packet;
+ d->last = packet;
+ }
+ else {
+ d->first = packet;
+ d->last = packet;
+ }
}
static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
{
struct ti_ohci *ohci = host->hostdata;
- struct hpsb_packet *p;
- unsigned long flags;
+ struct dma_trm_ctx *d;
+ unsigned char tcode;
+ int i=50;
if (packet->data_size >= 4096) {
PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)",
packet->data_size);
return 0;
}
-
- //HPSB_TRACE();
packet->xnext = NULL;
-
- spin_lock_irqsave(&ohci->async_queue_lock, flags);
- if (ohci->async_queue == NULL) {
- ohci->async_queue = packet;
- send_next_async(ohci);
- } else {
- p = ohci->async_queue;
- while (p->xnext != NULL) {
- p = p->xnext;
+ /* Decide wether we have a request or a response packet */
+ tcode = (packet->header[0]>>4)&0xf;
+ if ((tcode==TCODE_READQ)||
+ (tcode==TCODE_WRITEQ)||
+ (tcode==TCODE_READB)||
+ (tcode==TCODE_WRITEB)||
+ (tcode==TCODE_LOCK_REQUEST))
+ d = ohci->at_req_context;
+
+ else if ((tcode==TCODE_WRITE_RESPONSE)||
+ (tcode==TCODE_READQ_RESPONSE)||
+ (tcode==TCODE_READB_RESPONSE)||
+ (tcode==TCODE_LOCK_RESPONSE))
+ d = ohci->at_resp_context;
+
+ else {
+ PRINT(KERN_ERR, ohci->id,
+ "Unexpected packet tcode=%d in AT DMA", tcode);
+ return 0;
+ }
+
+ spin_lock(&d->lock);
+
+ if (d->free_prgs<1) {
+ PRINT(KERN_INFO, ohci->id,
+ "AT DMA ctx=%d Running out of prgs... waiting",d->ctx);
+ }
+ while (d->free_prgs<1) {
+ spin_unlock(&d->lock);
+ schedule();
+ if (i-- <0) {
+ stop_context(ohci, d->ctrlClear,
+ "AT DMA runaway loop... bailing out");
+ return 0;
}
-
- p->xnext = packet;
+ spin_lock(&d->lock);
+ }
+
+ insert_packet(ohci, d, packet);
+
+ /* Is the context running ? (should be unless it is
+ the first packet to be sent in this context) */
+ if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
+ DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx);
+ if (packet->data_size)
+ reg_write(ohci, d->cmdPtr,
+ virt_to_bus(&(d->prg[d->prg_ind])) | 0x3);
+ else
+ reg_write(ohci, d->cmdPtr,
+ virt_to_bus(&(d->prg[d->prg_ind])) | 0x2);
+
+ run_context(ohci, d->ctrlSet, NULL);
+ }
+ else {
+ DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx);
+ /* wake up the dma context if necessary */
+ if (!(reg_read(ohci, d->ctrlSet) & 0x400))
+ reg_write(ohci, d->ctrlSet, 0x1000);
}
-
- spin_unlock_irqrestore(&ohci->async_queue_lock, flags);
+
+ d->prg_ind = (d->prg_ind+1)%d->num_desc;
+ spin_unlock(&d->lock);
return 1;
}
@@ -528,31 +656,29 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
struct ti_ohci *ohci = host->hostdata;
int retval = 0;
unsigned long flags;
- struct hpsb_packet *packet, *lastpacket;
- u32 r;
switch (cmd) {
- case RESET_BUS:
+ case RESET_BUS:
PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
(host->attempt_root ? " and attempting to become root"
: ""));
- r = (host->attempt_root) ? 0x000041ff : 0x0000417f;
- reg_write(ohci, OHCI1394_PhyControl, r);
+ reg_write(ohci, OHCI1394_PhyControl,
+ (host->attempt_root) ? 0x000041ff : 0x0000417f);
break;
- case GET_CYCLE_COUNTER:
+ case GET_CYCLE_COUNTER:
retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
break;
- case SET_CYCLE_COUNTER:
+ case SET_CYCLE_COUNTER:
reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
break;
- case SET_BUS_ID:
+ case SET_BUS_ID:
PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err");
break;
- case ACT_CYCLE_MASTER:
+ case ACT_CYCLE_MASTER:
#if 0
if (arg) {
/* enable cycleTimer, cycleMaster, cycleSource */
@@ -564,23 +690,13 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
#endif
break;
- case CANCEL_REQUESTS:
- spin_lock_irqsave(&ohci->async_queue_lock, flags);
- /* stop any chip activity */
- reg_write(ohci, OHCI1394_HCControlClear, 0x00020000);
- packet = ohci->async_queue;
- ohci->async_queue = NULL;
- spin_unlock_irqrestore(&ohci->async_queue_lock, flags);
-
- while (packet != NULL) {
- lastpacket = packet;
- packet = packet->xnext;
- hpsb_packet_sent(host, lastpacket, ACKX_ABORTED);
- }
-
+ case CANCEL_REQUESTS:
+ DBGMSG(ohci->id, "Cancel request received");
+ dma_trm_reset(ohci->at_req_context);
+ dma_trm_reset(ohci->at_resp_context);
break;
- case MODIFY_USAGE:
+ case MODIFY_USAGE:
if (arg) {
MOD_INC_USE_COUNT;
} else {
@@ -588,7 +704,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
}
break;
- case ISO_LISTEN_CHANNEL:
+ case ISO_LISTEN_CHANNEL:
spin_lock_irqsave(&ohci->IR_channel_lock, flags);
@@ -614,7 +730,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
break;
- case ISO_UNLISTEN_CHANNEL:
+ case ISO_UNLISTEN_CHANNEL:
spin_lock_irqsave(&ohci->IR_channel_lock, flags);
@@ -642,7 +758,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
break;
- default:
+ default:
PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet\n",
cmd);
break;
@@ -659,160 +775,118 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
* Global stuff (interrupt handler, init/shutdown code) *
********************************************************/
-static void stop_ar_resp_context(struct ti_ohci *ohci, char *msg)
+static void dma_trm_reset(struct dma_trm_ctx *d)
{
- int i=0;
+ struct ti_ohci *ohci;
- /* stop the channel program if it's still running */
- reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
-
- /* Wait until it effectively stops */
- while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet)
- & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR, ohci->id,
- "runaway loop in Dma Ar Resp. bailing out...");
- break;
- }
+ if (d==NULL) {
+ PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg");
+ return;
+ }
+ ohci = (struct ti_ohci *)(d->ohci);
+ stop_context(ohci, d->ctrlClear, NULL);
+
+ spin_lock(&d->lock);
+
+ /* is there still any packet pending ? */
+ while(d->first) {
+ PRINT(KERN_INFO, ohci->id,
+ "AT dma reset ctx=%d, aborting transmission",
+ d->ctx);
+ hpsb_packet_sent(ohci->host, d->first, ACKX_ABORTED);
+ d->first = d->first->xnext;
}
- PRINT(KERN_ERR, ohci->id, "%s\n async response receive dma stopped\n", msg);
+ d->first = d->last = NULL;
+ d->branchAddrPtr=NULL;
+ d->sent_ind = d->prg_ind;
+ d->free_prgs = d->num_desc;
+ spin_unlock(&d->lock);
}
static void ohci_irq_handler(int irq, void *dev_id,
struct pt_regs *regs_are_unused)
{
- //int i;
- static quadlet_t event,node_id;
+ quadlet_t event,node_id;
struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
struct hpsb_host *host = ohci->host;
int phyid = -1, isroot = 0;
event=reg_read(ohci, OHCI1394_IntEventSet);
- /* Clear the interrupt register */
- reg_write(ohci, OHCI1394_IntEventClear, event);
-
- /* PRINT(KERN_INFO, ohci->id, "int event %08X mask %08X",
- event,reg_read(ohci, OHCI1394_IntMaskSet)); */
-
if (event & OHCI1394_busReset) {
-#if 0
- PRINT(KERN_INFO, ohci->id, "bus reset interrupt");
-#endif
if (!host->in_bus_reset) {
- hpsb_bus_reset(host);
+ PRINT(KERN_INFO, ohci->id, "Bus reset");
+
+ /* Wait for the AT fifo to be flushed */
+ dma_trm_reset(ohci->at_req_context);
+ dma_trm_reset(ohci->at_resp_context);
+
+ /* Subsystem call */
+ hpsb_bus_reset(ohci->host);
+
+ ohci->NumBusResets++;
}
- ohci->NumBusResets++;
}
- if (event & OHCI1394_RQPkt) {
- PRINT(KERN_INFO, ohci->id, "RQPkt int received");
+ /*
+ * Problem: How can I ensure that the AT bottom half will be
+ * executed before the AR bottom half (both events may have
+ * occured within a single irq event)
+ * Quick hack: just launch it within the IRQ handler
+ */
+ if (event & OHCI1394_reqTxComplete) {
+ struct dma_trm_ctx *d = ohci->at_req_context;
+ DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X",
+ reg_read(ohci, d->ctrlSet));
+ if (reg_read(ohci, d->ctrlSet) & 0x800)
+ stop_context(ohci, d->ctrlClear, "reqTxComplete");
+ else
+ dma_trm_bh((void *)d);
+ }
+ if (event & OHCI1394_respTxComplete) {
+ struct dma_trm_ctx *d = ohci->at_resp_context;
+ DBGMSG(ohci->id, "Got respTxComplete interrupt status=0x%08X",
+ reg_read(ohci, d->ctrlSet));
+ if (reg_read(ohci, d->ctrlSet) & 0x800)
+ stop_context(ohci, d->ctrlClear, "respTxComplete");
+ else
+ dma_trm_bh((void *)d);
}
if (event & OHCI1394_RQPkt) {
- PRINT(KERN_INFO, ohci->id, "ControlContext: %08X",
- reg_read(ohci, OHCI1394_AsReqRcvContextControlSet));
+ struct dma_rcv_ctx *d = ohci->ar_req_context;
+ DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",
+ reg_read(ohci, d->ctrlSet));
+ if (reg_read(ohci, d->ctrlSet) & 0x800)
+ stop_context(ohci, d->ctrlClear, "RQPkt");
+ else {
+ queue_task(&d->task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
}
if (event & OHCI1394_RSPkt) {
- unsigned int idx,offset,rescount;
-
- spin_lock(&ohci->AR_resp_lock);
-
- idx = ohci->AR_resp_buf_th_ind;
- offset = ohci->AR_resp_buf_th_offset;
-
- rescount = ohci->AR_resp_prg[idx]->status&0xffff;
- ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE - rescount - offset;
- offset = AR_RESP_BUF_SIZE - rescount;
-
- if (!rescount) { /* We cross a buffer boundary */
- idx = (idx+1) % AR_RESP_NUM_DESC;
-
-#if 0
- /* This bit of code does not work */
- /* Let's see how many bytes were written in the async response
- receive buf since last interrupt. This is done by finding
- the next active context (See OHCI Spec p91) */
- while (ohci->AR_resp_bytes_left <= AR_RESP_TOTAL_BUF_SIZE) {
- if (ohci->AR_resp_prg[idx]->status&0x04000000) break;
- idx = (idx+1) % AR_RESP_NUM_DESC;
- PRINT(KERN_INFO,ohci->id,"crossing more than one buffer boundary !!!");
- ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE;
- }
-#endif
- /* ASSUMPTION: only one buffer boundary is crossed */
- rescount = ohci->AR_resp_prg[idx]->status&0xffff;
- offset = AR_RESP_BUF_SIZE - rescount;
- ohci->AR_resp_bytes_left += offset;
- }
- if (offset==AR_RESP_BUF_SIZE) {
- offset=0;
- idx = (idx+1) % AR_RESP_NUM_DESC;
- }
- ohci->AR_resp_buf_th_ind = idx;
- ohci->AR_resp_buf_th_offset = offset;
-
- /* is buffer processing too slow? (all buffers used) */
- if (ohci->AR_resp_bytes_left > AR_RESP_TOTAL_BUF_SIZE) {
- stop_ar_resp_context(ohci,"async response receive processing too slow");
- spin_unlock(&ohci->AR_resp_lock);
- return;
+ struct dma_rcv_ctx *d = ohci->ar_resp_context;
+ DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",
+ reg_read(ohci, d->ctrlSet));
+ if (reg_read(ohci, d->ctrlSet) & 0x800)
+ stop_context(ohci, d->ctrlClear, "RSPkt");
+ else {
+ queue_task(&d->task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
- spin_unlock(&ohci->AR_resp_lock);
-
- /* queue bottom half in immediate queue */
- queue_task(&ohci->AR_resp_pdl_task, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
}
if (event & OHCI1394_isochRx) {
quadlet_t isoRecvIntEvent;
-
- /* ASSUMPTION: We assume there is only one context for now. */
-
- spin_lock(&ohci->IR_recv_lock);
-
- /* Clear the isoRecvIntEvent register (very important!) */
- isoRecvIntEvent= reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
+ struct dma_rcv_ctx *d = ohci->ir_context;
+ isoRecvIntEvent = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
isoRecvIntEvent);
-
- ohci->IR_buf_used++;
- ohci->IR_buf_next_ind=
- (ohci->IR_buf_next_ind + 1) % IR_NUM_DESC;
-
- /* is buffer processing too slow? (all buffers used) */
- if (ohci->IR_buf_next_ind == ohci->IR_buf_last_ind) {
- int i= 0;
-
- /* stop the context */
- reg_write(ohci,
- OHCI1394_IrRcvContextControlClear, 0x8000);
-
- while (reg_read(ohci, OHCI1394_IrRcvContextControlSet)
- & 0x400) {
- i++;
-
- if (i>5000) {
- PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out...");
- break;
- }
-
- }
-
- spin_unlock(&ohci->IR_recv_lock);
- PRINT(KERN_ERR, ohci->id,
- "iso receive processing too slow... stopped");
- return;
+ DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X",
+ reg_read(ohci, d->ctrlSet));
+ if (reg_read(ohci, d->ctrlSet) & 0x800)
+ stop_context(ohci, d->ctrlClear, "isochRx");
+ else {
+ queue_task(&d->task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
-
- /* reset status field of next descriptor */
- ohci->IR_recv_prg[ohci->IR_buf_next_ind]->status=
- IR_RECV_BUF_SIZE;
-
- spin_unlock(&ohci->IR_recv_lock);
-
- /* queue bottom half in immediate queue */
- queue_task(&ohci->IR_pdl_task, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
}
if (event & OHCI1394_selfIDComplete) {
if (host->in_bus_reset) {
@@ -828,9 +902,13 @@ static void ohci_irq_handler(int irq, void *dev_id,
handle_selfid(ohci, host, phyid, isroot);
}
else
- PRINT(KERN_ERR, ohci->id,
- "SelfID process finished but NodeID"
- " not valid: %08X",node_id);
+ PRINT(KERN_ERR, ohci->id,
+ "SelfID process finished but NodeID"
+ " not valid: %08X",node_id);
+
+ /* Accept Physical requests from all nodes. */
+ reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff);
+ reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff);
}
else PRINT(KERN_INFO, ohci->id,
"phy reg received without reset\n");
@@ -840,316 +918,424 @@ static void ohci_irq_handler(int irq, void *dev_id,
if (host->in_bus_reset) {
PRINT(KERN_INFO, ohci->id, "PhyControl: %08X",
reg_read(ohci, OHCI1394_PhyControl));
- } else printk("-%d- phy reg received without reset\n",
- ohci->id);
+ } else
+ PRINT(KERN_ERR, ohci->id,
+ "phy reg received without reset");
#endif
}
- if (event & OHCI1394_reqTxComplete) {
- /* async packet sent - transmitter ready */
- u32 ack;
- struct hpsb_packet *packet;
-
- if (ohci->async_queue) {
-
- spin_lock(&ohci->async_queue_lock);
-
- ack=reg_read(ohci, OHCI1394_AsReqTrContextControlSet)
- & 0xF;
-
- packet = ohci->async_queue;
- ohci->async_queue = packet->xnext;
-
- if (ohci->async_queue != NULL) {
- send_next_async(ohci);
- }
- spin_unlock(&ohci->async_queue_lock);
-#if 0
- PRINT(KERN_INFO,ohci->id,
- "packet sent with ack code %d",ack);
-#endif
- hpsb_packet_sent(host, packet, ack);
- } else
- PRINT(KERN_INFO,ohci->id,
- "packet sent without async_queue (self-id?)");
- ohci->TxRdy++;
+ /* clear the interrupt event register */
+ reg_write(ohci, OHCI1394_IntEventClear, event);
+}
+
+/* Put the buffer back into the dma context */
+static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
+{
+ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+ DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
+
+ d->prg[idx]->status = d->buf_size;
+ d->prg[idx]->branchAddress &= 0xfffffff0;
+ idx = (idx + d->num_desc - 1 ) % d->num_desc;
+ d->prg[idx]->branchAddress |= 0x1;
+
+ /* wake up the dma context if necessary */
+ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
+ PRINT(KERN_INFO, ohci->id,
+ "Waking dma cxt=%d ... processing is probably too slow",
+ d->ctx);
+ reg_write(ohci, d->ctrlSet, 0x1000);
}
+}
- ohci->NumInterrupts++;
+static int block_length(struct dma_rcv_ctx *d, int idx,
+ quadlet_t *buf_ptr, int offset)
+{
+ int length=0;
+
+ /* Where is the data length ? */
+ if (offset+12>=d->buf_size)
+ length = (d->buf[(idx+1)%d->num_desc]
+ [3-(d->buf_size-offset)/4]>>16);
+ else
+ length = (buf_ptr[3]>>16);
+ if (length % 4) length += 4 - (length % 4);
+ return length;
}
+static int packet_length(struct dma_rcv_ctx *d, int idx,
+ quadlet_t *buf_ptr, int offset)
+{
+ unsigned char tcode;
+ int length;
+
+ /* Let's see what kind of packet is in there */
+ tcode = (buf_ptr[0]>>4)&0xf;
+
+ if (d->ctx==0) { /* Async Receive Request */
+ if (tcode==TCODE_READQ) return 16;
+ else if (tcode==TCODE_WRITEQ ||
+ tcode==TCODE_READB) return 20;
+ else if (tcode==TCODE_WRITEB ||
+ tcode==TCODE_LOCK_REQUEST) {
+ return block_length(d, idx, buf_ptr, offset) + 20;
+ }
+ else if (tcode==0xE) { /* Phy packet */
+ return 16;
+ }
+ else return -1;
+ }
+ else if (d->ctx==1) { /* Async Receive Response */
+ if (tcode==TCODE_WRITE_RESPONSE) return 16;
+ else if (tcode==TCODE_READQ_RESPONSE) return 20;
+ else if (tcode==TCODE_READB_RESPONSE ||
+ tcode==TCODE_LOCK_RESPONSE) {
+ return block_length(d, idx, buf_ptr, offset) + 20;
+ }
+ else return -1;
+ }
+ else if (d->ctx==2) { /* Iso receive */
+ /* Assumption: buffer fill mode with header/trailer */
+ length = (buf_ptr[0]>>16);
+ if (length % 4) length += 4 - (length % 4);
+ return length+8;
+ }
+ return -1;
+}
-/* This is the bottom half that processes async response receive descriptor buffers. */
-static void ohci_ar_resp_proc_desc(void *data)
+/* Bottom half that processes dma receive buffers */
+static void dma_rcv_bh(void *data)
{
+ struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
+ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+ unsigned int split_left, idx, offset, rescount;
+ unsigned char tcode;
+ int length, bytes_left;
quadlet_t *buf_ptr;
char *split_ptr;
- unsigned int split_left;
- struct ti_ohci *ohci= (struct ti_ohci*)data;
- unsigned int packet_length;
- unsigned int idx,offset,tcode;
- unsigned long flags;
char msg[256];
- spin_lock_irqsave(&ohci->AR_resp_lock, flags);
+ spin_lock(&d->lock);
- idx = ohci->AR_resp_buf_bh_ind;
- offset = ohci->AR_resp_buf_bh_offset;
+ idx = d->buf_ind;
+ offset = d->buf_offset;
+ buf_ptr = d->buf[idx] + offset/4;
- buf_ptr = ohci->AR_resp_buf[idx];
- buf_ptr += offset/4;
+ rescount = d->prg[idx]->status&0xffff;
+ bytes_left = d->buf_size - rescount - offset;
- while(ohci->AR_resp_bytes_left > 0) {
-
- /* check to see if a fatal error occurred */
- if ((ohci->AR_resp_prg[idx]->status >> 16) & 0x800) {
- sprintf(msg,"fatal async response receive error -- status is %d",
- ohci->AR_resp_prg[idx]->status & 0x1F);
- stop_ar_resp_context(ohci, msg);
- spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
- return;
- }
-
- spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
-
- /* Let's see what kind of packet is in there */
+ while (bytes_left>0) {
tcode = (buf_ptr[0]>>4)&0xf;
- if (tcode==2) /* no-data receive */
- packet_length=16;
- else if (tcode==6) /* quadlet receive */
- packet_length=20;
- else if (tcode==7) { /* block receive */
- /* Where is the data length ? */
- if (offset+12>=AR_RESP_BUF_SIZE)
- packet_length=(ohci->AR_resp_buf[(idx+1)%AR_RESP_NUM_DESC]
- [3-(AR_RESP_BUF_SIZE-offset)/4]>>16)+20;
- else
- packet_length=(buf_ptr[3]>>16)+20;
- if (packet_length % 4)
- packet_length += 4 - (packet_length % 4);
- }
- else /* something is wrong */ {
- sprintf(msg,"unexpected packet tcode %d in async response receive buffer",tcode);
- stop_ar_resp_context(ohci,msg);
+ length = packet_length(d, idx, buf_ptr, offset);
+
+ if (length<4) { /* something is wrong */
+ sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d",
+ tcode, d->ctx);
+ stop_context(ohci, d->ctrlClear, msg);
+ spin_unlock(&d->lock);
return;
}
- if ((offset+packet_length)>AR_RESP_BUF_SIZE) {
- /* we have a split packet */
- if (packet_length>AR_RESP_SPLIT_PACKET_BUF_SIZE) {
- sprintf(msg,"packet size %d bytes exceed split packet buffer size %d bytes",
- packet_length,AR_RESP_SPLIT_PACKET_BUF_SIZE);
- stop_ar_resp_context(ohci, msg);
+
+ if ((offset+length)>d->buf_size) { /* Split packet */
+ if (length>d->split_buf_size) {
+ stop_context(ohci, d->ctrlClear,
+ "split packet size exceeded");
+ d->buf_ind = idx;
+ d->buf_offset = offset;
+ spin_unlock(&d->lock);
return;
}
- split_left = packet_length;
- split_ptr = (char *)ohci->AR_resp_spb;
- while (split_left>0) {
- memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE-offset);
- split_left -= AR_RESP_BUF_SIZE-offset;
- split_ptr += AR_RESP_BUF_SIZE-offset;
- ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
- idx = (idx+1) % AR_RESP_NUM_DESC;
- buf_ptr = ohci->AR_resp_buf[idx];
- offset=0;
- while (split_left >= AR_RESP_BUF_SIZE) {
- memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE);
- split_ptr += AR_RESP_BUF_SIZE;
- split_left -= AR_RESP_BUF_SIZE;
- ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
- idx = (idx+1) % AR_RESP_NUM_DESC;
- buf_ptr = ohci->AR_resp_buf[idx];
- }
- if (split_left>0) {
- memcpy(split_ptr,buf_ptr,split_left);
- offset = split_left;
- split_left=0;
- buf_ptr += split_left/4;
- }
+ if (d->prg[(idx+1)%d->num_desc]->status==d->buf_size) {
+ /* other part of packet not written yet */
+ /* this should never happen I think */
+ /* anyway we'll get it on the next call */
+ PRINT(KERN_INFO, ohci->id,
+ "Got only half a packet !!!");
+ d->buf_ind = idx;
+ d->buf_offset = offset;
+ spin_unlock(&d->lock);
+ return;
}
-#if 0
- PRINT(KERN_INFO,ohci->id,"AR resp: received split packet tcode=%d length=%d",
- tcode,packet_length);
-#endif
- hpsb_packet_received(ohci->host, ohci->AR_resp_spb, packet_length);
- ohci->AR_resp_bytes_left -= packet_length;
+ split_left = length;
+ split_ptr = (char *)d->spb;
+ memcpy(split_ptr,buf_ptr,d->buf_size-offset);
+ split_left -= d->buf_size-offset;
+ split_ptr += d->buf_size-offset;
+ insert_dma_buffer(d, idx);
+ idx = (idx+1) % d->num_desc;
+ buf_ptr = d->buf[idx];
+ offset=0;
+ while (split_left >= d->buf_size) {
+ memcpy(split_ptr,buf_ptr,d->buf_size);
+ split_ptr += d->buf_size;
+ split_left -= d->buf_size;
+ insert_dma_buffer(d, idx);
+ idx = (idx+1) % d->num_desc;
+ buf_ptr = d->buf[idx];
+ }
+ if (split_left>0) {
+ memcpy(split_ptr, buf_ptr, split_left);
+ offset = split_left;
+ buf_ptr += offset/4;
+ }
+
+ /*
+ * We get one phy packet for each bus reset.
+ * we know that from now on the bus topology may
+ * have changed. Just ignore it for the moment
+ */
+ if (tcode != 0xE) {
+ DBGMSG(ohci->id, "Split packet received from"
+ " node %d ack=0x%02X spd=%d tcode=0x%X"
+ " length=%d data=0x%08x ctx=%d",
+ (d->spb[1]>>16)&0x3f,
+ (d->spb[length/4-1]>>16)&0x1f,
+ (d->spb[length/4-1]>>21)&0x3,
+ tcode, length, d->spb[3], d->ctx);
+ hpsb_packet_received(ohci->host, d->spb,
+ length);
+ }
+ else
+ PRINT(KERN_INFO, ohci->id,
+ "Got phy packet ctx=%d ... discarded",
+ d->ctx);
}
else {
-#if 0
- PRINT(KERN_INFO,ohci->id,"AR resp: received packet tcode=%d length=%d",
- tcode,packet_length);
-#endif
- hpsb_packet_received(ohci->host, buf_ptr, packet_length);
- offset += packet_length;
- buf_ptr += packet_length/4;
- ohci->AR_resp_bytes_left -= packet_length;
- if (offset==AR_RESP_BUF_SIZE) {
- ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
- idx = (idx+1) % AR_RESP_NUM_DESC;
- buf_ptr = ohci->AR_resp_buf[idx];
+ /*
+ * We get one phy packet for each bus reset.
+ * we know that from now on the bus topology may
+ * have changed. Just ignore it for the moment
+ */
+ if (tcode != 0xE) {
+ DBGMSG(ohci->id, "Packet received from node"
+ " %d ack=0x%02X spd=%d tcode=0x%X"
+ " length=%d data=0x%08x ctx=%d",
+ (buf_ptr[1]>>16)&0x3f,
+ (buf_ptr[length/4-1]>>16)&0x1f,
+ (buf_ptr[length/4-1]>>21)&0x3,
+ tcode, length, buf_ptr[3], d->ctx);
+ hpsb_packet_received(ohci->host, buf_ptr,
+ length);
+ }
+ else
+ PRINT(KERN_INFO, ohci->id,
+ "Got phy packet ctx=%d ... discarded",
+ d->ctx);
+ offset += length;
+ buf_ptr += length/4;
+ if (offset==d->buf_size) {
+ insert_dma_buffer(d, idx);
+ idx = (idx+1) % d->num_desc;
+ buf_ptr = d->buf[idx];
offset=0;
}
}
-
+ rescount = d->prg[idx]->status & 0xffff;
+ bytes_left = d->buf_size - rescount - offset;
+
}
+
+ d->buf_ind = idx;
+ d->buf_offset = offset;
+
+ spin_unlock(&d->lock);
+}
+
+/* Bottom half that processes sent packets */
+static void dma_trm_bh(void *data)
+{
+ struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
+ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
+ struct hpsb_packet *packet;
+ u32 ack;
+
+ spin_lock(&d->lock);
+
+ if (d->first==NULL) {
+ stop_context(ohci, d->ctrlClear,
+ "Packet sent ack received but queue is empty");
+ spin_unlock(&d->lock);
+ return;
+ }
+ packet = d->first;
+ d->first = d->first->xnext;
+ if (d->first==NULL) d->last=NULL;
+ if (packet->data_size)
+ ack = d->prg[d->sent_ind].end.status>>16;
+ else
+ ack = d->prg[d->sent_ind].begin.status>>16;
+ d->sent_ind = (d->sent_ind+1)%d->num_desc;
+ d->free_prgs++;
+ spin_unlock(&d->lock);
- if (ohci->AR_resp_bytes_left<0)
- stop_ar_resp_context(ohci, "Sync problem in AR resp dma buffer");
+ DBGMSG(ohci->id, "Packet sent to node %d ack=0x%X spd=%d ctx=%d",
+ (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, d->ctx);
+ hpsb_packet_sent(ohci->host, packet, ack&0xf);
+}
+
+static int free_dma_rcv_ctx(struct dma_rcv_ctx *d)
+{
+ int i;
- ohci->AR_resp_buf_bh_ind = idx;
- ohci->AR_resp_buf_bh_offset = offset;
+ if (d==NULL) return -1;
- spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+ if (d->buf) {
+ for (i=0; i<d->num_desc; i++)
+ if (d->buf[i]) kfree(d->buf[i]);
+ kfree(d->buf);
+ }
+ if (d->prg) {
+ for (i=0; i<d->num_desc; i++)
+ if (d->prg[i]) kfree(d->prg[i]);
+ kfree(d->prg);
+ }
+ if (d->spb) kfree(d->spb);
+
+ kfree(d);
+
+ return 0;
}
-/* This is the bottom half that processes iso receive descriptor buffers. */
-static void ohci_ir_proc_desc(void *data)
+static struct dma_rcv_ctx *
+alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
+ int buf_size, int split_buf_size,
+ int ctrlSet, int ctrlClear, int cmdPtr)
{
- quadlet_t *buf_ptr;
- struct ti_ohci *ohci= (struct ti_ohci*)data;
- int bytes_left, data_length;
- unsigned int idx;
- unsigned long flags;
+ struct dma_rcv_ctx *d=NULL;
+ int i;
- spin_lock_irqsave(&ohci->IR_recv_lock, flags);
+ d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx),
+ GFP_KERNEL);
- while(ohci->IR_buf_used > 0)
- {
- idx= ohci->IR_buf_last_ind;
+ if (d==NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate dma_rcv_ctx");
+ return NULL;
+ }
- /* check to see if a fatal error occurred */
- if ((ohci->IR_recv_prg[idx]->status >> 16) & 0x800) {
- int i= 0;
+ d->ohci = (void *)ohci;
+ d->ctx = ctx;
- /* stop the context */
- reg_write(ohci, OHCI1394_IrRcvContextControlClear,
- 0x8000);
+ d->num_desc = num_desc;
+ d->buf_size = buf_size;
+ d->split_buf_size = split_buf_size;
+ d->ctrlSet = ctrlSet;
+ d->ctrlClear = ctrlClear;
+ d->cmdPtr = cmdPtr;
- while (reg_read(ohci, OHCI1394_IrRcvContextControlSet)
- & 0x400) {
- i++;
+ d->buf = NULL;
+ d->prg = NULL;
+ d->spb = NULL;
- if (i > 5000) {
- PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out...");
- break;
- }
+ d->buf = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
- }
+ if (d->buf == NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer");
+ free_dma_rcv_ctx(d);
+ return NULL;
+ }
+ memset(d->buf, 0, d->num_desc * sizeof(quadlet_t*));
- spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
- PRINT(KERN_ERR, ohci->id,
- "fatal iso receive error -- status is %d",
- ohci->IR_recv_prg[idx]->status & 0x1F);
- return;
- }
+ d->prg = kmalloc(d->num_desc * sizeof(struct dma_cmd*), GFP_KERNEL);
- spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
+ if (d->prg == NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg");
+ free_dma_rcv_ctx(d);
+ return NULL;
+ }
+ memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd*));
- buf_ptr= bus_to_virt(ohci->IR_recv_prg[idx]->address);
- bytes_left= IR_RECV_BUF_SIZE;
+ d->spb = kmalloc(d->split_buf_size, GFP_KERNEL);
- /* are we processing a split packet from last buffer */
- if (ohci->IR_sp_bytes_left) {
+ if (d->spb == NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate split buffer");
+ free_dma_rcv_ctx(d);
+ return NULL;
+ }
- if (!ohci->IR_spb_bytes_used) {
- /* packet is in process of being dropped */
- if (ohci->IR_sp_bytes_left > bytes_left) {
- ohci->IR_sp_bytes_left-= bytes_left;
- bytes_left= 0;
- } else {
- buf_ptr= bus_to_virt((unsigned long)
- &((quadlet_t*)ohci->IR_recv_prg
- [idx]->address)
- [ohci->IR_sp_bytes_left / 4]);
- bytes_left-= ohci->IR_sp_bytes_left;
- ohci->IR_sp_bytes_left= 0;
- }
+ for (i=0; i<d->num_desc; i++) {
+ d->buf[i] = kmalloc(d->buf_size, GFP_KERNEL);
+
+ if (d->buf[i] != NULL) {
+ memset(d->buf[i], 0, d->buf_size);
+ } else {
+ PRINT(KERN_ERR, ohci->id,
+ "failed to allocate dma buffer");
+ free_dma_rcv_ctx(d);
+ return NULL;
+ }
- } else {
- /* packet is being assembled */
- if (ohci->IR_sp_bytes_left > bytes_left) {
- memcpy(&ohci->IR_spb
- [ohci->IR_spb_bytes_used / 4],
- buf_ptr, bytes_left);
- ohci->IR_spb_bytes_used+= bytes_left;
- ohci->IR_sp_bytes_left-= bytes_left;
- bytes_left= 0;
- } else {
- memcpy(&ohci->IR_spb
- [ohci->IR_spb_bytes_used / 4],
- buf_ptr,
- ohci->IR_sp_bytes_left);
- ohci->IR_spb_bytes_used+=
- ohci->IR_sp_bytes_left;
- hpsb_packet_received(ohci->host,
- ohci->IR_spb,
- ohci->IR_spb_bytes_used);
- buf_ptr=
- bus_to_virt((unsigned long)
- &((quadlet_t*)ohci->IR_recv_prg
- [idx]->address)
- [ohci->IR_sp_bytes_left / 4]);
- bytes_left-= ohci->IR_sp_bytes_left;
- ohci->IR_sp_bytes_left= 0;
- ohci->IR_spb_bytes_used= 0;
- }
+ d->prg[i]= kmalloc(sizeof(struct dma_cmd), GFP_KERNEL);
- }
+ if (d->prg[i] != NULL) {
+ memset(d->prg[i], 0, sizeof(struct dma_cmd));
+ } else {
+ PRINT(KERN_ERR, ohci->id,
+ "failed to allocate dma prg");
+ free_dma_rcv_ctx(d);
+ return NULL;
+ }
+ }
- }
+ spin_lock_init(&d->lock);
- while(bytes_left > 0) {
- data_length= (int)((buf_ptr[0] >> 16) & 0xffff);
+ /* initialize bottom handler */
+ d->task.routine = dma_rcv_bh;
+ d->task.data = (void*)d;
- if (data_length % 4)
- data_length+= 4 - (data_length % 4);
+ return d;
+}
- /* is this a split packet? */
- if ( (bytes_left - (data_length + 8)) < 0 ) {
+static int free_dma_trm_ctx(struct dma_trm_ctx *d)
+{
+ if (d==NULL) return -1;
+ if (d->prg) kfree(d->prg);
+ kfree(d);
+ return 0;
+}
- if ( (data_length + 8) <=
- IR_SPLIT_PACKET_BUF_SIZE ) {
- memcpy(ohci->IR_spb, buf_ptr,
- bytes_left);
- ohci->IR_spb_bytes_used= bytes_left;
- } else {
- PRINT(KERN_ERR, ohci->id, "Packet too large for split packet buffer... dropping it");
- PRINT(KERN_DEBUG, ohci->id, "Header: %8.8x\n", buf_ptr[0]);
- ohci->IR_spb_bytes_used= 0;
- }
+static struct dma_trm_ctx *
+alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
+ int ctrlSet, int ctrlClear, int cmdPtr)
+{
+ struct dma_trm_ctx *d=NULL;
- ohci->IR_sp_bytes_left=
- (data_length + 8) - bytes_left;
- } else {
- hpsb_packet_received(ohci->host, buf_ptr,
- (data_length + 8));
- buf_ptr= bus_to_virt((unsigned long)
- &((quadlet_t*)ohci->IR_recv_prg
- [idx]->address)
- [(IR_RECV_BUF_SIZE - bytes_left
- + data_length + 8) / 4]);
- }
+ d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx),
+ GFP_KERNEL);
- bytes_left-= (data_length + 8);
- }
+ if (d==NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate dma_trm_ctx");
+ return NULL;
+ }
- spin_lock_irqsave(&ohci->IR_recv_lock, flags);
- ohci->IR_buf_last_ind= (idx + 1) % IR_NUM_DESC;
- ohci->IR_buf_used--;
- }
+ d->ohci = (void *)ohci;
+ d->ctx = ctx;
+ d->num_desc = num_desc;
+ d->ctrlSet = ctrlSet;
+ d->ctrlClear = ctrlClear;
+ d->cmdPtr = cmdPtr;
+ d->prg = NULL;
- spin_unlock_irqrestore(&ohci->IR_recv_lock, flags);
+ d->prg = kmalloc(d->num_desc * sizeof(struct at_dma_prg), GFP_KERNEL);
+
+ if (d->prg == NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg");
+ free_dma_trm_ctx(d);
+ return NULL;
+ }
+ memset(d->prg, 0, d->num_desc * sizeof(struct at_dma_prg));
+
+ spin_lock_init(&d->lock);
+
+ /* initialize bottom handler */
+ d->task.routine = dma_trm_bh;
+ d->task.data = (void*)d;
+
+ return d;
}
static int add_card(struct pci_dev *dev)
{
-#define FAIL(fmt, args...) \
- PRINT_G(KERN_ERR, fmt , ## args); \
- num_of_cards--; \
- remove_card(ohci); \
- return 1;
-
struct ti_ohci *ohci; /* shortcut to currently handled device */
- int i;
if (num_of_cards == MAX_OHCI1394_CARDS) {
PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
@@ -1185,124 +1371,51 @@ static int add_card(struct pci_dev *dev)
FAIL("failed to allocate DMA buffer for self-id packets");
}
- /* AR dma buffer and program allocation */
- ohci->AR_resp_buf=
- kmalloc(AR_RESP_NUM_DESC * sizeof(quadlet_t*),
- GFP_KERNEL);
-
- if (ohci->AR_resp_buf == NULL) {
- FAIL("failed to allocate AR response receive DMA buffer");
- }
-
- ohci->AR_resp_prg=
- kmalloc(AR_RESP_NUM_DESC * sizeof(struct dma_cmd*),
- GFP_KERNEL);
-
- if (ohci->AR_resp_prg == NULL) {
- FAIL("failed to allocate AR response receive DMA program");
- }
-
- ohci->AR_resp_spb= kmalloc(AR_RESP_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
-
- if (ohci->AR_resp_spb == NULL) {
- FAIL("failed to allocate AR response split packet buffer");
- }
-
- for (i= 0; i < AR_RESP_NUM_DESC; i++) {
- ohci->AR_resp_buf[i]= kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
-
- if (ohci->AR_resp_buf[i] != NULL) {
- memset(ohci->AR_resp_buf[i], 0, AR_RESP_BUF_SIZE);
- } else {
- FAIL("failed to allocate AR response DMA buffer");
- }
-
- ohci->AR_resp_prg[i]= kmalloc(sizeof(struct dma_cmd),
- GFP_KERNEL);
-
- if (ohci->AR_resp_prg[i] != NULL) {
- memset(ohci->AR_resp_prg[i], 0,
- sizeof(struct dma_cmd));
- } else {
- FAIL("failed to allocate AR response DMA buffer");
- }
-
- }
-
- ohci->AR_resp_buf_th_ind = 0;
- ohci->AR_resp_buf_th_offset = 0;
- ohci->AR_resp_buf_bh_ind = 0;
- ohci->AR_resp_buf_bh_offset = 0;
- ohci->AR_resp_bytes_left = 0;
- spin_lock_init(&ohci->AR_resp_lock);
-
- /* initialize AR response receive task */
- ohci->AR_resp_pdl_task.routine= ohci_ar_resp_proc_desc;
- ohci->AR_resp_pdl_task.data= (void*)ohci;
-
- /* AT dma program allocation */
- ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE,
- GFP_KERNEL);
- if (ohci->AT_req_prg != NULL) {
- memset(ohci->AT_req_prg, 0, AT_REQ_PRG_SIZE);
- } else {
- FAIL("failed to allocate AT request DMA program");
- }
-
- /* IR dma buffer and program allocation */
- ohci->IR_recv_buf=
- kmalloc(IR_NUM_DESC * sizeof(quadlet_t*),
- GFP_KERNEL);
-
- if (ohci->IR_recv_buf == NULL) {
- FAIL("failed to allocate IR receive DMA buffer");
- }
-
- ohci->IR_recv_prg=
- kmalloc(IR_NUM_DESC * sizeof(struct dma_cmd*),
- GFP_KERNEL);
-
- if (ohci->IR_recv_prg == NULL) {
- FAIL("failed to allocate IR receive DMA program");
- }
-
- ohci->IR_spb= kmalloc(IR_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
-
- if (ohci->IR_spb == NULL) {
- FAIL("failed to allocate IR split packet buffer");
- }
-
- for (i= 0; i < IR_NUM_DESC; i++) {
- ohci->IR_recv_buf[i]= kmalloc(IR_RECV_BUF_SIZE, GFP_KERNEL);
-
- if (ohci->IR_recv_buf[i] != NULL) {
- memset(ohci->IR_recv_buf[i], 0, IR_RECV_BUF_SIZE);
- } else {
- FAIL("failed to allocate IR DMA buffer");
- }
+ ohci->ar_req_context =
+ alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,
+ AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
+ OHCI1394_AsReqRcvContextControlSet,
+ OHCI1394_AsReqRcvContextControlClear,
+ OHCI1394_AsReqRcvCommandPtr);
+
+ if (ohci->ar_req_context == NULL) return 1;
+
+ ohci->ar_resp_context =
+ alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC,
+ AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
+ OHCI1394_AsRspRcvContextControlSet,
+ OHCI1394_AsRspRcvContextControlClear,
+ OHCI1394_AsRspRcvCommandPtr);
+
+ if (ohci->ar_resp_context == NULL) return 1;
- ohci->IR_recv_prg[i]= kmalloc(sizeof(struct dma_cmd),
- GFP_KERNEL);
+ ohci->at_req_context =
+ alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC,
+ OHCI1394_AsReqTrContextControlSet,
+ OHCI1394_AsReqTrContextControlClear,
+ OHCI1394_AsReqTrCommandPtr);
+
+ if (ohci->at_req_context == NULL) return 1;
- if (ohci->IR_recv_prg[i] != NULL) {
- memset(ohci->IR_recv_prg[i], 0,
- sizeof(struct dma_cmd));
- } else {
- FAIL("failed to allocate IR DMA buffer");
- }
+ ohci->at_resp_context =
+ alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC,
+ OHCI1394_AsRspTrContextControlSet,
+ OHCI1394_AsRspTrContextControlClear,
+ OHCI1394_AsRspTrCommandPtr);
+
+ if (ohci->at_resp_context == NULL) return 1;
+
+ ohci->ir_context =
+ alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
+ IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
+ OHCI1394_IrRcvContextControlSet,
+ OHCI1394_IrRcvContextControlClear,
+ OHCI1394_IrRcvCommandPtr);
- }
+ if (ohci->ir_context == NULL) return 1;
- ohci->IR_buf_used= 0;
- ohci->IR_buf_last_ind= 0;
- ohci->IR_buf_next_ind= 0;
- spin_lock_init(&ohci->IR_recv_lock);
- spin_lock_init(&ohci->IR_channel_lock);
ohci->IR_channel_usage= 0x0000000000000000;
-
- /* initialize iso receive task */
- ohci->IR_pdl_task.routine= ohci_ir_proc_desc;
- ohci->IR_pdl_task.data= (void*)ohci;
+ spin_lock_init(&ohci->IR_channel_lock);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
ohci->registers = ioremap_nocache(dev->base_address[0],
@@ -1342,6 +1455,8 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
//unsigned char phyreg;
//int i, nports;
int i;
+ struct dma_rcv_ctx *d=NULL;
+ struct dma_trm_ctx *dt=NULL;
p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n");
p += sprintf(p," bus number: 0x%x Node ID: 0x%x\n",
@@ -1370,22 +1485,93 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
host->is_busmgr ? "bus_mgr" : "");
p += sprintf(p,"\n---Iso Receive DMA---\n");
- for (i= 0; i < IR_NUM_DESC; i++) {
- p += sprintf(p, "IR_recv_buf[%d] : %p IR_recv_prg[%d]: %p\n",
- i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]);
+ d = ohci->ir_context;
+#if 0
+ for (i=0; i<d->num_desc; i++) {
+ p += sprintf(p, "IR buf[%d] : %p prg[%d]: %p\n",
+ i, d->buf[i], i, d->prg[i]);
}
+#endif
+ p += sprintf(p, "Current buf: %d offset: %d\n",
+ d->buf_ind,d->buf_offset);
+
+ p += sprintf(p,"\n---Async Receive DMA---\n");
+ d = ohci->ar_req_context;
+#if 0
+ for (i=0; i<d->num_desc; i++) {
+ p += sprintf(p, "AR req buf[%d] : %p prg[%d]: %p\n",
+ i, d->buf[i], i, d->prg[i]);
+ }
+#endif
+ p += sprintf(p, "Ar req current buf: %d offset: %d\n",
+ d->buf_ind,d->buf_offset);
+
+ d = ohci->ar_resp_context;
+#if 0
+ for (i=0; i<d->num_desc; i++) {
+ p += sprintf(p, "AR resp buf[%d] : %p prg[%d]: %p\n",
+ i, d->buf[i], i, d->prg[i]);
+ }
+#endif
+ p += sprintf(p, "AR resp current buf: %d offset: %d\n",
+ d->buf_ind,d->buf_offset);
+
+ p += sprintf(p,"\n---Async Transmit DMA---\n");
+ dt = ohci->at_req_context;
+ p += sprintf(p, "AT req prg: %d sent: %d free: %d branchAddrPtr: %p\n",
+ dt->prg_ind, dt->sent_ind, dt->free_prgs,
+ dt->branchAddrPtr);
+ p += sprintf(p, "AT req queue: first: %p last: %p\n",
+ dt->first, dt->last);
+ dt = ohci->at_resp_context;
+#if 0
+ for (i=0; i<dt->num_desc; i++) {
+ p += sprintf(p, "------- AT resp prg[%02d] ------\n",i);
+ p += sprintf(p, "%p: control : %08x\n",
+ &(dt->prg[i].begin.control),
+ dt->prg[i].begin.control);
+ p += sprintf(p, "%p: address : %08x\n",
+ &(dt->prg[i].begin.address),
+ dt->prg[i].begin.address);
+ p += sprintf(p, "%p: brancAddr: %08x\n",
+ &(dt->prg[i].begin.branchAddress),
+ dt->prg[i].begin.branchAddress);
+ p += sprintf(p, "%p: status : %08x\n",
+ &(dt->prg[i].begin.status),
+ dt->prg[i].begin.status);
+ p += sprintf(p, "%p: header[0]: %08x\n",
+ &(dt->prg[i].data[0]),
+ dt->prg[i].data[0]);
+ p += sprintf(p, "%p: header[1]: %08x\n",
+ &(dt->prg[i].data[1]),
+ dt->prg[i].data[1]);
+ p += sprintf(p, "%p: header[2]: %08x\n",
+ &(dt->prg[i].data[2]),
+ dt->prg[i].data[2]);
+ p += sprintf(p, "%p: header[3]: %08x\n",
+ &(dt->prg[i].data[3]),
+ dt->prg[i].data[3]);
+ p += sprintf(p, "%p: control : %08x\n",
+ &(dt->prg[i].end.control),
+ dt->prg[i].end.control);
+ p += sprintf(p, "%p: address : %08x\n",
+ &(dt->prg[i].end.address),
+ dt->prg[i].end.address);
+ p += sprintf(p, "%p: brancAddr: %08x\n",
+ &(dt->prg[i].end.branchAddress),
+ dt->prg[i].end.branchAddress);
+ p += sprintf(p, "%p: status : %08x\n",
+ &(dt->prg[i].end.status),
+ dt->prg[i].end.status);
+ }
+#endif
+ p += sprintf(p, "AR resp prg: %d sent: %d free: %d"
+ " branchAddrPtr: %p\n",
+ dt->prg_ind, dt->sent_ind, dt->free_prgs,
+ dt->branchAddrPtr);
+ p += sprintf(p, "AT resp queue: first: %p last: %p\n",
+ dt->first, dt->last);
-
- p += sprintf(p,"\n---Async Reponse Receive DMA---\n");
- for (i= 0; i < AR_RESP_NUM_DESC; i++) {
- p += sprintf(p, "AR_resp_buf[%d] : %p AR_resp_prg[%d]: %p\n",
- i, ohci->AR_resp_buf[i], i, ohci->AR_resp_prg[i]);
- }
- p += sprintf(p, "Current AR resp buf in irq handler: %d offset: %d\n",
- ohci->AR_resp_buf_th_ind,ohci->AR_resp_buf_th_offset);
- p += sprintf(p, "Current AR resp buf in bottom half: %d offset: %d\n",
- ohci->AR_resp_buf_bh_ind,ohci->AR_resp_buf_bh_offset);
-
/* ----- Register Dump ----- */
p += sprintf(p,"\n### HC Register dump ###\n");
SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n",
@@ -1427,20 +1613,32 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
SR("AsRsRvCtxCtl: %08x AsRsRvCmdPtr: %08x IntEvent : %08x\n",
OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr,
OHCI1394_IntEventSet);
-
+ for (i=0;i<4;i++) {
+ p += sprintf(p,"IsoRCtxCtl%02d: %08x IsoRCmdPtr%02d: %08x"
+ " IsoRCxtMch%02d: %08x\n", i,
+ reg_read(ohci,
+ OHCI1394_IrRcvContextControlSet+32*i),
+ i,reg_read(ohci, OHCI1394_IrRcvCommandPtr+32*i),
+ i,reg_read(ohci,
+ OHCI1394_IrRcvContextMatch+32*i));
+ }
+
#if 0
p += sprintf(p,"\n### Phy Register dump ###\n");
phyreg=get_phy_reg(ohci,1);
- p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d IBR: %d Gap_count: %d\n",
- 1,phyreg,(phyreg&0x80) != 0, (phyreg&0x40) !=0, phyreg&0x3f);
+ p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d"
+ "IBR: %d Gap_count: %d\n",
+ 1,phyreg,(phyreg&0x80) != 0,
+ (phyreg&0x40) !=0, phyreg&0x3f);
phyreg=get_phy_reg(ohci,2);
nports=phyreg&0x1f;
- p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d E : %d Ports : %2d\n",
- 2,phyreg,
- (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports);
+ p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d"
+ " E : %d Ports : %2d\n",
+ 2,phyreg, (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports);
for (i=0;i<nports;i++) {
phyreg=get_phy_reg(ohci,3+i);
- p += sprintf(p,"offset: %d val: 0x%02x -> [port %d] TPA: %d TPB: %d | %s %s\n",
+ p += sprintf(p,"offset: %d val: 0x%02x -> [port %d]"
+ " TPA: %d TPB: %d | %s %s\n",
3+i,phyreg,
i, (phyreg&0xC0)>>6, (phyreg&0x30)>>4,
(phyreg&0x08) ? "child" : "parent",
@@ -1454,11 +1652,6 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
phyreg&0x3f);
#endif
-#if 0
- p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control);
- p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status);
-#endif
-
return p - buf;
}
@@ -1494,53 +1687,26 @@ struct proc_dir_entry ohci_proc_entry =
static void remove_card(struct ti_ohci *ohci)
{
if (ohci->registers)
- iounmap(ohci->registers);
+ iounmap(ohci->registers);
- /* Free AR response buffers and programs */
- if (ohci->AR_resp_buf) {
- int i;
- for (i= 0; i < AR_RESP_NUM_DESC; i++) {
- kfree(ohci->AR_resp_buf[i]);
- }
- kfree(ohci->AR_resp_buf);
- }
- if (ohci->AR_resp_prg) {
- int i;
- for (i= 0; i < AR_RESP_NUM_DESC; i++) {
- kfree(ohci->AR_resp_prg[i]);
- }
- kfree(ohci->AR_resp_prg);
- }
- kfree(ohci->AR_resp_spb);
+ /* Free AR dma */
+ free_dma_rcv_ctx(ohci->ar_req_context);
+ free_dma_rcv_ctx(ohci->ar_resp_context);
- /* Free AT request buffer and program */
- if (ohci->AT_req_prg)
- kfree(ohci->AT_req_prg);
+ /* Free AT dma */
+ free_dma_trm_ctx(ohci->at_req_context);
+ free_dma_trm_ctx(ohci->at_resp_context);
- /* Free Iso receive buffers and programs */
- if (ohci->IR_recv_buf) {
- int i;
- for (i= 0; i < IR_NUM_DESC; i++) {
- kfree(ohci->IR_recv_buf[i]);
- }
- kfree(ohci->IR_recv_buf);
- }
- if (ohci->IR_recv_prg) {
- int i;
- for (i= 0; i < IR_NUM_DESC; i++) {
- kfree(ohci->IR_recv_prg[i]);
- }
- kfree(ohci->IR_recv_prg);
- }
- kfree(ohci->IR_spb);
+ /* Free IR dma */
+ free_dma_rcv_ctx(ohci->ir_context);
/* Free self-id buffer */
if (ohci->self_id_buffer)
- kfree(ohci->self_id_buffer);
+ kfree(ohci->self_id_buffer);
/* Free config rom */
if (ohci->csr_config_rom)
- kfree(ohci->csr_config_rom);
+ kfree(ohci->csr_config_rom);
/* Free the IRQ */
free_irq(ohci->dev->irq, ohci);
@@ -1562,13 +1728,13 @@ static int init_driver()
PRINT_G(KERN_INFO, "looking for Ohci1394 cards");
for (i = 0; supported_chips[i][0] != -1; i++) {
- while ((dev = pci_find_device(supported_chips[i][0],
- supported_chips[i][1], dev))
- != NULL) {
- if (add_card(dev) == 0) {
- success = 1;
+ while ((dev = pci_find_device(supported_chips[i][0],
+ supported_chips[i][1], dev))
+ != NULL) {
+ if (add_card(dev) == 0) {
+ success = 1;
+ }
}
- }
}
if (success == 0) {
@@ -1593,10 +1759,8 @@ static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr)
{
struct ti_ohci *ohci=host->hostdata;
-#if 0
- PRINT(KERN_INFO, ohci->id, "request csr_rom address: %08X",
- (u32)ohci->csr_config_rom);
-#endif
+ DBGMSG(ohci->id, "request csr_rom address: %08X",
+ (u32)ohci->csr_config_rom);
*ptr = ohci->csr_config_rom;
return sizeof(ohci_csr_rom);
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index 35d8fa2af..46d9a270f 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -4,6 +4,8 @@
#include "ieee1394_types.h"
+#define OHCI1394_DEBUG 1
+
#define OHCI1394_DRIVER_NAME "ohci1394"
#ifndef PCI_DEVICE_ID_TI_OHCI1394
@@ -18,21 +20,34 @@
#define PCI_DEVICE_ID_VIA_OHCI1394 0x3044
#endif
+#ifndef PCI_VENDOR_ID_SONY
+#define PCI_VENDOR_ID_SONY 0x104d
+#endif
+
+#ifndef PCI_DEVICE_ID_SONY_CXD3222
+#define PCI_DEVICE_ID_SONY_CXD3222 0x8039
+#endif
+
#define MAX_OHCI1394_CARDS 4
-#define OHCI1394_MAX_AT_REQ_RETRIES 1
-#define OHCI1394_MAX_AT_RESP_RETRIES 1
-#define OHCI1394_MAX_PHYS_RESP_RETRIES 4
+#define OHCI1394_MAX_AT_REQ_RETRIES 0x2
+#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
+
+#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */
+#define AR_REQ_BUF_SIZE 4096 /* size of AR req buffers */
+#define AR_REQ_SPLIT_BUF_SIZE 4096 /* split packet buffer */
#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */
#define AR_RESP_BUF_SIZE 4096 /* size of AR resp buffers */
-#define AR_RESP_SPLIT_PACKET_BUF_SIZE 256 /* split packet buffer */
-#define AR_RESP_TOTAL_BUF_SIZE (AR_RESP_BUF_SIZE * AR_RESP_NUM_DESC)
-#define AT_REQ_PRG_SIZE 256
+#define AR_RESP_SPLIT_BUF_SIZE 4096 /* split packet buffer */
-#define IR_RECV_BUF_SIZE 4096 /* 4096 bytes/buffer */
-#define IR_SPLIT_PACKET_BUF_SIZE 8192 /* size of buffer for split packets */
-#define IR_NUM_DESC 16 /* number of ISO recv descriptors */
+#define IR_NUM_DESC 16 /* number of IR descriptors */
+#define IR_BUF_SIZE 6480 /* 6480 bytes/buffer */
+#define IR_SPLIT_BUF_SIZE 8192 /* split packet buffer */
+
+#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */
+#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */
struct dma_cmd {
u32 control;
@@ -41,6 +56,50 @@ struct dma_cmd {
u32 status;
};
+struct at_dma_prg {
+ struct dma_cmd begin;
+ quadlet_t data[4];
+ struct dma_cmd end;
+};
+
+/* DMA receive context */
+struct dma_rcv_ctx {
+ void *ohci;
+ int ctx;
+ unsigned int num_desc;
+ unsigned int buf_size;
+ unsigned int split_buf_size;
+ struct dma_cmd **prg;
+ quadlet_t **buf;
+ unsigned int buf_ind;
+ unsigned int buf_offset;
+ quadlet_t *spb;
+ spinlock_t lock;
+ struct tq_struct task;
+ int ctrlClear;
+ int ctrlSet;
+ int cmdPtr;
+};
+
+/* DMA transmit context */
+struct dma_trm_ctx {
+ void *ohci;
+ int ctx;
+ unsigned int num_desc;
+ struct at_dma_prg *prg;
+ unsigned int prg_ind;
+ unsigned int sent_ind;
+ int free_prgs;
+ quadlet_t *branchAddrPtr;
+ struct hpsb_packet *first;
+ struct hpsb_packet *last;
+ spinlock_t lock;
+ struct tq_struct task;
+ int ctrlClear;
+ int ctrlSet;
+ int cmdPtr;
+};
+
struct ti_ohci {
int id; /* sequential card number */
@@ -54,42 +113,18 @@ struct ti_ohci {
quadlet_t *self_id_buffer; /* dma buffer for self-id packets */
quadlet_t *csr_config_rom; /* buffer for csr config rom */
- /* asynchronous receive */
- struct dma_cmd **AR_resp_prg;
- quadlet_t **AR_resp_buf;
- unsigned int AR_resp_buf_bh_ind;
- unsigned int AR_resp_buf_bh_offset;
- unsigned int AR_resp_buf_th_ind;
- unsigned int AR_resp_buf_th_offset;
- int AR_resp_bytes_left;
- quadlet_t *AR_resp_spb;
- spinlock_t AR_resp_lock;
-
- /* async receive task */
- struct tq_struct AR_resp_pdl_task;
-
- /* asynchronous transmit */
- struct dma_cmd *AT_req_prg;
-
- /* isochronous receive */
- struct dma_cmd **IR_recv_prg;
- quadlet_t **IR_recv_buf;
- unsigned int IR_buf_used;
- unsigned int IR_buf_last_ind;
- unsigned int IR_buf_next_ind;
- spinlock_t IR_recv_lock;
-
- /* iso recv split packet handling */
- quadlet_t *IR_spb;
- unsigned int IR_sp_bytes_left;
- unsigned int IR_spb_bytes_used;
-
- /* iso receive channel usage */
- spinlock_t IR_channel_lock;
- u64 IR_channel_usage;
+ /* async receive */
+ struct dma_rcv_ctx *ar_resp_context;
+ struct dma_rcv_ctx *ar_req_context;
- /* iso receive task */
- struct tq_struct IR_pdl_task;
+ /* async transmit */
+ struct dma_trm_ctx *at_resp_context;
+ struct dma_trm_ctx *at_req_context;
+
+ /* iso receive */
+ struct dma_rcv_ctx *ir_context;
+ u64 IR_channel_usage;
+ spinlock_t IR_channel_lock;
/* IEEE-1394 part follows */
struct hpsb_host *host;
@@ -98,16 +133,9 @@ struct ti_ohci {
spinlock_t phy_reg_lock;
- struct hpsb_packet *async_queue;
- spinlock_t async_queue_lock;
-
- int AR_resp_active;
int NumBusResets;
- int TxRdy;
- int NumInterrupts;
};
-
/*
* Register read and write helper functions.
*/
@@ -129,9 +157,9 @@ quadlet_t ohci_csr_rom[] = {
/* bus info block */
0x04040000, /* info/CRC length, CRC */
0x31333934, /* 1394 magic number */
- 0xf064a000, /* misc. settings - FIXME */
- 0x08002856, /* vendor ID, chip ID high */
- 0x0000083E, /* chip ID low */
+ 0xf07da002, /* cyc_clk_acc = 125us, max_rec = 1024 */
+ 0x00000000, /* vendor ID, chip ID high (written from card info) */
+ 0x00000000, /* chip ID low (written from card info) */
/* root directory - FIXME */
0x00090000, /* CRC length, CRC */
0x03080028, /* vendor ID (Texas Instr.) */
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
index 27cbd0c78..2809bde08 100644
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -348,8 +348,8 @@ struct ti_pcl {
struct {
u32 control;
u32 pointer;
- } buffer[13];
-};
+ } buffer[13] __attribute__ ((packed));
+} __attribute__ ((packed));
#include <linux/stddef.h>
#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
@@ -383,7 +383,11 @@ inline static void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
+ return lynx->dev->base_address[1] + pclid * sizeof(struct ti_pcl);
+#else
return lynx->dev->resource[1].start + pclid * sizeof(struct ti_pcl);
+#endif
}
#else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index adc45896d..0e63acb33 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -3,7 +3,7 @@
*
* Raw interface to the bus
*
- * Copyright (C) 1999 Andreas E. Bombe
+ * Copyright (C) 1999, 2000 Andreas E. Bombe
*/
#include <linux/kernel.h>
@@ -30,6 +30,9 @@ spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
static struct hpsb_highlevel *hl_handle = NULL;
+static atomic_t iso_buffer_size;
+static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
+
static void queue_complete_cb(struct pending_request *req);
static struct pending_request *__alloc_pending_request(int flags)
@@ -56,6 +59,7 @@ static void free_pending_request(struct pending_request *req)
{
if (req->ibs) {
if (atomic_dec_and_test(&req->ibs->refcount)) {
+ atomic_sub((req->data[0] >> 16) + 4, &iso_buffer_size);
kfree(req->ibs);
}
} else if (req->free_data) {
@@ -210,6 +214,10 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
struct iso_block_store *ibs = NULL;
LIST_HEAD(reqs);
+ if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+ return;
+ }
+
spin_lock_irqsave(&host_info_lock, flags);
hi = find_host_info(host);
@@ -227,6 +235,7 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
+ length, SLAB_ATOMIC);
if (!ibs) break;
+ atomic_add(length, &iso_buffer_size);
atomic_set(&ibs->refcount, 0);
memcpy(ibs->data, data, length);
}
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 2081f12fe..a73c26766 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -12,68 +12,99 @@ bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO
if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
bool ' Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
fi
-bool ' Support isdn diversion services' CONFIG_ISDN_DIVERSION
if [ "$CONFIG_X25" != "n" ]; then
bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25
fi
-dep_tristate ' ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate ' isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-dep_tristate ' PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate ' HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+
+mainmenu_option next_comment
+comment 'ISDN feature submodules'
+ dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+ bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
+endmenu
+
+comment 'low-level hardware drivers'
+
+mainmenu_option next_comment
+comment 'Passive ISDN cards'
+dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
- bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+ comment ' D-channel protocol features'
+ bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
if [ "$CONFIG_HISAX_EURO" != "n" ]; then
- bool ' Support for german chargeinfo' CONFIG_DE_AOC
- bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
- bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+ bool ' Support for german chargeinfo' CONFIG_DE_AOC
+ bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
+ bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+ bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
fi
- bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
- bool ' HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
- bool ' HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
- bool ' HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI
- bool ' HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX
- bool ' HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
- bool ' HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
- bool ' HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
- bool ' HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
- bool ' HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
- bool ' HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
- bool ' HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
- bool ' HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
- bool ' HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
- bool ' HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
- bool ' HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
- bool ' HiSax Support for MIC card' CONFIG_HISAX_MIC
- bool ' HiSax Support for NETjet card' CONFIG_HISAX_NETJET
- bool ' HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
- bool ' HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
- bool ' HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
- bool ' HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
- bool ' HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
- bool ' HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
- bool ' HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
- bool ' HiSax Support for Winbond W6692 based cards' CONFIG_HISAX_W6692
+ bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+ comment ' HiSax supported cards'
+ bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
+ bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+ bool ' Teles PCI' CONFIG_HISAX_TELESPCI
+ bool ' Teles S0Box' CONFIG_HISAX_S0BOX
+ bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+ bool ' AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+ bool ' AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
+ bool ' Elsa cards' CONFIG_HISAX_ELSA
+ bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+ bool ' Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+ bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
+ bool ' TELEINT cards' CONFIG_HISAX_TELEINT
+ bool ' HFC-S based cards' CONFIG_HISAX_HFCS
+ bool ' Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
+ bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+ bool ' MIC card' CONFIG_HISAX_MIC
+ bool ' NETjet card' CONFIG_HISAX_NETJET
+ bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+ bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
+ bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+ bool ' Telekom A4T card' CONFIG_HISAX_BKM_A4T
+ bool ' Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+ bool ' Gazel cards' CONFIG_HISAX_GAZEL
+ bool ' HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
+ bool ' Winbond W6692 based cards' CONFIG_HISAX_W6692
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-# bool ' HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+ bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
+# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- bool ' HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+ bool ' Am7930' CONFIG_HISAX_AMD7930
fi
fi
fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Active ISDN cards'
+dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
- dep_tristate ' Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
- dep_tristate ' IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+ dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+ dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
fi
-dep_tristate ' Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
- bool ' Eicon S, SX, SCOM, Quadro, S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
fi
-dep_tristate ' AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
- bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
- bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
- bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
- bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
- bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+ bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
+ bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
+ if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then
+ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ bool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ fi
+ fi
+ bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
+ bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
+ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ bool ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4
+ fi
+ bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+fi
+if [ "$CONFIG_PROC_FS" != "n" ]; then
+if [ "$CONFIG_MODULES" != "n" ]; then
+ bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN
+fi
fi
+endmenu
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index 04be19f9c..c94551716 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -1,6 +1,6 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert
+ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert hysdn
L_OBJS :=
LX_OBJS :=
@@ -137,5 +137,9 @@ else
endif
endif
+ifeq ($(CONFIG_HYSDN),y)
+ MOD_SUB_DIRS += hysdn
+endif
+
include $(TOPDIR)/Rules.make
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
index 111c39466..bfeb81939 100644
--- a/drivers/isdn/avmb1/Makefile
+++ b/drivers/isdn/avmb1/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.7 1999/09/15 08:16:03 calle Exp $
+# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
@@ -11,6 +11,11 @@
# parent makes..
#
# $Log: Makefile,v $
+# Revision 1.8 2000/01/25 14:33:38 calle
+# - Added Support AVM B1 PCI V4.0 (tested with prototype)
+# - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+# - support for revision register
+#
# Revision 1.7 1999/09/15 08:16:03 calle
# Implementation of 64Bit extention complete.
#
@@ -99,7 +104,7 @@ ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
ifdef CONFIG_ISDN_DRV_AVMB1_C4
O_OBJS += c4.o
endif
- OX_OBJS += capiutil.o capidrv.o b1.o
+ OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
else
ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
O_TARGET += kernelcapi.o
@@ -123,7 +128,7 @@ else
ifdef CONFIG_ISDN_DRV_AVMB1_C4
M_OBJS += c4.o
endif
- MX_OBJS += capiutil.o capidrv.o b1.o
+ MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
endif
endif
diff --git a/drivers/isdn/avmb1/avmcard.h b/drivers/isdn/avmb1/avmcard.h
index f4b5df689..56fa0fba6 100644
--- a/drivers/isdn/avmb1/avmcard.h
+++ b/drivers/isdn/avmb1/avmcard.h
@@ -1,9 +1,14 @@
/*
- * $Id: avmcard.h,v 1.6 1999/11/05 16:38:01 calle Exp $
+ * $Id: avmcard.h,v 1.7 2000/01/25 14:33:38 calle Exp $
*
* Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: avmcard.h,v $
+ * Revision 1.7 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.6 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -92,6 +97,8 @@ typedef struct avmcard {
unsigned irq;
unsigned long membase;
enum avmcardtype cardtype;
+ unsigned char revision;
+ unsigned char class;
int cardnr; /* for t1isa */
char msgbuf[128]; /* capimsg msg part */
@@ -228,8 +235,9 @@ extern int b1_irq_table[16];
#define B1_WRITE 0x01
#define B1_INSTAT 0x02
#define B1_OUTSTAT 0x03
-#define B1_RESET 0x10
#define B1_ANALYSE 0x04
+#define B1_REVISION 0x05
+#define B1_RESET 0x10
#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l)
@@ -561,10 +569,13 @@ static inline void b1_setinterrupt(unsigned int base, unsigned irq,
}
}
+/* b1.c */
int b1_detect(unsigned int base, enum avmcardtype cardtype);
+void b1_getrevision(avmcard *card);
int b1_load_t4file(avmcard *card, capiloaddatapart * t4file);
int b1_load_config(avmcard *card, capiloaddatapart * config);
int b1_loaded(avmcard *card);
+
int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1_reset_ctr(struct capi_ctr *ctrl);
void b1_register_appl(struct capi_ctr *ctrl, __u16 appl,
@@ -577,5 +588,21 @@ void b1_handle_interrupt(avmcard * card);
int b1ctl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
+/* b1dma.c */
+int b1pciv4_detect(avmcard *card);
+int t1pci_detect(avmcard *card);
+void b1dma_reset(avmcard *card);
+void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
+
+int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
+void b1dma_reset_ctr(struct capi_ctr *ctrl);
+void b1dma_remove_ctr(struct capi_ctr *ctrl);
+void b1dma_register_appl(struct capi_ctr *ctrl,
+ __u16 appl,
+ capi_register_params *rp);
+void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl);
+void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
+int b1dmactl_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl);
#endif /* _AVMCARD_H_ */
diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c
index 900b31c8c..65c4368cd 100644
--- a/drivers/isdn/avmb1/b1.c
+++ b/drivers/isdn/avmb1/b1.c
@@ -1,11 +1,16 @@
/*
- * $Id: b1.c,v 1.12 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1.c,v 1.13 2000/01/25 14:33:38 calle Exp $
*
* Common module for AVM B1 cards.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1.c,v $
+ * Revision 1.13 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.12 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -86,7 +91,7 @@
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.12 $";
+static char *revision = "$Revision: 1.13 $";
/* ------------------------------------------------------------- */
@@ -158,6 +163,12 @@ int b1_detect(unsigned int base, enum avmcardtype cardtype)
return 0;
}
+void b1_getrevision(avmcard *card)
+{
+ card->class = inb(card->port + B1_ANALYSE);
+ card->revision = inb(card->port + B1_REVISION);
+}
+
int b1_load_t4file(avmcard *card, capiloaddatapart * t4file)
{
unsigned char buf[256];
@@ -688,6 +699,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
EXPORT_SYMBOL(b1_irq_table);
EXPORT_SYMBOL(b1_detect);
+EXPORT_SYMBOL(b1_getrevision);
EXPORT_SYMBOL(b1_load_t4file);
EXPORT_SYMBOL(b1_load_config);
EXPORT_SYMBOL(b1_loaded);
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
new file mode 100644
index 000000000..8bf595282
--- /dev/null
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -0,0 +1,984 @@
+/*
+ * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $
+ *
+ * Common module for AVM B1 cards that support dma with AMCC
+ *
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1dma.c,v $
+ * Revision 1.2 2000/01/25 14:44:47 calle
+ * typo in b1pciv4_detect().
+ *
+ * Revision 1.1 2000/01/25 14:36:43 calle
+ * common function for T1 PCI and B1 PCI V4.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include "capilli.h"
+#include "avmcard.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+static char *revision = "$Revision: 1.2 $";
+
+/* ------------------------------------------------------------- */
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+int suppress_pollack = 0;
+MODULE_PARM(suppress_pollack, "0-1i");
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+/* S5933 */
+
+#define AMCC_RXPTR 0x24
+#define AMCC_RXLEN 0x28
+#define AMCC_TXPTR 0x2c
+#define AMCC_TXLEN 0x30
+
+#define AMCC_INTCSR 0x38
+# define EN_READ_TC_INT 0x00008000L
+# define EN_WRITE_TC_INT 0x00004000L
+# define EN_TX_TC_INT EN_READ_TC_INT
+# define EN_RX_TC_INT EN_WRITE_TC_INT
+# define AVM_FLAG 0x30000000L
+
+# define ANY_S5933_INT 0x00800000L
+# define READ_TC_INT 0x00080000L
+# define WRITE_TC_INT 0x00040000L
+# define TX_TC_INT READ_TC_INT
+# define RX_TC_INT WRITE_TC_INT
+# define MASTER_ABORT_INT 0x00100000L
+# define TARGET_ABORT_INT 0x00200000L
+# define BUS_MASTER_INT 0x00200000L
+# define ALL_INT 0x000C0000L
+
+#define AMCC_MCSR 0x3c
+# define A2P_HI_PRIORITY 0x00000100L
+# define EN_A2P_TRANSFERS 0x00000400L
+# define P2A_HI_PRIORITY 0x00001000L
+# define EN_P2A_TRANSFERS 0x00004000L
+# define RESET_A2P_FLAGS 0x04000000L
+# define RESET_P2A_FLAGS 0x02000000L
+
+/* ------------------------------------------------------------- */
+
+#define b1dmaoutmeml(addr, value) writel(value, addr)
+#define b1dmainmeml(addr) readl(addr)
+#define b1dmaoutmemw(addr, value) writew(value, addr)
+#define b1dmainmemw(addr) readw(addr)
+#define b1dmaoutmemb(addr, value) writeb(value, addr)
+#define b1dmainmemb(addr) readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int b1dma_tx_empty(unsigned int port)
+{
+ return inb(port + 0x03) & 0x1;
+}
+
+static inline int b1dma_rx_full(unsigned int port)
+{
+ return inb(port + 0x02) & 0x1;
+}
+
+static int b1dma_tolink(avmcard *card, void *buf, unsigned int len)
+{
+ unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
+ unsigned char *s = (unsigned char *)buf;
+ while (len--) {
+ while ( !b1dma_tx_empty(card->port)
+ && time_before(jiffies, stop));
+ if (!b1dma_tx_empty(card->port))
+ return -1;
+ t1outp(card->port, 0x01, *s++);
+ }
+ return 0;
+}
+
+static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len)
+{
+ unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
+ unsigned char *s = (unsigned char *)buf;
+ while (len--) {
+ while ( !b1dma_rx_full(card->port)
+ && time_before(jiffies, stop));
+ if (!b1dma_rx_full(card->port))
+ return -1;
+ *s++ = t1inp(card->port, 0x00);
+ }
+ return 0;
+}
+
+static int WriteReg(avmcard *card, __u32 reg, __u8 val)
+{
+ __u8 cmd = 0x00;
+ if ( b1dma_tolink(card, &cmd, 1) == 0
+ && b1dma_tolink(card, &reg, 4) == 0) {
+ __u32 tmp = val;
+ return b1dma_tolink(card, &tmp, 4);
+ }
+ return -1;
+}
+
+static __u8 ReadReg(avmcard *card, __u32 reg)
+{
+ __u8 cmd = 0x01;
+ if ( b1dma_tolink(card, &cmd, 1) == 0
+ && b1dma_tolink(card, &reg, 4) == 0) {
+ __u32 tmp;
+ if (b1dma_fromlink(card, &tmp, 4) == 0)
+ return (__u8)tmp;
+ }
+ return 0xff;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, __u8 val)
+{
+ __u8 *s = *pp;
+ *s++ = val;
+ *pp = s;
+}
+
+static inline void _put_word(void **pp, __u32 val)
+{
+ __u8 *s = *pp;
+ *s++ = val & 0xff;
+ *s++ = (val >> 8) & 0xff;
+ *s++ = (val >> 16) & 0xff;
+ *s++ = (val >> 24) & 0xff;
+ *pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+ unsigned i = len;
+ _put_word(pp, i);
+ while (i-- > 0)
+ _put_byte(pp, *dp++);
+}
+
+static inline __u8 _get_byte(void **pp)
+{
+ __u8 *s = *pp;
+ __u8 val;
+ val = *s++;
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_word(void **pp)
+{
+ __u8 *s = *pp;
+ __u32 val;
+ val = *s++;
+ val |= (*s++ << 8);
+ val |= (*s++ << 16);
+ val |= (*s++ << 24);
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_slice(void **pp, unsigned char *dp)
+{
+ unsigned int len, i;
+
+ len = i = _get_word(pp);
+ while (i-- > 0) *dp++ = _get_byte(pp);
+ return len;
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_reset(avmcard *card)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ card->csr = 0x0;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
+ b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
+
+ t1outp(card->port, 0x10, 0x00);
+ t1outp(card->port, 0x07, 0x00);
+
+ restore_flags(flags);
+
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ if (card->cardtype == avm_t1pci)
+ udelay(42 * 1000);
+ else
+ udelay(10 * 1000);
+}
+
+/* ------------------------------------------------------------- */
+
+int b1dma_detect(avmcard *card)
+{
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ udelay(42 * 1000);
+
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
+ b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
+ card->csr = 0x0;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+ if (b1dmainmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
+ return 1;
+
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
+ b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
+ if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
+ || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
+ return 2;
+
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0x0);
+ b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0x0);
+ if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0x0
+ || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0x0)
+ return 3;
+
+ t1outp(card->port, 0x10, 0x00);
+ t1outp(card->port, 0x07, 0x00);
+
+ t1outp(card->port, 0x02, 0x02);
+ t1outp(card->port, 0x03, 0x02);
+
+ if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02
+ || t1inp(card->port, 0x3) != 0x03)
+ return 4;
+
+ t1outp(card->port, 0x02, 0x00);
+ t1outp(card->port, 0x03, 0x00);
+
+ if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00
+ || t1inp(card->port, 0x3) != 0x01)
+ return 5;
+
+ return 0;
+}
+
+int t1pci_detect(avmcard *card)
+{
+ int ret;
+
+ if ((ret = b1dma_detect(card)) != 0)
+ return ret;
+
+ /* Transputer test */
+
+ if ( WriteReg(card, 0x80001000, 0x11) != 0
+ || WriteReg(card, 0x80101000, 0x22) != 0
+ || WriteReg(card, 0x80201000, 0x33) != 0
+ || WriteReg(card, 0x80301000, 0x44) != 0)
+ return 6;
+
+ if ( ReadReg(card, 0x80001000) != 0x11
+ || ReadReg(card, 0x80101000) != 0x22
+ || ReadReg(card, 0x80201000) != 0x33
+ || ReadReg(card, 0x80301000) != 0x44)
+ return 7;
+
+ if ( WriteReg(card, 0x80001000, 0x55) != 0
+ || WriteReg(card, 0x80101000, 0x66) != 0
+ || WriteReg(card, 0x80201000, 0x77) != 0
+ || WriteReg(card, 0x80301000, 0x88) != 0)
+ return 8;
+
+ if ( ReadReg(card, 0x80001000) != 0x55
+ || ReadReg(card, 0x80101000) != 0x66
+ || ReadReg(card, 0x80201000) != 0x77
+ || ReadReg(card, 0x80301000) != 0x88)
+ return 9;
+
+ return 0;
+}
+
+int b1pciv4_detect(avmcard *card)
+{
+ int ret, i;
+
+ if ((ret = b1dma_detect(card)) != 0)
+ return ret;
+
+ for (i=0; i < 5 ; i++) {
+ if (WriteReg(card, 0x80A00000, 0x21) != 0)
+ return 6;
+ if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)
+ return 7;
+ }
+ for (i=0; i < 5 ; i++) {
+ if (WriteReg(card, 0x80A00000, 0x20) != 0)
+ return 8;
+ if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)
+ return 9;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_dispatch_tx(avmcard *card)
+{
+ avmcard_dmainfo *dma = card->dma;
+ unsigned long flags;
+ struct sk_buff *skb;
+ __u8 cmd, subcmd;
+ __u16 len;
+ __u32 txlen;
+ int inint;
+ void *p;
+
+ save_flags(flags);
+ cli();
+
+ inint = card->interrupt;
+
+ if (card->csr & EN_TX_TC_INT) { /* tx busy */
+ restore_flags(flags);
+ return;
+ }
+
+ skb = skb_dequeue(&dma->send_queue);
+ if (!skb) {
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "tx(%d): underrun\n", inint);
+#endif
+ restore_flags(flags);
+ return;
+ }
+
+ len = CAPIMSG_LEN(skb->data);
+
+ if (len) {
+ cmd = CAPIMSG_COMMAND(skb->data);
+ subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+ p = dma->sendbuf;
+
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+ _put_byte(&p, SEND_DATA_B3_REQ);
+ _put_slice(&p, skb->data, len);
+ _put_slice(&p, skb->data + len, dlen);
+ } else {
+ _put_byte(&p, SEND_MESSAGE);
+ _put_slice(&p, skb->data, len);
+ }
+ txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
+ inint, txlen);
+#endif
+ } else {
+ txlen = skb->len-2;
+#ifdef CONFIG_B1DMA_POLLDEBUG
+ if (skb->data[2] == SEND_POLLACK)
+ printk(KERN_INFO "%s: send ack\n", card->name);
+#endif
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
+ inint, skb->data[2], txlen);
+#endif
+ memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+ }
+ txlen = (txlen + 3) & ~3;
+
+ b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
+ b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen);
+
+ card->csr |= EN_TX_TC_INT;
+
+ if (!inint)
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+ restore_flags(flags);
+ dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(3, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_POLLACK);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_handle_rx(avmcard *card)
+{
+ avmctrl_info *cinfo = &card->ctrlinfo[0];
+ avmcard_dmainfo *dma = card->dma;
+ struct capi_ctr *ctrl = cinfo->capi_ctrl;
+ struct sk_buff *skb;
+ void *p = dma->recvbuf+4;
+ __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+ __u8 b1cmd = _get_byte(&p);
+
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
+#endif
+
+ switch (b1cmd) {
+ case RECEIVE_DATA_B3_IND:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ DataB3Len = _get_slice(&p, card->databuf);
+
+ if (MsgLen < 30) { /* not CAPI 64Bit */
+ memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+ MsgLen = 30;
+ CAPIMSG_SETLEN(card->msgbuf, 30);
+ }
+ if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "%s: incoming packet dropped\n",
+ card->name);
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "%s: incoming packet dropped\n",
+ card->name);
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_NEW_NCCI:
+
+ ApplId = _get_word(&p);
+ NCCI = _get_word(&p);
+ WindowSize = _get_word(&p);
+
+ ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = _get_word(&p);
+ NCCI = _get_word(&p);
+
+ if (NCCI != 0xffffffff)
+ ctrl->free_ncci(ctrl, ApplId, NCCI);
+ else ctrl->appl_released(ctrl, ApplId);
+ break;
+
+ case RECEIVE_START:
+#ifdef CONFIG_B1DMA_POLLDEBUG
+ printk(KERN_INFO "%s: receive poll\n", card->name);
+#endif
+ if (!suppress_pollack)
+ queue_pollack(card);
+ ctrl->resume_output(ctrl);
+ break;
+
+ case RECEIVE_STOP:
+ ctrl->suspend_output(ctrl);
+ break;
+
+ case RECEIVE_INIT:
+
+ cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+ b1_parse_version(cinfo);
+ printk(KERN_INFO "%s: %s-card (%s) now active\n",
+ card->name,
+ cinfo->version[VER_CARDTYPE],
+ cinfo->version[VER_DRIVER]);
+ ctrl->ready(ctrl);
+ break;
+
+ case RECEIVE_TASK_READY:
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+ card->name, ApplId, card->msgbuf);
+ break;
+
+ case RECEIVE_DEBUGMSG:
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n",
+ card->name, b1cmd);
+ return;
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_handle_interrupt(avmcard *card)
+{
+ __u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR);
+ __u32 newcsr;
+
+ if ((status & ANY_S5933_INT) == 0)
+ return;
+
+ newcsr = card->csr | (status & ALL_INT);
+ if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
+ if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr);
+
+ if ((status & RX_TC_INT) != 0) {
+ __u8 *recvbuf = card->dma->recvbuf;
+ __u32 rxlen;
+ if (card->dma->recvlen == 0) {
+ card->dma->recvlen = *((__u32 *)recvbuf);
+ rxlen = (card->dma->recvlen + 3) & ~3;
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR,
+ virt_to_phys(recvbuf+4));
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen);
+ } else {
+ b1dma_handle_rx(card);
+ card->dma->recvlen = 0;
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
+ }
+ }
+
+ if ((status & TX_TC_INT) != 0) {
+ card->csr &= ~EN_TX_TC_INT;
+ b1dma_dispatch_tx(card);
+ } else if (card->csr & EN_TX_TC_INT) {
+ if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) {
+ card->csr &= ~EN_TX_TC_INT;
+ b1dma_dispatch_tx(card);
+ }
+ }
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+}
+
+void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "b1dma: interrupt: wrong device\n");
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ b1dma_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1dma_loaded(avmcard *card)
+{
+ unsigned long stop;
+ unsigned char ans;
+ unsigned long tout = 2;
+ unsigned int base = card->port;
+
+ for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+ if (b1_tx_empty(base))
+ break;
+ }
+ if (!b1_tx_empty(base)) {
+ printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n",
+ card->name);
+ return 0;
+ }
+ b1_put_byte(base, SEND_POLLACK);
+ for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+ if (b1_rx_full(base)) {
+ if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
+ return 1;
+ }
+ printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
+ return 0;
+ }
+ }
+ printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name);
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_send_init(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(15, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_INIT);
+ _put_word(&p, AVM_NAPPS);
+ _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+ _put_word(&p, card->cardnr - 1);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ unsigned long flags;
+ int retval;
+
+ b1dma_reset(card);
+
+ if ((retval = b1_load_t4file(card, &data->firmware))) {
+ b1dma_reset(card);
+ printk(KERN_ERR "%s: failed to load t4file!!\n",
+ card->name);
+ return retval;
+ }
+
+ if (data->configuration.len > 0 && data->configuration.data) {
+ if ((retval = b1_load_config(card, &data->configuration))) {
+ b1dma_reset(card);
+ printk(KERN_ERR "%s: failed to load config!!\n",
+ card->name);
+ return retval;
+ }
+ }
+
+ if (!b1dma_loaded(card)) {
+ b1dma_reset(card);
+ printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
+ return -EIO;
+ }
+
+ save_flags(flags);
+ cli();
+
+ card->csr = AVM_FLAG;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR,
+ EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
+ |A2P_HI_PRIORITY|P2A_HI_PRIORITY
+ |RESET_A2P_FLAGS|RESET_P2A_FLAGS);
+ t1outp(card->port, 0x07, 0x30);
+ t1outp(card->port, 0x10, 0xF0);
+
+ card->dma->recvlen = 0;
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
+ card->csr |= EN_RX_TC_INT;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+ restore_flags(flags);
+
+ b1dma_send_init(card);
+
+ return 0;
+}
+
+void b1dma_reset_ctr(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+
+ b1dma_reset(card);
+
+ memset(cinfo->version, 0, sizeof(cinfo->version));
+ ctrl->reseted(ctrl);
+}
+
+
+/* ------------------------------------------------------------- */
+
+
+void b1dma_register_appl(struct capi_ctr *ctrl,
+ __u16 appl,
+ capi_register_params *rp)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ int want = rp->level3cnt;
+ int nconn;
+ void *p;
+
+ if (want > 0) nconn = want;
+ else nconn = ctrl->profile.nbchannel * -want;
+ if (nconn == 0) nconn = ctrl->profile.nbchannel;
+
+ skb = alloc_skb(23, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_REGISTER);
+ _put_word(&p, appl);
+ _put_word(&p, 1024 * (nconn+1));
+ _put_word(&p, nconn);
+ _put_word(&p, rp->datablkcnt);
+ _put_word(&p, rp->datablklen);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+
+ ctrl->appl_registered(ctrl, appl);
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(7, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_RELEASE);
+ _put_word(&p, appl);
+
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+int b1dmactl_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ unsigned long flags;
+ __u8 flag;
+ int len = 0;
+ char *s;
+ __u32 txaddr, txlen, rxaddr, rxlen, csr;
+
+ len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+ len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+ len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+ len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+ switch (card->cardtype) {
+ case avm_b1isa: s = "B1 ISA"; break;
+ case avm_b1pci: s = "B1 PCI"; break;
+ case avm_b1pcmcia: s = "B1 PCMCIA"; break;
+ case avm_m1: s = "M1"; break;
+ case avm_m2: s = "M2"; break;
+ case avm_t1isa: s = "T1 ISA (HEMA)"; break;
+ case avm_t1pci: s = "T1 PCI"; break;
+ case avm_c4: s = "C4"; break;
+ default: s = "???"; break;
+ }
+ len += sprintf(page+len, "%-16s %s\n", "type", s);
+ if ((s = cinfo->version[VER_DRIVER]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ if ((s = cinfo->version[VER_SERIAL]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+ if (card->cardtype != avm_m1) {
+ flag = ((__u8 *)(ctrl->profile.manu))[3];
+ if (flag)
+ len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+ "protocol",
+ (flag & 0x01) ? " DSS1" : "",
+ (flag & 0x02) ? " CT1" : "",
+ (flag & 0x04) ? " VN3" : "",
+ (flag & 0x08) ? " NI1" : "",
+ (flag & 0x10) ? " AUSTEL" : "",
+ (flag & 0x20) ? " ESS" : "",
+ (flag & 0x40) ? " 1TR6" : ""
+ );
+ }
+ if (card->cardtype != avm_m1) {
+ flag = ((__u8 *)(ctrl->profile.manu))[5];
+ if (flag)
+ len += sprintf(page+len, "%-16s%s%s%s%s\n",
+ "linetype",
+ (flag & 0x01) ? " point to point" : "",
+ (flag & 0x02) ? " point to multipoint" : "",
+ (flag & 0x08) ? " leased line without D-channel" : "",
+ (flag & 0x04) ? " leased line with D-channel" : ""
+ );
+ }
+ len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+
+ save_flags(flags);
+ cli();
+
+ txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
+ txaddr -= (__u32)card->dma->sendbuf;
+ txlen = b1dmainmeml(card->mbase+0x30);
+
+ rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24));
+ rxaddr -= (__u32)card->dma->recvbuf;
+ rxlen = b1dmainmeml(card->mbase+0x28);
+
+ csr = b1dmainmeml(card->mbase+AMCC_INTCSR);
+
+ restore_flags(flags);
+
+ len += sprintf(page+len, "%-16s 0x%lx\n",
+ "csr (cached)", (unsigned long)card->csr);
+ len += sprintf(page+len, "%-16s 0x%lx\n",
+ "csr", (unsigned long)csr);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "txoff", (unsigned long)txaddr);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "txlen", (unsigned long)txlen);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "rxoff", (unsigned long)rxaddr);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "rxlen", (unsigned long)rxlen);
+
+ if (off+count >= len)
+ *eof = 1;
+ if (len < off)
+ return 0;
+ *start = page + off;
+ return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+EXPORT_SYMBOL(b1dma_reset);
+EXPORT_SYMBOL(t1pci_detect);
+EXPORT_SYMBOL(b1pciv4_detect);
+EXPORT_SYMBOL(b1dma_interrupt);
+
+EXPORT_SYMBOL(b1dma_load_firmware);
+EXPORT_SYMBOL(b1dma_reset_ctr);
+EXPORT_SYMBOL(b1dma_register_appl);
+EXPORT_SYMBOL(b1dma_release_appl);
+EXPORT_SYMBOL(b1dma_send_message);
+EXPORT_SYMBOL(b1dmactl_read_proc);
+
+#ifdef MODULE
+#define b1dma_init init_module
+void cleanup_module(void);
+#endif
+
+int b1dma_init(void)
+{
+ char *p;
+ char rev[10];
+
+ if ((p = strchr(revision, ':'))) {
+ strncpy(rev, p + 1, sizeof(rev));
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, "1.0");
+
+ printk(KERN_INFO "b1dma: revision %s\n", rev);
+
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/drivers/isdn/avmb1/b1isa.c b/drivers/isdn/avmb1/b1isa.c
index 01972b2d2..590e825b6 100644
--- a/drivers/isdn/avmb1/b1isa.c
+++ b/drivers/isdn/avmb1/b1isa.c
@@ -1,11 +1,19 @@
/*
- * $Id: b1isa.c,v 1.5 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 calle Exp $
*
* Module for AVM B1 ISA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1isa.c,v $
+ * Revision 1.7 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.6 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
* Revision 1.5 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -61,7 +69,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.7 $";
/* ------------------------------------------------------------- */
@@ -69,10 +77,6 @@ MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
-static struct capi_driver_interface *di;
-
-/* ------------------------------------------------------------- */
-
static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
{
avmcard *card;
@@ -96,6 +100,10 @@ static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
}
/* ------------------------------------------------------------- */
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
static void b1isa_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -122,10 +130,13 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
avmcard *card;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "b1isa: no memory.\n");
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -133,6 +144,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!cinfo) {
printk(KERN_WARNING "b1isa: no memory.\n");
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -149,12 +161,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
if (b1_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
if ( card->port != 0x150 && card->port != 0x250
@@ -162,6 +176,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
b1_reset(card->port);
@@ -170,9 +185,11 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
+ b1_getrevision(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
@@ -182,6 +199,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -192,10 +210,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- MOD_INC_USE_COUNT;
+ printk(KERN_INFO
+ "%s: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
+ driver->name, card->port, card->irq, card->revision);
+
return 0;
}
@@ -205,11 +227,12 @@ static char *b1isa_procinfo(struct capi_ctr *ctrl)
if (!cinfo)
return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index f4e87b12f..f7affea0d 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -1,11 +1,20 @@
/*
- * $Id: b1pci.c,v 1.18 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $
*
* Module for AVM B1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pci.c,v $
+ * Revision 1.20 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.19 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.18 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -66,7 +75,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.18 $";
+static char *revision = "$Revision: 1.20 $";
/* ------------------------------------------------------------- */
@@ -138,11 +147,12 @@ static char *b1pci_procinfo(struct capi_ctr *ctrl)
if (!cinfo)
return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
@@ -155,10 +165,13 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
avmctrl_info *cinfo;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -166,6 +179,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -182,6 +196,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
b1_reset(card->port);
@@ -190,9 +205,11 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
+ b1_getrevision(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
@@ -203,6 +220,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -214,10 +232,19 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- MOD_INC_USE_COUNT;
+ if (card->revision >= 4) {
+ printk(KERN_INFO
+ "%s: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
+ driver->name, card->port, card->irq, card->revision);
+ } else {
+ printk(KERN_INFO
+ "%s: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
+ driver->name, card->port, card->irq, card->revision);
+ }
return 0;
}
@@ -241,6 +268,187 @@ static struct capi_driver b1pci_driver = {
0, /* no add_card function */
};
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *div4;
+
+/* ------------------------------------------------------------- */
+
+static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+
+ b1dma_reset(card);
+
+ div4->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
+static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+ if (!cinfo)
+ return "";
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d",
+ cinfo->cardname[0] ? cinfo->cardname : "-",
+ cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+ cinfo->card ? cinfo->card->port : 0x0,
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->membase : 0,
+ cinfo->card ? cinfo->card->revision : 0
+ );
+ return cinfo->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+ unsigned long base, page_offset;
+ avmcard *card;
+ avmctrl_info *cinfo;
+ int retval;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+ if (!card->dma) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card);
+ return -ENOMEM;
+ }
+ memset(card->dma, 0, sizeof(avmcard_dmainfo));
+ cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+ if (!cinfo) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card->dma);
+ kfree(card);
+ return -ENOMEM;
+ }
+ memset(cinfo, 0, sizeof(avmctrl_info));
+ card->ctrlinfo = cinfo;
+ cinfo->card = card;
+ sprintf(card->name, "b1pciv4-%x", p->port);
+ card->port = p->port;
+ card->irq = p->irq;
+ card->membase = p->membase;
+ card->cardtype = avm_b1pci;
+
+ if (check_region(card->port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "%s: ports 0x%03x-0x%03x in use.\n",
+ driver->name, card->port, card->port + AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ base = card->membase & PAGE_MASK;
+ page_offset = card->membase - base;
+ card->mbase = ioremap_nocache(base, page_offset + 64);
+ if (card->mbase) {
+ card->mbase += page_offset;
+ } else {
+ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
+ driver->name, card->membase);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EIO;
+ }
+
+ b1dma_reset(card);
+
+ if ((retval = b1pciv4_detect(card)) != 0) {
+ printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+ driver->name, card->port, retval);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EIO;
+ }
+ b1dma_reset(card);
+ b1_getrevision(card);
+
+ request_region(p->port, AVMB1_PORTLEN, card->name);
+
+ retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ driver->name, card->irq);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
+ if (!cinfo->capi_ctrl) {
+ printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EBUSY;
+ }
+ card->cardnr = cinfo->capi_ctrl->cnr;
+
+ skb_queue_head_init(&card->dma->send_queue);
+
+ printk(KERN_INFO
+ "%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
+ driver->name, card->port, card->irq,
+ card->membase, card->revision);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+
+static struct capi_driver b1pciv4_driver = {
+ "b1pciv4",
+ "0.0",
+ b1dma_load_firmware,
+ b1dma_reset_ctr,
+ b1pciv4_remove_ctr,
+ b1dma_register_appl,
+ b1dma_release_appl,
+ b1dma_send_message,
+
+ b1pciv4_procinfo,
+ b1dmactl_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ 0, /* no add_card function */
+};
+
+#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
+
#ifdef MODULE
#define b1pci_init init_module
void cleanup_module(void);
@@ -248,9 +456,55 @@ void cleanup_module(void);
static int ncards = 0;
+static int add_card(struct pci_dev *dev)
+{
+ struct capi_driver *driver = &b1pci_driver;
+ struct capicardparams param;
+ int retval;
+
+ if (dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK) { /* B1 PCI V4 */
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ driver = &b1pciv4_driver;
+#endif
+ param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK;
+ param.port = dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK;
+ param.irq = dev->irq;
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
+ driver->name, param.port, param.irq, param.membase);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ retval = b1pciv4_add_card(driver, &param);
+#else
+ retval = b1pci_add_card(driver, &param);
+#endif
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
+ driver->name, param.port, param.irq, param.membase);
+ }
+ } else {
+ param.membase = 0;
+ param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
+ param.irq = dev->irq;
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
+ driver->name, param.port, param.irq);
+ retval = b1pci_add_card(driver, &param);
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: no AVM-B1 at i/o %#x, irq %d detected\n",
+ driver->name, param.port, param.irq);
+ }
+ }
+ return retval;
+}
+
int b1pci_init(void)
{
struct capi_driver *driver = &b1pci_driver;
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ struct capi_driver *driverv4 = &b1pciv4_driver;
+#endif
struct pci_dev *dev = NULL;
char *p;
int retval;
@@ -271,26 +525,32 @@ int b1pci_init(void)
return -EIO;
}
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision);
+
+ div4 = attach_capi_driver(driverv4);
+
+ if (!div4) {
+ detach_capi_driver(driver);
+ printk(KERN_ERR "%s: failed to attach capi_driver\n",
+ driverv4->name);
+ return -EIO;
+ }
+#endif
+
#ifdef CONFIG_PCI
if (!pci_present()) {
printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
detach_capi_driver(driver);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ detach_capi_driver(driverv4);
+#endif
return -EIO;
}
while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) {
- struct capicardparams param;
-
- param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
- param.irq = dev->irq;
- printk(KERN_INFO
- "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
- driver->name, param.port, param.irq);
- retval = b1pci_add_card(driver, &param);
+ retval = add_card(dev);
if (retval != 0) {
- printk(KERN_ERR
- "%s: no AVM-B1 at i/o %#x, irq %d detected\n",
- driver->name, param.port, param.irq);
#ifdef MODULE
cleanup_module();
#endif
@@ -315,5 +575,8 @@ int b1pci_init(void)
void cleanup_module(void)
{
detach_capi_driver(&b1pci_driver);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ detach_capi_driver(&b1pciv4_driver);
+#endif
}
#endif
diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c
index 79e343164..6e39c43d2 100644
--- a/drivers/isdn/avmb1/b1pcmcia.c
+++ b/drivers/isdn/avmb1/b1pcmcia.c
@@ -1,11 +1,19 @@
/*
- * $Id: b1pcmcia.c,v 1.5 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $
*
* Module for AVM B1/M1/M2 PCMCIA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pcmcia.c,v $
+ * Revision 1.7 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.6 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
* Revision 1.5 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -62,7 +70,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.7 $";
/* ------------------------------------------------------------- */
@@ -126,12 +134,16 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
{
avmctrl_info *cinfo;
avmcard *card;
+ char *cardname;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -139,6 +151,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -159,9 +172,11 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
+ b1_getrevision(card);
retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
if (retval) {
@@ -169,6 +184,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
driver->name, card->irq);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -179,10 +195,19 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
free_irq(card->irq, card);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
+ switch (cardtype) {
+ case avm_m1: cardname = "M1"; break;
+ case avm_m2: cardname = "M2"; break;
+ default : cardname = "B1 PCMCIA"; break;
+ }
+
+ printk(KERN_INFO
+ "%s: AVM %s at i/o %#x, irq %d, revision %d\n",
+ driver->name, cardname, card->port, card->irq, card->revision);
- MOD_INC_USE_COUNT;
return cinfo->capi_ctrl->cnr;
}
@@ -194,11 +219,12 @@ static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
if (!cinfo)
return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
new file mode 100644
index 000000000..7483370cf
--- /dev/null
+++ b/drivers/isdn/avmb1/c4.c
@@ -0,0 +1,1326 @@
+/*
+ * $Id: c4.c,v 1.4 2000/02/02 18:36:03 calle Exp $
+ *
+ * Module for AVM C4 card.
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: c4.c,v $
+ * Revision 1.4 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.3 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
+ * Revision 1.2 2000/01/21 20:52:58 keil
+ * pci_find_subsys as local function for 2.2.X kernel
+ *
+ * Revision 1.1 2000/01/20 10:51:37 calle
+ * Added driver for C4.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.4 $";
+
+#undef CONFIG_C4_DEBUG
+#undef CONFIG_C4_POLLDEBUG
+
+/* ------------------------------------------------------------- */
+
+#ifndef PCI_VENDOR_ID_DEC
+#define PCI_VENDOR_ID_DEC 0x1011
+#endif
+
+#ifndef PCI_DEVICE_ID_DEC_21285
+#define PCI_DEVICE_ID_DEC_21285 0x1065
+#endif
+
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM 0x1244
+#endif
+
+#ifndef PCI_DEVICE_ID_AVM_C4
+#define PCI_DEVICE_ID_AVM_C4 0x0800
+#endif
+
+/* ------------------------------------------------------------- */
+
+int suppress_pollack = 0;
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+MODULE_PARM(suppress_pollack, "0-1i");
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+#define DC21285_DRAM_A0MR 0x40000000
+#define DC21285_DRAM_A1MR 0x40004000
+#define DC21285_DRAM_A2MR 0x40008000
+#define DC21285_DRAM_A3MR 0x4000C000
+
+#define CAS_OFFSET 0x88
+
+#define DC21285_ARMCSR_BASE 0x42000000
+
+#define PCI_OUT_INT_STATUS 0x30
+#define PCI_OUT_INT_MASK 0x34
+#define MAILBOX_0 0x50
+#define MAILBOX_1 0x54
+#define MAILBOX_2 0x58
+#define MAILBOX_3 0x5C
+#define DOORBELL 0x60
+#define DOORBELL_SETUP 0x64
+
+#define CHAN_1_CONTROL 0x90
+#define CHAN_2_CONTROL 0xB0
+#define DRAM_TIMING 0x10C
+#define DRAM_ADDR_SIZE_0 0x110
+#define DRAM_ADDR_SIZE_1 0x114
+#define DRAM_ADDR_SIZE_2 0x118
+#define DRAM_ADDR_SIZE_3 0x11C
+#define SA_CONTROL 0x13C
+#define XBUS_CYCLE 0x148
+#define XBUS_STROBE 0x14C
+#define DBELL_PCI_MASK 0x150
+#define DBELL_SA_MASK 0x154
+
+#define SDRAM_SIZE 0x1000000
+
+/* ------------------------------------------------------------- */
+
+#define MBOX_PEEK_POKE MAILBOX_0
+
+#define DBELL_ADDR 0x01
+#define DBELL_DATA 0x02
+#define DBELL_RNWR 0x40
+#define DBELL_INIT 0x80
+
+/* ------------------------------------------------------------- */
+
+#define MBOX_UP_ADDR MAILBOX_0
+#define MBOX_UP_LEN MAILBOX_1
+#define MBOX_DOWN_ADDR MAILBOX_2
+#define MBOX_DOWN_LEN MAILBOX_3
+
+#define DBELL_UP_HOST 0x00000100
+#define DBELL_UP_ARM 0x00000200
+#define DBELL_DOWN_HOST 0x00000400
+#define DBELL_DOWN_ARM 0x00000800
+#define DBELL_RESET_HOST 0x40000000
+#define DBELL_RESET_ARM 0x80000000
+
+/* ------------------------------------------------------------- */
+
+#define DRAM_TIMING_DEF 0x001A01A5
+#define DRAM_AD_SZ_DEF0 0x00000045
+#define DRAM_AD_SZ_NULL 0x00000000
+
+#define SA_CTL_ALLRIGHT 0x64AA0271
+
+#define INIT_XBUS_CYCLE 0x100016DB
+#define INIT_XBUS_STROBE 0xF1F1F1F1
+
+/* ------------------------------------------------------------- */
+
+#define RESET_TIMEOUT (15*HZ) /* 15 sec */
+#define PEEK_POKE_TIMEOUT (HZ/10) /* 0.1 sec */
+
+/* ------------------------------------------------------------- */
+
+#define c4outmeml(addr, value) writel(value, addr)
+#define c4inmeml(addr) readl(addr)
+#define c4outmemw(addr, value) writew(value, addr)
+#define c4inmemw(addr) readw(addr)
+#define c4outmemb(addr, value) writeb(value, addr)
+#define c4inmemb(addr) readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int wait_for_doorbell(avmcard *card, unsigned long t)
+{
+ unsigned long stop;
+
+ stop = jiffies + t;
+ while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+ if (!time_before(jiffies, stop))
+ return -1;
+ }
+ return 0;
+}
+
+static int c4_poke(avmcard *card, unsigned long off, unsigned long value)
+{
+
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+ c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ c4outmeml(card->mbase+MBOX_PEEK_POKE, value);
+ c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR);
+
+ return 0;
+}
+
+static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep)
+{
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+ c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR);
+
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ *valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file)
+{
+ __u32 val;
+ unsigned char *dp;
+ int left, retval;
+ __u32 loadoff = 0;
+
+ dp = t4file->data;
+ left = t4file->len;
+ while (left >= sizeof(__u32)) {
+ if (t4file->user) {
+ retval = copy_from_user(&val, dp, sizeof(val));
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(&val, dp, sizeof(val));
+ }
+ if (c4_poke(card, loadoff, val)) {
+ printk(KERN_ERR "%s: corrupted firmware file ?\n",
+ card->name);
+ return -EIO;
+ }
+ left -= sizeof(__u32);
+ dp += sizeof(__u32);
+ loadoff += sizeof(__u32);
+ }
+ if (left) {
+ val = 0;
+ if (t4file->user) {
+ retval = copy_from_user(&val, dp, left);
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(&val, dp, left);
+ }
+ if (c4_poke(card, loadoff, val)) {
+ printk(KERN_ERR "%s: corrupted firmware file ?\n",
+ card->name);
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, __u8 val)
+{
+ __u8 *s = *pp;
+ *s++ = val;
+ *pp = s;
+}
+
+static inline void _put_word(void **pp, __u32 val)
+{
+ __u8 *s = *pp;
+ *s++ = val & 0xff;
+ *s++ = (val >> 8) & 0xff;
+ *s++ = (val >> 16) & 0xff;
+ *s++ = (val >> 24) & 0xff;
+ *pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+ unsigned i = len;
+ _put_word(pp, i);
+ while (i-- > 0)
+ _put_byte(pp, *dp++);
+}
+
+static inline __u8 _get_byte(void **pp)
+{
+ __u8 *s = *pp;
+ __u8 val;
+ val = *s++;
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_word(void **pp)
+{
+ __u8 *s = *pp;
+ __u32 val;
+ val = *s++;
+ val |= (*s++ << 8);
+ val |= (*s++ << 16);
+ val |= (*s++ << 24);
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_slice(void **pp, unsigned char *dp)
+{
+ unsigned int len, i;
+
+ len = i = _get_word(pp);
+ while (i-- > 0) *dp++ = _get_byte(pp);
+ return len;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_reset(avmcard *card)
+{
+ unsigned long stop;
+
+ c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+ stop = jiffies + HZ*10;
+ while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+ if (!time_before(jiffies, stop))
+ return;
+ c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+ }
+
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_detect(avmcard *card)
+{
+ unsigned long stop, dummy;
+
+ c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+ if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c)
+ return 1;
+
+ c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+ stop = jiffies + HZ*10;
+ while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+ if (!time_before(jiffies, stop))
+ return 2;
+ c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+ }
+
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+
+ c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa);
+ if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3;
+
+ c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55);
+ if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4;
+
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT))
+ return 7;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE))
+ return 8;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE))
+ return 8;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9;
+
+ udelay(1000);
+
+ if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10;
+ if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11;
+ if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12;
+ if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13;
+
+ if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14;
+ if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15;
+ if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16;
+ if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17;
+
+ udelay(1000);
+
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF))
+ return 18;
+
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0))
+ return 19;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL))
+ return 20;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL))
+ return 21;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL))
+ return 22;
+
+ /* Transputer test */
+
+ if ( c4_poke(card, 0x000000, 0x11111111)
+ || c4_poke(card, 0x400000, 0x22222222)
+ || c4_poke(card, 0x800000, 0x33333333)
+ || c4_poke(card, 0xC00000, 0x44444444))
+ return 23;
+
+ if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111
+ || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222
+ || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333
+ || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444)
+ return 24;
+
+ if ( c4_poke(card, 0x000000, 0x55555555)
+ || c4_poke(card, 0x400000, 0x66666666)
+ || c4_poke(card, 0x800000, 0x77777777)
+ || c4_poke(card, 0xC00000, 0x88888888))
+ return 25;
+
+ if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555
+ || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666
+ || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777
+ || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888)
+ return 26;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card)
+{
+ avmcard_dmainfo *dma = card->dma;
+ unsigned long flags;
+ struct sk_buff *skb;
+ __u8 cmd, subcmd;
+ __u16 len;
+ __u32 txlen;
+ void *p;
+
+ save_flags(flags);
+ cli();
+
+ if (card->csr & DBELL_DOWN_ARM) { /* tx busy */
+ restore_flags(flags);
+ return;
+ }
+
+ skb = skb_dequeue(&dma->send_queue);
+ if (!skb) {
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: tx underrun\n", card->name);
+#endif
+ restore_flags(flags);
+ return;
+ }
+
+ len = CAPIMSG_LEN(skb->data);
+
+ if (len) {
+ cmd = CAPIMSG_COMMAND(skb->data);
+ subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+ p = dma->sendbuf;
+
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+ _put_byte(&p, SEND_DATA_B3_REQ);
+ _put_slice(&p, skb->data, len);
+ _put_slice(&p, skb->data + len, dlen);
+ } else {
+ _put_byte(&p, SEND_MESSAGE);
+ _put_slice(&p, skb->data, len);
+ }
+ txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
+#endif
+ } else {
+ txlen = skb->len-2;
+#ifdef CONFIG_C4_POLLDEBUG
+ if (skb->data[2] == SEND_POLLACK)
+ printk(KERN_INFO "%s: ack to c4\n", card->name);
+#endif
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
+ card->name, skb->data[2], txlen);
+#endif
+ memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+ }
+ txlen = (txlen + 3) & ~3;
+
+ c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf));
+ c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen);
+
+ card->csr |= DBELL_DOWN_ARM;
+
+ c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM);
+
+ restore_flags(flags);
+ dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(3, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_POLLACK);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_handle_rx(avmcard *card)
+{
+ avmcard_dmainfo *dma = card->dma;
+ struct capi_ctr *ctrl;
+ avmctrl_info *cinfo;
+ struct sk_buff *skb;
+ void *p = dma->recvbuf;
+ __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+ __u8 b1cmd = _get_byte(&p);
+ __u32 cidx;
+
+
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name,
+ b1cmd, (unsigned long)dma->recvlen);
+#endif
+
+ switch (b1cmd) {
+ case RECEIVE_DATA_B3_IND:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ DataB3Len = _get_slice(&p, card->databuf);
+ cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+ if (MsgLen < 30) { /* not CAPI 64Bit */
+ memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+ MsgLen = 30;
+ CAPIMSG_SETLEN(card->msgbuf, 30);
+ }
+ if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "%s: incoming packet dropped\n",
+ card->name);
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+ if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "%s: incoming packet dropped\n",
+ card->name);
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_NEW_NCCI:
+
+ ApplId = _get_word(&p);
+ NCCI = _get_word(&p);
+ WindowSize = _get_word(&p);
+ cidx = (NCCI&0x7f) - card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+ ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = _get_word(&p);
+ NCCI = _get_word(&p);
+
+ if (NCCI != 0xffffffff) {
+ cidx = (NCCI&0x7f) - card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->free_ncci(ctrl, ApplId, NCCI);
+ } else {
+ for (cidx=0; cidx < 4; cidx++) {
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->appl_released(ctrl, ApplId);
+ }
+ }
+ break;
+
+ case RECEIVE_START:
+#ifdef CONFIG_C4_POLLDEBUG
+ printk(KERN_INFO "%s: poll from c4\n", card->name);
+#endif
+ if (!suppress_pollack)
+ queue_pollack(card);
+ for (cidx=0; cidx < 4; cidx++) {
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->resume_output(ctrl);
+ }
+ break;
+
+ case RECEIVE_STOP:
+ for (cidx=0; cidx < 4; cidx++) {
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->suspend_output(ctrl);
+ }
+ break;
+
+ case RECEIVE_INIT:
+
+ cidx = card->nlogcontr++;
+ cinfo = &card->ctrlinfo[cidx];
+ ctrl = cinfo->capi_ctrl;
+ cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+ b1_parse_version(cinfo);
+ printk(KERN_INFO "%s: %s-card (%s) now active\n",
+ card->name,
+ cinfo->version[VER_CARDTYPE],
+ cinfo->version[VER_DRIVER]);
+ ctrl->ready(cinfo->capi_ctrl);
+ break;
+
+ case RECEIVE_TASK_READY:
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+ card->name, ApplId, card->msgbuf);
+ break;
+
+ case RECEIVE_DEBUGMSG:
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n",
+ card->name, b1cmd);
+ return;
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_handle_interrupt(avmcard *card)
+{
+ __u32 status = c4inmeml(card->mbase+DOORBELL);
+
+ if (status & DBELL_RESET_HOST) {
+ int i;
+ c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+ printk(KERN_ERR "%s: unexpected reset\n", card->name);
+ for (i=0; i < 4; i++) {
+ avmctrl_info *cinfo = &card->ctrlinfo[i];
+ memset(cinfo->version, 0, sizeof(cinfo->version));
+ if (cinfo->capi_ctrl)
+ cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+ }
+ return;
+ }
+
+ status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
+ if (!status)
+ return;
+ c4outmeml(card->mbase+DOORBELL, status);
+
+ if ((status & DBELL_UP_HOST) != 0) {
+ card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN);
+ c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+ c4_handle_rx(card);
+ card->dma->recvlen = 0;
+ c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+ c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+ }
+
+ if ((status & DBELL_DOWN_HOST) != 0) {
+ card->csr &= ~DBELL_DOWN_ARM;
+ c4_dispatch_tx(card);
+ } else if (card->csr & DBELL_DOWN_HOST) {
+ if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) {
+ card->csr &= ~DBELL_DOWN_ARM;
+ c4_dispatch_tx(card);
+ }
+ }
+}
+
+static void c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "%s: interrupt: wrong device\n", card->name);
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "%s: reentering interrupt hander\n",
+ card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ c4_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_send_init(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(15, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_INIT);
+ _put_word(&p, AVM_NAPPS);
+ _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+ _put_word(&p, card->cardnr - 1);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+}
+
+static int c4_send_config(avmcard *card, capiloaddatapart * config)
+{
+ struct sk_buff *skb;
+ __u8 val[sizeof(__u32)];
+ void *p;
+ unsigned char *dp;
+ int left, retval;
+
+ skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, can't send config.\n",
+ card->name);
+ return -ENOMEM;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_CONFIG);
+ _put_word(&p, 1);
+ _put_byte(&p, SEND_CONFIG);
+ _put_word(&p, config->len); /* 12 */
+
+ dp = config->data;
+ left = config->len;
+ while (left >= sizeof(__u32)) {
+ if (config->user) {
+ retval = copy_from_user(val, dp, sizeof(val));
+ if (retval) {
+ dev_kfree_skb(skb);
+ return -EFAULT;
+ }
+ } else {
+ memcpy(val, dp, sizeof(val));
+ }
+ _put_byte(&p, SEND_CONFIG);
+ _put_byte(&p, val[0]);
+ _put_byte(&p, val[1]);
+ _put_byte(&p, val[2]);
+ _put_byte(&p, val[3]);
+ left -= sizeof(val);
+ dp += sizeof(val);
+ }
+ if (left) {
+ memset(val, 0, sizeof(val));
+ if (config->user) {
+ retval = copy_from_user(&val, dp, left);
+ if (retval) {
+ dev_kfree_skb(skb);
+ return -EFAULT;
+ }
+ } else {
+ memcpy(&val, dp, left);
+ }
+ _put_byte(&p, SEND_CONFIG);
+ _put_byte(&p, val[0]);
+ _put_byte(&p, val[1]);
+ _put_byte(&p, val[2]);
+ _put_byte(&p, val[3]);
+ }
+
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+
+ return 0;
+}
+
+static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ unsigned long flags;
+ int retval;
+
+ if ((retval = c4_load_t4file(card, &data->firmware))) {
+ printk(KERN_ERR "%s: failed to load t4file!!\n",
+ card->name);
+ c4_reset(card);
+ return retval;
+ }
+
+ save_flags(flags);
+ cli();
+
+ card->csr = 0;
+ c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+ c4outmeml(card->mbase+MBOX_DOWN_LEN, 0);
+ c4outmeml(card->mbase+DOORBELL, DBELL_INIT);
+ udelay(1000);
+ c4outmeml(card->mbase+DOORBELL,
+ DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST);
+
+ c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08);
+
+ card->dma->recvlen = 0;
+ c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf));
+ c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+ c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+ restore_flags(flags);
+
+ if (data->configuration.len > 0 && data->configuration.data)
+ c4_send_config(card, &data->configuration);
+
+ c4_send_init(card);
+
+ return 0;
+}
+
+
+void c4_reset_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
+ avmctrl_info *cinfo;
+ int i;
+
+ c4_reset(card);
+
+ for (i=0; i < 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ memset(cinfo->version, 0, sizeof(cinfo->version));
+ if (cinfo->capi_ctrl)
+ cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+ }
+}
+
+static void c4_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
+ avmctrl_info *cinfo;
+ int i;
+
+ c4_reset(card);
+
+ for (i=0; i <= 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ if (cinfo->capi_ctrl)
+ di->detach_ctr(cinfo->capi_ctrl);
+ }
+
+ free_irq(card->irq, card);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+
+void c4_register_appl(struct capi_ctr *ctrl,
+ __u16 appl,
+ capi_register_params *rp)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ int want = rp->level3cnt;
+ int nconn;
+ void *p;
+
+ if (ctrl->cnr == card->cardnr) {
+
+ if (want > 0) nconn = want;
+ else nconn = ctrl->profile.nbchannel * 4 * -want;
+ if (nconn == 0) nconn = ctrl->profile.nbchannel * 4;
+
+ skb = alloc_skb(23, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_REGISTER);
+ _put_word(&p, appl);
+ _put_word(&p, 1024 * (nconn+1));
+ _put_word(&p, nconn);
+ _put_word(&p, rp->datablkcnt);
+ _put_word(&p, rp->datablklen);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ }
+
+ ctrl->appl_registered(ctrl, appl);
+}
+
+/* ------------------------------------------------------------- */
+
+void c4_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ void *p;
+
+ if (ctrl->cnr == card->cardnr) {
+ skb = alloc_skb(7, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_RELEASE);
+ _put_word(&p, appl);
+
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+
+static void c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static char *c4_procinfo(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+ if (!cinfo)
+ return "";
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+ cinfo->cardname[0] ? cinfo->cardname : "-",
+ cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+ cinfo->card ? cinfo->card->port : 0x0,
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->membase : 0
+ );
+ return cinfo->infobuf;
+}
+
+static int c4_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ __u8 flag;
+ int len = 0;
+ char *s;
+
+ len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+ len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+ len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+ len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+ switch (card->cardtype) {
+ case avm_b1isa: s = "B1 ISA"; break;
+ case avm_b1pci: s = "B1 PCI"; break;
+ case avm_b1pcmcia: s = "B1 PCMCIA"; break;
+ case avm_m1: s = "M1"; break;
+ case avm_m2: s = "M2"; break;
+ case avm_t1isa: s = "T1 ISA (HEMA)"; break;
+ case avm_t1pci: s = "T1 PCI"; break;
+ case avm_c4: s = "C4"; break;
+ default: s = "???"; break;
+ }
+ len += sprintf(page+len, "%-16s %s\n", "type", s);
+ if ((s = cinfo->version[VER_DRIVER]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ if ((s = cinfo->version[VER_SERIAL]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+ if (card->cardtype != avm_m1) {
+ flag = ((__u8 *)(ctrl->profile.manu))[3];
+ if (flag)
+ len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+ "protocol",
+ (flag & 0x01) ? " DSS1" : "",
+ (flag & 0x02) ? " CT1" : "",
+ (flag & 0x04) ? " VN3" : "",
+ (flag & 0x08) ? " NI1" : "",
+ (flag & 0x10) ? " AUSTEL" : "",
+ (flag & 0x20) ? " ESS" : "",
+ (flag & 0x40) ? " 1TR6" : ""
+ );
+ }
+ if (card->cardtype != avm_m1) {
+ flag = ((__u8 *)(ctrl->profile.manu))[5];
+ if (flag)
+ len += sprintf(page+len, "%-16s%s%s%s%s\n",
+ "linetype",
+ (flag & 0x01) ? " point to point" : "",
+ (flag & 0x02) ? " point to multipoint" : "",
+ (flag & 0x08) ? " leased line without D-channel" : "",
+ (flag & 0x04) ? " leased line with D-channel" : ""
+ );
+ }
+ len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+
+ if (off+count >= len)
+ *eof = 1;
+ if (len < off)
+ return 0;
+ *start = page + off;
+ return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+ unsigned long base, page_offset;
+ avmctrl_info *cinfo;
+ avmcard *card;
+ int retval;
+ int i;
+
+ MOD_INC_USE_COUNT;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+ if (!card->dma) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+ memset(card->dma, 0, sizeof(avmcard_dmainfo));
+ cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
+ if (!cinfo) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+ memset(cinfo, 0, sizeof(avmctrl_info)*4);
+ card->ctrlinfo = cinfo;
+ for (i=0; i < 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ cinfo->card = card;
+ }
+ sprintf(card->name, "c4-%x", p->port);
+ card->port = p->port;
+ card->irq = p->irq;
+ card->membase = p->membase;
+ card->cardtype = avm_c4;
+
+ if (check_region(card->port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "%s: ports 0x%03x-0x%03x in use.\n",
+ driver->name, card->port, card->port + AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ base = card->membase & PAGE_MASK;
+ page_offset = card->membase - base;
+ card->mbase = ioremap_nocache(base, page_offset + 128);
+ if (card->mbase) {
+ card->mbase += page_offset;
+ } else {
+ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
+ driver->name, card->membase);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+
+ if ((retval = c4_detect(card)) != 0) {
+ printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+ driver->name, card->port, retval);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+ c4_reset(card);
+
+ request_region(p->port, AVMB1_PORTLEN, card->name);
+
+ retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ driver->name, card->irq);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ for (i=0; i < 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ cinfo->card = card;
+ cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+ if (!cinfo->capi_ctrl) {
+ printk(KERN_ERR "%s: attach controller failed (%d).\n",
+ driver->name, i);
+ for (i--; i >= 0; i--) {
+ cinfo = &card->ctrlinfo[i];
+ di->detach_ctr(cinfo->capi_ctrl);
+ }
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->dma);
+ kfree(card->ctrlinfo);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+ if (i == 0)
+ card->cardnr = cinfo->capi_ctrl->cnr;
+ }
+
+ skb_queue_head_init(&card->dma->send_queue);
+
+ printk(KERN_INFO
+ "%s: AVM C4 at i/o %#x, irq %d, mem %#lx\n",
+ driver->name, card->port, card->irq, card->membase);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver c4_driver = {
+ "c4",
+ "0.0",
+ c4_load_firmware,
+ c4_reset_ctr,
+ c4_remove_ctr,
+ c4_register_appl,
+ c4_release_appl,
+ c4_send_message,
+
+ c4_procinfo,
+ c4_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ 0, /* no add_card function */
+};
+
+#ifdef MODULE
+#define c4_init init_module
+void cleanup_module(void);
+#endif
+
+
+static int ncards = 0;
+
+int c4_init(void)
+{
+ struct capi_driver *driver = &c4_driver;
+ struct pci_dev *dev = NULL;
+ char *p;
+ int retval;
+
+ if ((p = strchr(revision, ':'))) {
+ strncpy(driver->revision, p + 1, sizeof(driver->revision));
+ p = strchr(driver->revision, '$');
+ *p = 0;
+ }
+
+ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+
+ di = attach_capi_driver(driver);
+
+ if (!di) {
+ printk(KERN_ERR "%s: failed to attach capi_driver\n",
+ driver->name);
+ return -EIO;
+ }
+
+#ifdef CONFIG_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
+ detach_capi_driver(driver);
+ return -EIO;
+ }
+
+ while ((dev = pci_find_subsys(
+ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285,
+ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) {
+ struct capicardparams param;
+
+ param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
+ param.irq = dev->irq;
+ param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK;
+
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n",
+ driver->name, param.port, param.irq, param.membase);
+ retval = c4_add_card(driver, &param);
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n",
+ driver->name, param.port, param.irq, param.membase);
+#ifdef MODULE
+ cleanup_module();
+#endif
+ return retval;
+ }
+ ncards++;
+ }
+ if (ncards) {
+ printk(KERN_INFO "%s: %d C4 card(s) detected\n",
+ driver->name, ncards);
+ return 0;
+ }
+ printk(KERN_ERR "%s: NO C4 card detected\n", driver->name);
+ return -ESRCH;
+#else
+ printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+ return -EIO;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ detach_capi_driver(&c4_driver);
+}
+#endif
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 6214a7c75..62f246407 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -128,6 +128,7 @@
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
+#include <linux/devfs_fs_kernel.h>
#include "capiutil.h"
#include "capicmd.h"
@@ -511,13 +512,18 @@ capi_release(struct inode *inode, struct file *file)
static struct file_operations capi_fops =
{
- llseek: capi_llseek,
- read: capi_read,
- write: capi_write,
- poll: capi_poll,
- ioctl: capi_ioctl,
- open: capi_open,
- release: capi_release,
+ capi_llseek,
+ capi_read,
+ capi_write,
+ NULL, /* capi_readdir */
+ capi_poll,
+ capi_ioctl,
+ NULL, /* capi_mmap */
+ capi_open,
+ NULL, /* capi_flush */
+ capi_release,
+ NULL, /* capi_fsync */
+ NULL, /* capi_fasync */
};
/* -------- /proc functions ----------------------------------- */
@@ -616,14 +622,36 @@ int capi_init(void)
init_waitqueue_head(&capidevs[j].recv_wait);
}
- if (register_chrdev(capi_major, "capi20", &capi_fops)) {
+ if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) {
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
return -EIO;
}
+ devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT,
+ capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capi_fops, NULL);
+ devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT,
+ capi_major, 1,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capi_fops, NULL);
+ devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT,
+ capi_major, 11,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capi_fops, NULL);
printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
- unregister_chrdev(capi_major, "capi20");
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
+ capi_major, 0,
+ DEVFS_SPECIAL_CHR, 0));
+ for (j = 0; j < 10; j++) {
+ char devname[32];
+
+ sprintf(devname, "isdn/capi20.0%i", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0));
+ sprintf (devname, "isdn/capi20.1%i", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0));
+ }
return -EIO;
}
(void)proc_init();
@@ -633,8 +661,18 @@ int capi_init(void)
#ifdef MODULE
void cleanup_module(void)
{
+ int i;
+ char devname[32];
+
(void)proc_exit();
- unregister_chrdev(capi_major, "capi20");
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0));
+ for (i = 0; i < 10; i++) {
+ sprintf (devname, "isdn/capi20.0%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 1, DEVFS_SPECIAL_CHR, 0));
+ sprintf (devname, "isdn/capi20.1%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 11, DEVFS_SPECIAL_CHR, 0));
+ }
(void) detach_capi_interface(&cuser);
}
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index 6db170e42..79bb370d1 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -1,11 +1,14 @@
/*
- * $Id: capidrv.c,v 1.28 1999/11/05 16:22:37 calle Exp $
+ * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidrv.c,v $
+ * Revision 1.29 1999/12/06 17:13:06 calle
+ * Added controller watchdog.
+ *
* Revision 1.28 1999/11/05 16:22:37 calle
* Bugfix: Missing break in switch on ISDN_CMD_HANGUP.
*
@@ -168,7 +171,7 @@
#include "capicmd.h"
#include "capidrv.h"
-static char *revision = "$Revision: 1.28 $";
+static char *revision = "$Revision: 1.29 $";
int debugmode = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -196,6 +199,7 @@ struct capidrv_contr {
int state;
__u32 cipmask;
__u32 cipmask2;
+ struct timer_list listentimer;
/*
* ID of capi message sent
@@ -2188,6 +2192,29 @@ static void disable_dchannel_trace(capidrv_contr *card)
send_message(card, &cmdcmsg);
}
+static void send_listen(capidrv_contr *card)
+{
+ capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
+ card->msgid++,
+ card->contrnr, /* controller */
+ 1 << 6, /* Infomask */
+ card->cipmask,
+ card->cipmask2,
+ 0, 0);
+ send_message(card, &cmdcmsg);
+ listen_change_state(card, EV_LISTEN_REQ);
+}
+
+static void listentimerfunc(unsigned long x)
+{
+ capidrv_contr *card = (capidrv_contr *)x;
+ if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
+ printk(KERN_ERR "%s: controller dead ??\n", card->name);
+ send_listen(card);
+ mod_timer(&card->listentimer, jiffies + 60*HZ);
+}
+
+
static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
{
capidrv_contr *card;
@@ -2202,6 +2229,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
return -1;
}
memset(card, 0, sizeof(capidrv_contr));
+ init_timer(&card->listentimer);
strcpy(card->name, id);
card->contrnr = contr;
card->nbchan = profp->nbchannel;
@@ -2258,15 +2286,11 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
card->cipmask = 0x1FFF03FF; /* any */
card->cipmask2 = 0;
- capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
- card->msgid++,
- contr, /* controller */
- 1 << 6, /* Infomask */
- card->cipmask,
- card->cipmask2,
- 0, 0);
- send_message(card, &cmdcmsg);
- listen_change_state(card, EV_LISTEN_REQ);
+ send_listen(card);
+
+ card->listentimer.data = (unsigned long)card;
+ card->listentimer.function = listentimerfunc;
+ mod_timer(&card->listentimer, jiffies + 60*HZ);
printk(KERN_INFO "%s: now up (%d B channels)\n",
card->name, card->nbchan);
@@ -2312,6 +2336,7 @@ static int capidrv_delcontr(__u16 contr)
printk(KERN_ERR "capidrv: bug in free_plci()\n");
}
kfree(card->bchans);
+ del_timer(&card->listentimer);
printk(KERN_INFO "%s: now down.\n", card->name);
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
index 84fb0d2f7..d82fbc496 100644
--- a/drivers/isdn/avmb1/kcapi.c
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -1,11 +1,18 @@
/*
- * $Id: kcapi.c,v 1.10 1999/10/26 15:30:32 calle Exp $
+ * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $
*
* Kernel CAPI 2.0 Module
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: kcapi.c,v $
+ * Revision 1.12 2000/01/28 16:45:39 calle
+ * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
+ * will search named driver and call the add_card function if one exist.
+ *
+ * Revision 1.11 1999/11/23 13:29:29 calle
+ * Bugfix: incoming capi message were never traced.
+ *
* Revision 1.10 1999/10/26 15:30:32 calle
* Generate error message if user want to add card, but driver module is
* not loaded.
@@ -79,7 +86,7 @@
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.12 $";
/* ------------------------------------------------------------- */
@@ -154,10 +161,6 @@ static int ncards = 0;
static struct sk_buff_head recv_queue;
static struct capi_interface_user *capi_users = 0;
static struct capi_driver *drivers;
-#ifdef CONFIG_AVMB1_COMPAT
-static struct capi_driver *b1isa_driver;
-static struct capi_driver *t1isa_driver;
-#endif
static long notify_up_set = 0;
static long notify_down_set = 0;
@@ -703,9 +706,9 @@ static void controllercb_handle_capimsg(struct capi_ctr * card,
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
card->nrecvdatapkt++;
if (card->traceflag > 2) showctl |= 2;
- if (card->traceflag) showctl |= 2;
} else {
card->nrecvctlpkt++;
+ if (card->traceflag) showctl |= 2;
}
showctl |= (card->traceflag & 1);
if (showctl & 2) {
@@ -877,8 +880,14 @@ drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata)
*pp = card;
driver->ncontroller++;
sprintf(card->procfn, "capi/controllers/%d", card->cnr);
- card->procent = create_proc_read_entry(card->procfn, 0, 0,
- driver->ctr_read_proc, card);
+ card->procent = create_proc_entry(card->procfn, 0, 0);
+ if (card->procent) {
+ card->procent->read_proc =
+ (int (*)(char *,char **,off_t,int,int *,void *))
+ driver->ctr_read_proc;
+ card->procent->data = card;
+ }
+
ncards++;
printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
card->cnr, card->name);
@@ -947,18 +956,18 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
driver->next = 0;
*pp = driver;
printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
-#ifdef CONFIG_AVMB1_COMPAT
- if (strcmp(driver->name, "b1isa") == 0 && driver->add_card)
- b1isa_driver = driver;
- if (strcmp(driver->name, "t1isa") == 0 && driver->add_card)
- t1isa_driver = driver;
-#endif
sprintf(driver->procfn, "capi/drivers/%s", driver->name);
- driver->procent = create_proc_read_entry(driver->procfn, 0, 0,
- driver->driver_read_proc
- ? driver->driver_read_proc
- : driver_read_proc,
- driver);
+ driver->procent = create_proc_entry(driver->procfn, 0, 0);
+ if (driver->procent) {
+ if (driver->driver_read_proc) {
+ driver->procent->read_proc =
+ (int (*)(char *,char **,off_t,int,int *,void *))
+ driver->driver_read_proc;
+ } else {
+ driver->procent->read_proc = driver_read_proc;
+ }
+ driver->procent->data = driver;
+ }
return &di;
}
@@ -968,10 +977,6 @@ void detach_capi_driver(struct capi_driver *driver)
for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
if (*pp) {
*pp = (*pp)->next;
-#ifdef CONFIG_AVMB1_COMPAT
- if (driver == b1isa_driver) b1isa_driver = 0;
- if (driver == t1isa_driver) t1isa_driver = 0;
-#endif
printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name);
} else {
printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
@@ -1186,6 +1191,15 @@ static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp)
return CAPI_NOERROR;
}
+static struct capi_driver *find_driver(char *name)
+{
+ struct capi_driver *dp;
+ for (dp = drivers; dp; dp = dp->next)
+ if (strcmp(dp->name, name) == 0)
+ return dp;
+ return 0;
+}
+
#ifdef CONFIG_AVMB1_COMPAT
static int old_capi_manufacturer(unsigned int cmd, void *data)
{
@@ -1217,9 +1231,15 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
cparams.cardnr = cdef.cardnr;
switch (cdef.cardtype) {
- case AVM_CARDTYPE_B1: driver = b1isa_driver; break;
- case AVM_CARDTYPE_T1: driver = t1isa_driver; break;
- default: driver = 0;
+ case AVM_CARDTYPE_B1:
+ driver = find_driver("b1isa");
+ break;
+ case AVM_CARDTYPE_T1:
+ driver = find_driver("t1isa");
+ break;
+ default:
+ driver = 0;
+ break;
}
if (!driver) {
printk(KERN_ERR "kcapi: driver not loaded.\n");
@@ -1331,9 +1351,7 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
return -ESRCH;
gdef.cardstate = card->cardstate;
- if (card->driver == b1isa_driver)
- gdef.cardtype = AVM_CARDTYPE_B1;
- else if (card->driver == t1isa_driver)
+ if (card->driver == find_driver("t1isa"))
gdef.cardtype = AVM_CARDTYPE_T1;
else gdef.cardtype = AVM_CARDTYPE_B1;
@@ -1377,7 +1395,6 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
static int capi_manufacturer(unsigned int cmd, void *data)
{
struct capi_ctr *card;
- kcapi_flagdef fdef;
int retval;
switch (cmd) {
@@ -1392,6 +1409,9 @@ static int capi_manufacturer(unsigned int cmd, void *data)
return old_capi_manufacturer(cmd, data);
#endif
case KCAPI_CMD_TRACE:
+ {
+ kcapi_flagdef fdef;
+
if ((retval = copy_from_user((void *) &fdef, data,
sizeof(kcapi_flagdef))))
return retval;
@@ -1406,6 +1426,44 @@ static int capi_manufacturer(unsigned int cmd, void *data)
card->cnr, card->traceflag);
return 0;
}
+
+ case KCAPI_CMD_ADDCARD:
+ {
+ struct capi_driver *driver;
+ capicardparams cparams;
+ kcapi_carddef cdef;
+
+ if ((retval = copy_from_user((void *) &cdef, data,
+ sizeof(cdef))))
+ return retval;
+
+ cparams.port = cdef.port;
+ cparams.irq = cdef.irq;
+ cparams.membase = cdef.membase;
+ cparams.cardnr = cdef.cardnr;
+ cparams.cardtype = 0;
+ cdef.driver[sizeof(cdef.driver)-1] = 0;
+
+ if ((driver = find_driver(cdef.driver)) == 0) {
+ printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
+ cdef.driver);
+ return -ESRCH;
+ }
+
+ if (!driver->add_card) {
+ printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
+ return -EIO;
+ }
+
+ return driver->add_card(driver, &cparams);
+ }
+
+ default:
+ printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
+ cmd);
+ break;
+
+ }
return -EINVAL;
}
diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c
index 22a07f2ad..e1efd3939 100644
--- a/drivers/isdn/avmb1/t1isa.c
+++ b/drivers/isdn/avmb1/t1isa.c
@@ -1,11 +1,19 @@
/*
- * $Id: t1isa.c,v 1.8 1999/11/05 16:38:01 calle Exp $
+ * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 calle Exp $
*
* Module for AVM T1 HEMA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: t1isa.c,v $
+ * Revision 1.10 2000/02/02 18:36:04 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.9 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
* Revision 1.8 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -73,7 +81,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.8 $";
+static char *revision = "$Revision: 1.10 $";
/* ------------------------------------------------------------- */
@@ -413,10 +421,13 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
avmcard *card;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -424,6 +435,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -440,6 +452,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
@@ -449,6 +462,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
if (hema_irq_table[card->irq & 0xf] == 0) {
@@ -456,6 +470,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->irq);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
@@ -465,6 +480,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->cardnr, cardp->port);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
}
@@ -473,6 +489,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
t1_disable_irq(card->port);
@@ -487,6 +504,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -498,10 +516,14 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- MOD_INC_USE_COUNT;
+ printk(KERN_INFO
+ "%s: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
+ driver->name, card->port, card->irq, card->cardnr);
+
return 0;
}
diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c
index d77340bff..d24894d9b 100644
--- a/drivers/isdn/avmb1/t1pci.c
+++ b/drivers/isdn/avmb1/t1pci.c
@@ -1,11 +1,20 @@
/*
- * $Id: t1pci.c,v 1.3 1999/11/13 21:27:16 keil Exp $
+ * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $
*
* Module for AVM T1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: t1pci.c,v $
+ * Revision 1.5 2000/02/02 18:36:04 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.4 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.3 1999/11/13 21:27:16 keil
* remove KERNELVERSION
*
@@ -38,7 +47,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.5 $";
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
@@ -55,712 +64,20 @@ static char *revision = "$Revision: 1.3 $";
/* ------------------------------------------------------------- */
-int suppress_pollack = 0;
-
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-MODULE_PARM(suppress_pollack, "0-1i");
-
-
/* ------------------------------------------------------------- */
static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
-static void t1pci_dispatch_tx(avmcard *card);
-
-/* ------------------------------------------------------------- */
-
-/* S5933 */
-
-#define AMCC_RXPTR 0x24
-#define AMCC_RXLEN 0x28
-#define AMCC_TXPTR 0x2c
-#define AMCC_TXLEN 0x30
-
-#define AMCC_INTCSR 0x38
-# define EN_READ_TC_INT 0x00008000L
-# define EN_WRITE_TC_INT 0x00004000L
-# define EN_TX_TC_INT EN_READ_TC_INT
-# define EN_RX_TC_INT EN_WRITE_TC_INT
-# define AVM_FLAG 0x30000000L
-
-# define ANY_S5933_INT 0x00800000L
-# define READ_TC_INT 0x00080000L
-# define WRITE_TC_INT 0x00040000L
-# define TX_TC_INT READ_TC_INT
-# define RX_TC_INT WRITE_TC_INT
-# define MASTER_ABORT_INT 0x00100000L
-# define TARGET_ABORT_INT 0x00200000L
-# define BUS_MASTER_INT 0x00200000L
-# define ALL_INT 0x000C0000L
-
-#define AMCC_MCSR 0x3c
-# define A2P_HI_PRIORITY 0x00000100L
-# define EN_A2P_TRANSFERS 0x00000400L
-# define P2A_HI_PRIORITY 0x00001000L
-# define EN_P2A_TRANSFERS 0x00004000L
-# define RESET_A2P_FLAGS 0x04000000L
-# define RESET_P2A_FLAGS 0x02000000L
-
-/* ------------------------------------------------------------- */
-
-#define t1outmeml(addr, value) writel(value, addr)
-#define t1inmeml(addr) readl(addr)
-#define t1outmemw(addr, value) writew(value, addr)
-#define t1inmemw(addr) readw(addr)
-#define t1outmemb(addr, value) writeb(value, addr)
-#define t1inmemb(addr) readb(addr)
-
-/* ------------------------------------------------------------- */
-
-static inline int t1pci_tx_empty(unsigned int port)
-{
- return inb(port + 0x03) & 0x1;
-}
-
-static inline int t1pci_rx_full(unsigned int port)
-{
- return inb(port + 0x02) & 0x1;
-}
-
-static int t1pci_tolink(avmcard *card, void *buf, unsigned int len)
-{
- unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
- unsigned char *s = (unsigned char *)buf;
- while (len--) {
- while ( !t1pci_tx_empty(card->port)
- && time_before(jiffies, stop));
- if (!t1pci_tx_empty(card->port))
- return -1;
- t1outp(card->port, 0x01, *s++);
- }
- return 0;
-}
-
-static int t1pci_fromlink(avmcard *card, void *buf, unsigned int len)
-{
- unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
- unsigned char *s = (unsigned char *)buf;
- while (len--) {
- while ( !t1pci_rx_full(card->port)
- && time_before(jiffies, stop));
- if (!t1pci_rx_full(card->port))
- return -1;
- *s++ = t1inp(card->port, 0x00);
- }
- return 0;
-}
-
-static int WriteReg(avmcard *card, __u32 reg, __u8 val)
-{
- __u8 cmd = 0x00;
- if ( t1pci_tolink(card, &cmd, 1) == 0
- && t1pci_tolink(card, &reg, 4) == 0) {
- __u32 tmp = val;
- return t1pci_tolink(card, &tmp, 4);
- }
- return -1;
-}
-
-static __u8 ReadReg(avmcard *card, __u32 reg)
-{
- __u8 cmd = 0x01;
- if ( t1pci_tolink(card, &cmd, 1) == 0
- && t1pci_tolink(card, &reg, 4) == 0) {
- __u32 tmp;
- if (t1pci_fromlink(card, &tmp, 4) == 0)
- return (__u8)tmp;
- }
- return 0xff;
-}
-
-/* ------------------------------------------------------------- */
-
-static inline void _put_byte(void **pp, __u8 val)
-{
- __u8 *s = *pp;
- *s++ = val;
- *pp = s;
-}
-
-static inline void _put_word(void **pp, __u32 val)
-{
- __u8 *s = *pp;
- *s++ = val & 0xff;
- *s++ = (val >> 8) & 0xff;
- *s++ = (val >> 16) & 0xff;
- *s++ = (val >> 24) & 0xff;
- *pp = s;
-}
-
-static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
-{
- unsigned i = len;
- _put_word(pp, i);
- while (i-- > 0)
- _put_byte(pp, *dp++);
-}
-
-static inline __u8 _get_byte(void **pp)
-{
- __u8 *s = *pp;
- __u8 val;
- val = *s++;
- *pp = s;
- return val;
-}
-
-static inline __u32 _get_word(void **pp)
-{
- __u8 *s = *pp;
- __u32 val;
- val = *s++;
- val |= (*s++ << 8);
- val |= (*s++ << 16);
- val |= (*s++ << 24);
- *pp = s;
- return val;
-}
-
-static inline __u32 _get_slice(void **pp, unsigned char *dp)
-{
- unsigned int len, i;
-
- len = i = _get_word(pp);
- while (i-- > 0) *dp++ = _get_byte(pp);
- return len;
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_reset(avmcard *card)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- card->csr = 0x0;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- t1outmeml(card->mbase+AMCC_RXLEN, 0);
- t1outmeml(card->mbase+AMCC_TXLEN, 0);
-
- t1outp(card->port, T1_RESETLINK, 0x00);
- t1outp(card->port, 0x07, 0x00);
-
- restore_flags(flags);
-
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(42 * 1000);
-
-}
-
-/* ------------------------------------------------------------- */
-
-static int t1pci_detect(avmcard *card)
-{
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(42 * 1000);
-
- t1outmeml(card->mbase+AMCC_RXLEN, 0);
- t1outmeml(card->mbase+AMCC_TXLEN, 0);
- card->csr = 0x0;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
-
- if (t1inmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
- return 1;
-
- t1outmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
- t1outmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
- if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
- || t1inmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
- return 2;
-
- t1outmeml(card->mbase+AMCC_RXPTR, 0x0);
- t1outmeml(card->mbase+AMCC_TXPTR, 0x0);
- if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0x0
- || t1inmeml(card->mbase+AMCC_TXPTR) != 0x0)
- return 3;
-
- t1outp(card->port, T1_RESETLINK, 0x00);
- t1outp(card->port, 0x07, 0x00);
-
- t1outp(card->port, 0x02, 0x02);
- t1outp(card->port, 0x03, 0x02);
-
- if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02
- || t1inp(card->port, 0x3) != 0x03)
- return 4;
-
- t1outp(card->port, 0x02, 0x00);
- t1outp(card->port, 0x03, 0x00);
-
- if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00
- || t1inp(card->port, 0x3) != 0x01)
- return 5;
-
- /* Transputer test */
-
- if ( WriteReg(card, 0x80001000, 0x11) != 0
- || WriteReg(card, 0x80101000, 0x22) != 0
- || WriteReg(card, 0x80201000, 0x33) != 0
- || WriteReg(card, 0x80301000, 0x44) != 0)
- return 6;
-
- if ( ReadReg(card, 0x80001000) != 0x11
- || ReadReg(card, 0x80101000) != 0x22
- || ReadReg(card, 0x80201000) != 0x33
- || ReadReg(card, 0x80301000) != 0x44)
- return 7;
-
- if ( WriteReg(card, 0x80001000, 0x55) != 0
- || WriteReg(card, 0x80101000, 0x66) != 0
- || WriteReg(card, 0x80201000, 0x77) != 0
- || WriteReg(card, 0x80301000, 0x88) != 0)
- return 8;
-
- if ( ReadReg(card, 0x80001000) != 0x55
- || ReadReg(card, 0x80101000) != 0x66
- || ReadReg(card, 0x80201000) != 0x77
- || ReadReg(card, 0x80301000) != 0x88)
- return 9;
-
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_dispatch_tx(avmcard *card)
-{
- avmcard_dmainfo *dma = card->dma;
- unsigned long flags;
- struct sk_buff *skb;
- __u8 cmd, subcmd;
- __u16 len;
- __u32 txlen;
- int inint;
- void *p;
-
- save_flags(flags);
- cli();
-
- inint = card->interrupt;
-
- if (card->csr & EN_TX_TC_INT) { /* tx busy */
- restore_flags(flags);
- return;
- }
-
- skb = skb_dequeue(&dma->send_queue);
- if (!skb) {
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "tx(%d): underrun\n", inint);
-#endif
- restore_flags(flags);
- return;
- }
-
- len = CAPIMSG_LEN(skb->data);
-
- if (len) {
- cmd = CAPIMSG_COMMAND(skb->data);
- subcmd = CAPIMSG_SUBCOMMAND(skb->data);
-
- p = dma->sendbuf;
-
- if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
- __u16 dlen = CAPIMSG_DATALEN(skb->data);
- _put_byte(&p, SEND_DATA_B3_REQ);
- _put_slice(&p, skb->data, len);
- _put_slice(&p, skb->data + len, dlen);
- } else {
- _put_byte(&p, SEND_MESSAGE);
- _put_slice(&p, skb->data, len);
- }
- txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
- inint, txlen);
-#endif
- } else {
- txlen = skb->len-2;
-#ifdef CONFIG_T1PCI_POLLDEBUG
- if (skb->data[2] == SEND_POLLACK)
- printk(KERN_INFO "%s: ack to t1\n", card->name);
-#endif
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
- inint, skb->data[2], txlen);
-#endif
- memcpy(dma->sendbuf, skb->data+2, skb->len-2);
- }
- txlen = (txlen + 3) & ~3;
-
- t1outmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
- t1outmeml(card->mbase+AMCC_TXLEN, txlen);
-
- card->csr |= EN_TX_TC_INT;
-
- if (!inint)
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
-
- restore_flags(flags);
- dev_kfree_skb(skb);
-}
-
-/* ------------------------------------------------------------- */
-
-static void queue_pollack(avmcard *card)
-{
- struct sk_buff *skb;
- void *p;
-
- skb = alloc_skb(3, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost poll ack\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_POLLACK);
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_handle_rx(avmcard *card)
-{
- avmctrl_info *cinfo = &card->ctrlinfo[0];
- avmcard_dmainfo *dma = card->dma;
- struct capi_ctr *ctrl = cinfo->capi_ctrl;
- struct sk_buff *skb;
- void *p = dma->recvbuf+4;
- __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
- __u8 b1cmd = _get_byte(&p);
-
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
-#endif
-
- switch (b1cmd) {
- case RECEIVE_DATA_B3_IND:
-
- ApplId = (unsigned) _get_word(&p);
- MsgLen = _get_slice(&p, card->msgbuf);
- DataB3Len = _get_slice(&p, card->databuf);
-
- if (MsgLen < 30) { /* not CAPI 64Bit */
- memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
- MsgLen = 30;
- CAPIMSG_SETLEN(card->msgbuf, 30);
- }
- if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
- printk(KERN_ERR "%s: incoming packet dropped\n",
- card->name);
- } else {
- memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
- memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
- ctrl->handle_capimsg(ctrl, ApplId, skb);
- }
- break;
-
- case RECEIVE_MESSAGE:
-
- ApplId = (unsigned) _get_word(&p);
- MsgLen = _get_slice(&p, card->msgbuf);
- if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
- printk(KERN_ERR "%s: incoming packet dropped\n",
- card->name);
- } else {
- memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
- ctrl->handle_capimsg(ctrl, ApplId, skb);
- }
- break;
-
- case RECEIVE_NEW_NCCI:
-
- ApplId = _get_word(&p);
- NCCI = _get_word(&p);
- WindowSize = _get_word(&p);
-
- ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
-
- break;
-
- case RECEIVE_FREE_NCCI:
-
- ApplId = _get_word(&p);
- NCCI = _get_word(&p);
-
- if (NCCI != 0xffffffff)
- ctrl->free_ncci(ctrl, ApplId, NCCI);
- else ctrl->appl_released(ctrl, ApplId);
- break;
-
- case RECEIVE_START:
-#ifdef CONFIG_T1PCI_POLLDEBUG
- printk(KERN_INFO "%s: poll from t1\n", card->name);
-#endif
- if (!suppress_pollack)
- queue_pollack(card);
- ctrl->resume_output(ctrl);
- break;
-
- case RECEIVE_STOP:
- ctrl->suspend_output(ctrl);
- break;
-
- case RECEIVE_INIT:
-
- cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
- b1_parse_version(cinfo);
- printk(KERN_INFO "%s: %s-card (%s) now active\n",
- card->name,
- cinfo->version[VER_CARDTYPE],
- cinfo->version[VER_DRIVER]);
- ctrl->ready(ctrl);
- break;
-
- case RECEIVE_TASK_READY:
- ApplId = (unsigned) _get_word(&p);
- MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
- printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
- card->name, ApplId, card->msgbuf);
- break;
-
- case RECEIVE_DEBUGMSG:
- MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
- printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
- break;
-
- default:
- printk(KERN_ERR "%s: t1pci_interrupt: 0x%x ???\n",
- card->name, b1cmd);
- return;
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_handle_interrupt(avmcard *card)
-{
- __u32 status = t1inmeml(card->mbase+AMCC_INTCSR);
- __u32 newcsr;
-
- if ((status & ANY_S5933_INT) == 0)
- return;
-
- newcsr = card->csr | (status & ALL_INT);
- if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
- if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
- t1outmeml(card->mbase+AMCC_INTCSR, newcsr);
-
- if ((status & RX_TC_INT) != 0) {
- __u8 *recvbuf = card->dma->recvbuf;
- __u32 rxlen;
- if (card->dma->recvlen == 0) {
- card->dma->recvlen = *((__u32 *)recvbuf);
- rxlen = (card->dma->recvlen + 3) & ~3;
- t1outmeml(card->mbase+AMCC_RXPTR,
- virt_to_phys(recvbuf+4));
- t1outmeml(card->mbase+AMCC_RXLEN, rxlen);
- } else {
- t1pci_handle_rx(card);
- card->dma->recvlen = 0;
- t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
- t1outmeml(card->mbase+AMCC_RXLEN, 4);
- }
- }
-
- if ((status & TX_TC_INT) != 0) {
- card->csr &= ~EN_TX_TC_INT;
- t1pci_dispatch_tx(card);
- } else if (card->csr & EN_TX_TC_INT) {
- if (t1inmeml(card->mbase+AMCC_TXLEN) == 0) {
- card->csr &= ~EN_TX_TC_INT;
- t1pci_dispatch_tx(card);
- }
- }
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
-}
-
-static void t1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
-{
- avmcard *card;
-
- card = (avmcard *) devptr;
-
- if (!card) {
- printk(KERN_WARNING "t1pci: interrupt: wrong device\n");
- return;
- }
- if (card->interrupt) {
- printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
- return;
- }
-
- card->interrupt = 1;
-
- t1pci_handle_interrupt(card);
-
- card->interrupt = 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static int t1pci_loaded(avmcard *card)
-{
- unsigned long stop;
- unsigned char ans;
- unsigned long tout = 2;
- unsigned int base = card->port;
-
- for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
- if (b1_tx_empty(base))
- break;
- }
- if (!b1_tx_empty(base)) {
- printk(KERN_ERR "%s: t1pci_loaded: tx err, corrupted t4 file ?\n",
- card->name);
- return 0;
- }
- b1_put_byte(base, SEND_POLLACK);
- for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
- if (b1_rx_full(base)) {
- if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
- return 1;
- }
- printk(KERN_ERR "%s: t1pci_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
- return 0;
- }
- }
- printk(KERN_ERR "%s: t1pci_loaded: firmware not running\n", card->name);
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_send_init(avmcard *card)
-{
- struct sk_buff *skb;
- void *p;
-
- skb = alloc_skb(15, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost register appl.\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_INIT);
- _put_word(&p, AVM_NAPPS);
- _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
- _put_word(&p, card->cardnr - 1);
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-static int t1pci_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- unsigned long flags;
- int retval;
-
- t1pci_reset(card);
-
- if ((retval = b1_load_t4file(card, &data->firmware))) {
- t1pci_reset(card);
- printk(KERN_ERR "%s: failed to load t4file!!\n",
- card->name);
- return retval;
- }
-
- if (data->configuration.len > 0 && data->configuration.data) {
- if ((retval = b1_load_config(card, &data->configuration))) {
- t1pci_reset(card);
- printk(KERN_ERR "%s: failed to load config!!\n",
- card->name);
- return retval;
- }
- }
-
- if (!t1pci_loaded(card)) {
- t1pci_reset(card);
- printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
- return -EIO;
- }
-
- save_flags(flags);
- cli();
-
- card->csr = AVM_FLAG;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
- t1outmeml(card->mbase+AMCC_MCSR,
- EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
- |A2P_HI_PRIORITY|P2A_HI_PRIORITY
- |RESET_A2P_FLAGS|RESET_P2A_FLAGS);
- t1outp(card->port, 0x07, 0x30);
- t1outp(card->port, 0x10, 0xF0);
-
- card->dma->recvlen = 0;
- t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
- t1outmeml(card->mbase+AMCC_RXLEN, 4);
- card->csr |= EN_RX_TC_INT;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
- restore_flags(flags);
-
- t1pci_send_init(card);
-
- return 0;
-}
-
-void t1pci_reset_ctr(struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
-
- t1pci_reset(card);
-
- memset(cinfo->version, 0, sizeof(cinfo->version));
- ctrl->reseted(ctrl);
-}
-
static void t1pci_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
- t1pci_reset(card);
+ b1dma_reset(card);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
@@ -776,210 +93,20 @@ static void t1pci_remove_ctr(struct capi_ctr *ctrl)
/* ------------------------------------------------------------- */
-
-void t1pci_register_appl(struct capi_ctr *ctrl,
- __u16 appl,
- capi_register_params *rp)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- struct sk_buff *skb;
- int want = rp->level3cnt;
- int nconn;
- void *p;
-
- if (want > 0) nconn = want;
- else nconn = ctrl->profile.nbchannel * -want;
- if (nconn == 0) nconn = ctrl->profile.nbchannel;
-
- skb = alloc_skb(23, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost register appl.\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_REGISTER);
- _put_word(&p, appl);
- _put_word(&p, 1024 * (nconn+1));
- _put_word(&p, nconn);
- _put_word(&p, rp->datablkcnt);
- _put_word(&p, rp->datablklen);
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-
- ctrl->appl_registered(ctrl, appl);
-}
-
-/* ------------------------------------------------------------- */
-
-void t1pci_release_appl(struct capi_ctr *ctrl, __u16 appl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- struct sk_buff *skb;
- void *p;
-
- skb = alloc_skb(7, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost release appl.\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_RELEASE);
- _put_word(&p, appl);
-
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-/* ------------------------------------------------------------- */
-
-
-static void t1pci_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-/* ------------------------------------------------------------- */
-
-static char *t1pci_procinfo(struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-
- if (!cinfo)
- return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
- cinfo->cardname[0] ? cinfo->cardname : "-",
- cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
- cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0,
- cinfo->card ? cinfo->card->membase : 0
- );
- return cinfo->infobuf;
-}
-
-static int t1pci_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- unsigned long flags;
- __u8 flag;
- int len = 0;
- char *s;
- __u32 txaddr, txlen, rxaddr, rxlen, csr;
-
- len += sprintf(page+len, "%-16s %s\n", "name", card->name);
- len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
- len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
- len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
- switch (card->cardtype) {
- case avm_b1isa: s = "B1 ISA"; break;
- case avm_b1pci: s = "B1 PCI"; break;
- case avm_b1pcmcia: s = "B1 PCMCIA"; break;
- case avm_m1: s = "M1"; break;
- case avm_m2: s = "M2"; break;
- case avm_t1isa: s = "T1 ISA (HEMA)"; break;
- case avm_t1pci: s = "T1 PCI"; break;
- case avm_c4: s = "C4"; break;
- default: s = "???"; break;
- }
- len += sprintf(page+len, "%-16s %s\n", "type", s);
- if ((s = cinfo->version[VER_DRIVER]) != 0)
- len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
- if ((s = cinfo->version[VER_CARDTYPE]) != 0)
- len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
- if ((s = cinfo->version[VER_SERIAL]) != 0)
- len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
-
- if (card->cardtype != avm_m1) {
- flag = ((__u8 *)(ctrl->profile.manu))[3];
- if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
- "protocol",
- (flag & 0x01) ? " DSS1" : "",
- (flag & 0x02) ? " CT1" : "",
- (flag & 0x04) ? " VN3" : "",
- (flag & 0x08) ? " NI1" : "",
- (flag & 0x10) ? " AUSTEL" : "",
- (flag & 0x20) ? " ESS" : "",
- (flag & 0x40) ? " 1TR6" : ""
- );
- }
- if (card->cardtype != avm_m1) {
- flag = ((__u8 *)(ctrl->profile.manu))[5];
- if (flag)
- len += sprintf(page+len, "%-16s%s%s%s%s\n",
- "linetype",
- (flag & 0x01) ? " point to point" : "",
- (flag & 0x02) ? " point to multipoint" : "",
- (flag & 0x08) ? " leased line without D-channel" : "",
- (flag & 0x04) ? " leased line with D-channel" : ""
- );
- }
- len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
-
- save_flags(flags);
- cli();
-
- txaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x2c));
- txaddr -= (__u32)card->dma->sendbuf;
- txlen = t1inmeml(card->mbase+0x30);
-
- rxaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x24));
- rxaddr -= (__u32)card->dma->recvbuf;
- rxlen = t1inmeml(card->mbase+0x28);
-
- csr = t1inmeml(card->mbase+AMCC_INTCSR);
-
- restore_flags(flags);
-
- len += sprintf(page+len, "%-16s 0x%lx\n",
- "csr (cached)", (unsigned long)card->csr);
- len += sprintf(page+len, "%-16s 0x%lx\n",
- "csr", (unsigned long)csr);
- len += sprintf(page+len, "%-16s %lu\n",
- "txoff", (unsigned long)txaddr);
- len += sprintf(page+len, "%-16s %lu\n",
- "txlen", (unsigned long)txlen);
- len += sprintf(page+len, "%-16s %lu\n",
- "rxoff", (unsigned long)rxaddr);
- len += sprintf(page+len, "%-16s %lu\n",
- "rxlen", (unsigned long)rxlen);
-
- if (off+count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len-off) ? count : len-off);
-}
-
-/* ------------------------------------------------------------- */
-
static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
{
- unsigned long page_offset, base;
+ unsigned long base, page_offset;
avmcard *card;
avmctrl_info *cinfo;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -987,6 +114,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card->dma, 0, sizeof(avmcard_dmainfo));
@@ -995,6 +123,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -1013,14 +142,26 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- base = card->membase & PAGE_MASK;
+ base = card->membase & PAGE_MASK;
page_offset = card->membase - base;
card->mbase = ioremap_nocache(base, page_offset + 64);
+ if (card->mbase) {
+ card->mbase += page_offset;
+ } else {
+ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
+ driver->name, card->membase);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
- t1pci_reset(card);
+ b1dma_reset(card);
if ((retval = t1pci_detect(card)) != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
@@ -1029,13 +170,14 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
- t1pci_reset(card);
+ b1dma_reset(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
- retval = request_irq(card->irq, t1pci_interrupt, SA_SHIRQ, card->name, card);
+ retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
@@ -1044,6 +186,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -1056,31 +199,52 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
card->cardnr = cinfo->capi_ctrl->cnr;
skb_queue_head_init(&card->dma->send_queue);
- MOD_INC_USE_COUNT;
+ printk(KERN_INFO
+ "%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
+ driver->name, card->port, card->irq, card->membase);
return 0;
}
/* ------------------------------------------------------------- */
+static char *t1pci_procinfo(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+ if (!cinfo)
+ return "";
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+ cinfo->cardname[0] ? cinfo->cardname : "-",
+ cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+ cinfo->card ? cinfo->card->port : 0x0,
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->membase : 0
+ );
+ return cinfo->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
static struct capi_driver t1pci_driver = {
"t1pci",
"0.0",
- t1pci_load_firmware,
- t1pci_reset_ctr,
+ b1dma_load_firmware,
+ b1dma_reset_ctr,
t1pci_remove_ctr,
- t1pci_register_appl,
- t1pci_release_appl,
- t1pci_send_message,
+ b1dma_register_appl,
+ b1dma_release_appl,
+ b1dma_send_message,
t1pci_procinfo,
- t1pci_read_proc,
+ b1dmactl_read_proc,
0, /* use standard driver_read_proc */
0, /* no add_card function */
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 38b2944f7..110b5a172 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -1,10 +1,10 @@
-/*
- * $Id: divert_procfs.c,v 1.5 1999/09/14 20:31:01 werner Exp $
+/*
+ * $Id: divert_procfs.c,v 1.6 2000/02/14 19:23:03 werner Exp $
*
* Filesystem handling for the diversion supplementary services.
*
* Copyright 1998 by Werner Cornelius (werner@isdn4linux.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -17,9 +17,13 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: divert_procfs.c,v $
+ * Revision 1.6 2000/02/14 19:23:03 werner
+ *
+ * Changed handling of proc filesystem tables to a more portable version
+ *
* Revision 1.5 1999/09/14 20:31:01 werner
*
* Removed obsoleted functions for proc fs and synced with new ones.
@@ -44,9 +48,9 @@
#include <linux/version.h>
#include <linux/poll.h>
#ifdef CONFIG_PROC_FS
- #include <linux/proc_fs.h>
+#include <linux/proc_fs.h>
#else
- #include <linux/fs.h>
+#include <linux/fs.h>
#endif
#include <linux/isdnif.h>
#include "isdn_divert.h"
@@ -54,220 +58,239 @@
/*********************************/
/* Variables for interface queue */
/*********************************/
-ulong if_used = 0; /* number of interface users */
-static struct divert_info *divert_info_head = NULL; /* head of queue */
-static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
+ulong if_used = 0; /* number of interface users */
+static struct divert_info *divert_info_head = NULL; /* head of queue */
+static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
static wait_queue_head_t rd_queue;
/*********************************/
/* put an info buffer into queue */
/*********************************/
-void put_info_buffer(char *cp)
-{ struct divert_info *ib;
- int flags;
-
- if (if_used <= 0) return;
- if (!cp) return;
- if (!*cp) return;
- if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info)+strlen(cp), GFP_ATOMIC))) return; /* no memory */
- strcpy(ib->info_start,cp); /* set output string */
- ib->next = NULL;
- save_flags(flags);
- cli();
- ib->usage_cnt = if_used;
- if (!divert_info_head)
- divert_info_head = ib; /* new head */
- else
- divert_info_tail->next = ib; /* follows existing messages */
- divert_info_tail = ib; /* new tail */
- restore_flags(flags);
-
- /* delete old entrys */
- while (divert_info_head->next)
- { if ((divert_info_head->usage_cnt <= 0) &&
- (divert_info_head->next->usage_cnt <= 0))
- { ib = divert_info_head;
- divert_info_head = divert_info_head->next;
- kfree(ib);
- }
- else break;
- } /* divert_info_head->next */
- wake_up_interruptible(&(rd_queue));
-} /* put_info_buffer */
+void
+put_info_buffer(char *cp)
+{
+ struct divert_info *ib;
+ int flags;
+
+ if (if_used <= 0)
+ return;
+ if (!cp)
+ return;
+ if (!*cp)
+ return;
+ if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
+ return; /* no memory */
+ strcpy(ib->info_start, cp); /* set output string */
+ ib->next = NULL;
+ save_flags(flags);
+ cli();
+ ib->usage_cnt = if_used;
+ if (!divert_info_head)
+ divert_info_head = ib; /* new head */
+ else
+ divert_info_tail->next = ib; /* follows existing messages */
+ divert_info_tail = ib; /* new tail */
+ restore_flags(flags);
+
+ /* delete old entrys */
+ while (divert_info_head->next) {
+ if ((divert_info_head->usage_cnt <= 0) &&
+ (divert_info_head->next->usage_cnt <= 0)) {
+ ib = divert_info_head;
+ divert_info_head = divert_info_head->next;
+ kfree(ib);
+ } else
+ break;
+ } /* divert_info_head->next */
+ wake_up_interruptible(&(rd_queue));
+} /* put_info_buffer */
/**********************************/
/* deflection device read routine */
/**********************************/
-static ssize_t isdn_divert_read(struct file *file, char *buf, size_t count, loff_t *off)
-{ struct divert_info *inf;
- int len;
-
- if (!*((struct divert_info **)file->private_data))
- { if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- interruptible_sleep_on(&(rd_queue));
- }
- if (!(inf = *((struct divert_info **)file->private_data))) return(0);
-
- inf->usage_cnt--; /* new usage count */
- (struct divert_info **)file->private_data = &inf->next; /* next structure */
- if ((len = strlen(inf->info_start)) <= count)
- { if (copy_to_user(buf, inf->info_start, len))
- return -EFAULT;
- file->f_pos += len;
- return(len);
- }
- return(0);
-} /* isdn_divert_read */
+static ssize_t
+isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ struct divert_info *inf;
+ int len;
+
+ if (!*((struct divert_info **) file->private_data)) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ interruptible_sleep_on(&(rd_queue));
+ }
+ if (!(inf = *((struct divert_info **) file->private_data)))
+ return (0);
+
+ inf->usage_cnt--; /* new usage count */
+ (struct divert_info **) file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->info_start)) <= count) {
+ if (copy_to_user(buf, inf->info_start, len))
+ return -EFAULT;
+ file->f_pos += len;
+ return (len);
+ }
+ return (0);
+} /* isdn_divert_read */
/**********************************/
/* deflection device write routine */
/**********************************/
-static ssize_t isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t *off)
+static ssize_t
+isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
- return(-ENODEV);
-} /* isdn_divert_write */
+ return (-ENODEV);
+} /* isdn_divert_write */
/***************************************/
/* select routines for various kernels */
/***************************************/
-static unsigned int isdn_divert_poll(struct file *file, poll_table * wait)
-{ unsigned int mask = 0;
+static unsigned int
+isdn_divert_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
- poll_wait(file, &(rd_queue), wait);
- /* mask = POLLOUT | POLLWRNORM; */
- if (*((struct divert_info **)file->private_data))
- { mask |= POLLIN | POLLRDNORM;
- }
- return mask;
-} /* isdn_divert_poll */
+ poll_wait(file, &(rd_queue), wait);
+ /* mask = POLLOUT | POLLWRNORM; */
+ if (*((struct divert_info **) file->private_data)) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+ return mask;
+} /* isdn_divert_poll */
/****************/
/* Open routine */
/****************/
-static int isdn_divert_open(struct inode *ino, struct file *filep)
-{ int flags;
-
- MOD_INC_USE_COUNT;
- save_flags(flags);
- cli();
- if_used++;
- if (divert_info_head)
- (struct divert_info **)filep->private_data = &(divert_info_tail->next);
- else
- (struct divert_info **)filep->private_data = &divert_info_head;
- restore_flags(flags);
- /* start_divert(); */
- return(0);
-} /* isdn_divert_open */
+static int
+isdn_divert_open(struct inode *ino, struct file *filep)
+{
+ int flags;
+
+ MOD_INC_USE_COUNT;
+ save_flags(flags);
+ cli();
+ if_used++;
+ if (divert_info_head)
+ (struct divert_info **) filep->private_data = &(divert_info_tail->next);
+ else
+ (struct divert_info **) filep->private_data = &divert_info_head;
+ restore_flags(flags);
+ /* start_divert(); */
+ return (0);
+} /* isdn_divert_open */
/*******************/
/* close routine */
/*******************/
-static int isdn_divert_close(struct inode *ino, struct file *filep)
-{ struct divert_info *inf;
- int flags;
-
- save_flags(flags);
- cli();
- if_used--;
- inf = *((struct divert_info **)filep->private_data);
- while (inf)
- { inf->usage_cnt--;
- inf = inf->next;
- }
- restore_flags(flags);
- if (if_used <= 0)
- while (divert_info_head)
- { inf = divert_info_head;
- divert_info_head = divert_info_head->next;
- kfree(inf);
- }
- MOD_DEC_USE_COUNT;
- return(0);
-} /* isdn_divert_close */
+static int
+isdn_divert_close(struct inode *ino, struct file *filep)
+{
+ struct divert_info *inf;
+ int flags;
+
+ save_flags(flags);
+ cli();
+ if_used--;
+ inf = *((struct divert_info **) filep->private_data);
+ while (inf) {
+ inf->usage_cnt--;
+ inf = inf->next;
+ }
+ restore_flags(flags);
+ if (if_used <= 0)
+ while (divert_info_head) {
+ inf = divert_info_head;
+ divert_info_head = divert_info_head->next;
+ kfree(inf);
+ }
+ MOD_DEC_USE_COUNT;
+ return (0);
+} /* isdn_divert_close */
/*********/
/* IOCTL */
/*********/
-static int isdn_divert_ioctl(struct inode *inode, struct file *file,
- uint cmd, ulong arg)
-{ divert_ioctl dioctl;
- int i, flags;
- divert_rule *rulep;
- char *cp;
-
- if ((i = copy_from_user(&dioctl,(char *) arg, sizeof(dioctl))))
- return(i);
-
- switch (cmd)
- {
- case IIOCGETVER:
- dioctl.drv_version = DIVERT_IIOC_VERSION ; /* set version */
- break;
-
- case IIOCGETDRV:
- if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
- return(-EINVAL);
- break;
-
- case IIOCGETNAM:
- cp = divert_if.drv_to_name(dioctl.getid.drvid);
- if (!cp) return(-EINVAL);
- if (!*cp) return(-EINVAL);
- strcpy(dioctl.getid.drvnam,cp);
- break;
-
- case IIOCGETRULE:
- if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
- return(-EINVAL);
- dioctl.getsetrule.rule = *rulep; /* copy data */
- break;
-
- case IIOCMODRULE:
- if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
- return(-EINVAL);
- save_flags(flags);
- cli();
- *rulep = dioctl.getsetrule.rule; /* copy data */
- restore_flags(flags);
- return(0); /* no copy required */
- break;
-
- case IIOCINSRULE:
- return(insertrule(dioctl.getsetrule.ruleidx,&dioctl.getsetrule.rule));
- break;
-
- case IIOCDELRULE:
- return(deleterule(dioctl.getsetrule.ruleidx));
- break;
-
- case IIOCDODFACT:
- return(deflect_extern_action(dioctl.fwd_ctrl.subcmd,
- dioctl.fwd_ctrl.callid,
- dioctl.fwd_ctrl.to_nr));
-
- case IIOCDOCFACT:
- case IIOCDOCFDIS:
- case IIOCDOCFINT:
- if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
- return(-EINVAL); /* invalid driver */
- if ((i = cf_command(dioctl.cf_ctrl.drvid,
- (cmd == IIOCDOCFACT) ? 1: (cmd == IIOCDOCFDIS) ? 0:2,
- dioctl.cf_ctrl.cfproc,
- dioctl.cf_ctrl.msn,
- dioctl.cf_ctrl.service,
- dioctl.cf_ctrl.fwd_nr,
- &dioctl.cf_ctrl.procid)))
- return(i);
- break;
-
- default:
- return(-EINVAL);
- } /* switch cmd */
- return(copy_to_user((char *) arg, &dioctl, sizeof(dioctl))); /* success */
-} /* isdn_divert_ioctl */
+static int
+isdn_divert_ioctl(struct inode *inode, struct file *file,
+ uint cmd, ulong arg)
+{
+ divert_ioctl dioctl;
+ int i, flags;
+ divert_rule *rulep;
+ char *cp;
+
+ if ((i = copy_from_user(&dioctl, (char *) arg, sizeof(dioctl))))
+ return (i);
+
+ switch (cmd) {
+ case IIOCGETVER:
+ dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
+ break;
+
+ case IIOCGETDRV:
+ if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
+ return (-EINVAL);
+ break;
+
+ case IIOCGETNAM:
+ cp = divert_if.drv_to_name(dioctl.getid.drvid);
+ if (!cp)
+ return (-EINVAL);
+ if (!*cp)
+ return (-EINVAL);
+ strcpy(dioctl.getid.drvnam, cp);
+ break;
+
+ case IIOCGETRULE:
+ if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
+ return (-EINVAL);
+ dioctl.getsetrule.rule = *rulep; /* copy data */
+ break;
+
+ case IIOCMODRULE:
+ if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
+ return (-EINVAL);
+ save_flags(flags);
+ cli();
+ *rulep = dioctl.getsetrule.rule; /* copy data */
+ restore_flags(flags);
+ return (0); /* no copy required */
+ break;
+
+ case IIOCINSRULE:
+ return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
+ break;
+
+ case IIOCDELRULE:
+ return (deleterule(dioctl.getsetrule.ruleidx));
+ break;
+
+ case IIOCDODFACT:
+ return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
+ dioctl.fwd_ctrl.callid,
+ dioctl.fwd_ctrl.to_nr));
+
+ case IIOCDOCFACT:
+ case IIOCDOCFDIS:
+ case IIOCDOCFINT:
+ if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
+ return (-EINVAL); /* invalid driver */
+ if ((i = cf_command(dioctl.cf_ctrl.drvid,
+ (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
+ dioctl.cf_ctrl.cfproc,
+ dioctl.cf_ctrl.msn,
+ dioctl.cf_ctrl.service,
+ dioctl.cf_ctrl.fwd_nr,
+ &dioctl.cf_ctrl.procid)))
+ return (i);
+ break;
+
+ default:
+ return (-EINVAL);
+ } /* switch cmd */
+ return (copy_to_user((char *) arg, &dioctl, sizeof(dioctl))); /* success */
+} /* isdn_divert_ioctl */
#ifdef CONFIG_PROC_FS
@@ -279,63 +302,66 @@ isdn_divert_lseek(struct file *file, loff_t offset, int orig)
static struct file_operations isdn_fops =
{
- llseek: isdn_divert_lseek,
- read: isdn_divert_read,
- write: isdn_divert_write,
- poll: isdn_divert_poll,
- ioctl: isdn_divert_ioctl,
- open: isdn_divert_open,
- release: isdn_divert_close,
-};
-
-struct inode_operations divert_file_inode_operations = {
- &isdn_fops, /* default proc file-ops */
+ isdn_divert_lseek,
+ isdn_divert_read,
+ isdn_divert_write,
+ NULL, /* isdn_readdir */
+ isdn_divert_poll, /* isdn_poll */
+ isdn_divert_ioctl, /* isdn_ioctl */
+ NULL, /* isdn_mmap */
+ isdn_divert_open,
+ NULL, /* flush */
+ isdn_divert_close,
+ NULL /* fsync */
};
+struct inode_operations divert_file_inode_operations;
/****************************/
/* isdn subdir in /proc/net */
/****************************/
static struct proc_dir_entry *isdn_proc_entry = NULL;
static struct proc_dir_entry *isdn_divert_entry = NULL;
-#endif CONFIG_PROC_FS
+#endif /* CONFIG_PROC_FS */
/***************************************************************************/
/* divert_dev_init must be called before the proc filesystem may be used */
/***************************************************************************/
-int divert_dev_init(void)
-{ int i;
+int
+divert_dev_init(void)
+{
init_waitqueue_head(&rd_queue);
#ifdef CONFIG_PROC_FS
- isdn_proc_entry = proc_mkdir("isdn", proc_net);
- if (!isdn_proc_entry)
- return(-1);
- isdn_divert_entry = create_proc_entry("divert",0,isdn_proc_entry);
- if (!isdn_divert_entry)
- {
- remove_proc_entry("isdn",proc_net);
- return(-1);
- }
- isdn_divert_entry->ops = &divert_file_inode_operations;
-#endif CONFIG_PROC_FS
-
- return(0);
-} /* divert_dev_init */
+ isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
+ if (!isdn_proc_entry)
+ return (-1);
+ isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
+ if (!isdn_divert_entry) {
+ remove_proc_entry("isdn", proc_net);
+ return (-1);
+ }
+ memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations));
+ divert_file_inode_operations.default_file_ops = &isdn_fops;
+ isdn_divert_entry->ops = &divert_file_inode_operations;
+#endif /* CONFIG_PROC_FS */
+
+ return (0);
+} /* divert_dev_init */
/***************************************************************************/
/* divert_dev_deinit must be called before leaving isdn when included as */
/* a module. */
/***************************************************************************/
-int divert_dev_deinit(void)
-{ int i;
+int
+divert_dev_deinit(void)
+{
#ifdef CONFIG_PROC_FS
- remove_proc_entry("divert",isdn_proc_entry);
- remove_proc_entry("isdn",proc_net);
-#endif CONFIG_PROC_FS
-
- return(0);
-} /* divert_dev_deinit */
+ remove_proc_entry("divert", isdn_proc_entry);
+ remove_proc_entry("isdn", proc_net);
+#endif /* CONFIG_PROC_FS */
+ return (0);
+} /* divert_dev_deinit */
diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h
index 88af10416..5ad164518 100644
--- a/drivers/isdn/eicon/eicon.h
+++ b/drivers/isdn/eicon/eicon.h
@@ -1,10 +1,10 @@
-/* $Id: eicon.h,v 1.17 1999/10/26 21:15:33 armin Exp $
+/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon.h,v $
+ * Revision 1.19 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.18 1999/11/25 11:43:27 armin
+ * Fixed statectrl and connect message.
+ * X.75 fix and HDLC/transparent with autoconnect.
+ * Minor cleanup.
+ *
* Revision 1.17 1999/10/26 21:15:33 armin
* using define for checking phone number len to avoid buffer overflow.
*
@@ -258,7 +267,7 @@ typedef struct {
/* Macro for delay via schedule() */
#define SLEEP(j) { \
- set_current_state(TASK_INTERRUPTIBLE); \
+ set_current_state(TASK_UNINTERRUPTIBLE); \
schedule_timeout(j); \
}
@@ -277,6 +286,8 @@ typedef struct {
#define XLOG_ERR_UNKNOWN (18)
#define XLOG_OK (0)
+#define TRACE_OK (1)
+
typedef struct {
__u8 Id __attribute__ ((packed));
__u8 uX __attribute__ ((packed));
@@ -494,12 +505,13 @@ typedef struct {
typedef struct {
int No; /* Channel Number */
unsigned short fsm_state; /* Current D-Channel state */
+ unsigned short statectrl; /* State controling bits */
unsigned short eazmask; /* EAZ-Mask for this Channel */
int queued; /* User-Data Bytes in TX queue */
int waitq; /* User-Data Bytes in wait queue */
int waitpq; /* User-Data Bytes in packet queue */
- unsigned short plci;
- unsigned short ncci;
+ struct sk_buff *tskb1; /* temp skb 1 */
+ struct sk_buff *tskb2; /* temp skb 2 */
unsigned char l2prot; /* Layer 2 protocol */
unsigned char l3prot; /* Layer 3 protocol */
#ifdef CONFIG_ISDN_TTY_FAX
@@ -600,21 +612,16 @@ typedef struct eicon_card {
struct eicon_card *next; /* Pointer to next device struct */
int myid; /* Driver-Nr. assigned by linklevel */
unsigned long flags; /* Statusflags */
- unsigned long ilock; /* Semaphores for IRQ-Routines */
struct sk_buff_head rcvq; /* Receive-Message queue */
struct sk_buff_head sndq; /* Send-Message queue */
struct sk_buff_head rackq; /* Req-Ack-Message queue */
struct sk_buff_head sackq; /* Data-Ack-Message queue */
struct sk_buff_head statq; /* Status-Message queue */
int statq_entries;
- u_char *ack_msg; /* Ptr to User Data in User skb */
- __u16 need_b3ack; /* Flag: Need ACK for current skb */
- struct sk_buff *sbuf; /* skb which is currently sent */
struct tq_struct snd_tq; /* Task struct for xmit bh */
struct tq_struct rcv_tq; /* Task struct for rcv bh */
struct tq_struct ack_tq; /* Task struct for ack bh */
msn_entry *msn_list;
- unsigned short msgnum; /* Message number for sending */
eicon_chan* IdTable[256]; /* Table to find entity */
__u16 ref_in;
__u16 ref_out;
@@ -696,6 +703,7 @@ extern int eicon_info(char *, int , void *);
extern ulong DebugVar;
extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
+extern void eicon_putstatus(eicon_card * card, char * buf);
#endif /* __KERNEL__ */
diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h
index 9ffbd9bdb..420d73f6e 100644
--- a/drivers/isdn/eicon/eicon_dsp.h
+++ b/drivers/isdn/eicon/eicon_dsp.h
@@ -1,10 +1,10 @@
-/* $Id: eicon_dsp.h,v 1.4 1999/07/25 15:12:02 armin Exp $
+/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for Eicon.Diehl active cards.
+ * ISDN lowlevel-module for Eicon active cards.
* DSP definitions
*
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1999,2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_dsp.h,v $
+ * Revision 1.5 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
* Revision 1.4 1999/07/25 15:12:02 armin
* fix of some debug logs.
* enabled ISA-cards option.
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index d8634bdbe..e53469070 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,10 +1,10 @@
-/* $Id: eicon_idi.c,v 1.24 1999/10/26 21:15:33 armin Exp $
+/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for Eicon.Diehl active cards.
+ * ISDN lowlevel-module for Eicon active cards.
* IDI interface
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH
* for sponsoring and testing fax
@@ -26,6 +26,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * Revision 1.29 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.28 2000/01/20 19:55:34 keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.27 1999/11/29 13:12:03 armin
+ * Autoconnect on L2_TRANS doesn't work with link_level correctly,
+ * changed back to former mode.
+ *
+ * Revision 1.26 1999/11/25 11:43:27 armin
+ * Fixed statectrl and connect message.
+ * X.75 fix and HDLC/transparent with autoconnect.
+ * Minor cleanup.
+ *
+ * Revision 1.25 1999/11/18 20:30:55 armin
+ * removed old workaround for ISA cards.
+ *
* Revision 1.24 1999/10/26 21:15:33 armin
* using define for checking phone number len to avoid buffer overflow.
*
@@ -130,7 +149,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.24 $";
+char *eicon_idi_revision = "$Revision: 1.29 $";
eicon_manifbuf *manbuf;
@@ -187,16 +206,13 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
reqbuf->XBuffer.P[l++] = LLC;
reqbuf->XBuffer.P[l++] = 2;
switch(chan->l2prot) {
- case ISDN_PROTO_L2_HDLC:
- reqbuf->XBuffer.P[l++] = 2;
+ case ISDN_PROTO_L2_TRANS:
+ reqbuf->XBuffer.P[l++] = 2; /* transparent */
break;
case ISDN_PROTO_L2_X75I:
case ISDN_PROTO_L2_X75UI:
case ISDN_PROTO_L2_X75BUI:
- reqbuf->XBuffer.P[l++] = 5;
- break;
- case ISDN_PROTO_L2_TRANS:
- reqbuf->XBuffer.P[l++] = 2;
+ reqbuf->XBuffer.P[l++] = 5; /* X.75 */
break;
case ISDN_PROTO_L2_MODEM:
if (chan->fsm_state == EICON_STATE_IWAIT)
@@ -204,17 +220,18 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
else
reqbuf->XBuffer.P[l++] = 10; /* V.42 */
break;
+ case ISDN_PROTO_L2_HDLC:
case ISDN_PROTO_L2_FAX:
if (chan->fsm_state == EICON_STATE_IWAIT)
reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */
else
- reqbuf->XBuffer.P[l++] = 2;
+ reqbuf->XBuffer.P[l++] = 2; /* transparent */
break;
default:
reqbuf->XBuffer.P[l++] = 1;
}
switch(chan->l3prot) {
- case ISDN_PROTO_L3_FAX:
+ case ISDN_PROTO_L3_FCLASS2:
#ifdef CONFIG_ISDN_TTY_FAX
reqbuf->XBuffer.P[l++] = 6;
reqbuf->XBuffer.P[l++] = NLC;
@@ -404,8 +421,10 @@ eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
idi_do_req(card, chan, ASSIGN, 0);
}
if (chan->fsm_state == EICON_STATE_NULL) {
- idi_do_req(card, chan, INDICATE_REQ, 0);
- chan->fsm_state = EICON_STATE_LISTEN;
+ if (!(chan->statectrl & HAVE_CONN_REQ)) {
+ idi_do_req(card, chan, INDICATE_REQ, 0);
+ chan->fsm_state = EICON_STATE_LISTEN;
+ }
}
return(0);
}
@@ -462,6 +481,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan)
}
if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
if (chan->fsm_state != EICON_STATE_NULL) {
+ chan->statectrl |= WAITING_FOR_HANGUP;
idi_do_req(card, chan, HANGUP, 0);
chan->fsm_state = EICON_STATE_NULL;
}
@@ -479,7 +499,6 @@ idi_connect_res(eicon_card *card, eicon_chan *chan)
return 1;
chan->fsm_state = EICON_STATE_IWAIT;
- idi_do_req(card, chan, CALL_RES, 0);
/* check if old NetID has been removed */
if (chan->e.B2Id) {
@@ -489,6 +508,7 @@ idi_connect_res(eicon_card *card, eicon_chan *chan)
}
idi_do_req(card, chan, ASSIGN, 1);
+ idi_do_req(card, chan, CALL_RES, 0);
return(0);
}
@@ -656,9 +676,18 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.length = l;
reqbuf->Reference = 0; /* Sig Entity */
- skb_queue_tail(&chan->e.X, skb);
- skb_queue_tail(&card->sndq, skb2);
- eicon_schedule_tx(card);
+ if (chan->statectrl & WAITING_FOR_HANGUP) {
+ /* If the line did not disconnect yet,
+ we have to delay this command */
+ eicon_log(card, 32, "idi_req: Ch%d: delaying conn_req\n", chan->No);
+ chan->statectrl |= HAVE_CONN_REQ;
+ chan->tskb1 = skb;
+ chan->tskb2 = skb2;
+ } else {
+ skb_queue_tail(&chan->e.X, skb);
+ skb_queue_tail(&card->sndq, skb2);
+ eicon_schedule_tx(card);
+ }
eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
return(0);
@@ -1433,6 +1462,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "");
ccard->interface.statcallb(&cmd);
cmd.driver = ccard->myid;
@@ -1489,6 +1519,8 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
break;
case 2: /* session end */
default:
+ /* send_edata produces error on some */
+ /* fax-machines here, so we don't */
/* idi_send_edata(ccard, chan); */
break;
}
@@ -1505,6 +1537,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "");
ccard->interface.statcallb(&cmd);
cmd.driver = ccard->myid;
@@ -2277,6 +2310,51 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
}
void
+eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len)
+{
+ int i,j,n;
+ int buflen = len * 3 + 30;
+ char *p;
+ struct trace_s {
+ unsigned long time;
+ unsigned short size;
+ unsigned short code;
+ unsigned char data[1];
+ } *q;
+
+ if (!(p = kmalloc(buflen, GFP_KERNEL))) {
+ eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n");
+ return;
+ }
+ memset(p, 0, buflen);
+ q = (struct trace_s *)buffer;
+
+ if (DebugVar & 512) {
+ if ((q->code == 3) || (q->code == 4)) {
+ n = (short) *(q->data);
+ if (n) {
+ j = sprintf(p, "DTRC:");
+ for (i = 0; i < n; i++) {
+ j += sprintf(p + j, "%02x ", q->data[i+2]);
+ }
+ j += sprintf(p + j, "\n");
+ }
+ }
+ } else {
+ j = sprintf(p, "XLOG: %lx %04x %04x ",
+ q->time, q->size, q->code);
+
+ for (i = 0; i < q->size; i++) {
+ j += sprintf(p + j, "%02x ", q->data[i]);
+ }
+ j += sprintf(p + j, "\n");
+ }
+ if (strlen(p))
+ eicon_putstatus(ccard, p);
+ kfree(p);
+}
+
+void
idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
{
int tmp;
@@ -2307,7 +2385,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
else
dlev = 128;
- eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
+ eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%x Id=%x Ch=%x MInd=%x MLen=%x Len=%x\n", chan->No,
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
free_buff = 1;
@@ -2347,12 +2425,25 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
} else {
if (chan->e.B2Id)
idi_do_req(ccard, chan, REMOVE, 1);
- chan->fsm_state = EICON_STATE_NULL;
- cmd.driver = ccard->myid;
- cmd.arg = chan->No;
- cmd.command = ISDN_STAT_DHUP;
- ccard->interface.statcallb(&cmd);
- eicon_idi_listen_req(ccard, chan);
+ chan->statectrl &= ~WAITING_FOR_HANGUP;
+ if (chan->statectrl & HAVE_CONN_REQ) {
+ eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No);
+ chan->statectrl &= ~HAVE_CONN_REQ;
+ if ((chan->tskb1) && (chan->tskb2)) {
+ skb_queue_tail(&chan->e.X, chan->tskb1);
+ skb_queue_tail(&ccard->sndq, chan->tskb2);
+ eicon_schedule_tx(ccard);
+ }
+ chan->tskb1 = NULL;
+ chan->tskb2 = NULL;
+ } else {
+ chan->fsm_state = EICON_STATE_NULL;
+ cmd.driver = ccard->myid;
+ cmd.arg = chan->No;
+ cmd.command = ISDN_STAT_DHUP;
+ ccard->interface.statcallb(&cmd);
+ eicon_idi_listen_req(ccard, chan);
+ }
}
break;
case INDICATE_IND:
@@ -2450,8 +2541,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
case ISDN_PROTO_L2_MODEM:
/* do nothing, wait for connect */
break;
- default:
+ case ISDN_PROTO_L2_TRANS:
idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+ break;
+ default:
+ /* On most incoming calls we use automatic connect */
+ /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */
}
} else
idi_hangup(ccard, chan);
@@ -2495,8 +2590,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if (chan->No == ccard->nchannels) {
/* Management Indication */
- idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
- chan->fsm_state = 1;
+ if (ind->Ind == 0x04) { /* Trace_Ind */
+ eicon_parse_trace(ccard, ind->RBuffer.P, ind->RBuffer.length);
+ } else {
+ idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
+ chan->fsm_state = 1;
+ }
}
else
switch(ind->Ind) {
@@ -2530,6 +2629,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "64000");
ccard->interface.statcallb(&cmd);
break;
case IDI_N_CONNECT:
@@ -2546,6 +2646,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "64000");
ccard->interface.statcallb(&cmd);
break;
case IDI_N_DISC:
@@ -2576,6 +2677,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.arg = chan->No;
ccard->interface.statcallb(&cmd);
chan->fsm_state = EICON_STATE_NULL;
+ chan->statectrl |= WAITING_FOR_HANGUP;
}
#ifdef CONFIG_ISDN_TTY_FAX
chan->fax = 0;
@@ -2631,7 +2733,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
isdn_ctrl cmd;
if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
- /* I dont know why this happens, just ignoring this RC */
+ /* I dont know why this happens, should not ! */
+ /* just ignoring this RC */
eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No,
ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
return 1;
@@ -2640,16 +2743,16 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
/* Management Interface */
if (chan->No == ccard->nchannels) {
/* Managementinterface: changing state */
- if (chan->e.Req == 0x04)
+ if (chan->e.Req != 0x02)
chan->fsm_state = 1;
}
/* Remove an Id */
if (chan->e.Req == REMOVE) {
if (ack->Reference != chan->e.ref) {
+ /* This should not happen anymore */
eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
ack->Reference, chan->e.ref);
- return 0;
}
save_flags(flags);
cli();
@@ -2807,11 +2910,14 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
dCh, ack->Rc, ack->RcId, ack->RcCh);
break;
default:
- eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
- dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
+ if (dCh != ccard->nchannels)
+ eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+ dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
}
if (dCh == ccard->nchannels) { /* Management */
chan->fsm_state = 2;
+ eicon_log(ccard, 8, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+ dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
} else if (dCh >= 0) {
/* any other channel */
/* card reports error: we hangup */
@@ -3011,38 +3117,36 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
chan = &(card->bch[card->nchannels]);
- if (chan->e.D3Id)
- return -EBUSY;
- chan->e.D3Id = 1;
- while((skb2 = skb_dequeue(&chan->e.X)))
- dev_kfree_skb(skb2);
- chan->e.busy = 0;
+ if (!(chan->e.D3Id)) {
+ chan->e.D3Id = 1;
+ while((skb2 = skb_dequeue(&chan->e.X)))
+ dev_kfree_skb(skb2);
+ chan->e.busy = 0;
- if ((ret = eicon_idi_manage_assign(card))) {
- chan->e.D3Id = 0;
- return(ret);
- }
+ if ((ret = eicon_idi_manage_assign(card))) {
+ chan->e.D3Id = 0;
+ return(ret);
+ }
- timeout = jiffies + 50;
- while (timeout > jiffies) {
- if (chan->e.B2Id) break;
- SLEEP(10);
- }
- if (!chan->e.B2Id) {
- chan->e.D3Id = 0;
- return -EIO;
+ timeout = jiffies + 50;
+ while (timeout > jiffies) {
+ if (chan->e.B2Id) break;
+ SLEEP(10);
+ }
+ if (!chan->e.B2Id) {
+ chan->e.D3Id = 0;
+ return -EIO;
+ }
}
chan->fsm_state = 0;
if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n");
- chan->e.D3Id = 0;
return -ENOMEM;
}
if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) {
kfree(manbuf);
- chan->e.D3Id = 0;
return -EFAULT;
}
@@ -3056,7 +3160,6 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
if (skb2)
dev_kfree_skb(skb2);
kfree(manbuf);
- chan->e.D3Id = 0;
return -ENOMEM;
}
@@ -3093,25 +3196,14 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
SLEEP(10);
}
if ((!chan->fsm_state) || (chan->fsm_state == 2)) {
- eicon_idi_manage_remove(card);
kfree(manbuf);
- chan->e.D3Id = 0;
return -EIO;
}
-
- if ((ret = eicon_idi_manage_remove(card))) {
- kfree(manbuf);
- chan->e.D3Id = 0;
- return(ret);
- }
-
if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) {
kfree(manbuf);
- chan->e.D3Id = 0;
return -EFAULT;
}
kfree(manbuf);
- chan->e.D3Id = 0;
return(0);
}
diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h
index e09c1954d..2fe6167a4 100644
--- a/drivers/isdn/eicon/eicon_idi.h
+++ b/drivers/isdn/eicon/eicon_idi.h
@@ -1,10 +1,10 @@
-/* $Id: eicon_idi.h,v 1.7 1999/08/22 20:26:46 calle Exp $
+/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for the Eicon.Diehl active cards.
+ * ISDN lowlevel-module for the Eicon active cards.
* IDI-Interface
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.h,v $
+ * Revision 1.9 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.8 1999/11/25 11:43:27 armin
+ * Fixed statectrl and connect message.
+ * X.75 fix and HDLC/transparent with autoconnect.
+ * Minor cleanup.
+ *
* Revision 1.7 1999/08/22 20:26:46 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -170,6 +179,10 @@
/*------------------------------------------------------------------*/
+/* defines for statectrl */
+#define WAITING_FOR_HANGUP 0x01
+#define HAVE_CONN_REQ 0x02
+
typedef struct {
char cpn[32];
char oad[32];
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c
index 779f241e0..4f4180ed6 100644
--- a/drivers/isdn/eicon/eicon_io.c
+++ b/drivers/isdn/eicon/eicon_io.c
@@ -1,12 +1,12 @@
-/* $Id: eicon_io.c,v 1.8 1999/10/08 22:09:34 armin Exp $
+/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
* Code for communicating with hardware.
*
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1999,2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
- * Thanks to Eicon Technology Diehl GmbH & Co. oHG for
+ * Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_io.c,v $
+ * Revision 1.10 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.9 1999/11/18 20:55:25 armin
+ * Ready_Int fix of ISA cards.
+ *
* Revision 1.8 1999/10/08 22:09:34 armin
* Some fixes of cards interface handling.
* Bugfix of NULL pointer occurence.
@@ -470,7 +477,7 @@ eicon_io_transmit(eicon_card *ccard) {
save_flags(flags);
cli();
if (scom) {
- if (ram_inb(ccard, &com->Req)) {
+ if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) {
if (!ccard->ReadyInt) {
tmp = ram_inb(ccard, &com->ReadyInt) + 1;
ram_outb(ccard, &com->ReadyInt, tmp);
@@ -566,7 +573,8 @@ eicon_io_transmit(eicon_card *ccard) {
chan->e.busy = 1;
eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
reqbuf->Req,
- ram_inb(ccard, &ReqOut->ReqId),
+ (scom) ? ram_inb(ccard, &com->ReqId) :
+ ram_inb(ccard, &ReqOut->ReqId),
reqbuf->ReqCh, reqbuf->XBuffer.length,
chan->e.ref);
}
@@ -754,6 +762,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if (ccard->ReadyInt) {
ccard->ReadyInt--;
ram_outb(ccard, &com->Rc, 0);
+ eicon_schedule_tx(ccard);
}
} else {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
index a89d18b12..86e6c0ef7 100644
--- a/drivers/isdn/eicon/eicon_isa.c
+++ b/drivers/isdn/eicon/eicon_isa.c
@@ -1,11 +1,11 @@
-/* $Id: eicon_isa.c,v 1.9 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon_isa.c,v 1.13 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for old ISA cards.
*
- * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,8 +22,21 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_isa.c,v $
+ * Revision 1.13 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.12 1999/11/27 12:56:19 armin
+ * Forgot some iomem changes for last ioremap compat.
+ *
+ * Revision 1.11 1999/11/25 11:33:09 armin
+ * Microchannel fix from Erik Weber (exrz73@ibm.net).
+ *
+ * Revision 1.10 1999/11/18 21:14:30 armin
+ * New ISA memory mapped IO
+ *
* Revision 1.9 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber.
+ * Added microchannel patch from Erik Weber (exrz73@ibm.net).
*
* Revision 1.8 1999/09/06 07:29:35 fritz
* Changed my mail-address.
@@ -70,7 +83,7 @@
#define release_shmem release_region
#define request_shmem request_region
-char *eicon_isa_revision = "$Revision: 1.9 $";
+char *eicon_isa_revision = "$Revision: 1.13 $";
#undef EICON_MCA_DEBUG
@@ -87,8 +100,10 @@ static int eicon_isa_valid_irq[] = {
static void
eicon_isa_release_shmem(eicon_isa_card *card) {
- if (card->mvalid)
- release_shmem((unsigned long)card->shmem, card->ramsize);
+ if (card->mvalid) {
+ iounmap(card->shmem);
+ release_mem_region(card->physmem, card->ramsize);
+ }
card->mvalid = 0;
}
@@ -117,7 +132,7 @@ eicon_isa_printpar(eicon_isa_card *card) {
case EICON_CTYPE_S2M:
printk(KERN_INFO "Eicon %s at 0x%lx, irq %d.\n",
eicon_ctype_name[card->type],
- (unsigned long)card->shmem,
+ card->physmem,
card->irq);
}
}
@@ -126,6 +141,7 @@ int
eicon_isa_find_card(int Mem, int Irq, char * Id)
{
int primary = 1;
+ unsigned long amem;
if (!strlen(Id))
return -1;
@@ -138,24 +154,27 @@ eicon_isa_find_card(int Mem, int Irq, char * Id)
Mem, Id);
return -1;
}
- if (check_shmem(Mem, RAMSIZE)) {
+ if (check_mem_region(Mem, RAMSIZE)) {
printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem);
return -1;
}
- writew(0x55aa, Mem + 0x402);
- if (readw(Mem + 0x402) != 0x55aa) primary = 0;
- writew(0, Mem + 0x402);
- if (readw(Mem + 0x402) != 0) primary = 0;
+ amem = (unsigned long) ioremap(Mem, RAMSIZE);
+ writew(0x55aa, amem + 0x402);
+ if (readw(amem + 0x402) != 0x55aa) primary = 0;
+ writew(0, amem + 0x402);
+ if (readw(amem + 0x402) != 0) primary = 0;
printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id);
if (primary) {
printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem);
- writeb(0, Mem + 0x3ffe);
+ writeb(0, amem + 0x3ffe);
+ iounmap((unsigned char *)amem);
return EICON_CTYPE_ISAPRI;
} else {
printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem);
- writeb(0, Mem + 0x400);
+ writeb(0, amem + 0x400);
+ iounmap((unsigned char *)amem);
return EICON_CTYPE_ISABRI;
}
return -1;
@@ -187,57 +206,65 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
return -EFAULT;
}
+ if (card->type == EICON_CTYPE_ISAPRI)
+ card->ramsize = RAMSIZE_P;
+ else
+ card->ramsize = RAMSIZE;
+
+ if (check_mem_region(card->physmem, card->ramsize)) {
+ printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
+ card->physmem);
+ kfree(code);
+ return -EBUSY;
+ }
+ request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN");
+ card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize);
+#ifdef EICON_MCA_DEBUG
+ printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);
+#endif
+ card->mvalid = 1;
+
switch(card->type) {
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
case EICON_CTYPE_ISABRI:
- card->ramsize = RAMSIZE;
card->intack = (__u8 *)card->shmem + INTACK;
card->startcpu = (__u8 *)card->shmem + STARTCPU;
card->stopcpu = (__u8 *)card->shmem + STOPCPU;
break;
case EICON_CTYPE_S2M:
case EICON_CTYPE_ISAPRI:
- card->ramsize = RAMSIZE_P;
card->intack = (__u8 *)card->shmem + INTACK_P;
card->startcpu = (__u8 *)card->shmem + STARTCPU_P;
card->stopcpu = (__u8 *)card->shmem + STOPCPU_P;
break;
default:
printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type);
+ eicon_isa_release_shmem(card);
+ kfree(code);
return -EINVAL;
}
- /* Register shmem */
- if (check_shmem((unsigned long)card->shmem, card->ramsize)) {
- printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
- (unsigned long)card->shmem);
- kfree(code);
- return -EBUSY;
- }
- request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN");
-#ifdef EICON_MCA_DEBUG
- printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);
-#endif
- card->mvalid = 1;
-
/* clear any pending irq's */
readb(card->intack);
#ifdef CONFIG_MCA
- if (card->type == EICON_CTYPE_SCOM) {
- outb_p(0,card->io+1);
- }
- else {
- printk(KERN_WARNING "eicon_isa_boot: Card type yet not supported.\n");
- return -EINVAL;
- };
+ if (MCA_bus) {
+ if (card->type == EICON_CTYPE_SCOM) {
+ outb_p(0,card->io+1);
+ }
+ else {
+ printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.\n");
+ eicon_isa_release_shmem(card);
+ return -EINVAL;
+ };
#ifdef EICON_MCA_DEBUG
printk(KERN_INFO "eicon_isa_boot: card->io = %x.\n", card->io);
printk(KERN_INFO "eicon_isa_boot: card->irq = %d.\n", (int)card->irq);
#endif
+ }
#else
/* set reset-line active */
writeb(0, card->stopcpu);
@@ -269,7 +296,9 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
/* Start CPU */
writeb(cbuf.boot_opt, &boot->ctrl);
#ifdef CONFIG_MCA
- outb_p(0, card->io);
+ if (MCA_bus) {
+ outb_p(0, card->io);
+ }
#else
writeb(0, card->startcpu);
#endif /* CONFIG_MCA */
@@ -320,7 +349,7 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
}
printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]);
if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
- tmp = eicon_addcard(card->type, (unsigned long)card->shmem, card->irq,
+ tmp = eicon_addcard(card->type, card->physmem, card->irq,
((eicon_card *)card->card)->regname);
printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
}
diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h
index b0d0b0eb9..b53adfcbf 100644
--- a/drivers/isdn/eicon/eicon_isa.h
+++ b/drivers/isdn/eicon/eicon_isa.h
@@ -1,10 +1,10 @@
-/* $Id: eicon_isa.h,v 1.6 1999/11/15 19:37:04 keil Exp $
+/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
*
- * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_isa.h,v $
+ * Revision 1.8 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.7 1999/11/18 21:14:30 armin
+ * New ISA memory mapped IO
+ *
* Revision 1.6 1999/11/15 19:37:04 keil
* need config.h
*
@@ -116,6 +123,7 @@ typedef union {
typedef struct {
int ramsize;
int irq; /* IRQ */
+ unsigned long physmem; /* physical memory address */
#ifdef CONFIG_MCA
int io; /* IO-port for MCA brand */
#endif /* CONFIG_MCA */
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index 8797e6aed..688d74de3 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -1,12 +1,12 @@
-/* $Id: eicon_mod.c,v 1.19 1999/11/12 13:21:44 armin Exp $
+/* $Id: eicon_mod.c,v 1.24 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for Eicon.Diehl active cards.
+ * ISDN lowlevel-module for Eicon active cards.
*
- * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
- * Thanks to Eicon Technology Diehl GmbH & Co. oHG for
+ * Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* Deutsche Telekom AG for S2M support.
@@ -31,6 +31,23 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_mod.c,v $
+ * Revision 1.24 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.23 2000/01/20 19:55:34 keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.22 1999/11/27 12:56:19 armin
+ * Forgot some iomem changes for last ioremap compat.
+ *
+ * Revision 1.21 1999/11/25 11:35:10 armin
+ * Microchannel fix from Erik Weber (exrz73@ibm.net).
+ * Minor cleanup.
+ *
+ * Revision 1.20 1999/11/18 21:14:30 armin
+ * New ISA memory mapped IO
+ *
* Revision 1.19 1999/11/12 13:21:44 armin
* Bugfix of undefined reference with CONFIG_MCA
*
@@ -46,7 +63,7 @@
* Improved debug and log via readstat()
*
* Revision 1.15 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber.
+ * Added microchannel patch from Erik Weber (exrz73@ibm.net).
*
* Revision 1.14 1999/09/06 07:29:35 fritz
* Changed my mail-address.
@@ -123,7 +140,7 @@
static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
start of card-list */
-static char *eicon_revision = "$Revision: 1.19 $";
+static char *eicon_revision = "$Revision: 1.24 $";
extern char *eicon_pci_revision;
extern char *eicon_isa_revision;
@@ -144,7 +161,7 @@ static int irq = -1;
#endif
static char *id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-MODULE_DESCRIPTION( "Driver for Eicon.Diehl active ISDN cards");
+MODULE_DESCRIPTION( "Driver for Eicon active ISDN cards");
MODULE_AUTHOR( "Armin Schindler");
MODULE_SUPPORTED_DEVICE( "ISDN subsystem");
MODULE_PARM_DESC(id, "ID-String of first card");
@@ -659,7 +676,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
break;
chan->l3prot = (c->arg >> 8);
#ifdef CONFIG_ISDN_TTY_FAX
- if (chan->l3prot == ISDN_PROTO_L3_FAX)
+ if (chan->l3prot == ISDN_PROTO_L3_FCLASS2)
chan->fax = c->parm.fax;
#endif
return 0;
@@ -839,8 +856,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
}
/* jiftime() copied from HiSax */
-inline int
-jiftime(char *s, long mark)
+static inline int jiftime(char *s, long mark)
{
s += 8;
@@ -1000,19 +1016,28 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
- if (membase == -1)
- membase = EICON_ISA_MEMBASE;
- if (irq == -1)
- irq = EICON_ISA_IRQ;
- card->bus = EICON_BUS_MCA;
- card->hwif.isa.card = (void *)card;
- card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
- card->hwif.isa.master = 1;
-
- card->hwif.isa.irq = irq;
- card->hwif.isa.type = Type;
- card->nchannels = 2;
- card->interface.channels = 1;
+ if (MCA_bus) {
+ if (membase == -1)
+ membase = EICON_ISA_MEMBASE;
+ if (irq == -1)
+ irq = EICON_ISA_IRQ;
+ card->bus = EICON_BUS_MCA;
+ card->hwif.isa.card = (void *)card;
+ card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+ card->hwif.isa.physmem = (unsigned long)membase;
+ card->hwif.isa.master = 1;
+
+ card->hwif.isa.irq = irq;
+ card->hwif.isa.type = Type;
+ card->nchannels = 2;
+ card->interface.channels = 1;
+ } else {
+ printk(KERN_WARNING
+ "eicon (%s): no MCA bus detected.\n",
+ card->interface.id);
+ kfree(card);
+ return;
+ }
break;
#endif /* CONFIG_MCA */
case EICON_CTYPE_QUADRO:
@@ -1023,6 +1048,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)(membase + (i+1) * EICON_ISA_QOFFSET);
+ card->hwif.isa.physmem = (unsigned long)(membase + (i+1) * EICON_ISA_QOFFSET);
card->hwif.isa.master = 0;
strcpy(card->interface.id, id);
if (id[strlen(id) - 1] == 'a') {
@@ -1067,7 +1093,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_MODEM |
ISDN_FEATURE_L2_FAX |
ISDN_FEATURE_L3_TRANSDSP |
- ISDN_FEATURE_L3_FAX;
+ ISDN_FEATURE_L3_FCLASS2;
card->hwif.pci.card = (void *)card;
card->hwif.pci.PCIreg = pcic->PCIreg;
card->hwif.pci.PCIcfg = pcic->PCIcfg;
@@ -1091,7 +1117,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_MODEM |
ISDN_FEATURE_L2_FAX |
ISDN_FEATURE_L3_TRANSDSP |
- ISDN_FEATURE_L3_FAX;
+ ISDN_FEATURE_L3_FCLASS2;
card->hwif.pci.card = (void *)card;
card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
card->hwif.pci.PCIreg = pcic->PCIreg;
@@ -1116,6 +1142,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+ card->hwif.isa.physmem = (unsigned long)membase;
card->hwif.isa.master = 1;
card->hwif.isa.irq = irq;
card->hwif.isa.type = Type;
@@ -1130,6 +1157,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+ card->hwif.isa.physmem = (unsigned long)membase;
card->hwif.isa.master = 1;
card->hwif.isa.irq = irq;
card->hwif.isa.type = Type;
@@ -1151,14 +1179,15 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
}
for (j=0; j< (card->nchannels + 1); j++) {
memset((char *)&card->bch[j], 0, sizeof(eicon_chan));
- card->bch[j].plci = 0x8000;
- card->bch[j].ncci = 0x8000;
+ card->bch[j].statectrl = 0;
card->bch[j].l2prot = ISDN_PROTO_L2_X75I;
card->bch[j].l3prot = ISDN_PROTO_L3_TRANS;
card->bch[j].e.D3Id = 0;
card->bch[j].e.B2Id = 0;
card->bch[j].e.Req = 0;
card->bch[j].No = j;
+ card->bch[j].tskb1 = NULL;
+ card->bch[j].tskb2 = NULL;
skb_queue_head_init(&card->bch[j].e.X);
skb_queue_head_init(&card->bch[j].e.R);
}
diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
index 5c96302cb..47196f953 100644
--- a/drivers/isdn/eicon/eicon_pci.c
+++ b/drivers/isdn/eicon/eicon_pci.c
@@ -1,12 +1,12 @@
-/* $Id: eicon_pci.c,v 1.10 1999/08/22 20:26:49 calle Exp $
+/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for PCI cards.
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
- * Thanks to Eicon Technology Diehl GmbH & Co. oHG for
+ * Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* Deutsche Telekom AG for S2M support.
@@ -26,6 +26,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_pci.c,v $
+ * Revision 1.11 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
* Revision 1.10 1999/08/22 20:26:49 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -77,7 +81,7 @@
#include "eicon_pci.h"
-char *eicon_pci_revision = "$Revision: 1.10 $";
+char *eicon_pci_revision = "$Revision: 1.11 $";
#if CONFIG_PCI /* intire stuff is only for PCI */
diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h
index a23faade2..384cc422c 100644
--- a/drivers/isdn/eicon/eicon_pci.h
+++ b/drivers/isdn/eicon/eicon_pci.h
@@ -1,9 +1,9 @@
-/* $Id: eicon_pci.h,v 1.3 1999/03/29 11:19:51 armin Exp $
+/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards (PCI part).
+ * ISDN low-level module for Eicon active ISDN-Cards (PCI part).
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_pci.h,v $
+ * Revision 1.4 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
* Revision 1.3 1999/03/29 11:19:51 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index e37d9c404..7bc340de9 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -137,6 +137,10 @@ ifeq ($(CONFIG_HISAX_HFC_PCI),y)
HFC_2BDS0 += hfc_pci.o
endif
+ifeq ($(CONFIG_HISAX_HFC_SX),y)
+ HFC_2BDS0 += hfc_sx.o
+endif
+
ifeq ($(CONFIG_HISAX_NICCY),y)
O_OBJS += niccy.o
ISAC_OBJ := isac.o
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
index e8abc9de2..5b3f3aadb 100644
--- a/drivers/isdn/hisax/arcofi.c
+++ b/drivers/isdn/hisax/arcofi.c
@@ -1,12 +1,19 @@
-/* $Id: arcofi.c,v 1.8 1999/08/25 16:50:51 keil Exp $
+/* $Id: arcofi.c,v 1.10 1999/12/23 15:09:32 keil Exp $
* arcofi.c Ansteuerung ARCOFI 2165
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
*
* $Log: arcofi.c,v $
+ * Revision 1.10 1999/12/23 15:09:32 keil
+ * change email
+ *
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/08/25 16:50:51 keil
* Fix bugs which cause 2.3.14 hangs (waitqueue init)
*
@@ -83,7 +90,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
if (event == ARCOFI_TIMEOUT) {
cs->dc.isac.arcofi_state = ARCOFI_NOP;
test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags);
- wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ wake_up(&cs->dc.isac.arcofi_wait);
return(1);
}
switch (cs->dc.isac.arcofi_state) {
@@ -109,7 +116,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
- wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ wake_up(&cs->dc.isac.arcofi_wait);
}
}
}
@@ -126,7 +133,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
- wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ wake_up(&cs->dc.isac.arcofi_wait);
}
}
break;
diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h
index 86617d6a1..7d1c445e5 100644
--- a/drivers/isdn/hisax/arcofi.h
+++ b/drivers/isdn/hisax/arcofi.h
@@ -1,12 +1,15 @@
-/* $Id: arcofi.h,v 1.4 1999/07/01 08:11:18 keil Exp $
+/* $Id: arcofi.h,v 1.5 1999/12/23 15:09:32 keil Exp $
* arcofi.h Ansteuerung ARCOFI 2165
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
*
* $Log: arcofi.h,v $
+ * Revision 1.5 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.4 1999/07/01 08:11:18 keil
* Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
*
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index 10657ad63..98c9736b6 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -1,4 +1,4 @@
-/* $Id: asuscom.c,v 1.8 1999/09/04 06:20:05 keil Exp $
+/* $Id: asuscom.c,v 1.9 1999/12/19 13:09:41 keil Exp $
* asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
*
@@ -8,6 +8,10 @@
*
*
* $Log: asuscom.c,v $
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -42,7 +46,7 @@
extern const char *CardType[];
-const char *Asuscom_revision = "$Revision: 1.8 $";
+const char *Asuscom_revision = "$Revision: 1.9 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -291,13 +295,13 @@ reset_asuscom(struct IsdnCardState *cs)
byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->subtyp == ASUS_IPAC)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
else
byteout(cs->hw.asus.adr, 0); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->subtyp == ASUS_IPAC) {
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index f343bfb5a..319e0b264 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -1,4 +1,4 @@
-/* $Id: avm_pci.c,v 1.12 1999/09/04 06:20:05 keil Exp $
+/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $
* avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
* Thanks to AVM, Berlin for informations
@@ -7,6 +7,13 @@
*
*
* $Log: avm_pci.c,v $
+ * Revision 1.14 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.13 1999/12/03 12:10:14 keil
+ * Bugfix: Wrong channel use on hangup of channel 2
+ *
* Revision 1.12 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -56,7 +63,7 @@
#include <linux/interrupt.h>
extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.12 $";
+static const char *avm_pci_rev = "$Revision: 1.14 $";
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
@@ -269,18 +276,26 @@ modehdlc(struct BCState *bcs, int mode, int bc)
int hdlc = bcs->channel;
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hdlc %c mode %d ichan %d",
- 'A' + hdlc, mode, bc);
- bcs->mode = mode;
- bcs->channel = bc;
+ debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d",
+ 'A' + hdlc, bcs->mode, mode, hdlc, bc);
bcs->hw.hdlc.ctrl.ctrl = 0;
switch (mode) {
+ case (-1): /* used for init */
+ bcs->mode = 1;
+ bcs->channel = bc;
+ bc = 0;
case (L1_MODE_NULL):
+ if (bcs->mode == L1_MODE_NULL)
+ return;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
+ bcs->mode = L1_MODE_NULL;
+ bcs->channel = bc;
break;
case (L1_MODE_TRANS):
+ bcs->mode = mode;
+ bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
@@ -290,6 +305,8 @@ modehdlc(struct BCState *bcs, int mode, int bc)
hdlc_sched_event(bcs, B_XMTBUFREADY);
break;
case (L1_MODE_HDLC):
+ bcs->mode = mode;
+ bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
write_ctrl(bcs, 5);
@@ -695,8 +712,8 @@ inithdlc(struct IsdnCardState *cs))
cs->bcs[1].BC_SetStack = setstack_hdlc;
cs->bcs[0].BC_Close = close_hdlcstate;
cs->bcs[1].BC_Close = close_hdlcstate;
- modehdlc(cs->bcs, 0, 0);
- modehdlc(cs->bcs + 1, 0, 0);
+ modehdlc(cs->bcs, -1, 0);
+ modehdlc(cs->bcs + 1, -1, 1);
}
static void
@@ -734,11 +751,11 @@ reset_avmpcipnp(struct IsdnCardState *cs)
save_flags(flags);
sti();
outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
}
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index cb999972c..ce02a1bc6 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -1,4 +1,4 @@
-/* $Id: bkm_a4t.c,v 1.8 1999/09/04 06:20:05 keil Exp $
+/* $Id: bkm_a4t.c,v 1.9 1999/12/19 13:09:41 keil Exp $
* bkm_a4t.c low level stuff for T-Berkom A4T
* derived from the original file sedlbauer.c
* derived from the original file niccy.c
@@ -7,6 +7,10 @@
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log: bkm_a4t.c,v $
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -48,7 +52,7 @@
extern const char *CardType[];
-const char *bkm_a4t_revision = "$Revision: 1.8 $";
+const char *bkm_a4t_revision = "$Revision: 1.9 $";
static inline u_char
@@ -231,11 +235,11 @@ reset_bkm(struct IsdnCardState *cs)
sti();
/* Issue the I20 soft reset */
pI20_Regs->i20SysControl = 0xFF; /* all in */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Remove the soft reset */
pI20_Regs->i20SysControl = sysRESET | 0xFF;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Set our configuration */
pI20_Regs->i20SysControl = sysRESET | sysCFG;
@@ -246,14 +250,14 @@ reset_bkm(struct IsdnCardState *cs)
g_A4T_ISAC_RES |
g_A4T_JADE_BOOTR |
g_A4T_ISAR_BOOTR;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Remove RESET state from ISDN */
pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
g_A4T_JADE_RES |
g_A4T_ISAR_RES);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index fda6c213c..8ec2e9a08 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -1,4 +1,4 @@
-/* $Id: bkm_a8.c,v 1.8 1999/09/04 06:20:05 keil Exp $
+/* $Id: bkm_a8.c,v 1.9 1999/12/19 13:09:41 keil Exp $
* bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive)
* derived from the original file sedlbauer.c
* derived from the original file niccy.c
@@ -7,6 +7,10 @@
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log: bkm_a8.c,v $
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -49,7 +53,7 @@
extern const char *CardType[];
-const char sct_quadro_revision[] = "$Revision: 1.8 $";
+const char sct_quadro_revision[] = "$Revision: 1.9 $";
/* To survive the startup phase */
typedef struct {
@@ -298,13 +302,13 @@ reset_bkm(struct IsdnCardState *cs)
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Remove the soft reset */
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index e4c26d9de..4a01218c3 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.39 1999/10/14 20:25:28 keil Exp $
+/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,10 @@
* Fritz Elfert
*
* $Log: callc.c,v $
+ * Revision 2.40 1999/12/19 12:59:56 keil
+ * fix leased line handling
+ * and cosmetics
+ *
* Revision 2.39 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
@@ -163,7 +167,7 @@
#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
#endif /* MODULE */
-const char *lli_revision = "$Revision: 2.39 $";
+const char *lli_revision = "$Revision: 2.40 $";
extern struct IsdnCard cards[];
extern int nrcards;
@@ -199,8 +203,7 @@ static int chancount = 0;
/*
* Find card with given driverId
*/
-static inline struct IsdnCardState
-*
+static inline struct IsdnCardState *
hisax_findcard(int driverid)
{
int i;
@@ -239,39 +242,39 @@ link_debug(struct Channel *chanp, int direction, char *fmt, ...)
}
enum {
- ST_NULL, /* 0 inactive */
- ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */
- ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */
- ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */
- ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */
- ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
- ST_ACTIVE, /* 6 active, b channel prot. established */
- ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */
- ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */
- ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */
- ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */
- ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */
- ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */
+ ST_NULL, /* 0 inactive */
+ ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */
+ ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */
+ ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */
+ ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */
+ ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
+ ST_ACTIVE, /* 6 active, b channel prot. established */
+ ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */
+ ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */
+ ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */
+ ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */
+ ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */
+ ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */
};
#define STATE_COUNT (ST_IN_PROCEED_SEND + 1)
- static char *strState[] =
- {
- "ST_NULL",
- "ST_OUT_DIAL",
- "ST_IN_WAIT_LL",
- "ST_IN_ALERT_SENT",
- "ST_IN_WAIT_CONN_ACK",
- "ST_WAIT_BCONN",
- "ST_ACTIVE",
+static char *strState[] =
+{
+ "ST_NULL",
+ "ST_OUT_DIAL",
+ "ST_IN_WAIT_LL",
+ "ST_IN_ALERT_SENT",
+ "ST_IN_WAIT_CONN_ACK",
+ "ST_WAIT_BCONN",
+ "ST_ACTIVE",
"ST_WAIT_BRELEASE",
"ST_WAIT_BREL_DISC",
"ST_WAIT_DCOMMAND",
"ST_WAIT_DRELEASE",
"ST_WAIT_D_REL_CNF",
- "ST_IN_PROCEED_SEND",
+ "ST_IN_PROCEED_SEND",
};
enum {
@@ -333,19 +336,19 @@ static char *strEvent[] =
static inline void
HL_LL(struct Channel *chanp, int command)
{
- isdn_ctrl ic;
+ isdn_ctrl ic;
- ic.driver = chanp->cs->myid;
- ic.command = command;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
+ ic.driver = chanp->cs->myid;
+ ic.command = command;
+ ic.arg = chanp->chan;
+ chanp->cs->iif.statcallb(&ic);
}
static inline void
lli_deliver_cause(struct Channel *chanp)
{
- isdn_ctrl ic;
-
+ isdn_ctrl ic;
+
if (chanp->proc->para.cause == NO_CAUSE)
return;
ic.driver = chanp->cs->myid;
@@ -363,42 +366,42 @@ lli_deliver_cause(struct Channel *chanp)
static inline void
lli_close(struct FsmInst *fi)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_NULL);
- chanp->Flags = 0;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
+ FsmChangeState(fi, ST_NULL);
+ chanp->Flags = 0;
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
}
- static void
+static void
lli_leased_in(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+ int ret;
- isdn_ctrl ic;
- int ret;
-
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_IN_WAIT_LL);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_ICALL_LEASED");
- ic.driver = chanp->cs->myid;
+ if (!chanp->leased)
+ return;
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
+ FsmChangeState(fi, ST_IN_WAIT_LL);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_ICALL_LEASED");
+ ic.driver = chanp->cs->myid;
ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW);
- ic.arg = chanp->chan;
- ic.parm.setup.si1 = 7;
- ic.parm.setup.si2 = 0;
- ic.parm.setup.plan = 0;
- ic.parm.setup.screen = 0;
- sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1);
- sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid);
- ret = chanp->cs->iif.statcallb(&ic);
- if (chanp->debug & 1)
- link_debug(chanp, 1, "statcallb ret=%d", ret);
-
- if (!ret) {
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_NULL);
- }
+ ic.arg = chanp->chan;
+ ic.parm.setup.si1 = 7;
+ ic.parm.setup.si2 = 0;
+ ic.parm.setup.plan = 0;
+ ic.parm.setup.screen = 0;
+ sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1);
+ sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid);
+ ret = chanp->cs->iif.statcallb(&ic);
+ if (chanp->debug & 1)
+ link_debug(chanp, 1, "statcallb ret=%d", ret);
+ if (!ret) {
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
+ FsmChangeState(fi, ST_NULL);
+ }
}
@@ -408,14 +411,14 @@ lli_leased_in(struct FsmInst *fi, int event, void *arg)
static void
lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_WAIT_BCONN);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DCONN");
- HL_LL(chanp, ISDN_STAT_DCONN);
- init_b_st(chanp, 0);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_WAIT_BCONN);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_DCONN");
+ HL_LL(chanp, ISDN_STAT_DCONN);
+ init_b_st(chanp, 0);
+ chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
}
static void
@@ -427,14 +430,13 @@ lli_prep_dialout(struct FsmInst *fi, int event, void *arg)
FsmDelTimer(&chanp->dial_timer, 73);
chanp->l2_active_protocol = chanp->l2_protocol;
chanp->incoming = 0;
-
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- if (chanp->leased) {
- lli_init_bchan_out(fi, event, arg);
- } else {
- FsmChangeState(fi, ST_OUT_DIAL);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
- }
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
+ if (chanp->leased) {
+ lli_init_bchan_out(fi, event, arg);
+ } else {
+ FsmChangeState(fi, ST_OUT_DIAL);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
+ }
}
static void
@@ -442,18 +444,17 @@ lli_resume(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- FsmDelTimer(&chanp->drel_timer, 60);
- FsmDelTimer(&chanp->dial_timer, 73);
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = 0;
-
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- if (chanp->leased) {
- lli_init_bchan_out(fi, event, arg);
- } else {
- FsmChangeState(fi, ST_OUT_DIAL);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
- }
+ FsmDelTimer(&chanp->drel_timer, 60);
+ FsmDelTimer(&chanp->dial_timer, 73);
+ chanp->l2_active_protocol = chanp->l2_protocol;
+ chanp->incoming = 0;
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
+ if (chanp->leased) {
+ lli_init_bchan_out(fi, event, arg);
+ } else {
+ FsmChangeState(fi, ST_OUT_DIAL);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
+ }
}
static void
@@ -521,15 +522,15 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
FsmChangeState(fi, ST_IN_ALERT_SENT);
chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
break;
- case 5: /* direct redirect */
- case 4: /* Proceeding desired */
+ case 5: /* direct redirect */
+ case 4: /* Proceeding desired */
FsmDelTimer(&chanp->drel_timer, 61);
FsmChangeState(fi, ST_IN_PROCEED_SEND);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
- if (ret == 5)
- { chanp->setup = ic.parm.setup;
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
- }
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
+ if (ret == 5) {
+ chanp->setup = ic.parm.setup;
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+ }
break;
case 2: /* Rejecting Call */
break;
@@ -590,17 +591,17 @@ lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
static void
lli_setup_rsp(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_init_bchan_in(fi, event, arg);
- } else {
- FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+ struct Channel *chanp = fi->userdata;
+
+ if (chanp->leased) {
+ lli_init_bchan_in(fi, event, arg);
+ } else {
+ FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
#ifdef WANT_ALERT
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
#endif
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
- }
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+ }
}
/* Call suspend */
@@ -616,51 +617,84 @@ lli_suspend(struct FsmInst *fi, int event, void *arg)
/* Call clearing */
static void
+lli_leased_hup(struct FsmInst *fi, struct Channel *chanp)
+{
+ isdn_ctrl ic;
+
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_CAUSE;
+ ic.arg = chanp->chan;
+ sprintf(ic.parm.num, "L0010");
+ chanp->cs->iif.statcallb(&ic);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_DHUP");
+ HL_LL(chanp, ISDN_STAT_DHUP);
+ lli_close(fi);
+}
+
+static void
lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
+ chanp->proc);
+ }
}
static void
lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->proc->para.cause = 0x15; /* Call Rejected */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
+ chanp->proc);
+ }
}
static void
lli_dhup_close(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp);
- HL_LL(chanp, ISDN_STAT_DHUP);
-
- lli_close(fi);
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_DHUP");
+ lli_deliver_cause(chanp);
+ HL_LL(chanp, ISDN_STAT_DHUP);
+ lli_close(fi);
+ }
}
static void
lli_reject_req(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ return;
+ }
#ifndef ALERT_REJECT
- chanp->proc->para.cause = 0x15; /* Call Rejected */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
- lli_dhup_close(fi, event, arg);
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
+ lli_dhup_close(fi, event, arg);
#else
- FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
- FsmChangeState(fi, ST_IN_ALERT_SENT);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+ FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
+ FsmChangeState(fi, ST_IN_ALERT_SENT);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
#endif
}
@@ -678,54 +712,45 @@ static void
lli_start_disc(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
if (chanp->leased) {
- ic.command = ISDN_STAT_CAUSE;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "L0010");
- chanp->cs->iif.statcallb(&ic);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- HL_LL(chanp, ISDN_STAT_DHUP);
- lli_close(fi);
+ lli_leased_hup(fi, chanp);
} else {
- lli_disconnect_req(fi, event, arg);
+ lli_disconnect_req(fi, event, arg);
}
}
static void
lli_rel_b_disc(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- release_b_st(chanp);
- lli_start_disc(fi, event, arg);
+ struct Channel *chanp = fi->userdata;
+
+ release_b_st(chanp);
+ lli_start_disc(fi, event, arg);
}
static void
lli_bhup_disc(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
+ struct Channel *chanp = fi->userdata;
- lli_rel_b_disc(fi, event, arg);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+ lli_rel_b_disc(fi, event, arg);
}
static void
lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_WAIT_DCOMMAND);
- chanp->data_open = 0;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
- release_b_st(chanp);
+ FsmChangeState(fi, ST_WAIT_DCOMMAND);
+ chanp->data_open = 0;
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+ release_b_st(chanp);
}
static void
@@ -742,63 +767,65 @@ lli_release_bchan(struct FsmInst *fi, int event, void *arg)
static void
lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- release_b_st(chanp);
- lli_dhup_close(fi, event, arg);
+ release_b_st(chanp);
+ lli_dhup_close(fi, event, arg);
}
static void
lli_bhup_dhup(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
-
- lli_rel_b_dhup(fi, event, arg);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+ lli_rel_b_dhup(fi, event, arg);
}
static void
lli_abort(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
-
- lli_bhup_dhup(fi, event, arg);
+ chanp->data_open = 0;
+ chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+ lli_bhup_dhup(fi, event, arg);
}
static void
lli_release_req(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_WAIT_D_REL_CNF);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc);
+ struct Channel *chanp = fi->userdata;
+
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ FsmChangeState(fi, ST_WAIT_D_REL_CNF);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST,
+ chanp->proc);
+ }
}
static void
lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- release_b_st(chanp);
- lli_release_req(fi, event, arg);
+ struct Channel *chanp = fi->userdata;
+
+ release_b_st(chanp);
+ lli_release_req(fi, event, arg);
}
static void
lli_bhup_release_req(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
+ struct Channel *chanp = fi->userdata;
- lli_rel_b_release_req(fi, event, arg);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+ lli_rel_b_release_req(fi, event, arg);
}
@@ -825,7 +852,7 @@ lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg)
if (chanp->debug & 1)
link_debug(chanp, 0, "STAT_DHUP");
- HL_LL(chanp, ISDN_STAT_DHUP);
+ HL_LL(chanp, ISDN_STAT_DHUP);
}
static void
@@ -836,67 +863,65 @@ lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
if (chanp->debug & 1)
link_debug(chanp, 0, "STAT_DHUP");
HL_LL(chanp, ISDN_STAT_DHUP);
- lli_close(fi);
+ lli_close(fi);
}
static void
lli_error(struct FsmInst *fi, int event, void *arg)
{
- FsmChangeState(fi, ST_WAIT_DRELEASE);
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
}
static void
lli_failure_l(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
- FsmChangeState(fi, ST_NULL);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_CAUSE;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f);
- chanp->cs->iif.statcallb(&ic);
- HL_LL(chanp, ISDN_STAT_DHUP);
- chanp->Flags = 0;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
+ FsmChangeState(fi, ST_NULL);
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_CAUSE;
+ ic.arg = chanp->chan;
+ sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f);
+ chanp->cs->iif.statcallb(&ic);
+ HL_LL(chanp, ISDN_STAT_DHUP);
+ chanp->Flags = 0;
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
}
static void
lli_rel_b_fail(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- release_b_st(chanp);
- lli_failure_l(fi, event, arg);
+ release_b_st(chanp);
+ lli_failure_l(fi, event, arg);
}
static void
lli_bhup_fail(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
-
- lli_rel_b_fail(fi, event, arg);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+ lli_rel_b_fail(fi, event, arg);
}
static void
lli_failure_a(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
-
- lli_bhup_fail(fi, event, arg);
+ chanp->data_open = 0;
+ chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+ lli_bhup_fail(fi, event, arg);
}
- /* *INDENT-OFF* */
- static struct FsmNode fnlist[] HISAX_INITDATA =
- {
+/* *INDENT-OFF* */
+static struct FsmNode fnlist[] HISAX_INITDATA =
+{
{ST_NULL, EV_DIAL, lli_prep_dialout},
{ST_NULL, EV_RESUME, lli_resume},
{ST_NULL, EV_SETUP_IND, lli_deliver_call},
@@ -959,10 +984,9 @@ lli_failure_a(struct FsmInst *fi, int event, void *arg)
{ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close},
{ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready},
};
- /* *INDENT-ON* */
-
+/* *INDENT-ON* */
- #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
+#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
HISAX_INITFUNC(void
CallcNew(void))
@@ -985,9 +1009,9 @@ release_b_st(struct Channel *chanp)
{
struct PStack *st = chanp->b_st;
- if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) {
- chanp->bcs->BC_Close(chanp->bcs);
- switch (chanp->l2_active_protocol) {
+ if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) {
+ chanp->bcs->BC_Close(chanp->bcs);
+ switch (chanp->l2_active_protocol) {
case (ISDN_PROTO_L2_X75I):
releasestack_isdnl2(st);
break;
@@ -995,10 +1019,10 @@ release_b_st(struct Channel *chanp)
case (ISDN_PROTO_L2_TRANS):
case (ISDN_PROTO_L2_MODEM):
case (ISDN_PROTO_L2_FAX):
- releasestack_transl2(st);
- break;
- }
- }
+ releasestack_transl2(st);
+ break;
+ }
+ }
}
struct Channel
@@ -1013,10 +1037,10 @@ struct Channel
else
i=0;
- if (!bch)
- { i = 2; /* virtual channel */
- chanp += 2;
- }
+ if (!bch) {
+ i = 2; /* virtual channel */
+ chanp += 2;
+ }
while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) {
if (chanp->fi.state == ST_NULL)
@@ -1025,17 +1049,17 @@ struct Channel
i++;
}
- if (bch) /* number of channels is limited */
- { i = 2; /* virtual channel */
- chanp = st->lli.userdata;
- chanp += i;
- while (i < (2 + MAX_WAITING_CALLS)) {
- if (chanp->fi.state == ST_NULL)
- return (chanp);
- chanp++;
- i++;
- }
- }
+ if (bch) /* number of channels is limited */ {
+ i = 2; /* virtual channel */
+ chanp = st->lli.userdata;
+ chanp += i;
+ while (i < (2 + MAX_WAITING_CALLS)) {
+ if (chanp->fi.state == ST_NULL)
+ return (chanp);
+ chanp++;
+ i++;
+ }
+ }
return (NULL);
}
@@ -1053,19 +1077,19 @@ static void
dchan_l3l4(struct PStack *st, int pr, void *arg)
{
struct l3_process *pc = arg;
- struct IsdnCardState *cs = st->l1.hardware;
+ struct IsdnCardState *cs = st->l1.hardware;
struct Channel *chanp;
- if(!pc)
- return;
-
- if (pr == (CC_SETUP | INDICATION)) {
- if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
- pc->para.cause = 0x11; /* User busy */
- pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
- } else {
- chanp->proc = pc;
- pc->chan = chanp;
+ if(!pc)
+ return;
+
+ if (pr == (CC_SETUP | INDICATION)) {
+ if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
+ pc->para.cause = 0x11; /* User busy */
+ pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
+ } else {
+ chanp->proc = pc;
+ pc->chan = chanp;
FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
}
return;
@@ -1121,8 +1145,8 @@ dchan_l3l4(struct PStack *st, int pr, void *arg)
break;
case (CC_REDIR | INDICATION):
stat_redir_result(cs, chanp->chan, pc->redir_result);
- break;
- default:
+ break;
+ default:
if (chanp->debug & 0x800) {
HiSax_putstatus(chanp->cs, "Ch",
"%d L3->L4 unknown primitiv %#x",
@@ -1147,7 +1171,7 @@ init_PStack(struct PStack **stp) {
(*stp)->l2.l2l1 = dummy_pstack;
(*stp)->l2.l2l3 = dummy_pstack;
(*stp)->l3.l3l2 = dummy_pstack;
- (*stp)->l3.l3ml3 = dummy_pstack;
+ (*stp)->l3.l3ml3 = dummy_pstack;
(*stp)->l3.l3l4 = dummy_pstack;
(*stp)->lli.l4l3 = dummy_pstack;
(*stp)->ma.layer = dummy_pstack;
@@ -1230,8 +1254,8 @@ init_chan(int chan, struct IsdnCardState *csta)
}
int
-CallcNewChan(struct IsdnCardState *csta)
-{ int i;
+CallcNewChan(struct IsdnCardState *csta) {
+ int i;
chancount += 2;
init_chan(0, csta);
@@ -1240,8 +1264,7 @@ CallcNewChan(struct IsdnCardState *csta)
for (i = 0; i < MAX_WAITING_CALLS; i++)
init_chan(i+2,csta);
- printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
-
+ printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
csta->channel->d_st->lli.l4l3(csta->channel->d_st,
@@ -1272,13 +1295,13 @@ CallcFreeChan(struct IsdnCardState *csta)
for (i = 0; i < 2; i++) {
FsmDelTimer(&csta->channel[i].drel_timer, 74);
FsmDelTimer(&csta->channel[i].dial_timer, 75);
- if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
- release_d_st(csta->channel + i);
- if (csta->channel[i].b_st) {
- release_b_st(csta->channel + i);
- kfree(csta->channel[i].b_st);
- csta->channel[i].b_st = NULL;
- } else
+ if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
+ release_d_st(csta->channel + i);
+ if (csta->channel[i].b_st) {
+ release_b_st(csta->channel + i);
+ kfree(csta->channel[i].b_st);
+ csta->channel[i].b_st = NULL;
+ } else
printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i);
if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
release_d_st(csta->channel + i);
@@ -1311,7 +1334,7 @@ lldata_handler(struct PStack *st, int pr, void *arg)
break;
default:
printk(KERN_WARNING "lldata_handler unknown primitive %#x\n",
- pr);
+ pr);
break;
}
}
@@ -1341,7 +1364,7 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
break;
default:
printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n",
- pr);
+ pr);
break;
}
}
@@ -1444,7 +1467,7 @@ leased_l4l3(struct PStack *st, int pr, void *arg)
break;
default:
printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n",
- pr);
+ pr);
break;
}
}
@@ -1598,7 +1621,7 @@ HiSax_command(isdn_ctrl * ic)
if (!csta) {
printk(KERN_ERR
"HiSax: if_command %d called with invalid driverId %d!\n",
- ic->command, ic->driver);
+ ic->command, ic->driver);
return -ENODEV;
}
switch (ic->command) {
@@ -1771,11 +1794,18 @@ HiSax_command(isdn_ctrl * ic)
num = *(unsigned int *) ic->parm.num;
chanp = csta->channel + (num & 1);
num = num >>1;
- test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
- chanp->d_st->l2.tei = num;
- HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
- printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
- num);
+ if (num == 127) {
+ test_and_clear_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
+ chanp->d_st->l2.tei = -1;
+ HiSax_putstatus(csta, "set card ", "in VAR TEI mode");
+ printk(KERN_DEBUG "HiSax: set card in VAR TEI mode\n");
+ } else {
+ test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
+ chanp->d_st->l2.tei = num;
+ HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
+ printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
+ num);
+ }
chanp->d_st->lli.l4l3(chanp->d_st,
DL_ESTABLISH | REQUEST, NULL);
break;
@@ -1811,7 +1841,7 @@ HiSax_command(isdn_ctrl * ic)
if (csta->auxcmd)
return(csta->auxcmd(csta, ic));
printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
- (int) ic->arg);
+ (int) ic->arg);
return (-EINVAL);
}
break;
@@ -1839,11 +1869,11 @@ HiSax_command(isdn_ctrl * ic)
break;
/* protocol specific io commands */
- case (ISDN_CMD_PROT_IO):
+ case (ISDN_CMD_PROT_IO):
for (st = csta->stlist; st; st = st->next)
if (st->protocol == (ic->arg & 0xFF))
return(st->lli.l4l3_proto(st, ic));
- return(-EINVAL);
+ return(-EINVAL);
break;
default:
if (csta->auxcmd)
@@ -1865,7 +1895,7 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
if (!csta) {
printk(KERN_ERR
- "HiSax: if_sendbuf called with invalid driverId!\n");
+ "HiSax: if_sendbuf called with invalid driverId!\n");
return -ENODEV;
}
chanp = csta->channel + chan;
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index a75810f02..8d389c623 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1,10 +1,21 @@
-/* $Id: config.c,v 2.40 1999/10/30 13:09:45 keil Exp $
+/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
*
*
* $Log: config.c,v $
+ * Revision 2.43 2000/01/20 19:49:36 keil
+ * Support teles 13.3c vendor version 2.1
+ *
+ * Revision 2.42 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 2.41 1999/11/18 00:00:43 werner
+ *
+ * Added support for HFC-S+ and HFC-SP cards
+ *
* Revision 2.40 1999/10/30 13:09:45 keil
* Version 3.3c
*
@@ -202,6 +213,7 @@
* 34 Gazel ISDN cards
* 35 HFC 2BDS0 PCI none
* 36 Winbond 6692 PCI none
+ * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase
*
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
*
@@ -217,6 +229,7 @@ const char *CardType[] =
"AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
"Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
"Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
+ "HFC 2BDS0 SX",
};
void HiSax_closecard(int cardnr);
@@ -352,6 +365,13 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
#define DEFAULT_CFG {0,0,0,0}
#endif
+#ifdef CONFIG_HISAX_HFC_SX
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_HFC_SX
+#define DEFAULT_CFG {5,0x2E0,0,0}
+#endif
+
#ifdef CONFIG_HISAX_AMD7930
#undef DEFAULT_CARD
@@ -529,9 +549,9 @@ HiSaxVersion(void))
printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
#ifdef MODULE
- printk(KERN_INFO "HiSax: Version 3.3c (module)\n");
+ printk(KERN_INFO "HiSax: Version 3.3d (module)\n");
#else
- printk(KERN_INFO "HiSax: Version 3.3c (kernel)\n");
+ printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n");
#endif
strcpy(tmp, l1_revision);
printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -687,6 +707,10 @@ extern int setup_hfcs(struct IsdnCard *card);
extern int setup_hfcpci(struct IsdnCard *card);
#endif
+#if CARD_HFC_SX
+extern int setup_hfcsx(struct IsdnCard *card);
+#endif
+
#if CARD_AMD7930
extern int setup_amd7930(struct IsdnCard *card);
#endif
@@ -994,7 +1018,7 @@ HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
while (cnt) {
cs->cardmsg(cs, CARD_INIT, NULL);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
/* Timeout 10ms */
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
@@ -1208,6 +1232,11 @@ checkcard(int cardnr, char *id, int *busy_flag))
ret = setup_hfcpci(card);
break;
#endif
+#if CARD_HFC_SX
+ case ISDN_CTYPE_HFC_SX:
+ ret = setup_hfcsx(card);
+ break;
+#endif
#if CARD_NICCY
case ISDN_CTYPE_NICCY:
ret = setup_niccy(card);
@@ -1515,6 +1544,7 @@ HiSax_init(void))
case ISDN_CTYPE_FRITZPCI:
case ISDN_CTYPE_HSTSAPHIR:
case ISDN_CTYPE_GAZEL:
+ case ISDN_CTYPE_HFC_SX:
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
break;
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index f1161e63d..5dc868942 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -1,4 +1,4 @@
-/* $Id: diva.c,v 1.17 1999/09/04 06:20:06 keil Exp $
+/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $
* diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards
*
@@ -12,6 +12,10 @@
*
*
* $Log: diva.c,v $
+ * Revision 1.18 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.17 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -80,7 +84,7 @@
extern const char *CardType[];
-const char *Diva_revision = "$Revision: 1.17 $";
+const char *Diva_revision = "$Revision: 1.18 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -750,30 +754,30 @@ reset_diva(struct IsdnCardState *cs)
sti();
if (cs->subtyp == DIVA_IPAC_ISA) {
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
} else if (cs->subtyp == DIVA_IPAC_PCI) {
unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
PITA_MISC_REG);
*ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
*ireg = PITA_PARA_MPX_MODE;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
} else { /* DIVA 2.0 */
cs->hw.diva.ctrl_reg = 0; /* Reset On */
byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */
byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->subtyp == DIVA_ISA)
cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 4dbe40c38..1e425ccc5 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 2.19 1999/09/04 06:20:06 keil Exp $
+/* $Id: elsa.c,v 2.20 1999/12/19 13:09:42 keil Exp $
* elsa.c low level stuff for Elsa isdn cards
*
@@ -14,6 +14,10 @@
* for ELSA PCMCIA support
*
* $Log: elsa.c,v $
+ * Revision 2.20 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 2.19 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -99,7 +103,7 @@
extern const char *CardType[];
-const char *Elsa_revision = "$Revision: 2.19 $";
+const char *Elsa_revision = "$Revision: 2.20 $";
const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
"PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI",
@@ -578,10 +582,10 @@ reset_elsa(struct IsdnCardState *cs)
save_flags(flags);
sti();
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
restore_flags(flags);
@@ -785,7 +789,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
byteout(cs->hw.elsa.timer, 0);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((110*HZ)/1000);
restore_flags(flags);
cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
index aa0ff4adb..665fa2c74 100644
--- a/drivers/isdn/hisax/fsm.c
+++ b/drivers/isdn/hisax/fsm.c
@@ -1,12 +1,15 @@
-/* $Id: fsm.c,v 1.10 1998/11/15 23:54:39 keil Exp $
+/* $Id: fsm.c,v 1.11 1999/12/23 15:09:32 keil Exp $
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log: fsm.c,v $
+ * Revision 1.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.10 1998/11/15 23:54:39 keil
* changes from 2.0
*
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index bb388c5c2..2b22cdfea 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1,11 +1,14 @@
-/* $Id: hfc_2bds0.c,v 1.10 1999/10/14 20:25:28 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $
*
* specific routines for CCD's HFC 2BDS0
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hfc_2bds0.c,v $
+ * Revision 1.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.10 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h
index d11e8b503..32f703662 100644
--- a/drivers/isdn/hisax/hfc_2bds0.h
+++ b/drivers/isdn/hisax/hfc_2bds0.h
@@ -1,11 +1,14 @@
-/* $Id: hfc_2bds0.h,v 1.2 1998/02/02 13:26:15 keil Exp $
+/* $Id: hfc_2bds0.h,v 1.3 1999/12/23 15:09:32 keil Exp $
* specific defines for CCD's HFC 2BDS0
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hfc_2bds0.h,v $
+ * Revision 1.3 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.2 1998/02/02 13:26:15 keil
* New
*
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index 6620b90ec..f3edefa3e 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.10 1999/10/14 20:25:28 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $
* specific routines for CCD's HFC 2BS0
*
@@ -6,6 +6,13 @@
*
*
* $Log: hfc_2bs0.c,v $
+ * Revision 1.12 1999/12/19 14:17:12 keil
+ * fix compiler warning
+ *
+ * Revision 1.11 1999/11/21 12:41:18 werner
+ *
+ * Implemented full audio support
+ *
* Revision 1.10 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
@@ -210,7 +217,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
WaitForBusy(cs);
return (NULL);
}
- if (count < 4) {
+ if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hfc_empty_fifo: incoming packet too small");
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
@@ -225,47 +232,55 @@ hfc_empty_fifo(struct BCState *bcs, int count)
#endif
return (NULL);
}
- if (!(skb = dev_alloc_skb(count - 3)))
+ if (bcs->mode == L1_MODE_TRANS)
+ count -= 1;
+ else
+ count -= 3;
+ if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HFC: receive out of memory\n");
else {
- ptr = skb_put(skb, count - 3);
+ ptr = skb_put(skb, count);
idx = 0;
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx < count - 3) && WaitNoBusy(cs)) {
*ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
idx++;
}
- if (idx != count - 3) {
+ if (idx != count) {
debugl1(cs, "RFIFO BUSY error");
printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
dev_kfree_skb(skb);
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
+ if (bcs->mode != L1_MODE_TRANS) {
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
+ }
return (NULL);
}
- WaitNoBusy(cs);
- chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
- WaitNoBusy(cs);
- chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
- bcs->channel, chksum, stat);
- if (stat) {
- debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
- skb = NULL;
+ if (bcs->mode != L1_MODE_TRANS) {
+ WaitNoBusy(cs);
+ chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
+ WaitNoBusy(cs);
+ chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
+ bcs->channel, chksum, stat);
+ if (stat) {
+ debugl1(cs, "FIFO CRC error");
+ dev_kfree_skb(skb);
+ skb = NULL;
#ifdef ERROR_STATISTIC
- bcs->err_crc++;
+ bcs->err_crc++;
#endif
+ }
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
}
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
}
return (skb);
}
@@ -277,6 +292,7 @@ hfc_fill_fifo(struct BCState *bcs)
long flags;
int idx, fcnt;
int count;
+ int z1, z2;
u_char cip;
if (!bcs->tx_skb)
@@ -288,29 +304,39 @@ hfc_fill_fifo(struct BCState *bcs)
cli();
cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
- cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
- WaitForBusy(cs);
+ cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+ WaitForBusy(cs);
}
WaitNoBusy(cs);
- bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
- bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
- bcs->hw.hfc.send[bcs->hw.hfc.f1]);
- fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
- if (fcnt < 0)
- fcnt += 32;
- if (fcnt > 30) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo more as 30 frames");
- restore_flags(flags);
- return;
- }
- count = GetFreeFifoBytes(bcs);
+ if (bcs->mode != L1_MODE_TRANS) {
+ bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
+ bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
+ bcs->hw.hfc.send[bcs->hw.hfc.f1]);
+ fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
+ if (fcnt < 0)
+ fcnt += 32;
+ if (fcnt > 30) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo more as 30 frames");
+ restore_flags(flags);
+ return;
+ }
+ count = GetFreeFifoBytes(bcs);
+ }
+ else {
+ WaitForBusy(cs);
+ z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ count = z1 - z2;
+ if (count < 0)
+ count += cs->hw.hfc.fifosize;
+ } /* L1_MODE_TRANS */
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)",
bcs->channel, bcs->tx_skb->len,
@@ -335,9 +361,11 @@ hfc_fill_fifo(struct BCState *bcs)
count = -1;
dev_kfree_skb(bcs->tx_skb);
bcs->tx_skb = NULL;
- WaitForBusy(cs);
- WaitNoBusy(cs);
- cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ if (bcs->mode != L1_MODE_TRANS) {
+ WaitForBusy(cs);
+ WaitNoBusy(cs);
+ cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ }
if (bcs->st->lli.l1writewakeup && (count >= 0))
bcs->st->lli.l1writewakeup(bcs->st, count);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
@@ -366,32 +394,39 @@ main_irq_hfc(struct BCState *bcs)
WaitForBusy(cs);
}
WaitNoBusy(cs);
- f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- if (f1 != f2) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
- bcs->channel, f1, f2);
+ receive = 0;
+ if (bcs->mode == L1_MODE_HDLC) {
+ f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ if (f1 != f2) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
+ bcs->channel, f1, f2);
+ receive = 1;
+ }
+ }
+ if (receive || (bcs->mode == L1_MODE_TRANS)) {
WaitForBusy(cs);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
rcnt = z1 - z2;
if (rcnt < 0)
rcnt += cs->hw.hfc.fifosize;
- rcnt++;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
- bcs->channel, z1, z2, rcnt);
-/* sti(); */
- if ((skb = hfc_empty_fifo(bcs, rcnt))) {
- skb_queue_tail(&bcs->rqueue, skb);
- hfc_sched_event(bcs, B_RCVBUFREADY);
+ if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) {
+ rcnt++;
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
+ bcs->channel, z1, z2, rcnt);
+ /* sti(); */
+ if ((skb = hfc_empty_fifo(bcs, rcnt))) {
+ skb_queue_tail(&bcs->rqueue, skb);
+ hfc_sched_event(bcs, B_RCVBUFREADY);
+ }
}
receive = 1;
- } else
- receive = 0;
+ }
restore_flags(flags);
udelay(1);
cli();
@@ -432,12 +467,19 @@ mode_hfc(struct BCState *bcs, int mode, int bc)
switch (mode) {
case (L1_MODE_NULL):
- if (bc)
+ if (bc) {
+ cs->hw.hfc.ctmt &= ~1;
cs->hw.hfc.isac_spcr &= ~0x03;
- else
+ }
+ else {
+ cs->hw.hfc.ctmt &= ~2;
cs->hw.hfc.isac_spcr &= ~0x0c;
+ }
break;
case (L1_MODE_TRANS):
+ cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */
+ cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
+ hfc_clear_fifo(bcs); /* complete fifo clear */
if (bc) {
cs->hw.hfc.ctmt |= 1;
cs->hw.hfc.isac_spcr &= ~0x03;
@@ -462,7 +504,7 @@ mode_hfc(struct BCState *bcs, int mode, int bc)
}
cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
- if (mode)
+ if (mode == L1_MODE_HDLC)
hfc_clear_fifo(bcs);
}
diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h
index cce8e4a35..981ae7cb3 100644
--- a/drivers/isdn/hisax/hfc_2bs0.h
+++ b/drivers/isdn/hisax/hfc_2bs0.h
@@ -1,11 +1,14 @@
-/* $Id: hfc_2bs0.h,v 1.1 1997/09/11 17:31:34 keil Exp $
+/* $Id: hfc_2bs0.h,v 1.2 1999/12/23 15:09:32 keil Exp $
* specific defines for CCD's HFC 2BS0
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hfc_2bs0.h,v $
+ * Revision 1.2 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.1 1997/09/11 17:31:34 keil
* Common part for HFC 2BS0 based cards
*
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 518c1670a..76f353861 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.23 1999/11/07 17:01:55 keil Exp $
+/* $Id: hfc_pci.c,v 1.26 2000/02/09 20:22:55 werner Exp $
* hfc_pci.c low level driver for CCD´s hfc-pci based cards
*
@@ -23,6 +23,18 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hfc_pci.c,v $
+ * Revision 1.26 2000/02/09 20:22:55 werner
+ *
+ * Updated PCI-ID table
+ *
+ * Revision 1.25 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.24 1999/11/17 23:59:55 werner
+ *
+ * removed unneeded data
+ *
* Revision 1.23 1999/11/07 17:01:55 keil
* fix for 2.3 pci structs
*
@@ -114,7 +126,7 @@
extern const char *CardType[];
-static const char *hfcpci_revision = "$Revision: 1.23 $";
+static const char *hfcpci_revision = "$Revision: 1.26 $";
/* table entry in the PCI devices list */
typedef struct {
@@ -143,26 +155,12 @@ static const PCI_ENTRY id_list[] =
{0x1051, 0x0100, "Motorola MC145575", "MC145575"},
{0x1397, 0xB100, "Seyeon", "B100"},
{0x15B0, 0x2BD0, "Zoltrix", "2BD0"},
+ {0x114f, 0x71, "Digi intl.","Digicom"},
{0, 0, NULL, NULL},
};
#if CONFIG_PCI
-/*****************************/
-/* release D- and B-channels */
-/*****************************/
-void
-releasehfcpci(struct IsdnCardState *cs)
-{
- if (cs->bcs[0].hw.hfc.send) {
- kfree(cs->bcs[0].hw.hfc.send);
- cs->bcs[0].hw.hfc.send = NULL;
- }
- if (cs->bcs[1].hw.hfc.send) {
- kfree(cs->bcs[1].hw.hfc.send);
- cs->bcs[1].hw.hfc.send = NULL;
- }
-}
/******************************************/
/* free hardware resources used by driver */
@@ -179,13 +177,12 @@ release_io_hfcpci(struct IsdnCardState *cs)
restore_flags(flags);
Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
#if CONFIG_PCI
pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */
#endif /* CONFIG_PCI */
- releasehfcpci(cs);
del_timer(&cs->hw.hfcpci.timer);
kfree(cs->hw.hfcpci.share_start);
cs->hw.hfcpci.share_start = NULL;
@@ -211,10 +208,10 @@ reset_hfcpci(struct IsdnCardState *cs)
pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */
Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (Read_hfc(cs, HFCPCI_STATUS) & 2)
printk(KERN_WARNING "HFC-PCI init bit busy\n");
@@ -1647,24 +1644,6 @@ hfcpci_bh(struct IsdnCardState *cs)
}
-/*************************************/
-/* Alloc memory send data for queues */
-/*************************************/
-__initfunc(unsigned int
- *init_send_hfcpci(int cnt))
-{
- int i, *send;
-
- if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for hfcpci.send\n");
- return (NULL);
- }
- for (i = 0; i < cnt; i++)
- send[i] = 0x1fff;
- return (send);
-}
-
/********************************/
/* called for card init message */
/********************************/
@@ -1676,10 +1655,6 @@ __initfunc(void
cs->dbusytimer.data = (long) cs;
init_timer(&cs->dbusytimer);
cs->tqueue.routine = (void *) (void *) hfcpci_bh;
- if (!cs->bcs[0].hw.hfc.send)
- cs->bcs[0].hw.hfc.send = init_send_hfcpci(32);
- if (!cs->bcs[1].hw.hfc.send)
- cs->bcs[1].hw.hfc.send = init_send_hfcpci(32);
cs->BC_Send_Data = &hfcpci_send_data;
cs->bcs[0].BC_SetStack = setstack_2b;
cs->bcs[1].BC_SetStack = setstack_2b;
@@ -1712,7 +1687,7 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
inithfcpci(cs);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */
/* now switch timer interrupt off */
cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
@@ -1746,8 +1721,6 @@ __initfunc(int
printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
#if CONFIG_PCI
cs->hw.hfcpci.int_s1 = 0;
- cs->bcs[0].hw.hfc.send = NULL;
- cs->bcs[1].hw.hfc.send = NULL;
cs->dc.hfcpci.ph_state = 0;
cs->hw.hfcpci.fifo = 255;
if (cs->typ == ISDN_CTYPE_HFC_PCI) {
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
new file mode 100644
index 000000000..462de9d91
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -0,0 +1,1583 @@
+/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $
+
+ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards
+ *
+ * Author Werner Cornelius (werner@isdn4linux.de)
+ * based on existing driver for CCD HFC PCI cards
+ *
+ * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hfc_sx.c,v $
+ * Revision 1.3 2000/01/20 19:49:36 keil
+ * Support teles 13.3c vendor version 2.1
+ *
+ * Revision 1.2 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.1 1999/11/18 00:09:18 werner
+ *
+ * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
+ * Audio and Echo are supported.
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_sx.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+extern const char *CardType[];
+
+static const char *hfcsx_revision = "$Revision: 1.3 $";
+
+/***************************************/
+/* IRQ-table for CCDs demo board */
+/* IRQs 6,5,10,11,12,15 are supported */
+/***************************************/
+
+/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1
+ *
+ * Thanks to Uwe Wisniewski
+ *
+ * ISA-SLOT Signal PIN
+ * B25 IRQ3 92 IRQ_G
+ * B23 IRQ5 94 IRQ_A
+ * B4 IRQ2/9 95 IRQ_B
+ * D3 IRQ10 96 IRQ_C
+ * D4 IRQ11 97 IRQ_D
+ * D5 IRQ12 98 IRQ_E
+ * D6 IRQ15 99 IRQ_F
+ */
+
+#undef CCD_DEMO_BOARD
+#ifdef CCD_DEMO_BOARD
+static u_char ccd_sp_irqtab[16] = {
+ 0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6
+};
+#else /* Teles 16.3c */
+static u_char ccd_sp_irqtab[16] = {
+ 0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6
+};
+#endif
+#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/******************************/
+/* In/Out access to registers */
+/******************************/
+static inline void
+Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val)
+{ register int flags;
+
+ save_flags(flags);
+ cli();
+ byteout(cs->hw.hfcsx.base+1, regnum);
+ byteout(cs->hw.hfcsx.base, val);
+ restore_flags(flags);
+}
+
+static inline u_char
+Read_hfc(struct IsdnCardState *cs, u_char regnum)
+{ register int flags;
+ register u_char ret;
+
+ save_flags(flags);
+ cli();
+ byteout(cs->hw.hfcsx.base+1, regnum);
+ ret = bytein(cs->hw.hfcsx.base);
+ restore_flags(flags);
+ return(ret);
+}
+
+
+/**************************************************/
+/* select a fifo and remember which one for reuse */
+/**************************************************/
+static void
+fifo_select(struct IsdnCardState *cs, u_char fifo)
+{ int flags;
+
+ if (fifo == cs->hw.hfcsx.last_fifo)
+ return; /* still valid */
+
+ save_flags(flags);
+ cli();
+ byteout(cs->hw.hfcsx.base+1, HFCSX_FIF_SEL);
+ byteout(cs->hw.hfcsx.base, fifo);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ udelay(4);
+ byteout(cs->hw.hfcsx.base, fifo);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ restore_flags(flags);
+}
+
+/******************************************/
+/* reset the specified fifo to defaults. */
+/* If its a send fifo init needed markers */
+/******************************************/
+static void
+reset_fifo(struct IsdnCardState *cs, u_char fifo)
+{ int flags;
+
+ save_flags(flags);
+ cli();
+ fifo_select(cs, fifo); /* first select the fifo */
+ byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM);
+ byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */
+ udelay(1);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ restore_flags(flags);
+}
+
+
+/*************************************************************/
+/* write_fifo writes the skb contents to the desired fifo */
+/* if no space is available or an error occurs 0 is returned */
+/* the skb is not released in any way. */
+/*************************************************************/
+static int
+write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max)
+{ unsigned short *msp;
+ int fifo_size, count, z1, z2;
+ u_char f_msk, f1, f2, *src;
+
+ if (skb->len <= 0) return(0);
+ if (fifo & 1) return(0); /* no write fifo */
+
+ fifo_select(cs, fifo);
+ if (fifo & 4) {
+ fifo_size = D_FIFO_SIZE; /* D-channel */
+ f_msk = MAX_D_FRAMES;
+ if (trans_max) return(0); /* only HDLC */
+ }
+ else {
+ fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
+ f_msk = MAX_B_FRAMES;
+ }
+
+ z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+ z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+
+ /* Check for transparent mode */
+ if (trans_max) {
+ z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+ z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+ count = z2 - z1;
+ if (count <= 0)
+ count += fifo_size; /* free bytes */
+ if (count < skb->len+1) return(0); /* no room */
+ count = fifo_size - count; /* bytes still not send */
+ if (count > 2 * trans_max) return(0); /* delay to long */
+ count = skb->len;
+ src = skb->data;
+ while (count--)
+ Write_hfc(cs, HFCSX_FIF_DWR, *src++);
+ return(1); /* success */
+ }
+
+ msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker;
+ msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES+1));
+ f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
+ f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
+
+ count = f1 - f2; /* frame count actually buffered */
+ if (count < 0)
+ count += (f_msk + 1); /* if wrap around */
+ if (count > f_msk-1) {
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d more as %d frames",fifo,f_msk-1);
+ return(0);
+ }
+
+ *(msp + f1) = z1; /* remember marker */
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)",
+ fifo, f1, f2, z1);
+ /* now determine free bytes in FIFO buffer */
+ count = *(msp + f2) - z1;
+ if (count <= 0)
+ count += fifo_size; /* count now contains available bytes */
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
+ fifo, skb->len, count);
+ if (count < skb->len) {
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo);
+ return(0);
+ }
+
+ count = skb->len; /* get frame len */
+ src = skb->data; /* source pointer */
+ while (count--)
+ Write_hfc(cs, HFCSX_FIF_DWR, *src++);
+
+ Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */
+ udelay(1);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ return(1);
+}
+
+/***************************************************************/
+/* read_fifo reads data to an skb from the desired fifo */
+/* if no data is available or an error occurs NULL is returned */
+/* the skb is not released in any way. */
+/***************************************************************/
+static struct sk_buff *
+read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
+{ int fifo_size, count, z1, z2;
+ u_char f_msk, f1, f2, *dst;
+ struct sk_buff *skb;
+
+ if (!(fifo & 1)) return(NULL); /* no read fifo */
+ fifo_select(cs, fifo);
+ if (fifo & 4) {
+ fifo_size = D_FIFO_SIZE; /* D-channel */
+ f_msk = MAX_D_FRAMES;
+ if (trans_max) return(NULL); /* only hdlc */
+ }
+ else {
+ fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
+ f_msk = MAX_B_FRAMES;
+ }
+
+ /* transparent mode */
+ if (trans_max) {
+ z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+ z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+ z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+ z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+ /* now determine bytes in actual FIFO buffer */
+ count = z1 - z2;
+ if (count <= 0)
+ count += fifo_size; /* count now contains buffered bytes */
+ count++;
+ if (count > trans_max)
+ count = trans_max; /* limit length */
+ if ((skb = dev_alloc_skb(count))) {
+ dst = skb_put(skb, count);
+ while (count--)
+ *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
+ return(skb);
+ }
+ else return(NULL); /* no memory */
+ }
+
+ do {
+ f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
+ f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
+
+ if (f1 == f2) return(NULL); /* no frame available */
+
+ z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+ z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+ z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+ z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)",
+ fifo, f1, f2, z1, z2);
+ /* now determine bytes in actual FIFO buffer */
+ count = z1 - z2;
+ if (count <= 0)
+ count += fifo_size; /* count now contains buffered bytes */
+ count++;
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_read_fifo %d count %ld)",
+ fifo, count);
+
+ if ((count > fifo_size) || (count < 4)) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcsx_read_fifo %d paket inv. len %d ", fifo , count);
+ while (count) {
+ count--; /* empty fifo */
+ Read_hfc(cs, HFCSX_FIF_DRD);
+ }
+ skb = NULL;
+ } else
+ if ((skb = dev_alloc_skb(count - 3))) {
+ count -= 3;
+ dst = skb_put(skb, count);
+
+ while (count--)
+ *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
+
+ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */
+ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */
+ if (Read_hfc(cs, HFCSX_FIF_DRD)) {
+ dev_kfree_skb(skb);
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_read_fifo %d crc error", fifo);
+ skb = NULL;
+ }
+ } else {
+ printk(KERN_WARNING "HFC-SX: receive out of memory\n");
+ return(NULL);
+ }
+
+ Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */
+ udelay(1);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ udelay(1);
+ } while (!skb); /* retry in case of crc error */
+ return(skb);
+}
+
+/******************************************/
+/* free hardware resources used by driver */
+/******************************************/
+void
+release_io_hfcsx(struct IsdnCardState *cs)
+{
+ int flags;
+
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+ restore_flags(flags);
+ Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */
+ sti();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
+ Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */
+ del_timer(&cs->hw.hfcsx.timer);
+ release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */
+ kfree(cs->hw.hfcsx.extra);
+ cs->hw.hfcsx.extra = NULL;
+}
+
+/**********************************************************/
+/* set_fifo_size determines the size of the RAM and FIFOs */
+/* returning 0 -> need to reset the chip again. */
+/**********************************************************/
+static int set_fifo_size(struct IsdnCardState *cs)
+{
+
+ if (cs->hw.hfcsx.b_fifo_size) return(1); /* already determined */
+
+ if ((cs->hw.hfcsx.chip >> 4) == 9) {
+ cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K;
+ return(1);
+ }
+
+ cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K;
+ cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */
+ return(0);
+
+}
+
+/********************************************************************************/
+/* function called to reset the HFC SX chip. A complete software reset of chip */
+/* and fifos is done. */
+/********************************************************************************/
+static void
+reset_hfcsx(struct IsdnCardState *cs)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+
+ printk(KERN_INFO "HFC_SX: resetting card\n");
+ while (1) {
+ Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */
+ sti();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
+ Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (Read_hfc(cs, HFCSX_STATUS) & 2)
+ printk(KERN_WARNING "HFC-SX init bit busy\n");
+ cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */
+ if (!set_fifo_size(cs)) continue;
+ break;
+ }
+
+ cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */
+ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+
+ Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */
+ cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE;
+ Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */
+ cs->hw.hfcsx.bswapped = 0; /* no exchange */
+ cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */
+ cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+
+ cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC |
+ HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+
+ /* Clear already pending ints */
+ if (Read_hfc(cs, HFCSX_INT_S1));
+
+ Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */
+ cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */
+
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+ cs->hw.hfcsx.sctrl_r = 0;
+ Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+
+ /* Init GCI/IOM2 in master mode */
+ /* Slots 0 and 1 are set for B-chan 1 and 2 */
+ /* D- and monitor/CI channel are not enabled */
+ /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
+ /* STIO2 is used as data input, B1+B2 from IOM->ST */
+ /* ST B-channel send disabled -> continous 1s */
+ /* The IOM slots are always enabled */
+ cs->hw.hfcsx.conn = 0x36; /* set data flow directions */
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
+ Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
+ Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
+ Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
+
+ /* Finally enable IRQ output */
+ cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+ if (Read_hfc(cs, HFCSX_INT_S2));
+ restore_flags(flags);
+}
+
+/***************************************************/
+/* Timer function called when kernel timer expires */
+/***************************************************/
+static void
+hfcsx_Timer(struct IsdnCardState *cs)
+{
+ cs->hw.hfcsx.timer.expires = jiffies + 75;
+ /* WD RESET */
+/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80);
+ add_timer(&cs->hw.hfcsx.timer);
+ */
+}
+
+
+/*********************************/
+/* schedule a new D-channel task */
+/*********************************/
+static void
+sched_event_D_sx(struct IsdnCardState *cs, int event)
+{
+ test_and_set_bit(event, &cs->event);
+ queue_task(&cs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/*********************************/
+/* schedule a new b_channel task */
+/*********************************/
+static void
+hfcsx_sched_event(struct BCState *bcs, int event)
+{
+ bcs->event |= 1 << event;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/************************************************/
+/* select a b-channel entry matching and active */
+/************************************************/
+static
+struct BCState *
+Sel_BCS(struct IsdnCardState *cs, int channel)
+{
+ if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
+ return (&cs->bcs[0]);
+ else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
+ return (&cs->bcs[1]);
+ else
+ return (NULL);
+}
+
+/*******************************/
+/* D-channel receive procedure */
+/*******************************/
+static
+int
+receive_dmsg(struct IsdnCardState *cs)
+{
+ struct sk_buff *skb;
+ int count = 5;
+
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "rec_dmsg blocked");
+ return (1);
+ }
+
+ do {
+ skb = read_fifo(cs, HFCSX_SEL_D_RX, 0);
+ if (skb) {
+ skb_queue_tail(&cs->rq, skb);
+ sched_event_D_sx(cs, D_RCVBUFREADY);
+ }
+ } while (--count && skb);
+
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ return (1);
+}
+
+/**********************************/
+/* B-channel main receive routine */
+/**********************************/
+void
+main_rec_hfcsx(struct BCState *bcs)
+{
+ long flags;
+ struct IsdnCardState *cs = bcs->cs;
+ int count = 5;
+ struct sk_buff *skb;
+
+ save_flags(flags);
+
+ Begin:
+ count--;
+ cli();
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "rec_data %d blocked", bcs->channel);
+ restore_flags(flags);
+ return;
+ }
+ sti();
+ skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
+ HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX,
+ (bcs->mode == L1_MODE_TRANS) ?
+ HFCSX_BTRANS_THRESHOLD : 0);
+
+ if (skb) {
+ cli();
+ skb_queue_tail(&bcs->rqueue, skb);
+ sti();
+ hfcsx_sched_event(bcs, B_RCVBUFREADY);
+ }
+
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ if (count && skb)
+ goto Begin;
+ restore_flags(flags);
+ return;
+}
+
+/**************************/
+/* D-channel send routine */
+/**************************/
+static void
+hfcsx_fill_dfifo(struct IsdnCardState *cs)
+{
+ if (!cs->tx_skb)
+ return;
+ if (cs->tx_skb->len <= 0)
+ return;
+
+ if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) {
+ dev_kfree_skb(cs->tx_skb);
+ cs->tx_skb = NULL;
+ }
+ return;
+}
+
+/**************************/
+/* B-channel send routine */
+/**************************/
+static void
+hfcsx_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int flags;
+
+ if (!bcs->tx_skb)
+ return;
+ if (bcs->tx_skb->len <= 0)
+ return;
+
+ save_flags(flags);
+ sti();
+
+ if (write_fifo(cs, bcs->tx_skb,
+ ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
+ HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX,
+ (bcs->mode == L1_MODE_TRANS) ?
+ HFCSX_BTRANS_THRESHOLD : 0)) {
+
+ bcs->tx_cnt -= bcs->tx_skb->len;
+ if (bcs->st->lli.l1writewakeup &&
+ (PACKET_NOACK != bcs->tx_skb->pkt_type))
+ bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
+ dev_kfree_skb(bcs->tx_skb);
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+
+ cli();
+ restore_flags(flags);
+ return;
+}
+
+/**********************************************/
+/* D-channel l1 state call for leased NT-mode */
+/**********************************************/
+static void
+dch_nt_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+
+ switch (pr) {
+ case (PH_DATA | REQUEST):
+ case (PH_PULL | REQUEST):
+ case (PH_PULL | INDICATION):
+ st->l1.l1hw(st, pr, arg);
+ break;
+ case (PH_ACTIVATE | REQUEST):
+ st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ break;
+ case (PH_TESTLOOP | REQUEST):
+ if (1 & (long) arg)
+ debugl1(cs, "PH_TEST_LOOP B1");
+ if (2 & (long) arg)
+ debugl1(cs, "PH_TEST_LOOP B2");
+ if (!(3 & (long) arg))
+ debugl1(cs, "PH_TEST_LOOP DISABLED");
+ st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
+ break;
+ default:
+ if (cs->debug)
+ debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
+ break;
+ }
+}
+
+
+
+/***********************/
+/* set/reset echo mode */
+/***********************/
+static int
+hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
+{
+ int flags;
+ int i = *(unsigned int *) ic->parm.num;
+
+ if ((ic->arg == 98) &&
+ (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) {
+ save_flags(flags);
+ cli();
+ Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */
+ udelay(10);
+ cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT;
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+ cs->dc.hfcsx.ph_state = 1;
+ cs->hw.hfcsx.nt_mode = 1;
+ cs->hw.hfcsx.nt_timer = 0;
+ cs->stlist->l2.l2l1 = dch_nt_l2l1;
+ restore_flags(flags);
+ debugl1(cs, "NT mode activated");
+ return (0);
+ }
+ if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) ||
+ (cs->hw.hfcsx.nt_mode) || (ic->arg != 12))
+ return (-EINVAL);
+
+ save_flags(flags);
+ cli();
+ if (i) {
+ cs->logecho = 1;
+ cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */
+ cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC;
+ /* reset Channel !!!!! */
+ } else {
+ cs->logecho = 0;
+ cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC;
+ }
+ cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
+ cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */
+ cs->hw.hfcsx.ctmt &= ~2;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+ Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ restore_flags(flags);
+ return (0);
+} /* hfcsx_auxcmd */
+
+/*****************************/
+/* E-channel receive routine */
+/*****************************/
+static void
+receive_emsg(struct IsdnCardState *cs)
+{
+ int flags;
+ int count = 5;
+ u_char *ptr;
+ struct sk_buff *skb;
+
+
+ save_flags(flags);
+ cli();
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "echo_rec_data blocked");
+ restore_flags(flags);
+ return;
+ }
+ sti();
+
+ do {
+ skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0);
+ if (skb) {
+ if (cs->debug & DEB_DLOG_HEX) {
+ ptr = cs->dlog;
+ if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
+ *ptr++ = 'E';
+ *ptr++ = 'C';
+ *ptr++ = 'H';
+ *ptr++ = 'O';
+ *ptr++ = ':';
+ ptr += QuickHex(ptr, skb->data, skb->len);
+ ptr--;
+ *ptr++ = '\n';
+ *ptr = 0;
+ HiSax_putstatus(cs, NULL, cs->dlog);
+ } else
+ HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
+ }
+ dev_kfree_skb(skb);
+ }
+ } while (--count && skb);
+
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ restore_flags(flags);
+ return;
+} /* receive_emsg */
+
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static void
+hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char exval;
+ struct BCState *bcs;
+ int count = 15;
+ long flags;
+ u_char val, stat;
+
+ if (!cs) {
+ printk(KERN_WARNING "HFC-SX: Spurious interrupt!\n");
+ return;
+ }
+ if (!(cs->hw.hfcsx.int_m2 & 0x08))
+ return; /* not initialised */
+
+ if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) {
+ val = Read_hfc(cs, HFCSX_INT_S1);
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val);
+ } else
+ return;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-SX irq %x %s", val,
+ test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+ "locked" : "unlocked");
+ val &= cs->hw.hfcsx.int_m1;
+ if (val & 0x40) { /* state machine irq */
+ exval = Read_hfc(cs, HFCSX_STATES) & 0xf;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state,
+ exval);
+ cs->dc.hfcsx.ph_state = exval;
+ sched_event_D_sx(cs, D_L1STATECHANGE);
+ val &= ~0x40;
+ }
+ if (val & 0x80) { /* timer irq */
+ if (cs->hw.hfcsx.nt_mode) {
+ if ((--cs->hw.hfcsx.nt_timer) < 0)
+ sched_event_D_sx(cs, D_L1STATECHANGE);
+ }
+ val &= ~0x80;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+ }
+ while (val) {
+ save_flags(flags);
+ cli();
+ if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ cs->hw.hfcsx.int_s1 |= val;
+ restore_flags(flags);
+ return;
+ }
+ if (cs->hw.hfcsx.int_s1 & 0x18) {
+ exval = val;
+ val = cs->hw.hfcsx.int_s1;
+ cs->hw.hfcsx.int_s1 = exval;
+ }
+ if (val & 0x08) {
+ if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x08 IRQ");
+ } else
+ main_rec_hfcsx(bcs);
+ }
+ if (val & 0x10) {
+ if (cs->logecho)
+ receive_emsg(cs);
+ else if (!(bcs = Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x10 IRQ");
+ } else
+ main_rec_hfcsx(bcs);
+ }
+ if (val & 0x01) {
+ if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x01 IRQ");
+ } else {
+ if (bcs->tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ hfcsx_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+ }
+ }
+ if (val & 0x02) {
+ if (!(bcs = Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x02 IRQ");
+ } else {
+ if (bcs->tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ hfcsx_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+ }
+ }
+ if (val & 0x20) { /* receive dframe */
+ receive_dmsg(cs);
+ }
+ if (val & 0x04) { /* dframe transmitted */
+ if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+ del_timer(&cs->dbusytimer);
+ if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+ sched_event_D_sx(cs, D_CLEARBUSY);
+ if (cs->tx_skb) {
+ if (cs->tx_skb->len) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+ }
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(cs->tx_skb);
+ cs->tx_cnt = 0;
+ cs->tx_skb = NULL;
+ }
+ }
+ if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+ cs->tx_cnt = 0;
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+ }
+ } else
+ sched_event_D_sx(cs, D_XMTBUFREADY);
+ }
+ afterXPR:
+ if (cs->hw.hfcsx.int_s1 && count--) {
+ val = cs->hw.hfcsx.int_s1;
+ cs->hw.hfcsx.int_s1 = 0;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count);
+ } else
+ val = 0;
+ restore_flags(flags);
+ }
+}
+
+/********************************************************************/
+/* timer callback for D-chan busy resolution. Currently no function */
+/********************************************************************/
+static void
+hfcsx_dbusy_timer(struct IsdnCardState *cs)
+{
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static void
+HFCSX_l1hw(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+ int flags;
+
+ switch (pr) {
+ case (PH_DATA | REQUEST):
+ if (cs->debug & DEB_DLOG_HEX)
+ LogFrame(cs, skb->data, skb->len);
+ if (cs->debug & DEB_DLOG_VERBOSE)
+ dlogframe(cs, skb, 0);
+ if (cs->tx_skb) {
+ skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+ } else {
+ cs->tx_skb = skb;
+ cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfcsx_fill_dfifo blocked");
+
+ }
+ break;
+ case (PH_PULL | INDICATION):
+ if (cs->tx_skb) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+ skb_queue_tail(&cs->sq, skb);
+ break;
+ }
+ if (cs->debug & DEB_DLOG_HEX)
+ LogFrame(cs, skb->data, skb->len);
+ if (cs->debug & DEB_DLOG_VERBOSE)
+ dlogframe(cs, skb, 0);
+ cs->tx_skb = skb;
+ cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfcsx_fill_dfifo blocked");
+ break;
+ case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+ if (!cs->tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ case (HW_RESET | REQUEST):
+ Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */
+ udelay(6);
+ Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */
+ cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+ l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+ break;
+ case (HW_ENABLE | REQUEST):
+ Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+ break;
+ case (HW_DEACTIVATE | REQUEST):
+ cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER;
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ break;
+ case (HW_INFO3 | REQUEST):
+ cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ break;
+ case (HW_TESTLOOP | REQUEST):
+ switch ((int) arg) {
+ case (1):
+ Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */
+ Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1;
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ restore_flags(flags);
+ break;
+
+ case (2):
+ Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */
+ Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08;
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ restore_flags(flags);
+ break;
+
+ default:
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg);
+ return;
+ }
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
+ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+ restore_flags(flags);
+ break;
+ default:
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr);
+ break;
+ }
+}
+
+/***********************************************/
+/* called during init setting l1 stack pointer */
+/***********************************************/
+void
+setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l1.l1hw = HFCSX_l1hw;
+}
+
+/**************************************/
+/* send B-channel data if not blocked */
+/**************************************/
+static void
+hfcsx_send_data(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "send_data %d blocked", bcs->channel);
+}
+
+/***************************************************************/
+/* activate/deactivate hardware for selected channels and mode */
+/***************************************************************/
+void
+mode_hfcsx(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int flags, fifo2;
+
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d",
+ mode, bc, bcs->channel);
+ bcs->mode = mode;
+ bcs->channel = bc;
+ fifo2 = bc;
+ save_flags(flags);
+ cli();
+ if (cs->chanlimit > 1) {
+ cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcsx.sctrl_e &= ~0x80;
+ } else {
+ if (bc) {
+ if (mode != L1_MODE_NULL) {
+ cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */
+ cs->hw.hfcsx.sctrl_e |= 0x80;
+ } else {
+ cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcsx.sctrl_e &= ~0x80;
+ }
+ fifo2 = 0;
+ } else {
+ cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcsx.sctrl_e &= ~0x80;
+ }
+ }
+ switch (mode) {
+ case (L1_MODE_NULL):
+ if (bc) {
+ cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA;
+ }
+ if (fifo2) {
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ } else {
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ }
+ break;
+ case (L1_MODE_TRANS):
+ if (bc) {
+ cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+ }
+ if (fifo2) {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ cs->hw.hfcsx.ctmt |= 2;
+ cs->hw.hfcsx.conn &= ~0x18;
+ } else {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ cs->hw.hfcsx.ctmt |= 1;
+ cs->hw.hfcsx.conn &= ~0x03;
+ }
+ break;
+ case (L1_MODE_HDLC):
+ if (bc) {
+ cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+ }
+ if (fifo2) {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ cs->hw.hfcsx.ctmt &= ~2;
+ cs->hw.hfcsx.conn &= ~0x18;
+ } else {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ cs->hw.hfcsx.ctmt &= ~1;
+ cs->hw.hfcsx.conn &= ~0x03;
+ }
+ break;
+ case (L1_MODE_EXTRN):
+ if (bc) {
+ cs->hw.hfcsx.conn |= 0x10;
+ cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ } else {
+ cs->hw.hfcsx.conn |= 0x02;
+ cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ }
+ break;
+ }
+ Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e);
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+ Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ if (mode != L1_MODE_EXTRN) {
+ reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX);
+ reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX);
+ }
+ restore_flags(flags);
+}
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static void
+hfcsx_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA | REQUEST):
+ save_flags(flags);
+ cli();
+ if (st->l1.bcs->tx_skb) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ restore_flags(flags);
+ } else {
+ st->l1.bcs->tx_skb = skb;
+/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ */ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ }
+ break;
+ case (PH_PULL | INDICATION):
+ if (st->l1.bcs->tx_skb) {
+ printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+ break;
+ }
+ save_flags(flags);
+ cli();
+/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ */ st->l1.bcs->tx_skb = skb;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ break;
+ case (PH_PULL | REQUEST):
+ if (!st->l1.bcs->tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ case (PH_ACTIVATE | REQUEST):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ mode_hfcsx(st->l1.bcs, st->l1.mode, st->l1.bc);
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | REQUEST):
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | CONFIRM):
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ mode_hfcsx(st->l1.bcs, 0, st->l1.bc);
+ st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ break;
+ }
+}
+
+/******************************************/
+/* deactivate B-channel access and queues */
+/******************************************/
+static void
+close_hfcsx(struct BCState *bcs)
+{
+ mode_hfcsx(bcs, 0, bcs->channel);
+ if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+ discard_queue(&bcs->rqueue);
+ discard_queue(&bcs->squeue);
+ if (bcs->tx_skb) {
+ dev_kfree_skb(bcs->tx_skb);
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+}
+
+/*************************************/
+/* init B-channel queues and control */
+/*************************************/
+static int
+open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs)
+{
+ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->event = 0;
+ bcs->tx_cnt = 0;
+ return (0);
+}
+
+/*********************************/
+/* inits the stack for B-channel */
+/*********************************/
+static int
+setstack_2b(struct PStack *st, struct BCState *bcs)
+{
+ bcs->channel = st->l1.bc;
+ if (open_hfcsxstate(st->l1.hardware, bcs))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = hfcsx_l2l1;
+ setstack_manager(st);
+ bcs->st = st;
+ setstack_l1_B(st);
+ return (0);
+}
+
+/***************************/
+/* handle L1 state changes */
+/***************************/
+static void
+hfcsx_bh(struct IsdnCardState *cs)
+{
+ int flags;
+/* struct PStack *stptr;
+ */
+ if (!cs)
+ return;
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ if (!cs->hw.hfcsx.nt_mode)
+ switch (cs->dc.hfcsx.ph_state) {
+ case (0):
+ l1_msg(cs, HW_RESET | INDICATION, NULL);
+ break;
+ case (3):
+ l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+ break;
+ case (8):
+ l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+ break;
+ case (6):
+ l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+ break;
+ case (7):
+ l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+ break;
+ default:
+ break;
+ } else {
+ switch (cs->dc.hfcsx.ph_state) {
+ case (2):
+ save_flags(flags);
+ cli();
+ if (cs->hw.hfcsx.nt_timer < 0) {
+ cs->hw.hfcsx.nt_timer = 0;
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ /* Clear already pending ints */
+ if (Read_hfc(cs, HFCSX_INT_S1));
+
+ Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE);
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, 4);
+ cs->dc.hfcsx.ph_state = 4;
+ } else {
+ cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER;
+ cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+ cs->hw.hfcsx.nt_timer = NT_T1_COUNT;
+ Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */
+ }
+ restore_flags(flags);
+ break;
+ case (1):
+ case (3):
+ case (4):
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.nt_timer = 0;
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ restore_flags(flags);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
+ DChannel_proc_rcv(cs);
+ if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
+ DChannel_proc_xmt(cs);
+}
+
+
+/********************************/
+/* called for card init message */
+/********************************/
+__initfunc(void
+ inithfcsx(struct IsdnCardState *cs))
+{
+ cs->setstack_d = setstack_hfcsx;
+ cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
+ cs->dbusytimer.data = (long) cs;
+ init_timer(&cs->dbusytimer);
+ cs->tqueue.routine = (void *) (void *) hfcsx_bh;
+ cs->BC_Send_Data = &hfcsx_send_data;
+ cs->bcs[0].BC_SetStack = setstack_2b;
+ cs->bcs[1].BC_SetStack = setstack_2b;
+ cs->bcs[0].BC_Close = close_hfcsx;
+ cs->bcs[1].BC_Close = close_hfcsx;
+ mode_hfcsx(cs->bcs, 0, 0);
+ mode_hfcsx(cs->bcs + 1, 0, 1);
+}
+
+
+
+/*******************************************/
+/* handle card messages from control layer */
+/*******************************************/
+static int
+hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ long flags;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFCSX: card_msg %x", mt);
+ switch (mt) {
+ case CARD_RESET:
+ reset_hfcsx(cs);
+ return (0);
+ case CARD_RELEASE:
+ release_io_hfcsx(cs);
+ return (0);
+ case CARD_INIT:
+ inithfcsx(cs);
+ save_flags(flags);
+ sti();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */
+ /* now switch timer interrupt off */
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ /* reinit mode reg */
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ restore_flags(flags);
+ return (0);
+ case CARD_TEST:
+ return (0);
+ }
+ return (0);
+}
+
+
+
+__initfunc(int
+ setup_hfcsx(struct IsdnCard *card))
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ int flags;
+
+ strcpy(tmp, hfcsx_revision);
+ printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.hfcsx.base = card->para[1] & 0xfffe;
+ cs->irq = card->para[0];
+ cs->hw.hfcsx.int_s1 = 0;
+ cs->dc.hfcsx.ph_state = 0;
+ cs->hw.hfcsx.fifo = 255;
+ if (cs->typ == ISDN_CTYPE_HFC_SX) {
+ if ((!cs->hw.hfcsx.base) ||
+ check_region((cs->hw.hfcsx.base), 2)) {
+ printk(KERN_WARNING
+ "HiSax: HFC-SX io-base 0x%x already in use\n",
+ cs->hw.hfcsx.base);
+ return(0);
+ } else {
+ request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn");
+ }
+ byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF);
+ byteout(cs->hw.hfcsx.base + 1,
+ ((cs->hw.hfcsx.base >> 8) & 3) | 0x54);
+ udelay(10);
+ cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID);
+ switch (cs->hw.hfcsx.chip >> 4) {
+ case 1:
+ tmp[0] ='+';
+ break;
+ case 9:
+ tmp[0] ='P';
+ break;
+ default:
+ printk(KERN_WARNING
+ "HFC-SX: invalid chip id 0x%x\n",
+ cs->hw.hfcsx.chip >> 4);
+ release_region(cs->hw.hfcsx.base, 2);
+ return(0);
+ }
+ if (!ccd_sp_irqtab[cs->irq & 0xF]) {
+ printk(KERN_WARNING
+ "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF);
+ release_region(cs->hw.hfcsx.base, 2);
+ return(0);
+ }
+ save_flags(flags);
+ cli();
+ if (!(cs->hw.hfcsx.extra = (void *)
+ kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) {
+ restore_flags(flags);
+ release_region(cs->hw.hfcsx.base, 2);
+ printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
+ return(0);
+ }
+ restore_flags(flags);
+
+ printk(KERN_INFO
+ "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n",
+ tmp[0], (u_int) cs->hw.hfcsx.base,
+ cs->irq, HZ);
+ cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */
+ cs->hw.hfcsx.int_m1 = 0;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+ } else
+ return (0); /* no valid card type */
+
+ cs->readisac = NULL;
+ cs->writeisac = NULL;
+ cs->readisacfifo = NULL;
+ cs->writeisacfifo = NULL;
+ cs->BC_Read_Reg = NULL;
+ cs->BC_Write_Reg = NULL;
+ cs->irq_func = &hfcsx_interrupt;
+
+ cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer;
+ cs->hw.hfcsx.timer.data = (long) cs;
+ cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */
+ cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */
+ init_timer(&cs->hw.hfcsx.timer);
+
+ reset_hfcsx(cs);
+ cs->cardmsg = &hfcsx_card_msg;
+ cs->auxcmd = &hfcsx_auxcmd;
+ return (1);
+}
+
+
+
+
diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h
new file mode 100644
index 000000000..ebb8d3e7d
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_sx.h
@@ -0,0 +1,216 @@
+/* $Id: hfc_sx.h,v 1.1 1999/11/18 00:09:18 werner Exp $
+
+ * specific defines for CCD's HFC 2BDS0 S+,SP chips
+ *
+ * Author Werner Cornelius (werner@isdn4linux.de)
+ *
+ * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hfc_sx.h,v $
+ * Revision 1.1 1999/11/18 00:09:18 werner
+ *
+ * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
+ * Audio and Echo are supported.
+ *
+ *
+ *
+ */
+
+/*********************************************/
+/* thresholds for transparent B-channel mode */
+/* change mask and threshold simultaneously */
+/*********************************************/
+#define HFCSX_BTRANS_THRESHOLD 128
+#define HFCSX_BTRANS_THRESMASK 0x00
+
+/* GCI/IOM bus monitor registers */
+
+#define HFCSX_C_I 0x02
+#define HFCSX_TRxR 0x03
+#define HFCSX_MON1_D 0x0A
+#define HFCSX_MON2_D 0x0B
+
+
+/* GCI/IOM bus timeslot registers */
+
+#define HFCSX_B1_SSL 0x20
+#define HFCSX_B2_SSL 0x21
+#define HFCSX_AUX1_SSL 0x22
+#define HFCSX_AUX2_SSL 0x23
+#define HFCSX_B1_RSL 0x24
+#define HFCSX_B2_RSL 0x25
+#define HFCSX_AUX1_RSL 0x26
+#define HFCSX_AUX2_RSL 0x27
+
+/* GCI/IOM bus data registers */
+
+#define HFCSX_B1_D 0x28
+#define HFCSX_B2_D 0x29
+#define HFCSX_AUX1_D 0x2A
+#define HFCSX_AUX2_D 0x2B
+
+/* GCI/IOM bus configuration registers */
+
+#define HFCSX_MST_EMOD 0x2D
+#define HFCSX_MST_MODE 0x2E
+#define HFCSX_CONNECT 0x2F
+
+
+/* Interrupt and status registers */
+
+#define HFCSX_TRM 0x12
+#define HFCSX_B_MODE 0x13
+#define HFCSX_CHIP_ID 0x16
+#define HFCSX_CIRM 0x18
+#define HFCSX_CTMT 0x19
+#define HFCSX_INT_M1 0x1A
+#define HFCSX_INT_M2 0x1B
+#define HFCSX_INT_S1 0x1E
+#define HFCSX_INT_S2 0x1F
+#define HFCSX_STATUS 0x1C
+
+/* S/T section registers */
+
+#define HFCSX_STATES 0x30
+#define HFCSX_SCTRL 0x31
+#define HFCSX_SCTRL_E 0x32
+#define HFCSX_SCTRL_R 0x33
+#define HFCSX_SQ 0x34
+#define HFCSX_CLKDEL 0x37
+#define HFCSX_B1_REC 0x3C
+#define HFCSX_B1_SEND 0x3C
+#define HFCSX_B2_REC 0x3D
+#define HFCSX_B2_SEND 0x3D
+#define HFCSX_D_REC 0x3E
+#define HFCSX_D_SEND 0x3E
+#define HFCSX_E_REC 0x3F
+
+/****************/
+/* FIFO section */
+/****************/
+#define HFCSX_FIF_SEL 0x10
+#define HFCSX_FIF_Z1L 0x80
+#define HFCSX_FIF_Z1H 0x84
+#define HFCSX_FIF_Z2L 0x88
+#define HFCSX_FIF_Z2H 0x8C
+#define HFCSX_FIF_INCF1 0xA8
+#define HFCSX_FIF_DWR 0xAC
+#define HFCSX_FIF_F1 0xB0
+#define HFCSX_FIF_F2 0xB4
+#define HFCSX_FIF_INCF2 0xB8
+#define HFCSX_FIF_DRD 0xBC
+
+/* bits in status register (READ) */
+#define HFCSX_SX_PROC 0x02
+#define HFCSX_NBUSY 0x04
+#define HFCSX_TIMER_ELAP 0x10
+#define HFCSX_STATINT 0x20
+#define HFCSX_FRAMEINT 0x40
+#define HFCSX_ANYINT 0x80
+
+/* bits in CTMT (Write) */
+#define HFCSX_CLTIMER 0x80
+#define HFCSX_TIM3_125 0x04
+#define HFCSX_TIM25 0x10
+#define HFCSX_TIM50 0x14
+#define HFCSX_TIM400 0x18
+#define HFCSX_TIM800 0x1C
+#define HFCSX_AUTO_TIMER 0x20
+#define HFCSX_TRANSB2 0x02
+#define HFCSX_TRANSB1 0x01
+
+/* bits in CIRM (Write) */
+#define HFCSX_IRQ_SELMSK 0x07
+#define HFCSX_IRQ_SELDIS 0x00
+#define HFCSX_RESET 0x08
+#define HFCSX_FIFO_RESET 0x80
+
+
+/* bits in INT_M1 and INT_S1 */
+#define HFCSX_INTS_B1TRANS 0x01
+#define HFCSX_INTS_B2TRANS 0x02
+#define HFCSX_INTS_DTRANS 0x04
+#define HFCSX_INTS_B1REC 0x08
+#define HFCSX_INTS_B2REC 0x10
+#define HFCSX_INTS_DREC 0x20
+#define HFCSX_INTS_L1STATE 0x40
+#define HFCSX_INTS_TIMER 0x80
+
+/* bits in INT_M2 */
+#define HFCSX_PROC_TRANS 0x01
+#define HFCSX_GCI_I_CHG 0x02
+#define HFCSX_GCI_MON_REC 0x04
+#define HFCSX_IRQ_ENABLE 0x08
+
+/* bits in STATES */
+#define HFCSX_STATE_MSK 0x0F
+#define HFCSX_LOAD_STATE 0x10
+#define HFCSX_ACTIVATE 0x20
+#define HFCSX_DO_ACTION 0x40
+#define HFCSX_NT_G2_G3 0x80
+
+/* bits in HFCD_MST_MODE */
+#define HFCSX_MASTER 0x01
+#define HFCSX_SLAVE 0x00
+/* remaining bits are for codecs control */
+
+/* bits in HFCD_SCTRL */
+#define SCTRL_B1_ENA 0x01
+#define SCTRL_B2_ENA 0x02
+#define SCTRL_MODE_TE 0x00
+#define SCTRL_MODE_NT 0x04
+#define SCTRL_LOW_PRIO 0x08
+#define SCTRL_SQ_ENA 0x10
+#define SCTRL_TEST 0x20
+#define SCTRL_NONE_CAP 0x40
+#define SCTRL_PWR_DOWN 0x80
+
+/* bits in SCTRL_E */
+#define HFCSX_AUTO_AWAKE 0x01
+#define HFCSX_DBIT_1 0x04
+#define HFCSX_IGNORE_COL 0x08
+#define HFCSX_CHG_B1_B2 0x80
+
+/**********************************/
+/* definitions for FIFO selection */
+/**********************************/
+#define HFCSX_SEL_D_RX 5
+#define HFCSX_SEL_D_TX 4
+#define HFCSX_SEL_B1_RX 1
+#define HFCSX_SEL_B1_TX 0
+#define HFCSX_SEL_B2_RX 3
+#define HFCSX_SEL_B2_TX 2
+
+#define MAX_D_FRAMES 15
+#define MAX_B_FRAMES 31
+#define B_SUB_VAL_32K 0x0200
+#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K)
+#define B_SUB_VAL_8K 0x1A00
+#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K)
+#define D_FIFO_SIZE 512
+#define D_FREG_MASK 0xF
+
+/************************************************************/
+/* structure holding additional dynamic data -> send marker */
+/************************************************************/
+struct hfcsx_extra {
+ unsigned short marker[2*(MAX_B_FRAMES+1) + (MAX_D_FRAMES+1)];
+};
+
+extern void main_irq_hfcsx(struct BCState *bcs);
+extern void inithfcsx(struct IsdnCardState *cs);
+extern void releasehfcsx(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index 8654857fd..7015f4bb5 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -1,4 +1,4 @@
-/* $Id: hfcscard.c,v 1.5 1999/09/04 06:20:06 keil Exp $
+/* $Id: hfcscard.c,v 1.6 1999/12/19 13:09:42 keil Exp $
* hfcscard.c low level stuff for hfcs based cards (Teles3c, ACER P10)
*
@@ -6,6 +6,10 @@
*
*
* $Log: hfcscard.c,v $
+ * Revision 1.6 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.5 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -30,7 +34,7 @@
extern const char *CardType[];
-static const char *hfcs_revision = "$Revision: 1.5 $";
+static const char *hfcs_revision = "$Revision: 1.6 $";
static void
hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
@@ -85,13 +89,13 @@ reset_hfcs(struct IsdnCardState *cs)
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000);
cs->hw.hfcD.cirm = 0;
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_MEM8K;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_INTB;
@@ -138,7 +142,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
init2bds0(cs);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((80*HZ)/1000);
cs->hw.hfcD.ctmt |= HFCD_TIM800;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 0c67d5c4a..6f5b5615c 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1,8 +1,16 @@
-/* $Id: hisax.h,v 2.38 1999/11/14 23:37:03 keil Exp $
+/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $
* Basic declarations, defines and prototypes
*
* $Log: hisax.h,v $
+ * Revision 2.40 2000/01/20 19:51:46 keil
+ * Fix AddTimer message
+ * Change CONFIG defines
+ *
+ * Revision 2.39 1999/11/18 00:00:43 werner
+ *
+ * Added support for HFC-S+ and HFC-SP cards
+ *
* Revision 2.38 1999/11/14 23:37:03 keil
* new ISA memory mapped IO
*
@@ -784,6 +792,31 @@ struct hfcPCI_hw {
struct timer_list timer;
};
+struct hfcSX_hw {
+ unsigned int base;
+ unsigned char cirm;
+ unsigned char ctmt;
+ unsigned char conn;
+ unsigned char mst_m;
+ unsigned char int_m1;
+ unsigned char int_m2;
+ unsigned char int_s1;
+ unsigned char sctrl;
+ unsigned char sctrl_r;
+ unsigned char sctrl_e;
+ unsigned char trm;
+ unsigned char stat;
+ unsigned char fifo;
+ unsigned char bswapped;
+ unsigned char nt_mode;
+ unsigned char chip;
+ int b_fifo_size;
+ unsigned char last_fifo;
+ void *extra;
+ int nt_timer;
+ struct timer_list timer;
+};
+
struct hfcD_hw {
unsigned int addr;
unsigned int bfifosize;
@@ -894,6 +927,10 @@ struct hfcpci_chip {
int ph_state;
};
+struct hfcsx_chip {
+ int ph_state;
+};
+
struct w6692_chip {
int ph_state;
};
@@ -934,6 +971,7 @@ struct IsdnCardState {
struct njet_hw njet;
struct hfcD_hw hfcD;
struct hfcPCI_hw hfcpci;
+ struct hfcSX_hw hfcsx;
struct ix1_hw niccy;
struct isurf_hw isurf;
struct saphir_hw saphir;
@@ -973,6 +1011,7 @@ struct IsdnCardState {
struct isac_chip isac;
struct hfcd_chip hfcd;
struct hfcpci_chip hfcpci;
+ struct hfcsx_chip hfcsx;
struct w6692_chip w6692;
} dc;
u_char *rcvbuf;
@@ -1032,7 +1071,8 @@ struct IsdnCardState {
#define ISDN_CTYPE_GAZEL 34
#define ISDN_CTYPE_HFC_PCI 35
#define ISDN_CTYPE_W6692 36
-#define ISDN_CTYPE_COUNT 36
+#define ISDN_CTYPE_HFC_SX 37
+#define ISDN_CTYPE_COUNT 37
#ifdef ISDN_CHIP_ISAC
@@ -1201,6 +1241,12 @@ struct IsdnCardState {
#define CARD_HFC_PCI 0
#endif
+#ifdef CONFIG_HISAX_HFC_SX
+#define CARD_HFC_SX 1
+#else
+#define CARD_HFC_SX 0
+#endif
+
#ifdef CONFIG_HISAX_AMD7930
#define CARD_AMD7930 1
#else
@@ -1298,19 +1344,6 @@ struct IsdnCardState {
#ifdef CONFIG_HISAX_EURO
#undef TEI_PER_CARD
#define TEI_PER_CARD 1
-#define HISAX_EURO_SENDCOMPLETE 1
-#define EXT_BEARER_CAPS 1
-#define HISAX_SEND_STD_LLC_IE 1
-#ifdef CONFIG_HISAX_NO_SENDCOMPLETE
-#undef HISAX_EURO_SENDCOMPLETE
-#endif
-#ifdef CONFIG_HISAX_NO_LLC
-#undef HISAX_SEND_STD_LLC_IE
-#endif
-#undef HISAX_DE_AOC
-#ifdef CONFIG_DE_AOC
-#define HISAX_DE_AOC 1
-#endif
#endif
/* L1 Debug */
diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h
index 08801bc73..00b566a44 100644
--- a/drivers/isdn/hisax/hscx.h
+++ b/drivers/isdn/hisax/hscx.h
@@ -1,11 +1,14 @@
-/* $Id: hscx.h,v 1.4 1998/04/15 16:45:34 keil Exp $
+/* $Id: hscx.h,v 1.5 1999/12/23 15:09:32 keil Exp $
* hscx.h HSCX specific defines
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hscx.h,v $
+ * Revision 1.5 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.4 1998/04/15 16:45:34 keil
* new init code
*
diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h
index 82c5fa8f8..34a85dd6b 100644
--- a/drivers/isdn/hisax/ipac.h
+++ b/drivers/isdn/hisax/ipac.h
@@ -1,11 +1,14 @@
-/* $Id: ipac.h,v 1.3 1998/04/15 16:48:09 keil Exp $
+/* $Id: ipac.h,v 1.4 1999/12/23 15:09:32 keil Exp $
* ipac.h IPAC specific defines
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: ipac.h,v $
+ * Revision 1.4 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.3 1998/04/15 16:48:09 keil
* IPAC_ATX added
*
diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h
index bed887d4f..a8a46e135 100644
--- a/drivers/isdn/hisax/isac.h
+++ b/drivers/isdn/hisax/isac.h
@@ -1,11 +1,14 @@
-/* $Id: isac.h,v 1.5 1998/05/25 12:58:03 keil Exp $
+/* $Id: isac.h,v 1.6 1999/12/23 15:09:32 keil Exp $
* isac.h ISAC specific defines
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: isac.h,v $
+ * Revision 1.6 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.5 1998/05/25 12:58:03 keil
* HiSax golden code from certification, Don't use !!!
* No leased lines, no X75, but many changes.
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 417f2157d..bfff86707 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.7 1999/10/14 20:25:29 keil Exp $
+/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $
* isar.c ISAR (Siemens PSB 7110) specific routines
*
@@ -6,6 +6,12 @@
*
*
* $Log: isar.c,v $
+ * Revision 1.9 2000/01/20 19:47:45 keil
+ * Add Fax Class 1 support
+ *
+ * Revision 1.8 1999/12/19 13:00:56 keil
+ * Fix races in setting a new mode
+ *
* Revision 1.7 1999/10/14 20:25:29 keil
* add a statistic for error monitoring
*
@@ -42,7 +48,17 @@
#define MIN(a,b) ((a<b)?a:b)
+#define DLE 0x10
+#define ETX 0x03
+
+
+const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146";
+const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+#define FAXMODCNT 13
+
void isar_setup(struct IsdnCardState *cs);
+static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
+static inline void ll_deliver_faxstat(struct BCState *bcs, u_char status);
static inline int
waitforHIA(struct IsdnCardState *cs, int timeout)
@@ -432,6 +448,12 @@ static void
isar_bh(struct BCState *bcs)
{
BChannel_bh(bcs);
+ if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event))
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR);
+ if (test_and_clear_bit(B_LL_CONNECT, &bcs->event))
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ if (test_and_clear_bit(B_LL_OK, &bcs->event))
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK);
}
static void
@@ -443,6 +465,42 @@ isar_sched_event(struct BCState *bcs, int event)
}
static inline void
+send_DLE_ETX(struct BCState *bcs)
+{
+ u_char dleetx[2] = {DLE,ETX};
+ struct sk_buff *skb;
+
+ if ((skb = dev_alloc_skb(2))) {
+ memcpy(skb_put(skb, 2), dleetx, 2);
+ skb_queue_tail(&bcs->rqueue, skb);
+ isar_sched_event(bcs, B_RCVBUFREADY);
+ } else {
+ printk(KERN_WARNING "HiSax: skb out of memory\n");
+ }
+}
+
+static inline int
+dle_count(unsigned char *buf, int len)
+{
+ int count = 0;
+
+ while (len--)
+ if (*buf++ == DLE)
+ count++;
+ return count;
+}
+
+static inline void
+insert_dle(unsigned char *dest, unsigned char *src, int count) {
+ /* <DLE> in input stream have to be flagged as <DLE><DLE> */
+ while (count--) {
+ *dest++ = *src;
+ if (*src++ == DLE)
+ *dest++ = DLE;
+ }
+}
+
+static inline void
isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
{
u_char *ptr;
@@ -512,6 +570,88 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
}
}
break;
+ case L1_MODE_FAX:
+ if (bcs->hw.isar.state != STFAX_ACTIV) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: not ACTIV");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ break;
+ }
+ if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
+ rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf);
+ bcs->hw.isar.rcvidx = ireg->clsb +
+ dle_count(bcs->hw.isar.rcvbuf, ireg->clsb);
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)",
+ ireg->clsb, bcs->hw.isar.rcvidx);
+ if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+ insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx),
+ bcs->hw.isar.rcvbuf, ireg->clsb);
+ skb_queue_tail(&bcs->rqueue, skb);
+ isar_sched_event(bcs, B_RCVBUFREADY);
+ if (ireg->cmsb & SART_NMD) { /* ABORT */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: no more data");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ send_DLE_ETX(bcs);
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+ 0, NULL);
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ isar_sched_event(bcs, B_LL_NOCARRIER);
+ }
+ } else {
+ printk(KERN_WARNING "HiSax: skb out of memory\n");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ }
+ break;
+ }
+ if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: unknown fax mode %x",
+ bcs->hw.isar.cmd);
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ break;
+ }
+ /* PCTRL_CMD_FRH */
+ if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: incoming packet too large");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ } else if (ireg->cmsb & HDLC_ERROR) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar frame error %x len %d",
+ ireg->cmsb, ireg->clsb);
+ bcs->hw.isar.rcvidx = 0;
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ } else {
+ if (ireg->cmsb & HDLC_FSD)
+ bcs->hw.isar.rcvidx = 0;
+ ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
+ bcs->hw.isar.rcvidx += ireg->clsb;
+ rcv_mbox(cs, ireg, ptr);
+ if (ireg->cmsb & HDLC_FED) {
+ if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
+ printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
+ bcs->hw.isar.rcvidx);
+ } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+ printk(KERN_WARNING "ISAR: receive out of memory\n");
+ } else {
+ memcpy(skb_put(skb, bcs->hw.isar.rcvidx),
+ bcs->hw.isar.rcvbuf,
+ bcs->hw.isar.rcvidx);
+ skb_queue_tail(&bcs->rqueue, skb);
+ isar_sched_event(bcs, B_RCVBUFREADY);
+ send_DLE_ETX(bcs);
+ isar_sched_event(bcs, B_LL_OK);
+ }
+ }
+ }
+ break;
default:
printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
@@ -544,38 +684,57 @@ isar_fill_fifo(struct BCState *bcs)
count = bcs->tx_skb->len;
msb = HDLC_FED;
}
- if (!bcs->hw.isar.txcnt)
- msb |= HDLC_FST;
save_flags(flags);
cli();
ptr = bcs->tx_skb->data;
+ if (!bcs->hw.isar.txcnt) {
+ msb |= HDLC_FST;
+ if ((bcs->mode == L1_MODE_FAX) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) {
+ if (bcs->tx_skb->len > 1) {
+ if ((ptr[0]== 0xff) && (ptr[1] == 0x13))
+ /* last frame */
+ test_and_set_bit(BC_FLG_LASTDATA,
+ &bcs->Flag);
+ }
+ }
+ }
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.isar.txcnt += count;
switch (bcs->mode) {
- case L1_MODE_NULL:
- printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
- break;
- case L1_MODE_TRANS:
- case L1_MODE_V32:
- if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
- 0, count, ptr)) {
- if (cs->debug)
- debugl1(cs, "isar bin data send dp%d failed",
- bcs->hw.isar.dpath);
- }
- break;
- case L1_MODE_HDLC:
- if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
- msb, count, ptr)) {
+ case L1_MODE_NULL:
+ printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
+ break;
+ case L1_MODE_TRANS:
+ case L1_MODE_V32:
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ break;
+ case L1_MODE_HDLC:
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ break;
+ case L1_MODE_FAX:
+ if (bcs->hw.isar.state != STFAX_ACTIV) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_fill_fifo: not ACTIV");
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_fill_fifo: not FTH/FTM");
+ }
+ break;
+ default:
if (cs->debug)
- debugl1(cs, "isar hdlc data send dp%d failed",
- bcs->hw.isar.dpath);
- }
- break;
- default:
- printk(KERN_ERR"isar_fill_fifo mode (%x)error\n", bcs->mode);
- break;
+ debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode);
+ printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode);
+ break;
}
restore_flags(flags);
}
@@ -603,6 +762,18 @@ send_frames(struct BCState *bcs)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt);
+ if (bcs->mode == L1_MODE_FAX) {
+ if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+ if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
+ test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
+ }
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
+ if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) {
+ test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag);
+ test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
+ }
+ }
+ }
dev_kfree_skb(bcs->tx_skb);
bcs->hw.isar.txcnt = 0;
bcs->tx_skb = NULL;
@@ -613,6 +784,18 @@ send_frames(struct BCState *bcs)
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
isar_fill_fifo(bcs);
} else {
+ if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) {
+ if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
+ if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) {
+ u_char dummy = 0;
+ sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) |
+ ISAR_HIS_SDATA, 0x01, 1, &dummy);
+ }
+ test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag);
+ } else {
+ isar_sched_event(bcs, B_LL_CONNECT);
+ }
+ }
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
isar_sched_event(bcs, B_XMTBUFREADY);
}
@@ -639,6 +822,7 @@ check_send(struct IsdnCardState *cs, u_char rdm)
}
}
+
const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
"300", "600", "1200", "2400", "4800", "7200",
"9600nt", "9600t", "12000", "14400", "WRONG"};
@@ -700,7 +884,7 @@ isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
}
static void
-isar_pump_status_ev(struct BCState *bcs, u_char devt) {
+isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
@@ -769,6 +953,192 @@ isar_pump_status_ev(struct BCState *bcs, u_char devt) {
}
}
+static inline void
+ll_deliver_faxstat(struct BCState *bcs, u_char status)
+{
+ isdn_ctrl ic;
+ struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
+
+ if (bcs->cs->debug & L1_DEB_HSCX)
+ debugl1(bcs->cs, "HL->LL FAXIND %x", status);
+ ic.driver = bcs->cs->myid;
+ ic.command = ISDN_STAT_FAXIND;
+ ic.arg = chanp->chan;
+ ic.parm.aux.cmd = status;
+ bcs->cs->iif.statcallb(&ic);
+}
+
+static void
+isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
+ struct IsdnCardState *cs = bcs->cs;
+ u_char dps = SET_DPS(bcs->hw.isar.dpath);
+ u_char p1;
+
+ switch(devt) {
+ case PSEV_10MS_TIMER:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev TIMER");
+ break;
+ case PSEV_RSP_READY:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_READY");
+ bcs->hw.isar.state = STFAX_READY;
+ l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
+ if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
+ isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3);
+ } else {
+ isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3);
+ }
+ break;
+ case PSEV_LINE_TX_H:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_TX_H");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_TX_H wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_LINE_RX_H:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_RX_H");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_RX_H wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_LINE_TX_B:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_TX_B");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_TX_B wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_LINE_RX_B:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_RX_B");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_RX_B wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_RSP_CONN:
+ if (bcs->hw.isar.state == STFAX_CONT) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_CONN");
+ bcs->hw.isar.state = STFAX_ACTIV;
+ test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
+ sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+ /* 1s Flags before data */
+ if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag))
+ del_timer(&bcs->hw.isar.ftimer);
+ /* 1000 ms */
+ bcs->hw.isar.ftimer.expires =
+ jiffies + ((1000 * HZ)/1000);
+ test_and_set_bit(BC_FLG_LL_CONN,
+ &bcs->Flag);
+ add_timer(&bcs->hw.isar.ftimer);
+ } else {
+ isar_sched_event(bcs, B_LL_CONNECT);
+ }
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev RSP_CONN wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_FLAGS_DET:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev FLAGS_DET");
+ break;
+ case PSEV_RSP_DISC:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_DISC");
+ if (bcs->hw.isar.state == STFAX_ESCAPE) {
+ switch(bcs->hw.isar.newcmd) {
+ case PCTRL_CMD_FTH:
+ case PCTRL_CMD_FTM:
+ p1 = 10;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_SILON, 1, &p1);
+ bcs->hw.isar.state = STFAX_SILDET;
+ break;
+ case PCTRL_CMD_FRH:
+ case PCTRL_CMD_FRM:
+ p1 = bcs->hw.isar.newmod;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
+ bcs->hw.isar.newcmd = 0;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+ bcs->hw.isar.cmd, 1, &p1);
+ bcs->hw.isar.state = STFAX_LINE;
+ break;
+ default:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd);
+ break;
+ }
+ } else if (bcs->hw.isar.state == STFAX_ACTIV) {
+ if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) {
+ isar_sched_event(bcs, B_LL_OK);
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
+ send_DLE_ETX(bcs);
+ isar_sched_event(bcs, B_LL_NOCARRIER);
+ } else {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+ }
+ bcs->hw.isar.state = STFAX_READY;
+ } else {
+ bcs->hw.isar.state = STFAX_READY;
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+ }
+ break;
+ case PSEV_RSP_SILDET:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_SILDET");
+ if (bcs->hw.isar.state == STFAX_SILDET) {
+ p1 = bcs->hw.isar.newmod;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
+ bcs->hw.isar.newcmd = 0;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+ bcs->hw.isar.cmd, 1, &p1);
+ bcs->hw.isar.state = STFAX_LINE;
+ }
+ break;
+ case PSEV_RSP_SILOFF:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_SILOFF");
+ break;
+ case PSEV_RSP_FCERR:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_FCERR");
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+ break;
+ default:
+ break;
+ }
+}
+
static char debbuf[128];
void
@@ -788,8 +1158,6 @@ isar_int_main(struct IsdnCardState *cs)
} else {
debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x",
ireg->iis, ireg->cmsb, ireg->clsb);
- printk(KERN_WARNING"isar spurious IIS_RDATA %x/%x/%x\n",
- ireg->iis, ireg->cmsb, ireg->clsb);
cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
}
break;
@@ -815,12 +1183,18 @@ isar_int_main(struct IsdnCardState *cs)
case ISAR_IIS_PSTEV:
if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
rcv_mbox(cs, ireg, (u_char *)ireg->par);
- isar_pump_status_ev(bcs, ireg->cmsb);
+ if (bcs->mode == L1_MODE_V32) {
+ isar_pump_statev_modem(bcs, ireg->cmsb);
+ } else if (bcs->mode == L1_MODE_FAX) {
+ isar_pump_statev_fax(bcs, ireg->cmsb);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
+ bcs->mode, ireg->cmsb);
+ }
} else {
debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x",
ireg->iis, ireg->cmsb, ireg->clsb);
- printk(KERN_WARNING"isar spurious IIS_PSTEV %x/%x/%x\n",
- ireg->iis, ireg->cmsb, ireg->clsb);
cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
}
break;
@@ -831,8 +1205,6 @@ isar_int_main(struct IsdnCardState *cs)
} else {
debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x",
ireg->iis, ireg->cmsb, ireg->clsb);
- printk(KERN_WARNING"isar spurious IIS_PSTRSP %x/%x/%x\n",
- ireg->iis, ireg->cmsb, ireg->clsb);
cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
}
break;
@@ -867,6 +1239,17 @@ isar_int_main(struct IsdnCardState *cs)
}
static void
+ftimer_handler(struct BCState *bcs) {
+ if (bcs->cs->debug)
+ debugl1(bcs->cs, "ftimer flags %04x",
+ bcs->Flag);
+ test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
+ if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
+ isar_sched_event(bcs, B_LL_CONNECT);
+ }
+}
+
+static void
setup_pump(struct BCState *bcs) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
@@ -876,11 +1259,7 @@ setup_pump(struct BCState *bcs) {
case L1_MODE_NULL:
case L1_MODE_TRANS:
case L1_MODE_HDLC:
- if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar pump bypass cfg dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
break;
case L1_MODE_V32:
ctrl = PMOD_DATAMODEM;
@@ -896,11 +1275,7 @@ setup_pump(struct BCState *bcs) {
param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
param[3] = PV32P4_UT144;
param[4] = PV32P5_UT144;
- if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param)) {
- if (cs->debug)
- debugl1(cs, "isar pump datamodem cfg dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
break;
case L1_MODE_FAX:
ctrl = PMOD_FAX;
@@ -911,18 +1286,16 @@ setup_pump(struct BCState *bcs) {
param[1] = PFAXP2_ATN;
}
param[0] = 6; /* 6 db */
- if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param)) {
- if (cs->debug)
- debugl1(cs, "isar pump faxmodem cfg dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
+ bcs->hw.isar.state = STFAX_NULL;
+ bcs->hw.isar.newcmd = 0;
+ bcs->hw.isar.newmod = 0;
+ test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag);
break;
}
- if (!sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar pump status req dp%d failed",
- bcs->hw.isar.dpath);
- }
+ udelay(1000);
+ sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ udelay(1000);
}
static void
@@ -933,44 +1306,30 @@ setup_sart(struct BCState *bcs) {
switch (bcs->mode) {
case L1_MODE_NULL:
- if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar sart disable dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0,
+ NULL);
break;
case L1_MODE_TRANS:
- if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, "\0\0")) {
- if (cs->debug)
- debugl1(cs, "isar sart binary dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2,
+ "\0\0");
break;
case L1_MODE_HDLC:
case L1_MODE_FAX:
param[0] = 0;
- if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param)) {
- if (cs->debug)
- debugl1(cs, "isar sart hdlc dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
+ param);
break;
case L1_MODE_V32:
ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
param[0] = S_P1_CHS_8;
param[1] = S_P2_BFT_DEF;
- if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, param)) {
- if (cs->debug)
- debugl1(cs, "isar sart v14 dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
+ param);
break;
}
- if (!sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar buf stat req dp%d failed",
- bcs->hw.isar.dpath);
- }
+ udelay(1000);
+ sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
+ udelay(1000);
}
static void
@@ -995,15 +1354,10 @@ setup_iom2(struct BCState *bcs) {
cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV;
break;
}
- if (!sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg)) {
- if (cs->debug)
- debugl1(cs, "isar iom2 dp%d failed", bcs->hw.isar.dpath);
- }
- if (!sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar IOM2 cfg req dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
+ udelay(1000);
+ sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
+ udelay(1000);
}
int
@@ -1041,8 +1395,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
&bcs->hw.isar.reg->Flags))
bcs->hw.isar.dpath = 1;
else {
- printk(KERN_WARNING"isar modeisar analog works only with DP1\n");
- debugl1(cs, "isar modeisar analog works only with DP1");
+ printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
+ debugl1(cs, "isar modeisar analog funktions only with DP1");
return(1);
}
break;
@@ -1066,6 +1420,107 @@ modeisar(struct BCState *bcs, int mode, int bc)
return(0);
}
+static void
+isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ u_char dps = SET_DPS(bcs->hw.isar.dpath);
+ u_char ctrl = 0, nom = 0, p1 = 0;
+
+ switch(cmd) {
+ case ISDN_FAX_CLASS1_FTM:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTM;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FTM) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FTM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ case ISDN_FAX_CLASS1_FTH:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTH;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FTH) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FTH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ case ISDN_FAX_CLASS1_FRM:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRM;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FRM) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FRM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ case ISDN_FAX_CLASS1_FRH:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRH;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FRH) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FRH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ }
+ if (ctrl)
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
+}
+
void
isar_setup(struct IsdnCardState *cs)
{
@@ -1076,11 +1531,8 @@ isar_setup(struct IsdnCardState *cs)
msg = 61;
for (i=0; i<2; i++) {
/* Buffer Config */
- if (!sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
- ISAR_HIS_P12CFG, 4, 1, &msg)) {
- if (cs->debug)
- debugl1(cs, "isar P%dCFG failed", i+1);
- }
+ sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
+ ISAR_HIS_P12CFG, 4, 1, &msg);
cs->bcs[i].hw.isar.mml = msg;
cs->bcs[i].mode = 0;
cs->bcs[i].hw.isar.dpath = i + 1;
@@ -1147,6 +1599,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg)
l1_msg_b(st, PH_ACTIVATE | REQUEST, arg);
break;
case L1_MODE_V32:
+ case L1_MODE_FAX:
if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc))
l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
break;
@@ -1185,6 +1638,7 @@ close_isarstate(struct BCState *bcs)
debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY");
}
}
+ del_timer(&bcs->hw.isar.ftimer);
}
int
@@ -1206,6 +1660,9 @@ open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
bcs->event = 0;
bcs->hw.isar.rcvidx = 0;
bcs->tx_cnt = 0;
+ bcs->hw.isar.ftimer.function = (void *) ftimer_handler;
+ bcs->hw.isar.ftimer.data = (long) bcs;
+ init_timer(&bcs->hw.isar.ftimer);
return (0);
}
@@ -1226,15 +1683,66 @@ setstack_isar(struct PStack *st, struct BCState *bcs)
int
isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
u_long adr;
- int features;
+ int features, i;
+ struct BCState *bcs;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg);
switch (ic->command) {
+ case (ISDN_CMD_FAXCMD):
+ bcs = cs->channel[ic->arg].bcs;
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d",
+ ic->parm.aux.cmd, ic->parm.aux.subcmd);
+ switch(ic->parm.aux.cmd) {
+ case ISDN_FAX_CLASS1_CTRL:
+ if (ic->parm.aux.subcmd == ETX)
+ test_and_set_bit(BC_FLG_DLEETX,
+ &bcs->Flag);
+ break;
+ case ISDN_FAX_CLASS1_FRM:
+ case ISDN_FAX_CLASS1_FRH:
+ case ISDN_FAX_CLASS1_FTM:
+ case ISDN_FAX_CLASS1_FTH:
+ if (ic->parm.aux.subcmd == AT_QUERY) {
+ sprintf(ic->parm.aux.para,
+ "%d", bcs->hw.isar.mod);
+ ic->command = ISDN_STAT_FAXIND;
+ ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+ cs->iif.statcallb(ic);
+ return(0);
+ } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+ strcpy(ic->parm.aux.para, faxmodulation_s);
+ ic->command = ISDN_STAT_FAXIND;
+ ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+ cs->iif.statcallb(ic);
+ return(0);
+ } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+ for(i=0;i<FAXMODCNT;i++)
+ if (faxmodulation[i]==ic->parm.aux.para[0])
+ break;
+ if ((FAXMODCNT > i) &&
+ test_bit(BC_FLG_INIT, &bcs->Flag)) {
+ isar_pump_cmd(bcs,
+ ic->parm.aux.cmd,
+ ic->parm.aux.para[0]);
+ return(0);
+ }
+ }
+ /* wrong modulation or not activ */
+ /* fall through */
+ default:
+ ic->command = ISDN_STAT_FAXIND;
+ ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
+ cs->iif.statcallb(ic);
+ }
+ break;
case (ISDN_CMD_IOCTL):
switch (ic->arg) {
case (9): /* load firmware */
- features = ISDN_FEATURE_L2_MODEM;
+ features = ISDN_FEATURE_L2_MODEM |
+ ISDN_FEATURE_L2_FAX |
+ ISDN_FEATURE_L3_FCLASS1;
memcpy(&adr, ic->parm.num, sizeof(ulong));
if (isar_load_firmware(cs, (u_char *)adr))
return(1);
diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h
index f2bc4820a..ec3bff89e 100644
--- a/drivers/isdn/hisax/isar.h
+++ b/drivers/isdn/hisax/isar.h
@@ -1,10 +1,13 @@
-/* $Id: isar.h,v 1.6 1999/10/14 20:25:29 keil Exp $
+/* $Id: isar.h,v 1.7 2000/01/20 19:47:45 keil Exp $
* isar.h ISAR (Siemens PSB 7110) specific defines
*
* Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: isar.h,v $
+ * Revision 1.7 2000/01/20 19:47:45 keil
+ * Add Fax Class 1 support
+ *
* Revision 1.6 1999/10/14 20:25:29 keil
* add a statistic for error monitoring
*
@@ -145,6 +148,28 @@
#define PSEV_REM_REN 0xcd
#define PSEV_GSTN_CLR 0xd4
+#define PSEV_RSP_READY 0xbc
+#define PSEV_LINE_TX_H 0xb3
+#define PSEV_LINE_TX_B 0xb2
+#define PSEV_LINE_RX_H 0xb1
+#define PSEV_LINE_RX_B 0xb0
+#define PSEV_RSP_CONN 0xb5
+#define PSEV_RSP_DISC 0xb7
+#define PSEV_RSP_FCERR 0xb9
+#define PSEV_RSP_SILDET 0xbe
+#define PSEV_RSP_SILOFF 0xab
+#define PSEV_FLAGS_DET 0xba
+
+#define PCTRL_CMD_FTH 0xa7
+#define PCTRL_CMD_FRH 0xa5
+#define PCTRL_CMD_FTM 0xa8
+#define PCTRL_CMD_FRM 0xa6
+#define PCTRL_CMD_SILON 0xac
+#define PCTRL_CMD_CONT 0xa2
+#define PCTRL_CMD_ESC 0xa4
+#define PCTRL_CMD_SILOFF 0xab
+#define PCTRL_CMD_HALT 0xa9
+
#define PCTRL_LOC_RET 0xcf
#define PCTRL_LOC_REN 0xce
@@ -193,6 +218,15 @@
#define BSTEV_TBO 0x1f
#define BSTEV_RBO 0x2f
+/* FAX State Machine */
+#define STFAX_NULL 0
+#define STFAX_READY 1
+#define STFAX_LINE 2
+#define STFAX_CONT 3
+#define STFAX_ACTIV 4
+#define STFAX_ESCAPE 5
+#define STFAX_SILDET 6
+
extern int ISARVersion(struct IsdnCardState *cs, char *s);
extern void isar_int_main(struct IsdnCardState *cs);
extern void initisar(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 768217025..7715991cb 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.36 1999/08/25 16:50:57 keil Exp $
+/* $Id: isdnl1.c,v 2.37 2000/01/20 19:51:46 keil Exp $
* isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards
* based on the teles driver from Jan den Ouden
@@ -15,6 +15,10 @@
*
*
* $Log: isdnl1.c,v $
+ * Revision 2.37 2000/01/20 19:51:46 keil
+ * Fix AddTimer message
+ * Change CONFIG defines
+ *
* Revision 2.36 1999/08/25 16:50:57 keil
* Fix bugs which cause 2.3.14 hangs (waitqueue init)
*
@@ -138,7 +142,7 @@
*
*/
-const char *l1_revision = "$Revision: 2.36 $";
+const char *l1_revision = "$Revision: 2.37 $";
#define __NO_VERSION__
#include "hisax.h"
@@ -362,7 +366,8 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
stptr = stptr->next;
if (!found)
dev_kfree_skb(skb);
- }
+ } else
+ dev_kfree_skb(skb);
}
}
@@ -559,11 +564,8 @@ l1_deact_req(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_F3);
-// if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) {
- FsmDelTimer(&st->l1.timer, 1);
- FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
- test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
-// }
+ FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
+ test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
}
static void
@@ -574,8 +576,7 @@ l1_power_up(struct FsmInst *fi, int event, void *arg)
if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
FsmChangeState(fi, ST_L1_F4);
st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
- FsmDelTimer(&st->l1.timer, 1);
- FsmAddTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
} else
FsmChangeState(fi, ST_L1_F3);
@@ -614,7 +615,7 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg)
if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
FsmDelTimer(&st->l1.timer, 3);
- FsmAddTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
}
}
@@ -729,7 +730,7 @@ l1b_activate(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_ACT);
- FsmAddTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
}
static void
@@ -738,7 +739,7 @@ l1b_deactivate(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_DEACT);
- FsmAddTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
}
static void
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
index 4ee5831fe..18a7cfc58 100644
--- a/drivers/isdn/hisax/isurf.c
+++ b/drivers/isdn/hisax/isurf.c
@@ -1,10 +1,14 @@
-/* $Id: isurf.c,v 1.7 1999/11/14 23:37:03 keil Exp $
+/* $Id: isurf.c,v 1.8 1999/12/19 13:09:42 keil Exp $
* isurf.c low level stuff for Siemens I-Surf/I-Talk cards
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* $Log: isurf.c,v $
+ * Revision 1.8 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.7 1999/11/14 23:37:03 keil
* new ISA memory mapped IO
*
@@ -40,7 +44,7 @@
extern const char *CardType[];
-static const char *ISurf_revision = "$Revision: 1.7 $";
+static const char *ISurf_revision = "$Revision: 1.8 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -162,10 +166,10 @@ reset_isurf(struct IsdnCardState *cs, u_char chips)
byteout(cs->hw.isurf.reset, chips); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index 31b25acdf..e6297bd94 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 2.9 1999/07/01 08:11:55 keil Exp $
+/* $Id: l3_1tr6.c,v 2.10 2000/01/20 19:42:01 keil Exp $
* German 1TR6 D-channel protocol
*
@@ -10,6 +10,9 @@
*
*
* $Log: l3_1tr6.c,v $
+ * Revision 2.10 2000/01/20 19:42:01 keil
+ * Fixed uninitialiesed location
+ *
* Revision 2.9 1999/07/01 08:11:55 keil
* Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
*
@@ -59,7 +62,7 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.9 $";
+const char *l3_1tr6_revision = "$Revision: 2.10 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
@@ -699,6 +702,7 @@ l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
{
newl3state(pc, 0);
pc->para.cause = 0x1b; /* Destination out of order */
+ pc->para.loc = 0;
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 035ee54ca..9fa10e326 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.20 1999/10/11 22:16:27 keil Exp $
+/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $
* EURO/DSS1 D-channel protocol
*
@@ -13,6 +13,16 @@
* Fritz Elfert
*
* $Log: l3dss1.c,v $
+ * Revision 2.22 2000/01/20 19:44:20 keil
+ * Fixed uninitialiesed location
+ * Fixed redirecting number IE in Setup
+ * Changes from certification
+ * option for disabling use of KEYPAD protocol
+ *
+ * Revision 2.21 1999/12/19 20:25:17 keil
+ * fixed LLC for outgoing analog calls
+ * IE Signal is valid on older local switches
+ *
* Revision 2.20 1999/10/11 22:16:27 keil
* Suspend/Resume is possible without explicit ID too
*
@@ -91,9 +101,10 @@
#include "isdnl3.h"
#include "l3dss1.h"
#include <linux/ctype.h>
+#include <linux/config.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.20 $";
+const char *dss1_revision = "$Revision: 2.22 $";
#define EXT_BEARER_CAPS 1
@@ -668,34 +679,36 @@ l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
}
static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
+ IE_USER_USER, -1};
static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_CONNECT_PN,
- IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
-static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, -1};
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
+ IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_USER_USER, -1};
-static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD,
+ IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
IE_CALLED_PN, -1};
static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
-static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, IE_USER_USER, -1};
+static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
+ IE_SIGNAL, IE_USER_USER, -1};
/* a RELEASE_COMPLETE with errors don't require special actions
-static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_USER_USER, -1};
+static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
*/
static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
IE_DISPLAY, -1};
static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
- IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_CALLING_PN,
- IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_LLC, IE_HLC,
- IE_USER_USER, -1};
+ IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
+ IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
+ IE_LLC, IE_HLC, IE_USER_USER, -1};
static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, -1};
+ IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
IE_MANDATORY, IE_DISPLAY, -1};
static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
@@ -1272,6 +1285,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
u_char tmp[128];
u_char *p = tmp;
u_char channel = 0;
+
u_char send_keypad;
u_char screen = 0x80;
u_char *teln;
@@ -1283,14 +1297,18 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
MsgHead(p, pc->callref, MT_SETUP);
teln = pc->para.setup.phone;
+#ifndef CONFIG_HISAX_NO_KEYPAD
send_keypad = (strchr(teln,'*') || strchr(teln,'#')) ? 1 : 0;
+#else
+ send_keypad = 0;
+#endif
+#ifndef CONFIG_HISAX_NO_SENDCOMPLETE
+ if (!send_keypad)
+ *p++ = 0xa1; /* complete indicator */
+#endif
/*
* Set Bearer Capability, Map info from 1TR6-convention to EDSS1
*/
-#if HISAX_EURO_SENDCOMPLETE
- if (!send_keypad)
- *p++ = 0xa1; /* complete indicator */
-#endif
if (!send_keypad)
switch (pc->para.setup.si1) {
case 1: /* Telephony */
@@ -1452,12 +1470,25 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
*p++ = 0x90;
*p++ = 0x21;
p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
-#if HISAX_SEND_STD_LLC_IE
+#ifndef CONFIG_HISAX_NO_LLC
} else {
- *p++ = 0x7c;
- *p++ = 0x02;
- *p++ = 0x88;
- *p++ = 0x90;
+ switch (pc->para.setup.si1) {
+ case 1: /* Telephony */
+ *p++ = 0x7c; /* BC-IE-code */
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
+ break;
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
+ default:
+ *p++ = 0x7c; /* BC-IE-code */
+ *p++ = 0x2; /* Length */
+ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ break;
+ }
#endif
}
#endif
@@ -2738,6 +2769,7 @@ static void
l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
{
pc->para.cause = 0x29; /* Temporary failure */
+ pc->para.loc = 0;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
}
@@ -2747,6 +2779,7 @@ l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg)
{
newl3state(pc, 0);
pc->para.cause = 0x1b; /* Destination out of order */
+ pc->para.loc = 0;
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h
index 268b5376f..2acb95c01 100644
--- a/drivers/isdn/hisax/l3dss1.h
+++ b/drivers/isdn/hisax/l3dss1.h
@@ -1,8 +1,11 @@
-/* $Id: l3dss1.h,v 1.7 1999/07/01 08:12:02 keil Exp $
+/* $Id: l3dss1.h,v 1.8 2000/01/20 19:46:15 keil Exp $
*
* DSS1 (Euro) D-channel protocol defines
*
* $Log: l3dss1.h,v $
+ * Revision 1.8 2000/01/20 19:46:15 keil
+ * Changes from certification
+ *
* Revision 1.7 1999/07/01 08:12:02 keil
* Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
*
@@ -35,6 +38,8 @@
#define T304 30000
#define T305 30000
#define T308 4000
+/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
+/* This makes some tests easier and quicker */
#define T309 40000
#define T310 30000
#define T313 4000
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 3b502f7db..3855625bd 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.16 1999/10/14 20:25:29 keil Exp $
+/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $
* netjet.c low level stuff for Traverse Technologie NETJet ISDN cards
*
@@ -7,6 +7,10 @@
* Thanks to Traverse Technologie Australia for documents and informations
*
* $Log: netjet.c,v $
+ * Revision 1.17 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.16 1999/10/14 20:25:29 keil
* add a statistic for error monitoring
*
@@ -81,7 +85,7 @@
extern const char *CardType[];
-const char *NETjet_revision = "$Revision: 1.16 $";
+const char *NETjet_revision = "$Revision: 1.17 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -1054,11 +1058,11 @@ reset_netjet(struct IsdnCardState *cs)
sti();
cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
restore_flags(flags);
cs->hw.njet.auxd = 0;
diff --git a/drivers/isdn/hisax/rawhdlc.c b/drivers/isdn/hisax/rawhdlc.c
index 17ac5c602..5a8b0591e 100644
--- a/drivers/isdn/hisax/rawhdlc.c
+++ b/drivers/isdn/hisax/rawhdlc.c
@@ -1,8 +1,8 @@
-/* $Id: rawhdlc.c,v 1.3 1998/06/17 19:51:21 he Exp $
+/* $Id: rawhdlc.c,v 1.4 1999/12/23 15:09:32 keil Exp $
* rawhdlc.c support routines for cards that don't support HDLC
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
* Brent Baccala <baccala@FreeSoft.org>
*
*
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
index 955a9a4de..b642d759c 100644
--- a/drivers/isdn/hisax/saphir.c
+++ b/drivers/isdn/hisax/saphir.c
@@ -1,4 +1,4 @@
-/* $Id: saphir.c,v 1.4 1999/09/04 06:20:06 keil Exp $
+/* $Id: saphir.c,v 1.5 1999/12/19 13:09:42 keil Exp $
* saphir.c low level stuff for HST Saphir 1
*
@@ -8,6 +8,10 @@
*
*
* $Log: saphir.c,v $
+ * Revision 1.5 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.4 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -29,7 +33,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-static char *saphir_rev = "$Revision: 1.4 $";
+static char *saphir_rev = "$Revision: 1.5 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -237,10 +241,10 @@ saphir_reset(struct IsdnCardState *cs)
save_flags(flags);
sti();
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
restore_flags(flags);
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index b93895ea1..dd1c53d04 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.18 1999/11/13 21:25:03 keil Exp $
+/* $Id: sedlbauer.c,v 1.20 2000/01/20 19:47:45 keil Exp $
* sedlbauer.c low level stuff for Sedlbauer cards
* includes support for the Sedlbauer speed star (speed star II),
@@ -17,6 +17,13 @@
* Edgar Toernig
*
* $Log: sedlbauer.c,v $
+ * Revision 1.20 2000/01/20 19:47:45 keil
+ * Add Fax Class 1 support
+ *
+ * Revision 1.19 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.18 1999/11/13 21:25:03 keil
* Support for Speedfax+ PCI
*
@@ -110,7 +117,7 @@
extern const char *CardType[];
-const char *Sedlbauer_revision = "$Revision: 1.18 $";
+const char *Sedlbauer_revision = "$Revision: 1.20 $";
const char *Sedlbauer_Types[] =
{"None", "speed card/win", "speed star", "speed fax+",
@@ -490,10 +497,10 @@ reset_sedlbauer(struct IsdnCardState *cs)
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
@@ -506,20 +513,20 @@ reset_sedlbauer(struct IsdnCardState *cs)
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
save_flags(flags);
sti();
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((20*HZ)/1000);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((20*HZ)/1000);
restore_flags(flags);
} else {
byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
@@ -659,15 +666,13 @@ setup_sedlbauer(struct IsdnCard *card))
(sub_id == PCI_SUB_ID_SPEEDFAXP)) {
cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
cs->subtyp = SEDL_SPEEDFAX_PCI;
- cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_PCI_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_PCI_ISAR_RESET_OFF;
} else {
cs->hw.sedl.chip = SEDL_CHIP_IPAC;
cs->subtyp = SEDL_SPEED_PCI;
}
bytecnt = 256;
+ cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+ cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
byteout(cs->hw.sedl.cfg_reg, 0xff);
byteout(cs->hw.sedl.cfg_reg, 0x00);
byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
@@ -675,7 +680,7 @@ setup_sedlbauer(struct IsdnCard *card))
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
save_flags(flags);
sti();
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
restore_flags(flags);
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index 91a6a6ae1..03ecedb93 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -1,12 +1,19 @@
-/* $Id: sportster.c,v 1.10 1999/09/04 06:20:06 keil Exp $
+/* $Id: sportster.c,v 1.12 1999/12/23 15:09:32 keil Exp $
* sportster.c low level stuff for USR Sportster internal TA
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
*
* $Log: sportster.c,v $
+ * Revision 1.12 1999/12/23 15:09:32 keil
+ * change email
+ *
+ * Revision 1.11 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.10 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -46,7 +53,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.10 $";
+const char *sportster_revision = "$Revision: 1.12 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -180,11 +187,11 @@ reset_sportster(struct IsdnCardState *cs)
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index c34dc5613..bbf59316d 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -1,4 +1,4 @@
-/* $Id: teleint.c,v 1.11 1999/09/04 06:20:06 keil Exp $
+/* $Id: teleint.c,v 1.12 1999/12/19 13:09:42 keil Exp $
* teleint.c low level stuff for TeleInt isdn cards
*
@@ -6,6 +6,10 @@
*
*
* $Log: teleint.c,v $
+ * Revision 1.12 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.11 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -51,7 +55,7 @@
extern const char *CardType[];
-const char *TeleInt_revision = "$Revision: 1.11 $";
+const char *TeleInt_revision = "$Revision: 1.12 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -260,11 +264,11 @@ reset_TeleInt(struct IsdnCardState *cs)
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000);
cs->hw.hfc.cirm &= ~HFC_RESET;
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index 8e8017bbb..c3a4a05eb 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -1,15 +1,18 @@
-/* $Id: teles0.c,v 2.10 1999/11/14 23:37:03 keil Exp $
+/* $Id: teles0.c,v 2.11 1999/12/23 15:09:32 keil Exp $
* teles0.c low level stuff for Teles Memory IO isdn cards
* based on the teles driver from Jan den Ouden
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
* $Log: teles0.c,v $
+ * Revision 2.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 2.10 1999/11/14 23:37:03 keil
* new ISA memory mapped IO
*
@@ -61,7 +64,7 @@
extern const char *CardType[];
-const char *teles0_revision = "$Revision: 2.10 $";
+const char *teles0_revision = "$Revision: 2.11 $";
#define TELES_IOMEM_SIZE 0x400
#define byteout(addr,val) outb(val,addr)
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index 0db245abc..171aeb07d 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -1,16 +1,22 @@
-/* $Id: teles3.c,v 2.13 1999/08/30 12:01:28 keil Exp $
+/* $Id: teles3.c,v 2.15 2000/02/03 16:40:10 keil Exp $
* teles3.c low level stuff for Teles 16.3 & PNP isdn cards
*
* based on the teles driver from Jan den Ouden
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
* $Log: teles3.c,v $
+ * Revision 2.15 2000/02/03 16:40:10 keil
+ * Fix teles pcmcia
+ *
+ * Revision 2.14 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 2.13 1999/08/30 12:01:28 keil
* HW version v1.3 support
*
@@ -88,7 +94,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.13 $";
+const char *teles3_revision = "$Revision: 2.15 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -225,7 +231,7 @@ void
release_io_teles3(struct IsdnCardState *cs)
{
if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
- release_region(cs->hw.teles3.hscx[0], 97);
+ release_region(cs->hw.teles3.hscx[1], 96);
} else {
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
@@ -367,15 +373,15 @@ setup_teles3(struct IsdnCard *card))
cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
- if (check_region((cs->hw.teles3.hscx[0]), 97)) {
+ if (check_region((cs->hw.teles3.hscx[1]), 96 )) {
printk(KERN_WARNING
"HiSax: %s ports %x-%x already in use\n",
CardType[cs->typ],
- cs->hw.teles3.hscx[0],
- cs->hw.teles3.hscx[0] + 96);
+ cs->hw.teles3.hscx[1],
+ cs->hw.teles3.hscx[1] + 96);
return (0);
} else
- request_region(cs->hw.teles3.hscx[0], 97, "HiSax Teles PCMCIA");
+ request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA");
} else {
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index 3486b470a..e90510b35 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -1,12 +1,15 @@
-/* $Id: telespci.c,v 2.10 1999/11/15 14:20:05 keil Exp $
+/* $Id: telespci.c,v 2.11 1999/12/23 15:09:32 keil Exp $
* telespci.c low level stuff for Teles PCI isdn cards
*
* Author Ton van Rosmalen
- * Karsten Keil (keil@temic-ech.spacenet.de)
+ * Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: telespci.c,v $
+ * Revision 2.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 2.10 1999/11/15 14:20:05 keil
* 64Bit compatibility
*
@@ -47,7 +50,7 @@
#include <linux/pci.h>
extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.10 $";
+const char *telespci_revision = "$Revision: 2.11 $";
#define ZORAN_PO_RQ_PEN 0x02000000
#define ZORAN_PO_WR 0x00800000
diff --git a/drivers/isdn/hysdn/.cvsignore b/drivers/isdn/hysdn/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/isdn/hysdn/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile
new file mode 100644
index 000000000..626a6deaa
--- /dev/null
+++ b/drivers/isdn/hysdn/Makefile
@@ -0,0 +1,24 @@
+SUB_DIRS :=
+MOD_SUB_DIRS :=
+ALL_SUB_DIRS :=
+
+L_OBJS :=
+LX_OBJS :=
+M_OBJS :=
+MX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+L_TARGET :=
+O_TARGET :=
+
+ifeq ($(CONFIG_PROC_FS),y)
+ ifeq ($(CONFIG_HYSDN),y)
+ M_OBJS += hysdn.o
+ O_TARGET += hysdn.o
+ O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o
+ OX_OBJS += hysdn_init.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
new file mode 100644
index 000000000..578e4a14d
--- /dev/null
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -0,0 +1,467 @@
+/* $Id: boardergo.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, specific routines for ergo type boards.
+ *
+ * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same
+ * DPRAM interface and layout with only minor differences all related
+ * stuff is done here, not in separate modules.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: boardergo.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "hysdn_defs.h"
+#include "boardergo.h"
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/***************************************************/
+/* The cards interrupt handler. Called from system */
+/***************************************************/
+static void
+ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ hysdn_card *card = dev_id; /* parameter from irq */
+ tErgDpram *dpr;
+ ulong flags;
+ uchar volatile b;
+
+ if (!card)
+ return; /* error -> spurious interrupt */
+ if (!card->irq_enabled)
+ return; /* other device interrupting or irq switched off */
+
+ save_flags(flags);
+ cli(); /* no further irqs allowed */
+
+ if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
+ restore_flags(flags); /* restore old state */
+ return; /* no interrupt requested by E1 */
+ }
+ /* clear any pending ints on the board */
+ dpr = card->dpram;
+ b = dpr->ToPcInt; /* clear for ergo */
+ b |= dpr->ToPcIntMetro; /* same for metro */
+ b |= dpr->ToHyInt; /* and for champ */
+
+ /* start kernel task immediately after leaving all interrupts */
+ if (!card->hw_lock) {
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ restore_flags(flags);
+} /* ergo_interrupt */
+
+/******************************************************************************/
+/* ergo_irq_bh is the function called by the immediate kernel task list after */
+/* being activated with queue_task and no interrupts active. This task is the */
+/* only one handling data transfer from or to the card after booting. The task */
+/* may be queued from everywhere (interrupts included). */
+/******************************************************************************/
+static void
+ergo_irq_bh(hysdn_card * card)
+{
+ tErgDpram *dpr;
+ int again;
+ ulong flags;
+
+ if (card->state != CARD_STATE_RUN)
+ return; /* invalid call */
+
+ dpr = card->dpram; /* point to DPRAM */
+
+ save_flags(flags);
+ cli();
+ if (card->hw_lock) {
+ restore_flags(flags); /* hardware currently unavailable */
+ return;
+ }
+ card->hw_lock = 1; /* we now lock the hardware */
+
+ do {
+ sti(); /* reenable other ints */
+ again = 0; /* assume loop not to be repeated */
+
+ if (!dpr->ToHyFlag) {
+ /* we are able to send a buffer */
+
+ if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel,
+ ERG_TO_HY_BUF_SIZE)) {
+ dpr->ToHyFlag = 1; /* enable tx */
+ again = 1; /* restart loop */
+ }
+ } /* we are able to send a buffer */
+ if (dpr->ToPcFlag) {
+ /* a message has arrived for us, handle it */
+
+ if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) {
+ dpr->ToPcFlag = 0; /* we worked the data */
+ again = 1; /* restart loop */
+ }
+ } /* a message has arrived for us */
+ cli(); /* no further ints */
+ if (again) {
+ dpr->ToHyInt = 1;
+ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
+ } else
+ card->hw_lock = 0; /* free hardware again */
+ } while (again); /* until nothing more to do */
+
+ restore_flags(flags);
+} /* ergo_irq_bh */
+
+
+/*********************************************************/
+/* stop the card (hardware reset) and disable interrupts */
+/*********************************************************/
+static void
+ergo_stopcard(hysdn_card * card)
+{
+ ulong flags;
+ uchar val;
+
+ hysdn_net_release(card); /* first release the net device if existing */
+ save_flags(flags);
+ cli();
+ val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
+ val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
+ byteout(card->iobase + PCI9050_INTR_REG, val);
+ card->irq_enabled = 0;
+ byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */
+ card->state = CARD_STATE_UNUSED;
+ card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
+
+ restore_flags(flags);
+} /* ergo_stopcard */
+
+/**************************************************************************/
+/* enable or disable the cards error log. The event is queued if possible */
+/**************************************************************************/
+static void
+ergo_set_errlog_state(hysdn_card * card, int on)
+{
+ ulong flags;
+
+ if (card->state != CARD_STATE_RUN) {
+ card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
+ return;
+ }
+ save_flags(flags);
+ cli();
+
+ if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
+ ((card->err_log_state == ERRLOG_STATE_ON) && on)) {
+ restore_flags(flags);
+ return; /* nothing to do */
+ }
+ if (on)
+ card->err_log_state = ERRLOG_STATE_START; /* request start */
+ else
+ card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
+
+ restore_flags(flags);
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+} /* ergo_set_errlog_state */
+
+/******************************************/
+/* test the cards RAM and return 0 if ok. */
+/******************************************/
+static const char TestText[36] = "This Message is filler, why read it";
+
+static int
+ergo_testram(hysdn_card * card)
+{
+ tErgDpram *dpr = card->dpram;
+
+ memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */
+ dpr->ToHyInt = 1; /* E1 INTR state forced */
+
+ memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText));
+ if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText)))
+ return (-1);
+
+ memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText));
+ if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText)))
+ return (-1);
+
+ return (0);
+} /* ergo_testram */
+
+/*****************************************************************************/
+/* this function is intended to write stage 1 boot image to the cards buffer */
+/* this is done in two steps. First the 1024 hi-words are written (offs=0), */
+/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */
+/* PCI-write-buffers flushed and the card is taken out of reset. */
+/* The function then waits for a reaction of the E1 processor or a timeout. */
+/* Negative return values are interpreted as errors. */
+/*****************************************************************************/
+static int
+ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
+{
+ uchar *dst;
+ tErgDpram *dpram;
+ int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs);
+
+ dst = card->dpram; /* pointer to start of DPRAM */
+ dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */
+ while (cnt--) {
+ *dst++ = *(buf + 1); /* high byte */
+ *dst++ = *buf; /* low byte */
+ dst += 2; /* point to next longword */
+ buf += 2; /* buffer only filled with words */
+ }
+
+ /* if low words (offs = 2) have been written, clear the rest of the DPRAM, */
+ /* flush the PCI-write-buffer and take the E1 out of reset */
+ if (offs) {
+ memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */
+ dpram = card->dpram; /* get pointer to dpram structure */
+ dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */
+ while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */
+
+ byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */
+ /* the interrupts are still masked */
+
+ sti();
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+
+ if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write bootldr no answer");
+ return (-ERR_BOOTIMG_FAIL);
+ }
+ } /* start_boot_img */
+ return (0); /* successfull */
+} /* ergo_writebootimg */
+
+/********************************************************************************/
+/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */
+/* using the boot spool mechanism. If everything works fine 0 is returned. In */
+/* case of errors a negative error value is returned. */
+/********************************************************************************/
+static int
+ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
+{
+ tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram;
+ uchar *dst;
+ uchar buflen;
+ int nr_write;
+ uchar tmp_rdptr;
+ uchar wr_mirror;
+ int i;
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write boot seq len=%d ", len);
+
+ dst = sp->Data; /* point to data in spool structure */
+ buflen = sp->Len; /* maximum len of spooled data */
+ wr_mirror = sp->WrPtr; /* only once read */
+ sti();
+
+ /* try until all bytes written or error */
+ i = 0x1000; /* timeout value */
+ while (len) {
+
+ /* first determine the number of bytes that may be buffered */
+ do {
+ tmp_rdptr = sp->RdPtr; /* first read the pointer */
+ i--; /* decrement timeout */
+ } while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */
+
+ if (!i) {
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write boot seq timeout");
+ return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */
+ }
+ if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0)
+ nr_write += buflen; /* now we got number of free bytes - 1 in buffer */
+
+ if (!nr_write)
+ continue; /* no free bytes in buffer */
+
+ if (nr_write > len)
+ nr_write = len; /* limit if last few bytes */
+ i = 0x1000; /* reset timeout value */
+
+ /* now we know how much bytes we may put in the puffer */
+ len -= nr_write; /* we savely could adjust len before output */
+ while (nr_write--) {
+ *(dst + wr_mirror) = *buf++; /* output one byte */
+ if (++wr_mirror >= buflen)
+ wr_mirror = 0;
+ sp->WrPtr = wr_mirror; /* announce the next byte to E1 */
+ } /* while (nr_write) */
+
+ } /* while (len) */
+
+ return (0);
+} /* ergo_writebootseq */
+
+/***********************************************************************************/
+/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */
+/* boot process. If the process has been successfull 0 is returned otherwise a */
+/* negative error code is returned. */
+/***********************************************************************************/
+static int
+ergo_waitpofready(struct HYSDN_CARD *card)
+{
+ tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */
+ int timecnt = 10000 / 50; /* timeout is 10 secs max. */
+ ulong flags;
+ int msg_size;
+ int i;
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: waiting for pof ready");
+
+ while (timecnt--) {
+ /* wait until timeout */
+
+ if (dpr->ToPcFlag) {
+ /* data has arrived */
+
+ if ((dpr->ToPcChannel != CHAN_SYSTEM) ||
+ (dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
+ (dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
+ ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
+ break; /* an error occured */
+
+ /* Check for additional data delivered during SysReady */
+ msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE;
+ if (msg_size > 0)
+ if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size))
+ break;
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "ERGO: pof boot success");
+
+ save_flags(flags);
+ cli();
+
+ card->state = CARD_STATE_RUN; /* now card is running */
+ /* enable the cards interrupt */
+ byteout(card->iobase + PCI9050_INTR_REG,
+ bytein(card->iobase + PCI9050_INTR_REG) |
+ (PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1));
+ card->irq_enabled = 1; /* we are ready to receive interrupts */
+
+ dpr->ToPcFlag = 0; /* reset data indicator */
+ dpr->ToHyInt = 1;
+ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
+
+ restore_flags(flags);
+ if ((i = hysdn_net_create(card))) {
+ ergo_stopcard(card);
+ card->state = CARD_STATE_BOOTERR;
+ return (i);
+ }
+ return (0); /* success */
+ } /* data has arrived */
+ sti();
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((50 * HZ) / 1000); /* Timeout 50ms */
+ } /* wait until timeout */
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: pof boot ready timeout");
+ return (-ERR_POF_TIMEOUT);
+} /* ergo_waitpofready */
+
+
+
+/************************************************************************************/
+/* release the cards hardware. Before releasing do a interrupt disable and hardware */
+/* reset. Also unmap dpram. */
+/* Use only during module release. */
+/************************************************************************************/
+static void
+ergo_releasehardware(hysdn_card * card)
+{
+ ergo_stopcard(card); /* first stop the card if not already done */
+ free_irq(card->irq, card); /* release interrupt */
+ release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */
+ release_region(card->iobase + PCI9050_USER_IO, 1);
+ vfree(card->dpram);
+ card->dpram = NULL; /* release shared mem */
+} /* ergo_releasehardware */
+
+
+/*********************************************************************************/
+/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */
+/* value is returned. */
+/* Use only during module init. */
+/*********************************************************************************/
+int
+ergo_inithardware(hysdn_card * card)
+{
+ if (check_region(card->iobase + PCI9050_INTR_REG, 1) ||
+ check_region(card->iobase + PCI9050_USER_IO, 1))
+ return (-1); /* ports already in use */
+
+ card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1;
+ if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE)))
+ return (-1);
+
+ request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN");
+ request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN");
+ ergo_stopcard(card); /* disable interrupts */
+ if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) {
+ ergo_releasehardware(card); /* return the aquired hardware */
+ return (-1);
+ }
+ /* success, now setup the function pointers */
+ card->stopcard = ergo_stopcard;
+ card->releasehardware = ergo_releasehardware;
+ card->testram = ergo_testram;
+ card->writebootimg = ergo_writebootimg;
+ card->writebootseq = ergo_writebootseq;
+ card->waitpofready = ergo_waitpofready;
+ card->set_errlog_state = ergo_set_errlog_state;
+ card->irq_queue.next = 0;
+ card->irq_queue.sync = 0;
+ card->irq_queue.data = card; /* init task queue for interrupt */
+ card->irq_queue.routine = (void *) (void *) ergo_irq_bh;
+
+ return (0);
+} /* ergo_inithardware */
diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/isdn/hysdn/boardergo.h
new file mode 100644
index 000000000..0e2c3f678
--- /dev/null
+++ b/drivers/isdn/hysdn/boardergo.h
@@ -0,0 +1,117 @@
+/* $Id: boardergo.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+
+ * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: boardergo.h,v $
+ * Revision 1.1 2000/02/10 19:44:30 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+
+/************************************************/
+/* defines for the dual port memory of the card */
+/************************************************/
+#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */
+#define BOOT_IMG_SIZE 4096
+#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE)
+
+#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */
+#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */
+
+/* following DPRAM layout copied from OS2-driver boarderg.h */
+typedef struct ErgDpram_tag {
+/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE];
+/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE];
+
+ /*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART];
+ /* size 0x1B0 */
+
+ /*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64];
+ /* size 64 bytes */
+ /*1DB0 ulong ulErrType; */
+ /*1DB4 ulong ulErrSubtype; */
+ /*1DB8 ulong ucTextSize; */
+ /*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
+ /*1DF0 */
+
+/*1DF0 */ word volatile ToHyChannel;
+/*1DF2 */ word volatile ToHySize;
+ /*1DF4 */ uchar volatile ToHyFlag;
+ /* !=0: msg for Hy waiting */
+ /*1DF5 */ uchar volatile ToPcFlag;
+ /* !=0: msg for PC waiting */
+/*1DF6 */ word volatile ToPcChannel;
+/*1DF8 */ word volatile ToPcSize;
+ /*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA];
+ /* 6 bytes */
+
+/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00];
+/*1F00 */ ulong TrapTable[62];
+ /*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8];
+ /* low part of reset vetor */
+/*1FFB */ uchar ToPcIntMetro;
+ /* notes:
+ * - metro has 32-bit boot ram - accessing
+ * ToPcInt and ToHyInt would be the same;
+ * so we moved ToPcInt to 1FFB.
+ * Because on the PC side both vars are
+ * readonly (reseting on int from E1 to PC),
+ * we can read both vars on both cards
+ * without destroying anything.
+ * - 1FFB is the high byte of the reset vector,
+ * so E1 side should NOT change this byte
+ * when writing!
+ */
+/*1FFC */ uchar volatile ToHyNoDpramErrLog;
+ /* note: ToHyNoDpramErrLog is used to inform
+ * boot loader, not to use DPRAM based
+ * ErrLog; when DOS driver is rewritten
+ * this becomes obsolete
+ */
+/*1FFD */ uchar bRes1FFD;
+ /*1FFE */ uchar ToPcInt;
+ /* E1_intclear; on CHAMP2: E1_intset */
+ /*1FFF */ uchar ToHyInt;
+ /* E1_intset; on CHAMP2: E1_intclear */
+} tErgDpram;
+
+/**********************************************/
+/* PCI9050 controller local register offsets: */
+/* copied from boarderg.c */
+/**********************************************/
+#define PCI9050_INTR_REG 0x4C /* Interrupt register */
+#define PCI9050_USER_IO 0x51 /* User I/O register */
+
+ /* bitmask for PCI9050_INTR_REG: */
+#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */
+#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */
+#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */
+#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */
+
+ /* bitmask for PCI9050_USER_IO: */
+#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */
+#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */
+#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */
+
+#define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */
+#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c
new file mode 100644
index 000000000..030c40de6
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_boot.c
@@ -0,0 +1,420 @@
+/* $Id: hysdn_boot.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, specific routines for booting and pof handling.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_boot.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/malloc.h>
+#include <asm/uaccess.h>
+
+#include "hysdn_defs.h"
+#include "hysdn_pof.h"
+
+/********************************/
+/* defines for pof read handler */
+/********************************/
+#define POF_READ_FILE_HEAD 0
+#define POF_READ_TAG_HEAD 1
+#define POF_READ_TAG_DATA 2
+
+/************************************************************/
+/* definition of boot specific data area. This data is only */
+/* needed during boot and so allocated dynamically. */
+/************************************************************/
+struct boot_data {
+ word Cryptor; /* for use with Decrypt function */
+ word Nrecs; /* records remaining in file */
+ uchar pof_state; /* actual state of read handler */
+ uchar is_crypted; /* card data is crypted */
+ int BufSize; /* actual number of bytes bufferd */
+ int last_error; /* last occured error */
+ word pof_recid; /* actual pof recid */
+ ulong pof_reclen; /* total length of pof record data */
+ ulong pof_recoffset; /* actual offset inside pof record */
+ union {
+ uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */
+ tPofRecHdr PofRecHdr; /* header for actual record/chunk */
+ tPofFileHdr PofFileHdr; /* header from POF file */
+ tPofTimeStamp PofTime; /* time information */
+ } buf;
+};
+
+/*****************************************************/
+/* start decryption of sucessive POF file chuncks. */
+/* */
+/* to be called at start of POF file reading, */
+/* before starting any decryption on any POF record. */
+/*****************************************************/
+void
+StartDecryption(struct boot_data *boot)
+{
+ boot->Cryptor = CRYPT_STARTTERM;
+} /* StartDecryption */
+
+
+/***************************************************************/
+/* decrypt complete BootBuf */
+/* NOTE: decryption must be applied to all or none boot tags - */
+/* to HI and LO boot loader and (all) seq tags, because */
+/* global Cryptor is started for whole POF. */
+/***************************************************************/
+void
+DecryptBuf(struct boot_data *boot, int cnt)
+{
+ uchar *bufp = boot->buf.BootBuf;
+
+ while (cnt--) {
+ boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
+ *bufp++ ^= (uchar) boot->Cryptor;
+ }
+} /* DecryptBuf */
+
+/********************************************************************************/
+/* pof_handle_data executes the required actions dependant on the active record */
+/* id. If successfull 0 is returned, a negative value shows an error. */
+/********************************************************************************/
+static int
+pof_handle_data(hysdn_card * card, int datlen)
+{
+ struct boot_data *boot = card->boot; /* pointer to boot specific data */
+ long l;
+ uchar *imgp;
+ int img_len;
+
+ /* handle the different record types */
+ switch (boot->pof_recid) {
+
+ case TAG_TIMESTMP:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText);
+ break;
+
+ case TAG_CBOOTDTA:
+ DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
+ case TAG_BOOTDTA:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
+ (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA",
+ datlen, boot->pof_recoffset);
+
+ if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) {
+ boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */
+ return (boot->last_error);
+ }
+ imgp = boot->buf.BootBuf; /* start of buffer */
+ img_len = datlen; /* maximum length to transfer */
+
+ l = POF_BOOT_LOADER_OFF_IN_PAGE -
+ (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1));
+ if (l > 0) {
+ /* buffer needs to be truncated */
+ imgp += l; /* advance pointer */
+ img_len -= l; /* adjust len */
+ }
+ /* at this point no special handling for data wrapping over buffer */
+ /* is necessary, because the boot image always will be adjusted to */
+ /* match a page boundary inside the buffer. */
+ /* The buffer for the boot image on the card is filled in 2 cycles */
+ /* first the 1024 hi-words are put in the buffer, then the low 1024 */
+ /* word are handled in the same way with different offset. */
+
+ if (img_len > 0) {
+ /* data available for copy */
+ if ((boot->last_error =
+ card->writebootimg(card, imgp,
+ (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0)
+ return (boot->last_error);
+ }
+ break; /* end of case boot image hi/lo */
+
+ case TAG_CABSDATA:
+ DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
+ case TAG_ABSDATA:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
+ (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
+ datlen, boot->pof_recoffset);
+
+ if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
+ return (boot->last_error); /* error writing data */
+
+ if (boot->pof_recoffset + datlen >= boot->pof_reclen)
+ return (card->waitpofready(card)); /* data completely spooled, wait for ready */
+
+ break; /* end of case boot seq data */
+
+ default:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid,
+ datlen, boot->pof_recoffset);
+
+ break; /* simply skip record */
+ } /* switch boot->pof_recid */
+
+ return (0);
+} /* pof_handle_data */
+
+
+/******************************************************************************/
+/* pof_write_buffer is called when the buffer has been filled with the needed */
+/* number of data bytes. The number delivered is additionally supplied for */
+/* verification. The functions handles the data and returns the needed number */
+/* of bytes for the next action. If the returned value is 0 or less an error */
+/* occured and booting must be aborted. */
+/******************************************************************************/
+int
+pof_write_buffer(hysdn_card * card, int datlen)
+{
+ struct boot_data *boot = card->boot; /* pointer to boot specific data */
+
+ if (!boot)
+ return (-EFAULT); /* invalid call */
+ if (boot->last_error < 0)
+ return (boot->last_error); /* repeated error */
+
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: got %d bytes ", datlen);
+
+ switch (boot->pof_state) {
+ case POF_READ_FILE_HEAD:
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: checking file header");
+
+ if (datlen != sizeof(tPofFileHdr)) {
+ boot->last_error = -EPOF_INTERNAL;
+ break;
+ }
+ if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) {
+ boot->last_error = -EPOF_BAD_MAGIC;
+ break;
+ }
+ /* Setup the new state and vars */
+ boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */
+ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
+ boot->last_error = sizeof(tPofRecHdr); /* new length */
+ break;
+
+ case POF_READ_TAG_HEAD:
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: checking tag header");
+
+ if (datlen != sizeof(tPofRecHdr)) {
+ boot->last_error = -EPOF_INTERNAL;
+ break;
+ }
+ boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */
+ boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */
+ boot->pof_recoffset = 0; /* no starting offset */
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ",
+ boot->pof_recid, boot->pof_reclen);
+
+ boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */
+ if (boot->pof_reclen < BOOT_BUF_SIZE)
+ boot->last_error = boot->pof_reclen; /* limit size */
+ else
+ boot->last_error = BOOT_BUF_SIZE; /* maximum */
+
+ if (!boot->last_error) { /* no data inside record */
+ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
+ boot->last_error = sizeof(tPofRecHdr); /* new length */
+ }
+ break;
+
+ case POF_READ_TAG_DATA:
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: getting tag data");
+
+ if (datlen != boot->last_error) {
+ boot->last_error = -EPOF_INTERNAL;
+ break;
+ }
+ if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
+ return (boot->last_error); /* an error occured */
+
+ boot->pof_recoffset += datlen;
+ if (boot->pof_recoffset >= boot->pof_reclen) {
+ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
+ boot->last_error = sizeof(tPofRecHdr); /* new length */
+ } else {
+ if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE)
+ boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */
+ else
+ boot->last_error = BOOT_BUF_SIZE; /* maximum */
+ }
+ break;
+
+ default:
+ boot->last_error = -EPOF_INTERNAL; /* unknown state */
+ break;
+ } /* switch (boot->pof_state) */
+
+ return (boot->last_error);
+} /* pof_write_buffer */
+
+
+/*******************************************************************************/
+/* pof_write_open is called when an open for boot on the cardlog device occurs. */
+/* The function returns the needed number of bytes for the next operation. If */
+/* the returned number is less or equal 0 an error specified by this code */
+/* occurred. Additionally the pointer to the buffer data area is set on success */
+/*******************************************************************************/
+int
+pof_write_open(hysdn_card * card, uchar ** bufp)
+{
+ struct boot_data *boot; /* pointer to boot specific data */
+
+ if (card->boot) {
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF open: already opened for boot");
+ return (-ERR_ALREADY_BOOT); /* boot already active */
+ }
+ /* error no mem available */
+ if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
+ if (card->debug_flags & LOG_MEM_ERR)
+ hysdn_addlog(card, "POF open: unable to allocate mem");
+ return (-EFAULT);
+ }
+ card->boot = boot;
+ card->state = CARD_STATE_BOOTING;
+ memset(boot, 0, sizeof(struct boot_data));
+
+ card->stopcard(card); /* first stop the card */
+ if (card->testram(card)) {
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF open: DPRAM test failure");
+ boot->last_error = -ERR_BOARD_DPRAM;
+ card->state = CARD_STATE_BOOTERR; /* show boot error */
+ return (boot->last_error);
+ }
+ boot->BufSize = 0; /* Buffer is empty */
+ boot->pof_state = POF_READ_FILE_HEAD; /* read file header */
+ StartDecryption(boot); /* if POF File should be encrypted */
+
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF open: success");
+
+ *bufp = boot->buf.BootBuf; /* point to buffer */
+ return (sizeof(tPofFileHdr));
+} /* pof_write_open */
+
+/********************************************************************************/
+/* pof_write_close is called when an close of boot on the cardlog device occurs. */
+/* The return value must be 0 if everything has happened as desired. */
+/********************************************************************************/
+int
+pof_write_close(hysdn_card * card)
+{
+ struct boot_data *boot = card->boot; /* pointer to boot specific data */
+
+ if (!boot)
+ return (-EFAULT); /* invalid call */
+
+ card->boot = NULL; /* no boot active */
+ kfree(boot);
+
+ if (card->state == CARD_STATE_RUN)
+ card->set_errlog_state(card, 1); /* activate error log */
+
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF close: success");
+
+ return (0);
+} /* pof_write_close */
+
+/*********************************************************************************/
+/* EvalSysrTokData checks additional records delivered with the Sysready Message */
+/* when POF has been booted. A return value of 0 is used if no error occured. */
+/*********************************************************************************/
+int
+EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
+{
+ u_char *p;
+ u_char crc;
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "SysReady Token data length %d", len);
+
+ if (len < 2) {
+ hysdn_addlog(card, "SysReady Token Data to short");
+ return (1);
+ }
+ for (p = cp, crc = 0; p < (cp + len - 2); p++)
+ if ((crc & 0x80))
+ crc = (((u_char) (crc << 1)) + 1) + *p;
+ else
+ crc = ((u_char) (crc << 1)) + *p;
+ crc = ~crc;
+ if (crc != *(cp + len - 1)) {
+ hysdn_addlog(card, "SysReady Token Data invalid CRC");
+ return (1);
+ }
+ len--; /* dont check CRC byte */
+ while (len > 0) {
+
+ if (*cp == SYSR_TOK_END)
+ return (0); /* End of Token stream */
+
+ if (len < (*(cp + 1) + 2)) {
+ hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
+ return (1);
+ }
+ switch (*cp) {
+ case SYSR_TOK_B_CHAN: /* 1 */
+ if (*(cp + 1) != 1)
+ return (1); /* length invalid */
+ card->bchans = *(cp + 2);
+ break;
+
+ case SYSR_TOK_FAX_CHAN: /* 2 */
+ if (*(cp + 1) != 1)
+ return (1); /* length invalid */
+ card->faxchans = *(cp + 2);
+ break;
+
+ case SYSR_TOK_MAC_ADDR: /* 3 */
+ if (*(cp + 1) != 6)
+ return (1); /* length invalid */
+ memcpy(card->mac_addr, cp + 2, 6);
+ break;
+
+ default:
+ hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
+ break;
+ }
+ len -= (*(cp + 1) + 2); /* adjust len */
+ cp += (*(cp + 1) + 2); /* and pointer */
+ }
+
+ hysdn_addlog(card, "no end token found");
+ return (1);
+} /* EvalSysrTokData */
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
new file mode 100644
index 000000000..cac76cb26
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -0,0 +1,229 @@
+/* $Id: hysdn_defs.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+
+ * Linux driver for HYSDN cards, global definitions and exported vars and functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_defs.h,v $
+ * Revision 1.1 2000/02/10 19:44:30 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#include <linux/hysdn_if.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/skbuff.h>
+
+/****************************/
+/* storage type definitions */
+/****************************/
+#define uchar unsigned char
+#define uint unsigned int
+#define ulong unsigned long
+#define word unsigned short
+
+#include "ince1pc.h"
+
+/************************************************/
+/* constants and bits for debugging/log outputs */
+/************************************************/
+#define LOG_MAX_LINELEN 120
+#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */
+#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */
+#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */
+#define LOG_POF_RECORD 0x00000020 /* log pof record parser */
+#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */
+#define LOG_POF_CARD 0x00000080 /* log pof related card functions */
+#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */
+#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */
+#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */
+#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */
+#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */
+#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */
+#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */
+
+#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */
+
+/**********************************/
+/* proc filesystem name constants */
+/**********************************/
+#define PROC_SUBDIR_NAME "hysdn"
+#define PROC_CONF_BASENAME "cardconf"
+#define PROC_LOG_BASENAME "cardlog"
+
+/************************/
+/* PCI constant defines */
+/************************/
+#define PCI_VENDOR_ID_HYPERCOPE 0x1365
+#define PCI_DEVICE_ID_PLX 0x9050 /* all DPRAM cards use the same id */
+
+/*****************************/
+/* sub ids determining cards */
+/*****************************/
+#define PCI_SUB_ID_OLD_ERGO 0x0104
+#define PCI_SUB_ID_ERGO 0x0106
+#define PCI_SUB_ID_METRO 0x0107
+#define PCI_SUB_ID_CHAMP2 0x0108
+#define PCI_SUB_ID_PLEXUS 0x0109
+
+/***********************************/
+/* PCI 32 bit parms for IO and MEM */
+/***********************************/
+#define PCI_REG_PLX_MEM_BASE 0
+#define PCI_REG_PLX_IO_BASE 1
+#define PCI_REG_MEMORY_BASE 3
+
+/**************/
+/* card types */
+/**************/
+#define BD_NONE 0U
+#define BD_PERFORMANCE 1U
+#define BD_VALUE 2U
+#define BD_PCCARD 3U
+#define BD_ERGO 4U
+#define BD_METRO 5U
+#define BD_CHAMP2 6U
+#define BD_PLEXUS 7U
+
+/******************************************************/
+/* defined states for cards shown by reading cardconf */
+/******************************************************/
+#define CARD_STATE_UNUSED 0 /* never been used or booted */
+#define CARD_STATE_BOOTING 1 /* booting is in progress */
+#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */
+#define CARD_STATE_RUN 3 /* card is active */
+
+/*******************************/
+/* defines for error_log_state */
+/*******************************/
+#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */
+#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */
+#define ERRLOG_STATE_START 2 /* start error logging */
+#define ERRLOG_STATE_STOP 3 /* stop error logging */
+
+/*******************************/
+/* data structure for one card */
+/*******************************/
+typedef struct HYSDN_CARD {
+
+ /* general variables for the cards */
+ int myid; /* own driver card id */
+ uchar bus; /* pci bus the card is connected to */
+ uchar devfn; /* slot+function bit encoded */
+ word subsysid; /* PCI subsystem id */
+ uchar brdtype; /* type of card */
+ uint bchans; /* number of available B-channels */
+ uint faxchans; /* number of available fax-channels */
+ uchar mac_addr[6]; /* MAC Address read from card */
+ uint irq; /* interrupt number */
+ uint iobase; /* IO-port base address */
+ ulong plxbase; /* PLX memory base */
+ ulong membase; /* DPRAM memory base */
+ ulong memend; /* DPRAM memory end */
+ void *dpram; /* mapped dpram */
+ int state; /* actual state of card -> CARD_STATE_** */
+ struct HYSDN_CARD *next; /* pointer to next card */
+
+ /* data areas for the /proc file system */
+ void *proclog; /* pointer to proclog filesystem specific data */
+ void *procconf; /* pointer to procconf filesystem specific data */
+
+ /* debugging and logging */
+ uchar err_log_state; /* actual error log state of the card */
+ ulong debug_flags; /* tells what should be debugged and where */
+ void (*set_errlog_state) (struct HYSDN_CARD *, int);
+
+ /* interrupt handler + interrupt synchronisation */
+ struct tq_struct irq_queue; /* interrupt task queue */
+ uchar volatile irq_enabled; /* interrupt enabled if != 0 */
+ uchar volatile hw_lock; /* hardware is currently locked -> no access */
+
+ /* boot process */
+ void *boot; /* pointer to boot private data */
+ int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong);
+ int (*writebootseq) (struct HYSDN_CARD *, uchar *, int);
+ int (*waitpofready) (struct HYSDN_CARD *);
+ int (*testram) (struct HYSDN_CARD *);
+
+ /* scheduler for data transfer (only async parts) */
+ uchar async_data[256]; /* async data to be sent (normally for config) */
+ word volatile async_len; /* length of data to sent */
+ word volatile async_channel; /* channel number for async transfer */
+ int volatile async_busy; /* flag != 0 sending in progress */
+ int volatile net_tx_busy; /* a network packet tx is in progress */
+
+ /* network interface */
+ void *netif; /* pointer to network structure */
+
+ /* init and deinit stopcard for booting, too */
+ void (*stopcard) (struct HYSDN_CARD *);
+ void (*releasehardware) (struct HYSDN_CARD *);
+} hysdn_card;
+
+
+/*****************/
+/* exported vars */
+/*****************/
+extern int cardmax; /* number of found cards */
+extern hysdn_card *card_root; /* pointer to first card */
+
+
+
+/*************************/
+/* im/exported functions */
+/*************************/
+extern int printk(const char *fmt,...);
+extern char *hysdn_getrev(const char *);
+
+/* hysdn_procconf.c */
+extern int hysdn_procconf_init(void); /* init proc config filesys */
+extern void hysdn_procconf_release(void); /* deinit proc config filesys */
+
+/* hysdn_proclog.c */
+extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */
+extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */
+extern void put_log_buffer(hysdn_card *, char *); /* output log data */
+extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */
+extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */
+
+/* boardergo.c */
+extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */
+
+/* hysdn_boot.c */
+extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */
+extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */
+extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */
+extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */
+
+/* hysdn_sched.c */
+extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *,
+ word);
+extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word);
+extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */
+
+/* hysdn_net.c */
+extern char *hysdn_net_revision;
+extern int hysdn_net_create(hysdn_card *); /* create a new net device */
+extern int hysdn_net_release(hysdn_card *); /* delete the device */
+extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */
+extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */
+extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */
+extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
new file mode 100644
index 000000000..eb3fed4d3
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -0,0 +1,243 @@
+/* $Id: hysdn_init.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, init functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_init.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_init_revision = "$Revision: 1.1 $";
+int cardmax; /* number of found cards */
+hysdn_card *card_root = NULL; /* pointer to first card */
+
+/**********************************************/
+/* table assigning PCI-sub ids to board types */
+/* the last entry contains all 0 */
+/**********************************************/
+static struct {
+ word subid; /* PCI sub id */
+ uchar cardtyp; /* card type assigned */
+} pci_subid_map[] = {
+
+ {
+ PCI_SUB_ID_METRO, BD_METRO
+ },
+ {
+ PCI_SUB_ID_CHAMP2, BD_CHAMP2
+ },
+ {
+ PCI_SUB_ID_ERGO, BD_ERGO
+ },
+ {
+ PCI_SUB_ID_OLD_ERGO, BD_ERGO
+ },
+ {
+ 0, 0
+ } /* terminating entry */
+};
+
+/*********************************************************************/
+/* search_cards searches for available cards in the pci config data. */
+/* If a card is found, the card structure is allocated and the cards */
+/* ressources are reserved. cardmax is incremented. */
+/*********************************************************************/
+static void
+search_cards(void)
+{
+ struct pci_dev *akt_pcidev = NULL;
+ hysdn_card *card, *card_last;
+ uchar irq;
+ int i;
+
+ card_root = NULL;
+ card_last = NULL;
+ while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_PLX,
+ akt_pcidev)) != NULL) {
+
+ if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+ return;
+ }
+ memset(card, 0, sizeof(hysdn_card));
+ card->myid = cardmax; /* set own id */
+ card->bus = akt_pcidev->bus->number;
+ card->devfn = akt_pcidev->devfn; /* slot + function */
+ pcibios_read_config_word(card->bus, card->devfn, PCI_SUBSYSTEM_ID, &card->subsysid);
+ pcibios_read_config_byte(card->bus, card->devfn, PCI_INTERRUPT_LINE, &irq);
+ card->irq = irq;
+ card->iobase = akt_pcidev->resource[ PCI_REG_PLX_IO_BASE].start & PCI_BASE_ADDRESS_IO_MASK;
+ card->plxbase = akt_pcidev->resource[ PCI_REG_PLX_MEM_BASE].start;
+ card->membase = akt_pcidev->resource[ PCI_REG_MEMORY_BASE].start;
+ card->brdtype = BD_NONE; /* unknown */
+ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
+ card->faxchans = 0; /* default no fax channels */
+ card->bchans = 2; /* and 2 b-channels */
+ for (i = 0; pci_subid_map[i].subid; i++)
+ if (pci_subid_map[i].subid == card->subsysid) {
+ card->brdtype = pci_subid_map[i].cardtyp;
+ break;
+ }
+ if (card->brdtype != BD_NONE) {
+ if (ergo_inithardware(card)) {
+ printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+ kfree(card);
+ continue;
+ }
+ } else {
+ printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
+ kfree(card); /* release mem */
+ continue;
+ }
+ cardmax++;
+ card->next = NULL; /*end of chain */
+ if (card_last)
+ card_last->next = card; /* pointer to next card */
+ else
+ card_root = card;
+ card_last = card; /* new chain end */
+ } /* device found */
+} /* search_cards */
+
+/************************************************************************************/
+/* free_resources frees the acquired PCI resources and returns the allocated memory */
+/************************************************************************************/
+static void
+free_resources(void)
+{
+ hysdn_card *card;
+
+ while (card_root) {
+ card = card_root;
+ if (card->releasehardware)
+ card->releasehardware(card); /* free all hardware resources */
+ card_root = card_root->next; /* remove card from chain */
+ kfree(card); /* return mem */
+
+ } /* while card_root */
+} /* free_resources */
+
+/**************************************************************************/
+/* stop_cards disables (hardware resets) all cards and disables interrupt */
+/**************************************************************************/
+static void
+stop_cards(void)
+{
+ hysdn_card *card;
+
+ card = card_root; /* first in chain */
+ while (card) {
+ if (card->stopcard)
+ card->stopcard(card);
+ card = card->next; /* remove card from chain */
+ } /* while card */
+} /* stop_cards */
+
+
+/****************************************************************************/
+/* The module startup and shutdown code. Only compiled when used as module. */
+/* Using the driver as module is always advisable, because the booting */
+/* image becomes smaller and the driver code is only loaded when needed. */
+/* Additionally newer versions may be activated without rebooting. */
+/****************************************************************************/
+#ifdef CONFIG_MODULES
+
+/******************************************************/
+/* extract revision number from string for log output */
+/******************************************************/
+char *
+hysdn_getrev(const char *revision)
+{
+ char *rev;
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ rev = p + 2;
+ p = strchr(rev, '$');
+ *--p = 0;
+ } else
+ rev = "???";
+ return rev;
+}
+
+
+/****************************************************************************/
+/* init_module is called once when the module is loaded to do all necessary */
+/* things like autodetect... */
+/* If the return value of this function is 0 the init has been successfull */
+/* and the module is added to the list in /proc/modules, otherwise an error */
+/* is assumed and the module will not be kept in memory. */
+/****************************************************************************/
+int
+init_module(void)
+{
+ char tmp[50];
+
+ strcpy(tmp, hysdn_init_revision);
+ printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
+ strcpy(tmp, hysdn_net_revision);
+ printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
+ if (!pci_present()) {
+ printk(KERN_ERR "HYSDN: no PCI bus present, module not loaded\n");
+ return (-1);
+ }
+ search_cards();
+ printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
+
+ if (hysdn_procconf_init()) {
+ free_resources(); /* proc file_sys not created */
+ return (-1);
+ }
+ return (0); /* no error */
+} /* init_module */
+
+
+/***********************************************************************/
+/* cleanup_module is called when the module is released by the kernel. */
+/* The routine is only called if init_module has been successfull and */
+/* the module counter has a value of 0. Otherwise this function will */
+/* not be called. This function must release all resources still allo- */
+/* cated as after the return from this function the module code will */
+/* be removed from memory. */
+/***********************************************************************/
+void
+cleanup_module(void)
+{
+
+ stop_cards();
+ hysdn_procconf_release();
+ free_resources();
+ printk(KERN_NOTICE "HYSDN: module unloaded\n");
+} /* cleanup_module */
+
+#endif /* CONFIG_MODULES */
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
new file mode 100644
index 000000000..1a3d21012
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -0,0 +1,378 @@
+/* $Id: hysdn_net.c,v 1.3 2000/02/14 19:24:12 werner Exp $
+
+ * Linux driver for HYSDN cards, net (ethernet type) handling routines.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This net module has been inspired by the skeleton driver from
+ * Donald Becker (becker@CESDIS.gsfc.nasa.gov)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_net.c,v $
+ * Revision 1.3 2000/02/14 19:24:12 werner
+ *
+ * Removed superflous file
+ *
+ * Revision 1.2 2000/02/13 17:32:19 werner
+ *
+ * Added support for new network layer of 2.3.43 and 44 kernels and tested driver.
+ *
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inetdevice.h>
+
+#include "hysdn_defs.h"
+
+/* store the actual version for log reporting */
+char *hysdn_net_revision = "$Revision: 1.3 $";
+
+#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
+
+/****************************************************************************/
+/* structure containing the complete network data. The structure is aligned */
+/* in a way that both, the device and statistics are kept inside it. */
+/* for proper access, the device structure MUST be the first var/struct */
+/* inside the definition. */
+/****************************************************************************/
+struct net_local {
+ struct net_device netdev; /* the network device */
+ struct net_device_stats stats;
+ /* additional vars may be added here */
+ char dev_name[9]; /* our own device name */
+
+ /* Tx control lock. This protects the transmit buffer ring
+ * state along with the "tx full" state of the driver. This
+ * means all netif_queue flow control actions are protected
+ * by this lock as well.
+ */
+ spinlock_t lock;
+ struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */
+ int in_idx, out_idx; /* indexes to buffer ring */
+ int sk_count; /* number of buffers currently in ring */
+
+ int is_open; /* flag controlling module locking */
+}; /* net_local */
+
+
+/*****************************************************/
+/* Get the current statistics for this card. */
+/* This may be called with the card open or closed ! */
+/*****************************************************/
+static struct net_device_stats *
+net_get_stats(struct net_device *dev)
+{
+ return (&((struct net_local *) dev)->stats);
+} /* net_device_stats */
+
+/*********************************************************************/
+/* Open/initialize the board. This is called (in the current kernel) */
+/* sometime after booting when the 'ifconfig' program is run. */
+/* This routine should set everything up anew at each open, even */
+/* registers that "should" only need to be set once at boot, so that */
+/* there is non-reboot way to recover if something goes wrong. */
+/*********************************************************************/
+static int
+net_open(struct net_device *dev)
+{
+ struct in_device *in_dev;
+ hysdn_card *card = dev->priv;
+ int i;
+
+ if (!((struct net_local *) dev)->is_open)
+ MOD_INC_USE_COUNT; /* increment only if interface is actually down */
+ ((struct net_local *) dev)->is_open = 1; /* device actually open */
+
+ netif_start_queue(dev); /* start tx-queueing */
+
+ /* Fill in the MAC-level header (if not already set) */
+ if (!card->mac_addr[0]) {
+ for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
+ dev->dev_addr[i] = 0xfc;
+ if ((in_dev = dev->ip_ptr) != NULL) {
+ struct in_ifaddr *ifa = in_dev->ifa_list;
+ if (ifa != NULL)
+ memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong));
+ }
+ } else
+ memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
+
+ return (0);
+} /* net_open */
+
+/*******************************************/
+/* flush the currently occupied tx-buffers */
+/* must only be called when device closed */
+/*******************************************/
+static void
+flush_tx_buffers(struct net_local *nl)
+{
+
+ while (nl->sk_count) {
+ dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */
+ if (nl->out_idx >= MAX_SKB_BUFFERS)
+ nl->out_idx = 0; /* wrap around */
+ nl->sk_count--;
+ }
+} /* flush_tx_buffers */
+
+
+/*********************************************************************/
+/* close/decativate the device. The device is not removed, but only */
+/* deactivated. */
+/*********************************************************************/
+static int
+net_close(struct net_device *dev)
+{
+
+ netif_stop_queue(dev); /* disable queueing */
+
+ if (((struct net_local *) dev)->is_open)
+ MOD_DEC_USE_COUNT; /* adjust module counter */
+ ((struct net_local *) dev)->is_open = 0;
+ flush_tx_buffers((struct net_local *) dev);
+
+ return (0); /* success */
+} /* net_close */
+
+/************************************/
+/* send a packet on this interface. */
+/* new style for kernel >= 2.3.33 */
+/************************************/
+static int
+net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *) dev;
+
+ spin_lock_irq(&lp->lock);
+
+ lp->skbs[lp->in_idx++] = skb; /* add to buffer list */
+ if (lp->in_idx >= MAX_SKB_BUFFERS)
+ lp->in_idx = 0; /* wrap around */
+ lp->sk_count++; /* adjust counter */
+ dev->trans_start = jiffies;
+
+ /* If we just used up the very last entry in the
+ * TX ring on this device, tell the queueing
+ * layer to send no more.
+ */
+ if (lp->sk_count >= MAX_SKB_BUFFERS)
+ netif_stop_queue(dev);
+
+ /* When the TX completion hw interrupt arrives, this
+ * is when the transmit statistics are updated.
+ */
+
+ spin_unlock_irq(&lp->lock);
+
+ if (lp->sk_count <= 3) {
+ queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ return (0); /* success */
+} /* net_send_packet */
+
+
+
+/***********************************************************************/
+/* acknowlegde a packet send. The network layer will be informed about */
+/* completion */
+/***********************************************************************/
+void
+hysdn_tx_netack(hysdn_card * card)
+{
+ struct net_local *lp = card->netif;
+
+ if (!lp)
+ return; /* non existing device */
+
+
+ if (!lp->sk_count)
+ return; /* error condition */
+
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
+
+ dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */
+ if (lp->out_idx >= MAX_SKB_BUFFERS)
+ lp->out_idx = 0; /* wrap around */
+
+ if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */
+ netif_start_queue((struct net_device *) lp);
+} /* hysdn_tx_netack */
+
+/*****************************************************/
+/* we got a packet from the network, go and queue it */
+/*****************************************************/
+void
+hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len)
+{
+ struct net_local *lp = card->netif;
+ struct sk_buff *skb;
+
+ if (!lp)
+ return; /* non existing device */
+
+ lp->stats.rx_bytes += len;
+
+ skb = dev_alloc_skb(len);
+ if (skb == NULL) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+ lp->netdev.name);
+ lp->stats.rx_dropped++;
+ return;
+ }
+ skb->dev = &lp->netdev;
+
+ /* copy the data */
+ memcpy(skb_put(skb, len), buf, len);
+
+ /* determine the used protocol */
+ skb->protocol = eth_type_trans(skb, &lp->netdev);
+
+ netif_rx(skb);
+ lp->stats.rx_packets++; /* adjust packet count */
+
+} /* hysdn_rx_netpkt */
+
+/*****************************************************/
+/* return the pointer to a network packet to be send */
+/*****************************************************/
+struct sk_buff *
+hysdn_tx_netget(hysdn_card * card)
+{
+ struct net_local *lp = card->netif;
+
+ if (!lp)
+ return (NULL); /* non existing device */
+
+ if (!lp->sk_count)
+ return (NULL); /* nothing available */
+
+ return (lp->skbs[lp->out_idx]); /* next packet to send */
+} /* hysdn_tx_netget */
+
+
+/*******************************************/
+/* init function called by register device */
+/*******************************************/
+static int
+net_init(struct net_device *dev)
+{
+ /* setup the function table */
+ dev->open = net_open;
+ dev->stop = net_close;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+
+ return (0); /* success */
+} /* net_init */
+
+/*****************************************************************************/
+/* hysdn_net_create creates a new net device for the given card. If a device */
+/* already exists, it will be deleted and created a new one. The return value */
+/* 0 announces success, else a negative error code will be returned. */
+/*****************************************************************************/
+int
+hysdn_net_create(hysdn_card * card)
+{
+ struct net_device *dev;
+ int i;
+
+ hysdn_net_release(card); /* release an existing net device */
+ if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
+ printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
+ if (card->debug_flags & LOG_NET_INIT)
+ return (-ENOMEM);
+ }
+ memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
+
+ spin_lock_init(&((struct net_local *) dev)->lock);
+
+ /* initialise necessary or informing fields */
+ dev->base_addr = card->iobase; /* IO address */
+ dev->irq = card->irq; /* irq */
+ dev->init = net_init; /* the init function of the device */
+ dev->name = ((struct net_local *) dev)->dev_name; /* device name */
+ if ((i = register_netdev(dev))) {
+ printk(KERN_WARNING "HYSDN: unable to create network device\n");
+ kfree(dev);
+ return (i);
+ }
+ dev->priv = card; /* remember pointer to own data structure */
+ card->netif = dev; /* setup the local pointer */
+
+ if (card->debug_flags & LOG_NET_INIT)
+ hysdn_addlog(card, "network device created");
+ return (0); /* and return success */
+} /* hysdn_net_create */
+
+/***************************************************************************/
+/* hysdn_net_release deletes the net device for the given card. The return */
+/* value 0 announces success, else a negative error code will be returned. */
+/***************************************************************************/
+int
+hysdn_net_release(hysdn_card * card)
+{
+ struct net_device *dev = card->netif;
+
+ if (!dev)
+ return (0); /* non existing */
+
+ card->netif = NULL; /* clear out pointer */
+ dev->stop(dev); /* close the device */
+
+ flush_tx_buffers((struct net_local *) dev); /* empty buffers */
+
+ unregister_netdev(dev); /* release the device */
+ kfree(dev); /* release the memory allocated */
+ if (card->debug_flags & LOG_NET_INIT)
+ hysdn_addlog(card, "network device deleted");
+
+ return (0); /* always successfull */
+} /* hysdn_net_release */
+
+/*****************************************************************************/
+/* hysdn_net_getname returns a pointer to the name of the network interface. */
+/* if the interface is not existing, a "-" is returned. */
+/*****************************************************************************/
+char *
+hysdn_net_getname(hysdn_card * card)
+{
+ struct net_device *dev = card->netif;
+
+ if (!dev)
+ return ("-"); /* non existing */
+
+ return (dev->name);
+} /* hysdn_net_getname */
diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h
new file mode 100644
index 000000000..619c07897
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_pof.h
@@ -0,0 +1,95 @@
+/* $Id: hysdn_pof.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+
+ * Linux driver for HYSDN cards, definitions used for handling pof-files.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_pof.h,v $
+ * Revision 1.1 2000/02/10 19:44:30 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+/************************/
+/* POF specific defines */
+/************************/
+#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */
+#define CRYPT_FEEDTERM 0x8142
+#define CRYPT_STARTTERM 0x81a5
+ /* max. timeout time in seconds
+ * from end of booting to POF is ready
+ */
+#define POF_READY_TIME_OUT_SEC 10
+
+/**********************************/
+/* defines for 1.stage boot image */
+/**********************************/
+
+/* the POF file record containing the boot loader image
+ * has 2 pages a 16KB:
+ * 1. page contains the high 16-bit part of the 32-bit E1 words
+ * 2. page contains the low 16-bit part of the 32-bit E1 words
+ *
+ * In each 16KB page we assume the start of the boot loader code
+ * in the highest 2KB part (at offset 0x3800);
+ * the rest (0x0000..0x37FF) is assumed to contain 0 bytes.
+ */
+
+#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */
+#define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE)
+
+#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */
+
+ /* offset in boot page, where loader code may start */
+ /* =0x3800= 14336U */
+#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE)
+
+
+/*--------------------------------------POF file record structs------------*/
+typedef struct PofFileHdr_tag { /* Pof file header */
+/*00 */ ulong Magic __attribute__((packed));
+/*04 */ ulong N_PofRecs __attribute__((packed));
+/*08 */
+} tPofFileHdr;
+
+typedef struct PofRecHdr_tag { /* Pof record header */
+/*00 */ word PofRecId __attribute__((packed));
+/*02 */ ulong PofRecDataLen __attribute__((packed));
+/*06 */
+} tPofRecHdr;
+
+typedef struct PofTimeStamp_tag {
+/*00 */ ulong UnixTime __attribute__((packed));
+ /*04 */ uchar DateTimeText[0x28] __attribute__((packed));
+ /* =40 */
+/*2C */
+} tPofTimeStamp;
+
+ /* tPofFileHdr.Magic value: */
+#define TAGFILEMAGIC 0x464F501AUL
+ /* tPofRecHdr.PofRecId values: */
+#define TAG_ABSDATA 0x1000 /* abs. data */
+#define TAG_BOOTDTA 0x1001 /* boot data */
+#define TAG_COMMENT 0x0020
+#define TAG_SYSCALL 0x0021
+#define TAG_FLOWCTRL 0x0022
+#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */
+#define TAG_CABSDATA 0x1100 /* crypted abs. data */
+#define TAG_CBOOTDTA 0x1101 /* crypted boot data */
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
new file mode 100644
index 000000000..81e1b84f0
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -0,0 +1,485 @@
+/* $Id: hysdn_procconf.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_procconf.c,v $
+ * Revision 1.2 2000/02/14 19:23:03 werner
+ *
+ * Changed handling of proc filesystem tables to a more portable version
+ *
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_procconf_revision = "$Revision: 1.2 $";
+
+#define INFO_OUT_LEN 80 /* length of info line including lf */
+
+/********************************************************/
+/* defines and data structure for conf write operations */
+/********************************************************/
+#define CONF_STATE_DETECT 0 /* waiting for detect */
+#define CONF_STATE_CONF 1 /* writing config data */
+#define CONF_STATE_POF 2 /* writing pof data */
+#define CONF_LINE_LEN 80 /* 80 chars max */
+
+struct conf_writedata {
+ hysdn_card *card; /* card the device is connected to */
+ int buf_size; /* actual number of bytes in the buffer */
+ int needed_size; /* needed size when reading pof */
+ int state; /* actual interface states from above constants */
+ uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */
+ word channel; /* active channel number */
+ uchar *pof_buffer; /* buffer when writing pof */
+};
+
+/***********************************************************************/
+/* process_line parses one config line and transfers it to the card if */
+/* necessary. */
+/* if the return value is negative an error occured. */
+/***********************************************************************/
+static int
+process_line(struct conf_writedata *cnf)
+{
+ uchar *cp = cnf->conf_line;
+ int i;
+
+ if (cnf->card->debug_flags & LOG_CNF_LINE)
+ hysdn_addlog(cnf->card, "conf line: %s", cp);
+
+ if (*cp == '-') { /* option */
+ cp++; /* point to option char */
+
+ if (*cp++ != 'c')
+ return (0); /* option unknown or used */
+ i = 0; /* start value for channel */
+ while ((*cp <= '9') && (*cp >= '0'))
+ i = i * 10 + *cp++ - '0'; /* get decimal number */
+ if (i > 65535) {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "conf channel invalid %d", i);
+ return (-ERR_INV_CHAN); /* invalid channel */
+ }
+ cnf->channel = i & 0xFFFF; /* set new channel number */
+ return (0); /* success */
+ } /* option */
+ if (*cp == '*') { /* line to send */
+ if (cnf->card->debug_flags & LOG_CNF_DATA)
+ hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp);
+ return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1,
+ cnf->channel)); /* send the line without * */
+ } /* line to send */
+ return (0);
+} /* process_line */
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+ return -ESPIPE;
+} /* hysdn_dummy_lseek */
+
+/***********************************/
+/* conf file operations and tables */
+/***********************************/
+
+/****************************************************/
+/* write conf file -> boot or send cfg line to card */
+/****************************************************/
+static ssize_t
+hysdn_conf_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+ struct conf_writedata *cnf;
+ int i;
+ uchar ch, *cp;
+
+ if (&file->f_pos != off) /* fs error check */
+ return (-ESPIPE);
+ if (!count)
+ return (0); /* nothing to handle */
+
+ if (!(cnf = file->private_data))
+ return (-EFAULT); /* should never happen */
+
+ if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */
+ if (copy_from_user(&ch, buf, 1)) /* get first char for detect */
+ return (-EFAULT);
+
+ if (ch == 0x1A) {
+ /* we detected a pof file */
+ if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0)
+ return (cnf->needed_size); /* an error occured -> exit */
+ cnf->buf_size = 0; /* buffer is empty */
+ cnf->state = CONF_STATE_POF; /* new state */
+ } else {
+ /* conf data has been detected */
+ cnf->buf_size = 0; /* buffer is empty */
+ cnf->state = CONF_STATE_CONF; /* requested conf data write */
+ if (cnf->card->state != CARD_STATE_RUN)
+ return (-ERR_NOT_BOOTED);
+ cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */
+ cnf->channel = 4098; /* default channel for output */
+ }
+ } /* state was auto detect */
+ if (cnf->state == CONF_STATE_POF) { /* pof write active */
+ i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */
+ if (i <= 0)
+ return (-EINVAL); /* size error handling pof */
+
+ if (i < count)
+ count = i; /* limit requested number of bytes */
+ if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count))
+ return (-EFAULT); /* error while copying */
+ cnf->buf_size += count;
+
+ if (cnf->needed_size == cnf->buf_size) {
+ cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */
+ if (cnf->needed_size <= 0) {
+ cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */
+ return (cnf->needed_size); /* an error occured */
+ }
+ cnf->buf_size = 0; /* buffer is empty again */
+ }
+ }
+ /* pof write active */
+ else { /* conf write active */
+
+ if (cnf->card->state != CARD_STATE_RUN) {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "cnf write denied -> not booted");
+ return (-ERR_NOT_BOOTED);
+ }
+ i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */
+ if (i > 0) {
+ /* copy remaining bytes into buffer */
+
+ if (count > i)
+ count = i; /* limit transfer */
+ if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count))
+ return (-EFAULT); /* error while copying */
+
+ i = count; /* number of chars in buffer */
+ cp = cnf->conf_line + cnf->buf_size;
+ while (i) {
+ /* search for end of line */
+ if ((*cp < ' ') && (*cp != 9))
+ break; /* end of line found */
+ cp++;
+ i--;
+ } /* search for end of line */
+
+ if (i) {
+ /* delimiter found */
+ *cp++ = 0; /* string termination */
+ count -= (i - 1); /* subtract remaining bytes from count */
+ while ((i) && (*cp < ' ') && (*cp != 9)) {
+ i--; /* discard next char */
+ count++; /* mark as read */
+ cp++; /* next char */
+ }
+ cnf->buf_size = 0; /* buffer is empty after transfer */
+ if ((i = process_line(cnf)) < 0) /* handle the line */
+ count = i; /* return the error */
+ }
+ /* delimiter found */
+ else {
+ cnf->buf_size += count; /* add chars to string */
+ if (cnf->buf_size >= CONF_LINE_LEN - 1) {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count);
+ return (-ERR_CONF_LONG);
+ }
+ } /* not delimited */
+
+ }
+ /* copy remaining bytes into buffer */
+ else {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "cnf line too long");
+ return (-ERR_CONF_LONG);
+ }
+ } /* conf write active */
+
+ return (count);
+} /* hysdn_conf_write */
+
+/*******************************************/
+/* read conf file -> output card info data */
+/*******************************************/
+static ssize_t
+hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ char *cp;
+ int i;
+
+ if (off != &file->f_pos) /* fs error check */
+ return -ESPIPE;
+
+ if (file->f_mode & FMODE_READ) {
+ if (!(cp = file->private_data))
+ return (-EFAULT); /* should never happen */
+ i = strlen(cp); /* get total string length */
+ if (*off < i) {
+ /* still bytes to transfer */
+ cp += *off; /* point to desired data offset */
+ i -= *off; /* remaining length */
+ if (i > count)
+ i = count; /* limit length to transfer */
+ if (copy_to_user(buf, cp, i))
+ return (-EFAULT); /* copy error */
+ *off += i; /* adjust offset */
+ } else
+ return (0);
+ } else
+ return (-EPERM); /* no permission to read */
+
+ return (i);
+} /* hysdn_conf_read */
+
+/******************/
+/* open conf file */
+/******************/
+static int
+hysdn_conf_open(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct proc_dir_entry *pd;
+ struct conf_writedata *cnf;
+ char *cp, *tmp;
+
+ MOD_INC_USE_COUNT; /* lock module */
+
+ /* now search the addressed card */
+ card = card_root;
+ while (card) {
+ pd = card->procconf;
+ if (pd->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+ hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
+ filep->f_uid, filep->f_gid, filep->f_mode);
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write boot file or conf line */
+
+ if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return (-EFAULT);
+ }
+ cnf->card = card;
+ cnf->buf_size = 0; /* nothing buffered */
+ cnf->state = CONF_STATE_DETECT; /* start auto detect */
+ filep->private_data = cnf;
+
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+ /* read access -> output card info data */
+
+ if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return (-EFAULT); /* out of memory */
+ }
+ filep->private_data = tmp; /* start of string */
+
+ /* first output a headline */
+ sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device");
+ cp = tmp; /* start of string */
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+
+ /* and now the data */
+ sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s",
+ card->myid,
+ card->bus,
+ PCI_SLOT(card->devfn),
+ card->brdtype,
+ card->irq,
+ card->iobase,
+ card->membase,
+ card->bchans,
+ card->faxchans,
+ card->state,
+ hysdn_net_getname(card));
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+ *cp = 0; /* end of string */
+ } else { /* simultaneous read/write access forbidden ! */
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ return (0);
+} /* hysdn_conf_open */
+
+/***************************/
+/* close a config file. */
+/***************************/
+static int
+hysdn_conf_close(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct conf_writedata *cnf;
+ int retval = 0;
+ struct proc_dir_entry *pd;
+
+ /* search the addressed card */
+ card = card_root;
+ while (card) {
+ pd = card->procconf;
+ if (pd->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+ hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
+ filep->f_uid, filep->f_gid, filep->f_mode);
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write boot file or conf line */
+ if (filep->private_data) {
+ cnf = filep->private_data;
+
+ if (cnf->state == CONF_STATE_POF)
+ retval = pof_write_close(cnf->card); /* close the pof write */
+ kfree(filep->private_data); /* free allocated memory for buffer */
+
+ } /* handle write private data */
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+ /* read access -> output card info data */
+
+ if (filep->private_data)
+ kfree(filep->private_data); /* release memory */
+ }
+ MOD_DEC_USE_COUNT; /* reduce usage count */
+ return (retval);
+} /* hysdn_conf_close */
+
+/******************************************************/
+/* table for conf filesystem functions defined above. */
+/******************************************************/
+static struct file_operations conf_fops =
+{
+ hysdn_dummy_lseek,
+ hysdn_conf_read,
+ hysdn_conf_write,
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ hysdn_conf_open,
+ NULL, /* flush */
+ hysdn_conf_close,
+ NULL /* fsync */
+};
+
+static struct inode_operations conf_inode_operations;
+
+/*****************************/
+/* hysdn subdir in /proc/net */
+/*****************************/
+struct proc_dir_entry *hysdn_proc_entry = NULL;
+
+/*******************************************************************************/
+/* hysdn_procconf_init is called when the module is loaded and after the cards */
+/* have been detected. The needed proc dir and card config files are created. */
+/* The log init is called at last. */
+/*******************************************************************************/
+int
+hysdn_procconf_init(void)
+{
+ hysdn_card *card;
+ uchar conf_name[20];
+
+ hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
+ if (!hysdn_proc_entry) {
+ printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
+ return (-1);
+ }
+ card = card_root; /* point to first card */
+ while (card) {
+
+ sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
+ if ((card->procconf = (void *) create_proc_entry(conf_name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ hysdn_proc_entry)) != NULL) {
+ memset(&conf_inode_operations, 0, sizeof(struct inode_operations));
+ conf_inode_operations.default_file_ops = &conf_fops;
+
+ ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations;
+ hysdn_proclog_init(card); /* init the log file entry */
+ }
+ card = card->next; /* next entry */
+ }
+
+ printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
+ return (0);
+} /* hysdn_procconf_init */
+
+/*************************************************************************************/
+/* hysdn_procconf_release is called when the module is unloaded and before the cards */
+/* resources are released. The module counter is assumed to be 0 ! */
+/*************************************************************************************/
+void
+hysdn_procconf_release(void)
+{
+ hysdn_card *card;
+ uchar conf_name[20];
+
+ card = card_root; /* start with first card */
+ while (card) {
+
+ sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
+ if (card->procconf)
+ remove_proc_entry(conf_name, hysdn_proc_entry);
+
+ hysdn_proclog_release(card); /* init the log file entry */
+
+ card = card->next; /* point to next card */
+ }
+
+ remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+} /* hysdn_procfs_release */
diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c
new file mode 100644
index 000000000..d70d350e9
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_procfs.c
@@ -0,0 +1,502 @@
+/* $Id: hysdn_procfs.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem log functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_procfs.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_procfs_revision = "$Revision: 1.1 $";
+
+#define INFO_OUT_LEN 80 /* length of info line including lf */
+
+/*************************************************/
+/* structure keeping ascii log for device output */
+/*************************************************/
+struct log_data {
+ struct log_data *next;
+ ulong usage_cnt; /* number of files still to work */
+ void *proc_ctrl; /* pointer to own control procdata structure */
+ char log_start[2]; /* log string start (final len aligned by size) */
+};
+
+/**********************************************/
+/* structure holding proc entrys for one card */
+/**********************************************/
+struct procdata {
+ struct proc_dir_entry *log; /* log entry */
+ char log_name[15]; /* log filename */
+ struct log_data *log_head, *log_tail; /* head and tail for queue */
+ int if_used; /* open count for interface */
+ wait_queue_head_t rd_queue;
+};
+
+/********************************************/
+/* put an log buffer into the log queue. */
+/* This buffer will be kept until all files */
+/* opened for read got the contents. */
+/* Flushes buffers not longer in use. */
+/********************************************/
+void
+put_log_buffer(hysdn_card * card, char *cp)
+{
+ struct log_data *ib;
+ struct procdata *pd = card->procfs;
+ int flags;
+
+ if (!pd)
+ return;
+ if (!cp)
+ return;
+ if (!*cp)
+ return;
+ if (pd->if_used <= 0)
+ return; /* no open file for read */
+
+ if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
+ return; /* no memory */
+ strcpy(ib->log_start, cp); /* set output string */
+ ib->next = NULL;
+ ib->proc_ctrl = pd; /* point to own control structure */
+ save_flags(flags);
+ cli();
+ ib->usage_cnt = pd->if_used;
+ if (!pd->log_head)
+ pd->log_head = ib; /* new head */
+ else
+ pd->log_tail->next = ib; /* follows existing messages */
+ pd->log_tail = ib; /* new tail */
+ restore_flags(flags);
+
+ /* delete old entrys */
+ while (pd->log_head->next) {
+ if ((pd->log_head->usage_cnt <= 0) &&
+ (pd->log_head->next->usage_cnt <= 0)) {
+ ib = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(ib);
+ } else
+ break;
+ } /* pd->log_head->next */
+ wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
+} /* put_log_buffer */
+
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+ return -ESPIPE;
+} /* hysdn_dummy_lseek */
+
+/**********************************/
+/* log file operations and tables */
+/**********************************/
+
+/****************************************/
+/* write log file -> set log level bits */
+/****************************************/
+static ssize_t
+hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+ int retval;
+ hysdn_card *card = (hysdn_card *) file->private_data;
+
+ if (&file->f_pos != off) /* fs error check */
+ return (-ESPIPE);
+
+ if ((retval = pof_boot_write(card, buf, count)) < 0)
+ retval = -EFAULT; /* an error occured */
+
+ return (retval);
+} /* hysdn_log_write */
+
+/******************/
+/* read log file */
+/******************/
+static ssize_t
+hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ struct log_data *inf;
+ int len;
+ word ino;
+ struct procdata *pd;
+ hysdn_card *card;
+
+ if (!*((struct log_data **) file->private_data)) {
+ if (file->f_flags & O_NONBLOCK)
+ return (-EAGAIN);
+
+ /* sorry, but we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ interruptible_sleep_on(&(pd->rd_queue));
+ else
+ return (-EAGAIN);
+
+ }
+ if (!(inf = *((struct log_data **) file->private_data)))
+ return (0);
+
+ inf->usage_cnt--; /* new usage count */
+ (struct log_data **) file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->log_start)) <= count) {
+ if (copy_to_user(buf, inf->log_start, len))
+ return -EFAULT;
+ file->f_pos += len;
+ return (len);
+ }
+ return (0);
+} /* hysdn_log_read */
+
+/******************/
+/* open log file */
+/******************/
+static int
+hysdn_log_open(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct procdata *pd;
+ ulong flags;
+
+ MOD_INC_USE_COUNT; /* lock module */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ filep->private_data = card; /* remember our own card */
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> boot pof data */
+ if (pof_boot_open(card)) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+
+ /* read access -> log/debug read */
+ save_flags(flags);
+ cli();
+ pd->if_used++;
+ if (pd->log_head)
+ (struct log_data **) filep->private_data = &(pd->log_tail->next);
+ else
+ (struct log_data **) filep->private_data = &(pd->log_head);
+ restore_flags(flags);
+
+ } else { /* simultaneous read/write access forbidden ! */
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ return (0);
+} /* hysdn_log_open */
+
+/*******************************************************************************/
+/* close a cardlog file. If the file has been opened for exclusive write it is */
+/* assumed as pof data input and the pof loader is noticed about. */
+/* Otherwise file is handled as log output. In this case the interface usage */
+/* count is decremented and all buffers are noticed of closing. If this file */
+/* was the last one to be closed, all buffers are freed. */
+/*******************************************************************************/
+static int
+hysdn_log_close(struct inode *ino, struct file *filep)
+{
+ struct log_data *inf;
+ struct procdata *pd;
+ hysdn_card *card;
+ int flags, retval = 0;
+
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write debug completely written */
+ retval = 0; /* success */
+ } else {
+ /* read access -> log/debug read, mark one further file as closed */
+
+ pd = NULL;
+ save_flags(flags);
+ cli();
+ inf = *((struct log_data **) filep->private_data); /* get first log entry */
+ if (inf)
+ pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
+ else {
+ /* no info available -> search card */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ pd = card->procfs; /* pointer to procfs ctrl */
+ }
+ if (pd)
+ pd->if_used--; /* decrement interface usage count by one */
+
+ while (inf) {
+ inf->usage_cnt--; /* decrement usage count for buffers */
+ inf = inf->next;
+ }
+ restore_flags(flags);
+
+ if (pd)
+ if (pd->if_used <= 0) /* delete buffers if last file closed */
+ while (pd->log_head) {
+ inf = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(inf);
+ }
+ } /* read access */
+
+ MOD_DEC_USE_COUNT;
+ return (retval);
+} /* hysdn_log_close */
+
+/*************************************************/
+/* select/poll routine to be able using select() */
+/*************************************************/
+static unsigned int
+hysdn_log_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
+ word ino;
+ hysdn_card *card;
+ struct procdata *pd;
+
+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
+ return (mask); /* no polling for write supported */
+
+ /* we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card)
+ return (mask); /* card not found */
+
+ poll_wait(file, &(pd->rd_queue), wait);
+
+ if (*((struct log_data **) file->private_data))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+} /* hysdn_log_poll */
+
+/**************************************************/
+/* table for log filesystem functions defined above. */
+/**************************************************/
+static struct file_operations log_fops =
+{
+ hysdn_dummy_lseek,
+ hysdn_log_read,
+ hysdn_log_write,
+ NULL, /* readdir */
+ hysdn_log_poll, /* poll */
+ NULL, /*hysdn_log_ioctl, *//* ioctl */
+ NULL, /* mmap */
+ hysdn_log_open,
+ NULL, /* flush */
+ hysdn_log_close,
+ NULL /* fsync */
+};
+
+struct inode_operations log_inode_operations =
+{
+ &log_fops, /* log proc file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+/*****************************************/
+/* Output info data to the cardinfo file */
+/*****************************************/
+static int
+info_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+ char tmp[INFO_OUT_LEN * 11 + 2];
+ int i;
+ char *cp;
+ hysdn_card *card;
+
+ sprintf(tmp, "id bus slot type irq iobase plx-mem dp-mem boot device");
+ cp = tmp; /* start of string */
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+
+ card = card_root; /* start of list */
+ while (card) {
+ sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x 0x%08x",
+ card->myid,
+ card->bus,
+ PCI_SLOT(card->devfn),
+ card->brdtype,
+ card->irq,
+ card->iobase,
+ card->plxbase,
+ card->membase);
+ card = card->next;
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+ }
+
+ i = cp - tmp;
+ *start = buffer;
+ if (offset + length > i) {
+ length = i - offset;
+ *eof = 1;
+ } else if (offset > i) {
+ length = 0;
+ *eof = 1;
+ }
+ cp = tmp + offset;
+
+ if (length > 0) {
+ /* start_bh_atomic(); */
+ memcpy(buffer, cp, length);
+ /* end_bh_atomic(); */
+ return length;
+ }
+ return 0;
+} /* info_read */
+
+/*****************************/
+/* hysdn subdir in /proc/net */
+/*****************************/
+static struct proc_dir_entry *hysdn_proc_entry = NULL;
+static struct proc_dir_entry *hysdn_info_entry = NULL;
+
+/***************************************************************************************/
+/* hysdn_procfs_init is called when the module is loaded and after the cards have been */
+/* detected. The needed proc dir and card entries are created. */
+/***************************************************************************************/
+int
+hysdn_procfs_init(void)
+{
+ struct procdata *pd;
+ hysdn_card *card;
+
+ hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
+ if (!hysdn_proc_entry) {
+ printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
+ return (-1);
+ }
+ hysdn_info_entry = create_proc_entry("cardinfo", 0, hysdn_proc_entry);
+ if (hysdn_info_entry)
+ hysdn_info_entry->read_proc = info_read; /* read info function */
+
+ /* create all cardlog proc entries */
+
+ card = card_root; /* start with first card */
+ while (card) {
+ if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
+ memset(pd, 0, sizeof(struct procdata));
+
+ sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
+ if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
+ pd->log->ops = &log_inode_operations; /* set new operations table */
+
+ init_waitqueue_head(&(pd->rd_queue));
+
+ card->procfs = (void *) pd; /* remember procfs structure */
+ }
+ card = card->next; /* point to next card */
+ }
+
+ printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procfs_revision));
+ return (0);
+} /* hysdn_procfs_init */
+
+/***************************************************************************************/
+/* hysdn_procfs_release is called when the module is unloaded and before the cards */
+/* resources are released. The module counter is assumed to be 0 ! */
+/***************************************************************************************/
+void
+hysdn_procfs_release(void)
+{
+ struct procdata *pd;
+ hysdn_card *card;
+
+ card = card_root; /* start with first card */
+ while (card) {
+ if ((pd = (struct procdata *) card->procfs) != NULL) {
+ if (pd->log)
+ remove_proc_entry(pd->log_name, hysdn_proc_entry);
+ kfree(pd); /* release memory */
+ }
+ card = card->next; /* point to next card */
+ }
+
+ remove_proc_entry("cardinfo", hysdn_proc_entry);
+ remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+} /* hysdn_procfs_release */
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
new file mode 100644
index 000000000..aea6a96ad
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -0,0 +1,481 @@
+/* $Id: hysdn_proclog.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem log functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_proclog.c,v $
+ * Revision 1.2 2000/02/14 19:23:03 werner
+ *
+ * Changed handling of proc filesystem tables to a more portable version
+ *
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_proclog_revision = "$Revision: 1.2 $";
+
+/* the proc subdir for the interface is defined in the procconf module */
+extern struct proc_dir_entry *hysdn_proc_entry;
+
+/*************************************************/
+/* structure keeping ascii log for device output */
+/*************************************************/
+struct log_data {
+ struct log_data *next;
+ ulong usage_cnt; /* number of files still to work */
+ void *proc_ctrl; /* pointer to own control procdata structure */
+ char log_start[2]; /* log string start (final len aligned by size) */
+};
+
+/**********************************************/
+/* structure holding proc entrys for one card */
+/**********************************************/
+struct procdata {
+ struct proc_dir_entry *log; /* log entry */
+ char log_name[15]; /* log filename */
+ struct log_data *log_head, *log_tail; /* head and tail for queue */
+ int if_used; /* open count for interface */
+ int volatile del_lock; /* lock for delete operations */
+ uchar logtmp[LOG_MAX_LINELEN];
+ wait_queue_head_t rd_queue;
+};
+
+
+/**********************************************/
+/* log function for cards error log interface */
+/**********************************************/
+void
+hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
+{
+ char buf[ERRLOG_TEXT_SIZE + 40];
+
+ sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
+ put_log_buffer(card, buf); /* output the string */
+} /* hysdn_card_errlog */
+
+/***************************************************/
+/* Log function using format specifiers for output */
+/***************************************************/
+void
+hysdn_addlog(hysdn_card * card, char *fmt,...)
+{
+ struct procdata *pd = card->proclog;
+ char *cp;
+ va_list args;
+
+ if (!pd)
+ return; /* log structure non existent */
+
+ cp = pd->logtmp;
+ cp += sprintf(cp, "HYSDN: card %d ", card->myid);
+
+ va_start(args, fmt);
+ cp += vsprintf(cp, fmt, args);
+ va_end(args);
+ *cp++ = '\n';
+ *cp = 0;
+
+ if (card->debug_flags & DEB_OUT_SYSLOG)
+ printk(KERN_INFO "%s", pd->logtmp);
+ else
+ put_log_buffer(card, pd->logtmp);
+
+} /* hysdn_addlog */
+
+/********************************************/
+/* put an log buffer into the log queue. */
+/* This buffer will be kept until all files */
+/* opened for read got the contents. */
+/* Flushes buffers not longer in use. */
+/********************************************/
+void
+put_log_buffer(hysdn_card * card, char *cp)
+{
+ struct log_data *ib;
+ struct procdata *pd = card->proclog;
+ int i, flags;
+
+ if (!pd)
+ return;
+ if (!cp)
+ return;
+ if (!*cp)
+ return;
+ if (pd->if_used <= 0)
+ return; /* no open file for read */
+
+ if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
+ return; /* no memory */
+ strcpy(ib->log_start, cp); /* set output string */
+ ib->next = NULL;
+ ib->proc_ctrl = pd; /* point to own control structure */
+ save_flags(flags);
+ cli();
+ ib->usage_cnt = pd->if_used;
+ if (!pd->log_head)
+ pd->log_head = ib; /* new head */
+ else
+ pd->log_tail->next = ib; /* follows existing messages */
+ pd->log_tail = ib; /* new tail */
+ i = pd->del_lock++; /* get lock state */
+ restore_flags(flags);
+
+ /* delete old entrys */
+ if (!i)
+ while (pd->log_head->next) {
+ if ((pd->log_head->usage_cnt <= 0) &&
+ (pd->log_head->next->usage_cnt <= 0)) {
+ ib = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(ib);
+ } else
+ break;
+ } /* pd->log_head->next */
+ pd->del_lock--; /* release lock level */
+ wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
+} /* put_log_buffer */
+
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+ return -ESPIPE;
+} /* hysdn_dummy_lseek */
+
+/******************************/
+/* file operations and tables */
+/******************************/
+
+/****************************************/
+/* write log file -> set log level bits */
+/****************************************/
+static ssize_t
+hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+ ulong u = 0;
+ int found = 0;
+ uchar *cp, valbuf[128];
+ long base = 10;
+ hysdn_card *card = (hysdn_card *) file->private_data;
+
+ if (&file->f_pos != off) /* fs error check */
+ return (-ESPIPE);
+
+ if (count > (sizeof(valbuf) - 1))
+ count = sizeof(valbuf) - 1; /* limit length */
+ if (copy_from_user(valbuf, buf, count))
+ return (-EFAULT); /* copy failed */
+
+ valbuf[count] = 0; /* terminating 0 */
+ cp = valbuf;
+ if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
+ cp += 2; /* pointer after hex modifier */
+ base = 16;
+ }
+ /* scan the input for debug flags */
+ while (*cp) {
+ if ((*cp >= '0') && (*cp <= '9')) {
+ found = 1;
+ u *= base; /* adjust to next digit */
+ u += *cp++ - '0';
+ continue;
+ }
+ if (base != 16)
+ break; /* end of number */
+
+ if ((*cp >= 'a') && (*cp <= 'f')) {
+ found = 1;
+ u *= base; /* adjust to next digit */
+ u += *cp++ - 'a' + 10;
+ continue;
+ }
+ break; /* terminated */
+ }
+
+ if (found) {
+ card->debug_flags = u; /* remember debug flags */
+ hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
+ }
+ return (count);
+} /* hysdn_log_write */
+
+/******************/
+/* read log file */
+/******************/
+static ssize_t
+hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ struct log_data *inf;
+ int len;
+ word ino;
+ struct procdata *pd;
+ hysdn_card *card;
+
+ if (!*((struct log_data **) file->private_data)) {
+ if (file->f_flags & O_NONBLOCK)
+ return (-EAGAIN);
+
+ /* sorry, but we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ interruptible_sleep_on(&(pd->rd_queue));
+ else
+ return (-EAGAIN);
+
+ }
+ if (!(inf = *((struct log_data **) file->private_data)))
+ return (0);
+
+ inf->usage_cnt--; /* new usage count */
+ (struct log_data **) file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->log_start)) <= count) {
+ if (copy_to_user(buf, inf->log_start, len))
+ return -EFAULT;
+ file->f_pos += len;
+ return (len);
+ }
+ return (0);
+} /* hysdn_log_read */
+
+/******************/
+/* open log file */
+/******************/
+static int
+hysdn_log_open(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct procdata *pd;
+ ulong flags;
+
+ MOD_INC_USE_COUNT; /* lock module */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ filep->private_data = card; /* remember our own card */
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write log level only */
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+
+ /* read access -> log/debug read */
+ save_flags(flags);
+ cli();
+ pd->if_used++;
+ if (pd->log_head)
+ (struct log_data **) filep->private_data = &(pd->log_tail->next);
+ else
+ (struct log_data **) filep->private_data = &(pd->log_head);
+ restore_flags(flags);
+ } else { /* simultaneous read/write access forbidden ! */
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ return (0);
+} /* hysdn_log_open */
+
+/*******************************************************************************/
+/* close a cardlog file. If the file has been opened for exclusive write it is */
+/* assumed as pof data input and the pof loader is noticed about. */
+/* Otherwise file is handled as log output. In this case the interface usage */
+/* count is decremented and all buffers are noticed of closing. If this file */
+/* was the last one to be closed, all buffers are freed. */
+/*******************************************************************************/
+static int
+hysdn_log_close(struct inode *ino, struct file *filep)
+{
+ struct log_data *inf;
+ struct procdata *pd;
+ hysdn_card *card;
+ int flags, retval = 0;
+
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write debug level written */
+ retval = 0; /* success */
+ } else {
+ /* read access -> log/debug read, mark one further file as closed */
+
+ pd = NULL;
+ save_flags(flags);
+ cli();
+ inf = *((struct log_data **) filep->private_data); /* get first log entry */
+ if (inf)
+ pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
+ else {
+ /* no info available -> search card */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ pd = card->proclog; /* pointer to procfs log */
+ }
+ if (pd)
+ pd->if_used--; /* decrement interface usage count by one */
+
+ while (inf) {
+ inf->usage_cnt--; /* decrement usage count for buffers */
+ inf = inf->next;
+ }
+ restore_flags(flags);
+
+ if (pd)
+ if (pd->if_used <= 0) /* delete buffers if last file closed */
+ while (pd->log_head) {
+ inf = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(inf);
+ }
+ } /* read access */
+
+ MOD_DEC_USE_COUNT;
+ return (retval);
+} /* hysdn_log_close */
+
+/*************************************************/
+/* select/poll routine to be able using select() */
+/*************************************************/
+static unsigned int
+hysdn_log_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
+ word ino;
+ hysdn_card *card;
+ struct procdata *pd;
+
+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
+ return (mask); /* no polling for write supported */
+
+ /* we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card)
+ return (mask); /* card not found */
+
+ poll_wait(file, &(pd->rd_queue), wait);
+
+ if (*((struct log_data **) file->private_data))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+} /* hysdn_log_poll */
+
+/**************************************************/
+/* table for log filesystem functions defined above. */
+/**************************************************/
+static struct file_operations log_fops =
+{
+ hysdn_dummy_lseek,
+ hysdn_log_read,
+ hysdn_log_write,
+ NULL, /* readdir */
+ hysdn_log_poll, /* poll */
+ NULL,
+ NULL, /* mmap */
+ hysdn_log_open,
+ NULL, /* flush */
+ hysdn_log_close,
+ NULL /* fsync */
+};
+
+struct inode_operations log_inode_operations;
+
+/***********************************************************************************/
+/* hysdn_proclog_init is called when the module is loaded after creating the cards */
+/* conf files. */
+/***********************************************************************************/
+int
+hysdn_proclog_init(hysdn_card * card)
+{
+ struct procdata *pd;
+
+ /* create a cardlog proc entry */
+
+ if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
+ memset(pd, 0, sizeof(struct procdata));
+ memset(&log_inode_operations, 0, sizeof(struct inode_operations));
+ log_inode_operations.default_file_ops = &log_fops;
+
+ sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
+ if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
+ pd->log->ops = &log_inode_operations; /* set new operations table */
+
+ init_waitqueue_head(&(pd->rd_queue));
+
+ card->proclog = (void *) pd; /* remember procfs structure */
+ }
+ return (0);
+} /* hysdn_proclog_init */
+
+/************************************************************************************/
+/* hysdn_proclog_release is called when the module is unloaded and before the cards */
+/* conf file is released */
+/* The module counter is assumed to be 0 ! */
+/************************************************************************************/
+void
+hysdn_proclog_release(hysdn_card * card)
+{
+ struct procdata *pd;
+
+ if ((pd = (struct procdata *) card->proclog) != NULL) {
+ if (pd->log)
+ remove_proc_entry(pd->log_name, hysdn_proc_entry);
+ kfree(pd); /* release memory */
+ card->proclog = NULL;
+ }
+} /* hysdn_proclog_release */
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
new file mode 100644
index 000000000..0e5f9e7ba
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -0,0 +1,202 @@
+/* $Id: hysdn_sched.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hysdn_sched.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "hysdn_defs.h"
+
+/*****************************************************************************/
+/* hysdn_sched_rx is called from the cards handler to announce new data is */
+/* available from the card. The routine has to handle the data and return */
+/* with a nonzero code if the data could be worked (or even thrown away), if */
+/* no room to buffer the data is available a zero return tells the card */
+/* to keep the data until later. */
+/*****************************************************************************/
+int
+hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
+{
+
+ switch (chan) {
+ case CHAN_NDIS_DATA:
+ hysdn_rx_netpkt(card, buf, len); /* give packet to network handler */
+ break;
+
+ case CHAN_ERRLOG:
+ hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
+ if (card->err_log_state == ERRLOG_STATE_ON)
+ card->err_log_state = ERRLOG_STATE_START; /* start new fetch */
+ break;
+
+ default:
+ printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
+ break;
+
+ } /* switch rx channel */
+
+ return (1); /* always handled */
+} /* hysdn_sched_rx */
+
+/*****************************************************************************/
+/* hysdn_sched_tx is called from the cards handler to announce that there is */
+/* room in the tx-buffer to the card and data may be sent if needed. */
+/* If the routine wants to send data it must fill buf, len and chan with the */
+/* appropriate data and return a nonzero value. With a zero return no new */
+/* data to send is assumed. maxlen specifies the buffer size available for */
+/* sending. */
+/*****************************************************************************/
+int
+hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen)
+{
+ struct sk_buff *skb;
+
+ if (card->net_tx_busy) {
+ card->net_tx_busy = 0; /* reset flag */
+ hysdn_tx_netack(card); /* acknowledge packet send */
+ } /* a network packet has completely been transferred */
+ /* first of all async requests are handled */
+ if (card->async_busy) {
+ if (card->async_len <= maxlen) {
+ memcpy(buf, card->async_data, card->async_len);
+ *len = card->async_len;
+ *chan = card->async_channel;
+ card->async_busy = 0; /* reset request */
+ return (1);
+ }
+ card->async_busy = 0; /* in case of length error */
+ } /* async request */
+ if ((card->err_log_state == ERRLOG_STATE_START) &&
+ (maxlen >= ERRLOG_CMD_REQ_SIZE)) {
+ strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */
+ *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */
+ *chan = CHAN_ERRLOG; /* and channel */
+ card->err_log_state = ERRLOG_STATE_ON; /* new state is on */
+ return (1); /* tell that data should be send */
+ } /* error log start and able to send */
+ if ((card->err_log_state == ERRLOG_STATE_STOP) &&
+ (maxlen >= ERRLOG_CMD_STOP_SIZE)) {
+ strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */
+ *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */
+ *chan = CHAN_ERRLOG; /* and channel */
+ card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */
+ return (1); /* tell that data should be send */
+ } /* error log start and able to send */
+ /* now handle network interface packets */
+ if ((skb = hysdn_tx_netget(card)) != NULL) {
+ if (skb->len <= maxlen) {
+ memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */
+ *len = skb->len;
+ *chan = CHAN_NDIS_DATA;
+ card->net_tx_busy = 1; /* we are busy sending network data */
+ return (1); /* go and send the data */
+ } else
+ hysdn_tx_netack(card); /* aknowledge packet -> throw away */
+ } /* send a network packet if available */
+ return (0); /* nothing to send */
+} /* hysdn_sched_tx */
+
+
+/*****************************************************************************/
+/* send one config line to the card and return 0 if successfull, otherwise a */
+/* negative error code. */
+/* The function works with timeouts perhaps not giving the greatest speed */
+/* sending the line, but this should be meaningless beacuse only some lines */
+/* are to be sent and this happens very seldom. */
+/*****************************************************************************/
+int
+hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
+{
+ int cnt = 50; /* timeout intervalls */
+ ulong flags;
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
+
+ save_flags(flags);
+ cli();
+ while (card->async_busy) {
+ sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg delayed");
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (!--cnt) {
+ restore_flags(flags);
+ return (-ERR_ASYNC_TIME); /* timed out */
+ }
+ cli();
+ } /* wait for buffer to become free */
+
+ strcpy(card->async_data, line);
+ card->async_len = strlen(line) + 1;
+ card->async_channel = chan;
+ card->async_busy = 1; /* request transfer */
+
+ /* now queue the task */
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data queued");
+
+ cnt++; /* short delay */
+ cli();
+
+ while (card->async_busy) {
+ sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (!--cnt) {
+ restore_flags(flags);
+ return (-ERR_ASYNC_TIME); /* timed out */
+ }
+ cli();
+ } /* wait for buffer to become free again */
+
+ restore_flags(flags);
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data send");
+
+ return (0); /* line send correctly */
+} /* hysdn_tx_cfgline */
diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h
new file mode 100644
index 000000000..c22974d85
--- /dev/null
+++ b/drivers/isdn/hysdn/ince1pc.h
@@ -0,0 +1,132 @@
+#ifndef __INCE1PC_H__
+#define __INCE1PC_H__
+
+/****************************************************************************
+
+ FILE: ince1pc.h
+
+ AUTHOR: M.Steinkopf
+
+ PURPOSE: common definitions for both sides of the bus:
+ - conventions both spoolers must know
+ - channel numbers agreed upon
+
+*****************************************************************************/
+
+/* basic scalar definitions have same meanning,
+ * but their declaration location depends on environment
+ */
+
+/*--------------------------------------channel numbers---------------------*/
+#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
+#define CHAN_ERRLOG 0x0005 /* error logger */
+#define CHAN_CAPI 0x0064 /* CAPI interface */
+#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
+
+/*--------------------------------------POF ready msg-----------------------*/
+ /* NOTE: after booting POF sends system ready message to PC: */
+#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
+#define RDY_MAGIC_SIZE 4 /* size in bytes */
+
+#define MAX_N_TOK_BYTES 255
+
+#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
+#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+
+#define SYSR_TOK_END 0
+#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
+#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
+#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
+#define SYSR_TOK_ESC 255 /* undefined data size yet */
+ /* default values, if not corrected by token: */
+#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
+#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
+
+/* syntax of new SYSR token stream:
+ * channel: CHAN_SYSTEM
+ * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
+ * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+ * msg : 0 1 2 3 {4 5 6 ..}
+ * S Y S R MAX_N_TOK_BYTES bytes of TokenStream
+ *
+ * TokenStream := empty
+ * | {NonEndTokenChunk} EndToken RotlCRC
+ * NonEndTokenChunk:= NonEndTokenId DataLen [Data]
+ * NonEndTokenId := 0x01 .. 0xFE 1 BYTE
+ * DataLen := 0x00 .. 0xFF 1 BYTE
+ * Data := DataLen bytes
+ * EndToken := 0x00
+ * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
+ * s. RotlCRC algorithm
+ *
+ * RotlCRC algorithm:
+ * ucSum= 0 1 uchar
+ * for all NonEndTokenChunk bytes:
+ * ROTL(ucSum,1) rotate left by 1
+ * ucSum += Char; add current byte with swap around
+ * RotlCRC= ~ucSum; invert all bits for result
+ *
+ * note:
+ * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
+ */
+
+/*--------------------------------------error logger------------------------*/
+ /* note: pof needs final 0 ! */
+#define ERRLOG_CMD_REQ "ERRLOG ON"
+#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
+#define ERRLOG_CMD_STOP "ERRLOG OFF"
+#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
+
+#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
+ /* remaining text size = 55 */
+#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
+
+typedef struct ErrLogEntry_tag {
+
+/*00 */ ulong ulErrType;
+
+/*04 */ ulong ulErrSubtype;
+
+/*08 */ uchar ucTextSize;
+
+ /*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
+ /* ASCIIZ of len ucTextSize-1 */
+
+/*40 */
+} tErrLogEntry;
+
+
+#if defined(__TURBOC__)
+#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
+#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
+#endif /* */
+#endif /* */
+
+/*--------------------------------------DPRAM boot spooler------------------*/
+ /* this is the struture used between pc and
+ * hyperstone to exchange boot data
+ */
+#define DPRAM_SPOOLER_DATA_SIZE 0x20
+typedef struct DpramBootSpooler_tag {
+
+/*00 */ uchar Len;
+
+/*01 */ volatile uchar RdPtr;
+
+/*02 */ uchar WrPtr;
+
+/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
+
+/*23 */
+} tDpramBootSpooler;
+
+
+#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
+#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
+
+/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
+ /* at DPRAM offset 0x1C00: */
+#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
+
+
+#endif /* __INCE1PC_H__ */
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index 1626fa4e9..f1df11f55 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.93 1999/11/04 13:11:36 keil Exp $
+/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,32 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.97 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.96 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.95 2000/01/09 20:43:13 detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.94 1999/11/20 22:14:13 detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * to many connection's in short time.
+ * config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * or remote side.
+ * wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
* Revision 1.93 1999/11/04 13:11:36 keil
* Reinit of v110 structs
*
@@ -410,13 +436,14 @@
#endif CONFIG_ISDN_DIVERSION
#include "isdn_v110.h"
#include "isdn_cards.h"
+#include <linux/devfs_fs_kernel.h>
/* Debugflags */
#undef ISDN_DEBUG_STATCALLB
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.93 $";
+static char *isdn_revision = "$Revision: 1.97 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -438,6 +465,9 @@ isdn_divert_if *divert_if = NULL; /* interface to diversion module */
static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+static void set_global_features(void);
+static void isdn_register_devfs(int);
+static void isdn_unregister_devfs(int);
void
isdn_MOD_INC_USE_COUNT(void)
@@ -720,29 +750,33 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
int
isdn_command(isdn_ctrl *cmd)
{
+ if (cmd->driver == -1) {
+ printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
+ return(1);
+ }
if (cmd->command == ISDN_CMD_SETL2) {
- int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
- unsigned long l2prot = (cmd->arg >> 8) & 255;
- unsigned long features = (dev->drv[cmd->driver]->interface->features
- >> ISDN_FEATURE_L2_SHIFT) &
- ISDN_FEATURE_L2_MASK;
- unsigned long l2_feature = (1 << l2prot);
-
- switch (l2prot) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- /* If V.110 requested, but not supported by
- * HL-driver, set emulator-flag and change
- * Layer-2 to transparent
- */
- if (!(features & l2_feature)) {
- dev->v110emu[idx] = l2prot;
- cmd->arg = (cmd->arg & 255) |
- (ISDN_PROTO_L2_TRANS << 8);
- } else
- dev->v110emu[idx] = 0;
- }
+ int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
+ unsigned long l2prot = (cmd->arg >> 8) & 255;
+ unsigned long features = (dev->drv[cmd->driver]->interface->features
+ >> ISDN_FEATURE_L2_SHIFT) &
+ ISDN_FEATURE_L2_MASK;
+ unsigned long l2_feature = (1 << l2prot);
+
+ switch (l2prot) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ /* If V.110 requested, but not supported by
+ * HL-driver, set emulator-flag and change
+ * Layer-2 to transparent
+ */
+ if (!(features & l2_feature)) {
+ dev->v110emu[idx] = l2prot;
+ cmd->arg = (cmd->arg & 255) |
+ (ISDN_PROTO_L2_TRANS << 8);
+ } else
+ dev->v110emu[idx] = 0;
+ }
}
return dev->drv[cmd->driver]->interface->command(cmd);
}
@@ -822,6 +856,7 @@ isdn_status_callback(isdn_ctrl * c)
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (dev->drvmap[i] == di)
isdn_all_eaz(di, dev->chanmap[i]);
+ set_global_features();
break;
case ISDN_STAT_STOP:
dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
@@ -1065,6 +1100,7 @@ isdn_status_callback(isdn_ctrl * c)
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
dev->usage[i] &= ~ISDN_USAGE_DISABLED;
+ isdn_unregister_devfs(i);
}
dev->drivers--;
dev->channels -= dev->drv[di]->channels;
@@ -1078,6 +1114,7 @@ isdn_status_callback(isdn_ctrl * c)
dev->drv[di] = NULL;
dev->drvid[di][0] = '\0';
isdn_info_update();
+ set_global_features();
restore_flags(flags);
return 0;
case ISDN_STAT_L1ERR:
@@ -1563,6 +1600,9 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
* are serialized by means of a semaphore.
*/
switch (cmd) {
+ case IIOCNETDWRSET:
+ printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+ return(-EINVAL);
case IIOCNETLCR:
printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
return -ENODEV;
@@ -1854,7 +1894,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
for (i = 0; i < 10; i++) {
sprintf(bname, "%s%s",
strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "-",
+ dev->drv[drvidx]->msn2eaz[i] : "_",
(i < 9) ? "," : "\0");
if (copy_to_user(p, bname, strlen(bname) + 1))
return -EFAULT;
@@ -2024,13 +2064,17 @@ isdn_close(struct inode *ino, struct file *filep)
static struct file_operations isdn_fops =
{
- llseek: isdn_lseek,
- read: isdn_read,
- write: isdn_write,
- poll: isdn_poll,
- ioctl: isdn_ioctl,
- open: isdn_open,
- release: isdn_close,
+ isdn_lseek,
+ isdn_read,
+ isdn_write,
+ NULL, /* isdn_readdir */
+ isdn_poll, /* isdn_poll */
+ isdn_ioctl, /* isdn_ioctl */
+ NULL, /* isdn_mmap */
+ isdn_open,
+ NULL, /* flush */
+ isdn_close,
+ NULL /* fsync */
};
char *
@@ -2056,7 +2100,7 @@ isdn_map_eaz2msn(char *msn, int di)
int
isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
- ,int pre_chan)
+ ,int pre_chan, char *msn)
{
int i;
ulong flags;
@@ -2079,6 +2123,8 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
((pre_dev != d) || (pre_chan != dev->chanmap[i])))
continue;
+ if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
+ continue;
if (dev->usage[i] & ISDN_USAGE_DISABLED)
continue; /* usage not allowed */
if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
@@ -2349,6 +2395,7 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
if (dev->chanmap[k] < 0) {
dev->chanmap[k] = j;
dev->drvmap[k] = drvidx;
+ isdn_register_devfs(k);
break;
}
restore_flags(flags);
@@ -2360,6 +2407,19 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
* Low-level-driver registration
*/
+static void
+set_global_features(void)
+{
+ int drvidx;
+
+ dev->global_features = 0;
+ for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
+ if (!dev->drv[drvidx])
+ continue;
+ if (dev->drv[drvidx]->interface)
+ dev->global_features |= dev->drv[drvidx]->interface->features;
+ }
+}
#ifdef CONFIG_ISDN_DIVERSION
extern isdn_divert_if *divert_if;
@@ -2473,6 +2533,7 @@ register_isdn(isdn_if * i)
strcpy(dev->drvid[drvidx], i->id);
isdn_info_update();
dev->drivers++;
+ set_global_features();
restore_flags(flags);
return 1;
}
@@ -2504,6 +2565,96 @@ isdn_getrev(const char *revision)
return rev;
}
+#ifdef CONFIG_DEVFS_FS
+
+static devfs_handle_t devfs_handle = NULL;
+
+static void isdn_register_devfs(int k)
+{
+ char buf[11];
+
+ sprintf (buf, "isdn%d", k);
+ dev->devfs_handle_isdnX[k] =
+ devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR, 0, 0,
+ &isdn_fops, NULL);
+ sprintf (buf, "isdnctrl%d", k);
+ dev->devfs_handle_isdnctrlX[k] =
+ devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_CTRL + k, 0600 | S_IFCHR,
+ 0, 0, &isdn_fops, NULL);
+}
+
+static void isdn_unregister_devfs(int k)
+{
+ devfs_unregister (dev->devfs_handle_isdnX[k]);
+ devfs_unregister (dev->devfs_handle_isdnctrlX[k]);
+}
+
+static void isdn_init_devfs(void)
+{
+# ifdef CONFIG_ISDN_PPP
+ int i;
+# endif
+
+ devfs_handle = devfs_mk_dir (NULL, "isdn", 4, NULL);
+# ifdef CONFIG_ISDN_PPP
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ char buf[8];
+
+ sprintf (buf, "ippp%d", i);
+ dev->devfs_handle_ipppX[i] =
+ devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_PPP + i,
+ 0600 | S_IFCHR, 0, 0, &isdn_fops, NULL);
+ }
+# endif
+
+ dev->devfs_handle_isdninfo =
+ devfs_register (devfs_handle, "isdninfo", 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_STATUS, 0600 | S_IFCHR,
+ 0, 0, &isdn_fops, NULL);
+ dev->devfs_handle_isdnctrl =
+ devfs_register (devfs_handle, "isdnctrl", 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, 0, 0,
+ &isdn_fops, NULL);
+}
+
+static void isdn_cleanup_devfs(void)
+{
+# ifdef CONFIG_ISDN_PPP
+ int i;
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ devfs_unregister (dev->devfs_handle_ipppX[i]);
+# endif
+ devfs_unregister (dev->devfs_handle_isdninfo);
+ devfs_unregister (dev->devfs_handle_isdnctrl);
+ devfs_unregister (devfs_handle);
+}
+
+#else /* CONFIG_DEVFS_FS */
+static void isdn_register_devfs(int dummy)
+{
+ return;
+}
+
+static void isdn_unregister_devfs(int dummy)
+{
+ return;
+}
+
+static void isdn_init_devfs(void)
+{
+ return;
+}
+
+static void isdn_cleanup_devfs(void)
+{
+ return;
+}
+
+#endif /* CONFIG_DEVFS_FS */
+
/*
* Allocate and initialize all data, register modem-devices
*/
@@ -2530,11 +2681,12 @@ isdn_init(void)
init_waitqueue_head(&dev->mdm.info[i].open_wait);
init_waitqueue_head(&dev->mdm.info[i].close_wait);
}
- if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
+ if (devfs_register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
printk(KERN_WARNING "isdn: Could not register control devices\n");
vfree(dev);
return -EIO;
}
+ isdn_init_devfs();
if ((i = isdn_tty_modem_init()) < 0) {
printk(KERN_WARNING "isdn: Could not register tty devices\n");
if (i == -3)
@@ -2542,7 +2694,8 @@ isdn_init(void)
if (i <= -2)
tty_unregister_driver(&dev->mdm.tty_modem);
vfree(dev);
- unregister_chrdev(ISDN_MAJOR, "isdn");
+ isdn_cleanup_devfs();
+ devfs_unregister_chrdev(ISDN_MAJOR, "isdn");
return -EIO;
}
#ifdef CONFIG_ISDN_PPP
@@ -2552,7 +2705,8 @@ isdn_init(void)
tty_unregister_driver(&dev->mdm.cua_modem);
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
kfree(dev->mdm.info[i].xmit_buf - 4);
- unregister_chrdev(ISDN_MAJOR, "isdn");
+ isdn_cleanup_devfs();
+ devfs_unregister_chrdev(ISDN_MAJOR, "isdn");
vfree(dev);
return -EIO;
}
@@ -2618,9 +2772,10 @@ cleanup_module(void)
kfree(dev->mdm.info[i].fax);
#endif
}
- if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
+ if (devfs_unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
} else {
+ isdn_cleanup_devfs();
del_timer(&dev->timer);
vfree(dev);
printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h
index 3c60d7c80..c45dd5202 100644
--- a/drivers/isdn/isdn_common.h
+++ b/drivers/isdn/isdn_common.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.17 1999/10/27 21:21:17 detabc Exp $
+/* $Id: isdn_common.h,v 1.18 2000/01/23 18:45:37 keil Exp $
* header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
*
@@ -21,6 +21,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.h,v $
+ * Revision 1.18 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
* Revision 1.17 1999/10/27 21:21:17 detabc
* Added support for building logically-bind-group's per interface.
* usefull for outgoing call's with more then one isdn-card.
@@ -128,7 +131,7 @@ extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **);
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
-extern int isdn_get_free_channel(int, int, int, int, int);
+extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
extern int isdn_wildmat(char *, char *);
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index e1c7cb75d..592d20ed9 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.95 1999/10/27 21:21:17 detabc Exp $
+/* $Id: isdn_net.c,v 1.107 2000/02/13 09:52:05 kai Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,66 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.107 2000/02/13 09:52:05 kai
+ * increased TX_TIMEOUT to 20sec
+ *
+ * Revision 1.106 2000/02/12 19:26:55 kai
+ * adopted to latest 2.3 softnet changes.
+ *
+ * tested with PPP and MPPP, it works here.
+ * can somebody check raw-ip?
+ *
+ * also changed std2kern, stddiff for bash-1 compatibility,
+ * hope this doesn't break anything.
+ *
+ * Revision 1.105 2000/02/12 11:43:26 he
+ * SOFTNET related changes, first try. Compatible with linux 2.2.x, but
+ * not tested for kernels with softnet (>= 2.3.43) yet.
+ *
+ * Revision 1.104 2000/02/06 21:49:59 detabc
+ * add rewriting of socket's and frame's saddr for udp-ipv4 dynip-connections.
+ * Include checksum-recompute of ip- and udp-header's.
+ *
+ * Revision 1.103 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.102 2000/01/09 20:43:14 detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.101 1999/12/05 16:06:08 detabc
+ * add resethandling for rawip-compression.
+ * at now all B2-Protocols are usable with rawip-compression
+ *
+ * Revision 1.100 1999/12/04 15:05:25 detabc
+ * bugfix abc-rawip-bsdcompress with channel-bundeling
+ *
+ * Revision 1.99 1999/11/30 11:29:06 detabc
+ * add a on the fly frame-counter and limit
+ *
+ * Revision 1.98 1999/11/28 14:49:07 detabc
+ * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the
+ * uncompressed size.
+ *
+ * Revision 1.97 1999/11/26 15:54:59 detabc
+ * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol.
+ *
+ * Revision 1.96 1999/11/20 22:14:13 detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * to many connection's in short time.
+ * config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * or remote side.
+ * wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
* Revision 1.95 1999/10/27 21:21:17 detabc
* Added support for building logically-bind-group's per interface.
* usefull for outgoing call's with more then one isdn-card.
@@ -393,10 +453,6 @@
#endif
-#ifndef ISDN_NEW_TBUSY
-#define ISDN_NEW_TBUSY
-#endif
-#ifdef ISDN_NEW_TBUSY
/*
* Outline of new tbusy handling:
*
@@ -413,29 +469,60 @@
*/
/*
- * Tell upper layers that the network device is ready to xmit more frames.
+ * About SOFTNET:
+ * Most of the changes were pretty obvious and basically done by HE already.
+ *
+ * One problem of the isdn net device code is that is uses struct net_device
+ * for masters and slaves. However, only master interface are registered to
+ * the network layer, and therefore, it only makes sense to call netif_*
+ * functions on them.
+ *
+ * The old code abused the slaves dev->start to remember the corresponding
+ * master's interface state (ifup'ed or not). This does not work with SOFTNET
+ * any more, because there's now dev->start anymore.
+ * Instead I chose to add isdn_net_started() which gives the state of the
+ * master in case of slaves.
+ * I'm still not sure if this is how it's supposed to be done this way
+ * because it uses netif_running(dev) which might be
+ * considered private to the network layer. However, it works for now.
+ * Alternative: set a flag in _open() and clear it in _close()
+ *
+ * I left some dead code around in #if 0 which I'm not absolutely sure about.
+ * If no problems turn up, it should be removed later
+ *
+ * --KG
*/
-static void __inline__ isdn_net_dev_xon(struct net_device * dev)
-{
- dev->tbusy = 0;
- mark_bh(NET_BH);
-}
-static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+/*
+ * Find out if the netdevice has been ifup-ed yet.
+ * For slaves, look at the corresponding master.
+ */
+static int __inline__ isdn_net_started(isdn_net_dev *n)
{
- lp->netdev->dev.tbusy = 0;
- if(lp->master) lp->master->tbusy = 0;
- mark_bh(NET_BH);
+ isdn_net_local *lp = n->local;
+ struct net_device *dev;
+
+ if (lp->master)
+ dev = lp->master;
+ else
+ dev = &n->dev;
+ return netif_running(dev);
}
/*
- * Ask upper layers to temporarily cease passing us more xmit frames.
+ * wake up the network -> net_device queue.
+ * For slaves, wake the corresponding master interface.
*/
-static void __inline__ isdn_net_dev_xoff(struct net_device * dev)
+static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
{
- dev->tbusy = 1;
+ if (lp->master)
+ netif_wake_queue(lp->master);
+ else
+ netif_wake_queue(&lp->netdev->dev);
}
-#endif
+
+
+#define ISDN_NET_TX_TIMEOUT (20*HZ)
/* Prototypes */
@@ -443,7 +530,7 @@ int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *);
-char *isdn_net_revision = "$Revision: 1.95 $";
+char *isdn_net_revision = "$Revision: 1.107 $";
/*
* Code for raw-networking over ISDN
@@ -482,14 +569,9 @@ isdn_net_reset(struct net_device *dev)
#endif
ulong flags;
+ /* not sure if the cli() is needed at all --KG */
save_flags(flags);
cli(); /* Avoid glitch on writes to CMD regs */
- dev->interrupt = 0;
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xon(dev);
-#else
- dev->tbusy = 0;
-#endif
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops && dops )
cprot -> pops -> restart ( cprot, dev, dops );
@@ -505,8 +587,12 @@ isdn_net_open(struct net_device *dev)
struct net_device *p;
struct in_device *in_dev;
+ /* moved here from isdn_net_reset, because only the master has an
+ interface associated which is supposed to be started. BTW:
+ we need to call netif_start_queue, not netif_wake_queue here */
+ netif_start_queue(dev);
+
isdn_net_reset(dev);
- dev->start = 1;
/* Fill in the MAC-level header (not needed, but for compatibility... */
for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
dev->dev_addr[i] = 0xfc;
@@ -524,7 +610,6 @@ isdn_net_open(struct net_device *dev)
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
while (p) {
isdn_net_reset(p);
- p->start = 1;
p = (((isdn_net_local *) p->priv)->slave);
}
}
@@ -703,19 +788,11 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
mdev = &lp->netdev->dev;
if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
lp->sav_skb = NULL;
-#ifndef ISDN_NEW_TBUSY
- mark_bh(NET_BH);
-#endif
} else {
return 1;
}
}
-#ifdef ISDN_NEW_TBUSY
isdn_net_lp_xon(lp);
-#else
- if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
- mark_bh(NET_BH);
-#endif
}
return 1;
case ISDN_STAT_DCONN:
@@ -814,18 +891,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
lp->first_skb = NULL;
}
-#ifdef ISDN_NEW_TBUSY
if(! lp->first_skb) isdn_net_lp_xon(lp);
-#else
- else {
- /*
- * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb).
- * With an empty lp->first_skb, we need to do this ourselves
- */
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH);
- }
-#endif /* ISDN_NEW_TBUSY */
return 1;
}
break;
@@ -1259,14 +1325,16 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
strcpy(addinfo, " IDP");
break;
}
- printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
+ printk(KERN_INFO
+ "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
p[12], p[13], p[14], p[15],
p[16], p[17], p[18], p[19],
addinfo);
break;
case ETH_P_ARP:
- printk(KERN_INFO "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
+ printk(KERN_INFO
+ "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
p[14], p[15], p[16], p[17],
p[24], p[25], p[26], p[27]);
break;
@@ -1280,14 +1348,8 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
*
* Return: 0 on success, !0 on failure.
*/
-#ifndef ISDN_NEW_TBUSY
-/*
- * Side-effects: ndev->tbusy is cleared on success.
- */
-#endif
-int
-isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp,
- struct sk_buff *skb)
+int isdn_net_send_skb
+ (struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb)
{
int ret;
int len = skb->len; /* save len */
@@ -1295,17 +1357,11 @@ isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp,
ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
if (ret == len) {
lp->transcount += len;
-#ifndef ISDN_NEW_TBUSY
- clear_bit(0, (void *) &(ndev->tbusy));
-#endif
return 0;
}
if (ret < 0) {
dev_kfree_skb(skb);
lp->stats.tx_errors++;
-#ifndef ISDN_NEW_TBUSY
- clear_bit(0, (void *) &(ndev->tbusy));
-#endif
return 0;
}
return 1;
@@ -1351,11 +1407,7 @@ isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
if (lp->srobin == ndev)
ret = isdn_net_send_skb(ndev, lp, skb);
else
-#ifdef ISDN_NEW_TBUSY
ret = isdn_net_start_xmit(skb, lp->srobin);
-#else
- ret = ndev->tbusy = isdn_net_start_xmit(skb, lp->srobin);
-#endif
lp->srobin = (slp->slave) ? slp->slave : ndev;
slp = (isdn_net_local *) (lp->srobin->priv);
if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
@@ -1397,6 +1449,35 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
}
}
+
+void isdn_net_tx_timeout(struct net_device * ndev)
+{
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+
+ printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
+ if (!lp->dialstate){
+ lp->stats.tx_errors++;
+ /*
+ * There is a certain probability that this currently
+ * works at all because if we always wake up the interface,
+ * then upper layer will try to send the next packet
+ * immediately. And then, the old clean_up logic in the
+ * driver will hopefully continue to work as it used to do.
+ *
+ * This is rather primitive right know, we better should
+ * clean internal queues here, in particular for multilink and
+ * ppp, and reset HL driver's channel, too. --HE
+ *
+ * actually, this may not matter at all, because ISDN hardware
+ * should not see transmitter hangs at all IMO
+ * changed KERN_DEBUG to KERN_WARNING to find out if this is
+ * ever called
+ */
+ }
+ ndev->trans_start = jiffies;
+ netif_wake_queue(ndev);
+}
+
/*
* Try sending a packet.
* If this interface isn't connected to a ISDN-Channel, find a free channel,
@@ -1409,19 +1490,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = lp -> netdev -> cprot;
#endif
- if (ndev->tbusy) {
- if (jiffies - ndev->trans_start < (2 * HZ))
- return 1;
- if (!lp->dialstate)
- lp->stats.tx_errors++;
- ndev->trans_start = jiffies;
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xon(ndev);
-#endif
- }
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
-#endif
#ifdef CONFIG_ISDN_X25
/* At this point hard_start_xmit() passes control to the encapsulation
protocol (if present).
@@ -1436,9 +1504,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
if( cprot ) {
int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
-#ifdef ISDN_NEW_TBUSY
- if(ret) isdn_net_dev_xoff(ndev);
-#endif
+ if(ret) netif_stop_queue(ndev);
return ret;
} else
#endif
@@ -1458,9 +1524,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
if (lp->phone[1]) {
@@ -1476,15 +1539,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if(jiffies < lp->dialwait_timer) {
isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
restore_flags(flags);
return 0;
} else
lp->dialwait_timer = 0;
}
-
/* Grab a free ISDN-Channel */
if (((chi =
isdn_get_free_channel(
@@ -1492,7 +1551,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) &&
((chi =
isdn_get_free_channel(
@@ -1500,15 +1560,13 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel^1)
+ lp->pre_channel^1,
+ lp->msn)
) < 0)) {
restore_flags(flags);
isdn_net_unreachable(ndev, skb,
"No channel");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
/* Log packet, which triggered dialing */
@@ -1528,9 +1586,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
restore_flags(flags);
isdn_net_dial(); /* Initiate dialing */
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#endif
+ netif_stop_queue(ndev);
return 1; /* let upper layer requeue skb packet */
}
#endif
@@ -1544,9 +1600,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
lp->first_skb = skb;
/* Initiate dialing */
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
restore_flags(flags);
isdn_net_dial();
return 0;
@@ -1554,9 +1607,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_unreachable(ndev, skb,
"No phone number");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
} else {
@@ -1567,24 +1617,16 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
int ret;
if (lp->first_skb) {
if (isdn_net_xmit(ndev, lp, lp->first_skb)){
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#endif
+ netif_stop_queue(ndev);
return 1;
}
lp->first_skb = NULL;
}
ret = (isdn_net_xmit(ndev, lp, skb));
-#ifdef ISDN_NEW_TBUSY
- if(ret) isdn_net_dev_xoff(ndev);
-#endif
+ if(ret) netif_stop_queue(ndev);
return ret;
} else
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#else
- ndev->tbusy = 1;
-#endif
+ netif_stop_queue(ndev);
}
}
return 1;
@@ -1606,8 +1648,7 @@ isdn_net_close(struct net_device *dev)
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
#endif
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
/* If this interface has slaves, stop them also */
while (p) {
@@ -1618,8 +1659,6 @@ isdn_net_close(struct net_device *dev)
cprot -> pops -> close( cprot );
#endif
isdn_net_hangup(p);
- p->tbusy = 1;
- p->start = 0;
p = (((isdn_net_local *) p->priv)->slave);
}
}
@@ -2360,7 +2399,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
* Is the interface up?
* If not, reject the call actively.
*/
- if (!p->dev.start) {
+ if (!isdn_net_started(p)) {
restore_flags(flags);
printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
lp->name);
@@ -2389,7 +2428,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
p = (isdn_net_dev *) p->next;
continue;
}
- }
+ }
if (lp->flags & ISDN_NET_CALLBACK) {
int chi;
/*
@@ -2411,9 +2450,10 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
isdn_get_free_channel(
ISDN_USAGE_NET,
lp->l2_proto,
- lp->l3_proto,
+ lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) {
printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
@@ -2528,7 +2568,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) {
printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
restore_flags(flags);
@@ -2626,11 +2667,13 @@ isdn_net_new(char *name, struct net_device *master)
p = (((isdn_net_local *) p->priv)->slave);
}
((isdn_net_local *) q->priv)->slave = &(netdev->dev);
- q->interrupt = 0;
- q->tbusy = 0;
- q->start = master->start;
} else {
/* Device shall be a master */
+ /*
+ * Watchdog timer (currently) for master only.
+ */
+ netdev->dev.tx_timeout = isdn_net_tx_timeout;
+ netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
if (register_netdev(&netdev->dev) != 0) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
kfree(netdev->local);
@@ -2701,7 +2744,7 @@ isdn_net_newslave(char *parm)
if (n->local->master)
return NULL;
/* Master must not be started yet */
- if (n->dev.start)
+ if (isdn_net_started(n))
return NULL;
return (isdn_net_new(newname, &(n->dev)));
}
@@ -2744,9 +2787,8 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = p -> cprot;
#endif
- if (p->dev.start) {
- printk(KERN_WARNING
- "%s: cannot change encap when if is up\n",
+ if (isdn_net_started(p)) {
+ printk(KERN_WARNING "%s: cannot change encap when if is up\n",
lp->name);
return -EBUSY;
}
@@ -2837,10 +2879,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
/* If binding is exclusive, try to grab the channel */
save_flags(flags);
- if ((i = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
- lp->l3_proto,
- drvidx,
- chidx)) < 0) {
+ if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
+ lp->l2_proto, lp->l3_proto, drvidx,
+ chidx, lp->msn)) < 0) {
/* Grab failed, because desired channel is in use */
lp->exclusive = -1;
restore_flags(flags);
@@ -3181,14 +3222,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
save_flags(flags);
cli();
- if (p->local->master) {
- /* If it's a slave, it may be removed even if it is busy. However
- * it has to be hung up first.
- */
- isdn_net_hangup(&p->dev);
- p->dev.start = 0;
- }
- if (p->dev.start) {
+ if (isdn_net_started(p)) {
restore_flags(flags);
return -EBUSY;
}
diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c
index 06c2d83ad..2551dc344 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.60 1999/11/04 20:29:55 he Exp $
+/* $Id: isdn_ppp.c,v 1.62 2000/02/12 19:26:55 kai Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,31 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.62 2000/02/12 19:26:55 kai
+ * adopted to latest 2.3 softnet changes.
+ *
+ * tested with PPP and MPPP, it works here.
+ * can somebody check raw-ip?
+ *
+ * also changed std2kern, stddiff for bash-1 compatibility,
+ * hope this doesn't break anything.
+ *
+ * Revision 1.61 1999/11/20 22:14:14 detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * to many connection's in short time.
+ * config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * or remote side.
+ * wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
* Revision 1.60 1999/11/04 20:29:55 he
* applied Andre Beck's reset_free fix
*
@@ -306,7 +331,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
static void isdn_ppp_free_mpqueue(isdn_net_dev *);
#endif
-char *isdn_ppp_revision = "$Revision: 1.60 $";
+char *isdn_ppp_revision = "$Revision: 1.62 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
@@ -699,7 +724,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCGIFNAME:
if(!lp)
return -EINVAL;
- if ((r = set_arg((void *) arg, lp->name,strlen(lp->name))))
+ if ((r = set_arg((void *) arg, lp->name, strlen(lp->name))))
return r;
break;
case PPPIOCGMPFLAGS: /* get configuration flags */
@@ -721,8 +746,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
}
if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
if (lp) {
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+ /* OK .. we are ready to send buffers */
+ netif_wake_queue(&lp->netdev->dev);
}
}
is->pppcfg = val;
diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c
index 5b301adb9..0503c67a2 100644
--- a/drivers/isdn/isdn_tty.c
+++ b/drivers/isdn/isdn_tty.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.80 1999/11/07 13:34:30 armin Exp $
+/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
@@ -20,6 +20,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.82 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.81 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
* Revision 1.80 1999/11/07 13:34:30 armin
* Fixed AT command line editor
*
@@ -348,6 +354,7 @@
#endif
#define FIX_FILE_TRANSFER
+#define DUMMY_HAYES_AT
/* Prototypes */
@@ -372,7 +379,7 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.80 $";
+char *isdn_tty_revision = "$Revision: 1.82 $";
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -976,7 +983,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(6, info);
@@ -1187,7 +1194,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(6, info);
@@ -1281,7 +1288,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(6, info);
@@ -1555,6 +1562,23 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
}
}
} else
+ if (TTY_IS_FCLASS1(info)) {
+ int cc = isdn_tty_handleDLEdown(info, m, c);
+
+ if (info->vonline & 4) { /* ETX seen */
+ isdn_ctrl c;
+
+ c.command = ISDN_CMD_FAXCMD;
+ c.driver = info->isdn_driver;
+ c.arg = info->isdn_channel;
+ c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
+ c.parm.aux.subcmd = ETX;
+ isdn_command(&c);
+ }
+ info->vonline = 0;
+ printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c);
+ info->xmit_count += cc;
+ } else
#endif
info->xmit_count += c;
} else {
@@ -2567,7 +2591,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
int
-isdn_tty_stat_callback(int i, isdn_ctrl * c)
+isdn_tty_stat_callback(int i, isdn_ctrl *c)
{
int mi;
modem_info *info;
@@ -2668,8 +2692,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
strcpy(info->emu.connmsg, c->parm.num);
isdn_tty_modem_result(1, info);
- }
- else
+ } else
isdn_tty_modem_result(5, info);
}
if (USG_VOICE(dev->usage[i]))
@@ -2720,7 +2743,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
#ifdef CONFIG_ISDN_TTY_FAX
case ISDN_STAT_FAXIND:
if (TTY_IS_ACTIVE(info)) {
- isdn_tty_fax_command(info);
+ isdn_tty_fax_command(info, c);
}
break;
#endif
@@ -3247,8 +3270,22 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
info->xmit_size /= 10;
}
break;
+ case 'C':
+ /* &C - DCD Status */
+ p[0]++;
+ switch (isdn_getnum(p)) {
+ case 0:
+ m->mdmreg[REG_DCD] &= ~BIT_DCD;
+ break;
+ case 1:
+ m->mdmreg[REG_DCD] |= BIT_DCD;
+ break;
+ default:
+ PARSE_ERROR1
+ }
+ break;
case 'D':
- /* &D - Set DCD-Low-behavior */
+ /* &D - Set DTR-Low-behavior */
p[0]++;
switch (isdn_getnum(p)) {
case 0:
@@ -3280,6 +3317,14 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
isdn_tty_reset_profile(m);
isdn_tty_modem_reset_regs(info, 1);
break;
+#ifdef DUMMY_HAYES_AT
+ case 'K':
+ /* only for be compilant with common scripts */
+ /* &K Flowcontrol - no function */
+ p[0]++;
+ isdn_getnum(p);
+ break;
+#endif
case 'L':
/* &L -Set Numbers to listen on */
p[0]++;
@@ -3565,8 +3610,10 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
sprintf(rs, "\r\n%d",
(m->mdmreg[REG_SI1] & 1) ? 8 : 0);
#ifdef CONFIG_ISDN_TTY_FAX
- if (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX)
- sprintf(rs, "\r\n2");
+ if (TTY_IS_FCLASS2(info))
+ sprintf(rs, "\r\n2");
+ else if (TTY_IS_FCLASS1(info))
+ sprintf(rs, "\r\n1");
#endif
isdn_tty_at_cout(rs, info);
break;
@@ -3582,11 +3629,25 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
m->mdmreg[REG_PSIZE] * 16;
break;
#ifdef CONFIG_ISDN_TTY_FAX
+ case '1':
+ p[0]++;
+ if (!(dev->global_features &
+ ISDN_FEATURE_L3_FCLASS1))
+ PARSE_ERROR1;
+ m->mdmreg[REG_SI1] = 1;
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
+ m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
+ info->xmit_size =
+ m->mdmreg[REG_PSIZE] * 16;
+ break;
case '2':
p[0]++;
+ if (!(dev->global_features &
+ ISDN_FEATURE_L3_FCLASS2))
+ PARSE_ERROR1;
m->mdmreg[REG_SI1] = 1;
m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FAX;
+ m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
info->xmit_size =
m->mdmreg[REG_PSIZE] * 16;
break;
@@ -3601,11 +3662,17 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
break;
case '?':
p[0]++;
+ strcpy(rs, "\r\n0,");
#ifdef CONFIG_ISDN_TTY_FAX
- isdn_tty_at_cout("\r\n0,2,8", info);
-#else
- isdn_tty_at_cout("\r\n0,8", info);
+ if (dev->global_features &
+ ISDN_FEATURE_L3_FCLASS1)
+ strcat(rs, "1,");
+ if (dev->global_features &
+ ISDN_FEATURE_L3_FCLASS2)
+ strcat(rs, "2,");
#endif
+ strcat(rs, "8");
+ isdn_tty_at_cout(rs, info);
break;
default:
PARSE_ERROR1;
@@ -3995,6 +4062,15 @@ isdn_tty_parse_at(modem_info * info)
default:
}
break;
+#ifdef DUMMY_HAYES_AT
+ case 'L':
+ case 'M':
+ /* only for be compilant with common scripts */
+ /* no function */
+ p++;
+ isdn_getnum(&p);
+ break;
+#endif
case 'O':
/* O - Go online */
p++;
diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h
index 1c27b8300..ff7e479f0 100644
--- a/drivers/isdn/isdn_tty.h
+++ b/drivers/isdn/isdn_tty.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.17 1999/09/21 19:00:35 armin Exp $
+/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $
* header for Linux ISDN subsystem, tty related functions (linklevel).
*
@@ -20,6 +20,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.h,v $
+ * Revision 1.18 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
* Revision 1.17 1999/09/21 19:00:35 armin
* Extended FCON message with added CPN
* can now be activated with Bit 1 of Reg 23.
@@ -160,6 +163,13 @@
#define BIT_CPN 1
#define BIT_CPNFCON 2
+#define TTY_IS_FCLASS1(info) \
+ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
+#define TTY_IS_FCLASS2(info) \
+ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
+
extern void isdn_tty_modem_escape(void);
extern void isdn_tty_modem_ring(void);
extern void isdn_tty_carrier_timeout(void);
@@ -175,6 +185,6 @@ extern void isdn_tty_at_cout(char *, modem_info *);
extern void isdn_tty_modem_hup(modem_info *, int);
#ifdef CONFIG_ISDN_TTY_FAX
extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
-extern int isdn_tty_fax_command(modem_info *);
+extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
#endif
diff --git a/drivers/isdn/isdn_ttyfax.c b/drivers/isdn/isdn_ttyfax.c
index 9b7268b32..33f67ff4b 100644
--- a/drivers/isdn/isdn_ttyfax.c
+++ b/drivers/isdn/isdn_ttyfax.c
@@ -1,9 +1,9 @@
-/* $Id: isdn_ttyfax.c,v 1.4 1999/09/21 19:00:35 armin Exp $
+/* $Id: isdn_ttyfax.c,v 1.6 2000/01/26 00:41:13 keil Exp $
* Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
*
* Copyright 1999 by Armin Schindler (mac@melware.de)
* Copyright 1999 by Ralf Spachmann (mel@melware.de)
- * Copyright 1999 by Cytronics & Melware
+ * Copyright 1999 by Cytronics & Melware
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ttyfax.c,v $
+ * Revision 1.6 2000/01/26 00:41:13 keil
+ * add "00" as dummy msn in isdn_get_free_channel call
+ *
+ * Revision 1.5 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
* Revision 1.4 1999/09/21 19:00:35 armin
* Extended FCON message with added CPN
* can now be activated with Bit 1 of Reg 23.
@@ -50,31 +56,32 @@
#include "isdn_ttyfax.h"
-static char *isdn_tty_fax_revision = "$Revision: 1.4 $";
+static char *isdn_tty_fax_revision = "$Revision: 1.6 $";
#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
static char *
isdn_getrev(const char *revision)
{
- char *rev;
- char *p;
+ char *rev;
+ char *p;
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
+ if ((p = strchr(revision, ':'))) {
+ rev = p + 2;
+ p = strchr(rev, '$');
+ *--p = 0;
+ } else
+ rev = "???";
+ return rev;
}
-
/*
* Fax Class 2 Modem results
*
*/
-static void isdn_tty_fax_modem_result(int code, modem_info * info)
+
+static void
+isdn_tty_fax_modem_result(int code, modem_info * info)
{
atemu *m = &info->emu;
T30_s *f = info->fax;
@@ -85,7 +92,7 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
static char *msg[] =
{"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
"+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
- "+FCFR", "+FPTS:", "+FET:" };
+ "+FCFR", "+FPTS:", "+FET:"};
isdn_tty_at_cout("\r\n", info);
@@ -115,12 +122,12 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
case 3: /* +FCSI */
case 8: /* +FTSI */
sprintf(rs, "\"%s\"", f->r_id);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
break;
case 4: /* +FDIS */
rs[0] = 0;
rp = &f->r_resolution;
- for(i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
sprintf(rss, "%c%s", rp[i] + 48,
(i < 7) ? "," : "");
strcat(rs, rss);
@@ -128,18 +135,18 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
isdn_tty_at_cout(rs, info);
#ifdef ISDN_TTY_FAX_CMD_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
- rs, info->line);
+ rs, info->line);
#endif
break;
case 5: /* +FHNG */
sprintf(rs, "%d", f->code);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
info->faxonline = 0;
break;
case 6: /* +FDCS */
rs[0] = 0;
rp = &f->r_resolution;
- for(i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
sprintf(rss, "%c%s", rp[i] + 48,
(i < 7) ? "," : "");
strcat(rs, rss);
@@ -147,127 +154,169 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
isdn_tty_at_cout(rs, info);
#ifdef ISDN_TTY_FAX_CMD_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
- rs, info->line);
+ rs, info->line);
#endif
break;
case 7: /* CONNECT */
info->faxonline |= 2;
break;
- case 9: /* FCFR */
+ case 9: /* FCFR */
break;
- case 10: /* FPTS */
+ case 10: /* FPTS */
isdn_tty_at_cout("1", info);
break;
- case 11: /* FET */
+ case 11: /* FET */
sprintf(rs, "%d", f->fet);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
break;
}
isdn_tty_at_cout("\r\n", info);
switch (code) {
- case 7: /* CONNECT */
+ case 7: /* CONNECT */
info->online = 2;
if (info->faxonline & 1) {
sprintf(rs, "%c", XON);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
+ }
+ break;
+ }
+}
+
+int
+isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c)
+{
+ static char *msg[] =
+ {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
+#endif
+ if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
+ if (info->online)
+ info->online = 1;
+ isdn_tty_at_cout("\r\n", info);
+ isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
+ isdn_tty_at_cout("\r\n", info);
+ }
+ switch (c->parm.aux.cmd) {
+ case ISDN_FAX_CLASS1_CONNECT:
+ info->online = 2;
+ break;
+ case ISDN_FAX_CLASS1_OK:
+ case ISDN_FAX_CLASS1_FCERROR:
+ case ISDN_FAX_CLASS1_ERROR:
+ case ISDN_FAX_CLASS1_NOCARR:
+ break;
+ case ISDN_FAX_CLASS1_QUERY:
+ isdn_tty_at_cout("\r\n", info);
+ if (!c->parm.aux.para[0]) {
+ isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
+ isdn_tty_at_cout("\r\n", info);
+ } else {
+ isdn_tty_at_cout(c->parm.aux.para, info);
+ isdn_tty_at_cout("\r\nOK\r\n", info);
}
break;
}
+ return (0);
}
int
-isdn_tty_fax_command(modem_info * info)
+isdn_tty_fax_command(modem_info * info, isdn_ctrl * c)
{
T30_s *f = info->fax;
char rs[10];
+ if (TTY_IS_FCLASS1(info))
+ return (isdn_tty_fax_command1(info, c));
+
#ifdef ISDN_TTY_FAX_CMD_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
- f->r_code, info->line);
+ f->r_code, info->line);
#endif
- switch(f->r_code) {
+ switch (f->r_code) {
case ISDN_TTY_FAX_FCON:
info->faxonline = 1;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return(0);
+ isdn_tty_fax_modem_result(2, info); /* +FCON */
+ return (0);
case ISDN_TTY_FAX_FCON_I:
info->faxonline = 16;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return(0);
+ isdn_tty_fax_modem_result(2, info); /* +FCON */
+ return (0);
case ISDN_TTY_FAX_RID:
if (info->faxonline & 1)
- isdn_tty_fax_modem_result(3, info); /* +FCSI */
+ isdn_tty_fax_modem_result(3, info); /* +FCSI */
if (info->faxonline & 16)
- isdn_tty_fax_modem_result(8, info); /* +FTSI */
- return(0);
+ isdn_tty_fax_modem_result(8, info); /* +FTSI */
+ return (0);
case ISDN_TTY_FAX_DIS:
- isdn_tty_fax_modem_result(4, info); /* +FDIS */
- return(0);
+ isdn_tty_fax_modem_result(4, info); /* +FDIS */
+ return (0);
case ISDN_TTY_FAX_HNG:
if (f->phase == ISDN_FAX_PHASE_C) {
if (f->direction == ISDN_TTY_FAX_CONN_IN) {
sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
} else {
sprintf(rs, "%c", 0x18);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
}
- info->faxonline &= ~2; /* leave data mode */
+ info->faxonline &= ~2; /* leave data mode */
info->online = 1;
}
f->phase = ISDN_FAX_PHASE_E;
- isdn_tty_fax_modem_result(5, info); /* +FHNG */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return(0);
+ isdn_tty_fax_modem_result(5, info); /* +FHNG */
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ return (0);
case ISDN_TTY_FAX_DCS:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
+ isdn_tty_fax_modem_result(6, info); /* +FDCS */
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
f->phase = ISDN_FAX_PHASE_C;
- return(0);
+ return (0);
case ISDN_TTY_FAX_TRAIN_OK:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return(0);
+ isdn_tty_fax_modem_result(6, info); /* +FDCS */
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ return (0);
case ISDN_TTY_FAX_SENT:
- isdn_tty_fax_modem_result(0, info); /* OK */
- return(0);
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ return (0);
case ISDN_TTY_FAX_CFR:
- isdn_tty_fax_modem_result(9, info); /* +FCFR */
- return(0);
+ isdn_tty_fax_modem_result(9, info); /* +FCFR */
+ return (0);
case ISDN_TTY_FAX_ET:
sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
- isdn_tty_fax_modem_result(11, info); /* +FET */
- isdn_tty_fax_modem_result(0, info); /* OK */
- info->faxonline &= ~2; /* leave data mode */
+ isdn_tty_at_cout(rs, info);
+ isdn_tty_fax_modem_result(10, info); /* +FPTS */
+ isdn_tty_fax_modem_result(11, info); /* +FET */
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ info->faxonline &= ~2; /* leave data mode */
info->online = 1;
f->phase = ISDN_FAX_PHASE_D;
- return(0);
+ return (0);
case ISDN_TTY_FAX_PTS:
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
+ isdn_tty_fax_modem_result(10, info); /* +FPTS */
if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
if (f->fet == 1)
f->phase = ISDN_FAX_PHASE_B;
if (f->fet == 0)
- isdn_tty_fax_modem_result(0, info); /* OK */
+ isdn_tty_fax_modem_result(0, info); /* OK */
}
- return(0);
+ return (0);
case ISDN_TTY_FAX_EOP:
- info->faxonline &= ~2; /* leave data mode */
+ info->faxonline &= ~2; /* leave data mode */
info->online = 1;
f->phase = ISDN_FAX_PHASE_D;
- return(0);
+ return (0);
}
- return(-1);
+ return (-1);
}
void
-isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
+isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb)
{
__u8 LeftMask;
__u8 RightMask;
@@ -276,13 +325,13 @@ isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
int i;
if (!info->fax->bor) {
- for(i = 0; i < skb->len; i++) {
+ for (i = 0; i < skb->len; i++) {
Data = skb->data[i];
for (
- LeftMask = 0x80, RightMask = 0x01;
- LeftMask > RightMask;
- LeftMask >>= 1, RightMask <<= 1
- ) {
+ LeftMask = 0x80, RightMask = 0x01;
+ LeftMask > RightMask;
+ LeftMask >>= 1, RightMask <<= 1
+ ) {
fBit = (Data & LeftMask);
if (Data & RightMask)
Data |= LeftMask;
@@ -300,10 +349,103 @@ isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
}
/*
+ * Parse AT+F.. FAX class 1 commands
+ */
+
+int
+isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
+{
+ static char *cmd[] =
+ {"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
+ isdn_ctrl c;
+ int par, i;
+ long flags;
+
+ for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
+ if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
+ break;
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
+#endif
+ if (c.parm.aux.cmd == 7)
+ PARSE_ERROR1;
+
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ c.parm.aux.subcmd = AT_QUERY;
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ c.parm.aux.subcmd = AT_EQ_QUERY;
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ c.parm.aux.subcmd = AT_EQ_VALUE;
+ c.parm.aux.para[0] = par;
+ }
+ break;
+ case 0:
+ c.parm.aux.subcmd = AT_COMMAND;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ c.command = ISDN_CMD_FAXCMD;
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
+ c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
+#endif
+ if (info->isdn_driver < 0) {
+ save_flags(flags);
+ cli();
+ if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
+ (c.parm.aux.subcmd == AT_COMMAND)) {
+ restore_flags(flags);
+ PARSE_ERROR1;
+ }
+ /* get a temporary connection to the first free fax driver */
+ i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
+ ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
+ if (i < 0) {
+ restore_flags(flags);
+ PARSE_ERROR1;
+ }
+ info->isdn_driver = dev->drvmap[i];
+ info->isdn_channel = dev->chanmap[i];
+ info->drv_index = i;
+ dev->m_idx[i] = info->line;
+ c.driver = info->isdn_driver;
+ c.arg = info->isdn_channel;
+ isdn_command(&c);
+ isdn_free_channel(info->isdn_driver, info->isdn_channel,
+ ISDN_USAGE_FAX);
+ info->isdn_driver = -1;
+ info->isdn_channel = -1;
+ if (info->drv_index >= 0) {
+ dev->m_idx[info->drv_index] = -1;
+ info->drv_index = -1;
+ }
+ restore_flags(flags);
+ } else {
+ c.driver = info->isdn_driver;
+ c.arg = info->isdn_channel;
+ isdn_command(&c);
+ }
+ return 1;
+}
+
+/*
* Parse AT+F.. FAX class 2 commands
*/
-int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
+int
+isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
{
atemu *m = &info->emu;
T30_s *f = info->fax;
@@ -311,10 +453,11 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
int par;
char rs[50];
char rss[50];
- int maxdccval[]={1,5,2,2,3,2,0,7};
+ int maxdccval[] =
+ {1, 5, 2, 2, 3, 2, 0, 7};
/* FAA still unchanged */
- if (!strncmp(p[0], "AA", 2)) { /* TODO */
+ if (!strncmp(p[0], "AA", 2)) { /* TODO */
p[0] += 2;
switch (*p[0]) {
case '?':
@@ -332,399 +475,363 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
PARSE_ERROR1;
}
return 0;
- }
-
+ }
/* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
- if (!strncmp(p[0], "BADLIN", 6)) {
- p[0] += 6;
+ if (!strncmp(p[0], "BADLIN", 6)) {
+ p[0] += 6;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d",f->badlin);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->badlin);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badlin = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->badlin = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
- PARSE_ERROR1;
+ PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */
- if (!strncmp(p[0], "BADMUL", 6)){
- p[0] +=6;
+ if (!strncmp(p[0], "BADMUL", 6)) {
+ p[0] += 6;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d", f->badmul);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->badmul);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badmul = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->badmul = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* BOR=n - Phase C bit order, 0=direct, 1=reverse */
- if (!strncmp(p[0], "BOR", 3)){
- p[0] +=3;
+ if (!strncmp(p[0], "BOR", 3)) {
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d", f->bor);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->bor);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->bor = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->bor = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
/* NBC=n - No Best Capabilities */
- if (!strncmp(p[0], "NBC", 3)){
- p[0] +=3;
+ if (!strncmp(p[0], "NBC", 3)) {
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d", f->nbc);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->nbc);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->nbc = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->nbc = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
/* BUF? - Readonly buffersize readout */
- if (!strncmp(p[0], "BUF?", 4)) {
- p[0] += 4;
+ if (!strncmp(p[0], "BUF?", 4)) {
+ p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
+ printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
#endif
- p[0]++;
- sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
-
+ p[0]++;
+ sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
+ isdn_tty_at_cout(rs, info);
+ return 0;
+ }
/* CIG=string - local fax station id string for polling rx */
- if (!strncmp(p[0], "CIG", 3)) {
+ if (!strncmp(p[0], "CIG", 3)) {
int i, r;
- p[0] += 3;
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
sprintf(rs, "\r\n\"%s\"", f->pollid);
- isdn_tty_at_cout(rs, info);
- break;
+ isdn_tty_at_cout(rs, info);
+ break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- if (*p[0] =='"')
- p[0]++;
- for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++)
- {
- f->pollid[i] = *p[0]++;
- }
- if (*p[0] =='"')
- p[0]++;
- for(r=i; r < FAXIDLEN; r++)
- {
- f->pollid[r] = 32;
- }
- f->pollid[FAXIDLEN-1] = 0;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n\"STRING\"");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ if (*p[0] == '"')
+ p[0]++;
+ for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
+ f->pollid[i] = *p[0]++;
+ }
+ if (*p[0] == '"')
+ p[0]++;
+ for (r = i; r < FAXIDLEN; r++) {
+ f->pollid[r] = 32;
+ }
+ f->pollid[FAXIDLEN - 1] = 0;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
+ printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
- if (!strncmp(p[0], "CQ", 2)) {
- p[0] += 2;
+ if (!strncmp(p[0], "CQ", 2)) {
+ p[0] += 2;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d", f->cq);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->cq);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0,1,2");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 2))
- PARSE_ERROR1;
- f->cq = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0,1,2");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 2))
+ PARSE_ERROR1;
+ f->cq = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
- if (!strncmp(p[0], "CR", 2)) {
- p[0] += 2;
+ if (!strncmp(p[0], "CR", 2)) {
+ p[0] += 2;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0,1"); /* display online help */
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->cr = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0,1"); /* display online help */
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->cr = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* CTCRTY=value - ECM retry count */
- if (!strncmp(p[0], "CTCRTY", 6)){
- p[0] +=6;
+ if (!strncmp(p[0], "CTCRTY", 6)) {
+ p[0] += 6;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d",f->ctcrty);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->ctcrty);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->ctcrty = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->ctcrty = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
- if (!strncmp(p[0], "DCC", 3)) {
+ if (!strncmp(p[0], "DCC", 3)) {
char *rp = &f->resolution;
int i;
- p[0] += 3;
- switch(*p[0]) {
+ p[0] += 3;
+ switch (*p[0]) {
case '?':
p[0]++;
- strcpy(rs, "\r\n");
- for(i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
+ strcpy(rs, "\r\n");
+ for (i = 0; i < 8; i++) {
+ sprintf(rss, "%c%s", rp[i] + 48,
+ (i < 7) ? "," : "");
+ strcat(rs, rss);
+ }
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info);
- p[0]++;
- } else {
- for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) {
+ p[0]++;
+ if (*p[0] == '?') {
+ isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
+ p[0]++;
+ } else {
+ for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
if (*p[0] != ',') {
if ((*p[0] - 48) > maxdccval[i]) {
PARSE_ERROR1;
}
rp[i] = *p[0] - 48;
p[0]++;
- if (*p[0] == ',')
+ if (*p[0] == ',')
p[0]++;
- } else p[0]++;
+ } else
+ p[0]++;
}
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
+ printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
+ rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
#endif
- }
+ }
break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
- if (!strncmp(p[0], "DIS", 3)) {
+ if (!strncmp(p[0], "DIS", 3)) {
char *rp = &f->resolution;
int i;
- p[0] += 3;
- switch(*p[0]) {
+ p[0] += 3;
+ switch (*p[0]) {
case '?':
p[0]++;
- strcpy(rs, "\r\n");
- for(i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
+ strcpy(rs, "\r\n");
+ for (i = 0; i < 8; i++) {
+ sprintf(rss, "%c%s", rp[i] + 48,
+ (i < 7) ? "," : "");
+ strcat(rs, rss);
+ }
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info);
- p[0]++;
- } else {
- for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) {
+ p[0]++;
+ if (*p[0] == '?') {
+ isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
+ p[0]++;
+ } else {
+ for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
if (*p[0] != ',') {
if ((*p[0] - 48) > maxdccval[i]) {
PARSE_ERROR1;
}
rp[i] = *p[0] - 48;
p[0]++;
- if (*p[0] == ',')
+ if (*p[0] == ',')
p[0]++;
- } else p[0]++;
+ } else
+ p[0]++;
}
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
+ printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
+ rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
#endif
- }
+ }
break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
- /* DR - Receive Phase C data command, initiates document reception */
- if (!strncmp(p[0], "DR", 2)) {
- p[0] += 2;
+ return 0;
+ }
+ /* DR - Receive Phase C data command, initiates document reception */
+ if (!strncmp(p[0], "DR", 2)) {
+ p[0] += 2;
if ((info->faxonline & 16) && /* incoming connection */
- ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
+ ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
#ifdef ISDN_TTY_FAX_STAT_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
#endif
@@ -735,11 +842,11 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
isdn_command(&cmd);
if (f->phase == ISDN_FAX_PHASE_B) {
f->phase = ISDN_FAX_PHASE_C;
- } else if (f->phase == ISDN_FAX_PHASE_D) {
- switch(f->fet) {
+ } else if (f->phase == ISDN_FAX_PHASE_D) {
+ switch (f->fet) {
case 0: /* next page will be received */
f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
break;
case 1: /* next doc will be received */
f->phase = ISDN_FAX_PHASE_B;
@@ -747,35 +854,36 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
case 2: /* fax session is terminating */
f->phase = ISDN_FAX_PHASE_E;
break;
- default:
+ default:
PARSE_ERROR1;
}
}
} else {
PARSE_ERROR1;
}
- return 1;
+ return 1;
}
-
/* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
- if (!strncmp(p[0], "DT", 2)) {
- int i, val[]={4,0,2,3};
+ if (!strncmp(p[0], "DT", 2)) {
+ int i, val[] =
+ {4, 0, 2, 3};
char *rp = &f->resolution;
- p[0] += 2;
- if (!info->faxonline & 1) /* not outgoing connection */
+ p[0] += 2;
+ if (!info->faxonline & 1) /* not outgoing connection */
PARSE_ERROR1;
- for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<4); i++) {
+ for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
if (*p[0] != ',') {
if ((*p[0] - 48) > maxdccval[val[i]]) {
PARSE_ERROR1;
}
rp[val[i]] = *p[0] - 48;
p[0]++;
- if (*p[0] == ',')
+ if (*p[0] == ',')
p[0]++;
- } else p[0]++;
+ } else
+ p[0]++;
}
#ifdef ISDN_TTY_FAX_STAT_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
@@ -789,48 +897,43 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
isdn_command(&cmd);
if (f->phase == ISDN_FAX_PHASE_D) {
f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
}
} else {
PARSE_ERROR1;
}
- return 1;
- }
-
+ return 1;
+ }
/* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
- if (!strncmp(p[0], "ECM", 3)) {
- p[0] += 3;
+ if (!strncmp(p[0], "ECM", 3)) {
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d",f->ecm);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->ecm);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0,2");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par != 0) && (par != 2))
- PARSE_ERROR1;
- f->ecm = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0,2");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par != 0) && (par != 2))
+ PARSE_ERROR1;
+ f->ecm = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* ET=n - End of page or document */
if (!strncmp(p[0], "ET=", 3)) {
p[0] += 3;
@@ -857,7 +960,6 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
}
return 0;
}
-
/* K - terminate */
if (!strncmp(p[0], "K", 1)) {
p[0] += 1;
@@ -866,205 +968,191 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
isdn_tty_modem_hup(info, 1);
return 1;
}
-
/* LID=string - local fax ID */
- if (!strncmp(p[0], "LID", 3)) {
+ if (!strncmp(p[0], "LID", 3)) {
int i, r;
- p[0] += 3;
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
sprintf(rs, "\r\n\"%s\"", f->id);
- isdn_tty_at_cout(rs, info);
- break;
+ isdn_tty_at_cout(rs, info);
+ break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- if (*p[0] =='"')
- p[0]++;
- for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++)
- {
- f->id[i] = *p[0]++;
- }
- if (*p[0] =='"')
- p[0]++;
- for(r=i; r < FAXIDLEN; r++)
- {
- f->id[r] = 32;
- }
- f->id[FAXIDLEN-1] = 0;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n\"STRING\"");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ if (*p[0] == '"')
+ p[0]++;
+ for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
+ f->id[i] = *p[0]++;
+ }
+ if (*p[0] == '"')
+ p[0]++;
+ for (r = i; r < FAXIDLEN; r++) {
+ f->id[r] = 32;
+ }
+ f->id[FAXIDLEN - 1] = 0;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
+ printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* MDL? - DCE Model */
- if (!strncmp(p[0], "MDL?", 4)) {
- p[0] += 4;
+ if (!strncmp(p[0], "MDL?", 4)) {
+ p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMDL?\n");
+ printk(KERN_DEBUG "isdn_tty: FMDL?\n");
#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
-
+ isdn_tty_at_cout("\r\nisdn4linux", info);
+ return 0;
+ }
/* MFR? - DCE Manufacturer */
- if (!strncmp(p[0], "MFR?", 4)) {
- p[0] += 4;
+ if (!strncmp(p[0], "MFR?", 4)) {
+ p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMFR?\n");
+ printk(KERN_DEBUG "isdn_tty: FMFR?\n");
#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
-
+ isdn_tty_at_cout("\r\nisdn4linux", info);
+ return 0;
+ }
/* MINSP=n - Minimum Speed for Phase C */
- if (!strncmp(p[0], "MINSP", 5)) {
- p[0] += 5;
+ if (!strncmp(p[0], "MINSP", 5)) {
+ p[0] += 5;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d",f->minsp);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->minsp);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0-5");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 5))
- PARSE_ERROR1;
- f->minsp = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0-5");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 5))
+ PARSE_ERROR1;
+ f->minsp = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* PHCTO=value - DTE phase C timeout */
- if (!strncmp(p[0], "PHCTO", 5)){
- p[0] +=5;
+ if (!strncmp(p[0], "PHCTO", 5)) {
+ p[0] += 5;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d",f->phcto);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->phcto);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->phcto = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->phcto = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* REL=n - Phase C received EOL alignment */
- if (!strncmp(p[0], "REL", 3)) {
- p[0] += 3;
+ if (!strncmp(p[0], "REL", 3)) {
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
- sprintf(rs, "\r\n%d",f->rel);
- isdn_tty_at_cout(rs, info);
+ sprintf(rs, "\r\n%d", f->rel);
+ isdn_tty_at_cout(rs, info);
break;
case '=':
- p[0]++;
- if (*p[0] == '?')
- {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- }
- else
- {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->rel = par;
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->rel = par;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
+ printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* REV? - DCE Revision */
- if (!strncmp(p[0], "REV?", 4)) {
- p[0] += 4;
+ if (!strncmp(p[0], "REV?", 4)) {
+ p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FREV?\n");
+ printk(KERN_DEBUG "isdn_tty: FREV?\n");
#endif
strcpy(rss, isdn_tty_fax_revision);
sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
-
+ isdn_tty_at_cout(rs, info);
+ return 0;
+ }
/* Phase C Transmit Data Block Size */
- if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
+ if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
+ printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
#endif
- switch (*p[0]) {
- case '0':
- p[0]++;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
}
-
- printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
+ printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
PARSE_ERROR1;
}
+int
+isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
+{
+ if (TTY_IS_FCLASS2(info))
+ return (isdn_tty_cmd_FCLASS2(p, info));
+ else if (TTY_IS_FCLASS1(info))
+ return (isdn_tty_cmd_FCLASS1(p, info));
+ PARSE_ERROR1;
+}
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 14f1ac181..c9a40a3c1 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -68,6 +68,10 @@ ifdef CONFIG_ADB_PMU
L_OBJS += via-pmu.o
endif
+ifdef CONFIG_ADB_PMU68K
+ L_OBJS += via-pmu68k.o
+endif
+
ifdef CONFIG_ADB_MACIO
L_OBJS += macio-adb.o
endif
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
new file mode 100644
index 000000000..cf0504e0e
--- /dev/null
+++ b/drivers/macintosh/adb-iop.c
@@ -0,0 +1,283 @@
+/*
+ * I/O Processor (IOP) ADB Driver
+ * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
+ * Based on via-cuda.c by Paul Mackerras.
+ *
+ * 1999-07-01 (jmt) - First implementation for new driver architecture.
+ *
+ * 1999-07-31 (jmt) - First working version.
+ *
+ * TODO:
+ *
+ * o Implement SRQ handling.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/bootinfo.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_iop.h>
+#include <asm/mac_oss.h>
+#include <asm/adb_iop.h>
+
+#include <linux/adb.h>
+
+/*#define DEBUG_ADB_IOP*/
+
+extern void iop_ism_irq(int, void *, struct pt_regs *);
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+#if 0
+static unsigned char reply_buff[16];
+static unsigned char *reply_ptr;
+#endif
+
+static enum adb_iop_state {
+ idle,
+ sending,
+ awaiting_reply
+} adb_iop_state;
+
+static void adb_iop_start(void);
+static int adb_iop_probe(void);
+static int adb_iop_init(void);
+static int adb_iop_send_request(struct adb_request *, int);
+static int adb_iop_write(struct adb_request *);
+static int adb_iop_autopoll(int);
+static void adb_iop_poll(void);
+static int adb_iop_reset_bus(void);
+
+struct adb_driver adb_iop_driver = {
+ "ISM IOP",
+ adb_iop_probe,
+ adb_iop_init,
+ adb_iop_send_request,
+ adb_iop_autopoll,
+ adb_iop_poll,
+ adb_iop_reset_bus
+};
+
+static void adb_iop_end_req(struct adb_request *req, int state)
+{
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done) (*req->done)(req);
+ adb_iop_state = state;
+}
+
+/*
+ * Completion routine for ADB commands sent to the IOP.
+ *
+ * This will be called when a packet has been successfully sent.
+ */
+
+static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs)
+{
+ struct adb_request *req;
+ uint flags;
+
+ save_flags(flags);
+ cli();
+
+ req = current_req;
+ if ((adb_iop_state == sending) && req && req->reply_expected) {
+ adb_iop_state = awaiting_reply;
+ }
+
+ restore_flags(flags);
+}
+
+/*
+ * Listen for ADB messages from the IOP.
+ *
+ * This will be called when unsolicited messages (usually replies to TALK
+ * commands or autopoll packets) are received.
+ */
+
+static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
+{
+ struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
+ struct adb_request *req;
+ uint flags;
+
+ save_flags(flags);
+ cli();
+
+ req = current_req;
+
+#ifdef DEBUG_ADB_IOP
+ printk("adb_iop_listen: rcvd packet, %d bytes: %02X %02X",
+ (uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd);
+ i = 0;
+ while (i < amsg->count) {
+ printk(" %02X", (uint) amsg->data[i++]);
+ }
+ printk("\n");
+#endif
+
+ /* Handle a timeout. Timeout packets seem to occur even after */
+ /* we've gotten a valid reply to a TALK, so I'm assuming that */
+ /* a "timeout" is actually more like an "end-of-data" signal. */
+ /* We need to send back a timeout packet to the IOP to shut */
+ /* it up, plus complete the current request, if any. */
+
+ if (amsg->flags & ADB_IOP_TIMEOUT) {
+ msg->reply[0] = ADB_IOP_TIMEOUT | ADB_IOP_AUTOPOLL;
+ msg->reply[1] = 0;
+ msg->reply[2] = 0;
+ if (req && (adb_iop_state != idle)) {
+ adb_iop_end_req(req, idle);
+ }
+ } else {
+ /* TODO: is it possible for more tha one chunk of data */
+ /* to arrive before the timeout? If so we need to */
+ /* use reply_ptr here like the other drivers do. */
+ if ((adb_iop_state == awaiting_reply) &&
+ (amsg->flags & ADB_IOP_EXPLICIT)) {
+ req->reply_len = amsg->count + 1;
+ memcpy(req->reply, &amsg->cmd, req->reply_len);
+ } else {
+ adb_input(&amsg->cmd, amsg->count + 1, regs,
+ amsg->flags & ADB_IOP_AUTOPOLL);
+ }
+ memcpy(msg->reply, msg->message, IOP_MSG_LEN);
+ }
+ iop_complete_message(msg);
+ restore_flags(flags);
+}
+
+/*
+ * Start sending an ADB packet, IOP style
+ *
+ * There isn't much to do other than hand the packet over to the IOP
+ * after encapsulating it in an adb_iopmsg.
+ */
+
+static void adb_iop_start(void)
+{
+ unsigned long flags;
+ struct adb_request *req;
+ struct adb_iopmsg amsg;
+
+ /* get the packet to send */
+ req = current_req;
+ if (!req) return;
+
+ save_flags(flags);
+ cli();
+
+#ifdef DEBUG_ADB_IOP
+ printk("adb_iop_start: sending packet, %d bytes:", req->nbytes);
+ for (i = 0 ; i < req->nbytes ; i++)
+ printk(" %02X", (uint) req->data[i]);
+ printk("\n");
+#endif
+
+ /* The IOP takes MacII-style packets, so */
+ /* strip the initial ADB_PACKET byte. */
+
+ amsg.flags = ADB_IOP_EXPLICIT;
+ amsg.count = req->nbytes - 2;
+
+ /* amsg.data immediately follows amsg.cmd, effectively making */
+ /* amsg.cmd a pointer to the beginning of a full ADB packet. */
+ memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
+
+ req->sent = 1;
+ adb_iop_state = sending;
+ restore_flags(flags);
+
+ /* Now send it. The IOP manager will call adb_iop_complete */
+ /* when the packet has been sent. */
+
+ iop_send_message(ADB_IOP, ADB_CHAN, req,
+ sizeof(amsg), (__u8 *) &amsg, adb_iop_complete);
+}
+
+int adb_iop_probe(void)
+{
+ if (!iop_ism_present) return -ENODEV;
+ return 0;
+}
+
+int adb_iop_init(void)
+{
+ printk("adb: IOP ISM driver v0.4 for Unified ADB.\n");
+ iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
+ return 0;
+}
+
+int adb_iop_send_request(struct adb_request *req, int sync)
+{
+ int err;
+
+ err = adb_iop_write(req);
+ if (err) return err;
+
+ if (sync) {
+ while (!req->complete) adb_iop_poll();
+ }
+ return 0;
+}
+
+static int adb_iop_write(struct adb_request *req)
+{
+ unsigned long flags;
+
+ if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
+ req->complete = 1;
+ return -EINVAL;
+ }
+
+ save_flags(flags);
+ cli();
+
+ req->next = 0;
+ req->sent = 0;
+ req->complete = 0;
+ req->reply_len = 0;
+
+ if (current_req != 0) {
+ last_req->next = req;
+ last_req = req;
+ } else {
+ current_req = req;
+ last_req = req;
+ }
+
+ restore_flags(flags);
+ if (adb_iop_state == idle) adb_iop_start();
+ return 0;
+}
+
+int adb_iop_autopoll(int devs)
+{
+ /* TODO: how do we enable/disable autopoll? */
+ return 0;
+}
+
+void adb_iop_poll(void)
+{
+ if (adb_iop_state == idle) adb_iop_start();
+ iop_ism_irq(0, (void *) ADB_IOP, NULL);
+}
+
+int adb_iop_reset_bus(void)
+{
+ struct adb_request req;
+
+ req.reply_expected = 0;
+ req.nbytes = 2;
+ req.data[0] = ADB_PACKET;
+ req.data[1] = 0; /* RESET */
+ adb_iop_write(&req);
+ while (!req.complete) adb_iop_poll();
+ return 0;
+}
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 9ed259a20..fd8c1645a 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -22,6 +22,7 @@
#include <linux/malloc.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/adb.h>
@@ -664,6 +665,11 @@ void adbdev_init()
return;
#endif
- if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
+ if (devfs_register_chrdev(ADB_MAJOR, "adb", &adb_fops))
printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+ else
+ devfs_register (NULL, "adb", 0, DEVFS_FL_NONE,
+ ADB_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &adb_fops, NULL);
}
diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c
index 2ba5baac2..04999bb4c 100644
--- a/drivers/macintosh/mac_keyb.c
+++ b/drivers/macintosh/mac_keyb.c
@@ -391,16 +391,17 @@ input_keycode(int keycode, int repeat)
case 0x39:
handle_scancode(0x39, 1);
handle_scancode(0x39, 0);
- mark_bh(KEYBOARD_BH);
+ tasklet_schedule(&keyboard_tasklet);
return;
case 0x47:
/*case 0xc7:*/
- mark_bh(KEYBOARD_BH);
+ tasklet_schedule(&keyboard_tasklet);
break;
}
}
handle_scancode(keycode, !up_flag);
+ tasklet_schedule(&keyboard_tasklet);
}
static void
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
index 2555d5383..94ec60e1c 100644
--- a/drivers/macintosh/macserial.c
+++ b/drivers/macintosh/macserial.c
@@ -2796,7 +2796,6 @@ static struct console sercons = {
void __init serial_console_init(void)
{
register_console(&sercons);
- return kmem_start;
}
#endif /* ifdef CONFIG_SERIAL_CONSOLE */
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
new file mode 100644
index 000000000..f4670f1db
--- /dev/null
+++ b/drivers/macintosh/via-macii.c
@@ -0,0 +1,679 @@
+/*
+ * Device driver for the via ADB on (many) Mac II-class machines
+ *
+ * Based on the original ADB keyboard handler Copyright (c) 1997 Alan Cox
+ * Also derived from code Copyright (C) 1996 Paul Mackerras.
+ *
+ * With various updates provided over the years by Michael Schmitz,
+ * Guideo Koerber and others.
+ *
+ * Rewrite for Unified ADB by Joshua M. Thompson (funaho@jurai.org)
+ *
+ * 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/adb.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/init.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS 0x200 /* skip between registers */
+#define B 0 /* B-side data */
+#define A RS /* A-side data */
+#define DIRB (2*RS) /* B-side direction (1=output) */
+#define DIRA (3*RS) /* A-side direction (1=output) */
+#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
+#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
+#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
+#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
+#define SR (10*RS) /* Shift register */
+#define ACR (11*RS) /* Auxiliary control register */
+#define PCR (12*RS) /* Peripheral control register */
+#define IFR (13*RS) /* Interrupt flag register */
+#define IER (14*RS) /* Interrupt enable register */
+#define ANH (15*RS) /* A-side data, no handshake */
+
+/* Bits in B data register: all active low */
+#define TREQ 0x08 /* Transfer request (input) */
+#define TACK 0x10 /* Transfer acknowledge (output) */
+#define TIP 0x20 /* Transfer in progress (output) */
+#define ST_MASK 0x30 /* mask for selecting ADB state bits */
+
+/* Bits in ACR */
+#define SR_CTRL 0x1c /* Shift register control bits */
+#define SR_EXT 0x0c /* Shift on external clock */
+#define SR_OUT 0x10 /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET 0x80 /* set bits in IER */
+#define IER_CLR 0 /* clear bits in IER */
+#define SR_INT 0x04 /* Shift register full/empty */
+#define SR_DATA 0x08 /* Shift register data */
+#define SR_CLOCK 0x10 /* Shift register clock */
+
+/* ADB transaction states according to GMHW */
+#define ST_CMD 0x00 /* ADB state: command byte */
+#define ST_EVEN 0x10 /* ADB state: even data byte */
+#define ST_ODD 0x20 /* ADB state: odd data byte */
+#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */
+
+static int macii_init_via(void);
+static void macii_start(void);
+static void macii_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void macii_retransmit(int);
+static void macii_queue_poll(void);
+
+static int macii_probe(void);
+static int macii_init(void);
+static int macii_send_request(struct adb_request *req, int sync);
+static int macii_write(struct adb_request *req);
+static int macii_autopoll(int devs);
+static void macii_poll(void);
+static int macii_reset_bus(void);
+
+struct adb_driver via_macii_driver = {
+ "Mac II",
+ macii_probe,
+ macii_init,
+ macii_send_request,
+ macii_autopoll,
+ macii_poll,
+ macii_reset_bus
+};
+
+static enum macii_state {
+ idle,
+ sent_first_byte,
+ sending,
+ reading,
+ read_done,
+ awaiting_reply
+} macii_state;
+
+static int need_poll = 0;
+static int command_byte = 0;
+static int last_reply = 0;
+static int last_active = 0;
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+static struct adb_request *retry_req;
+static unsigned char reply_buf[16];
+static unsigned char *reply_ptr;
+static int reply_len;
+static int reading_reply;
+static int data_index;
+static int first_byte;
+static int prefix_len;
+static int status = ST_IDLE|TREQ;
+static int last_status;
+static int driver_running = 0;
+
+/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */
+extern int console_loglevel;
+
+/* Check for MacII style ADB */
+static int macii_probe(void)
+{
+ if (macintosh_config->adb_type != MAC_ADB_II) return -ENODEV;
+
+ via = via1;
+
+ printk("adb: Mac II ADB Driver v0.4 for Unified ADB\n");
+ return 0;
+}
+
+/* Initialize the driver */
+int macii_init(void)
+{
+ unsigned long flags;
+ int err;
+
+ save_flags(flags);
+ cli();
+
+ err = macii_init_via();
+ if (err) return err;
+
+ err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB",
+ macii_interrupt);
+ if (err) return err;
+
+ macii_state = idle;
+ restore_flags(flags);
+ return 0;
+}
+
+/* initialize the hardware */
+static int macii_init_via(void)
+{
+ unsigned char x;
+
+ /* Set the lines up. We want TREQ as input TACK|TIP as output */
+ via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
+
+ /* Set up state: idle */
+ via[B] |= ST_IDLE;
+ last_status = via[B] & (ST_MASK|TREQ);
+
+ /* Shift register on input */
+ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
+
+ /* Wipe any pending data and int */
+ x = via[SR];
+
+ return 0;
+}
+
+/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */
+static void macii_queue_poll(void)
+{
+ static int device = 0;
+ static int in_poll=0;
+ static struct adb_request req;
+ unsigned long flags;
+
+ if (in_poll) printk("macii_queue_poll: double poll!\n");
+
+ in_poll++;
+ if (++device > 15) device = 1;
+
+ adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
+ ADB_READREG(device, 0));
+
+ save_flags(flags);
+ cli();
+
+ req.next = current_req;
+ current_req = &req;
+
+ restore_flags(flags);
+ macii_start();
+ in_poll--;
+}
+
+/* Send an ADB retransmit (Talk, appended to the request queue) */
+static void macii_retransmit(int device)
+{
+ static int in_retransmit = 0;
+ static struct adb_request rt;
+ unsigned long flags;
+
+ if (in_retransmit) printk("macii_retransmit: double retransmit!\n");
+
+ in_retransmit++;
+
+ adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
+ ADB_READREG(device, 0));
+
+ save_flags(flags);
+ cli();
+
+ if (current_req != NULL) {
+ last_req->next = &rt;
+ last_req = &rt;
+ } else {
+ current_req = &rt;
+ last_req = &rt;
+ }
+
+ if (macii_state == idle) macii_start();
+
+ restore_flags(flags);
+ in_retransmit--;
+}
+
+/* Send an ADB request; if sync, poll out the reply 'till it's done */
+static int macii_send_request(struct adb_request *req, int sync)
+{
+ int i;
+
+ i = macii_write(req);
+ if (i) return i;
+
+ if (sync) {
+ while (!req->complete) macii_poll();
+ }
+ return 0;
+}
+
+/* Send an ADB request */
+static int macii_write(struct adb_request *req)
+{
+ unsigned long flags;
+
+ if (req->nbytes < 2 || req->data[0] != ADB_PACKET) {
+ req->complete = 1;
+ return -EINVAL;
+ }
+
+ req->next = 0;
+ req->sent = 0;
+ req->complete = 0;
+ req->reply_len = 0;
+
+ save_flags(flags); cli();
+
+ if (current_req != NULL) {
+ last_req->next = req;
+ last_req = req;
+ } else {
+ current_req = req;
+ last_req = req;
+ if (macii_state == idle) macii_start();
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+/* Start auto-polling */
+static int macii_autopoll(int devs)
+{
+ /* Just ping a random default address */
+ if (!(current_req || retry_req))
+ macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3);
+ return 0;
+}
+
+/* Prod the chip without interrupts */
+static void macii_poll(void)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (via[IFR] & SR_INT) macii_interrupt(0, 0, 0);
+ restore_flags(flags);
+}
+
+/* Reset the bus */
+static int macii_reset_bus(void)
+{
+ static struct adb_request req;
+
+ /* Command = 0, Address = ignored */
+ adb_request(&req, NULL, 0, 1, ADB_BUSRESET);
+
+ return 0;
+}
+
+/* Start sending ADB packet */
+static void macii_start(void)
+{
+ unsigned long flags;
+ struct adb_request *req;
+
+ req = current_req;
+ if (!req) return;
+
+ /* assert macii_state == idle */
+ if (macii_state != idle) {
+ printk("macii_start: called while driver busy (%p %x %x)!\n",
+ req, macii_state, (uint) via1[B] & (ST_MASK|TREQ));
+ return;
+ }
+
+ save_flags(flags); cli();
+
+ /*
+ * IRQ signaled ?? (means ADB controller wants to send, or might
+ * be end of packet if we were reading)
+ */
+ if ((via[B] & TREQ) == 0) {
+ /*
+ * FIXME - we need to restart this on a timer
+ * or a collision at boot hangs us.
+ * Never set macii_state to idle here, or macii_start
+ * won't be called again from send_request!
+ * (need to re-check other cases ...)
+ */
+ /*
+ * if the interrupt handler set the need_poll
+ * flag, it's hopefully a SRQ poll or re-Talk
+ * so we try to send here anyway
+ */
+ if (!need_poll) {
+ if (console_loglevel == 10)
+ printk("macii_start: device busy - retry %p state %d status %x!\n",
+ req, macii_state,
+ (uint) via[B] & (ST_MASK|TREQ));
+ retry_req = req;
+ /* set ADB status here ? */
+ restore_flags(flags);
+ return;
+ } else {
+ need_poll = 0;
+ }
+ }
+ /*
+ * Another retry pending? (sanity check)
+ */
+ if (retry_req) {
+ retry_req = NULL;
+ }
+
+ /* Now send it. Be careful though, that first byte of the request */
+ /* is actually ADB_PACKET; the real data begins at index 1! */
+
+ /* store command byte */
+ command_byte = req->data[1];
+ /* Output mode */
+ via[ACR] |= SR_OUT;
+ /* Load data */
+ via[SR] = req->data[1];
+ /* set ADB state to 'command' */
+ via[B] = (via[B] & ~ST_MASK) | ST_CMD;
+
+ macii_state = sent_first_byte;
+ data_index = 2;
+
+ restore_flags(flags);
+}
+
+/*
+ * The notorious ADB interrupt handler - does all of the protocol handling,
+ * except for starting new send operations. Relies heavily on the ADB
+ * controller sending and receiving data, thereby generating SR interrupts
+ * for us. This means there has to be always activity on the ADB bus, otherwise
+ * the whole process dies and has to be re-kicked by sending TALK requests ...
+ * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
+ * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
+ * a good choice; either on timeout or on a timer interrupt).
+ *
+ * The basic ADB state machine was left unchanged from the original MacII code
+ * by Alan Cox, which was based on the CUDA driver for PowerMac.
+ * The syntax of the ADB status lines seems to be totally different on MacII,
+ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
+ * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start
+ * and end of a receive packet are signaled by asserting /IRQ on the interrupt
+ * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on
+ * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the
+ * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB
+ * protocol with a logic analyzer!!)
+ *
+ * Note: As of 21/10/97, the MacII ADB part works including timeout detection
+ * and retransmit (Talk to the last active device).
+ */
+void macii_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+ int x, adbdir;
+ unsigned long flags;
+ struct adb_request *req;
+
+ last_status = status;
+
+ /* prevent races due to SCSI enabling ints */
+ save_flags(flags); cli();
+
+ if (driver_running) {
+ restore_flags(flags);
+ return;
+ }
+
+ driver_running = 1;
+
+ status = via[B] & (ST_MASK|TREQ);
+ adbdir = via[ACR] & SR_OUT;
+
+ switch (macii_state) {
+ case idle:
+ x = via[SR];
+ first_byte = x;
+ /* set ADB state = even for first data byte */
+ via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+
+ reply_buf[0] = first_byte; /* was command_byte?? */
+ reply_ptr = reply_buf + 1;
+ reply_len = 1;
+ prefix_len = 1;
+ reading_reply = 0;
+
+ macii_state = reading;
+ break;
+
+ case awaiting_reply:
+ /* handshake etc. for II ?? */
+ x = via[SR];
+ first_byte = x;
+ /* set ADB state = even for first data byte */
+ via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+
+ current_req->reply[0] = first_byte;
+ reply_ptr = current_req->reply + 1;
+ reply_len = 1;
+ prefix_len = 1;
+ reading_reply = 1;
+
+ macii_state = reading;
+ break;
+
+ case sent_first_byte:
+ req = current_req;
+ /* maybe we're already done (Talk, or Poll)? */
+ if (data_index >= req->nbytes) {
+ /* reset to shift in */
+ /* If it's a Listen command and we're done, someone's doing weird stuff. */
+ if (((command_byte & 0x0C) == 0x08)
+ && (console_loglevel == 10))
+ printk("macii_interrupt: listen command with no data: %x!\n",
+ command_byte);
+ /* reset to shift in */
+ via[ACR] &= ~SR_OUT;
+ x = via[SR];
+ /* set ADB state idle - might get SRQ */
+ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+
+ req->sent = 1;
+
+ if (req->reply_expected) {
+ macii_state = awaiting_reply;
+ } else {
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done) (*req->done)(req);
+ macii_state = idle;
+ if (current_req || retry_req)
+ macii_start();
+ else
+ macii_retransmit((command_byte & 0xF0) >> 4);
+ }
+ } else {
+ /* SR already set to shift out; send byte */
+ via[SR] = current_req->data[data_index++];
+ /* set state to ST_EVEN (first byte was: ST_CMD) */
+ via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+ macii_state = sending;
+ }
+ break;
+
+ case sending:
+ req = current_req;
+ if (data_index >= req->nbytes) {
+ /* reset to shift in */
+ via[ACR] &= ~SR_OUT;
+ x = via[SR];
+ /* set ADB state idle - might get SRQ */
+ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+
+ req->sent = 1;
+
+ if (req->reply_expected) {
+ macii_state = awaiting_reply;
+ } else {
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done) (*req->done)(req);
+ macii_state = idle;
+ if (current_req || retry_req)
+ macii_start();
+ else
+ macii_retransmit((command_byte & 0xF0) >> 4);
+ }
+ } else {
+ via[SR] = req->data[data_index++];
+
+ /* invert state bits, toggle ODD/EVEN */
+ via[B] ^= ST_MASK;
+ }
+ break;
+
+ case reading:
+
+ /* timeout / SRQ handling for II hw */
+ if( (first_byte == 0xFF && (reply_len-prefix_len)==2
+ && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) ||
+ ((reply_len-prefix_len)==3
+ && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
+ {
+ /*
+ * possible timeout (in fact, most probably a
+ * timeout, since SRQ can't be signaled without
+ * transfer on the bus).
+ * The last three bytes seen were FF, together
+ * with the starting byte (in case we started
+ * on 'idle' or 'awaiting_reply') this probably
+ * makes four. So this is mostl likely #5!
+ * The timeout signal is a pattern 1 0 1 0 0..
+ * on /INT, meaning we missed it :-(
+ */
+ x = via[SR];
+ if (x != 0xFF) printk("macii_interrupt: mistaken timeout/SRQ!\n");
+
+ if ((status & TREQ) == (last_status & TREQ)) {
+ /* Not a timeout. Unsolicited SRQ? weird. */
+ /* Terminate the SRQ packet and poll */
+ need_poll = 1;
+ }
+ /* There's no packet to get, so reply is blank */
+ via[B] ^= ST_MASK;
+ reply_ptr -= (reply_len-prefix_len);
+ reply_len = prefix_len;
+ macii_state = read_done;
+ break;
+ } /* end timeout / SRQ handling for II hw. */
+
+ if((reply_len-prefix_len)>3
+ && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+ {
+ /* SRQ tacked on data packet */
+ /* Terminate the packet (SRQ never ends) */
+ x = via[SR];
+ macii_state = read_done;
+ reply_len -= 3;
+ reply_ptr -= 3;
+ need_poll = 1;
+ /* need to continue; next byte not seen else */
+ } else {
+ /* Sanity check */
+ if (reply_len > 15) reply_len = 0;
+ /* read byte */
+ x = via[SR];
+ *reply_ptr = x;
+ reply_ptr++;
+ reply_len++;
+ }
+ /* The usual handshake ... */
+
+ /*
+ * NetBSD hints that the next to last byte
+ * is sent with IRQ !!
+ * Guido found out it's the last one (0x0),
+ * but IRQ should be asserted already.
+ * Problem with timeout detection: First
+ * transition to /IRQ might be second
+ * byte of timeout packet!
+ * Timeouts are signaled by 4x FF.
+ */
+ if (!(status & TREQ) && (x == 0x00)) { /* != 0xFF */
+ /* invert state bits, toggle ODD/EVEN */
+ via[B] ^= ST_MASK;
+
+ /* adjust packet length */
+ reply_len--;
+ reply_ptr--;
+ macii_state = read_done;
+ } else {
+ /* not caught: ST_CMD */
+ /* required for re-entry 'reading'! */
+ if ((status & ST_MASK) == ST_IDLE) {
+ /* (in)sanity check - set even */
+ via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+ } else {
+ /* invert state bits */
+ via[B] ^= ST_MASK;
+ }
+ }
+ break;
+
+ case read_done:
+ x = via[SR];
+ if (reading_reply) {
+ req = current_req;
+ req->reply_len = reply_ptr - req->reply;
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done) (*req->done)(req);
+ } else {
+ adb_input(reply_buf, reply_ptr - reply_buf,
+ regs, 0);
+ }
+
+ /*
+ * remember this device ID; it's the latest we got a
+ * reply from!
+ */
+ last_reply = command_byte;
+ last_active = (command_byte & 0xF0) >> 4;
+
+ /* SRQ seen before, initiate poll now */
+ if (need_poll) {
+ macii_state = idle;
+ macii_queue_poll();
+ need_poll = 0;
+ break;
+ }
+
+ /* /IRQ seen, so the ADB controller has data for us */
+ if (!(status & TREQ)) {
+ /* set ADB state to idle */
+ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+
+ macii_state = reading;
+
+ reply_buf[0] = command_byte;
+ reply_ptr = reply_buf + 1;
+ reply_len = 1;
+ prefix_len = 1;
+ reading_reply = 0;
+ } else {
+ /* no IRQ, send next packet or wait */
+ macii_state = idle;
+ if (current_req)
+ macii_start();
+ else
+ macii_retransmit(last_active);
+ }
+ break;
+
+ default:
+ break;
+ }
+ /* reset mutex and interrupts */
+ driver_running = 0;
+ restore_flags(flags);
+}
diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c
new file mode 100644
index 000000000..04ce095d6
--- /dev/null
+++ b/drivers/macintosh/via-maciisi.c
@@ -0,0 +1,486 @@
+/*
+ * Device driver for the IIsi-style ADB on some Mac LC and II-class machines
+ *
+ * Based on via-cuda.c and via-macii.c, as well as the original
+ * adb-bus.c, which in turn is somewhat influenced by (but uses no
+ * code from) the NetBSD HWDIRECT ADB code. Original IIsi driver work
+ * was done by Robert Thompson and integrated into the old style
+ * driver by Michael Schmitz.
+ *
+ * Original sources (c) Alan Cox, Paul Mackerras, and others.
+ *
+ * Rewritten for Unified ADB by David Huggins-Daines <dhd@debian.org> */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/delay.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart - only the ones we actually use */
+#define RS 0x200 /* skip between registers */
+#define B 0 /* B-side data */
+#define A RS /* A-side data */
+#define DIRB (2*RS) /* B-side direction (1=output) */
+#define DIRA (3*RS) /* A-side direction (1=output) */
+#define SR (10*RS) /* Shift register */
+#define ACR (11*RS) /* Auxiliary control register */
+#define IFR (13*RS) /* Interrupt flag register */
+#define IER (14*RS) /* Interrupt enable register */
+
+/* Bits in B data register: all active low */
+#define TREQ 0x08 /* Transfer request (input) */
+#define TACK 0x10 /* Transfer acknowledge (output) */
+#define TIP 0x20 /* Transfer in progress (output) */
+#define ST_MASK 0x30 /* mask for selecting ADB state bits */
+
+/* Bits in ACR */
+#define SR_CTRL 0x1c /* Shift register control bits */
+#define SR_EXT 0x0c /* Shift on external clock */
+#define SR_OUT 0x10 /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET 0x80 /* set bits in IER */
+#define IER_CLR 0 /* clear bits in IER */
+#define SR_INT 0x04 /* Shift register full/empty */
+#define SR_DATA 0x08 /* Shift register data */
+#define SR_CLOCK 0x10 /* Shift register clock */
+
+#define ADB_DELAY 150
+
+static struct adb_request* current_req = NULL;
+static struct adb_request* last_req = NULL;
+static unsigned char maciisi_rbuf[16];
+static unsigned char *reply_ptr = NULL;
+static int data_index;
+static int reading_reply;
+static int reply_len;
+
+static enum maciisi_state {
+ idle,
+ sending,
+ reading,
+} maciisi_state;
+
+static int maciisi_probe(void);
+static int maciisi_init(void);
+static int maciisi_send_request(struct adb_request* req, int sync);
+static int maciisi_write(struct adb_request* req);
+static void maciisi_interrupt(int irq, void* arg, struct pt_regs* regs);
+static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs);
+static int maciisi_init_via(void);
+static void maciisi_poll(void);
+static void maciisi_start(void);
+
+struct adb_driver via_maciisi_driver = {
+ "Mac IIsi",
+ maciisi_probe,
+ maciisi_init,
+ maciisi_send_request,
+ NULL, /* maciisi_adb_autopoll, */
+ maciisi_poll,
+ NULL /* maciisi_reset_adb_bus */
+};
+
+static int
+maciisi_probe(void)
+{
+ if (macintosh_config->adb_type != MAC_ADB_IISI)
+ return -ENODEV;
+
+ via = via1;
+ return 0;
+}
+
+static int
+maciisi_init(void)
+{
+ int err;
+
+ if (via == NULL)
+ return -ENODEV;
+
+ if ((err = maciisi_init_via())) {
+ printk(KERN_ERR "maciisi_init: maciisi_init_via() failed, code %d\n", err);
+ via = NULL;
+ return err;
+ }
+
+ if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK,
+ "ADB", maciisi_interrupt)) {
+ printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB);
+ return -EAGAIN;
+ }
+
+ printk("adb: Mac IIsi driver v0.1 for Unified ADB.\n");
+ return 0;
+}
+
+static void
+maciisi_stfu(void)
+{
+ int status = via[B] & (TIP|TREQ);
+
+ if (status & TREQ) {
+ printk (KERN_DEBUG "maciisi_stfu called with TREQ high!\n");
+ return;
+ }
+
+ /* start transfer */
+ via[B] |= TIP;
+ while (!(status & TREQ)) {
+ int poll_timeout = ADB_DELAY * 5;
+ /* Poll for SR interrupt */
+ while (!(via[IFR] & SR_INT) && poll_timeout-- > 0)
+ status = via[B] & (TIP|TREQ);
+ via[SR]; /* Clear shift register */
+ printk(KERN_DEBUG "maciisi_stfu: status %x timeout %d\n",
+ status, poll_timeout);
+
+ /* ACK on-off */
+ via[B] |= TACK;
+ udelay(ADB_DELAY);
+ via[B] &= ~TACK;
+ }
+ /* end frame */
+ via[B] &= ~TIP;
+}
+
+/* All specifically VIA-related initialization goes here */
+static int
+maciisi_init_via(void)
+{
+ /* Set the lines up. We want TREQ as input TACK|TIP as output */
+ via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
+ /* Shift register on input */
+ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
+ printk(KERN_DEBUG "maciisi_init_via: initial status %x\n", via[B] & (TIP|TREQ));
+ /* Set initial state: idle */
+ via[B] &= ~(TACK|TIP);
+ /* Wipe any pending data and int */
+ via[SR];
+ if (!(via[B] & TREQ))
+ maciisi_stfu();
+ via[IER] = IER_SET | SR_INT;
+ maciisi_state = idle;
+ return 0;
+}
+
+/* Send a request, possibly waiting for a reply */
+static int
+maciisi_send_request(struct adb_request* req, int sync)
+{
+ int i;
+ static int dump_packet = 1;
+
+ if (via == NULL) {
+ req->complete = 1;
+ return -ENXIO;
+ }
+
+ if (dump_packet) {
+ printk(KERN_DEBUG "maciisi_send_request:");
+ for (i = 0; i < req->nbytes; i++) {
+ printk(" %.2x", req->data[i]);
+ }
+ printk("\n");
+ }
+ req->reply_expected = 1;
+
+ i = maciisi_write(req);
+ if (i)
+ return i;
+
+ if (sync) {
+ while (!req->complete) {
+ maciisi_poll();
+ }
+ }
+ return 0;
+}
+
+/* Enqueue a request, and run the queue if possible */
+static int
+maciisi_write(struct adb_request* req)
+{
+ unsigned long flags;
+
+ printk(KERN_DEBUG "maciisi_write called, state=%d ifr=%x\n", maciisi_state, via[IFR]);
+ /* We will accept CUDA packets - the VIA sends them to us, so
+ it figures that we should be able to send them to it */
+ if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
+ printk(KERN_ERR "maciisi_write: packet too small or not an ADB or CUDA packet\n");
+ req->complete = 1;
+ return -EINVAL;
+ }
+ req->next = 0;
+ req->sent = 0;
+ req->complete = 0;
+ req->reply_len = 0;
+ save_flags(flags); cli();
+
+ if (current_req) {
+ last_req->next = req;
+ last_req = req;
+ } else {
+ current_req = req;
+ last_req = req;
+ }
+ if (maciisi_state == idle)
+ maciisi_start();
+ else
+ printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state);
+
+ restore_flags(flags);
+ return 0;
+}
+
+static void
+maciisi_start(void)
+{
+ struct adb_request* req;
+ int status;
+
+ printk(KERN_DEBUG "maciisi_start called, state=%d, ifr=%x\n", maciisi_state, via[IFR]);
+ if (maciisi_state != idle) {
+ /* shouldn't happen */
+ printk(KERN_ERR "maciisi_start: maciisi_start called when driver busy!\n");
+ return;
+ }
+
+ req = current_req;
+ if (req == NULL)
+ return;
+
+ status = via[B] & (TIP|TREQ);
+ if (!(status & TREQ)) {
+ /* Bus is busy, set up for reading */
+ printk(KERN_DEBUG "maciisi_start: bus busy - aborting\n");
+ return;
+ }
+
+ /* Okay, send */
+ printk(KERN_DEBUG "maciisi_start: sending\n");
+ /* Set state to active */
+ via[B] |= TIP;
+ /* ACK off */
+ via[B] &= ~TACK;
+ /* Shift out and send */
+ via[ACR] |= SR_OUT;
+ via[SR] = req->data[0];
+ data_index = 1;
+ /* ACK on */
+ via[B] |= TACK;
+ maciisi_state = sending;
+}
+
+void
+maciisi_poll(void)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (via[IFR] & SR_INT) {
+ maciisi_interrupt(0, 0, 0);
+ }
+ restore_flags(flags);
+}
+
+/* Shift register interrupt - this is *supposed* to mean that the
+ register is either full or empty. In practice, I have no idea what
+ it means :( */
+static void
+maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
+{
+ int status;
+ struct adb_request *req;
+ static int dump_reply = 1;
+
+ if (!(via[IFR] & SR_INT)) {
+ /* Shouldn't happen, we hope */
+ printk(KERN_DEBUG "maciisi_interrupt: called without interrupt flag set\n");
+ return;
+ }
+
+ status = via[B] & (TIP|TREQ);
+ printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]);
+
+ switch_start:
+ switch (maciisi_state) {
+ case idle:
+ printk(KERN_DEBUG "maciisi_interrupt: state=idle, status %x\n", status);
+ if (status & TIP)
+ printk(KERN_DEBUG "maciisi_interrupt: state is idle but TIP asserted!\n");
+
+ udelay(ADB_DELAY);
+ /* Shift in */
+ via[ACR] &= ~SR_OUT;
+ /* Signal start of frame */
+ via[B] |= TIP;
+ /* Clear the interrupt (throw this value on the floor, it's useless) */
+ via[SR];
+ /* ACK adb chip, high-low */
+ via[B] |= TACK;
+ udelay(ADB_DELAY);
+ via[B] &= ~TACK;
+ reply_len = 0;
+ maciisi_state = reading;
+ if (reading_reply) {
+ reply_ptr = current_req->reply;
+ } else {
+ printk(KERN_DEBUG "maciisi_interrupt: received unsolicited packet\n");
+ reply_ptr = maciisi_rbuf;
+ }
+ break;
+
+ case sending:
+ printk(KERN_DEBUG "maciisi_interrupt: state=sending, status=%x\n", status);
+ /* Clear interrupt */
+ via[SR];
+ /* Set ACK off */
+ via[B] &= ~TACK;
+ req = current_req;
+
+ if (!(status & TREQ)) {
+ /* collision */
+ printk(KERN_DEBUG "maciisi_interrupt: send collision\n");
+ /* Set idle and input */
+ via[B] &= ~TIP;
+ via[ACR] &= ~SR_OUT;
+ /* Must re-send */
+ reading_reply = 0;
+ reply_len = 0;
+ maciisi_state = idle;
+ /* process this now, because the IFR has been cleared */
+ goto switch_start;
+ }
+
+ if (data_index >= req->nbytes) {
+ /* Sent the whole packet, put the bus back in idle state */
+ /* Shift in, we are about to read a reply (hopefully) */
+ via[ACR] &= ~SR_OUT;
+ /* End of frame */
+ via[B] &= ~TIP;
+ req->sent = 1;
+ maciisi_state = idle;
+ if (req->reply_expected) {
+ /* Note: only set this once we've
+ successfully sent the packet */
+ reading_reply = 1;
+ } else {
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ }
+ } else {
+ /* Sending more stuff */
+ /* Shift out */
+ via[ACR] |= SR_OUT;
+ /* Delay */
+ udelay(ADB_DELAY);
+ /* Write */
+ via[SR] = req->data[data_index++];
+ /* Signal 'byte ready' */
+ via[B] |= TACK;
+ }
+ break;
+
+ case reading:
+ printk(KERN_DEBUG "maciisi_interrupt: state=reading, status=%x\n", status);
+ /* Shift in */
+ via[ACR] &= ~SR_OUT;
+ if (reply_len++ > 16) {
+ printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n");
+ via[B] |= TACK;
+ udelay(ADB_DELAY);
+ via[B] &= ~(TACK|TIP);
+ maciisi_state = idle;
+ maciisi_start();
+ break;
+ }
+ *reply_ptr++ = via[SR];
+ status = via[B] & (TIP|TREQ);
+ /* ACK on/off */
+ via[B] |= TACK;
+ udelay(ADB_DELAY);
+ via[B] &= ~TACK;
+ if (!(status & TREQ))
+ break; /* more stuff to deal with */
+
+ /* end of frame */
+ via[B] &= ~TIP;
+
+ /* end of packet, deal with it */
+ if (reading_reply) {
+ req = current_req;
+ req->reply_len = reply_ptr - req->reply;
+ if (req->data[0] == ADB_PACKET) {
+ /* Have to adjust the reply from ADB commands */
+ if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
+ /* the 0x2 bit indicates no response */
+ req->reply_len = 0;
+ } else {
+ /* leave just the command and result bytes in the reply */
+ req->reply_len -= 2;
+ memmove(req->reply, req->reply + 2, req->reply_len);
+ }
+ }
+ if (dump_reply) {
+ int i;
+ printk(KERN_DEBUG "maciisi_interrupt: reply is ");
+ for (i = 0; i < req->reply_len; ++i)
+ printk(" %.2x", req->reply[i]);
+ printk("\n");
+ }
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ /* Obviously, we got it */
+ reading_reply = 0;
+ } else {
+ maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs);
+ }
+ maciisi_state = idle;
+ status = via[B] & (TIP|TREQ);
+ if (!(status & TREQ)) {
+ /* Timeout?! */
+ printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n",
+ status, via[IFR]);
+ maciisi_stfu();
+ }
+ /* Do any queued requests now if possible */
+ maciisi_start();
+ break;
+
+ default:
+ printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state);
+ }
+}
+
+static void
+maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs)
+{
+ int i;
+
+ switch (buf[0]) {
+ case ADB_PACKET:
+ adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
+ break;
+ default:
+ printk(KERN_DEBUG "data from IIsi ADB (%d bytes):", nb);
+ for (i = 0; i < nb; ++i)
+ printk(" %.2x", buf[i]);
+ printk("\n");
+
+ }
+}
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
new file mode 100644
index 000000000..0c14baed5
--- /dev/null
+++ b/drivers/macintosh/via-pmu68k.c
@@ -0,0 +1,1063 @@
+/*
+ * Device driver for the PMU on 68K-based Apple PowerBooks
+ *
+ * The VIA (versatile interface adapter) interfaces to the PMU,
+ * a 6805 microprocessor core whose primary function is to control
+ * battery charging and system power on the PowerBooks.
+ * The PMU also controls the ADB (Apple Desktop Bus) which connects
+ * to the keyboard and mouse, as well as the non-volatile RAM
+ * and the RTC (real time clock) chip.
+ *
+ * Adapted for 68K PMU by Joshua M. Thompson
+ *
+ * Based largely on the PowerMac PMU code by Paul Mackerras and
+ * Fabio Riccardi.
+ *
+ * Also based on the PMU driver from MkLinux by Apple Computer, Inc.
+ * and the Open Software Foundation, Inc.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* Misc minor number allocated for /dev/pmu */
+#define PMU_MINOR 154
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS 0x200 /* skip between registers */
+#define B 0 /* B-side data */
+#define A RS /* A-side data */
+#define DIRB (2*RS) /* B-side direction (1=output) */
+#define DIRA (3*RS) /* A-side direction (1=output) */
+#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
+#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
+#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
+#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
+#define SR (10*RS) /* Shift register */
+#define ACR (11*RS) /* Auxiliary control register */
+#define PCR (12*RS) /* Peripheral control register */
+#define IFR (13*RS) /* Interrupt flag register */
+#define IER (14*RS) /* Interrupt enable register */
+#define ANH (15*RS) /* A-side data, no handshake */
+
+/* Bits in B data register: both active low */
+#define TACK 0x02 /* Transfer acknowledge (input) */
+#define TREQ 0x04 /* Transfer request (output) */
+
+/* Bits in ACR */
+#define SR_CTRL 0x1c /* Shift register control bits */
+#define SR_EXT 0x0c /* Shift on external clock */
+#define SR_OUT 0x10 /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define SR_INT 0x04 /* Shift register full/empty */
+#define CB1_INT 0x10 /* transition on CB1 input */
+
+static enum pmu_state {
+ idle,
+ sending,
+ intack,
+ reading,
+ reading_intr,
+} pmu_state;
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+static struct adb_request *req_awaiting_reply;
+static unsigned char interrupt_data[32];
+static unsigned char *reply_ptr;
+static int data_index;
+static int data_len;
+static int adb_int_pending;
+static int pmu_adb_flags;
+static int adb_dev_map = 0;
+static struct adb_request bright_req_1, bright_req_2, bright_req_3;
+static int pmu_kind = PMU_UNKNOWN;
+static int pmu_fully_inited = 0;
+
+int asleep;
+struct notifier_block *sleep_notifier_list;
+
+static int pmu_probe(void);
+static int pmu_init(void);
+static void pmu_start(void);
+static void pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
+static int pmu_send_request(struct adb_request *req, int sync);
+static int pmu_autopoll(int devs);
+void pmu_poll(void);
+static int pmu_reset_bus(void);
+static int pmu_queue_request(struct adb_request *req);
+
+static void pmu_start(void);
+static void send_byte(int x);
+static void recv_byte(void);
+static void pmu_done(struct adb_request *req);
+static void pmu_handle_data(unsigned char *data, int len,
+ struct pt_regs *regs);
+static void set_volume(int level);
+
+struct adb_driver via_pmu_driver = {
+ "68K PMU",
+ pmu_probe,
+ pmu_init,
+ pmu_send_request,
+ pmu_autopoll,
+ pmu_poll,
+ pmu_reset_bus
+};
+
+/*
+ * This table indicates for each PMU opcode:
+ * - the number of data bytes to be sent with the command, or -1
+ * if a length byte should be sent,
+ * - the number of response bytes which the PMU will return, or
+ * -1 if it will send a length byte.
+ */
+static s8 pmu_data_len[256][2] = {
+/* 0 1 2 3 4 5 6 7 */
+/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
+/*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
+/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
+/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
+/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
+/*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
+/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
+/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
+/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
+/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
+/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+};
+
+int pmu_probe()
+{
+ if (macintosh_config->adb_type == MAC_ADB_PB1) {
+ pmu_kind = PMU_68K_V1;
+ } else if (macintosh_config->adb_type == MAC_ADB_PB2) {
+ pmu_kind = PMU_68K_V2;
+ } else {
+ return -ENODEV;
+ }
+
+ pmu_state = idle;
+
+ return 0;
+}
+
+static int
+pmu_init(void)
+{
+ int timeout;
+ volatile struct adb_request req;
+
+ via2[B] |= TREQ; /* negate TREQ */
+ via2[DIRB] = (via2[DIRB] | TREQ) & ~TACK; /* TACK in, TREQ out */
+
+ pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB);
+ timeout = 100000;
+ while (!req.complete) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "pmu_init: no response from PMU\n");
+ return -EAGAIN;
+ }
+ udelay(10);
+ pmu_poll();
+ }
+
+ /* ack all pending interrupts */
+ timeout = 100000;
+ interrupt_data[0] = 1;
+ while (interrupt_data[0] || pmu_state != idle) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "pmu_init: timed out acking intrs\n");
+ return -EAGAIN;
+ }
+ if (pmu_state == idle) {
+ adb_int_pending = 1;
+ pmu_interrupt(0, NULL, NULL);
+ }
+ pmu_poll();
+ udelay(10);
+ }
+
+ pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK,
+ PMU_INT_ADB_AUTO|PMU_INT_SNDBRT|PMU_INT_ADB);
+ timeout = 100000;
+ while (!req.complete) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "pmu_init: no response from PMU\n");
+ return -EAGAIN;
+ }
+ udelay(10);
+ pmu_poll();
+ }
+
+ bright_req_1.complete = 1;
+ bright_req_2.complete = 1;
+ bright_req_3.complete = 1;
+
+ if (request_irq(IRQ_MAC_ADB_SR, pmu_interrupt, 0, "pmu-shift",
+ pmu_interrupt)) {
+ printk(KERN_ERR "pmu_init: can't get irq %d\n",
+ IRQ_MAC_ADB_SR);
+ return -EAGAIN;
+ }
+ if (request_irq(IRQ_MAC_ADB_CL, pmu_interrupt, 0, "pmu-clock",
+ pmu_interrupt)) {
+ printk(KERN_ERR "pmu_init: can't get irq %d\n",
+ IRQ_MAC_ADB_CL);
+ free_irq(IRQ_MAC_ADB_SR, pmu_interrupt);
+ return -EAGAIN;
+ }
+
+ pmu_fully_inited = 1;
+
+ /* Enable backlight */
+ pmu_enable_backlight(1);
+
+ printk("adb: PMU 68K driver v0.5 for Unified ADB.\n");
+
+ return 0;
+}
+
+int
+pmu_get_model(void)
+{
+ return pmu_kind;
+}
+
+/* Send an ADB command */
+static int
+pmu_send_request(struct adb_request *req, int sync)
+{
+ int i, ret;
+
+ if (!pmu_fully_inited)
+ {
+ req->complete = 1;
+ return -ENXIO;
+ }
+
+ ret = -EINVAL;
+
+ switch (req->data[0]) {
+ case PMU_PACKET:
+ for (i = 0; i < req->nbytes - 1; ++i)
+ req->data[i] = req->data[i+1];
+ --req->nbytes;
+ if (pmu_data_len[req->data[0]][1] != 0) {
+ req->reply[0] = ADB_RET_OK;
+ req->reply_len = 1;
+ } else
+ req->reply_len = 0;
+ ret = pmu_queue_request(req);
+ break;
+ case CUDA_PACKET:
+ switch (req->data[1]) {
+ case CUDA_GET_TIME:
+ if (req->nbytes != 2)
+ break;
+ req->data[0] = PMU_READ_RTC;
+ req->nbytes = 1;
+ req->reply_len = 3;
+ req->reply[0] = CUDA_PACKET;
+ req->reply[1] = 0;
+ req->reply[2] = CUDA_GET_TIME;
+ ret = pmu_queue_request(req);
+ break;
+ case CUDA_SET_TIME:
+ if (req->nbytes != 6)
+ break;
+ req->data[0] = PMU_SET_RTC;
+ req->nbytes = 5;
+ for (i = 1; i <= 4; ++i)
+ req->data[i] = req->data[i+1];
+ req->reply_len = 3;
+ req->reply[0] = CUDA_PACKET;
+ req->reply[1] = 0;
+ req->reply[2] = CUDA_SET_TIME;
+ ret = pmu_queue_request(req);
+ break;
+ case CUDA_GET_PRAM:
+ if (req->nbytes != 4)
+ break;
+ req->data[0] = PMU_READ_NVRAM;
+ req->data[1] = req->data[2];
+ req->data[2] = req->data[3];
+ req->nbytes = 3;
+ req->reply_len = 3;
+ req->reply[0] = CUDA_PACKET;
+ req->reply[1] = 0;
+ req->reply[2] = CUDA_GET_PRAM;
+ ret = pmu_queue_request(req);
+ break;
+ case CUDA_SET_PRAM:
+ if (req->nbytes != 5)
+ break;
+ req->data[0] = PMU_WRITE_NVRAM;
+ req->data[1] = req->data[2];
+ req->data[2] = req->data[3];
+ req->data[3] = req->data[4];
+ req->nbytes = 4;
+ req->reply_len = 3;
+ req->reply[0] = CUDA_PACKET;
+ req->reply[1] = 0;
+ req->reply[2] = CUDA_SET_PRAM;
+ ret = pmu_queue_request(req);
+ break;
+ }
+ break;
+ case ADB_PACKET:
+ for (i = req->nbytes - 1; i > 1; --i)
+ req->data[i+2] = req->data[i];
+ req->data[3] = req->nbytes - 2;
+ req->data[2] = pmu_adb_flags;
+ /*req->data[1] = req->data[1];*/
+ req->data[0] = PMU_ADB_CMD;
+ req->nbytes += 2;
+ req->reply_expected = 1;
+ req->reply_len = 0;
+ ret = pmu_queue_request(req);
+ break;
+ }
+ if (ret)
+ {
+ req->complete = 1;
+ return ret;
+ }
+
+ if (sync) {
+ while (!req->complete)
+ pmu_poll();
+ }
+
+ return 0;
+}
+
+/* Enable/disable autopolling */
+static int
+pmu_autopoll(int devs)
+{
+ struct adb_request req;
+
+ if (!pmu_fully_inited) return -ENXIO;
+
+ if (devs) {
+ adb_dev_map = devs;
+ pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
+ adb_dev_map >> 8, adb_dev_map);
+ pmu_adb_flags = 2;
+ } else {
+ pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);
+ pmu_adb_flags = 0;
+ }
+ while (!req.complete)
+ pmu_poll();
+ return 0;
+}
+
+/* Reset the ADB bus */
+static int
+pmu_reset_bus(void)
+{
+ struct adb_request req;
+ long timeout;
+ int save_autopoll = adb_dev_map;
+
+ if (!pmu_fully_inited) return -ENXIO;
+
+ /* anyone got a better idea?? */
+ pmu_autopoll(0);
+
+ req.nbytes = 5;
+ req.done = NULL;
+ req.data[0] = PMU_ADB_CMD;
+ req.data[1] = 0;
+ req.data[2] = 3; /* ADB_BUSRESET ??? */
+ req.data[3] = 0;
+ req.data[4] = 0;
+ req.reply_len = 0;
+ req.reply_expected = 1;
+ if (pmu_queue_request(&req) != 0)
+ {
+ printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
+ return -EIO;
+ }
+ while (!req.complete)
+ pmu_poll();
+ timeout = 100000;
+ while (!req.complete) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
+ return -EIO;
+ }
+ udelay(10);
+ pmu_poll();
+ }
+
+ if (save_autopoll != 0)
+ pmu_autopoll(save_autopoll);
+
+ return 0;
+}
+
+/* Construct and send a pmu request */
+int
+pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
+ int nbytes, ...)
+{
+ va_list list;
+ int i;
+
+ if (nbytes < 0 || nbytes > 32) {
+ printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
+ req->complete = 1;
+ return -EINVAL;
+ }
+ req->nbytes = nbytes;
+ req->done = done;
+ va_start(list, nbytes);
+ for (i = 0; i < nbytes; ++i)
+ req->data[i] = va_arg(list, int);
+ va_end(list);
+ if (pmu_data_len[req->data[0]][1] != 0) {
+ req->reply[0] = ADB_RET_OK;
+ req->reply_len = 1;
+ } else
+ req->reply_len = 0;
+ req->reply_expected = 0;
+ return pmu_queue_request(req);
+}
+
+static int
+pmu_queue_request(struct adb_request *req)
+{
+ unsigned long flags;
+ int nsend;
+
+ if (req->nbytes <= 0) {
+ req->complete = 1;
+ return 0;
+ }
+ nsend = pmu_data_len[req->data[0]][0];
+ if (nsend >= 0 && req->nbytes != nsend + 1) {
+ req->complete = 1;
+ return -EINVAL;
+ }
+
+ req->next = 0;
+ req->sent = 0;
+ req->complete = 0;
+ save_flags(flags); cli();
+
+ if (current_req != 0) {
+ last_req->next = req;
+ last_req = req;
+ } else {
+ current_req = req;
+ last_req = req;
+ if (pmu_state == idle)
+ pmu_start();
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+static void
+send_byte(int x)
+{
+ via1[ACR] |= SR_CTRL;
+ via1[SR] = x;
+ via2[B] &= ~TREQ; /* assert TREQ */
+}
+
+static void
+recv_byte()
+{
+ char c;
+
+ via1[ACR] = (via1[ACR] | SR_EXT) & ~SR_OUT;
+ c = via1[SR]; /* resets SR */
+ via2[B] &= ~TREQ;
+}
+
+static void
+pmu_start()
+{
+ unsigned long flags;
+ struct adb_request *req;
+
+ /* assert pmu_state == idle */
+ /* get the packet to send */
+ save_flags(flags); cli();
+ req = current_req;
+ if (req == 0 || pmu_state != idle
+ || (req->reply_expected && req_awaiting_reply))
+ goto out;
+
+ pmu_state = sending;
+ data_index = 1;
+ data_len = pmu_data_len[req->data[0]][0];
+
+ /* set the shift register to shift out and send a byte */
+ send_byte(req->data[0]);
+
+out:
+ restore_flags(flags);
+}
+
+void
+pmu_poll()
+{
+ unsigned long cpu_flags;
+
+ save_flags(cpu_flags);
+ cli();
+ if (via1[IFR] & SR_INT) {
+ via1[IFR] = SR_INT;
+ pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL);
+ }
+ if (via1[IFR] & CB1_INT) {
+ via1[IFR] = CB1_INT;
+ pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL);
+ }
+ restore_flags(cpu_flags);
+}
+
+static void
+pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct adb_request *req;
+ int timeout, bite = 0; /* to prevent compiler warning */
+
+#if 0
+ printk("pmu_interrupt: irq %d state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",
+ irq, pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);
+#endif
+
+ if (irq == IRQ_MAC_ADB_CL) { /* CB1 interrupt */
+ adb_int_pending = 1;
+ } else if (irq == IRQ_MAC_ADB_SR) { /* SR interrupt */
+ if (via2[B] & TACK) {
+ printk(KERN_DEBUG "PMU: SR_INT but ack still high! (%x)\n", via2[B]);
+ }
+
+ /* if reading grab the byte */
+ if ((via1[ACR] & SR_OUT) == 0) bite = via1[SR];
+
+ /* reset TREQ and wait for TACK to go high */
+ via2[B] |= TREQ;
+ timeout = 3200;
+ while (!(via2[B] & TACK)) {
+ if (--timeout < 0) {
+ printk(KERN_ERR "PMU not responding (!ack)\n");
+ goto finish;
+ }
+ udelay(10);
+ }
+
+ switch (pmu_state) {
+ case sending:
+ req = current_req;
+ if (data_len < 0) {
+ data_len = req->nbytes - 1;
+ send_byte(data_len);
+ break;
+ }
+ if (data_index <= data_len) {
+ send_byte(req->data[data_index++]);
+ break;
+ }
+ req->sent = 1;
+ data_len = pmu_data_len[req->data[0]][1];
+ if (data_len == 0) {
+ pmu_state = idle;
+ current_req = req->next;
+ if (req->reply_expected)
+ req_awaiting_reply = req;
+ else
+ pmu_done(req);
+ } else {
+ pmu_state = reading;
+ data_index = 0;
+ reply_ptr = req->reply + req->reply_len;
+ recv_byte();
+ }
+ break;
+
+ case intack:
+ data_index = 0;
+ data_len = -1;
+ pmu_state = reading_intr;
+ reply_ptr = interrupt_data;
+ recv_byte();
+ break;
+
+ case reading:
+ case reading_intr:
+ if (data_len == -1) {
+ data_len = bite;
+ if (bite > 32)
+ printk(KERN_ERR "PMU: bad reply len %d\n",
+ bite);
+ } else {
+ reply_ptr[data_index++] = bite;
+ }
+ if (data_index < data_len) {
+ recv_byte();
+ break;
+ }
+
+ if (pmu_state == reading_intr) {
+ pmu_handle_data(interrupt_data, data_index, regs);
+ } else {
+ req = current_req;
+ current_req = req->next;
+ req->reply_len += data_index;
+ pmu_done(req);
+ }
+ pmu_state = idle;
+
+ break;
+
+ default:
+ printk(KERN_ERR "pmu_interrupt: unknown state %d?\n",
+ pmu_state);
+ }
+ }
+finish:
+ if (pmu_state == idle) {
+ if (adb_int_pending) {
+ pmu_state = intack;
+ send_byte(PMU_INT_ACK);
+ adb_int_pending = 0;
+ } else if (current_req) {
+ pmu_start();
+ }
+ }
+
+#if 0
+ printk("pmu_interrupt: exit state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",
+ pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);
+#endif
+}
+
+static void
+pmu_done(struct adb_request *req)
+{
+ req->complete = 1;
+ if (req->done)
+ (*req->done)(req);
+}
+
+/* Interrupt data could be the result data from an ADB cmd */
+static void
+pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+{
+ static int show_pmu_ints = 1;
+
+ asleep = 0;
+ if (len < 1) {
+ adb_int_pending = 0;
+ return;
+ }
+ if (data[0] & PMU_INT_ADB) {
+ if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
+ struct adb_request *req = req_awaiting_reply;
+ if (req == 0) {
+ printk(KERN_ERR "PMU: extra ADB reply\n");
+ return;
+ }
+ req_awaiting_reply = 0;
+ if (len <= 2)
+ req->reply_len = 0;
+ else {
+ memcpy(req->reply, data + 1, len - 1);
+ req->reply_len = len - 1;
+ }
+ pmu_done(req);
+ } else {
+ adb_input(data+1, len-1, regs, 1);
+ }
+ } else {
+ if (data[0] == 0x08 && len == 3) {
+ /* sound/brightness buttons pressed */
+ pmu_set_brightness(data[1] >> 3);
+ set_volume(data[2]);
+ } else if (show_pmu_ints
+ && !(data[0] == PMU_INT_TICK && len == 1)) {
+ int i;
+ printk(KERN_DEBUG "pmu intr");
+ for (i = 0; i < len; ++i)
+ printk(" %.2x", data[i]);
+ printk("\n");
+ }
+ }
+}
+
+int backlight_level = -1;
+int backlight_enabled = 0;
+
+#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1))
+
+void
+pmu_enable_backlight(int on)
+{
+ struct adb_request req;
+
+ if (on) {
+ /* first call: get current backlight value */
+ if (backlight_level < 0) {
+ switch(pmu_kind) {
+ case PMU_68K_V1:
+ case PMU_68K_V2:
+ pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
+ while (!req.complete)
+ pmu_poll();
+ printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]);
+ backlight_level = req.reply[1];
+ break;
+ default:
+ backlight_enabled = 0;
+ return;
+ }
+ }
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ LEVEL_TO_BRIGHT(backlight_level));
+ while (!req.complete)
+ pmu_poll();
+ }
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
+ while (!req.complete)
+ pmu_poll();
+ backlight_enabled = on;
+}
+
+void
+pmu_set_brightness(int level)
+{
+ int bright;
+
+ backlight_level = level;
+ bright = LEVEL_TO_BRIGHT(level);
+ if (!backlight_enabled)
+ return;
+ if (bright_req_1.complete)
+ pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ bright);
+ if (bright_req_2.complete)
+ pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));
+}
+
+void
+pmu_enable_irled(int on)
+{
+ struct adb_request req;
+
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
+ (on ? PMU_POW_ON : PMU_POW_OFF));
+ while (!req.complete)
+ pmu_poll();
+}
+
+static void
+set_volume(int level)
+{
+}
+
+int
+pmu_present(void)
+{
+ return (pmu_kind != PMU_UNKNOWN);
+}
+
+#if 0 /* needs some work for 68K */
+
+/*
+ * This struct is used to store config register values for
+ * PCI devices which may get powered off when we sleep.
+ */
+static struct pci_save {
+ u16 command;
+ u16 cache_lat;
+ u16 intr;
+} *pbook_pci_saves;
+static int n_pbook_pci_saves;
+
+static inline void __openfirmware
+pbook_pci_save(void)
+{
+ int npci;
+ struct pci_dev *pd;
+ struct pci_save *ps;
+
+ npci = 0;
+ for (pd = pci_devices; pd != NULL; pd = pd->next)
+ ++npci;
+ n_pbook_pci_saves = npci;
+ if (npci == 0)
+ return;
+ ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL);
+ pbook_pci_saves = ps;
+ if (ps == NULL)
+ return;
+
+ for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) {
+ pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+ pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
+ pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
+ ++ps;
+ --npci;
+ }
+}
+
+static inline void __openfirmware
+pbook_pci_restore(void)
+{
+ u16 cmd;
+ struct pci_save *ps = pbook_pci_saves;
+ struct pci_dev *pd;
+ int j;
+
+ for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) {
+ if (ps->command == 0)
+ continue;
+ pci_read_config_word(pd, PCI_COMMAND, &cmd);
+ if ((ps->command & ~cmd) == 0)
+ continue;
+ switch (pd->hdr_type) {
+ case PCI_HEADER_TYPE_NORMAL:
+ for (j = 0; j < 6; ++j)
+ pci_write_config_dword(pd,
+ PCI_BASE_ADDRESS_0 + j*4,
+ pd->resource[j].start);
+ pci_write_config_dword(pd, PCI_ROM_ADDRESS,
+ pd->resource[PCI_ROM_RESOURCE].start);
+ pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
+ ps->cache_lat);
+ pci_write_config_word(pd, PCI_INTERRUPT_LINE,
+ ps->intr);
+ pci_write_config_word(pd, PCI_COMMAND, ps->command);
+ break;
+ /* other header types not restored at present */
+ }
+ }
+}
+
+/*
+ * Put the powerbook to sleep.
+ */
+#define IRQ_ENABLE ((unsigned int *)0xf3000024)
+#define MEM_CTRL ((unsigned int *)0xf8000070)
+
+int __openfirmware powerbook_sleep(void)
+{
+ int ret, i, x;
+ static int save_backlight;
+ static unsigned int save_irqen;
+ unsigned long msr;
+ unsigned int hid0;
+ unsigned long p, wait;
+ struct adb_request sleep_req;
+
+ /* Notify device drivers */
+ ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL);
+ if (ret & NOTIFY_STOP_MASK)
+ return -EBUSY;
+
+ /* Sync the disks. */
+ /* XXX It would be nice to have some way to ensure that
+ * nobody is dirtying any new buffers while we wait. */
+ fsync_dev(0);
+
+ /* Turn off the display backlight */
+ save_backlight = backlight_enabled;
+ if (save_backlight)
+ pmu_enable_backlight(0);
+
+ /* Give the disks a little time to actually finish writing */
+ for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+ mb();
+
+ /* Disable all interrupts except pmu */
+ save_irqen = in_le32(IRQ_ENABLE);
+ for (i = 0; i < 32; ++i)
+ if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
+ disable_irq(i);
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+ /* Save the state of PCI config space for some slots */
+ pbook_pci_save();
+
+ /* Set the memory controller to keep the memory refreshed
+ while we're asleep */
+ for (i = 0x403f; i >= 0x4000; --i) {
+ out_be32(MEM_CTRL, i);
+ do {
+ x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;
+ } while (x == 0);
+ if (x >= 0x100)
+ break;
+ }
+
+ /* Ask the PMU to put us to sleep */
+ pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!sleep_req.complete)
+ mb();
+ /* displacement-flush the L2 cache - necessary? */
+ for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
+ i = *(volatile int *)p;
+ asleep = 1;
+
+ /* Put the CPU into sleep mode */
+ asm volatile("mfspr %0,1008" : "=r" (hid0) :);
+ hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
+ asm volatile("mtspr 1008,%0" : : "r" (hid0));
+ save_flags(msr);
+ msr |= MSR_POW | MSR_EE;
+ restore_flags(msr);
+ udelay(10);
+
+ /* OK, we're awake again, start restoring things */
+ out_be32(MEM_CTRL, 0x3f);
+ pbook_pci_restore();
+
+ /* wait for the PMU interrupt sequence to complete */
+ while (asleep)
+ mb();
+
+ /* reenable interrupts */
+ for (i = 0; i < 32; ++i)
+ if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
+ enable_irq(i);
+
+ /* Notify drivers */
+ notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
+
+ /* reenable ADB autopoll */
+ pmu_adb_autopoll(adb_dev_map);
+
+ /* Turn on the screen backlight, if it was on before */
+ if (save_backlight)
+ pmu_enable_backlight(1);
+
+ /* Wait for the hard disk to spin up */
+
+ return 0;
+}
+
+/*
+ * Support for /dev/pmu device
+ */
+static int __openfirmware pmu_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static ssize_t __openfirmware pmu_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+/* Note: removed __openfirmware here since it causes link errors */
+static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp,
+ u_int cmd, u_long arg)
+{
+ int error;
+ __u32 value;
+
+ switch (cmd) {
+ case PMU_IOC_SLEEP:
+ return -ENOSYS;
+ case PMU_IOC_GET_BACKLIGHT:
+ return put_user(backlight_level, (__u32 *)arg);
+ case PMU_IOC_SET_BACKLIGHT:
+ error = get_user(value, (__u32 *)arg);
+ if (!error)
+ pmu_set_brightness(value);
+ return error;
+ case PMU_IOC_GET_MODEL:
+ return put_user(pmu_kind, (__u32 *)arg);
+ }
+ return -EINVAL;
+}
+
+static struct file_operations pmu_device_fops = {
+ NULL, /* no seek */
+ pmu_read,
+ pmu_write,
+ NULL, /* no readdir */
+ NULL, /* no poll yet */
+ pmu_ioctl,
+ NULL, /* no mmap */
+ pmu_open,
+ NULL, /* flush */
+ NULL /* no release */
+};
+
+static struct miscdevice pmu_device = {
+ PMU_MINOR, "pmu", &pmu_device_fops
+};
+
+void pmu_device_init(void)
+{
+ if (via)
+ misc_register(&pmu_device);
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 1bd65d54f..d66393649 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -101,6 +101,7 @@
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/ioport.h>
+#include <linux/spinlock.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -183,23 +184,9 @@ static const int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
/* Dma Memory related stuff */
-/* Pure 2^n version of get_order */
-static inline int __get_order(unsigned long size)
-{
- int order;
-
- size = (size - 1) >> (PAGE_SHIFT - 1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
static unsigned long dma_mem_alloc(int size)
{
- int order = __get_order(size);
+ int order = get_order(size);
return __get_dma_pages(GFP_KERNEL, order);
}
@@ -374,7 +361,8 @@ static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char b
static inline void prime_rx(struct net_device *dev)
{
elp_device *adapter = dev->priv;
- while (adapter->rx_active < ELP_RX_PCBS && dev->start) {
+ while (adapter->rx_active < ELP_RX_PCBS &&
+ netif_running(dev->state)) {
if (!start_receive(dev, &adapter->itx_pcb))
break;
}
@@ -672,23 +660,10 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
elp_device *adapter;
int timeout;
- if (irq < 0 || irq > 15) {
- printk("elp_interrupt(): illegal IRQ number found in interrupt routine (%i)\n", irq);
- return;
- }
dev = dev_id;
-
- if (dev == NULL) {
- printk("elp_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
adapter = (elp_device *) dev->priv;
-
- if (dev->interrupt) {
- printk("%s: re-entering the interrupt handler!\n", dev->name);
- return;
- }
- dev->interrupt = 1;
+
+ spin_lock(&adapter->lock);
do {
/*
@@ -702,20 +677,19 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
printk("%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr));
}
- outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR),
- dev);
+ outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
if (adapter->current_dma.direction) {
- dev_kfree_skb(adapter->current_dma.skb);
+ dev_kfree_skb_irq(adapter->current_dma.skb);
} else {
struct sk_buff *skb = adapter->current_dma.skb;
if (skb) {
- if (adapter->current_dma.target) {
- /* have already done the skb_put() */
- memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
- }
- skb->protocol = eth_type_trans(skb,dev);
- adapter->stats.rx_bytes += skb->len;
- netif_rx(skb);
+ if (adapter->current_dma.target) {
+ /* have already done the skb_put() */
+ memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
+ }
+ skb->protocol = eth_type_trans(skb,dev);
+ adapter->stats.rx_bytes += skb->len;
+ netif_rx(skb);
}
}
adapter->dmaing = 0;
@@ -733,15 +707,14 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
check_3c505_dma(dev);
}
- sti();
-
/*
* receive a PCB from the adapter
*/
timeout = jiffies + 3*HZ/100;
while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
if (receive_pcb(dev, &adapter->irx_pcb)) {
- switch (adapter->irx_pcb.command) {
+ switch (adapter->irx_pcb.command)
+ {
case 0:
break;
/*
@@ -750,19 +723,15 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
case 0xff:
case CMD_RECEIVE_PACKET_COMPLETE:
/* if the device isn't open, don't pass packets up the stack */
- if (dev->start == 0)
+ if (!netif_running(dev))
break;
- cli();
len = adapter->irx_pcb.data.rcv_resp.pkt_len;
dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
- printk("%s: interrupt - packet not received correctly\n", dev->name);
- sti();
+ printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name);
} else {
if (elp_debug >= 3) {
- sti();
printk("%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);
- cli();
}
if (adapter->irx_pcb.command == 0xff) {
if (elp_debug >= 2)
@@ -772,7 +741,6 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
} else {
receive_packet(dev, dlen);
}
- sti();
if (elp_debug >= 3)
printk("%s: packet received\n", dev->name);
}
@@ -839,7 +807,7 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
case CMD_TRANSMIT_PACKET_COMPLETE:
if (elp_debug >= 3)
printk("%s: interrupt - packet sent\n", dev->name);
- if (dev->start == 0)
+ if (!netif_running(dev))
break;
switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
case 0xffff:
@@ -851,8 +819,7 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
break;
}
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
break;
/*
@@ -875,7 +842,7 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
/*
* indicate no longer in interrupt routine
*/
- dev->interrupt = 0;
+ spin_unlock(&adapter->lock);
}
@@ -913,16 +880,6 @@ static int elp_open(struct net_device *dev)
adapter_reset(dev);
/*
- * interrupt routine not entered
- */
- dev->interrupt = 0;
-
- /*
- * transmitter not busy
- */
- dev->tbusy = 0;
-
- /*
* no receive PCBs active
*/
adapter->rx_active = 0;
@@ -931,6 +888,8 @@ static int elp_open(struct net_device *dev)
adapter->send_pcb_semaphore = 0;
adapter->rx_backlog.in = 0;
adapter->rx_backlog.out = 0;
+
+ spin_lock_init(&adapter->lock);
/*
* install our interrupt service routine
@@ -1008,8 +967,8 @@ static int elp_open(struct net_device *dev)
/*
* device is now officially open!
*/
- dev->start = 1;
+ netif_wake_queue(dev);
MOD_INC_USE_COUNT;
return 0; /* Always succeed */
@@ -1085,6 +1044,25 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
return TRUE;
}
+/*
+ * The upper layer thinks we timed out
+ */
+
+static void elp_timeout(struct net_device *dev)
+{
+ unsigned long flags;
+ elp_device *adapter = dev->priv;
+ int stat;
+
+ stat = inb_status(dev->base_addr);
+ printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");
+ if (elp_debug >= 1)
+ printk("%s: status %#02x\n", dev->name, stat);
+ dev->trans_start = jiffies;
+ adapter->stats.tx_dropped++;
+ netif_wake_queue(dev);
+}
+
/******************************************************
*
* start the transmitter
@@ -1094,40 +1072,17 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- if (dev->interrupt) {
- printk("%s: start_xmit aborted (in irq)\n", dev->name);
- return 1;
- }
-
+ unsigned long flags;
+ elp_device *adapter = dev->priv;
+
+ spin_lock_irqsave(&adapter->lock, flags);
check_3c505_dma(dev);
- /*
- * if the transmitter is still busy, we have a transmit timeout...
- */
- if (dev->tbusy) {
- elp_device *adapter = dev->priv;
- int tickssofar = jiffies - dev->trans_start;
- int stat;
-
- if (tickssofar < 1000)
- return 1;
-
- stat = inb_status(dev->base_addr);
- printk("%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");
- if (elp_debug >= 1)
- printk("%s: status %#02x\n", dev->name, stat);
- dev->trans_start = jiffies;
- dev->tbusy = 0;
- adapter->stats.tx_dropped++;
- }
-
if (elp_debug >= 3)
printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
- if (test_and_set_bit(0, (void *) &dev->tbusy)) {
- printk("%s: transmitter access conflict\n", dev->name);
- return 1;
- }
+ netif_stop_queue(dev);
+
/*
* send the packet at skb->data for skb->len
*/
@@ -1135,7 +1090,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (elp_debug >= 2) {
printk("%s: failed to transmit packet\n", dev->name);
}
- dev->tbusy = 0;
+ spin_unlock_irqrestore(&adapter->lock, flags);
return 1;
}
if (elp_debug >= 3)
@@ -1147,7 +1102,8 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
prime_rx(dev);
-
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ netif_start_queue(dev);
return 0;
}
@@ -1166,7 +1122,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev)
/* If the device is closed, just return the latest stats we have,
- we cannot ask from the adapter without interrupts */
- if (!dev->start)
+ if (!netif_running(dev))
return &adapter->stats;
/* send a get statistics command to the board */
@@ -1203,6 +1159,8 @@ static int elp_close(struct net_device *dev)
if (elp_debug >= 3)
printk("%s: request to close device\n", dev->name);
+ netif_stop_queue(dev);
+
/* Someone may request the device statistic information even when
* the interface is closed. The following will update the statistics
* structure in the driver, so we'll be able to give current statistics.
@@ -1215,22 +1173,12 @@ static int elp_close(struct net_device *dev)
outb_control(0, dev);
/*
- * flag transmitter as busy (i.e. not available)
- */
- dev->tbusy = 1;
-
- /*
- * indicate device is closed
- */
- dev->start = 0;
-
- /*
* release the IRQ
*/
free_irq(dev->irq, dev);
free_dma(dev->dma);
- free_pages((unsigned long) adapter->dma_buffer, __get_order(DMA_BUFFER_SIZE));
+ free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
MOD_DEC_USE_COUNT;
@@ -1252,10 +1200,13 @@ static void elp_set_mc_list(struct net_device *dev)
elp_device *adapter = (elp_device *) dev->priv;
struct dev_mc_list *dmi = dev->mc_list;
int i;
+ unsigned long flags;
if (elp_debug >= 3)
printk("%s: request to set multicast list\n", dev->name);
+ spin_lock_irqsave(&adapter->lock, flags);
+
if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
/* send a "load multicast list" command to the board, max 10 addrs/cmd */
/* if num_addrs==0 the list will be cleared */
@@ -1291,9 +1242,13 @@ static void elp_set_mc_list(struct net_device *dev)
adapter->tx_pcb.length = 2;
adapter->got[CMD_CONFIGURE_82586] = 0;
if (!send_pcb(dev, &adapter->tx_pcb))
+ {
+ spin_unlock_irqrestore(&lp->lock, flags);
printk("%s: couldn't send 82586 configure command\n", dev->name);
+ }
else {
int timeout = jiffies + TIMEOUT;
+ spin_unlock_irqrestore(&lp->lock, flags);
while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout))
TIMEOUT_MSG(__LINE__);
@@ -1313,10 +1268,12 @@ static inline void elp_init(struct net_device *dev)
/*
* set ptrs to various functions
*/
- dev->open = elp_open; /* local */
- dev->stop = elp_close; /* local */
- dev->get_stats = elp_get_stats; /* local */
- dev->hard_start_xmit = elp_start_xmit; /* local */
+ dev->open = elp_open; /* local */
+ dev->stop = elp_close; /* local */
+ dev->get_stats = elp_get_stats; /* local */
+ dev->hard_start_xmit = elp_start_xmit; /* local */
+ dev->tx_timeout = elp_timeout; /* local */
+ dev->watchdog_timeo = 10*HZ;
dev->set_multicast_list = elp_set_mc_list; /* local */
/* Setup the generic properties */
diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
index 41993d4ec..1cbf41fae 100644
--- a/drivers/net/3c505.h
+++ b/drivers/net/3c505.h
@@ -289,4 +289,5 @@ typedef struct {
unsigned int rx_active; /* number of receive PCBs */
volatile unsigned char hcr_val; /* what we think the HCR contains */
+ spinlock_t lock; /* Interrupt v tx lock */
} elp_device;
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 2a6ddac7a..faecb72ad 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -199,6 +199,8 @@ struct net_local {
#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
#define RX_BUF_END (dev->mem_end - dev->mem_start)
+#define TX_TIMEOUT 5
+
/*
That's it: only 86 bytes to set up the beast, including every extra
command available. The 170 byte buffer at DUMP_DATA is shared between the
@@ -287,6 +289,7 @@ static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void el16_rx(struct net_device *dev);
static int el16_close(struct net_device *dev);
static struct net_device_stats *el16_get_stats(struct net_device *dev);
+static void el16_tx_timeout (struct net_device *dev);
static void hardware_send_packet(struct net_device *dev, void *buf, short length);
static void init_82586_mem(struct net_device *dev);
@@ -325,7 +328,7 @@ int __init el16_probe(struct net_device *dev)
return ENODEV;
}
-int __init el16_probe1(struct net_device *dev, int ioaddr)
+static int __init el16_probe1(struct net_device *dev, int ioaddr)
{
static unsigned char init_ID_done = 0, version_printed = 0;
int i, irq, irqval;
@@ -423,6 +426,8 @@ int __init el16_probe1(struct net_device *dev, int ioaddr)
dev->stop = el16_close;
dev->hard_start_xmit = el16_send_packet;
dev->get_stats = el16_get_stats;
+ dev->tx_timeout = el16_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
ether_setup(dev); /* Generic ethernet behaviour */
@@ -443,62 +448,59 @@ static int el16_open(struct net_device *dev)
return 0;
}
-static int el16_send_packet(struct sk_buff *skb, struct net_device *dev)
+
+static void el16_tx_timeout (struct net_device *dev)
{
- struct net_local *lp = (struct net_local *)dev->priv;
+ struct net_local *lp = (struct net_local *) dev->priv;
int ioaddr = dev->base_addr;
unsigned long shmem = dev->mem_start;
- unsigned long flags;
-#if 0 /* LINK_STATE_XOFF is never set when we reach here */
- if (test_bit(LINK_STATE_XOFF, &dev->flags))
- {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
+ if (net_debug > 1)
+ printk ("%s: transmit timed out, %s? ", dev->name,
+ isa_readw (shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
+ "network cable problem");
+ /* Try to restart the adaptor. */
+ if (lp->last_restart == lp->stats.tx_packets) {
if (net_debug > 1)
- printk("%s: transmit timed out, %s? ", dev->name,
- isa_readw(shmem+iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
- "network cable problem");
- /* Try to restart the adaptor. */
- if (lp->last_restart == lp->stats.tx_packets) {
- if (net_debug > 1) printk("Resetting board.\n");
- /* Completely reset the adaptor. */
- init_82586_mem(dev);
- } else {
- /* Issue the channel attention signal and hope it "gets better". */
- if (net_debug > 1) printk("Kicking board.\n");
- isa_writew(0xf000|CUC_START|RX_START,shmem+iSCB_CMD);
- outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
- lp->last_restart = lp->stats.tx_packets;
- }
- netif_start_queue(dev);
- dev->trans_start = jiffies;
+ printk ("Resetting board.\n");
+ /* Completely reset the adaptor. */
+ init_82586_mem (dev);
+ } else {
+ /* Issue the channel attention signal and hope it "gets better". */
+ if (net_debug > 1)
+ printk ("Kicking board.\n");
+ isa_writew (0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
+ outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
+ lp->last_restart = lp->stats.tx_packets;
}
-#endif
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+}
- {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
- spin_lock_irqsave(&lp->lock, flags);
+static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *) dev->priv;
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
- lp->stats.tx_bytes+=length;
- /* Disable the 82586's input to the interrupt line. */
- outb(0x80, ioaddr + MISC_CTRL);
+ netif_stop_queue (dev);
- hardware_send_packet(dev, buf, length);
+ spin_lock_irqsave (&lp->lock, flags);
- dev->trans_start = jiffies;
- /* Enable the 82586 interrupt input. */
- outb(0x84, ioaddr + MISC_CTRL);
+ lp->stats.tx_bytes += length;
+ /* Disable the 82586's input to the interrupt line. */
+ outb (0x80, ioaddr + MISC_CTRL);
- spin_unlock_irqrestore(&lp->lock, flags);
+ hardware_send_packet (dev, buf, length);
- netif_stop_queue(dev);
- }
+ dev->trans_start = jiffies;
+ /* Enable the 82586 interrupt input. */
+ outb (0x84, ioaddr + MISC_CTRL);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
dev_kfree_skb (skb);
@@ -574,8 +576,7 @@ static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* Acknowledge the interrupt sources. */
ack_cmd = status & 0xf000;
- if ((status & 0x0700) != 0x0200 &&
- (test_bit(LINK_STATE_START, &dev->state))) {
+ if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
if (net_debug)
printk("%s: Command unit stopped, status %04x, restarting.\n",
dev->name, status);
@@ -585,9 +586,7 @@ static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ack_cmd |= CUC_RESUME;
}
- if ((status & 0x0070) != 0x0040 &&
- (test_bit(LINK_STATE_START, &dev->state)))
- {
+ if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
static void init_rx_bufs(struct net_device *);
/* The Rx unit is not ready, it must be hung. Restart the receiver by
initializing the rx buffers, and issuing an Rx start command. */
@@ -788,7 +787,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length
}
if (lp->tx_head != lp->tx_reap)
- netif_start_queue(dev);
+ netif_wake_queue(dev);
}
static void el16_rx(struct net_device *dev)
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 07038b4ba..06a616592 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -412,6 +412,9 @@ no_pnp:
}
}
+ if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509"))
+ return -EBUSY;
+
/* Set the adaptor tag so that the next card can be found. */
outb(0xd0 + ++current_tag, id_port);
@@ -419,22 +422,26 @@ no_pnp:
outb((ioaddr >> 4) | 0xe0, id_port);
EL3WINDOW(0);
- if (inw(ioaddr) != 0x6d50)
+ if (inw(ioaddr) != 0x6d50) {
+ release_region(ioaddr, EL3_IO_EXTENT);
return -ENODEV;
+ }
/* Free the interrupt so that some other card can use it. */
outw(0x0f00, ioaddr + WN0_IRQ);
found:
if (dev == NULL) {
dev = init_etherdev(dev, sizeof(struct el3_private));
+ if (dev == NULL) {
+ release_region(ioaddr, EL3_IO_EXTENT);
+ return -ENOMEM;
+ }
}
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
dev->base_addr = ioaddr;
dev->irq = irq;
dev->if_port = (dev->mem_start & 0x1f) ? dev->mem_start & 3 : if_port;
- request_region(dev->base_addr, EL3_IO_EXTENT, "3c509");
-
{
const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
printk("%s: 3c509 at %#3.3lx, %s port, address ",
@@ -599,7 +606,7 @@ el3_tx_timeout (struct net_device *dev)
/* Issue TX_RESET and TX_START commands. */
outw(TxReset, ioaddr + EL3_CMD);
outw(TxEnable, ioaddr + EL3_CMD);
- netif_start_queue(dev);
+ netif_wake_queue(dev);
}
@@ -610,6 +617,8 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
int ioaddr = dev->base_addr;
unsigned long flags;
+ netif_stop_queue (dev);
+
lp->stats.tx_bytes += skb->len;
if (el3_debug > 4) {
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 5012dae6e..36f15f0cb 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -10,17 +10,22 @@
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
*/
-static char *version = "3c515.c:v0.99 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "3c515.c:v0.99-sn 2000/02/12 becker@cesdis.gsfc.nasa.gov and others\n";
+
#define CORKSCREW 1
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1512 effectively disables this feature. */
static const int rx_copybreak = 200;
+
/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
static const int mtu = 1500;
+
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
@@ -37,7 +42,7 @@ static int max_interrupt_work = 20;
/* Keep the ring sizes a power of two for efficiency. */
#define TX_RING_SIZE 16
#define RX_RING_SIZE 16
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
#include <linux/module.h>
#include <linux/version.h>
@@ -65,15 +70,10 @@ static int max_interrupt_work = 20;
/* Kernel version compatibility functions. */
#define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
-#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
-#if (LINUX_VERSION_CODE < 0x20123)
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#elif defined(MODULE)
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
MODULE_PARM(debug, "i");
@@ -81,7 +81,6 @@ MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(max_interrupt_work, "i");
-#endif
/* "Knobs" for adjusting internal parameters. */
/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
@@ -102,15 +101,10 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
*/
#define CORKSCREW_TOTAL_SIZE 0x20
-#ifdef HAVE_DEVLIST
-struct netdev_entry tc515_drv =
-{"3c515", tc515_probe, CORKSCREW_TOTAL_SIZE, NULL};
-#endif
-
#ifdef DRIVER_DEBUG
-int vortex_debug = DRIVER_DEBUG;
+int corkscrew_debug = DRIVER_DEBUG;
#else
-int vortex_debug = 1;
+int corkscrew_debug = 1;
#endif
#define CORKSCREW_ID 10
@@ -149,8 +143,8 @@ correctly-sized skbuff.
IIIC. Synchronization
The driver runs as two independent, single-threaded flows of control. One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag. The other thread is the interrupt handler, which is single
+is the send-packet routine, which enforces single-threaded use by the netif
+layer. The other thread is the interrupt handler, which is single
threaded by the hardware and other software.
IV. Notes
@@ -184,87 +178,98 @@ of 1.5K, but the changes to support 4.5K are minimal.
can handle FDDI length frames (~4500 octets) and now parameters count
32-bit 'Dwords' rather than octets. */
-enum vortex_cmd {
- TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
- RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
- UpStall = 6<<11, UpUnstall = (6<<11)+1,
- DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
- RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
- FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
- SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
- SetTxThreshold = 18<<11, SetTxStart = 19<<11,
- StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
- StatsDisable = 22<<11, StopCoax = 23<<11,};
+enum corkscrew_cmd {
+ TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
+ RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
+ UpStall = 6 << 11, UpUnstall = (6 << 11) + 1,
+ DownStall = (6 << 11) + 2, DownUnstall = (6 << 11) + 3,
+ RxDiscard = 8 << 11, TxEnable = 9 << 11, TxDisable =
+ 10 << 11, TxReset = 11 << 11,
+ FakeIntr = 12 << 11, AckIntr = 13 << 11, SetIntrEnb = 14 << 11,
+ SetStatusEnb = 15 << 11, SetRxFilter = 16 << 11, SetRxThreshold =
+ 17 << 11,
+ SetTxThreshold = 18 << 11, SetTxStart = 19 << 11,
+ StartDMAUp = 20 << 11, StartDMADown = (20 << 11) + 1, StatsEnable =
+ 21 << 11,
+ StatsDisable = 22 << 11, StopCoax = 23 << 11,
+};
/* The SetRxFilter command accepts the following classes: */
enum RxFilter {
- RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
+ RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+};
/* Bits in the general status register. */
-enum vortex_status {
+enum corkscrew_status {
IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
IntReq = 0x0040, StatsFull = 0x0080,
- DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
- DMAInProgress = 1<<11, /* DMA controller is still busy.*/
- CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/
+ DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10,
+ DMAInProgress = 1 << 11, /* DMA controller is still busy. */
+ CmdInProgress = 1 << 12, /* EL3_CMD is still busy. */
};
/* Register window 1 offsets, the window used in normal operation.
On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */
enum Window1 {
- TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
- RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B,
- TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
+ TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
+ RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B,
+ TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
};
enum Window0 {
- Wn0IRQ = 0x08,
+ Wn0IRQ = 0x08,
#if defined(CORKSCREW)
- Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */
- Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */
+ Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */
+ Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */
#else
- Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
- Wn0EepromData = 12, /* Window 0: EEPROM results register. */
+ Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
+ Wn0EepromData = 12, /* Window 0: EEPROM results register. */
#endif
};
enum Win0_EEPROM_bits {
EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
- EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
- EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
+ EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
+ EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
};
+
/* EEPROM locations. */
enum eeprom_offset {
- PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
- EtherLink3ID=7, };
+ PhysAddr01 = 0, PhysAddr23 = 1, PhysAddr45 = 2, ModelID = 3,
+ EtherLink3ID = 7,
+};
enum Window3 { /* Window 3: MAC/config bits. */
- Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
+ Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
};
union wn3_config {
int i;
struct w3_config_fields {
- unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
+ unsigned int ram_size:3, ram_width:1, ram_speed:2,
+ rom_size:2;
int pad8:8;
- unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
+ unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1,
+ autoselect:1;
int pad24:7;
} u;
};
enum Window4 {
- Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */
+ Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */
};
enum Win4_Media_bits {
- Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
+ Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
- Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
+ Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
Media_LnkBeat = 0x0800,
};
-enum Window7 { /* Window 7: Bus Master control. */
+enum Window7 { /* Window 7: Bus Master control. */
Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
};
+
/* Boomerang-style bus master control registers. Note ISA aliases! */
enum MasterCtrl {
- PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen = 0x40c,
+ PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen =
+ 0x40c,
TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418,
};
@@ -277,9 +282,10 @@ struct boom_rx_desc {
u32 addr;
s32 length;
};
+
/* Values for the Rx status entry. */
enum rx_desc_status {
- RxDComplete=0x00008000, RxDError=0x4000,
+ RxDComplete = 0x00008000, RxDError = 0x4000,
/* See boomerang_rx() for actual error bits */
};
@@ -290,111 +296,112 @@ struct boom_tx_desc {
s32 length;
};
-struct vortex_private {
- char devname[8]; /* "ethN" string, also for kernel debug. */
+struct corkscrew_private {
+ char devname[8]; /* "ethN" string, also for kernel debug. */
const char *product_name;
struct net_device *next_module;
/* The Rx and Tx rings are here to keep them quad-word-aligned. */
struct boom_rx_desc rx_ring[RX_RING_SIZE];
struct boom_tx_desc tx_ring[TX_RING_SIZE];
/* The addresses of transmit- and receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- unsigned int cur_rx, cur_tx; /* The next free ring entry */
- unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ unsigned int cur_rx, cur_tx; /* The next free ring entry */
+ unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
struct enet_statistics stats;
- struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
+ struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
struct timer_list timer; /* Media selection timer. */
- int capabilities; /* Adapter capabilities word. */
- int options; /* User-settable misc. driver options. */
+ int capabilities ; /* Adapter capabilities word. */
+ int options; /* User-settable misc. driver options. */
int last_rx_packets; /* For media autoselection. */
unsigned int available_media:8, /* From Wn3_Options */
- media_override:3, /* Passed-in media type. */
- default_media:3, /* Read from the EEPROM. */
- full_duplex:1, autoselect:1,
- bus_master:1, /* Vortex can only do a fragment bus-m. */
- full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */
- tx_full:1;
+ media_override:3, /* Passed-in media type. */
+ default_media:3, /* Read from the EEPROM. */
+ full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */
+ full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */
+ tx_full:1;
};
/* The action to take with a media selection timer tick.
Note that we deviate from the 3Com order by checking 10base2 before AUI.
*/
enum xcvr_types {
- XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
- XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8,
+ XCVR_10baseT =
+ 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
+ XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8,
};
static struct media_table {
- char *name;
- unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
- mask:8, /* The transceiver-present bit in Wn3_Config.*/
- next:8; /* The media type to try next. */
- short wait; /* Time before we check media status. */
-} media_tbl[] = {
- { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
- { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
- { "undefined", 0, 0x80, XCVR_10baseT, 10000},
- { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10},
- { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
- { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10},
- { "MII", 0, 0x40, XCVR_10baseT, 3*HZ },
- { "undefined", 0, 0x01, XCVR_10baseT, 10000},
- { "Default", 0, 0xFF, XCVR_10baseT, 10000},
+ char *name;
+ unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
+ mask:8, /* The transceiver-present bit in Wn3_Config. */
+ next:8; /* The media type to try next. */
+ short wait; /* Time before we check media status. */
+} media_tbl[] = {
+ { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
+ { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
+ { "undefined", 0, 0x80, XCVR_10baseT, 10000},
+ { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
+ { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
+ { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
+ { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
+ { "undefined", 0, 0x01, XCVR_10baseT, 10000},
+ { "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
-static int vortex_scan(struct net_device *dev);
-static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr,
- int irq, int product_index,
- int options);
-static int vortex_probe1(struct net_device *dev);
-static int vortex_open(struct net_device *dev);
-static void vortex_timer(unsigned long arg);
-static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int vortex_rx(struct net_device *dev);
+static int corkscrew_scan(struct net_device *dev);
+static struct net_device *corkscrew_found_device(struct net_device *dev,
+ int ioaddr, int irq,
+ int product_index,
+ int options);
+static int corkscrew_probe1(struct net_device *dev);
+static int corkscrew_open(struct net_device *dev);
+static void corkscrew_timer(unsigned long arg);
+static int corkscrew_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+static int corkscrew_rx(struct net_device *dev);
+static void corkscrew_timeout(struct net_device *dev);
static int boomerang_rx(struct net_device *dev);
-static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
-static int vortex_close(struct net_device *dev);
+static void corkscrew_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs);
+static int corkscrew_close(struct net_device *dev);
static void update_stats(int addr, struct net_device *dev);
-static struct enet_statistics *vortex_get_stats(struct net_device *dev);
+static struct enet_statistics *corkscrew_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-/* Unlike the other PCI cards the 59x cards don't need a large contiguous
- memory region, so making the driver a loadable module is feasible.
-
+/*
Unfortunately maximizing the shared code between the integrated and
module version of the driver results in a complicated set of initialization
procedures.
init_module() -- modules / tc59x_init() -- built-in
- The wrappers for vortex_scan()
- vortex_scan() The common routine that scans for PCI and EISA cards
- vortex_found_device() Allocate a device structure when we find a card.
+ The wrappers for corkscrew_scan()
+ corkscrew_scan() The common routine that scans for PCI and EISA cards
+ corkscrew_found_device() Allocate a device structure when we find a card.
Different versions exist for modules and built-in.
- vortex_probe1() Fill in the device structure -- this is separated
+ corkscrew_probe1() Fill in the device structure -- this is separated
so that the modules code can put it in dev->init.
*/
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
/* Note: this is the only limit on the number of cards supported!! */
-static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1, };
#ifdef MODULE
static int debug = -1;
/* A list of all installed Vortex devices, for removing the driver module. */
-static struct net_device *root_vortex_dev = NULL;
+static struct net_device *root_corkscrew_dev = NULL;
-int
-init_module(void)
+int init_module(void)
{
int cards_found;
if (debug >= 0)
- vortex_debug = debug;
- if (vortex_debug)
+ corkscrew_debug = debug;
+ if (corkscrew_debug)
printk(version);
- root_vortex_dev = NULL;
- cards_found = vortex_scan(0);
+ root_corkscrew_dev = NULL;
+ cards_found = corkscrew_scan(0);
return cards_found ? 0 : -ENODEV;
}
@@ -403,80 +410,86 @@ int tc515_probe(struct net_device *dev)
{
int cards_found = 0;
- cards_found = vortex_scan(dev);
+ cards_found = corkscrew_scan(dev);
- if (vortex_debug > 0 && cards_found)
+ if (corkscrew_debug > 0 && cards_found)
printk(version);
return cards_found ? 0 : -ENODEV;
}
-#endif /* not MODULE */
+#endif /* not MODULE */
-static int vortex_scan(struct net_device *dev)
+static int corkscrew_scan(struct net_device *dev)
{
int cards_found = 0;
static int ioaddr = 0x100;
/* Check all locations on the ISA bus -- evil! */
for (; ioaddr < 0x400; ioaddr += 0x20) {
- int irq;
- if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE))
- continue;
- /* Check the resource configuration for a matching ioaddr. */
- if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0))
- continue;
- /* Verify by reading the device ID from the EEPROM. */
- {
- int timer;
- outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd);
- /* Pause for at least 162 us. for the read to take place. */
- for (timer = 4; timer >= 0; timer--) {
- udelay(162);
- if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
- break;
+ int irq;
+ if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE))
+ continue;
+ /* Check the resource configuration for a matching ioaddr. */
+ if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0))
+ continue;
+ /* Verify by reading the device ID from the EEPROM. */
+ {
+ int timer;
+ outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd);
+ /* Pause for at least 162 us. for the read to take place. */
+ for (timer = 4; timer >= 0; timer--) {
+ udelay(162);
+ if ((inw(ioaddr + Wn0EepromCmd) & 0x0200)
+ == 0)
+ break;
+ }
+ if (inw(ioaddr + Wn0EepromData) != 0x6d50)
+ continue;
}
- if (inw(ioaddr + Wn0EepromData) != 0x6d50)
- continue;
- }
- printk("3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n",
- inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
- irq = inw(ioaddr + 0x2002) & 15;
- vortex_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev && dev->mem_start
- ? dev->mem_start : options[cards_found]);
- dev = 0;
- cards_found++;
+ printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n",
+ inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
+ irq = inw(ioaddr + 0x2002) & 15;
+ corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev
+ && dev->mem_start ? dev->
+ mem_start : options[cards_found]);
+ dev = 0;
+ cards_found++;
}
- if (vortex_debug)
- printk("%d 3c515 cards found.\n", cards_found);
+ if (corkscrew_debug)
+ printk(KERN_INFO "%d 3c515 cards found.\n", cards_found);
return cards_found;
}
-static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr,
- int irq, int product_index,
- int options)
+static struct net_device *corkscrew_found_device(struct net_device *dev,
+ int ioaddr, int irq,
+ int product_index,
+ int options)
{
- struct vortex_private *vp;
+ struct corkscrew_private *vp;
#ifdef MODULE
/* Allocate and fill new device structure. */
int dev_size = sizeof(struct net_device) +
- sizeof(struct vortex_private) + 15; /* Pad for alignment */
-
+ sizeof(struct corkscrew_private) + 15; /* Pad for alignment */
+
dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL);
memset(dev, 0, dev_size);
/* Align the Rx and Tx ring entries. */
- dev->priv = (void *)(((long)dev + sizeof(struct net_device) + 15) & ~15);
- vp = (struct vortex_private *)dev->priv;
- dev->name = vp->devname; /* An empty string. */
+ dev->priv =
+ (void *) (((long) dev + sizeof(struct net_device) + 15) & ~15);
+ vp = (struct corkscrew_private *) dev->priv;
+ dev->name = vp->devname; /* An empty string. */
dev->base_addr = ioaddr;
dev->irq = irq;
- dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0);
- dev->init = vortex_probe1;
+ dev->dma =
+ (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0);
+ dev->init = corkscrew_probe1;
vp->product_name = "3c515";
vp->options = options;
if (options >= 0) {
- vp->media_override = ((options & 7) == 2) ? 0 : options & 7;
+ vp->media_override =
+ ((options & 7) == 2) ? 0 : options & 7;
vp->full_duplex = (options & 8) ? 1 : 0;
vp->bus_master = (options & 16) ? 1 : 0;
} else {
@@ -485,25 +498,28 @@ static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr
vp->bus_master = 0;
}
ether_setup(dev);
- vp->next_module = root_vortex_dev;
- root_vortex_dev = dev;
+ vp->next_module = root_corkscrew_dev;
+ root_corkscrew_dev = dev;
if (register_netdev(dev) != 0)
return 0;
-#else /* not a MODULE */
+#else /* not a MODULE */
if (dev) {
/* Caution: quad-word alignment required for rings! */
- dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof (struct vortex_private));
+ dev->priv =
+ kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct corkscrew_private));
}
- dev = init_etherdev(dev, sizeof(struct vortex_private));
+ dev = init_etherdev(dev, sizeof(struct corkscrew_private));
dev->base_addr = ioaddr;
dev->irq = irq;
- dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0);
- vp = (struct vortex_private *)dev->priv;
+ dev->dma =
+ (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0);
+ vp = (struct corkscrew_private *) dev->priv;
vp->product_name = "3c515";
vp->options = options;
if (options >= 0) {
- vp->media_override = ((options & 7) == 2) ? 0 : options & 7;
+ vp->media_override =
+ ((options & 7) == 2) ? 0 : options & 7;
vp->full_duplex = (options & 8) ? 1 : 0;
vp->bus_master = (options & 16) ? 1 : 0;
} else {
@@ -512,25 +528,26 @@ static struct net_device *vortex_found_device(struct net_device *dev, int ioaddr
vp->bus_master = 0;
}
- vortex_probe1(dev);
-#endif /* MODULE */
+ corkscrew_probe1(dev);
+#endif /* MODULE */
return dev;
}
-static int vortex_probe1(struct net_device *dev)
+static int corkscrew_probe1(struct net_device *dev)
{
int ioaddr = dev->base_addr;
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
+ unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
- printk("%s: 3Com %s at %#3x,", dev->name,
- vp->product_name, ioaddr);
+ printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name,
+ vp->product_name, ioaddr);
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
for (i = 0; i < 0x18; i++) {
- short *phys_addr = (short *)dev->dev_addr;
+ short *phys_addr = (short *) dev->dev_addr;
int timer;
outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
/* Pause for at least 162 us. for the read to take place. */
@@ -549,97 +566,100 @@ static int vortex_probe1(struct net_device *dev)
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
for (i = 0; i < 6; i++)
printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
- if (eeprom[16] == 0x11c7) { /* Corkscrew */
- if (request_dma(dev->dma, "3c515")) {
- printk(", DMA %d allocation failed", dev->dma);
- dev->dma = 0;
- } else
- printk(", DMA %d", dev->dma);
+ if (eeprom[16] == 0x11c7) { /* Corkscrew */
+ if (request_dma(dev->dma, "3c515")) {
+ printk(", DMA %d allocation failed", dev->dma);
+ dev->dma = 0;
+ } else
+ printk(", DMA %d", dev->dma);
}
printk(", IRQ %d\n", dev->irq);
/* Tell them about an invalid IRQ. */
- if (vortex_debug && (dev->irq <= 0 || dev->irq > 15))
- printk(" *** Warning: this IRQ is unlikely to work! ***\n");
+ if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15))
+ printk(KERN_WARNING " *** Warning: this IRQ is unlikely to work! ***\n");
{
- char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+ char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
union wn3_config config;
EL3WINDOW(3);
vp->available_media = inw(ioaddr + Wn3_Options);
config.i = inl(ioaddr + Wn3_Config);
- if (vortex_debug > 1)
- printk(" Internal config register is %4.4x, transceivers %#x.\n",
- config.i, inw(ioaddr + Wn3_Options));
- printk(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
- 8 << config.u.ram_size,
- config.u.ram_width ? "word" : "byte",
- ram_split[config.u.ram_split],
- config.u.autoselect ? "autoselect/" : "",
- media_tbl[config.u.xcvr].name);
+ if (corkscrew_debug > 1)
+ printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n",
+ config.i, inw(ioaddr + Wn3_Options));
+ printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+ 8 << config.u.ram_size,
+ config.u.ram_width ? "word" : "byte",
+ ram_split[config.u.ram_split],
+ config.u.autoselect ? "autoselect/" : "",
+ media_tbl[config.u.xcvr].name);
dev->if_port = config.u.xcvr;
vp->default_media = config.u.xcvr;
vp->autoselect = config.u.autoselect;
}
if (vp->media_override != 7) {
- printk(" Media override to transceiver type %d (%s).\n",
- vp->media_override, media_tbl[vp->media_override].name);
+ printk(KERN_INFO " Media override to transceiver type %d (%s).\n",
+ vp->media_override,
+ media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
}
vp->capabilities = eeprom[16];
vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0;
/* Rx is broken at 10mbps, so we always disable it. */
- /* vp->full_bus_master_rx = 0;*/
+ /* vp->full_bus_master_rx = 0; */
vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
/* We do a request_region() to register /proc/ioports info. */
request_region(ioaddr, CORKSCREW_TOTAL_SIZE, vp->product_name);
- /* The 3c59x-specific entries in the device structure. */
- dev->open = &vortex_open;
- dev->hard_start_xmit = &vortex_start_xmit;
- dev->stop = &vortex_close;
- dev->get_stats = &vortex_get_stats;
+ /* The 3c51x-specific entries in the device structure. */
+ dev->open = &corkscrew_open;
+ dev->hard_start_xmit = &corkscrew_start_xmit;
+ dev->tx_timeout = &corkscrew_timeout;
+ dev->watchdog_timeo = (400 * HZ) / 1000;
+ dev->stop = &corkscrew_close;
+ dev->get_stats = &corkscrew_get_stats;
dev->set_multicast_list = &set_rx_mode;
return 0;
}
-
-static int
-vortex_open(struct net_device *dev)
+
+static int corkscrew_open(struct net_device *dev)
{
int ioaddr = dev->base_addr;
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
union wn3_config config;
int i;
/* Before initializing select the active media port. */
EL3WINDOW(3);
if (vp->full_duplex)
- outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
+ outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
config.i = inl(ioaddr + Wn3_Config);
if (vp->media_override != 7) {
- if (vortex_debug > 1)
- printk("%s: Media override to transceiver %d (%s).\n",
- dev->name, vp->media_override,
- media_tbl[vp->media_override].name);
+ if (corkscrew_debug > 1)
+ printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
+ dev->name, vp->media_override,
+ media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
} else if (vp->autoselect) {
/* Find first available media type, starting with 100baseTx. */
dev->if_port = 4;
- while (! (vp->available_media & media_tbl[dev->if_port].mask))
+ while (!(vp->available_media & media_tbl[dev->if_port].mask))
dev->if_port = media_tbl[dev->if_port].next;
- if (vortex_debug > 1)
+ if (corkscrew_debug > 1)
printk("%s: Initial media type %s.\n",
- dev->name, media_tbl[dev->if_port].name);
+ dev->name, media_tbl[dev->if_port].name);
init_timer(&vp->timer);
vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
- vp->timer.data = (unsigned long)dev;
- vp->timer.function = &vortex_timer; /* timer handler */
+ vp->timer.data = (unsigned long) dev;
+ vp->timer.function = &corkscrew_timer; /* timer handler */
add_timer(&vp->timer);
} else
dev->if_port = vp->default_media;
@@ -647,63 +667,62 @@ vortex_open(struct net_device *dev)
config.u.xcvr = dev->if_port;
outl(config.i, ioaddr + Wn3_Config);
- if (vortex_debug > 1) {
- printk("%s: vortex_open() InternalConfig %8.8x.\n",
- dev->name, config.i);
+ if (corkscrew_debug > 1) {
+ printk("%s: corkscrew_open() InternalConfig %8.8x.\n",
+ dev->name, config.i);
}
outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ for (i = 20; i >= 0; i--)
+ if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
outw(RxReset, ioaddr + EL3_CMD);
/* Wait a few ticks for the RxReset command to complete. */
- for (i = 20; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ for (i = 20; i >= 0; i--)
+ if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
/* Use the now-standard shared IRQ implementation. */
if (vp->capabilities == 0x11c7) {
- /* Corkscrew: Cannot share ISA resources. */
- if (dev->irq == 0
- || dev->dma == 0
- || request_irq(dev->irq, &vortex_interrupt, 0,
- vp->product_name, dev))
+ /* Corkscrew: Cannot share ISA resources. */
+ if (dev->irq == 0
+ || dev->dma == 0
+ || request_irq(dev->irq, &corkscrew_interrupt, 0,
+ vp->product_name, dev)) return -EAGAIN;
+ enable_dma(dev->dma);
+ set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+ } else if (request_irq(dev->irq, &corkscrew_interrupt, SA_SHIRQ,
+ vp->product_name, dev)) {
return -EAGAIN;
- enable_dma(dev->dma);
- set_dma_mode(dev->dma, DMA_MODE_CASCADE);
- } else if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
- vp->product_name, dev)) {
- return -EAGAIN;
}
- if (vortex_debug > 1) {
+ if (corkscrew_debug > 1) {
EL3WINDOW(4);
- printk("%s: vortex_open() irq %d media status %4.4x.\n",
- dev->name, dev->irq, inw(ioaddr + Wn4_Media));
+ printk("%s: corkscrew_open() irq %d media status %4.4x.\n",
+ dev->name, dev->irq, inw(ioaddr + Wn4_Media));
}
/* Set the station address and mask in window 2 each time opened. */
EL3WINDOW(2);
for (i = 0; i < 6; i++)
outb(dev->dev_addr[i], ioaddr + i);
- for (; i < 12; i+=2)
+ for (; i < 12; i += 2)
outw(0, ioaddr + i);
if (dev->if_port == 3)
- /* Start the thinnet transceiver. We should really wait 50ms...*/
+ /* Start the thinnet transceiver. We should really wait 50ms... */
outw(StartCoax, ioaddr + EL3_CMD);
EL3WINDOW(4);
- outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+ outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) |
+ media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
/* Switch to the stats window, and clear all stats by reading. */
outw(StatsDisable, ioaddr + EL3_CMD);
EL3WINDOW(6);
- for (i = 0; i < 10; i++)
+ for (i = 0; i < 10; i++)
inb(ioaddr + i);
inw(ioaddr + 10);
inw(ioaddr + 12);
@@ -716,32 +735,34 @@ vortex_open(struct net_device *dev)
/* Switch to register set 7 for normal use. */
EL3WINDOW(7);
- if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+ if (vp->full_bus_master_rx) { /* Boomerang bus master. */
vp->cur_rx = vp->dirty_rx = 0;
- if (vortex_debug > 2)
- printk("%s: Filling in the Rx ring.\n", dev->name);
+ if (corkscrew_debug > 2)
+ printk("%s: Filling in the Rx ring.\n",
+ dev->name);
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb;
if (i < (RX_RING_SIZE - 1))
- vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
+ vp->rx_ring[i].next =
+ virt_to_bus(&vp->rx_ring[i + 1]);
else
- vp->rx_ring[i].next = 0;
+ vp->rx_ring[i].next = 0;
vp->rx_ring[i].status = 0; /* Clear complete bit. */
vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000;
skb = dev_alloc_skb(PKT_BUF_SZ);
vp->rx_skbuff[i] = skb;
if (skb == NULL)
- break; /* Bad news! */
- skb->dev = dev; /* Mark as being used by this device. */
+ break; /* Bad news! */
+ skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
vp->rx_ring[i].addr = virt_to_bus(skb->tail);
}
- vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
+ vp->rx_ring[i - 1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
}
- if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
+ if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
vp->cur_tx = vp->dirty_tx = 0;
- outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
+ outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold); /* Room for a packet. */
/* Clear the Tx ring. */
for (i = 0; i < TX_RING_SIZE; i++)
vp->tx_skbuff[i] = 0;
@@ -749,175 +770,188 @@ vortex_open(struct net_device *dev)
}
/* Set receiver mode: presumably accept b-case and phys addr only. */
set_rx_mode(dev);
- outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+ outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
- outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
- outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+ outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
/* Allow status bits to be seen. */
- outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull |
- (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
- (vp->full_bus_master_rx ? UpComplete : RxComplete) |
- (vp->bus_master ? DMADone : 0),
- ioaddr + EL3_CMD);
+ outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull |
+ (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+ (vp->full_bus_master_rx ? UpComplete : RxComplete) |
+ (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD);
/* Ack all pending events, and set active indicator mask. */
outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
+ ioaddr + EL3_CMD);
outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
- | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
- ioaddr + EL3_CMD);
+ | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
+ ioaddr + EL3_CMD);
MOD_INC_USE_COUNT;
return 0;
}
-static void vortex_timer(unsigned long data)
+static void corkscrew_timer(unsigned long data)
{
#ifdef AUTOMEDIA
- struct net_device *dev = (struct net_device *)data;
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ struct net_device *dev = (struct net_device *) data;
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
int ioaddr = dev->base_addr;
unsigned long flags;
int ok = 0;
- if (vortex_debug > 1)
+ if (corkscrew_debug > 1)
printk("%s: Media selection timer tick happened, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- save_flags(flags); cli(); {
- int old_window = inw(ioaddr + EL3_CMD) >> 13;
- int media_status;
- EL3WINDOW(4);
- media_status = inw(ioaddr + Wn4_Media);
- switch (dev->if_port) {
- case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */
- if (media_status & Media_LnkBeat) {
- ok = 1;
- if (vortex_debug > 1)
- printk("%s: Media %s has link beat, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
- } else if (vortex_debug > 1)
- printk("%s: Media %s is has no link beat, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
-
- break;
- default: /* Other media types handled by Tx timeouts. */
- if (vortex_debug > 1)
- printk("%s: Media %s is has no indication, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
- ok = 1;
- }
- if ( ! ok) {
- union wn3_config config;
+ dev->name, media_tbl[dev->if_port].name);
- do {
- dev->if_port = media_tbl[dev->if_port].next;
- } while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
- if (dev->if_port == 8) { /* Go back to default. */
- dev->if_port = vp->default_media;
- if (vortex_debug > 1)
- printk("%s: Media selection failing, using default %s port.\n",
- dev->name, media_tbl[dev->if_port].name);
- } else {
- if (vortex_debug > 1)
- printk("%s: Media selection failed, now trying %s port.\n",
- dev->name, media_tbl[dev->if_port].name);
- vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
- add_timer(&vp->timer);
+ save_flags(flags);
+ cli(); {
+ int old_window = inw(ioaddr + EL3_CMD) >> 13;
+ int media_status;
+ EL3WINDOW(4);
+ media_status = inw(ioaddr + Wn4_Media);
+ switch (dev->if_port) {
+ case 0:
+ case 4:
+ case 5: /* 10baseT, 100baseTX, 100baseFX */
+ if (media_status & Media_LnkBeat) {
+ ok = 1;
+ if (corkscrew_debug > 1)
+ printk("%s: Media %s has link beat, %x.\n",
+ dev->name,
+ media_tbl[dev->if_port].name,
+ media_status);
+ } else if (corkscrew_debug > 1)
+ printk("%s: Media %s is has no link beat, %x.\n",
+ dev->name,
+ media_tbl[dev->if_port].name,
+ media_status);
+
+ break;
+ default: /* Other media types handled by Tx timeouts. */
+ if (corkscrew_debug > 1)
+ printk("%s: Media %s is has no indication, %x.\n",
+ dev->name,
+ media_tbl[dev->if_port].name,
+ media_status);
+ ok = 1;
}
- outw((media_status & ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+ if (!ok) {
+ union wn3_config config;
- EL3WINDOW(3);
- config.i = inl(ioaddr + Wn3_Config);
- config.u.xcvr = dev->if_port;
- outl(config.i, ioaddr + Wn3_Config);
-
- outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD);
- }
- EL3WINDOW(old_window);
- } restore_flags(flags);
- if (vortex_debug > 1)
- printk("%s: Media selection timer finished, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
-#endif /* AUTOMEDIA*/
+ do {
+ dev->if_port =
+ media_tbl[dev->if_port].next;
+ }
+ while (!(vp->available_media & media_tbl[dev->if_port].mask));
+
+ if (dev->if_port == 8) { /* Go back to default. */
+ dev->if_port = vp->default_media;
+ if (corkscrew_debug > 1)
+ printk("%s: Media selection failing, using default %s port.\n",
+ dev->name,
+ media_tbl[dev->if_port].name);
+ } else {
+ if (corkscrew_debug > 1)
+ printk("%s: Media selection failed, now trying %s port.\n",
+ dev->name,
+ media_tbl[dev->if_port].name);
+ vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+ add_timer(&vp->timer);
+ }
+ outw((media_status & ~(Media_10TP | Media_SQE)) |
+ media_tbl[dev->if_port].media_bits,
+ ioaddr + Wn4_Media);
+
+ EL3WINDOW(3);
+ config.i = inl(ioaddr + Wn3_Config);
+ config.u.xcvr = dev->if_port;
+ outl(config.i, ioaddr + Wn3_Config);
+
+ outw(dev->if_port == 3 ? StartCoax : StopCoax,
+ ioaddr + EL3_CMD);
+ }
+ EL3WINDOW(old_window);
+ }
+ restore_flags(flags);
+ if (corkscrew_debug > 1)
+ printk("%s: Media selection timer finished, %s.\n",
+ dev->name, media_tbl[dev->if_port].name);
+
+#endif /* AUTOMEDIA */
return;
}
-static int
-vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void corkscrew_timeout(struct net_device *dev)
{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int i;
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
int ioaddr = dev->base_addr;
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- int i;
-
- /* Min. wait before assuming a Tx failed == 400ms. */
-
- if (tickssofar < 400*HZ/1000) /* We probably aren't empty. */
- return 1;
- printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, inb(ioaddr + TxStatus),
- inw(ioaddr + EL3_STATUS));
- /* Slight code bloat to be user friendly. */
- if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
- printk("%s: Transmitter encountered 16 collisions -- network"
- " network cable problem?\n", dev->name);
+ printk(KERN_WARNING
+ "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+ dev->name, inb(ioaddr + TxStatus),
+ inw(ioaddr + EL3_STATUS));
+ /* Slight code bloat to be user friendly. */
+ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
+ printk(KERN_WARNING
+ "%s: Transmitter encountered 16 collisions -- network"
+ " network cable problem?\n", dev->name);
#ifndef final_version
- printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
- vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
- printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
- &vp->tx_ring[0]);
- for (i = 0; i < TX_RING_SIZE; i++) {
- printk(" %d: %p length %8.8x status %8.8x\n", i,
- &vp->tx_ring[i],
- vp->tx_ring[i].length,
- vp->tx_ring[i].status);
- }
-#endif
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies;
- /* dev->tbusy = 0;*/
- vp->stats.tx_errors++;
- vp->stats.tx_dropped++;
- return 0; /* Yes, silently *drop* the packet! */
+ printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
+ vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx,
+ vp->cur_tx);
+ printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+ &vp->tx_ring[0]);
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ printk(" %d: %p length %8.8x status %8.8x\n", i,
+ &vp->tx_ring[i],
+ vp->tx_ring[i].length, vp->tx_ring[i].status);
}
+#endif
+ /* Issue TX_RESET and TX_START commands. */
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (i = 20; i >= 0; i--)
+ if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ outw(TxEnable, ioaddr + EL3_CMD);
+ dev->trans_start = jiffies;
+ vp->stats.tx_errors++;
+ vp->stats.tx_dropped++;
+ netif_wake_queue(dev);
+}
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- If this ever occurs the queue layer is doing something evil! */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
+static int corkscrew_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
+ int ioaddr = dev->base_addr;
+
+ /* Block a timer-based transmit from overlapping. */
- if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */
+ netif_stop_queue(dev);
+
+ if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */
/* Calculate the next Tx descriptor entry. */
int entry = vp->cur_tx % TX_RING_SIZE;
struct boom_tx_desc *prev_entry;
unsigned long flags, i;
- if (vp->tx_full) /* No room to transmit with */
- return 1;
+ if (vp->tx_full) /* No room to transmit with */
+ return 1;
if (vp->cur_tx != 0)
- prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
+ prev_entry =
+ &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE];
else
- prev_entry = NULL;
- if (vortex_debug > 3)
+ prev_entry = NULL;
+ if (corkscrew_debug > 3)
printk("%s: Trying to send a packet, Tx index %d.\n",
- dev->name, vp->cur_tx);
+ dev->name, vp->cur_tx);
/* vp->tx_full = 1; */
vp->tx_skbuff[entry] = skb;
vp->tx_ring[entry].next = 0;
@@ -929,13 +963,15 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
cli();
outw(DownStall, ioaddr + EL3_CMD);
/* Wait for the stall to complete. */
- for (i = 20; i >= 0 ; i--)
- if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
- break;
+ for (i = 20; i >= 0; i--)
+ if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) ==
+ 0) break;
if (prev_entry)
- prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
+ prev_entry->next =
+ virt_to_bus(&vp->tx_ring[entry]);
if (inl(ioaddr + DownListPtr) == 0) {
- outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
+ outl(virt_to_bus(&vp->tx_ring[entry]),
+ ioaddr + DownListPtr);
queued_packet++;
}
outw(DownUnstall, ioaddr + EL3_CMD);
@@ -944,10 +980,10 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
vp->cur_tx++;
if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
vp->tx_full = 1;
- else { /* Clear previous interrupt enable. */
- if (prev_entry)
- prev_entry->status &= ~0x80000000;
- dev->tbusy = 0;
+ else { /* Clear previous interrupt enable. */
+ if (prev_entry)
+ prev_entry->status &= ~0x80000000;
+ netif_wake_queue(dev);
}
dev->trans_start = jiffies;
return 0;
@@ -957,31 +993,32 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef VORTEX_BUS_MASTER
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
- outl((int)(skb->data), ioaddr + Wn7_MasterAddr);
+ outl((int) (skb->data), ioaddr + Wn7_MasterAddr);
outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
vp->tx_skb = skb;
outw(StartDMADown, ioaddr + EL3_CMD);
- /* dev->tbusy will be cleared at the DMADone interrupt. */
+ /* queue will be woken at the DMADone interrupt. */
} else {
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb);
+ dev_kfree_skb(skb);
if (inw(ioaddr + TxFree) > 1536) {
- dev->tbusy = 0;
+ netif_wake_queue(dev);
} else
/* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+ outw(SetTxThreshold + (1536 >> 2),
+ ioaddr + EL3_CMD);
}
#else
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb);
+ dev_kfree_skb(skb);
if (inw(ioaddr + TxFree) > 1536) {
- dev->tbusy = 0;
+ netif_wake_queue(dev);
} else
/* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-#endif /* bus master */
+ outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD);
+#endif /* bus master */
dev->trans_start = jiffies;
@@ -990,80 +1027,79 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
short tx_status;
int i = 4;
- while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
- if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
- if (vortex_debug > 2)
- printk("%s: Tx error, status %2.2x.\n",
- dev->name, tx_status);
- if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
- if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
+ while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
+ if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
+ if (corkscrew_debug > 2)
+ printk("%s: Tx error, status %2.2x.\n",
+ dev->name, tx_status);
+ if (tx_status & 0x04)
+ vp->stats.tx_fifo_errors++;
+ if (tx_status & 0x38)
+ vp->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
- for (j = 20; j >= 0 ; j--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ for (j = 20; j >= 0; j--)
+ if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
}
outw(TxEnable, ioaddr + EL3_CMD);
}
- outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
+ outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- vp->stats.tx_bytes+=skb->len;
+ vp->stats.tx_bytes += skb->len;
return 0;
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
+
+static void corkscrew_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
{
/* Use the now-standard shared IRQ implementation. */
struct net_device *dev = dev_id;
- struct vortex_private *lp;
+ struct corkscrew_private *lp;
int ioaddr, status;
int latency;
int i = max_interrupt_work;
- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
- return;
- }
-
ioaddr = dev->base_addr;
latency = inb(ioaddr + Timer);
- lp = (struct vortex_private *)dev->priv;
+ lp = (struct corkscrew_private *) dev->priv;
status = inw(ioaddr + EL3_STATUS);
- if (vortex_debug > 4)
- printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name,
- status, latency);
+ if (corkscrew_debug > 4)
+ printk("%s: interrupt, status %4.4x, timer %d.\n",
+ dev->name, status, latency);
if ((status & 0xE000) != 0xE000) {
- static int donedidthis=0;
+ static int donedidthis = 0;
/* Some interrupt controllers store a bogus interrupt from boot-time.
Ignore a single early interrupt, but don't hang the machine for
other interrupt problems. */
if (donedidthis++ > 100) {
- printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
- dev->name, status, dev->start);
- FREE_IRQ(dev->irq, dev);
+ printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
+ dev->name, status, netif_running(dev));
+ free_irq(dev->irq, dev);
}
}
do {
- if (vortex_debug > 5)
- printk("%s: In interrupt loop, status %4.4x.\n",
- dev->name, status);
+ if (corkscrew_debug > 5)
+ printk("%s: In interrupt loop, status %4.4x.\n",
+ dev->name, status);
if (status & RxComplete)
- vortex_rx(dev);
+ corkscrew_rx(dev);
if (status & TxAvailable) {
- if (vortex_debug > 5)
- printk(" TX room bit was handled.\n");
+ if (corkscrew_debug > 5)
+ printk
+ (" TX room bit was handled.\n");
/* There's room in the FIFO for a full-sized packet. */
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
if (status & DownComplete) {
unsigned int dirty_tx = lp->dirty_tx;
@@ -1071,28 +1107,29 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
while (lp->cur_tx - dirty_tx > 0) {
int entry = dirty_tx % TX_RING_SIZE;
if (inl(ioaddr + DownListPtr) ==
- virt_to_bus(&lp->tx_ring[entry]))
- break; /* It still hasn't been processed. */
+ virt_to_bus(&lp->tx_ring[entry]))
+ break; /* It still hasn't been processed. */
if (lp->tx_skbuff[entry]) {
- dev_kfree_skb(lp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(lp->
+ tx_skbuff
+ [entry]);
lp->tx_skbuff[entry] = 0;
}
dirty_tx++;
}
lp->dirty_tx = dirty_tx;
outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
- if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
- lp->tx_full= 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ if (lp->tx_full
+ && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+ lp->tx_full = 0;
+ netif_wake_queue(dev);
}
}
#ifdef VORTEX_BUS_MASTER
if (status & DMADone) {
- outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- dev->tbusy = 0;
- dev_kfree_skb (lp->tx_skb); /* Release the transfered buffer */
- mark_bh(NET_BH);
+ outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
+ dev_kfree_skb_irq(lp->tx_skb); /* Release the transfered buffer */
+ netif_wake_queue(dev);
}
#endif
if (status & UpComplete) {
@@ -1101,32 +1138,36 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
}
if (status & (AdapterFailure | RxEarly | StatsFull)) {
/* Handle all uncommon interrupts at once. */
- if (status & RxEarly) { /* Rx early is unused. */
- vortex_rx(dev);
+ if (status & RxEarly) { /* Rx early is unused. */
+ corkscrew_rx(dev);
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
}
- if (status & StatsFull) { /* Empty statistics. */
+ if (status & StatsFull) { /* Empty statistics. */
static int DoneDidThat = 0;
- if (vortex_debug > 4)
- printk("%s: Updating stats.\n", dev->name);
+ if (corkscrew_debug > 4)
+ printk("%s: Updating stats.\n",
+ dev->name);
update_stats(ioaddr, dev);
/* DEBUG HACK: Disable statistics as an interrupt source. */
/* This occurs when we have the wrong media type! */
- if (DoneDidThat == 0 &&
- inw(ioaddr + EL3_STATUS) & StatsFull) {
+ if (DoneDidThat == 0 &&
+ inw(ioaddr + EL3_STATUS) & StatsFull) {
int win, reg;
printk("%s: Updating stats failed, disabling stats as an"
- " interrupt source.\n", dev->name);
+ " interrupt source.\n",
+ dev->name);
for (win = 0; win < 8; win++) {
EL3WINDOW(win);
printk("\n Vortex window %d:", win);
for (reg = 0; reg < 16; reg++)
- printk(" %2.2x", inb(ioaddr+reg));
+ printk(" %2.2x",
+ inb(ioaddr + reg));
}
EL3WINDOW(7);
- outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure
- | UpComplete | DownComplete | TxComplete,
- ioaddr + EL3_CMD);
+ outw(SetIntrEnb | TxAvailable |
+ RxComplete | AdapterFailure |
+ UpComplete | DownComplete |
+ TxComplete, ioaddr + EL3_CMD);
DoneDidThat++;
}
}
@@ -1135,139 +1176,150 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
outw(RxReset, ioaddr + EL3_CMD);
/* Set the Rx filter to the current state. */
set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+ outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+ outw(AckIntr | AdapterFailure,
+ ioaddr + EL3_CMD);
}
}
if (--i < 0) {
- printk("%s: Too much work in interrupt, status %4.4x. "
- "Disabling functions (%4.4x).\n",
- dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
+ printk(KERN_ERR "%s: Too much work in interrupt, status %4.4x. "
+ "Disabling functions (%4.4x).\n", dev->name,
+ status, SetStatusEnb | ((~status) & 0x7FE));
/* Disable all pending interrupts. */
- outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
+ outw(SetStatusEnb | ((~status) & 0x7FE),
+ ioaddr + EL3_CMD);
outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
break;
}
/* Acknowledge the IRQ. */
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
- } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+ } while ((status = inw(ioaddr + EL3_STATUS)) &
+ (IntLatch | RxComplete));
- if (vortex_debug > 4)
- printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
-
- dev->interrupt = 0;
- return;
+ if (corkscrew_debug > 4)
+ printk("%s: exiting interrupt, status %4.4x.\n", dev->name,
+ status);
}
-static int
-vortex_rx(struct net_device *dev)
+static int corkscrew_rx(struct net_device *dev)
{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;
int ioaddr = dev->base_addr;
int i;
short rx_status;
- if (vortex_debug > 5)
+ if (corkscrew_debug > 5)
printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+ inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
- if (rx_status & 0x4000) { /* Error, update stats. */
+ if (rx_status & 0x4000) { /* Error, update stats. */
unsigned char rx_error = inb(ioaddr + RxErrors);
- if (vortex_debug > 2)
- printk(" Rx error: status %2.2x.\n", rx_error);
+ if (corkscrew_debug > 2)
+ printk(" Rx error: status %2.2x.\n",
+ rx_error);
vp->stats.rx_errors++;
- if (rx_error & 0x01) vp->stats.rx_over_errors++;
- if (rx_error & 0x02) vp->stats.rx_length_errors++;
- if (rx_error & 0x04) vp->stats.rx_frame_errors++;
- if (rx_error & 0x08) vp->stats.rx_crc_errors++;
- if (rx_error & 0x10) vp->stats.rx_length_errors++;
+ if (rx_error & 0x01)
+ vp->stats.rx_over_errors++;
+ if (rx_error & 0x02)
+ vp->stats.rx_length_errors++;
+ if (rx_error & 0x04)
+ vp->stats.rx_frame_errors++;
+ if (rx_error & 0x08)
+ vp->stats.rx_crc_errors++;
+ if (rx_error & 0x10)
+ vp->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
- skb = DEV_ALLOC_SKB(pkt_len + 5);
- if (vortex_debug > 4)
+ skb = dev_alloc_skb(pkt_len + 5 + 2);
+ if (corkscrew_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
+ pkt_len, rx_status);
if (skb != NULL) {
skb->dev = dev;
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
- insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
- (pkt_len + 3) >> 2);
- outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
+ insl(ioaddr + RX_FIFO,
+ skb_put(skb, pkt_len),
+ (pkt_len + 3) >> 2);
+ outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
vp->stats.rx_packets++;
- vp->stats.rx_bytes+=skb->len;
+ vp->stats.rx_bytes += skb->len;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
continue;
- } else if (vortex_debug)
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, pkt_len);
+ } else if (corkscrew_debug)
+ printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
}
outw(RxDiscard, ioaddr + EL3_CMD);
vp->stats.rx_dropped++;
/* Wait a limited time to skip this packet. */
for (i = 200; i >= 0; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
}
-
return 0;
}
-static int
-boomerang_rx(struct net_device *dev)
+static int boomerang_rx(struct net_device *dev)
{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
int entry = vp->cur_rx % RX_RING_SIZE;
int ioaddr = dev->base_addr;
int rx_status;
- if (vortex_debug > 5)
+ if (corkscrew_debug > 5)
printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+ inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
- if (rx_status & RxDError) { /* Error, update stats. */
+ if (rx_status & RxDError) { /* Error, update stats. */
unsigned char rx_error = rx_status >> 16;
- if (vortex_debug > 2)
- printk(" Rx error: status %2.2x.\n", rx_error);
+ if (corkscrew_debug > 2)
+ printk(" Rx error: status %2.2x.\n",
+ rx_error);
vp->stats.rx_errors++;
- if (rx_error & 0x01) vp->stats.rx_over_errors++;
- if (rx_error & 0x02) vp->stats.rx_length_errors++;
- if (rx_error & 0x04) vp->stats.rx_frame_errors++;
- if (rx_error & 0x08) vp->stats.rx_crc_errors++;
- if (rx_error & 0x10) vp->stats.rx_length_errors++;
+ if (rx_error & 0x01)
+ vp->stats.rx_over_errors++;
+ if (rx_error & 0x02)
+ vp->stats.rx_length_errors++;
+ if (rx_error & 0x04)
+ vp->stats.rx_frame_errors++;
+ if (rx_error & 0x08)
+ vp->stats.rx_crc_errors++;
+ if (rx_error & 0x10)
+ vp->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
- vp->stats.rx_bytes+=pkt_len;
- if (vortex_debug > 4)
+ vp->stats.rx_bytes += pkt_len;
+ if (corkscrew_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
+ pkt_len, rx_status);
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
if (pkt_len < rx_copybreak
- && (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
+ && (skb = dev_alloc_skb(pkt_len + 4)) != 0) {
skb->dev = dev;
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
memcpy(skb_put(skb, pkt_len),
- bus_to_virt(vp->rx_ring[entry].addr),
- pkt_len);
+ bus_to_virt(vp->rx_ring[entry].
+ addr), pkt_len);
rx_copy++;
- } else{
+ } else {
void *temp;
/* Pass up the skbuff already on the Rx ring. */
skb = vp->rx_skbuff[entry];
@@ -1275,10 +1327,13 @@ boomerang_rx(struct net_device *dev)
temp = skb_put(skb, pkt_len);
/* Remove this checking code for final release. */
if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
- printk("%s: Warning -- the skbuff addresses do not match"
- " in boomerang_rx: %p vs. %p / %p.\n", dev->name,
- bus_to_virt(vp->rx_ring[entry].addr),
- skb->head, temp);
+ printk("%s: Warning -- the skbuff addresses do not match"
+ " in boomerang_rx: %p vs. %p / %p.\n",
+ dev->name,
+ bus_to_virt(vp->
+ rx_ring[entry].
+ addr), skb->head,
+ temp);
rx_nocopy++;
}
skb->protocol = eth_type_trans(skb, dev);
@@ -1295,8 +1350,8 @@ boomerang_rx(struct net_device *dev)
if (vp->rx_skbuff[entry] == NULL) {
skb = dev_alloc_skb(PKT_BUF_SZ);
if (skb == NULL)
- break; /* Bad news! */
- skb->dev = dev; /* Mark as being used by this device. */
+ break; /* Bad news! */
+ skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
vp->rx_ring[entry].addr = virt_to_bus(skb->tail);
vp->rx_skbuff[entry] = skb;
@@ -1306,22 +1361,22 @@ boomerang_rx(struct net_device *dev)
return 0;
}
-static int
-vortex_close(struct net_device *dev)
+static int corkscrew_close(struct net_device *dev)
{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
int ioaddr = dev->base_addr;
int i;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
- if (vortex_debug > 1) {
- printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
- dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
- printk("%s: vortex close stats: rx_nocopy %d rx_copy %d"
- " tx_queued %d.\n",
- dev->name, rx_nocopy, rx_copy, queued_packet);
+ if (corkscrew_debug > 1) {
+ printk("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n",
+ dev->name, inw(ioaddr + EL3_STATUS),
+ inb(ioaddr + TxStatus));
+ printk("%s: corkscrew close stats: rx_nocopy %d rx_copy %d"
+ " tx_queued %d.\n", dev->name, rx_nocopy, rx_copy,
+ queued_packet);
}
del_timer(&vp->timer);
@@ -1337,28 +1392,20 @@ vortex_close(struct net_device *dev)
/* Turn off thinnet power. Green! */
outw(StopCoax, ioaddr + EL3_CMD);
-#ifdef SA_SHIRQ
free_irq(dev->irq, dev);
-#else
- free_irq(dev->irq);
- irq2dev_map[dev->irq] = 0;
-#endif
outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
update_stats(ioaddr, dev);
- if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+ if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
outl(0, ioaddr + UpListPtr);
for (i = 0; i < RX_RING_SIZE; i++)
if (vp->rx_skbuff[i]) {
-#if LINUX_VERSION_CODE < 0x20100
- vp->rx_skbuff[i]->free = 1;
-#endif
- dev_kfree_skb (vp->rx_skbuff[i]);
+ dev_kfree_skb(vp->rx_skbuff[i]);
vp->rx_skbuff[i] = 0;
}
}
- if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
+ if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
outl(0, ioaddr + DownListPtr);
for (i = 0; i < TX_RING_SIZE; i++)
if (vp->tx_skbuff[i]) {
@@ -1372,13 +1419,13 @@ vortex_close(struct net_device *dev)
return 0;
}
-static struct enet_statistics *
-vortex_get_stats(struct net_device *dev)
+static struct enet_statistics *corkscrew_get_stats(struct net_device *dev)
{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
unsigned long flags;
- if (dev->start) {
+ if (netif_running(dev)) {
save_flags(flags);
cli();
update_stats(dev->base_addr, dev);
@@ -1396,21 +1443,23 @@ vortex_get_stats(struct net_device *dev)
*/
static void update_stats(int ioaddr, struct net_device *dev)
{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ struct corkscrew_private *vp =
+ (struct corkscrew_private *) dev->priv;
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- vp->stats.tx_carrier_errors += inb(ioaddr + 0);
- vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
- /* Multiple collisions. */ inb(ioaddr + 2);
- vp->stats.collisions += inb(ioaddr + 3);
- vp->stats.tx_window_errors += inb(ioaddr + 4);
- vp->stats.rx_fifo_errors += inb(ioaddr + 5);
- vp->stats.tx_packets += inb(ioaddr + 6);
- vp->stats.tx_packets += (inb(ioaddr + 9)&0x30) << 4;
- /* Rx packets */ inb(ioaddr + 7); /* Must read to clear */
- /* Tx deferrals */ inb(ioaddr + 8);
+ vp->stats.tx_carrier_errors += inb(ioaddr + 0);
+ vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ /* Multiple collisions. */ inb(ioaddr + 2);
+ vp->stats.collisions += inb(ioaddr + 3);
+ vp->stats.tx_window_errors += inb(ioaddr + 4);
+ vp->stats.rx_fifo_errors += inb(ioaddr + 5);
+ vp->stats.tx_packets += inb(ioaddr + 6);
+ vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
+ /* Rx packets */ inb(ioaddr + 7);
+ /* Must read to clear */
+ /* Tx deferrals */ inb(ioaddr + 8);
/* Don't bother with register 9, an extension of registers 6&7.
If we do use the 6&7 values the atomic update assumption above
is invalid. */
@@ -1429,18 +1478,18 @@ static void update_stats(int ioaddr, struct net_device *dev)
The Vortex chip has no documented multicast filter, so the only
multicast setting is to receive all multicast frames. At least
the chip has a very clean way to set the mode, unlike many others. */
-static void
-set_rx_mode(struct net_device *dev)
+static void set_rx_mode(struct net_device *dev)
{
int ioaddr = dev->base_addr;
short new_mode;
if (dev->flags & IFF_PROMISC) {
- if (vortex_debug > 3)
- printk("%s: Setting promiscuous mode.\n", dev->name);
- new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
- } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
- new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
+ if (corkscrew_debug > 3)
+ printk("%s: Setting promiscuous mode.\n",
+ dev->name);
+ new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm;
+ } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
+ new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast;
} else
new_mode = SetRxFilter | RxStation | RxBroadcast;
@@ -1448,24 +1497,26 @@ set_rx_mode(struct net_device *dev)
}
#ifdef MODULE
-void
-cleanup_module(void)
+void cleanup_module(void)
{
struct net_device *next_dev;
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_vortex_dev) {
- next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module;
- if (root_vortex_dev->dma)
- free_dma(root_vortex_dev->dma);
- unregister_netdev(root_vortex_dev);
- outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
- release_region(root_vortex_dev->base_addr, CORKSCREW_TOTAL_SIZE);
- kfree(root_vortex_dev);
- root_vortex_dev = next_dev;
+ while (root_corkscrew_dev) {
+ next_dev =
+ ((struct corkscrew_private *) root_corkscrew_dev->
+ priv)->next_module;
+ if (root_corkscrew_dev->dma)
+ free_dma(root_corkscrew_dev->dma);
+ unregister_netdev(root_corkscrew_dev);
+ outw(TotalReset, root_corkscrew_dev->base_addr + EL3_CMD);
+ release_region(root_corkscrew_dev->base_addr,
+ CORKSCREW_TOTAL_SIZE);
+ kfree(root_corkscrew_dev);
+ root_corkscrew_dev = next_dev;
}
}
-#endif /* MODULE */
+#endif /* MODULE */
/*
* Local variables:
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index fe150fac5..9e3f72b33 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -297,7 +297,7 @@ static int elmc_open(struct net_device *dev)
alloc586(dev);
init586(dev);
startrecv586(dev);
- netif_wake_queue(dev);
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0; /* most done by init */
}
@@ -869,7 +869,7 @@ static void elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
if (dev == NULL) {
printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2));
return;
- } else if (!test_bit(LINK_STATE_START, &dev->state)) {
+ } else if (!netif_running(dev)) {
/* The 3c523 has this habit of generating interrupts during the
reset. I'm not sure if the ni52 has this same problem, but it's
really annoying if we haven't finished initializing it. I was
@@ -902,7 +902,7 @@ static void elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
#ifndef NO_NOPCOMMANDS
if (stat & STAT_CNA) {
/* CU went 'not ready' */
- if (test_bit(LINK_STATE_START, &dev->state)) {
+ if (netif_running(dev->state)) {
printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status);
}
}
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 9cce2fa76..dab3f99b9 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -902,7 +902,7 @@ static int mc32_open(struct net_device *dev)
mc32_rx_begin(dev);
mc32_tx_begin(dev);
- netif_wake_queue(dev);
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
@@ -1156,7 +1156,7 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
basically a FIFO queue of buffers matching
the card ring */
lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len;
- dev_kfree_skb(lp->tx_skb[lp->tx_skb_top]);
+ dev_kfree_skb_irq(lp->tx_skb[lp->tx_skb_top]);
lp->tx_skb[lp->tx_skb_top]=NULL;
lp->tx_skb_top++;
lp->tx_skb_top&=(TX_RING_MAX-1);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 4710b1d37..839c15ebc 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -14,6 +14,7 @@
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
Version history:
+ 0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
0.99H+lk1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
Remove compatibility defines for kernel versions < 2.2.x.
Update for new 2.3.x module interface
@@ -402,8 +403,6 @@ struct vortex_private {
struct sk_buff* rx_skbuff[RX_RING_SIZE];
struct sk_buff* tx_skbuff[TX_RING_SIZE];
struct net_device *next_module;
- void *priv_addr;
- dma_addr_t ring_dma;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
struct net_device_stats stats;
@@ -768,13 +767,11 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn;
vp->pdev = pdev;
- vp->priv_addr = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
- + sizeof(struct boom_tx_desc) * TX_RING_SIZE
- + 15, &vp->ring_dma);
- /* Make sure rings are 16 byte aligned. */
- vp->rx_ring = (void *)(((long)vp->priv_addr + 15) & ~15);
+ /* Makes sure rings are at least 16 byte aligned. */
+ vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
+ + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
+ &vp->rx_ring_dma);
vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
- vp->rx_ring_dma = (vp->ring_dma + 15) & ~15;
vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
/* The lower four bits are the media type. */
@@ -1088,7 +1085,7 @@ vortex_open(struct net_device *dev)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ));
+ vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
}
/* Wrap the ring. */
vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
@@ -1410,7 +1407,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
int len = (skb->len + 3) & ~3;
- outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len), ioaddr + Wn7_MasterAddr);
+ outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr);
outw(len, ioaddr + Wn7_MasterLen);
vp->tx_skb = skb;
outw(StartDMADown, ioaddr + EL3_CMD);
@@ -1482,7 +1479,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
vp->tx_skbuff[entry] = skb;
vp->tx_ring[entry].next = 0;
- vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len));
+ vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
@@ -1562,7 +1559,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (vp->tx_skbuff[entry]) {
struct sk_buff *skb = vp->tx_skbuff[entry];
- pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len);
+ pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(vp->tx_skbuff[entry]);
vp->tx_skbuff[entry] = 0;
}
@@ -1579,7 +1576,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & DMADone) {
if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3);
+ pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
if (inw(ioaddr + TxFree) > 1536) {
netif_wake_queue(dev);
@@ -1660,13 +1657,13 @@ static int vortex_rx(struct net_device *dev)
if (vp->bus_master &&
! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) {
dma_addr_t dma = pci_map_single(vp->pdev, skb_put(skb, pkt_len),
- pkt_len);
+ pkt_len, PCI_DMA_FROMDEVICE);
outl(dma, ioaddr + Wn7_MasterAddr);
outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
outw(StartDMAUp, ioaddr + EL3_CMD);
while (inw(ioaddr + Wn7_MasterStatus) & 0x8000)
;
- pci_unmap_single(vp->pdev, dma, pkt_len);
+ pci_unmap_single(vp->pdev, dma, pkt_len, PCI_DMA_FROMDEVICE);
} else {
insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
(pkt_len + 3) >> 2);
@@ -1740,7 +1737,7 @@ boomerang_rx(struct net_device *dev)
&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
skb->dev = dev;
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ);
+ pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
/* 'skb_put()' points to the start of sk_buff data area. */
memcpy(skb_put(skb, pkt_len),
vp->rx_skbuff[entry]->tail,
@@ -1751,7 +1748,7 @@ boomerang_rx(struct net_device *dev)
skb = vp->rx_skbuff[entry];
vp->rx_skbuff[entry] = NULL;
skb_put(skb, pkt_len);
- pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ);
+ pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
rx_nocopy++;
}
skb->protocol = eth_type_trans(skb, dev);
@@ -1780,7 +1777,7 @@ boomerang_rx(struct net_device *dev)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ));
+ vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
vp->rx_skbuff[entry] = skb;
}
vp->rx_ring[entry].status = 0; /* Clear complete bit. */
@@ -1828,7 +1825,7 @@ vortex_close(struct net_device *dev)
outl(0, ioaddr + UpListPtr);
for (i = 0; i < RX_RING_SIZE; i++)
if (vp->rx_skbuff[i]) {
- pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ);
+ pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
DEV_FREE_SKB(vp->rx_skbuff[i]);
vp->rx_skbuff[i] = 0;
}
@@ -1839,7 +1836,7 @@ vortex_close(struct net_device *dev)
if (vp->tx_skbuff[i]) {
struct sk_buff *skb = vp->tx_skbuff[i];
- pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len);
+ pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
DEV_FREE_SKB(skb);
vp->tx_skbuff[i] = 0;
}
@@ -1855,7 +1852,7 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev)
struct vortex_private *vp = (struct vortex_private *)dev->priv;
unsigned long flags;
- if (test_bit(LINK_STATE_START, &dev->state)) {
+ if (netif_running(dev)) {
save_flags(flags);
cli();
update_stats(dev->base_addr, dev);
@@ -2061,7 +2058,7 @@ static void __exit vortex_cleanup_module (void)
kfree(root_vortex_dev);
pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
+ sizeof(struct boom_tx_desc) * TX_RING_SIZE
- + 15, vp->priv_addr, vp->ring_dma);
+ + 15, vp->rx_ring, vp->rx_ring_dma);
kfree(vp);
root_vortex_dev = next_dev;
}
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
new file mode 100644
index 000000000..c2eceb8db
--- /dev/null
+++ b/drivers/net/8139too.c
@@ -0,0 +1,1879 @@
+/*
+
+ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
+
+ Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+ Originally: Written 1997-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Contributors:
+
+ Donald Becker - he wrote the original driver, kudos to him!
+ (but please don't e-mail him for support, this isn't his driver)
+
+ Tigran Aivazian - bug fixes, skbuff free cleanup
+
+ Martin Mares - suggestions for PCI cleanup
+
+ David S. Miller - PCI DMA and softnet updates
+
+ Ernst Gill - fixes ported from BSD driver
+
+ Daniel Kobras - identified specific locations of
+ posted MMIO write bugginess
+
+-----------------------------------------------------------------------------
+
+ Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the RealTek RTL8139 series, the RealTek
+Fast Ethernet controllers for PCI and CardBus. This chip is used on many
+low-end boards, sometimes with its markings changed.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board. The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+
+III. Driver operation
+
+IIIa. Rx Ring buffers
+
+The receive unit uses a single linear ring buffer rather than the more
+common (and more efficient) descriptor-based architecture. Incoming frames
+are sequentially stored into the Rx region, and the host copies them into
+skbuffs.
+
+Comment: While it is theoretically possible to process many frames in place,
+any delay in Rx processing would cause us to drop frames. More importantly,
+the Linux protocol stack is not designed to operate in this manner.
+
+IIIb. Tx operation
+
+The RTL8139 uses a fixed set of four Tx descriptors in register space.
+In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux
+aligns the IP header on word boundaries, and 14 byte ethernet header means
+that almost all frames will need to be copied to an alignment buffer.
+
+IVb. References
+
+http://www.realtek.com.tw/cn/cn.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+IVc. Errata
+
+1) The RTL-8139 has a serious problem with motherboards which do
+posted MMIO writes to PCI space. This driver works around the
+problem by having an MMIO register write be immediately followed by
+an MMIO register read.
+
+2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver.
+
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/io.h>
+
+
+#define RTL8139_VERSION "0.9.3"
+#define RTL8139_MODULE_NAME "8139too"
+#define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
+#define PFX RTL8139_MODULE_NAME ": "
+
+#undef RTL8139_DEBUG /* define to 1 to enable copious debugging info */
+
+#ifdef RTL8139_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define RTL8139_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */
+#if RTL8139_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+ if(!(expr)) { \
+ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
+#endif
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+
+#ifndef PCI_GET_DRIVER_DATA
+ #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data)
+ #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data))
+#endif /* PCI_GET_DRIVER_DATA */
+
+
+/* A few user-configurable values. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ The RTL chips use a 64 element hash table based on the Ethernet CRC. */
+static int multicast_filter_limit = 32;
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE 1536
+
+/* PCI Tuning Parameters
+ Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */
+#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (6*HZ)
+
+
+enum {
+ HAS_CHIP_XCVR = 0x020000,
+ HAS_LNK_CHNG = 0x040000,
+};
+
+#define RTL_IO_SIZE 0x80
+
+#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
+
+typedef enum {
+ RTL8139,
+ RTL8139_CB,
+ SMC1211TX,
+ /*MPX5030,*/
+ DELTA8139,
+ ADDTRON8139,
+} chip_t;
+
+
+static struct {
+ chip_t chip;
+ const char *name;
+} chip_info[] __devinitdata = {
+ { RTL8139, "RealTek RTL8139 Fast Ethernet"},
+ { RTL8139_CB, "RealTek RTL8139B PCI/CardBus"},
+ { SMC1211TX, "SMC1211TX EZCard 10/100 (RealTek RTL8139)"},
+/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)"},*/
+ { DELTA8139, "Delta Electronics 8139 10/100BaseTX"},
+ { ADDTRON8139, "Addtron Technolgy 8139 10/100BaseTX"},
+ {0,},
+};
+
+
+static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = {
+ {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB },
+ {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
+/* {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
+ {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
+ {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
+ {0,},
+};
+MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
+
+
+/* The rest of these values should never change. */
+#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAR0 = 8, /* Multicast filter. */
+ TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
+ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
+ RxBuf = 0x30,
+ RxEarlyCnt = 0x34,
+ RxEarlyStatus = 0x36,
+ ChipCmd = 0x37,
+ RxBufPtr = 0x38,
+ RxBufAddr = 0x3A,
+ IntrMask = 0x3C,
+ IntrStatus = 0x3E,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ Timer = 0x48, /* A general-purpose counter. */
+ RxMissed = 0x4C, /* 24 bits valid, write clears. */
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ FlashReg = 0x54,
+ GPPinData = 0x58,
+ GPPinDir = 0x59,
+ Config4 = 0x5A, /* absent on RTL-8139A */
+ HltClk = 0x5B,
+ MultiIntr = 0x5C,
+ TxSummary = 0x60,
+ BasicModeCtrl = 0x62,
+ BasicModeStatus = 0x64,
+ NWayAdvert = 0x66,
+ NWayLPAR = 0x68,
+ NWayExpansion = 0x6A,
+ /* Undocumented registers, but required for proper operation. */
+ FIFOTMS = 0x70, /* FIFO Control and test. */
+ CSCR = 0x74, /* Chip Status and Configuration Register. */
+ PARA78 = 0x78,
+ PARA7c = 0x7c, /* Magic transceiver parameter register. */
+};
+
+enum ChipCmdBits {
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+ PCIErr = 0x8000,
+ PCSTimeout = 0x4000,
+ RxFIFOOver = 0x40,
+ RxUnderrun = 0x20,
+ RxOverflow = 0x10,
+ TxErr = 0x08,
+ TxOK = 0x04,
+ RxErr = 0x02,
+ RxOK = 0x01,
+};
+enum TxStatusBits {
+ TxHostOwns = 0x2000,
+ TxUnderrun = 0x4000,
+ TxStatOK = 0x8000,
+ TxOutOfWindow = 0x20000000,
+ TxAborted = 0x40000000,
+ TxCarrierLost = 0x80000000,
+};
+enum RxStatusBits {
+ RxMulticast = 0x8000,
+ RxPhysical = 0x4000,
+ RxBroadcast = 0x2000,
+ RxBadSymbol = 0x0020,
+ RxRunt = 0x0010,
+ RxTooLong = 0x0008,
+ RxCRCErr = 0x0004,
+ RxBadAlign = 0x0002,
+ RxStatusOK = 0x0001,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+};
+
+/* Bits in Config1 */
+enum Config1Bits {
+ Cfg1_PM_Enable = 0x01,
+ Cfg1_VPD_Enable = 0x02,
+ Cfg1_PIO = 0x04,
+ Cfg1_MMIO = 0x08,
+ Cfg1_LWAKE = 0x10,
+ Cfg1_Driver_Load = 0x20,
+ Cfg1_LED0 = 0x40,
+ Cfg1_LED1 = 0x80,
+};
+
+/* Twister tuning parameters from RealTek.
+ Completely undocumented, but required to tune bad links. */
+enum CSCRBits {
+ CSCR_LinkOKBit = 0x0400,
+ CSCR_LinkChangeBit = 0x0800,
+ CSCR_LinkStatusBits = 0x0f000,
+ CSCR_LinkDownOffCmd = 0x003c0,
+ CSCR_LinkDownCmd = 0x0f3c0,
+};
+#define PARA78_default 0x78fa8388
+#define PARA7c_default 0xcb38de43 /* param[0][3] */
+#define PARA7c_xxx 0xcb38de43
+static const unsigned long param[4][4] = {
+ {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
+};
+
+struct ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+};
+
+
+#define PRIV_ALIGN 15 /* Required alignment mask */
+struct rtl8139_private {
+ chip_t chip;
+ void *mmio_addr;
+ spinlock_t lock;
+ int drv_flags;
+ struct pci_dev *pci_dev;
+ struct net_device_stats stats;
+ struct timer_list timer; /* Media selection timer. */
+ unsigned char *rx_ring;
+ unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
+ unsigned int cur_tx, dirty_tx, tx_flag;
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct ring_info tx_info[NUM_TX_DESC];
+ unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
+ unsigned char *tx_bufs; /* Tx bounce buffer region. */
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_bufs_dma;
+ char phys[4]; /* MII device addresses. */
+ char twistie, twist_row, twist_col; /* Twister tune state. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int duplex_lock:1;
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int media2:4; /* Secondary monitored media port. */
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+};
+
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
+MODULE_PARM (multicast_filter_limit, "i");
+MODULE_PARM (max_interrupt_work, "i");
+MODULE_PARM (debug, "i");
+
+static int read_eeprom (void *ioaddr, int location, int addr_len);
+static int rtl8139_open (struct net_device *dev);
+static int mdio_read (struct net_device *dev, int phy_id, int location);
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+ int val);
+static void rtl8139_timer (unsigned long data);
+static void rtl8139_tx_timeout (struct net_device *dev);
+static void rtl8139_init_ring (struct net_device *dev);
+static int rtl8139_start_xmit (struct sk_buff *skb,
+ struct net_device *dev);
+static void rtl8139_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs);
+static int rtl8139_close (struct net_device *dev);
+static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
+static inline u32 ether_crc (int length, unsigned char *data);
+static void rtl8139_set_rx_mode (struct net_device *dev);
+
+/* write MMIO register, with flush */
+/* Flush avoids rtl8139 bug w/ posted MMIO writes */
+#define RTL_W8_F(reg, val8) do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0)
+#define RTL_W16_F(reg, val16) do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0)
+#define RTL_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)
+
+
+#if MMIO_FLUSH_AUDIT_COMPLETE
+
+/* write MMIO register */
+#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
+
+#else
+
+/* write MMIO register, then flush */
+#define RTL_W8 RTL_W8_F
+#define RTL_W16 RTL_W16_F
+#define RTL_W32 RTL_W32_F
+
+#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
+
+/* read MMIO register */
+#define RTL_R8(reg) readb (ioaddr + (reg))
+#define RTL_R16(reg) readw (ioaddr + (reg))
+#define RTL_R32(reg) readl (ioaddr + (reg))
+
+
+static const u16 rtl8139_intr_mask =
+ PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
+ TxErr | TxOK | RxErr | RxOK;
+
+static const unsigned int rtl8139_rx_config =
+ (RX_FIFO_THRESH << 13) |
+ (RX_BUF_LEN_IDX << 11) |
+ (RX_DMA_BURST << 8);
+
+
+static const char * __devinit rtl8139_name_from_chip (chip_t chip)
+{
+ int i;
+
+ for (i = 0; i < arraysize (chip_info); i++)
+ if (chip == chip_info[i].chip)
+ return chip_info[i].name;
+
+ return "unknown";
+}
+
+
+static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
+{
+ void *ioaddr = NULL;
+ u8 tmp8;
+ int rc;
+ u32 pio_start, pio_end, pio_flags;
+ u32 mmio_start, mmio_end, mmio_flags;
+
+ DPRINTK ("ENTER\n");
+
+ assert (pdev != NULL);
+ assert (ioaddr_out != NULL);
+
+ *ioaddr_out = NULL;
+
+ pio_start = pci_resource_start (pdev, 0);
+ pio_end = pci_resource_end (pdev, 0);
+ pio_flags = pci_resource_flags (pdev, 0);
+
+ mmio_start = pci_resource_start (pdev, 1);
+ mmio_end = pci_resource_end (pdev, 1);
+ mmio_flags = pci_resource_flags (pdev, 1);
+
+ /* make sure PCI base addr 0 is PIO */
+ if (pio_start == 0 || pio_end <= pio_start ||
+ (!(pio_flags & IORESOURCE_IO))) {
+ printk (KERN_ERR PFX "no PIO resource, aborting\n");
+ return -ENODEV;
+ }
+
+ /* make sure PCI base addr 1 is MMIO */
+ if (mmio_start == 0 || mmio_end <= mmio_start ||
+ (!(mmio_flags & IORESOURCE_MEM))) {
+ printk (KERN_ERR PFX "no MMIO resource, aborting\n");
+ return -ENODEV;
+ }
+
+ /* make sure our PIO region in PCI space is available */
+ if (!request_region (pio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) {
+ printk (KERN_ERR PFX "no I/O resource available, aborting\n");
+ return -EBUSY;
+ }
+
+ /* make sure our MMIO region in PCI space is available */
+ if (!request_mem_region (mmio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) {
+ release_region (pio_start, RTL_IO_SIZE);
+ printk (KERN_ERR PFX "no mem resource available, aborting\n");
+ return -EBUSY;
+ }
+
+ /* enable device (incl. PCI PM wakeup), and bus-mastering */
+ pci_enable_device (pdev);
+ pci_set_master (pdev);
+
+ /* ioremap MMIO region */
+ ioaddr = ioremap (mmio_start, RTL_IO_SIZE);
+ if (ioaddr == NULL) {
+ printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
+ rc = -EIO;
+ goto err_out;
+ }
+
+ /* Bring the chip out of low-power mode. */
+ RTL_W8 (Config1, 0x00);
+
+ /* make sure chip thinks PIO and MMIO are enabled */
+ tmp8 = RTL_R8 (Config1);
+ if ((tmp8 & Cfg1_PIO) == 0) {
+ printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8);
+ rc = -EIO;
+ goto err_out;
+ }
+ if ((tmp8 & Cfg1_MMIO) == 0) {
+ printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8);
+ rc = -EIO;
+ goto err_out;
+ }
+
+ /* sanity checks -- ensure PIO and MMIO registers agree */
+ assert (inb (pio_start+Config0) == RTL_R8 (Config0));
+ assert (inb (pio_start+Config1) == RTL_R8 (Config1));
+ assert (inb (pio_start+TxConfig) == RTL_R8 (TxConfig));
+ assert (inb (pio_start+RxConfig) == RTL_R8 (RxConfig));
+
+ DPRINTK ("EXIT, returning 0\n");
+ *ioaddr_out = ioaddr;
+ return 0;
+
+err_out:
+ if (ioaddr)
+ iounmap (ioaddr);
+ release_region (pio_start, RTL_IO_SIZE);
+ release_mem_region (mmio_start, RTL_IO_SIZE);
+ DPRINTK ("EXIT, returning %d\n", rc);
+ return rc;
+}
+
+
+static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ struct rtl8139_private *tp;
+ int i, addr_len, option = -1;
+ void *ioaddr = NULL;
+
+ DPRINTK ("ENTER\n");
+
+ assert (pdev != NULL);
+ assert (ent != NULL);
+
+ i = rtl8139_init_pci (pdev, &ioaddr);
+ if (i < 0) {
+ DPRINTK ("EXIT, returning %d\n", i);
+ return i;
+ }
+
+ assert (ioaddr != NULL);
+
+ /* dev zeroed in init_etherdev */
+ dev = init_etherdev (NULL, sizeof (*tp) + PRIV_ALIGN);
+ if (dev == NULL) {
+ iounmap (ioaddr);
+ printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+ DPRINTK ("EXIT, returning -ENOMEM\n");
+ return -ENOMEM;
+ }
+
+ addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
+ for (i = 0; i < 3; i++)
+ ((u16 *) (dev->dev_addr))[i] =
+ le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+
+ /* The Rtl8139-specific entries in the device structure. */
+ dev->open = rtl8139_open;
+ dev->hard_start_xmit = rtl8139_start_xmit;
+ dev->stop = rtl8139_close;
+ dev->get_stats = rtl8139_get_stats;
+ dev->set_multicast_list = rtl8139_set_rx_mode;
+ dev->do_ioctl = mii_ioctl;
+ dev->tx_timeout = rtl8139_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ dev->irq = pdev->irq;
+ dev->base_addr = pci_resource_start (pdev, 1);
+
+ dev->priv = tp = (void *)
+ (((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
+
+ printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d, "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ dev->name, rtl8139_name_from_chip(ent->driver_data),
+ dev->base_addr, dev->irq,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5]);
+
+ /* tp zeroed in init_etherdev */
+ tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | RTL8139_CAPS;
+ tp->pci_dev = pdev;
+ tp->chip = ent->driver_data;
+ tp->mmio_addr = ioaddr;
+ tp->lock = SPIN_LOCK_UNLOCKED;
+
+ PCI_SET_DRIVER_DATA (pdev, dev);
+
+ tp->phys[0] = 32;
+
+ /* Put the chip into low-power mode. */
+ RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Config1, 0x03); /* Enable PM & PCI VPD */
+ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
+
+ /* The lower four bits are the media type. */
+ if (option > 0) {
+ tp->full_duplex = (option & 0x200) ? 1 : 0;
+ tp->default_port = option & 15;
+ if (tp->default_port)
+ tp->medialock = 1;
+ }
+
+ if (tp->full_duplex) {
+ printk (KERN_INFO
+ "%s: Media type forced to Full Duplex.\n",
+ dev->name);
+ mdio_write (dev, tp->phys[0], 4, 0x141);
+ tp->duplex_lock = 1;
+ }
+
+ DPRINTK ("EXIT - returning 0\n");
+ return 0;
+}
+
+
+static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
+ struct rtl8139_private *np;
+
+ DPRINTK ("ENTER\n");
+
+ assert (dev != NULL);
+
+ np = (struct rtl8139_private *) (dev->priv);
+ assert (np != NULL);
+
+ unregister_netdev (dev);
+
+ iounmap (np->mmio_addr);
+ release_region (pci_resource_start (pdev, 0), RTL_IO_SIZE);
+ release_mem_region (pci_resource_start (pdev, 1), RTL_IO_SIZE);
+
+#ifndef RTL8139_NDEBUG
+ /* poison memory before freeing */
+ memset (dev, 0xC0,
+ sizeof (struct net_device) +
+ sizeof (struct rtl8139_private) +
+ PRIV_ALIGN);
+#endif
+
+ kfree (dev);
+
+ DPRINTK ("EXIT\n");
+}
+
+
+/* Serial EEPROM section. */
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
+#define EE_CS 0x08 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x00
+#define EE_WRITE_1 0x02
+#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
+#define EE_ENB (0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay() readl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5)
+#define EE_READ_CMD (6)
+#define EE_ERASE_CMD (7)
+
+static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned retval = 0;
+ void *ee_addr = ioaddr + Cfg9346;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ DPRINTK ("ENTER\n");
+
+ writeb (EE_ENB & ~EE_CS, ee_addr);
+ writeb (EE_ENB, ee_addr);
+ eeprom_delay ();
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ writeb (EE_ENB | dataval, ee_addr);
+ eeprom_delay ();
+ writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay ();
+ }
+ writeb (EE_ENB, ee_addr);
+ eeprom_delay ();
+
+ for (i = 16; i > 0; i--) {
+ writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay ();
+ retval =
+ (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
+ 0);
+ writeb (EE_ENB, ee_addr);
+ eeprom_delay ();
+ }
+
+ /* Terminate the EEPROM access. */
+ writeb (~EE_CS, ee_addr);
+ eeprom_delay ();
+
+ DPRINTK ("EXIT - returning %d\n", retval);
+ return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+ serial MDIO protocol.
+ The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues. */
+#define MDIO_DIR 0x80
+#define MDIO_DATA_OUT 0x04
+#define MDIO_DATA_IN 0x02
+#define MDIO_CLK 0x01
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+
+#define mdio_delay() readb(mdio_addr)
+
+
+static char mii_2_8139_map[8] = {
+ BasicModeCtrl,
+ BasicModeStatus,
+ 0,
+ 0,
+ NWayAdvert,
+ NWayLPAR,
+ NWayExpansion,
+ 0
+};
+
+
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync (void *mdio_addr)
+{
+ int i;
+
+ DPRINTK ("ENTER\n");
+
+ for (i = 32; i >= 0; i--) {
+ writeb (MDIO_WRITE1, mdio_addr);
+ mdio_delay ();
+ writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
+ mdio_delay ();
+ }
+
+ DPRINTK ("EXIT\n");
+}
+
+
+static int mdio_read (struct net_device *dev, int phy_id, int location)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *mdio_addr = tp->mmio_addr + Config4;
+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int retval = 0;
+ int i;
+
+ DPRINTK ("ENTER\n");
+
+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
+ DPRINTK ("EXIT after directly using 8139 internal regs\n");
+ return location < 8 && mii_2_8139_map[location] ?
+ readw (tp->mmio_addr + mii_2_8139_map[location]) : 0;
+ }
+ mdio_sync (mdio_addr);
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+ writeb (MDIO_DIR | dataval, mdio_addr);
+ mdio_delay ();
+ writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
+ mdio_delay ();
+ }
+
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ writeb (0, mdio_addr);
+ mdio_delay ();
+ retval =
+ (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1
+ : 0);
+ writeb (MDIO_CLK, mdio_addr);
+ mdio_delay ();
+ }
+
+ DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff);
+ return (retval >> 1) & 0xffff;
+}
+
+
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+ int value)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *mdio_addr = tp->mmio_addr + Config4;
+ int mii_cmd =
+ (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+ int i;
+
+ DPRINTK ("ENTER\n");
+
+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
+ if (location < 8 && mii_2_8139_map[location]) {
+ writew (value,
+ tp->mmio_addr + mii_2_8139_map[location]);
+ readw (tp->mmio_addr + mii_2_8139_map[location]);
+ }
+ DPRINTK ("EXIT after directly using 8139 internal regs\n");
+ return;
+ }
+ mdio_sync (mdio_addr);
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval =
+ (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+ writeb (dataval, mdio_addr);
+ mdio_delay ();
+ writeb (dataval | MDIO_CLK, mdio_addr);
+ mdio_delay ();
+ }
+
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ writeb (0, mdio_addr);
+ mdio_delay ();
+ writeb (MDIO_CLK, mdio_addr);
+ mdio_delay ();
+ }
+
+ DPRINTK ("EXIT\n");
+}
+
+
+static int rtl8139_open (struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+ int i;
+
+ DPRINTK ("ENTER\n");
+
+ MOD_INC_USE_COUNT;
+
+ /* Soft reset the chip. */
+ RTL_W8 (ChipCmd, CmdReset);
+
+ if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) {
+ DPRINTK ("EXIT, returning -EBUSY\n");
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+ &tp->tx_bufs_dma);
+ tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+ &tp->rx_ring_dma);
+ if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
+ free_irq(dev->irq, dev);
+
+ if (tp->tx_bufs)
+ pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ if (tp->rx_ring)
+ pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+ tp->rx_ring, tp->rx_ring_dma);
+
+ DPRINTK ("EXIT, returning -ENOMEM\n");
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+
+ }
+
+ rtl8139_init_ring (dev);
+ tp->full_duplex = tp->duplex_lock;
+ tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
+
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--)
+ if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+ break;
+
+ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+ RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+ RTL_W32 (RxConfig, rtl8139_rx_config);
+ RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000);
+
+ /* Reset N-Way to chipset defaults */
+ RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9));
+ for (i = 1000; i > 0; i--)
+ if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
+ break;
+
+ /* Set N-Way to sane defaults */
+ RTL_W16 (FIFOTMS, 0x0000);
+ RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1);
+ RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
+
+ RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+ RTL_W8 (Cfg9346, 0x00);
+
+ RTL_W32 (RxBuf, tp->rx_ring_dma);
+
+ /* Start the chip's Tx and Rx process. */
+ RTL_W32 (RxMissed, 0);
+ rtl8139_set_rx_mode (dev);
+
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+ /* Enable all known interrupts by setting the interrupt mask. */
+ RTL_W16 (IntrMask, rtl8139_intr_mask);
+
+ DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d"
+ " GP Pins %2.2x %s-duplex.\n",
+ dev->name, pci_resource_start (tp->pci_dev, 1),
+ dev->irq, RTL_R8 (GPPinData),
+ tp->full_duplex ? "full" : "half");
+
+ /* Set the timer to switch to check for link beat and perhaps switch
+ to an alternate media type. */
+ init_timer (&tp->timer);
+ tp->timer.expires = jiffies + 3 * HZ;
+ tp->timer.data = (unsigned long) dev;
+ tp->timer.function = &rtl8139_timer;
+ add_timer (&tp->timer);
+
+ netif_start_queue (dev);
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+/* Start the hardware at open or resume. */
+static void rtl8139_hw_start (struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+ int i;
+
+ DPRINTK ("ENTER\n");
+
+ /* Soft reset the chip. */
+ RTL_W8 (ChipCmd, CmdReset);
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--)
+ if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+ break;
+
+ /* Restore our idea of the MAC address. */
+ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+ RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+ /* Hmmm, do these belong here? */
+ RTL_W8 (Cfg9346, 0x00);
+ tp->cur_rx = 0;
+
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+ RTL_W32 (RxConfig, rtl8139_rx_config);
+ /* Check this value: the documentation contradicts ifself. Is the
+ IFG correct with bit 28:27 zero, or with |0x03000000 ? */
+ RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000);
+
+ /* Reset N-Way to chipset defaults */
+ RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9));
+ for (i = 1000; i > 0; i--)
+ if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
+ break;
+
+ /* Set N-Way to sane defaults */
+ RTL_W16 (FIFOTMS, 0x0000);
+ RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1);
+ RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
+
+ /* check_duplex() here. */
+ RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+ RTL_W8 (Cfg9346, 0x00);
+
+ RTL_W32 (RxBuf, tp->rx_ring_dma);
+ /* Start the chip's Tx and Rx process. */
+ RTL_W32 (RxMissed, 0);
+ rtl8139_set_rx_mode (dev);
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+ /* Enable all known interrupts by setting the interrupt mask. */
+ RTL_W16 (IntrMask, rtl8139_intr_mask);
+
+ netif_start_queue (dev);
+
+ DPRINTK ("EXIT\n");
+}
+
+
+#ifndef RTL_TUNE_TWISTER
+static inline void rtl8139_tune_twister (struct net_device *dev,
+ struct rtl8139_private *tp) {}
+#else
+static void rtl8139_tune_twister (struct net_device *dev,
+ struct rtl8139_private *tp)
+{
+ int linkcase;
+
+ DPRINTK ("ENTER\n");
+
+ /* This is a complicated state machine to configure the "twister" for
+ impedance/echos based on the cable length.
+ All of this is magic and undocumented.
+ */
+ switch (tp->twistie) {
+ case 1:
+ if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {
+ /* We have link beat, let us tune the twister. */
+ RTL_W16 (CSCR, CSCR_LinkDownOffCmd);
+ tp->twistie = 2; /* Change to state 2. */
+ next_tick = HZ / 10;
+ } else {
+ /* Just put in some reasonable defaults for when beat returns. */
+ RTL_W16 (CSCR, CSCR_LinkDownCmd);
+ RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */
+ RTL_W32 (PARA78, PARA78_default);
+ RTL_W32 (PARA7c, PARA7c_default);
+ tp->twistie = 0; /* Bail from future actions. */
+ }
+ break;
+ case 2:
+ /* Read how long it took to hear the echo. */
+ linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;
+ if (linkcase == 0x7000)
+ tp->twist_row = 3;
+ else if (linkcase == 0x3000)
+ tp->twist_row = 2;
+ else if (linkcase == 0x1000)
+ tp->twist_row = 1;
+ else
+ tp->twist_row = 0;
+ tp->twist_col = 0;
+ tp->twistie = 3; /* Change to state 2. */
+ next_tick = HZ / 10;
+ break;
+ case 3:
+ /* Put out four tuning parameters, one per 100msec. */
+ if (tp->twist_col == 0)
+ RTL_W16 (FIFOTMS, 0);
+ RTL_W32 (PARA7c, param[(int) tp->twist_row]
+ [(int) tp->twist_col]);
+ next_tick = HZ / 10;
+ if (++tp->twist_col >= 4) {
+ /* For short cables we are done.
+ For long cables (row == 3) check for mistune. */
+ tp->twistie =
+ (tp->twist_row == 3) ? 4 : 0;
+ }
+ break;
+ case 4:
+ /* Special case for long cables: check for mistune. */
+ if ((RTL_R16 (CSCR) &
+ CSCR_LinkStatusBits) == 0x7000) {
+ tp->twistie = 0;
+ break;
+ } else {
+ RTL_W32 (PARA7c, 0xfb38de03);
+ tp->twistie = 5;
+ next_tick = HZ / 10;
+ }
+ break;
+ case 5:
+ /* Retune for shorter cable (column 2). */
+ RTL_W32 (FIFOTMS, 0x20);
+ RTL_W32 (PARA78, PARA78_default);
+ RTL_W32 (PARA7c, PARA7c_default);
+ RTL_W32 (FIFOTMS, 0x00);
+ tp->twist_row = 2;
+ tp->twist_col = 0;
+ tp->twistie = 3;
+ next_tick = HZ / 10;
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+
+ DPRINTK ("EXIT\n");
+}
+#endif /* RTL_TUNE_TWISTER */
+
+
+static void rtl8139_timer (unsigned long data)
+{
+ struct net_device *dev = (struct net_device *) data;
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+ int next_tick = 60 * HZ;
+ int mii_reg5 = mdio_read (dev, tp->phys[0], 5);
+
+ DPRINTK ("ENTER\n");
+
+ if (!tp->duplex_lock && mii_reg5 != 0xffff) {
+ int duplex = (mii_reg5 & 0x0100)
+ || (mii_reg5 & 0x01C0) == 0x0040;
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ printk (KERN_INFO
+ "%s: Setting %s-duplex based on MII #%d link"
+ " partner ability of %4.4x.\n", dev->name,
+ tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+ RTL_W8 (Cfg9346, 0x00);
+ }
+ }
+
+ rtl8139_tune_twister (dev, tp);
+
+ DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
+ dev->name, RTL_R16 (NWayLPAR));
+ DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x"
+ " RxStatus %4.4x.\n", dev->name,
+ RTL_R16 (IntrMask),
+ RTL_R16 (IntrStatus),
+ RTL_R32 (RxEarlyStatus));
+ DPRINTK ("%s: Chip config %2.2x %2.2x.\n",
+ dev->name, RTL_R8 (Config0),
+ RTL_R8 (Config1));
+
+ tp->timer.expires = jiffies + next_tick;
+ add_timer (&tp->timer);
+
+ DPRINTK ("EXIT\n");
+}
+
+
+static void rtl8139_tx_timeout (struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+ int mii_reg, i;
+
+ DPRINTK ("ENTER\n");
+
+ netif_stop_queue (dev);
+
+ DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
+ "media %2.2x.\n", dev->name,
+ RTL_R8 (ChipCmd),
+ RTL_R16 (IntrStatus),
+ RTL_R8 (GPPinData));
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16 (IntrMask, 0x0000);
+ /* Emit info to figure out what went wrong. */
+ printk (KERN_DEBUG
+ "%s: Tx queue start entry %d dirty entry %d.\n",
+ dev->name, tp->cur_tx, tp->dirty_tx);
+ for (i = 0; i < NUM_TX_DESC; i++)
+ printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n",
+ dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
+ i ==
+ tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
+ printk (KERN_DEBUG "%s: MII #%d registers are:", dev->name,
+ tp->phys[0]);
+ for (mii_reg = 0; mii_reg < 8; mii_reg++)
+ printk (" %4.4x", mdio_read (dev, tp->phys[0], mii_reg));
+ printk (".\n");
+
+ /* Stop a shared interrupt from scavenging while we are. */
+ tp->dirty_tx = tp->cur_tx = 0;
+
+ /* Dump the unsent Tx packets. */
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ struct ring_info *rp = &tp->tx_info[i];
+ if (rp->skb) {
+ dev_kfree_skb (rp->skb);
+ rp->skb = NULL;
+ tp->stats.tx_dropped++;
+ }
+ if (rp->mapping != 0) {
+ pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);
+ rp->mapping = 0;
+ }
+ }
+
+ rtl8139_hw_start (dev);
+
+ DPRINTK ("EXIT\n");
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring (struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ int i;
+
+ DPRINTK ("ENTER\n");
+
+ tp->cur_rx = 0;
+ tp->dirty_tx = tp->cur_tx = 0;
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ tp->tx_info[i].skb = NULL;
+ tp->tx_info[i].mapping = 0;
+ tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
+ }
+
+ DPRINTK ("EXIT\n");
+}
+
+static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+ int entry;
+ unsigned long flags;
+
+ DPRINTK ("ENTER\n");
+
+ netif_stop_queue (dev);
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = tp->cur_tx % NUM_TX_DESC;
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ tp->tx_info[entry].skb = skb;
+ if ((long) skb->data & 3) { /* Must use alignment buffer. */
+ tp->tx_info[entry].mapping = 0;
+ memcpy (tp->tx_buf[entry], skb->data, skb->len);
+
+ assert (tp->tx_bufs_dma > 0);
+ RTL_W32 (TxAddr0 + entry * 4, tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
+ } else {
+ tp->tx_info[entry].mapping =
+ pci_map_single(tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ assert (tp->tx_info[entry].mapping > 0);
+ RTL_W32 (TxAddr0 + entry * 4, tp->tx_info[entry].mapping);
+ }
+
+ /* Note: the chip doesn't have auto-pad! */
+ RTL_W32 (TxStatus0 + entry * 4,
+ tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+
+ dev->trans_start = jiffies;
+ if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) /* Typical path */
+ netif_start_queue (dev);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ DPRINTK ("%s: Queued Tx packet at %p size %lu to slot %d.\n",
+ dev->name, skb->data, skb->len, entry);
+
+ DPRINTK ("EXIT\n");
+ return 0;
+}
+
+
+static inline void rtl8139_tx_interrupt (struct net_device *dev,
+ struct rtl8139_private *tp)
+{
+ void *ioaddr;
+ unsigned int dirty_tx;
+
+ assert (dev != NULL);
+ assert (tp != NULL);
+
+ dirty_tx = tp->dirty_tx;
+ ioaddr = tp->mmio_addr;
+
+ while (tp->cur_tx - dirty_tx > 0) {
+ int entry = dirty_tx % NUM_TX_DESC;
+ int txstatus = RTL_R32 (TxStatus0 + (entry * 4));
+
+ if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
+ break; /* It still hasn't been Txed */
+
+ /* Note: TxCarrierLost is always asserted at 100mbps. */
+ if (txstatus & (TxOutOfWindow | TxAborted)) {
+ /* There was an major error, log it. */
+ DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, txstatus);
+ tp->stats.tx_errors++;
+ if (txstatus & TxAborted) {
+ tp->stats.tx_aborted_errors++;
+ RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x03000001);
+ }
+ if (txstatus & TxCarrierLost)
+ tp->stats.tx_carrier_errors++;
+ if (txstatus & TxOutOfWindow)
+ tp->stats.tx_window_errors++;
+#ifdef ETHER_STATS
+ if ((txstatus & 0x0f000000) == 0x0f000000)
+ tp->stats.collisions16++;
+#endif
+ } else {
+ if (txstatus & TxUnderrun) {
+ /* Add 64 to the Tx FIFO threshold. */
+ if (tp->tx_flag < 0x00300000)
+ tp->tx_flag += 0x00020000;
+ tp->stats.tx_fifo_errors++;
+ }
+ tp->stats.collisions += (txstatus >> 24) & 15;
+ tp->stats.tx_bytes += txstatus & 0x7ff;
+ tp->stats.tx_packets++;
+ }
+
+ if (tp->tx_info[entry].mapping != 0) {
+ pci_unmap_single (tp->pci_dev,
+ tp->tx_info[entry].mapping,
+ tp->tx_info[entry].skb->len,
+ PCI_DMA_TODEVICE);
+ tp->tx_info[entry].mapping = 0;
+ }
+ /* Free the original skb. */
+ dev_kfree_skb_irq (tp->tx_info[entry].skb);
+ tp->tx_info[entry].skb = NULL;
+ dirty_tx++;
+ if (tp->cur_tx - dirty_tx < NUM_TX_DESC)
+ netif_wake_queue (dev);
+ else
+ netif_stop_queue (dev);
+ }
+
+#ifndef RTL8139_NDEBUG
+ if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+ printk (KERN_ERR
+ "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
+ dev->name, dirty_tx, tp->cur_tx);
+ dirty_tx += NUM_TX_DESC;
+ }
+#endif
+
+ tp->dirty_tx = dirty_tx;
+}
+
+
+/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
+ field alignments and semantics. */
+static inline void rtl8139_rx_interrupt (struct net_device *dev,
+ struct rtl8139_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ unsigned char *rx_ring = tp->rx_ring;
+ u16 cur_rx = tp->cur_rx;
+
+ DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+ RTL_R16 (RxBufAddr),
+ RTL_R16 (RxBufPtr),
+ RTL_R8 (ChipCmd));
+
+ while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
+ int ring_offset = cur_rx % RX_BUF_LEN;
+ u32 rx_status =
+ le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+ int rx_size = rx_status >> 16;
+
+#ifdef RTL8139_DEBUG
+ int i;
+ DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x,"
+ " cur %4.4x.\n", dev->name, rx_status,
+ rx_size, cur_rx);
+ DPRINTK ("%s: Frame contents ", dev->name);
+ for (i = 0; i < 70; i++)
+ printk (" %2.2x", rx_ring[ring_offset + i]);
+ printk (".\n");
+#endif
+
+ /* E. Gill */
+ /* Note from BSD driver:
+ * Here's a totally undocumented fact for you. When the
+ * RealTek chip is in the process of copying a packet into
+ * RAM for you, the length will be 0xfff0. If you spot a
+ * packet header with this value, you need to stop. The
+ * datasheet makes absolutely no mention of this and
+ * RealTek should be shot for this.
+ */
+ if (rx_size == 0xfff0)
+ break;
+
+ if (rx_status &
+ (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr |
+ RxBadAlign)) {
+ DPRINTK ("%s: Ethernet frame had errors,"
+ " status %8.8x.\n", dev->name,
+ rx_status);
+ if (rx_status & RxTooLong) {
+ DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
+ dev->name, rx_status);
+ /* A.C.: The chip hangs here. */
+ }
+ tp->stats.rx_errors++;
+ if (rx_status & (RxBadSymbol | RxBadAlign))
+ tp->stats.rx_frame_errors++;
+ if (rx_status & (RxRunt | RxTooLong))
+ tp->stats.rx_length_errors++;
+ if (rx_status & RxCRCErr)
+ tp->stats.rx_crc_errors++;
+ /* Reset the receiver, based on RealTek recommendation. (Bug?) */
+ tp->cur_rx = 0;
+ RTL_W8 (ChipCmd, CmdTxEnb);
+ /* A.C.: Reset the multicast list. */
+ rtl8139_set_rx_mode (dev);
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+ } else {
+ /* Malloc up new buffer, compatible with net-2e. */
+ /* Omit the four octet CRC from the length. */
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb (rx_size + 2);
+ if (skb == NULL) {
+ printk (KERN_WARNING
+ "%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ /* We should check that some rx space is free.
+ If not, free one and mark stats->rx_dropped++. */
+ tp->stats.rx_dropped++;
+ break;
+ }
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align the IP fields. */
+ if (ring_offset + rx_size + 4 > RX_BUF_LEN) {
+ int semi_count =
+ RX_BUF_LEN - ring_offset - 4;
+ /* This could presumably use two calls to copy_and_sum()? */
+ memcpy (skb_put (skb, semi_count),
+ &rx_ring[ring_offset + 4],
+ semi_count);
+ memcpy (skb_put
+ (skb, rx_size - semi_count),
+ rx_ring, rx_size - semi_count);
+#ifdef RTL8139_DEBUG
+ {
+ int i;
+ printk (KERN_DEBUG
+ "%s: Frame wrap @%d",
+ dev->name, semi_count);
+ for (i = 0; i < 16; i++)
+ printk (" %2.2x",
+ rx_ring[i]);
+ printk (".\n");
+ memset (rx_ring, 0xcc, 16);
+ }
+#endif /* RTL8139_DEBUG */
+
+ } else {
+ eth_copy_and_sum (skb,
+ &rx_ring[ring_offset +
+ 4], rx_size, 0);
+ skb_put (skb, rx_size);
+ }
+ skb->protocol = eth_type_trans (skb, dev);
+ netif_rx (skb);
+ tp->stats.rx_bytes += rx_size;
+ tp->stats.rx_packets++;
+ }
+
+ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+ RTL_W16_F (RxBufPtr, cur_rx - 16);
+ }
+ DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+ RTL_R16 (RxBufAddr),
+ RTL_R16 (RxBufPtr),
+ RTL_R8 (ChipCmd));
+ tp->cur_rx = cur_rx;
+}
+
+
+static inline int rtl8139_weird_interrupt (struct net_device *dev,
+ struct rtl8139_private *tp,
+ int status, int link_changed)
+{
+ void *ioaddr;
+
+ DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
+ dev->name, status);
+
+ assert (dev != NULL);
+ assert (tp != NULL);
+
+ ioaddr = tp->mmio_addr;
+
+ if (status == 0xffffffff) {
+ printk (KERN_WARNING PFX "abnormal interrupt, card ejected? (ok to ignore)\n");
+ return -1;
+ }
+
+ /* Update the error count. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ if ((status & RxUnderrun) && link_changed &&
+ (tp->drv_flags & HAS_LNK_CHNG)) {
+ /* Really link-change on new chips. */
+ int lpar = RTL_R16 (NWayLPAR);
+ int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040
+ || tp->duplex_lock;
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+ RTL_W8 (Cfg9346, 0x00);
+ }
+ status &= ~RxUnderrun;
+ }
+ if (status &
+ (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
+ tp->stats.rx_errors++;
+
+ if (status & (PCSTimeout))
+ tp->stats.rx_length_errors++;
+ if (status & (RxUnderrun | RxFIFOOver))
+ tp->stats.rx_fifo_errors++;
+ if (status & RxOverflow) {
+ tp->stats.rx_over_errors++;
+ tp->cur_rx = RTL_R16 (RxBufAddr) % RX_BUF_LEN;
+ RTL_W16_F (RxBufPtr, tp->cur_rx - 16);
+ }
+ if (status & PCIErr) {
+ u16 pci_cmd_status;
+ pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
+
+ printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
+ dev->name, pci_cmd_status);
+ }
+
+ return 0;
+}
+
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+static void rtl8139_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ int boguscnt = max_interrupt_work;
+ void *ioaddr = tp->mmio_addr;
+ int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */
+
+ spin_lock_irq (&tp->lock);
+
+ /* disable interrupt generation while handling this interrupt */
+ RTL_W16 (IntrMask, 0x0000);
+
+ do {
+ int status = RTL_R16 (IntrStatus);
+ /* Acknowledge all of the current interrupt sources ASAP, but
+ an first get an additional status bit from CSCR. */
+ if (status & RxUnderrun)
+ link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
+
+ /* E. Gill */
+ /* In case of an RxFIFOOver we must also clear the RxOverflow
+ bit to avoid dropping frames for ever. Believe me, I got a
+ lot of troubles copying huge data (approximately 2 RxFIFOOver
+ errors per 1GB data transfer).
+ The following is written in the 'p-guide.pdf' file (RTL8139(A/B)
+ Programming guide V0.1, from 1999/1/15) on page 9 from REALTEC.
+ -----------------------------------------------------------
+ 2. RxFIFOOvw handling:
+ When RxFIFOOvw occurs, all incoming packets are discarded.
+ Clear ISR(RxFIFOOvw) doesn't dismiss RxFIFOOvw event. To
+ dismiss RxFIFOOvw event, the ISR(RxBufOvw) must be written
+ with a '1'.
+ -----------------------------------------------------------
+ Unfortunately I was not able to find any reason for the
+ RxFIFOOver error (I got the feeling this depends on the
+ CPU speed, lower CPU speed --> more errors).
+ After clearing the RxOverflow bit the transfer of the
+ packet was repeated and all data are error free transfered */
+ RTL_W16 (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
+
+ DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n",
+ dev->name, status,
+ RTL_R16 (IntrStatus));
+
+ if ((status &
+ (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
+ RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
+ break;
+
+ /* Check uncommon events with one test. */
+ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
+ RxFIFOOver | TxErr | RxErr))
+ if (rtl8139_weird_interrupt (dev, tp, status,
+ link_changed) == -1)
+ break;
+
+ if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */
+ rtl8139_rx_interrupt (dev, tp);
+
+ if (status & (TxOK | TxErr))
+ rtl8139_tx_interrupt (dev, tp);
+
+ if (--boguscnt < 0) {
+ printk (KERN_WARNING
+ "%s: Too much work at interrupt, "
+ "IntrStatus=0x%4.4x.\n", dev->name,
+ status);
+ /* Clear all interrupt sources. */
+ RTL_W16 (IntrStatus, 0xffff);
+ break;
+ }
+ } while (1);
+
+ /* Enable all known interrupts by setting the interrupt mask. */
+ RTL_W16 (IntrMask, rtl8139_intr_mask);
+
+ spin_unlock_irq (&tp->lock);
+
+ DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
+ dev->name, RTL_R16 (IntrStatus));
+
+}
+
+static int rtl8139_close (struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+ int i;
+
+ DPRINTK ("ENTER\n");
+
+ netif_stop_queue (dev);
+
+ DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
+ dev->name, RTL_R16 (IntrStatus));
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16 (IntrMask, 0x0000);
+
+ /* Stop the chip's Tx and Rx DMA processes. */
+ RTL_W8 (ChipCmd, 0x00);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ del_timer (&tp->timer);
+
+ free_irq (dev->irq, dev);
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ struct sk_buff *skb = tp->tx_info[i].skb;
+ dma_addr_t mapping = tp->tx_info[i].mapping;
+
+ if (skb) {
+ if (mapping)
+ pci_unmap_single (tp->pci_dev, mapping, skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb (skb);
+ }
+ tp->tx_info[i].skb = NULL;
+ tp->tx_info[i].mapping = 0;
+ }
+
+ pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+ tp->rx_ring, tp->rx_ring_dma);
+ pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ tp->rx_ring = NULL;
+ tp->tx_bufs = NULL;
+
+ /* Green! Put the chip in low-power mode. */
+ RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Config1, 0x03);
+ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
+
+ MOD_DEC_USE_COUNT;
+
+ DPRINTK ("EXIT\n");
+ return 0;
+}
+
+static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ u16 *data = (u16 *) & rq->ifr_data;
+
+ DPRINTK ("ENTER\n");
+
+ switch (cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ data[0] = tp->phys[0] & 0x3f;
+ /* Fall Through */
+ case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */
+ data[3] = mdio_read (dev, data[0], data[1] & 0x1f);
+ DPRINTK ("EXIT\n");
+ return 0;
+ case SIOCDEVPRIVATE + 2: /* Write the specified MII register */
+ if (!capable (CAP_NET_ADMIN))
+ return -EPERM;
+ mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
+ DPRINTK ("EXIT\n");
+ return 0;
+ default:
+ DPRINTK ("EXIT\n");
+ return -EOPNOTSUPP;
+ }
+
+ DPRINTK ("EXIT\n");
+}
+
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+
+ DPRINTK ("ENTER\n");
+
+ assert (tp != NULL);
+
+ if (netif_running(dev)) {
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+ }
+
+ DPRINTK ("EXIT\n");
+ return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ This routine is not state sensitive and need not be SMP locked. */
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc (int length, unsigned char *data)
+{
+ int crc = -1;
+
+ DPRINTK ("ENTER\n");
+
+ while (--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^
+ ((crc < 0) ^ (current_octet & 1) ?
+ ethernet_polynomial : 0);
+ }
+
+ DPRINTK ("EXIT\n");
+ return crc;
+}
+
+static void rtl8139_set_rx_mode (struct net_device *dev)
+{
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ int i, rx_mode;
+
+ DPRINTK ("ENTER\n");
+
+ DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+ dev->name, dev->flags, RTL_R32 (RxConfig));
+
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
+ /* Unconditionally log net taps. */
+ printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+ dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else if ((dev->mc_count > multicast_filter_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter perfectly -- accept all multicasts. */
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else {
+ struct dev_mc_list *mclist;
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list;
+ mclist && i < dev->mc_count;
+ i++, mclist =
+ mclist->next) set_bit (ether_crc (ETH_ALEN,
+ mclist->
+ dmi_addr) >> 26,
+ mc_filter);
+ }
+ /* We can safely update without stopping the chip. */
+ RTL_W32 (RxConfig, rtl8139_rx_config | rx_mode);
+ RTL_W32_F (MAR0 + 0, mc_filter[0]);
+ RTL_W32_F (MAR0 + 4, mc_filter[1]);
+
+ DPRINTK ("EXIT\n");
+}
+
+
+static void rtl8139_suspend (struct pci_dev *pdev)
+{
+ struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
+ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+ void *ioaddr = tp->mmio_addr;
+
+ netif_stop_queue (dev);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ RTL_W16 (IntrMask, 0x0000);
+ RTL_W8 (ChipCmd, 0x00);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+}
+
+
+static void rtl8139_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
+
+ rtl8139_hw_start(dev);
+}
+
+
+static struct pci_driver rtl8139_pci_driver = {
+ name: RTL8139_MODULE_NAME,
+ id_table: rtl8139_pci_tbl,
+ probe: rtl8139_init_one,
+ remove: rtl8139_remove_one,
+ suspend: rtl8139_suspend,
+ resume: rtl8139_resume,
+};
+
+
+static int __init rtl8139_init_module (void)
+{
+ int rc;
+
+ DPRINTK ("ENTER\n");
+
+ rc = pci_register_driver (&rtl8139_pci_driver);
+
+ if (rc > 0) {
+ printk (KERN_INFO RTL8139_DRIVER_NAME
+ " loaded (%d device%s registered)\n",
+ rc, rc > 1 ? "s" : "");
+ } else {
+ pci_unregister_driver (&rtl8139_pci_driver);
+ }
+
+ DPRINTK ("EXIT\n");
+ return rc > 0 ? 0 : -ENODEV;
+}
+
+
+static void __exit rtl8139_cleanup_module (void)
+{
+ pci_unregister_driver (&rtl8139_pci_driver);
+}
+
+
+module_init(rtl8139_init_module);
+module_exit(rtl8139_cleanup_module);
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 0b8a9723b..55c85bbd1 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -164,6 +164,8 @@ enum commands {
#define RX_SUSPEND 0x0030
#define RX_ABORT 0x0040
+#define TX_TIMEOUT 5
+
struct i596_reg {
unsigned short porthi;
unsigned short portlo;
@@ -267,6 +269,7 @@ struct i596_private {
struct tx_cmd tx_cmds[TX_RING_SIZE];
struct i596_tbd tbds[TX_RING_SIZE];
int next_tx_cmd;
+ spinlock_t lock;
};
char init_setup[] =
@@ -296,6 +299,7 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int i596_close(struct net_device *dev);
static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
static void print_eth(char *);
static void set_multicast_list(struct net_device *dev);
@@ -561,8 +565,7 @@ static inline void init_i596_mem(struct net_device *dev)
boguscnt = 200000;
- save_flags(flags);
- cli();
+ spin_lock_irqsave (&lp->lock, flags);
while (lp->scb.command)
if (--boguscnt == 0) {
@@ -573,7 +576,7 @@ static inline void init_i596_mem(struct net_device *dev)
lp->scb.command = RX_START;
CA(dev);
- restore_flags(flags);
+ spin_unlock_irqrestore (&lp->lock, flags);
boguscnt = 2000;
while (lp->scb.command)
@@ -778,8 +781,7 @@ static inline void i596_reset(struct net_device *dev, struct i596_private *lp, i
if (i596_debug > 1)
printk("i596_reset\n");
- save_flags(flags);
- cli();
+ spin_lock_irqsave (&lp->lock, flags);
while (lp->scb.command)
if (--boguscnt == 0) {
@@ -787,8 +789,8 @@ static inline void i596_reset(struct net_device *dev, struct i596_private *lp, i
lp->scb.status, lp->scb.command);
break;
}
- dev->start = 0;
- dev->tbusy = 1;
+
+ netif_stop_queue(dev);
lp->scb.command = CUC_ABORT | RX_ABORT;
CA(dev);
@@ -802,14 +804,12 @@ static inline void i596_reset(struct net_device *dev, struct i596_private *lp, i
lp->scb.status, lp->scb.command);
break;
}
- restore_flags(flags);
+ spin_unlock_irqrestore (&lp->lock, flags);
i596_cleanup_cmd(lp);
i596_rx(dev);
- dev->start = 1;
- dev->tbusy = 0;
- dev->interrupt = 0;
+ netif_start_queue(dev);
init_i596_mem(dev);
}
@@ -826,8 +826,8 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
cmd->status = 0;
cmd->command |= (CMD_EOL | CMD_INTR);
cmd->next = (struct i596_cmd *) I596_NULL;
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave (&lp->lock, flags);
/*
* RGH 300597: Looks to me like there could be a race condition
@@ -857,7 +857,8 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
lp->cmd_backlog++;
lp->cmd_head = WSWAPcmd(lp->scb.cmd); /* Is this redundant? RGH 300597 */
- restore_flags(flags);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
if (lp->cmd_backlog > max_cmd_backlog) {
unsigned long tickssofar = jiffies - lp->last_cmd;
@@ -886,9 +887,8 @@ static int i596_open(struct net_device *dev)
#endif
init_rx_bufs(dev);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
+
MOD_INC_USE_COUNT;
/* Initialize the 82596 memory */
@@ -897,51 +897,53 @@ static int i596_open(struct net_device *dev)
return 0; /* Always succeed */
}
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void i596_tx_timeout (struct net_device *dev)
{
struct i596_private *lp = (struct i596_private *) dev->priv;
int ioaddr = dev->base_addr;
+
+ /* Transmitter timeout, serious problems. */
+ printk ("%s: transmit timed out, status resetting.\n", dev->name);
+
+ lp->stats.tx_errors++;
+
+ /* Try to restart the adaptor */
+ if (lp->last_restart == lp->stats.tx_packets) {
+ if (i596_debug > 1)
+ printk ("Resetting board.\n");
+
+ /* Shutdown and restart */
+ i596_reset (dev, lp, ioaddr);
+ } else {
+ /* Issue a channel attention signal */
+ if (i596_debug > 1)
+ printk ("Kicking board.\n");
+ lp->scb.command = CUC_START | RX_START;
+ CA (dev);
+ lp->last_restart = lp->stats.tx_packets;
+ }
+
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+}
+
+
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
struct tx_cmd *tx_cmd;
struct i596_tbd *tbd;
if (i596_debug > 2)
printk("%s: 82596 start xmit\n", dev->name);
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("%s: transmit timed out, status resetting.\n",
- dev->name);
- lp->stats.tx_errors++;
- /* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
- if (i596_debug > 1)
- printk("Resetting board.\n");
-
- /* Shutdown and restart */
- i596_reset(dev, lp, ioaddr);
- } else {
- /* Issue a channel attention signal */
- if (i596_debug > 1)
- printk("Kicking board.\n");
- lp->scb.command = CUC_START | RX_START;
- CA(dev);
- lp->last_restart = lp->stats.tx_packets;
- }
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- }
if (i596_debug > 3)
printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
skb->len, (unsigned int)skb->data);
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
+ netif_stop_queue(dev);
+
+ {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
dev->trans_start = jiffies;
@@ -982,7 +984,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- dev->tbusy = 0;
+ netif_start_queue(dev);
return 0;
}
@@ -1086,11 +1088,14 @@ int __init i82596_probe(struct net_device *dev)
printk(version);
/* The 82596-specific entries in the device structure. */
- dev->open = &i596_open;
- dev->stop = &i596_close;
- dev->hard_start_xmit = &i596_start_xmit;
- dev->get_stats = &i596_get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->open = i596_open;
+ dev->stop = i596_close;
+ dev->hard_start_xmit = i596_start_xmit;
+ dev->get_stats = i596_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->tx_timeout = i596_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
dev->priv = (void *)(dev->mem_start);
@@ -1110,6 +1115,7 @@ int __init i82596_probe(struct net_device *dev)
lp->scb.command = 0;
lp->scb.cmd = (struct i596_cmd *) I596_NULL;
lp->scb.rfd = (struct i596_rfd *) I596_NULL;
+ lp->lock = SPIN_LOCK_UNLOCKED;
return 0;
}
@@ -1137,14 +1143,10 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (i596_debug > 3)
printk("%s: i596_interrupt(): irq %d\n", dev->name, irq);
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
-
lp = (struct i596_private *) dev->priv;
+
+ spin_lock (&lp->lock);
while (lp->scb.command)
if (--boguscnt == 0) {
@@ -1248,7 +1250,8 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ptr = WSWAPcmd(ptr->next);
}
- if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (dev->start))
+ if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) &&
+ netif_running(dev))
ack_cmd |= CUC_START;
lp->scb.cmd = WSWAPcmd(lp->cmd_head);
}
@@ -1257,7 +1260,7 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk("%s: i596 interrupt received a frame.\n", dev->name);
/* Only RX_START if stopped - RGH 07-07-96 */
if (status & 0x1000) {
- if (dev->start)
+ if (netif_running(dev))
ack_cmd |= RX_START;
if (i596_debug > 1)
printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0);
@@ -1304,7 +1307,8 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (i596_debug > 4)
printk("%s: exiting interrupt.\n", dev->name);
- dev->interrupt = 0;
+ spin_unlock (&lp->lock);
+
return;
}
@@ -1314,8 +1318,7 @@ static int i596_close(struct net_device *dev)
int boguscnt = 2000;
unsigned long flags;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
if (i596_debug > 1)
printk("%s: Shutting down ethercard, status was %4.4x.\n",
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index f63e1c310..641693f45 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -167,7 +167,6 @@ int ei_open(struct net_device *dev)
NS8390_init(dev, 1);
/* Set the flag before we drop the lock, That way the IRQ arrives
after its set and we get no silly warnings */
- clear_bit(LINK_STATE_RXSEM, &dev->state);
netif_start_queue(dev);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
ei_local->irqlock = 0;
@@ -203,8 +202,8 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* board has died and kick it.
*/
- if (test_bit(LINK_STATE_XOFF, &dev->state))
- { /* Do timeouts, just like the 8003 driver. */
+ if (netif_queue_stopped(dev)) {
+ /* Do timeouts, just like the 8003 driver. */
int txsr;
int isr;
int tickssofar = jiffies - dev->trans_start;
@@ -224,8 +223,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
ei_local->stat.tx_errors++;
isr = inb(e8390_base+EN0_ISR);
- if (!test_bit(LINK_STATE_START, &dev->state))
- {
+ if (!netif_running(dev)) {
spin_unlock_irqrestore(&ei_local->page_lock, flags);
printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name);
return 1;
@@ -430,8 +428,6 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
return;
}
- set_bit(LINK_STATE_RXSEM, &dev->state);
-
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
if (ei_debug > 3)
@@ -442,8 +438,7 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
&& ++nr_serviced < MAX_SERVICE)
{
- if (!test_bit(LINK_STATE_START, &dev->state))
- {
+ if (!netif_running(dev)) {
printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
interrupts = 0;
break;
@@ -491,7 +486,6 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
}
}
- clear_bit(LINK_STATE_RXSEM, &dev->state);
spin_unlock(&ei_local->page_lock);
return;
}
@@ -567,7 +561,6 @@ static void ei_tx_intr(struct net_device *dev)
printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
ei_local->name, ei_local->lasttx, ei_local->tx1);
ei_local->tx1 = 0;
- netif_start_queue(dev);
if (ei_local->tx2 > 0)
{
ei_local->txing = 1;
@@ -584,7 +577,6 @@ static void ei_tx_intr(struct net_device *dev)
printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
ei_local->name, ei_local->lasttx, ei_local->tx2);
ei_local->tx2 = 0;
- netif_start_queue(dev);
if (ei_local->tx1 > 0)
{
ei_local->txing = 1;
@@ -604,7 +596,6 @@ static void ei_tx_intr(struct net_device *dev)
* Single Tx buffer: mark it free so another packet can be loaded.
*/
ei_local->txing = 0;
- netif_start_queue(dev);
#endif
/* Minimize Tx latency: update the statistics after we restart TXing. */
@@ -840,7 +831,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
unsigned long flags;
/* If the card is stopped, just return the present stats. */
- if (!test_bit(LINK_STATE_START, &dev->state))
+ if (!netif_running(dev))
return &ei_local->stat;
spin_lock_irqsave(&ei_local->page_lock,flags);
@@ -936,7 +927,7 @@ static void do_set_multicast_list(struct net_device *dev)
* Ultra32 EISA) appears to have this bug fixed.
*/
- if (test_bit(LINK_STATE_START, &dev->state))
+ if (netif_running(dev))
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
for(i = 0; i < 8; i++)
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 835995197..f3cc0af3a 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -76,7 +76,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
tristate ' SMC Ultra support' CONFIG_ULTRA
tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32
- tristate ' SMC 9194 support' CONFIG_SMC9194
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' SMC 9194 support' CONFIG_SMC9194
+ fi
fi
bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
@@ -86,10 +88,6 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' NI5210 support' CONFIG_NI52
tristate ' NI6510 support' CONFIG_NI65
fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' RealTek 8129/8139 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8139
- tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
- fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
fi
@@ -97,18 +95,22 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
bool ' Other ISA cards' CONFIG_NET_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then
tristate ' Cabletron E21xx support' CONFIG_E2100
- tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+ fi
tristate ' EtherExpress 16 support' CONFIG_EEXPRESS
tristate ' EtherExpressPro support' CONFIG_EEXPRESS_PRO
- tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X
+ fi
tristate ' HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
tristate ' HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' ICL EtherTeam 16i/32 support (EXPERIMENTAL)' CONFIG_ETH16I
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' ICL EtherTeam 16i/32 support' CONFIG_ETH16I
fi
tristate ' NE2000/NE1000 support' CONFIG_NE2000
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
fi
bool ' SK_G16 support' CONFIG_SK_G16
@@ -117,8 +119,8 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' SKnet MCA support' CONFIG_SKMC
tristate ' NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
fi
- bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
- if [ "$CONFIG_NET_EISA" = "y" ]; then
+ bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+ if [ "$CONFIG_NET_PCI" = "y" ]; then
tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
@@ -128,29 +130,43 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT
- tristate ' CS89x0 support' CONFIG_CS89x0
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' CS89x0 support' CONFIG_CS89x0
+ fi
tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
- tristate ' EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
+ fi
+ tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then
+ bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM
+ fi
tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
fi
tristate ' PCI NE2000 support' CONFIG_NE2K_PCI
# tristate ' Sundance Alta support' CONFIG_ALTA
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129
+ fi
+ tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO
tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900
tristate ' TI ThunderLAN support' CONFIG_TLAN
tristate ' VIA Rhine support' CONFIG_VIA_RHINE
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
tristate ' SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
+ fi
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
fi
fi
bool ' Pocket and portable adapters' CONFIG_NET_POCKET
if [ "$CONFIG_NET_POCKET" = "y" ]; then
- bool ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+ tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600
tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620
fi
@@ -179,6 +195,7 @@ endmenu
bool 'FDDI driver support' CONFIG_FDDI
if [ "$CONFIG_FDDI" = "y" ]; then
bool ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+ tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -237,7 +254,9 @@ comment 'Wireless LAN (non-hamradio)'
bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
if [ "$CONFIG_NET_RADIO" = "y" ]; then
dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
- tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+ fi
tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3d7e6e851..3c2ede8f5 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -17,7 +17,8 @@ obj- :=
SUB_DIRS :=
MOD_SUB_DIRS :=
MOD_IN_SUB_DIRS :=
-ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin arcnet
+ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \
+ arcnet skfp
O_TARGET := net.o
MOD_LIST_NAME := NET_MODULES
@@ -119,7 +120,7 @@ obj-$(CONFIG_RCPCI) += rcpci.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
obj-$(CONFIG_PCNET32) += pcnet32.o
-obj-$(CONFIG_EEXPRESS_PRO100) += eepro100.o
+obj-$(CONFIG_EEPRO100) += eepro100.o
obj-$(CONFIG_TLAN) += tlan.o
obj-$(CONFIG_TULIP) += tulip.o
obj-$(CONFIG_EPIC100) += epic100.o
@@ -137,6 +138,15 @@ else
endif
endif
+ifeq ($(CONFIG_SKFP),y)
+ SUB_DIRS += skfp
+ obj-y += skfp/skfp.o
+else
+ ifeq ($(CONFIG_SKFP),m)
+ MOD_IN_SUB_DIRS += skfp
+ endif
+endif
+
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
@@ -228,7 +238,8 @@ obj-$(CONFIG_EL3) += 3c509.o
obj-$(CONFIG_3C515) += 3c515.o
obj-$(CONFIG_EEXPRESS) += eexpress.o
obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_RTL8139) += rtl8139.o
+obj-$(CONFIG_RTL8129) += rtl8129.o
+obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_WAVELAN) += wavelan.o
obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
obj-$(CONFIG_ZNET) += znet.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 50508db31..758914520 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -121,6 +121,7 @@ extern int de620_probe(struct net_device *);
/* FDDI adapters */
extern int dfx_probe(struct net_device *dev);
extern int apfddi_init(struct net_device *dev);
+extern int skfp_probe(struct net_device *dev);
/* Fibre Channel adapters */
extern int iph5526_probe(struct net_device *dev);
@@ -474,6 +475,9 @@ static int __init fddiif_probe(struct net_device *dev)
#ifdef CONFIG_APFDDI
&& apfddi_init(dev)
#endif
+#ifdef CONFIG_SKFP
+ && skfp_probe(dev)
+#endif
&& 1 ) {
return 1; /* -ENODEV or -EAGAIN would be more accurate. */
}
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index f15e31ae4..25364d920 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -164,7 +164,6 @@ static void load_csrs (struct lance_private *lp)
#define ZERO 0
/* Setup the Lance Rx and Tx rings */
-/* Sets dev->tbusy */
static void lance_init_ring (struct net_device *dev)
{
struct lance_private *lp = (struct lance_private *) dev->priv;
@@ -176,7 +175,7 @@ static void lance_init_ring (struct net_device *dev)
aib = lp->lance_init_block;
/* Lock out other processes while setting up hardware */
- dev->tbusy = 1;
+ netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
lp->rx_old = lp->tx_old = 0;
@@ -442,11 +441,6 @@ static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
if (!(csr0 & LE_C0_INTR)) /* Check if any interrupt has */
return; /* been generated by the Lance. */
- if (dev->interrupt)
- printk ("%s: again", dev->name);
-
- dev->interrupt = 1;
-
/* Acknowledge all the interrupt sources ASAP */
ll->rdp = csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|
LE_C0_INIT);
@@ -473,15 +467,13 @@ static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
ll->rdp = LE_C0_STRT;
}
- if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
- dev->tbusy = 0;
- mark_bh (NET_BH);
- }
+ if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL > 0)
+ netif_wake_queue(dev);
+
ll->rap = LE_CSR0;
ll->rdp = LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|
LE_C0_IDON|LE_C0_INEA;
- dev->interrupt = 0;
}
struct net_device *last_dev = 0;
@@ -506,9 +498,7 @@ static int lance_open (struct net_device *dev)
load_csrs (lp);
lance_init_ring (dev);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
status = init_restart_lance (lp);
@@ -522,9 +512,8 @@ static int lance_close (struct net_device *dev)
struct lance_private *lp = (struct lance_private *) dev->priv;
volatile struct lance_regs *ll = lp->ll;
- dev->start = 0;
- dev->tbusy = 1;
- del_timer(&lp->multicast_timer);
+ netif_stop_queue(dev);
+ del_timer_sync(&lp->multicast_timer);
/* Stop the card */
ll->rap = LE_CSR0;
@@ -548,11 +537,11 @@ static inline int lance_reset (struct net_device *dev)
ll->rdp = LE_C0_STOP;
load_csrs (lp);
+
lance_init_ring (dev);
dev->trans_start = jiffies;
- dev->interrupt = 0;
- dev->start = 1;
- dev->tbusy = 0;
+ netif_start_queue(dev);
+
status = init_restart_lance (lp);
#ifdef DEBUG_DRIVER
printk ("Lance restart=%d\n", status);
@@ -560,6 +549,17 @@ static inline int lance_reset (struct net_device *dev)
return status;
}
+static void lance_tx_timeout(struct net_device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_regs *ll = lp->ll;
+
+ printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n",
+ dev->name, ll->rdp);
+ lance_reset(dev);
+ netif_wake_queue(dev);
+}
+
static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct lance_private *lp = (struct lance_private *)dev->priv;
@@ -570,26 +570,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
static int outs;
unsigned long flags;
- /* Transmitter timeout, serious problems */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
-
- if (tickssofar < 100) {
- status = -1;
- } else {
- printk ("%s: transmit timed out, status %04x, resetting\n",
- dev->name, ll->rdp);
- lance_reset (dev);
- }
- return status;
- }
-
- /* Block a timer-based transmit from overlapping. */
- if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
- printk ("Transmitter access conflict.\n");
- return -1;
- }
-
skblen = skb->len;
save_flags(flags);
@@ -628,13 +608,15 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
outs++;
+
+ if (TX_BUFFS_AVAIL <= 0)
+ netif_stop_queue(dev);
+
/* Kick the lance: transmit now */
ll->rdp = LE_C0_INEA | LE_C0_TDMD;
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- if (TX_BUFFS_AVAIL)
- dev->tbusy = 0;
restore_flags(flags);
return status;
@@ -704,21 +686,17 @@ static void lance_set_multicast (struct net_device *dev)
volatile struct lance_init_block *ib = lp->init_block;
volatile struct lance_regs *ll = lp->ll;
- if (!dev->start)
+ if (!netif_running(dev))
return;
- if (dev->tbusy) {
- mod_timer(&lp->multicast_timer, jiffies + 2);
- return;
- }
- set_bit (0, (void *) &dev->tbusy);
-
if (lp->tx_old != lp->tx_new) {
mod_timer(&lp->multicast_timer, jiffies + 4);
- dev->tbusy = 0;
+ netif_wake_queue(dev);
return;
}
+ netif_stop_queue(dev);
+
ll->rap = LE_CSR0;
ll->rdp = LE_C0_STOP;
lance_init_ring (dev);
@@ -731,14 +709,19 @@ static void lance_set_multicast (struct net_device *dev)
}
load_csrs (lp);
init_restart_lance (lp);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
-int __init a2065_probe(struct net_device *dev)
+static int __init a2065_probe(void)
{
+ struct net_device *dev = NULL;
+ static int called = 0;
struct zorro_dev *z = NULL;
+ if (called)
+ return -ENODEV;
+ called++;
+
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
unsigned long board, base_addr, ram_start;
int is_cbm;
@@ -765,6 +748,18 @@ int __init a2065_probe(struct net_device *dev)
continue;
}
strcpy(z->name, "A2065 Ethernet Card");
+
+ dev = init_etherdev(NULL, sizeof(struct lance_private));
+
+ if (dev == NULL) {
+ release_mem_region(base_addr,
+ sizeof(struct lance_regs));
+ release_mem_region(ram_start, A2065_RAM_SIZE);
+ return -ENOMEM;
+ }
+ priv = (struct lance_private *)dev->priv;
+ memset(priv, 0, sizeof(struct lance_private));
+
if (is_cbm) { /* Commodore */
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x80;
@@ -782,18 +777,6 @@ int __init a2065_probe(struct net_device *dev)
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- init_etherdev(dev, 0);
-
- dev->priv = kmalloc(sizeof(struct lance_private), GFP_KERNEL);
- if (dev->priv == NULL) {
- release_mem_region(base_addr,
- sizeof(struct lance_regs));
- release_mem_region(ram_start, A2065_RAM_SIZE);
- return -ENOMEM;
- }
- priv = (struct lance_private *)dev->priv;
- memset(priv, 0, sizeof(struct lance_private));
-
dev->base_addr = ZTWO_VADDR(base_addr);
dev->mem_start = ZTWO_VADDR(ram_start);
dev->mem_end = dev->mem_start+A2065_RAM_SIZE;
@@ -812,6 +795,8 @@ int __init a2065_probe(struct net_device *dev)
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
+ dev->tx_timeout = &lance_tx_timeout;
+ dev->watchdog_timeo = 5*HZ;
dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->dma = 0;
@@ -828,31 +813,9 @@ int __init a2065_probe(struct net_device *dev)
}
-#ifdef MODULE
-static char devicename[9] = { 0, };
-
-static struct net_device a2065_dev =
-{
- devicename, /* filled in by register_netdev() */
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, a2065_probe,
-};
-
-int init_module(void)
-{
- int err;
-
- if ((err = register_netdev(&a2065_dev))) {
- if (err == -EIO)
- printk("No A2065 board found. Module not loaded.\n");
- return(err);
- }
- return(0);
-}
-
-void cleanup_module(void)
+static void __exit a2065_cleanup(void)
{
+#ifdef MODULE
struct lance_private *priv = (struct lance_private *)a2065_dev.priv;
unregister_netdev(&a2065_dev);
@@ -860,6 +823,8 @@ void cleanup_module(void)
sizeof(struct lance_regs));
release_mem_region(ZTWO_PADDR(a2065_dev.mem_start), A2065_RAM_SIZE);
kfree(priv);
+#endif
}
-#endif /* MODULE */
+module_init(a2065_probe);
+module_exit(a2065_cleanup);
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 8420b3e07..3587dfe16 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -2,7 +2,7 @@
* acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card
* and other Tigon based cards.
*
- * Copyright 1998, 1999 by Jes Sorensen, <Jes.Sorensen@cern.ch>.
+ * Copyright 1998-2000 by Jes Sorensen, <Jes.Sorensen@cern.ch>.
*
* Thanks to Alteon and 3Com for providing hardware and documentation
* enabling me to write this driver.
@@ -17,16 +17,23 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * Additional work by Pete Wyckoff <wyckoff@ca.sandia.gov> for initial
- * Alpha and trace dump support. The trace dump support has not been
- * integrated yet however.
- *
- * Big-endian+Sparc fixes and conversion to new PCI dma mapping
- * infrastructure by David S. Miller <davem@redhat.com>.
+ * Additional credits:
+ * Pete Wyckoff <wyckoff@ca.sandia.gov>: Initial Linux/Alpha and trace
+ * dump support. The trace dump support has not been
+ * integrated yet however.
+ * Troy Benjegerdes: Big Endian (PPC) patches.
+ * Nate Stahl: Better out of memory handling and stats support.
+ * Aman Singla: Nasty race between interrupt handler and tx code dealing
+ * with 'testing the tx_ret_csm and setting tx_full'
+ * David S. Miller <davem@redhat.com>: conversion to new PCI dma mapping
+ * infrastructure and Sparc support
+ * Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the
+ * driver under Linux/Sparc64
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioport.h>
@@ -38,6 +45,10 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
+
+#undef ETHTOOL
+#undef INDEX_DEBUG
+
#ifdef ETHTOOL
#include <linux/ethtool.h>
#endif
@@ -85,6 +96,62 @@
#define wmb() mb()
#endif
+#ifndef __exit
+#define __exit
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02030e)
+#define net_device device
+#endif
+
+#if (LINUX_VERSION_CODE >= 0x02031b)
+#define NEW_NETINIT
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02032a)
+typedef u32 dma_addr_t;
+
+static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t *dma_handle)
+{
+ void *virt_ptr;
+
+ virt_ptr = kmalloc(size, GFP_KERNEL);
+ *dma_handle = virt_to_bus(virt_ptr);
+ return virt_ptr;
+}
+#define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr)
+#define pci_map_single(cookie, address, size, dir) virt_to_bus(address)
+#define pci_unmap_single(cookie, address, size, dir)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02032b)
+/*
+ * SoftNet
+ */
+#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
+#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy)
+#define netif_stop_queue(dev) set_bit(0, &dev->tbusy)
+
+static inline void netif_start_queue(struct net_device *dev)
+{
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+}
+
+#define ace_mark_net_bh(foo) mark_bh(foo)
+#define ace_if_busy(dev) dev->tbusy
+#define ace_if_running(dev) dev->start
+#define ace_if_down(dev) {do{dev->start = 0;}while (0);}
+#else
+#define NET_BH 0
+#define ace_mark_net_bh(foo) {do{} while(0);}
+#define ace_if_busy(dev) netif_queue_stopped(dev)
+#define ace_if_running(dev) netif_running(dev)
+#define ace_if_down(dev) {do{} while(0);}
+#endif
+
#include "acenic.h"
/*
@@ -98,9 +165,10 @@
/*
* This driver currently supports Tigon I and Tigon II based cards
- * including the Alteon AceNIC and the 3Com 3C985. The driver should
- * also work on the NetGear GA620, however I have not been able to
- * test that myself.
+ * including the Alteon AceNIC, the 3Com 3C985[B] and NetGear
+ * GA620. The driver should also work on the SGI, DEC and Farallon
+ * versions of the card, however I have not been able to test that
+ * myself.
*
* This card is really neat, it supports receive hardware checksumming
* and jumbo frames (up to 9000 bytes) and does a lot of work in the
@@ -269,10 +337,14 @@
#define ACE_JUMBO_BUFSIZE (ACE_JUMBO_MTU + ETH_HLEN + 2+4+16)
#define DEF_TX_RATIO 24
-#define DEF_TX_COAL 1000
+/*
+ * There seems to be a magic difference in the effect between 995 and 996
+ * but little difference between 900 and 995 ... no idea why.
+ */
+#define DEF_TX_COAL 996
#define DEF_TX_MAX_DESC 40
#define DEF_RX_COAL 1000
-#define DEF_RX_MAX_DESC 20
+#define DEF_RX_MAX_DESC 25
#define TX_COAL_INTS_ONLY 0 /* seems not worth it */
#define DEF_TRACE 0
#define DEF_STAT 2 * TICKS_PER_SEC
@@ -286,115 +358,29 @@ static int max_rx_desc[8] = {0, };
static int tx_ratio[8] = {0, };
static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1};
-static const char __initdata *version = "acenic.c: v0.34 09/03/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n";
+static const char __initdata *version =
+ "acenic.c: v0.41 02/16/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
+ " http://home.cern.ch/~jes/gige/acenic.html\n";
static struct net_device *root_dev = NULL;
static int probed __initdata = 0;
-void ace_free_descriptors(struct net_device *dev)
-{
- struct ace_private *ap = dev->priv;
- int size;
- if (ap->rx_std_ring != NULL) {
- size = (sizeof(struct rx_desc) *
- (RX_STD_RING_ENTRIES +
- RX_JUMBO_RING_ENTRIES +
- RX_MINI_RING_ENTRIES +
- RX_RETURN_RING_ENTRIES));
- pci_free_consistent(ap->pdev, size,
- ap->rx_std_ring,
- ap->rx_ring_base_dma);
- ap->rx_std_ring = NULL;
- ap->rx_jumbo_ring = NULL;
- ap->rx_mini_ring = NULL;
- ap->rx_return_ring = NULL;
- }
- if (ap->evt_ring != NULL) {
- size = (sizeof(struct event) * EVT_RING_ENTRIES);
- pci_free_consistent(ap->pdev, size,
- ap->evt_ring,
- ap->evt_ring_dma);
- ap->evt_ring = NULL;
- }
- if (ap->evt_prd != NULL) {
- pci_free_consistent(ap->pdev, sizeof(u32),
- (void *)ap->evt_prd, ap->evt_prd_dma);
- ap->evt_prd = NULL;
- }
- if (ap->rx_ret_prd != NULL) {
- pci_free_consistent(ap->pdev, sizeof(u32),
- (void *)ap->rx_ret_prd, ap->rx_ret_prd_dma);
- ap->rx_ret_prd = NULL;
- }
- if (ap->tx_csm != NULL) {
- pci_free_consistent(ap->pdev, sizeof(u32),
- (void *)ap->tx_csm, ap->tx_csm_dma);
- ap->tx_csm = NULL;
- }
-}
-
-int ace_allocate_descriptors(struct net_device *dev)
+#ifdef NEW_NETINIT
+int __init acenic_probe (void)
+#else
+int __init acenic_probe (struct net_device *dev)
+#endif
{
- struct ace_private *ap = dev->priv;
- int size;
-
- size = (sizeof(struct rx_desc) *
- (RX_STD_RING_ENTRIES +
- RX_JUMBO_RING_ENTRIES +
- RX_MINI_RING_ENTRIES +
- RX_RETURN_RING_ENTRIES));
-
- ap->rx_std_ring = pci_alloc_consistent(ap->pdev, size,
- &ap->rx_ring_base_dma);
- if (ap->rx_std_ring == NULL)
- goto fail;
-
- ap->rx_jumbo_ring = ap->rx_std_ring + RX_STD_RING_ENTRIES;
- ap->rx_mini_ring = ap->rx_jumbo_ring + RX_JUMBO_RING_ENTRIES;
- ap->rx_return_ring = ap->rx_mini_ring + RX_MINI_RING_ENTRIES;
-
- size = (sizeof(struct event) * EVT_RING_ENTRIES);
-
- ap->evt_ring = pci_alloc_consistent(ap->pdev, size,
- &ap->evt_ring_dma);
-
- if (ap->evt_ring == NULL)
- goto fail;
-
- ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32),
- &ap->evt_prd_dma);
- if (ap->evt_prd == NULL)
- goto fail;
-
- ap->rx_ret_prd = pci_alloc_consistent(ap->pdev, sizeof(u32),
- &ap->rx_ret_prd_dma);
- if (ap->rx_ret_prd == NULL)
- goto fail;
-
- ap->tx_csm = pci_alloc_consistent(ap->pdev, sizeof(u32),
- &ap->tx_csm_dma);
- if (ap->tx_csm == NULL)
- goto fail;
-
- return 0;
-
-fail:
- /* Clean up. */
- ace_free_descriptors(dev);
- iounmap(ap->regs);
- unregister_netdev(dev);
- return 1;
-}
+#ifdef NEW_NETINIT
+ struct net_device *dev;
+#endif
-static int __init acenic_probe(void)
-{
- int boards_found = 0;
- int version_disp;
struct ace_private *ap;
struct pci_dev *pdev = NULL;
- struct net_device *dev;
+ int boards_found = 0;
+ int version_disp;
if (probed)
return -ENODEV;
@@ -405,7 +391,7 @@ static int __init acenic_probe(void)
version_disp = 0;
- while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))){
+ while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
(pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC)) &&
@@ -425,24 +411,23 @@ static int __init acenic_probe(void)
dev = init_etherdev(NULL, sizeof(struct ace_private));
- if (dev == NULL){
- printk(KERN_ERR "acenic: Unable to allocate net_device "
- "structure!\n");
+ if (dev == NULL) {
+ printk(KERN_ERR "acenic: Unable to allocate "
+ "net_device structure!\n");
break;
}
if (!dev->priv)
dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL);
- if (!dev->priv)
- {
- printk(KERN_ERR "acenic: Unable to allocate memory.\n");
+ if (!dev->priv) {
+ printk(KERN_ERR "acenic: Unable to allocate memory\n");
return -ENOMEM;
}
+
ap = dev->priv;
ap->pdev = pdev;
dev->irq = pdev->irq;
-
dev->open = &ace_open;
dev->hard_start_xmit = &ace_start_xmit;
dev->stop = &ace_close;
@@ -463,9 +448,20 @@ static int __init acenic_probe(void)
pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
+ /* OpenFirmware on Mac's does not set this - DOH.. */
+ if (!ap->pci_command & PCI_COMMAND_MEMORY) {
+ printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
+ "access - was not enabled by BIOS/Firmware\n",
+ dev->name);
+ ap->pci_command = ap->pci_command | PCI_COMMAND_MEMORY;
+ pci_write_config_word(ap->pdev, PCI_COMMAND,
+ ap->pci_command);
+ wmb();
+ }
+
pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
&ap->pci_latency);
- if (ap->pci_latency <= 0x40){
+ if (ap->pci_latency <= 0x40) {
ap->pci_latency = 0x40;
pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
ap->pci_latency);
@@ -477,53 +473,68 @@ static int __init acenic_probe(void)
/* NOTE: Cache line size is in 32-bit word units. */
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
#endif
+
/*
* Remap the regs into kernel space - this is abuse of
* dev->base_addr since it was means for I/O port
* addresses but who gives a damn.
*/
+#if (LINUX_VERSION_CODE < 0x02030d)
+ dev->base_addr = pdev->base_address[0];
+#else
dev->base_addr = pdev->resource[0].start;
+#endif
ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
- if (!ap->regs){
+ if (!ap->regs) {
printk(KERN_ERR "%s: Unable to map I/O register, "
"AceNIC %i will be disabled.\n",
dev->name, boards_found);
break;
}
- switch(pdev->vendor){
+ switch(pdev->vendor) {
case PCI_VENDOR_ID_ALTEON:
- sprintf(ap->name, "AceNIC Gigabit Ethernet");
+ strncpy(ap->name, "AceNIC Gigabit Ethernet",
+ sizeof (ap->name));
printk(KERN_INFO "%s: Alteon AceNIC ", dev->name);
break;
case PCI_VENDOR_ID_3COM:
- sprintf(ap->name, "3Com 3C985 Gigabit Ethernet");
+ strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
+ sizeof (ap->name));
printk(KERN_INFO "%s: 3Com 3C985 ", dev->name);
break;
case PCI_VENDOR_ID_NETGEAR:
- sprintf(ap->name, "NetGear GA620 Gigabit Ethernet");
+ strncpy(ap->name, "NetGear GA620 Gigabit Ethernet",
+ sizeof (ap->name));
printk(KERN_INFO "%s: NetGear GA620 ", dev->name);
break;
case PCI_VENDOR_ID_DEC:
if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) {
- sprintf(ap->name, "Farallon PN9000-SX "
- "Gigabit Ethernet");
+ strncpy(ap->name, "Farallon PN9000-SX "
+ "Gigabit Ethernet", sizeof (ap->name));
printk(KERN_INFO "%s: Farallon PN9000-SX ",
dev->name);
break;
}
case PCI_VENDOR_ID_SGI:
- sprintf(ap->name, "SGI AceNIC Gigabit Ethernet");
+ strncpy(ap->name, "SGI AceNIC Gigabit Ethernet",
+ sizeof (ap->name));
printk(KERN_INFO "%s: SGI AceNIC ", dev->name);
break;
default:
- sprintf(ap->name, "Unknown AceNIC based Gigabit Ethernet");
+ strncpy(ap->name, "Unknown AceNIC based Gigabit "
+ "Ethernet", sizeof (ap->name));
printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
break;
}
- printk("Gigabit Ethernet at 0x%08lx, irq %i\n",
- dev->base_addr, dev->irq);
+ ap->name [sizeof (ap->name) - 1] = '\0';
+ printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr);
+#ifdef __sparc__
+ printk("irq %s\n", __irq_itoa(dev->irq));
+#else
+ printk("irq %i\n", dev->irq);
+#endif
#ifdef CONFIG_ACENIC_OMIT_TIGON_I
if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
@@ -566,6 +577,7 @@ static int __init acenic_probe(void)
}
+#ifdef MODULE
MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");
MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver");
MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
@@ -576,25 +588,14 @@ MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
-static int __init acenic_init_module (void)
-{
- int cards;
-
- root_dev = NULL;
-
- cards = acenic_probe();
- return cards ? 0 : -ENODEV;
-}
-
-
-static void __exit acenic_cleanup_module (void)
+void __exit ace_module_cleanup(void)
{
struct ace_private *ap;
struct ace_regs *regs;
struct net_device *next;
short i;
- while (root_dev){
+ while (root_dev) {
next = ((struct ace_private *)root_dev->priv)->next;
ap = (struct ace_private *)root_dev->priv;
@@ -607,7 +608,7 @@ static void __exit acenic_cleanup_module (void)
/*
* This clears any pending interrupts
*/
- writel(0, &regs->Mb0Lo);
+ writel(1, &regs->Mb0Lo);
/*
* Make sure no other CPUs are processing interrupts
@@ -629,11 +630,11 @@ static void __exit acenic_cleanup_module (void)
mapping = ap->skb->rx_std_skbuff[i].mapping;
ap->rx_std_ring[i].size = 0;
- set_aceaddr(&ap->rx_std_ring[i].addr, 0);
+ ap->skb->rx_std_skbuff[i].skb = NULL;
pci_unmap_single(ap->pdev, mapping,
- ACE_STD_BUFSIZE - (2 + 16));
+ ACE_STD_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
- ap->skb->rx_std_skbuff[i].skb = NULL;
}
}
if (ap->version >= 2) {
@@ -644,34 +645,183 @@ static void __exit acenic_cleanup_module (void)
dma_addr_t mapping;
mapping = ap->skb->rx_mini_skbuff[i].mapping;
-
ap->rx_mini_ring[i].size = 0;
- set_aceaddr(&ap->rx_mini_ring[i].addr, 0);
+ ap->skb->rx_mini_skbuff[i].skb = NULL;
pci_unmap_single(ap->pdev, mapping,
- ACE_MINI_BUFSIZE - (2 + 16));
+ ACE_MINI_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
}
}
}
+ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
+ struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
+ if (skb) {
+ dma_addr_t mapping;
+
+ mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
+
+ ap->rx_jumbo_ring[i].size = 0;
+ ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+ pci_unmap_single(ap->pdev, mapping,
+ ACE_JUMBO_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skb);
+ }
+ }
ace_free_descriptors(root_dev);
- iounmap(regs);
- if(ap->trace_buf)
+ if (ap->trace_buf)
kfree(ap->trace_buf);
- pci_free_consistent(ap->pdev, sizeof(struct ace_info),
- ap->info, ap->info_dma);
- kfree(ap->skb);
- free_irq(root_dev->irq, root_dev);
+ if (ap->info)
+ pci_free_consistent(ap->pdev, sizeof(struct ace_info),
+ ap->info, ap->info_dma);
+ if (ap->skb)
+ kfree(ap->skb);
+ if (root_dev->irq)
+ free_irq(root_dev->irq, root_dev);
unregister_netdev(root_dev);
+ iounmap(regs);
kfree(root_dev);
root_dev = next;
}
}
-module_init(acenic_init_module);
-module_exit(acenic_cleanup_module);
+
+int __init ace_module_init(void)
+{
+ int cards;
+
+ root_dev = NULL;
+
+#ifdef NEW_NETINIT
+ cards = acenic_probe();
+#else
+ cards = acenic_probe(NULL);
+#endif
+ return cards ? 0 : -ENODEV;
+}
+
+
+#if (LINUX_VERSION_CODE < 0x02032a)
+int init_module(void)
+{
+ return ace_module_init();
+}
+
+
+void cleanup_module(void)
+{
+ ace_module_cleanup();
+}
+#endif
+#endif
+
+
+#if (LINUX_VERSION_CODE >= 0x02032a)
+module_init(ace_module_init);
+module_exit(ace_module_cleanup);
+#endif
+
+
+static void ace_free_descriptors(struct net_device *dev)
+{
+ struct ace_private *ap = dev->priv;
+ int size;
+
+ if (ap->rx_std_ring != NULL) {
+ size = (sizeof(struct rx_desc) *
+ (RX_STD_RING_ENTRIES +
+ RX_JUMBO_RING_ENTRIES +
+ RX_MINI_RING_ENTRIES +
+ RX_RETURN_RING_ENTRIES));
+ pci_free_consistent(ap->pdev, size,
+ ap->rx_std_ring,
+ ap->rx_ring_base_dma);
+ ap->rx_std_ring = NULL;
+ ap->rx_jumbo_ring = NULL;
+ ap->rx_mini_ring = NULL;
+ ap->rx_return_ring = NULL;
+ }
+ if (ap->evt_ring != NULL) {
+ size = (sizeof(struct event) * EVT_RING_ENTRIES);
+ pci_free_consistent(ap->pdev, size,
+ ap->evt_ring,
+ ap->evt_ring_dma);
+ ap->evt_ring = NULL;
+ }
+ if (ap->evt_prd != NULL) {
+ pci_free_consistent(ap->pdev, sizeof(u32),
+ (void *)ap->evt_prd, ap->evt_prd_dma);
+ ap->evt_prd = NULL;
+ }
+ if (ap->rx_ret_prd != NULL) {
+ pci_free_consistent(ap->pdev, sizeof(u32),
+ (void *)ap->rx_ret_prd, ap->rx_ret_prd_dma);
+ ap->rx_ret_prd = NULL;
+ }
+ if (ap->tx_csm != NULL) {
+ pci_free_consistent(ap->pdev, sizeof(u32),
+ (void *)ap->tx_csm, ap->tx_csm_dma);
+ ap->tx_csm = NULL;
+ }
+}
+
+
+static int ace_allocate_descriptors(struct net_device *dev)
+{
+ struct ace_private *ap = dev->priv;
+ int size;
+
+ size = (sizeof(struct rx_desc) *
+ (RX_STD_RING_ENTRIES +
+ RX_JUMBO_RING_ENTRIES +
+ RX_MINI_RING_ENTRIES +
+ RX_RETURN_RING_ENTRIES));
+
+ ap->rx_std_ring = pci_alloc_consistent(ap->pdev, size,
+ &ap->rx_ring_base_dma);
+ if (ap->rx_std_ring == NULL)
+ goto fail;
+
+ ap->rx_jumbo_ring = ap->rx_std_ring + RX_STD_RING_ENTRIES;
+ ap->rx_mini_ring = ap->rx_jumbo_ring + RX_JUMBO_RING_ENTRIES;
+ ap->rx_return_ring = ap->rx_mini_ring + RX_MINI_RING_ENTRIES;
+
+ size = (sizeof(struct event) * EVT_RING_ENTRIES);
+
+ ap->evt_ring = pci_alloc_consistent(ap->pdev, size,
+ &ap->evt_ring_dma);
+
+ if (ap->evt_ring == NULL)
+ goto fail;
+
+ ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32),
+ &ap->evt_prd_dma);
+ if (ap->evt_prd == NULL)
+ goto fail;
+
+ ap->rx_ret_prd = pci_alloc_consistent(ap->pdev, sizeof(u32),
+ &ap->rx_ret_prd_dma);
+ if (ap->rx_ret_prd == NULL)
+ goto fail;
+
+ ap->tx_csm = pci_alloc_consistent(ap->pdev, sizeof(u32),
+ &ap->tx_csm_dma);
+ if (ap->tx_csm == NULL)
+ goto fail;
+
+ return 0;
+
+fail:
+ /* Clean up. */
+ ace_free_descriptors(dev);
+ iounmap(ap->regs);
+ unregister_netdev(dev);
+ return 1;
+}
/*
@@ -694,19 +844,38 @@ static int __init ace_init(struct net_device *dev, int board_idx)
{
struct ace_private *ap;
struct ace_regs *regs;
- struct ace_info *info;
+ struct ace_info *info = NULL;
unsigned long tmp_ptr, myjif;
u32 tig_ver, mac1, mac2, tmp, pci_state;
+ int ecode = 0;
short i;
ap = dev->priv;
regs = ap->regs;
/*
+ * aman@sgi.com - its useful to do a NIC reset here to
+ * address the `Firmware not running' problem subsequent
+ * to any crashes involving the NIC
+ */
+ writel(HW_RESET | (HW_RESET << 24), &regs->HostCtrl);
+ wmb();
+
+ /*
* Don't access any other registes before this point!
*/
+#ifdef __BIG_ENDIAN
+ /*
+ * This will most likely need BYTE_SWAP once we switch
+ * to using __raw_writel()
+ */
+ writel((WORD_SWAP | CLR_INT |
+ ((WORD_SWAP | CLR_INT) << 24)),
+ &regs->HostCtrl);
+#else
writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
&regs->HostCtrl);
+#endif
mb();
/*
@@ -720,7 +889,7 @@ static int __init ace_init(struct net_device *dev, int board_idx)
switch(tig_ver){
#ifndef CONFIG_ACENIC_OMIT_TIGON_I
case 4:
- printk(KERN_INFO" Tigon I (Rev. 4), Firmware: %i.%i.%i, ",
+ printk(KERN_INFO" Tigon I (Rev. 4), Firmware: %i.%i.%i, ",
tigonFwReleaseMajor, tigonFwReleaseMinor,
tigonFwReleaseFix);
writel(0, &regs->LocalCtrl);
@@ -732,6 +901,11 @@ static int __init ace_init(struct net_device *dev, int board_idx)
tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor,
tigon2FwReleaseFix);
writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
+ /*
+ * The SRAM bank size does _not_ indicate the amount
+ * of memory on the card, it controls the _bank_ size!
+ * Ie. a 1MB AceNIC will have two banks of 512KB.
+ */
writel(SRAM_BANK_512K, &regs->LocalCtrl);
writel(SYNC_SRAM_TIMING, &regs->MiscCfg);
ap->version = 2;
@@ -739,7 +913,8 @@ static int __init ace_init(struct net_device *dev, int board_idx)
default:
printk(KERN_INFO" Unsupported Tigon version detected (%i), ",
tig_ver);
- return -ENODEV;
+ ecode = -ENODEV;
+ goto init_error;
}
/*
@@ -749,18 +924,34 @@ static int __init ace_init(struct net_device *dev, int board_idx)
* value a second time works as well. This is what caused the
* `Firmware not running' problem on the Tigon II.
*/
- writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL |
- ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
+#ifdef __BIG_ENDIAN
+ writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL | ACE_BYTE_SWAP_BD |
+ ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
+#else
+ writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL |
+ ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
+#endif
+ mb();
mac1 = 0;
- for(i = 0; i < 4; i++){
+ for(i = 0; i < 4; i++) {
mac1 = mac1 << 8;
- mac1 |= read_eeprom_byte(regs, 0x8c+i);
+ tmp = read_eeprom_byte(dev, 0x8c+i);
+ if (tmp < 0) {
+ ecode = -EIO;
+ goto init_error;
+ } else
+ mac1 |= (tmp & 0xff);
}
mac2 = 0;
- for(i = 4; i < 8; i++){
+ for(i = 4; i < 8; i++) {
mac2 = mac2 << 8;
- mac2 |= read_eeprom_byte(regs, 0x8c+i);
+ tmp = read_eeprom_byte(dev, 0x8c+i);
+ if (tmp < 0) {
+ ecode = -EIO;
+ goto init_error;
+ } else
+ mac2 |= (tmp & 0xff);
}
writel(mac1, &regs->MacAddrHi);
@@ -778,8 +969,11 @@ static int __init ace_init(struct net_device *dev, int board_idx)
dev->dev_addr[5] = mac2 & 0xff;
pci_state = readl(&regs->PciState);
- printk(KERN_INFO " PCI bus speed: %iMHz, latency: %i clks\n",
- (pci_state & PCI_66MHZ) ? 66 : 33, ap->pci_latency);
+ printk(KERN_INFO " PCI bus width: %i bits, speed: %iMHz, "
+ "latency: %i clks\n",
+ (pci_state & PCI_32BIT) ? 32 : 64,
+ (pci_state & PCI_66MHZ) ? 66 : 33,
+ ap->pci_latency);
/*
* Set the max DMA transfer size. Seems that for most systems
@@ -792,7 +986,7 @@ static int __init ace_init(struct net_device *dev, int board_idx)
* - that is what Alteon does for NT.
*/
tmp = READ_CMD_MEM | WRITE_CMD_MEM;
- if (ap->version >= 2){
+ if (ap->version >= 2) {
tmp |= (MEM_READ_MULTIPLE | (pci_state & PCI_66MHZ));
/*
* Tuning parameters only supported for 8 cards
@@ -805,11 +999,11 @@ static int __init ace_init(struct net_device *dev, int board_idx)
printk(KERN_INFO "%s: disabling PCI memory "
"write and invalidate\n", dev->name);
}
- } else if (ap->pci_command & PCI_COMMAND_INVALIDATE){
+ } else if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
printk(KERN_INFO "%s: PCI memory write & invalidate "
"enabled by BIOS, enabling counter "
"measures\n", dev->name);
- switch(L1_CACHE_BYTES){
+ switch(L1_CACHE_BYTES) {
case 16:
tmp |= DMA_WRITE_MAX_16;
break;
@@ -829,6 +1023,21 @@ static int __init ace_init(struct net_device *dev, int board_idx)
}
}
}
+#ifdef __sparc__
+ /* On this platform, we know what the best dma settings
+ * are. We use 64-byte maximum bursts, because if we
+ * burst larger than the cache line size (or even cross
+ * a 64byte boundry in a single burst) the UltraSparc
+ * PCI controller will disconnect at 64-byte multiples.
+ *
+ * Read-multiple will be properly enabled above, and when
+ * set will give the PCI controller proper hints about
+ * prefetching.
+ */
+ tmp = (tmp & ~(0xfc));
+ tmp |= DMA_READ_MAX_64;
+ tmp |= DMA_WRITE_MAX_64;
+#endif
writel(tmp, &regs->PciState);
/*
@@ -836,23 +1045,26 @@ static int __init ace_init(struct net_device *dev, int board_idx)
* and the control blocks for the transmit and receive rings
* as they need to be setup once and for all.
*/
- info = pci_alloc_consistent(ap->pdev, sizeof(struct ace_info),
- &ap->info_dma);
- if (info == NULL)
- goto fail;
+ if (!(info = pci_alloc_consistent(ap->pdev, sizeof(struct ace_info),
+ &ap->info_dma))) {
+ ecode = -EAGAIN;
+ goto init_error;
+ }
+ ap->info = info;
/*
* Get the memory for the skb rings.
*/
- if (!(ap->skb = kmalloc(sizeof(struct ace_skb), GFP_KERNEL)))
- goto fail;
-
- memset(ap->skb, 0, sizeof(struct ace_skb));
+ if (!(ap->skb = kmalloc(sizeof(struct ace_skb), GFP_KERNEL))) {
+ ecode = -EAGAIN;
+ goto init_error;
+ }
if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) {
printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
dev->name, dev->irq);
- goto fail;
+ ecode = -EAGAIN;
+ goto init_error;
}
/*
@@ -862,7 +1074,15 @@ static int __init ace_init(struct net_device *dev, int board_idx)
ap->next = root_dev;
root_dev = dev;
- ap->info = info;
+#ifdef INDEX_DEBUG
+ spin_lock_init(&ap->debug_lock);
+ ap->last_tx = TX_RING_ENTRIES - 1;
+ ap->last_std_rx = 0;
+ ap->last_mini_rx = 0;
+#endif
+
+ memset(ap->info, 0, sizeof(struct ace_info));
+ memset(ap->skb, 0, sizeof(struct ace_skb));
ace_load_firmware(dev);
ap->fw_running = 0;
@@ -900,14 +1120,14 @@ static int __init ace_init(struct net_device *dev, int board_idx)
set_aceaddr(&info->stats2_ptr, (dma_addr_t) tmp_ptr);
set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma);
- info->rx_std_ctrl.max_len = cpu_to_le16(ACE_STD_MTU + ETH_HLEN + 4);
- info->rx_std_ctrl.flags = cpu_to_le16(RCB_FLG_TCP_UDP_SUM);
+ info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
+ info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
memset(ap->rx_std_ring, 0,
RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
for (i = 0; i < RX_STD_RING_ENTRIES; i++)
- ap->rx_std_ring[i].flags = cpu_to_le16(BD_FLG_TCP_UDP_SUM);
+ ap->rx_std_ring[i].flags = BD_FLG_TCP_UDP_SUM;
ap->rx_std_skbprd = 0;
atomic_set(&ap->cur_rx_bufs, 0);
@@ -916,14 +1136,13 @@ static int __init ace_init(struct net_device *dev, int board_idx)
(ap->rx_ring_base_dma +
(sizeof(struct rx_desc) * RX_STD_RING_ENTRIES)));
info->rx_jumbo_ctrl.max_len = 0;
- info->rx_jumbo_ctrl.flags = cpu_to_le16(RCB_FLG_TCP_UDP_SUM);
+ info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
memset(ap->rx_jumbo_ring, 0,
RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++)
- ap->rx_jumbo_ring[i].flags =
- cpu_to_le16(BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO);
+ ap->rx_jumbo_ring[i].flags = BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO;
ap->rx_jumbo_skbprd = 0;
atomic_set(&ap->cur_jumbo_bufs, 0);
@@ -937,15 +1156,15 @@ static int __init ace_init(struct net_device *dev, int board_idx)
(sizeof(struct rx_desc) *
(RX_STD_RING_ENTRIES +
RX_JUMBO_RING_ENTRIES))));
- info->rx_mini_ctrl.max_len = cpu_to_le16(ACE_MINI_SIZE);
- info->rx_mini_ctrl.flags = cpu_to_le16(RCB_FLG_TCP_UDP_SUM);
+ info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
+ info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
ap->rx_mini_ring[i].flags =
- cpu_to_le16(BD_FLG_TCP_UDP_SUM | BD_FLG_MINI);
+ BD_FLG_TCP_UDP_SUM | BD_FLG_MINI;
} else {
set_aceaddr(&info->rx_mini_ctrl.rngptr, 0);
- info->rx_mini_ctrl.flags = cpu_to_le16(RCB_FLG_RNG_DISABLE);
+ info->rx_mini_ctrl.flags = RCB_FLG_RNG_DISABLE;
info->rx_mini_ctrl.max_len = 0;
}
@@ -959,7 +1178,7 @@ static int __init ace_init(struct net_device *dev, int board_idx)
RX_JUMBO_RING_ENTRIES +
RX_MINI_RING_ENTRIES))));
info->rx_return_ctrl.flags = 0;
- info->rx_return_ctrl.max_len = cpu_to_le16(RX_RETURN_RING_ENTRIES);
+ info->rx_return_ctrl.max_len = RX_RETURN_RING_ENTRIES;
memset(ap->rx_return_ring, 0,
RX_RETURN_RING_ENTRIES * sizeof(struct rx_desc));
@@ -969,14 +1188,14 @@ static int __init ace_init(struct net_device *dev, int board_idx)
writel(TX_RING_BASE, &regs->WinBase);
ap->tx_ring = (struct tx_desc *)regs->Window;
- for (i = 0; i < (TX_RING_ENTRIES * sizeof(struct tx_desc) / 4); i++){
+ for (i = 0; i < (TX_RING_ENTRIES * sizeof(struct tx_desc) / 4); i++) {
writel(0, (unsigned long)ap->tx_ring + i * 4);
}
set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
- info->tx_ctrl.max_len = cpu_to_le16(TX_RING_ENTRIES);
+ info->tx_ctrl.max_len = TX_RING_ENTRIES;
#if TX_COAL_INTS_ONLY
- info->tx_ctrl.flags = cpu_to_le16(RCB_FLG_COAL_INT_ONLY);
+ info->tx_ctrl.flags = RCB_FLG_COAL_INT_ONLY;
#else
info->tx_ctrl.flags = 0;
#endif
@@ -1044,7 +1263,7 @@ static int __init ace_init(struct net_device *dev, int board_idx)
tmp = LNK_ENABLE;
- if (option & 0x01){
+ if (option & 0x01) {
printk(KERN_INFO "%s: Setting half duplex link\n",
dev->name);
tmp &= ~LNK_FULL_DUPLEX;
@@ -1057,7 +1276,7 @@ static int __init ace_init(struct net_device *dev, int board_idx)
tmp |= LNK_100MB;
if (option & 0x40)
tmp |= LNK_1000MB;
- if ((option & 0x70) == 0){
+ if ((option & 0x70) == 0) {
printk(KERN_WARNING "%s: No media speed specified, "
"forcing auto negotiation\n", dev->name);
tmp |= LNK_NEGOTIATE | LNK_1000MB |
@@ -1070,7 +1289,7 @@ static int __init ace_init(struct net_device *dev, int board_idx)
"negotiation\n", dev->name);
if (option & 0x200)
tmp |= LNK_RX_FLOW_CTL_Y;
- if ((option & 0x400) && (ap->version >= 2)){
+ if ((option & 0x400) && (ap->version >= 2)) {
printk(KERN_INFO "%s: Enabling TX flow control\n",
dev->name);
tmp |= LNK_TX_FLOW_CTL_Y;
@@ -1100,7 +1319,7 @@ static int __init ace_init(struct net_device *dev, int board_idx)
ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0;
wmb();
- writel(0, &regs->TxPrd);
+ ace_set_txprd(regs, ap, 0);
writel(0, &regs->RxRetCsm);
/*
@@ -1113,11 +1332,31 @@ static int __init ace_init(struct net_device *dev, int board_idx)
*/
myjif = jiffies + 3 * HZ;
while (time_before(jiffies, myjif) && !ap->fw_running);
- if (!ap->fw_running){
+
+ if (!ap->fw_running) {
printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name);
+
ace_dump_trace(ap);
writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
- return -EBUSY;
+
+ /* aman@sgi.com - account for badly behaving firmware/NIC:
+ * - have observed that the NIC may continue to generate
+ * interrupts for some reason; attempt to stop it - halt
+ * second CPU for Tigon II cards, and also clear Mb0
+ * - if we're a module, we'll fail to load if this was
+ * the only GbE card in the system => if the kernel does
+ * see an interrupt from the NIC, code to handle it is
+ * gone and OOps! - so free_irq also
+ */
+ if (ap->version >= 2)
+ writel(readl(&regs->CpuBCtrl) | CPU_HALT,
+ &regs->CpuBCtrl);
+ writel(0, &regs->Mb0Lo);
+ free_irq(dev->irq, dev);
+ dev->irq = 0;
+
+ ecode = -EBUSY;
+ goto init_error;
}
/*
@@ -1137,17 +1376,17 @@ static int __init ace_init(struct net_device *dev, int board_idx)
"the RX mini ring\n", dev->name);
}
return 0;
-
-fail:
- if (info != NULL)
- pci_free_consistent(ap->pdev, sizeof(struct ace_info),
- info, ap->info_dma);
- if (ap->skb != NULL) {
+ init_error:
+ iounmap(ap->regs);
+ unregister_netdev(dev);
+ if (ap->skb) {
kfree(ap->skb);
ap->skb = NULL;
}
-
- return -EAGAIN;
+ if (ap->info)
+ pci_free_consistent(ap->pdev, sizeof(struct ace_info),
+ info, ap->info_dma);
+ return ecode;
}
@@ -1165,7 +1404,7 @@ static void ace_timer(unsigned long data)
* seconds and there is data in the transmit queue, thus we
* asume the card is stuck.
*/
- if (le32_to_cpu(*(ap->tx_csm)) != ap->tx_ret_csm){
+ if (*ap->tx_csm != ap->tx_ret_csm) {
printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n",
dev->name, (unsigned int)readl(&regs->HostCtrl));
}
@@ -1248,23 +1487,30 @@ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
dma_addr_t mapping;
skb = alloc_skb(ACE_STD_BUFSIZE, GFP_ATOMIC);
+ if (!skb)
+ break;
+
/*
* Make sure IP header starts on a fresh cache line.
*/
skb_reserve(skb, 2 + 16);
mapping = pci_map_single(ap->pdev, skb->data,
- ACE_STD_BUFSIZE - (2 + 16));
+ ACE_STD_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
ap->skb->rx_std_skbuff[idx].skb = skb;
ap->skb->rx_std_skbuff[idx].mapping = mapping;
rd = &ap->rx_std_ring[idx];
set_aceaddr(&rd->addr, mapping);
- rd->size = cpu_to_le16(ACE_STD_MTU + ETH_HLEN + 4);
- rd->idx = cpu_to_le16(idx);
+ rd->size = ACE_STD_MTU + ETH_HLEN + 4;
+ rd->idx = idx;
idx = (idx + 1) % RX_STD_RING_ENTRIES;
}
- atomic_add(nr_bufs, &ap->cur_rx_bufs);
+ if (!i)
+ goto error_out;
+
+ atomic_add(i, &ap->cur_rx_bufs);
ap->rx_std_skbprd = idx;
if (ACE_IS_TIGON_I(ap)) {
@@ -1278,8 +1524,14 @@ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
wmb();
}
+ out:
clear_bit(0, &ap->std_refill_busy);
return;
+
+ error_out:
+ printk(KERN_INFO "Out of memory when allocating "
+ "standard receive buffers\n");
+ goto out;
}
@@ -1297,31 +1549,43 @@ static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs)
dma_addr_t mapping;
skb = alloc_skb(ACE_MINI_BUFSIZE, GFP_ATOMIC);
+ if (!skb)
+ break;
+
/*
* Make sure the IP header ends up on a fresh cache line
*/
skb_reserve(skb, 2 + 16);
mapping = pci_map_single(ap->pdev, skb->data,
- ACE_MINI_BUFSIZE - (2 + 16));
+ ACE_MINI_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
ap->skb->rx_mini_skbuff[idx].skb = skb;
ap->skb->rx_mini_skbuff[idx].mapping = mapping;
rd = &ap->rx_mini_ring[idx];
set_aceaddr(&rd->addr, mapping);
- rd->size = cpu_to_le16(ACE_MINI_SIZE);
- rd->idx = cpu_to_le16(idx);
+ rd->size = ACE_MINI_SIZE;
+ rd->idx = idx;
idx = (idx + 1) % RX_MINI_RING_ENTRIES;
}
- atomic_add(nr_bufs, &ap->cur_mini_bufs);
+ if (!i)
+ goto error_out;
+
+ atomic_add(i, &ap->cur_mini_bufs);
ap->rx_mini_skbprd = idx;
writel(idx, &regs->RxMiniPrd);
wmb();
+ out:
clear_bit(0, &ap->mini_refill_busy);
return;
+ error_out:
+ printk(KERN_INFO "Out of memory when allocating "
+ "mini receive buffers\n");
+ goto out;
}
@@ -1344,23 +1608,30 @@ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs)
dma_addr_t mapping;
skb = alloc_skb(ACE_JUMBO_BUFSIZE, GFP_ATOMIC);
+ if (!skb)
+ break;
+
/*
* Make sure the IP header ends up on a fresh cache line
*/
skb_reserve(skb, 2 + 16);
mapping = pci_map_single(ap->pdev, skb->data,
- ACE_JUMBO_BUFSIZE - (2 + 16));
+ ACE_JUMBO_BUFSIZE - (2 + 16),
+ PCI_DMA_FROMDEVICE);
ap->skb->rx_jumbo_skbuff[idx].skb = skb;
ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
rd = &ap->rx_jumbo_ring[idx];
set_aceaddr(&rd->addr, mapping);
- rd->size = cpu_to_le16(ACE_JUMBO_MTU + ETH_HLEN + 4);
- rd->idx = cpu_to_le16(idx);
+ rd->size = ACE_JUMBO_MTU + ETH_HLEN + 4;
+ rd->idx = idx;
idx = (idx + 1) % RX_JUMBO_RING_ENTRIES;
}
- atomic_add(nr_bufs, &ap->cur_jumbo_bufs);
+ if (!i)
+ goto error_out;
+
+ atomic_add(i, &ap->cur_jumbo_bufs);
ap->rx_jumbo_skbprd = idx;
if (ACE_IS_TIGON_I(ap)) {
@@ -1374,52 +1645,13 @@ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs)
wmb();
}
+ out:
clear_bit(0, &ap->jumbo_refill_busy);
return;
-}
-
-
-/*
- * Tell the firmware not to accept jumbos and flush the jumbo ring.
- */
-static int ace_flush_jumbo_rx_ring(struct net_device *dev)
-{
- struct ace_private *ap;
- struct ace_regs *regs;
- struct cmd cmd;
- short i;
-
- ap = (struct ace_private *)dev->priv;
- regs = ap->regs;
-
- if (ap->jumbo){
- cmd.evt = C_RESET_JUMBO_RNG;
- cmd.code = 0;
- cmd.idx = 0;
- ace_issue_cmd(regs, &cmd);
-
- for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
- struct sk_buff *skb;
-
- skb = ap->skb->rx_jumbo_skbuff[i].skb;
- if (skb) {
- dma_addr_t mapping;
-
- mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
-
- ap->rx_jumbo_ring[i].size = 0;
- set_aceaddr(&ap->rx_jumbo_ring[i].addr, 0);
- pci_unmap_single(ap->pdev, mapping,
- ACE_JUMBO_BUFSIZE - (2 + 16));
- dev_kfree_skb(skb);
- ap->skb->rx_jumbo_skbuff[i].skb = NULL;
- }
- }
- }else
- printk(KERN_ERR "%s: Trying to flush Jumbo ring without "
- "Jumbo support enabled\n", dev->name);
-
- return 0;
+ error_out:
+ printk(KERN_INFO "Out of memory when allocating "
+ "jumbo receive buffers\n");
+ goto out;
}
@@ -1434,23 +1666,20 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
ap = (struct ace_private *)dev->priv;
- while (evtcsm != evtprd){
- struct event evt_local;
-
- memcpy(&evt_local, &ap->evt_ring[evtcsm], sizeof(evt_local));
- evt_local.u.word = le32_to_cpu(evt_local.u.word);
- switch (evt_local.u.data.evt){
+ while (evtcsm != evtprd) {
+ switch (ap->evt_ring[evtcsm].evt) {
case E_FW_RUNNING:
printk(KERN_INFO "%s: Firmware up and running\n",
dev->name);
ap->fw_running = 1;
+ wmb();
break;
case E_STATS_UPDATED:
break;
case E_LNK_STATE:
{
- u16 code = evt_local.u.data.code;
- if (code == E_C_LINK_UP){
+ u16 code = ap->evt_ring[evtcsm].code;
+ if (code == E_C_LINK_UP) {
printk(KERN_WARNING "%s: Optical link UP\n",
dev->name);
}
@@ -1463,7 +1692,7 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
break;
}
case E_ERROR:
- switch(evt_local.u.data.code){
+ switch(ap->evt_ring[evtcsm].code) {
case E_C_ERR_INVAL_CMD:
printk(KERN_ERR "%s: invalid command error\n",
dev->name);
@@ -1478,14 +1707,31 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
break;
default:
printk(KERN_ERR "%s: unknown error %02x\n",
- dev->name, evt_local.u.data.code);
+ dev->name, ap->evt_ring[evtcsm].code);
}
break;
case E_RESET_JUMBO_RNG:
+ {
+ int i;
+ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
+ if (ap->skb->rx_jumbo_skbuff[i].skb) {
+ ap->rx_jumbo_ring[i].size = 0;
+ set_aceaddr(&ap->rx_jumbo_ring[i].addr, 0);
+ dev_kfree_skb(ap->skb->rx_jumbo_skbuff[i].skb);
+ ap->skb->rx_jumbo_skbuff[i].skb = NULL;
+ }
+ }
+ ap->jumbo = 0;
+ printk(KERN_INFO "%s: Jumbo ring flushed\n",
+ dev->name);
+ if (!ap->tx_full)
+ netif_wake_queue(dev);
+ clear_bit(0, &ap->jumbo_refill_busy);
break;
+ }
default:
printk(KERN_ERR "%s: Unhandled event 0x%02x\n",
- dev->name, evt_local.u.data.evt);
+ dev->name, ap->evt_ring[evtcsm].evt);
}
evtcsm = (evtcsm + 1) % EVT_RING_ENTRIES;
}
@@ -1502,18 +1748,17 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
idx = rxretcsm;
- while (idx != rxretprd){
+ while (idx != rxretprd) {
struct ring_info *rip;
struct sk_buff *skb;
- struct rx_desc *rxdesc;
- dma_addr_t mapping;
+ struct rx_desc *rxdesc, *retdesc;
u32 skbidx;
int desc_type, mapsize;
u16 csum;
- skbidx = le16_to_cpu(ap->rx_return_ring[idx].idx);
- desc_type = le16_to_cpu(ap->rx_return_ring[idx].flags) &
- (BD_FLG_JUMBO | BD_FLG_MINI);
+ retdesc = &ap->rx_return_ring[idx];
+ skbidx = retdesc->idx;
+ desc_type = retdesc->flags & (BD_FLG_JUMBO | BD_FLG_MINI);
switch(desc_type) {
/*
@@ -1544,27 +1789,23 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
default:
printk(KERN_INFO "%s: unknown frame type (0x%02x) "
"returned by NIC\n", dev->name,
- le16_to_cpu(ap->rx_return_ring[idx].flags));
+ retdesc->flags);
goto error;
}
skb = rip->skb;
- mapping = rip->mapping;
-#if DEBUG
- if (skb == NULL) {
- printk("Mayday! illegal skb received! (idx %i)\n", skbidx);
- goto error;
- }
-#endif
rip->skb = NULL;
- pci_unmap_single(ap->pdev, mapping, mapsize);
- skb_put(skb, le16_to_cpu(rxdesc->size));
+ pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE);
+ skb_put(skb, retdesc->size);
+#if 0
+ /* unncessary */
rxdesc->size = 0;
+#endif
/*
* Fly baby, fly!
*/
- csum = le16_to_cpu(ap->rx_return_ring[idx].tcp_udp_csum);
+ csum = retdesc->tcp_udp_csum;
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
@@ -1583,7 +1824,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
netif_rx(skb); /* send it up */
ap->stats.rx_packets++;
- ap->stats.rx_bytes += skb->len;
+ ap->stats.rx_bytes += retdesc->size;
idx = (idx + 1) % RX_RETURN_RING_ENTRIES;
}
@@ -1642,13 +1883,13 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
* working on the other stuff - hey we don't need a spin lock
* anymore.
*/
- rxretprd = le32_to_cpu(*(ap->rx_ret_prd));
+ rxretprd = *ap->rx_ret_prd;
rxretcsm = ap->cur_rx;
if (rxretprd != rxretcsm)
ace_rx_int(dev, rxretprd, rxretcsm);
- txcsm = le32_to_cpu(*(ap->tx_csm));
+ txcsm = *ap->tx_csm;
idx = ap->tx_ret_csm;
if (txcsm != idx) {
@@ -1661,9 +1902,8 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
ap->stats.tx_packets++;
ap->stats.tx_bytes += skb->len;
-
- pci_unmap_single(ap->pdev, mapping, skb->len);
- dev_kfree_skb(skb);
+ pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
ap->skb->tx_skbuff[idx].skb = NULL;
@@ -1688,14 +1928,13 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
* Ie. skip the comparison of the tx producer vs. the
* consumer.
*/
- if (ap->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->state)) {
- ap->tx_full = 0;
+ if (ace_if_busy(dev) && xchg(&ap->tx_full, 0)) {
/*
* This does not need to be atomic (and expensive),
* I've seen cases where it would fail otherwise ;-(
*/
netif_wake_queue(dev);
+ ace_mark_net_bh(NET_BH);
/*
* TX ring is no longer full, aka the
@@ -1709,7 +1948,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
}
evtcsm = readl(&regs->EvtCsm);
- evtprd = le32_to_cpu(*(ap->evt_prd));
+ evtprd = *ap->evt_prd;
if (evtcsm != evtprd) {
evtcsm = ace_handle_event(dev, evtcsm, evtprd);
@@ -1720,7 +1959,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
* This has to go last in the interrupt handler and run with
* the spin lock released ... what lock?
*/
- if (test_bit(LINK_STATE_START, &dev->state)) {
+ if (ace_if_running(dev)) {
int cur_size;
int run_bh = 0;
@@ -1733,7 +1972,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
#endif
ace_load_std_rx_ring(ap,
RX_RING_SIZE - cur_size);
- }
+ } else
run_bh = 1;
}
@@ -1791,13 +2030,23 @@ static int ace_open(struct net_device *dev)
ap = dev->priv;
regs = ap->regs;
- if (!(ap->fw_running)){
+ if (!(ap->fw_running)) {
printk(KERN_WARNING "%s: Firmware not running!\n", dev->name);
return -EBUSY;
}
writel(dev->mtu + ETH_HLEN + 4, &regs->IfMtu);
+ /*
+ * Zero the stats when restarting the interface...
+ */
+ memset(&ap->stats, 0, sizeof(ap->stats));
+
+ cmd.evt = C_CLEAR_STATS;
+ cmd.code = 0;
+ cmd.idx = 0;
+ ace_issue_cmd(regs, &cmd);
+
cmd.evt = C_HOST_STATE;
cmd.code = C_C_STACK_UP;
cmd.idx = 0;
@@ -1807,7 +2056,7 @@ static int ace_open(struct net_device *dev)
!test_and_set_bit(0, &ap->jumbo_refill_busy))
ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
- if (dev->flags & IFF_PROMISC){
+ if (dev->flags & IFF_PROMISC) {
cmd.evt = C_SET_PROMISC_MODE;
cmd.code = C_C_PROMISC_ENABLE;
cmd.idx = 0;
@@ -1825,6 +2074,8 @@ static int ace_open(struct net_device *dev)
ace_issue_cmd(regs, &cmd);
#endif
+ netif_start_queue(dev);
+
MOD_INC_USE_COUNT;
/*
@@ -1854,6 +2105,7 @@ static int ace_close(struct net_device *dev)
unsigned long flags;
short i;
+ ace_if_down(dev);
netif_stop_queue(dev);
ap = (struct ace_private *)dev->priv;
@@ -1861,7 +2113,7 @@ static int ace_close(struct net_device *dev)
del_timer(&ap->timer);
- if (ap->promisc){
+ if (ap->promisc) {
cmd.evt = C_SET_PROMISC_MODE;
cmd.code = C_C_PROMISC_DISABLE;
cmd.idx = 0;
@@ -1891,13 +2143,18 @@ static int ace_close(struct net_device *dev)
writel(0, &ap->tx_ring[i].addr.addrhi);
writel(0, &ap->tx_ring[i].addr.addrlo);
writel(0, &ap->tx_ring[i].flagsize);
- pci_unmap_single(ap->pdev, mapping, skb->len);
+ pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
+ ap->skb->tx_skbuff[i].skb = NULL;
}
}
- if (ap->jumbo)
- ace_flush_jumbo_rx_ring(dev);
+ if (ap->jumbo) {
+ cmd.evt = C_RESET_JUMBO_RNG;
+ cmd.code = 0;
+ cmd.idx = 0;
+ ace_issue_cmd(regs, &cmd);
+ }
restore_flags(flags);
@@ -1913,6 +2170,16 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long addr;
u32 idx, flagsize;
+ /*
+ * ARGH, there is just no pretty way to do this
+ */
+#if (LINUX_VERSION_CODE < 0x02032b)
+ if (test_and_set_bit(0, &dev->tbusy))
+ return 1;
+#else
+ netif_stop_queue(dev);
+#endif
+
idx = ap->tx_prd;
if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) {
@@ -1926,7 +2193,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
ap->skb->tx_skbuff[idx].skb = skb;
ap->skb->tx_skbuff[idx].mapping =
- pci_map_single(ap->pdev, skb->data, skb->len);
+ pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping;
#if (BITS_PER_LONG == 64)
writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
@@ -1938,14 +2205,13 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
idx = (idx + 1) % TX_RING_ENTRIES;
ap->tx_prd = idx;
- writel(idx, &regs->TxPrd);
- wmb();
+ ace_set_txprd(regs, ap, idx);
/*
* tx_csm is set by the NIC whereas we set tx_ret_csm which
* is always trying to catch tx_csm
*/
- if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm){
+ if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm) {
ap->tx_full = 1;
/*
* Queue is full, add timer to detect whether the
@@ -1954,11 +2220,25 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
* timers.
*/
mod_timer(&ap->timer, jiffies + (3 * HZ));
+
+ /* The following check will fix a race between the interrupt
+ * handler increasing the tx_ret_csm and testing for tx_full
+ * and this tx routine's testing the tx_ret_csm and setting
+ * the tx_full; note that this fix makes assumptions on the
+ * ordering of writes (sequential consistency will fly; TSO
+ * processor order would work too) but that's what lock-less
+ * programming is all about
+ */
+ if (((idx + 2) % TX_RING_ENTRIES != ap->tx_ret_csm)
+ && xchg(&ap->tx_full, 0)) {
+ del_timer(&ap->timer);
+ netif_wake_queue(dev);
+ }
} else {
/*
* No need for it to be atomic - seems it needs to be
*/
- netif_stop_queue(dev);
+ netif_wake_queue(dev);
}
dev->trans_start = jiffies;
@@ -1977,23 +2257,27 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu)
writel(new_mtu + ETH_HLEN + 4, &regs->IfMtu);
dev->mtu = new_mtu;
- if (new_mtu > ACE_STD_MTU){
- if (!(ap->jumbo)){
+ if (new_mtu > ACE_STD_MTU) {
+ if (!(ap->jumbo)) {
printk(KERN_INFO "%s: Enabling Jumbo frame "
"support\n", dev->name);
ap->jumbo = 1;
if (!test_and_set_bit(0, &ap->jumbo_refill_busy))
ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
+ ap->jumbo = 1;
}
- ap->jumbo = 1;
- }else{
+ } else {
+ netif_stop_queue(dev);
+ while (test_and_set_bit(0, &ap->jumbo_refill_busy));
+ synchronize_irq();
if (ap->jumbo){
- ace_flush_jumbo_rx_ring(dev);
+ struct cmd cmd;
- printk(KERN_INFO "%s: Disabling Jumbo frame support\n",
- dev->name);
+ cmd.evt = C_RESET_JUMBO_RNG;
+ cmd.code = 0;
+ cmd.idx = 0;
+ ace_issue_cmd(regs, &cmd);
}
- ap->jumbo = 0;
}
return 0;
@@ -2008,6 +2292,21 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct ethtool_cmd ecmd;
u32 link, speed;
+#ifdef SPIN_DEBUG
+ if (cmd == (SIOCDEVPRIVATE+0x0e)) {
+ printk(KERN_NOTICE "%s: dumping debug info\n", dev->name);
+ printk(KERN_NOTICE "%s: tbusy %li, tx_ret_csm %i, "
+ "tx_prd %i\n", dev->name, dev->tbusy,
+ ap->tx_ret_csm, ap->tx_prd);
+ printk(KERN_NOTICE "%s: cur_rx %i, std_refill %li, "
+ "mini_rx %i, mini_refill %li\n", dev->name,
+ atomic_read(&ap->cur_rx_bufs), ap->std_refill_busy,
+ atomic_read(&ap->cur_mini_bufs), ap->mini_refill_busy);
+ printk(KERN_NOTICE "%s: CpuCtrl %08x\n",
+ dev->name, readl(&regs->CpuCtrl));
+ return 0;
+ }
+#endif
if (cmd != SIOCETHTOOL)
return -EOPNOTSUPP;
if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
@@ -2130,7 +2429,7 @@ static int ace_set_mac_addr(struct net_device *dev, void *p)
u16 *da;
struct cmd cmd;
- if(test_bit(LINK_STATE_START, &dev->state))
+ if(ace_if_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
@@ -2162,9 +2461,9 @@ static void ace_set_multicast_list(struct net_device *dev)
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
ap->mcast_all = 1;
- } else if (ap->mcast_all){
+ } else if (ap->mcast_all) {
cmd.evt = C_SET_MULTICAST_MODE;
- cmd.code = C_C_MCAST_ENABLE;
+ cmd.code = C_C_MCAST_DISABLE;
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
ap->mcast_all = 0;
@@ -2176,7 +2475,7 @@ static void ace_set_multicast_list(struct net_device *dev)
cmd.idx = 0;
ace_issue_cmd(regs, &cmd);
ap->promisc = 1;
- }else if (!(dev->flags & IFF_PROMISC) && (ap->promisc)){
+ }else if (!(dev->flags & IFF_PROMISC) && (ap->promisc)) {
cmd.evt = C_SET_PROMISC_MODE;
cmd.code = C_C_PROMISC_DISABLE;
cmd.idx = 0;
@@ -2207,28 +2506,38 @@ static void ace_set_multicast_list(struct net_device *dev)
static struct net_device_stats *ace_get_stats(struct net_device *dev)
{
struct ace_private *ap = dev->priv;
+ struct ace_mac_stats *mac_stats =
+ (struct ace_mac_stats *)ap->regs->Stats;
+
+ ap->stats.rx_missed_errors = readl(&mac_stats->drop_space);
+ ap->stats.multicast = readl(&mac_stats->kept_mc);
+ ap->stats.collisions = readl(&mac_stats->coll);
return(&ap->stats);
}
-void __init ace_copy(struct ace_regs *regs, void *src, unsigned long dest, int size)
+void __init ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)
{
unsigned long tdest;
u32 *wsrc;
- unsigned long tsize, i;
+ short tsize, i;
if (size <= 0)
return;
- while (size > 0){
+ while (size > 0) {
tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
min(size, ACE_WINDOW_SIZE));
tdest = (unsigned long)&regs->Window +
(dest & (ACE_WINDOW_SIZE - 1));
writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
+ /*
+ * This requires byte swapping on big endian, however
+ * writel does that for us
+ */
wsrc = src;
- for (i = 0; i < (tsize / 4); i++){
+ for (i = 0; i < (tsize / 4); i++) {
writel(wsrc[i], tdest + i*4);
}
dest += tsize;
@@ -2240,22 +2549,22 @@ void __init ace_copy(struct ace_regs *regs, void *src, unsigned long dest, int s
}
-void __init ace_clear(struct ace_regs *regs, unsigned long dest, int size)
+void __init ace_clear(struct ace_regs *regs, u32 dest, int size)
{
unsigned long tdest;
- unsigned long tsize = 0, i;
+ short tsize = 0, i;
if (size <= 0)
return;
- while (size > 0){
+ while (size > 0) {
tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
min(size, ACE_WINDOW_SIZE));
tdest = (unsigned long)&regs->Window +
(dest & (ACE_WINDOW_SIZE - 1));
writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
- for (i = 0; i < (tsize / 4); i++){
+ for (i = 0; i < (tsize / 4); i++) {
writel(0, tdest + i*4);
}
@@ -2281,7 +2590,7 @@ int __init ace_load_firmware(struct net_device *dev)
ap = (struct ace_private *)dev->priv;
regs = ap->regs;
- if (!(readl(&regs->CpuCtrl) & CPU_HALTED)){
+ if (!(readl(&regs->CpuCtrl) & CPU_HALTED)) {
printk(KERN_ERR "%s: trying to download firmware while the "
"CPU is running!\n", dev->name);
return -EFAULT;
@@ -2292,14 +2601,14 @@ int __init ace_load_firmware(struct net_device *dev)
* funny things on NICs with only 512KB SRAM
*/
ace_clear(regs, 0x2000, 0x80000-0x2000);
- if (ACE_IS_TIGON_I(ap)){
+ if (ACE_IS_TIGON_I(ap)) {
ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen);
ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen);
ace_copy(regs, tigonFwRodata, tigonFwRodataAddr,
tigonFwRodataLen);
ace_clear(regs, tigonFwBssAddr, tigonFwBssLen);
ace_clear(regs, tigonFwSbssAddr, tigonFwSbssLen);
- }else if (ap->version == 2){
+ }else if (ap->version == 2) {
ace_clear(regs, tigon2FwBssAddr, tigon2FwBssLen);
ace_clear(regs, tigon2FwSbssAddr, tigon2FwSbssLen);
ace_copy(regs, tigon2FwText, tigon2FwTextAddr,tigon2FwTextLen);
@@ -2323,24 +2632,28 @@ int __init ace_load_firmware(struct net_device *dev)
* specs.
*
* Oh yes, this is only the beginning!
+ *
+ * Thanks to Stevarino Webinski for helping tracking down the bugs in the
+ * code i2c readout code by beta testing all my hacks.
*/
static void __init eeprom_start(struct ace_regs *regs)
{
- u32 local = readl(&regs->LocalCtrl);
+ u32 local;
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
+ local = readl(&regs->LocalCtrl);
local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
@@ -2352,7 +2665,7 @@ static void __init eeprom_prep(struct ace_regs *regs, u8 magic)
short i;
u32 local;
- udelay(2);
+ udelay(ACE_SHORT_DELAY);
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_DATA_OUT;
local |= EEPROM_WRITE_ENABLE;
@@ -2360,7 +2673,7 @@ static void __init eeprom_prep(struct ace_regs *regs, u8 magic)
mb();
for (i = 0; i < 8; i++, magic <<= 1) {
- udelay(2);
+ udelay(ACE_SHORT_DELAY);
if (magic & 0x80)
local |= EEPROM_DATA_OUT;
else
@@ -2368,11 +2681,11 @@ static void __init eeprom_prep(struct ace_regs *regs, u8 magic)
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
writel(local, &regs->LocalCtrl);
mb();
@@ -2389,14 +2702,14 @@ static int __init eeprom_check_ack(struct ace_regs *regs)
local &= ~EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
- udelay(2);
+ udelay(ACE_LONG_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
/* sample data in middle of high clk */
state = (readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0;
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
mb();
writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
mb();
@@ -2409,23 +2722,24 @@ static void __init eeprom_stop(struct ace_regs *regs)
{
u32 local;
+ udelay(ACE_SHORT_DELAY);
local = readl(&regs->LocalCtrl);
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
local |= EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
mb();
- udelay(2);
+ udelay(ACE_LONG_DELAY);
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
mb();
@@ -2435,73 +2749,115 @@ static void __init eeprom_stop(struct ace_regs *regs)
/*
* Read a whole byte from the EEPROM.
*/
-static u8 __init read_eeprom_byte(struct ace_regs *regs, unsigned long offset)
+static int __init read_eeprom_byte(struct net_device *dev,
+ unsigned long offset)
{
+ struct ace_regs *regs;
+ unsigned long flags;
u32 local;
+ int result = 0;
short i;
- u8 result = 0;
- if (!regs){
- printk(KERN_ERR "No regs!\n");
- return 0;
+ if (!dev) {
+ printk(KERN_ERR "No device!\n");
+ result = -ENODEV;
+ goto eeprom_read_error;
}
+ regs = ((struct ace_private *)dev->priv)->regs;
+
+ /*
+ * Don't take interrupts on this CPU will bit banging
+ * the %#%#@$ I2C device
+ */
+ __save_flags(flags);
+ __cli();
+
eeprom_start(regs);
eeprom_prep(regs, EEPROM_WRITE_SELECT);
- if (eeprom_check_ack(regs)){
- printk("Unable to sync eeprom\n");
- return 0;
+ if (eeprom_check_ack(regs)) {
+ __restore_flags(flags);
+ printk(KERN_ERR "%s: Unable to sync eeprom\n", dev->name);
+ result = -EIO;
+ goto eeprom_read_error;
}
eeprom_prep(regs, (offset >> 8) & 0xff);
- if (eeprom_check_ack(regs))
- return 0;
+ if (eeprom_check_ack(regs)) {
+ __restore_flags(flags);
+ printk(KERN_ERR "%s: Unable to set address byte 0\n",
+ dev->name);
+ result = -EIO;
+ goto eeprom_read_error;
+ }
eeprom_prep(regs, offset & 0xff);
- if (eeprom_check_ack(regs))
- return 0;
+ if (eeprom_check_ack(regs)) {
+ __restore_flags(flags);
+ printk(KERN_ERR "%s: Unable to set address byte 1\n",
+ dev->name);
+ result = -EIO;
+ goto eeprom_read_error;
+ }
eeprom_start(regs);
eeprom_prep(regs, EEPROM_READ_SELECT);
- if (eeprom_check_ack(regs))
- return 0;
+ if (eeprom_check_ack(regs)) {
+ __restore_flags(flags);
+ printk(KERN_ERR "%s: Unable to set READ_SELECT\n",
+ dev->name);
+ result = -EIO;
+ goto eeprom_read_error;
+ }
for (i = 0; i < 8; i++) {
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
- udelay(2);
+ udelay(ACE_LONG_DELAY);
mb();
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
- udelay(1);
mb();
+ udelay(ACE_SHORT_DELAY);
/* sample data mid high clk */
result = (result << 1) |
((readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0);
- udelay(1);
+ udelay(ACE_SHORT_DELAY);
mb();
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
+ udelay(ACE_SHORT_DELAY);
mb();
- if (i == 7){
+ if (i == 7) {
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
mb();
+ udelay(ACE_SHORT_DELAY);
}
}
local |= EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
- udelay(1);
+ mb();
+ udelay(ACE_SHORT_DELAY);
writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);
- udelay(2);
+ udelay(ACE_LONG_DELAY);
writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
+ mb();
+ udelay(ACE_SHORT_DELAY);
eeprom_stop(regs);
+ __restore_flags(flags);
+ out:
return result;
+
+ eeprom_read_error:
+ printk(KERN_ERR "%s: Unable to read eeprom byte 0x%02lx\n",
+ dev->name, offset);
+ goto out;
}
diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
index 50f290c89..7719338ab 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/acenic.h
@@ -18,25 +18,6 @@
* modified to deal properly with readl/writel usage.
*/
-typedef struct {
- u32 addrhi;
- u32 addrlo;
-} aceaddr;
-
-
-static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
-{
- unsigned long baddr = (unsigned long) addr;
-#if (BITS_PER_LONG == 64)
- aa->addrlo = cpu_to_le32(baddr & 0xffffffff);
- aa->addrhi = cpu_to_le32(baddr >> 32);
-#else
- /* Don't bother setting zero every time */
- aa->addrlo = cpu_to_le32(baddr);
-#endif
- mb();
-}
-
struct ace_regs {
u32 pad0[16]; /* PCI control registers */
@@ -167,6 +148,13 @@ struct ace_regs {
u32 Window[0x200];
};
+
+typedef struct {
+ u32 addrhi;
+ u32 addrlo;
+} aceaddr;
+
+
#define ACE_WINDOW_SIZE 0x800
#define ACE_JUMBO_MTU 9000
@@ -180,6 +168,7 @@ struct ace_regs {
#define IN_INT 0x01
#define CLR_INT 0x02
+#define HW_RESET 0x08
#define BYTE_SWAP 0x10
#define WORD_SWAP 0x20
#define MASK_INTS 0x40
@@ -202,6 +191,13 @@ struct ace_regs {
/*
+ * udelay() values for when clocking the eeprom
+ */
+#define ACE_SHORT_DELAY 1
+#define ACE_LONG_DELAY 2
+
+
+/*
* Misc Config bits
*/
@@ -239,6 +235,7 @@ struct ace_regs {
#define DMA_WRITE_MAX_1K 0xe0
#define MEM_READ_MULTIPLE 0x00020000
#define PCI_66MHZ 0x00080000
+#define PCI_32BIT 0x00100000
#define DMA_WRITE_ALL_ALIGN 0x00800000
#define READ_CMD_MEM 0x06000000
#define WRITE_CMD_MEM 0x70000000
@@ -248,9 +245,10 @@ struct ace_regs {
* Mode status
*/
-#define ACE_BYTE_SWAP_DATA 0x10
+#define ACE_BYTE_SWAP_BD 0x02
+#define ACE_WORD_SWAP_BD 0x04 /* not actually used */
#define ACE_WARN 0x08
-#define ACE_WORD_SWAP 0x04
+#define ACE_BYTE_SWAP_DMA 0x10
#define ACE_NO_JUMBO_FRAG 0x200
#define ACE_FATAL 0x40000000
@@ -300,20 +298,15 @@ struct ace_regs {
#define EVT_RING_SIZE (EVT_RING_ENTRIES * sizeof(struct event))
struct event {
- union {
- u32 word;
- struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- u32 idx:12;
- u32 code:12;
- u32 evt:8;
+#ifdef __LITTLE_ENDIAN_BITFIELD
+ u32 idx:12;
+ u32 code:12;
+ u32 evt:8;
#else
- u32 evt:8;
- u32 code:12;
- u32 idx:12;
+ u32 evt:8;
+ u32 code:12;
+ u32 idx:12;
#endif
- } data;
- } u;
u32 pad;
};
@@ -351,7 +344,7 @@ struct event {
#define CMD_RING_ENTRIES 64
struct cmd {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
+#ifdef __LITTLE_ENDIAN_BITFIELD
u32 idx:12;
u32 code:12;
u32 evt:8;
@@ -435,10 +428,17 @@ struct tx_desc{
* This is in PCI shared mem and must be accessed with readl/writel
* real layout is:
*/
+#if __LITTLE_ENDIAN
u16 flags;
u16 size;
u16 vlan;
u16 reserved;
+#else
+ u16 size;
+ u16 flags;
+ u16 reserved;
+ u16 vlan;
+#endif
#endif
u32 vlanres;
};
@@ -459,14 +459,34 @@ struct tx_desc{
struct rx_desc{
aceaddr addr;
+#ifdef __LITTLE_ENDIAN
u16 size;
u16 idx;
+#else
+ u16 idx;
+ u16 size;
+#endif
+#ifdef __LITTLE_ENDIAN
u16 flags;
u16 type;
+#else
+ u16 type;
+ u16 flags;
+#endif
+#ifdef __LITTLE_ENDIAN
u16 tcp_udp_csum;
u16 ip_csum;
+#else
+ u16 ip_csum;
+ u16 tcp_udp_csum;
+#endif
+#ifdef __LITTLE_ENDIAN
u16 vlan;
u16 err_flags;
+#else
+ u16 err_flags;
+ u16 vlan;
+#endif
u32 reserved;
u32 opague;
};
@@ -477,8 +497,13 @@ struct rx_desc{
*/
struct ring_ctrl {
aceaddr rngptr;
+#ifdef __LITTLE_ENDIAN
u16 flags;
u16 max_len;
+#else
+ u16 max_len;
+ u16 flags;
+#endif
u32 pad;
};
@@ -535,16 +560,17 @@ struct ace_info {
};
-/*
- * struct ace_skb holding the rings of skb's. This is an awful lot of
- * pointers, but I don't see any other smart mode to do this in an
- * efficient manner ;-(
- */
struct ring_info {
struct sk_buff *skb;
dma_addr_t mapping;
};
+
+/*
+ * struct ace_skb holding the rings of skb's. This is an awful lot of
+ * pointers, but I don't see any other smart mode to do this in an
+ * efficient manner ;-(
+ */
struct ace_skb
{
struct ring_info tx_skbuff[TX_RING_ENTRIES];
@@ -575,9 +601,10 @@ struct ace_private
* The send ring is located in the shared memory window
*/
struct ace_info *info;
- dma_addr_t info_dma;
struct tx_desc *tx_ring;
- u32 tx_prd, tx_full, tx_ret_csm;
+ dma_addr_t info_dma;
+ u32 tx_prd;
+ volatile u32 tx_full, tx_ret_csm;
struct timer_list timer;
unsigned long std_refill_busy
@@ -590,9 +617,8 @@ struct ace_private
u32 cur_rx;
struct tq_struct immediate;
int bh_pending, jumbo;
-
- /* These elements are allocated using consistent PCI
- * dma memory.
+ /*
+ * These elements are allocated using consistent PCI dma memory.
*/
struct rx_desc *rx_std_ring;
struct rx_desc *rx_jumbo_ring;
@@ -611,10 +637,64 @@ struct ace_private
struct net_device *next;
u16 pci_command;
u8 pci_latency;
- char name[24];
+ char name[48];
+#ifdef INDEX_DEBUG
+ spinlock_t debug_lock
+ __attribute__ ((aligned (L1_CACHE_BYTES)));;
+ u32 last_tx, last_std_rx, last_mini_rx;
+#endif
struct net_device_stats stats;
};
+
+static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
+{
+ unsigned long baddr = (unsigned long) addr;
+#if (BITS_PER_LONG == 64)
+ aa->addrlo = baddr & 0xffffffff;
+ aa->addrhi = baddr >> 32;
+#else
+ /* Don't bother setting zero every time */
+ aa->addrlo = baddr;
+#endif
+ mb();
+}
+
+
+#if 0
+static inline void *get_aceaddr(aceaddr *aa)
+{
+ unsigned long addr;
+ mb();
+#if (BITS_PER_LONG == 64)
+ addr = (u64)aa->addrhi << 32 | aa->addrlo;
+#else
+ addr = aa->addrlo;
+#endif
+ return (void *)addr;
+}
+#endif
+
+
+static inline void ace_set_txprd(struct ace_regs *regs,
+ struct ace_private *ap, u32 value)
+{
+#ifdef INDEX_DEBUG
+ unsigned long flags;
+ spin_lock_irqsave(&ap->debug_lock, flags);
+ writel(value, &regs->TxPrd);
+ if (value == ap->last_tx)
+ printk(KERN_ERR "AceNIC RACE ALERT! writing identical value "
+ "to tx producer (%i)\n", value);
+ ap->last_tx = value;
+ spin_unlock_irqrestore(&ap->debug_lock, flags);
+#else
+ writel(value, &regs->TxPrd);
+#endif
+ wmb();
+}
+
+
/*
* Prototypes
*/
@@ -622,7 +702,6 @@ static int ace_init(struct net_device *dev, int board_idx);
static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
-static int ace_flush_jumbo_rx_ring(struct net_device *dev);
static void ace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int ace_load_firmware(struct net_device *dev);
static int ace_open(struct net_device *dev);
@@ -638,7 +717,9 @@ extern int ace_recycle(struct sk_buff *skb);
#endif
static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static int ace_set_mac_addr(struct net_device *dev, void *p);
+static int ace_allocate_descriptors(struct net_device *dev);
+static void ace_free_descriptors(struct net_device *dev);
static struct net_device_stats *ace_get_stats(struct net_device *dev);
-static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset);
+static int read_eeprom_byte(struct net_device *dev, unsigned long offset);
#endif /* _ACENIC_H_ */
diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h
index d28e266a0..729eac664 100644
--- a/drivers/net/acenic_firmware.h
+++ b/drivers/net/acenic_firmware.h
@@ -4,38 +4,37 @@
* the compiler complaining about undefined symbols.
*/
#define tigonFwReleaseMajor 0xc
-#define tigonFwReleaseMinor 0x3
-#define tigonFwReleaseFix 0xd
+#define tigonFwReleaseMinor 0x4
+#define tigonFwReleaseFix 0x5
#define tigonFwStartAddr 0x00004000
#define tigonFwTextAddr 0x00004000
-#define tigonFwTextLen 0x10920
-#define tigonFwRodataAddr 0x00014920
-#define tigonFwRodataLen 0xaa0
-#define tigonFwDataAddr 0x000153e0
-#define tigonFwDataLen 0x150
-#define tigonFwSbssAddr 0x00015530
-#define tigonFwSbssLen 0x2c
-#define tigonFwBssAddr 0x00015560
+#define tigonFwTextLen 0x11190
+#define tigonFwRodataAddr 0x00015190
+#define tigonFwRodataLen 0xac0
+#define tigonFwDataAddr 0x00015c80
+#define tigonFwDataLen 0x170
+#define tigonFwSbssAddr 0x00015df0
+#define tigonFwSbssLen 0x34
+#define tigonFwBssAddr 0x00015e30
#define tigonFwBssLen 0x2080
u32 tigonFwText[];
u32 tigonFwData[];
u32 tigonFwRodata[];
-
#ifndef CONFIG_ACENIC_OMIT_TIGON_I
/* Generated by genfw.c */
u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x10000003,
0x0, 0xd, 0xd, 0x3c1d0001,
-0x8fbd5414, 0x3a0f021, 0x3c100000, 0x26104000,
+0x8fbd5cb4, 0x3a0f021, 0x3c100000, 0x26104000,
0xc00100c, 0x0, 0xd, 0x27bdffd8,
0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021,
0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8,
0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8,
-0x0, 0x3c040001, 0x24844984, 0x24050001,
-0x2e03021, 0x3821, 0x3c100001, 0x261075e0,
+0x0, 0x3c040001, 0x248451f4, 0x24050001,
+0x2e03021, 0x3821, 0x3c100001, 0x26107eb0,
0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f,
0x3442ffff, 0x2021024, 0x362102b, 0x10400009,
-0x24050003, 0x3c040001, 0x24844990, 0x2003021,
+0x24050003, 0x3c040001, 0x24845200, 0x2003021,
0x3603821, 0x3c020010, 0xafa20010, 0xc002403,
0xafa00014, 0x2021, 0x3405c000, 0x3c010001,
0x370821, 0xa02083b0, 0x3c010001, 0x370821,
@@ -73,7 +72,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc,
0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d,
0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001,
-0x2484499c, 0x3c050001, 0xafa00010, 0xafa00014,
+0x2484520c, 0x3c050001, 0xafa00010, 0xafa00014,
0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021,
0x26e40030, 0xc002488, 0x24050400, 0x27440080,
0xc002488, 0x24050080, 0x26e4777c, 0xc002488,
@@ -83,7 +82,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x3442ca00, 0x2021, 0x24030002, 0xaee30074,
0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104,
0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001,
-0x641821, 0x906353e0, 0x2e41021, 0x24840001,
+0x641821, 0x90635c80, 0x2e41021, 0x24840001,
0xa043009c, 0x2c82000f, 0x1440fff8, 0x0,
0x8f820040, 0x2e41821, 0x24840001, 0x21702,
0x24420030, 0xa062009c, 0x2e41021, 0xa040009c,
@@ -129,7 +128,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
0x210c0, 0x24425038, 0x2e22021, 0x24020007,
0xac820000, 0x24020001, 0xac820004, 0x54c0000c,
-0xaee90608, 0x3c040001, 0x248449a8, 0xafa00010,
+0xaee90608, 0x3c040001, 0x24845218, 0xafa00010,
0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
0xc002403, 0x34a5f000, 0x8001223, 0x0,
0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
@@ -155,21 +154,21 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
0x24425038, 0x2e22021, 0x24020012, 0xac820000,
0x24020001, 0xac820004, 0x14c0001b, 0x0,
-0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014,
+0x3c040001, 0x24845220, 0xafa00010, 0xafa00014,
0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0,
-0x8001223, 0x8ee201b0, 0x3c040001, 0x248449bc,
+0x8001223, 0x8ee201b0, 0x3c040001, 0x2484522c,
0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001,
0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001,
-0x248449c8, 0x3405f001, 0x24420001, 0xaee20160,
+0x24845238, 0x3405f001, 0x24420001, 0xaee20160,
0x8ee20160, 0x3021, 0x3821, 0xafa00010,
0xc002403, 0xafa00014, 0x8001238, 0x0,
0x3c020001, 0x2442f5a8, 0x21100, 0x21182,
0x431025, 0x3c010001, 0xac221278, 0x96e2045a,
0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8,
0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8,
-0x3c040001, 0x248449d4, 0x24020001, 0xa2e204ec,
+0x3c040001, 0x24845244, 0x24020001, 0xa2e204ec,
0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001,
0x2442a390, 0x451024, 0x21082, 0xaee304c8,
0x3c030800, 0x431025, 0x3c010001, 0xac221220,
@@ -212,7 +211,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
0x2e22021, 0x24020007, 0xac820000, 0x24020001,
0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
-0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x24845218, 0xafa00010, 0xafa00014, 0x8ee60608,
0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
0x800136d, 0x0, 0x8f830120, 0x27623800,
0x24660020, 0xc2102b, 0x50400001, 0x27663000,
@@ -237,17 +236,17 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x14c0001b, 0x0, 0x3c040001, 0x248449b0,
+0x14c0001b, 0x0, 0x3c040001, 0x24845220,
0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0,
-0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608,
+0x3c040001, 0x2484522c, 0xafa00014, 0x8ee60608,
0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
-0x8ee20160, 0x3c040001, 0x248449c8, 0x3405f002,
+0x8ee20160, 0x3c040001, 0x24845238, 0x3405f002,
0x24420001, 0xaee20160, 0x8ee20160, 0x3021,
0x3821, 0xafa00010, 0xc002403, 0xafa00014,
-0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449e0,
+0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845250,
0x24050012, 0xafa00010, 0xc002403, 0xafa00014,
0xc004500, 0x0, 0xc002318, 0x0,
0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228,
@@ -290,7 +289,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
0x2e22021, 0x24020007, 0xac820000, 0x24020001,
0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
-0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x24845218, 0xafa00010, 0xafa00014, 0x8ee60608,
0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
0x80014a5, 0x0, 0x8f830120, 0x27623800,
0x24660020, 0xc2102b, 0x50400001, 0x27663000,
@@ -315,11 +314,11 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x14c0001b, 0x0, 0x3c040001, 0x248449b0,
+0x14c0001b, 0x0, 0x3c040001, 0x24845220,
0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0,
-0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608,
+0x3c040001, 0x2484522c, 0xafa00014, 0x8ee60608,
0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc,
@@ -341,7 +340,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821,
0xac2083bc, 0x3c010001, 0x370821, 0x3e00008,
0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020,
-0x8f820054, 0x3c030001, 0x8c635498, 0x24420067,
+0x8f820054, 0x3c030001, 0x8c635d38, 0x24420067,
0x1060000d, 0xaf820058, 0x3c020001, 0x571021,
0x904283b8, 0x10400005, 0x3c030200, 0x3c010001,
0x370821, 0x8001503, 0xa02083b8, 0x8ee20000,
@@ -359,7 +358,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x0, 0x3c030001, 0x771821, 0x8c6383d4,
0x8f8200b4, 0x1462007c, 0x0, 0x3c070001,
0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001,
-0x24844a50, 0xafa00014, 0xafa20010, 0x8f8600b0,
+0x248452c0, 0xafa00014, 0xafa20010, 0x8f8600b0,
0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c,
0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0,
0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120,
@@ -387,10 +386,10 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xac820000, 0x24020001, 0xac820004, 0x8f82011c,
0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4,
0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001,
-0xaee201e4, 0x8ee201e4, 0x3c040001, 0x24844a5c,
+0xaee201e4, 0x8ee201e4, 0x3c040001, 0x248452cc,
0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001,
0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001,
-0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a64,
+0xf73821, 0x8ce783d0, 0x3c040001, 0x248452d4,
0x3c010001, 0x370821, 0xac2283d4, 0xafa00010,
0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403,
0x34a50900, 0x80015cc, 0x0, 0x8f820104,
@@ -423,7 +422,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
0x24425038, 0x2e22021, 0x24020012, 0xac820000,
0x24020001, 0xac820004, 0x5600000b, 0x24100001,
-0x8ee204e4, 0x3c040001, 0x24844a6c, 0xafa00014,
+0x8ee204e4, 0x3c040001, 0x248452dc, 0xafa00014,
0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
0xc002403, 0x34a5f006, 0x16000003, 0x24020001,
0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001,
@@ -453,7 +452,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0x24020012, 0xac820000, 0x24020001, 0xac820004,
0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001,
-0x24844a78, 0xafa00014, 0xafa20010, 0x8ee6724c,
+0x248452e8, 0xafa00014, 0xafa20010, 0x8ee6724c,
0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008,
0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001,
0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019,
@@ -564,11 +563,11 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
0x0, 0x316300ff, 0x24020001, 0x14620003,
0x3c050009, 0x800197c, 0x24100001, 0x3c040001,
-0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120,
+0x248452f4, 0xafa00010, 0xafa00014, 0x8f860120,
0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001,
-0x24844a90, 0xafa00010, 0xafa00014, 0x8f860120,
+0x24845300, 0xafa00010, 0xafa00014, 0x8f860120,
0x8f870124, 0x34a5f010, 0xc002403, 0x8021,
-0x800197c, 0x0, 0x3c040001, 0x24844a9c,
+0x800197c, 0x0, 0x3c040001, 0x2484530c,
0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228,
0x24420001, 0x304900ff, 0x512300e2, 0xafa00010,
@@ -599,7 +598,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
0x24425038, 0x2e22021, 0x24020007, 0xac820000,
0x24020001, 0xac820004, 0x5600000c, 0xaee90608,
-0x3c040001, 0x24844aa8, 0xafa00010, 0xafa00014,
+0x3c040001, 0x24845318, 0xafa00010, 0xafa00014,
0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
0x34a5f000, 0x800197c, 0x0, 0x8f830120,
0x27623800, 0x24660020, 0xc2102b, 0x50400001,
@@ -625,10 +624,10 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
0x2e22021, 0x24020012, 0xac820000, 0x24020001,
0xac820004, 0x5600001d, 0x24100001, 0x3c040001,
-0x24844ab0, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x24845320, 0xafa00010, 0xafa00014, 0x8ee60608,
0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001,
0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c,
-0x8ee201b0, 0x3c040001, 0x24844abc, 0xafa00014,
+0x8ee201b0, 0x3c040001, 0x2484532c, 0xafa00014,
0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005,
0xc002403, 0x0, 0x8ee201ac, 0x8021,
0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c,
@@ -636,7 +635,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158,
0x8ee30158, 0x800198c, 0xaee27278, 0x24020001,
0x3c010001, 0x370821, 0xa02283b0, 0x3c020001,
-0x8c425498, 0x10400187, 0x0, 0x8ee27b84,
+0x8c425d38, 0x10400187, 0x0, 0x8ee27b84,
0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84,
0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84,
0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002,
@@ -700,12 +699,12 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
0x24020001, 0x10620022, 0x0, 0x3c040001,
-0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120,
+0x248452f4, 0xafa00010, 0xafa00014, 0x8f860120,
0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011,
-0x8001aad, 0x0, 0x3c040001, 0x24844a90,
+0x8001aad, 0x0, 0x3c040001, 0x24845300,
0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
0xc002403, 0x34a5f010, 0x8001aad, 0x0,
-0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608,
+0x3c040001, 0x2484530c, 0xafa00014, 0x8ee60608,
0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f,
0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c,
@@ -742,7 +741,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaf820044, 0x8f820044, 0x34420040, 0xaf820044,
0x8ee27b88, 0x24430001, 0x28421389, 0x14400005,
0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044,
-0xaee07b88, 0xc0045c2, 0x0, 0x8fbf0024,
+0xaee07b88, 0xc0045f4, 0x0, 0x8fbf0024,
0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8,
0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038,
0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028,
@@ -752,18 +751,18 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001,
0x10400004, 0x24020001, 0xaf820064, 0x80022f4,
0x0, 0x32c20002, 0x1440000c, 0x3c050003,
-0x3c040001, 0x24844b34, 0x34a50001, 0x2c03021,
+0x3c040001, 0x248453a4, 0x34a50001, 0x2c03021,
0x3821, 0xafa00010, 0xc002403, 0xafa00014,
0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c,
0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c,
0x21080, 0x5a1021, 0x8c420300, 0xafa20020,
0x8f42022c, 0x24070001, 0x24420001, 0x3042003f,
-0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b40,
+0x8001b80, 0xaf42022c, 0x3c040001, 0x248453b0,
0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003,
0xc002403, 0x34a5f01f, 0x3821, 0x14e00003,
0x0, 0x80022ed, 0xaf960064, 0x93a20020,
0x2443ffff, 0x2c620011, 0x10400658, 0x31080,
-0x3c010001, 0x220821, 0x8c224bf8, 0x400008,
+0x3c010001, 0x220821, 0x8c225468, 0x400008,
0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c,
0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118,
0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118,
@@ -779,7 +778,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f840054, 0x41442, 0x41c82, 0x431021,
0x41cc2, 0x431023, 0x41d02, 0x431021,
0x41d42, 0x431023, 0x8001bd0, 0xaee20078,
-0x3c040001, 0x24844b4c, 0xafa00014, 0x8fa60020,
+0x3c040001, 0x248453bc, 0xafa00014, 0x8fa60020,
0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110,
0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110,
0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
@@ -795,7 +794,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010,
0x618c0, 0x610c0, 0x571821, 0x8c63737c,
0x571021, 0xafa30010, 0x8c427380, 0x3c040001,
-0x24844b58, 0xafa20014, 0x8f470214, 0x3c050003,
+0x248453c8, 0xafa20014, 0x8f470214, 0x3c050003,
0xc002403, 0x34a50013, 0x8001c90, 0x3c020800,
0x97440212, 0x771021, 0xa444737e, 0x8f440214,
0x771021, 0x2e31821, 0xac447380, 0x34028000,
@@ -813,7 +812,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24840001, 0x2c820080, 0x1440fff8, 0x410c0,
0x4c10023, 0x618c0, 0x910c0, 0x571821,
0x8c63727c, 0x571021, 0xafa30010, 0x8c427280,
-0x3c040001, 0x24844b64, 0xafa20014, 0x8f470214,
+0x3c040001, 0x248453d4, 0xafa20014, 0x8f470214,
0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90,
0x3c020800, 0x8f430210, 0xb71021, 0xac43777c,
0x8f430214, 0xb71021, 0xac437780, 0x3c020001,
@@ -888,13 +887,13 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
-0x10620022, 0x0, 0x3c040001, 0x24844b70,
+0x10620022, 0x0, 0x3c040001, 0x248453e0,
0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0,
-0x0, 0x3c040001, 0x24844b7c, 0xafa00014,
+0x0, 0x3c040001, 0x248453ec, 0xafa00014,
0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
0x34a5f010, 0x8001da0, 0x0, 0x3c040001,
-0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x248453f8, 0xafa00014, 0x8ee60608, 0x8f470228,
0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124,
0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124,
@@ -909,7 +908,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1221004, 0x21027, 0x621824, 0xaf830228,
0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e,
0xa462727c, 0x8f420214, 0xafa20010, 0x910c0,
-0x571021, 0x8c42727c, 0x3c040001, 0x24844b94,
+0x571021, 0x8c42727c, 0x3c040001, 0x24845404,
0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c,
0xc002403, 0x1203021, 0x8001e83, 0x3c020800,
0xb71021, 0x9443727e, 0x97420212, 0x14620019,
@@ -937,7 +936,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x910c0, 0x2e41821, 0x3402c000, 0x15000015,
0xa462737c, 0x910c0, 0x2e21821, 0x34028000,
0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c,
-0x3c040001, 0x24844ba0, 0x3c050003, 0xafa20010,
+0x3c040001, 0x24845410, 0x3c050003, 0xafa20010,
0x710c0, 0x571021, 0x8c42737c, 0x34a5001e,
0x1203021, 0xc002403, 0xafa20014, 0x8001e83,
0x3c020800, 0x2021, 0x428c0, 0xb71021,
@@ -1013,12 +1012,12 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001,
0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
0x0, 0x316300ff, 0x24020001, 0x10620022,
-0x0, 0x3c040001, 0x24844b70, 0xafa00010,
+0x0, 0x3c040001, 0x248453e0, 0xafa00010,
0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
0xc002403, 0x34a5f011, 0x8001f93, 0x0,
-0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120,
+0x3c040001, 0x248453ec, 0xafa00014, 0x8f860120,
0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010,
-0x8001f93, 0x0, 0x3c040001, 0x24844b88,
+0x8001f93, 0x0, 0x3c040001, 0x248453f8,
0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001,
0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001,
@@ -1030,7 +1029,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228,
0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8,
0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228,
-0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844ba8,
+0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24845418,
0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c,
0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200,
@@ -1041,7 +1040,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x370821, 0xa02283b2, 0x8001fea, 0xaee40108,
0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024,
0xaf820220, 0x3c010001, 0x370821, 0xa02083b2,
-0x8001fea, 0xaee40108, 0x3c040001, 0x24844bb4,
+0x8001fea, 0xaee40108, 0x3c040001, 0x24845424,
0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c,
0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200,
@@ -1053,13 +1052,13 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x571021, 0x904283b2, 0x3c010001, 0x370821,
0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff,
0x3463fff7, 0x431024, 0x8002018, 0xaf820220,
-0x3c040001, 0x24844bc0, 0xafa00014, 0x8fa60020,
+0x3c040001, 0x24845430, 0xafa00014, 0x8fa60020,
0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114,
0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114,
0x27840208, 0x27450200, 0xc00249a, 0x24060008,
0x26e40094, 0x27450200, 0xc00249a, 0x24060008,
0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8,
-0x8ee20134, 0x8f460248, 0x2021, 0xc004fa8,
+0x8ee20134, 0x8f460248, 0x2021, 0xc0050e0,
0x24050004, 0x8ee20130, 0x24420001, 0xaee20130,
0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0,
0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001,
@@ -1073,7 +1072,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220,
0x30420008, 0x10400004, 0x0, 0xaee30108,
0x8002061, 0x2021, 0xaee40108, 0x2021,
-0x3c030001, 0x641821, 0x906353f0, 0x2e41021,
+0x3c030001, 0x641821, 0x90635c90, 0x2e41021,
0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8,
0x0, 0x8f820040, 0x2e41821, 0x24840001,
0x21702, 0x24420030, 0xa062009c, 0x2e41021,
@@ -1153,13 +1152,13 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
-0x10620022, 0x0, 0x3c040001, 0x24844b70,
+0x10620022, 0x0, 0x3c040001, 0x248453e0,
0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4,
-0x0, 0x3c040001, 0x24844b7c, 0xafa00014,
+0x0, 0x3c040001, 0x248453ec, 0xafa00014,
0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
0x34a5f010, 0x80021c4, 0x0, 0x3c040001,
-0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x248453f8, 0xafa00014, 0x8ee60608, 0x8f470228,
0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120,
0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168,
@@ -1169,7 +1168,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f820220, 0x30420008, 0x14400002, 0x24020001,
0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001,
0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001,
-0x24844bcc, 0xafa00010, 0xafa00014, 0x8fa60020,
+0x2484543c, 0xafa00010, 0xafa00014, 0x8fa60020,
0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020,
0x3c030700, 0x34631000, 0x431025, 0xafa20018,
0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff,
@@ -1200,7 +1199,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bd4,
+0x54e0000c, 0xaee90608, 0x3c040001, 0x24845444,
0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0,
0x0, 0x8f830120, 0x27623800, 0x24660020,
@@ -1226,11 +1225,11 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
0x210c0, 0x24425038, 0x2e22021, 0x24020012,
0xac820000, 0x24020001, 0xac820004, 0x14e0001b,
-0x0, 0x3c040001, 0x24844bdc, 0xafa00010,
+0x0, 0x3c040001, 0x2484544c, 0xafa00010,
0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001,
0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001,
-0x24844be8, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x24845458, 0xafa00014, 0x8ee60608, 0x8f470228,
0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac,
0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150,
0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160,
@@ -1257,7 +1256,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018,
0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010,
0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0,
-0x8f87011c, 0x3c040001, 0x24844ca0, 0xc002403,
+0x8f87011c, 0x3c040001, 0x24845510, 0xc002403,
0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824,
0x3c020400, 0x10620029, 0x43102b, 0x14400008,
0x3c022000, 0x3c020100, 0x10620024, 0x3c020200,
@@ -1274,7 +1273,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018,
0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001,
0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001,
-0x24844cac, 0xc002403, 0x34a5f000, 0x8f8300a0,
+0x2484551c, 0xc002403, 0x34a5f000, 0x8f8300a0,
0x3c027f00, 0x621824, 0x3c020400, 0x10620053,
0x8021, 0x43102b, 0x14400008, 0x3c042000,
0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a,
@@ -1299,43 +1298,43 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0,
0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018,
0x3e00008, 0x27bd0020, 0x0, 0x3c020001,
-0x8c425418, 0x27bdffe8, 0xafbf0014, 0x14400012,
-0xafb00010, 0x3c100001, 0x26105560, 0x2002021,
+0x8c425cb8, 0x27bdffe8, 0xafbf0014, 0x14400012,
+0xafb00010, 0x3c100001, 0x26105e30, 0x2002021,
0xc002488, 0x24052000, 0x26021fe0, 0x3c010001,
-0xac225534, 0x3c010001, 0xac225530, 0xaf420250,
+0xac225df4, 0x3c010001, 0xac225df0, 0xaf420250,
0x24022000, 0xaf500254, 0xaf420258, 0x24020001,
-0x3c010001, 0xac225418, 0x8fbf0014, 0x8fb00010,
-0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635534,
+0x3c010001, 0xac225cb8, 0x8fbf0014, 0x8fb00010,
+0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635df4,
0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000,
-0x3c020001, 0x8c425534, 0x8c830004, 0xac430004,
+0x3c020001, 0x8c425df4, 0x8c830004, 0xac430004,
0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010,
0xac470014, 0xac480018, 0xac49001c, 0x3c010001,
-0xac235534, 0xac44000c, 0x3c020001, 0x24425560,
+0xac235df4, 0xac44000c, 0x3c020001, 0x24425e30,
0x62182b, 0x10600005, 0x0, 0x3c020001,
-0x8c425530, 0x3c010001, 0xac225534, 0x3c030001,
-0x8c635534, 0x3c020001, 0x8c425400, 0xac620000,
-0x3c030001, 0x8c635534, 0x3c020001, 0x8c425400,
+0x8c425df0, 0x3c010001, 0xac225df4, 0x3c030001,
+0x8c635df4, 0x3c020001, 0x8c425ca0, 0xac620000,
+0x3c030001, 0x8c635df4, 0x3c020001, 0x8c425ca0,
0xac620004, 0x3e00008, 0xaf430250, 0x3c030001,
-0x8c635534, 0x3c020001, 0x8c425400, 0x27bdffd0,
+0x8c635df4, 0x3c020001, 0x8c425ca0, 0x27bdffd0,
0xafb40020, 0x8fb40040, 0xafb00010, 0x808021,
0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014,
0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018,
-0xac620000, 0x3c050001, 0x8ca55534, 0x3c020001,
-0x8c425400, 0xc09021, 0xe09821, 0x10800006,
+0xac620000, 0x3c050001, 0x8ca55df4, 0x3c020001,
+0x8c425ca0, 0xc09021, 0xe09821, 0x10800006,
0xaca20004, 0x24a50008, 0xc002490, 0x24060018,
0x800244e, 0x0, 0x24a40008, 0xc002488,
-0x24050018, 0x3c020001, 0x8c425534, 0x3c050001,
-0x24a55560, 0x2442ffe0, 0x3c010001, 0xac225534,
+0x24050018, 0x3c020001, 0x8c425df4, 0x3c050001,
+0x24a55e30, 0x2442ffe0, 0x3c010001, 0xac225df4,
0x45102b, 0x10400005, 0x0, 0x3c020001,
-0x8c425530, 0x3c010001, 0xac225534, 0x3c030001,
-0x8c635534, 0x8e020000, 0xac620000, 0x3c030001,
-0x8c635534, 0x8e020004, 0xac620004, 0xac710008,
-0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225534,
+0x8c425df0, 0x3c010001, 0xac225df4, 0x3c030001,
+0x8c635df4, 0x8e020000, 0xac620000, 0x3c030001,
+0x8c635df4, 0x8e020004, 0xac620004, 0xac710008,
+0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225df4,
0x45102b, 0xac720010, 0xac730014, 0xac740018,
0xac75001c, 0x10400005, 0xac64000c, 0x3c020001,
-0x8c425530, 0x3c010001, 0xac225534, 0x3c030001,
-0x8c635534, 0x3c020001, 0x8c425400, 0xac620000,
-0x3c030001, 0x8c635534, 0x3c020001, 0x8c425400,
+0x8c425df0, 0x3c010001, 0xac225df4, 0x3c030001,
+0x8c635df4, 0x3c020001, 0x8c425ca0, 0xac620000,
+0x3c030001, 0x8c635df4, 0x3c020001, 0x8c425ca0,
0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024,
0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005,
@@ -1381,7 +1380,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
0xac820000, 0x24020001, 0xac820004, 0x1520000a,
0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001,
-0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4,
+0x24845780, 0x3c050004, 0xafa20014, 0x8ee604e4,
0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800,
0x3641821, 0x24420010, 0x43102b, 0x14400073,
0x0, 0x8ee27264, 0x24480010, 0x3641021,
@@ -1410,7 +1409,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
0xac820000, 0x24020001, 0xac820004, 0x1520000a,
0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001,
-0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4,
+0x24845780, 0x3c050004, 0xafa20014, 0x8ee604e4,
0x80028be, 0x34a5f125, 0x34028100, 0xa5020000,
0x9582000e, 0x800261d, 0xa5020002, 0x8f850100,
0x27623000, 0x24a60020, 0xc2102b, 0x50400001,
@@ -1437,7 +1436,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
0x24020005, 0xac820000, 0x24020001, 0xac820004,
0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264,
-0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014,
+0x3c040001, 0x24845780, 0x3c050004, 0xafa20014,
0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264,
0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e,
0x8002681, 0x24e70004, 0x8f840100, 0x27623000,
@@ -1463,7 +1462,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
0x24020001, 0xac820004, 0x15200009, 0x3c050004,
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10,
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845780,
0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004,
0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c,
0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100,
@@ -1483,7 +1482,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c,
0xac430000, 0xac440004, 0xaf8700f0, 0x15200012,
0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4,
-0x3c040001, 0x24844f1c, 0xafa20014, 0x8fa60018,
+0x3c040001, 0x2484578c, 0xafa20014, 0x8fa60018,
0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005,
0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088,
0x80028d3, 0xaee0725c, 0x30430003, 0x24020002,
@@ -1525,7 +1524,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
0x2e22021, 0x24020005, 0xac820000, 0x24020001,
0xac820004, 0x1520000a, 0x3c040001, 0xafab0010,
-0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004,
+0x8ee27264, 0x3c040001, 0x24845780, 0x3c050004,
0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014,
0x8ee27264, 0x34843800, 0x3641821, 0x24420010,
0x43102b, 0x14400073, 0x0, 0x8ee27264,
@@ -1554,7 +1553,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
0x2e22021, 0x24020005, 0xac820000, 0x24020001,
0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010,
-0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004,
+0x8ee27264, 0x3c040001, 0x24845780, 0x3c050004,
0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015,
0x34028100, 0xa5020000, 0x9582000e, 0x800285f,
0xa5020002, 0x8f850100, 0x27623000, 0x24a60020,
@@ -1581,7 +1580,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
0x24020001, 0xac820004, 0x1520000a, 0x34028100,
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10,
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845780,
0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be,
0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264,
0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004,
@@ -1607,7 +1606,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
0x2e22021, 0x24020005, 0xac820000, 0x24020001,
0xac820004, 0x1520000b, 0x3c050004, 0x3c040001,
-0x24844f28, 0xafab0010, 0xafa00014, 0x8ee604e4,
+0x24845798, 0xafab0010, 0xafa00014, 0x8ee604e4,
0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1,
0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff,
0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264,
@@ -1673,7 +1672,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
0x24020001, 0xac820004, 0x1540000a, 0x24020001,
-0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f10,
+0xafa90010, 0x8ee27264, 0x3c040001, 0x24845780,
0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f,
0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc,
0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001,
@@ -1707,7 +1706,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
0x2e22021, 0x24020005, 0xac820000, 0x24020001,
0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001,
-0x24844f28, 0x3c050004, 0xafa90010, 0xafa00014,
+0x24845798, 0x3c050004, 0xafa90010, 0xafa00014,
0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff,
0x8002a72, 0x0, 0x8ee27264, 0x451021,
0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001,
@@ -1731,7 +1730,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f830108, 0x21140, 0x621821, 0xaf830108,
0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013,
0x104000c1, 0x31080, 0x3c010001, 0x220821,
-0x8c224f50, 0x400008, 0x0, 0x8ee204f0,
+0x8c2257c0, 0x400008, 0x0, 0x8ee204f0,
0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c,
0x43102b, 0x144000be, 0x0, 0x8ee304e4,
0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120,
@@ -1758,7 +1757,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
0x2e22021, 0x24020012, 0xac820000, 0x24020001,
0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4,
-0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010,
+0x3c040001, 0x248457a4, 0xafa00014, 0xafa20010,
0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
0x34a5f006, 0x16000003, 0x24020001, 0x8002b71,
0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170,
@@ -1779,7 +1778,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001,
0x370821, 0xa02083e0, 0x24420001, 0xaee2014c,
0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c,
-0x3c040001, 0x24844f40, 0xafa60014, 0xafa20010,
+0x3c040001, 0x248457b0, 0xafa60014, 0xafa20010,
0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910,
0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058,
@@ -1788,7 +1787,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001,
0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018,
0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf,
-0x31080, 0x3c010001, 0x220821, 0x8c224fa0,
+0x31080, 0x3c010001, 0x220821, 0x8c225810,
0x400008, 0x0, 0x9663000e, 0x8ee2725c,
0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c,
0x96e20458, 0x24840001, 0xaee404f0, 0x24630001,
@@ -1817,7 +1816,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
0x2e22021, 0x24020012, 0x240c0001, 0xac820000,
0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4,
-0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010,
+0x3c040001, 0x248457a4, 0xafa00014, 0xafa20010,
0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006,
0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a,
0x240c0001, 0x8002f19, 0x0, 0x966c001c,
@@ -2011,7 +2010,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
0x24425038, 0x2e22021, 0x24020012, 0x240c0001,
0xac820000, 0xac8c0004, 0x5600000d, 0x24100001,
-0x8ee204e4, 0x3c040001, 0x24844f34, 0xafa00014,
+0x8ee204e4, 0x3c040001, 0x248457a4, 0xafa00014,
0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038,
0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4,
@@ -2066,7 +2065,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8821, 0x8f8200e4, 0x24110001, 0x8c430000,
0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e,
0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8,
-0x3c040001, 0x24845050, 0xafa20014, 0x8f8600e0,
+0x3c040001, 0x248458c0, 0xafa20014, 0x8f8600e0,
0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000,
0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018,
0x3074ffff, 0x2694fffc, 0x621024, 0x10400058,
@@ -2164,11 +2163,11 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c8,
0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
0xc002403, 0x34a5f003, 0x80034cc, 0x0,
0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0x248458d4, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0,
0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0,
0x2403ffbf, 0x431024, 0x8003470, 0xaee20000,
@@ -2220,7 +2219,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x50550003, 0x1021, 0x8ee24e30, 0x24420001,
0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
0x2e22021, 0xac960000, 0xac9e0004, 0x16200018,
-0x3c050006, 0x8e020018, 0x3c040001, 0x24845070,
+0x3c050006, 0x8e020018, 0x3c040001, 0x248458e0,
0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009,
0x2003021, 0xc002403, 0xafa30014, 0x93a20037,
0x10400216, 0x340f8100, 0x8e420004, 0x8e430008,
@@ -2253,7 +2252,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x210c0, 0x24425038, 0x2e22021, 0xac960000,
0xac9e0004, 0x1620000d, 0x0, 0xa60c000a,
0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104,
-0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014,
+0x3c040001, 0x248458ec, 0x3c050006, 0xafa20014,
0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001,
0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8,
0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
@@ -2285,7 +2284,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001,
-0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014,
+0x8ee2724c, 0x3c040001, 0x248458f8, 0xafa00014,
0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009,
0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048,
0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001,
@@ -2312,7 +2311,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
0x210c0, 0x24425038, 0x2e22021, 0xac8e0000,
0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c,
-0x3c040001, 0x24845088, 0xafa00014, 0xafa20010,
+0x3c040001, 0x248458f8, 0xafa00014, 0xafa20010,
0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008,
0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174,
0x24420001, 0xaee20174, 0x8ee20174, 0x800346e,
@@ -2342,7 +2341,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0xac960000, 0xac9e0004, 0x1620001d, 0x0,
0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104,
-0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014,
+0x3c040001, 0x248458ec, 0x3c050006, 0xafa20014,
0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821,
0x93a20037, 0x10400031, 0x340f8100, 0x8e420004,
0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000,
@@ -2404,7 +2403,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x10430007, 0x4821, 0x8f8200e4, 0x24090001,
0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
-0x8f8200c8, 0x3c040001, 0x24845050, 0xafa20014,
+0x8f8200c8, 0x3c040001, 0x248458c0, 0xafa20014,
0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
0x34a5f000, 0x8003850, 0x0, 0x8fa3001c,
0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
@@ -2502,15 +2501,15 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c8,
0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
0xc002403, 0x34a5f003, 0x8003850, 0x0,
0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0x248458d4, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf,
0x431024, 0x80037f8, 0xaee20000, 0x8ee25240,
-0xafa20010, 0x8ee25244, 0x3c040001, 0x24845064,
+0xafa20010, 0x8ee25244, 0x3c040001, 0x248458d4,
0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006,
0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468,
@@ -2569,7 +2568,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
0x24425038, 0x2e22021, 0x24020007, 0xac820000,
0x24020001, 0xac820004, 0x15200018, 0x3c050006,
-0x8e020018, 0x3c040001, 0x24845070, 0xafa20010,
+0x8e020018, 0x3c040001, 0x248458e0, 0xafa20010,
0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021,
0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b,
0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c,
@@ -2629,7 +2628,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x10430007, 0x3821, 0x8f8200e4, 0x24070001,
0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
-0x8f8200c8, 0x3c040001, 0x24845094, 0xafa20014,
+0x8f8200c8, 0x3c040001, 0x24845904, 0xafa20014,
0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c,
0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
@@ -2727,11 +2726,11 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x248450a0,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845910,
0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
0xc002403, 0x34a5f203, 0x8003c5b, 0x0,
0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x248450ac, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0x2484591c, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0,
0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0,
0x96e20468, 0x53102b, 0x54400001, 0x3c168000,
@@ -2827,7 +2826,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x14e00019, 0x3c050006, 0x3c040001, 0x24845070,
+0x14e00019, 0x3c050006, 0x3c040001, 0x248458e0,
0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000,
0x8e230004, 0x2203021, 0x1603821, 0xc002403,
0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100,
@@ -2891,7 +2890,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24020001, 0xac620004, 0x1480000e, 0x24030040,
0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007,
0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001,
-0x248450b4, 0xc002403, 0x34a5f001, 0x8003cdd,
+0x24845924, 0xc002403, 0x34a5f001, 0x8003cdd,
0x0, 0x8ee20500, 0x24420001, 0x50430003,
0x1021, 0x8ee20500, 0x24420001, 0xaee20500,
0x8ee20500, 0x21080, 0x571021, 0xac490508,
@@ -2923,7 +2922,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24020003, 0xac620000, 0x24020001, 0xac620004,
0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010,
0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238,
-0x8ee75240, 0x3c040001, 0x248450c0, 0xc002403,
+0x8ee75240, 0x3c040001, 0x24845930, 0xc002403,
0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500,
0x24420001, 0x50430003, 0x1021, 0x8ee20500,
0x24420001, 0xaee20500, 0x8ee20500, 0x21080,
@@ -2943,7 +2942,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f830128, 0x21140, 0x621821, 0xaf830128,
0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012,
0x10400008, 0x31080, 0x3c010001, 0x220821,
-0x8c2250d0, 0x400008, 0x0, 0x24020001,
+0x8c225940, 0x400008, 0x0, 0x24020001,
0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8,
0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024,
0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128,
@@ -2952,7 +2951,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020,
0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe,
0x2c620012, 0x1040029c, 0x31080, 0x3c010001,
-0x220821, 0x8c225128, 0x400008, 0x0,
+0x220821, 0x8c225998, 0x400008, 0x0,
0x8f420218, 0x30420100, 0x10400007, 0x0,
0x95830016, 0x95820018, 0x621823, 0x31402,
0x431021, 0xa5820016, 0x8d82001c, 0x3c038000,
@@ -3053,7 +3052,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
0x24425038, 0x2e22021, 0x24020007, 0xac820000,
0x24020001, 0xac820004, 0x1600000d, 0x0,
-0x8f820120, 0x3c040001, 0x24845118, 0xafa00014,
+0x8f820120, 0x3c040001, 0x24845988, 0xafa00014,
0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008,
0xc002403, 0x34a50001, 0x8004057, 0x0,
0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006,
@@ -3088,7 +3087,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
0x24425038, 0x2e22021, 0x24020001, 0xac950000,
0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c,
-0x3c040001, 0x24845088, 0xafa00014, 0xafa20010,
+0x3c040001, 0x248458f8, 0xafa00014, 0xafa20010,
0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403,
0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188,
0x24420001, 0xaee20188, 0x8004050, 0x8ee20188,
@@ -3114,7 +3113,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
0x24020001, 0xac950000, 0xac820004, 0x1600000b,
-0x0, 0x8ee2724c, 0x3c040001, 0x24845088,
+0x0, 0x8ee2724c, 0x3c040001, 0x248458f8,
0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280,
0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174,
0x24420001, 0xaee20174, 0x8004057, 0x8ee20174,
@@ -3126,16 +3125,16 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xc00249a, 0xafb00010, 0x2021, 0x24100001,
0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204,
0xaf820214, 0x8f460248, 0x24030004, 0x3c020040,
-0x3c010001, 0xac235484, 0x3c010001, 0xac235488,
-0x3c010001, 0xac20553c, 0x3c010001, 0xac225480,
-0x3c010001, 0xac235488, 0xc004fa8, 0x24050004,
-0xc004785, 0x0, 0x8ee20000, 0x3c03feff,
+0x3c010001, 0xac235d24, 0x3c010001, 0xac235d28,
+0x3c010001, 0xac205dfc, 0x3c010001, 0xac225d20,
+0x3c010001, 0xac235d28, 0xc0050e0, 0x24050004,
+0xc0047fc, 0x0, 0x8ee20000, 0x3c03feff,
0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00,
0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac,
0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018,
0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018,
0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001,
-0x248451d0, 0xc002403, 0x3821, 0x8ee20280,
+0x24845a40, 0xc002403, 0x3821, 0x8ee20280,
0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200,
0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400,
0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
@@ -3147,16 +3146,16 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff,
0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c,
0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff,
-0x8ee20000, 0x3c040001, 0x248451dc, 0x3c050008,
+0x8ee20000, 0x3c040001, 0x24845a4c, 0x3c050008,
0x2003021, 0x431024, 0xaee20000, 0x8f820220,
0x3821, 0x3c030300, 0x481024, 0x431025,
0xaf820220, 0xafa00010, 0xc002403, 0xafa00014,
0x8004296, 0x0, 0x2111024, 0x1040001f,
0x3c024000, 0x8f830224, 0x24021402, 0x1462000b,
-0x3c03fdff, 0x3c040001, 0x248451e8, 0x3c050008,
+0x3c03fdff, 0x3c040001, 0x24845a58, 0x3c050008,
0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff,
0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000,
-0x3463ffff, 0x2002021, 0x431024, 0xc004cf4,
+0x3463ffff, 0x2002021, 0x431024, 0xc004e2c,
0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220,
0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
0x431024, 0x8004295, 0x511025, 0x2021024,
@@ -3227,7 +3226,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4,
0x10c4002a, 0x0, 0x8ee2007c, 0x24420001,
0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0,
-0x3c020001, 0x8c4275c0, 0x3c030008, 0x8f8600e0,
+0x3c020001, 0x8c427e90, 0x3c030008, 0x8f8600e0,
0x431024, 0x1040001d, 0x0, 0x10c4001b,
0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080,
0x24850008, 0x27622800, 0x50a20001, 0x27651800,
@@ -3263,12 +3262,12 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x621023, 0x2c420002, 0x1440fffc, 0x0,
0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425498,
+0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425d38,
0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001,
-0x248451f4, 0x3c050008, 0x24020001, 0x3c010001,
+0x24845a64, 0x3c050008, 0x24020001, 0x3c010001,
0x370821, 0xac2283ac, 0xafa00010, 0xafa00014,
-0x8f860220, 0x34a50498, 0x3c010001, 0xac205498,
-0x3c010001, 0xac22548c, 0xc002403, 0x3821,
+0x8f860220, 0x34a50498, 0x3c010001, 0xac205d38,
+0x3c010001, 0xac225d2c, 0xc002403, 0x3821,
0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024,
0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe,
0x431024, 0x30840002, 0x1080011e, 0xaee204d0,
@@ -3334,24 +3333,24 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
0x24020001, 0x54620003, 0xafa00010, 0x80043d6,
-0x0, 0x3c040001, 0x24845200, 0xafa00014,
+0x0, 0x3c040001, 0x24845a70, 0xafa00014,
0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
0x34a5f011, 0x80043d6, 0x0, 0x3c040001,
-0x2484520c, 0xafa00014, 0x8f860120, 0x8f870124,
+0x24845a7c, 0xafa00014, 0x8f860120, 0x8f870124,
0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6,
-0x0, 0x3c040001, 0x24845218, 0xafa00014,
+0x0, 0x3c040001, 0x24845a88, 0xafa00014,
0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac,
0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c,
0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028,
-0x3c020001, 0x8c425498, 0x27bdffe0, 0x1440000d,
-0xafbf0018, 0x3c040001, 0x24845224, 0x3c050008,
+0x3c020001, 0x8c425d38, 0x27bdffe0, 0x1440000d,
+0xafbf0018, 0x3c040001, 0x24845a94, 0x3c050008,
0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499,
-0x24020001, 0x3c010001, 0xac225498, 0xc002403,
+0x24020001, 0x3c010001, 0xac225d38, 0xc002403,
0x3821, 0x8ee204d0, 0x3c030001, 0x771821,
0x946383b2, 0x34420001, 0x10600007, 0xaee204d0,
0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
-0x34420008, 0xaf820220, 0x2021, 0xc0050b3,
+0x34420008, 0xaf820220, 0x2021, 0xc005276,
0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008,
0x27bd0020, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
@@ -3369,7 +3368,7 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x3c120001,
-0x26521200, 0x3c140001, 0x8e945410, 0x3c100001,
+0x26521200, 0x3c140001, 0x8e945cb0, 0x3c100001,
0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000,
0x8eb30000, 0x26a400b, 0x248000a, 0x200f821,
0x0, 0xd, 0x0, 0x0,
@@ -3430,843 +3429,978 @@ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1062000c, 0x43102b, 0x14400006, 0x3c026000,
0x3c024000, 0x10620008, 0x24020800, 0x8004539,
0x0, 0x10620004, 0x24020800, 0x8004539,
-0x0, 0x24020700, 0x3c010001, 0xac22549c,
+0x0, 0x24020700, 0x3c010001, 0xac225d3c,
0x3e00008, 0x0, 0x27bdffd0, 0xafbf0028,
-0x3c010001, 0xc004cd1, 0xac205484, 0x24040001,
-0x2821, 0x27a60020, 0x34028000, 0xc0048ee,
-0xa7a20020, 0x8f830054, 0x8f820054, 0x800454b,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050001, 0xc0048ac,
-0x27a60020, 0x8f830054, 0x8f820054, 0x8004557,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050001, 0xc0048ac,
-0x27a60020, 0x8f830054, 0x8f820054, 0x8004563,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050002, 0xc0048ac,
-0x27a60018, 0x8f830054, 0x8f820054, 0x800456f,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050003, 0xc0048ac,
-0x27a6001a, 0x97a20020, 0x10400028, 0x24030001,
-0x3c020001, 0x8c425484, 0x97a30018, 0x34420001,
-0x3c010001, 0xac225484, 0x24020015, 0x1462000e,
-0x0, 0x97a2001a, 0x3042fff0, 0x3843f420,
-0x2c630001, 0x3842f430, 0x2c420001, 0x621825,
-0x10600005, 0x24020003, 0x3c010001, 0xac225550,
-0x80045a8, 0x3c08fff0, 0x97a30018, 0x24027810,
-0x1462000a, 0x24020002, 0x97a2001a, 0x3042fff0,
-0x14400006, 0x24020002, 0x24020004, 0x3c010001,
-0xac225550, 0x80045a8, 0x3c08fff0, 0x3c010001,
-0xac225550, 0x80045a8, 0x3c08fff0, 0x3c020001,
-0x8c425484, 0x3c010001, 0xac235550, 0x34420004,
-0x3c010001, 0xac225484, 0x3c08fff0, 0x3508bdc0,
-0x8f830054, 0x97a60018, 0x3c070001, 0x8ce75550,
-0x3c040001, 0x24845290, 0x24020001, 0x3c010001,
-0xac22548c, 0xafa60010, 0x3c060001, 0x8cc65484,
-0x97a2001a, 0x3c05000d, 0x34a50100, 0x3c010001,
-0xac205488, 0x681821, 0x3c010001, 0xac235548,
-0xc002403, 0xafa20014, 0x8fbf0028, 0x3e00008,
-0x27bd0030, 0x27bdffe8, 0x24070004, 0x3c040001,
-0x8c845488, 0x3021, 0x24020001, 0x1482000a,
-0xafbf0010, 0x3c020001, 0x8c4275cc, 0x3c050004,
-0x30428000, 0x1040000c, 0x34a593e0, 0x3c05000f,
-0x80045db, 0x34a54240, 0x3c020001, 0x8c4275cc,
-0x3c05000f, 0x30428000, 0x10400003, 0x34a54240,
-0x3c05001e, 0x34a58480, 0x3c020001, 0x8c425548,
-0x8f830054, 0x451021, 0x431023, 0x45102b,
-0x1440002e, 0x0, 0x3c020001, 0x8c425490,
-0x1440002a, 0x2cc20001, 0x7182b, 0x431024,
-0x1040001d, 0x0, 0x3c090001, 0x8d295484,
-0x240b0001, 0x3c054000, 0x3c080001, 0x250875cc,
-0x250afffc, 0x42042, 0x14800002, 0x24e7ffff,
-0x24040008, 0x891024, 0x5040000b, 0x2cc20001,
-0x148b0004, 0x0, 0x8d020000, 0x8004600,
-0x451024, 0x8d420000, 0x451024, 0x54400001,
-0x24060001, 0x2cc20001, 0x7182b, 0x431024,
-0x5440ffed, 0x42042, 0x3c010001, 0x10c00024,
-0xac245488, 0x8f830054, 0x24020001, 0x3c010001,
-0xac22548c, 0x3c010001, 0xac235548, 0x3c020001,
-0x8c42548c, 0x10400006, 0x24020001, 0x3c010001,
-0xac20548c, 0x3c010001, 0x370821, 0xac2283ac,
-0x3c030001, 0x771821, 0x8c6383ac, 0x24020008,
-0x10620005, 0x24020001, 0xc004630, 0x0,
-0x800462d, 0x0, 0x3c030001, 0x8c635488,
-0x10620007, 0x2402000e, 0x3c030001, 0x8c637560,
-0x10620003, 0x0, 0xc004cf4, 0x8f840220,
-0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0,
-0x3c02fdff, 0xafbf0018, 0x8ee30000, 0x3c050001,
-0x8ca55488, 0x3c040001, 0x8c8454a8, 0x3442ffff,
-0x621824, 0x14a40008, 0xaee30000, 0x3c030001,
-0x771821, 0x8c6383ac, 0x3c020001, 0x8c4254ac,
-0x10620008, 0x0, 0x3c020001, 0x571021,
-0x8c4283ac, 0x3c010001, 0xac2554a8, 0x3c010001,
-0xac2254ac, 0x3c030001, 0x8c635488, 0x24020002,
-0x10620131, 0x2c620003, 0x10400005, 0x24020001,
-0x10620008, 0x0, 0x800477f, 0x0,
-0x24020004, 0x10620079, 0x24020001, 0x8004780,
+0x8f830054, 0x8f820054, 0x3c010001, 0xac205d24,
+0x8004544, 0x24630064, 0x8f820054, 0x621023,
+0x2c420065, 0x1440fffc, 0x0, 0xc004d49,
+0x0, 0x24040001, 0x2821, 0x27a60020,
+0x34028000, 0xc004966, 0xa7a20020, 0x8f830054,
+0x8f820054, 0x8004555, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
+0x24050001, 0xc004924, 0x27a60020, 0x8f830054,
+0x8f820054, 0x8004561, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
+0x24050001, 0xc004924, 0x27a60020, 0x8f830054,
+0x8f820054, 0x800456d, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
+0x24050002, 0xc004924, 0x27a60018, 0x8f830054,
+0x8f820054, 0x8004579, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
+0x24050003, 0xc004924, 0x27a6001a, 0x3c040001,
+0x24845b00, 0x97a60020, 0x97a70018, 0x97a2001a,
+0x3c05000d, 0x34a50100, 0xafa00014, 0xc002403,
+0xafa20010, 0x97a20020, 0x10400045, 0x24036040,
+0x97a2001a, 0x3042fff0, 0x14430009, 0x24020020,
+0x97a30018, 0x54620008, 0x24027830, 0x24020003,
+0x3c010001, 0xac225d24, 0x80045a4, 0x24020005,
+0x97a30018, 0x24027830, 0x1462000e, 0x24030010,
+0x97a2001a, 0x3042fff0, 0x1443000a, 0x24020003,
+0x3c010001, 0xac225d24, 0x24020006, 0x3c010001,
+0xac225e0c, 0x3c010001, 0xac225e18, 0x80045da,
+0x3c09fff0, 0x3c020001, 0x8c425d24, 0x97a30018,
+0x34420001, 0x3c010001, 0xac225d24, 0x24020015,
+0x1462000e, 0x0, 0x97a2001a, 0x3042fff0,
+0x3843f420, 0x2c630001, 0x3842f430, 0x2c420001,
+0x621825, 0x10600005, 0x24020003, 0x3c010001,
+0xac225e18, 0x80045da, 0x3c09fff0, 0x97a30018,
+0x24027810, 0x1462000a, 0x24020002, 0x97a2001a,
+0x3042fff0, 0x14400006, 0x24020002, 0x24020004,
+0x3c010001, 0xac225e18, 0x80045da, 0x3c09fff0,
+0x3c010001, 0xac225e18, 0x80045da, 0x3c09fff0,
+0x3c020001, 0x8c425d24, 0x24030001, 0x3c010001,
+0xac235e18, 0x34420004, 0x3c010001, 0xac225d24,
+0x3c09fff0, 0x3529bdc0, 0x8f830054, 0x3c060001,
+0x8cc65d24, 0x3c070001, 0x8ce75e18, 0x97a80018,
+0x3c040001, 0x24845b00, 0x24020001, 0x3c010001,
+0xac225d2c, 0xafa80010, 0x97a2001a, 0x3c05000d,
+0x34a50100, 0x3c010001, 0xac205d28, 0x691821,
+0x3c010001, 0xac235e08, 0xc002403, 0xafa20014,
+0x8fbf0028, 0x3e00008, 0x27bd0030, 0x27bdffe8,
+0x3c050001, 0x8ca55d28, 0x24060004, 0x24020001,
+0x14a20014, 0xafbf0010, 0x3c020001, 0x8c427e9c,
+0x30428000, 0x10400005, 0x3c04000f, 0x3c030001,
+0x8c635e18, 0x8004608, 0x34844240, 0x3c040004,
+0x3c030001, 0x8c635e18, 0x348493e0, 0x24020005,
+0x14620016, 0x0, 0x3c04003d, 0x8004620,
+0x34840900, 0x3c020001, 0x8c427e98, 0x30428000,
+0x10400005, 0x3c04001e, 0x3c030001, 0x8c635e18,
+0x800461b, 0x34848480, 0x3c04000f, 0x3c030001,
+0x8c635e18, 0x34844240, 0x24020005, 0x14620003,
+0x0, 0x3c04007a, 0x34841200, 0x3c020001,
+0x8c425e08, 0x8f830054, 0x441021, 0x431023,
+0x44102b, 0x14400037, 0x0, 0x3c020001,
+0x8c425d30, 0x14400033, 0x0, 0x3c010001,
+0x10c00025, 0xac205d40, 0x3c090001, 0x8d295d24,
+0x24070001, 0x3c044000, 0x3c080001, 0x25087e9c,
+0x250afffc, 0x52842, 0x14a00002, 0x24c6ffff,
+0x24050008, 0xa91024, 0x10400010, 0x0,
+0x14a70008, 0x0, 0x8d020000, 0x441024,
+0x1040000a, 0x0, 0x3c010001, 0x800464c,
+0xac255d40, 0x8d420000, 0x441024, 0x10400003,
+0x0, 0x3c010001, 0xac275d40, 0x3c020001,
+0x8c425d40, 0x6182b, 0x2c420001, 0x431024,
+0x5440ffe5, 0x52842, 0x8f820054, 0x3c030001,
+0x8c635d40, 0x3c010001, 0xac225e08, 0x1060002a,
+0x24020001, 0x3c010001, 0xac255d28, 0x3c010001,
+0xac225d2c, 0x3c020001, 0x8c425d40, 0x10400022,
+0x0, 0x3c020001, 0x8c425d2c, 0x1040000a,
+0x24020001, 0x3c010001, 0xac205d2c, 0x3c010001,
+0x370821, 0xac2283ac, 0x3c010001, 0xac205dac,
+0x3c010001, 0xac225d64, 0x3c030001, 0x771821,
+0x8c6383ac, 0x24020008, 0x10620005, 0x24020001,
+0xc004686, 0x0, 0x8004683, 0x0,
+0x3c030001, 0x8c635d28, 0x10620007, 0x2402000e,
+0x3c030001, 0x8c637e30, 0x10620003, 0x0,
+0xc004e2c, 0x8f840220, 0x8fbf0010, 0x3e00008,
+0x27bd0018, 0x27bdffe0, 0x3c02fdff, 0xafbf001c,
+0xafb00018, 0x8ee30000, 0x3c050001, 0x8ca55d28,
+0x3c040001, 0x8c845d50, 0x3442ffff, 0x621824,
+0x14a40008, 0xaee30000, 0x3c030001, 0x771821,
+0x8c6383ac, 0x3c020001, 0x8c425d54, 0x10620008,
0x0, 0x3c020001, 0x571021, 0x8c4283ac,
-0x2443ffff, 0x2c620008, 0x10400122, 0x31080,
-0x3c010001, 0x220821, 0x8c2252a8, 0x400008,
-0x0, 0xc004785, 0x0, 0x3c020001,
-0x8c425494, 0x3c010001, 0xac205420, 0x104000bd,
-0x24020002, 0x3c010001, 0x370821, 0xac2283ac,
-0x3c010001, 0x8004782, 0xac205494, 0xc00492f,
-0x0, 0x3c030001, 0x8c6354b0, 0x80046f1,
-0x24020011, 0x3c050001, 0x8ca55488, 0x3c060001,
-0x8cc675cc, 0xc004fa8, 0x2021, 0x24020005,
-0x3c010001, 0xac205494, 0x3c010001, 0x370821,
-0x8004782, 0xac2283ac, 0x3c040001, 0x2484529c,
-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
-0xafa00010, 0xc002403, 0xafa00014, 0x8004782,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0x800471a, 0xaf820220, 0x8f820220, 0x3c030004,
-0x431024, 0x14400090, 0x24020007, 0x8f830054,
-0x3c020001, 0x8c425540, 0x2463d8f0, 0x431023,
-0x2c422710, 0x144000df, 0x24020001, 0x8004780,
-0x0, 0x3c050001, 0x8ca55488, 0xc0050b3,
-0x2021, 0xc00517e, 0x2021, 0x3c030001,
-0x8c6375c4, 0x46100d1, 0x24020001, 0x3c020008,
-0x621024, 0x10400006, 0x0, 0x8f820214,
-0x3c03ffff, 0x431024, 0x80046bd, 0x3442251f,
-0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
-0xaf820214, 0x8ee20000, 0x3c030200, 0x431025,
-0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
-0x24020008, 0x3c010001, 0x370821, 0xc0043dd,
-0xac2283ac, 0x8004782, 0x0, 0x3c020001,
-0x571021, 0x8c4283ac, 0x2443ffff, 0x2c620008,
-0x104000ac, 0x31080, 0x3c010001, 0x220821,
-0x8c2252c8, 0x400008, 0x0, 0xc00429b,
-0x0, 0x3c010001, 0xac20548c, 0xaf800204,
-0x3c010001, 0xc004785, 0xac2075b0, 0x24020001,
-0x3c010001, 0xac2254a0, 0x24020002, 0x3c010001,
-0x370821, 0x8004782, 0xac2283ac, 0xc004802,
-0x0, 0x3c030001, 0x8c6354a0, 0x24020009,
-0x14620090, 0x24020003, 0x3c010001, 0x370821,
-0x8004782, 0xac2283ac, 0x3c020001, 0x8c4275c8,
-0x30424000, 0x10400005, 0x0, 0x8f820044,
-0x3c03ffff, 0x8004702, 0x34637fff, 0x8f820044,
-0x2403ff7f, 0x431024, 0xaf820044, 0x8f830054,
-0x800471c, 0x24020004, 0x8f830054, 0x3c020001,
-0x8c425540, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400074, 0x24020005, 0x3c010001, 0x370821,
-0x8004782, 0xac2283ac, 0x8f820220, 0x3c03f700,
-0x431025, 0xaf820220, 0xaf800204, 0x3c010001,
-0xac2075b0, 0x8f830054, 0x24020006, 0x3c010001,
-0x370821, 0xac2283ac, 0x3c010001, 0x8004782,
-0xac235540, 0x8f830054, 0x3c020001, 0x8c425540,
-0x2463fff6, 0x431023, 0x2c42000a, 0x14400059,
-0x0, 0x24020007, 0x3c010001, 0x370821,
-0x8004782, 0xac2283ac, 0x8f820220, 0x3c04f700,
-0x441025, 0xaf820220, 0x8f820220, 0x3c030300,
-0x431024, 0x14400005, 0x1821, 0x8f820220,
-0x24030001, 0x441025, 0xaf820220, 0x10600043,
-0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001,
-0x8c845538, 0x431024, 0x3442251f, 0xaf820214,
-0x24020008, 0x3c010001, 0x370821, 0x1080000b,
-0xac2283ac, 0x3c020001, 0x8c425514, 0x14400007,
-0x24020001, 0x3c010001, 0xac227560, 0xc004cf4,
-0x8f840220, 0x800476f, 0x0, 0x8f820220,
-0x3c030008, 0x431024, 0x14400017, 0x2402000e,
-0x3c010001, 0xac227560, 0x8ee20000, 0x2021,
-0x3c030200, 0x431025, 0xc00517e, 0xaee20000,
-0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
-0x8f820220, 0x34420002, 0xc0043dd, 0xaf820220,
-0x3c050001, 0x8ca55488, 0xc0050b3, 0x2021,
-0x8004782, 0x0, 0x3c020001, 0x8c425514,
-0x10400010, 0x0, 0x3c020001, 0x8c425510,
-0x2442ffff, 0x3c010001, 0xac225510, 0x14400009,
-0x24020002, 0x3c010001, 0xac205514, 0x3c010001,
-0x8004782, 0xac225510, 0x24020001, 0x3c010001,
-0xac22548c, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x8f820200, 0x8f820220, 0x8f820220, 0x34420004,
-0xaf820220, 0x8f820200, 0x3c060001, 0x8cc65488,
-0x34420004, 0xaf820200, 0x24020002, 0x10c2003a,
-0x2cc20003, 0x10400005, 0x24020001, 0x10c20008,
-0x0, 0x80047cb, 0x0, 0x24020004,
-0x10c20013, 0x24020001, 0x80047cb, 0x0,
-0x3c030001, 0x8c635478, 0x3c020001, 0x8c425480,
-0x3c040001, 0x8c84549c, 0x3c050001, 0x8ca5547c,
-0xaf860200, 0xaf860220, 0x34630022, 0x441025,
-0x451025, 0x34420002, 0x80047ca, 0xaf830200,
-0x3c030001, 0x8c635538, 0xaf820200, 0x10600009,
-0xaf820220, 0x3c020001, 0x8c425514, 0x14400005,
-0x3c033f00, 0x3c020001, 0x8c425470, 0x80047be,
-0x346300e0, 0x3c020001, 0x8c425470, 0x3c033f00,
-0x346300e2, 0x431025, 0xaf820200, 0x3c030001,
-0x8c635474, 0x3c04f700, 0x3c020001, 0x8c425480,
-0x3c050001, 0x8ca5549c, 0x641825, 0x431025,
-0x451025, 0xaf820220, 0x3e00008, 0x0,
-0x8f820220, 0x3c030001, 0x8c635488, 0x34420004,
-0xaf820220, 0x24020001, 0x1062000f, 0x0,
-0x8f830054, 0x8f820054, 0x24630002, 0x621023,
-0x2c420003, 0x10400011, 0x0, 0x8f820054,
-0x621023, 0x2c420003, 0x1040000c, 0x0,
-0x80047dc, 0x0, 0x8f830054, 0x8f820054,
-0x80047e8, 0x24630007, 0x8f820054, 0x621023,
-0x2c420008, 0x1440fffc, 0x0, 0x8f8400e0,
-0x30820007, 0x1040000d, 0x0, 0x8f820054,
-0x8f8300e0, 0x14830009, 0x24450032, 0x8f820054,
-0xa21023, 0x2c420033, 0x10400004, 0x0,
-0x8f8200e0, 0x1082fff9, 0x0, 0x8f820220,
-0x2403fffd, 0x431024, 0xaf820220, 0x3e00008,
-0x0, 0x3c030001, 0x8c6354a0, 0x3c020001,
-0x8c4254a4, 0x50620004, 0x2463ffff, 0x3c010001,
-0xac2354a4, 0x2463ffff, 0x2c620009, 0x1040009d,
-0x31080, 0x3c010001, 0x220821, 0x8c2252e8,
-0x400008, 0x0, 0x8f820044, 0x34428080,
-0xaf820044, 0x8f830054, 0x800489b, 0x24020002,
-0x8f830054, 0x3c020001, 0x8c425544, 0x2463d8f0,
-0x431023, 0x2c422710, 0x1440008a, 0x24020003,
-0x80048a8, 0x0, 0x8f820044, 0x3c03ffff,
-0x34637fff, 0x431024, 0xaf820044, 0x8f830054,
-0x800489b, 0x24020004, 0x8f830054, 0x3c020001,
-0x8c425544, 0x2463fff6, 0x431023, 0x2c42000a,
-0x14400078, 0x24020005, 0x80048a8, 0x0,
+0x3c010001, 0xac255d50, 0x3c010001, 0xac225d54,
+0x3c030001, 0x8c635d28, 0x24020002, 0x10620150,
+0x2c620003, 0x10400005, 0x24020001, 0x10620008,
+0x0, 0x80047f5, 0x0, 0x24020004,
+0x10620098, 0x24020001, 0x80047f6, 0x0,
+0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff,
+0x2c620008, 0x10400141, 0x31080, 0x3c010001,
+0x220821, 0x8c225b18, 0x400008, 0x0,
+0x3c030001, 0x8c635e18, 0x24020005, 0x14620014,
+0x0, 0x3c020001, 0x8c425d34, 0x1040000a,
+0x24020003, 0xc0047fc, 0x0, 0x24020002,
+0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+0x80046d2, 0xac205d34, 0x3c010001, 0x370821,
+0xac2283ac, 0x3c010001, 0x80047f8, 0xac205cc0,
+0xc0047fc, 0x0, 0x3c020001, 0x8c425d34,
+0x3c010001, 0xac205cc0, 0x104000c4, 0x24020002,
+0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+0x80047f8, 0xac205d34, 0x24020001, 0x3c010001,
+0xc0049a7, 0xac225d60, 0x3c030001, 0x8c635d60,
+0x8004767, 0x24020011, 0x3c020001, 0x8c425e18,
+0x24100005, 0x10500007, 0x0, 0x3c050001,
+0x8ca55d28, 0x3c060001, 0x8cc67e9c, 0xc0050e0,
+0x2021, 0x3c010001, 0xac205d34, 0x3c010001,
+0x370821, 0x80047f8, 0xac3083ac, 0x3c040001,
+0x24845b0c, 0x3c05000f, 0x34a50100, 0x3021,
+0x3821, 0xafa00010, 0xc002403, 0xafa00014,
+0x80047f8, 0x0, 0x8f820220, 0x3c03f700,
+0x431025, 0x8004790, 0xaf820220, 0x8f820220,
+0x3c030004, 0x431024, 0x14400091, 0x24020007,
+0x8f830054, 0x3c020001, 0x8c425e00, 0x2463d8f0,
+0x431023, 0x2c422710, 0x144000e0, 0x24020001,
+0x80047f6, 0x0, 0x3c050001, 0x8ca55d28,
+0xc005276, 0x2021, 0xc005397, 0x2021,
+0x3c030001, 0x8c637e94, 0x46100d2, 0x24020001,
+0x3c020008, 0x621024, 0x10400006, 0x0,
+0x8f820214, 0x3c03ffff, 0x431024, 0x8004732,
+0x3442251f, 0x8f820214, 0x3c03ffff, 0x431024,
+0x3442241f, 0xaf820214, 0x8ee20000, 0x3c030200,
+0x431025, 0xaee20000, 0x8f820220, 0x2403fffb,
+0x431024, 0xaf820220, 0x8f820220, 0x34420002,
+0xaf820220, 0x24020008, 0x3c010001, 0x370821,
+0xc0043dd, 0xac2283ac, 0x3c010001, 0x80047f8,
+0xac205db0, 0x3c020001, 0x571021, 0x8c4283ac,
+0x2443ffff, 0x2c620008, 0x104000ac, 0x31080,
+0x3c010001, 0x220821, 0x8c225b38, 0x400008,
+0x0, 0xc00429b, 0x0, 0x3c010001,
+0xac205d2c, 0xaf800204, 0x3c010001, 0xc0047fc,
+0xac207e80, 0x24020001, 0x3c010001, 0xac225d44,
+0x24020002, 0x3c010001, 0x370821, 0x80047f8,
+0xac2283ac, 0xc004879, 0x0, 0x3c030001,
+0x8c635d44, 0x24020009, 0x14620090, 0x24020003,
+0x3c010001, 0x370821, 0x80047f8, 0xac2283ac,
+0x3c020001, 0x8c427e98, 0x30424000, 0x10400005,
+0x0, 0x8f820044, 0x3c03ffff, 0x8004778,
+0x34637fff, 0x8f820044, 0x2403ff7f, 0x431024,
+0xaf820044, 0x8f830054, 0x8004792, 0x24020004,
+0x8f830054, 0x3c020001, 0x8c425e00, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400074, 0x24020005,
+0x3c010001, 0x370821, 0x80047f8, 0xac2283ac,
0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
-0x8f820220, 0x34420002, 0xaf820220, 0x3c023f00,
-0x344200e0, 0xaf820200, 0x8f820200, 0x2403fffd,
-0x431024, 0xaf820200, 0x24040001, 0x3405ffff,
-0xaf840204, 0x8f830054, 0x8f820054, 0x800484f,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820224, 0x42040,
-0xa4102b, 0x1040fff2, 0x0, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x8f820214,
-0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214,
-0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
-0x8f820220, 0x3c04f700, 0x34840008, 0x34420002,
-0xaf820220, 0x8f820220, 0x3c033f00, 0x346300e2,
-0x441025, 0xaf820220, 0xaf830200, 0x8f8400f0,
-0x276217f8, 0x14820002, 0x24850008, 0x27651000,
-0x8f8200f4, 0x10a20007, 0x3c038000, 0x34630040,
-0x3c020001, 0x24425430, 0xac820000, 0xac830004,
-0xaf8500f0, 0x8f830054, 0x800489b, 0x24020006,
-0x8f830054, 0x3c020001, 0x8c425544, 0x2463fff6,
-0x431023, 0x2c42000a, 0x14400022, 0x24020007,
-0x80048a8, 0x0, 0x8f8200e0, 0xaf8200e4,
-0x8f8200e0, 0xaf8200e8, 0x8f820220, 0x34420004,
-0xaf820220, 0x8f820220, 0x2403fff7, 0x431024,
-0xaf820220, 0x8f820044, 0x34428080, 0xaf820044,
-0x8f830054, 0x24020008, 0x3c010001, 0xac2254a0,
-0x3c010001, 0x80048aa, 0xac235544, 0x8f830054,
-0x3c020001, 0x8c425544, 0x2463d8f0, 0x431023,
-0x2c422710, 0x14400003, 0x24020009, 0x3c010001,
-0xac2254a0, 0x3e00008, 0x0, 0x27bdffd8,
+0xaf800204, 0x3c010001, 0xac207e80, 0x8f830054,
+0x24020006, 0x3c010001, 0x370821, 0xac2283ac,
+0x3c010001, 0x80047f8, 0xac235e00, 0x8f830054,
+0x3c020001, 0x8c425e00, 0x2463fff6, 0x431023,
+0x2c42000a, 0x14400059, 0x0, 0x24020007,
+0x3c010001, 0x370821, 0x80047f8, 0xac2283ac,
+0x8f820220, 0x3c04f700, 0x441025, 0xaf820220,
+0x8f820220, 0x3c030300, 0x431024, 0x14400005,
+0x1821, 0x8f820220, 0x24030001, 0x441025,
+0xaf820220, 0x10600043, 0x24020001, 0x8f820214,
+0x3c03ffff, 0x3c040001, 0x8c845df8, 0x431024,
+0x3442251f, 0xaf820214, 0x24020008, 0x3c010001,
+0x370821, 0x1080000b, 0xac2283ac, 0x3c020001,
+0x8c425dd4, 0x14400007, 0x24020001, 0x3c010001,
+0xac227e30, 0xc004e2c, 0x8f840220, 0x80047e5,
+0x0, 0x8f820220, 0x3c030008, 0x431024,
+0x14400017, 0x2402000e, 0x3c010001, 0xac227e30,
+0x8ee20000, 0x2021, 0x3c030200, 0x431025,
+0xc005397, 0xaee20000, 0x8f820220, 0x2403fffb,
+0x431024, 0xaf820220, 0x8f820220, 0x34420002,
+0xc0043dd, 0xaf820220, 0x3c050001, 0x8ca55d28,
+0xc005276, 0x2021, 0x80047f8, 0x0,
+0x3c020001, 0x8c425dd4, 0x10400010, 0x0,
+0x3c020001, 0x8c425dd0, 0x2442ffff, 0x3c010001,
+0xac225dd0, 0x14400009, 0x24020002, 0x3c010001,
+0xac205dd4, 0x3c010001, 0x80047f8, 0xac225dd0,
+0x24020001, 0x3c010001, 0xac225d2c, 0x8fbf001c,
+0x8fb00018, 0x3e00008, 0x27bd0020, 0x8f820200,
+0x8f820220, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820200, 0x3c060001, 0x8cc65d28, 0x34420004,
+0xaf820200, 0x24020002, 0x10c2003a, 0x2cc20003,
+0x10400005, 0x24020001, 0x10c20008, 0x0,
+0x8004842, 0x0, 0x24020004, 0x10c20013,
+0x24020001, 0x8004842, 0x0, 0x3c030001,
+0x8c635d18, 0x3c020001, 0x8c425d20, 0x3c040001,
+0x8c845d3c, 0x3c050001, 0x8ca55d1c, 0xaf860200,
+0xaf860220, 0x34630022, 0x441025, 0x451025,
+0x34420002, 0x8004841, 0xaf830200, 0x3c030001,
+0x8c635df8, 0xaf820200, 0x10600009, 0xaf820220,
+0x3c020001, 0x8c425dd4, 0x14400005, 0x3c033f00,
+0x3c020001, 0x8c425d10, 0x8004835, 0x346300e0,
+0x3c020001, 0x8c425d10, 0x3c033f00, 0x346300e2,
+0x431025, 0xaf820200, 0x3c030001, 0x8c635d14,
+0x3c04f700, 0x3c020001, 0x8c425d20, 0x3c050001,
+0x8ca55d3c, 0x641825, 0x431025, 0x451025,
+0xaf820220, 0x3e00008, 0x0, 0x8f820220,
+0x3c030001, 0x8c635d28, 0x34420004, 0xaf820220,
+0x24020001, 0x1062000f, 0x0, 0x8f830054,
+0x8f820054, 0x24630002, 0x621023, 0x2c420003,
+0x10400011, 0x0, 0x8f820054, 0x621023,
+0x2c420003, 0x1040000c, 0x0, 0x8004853,
+0x0, 0x8f830054, 0x8f820054, 0x800485f,
+0x24630007, 0x8f820054, 0x621023, 0x2c420008,
+0x1440fffc, 0x0, 0x8f8400e0, 0x30820007,
+0x1040000d, 0x0, 0x8f820054, 0x8f8300e0,
+0x14830009, 0x24450032, 0x8f820054, 0xa21023,
+0x2c420033, 0x10400004, 0x0, 0x8f8200e0,
+0x1082fff9, 0x0, 0x8f820220, 0x2403fffd,
+0x431024, 0xaf820220, 0x3e00008, 0x0,
+0x3c030001, 0x8c635d44, 0x3c020001, 0x8c425d48,
+0x50620004, 0x2463ffff, 0x3c010001, 0xac235d48,
+0x2463ffff, 0x2c620009, 0x1040009d, 0x31080,
+0x3c010001, 0x220821, 0x8c225b58, 0x400008,
+0x0, 0x8f820044, 0x34428080, 0xaf820044,
+0x8f830054, 0x8004912, 0x24020002, 0x8f830054,
+0x3c020001, 0x8c425e04, 0x2463d8f0, 0x431023,
+0x2c422710, 0x1440008a, 0x24020003, 0x800491f,
+0x0, 0x8f820044, 0x3c03ffff, 0x34637fff,
+0x431024, 0xaf820044, 0x8f830054, 0x8004912,
+0x24020004, 0x8f830054, 0x3c020001, 0x8c425e04,
+0x2463fff6, 0x431023, 0x2c42000a, 0x14400078,
+0x24020005, 0x800491f, 0x0, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0x8f820220,
+0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+0x34420002, 0xaf820220, 0x3c023f00, 0x344200e0,
+0xaf820200, 0x8f820200, 0x2403fffd, 0x431024,
+0xaf820200, 0x24040001, 0x3405ffff, 0xaf840204,
+0x8f830054, 0x8f820054, 0x80048c6, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820224, 0x42040, 0xa4102b,
+0x1040fff2, 0x0, 0x8f820220, 0x3c03f700,
+0x431025, 0xaf820220, 0x8f820214, 0x3c03ffff,
+0x431024, 0x3442251f, 0xaf820214, 0x8f820220,
+0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+0x3c04f700, 0x34840008, 0x34420002, 0xaf820220,
+0x8f820220, 0x3c033f00, 0x346300e2, 0x441025,
+0xaf820220, 0xaf830200, 0x8f8400f0, 0x276217f8,
+0x14820002, 0x24850008, 0x27651000, 0x8f8200f4,
+0x10a20007, 0x3c038000, 0x34630040, 0x3c020001,
+0x24425cd0, 0xac820000, 0xac830004, 0xaf8500f0,
+0x8f830054, 0x8004912, 0x24020006, 0x8f830054,
+0x3c020001, 0x8c425e04, 0x2463fff6, 0x431023,
+0x2c42000a, 0x14400022, 0x24020007, 0x800491f,
+0x0, 0x8f8200e0, 0xaf8200e4, 0x8f8200e0,
+0xaf8200e8, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820220, 0x2403fff7, 0x431024, 0xaf820220,
+0x8f820044, 0x34428080, 0xaf820044, 0x8f830054,
+0x24020008, 0x3c010001, 0xac225d44, 0x3c010001,
+0x8004921, 0xac235e04, 0x8f830054, 0x3c020001,
+0x8c425e04, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400003, 0x24020009, 0x3c010001, 0xac225d44,
+0x3e00008, 0x0, 0x0, 0x27bdffd8,
0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
0xafb10014, 0xc08821, 0xafb00010, 0x8021,
-0xafbf0020, 0xa6200000, 0xc004cab, 0x24040001,
+0xafbf0020, 0xa6200000, 0xc004d23, 0x24040001,
0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004cab, 0x2021, 0xc004cab, 0x24040001,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
+0xc004d23, 0x2021, 0xc004d23, 0x24040001,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
0x24100010, 0x2501024, 0x10400002, 0x2021,
-0x24040001, 0xc004cab, 0x108042, 0x1600fffa,
+0x24040001, 0xc004d23, 0x108042, 0x1600fffa,
0x2501024, 0x24100010, 0x2701024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fffa, 0x2701024, 0xc004cd1, 0x34108000,
-0xc004cd1, 0x0, 0xc004c8b, 0x0,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fffa, 0x2701024, 0xc004d49, 0x34108000,
+0xc004d49, 0x0, 0xc004d03, 0x0,
0x50400005, 0x108042, 0x96220000, 0x501025,
0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004cd1, 0x0, 0x8fbf0020, 0x8fb3001c,
+0xc004d49, 0x0, 0x8fbf0020, 0x8fb3001c,
0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
-0xafb00010, 0x8021, 0xafbf0020, 0xc004cab,
+0xafb00010, 0x8021, 0xafbf0020, 0xc004d23,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004cab, 0x2021, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0xc004cab,
+0x0, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0xc004d23,
0x24040001, 0x24100010, 0x2301024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
-0x108042, 0x1600fffa, 0x2501024, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0x34108000,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
+0x108042, 0x1600fffa, 0x2501024, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0x34108000,
0x96620000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004cab, 0x108042, 0x1600fff8,
-0x0, 0xc004cd1, 0x0, 0x8fbf0020,
+0x24040001, 0xc004d23, 0x108042, 0x1600fff8,
+0x0, 0xc004d49, 0x0, 0x8fbf0020,
0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c6354b0,
-0x3c020001, 0x8c4254f4, 0x27bdffd8, 0xafbf0020,
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d60,
+0x3c020001, 0x8c425da8, 0x27bdffd8, 0xafbf0020,
0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
-0xac2354f4, 0x2463ffff, 0x2c620013, 0x10400349,
-0x31080, 0x3c010001, 0x220821, 0x8c225310,
-0x400008, 0x0, 0xc004cd1, 0x8021,
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004cab,
+0xac235da8, 0x2463ffff, 0x2c620013, 0x10400349,
+0x31080, 0x3c010001, 0x220821, 0x8c225b80,
+0x400008, 0x0, 0xc004d49, 0x8021,
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004d23,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004cab, 0x2021, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0xc004cab,
+0x0, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0xc004d23,
0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004cab,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d23,
0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fff8, 0x0, 0xc004cd1, 0x0,
-0x8004c84, 0x24020002, 0x27b10010, 0xa7a00010,
-0x8021, 0xc004cab, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004cab,
-0x2021, 0xc004cab, 0x24040001, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0x24100010,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fff8, 0x0, 0xc004d49, 0x0,
+0x8004cfc, 0x24020002, 0x27b10010, 0xa7a00010,
+0x8021, 0xc004d23, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004d23,
+0x2021, 0xc004d23, 0x24040001, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0x24100010,
0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004cab, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004cd1, 0x34108000,
-0xc004cd1, 0x0, 0xc004c8b, 0x0,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc004d23, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc004d49, 0x34108000,
+0xc004d49, 0x0, 0xc004d03, 0x0,
0x50400005, 0x108042, 0x96220000, 0x501025,
0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004cd1, 0x0, 0x97a20010, 0x30428000,
-0x144002dc, 0x24020003, 0x8004c84, 0x0,
+0xc004d49, 0x0, 0x97a20010, 0x30428000,
+0x144002dc, 0x24020003, 0x8004cfc, 0x0,
0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0xc004cab, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0xc004cab, 0x24040001, 0xc004cab,
+0xc004d23, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0xc004d23, 0x24040001, 0xc004d23,
0x2021, 0x34108000, 0x96220000, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
-0x108042, 0x1600fff8, 0x0, 0xc004cd1,
-0x0, 0x8f830054, 0x8004c76, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c42554c, 0x2463ff9c,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
+0x108042, 0x1600fff8, 0x0, 0xc004d49,
+0x0, 0x8f830054, 0x8004cee, 0x24020004,
+0x8f830054, 0x3c020001, 0x8c425e14, 0x2463ff9c,
0x431023, 0x2c420064, 0x1440029e, 0x24020002,
-0x3c030001, 0x8c635550, 0x10620297, 0x2c620003,
+0x3c030001, 0x8c635e18, 0x10620297, 0x2c620003,
0x14400296, 0x24020011, 0x24020003, 0x10620005,
-0x24020004, 0x10620291, 0x2402000f, 0x8004c84,
-0x24020011, 0x8004c84, 0x24020005, 0x24020014,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004cab,
+0x24020004, 0x10620291, 0x2402000f, 0x8004cfc,
+0x24020011, 0x8004cfc, 0x24020005, 0x24020014,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d23,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004cab, 0x2021, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0xc004cab,
+0x0, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0xc004d23,
0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
-0x108042, 0x1600fffa, 0x32020012, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0x34108000,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
+0x108042, 0x1600fffa, 0x32020012, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0x34108000,
0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004cab, 0x108042, 0x1600fff8,
-0x0, 0xc004cd1, 0x0, 0x8f830054,
-0x8004c76, 0x24020006, 0x8f830054, 0x3c020001,
-0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400250, 0x24020007, 0x8004c84, 0x0,
+0x24040001, 0xc004d23, 0x108042, 0x1600fff8,
+0x0, 0xc004d49, 0x0, 0x8f830054,
+0x8004cee, 0x24020006, 0x8f830054, 0x3c020001,
+0x8c425e14, 0x2463ff9c, 0x431023, 0x2c420064,
+0x14400250, 0x24020007, 0x8004cfc, 0x0,
0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020013, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020013,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020013,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fff8, 0x0, 0xc004cd1, 0x0,
-0x8f830054, 0x8004c76, 0x24020008, 0x8f830054,
-0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440020f, 0x24020009, 0x8004c84,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fff8, 0x0, 0xc004d49, 0x0,
+0x8f830054, 0x8004cee, 0x24020008, 0x8f830054,
+0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440020f, 0x24020009, 0x8004cfc,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x24040001,
-0xc004cab, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x24040001,
+0xc004d23, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020018,
-0xc004cd1, 0x34108000, 0xc004cd1, 0x0,
-0xc004c8b, 0x0, 0x50400005, 0x108042,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d49, 0x34108000, 0xc004d49, 0x0,
+0xc004d03, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004cd1, 0x8021,
+0x1600fff7, 0x0, 0xc004d49, 0x8021,
0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020018,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fff8, 0x0, 0xc004cd1, 0x0,
-0x8f830054, 0x8004c76, 0x2402000a, 0x8f830054,
-0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440019b, 0x2402000b, 0x8004c84,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fff8, 0x0, 0xc004d49, 0x0,
+0x8f830054, 0x8004cee, 0x2402000a, 0x8f830054,
+0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440019b, 0x2402000b, 0x8004cfc,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x24040001,
-0xc004cab, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x24040001,
+0xc004d23, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020017,
-0xc004cd1, 0x34108000, 0xc004cd1, 0x0,
-0xc004c8b, 0x0, 0x50400005, 0x108042,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020017,
+0xc004d49, 0x34108000, 0xc004d49, 0x0,
+0xc004d03, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004cd1, 0x8021,
+0x1600fff7, 0x0, 0xc004d49, 0x8021,
0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020017,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020017,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fff8, 0x0, 0xc004cd1, 0x0,
-0x8f830054, 0x8004c76, 0x2402000c, 0x8f830054,
-0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x14400127, 0x24020012, 0x8004c84,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fff8, 0x0, 0xc004d49, 0x0,
+0x8f830054, 0x8004cee, 0x2402000c, 0x8f830054,
+0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023,
+0x2c420064, 0x14400127, 0x24020012, 0x8004cfc,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x24040001,
-0xc004cab, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x24040001,
+0xc004d23, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020014,
-0xc004cd1, 0x34108000, 0xc004cd1, 0x0,
-0xc004c8b, 0x0, 0x50400005, 0x108042,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020014,
+0xc004d49, 0x34108000, 0xc004d49, 0x0,
+0xc004d03, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004cd1, 0x8021,
+0x1600fff7, 0x0, 0xc004d49, 0x8021,
0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020014,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020014,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fff8, 0x0, 0xc004cd1, 0x0,
-0x8f830054, 0x8004c76, 0x24020013, 0x8f830054,
-0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x144000b3, 0x2402000d, 0x8004c84,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fff8, 0x0, 0xc004d49, 0x0,
+0x8f830054, 0x8004cee, 0x24020013, 0x8f830054,
+0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023,
+0x2c420064, 0x144000b3, 0x2402000d, 0x8004cfc,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x24040001,
-0xc004cab, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x24040001,
+0xc004d23, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020018,
-0xc004cd1, 0x34108000, 0xc004cd1, 0x0,
-0xc004c8b, 0x0, 0x50400005, 0x108042,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d49, 0x34108000, 0xc004d49, 0x0,
+0xc004d03, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004cd1, 0x8021,
+0x1600fff7, 0x0, 0xc004d49, 0x8021,
0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
-0xc004cab, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
-0xc004cab, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
+0xc004d23, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
+0xc004d23, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004cab, 0x108042, 0x1600fffa, 0x32020018,
-0xc004cab, 0x24040001, 0xc004cab, 0x2021,
+0xc004d23, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d23, 0x24040001, 0xc004d23, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
-0x1600fff8, 0x0, 0xc004cd1, 0x0,
-0x8f830054, 0x8004c76, 0x2402000e, 0x24020840,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004cab,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fff8, 0x0, 0xc004d49, 0x0,
+0x8f830054, 0x8004cee, 0x2402000e, 0x24020840,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d23,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004cab, 0x2021, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0xc004cab,
+0x0, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0xc004d23,
0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004cab, 0x108042,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
-0x10400002, 0x2021, 0x24040001, 0xc004cab,
-0x108042, 0x1600fffa, 0x32020013, 0xc004cab,
-0x24040001, 0xc004cab, 0x2021, 0x34108000,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
+0x108042, 0x1600fffa, 0x32020013, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0x34108000,
0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004cab, 0x108042, 0x1600fff8,
-0x0, 0xc004cd1, 0x0, 0x8f830054,
-0x24020010, 0x3c010001, 0xac2254b0, 0x3c010001,
-0x8004c86, 0xac23554c, 0x8f830054, 0x3c020001,
-0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064,
+0x24040001, 0xc004d23, 0x108042, 0x1600fff8,
+0x0, 0xc004d49, 0x0, 0x8f830054,
+0x24020010, 0x3c010001, 0xac225d60, 0x3c010001,
+0x8004cfe, 0xac235e14, 0x8f830054, 0x3c020001,
+0x8c425e14, 0x2463ff9c, 0x431023, 0x2c420064,
0x14400004, 0x0, 0x24020011, 0x3c010001,
-0xac2254b0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+0xac225d60, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
-0x8f840054, 0x8f820054, 0xa32824, 0x8004c97,
+0x8f840054, 0x8f820054, 0xa32824, 0x8004d0f,
0x24840001, 0x8f820054, 0x821023, 0x2c420002,
0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x8004ca5, 0x24630001, 0x8f820054,
+0x8f820054, 0x8004d1d, 0x24630001, 0x8f820054,
0x621023, 0x2c420002, 0x1440fffc, 0x0,
0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
0x3442ffff, 0x42480, 0x621824, 0x3c020002,
0x822025, 0x641825, 0xaf830044, 0x8f820044,
-0x3c030001, 0x431025, 0xaf820044, 0x8f830054,
-0x8f820054, 0x8004cbd, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004ccb,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+0x8f830054, 0x8f820054, 0x8004d36, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820044, 0x3c030001, 0x431025,
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d43,
0x24630001, 0x8f820054, 0x621023, 0x2c420002,
0x1440fffc, 0x0, 0x3e00008, 0x0,
0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004cdf,
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d57,
0x24630001, 0x8f820054, 0x621023, 0x2c420002,
0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x8004ced, 0x24630001, 0x8f820054,
+0x8f820054, 0x8004d65, 0x24630001, 0x8f820054,
0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0x0, 0x0, 0x27bdffe8,
+0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+0x809821, 0xafb5002c, 0xa0a821, 0xafb20020,
+0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028,
+0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d23,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d23, 0x108042, 0x12000075,
+0x0, 0x8004da1, 0x0, 0x3274ffff,
+0x27b10010, 0xa7a00010, 0x8021, 0xc004d23,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0xc004d23, 0x24040001, 0xc004d23,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2901024,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
+0x108042, 0x1600fffa, 0x2901024, 0xc004d49,
+0x34108000, 0xc004d49, 0x0, 0xc004d03,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004d49, 0x0, 0x32a5ffff,
+0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
+0x8004dec, 0x521025, 0x14a20006, 0x3271ffff,
+0x97a20010, 0x121827, 0x431024, 0xa7a20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d23,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0xc004d23,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d23, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d23,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d23,
+0x24040001, 0xc004d23, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d23, 0x108042, 0x1600fff8,
+0x0, 0xc004d49, 0x0, 0x8fbf0030,
+0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
+0x0, 0x0, 0x0, 0x27bdffe8,
0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac,
0x24020008, 0x1462022c, 0x803021, 0x3c020001,
-0x8c425538, 0x14400033, 0x0, 0x8f850224,
+0x8c425df8, 0x14400033, 0x0, 0x8f850224,
0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001,
0x621825, 0x1460000d, 0x38a30030, 0x2c630001,
0x38a20400, 0x2c420001, 0x621825, 0x14600007,
0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001,
0x621825, 0x10600005, 0x0, 0xc00429b,
-0x0, 0x8004d2d, 0x2402000e, 0xc0043dd,
-0x0, 0x3c050001, 0x8ca55488, 0xc0050b3,
-0x2021, 0x3c030001, 0x8c635488, 0x24020004,
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c425484,
-0x8004d29, 0x2403fff7, 0x3c020001, 0x8c425484,
-0x431024, 0x3c010001, 0xac225484, 0x2402000e,
-0x3c010001, 0xc00429b, 0xac227560, 0x8004f27,
+0x0, 0x8004e65, 0x2402000e, 0xc0043dd,
+0x0, 0x3c050001, 0x8ca55d28, 0xc005276,
+0x2021, 0x3c030001, 0x8c635d28, 0x24020004,
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c425d24,
+0x8004e61, 0x2403fff7, 0x3c020001, 0x8c425d24,
+0x431024, 0x3c010001, 0xac225d24, 0x2402000e,
+0x3c010001, 0xc00429b, 0xac227e30, 0x800505f,
0x0, 0x8f820220, 0x3c030400, 0x431024,
0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001,
-0x8c42756c, 0xa32024, 0x431024, 0x1482000c,
-0x0, 0x3c020001, 0x8c427570, 0x24420001,
-0x3c010001, 0xac227570, 0x2c420002, 0x14400008,
-0x24020001, 0x3c010001, 0x8004d4d, 0xac227590,
-0x3c010001, 0xac207570, 0x3c010001, 0xac207590,
-0x3c020001, 0x8c427590, 0x10400006, 0x30a20040,
-0x10400004, 0x24020001, 0x3c010001, 0x8004d58,
-0xac227594, 0x3c010001, 0xac207594, 0x3c010001,
-0xac25756c, 0x3c010001, 0x8004d68, 0xac2075a0,
-0x24020001, 0x3c010001, 0xac2275a0, 0x3c010001,
-0xac207590, 0x3c010001, 0xac207570, 0x3c010001,
-0xac207594, 0x3c010001, 0xac20756c, 0x3c030001,
-0x8c637560, 0x3c020001, 0x8c427564, 0x10620003,
-0x3c020200, 0x3c010001, 0xac237564, 0xc21024,
+0x8c427e3c, 0xa32024, 0x431024, 0x1482000c,
+0x0, 0x3c020001, 0x8c427e40, 0x24420001,
+0x3c010001, 0xac227e40, 0x2c420002, 0x14400008,
+0x24020001, 0x3c010001, 0x8004e85, 0xac227e60,
+0x3c010001, 0xac207e40, 0x3c010001, 0xac207e60,
+0x3c020001, 0x8c427e60, 0x10400006, 0x30a20040,
+0x10400004, 0x24020001, 0x3c010001, 0x8004e90,
+0xac227e64, 0x3c010001, 0xac207e64, 0x3c010001,
+0xac257e3c, 0x3c010001, 0x8004ea0, 0xac207e70,
+0x24020001, 0x3c010001, 0xac227e70, 0x3c010001,
+0xac207e60, 0x3c010001, 0xac207e40, 0x3c010001,
+0xac207e64, 0x3c010001, 0xac207e3c, 0x3c030001,
+0x8c637e30, 0x3c020001, 0x8c427e34, 0x10620003,
+0x3c020200, 0x3c010001, 0xac237e34, 0xc21024,
0x10400007, 0x2463ffff, 0x8f820220, 0x24030001,
-0x3c010001, 0xac23548c, 0x8004f25, 0x3c03f700,
+0x3c010001, 0xac235d2c, 0x800505d, 0x3c03f700,
0x2c62000e, 0x104001a8, 0x31080, 0x3c010001,
-0x220821, 0x8c225360, 0x400008, 0x0,
-0x3c010001, 0xac207590, 0x3c010001, 0xac207570,
-0x3c010001, 0xac20756c, 0x3c010001, 0xac207594,
-0x3c010001, 0xac207588, 0x3c010001, 0xac207580,
-0xc0047cd, 0xaf800224, 0x24020002, 0x3c010001,
-0xac227560, 0x3c020001, 0x8c4275a0, 0x14400056,
+0x220821, 0x8c225bd0, 0x400008, 0x0,
+0x3c010001, 0xac207e60, 0x3c010001, 0xac207e40,
+0x3c010001, 0xac207e3c, 0x3c010001, 0xac207e64,
+0x3c010001, 0xac207e58, 0x3c010001, 0xac207e50,
+0xc004844, 0xaf800224, 0x24020002, 0x3c010001,
+0xac227e30, 0x3c020001, 0x8c427e70, 0x14400056,
0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200,
0x2403fffd, 0x431024, 0xaf820200, 0x3c010001,
-0xac2075b0, 0x8f830054, 0x3c020001, 0x8c427588,
-0x24040001, 0x3c010001, 0xac24759c, 0x24420001,
-0x3c010001, 0xac227588, 0x2c420004, 0x3c010001,
-0xac237584, 0x14400006, 0x24020003, 0x3c010001,
-0xac24548c, 0x3c010001, 0x8004f23, 0xac207588,
-0x3c010001, 0x8004f23, 0xac227560, 0x8f830054,
-0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023,
+0xac207e80, 0x8f830054, 0x3c020001, 0x8c427e58,
+0x24040001, 0x3c010001, 0xac247e6c, 0x24420001,
+0x3c010001, 0xac227e58, 0x2c420004, 0x3c010001,
+0xac237e54, 0x14400006, 0x24020003, 0x3c010001,
+0xac245d2c, 0x3c010001, 0x800505b, 0xac207e58,
+0x3c010001, 0x800505b, 0xac227e30, 0x8f830054,
+0x3c020001, 0x8c427e54, 0x2463d8f0, 0x431023,
0x2c422710, 0x14400003, 0x24020004, 0x3c010001,
-0xac227560, 0x3c020001, 0x8c4275a0, 0x14400026,
+0xac227e30, 0x3c020001, 0x8c427e70, 0x14400026,
0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
-0x8004f23, 0xaee20000, 0x3c040001, 0x8c84553c,
-0x3c010001, 0xc004f2a, 0xac207578, 0x3c020001,
-0x8c4275ac, 0xaf820204, 0x3c020001, 0x8c4275a0,
+0x800505b, 0xaee20000, 0x3c040001, 0x8c845dfc,
+0x3c010001, 0xc005062, 0xac207e48, 0x3c020001,
+0x8c427e7c, 0xaf820204, 0x3c020001, 0x8c427e70,
0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff,
0x431024, 0xaee20000, 0x8f820204, 0x30420030,
-0x1440013c, 0x24020002, 0x3c030001, 0x8c6375ac,
-0x24020005, 0x3c010001, 0xac227560, 0x3c010001,
-0x8004f23, 0xac2375b0, 0x3c020001, 0x8c4275a0,
-0x10400010, 0x3c03fdff, 0x3c020001, 0x8c42550c,
-0x24420001, 0x3c010001, 0xac22550c, 0x2c420002,
-0x14400131, 0x24020001, 0x3c010001, 0xac225514,
-0x3c010001, 0xac20550c, 0x3c010001, 0x8004f23,
-0xac22548c, 0x8ee20000, 0x3463ffff, 0x431024,
-0xaee20000, 0x3c020001, 0x8c427590, 0x10400122,
-0x0, 0x3c020001, 0x8c42756c, 0x1040011e,
-0x0, 0x3c010001, 0xac227598, 0x24020003,
-0x3c010001, 0xac227570, 0x8004ec4, 0x24020006,
-0x3c010001, 0xac207578, 0x8f820204, 0x34420040,
-0xaf820204, 0x3c020001, 0x8c4275b0, 0x24030007,
-0x3c010001, 0xac237560, 0x34420040, 0x3c010001,
-0xac2275b0, 0x3c020001, 0x8c427590, 0x10400005,
-0x0, 0x3c020001, 0x8c42756c, 0x104000f9,
-0x24020002, 0x3c050001, 0x24a57570, 0x8ca20000,
+0x1440013c, 0x24020002, 0x3c030001, 0x8c637e7c,
+0x24020005, 0x3c010001, 0xac227e30, 0x3c010001,
+0x800505b, 0xac237e80, 0x3c020001, 0x8c427e70,
+0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425dcc,
+0x24420001, 0x3c010001, 0xac225dcc, 0x2c420002,
+0x14400131, 0x24020001, 0x3c010001, 0xac225dd4,
+0x3c010001, 0xac205dcc, 0x3c010001, 0x800505b,
+0xac225d2c, 0x8ee20000, 0x3463ffff, 0x431024,
+0xaee20000, 0x3c020001, 0x8c427e60, 0x10400122,
+0x0, 0x3c020001, 0x8c427e3c, 0x1040011e,
+0x0, 0x3c010001, 0xac227e68, 0x24020003,
+0x3c010001, 0xac227e40, 0x8004ffc, 0x24020006,
+0x3c010001, 0xac207e48, 0x8f820204, 0x34420040,
+0xaf820204, 0x3c020001, 0x8c427e80, 0x24030007,
+0x3c010001, 0xac237e30, 0x34420040, 0x3c010001,
+0xac227e80, 0x3c020001, 0x8c427e60, 0x10400005,
+0x0, 0x3c020001, 0x8c427e3c, 0x104000f9,
+0x24020002, 0x3c050001, 0x24a57e40, 0x8ca20000,
0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001,
-0x8c427594, 0x104000f8, 0x2404ffbf, 0x3c020001,
-0x8c42756c, 0x3c030001, 0x8c637598, 0x441024,
+0x8c427e64, 0x104000f8, 0x2404ffbf, 0x3c020001,
+0x8c427e3c, 0x3c030001, 0x8c637e68, 0x441024,
0x641824, 0x10430004, 0x24020001, 0x3c010001,
-0x8004f23, 0xac227560, 0x24020003, 0xaca20000,
-0x24020008, 0x3c010001, 0xac227560, 0x3c020001,
-0x8c42759c, 0x1040000c, 0x24020001, 0x3c040001,
-0xc004f37, 0x8c84756c, 0x3c020001, 0x8c4275b8,
-0x14400005, 0x24020001, 0x3c020001, 0x8c4275b4,
-0x10400006, 0x24020001, 0x3c010001, 0xac22548c,
-0x3c010001, 0x8004f23, 0xac207588, 0x3c020001,
-0x8c427580, 0x3c030001, 0x8c63756c, 0x2c420001,
-0x210c0, 0x30630008, 0x3c010001, 0xac227580,
-0x3c010001, 0xac23757c, 0x8f830054, 0x24020009,
-0x3c010001, 0xac227560, 0x3c010001, 0x8004f23,
-0xac237584, 0x8f830054, 0x3c020001, 0x8c427584,
+0x800505b, 0xac227e30, 0x24020003, 0xaca20000,
+0x24020008, 0x3c010001, 0xac227e30, 0x3c020001,
+0x8c427e6c, 0x1040000c, 0x24020001, 0x3c040001,
+0xc00506f, 0x8c847e3c, 0x3c020001, 0x8c427e88,
+0x14400005, 0x24020001, 0x3c020001, 0x8c427e84,
+0x10400006, 0x24020001, 0x3c010001, 0xac225d2c,
+0x3c010001, 0x800505b, 0xac207e58, 0x3c020001,
+0x8c427e50, 0x3c030001, 0x8c637e3c, 0x2c420001,
+0x210c0, 0x30630008, 0x3c010001, 0xac227e50,
+0x3c010001, 0xac237e4c, 0x8f830054, 0x24020009,
+0x3c010001, 0xac227e30, 0x3c010001, 0x800505b,
+0xac237e54, 0x8f830054, 0x3c020001, 0x8c427e54,
0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8,
-0x0, 0x3c020001, 0x8c427590, 0x10400005,
-0x0, 0x3c020001, 0x8c42756c, 0x104000a9,
-0x24020002, 0x3c030001, 0x24637570, 0x8c620000,
+0x0, 0x3c020001, 0x8c427e60, 0x10400005,
+0x0, 0x3c020001, 0x8c427e3c, 0x104000a9,
+0x24020002, 0x3c030001, 0x24637e40, 0x8c620000,
0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001,
-0x8c42759c, 0x1040000e, 0x0, 0x3c020001,
-0x8c42756c, 0x3c010001, 0xac20759c, 0x30420080,
+0x8c427e6c, 0x1040000e, 0x0, 0x3c020001,
+0x8c427e3c, 0x3c010001, 0xac207e6c, 0x30420080,
0x1040002f, 0x2402000c, 0x8f820204, 0x30420080,
-0x1440000c, 0x24020003, 0x8004eb1, 0x2402000c,
-0x3c020001, 0x8c42756c, 0x30420080, 0x14400005,
+0x1440000c, 0x24020003, 0x8004fe9, 0x2402000c,
+0x3c020001, 0x8c427e3c, 0x30420080, 0x14400005,
0x24020003, 0x8f820204, 0x30420080, 0x1040001f,
0x24020003, 0xac620000, 0x2402000a, 0x3c010001,
-0xac227560, 0x3c040001, 0x248475a8, 0x8c820000,
-0x3c030001, 0x8c637580, 0x431025, 0xaf820204,
-0x8c830000, 0x3c040001, 0x8c847580, 0x2402000b,
-0x3c010001, 0xac227560, 0x641825, 0x3c010001,
-0xac2375b0, 0x3c050001, 0x24a57570, 0x8ca20000,
+0xac227e30, 0x3c040001, 0x24847e78, 0x8c820000,
+0x3c030001, 0x8c637e50, 0x431025, 0xaf820204,
+0x8c830000, 0x3c040001, 0x8c847e50, 0x2402000b,
+0x3c010001, 0xac227e30, 0x641825, 0x3c010001,
+0xac237e80, 0x3c050001, 0x24a57e40, 0x8ca20000,
0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001,
-0x8c4275a0, 0x10400005, 0x0, 0x2402000c,
-0x3c010001, 0x8004f23, 0xac227560, 0x3c020001,
-0x8c427590, 0x1040006c, 0x0, 0x3c040001,
-0x8c84756c, 0x1080005e, 0x30820008, 0x3c030001,
-0x8c63757c, 0x10620064, 0x24020003, 0x3c010001,
-0xac247598, 0xaca20000, 0x24020006, 0x3c010001,
-0x8004f23, 0xac227560, 0x8f820200, 0x34420002,
+0x8c427e70, 0x10400005, 0x0, 0x2402000c,
+0x3c010001, 0x800505b, 0xac227e30, 0x3c020001,
+0x8c427e60, 0x1040006c, 0x0, 0x3c040001,
+0x8c847e3c, 0x1080005e, 0x30820008, 0x3c030001,
+0x8c637e4c, 0x10620064, 0x24020003, 0x3c010001,
+0xac247e68, 0xaca20000, 0x24020006, 0x3c010001,
+0x800505b, 0xac227e30, 0x8f820200, 0x34420002,
0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001,
-0xac227560, 0x3c010001, 0xac237584, 0x8f830054,
-0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023,
+0xac227e30, 0x3c010001, 0xac237e54, 0x8f830054,
+0x3c020001, 0x8c427e54, 0x2463d8f0, 0x431023,
0x2c422710, 0x1440003a, 0x0, 0x3c020001,
-0x8c4275a0, 0x10400029, 0x2402000e, 0x3c030001,
-0x8c6375b4, 0x3c010001, 0x14600015, 0xac227560,
-0xc0043dd, 0x0, 0x3c050001, 0x8ca55488,
-0xc0050b3, 0x2021, 0x3c030001, 0x8c635488,
+0x8c427e70, 0x10400029, 0x2402000e, 0x3c030001,
+0x8c637e84, 0x3c010001, 0x14600015, 0xac227e30,
+0xc0043dd, 0x0, 0x3c050001, 0x8ca55d28,
+0xc005276, 0x2021, 0x3c030001, 0x8c635d28,
0x24020004, 0x14620005, 0x2403fffb, 0x3c020001,
-0x8c425484, 0x8004ef2, 0x2403fff7, 0x3c020001,
-0x8c425484, 0x431024, 0x3c010001, 0xac225484,
+0x8c425d24, 0x800502a, 0x2403fff7, 0x3c020001,
+0x8c425d24, 0x431024, 0x3c010001, 0xac225d24,
0x8ee20000, 0x3c030200, 0x431025, 0xaee20000,
-0x8f820224, 0x3c010001, 0xac2275bc, 0x8f820220,
+0x8f820224, 0x3c010001, 0xac227e8c, 0x8f820220,
0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
-0x34420002, 0x8004f23, 0xaf820220, 0x3c020001,
-0x8c427590, 0x10400005, 0x0, 0x3c020001,
-0x8c42756c, 0x1040000f, 0x24020002, 0x3c020001,
-0x8c427570, 0x2c424e21, 0x1040000a, 0x24020002,
-0x3c020001, 0x8c427590, 0x1040000f, 0x0,
-0x3c020001, 0x8c42756c, 0x1440000b, 0x0,
-0x24020002, 0x3c010001, 0x8004f23, 0xac227560,
-0x3c020001, 0x8c427590, 0x10400003, 0x0,
+0x34420002, 0x800505b, 0xaf820220, 0x3c020001,
+0x8c427e60, 0x10400005, 0x0, 0x3c020001,
+0x8c427e3c, 0x1040000f, 0x24020002, 0x3c020001,
+0x8c427e40, 0x2c424e21, 0x1040000a, 0x24020002,
+0x3c020001, 0x8c427e60, 0x1040000f, 0x0,
+0x3c020001, 0x8c427e3c, 0x1440000b, 0x0,
+0x24020002, 0x3c010001, 0x800505b, 0xac227e30,
+0x3c020001, 0x8c427e60, 0x10400003, 0x0,
0xc00429b, 0x0, 0x8f820220, 0x3c03f700,
0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008,
-0x27bd0018, 0x3c030001, 0x246375b8, 0x8c620000,
-0x10400005, 0x34422000, 0x3c010001, 0xac2275ac,
-0x8004f35, 0xac600000, 0x3c010001, 0xac2475ac,
+0x27bd0018, 0x3c030001, 0x24637e88, 0x8c620000,
+0x10400005, 0x34422000, 0x3c010001, 0xac227e7c,
+0x800506d, 0xac600000, 0x3c010001, 0xac247e7c,
0x3e00008, 0x0, 0x27bdffe0, 0x30820030,
-0xafbf0018, 0x3c010001, 0xac2275b4, 0x14400067,
+0xafbf0018, 0x3c010001, 0xac227e84, 0x14400067,
0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061,
0x24020030, 0x30822000, 0x1040005d, 0x30838000,
0x31a02, 0x30820001, 0x21200, 0x3c040001,
-0x8c84553c, 0x621825, 0x331c2, 0x3c030001,
-0x24635518, 0x30828000, 0x21202, 0x30840001,
+0x8c845dfc, 0x621825, 0x331c2, 0x3c030001,
+0x24635dd8, 0x30828000, 0x21202, 0x30840001,
0x42200, 0x441025, 0x239c2, 0x61080,
0x431021, 0x471021, 0x90430000, 0x24020001,
0x10620025, 0x0, 0x10600007, 0x24020002,
0x10620013, 0x24020003, 0x1062002c, 0x3c05000f,
-0x8004f99, 0x0, 0x8f820200, 0x2403feff,
+0x80050d1, 0x0, 0x8f820200, 0x2403feff,
0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe,
0x3463ffff, 0x431024, 0xaf820220, 0x3c010001,
-0xac2075d4, 0x3c010001, 0x8004fa4, 0xac2075dc,
+0xac207ea4, 0x3c010001, 0x80050dc, 0xac207eac,
0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
-0x24020100, 0x3c010001, 0xac2275d4, 0x3c010001,
-0x8004fa4, 0xac2075dc, 0x8f820200, 0x2403feff,
+0x24020100, 0x3c010001, 0xac227ea4, 0x3c010001,
+0x80050dc, 0xac207eac, 0x8f820200, 0x2403feff,
0x431024, 0xaf820200, 0x8f820220, 0x3c030001,
-0x431025, 0xaf820220, 0x3c010001, 0xac2075d4,
-0x3c010001, 0x8004fa4, 0xac2375dc, 0x8f820200,
+0x431025, 0xaf820220, 0x3c010001, 0xac207ea4,
+0x3c010001, 0x80050dc, 0xac237eac, 0x8f820200,
0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
0x431025, 0xaf820220, 0x24020100, 0x3c010001,
-0xac2275d4, 0x3c010001, 0x8004fa4, 0xac2375dc,
-0x34a5ffff, 0x3c040001, 0x24845398, 0xafa30010,
-0xc002403, 0xafa00014, 0x8004fa4, 0x0,
-0x24020030, 0x3c010001, 0xac2275b8, 0x8fbf0018,
+0xac227ea4, 0x3c010001, 0x80050dc, 0xac237eac,
+0x34a5ffff, 0x3c040001, 0x24845c08, 0xafa30010,
+0xc002403, 0xafa00014, 0x80050dc, 0x0,
+0x24020030, 0x3c010001, 0xac227e88, 0x8fbf0018,
0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8,
-0xafb10024, 0x808821, 0xafb3002c, 0xa09821,
-0xafb00020, 0xc08021, 0x3c040001, 0x248453b0,
-0x3c050009, 0x3c020001, 0x8c425488, 0x34a59001,
-0x2203021, 0x2603821, 0xafbf0030, 0xafb20028,
+0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+0xafb00020, 0xc08021, 0x3c040001, 0x24845c20,
+0x3c050009, 0x3c020001, 0x8c425d28, 0x34a59001,
+0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010,
-0x24020002, 0x126200ed, 0x2e620003, 0x10400005,
-0x24020001, 0x1262000a, 0x3c02fffb, 0x80050ac,
-0x0, 0x24020004, 0x1262006d, 0x24020008,
-0x1262006c, 0x3c02ffec, 0x80050ac, 0x0,
-0x3442ffff, 0x2028024, 0x119140, 0x3c010001,
-0x320821, 0xac3075cc, 0x3c024000, 0x2021024,
-0x10400046, 0x1023c2, 0x30840030, 0x101382,
-0x3042000c, 0x3c030001, 0x246354b4, 0x431021,
-0x823821, 0x3c020020, 0x2021024, 0x10400006,
-0x24020100, 0x3c010001, 0x320821, 0xac2275d0,
-0x8004feb, 0x3c020080, 0x3c010001, 0x320821,
-0xac2075d0, 0x3c020080, 0x2021024, 0x10400006,
-0x111940, 0x3c020001, 0x3c010001, 0x230821,
-0x8004ff7, 0xac2275d8, 0x111140, 0x3c010001,
-0x220821, 0xac2075d8, 0x94e30000, 0x32024000,
-0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018,
-0x24040001, 0x94e20002, 0x24050004, 0x24e60002,
-0x34420001, 0xc0048ee, 0xa4e20002, 0x24040001,
-0x2821, 0xc0048ee, 0x27a60018, 0x3c020001,
-0x8c425488, 0x24110001, 0x3c010001, 0xac315494,
-0x14530004, 0x32028000, 0xc00429b, 0x0,
-0x32028000, 0x10400099, 0x0, 0xc00429b,
-0x0, 0x24020002, 0x3c010001, 0xac31548c,
-0x3c010001, 0x80050ac, 0xac225488, 0x24040001,
-0x24050004, 0x27b0001a, 0xc0048ee, 0x2003021,
-0x24040001, 0x2821, 0xc0048ee, 0x2003021,
-0x3c020001, 0x521021, 0x8c4275c4, 0x3c040001,
-0x8c845488, 0x3c03bfff, 0x3463ffff, 0x3c010001,
-0xac335494, 0x431024, 0x3c010001, 0x320821,
-0x10930078, 0xac2275c4, 0x80050ac, 0x0,
-0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008,
-0x2028025, 0x111140, 0x3c010001, 0x220821,
-0xac3075c8, 0x3c022000, 0x2021024, 0x10400009,
-0x0, 0x3c020001, 0x8c425514, 0x14400005,
-0x24020001, 0x3c010001, 0xac225538, 0x800504d,
-0x3c024000, 0x3c010001, 0xac205538, 0x3c024000,
-0x2021024, 0x1440001c, 0x0, 0x3c020001,
-0x8c425538, 0x10400007, 0x24022020, 0x3c010001,
-0xac22553c, 0x24020001, 0x3c010001, 0x370821,
-0xac2283ac, 0x3c04bfff, 0x111940, 0x3c020001,
-0x431021, 0x8c4275c0, 0x3c050001, 0x8ca55488,
-0x3484ffff, 0x441024, 0x3c010001, 0x230821,
-0xac2275c0, 0x24020001, 0x10a20044, 0x0,
-0x80050aa, 0x0, 0x3c020001, 0x8c425538,
-0x1040001c, 0x24022000, 0x3c010001, 0xac22553c,
-0x3c0300a0, 0x2031024, 0x14430005, 0x111140,
-0x3402a000, 0x3c010001, 0x80050a5, 0xac22553c,
-0x3c030001, 0x621821, 0x8c6375c8, 0x3c020020,
-0x621024, 0x10400004, 0x24022001, 0x3c010001,
-0x80050a5, 0xac22553c, 0x3c020080, 0x621024,
-0x1040001f, 0x3402a001, 0x3c010001, 0x80050a5,
-0xac22553c, 0x3c020020, 0x2021024, 0x10400007,
-0x111940, 0x24020100, 0x3c010001, 0x230821,
-0xac2275d4, 0x8005099, 0x3c020080, 0x111140,
-0x3c010001, 0x220821, 0xac2075d4, 0x3c020080,
-0x2021024, 0x10400006, 0x111940, 0x3c020001,
-0x3c010001, 0x230821, 0x80050a5, 0xac2275dc,
-0x111140, 0x3c010001, 0x220821, 0xac2075dc,
-0x3c030001, 0x8c635488, 0x24020001, 0x10620003,
-0x0, 0xc00429b, 0x0, 0x8fbf0030,
-0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
-0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb40028,
-0x80a021, 0xafb20020, 0x9021, 0xafb30024,
-0x9821, 0xafb1001c, 0x8821, 0x24020002,
-0xafbf002c, 0xafb00018, 0xa7a00012, 0x10a20068,
-0xa7a00010, 0x2ca20003, 0x10400005, 0x24020001,
-0x10a2000a, 0x148140, 0x8005176, 0x2201021,
-0x24020004, 0x10a2005e, 0x24020008, 0x10a2005d,
-0x142940, 0x8005176, 0x2201021, 0x3c030001,
-0x701821, 0x8c6375cc, 0x3c024000, 0x621024,
-0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff,
-0x628824, 0x3c010001, 0x300821, 0xac3175c4,
-0x8005176, 0x2201021, 0x24050001, 0xc0048ac,
-0x27a60010, 0x24040001, 0x24050001, 0xc0048ac,
-0x27a60010, 0x97a20010, 0x30420004, 0x10400034,
-0x3c114000, 0x3c030001, 0x8c635550, 0x24020003,
-0x10620008, 0x2c620004, 0x14400029, 0x3c028000,
-0x24020004, 0x10620014, 0x24040001, 0x8005119,
-0x3c028000, 0x24040001, 0x24050011, 0x27b00012,
-0xc0048ac, 0x2003021, 0x24040001, 0x24050011,
-0xc0048ac, 0x2003021, 0x97a30012, 0x30624000,
-0x10400002, 0x3c130010, 0x3c130008, 0x3c120001,
-0x8005116, 0x30628000, 0x24050014, 0x27b00012,
-0xc0048ac, 0x2003021, 0x24040001, 0x24050014,
-0xc0048ac, 0x2003021, 0x97a30012, 0x30621000,
-0x10400002, 0x3c130010, 0x3c130008, 0x3c120001,
-0x30620800, 0x54400001, 0x3c120002, 0x3c028000,
-0x2221025, 0x2531825, 0x8005123, 0x438825,
-0x3c110001, 0x2308821, 0x8e3175cc, 0x3c027fff,
-0x3442ffff, 0x2228824, 0x141140, 0x3c010001,
-0x220821, 0xac3175c4, 0x8005176, 0x2201021,
-0x142940, 0x3c030001, 0x651821, 0x8c6375c8,
-0x3c024000, 0x621024, 0x14400008, 0x3c027fff,
-0x3442ffff, 0x628824, 0x3c010001, 0x250821,
-0xac3175c0, 0x8005176, 0x2201021, 0x3c020001,
-0x8c425498, 0x10400033, 0x3c11c00c, 0x3c020001,
-0x8c425514, 0x3c04c00c, 0x34842000, 0x3c030001,
-0x8c635538, 0x2102b, 0x21023, 0x441024,
-0x10600003, 0x518825, 0x3c022000, 0x2228825,
-0x3c020001, 0x451021, 0x8c4275d4, 0x10400003,
-0x3c020020, 0x8005153, 0x2228825, 0x3c02ffdf,
+0x24020002, 0x1262007f, 0x2e620003, 0x10400005,
+0x24020001, 0x1262000a, 0x0, 0x800526f,
+0x0, 0x24020004, 0x126200f6, 0x24020008,
+0x126200f5, 0x3c02ffec, 0x800526f, 0x0,
+0x3c020001, 0x8c425d24, 0x30420002, 0x14400004,
+0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+0x3c010001, 0x310821, 0xac307e9c, 0x3c024000,
+0x2021024, 0x1040004a, 0x1023c2, 0x30840030,
+0x101382, 0x3042001c, 0x3c030001, 0x24635d68,
+0x431021, 0x823821, 0x3c020020, 0x2021024,
+0x10400006, 0x24020100, 0x3c010001, 0x310821,
+0xac227ea0, 0x8005128, 0x3c020080, 0x3c010001,
+0x310821, 0xac207ea0, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+0x230821, 0x8005134, 0xac227ea8, 0x121140,
+0x3c010001, 0x220821, 0xac207ea8, 0x94e30000,
+0x32024000, 0x10400003, 0xa7a30018, 0x34624000,
+0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
+0x24e60002, 0x34420001, 0xc004966, 0xa4e20002,
+0x24040001, 0x2821, 0xc004966, 0x27a60018,
+0x3c020001, 0x8c425d28, 0x24110001, 0x3c010001,
+0xac315d34, 0x14530004, 0x32028000, 0xc00429b,
+0x0, 0x32028000, 0x1040011f, 0x0,
+0xc00429b, 0x0, 0x3c030001, 0x8c635e18,
+0x24020005, 0x10620118, 0x24020002, 0x3c010001,
+0xac315d2c, 0x3c010001, 0x800526f, 0xac225d28,
+0x24040001, 0x24050004, 0x27b0001a, 0xc004966,
+0x2003021, 0x24040001, 0x2821, 0xc004966,
+0x2003021, 0x3c020001, 0x511021, 0x8c427e94,
+0x3c040001, 0x8c845d28, 0x3c03bfff, 0x3463ffff,
+0x3c010001, 0xac335d34, 0x431024, 0x3c010001,
+0x310821, 0x109300fa, 0xac227e94, 0x800526f,
+0x0, 0x3c022000, 0x2021024, 0x10400005,
+0x24020001, 0x3c010001, 0xac225df8, 0x8005181,
+0x128940, 0x3c010001, 0xac205df8, 0x128940,
+0x3c010001, 0x310821, 0xac307e98, 0x3c024000,
+0x2021024, 0x14400016, 0x0, 0x3c020001,
+0x8c425df8, 0x10400008, 0x24040004, 0x24050001,
+0xc004d6b, 0x24062000, 0x24020001, 0x3c010001,
+0x370821, 0xac2283ac, 0x3c020001, 0x511021,
+0x8c427e90, 0x3c03bfff, 0x3463ffff, 0x431024,
+0x3c010001, 0x310821, 0x800526d, 0xac227e90,
+0x3c020001, 0x8c425df8, 0x10400028, 0x3c0300a0,
+0x2031024, 0x5443000d, 0x3c020020, 0x3c020001,
+0x8c425dfc, 0x24030100, 0x3c010001, 0x310821,
+0xac237ea4, 0x3c030001, 0x3c010001, 0x310821,
+0xac237eac, 0x80051c4, 0x34420400, 0x2021024,
+0x10400008, 0x24030100, 0x3c020001, 0x8c425dfc,
+0x3c010001, 0x310821, 0xac237ea4, 0x80051c4,
+0x34420800, 0x3c020080, 0x2021024, 0x1040002e,
+0x3c030001, 0x3c020001, 0x8c425dfc, 0x3c010001,
+0x310821, 0xac237eac, 0x34420c00, 0x3c010001,
+0xac225dfc, 0x80051ec, 0x24040001, 0x3c020020,
+0x2021024, 0x10400006, 0x24020100, 0x3c010001,
+0x310821, 0xac227ea4, 0x80051d5, 0x3c020080,
+0x3c010001, 0x310821, 0xac207ea4, 0x3c020080,
+0x2021024, 0x10400007, 0x121940, 0x3c020001,
+0x3c010001, 0x230821, 0xac227eac, 0x80051e3,
+0x24040001, 0x121140, 0x3c010001, 0x220821,
+0xac207eac, 0x24040001, 0x2821, 0x27b0001e,
+0xc004924, 0x2003021, 0x24040001, 0x2821,
+0xc004924, 0x2003021, 0x24040001, 0x24050001,
+0x27b0001c, 0xc004924, 0x2003021, 0x24040001,
+0x24050001, 0xc004924, 0x2003021, 0x800526d,
+0x0, 0x3c02ffec, 0x3442ffff, 0x2028024,
+0x3c020008, 0x2028025, 0x121140, 0x3c010001,
+0x220821, 0xac307e98, 0x3c022000, 0x2021024,
+0x10400009, 0x0, 0x3c020001, 0x8c425dd4,
+0x14400005, 0x24020001, 0x3c010001, 0xac225df8,
+0x800520e, 0x3c024000, 0x3c010001, 0xac205df8,
+0x3c024000, 0x2021024, 0x1440001e, 0x0,
+0x3c020001, 0x8c425df8, 0x3c010001, 0xac205d40,
+0x10400007, 0x24022020, 0x3c010001, 0xac225dfc,
+0x24020001, 0x3c010001, 0x370821, 0xac2283ac,
+0x3c04bfff, 0x121940, 0x3c020001, 0x431021,
+0x8c427e90, 0x3c050001, 0x8ca55d28, 0x3484ffff,
+0x441024, 0x3c010001, 0x230821, 0xac227e90,
+0x24020001, 0x10a20044, 0x0, 0x800526d,
+0x0, 0x3c020001, 0x8c425df8, 0x1040001c,
+0x24022000, 0x3c010001, 0xac225dfc, 0x3c0300a0,
+0x2031024, 0x14430005, 0x121140, 0x3402a000,
+0x3c010001, 0x8005268, 0xac225dfc, 0x3c030001,
+0x621821, 0x8c637e98, 0x3c020020, 0x621024,
+0x10400004, 0x24022001, 0x3c010001, 0x8005268,
+0xac225dfc, 0x3c020080, 0x621024, 0x1040001f,
+0x3402a001, 0x3c010001, 0x8005268, 0xac225dfc,
+0x3c020020, 0x2021024, 0x10400007, 0x121940,
+0x24020100, 0x3c010001, 0x230821, 0xac227ea4,
+0x800525c, 0x3c020080, 0x121140, 0x3c010001,
+0x220821, 0xac207ea4, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+0x230821, 0x8005268, 0xac227eac, 0x121140,
+0x3c010001, 0x220821, 0xac207eac, 0x3c030001,
+0x8c635d28, 0x24020001, 0x10620003, 0x0,
+0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c,
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0038, 0x27bdffc0, 0xafb40038, 0x80a021,
+0xafb20030, 0x9021, 0xafb1002c, 0x8821,
+0x24020002, 0xafbf003c, 0xafb30034, 0xafb00028,
+0xa7a00020, 0xa7a00018, 0xa7a0001a, 0xa7a0001c,
+0x10a20108, 0xa7a0001e, 0x2ca20003, 0x10400005,
+0x24020001, 0x10a2000a, 0x149940, 0x800538f,
+0x2201021, 0x24020004, 0x10a200b2, 0x24020008,
+0x10a200b1, 0x142940, 0x800538f, 0x2201021,
+0x3c030001, 0x731821, 0x8c637e9c, 0x3c024000,
+0x621024, 0x14400009, 0x24040001, 0x3c027fff,
+0x3442ffff, 0x628824, 0x3c010001, 0x330821,
+0xac317e94, 0x800538f, 0x2201021, 0x2821,
+0xc004924, 0x27a60018, 0x24040001, 0x2821,
+0xc004924, 0x27a60018, 0x24040001, 0x24050001,
+0x27b0001a, 0xc004924, 0x2003021, 0x24040001,
+0x24050001, 0xc004924, 0x2003021, 0x24040001,
+0x24050004, 0x27b0001c, 0xc004924, 0x2003021,
+0x24040001, 0x24050004, 0xc004924, 0x2003021,
+0x24040001, 0x24050005, 0x27b0001e, 0xc004924,
+0x2003021, 0x24040001, 0x24050005, 0xc004924,
+0x2003021, 0x24040001, 0x24050009, 0xc004924,
+0x2003021, 0x24040001, 0x24050009, 0xc004924,
+0x2003021, 0x24040001, 0x24050001, 0xc004924,
+0x27a60018, 0x24040001, 0x24050001, 0xc004924,
+0x27a60018, 0x97a20018, 0x30420004, 0x10400034,
+0x3c114000, 0x3c020001, 0x8c425e18, 0x2443ffff,
+0x2c620006, 0x10400034, 0x31080, 0x3c010001,
+0x220821, 0x8c225c38, 0x400008, 0x0,
+0x24040001, 0x24050011, 0x27b00020, 0xc004924,
+0x2003021, 0x24040001, 0x24050011, 0xc004924,
+0x2003021, 0x97a40020, 0x30824000, 0x10400002,
+0x3c030010, 0x3c030008, 0x3c120001, 0x8005306,
+0x30828000, 0x24040001, 0x24050014, 0x27b00020,
+0xc004924, 0x2003021, 0x24040001, 0x24050014,
+0xc004924, 0x2003021, 0x97a40020, 0x30821000,
+0x10400002, 0x3c030010, 0x3c030008, 0x3c120001,
+0x30820800, 0x54400001, 0x3c120002, 0x3c028000,
+0x2221025, 0x2431825, 0x8005313, 0x438825,
+0x3c110001, 0x2338821, 0x8e317e9c, 0x3c027fff,
+0x3442ffff, 0x2228824, 0x3c020001, 0x8c425d38,
+0x1040001c, 0x0, 0x3c020001, 0x8c425df8,
+0x10400002, 0x3c022000, 0x2228825, 0x141140,
+0x3c010001, 0x220821, 0x8c227ea0, 0x10400003,
+0x3c020020, 0x8005327, 0x2228825, 0x3c02ffdf,
0x3442ffff, 0x2228824, 0x141140, 0x3c010001,
-0x220821, 0x8c2275dc, 0x10400003, 0x3c020080,
-0x800515e, 0x2228825, 0x3c02ff7f, 0x3442ffff,
-0x2228824, 0x3c020001, 0x8c425500, 0x10400002,
-0x3c020800, 0x2228825, 0x3c020001, 0x8c425504,
-0x10400002, 0x3c020400, 0x2228825, 0x3c020001,
-0x8c425508, 0x10400006, 0x3c020100, 0x8005171,
-0x2228825, 0x3c027fff, 0x3442ffff, 0x628824,
-0x141140, 0x3c010001, 0x220821, 0xac3175c0,
-0x2201021, 0x8fbf002c, 0x8fb40028, 0x8fb30024,
-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
-0x27bd0030, 0x27bdffd8, 0xafb40020, 0x80a021,
-0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014,
-0xafb00010, 0x8f900200, 0x3c030001, 0x8c635488,
-0x8f930220, 0x24020002, 0x106200b4, 0x2c620003,
-0x10400005, 0x24020001, 0x1062000a, 0x141940,
-0x8005240, 0x0, 0x24020004, 0x1062005a,
-0x24020008, 0x10620059, 0x149140, 0x8005240,
-0x0, 0x3c040001, 0x832021, 0x8c8475cc,
-0x3c110001, 0x2238821, 0x8e3175c4, 0x3c024000,
-0x821024, 0x1040003e, 0x3c020008, 0x2221024,
-0x10400020, 0x36100002, 0x3c020001, 0x431021,
-0x8c4275d0, 0x10400005, 0x36100020, 0x36100100,
-0x3c020020, 0x80051b5, 0x2228825, 0x2402feff,
-0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x141140, 0x3c010001, 0x220821, 0x8c2275d8,
-0x10400005, 0x3c020001, 0x2629825, 0x3c020080,
-0x80051d4, 0x2228825, 0x3c02fffe, 0x3442ffff,
-0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80051d4,
-0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe,
-0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff,
-0x2228824, 0x3c010001, 0x230821, 0xac2075d0,
-0x3c010001, 0x230821, 0xac2075d8, 0xc0047cd,
-0x0, 0xaf900200, 0xaf930220, 0x8f820220,
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
-0x34420002, 0xaf820220, 0x80051eb, 0x141140,
-0x8f820200, 0x2403fffd, 0x431024, 0xc0047cd,
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
+0x220821, 0x8c227ea8, 0x10400003, 0x3c020080,
+0x8005332, 0x2228825, 0x3c02ff7f, 0x3442ffff,
+0x2228824, 0x3c040001, 0x24845c2c, 0x3c05000c,
+0x34a50326, 0x3c070001, 0x8ce75d28, 0x3021,
+0x141140, 0x3c010001, 0x220821, 0xac317e94,
+0xafb20010, 0xc002403, 0xafb10014, 0x800538f,
+0x2201021, 0x142940, 0x3c030001, 0x651821,
+0x8c637e98, 0x3c024000, 0x621024, 0x14400008,
+0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001,
+0x250821, 0xac317e90, 0x800538f, 0x2201021,
+0x3c020001, 0x8c425d38, 0x10400033, 0x3c11c00c,
+0x3c020001, 0x8c425dd4, 0x3c04c00c, 0x34842000,
+0x3c030001, 0x8c635df8, 0x2102b, 0x21023,
+0x441024, 0x10600003, 0x518825, 0x3c022000,
+0x2228825, 0x3c020001, 0x451021, 0x8c427ea4,
+0x10400003, 0x3c020020, 0x800536c, 0x2228825,
+0x3c02ffdf, 0x3442ffff, 0x2228824, 0x141140,
+0x3c010001, 0x220821, 0x8c227eac, 0x10400003,
+0x3c020080, 0x8005377, 0x2228825, 0x3c02ff7f,
+0x3442ffff, 0x2228824, 0x3c020001, 0x8c425dc0,
+0x10400002, 0x3c020800, 0x2228825, 0x3c020001,
+0x8c425dc4, 0x10400002, 0x3c020400, 0x2228825,
+0x3c020001, 0x8c425dc8, 0x10400006, 0x3c020100,
+0x800538a, 0x2228825, 0x3c027fff, 0x3442ffff,
+0x628824, 0x141140, 0x3c010001, 0x220821,
+0xac317e90, 0x2201021, 0x8fbf003c, 0x8fb40038,
+0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
+0x3e00008, 0x27bd0040, 0x27bdffd8, 0xafb40020,
+0x80a021, 0xafbf0024, 0xafb3001c, 0xafb20018,
+0xafb10014, 0xafb00010, 0x8f900200, 0x3c030001,
+0x8c635d28, 0x8f930220, 0x24020002, 0x10620063,
+0x2c620003, 0x10400005, 0x24020001, 0x1062000a,
+0x141940, 0x8005459, 0x0, 0x24020004,
+0x1062005a, 0x24020008, 0x10620059, 0x149140,
+0x8005459, 0x0, 0x3c040001, 0x832021,
+0x8c847e9c, 0x3c110001, 0x2238821, 0x8e317e94,
+0x3c024000, 0x821024, 0x1040003e, 0x3c020008,
+0x2221024, 0x10400020, 0x36100002, 0x3c020001,
+0x431021, 0x8c427ea0, 0x10400005, 0x36100020,
+0x36100100, 0x3c020020, 0x80053ce, 0x2228825,
+0x2402feff, 0x2028024, 0x3c02ffdf, 0x3442ffff,
0x2228824, 0x141140, 0x3c010001, 0x220821,
-0x8005240, 0xac3175c4, 0x149140, 0x3c040001,
-0x922021, 0x8c8475c8, 0x3c110001, 0x2328821,
-0x8e3175c0, 0x3c024000, 0x821024, 0x14400011,
-0x0, 0x3c020001, 0x8c425538, 0x14400006,
-0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cd,
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
-0x2228824, 0x3c010001, 0x320821, 0x8005240,
-0xac3175c0, 0x3c020001, 0x8c425538, 0x10400005,
-0x3c020020, 0x3c020001, 0x8c425514, 0x1040002b,
-0x3c020020, 0x821024, 0x10400007, 0x36100020,
-0x24020100, 0x3c010001, 0x320821, 0xac2275d4,
-0x8005220, 0x36100100, 0x3c010001, 0x320821,
-0xac2075d4, 0x2402feff, 0x2028024, 0x3c020080,
-0x821024, 0x10400007, 0x141940, 0x3c020001,
-0x3c010001, 0x230821, 0xac2275dc, 0x8005231,
-0x2629825, 0x141140, 0x3c010001, 0x220821,
-0xac2075dc, 0x3c02fffe, 0x3442ffff, 0x2629824,
-0xc0047cd, 0x0, 0xaf900200, 0xaf930220,
+0x8c227ea8, 0x10400005, 0x3c020001, 0x2629825,
+0x3c020080, 0x80053ed, 0x2228825, 0x3c02fffe,
+0x3442ffff, 0x2629824, 0x3c02ff7f, 0x3442ffff,
+0x80053ed, 0x2228824, 0x2402fedf, 0x2028024,
+0x3c02fffe, 0x3442ffff, 0x2629824, 0x3c02ff5f,
+0x3442ffff, 0x2228824, 0x3c010001, 0x230821,
+0xac207ea0, 0x3c010001, 0x230821, 0xac207ea8,
+0xc004844, 0x0, 0xaf900200, 0xaf930220,
0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
-0x8f820220, 0x34420002, 0xaf820220, 0x141140,
-0x3c010001, 0x220821, 0xac3175c0, 0x8fbf0024,
-0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
-0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
+0x8f820220, 0x34420002, 0xaf820220, 0x8005404,
+0x141140, 0x8f820200, 0x2403fffd, 0x431024,
+0xc004844, 0xaf820200, 0x3c02bfff, 0x3442ffff,
+0xc00429b, 0x2228824, 0x141140, 0x3c010001,
+0x220821, 0x8005459, 0xac317e94, 0x149140,
+0x3c040001, 0x922021, 0x8c847e98, 0x3c110001,
+0x2328821, 0x8e317e90, 0x3c024000, 0x821024,
+0x14400011, 0x0, 0x3c020001, 0x8c425df8,
+0x14400006, 0x3c02bfff, 0x8f820200, 0x34420002,
+0xc004844, 0xaf820200, 0x3c02bfff, 0x3442ffff,
+0xc00429b, 0x2228824, 0x3c010001, 0x320821,
+0x8005459, 0xac317e90, 0x3c020001, 0x8c425df8,
+0x10400005, 0x3c020020, 0x3c020001, 0x8c425dd4,
+0x1040002b, 0x3c020020, 0x821024, 0x10400007,
+0x36100020, 0x24020100, 0x3c010001, 0x320821,
+0xac227ea4, 0x8005439, 0x36100100, 0x3c010001,
+0x320821, 0xac207ea4, 0x2402feff, 0x2028024,
+0x3c020080, 0x821024, 0x10400007, 0x141940,
+0x3c020001, 0x3c010001, 0x230821, 0xac227eac,
+0x800544a, 0x2629825, 0x141140, 0x3c010001,
+0x220821, 0xac207eac, 0x3c02fffe, 0x3442ffff,
+0x2629824, 0xc004844, 0x0, 0xaf900200,
+0xaf930220, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
+0x141140, 0x3c010001, 0x220821, 0xac317e90,
+0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018,
+0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028,
+0x0, 0x0, 0x0, 0x0 };
u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x24486561, 0x6465723a, 0x202f7072,
0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
@@ -4339,10 +4473,10 @@ u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
0x31333a34, 0x30207368, 0x75616e67, 0x20457870,
0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20,
-0x23312054, 0x68752041, 0x75672031, 0x32203135,
-0x3a34393a, 0x35332050, 0x44542031, 0x39393900,
+0x23312053, 0x61742044, 0x65632031, 0x31203136,
+0x3a30333a, 0x31392050, 0x53542031, 0x39393900,
0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a,
-0x2031353a, 0x34393a35, 0x33000000, 0x46575f43,
+0x2031363a, 0x30333a31, 0x39000000, 0x46575f43,
0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263,
0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48,
0x4f53543a, 0x20636f6d, 0x70757465, 0x0,
@@ -4420,25 +4554,27 @@ u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
0x3a31333a, 0x33392073, 0x6875616e, 0x67204578,
0x70202400, 0x50726f62, 0x65506879, 0x0,
-0x6c6e6b41, 0x53535254, 0x0, 0x11998,
-0x119d0, 0x119e8, 0x11a1c, 0x11a48,
-0x11a5c, 0x11a98, 0x11e08, 0x11b70,
-0x11bb0, 0x11bdc, 0x11c1c, 0x11c4c,
-0x11c88, 0x11cbc, 0x11e08, 0x1204c,
-0x12064, 0x1208c, 0x120ac, 0x120d4,
-0x12204, 0x1222c, 0x12280, 0x122a8,
-0x0, 0x1250c, 0x125dc, 0x126b4,
-0x12784, 0x127e0, 0x128bc, 0x128e4,
-0x129c0, 0x129e8, 0x12b90, 0x12bb8,
-0x12d60, 0x12f58, 0x131ec, 0x13100,
-0x131ec, 0x13218, 0x12d88, 0x12f30,
-0x0, 0x13604, 0x13648, 0x136e0,
-0x1372c, 0x1379c, 0x13834, 0x13868,
-0x138f0, 0x13988, 0x13a58, 0x13a98,
-0x13b1c, 0x13b40, 0x13c74, 0x646f4261,
+0x6c6e6b41, 0x53535254, 0x0, 0x11af4,
+0x11b8c, 0x11bac, 0x11bf0, 0x11c1c,
+0x11c30, 0x11c6c, 0x11fe0, 0x11d48,
+0x11d88, 0x11db4, 0x11df4, 0x11e24,
+0x11e60, 0x11e94, 0x11fe0, 0x12228,
+0x12240, 0x12268, 0x12288, 0x122b0,
+0x123e0, 0x12408, 0x1245c, 0x12484,
+0x0, 0x126ec, 0x127bc, 0x12894,
+0x12964, 0x129c0, 0x12a9c, 0x12ac4,
+0x12ba0, 0x12bc8, 0x12d70, 0x12d98,
+0x12f40, 0x13138, 0x133cc, 0x132e0,
+0x133cc, 0x133f8, 0x12f68, 0x13110,
+0x0, 0x13ae4, 0x13b28, 0x13bc0,
+0x13c0c, 0x13c7c, 0x13d14, 0x13d48,
+0x13dd0, 0x13e68, 0x13f38, 0x13f78,
+0x13ffc, 0x14020, 0x14154, 0x646f4261,
0x73655067, 0x0, 0x0, 0x0,
0x0, 0x73746d61, 0x634c4e4b, 0x0,
-0x0, 0x0 };
+0x6765746d, 0x636c6e6b, 0x0, 0x14c4c,
+0x14c4c, 0x14b94, 0x14bd8, 0x14c4c,
+0x14c4c, 0x0 };
u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
0x416c7465,
0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465,
@@ -4452,39 +4588,41 @@ u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x3, 0x0,
-0x1, 0x0, 0x0, 0x1,
+0x1, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x1, 0x0,
0x0, 0x0, 0x0, 0x1,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x1000000, 0x21000000, 0x12000140,
-0x0, 0x0, 0x20000000, 0x120000a0,
-0x0, 0x12000060, 0x12000180, 0x120001e0,
-0x0, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x1000000, 0x21000000,
+0x12000140, 0x0, 0x0, 0x20000000,
+0x120000a0, 0x0, 0x12000060, 0x12000180,
+0x120001e0, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2,
0x0, 0x0, 0x30001, 0x1,
0x30201, 0x0, 0x0, 0x0 };
#endif
/* Generated by genfw.c */
#define tigon2FwReleaseMajor 0xc
-#define tigon2FwReleaseMinor 0x3
-#define tigon2FwReleaseFix 0xd
+#define tigon2FwReleaseMinor 0x4
+#define tigon2FwReleaseFix 0x5
#define tigon2FwStartAddr 0x00004000
#define tigon2FwTextAddr 0x00004000
-#define tigon2FwTextLen 0xeca0
-#define tigon2FwRodataAddr 0x00012ca0
-#define tigon2FwRodataLen 0xff0
-#define tigon2FwDataAddr 0x00013cc0
-#define tigon2FwDataLen 0x170
-#define tigon2FwSbssAddr 0x00013e30
-#define tigon2FwSbssLen 0xbc
-#define tigon2FwBssAddr 0x00013ef0
+#define tigon2FwTextLen 0x11c50
+#define tigon2FwRodataAddr 0x00015c50
+#define tigon2FwRodataLen 0x10c0
+#define tigon2FwDataAddr 0x00016d40
+#define tigon2FwDataLen 0x1c0
+#define tigon2FwSbssAddr 0x00016f00
+#define tigon2FwSbssLen 0xc4
+#define tigon2FwBssAddr 0x00016fd0
#define tigon2FwBssLen 0x20c0
u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x0,
0x10000003, 0x0, 0xd, 0xd,
-0x3c1d0001, 0x8fbd3d10, 0x3a0f021, 0x3c100000,
+0x3c1d0001, 0x8fbd6da0, 0x3a0f021, 0x3c100000,
0x26104000, 0xc0010c0, 0x0, 0xd,
-0x3c1d0001, 0x8fbd3d14, 0x3a0f021, 0x3c100000,
-0x26104000, 0xc00178e, 0x0, 0xd,
+0x3c1d0001, 0x8fbd6da4, 0x3a0f021, 0x3c100000,
+0x26104000, 0xc0017c8, 0x0, 0xd,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
@@ -4496,22 +4634,22 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2000008,
-0x0, 0x80016dd, 0x3c0a0001, 0x80016dd,
-0x3c0a0002, 0x80016dd, 0x0, 0x8002ab5,
-0x0, 0x8002a58, 0x0, 0x80016dd,
-0x3c0a0004, 0x800306c, 0x0, 0x8001a07,
-0x0, 0x80036c3, 0x0, 0x8004aad,
-0x0, 0x80016dd, 0x3c0a0006, 0x8003731,
-0x3c0a0007, 0x80016dd, 0x3c0a0008, 0x80016dd,
-0x3c0a0009, 0x8003789, 0x0, 0x8002caf,
-0x0, 0x80016dd, 0x3c0a000b, 0x80016dd,
-0x3c0a000c, 0x80016dd, 0x3c0a000d, 0x800277b,
-0x0, 0x8002710, 0x0, 0x80016dd,
-0x3c0a000e, 0x8001f20, 0x0, 0x8001919,
-0x0, 0x80019b9, 0x0, 0x8003a08,
-0x0, 0x80039f6, 0x0, 0x80016dd,
-0x0, 0x80018c6, 0x0, 0x80016dd,
-0x0, 0x80016dd, 0x3c0a0013, 0x80016dd,
+0x0, 0x8001717, 0x3c0a0001, 0x8001717,
+0x3c0a0002, 0x8001717, 0x0, 0x8002c68,
+0x0, 0x8002c0b, 0x0, 0x8001717,
+0x3c0a0004, 0x8003272, 0x0, 0x8001a3a,
+0x0, 0x8003925, 0x0, 0x80038cc,
+0x0, 0x8001717, 0x3c0a0006, 0x8003993,
+0x3c0a0007, 0x8001717, 0x3c0a0008, 0x8001717,
+0x3c0a0009, 0x80039eb, 0x0, 0x8002e62,
+0x0, 0x8001717, 0x3c0a000b, 0x8001717,
+0x3c0a000c, 0x8001717, 0x3c0a000d, 0x80028d7,
+0x0, 0x800286c, 0x0, 0x8001717,
+0x3c0a000e, 0x8002074, 0x0, 0x800194c,
+0x0, 0x80019ec, 0x0, 0x8003c7e,
+0x0, 0x8003c6c, 0x0, 0x8001717,
+0x0, 0x8001902, 0x0, 0x8001717,
+0x0, 0x8001717, 0x3c0a0013, 0x8001717,
0x3c0a0014, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
@@ -4529,78 +4667,78 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x27bdffe0,
0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140,
-0x24030003, 0xaf8300ec, 0x34420004, 0xc0029a0,
-0xaf820140, 0x3c0100c0, 0xc001711, 0xac203ffc,
-0x403021, 0x3c020008, 0x3c010001, 0xac263e48,
+0x24030003, 0xaf8300ec, 0x34420004, 0xc002afc,
+0xaf820140, 0x3c0100c0, 0xc00174b, 0xac203ffc,
+0x403021, 0x3c020008, 0x3c010001, 0xac266f18,
0x50c2000d, 0x24020008, 0x3c100010, 0x10d00009,
-0x24050100, 0x3c040001, 0x24842d54, 0x3821,
-0xafa00010, 0xc0029bb, 0xafa00014, 0x3c010001,
-0xac303e48, 0x24020008, 0x3c010001, 0xac223e60,
-0x2402001f, 0x3c010001, 0xac223e70, 0x24020016,
-0x3c010001, 0xac223e44, 0x3c05fffe, 0x34a56f08,
-0x3c020001, 0x8c423e48, 0x3c030001, 0x24635fb0,
-0x3c040001, 0x8c843cc4, 0x431023, 0x14800002,
-0x458021, 0x2610fa48, 0x2402f000, 0x2028024,
-0xc001733, 0x2002021, 0x2022823, 0x3c040020,
+0x24050100, 0x3c040001, 0x24845d04, 0x3821,
+0xafa00010, 0xc002b17, 0xafa00014, 0x3c010001,
+0xac306f18, 0x24020008, 0x3c010001, 0xac226f30,
+0x2402001f, 0x3c010001, 0xac226f40, 0x24020016,
+0x3c010001, 0xac226f14, 0x3c05fffe, 0x34a56f08,
+0x3c020001, 0x8c426f18, 0x3c030002, 0x24639090,
+0x3c040001, 0x8c846d44, 0x431023, 0x14800002,
+0x458021, 0x2610fa38, 0x2402f000, 0x2028024,
+0xc00176d, 0x2002021, 0x2022823, 0x3c040020,
0x821823, 0x651823, 0x247bb000, 0x3c03fffe,
0x3463bf08, 0x363b821, 0x3c0600bf, 0x34c6f000,
-0x3c070001, 0x8ce73cc0, 0x3c0300bf, 0x3463e000,
-0x852023, 0x3c010001, 0xac243e54, 0x822023,
-0x3c010001, 0xac253e3c, 0x52842, 0x3c010001,
-0xac223e30, 0x27620ffc, 0x3c010001, 0xac223d10,
+0x3c070001, 0x8ce76d40, 0x3c0300bf, 0x3463e000,
+0x852023, 0x3c010001, 0xac246f24, 0x822023,
+0x3c010001, 0xac256f0c, 0x52842, 0x3c010001,
+0xac226f00, 0x27620ffc, 0x3c010001, 0xac226da0,
0x27621ffc, 0xdb3023, 0x7b1823, 0x3c010001,
-0xac243e34, 0x3c010001, 0xac253e58, 0x3c010001,
-0xac223d14, 0xaf860150, 0x10e00011, 0xaf830250,
-0x3c1d0001, 0x8fbd3ccc, 0x3a0f021, 0xc0016f7,
-0x0, 0x3c020001, 0x8c423cd0, 0x3c030001,
-0x8c633cd4, 0x2442fe00, 0x24630200, 0x3c010001,
-0xac223cd0, 0x3c010001, 0x10000004, 0xac233cd4,
-0x3c1d0001, 0x8fbd3d10, 0x3a0f021, 0x3c020001,
-0x8c423cc4, 0x1040000d, 0x26fafa48, 0x3c020001,
-0x8c423cd0, 0x3c030001, 0x8c633cd4, 0x3c1a0001,
-0x8f5a3cd4, 0x2442fa48, 0x246305b8, 0x3c010001,
-0xac223cd0, 0x3c010001, 0xac233cd4, 0x3c020001,
-0x8c423cc8, 0x14400003, 0x0, 0x3c010001,
-0xac203cd0, 0xc00114c, 0x0, 0x8fbf001c,
+0xac246f04, 0x3c010001, 0xac256f28, 0x3c010001,
+0xac226da4, 0xaf860150, 0x10e00011, 0xaf830250,
+0x3c1d0001, 0x8fbd6d4c, 0x3a0f021, 0xc001731,
+0x0, 0x3c020001, 0x8c426d50, 0x3c030001,
+0x8c636d54, 0x2442fe00, 0x24630200, 0x3c010001,
+0xac226d50, 0x3c010001, 0x10000004, 0xac236d54,
+0x3c1d0001, 0x8fbd6da0, 0x3a0f021, 0x3c020001,
+0x8c426d44, 0x1040000d, 0x26fafa38, 0x3c020001,
+0x8c426d50, 0x3c030001, 0x8c636d54, 0x3c1a0001,
+0x8f5a6d54, 0x2442fa38, 0x246305c8, 0x3c010001,
+0xac226d50, 0x3c010001, 0xac236d54, 0x3c020001,
+0x8c426d48, 0x14400003, 0x0, 0x3c010001,
+0xac206d50, 0xc00114c, 0x0, 0x8fbf001c,
0x8fb00018, 0x3e00008, 0x27bd0020, 0x3c020001,
-0x8c423cd0, 0x3c030001, 0x8c633cd4, 0x27bdffa0,
-0xafb00040, 0x3c100001, 0x8e103738, 0x3c040001,
-0x24842d60, 0xafbf0058, 0xafbe0054, 0xafb50050,
+0x8c426d50, 0x3c030001, 0x8c636d54, 0x27bdffa0,
+0xafb00040, 0x3c100001, 0x8e106748, 0x3c040001,
+0x24845d10, 0xafbf0058, 0xafbe0054, 0xafb50050,
0xafb3004c, 0xafb20048, 0xafb10044, 0xafa20034,
0xafa30030, 0xafa00010, 0xafa00014, 0x8f860040,
-0x24050200, 0xc0029bb, 0x2003821, 0x8f830040,
+0x24050200, 0xc002b17, 0x2003821, 0x8f830040,
0x3c02f000, 0x621824, 0x3c026000, 0x1062000b,
-0xa3a0003f, 0x240e0001, 0x3c040001, 0x24842d68,
+0xa3a0003f, 0x240e0001, 0x3c040001, 0x24845d18,
0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f860040,
-0x24050300, 0xc0029bb, 0x2003821, 0x8f820240,
+0x24050300, 0xc002b17, 0x2003821, 0x8f820240,
0x3c030001, 0x431025, 0xaf820240, 0xaf800048,
0x8f820048, 0x14400005, 0x0, 0xaf800048,
0x8f820048, 0x10400004, 0x0, 0xaf800048,
0x10000003, 0x2e02021, 0xaf80004c, 0x2e02021,
-0x3c050001, 0xc002a28, 0x34a540f8, 0x3402021,
-0xc002a28, 0x240505b8, 0x3c020001, 0x8c423e54,
-0x3c0d0001, 0x8dad3e34, 0x3c030001, 0x8c633e30,
-0x3c080001, 0x8d083e3c, 0x3c090001, 0x8d293e58,
-0x3c0a0001, 0x8d4a3e60, 0x3c0b0001, 0x8d6b3e70,
-0x3c0c0001, 0x8d8c3e44, 0x3c040001, 0x24842d74,
-0x24050400, 0xaf420130, 0x8f420130, 0x24060001,
-0x24070001, 0xaf400000, 0xaf4d012c, 0xaf430138,
-0xaf48013c, 0xaf490140, 0xaf4a0144, 0xaf4b0148,
-0xaf4c014c, 0x2442ff80, 0xaf420134, 0x24020001,
-0xafa20010, 0xc0029bb, 0xafa00014, 0x8f42012c,
-0xafa20010, 0x8f420130, 0xafa20014, 0x8f460138,
-0x8f47013c, 0x3c040001, 0x24842d80, 0xc0029bb,
-0x24050500, 0xafb70010, 0xafba0014, 0x8f460140,
-0x8f470144, 0x3c040001, 0x24842d8c, 0xc0029bb,
-0x24050600, 0x3c020001, 0x8c423e48, 0x3603821,
-0x3c060001, 0x24c65fb0, 0x2448ffff, 0x1061824,
+0x3c050001, 0xc002b84, 0x34a540f8, 0x3402021,
+0xc002b84, 0x240505c8, 0x3c020001, 0x8c426f24,
+0x3c0d0001, 0x8dad6f04, 0x3c030001, 0x8c636f00,
+0x3c080001, 0x8d086f0c, 0x3c090001, 0x8d296f28,
+0x3c0a0001, 0x8d4a6f30, 0x3c0b0001, 0x8d6b6f40,
+0x3c0c0001, 0x8d8c6f14, 0x3c040001, 0x24845d24,
+0x24050400, 0xaf42013c, 0x8f42013c, 0x24060001,
+0x24070001, 0xaf400000, 0xaf4d0138, 0xaf430144,
+0xaf480148, 0xaf49014c, 0xaf4a0150, 0xaf4b0154,
+0xaf4c0158, 0x2442ff80, 0xaf420140, 0x24020001,
+0xafa20010, 0xc002b17, 0xafa00014, 0x8f420138,
+0xafa20010, 0x8f42013c, 0xafa20014, 0x8f460144,
+0x8f470148, 0x3c040001, 0x24845d30, 0xc002b17,
+0x24050500, 0xafb70010, 0xafba0014, 0x8f46014c,
+0x8f470150, 0x3c040001, 0x24845d3c, 0xc002b17,
+0x24050600, 0x3c020001, 0x8c426f18, 0x3603821,
+0x3c060002, 0x24c69090, 0x2448ffff, 0x1061824,
0xe81024, 0x43102b, 0x10400006, 0x24050900,
-0x3c040001, 0x24842d98, 0xafa80010, 0xc0029bb,
+0x3c040001, 0x24845d48, 0xafa80010, 0xc002b17,
0xafa00014, 0x8f82000c, 0xafa20010, 0x8f82003c,
0xafa20014, 0x8f860000, 0x8f870004, 0x3c040001,
-0x24842da4, 0xc0029bb, 0x24051000, 0x8c020220,
+0x24845d54, 0xc002b17, 0x24051000, 0x8c020220,
0x8c030224, 0x8c060218, 0x8c07021c, 0x3c040001,
-0x24842dac, 0x24051100, 0xafa20010, 0xc0029bb,
+0x24845d5c, 0x24051100, 0xafa20010, 0xc002b17,
0xafa30014, 0xaf800054, 0xaf80011c, 0x8c020218,
0x30420002, 0x10400009, 0x0, 0x8c020220,
0x3c030002, 0x34630004, 0x431025, 0xaf42000c,
@@ -4619,11 +4757,20 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24020490, 0xaee20010, 0xaee40008, 0xaee5000c,
0x26e40008, 0x8c820000, 0x8c830004, 0xaf820090,
0xaf830094, 0x8c820018, 0xaf8200b4, 0x9482000a,
-0xaf82009c, 0x8f8200b0, 0x8f430014, 0x431025,
-0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
-0x24051200, 0x96e20472, 0x96e60452, 0x96e70462,
-0xafa20010, 0x96e20482, 0x3c040001, 0x24842db4,
-0xc0029bb, 0xafa20014, 0x96f00452, 0x32020001,
+0xaf82009c, 0x8f420014, 0xaf8200b0, 0x8f8200b0,
+0x30420004, 0x1440fffd, 0x0, 0x8f8200b0,
+0x3c03ef00, 0x431024, 0x10400021, 0x0,
+0x8f8200b4, 0xafa20010, 0x8f820090, 0x8f830094,
+0x3c040001, 0x24845d64, 0xafa30014, 0x8f8600b0,
+0x8f87009c, 0x3c050001, 0xc002b17, 0x34a5200d,
+0x3c040001, 0x24845d70, 0x240203ac, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e75d78,
+0xc002b17, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x96e20472, 0x96e60452, 0x96e70462, 0xafa20010,
+0x96e20482, 0x3c040001, 0x24845da4, 0x24051200,
+0xc002b17, 0xafa20014, 0x96f00452, 0x32020001,
0x10400002, 0xb021, 0x24160001, 0x32020002,
0x54400001, 0x36d60002, 0x32020008, 0x54400001,
0x36d60004, 0x32020010, 0x54400001, 0x36d60008,
@@ -4635,9 +4782,9 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x36d61000, 0x96f00462, 0x32c24000, 0x14400004,
0x3207009b, 0x30c2009b, 0x14e20007, 0x240e0001,
0x32c22000, 0x1440000d, 0x32020001, 0x3062009b,
-0x10e20009, 0x240e0001, 0x3c040001, 0x24842dc0,
+0x10e20009, 0x240e0001, 0x3c040001, 0x24845db0,
0x24051300, 0x2003821, 0xa3ae003f, 0xafa30010,
-0xc0029bb, 0xafa00014, 0x32020001, 0x54400001,
+0xc002b17, 0xafa00014, 0x32020001, 0x54400001,
0x36d60080, 0x32020002, 0x54400001, 0x36d60100,
0x32020008, 0x54400001, 0x36d60200, 0x32020010,
0x54400001, 0x36d60400, 0x32020080, 0x54400001,
@@ -4651,1060 +4798,1138 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x10400002, 0x3c020010, 0x2c2b025, 0x8c020218,
0x30424000, 0x10400002, 0x3c020020, 0x2c2b025,
0x8c020218, 0x30421000, 0x10400002, 0x3c020040,
-0x2c2b025, 0x8ee20498, 0x8ee3049c, 0xaf420150,
-0xaf430154, 0x8ee204a0, 0x8ee304a4, 0xaf420158,
-0xaf43015c, 0x8ee204a8, 0x8ee304ac, 0xaf420160,
-0xaf430164, 0x8ee20428, 0x8ee3042c, 0xaf420168,
-0xaf43016c, 0x8ee20448, 0x8ee3044c, 0xaf420170,
-0xaf430174, 0x8ee20458, 0x8ee3045c, 0xaf420178,
-0xaf43017c, 0x8ee20468, 0x8ee3046c, 0xaf420180,
-0xaf430184, 0x8ee20478, 0x8ee3047c, 0xaf420188,
-0xaf43018c, 0x8ee20488, 0x8ee3048c, 0xaf420190,
-0xaf430194, 0x8ee204b0, 0x8ee304b4, 0x24040080,
-0xaf420198, 0xaf43019c, 0xc002a28, 0x24050080,
-0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260,
-0x24050200, 0x24060008, 0xc002a3f, 0xaf4201e8,
+0x2c2b025, 0x8ee20498, 0x8ee3049c, 0xaf420160,
+0xaf430164, 0x8ee204a0, 0x8ee304a4, 0xaf420168,
+0xaf43016c, 0x8ee204a8, 0x8ee304ac, 0xaf420170,
+0xaf430174, 0x8ee20428, 0x8ee3042c, 0xaf420178,
+0xaf43017c, 0x8ee20448, 0x8ee3044c, 0xaf420180,
+0xaf430184, 0x8ee20458, 0x8ee3045c, 0xaf420188,
+0xaf43018c, 0x8ee20468, 0x8ee3046c, 0xaf420190,
+0xaf430194, 0x8ee20478, 0x8ee3047c, 0xaf420198,
+0xaf43019c, 0x8ee20488, 0x8ee3048c, 0xaf4201a0,
+0xaf4301a4, 0x8ee204b0, 0x8ee304b4, 0x24040080,
+0xaf4201a8, 0xaf4301ac, 0xc002b84, 0x24050080,
+0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
+0x24050200, 0x24060008, 0xc002b9b, 0xaf4201f8,
0x3c043b9a, 0x3484ca00, 0x3821, 0x24020006,
-0x24030002, 0xaf4201e4, 0x240203e8, 0xaf4301f4,
-0xaf4301f0, 0xaf4401ec, 0xaf420284, 0x24020001,
-0xaf430280, 0xaf42028c, 0x3c030001, 0x671821,
-0x90633cd8, 0x3471021, 0x24e70001, 0xa043021c,
+0x24030002, 0xaf4201f4, 0x240203e8, 0xaf430204,
+0xaf430200, 0xaf4401fc, 0xaf420294, 0x24020001,
+0xaf430290, 0xaf42029c, 0x3c030001, 0x671821,
+0x90636d58, 0x3471021, 0x24e70001, 0xa043022c,
0x2ce2000f, 0x1440fff8, 0x3471821, 0x24e70001,
0x3c080001, 0x350840f8, 0x8f820040, 0x3c040001,
-0x24842dcc, 0x24051400, 0x21702, 0x24420030,
-0xa062021c, 0x3471021, 0xa040021c, 0x8c070218,
-0x2c03021, 0x240205b8, 0xafa20010, 0xc0029bb,
-0xafa80014, 0x3c040001, 0x24842dd8, 0x3c050000,
-0x24a55b38, 0x24060010, 0x27b10030, 0x2203821,
-0x27b30034, 0xc001751, 0xafb30010, 0x3c030001,
-0x8c633cc8, 0x1060000a, 0x408021, 0x8fa30030,
+0x24845dbc, 0x24051400, 0x21702, 0x24420030,
+0xa062022c, 0x3471021, 0xa040022c, 0x8c070218,
+0x2c03021, 0x240205c8, 0xafa20010, 0xc002b17,
+0xafa80014, 0x3c040001, 0x24845dc8, 0x3c050000,
+0x24a55c20, 0x24060010, 0x27b10030, 0x2203821,
+0x27b30034, 0xc00178b, 0xafb30010, 0x3c030001,
+0x8c636d48, 0x1060000a, 0x408021, 0x8fa30030,
0x2405ff00, 0x8fa20034, 0x246400ff, 0x852024,
0x831823, 0x431023, 0xafa20034, 0xafa40030,
-0xafb30010, 0x3c040001, 0x24842de4, 0x3c050000,
-0x24a54100, 0x24060108, 0xc001751, 0x2203821,
+0xafb30010, 0x3c040001, 0x24845dd4, 0x3c050000,
+0x24a54100, 0x24060108, 0xc00178b, 0x2203821,
0x409021, 0x32c20003, 0x50400045, 0x2203821,
0x8f820050, 0x3c030010, 0x431024, 0x10400016,
0x0, 0x8c020218, 0x30420040, 0x1040000f,
0x24020001, 0x8f820050, 0x8c030218, 0x240e0001,
-0x3c040001, 0x24842df0, 0xa3ae003f, 0xafa20010,
-0xafa30014, 0x8f870040, 0x24051500, 0xc0029bb,
+0x3c040001, 0x24845de0, 0xa3ae003f, 0xafa20010,
+0xafa30014, 0x8f870040, 0x24051500, 0xc002b17,
0x2c03021, 0x10000004, 0x0, 0x3c010001,
-0x370821, 0xa02240f4, 0x3c040001, 0x24842dfc,
-0x3c050001, 0x24a52c20, 0x3c060001, 0x24c62c8c,
+0x370821, 0xa02240f4, 0x3c040001, 0x24845dec,
+0x3c050001, 0x24a55bd0, 0x3c060001, 0x24c65c3c,
0xc53023, 0x8f420010, 0x27b30030, 0x2603821,
-0x27b10034, 0x34420a00, 0xaf420010, 0xc001751,
-0xafb10010, 0x3c040001, 0x24842e10, 0x3c050001,
-0x24a5af38, 0x3c060001, 0x24c6b2b4, 0xc53023,
-0x2603821, 0xaf420108, 0xc001751, 0xafb10010,
-0x3c040001, 0x24842e2c, 0x3c050001, 0x24a5b6c4,
-0x3c060001, 0x24c6c1a8, 0xc53023, 0x2603821,
-0x3c010001, 0xac223ea0, 0xc001751, 0xafb10010,
-0x3c040001, 0x24842e44, 0x10000024, 0x24051600,
-0x3c040001, 0x24842e4c, 0x3c050001, 0x24a59b0c,
-0x3c060001, 0x24c69c38, 0xc53023, 0xc001751,
-0xafb30010, 0x3c040001, 0x24842e5c, 0x3c050001,
-0x24a5aad4, 0x3c060001, 0x24c6af30, 0xc53023,
-0x2203821, 0xaf420108, 0xc001751, 0xafb30010,
-0x3c040001, 0x24842e70, 0x3c050001, 0x24a5b2bc,
-0x3c060001, 0x24c6b6bc, 0xc53023, 0x2203821,
-0x3c010001, 0xac223ea0, 0xc001751, 0xafb30010,
-0x3c040001, 0x24842e84, 0x24051650, 0x2c03021,
-0x3821, 0x3c010001, 0xac223ea4, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x32c20020, 0x10400021,
-0x27a70030, 0x3c040001, 0x24842e90, 0x3c050001,
-0x24a5a960, 0x3c060001, 0x24c6aacc, 0xc53023,
-0x24022000, 0xaf42001c, 0x27a20034, 0xc001751,
+0x27b10034, 0x34420a00, 0xaf420010, 0xc00178b,
+0xafb10010, 0x3c040001, 0x24845e00, 0x3c050001,
+0x24a5b604, 0x3c060001, 0x24c6b980, 0xc53023,
+0x2603821, 0xaf420108, 0xc00178b, 0xafb10010,
+0x3c040001, 0x24845e1c, 0x3c050001, 0x24a5bda0,
+0x3c060001, 0x24c6c8a0, 0xc53023, 0x2603821,
+0x3c010001, 0xac226f70, 0xc00178b, 0xafb10010,
+0x3c040001, 0x24845e34, 0x10000024, 0x24051600,
+0x3c040001, 0x24845e3c, 0x3c050001, 0x24a5a07c,
+0x3c060001, 0x24c6a1a8, 0xc53023, 0xc00178b,
+0xafb30010, 0x3c040001, 0x24845e4c, 0x3c050001,
+0x24a5b1a0, 0x3c060001, 0x24c6b5fc, 0xc53023,
+0x2203821, 0xaf420108, 0xc00178b, 0xafb30010,
+0x3c040001, 0x24845e60, 0x3c050001, 0x24a5b988,
+0x3c060001, 0x24c6bd98, 0xc53023, 0x2203821,
+0x3c010001, 0xac226f70, 0xc00178b, 0xafb30010,
+0x3c040001, 0x24845e74, 0x24051650, 0x2c03021,
+0x3821, 0x3c010001, 0xac226f74, 0xafa00010,
+0xc002b17, 0xafa00014, 0x32c20020, 0x10400021,
+0x27a70030, 0x3c040001, 0x24845e80, 0x3c050001,
+0x24a5b02c, 0x3c060001, 0x24c6b198, 0xc53023,
+0x24022000, 0xaf42001c, 0x27a20034, 0xc00178b,
0xafa20010, 0x21900, 0x31982, 0x3c040800,
0x641825, 0xae430028, 0x24030010, 0xaf43003c,
0x96e30450, 0xaf430040, 0x8f430040, 0x3c040001,
-0x24842ea4, 0xafa00014, 0xafa30010, 0x8f47001c,
-0x24051660, 0x3c010001, 0xac223e9c, 0x10000025,
+0x24845e94, 0xafa00014, 0xafa30010, 0x8f47001c,
+0x24051660, 0x3c010001, 0xac226f6c, 0x10000025,
0x32c60020, 0x8ee20448, 0x8ee3044c, 0xaf43001c,
0x8f42001c, 0x2442e000, 0x2c422001, 0x1440000a,
-0x240e0001, 0x3c040001, 0x24842eb0, 0xa3ae003f,
+0x240e0001, 0x3c040001, 0x24845ea0, 0xa3ae003f,
0xafa00010, 0xafa00014, 0x8f46001c, 0x24051700,
-0xc0029bb, 0x3821, 0x3c020000, 0x24425b74,
+0xc002b17, 0x3821, 0x3c020000, 0x24425c5c,
0x21100, 0x21182, 0x3c030800, 0x431025,
0xae420028, 0x24020008, 0xaf42003c, 0x96e20450,
-0xaf420040, 0x8f420040, 0x3c040001, 0x24842ebc,
+0xaf420040, 0x8f420040, 0x3c040001, 0x24845eac,
0xafa00014, 0xafa20010, 0x8f47001c, 0x24051800,
-0x32c60020, 0xc0029bb, 0x0, 0x3c030001,
-0x8c633ea0, 0x3c050fff, 0x34a5ffff, 0x3c020001,
-0x8c423ea4, 0x3c040800, 0x651824, 0x31882,
+0x32c60020, 0xc002b17, 0x0, 0x3c030001,
+0x8c636f70, 0x3c050fff, 0x34a5ffff, 0x3c020001,
+0x8c426f74, 0x3c040800, 0x651824, 0x31882,
0x641825, 0x451024, 0x21082, 0x441025,
0xae420080, 0x32c20180, 0x10400056, 0xae430020,
0x8f82005c, 0x3c030080, 0x431024, 0x1040000d,
0x0, 0x8f820050, 0xafa20010, 0x8f82005c,
-0x240e0001, 0x3c040001, 0x24842ec8, 0xa3ae003f,
-0xafa20014, 0x8f870040, 0x24051900, 0xc0029bb,
+0x240e0001, 0x3c040001, 0x24845eb8, 0xa3ae003f,
+0xafa20014, 0x8f870040, 0x24051900, 0xc002b17,
0x2c03021, 0x8f820050, 0x3c030010, 0x431024,
0x10400016, 0x0, 0x8c020218, 0x30420040,
0x1040000f, 0x24020001, 0x8f820050, 0x8c030218,
-0x240e0001, 0x3c040001, 0x24842df0, 0xa3ae003f,
+0x240e0001, 0x3c040001, 0x24845de0, 0xa3ae003f,
0xafa20010, 0xafa30014, 0x8f870040, 0x24052000,
-0xc0029bb, 0x2c03021, 0x10000004, 0x0,
+0xc002b17, 0x2c03021, 0x10000004, 0x0,
0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
-0x24842ed4, 0x3c050001, 0x24a52ba0, 0x3c060001,
-0x24c62c18, 0xc53023, 0x8f420008, 0x27b30030,
+0x24845ec4, 0x3c050001, 0x24a55b50, 0x3c060001,
+0x24c65bc8, 0xc53023, 0x8f420008, 0x27b30030,
0x2603821, 0x27b10034, 0x34420e00, 0xaf420008,
-0xc001751, 0xafb10010, 0x3c040001, 0x24842eec,
-0x3c050001, 0x24a5cffc, 0x3c060001, 0x24c6db04,
-0xc53023, 0x2603821, 0xaf42010c, 0xc001751,
-0xafb10010, 0x3c040001, 0x24842f04, 0x3c050001,
-0x24a5df84, 0x3c060001, 0x24c6e6bc, 0xc53023,
-0x2603821, 0x3c010001, 0xac223eb0, 0xc001751,
-0xafb10010, 0x3c040001, 0x24842f1c, 0x10000027,
-0x24052100, 0x3c040001, 0x24842f24, 0x3c050001,
-0x24a599c8, 0x3c060001, 0x24c69b04, 0xc53023,
-0x27b10030, 0x2203821, 0x27b30034, 0xc001751,
-0xafb30010, 0x3c040001, 0x24842f34, 0x3c050001,
-0x24a5c25c, 0x3c060001, 0x24c6cff4, 0xc53023,
-0x2203821, 0xaf42010c, 0xc001751, 0xafb30010,
-0x3c040001, 0x24842f44, 0x3c050001, 0x24a5de24,
-0x3c060001, 0x24c6df7c, 0xc53023, 0x2203821,
-0x3c010001, 0xac223eb0, 0xc001751, 0xafb30010,
-0x3c040001, 0x24842f58, 0x24052150, 0x2c03021,
-0x3821, 0x3c010001, 0xac223ebc, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x3c030001, 0x8c633eb0,
-0x3c110fff, 0x3631ffff, 0x3c020001, 0x8c423ebc,
+0xc00178b, 0xafb10010, 0x3c040001, 0x24845edc,
+0x3c050001, 0x24a5d814, 0x3c060001, 0x24c6e328,
+0xc53023, 0x2603821, 0xaf42010c, 0xc00178b,
+0xafb10010, 0x3c040001, 0x24845ef4, 0x3c050001,
+0x24a5e90c, 0x3c060001, 0x24c6f050, 0xc53023,
+0x2603821, 0x3c010001, 0xac226f80, 0xc00178b,
+0xafb10010, 0x3c040001, 0x24845f0c, 0x10000027,
+0x24052100, 0x3c040001, 0x24845f14, 0x3c050001,
+0x24a59f38, 0x3c060001, 0x24c6a074, 0xc53023,
+0x27b10030, 0x2203821, 0x27b30034, 0xc00178b,
+0xafb30010, 0x3c040001, 0x24845f24, 0x3c050001,
+0x24a5ca74, 0x3c060001, 0x24c6d80c, 0xc53023,
+0x2203821, 0xaf42010c, 0xc00178b, 0xafb30010,
+0x3c040001, 0x24845f34, 0x3c050001, 0x24a5e7ac,
+0x3c060001, 0x24c6e904, 0xc53023, 0x2203821,
+0x3c010001, 0xac226f80, 0xc00178b, 0xafb30010,
+0x3c040001, 0x24845f48, 0x24052150, 0x2c03021,
+0x3821, 0x3c010001, 0xac226f8c, 0xafa00010,
+0xc002b17, 0xafa00014, 0x3c030001, 0x8c636f80,
+0x3c110fff, 0x3631ffff, 0x3c020001, 0x8c426f8c,
0x3c1e0800, 0x711824, 0x31882, 0x7e1825,
0x511024, 0x21082, 0x5e1025, 0xae430038,
0xae420078, 0x8c020218, 0x30420040, 0x14400004,
0x24020001, 0x3c010001, 0x370821, 0xa02240f4,
-0x3c040001, 0x24842f64, 0x3c050001, 0x24a52ab4,
-0x3c060001, 0x24c62b90, 0xc53023, 0x27b50030,
-0x2a03821, 0x27b30034, 0xc001751, 0xafb30010,
-0x3c010001, 0xac223ea8, 0x511024, 0x21082,
+0x3c040001, 0x24845f54, 0x3c050001, 0x24a5e330,
+0x3c060001, 0x24c6e48c, 0xc53023, 0x27b50030,
+0x2a03821, 0x27b30034, 0xc00178b, 0xafb30010,
+0x3c010001, 0xac226f78, 0x511024, 0x21082,
0x5e1025, 0xae420050, 0x32c22000, 0x10400005,
-0x2a03821, 0x3c020000, 0x24425b74, 0x1000000d,
-0x511024, 0x3c040001, 0x24842f78, 0x3c050001,
-0x24a5db0c, 0x3c060001, 0x24c6dcbc, 0xc53023,
-0xc001751, 0xafb30010, 0x3c010001, 0xac223ec0,
+0x2a03821, 0x3c020000, 0x24425c5c, 0x1000000d,
+0x511024, 0x3c040001, 0x24845f68, 0x3c050001,
+0x24a5e494, 0x3c060001, 0x24c6e644, 0xc53023,
+0xc00178b, 0xafb30010, 0x3c010001, 0xac226f90,
0x511024, 0x21082, 0x5e1025, 0xae420048,
0x32c24000, 0x10400005, 0x27a70030, 0x3c020000,
-0x24425b74, 0x1000000e, 0x21100, 0x3c040001,
-0x24842f90, 0x3c050001, 0x24a5dcc4, 0x3c060001,
-0x24c6de1c, 0xc53023, 0x27a20034, 0xc001751,
-0xafa20010, 0x3c010001, 0xac223eb4, 0x21100,
+0x24425c5c, 0x1000000e, 0x21100, 0x3c040001,
+0x24845f80, 0x3c050001, 0x24a5e64c, 0x3c060001,
+0x24c6e7a4, 0xc53023, 0x27a20034, 0xc00178b,
+0xafa20010, 0x3c010001, 0xac226f84, 0x21100,
0x21182, 0x3c030800, 0x431025, 0xae420060,
-0x3c040001, 0x24842fa8, 0x3c050000, 0x24a57c80,
-0x3c060001, 0x24c680a4, 0xc53023, 0x27b10030,
-0x2203821, 0x27b30034, 0xc001751, 0xafb30010,
-0x3c1e0fff, 0x37deffff, 0x3c040001, 0x24842fb4,
-0x3c050000, 0x24a56318, 0x3c060000, 0x24c6645c,
-0xc53023, 0x2203821, 0x3c010001, 0xac223e88,
+0x3c040001, 0x24845f98, 0x3c050001, 0x24a581d0,
+0x3c060001, 0x24c685f0, 0xc53023, 0x27b10030,
+0x2203821, 0x27b30034, 0xc00178b, 0xafb30010,
+0x3c1e0fff, 0x37deffff, 0x3c040001, 0x24845fa4,
+0x3c050000, 0x24a56408, 0x3c060000, 0x24c66528,
+0xc53023, 0x2203821, 0x3c010001, 0xac226f58,
0x5e1024, 0x21082, 0x3c150800, 0x551025,
-0xae4200b8, 0xc001751, 0xafb30010, 0x3c040001,
-0x24842fc0, 0x3c050000, 0x24a56464, 0x3c060000,
-0x24c666dc, 0xc53023, 0x2203821, 0x3c010001,
-0xac223e7c, 0x5e1024, 0x21082, 0x551025,
-0xae4200e8, 0xc001751, 0xafb30010, 0x3c040001,
-0x24842fd8, 0x3c050000, 0x24a566e4, 0x3c060000,
-0x24c66814, 0xc53023, 0x2203821, 0x3c010001,
-0xac223e74, 0x5e1024, 0x21082, 0x551025,
-0xae4200c0, 0xc001751, 0xafb30010, 0x3c040001,
-0x24842ff0, 0x3c050001, 0x24a5efb0, 0x3c060001,
-0x24c6f088, 0xc53023, 0x2203821, 0x3c010001,
-0xac223e80, 0x5e1024, 0x21082, 0x551025,
-0xae4200c8, 0xc001751, 0xafb30010, 0x3c040001,
-0x24842ffc, 0x3c050001, 0x24a529f0, 0x3c060001,
-0x24c62a78, 0xc53023, 0x2203821, 0xaf420110,
-0xc001751, 0xafb30010, 0x3c040001, 0x2484300c,
-0x3c050001, 0x24a52a80, 0x3c060001, 0x24c62aac,
-0xc53023, 0x2203821, 0xaf420114, 0xc001751,
-0xafb30010, 0x3c040001, 0x24843018, 0x3c050001,
-0x24a5e820, 0x3c060001, 0x24c6ec24, 0xc53023,
-0x2203821, 0xaf420118, 0xc001751, 0xafb30010,
-0x3c010001, 0xac223ec4, 0x5e1024, 0x21082,
-0x551025, 0xc003cfb, 0xae4200d0, 0xc0039b4,
-0x0, 0xc002628, 0x0, 0xac000228,
+0xae4200b8, 0xc00178b, 0xafb30010, 0x3c040001,
+0x24845fb0, 0x3c050000, 0x24a56530, 0x3c060000,
+0x24c667a8, 0xc53023, 0x2203821, 0x3c010001,
+0xac226f4c, 0x5e1024, 0x21082, 0x551025,
+0xae4200e8, 0xc00178b, 0xafb30010, 0x3c040001,
+0x24845fc8, 0x3c050000, 0x24a567b0, 0x3c060000,
+0x24c668e0, 0xc53023, 0x2203821, 0x3c010001,
+0xac226f44, 0x5e1024, 0x21082, 0x551025,
+0xae4200c0, 0xc00178b, 0xafb30010, 0x3c040001,
+0x24845fe0, 0x3c050001, 0x24a5fa30, 0x3c060001,
+0x24c6fb08, 0xc53023, 0x2203821, 0x3c010001,
+0xac226f50, 0x5e1024, 0x21082, 0x551025,
+0xae4200c8, 0xc00178b, 0xafb30010, 0x3c040001,
+0x24845fec, 0x3c050001, 0x24a5c8dc, 0x3c060001,
+0x24c6c9c0, 0xc53023, 0x2203821, 0xaf420110,
+0xc00178b, 0xafb30010, 0x3c040001, 0x24845ffc,
+0x3c050001, 0x24a5c8b0, 0x3c060001, 0x24c6c8d4,
+0xc53023, 0x2203821, 0xaf420124, 0xc00178b,
+0xafb30010, 0x3c040001, 0x2484600c, 0x3c050001,
+0x24a55b10, 0x3c060001, 0x24c65b3c, 0xc53023,
+0x2203821, 0xaf420120, 0xaf420114, 0xc00178b,
+0xafb30010, 0x3c040001, 0x24846018, 0x3c050001,
+0x24a5f1f8, 0x3c060001, 0x24c6f614, 0xc53023,
+0x2203821, 0xaf420118, 0xc00178b, 0xafb30010,
+0x3c010001, 0xac226f94, 0x5e1024, 0x21082,
+0x551025, 0xc003f9b, 0xae4200d0, 0xc003c18,
+0x0, 0xc002784, 0x0, 0xac000228,
0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038,
0x96e20460, 0xaf420080, 0x32c24000, 0x14400003,
0x0, 0x96e20480, 0xaf420084, 0x96e70490,
0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088,
0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000,
0x10400003, 0x24020400, 0x10e2000b, 0x0,
-0x240e0001, 0x3c040001, 0x24843028, 0xa3ae003f,
+0x240e0001, 0x3c040001, 0x24846028, 0xa3ae003f,
0x96e60490, 0x24052170, 0x2c03821, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x8f43012c, 0x8f44012c,
-0x24020001, 0xa34205b3, 0xaf430094, 0xaf440098,
+0xc002b17, 0xafa00014, 0x8f430138, 0x8f440138,
+0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098,
0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084,
-0x3c040001, 0x24843034, 0xc0029bb, 0x24052200,
-0xc002324, 0x3c110800, 0x3c1433d8, 0x3694cb58,
-0x3c020800, 0x34420080, 0x3c040001, 0x24843040,
-0x3c050000, 0x24a55bb8, 0x3c060000, 0x24c65bd4,
+0x3c040001, 0x24846034, 0xc002b17, 0x24052200,
+0xc002480, 0x3c110800, 0x3c1433d8, 0x3694cb58,
+0x3c020800, 0x34420080, 0x3c040001, 0x24846040,
+0x3c050000, 0x24a55ca0, 0x3c060000, 0x24c65cbc,
0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff,
-0xaf820064, 0x27a20034, 0xc001751, 0xafa20010,
-0x3c010001, 0xac223e64, 0x21100, 0x21182,
-0x511025, 0xc0018a8, 0xae420000, 0x8f820240,
+0xaf820064, 0x27a20034, 0xc00178b, 0xafa20010,
+0x3c010001, 0xac226f34, 0x21100, 0x21182,
+0x511025, 0xc0018e4, 0xae420000, 0x8f820240,
0x3c030001, 0x431025, 0xaf820240, 0x3c020000,
0x24424034, 0xaf820244, 0xaf800240, 0x8f820060,
0x511024, 0x14400005, 0x3c030800, 0x8f820060,
-0x431024, 0x1040fffd, 0x0, 0xc0039c1,
+0x431024, 0x1040fffd, 0x0, 0xc003c25,
0x8821, 0x3c020100, 0xafa20020, 0x8f530018,
0x240200ff, 0x56620001, 0x26710001, 0x8c020228,
-0x1622000e, 0x1330c0, 0x8f42032c, 0x24420001,
-0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001,
-0x24842d04, 0x3c050009, 0xafa00014, 0xafa20010,
+0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x24845cb4, 0x3c050009, 0xafa00014, 0xafa20010,
0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021,
0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0xc01821, 0x8f440168, 0x8f45016c, 0x1021,
+0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c,
0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
0x24070008, 0xa32821, 0xa3482b, 0x822021,
0x100f809, 0x892021, 0x1440000b, 0x24070008,
0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24842d0c, 0x3c050009, 0xafa20014, 0x8fa60020,
-0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154,
+0x24845cbc, 0x3c050009, 0xafa20014, 0x8fa60020,
+0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010,
0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c,
0x40f809, 0x24c6001c, 0x14400010, 0x0,
-0x8f420330, 0x24420001, 0xaf420330, 0x8f420330,
+0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24842d14, 0x3c050009, 0xafa20014, 0x8fa60020,
-0x34a50300, 0xc0029bb, 0x2603821, 0x8f4202d4,
-0x24420001, 0xaf4202d4, 0x8f4202d4, 0x93a2003f,
+0x24845cc4, 0x3c050009, 0xafa20014, 0x8fa60020,
+0x34a50300, 0xc002b17, 0x2603821, 0x8f4202e4,
+0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f,
0x10400069, 0x3c020700, 0x34423000, 0xafa20028,
0x8f530018, 0x240200ff, 0x12620002, 0x8821,
0x26710001, 0x8c020228, 0x1622000e, 0x1330c0,
-0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c,
-0x8c020228, 0x3c040001, 0x24842d04, 0x3c050009,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x24845cb4, 0x3c050009,
0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f,
0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c,
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168,
-0x8f45016c, 0x1021, 0x24070004, 0xafa70010,
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021,
0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
0xa3482b, 0x822021, 0x100f809, 0x892021,
0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24842d0c, 0x3c050009,
+0x8f820124, 0x3c040001, 0x24845cbc, 0x3c050009,
0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200,
-0x8f440150, 0x8f450154, 0x8f43000c, 0xaf510018,
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018,
0x8f860120, 0x24020010, 0xafa20010, 0xafb10014,
0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400010, 0x0, 0x8f420330, 0x24420001,
-0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24842d14, 0x3c050009,
-0xafa20014, 0x8fa60028, 0x34a50300, 0xc0029bb,
-0x2603821, 0x8f4202e0, 0x24420001, 0xaf4202e0,
-0x8f4202e0, 0x3c040001, 0x24843050, 0xafa00010,
-0xafa00014, 0x8fa60028, 0x24052300, 0xc0029bb,
+0x14400010, 0x0, 0x8f420340, 0x24420001,
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24845cc4, 0x3c050009,
+0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b17,
+0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0,
+0x8f4202f0, 0x3c040001, 0x24846050, 0xafa00010,
+0xafa00014, 0x8fa60028, 0x24052300, 0xc002b17,
0x3821, 0x10000004, 0x0, 0x8c020264,
0x10400005, 0x0, 0x8f8200a0, 0x30420004,
0x1440fffa, 0x0, 0x8f820044, 0x34420004,
-0xaf820044, 0x8f4202f8, 0x24420001, 0xaf4202f8,
-0x8f4202f8, 0x8f8200d8, 0x8f8300d4, 0x431023,
+0xaf820044, 0x8f420308, 0x24420001, 0xaf420308,
+0x8f420308, 0x8f8200d8, 0x8f8300d4, 0x431023,
0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81,
-0x10400006, 0x24020001, 0x8f420090, 0x8f430138,
+0x10400006, 0x24020001, 0x8f420090, 0x8f430144,
0x431021, 0xaf420090, 0x24020001, 0xaf42008c,
0x32c20008, 0x10400006, 0x0, 0x8f820214,
0x3c038100, 0x3042ffff, 0x431025, 0xaf820214,
-0x3c020001, 0x8c423d84, 0x30420001, 0x10400009,
-0x0, 0x3c040001, 0x2484305c, 0x3c050000,
-0x24a56c24, 0x3c060000, 0x24c670cc, 0x10000008,
-0xc53023, 0x3c040001, 0x2484306c, 0x3c050000,
-0x24a5681c, 0x3c060000, 0x24c66c1c, 0xc53023,
-0x27a70030, 0x27a20034, 0xc001751, 0xafa20010,
-0x3c010001, 0xac223e78, 0x3c020001, 0x8c423e78,
-0x3c030800, 0x21100, 0x21182, 0x431025,
-0xae420040, 0x8f8200a0, 0xafa20010, 0x8f8200b0,
-0xafa20014, 0x8f86005c, 0x8f87011c, 0x3c040001,
-0x2484307c, 0x3c010001, 0xac363e50, 0x3c010001,
-0xac203e40, 0x3c010001, 0xac3c3e38, 0x3c010001,
-0xac3b3e68, 0x3c010001, 0xac373e6c, 0x3c010001,
-0xac3a3e4c, 0xc0029bb, 0x24052400, 0x8f820200,
-0xafa20010, 0x8f820220, 0xafa20014, 0x8f860044,
-0x8f870050, 0x3c040001, 0x24843088, 0xc0029bb,
-0x24052500, 0x8f830060, 0x74100b, 0x242000a,
-0x200f821, 0x0, 0xd, 0x8fbf0058,
-0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
-0x27bdffe0, 0x3c040001, 0x24843094, 0x24052600,
-0x3021, 0x3821, 0xafbf0018, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x3e00008, 0x0, 0x3e00008,
+0x3c030001, 0x8c636e14, 0x30620002, 0x10400009,
+0x30620001, 0x3c040001, 0x2484605c, 0x3c050000,
+0x24a56cf0, 0x3c060000, 0x24c67168, 0x10000012,
+0xc53023, 0x10400009, 0x0, 0x3c040001,
+0x2484606c, 0x3c050000, 0x24a57170, 0x3c060000,
+0x24c67618, 0x10000008, 0xc53023, 0x3c040001,
+0x2484607c, 0x3c050000, 0x24a568e8, 0x3c060000,
+0x24c66ce8, 0xc53023, 0x27a70030, 0x27a20034,
+0xc00178b, 0xafa20010, 0x3c010001, 0xac226f48,
+0x3c020001, 0x8c426f48, 0x3c030800, 0x21100,
+0x21182, 0x431025, 0xae420040, 0x8f8200a0,
+0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c,
+0x8f87011c, 0x3c040001, 0x2484608c, 0x3c010001,
+0xac366f20, 0x3c010001, 0xac206f10, 0x3c010001,
+0xac3c6f08, 0x3c010001, 0xac3b6f38, 0x3c010001,
+0xac376f3c, 0x3c010001, 0xac3a6f1c, 0xc002b17,
+0x24052400, 0x8f820200, 0xafa20010, 0x8f820220,
+0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001,
+0x24846098, 0xc002b17, 0x24052500, 0x8f830060,
+0x74100b, 0x242000a, 0x200f821, 0x0,
+0xd, 0x8fbf0058, 0x8fbe0054, 0x8fb50050,
+0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040,
+0x3e00008, 0x27bd0060, 0x27bdffe0, 0x3c040001,
+0x248460a4, 0x24052600, 0x3021, 0x3821,
+0xafbf0018, 0xafa00010, 0xc002b17, 0xafa00014,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
+0x0, 0x3e00008, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x3e00008, 0x0,
-0x3e00008, 0x0, 0x27bdfde0, 0x27a50018,
-0x3c04dead, 0x3484beef, 0xafbf0218, 0x8f820150,
-0x3c03001f, 0x3463ffff, 0xafa40018, 0xa22823,
-0xa32824, 0x8ca20000, 0x1044000a, 0x0,
-0xafa50010, 0x8ca20000, 0xafa20014, 0x8f860150,
-0x8f870250, 0x3c040001, 0x2484309c, 0xc0029bb,
-0x24052700, 0x8fbf0218, 0x3e00008, 0x27bd0220,
-0x27bdffe0, 0x3c06abba, 0x34c6babe, 0xafb00018,
-0x3c100004, 0x3c07007f, 0x34e7ffff, 0xafbf001c,
-0x102840, 0x8e040000, 0x8ca30000, 0xaca00000,
-0xae060000, 0x8ca20000, 0xaca30000, 0x10460005,
-0xae040000, 0xa08021, 0xf0102b, 0x1040fff5,
-0x102840, 0x3c040001, 0x248430a8, 0x24052800,
-0x2003021, 0x3821, 0xafa00010, 0xc0029bb,
-0xafa00014, 0x2001021, 0x8fbf001c, 0x8fb00018,
-0x3e00008, 0x27bd0020, 0x8c020224, 0x3047003f,
-0x10e00010, 0x803021, 0x2821, 0x24030020,
-0xe31024, 0x10400002, 0x63042, 0xa62821,
-0x31842, 0x1460fffb, 0xe31024, 0x2402f000,
-0xa22824, 0x3402ffff, 0x45102b, 0x14400003,
-0x3c020001, 0x10000008, 0x3c020001, 0x3442ffff,
-0x851823, 0x43102b, 0x14400003, 0xa01021,
-0x3c02fffe, 0x821021, 0x3e00008, 0x0,
-0x27bdffd0, 0xafb50028, 0x8fb50040, 0xafb20020,
-0xa09021, 0xafb1001c, 0x24c60003, 0xafbf002c,
-0xafb30024, 0xafb00018, 0x8ea20000, 0x2403fffc,
-0xc38024, 0x50102b, 0x1440001b, 0xe08821,
-0x8e330000, 0xafb00010, 0x8ea20000, 0xafa20014,
-0x8e270000, 0x24053000, 0xc0029bb, 0x2403021,
-0x8e230000, 0x702021, 0x64102b, 0x10400007,
-0x2402821, 0x8ca20000, 0xac620000, 0x24630004,
-0x64102b, 0x1440fffb, 0x24a50004, 0x8ea20000,
-0x501023, 0xaea20000, 0x8e220000, 0x501021,
-0x1000000b, 0xae220000, 0x2402002d, 0xa0820000,
-0xafb00010, 0x8ea20000, 0x2409821, 0xafa20014,
-0x8e270000, 0x24053100, 0xc0029bb, 0x2603021,
-0x2601021, 0x8fbf002c, 0x8fb50028, 0x8fb30024,
-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
-0x27bd0030, 0x27bdffe8, 0x3c1cc000, 0x3c05fffe,
-0x3c030001, 0x8c633e30, 0x3c040001, 0x8c843e3c,
-0x34a5bf08, 0x24021ffc, 0x3c010001, 0xac223cd0,
-0x3c0200c0, 0x3c010001, 0xac223cd4, 0x3c020020,
-0xafbf0010, 0x3c0100c0, 0xac201ffc, 0x431023,
-0x441023, 0x245bb000, 0x365b821, 0x3c1d0001,
-0x8fbd3ccc, 0x3a0f021, 0x3c0400c0, 0x34840200,
-0x3c1a00c0, 0x3c0300c0, 0x346307b8, 0x24021dfc,
-0x3c010001, 0xac223cd0, 0x24021844, 0x3c010001,
-0xac243cd4, 0x3c010001, 0xac223cd0, 0x3c010001,
-0xac233cd4, 0xc0017bb, 0x375a0200, 0x8fbf0010,
-0x3e00008, 0x27bd0018, 0x27bdffc8, 0x3c040001,
-0x248430b4, 0x24053200, 0x3c020001, 0x8c423cd0,
-0x3c030001, 0x8c633cd4, 0x3021, 0x3603821,
-0xafbf0030, 0xafb3002c, 0xafb20028, 0xafb10024,
-0xafb00020, 0xafa2001c, 0xafa30018, 0xafb70010,
-0xc0029bb, 0xafba0014, 0xc0018c2, 0x0,
-0x8f820240, 0x34420004, 0xaf820240, 0x24020001,
-0xaf420000, 0x3c020001, 0x571021, 0x904240f4,
-0x10400092, 0x2403fffc, 0x3c100001, 0x2610a673,
-0x3c120001, 0x2652a24c, 0x2121023, 0x438024,
-0x8fa3001c, 0x3c040001, 0x248430c0, 0x70102b,
-0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000,
-0x2403021, 0xafb00010, 0xafa30014, 0xc0029bb,
-0x2203821, 0x8fa30018, 0x702021, 0x64102b,
-0x10400007, 0x2403021, 0x8cc20000, 0xac620000,
-0x24630004, 0x64102b, 0x1440fffb, 0x24c60004,
-0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000,
-0x501021, 0x1000000a, 0xae620000, 0x2408821,
-0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018,
-0x2203021, 0x2402002d, 0xc0029bb, 0xa0820000,
-0x24070020, 0x8fa3001c, 0x3c040001, 0x248430dc,
-0x24120020, 0x3c010001, 0xac313e5c, 0x2c620020,
-0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000,
-0x3c060001, 0x24c63ef0, 0xafa70010, 0xafa30014,
-0xc0029bb, 0x2003821, 0x8fa30018, 0x3c040001,
-0x24843ef0, 0x24650020, 0x65102b, 0x10400007,
-0x0, 0x8c820000, 0xac620000, 0x24630004,
-0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c,
-0x521023, 0xafa2001c, 0x8e220000, 0x521021,
-0x1000000b, 0xae220000, 0x3c100001, 0x26103ef0,
-0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018,
-0x2003021, 0x2402002d, 0xc0029bb, 0xa0820000,
-0x24070020, 0x3c040001, 0x248430f0, 0x8fa3001c,
-0x24120020, 0x3c010001, 0xac303e90, 0x2c620020,
-0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000,
-0x3c060001, 0x24c63f10, 0xafa70010, 0xafa30014,
-0xc0029bb, 0x2003821, 0x8fa30018, 0x3c040001,
-0x24843f10, 0x24650020, 0x65102b, 0x10400007,
-0x0, 0x8c820000, 0xac620000, 0x24630004,
-0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c,
-0x521023, 0xafa2001c, 0x8e220000, 0x521021,
-0x1000000b, 0xae220000, 0x3c100001, 0x26103f10,
-0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018,
-0x2003021, 0x2402002d, 0xc0029bb, 0xa0820000,
-0x3c010001, 0x10000031, 0xac303e8c, 0x3c100000,
-0x26107c73, 0x3c120000, 0x26527af0, 0x2121023,
-0x438024, 0x8fa3001c, 0x3c040001, 0x24843104,
-0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018,
-0x24053000, 0x2403021, 0xafb00010, 0xafa30014,
-0xc0029bb, 0x2203821, 0x8fa30018, 0x702021,
-0x64102b, 0x10400007, 0x2403021, 0x8cc20000,
+0x3e00008, 0x0, 0x3e00008, 0x0,
+0x27bdfde0, 0x27a50018, 0x3c04dead, 0x3484beef,
+0xafbf0218, 0x8f820150, 0x3c03001f, 0x3463ffff,
+0xafa40018, 0xa22823, 0xa32824, 0x8ca20000,
+0x1044000a, 0x0, 0xafa50010, 0x8ca20000,
+0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001,
+0x248460ac, 0xc002b17, 0x24052700, 0x8fbf0218,
+0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba,
+0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f,
+0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000,
+0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000,
+0xaca30000, 0x10460005, 0xae040000, 0xa08021,
+0xf0102b, 0x1040fff5, 0x102840, 0x3c040001,
+0x248460b8, 0x24052800, 0x2003021, 0x3821,
+0xafa00010, 0xc002b17, 0xafa00014, 0x2001021,
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+0x8c020224, 0x3047003f, 0x10e00010, 0x803021,
+0x2821, 0x24030020, 0xe31024, 0x10400002,
+0x63042, 0xa62821, 0x31842, 0x1460fffb,
+0xe31024, 0x2402f000, 0xa22824, 0x3402ffff,
+0x45102b, 0x14400003, 0x3c020001, 0x10000008,
+0x3c020001, 0x3442ffff, 0x851823, 0x43102b,
+0x14400003, 0xa01021, 0x3c02fffe, 0x821021,
+0x3e00008, 0x0, 0x27bdffd0, 0xafb50028,
+0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c,
+0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018,
+0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b,
+0x1440001b, 0xe08821, 0x8e330000, 0xafb00010,
+0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000,
+0xc002b17, 0x2403021, 0x8e230000, 0x702021,
+0x64102b, 0x10400007, 0x2402821, 0x8ca20000,
0xac620000, 0x24630004, 0x64102b, 0x1440fffb,
-0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c,
-0x8e620000, 0x501021, 0x1000000a, 0xae620000,
-0x2408821, 0x24053100, 0xafb00010, 0xafa30014,
-0x8fa70018, 0x2203021, 0x2402002d, 0xc0029bb,
-0xa0820000, 0x3c010001, 0xac313e5c, 0x3c030001,
-0x8c633e5c, 0x24020400, 0x60f809, 0xaf820070,
-0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024,
-0x8fb00020, 0x3e00008, 0x27bd0038, 0x8f820040,
+0x24a50004, 0x8ea20000, 0x501023, 0xaea20000,
+0x8e220000, 0x501021, 0x1000000b, 0xae220000,
+0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000,
+0x2409821, 0xafa20014, 0x8e270000, 0x24053100,
+0xc002b17, 0x2603021, 0x2601021, 0x8fbf002c,
+0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8,
+0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636f00,
+0x3c040001, 0x8c846f0c, 0x34a5bf08, 0x24021ffc,
+0x3c010001, 0xac226d50, 0x3c0200c0, 0x3c010001,
+0xac226d54, 0x3c020020, 0xafbf0010, 0x3c0100c0,
+0xac201ffc, 0x431023, 0x441023, 0x245bb000,
+0x365b821, 0x3c1d0001, 0x8fbd6d4c, 0x3a0f021,
+0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0,
+0x346307c8, 0x24021dfc, 0x3c010001, 0xac226d50,
+0x24021834, 0x3c010001, 0xac246d54, 0x3c010001,
+0xac226d50, 0x3c010001, 0xac236d54, 0xc0017f5,
+0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffc8, 0x3c040001, 0x248460c4, 0x24053200,
+0x3c020001, 0x8c426d50, 0x3c030001, 0x8c636d54,
+0x3021, 0x3603821, 0xafbf0030, 0xafb3002c,
+0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c,
+0xafa30018, 0xafb70010, 0xc002b17, 0xafba0014,
+0xc0018fe, 0x0, 0x8f820240, 0x34420004,
+0xaf820240, 0x24020001, 0xaf420000, 0x3c020001,
+0x571021, 0x904240f4, 0x10400092, 0x2403fffc,
+0x3c100001, 0x2610abe3, 0x3c120001, 0x2652a7bc,
+0x2121023, 0x438024, 0x8fa3001c, 0x3c040001,
+0x248460d0, 0x70102b, 0x1440001a, 0x27b30018,
+0x8fb10018, 0x24053000, 0x2403021, 0xafb00010,
+0xafa30014, 0xc002b17, 0x2203821, 0x8fa30018,
+0x702021, 0x64102b, 0x10400007, 0x2403021,
+0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
+0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023,
+0xafa2001c, 0x8e620000, 0x501021, 0x1000000a,
+0xae620000, 0x2408821, 0x24053100, 0xafb00010,
+0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d,
+0xc002b17, 0xa0820000, 0x24070020, 0x8fa3001c,
+0x3c040001, 0x248460ec, 0x24120020, 0x3c010001,
+0xac316f2c, 0x2c620020, 0x1440001d, 0x27b10018,
+0x8fb00018, 0x24053000, 0x3c060001, 0x24c66fd0,
+0xafa70010, 0xafa30014, 0xc002b17, 0x2003821,
+0x8fa30018, 0x3c040001, 0x24846fd0, 0x24650020,
+0x65102b, 0x10400007, 0x0, 0x8c820000,
+0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+0x3c100001, 0x26106fd0, 0x24053100, 0xafa70010,
+0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+0xc002b17, 0xa0820000, 0x24070020, 0x3c040001,
+0x24846100, 0x8fa3001c, 0x24120020, 0x3c010001,
+0xac306f60, 0x2c620020, 0x1440001d, 0x27b10018,
+0x8fb00018, 0x24053000, 0x3c060001, 0x24c66ff0,
+0xafa70010, 0xafa30014, 0xc002b17, 0x2003821,
+0x8fa30018, 0x3c040001, 0x24846ff0, 0x24650020,
+0x65102b, 0x10400007, 0x0, 0x8c820000,
+0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+0x3c100001, 0x26106ff0, 0x24053100, 0xafa70010,
+0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+0xc002b17, 0xa0820000, 0x3c010001, 0x10000031,
+0xac306f5c, 0x3c100001, 0x261081bf, 0x3c120001,
+0x2652803c, 0x2121023, 0x438024, 0x8fa3001c,
+0x3c040001, 0x24846114, 0x70102b, 0x1440001a,
+0x27b30018, 0x8fb10018, 0x24053000, 0x2403021,
+0xafb00010, 0xafa30014, 0xc002b17, 0x2203821,
+0x8fa30018, 0x702021, 0x64102b, 0x10400007,
+0x2403021, 0x8cc20000, 0xac620000, 0x24630004,
+0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c,
+0x501023, 0xafa2001c, 0x8e620000, 0x501021,
+0x1000000a, 0xae620000, 0x2408821, 0x24053100,
+0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021,
+0x2402002d, 0xc002b17, 0xa0820000, 0x3c010001,
+0xac316f2c, 0x3c030001, 0x8c636f2c, 0x24020400,
+0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c,
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0038, 0x0, 0x0, 0x8f820040,
0x3c03f000, 0x431024, 0x3c036000, 0x14430006,
0x0, 0x8f820050, 0x2403ff80, 0x431024,
0x34420055, 0xaf820050, 0x8f820054, 0x244203e8,
0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004,
-0xaf4200e8, 0x24020002, 0xaf4001a0, 0xaf4000e4,
+0xaf4200e8, 0x24020002, 0xaf4001b0, 0xaf4000e4,
0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008,
0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008,
0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054,
0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024,
0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024,
-0x36940040, 0x3c020001, 0x8c423d98, 0x10400020,
-0x3c020200, 0x934305b1, 0x10600007, 0x282a025,
-0xa34005b1, 0x8f820220, 0x3c0308ff, 0x3463fffb,
-0x431024, 0xaf820220, 0x3c020001, 0x8c423ec8,
-0x10400016, 0x3c020200, 0x3c020001, 0x8c423e14,
-0x14400012, 0x3c020200, 0x3c020001, 0x8c423d84,
-0x30420001, 0x1440000d, 0x3c020200, 0x8f830224,
-0x3c020001, 0x8c425f8c, 0x10620008, 0x3c020200,
-0xc003b0b, 0x0, 0x10000004, 0x3c020200,
-0xc003e84, 0x0, 0x3c020200, 0x2c21024,
-0x10400003, 0x0, 0xc001de0, 0x0,
-0x8f4200d8, 0x8f4300dc, 0x24420001, 0xaf4200d8,
-0x43102b, 0x14400003, 0x0, 0xaf4000d8,
-0x36940080, 0x8c030238, 0x1060000c, 0x0,
-0x8f4201a0, 0x244203e8, 0xaf4201a0, 0x43102b,
-0x14400006, 0x0, 0x934205b6, 0x14400003,
-0x0, 0xc001c35, 0x0, 0x8fbf0010,
-0x3e00008, 0x27bd0018, 0x3e00008, 0x0,
-0x27bdffd8, 0xafbf0020, 0x8f43002c, 0x8f420038,
-0x10620059, 0x0, 0x3c020001, 0x571021,
-0x904240f0, 0x10400026, 0x24070008, 0x8f440160,
-0x8f450164, 0x8f48000c, 0x8f860120, 0x24020020,
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
-0x3c010001, 0x370821, 0xa02240f0, 0x8f820124,
-0xafa20010, 0x8f820128, 0x3c040001, 0x248431a8,
-0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009,
-0xc0029bb, 0x34a50900, 0x1000005c, 0x0,
-0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0,
-0x8f42002c, 0xa34005b2, 0x10000027, 0xaf420038,
-0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c,
-0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x248431b4, 0xafa20014, 0x8f46002c,
-0x8f870120, 0x3c050009, 0xc0029bb, 0x34a51100,
-0x10000036, 0x0, 0x8f4202f0, 0x8f43002c,
-0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001,
-0xa34205b2, 0xaf430038, 0x3c010001, 0x370821,
-0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0,
-0x10000026, 0xaf400034, 0x934205b2, 0x1040001d,
-0x0, 0xa34005b2, 0x8f820040, 0x30420001,
-0x14400008, 0x2021, 0x8c030104, 0x24020001,
-0x50620005, 0x24040001, 0x8c020264, 0x10400003,
-0x801021, 0x24040001, 0x801021, 0x10400006,
-0x0, 0x8f4202fc, 0x24420001, 0xaf4202fc,
-0x10000008, 0x8f4202fc, 0x8f820044, 0x34420004,
-0xaf820044, 0x8f4202f8, 0x24420001, 0xaf4202f8,
-0x8f4202f8, 0x3c010001, 0x370821, 0xa02040f0,
-0x3c010001, 0x370821, 0xa02040f1, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x3c03ff7f, 0x3463ffff, 0x431024,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0020,
-0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
-0x27bdffd8, 0xafbf0020, 0x8f430044, 0x8f42007c,
-0x10620029, 0x24070008, 0x8f440158, 0x8f45015c,
-0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010,
+0x36940040, 0x3c020001, 0x8c426e28, 0x10400017,
+0x3c020200, 0x3c030001, 0x8c636f98, 0x10600016,
+0x282a025, 0x3c020001, 0x8c426ec4, 0x14400012,
+0x3c020200, 0x3c020001, 0x8c426e14, 0x30420003,
+0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002,
+0x8c42906c, 0x10620008, 0x3c020200, 0xc003d87,
+0x0, 0x10000004, 0x3c020200, 0xc004161,
+0x0, 0x3c020200, 0x2c21024, 0x10400003,
+0x0, 0xc001f33, 0x0, 0x8f4200d8,
+0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b,
+0x14400003, 0x0, 0xaf4000d8, 0x36940080,
+0x8c030238, 0x1060000c, 0x0, 0x8f4201b0,
+0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006,
+0x0, 0x934205c5, 0x14400003, 0x0,
+0xc001d88, 0x0, 0x8fbf0010, 0x3e00008,
+0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8,
+0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059,
+0x0, 0x3c020001, 0x571021, 0x904240f0,
+0x10400026, 0x24070008, 0x8f440170, 0x8f450174,
+0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010,
0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f2, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x248431bc, 0xafa20014,
-0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb,
-0x34a51300, 0x1000000f, 0x0, 0x8f4202f4,
-0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044,
-0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2,
-0x10000004, 0xaf400078, 0x3c010001, 0x370821,
-0xa02040f2, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x3c03feff,
-0x3463ffff, 0x431024, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x10000002, 0xaf80004c,
-0xaf800048, 0x8fbf0020, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x3c020001, 0x8c423d98,
-0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048,
-0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038,
-0x104000d5, 0x8f900044, 0x8f4200d0, 0x24430001,
-0x2842000b, 0x144000e4, 0xaf4300d0, 0x8f420004,
-0x30420002, 0x1440009c, 0xaf4000d0, 0x8f420004,
-0x3c030001, 0x8c633d88, 0x34420002, 0xaf420004,
+0x370821, 0xa02240f0, 0x8f820124, 0xafa20010,
+0x8f820128, 0x3c040001, 0x248461b8, 0xafa20014,
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b17,
+0x34a50900, 0x1000005c, 0x0, 0x8f420300,
+0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c,
+0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170,
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x248461c4, 0xafa20014, 0x8f46002c, 0x8f870120,
+0x3c050009, 0xc002b17, 0x34a51100, 0x10000036,
+0x0, 0x8f420300, 0x8f43002c, 0x24420001,
+0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
+0xaf430038, 0x3c010001, 0x370821, 0xa02040f1,
+0x3c010001, 0x370821, 0xa02040f0, 0x10000026,
+0xaf400034, 0x934205c1, 0x1040001d, 0x0,
+0xa34005c1, 0x8f820040, 0x30420001, 0x14400008,
+0x2021, 0x8c030104, 0x24020001, 0x50620005,
+0x24040001, 0x8c020264, 0x10400003, 0x801021,
+0x24040001, 0x801021, 0x10400006, 0x0,
+0x8f42030c, 0x24420001, 0xaf42030c, 0x10000008,
+0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
+0x8f420308, 0x24420001, 0xaf420308, 0x8f420308,
+0x3c010001, 0x370821, 0xa02040f0, 0x3c010001,
+0x370821, 0xa02040f1, 0x8f420000, 0x10400007,
+0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+0x0, 0x10000005, 0x0, 0xaf800048,
+0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x10000002,
+0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008,
+0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8,
+0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029,
+0x24070008, 0x8f440168, 0x8f45016c, 0x8f48000c,
+0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x248461cc, 0xafa20014, 0x8f460044,
+0x8f870120, 0x3c050009, 0xc002b17, 0x34a51300,
+0x1000000f, 0x0, 0x8f420304, 0x24420001,
+0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
+0x3c010001, 0x370821, 0xa02040f2, 0x10000004,
+0xaf400078, 0x3c010001, 0x370821, 0xa02040f2,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x3c03feff, 0x3463ffff,
+0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
+0x0, 0x3c020001, 0x8c426e28, 0x27bdffa8,
+0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
+0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5,
+0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b,
+0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002,
+0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001,
+0x8c636e18, 0x34420002, 0xaf420004, 0x24020001,
+0x14620003, 0x3c020600, 0x10000002, 0x34423000,
+0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034,
+0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff,
+0x11420002, 0x1821, 0x25430001, 0x8c020228,
+0x609821, 0x1662000e, 0x3c050009, 0x8f42033c,
+0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+0x8fa70034, 0x3c040001, 0x2484619c, 0xafa00014,
+0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500,
+0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020,
+0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
+0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
+0x1040001b, 0xa821, 0xe09021, 0x265e04c0,
+0x8f440178, 0x8f45017c, 0x2401821, 0x240a0004,
+0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021,
+0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008,
+0xa32821, 0xa3482b, 0x822021, 0x100f809,
+0x892021, 0x54400006, 0x24150001, 0x8f820054,
+0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0,
+0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124,
+0x3c040001, 0x248461a8, 0xafa20014, 0x8d460000,
+0x3c050009, 0x10000035, 0x34a50600, 0x8f420308,
+0x24150001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054,
+0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016,
+0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c,
+0x8f440160, 0x8f450164, 0x8f860120, 0xafb20010,
+0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c,
+0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
+0x0, 0x8f820054, 0x2221023, 0x2c4203e9,
+0x1440ffee, 0x0, 0x32a200ff, 0x14400011,
+0x3c050009, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034,
+0xafa20010, 0x8f820124, 0x3c040001, 0x248461b0,
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b17,
+0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec,
+0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029,
+0x36100040, 0x3c020400, 0x2c21024, 0x10400013,
+0x2404ffdf, 0x8f420250, 0x8f430254, 0x8f4401b4,
+0x14640006, 0x36100040, 0x8f420270, 0x8f430274,
+0x8f4401b8, 0x10640007, 0x2402ffdf, 0x8f420250,
+0x8f430254, 0x8f440270, 0x8f450274, 0x10000012,
+0x3a100020, 0x1000002b, 0x2028024, 0x8f420250,
+0x8f430254, 0x8f4501b4, 0x14650006, 0x2048024,
+0x8f420270, 0x8f430274, 0x8f4401b8, 0x50640021,
+0x36100040, 0x8f420250, 0x8f430254, 0x8f440270,
+0x8f450274, 0x3a100040, 0xaf4301b4, 0x10000019,
+0xaf4501b8, 0x8f4200d4, 0x24430001, 0x10000011,
+0x28420033, 0x8f420004, 0x30420001, 0x10400009,
+0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf,
+0x2028024, 0x1000000b, 0x36100040, 0x10000009,
+0x36100060, 0x8f4200d4, 0x36100040, 0x24430001,
+0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4,
+0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024,
+0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
+0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
+0x27bd0058, 0x3e00008, 0x0, 0x3c020001,
+0x8c426e28, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001,
+0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004,
+0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004,
+0x3c030001, 0x8c636e18, 0x34420002, 0xaf420004,
0x24020001, 0x14620003, 0x3c020600, 0x10000002,
-0x34423000, 0x34421000, 0xafa20020, 0x8f4a0018,
-0xafaa0034, 0x27aa0020, 0xafaa002c, 0x8faa0034,
-0x240200ff, 0x11420002, 0x1821, 0x25430001,
-0x8c020228, 0x609821, 0x1662000e, 0x3c050009,
-0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c,
-0x8c020228, 0x8fa70034, 0x3c040001, 0x2484318c,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x10000070,
-0x34a50500, 0x8faa0034, 0xa38c0, 0xf71021,
+0x34423000, 0x34421000, 0xafa20020, 0x1821,
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x2484619c, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021,
0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247103e8, 0x2221023,
-0x2c4203e9, 0x1040001b, 0xa821, 0xe09021,
-0x265e04c0, 0x8f440168, 0x8f45016c, 0x2401821,
-0x240a0004, 0xafaa0010, 0xafb30014, 0x8f48000c,
-0x1021, 0x2fe3021, 0xafa80018, 0x8f48010c,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24150001,
-0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x32a200ff, 0x54400018, 0xaf530018,
-0x8f420368, 0x24420001, 0xaf420368, 0x8f420368,
-0x8f820120, 0x8faa002c, 0x8fa70034, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24843198, 0xafa20014,
-0x8d460000, 0x3c050009, 0x10000035, 0x34a50600,
-0x8f4202f8, 0x24150001, 0x24420001, 0xaf4202f8,
-0x8f4202f8, 0x1000001e, 0x32a200ff, 0x8f830054,
-0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
-0x10400016, 0xa821, 0x3c1e0020, 0x24120010,
-0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120,
-0xafb20010, 0xafb30014, 0x5e1025, 0xafa20018,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x248461a8, 0x3c050009, 0xafa20014,
+0x8d460000, 0x10000035, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016,
+0x9821, 0x3c150020, 0x24110010, 0x8f42000c,
+0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010,
+0xafb20014, 0x551025, 0xafa20018, 0x8f42010c,
+0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
+0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffee, 0x0, 0x326200ff, 0x14400011,
+0x0, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x248461b0, 0x3c050009,
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b17,
+0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec,
+0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018,
+0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4,
+0x3c010001, 0x14650006, 0xa0246d71, 0x8f420270,
+0x8f430274, 0x8f4401b8, 0x10640021, 0x0,
+0x8f420250, 0x8f430254, 0x3c040001, 0x90846d70,
+0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4,
+0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246d70,
+0x8f4200d4, 0x3c010001, 0xa0206d70, 0x24430001,
+0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001,
+0x90426d71, 0xaf4000d4, 0x10000017, 0x38420001,
+0x8f420004, 0x30420001, 0x10400008, 0x0,
+0xc00567e, 0x2021, 0x3c010001, 0xa0206d71,
+0x3c010001, 0x1000000e, 0xa0206d70, 0x8f4200d4,
+0x3c010001, 0xa0206d70, 0x24430001, 0x284201f5,
+0x14400007, 0xaf4300d4, 0x3c020001, 0x90426d71,
+0xaf4000d4, 0x421026, 0x3c010001, 0xa0226d71,
+0x3c030001, 0x8c636e18, 0x24020002, 0x1462000c,
+0x3c030002, 0x3c030001, 0x90636d71, 0x24020001,
+0x5462001f, 0x2021, 0x3c020001, 0x90426d70,
+0x1443001b, 0x24040005, 0x10000019, 0x24040006,
+0x3c020002, 0x8c429074, 0x431024, 0x1040000b,
+0x24020001, 0x3c030001, 0x90636d71, 0x54620010,
+0x2021, 0x3c020001, 0x90426d70, 0x1443000c,
+0x24040003, 0x1000000a, 0x24040004, 0x3c030001,
+0x90636d71, 0x14620006, 0x2021, 0x3c020001,
+0x90426d70, 0x24040001, 0x50440001, 0x24040002,
+0xc00567e, 0x0, 0x2402ff7f, 0x282a024,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x3e00008, 0x0, 0x3c020001,
+0x8c426e28, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001,
+0x8c846e18, 0x24430001, 0x2842000b, 0xaf4400e8,
+0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002,
+0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002,
+0xaf420004, 0x24020001, 0x14820003, 0x3c020600,
+0x10000002, 0x34423000, 0x34421000, 0xafa20020,
+0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
+0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
+0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
+0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+0x3c040001, 0x2484619c, 0x3c050009, 0xafa00014,
+0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
+0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
+0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
+0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
+0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
+0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
+0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
+0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
+0x822021, 0x100f809, 0x892021, 0x54400006,
+0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
+0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x248461a8, 0x3c050009,
+0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
+0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
+0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
+0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
+0x10400016, 0x9821, 0x3c150020, 0x24110010,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
-0x1440ffe3, 0x0, 0x8f820054, 0x2221023,
-0x2c4203e9, 0x1440ffee, 0x0, 0x32a200ff,
-0x14400011, 0x3c050009, 0x8f420368, 0x24420001,
-0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c,
-0x8fa70034, 0xafa20010, 0x8f820124, 0x3c040001,
-0x248431a0, 0xafa20014, 0x8d460000, 0x34a50700,
-0xc0029bb, 0x0, 0x8f4202dc, 0x24420001,
-0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001,
-0x50400029, 0x36100040, 0x3c020400, 0x2c21024,
-0x10400013, 0x2404ffdf, 0x8f420240, 0x8f430244,
-0x8f4401a4, 0x14640006, 0x36100040, 0x8f420260,
-0x8f430264, 0x8f4401a8, 0x10640007, 0x2402ffdf,
-0x8f420240, 0x8f430244, 0x8f440260, 0x8f450264,
-0x10000012, 0x3a100020, 0x1000002b, 0x2028024,
-0x8f420240, 0x8f430244, 0x8f4501a4, 0x14650006,
-0x2048024, 0x8f420260, 0x8f430264, 0x8f4401a8,
-0x50640021, 0x36100040, 0x8f420240, 0x8f430244,
-0x8f440260, 0x8f450264, 0x3a100040, 0xaf4301a4,
-0x10000019, 0xaf4501a8, 0x8f4200d4, 0x24430001,
-0x10000011, 0x28420033, 0x8f420004, 0x30420001,
-0x10400009, 0x3c020400, 0x2c21024, 0x10400004,
-0x2402ffdf, 0x2028024, 0x1000000b, 0x36100040,
-0x10000009, 0x36100060, 0x8f4200d4, 0x36100040,
-0x24430001, 0x284201f5, 0x14400003, 0xaf4300d4,
-0xaf4000d4, 0x3a100020, 0xaf900044, 0x2402ff7f,
-0x282a024, 0x8fbf0050, 0x8fbe004c, 0x8fb50048,
-0x8fb30044, 0x8fb20040, 0x8fb1003c, 0x8fb00038,
-0x3e00008, 0x27bd0058, 0x3e00008, 0x0,
-0x3c020001, 0x8c423d98, 0x27bdffb0, 0xafbf0048,
-0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038,
-0xafb10034, 0x104000de, 0xafb00030, 0x8f4200d0,
-0x3c040001, 0x8c843d88, 0x24430001, 0x2842000b,
-0xaf4400e8, 0x144000fe, 0xaf4300d0, 0x8f420004,
-0x30420002, 0x14400095, 0xaf4000d0, 0x8f420004,
-0x34420002, 0xaf420004, 0x24020001, 0x14820003,
-0x3c020600, 0x10000002, 0x34423000, 0x34421000,
-0xafa20020, 0x1821, 0x8f5e0018, 0x27aa0020,
-0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001,
-0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
-0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c,
-0x8c020228, 0x3c040001, 0x2484318c, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
-0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
-0x9821, 0xe08821, 0x263504c0, 0x8f440168,
-0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010,
-0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x54400006, 0x24130001, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
-0x54400017, 0xaf520018, 0x8f420368, 0x24420001,
-0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24843198,
-0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
-0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001,
-0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff,
+0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
+0x14400011, 0x0, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x248461b0,
+0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
+0xc002b17, 0x3c03821, 0x8f4202ec, 0x24420001,
+0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
+0x10400033, 0x3c020400, 0x2c21024, 0x10400017,
+0x0, 0x934205c0, 0x8f440250, 0x8f450254,
+0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0,
+0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008,
+0x0, 0x8f420250, 0x8f430254, 0x934405c0,
+0x8f460270, 0x8f470274, 0x10000016, 0x38840040,
+0x934205c0, 0x10000048, 0x304200bf, 0x934205c0,
+0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf,
+0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274,
+0x8f4401b8, 0x1064000b, 0x0, 0x8f420250,
+0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274,
+0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033,
+0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020,
+0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0,
+0x24620001, 0x10000023, 0x28630033, 0x8f4200e4,
+0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a,
+0x14400006, 0x24030001, 0x8f4200e8, 0x14430002,
+0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004,
+0x30420001, 0x1040000d, 0x3c020400, 0x2c21024,
+0x10400007, 0x0, 0x934205c0, 0x34420040,
+0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df,
+0x934205c0, 0x1000000c, 0x34420060, 0x934205c0,
+0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001,
+0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0,
+0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0,
+0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001,
+0x14620005, 0x0, 0x934405c0, 0x42102,
+0x10000003, 0x348400f0, 0x934405c0, 0x3484000f,
+0xc005664, 0x0, 0x2402ff7f, 0x282a024,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0,
+0x274401c0, 0x26e30028, 0x24650400, 0x65102b,
+0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
+0xafb20038, 0xafb10034, 0x10400007, 0xafb00030,
+0x8c820000, 0xac620000, 0x24630004, 0x65102b,
+0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044,
+0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030,
+0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240,
+0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248,
+0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250,
+0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258,
+0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260,
+0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268,
+0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270,
+0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034,
+0x41080, 0x571021, 0x8ee30034, 0x8c42023c,
+0x24840001, 0x621821, 0x2c82000f, 0xaee30034,
+0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048,
+0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8,
+0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200,
+0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208,
+0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b,
+0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4,
+0x24040001, 0x24050000, 0x651821, 0x65302b,
+0x441021, 0x461021, 0xaee200c0, 0xaee300c4,
+0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff,
+0x24090000, 0x401821, 0x1021, 0x882024,
+0xa92824, 0x822025, 0xa32825, 0xaee400c0,
+0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4,
+0x45102b, 0x1040000b, 0x0, 0x8ee200d0,
+0x8ee300d4, 0x24040001, 0x24050000, 0x651821,
+0x65302b, 0x441021, 0x461021, 0xaee200d0,
+0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4,
+0x401821, 0x1021, 0x882024, 0xa92824,
+0x822025, 0xa32825, 0xaee400d0, 0xaee500d4,
+0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b,
+0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc,
+0x24040001, 0x24050000, 0x651821, 0x65302b,
+0x441021, 0x461021, 0xaee200c8, 0xaee300cc,
+0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821,
+0x1021, 0x882024, 0xa92824, 0x822025,
+0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc,
+0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208,
+0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028,
+0x40f809, 0x24070400, 0x104000f0, 0x3c020400,
+0xafa20020, 0x934205c6, 0x10400089, 0x1821,
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x2484619c, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
-0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154,
-0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x248461a8, 0x3c050009, 0xafa20014,
+0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420368,
-0x24420001, 0xaf420368, 0x8f420368, 0x8f820120,
+0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+0x326200ff, 0x54400012, 0x24020001, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x248431a0, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202dc,
-0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8f420004,
-0x30420001, 0x10400033, 0x3c020400, 0x2c21024,
-0x10400017, 0x0, 0x934205b0, 0x8f440240,
-0x8f450244, 0x8f4301a4, 0x34420020, 0x14a30006,
-0xa34205b0, 0x8f420260, 0x8f430264, 0x8f4401a8,
-0x10640008, 0x0, 0x8f420240, 0x8f430244,
-0x934405b0, 0x8f460260, 0x8f470264, 0x10000016,
-0x38840040, 0x934205b0, 0x10000048, 0x304200bf,
-0x934205b0, 0x8f440240, 0x8f450244, 0x8f4301a4,
-0x304200bf, 0x14a30006, 0xa34205b0, 0x8f420260,
-0x8f430264, 0x8f4401a8, 0x1064000b, 0x0,
-0x8f420240, 0x8f430244, 0x934405b0, 0x8f460260,
-0x8f470264, 0x38840020, 0xaf4301a4, 0xaf4701a8,
-0x10000033, 0xa34405b0, 0x934205b0, 0x1000002f,
-0x34420020, 0x934205b0, 0x8f4300d4, 0x34420020,
-0xa34205b0, 0x24620001, 0x10000023, 0x28630033,
-0x8f4200e4, 0x8f4300e0, 0x24420001, 0xaf4200e4,
-0x43102a, 0x14400006, 0x24030001, 0x8f4200e8,
-0x14430002, 0xaf4000e4, 0x24030004, 0xaf4300e8,
-0x8f420004, 0x30420001, 0x1040000d, 0x3c020400,
-0x2c21024, 0x10400007, 0x0, 0x934205b0,
-0x34420040, 0xa34205b0, 0x934205b0, 0x1000000f,
-0x304200df, 0x934205b0, 0x1000000c, 0x34420060,
-0x934205b0, 0x8f4300d4, 0x34420020, 0xa34205b0,
-0x24620001, 0x286300fb, 0x14600005, 0xaf4200d4,
-0x934205b0, 0xaf4000d4, 0x38420040, 0xa34205b0,
-0x934205b0, 0x8f4300e8, 0x3042007f, 0xa34205b0,
-0x24020001, 0x14620005, 0x0, 0x934405b0,
-0x42102, 0x10000003, 0x348400f0, 0x934405b0,
-0x3484000f, 0xc004a60, 0x0, 0x2402ff7f,
-0x282a024, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+0x248461b0, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002b17, 0x3c03821, 0x1021,
+0x1440005b, 0x24020001, 0x10000065, 0x0,
+0x8f510018, 0x240200ff, 0x12220002, 0x8021,
+0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x24846184, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
+0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x2484618c, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
+0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x54400011, 0x24020001, 0x8f420340, 0x24420001,
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24846194, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b17,
+0x2203821, 0x1021, 0x1040000d, 0x24020001,
+0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001,
+0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001,
+0xaee20150, 0x10000003, 0x8ee20150, 0x24020001,
+0xa34205c6, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
-0x3e00008, 0x27bd0050, 0x3e00008, 0x0,
-0x27bdffb0, 0x274401b0, 0x26e30028, 0x24650400,
-0x65102b, 0xafbf0048, 0xafbe0044, 0xafb50040,
-0xafb3003c, 0xafb20038, 0xafb10034, 0x10400007,
-0xafb00030, 0x8c820000, 0xac620000, 0x24630004,
-0x65102b, 0x1440fffb, 0x24840004, 0x8c020080,
-0xaee20044, 0x8c0200c0, 0xaee20040, 0x8c020084,
-0xaee20030, 0x8c020084, 0xaee2023c, 0x8c020088,
-0xaee20240, 0x8c02008c, 0xaee20244, 0x8c020090,
-0xaee20248, 0x8c020094, 0xaee2024c, 0x8c020098,
-0xaee20250, 0x8c02009c, 0xaee20254, 0x8c0200a0,
-0xaee20258, 0x8c0200a4, 0xaee2025c, 0x8c0200a8,
-0xaee20260, 0x8c0200ac, 0xaee20264, 0x8c0200b0,
-0xaee20268, 0x8c0200b4, 0xaee2026c, 0x8c0200b8,
-0xaee20270, 0x8c0200bc, 0x24040001, 0xaee20274,
-0xaee00034, 0x41080, 0x571021, 0x8ee30034,
-0x8c42023c, 0x24840001, 0x621821, 0x2c82000f,
-0xaee30034, 0x1440fff8, 0x41080, 0x8c0200cc,
-0xaee20048, 0x8c0200d0, 0xaee2004c, 0x8c0200e0,
-0xaee201f8, 0x8c0200e4, 0xaee201fc, 0x8c0200e8,
-0xaee20200, 0x8c0200ec, 0xaee20204, 0x8c0200f0,
-0xaee20208, 0x8ee400c0, 0x8ee500c4, 0x8c0200fc,
-0x45102b, 0x1040000b, 0x0, 0x8ee200c0,
-0x8ee300c4, 0x24040001, 0x24050000, 0x651821,
-0x65302b, 0x441021, 0x461021, 0xaee200c0,
-0xaee300c4, 0x8c0200fc, 0x8ee400c0, 0x8ee500c4,
-0x2408ffff, 0x24090000, 0x401821, 0x1021,
-0x882024, 0xa92824, 0x822025, 0xa32825,
-0xaee400c0, 0xaee500c4, 0x8ee400d0, 0x8ee500d4,
-0x8c0200f4, 0x45102b, 0x1040000b, 0x0,
-0x8ee200d0, 0x8ee300d4, 0x24040001, 0x24050000,
-0x651821, 0x65302b, 0x441021, 0x461021,
-0xaee200d0, 0xaee300d4, 0x8c0200f4, 0x8ee400d0,
-0x8ee500d4, 0x401821, 0x1021, 0x882024,
-0xa92824, 0x822025, 0xa32825, 0xaee400d0,
-0xaee500d4, 0x8ee400c8, 0x8ee500cc, 0x8c0200f8,
-0x45102b, 0x1040000b, 0x0, 0x8ee200c8,
-0x8ee300cc, 0x24040001, 0x24050000, 0x651821,
-0x65302b, 0x441021, 0x461021, 0xaee200c8,
-0xaee300cc, 0x8c0200f8, 0x8ee400c8, 0x8ee500cc,
-0x401821, 0x1021, 0x882024, 0xa92824,
-0x822025, 0xa32825, 0x24020008, 0xaee400c8,
-0xaee500cc, 0xafa20010, 0xafa00014, 0x8f42000c,
+0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020,
+0x8f8200b0, 0x30420004, 0x10400068, 0x0,
+0x8f430128, 0x8f820104, 0x14620005, 0x0,
+0x8f430130, 0x8f8200b4, 0x10620006, 0x0,
+0x8f820104, 0xaf420128, 0x8f8200b4, 0x1000005b,
+0xaf420130, 0x8f8200b0, 0x3c030080, 0x431024,
+0x1040000d, 0x0, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024,
+0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024,
+0x1000004a, 0xaf82011c, 0x8f430128, 0x8f820104,
+0x14620005, 0x0, 0x8f430130, 0x8f8200b4,
+0x10620010, 0x0, 0x8f820104, 0xaf420128,
+0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010,
+0x8f420130, 0x3c040001, 0x248461d4, 0xafa20014,
+0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031,
+0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130,
+0x3c040001, 0x248461e0, 0xafa20014, 0x8f86011c,
+0x8f8700b0, 0x3c050005, 0xc002b17, 0x34a51000,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104,
+0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008,
+0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c,
0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c,
-0x26e60028, 0x40f809, 0x24070400, 0x104000f0,
-0x3c020400, 0xafa20020, 0x934205b7, 0x10400089,
-0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
-0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
-0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c,
-0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228,
-0x3c040001, 0x2484318c, 0x3c050009, 0xafa00014,
+0x26e60028, 0x40f809, 0x24070400, 0x8f82011c,
+0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
+0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128,
+0xafa20010, 0x8f420130, 0x3c040001, 0x248461ec,
+0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
+0x34a51100, 0xc002b17, 0x0, 0x8f8200a0,
+0x30420004, 0x10400069, 0x0, 0x8f43012c,
+0x8f820124, 0x14620005, 0x0, 0x8f430134,
+0x8f8200a4, 0x10620006, 0x0, 0x8f820124,
+0xaf42012c, 0x8f8200a4, 0x1000005c, 0xaf420134,
+0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d,
+0x0, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0,
+0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b,
+0xaf82011c, 0x8f43012c, 0x8f820124, 0x14620005,
+0x0, 0x8f430134, 0x8f8200a4, 0x10620010,
+0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4,
+0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134,
+0x3c040001, 0x248461f8, 0xafa20014, 0x8f86011c,
+0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200,
+0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001,
+0x24846204, 0xafa20014, 0x8f86011c, 0x8f8700a0,
+0x3c050005, 0xc002b17, 0x34a51300, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0,
+0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124,
+0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208,
+0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001,
+0x24c66f54, 0x40f809, 0x24070004, 0x8f82011c,
+0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
+0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c,
+0xafa20010, 0x8f420134, 0x3c040001, 0x24846210,
+0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005,
+0x34a51400, 0xc002b17, 0x0, 0x8fbf0020,
+0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001,
+0x3c060080, 0x3c050100, 0x8f820070, 0x481024,
+0x1040fffd, 0x0, 0x8f820054, 0x24420005,
+0xaf820078, 0x8c040234, 0x10800016, 0x1821,
+0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
+0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
+0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
+0x0, 0x3c030080, 0x3c010001, 0x370821,
+0xac2040e8, 0x3c010001, 0x370821, 0x1000000b,
+0xa02740f0, 0x3c020001, 0x571021, 0x904240f0,
+0x54400006, 0x661825, 0x3c020001, 0x571021,
+0x904240f1, 0x54400001, 0x661825, 0x8c040230,
+0x10800013, 0x0, 0x3c020001, 0x571021,
+0x8c4240ec, 0x24420005, 0x3c010001, 0x370821,
+0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec,
+0x44102b, 0x14400006, 0x0, 0x3c010001,
+0x370821, 0xac2040ec, 0x10000006, 0x651825,
+0x3c020001, 0x571021, 0x904240f2, 0x54400001,
+0x651825, 0x1060ffbc, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x431025, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x1000ffa7, 0xaf80004c,
+0x1000ffa5, 0xaf800048, 0x3e00008, 0x0,
+0x0, 0x0, 0x0, 0x27bdffe0,
+0xafbf0018, 0x8f860064, 0x30c20004, 0x10400025,
+0x24040004, 0x8c020114, 0xaf420020, 0xaf840064,
+0x8f4202fc, 0x24420001, 0xaf4202fc, 0x8f4202fc,
+0x8f820064, 0x30420004, 0x14400005, 0x0,
+0x8c030114, 0x8f420020, 0x1462fff2, 0x0,
+0x8f420000, 0x10400007, 0x8f43003c, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x431025, 0xaf820060,
+0x8f420000, 0x10400073, 0x0, 0x1000006f,
+0x0, 0x30c20008, 0x10400020, 0x24040008,
+0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8,
+0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064,
+0x30420008, 0x14400005, 0x0, 0x8c03011c,
+0x8f420048, 0x1462fff2, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020,
+0x10400023, 0x24040020, 0x8c02012c, 0xaf420068,
+0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8,
+0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005,
+0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2,
+0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x1000ffb4, 0x34420800,
+0x30c20010, 0x10400029, 0x24040010, 0x8c020124,
+0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001,
+0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010,
+0x14400005, 0x32c22000, 0x8c030124, 0x8f420058,
+0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x34420100, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x1000006c,
+0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001,
+0x10400004, 0x24020001, 0xaf820064, 0x10000064,
+0x0, 0x30c20002, 0x1440000b, 0x3c050003,
+0x3c040001, 0x248462d4, 0x34a50500, 0x3821,
+0xafa00010, 0xc002b17, 0xafa00014, 0x2402ffc0,
+0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c,
+0x10a20048, 0x51080, 0x8c460300, 0x24a20001,
+0x3045003f, 0x24020003, 0xac05022c, 0x61e02,
+0x10620005, 0x24020010, 0x1062001d, 0x30c20fff,
+0x10000039, 0x0, 0x8f4302a8, 0x8f440000,
+0x30c20fff, 0xaf420048, 0x24630001, 0xaf4302a8,
+0x10800007, 0x8f4202a8, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x34420200, 0xaf820060, 0x8f420000,
+0x1040001f, 0x0, 0x1000001b, 0x0,
+0xaf420058, 0x32c22000, 0x50400001, 0x36d68000,
+0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4,
+0x10600007, 0x8f4202d4, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x34420100, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x10000006, 0xaf80004c,
+0x10000004, 0xaf800048, 0xc00217e, 0xc02021,
+0x402821, 0x8c02010c, 0x14a20002, 0x24020002,
+0xaf820064, 0x8f820064, 0x30420002, 0x14400004,
+0x0, 0x8c02010c, 0x14a2ffac, 0x0,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
+0x0, 0x27bdffa0, 0xafb00040, 0x808021,
+0x101602, 0x2442ffff, 0x304300ff, 0x2c620013,
+0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c,
+0xafb20048, 0xafb10044, 0x104001ec, 0xafa50034,
+0x31080, 0x3c010001, 0x220821, 0x8c226318,
+0x400008, 0x0, 0x101302, 0x30440fff,
+0x24020001, 0x10820005, 0x24020002, 0x1082000a,
+0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004,
+0x3c020001, 0x8c426f80, 0xaf440200, 0xaf440204,
+0x10000007, 0x34630001, 0x8f430004, 0xaf440200,
+0xaf440204, 0x621824, 0x3c020001, 0x2442c9c8,
+0x21100, 0x21182, 0xaf430004, 0x3c030800,
+0x431025, 0x3c010000, 0xac224138, 0x8f840054,
+0x41442, 0x41c82, 0x431021, 0x41cc2,
+0x431023, 0x41d02, 0x431021, 0x41d42,
+0x431023, 0x10000009, 0xaf420208, 0x3c040001,
+0x248462e0, 0x34a51000, 0x2003021, 0x3821,
+0xafa00010, 0xc002b17, 0xafa00014, 0x8f4202a0,
+0x24420001, 0xaf4202a0, 0x1000021b, 0x8f4202a0,
+0x27b00028, 0x2002021, 0x24050210, 0xc002b9b,
+0x24060008, 0xc0024f4, 0x2002021, 0x10000212,
+0x0, 0x8faa0034, 0x27a40028, 0xa1880,
+0x25420001, 0x3042003f, 0xafa20034, 0x8c650300,
+0x8faa0034, 0x21080, 0x8c430300, 0x25420001,
+0x3042003f, 0xafa20034, 0xac02022c, 0xafa50028,
+0xc0024f4, 0xafa3002c, 0x100001ff, 0x0,
+0x27b00028, 0x2002021, 0x24050210, 0xc002b9b,
+0x24060008, 0xc002633, 0x2002021, 0x100001f6,
+0x0, 0x8faa0034, 0x27a40028, 0xa1880,
+0x25420001, 0x3042003f, 0xafa20034, 0x8c650300,
+0x8faa0034, 0x21080, 0x8c430300, 0x25420001,
+0x3042003f, 0xafa20034, 0xac02022c, 0xafa50028,
+0xc002633, 0xafa3002c, 0x100001e3, 0x0,
+0x101302, 0x30430fff, 0x24020001, 0x10620005,
+0x24020002, 0x1062001e, 0x3c020002, 0x10000033,
+0x3c050003, 0x3c030002, 0x2c31024, 0x54400037,
+0x2c3b025, 0x8f820228, 0x3c010001, 0x370821,
+0xac2238d8, 0x8f82022c, 0x3c010001, 0x370821,
+0xac2238dc, 0x8f820230, 0x3c010001, 0x370821,
+0xac2238e0, 0x8f820234, 0x3c010001, 0x370821,
+0xac2238e4, 0x2402ffff, 0xaf820228, 0xaf82022c,
+0xaf820230, 0xaf820234, 0x10000020, 0x2c3b025,
+0x2c21024, 0x10400012, 0x3c02fffd, 0x3c020001,
+0x571021, 0x8c4238d8, 0xaf820228, 0x3c020001,
+0x571021, 0x8c4238dc, 0xaf82022c, 0x3c020001,
+0x571021, 0x8c4238e0, 0xaf820230, 0x3c020001,
+0x571021, 0x8c4238e4, 0xaf820234, 0x3c02fffd,
+0x3442ffff, 0x10000009, 0x2c2b024, 0x3c040001,
+0x248462ec, 0x34a51100, 0x2003021, 0x3821,
+0xafa00010, 0xc002b17, 0xafa00014, 0x8f4202cc,
+0x24420001, 0xaf4202cc, 0x1000019b, 0x8f4202cc,
+0x101302, 0x30450fff, 0x24020001, 0x10a20005,
+0x24020002, 0x10a2000d, 0x3c0408ff, 0x10000014,
+0x3c050003, 0x3c0208ff, 0x3442ffff, 0x8f830220,
+0x3c040004, 0x2c4b025, 0x621824, 0x34630008,
+0xaf830220, 0x10000012, 0xaf450298, 0x3484fff7,
+0x3c03fffb, 0x8f820220, 0x3463ffff, 0x2c3b024,
+0x441024, 0xaf820220, 0x10000009, 0xaf450298,
+0x3c040001, 0x248462f8, 0x34a51200, 0x2003021,
+0x3821, 0xafa00010, 0xc002b17, 0xafa00014,
+0x8f4202bc, 0x24420001, 0xaf4202bc, 0x10000172,
+0x8f4202bc, 0x27840208, 0x24050200, 0xc002b9b,
+0x24060008, 0x27440224, 0x24050200, 0xc002b9b,
+0x24060008, 0x8f4202c4, 0x24420001, 0xaf4202c4,
+0x10000165, 0x8f4202c4, 0x101302, 0x30430fff,
+0x24020001, 0x10620011, 0x28620002, 0x50400005,
+0x24020002, 0x10600007, 0x0, 0x10000017,
+0x0, 0x1062000f, 0x0, 0x10000013,
+0x0, 0x8c060248, 0x2021, 0xc005134,
+0x24050004, 0x10000007, 0x0, 0x8c060248,
+0x2021, 0xc005134, 0x24050004, 0x10000010,
+0x0, 0x8c06024c, 0x2021, 0xc005134,
+0x24050001, 0x1000000a, 0x0, 0x3c040001,
+0x24846304, 0x3c050003, 0x34a51300, 0x2003021,
+0x3821, 0xafa00010, 0xc002b17, 0xafa00014,
+0x8f4202c0, 0x24420001, 0xaf4202c0, 0x10000136,
+0x8f4202c0, 0xc002407, 0x0, 0x10000132,
+0x0, 0x24020001, 0xa34205c5, 0x24100100,
+0x8f4401a8, 0x8f4501ac, 0xafb00010, 0xafa00014,
+0x8f420014, 0xafa20018, 0x8f420108, 0x26e60028,
+0x40f809, 0x24070400, 0x1040fff5, 0x0,
+0x10000121, 0x0, 0x3c02ffff, 0x34427fff,
+0x2c2b024, 0x1821, 0x3c020900, 0xaf400058,
+0xaf40005c, 0xaf400060, 0xaf400064, 0xaf400360,
+0xafa20020, 0x8f5e0018, 0x27aa0020, 0x240200ff,
+0x13c20002, 0xafaa003c, 0x27c30001, 0x8c020228,
+0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
+0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+0x3c040001, 0x2484629c, 0x3c050009, 0xafa00014,
0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500,
0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
-0xe08821, 0x263504c0, 0x8f440168, 0x8f45016c,
+0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
0x822021, 0x100f809, 0x892021, 0x54400006,
0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
-0xaf520018, 0x8f420368, 0x24420001, 0xaf420368,
-0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24843198, 0x3c050009,
+0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa003c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x248462a8, 0x3c050009,
0xafa20014, 0x8d460000, 0x10000033, 0x34a50600,
-0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8,
-0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054,
+0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
+0x8f420308, 0x1000001c, 0x326200ff, 0x8f830054,
0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
0x10400014, 0x9821, 0x24110010, 0x8f42000c,
-0x8f440150, 0x8f450154, 0x8f860120, 0xafb10010,
+0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010,
0xafb20014, 0xafa20018, 0x8f42010c, 0x24070008,
0x40f809, 0x24c6001c, 0x1440ffe5, 0x0,
0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffef,
-0x0, 0x326200ff, 0x54400012, 0x24020001,
-0x8f420368, 0x24420001, 0xaf420368, 0x8f420368,
-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
-0x3c040001, 0x248431a0, 0x3c050009, 0xafa20014,
-0x8d460000, 0x34a50700, 0xc0029bb, 0x3c03821,
-0x1021, 0x1440005b, 0x24020001, 0x10000065,
-0x0, 0x8f510018, 0x240200ff, 0x12220002,
+0x0, 0x326200ff, 0x14400011, 0x0,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x248462b0, 0x3c050009, 0xafa20014,
+0x8d460000, 0x34a50700, 0xc002b17, 0x3c03821,
+0x8f4202b0, 0x24420001, 0xaf4202b0, 0x8f4202b0,
+0x8f4202f8, 0x24420001, 0xaf4202f8, 0x1000008a,
+0x8f4202f8, 0x8c02025c, 0x27440224, 0xaf4201f0,
+0x8c020260, 0x24050200, 0x24060008, 0xc002b9b,
+0xaf4201f8, 0x8f820220, 0x30420008, 0x14400002,
+0x24020001, 0x24020002, 0xaf420298, 0x8f4202ac,
+0x24420001, 0xaf4202ac, 0x10000077, 0x8f4202ac,
+0x3c0200ff, 0x3442ffff, 0x2021824, 0x32c20180,
+0x14400006, 0x3402fffb, 0x43102b, 0x14400003,
+0x0, 0x1000006c, 0xaf4300bc, 0x3c040001,
+0x24846310, 0x3c050003, 0x34a51500, 0x2003021,
+0x3821, 0xafa00010, 0xc002b17, 0xafa00014,
+0x3c020700, 0x34421000, 0x101e02, 0x621825,
+0xafa30020, 0x8f510018, 0x240200ff, 0x12220002,
0x8021, 0x26300001, 0x8c020228, 0x1602000e,
-0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c,
-0x8f42032c, 0x8c020228, 0x3c040001, 0x24843174,
+0x1130c0, 0x8f42033c, 0x24420001, 0xaf42033c,
+0x8f42033c, 0x8c020228, 0x3c040001, 0x24846284,
0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020,
0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020,
0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821,
-0x8f440168, 0x8f45016c, 0x1021, 0x24070004,
+0x8f440178, 0x8f45017c, 0x1021, 0x24070004,
0xafa70010, 0xafb00014, 0x8f48000c, 0x24c604c0,
0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008,
0xa32821, 0xa3482b, 0x822021, 0x100f809,
0x892021, 0x1440000b, 0x24070008, 0x8f820120,
-0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x2484628c,
0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c,
-0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c,
+0x34a50200, 0x8f440160, 0x8f450164, 0x8f43000c,
0xaf500018, 0x8f860120, 0x24020010, 0xafa20010,
0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x54400011, 0x24020001, 0x8f420330,
-0x24420001, 0xaf420330, 0x8f420330, 0x8f820120,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24843184,
+0x24c6001c, 0x14400010, 0x0, 0x8f420340,
+0x24420001, 0xaf420340, 0x8f420340, 0x8f820120,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846294,
0x3c050009, 0xafa20014, 0x8fa60020, 0x34a50300,
-0xc0029bb, 0x2203821, 0x1021, 0x1040000d,
-0x24020001, 0x8f4202d8, 0xa34005b7, 0xaf4001a0,
-0x24420001, 0xaf4202d8, 0x8f4202d8, 0x8ee20150,
-0x24420001, 0xaee20150, 0x10000003, 0x8ee20150,
-0x24020001, 0xa34205b7, 0x8fbf0048, 0x8fbe0044,
-0x8fb50040, 0x8fb3003c, 0x8fb20038, 0x8fb10034,
-0x8fb00030, 0x3e00008, 0x27bd0050, 0x27bdffd8,
-0xafbf0020, 0x8f8200b0, 0x30420004, 0x10400068,
-0x0, 0x8f43011c, 0x8f820104, 0x14620005,
-0x0, 0x8f430124, 0x8f8200b4, 0x10620006,
-0x0, 0x8f820104, 0xaf42011c, 0x8f8200b4,
-0x1000005b, 0xaf420124, 0x8f8200b0, 0x3c030080,
-0x431024, 0x1040000d, 0x0, 0x8f82011c,
-0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
-0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
-0x431024, 0x1000004a, 0xaf82011c, 0x8f43011c,
-0x8f820104, 0x14620005, 0x0, 0x8f430124,
-0x8f8200b4, 0x10620010, 0x0, 0x8f820104,
-0xaf42011c, 0x8f8200b4, 0x8f43011c, 0xaf420124,
-0xafa30010, 0x8f420124, 0x3c040001, 0x248431c4,
-0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
-0x10000031, 0x34a50900, 0x8f42011c, 0xafa20010,
-0x8f420124, 0x3c040001, 0x248431d0, 0xafa20014,
-0x8f86011c, 0x8f8700b0, 0x3c050005, 0xc0029bb,
-0x34a51000, 0x8f82011c, 0x34420002, 0xaf82011c,
-0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0,
-0x24020008, 0xaf830104, 0xafa20010, 0xafa00014,
-0x8f42000c, 0x8c040208, 0x8c05020c, 0xafa20018,
-0x8f42010c, 0x26e60028, 0x40f809, 0x24070400,
-0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c,
-0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc,
-0x8f42011c, 0xafa20010, 0x8f420124, 0x3c040001,
-0x248431dc, 0xafa20014, 0x8f86011c, 0x8f8700b0,
-0x3c050005, 0x34a51100, 0xc0029bb, 0x0,
-0x8f8200a0, 0x30420004, 0x10400069, 0x0,
-0x8f430120, 0x8f820124, 0x14620005, 0x0,
-0x8f430128, 0x8f8200a4, 0x10620006, 0x0,
-0x8f820124, 0xaf420120, 0x8f8200a4, 0x1000005c,
-0xaf420128, 0x8f8200a0, 0x3c030080, 0x431024,
-0x1040000d, 0x0, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f8200a0, 0x2403fffb, 0x431024,
-0xaf8200a0, 0x8f82011c, 0x2403fffd, 0x431024,
-0x1000004b, 0xaf82011c, 0x8f430120, 0x8f820124,
-0x14620005, 0x0, 0x8f430128, 0x8f8200a4,
-0x10620010, 0x0, 0x8f820124, 0xaf420120,
-0x8f8200a4, 0x8f430120, 0xaf420128, 0xafa30010,
-0x8f420128, 0x3c040001, 0x248431e8, 0xafa20014,
-0x8f86011c, 0x8f8700a0, 0x3c050005, 0x10000032,
-0x34a51200, 0x8f420120, 0xafa20010, 0x8f420128,
-0x3c040001, 0x248431f4, 0xafa20014, 0x8f86011c,
-0x8f8700a0, 0x3c050005, 0xc0029bb, 0x34a51300,
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124,
-0x8f8200a0, 0x34420001, 0xaf8200a0, 0x24020080,
-0xaf830124, 0xafa20010, 0xafa00014, 0x8f420014,
-0x8c040208, 0x8c05020c, 0xafa20018, 0x8f420108,
-0x3c060001, 0x24c63e84, 0x40f809, 0x24070004,
-0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c,
-0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc,
-0x8f420120, 0xafa20010, 0x8f420128, 0x3c040001,
-0x24843200, 0xafa20014, 0x8f86011c, 0x8f8700a0,
-0x3c050005, 0x34a51400, 0xc0029bb, 0x0,
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3c081000,
-0x24070001, 0x3c060080, 0x3c050100, 0x8f820070,
-0x481024, 0x1040fffd, 0x0, 0x8f820054,
-0x24420005, 0xaf820078, 0x8c040234, 0x10800016,
-0x1821, 0x3c020001, 0x571021, 0x8c4240e8,
-0x24420005, 0x3c010001, 0x370821, 0xac2240e8,
-0x3c020001, 0x571021, 0x8c4240e8, 0x44102b,
-0x14400009, 0x0, 0x3c030080, 0x3c010001,
-0x370821, 0xac2040e8, 0x3c010001, 0x370821,
-0x1000000b, 0xa02740f0, 0x3c020001, 0x571021,
-0x904240f0, 0x54400006, 0x661825, 0x3c020001,
-0x571021, 0x904240f1, 0x54400001, 0x661825,
-0x8c040230, 0x10800013, 0x0, 0x3c020001,
-0x571021, 0x8c4240ec, 0x24420005, 0x3c010001,
-0x370821, 0xac2240ec, 0x3c020001, 0x571021,
-0x8c4240ec, 0x44102b, 0x14400006, 0x0,
-0x3c010001, 0x370821, 0xac2040ec, 0x10000006,
-0x651825, 0x3c020001, 0x571021, 0x904240f2,
-0x54400001, 0x651825, 0x1060ffbc, 0x0,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x431025, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x1000ffa7,
-0xaf80004c, 0x1000ffa5, 0xaf800048, 0x3e00008,
-0x0, 0x0, 0x0, 0x27bdffe0,
-0xafbf001c, 0xafb00018, 0x8f860064, 0x30c20004,
-0x10400025, 0x24040004, 0x8c020114, 0xaf420020,
-0xaf840064, 0x8f4202ec, 0x24420001, 0xaf4202ec,
-0x8f4202ec, 0x8f820064, 0x30420004, 0x14400005,
-0x0, 0x8c030114, 0x8f420020, 0x1462fff2,
-0x0, 0x8f420000, 0x10400007, 0x8f43003c,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x431025,
-0xaf820060, 0x8f420000, 0x10400073, 0x0,
-0x1000006f, 0x0, 0x30c20008, 0x10400020,
-0x24040008, 0x8c02011c, 0xaf420048, 0xaf840064,
-0x8f420298, 0x24420001, 0xaf420298, 0x8f420298,
-0x8f820064, 0x30420008, 0x14400005, 0x0,
-0x8c03011c, 0x8f420048, 0x1462fff2, 0x0,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x1000ffd9, 0x34420200,
-0x30c20020, 0x10400023, 0x24040020, 0x8c02012c,
-0xaf420068, 0xaf840064, 0x8f4202c8, 0x24420001,
-0xaf4202c8, 0x8f4202c8, 0x8f820064, 0x30420020,
-0x14400005, 0x32c24000, 0x8c03012c, 0x8f420068,
-0x1462fff2, 0x32c24000, 0x14400002, 0x3c020001,
-0x2c2b025, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x1000ffb4,
-0x34420800, 0x30c20010, 0x10400029, 0x24040010,
-0x8c020124, 0xaf420058, 0xaf840064, 0x8f4202c4,
-0x24420001, 0xaf4202c4, 0x8f4202c4, 0x8f820064,
-0x30420010, 0x14400005, 0x32c22000, 0x8c030124,
-0x8f420058, 0x1462fff2, 0x32c22000, 0x50400001,
-0x36d68000, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x34420100,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x1000006b, 0xaf80004c, 0x10000069, 0xaf800048,
-0x30c20001, 0x10400004, 0x24020001, 0xaf820064,
-0x10000063, 0x0, 0x30c20002, 0x1440000b,
-0x3c050003, 0x3c040001, 0x248432c4, 0x34a50500,
-0x3821, 0xafa00010, 0xc0029bb, 0xafa00014,
-0x2402ffc0, 0x10000056, 0xaf820064, 0x8c10022c,
-0x8c02010c, 0x12020047, 0x101080, 0x8c450300,
-0x26020001, 0x3050003f, 0x24020003, 0xac10022c,
-0x51e02, 0x10620005, 0x24020010, 0x1062001d,
-0x30a20fff, 0x10000039, 0x0, 0x8f430298,
-0x8f440000, 0x30a20fff, 0xaf420048, 0x24630001,
-0xaf430298, 0x10800007, 0x8f420298, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x34420200, 0xaf820060,
-0x8f420000, 0x1040001f, 0x0, 0x1000001b,
-0x0, 0xaf420058, 0x32c22000, 0x50400001,
-0x36d68000, 0x8f4202c4, 0x8f430000, 0x24420001,
-0xaf4202c4, 0x10600007, 0x8f4202c4, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x34420100, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000005,
-0xaf80004c, 0x10000003, 0xaf800048, 0xc00202b,
-0xa02021, 0x8c02010c, 0x16020002, 0x24020002,
-0xaf820064, 0x8f820064, 0x30420002, 0x14400004,
-0x0, 0x8c02010c, 0x1602ffad, 0x0,
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
-0x3e00008, 0x0, 0x27bdffa8, 0xafb00038,
-0x808021, 0x101602, 0x2442ffff, 0x304300ff,
-0x2c620013, 0xafbf0050, 0xafbe004c, 0xafb50048,
-0xafb30044, 0xafb20040, 0x104001e6, 0xafb1003c,
-0x31080, 0x3c010001, 0x220821, 0x8c223308,
-0x400008, 0x0, 0x101302, 0x30440fff,
-0x24020001, 0x10820005, 0x24020002, 0x1082000a,
-0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004,
-0x3c020001, 0x8c423eb0, 0xaf4401f0, 0xaf4401f4,
-0x10000007, 0x34630001, 0x8f430004, 0xaf4401f0,
-0xaf4401f4, 0x621824, 0x3c020001, 0x2442c1b0,
-0x21100, 0x21182, 0xaf430004, 0x3c030800,
-0x431025, 0x3c010000, 0xac224138, 0x8f840054,
-0x41442, 0x41c82, 0x431021, 0x41cc2,
-0x431023, 0x41d02, 0x431021, 0x41d42,
-0x431023, 0x10000009, 0xaf4201f8, 0x3c040001,
-0x248432d0, 0x34a51000, 0x2003021, 0x3821,
-0xafa00010, 0xc0029bb, 0xafa00014, 0x8f420290,
-0x24420001, 0xaf420290, 0x10000215, 0x8f420290,
-0x27b00028, 0x2002021, 0x24050210, 0xc002a3f,
-0x24060008, 0xc002398, 0x2002021, 0x1000020c,
-0x0, 0x8c06022c, 0x27a40028, 0x61880,
-0x24c20001, 0x3046003f, 0x8c650300, 0x61080,
-0x8c430300, 0x24c20001, 0x3042003f, 0xac02022c,
-0xafa50028, 0xc002398, 0xafa3002c, 0x100001fc,
-0x0, 0x27b00028, 0x2002021, 0x24050210,
-0xc002a3f, 0x24060008, 0xc0024d7, 0x2002021,
-0x100001f3, 0x0, 0x8c06022c, 0x27a40028,
-0x61880, 0x24c20001, 0x3046003f, 0x8c650300,
-0x61080, 0x8c430300, 0x24c20001, 0x3042003f,
-0xac02022c, 0xafa50028, 0xc0024d7, 0xafa3002c,
-0x100001e3, 0x0, 0x101302, 0x30430fff,
-0x24020001, 0x10620005, 0x24020002, 0x1062001e,
-0x3c020002, 0x10000033, 0x3c050003, 0x3c030002,
-0x2c31024, 0x54400037, 0x2c3b025, 0x8f820228,
-0x3c010001, 0x370821, 0xac2238d8, 0x8f82022c,
-0x3c010001, 0x370821, 0xac2238dc, 0x8f820230,
-0x3c010001, 0x370821, 0xac2238e0, 0x8f820234,
-0x3c010001, 0x370821, 0xac2238e4, 0x2402ffff,
-0xaf820228, 0xaf82022c, 0xaf820230, 0xaf820234,
-0x10000020, 0x2c3b025, 0x2c21024, 0x10400012,
-0x3c02fffd, 0x3c020001, 0x571021, 0x8c4238d8,
-0xaf820228, 0x3c020001, 0x571021, 0x8c4238dc,
-0xaf82022c, 0x3c020001, 0x571021, 0x8c4238e0,
-0xaf820230, 0x3c020001, 0x571021, 0x8c4238e4,
-0xaf820234, 0x3c02fffd, 0x3442ffff, 0x10000009,
-0x2c2b024, 0x3c040001, 0x248432dc, 0x34a51100,
-0x2003021, 0x3821, 0xafa00010, 0xc0029bb,
-0xafa00014, 0x8f4202bc, 0x24420001, 0xaf4202bc,
-0x1000019b, 0x8f4202bc, 0x101302, 0x30450fff,
-0x24020001, 0x10a20005, 0x24020002, 0x10a2000d,
-0x3c0408ff, 0x10000014, 0x3c050003, 0x3c0208ff,
-0x3442ffff, 0x8f830220, 0x3c040004, 0x2c4b025,
-0x621824, 0x34630008, 0xaf830220, 0x10000012,
-0xaf450288, 0x3484fff7, 0x3c03fffb, 0x8f820220,
-0x3463ffff, 0x2c3b024, 0x441024, 0xaf820220,
-0x10000009, 0xaf450288, 0x3c040001, 0x248432e8,
-0x34a51200, 0x2003021, 0x3821, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x8f4202ac, 0x24420001,
-0xaf4202ac, 0x10000172, 0x8f4202ac, 0x27840208,
-0x24050200, 0xc002a3f, 0x24060008, 0x27440214,
-0x24050200, 0xc002a3f, 0x24060008, 0x8f4202b4,
-0x24420001, 0xaf4202b4, 0x10000165, 0x8f4202b4,
-0x101302, 0x30430fff, 0x24020001, 0x10620011,
-0x28620002, 0x50400005, 0x24020002, 0x10600007,
-0x0, 0x10000017, 0x0, 0x1062000f,
-0x0, 0x10000013, 0x0, 0x8c060248,
-0x2021, 0xc0047d4, 0x24050004, 0x10000007,
-0x0, 0x8c060248, 0x2021, 0xc0047d4,
-0x24050004, 0x10000010, 0x0, 0x8c06024c,
-0x2021, 0xc0047d4, 0x24050001, 0x1000000a,
-0x0, 0x3c040001, 0x248432f4, 0x3c050003,
-0x34a51300, 0x2003021, 0x3821, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x8f4202b0, 0x24420001,
-0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022ac,
-0x0, 0x10000132, 0x0, 0x24020001,
-0xa34205b6, 0x24100100, 0x8f440198, 0x8f45019c,
-0xafb00010, 0xafa00014, 0x8f420014, 0xafa20018,
-0x8f420108, 0x26e60028, 0x40f809, 0x24070400,
-0x1040fff5, 0x0, 0x10000121, 0x0,
-0x3c02ffff, 0x34427fff, 0x2c2b024, 0x1821,
-0x3c020900, 0xaf400058, 0xaf40005c, 0xaf400060,
-0xaf400064, 0xaf400350, 0xafa20020, 0x8f5e0018,
-0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa0034,
-0x27c30001, 0x8c020228, 0x609021, 0x1642000e,
-0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c,
-0x8f42032c, 0x8c020228, 0x3c040001, 0x2484328c,
-0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020,
-0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020,
-0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
-0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
-0x1040001b, 0x9821, 0xe08821, 0x263504c0,
-0x8f440168, 0x8f45016c, 0x2201821, 0x240a0004,
-0xafaa0010, 0xafb20014, 0x8f48000c, 0x1021,
-0x2f53021, 0xafa80018, 0x8f48010c, 0x24070008,
-0xa32821, 0xa3482b, 0x822021, 0x100f809,
-0x892021, 0x54400006, 0x24130001, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffe9, 0x0,
-0x326200ff, 0x54400017, 0xaf520018, 0x8f420368,
-0x24420001, 0xaf420368, 0x8f420368, 0x8f820120,
-0x8faa0034, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24843298, 0x3c050009, 0xafa20014, 0x8d460000,
-0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001,
-0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c,
-0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8,
-0x2021023, 0x2c4203e9, 0x10400014, 0x9821,
-0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154,
-0x8f860120, 0xafb10010, 0xafb20014, 0xafa20018,
-0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
-0x1440ffe5, 0x0, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffef, 0x0, 0x326200ff,
-0x14400011, 0x0, 0x8f420368, 0x24420001,
-0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034,
-0xafa20010, 0x8f820124, 0x3c040001, 0x248432a0,
-0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
-0xc0029bb, 0x3c03821, 0x8f4202a0, 0x24420001,
-0xaf4202a0, 0x8f4202a0, 0x8f4202e8, 0x24420001,
-0xaf4202e8, 0x1000008a, 0x8f4202e8, 0x8c02025c,
-0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200,
-0x24060008, 0xc002a3f, 0xaf4201e8, 0x8f820220,
-0x30420008, 0x14400002, 0x24020001, 0x24020002,
-0xaf420288, 0x8f42029c, 0x24420001, 0xaf42029c,
-0x10000077, 0x8f42029c, 0x3c0200ff, 0x3442ffff,
-0x2021824, 0x32c20180, 0x14400006, 0x3402fffb,
-0x43102b, 0x14400003, 0x0, 0x1000006c,
-0xaf4300bc, 0x3c040001, 0x24843300, 0x3c050003,
-0x34a51500, 0x2003021, 0x3821, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x3c020700, 0x34421000,
-0x101e02, 0x621825, 0xafa30020, 0x8f510018,
-0x240200ff, 0x12220002, 0x8021, 0x26300001,
-0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c,
-0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228,
-0x3c040001, 0x24843274, 0x3c050009, 0xafa00014,
-0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100,
-0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
-0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c,
-0x1021, 0x24070004, 0xafa70010, 0xafb00014,
-0x8f48000c, 0x24c604c0, 0x2e63021, 0xafa80018,
-0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
-0x822021, 0x100f809, 0x892021, 0x1440000b,
-0x24070008, 0x8f820120, 0xafa20010, 0x8f820124,
-0x3c040001, 0x2484327c, 0x3c050009, 0xafa20014,
-0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150,
-0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120,
-0x24020010, 0xafa20010, 0xafb00014, 0xafa30018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010,
-0x0, 0x8f420330, 0x24420001, 0xaf420330,
-0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24843284, 0x3c050009, 0xafa20014,
-0x8fa60020, 0x34a50300, 0xc0029bb, 0x2203821,
-0x8f4202d0, 0x24420001, 0xaf4202d0, 0x8f4202d0,
-0x8f4202e0, 0x24420001, 0xaf4202e0, 0x8f4202e0,
-0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
-0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
-0x27bd0058, 0x27bdfff8, 0x2408ffff, 0x10a00014,
-0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
-0x24840001, 0x3021, 0x1071026, 0x30420001,
-0x10400002, 0x81842, 0x6a1826, 0x604021,
-0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
-0x25290001, 0x125102b, 0x1440fff0, 0x0,
-0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffb8,
-0xafbf0040, 0xafbe003c, 0xafb50038, 0xafb30034,
-0xafb20030, 0xafb1002c, 0xafb00028, 0x8f870220,
-0xafa7001c, 0x8f870200, 0xafa70024, 0x8f820220,
-0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004,
-0xaf820220, 0x8f820200, 0x3c03c0ff, 0x3463ffff,
-0x431024, 0x34420004, 0xaf820200, 0x8f53034c,
-0x8f550350, 0x8f5e0354, 0x8f470358, 0xafa70014,
-0x8f4202c0, 0x274401b0, 0x24420001, 0xaf4202c0,
-0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a28,
-0x24050400, 0xaf53034c, 0xaf550350, 0xaf5e0354,
-0x8fa70014, 0xaf470358, 0xaf5002c0, 0xaf5101f4,
-0xaf5201f0, 0x8c02025c, 0x27440214, 0xaf4201e0,
-0x8c020260, 0x24050200, 0x24060008, 0xaf4201e8,
-0x24020006, 0xc002a3f, 0xaf4201e4, 0x3c023b9a,
-0x3442ca00, 0xaf4201ec, 0x240203e8, 0x24040002,
-0x24030001, 0xaf420284, 0xaf440280, 0xaf43028c,
-0x8f820220, 0x30420008, 0x10400004, 0x0,
-0xaf430288, 0x10000003, 0x3021, 0xaf440288,
-0x3021, 0x3c030001, 0x661821, 0x90633cf0,
-0x3461021, 0x24c60001, 0xa043021c, 0x2cc2000f,
-0x1440fff8, 0x3461821, 0x24c60001, 0x8f820040,
-0x24040080, 0x24050080, 0x21702, 0x24420030,
-0xa062021c, 0x3461021, 0xc002a28, 0xa040021c,
-0x8fa7001c, 0x30e20004, 0x14400006, 0x0,
-0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
-0xaf820220, 0x8fa70024, 0x30e20004, 0x14400006,
-0x0, 0x8f820200, 0x3c03c0ff, 0x3463fffb,
-0x431024, 0xaf820200, 0x8fbf0040, 0x8fbe003c,
-0x8fb50038, 0x8fb30034, 0x8fb20030, 0x8fb1002c,
-0x8fb00028, 0x3e00008, 0x27bd0048, 0xaf400104,
+0xc002b17, 0x2203821, 0x8f4202e0, 0x24420001,
+0xaf4202e0, 0x8f4202e0, 0x8f4202f0, 0x24420001,
+0xaf4202f0, 0x8f4202f0, 0x8fa20034, 0x8fbf0058,
+0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
+0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
+0x27bdfff8, 0x2408ffff, 0x10a00014, 0x4821,
+0x3c0aedb8, 0x354a8320, 0x90870000, 0x24840001,
+0x3021, 0x1071026, 0x30420001, 0x10400002,
+0x81842, 0x6a1826, 0x604021, 0x24c60001,
+0x2cc20008, 0x1440fff7, 0x73842, 0x25290001,
+0x125102b, 0x1440fff0, 0x0, 0x1001021,
+0x3e00008, 0x27bd0008, 0x27bdffb8, 0xafbf0040,
+0xafbe003c, 0xafb50038, 0xafb30034, 0xafb20030,
+0xafb1002c, 0xafb00028, 0x8f870220, 0xafa7001c,
+0x8f870200, 0xafa70024, 0x8f820220, 0x3c0308ff,
+0x3463ffff, 0x431024, 0x34420004, 0xaf820220,
+0x8f820200, 0x3c03c0ff, 0x3463ffff, 0x431024,
+0x34420004, 0xaf820200, 0x8f53035c, 0x8f550360,
+0x8f5e0364, 0x8f470368, 0xafa70014, 0x8f4202d0,
+0x274401c0, 0x24420001, 0xaf4202d0, 0x8f5002d0,
+0x8f510204, 0x8f520200, 0xc002b84, 0x24050400,
+0xaf53035c, 0xaf550360, 0xaf5e0364, 0x8fa70014,
+0xaf470368, 0xaf5002d0, 0xaf510204, 0xaf520200,
+0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
+0x24050200, 0x24060008, 0xaf4201f8, 0x24020006,
+0xc002b9b, 0xaf4201f4, 0x3c023b9a, 0x3442ca00,
+0xaf4201fc, 0x240203e8, 0x24040002, 0x24030001,
+0xaf420294, 0xaf440290, 0xaf43029c, 0x8f820220,
+0x30420008, 0x10400004, 0x0, 0xaf430298,
+0x10000003, 0x3021, 0xaf440298, 0x3021,
+0x3c030001, 0x661821, 0x90636d80, 0x3461021,
+0x24c60001, 0xa043022c, 0x2cc2000f, 0x1440fff8,
+0x3461821, 0x24c60001, 0x8f820040, 0x24040080,
+0x24050080, 0x21702, 0x24420030, 0xa062022c,
+0x3461021, 0xc002b84, 0xa040022c, 0x8fa7001c,
+0x30e20004, 0x14400006, 0x0, 0x8f820220,
+0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220,
+0x8fa70024, 0x30e20004, 0x14400006, 0x0,
+0x8f820200, 0x3c03c0ff, 0x3463fffb, 0x431024,
+0xaf820200, 0x8fbf0040, 0x8fbe003c, 0x8fb50038,
+0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
+0x3e00008, 0x27bd0048, 0x0, 0xaf400104,
0x24040001, 0x410c0, 0x2e21821, 0x24820001,
0x3c010001, 0x230821, 0xa42234d0, 0x402021,
0x2c820080, 0x1440fff8, 0x410c0, 0x24020001,
@@ -5721,7 +5946,7 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x2c450001, 0xa01021, 0x14400009, 0x24840008,
0x86102b, 0x1440fff0, 0x1021, 0x304200ff,
0x14400030, 0x24020001, 0x1000002e, 0x1021,
-0x1000fffa, 0x24020001, 0x2002021, 0xc002292,
+0x1000fffa, 0x24020001, 0x2002021, 0xc0023ed,
0x24050006, 0x3042007f, 0x218c0, 0x2e31021,
0x3c010001, 0x220821, 0x942230d0, 0x1040fff2,
0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0,
@@ -5736,7 +5961,7 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0,
0x801021, 0xafb00030, 0x24500002, 0x2002021,
0x24050006, 0xafb10034, 0x408821, 0xafbf0048,
-0xafbe0044, 0xafb50040, 0xafb3003c, 0xc002292,
+0xafbe0044, 0xafb50040, 0xafb3003c, 0xc0023ed,
0xafb20038, 0x3047007f, 0x710c0, 0x2e21021,
0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c,
0xa03021, 0x3c090001, 0x352934d2, 0x96280002,
@@ -5749,15 +5974,15 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x10c00014, 0x610c0, 0x571821, 0x3c010001,
0x230821, 0x8c2334d0, 0x571021, 0xafa30010,
0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001,
-0x24843414, 0xafa20014, 0x8e260000, 0x8e270004,
-0x3c050004, 0xc0029bb, 0x34a50400, 0x10000063,
+0x24846424, 0xafa20014, 0x8e260000, 0x8e270004,
+0x3c050004, 0xc002b17, 0x34a50400, 0x10000063,
0x3c020800, 0x8f450100, 0x10a00006, 0x510c0,
0x2e21021, 0x3c010001, 0x220821, 0x942234d0,
0xaf420100, 0xa03021, 0x14c00011, 0x628c0,
0x710c0, 0x2e21021, 0xafa70010, 0x3c010001,
-0x220821, 0x942230d0, 0x3c040001, 0x24843420,
+0x220821, 0x942230d0, 0x3c040001, 0x24846430,
0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004,
-0xc0029bb, 0x34a50500, 0x10000048, 0x3c020800,
+0xc002b17, 0x34a50500, 0x10000048, 0x3c020800,
0xb71821, 0x3c020001, 0x96040000, 0x344234d2,
0x621821, 0xa4640000, 0x8e020002, 0x720c0,
0xac620002, 0x2e41021, 0x3c030001, 0x621821,
@@ -5779,44 +6004,44 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020,
0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001,
0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
-0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c,
-0x8c020228, 0x3c040001, 0x248433dc, 0x3c050009,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x248463ec, 0x3c050009,
0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b,
0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
-0x9821, 0xe08821, 0x263504c0, 0x8f440168,
-0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010,
+0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
0xa3482b, 0x822021, 0x100f809, 0x892021,
0x54400006, 0x24130001, 0x8f820054, 0x2021023,
0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
-0x54400017, 0xaf520018, 0x8f420368, 0x24420001,
-0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x248433e8,
+0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x248463f8,
0x3c050009, 0xafa20014, 0x8d460000, 0x10000033,
-0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001,
-0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff,
+0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff,
0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
0x2c4203e9, 0x10400014, 0x9821, 0x24110010,
-0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c,
0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5,
0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
0x1440ffef, 0x0, 0x326200ff, 0x14400011,
-0x0, 0x8f420368, 0x24420001, 0xaf420368,
-0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x248433f0, 0x3c050009,
-0xafa20014, 0x8d460000, 0x34a50700, 0xc0029bb,
-0x3c03821, 0x8f4202a4, 0x24420001, 0xaf4202a4,
-0x8f4202a4, 0x8f4202e4, 0x24420001, 0xaf4202e4,
-0x8f4202e4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+0x0, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24846400, 0x3c050009,
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b17,
+0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4,
+0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4,
+0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021,
0xafb00040, 0x24500002, 0x2002021, 0x24050006,
0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054,
-0xafb50050, 0xafb3004c, 0xc002292, 0xafb20048,
+0xafb50050, 0xafb3004c, 0xc0023ed, 0xafb20048,
0x3048007f, 0x810c0, 0x2e21021, 0x3c060001,
0xc23021, 0x94c630d0, 0x10c0001c, 0x3821,
0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0,
@@ -5828,8 +6053,8 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011,
0xafa70028, 0x810c0, 0x2e21021, 0xafa80010,
0x3c010001, 0x220821, 0x942230d0, 0x3c040001,
-0x2484342c, 0xafa20014, 0x8e260000, 0x8e270004,
-0x3c050004, 0xc0029bb, 0x34a50900, 0x10000075,
+0x2484643c, 0xafa20014, 0x8e260000, 0x8e270004,
+0x3c050004, 0xc002b17, 0x34a50900, 0x10000075,
0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021,
0x3c030001, 0x621821, 0x946334d0, 0x710c0,
0x2e21021, 0x3c010001, 0x220821, 0xa42334d0,
@@ -5862,43 +6087,43 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x3c020800, 0x34422000, 0x1821, 0xafa20020,
0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002,
0xafab0034, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001,
-0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001,
-0x248433dc, 0x3c050009, 0xafa00014, 0xafa20010,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x248463ec, 0x3c050009, 0xafa00014, 0xafa20010,
0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c,
0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
0x24070008, 0xa32821, 0xa3482b, 0x822021,
0x100f809, 0x892021, 0x54400006, 0x24130001,
0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420368, 0x24420001, 0xaf420368, 0x8f420368,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124,
-0x3c040001, 0x248433e8, 0x3c050009, 0xafa20014,
-0x8d660000, 0x10000033, 0x34a50600, 0x8f4202f8,
-0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8,
+0x3c040001, 0x248463f8, 0x3c050009, 0xafa20014,
+0x8d660000, 0x10000033, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
-0x9821, 0x24110010, 0x8f42000c, 0x8f440150,
-0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014,
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420368,
-0x24420001, 0xaf420368, 0x8f420368, 0x8f820120,
+0x326200ff, 0x14400011, 0x0, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001,
-0x248433f0, 0x3c050009, 0xafa20014, 0x8d660000,
-0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202a8,
-0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f4202e4,
-0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0058,
+0x24846400, 0x3c050009, 0xafa20014, 0x8d660000,
+0x34a50700, 0xc002b17, 0x3c03821, 0x8f4202b8,
+0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4,
+0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058,
0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
0x0, 0x0, 0x0, 0x27bdffe0,
-0x27644000, 0xafbf0018, 0xc002a28, 0x24051000,
+0x27644000, 0xafbf0018, 0xc002b84, 0x24051000,
0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8,
0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100,
0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114,
@@ -5907,21 +6132,21 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4,
0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021,
0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c,
-0x3c040001, 0x248434f0, 0x3c050001, 0x34420001,
+0x3c040001, 0x24846500, 0x3c050001, 0x34420001,
0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
-0x34a50100, 0xc0029bb, 0x3821, 0x8c020218,
+0x34a50100, 0xc002b17, 0x3821, 0x8c020218,
0x30420040, 0x10400014, 0x0, 0x8f82011c,
-0x3c040001, 0x248434fc, 0x3c050001, 0x34420004,
+0x3c040001, 0x2484650c, 0x3c050001, 0x34420004,
0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
-0x10000007, 0x34a50200, 0x3c040001, 0x24843504,
+0x10000007, 0x34a50200, 0x3c040001, 0x24846514,
0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300,
-0xc0029bb, 0x3821, 0x8fbf0018, 0x3e00008,
+0xc002b17, 0x3821, 0x8fbf0018, 0x3e00008,
0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014,
0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002,
0x24680020, 0x27684800, 0x8f820128, 0x11020004,
0x0, 0x8f820124, 0x15020007, 0x0,
-0x8f430324, 0x1021, 0x24630001, 0xaf430324,
-0x10000039, 0x8f430324, 0xac640000, 0xac650004,
+0x8f430334, 0x1021, 0x24630001, 0xaf430334,
+0x10000039, 0x8f430334, 0xac640000, 0xac650004,
0xac660008, 0xa467000e, 0xac690018, 0xac6a001c,
0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc,
0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000,
@@ -5940,8 +6165,8 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0,
0x14620002, 0x24680020, 0x27684000, 0x8f820108,
0x11020004, 0x0, 0x8f820104, 0x15020007,
-0x0, 0x8f430328, 0x1021, 0x24630001,
-0xaf430328, 0x10000035, 0x8f430328, 0xac640000,
+0x0, 0x8f430338, 0x1021, 0x24630001,
+0xaf430338, 0x10000035, 0x8f430338, 0xac640000,
0xac650004, 0xac660008, 0xa467000e, 0xac690018,
0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100,
0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019,
@@ -5956,55 +6181,55 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x2e21021, 0x402021, 0x24020001, 0xaf4400ec,
0xac890000, 0xac820004, 0x24020001, 0x3e00008,
0x0, 0x3e00008, 0x0, 0x27bdffd8,
-0x3c040001, 0x2484350c, 0x3c050001, 0xafbf0024,
+0x3c040001, 0x2484651c, 0x3c050001, 0xafbf0024,
0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104,
0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100,
-0x2403021, 0x2203821, 0xafa20010, 0xc0029bb,
+0x2403021, 0x2203821, 0xafa20010, 0xc002b17,
0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c,
-0x3c040001, 0x24843518, 0xafa20014, 0x8e060000,
-0x8e070004, 0x3c050001, 0xc0029bb, 0x34a52510,
+0x3c040001, 0x24846528, 0xafa20014, 0x8e060000,
+0x8e070004, 0x3c050001, 0xc002b17, 0x34a52510,
0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001,
-0x24843524, 0xafa20014, 0x8e060010, 0x8e070014,
-0x3c050001, 0xc0029bb, 0x34a52520, 0x3c027f00,
+0x24846534, 0xafa20014, 0x8e060010, 0x8e070014,
+0x3c050001, 0xc002b17, 0x34a52520, 0x3c027f00,
0x2221024, 0x3c030800, 0x54430016, 0x3c030200,
0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200,
-0x3c040001, 0x24843530, 0x3c050002, 0x34a5f030,
+0x3c040001, 0x24846540, 0x3c050002, 0x34a5f030,
0x3021, 0x3821, 0x36420002, 0xaf82011c,
0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c,
-0xafa00010, 0xc0029bb, 0xafa00014, 0x10000024,
+0xafa00010, 0xc002b17, 0xafa00014, 0x10000024,
0x0, 0x2c31024, 0x1040000d, 0x2231024,
0x1040000b, 0x36420002, 0xaf82011c, 0x36220001,
-0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420320,
-0x24420001, 0xaf420320, 0x10000015, 0x8f420320,
-0x3c040001, 0x24843538, 0x240202a9, 0xafa20010,
-0xafa00014, 0x8f860144, 0x3c070001, 0x24e73540,
-0xc0029bb, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330,
+0x24420001, 0xaf420330, 0x10000015, 0x8f420330,
+0x3c040001, 0x24846548, 0x240202a9, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e76550,
+0xc002b17, 0x3405dead, 0x8f82011c, 0x34420002,
0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018,
0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001,
-0x24843568, 0x3c050001, 0xafbf0024, 0xafb20020,
+0x24846578, 0x3c050001, 0xafbf0024, 0xafb20020,
0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0,
0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021,
-0x2203821, 0xafa20010, 0xc0029bb, 0xafb00014,
+0x2203821, 0xafa20010, 0xc002b17, 0xafb00014,
0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001,
-0x24843574, 0xafa20014, 0x8e060000, 0x8e070004,
-0x3c050001, 0xc0029bb, 0x34a52610, 0x8e020018,
-0xafa20010, 0x8e02001c, 0x3c040001, 0x24843580,
+0x24846584, 0xafa20014, 0x8e060000, 0x8e070004,
+0x3c050001, 0xc002b17, 0x34a52610, 0x8e020018,
+0xafa20010, 0x8e02001c, 0x3c040001, 0x24846590,
0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001,
-0xc0029bb, 0x34a52620, 0x3c027f00, 0x2221024,
+0xc002b17, 0x34a52620, 0x3c027f00, 0x2221024,
0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac,
0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001,
-0x2484358c, 0x3c050001, 0x34a5f030, 0x3021,
+0x2484659c, 0x3c050001, 0x34a5f030, 0x3021,
0x3821, 0x36420002, 0xaf82011c, 0x36220001,
0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010,
-0xc0029bb, 0xafa00014, 0x10000024, 0x0,
+0xc002b17, 0xafa00014, 0x10000024, 0x0,
0x2c31024, 0x1040000d, 0x2231024, 0x1040000b,
0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0,
-0xaf900124, 0xaf92011c, 0x8f42031c, 0x24420001,
-0xaf42031c, 0x10000015, 0x8f42031c, 0x3c040001,
-0x24843538, 0x240202e2, 0xafa20010, 0xafa00014,
-0x8f860144, 0x3c070001, 0x24e73540, 0xc0029bb,
+0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001,
+0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001,
+0x24846548, 0x240202e2, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e76550, 0xc002b17,
0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
@@ -6013,24 +6238,24 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x2821, 0x6821, 0x4821, 0x7821,
0x7021, 0x8f880124, 0x8f870104, 0x1580002e,
0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120,
-0x10460029, 0x0, 0x3c040001, 0x8c843e90,
+0x10460029, 0x0, 0x3c040001, 0x8c846f60,
0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004,
0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e,
0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014,
0x10000012, 0x24c60020, 0x10400017, 0x0,
-0x3c040001, 0x8c843e90, 0x8d020000, 0x8d030004,
+0x3c040001, 0x8c846f60, 0x8d020000, 0x8d030004,
0xac820000, 0xac830004, 0x8d020008, 0xac820008,
0x9502000e, 0xa482000e, 0x8d020010, 0x25060020,
0xac820010, 0x8d020014, 0x240c0001, 0xc01821,
0xac820014, 0x27624fe0, 0x43102b, 0x54400001,
0x27634800, 0x603021, 0x1540002f, 0x31620100,
0x11200014, 0x31628000, 0x8f820100, 0x1045002a,
-0x31620100, 0x3c040001, 0x8c843e8c, 0x8ca20000,
+0x31620100, 0x3c040001, 0x8c846f5c, 0x8ca20000,
0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008,
0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010,
0x240a0001, 0xac820010, 0x8ca20014, 0x10000012,
0x24a50020, 0x10400018, 0x31620100, 0x3c040001,
-0x8c843e8c, 0x8ce20000, 0x8ce30004, 0xac820000,
+0x8c846f5c, 0x8ce20000, 0x8ce30004, 0xac820000,
0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e,
0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010,
0x8ce20014, 0x240a0001, 0xa01821, 0xac820014,
@@ -6039,7 +6264,7 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x11a00009, 0x31a20800, 0x10400004, 0x25020020,
0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124,
0x8f880124, 0x6821, 0x11800011, 0x31621000,
-0x3c040001, 0x8c843e90, 0x8c820000, 0x8c830004,
+0x3c040001, 0x8c846f60, 0x8c820000, 0x8c830004,
0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4,
0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021,
0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000,
@@ -6048,7 +6273,7 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x3c020002, 0x1221024, 0x10400004, 0x24e20020,
0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104,
0x8f870104, 0x4821, 0x1140ff70, 0x0,
-0x3c040001, 0x8c843e8c, 0x8c820000, 0x8c830004,
+0x3c040001, 0x8c846f5c, 0x8c820000, 0x8c830004,
0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4,
0x9482000e, 0xaf82009c, 0x8c820010, 0x5021,
0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014,
@@ -6057,11 +6282,11 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x7821, 0x7021, 0x8f880124, 0x8f870104,
0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014,
0x31220800, 0x8f820120, 0x10460029, 0x0,
-0x3c040001, 0x8c843e90, 0x8cc20000, 0x8cc30004,
+0x3c040001, 0x8c846f60, 0x8cc20000, 0x8cc30004,
0xac820000, 0xac830004, 0x8cc20008, 0xac820008,
0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001,
0xac820010, 0x8cc20014, 0x10000012, 0x24c60020,
-0x10400017, 0x0, 0x3c040001, 0x8c843e90,
+0x10400017, 0x0, 0x3c040001, 0x8c846f60,
0x8d020000, 0x8d030004, 0xac820000, 0xac830004,
0x8d020008, 0xac820008, 0x9502000e, 0xa482000e,
0x8d020010, 0x25060020, 0xac820010, 0x8d020014,
@@ -6069,11 +6294,11 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x43102b, 0x54400001, 0x27634800, 0x603021,
0x1560002f, 0x31220100, 0x11400014, 0x31228000,
0x8f820100, 0x1045002a, 0x31220100, 0x3c040001,
-0x8c843e8c, 0x8ca20000, 0x8ca30004, 0xac820000,
+0x8c846f5c, 0x8ca20000, 0x8ca30004, 0xac820000,
0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e,
0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010,
0x8ca20014, 0x10000012, 0x24a50020, 0x10400018,
-0x31220100, 0x3c040001, 0x8c843e8c, 0x8ce20000,
+0x31220100, 0x3c040001, 0x8c846f5c, 0x8ce20000,
0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008,
0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010,
0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001,
@@ -6082,7 +6307,7 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x5440001d, 0x31221000, 0x11a00009, 0x31a20800,
0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000,
0x25020020, 0xaf820124, 0x8f880124, 0x6821,
-0x11800011, 0x31221000, 0x3c040001, 0x8c843e90,
+0x11800011, 0x31221000, 0x3c040001, 0x8c846f60,
0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084,
0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac,
0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010,
@@ -6091,7 +6316,7 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024,
0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4,
0x24e20020, 0xaf820104, 0x8f870104, 0x5021,
-0x11600010, 0x0, 0x3c040001, 0x8c843e8c,
+0x11600010, 0x0, 0x3c040001, 0x8c846f5c,
0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c,
0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010,
@@ -6120,37 +6345,37 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f420000, 0x10400003, 0x0, 0x1000ff05,
0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008,
0x0, 0x0, 0x0, 0x3c020001,
-0x8c423d18, 0x27bdffe8, 0xafbf0014, 0x14400012,
-0xafb00010, 0x3c100001, 0x26103f30, 0x2002021,
-0xc002a28, 0x24052000, 0x26021fe0, 0x3c010001,
-0xac223e98, 0x3c010001, 0xac223e94, 0xac020250,
+0x8c426da8, 0x27bdffe8, 0xafbf0014, 0x14400012,
+0xafb00010, 0x3c100001, 0x26107010, 0x2002021,
+0xc002b84, 0x24052000, 0x26021fe0, 0x3c010001,
+0xac226f68, 0x3c010001, 0xac226f64, 0xac020250,
0x24022000, 0xac100254, 0xac020258, 0x24020001,
-0x3c010001, 0xac223d18, 0x8fbf0014, 0x8fb00010,
-0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293e98,
+0x3c010001, 0xac226da8, 0x8fbf0014, 0x8fb00010,
+0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296f68,
0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000,
0x8c820004, 0xad250008, 0xad220004, 0x8f820054,
0xad260010, 0xad270014, 0xad230018, 0xad28001c,
-0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423f30,
+0xad22000c, 0x2529ffe0, 0x3c020001, 0x24427010,
0x122102b, 0x10400003, 0x0, 0x3c090001,
-0x8d293e94, 0x3c020001, 0x8c423d00, 0xad220000,
-0x3c020001, 0x8c423d00, 0x3c010001, 0xac293e98,
+0x8d296f64, 0x3c020001, 0x8c426d90, 0xad220000,
+0x3c020001, 0x8c426d90, 0x3c010001, 0xac296f68,
0xad220004, 0xac090250, 0x3e00008, 0x0,
-0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103e98,
-0x3c020001, 0x8c423d00, 0xafb10014, 0x808821,
+0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106f68,
+0x3c020001, 0x8c426d90, 0xafb10014, 0x808821,
0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018,
0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c,
-0xae020000, 0x3c020001, 0x8c423d00, 0xc09821,
+0xae020000, 0x3c020001, 0x8c426d90, 0xc09821,
0xe0a821, 0x10800006, 0xae020004, 0x26050008,
-0xc002a33, 0x24060018, 0x10000005, 0x2610ffe0,
-0x26040008, 0xc002a28, 0x24050018, 0x2610ffe0,
-0x3c030001, 0x24633f30, 0x203102b, 0x10400003,
-0x0, 0x3c100001, 0x8e103e94, 0x8e220000,
+0xc002b8f, 0x24060018, 0x10000005, 0x2610ffe0,
+0x26040008, 0xc002b84, 0x24050018, 0x2610ffe0,
+0x3c030001, 0x24637010, 0x203102b, 0x10400003,
+0x0, 0x3c100001, 0x8e106f64, 0x8e220000,
0xae020000, 0x8e220004, 0xae120008, 0xae020004,
0x8f820054, 0xae130010, 0xae150014, 0xae1e0018,
0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0,
0x203102b, 0x10400003, 0x0, 0x3c100001,
-0x8e103e94, 0x3c020001, 0x8c423d00, 0xae020000,
-0x3c020001, 0x8c423d00, 0x3c010001, 0xac303e98,
+0x8e106f64, 0x3c020001, 0x8c426d90, 0xae020000,
+0x3c020001, 0x8c426d90, 0x3c010001, 0xac306f68,
0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024,
0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821,
@@ -6165,924 +6390,989 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x3e00008, 0x0, 0x63080, 0x861821,
0x83102b, 0x10400006, 0x0, 0xac850000,
0x24840004, 0x83102b, 0x5440fffd, 0xac850000,
-0x3e00008, 0x0, 0x0, 0x27bdffd8,
-0xafbf0024, 0xafb00020, 0x8f430024, 0x8f420020,
-0x10620038, 0x0, 0x8f430020, 0x8f420024,
-0x622023, 0x4810003, 0x0, 0x8f420040,
-0x822021, 0x8f430030, 0x8f420024, 0x43102b,
-0x14400005, 0x0, 0x8f430040, 0x8f420024,
-0x10000005, 0x621023, 0x8f420030, 0x8f430024,
-0x431023, 0x2442ffff, 0x406021, 0x8c102a,
-0x54400001, 0x806021, 0x8f4a0024, 0x8f490040,
-0x8f480024, 0x8f440170, 0x8f450174, 0x8f460024,
-0x8f4b001c, 0x24070001, 0xafa70010, 0x84100,
-0x1001821, 0x14c5021, 0x2529ffff, 0x1498024,
-0xafb00014, 0x8f470014, 0x1021, 0x63100,
-0xafa70018, 0xa32821, 0xa3382b, 0x822021,
-0x872021, 0x8f420108, 0x1663021, 0x40f809,
-0xc3900, 0x54400001, 0xaf500024, 0x8f430024,
-0x8f420020, 0x14620018, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x2403ffef, 0x431024, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000002,
-0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
-0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
-0x27bdffc0, 0x32c20020, 0xafbf0038, 0xafb30034,
-0xafb20030, 0xafb1002c, 0x10400004, 0xafb00028,
-0x8f530028, 0x10000002, 0x0, 0x8f530020,
-0x8f420030, 0x105300eb, 0x21100, 0x8f43001c,
-0x628021, 0x8e040000, 0x8e050004, 0x96120008,
-0x8f420090, 0x9611000a, 0x3246ffff, 0x46102a,
-0x10400017, 0x0, 0x8f8200d8, 0x8f430098,
-0x431023, 0x2442fff8, 0xaf420090, 0x8f420090,
-0x2842fff9, 0x10400005, 0x0, 0x8f420090,
-0x8f430138, 0x431021, 0xaf420090, 0x8f420090,
-0x46102a, 0x10400006, 0x0, 0x8f420338,
-0x24420001, 0xaf420338, 0x100000e1, 0x8f420338,
-0x8f8200fc, 0x14400006, 0x32c20008, 0x8f420334,
-0x24420001, 0xaf420334, 0x100000d9, 0x8f420334,
-0x5040000c, 0xaf4000ac, 0x934205b3, 0x10400008,
-0x32220200, 0x10400006, 0x3c034000, 0x9602000e,
-0xaf4300ac, 0x21400, 0x10000002, 0xaf4200b0,
-0xaf4000ac, 0x32220004, 0x1040007f, 0x32220800,
-0x10400003, 0x3247ffff, 0x10000002, 0x24020020,
-0x24020004, 0xafa20010, 0x8f420030, 0xafa20014,
-0x8f420010, 0x3c030002, 0x431025, 0xafa20018,
+0x3e00008, 0x0, 0x0, 0x3c0208ff,
+0x3442ffff, 0x3c03c0ff, 0x8f850220, 0x3463ffff,
+0x8f860200, 0xa21024, 0x34420004, 0xc31824,
+0x34630004, 0xaf820220, 0xaf830200, 0x8c820214,
+0xac020084, 0x8c820218, 0xac020088, 0x8c82021c,
+0xac02008c, 0x8c820220, 0xac020090, 0x8c820224,
+0xac020094, 0x8c820228, 0xac020098, 0x8c82022c,
+0xac02009c, 0x8c820230, 0xac0200a0, 0x8c820234,
+0xac0200a4, 0x8c820238, 0xac0200a8, 0x8c82023c,
+0xac0200ac, 0x8c820240, 0xac0200b0, 0x8c820244,
+0xac0200b4, 0x8c820248, 0xac0200b8, 0x8c82024c,
+0xac0200bc, 0x8c82001c, 0xac020080, 0x8c820018,
+0xac0200c0, 0x8c820020, 0xac0200cc, 0x8c820024,
+0xac0200d0, 0x8c8201d0, 0xac0200e0, 0x8c8201d4,
+0xac0200e4, 0x8c8201d8, 0xac0200e8, 0x8c8201dc,
+0xac0200ec, 0x8c8201e0, 0xac0200f0, 0x8c820098,
+0x8c83009c, 0xac0300fc, 0x8c8200a8, 0x8c8300ac,
+0xac0300f4, 0x8c8200a0, 0x8c8300a4, 0x30a50004,
+0xac0300f8, 0x14a00007, 0x30c20004, 0x8f820220,
+0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220,
+0x30c20004, 0x14400006, 0x0, 0x8f820200,
+0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200,
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+0xafb00020, 0x8f430024, 0x8f420020, 0x10620038,
+0x0, 0x8f430020, 0x8f420024, 0x622023,
+0x4810003, 0x0, 0x8f420040, 0x822021,
+0x8f430030, 0x8f420024, 0x43102b, 0x14400005,
+0x0, 0x8f430040, 0x8f420024, 0x10000005,
+0x621023, 0x8f420030, 0x8f430024, 0x431023,
+0x2442ffff, 0x406021, 0x8c102a, 0x54400001,
+0x806021, 0x8f4a0024, 0x8f490040, 0x8f480024,
+0x8f440180, 0x8f450184, 0x8f460024, 0x8f4b001c,
+0x24070001, 0xafa70010, 0x84100, 0x1001821,
+0x14c5021, 0x2529ffff, 0x1498024, 0xafb00014,
+0x8f470014, 0x1021, 0x63100, 0xafa70018,
+0xa32821, 0xa3382b, 0x822021, 0x872021,
+0x8f420108, 0x1663021, 0x40f809, 0xc3900,
+0x54400001, 0xaf500024, 0x8f430024, 0x8f420020,
+0x14620018, 0x0, 0x8f420000, 0x10400007,
+0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+0x0, 0x10000005, 0x0, 0xaf800048,
+0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+0x2403ffef, 0x431024, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x10000002, 0xaf80004c,
+0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008,
+0x27bd0028, 0x3e00008, 0x0, 0x27bdffc0,
+0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030,
+0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028,
+0x10000002, 0x0, 0x8f530020, 0x8f420030,
+0x105300eb, 0x21100, 0x8f43001c, 0x628021,
+0x8e040000, 0x8e050004, 0x96120008, 0x8f420090,
+0x9611000a, 0x3246ffff, 0x46102a, 0x10400017,
+0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+0x2442fff8, 0xaf420090, 0x8f420090, 0x2842fff9,
+0x10400005, 0x0, 0x8f420090, 0x8f430144,
+0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+0x10400006, 0x0, 0x8f420348, 0x24420001,
+0xaf420348, 0x100000e1, 0x8f420348, 0x8f8200fc,
+0x14400006, 0x0, 0x8f420344, 0x24420001,
+0xaf420344, 0x100000d9, 0x8f420344, 0x934205c2,
+0x1040000b, 0x32c20008, 0x10400008, 0x32220200,
+0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac,
+0x21400, 0x10000002, 0xaf4200b0, 0xaf4000ac,
+0x32220004, 0x1040007f, 0x32220800, 0x10400003,
+0x3247ffff, 0x10000002, 0x24020020, 0x24020004,
+0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010,
+0x3c030002, 0x431025, 0xafa20018, 0x8f460098,
+0x8f420108, 0x40f809, 0x0, 0x104000b7,
+0x0, 0x8f42009c, 0x8f430094, 0x2421021,
+0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008,
+0x3c034000, 0x8f420094, 0x431025, 0xafa20020,
+0x8f42009c, 0x8f4300b0, 0x10000004, 0x431025,
+0x8f420094, 0xafa20020, 0x8f42009c, 0xafa20024,
+0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
+0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
+0x8f440270, 0x8f450274, 0x401821, 0x1021,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0x32230060, 0x24020040, 0xaf440270, 0xaf450274,
+0x10620017, 0x2c620041, 0x10400005, 0x24020020,
+0x10620008, 0x24020001, 0x10000026, 0x0,
+0x24020060, 0x10620019, 0x24020001, 0x10000021,
+0x0, 0x8f420278, 0x8f43027c, 0x24630001,
+0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
+0x8f420278, 0x8f43027c, 0x10000016, 0x24020001,
+0x8f420280, 0x8f430284, 0x24630001, 0x2c640001,
+0x441021, 0xaf420280, 0xaf430284, 0x8f420280,
+0x8f430284, 0x1000000b, 0x24020001, 0x8f420288,
+0x8f43028c, 0x24630001, 0x2c640001, 0x441021,
+0xaf420288, 0xaf43028c, 0x8f420288, 0x8f43028c,
+0x24020001, 0xa34205c2, 0x8f420098, 0x3244ffff,
+0x2406fff8, 0x8f45013c, 0x441021, 0x24420007,
+0x461024, 0x24840007, 0xaf420094, 0x8f420090,
+0x8f430094, 0x862024, 0x441023, 0x65182b,
+0x14600005, 0xaf420090, 0x8f420094, 0x8f430144,
+0x431023, 0xaf420094, 0x8f420094, 0x10000023,
+0xaf40009c, 0x3247ffff, 0x50e00022, 0x32c20020,
+0x14400002, 0x24020010, 0x24020002, 0xafa20010,
+0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018,
0x8f460098, 0x8f420108, 0x40f809, 0x0,
-0x104000b7, 0x0, 0x8f42009c, 0x8f430094,
-0x2421021, 0xaf42009c, 0xae03000c, 0x8f4200ac,
-0x10400008, 0x3c034000, 0x8f420094, 0x431025,
-0xafa20020, 0x8f42009c, 0x8f4300b0, 0x10000004,
-0x431025, 0x8f420094, 0xafa20020, 0x8f42009c,
-0xafa20024, 0x8f8200fc, 0x8fa30020, 0x8fa40024,
-0xac430000, 0xac440004, 0x24420008, 0xaf8200f0,
-0x8f42009c, 0x8f440260, 0x8f450264, 0x401821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0x32230060, 0x24020040, 0xaf440260,
-0xaf450264, 0x10620017, 0x2c620041, 0x10400005,
-0x24020020, 0x10620008, 0x24020001, 0x10000026,
-0x0, 0x24020060, 0x10620019, 0x24020001,
-0x10000021, 0x0, 0x8f420268, 0x8f43026c,
-0x24630001, 0x2c640001, 0x441021, 0xaf420268,
-0xaf43026c, 0x8f420268, 0x8f43026c, 0x10000016,
-0x24020001, 0x8f420270, 0x8f430274, 0x24630001,
-0x2c640001, 0x441021, 0xaf420270, 0xaf430274,
-0x8f420270, 0x8f430274, 0x1000000b, 0x24020001,
-0x8f420278, 0x8f43027c, 0x24630001, 0x2c640001,
-0x441021, 0xaf420278, 0xaf43027c, 0x8f420278,
-0x8f43027c, 0x24020001, 0xa34205b3, 0x8f420098,
-0x3244ffff, 0x2406fff8, 0x8f450130, 0x441021,
+0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090,
+0x8f46013c, 0x451021, 0xaf420098, 0x8f42009c,
+0x8f440098, 0xa34005c2, 0x651823, 0xaf430090,
+0x451021, 0x86202b, 0x14800005, 0xaf42009c,
+0x8f420098, 0x8f430144, 0x431023, 0xaf420098,
+0x32c20020, 0x10400005, 0x0, 0x8f420358,
+0x2442ffff, 0xaf420358, 0x8f420358, 0x8f420030,
+0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
+0xaf420030, 0x8f420030, 0x14530018, 0x0,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x2403fff7, 0x431024,
+0xaf820060, 0x8f420000, 0x10400003, 0x0,
+0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0038,
+0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
+0x3e00008, 0x27bd0040, 0x3e00008, 0x0,
+0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028,
+0xafb10024, 0x10400004, 0xafb00020, 0x8f520028,
+0x10000002, 0x0, 0x8f520020, 0x8f420030,
+0x105200b5, 0x21100, 0x8f43001c, 0x628021,
+0x8e040000, 0x8e050004, 0x96110008, 0x8f420090,
+0x9607000a, 0x3226ffff, 0x46102a, 0x10400017,
+0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81,
+0x10400005, 0x0, 0x8f420090, 0x8f430144,
+0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+0x10400006, 0x0, 0x8f420348, 0x24420001,
+0xaf420348, 0x100000ab, 0x8f420348, 0x8f8600fc,
+0x10c0000c, 0x0, 0x8f8200f4, 0x2403fff8,
+0x431024, 0x461023, 0x218c3, 0x58600001,
+0x24630100, 0x8f42008c, 0x43102b, 0x14400006,
+0x712c2, 0x8f420344, 0x24420001, 0xaf420344,
+0x10000098, 0x8f420344, 0x934305c2, 0x1060000f,
+0x30460001, 0x8f420010, 0x34480400, 0x32c20008,
+0x10400008, 0x30e20200, 0x10400006, 0x3c034000,
+0x9602000e, 0xaf4300ac, 0x21400, 0x10000004,
+0xaf4200b0, 0x10000002, 0xaf4000ac, 0x8f480010,
+0x30e20004, 0x10400045, 0x3227ffff, 0x8f4900ac,
+0x11200005, 0x30c200ff, 0x14400006, 0x24020040,
+0x10000004, 0x24020008, 0x14400002, 0x24020020,
+0x24020004, 0xafa20010, 0x8f430030, 0x11200004,
+0xafa30014, 0x8f4200b0, 0x621025, 0xafa20014,
+0x3c020002, 0x1021025, 0xafa20018, 0x8f460098,
+0x8f420108, 0x40f809, 0x0, 0x10400069,
+0x3224ffff, 0x8f42008c, 0x8f430094, 0x24420001,
+0xaf42008c, 0x24020001, 0xae03000c, 0xa34205c2,
+0x8f420098, 0x2406fff8, 0x8f45013c, 0x441021,
0x24420007, 0x461024, 0x24840007, 0xaf420094,
0x8f420090, 0x8f430094, 0x862024, 0x441023,
0x65182b, 0x14600005, 0xaf420090, 0x8f420094,
-0x8f430138, 0x431023, 0xaf420094, 0x8f420094,
-0x10000023, 0xaf40009c, 0x3247ffff, 0x50e00022,
-0x32c20020, 0x14400002, 0x24020010, 0x24020002,
-0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010,
-0xafa20018, 0x8f460098, 0x8f420108, 0x40f809,
-0x0, 0x1040003a, 0x3245ffff, 0x8f420098,
-0x8f430090, 0x8f460130, 0x451021, 0xaf420098,
-0x8f42009c, 0x8f440098, 0xa34005b3, 0x651823,
-0xaf430090, 0x451021, 0x86202b, 0x14800005,
-0xaf42009c, 0x8f420098, 0x8f430138, 0x431023,
-0xaf420098, 0x32c20020, 0x10400005, 0x0,
-0x8f420348, 0x2442ffff, 0xaf420348, 0x8f420348,
-0x8f420030, 0x8f430040, 0x24420001, 0x2463ffff,
-0x431024, 0xaf420030, 0x8f420030, 0x14530018,
-0x0, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x2403fff7,
-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
-0x8fbf0038, 0x8fb30034, 0x8fb20030, 0x8fb1002c,
-0x8fb00028, 0x3e00008, 0x27bd0040, 0x3e00008,
-0x0, 0x27bdffd0, 0x32c20020, 0xafbf002c,
-0xafb20028, 0xafb10024, 0x10400004, 0xafb00020,
-0x8f520028, 0x10000002, 0x0, 0x8f520020,
-0x8f420030, 0x105200b5, 0x21100, 0x8f43001c,
-0x628021, 0x8e040000, 0x8e050004, 0x96110008,
-0x8f420090, 0x9607000a, 0x3226ffff, 0x46102a,
-0x10400017, 0x0, 0x8f8200d8, 0x8f430098,
-0x431023, 0x2442ff80, 0xaf420090, 0x8f420090,
-0x2842ff81, 0x10400005, 0x0, 0x8f420090,
-0x8f430138, 0x431021, 0xaf420090, 0x8f420090,
-0x46102a, 0x10400006, 0x0, 0x8f420338,
-0x24420001, 0xaf420338, 0x100000ab, 0x8f420338,
-0x8f8600fc, 0x10c0000c, 0x0, 0x8f8200f4,
-0x2403fff8, 0x431024, 0x461023, 0x218c3,
-0x50600001, 0x24030100, 0x8f42008c, 0x43102b,
-0x14400006, 0x712c2, 0x8f420334, 0x24420001,
-0xaf420334, 0x10000098, 0x8f420334, 0x934305b3,
-0x1060000f, 0x30460001, 0x8f420010, 0x34480400,
-0x32c20008, 0x10400008, 0x30e20200, 0x10400006,
-0x3c034000, 0x9602000e, 0xaf4300ac, 0x21400,
-0x10000004, 0xaf4200b0, 0x10000002, 0xaf4000ac,
-0x8f480010, 0x30e20004, 0x10400045, 0x3227ffff,
-0x8f4900ac, 0x11200005, 0x30c200ff, 0x14400006,
-0x24020040, 0x10000004, 0x24020008, 0x14400002,
-0x24020020, 0x24020004, 0xafa20010, 0x8f430030,
-0x11200004, 0xafa30014, 0x8f4200b0, 0x621025,
-0xafa20014, 0x3c020002, 0x1021025, 0xafa20018,
+0x8f430144, 0x431023, 0xaf420094, 0x8f430094,
+0x8f420140, 0x43102b, 0x10400009, 0x0,
+0x8f43013c, 0x8f440094, 0x8f420090, 0x8f450138,
+0x641823, 0x431023, 0xaf420090, 0xaf450094,
+0x8f420094, 0x1000001f, 0xaf420098, 0x10e0001d,
+0x30c200ff, 0x14400002, 0x24020010, 0x24020002,
+0xafa20010, 0x8f420030, 0xafa80018, 0xafa20014,
0x8f460098, 0x8f420108, 0x40f809, 0x0,
-0x10400069, 0x3224ffff, 0x8f42008c, 0x8f430094,
-0x24420001, 0xaf42008c, 0x24020001, 0xae03000c,
-0xa34205b3, 0x8f420098, 0x2406fff8, 0x8f450130,
-0x441021, 0x24420007, 0x461024, 0x24840007,
-0xaf420094, 0x8f420090, 0x8f430094, 0x862024,
-0x441023, 0x65182b, 0x14600005, 0xaf420090,
-0x8f420094, 0x8f430138, 0x431023, 0xaf420094,
-0x8f430094, 0x8f420134, 0x43102b, 0x10400009,
-0x0, 0x8f430130, 0x8f440094, 0x8f420090,
-0x8f45012c, 0x641823, 0x431023, 0xaf420090,
-0xaf450094, 0x8f420094, 0x1000001f, 0xaf420098,
-0x10e0001d, 0x30c200ff, 0x14400002, 0x24020010,
-0x24020002, 0xafa20010, 0x8f420030, 0xafa80018,
-0xafa20014, 0x8f460098, 0x8f420108, 0x40f809,
-0x0, 0x10400030, 0x3225ffff, 0x8f420098,
-0x8f440130, 0x451021, 0xaf420098, 0x8f420090,
-0x8f430098, 0xa34005b3, 0x451023, 0x64182b,
-0x14600005, 0xaf420090, 0x8f420098, 0x8f430138,
-0x431023, 0xaf420098, 0x8f420030, 0x8f430040,
-0x24420001, 0x2463ffff, 0x431024, 0xaf420030,
-0x8f420030, 0x14520018, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000002,
-0xaf80004c, 0xaf800048, 0x8fbf002c, 0x8fb20028,
-0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030,
-0x3e00008, 0x0, 0x27bdffd8, 0x3c020001,
-0x34422ec0, 0xafbf0020, 0x8f4300f0, 0x8f840108,
-0x2e21021, 0x54620004, 0x24620008, 0x3c020001,
-0x34422cc0, 0x2e21021, 0x401821, 0xaf4300f0,
-0xac600000, 0x8f4200ec, 0x8c660004, 0x14620004,
-0x3c020001, 0x24820020, 0x1000000f, 0xaf820108,
-0x8f4300f0, 0x34422ec0, 0x2e21021, 0x54620004,
-0x24620008, 0x3c020001, 0x34422cc0, 0x2e21021,
-0x401821, 0x8c620004, 0x21140, 0x821021,
-0xaf820108, 0xac600000, 0x8c850018, 0x30a20036,
-0x1040006c, 0x30a20001, 0x8c82001c, 0x8f430040,
-0x8f440034, 0x24420001, 0x2463ffff, 0x431024,
-0x862021, 0xaf42002c, 0x30a20030, 0x14400006,
-0xaf440034, 0x8f420034, 0x8c03023c, 0x43102b,
-0x144000c6, 0x0, 0x32c20010, 0x10400028,
-0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c,
-0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x24843844, 0xafa20014,
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029bb,
-0x34a51100, 0x10000036, 0x0, 0x8f4202f0,
-0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0,
-0x24020001, 0xa34205b2, 0x10000026, 0xaf430038,
-0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c,
-0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
+0x10400030, 0x3225ffff, 0x8f420098, 0x8f44013c,
+0x451021, 0xaf420098, 0x8f420090, 0x8f430098,
+0xa34005c2, 0x451023, 0x64182b, 0x14600005,
+0xaf420090, 0x8f420098, 0x8f430144, 0x431023,
+0xaf420098, 0x8f420030, 0x8f430040, 0x24420001,
+0x2463ffff, 0x431024, 0xaf420030, 0x8f420030,
+0x14520018, 0x0, 0x8f420000, 0x10400007,
+0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+0x0, 0x10000005, 0x0, 0xaf800048,
+0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+0x2403fff7, 0x431024, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x10000002, 0xaf80004c,
+0xaf800048, 0x8fbf002c, 0x8fb20028, 0x8fb10024,
+0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008,
+0x0, 0x27bdffd8, 0x3c020001, 0x34422ec0,
+0xafbf0020, 0x8f4300f0, 0x8f840108, 0x2e21021,
+0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
+0x2e21021, 0x401821, 0xaf4300f0, 0xac600000,
+0x8f4200ec, 0x8c660004, 0x14620004, 0x3c020001,
+0x24820020, 0x1000000f, 0xaf820108, 0x8f4300f0,
+0x34422ec0, 0x2e21021, 0x54620004, 0x24620008,
+0x3c020001, 0x34422cc0, 0x2e21021, 0x401821,
+0x8c620004, 0x21140, 0x821021, 0xaf820108,
+0xac600000, 0x8c850018, 0x30a20036, 0x1040006c,
+0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034,
+0x24420001, 0x2463ffff, 0x431024, 0x862021,
+0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034,
+0x8f420034, 0x8c03023c, 0x43102b, 0x144000ca,
+0x0, 0x32c20010, 0x10400028, 0x24070008,
+0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x24843838, 0xafa20014, 0x8f46002c,
-0x8f870120, 0x3c050009, 0xc0029bb, 0x34a50900,
-0x1000000f, 0x0, 0x8f4202f0, 0x24420001,
-0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2,
-0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
-0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
-0x8f420304, 0x24420001, 0xaf420304, 0x1000006b,
-0x8f420304, 0x10400022, 0x30a27000, 0x8c85001c,
-0x8f420028, 0xa22023, 0x4810003, 0x0,
-0x8f420040, 0x822021, 0x8f420348, 0x8f430000,
-0xaf450028, 0x441021, 0x10600007, 0xaf420348,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x34420008,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x1000004a, 0xaf80004c, 0x10000048, 0xaf800048,
-0x1040002f, 0x30a21000, 0x1040000c, 0x30a24000,
-0x8c83001c, 0x8f420050, 0x622023, 0x4820001,
-0x24840200, 0x8f42034c, 0x441021, 0xaf42034c,
-0x8f420358, 0x1000001a, 0xaf430050, 0x1040000c,
-0x32c28000, 0x8c83001c, 0x8f420070, 0x622023,
-0x4820001, 0x24840400, 0x8f420354, 0x441021,
-0xaf420354, 0x8f420358, 0x1000000d, 0xaf430070,
-0x1040000e, 0x3c020800, 0x8c83001c, 0x8f420060,
-0x622023, 0x4820001, 0x24840100, 0x8f420350,
-0x441021, 0xaf420350, 0x8f420358, 0xaf430060,
-0x441021, 0xaf420358, 0x3c020800, 0x2c21024,
-0x5040001a, 0x36940040, 0x10000018, 0x0,
-0x30a20100, 0x10400015, 0x0, 0x3c020001,
-0x8c423cc4, 0x1040000c, 0x0, 0x274301b0,
-0x24650400, 0x65102b, 0x10400007, 0x26e40028,
-0x8c820000, 0xac620000, 0x24630004, 0x65102b,
-0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6,
-0x24420001, 0xaf4202cc, 0x8f4202cc, 0x8fbf0020,
-0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
-0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048,
-0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038,
-0x8f910108, 0x26220020, 0xaf820108, 0x8e320018,
-0xa821, 0x32420024, 0x104001b7, 0xf021,
-0x8e26001c, 0x8f42001c, 0x61900, 0x431021,
-0x8c50000c, 0x9603000c, 0x962d0016, 0x9453000a,
-0x2c6205dd, 0x10400015, 0x2821, 0x32c20040,
-0x10400015, 0x24020800, 0x96030014, 0x14620012,
-0x3402aaaa, 0x9603000e, 0x14620007, 0x2021,
-0x96030010, 0x24020300, 0x14620004, 0x801021,
-0x96020012, 0x2c440001, 0x801021, 0x54400006,
-0x24050016, 0x10000004, 0x0, 0x24020800,
-0x50620001, 0x2405000e, 0x934205b4, 0x14400008,
-0x5821, 0x240b0001, 0x32620180, 0xaf4500a8,
-0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05b4,
-0x10a00085, 0x2054021, 0x91020000, 0x3821,
-0x3042000f, 0x25080, 0x32c20002, 0x10400012,
-0x10a1821, 0x32620002, 0x10400010, 0x32c20001,
-0x1002021, 0x94820000, 0x24840002, 0xe23821,
-0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02,
+0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x24846854, 0xafa20014, 0x8f46002c,
+0x8f870120, 0x3c050009, 0xc002b17, 0x34a51100,
+0x10000036, 0x0, 0x8f420300, 0x8f43002c,
+0x24420001, 0xaf420300, 0x8f420300, 0x24020001,
+0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170,
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+0x24020020, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x24020001, 0x3c010001, 0x370821, 0xa02240f0,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x24846848, 0xafa20014, 0x8f46002c, 0x8f870120,
+0x3c050009, 0xc002b17, 0x34a50900, 0x1000000f,
+0x0, 0x8f420300, 0x24420001, 0xaf420300,
+0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038,
+0x3c010001, 0x370821, 0xa02040f1, 0x3c010001,
+0x370821, 0xa02040f0, 0xaf400034, 0x8f420314,
+0x24420001, 0xaf420314, 0x1000006f, 0x8f420314,
+0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028,
+0xa22023, 0x4810003, 0x0, 0x8f420040,
+0x822021, 0x8f420358, 0x8f430000, 0xaf450028,
+0x441021, 0x10600007, 0xaf420358, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x34420008, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x1000004e,
+0xaf80004c, 0x1000004c, 0xaf800048, 0x1040002f,
+0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c,
+0x8f420050, 0x622023, 0x4820001, 0x24840200,
+0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368,
+0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000,
+0x8c83001c, 0x8f420070, 0x622023, 0x4820001,
+0x24840400, 0x8f420364, 0x441021, 0xaf420364,
+0x8f420368, 0x1000000d, 0xaf430070, 0x1040000e,
+0x3c020800, 0x8c83001c, 0x8f420060, 0x622023,
+0x4820001, 0x24840100, 0x8f420360, 0x441021,
+0xaf420360, 0x8f420368, 0xaf430060, 0x441021,
+0xaf420368, 0x3c020800, 0x2c21024, 0x5040001e,
+0x36940040, 0x1000001c, 0x0, 0x30a20100,
+0x10400019, 0x0, 0x3c020001, 0x8c426d44,
+0x1040000d, 0x274301c0, 0x24650400, 0x65102b,
+0x10400007, 0x26e40028, 0x8c820000, 0xac620000,
+0x24630004, 0x65102b, 0x1440fffb, 0x24840004,
+0x10000002, 0x274401c0, 0x26e40028, 0xc002bb4,
+0x0, 0x8f4202dc, 0xa34005c5, 0x24420001,
+0xaf4202dc, 0x8f4202dc, 0x8fbf0020, 0x3e00008,
+0x27bd0028, 0x3e00008, 0x0, 0x27bdffa8,
+0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
+0xafb20040, 0xafb1003c, 0xafb00038, 0x8f910108,
+0x26220020, 0xaf820108, 0x8e320018, 0xa821,
+0x32420024, 0x104001ba, 0xf021, 0x8e26001c,
+0x8f43001c, 0x61100, 0x621821, 0x8c70000c,
+0x9604000c, 0x962d0016, 0x9473000a, 0x2c8305dd,
+0x38828870, 0x2c420001, 0x621825, 0x10600015,
+0x2821, 0x32c20040, 0x10400015, 0x24020800,
+0x96030014, 0x14620012, 0x3402aaaa, 0x9603000e,
+0x14620007, 0x2021, 0x96030010, 0x24020300,
+0x14620004, 0x801021, 0x96020012, 0x2c440001,
+0x801021, 0x54400006, 0x24050016, 0x10000004,
+0x0, 0x24020800, 0x50820001, 0x2405000e,
+0x934205c3, 0x14400008, 0x5821, 0x240b0001,
+0x32620180, 0xaf4500a8, 0xaf5000a0, 0x10400002,
+0xaf4600a4, 0xa34b05c3, 0x10a00085, 0x2054021,
+0x91020000, 0x3821, 0x3042000f, 0x25080,
+0x32c20002, 0x10400012, 0x10a1821, 0x32620002,
+0x10400010, 0x32c20001, 0x1002021, 0x94820000,
+0x24840002, 0xe23821, 0x83102b, 0x1440fffb,
+0x30e2ffff, 0x71c02, 0x623821, 0x71c02,
+0x30e2ffff, 0x623821, 0x71027, 0xa502000a,
+0x32c20001, 0x1040006a, 0x32620001, 0x10400068,
+0x0, 0x8f4200a8, 0x10400065, 0x0,
+0x8f4200a0, 0x8f4300a8, 0x431021, 0x904c0009,
+0x318900ff, 0x39230006, 0x3182b, 0x39220011,
+0x2102b, 0x621824, 0x1060000c, 0x3c050006,
+0x8f4200a4, 0x3c040001, 0x24846864, 0xafa20010,
+0x8f4200a0, 0x34a54600, 0x1203821, 0xc002b17,
+0xafa20014, 0x1000004e, 0x0, 0x32c20004,
+0x14400013, 0x2821, 0x316200ff, 0x14400004,
+0x0, 0x95020002, 0x1000000d, 0x4a2823,
+0x9505000c, 0x9502000e, 0x95030010, 0xa22821,
+0xa32821, 0x95030012, 0x91040009, 0x95020002,
+0xa32821, 0xa42821, 0x4a1023, 0xa22821,
+0x2002021, 0x94820000, 0x24840002, 0xe23821,
+0x88102b, 0x1440fffb, 0x71c02, 0x30e2ffff,
0x623821, 0x71c02, 0x30e2ffff, 0x623821,
-0x71027, 0xa502000a, 0x32c20001, 0x1040006a,
-0x32620001, 0x10400068, 0x0, 0x8f4200a8,
-0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8,
-0x431021, 0x904c0009, 0x318900ff, 0x39230006,
-0x3182b, 0x39220011, 0x2102b, 0x621824,
-0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001,
-0x24843854, 0xafa20010, 0x8f4200a0, 0x34a54600,
-0x1203821, 0xc0029bb, 0xafa20014, 0x1000004e,
-0x0, 0x32c20004, 0x14400013, 0x2821,
-0x316200ff, 0x14400004, 0x0, 0x95020002,
-0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e,
-0x95030010, 0xa22821, 0xa32821, 0x95030012,
-0x91040009, 0x95020002, 0xa32821, 0xa42821,
-0x4a1023, 0xa22821, 0x2002021, 0x94820000,
-0x24840002, 0xe23821, 0x88102b, 0x1440fffb,
-0x71c02, 0x30e2ffff, 0x623821, 0x71c02,
-0x30e2ffff, 0x623821, 0x1a52821, 0x51c02,
-0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff,
-0x622821, 0xa72823, 0x51402, 0xa22821,
-0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff,
-0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8,
-0x624021, 0x91020000, 0x3042000f, 0x25080,
-0x318300ff, 0x24020006, 0x14620003, 0x10a1021,
-0x10000002, 0x24440010, 0x24440006, 0x316200ff,
-0x14400006, 0x0, 0x94820000, 0xa22821,
-0x51c02, 0x30a2ffff, 0x622821, 0x934205b4,
-0x10400003, 0x32620100, 0x50400003, 0xa4850000,
-0x52827, 0xa4850000, 0x9622000e, 0x8f43009c,
-0x621821, 0x32a200ff, 0x10400007, 0xaf43009c,
-0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c,
-0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c,
-0xafa20024, 0x32620080, 0x10400010, 0x32620100,
-0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
-0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
-0x220821, 0xac2338e8, 0x3c010001, 0x220821,
-0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064,
-0x0, 0x8f4200b4, 0x24430001, 0x210c0,
-0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024,
-0x3c010001, 0x220821, 0xac2338e8, 0x3c010001,
-0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051,
-0x3821, 0x3c090001, 0x352938e8, 0x3c08001f,
-0x3508ffff, 0x240bffff, 0x340affff, 0x710c0,
-0x571021, 0x491021, 0x8c430000, 0x8c440004,
-0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028,
-0x8fa4002c, 0xac430000, 0xac440004, 0x24420008,
-0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c,
-0x97a2002e, 0x8f440260, 0x8f450264, 0x401821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaf440260, 0xaf450264, 0x8fa20028,
-0x481024, 0x90430000, 0x30630001, 0x1460000b,
-0x402021, 0x8f420268, 0x8f43026c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420268, 0xaf43026c,
-0x8f420268, 0x1000001a, 0x8f43026c, 0x8c820000,
-0x144b000e, 0x0, 0x94820004, 0x144a000b,
-0x0, 0x8f420278, 0x8f43027c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
-0x8f420278, 0x1000000a, 0x8f43027c, 0x8f420270,
-0x8f430274, 0x24630001, 0x2c640001, 0x441021,
-0xaf420270, 0xaf430274, 0x8f420270, 0x8f430274,
-0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8,
-0x710c0, 0xa34005b4, 0x1000003f, 0xaf4000b4,
-0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
-0x8f46008c, 0x8f440260, 0x8f450264, 0x401821,
-0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaf440260,
-0xaf450264, 0x92020000, 0x30420001, 0x1440000c,
-0x2402ffff, 0x8f420268, 0x8f43026c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420268, 0xaf43026c,
-0x8f420268, 0x8f43026c, 0x1000001c, 0x32c20020,
-0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004,
-0x1462000c, 0x0, 0x8f420278, 0x8f43027c,
-0x24630001, 0x2c640001, 0x441021, 0xaf420278,
-0xaf43027c, 0x8f420278, 0x8f43027c, 0x1000000b,
-0x32c20020, 0x8f420270, 0x8f430274, 0x24630001,
-0x2c640001, 0x441021, 0xaf420270, 0xaf430274,
-0x8f420270, 0x8f430274, 0x32c20020, 0x10400005,
-0xaf40009c, 0x8f420348, 0x2442ffff, 0xaf420348,
-0x8f420348, 0x8e22001c, 0x8f430040, 0x24420001,
-0x2463ffff, 0x431024, 0xaf42002c, 0x32420060,
-0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
-0xaf420034, 0x8c03023c, 0x43102b, 0x14400114,
-0x32c20010, 0x10400018, 0x24070008, 0x8f440160,
-0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120,
-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047,
-0x24020001, 0x8f4202f0, 0x8f43002c, 0x24420001,
-0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2,
-0x1000007c, 0xaf430038, 0x8f440160, 0x8f450164,
-0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x10400057, 0x24020001,
-0x10000065, 0x0, 0x32420012, 0x10400075,
-0x32420001, 0x9622000e, 0x8f43009c, 0x621821,
-0x32c20020, 0x10400005, 0xaf43009c, 0x8f420348,
-0x2442ffff, 0xaf420348, 0x8f420348, 0x8e22001c,
+0x1a52821, 0x51c02, 0x30a2ffff, 0x622821,
+0x51c02, 0x30a2ffff, 0x622821, 0xa72823,
+0x51402, 0xa22821, 0x30a5ffff, 0x50a00001,
+0x3405ffff, 0x316200ff, 0x14400008, 0x318300ff,
+0x8f4300a0, 0x8f4200a8, 0x624021, 0x91020000,
+0x3042000f, 0x25080, 0x318300ff, 0x24020006,
+0x14620003, 0x10a1021, 0x10000002, 0x24440010,
+0x24440006, 0x316200ff, 0x14400006, 0x0,
+0x94820000, 0xa22821, 0x51c02, 0x30a2ffff,
+0x622821, 0x934205c3, 0x10400003, 0x32620100,
+0x50400003, 0xa4850000, 0x52827, 0xa4850000,
+0x9622000e, 0x8f43009c, 0x621821, 0x32a200ff,
+0x10400007, 0xaf43009c, 0x3c024000, 0x2021025,
+0xafa20020, 0x8f42009c, 0x10000003, 0x5e1025,
+0xafb00020, 0x8f42009c, 0xafa20024, 0x32620080,
+0x10400010, 0x32620100, 0x8f4200b4, 0x24430001,
+0x210c0, 0x571021, 0xaf4300b4, 0x8fa30020,
+0x8fa40024, 0x3c010001, 0x220821, 0xac2338e8,
+0x3c010001, 0x220821, 0xac2438ec, 0x100000a5,
+0x32c20020, 0x10400064, 0x0, 0x8f4200b4,
+0x24430001, 0x210c0, 0x571021, 0xaf4300b4,
+0x8fa30020, 0x8fa40024, 0x3c010001, 0x220821,
+0xac2338e8, 0x3c010001, 0x220821, 0xac2438ec,
+0x8f4200b4, 0x10400051, 0x3821, 0x3c090001,
+0x352938e8, 0x3c08001f, 0x3508ffff, 0x240bffff,
+0x340affff, 0x710c0, 0x571021, 0x491021,
+0x8c430000, 0x8c440004, 0xafa30028, 0xafa4002c,
+0x8f8200fc, 0x8fa30028, 0x8fa4002c, 0xac430000,
+0xac440004, 0x24420008, 0xaf8200f0, 0x8f42008c,
+0x2442ffff, 0xaf42008c, 0x97a2002e, 0x8f440270,
+0x8f450274, 0x401821, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xaf440270,
+0xaf450274, 0x8fa20028, 0x481024, 0x90430000,
+0x30630001, 0x1460000b, 0x402021, 0x8f420278,
+0x8f43027c, 0x24630001, 0x2c640001, 0x441021,
+0xaf420278, 0xaf43027c, 0x8f420278, 0x1000001a,
+0x8f43027c, 0x8c820000, 0x144b000e, 0x0,
+0x94820004, 0x144a000b, 0x0, 0x8f420288,
+0x8f43028c, 0x24630001, 0x2c640001, 0x441021,
+0xaf420288, 0xaf43028c, 0x8f420288, 0x1000000a,
+0x8f43028c, 0x8f420280, 0x8f430284, 0x24630001,
+0x2c640001, 0x441021, 0xaf420280, 0xaf430284,
+0x8f420280, 0x8f430284, 0x8f4200b4, 0x24e70001,
+0xe2102b, 0x1440ffb8, 0x710c0, 0xa34005c3,
+0x1000003f, 0xaf4000b4, 0x8f8200fc, 0x8fa30020,
+0x8fa40024, 0xac430000, 0xac440004, 0x24420008,
+0xaf8200f0, 0x8f42009c, 0x8f46008c, 0x8f440270,
+0x8f450274, 0x401821, 0x1021, 0x24c6ffff,
+0xaf46008c, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaf440270, 0xaf450274, 0x92020000,
+0x30420001, 0x1440000c, 0x2402ffff, 0x8f420278,
+0x8f43027c, 0x24630001, 0x2c640001, 0x441021,
+0xaf420278, 0xaf43027c, 0x8f420278, 0x8f43027c,
+0x1000001c, 0x32c20020, 0x8e030000, 0x1462000f,
+0x3402ffff, 0x96030004, 0x1462000c, 0x0,
+0x8f420288, 0x8f43028c, 0x24630001, 0x2c640001,
+0x441021, 0xaf420288, 0xaf43028c, 0x8f420288,
+0x8f43028c, 0x1000000b, 0x32c20020, 0x8f420280,
+0x8f430284, 0x24630001, 0x2c640001, 0x441021,
+0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
+0x32c20020, 0x10400005, 0xaf40009c, 0x8f420358,
+0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c,
0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
-0xaf42002c, 0x32420010, 0x14400008, 0x32c20010,
+0xaf42002c, 0x32420060, 0x14400008, 0x32c20010,
0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c,
-0x43102b, 0x144000ce, 0x32c20010, 0x10400028,
-0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c,
+0x43102b, 0x14400118, 0x32c20010, 0x10400018,
+0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x24843844, 0xafa20014,
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029bb,
-0x34a51100, 0x10000036, 0x0, 0x8f4202f0,
-0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0,
-0x24020001, 0xa34205b2, 0x10000026, 0xaf430038,
-0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c,
+0x24c6001c, 0x10400047, 0x24020001, 0x8f420300,
+0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
+0x24020001, 0xa34205c1, 0x1000007c, 0xaf430038,
+0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x24843838, 0xafa20014, 0x8f46002c,
-0x8f870120, 0x3c050009, 0xc0029bb, 0x34a50900,
-0x1000000f, 0x0, 0x8f4202f0, 0x24420001,
-0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2,
-0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
-0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
-0x8f420304, 0x24420001, 0xaf420304, 0x10000074,
-0x8f420304, 0x10400022, 0x32427000, 0x8e25001c,
-0x8f420028, 0xa22023, 0x4810003, 0x0,
-0x8f420040, 0x822021, 0x8f420348, 0x8f430000,
-0xaf450028, 0x441021, 0x10600007, 0xaf420348,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x34420008,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x10000053, 0xaf80004c, 0x10000051, 0xaf800048,
-0x1040002f, 0x32421000, 0x1040000c, 0x32424000,
-0x8e23001c, 0x8f420050, 0x622023, 0x4820001,
-0x24840200, 0x8f42034c, 0x441021, 0xaf42034c,
-0x8f420358, 0x1000001a, 0xaf430050, 0x1040000c,
-0x32c28000, 0x8e23001c, 0x8f420070, 0x622023,
-0x4820001, 0x24840400, 0x8f420354, 0x441021,
-0xaf420354, 0x8f420358, 0x1000000d, 0xaf430070,
-0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060,
-0x622023, 0x4820001, 0x24840100, 0x8f420350,
-0x441021, 0xaf420350, 0x8f420358, 0xaf430060,
-0x441021, 0xaf420358, 0x3c020800, 0x2c21024,
-0x50400023, 0x36940040, 0x10000021, 0x0,
-0x32420048, 0x10400007, 0x24150001, 0x8e22001c,
-0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd78,
-0xae22001c, 0x32420100, 0x10400015, 0x0,
-0x3c020001, 0x8c423cc4, 0x1040000c, 0x0,
-0x274301b0, 0x24650400, 0x65102b, 0x10400007,
-0x26e40028, 0x8c820000, 0xac620000, 0x24630004,
-0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc,
-0xa34005b6, 0x24420001, 0xaf4202cc, 0x8f4202cc,
-0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
-0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
-0x27bd0058, 0x3e00008, 0x0, 0x8f8400e0,
-0x8f8800c4, 0x8f8300e8, 0x2402fff8, 0x823824,
-0xe32023, 0x2c821000, 0x50400001, 0x24841000,
-0x420c2, 0x801821, 0x8f440248, 0x8f45024c,
+0x10400057, 0x24020001, 0x10000065, 0x0,
+0x32420012, 0x10400075, 0x32420001, 0x9622000e,
+0x8f43009c, 0x621821, 0x32c20020, 0x10400005,
+0xaf43009c, 0x8f420358, 0x2442ffff, 0xaf420358,
+0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001,
+0x2463ffff, 0x431024, 0xaf42002c, 0x32420010,
+0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
+0xaf420034, 0x8c03023c, 0x43102b, 0x144000d2,
+0x32c20010, 0x10400028, 0x24070008, 0x8f440170,
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x24846854, 0xafa20014, 0x8f46002c, 0x8f870120,
+0x3c050009, 0xc002b17, 0x34a51100, 0x10000036,
+0x0, 0x8f420300, 0x8f43002c, 0x24420001,
+0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
+0x10000026, 0xaf430038, 0x8f440170, 0x8f450174,
+0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
+0x3c010001, 0x370821, 0xa02240f0, 0x8f820124,
+0xafa20010, 0x8f820128, 0x3c040001, 0x24846848,
+0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009,
+0xc002b17, 0x34a50900, 0x1000000f, 0x0,
+0x8f420300, 0x24420001, 0xaf420300, 0x8f420300,
+0x8f42002c, 0xa34005c1, 0xaf420038, 0x3c010001,
+0x370821, 0xa02040f1, 0x3c010001, 0x370821,
+0xa02040f0, 0xaf400034, 0x8f420314, 0x24420001,
+0xaf420314, 0x10000078, 0x8f420314, 0x10400022,
+0x32427000, 0x8e25001c, 0x8f420028, 0xa22023,
+0x4810003, 0x0, 0x8f420040, 0x822021,
+0x8f420358, 0x8f430000, 0xaf450028, 0x441021,
+0x10600007, 0xaf420358, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x34420008, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x10000057, 0xaf80004c,
+0x10000055, 0xaf800048, 0x1040002f, 0x32421000,
+0x1040000c, 0x32424000, 0x8e23001c, 0x8f420050,
+0x622023, 0x4820001, 0x24840200, 0x8f42035c,
+0x441021, 0xaf42035c, 0x8f420368, 0x1000001a,
+0xaf430050, 0x1040000c, 0x32c28000, 0x8e23001c,
+0x8f420070, 0x622023, 0x4820001, 0x24840400,
+0x8f420364, 0x441021, 0xaf420364, 0x8f420368,
+0x1000000d, 0xaf430070, 0x1040000e, 0x3c020800,
+0x8e23001c, 0x8f420060, 0x622023, 0x4820001,
+0x24840100, 0x8f420360, 0x441021, 0xaf420360,
+0x8f420368, 0xaf430060, 0x441021, 0xaf420368,
+0x3c020800, 0x2c21024, 0x50400027, 0x36940040,
+0x10000025, 0x0, 0x32420048, 0x10400007,
+0x24150001, 0x8e22001c, 0x3c03ffff, 0x43f024,
+0x3042ffff, 0x1000fd75, 0xae22001c, 0x32420100,
+0x10400019, 0x0, 0x3c020001, 0x8c426d44,
+0x1040000d, 0x274301c0, 0x24650400, 0x65102b,
+0x10400007, 0x26e40028, 0x8c820000, 0xac620000,
+0x24630004, 0x65102b, 0x1440fffb, 0x24840004,
+0x10000002, 0x274401c0, 0x26e40028, 0xc002bb4,
+0x0, 0x8f4202dc, 0xa34005c5, 0x24420001,
+0xaf4202dc, 0x8f4202dc, 0x8fbf0050, 0x8fbe004c,
+0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c,
+0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008,
+0x0, 0x0, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x2404fff8, 0x441024, 0x621026,
+0x2102b, 0x21023, 0x3e00008, 0x621024,
+0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c,
+0xafb00018, 0x8f8600c4, 0x8f8400e0, 0x8f8500e4,
+0x2402fff8, 0x821824, 0x10a30009, 0x27623ff8,
+0x14a20002, 0x24a20008, 0x27623000, 0x408021,
+0x16030005, 0x30820004, 0x10400004, 0xc02021,
+0x10000022, 0x1021, 0x8e040000, 0x8f42011c,
+0x14a20003, 0x0, 0x8f420120, 0xaf420114,
+0x8ca30000, 0x8f420148, 0x831823, 0x43102b,
+0x10400003, 0x0, 0x8f420148, 0x621821,
+0x94a20006, 0x24420050, 0x62102b, 0x1440000f,
+0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000,
+0x8ca70004, 0x3c040001, 0xc002b17, 0x24846924,
+0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
+0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c,
+0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008,
+0x0, 0x8f8400e0, 0x8f8800c4, 0x8f8300e8,
+0x2402fff8, 0x823824, 0xe32023, 0x2c821000,
+0x50400001, 0x24841000, 0x420c2, 0x801821,
+0x8f440258, 0x8f45025c, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xaf440258,
+0xaf45025c, 0x8f8300c8, 0x8f420148, 0x1032023,
+0x82102b, 0x14400004, 0x801821, 0x8f420148,
+0x822021, 0x801821, 0x8f440250, 0x8f450254,
0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaf440248, 0xaf45024c, 0x8f8300c8,
-0x8f42013c, 0x1032023, 0x82102b, 0x14400004,
-0x801821, 0x8f42013c, 0x822021, 0x801821,
-0x8f440240, 0x8f450244, 0x1021, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaf440240,
-0xaf450244, 0xaf8800c8, 0xaf8700e4, 0xaf8700e8,
-0x3e00008, 0x0, 0x27bdff30, 0x240a0001,
-0xafbf00c8, 0xafbe00c4, 0xafb500c0, 0xafb300bc,
-0xafb200b8, 0xafb100b4, 0xafb000b0, 0xa3a00097,
-0xafa00044, 0xafaa005c, 0x934205b5, 0xa7a0008e,
-0x1040000a, 0xa7a00086, 0x8f4b00c4, 0xafab0064,
-0x8f4a00c0, 0xafaa006c, 0x8f4b00cc, 0xafab0074,
-0x8f4a00c8, 0x10000129, 0xafaa007c, 0x8f420114,
-0x40f809, 0x0, 0x403021, 0x10c0033f,
-0x0, 0x8cc20000, 0x8cc30004, 0xafa20020,
-0xafa30024, 0x8fab0024, 0x8faa0020, 0x3162ffff,
-0x2442fffc, 0xafa2006c, 0x3c020006, 0x2c21024,
-0xafab007c, 0x14400015, 0xafaa0064, 0x91420000,
-0x30420001, 0x10400011, 0x2402ffff, 0x8d430000,
-0x14620004, 0x3402ffff, 0x95430004, 0x1062000b,
-0x0, 0xc00233b, 0x8fa40064, 0x304200ff,
-0x14400006, 0x0, 0x8f420118, 0x40f809,
-0x0, 0x1000031d, 0x0, 0x8fa20024,
-0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff,
-0x431824, 0x14600003, 0xafa20024, 0x10000040,
-0x1821, 0x3c020080, 0x621024, 0x10400007,
-0x0, 0x8f42037c, 0x24420001, 0xaf42037c,
-0x8f42037c, 0x10000036, 0x24030001, 0x8f420200,
-0x24420001, 0xaf420200, 0x8f420200, 0x3c020001,
-0x621024, 0x10400006, 0x3c020002, 0x8f4201b4,
-0x24420001, 0xaf4201b4, 0x8f4201b4, 0x3c020002,
-0x621024, 0x10400006, 0x3c020004, 0x8f42036c,
-0x24420001, 0xaf42036c, 0x8f42036c, 0x3c020004,
-0x621024, 0x10400006, 0x3c020008, 0x8f420370,
-0x24420001, 0xaf420370, 0x8f420370, 0x3c020008,
-0x621024, 0x10400006, 0x3c020010, 0x8f420374,
-0x24420001, 0xaf420374, 0x8f420374, 0x3c020010,
-0x621024, 0x10400006, 0x3c020020, 0x8f4201b0,
-0x24420001, 0xaf4201b0, 0x8f4201b0, 0x3c020020,
-0x621024, 0x10400006, 0x24030001, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x24030001,
-0x8c020260, 0x8fab006c, 0x4b102b, 0x10400014,
-0x307000ff, 0x8f4201d8, 0x24420001, 0xaf4201d8,
-0x8f4201d8, 0x8faa007c, 0x8f8200e0, 0x354a0100,
-0xafaa007c, 0xafa20010, 0x8f8200e4, 0x24100001,
-0x3c040001, 0x24843914, 0xafa20014, 0x8fa60020,
-0x8fa70024, 0x3c050007, 0xc0029bb, 0x34a50800,
-0x12000010, 0x3c020080, 0x2c21024, 0x1440000e,
-0x32c20400, 0x8fab007c, 0x3c020080, 0x34420100,
-0x1621024, 0x10400005, 0x0, 0x8f4201fc,
-0x24420001, 0xaf4201fc, 0x8f4201fc, 0x100002a0,
-0x8fa3006c, 0x32c20400, 0x10400015, 0x34028100,
-0x8faa0064, 0x9543000c, 0x14620012, 0x3c020100,
-0x240b0200, 0xa7ab008e, 0x9542000e, 0x8d430008,
-0x8d440004, 0x8d450000, 0x8faa006c, 0x8fab0064,
-0x254afffc, 0xafaa006c, 0xa7a20086, 0xad63000c,
-0xad640008, 0xad650004, 0x256b0004, 0xafab0064,
-0x3c020100, 0x2c21024, 0x10400004, 0x0,
-0x8faa006c, 0x254a0004, 0xafaa006c, 0x8f4200bc,
-0x5040000a, 0xafa00074, 0x8fab006c, 0x4b102b,
-0x50400006, 0xafa00074, 0x8f4200bc, 0x1621023,
-0xafa20074, 0x8f4a00bc, 0xafaa006c, 0x8f420080,
-0x8fab006c, 0x4b102b, 0x10400056, 0x32c28000,
-0x1040005e, 0x240a0003, 0x32c21000, 0x1040005b,
-0xafaa005c, 0x10000058, 0x240b0004, 0x8f420340,
-0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340,
-0x1000023f, 0x8f420340, 0x2c2b025, 0x2402ffbf,
-0x282a024, 0x8f830128, 0x3c040001, 0x24843944,
-0x26620001, 0xafa20014, 0xafa30010, 0x8f860120,
-0x8f870124, 0x3c050007, 0xc0029bb, 0x34a52250,
-0x1000022f, 0x0, 0x2c2b025, 0x2402ffbf,
-0x282a024, 0x8f830128, 0x3c040001, 0x24843944,
-0x24020002, 0xafa20014, 0xafa30010, 0x8f860120,
-0x8f870124, 0x3c050007, 0xc0029bb, 0x34a52450,
-0x1000021f, 0x0, 0x8ea20000, 0x8ea30004,
-0x3c040001, 0x2484395c, 0xafb00010, 0xafbe0014,
-0x8ea70018, 0x34a52800, 0xc0029bb, 0x603021,
-0x10000213, 0x0, 0xa6b1000a, 0x8f820124,
-0x3c040001, 0x24843964, 0xafbe0014, 0xafa20010,
-0x8f460044, 0x8f870120, 0x3c050007, 0xc0029bb,
-0x34a53000, 0x10000206, 0x0, 0xa6b1000a,
-0xa6b2000e, 0x8f820124, 0x3c040001, 0x24843970,
+0x862021, 0xaf440250, 0xaf450254, 0xaf8800c8,
+0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0,
+0x27bdff30, 0x240a0001, 0xafbf00c8, 0xafbe00c4,
+0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4,
+0xafb000b0, 0xa3a00097, 0xafa00044, 0xafaa005c,
+0x934205c4, 0xa7a0008e, 0x1040000a, 0xa7a00086,
+0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c,
+0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129,
+0xafaa007c, 0x8f420114, 0x40f809, 0x0,
+0x403021, 0x10c0033f, 0x0, 0x8cc20000,
+0x8cc30004, 0xafa20020, 0xafa30024, 0x8fab0024,
+0x8faa0020, 0x3162ffff, 0x2442fffc, 0xafa2006c,
+0x3c020006, 0x2c21024, 0xafab007c, 0x14400015,
+0xafaa0064, 0x91420000, 0x30420001, 0x10400011,
+0x2402ffff, 0x8d430000, 0x14620004, 0x3402ffff,
+0x95430004, 0x1062000b, 0x0, 0xc002497,
+0x8fa40064, 0x304200ff, 0x14400006, 0x0,
+0x8f420118, 0x40f809, 0x0, 0x1000031d,
+0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
+0x431024, 0x3c03ffff, 0x431824, 0x14600003,
+0xafa20024, 0x10000040, 0x1821, 0x3c020080,
+0x621024, 0x10400007, 0x0, 0x8f42038c,
+0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
+0x24030001, 0x8f420210, 0x24420001, 0xaf420210,
+0x8f420210, 0x3c020001, 0x621024, 0x10400006,
+0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
+0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
+0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
+0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
+0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
+0x8f420380, 0x3c020008, 0x621024, 0x10400006,
+0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
+0x8f420384, 0x3c020010, 0x621024, 0x10400006,
+0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
+0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
+0x24030001, 0x8f420388, 0x24420001, 0xaf420388,
+0x8f420388, 0x24030001, 0x8c020260, 0x8fab006c,
+0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8,
+0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c,
+0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010,
+0x8f8200e4, 0x24100001, 0x3c040001, 0x24846930,
+0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
+0xc002b17, 0x34a50800, 0x12000010, 0x3c020080,
+0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c,
+0x3c020080, 0x34420100, 0x1621024, 0x10400005,
+0x0, 0x8f42020c, 0x24420001, 0xaf42020c,
+0x8f42020c, 0x100002a0, 0x8fa3006c, 0x32c20400,
+0x10400015, 0x34028100, 0x8faa0064, 0x9543000c,
+0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e,
+0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000,
+0x8faa006c, 0x8fab0064, 0x254afffc, 0xafaa006c,
+0xa7a20086, 0xad63000c, 0xad640008, 0xad650004,
+0x256b0004, 0xafab0064, 0x3c020100, 0x2c21024,
+0x10400004, 0x0, 0x8faa006c, 0x254a0004,
+0xafaa006c, 0x8f4200bc, 0x5040000a, 0xafa00074,
+0x8fab006c, 0x4b102b, 0x50400006, 0xafa00074,
+0x8f4200bc, 0x1621023, 0xafa20074, 0x8f4a00bc,
+0xafaa006c, 0x8f420080, 0x8fab006c, 0x4b102b,
+0x10400056, 0x32c28000, 0x1040005e, 0x240a0003,
+0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058,
+0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024,
+0x24420001, 0xaf420350, 0x1000023f, 0x8f420350,
+0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
+0x3c040001, 0x24846960, 0x26620001, 0xafa20014,
+0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
+0xc002b17, 0x34a52250, 0x1000022f, 0x0,
+0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
+0x3c040001, 0x24846960, 0x24020002, 0xafa20014,
+0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
+0xc002b17, 0x34a52450, 0x1000021f, 0x0,
+0x8ea20000, 0x8ea30004, 0x3c040001, 0x24846978,
+0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800,
+0xc002b17, 0x603021, 0x10000213, 0x0,
+0xa6b1000a, 0x8f820124, 0x3c040001, 0x24846980,
0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120,
-0x3c050007, 0xc0029bb, 0x34a53200, 0x100001f8,
-0x0, 0x8f420084, 0x8faa006c, 0x4a102b,
-0x14400007, 0x3c020001, 0x2c21024, 0x10400004,
-0x0, 0x240b0002, 0xafab005c, 0x8faa006c,
-0x1140020b, 0x27ab0020, 0xafab00a4, 0x3c0a001f,
-0x354affff, 0xafaa009c, 0x8fab005c, 0x240a0001,
-0x156a0021, 0x24020002, 0x8f430054, 0x8f420050,
-0x1062000b, 0x274b0054, 0x8f5e0054, 0x3403ecc0,
-0xafab004c, 0x27c20001, 0x304201ff, 0xafa20054,
-0x1e1140, 0x431021, 0x1000006b, 0x2e2a821,
-0x8f420044, 0x8faa006c, 0x3c040001, 0x24843920,
-0xafaa0014, 0xafa20010, 0x8f460054, 0x8f470050,
-0x3c050007, 0xc0029bb, 0x34a51300, 0x8f430340,
-0x2402ffbf, 0x282a024, 0x24630001, 0xaf430340,
-0x100001c3, 0x8f420340, 0x1562001d, 0x0,
-0x8f430074, 0x8f420070, 0x1062000a, 0x274a0074,
-0x8f5e0074, 0xafaa004c, 0x27c20001, 0x304203ff,
-0xafa20054, 0x1e1140, 0x24426cc0, 0x1000004a,
-0x2e2a821, 0x8f420044, 0x8fab006c, 0x3c040001,
-0x2484392c, 0x3c050007, 0xafab0014, 0xafa20010,
-0x8f460074, 0x8f470070, 0x34a51500, 0x240a0001,
-0xc0029bb, 0xafaa005c, 0x1000ffc3, 0x0,
-0x8f430064, 0x8f420060, 0x1062001a, 0x274b0064,
-0x8f5e0064, 0x8faa005c, 0xafab004c, 0x27c20001,
-0x304200ff, 0xafa20054, 0x24020004, 0x1542000e,
-0x1e1140, 0x1e1180, 0x24420cc0, 0x2e21021,
-0xafa20044, 0x9442002a, 0x8fab0044, 0x8faa006c,
-0x4a102b, 0x10400024, 0x25750020, 0x240b0001,
-0x10000021, 0xa3ab0097, 0x24424cc0, 0x1000001e,
-0x2e2a821, 0x8f420044, 0x8faa006c, 0x3c040001,
-0x24843938, 0xafaa0014, 0xafa20010, 0x8f460064,
-0x8f470060, 0x3c050007, 0xc0029bb, 0x34a51800,
-0x3c020008, 0x2c21024, 0x1440ff34, 0x0,
-0x8f420360, 0x240b0001, 0xafab005c, 0x24420001,
-0xaf420360, 0x1000ff90, 0x8f420360, 0x27a30036,
-0x131040, 0x621821, 0x94620000, 0x441021,
-0x10000020, 0xa4620000, 0x8faa0064, 0xaeaa0018,
-0x93a20097, 0x10400072, 0x9821, 0x8fab0044,
-0x8fa4006c, 0x8fa300a4, 0x25620020, 0xafa20028,
-0x25620008, 0xafa20030, 0x25620010, 0xafab002c,
-0xafa20034, 0x9562002a, 0xa7a20038, 0x95620018,
-0xa7a2003a, 0x9562001a, 0xa7a2003c, 0x9562001c,
-0xa7a2003e, 0x94620018, 0x24630002, 0x822023,
-0x1880ffde, 0x26730001, 0x2e620004, 0x1440fff9,
-0x0, 0x8f4200fc, 0x26650001, 0xa2102a,
-0x1440002b, 0x24030001, 0x8f83012c, 0x10600023,
-0x0, 0x8f820124, 0x431023, 0x22143,
-0x58800001, 0x24840040, 0x8f820128, 0x431023,
-0x21943, 0x58600001, 0x24630040, 0x64102a,
-0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc,
-0xa2102a, 0x10400011, 0x24030001, 0x10000015,
-0x306200ff, 0x8faa0064, 0x96070018, 0xafaa0010,
-0x8e220008, 0x3c040001, 0x24843950, 0x8c430004,
-0x8c420000, 0x34a52400, 0x2403021, 0xc0029bb,
-0xafa30014, 0x1000002b, 0x0, 0x8f420324,
-0x1821, 0x24420001, 0xaf420324, 0x8f420324,
-0x306200ff, 0x5040fedc, 0x3c020800, 0x12600021,
-0x9021, 0x8fb100a4, 0x2208021, 0x8e220008,
-0x96070018, 0x8fa60064, 0x8c440000, 0x8c450004,
-0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008,
-0xafa20018, 0x8f42010c, 0x40f809, 0x0,
-0x1040ffd8, 0x3c050007, 0x96020018, 0x8faa0064,
-0x8fab009c, 0x1425021, 0x16a102b, 0x10400004,
-0xafaa0064, 0x8f42013c, 0x1425023, 0xafaa0064,
-0x26100002, 0x26520001, 0x253102b, 0x1440ffe3,
-0x26310004, 0x8fb0006c, 0x10000036, 0x97b10038,
-0x8f4200fc, 0x24050002, 0xa2102a, 0x1440001b,
-0x24030001, 0x8f83012c, 0x10600013, 0x0,
-0x8f820124, 0x431023, 0x22143, 0x58800001,
-0x24840040, 0x8f820128, 0x431023, 0x21943,
-0x58600001, 0x24630040, 0x64102a, 0x54400001,
-0x602021, 0xaf4400fc, 0x8f4200fc, 0xa2102a,
-0x14400006, 0x24030001, 0x8f420324, 0x1821,
-0x24420001, 0xaf420324, 0x8f420324, 0x306200ff,
-0x1040fea5, 0x3c020800, 0x96b1000a, 0x8fb0006c,
-0x3223ffff, 0x70102b, 0x54400001, 0x608021,
-0x8ea40000, 0x8ea50004, 0x240a0001, 0xafaa0010,
-0xafbe0014, 0x8f420008, 0x8fa60064, 0xafa20018,
-0x8f42010c, 0x40f809, 0x2003821, 0x1040fea2,
-0x3c050007, 0x96a3000e, 0x97ab008e, 0x11600007,
-0x609021, 0x934205b5, 0x14400004, 0x0,
-0x97aa0086, 0x6b1825, 0xa6aa0016, 0x8fab007c,
-0x3c02ffff, 0x1621024, 0x10400003, 0xb1402,
-0x34630400, 0xa6a20014, 0x8faa006c, 0x560a0072,
-0xa6a3000e, 0x34620004, 0xa6a2000e, 0x8fab0074,
-0x14b1021, 0xa6a2000a, 0x8f430044, 0x8f440190,
-0x8f450194, 0x34028000, 0xafa20010, 0x8f420044,
-0x2a03021, 0x24070020, 0xafa20014, 0x8f42000c,
-0x31940, 0x604821, 0xafa20018, 0x8f42010c,
-0x4021, 0xa92821, 0xa9182b, 0x882021,
-0x40f809, 0x832021, 0x5040fe7f, 0xa6b2000e,
-0x8f420358, 0xafa0006c, 0xa34005b5, 0x2442ffff,
-0xaf420358, 0x8faa005c, 0x240b0001, 0x8f420358,
-0x154b0006, 0x24020002, 0x8f42034c, 0x2442ffff,
-0xaf42034c, 0x1000000c, 0x8f42034c, 0x15420006,
-0x0, 0x8f420354, 0x2442ffff, 0xaf420354,
-0x10000005, 0x8f420354, 0x8f420350, 0x2442ffff,
-0xaf420350, 0x8f420350, 0x8faa0054, 0x8fab004c,
-0xad6a0000, 0x8f420044, 0x8f440088, 0x8f430078,
-0x24420001, 0x441024, 0x24630001, 0xaf420044,
-0xaf430078, 0x8c020240, 0x62182b, 0x14600065,
-0x24070008, 0x8f440158, 0x8f45015c, 0x8f430044,
-0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010,
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x240b0001, 0x3c010001,
-0x370821, 0xa02b40f2, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x2484390c, 0xafa20014,
-0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb,
-0x34a51300, 0x1000000b, 0x0, 0x8f4202f4,
-0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044,
-0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2,
-0xaf400078, 0x8f420308, 0x24420001, 0xaf420308,
-0x10000038, 0x8f420308, 0xa6b0000a, 0x8f430044,
-0x8f440190, 0x8f450194, 0x34028000, 0xafa20010,
-0x8f420044, 0x2a03021, 0x24070020, 0xafa20014,
-0x8f42000c, 0x31940, 0x604821, 0xafa20018,
-0x8f42010c, 0x4021, 0xa92821, 0xa9182b,
-0x882021, 0x40f809, 0x832021, 0x1040fe1f,
-0x240a0001, 0xa34a05b5, 0x8fab006c, 0x8faa0064,
-0x1705823, 0xafab006c, 0x8fab009c, 0x1505021,
-0x16a102b, 0x10400004, 0xafaa0064, 0x8f42013c,
-0x1425023, 0xafaa0064, 0x8f420358, 0x2442ffff,
-0xaf420358, 0x8f420358, 0x8f42034c, 0x2442ffff,
-0xaf42034c, 0x8fab0054, 0x8faa004c, 0x8f42034c,
-0xad4b0000, 0x8f420044, 0x8f440088, 0x8f430078,
-0x24420001, 0x441024, 0x24630001, 0xaf420044,
-0xaf430078, 0x8faa006c, 0x1540fe1b, 0x0,
-0x8fab006c, 0x1160001e, 0x0, 0x934205b5,
-0x10400009, 0x0, 0x8faa0064, 0xaf4a00c4,
-0xaf4b00c0, 0x8fab007c, 0xaf4b00c8, 0x8faa0074,
-0x1000000e, 0xaf4a00cc, 0x97ab008e, 0x1160000b,
-0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c,
-0x97aa0086, 0x8c440004, 0x8c450008, 0xa44a000e,
-0xac440000, 0xac450004, 0xac460008, 0x8f42033c,
-0x24420001, 0xaf42033c, 0x10000010, 0x8f42033c,
-0x8fab007c, 0x3164ffff, 0x2484fffc, 0x801821,
-0x8f440240, 0x8f450244, 0x8f460118, 0x1021,
-0xa32821, 0xa3382b, 0x822021, 0x872021,
-0xaf440240, 0xc0f809, 0xaf450244, 0x8fbf00c8,
-0x8fbe00c4, 0x8fb500c0, 0x8fb300bc, 0x8fb200b8,
-0x8fb100b4, 0x8fb000b0, 0x3e00008, 0x27bd00d0,
-0x3e00008, 0x0, 0x27bdff38, 0x240b0001,
-0xafbf00c0, 0xafbe00bc, 0xafb500b8, 0xafb300b4,
-0xafb200b0, 0xafb100ac, 0xafb000a8, 0xa3a00087,
-0xafa00044, 0xafab005c, 0x934205b5, 0xa7a00076,
-0x10400007, 0xa7a0007e, 0x8f4c00c0, 0xafac0064,
-0x8f4b00c8, 0x8f5e00c4, 0x1000012d, 0xafab006c,
-0x8f420114, 0x40f809, 0x0, 0x403021,
-0x10c0029e, 0x0, 0x8cc20000, 0x8cc30004,
-0xafa20020, 0xafa30024, 0x8fac0024, 0x8fbe0020,
-0x3182ffff, 0x2442fffc, 0xafa20064, 0x3c020006,
-0x2c21024, 0x14400015, 0xafac006c, 0x93c20000,
-0x30420001, 0x10400011, 0x2402ffff, 0x8fc30000,
-0x14620004, 0x3402ffff, 0x97c30004, 0x1062000b,
-0x0, 0xc00233b, 0x3c02021, 0x304200ff,
-0x14400006, 0x0, 0x8f420118, 0x40f809,
-0x0, 0x1000027d, 0x0, 0x8fa20024,
-0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff,
-0x431824, 0x14600003, 0xafa20024, 0x10000040,
-0x8021, 0x3c020080, 0x621024, 0x10400007,
-0x0, 0x8f42037c, 0x24420001, 0xaf42037c,
-0x8f42037c, 0x10000036, 0x24100001, 0x8f420200,
-0x24420001, 0xaf420200, 0x8f420200, 0x3c020001,
-0x621024, 0x10400006, 0x3c020002, 0x8f4201b4,
-0x24420001, 0xaf4201b4, 0x8f4201b4, 0x3c020002,
-0x621024, 0x10400006, 0x3c020004, 0x8f42036c,
-0x24420001, 0xaf42036c, 0x8f42036c, 0x3c020004,
-0x621024, 0x10400006, 0x3c020008, 0x8f420370,
-0x24420001, 0xaf420370, 0x8f420370, 0x3c020008,
-0x621024, 0x10400006, 0x3c020010, 0x8f420374,
-0x24420001, 0xaf420374, 0x8f420374, 0x3c020010,
-0x621024, 0x10400006, 0x3c020020, 0x8f4201b0,
-0x24420001, 0xaf4201b0, 0x8f4201b0, 0x3c020020,
-0x621024, 0x10400006, 0x24100001, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x24100001,
-0x8c020260, 0x8fab0064, 0x4b102b, 0x10400015,
-0x320200ff, 0x8f4201d8, 0x24420001, 0xaf4201d8,
-0x8f4201d8, 0x8fac006c, 0x8f8200e0, 0x358c0100,
-0xafac006c, 0xafa20010, 0x8f8200e4, 0x24100001,
-0x3c040001, 0x24843914, 0xafa20014, 0x8fa60020,
-0x8fa70024, 0x3c050007, 0xc0029bb, 0x34a53600,
-0x320200ff, 0x10400010, 0x3c020080, 0x2c21024,
-0x1440000e, 0x32c20400, 0x8fab006c, 0x3c020080,
-0x34420100, 0x1621024, 0x10400005, 0x0,
-0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc,
-0x100001ff, 0x8fa30064, 0x32c20400, 0x10400012,
-0x34028100, 0x97c3000c, 0x1462000f, 0x0,
-0x240c0200, 0xa7ac0076, 0x97c2000e, 0x8fc30008,
-0x8fc40004, 0x8fab0064, 0x8fc50000, 0x256bfffc,
-0xafab0064, 0xa7a2007e, 0xafc3000c, 0xafc40008,
-0xafc50004, 0x27de0004, 0x8fa70064, 0x320200ff,
-0x14400031, 0x3c020100, 0x97c3000c, 0x2c6205dd,
-0x10400015, 0x2821, 0x32c20800, 0x10400015,
-0x24020800, 0x97c30014, 0x14620012, 0x3402aaaa,
-0x97c3000e, 0x14620007, 0x2021, 0x97c30010,
-0x24020300, 0x14620004, 0x801021, 0x97c20012,
-0x2c440001, 0x801021, 0x54400006, 0x24050016,
-0x10000004, 0x0, 0x24020800, 0x50620001,
-0x2405000e, 0x10a00013, 0x3c52021, 0x24830009,
-0x3c02001f, 0x3442ffff, 0x43102b, 0x10400003,
-0x0, 0x8f42013c, 0x621823, 0x90620000,
-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x10600004, 0x3c020100, 0x94820002,
-0x453821, 0x3c020100, 0x2c21024, 0x5040000e,
-0xafa70064, 0x8fac0064, 0x10ec0008, 0x3c050007,
-0x3c040001, 0x2484397c, 0x8fa60064, 0x34a54000,
-0xafa00010, 0xc0029bb, 0xafa00014, 0x8fab0064,
-0x256b0004, 0xafab0064, 0x8f420080, 0x8fac0064,
-0x4c102b, 0x1040002c, 0x32c28000, 0x10400034,
-0x240b0003, 0x32c21000, 0x10400031, 0xafab005c,
-0x1000002e, 0x240c0004, 0x8f420340, 0x2403ffbf,
-0x283a024, 0x24420001, 0xaf420340, 0x10000173,
-0x8f420340, 0x3c020800, 0x2c2b025, 0x2402ffbf,
-0x282a024, 0x8f830128, 0x3c040001, 0x24843944,
-0x26620001, 0xafa20014, 0xafa30010, 0x8f860120,
-0x8f870124, 0x3c050007, 0xc0029bb, 0x34a55300,
-0x10000162, 0x0, 0x8ea20000, 0x8ea30004,
-0x3c040001, 0x2484395c, 0xafb00010, 0xafb10014,
-0x8ea70018, 0x34a55900, 0xc0029bb, 0x603021,
-0x10000156, 0x0, 0x8f420084, 0x8fab0064,
-0x4b102b, 0x14400007, 0x3c020001, 0x2c21024,
-0x10400004, 0x0, 0x240c0002, 0xafac005c,
-0x8fab0064, 0x11600166, 0x27ac0020, 0xafac008c,
-0x8fab005c, 0x240c0001, 0x556c0021, 0x240c0002,
+0x3c050007, 0xc002b17, 0x34a53000, 0x10000206,
+0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124,
+0x3c040001, 0x2484698c, 0xafbe0014, 0xafa20010,
+0x8f460044, 0x8f870120, 0x3c050007, 0xc002b17,
+0x34a53200, 0x100001f8, 0x0, 0x8f420084,
+0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001,
+0x2c21024, 0x10400004, 0x0, 0x240b0002,
+0xafab005c, 0x8faa006c, 0x1140020b, 0x27ab0020,
+0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c,
+0x8fab005c, 0x240a0001, 0x156a0021, 0x24020002,
0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054,
-0x8f510054, 0x3403ecc0, 0xafab004c, 0x26220001,
-0x304201ff, 0xafa20054, 0x111140, 0x431021,
-0x1000006b, 0x2e2a821, 0x8f420044, 0x8fac0064,
-0x3c040001, 0x24843920, 0xafac0014, 0xafa20010,
-0x8f460054, 0x8f470050, 0x3c050007, 0xc0029bb,
-0x34a54300, 0x8f430340, 0x2402ffbf, 0x282a024,
-0x24630001, 0xaf430340, 0x10000124, 0x8f420340,
-0x156c001d, 0x0, 0x8f430074, 0x8f420070,
-0x1062000a, 0x274b0074, 0x8f510074, 0xafab004c,
-0x26220001, 0x304203ff, 0xafa20054, 0x111140,
+0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001,
+0x304201ff, 0xafa20054, 0x1e1140, 0x431021,
+0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c,
+0x3c040001, 0x2484693c, 0xafaa0014, 0xafa20010,
+0x8f460054, 0x8f470050, 0x3c050007, 0xc002b17,
+0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024,
+0x24630001, 0xaf430350, 0x100001c3, 0x8f420350,
+0x1562001d, 0x0, 0x8f430074, 0x8f420070,
+0x1062000a, 0x274a0074, 0x8f5e0074, 0xafaa004c,
+0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140,
0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044,
-0x8fac0064, 0x3c040001, 0x2484392c, 0x3c050007,
-0xafac0014, 0xafa20010, 0x8f460074, 0x8f470070,
-0x34a54500, 0x240b0001, 0xc0029bb, 0xafab005c,
+0x8fab006c, 0x3c040001, 0x24846948, 0x3c050007,
+0xafab0014, 0xafa20010, 0x8f460074, 0x8f470070,
+0x34a51500, 0x240a0001, 0xc002b17, 0xafaa005c,
0x1000ffc3, 0x0, 0x8f430064, 0x8f420060,
-0x1062001a, 0x274c0064, 0x8f510064, 0x8fab005c,
-0xafac004c, 0x26220001, 0x304200ff, 0xafa20054,
-0x24020004, 0x1562000e, 0x111140, 0x111180,
+0x1062001a, 0x274b0064, 0x8f5e0064, 0x8faa005c,
+0xafab004c, 0x27c20001, 0x304200ff, 0xafa20054,
+0x24020004, 0x1542000e, 0x1e1140, 0x1e1180,
0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a,
-0x8fac0044, 0x8fab0064, 0x4b102b, 0x10400024,
-0x25950020, 0x240c0001, 0x10000021, 0xa3ac0087,
+0x8fab0044, 0x8faa006c, 0x4a102b, 0x10400024,
+0x25750020, 0x240b0001, 0x10000021, 0xa3ab0097,
0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044,
-0x8fab0064, 0x3c040001, 0x24843938, 0xafab0014,
+0x8faa006c, 0x3c040001, 0x24846954, 0xafaa0014,
0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007,
-0xc0029bb, 0x34a54800, 0x3c020008, 0x2c21024,
-0x1440ff61, 0x0, 0x8f420360, 0x240c0001,
-0xafac005c, 0x24420001, 0xaf420360, 0x1000ff90,
-0x8f420360, 0x27a30036, 0x131040, 0x621821,
-0x94620000, 0x441021, 0x1000001f, 0xa4620000,
-0xaebe0018, 0x93a20087, 0x10400084, 0x9821,
-0x8fab0044, 0x8fa40064, 0x8fa3008c, 0x25620020,
-0xafa20028, 0x25620008, 0xafa20030, 0x25620010,
-0xafab002c, 0xafa20034, 0x9562002a, 0xa7a20038,
-0x95620018, 0xa7a2003a, 0x9562001a, 0xa7a2003c,
-0x9562001c, 0xa7a2003e, 0x94620018, 0x24630002,
-0x822023, 0x1880ffdf, 0x26730001, 0x2e620004,
-0x1440fff9, 0x0, 0x8f4200fc, 0x262102a,
-0x14400030, 0x24030001, 0x8f83012c, 0x10600028,
-0x0, 0x8f820124, 0x431023, 0x22143,
-0x58800001, 0x24840040, 0x8f820128, 0x431023,
-0x21943, 0x58600001, 0x24630040, 0x64102a,
-0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc,
-0x262102a, 0x10400016, 0x24030001, 0x1000001a,
-0x306200ff, 0x8fac008c, 0x101040, 0x4c1021,
-0x94470018, 0x101080, 0x4c1021, 0xafbe0010,
-0x8c420008, 0x3c040001, 0x24843950, 0x3c050007,
-0x8c430004, 0x8c420000, 0x34a55500, 0x2003021,
-0xc0029bb, 0xafa30014, 0x10000039, 0x0,
-0x8f420324, 0x1821, 0x24420001, 0xaf420324,
-0x8f420324, 0x306200ff, 0x1040ff06, 0x8021,
-0x8f430008, 0x2402fbff, 0x1260002d, 0x625024,
-0x3c0b4000, 0x22b4025, 0x8fb1008c, 0x2669ffff,
-0x2209021, 0x8e420008, 0x96270018, 0x8c440000,
-0x8c450004, 0x56090004, 0x240b0001, 0x240c0002,
-0x10000002, 0xafac0010, 0xafab0010, 0x16000004,
-0xafa80014, 0x8f420008, 0x10000002, 0xafa20018,
-0xafaa0018, 0x8f42010c, 0x3c03021, 0xafa80098,
-0xafa9009c, 0x40f809, 0xafaa00a0, 0x8fa80098,
-0x8fa9009c, 0x8faa00a0, 0x1040ffc2, 0x3c02001f,
-0x96230018, 0x3442ffff, 0x3c3f021, 0x5e102b,
-0x10400003, 0x26310002, 0x8f42013c, 0x3c2f023,
-0x26100001, 0x213102b, 0x1440ffda, 0x26520004,
-0x8fb00064, 0x1000001a, 0x0, 0x96a3000a,
-0x8fb00064, 0x70102b, 0x54400001, 0x608021,
-0x8ea40000, 0x8ea50004, 0x8fab005c, 0x240c0002,
-0xafac0010, 0x934305b5, 0xb1700, 0x10600003,
-0x2223025, 0x3c020800, 0xc23025, 0xafa60014,
-0x8f420008, 0xafa20018, 0x8f42010c, 0x3c03021,
-0x40f809, 0x2003821, 0x1040fecb, 0x3c050007,
-0x97ac0076, 0x11800007, 0x96a3000e, 0x934205b5,
-0x14400004, 0x0, 0x97ab007e, 0x6c1825,
-0xa6ab0016, 0x8fac006c, 0x3c02ffff, 0x1821024,
-0x10400003, 0xc1402, 0x34630400, 0xa6a20014,
-0xa6b0000a, 0x8fab0064, 0x560b0006, 0x3d0f021,
-0x34620004, 0xafa00064, 0xa6a2000e, 0x1000000d,
-0xa34005b5, 0x8fac0064, 0x3c02001f, 0x3442ffff,
-0x5e102b, 0x1906023, 0xafac0064, 0xa6a3000e,
-0x240b0001, 0x10400003, 0xa34b05b5, 0x8f42013c,
-0x3c2f023, 0x8fab0054, 0x8fac004c, 0xad8b0000,
-0x8fac0064, 0x1580feba, 0x0, 0x8fab0064,
-0x1160001b, 0x0, 0x934205b5, 0x10400006,
-0x0, 0xaf5e00c4, 0xaf4b00c0, 0x8fac006c,
-0x1000000e, 0xaf4c00c8, 0x97ab0076, 0x1160000b,
-0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c,
-0x97ac007e, 0x8c440004, 0x8c450008, 0xa44c000e,
-0xac440000, 0xac450004, 0xac460008, 0x8f42033c,
-0x24420001, 0xaf42033c, 0x10000010, 0x8f42033c,
-0x8fab006c, 0x3164ffff, 0x2484fffc, 0x801821,
-0x8f440240, 0x8f450244, 0x8f460118, 0x1021,
-0xa32821, 0xa3382b, 0x822021, 0x872021,
-0xaf440240, 0xc0f809, 0xaf450244, 0x8fbf00c0,
-0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, 0x8fb200b0,
-0x8fb100ac, 0x8fb000a8, 0x3e00008, 0x27bd00c8,
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
-0xafb00020, 0x8f43005c, 0x8f420058, 0x10620049,
-0x0, 0x8f430058, 0x8f42005c, 0x622023,
-0x4820001, 0x24840100, 0x8f430064, 0x8f42005c,
-0x43102b, 0x14400004, 0x24020100, 0x8f43005c,
-0x10000005, 0x431023, 0x8f420064, 0x8f43005c,
-0x431023, 0x2442ffff, 0x403821, 0x87102a,
-0x54400001, 0x803821, 0x8f42005c, 0x471021,
-0x305000ff, 0x32c21000, 0x10400015, 0x24082000,
-0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c,
-0x73980, 0xafa80010, 0xafb00014, 0x8f480014,
-0x94980, 0x1201821, 0x1021, 0xa32821,
-0xa3482b, 0x822021, 0x892021, 0x63180,
-0xafa80018, 0x8f420108, 0x10000014, 0x24c60cc0,
-0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c,
-0x73940, 0xafa80010, 0xafb00014, 0x8f480014,
-0x94940, 0x1201821, 0x1021, 0xa32821,
-0xa3482b, 0x822021, 0x892021, 0x63140,
-0xafa80018, 0x8f420108, 0x24c64cc0, 0x40f809,
-0x2e63021, 0x54400001, 0xaf50005c, 0x8f43005c,
-0x8f420058, 0x14620018, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x2403feff, 0x431024, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000002,
-0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
-0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
-0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43006c,
-0x8f420068, 0x10620033, 0x0, 0x8f430068,
-0x8f42006c, 0x622023, 0x4820001, 0x24840400,
-0x8f430074, 0x8f42006c, 0x43102b, 0x14400004,
-0x24020400, 0x8f43006c, 0x10000005, 0x431023,
-0x8f420074, 0x8f43006c, 0x431023, 0x2442ffff,
-0x405021, 0x8a102a, 0x54400001, 0x805021,
-0x8f49006c, 0x8f48006c, 0x8f440188, 0x8f45018c,
-0x8f46006c, 0x24074000, 0xafa70010, 0x84140,
-0x1001821, 0x12a4821, 0x313003ff, 0xafb00014,
-0x8f470014, 0x1021, 0x63140, 0x24c66cc0,
-0xafa70018, 0xa32821, 0xa3382b, 0x822021,
-0x872021, 0x8f420108, 0x2e63021, 0x40f809,
-0xa3940, 0x54400001, 0xaf50006c, 0x8f43006c,
-0x8f420068, 0x14620018, 0x0, 0x8f420000,
+0xc002b17, 0x34a51800, 0x3c020008, 0x2c21024,
+0x1440ff34, 0x0, 0x8f420370, 0x240b0001,
+0xafab005c, 0x24420001, 0xaf420370, 0x1000ff90,
+0x8f420370, 0x27a30036, 0x131040, 0x621821,
+0x94620000, 0x441021, 0x10000020, 0xa4620000,
+0x8faa0064, 0xaeaa0018, 0x93a20097, 0x10400072,
+0x9821, 0x8fab0044, 0x8fa4006c, 0x8fa300a4,
+0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
+0x25620010, 0xafab002c, 0xafa20034, 0x9562002a,
+0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a,
+0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018,
+0x24630002, 0x822023, 0x1880ffde, 0x26730001,
+0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
+0x26650001, 0xa2102a, 0x1440002b, 0x24030001,
+0x8f83012c, 0x10600023, 0x0, 0x8f820124,
+0x431023, 0x22143, 0x58800001, 0x24840040,
+0x8f820128, 0x431023, 0x21943, 0x58600001,
+0x24630040, 0x64102a, 0x54400001, 0x602021,
+0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011,
+0x24030001, 0x10000015, 0x306200ff, 0x8faa0064,
+0x96070018, 0xafaa0010, 0x8e220008, 0x3c040001,
+0x2484696c, 0x8c430004, 0x8c420000, 0x34a52400,
+0x2403021, 0xc002b17, 0xafa30014, 0x1000002b,
+0x0, 0x8f420334, 0x1821, 0x24420001,
+0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc,
+0x3c020800, 0x12600021, 0x9021, 0x8fb100a4,
+0x2208021, 0x8e220008, 0x96070018, 0x8fa60064,
+0x8c440000, 0x8c450004, 0x240b0001, 0xafab0010,
+0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c,
+0x40f809, 0x0, 0x1040ffd8, 0x3c050007,
+0x96020018, 0x8faa0064, 0x8fab009c, 0x1425021,
+0x16a102b, 0x10400004, 0xafaa0064, 0x8f420148,
+0x1425023, 0xafaa0064, 0x26100002, 0x26520001,
+0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c,
+0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002,
+0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c,
+0x10600013, 0x0, 0x8f820124, 0x431023,
+0x22143, 0x58800001, 0x24840040, 0x8f820128,
+0x431023, 0x21943, 0x58600001, 0x24630040,
+0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
+0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001,
+0x8f420334, 0x1821, 0x24420001, 0xaf420334,
+0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800,
+0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b,
+0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
+0x240a0001, 0xafaa0010, 0xafbe0014, 0x8f420008,
+0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809,
+0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e,
+0x97ab008e, 0x11600007, 0x609021, 0x934205c4,
+0x14400004, 0x0, 0x97aa0086, 0x6b1825,
+0xa6aa0016, 0x8fab007c, 0x3c02ffff, 0x1621024,
+0x10400003, 0xb1402, 0x34630400, 0xa6a20014,
+0x8faa006c, 0x560a0072, 0xa6a3000e, 0x34620004,
+0xa6a2000e, 0x8fab0074, 0x14b1021, 0xa6a2000a,
+0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000,
+0xafa20010, 0x8f420044, 0x2a03021, 0x24070020,
+0xafa20014, 0x8f42000c, 0x31940, 0x604821,
+0xafa20018, 0x8f42010c, 0x4021, 0xa92821,
+0xa9182b, 0x882021, 0x40f809, 0x832021,
+0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c,
+0xa34005c4, 0x2442ffff, 0xaf420368, 0x8faa005c,
+0x240b0001, 0x8f420368, 0x154b0006, 0x24020002,
+0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
+0x8f42035c, 0x15420006, 0x0, 0x8f420364,
+0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364,
+0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360,
+0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044,
+0x8f440088, 0x8f430078, 0x24420001, 0x441024,
+0x24630001, 0xaf420044, 0xaf430078, 0x8c020240,
+0x62182b, 0x14600065, 0x24070008, 0x8f440168,
+0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120,
+0x24020040, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x2484691c, 0xafa20014, 0x8f460044, 0x8f870120,
+0x3c050009, 0xc002b17, 0x34a51300, 0x1000000b,
+0x0, 0x8f420304, 0x24420001, 0xaf420304,
+0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001,
+0x370821, 0xa02040f2, 0xaf400078, 0x8f420318,
+0x24420001, 0xaf420318, 0x10000038, 0x8f420318,
+0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4,
+0x34028000, 0xafa20010, 0x8f420044, 0x2a03021,
+0x24070020, 0xafa20014, 0x8f42000c, 0x31940,
+0x604821, 0xafa20018, 0x8f42010c, 0x4021,
+0xa92821, 0xa9182b, 0x882021, 0x40f809,
+0x832021, 0x1040fe1f, 0x240a0001, 0xa34a05c4,
+0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c,
+0x8fab009c, 0x1505021, 0x16a102b, 0x10400004,
+0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064,
+0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420368,
+0x8f42035c, 0x2442ffff, 0xaf42035c, 0x8fab0054,
+0x8faa004c, 0x8f42035c, 0xad4b0000, 0x8f420044,
+0x8f440088, 0x8f430078, 0x24420001, 0x441024,
+0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c,
+0x1540fe1b, 0x0, 0x8fab006c, 0x1160001e,
+0x0, 0x934205c4, 0x10400009, 0x0,
+0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c,
+0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc,
+0x97ab008e, 0x1160000b, 0x34038100, 0x8fa20020,
+0x8c46000c, 0xa443000c, 0x97aa0086, 0x8c440004,
+0x8c450008, 0xa44a000e, 0xac440000, 0xac450004,
+0xac460008, 0x8f42034c, 0x24420001, 0xaf42034c,
+0x10000010, 0x8f42034c, 0x8fab007c, 0x3164ffff,
+0x2484fffc, 0x801821, 0x8f440250, 0x8f450254,
+0x8f460118, 0x1021, 0xa32821, 0xa3382b,
+0x822021, 0x872021, 0xaf440250, 0xc0f809,
+0xaf450254, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0,
+0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0,
+0x3e00008, 0x27bd00d0, 0x3e00008, 0x0,
+0x27bdff38, 0x240b0001, 0xafbf00c0, 0xafbe00bc,
+0xafb500b8, 0xafb300b4, 0xafb200b0, 0xafb100ac,
+0xafb000a8, 0xa3a00087, 0xafa00044, 0xafab005c,
+0x934205c4, 0xa7a00076, 0x10400007, 0xa7a0007e,
+0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4,
+0x10000130, 0xafab006c, 0x8f420114, 0x40f809,
+0x0, 0x403021, 0x10c002a1, 0x0,
+0x8cc20000, 0x8cc30004, 0xafa20020, 0xafa30024,
+0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc,
+0xafa20064, 0x3c020006, 0x2c21024, 0x14400015,
+0xafac006c, 0x93c20000, 0x30420001, 0x10400011,
+0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff,
+0x97c30004, 0x1062000b, 0x0, 0xc002497,
+0x3c02021, 0x304200ff, 0x14400006, 0x0,
+0x8f420118, 0x40f809, 0x0, 0x10000280,
+0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
+0x431024, 0x3c03ffff, 0x431824, 0x14600003,
+0xafa20024, 0x10000040, 0x8021, 0x3c020080,
+0x621024, 0x10400007, 0x0, 0x8f42038c,
+0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
+0x24100001, 0x8f420210, 0x24420001, 0xaf420210,
+0x8f420210, 0x3c020001, 0x621024, 0x10400006,
+0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
+0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
+0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
+0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
+0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
+0x8f420380, 0x3c020008, 0x621024, 0x10400006,
+0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
+0x8f420384, 0x3c020010, 0x621024, 0x10400006,
+0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
+0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
+0x24100001, 0x8f420388, 0x24420001, 0xaf420388,
+0x8f420388, 0x24100001, 0x8c020260, 0x8fab0064,
+0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8,
+0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c,
+0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010,
+0x8f8200e4, 0x24100001, 0x3c040001, 0x24846930,
+0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
+0xc002b17, 0x34a53600, 0x320200ff, 0x10400010,
+0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400,
+0x8fab006c, 0x3c020080, 0x34420100, 0x1621024,
+0x10400005, 0x0, 0x8f42020c, 0x24420001,
+0xaf42020c, 0x8f42020c, 0x10000202, 0x8fa30064,
+0x32c20400, 0x10400012, 0x34028100, 0x97c3000c,
+0x1462000f, 0x0, 0x240c0200, 0xa7ac0076,
+0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064,
+0x8fc50000, 0x256bfffc, 0xafab0064, 0xa7a2007e,
+0xafc3000c, 0xafc40008, 0xafc50004, 0x27de0004,
+0x8fa70064, 0x320200ff, 0x14400034, 0x3c020100,
+0x97c4000c, 0x2c8305dd, 0x38828870, 0x2c420001,
+0x621825, 0x10600015, 0x2821, 0x32c20800,
+0x10400015, 0x24020800, 0x97c30014, 0x14620012,
+0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021,
+0x97c30010, 0x24020300, 0x14620004, 0x801021,
+0x97c20012, 0x2c440001, 0x801021, 0x54400006,
+0x24050016, 0x10000004, 0x0, 0x24020800,
+0x50820001, 0x2405000e, 0x10a00013, 0x3c52021,
+0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b,
+0x10400003, 0x0, 0x8f420148, 0x621823,
+0x90620000, 0x38430006, 0x2c630001, 0x38420011,
+0x2c420001, 0x621825, 0x10600004, 0x3c020100,
+0x94820002, 0x453821, 0x3c020100, 0x2c21024,
+0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008,
+0x3c050007, 0x3c040001, 0x24846998, 0x8fa60064,
+0x34a54000, 0xafa00010, 0xc002b17, 0xafa00014,
+0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080,
+0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000,
+0x10400034, 0x240b0003, 0x32c21000, 0x10400031,
+0xafab005c, 0x1000002e, 0x240c0004, 0x8f420350,
+0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350,
+0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025,
+0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001,
+0x24846960, 0x26620001, 0xafa20014, 0xafa30010,
+0x8f860120, 0x8f870124, 0x3c050007, 0xc002b17,
+0x34a55300, 0x10000162, 0x0, 0x8ea20000,
+0x8ea30004, 0x3c040001, 0x24846978, 0xafb00010,
+0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b17,
+0x603021, 0x10000156, 0x0, 0x8f420084,
+0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001,
+0x2c21024, 0x10400004, 0x0, 0x240c0002,
+0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020,
+0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021,
+0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b,
+0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c,
+0x26220001, 0x304201ff, 0xafa20054, 0x111140,
+0x431021, 0x1000006b, 0x2e2a821, 0x8f420044,
+0x8fac0064, 0x3c040001, 0x2484693c, 0xafac0014,
+0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007,
+0xc002b17, 0x34a54300, 0x8f430350, 0x2402ffbf,
+0x282a024, 0x24630001, 0xaf430350, 0x10000124,
+0x8f420350, 0x156c001d, 0x0, 0x8f430074,
+0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074,
+0xafab004c, 0x26220001, 0x304203ff, 0xafa20054,
+0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821,
+0x8f420044, 0x8fac0064, 0x3c040001, 0x24846948,
+0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074,
+0x8f470070, 0x34a54500, 0x240b0001, 0xc002b17,
+0xafab005c, 0x1000ffc3, 0x0, 0x8f430064,
+0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064,
+0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff,
+0xafa20054, 0x24020004, 0x1562000e, 0x111140,
+0x111180, 0x24420cc0, 0x2e21021, 0xafa20044,
+0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b,
+0x10400024, 0x25950020, 0x240c0001, 0x10000021,
+0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821,
+0x8f420044, 0x8fab0064, 0x3c040001, 0x24846954,
+0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060,
+0x3c050007, 0xc002b17, 0x34a54800, 0x3c020008,
+0x2c21024, 0x1440ff61, 0x0, 0x8f420370,
+0x240c0001, 0xafac005c, 0x24420001, 0xaf420370,
+0x1000ff90, 0x8f420370, 0x27a30036, 0x131040,
+0x621821, 0x94620000, 0x441021, 0x1000001f,
+0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084,
+0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c,
+0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
+0x25620010, 0xafab002c, 0xafa20034, 0x9562002a,
+0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a,
+0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018,
+0x24630002, 0x822023, 0x1880ffdf, 0x26730001,
+0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
+0x262102a, 0x14400030, 0x24030001, 0x8f83012c,
+0x10600028, 0x0, 0x8f820124, 0x431023,
+0x22143, 0x58800001, 0x24840040, 0x8f820128,
+0x431023, 0x21943, 0x58600001, 0x24630040,
+0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
+0x8f4200fc, 0x262102a, 0x10400016, 0x24030001,
+0x1000001a, 0x306200ff, 0x8fac008c, 0x101040,
+0x4c1021, 0x94470018, 0x101080, 0x4c1021,
+0xafbe0010, 0x8c420008, 0x3c040001, 0x2484696c,
+0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500,
+0x2003021, 0xc002b17, 0xafa30014, 0x10000039,
+0x0, 0x8f420334, 0x1821, 0x24420001,
+0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06,
+0x8021, 0x8f430008, 0x2402fbff, 0x1260002d,
+0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c,
+0x2669ffff, 0x2209021, 0x8e420008, 0x96270018,
+0x8c440000, 0x8c450004, 0x56090004, 0x240b0001,
+0x240c0002, 0x10000002, 0xafac0010, 0xafab0010,
+0x16000004, 0xafa80014, 0x8f420008, 0x10000002,
+0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021,
+0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0,
+0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2,
+0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021,
+0x5e102b, 0x10400003, 0x26310002, 0x8f420148,
+0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda,
+0x26520004, 0x8fb00064, 0x1000001a, 0x0,
+0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001,
+0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c,
+0x240c0002, 0xafac0010, 0x934305c4, 0xb1700,
+0x10600003, 0x2223025, 0x3c020800, 0xc23025,
+0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c,
+0x3c03021, 0x40f809, 0x2003821, 0x1040fecb,
+0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e,
+0x934205c4, 0x14400004, 0x0, 0x97ab007e,
+0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff,
+0x1821024, 0x10400003, 0xc1402, 0x34630400,
+0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006,
+0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e,
+0x1000000d, 0xa34005c4, 0x8fac0064, 0x3c02001f,
+0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064,
+0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05c4,
+0x8f420148, 0x3c2f023, 0x8fab0054, 0x8fac004c,
+0xad8b0000, 0x8fac0064, 0x1580feba, 0x0,
+0x8fab0064, 0x1160001b, 0x0, 0x934205c4,
+0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0,
+0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076,
+0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c,
+0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008,
+0xa44c000e, 0xac440000, 0xac450004, 0xac460008,
+0x8f42034c, 0x24420001, 0xaf42034c, 0x10000010,
+0x8f42034c, 0x8fab006c, 0x3164ffff, 0x2484fffc,
+0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
+0x1021, 0xa32821, 0xa3382b, 0x822021,
+0x872021, 0xaf440250, 0xc0f809, 0xaf450254,
+0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4,
+0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008,
+0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8,
+0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048,
+0x10620034, 0x0, 0x8f430048, 0x8f42004c,
+0x622023, 0x4820001, 0x24840200, 0x8f430054,
+0x8f42004c, 0x43102b, 0x14400004, 0x24020200,
+0x8f43004c, 0x10000005, 0x431023, 0x8f420054,
+0x8f43004c, 0x431023, 0x2442ffff, 0x405021,
+0x8a102a, 0x54400001, 0x805021, 0x8f49004c,
+0x8f48004c, 0x8f440188, 0x8f45018c, 0x8f46004c,
+0x24071000, 0xafa70010, 0x84140, 0x1001821,
+0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014,
+0x1021, 0x63140, 0xafa70018, 0xa32821,
+0xa3382b, 0x822021, 0x872021, 0x3402ecc0,
+0xc23021, 0x8f420108, 0x2e63021, 0x40f809,
+0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c,
+0x8f420048, 0x14620018, 0x0, 0x8f420000,
0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
0x1040fffd, 0x0, 0x10000005, 0x0,
0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x2403f7ff, 0x431024, 0xaf820060,
+0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
0x8f420000, 0x10400003, 0x0, 0x10000002,
0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
-0x8f4200fc, 0x3c030001, 0x8f4400f8, 0x346330c8,
-0x24420001, 0xaf4200fc, 0x8f850128, 0x2e31021,
-0x54820004, 0x24820008, 0x3c020001, 0x34422ec8,
-0x2e21021, 0x401821, 0xaf4300f8, 0xac600000,
-0x8f4200f4, 0x14620004, 0x3c020001, 0x24a20020,
-0x1000000f, 0xaf820128, 0x8f4300f8, 0x344230c8,
-0x2e21021, 0x54620004, 0x24620008, 0x3c020001,
-0x34422ec8, 0x2e21021, 0x401821, 0x8c620004,
-0x21140, 0xa21021, 0xaf820128, 0xac600000,
-0x8ca30018, 0x30620070, 0x1040002d, 0x30620020,
+0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c,
+0x8f420058, 0x10620049, 0x0, 0x8f430058,
+0x8f42005c, 0x622023, 0x4820001, 0x24840100,
+0x8f430064, 0x8f42005c, 0x43102b, 0x14400004,
+0x24020100, 0x8f43005c, 0x10000005, 0x431023,
+0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff,
+0x403821, 0x87102a, 0x54400001, 0x803821,
+0x8f42005c, 0x471021, 0x305000ff, 0x32c21000,
+0x10400015, 0x24082000, 0x8f49005c, 0x8f440190,
+0x8f450194, 0x8f46005c, 0x73980, 0xafa80010,
+0xafb00014, 0x8f480014, 0x94980, 0x1201821,
+0x1021, 0xa32821, 0xa3482b, 0x822021,
+0x892021, 0x63180, 0xafa80018, 0x8f420108,
+0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440190,
+0x8f450194, 0x8f46005c, 0x73940, 0xafa80010,
+0xafb00014, 0x8f480014, 0x94940, 0x1201821,
+0x1021, 0xa32821, 0xa3482b, 0x822021,
+0x892021, 0x63140, 0xafa80018, 0x8f420108,
+0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001,
+0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018,
+0x0, 0x8f420000, 0x10400007, 0x0,
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+0x10000005, 0x0, 0xaf800048, 0x8f820048,
+0x1040fffd, 0x0, 0x8f820060, 0x2403feff,
+0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033,
+0x0, 0x8f430068, 0x8f42006c, 0x622023,
+0x4820001, 0x24840400, 0x8f430074, 0x8f42006c,
+0x43102b, 0x14400004, 0x24020400, 0x8f43006c,
+0x10000005, 0x431023, 0x8f420074, 0x8f43006c,
+0x431023, 0x2442ffff, 0x405021, 0x8a102a,
+0x54400001, 0x805021, 0x8f49006c, 0x8f48006c,
+0x8f440198, 0x8f45019c, 0x8f46006c, 0x24074000,
+0xafa70010, 0x84140, 0x1001821, 0x12a4821,
+0x313003ff, 0xafb00014, 0x8f470014, 0x1021,
+0x63140, 0x24c66cc0, 0xafa70018, 0xa32821,
+0xa3382b, 0x822021, 0x872021, 0x8f420108,
+0x2e63021, 0x40f809, 0xa3940, 0x54400001,
+0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018,
+0x0, 0x8f420000, 0x10400007, 0x0,
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+0x10000005, 0x0, 0xaf800048, 0x8f820048,
+0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff,
+0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x8f4200fc, 0x3c030001,
+0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc,
+0x8f850128, 0x2e31021, 0x54820004, 0x24820008,
+0x3c020001, 0x34422ec8, 0x2e21021, 0x401821,
+0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004,
+0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128,
+0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
+0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
+0x401821, 0x8c620004, 0x21140, 0xa21021,
+0xaf820128, 0xac600000, 0x8ca30018, 0x30620070,
+0x1040002d, 0x30620020, 0x10400004, 0x3c020010,
+0x2c21024, 0x1040000d, 0x0, 0x30620040,
+0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
+0x0, 0x30620010, 0x1040001f, 0x3c020040,
+0x2c21024, 0x1440001c, 0x0, 0x8f820040,
+0x30420001, 0x14400008, 0x2021, 0x8c030104,
+0x24020001, 0x50620005, 0x24040001, 0x8c020264,
+0x10400003, 0x801021, 0x24040001, 0x801021,
+0x10400006, 0x0, 0x8f42030c, 0x24420001,
+0xaf42030c, 0x10000008, 0x8f42030c, 0x8f820044,
+0x34420004, 0xaf820044, 0x8f420308, 0x24420001,
+0xaf420308, 0x8f420308, 0x3e00008, 0x0,
+0x3e00008, 0x0, 0x27bdff98, 0xafbf0060,
+0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050,
+0xafb1004c, 0xafb00048, 0x8f4200fc, 0x24420001,
+0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128,
+0x8d030018, 0x30620070, 0x1040002e, 0x30620020,
0x10400004, 0x3c020010, 0x2c21024, 0x1040000d,
0x0, 0x30620040, 0x10400004, 0x3c020020,
0x2c21024, 0x10400007, 0x0, 0x30620010,
-0x1040001f, 0x3c020040, 0x2c21024, 0x1440001c,
+0x104001a9, 0x3c020040, 0x2c21024, 0x144001a6,
0x0, 0x8f820040, 0x30420001, 0x14400008,
0x2021, 0x8c030104, 0x24020001, 0x50620005,
0x24040001, 0x8c020264, 0x10400003, 0x801021,
0x24040001, 0x801021, 0x10400006, 0x0,
-0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008,
-0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044,
-0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8,
-0x3e00008, 0x0, 0x3e00008, 0x0,
-0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb50058,
-0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048,
-0x8f4200fc, 0x24420001, 0xaf4200fc, 0x8f880128,
-0x25020020, 0xaf820128, 0x8d030018, 0x30620070,
-0x1040002e, 0x30620020, 0x10400004, 0x3c020010,
-0x2c21024, 0x1040000d, 0x0, 0x30620040,
-0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
-0x0, 0x30620010, 0x104001a6, 0x3c020040,
-0x2c21024, 0x144001a3, 0x0, 0x8f820040,
-0x30420001, 0x14400008, 0x2021, 0x8c030104,
-0x24020001, 0x50620005, 0x24040001, 0x8c020264,
-0x10400003, 0x801021, 0x24040001, 0x801021,
-0x10400006, 0x0, 0x8f4202fc, 0x24420001,
-0xaf4202fc, 0x1000018f, 0x8f4202fc, 0x8f820044,
-0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001,
-0xaf4202f8, 0x10000187, 0x8f4202f8, 0x30620002,
-0x10400148, 0x3c020800, 0x8d0a001c, 0x1422024,
-0xafaa0024, 0xa5702, 0xafaa0034, 0x8faa0024,
-0x314affff, 0xafaa0024, 0x950a0016, 0xafaa002c,
-0x8faa0034, 0x24020001, 0x15420007, 0x24020002,
-0x8faa0024, 0xa1140, 0x3403ecc0, 0x431021,
-0x10000014, 0x2e2a821, 0x15420006, 0x24020003,
-0x8faa0024, 0xa1140, 0x24426cc0, 0x1000000d,
-0x2e2a821, 0x8faa0034, 0x15420006, 0x0,
-0x8faa0024, 0xa1140, 0x24424cc0, 0x10000005,
-0x2e2a821, 0x8faa0024, 0xa1180, 0x571021,
-0x24550ce0, 0x96a2000e, 0x305efffc, 0x30420400,
-0x144000d8, 0x8821, 0x10800004, 0x24091000,
-0x97b1002e, 0x100000d4, 0x0, 0x8eb30018,
-0x966a000c, 0xa7aa003e, 0x97a3003e, 0x2c6205dd,
-0x10400015, 0x2021, 0x32c20800, 0x10400015,
-0x24020800, 0x96630014, 0x14620012, 0x3402aaaa,
-0x9663000e, 0x14620007, 0x2821, 0x96630010,
-0x24020300, 0x14620004, 0xa01021, 0x96620012,
-0x2c450001, 0xa01021, 0x54400006, 0x24040016,
-0x10000004, 0x0, 0x24020800, 0x50620001,
-0x2404000e, 0x108000b3, 0x2649021, 0x92420000,
-0x3042000f, 0x28080, 0x32c20100, 0x1040001e,
-0x2501821, 0x3c020020, 0x43102b, 0x1440000e,
-0x2402021, 0x2821, 0x94820000, 0x24840002,
-0xa22821, 0x83102b, 0x1440fffb, 0x30a2ffff,
-0x51c02, 0x622821, 0x51c02, 0x30a2ffff,
-0x10000009, 0x622821, 0x8f47013c, 0x8f420110,
-0x102842, 0x3c060020, 0x40f809, 0xafa80040,
-0x3045ffff, 0x8fa80040, 0x50a00001, 0x3405ffff,
-0x10000002, 0x37de0002, 0x2821, 0x32c20080,
-0x1040008c, 0xa6a50010, 0x26430009, 0x3c02001f,
+0x8f42030c, 0x24420001, 0xaf42030c, 0x10000192,
+0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
+0x8f420308, 0x24420001, 0xaf420308, 0x1000018a,
+0x8f420308, 0x30620002, 0x1040014b, 0x3c020800,
+0x8d1e001c, 0x1e5702, 0xafaa0034, 0x950a0016,
+0x3c22024, 0xafaa0024, 0x8faa0034, 0x24020001,
+0x15420006, 0x33deffff, 0x1e1140, 0x3403ecc0,
+0x431021, 0x10000010, 0x2e2a821, 0x24020002,
+0x15420005, 0x24020003, 0x1e1140, 0x24426cc0,
+0x10000009, 0x2e2a821, 0x15420005, 0x1e1180,
+0x1e1140, 0x24424cc0, 0x10000003, 0x2e2a821,
+0x571021, 0x24550ce0, 0x96a2000e, 0x304afffc,
+0x30420400, 0x10400003, 0xafaa002c, 0x100000e1,
+0x8821, 0x10800004, 0x8821, 0x97b10026,
+0x100000dd, 0xa6b10012, 0x8eb30018, 0x966a000c,
+0xa7aa003e, 0x97a5003e, 0x2ca305dd, 0x38a28870,
+0x2c420001, 0x621825, 0x10600015, 0x2021,
+0x32c20800, 0x10400015, 0x24020800, 0x96630014,
+0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007,
+0x2821, 0x96630010, 0x24020300, 0x14620004,
+0xa01021, 0x96620012, 0x2c450001, 0xa01021,
+0x54400006, 0x24040016, 0x10000004, 0x0,
+0x24020800, 0x50a20001, 0x2404000e, 0x108000b9,
+0x2649021, 0x92420000, 0x3042000f, 0x28080,
+0x32c20100, 0x10400020, 0x2501821, 0x3c020020,
+0x43102b, 0x1440000e, 0x2402021, 0x2821,
+0x94820000, 0x24840002, 0xa22821, 0x83102b,
+0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821,
+0x51c02, 0x30a2ffff, 0x10000009, 0x622821,
+0x8f470148, 0x8f420110, 0x102842, 0x3c060020,
+0x40f809, 0xafa80040, 0x3045ffff, 0x8fa80040,
+0x50a00001, 0x3405ffff, 0x8faa002c, 0x354a0002,
+0x10000002, 0xafaa002c, 0x2821, 0x32c20080,
+0x10400090, 0xa6a50010, 0x26430009, 0x3c02001f,
0x3442ffff, 0x43102b, 0x10400003, 0x0,
-0x8f42013c, 0x621823, 0x90660000, 0x30c200ff,
+0x8f420148, 0x621823, 0x90660000, 0x30c200ff,
0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x1060007b, 0x24020800, 0x8821,
+0x621825, 0x1060007f, 0x24020800, 0x8821,
0x97a3003e, 0x1462000f, 0x2602021, 0x96710000,
0x96620002, 0x96630004, 0x96640006, 0x2228821,
0x2238821, 0x2248821, 0x96620008, 0x9663000a,
@@ -7092,155 +7382,162 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
0x628821, 0x32c20200, 0x10400003, 0x26440006,
0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff,
-0xa4102b, 0x10400003, 0x0, 0x8f42013c,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
0x822023, 0x94820000, 0x30421fff, 0x10400004,
0x2644000c, 0x96420002, 0x10000030, 0x508023,
0x96420002, 0x26430014, 0x508023, 0x3c020020,
0x43102b, 0x1440000a, 0xd08021, 0x9642000c,
0x2028021, 0x9642000e, 0x96430010, 0x96440012,
0x2028021, 0x2038021, 0x10000020, 0x2048021,
-0xa4102b, 0x10400003, 0x0, 0x8f42013c,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f42013c,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f42013c,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f42013c,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
0x822023, 0x94820000, 0x2028021, 0x3c020100,
-0x2c21024, 0x1040000c, 0x33c20004, 0x1040000a,
-0x0, 0x9504000e, 0x2642021, 0xc003c24,
-0x2484fffc, 0x3042ffff, 0x2228821, 0x111c02,
-0x3222ffff, 0x628821, 0x8faa002c, 0x1518823,
-0x111402, 0x2228821, 0x2308821, 0x111402,
-0x2228821, 0x3231ffff, 0x52200001, 0x3411ffff,
-0x37de0001, 0x24091000, 0x33c20004, 0xa6b10012,
-0x10400002, 0xa6be000e, 0x34098000, 0x8f480044,
-0x8f440190, 0x8f450194, 0xafa90010, 0x8f490044,
-0x84140, 0x1001821, 0xafa90014, 0x8f48000c,
-0x2a03021, 0x24070020, 0xafa80018, 0x8f48010c,
-0x1021, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x1440000c, 0x0,
-0x8f820128, 0x8faa0024, 0x3c040001, 0x24843988,
-0xafaa0014, 0xafa20010, 0x8f860124, 0x8f870120,
-0x3c050007, 0xc0029bb, 0x34a59920, 0x8f420358,
-0x2442ffff, 0xaf420358, 0x8f420044, 0x8f430088,
-0x24420001, 0x431024, 0xaf420044, 0x8faa0034,
-0x8f440358, 0x24020001, 0x15420006, 0x24020002,
-0x8f42034c, 0x2442ffff, 0xaf42034c, 0x10000049,
-0x8f42034c, 0x15420006, 0x0, 0x8f420354,
-0x2442ffff, 0xaf420354, 0x10000042, 0x8f420354,
-0x8f420350, 0x2442ffff, 0xaf420350, 0x1000003d,
-0x8f420350, 0x30621000, 0x10400005, 0x30628000,
-0x8f420078, 0x24420001, 0x10000036, 0xaf420078,
-0x10400034, 0x0, 0x8f420078, 0x24420001,
-0xaf420078, 0x8c030240, 0x43102b, 0x1440002d,
-0x24070008, 0x8f440158, 0x8f45015c, 0x8f430044,
-0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010,
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f2, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x2484390c, 0xafa20014,
-0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb,
-0x34a51300, 0x1000000b, 0x0, 0x8f4202f4,
-0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044,
-0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2,
-0xaf400078, 0x8f420308, 0x24420001, 0xaf420308,
-0x8f420308, 0x8fbf0060, 0x8fbe005c, 0x8fb50058,
-0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048,
-0x3e00008, 0x27bd0068, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x8f420130,
-0xaf8200c0, 0x8f420130, 0xaf8200c4, 0x8f420130,
-0xaf8200c8, 0x8f42012c, 0xaf8200d0, 0x8f42012c,
-0xaf8200d4, 0x8f42012c, 0x3e00008, 0xaf8200d8,
+0x2c21024, 0x1040000e, 0x0, 0x8faa002c,
+0x31420004, 0x1040000a, 0x0, 0x9504000e,
+0x2642021, 0xc003ec4, 0x2484fffc, 0x3042ffff,
+0x2228821, 0x111c02, 0x3222ffff, 0x628821,
+0x8faa0024, 0x1518823, 0x111402, 0x2228821,
+0x2308821, 0x111402, 0x2228821, 0x3231ffff,
+0x52200001, 0x3411ffff, 0x8faa002c, 0x354a0001,
+0xafaa002c, 0xa6b10012, 0x97aa002e, 0xa6aa000e,
+0x8faa002c, 0x31420004, 0x10400002, 0x24091000,
+0x34098000, 0x8f480044, 0x8f4401a0, 0x8f4501a4,
+0xafa90010, 0x8f490044, 0x84140, 0x1001821,
+0xafa90014, 0x8f48000c, 0x2a03021, 0x24070020,
+0xafa80018, 0x8f48010c, 0x1021, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x0, 0x8f820128, 0x3c040001,
+0x248469a4, 0xafbe0014, 0xafa20010, 0x8f860124,
+0x8f870120, 0x3c050007, 0xc002b17, 0x34a59920,
+0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044,
+0x8f430088, 0x24420001, 0x431024, 0xaf420044,
+0x8faa0034, 0x8f440368, 0x24020001, 0x15420006,
+0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c,
+0x10000049, 0x8f42035c, 0x15420006, 0x0,
+0x8f420364, 0x2442ffff, 0xaf420364, 0x10000042,
+0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360,
+0x1000003d, 0x8f420360, 0x30621000, 0x10400005,
+0x30628000, 0x8f420078, 0x24420001, 0x10000036,
+0xaf420078, 0x10400034, 0x0, 0x8f420078,
+0x24420001, 0xaf420078, 0x8c030240, 0x43102b,
+0x1440002d, 0x24070008, 0x8f440168, 0x8f45016c,
+0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040,
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
+0x3c010001, 0x370821, 0xa02240f2, 0x8f820124,
+0xafa20010, 0x8f820128, 0x3c040001, 0x2484691c,
+0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009,
+0xc002b17, 0x34a51300, 0x1000000b, 0x0,
+0x8f420304, 0x24420001, 0xaf420304, 0x8f420304,
+0x8f420044, 0xaf42007c, 0x3c010001, 0x370821,
+0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001,
+0xaf420318, 0x8f420318, 0x8fbf0060, 0x8fbe005c,
+0x8fb50058, 0x8fb30054, 0x8fb20050, 0x8fb1004c,
+0x8fb00048, 0x3e00008, 0x27bd0068, 0x3e00008,
+0x0, 0x0, 0x0, 0x8f42013c,
+0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c,
+0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138,
+0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8,
0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018,
-0xc002a3f, 0x24060008, 0x8c020204, 0xc003d4a,
-0xaf820210, 0x2021, 0x8c060248, 0x24020004,
-0x3c010001, 0xac223d88, 0xc0047d4, 0x24050004,
-0x3c020001, 0x8c423d84, 0x30420001, 0x10400007,
-0x24020001, 0x3c010001, 0xac223d88, 0x2021,
-0x24050001, 0xc0047d4, 0x3c06601b, 0x3c040001,
-0x24843a50, 0x8f420144, 0x8f430148, 0x3c050008,
-0x8f46014c, 0x21640, 0x31940, 0x34630403,
-0x431025, 0x633c0, 0x461025, 0xaf82021c,
-0xafa00010, 0xafa00014, 0x8f86021c, 0x34a50200,
-0xc0029bb, 0x3821, 0x3c010001, 0xac203d80,
-0x3c010001, 0xac203d98, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x27bdffe0, 0x3c050008, 0x34a50300,
-0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200,
-0x3c040001, 0x24843a5c, 0xc0029bb, 0x3821,
-0x8f420400, 0x24420001, 0xaf420400, 0x8f420400,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffd8,
-0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f420394,
-0x24420001, 0xaf420394, 0x8f420394, 0x8f900220,
-0x8f8200e0, 0xafa20010, 0x8f8200e4, 0xafa20014,
-0x8f8600c4, 0x8f8700c8, 0x3c040001, 0x24843a68,
-0xc0029bb, 0x2002821, 0x3c044000, 0x2041024,
-0x504000ae, 0x3c040100, 0x8f4203ac, 0x24420001,
-0xaf4203ac, 0x8f4203ac, 0x8f8700c4, 0x8f8300c8,
-0x8f42013c, 0x671823, 0x43102b, 0x10400003,
-0x0, 0x8f42013c, 0x621821, 0x10600005,
-0x0, 0x8f420140, 0x43102b, 0x10400007,
-0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb,
-0x431024, 0x100000cc, 0x441025, 0x8f820220,
-0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004,
-0xaf820220, 0x8f8600c8, 0x8f840120, 0x8f830124,
-0x10000005, 0x2821, 0x14620002, 0x24620020,
-0x27624800, 0x401821, 0x1064000c, 0x30a200ff,
-0x8c620018, 0x30420003, 0x1040fff7, 0x27624fe0,
-0x8f4203c0, 0x24050001, 0x24420001, 0xaf4203c0,
-0x8f4203c0, 0x8c660008, 0x30a200ff, 0x14400058,
-0x0, 0x934205b5, 0x14400055, 0x0,
-0x8f8700c4, 0x8f8800e0, 0x8f8400e4, 0x2402fff8,
-0x1024024, 0x1041023, 0x218c3, 0x4620001,
-0x24630200, 0x10600005, 0x24020001, 0x10620009,
-0x0, 0x1000001f, 0x0, 0x8f4203b0,
-0xe03021, 0x24420001, 0xaf4203b0, 0x10000040,
-0x8f4203b0, 0x8f4203b4, 0x24420001, 0xaf4203b4,
-0x8c860000, 0x8f42013c, 0x8f4303b4, 0xe61823,
-0x43102b, 0x10400004, 0x2c62233f, 0x8f42013c,
-0x621821, 0x2c62233f, 0x14400031, 0x0,
-0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc,
-0xe03021, 0x24820008, 0xaf8200e4, 0x10000028,
-0xaf8200e8, 0x8f4203b8, 0x24420001, 0xaf4203b8,
-0x8f4203b8, 0x8c850000, 0x8f42013c, 0xa71823,
-0x43102b, 0x10400003, 0x0, 0x8f42013c,
-0x621821, 0x8f420140, 0x43102b, 0x5440000a,
-0xa03021, 0x8f4201fc, 0x24420001, 0xaf4201fc,
-0x8f4201fc, 0x24820008, 0xaf8200e4, 0x8f8400e4,
-0x1488ffec, 0xaf8400e8, 0x1488000d, 0x27623000,
-0x14820002, 0x2482fff8, 0x27623ff8, 0x94430006,
-0x3c02001f, 0x3442ffff, 0xc33021, 0x46102b,
-0x10400003, 0x0, 0x8f42013c, 0xc23023,
-0xaf8600c8, 0x8f8300c4, 0x8f42013c, 0xc31823,
-0x43102b, 0x10400003, 0x0, 0x8f42013c,
-0x621821, 0x10600005, 0x0, 0x8f420140,
-0x43102b, 0x50400008, 0x3c02fdff, 0x8f820220,
-0x3c0308ff, 0x3463fffb, 0x431024, 0x3c034000,
-0x10000041, 0x431025, 0x3442ffff, 0x8f4303bc,
-0x282a024, 0x24020001, 0xa34205b1, 0x24630001,
-0xaf4303bc, 0x10000039, 0x8f4203bc, 0x2041024,
-0x1040000e, 0x3c110200, 0x8f420398, 0x24420001,
-0xaf420398, 0x8f420398, 0x8f820220, 0x3c0308ff,
-0x3463ffff, 0x431024, 0x441025, 0xc003b0b,
+0xc002b9b, 0x24060008, 0x8c020204, 0xc003fea,
+0xaf820210, 0x3c020001, 0x8c426e14, 0x30420002,
+0x1040000e, 0x2021, 0x8c060248, 0x24020002,
+0x3c010001, 0xac226e18, 0xc005134, 0x24050002,
+0x2021, 0x8c060248, 0x24020001, 0x3c010001,
+0xac226e18, 0x10000011, 0x24050001, 0x8c060248,
+0x24020004, 0x3c010001, 0xac226e18, 0xc005134,
+0x24050004, 0x3c020001, 0x8c426e14, 0x30420001,
+0x10400008, 0x24020001, 0x3c010001, 0xac226e18,
+0x2021, 0x24050001, 0x3c06601b, 0xc005134,
+0x0, 0x3c040001, 0x24846a60, 0x8f420150,
+0x8f430154, 0x3c050008, 0x8f460158, 0x21640,
+0x31940, 0x34630403, 0x431025, 0x633c0,
+0x461025, 0xaf82021c, 0xafa00010, 0xafa00014,
+0x8f86021c, 0x34a50200, 0xc002b17, 0x3821,
+0x3c010001, 0xac206e10, 0x3c010001, 0xac206e28,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
+0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010,
+0xafa00014, 0x8f860200, 0x3c040001, 0x24846a6c,
+0xc002b17, 0x3821, 0x8f420410, 0x24420001,
+0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c,
+0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4,
+0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010,
+0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8,
+0x3c040001, 0x24846a78, 0xc002b17, 0x2002821,
+0x3c044000, 0x2041024, 0x504000b4, 0x3c040100,
+0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc,
+0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823,
+0x43102b, 0x10400003, 0x0, 0x8f420148,
+0x621821, 0x10600005, 0x0, 0x8f42014c,
+0x43102b, 0x1040000b, 0x0, 0x8f8200e0,
+0x8f430124, 0xaf42011c, 0xaf430114, 0x8f820220,
+0x3c0308ff, 0x3463fffb, 0x431024, 0x100000ce,
+0x441025, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420004, 0xaf820220, 0x8f8200e0,
+0x8f430124, 0xaf42011c, 0xaf430114, 0x8f8600c8,
+0x8f840120, 0x8f830124, 0x10000005, 0x2821,
+0x14620002, 0x24620020, 0x27624800, 0x401821,
+0x1064000c, 0x30a200ff, 0x8c620018, 0x30420003,
+0x1040fff7, 0x27624fe0, 0x8f4203d0, 0x24050001,
+0x24420001, 0xaf4203d0, 0x8f4203d0, 0x8c660008,
+0x30a200ff, 0x14400058, 0x0, 0x934205c4,
+0x14400055, 0x0, 0x8f8700c4, 0x8f8800e0,
+0x8f8400e4, 0x2402fff8, 0x1024024, 0x1041023,
+0x218c3, 0x4620001, 0x24630200, 0x10600005,
+0x24020001, 0x10620009, 0x0, 0x1000001f,
+0x0, 0x8f4203c0, 0xe03021, 0x24420001,
+0xaf4203c0, 0x10000040, 0x8f4203c0, 0x8f4203c4,
+0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148,
+0x8f4303c4, 0xe61823, 0x43102b, 0x10400004,
+0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f,
+0x14400031, 0x0, 0x8f42020c, 0x24420001,
+0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008,
+0xaf8200e4, 0x10000028, 0xaf8200e8, 0x8f4203c8,
+0x24420001, 0xaf4203c8, 0x8f4203c8, 0x8c850000,
+0x8f420148, 0xa71823, 0x43102b, 0x10400003,
+0x0, 0x8f420148, 0x621821, 0x8f42014c,
+0x43102b, 0x5440000a, 0xa03021, 0x8f42020c,
+0x24420001, 0xaf42020c, 0x8f42020c, 0x24820008,
+0xaf8200e4, 0x8f8400e4, 0x1488ffec, 0xaf8400e8,
+0x1488000d, 0x27623000, 0x14820002, 0x2482fff8,
+0x27623ff8, 0x94430006, 0x3c02001f, 0x3442ffff,
+0xc33021, 0x46102b, 0x10400003, 0x0,
+0x8f420148, 0xc23023, 0xaf8600c8, 0x8f8300c4,
+0x8f420148, 0xc31823, 0x43102b, 0x10400003,
+0x0, 0x8f420148, 0x621821, 0x10600005,
+0x0, 0x8f42014c, 0x43102b, 0x50400008,
+0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb,
+0x431024, 0x3c034000, 0x1000003f, 0x431025,
+0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001,
+0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024,
+0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001,
+0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff,
+0x3463ffff, 0x431024, 0x441025, 0xc003d87,
0xaf820220, 0x10000029, 0x0, 0x2111024,
-0x50400008, 0x3c110400, 0x8f42039c, 0x24420001,
-0xaf42039c, 0xc003b0b, 0x8f42039c, 0x10000019,
+0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001,
+0xaf4203ac, 0xc003d87, 0x8f4203ac, 0x10000019,
0x0, 0x2111024, 0x1040001c, 0x0,
0x8f830224, 0x24021402, 0x14620009, 0x3c050008,
-0x3c040001, 0x24843a74, 0xafa00010, 0xafa00014,
-0x8f860224, 0x34a50500, 0xc0029bb, 0x3821,
-0x8f4203a0, 0x24420001, 0xaf4203a0, 0x8f4203a0,
-0x8f820220, 0x2002021, 0x34420002, 0xc00456c,
+0x3c040001, 0x24846a84, 0xafa00010, 0xafa00014,
+0x8f860224, 0x34a50500, 0xc002b17, 0x3821,
+0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0,
+0x8f820220, 0x2002021, 0x34420002, 0xc004ecc,
0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
0x431024, 0x511025, 0xaf820220, 0x8fbf0020,
0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x3c020001, 0x8c423d98,
+0x3e00008, 0x0, 0x3c020001, 0x8c426e28,
0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040,
0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f,
-0xafb00030, 0x3c040001, 0x24843a80, 0x3c050008,
+0xafb00030, 0x3c040001, 0x24846a90, 0x3c050008,
0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600,
-0x24020001, 0x3c010001, 0xac203d98, 0x3c010001,
-0xac223d8c, 0xc0029bb, 0x3821, 0x3c037fff,
+0x24020001, 0x3c010001, 0xac206e28, 0x3c010001,
+0xac226e1c, 0xc002b17, 0x3821, 0x3c037fff,
0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024,
0xac020268, 0x8f420004, 0x3484ffff, 0x30420002,
0x10400092, 0x284a024, 0x3c040600, 0x34842000,
@@ -7248,49 +7545,58 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020,
0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001,
0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0,
-0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c,
-0x8c020228, 0x3c040001, 0x24843a18, 0x3c050009,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x24846a28, 0x3c050009,
0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
-0x9821, 0xe08821, 0x263504c0, 0x8f440168,
-0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010,
+0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
0xa3482b, 0x822021, 0x100f809, 0x892021,
0x54400006, 0x24130001, 0x8f820054, 0x2021023,
0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
-0x54400017, 0xaf520018, 0x8f420368, 0x24420001,
-0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24843a24,
+0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846a34,
0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
-0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001,
-0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff,
+0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff,
0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
-0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154,
+0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420368,
-0x24420001, 0xaf420368, 0x8f420368, 0x8f820120,
+0x326200ff, 0x14400011, 0x0, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24843a2c, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202dc,
-0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8fbf0048,
+0x24846a3c, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002b17, 0x3c03821, 0x8f4202ec,
+0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048,
0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
-0x3c020001, 0x8c423d98, 0x27bdffe0, 0x1440000d,
-0xafbf0018, 0x3c040001, 0x24843a8c, 0x3c050008,
+0x3c020001, 0x8c426e28, 0x27bdffe0, 0x1440000d,
+0xafbf0018, 0x3c040001, 0x24846a9c, 0x3c050008,
0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700,
-0x24020001, 0x3c010001, 0xac223d98, 0xc0029bb,
-0x3821, 0x3c020004, 0x2c21024, 0x10400008,
-0x2021, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420008, 0xaf820220, 0x2021,
-0xc0048dd, 0x24050004, 0xac020268, 0x8fbf0018,
-0x3e00008, 0x27bd0020, 0x0, 0x86102b,
+0x24020001, 0x3c010001, 0xac226e28, 0xc002b17,
+0x3821, 0x3c020004, 0x2c21024, 0x10400007,
+0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420008, 0xaf820220, 0x3c050001,
+0x8ca56e18, 0x24020001, 0x14a20007, 0x2021,
+0xc0052c7, 0x24050001, 0xac02026c, 0x8c03026c,
+0x10000006, 0x3c020007, 0xc0052c7, 0x2021,
+0xac020268, 0x8c030268, 0x3c020007, 0x621824,
+0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b,
+0x14400006, 0x3c020004, 0x3c020001, 0x10620009,
+0x3c020098, 0x1000000b, 0x0, 0x14620009,
+0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002,
+0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc,
+0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x0, 0x0, 0x0, 0x86102b,
0x50400001, 0x872023, 0xc41023, 0x24843,
0x125102b, 0x1040001b, 0x91040, 0x824021,
0x88102b, 0x10400007, 0x1821, 0x94820000,
@@ -7309,28 +7615,28 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x24a20004, 0x62102b, 0x54400007, 0x65102b,
0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002,
0x1000002a, 0x441021, 0x10400003, 0x0,
-0x8f42013c, 0xa22823, 0x90a40000, 0x24a50001,
-0x65102b, 0x10400003, 0x0, 0x8f42013c,
+0x8f420148, 0xa22823, 0x90a40000, 0x24a50001,
+0x65102b, 0x10400003, 0x0, 0x8f420148,
0xa22823, 0x90a20000, 0x24a50001, 0x21200,
0x822021, 0x65102b, 0x10400003, 0x0,
-0x8f42013c, 0xa22823, 0x90a20000, 0x24a50001,
+0x8f420148, 0xa22823, 0x90a20000, 0x24a50001,
0x822021, 0x65102b, 0x10400003, 0x0,
-0x8f42013c, 0xa22823, 0x90a20000, 0x1000002d,
+0x8f420148, 0xa22823, 0x90a20000, 0x1000002d,
0x21200, 0x3463ffff, 0x24a20004, 0x62102b,
0x5440000a, 0x65102b, 0x90a20000, 0x90a40002,
0x90a30001, 0x90a50003, 0x441021, 0x21200,
0x651821, 0x10000020, 0x432021, 0x10400003,
-0x0, 0x8f42013c, 0xa22823, 0x90a20000,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
0x24a50001, 0x22200, 0x65102b, 0x10400003,
-0x0, 0x8f42013c, 0xa22823, 0x90a20000,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
0x24a50001, 0x822021, 0x65102b, 0x10400003,
-0x0, 0x8f42013c, 0xa22823, 0x90a20000,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
0x24a50001, 0x21200, 0x822021, 0x65102b,
-0x10400003, 0x0, 0x8f42013c, 0xa22823,
+0x10400003, 0x0, 0x8f420148, 0xa22823,
0x90a20000, 0x822021, 0x41c02, 0x3082ffff,
0x622021, 0x41c02, 0x3082ffff, 0x622021,
0x3e00008, 0x3082ffff, 0x0, 0x8f820220,
-0x34420002, 0xaf820220, 0x3c020001, 0x8c425f98,
+0x34420002, 0xaf820220, 0x3c020002, 0x8c429078,
0x30424000, 0x10400054, 0x24040001, 0x8f820200,
0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd,
0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
@@ -7377,502 +7683,880 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x43102b, 0x14400006, 0x3c026000, 0x3c024000,
0x10620008, 0x24020800, 0x10000008, 0x0,
0x10620004, 0x24020800, 0x10000004, 0x0,
-0x24020700, 0x3c010001, 0xac223d9c, 0x3e00008,
-0x0, 0x27bdffc8, 0xafbf0034, 0xafb20030,
-0xafb1002c, 0xafb00028, 0x3c010001, 0xc004549,
-0xac203d84, 0x24040001, 0x2821, 0x27a60020,
-0x34028000, 0xc004166, 0xa7a20020, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
-0x24050001, 0xc004124, 0x27a60020, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
-0x24050001, 0xc004124, 0x27a60020, 0x8f830054,
+0x24020700, 0x3c010001, 0xac226e2c, 0x3e00008,
+0x0, 0x3c020001, 0x8c426e3c, 0x27bdffc8,
+0xafbf0034, 0xafb20030, 0xafb1002c, 0xafb00028,
+0x3c010001, 0x10400005, 0xac206e14, 0xc004dd1,
+0x0, 0x3c010001, 0xac206e3c, 0x8f830054,
0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
-0x24050002, 0xc004124, 0x27a60018, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001,
-0x24050003, 0xc004124, 0x27a6001a, 0x97a20020,
-0x1040002a, 0x24020001, 0x3c020001, 0x8c423d84,
-0x97a30018, 0x34420001, 0x3c010001, 0xac223d84,
-0x24020015, 0x1462000a, 0x0, 0x97a2001a,
-0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430,
-0x2c420001, 0x621825, 0x14600018, 0x24020003,
-0x97a30018, 0x24027810, 0x14620014, 0x24020002,
-0x97a2001a, 0x3042fff0, 0x14400010, 0x24020002,
-0x1000000e, 0x24020004, 0x3c020001, 0x8c423d84,
-0x34420008, 0x3c010001, 0xac223d84, 0x10000058,
-0x24020004, 0x3c020001, 0x8c423d84, 0x34420004,
-0x3c010001, 0x100000a9, 0xac223d84, 0x3c010001,
-0xac223ee0, 0x24020e00, 0xaf820238, 0x8f840054,
-0x8f820054, 0x24030008, 0x3c010001, 0xac233d88,
-0x10000002, 0x248401f4, 0x8f820054, 0x821023,
-0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0xc004dec, 0x0, 0x24040001, 0x2821,
+0x27a60020, 0x34028000, 0xc00450e, 0xa7a20020,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc0044cc, 0x27a60020,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc0044cc, 0x27a60020,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050002, 0xc0044cc, 0x27a60018,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050003, 0xc0044cc, 0x27a6001a,
+0x3c040001, 0x24846b70, 0x97a60020, 0x97a70018,
+0x97a2001a, 0x3c05000d, 0x34a50100, 0xafa00014,
+0xc002b17, 0xafa20010, 0x97a20020, 0x10400046,
+0x24036040, 0x97a2001a, 0x3042fff0, 0x1443000b,
+0x24020020, 0x97a30018, 0x1462000a, 0x24027830,
+0x24020003, 0x3c010001, 0xac226e14, 0x24020005,
+0x3c010001, 0x10000039, 0xac226fac, 0x97a30018,
+0x24027830, 0x1462000b, 0x24030010, 0x97a2001a,
+0x3042fff0, 0x14430007, 0x24020003, 0x3c010001,
+0xac226e14, 0x24020006, 0x3c010001, 0x1000002b,
+0xac226fac, 0x3c020001, 0x8c426e14, 0x97a30018,
+0x34420001, 0x3c010001, 0xac226e14, 0x24020015,
+0x1462000a, 0x0, 0x97a2001a, 0x3042fff0,
+0x3843f420, 0x2c630001, 0x3842f430, 0x2c420001,
+0x621825, 0x14600019, 0x24020003, 0x97a30018,
+0x24027810, 0x14620015, 0x24020002, 0x97a2001a,
+0x3042fff0, 0x14400011, 0x24020002, 0x1000000f,
+0x24020004, 0x3c020001, 0x8c426e14, 0x34420008,
+0x3c010001, 0xac226e14, 0x1000005e, 0x24020004,
+0x3c020001, 0x8c426e14, 0x34420004, 0x3c010001,
+0x100000af, 0xac226e14, 0x24020001, 0x3c010001,
+0xac226fb8, 0x3c020001, 0x8c426e14, 0x30420002,
+0x144000b2, 0x3c09fff0, 0x24020e00, 0xaf820238,
+0x8f840054, 0x8f820054, 0x24030008, 0x3c010001,
+0xac236e18, 0x10000002, 0x248401f4, 0x8f820054,
+0x821023, 0x2c4201f5, 0x1440fffc, 0x3c0200c8,
+0x344201fb, 0xaf820238, 0x8f830054, 0x8f820054,
+0x10000002, 0x246301f4, 0x8f820054, 0x621023,
+0x2c4201f5, 0x1440fffc, 0x8021, 0x24120001,
+0x24110009, 0xc0043d3, 0x0, 0x3c010001,
+0xac326e34, 0xc004498, 0x0, 0x3c020001,
+0x8c426e34, 0x1451fffb, 0x3c0200c8, 0x344201f6,
0xaf820238, 0x8f830054, 0x8f820054, 0x10000002,
-0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5,
-0x1440fffc, 0x8021, 0x24120001, 0x24110009,
-0xc004045, 0x0, 0x3c010001, 0xac323da0,
-0xc0040f2, 0x0, 0x3c020001, 0x8c423da0,
-0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238,
-0x8f830054, 0x8f820054, 0x10000002, 0x2463000a,
-0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc,
+0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
+0x1440fffc, 0x0, 0x8f820220, 0x24040001,
+0x34420002, 0xaf820220, 0x8f830200, 0x24057fff,
+0x2402fffd, 0x621824, 0xaf830200, 0xaf840204,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820224, 0x14440005, 0x34028000,
+0x42040, 0xa4102b, 0x1040fff0, 0x34028000,
+0x1082ffa0, 0x26100001, 0x2e020014, 0x1440ffcd,
+0x24020004, 0x3c010001, 0xac226e18, 0x8021,
+0x24120009, 0x3c11ffff, 0x36313f7f, 0xc0043d3,
+0x0, 0x24020001, 0x3c010001, 0xac226e34,
+0xc004498, 0x0, 0x3c020001, 0x8c426e34,
+0x1452fffb, 0x0, 0x8f820044, 0x511024,
+0x34425080, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x2463000a, 0x8f820054, 0x621023,
+0x2c42000b, 0x1440fffc, 0x0, 0x8f820044,
+0x511024, 0x3442f080, 0xaf820044, 0x8f830054,
+0x8f820054, 0x10000002, 0x2463000a, 0x8f820054,
+0x621023, 0x2c42000b, 0x1440fffc, 0x0,
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
0x0, 0x8f820220, 0x24040001, 0x34420002,
0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd,
0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
0x621023, 0x2c420002, 0x1440fffc, 0x0,
0x8f820224, 0x14440005, 0x34028000, 0x42040,
-0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa6,
-0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004,
-0x3c010001, 0xac223d88, 0x8021, 0x24120009,
-0x3c11ffff, 0x36313f7f, 0xc004045, 0x0,
-0x24020001, 0x3c010001, 0xac223da0, 0xc0040f2,
-0x0, 0x3c020001, 0x8c423da0, 0x1452fffb,
-0x0, 0x8f820044, 0x511024, 0x34425080,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
-0x1440fffc, 0x0, 0x8f820044, 0x511024,
-0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054,
-0x10000002, 0x2463000a, 0x8f820054, 0x621023,
-0x2c42000b, 0x1440fffc, 0x0, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0x8f820220, 0x24040001, 0x34420002, 0xaf820220,
-0x8f830200, 0x24057fff, 0x2402fffd, 0x621824,
-0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054,
-0x10000002, 0x24630001, 0x8f820054, 0x621023,
-0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
-0x14440005, 0x34028000, 0x42040, 0xa4102b,
-0x1040fff0, 0x34028000, 0x1082ff56, 0x26100001,
-0x2e020064, 0x1440ffb0, 0x0, 0x3c020001,
-0x8c423d84, 0x30420004, 0x14400007, 0x3c08fff0,
-0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
-0xaf820044, 0x3c08fff0, 0x3508bdc0, 0x8f830054,
-0x97a60018, 0x3c070001, 0x8ce73ee0, 0x3c040001,
-0x24843b60, 0x24020001, 0x3c010001, 0xac223d8c,
-0xafa60010, 0x3c060001, 0x8cc63d84, 0x97a2001a,
-0x3c05000d, 0x34a50100, 0x3c010001, 0xac203d88,
-0x681821, 0x3c010001, 0xac233ed8, 0xc0029bb,
-0xafa20014, 0x8fbf0034, 0x8fb20030, 0x8fb1002c,
-0x8fb00028, 0x3e00008, 0x27bd0038, 0x27bdffe8,
-0x24070004, 0x3c040001, 0x8c843d88, 0x3021,
-0x24020001, 0x1482000a, 0xafbf0010, 0x3c020001,
-0x8c425f9c, 0x3c050004, 0x30428000, 0x1040000c,
-0x34a593e0, 0x3c05000f, 0x10000009, 0x34a54240,
-0x3c020001, 0x8c425f9c, 0x3c05000f, 0x30428000,
-0x10400003, 0x34a54240, 0x3c05001e, 0x34a58480,
-0x3c020001, 0x8c423ed8, 0x8f830054, 0x451021,
-0x431023, 0x45102b, 0x1440002e, 0x0,
-0x3c020001, 0x8c423d90, 0x1440002a, 0x2cc20001,
-0x7182b, 0x431024, 0x1040001d, 0x0,
-0x3c090001, 0x8d293d84, 0x240b0001, 0x3c054000,
-0x3c080001, 0x25085f9c, 0x250afffc, 0x42042,
-0x14800002, 0x24e7ffff, 0x24040008, 0x891024,
-0x5040000b, 0x2cc20001, 0x148b0004, 0x0,
-0x8d020000, 0x10000003, 0x451024, 0x8d420000,
-0x451024, 0x54400001, 0x24060001, 0x2cc20001,
-0x7182b, 0x431024, 0x5440ffed, 0x42042,
-0x3c010001, 0x10c00020, 0xac243d88, 0x8f830054,
-0x24020001, 0x3c010001, 0xac223d8c, 0x3c010001,
-0xac233ed8, 0x3c020001, 0x8c423d8c, 0x10400004,
-0x24020001, 0x3c010001, 0xac203d8c, 0xaee204b8,
-0x8ee304b8, 0x24020008, 0x10620005, 0x24020001,
-0xc003eee, 0x0, 0x1000000b, 0x0,
-0x3c030001, 0x8c633d88, 0x10620007, 0x2402000e,
-0x3c030001, 0x8c635f30, 0x10620003, 0x0,
-0xc00456c, 0x8f840220, 0x8fbf0010, 0x3e00008,
-0x27bd0018, 0x27bdffe0, 0x3c03fdff, 0x3c040001,
-0x8c843d88, 0x3c020001, 0x8c423da8, 0x3463ffff,
-0x283a024, 0x14820006, 0xafbf0018, 0x8ee304b8,
-0x3c020001, 0x8c423dac, 0x10620006, 0x0,
-0x8ee204b8, 0x3c010001, 0xac243da8, 0x3c010001,
-0xac223dac, 0x3c030001, 0x8c633d88, 0x24020002,
-0x1062013c, 0x2c620003, 0x10400005, 0x24020001,
-0x1062000a, 0x0, 0x10000134, 0x0,
-0x24020004, 0x1062006d, 0x24020008, 0x1062009f,
-0x24020001, 0x1000012d, 0x0, 0x8ee204b8,
-0x2443ffff, 0x2c620008, 0x1040012a, 0x31080,
-0x3c010001, 0x220821, 0x8c223b78, 0x400008,
-0x0, 0xc004045, 0x0, 0x3c020001,
-0x8c423d94, 0x3c010001, 0xac203d20, 0x104000d7,
-0x24020002, 0xaee204b8, 0x3c010001, 0x10000119,
-0xac203d94, 0xc0041a7, 0x0, 0x3c030001,
-0x8c633db0, 0x1000009e, 0x24020011, 0x3c050001,
-0x8ca53d88, 0x3c060001, 0x8cc65f9c, 0xc0047d4,
-0x2021, 0x24020005, 0x3c010001, 0xac203d94,
-0x10000108, 0xaee204b8, 0x3c040001, 0x24843b6c,
-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
-0xafa00010, 0xc0029bb, 0xafa00014, 0x100000fd,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0x100000a4, 0xaf820220, 0x8f820220, 0x3c030004,
-0x431024, 0x144000ae, 0x24020007, 0x8f830054,
-0x3c020001, 0x8c423ed0, 0x2463d8f0, 0x431023,
-0x2c422710, 0x144000eb, 0x24020001, 0x100000e7,
-0x0, 0x3c050001, 0x8ca53d88, 0xc0048dd,
-0x2021, 0xc0049a8, 0x2021, 0x3c030001,
-0x8c635f94, 0x46100dd, 0x24020001, 0x3c020008,
-0x621024, 0x10400006, 0x0, 0x8f820214,
-0x3c03ffff, 0x431024, 0x10000005, 0x3442251f,
-0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
-0xaf820214, 0x8f820220, 0x3c030200, 0x283a025,
-0x34420002, 0xaf820220, 0x24020008, 0xc003bc9,
-0xaee204b8, 0x100000c7, 0x0, 0x8ee204b8,
-0x2443ffff, 0x2c620008, 0x104000c2, 0x31080,
-0x3c010001, 0x220821, 0x8c223b98, 0x400008,
-0x0, 0x3c020001, 0x8c425f98, 0x30424000,
+0xa4102b, 0x1040fff0, 0x34028000, 0x1082ff50,
+0x26100001, 0x2e020064, 0x1440ffb0, 0x0,
+0x3c020001, 0x8c426e14, 0x30420004, 0x14400007,
+0x3c09fff0, 0x8f820044, 0x3c03ffff, 0x34633f7f,
+0x431024, 0xaf820044, 0x3c09fff0, 0x3529bdc0,
+0x8f830054, 0x3c060001, 0x8cc66e14, 0x3c070001,
+0x8ce76fb8, 0x97a80018, 0x3c040001, 0x24846b70,
+0x24020001, 0x3c010001, 0xac226e1c, 0xafa80010,
+0x97a2001a, 0x3c05000d, 0x34a50100, 0x3c010001,
+0xac206e18, 0x691821, 0x3c010001, 0xac236fa8,
+0xc002b17, 0xafa20014, 0x8fbf0034, 0x8fb20030,
+0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038,
+0x27bdffe8, 0x3c050001, 0x8ca56e18, 0x24060004,
+0x24020001, 0x14a20014, 0xafbf0010, 0x3c020002,
+0x8c42907c, 0x30428000, 0x10400005, 0x3c04000f,
+0x3c030001, 0x8c636fb8, 0x10000005, 0x34844240,
+0x3c040004, 0x3c030001, 0x8c636fb8, 0x348493e0,
+0x24020005, 0x14620016, 0x0, 0x3c04003d,
+0x10000013, 0x34840900, 0x3c020002, 0x8c429078,
+0x30428000, 0x10400005, 0x3c04001e, 0x3c030001,
+0x8c636fb8, 0x10000005, 0x34848480, 0x3c04000f,
+0x3c030001, 0x8c636fb8, 0x34844240, 0x24020005,
+0x14620003, 0x0, 0x3c04007a, 0x34841200,
+0x3c020001, 0x8c426fa8, 0x8f830054, 0x441021,
+0x431023, 0x44102b, 0x1440004b, 0x0,
+0x3c020001, 0x8c426e20, 0x14400047, 0x0,
+0x3c010001, 0x10c00025, 0xac206e30, 0x3c090001,
+0x8d296e14, 0x24070001, 0x3c044000, 0x3c080002,
+0x2508907c, 0x250afffc, 0x52842, 0x14a00002,
+0x24c6ffff, 0x24050008, 0xa91024, 0x10400010,
+0x0, 0x14a70008, 0x0, 0x8d020000,
+0x441024, 0x1040000a, 0x0, 0x3c010001,
+0x10000007, 0xac256e30, 0x8d420000, 0x441024,
+0x10400003, 0x0, 0x3c010001, 0xac276e30,
+0x3c020001, 0x8c426e30, 0x6182b, 0x2c420001,
+0x431024, 0x5440ffe5, 0x52842, 0x8f820054,
+0x3c030001, 0x8c636e30, 0x3c010001, 0xac226fa8,
+0x1060003a, 0x24020005, 0x3c030001, 0x8c636fb8,
+0x3c010001, 0xac256e18, 0x14620011, 0x24020001,
+0x3c020002, 0x8c429078, 0x3c032000, 0x431024,
+0x14400006, 0x24020001, 0x3c010001, 0xac206f98,
+0x3c010001, 0xac226e18, 0x24020001, 0x3c010001,
+0xac226ea4, 0x3c010001, 0xac226e24, 0x24020001,
+0x3c010001, 0xac226e1c, 0x3c020001, 0x8c426e30,
+0x1040001e, 0x0, 0x3c020001, 0x8c426e1c,
+0x10400008, 0x24020001, 0x3c010001, 0xac206e1c,
+0xaee204b8, 0x3c010001, 0xac206e9c, 0x3c010001,
+0xac226e54, 0x8ee304b8, 0x24020008, 0x10620005,
+0x24020001, 0xc004203, 0x0, 0x1000000b,
+0x0, 0x3c030001, 0x8c636e18, 0x10620007,
+0x2402000e, 0x3c030002, 0x8c639010, 0x10620003,
+0x0, 0xc004ecc, 0x8f840220, 0x8fbf0010,
+0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c03fdff,
+0x3c040001, 0x8c846e18, 0x3c020001, 0x8c426e40,
+0x3463ffff, 0x283a024, 0xafbf001c, 0x14820006,
+0xafb00018, 0x8ee304b8, 0x3c020001, 0x8c426e44,
+0x10620006, 0x0, 0x8ee204b8, 0x3c010001,
+0xac246e40, 0x3c010001, 0xac226e44, 0x3c030001,
+0x8c636e18, 0x24020002, 0x10620167, 0x2c620003,
+0x10400005, 0x24020001, 0x1062000a, 0x0,
+0x100001ab, 0x0, 0x24020004, 0x10620081,
+0x24020008, 0x106200d5, 0x24020001, 0x100001a4,
+0x0, 0x8ee204b8, 0x2443ffff, 0x2c620008,
+0x104001a1, 0x31080, 0x3c010001, 0x220821,
+0x8c226b88, 0x400008, 0x0, 0x3c030001,
+0x8c636fb8, 0x24020005, 0x14620010, 0x0,
+0x3c020001, 0x8c426e24, 0x10400008, 0x24020003,
+0xc0043d3, 0x0, 0x24020002, 0xaee204b8,
+0x3c010001, 0x10000002, 0xac206e24, 0xaee204b8,
+0x3c010001, 0x10000188, 0xac206db0, 0xc0043d3,
+0x0, 0x3c020001, 0x8c426e24, 0x3c010001,
+0xac206db0, 0x14400145, 0x24020002, 0x10000163,
+0x24020007, 0x24020001, 0x3c010001, 0xc00454f,
+0xac226e50, 0x3c030001, 0x8c636e50, 0x10000144,
+0x24020011, 0x3c020001, 0x8c426fb8, 0x24100005,
+0x10500007, 0x0, 0x3c050001, 0x8ca56e18,
+0x3c060002, 0x8cc6907c, 0xc005134, 0x2021,
+0x3c010001, 0xac206e24, 0x10000167, 0xaef004b8,
+0x3c040001, 0x24846b7c, 0x3c05000f, 0x34a50100,
+0x3021, 0x3821, 0xafa00010, 0xc002b17,
+0xafa00014, 0x1000015c, 0x0, 0x8f820220,
+0x3c030004, 0x431024, 0x1440013c, 0x24020007,
+0x8f830054, 0x3c020001, 0x8c426fa0, 0x2463d8f0,
+0x431023, 0x2c422710, 0x1440014f, 0x24020001,
+0x1000014b, 0x0, 0x3c050001, 0x8ca56e18,
+0xc0052c7, 0x2021, 0xc00553d, 0x2021,
+0x3c030002, 0x8c639074, 0x4610141, 0x24020001,
+0x3c020008, 0x621024, 0x10400006, 0x0,
+0x8f820214, 0x3c03ffff, 0x431024, 0x10000005,
+0x3442251f, 0x8f820214, 0x3c03ffff, 0x431024,
+0x3442241f, 0xaf820214, 0x8f820220, 0x3c030200,
+0x283a025, 0x34420002, 0xaf820220, 0x24020008,
+0xc003e45, 0xaee204b8, 0x3c010001, 0x1000012a,
+0xac206ea0, 0x8ee204b8, 0x2443ffff, 0x2c620008,
+0x10400125, 0x31080, 0x3c010001, 0x220821,
+0x8c226ba8, 0x400008, 0x0, 0xc004498,
+0x0, 0x3c030001, 0x8c636e34, 0x100000e8,
+0x24020009, 0x3c020002, 0x8c429078, 0x30424000,
0x10400004, 0x0, 0x8f820044, 0x10000006,
0x3442f080, 0x8f820044, 0x3c03ffff, 0x34633f7f,
0x431024, 0x3442a080, 0xaf820044, 0x8f830054,
-0x1000005a, 0x24020004, 0xc003c88, 0x0,
-0x104000a6, 0x24020001, 0x8f820214, 0x3c03ffff,
-0x3c040001, 0x8c843ec8, 0x431024, 0x3442251f,
+0x100000ea, 0x24020004, 0x8f830054, 0x3c020001,
+0x8c426fa0, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400101, 0x24020005, 0x100000d8, 0x0,
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+0xaf800204, 0x3c010002, 0x100000d6, 0xac209060,
+0x8f830054, 0x3c020001, 0x8c426fa0, 0x2463fff6,
+0x431023, 0x2c42000a, 0x144000ef, 0x24020007,
+0x100000d2, 0x0, 0xc003f28, 0x0,
+0x104000e7, 0x24020001, 0x8f820214, 0x3c03ffff,
+0x3c040001, 0x8c846f98, 0x431024, 0x3442251f,
0xaf820214, 0x24020008, 0x10800005, 0xaee204b8,
-0x3c020001, 0x8c423e14, 0x1040006d, 0x24020001,
-0x8f820220, 0x3c030008, 0x431024, 0x10400073,
-0x3c020200, 0x10000081, 0x0, 0x8ee204b8,
-0x2443ffff, 0x2c620007, 0x1040008e, 0x31080,
-0x3c010001, 0x220821, 0x8c223bb8, 0x400008,
-0x0, 0xc003b0b, 0x0, 0x3c010001,
-0xac203d8c, 0xaf800204, 0x3c010001, 0xc004045,
-0xac205f80, 0x24020001, 0x3c010001, 0xac223da0,
-0x24020002, 0x1000007b, 0xaee204b8, 0xc0040f2,
-0x0, 0x3c030001, 0x8c633da0, 0x24020009,
-0x14620074, 0x24020003, 0x10000072, 0xaee204b8,
-0x3c020001, 0x8c425f98, 0x30424000, 0x10400003,
-0x3c0200c8, 0x10000002, 0x344201f6, 0x344201fe,
-0xaf820238, 0x8f830054, 0x10000014, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c423ed0, 0x2463d8f0,
-0x431023, 0x2c422710, 0x1440005e, 0x24020005,
-0x1000005c, 0xaee204b8, 0x8f820220, 0x3c03f700,
-0x431025, 0xaf820220, 0xaf800204, 0x3c010001,
-0xac205f80, 0x8f830054, 0x24020006, 0xaee204b8,
-0x3c010001, 0x1000004f, 0xac233ed0, 0x8f830054,
-0x3c020001, 0x8c423ed0, 0x2463fff6, 0x431023,
-0x2c42000a, 0x14400047, 0x0, 0x24020007,
-0x10000044, 0xaee204b8, 0xc003c88, 0x0,
-0x1040003e, 0x24020001, 0x8f820214, 0x3c03ffff,
-0x3c040001, 0x8c843ec8, 0x431024, 0x3442251f,
-0xaf820214, 0x24020008, 0x1080000f, 0xaee204b8,
-0x3c020001, 0x8c423e14, 0x1440000b, 0x0,
-0x8f820220, 0x34420002, 0xaf820220, 0x24020001,
-0x3c010001, 0xac225f30, 0xc00456c, 0x8f840220,
-0x10000016, 0x0, 0x8f820220, 0x3c030008,
-0x431024, 0x14400011, 0x3c020200, 0x282a025,
-0x2402000e, 0x3c010001, 0xac225f30, 0xc0049a8,
-0x2021, 0x8f820220, 0x34420002, 0xc003bc9,
-0xaf820220, 0x3c050001, 0x8ca53d88, 0xc0048dd,
-0x2021, 0x10000013, 0x0, 0x3c020001,
-0x8c423e14, 0x1040000f, 0x0, 0x3c020001,
-0x8c423e10, 0x2442ffff, 0x3c010001, 0xac223e10,
-0x14400008, 0x24020002, 0x3c010001, 0xac203e14,
-0x3c010001, 0x10000003, 0xac223e10, 0x3c010001,
-0xac223d8c, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x8f820200, 0x8f820220, 0x8f820220, 0x34420004,
-0xaf820220, 0x8f820200, 0x3c060001, 0x8cc63d88,
-0x34420004, 0xaf820200, 0x24020002, 0x10c2003b,
-0x2cc20003, 0x10400005, 0x24020001, 0x10c2000a,
-0x3c03f0ff, 0x10000099, 0x0, 0x24020004,
-0x10c2005a, 0x24020008, 0x10c2006d, 0x3c02f0ff,
-0x10000092, 0x0, 0x8f820050, 0x3463ffff,
-0x3c05ffff, 0x3c040001, 0x8c843ee0, 0x431024,
-0x3c030700, 0x431025, 0xaf820050, 0x24020e00,
-0xaf860200, 0xaf860220, 0xaf820238, 0x8f820044,
-0x3c030001, 0x8c633d78, 0x34a53f7f, 0x451024,
-0x34630022, 0xaf820044, 0x24020004, 0xaf860238,
-0x1082000c, 0xaf830200, 0x3c020001, 0x8c423d9c,
-0x3c030001, 0x8c633d80, 0x3c040001, 0x8c843d7c,
-0x34428000, 0x621825, 0x641825, 0x1000006e,
-0x34620002, 0x3c020001, 0x8c423d80, 0x3c030001,
-0x8c633d9c, 0x3c040001, 0x8c843d7c, 0x431025,
-0x441025, 0x10000064, 0x34420002, 0x8f830050,
-0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c843ec8,
+0x3c020001, 0x8c426ec4, 0x10400064, 0x24020001,
+0x8f820220, 0x3c030008, 0x431024, 0x1040006a,
+0x3c020200, 0x10000078, 0x0, 0x8ee204b8,
+0x2443ffff, 0x2c620007, 0x104000cf, 0x31080,
+0x3c010001, 0x220821, 0x8c226bc8, 0x400008,
+0x0, 0xc003d87, 0x0, 0x3c010001,
+0xac206e1c, 0xaf800204, 0x3c010002, 0xc0043d3,
+0xac209060, 0x24020001, 0x3c010001, 0xac226e34,
+0x24020002, 0x100000bc, 0xaee204b8, 0xc004498,
+0x0, 0x3c030001, 0x8c636e34, 0x10000084,
+0x24020009, 0x3c020002, 0x8c429078, 0x30424000,
+0x10400003, 0x3c0200c8, 0x10000002, 0x344201f6,
+0x344201fe, 0xaf820238, 0x8f830054, 0x1000008b,
+0x24020004, 0x8f830054, 0x3c020001, 0x8c426fa0,
+0x2463d8f0, 0x431023, 0x2c422710, 0x144000a2,
+0x24020005, 0x10000079, 0x0, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
+0x3c010002, 0x10000077, 0xac209060, 0x8f830054,
+0x3c020001, 0x8c426fa0, 0x2463fff6, 0x431023,
+0x2c42000a, 0x14400090, 0x24020007, 0x10000073,
+0x0, 0xc003f28, 0x0, 0x10400088,
+0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001,
+0x8c846f98, 0x431024, 0x3442251f, 0xaf820214,
+0x24020008, 0x1080000f, 0xaee204b8, 0x3c020001,
+0x8c426ec4, 0x1440000b, 0x0, 0x8f820220,
+0x34420002, 0xaf820220, 0x24020001, 0x3c010002,
+0xac229010, 0xc004ecc, 0x8f840220, 0x10000016,
+0x0, 0x8f820220, 0x3c030008, 0x431024,
+0x14400011, 0x3c020200, 0x282a025, 0x2402000e,
+0x3c010002, 0xac229010, 0xc00553d, 0x2021,
+0x8f820220, 0x34420002, 0xc003e45, 0xaf820220,
+0x3c050001, 0x8ca56e18, 0xc0052c7, 0x2021,
+0x1000005d, 0x0, 0x3c020001, 0x8c426ec4,
+0x10400059, 0x0, 0x3c020001, 0x8c426ec0,
+0x2442ffff, 0x3c010001, 0xac226ec0, 0x14400052,
+0x24020002, 0x3c010001, 0xac206ec4, 0x3c010001,
+0x1000004d, 0xac226ec0, 0x8ee204b8, 0x2443ffff,
+0x2c620007, 0x10400048, 0x31080, 0x3c010001,
+0x220821, 0x8c226be8, 0x400008, 0x0,
+0x3c020001, 0x8c426e24, 0x10400024, 0x24020007,
+0xc0043d3, 0x0, 0x24020002, 0xaee204b8,
+0x3c010001, 0x10000038, 0xac206e24, 0xc0048b3,
+0x0, 0x3c030001, 0x8c636e54, 0x24020006,
+0x14620031, 0x24020003, 0x1000002f, 0xaee204b8,
+0x3c050001, 0x8ca56e18, 0x3c060002, 0x8cc69078,
+0xc005134, 0x2021, 0x24020005, 0x10000026,
+0xaee204b8, 0x8f820220, 0x3c03f700, 0x431025,
+0xaf820220, 0x8f830054, 0x24020006, 0xaee204b8,
+0x3c010001, 0x1000001c, 0xac236fa0, 0x1000001a,
+0xaee204b8, 0x3c050001, 0x8ca56e18, 0xc0052c7,
+0x2021, 0xc00553d, 0x2021, 0x3c020002,
+0x8c429070, 0x441000e, 0x24020001, 0x8f820214,
+0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214,
+0x24020008, 0xaee204b8, 0x8f820220, 0x34420002,
+0xc003e45, 0xaf820220, 0x10000003, 0x0,
+0x3c010001, 0xac226e1c, 0x8fbf001c, 0x8fb00018,
+0x3e00008, 0x27bd0020, 0x8f820200, 0x8f820220,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820200,
+0x3c050001, 0x8ca56e18, 0x34420004, 0xaf820200,
+0x24020002, 0x10a2004b, 0x2ca20003, 0x10400005,
+0x24020001, 0x10a2000a, 0x0, 0x100000b1,
+0x0, 0x24020004, 0x10a20072, 0x24020008,
+0x10a20085, 0x3c02f0ff, 0x100000aa, 0x0,
+0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001,
+0x8c846fb8, 0x621824, 0x3c020700, 0x621825,
+0x24020e00, 0x2484fffb, 0x2c840002, 0xaf830050,
+0xaf850200, 0xaf850220, 0x14800006, 0xaf820238,
+0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
+0xaf820044, 0x3c030001, 0x8c636fb8, 0x24020005,
+0x14620004, 0x0, 0x8f820044, 0x34425000,
+0xaf820044, 0x3c020001, 0x8c426e08, 0x3c030001,
+0x8c636fb8, 0x34420022, 0x2463fffc, 0x2c630002,
+0x1460000c, 0xaf820200, 0x3c020001, 0x8c426e2c,
+0x3c030001, 0x8c636e10, 0x3c040001, 0x8c846e0c,
+0x34428000, 0x621825, 0x641825, 0x1000000a,
+0x34620002, 0x3c020001, 0x8c426e10, 0x3c030001,
+0x8c636e2c, 0x3c040001, 0x8c846e0c, 0x431025,
+0x441025, 0x34420002, 0xaf820220, 0x1000002f,
+0x24020001, 0x24020e01, 0xaf820238, 0x8f830050,
+0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f98,
0x621824, 0x3c020d00, 0x621825, 0x24020001,
-0xaf830050, 0xaf820200, 0xaf820220, 0x24020e00,
-0x10800009, 0xaf820238, 0x3c020001, 0x8c423e14,
-0x14400005, 0x3c033f00, 0x3c020001, 0x8c423d70,
-0x10000005, 0x34630070, 0x3c020001, 0x8c423d70,
-0x3c033f00, 0x34630072, 0x431025, 0xaf820200,
-0x3c030001, 0x8c633d74, 0x3c04f700, 0x3c020001,
-0x8c423d80, 0x3c050001, 0x8ca53d9c, 0x641825,
-0x431025, 0x1000003c, 0x451025, 0x8f830050,
-0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c843ec8,
-0x621824, 0x3c020a00, 0x621825, 0x24020001,
-0xaf830050, 0xaf820200, 0x1080001e, 0xaf820220,
-0x3c020001, 0x8c423e14, 0x1440001a, 0x3c033f00,
-0x3c020001, 0x8c423d70, 0x1000001a, 0x346300e0,
-0x8f830050, 0x3c040001, 0x8c843ec8, 0x3442ffff,
-0x621824, 0x1080000f, 0xaf830050, 0x3c020001,
-0x8c423e14, 0x1440000b, 0x3c043f00, 0x3c030001,
-0x8c633d70, 0x348400e0, 0x24020001, 0xaf820200,
-0xaf820220, 0x641825, 0xaf830200, 0x10000008,
-0x3c05f700, 0x3c020001, 0x8c423d70, 0x3c033f00,
-0x346300e2, 0x431025, 0xaf820200, 0x3c05f700,
-0x34a58000, 0x3c030001, 0x8c633d74, 0x3c020001,
-0x8c423d80, 0x3c040001, 0x8c843d9c, 0x651825,
-0x431025, 0x441025, 0xaf820220, 0x3e00008,
-0x0, 0x3c030001, 0x8c633da0, 0x3c020001,
-0x8c423da4, 0x10620003, 0x24020002, 0x3c010001,
-0xac233da4, 0x1062001d, 0x2c620003, 0x10400025,
-0x24020001, 0x14620023, 0x24020004, 0x3c030001,
-0x8c633d88, 0x10620006, 0x24020008, 0x1462000c,
-0x3c0200c8, 0x344201fb, 0x10000009, 0xaf820238,
-0x24020e01, 0xaf820238, 0x8f820044, 0x3c03ffff,
-0x34633f7f, 0x431024, 0x34420080, 0xaf820044,
-0x8f830054, 0x24020002, 0x3c010001, 0xac223da0,
-0x3c010001, 0x1000000b, 0xac233ed4, 0x8f830054,
-0x3c020001, 0x8c423ed4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x14400003, 0x24020009, 0x3c010001,
-0xac223da0, 0x3e00008, 0x0, 0x27bdffd8,
+0xaf830050, 0xaf820200, 0xaf820220, 0x10800005,
+0x3c033f00, 0x3c020001, 0x8c426e00, 0x10000004,
+0x34630070, 0x3c020001, 0x8c426e00, 0x34630072,
+0x431025, 0xaf820200, 0x3c030001, 0x8c636e04,
+0x3c02f700, 0x621825, 0x3c020001, 0x8c426e10,
+0x3c040001, 0x8c846e2c, 0x3c050001, 0x8ca56fb8,
+0x431025, 0x441025, 0xaf820220, 0x24020005,
+0x14a20006, 0x24020001, 0x8f820044, 0x2403afff,
+0x431024, 0xaf820044, 0x24020001, 0x1000003d,
+0xaf820238, 0x8f830050, 0x3c02f0ff, 0x3442ffff,
+0x3c040001, 0x8c846f98, 0x621824, 0x3c020a00,
+0x621825, 0x24020001, 0xaf830050, 0xaf820200,
+0x1080001e, 0xaf820220, 0x3c020001, 0x8c426ec4,
+0x1440001a, 0x3c033f00, 0x3c020001, 0x8c426e00,
+0x1000001a, 0x346300e0, 0x8f830050, 0x3c040001,
+0x8c846f98, 0x3442ffff, 0x621824, 0x1080000f,
+0xaf830050, 0x3c020001, 0x8c426ec4, 0x1440000b,
+0x3c043f00, 0x3c030001, 0x8c636e00, 0x348400e0,
+0x24020001, 0xaf820200, 0xaf820220, 0x641825,
+0xaf830200, 0x10000008, 0x3c05f700, 0x3c020001,
+0x8c426e00, 0x3c033f00, 0x346300e2, 0x431025,
+0xaf820200, 0x3c05f700, 0x34a58000, 0x3c030001,
+0x8c636e04, 0x3c020001, 0x8c426e10, 0x3c040001,
+0x8c846e2c, 0x651825, 0x431025, 0x441025,
+0xaf820220, 0x3e00008, 0x0, 0x3c030001,
+0x8c636e34, 0x3c020001, 0x8c426e38, 0x10620003,
+0x24020002, 0x3c010001, 0xac236e38, 0x1062001d,
+0x2c620003, 0x10400025, 0x24020001, 0x14620023,
+0x24020004, 0x3c030001, 0x8c636e18, 0x10620006,
+0x24020008, 0x1462000c, 0x3c0200c8, 0x344201fb,
+0x10000009, 0xaf820238, 0x24020e01, 0xaf820238,
+0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
+0x34420080, 0xaf820044, 0x8f830054, 0x24020002,
+0x3c010001, 0xac226e34, 0x3c010001, 0x1000000b,
+0xac236fa4, 0x8f830054, 0x3c020001, 0x8c426fa4,
+0x2463d8f0, 0x431023, 0x2c422710, 0x14400003,
+0x24020009, 0x3c010001, 0xac226e34, 0x3e00008,
+0x0, 0x0, 0x0, 0x27bdffd8,
0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
0xafb10014, 0xc08821, 0xafb00010, 0x8021,
-0xafbf0020, 0xa6200000, 0xc004523, 0x24040001,
+0xafbf0020, 0xa6200000, 0xc004dab, 0x24040001,
0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004523, 0x2021, 0xc004523, 0x24040001,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
0x24100010, 0x2501024, 0x10400002, 0x2021,
-0x24040001, 0xc004523, 0x108042, 0x1600fffa,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
0x2501024, 0x24100010, 0x2701024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fffa, 0x2701024, 0xc004549, 0x34108000,
-0xc004549, 0x0, 0xc004503, 0x0,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x2701024, 0xc004dec, 0x34108000,
+0xc004dec, 0x0, 0xc004d8b, 0x0,
0x50400005, 0x108042, 0x96220000, 0x501025,
0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004549, 0x0, 0x8fbf0020, 0x8fb3001c,
+0xc004dec, 0x0, 0x8fbf0020, 0x8fb3001c,
0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
-0xafb00010, 0x8021, 0xafbf0020, 0xc004523,
+0xafb00010, 0x8021, 0xafbf0020, 0xc004dab,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004523, 0x2021, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0xc004523,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0xc004dab,
0x24040001, 0x24100010, 0x2301024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
-0x108042, 0x1600fffa, 0x2501024, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0x34108000,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x2501024, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x34108000,
0x96620000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004523, 0x108042, 0x1600fff8,
-0x0, 0xc004549, 0x0, 0x8fbf0020,
+0x24040001, 0xc004dab, 0x108042, 0x1600fff8,
+0x0, 0xc004dec, 0x0, 0x8fbf0020,
0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633db0,
-0x3c020001, 0x8c423df4, 0x27bdffd8, 0xafbf0020,
-0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
-0xac233df4, 0x2463ffff, 0x2c620013, 0x10400349,
-0x31080, 0x3c010001, 0x220821, 0x8c223be0,
-0x400008, 0x0, 0xc004549, 0x8021,
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004523,
+0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846e50,
+0x3c020001, 0x8c426e98, 0x27bdffd8, 0xafbf0020,
+0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001,
+0xac246e98, 0x3c030001, 0x8c636fb8, 0x24020005,
+0x14620005, 0x2483ffff, 0xc0048b3, 0x0,
+0x1000034c, 0x0, 0x2c620013, 0x10400349,
+0x31080, 0x3c010001, 0x220821, 0x8c226c10,
+0x400008, 0x0, 0xc004dec, 0x8021,
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004dab,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004523, 0x2021, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0xc004523,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0xc004dab,
0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004523,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc004dab,
0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fff8, 0x0, 0xc004549, 0x0,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fff8, 0x0, 0xc004dec, 0x0,
0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010,
-0x8021, 0xc004523, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004523,
-0x2021, 0xc004523, 0x24040001, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0x24100010,
+0x8021, 0xc004dab, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x24100010,
0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004523, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004549, 0x34108000,
-0xc004549, 0x0, 0xc004503, 0x0,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc004dab, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc004dec, 0x34108000,
+0xc004dec, 0x0, 0xc004d8b, 0x0,
0x50400005, 0x108042, 0x96220000, 0x501025,
0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004549, 0x0, 0x97a20010, 0x30428000,
+0xc004dec, 0x0, 0x97a20010, 0x30428000,
0x144002dc, 0x24020003, 0x100002d8, 0x0,
0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0xc004523, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0xc004523, 0x24040001, 0xc004523,
+0xc004dab, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0xc004dab, 0x24040001, 0xc004dab,
0x2021, 0x34108000, 0x96220000, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
-0x108042, 0x1600fff8, 0x0, 0xc004549,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fff8, 0x0, 0xc004dec,
0x0, 0x8f830054, 0x10000296, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c423edc, 0x2463ff9c,
+0x8f830054, 0x3c020001, 0x8c426fb4, 0x2463ff9c,
0x431023, 0x2c420064, 0x1440029e, 0x24020002,
-0x3c030001, 0x8c633ee0, 0x10620297, 0x2c620003,
+0x3c030001, 0x8c636fb8, 0x10620297, 0x2c620003,
0x14400296, 0x24020011, 0x24020003, 0x10620005,
0x24020004, 0x10620291, 0x2402000f, 0x1000028f,
0x24020011, 0x1000028d, 0x24020005, 0x24020014,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004523,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004dab,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004523, 0x2021, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0xc004523,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0xc004dab,
0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
-0x108042, 0x1600fffa, 0x32020012, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0x34108000,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x32020012, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x34108000,
0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004523, 0x108042, 0x1600fff8,
-0x0, 0xc004549, 0x0, 0x8f830054,
+0x24040001, 0xc004dab, 0x108042, 0x1600fff8,
+0x0, 0xc004dec, 0x0, 0x8f830054,
0x10000248, 0x24020006, 0x8f830054, 0x3c020001,
-0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064,
+0x8c426fb4, 0x2463ff9c, 0x431023, 0x2c420064,
0x14400250, 0x24020007, 0x1000024c, 0x0,
0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020013, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020013,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020013,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fff8, 0x0, 0xc004549, 0x0,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fff8, 0x0, 0xc004dec, 0x0,
0x8f830054, 0x10000207, 0x24020008, 0x8f830054,
-0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023,
+0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023,
0x2c420064, 0x1440020f, 0x24020009, 0x1000020b,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x24040001,
-0xc004523, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020018,
-0xc004549, 0x34108000, 0xc004549, 0x0,
-0xc004503, 0x0, 0x50400005, 0x108042,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020018,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004549, 0x8021,
+0x1600fff7, 0x0, 0xc004dec, 0x8021,
0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020018,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020018,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fff8, 0x0, 0xc004549, 0x0,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fff8, 0x0, 0xc004dec, 0x0,
0x8f830054, 0x10000193, 0x2402000a, 0x8f830054,
-0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023,
+0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023,
0x2c420064, 0x1440019b, 0x2402000b, 0x10000197,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x24040001,
-0xc004523, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020017,
-0xc004549, 0x34108000, 0xc004549, 0x0,
-0xc004503, 0x0, 0x50400005, 0x108042,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020017,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004549, 0x8021,
+0x1600fff7, 0x0, 0xc004dec, 0x8021,
0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020017,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020017,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fff8, 0x0, 0xc004549, 0x0,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fff8, 0x0, 0xc004dec, 0x0,
0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054,
-0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023,
+0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023,
0x2c420064, 0x14400127, 0x24020012, 0x10000123,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x24040001,
-0xc004523, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020014,
-0xc004549, 0x34108000, 0xc004549, 0x0,
-0xc004503, 0x0, 0x50400005, 0x108042,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020014,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004549, 0x8021,
+0x1600fff7, 0x0, 0xc004dec, 0x8021,
0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020014,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020014,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fff8, 0x0, 0xc004549, 0x0,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fff8, 0x0, 0xc004dec, 0x0,
0x8f830054, 0x100000ab, 0x24020013, 0x8f830054,
-0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023,
+0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023,
0x2c420064, 0x144000b3, 0x2402000d, 0x100000af,
0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x24040001,
-0xc004523, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020018,
-0xc004549, 0x34108000, 0xc004549, 0x0,
-0xc004503, 0x0, 0x50400005, 0x108042,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020018,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004549, 0x8021,
+0x1600fff7, 0x0, 0xc004dec, 0x8021,
0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
-0xc004523, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
-0xc004523, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
0x108042, 0x1600fffa, 0x32020001, 0x24100010,
0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004523, 0x108042, 0x1600fffa, 0x32020018,
-0xc004523, 0x24040001, 0xc004523, 0x2021,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020018,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
-0x1600fff8, 0x0, 0xc004549, 0x0,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fff8, 0x0, 0xc004dec, 0x0,
0x8f830054, 0x10000037, 0x2402000e, 0x24020840,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004523,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004dab,
0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004523, 0x2021, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0xc004523,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0xc004dab,
0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004523, 0x108042,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
-0x10400002, 0x2021, 0x24040001, 0xc004523,
-0x108042, 0x1600fffa, 0x32020013, 0xc004523,
-0x24040001, 0xc004523, 0x2021, 0x34108000,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x32020013, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x34108000,
0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004523, 0x108042, 0x1600fff8,
-0x0, 0xc004549, 0x0, 0x8f830054,
-0x24020010, 0x3c010001, 0xac223db0, 0x3c010001,
-0x1000000c, 0xac233edc, 0x8f830054, 0x3c020001,
-0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064,
+0x24040001, 0xc004dab, 0x108042, 0x1600fff8,
+0x0, 0xc004dec, 0x0, 0x8f830054,
+0x24020010, 0x3c010001, 0xac226e50, 0x3c010001,
+0x1000000c, 0xac236fb4, 0x8f830054, 0x3c020001,
+0x8c426fb4, 0x2463ff9c, 0x431023, 0x2c420064,
0x14400004, 0x0, 0x24020011, 0x3c010001,
-0xac223db0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
+0xac226e50, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636e18,
+0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030,
+0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002,
+0x10000003, 0x8e529078, 0x3c120002, 0x8e52907c,
+0x3c030001, 0x8c636e54, 0x3c020001, 0x8c426e9c,
+0x50620004, 0x2463ffff, 0x3c010001, 0xac236e9c,
+0x2463ffff, 0x2c620006, 0x104004b9, 0x31080,
+0x3c010001, 0x220821, 0x8c226c68, 0x400008,
+0x0, 0x2021, 0x2821, 0xc004e0e,
+0x34068000, 0x24040010, 0x24050002, 0x24060002,
+0x24020002, 0xc004e0e, 0xa7a20018, 0x24020002,
+0x3c010001, 0x100004a6, 0xac226e54, 0x27b10018,
+0xa7a00018, 0x8021, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0xc004dab, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0xc004dec,
+0x34108000, 0xc004dec, 0x0, 0xc004d8b,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004dec, 0x0, 0x97a20018,
+0x30428000, 0x14400004, 0x24020003, 0x3c010001,
+0xac226e54, 0x24020003, 0x3c010001, 0x1000046c,
+0xac226e54, 0x24040010, 0x24050002, 0x24060002,
+0x24020002, 0xc004e0e, 0xa7a20018, 0x3c030001,
+0x8c636ea0, 0x24020001, 0x146201e2, 0x0,
+0x27b10018, 0xa7a00018, 0x8021, 0xc004dab,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x24040001, 0xc004dab,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020018,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x32020018, 0xc004dec,
+0x34108000, 0xc004dec, 0x0, 0xc004d8b,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004dec, 0x8021, 0x27b10018,
+0xa7a00018, 0xc004dab, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0x32020018, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020018, 0xc004dec, 0x34108000, 0xc004dec,
+0x0, 0xc004d8b, 0x0, 0x50400005,
+0x108042, 0x96220000, 0x501025, 0xa6220000,
+0x108042, 0x1600fff7, 0x0, 0xc004dec,
+0x8021, 0x24040018, 0x2821, 0xc004e0e,
+0x24060404, 0xa7a0001a, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x32020018, 0xc004dec, 0x34108000,
+0xc004dec, 0x0, 0xc004d8b, 0x0,
+0x50400005, 0x108042, 0x97a2001a, 0x501025,
+0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
+0xc004dec, 0x8021, 0xa7a0001a, 0xc004dab,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x24040001, 0xc004dab,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020018,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x32020018, 0xc004dec,
+0x34108000, 0xc004dec, 0x0, 0xc004d8b,
+0x0, 0x50400005, 0x108042, 0x97a2001a,
+0x501025, 0xa7a2001a, 0x108042, 0x1600fff7,
+0x0, 0xc004dec, 0x8021, 0xa7a0001c,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x24100010, 0xc004dab,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0x24100010, 0x3202001e, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x3202001e, 0xc004dec, 0x34108000, 0xc004dec,
+0x0, 0xc004d8b, 0x0, 0x50400005,
+0x108042, 0x97a2001c, 0x501025, 0xa7a2001c,
+0x108042, 0x1600fff7, 0x0, 0xc004dec,
+0x8021, 0xa7a0001c, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0x24100010, 0xc004dab, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0x24100010, 0x3202001e,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x3202001e, 0xc004dec,
+0x34108000, 0xc004dec, 0x0, 0xc004d8b,
+0x0, 0x50400005, 0x108042, 0x97a2001c,
+0x501025, 0xa7a2001c, 0x108042, 0x1600fff7,
+0x0, 0xc004dec, 0x8021, 0x24020002,
+0xa7a2001e, 0xc004dab, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0x24100010,
+0xc004dab, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0x24100010, 0x3202001e, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x3202001e, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x34108000, 0x97a2001e,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fff8, 0x0,
+0xc004dec, 0x8021, 0xa7a00020, 0xc004dab,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x24040001, 0xc004dab,
+0x2021, 0x24100010, 0xc004dab, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0x24100010,
+0x3202001e, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fffa, 0x3202001e,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
+0x97a20020, 0x501025, 0xa7a20020, 0x108042,
+0x1600fff7, 0x0, 0xc004dec, 0x8021,
+0xa7a00020, 0xc004dab, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x24100010,
+0xc004dab, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0x24100010, 0x3202001e, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x3202001e, 0xc004dec, 0x34108000,
+0xc004dec, 0x0, 0xc004d8b, 0x0,
+0x50400005, 0x108042, 0x97a20020, 0x501025,
+0xa7a20020, 0x108042, 0x1600fff7, 0x0,
+0xc004dec, 0x8021, 0xa7a00022, 0xc004dab,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0x24100010, 0xc004dab, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0x24100010,
+0xc004dab, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0xc004dab, 0x24040001, 0xc004dab,
+0x2021, 0x34108000, 0x97a20022, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fff8, 0x0, 0xc004dec,
+0x0, 0x24040018, 0x24050002, 0xc004e0e,
+0x24060004, 0x3c030001, 0x8c636ea4, 0x24020001,
+0x146200fc, 0x3c024000, 0x3c010001, 0xac206ea4,
+0x2421024, 0x10400276, 0x3c022000, 0x2421024,
+0x10400004, 0x0, 0x3c010001, 0x10000003,
+0xac236f98, 0x3c010001, 0xac206f98, 0x3c030001,
+0x8c636fac, 0x24020005, 0x146200ea, 0x0,
+0x3c020001, 0x8c426f98, 0x1040005f, 0x3c020004,
+0x2421024, 0x10400011, 0xa7a00018, 0x3c020008,
+0x2421024, 0x10400002, 0x24020200, 0xa7a20018,
+0x3c020010, 0x2421024, 0x10400004, 0x0,
+0x97a20018, 0x34420100, 0xa7a20018, 0x97a60018,
+0x24040009, 0x10000004, 0x2821, 0x24040009,
+0x2821, 0x3021, 0xc004e0e, 0x0,
+0x24020001, 0xa7a2001a, 0x3c020008, 0x2421024,
+0x1040000c, 0x3c020002, 0x2421024, 0x10400002,
+0x24020101, 0xa7a2001a, 0x3c020001, 0x2421024,
+0x10400005, 0x3c020010, 0x97a2001a, 0x34420040,
+0xa7a2001a, 0x3c020010, 0x2421024, 0x1040000e,
+0x3c020002, 0x2421024, 0x10400005, 0x3c020001,
+0x97a2001a, 0x34420080, 0xa7a2001a, 0x3c020001,
+0x2421024, 0x10400005, 0x3c0300a0, 0x97a2001a,
+0x34420020, 0xa7a2001a, 0x3c0300a0, 0x2431024,
+0x54430004, 0x3c020020, 0x97a2001a, 0x1000000c,
+0x34420400, 0x2421024, 0x50400004, 0x3c020080,
+0x97a2001a, 0x10000006, 0x34420800, 0x2421024,
+0x10400004, 0x0, 0x97a2001a, 0x34420c00,
+0xa7a2001a, 0x97a6001a, 0x24040004, 0xc004e0e,
+0x2821, 0x32424000, 0x10400003, 0xa7a0001c,
+0x24024000, 0xa7a2001c, 0x97a6001c, 0x2021,
+0x2821, 0x34c61200, 0xc004e0e, 0xa7a6001c,
+0x10000088, 0x0, 0x32424000, 0x10400003,
+0xa7a00018, 0x24024000, 0xa7a20018, 0x3c020010,
+0x2421024, 0x10400004, 0x0, 0x97a20018,
+0x10000004, 0xa7a20018, 0x97a20018, 0x34420100,
+0xa7a20018, 0x3c020001, 0x2421024, 0x10400004,
+0x0, 0x97a20018, 0x10000004, 0xa7a20018,
+0x97a20018, 0x34422000, 0xa7a20018, 0x2021,
+0x97a60018, 0x2821, 0xc004e0e, 0x8021,
+0xa7a0001a, 0xc004dab, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc004dab, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc004dec, 0x34108000,
+0xc004dec, 0x0, 0xc004d8b, 0x0,
+0x50400005, 0x108042, 0x97a2001a, 0x501025,
+0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
+0xc004dec, 0x8021, 0xa7a0001a, 0xc004dab,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x24040001, 0xc004dab,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc004dab,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
+0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
+0x1600fff7, 0x0, 0xc004dec, 0x0,
+0x3c040001, 0x24846c5c, 0x97a60018, 0x97a7001a,
+0x3c020001, 0x8c426e18, 0x3c030001, 0x8c636f98,
+0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b17,
+0xafa30014, 0x8f830054, 0x24020004, 0x3c010001,
+0xac226e54, 0x3c010001, 0x10000179, 0xac236fb0,
+0x8f830054, 0x3c020001, 0x8c426fb0, 0x2463ff9c,
+0x431023, 0x2c420064, 0x14400009, 0x27b10018,
+0x8f820220, 0x24030005, 0x3c010001, 0xac236e54,
+0x3c03f700, 0x431025, 0xaf820220, 0x27b10018,
+0xa7a00018, 0x8021, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0xc004dab, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0xc004dec,
+0x34108000, 0xc004dec, 0x0, 0xc004d8b,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004dec, 0x8021, 0xa7a0001a,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020001,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
+0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
+0x1600fff7, 0x0, 0xc004dec, 0x8021,
+0xa7a0001a, 0xc004dab, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0xc004dec, 0x34108000, 0xc004dec,
+0x0, 0xc004d8b, 0x0, 0x50400005,
+0x108042, 0x97a2001a, 0x501025, 0xa7a2001a,
+0x108042, 0x1600fff7, 0x0, 0xc004dec,
+0x8021, 0xa7a0001c, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020004, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x32020004, 0xc004dec, 0x34108000,
+0xc004dec, 0x0, 0xc004d8b, 0x0,
+0x50400005, 0x108042, 0x97a2001c, 0x501025,
+0xa7a2001c, 0x108042, 0x1600fff7, 0x0,
+0xc004dec, 0x8021, 0xa7a0001c, 0xc004dab,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004dab, 0x2021, 0xc004dab,
+0x24040001, 0xc004dab, 0x24040001, 0xc004dab,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020004,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x32020004, 0xc004dec,
+0x34108000, 0xc004dec, 0x0, 0xc004d8b,
+0x0, 0x50400005, 0x108042, 0x97a2001c,
+0x501025, 0xa7a2001c, 0x108042, 0x1600fff7,
+0x0, 0xc004dec, 0x8021, 0xa7a00020,
+0xc004dab, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004dab, 0x2021,
+0xc004dab, 0x24040001, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004dab,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020019, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020019,
+0xc004dec, 0x34108000, 0xc004dec, 0x0,
+0xc004d8b, 0x0, 0x50400005, 0x108042,
+0x97a20020, 0x501025, 0xa7a20020, 0x108042,
+0x1600fff7, 0x0, 0xc004dec, 0x8021,
+0xa7a00020, 0xc004dab, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004dab,
+0x2021, 0xc004dab, 0x24040001, 0xc004dab,
+0x24040001, 0xc004dab, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0x32020019, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020019, 0xc004dec, 0x34108000, 0xc004dec,
+0x0, 0xc004d8b, 0x0, 0x50400005,
+0x108042, 0x97a20020, 0x501025, 0xa7a20020,
+0x108042, 0x1600fff7, 0x0, 0xc004dec,
+0x0, 0x97a60018, 0x97a7001a, 0x97a2001c,
+0x3c040001, 0x24846c5c, 0xafa20010, 0x97a20020,
+0x3c05000d, 0x34a50204, 0xc002b17, 0xafa20014,
+0x10000007, 0x0, 0x24020006, 0x3c010001,
+0xac226e54, 0x24020011, 0x3c010001, 0xac226e50,
+0x8fbf0034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
+0x3e00008, 0x27bd0038, 0x8f850044, 0x8f820044,
0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
0x8f840054, 0x8f820054, 0xa32824, 0x10000002,
0x24840001, 0x8f820054, 0x821023, 0x2c420002,
@@ -7883,153 +8567,207 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
0x3442ffff, 0x42480, 0x621824, 0x3c020002,
0x822025, 0x641825, 0xaf830044, 0x8f820044,
-0x3c030001, 0x431025, 0xaf820044, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820044, 0x3c030001, 0x431025,
0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
0x24630001, 0x8f820054, 0x621023, 0x2c420002,
0x1440fffc, 0x0, 0x3e00008, 0x0,
-0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0x0, 0x0, 0x27bdffe8,
+0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820044, 0x34420080, 0xaf820044,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x3e00008, 0x0, 0x8f820044,
+0x3c03fff0, 0x3463ffff, 0x431024, 0xaf820044,
+0x8f820044, 0x3c030001, 0x431025, 0xaf820044,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff,
+0x431024, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x3e00008,
+0x0, 0x27bdffc8, 0xafb30024, 0x809821,
+0xafbe002c, 0xa0f021, 0xafb20020, 0xc09021,
+0x33c2ffff, 0xafbf0030, 0xafb50028, 0xafb1001c,
+0xafb00018, 0x14400034, 0xa7b20010, 0x3271ffff,
+0x27b20010, 0x8021, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x2301024, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x2301024, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x34108000, 0x96420000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x12000075, 0x0,
+0x1000fff6, 0x0, 0x3275ffff, 0x27b10010,
+0xa7a00010, 0x8021, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x24040001, 0xc004dab, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x2b01024, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x2b01024, 0xc004dec, 0x34108000,
+0xc004dec, 0x0, 0xc004d8b, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004dec, 0x0, 0x33c5ffff, 0x24020001,
+0x54a20004, 0x24020002, 0x97a20010, 0x10000006,
+0x521025, 0x14a20006, 0x3271ffff, 0x97a20010,
+0x121827, 0x431024, 0xa7a20010, 0x3271ffff,
+0x27b20010, 0x8021, 0xc004dab, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0xc004dab, 0x24040001,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004dab, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x2301024, 0x10400002,
+0x2021, 0x24040001, 0xc004dab, 0x108042,
+0x1600fffa, 0x2301024, 0xc004dab, 0x24040001,
+0xc004dab, 0x2021, 0x34108000, 0x96420000,
+0x501024, 0x10400002, 0x2021, 0x24040001,
+0xc004dab, 0x108042, 0x1600fff8, 0x0,
+0xc004dec, 0x0, 0x8fbf0030, 0x8fbe002c,
+0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8,
0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0,
-0x0, 0x3c020001, 0x8c423ec8, 0x14400005,
-0x0, 0xc003b0b, 0x8f840224, 0x100001d8,
+0x0, 0x3c020001, 0x8c426f98, 0x14400005,
+0x0, 0xc003d87, 0x8f840224, 0x100001d8,
0x0, 0x8f820220, 0x3c030008, 0x431024,
0x10400026, 0x24020001, 0x8f840224, 0x8f820220,
0x3c030400, 0x431024, 0x10400006, 0x0,
-0x3c010001, 0xac205f40, 0x3c010001, 0x1000000b,
-0xac205f60, 0x3c030001, 0x24635f40, 0x8c620000,
+0x3c010002, 0xac209020, 0x3c010002, 0x1000000b,
+0xac209040, 0x3c030002, 0x24639020, 0x8c620000,
0x24420001, 0xac620000, 0x2c420002, 0x14400003,
-0x24020001, 0x3c010001, 0xac225f60, 0x3c020001,
-0x8c425f60, 0x10400006, 0x30820040, 0x10400004,
-0x24020001, 0x3c010001, 0x10000003, 0xac225f64,
-0x3c010001, 0xac205f64, 0x3c010001, 0xac245f3c,
-0x3c010001, 0x1000000b, 0xac205f70, 0x3c010001,
-0xac225f70, 0x3c010001, 0xac205f60, 0x3c010001,
-0xac205f40, 0x3c010001, 0xac205f64, 0x3c010001,
-0xac205f3c, 0x3c030001, 0x8c635f30, 0x3c020001,
-0x8c425f34, 0x50620004, 0x2463ffff, 0x3c010001,
-0xac235f34, 0x2463ffff, 0x2c62000e, 0x10400194,
-0x31080, 0x3c010001, 0x220821, 0x8c223c30,
-0x400008, 0x0, 0x24020002, 0x3c010001,
-0xac205f60, 0x3c010001, 0xac205f40, 0x3c010001,
-0xac205f3c, 0x3c010001, 0xac205f64, 0x3c010001,
-0xac205f58, 0x3c010001, 0xac205f50, 0xaf800224,
-0x3c010001, 0xac225f30, 0x3c020001, 0x8c425f70,
-0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003b0b,
+0x24020001, 0x3c010002, 0xac229040, 0x3c020002,
+0x8c429040, 0x10400006, 0x30820040, 0x10400004,
+0x24020001, 0x3c010002, 0x10000003, 0xac229044,
+0x3c010002, 0xac209044, 0x3c010002, 0xac24901c,
+0x3c010002, 0x1000000b, 0xac209050, 0x3c010002,
+0xac229050, 0x3c010002, 0xac209040, 0x3c010002,
+0xac209020, 0x3c010002, 0xac209044, 0x3c010002,
+0xac20901c, 0x3c030002, 0x8c639010, 0x3c020002,
+0x8c429014, 0x50620004, 0x2463ffff, 0x3c010002,
+0xac239014, 0x2463ffff, 0x2c62000e, 0x10400194,
+0x31080, 0x3c010001, 0x220821, 0x8c226c80,
+0x400008, 0x0, 0x24020002, 0x3c010002,
+0xac209040, 0x3c010002, 0xac209020, 0x3c010002,
+0xac20901c, 0x3c010002, 0xac209044, 0x3c010002,
+0xac209038, 0x3c010002, 0xac209030, 0xaf800224,
+0x3c010002, 0xac229010, 0x3c020002, 0x8c429050,
+0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003d87,
0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd,
-0x431024, 0xaf820200, 0x3c010001, 0xac205f80,
-0x8f830054, 0x3c020001, 0x8c425f58, 0x24040001,
-0x3c010001, 0xac245f6c, 0x24420001, 0x3c010001,
-0xac225f58, 0x2c420004, 0x3c010001, 0xac235f54,
-0x14400006, 0x24020003, 0x3c010001, 0xac243d8c,
-0x3c010001, 0x1000015e, 0xac205f58, 0x3c010001,
-0x1000015b, 0xac225f30, 0x8f830054, 0x3c020001,
-0x8c425f54, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400003, 0x24020004, 0x3c010001, 0xac225f30,
-0x3c020001, 0x8c425f70, 0x14400021, 0x3c02fdff,
+0x431024, 0xaf820200, 0x3c010002, 0xac209060,
+0x8f830054, 0x3c020002, 0x8c429038, 0x24040001,
+0x3c010002, 0xac24904c, 0x24420001, 0x3c010002,
+0xac229038, 0x2c420004, 0x3c010002, 0xac239034,
+0x14400006, 0x24020003, 0x3c010001, 0xac246e1c,
+0x3c010002, 0x1000015e, 0xac209038, 0x3c010002,
+0x1000015b, 0xac229010, 0x8f830054, 0x3c020002,
+0x8c429034, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400003, 0x24020004, 0x3c010002, 0xac229010,
+0x3c020002, 0x8c429050, 0x14400021, 0x3c02fdff,
0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001,
-0x8c843ecc, 0x3c010001, 0xc004754, 0xac205f48,
-0x3c020001, 0x8c425f7c, 0xaf820204, 0x3c020001,
-0x8c425f70, 0x14400012, 0x3c03fdff, 0x8f820204,
+0x8c846f9c, 0x3c010002, 0xc0050b4, 0xac209028,
+0x3c020002, 0x8c42905c, 0xaf820204, 0x3c020002,
+0x8c429050, 0x14400012, 0x3c03fdff, 0x8f820204,
0x3463ffff, 0x30420030, 0x1440012f, 0x283a024,
-0x3c030001, 0x8c635f7c, 0x24020005, 0x3c010001,
-0xac225f30, 0x3c010001, 0x10000131, 0xac235f80,
-0x3c020001, 0x8c425f70, 0x10400010, 0x3c02fdff,
-0x3c020001, 0x8c423e0c, 0x24420001, 0x3c010001,
-0xac223e0c, 0x2c420002, 0x14400125, 0x24020001,
-0x3c010001, 0xac223e14, 0x3c010001, 0xac203e0c,
-0x3c010001, 0x1000011e, 0xac223d8c, 0x3c030001,
-0x8c635f60, 0x3442ffff, 0x10600119, 0x282a024,
-0x3c020001, 0x8c425f3c, 0x10400115, 0x0,
-0x3c010001, 0xac225f68, 0x24020003, 0x3c010001,
-0xac225f40, 0x100000b8, 0x24020006, 0x3c010001,
-0xac205f48, 0x8f820204, 0x34420040, 0xaf820204,
-0x3c020001, 0x8c425f80, 0x24030007, 0x3c010001,
-0xac235f30, 0x34420040, 0x3c010001, 0xac225f80,
-0x3c020001, 0x8c425f60, 0x10400005, 0x0,
-0x3c020001, 0x8c425f3c, 0x104000f0, 0x24020002,
-0x3c050001, 0x24a55f40, 0x8ca20000, 0x2c424e21,
-0x104000ea, 0x24020002, 0x3c020001, 0x8c425f64,
-0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425f3c,
-0x3c030001, 0x8c635f68, 0x441024, 0x641824,
-0x10430004, 0x24020001, 0x3c010001, 0x100000e4,
-0xac225f30, 0x24020003, 0xaca20000, 0x24020008,
-0x3c010001, 0xac225f30, 0x3c020001, 0x8c425f6c,
-0x1040000c, 0x24020001, 0x3c040001, 0xc004761,
-0x8c845f3c, 0x3c020001, 0x8c425f88, 0x14400005,
-0x24020001, 0x3c020001, 0x8c425f84, 0x10400006,
-0x24020001, 0x3c010001, 0xac223d8c, 0x3c010001,
-0x100000cb, 0xac205f58, 0x3c020001, 0x8c425f50,
-0x3c030001, 0x8c635f3c, 0x2c420001, 0x210c0,
-0x30630008, 0x3c010001, 0xac225f50, 0x3c010001,
-0xac235f4c, 0x8f830054, 0x24020009, 0x3c010001,
-0xac225f30, 0x3c010001, 0x100000b9, 0xac235f54,
-0x8f830054, 0x3c020001, 0x8c425f54, 0x2463d8f0,
+0x3c030002, 0x8c63905c, 0x24020005, 0x3c010002,
+0xac229010, 0x3c010002, 0x10000131, 0xac239060,
+0x3c020002, 0x8c429050, 0x10400010, 0x3c02fdff,
+0x3c020001, 0x8c426ebc, 0x24420001, 0x3c010001,
+0xac226ebc, 0x2c420002, 0x14400125, 0x24020001,
+0x3c010001, 0xac226ec4, 0x3c010001, 0xac206ebc,
+0x3c010001, 0x1000011e, 0xac226e1c, 0x3c030002,
+0x8c639040, 0x3442ffff, 0x10600119, 0x282a024,
+0x3c020002, 0x8c42901c, 0x10400115, 0x0,
+0x3c010002, 0xac229048, 0x24020003, 0x3c010002,
+0xac229020, 0x100000b8, 0x24020006, 0x3c010002,
+0xac209028, 0x8f820204, 0x34420040, 0xaf820204,
+0x3c020002, 0x8c429060, 0x24030007, 0x3c010002,
+0xac239010, 0x34420040, 0x3c010002, 0xac229060,
+0x3c020002, 0x8c429040, 0x10400005, 0x0,
+0x3c020002, 0x8c42901c, 0x104000f0, 0x24020002,
+0x3c050002, 0x24a59020, 0x8ca20000, 0x2c424e21,
+0x104000ea, 0x24020002, 0x3c020002, 0x8c429044,
+0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c42901c,
+0x3c030002, 0x8c639048, 0x441024, 0x641824,
+0x10430004, 0x24020001, 0x3c010002, 0x100000e4,
+0xac229010, 0x24020003, 0xaca20000, 0x24020008,
+0x3c010002, 0xac229010, 0x3c020002, 0x8c42904c,
+0x1040000c, 0x24020001, 0x3c040002, 0xc0050c1,
+0x8c84901c, 0x3c020002, 0x8c429068, 0x14400005,
+0x24020001, 0x3c020002, 0x8c429064, 0x10400006,
+0x24020001, 0x3c010001, 0xac226e1c, 0x3c010002,
+0x100000cb, 0xac209038, 0x3c020002, 0x8c429030,
+0x3c030002, 0x8c63901c, 0x2c420001, 0x210c0,
+0x30630008, 0x3c010002, 0xac229030, 0x3c010002,
+0xac23902c, 0x8f830054, 0x24020009, 0x3c010002,
+0xac229010, 0x3c010002, 0x100000b9, 0xac239034,
+0x8f830054, 0x3c020002, 0x8c429034, 0x2463d8f0,
0x431023, 0x2c422710, 0x1440009f, 0x0,
-0x3c020001, 0x8c425f60, 0x10400005, 0x0,
-0x3c020001, 0x8c425f3c, 0x104000a0, 0x24020002,
-0x3c030001, 0x24635f40, 0x8c620000, 0x2c424e21,
-0x1040009a, 0x24020002, 0x3c020001, 0x8c425f6c,
-0x1040000e, 0x0, 0x3c020001, 0x8c425f3c,
-0x3c010001, 0xac205f6c, 0x30420080, 0x1040002f,
+0x3c020002, 0x8c429040, 0x10400005, 0x0,
+0x3c020002, 0x8c42901c, 0x104000a0, 0x24020002,
+0x3c030002, 0x24639020, 0x8c620000, 0x2c424e21,
+0x1040009a, 0x24020002, 0x3c020002, 0x8c42904c,
+0x1040000e, 0x0, 0x3c020002, 0x8c42901c,
+0x3c010002, 0xac20904c, 0x30420080, 0x1040002f,
0x2402000c, 0x8f820204, 0x30420080, 0x1440000c,
-0x24020003, 0x10000029, 0x2402000c, 0x3c020001,
-0x8c425f3c, 0x30420080, 0x14400005, 0x24020003,
+0x24020003, 0x10000029, 0x2402000c, 0x3c020002,
+0x8c42901c, 0x30420080, 0x14400005, 0x24020003,
0x8f820204, 0x30420080, 0x1040001f, 0x24020003,
-0xac620000, 0x2402000a, 0x3c010001, 0xac225f30,
-0x3c040001, 0x24845f78, 0x8c820000, 0x3c030001,
-0x8c635f50, 0x431025, 0xaf820204, 0x8c830000,
-0x3c040001, 0x8c845f50, 0x2402000b, 0x3c010001,
-0xac225f30, 0x641825, 0x3c010001, 0xac235f80,
-0x3c050001, 0x24a55f40, 0x8ca20000, 0x2c424e21,
-0x10400066, 0x24020002, 0x3c020001, 0x8c425f70,
-0x10400005, 0x0, 0x2402000c, 0x3c010001,
-0x10000067, 0xac225f30, 0x3c020001, 0x8c425f60,
-0x10400063, 0x0, 0x3c040001, 0x8c845f3c,
-0x10800055, 0x30820008, 0x3c030001, 0x8c635f4c,
-0x1062005b, 0x24020003, 0x3c010001, 0xac245f68,
-0xaca20000, 0x24020006, 0x3c010001, 0x10000054,
-0xac225f30, 0x8f820200, 0x34420002, 0xaf820200,
-0x8f830054, 0x2402000d, 0x3c010001, 0xac225f30,
-0x3c010001, 0xac235f54, 0x8f830054, 0x3c020001,
-0x8c425f54, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400031, 0x0, 0x3c020001, 0x8c425f70,
-0x10400020, 0x2402000e, 0x3c030001, 0x8c635f84,
-0x3c010001, 0x14600015, 0xac225f30, 0xc003bc9,
-0x0, 0x3c050001, 0x8ca53d88, 0xc0048dd,
-0x2021, 0x3c030001, 0x8c633d88, 0x24020004,
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c423d84,
-0x10000003, 0x2403fff7, 0x3c020001, 0x8c423d84,
-0x431024, 0x3c010001, 0xac223d84, 0x8f830224,
-0x3c020200, 0x3c010001, 0xac235f8c, 0x10000020,
-0x282a025, 0x3c020001, 0x8c425f60, 0x10400005,
-0x0, 0x3c020001, 0x8c425f3c, 0x1040000f,
-0x24020002, 0x3c020001, 0x8c425f40, 0x2c424e21,
-0x1040000a, 0x24020002, 0x3c020001, 0x8c425f60,
-0x1040000f, 0x0, 0x3c020001, 0x8c425f3c,
-0x1440000b, 0x0, 0x24020002, 0x3c010001,
-0x10000007, 0xac225f30, 0x3c020001, 0x8c425f60,
-0x10400003, 0x0, 0xc003b0b, 0x0,
+0xac620000, 0x2402000a, 0x3c010002, 0xac229010,
+0x3c040002, 0x24849058, 0x8c820000, 0x3c030002,
+0x8c639030, 0x431025, 0xaf820204, 0x8c830000,
+0x3c040002, 0x8c849030, 0x2402000b, 0x3c010002,
+0xac229010, 0x641825, 0x3c010002, 0xac239060,
+0x3c050002, 0x24a59020, 0x8ca20000, 0x2c424e21,
+0x10400066, 0x24020002, 0x3c020002, 0x8c429050,
+0x10400005, 0x0, 0x2402000c, 0x3c010002,
+0x10000067, 0xac229010, 0x3c020002, 0x8c429040,
+0x10400063, 0x0, 0x3c040002, 0x8c84901c,
+0x10800055, 0x30820008, 0x3c030002, 0x8c63902c,
+0x1062005b, 0x24020003, 0x3c010002, 0xac249048,
+0xaca20000, 0x24020006, 0x3c010002, 0x10000054,
+0xac229010, 0x8f820200, 0x34420002, 0xaf820200,
+0x8f830054, 0x2402000d, 0x3c010002, 0xac229010,
+0x3c010002, 0xac239034, 0x8f830054, 0x3c020002,
+0x8c429034, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400031, 0x0, 0x3c020002, 0x8c429050,
+0x10400020, 0x2402000e, 0x3c030002, 0x8c639064,
+0x3c010002, 0x14600015, 0xac229010, 0xc003e45,
+0x0, 0x3c050001, 0x8ca56e18, 0xc0052c7,
+0x2021, 0x3c030001, 0x8c636e18, 0x24020004,
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c426e14,
+0x10000003, 0x2403fff7, 0x3c020001, 0x8c426e14,
+0x431024, 0x3c010001, 0xac226e14, 0x8f830224,
+0x3c020200, 0x3c010002, 0xac23906c, 0x10000020,
+0x282a025, 0x3c020002, 0x8c429040, 0x10400005,
+0x0, 0x3c020002, 0x8c42901c, 0x1040000f,
+0x24020002, 0x3c020002, 0x8c429020, 0x2c424e21,
+0x1040000a, 0x24020002, 0x3c020002, 0x8c429040,
+0x1040000f, 0x0, 0x3c020002, 0x8c42901c,
+0x1440000b, 0x0, 0x24020002, 0x3c010002,
+0x10000007, 0xac229010, 0x3c020002, 0x8c429040,
+0x10400003, 0x0, 0xc003d87, 0x0,
0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030001,
-0x24635f88, 0x8c620000, 0x10400005, 0x34422000,
-0x3c010001, 0xac225f7c, 0x10000003, 0xac600000,
-0x3c010001, 0xac245f7c, 0x3e00008, 0x0,
-0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001,
-0xac225f84, 0x14400067, 0x3c02ffff, 0x34421f0e,
+0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002,
+0x24639068, 0x8c620000, 0x10400005, 0x34422000,
+0x3c010002, 0xac22905c, 0x10000003, 0xac600000,
+0x3c010002, 0xac24905c, 0x3e00008, 0x0,
+0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002,
+0xac229064, 0x14400067, 0x3c02ffff, 0x34421f0e,
0x821024, 0x14400061, 0x24020030, 0x30822000,
0x1040005d, 0x30838000, 0x31a02, 0x30820001,
-0x21200, 0x3c040001, 0x8c843ecc, 0x621825,
-0x331c2, 0x3c030001, 0x24633e18, 0x30828000,
+0x21200, 0x3c040001, 0x8c846f9c, 0x621825,
+0x331c2, 0x3c030001, 0x24636ec8, 0x30828000,
0x21202, 0x30840001, 0x42200, 0x441025,
0x239c2, 0x61080, 0x431021, 0x471021,
0x90430000, 0x24020001, 0x10620025, 0x0,
@@ -8037,191 +8775,368 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x1062002c, 0x3c05000f, 0x10000037, 0x0,
0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820220, 0x3c010001, 0xac205fa4, 0x3c010001,
-0x10000034, 0xac205fac, 0x8f820200, 0x34420100,
+0xaf820220, 0x3c010002, 0xac209084, 0x3c010002,
+0x10000034, 0xac20908c, 0x8f820200, 0x34420100,
0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
-0x431024, 0xaf820220, 0x24020100, 0x3c010001,
-0xac225fa4, 0x3c010001, 0x10000026, 0xac205fac,
+0x431024, 0xaf820220, 0x24020100, 0x3c010002,
+0xac229084, 0x3c010002, 0x10000026, 0xac20908c,
0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
-0x3c010001, 0xac205fa4, 0x3c010001, 0x10000019,
-0xac235fac, 0x8f820200, 0x34420100, 0xaf820200,
+0x3c010002, 0xac209084, 0x3c010002, 0x10000019,
+0xac23908c, 0x8f820200, 0x34420100, 0xaf820200,
0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
-0x24020100, 0x3c010001, 0xac225fa4, 0x3c010001,
-0x1000000c, 0xac235fac, 0x34a5ffff, 0x3c040001,
-0x24843c68, 0xafa30010, 0xc0029bb, 0xafa00014,
-0x10000004, 0x0, 0x24020030, 0x3c010001,
-0xac225f88, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x24020100, 0x3c010002, 0xac229084, 0x3c010002,
+0x1000000c, 0xac23908c, 0x34a5ffff, 0x3c040001,
+0x24846cb8, 0xafa30010, 0xc002b17, 0xafa00014,
+0x10000004, 0x0, 0x24020030, 0x3c010002,
+0xac229068, 0x8fbf0018, 0x3e00008, 0x27bd0020,
0x0, 0x0, 0x0, 0x27bdffc8,
-0xafb10024, 0x808821, 0xafb3002c, 0xa09821,
-0xafb00020, 0xc08021, 0x3c040001, 0x24843c80,
-0x3c050009, 0x3c020001, 0x8c423d88, 0x34a59001,
-0x2203021, 0x2603821, 0xafbf0030, 0xafb20028,
-0xa7a0001a, 0xafb00014, 0xc0029bb, 0xafa20010,
-0x24020002, 0x126200eb, 0x2e620003, 0x10400005,
-0x24020001, 0x1262000a, 0x3c02fffb, 0x100000e5,
-0x0, 0x24020004, 0x1262006d, 0x24020008,
-0x1262006c, 0x3c02ffec, 0x100000de, 0x0,
-0x3442ffff, 0x2028024, 0x119140, 0x3c010001,
-0x320821, 0xac305f9c, 0x3c024000, 0x2021024,
-0x10400046, 0x1023c2, 0x30840030, 0x101382,
-0x3042000c, 0x3c030001, 0x24633db4, 0x431021,
-0x823821, 0x3c020020, 0x2021024, 0x10400006,
-0x24020100, 0x3c010001, 0x320821, 0xac225fa0,
-0x10000005, 0x3c020080, 0x3c010001, 0x320821,
-0xac205fa0, 0x3c020080, 0x2021024, 0x10400006,
-0x111940, 0x3c020001, 0x3c010001, 0x230821,
-0x10000005, 0xac225fa8, 0x111140, 0x3c010001,
-0x220821, 0xac205fa8, 0x94e30000, 0x32024000,
-0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018,
-0x24040001, 0x94e20002, 0x24050004, 0x24e60002,
-0x34420001, 0xc004166, 0xa4e20002, 0x24040001,
-0x2821, 0xc004166, 0x27a60018, 0x3c020001,
-0x8c423d88, 0x24110001, 0x3c010001, 0xac313d94,
-0x14530004, 0x32028000, 0xc003b0b, 0x0,
-0x32028000, 0x10400097, 0x0, 0xc003b0b,
-0x0, 0x24020002, 0x3c010001, 0xac313d8c,
-0x3c010001, 0x1000008f, 0xac223d88, 0x24040001,
-0x24050004, 0x27b0001a, 0xc004166, 0x2003021,
-0x24040001, 0x2821, 0xc004166, 0x2003021,
-0x3c020001, 0x521021, 0x8c425f94, 0x3c040001,
-0x8c843d88, 0x3c03bfff, 0x3463ffff, 0x3c010001,
-0xac333d94, 0x431024, 0x3c010001, 0x320821,
-0x10930076, 0xac225f94, 0x10000076, 0x0,
-0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008,
-0x2028025, 0x111140, 0x3c010001, 0x220821,
-0xac305f98, 0x3c022000, 0x2021024, 0x10400009,
-0x0, 0x3c020001, 0x8c423e14, 0x14400005,
-0x24020001, 0x3c010001, 0xac223ec8, 0x10000004,
-0x3c024000, 0x3c010001, 0xac203ec8, 0x3c024000,
-0x2021024, 0x1440001a, 0x0, 0x3c020001,
-0x8c423ec8, 0x10400005, 0x24022020, 0x3c010001,
-0xac223ecc, 0x24020001, 0xaee204b8, 0x3c04bfff,
-0x111940, 0x3c020001, 0x431021, 0x8c425f90,
-0x3c050001, 0x8ca53d88, 0x3484ffff, 0x441024,
-0x3c010001, 0x230821, 0xac225f90, 0x24020001,
-0x10a20044, 0x0, 0x10000040, 0x0,
-0x3c020001, 0x8c423ec8, 0x1040001c, 0x24022000,
-0x3c010001, 0xac223ecc, 0x3c0300a0, 0x2031024,
-0x14430005, 0x111140, 0x3402a000, 0x3c010001,
-0x1000002d, 0xac223ecc, 0x3c030001, 0x621821,
-0x8c635f98, 0x3c020020, 0x621024, 0x10400004,
-0x24022001, 0x3c010001, 0x10000023, 0xac223ecc,
-0x3c020080, 0x621024, 0x1040001f, 0x3402a001,
-0x3c010001, 0x1000001c, 0xac223ecc, 0x3c020020,
-0x2021024, 0x10400007, 0x111940, 0x24020100,
-0x3c010001, 0x230821, 0xac225fa4, 0x10000006,
-0x3c020080, 0x111140, 0x3c010001, 0x220821,
-0xac205fa4, 0x3c020080, 0x2021024, 0x10400006,
-0x111940, 0x3c020001, 0x3c010001, 0x230821,
-0x10000005, 0xac225fac, 0x111140, 0x3c010001,
-0x220821, 0xac205fac, 0x3c030001, 0x8c633d88,
-0x24020001, 0x10620003, 0x0, 0xc003b0b,
-0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028,
-0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038,
-0x27bdffd0, 0xafb50028, 0x80a821, 0xafb20020,
-0x9021, 0xafb30024, 0x9821, 0xafb1001c,
-0x8821, 0x24020002, 0xafbf002c, 0xafb00018,
-0xa7a00012, 0x10a20068, 0xa7a00010, 0x2ca20003,
-0x10400005, 0x24020001, 0x10a2000a, 0x158140,
-0x100000ae, 0x2201021, 0x24020004, 0x10a2005e,
-0x24020008, 0x10a2005d, 0x152940, 0x100000a7,
-0x2201021, 0x3c030001, 0x701821, 0x8c635f9c,
-0x3c024000, 0x621024, 0x14400009, 0x24040001,
-0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001,
-0x300821, 0xac315f94, 0x10000098, 0x2201021,
-0x24050001, 0xc004124, 0x27a60010, 0x24040001,
-0x24050001, 0xc004124, 0x27a60010, 0x97a20010,
-0x30420004, 0x10400034, 0x3c114000, 0x3c030001,
-0x8c633ee0, 0x24020003, 0x10620008, 0x2c620004,
-0x14400029, 0x3c028000, 0x24020004, 0x10620014,
-0x24040001, 0x10000024, 0x3c028000, 0x24040001,
-0x24050011, 0x27b00012, 0xc004124, 0x2003021,
-0x24040001, 0x24050011, 0xc004124, 0x2003021,
-0x97a30012, 0x30624000, 0x10400002, 0x3c130010,
-0x3c130008, 0x3c120001, 0x10000010, 0x30628000,
-0x24050014, 0x27b00012, 0xc004124, 0x2003021,
-0x24040001, 0x24050014, 0xc004124, 0x2003021,
-0x97a30012, 0x30621000, 0x10400002, 0x3c130010,
-0x3c130008, 0x3c120001, 0x30620800, 0x54400001,
-0x3c120002, 0x3c028000, 0x2221025, 0x2531825,
-0x10000007, 0x438825, 0x3c110001, 0x2308821,
-0x8e315f9c, 0x3c027fff, 0x3442ffff, 0x2228824,
-0x151140, 0x3c010001, 0x220821, 0xac315f94,
-0x1000004e, 0x2201021, 0x152940, 0x3c030001,
-0x651821, 0x8c635f98, 0x3c024000, 0x621024,
+0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+0xafb00020, 0xc08021, 0x3c040001, 0x24846cd0,
+0x3c050009, 0x3c020001, 0x8c426e18, 0x34a59001,
+0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
+0xa7a0001a, 0xafb00014, 0xc002b17, 0xafa20010,
+0x24020002, 0x1262007f, 0x2e620003, 0x10400005,
+0x24020001, 0x1262000a, 0x0, 0x1000016f,
+0x0, 0x24020004, 0x126200f4, 0x24020008,
+0x126200f3, 0x3c02ffec, 0x10000168, 0x0,
+0x3c020001, 0x8c426e14, 0x30420002, 0x14400004,
+0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+0x3c010002, 0x310821, 0xac30907c, 0x3c024000,
+0x2021024, 0x1040004a, 0x1023c2, 0x30840030,
+0x101382, 0x3042001c, 0x3c030001, 0x24636e58,
+0x431021, 0x823821, 0x3c020020, 0x2021024,
+0x10400006, 0x24020100, 0x3c010002, 0x310821,
+0xac229080, 0x10000005, 0x3c020080, 0x3c010002,
+0x310821, 0xac209080, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010002,
+0x230821, 0x10000005, 0xac229088, 0x121140,
+0x3c010002, 0x220821, 0xac209088, 0x94e30000,
+0x32024000, 0x10400003, 0xa7a30018, 0x34624000,
+0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
+0x24e60002, 0x34420001, 0xc00450e, 0xa4e20002,
+0x24040001, 0x2821, 0xc00450e, 0x27a60018,
+0x3c020001, 0x8c426e18, 0x24110001, 0x3c010001,
+0xac316e24, 0x14530004, 0x32028000, 0xc003d87,
+0x0, 0x32028000, 0x1040011c, 0x0,
+0xc003d87, 0x0, 0x3c030001, 0x8c636fb8,
+0x24020005, 0x10620115, 0x24020002, 0x3c010001,
+0xac316e1c, 0x3c010001, 0x10000110, 0xac226e18,
+0x24040001, 0x24050004, 0x27b0001a, 0xc00450e,
+0x2003021, 0x24040001, 0x2821, 0xc00450e,
+0x2003021, 0x3c020002, 0x511021, 0x8c429074,
+0x3c040001, 0x8c846e18, 0x3c03bfff, 0x3463ffff,
+0x3c010001, 0xac336e24, 0x431024, 0x3c010002,
+0x310821, 0x109300f7, 0xac229074, 0x100000f7,
+0x0, 0x3c022000, 0x2021024, 0x10400005,
+0x24020001, 0x3c010001, 0xac226f98, 0x10000004,
+0x128940, 0x3c010001, 0xac206f98, 0x128940,
+0x3c010002, 0x310821, 0xac309078, 0x3c024000,
+0x2021024, 0x14400014, 0x0, 0x3c020001,
+0x8c426f98, 0x10400006, 0x24040004, 0x24050001,
+0xc004e0e, 0x24062000, 0x24020001, 0xaee204b8,
+0x3c020002, 0x511021, 0x8c429070, 0x3c03bfff,
+0x3463ffff, 0x431024, 0x3c010002, 0x310821,
+0x100000d0, 0xac229070, 0x3c020001, 0x8c426f98,
+0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d,
+0x3c020020, 0x3c020001, 0x8c426f9c, 0x24030100,
+0x3c010002, 0x310821, 0xac239084, 0x3c030001,
+0x3c010002, 0x310821, 0xac23908c, 0x10000015,
+0x34420400, 0x2021024, 0x10400008, 0x24030100,
+0x3c020001, 0x8c426f9c, 0x3c010002, 0x310821,
+0xac239084, 0x1000000b, 0x34420800, 0x3c020080,
+0x2021024, 0x1040002e, 0x3c030001, 0x3c020001,
+0x8c426f9c, 0x3c010002, 0x310821, 0xac23908c,
+0x34420c00, 0x3c010001, 0xac226f9c, 0x10000025,
+0x24040001, 0x3c020020, 0x2021024, 0x10400006,
+0x24020100, 0x3c010002, 0x310821, 0xac229084,
+0x10000005, 0x3c020080, 0x3c010002, 0x310821,
+0xac209084, 0x3c020080, 0x2021024, 0x10400007,
+0x121940, 0x3c020001, 0x3c010002, 0x230821,
+0xac22908c, 0x10000006, 0x24040001, 0x121140,
+0x3c010002, 0x220821, 0xac20908c, 0x24040001,
+0x2821, 0x27b0001e, 0xc0044cc, 0x2003021,
+0x24040001, 0x2821, 0xc0044cc, 0x2003021,
+0x24040001, 0x24050001, 0x27b0001c, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050001, 0xc0044cc,
+0x2003021, 0x10000077, 0x0, 0x3c02ffec,
+0x3442ffff, 0x2028024, 0x3c020008, 0x2028025,
+0x121140, 0x3c010002, 0x220821, 0xac309078,
+0x3c022000, 0x2021024, 0x10400009, 0x0,
+0x3c020001, 0x8c426ec4, 0x14400005, 0x24020001,
+0x3c010001, 0xac226f98, 0x10000004, 0x3c024000,
+0x3c010001, 0xac206f98, 0x3c024000, 0x2021024,
+0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f98,
+0xaf820238, 0x3c010001, 0xac206e30, 0x10600005,
+0x24022020, 0x3c010001, 0xac226f9c, 0x24020001,
+0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002,
+0x431021, 0x8c429070, 0x3c050001, 0x8ca56e18,
+0x3484ffff, 0x441024, 0x3c010002, 0x230821,
+0xac229070, 0x24020001, 0x10a20044, 0x0,
+0x10000040, 0x0, 0x3c020001, 0x8c426f98,
+0x1040001c, 0x24022000, 0x3c010001, 0xac226f9c,
+0x3c0300a0, 0x2031024, 0x14430005, 0x121140,
+0x3402a000, 0x3c010001, 0x1000002d, 0xac226f9c,
+0x3c030002, 0x621821, 0x8c639078, 0x3c020020,
+0x621024, 0x10400004, 0x24022001, 0x3c010001,
+0x10000023, 0xac226f9c, 0x3c020080, 0x621024,
+0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c,
+0xac226f9c, 0x3c020020, 0x2021024, 0x10400007,
+0x121940, 0x24020100, 0x3c010002, 0x230821,
+0xac229084, 0x10000006, 0x3c020080, 0x121140,
+0x3c010002, 0x220821, 0xac209084, 0x3c020080,
+0x2021024, 0x10400006, 0x121940, 0x3c020001,
+0x3c010002, 0x230821, 0x10000005, 0xac22908c,
+0x121140, 0x3c010002, 0x220821, 0xac20908c,
+0x3c030001, 0x8c636e18, 0x24020001, 0x10620003,
+0x0, 0xc003d87, 0x0, 0x8fbf0030,
+0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+0x3e00008, 0x27bd0038, 0x27bdffb8, 0xafbe003c,
+0x80f021, 0xafb30034, 0x9821, 0xafb20030,
+0x9021, 0xafb1002c, 0x8821, 0x24020002,
+0xafbf0040, 0xafb50038, 0xafb00028, 0xa7a00020,
+0xa7a00018, 0xa7a0001a, 0xa7a0001c, 0xa7a0001e,
+0x10a20142, 0xa7a00022, 0x2ca20003, 0x10400005,
+0x24020001, 0x10a2000a, 0x1ea940, 0x10000253,
+0x2201021, 0x24020004, 0x10a20203, 0x24020008,
+0x10a20202, 0x1e2940, 0x1000024c, 0x2201021,
+0x3c030002, 0x751821, 0x8c63907c, 0x3c024000,
+0x621024, 0x14400009, 0x24040001, 0x3c027fff,
+0x3442ffff, 0x628824, 0x3c010002, 0x350821,
+0xac319074, 0x1000023d, 0x2201021, 0x2821,
+0xc0044cc, 0x27a60018, 0x24040001, 0x2821,
+0xc0044cc, 0x27a60018, 0x24040001, 0x24050001,
+0x27b0001a, 0xc0044cc, 0x2003021, 0x24040001,
+0x24050001, 0xc0044cc, 0x2003021, 0x24040001,
+0x24050004, 0x27b0001c, 0xc0044cc, 0x2003021,
+0x24040001, 0x24050004, 0xc0044cc, 0x2003021,
+0x24040001, 0x24050005, 0x27b0001e, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050005, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050009, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050009, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050001, 0xc0044cc,
+0x27a60018, 0x24040001, 0x24050001, 0xc0044cc,
+0x27a60018, 0x97a20018, 0x30420004, 0x104000ba,
+0x3c114000, 0x3c020001, 0x8c426fb8, 0x2443ffff,
+0x2c620006, 0x104000ba, 0x31080, 0x3c010001,
+0x220821, 0x8c226ce8, 0x400008, 0x0,
+0x24040001, 0x24050011, 0x27b00020, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050011, 0xc0044cc,
+0x2003021, 0x97a30020, 0x30624000, 0x10400002,
+0x3c120010, 0x3c120008, 0x3c130001, 0x30628000,
+0x54400098, 0x3c130002, 0x10000097, 0x3c028000,
+0x24040001, 0x24050014, 0x27b00020, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050014, 0xc0044cc,
+0x2003021, 0x97a30020, 0x30621000, 0x10400002,
+0x3c120010, 0x3c120008, 0x3c130001, 0x1000ffec,
+0x30620800, 0x24040001, 0x24050019, 0x27b00022,
+0xc0044cc, 0x2003021, 0x24040001, 0x24050019,
+0xc0044cc, 0x2003021, 0x97a20022, 0x30430700,
+0x24020400, 0x10620027, 0x28620401, 0x1040000e,
+0x24020200, 0x1062001f, 0x28620201, 0x10400005,
+0x24020100, 0x5062001e, 0x3c130001, 0x1000001e,
+0x24040001, 0x24020300, 0x50620019, 0x3c130002,
+0x10000019, 0x24040001, 0x24020600, 0x1062000d,
+0x28620601, 0x10400005, 0x24020500, 0x5062000b,
+0x3c130002, 0x10000010, 0x24040001, 0x24020700,
+0x1462000d, 0x24040001, 0x3c130004, 0x1000000a,
+0x3c120008, 0x10000006, 0x3c130004, 0x10000005,
+0x3c120008, 0x3c130001, 0x10000002, 0x3c120008,
+0x3c120010, 0x24040001, 0x24050010, 0x27b0001c,
+0xc0044cc, 0x2003021, 0x24040001, 0x24050010,
+0xc0044cc, 0x2003021, 0x3c020004, 0x16620010,
+0x3c020001, 0x8f840054, 0x24030001, 0x24020002,
+0x3c010001, 0xac236e1c, 0x3c010001, 0xac226e18,
+0x3c010001, 0xac236e24, 0x3c010001, 0xac236ea4,
+0x3c010001, 0xac246fa8, 0x10000041, 0x2538825,
+0x16620035, 0x3c028000, 0x3c020001, 0x8c426ea0,
+0x1440001e, 0x24040018, 0x2021, 0x2821,
+0xc004e0e, 0x34068000, 0x8f830054, 0x8f820054,
+0x2538825, 0x10000002, 0x24630032, 0x8f820054,
+0x621023, 0x2c420033, 0x1440fffc, 0x0,
+0x8f830054, 0x24020001, 0x3c010001, 0xac226ea0,
+0x3c010001, 0xac226e1c, 0x3c010001, 0xac226e18,
+0x3c010001, 0xac226e24, 0x3c010001, 0xac226ea4,
+0x3c010001, 0x1000001e, 0xac236fa8, 0x2821,
+0xc004e0e, 0x24060404, 0x2021, 0x2405001e,
+0x27a60018, 0x24020002, 0xc00450e, 0xa7a20018,
+0x2021, 0x2821, 0x27a60018, 0xc00450e,
+0xa7a00018, 0x24040018, 0x24050002, 0xc004e0e,
+0x24060004, 0x3c028000, 0x2221025, 0x2721825,
+0x10000007, 0x438825, 0x3c110002, 0x2358821,
+0x8e31907c, 0x3c027fff, 0x3442ffff, 0x2228824,
+0x3c020001, 0x8c426e28, 0x1040001c, 0x0,
+0x3c020001, 0x8c426f98, 0x10400002, 0x3c022000,
+0x2228825, 0x1e1140, 0x3c010002, 0x220821,
+0x8c229080, 0x10400003, 0x3c020020, 0x10000004,
+0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+0x1e1140, 0x3c010002, 0x220821, 0x8c229088,
+0x10400003, 0x3c020080, 0x10000004, 0x2228825,
+0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c040001,
+0x24846cdc, 0x3c05000c, 0x97a60022, 0x3c070001,
+0x8ce76e18, 0x34a50326, 0x1e1140, 0x3c010002,
+0x220821, 0xac319074, 0xafb30010, 0xc002b17,
+0xafb10014, 0x10000119, 0x2201021, 0x1ea940,
+0x3c030002, 0x751821, 0x8c639078, 0x3c024000,
+0x621024, 0x14400009, 0x24040001, 0x3c027fff,
+0x3442ffff, 0x628824, 0x3c010002, 0x350821,
+0xac319070, 0x10000109, 0x2201021, 0x2821,
+0xc0044cc, 0x27a60018, 0x24040001, 0x2821,
+0xc0044cc, 0x27a60018, 0x24040001, 0x24050001,
+0x27b1001a, 0xc0044cc, 0x2203021, 0x24040001,
+0x24050001, 0xc0044cc, 0x2203021, 0x24040001,
+0x24050004, 0x27b0001c, 0xc0044cc, 0x2003021,
+0x24040001, 0x24050004, 0xc0044cc, 0x2003021,
+0x24040001, 0x24050005, 0x27b0001e, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050005, 0xc0044cc,
+0x2003021, 0x24040001, 0x24050010, 0xc0044cc,
+0x27a60018, 0x24040001, 0x24050010, 0xc0044cc,
+0x27a60018, 0x24040001, 0x2405000a, 0xc0044cc,
+0x2203021, 0x24040001, 0x2405000a, 0xc0044cc,
+0x2203021, 0x24040001, 0x24050001, 0xc0044cc,
+0x27a60018, 0x24040001, 0x24050001, 0xc0044cc,
+0x27a60018, 0x97a20018, 0x30420004, 0x10400058,
+0x3c114000, 0x3c030001, 0x8c636fac, 0x24020005,
+0x14620059, 0x24040001, 0x24050019, 0x27b00022,
+0xc0044cc, 0x2003021, 0x24040001, 0x24050019,
+0xc0044cc, 0x2003021, 0x97a20022, 0x30430700,
+0x24020400, 0x10620027, 0x28620401, 0x1040000e,
+0x24020200, 0x1062001f, 0x28620201, 0x10400005,
+0x24020100, 0x5062001e, 0x3c130001, 0x1000001e,
+0x3c020004, 0x24020300, 0x50620019, 0x3c130002,
+0x10000019, 0x3c020004, 0x24020600, 0x1062000d,
+0x28620601, 0x10400005, 0x24020500, 0x5062000b,
+0x3c130002, 0x10000010, 0x3c020004, 0x24020700,
+0x1462000d, 0x3c020004, 0x3c130004, 0x1000000a,
+0x3c120008, 0x10000006, 0x3c130004, 0x10000005,
+0x3c120008, 0x3c130001, 0x10000002, 0x3c120008,
+0x3c120010, 0x3c020004, 0x12620017, 0x3c028000,
+0x8f820054, 0x24100001, 0x3c010001, 0xac306e1c,
+0x3c010001, 0xac306e18, 0x3c010001, 0xac306e24,
+0x3c010001, 0xac306ea4, 0x3c010001, 0xac226fa8,
+0x3c020001, 0x16620014, 0x2728825, 0x2021,
+0x2821, 0xc004e0e, 0x34068000, 0x3c010001,
+0x1000000d, 0xac306ea0, 0x2221025, 0x2531825,
+0x3c010001, 0xac206ea0, 0x10000007, 0x438825,
+0x3c110002, 0x2358821, 0x8e319070, 0x3c027fff,
+0x3442ffff, 0x2228824, 0x3c020001, 0x8c426e28,
+0x10400066, 0x1e1140, 0x3c020001, 0x8c426f98,
+0x10400002, 0x3c022000, 0x2228825, 0x1e1140,
+0x3c010002, 0x220821, 0x8c229084, 0x10400003,
+0x3c020020, 0x10000004, 0x2228825, 0x3c02ffdf,
+0x3442ffff, 0x2228824, 0x1e1140, 0x3c010002,
+0x220821, 0x8c22908c, 0x10400003, 0x3c020080,
+0x1000004d, 0x2228825, 0x3c02ff7f, 0x3442ffff,
+0x10000049, 0x2228824, 0x1e2940, 0x3c030002,
+0x651821, 0x8c639078, 0x3c024000, 0x621024,
0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
-0x3c010001, 0x250821, 0xac315f90, 0x1000003f,
-0x2201021, 0x3c020001, 0x8c423d98, 0x10400033,
-0x3c11c00c, 0x3c020001, 0x8c423e14, 0x3c04c00c,
-0x34842000, 0x3c030001, 0x8c633ec8, 0x2102b,
+0x3c010002, 0x250821, 0xac319070, 0x1000003f,
+0x2201021, 0x3c020001, 0x8c426e28, 0x10400033,
+0x3c11c00c, 0x3c020001, 0x8c426ec4, 0x3c04c00c,
+0x34842000, 0x3c030001, 0x8c636f98, 0x2102b,
0x21023, 0x441024, 0x10600003, 0x518825,
-0x3c022000, 0x2228825, 0x3c020001, 0x451021,
-0x8c425fa4, 0x10400003, 0x3c020020, 0x10000004,
+0x3c022000, 0x2228825, 0x3c020002, 0x451021,
+0x8c429084, 0x10400003, 0x3c020020, 0x10000004,
0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x151140, 0x3c010001, 0x220821, 0x8c225fac,
+0x1e1140, 0x3c010002, 0x220821, 0x8c22908c,
0x10400003, 0x3c020080, 0x10000004, 0x2228825,
0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001,
-0x8c423e00, 0x10400002, 0x3c020800, 0x2228825,
-0x3c020001, 0x8c423e04, 0x10400002, 0x3c020400,
-0x2228825, 0x3c020001, 0x8c423e08, 0x10400006,
+0x8c426eb0, 0x10400002, 0x3c020800, 0x2228825,
+0x3c020001, 0x8c426eb4, 0x10400002, 0x3c020400,
+0x2228825, 0x3c020001, 0x8c426eb8, 0x10400006,
0x3c020100, 0x10000004, 0x2228825, 0x3c027fff,
-0x3442ffff, 0x628824, 0x151140, 0x3c010001,
-0x220821, 0xac315f90, 0x2201021, 0x8fbf002c,
-0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
-0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe0,
-0xafb20018, 0x809021, 0xafbf001c, 0xafb10014,
-0xafb00010, 0x8f840200, 0x3c030001, 0x8c633d88,
-0x8f860220, 0x24020002, 0x106200a6, 0x2c620003,
-0x10400005, 0x24020001, 0x1062000a, 0x121940,
-0x100000a0, 0x0, 0x24020004, 0x10620053,
-0x24020008, 0x10620052, 0x128940, 0x10000099,
-0x0, 0x3c050001, 0xa32821, 0x8ca55f9c,
-0x3c100001, 0x2038021, 0x8e105f94, 0x3c024000,
-0xa21024, 0x10400038, 0x3c020008, 0x2021024,
-0x10400020, 0x34840002, 0x3c020001, 0x431021,
-0x8c425fa0, 0x10400005, 0x34840020, 0x34840100,
-0x3c020020, 0x10000006, 0x2028025, 0x2402feff,
-0x822024, 0x3c02ffdf, 0x3442ffff, 0x2028024,
-0x121140, 0x3c010001, 0x220821, 0x8c225fa8,
-0x10400005, 0x3c020001, 0xc23025, 0x3c020080,
-0x10000016, 0x2028025, 0x3c02fffe, 0x3442ffff,
-0xc23024, 0x3c02ff7f, 0x3442ffff, 0x1000000f,
-0x2028024, 0x2402fedf, 0x822024, 0x3c02fffe,
-0x3442ffff, 0xc23024, 0x3c02ff5f, 0x3442ffff,
-0x2028024, 0x3c010001, 0x230821, 0xac205fa0,
-0x3c010001, 0x230821, 0xac205fa8, 0xaf840200,
-0xaf860220, 0x8f820220, 0x34420002, 0xaf820220,
-0x1000000a, 0x121140, 0x3c02bfff, 0x3442ffff,
-0x8f830200, 0x2028024, 0x2402fffd, 0x621824,
-0xc003b0b, 0xaf830200, 0x121140, 0x3c010001,
-0x220821, 0x1000004b, 0xac305f94, 0x128940,
-0x3c050001, 0xb12821, 0x8ca55f98, 0x3c100001,
-0x2118021, 0x8e105f90, 0x3c024000, 0xa21024,
-0x14400010, 0x0, 0x3c020001, 0x8c423ec8,
-0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002,
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003b0b,
-0x2028024, 0x3c010001, 0x310821, 0x10000031,
-0xac305f90, 0x3c020001, 0x8c423ec8, 0x10400005,
-0x3c020020, 0x3c020001, 0x8c423e14, 0x10400025,
-0x3c020020, 0xa21024, 0x10400007, 0x34840020,
-0x24020100, 0x3c010001, 0x310821, 0xac225fa4,
-0x10000006, 0x34840100, 0x3c010001, 0x310821,
-0xac205fa4, 0x2402feff, 0x822024, 0x3c020080,
-0xa21024, 0x10400007, 0x121940, 0x3c020001,
-0x3c010001, 0x230821, 0xac225fac, 0x10000008,
-0xc23025, 0x121140, 0x3c010001, 0x220821,
-0xac205fac, 0x3c02fffe, 0x3442ffff, 0xc23024,
+0x3442ffff, 0x628824, 0x1e1140, 0x3c010002,
+0x220821, 0xac319070, 0x2201021, 0x8fbf0040,
+0x8fbe003c, 0x8fb50038, 0x8fb30034, 0x8fb20030,
+0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0048,
+0x27bdffd0, 0xafb20028, 0x809021, 0xafbf002c,
+0xafb10024, 0xafb00020, 0x8f840200, 0x3c100001,
+0x8e106e18, 0x8f860220, 0x24020002, 0x1202005c,
+0x2e020003, 0x10400005, 0x24020001, 0x1202000a,
+0x121940, 0x1000010c, 0x0, 0x24020004,
+0x120200bf, 0x24020008, 0x120200be, 0x128940,
+0x10000105, 0x0, 0x3c050002, 0xa32821,
+0x8ca5907c, 0x3c100002, 0x2038021, 0x8e109074,
+0x3c024000, 0xa21024, 0x10400038, 0x3c020008,
+0x2021024, 0x10400020, 0x34840002, 0x3c020002,
+0x431021, 0x8c429080, 0x10400005, 0x34840020,
+0x34840100, 0x3c020020, 0x10000006, 0x2028025,
+0x2402feff, 0x822024, 0x3c02ffdf, 0x3442ffff,
+0x2028024, 0x121140, 0x3c010002, 0x220821,
+0x8c229088, 0x10400005, 0x3c020001, 0xc23025,
+0x3c020080, 0x10000016, 0x2028025, 0x3c02fffe,
+0x3442ffff, 0xc23024, 0x3c02ff7f, 0x3442ffff,
+0x1000000f, 0x2028024, 0x2402fedf, 0x822024,
+0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff5f,
+0x3442ffff, 0x2028024, 0x3c010002, 0x230821,
+0xac209080, 0x3c010002, 0x230821, 0xac209088,
0xaf840200, 0xaf860220, 0x8f820220, 0x34420002,
-0xaf820220, 0x121140, 0x3c010001, 0x220821,
-0xac305f90, 0x8fbf001c, 0x8fb20018, 0x8fb10014,
-0x8fb00010, 0x3e00008, 0x27bd0020, 0x1821,
+0xaf820220, 0x1000000a, 0x121140, 0x3c02bfff,
+0x3442ffff, 0x8f830200, 0x2028024, 0x2402fffd,
+0x621824, 0xc003d87, 0xaf830200, 0x121140,
+0x3c010002, 0x220821, 0x100000b7, 0xac309074,
+0x3c020001, 0x8c426f98, 0x10400069, 0x24050004,
+0x24040001, 0xc0044cc, 0x27a60018, 0x24040001,
+0x24050005, 0xc0044cc, 0x27a6001a, 0x97a30018,
+0x97a2001a, 0x3c040001, 0x24846ec8, 0x30630c00,
+0x31a82, 0x30420c00, 0x21282, 0xa7a2001a,
+0x21080, 0x441021, 0x431021, 0xa7a30018,
+0x90480000, 0x24020001, 0x3103ffff, 0x10620029,
+0x28620002, 0x10400005, 0x0, 0x10600009,
+0x0, 0x1000003d, 0x0, 0x10700013,
+0x24020003, 0x1062002c, 0x0, 0x10000037,
+0x0, 0x8f820200, 0x2403feff, 0x431024,
+0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
+0x431024, 0xaf820220, 0x3c010002, 0xac209084,
+0x3c010002, 0x10000032, 0xac20908c, 0x8f820200,
+0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820220, 0x24020100,
+0x3c010002, 0xac229084, 0x3c010002, 0x10000024,
+0xac20908c, 0x8f820200, 0x2403feff, 0x431024,
+0xaf820200, 0x8f820220, 0x3c030001, 0x431025,
+0xaf820220, 0x3c010002, 0xac209084, 0x3c010002,
+0x10000017, 0xac23908c, 0x8f820200, 0x34420100,
+0xaf820200, 0x8f820220, 0x3c030001, 0x431025,
+0xaf820220, 0x24020100, 0x3c010002, 0xac229084,
+0x3c010002, 0x1000000a, 0xac23908c, 0x3c040001,
+0x24846d00, 0x97a6001a, 0x97a70018, 0x3c050001,
+0x34a5ffff, 0xafa80010, 0xc002b17, 0xafa00014,
+0x8f820200, 0x34420002, 0x1000004b, 0xaf820200,
+0x128940, 0x3c050002, 0xb12821, 0x8ca59078,
+0x3c100002, 0x2118021, 0x8e109070, 0x3c024000,
+0xa21024, 0x14400010, 0x0, 0x3c020001,
+0x8c426f98, 0x14400005, 0x3c02bfff, 0x8f820200,
+0x34420002, 0xaf820200, 0x3c02bfff, 0x3442ffff,
+0xc003d87, 0x2028024, 0x3c010002, 0x310821,
+0x10000031, 0xac309070, 0x3c020001, 0x8c426f98,
+0x10400005, 0x3c020020, 0x3c020001, 0x8c426ec4,
+0x10400025, 0x3c020020, 0xa21024, 0x10400007,
+0x34840020, 0x24020100, 0x3c010002, 0x310821,
+0xac229084, 0x10000006, 0x34840100, 0x3c010002,
+0x310821, 0xac209084, 0x2402feff, 0x822024,
+0x3c020080, 0xa21024, 0x10400007, 0x121940,
+0x3c020001, 0x3c010002, 0x230821, 0xac22908c,
+0x10000008, 0xc23025, 0x121140, 0x3c010002,
+0x220821, 0xac20908c, 0x3c02fffe, 0x3442ffff,
+0xc23024, 0xaf840200, 0xaf860220, 0x8f820220,
+0x34420002, 0xaf820220, 0x121140, 0x3c010002,
+0x220821, 0xac309070, 0x8fbf002c, 0x8fb20028,
+0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030,
+0x0, 0x0, 0x0, 0x1821,
0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007,
0x30420001, 0x10400004, 0x0, 0x8f820044,
0x10000003, 0x34420040, 0x8f820044, 0x461024,
0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
0x8f820044, 0x451024, 0xaf820044, 0x24630001,
0x28620008, 0x5440ffee, 0x641007, 0x3e00008,
+0x0, 0x2c820008, 0x1040001b, 0x0,
+0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001,
+0x24426ee0, 0x621821, 0x24640004, 0x90620000,
+0x10400004, 0x0, 0x8f820044, 0x10000003,
+0x34420040, 0x8f820044, 0x461024, 0xaf820044,
+0x8f820044, 0x34420020, 0xaf820044, 0x8f820044,
+0x451024, 0xaf820044, 0x24630001, 0x64102b,
+0x1440ffee, 0x0, 0x3e00008, 0x0,
0x0, 0x0, 0x0, 0x8f8400c4,
0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824,
0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008,
@@ -8232,23 +9147,9 @@ u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8,
0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008,
0x1021, 0x3e00008, 0x0, 0x8f8300e4,
-0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e4,
-0x3e00008, 0xaf8200e8, 0x27623000, 0xaf8200e4,
-0x3e00008, 0xaf8200e8, 0x3e00008, 0x0,
-0x27bdffd0, 0xafbf0028, 0x8f4c004c, 0x8f4d0048,
-0xafb00024, 0x118d0026, 0x1ac4023, 0x8f490054,
-0x5020001, 0x25080200, 0x189102b, 0x14400003,
-0x24020200, 0x8004abe, 0x4c5023, 0x12c5023,
-0x254affff, 0x10a102a, 0x54400001, 0x1005021,
-0x14c8021, 0x321001ff, 0x8f45017c, 0x8f440178,
-0xc1140, 0xa22821, 0x3406ecc0, 0xc23021,
-0x2e63021, 0xa3940, 0x24031000, 0xafa30010,
-0x8f430108, 0xafb00014, 0x8f420014, 0x60f809,
-0xafa20018, 0x10400002, 0x8fbf0028, 0xaf50004c,
-0x120d0003, 0x8fb00024, 0x3e00008, 0x27bd0030,
-0xaf800048, 0x8f820048, 0x0, 0x1040fffc,
-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
-0xaf800048, 0x3e00008, 0x27bd0030, 0x3e00008,
+0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e8,
+0x3e00008, 0xaf8200e4, 0x27623000, 0xaf8200e8,
+0x3e00008, 0xaf8200e4, 0x3e00008, 0x0,
0x0, 0x0, 0x0, 0x8f880120,
0x27624fe0, 0x8f830128, 0x15020002, 0x25090020,
0x27694800, 0x11230012, 0x8fa20010, 0xad040000,
@@ -8284,7 +9185,11 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x0, 0x74785278, 0x4266537a, 0x0,
0x62664174, 0x6e4d726b, 0x0, 0x7265645a,
0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600,
-0x67656e43, 0x6f6e6600, 0x72636246, 0x6c616773,
+0x67656e43, 0x6f6e6600, 0x2a646d61, 0x5244666c,
+0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e,
+0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e,
+0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f6677,
+0x6d61696e, 0x2e630000, 0x72636246, 0x6c616773,
0x0, 0x62616452, 0x78526362, 0x0,
0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469,
0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64,
@@ -8321,12 +9226,14 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64,
0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64,
0x0, 0x2b636b73, 0x756d3136, 0x0,
+0x2b706565, 0x6b5f6d61, 0x635f7278, 0x5f776100,
0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0,
0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d,
0x61635f72, 0x785f6174, 0x746e0000, 0x62616452,
0x6574537a, 0x0, 0x72784264, 0x4266537a,
0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65,
0x72000000, 0x66774f70, 0x4661696c, 0x0,
+0x2b685f75, 0x70646174, 0x655f6c65, 0x64340000,
0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000,
0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000,
0x696e7453, 0x74617465, 0x0, 0x2a2a696e,
@@ -8369,12 +9276,12 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x0, 0x3f636d64, 0x48737453, 0x0,
0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64,
0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b,
-0x0, 0x3f636d64, 0x45727200, 0x80fc,
-0x8878, 0x8878, 0x8800, 0x85a4,
-0x884c, 0x8878, 0x81d4, 0x8238,
-0x83bc, 0x8494, 0x8460, 0x8878,
-0x829c, 0x8550, 0x8878, 0x8560,
-0x81f8, 0x825c, 0x0, 0x0,
+0x0, 0x3f636d64, 0x45727200, 0x864c,
+0x8de0, 0x8de0, 0x8d68, 0x8b0c,
+0x8db4, 0x8de0, 0x8724, 0x8794,
+0x8924, 0x89fc, 0x89c8, 0x8de0,
+0x8804, 0x8ab8, 0x8de0, 0x8ac8,
+0x8748, 0x87b8, 0x0, 0x0,
0x0, 0x24486561, 0x6465723a, 0x202f7072,
0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
@@ -8425,10 +9332,10 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x2e313220, 0x31393939, 0x2f30312f, 0x32302031,
0x393a3439, 0x3a353120, 0x73687561, 0x6e672045,
0x78702024, 0x0, 0x46575f56, 0x45525349,
-0x4f4e3a20, 0x23312054, 0x68752041, 0x75672031,
-0x32203135, 0x3a35323a, 0x32392050, 0x44542031,
+0x4f4e3a20, 0x23312053, 0x61742044, 0x65632031,
+0x31203136, 0x3a30353a, 0x30332050, 0x53542031,
0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54,
-0x494d453a, 0x2031353a, 0x35323a32, 0x39000000,
+0x494d453a, 0x2031363a, 0x30353a30, 0x33000000,
0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064,
0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049,
0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465,
@@ -8436,7 +9343,7 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f,
0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049,
0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e,
-0x20322e37, 0x2e320000, 0x0, 0x12030303,
+0x20322e37, 0x2e320000, 0x0, 0x12040100,
0x0, 0x24486561, 0x6465723a, 0x202f7072,
0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
@@ -8466,15 +9373,15 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x4d657674, 0x526e6746, 0x0, 0x4d516576,
0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x72784672, 0x6d324c67,
-0x0, 0x72784e6f, 0x53744264, 0x0,
-0x72784e6f, 0x4d694264, 0x0, 0x72784e6f,
-0x4a6d4264, 0x0, 0x7278436b, 0x446d6146,
-0x0, 0x72785144, 0x6d457846, 0x0,
-0x72785144, 0x6d614600, 0x72785144, 0x4c426446,
-0x0, 0x72785144, 0x6d426446, 0x0,
-0x72784372, 0x63506164, 0x0, 0x72536d51,
-0x446d6146, 0x0, 0x0, 0x0,
+0x51725072, 0x6f644600, 0x724d6163, 0x43686b30,
+0x0, 0x72784672, 0x6d324c67, 0x0,
+0x72784e6f, 0x53744264, 0x0, 0x72784e6f,
+0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264,
+0x0, 0x7278436b, 0x446d6146, 0x0,
+0x72785144, 0x6d457846, 0x0, 0x72785144,
+0x6d614600, 0x72785144, 0x4c426446, 0x0,
+0x72785144, 0x6d426446, 0x0, 0x72784372,
+0x63506164, 0x0, 0x72536d51, 0x446d6146,
0x0, 0x24486561, 0x6465723a, 0x202f7072,
0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
@@ -8504,30 +9411,38 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
0x51725072, 0x6f644600, 0x0, 0x0,
0x0, 0x50726f62, 0x65506879, 0x0,
-0x6c6e6b41, 0x53535254, 0x0, 0xfc78,
-0xfca8, 0xfcc0, 0xfcec, 0xfd18,
-0xfd2c, 0xfd68, 0x10108, 0xfee8,
-0xff20, 0xfe18, 0xff74, 0xff9c,
-0xffd0, 0xfe5c, 0x10108, 0xfee8,
-0xff20, 0xff44, 0xff74, 0xff9c,
-0xffd0, 0xfffc, 0x0, 0x0,
-0x0, 0x106ec, 0x107bc, 0x10894,
-0x10964, 0x109c0, 0x10a9c, 0x10ac4,
-0x10ba0, 0x10bc8, 0x10d70, 0x10d98,
-0x10f40, 0x11138, 0x113cc, 0x112e0,
-0x113cc, 0x113f8, 0x10f68, 0x11110,
-0x0, 0x116fc, 0x1173c, 0x117cc,
-0x11810, 0x11874, 0x11900, 0x11934,
-0x119bc, 0x11a54, 0x11b24, 0x11b64,
-0x11be8, 0x11c0c, 0x11d1c, 0x646f4261,
+0x6c6e6b41, 0x53535254, 0x0, 0x108d0,
+0x10948, 0x10968, 0x109a4, 0x10ea8,
+0x109d0, 0x10a0c, 0x10f3c, 0x10c18,
+0x10ac0, 0x10ad8, 0x10b1c, 0x10b44,
+0x10b64, 0x10b8c, 0x10f3c, 0x10c18,
+0x10c50, 0x10c68, 0x10c98, 0x10cc0,
+0x10ce0, 0x10d08, 0x0, 0x10e34,
+0x10e60, 0x10e84, 0x10f3c, 0x10ea8,
+0x109d0, 0x10ed8, 0x0, 0x0,
+0x0, 0x115ac, 0x1167c, 0x11754,
+0x11824, 0x11880, 0x1195c, 0x11984,
+0x11a60, 0x11a88, 0x11c30, 0x11c58,
+0x11e00, 0x11ff8, 0x1228c, 0x121a0,
+0x1228c, 0x122b8, 0x11e28, 0x11fd0,
+0x7273745f, 0x676d6969, 0x0, 0x12348,
+0x12380, 0x12468, 0x13034, 0x135fc,
+0x13614, 0x13c7c, 0x13cbc, 0x13d4c,
+0x13d90, 0x13df4, 0x13e80, 0x13eb4,
+0x13f3c, 0x13fd4, 0x140a4, 0x140e4,
+0x14168, 0x1418c, 0x1429c, 0x646f4261,
0x73655067, 0x0, 0x0, 0x0,
0x0, 0x73746d61, 0x634c4e4b, 0x0,
+0x6765746d, 0x636c6e6b, 0x0, 0x14fb4,
+0x14fb4, 0x14ce4, 0x14d34, 0x14d78,
+0x14fb4, 0x7365746d, 0x61636163, 0x74000000,
0x0, 0x0 };
u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = {
0x1,
0x1, 0x1, 0xc001fc, 0x3ffc,
0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49,
-0x43205600, 0x0, 0x0, 0x416c7465,
+0x43205600, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x416c7465,
0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
0x0, 0x0, 0x0, 0x1ffffc,
0x1fff7c, 0x0, 0x0, 0x0,
@@ -8538,13 +9453,17 @@ u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = {
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x3, 0x0,
-0x1, 0x0, 0x0, 0x1,
+0x1, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x1, 0x0,
0x0, 0x0, 0x0, 0x1,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x1000000, 0x21000000, 0x12000140,
-0x0, 0x0, 0x20000000, 0x120000a0,
-0x0, 0x12000060, 0x12000180, 0x120001e0,
-0x0, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x1000000, 0x21000000,
+0x12000140, 0x0, 0x0, 0x20000000,
+0x120000a0, 0x0, 0x12000060, 0x12000180,
+0x120001e0, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2,
0x0, 0x0, 0x30001, 0x1,
-0x30201, 0x0, 0x0, 0x0 };
+0x30201, 0x0, 0x0, 0x1010101,
+0x1010100, 0x10100, 0x1010001, 0x10001,
+0x1000101, 0x101, 0x0, 0x0 };
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
index 1fc708ee1..0829bd82e 100644
--- a/drivers/net/arcnet/arc-rimi.c
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -2,7 +2,7 @@
* Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards
*
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -325,20 +325,11 @@ void cleanup_module(void)
{
struct net_device *dev = my_dev;
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
- void *ioaddr = lp->mem_start + 0x800;
-
- if (dev->start)
- dev->stop(dev);
-
- /* Flush TX and disable RX */
- AINTMASK(0); /* disable IRQ's */
- ACOMMAND(NOTXcmd); /* stop transmit */
- ACOMMAND(NORXcmd); /* disable receive */
+ unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(lp->mem_start);
release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
- unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 98b2ac4da..1608b8bdd 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -3,7 +3,7 @@
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -41,7 +41,7 @@
* <jojo@repas.de>
*/
-#define VERSION "arcnet: v3.91 BETA 99/12/18 - by Avery Pennarun et al.\n"
+#define VERSION "arcnet: v3.92 BETA 2000/02/13 - by Avery Pennarun et al.\n"
#include <linux/module.h>
#include <linux/config.h>
@@ -97,6 +97,7 @@ EXPORT_SYMBOL(arcnet_interrupt);
static int arcnet_open(struct net_device *dev);
static int arcnet_close(struct net_device *dev);
static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void arcnet_timeout(struct net_device *dev);
static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned len);
@@ -347,6 +348,7 @@ void arcdev_setup(struct net_device *dev)
dev->addr_len = 1;
dev->tx_queue_len = 30;
dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */
+ dev->watchdog_timeo = TX_TIMEOUT;
/* New-style flags. */
dev->flags = IFF_BROADCAST;
@@ -358,6 +360,7 @@ void arcdev_setup(struct net_device *dev)
dev->open = arcnet_open;
dev->stop = arcnet_close;
dev->hard_start_xmit = arcnet_send_packet;
+ dev->tx_timeout = arcnet_timeout;
dev->get_stats = arcnet_get_stats;
dev->hard_header = arcnet_header;
dev->rebuild_header = arcnet_rebuild_header;
@@ -397,10 +400,6 @@ static int arcnet_open(struct net_device *dev)
if (ARCRESET(0) && ARCRESET(1))
return -ENODEV;
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 0;
-
newmtu = choose_mtu();
if (newmtu < dev->mtu)
dev->mtu = newmtu;
@@ -441,9 +440,6 @@ static int arcnet_open(struct net_device *dev)
if (ASTATUS() & RESETflag)
ACOMMAND(CFLAGScmd | RESETclear);
- /* we're started */
- dev->start = 1;
-
/* make sure we're ready to receive IRQ's. */
AINTMASK(0);
udelay(1); /* give it time to set the mask before
@@ -453,6 +449,8 @@ static int arcnet_open(struct net_device *dev)
lp->intmask = NORXflag | RECONflag;
AINTMASK(lp->intmask);
+ netif_start_queue(dev);
+
return 0;
}
@@ -462,16 +460,14 @@ static int arcnet_close(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+ netif_stop_queue(dev);
+
/* flush TX and disable RX */
AINTMASK(0);
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
mdelay(1);
- dev->tbusy = 1;
- dev->start = 0;
- dev->interrupt = 0;
-
/* shut down the card */
ARCOPEN(0);
@@ -584,48 +580,6 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
"transmit requested (status=%Xh, txbufs=%d/%d, len=%d)\n",
ASTATUS(), lp->cur_tx, lp->next_tx, skb->len);
- if (dev->tbusy) {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- unsigned long flags;
- int tickssofar = jiffies - dev->trans_start, status = ASTATUS();
-
- if (tickssofar < TX_TIMEOUT) {
- BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d)\n",
- status, tickssofar);
- return 1; /* means "try again" */
- }
- save_flags(flags);
- cli();
-
- if (status & TXFREEflag) { /* transmit _DID_ finish */
- BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n",
- status, tickssofar, lp->intmask, lp->lasttrans_dest);
- lp->stats.tx_errors++;
- } else {
- BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n",
- status, tickssofar, lp->intmask, lp->lasttrans_dest);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
-
- ACOMMAND(NOTXcmd | (lp->cur_tx << 3));
- }
-
- /*
- * interrupt handler will set dev->tbusy = 0 when it notices the
- * transmit has been canceled.
- */
-
- /* make sure we didn't miss a TX IRQ */
- AINTMASK(0);
- lp->intmask |= TXFREEflag;
- AINTMASK(lp->intmask);
-
- restore_flags(flags);
- return 1;
- }
pkt = (struct archdr *) skb->data;
soft = &pkt->soft.rfc1201;
proto = arc_proto_map[soft->proto];
@@ -638,18 +592,10 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
return 0; /* don't try again */
}
- /*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
- if (test_and_set_bit(0, (int *) &dev->tbusy)) {
- BUGMSG(D_NORMAL, "transmitter called with busy bit set! "
- "(status=%Xh, tickssofar=%ld)\n",
- ASTATUS(), jiffies - dev->trans_start);
- lp->stats.tx_errors++;
- lp->stats.tx_fifo_errors++;
- return 0; /* don't try again */
- }
+
+ /* We're busy transmitting a packet... */
+ netif_stop_queue(dev);
+
AINTMASK(0);
txbuf = get_arcbuf(dev);
@@ -718,6 +664,37 @@ static int go_tx(struct net_device *dev)
}
+/* Called by the kernel when transmit times out */
+static void arcnet_timeout(struct net_device *dev)
+{
+ unsigned long flags;
+ struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+ int status = ASTATUS();
+
+ save_flags(flags);
+ cli();
+
+ if (status & TXFREEflag) { /* transmit _DID_ finish */
+ BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, mask=%Xh, dest=%02Xh)\n",
+ status, lp->intmask, lp->lasttrans_dest);
+ lp->stats.tx_errors++;
+ } else {
+ BUGMSG(D_EXTRA, "tx timed out (status=%Xh, intmask=%Xh, dest=%02Xh)\n",
+ status, lp->intmask, lp->lasttrans_dest);
+ lp->stats.tx_errors++;
+ lp->stats.tx_aborted_errors++;
+ ACOMMAND(NOTXcmd | (lp->cur_tx << 3));
+ }
+
+ /* make sure we didn't miss a TX IRQ */
+ AINTMASK(0);
+ lp->intmask |= TXFREEflag;
+ AINTMASK(lp->intmask);
+
+ restore_flags(flags);
+}
+
+
/*
* The typical workload of the driver: Handle the network interface
* interrupts. Establish which device needs attention, and call the correct
@@ -743,25 +720,20 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
/*
- * RESET flag was enabled - if !dev->start, we must clear it right
+ * RESET flag was enabled - if device is not running, we must clear it right
* away (but nothing else).
*/
- if (!dev->start) {
+ if (!netif_running(dev)) {
if (ASTATUS() & RESETflag)
ACOMMAND(CFLAGScmd | RESETclear);
AINTMASK(0);
return;
}
- if (dev->interrupt) {
- BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n");
- return; /* don't even try. */
- }
- dev->interrupt = 1;
BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
ASTATUS(), lp->intmask);
- boguscount = 3;
+ boguscount = 5;
do {
status = ASTATUS();
didsomething = 0;
@@ -839,17 +811,15 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (lp->outgoing.proto->continue_tx(dev, txbuf)) {
/* that was the last segment */
lp->stats.tx_bytes += lp->outgoing.skb->len;
- dev_kfree_skb(lp->outgoing.skb);
+ dev_kfree_skb_irq(lp->outgoing.skb);
lp->outgoing.proto = NULL;
}
lp->next_tx = txbuf;
}
}
/* inform upper layers of idleness, if necessary */
- if (lp->cur_tx == -1) {
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
+ if (lp->cur_tx == -1)
+ netif_wake_queue(dev);
}
/* now process the received packet, if any */
if (recbuf != -1) {
@@ -922,8 +892,6 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
AINTMASK(0);
udelay(1);
AINTMASK(lp->intmask);
-
- dev->interrupt = 0;
}
@@ -987,11 +955,6 @@ void arcnet_rx(struct net_device *dev, int bufnum)
}
/* call the protocol-specific receiver. */
arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length);
-
- /*
- * If any worthwhile packets have been received, a mark_bh(NET_BH) has
- * been done by netif_rx and Linux will handle them after we return.
- */
}
diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c
index 94c68901b..7bd06e2e4 100644
--- a/drivers/net/arcnet/com20020-isa.c
+++ b/drivers/net/arcnet/com20020-isa.c
@@ -3,7 +3,7 @@
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -176,12 +176,9 @@ void cleanup_module(void)
{
struct net_device *dev = my_dev;
- if (dev->start)
- dev->stop(dev);
-
+ unregister_netdev(dev);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
- unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index 585308c27..b88203f54 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -3,7 +3,7 @@
*
* Written 1994-1999 by Avery Pennarun,
* based on an ISA version by David Woodhouse.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -148,13 +148,9 @@ void cleanup_module(void)
for (count = 0; count < numcards; count++) {
dev = cards[count];
-
- if (dev->start)
- dev->stop(dev);
-
+ unregister_netdev(dev);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
- unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index edd92ff25..79800883f 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -3,7 +3,7 @@
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -406,20 +406,13 @@ void cleanup_module(void)
struct net_device *dev = my_dev;
int ioaddr = dev->base_addr;
- if (dev->start)
- dev->stop(dev);
-
- /* Flush TX and disable RX */
- AINTMASK(0); /* disable IRQ's */
- ACOMMAND(NOTXcmd); /* stop transmit */
- ACOMMAND(NORXcmd); /* disable receive */
+ unregister_netdev(dev);
/* Set the thing back to MMAP mode, in case the old driver is loaded later */
outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
- unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
index 843115609..ac8790ef0 100644
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -143,7 +143,7 @@ int __init com90xx_probe(struct net_device *dev)
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S1: ");
+ BUGMSG2(D_INIT, "S1: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
@@ -151,7 +151,7 @@ int __init com90xx_probe(struct net_device *dev)
if (check_region(*port, ARCNET_TOTAL_SIZE)) {
BUGMSG2(D_INIT_REASONS, "(check_region)\n");
- BUGMSG(D_INIT_REASONS, "S1: ");
+ BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
@@ -160,7 +160,7 @@ int __init com90xx_probe(struct net_device *dev)
}
if (ASTATUS() == 0xFF) {
BUGMSG2(D_INIT_REASONS, "(empty)\n");
- BUGMSG(D_INIT_REASONS, "S1: ");
+ BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
@@ -170,13 +170,13 @@ int __init com90xx_probe(struct net_device *dev)
inb(_RESET); /* begin resetting card */
BUGMSG2(D_INIT_REASONS, "\n");
- BUGMSG(D_INIT_REASONS, "S1: ");
+ BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numports) {
- BUGMSG(D_NORMAL, "S1: No ARCnet cards found.\n");
+ BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n");
return -ENODEV;
}
/* Stage 2: we have now reset any possible ARCnet cards, so we can't
@@ -189,7 +189,7 @@ int __init com90xx_probe(struct net_device *dev)
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S2: ");
+ BUGMSG2(D_INIT, "S2: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
}
@@ -207,13 +207,13 @@ int __init com90xx_probe(struct net_device *dev)
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S3: ");
+ BUGMSG2(D_INIT, "S3: ");
}
BUGMSG2(D_INIT, "%lXh ", *shmem);
if (check_mem_region(*shmem, BUFFER_SIZE)) {
BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n");
- BUGMSG(D_INIT_REASONS, "Stage 3: ");
+ BUGMSG2(D_INIT_REASONS, "Stage 3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*shmem = shmems[numshmems - 1];
numshmems--;
@@ -223,7 +223,7 @@ int __init com90xx_probe(struct net_device *dev)
if (isa_readb(ptr) != TESTvalue) {
BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
isa_readb(ptr), TESTvalue);
- BUGMSG(D_INIT_REASONS, "S3: ");
+ BUGMSG2(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*shmem = shmems[numshmems - 1];
numshmems--;
@@ -238,20 +238,20 @@ int __init com90xx_probe(struct net_device *dev)
isa_writeb(0x42, ptr);
if (isa_readb(ptr) != 0x42) {
BUGMSG2(D_INIT_REASONS, "(read only)\n");
- BUGMSG(D_INIT_REASONS, "S3: ");
+ BUGMSG2(D_INIT_REASONS, "S3: ");
*shmem = shmems[numshmems - 1];
numshmems--;
shmem--;
continue;
}
BUGMSG2(D_INIT_REASONS, "\n");
- BUGMSG(D_INIT_REASONS, "S3: ");
+ BUGMSG2(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
}
BUGMSG2(D_INIT, "\n");
if (!numshmems) {
- BUGMSG(D_NORMAL, "S3: No ARCnet cards found.\n");
+ BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n");
return -ENODEV;
}
/* Stage 4: something of a dummy, to report the shmems that are
@@ -263,7 +263,7 @@ int __init com90xx_probe(struct net_device *dev)
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S4: ");
+ BUGMSG2(D_INIT, "S4: ");
}
BUGMSG2(D_INIT, "%lXh ", *shmem);
}
@@ -282,7 +282,7 @@ int __init com90xx_probe(struct net_device *dev)
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S5: ");
+ BUGMSG2(D_INIT, "S5: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
@@ -292,7 +292,7 @@ int __init com90xx_probe(struct net_device *dev)
if ((status & 0x9D)
!= (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status);
- BUGMSG(D_INIT_REASONS, "S5: ");
+ BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
@@ -304,7 +304,7 @@ int __init com90xx_probe(struct net_device *dev)
if (status & RESETflag) {
BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
status);
- BUGMSG(D_INIT_REASONS, "S5: ");
+ BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
@@ -327,7 +327,7 @@ int __init com90xx_probe(struct net_device *dev)
if (airq <= 0) {
BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);
- BUGMSG(D_INIT_REASONS, "S5: ");
+ BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
*port = ports[numports - 1];
numports--;
@@ -398,7 +398,7 @@ int __init com90xx_probe(struct net_device *dev)
isa_writeb(TESTvalue, *shmem);
if (retval && dev && !numcards)
- BUGMSG(D_NORMAL, "S5: No ARCnet cards found.\n");
+ BUGMSG2(D_NORMAL, "S5: No ARCnet cards found.\n");
return retval;
}
@@ -416,7 +416,7 @@ static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq,
/* allocate struct net_device if we don't have one yet */
if (!dev && !(dev = dev_alloc("arc%d", &err))) {
- BUGMSG(D_NORMAL, "Can't allocate device!\n");
+ BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n");
return err;
}
lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
@@ -546,8 +546,7 @@ int com90xx_reset(struct net_device *dev, int really_reset)
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
short ioaddr = dev->base_addr;
- BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
- dev->name, ASTATUS());
+ BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS());
if (really_reset) {
/* reset the card */
@@ -653,13 +652,11 @@ void cleanup_module(void)
dev = cards[count];
lp = (struct arcnet_local *) dev->priv;
- if (dev->start)
- dev->stop(dev);
+ unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(lp->mem_start);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
- unregister_netdev(dev);
kfree(dev->priv);
kfree(dev);
}
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
index 759263ca0..92d026ec8 100644
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -171,7 +171,7 @@ static void rx(struct net_device *dev, int bufnum,
BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag, soft->sequence);
lp->rfc1201.aborted_seq = soft->sequence;
- kfree_skb(in->skb);
+ dev_kfree_skb_irq(in->skb);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->skb = NULL;
@@ -255,7 +255,7 @@ static void rx(struct net_device *dev, int bufnum,
BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
saddr, in->sequence, soft->sequence,
soft->split_flag);
- kfree_skb(in->skb);
+ dev_kfree_skb_irq(in->skb);
in->skb = NULL;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
@@ -271,7 +271,7 @@ static void rx(struct net_device *dev, int bufnum,
soft->sequence);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
- kfree_skb(in->skb);
+ dev_kfree_skb_irq(in->skb);
}
in->sequence = soft->sequence;
in->numpackets = ((unsigned) soft->split_flag >> 1) + 2;
@@ -332,7 +332,7 @@ static void rx(struct net_device *dev, int bufnum,
"(seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag, soft->sequence);
lp->rfc1201.aborted_seq = soft->sequence;
- kfree_skb(in->skb);
+ dev_kfree_skb_irq(in->skb);
in->skb = NULL;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 099bd1300..89d5fd599 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -160,6 +160,16 @@ int __init ariadne_probe(struct net_device *dev)
continue;
}
strcpy(z->name, "Ariadne Ethernet Card and Parallel Ports");
+
+ dev = init_etherdev(NULL, sizeof(struct ariadne_private));
+
+ if (dev == NULL) {
+ release_mem_region(base_addr, sizeof(struct Am79C960));
+ release_mem_region(ram_start, ARIADNE_RAM_SIZE);
+ return -ENOMEM;
+ }
+ memset(dev->priv, 0, sizeof(struct ariadne_private));
+
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x60;
dev->dev_addr[2] = 0x30;
@@ -171,16 +181,6 @@ int __init ariadne_probe(struct net_device *dev)
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- init_etherdev(dev, 0);
-
- dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL);
- if (dev->priv == NULL) {
- release_mem_region(base_addr, sizeof(struct Am79C960));
- release_mem_region(ram_start, ARIADNE_RAM_SIZE);
- return -ENOMEM;
- }
- memset(dev->priv, 0, sizeof(struct ariadne_private));
-
dev->base_addr = ZTWO_VADDR(base_addr);
dev->mem_start = ZTWO_VADDR(ram_start);
dev->mem_end = dev->mem_start+ARIADNE_RAM_SIZE;
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index a028b159e..4c8723efa 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -111,6 +111,7 @@ typedef unsigned char uchar;
/* Information that need to be kept for each board. */
struct net_local {
struct enet_statistics stats;
+ spinlock_t lock;
unsigned char mc_filter[8];
uint jumpered:1; /* Set iff the board has jumper config. */
uint tx_started:1; /* Packets are on the Tx queue. */
@@ -148,6 +149,10 @@ struct net_local {
#define SAPROM 20 /* The station address PROM, if no EEPROM. */
#define RESET 31 /* Write to reset some parts of the chip. */
#define AT1700_IO_EXTENT 32
+
+#define TX_TIMEOUT 10
+
+
/* Index to functions, as function prototypes. */
extern int at1700_probe(struct net_device *dev);
@@ -161,6 +166,7 @@ static void net_rx(struct net_device *dev);
static int net_close(struct net_device *dev);
static struct enet_statistics *net_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
+static void net_tx_timeout (struct net_device *dev);
#ifdef CONFIG_MCA
@@ -228,6 +234,7 @@ int at1700_probe1(struct net_device *dev, int ioaddr)
char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
int slot;
+ struct net_local *lp;
/* Resetting the chip doesn't reset the ISA interface, so don't bother.
That means we have to be careful with the register values we probe for.
@@ -427,21 +434,23 @@ found:
dev->hard_start_xmit = net_send_packet;
dev->get_stats = net_get_stats;
dev->set_multicast_list = &set_rx_mode;
+ dev->tx_timeout = net_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ lp = (struct net_local *)dev->priv;
+ lp->lock = SPIN_LOCK_UNLOCKED;
/* Fill in the fields of 'dev' with ethernet-generic values. */
ether_setup(dev);
- {
- struct net_local *lp = (struct net_local *)dev->priv;
- lp->jumpered = is_fmv18x;
- lp->mca_slot = slot;
- /* Snarf the interrupt vector now. */
- if (request_irq(irq, &net_interrupt, 0, dev->name, dev)) {
- printk (" AT1700 at %#3x is unusable due to a conflict on"
- "IRQ %d.\n", ioaddr, irq);
- lp->invalid_irq = 1;
- return 0;
- }
+ lp->jumpered = is_fmv18x;
+ lp->mca_slot = slot;
+ /* Snarf the interrupt vector now. */
+ if (request_irq(irq, &net_interrupt, 0, dev->name, dev)) {
+ printk (" AT1700 at %#3x is unusable due to a conflict on"
+ "IRQ %d.\n", ioaddr, irq);
+ lp->invalid_irq = 1;
+ return 0;
}
return 0;
@@ -525,86 +534,81 @@ static int net_open(struct net_device *dev)
outb(0x80, ioaddr + IOCONFIG1);
}
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
}
-static int
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void net_tx_timeout (struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10)
- return 1;
- printk("%s: transmit timed out with status %04x, %s?\n", dev->name,
- inw(ioaddr + STATUS), inb(ioaddr + TX_STATUS) & 0x80
- ? "IRQ conflict" : "network cable problem");
- printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
- dev->name, inw(ioaddr + 0), inw(ioaddr + 2), inw(ioaddr + 4),
- inw(ioaddr + 6), inw(ioaddr + 8), inw(ioaddr + 10),
- inw(ioaddr + 12), inw(ioaddr + 14));
- lp->stats.tx_errors++;
- /* ToDo: We should try to restart the adaptor... */
- outw(0xffff, ioaddr + 24);
- outw(0xffff, ioaddr + TX_STATUS);
- outw(0xe85a, ioaddr + CONFIG_0);
- outw(0x8182, ioaddr + TX_INTR);
- outb(0x00, ioaddr + TX_START);
- outb(0x03, ioaddr + COL16CNTL);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- lp->tx_started = 0;
- lp->tx_queue_ready = 1;
- lp->rx_started = 0;
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- }
+ printk ("%s: transmit timed out with status %04x, %s?\n", dev->name,
+ inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
+ ? "IRQ conflict" : "network cable problem");
+ printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
+ dev->name, inw (ioaddr + 0), inw (ioaddr + 2), inw (ioaddr + 4),
+ inw (ioaddr + 6), inw (ioaddr + 8), inw (ioaddr + 10),
+ inw (ioaddr + 12), inw (ioaddr + 14));
+ lp->stats.tx_errors++;
+ /* ToDo: We should try to restart the adaptor... */
+ outw (0xffff, ioaddr + 24);
+ outw (0xffff, ioaddr + TX_STATUS);
+ outw (0xe85a, ioaddr + CONFIG_0);
+ outw (0x8182, ioaddr + TX_INTR);
+ outb (0x00, ioaddr + TX_START);
+ outb (0x03, ioaddr + COL16CNTL);
+
+ dev->trans_start = jiffies;
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
-
- /* We may not start transmitting unless we finish transferring
- a packet into the Tx queue. During executing the following
- codes we possibly catch a Tx interrupt. Thus we flag off
- tx_queue_ready, so that we prevent the interrupt routine
- (net_interrupt) to start transmitting. */
- lp->tx_queue_ready = 0;
- {
- outw(length, ioaddr + DATAPORT);
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
- }
- lp->tx_queue_ready = 1;
-
- if (lp->tx_started == 0) {
- /* If the Tx is idle, always trigger a transmit. */
- outb(0x80 | lp->tx_queue, ioaddr + TX_START);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- dev->trans_start = jiffies;
- lp->tx_started = 1;
- dev->tbusy = 0;
- } else if (lp->tx_queue_len < 4096 - 1502)
- /* Yes, there is room for one more packet. */
- dev->tbusy = 0;
+ lp->tx_started = 0;
+ lp->tx_queue_ready = 1;
+ lp->rx_started = 0;
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+
+ netif_wake_queue(dev);
+}
+
+
+static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *) dev->priv;
+ int ioaddr = dev->base_addr;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+
+ netif_stop_queue (dev);
+
+ /* We may not start transmitting unless we finish transferring
+ a packet into the Tx queue. During executing the following
+ codes we possibly catch a Tx interrupt. Thus we flag off
+ tx_queue_ready, so that we prevent the interrupt routine
+ (net_interrupt) to start transmitting. */
+ lp->tx_queue_ready = 0;
+ {
+ outw (length, ioaddr + DATAPORT);
+ outsw (ioaddr + DATAPORT, buf, (length + 1) >> 1);
+
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
}
+ lp->tx_queue_ready = 1;
+
+ if (lp->tx_started == 0) {
+ /* If the Tx is idle, always trigger a transmit. */
+ outb (0x80 | lp->tx_queue, ioaddr + TX_START);
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
+ lp->tx_started = 1;
+ netif_start_queue (dev);
+ } else if (lp->tx_queue_len < 4096 - 1502)
+ /* Yes, there is room for one more packet. */
+ netif_start_queue (dev);
dev_kfree_skb (skb);
return 0;
@@ -623,10 +627,12 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
return;
}
- dev->interrupt = 1;
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
+
+ spin_lock (&lp->lock);
+
status = inw(ioaddr + TX_STATUS);
outw(status, ioaddr + TX_STATUS);
@@ -665,17 +671,15 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue (dev);
} else {
lp->tx_started = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue (dev);
}
}
}
- dev->interrupt = 0;
+ spin_unlock (&lp->lock);
return;
}
@@ -767,8 +771,7 @@ static int net_close(struct net_device *dev)
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
/* Set configuration register 0 to disable Tx and Rx. */
outb(0xda, ioaddr + CONFIG_0);
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 45da37261..1f58b30c4 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -16,6 +16,8 @@
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
The timer-based reset code was written by Bill Carlson, wwc@super.org.
+
+ Modular support/softnet added by Alan Cox.
*/
static const char *version =
@@ -82,6 +84,7 @@ static const char *version =
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
@@ -101,6 +104,7 @@ static const char *version =
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/spinlock.h>
#include "atp.h"
@@ -133,9 +137,10 @@ static void get_node_ID(struct net_device *dev);
static unsigned short eeprom_op(short ioaddr, unsigned int cmd);
static int net_open(struct net_device *dev);
static void hardware_init(struct net_device *dev);
+static void tx_timeout(struct net_device *dev);
static void write_packet(short ioaddr, int length, unsigned char *packet, int mode);
static void trigger_send(short ioaddr, int length);
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void net_rx(struct net_device *dev);
static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode);
@@ -150,8 +155,8 @@ static void set_multicast_list(struct net_device *dev);
If dev->base_addr == 2, allocate space for the device and return success
(detachable devices only).
*/
-int __init
-atp_init(struct net_device *dev)
+
+int __init atp_init(struct net_device *dev)
{
int *port, ports[] = {0x378, 0x278, 0x3bc, 0};
int base_addr = dev->base_addr;
@@ -220,7 +225,7 @@ static int __init atp_probe1(struct net_device *dev, short ioaddr)
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/* Leave the hardware in a reset state. */
- write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+ write_reg_high(ioaddr, CMR1, CMR1h_RESET);
if (net_debug)
printk(version);
@@ -231,11 +236,10 @@ static int __init atp_probe1(struct net_device *dev, short ioaddr)
if (dev->priv == NULL)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct net_local));
-
-
{
struct net_local *lp = (struct net_local *)dev->priv;
lp->addr_mode = CMR2h_Normal;
+ spin_lock_init(&lp->lock);
}
/* For the ATP adapter the "if_port" is really the data transfer mode. */
@@ -245,9 +249,11 @@ static int __init atp_probe1(struct net_device *dev, short ioaddr)
dev->open = net_open;
dev->stop = net_close;
- dev->hard_start_xmit = net_send_packet;
- dev->get_stats = net_get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->tx_timeout = tx_timeout;
+ dev->watchdog_timeo = HZ/20;
#ifdef TIMED_CHECKER
del_timer(&atp_timer);
@@ -327,12 +333,12 @@ static int net_open(struct net_device *dev)
/* The interrupt line is turned off (tri-stated) when the device isn't in
use. That's especially important for "attached" interfaces where the
port or interrupt may be shared. */
+
if (request_irq(dev->irq, &net_interrupt, 0, "ATP", dev)) {
return -EAGAIN;
}
-
hardware_init(dev);
- dev->start = 1;
+ netif_start_queue(dev);
return 0;
}
@@ -342,11 +348,11 @@ static void hardware_init(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
- int i;
+ int i;
write_reg_high(ioaddr, CMR1, CMR1h_RESET);
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
write_reg_high(ioaddr, CMR2, lp->addr_mode);
@@ -356,22 +362,19 @@ static void hardware_init(struct net_device *dev)
(read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f);
}
- write_reg(ioaddr, CMR2, CMR2_IRQOUT);
- write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
+ write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+ write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
/* Enable the interrupt line from the serial port. */
outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
/* Unmask the interesting interrupts. */
- write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
- write_reg_high(ioaddr, IMR, ISRh_RxErr);
+ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+ write_reg_high(ioaddr, IMR, ISRh_RxErr);
lp->tx_unit_busy = 0;
- lp->pac_cnt_in_tx_buf = 0;
+ lp->pac_cnt_in_tx_buf = 0;
lp->saved_tx_size = 0;
-
- dev->tbusy = 0;
- dev->interrupt = 0;
}
static void trigger_send(short ioaddr, int length)
@@ -383,15 +386,15 @@ static void trigger_send(short ioaddr, int length)
static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode)
{
- length = (length + 1) & ~1; /* Round up to word length. */
- outb(EOC+MAR, ioaddr + PAR_DATA);
- if ((data_mode & 1) == 0) {
+ length = (length + 1) & ~1; /* Round up to word length. */
+ outb(EOC+MAR, ioaddr + PAR_DATA);
+ if ((data_mode & 1) == 0) {
/* Write the packet out, starting with the write addr. */
outb(WrAddr+MAR, ioaddr + PAR_DATA);
do {
write_byte_mode0(ioaddr, *packet++);
} while (--length > 0) ;
- } else {
+ } else {
/* Write the packet out in slow mode. */
unsigned char outbyte = *packet++;
@@ -405,70 +408,61 @@ static void write_packet(short ioaddr, int length, unsigned char *packet, int da
outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
while (--length > 0)
write_byte_mode1(ioaddr, *packet++);
- }
- /* Terminate the Tx frame. End of write: ECB. */
- outb(0xff, ioaddr + PAR_DATA);
- outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+ }
+ /* Terminate the Tx frame. End of write: ECB. */
+ outb(0xff, ioaddr + PAR_DATA);
+ outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);
}
-static int
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void tx_timeout(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
+ /* If we get here, some higher level has decided we are broken. */
+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+ inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
+ : "IRQ conflict");
+ lp->stats.tx_errors++;
+ /* Try to restart the adapter. */
+ hardware_init(dev);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("%s: transmit timed out, %s?\n", dev->name,
- inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
- : "IRQ conflict");
- lp->stats.tx_errors++;
- /* Try to restart the adapter. */
- hardware_init(dev);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ /* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
+ This sequence must not be interrupted by an incoming packet. */
+
+ spin_lock_irqsave(&lp->lock, flags);
+ write_reg(ioaddr, IMR, 0);
+ write_reg_high(ioaddr, IMR, 0);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ write_packet(ioaddr, length, buf, dev->if_port);
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
- int flags;
-
- /* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
- This sequence must not be interrupted by an incoming packet. */
- save_flags(flags);
- cli();
- write_reg(ioaddr, IMR, 0);
- write_reg_high(ioaddr, IMR, 0);
- restore_flags(flags);
-
- write_packet(ioaddr, length, buf, dev->if_port);
-
- lp->pac_cnt_in_tx_buf++;
- if (lp->tx_unit_busy == 0) {
- trigger_send(ioaddr, length);
- lp->saved_tx_size = 0; /* Redundant */
- lp->re_tx = 0;
+ lp->pac_cnt_in_tx_buf++;
+ if (lp->tx_unit_busy == 0) {
+ trigger_send(ioaddr, length);
+ lp->saved_tx_size = 0; /* Redundant */
+ lp->re_tx = 0;
lp->tx_unit_busy = 1;
- } else
- lp->saved_tx_size = length;
-
- dev->trans_start = jiffies;
- /* Re-enable the LPT interrupts. */
- write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
- write_reg_high(ioaddr, IMR, ISRh_RxErr);
- }
+ } else
+ lp->saved_tx_size = length;
+ dev->trans_start = jiffies;
+ /* Re-enable the LPT interrupts. */
+ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+ write_reg_high(ioaddr, IMR, ISRh_RxErr);
dev_kfree_skb (skb);
-
return 0;
}
@@ -482,14 +476,10 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
int ioaddr, status, boguscount = 20;
static int num_tx_since_rx = 0;
- if (dev == NULL) {
- printk ("ATP_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
+
+ spin_lock(&lp->lock);
/* Disable additional spurious interrupts. */
outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
@@ -498,10 +488,14 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
write_reg(ioaddr, CMR2, CMR2_NULL);
write_reg(ioaddr, IMR, 0);
- if (net_debug > 5) printk("%s: In interrupt ", dev->name);
- while (--boguscount > 0) {
+ if (net_debug > 5)
+ printk("%s: In interrupt ", dev->name);
+
+ while (--boguscount > 0)
+ {
status = read_nibble(ioaddr, ISR);
- if (net_debug > 5) printk("loop status %02x..", status);
+ if (net_debug > 5)
+ printk("loop status %02x..", status);
if (status & (ISR_RxOK<<3)) {
write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */
@@ -539,7 +533,8 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
break;
}
/* Attempt to retransmit. */
- if (net_debug > 6) printk("attempting to ReTx");
+ if (net_debug > 6)
+ printk("attempting to ReTx");
write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);
} else {
/* Finish up the transmit. */
@@ -551,8 +546,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
lp->re_tx = 0;
} else
lp->tx_unit_busy = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
}
num_tx_since_rx++;
} else if (num_tx_since_rx > 8
@@ -568,7 +562,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
break;
} else
break;
- }
+ }
/* This following code fixes a rare (and very difficult to track down)
problem where the adapter forgets its ethernet address. */
@@ -584,17 +578,17 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
/* Tell the adapter that it can go back to using the output line as IRQ. */
- write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+ write_reg(ioaddr, CMR2, CMR2_IRQOUT);
/* Enable the physical interrupt line, which is sure to be low until.. */
outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
/* .. we enable the interrupt sources. */
write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
write_reg_high(ioaddr, IMR, ISRh_RxErr); /* Hmmm, really needed? */
- if (net_debug > 5) printk("exiting interrupt.\n");
-
- dev->interrupt = 0;
-
+ if (net_debug > 5)
+ printk("exiting interrupt.\n");
+
+ spin_unlock(&lp->lock);
return;
}
@@ -603,33 +597,17 @@ net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
problem where the adapter forgets its ethernet address. */
static void atp_timed_checker(unsigned long ignored)
{
- int i;
- int ioaddr = atp_timed_dev->base_addr;
+ int i;
+ struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
+ int ioaddr = atp_timed_dev->base_addr;
- if (!atp_timed_dev->interrupt)
- {
- for (i = 0; i < 6; i++)
-#if 0
- if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i])
- {
- struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
- write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
- if (i == 2)
- lp->stats.tx_errors++;
- else if (i == 3)
- lp->stats.tx_dropped++;
- else if (i == 4)
- lp->stats.collisions++;
- else
- lp->stats.rx_errors++;
- }
-#else
- write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
-#endif
- }
- del_timer(&atp_timer);
- atp_timer.expires = jiffies + TIMED_CHECKER;
- add_timer(&atp_timer);
+ spin_lock(&lp->lock);
+ for (i = 0; i < 6; i++)
+ write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
+ spin_unlock(&lp->lock);
+ del_timer(&atp_timer);
+ atp_timer.expires = jiffies + TIMED_CHECKER;
+ add_timer(&atp_timer);
}
#endif
@@ -707,19 +685,17 @@ static void read_block(short ioaddr, int length, unsigned char *p, int data_mode
else
do *p++ = read_byte_mode6(ioaddr); while (--length > 0);
- outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
+ outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
}
/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
+static int net_close(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
/* Flush the Tx and disable Rx here. */
lp->addr_mode = CMR2h_OFF;
@@ -730,7 +706,7 @@ net_close(struct net_device *dev)
free_irq(dev->irq, dev);
/* Leave the hardware in a reset state. */
- write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+ write_reg_high(ioaddr, CMR1, CMR1h_RESET);
return 0;
}
@@ -774,3 +750,27 @@ static void set_multicast_list(struct net_device *dev)
* tab-width: 4
* End:
*/
+
+#ifdef MODULE
+
+static int io = 0;
+static char nullname[8] = "";
+static struct net_device atp_dev = {
+ nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_probe };
+
+MODULE_PARM(io, "I/O port of the pocket adapter");
+
+int init_module(void)
+{
+ atp_dev.base_addr = io;
+ if (register_netdev(&atp_dev) != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_netdev(&atp_dev);
+}
+
+#endif
diff --git a/drivers/net/atp.h b/drivers/net/atp.h
index 8a74d4451..46801e401 100644
--- a/drivers/net/atp.h
+++ b/drivers/net/atp.h
@@ -4,15 +4,14 @@
struct net_local
{
-#ifdef __KERNEL__
struct net_device_stats stats;
-#endif
ushort saved_tx_size;
unsigned char
re_tx, /* Number of packet retransmissions. */
tx_unit_busy,
addr_mode, /* Current Rx filter e.g. promiscuous, etc. */
pac_cnt_in_tx_buf;
+ spinlock_t lock; /* Safety lock */
};
struct rx_header {
@@ -52,8 +51,7 @@ enum page0_regs
CMR2_h = 0x1d,
};
-enum eepage_regs
-{ PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */
+enum eepage_regs { PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */
#define ISR_TxOK 0x01
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 30aa851b8..1c297dbec 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -65,6 +65,7 @@ struct bmac_data {
volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */
volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */
struct device_node *node;
+ int is_bmac_plus;
struct sk_buff *rx_bufs[N_RX_RING];
int rx_fill;
int rx_empty;
@@ -80,6 +81,7 @@ struct bmac_data {
int tx_allocated;
unsigned short hash_use_count[64];
unsigned short hash_table_mask[4];
+ struct net_device *next_bmac;
};
typedef struct bmac_reg_entry {
@@ -124,7 +126,6 @@ bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
};
struct net_device *bmac_devs = NULL;
-static int is_bmac_plus;
#ifdef CONFIG_PMAC_PBOOK
int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when);
@@ -133,13 +134,6 @@ static struct pmu_sleep_notifier bmac_sleep_notifier = {
};
#endif
-#if 0
-/*
- * If we can't get a skbuff when we need it, we use this area for DMA.
- */
-static unsigned char dummy_buf[RX_BUFLEN];
-#endif
-
/*
* Number of bytes of private data per BMAC: allow enough for
* the rx and tx dma commands plus a branch dma command each,
@@ -151,6 +145,7 @@ static unsigned char dummy_buf[RX_BUFLEN];
+ sizeof(struct sk_buff_head))
static unsigned char bitrev(unsigned char b);
+static void bmac_probe1(struct device_node *bmac, int is_bmac_plus);
static int bmac_open(struct net_device *dev);
static int bmac_close(struct net_device *dev);
static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -192,9 +187,10 @@ dbdma_ld32(volatile unsigned long *a)
void
dbdma_stop(volatile struct dbdma_regs *dmap)
{
- dbdma_st32((volatile unsigned long *)&dmap->control, DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
+ dbdma_st32((volatile unsigned long *)&dmap->control,
+ DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
eieio();
-
+
while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH))
eieio();
}
@@ -210,10 +206,11 @@ dbdma_continue(volatile struct dbdma_regs *dmap)
static void
dbdma_reset(volatile struct dbdma_regs *dmap)
{
- dbdma_st32((volatile unsigned long *)&dmap->control,
- DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
+ dbdma_st32((volatile unsigned long *)&dmap->control,
+ DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
eieio();
- while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio();
+ while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN)
+ eieio();
}
static void
@@ -239,7 +236,7 @@ void bmwrite(struct net_device *dev, unsigned long reg_offset, unsigned data )
static __inline__
volatile unsigned short bmread(struct net_device *dev, unsigned long reg_offset )
{
- return in_le16((void *)dev->base_addr + reg_offset);
+ return in_le16((void *)dev->base_addr + reg_offset);
}
static void
@@ -248,7 +245,7 @@ bmac_reset_chip(struct net_device *dev)
struct bmac_data *bp = (struct bmac_data *) dev->priv;
volatile struct dbdma_regs *rd = bp->rx_dma;
volatile struct dbdma_regs *td = bp->tx_dma;
-
+
dbdma_reset(rd);
dbdma_reset(td);
@@ -349,7 +346,7 @@ bmac_init_registers(struct net_device *dev)
regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
} while ((regValue & TxResetBit) && i > 0);
- if (!is_bmac_plus) {
+ if (!bp->is_bmac_plus) {
regValue = bmread(dev, XCVRIF);
regValue |= ClkBit | SerialMode | COLActiveLow;
bmwrite(dev, XCVRIF, regValue);
@@ -385,7 +382,7 @@ bmac_init_registers(struct net_device *dev)
/* set rx fifo information */
bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */
- bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+ bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
//bmwrite(dev, TXCFG, TxMACEnable); /* TxNeverGiveUp maybe later */
bmread(dev, STATUS); /* read it just to clear it */
@@ -433,13 +430,13 @@ bmac_start_chip(struct net_device *dev)
/* enable rx dma channel */
dbdma_continue(rd);
-
+
oldConfig = bmread(dev, TXCFG);
- bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
-
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
/* turn on rx plus any other bits already on (promiscuous possibly) */
oldConfig = bmread(dev, RXCFG);
- bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
udelay(20000);
}
@@ -447,6 +444,7 @@ static void
bmac_init_phy(struct net_device *dev)
{
unsigned int addr;
+ struct bmac_data *bp = (struct bmac_data *) dev->priv;
printk(KERN_DEBUG "phy registers:");
for (addr = 0; addr < 32; ++addr) {
@@ -455,7 +453,7 @@ bmac_init_phy(struct net_device *dev)
printk(" %.4x", bmac_mif_read(dev, addr));
}
printk("\n");
- if (is_bmac_plus) {
+ if (bp->is_bmac_plus) {
unsigned int capable, ctrl;
ctrl = bmac_mif_read(dev, 0);
@@ -622,7 +620,8 @@ bmac_init_rx_ring(struct bmac_data *bp)
if (!bp->rx_allocated) {
for (i = 0; i < N_RX_RING; i++) {
bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
- if (bp->rx_bufs[i] == NULL) return 0;
+ if (bp->rx_bufs[i] == NULL)
+ return 0;
skb_reserve(bp->rx_bufs[i], 2);
}
bp->rx_allocated = 1;
@@ -657,9 +656,10 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
/* bp->tx_empty, bp->tx_fill)); */
i = bp->tx_fill + 1;
- if (i >= N_TX_RING) i = 0;
+ if (i >= N_TX_RING)
+ i = 0;
if (i == bp->tx_empty) {
- dev->tbusy = 1;
+ netif_stop_queue(dev);
bp->tx_fullup = 1;
XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
return -1; /* can't take it at the moment */
@@ -776,16 +776,15 @@ static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
if (bp->tx_bufs[bp->tx_empty]) {
++bp->stats.tx_packets;
- dev_kfree_skb(bp->tx_bufs[bp->tx_empty]);
+ dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]);
}
bp->tx_bufs[bp->tx_empty] = NULL;
bp->tx_fullup = 0;
- dev->tbusy = 0;
- /* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */
- /* i, bp->tx_fill)); */
- mark_bh(NET_BH);
- if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0;
- if (bp->tx_empty == bp->tx_fill) break;
+ netif_wake_queue(dev);
+ if (++bp->tx_empty >= N_TX_RING)
+ bp->tx_empty = 0;
+ if (bp->tx_empty == bp->tx_fill)
+ break;
}
restore_flags(flags);
@@ -831,7 +830,7 @@ crc416(unsigned int curval, unsigned short nxtval)
/* is high CRC bit set? */
if ((cur & 0x80000000) == 0) high_crc_set = 0;
else high_crc_set = 1;
-
+
cur = cur << 1;
if ((next & 0x0001) == 0) low_data_set = 0;
@@ -859,8 +858,8 @@ bmac_crc(unsigned short *address)
}
/*
- * Add requested mcast addr to BMac's hash table filter.
- *
+ * Add requested mcast addr to BMac's hash table filter.
+ *
*/
static void
@@ -925,7 +924,7 @@ bmac_rx_on(struct net_device *dev, int hash_enable, int promisc_enable)
else rx_cfg &= ~RxPromiscEnable;
bmwrite(dev, RXRST, RxResetValue);
bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */
- bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
+ bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
bmwrite(dev, RXCFG, rx_cfg );
return rx_cfg;
}
@@ -1020,13 +1019,7 @@ static void bmac_set_multicast(struct net_device *dev)
int i, j, bit, byte;
unsigned short rx_cfg;
u32 crc, poly = CRC_POLYNOMIAL_LE;
-
- /* Let the transmits drain. */
- /* while(dev->tbusy) schedule(); */
-
- /* Lock out others. */
- /* set_bit(0, (void *) &dev->tbusy); */
-
+
if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
bmwrite(dev, BHASH0, 0xffff);
bmwrite(dev, BHASH1, 0xffff);
@@ -1048,15 +1041,15 @@ static void bmac_set_multicast(struct net_device *dev)
for(i = 0; i < dev->mc_count; i++) {
addrs = dmi->dmi_addr;
dmi = dmi->next;
-
+
if(!(*addrs & 1))
continue;
-
+
crc = 0xffffffffU;
for(byte = 0; byte < 6; byte++) {
for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
int test;
-
+
test = ((bit ^ crc) & 0x01);
crc >>= 1;
if(test)
@@ -1071,9 +1064,6 @@ static void bmac_set_multicast(struct net_device *dev)
bmwrite(dev, BHASH2, hash_table[2]);
bmwrite(dev, BHASH3, hash_table[3]);
}
-
- /* Let us get going again. */
- /* dev->tbusy = 0; */
}
#endif /* SUNHME_MULTICAST */
@@ -1103,7 +1093,7 @@ static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
}
/*
- * Procedure for reading EEPROM
+ * Procedure for reading EEPROM
*/
#define SROMAddressLength 5
#define DataInOn 0x0008
@@ -1126,28 +1116,28 @@ bmac_clock_out_bit(struct net_device *dev)
bmwrite(dev, SROMCSR, ChipSelect | Clk);
udelay(DelayValue);
-
+
data = bmread(dev, SROMCSR);
udelay(DelayValue);
val = (data >> SD0ShiftCount) & 1;
bmwrite(dev, SROMCSR, ChipSelect);
udelay(DelayValue);
-
+
return val;
}
static void
bmac_clock_in_bit(struct net_device *dev, unsigned int val)
{
- unsigned short data;
+ unsigned short data;
if (val != 0 && val != 1) return;
-
+
data = (val << SDIShiftCount);
bmwrite(dev, SROMCSR, data | ChipSelect );
udelay(DelayValue);
-
+
bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
udelay(DelayValue);
@@ -1161,7 +1151,7 @@ reset_and_select_srom(struct net_device *dev)
/* first reset */
bmwrite(dev, SROMCSR, 0);
udelay(DelayValue);
-
+
/* send it the read command (110) */
bmac_clock_in_bit(dev, 1);
bmac_clock_in_bit(dev, 1);
@@ -1173,13 +1163,13 @@ read_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len)
{
unsigned short data, val;
int i;
-
+
/* send out the address we want to read from */
for (i = 0; i < addr_len; i++) {
val = addr >> (addr_len-i-1);
bmac_clock_in_bit(dev, val & 1);
}
-
+
/* Now read in the 16-bit data */
data = 0;
for (i = 0; i < 16; i++) {
@@ -1188,24 +1178,24 @@ read_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len)
data |= val;
}
bmwrite(dev, SROMCSR, 0);
-
+
return data;
}
/*
* It looks like Cogent and SMC use different methods for calculating
- * checksums. What a pain..
+ * checksums. What a pain..
*/
static int
bmac_verify_checksum(struct net_device *dev)
{
unsigned short data, storedCS;
-
+
reset_and_select_srom(dev);
data = read_srom(dev, 3, SROMAddressBits);
storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
-
+
return 0;
}
@@ -1236,8 +1226,10 @@ static int bmac_reset_and_enable(struct net_device *dev, int enable)
bp->reset_and_enabled = 0;
bmac_reset_chip(dev);
if (enable) {
- if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0;
- if (!bmac_init_chip(dev)) return 0;
+ if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp))
+ return 0;
+ if (!bmac_init_chip(dev))
+ return 0;
bmac_start_chip(dev);
bmwrite(dev, INTDISABLE, EnableNormal);
bp->reset_and_enabled = 1;
@@ -1257,70 +1249,55 @@ static int bmac_reset_and_enable(struct net_device *dev, int enable)
return 1;
}
-static int __init bmac_probe (void)
+static int __init bmac_probe(void)
{
- int j, rev;
- struct bmac_data *bp;
- struct device_node *bmacs;
- unsigned char *addr;
- static struct device_node *all_bmacs = NULL, *next_bmac;
- struct net_device *dev = NULL;
+ struct device_node *bmac;
-#ifdef MODULE
- if(bmac_devs != NULL)
- return -EBUSY;
-#endif
-
- if (all_bmacs == NULL) {
- all_bmacs = find_devices("bmac");
- is_bmac_plus = 0;
- if (all_bmacs == NULL) {
- all_bmacs = find_compatible_devices("network", "bmac+");
- if (all_bmacs)
- is_bmac_plus = 1;
- }
- next_bmac = all_bmacs;
- }
- bmacs = next_bmac;
- if (bmacs == NULL) return -ENODEV;
- next_bmac = bmacs->next;
+ for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next)
+ bmac_probe1(bmac, 0);
+ for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0;
+ bmac = bmac->next)
+ bmac_probe1(bmac, 1);
- if (bmac_devs == 0) {
- bmac_devs = dev; /* KLUDGE!! */
+ if (bmac_devs != 0) {
+ proc_net_create ("bmac", 0, bmac_proc_info);
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&bmac_sleep_notifier);
#endif
}
+ return 0;
+}
- if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) {
- printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n",
- bmacs->full_name);
- return -EINVAL;
+static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
+{
+ int j, rev;
+ struct bmac_data *bp;
+ unsigned char *addr;
+ struct net_device *dev;
+
+ if (bmac->n_addrs != 3 || bmac->n_intrs != 3) {
+ printk(KERN_ERR "can't use BMAC %s: need 3 addrs and 3 intrs\n",
+ bmac->full_name);
+ return;
+ }
+ addr = get_property(bmac, "mac-address", NULL);
+ if (addr == NULL) {
+ addr = get_property(bmac, "local-mac-address", NULL);
+ if (addr == NULL) {
+ printk(KERN_ERR "Can't get mac-address for BMAC %s\n",
+ bmac->full_name);
+ return;
+ }
}
dev = init_etherdev(NULL, PRIV_BYTES);
- bmac_devs = dev; /*KLUDGE!!*/
-#ifdef MODULE
- bmac_devs = dev;
-#endif
-
dev->base_addr = (unsigned long)
- ioremap(bmacs->addrs[0].address, bmacs->addrs[0].size);
- dev->irq = bmacs->intrs[0].line;
+ ioremap(bmac->addrs[0].address, bmac->addrs[0].size);
+ dev->irq = bmac->intrs[0].line;
bmwrite(dev, INTDISABLE, DisableAll);
-
- addr = get_property(bmacs, "mac-address", NULL);
- if (addr == NULL) {
- addr = get_property(bmacs, "local-mac-address", NULL);
- if (addr == NULL) {
- printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n",
- dev->base_addr);
- return -EAGAIN;
- }
- }
-
+
printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j) {
@@ -1329,7 +1306,7 @@ static int __init bmac_probe (void)
}
XXDEBUG((", base_addr=%#0lx", dev->base_addr));
printk("\n");
-
+
dev->open = bmac_open;
dev->stop = bmac_close;
dev->hard_start_xmit = bmac_output;
@@ -1338,61 +1315,55 @@ static int __init bmac_probe (void)
dev->set_mac_address = bmac_set_address;
bmac_get_station_address(dev, addr);
- if (bmac_verify_checksum(dev) != 0) return -EINVAL;
-
+ if (bmac_verify_checksum(dev) != 0)
+ return;
+
ether_setup(dev);
-
+
bp = (struct bmac_data *) dev->priv;
memset(bp, 0, sizeof(struct bmac_data));
+ bp->is_bmac_plus = is_bmac_plus;
bp->tx_dma = (volatile struct dbdma_regs *)
- ioremap(bmacs->addrs[1].address, bmacs->addrs[1].size);
- bp->tx_dma_intr = bmacs->intrs[1].line;
+ ioremap(bmac->addrs[1].address, bmac->addrs[1].size);
+ bp->tx_dma_intr = bmac->intrs[1].line;
bp->rx_dma = (volatile struct dbdma_regs *)
- ioremap(bmacs->addrs[2].address, bmacs->addrs[2].size);
- bp->rx_dma_intr = bmacs->intrs[2].line;
-
+ ioremap(bmac->addrs[2].address, bmac->addrs[2].size);
+ bp->rx_dma_intr = bmac->intrs[2].line;
+
bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
skb_queue_head_init(bp->queue);
-
- bp->node = bmacs;
+
+ bp->node = bmac;
memset(&bp->stats, 0, sizeof(bp->stats));
memset((char *) bp->tx_cmds, 0,
(N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
/* init_timer(&bp->tx_timeout); */
/* bp->timeout_active = 0; */
- if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) {
+ if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev))
printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
- return -EAGAIN;
- }
- if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
- dev)) {
- printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line);
- return -EAGAIN;
- }
- if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
- dev)) {
- printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line);
- return -EAGAIN;
- }
-
- if (!bmac_reset_and_enable(dev, 0)) return -ENOMEM;
-
- proc_net_create ("bmac", 0, bmac_proc_info);
-
- return 0;
+ if (request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
+ dev))
+ printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line);
+ if (request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
+ dev))
+ printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line);
+
+ bp->next_bmac = bmac_devs;
+ bmac_devs = dev;
}
static int bmac_open(struct net_device *dev)
{
/* XXDEBUG(("bmac: enter open\n")); */
/* reset the chip */
- bmac_reset_and_enable(dev, 1);
+ if (!bmac_reset_and_enable(dev, 1))
+ return -ENOMEM;
- dev->flags |= IFF_UP | IFF_RUNNING;
+ dev->flags |= IFF_RUNNING;
MOD_INC_USE_COUNT;
return 0;
@@ -1452,14 +1423,17 @@ bmac_start(struct net_device *dev)
int i;
struct sk_buff *skb;
unsigned long flags;
-
+
save_flags(flags); cli();
while (1) {
i = bp->tx_fill + 1;
- if (i >= N_TX_RING) i = 0;
- if (i == bp->tx_empty) break;
+ if (i >= N_TX_RING)
+ i = 0;
+ if (i == bp->tx_empty)
+ break;
skb = skb_dequeue(bp->queue);
- if (skb == NULL) break;
+ if (skb == NULL)
+ break;
bmac_transmit_packet(skb, dev);
}
restore_flags(flags);
@@ -1525,9 +1499,7 @@ static void bmac_tx_timeout(unsigned long data)
bp->tx_empty = i;
}
bp->tx_fullup = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
- XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n"));
+ netif_wake_queue(dev);
if (i != bp->tx_fill) {
cp = &bp->tx_cmds[i];
out_le16(&cp->xfer_status, 0);
@@ -1540,9 +1512,9 @@ static void bmac_tx_timeout(unsigned long data)
/* turn it back on */
oldConfig = bmread(dev, RXCFG);
- bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
+ bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
oldConfig = bmread(dev, TXCFG);
- bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
restore_flags(flags);
}
@@ -1573,7 +1545,8 @@ bmac_proc_info(char *buffer, char **start, off_t offset, int length)
off_t begin = 0;
int i;
- if (bmac_devs == NULL) return (-ENOSYS);
+ if (bmac_devs == NULL)
+ return (-ENOSYS);
len += sprintf(buffer, "BMAC counters & registers\n");
@@ -1582,20 +1555,20 @@ bmac_proc_info(char *buffer, char **start, off_t offset, int length)
reg_entries[i].name,
bmread(bmac_devs, reg_entries[i].reg_offset));
pos = begin + len;
-
+
if (pos < offset) {
len = 0;
begin = pos;
}
-
+
if (pos > offset+length) break;
}
-
+
*start = buffer + (offset - begin);
len -= (offset - begin);
-
+
if (len > length) len = length;
-
+
return len;
}
@@ -1606,26 +1579,28 @@ MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
static void __exit bmac_cleanup (void)
{
-#ifdef MODULE
- struct bmac_data *bp;
+ struct bmac_data *bp;
+ struct net_device *dev;
- if (bmac_devs == 0)
- return;
+ if (bmac_devs == 0)
+ return;
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
+#endif
+ proc_net_remove("bmac");
- bp = (struct bmac_data *) bmac_devs->priv;
- unregister_netdev(bmac_devs);
- proc_net_remove("bmac");
+ do {
+ dev = bmac_devs;
+ bp = (struct bmac_data *) dev->priv;
+ bmac_devs = bp->next_bmac;
- free_irq(bmac_devs->irq, bmac_misc_intr);
- free_irq(bp->tx_dma_intr, bmac_txdma_intr);
- free_irq(bp->rx_dma_intr, bmac_rxdma_intr);
+ free_irq(dev->irq, dev);
+ free_irq(bp->tx_dma_intr, dev);
+ free_irq(bp->rx_dma_intr, dev);
-#ifdef CONFIG_PMAC_PBOOK
- pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
-#endif
- kfree(bmac_devs);
- bmac_devs = NULL;
-#endif
+ unregister_netdev(dev);
+ kfree(dev);
+ } while (bmac_devs != NULL);
}
module_init(bmac_probe);
diff --git a/drivers/net/cops.c b/drivers/net/cops.c
index c15a1937c..466705f9e 100644
--- a/drivers/net/cops.c
+++ b/drivers/net/cops.c
@@ -30,6 +30,7 @@
* cleanup of formatting and program
* logic. Added emacs 'local-vars'
* setup for Jay's brace style.
+ * 20000211 Alan Cox Cleaned up for softnet
*/
static const char *version =
@@ -48,10 +49,8 @@ static const char *version =
*/
#include <linux/config.h>
-#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
-#endif
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -180,7 +179,7 @@ static unsigned int cops_debug = COPS_DEBUG;
struct cops_local
{
- struct enet_statistics stats;
+ struct net_device_stats stats;
int board; /* Holds what board type is. */
int nodeid; /* Set to 1 once have nodeid. */
unsigned char node_acquire; /* Node ID when acquired. */
@@ -200,6 +199,7 @@ static int cops_nodeid (struct net_device *dev, int nodeid);
static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
static void cops_poll (unsigned long ltdev);
+static void cops_timeout(struct net_device *dev);
static void cops_rx (struct net_device *dev);
static int cops_send_packet (struct sk_buff *skb, struct net_device *dev);
static void set_multicast_list (struct net_device *dev);
@@ -209,7 +209,7 @@ static int cops_hard_header (struct sk_buff *skb, struct net_device *dev,
static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static int cops_close (struct net_device *dev);
-static struct enet_statistics *cops_get_stats (struct net_device *dev);
+static struct net_device_stats *cops_get_stats (struct net_device *dev);
/*
@@ -323,13 +323,15 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr)
/* Fill in the fields of the device structure with LocalTalk values. */
ltalk_setup(dev);
- dev->hard_start_xmit = &cops_send_packet;
+ dev->hard_start_xmit = cops_send_packet;
+ dev->tx_timeout = cops_timeout;
+ dev->watchdog_timeo = HZ * 2;
dev->hard_header = cops_hard_header;
dev->get_stats = cops_get_stats;
dev->open = cops_open;
dev->stop = cops_close;
- dev->do_ioctl = &cops_ioctl;
- dev->set_multicast_list = &set_multicast_list;
+ dev->do_ioctl = cops_ioctl;
+ dev->set_multicast_list = set_multicast_list;
dev->mc_list = NULL;
/* Tell the user where the card is and what mode we're in. */
@@ -424,10 +426,7 @@ static int cops_open(struct net_device *dev)
cops_jumpstart(dev); /* Start the card up. */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
@@ -501,8 +500,7 @@ static void cops_reset(struct net_device *dev, int sleep)
else
udelay(333333);
}
- dev->tbusy=0;
-
+ netif_wake_queue(dev);
return;
}
@@ -673,6 +671,7 @@ static int cops_nodeid (struct net_device *dev, int nodeid)
/*
* Poll the Tangent type cards to see if we have work.
*/
+
static void cops_poll(unsigned long ltdev)
{
int ioaddr, status;
@@ -691,7 +690,7 @@ static void cops_poll(unsigned long ltdev)
if(status & TANG_RX_READY)
cops_rx(dev);
if(status & TANG_TX_READY)
- dev->tbusy = 0;
+ netif_wake_queue(dev);
status = inb(ioaddr+TANG_CARD_STATUS);
} while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
@@ -712,14 +711,6 @@ static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
int ioaddr, status;
int boguscount = 0;
- if(dev == NULL)
- {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
- cardname, irq);
- return;
- }
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
lp = (struct cops_local *)dev->priv;
@@ -730,8 +721,7 @@ static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
status=inb(ioaddr+DAYNA_CARD_STATUS);
if((status&0x03)==DAYNA_RX_REQUEST)
cops_rx(dev);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
} while(++boguscount < 20);
}
else
@@ -741,13 +731,11 @@ static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if(status & TANG_RX_READY)
cops_rx(dev);
if(status & TANG_TX_READY)
- dev->tbusy = 0;
+ netif_wake_queue(dev);
status=inb(ioaddr+TANG_CARD_STATUS);
- } while((++boguscount < 20) &&
- (status&(TANG_RX_READY|TANG_TX_READY)));
+ } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));
}
- dev->interrupt = 0;
return;
}
@@ -762,7 +750,10 @@ static void cops_rx(struct net_device *dev)
struct cops_local *lp = (struct cops_local *)dev->priv;
int ioaddr = dev->base_addr;
int boguscount = 0;
+ unsigned long flags;
+
+ save_flags(flags);
cli(); /* Disable interrupts. */
if(lp->board==DAYNA)
@@ -798,7 +789,7 @@ static void cops_rx(struct net_device *dev)
skb = dev_alloc_skb(pkt_len);
if(skb == NULL)
{
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+ printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",
dev->name);
lp->stats.rx_dropped++;
while(pkt_len--) /* Discard packet */
@@ -814,12 +805,12 @@ static void cops_rx(struct net_device *dev)
if(lp->board==DAYNA)
outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card */
- sti(); /* Restore interrupts. */
+ restore_flags(flags); /* Restore interrupts. */
/* Check for bad response length */
if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)
{
- printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n",
+ printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n",
dev->name, pkt_len);
lp->stats.tx_errors++;
kfree_skb(skb);
@@ -837,7 +828,7 @@ static void cops_rx(struct net_device *dev)
/* One last check to make sure we have a good packet. */
if(rsp_type != LAP_RESPONSE)
{
- printk("%s: Bad packet type %d.\n", dev->name, rsp_type);
+ printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
lp->stats.tx_errors++;
kfree_skb(skb);
return;
@@ -857,79 +848,72 @@ static void cops_rx(struct net_device *dev)
return;
}
+static void cops_timeout(struct net_device *dev)
+{
+ struct cops_local *lp = (struct cops_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ lp->stats.tx_errors++;
+ if(lp->board==TANGENT)
+ {
+ if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
+ printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
+ }
+ printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
+ cops_jumpstart(dev); /* Restart the card. */
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+
/*
* Make the card transmit a LocalTalk packet.
*/
+
static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct cops_local *lp = (struct cops_local *)dev->priv;
int ioaddr = dev->base_addr;
-
- if(dev->tbusy)
- {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- int tickssofar = jiffies - dev->trans_start;
- if(tickssofar < 5)
- return 1;
- lp->stats.tx_errors++;
- if(lp->board==TANGENT)
- {
- if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
- printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
- }
- printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
- cops_jumpstart(dev); /* Restart the card. */
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
+ unsigned long flags;
/*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+ * Block a timer-based transmit from overlapping.
*/
- if(test_and_set_bit(0, (void*) &dev->tbusy) != 0)
- printk(KERN_WARNING "%s: Transmitter access conflict.\n",
- dev->name);
- else
- {
- cli(); /* Disable interrupts. */
- if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */
- while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
- if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
- while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0);
-
- /* Output IO length. */
- outb(skb->len, ioaddr);
- if(lp->board == DAYNA)
- outb(skb->len >> 8, ioaddr);
- else
- outb((skb->len >> 8)&0x0FF, ioaddr);
-
- /* Output IO code. */
- outb(LAP_WRITE, ioaddr);
+
+ netif_stop_queue(dev);
+
+ save_flags(flags);
+ cli(); /* Disable interrupts. */
+ if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */
+ while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+ if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */
+ while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0);
+
+ /* Output IO length. */
+ outb(skb->len, ioaddr);
+ if(lp->board == DAYNA)
+ outb(skb->len >> 8, ioaddr);
+ else
+ outb((skb->len >> 8)&0x0FF, ioaddr);
- if(lp->board == DAYNA) /* Check the transmit buffer again. */
- while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+ /* Output IO code. */
+ outb(LAP_WRITE, ioaddr);
- outsb(ioaddr, skb->data, skb->len); /* Send out the data. */
+ if(lp->board == DAYNA) /* Check the transmit buffer again. */
+ while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
- if(lp->board==DAYNA) /* Dayna requires you kick the card */
- outb(1, ioaddr+DAYNA_INT_CARD);
+ outsb(ioaddr, skb->data, skb->len); /* Send out the data. */
- sti(); /* Restore interrupts. */
+ if(lp->board==DAYNA) /* Dayna requires you kick the card */
+ outb(1, ioaddr+DAYNA_INT_CARD);
- /* Done sending packet, update counters and cleanup. */
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += skb->len;
- dev->trans_start = jiffies;
- }
+ restore_flags(flags); /* Restore interrupts. */
+ /* Done sending packet, update counters and cleanup. */
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += skb->len;
+ dev->trans_start = jiffies;
dev_kfree_skb (skb);
- dev->tbusy = 0;
-
return 0;
}
@@ -1005,9 +989,7 @@ static int cops_close(struct net_device *dev)
if(lp->board==TANGENT && dev->irq==0)
del_timer(&cops_timer);
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
@@ -1019,7 +1001,7 @@ static int cops_close(struct net_device *dev)
* Get the current statistics.
* This may be called with the card open or closed.
*/
-static struct enet_statistics *cops_get_stats(struct net_device *dev)
+static struct net_device_stats *cops_get_stats(struct net_device *dev)
{
struct cops_local *lp = (struct cops_local *)dev->priv;
return &lp->stats;
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index ac6ff986c..01dd799b3 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -120,6 +120,7 @@ static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void set_multicast_list(struct net_device *dev);
+static void net_timeout(struct net_device *dev);
static void net_rx(struct net_device *dev);
static int net_close(struct net_device *dev);
static struct net_device_stats *net_get_stats(struct net_device *dev);
@@ -139,14 +140,8 @@ static int set_mac_address(struct net_device *dev, void *addr);
If dev->base_addr == 2, allocate space for the device and return success
(detachable devices only).
*/
-#ifdef HAVE_DEVLIST
-/* Support for a alternate probe manager, which will eliminate the
- boilerplate below. */
-struct netdev_entry netcard_drv =
-{"netcard", cs89x0_probe1, NETCARD_IO_EXTENT, netcard_portlist};
-#else
-int __init
-cs89x0_probe(struct net_device *dev)
+
+int __init cs89x0_probe(struct net_device *dev)
{
int i;
int base_addr = dev ? dev->base_addr : 0;
@@ -166,37 +161,31 @@ cs89x0_probe(struct net_device *dev)
printk("cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n");
return ENODEV;
}
-#endif
-static int inline
-readreg(struct net_device *dev, int portno)
+extern int inline readreg(struct net_device *dev, int portno)
{
outw(portno, dev->base_addr + ADD_PORT);
return inw(dev->base_addr + DATA_PORT);
}
-static void inline
-writereg(struct net_device *dev, int portno, int value)
+extern void inline writereg(struct net_device *dev, int portno, int value)
{
outw(portno, dev->base_addr + ADD_PORT);
outw(value, dev->base_addr + DATA_PORT);
}
-static int inline
-readword(struct net_device *dev, int portno)
+extern int inline readword(struct net_device *dev, int portno)
{
return inw(dev->base_addr + portno);
}
-static void inline
-writeword(struct net_device *dev, int portno, int value)
+extern void inline writeword(struct net_device *dev, int portno, int value)
{
outw(value, dev->base_addr + portno);
}
-static int __init
-wait_eeprom_ready(struct net_device *dev)
+static int __init wait_eeprom_ready(struct net_device *dev)
{
int timeout = jiffies;
/* check to see if the EEPROM is ready, a timeout is used -
@@ -208,8 +197,7 @@ wait_eeprom_ready(struct net_device *dev)
return 0;
}
-static int __init
-get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
+static int __init get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
{
int i;
@@ -226,8 +214,7 @@ get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
return 0;
}
-static int __init
-get_eeprom_cksum(int off, int len, int *buffer)
+static int __init get_eeprom_cksum(int off, int len, int *buffer)
{
int i, cksum;
@@ -378,10 +365,12 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)
dev->open = net_open;
dev->stop = net_close;
- dev->hard_start_xmit = net_send_packet;
- dev->get_stats = net_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- dev->set_mac_address = &set_mac_address;
+ dev->tx_timeout = net_timeout;
+ dev->watchdog_timeo = HZ;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->set_mac_address = set_mac_address;
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
@@ -720,85 +709,69 @@ net_open(struct net_device *dev)
/* now that we've got our act together, enable everything */
writereg(dev, PP_BusCTL, ENABLE_IRQ
);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
MOD_INC_USE_COUNT;
+ netif_start_queue(dev);
return 0;
}
-static int
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void net_timeout(struct net_device *dev)
{
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict ?" : "network cable problem");
- /* Try to restart the adaptor. */
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
+ /* If we get here, some higher level has decided we are broken.
+ There should really be a "kick me" function call instead. */
+ if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
+ tx_done(dev) ? "IRQ conflict ?" : "network cable problem");
+ /* Try to restart the adaptor. */
+ netif_wake_queue(dev);
+}
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- struct net_local *lp = (struct net_local *)dev->priv;
- short ioaddr = dev->base_addr;
- unsigned long flags;
-
- if (net_debug > 3)printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
-
- /* keep the upload from being interrupted, since we
- ask the chip to start transmitting before the
- whole packet has been completely uploaded. */
- save_flags(flags);
- cli();
-
- /* initiate a transmit sequence */
- outw(lp->send_cmd, ioaddr + TX_CMD_PORT);
- outw(skb->len, ioaddr + TX_LEN_PORT);
-
- /* Test to see if the chip has allocated memory for the packet */
- if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
- /* Gasp! It hasn't. But that shouldn't happen since
- we're waiting for TxOk, so return 1 and requeue this packet. */
- restore_flags(flags);
- return 1;
- }
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ short ioaddr = dev->base_addr;
+ unsigned long flags;
+
+ if (net_debug > 3)
+ printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
+
+ /* keep the upload from being interrupted, since we
+ ask the chip to start transmitting before the
+ whole packet has been completely uploaded. */
- /* Write the contents of the packet */
- outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+ save_flags(flags);
+ cli();
+ netif_stop_queue(dev);
+
+ /* initiate a transmit sequence */
+ outw(lp->send_cmd, ioaddr + TX_CMD_PORT);
+ outw(skb->len, ioaddr + TX_LEN_PORT);
+ /* Test to see if the chip has allocated memory for the packet */
+ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+ /* Gasp! It hasn't. But that shouldn't happen since
+ we're waiting for TxOk, so return 1 and requeue this packet. */
restore_flags(flags);
- dev->trans_start = jiffies;
+ return 1;
}
- dev_kfree_skb (skb);
+ /* Write the contents of the packet */
+ outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
+ restore_flags(flags);
+ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+ netif_wake_queue(dev);
+
return 0;
}
/* The typical workload of the driver:
Handle the network interface interrupts. */
+
static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status;
- if (dev == NULL) {
- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
@@ -818,8 +791,7 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
break;
case ISQ_TRANSMITTER_EVENT:
lp->stats.tx_packets++;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
if ((status & TX_OK) == 0) lp->stats.tx_errors++;
if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
@@ -833,8 +805,7 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
That shouldn't happen since we only ever
load one packet. Shrug. Do the right
thing anyway. */
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & TX_UNDERRUN) {
if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
@@ -846,8 +817,7 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
avoids having to wait for the upper
layers to timeout on us, in the
event of a tx underrun */
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
}
break;
case ISQ_RX_MISS_EVENT:
@@ -858,8 +828,6 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
break;
}
}
- dev->interrupt = 0;
- return;
}
/* We have a good packet(s), get it/them out of the buffers. */
@@ -913,14 +881,13 @@ net_rx(struct net_device *dev)
static int
net_close(struct net_device *dev)
{
-
+ netif_stop_queue(dev);
+
writereg(dev, PP_RxCFG, 0);
writereg(dev, PP_TxCFG, 0);
writereg(dev, PP_BufCFG, 0);
writereg(dev, PP_BusCTL, 0);
- dev->start = 0;
-
free_irq(dev->irq, dev);
/* Update the statistics here. */
@@ -974,7 +941,7 @@ static void set_multicast_list(struct net_device *dev)
static int set_mac_address(struct net_device *dev, void *addr)
{
int i;
- if (dev->start)
+ if (netif_running(dev))
return -EBUSY;
printk("%s: Setting MAC address to ", dev->name);
for (i = 0; i < 6; i++)
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index 7bb5b9796..81e0dbdae 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -458,6 +458,9 @@ static const char *version = "de4x5.c:V0.545 1999/11/28 davies@maniac.ultranet.c
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC
+#include <asm/machdep.h>
+#endif /* CONFIG_PPC */
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -1558,15 +1561,14 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
return -1;
/* Transmit descriptor ring full or stale skb */
- if (test_bit(LINK_STATE_XOFF, &dev->state) ||
- (u_long) lp->tx_skb[lp->tx_new] > 1) {
+ if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) {
if (lp->interrupt) {
de4x5_putb_cache(dev, skb); /* Requeue the buffer */
} else {
de4x5_put_cache(dev, skb);
}
if (de4x5_debug & DEBUG_TX) {
- printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), test_bit(LINK_STATE_XOFF, &dev->state), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO");
+ printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), netif_queue_stopped(dev), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO");
}
} else if (skb->len > 0) {
/* If we already have stuff queued locally, use that first */
@@ -1575,7 +1577,8 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
skb = de4x5_get_cache(dev);
}
- while (skb && !test_bit(LINK_STATE_XOFF, &dev->state) && (u_long) lp->tx_skb[lp->tx_new] <= 1) {
+ while (skb && !netif_queue_stopped(dev) &&
+ (u_long) lp->tx_skb[lp->tx_new] <= 1) {
spin_lock_irqsave(&lp->lock, flags);
netif_stop_queue(dev);
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
@@ -1663,7 +1666,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* Load the TX ring with any locally stored packets */
if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
- while (lp->cache.skb && !test_bit(LINK_STATE_XOFF, &dev->state) && lp->tx_enable) {
+ while (lp->cache.skb && !netif_queue_stopped(dev) && lp->tx_enable) {
de4x5_queue_pkt(de4x5_get_cache(dev), dev);
}
lp->cache.lock = 0;
@@ -1756,9 +1759,10 @@ static inline void
de4x5_free_tx_buff(struct de4x5_private *lp, int entry)
{
pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf),
- le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1);
+ le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1,
+ PCI_DMA_TODEVICE);
if ((u_long) lp->tx_skb[entry] > 1)
- dev_kfree_skb(lp->tx_skb[entry]);
+ dev_kfree_skb_irq(lp->tx_skb[entry]);
lp->tx_skb[entry] = NULL;
}
@@ -1807,7 +1811,7 @@ de4x5_tx(struct net_device *dev)
}
/* Any resources available? */
- if (TX_BUFFS_AVAIL && test_bit(LINK_STATE_XOFF, &dev->state)) {
+ if (TX_BUFFS_AVAIL && netif_queue_stopped(dev)) {
if (lp->interrupt)
netif_wake_queue(dev);
else
@@ -1977,7 +1981,7 @@ load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1);
- dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1);
+ dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1, PCI_DMA_TODEVICE);
lp->tx_ring[lp->tx_new].buf = cpu_to_le32(buf_dma);
lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
@@ -4186,20 +4190,24 @@ get_hw_addr(struct net_device *dev)
/* If possible, try to fix a broken card - SMC only so far */
srom_repair(dev, broken);
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
/*
** If the address starts with 00 a0, we have to bit-reverse
** each byte of the address.
*/
- if (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0xa0) {
- for (i = 0; i < ETH_ALEN; ++i) {
- int x = dev->dev_addr[i];
- x = ((x & 0xf) << 4) + ((x & 0xf0) >> 4);
- x = ((x & 0x33) << 2) + ((x & 0xcc) >> 2);
- dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
- }
+ if ( (ppc_md.ppc_machine & _MACH_Pmac) &&
+ (dev->dev_addr[0] == 0) &&
+ (dev->dev_addr[1] == 0xa0) )
+ {
+ for (i = 0; i < ETH_ALEN; ++i)
+ {
+ int x = dev->dev_addr[i];
+ x = ((x & 0xf) << 4) + ((x & 0xf0) >> 4);
+ x = ((x & 0x33) << 2) + ((x & 0xcc) >> 2);
+ dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
+ }
}
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
/* Test for a bad enet address */
status = test_bad_enet(dev, status);
@@ -5599,18 +5607,19 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case DE4X5_SET_HWADDR: /* Set the hardware address */
if (!capable(CAP_NET_ADMIN)) return -EPERM;
if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT;
+ if (netif_queue_stopped(dev))
+ return -EBUSY;
+ netif_stop_queue(dev);
for (i=0; i<ETH_ALEN; i++) {
dev->dev_addr[i] = tmp.addr[i];
}
build_setup_frame(dev, PHYS_ADDR_ONLY);
/* Set up the descriptor and give ownership to the card */
- while (test_and_set_bit(LINK_STATE_XOFF, &dev->state) != 0)
- barrier();
load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, (struct sk_buff *)1);
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
- netif_start_queue(dev); /* Unlock the TX ring */
+ netif_wake_queue(dev); /* Unlock the TX ring */
break;
case DE4X5_SET_PROM: /* Set Promiscuous Mode */
@@ -5762,7 +5771,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
tmp.addr[j++] = lp->txRingSize;
- tmp.addr[j++] = test_bit(LINK_STATE_XOFF, &dev->state);
+ tmp.addr[j++] = netif_queue_stopped(dev);
ioc->len = j;
if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index 1805ae5f3..075f19cb8 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -348,7 +348,6 @@ de600_open(struct net_device *dev)
}
MOD_INC_USE_COUNT;
- dev->start = 1;
if (adapter_init(dev)) {
return 1;
}
@@ -369,9 +368,8 @@ de600_close(struct net_device *dev)
de600_put_command(0);
select_prn();
- if (dev->start) {
+ if (netif_running(dev)) { /* perhaps not needed? */
free_irq(DE600_IRQ, dev);
- dev->start = 0;
MOD_DEC_USE_COUNT;
}
return 0;
@@ -400,6 +398,7 @@ trigger_interrupt(struct net_device *dev)
static int
de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ unsigned long flags;
int transmit_from;
int len;
int tickssofar;
@@ -429,6 +428,7 @@ de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ((len = skb->len) < RUNT)
len = RUNT;
+ save_flags(flags);
cli();
select_nic();
tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
@@ -440,7 +440,7 @@ de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
de600_read_byte(READ_DATA, dev);
if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
if (adapter_init(dev)) {
- sti();
+ restore_flags(flags);
return 1;
}
}
@@ -452,17 +452,20 @@ de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
dev->trans_start = jiffies;
- dev->tbusy = 0; /* allow more packets into adapter */
+ netif_start_queue(dev); /* allow more packets into adapter */
/* Send page and generate a faked interrupt */
de600_setup_address(transmit_from, TX_ADDR);
de600_put_command(TX_ENABLE);
}
else {
- dev->tbusy = !free_tx_pages;
+ if (free_tx_pages)
+ netif_start_queue(dev);
+ else
+ netif_stop_queue(dev);
select_prn();
}
- sti(); /* interrupts back on */
+ restore_flags(flags);
#ifdef FAKE_SMALL_MAX
/* This will "patch" the socket TCP proto at an early moment */
@@ -489,12 +492,11 @@ de600_interrupt(int irq, void *dev_id, struct pt_regs * regs)
int boguscount = 0;
/* This might just as well be deleted now, no crummy drivers present :-) */
- if ((dev == NULL) || (dev->start == 0) || (DE600_IRQ != irq)) {
+ if ((dev == NULL) || (DE600_IRQ != irq)) {
printk("%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq);
return;
}
- dev->interrupt = 1;
select_nic();
irq_status = de600_read_status(dev);
@@ -521,13 +523,11 @@ de600_interrupt(int irq, void *dev_id, struct pt_regs * regs)
*/
/* Enable adapter interrupts */
- dev->interrupt = 0;
select_prn();
if (retrig)
trigger_interrupt(dev);
- sti();
return;
}
@@ -538,7 +538,6 @@ de600_tx_intr(struct net_device *dev, int irq_status)
* Returns 1 if tx still not done
*/
- mark_bh(NET_BH);
/* Check if current transmission is done yet */
if (irq_status & TX_BUSY)
return 1; /* tx not done, try again */
@@ -549,7 +548,7 @@ de600_tx_intr(struct net_device *dev, int irq_status)
tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
++free_tx_pages;
((struct net_device_stats *)(dev->priv))->tx_packets++;
- dev->tbusy = 0;
+ netif_wake_queue(dev);
}
/* More to send, or resend last packet? */
@@ -571,12 +570,15 @@ static void
de600_rx_intr(struct net_device *dev)
{
struct sk_buff *skb;
+ unsigned long flags;
int i;
int read_from;
int size;
register unsigned char *buffer;
+ save_flags(flags);
cli();
+
/* Get size of received packet */
size = de600_read_byte(RX_LEN, dev); /* low byte */
size += (de600_read_byte(RX_LEN, dev) << 8); /* high byte */
@@ -586,7 +588,8 @@ de600_rx_intr(struct net_device *dev)
read_from = rx_page_adr();
next_rx_page();
de600_put_command(RX_ENABLE);
- sti();
+
+ restore_flags(flags);
if ((size < 32) || (size > 1535)) {
printk("%s: Bogus packet size %d.\n", dev->name, size);
@@ -596,7 +599,7 @@ de600_rx_intr(struct net_device *dev)
}
skb = dev_alloc_skb(size+2);
- sti();
+ restore_flags(flags);
if (skb == NULL) {
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, size);
@@ -738,7 +741,7 @@ adapter_init(struct net_device *dev)
de600_close(dev);
#endif /* SHUTDOWN_WHEN_LOST */
was_down = 1;
- dev->tbusy = 1; /* Transmit busy... */
+ netif_stop_queue(dev); /* Transmit busy... */
restore_flags(flags);
return 1; /* failed */
}
@@ -748,8 +751,7 @@ adapter_init(struct net_device *dev)
was_down = 0;
}
- dev->tbusy = 0; /* Transmit busy... */
- dev->interrupt = 0;
+ netif_start_queue(dev);
tx_fifo_in = 0;
tx_fifo_out = 0;
free_tx_pages = TX_PAGES;
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 3f138239f..440ac9951 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -435,19 +435,18 @@ de620_get_register(struct net_device *dev, byte reg)
* there is a non-reboot way to recover if something goes wrong.
*
*/
-static int
-de620_open(struct net_device *dev)
+static int de620_open(struct net_device *dev)
{
if (request_irq(dev->irq, de620_interrupt, 0, "de620", dev)) {
- printk ("%s: unable to get IRQ %d\n", dev->name, dev->irq);
+ printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
return 1;
}
- MOD_INC_USE_COUNT;
- if (adapter_init(dev)) {
+ if (adapter_init(dev))
return 1;
- }
- dev->start = 1;
+
+ MOD_INC_USE_COUNT;
+ netif_start_queue(dev);
return 0;
}
@@ -456,15 +455,13 @@ de620_open(struct net_device *dev)
* The inverse routine to de620_open().
*
*/
-static int
-de620_close(struct net_device *dev)
+
+static int de620_close(struct net_device *dev)
{
+ netif_stop_queue(dev);
/* disable recv */
de620_set_register(dev, W_TCR, RXOFF);
-
free_irq(dev->irq, dev);
-
- dev->start = 0;
MOD_DEC_USE_COUNT;
return 0;
}
@@ -506,38 +503,37 @@ static void de620_set_multicast_list(struct net_device *dev)
}
/*******************************************************
+ *
+ * Handle timeouts on transmit
+ */
+
+static void de620_timeout(struct net_device *dev)
+{
+ printk("%s: transmit timed out, %s?\n",
+ dev->name,
+ "network cable problem"
+ );
+ /* Restart the adapter. */
+ if (!adapter_init(dev)) /* maybe close it */
+ netif_wake_queue(dev);
+}
+
+/*******************************************************
*
* Copy a buffer to the adapter transmit page memory.
* Start sending.
*/
-static int
-de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
int len;
- int tickssofar;
byte *buffer = skb->data;
byte using_txbuf;
using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
- dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */
-
- if (dev->tbusy) { /* Do timeouts, to avoid hangs. */
- tickssofar = jiffies - dev->trans_start;
-
- if (tickssofar < 5)
- return 1;
-
- /* else */
- printk("%s: transmit timed out (%d), %s?\n",
- dev->name,
- tickssofar,
- "network cable problem"
- );
- /* Restart the adapter. */
- if (adapter_init(dev)) /* maybe close it */
- return 1;
- }
+
+ netif_stop_queue(dev);
+
if ((len = skb->len) < RUNT)
len = RUNT;
@@ -565,7 +561,7 @@ de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
break;
case (TXBF0 | TXBF1): /* NONE!!! */
- printk("de620: Ouch! No tx-buffer available!\n");
+ printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name);
restore_flags(flags);
return 1;
break;
@@ -573,14 +569,12 @@ de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
de620_write_block(dev, buffer, len);
dev->trans_start = jiffies;
- dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */
+ if(!(using_txbuf == (TXBF0 | TXBF1)))
+ netif_wake_queue(dev);
((struct net_device_stats *)(dev->priv))->tx_packets++;
-
restore_flags(flags); /* interrupts maybe back on */
-
dev_kfree_skb (skb);
-
return 0;
}
@@ -589,8 +583,7 @@ de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
* Handle the network interface interrupts.
*
*/
-static void
-de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
+static void de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
byte irq_status;
@@ -603,9 +596,6 @@ de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
return;
}
- cli();
- dev->interrupt = 1;
-
/* Read the status register (_not_ the status port) */
irq_status = de620_get_register(dev, R_STS);
@@ -619,11 +609,8 @@ de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
while (again && (++bogus_count < 100));
}
- dev->tbusy = (de620_tx_buffs(dev) == (TXBF0 | TXBF1)); /* Boolean! */
-
- dev->interrupt = 0;
- sti();
- return;
+ if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
+ netif_wake_queue(dev);
}
/**************************************
@@ -633,8 +620,7 @@ de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
* Send it "upstairs"
*
*/
-static int
-de620_rx_intr(struct net_device *dev)
+static int de620_rx_intr(struct net_device *dev)
{
struct header_buf {
byte status;
@@ -663,9 +649,10 @@ de620_rx_intr(struct net_device *dev)
pagelink = header_buf.Rx_NextPage;
if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
/* Ouch... Forget it! Skip all and start afresh... */
- printk("%s: Ring overrun? Restoring...\n", dev->name);
+ printk(KERN_WARNING "%s: Ring overrun? Restoring...\n", dev->name);
/* You win some, you lose some. And sometimes plenty... */
adapter_init(dev);
+ netif_wake_queue(dev);
((struct net_device_stats *)(dev->priv))->rx_over_errors++;
return 0;
}
@@ -682,7 +669,7 @@ de620_rx_intr(struct net_device *dev)
/* Is the _computed_ next page number equal to what the adapter says? */
if (pagelink != header_buf.Rx_NextPage) {
/* Naah, we'll skip this packet. Probably bogus data as well */
- printk("%s: Page link out of sync! Restoring...\n", dev->name);
+ printk(KERN_WARNING "%s: Page link out of sync! Restoring...\n", dev->name);
next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
de620_send_command(dev, W_DUMMY);
de620_set_register(dev, W_NPRF, next_rx_page);
@@ -693,12 +680,12 @@ de620_rx_intr(struct net_device *dev)
size = header_buf.Rx_ByteCount - 4;
if ((size < RUNT) || (GIANT < size)) {
- printk("%s: Illegal packet size: %d!\n", dev->name, size);
+ printk(KERN_WARNING "%s: Illegal packet size: %d!\n", dev->name, size);
}
else { /* Good packet? */
skb = dev_alloc_skb(size+2);
if (skb == NULL) { /* Yeah, but no place to put it... */
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+ printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, size);
((struct net_device_stats *)(dev->priv))->rx_dropped++;
}
@@ -732,8 +719,7 @@ de620_rx_intr(struct net_device *dev)
* Reset the adapter to a known state
*
*/
-static int
-adapter_init(struct net_device *dev)
+static int adapter_init(struct net_device *dev)
{
int i;
static int was_down = 0;
@@ -787,11 +773,11 @@ adapter_init(struct net_device *dev)
/* ignore: EEDI RXGOOD COLS LNKS*/
if (((i = de620_get_register(dev, R_STS)) & CHECK_MASK) != CHECK_OK) {
- printk("Something has happened to the DE-620! Please check it"
+ printk(KERN_ERR "%s: Something has happened to the DE-620! Please check it"
#ifdef SHUTDOWN_WHEN_LOST
" and do a new ifconfig"
#endif
- "! (%02x)\n", i);
+ "! (%02x)\n", dev->name, i);
#ifdef SHUTDOWN_WHEN_LOST
/* Goodbye, cruel world... */
dev->flags &= ~IFF_UP;
@@ -801,7 +787,7 @@ adapter_init(struct net_device *dev)
return 1; /* failed */
}
if (was_down) {
- printk("Thanks, I feel much better now!\n");
+ printk(KERN_WARNING "%s: Thanks, I feel much better now!\n", dev->name);
was_down = 0;
}
@@ -820,8 +806,7 @@ adapter_init(struct net_device *dev)
*
* Check if there is a DE-620 connected
*/
-int __init
-de620_probe(struct net_device *dev)
+int __init de620_probe(struct net_device *dev)
{
static struct net_device_stats de620_netstats;
int i;
@@ -837,7 +822,7 @@ de620_probe(struct net_device *dev)
if (de620_debug)
printk(version);
- printk("D-Link DE-620 pocket adapter");
+ printk(KERN_INFO "D-Link DE-620 pocket adapter");
/* Initially, configure basic nibble mode, so we can read the EEPROM */
NIC_Cmd = DEF_NIC_CMD;
@@ -880,11 +865,14 @@ de620_probe(struct net_device *dev)
dev->priv = &de620_netstats;
memset(dev->priv, 0, sizeof(struct net_device_stats));
- dev->get_stats = get_stats;
- dev->open = de620_open;
- dev->stop = de620_close;
- dev->hard_start_xmit = &de620_start_xmit;
- dev->set_multicast_list = &de620_set_multicast_list;
+ dev->get_stats = get_stats;
+ dev->open = de620_open;
+ dev->stop = de620_close;
+ dev->hard_start_xmit = de620_start_xmit;
+ dev->tx_timeout = de620_timeout;
+ dev->watchdog_timeo = HZ*2;
+ dev->set_multicast_list = de620_set_multicast_list;
+
/* base_addr and irq are already set, see above! */
ether_setup(dev);
@@ -913,8 +901,7 @@ de620_probe(struct net_device *dev)
*/
#define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister);
-static unsigned short __init
-ReadAWord(struct net_device *dev, int from)
+static unsigned short __init ReadAWord(struct net_device *dev, int from)
{
unsigned short data;
int nbits;
@@ -956,8 +943,7 @@ ReadAWord(struct net_device *dev, int from)
return data;
}
-static int __init
-read_eeprom(struct net_device *dev)
+static int __init read_eeprom(struct net_device *dev)
{
unsigned short wrd;
@@ -1003,16 +989,14 @@ static char nullname[8] = "";
static struct net_device de620_dev = {
nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de620_probe };
-int
-init_module(void)
+int init_module(void)
{
if (register_netdev(&de620_dev) != 0)
return -EIO;
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
unregister_netdev(&de620_dev);
release_region(de620_dev.base_addr, 3);
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index be62ef741..b3851ef09 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -253,7 +253,7 @@ static int dfx_close(struct net_device *dev);
static void dfx_int_pr_halt_id(DFX_board_t *bp);
static void dfx_int_type_0_process(DFX_board_t *bp);
-static void dfx_int_common(DFX_board_t *bp);
+static void dfx_int_common(struct net_device *dev);
static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
@@ -272,7 +272,7 @@ static void dfx_rcv_init(DFX_board_t *bp);
static void dfx_rcv_queue_process(DFX_board_t *bp);
static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static void dfx_xmt_done(DFX_board_t *bp);
+static int dfx_xmt_done(DFX_board_t *bp);
static void dfx_xmt_flush(DFX_board_t *bp);
/* Define module-wide (static) variables */
@@ -1423,9 +1423,7 @@ int dfx_open(
/* Set device structure info */
- dev->tbusy = 0;
- dev->interrupt = DFX_UNMASK_INTERRUPTS;
- dev->start = 1;
+ netif_start_queue(dev);
return(0);
}
@@ -1511,9 +1509,8 @@ int dfx_close(
/* Clear device structure flags */
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
/* Deregister (free) IRQ */
free_irq(dev->irq, dev);
@@ -1804,16 +1801,15 @@ void dfx_int_type_0_process(
* or updating completion indices.
*/
-void dfx_int_common(
- DFX_board_t *bp
- )
-
- {
+void dfx_int_common(struct net_device *dev)
+{
+ DFX_board_t *bp = (DFX_board_t *) dev->priv;
PI_UINT32 port_status; /* Port Status register */
/* Process xmt interrupts - frequent case, so always call this routine */
- dfx_xmt_done(bp); /* free consumed xmt packets */
+ if(dfx_xmt_done(bp)) /* free consumed xmt packets */
+ netif_wake_queue(dev);
/* Process rcv interrupts - frequent case, so always call this routine */
@@ -1889,21 +1885,12 @@ void dfx_interrupt(
/* Get board pointer only if device structure is valid */
- if (dev == NULL)
- {
- printk("dfx_interrupt(): irq %d for unknown device!\n", irq);
- return;
- }
bp = (DFX_board_t *) dev->priv;
spin_lock(&bp->lock);
/* See if we're already servicing an interrupt */
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler!\n", dev->name);
- dev->interrupt = DFX_MASK_INTERRUPTS; /* ensure non reentrancy */
-
/* Service adapter interrupts */
if (bp->bus_type == DFX_BUS_TYPE_PCI)
@@ -1914,7 +1901,7 @@ void dfx_interrupt(
/* Call interrupt service routine for this adapter */
- dfx_int_common(bp);
+ dfx_int_common(dev);
/* Clear PDQ interrupt status bit and reenable interrupts */
@@ -1932,7 +1919,7 @@ void dfx_interrupt(
/* Call interrupt service routine for this adapter */
- dfx_int_common(bp);
+ dfx_int_common(dev);
/* Reenable interrupts at the ESIC */
@@ -1941,7 +1928,6 @@ void dfx_interrupt(
dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
}
- dev->interrupt = DFX_UNMASK_INTERRUPTS;
spin_unlock(&bp->lock);
return;
}
@@ -3199,6 +3185,8 @@ int dfx_xmt_queue_pkt(
XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
unsigned long flags;
+ netif_stop_queue(dev);
+
/*
* Verify that incoming transmit request is OK
*
@@ -3213,7 +3201,7 @@ int dfx_xmt_queue_pkt(
printk("%s: Invalid packet length - %u bytes\n",
dev->name, skb->len);
bp->xmt_length_errors++; /* bump error counter */
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
dev_kfree_skb(skb);
return(0); /* return "success" */
}
@@ -3237,6 +3225,7 @@ int dfx_xmt_queue_pkt(
{
bp->xmt_discards++; /* bump error counter */
dev_kfree_skb(skb); /* free sk_buff now */
+ netif_wake_queue(dev);
return(0); /* return "success" */
}
}
@@ -3339,6 +3328,7 @@ int dfx_xmt_queue_pkt(
bp->rcv_xmt_reg.index.xmt_prod = prod;
dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
spin_unlock_irqrestore(&bp->lock, flags);
+ netif_wake_queue(dev);
return(0); /* packet queued to adapter */
}
@@ -3375,13 +3365,14 @@ int dfx_xmt_queue_pkt(
* None
*/
-void dfx_xmt_done(
+int dfx_xmt_done(
DFX_board_t *bp
)
{
XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */
+ int freed = 0; /* buffers freed */
/* Service all consumed transmit frames */
@@ -3413,8 +3404,9 @@ void dfx_xmt_done(
*/
bp->rcv_xmt_reg.index.xmt_comp += 1;
+ freed++;
}
- return;
+ return freed;
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index bfcc78744..06d9e6171 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -270,6 +270,8 @@ static int depca_debug = 1;
#define DEPCA_NDA 0xffe0 /* No Device Address */
+#define TX_TIMEOUT (1*HZ)
+
/*
** Ethernet PROM defines
*/
@@ -387,6 +389,7 @@ struct depca_private {
int rx_new, tx_new; /* The next free ring entry */
int rx_old, tx_old; /* The ring entries to be free()ed. */
struct net_device_stats stats;
+ spinlock_t lock;
struct { /* Private stats counters */
u32 bins[DEPCA_PKT_STAT_SZ];
u32 unicast;
@@ -421,6 +424,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int depca_close(struct net_device *dev);
static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void depca_tx_timeout (struct net_device *dev);
static struct net_device_stats *depca_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -584,6 +588,7 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
memset((char *)dev->priv, 0, sizeof(struct depca_private));
lp->adapter = adapter;
lp->mca_slot = mca_slot;
+ lp->lock = SPIN_LOCK_UNLOCKED;
sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
@@ -703,6 +708,8 @@ depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
dev->get_stats = &depca_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &depca_ioctl;
+ dev->tx_timeout = depca_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
dev->mem_start = 0;
@@ -755,9 +762,7 @@ depca_open(struct net_device *dev)
outb(nicsr, DEPCA_NICSR);
outw(CSR0,DEPCA_ADDR);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
status = InitRestartDepca(dev);
@@ -781,7 +786,7 @@ depca_init_ring(struct net_device *dev)
u_long p;
/* Lock out other processes whilst setting up the hardware */
- test_and_set_bit(0, (void *)&dev->tbusy);
+ netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
lp->rx_old = lp->tx_old = 0;
@@ -809,122 +814,110 @@ depca_init_ring(struct net_device *dev)
}
lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
+}
- return;
+
+static void depca_tx_timeout (struct net_device *dev)
+{
+ u_long ioaddr = dev->base_addr;
+
+ printk ("%s: transmit timed out, status %04x, resetting.\n",
+ dev->name, inw (DEPCA_DATA));
+
+ STOP_DEPCA;
+ depca_init_ring (dev);
+ LoadCSRs (dev);
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+ InitRestartDepca (dev);
}
+
/*
** Writes a socket buffer to TX descriptor ring and starts transmission
*/
-static int
-depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int depca_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_long ioaddr = dev->base_addr;
- int status = 0;
+ struct depca_private *lp = (struct depca_private *) dev->priv;
+ u_long ioaddr = dev->base_addr;
+ int status = 0;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 1*HZ) {
- status = -1;
- } else {
- printk("%s: transmit timed out, status %04x, resetting.\n",
- dev->name, inw(DEPCA_DATA));
-
- STOP_DEPCA;
- depca_init_ring(dev);
- LoadCSRs(dev);
- dev->interrupt = UNMASK_INTERRUPTS;
- dev->start = 1;
- dev->tbusy=0;
- dev->trans_start = jiffies;
- InitRestartDepca(dev);
- }
- return status;
- } else if (skb->len > 0) {
- /* Enforce 1 process per h/w access */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- status = -1;
- } else {
- if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
- status = load_packet(dev, skb);
+ /* Transmitter timeout, serious problems. */
+ if (skb->len < 1)
+ goto out;
- if (!status) {
- /* Trigger an immediate send demand. */
- outw(CSR0, DEPCA_ADDR);
- outw(INEA | TDMD, DEPCA_DATA);
-
- dev->trans_start = jiffies;
- dev_kfree_skb(skb);
- }
- if (TX_BUFFS_AVAIL) {
- dev->tbusy=0;
- }
- } else {
- status = -1;
- }
- }
- }
-
- return status;
+ netif_stop_queue (dev);
+
+ if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
+ status = load_packet (dev, skb);
+
+ if (!status) {
+ /* Trigger an immediate send demand. */
+ outw (CSR0, DEPCA_ADDR);
+ outw (INEA | TDMD, DEPCA_DATA);
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+ }
+ if (TX_BUFFS_AVAIL)
+ netif_start_queue (dev);
+ } else
+ status = -1;
+
+out:
+ return status;
}
/*
** The DEPCA interrupt handler.
*/
-static void
-depca_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void depca_interrupt (int irq, void *dev_id, struct pt_regs *regs)
{
- struct net_device *dev = dev_id;
- struct depca_private *lp;
- s16 csr0, nicsr;
- u_long ioaddr;
+ struct net_device *dev = dev_id;
+ struct depca_private *lp;
+ s16 csr0, nicsr;
+ u_long ioaddr;
- if (dev == NULL) {
- printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
- } else {
- lp = (struct depca_private *)dev->priv;
- ioaddr = dev->base_addr;
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ if (dev == NULL) {
+ printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
- dev->interrupt = MASK_INTERRUPTS;
+ lp = (struct depca_private *) dev->priv;
+ ioaddr = dev->base_addr;
- /* mask the DEPCA board interrupts and turn on the LED */
- nicsr = inb(DEPCA_NICSR);
- nicsr |= (IM|LED);
- outb(nicsr, DEPCA_NICSR);
+ spin_lock (&lp->lock);
- outw(CSR0, DEPCA_ADDR);
- csr0 = inw(DEPCA_DATA);
+ /* mask the DEPCA board interrupts and turn on the LED */
+ nicsr = inb (DEPCA_NICSR);
+ nicsr |= (IM | LED);
+ outb (nicsr, DEPCA_NICSR);
- /* Acknowledge all of the current interrupt sources ASAP. */
- outw(csr0 & INTE, DEPCA_DATA);
+ outw (CSR0, DEPCA_ADDR);
+ csr0 = inw (DEPCA_DATA);
- if (csr0 & RINT) /* Rx interrupt (packet arrived) */
- depca_rx(dev);
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outw (csr0 & INTE, DEPCA_DATA);
- if (csr0 & TINT) /* Tx interrupt (packet sent) */
- depca_tx(dev);
+ if (csr0 & RINT) /* Rx interrupt (packet arrived) */
+ depca_rx (dev);
- if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */
- dev->tbusy = 0; /* clear TX busy flag */
- mark_bh(NET_BH);
- }
+ if (csr0 & TINT) /* Tx interrupt (packet sent) */
+ depca_tx (dev);
- /* Unmask the DEPCA board interrupts and turn off the LED */
- nicsr = (nicsr & ~IM & ~LED);
- outb(nicsr, DEPCA_NICSR);
+ /* Any resources available? */
+ if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
+ netif_wake_queue (dev);
- dev->interrupt = UNMASK_INTERRUPTS;
- }
+ /* Unmask the DEPCA board interrupts and turn off the LED */
+ nicsr = (nicsr & ~IM & ~LED);
+ outb (nicsr, DEPCA_NICSR);
+ }
- return;
+ spin_unlock (&lp->lock);
}
+
static int
depca_rx(struct net_device *dev)
{
@@ -1070,8 +1063,7 @@ depca_close(struct net_device *dev)
s16 nicsr;
u_long ioaddr = dev->base_addr;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
outw(CSR0, DEPCA_ADDR);
@@ -1173,8 +1165,7 @@ set_multicast_list(struct net_device *dev)
u_long ioaddr = dev->base_addr;
if (dev) {
- while(dev->tbusy) barrier(); /* Stop ring access */
- set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
@@ -1189,7 +1180,7 @@ set_multicast_list(struct net_device *dev)
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
}
}
@@ -1909,21 +1900,19 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
for (i=0; i<ETH_ALEN; i++) {
dev->dev_addr[i] = tmp.addr[i];
}
- while(dev->tbusy) barrier(); /* Stop ring access */
- test_and_set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
depca_init_ring(dev); /* Initialize the descriptor rings */
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
break;
case DEPCA_SET_PROM: /* Set Promiscuous Mode */
if (!capable(CAP_NET_ADMIN)) return -EPERM;
- while(dev->tbusy) barrier(); /* Stop ring access */
- test_and_set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
@@ -1932,13 +1921,12 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
break;
case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
if (!capable(CAP_NET_ADMIN)) return -EPERM;
- while(dev->tbusy) barrier(); /* Stop ring access */
- test_and_set_bit(0, (void*)&dev->tbusy);
+ netif_stop_queue(dev);
while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
STOP_DEPCA; /* Temporarily stop the depca. */
@@ -1947,7 +1935,7 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
- dev->tbusy = 0; /* Unlock the TX ring */
+ netif_start_queue(dev); /* Unlock the TX ring */
break;
case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c
index e341ed226..01a32afd5 100644
--- a/drivers/net/dmfe.c
+++ b/drivers/net/dmfe.c
@@ -460,8 +460,6 @@ static int dmfe_open(struct net_device *dev)
dmfe_init_dm910x(dev);
/* Active System Interface */
- dev->tbusy = 0; /* Can transmit packet */
- dev->start = 1; /* interface ready */
MOD_INC_USE_COUNT;
/* set and active a timer process */
@@ -470,6 +468,8 @@ static int dmfe_open(struct net_device *dev)
db->timer.data = (unsigned long) dev;
db->timer.function = &dmfe_timer;
add_timer(&db->timer);
+
+ netif_wake_queue(dev);
return 0;
}
@@ -543,24 +543,18 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct tx_desc *txptr;
DMFE_DBUG(0, "dmfe_start_xmit", 0);
-
- if ((dev->tbusy == 1) && (db->tx_packet_cnt != 0))
- return 1;
- else
- dev->tbusy = 0;
-
+
+ netif_stop_queue(dev);
+
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
- printk(KERN_ERR "%s: oversized frame (%d bytes) received.\n", dev->name, (u16) skb->len);
+ printk(KERN_ERR "%s: oversized frame (%d bytes) for transmit.\n", dev->name, (u16) skb->len);
dev_kfree_skb(skb);
return 0;
}
/* No Tx resource check, it never happen nromally */
if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
- printk(KERN_WARNING "%s: No Tx resource, enter xmit() again \n", dev->name);
- dev_kfree_skb(skb);
- dev->tbusy = 1;
- return -EBUSY;
+ return 1;
}
/* transmit this packet */
@@ -580,8 +574,8 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
outl(0x1, dev->base_addr + DCR1);
/* Tx resource check */
- if (db->tx_packet_cnt >= TX_FREE_DESC_CNT)
- dev->tbusy = 1;
+ if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
+ netif_wake_queue(dev);
/* Set transmit time stamp */
dev->trans_start = jiffies; /* saved the time stamp */
@@ -603,9 +597,7 @@ static int dmfe_stop(struct net_device *dev)
DMFE_DBUG(0, "dmfe_stop", 0);
- /* disable system */
- dev->start = 0; /* interface disable */
- dev->tbusy = 1; /* can't transmit */
+ netif_stop_queue(dev);
/* Reset & stop DM910X board */
outl(DM910X_RESET, ioaddr + DCR0);
@@ -645,13 +637,8 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0);
return;
}
- if (dev->interrupt) {
- DMFE_DBUG(1, "dmfe_interrupt() re-entry ", 0);
- return;
- }
/* A real interrupt coming */
- dev->interrupt = 1; /* Lock interrupt */
db = (struct dmfe_board_info *) dev->priv;
ioaddr = dev->base_addr;
@@ -669,10 +656,9 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (db->cr5_data & 0x2000) {
/* A system bus error occurred */
DMFE_DBUG(1, "A system bus error occurred. CR5=", db->cr5_data);
- dev->tbusy = 1;
+ netif_stop_queue(dev);
db->wait_reset = 1; /* Need to RESET */
outl(0, ioaddr + DCR7); /* disable all interrupt */
- dev->interrupt = 0; /* unlock interrupt */
return;
}
/* Free the transmitted descriptor */
@@ -690,10 +676,9 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
db->tx_remove_ptr = (struct tx_desc *) txptr;
- if (dev->tbusy && (db->tx_packet_cnt < TX_FREE_DESC_CNT)) {
- dev->tbusy = 0; /* free a resource */
- mark_bh(NET_BH); /* active bottom half */
- }
+ if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
+ netif_wake_queue(dev);
+
/* Received the coming packet */
if (db->rx_avail_cnt)
dmfe_rx_packet(dev, db);
@@ -708,7 +693,6 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
db->cr6_data |= 0x100;
update_cr6(db->cr6_data, db->ioaddr);
}
- dev->interrupt = 0; /* release interrupt lock */
/* Restore CR7 to enable interrupt mask */
@@ -935,9 +919,8 @@ static void dmfe_dynamic_reset(struct net_device *dev)
db->in_reset_state = 1;
/* Disable upper layer interface */
- dev->tbusy = 1; /* transmit packet disable */
- dev->start = 0; /* interface not ready */
-
+ netif_stop_queue(dev);
+
db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */
update_cr6(db->cr6_data, dev->base_addr);
@@ -954,12 +937,11 @@ static void dmfe_dynamic_reset(struct net_device *dev)
/* Re-initilize DM910X board */
dmfe_init_dm910x(dev);
- /* Restart upper layer interface */
- dev->tbusy = 0; /* Can transmit packet */
- dev->start = 1; /* interface ready */
-
/* Leave dynamic reser route */
db->in_reset_state = 0;
+
+ /* Restart upper layer interface */
+ netif_wake_queue(dev);
}
/*
@@ -1113,7 +1095,7 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
/* prepare the setup frame */
db->tx_packet_cnt++;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
txptr->tdes1 = 0x890000c0;
txptr->tdes0 = 0x80000000;
db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 21236be77..c9e7beaca 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -987,7 +987,7 @@ static void eepro_tx_timeout (struct net_device *dev)
lp->tx_last = 0;
dev->trans_start = jiffies;
- netif_start_queue (dev);
+ netif_wake_queue (dev);
outb (RCV_ENABLE_CMD, ioaddr);
}
@@ -1001,6 +1001,8 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
if (net_debug > 5)
printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name);
+ netif_stop_queue (dev);
+
spin_lock_irqsave(&lp->lock, flags);
{
@@ -1014,7 +1016,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
}
- compat_dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
/* lp->stats.tx_aborted_errors++; */
@@ -1407,8 +1409,8 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
lp->tx_last = last;
lp->tx_end = end;
- if (test_bit(LINK_STATE_XOFF, &dev->flags))
- netif_start_queue(dev);
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
/* Enable RX and TX interrupts */
outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index e651be8a8..8410c0cf8 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1,7 +1,9 @@
-/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
/*
- NOTICE: this version tested with kernels 1.3.72 and later only!
+
+ drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux
+
Written 1996-1999 by Donald Becker.
+ Modified 2000 by Linux Kernel Team
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -20,132 +22,15 @@
http://cesdis.gsfc.nasa.gov/linux/misc/modules.html
There is a Majordomo mailing list based at
linux-eepro100@cesdis.gsfc.nasa.gov
-*/
-
-static const char *version =
-"eepro100.c:v1.09j 7/27/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
-
-/* A few user-configurable values that apply to all boards.
- First set is undocumented and spelled per Intel recommendations. */
-
-static int congenb = 0; /* Enable congestion control in the DP83840. */
-static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
-static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
-/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
-static int txdmacount = 128;
-static int rxdmacount = 0;
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
- Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
-
-/* 'options' is used to pass a transceiver override or full-duplex flag
- e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int debug = -1; /* The debug level */
-
-/* A few values that may be tweaked. */
-/* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */
-#define RX_RING_SIZE 32
-/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
-#define TX_QUEUE_LIMIT 12
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
-/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-#define PKT_BUF_SZ 1536
-
-#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
-#warning You must compile this file with the correct options!
-#warning See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
-#include <linux/version.h>
-#include <linux/module.h>
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#ifdef HAS_PCI_NETIF
-#include "pci-netif.h"
-#else
-#include <linux/pci.h>
-#if LINUX_VERSION_CODE < 0x20155
-#include <linux/bios32.h> /* Ignore the bogus warning in 2.1.100+ */
-#endif
-#endif
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(multicast_filter_limit, "i");
-#define RUN_AT(x) (jiffies + (x))
-#if (LINUX_VERSION_CODE < 0x20123)
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#define le16_to_cpu(val) (val)
-#define cpu_to_le16(val) (val)
-#define le32_to_cpu(val) (val)
-#define cpu_to_le32(val) (val)
-#define spin_lock_irqsave(&sp->lock, flags) save_flags(flags); cli();
-#define spin_unlock_irqrestore(&sp->lock, flags); restore_flags(flags);
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
-#if ! defined(CAP_NET_ADMIN)
-#define capable(CAP_XXX) (suser())
-#endif
-#if ! defined(HAS_NETIF_QUEUE)
-#define netif_wake_queue(dev) mark_bh(NET_BH);
-#endif
+ Version history:
+ v1.09j+LK1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
+ Convert to new PCI driver interface
-/* The total I/O port extent of the board.
- The registers beyond 0x18 only exist on the i82558. */
-#define SPEEDO3_TOTAL_SIZE 0x20
-int speedo_debug = 1;
-/*
Theory of Operation
I. Board Compatibility
@@ -277,40 +162,118 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
*/
-/* This table drives the PCI probe routines. */
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-#ifdef USE_IO
-#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
-#define SPEEDO_SIZE 32
-#else
-#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0
-#define SPEEDO_SIZE 0x1000
+static const char *version =
+"eepro100.c:v1.09j+LK1.0 Feb 13, 2000 Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
+
+/* A few user-configurable values that apply to all boards.
+ First set is undocumented and spelled per Intel recommendations. */
+
+static int congenb = 0; /* Enable congestion control in the DP83840. */
+static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
+static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
+/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
+static int txdmacount = 128;
+static int rxdmacount = 0;
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
+ Lower values use more memory, but are faster. */
+static int rx_copybreak = 200;
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
+
+/* 'options' is used to pass a transceiver override or full-duplex flag
+ e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int debug = -1; /* The debug level */
+
+/* A few values that may be tweaked. */
+/* The ring sizes should be a power of two for efficiency. */
+#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */
+#define RX_RING_SIZE 32
+/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
+#define TX_QUEUE_LIMIT 12
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (2*HZ)
+/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
+#define PKT_BUF_SZ 1536
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
#endif
-#if defined(HAS_PCI_NETIF)
-struct pci_id_info static pci_tbl[] = {
- { "Intel PCI EtherExpress Pro100",
- { 0x12298086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE,
- 0, speedo_found1 },
- {0,}, /* 0 terminated list. */
-};
-#else
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
+
+#define EEPRO100_MODULE_NAME "eepro100"
+#define PFX EEPRO100_MODULE_NAME ": "
+
+#define RUN_AT(x) (jiffies + (x))
+
+/* ACPI power states don't universally work (yet) */
+#ifndef CONFIG_EEPRO100_PM
+#undef pci_set_power_state
+#define pci_set_power_state null_set_power_state
+static inline int null_set_power_state(struct pci_dev *dev, int state)
+{
+ return 0;
+}
+#endif /* CONFIG_EEPRO100_PM */
+
+
+/* compile-time switch to en/disable slow PIO */
+#undef USE_IO
+
+
+int speedo_debug = 1;
+
+
enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, flags;
- int io_size;
- struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-} static pci_tbl[] = {
- { "Intel PCI EtherExpress Pro100",
- 0x8086, 0x1229, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 32, speedo_found1 },
- {0,}, /* 0 terminated list. */
-};
-#endif
#ifndef USE_IO
#define inb readb
@@ -321,34 +284,45 @@ struct pci_id_info {
#define outl writel
#endif
+
/* How to wait for the command unit to accept a command.
Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done(long cmd_ioaddr)
+static inline void wait_for_cmd_done (long cmd_ioaddr)
{
int wait = 100;
- do ;
- while(inb(cmd_ioaddr) && --wait >= 0);
+ do;
+ while (inb (cmd_ioaddr) && --wait >= 0);
}
+
/* Offsets to the various registers.
All accesses need not be longword aligned. */
enum speedo_offsets {
SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */
- SCBPointer = 4, /* General purpose pointer. */
- SCBPort = 8, /* Misc. commands and operands. */
- SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
- SCBCtrlMDI = 16, /* MDI interface control. */
- SCBEarlyRx = 20, /* Early receive byte count. */
+ SCBPointer = 4, /* General purpose pointer. */
+ SCBPort = 8, /* Misc. commands and operands. */
+ SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
+ SCBCtrlMDI = 16, /* MDI interface control. */
+ SCBEarlyRx = 20, /* Early receive byte count. */
};
+
+
/* Commands that can be put in a command list entry. */
enum commands {
- CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000,
- CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000,
- CmdDump = 0x60000, CmdDiagnose = 0x70000,
+ CmdNOp = 0,
+ CmdIASetup = 0x10000,
+ CmdConfigure = 0x20000,
+ CmdMulticastList = 0x30000,
+ CmdTx = 0x40000,
+ CmdTDR = 0x50000,
+ CmdDump = 0x60000,
+ CmdDiagnose = 0x70000,
CmdSuspend = 0x40000000, /* Suspend after completion. */
CmdIntr = 0x20000000, /* Interrupt after completion. */
CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */
};
+
+
/* Do atomically if possible. */
#if defined(__i386__) || defined(__alpha__) || defined(__ia64__)
#define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status)
@@ -362,54 +336,75 @@ enum commands {
#endif
enum SCBCmdBits {
- SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
- SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
- SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
- /* The rest are Rx and Tx commands. */
- CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
- CUCmdBase=0x0060, /* CU Base address (set to zero) . */
- CUDumpStats=0x0070, /* Dump then reset stats counters. */
- RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
- RxResumeNoResources=0x0007,
+ SCBMaskCmdDone = 0x8000,
+ SCBMaskRxDone = 0x4000,
+ SCBMaskCmdIdle = 0x2000,
+ SCBMaskRxSuspend = 0x1000,
+ SCBMaskEarlyRx = 0x0800,
+ SCBMaskFlowCtl = 0x0400,
+ SCBTriggerIntr = 0x0200,
+ SCBMaskAll = 0x0100,
+ /* The rest are Rx and Tx commands. */
+ CUStart = 0x0010,
+ CUResume = 0x0020,
+ CUStatsAddr = 0x0040,
+ CUShowStats = 0x0050,
+ CUCmdBase = 0x0060, /* CU Base address (set to zero) . */
+ CUDumpStats = 0x0070, /* Dump then reset stats counters. */
+ RxStart = 0x0001,
+ RxResume = 0x0002,
+ RxAbort = 0x0004,
+ RxAddrLoad = 0x0006,
+ RxResumeNoResources = 0x0007,
};
enum SCBPort_cmds {
- PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
+ PortReset = 0,
+ PortSelfTest = 1,
+ PortPartialReset = 2,
+ PortDump = 3,
};
/* The Speedo3 Rx and Tx frame/buffer descriptors. */
-struct descriptor { /* A generic descriptor. */
- s32 cmd_status; /* All command and status fields. */
- u32 link; /* struct descriptor * */
+struct descriptor { /* A generic descriptor. */
+ s32 cmd_status; /* All command and status fields. */
+ u32 link; /* struct descriptor * */
unsigned char params[0];
};
/* The Speedo3 Rx and Tx buffer descriptors. */
-struct RxFD { /* Receive frame descriptor. */
+struct RxFD { /* Receive frame descriptor. */
s32 status;
- u32 link; /* struct RxFD * */
- u32 rx_buf_addr; /* void * */
+ u32 link; /* struct RxFD * */
+ u32 rx_buf_addr; /* void * */
u32 count;
};
/* Selected elements of the Tx/RxFD.status word. */
enum RxFD_bits {
- RxComplete=0x8000, RxOK=0x2000,
- RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
- RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
- TxUnderrun=0x1000, StatusComplete=0x8000,
+ RxComplete = 0x8000,
+ RxOK = 0x2000,
+ RxErrCRC = 0x0800,
+ RxErrAlign = 0x0400,
+ RxErrTooBig = 0x0200,
+ RxErrSymbol = 0x0010,
+ RxEth2Type = 0x0020,
+ RxNoMatch = 0x0004,
+ RxNoIAMatch = 0x0002,
+ TxUnderrun = 0x1000,
+ StatusComplete = 0x8000,
};
-struct TxFD { /* Transmit frame descriptor set. */
+struct TxFD { /* Transmit frame descriptor set. */
s32 status;
- u32 link; /* void * */
- u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
- s32 count; /* # of TBD (=1), Tx start thresh., etc. */
+ u32 link; /* void * */
+ u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
+ s32 count; /* # of TBD (=1), Tx start thresh., etc. */
/* This constitutes two "TBD" entries -- we only use one. */
- u32 tx_buf_addr0; /* void *, frame to be transmitted. */
- s32 tx_buf_size0; /* Length of Tx frame. */
- u32 tx_buf_addr1; /* void *, frame to be transmitted. */
- s32 tx_buf_size1; /* Length of Tx frame. */
+ u32 tx_buf_addr0; /* void *, frame to be transmitted. */
+ s32 tx_buf_size0; /* Length of Tx frame. */
+ u32 tx_buf_addr1; /* void *, frame to be transmitted. */
+ s32 tx_buf_size1; /* Length of Tx frame. */
};
/* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -436,46 +431,43 @@ struct speedo_stats {
/* Do not change the position (alignment) of the first few elements!
The later elements are grouped for cache locality. */
struct speedo_private {
- struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */
- struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */
+ struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */
+ struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */
/* The addresses of a Tx/Rx-in-place packets/buffers. */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
- dma_addr_t rx_ring_dma[RX_RING_SIZE];
- dma_addr_t tx_ring_dma;
- struct descriptor *last_cmd; /* Last command sent. */
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ dma_addr_t rx_ring_dma[RX_RING_SIZE];
+ dma_addr_t tx_ring_dma;
+ struct descriptor *last_cmd; /* Last command sent. */
unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */
- spinlock_t lock; /* Group with Tx control cache line. */
- u32 tx_threshold; /* The value for txdesc.count. */
- struct RxFD *last_rxf; /* Last command sent. */
- unsigned int cur_rx, dirty_rx; /* The next free ring entry */
- long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
+ spinlock_t lock; /* Group with Tx control cache line. */
+ u32 tx_threshold; /* The value for txdesc.count. */
+ struct RxFD *last_rxf; /* Last command sent. */
+ unsigned int cur_rx, dirty_rx; /* The next free ring entry */
+ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
const char *product_name;
- struct net_device *next_module;
- void *priv_addr; /* Unaligned address for kfree */
struct enet_statistics stats;
struct speedo_stats *lstats;
int chip_id;
- unsigned char pci_bus, pci_devfn, acpi_pwr;
+ unsigned char acpi_pwr;
struct pci_dev *pdev;
struct timer_list timer; /* Media selection timer. */
- int mc_setup_frm_len; /* The length of an allocated.. */
- struct descriptor *mc_setup_frm; /* ..multicast setup frame. */
- int mc_setup_busy; /* Avoid double-use of setup frame. */
+ int mc_setup_frm_len; /* The length of an allocated.. */
+ struct descriptor *mc_setup_frm;/* ..multicast setup frame. */
+ int mc_setup_busy; /* Avoid double-use of setup frame. */
dma_addr_t mc_setup_dma;
- char rx_mode; /* Current PROMISC/ALLMULTI setting. */
- unsigned int tx_full:1; /* The Tx queue is full. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
- unsigned int rx_bug:1; /* Work around receiver hang errata. */
- unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */
- unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */
- unsigned char default_port:8; /* Last dev->if_port value. */
- unsigned short phy[2]; /* PHY media interfaces available. */
- unsigned short advertising; /* Current PHY advertised caps. */
- unsigned short partner; /* Link partner caps. */
+ char rx_mode; /* Current PROMISC/ALLMULTI setting. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
+ unsigned int rx_bug:1; /* Work around receiver hang errata. */
+ unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */
+ unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */
+ unsigned char default_port:8; /* Last dev->if_port value. */
+ unsigned short phy[2]; /* PHY media interfaces available. */
+ unsigned short advertising; /* Current PHY advertised caps. */
+ unsigned short partner; /* Link partner caps. */
};
-
/* The parameters for a CmdConfigure operation.
There are so many options that it would be difficult to document each bit.
We mostly use the default or recommended settings. */
@@ -526,139 +518,75 @@ static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100,
0x2000, 0x2100, 0x0400, 0x3100};
#endif
-/* A list of all installed Speedo devices, for removing the driver module. */
-static struct net_device *root_speedo_dev = NULL;
-
-#if ! defined(HAS_PCI_NETIF)
-int eepro100_init(void)
-{
- int cards_found = 0;
- static int pci_index = 0;
-
- if (! pcibios_present())
- return cards_found;
-
- for (; pci_index < 8; pci_index++) {
- unsigned char pci_bus, pci_device_fn, pci_latency;
- long ioaddr;
- int irq;
-
- u16 pci_command, new_command;
-
- if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82557,
- pci_index, &pci_bus,
- &pci_device_fn))
- break;
-#if LINUX_VERSION_CODE >= 0x20155 || PCI_SUPPORT_1
- {
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-#ifdef USE_IO
- ioaddr = pdev->resource[1].start;
-#else
- ioaddr = pdev->resource[0].start;
-#endif
- irq = pdev->irq;
- }
-#else
- {
- u32 pciaddr;
- u8 pci_irq_line;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
-#ifdef USE_IO
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_1, &pciaddr);
- pciaddr &= ~3UL;
-#else
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pciaddr);
-#endif
- ioaddr = pciaddr;
- irq = pci_irq_line;
- }
-#endif
- /* Remove I/O space marker in bit 0. */
-#ifdef USE_IO
- if (check_region(ioaddr, 32))
- continue;
-#else
- {
- unsigned long orig_ioaddr = ioaddr;
-
- if ((ioaddr = (long)ioremap(ioaddr & ~0xfUL, 0x1000)) == 0) {
- printk(KERN_INFO "Failed to map PCI address %#lx.\n",
- orig_ioaddr);
- continue;
- }
- }
-#endif
- if (speedo_debug > 2)
- printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
- ioaddr, irq);
-
- /* Get and check the bus-master and latency values. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled this"
- " device! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
- }
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 32) {
- printk(" PCI latency timer (CFLT) is unreasonably low at %d."
- " Setting to 32 clocks.\n", pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 32);
- } else if (speedo_debug > 1)
- printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
-
- if(speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0,cards_found))
- cards_found++;
- }
- return cards_found;
-}
-#endif
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
- long ioaddr, int irq, int chip_idx, int card_idx)
+static int __devinit eepro100_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct net_device *dev;
struct speedo_private *sp;
- struct pci_dev *pdev;
unsigned char *tx_ring;
dma_addr_t tx_ring_dma;
const char *product;
int i, option;
u16 eeprom[0x100];
- int acpi_idle_state = 0;
+ int acpi_idle_state = 0, pm, irq;
+ unsigned long ioaddr;
+ static int card_idx = -1;
static int did_version = 0; /* Already printed version info. */
+
+#ifdef USE_IO
+ ioaddr = pci_resource_start (pdev, 0);
+#else
+ ioaddr = pci_resource_start (pdev, 1);
+#endif
+ irq = pdev->irq;
+
+ card_idx++;
+
+ if (!request_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1),
+ EEPRO100_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot reserve I/O ports\n");
+ goto err_out_none;
+ }
+ if (!request_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0),
+ EEPRO100_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot reserve MMIO region\n");
+ goto err_out_free_pio_region;
+ }
+
+#ifndef USE_IO
+ ioaddr = (unsigned long) ioremap (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+ if (!ioaddr) {
+ printk (KERN_ERR PFX "cannot remap MMIO region %lx @ %lx\n",
+ pci_resource_len (pdev, 0),
+ pci_resource_start (pdev, 0));
+ goto err_out_free_mmio_region;
+ }
+#endif
+
if (speedo_debug > 0 && did_version++ == 0)
printk(version);
- pdev = pci_find_slot(pci_bus, pci_devfn);
-
tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+ sizeof(struct speedo_stats), &tx_ring_dma);
if (!tx_ring) {
- printk(KERN_ERR "Could not allocate DMA memory.\n");
- return NULL;
+ printk(KERN_ERR PFX "Could not allocate DMA memory.\n");
+ goto err_out_iounmap;
}
dev = init_etherdev(NULL, sizeof(struct speedo_private));
if (dev == NULL) {
- pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
- + sizeof(struct speedo_stats),
- tx_ring, tx_ring_dma);
- return NULL;
+ printk(KERN_ERR PFX "Could not allocate ethernet device.\n");
+ goto err_out_free_tx_ring;
+ }
+ if (dev->priv == NULL) {
+ printk(KERN_ERR PFX "Could not allocate ethernet device private info.\n");
+ goto err_out_free_netdev;
}
if (dev->mem_start > 0)
@@ -668,9 +596,16 @@ static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
else
option = 0;
-#if defined(HAS_PCI_NETIF)
- acpi_idle_state = acpi_set_pwr_state(pci_bus, pci_devfn, ACPI_D0);
-#endif
+ /* save power state b4 pci_enable_device overwrites it */
+ pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm) {
+ u16 pwr_command;
+ pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
+ acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+ }
+
+ pci_enable_device (pdev);
+ pci_set_master (pdev);
/* Read the station address EEPROM before doing the reset.
Nominally his should even be done before accepting the device, but
@@ -716,7 +651,7 @@ static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
if (eeprom[3] & 0x0100)
product = "OEM i82557/i82558 10/100 Ethernet";
else
- product = pci_tbl[chip_idx].name;
+ product = "Intel PCI EtherExpress Pro100";
printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
@@ -724,7 +659,7 @@ static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
printk("%2.2X:", dev->dev_addr[i]);
printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
-#ifndef kernel_bloat
+#if 1
/* OK, this is pure kernel bloat. I don't like it when other drivers
waste non-pageable kernel space to emit similar messages, but I need
them for bug reports. */
@@ -793,41 +728,29 @@ static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
#endif /* kernel_bloat */
outl(PortReset, ioaddr + SCBPort);
-#if defined(HAS_PCI_NETIF)
- /* Return the chip to its original power state. */
- acpi_set_pwr_state(pci_bus, pci_devfn, acpi_idle_state);
-#endif
- /* We do a request_region() only to register /proc/ioports info. */
- request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
+ /* Return the chip to its original power state. */
+ pci_set_power_state (pdev, acpi_idle_state);
dev->base_addr = ioaddr;
dev->irq = irq;
sp = dev->priv;
- if (dev->priv == NULL) {
- void *mem = kmalloc(sizeof(*sp), GFP_KERNEL);
- dev->priv = sp = mem; /* Cache align here if kmalloc does not. */
- sp->priv_addr = mem;
- }
memset(sp, 0, sizeof(*sp));
- sp->next_module = root_speedo_dev;
- root_speedo_dev = dev;
- sp->pci_bus = pci_bus;
- sp->pci_devfn = pci_devfn;
sp->pdev = pdev;
- sp->chip_id = chip_idx;
sp->acpi_pwr = acpi_idle_state;
sp->tx_ring = (struct TxFD *)tx_ring;
sp->tx_ring_dma = tx_ring_dma;
sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
+
if (card_idx >= 0) {
if (full_duplex[card_idx] >= 0)
sp->full_duplex = full_duplex[card_idx];
}
+
sp->default_port = option >= 0 ? (option & 0x0f) : 0;
sp->phy[0] = eeprom[6];
@@ -847,9 +770,30 @@ static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &speedo_ioctl;
- return dev;
+ return 0;
+
+err_out_free_netdev:
+ unregister_netdevice (dev);
+ kfree (dev);
+err_out_free_tx_ring:
+ pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+ + sizeof(struct speedo_stats),
+ tx_ring, tx_ring_dma);
+err_out_iounmap:
+#ifndef USE_IO
+ iounmap ((void *)ioaddr);
+err_out_free_mmio_region:
+#endif
+ release_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+err_out_free_pio_region:
+ release_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1));
+err_out_none:
+ return -ENODEV;
}
-
+
+
/* Serial EEPROM section.
A "bit" grungy, but we work our way through bit-by-bit :->. */
/* EEPROM_Ctrl bits. */
@@ -925,13 +869,11 @@ speedo_open(struct net_device *dev)
struct speedo_private *sp = (struct speedo_private *)dev->priv;
long ioaddr = dev->base_addr;
-#if defined(HAS_PCI_NETIF)
- acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
-#endif
-
if (speedo_debug > 1)
printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
+ pci_set_power_state(sp->pdev, 0);
+
/* Set up the Tx queue early.. */
sp->cur_tx = 0;
sp->dirty_tx = 0;
@@ -940,9 +882,9 @@ speedo_open(struct net_device *dev)
spin_lock_init(&sp->lock);
/* .. we can safely take handler calls during init. */
- if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
- return -EAGAIN;
- }
+ if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev))
+ return -EBUSY;
+
MOD_INC_USE_COUNT;
dev->if_port = sp->default_port;
@@ -970,7 +912,6 @@ speedo_open(struct net_device *dev)
/* Fire up the hardware. */
speedo_resume(dev);
- clear_bit(LINK_STATE_RXSEM, &dev->state);
netif_start_queue(dev);
/* Setup the chip and configure the multicast list. */
@@ -1059,6 +1000,8 @@ static void speedo_resume(struct net_device *dev)
+ (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD),
ioaddr + SCBPointer);
outw(CUStart, ioaddr + SCBCmd);
+
+ netif_start_queue (dev);
}
/* Media monitoring and control. */
@@ -1158,7 +1101,7 @@ speedo_init_rx_ring(struct net_device *dev)
rxf = (struct RxFD *)skb->tail;
sp->rx_ringp[i] = rxf;
sp->rx_ring_dma[i] =
- pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD));
+ pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
skb_reserve(skb, sizeof(struct RxFD));
if (last_rxf)
last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]);
@@ -1220,9 +1163,10 @@ static void speedo_tx_timeout(struct net_device *dev)
}
sp->stats.tx_errors++;
dev->trans_start = jiffies;
- return;
+ netif_start_queue (dev);
}
+
static int
speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -1230,6 +1174,8 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
long ioaddr = dev->base_addr;
int entry;
+ netif_stop_queue (dev);
+
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
@@ -1256,7 +1202,7 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
sp->tx_ring[entry].tx_buf_addr0 =
cpu_to_le32(pci_map_single(sp->pdev, skb->data,
- skb->len));
+ skb->len, PCI_DMA_TODEVICE));
sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
than half full. Argument against: we should be receiving packets
@@ -1270,13 +1216,15 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) {
sp->tx_full = 1;
- netif_stop_queue(dev);
}
spin_unlock_irqrestore(&sp->lock, flags);
}
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CUResume, ioaddr + SCBCmd);
dev->trans_start = jiffies;
+
+ if (! sp->tx_full)
+ netif_start_queue (dev);
return 0;
}
@@ -1300,6 +1248,8 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
ioaddr = dev->base_addr;
sp = (struct speedo_private *)dev->priv;
+ spin_lock (&sp->lock);
+
do {
status = inw(ioaddr + SCBStatus);
/* Acknowledge all of the current interrupt sources ASAP. */
@@ -1330,7 +1280,6 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* User interrupt, Command/Tx unit interrupt or CU not active. */
if (status & 0xA400) {
unsigned int dirty_tx;
- spin_lock(&sp->lock);
dirty_tx = sp->dirty_tx;
while (sp->cur_tx - dirty_tx > 0) {
@@ -1348,19 +1297,18 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Free the original skb. */
if (sp->tx_skbuff[entry]) {
sp->stats.tx_packets++; /* Count only user packets. */
-#if LINUX_VERSION_CODE > 0x20127
sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
-#endif
pci_unmap_single(sp->pdev,
le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
- sp->tx_skbuff[entry]->len);
+ sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(sp->tx_skbuff[entry]);
sp->tx_skbuff[entry] = 0;
} else if ((status & 0x70000) == CmdNOp) {
if (sp->mc_setup_busy)
pci_unmap_single(sp->pdev,
sp->mc_setup_dma,
- sp->mc_setup_frm_len);
+ sp->mc_setup_frm_len,
+ PCI_DMA_TODEVICE);
sp->mc_setup_busy = 0;
}
dirty_tx++;
@@ -1380,10 +1328,12 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
&& sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) {
/* The ring is no longer full, clear tbusy. */
sp->tx_full = 0;
- spin_unlock(&sp->lock);
- netif_wake_queue(dev);
- } else
- spin_unlock(&sp->lock);
+ }
+
+ if (sp->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
}
if (--boguscnt < 0) {
@@ -1399,7 +1349,7 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, inw(ioaddr + SCBStatus));
- return;
+ spin_unlock (&sp->lock);
}
static int
@@ -1443,7 +1393,7 @@ speedo_rx(struct net_device *dev)
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry],
- PKT_BUF_SZ + sizeof(struct RxFD));
+ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
#if 1 || USE_IP_CSUM
/* Packet is in one chunk -- we can copy + cksum. */
eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
@@ -1465,14 +1415,12 @@ speedo_rx(struct net_device *dev)
temp = skb_put(skb, pkt_len);
sp->rx_ringp[entry] = NULL;
pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
- PKT_BUF_SZ + sizeof(struct RxFD));
+ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
sp->stats.rx_packets++;
-#if LINUX_VERSION_CODE > 0x20127
sp->stats.rx_bytes += pkt_len;
-#endif
}
entry = (++sp->cur_rx) % RX_RING_SIZE;
}
@@ -1493,7 +1441,7 @@ speedo_rx(struct net_device *dev)
rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
sp->rx_ring_dma[entry] =
pci_map_single(sp->pdev, rxf, PKT_BUF_SZ
- + sizeof(struct RxFD));
+ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
skb->dev = dev;
skb_reserve(skb, sizeof(struct RxFD));
rxf->rx_buf_addr = 0xffffffff;
@@ -1542,11 +1490,8 @@ speedo_close(struct net_device *dev)
if (skb) {
pci_unmap_single(sp->pdev,
sp->rx_ring_dma[i],
- PKT_BUF_SZ + sizeof(struct RxFD));
-#if LINUX_VERSION_CODE < 0x20100
- skb->free = 1;
-#endif
- dev_free_skb(skb);
+ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skb);
}
}
@@ -1558,8 +1503,8 @@ speedo_close(struct net_device *dev)
if (skb) {
pci_unmap_single(sp->pdev,
le32_to_cpu(sp->tx_ring[i].tx_buf_addr0),
- skb->len);
- dev_free_skb(skb);
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
}
}
if (sp->mc_setup_frm) {
@@ -1571,10 +1516,9 @@ speedo_close(struct net_device *dev)
if (speedo_debug > 3)
speedo_show_state(dev);
-#if defined(HAS_PCI_NETIF)
/* Alt: acpi_set_pwr_state(pci_bus, pci_devfn, sp->acpi_pwr); */
- acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D2);
-#endif
+ pci_set_power_state (sp->pdev, 2);
+
MOD_DEC_USE_COUNT;
return 0;
@@ -1612,7 +1556,7 @@ speedo_get_stats(struct net_device *dev)
sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats->rx_overrun_errs);
sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs);
sp->lstats->done_marker = 0x0000;
- if (test_bit(LINK_STATE_START, &dev->state)) {
+ if (netif_running(dev)) {
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CUDumpStats, ioaddr + SCBCmd);
}
@@ -1626,32 +1570,22 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
long ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_data;
int phy = sp->phy[0] & 0x1f;
-#if defined(HAS_PCI_NETIF)
int saved_acpi;
-#endif
switch(cmd) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
data[0] = phy;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-#if defined(HAS_PCI_NETIF)
- saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
- data[3] = mdio_read(ioaddr, data[0], data[1]);
- acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
-#else
- data[3] = mdio_read(ioaddr, data[0], data[1]);
-#endif
+ saved_acpi = pci_set_power_state (sp->pdev, 0);
+ data[3] = mdio_read (ioaddr, data[0], data[1]);
+ pci_set_power_state (sp->pdev, saved_acpi);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
-#if defined(HAS_PCI_NETIF)
- saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
- mdio_write(ioaddr, data[0], data[1], data[2]);
- acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
-#else
+ saved_acpi = pci_set_power_state(sp->pdev, 0);
mdio_write(ioaddr, data[0], data[1], data[2]);
-#endif
+ pci_set_power_state(sp->pdev, saved_acpi);
return 0;
default:
return -EOPNOTSUPP;
@@ -1814,7 +1748,7 @@ static void set_rx_mode(struct net_device *dev)
/* Change the command to a NoOp, pointing to the CmdMulti command. */
sp->tx_skbuff[entry] = 0;
sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
- sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len);
+ sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len, PCI_DMA_TODEVICE);
sp->tx_ring[entry].link = cpu_to_le32(sp->mc_setup_dma);
/* Set the link in the setup frame. */
@@ -1836,55 +1770,103 @@ static void set_rx_mode(struct net_device *dev)
}
+static void eepro100_suspend (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ long ioaddr = dev->base_addr;
+
+ netif_device_detach(dev);
+ outl(PortPartialReset, ioaddr + SCBPort);
+
+ /* XXX call pci_set_power_state ()? */
+}
+
+
+static void eepro100_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct speedo_private *np = (struct speedo_private *)dev->priv;
+
+ netif_device_attach(dev);
+ speedo_resume(dev);
+ np->rx_mode = -1;
+ np->flow_ctrl = np->partner = 0;
+ set_rx_mode(dev);
+}
+
+
+static void __devexit eepro100_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+
+ unregister_netdev (dev);
+
+ release_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1));
+ release_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+
+#ifndef USE_IO
+ iounmap ((char *) dev->base_addr);
+#endif
+
+ pci_set_power_state (pdev, sp->acpi_pwr);
+
+ pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+ + sizeof(struct speedo_stats),
+ sp->tx_ring, sp->tx_ring_dma);
+
+ kfree (dev);
+}
+
+
+static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { 0,},
+};
+MODULE_DEVICE_TABLE (pci, eepro100_pci_tbl);
+
+
+static struct pci_driver eepro100_driver = {
+ name: EEPRO100_MODULE_NAME,
+ id_table: eepro100_pci_tbl,
+ probe: eepro100_init_one,
+ remove: eepro100_remove_one,
+ suspend: eepro100_suspend,
+ resume: eepro100_resume,
+};
+
+
static int __init eepro100_init_module(void)
{
int cards_found;
if (debug >= 0)
speedo_debug = debug;
+
/* Always emit the version message. */
if (speedo_debug)
printk(KERN_INFO "%s", version);
-#if defined(HAS_PCI_NETIF)
- cards_found = netif_pci_probe(pci_tbl);
- if (cards_found < 0)
- printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
- return cards_found;
-#else
- cards_found = eepro100_init();
+ cards_found = pci_register_driver (&eepro100_driver);
if (cards_found <= 0) {
- printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
+ printk(KERN_INFO PFX "No cards found, driver not installed.\n");
+ pci_unregister_driver (&eepro100_driver);
return -ENODEV;
}
-#endif
+
return 0;
}
+
static void __exit eepro100_cleanup_module(void)
{
- struct net_device *next_dev;
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_speedo_dev) {
- struct speedo_private *sp = (void *)root_speedo_dev->priv;
- unregister_netdev(root_speedo_dev);
-#ifdef USE_IO
- release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
-#else
- iounmap((char *)root_speedo_dev->base_addr);
-#endif
-#if defined(HAS_PCI_NETIF)
- acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, sp->acpi_pwr);
-#endif
- next_dev = sp->next_module;
- if (sp->priv_addr)
- kfree(sp->priv_addr);
- kfree(root_speedo_dev);
- root_speedo_dev = next_dev;
- }
+ pci_unregister_driver (&eepro100_driver);
}
+
module_init(eepro100_init_module);
module_exit(eepro100_cleanup_module);
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 0b04615ef..03c69417a 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -251,6 +251,7 @@ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
extern int express_probe(struct net_device *dev);
static int eexp_open(struct net_device *dev);
static int eexp_close(struct net_device *dev);
+static void eexp_timeout(struct net_device *dev);
static struct net_device_stats *eexp_stats(struct net_device *dev);
static int eexp_xmit(struct sk_buff *buf, struct net_device *dev);
@@ -437,8 +438,6 @@ static int eexp_open(struct net_device *dev)
request_region(ioaddr+0x4000, 16, "EtherExpress shadow");
request_region(ioaddr+0x8000, 16, "EtherExpress shadow");
request_region(ioaddr+0xc000, 16, "EtherExpress shadow");
- dev->tbusy = 0;
- dev->interrupt = 0;
if (lp->width) {
printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
@@ -446,8 +445,8 @@ static int eexp_open(struct net_device *dev)
}
eexp_hw_init586(dev);
- dev->start = 1;
MOD_INC_USE_COUNT;
+ netif_start_queue(dev);
#if NET_DEBUG > 6
printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
#endif
@@ -465,9 +464,8 @@ static int eexp_close(struct net_device *dev)
int irq = dev->irq;
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
lp->started = 0;
scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
@@ -530,8 +528,7 @@ static void unstick_cu(struct net_device *dev)
outb(0,ioaddr+SIGNAL_CA);
}
}
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
else
{
@@ -546,13 +543,12 @@ static void unstick_cu(struct net_device *dev)
else
{
unsigned short txstatus = eexp_hw_lasttxstat(dev);
- if (dev->tbusy && !txstatus)
+ if (netif_queue_stopped(dev) && !txstatus)
{
printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
dev->name,status,txstatus);
eexp_hw_init586(dev);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
else
{
@@ -570,12 +566,47 @@ static void unstick_cu(struct net_device *dev)
printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
dev->name, status);
eexp_hw_init586(dev);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
}
}
+static void eexp_timeout(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+#ifdef CONFIG_SMP
+ unsigned long flags;
+#endif
+ int status;
+
+ disable_irq(dev->irq);
+
+ /*
+ * Best would be to use synchronize_irq(); spin_lock() here
+ * lets make it work first..
+ */
+
+#ifdef CONFIG_SMP
+ spin_lock_irqsave(&lp->lock, flags);
+#endif
+
+ status = scb_status(dev);
+ unstick_cu(dev);
+ printk(KERN_INFO "%s: transmit timed out, %s?", dev->name,
+ (SCB_complete(status)?"lost interrupt":
+ "board on fire"));
+ lp->stats.tx_errors++;
+ lp->last_tx = jiffies;
+ if (!SCB_complete(status)) {
+ scb_command(dev, SCB_CUabort);
+ outb(0,dev->base_addr+SIGNAL_CA);
+ }
+ netif_wake_queue(dev);
+#ifdef CONFIG_SMP
+ spin_unlock_irqrestore(&lp->lock, flags);
+#endif
+}
+
/*
* Called to transmit a packet, or to allow us to right ourselves
* if the kernel thinks we've died.
@@ -601,38 +632,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
#ifdef CONFIG_SMP
spin_lock_irqsave(&lp->lock, flags);
#endif
-
- /* If dev->tbusy is set, all our tx buffers are full but the kernel
- * is calling us anyway. Check that nothing bad is happening.
- */
- if (dev->tbusy) {
- int status = scb_status(dev);
- unstick_cu(dev);
- if ((jiffies - lp->last_tx) < HZ)
- {
-#ifdef CONFIG_SMP
- spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-
- return 1;
- }
- printk(KERN_INFO "%s: transmit timed out, %s?", dev->name,
- (SCB_complete(status)?"lost interrupt":
- "board on fire"));
- lp->stats.tx_errors++;
- dev->tbusy = 0;
- lp->last_tx = jiffies;
- if (!SCB_complete(status)) {
- scb_command(dev, SCB_CUabort);
- outb(0,dev->base_addr+SIGNAL_CA);
- }
- }
- if (test_and_set_bit(0,(void *)&dev->tbusy))
- {
- lp->stats.tx_dropped++;
- }
- else
{
unsigned short length = (ETH_ZLEN < buf->len) ? buf->len :
ETH_ZLEN;
@@ -756,8 +756,6 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
- dev->interrupt = 1;
-
status = scb_status(dev);
#if NET_DEBUG > 4
@@ -825,7 +823,6 @@ static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
- dev->interrupt = 0;
#if NET_DEBUG > 6
printk("%s: leaving eexp_irq()\n", dev->name);
#endif
@@ -1004,8 +1001,8 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
else
lp->tx_head += TX_BUF_SIZE;
if (lp->tx_head != lp->tx_reap)
- dev->tbusy = 0;
-
+ netif_wake_queue(dev);
+
if (LOCKUP16 || lp->width) {
/* Restart the CU so that the packet can actually
be transmitted. (Zoltan Szilagyi 10-12-96) */
@@ -1141,6 +1138,8 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
dev->hard_start_xmit = eexp_xmit;
dev->get_stats = eexp_stats;
dev->set_multicast_list = &eexp_set_multicast;
+ dev->tx_timeout = eexp_timeout;
+ dev->watchdog_timeo = 2*HZ;
ether_setup(dev);
return 0;
}
@@ -1205,7 +1204,7 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
unsigned short tx_block = lp->tx_reap;
unsigned short status;
- if ((!dev->tbusy) && lp->tx_head==lp->tx_reap)
+ if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
return 0x0000;
do
@@ -1254,8 +1253,7 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
lp->tx_reap = tx_block = TX_BUF_START;
else
lp->tx_reap = tx_block += TX_BUF_SIZE;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
while (lp->tx_reap != lp->tx_head);
@@ -1298,8 +1296,7 @@ static void eexp_hw_txrestart(struct net_device *dev)
{
printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
eexp_hw_init586(dev);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
return;
}
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index c7dfb7a65..1c546b4d1 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -15,8 +15,42 @@
Information and updates available at
http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
+
+
+
+ Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the SMC "EPIC/100", the SMC
+single-chip Ethernet controllers for PCI. This chip is used on
+the SMC EtherPower II boards.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board. The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+IVb. References
+
+http://www.smsc.com/main/datasheets/83c171.pdf
+http://www.smsc.com/main/datasheets/83c175.pdf
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.national.com/pf/DP/DP83840A.html
+
+IVc. Errata
+
*/
+
+
static const char *version =
"epic100.c:v1.04 8/23/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
@@ -56,7 +90,6 @@ static int max_interrupt_work = 10;
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
-#define PCI_SUPPORT_VER2
#include <linux/delay.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
@@ -72,6 +105,9 @@ static int max_interrupt_work = 10;
#define RUN_AT(x) (jiffies + (x))
+#define EPIC100_MODULE_NAME "epic100"
+#define PFX EPIC100_MODULE_NAME ": "
+
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
MODULE_PARM(debug, "i");
@@ -79,7 +115,6 @@ MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(max_interrupt_work, "i");
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
/* The I/O extent. */
#define EPIC_TOTAL_SIZE 0x100
@@ -87,82 +122,88 @@ MODULE_PARM(max_interrupt_work, "i");
#define epic_debug debug
static int epic_debug = 1;
-/*
- Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the SMC "EPIC/100", the SMC
-single-chip Ethernet controllers for PCI. This chip is used on
-the SMC EtherPower II boards.
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board. The system BIOS will assign the
-PCI INTA signal to a (preferably otherwise unused) system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
-
-III. Driver operation
+/* The rest of these values should never change. */
-IIIa. Ring buffers
-IVb. References
+enum pci_flags_bit {
+ PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+ PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
-http://www.smsc.com/main/datasheets/83c171.pdf
-http://www.smsc.com/main/datasheets/83c175.pdf
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-http://www.national.com/pf/DP/DP83840A.html
-IVc. Errata
+typedef enum {
+ SMSC_83C170,
+ SMSC_83C175,
+} chip_t;
-*/
-/* The rest of these values should never change. */
+struct epic100_chip_info {
+ const char *name;
+};
-static struct net_device *epic_probe1(struct pci_dev *pdev, long ioaddr, int irq,
- int chip_id, int card_idx);
-enum pci_flags_bit {
- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+/* indexed by chip_t */
+static struct epic100_chip_info epic100_chip_info[] __devinitdata = {
+ { "SMSC EPIC/100 83c170" },
+ { "SMSC EPIC/C 83c175" },
};
-struct chip_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, pci_flags;
- int io_size, min_latency;
- struct net_device *(*probe1)(struct pci_dev *pdev,
- long ioaddr, int irq, int chip_idx,
- int fnd_cnt);
-} chip_tbl[] = {
- {"SMSC EPIC/100 83c170", 0x10B8, 0x0005, 0x7fff,
- PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
- {"SMSC EPIC/C 83c175", 0x10B8, 0x0006, 0x7fff,
- PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
- {0,},
+
+static struct pci_device_id epic100_pci_tbl[] __devinitdata = {
+ { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170, },
+ { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C175, },
+ { 0,},
};
+MODULE_DEVICE_TABLE (pci, epic100_pci_tbl);
+
/* Offsets to registers, using the (ugh) SMC names. */
enum epic_registers {
- COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14,
- PCIBurstCnt=0x18,
- TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28, /* Rx error counters. */
- MIICtrl=0x30, MIIData=0x34, MIICfg=0x38,
- LAN0=64, /* MAC address. */
- MC0=80, /* Multicast filter table. */
- RxCtrl=96, TxCtrl=112, TxSTAT=0x74,
- PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC,
+ COMMAND = 0,
+ INTSTAT = 4,
+ INTMASK = 8,
+ GENCTL = 0x0C,
+ NVCTL = 0x10,
+ EECTL = 0x14,
+ PCIBurstCnt = 0x18,
+ TEST1 = 0x1C,
+ CRCCNT = 0x20,
+ ALICNT = 0x24,
+ MPCNT = 0x28, /* Rx error counters. */
+ MIICtrl = 0x30,
+ MIIData = 0x34,
+ MIICfg = 0x38,
+ LAN0 = 64, /* MAC address. */
+ MC0 = 80, /* Multicast filter table. */
+ RxCtrl = 96,
+ TxCtrl = 112,
+ TxSTAT = 0x74,
+ PRxCDAR = 0x84,
+ RxSTAT = 0xA4,
+ EarlyRx = 0xB0,
+ PTxCDAR = 0xC4,
+ TxThresh = 0xDC,
};
+
/* Interrupt register bits, using my own meaningful names. */
enum IntrStatus {
- TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000,
- PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000,
- RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100,
- TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
- RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
+ TxIdle = 0x40000,
+ RxIdle = 0x20000,
+ IntrSummary = 0x010000,
+ PCIBusErr170 = 0x7000,
+ PCIBusErr175 = 0x1000,
+ PhyEvent175 = 0x8000,
+ RxStarted = 0x0800,
+ RxEarlyWarn = 0x0400,
+ CntFull = 0x0200,
+ TxUnderrun = 0x0100,
+ TxEmpty = 0x0080,
+ TxDone = 0x0020, RxError = 0x0010,
+ RxOverflow = 0x0008,
+ RxFull = 0x0004,
+ RxHeader = 0x0002,
+ RxDone = 0x0001,
};
/* The EPIC100 Rx and Tx buffer descriptors. */
@@ -203,7 +244,7 @@ struct epic_private {
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- u8 pci_bus, pci_dev_fn; /* PCI bus location. */
+ struct pci_dev *pdev;
u16 chip_id;
struct net_device_stats stats;
@@ -241,194 +282,9 @@ static int epic_close(struct net_device *dev);
static struct net_device_stats *epic_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-
-/* A list of all installed EPIC devices, for removing the driver module. */
-static struct net_device *root_epic_dev = NULL;
-
-#ifndef CARDBUS
-static int __init epic100_probe(void)
-{
- int cards_found = 0;
- int chip_idx, irq;
- u16 pci_command, new_command;
- unsigned char pci_bus, pci_device_fn;
- struct net_device *dev;
-
- struct pci_dev *pcidev = NULL;
- while ((pcidev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pcidev))
- != NULL) {
- long pci_ioaddr = pcidev->resource[0].start;
- int vendor = pcidev->vendor;
- int device = pcidev->device;
-
- for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == chip_tbl[chip_idx].vendor_id
- && (device & chip_tbl[chip_idx].device_id_mask) ==
- chip_tbl[chip_idx].device_id)
- break;
- if (chip_tbl[chip_idx].vendor_id == 0 /* Compiled out! */
- || check_region(pci_ioaddr, chip_tbl[chip_idx].io_size))
- continue;
- pci_bus = pcidev->bus->number;
- pci_device_fn = pcidev->devfn;
- irq = pcidev->irq;
-
- /* EPIC-specific code: Soft-reset the chip ere setting as master. */
- outl(0x0001, pci_ioaddr + GENCTL);
-
- /* Activate the card: fix for brain-damaged Win98 BIOSes. */
- pci_read_config_word(pcidev, PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled Ethernet"
- " device %4.4x-%4.4x."
- " Updating PCI command %4.4x->%4.4x.\n",
- vendor, device, pci_command, new_command);
- pci_write_config_word(pcidev, PCI_COMMAND, new_command);
- }
-
- dev = chip_tbl[chip_idx].probe1(pcidev, pci_ioaddr, irq,
- chip_idx, cards_found);
-
- /* Check the latency timer. */
- if (dev) {
- u8 pci_latency;
- pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < chip_tbl[chip_idx].min_latency) {
- printk(KERN_INFO " PCI latency timer (CFLT) value of %d is "
- "unreasonably low, setting to %d.\n", pci_latency,
- chip_tbl[chip_idx].min_latency);
- pci_write_config_byte(pcidev, PCI_LATENCY_TIMER,
- chip_tbl[chip_idx].min_latency);
- }
- dev = 0;
- cards_found++;
- }
- }
-
- return cards_found ? 0 : -ENODEV;
-}
-#endif /* not CARDBUS */
-
-static struct net_device *epic_probe1(struct pci_dev *pdev, long ioaddr, int irq,
- int chip_idx, int card_idx)
-{
- struct epic_private *ep;
- int i, option = 0, duplex = 0;
- struct net_device *dev;
-
-// FIXME if (dev && dev->mem_start) {
-// option = dev->mem_start;
-// duplex = (dev->mem_start & 16) ? 1 : 0;
-// }
-// else
- if (card_idx >= 0 && card_idx < MAX_UNITS) {
- if (options[card_idx] >= 0)
- option = options[card_idx];
- if (full_duplex[card_idx] >= 0)
- duplex = full_duplex[card_idx];
- }
-
- dev = init_etherdev(NULL, 0);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
- printk(KERN_INFO "%s: SMC EPIC/100 at %#lx, IRQ %d, ",
- dev->name, ioaddr, dev->irq);
-
- /* Bring the chip out of low-power mode. */
- outl(0x4200, ioaddr + GENCTL);
- /* Magic?! If we don't set this bit the MII interface won't work. */
- outl(0x0008, ioaddr + TEST1);
-
- /* Turn on the MII transceiver. */
- outl(0x12, ioaddr + MIICfg);
- if (chip_idx == 1)
- outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
- outl(0x0200, ioaddr + GENCTL);
-
- /* This could also be read from the EEPROM. */
- for (i = 0; i < 3; i++)
- ((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4);
-
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x.\n", dev->dev_addr[i]);
-
- if (epic_debug > 1) {
- printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name);
- for (i = 0; i < 64; i++)
- printk(" %4.4x%s", read_eeprom(ioaddr, i),
- i % 16 == 15 ? "\n" : "");
- }
-
- /* We do a request_region() to register /proc/ioports info. */
- request_region(ioaddr, EPIC_TOTAL_SIZE, dev->name);
-
- /* The data structures must be quadword aligned. */
- ep = kmalloc(sizeof(*ep), GFP_KERNEL | GFP_DMA);
- memset(ep, 0, sizeof(*ep));
- dev->priv = ep;
-
- ep->next_module = root_epic_dev;
- root_epic_dev = dev;
-
- ep->lock = SPIN_LOCK_UNLOCKED;
- ep->pci_bus = pdev->bus->number;
- ep->pci_dev_fn = pdev->devfn;
- ep->chip_id = pdev->device;
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later, but
- takes too much time. */
- {
- int phy, phy_idx;
- for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys);
- phy++) {
- int mii_status = mdio_read(ioaddr, phy, 1);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- ep->phys[phy_idx++] = phy;
- printk(KERN_INFO "%s: MII transceiver #%d control "
- "%4.4x status %4.4x.\n"
- KERN_INFO "%s: Autonegotiation advertising %4.4x "
- "link partner %4.4x.\n",
- dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status,
- dev->name, mdio_read(ioaddr, phy, 4),
- mdio_read(ioaddr, phy, 5));
- }
- }
- if (phy_idx == 0) {
- printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n",
- dev->name);
- /* Use the known PHY address of the EPII. */
- ep->phys[0] = 3;
- }
- }
- /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
- if (ep->chip_id == 6)
- outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL);
- outl(0x0008, ioaddr + GENCTL);
- /* The lower four bits are the media type. */
- ep->force_fd = duplex;
- ep->default_port = option;
- if (ep->default_port)
- ep->medialock = 1;
-
- /* The Epic-specific entries in the device structure. */
- dev->open = &epic_open;
- dev->hard_start_xmit = &epic_start_xmit;
- dev->stop = &epic_close;
- dev->get_stats = &epic_get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &mii_ioctl;
- dev->tx_timeout = epic_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- return dev;
-}
-
/* Serial EEPROM section. */
/* EEPROM_Ctrl bits. */
@@ -527,13 +383,15 @@ epic_open(struct net_device *dev)
int mii_reg5;
ep->full_duplex = ep->force_fd;
+ MOD_INC_USE_COUNT;
+
/* Soft reset the chip. */
outl(0x4001, ioaddr + GENCTL);
- if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev))
- return -EAGAIN;
-
- MOD_INC_USE_COUNT;
+ if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, EPIC100_MODULE_NAME, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
epic_init_ring(dev);
@@ -581,8 +439,6 @@ epic_open(struct net_device *dev)
set_rx_mode(dev);
outl(0x000A, ioaddr + COMMAND);
- netif_start_queue(dev);
-
/* Enable interrupts by setting the interrupt mask. */
outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170)
| CntFull | TxUnderrun | TxDone
@@ -595,10 +451,12 @@ epic_open(struct net_device *dev)
dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL),
ep->full_duplex ? "full" : "half");
+ netif_start_queue(dev);
+
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
init_timer(&ep->timer);
- ep->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ ep->timer.expires = RUN_AT(3*HZ); /* 3 sec. */
ep->timer.data = (unsigned long)dev;
ep->timer.function = &epic_timer; /* timer handler */
add_timer(&ep->timer);
@@ -606,6 +464,7 @@ epic_open(struct net_device *dev)
return 0;
}
+
/* Reset the chip to recover from a PCI transaction error.
This may occur at interrupt time. */
static void epic_pause(struct net_device *dev)
@@ -613,6 +472,8 @@ static void epic_pause(struct net_device *dev)
long ioaddr = dev->base_addr;
struct epic_private *ep = (struct epic_private *)dev->priv;
+ netif_stop_queue (dev);
+
/* Disable interrupts by clearing the interrupt mask. */
outl(0x00000000, ioaddr + INTMASK);
/* Stop the chip's Tx and Rx DMA processes. */
@@ -671,11 +532,13 @@ static void epic_restart(struct net_device *dev)
| CntFull | TxUnderrun | TxDone
| RxError | RxOverflow | RxFull | RxHeader | RxDone,
ioaddr + INTMASK);
+
+ netif_start_queue (dev);
+
printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
" interrupt %4.4x.\n",
dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL),
inl(ioaddr + INTSTAT));
- return;
}
static void epic_timer(unsigned long data)
@@ -738,7 +601,8 @@ static void epic_tx_timeout(struct net_device *dev)
dev->trans_start = jiffies;
ep->stats.tx_errors++;
- return;
+
+ netif_start_queue (dev);
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -790,6 +654,8 @@ epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
int entry;
u32 flag;
+ netif_stop_queue (dev);
+
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
@@ -806,13 +672,10 @@ epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
flag = 0x10; /* No interrupt */
- netif_start_queue(dev);
} else if (ep->cur_tx - ep->dirty_tx == TX_RING_SIZE/2) {
flag = 0x14; /* Tx-done intr. */
- netif_start_queue(dev);
} else if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE - 2) {
flag = 0x10; /* No Tx-done intr. */
- netif_start_queue(dev);
} else {
/* Leave room for two additional entries. */
flag = 0x14; /* Tx-done intr. */
@@ -826,6 +689,10 @@ epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
outl(0x0004, dev->base_addr + COMMAND);
dev->trans_start = jiffies;
+
+ if (! ep->tx_full)
+ netif_start_queue (dev);
+
if (epic_debug > 4)
printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
"flag %2.2x Tx status %8.8x.\n",
@@ -895,7 +762,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
/* Free the original skb. */
- DEV_FREE_SKB(ep->tx_skbuff[entry]);
+ dev_kfree_skb_irq(ep->tx_skbuff[entry]);
ep->tx_skbuff[entry] = 0;
}
@@ -908,12 +775,16 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
#endif
if (ep->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->flags) &&
+ netif_queue_stopped(dev) &&
dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) {
/* The ring is no longer full, clear tbusy. */
ep->tx_full = 0;
- netif_wake_queue (dev);
}
+
+ if (ep->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
ep->dirty_tx = dirty_tx;
}
@@ -963,6 +834,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
spin_unlock (&ep->lock);
}
+
static int epic_rx(struct net_device *dev)
{
struct epic_private *ep = (struct epic_private *)dev->priv;
@@ -1039,6 +911,7 @@ static int epic_rx(struct net_device *dev)
return work_done;
}
+
static int epic_close(struct net_device *dev)
{
long ioaddr = dev->base_addr;
@@ -1073,12 +946,12 @@ static int epic_close(struct net_device *dev)
ep->rx_ring[i].buflength = 0;
ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
if (skb) {
- DEV_FREE_SKB(skb);
+ dev_kfree_skb(skb);
}
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (ep->tx_skbuff[i])
- DEV_FREE_SKB(ep->tx_skbuff[i]);
+ dev_kfree_skb(ep->tx_skbuff[i]);
ep->tx_skbuff[i] = 0;
}
@@ -1091,12 +964,13 @@ static int epic_close(struct net_device *dev)
return 0;
}
+
static struct net_device_stats *epic_get_stats(struct net_device *dev)
{
struct epic_private *ep = (struct epic_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (test_bit(LINK_STATE_START, &dev->state)) {
+ if (netif_running(dev)) {
/* Update the error counts. */
ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
@@ -1106,6 +980,7 @@ static struct net_device_stats *epic_get_stats(struct net_device *dev)
return &ep->stats;
}
+
/* Set or clear the multicast filter for this adaptor.
Note that we only use exclusion around actually queueing the
new frame, not around filling ep->setup_frame. This is non-deterministic
@@ -1172,6 +1047,7 @@ static void set_rx_mode(struct net_device *dev)
return;
}
+
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
long ioaddr = dev->base_addr;
@@ -1182,12 +1058,12 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f;
/* Fall Through */
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- if (! test_bit(LINK_STATE_START, &dev->state)) {
+ if (! netif_running(dev)) {
outl(0x0200, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
}
data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
- if (! test_bit(LINK_STATE_START, &dev->state)) {
+ if (! netif_running(dev)) {
#ifdef notdef
outl(0x0008, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
@@ -1197,12 +1073,12 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
if (!suser())
return -EPERM;
- if (! test_bit(LINK_STATE_START, &dev->state)) {
+ if (! netif_running(dev)) {
outl(0x0200, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
}
mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
- if (! test_bit(LINK_STATE_START, &dev->state)) {
+ if (! netif_running(dev)) {
#ifdef notdef
outl(0x0008, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
@@ -1214,131 +1090,214 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
}
-
-#ifdef CARDBUS
-
-#include <pcmcia/driver_ops.h>
-static dev_node_t *epic_attach(dev_locator_t *loc)
+static int __devinit epic100_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
+ struct epic_private *ep;
+ int i, option = 0, duplex = 0, irq, chip_idx;
struct net_device *dev;
- u16 dev_id;
- u32 io;
- u8 bus, devfn, irq;
- struct pci_dev *pdev;
-
- if (loc->bus != LOC_PCI) return NULL;
- pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
- if (!pdev) return NULL;
- printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn);
- io = pdev->resource[0].start;
+ long ioaddr;
+ static int card_idx = -1;
+
+ chip_idx = ent->driver_data;
+
+ ioaddr = pci_resource_start (pdev, 0);
+ if (!ioaddr)
+ return -ENODEV;
+
irq = pdev->irq;
- dev_id = pdev->device;
- io &= ~3;
- if (io == 0 || irq == 0) {
- printk(KERN_ERR "The EPIC/C CardBus Ethernet interface was not "
- "assigned an %s.\n" KERN_ERR " It will not be activated.\n",
- io == 0 ? "I/O address" : "IRQ");
- return NULL;
- }
- dev = epic_probe1(bus, devfn, io, irq, 2, -1);
- if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
- node->major = node->minor = 0;
- node->next = NULL;
- MOD_INC_USE_COUNT;
- return node;
- }
- return NULL;
-}
+ if (!irq)
+ return -ENODEV;
-static void epic_suspend(dev_node_t *node)
-{
- struct net_device **devp, **next;
- printk(KERN_INFO "epic_suspend(%s)\n", node->dev_name);
- for (devp = &root_epic_dev; *devp; devp = next) {
- next = &((struct epic_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
- }
- if (*devp) {
- long ioaddr = (*devp)->base_addr;
- epic_pause(*devp);
- /* Put the chip into low-power mode. */
- outl(0x0008, ioaddr + GENCTL);
+ /* We do a request_region() to register /proc/ioports info. */
+ if (!request_region(ioaddr, EPIC_TOTAL_SIZE, EPIC100_MODULE_NAME))
+ return -EBUSY;
+
+ pci_enable_device (pdev);
+
+ /* EPIC-specific code: Soft-reset the chip ere setting as master. */
+ outl(0x0001, ioaddr + GENCTL);
+
+ pci_set_master (pdev);
+
+// FIXME if (dev && dev->mem_start) {
+// option = dev->mem_start;
+// duplex = (dev->mem_start & 16) ? 1 : 0;
+// }
+// else
+
+ card_idx++;
+ if (card_idx >= 0 && card_idx < MAX_UNITS) {
+ if (options[card_idx] >= 0)
+ option = options[card_idx];
+ if (full_duplex[card_idx] >= 0)
+ duplex = full_duplex[card_idx];
}
-}
-static void epic_resume(dev_node_t *node)
-{
- struct net_device **devp, **next;
- printk(KERN_INFO "epic_resume(%s)\n", node->dev_name);
- for (devp = &root_epic_dev; *devp; devp = next) {
- next = &((struct epic_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
+
+ dev = init_etherdev(NULL, sizeof (*ep));
+ if (!dev)
+ goto err_out_free_region;
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
+ dev->name, epic100_chip_info[chip_idx].name,
+ ioaddr, dev->irq);
+
+ /* Bring the chip out of low-power mode. */
+ outl(0x4200, ioaddr + GENCTL);
+ /* Magic?! If we don't set this bit the MII interface won't work. */
+ outl(0x0008, ioaddr + TEST1);
+
+ /* Turn on the MII transceiver. */
+ outl(0x12, ioaddr + MIICfg);
+ if (chip_idx == 1)
+ outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+ outl(0x0200, ioaddr + GENCTL);
+
+ /* This could also be read from the EEPROM. */
+ for (i = 0; i < 3; i++)
+ ((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4);
+
+ for (i = 0; i < 5; i++)
+ printk("%2.2x:", dev->dev_addr[i]);
+ printk("%2.2x.\n", dev->dev_addr[i]);
+
+ if (epic_debug > 1) {
+ printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name);
+ for (i = 0; i < 64; i++)
+ printk(" %4.4x%s", read_eeprom(ioaddr, i),
+ i % 16 == 15 ? "\n" : "");
}
- if (*devp) {
- epic_restart(*devp);
+
+ /* The data structures must be quadword aligned,
+ * init_etherdev ensures this */
+ ep = dev->priv;
+ memset(ep, 0, sizeof(*ep));
+
+ ep->lock = SPIN_LOCK_UNLOCKED;
+ ep->chip_id = pdev->device;
+ ep->pdev = pdev;
+ pdev->driver_data = dev;
+
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later, but
+ takes too much time. */
+ {
+ int phy, phy_idx;
+ for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys);
+ phy++) {
+ int mii_status = mdio_read(ioaddr, phy, 1);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ ep->phys[phy_idx++] = phy;
+ printk(KERN_INFO "%s: MII transceiver #%d control "
+ "%4.4x status %4.4x.\n"
+ KERN_INFO "%s: Autonegotiation advertising %4.4x "
+ "link partner %4.4x.\n",
+ dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status,
+ dev->name, mdio_read(ioaddr, phy, 4),
+ mdio_read(ioaddr, phy, 5));
+ }
+ }
+ if (phy_idx == 0) {
+ printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n",
+ dev->name);
+ /* Use the known PHY address of the EPII. */
+ ep->phys[0] = 3;
+ }
}
+
+ /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
+ if (ep->chip_id == 6)
+ outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL);
+ outl(0x0008, ioaddr + GENCTL);
+
+ /* The lower four bits are the media type. */
+ ep->force_fd = duplex;
+ ep->default_port = option;
+ if (ep->default_port)
+ ep->medialock = 1;
+
+ /* The Epic-specific entries in the device structure. */
+ dev->open = epic_open;
+ dev->hard_start_xmit = epic_start_xmit;
+ dev->stop = epic_close;
+ dev->get_stats = epic_get_stats;
+ dev->set_multicast_list = set_rx_mode;
+ dev->do_ioctl = mii_ioctl;
+ dev->tx_timeout = epic_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ netif_stop_queue (dev);
+
+ return 0;
+
+err_out_free_region:
+ release_region(ioaddr, EPIC_TOTAL_SIZE);
+ return -ENODEV;
}
-static void epic_detach(dev_node_t *node)
+
+
+static void __devexit epic100_remove_one (struct pci_dev *pdev)
{
- struct net_device **devp, **next;
- printk(KERN_INFO "epic_detach(%s)\n", node->dev_name);
- for (devp = &root_epic_dev; *devp; devp = next) {
- next = &((struct epic_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
- }
- if (*devp) {
- unregister_netdev(*devp);
- kfree(*devp);
- *devp = *next;
- kfree(node);
- MOD_DEC_USE_COUNT;
- }
+ struct net_device *dev = pdev->driver_data;
+
+ unregister_netdev(dev);
+ release_region(dev->base_addr, EPIC_TOTAL_SIZE);
+ kfree(dev);
}
-struct driver_operations epic_ops = {
- "epic_cb", epic_attach, epic_suspend, epic_resume, epic_detach
-};
-#endif /* Cardbus support */
+static void epic100_suspend (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ long ioaddr = dev->base_addr;
+
+ epic_pause(dev);
+ /* Put the chip into low-power mode. */
+ outl(0x0008, ioaddr + GENCTL);
+}
-static int __init epic100_init_module(void)
+static void epic100_resume (struct pci_dev *pdev)
{
- if (epic_debug)
- printk(KERN_INFO "%s", version);
+ struct net_device *dev = pdev->driver_data;
-#ifdef CARDBUS
- register_driver(&epic_ops);
- return 0;
-#else
- return epic100_probe();
-#endif
+ epic_restart (dev);
}
-static void __exit epic100_cleanup_module(void)
+
+static struct pci_driver epic100_driver = {
+ name: EPIC100_MODULE_NAME,
+ id_table: epic100_pci_tbl,
+ probe: epic100_init_one,
+ remove: epic100_remove_one,
+ suspend: epic100_suspend,
+ resume: epic100_resume,
+};
+
+
+static int __init epic100_init (void)
{
- struct net_device *next_dev;
+ printk (KERN_INFO "%s", version);
+
+ if (pci_register_driver (&epic100_driver) > 0)
+ return 0;
+
+ pci_unregister_driver (&epic100_driver);
+ return -ENODEV;
+}
-#ifdef CARDBUS
- unregister_driver(&epic_ops);
-#endif
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_epic_dev) {
- struct epic_private *ep = (struct epic_private *)root_epic_dev->priv;
- next_dev = ep->next_module;
- unregister_netdev(root_epic_dev);
- release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);
- kfree(root_epic_dev);
- root_epic_dev = next_dev;
- kfree(ep);
- }
+static void __exit epic100_cleanup (void)
+{
+ pci_unregister_driver (&epic100_driver);
}
-module_init(epic100_init_module);
-module_exit(epic100_cleanup_module);
+
+module_init(epic100_init);
+module_exit(epic100_cleanup);
/*
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index b1af7e5dc..502936cab 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -158,6 +158,8 @@ static char *version =
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -168,26 +170,7 @@ static char *version =
#include <asm/io.h>
#include <asm/dma.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#endif
-#if LINUX_VERSION_CODE < 0x20138
-#define test_and_set_bit(val,addr) set_bit(val,addr)
-#endif
-
-#if LINUX_VERSION_CODE < 0x020100
-typedef struct enet_statistics eth16i_stats_type;
-#else
-typedef struct net_device_stats eth16i_stats_type;
-#endif
/* Few macros */
#define BIT(a) ( (1 << (a)) )
@@ -371,12 +354,14 @@ typedef struct net_device_stats eth16i_stats_type;
#define RESET ID_ROM_0
/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] =
- { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
+static unsigned int eth16i_portlist[] = {
+ 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
+};
-static unsigned int eth32i_portlist[] =
- { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
+static unsigned int eth32i_portlist[] = {
+ 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+ 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
+};
/* This is the Interrupt lookup table for Eth16i card */
static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 };
@@ -399,7 +384,7 @@ static unsigned int eth16i_debug = ETH16I_DEBUG;
/* Information for each board */
struct eth16i_local {
- eth16i_stats_type stats;
+ struct net_device_stats stats;
unsigned char tx_started;
unsigned char tx_buf_busy;
unsigned short tx_queue; /* Number of packets in transmit buffer */
@@ -409,6 +394,7 @@ struct eth16i_local {
unsigned long tx_buffered_packets;
unsigned long tx_buffered_bytes;
unsigned long col_16;
+ spinlock_t lock;
};
/* Function prototypes */
@@ -429,8 +415,10 @@ static int eth16i_open(struct net_device *dev);
static int eth16i_close(struct net_device *dev);
static int eth16i_tx(struct sk_buff *skb, struct net_device *dev);
static void eth16i_rx(struct net_device *dev);
+static void eth16i_timeout(struct net_device *dev);
static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void eth16i_reset(struct net_device *dev);
+static void eth16i_timeout(struct net_device *dev);
static void eth16i_skip_packet(struct net_device *dev);
static void eth16i_multicast(struct net_device *dev);
static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
@@ -444,18 +432,10 @@ static int eth16i_set_irq(struct net_device *dev);
static ushort eth16i_parse_mediatype(const char* s);
#endif
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev);
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
static char *cardname = "ICL EtherTeam 16i/32";
-#ifdef HAVE_DEVLIST
-
-/* Support for alternate probe manager */
-/struct netdev_entry eth16i_drv =
- {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list};
-
-#else /* Not HAVE_DEVLIST */
-
int __init eth16i_probe(struct net_device *dev)
{
int i;
@@ -488,10 +468,11 @@ int __init eth16i_probe(struct net_device *dev)
return ENODEV;
}
-#endif /* Not HAVE_DEVLIST */
static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
{
+ struct eth16i_local *lp;
+
static unsigned version_printed = 0;
boot = 1; /* To inform initilization that we are in boot probe */
@@ -535,17 +516,6 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
printk(KERN_INFO "%s", version);
dev->base_addr = ioaddr;
-
-#if 0
- if(dev->irq) {
- if(eth16i_set_irq(dev)) {
- dev->irq = eth16i_get_irq(ioaddr);
- }
-
- }
- else {
-#endif
-
dev->irq = eth16i_get_irq(ioaddr);
/* Try to obtain interrupt vector */
@@ -556,10 +526,6 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
return -EAGAIN;
}
-#if 0
- irq2dev_map[dev->irq] = dev;
-#endif
-
printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
dev->name, cardname, ioaddr, dev->irq);
@@ -583,12 +549,16 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
}
memset(dev->priv, 0, sizeof(struct eth16i_local));
-
dev->open = eth16i_open;
dev->stop = eth16i_close;
dev->hard_start_xmit = eth16i_tx;
dev->get_stats = eth16i_get_stats;
- dev->set_multicast_list = &eth16i_multicast;
+ dev->set_multicast_list = eth16i_multicast;
+ dev->tx_timeout = eth16i_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ lp = (struct eth16i_local *)dev->priv;
+ spin_lock_init(&lp->lock);
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
@@ -1004,10 +974,7 @@ static int eth16i_open(struct net_device *dev)
/* Turn on interrupts*/
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
@@ -1023,9 +990,8 @@ static int eth16i_close(struct net_device *dev)
/* Turn off interrupts*/
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
lp->open_time = 0;
/* Disable transmit and receive */
@@ -1042,153 +1008,115 @@ static int eth16i_close(struct net_device *dev)
return 0;
}
-static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+static void eth16i_timeout(struct net_device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
- int status = 0;
+ /*
+ If we get here, some higher level has decided that
+ we are broken. There should really be a "kick me"
+ function call instead.
+ */
- if(dev->tbusy) {
-
- /*
- If we get here, some higher level has decided that
- we are broken. There should really be a "kick me"
- function call instead.
- */
-
- int tickssofar = jiffies - dev->trans_start;
- if(tickssofar < TX_TIMEOUT)
- return 1;
-
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
- printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
- dev->name,
- inw(ioaddr + TX_STATUS_REG),
- (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
+ dev->name,
+ inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
"IRQ conflict" : "network cable problem");
- dev->trans_start = jiffies;
-
- /* Let's dump all registers */
- if(eth16i_debug > 0) {
- printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
- dev->name, inb(ioaddr + 0),
- inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4),
- inb(ioaddr + 5),
- inb(ioaddr + 6), inb(ioaddr + 7));
+ dev->trans_start = jiffies;
- printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
- dev->name, inb(ioaddr + TRANSMIT_START_REG),
- inb(ioaddr + COL_16_REG));
+ /* Let's dump all registers */
+ if(eth16i_debug > 0) {
+ printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+ dev->name, inb(ioaddr + 0),
+ inb(ioaddr + 1), inb(ioaddr + 2),
+ inb(ioaddr + 3), inb(ioaddr + 4),
+ inb(ioaddr + 5),
+ inb(ioaddr + 6), inb(ioaddr + 7));
+ printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
+ dev->name, inb(ioaddr + TRANSMIT_START_REG),
+ inb(ioaddr + COL_16_REG));
printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
- printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
- printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
-
- }
-
- lp->stats.tx_errors++;
-
- eth16i_reset(dev);
-
- dev->trans_start = jiffies;
-
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+ printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
+ printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
}
+ lp->stats.tx_errors++;
+ eth16i_reset(dev);
+ dev->trans_start = jiffies;
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ netif_wake_queue(dev);
+}
- /*
- If some higher layer thinks we've missed an tx-done interrupt
- we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- itself
- */
-
- if(skb == NULL) {
-#if LINUX_VERSION_CODE < 0x020100
- dev_tint(dev);
-#endif
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name);
- return 0;
- }
+static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int status = 0;
+ ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+ unsigned long flags;
- /* Block a timer based transmitter from overlapping.
- This could better be done with atomic_swap(1, dev->tbusy),
- but set_bit() works as well. */
- set_bit(0, (void *)&lp->tx_buf_busy);
-
+ netif_stop_queue(dev);
+
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+ /* We would be better doing the disable_irq tricks the 3c509 does,
+ that would make this suck a lot less */
+
+ spin_lock_irqsave(&lp->lock, flags);
- if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- status = -1;
- }
+ if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
+ }
else {
- ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
+ outw(length, ioaddr + DATAPORT);
- if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
- }
+ if( ioaddr < 0x1000 )
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
else {
- outw(length, ioaddr + DATAPORT);
-
- if( ioaddr < 0x1000 )
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
- else {
- unsigned char frag = length % 4;
-
- outsl(ioaddr + DATAPORT, buf, length >> 2);
-
- if( frag != 0 ) {
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
- if( frag == 3 )
- outsw(ioaddr + DATAPORT,
- (buf + (length & 0xFFFC) + 2), 1);
- }
+ unsigned char frag = length % 4;
+ outsl(ioaddr + DATAPORT, buf, length >> 2);
+ if( frag != 0 ) {
+ outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+ if( frag == 3 )
+ outsw(ioaddr + DATAPORT,
+ (buf + (length & 0xFFFC) + 2), 1);
}
-
- lp->tx_buffered_packets++;
- lp->tx_buffered_bytes = length;
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
- }
-
- lp->tx_buf_busy = 0;
-
- if(lp->tx_started == 0) {
- /* If the transmitter is idle..always trigger a transmit */
- outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- dev->trans_start = jiffies;
- lp->tx_started = 1;
- dev->tbusy = 0;
- }
- else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
- /* There is still more room for one more packet in tx buffer */
- dev->tbusy = 0;
}
-
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
- /* Turn TX interrupts back on */
- /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
- status = 0;
- }
+ lp->tx_buffered_packets++;
+ lp->tx_buffered_bytes = length;
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+ }
+ lp->tx_buf_busy = 0;
-#if LINUX_VERSION_CODE >= 0x020100
+ if(lp->tx_started == 0) {
+ /* If the transmitter is idle..always trigger a transmit */
+ outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
+ lp->tx_started = 1;
+ netif_wake_queue(dev);
+ }
+ else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+ /* There is still more room for one more packet in tx buffer */
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ /* Turn TX interrupts back on */
+ /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
+ status = 0;
dev_kfree_skb(skb);
-#else
- dev_kfree_skb(skb, FREE_WRITE);
-#endif
-
- return status;
+ return 0;
}
static void eth16i_rx(struct net_device *dev)
@@ -1284,51 +1212,23 @@ static void eth16i_rx(struct net_device *dev)
break;
} /* while */
-
-#if 0
- {
- int i;
-
- for(i = 0; i < 20; i++) {
- if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) ==
- RX_BUFFER_EMPTY)
- break;
- inw(ioaddr + DATAPORT);
- outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
- }
-
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name);
- }
-#endif
-
- return;
}
static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct eth16i_local *lp;
- int ioaddr = 0,
- status;
+ int ioaddr = 0, status;
- if(dev == NULL) {
- printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq);
- return;
- }
+ ioaddr = dev->base_addr;
+ lp = (struct eth16i_local *)dev->priv;
/* Turn off all interrupts from adapter */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- set_bit(0, (void *)&dev->tbusy); /* Set the device busy so that */
/* eth16i_tx wont be called */
+ spin_lock(&lp->lock);
- if(dev->interrupt)
- printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
-
- ioaddr = dev->base_addr;
- lp = (struct eth16i_local *)dev->priv;
status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
@@ -1386,13 +1286,11 @@ static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->tx_queue = 0;
lp->tx_queue_len = 0;
lp->tx_started = 1;
- dev->trans_start = jiffies;
- mark_bh(NET_BH);
}
else {
lp->tx_started = 0;
- mark_bh(NET_BH);
}
+ netif_wake_queue(dev);
}
}
@@ -1401,16 +1299,16 @@ static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
eth16i_rx(dev); /* We have packet in receive buffer */
}
- dev->interrupt = 0;
-
/* Turn interrupts back on */
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
/* There is still more room for one more packet in tx buffer */
- dev->tbusy = 0;
+ netif_wake_queue(dev);
}
+ spin_unlock(&lp->lock);
+
return;
}
@@ -1442,10 +1340,6 @@ static void eth16i_reset(struct net_device *dev)
lp->tx_buf_busy = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
-
- dev->interrupt = 0;
- dev->start = 1;
- dev->tbusy = 0;
BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
}
@@ -1462,10 +1356,9 @@ static void eth16i_multicast(struct net_device *dev)
}
}
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev)
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-
return &lp->stats;
}
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index eecbb9a56..90c82b341 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -138,6 +138,7 @@
static const char *version = "ewrk3.c:v0.43 96/8/16 davies@maniac.ultranet.com\n";
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -303,6 +304,7 @@ static int ewrk3_hw_init(struct net_device *dev, u_long iobase);
static void ewrk3_init(struct net_device *dev);
static int ewrk3_rx(struct net_device *dev);
static int ewrk3_tx(struct net_device *dev);
+static void ewrk3_timeout(struct net_device *dev);
static void EthwrkSignature(char *name, char *eeprom_image);
static int DevicePresent(u_long iobase);
@@ -601,12 +603,14 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
printk(version);
}
/* The EWRK3-specific entries in the device structure. */
- dev->open = &ewrk3_open;
- dev->hard_start_xmit = &ewrk3_queue_pkt;
- dev->stop = &ewrk3_close;
- dev->get_stats = &ewrk3_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- dev->do_ioctl = &ewrk3_ioctl;
+ dev->open = ewrk3_open;
+ dev->hard_start_xmit = ewrk3_queue_pkt;
+ dev->stop = ewrk3_close;
+ dev->get_stats = ewrk3_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->do_ioctl = ewrk3_ioctl;
+ dev->tx_timeout = ewrk3_timeout;
+ dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
dev->mem_start = 0;
@@ -616,7 +620,6 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
} else {
status = -ENXIO;
}
-
return status;
}
@@ -664,10 +667,7 @@ static int ewrk3_open(struct net_device *dev)
printk(" cmr: 0x%02x\n", inb(EWRK3_CMR));
printk(" fmqc: 0x%02x\n", inb(EWRK3_FMQC));
}
- dev->tbusy = 0;
- dev->start = 1;
- dev->interrupt = UNMASK_INTERRUPTS;
-
+ netif_start_queue(dev);
/*
** Unmask EWRK3 board interrupts
*/
@@ -676,10 +676,9 @@ static int ewrk3_open(struct net_device *dev)
}
} else {
- dev->start = 0;
- dev->tbusy = 1;
- printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name);
- printk(" Run the 'ewrk3setup' utility or remove the hard straps.\n");
+ printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name);
+ printk(KERN_ERR " Run the 'ewrk3setup' utility or remove the hard straps.\n");
+ return -EINVAL;
}
MOD_INC_USE_COUNT;
@@ -722,149 +721,148 @@ static void ewrk3_init(struct net_device *dev)
}
/*
- ** Writes a socket buffer to the free page queue
+ * Transmit timeout
*/
-static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+
+static void ewrk3_timeout(struct net_device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int status = 0;
u_char icr, csr;
+ u_long iobase = dev->base_addr;
+
+ if (!lp->hard_strapped)
+ {
+ printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
+ dev->name, inb(EWRK3_CSR));
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy || lp->lock) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < QUEUE_PKT_TIMEOUT) {
- status = -1;
- } else if (!lp->hard_strapped) {
- printk("%s: transmit timed/locked out, status %04x, resetting.\n",
- dev->name, inb(EWRK3_CSR));
-
- /*
- ** Mask all board interrupts
- */
- DISABLE_IRQs;
-
- /*
- ** Stop the TX and RX...
- */
- STOP_EWRK3;
-
- ewrk3_init(dev);
-
- /*
- ** Unmask EWRK3 board interrupts
- */
- ENABLE_IRQs;
-
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- }
- } else if (skb->len > 0) {
+ /*
+ ** Mask all board interrupts
+ */
+ DISABLE_IRQs;
/*
- ** Block a timer-based transmit from overlapping. This could better be
- ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+ ** Stop the TX and RX...
*/
- if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
+ STOP_EWRK3;
- DISABLE_IRQs; /* So that the page # remains correct */
+ ewrk3_init(dev);
/*
- ** Get a free page from the FMQ when resources are available
+ ** Unmask EWRK3 board interrupts
*/
- if (inb(EWRK3_FMQC) > 0) {
- u_long buf = 0;
- u_char page;
+ ENABLE_IRQs;
- if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
- /*
- ** Set up shared memory window and pointer into the window
- */
- while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */
- if (lp->shmem_length == IO_ONLY) {
- outb(page, EWRK3_IOPR);
- } else if (lp->shmem_length == SHMEM_2K) {
- buf = lp->shmem_base;
- outb(page, EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_32K) {
- buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
- outb((page >> 4), EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_64K) {
- buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
- outb((page >> 5), EWRK3_MPR);
- } else {
- status = -1;
- printk("%s: Oops - your private data area is hosed!\n", dev->name);
- }
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ }
+}
- if (!status) {
+/*
+ ** Writes a socket buffer to the free page queue
+ */
+static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+ u_long iobase = dev->base_addr;
+ int status = 0;
+ u_char icr;
- /*
- ** Set up the buffer control structures and copy the data from
- ** the socket buffer to the shared memory .
- */
+ netif_stop_queue(dev);
+#ifdef CONFIG_SMP
+#error "This needs spinlocks"
+#endif
+ DISABLE_IRQs; /* So that the page # remains correct */
- if (lp->shmem_length == IO_ONLY) {
- int i;
- u_char *p = skb->data;
+ /*
+ ** Get a free page from the FMQ when resources are available
+ */
+ if (inb(EWRK3_FMQC) > 0)
+ {
+ u_long buf = 0;
+ u_char page;
+ if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
+ /*
+ ** Set up shared memory window and pointer into the window
+ */
+ while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */
+ if (lp->shmem_length == IO_ONLY) {
+ outb(page, EWRK3_IOPR);
+ } else if (lp->shmem_length == SHMEM_2K) {
+ buf = lp->shmem_base;
+ outb(page, EWRK3_MPR);
+ } else if (lp->shmem_length == SHMEM_32K) {
+ buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
+ outb((page >> 4), EWRK3_MPR);
+ } else if (lp->shmem_length == SHMEM_64K) {
+ buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
+ outb((page >> 5), EWRK3_MPR);
+ } else {
+ status = -1;
+ printk(KERN_ERR "%s: Oops - your private data area is hosed!\n", dev->name);
+ }
+
+ if (!status) {
+ /*
+ ** Set up the buffer control structures and copy the data from
+ ** the socket buffer to the shared memory .
+ */
+ if (lp->shmem_length == IO_ONLY) {
+ int i;
+ u_char *p = skb->data;
outb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
- outb((char) (skb->len & 0xff), EWRK3_DATA);
- outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
- outb((char) 0x04, EWRK3_DATA);
- for (i = 0; i < skb->len; i++) {
- outb(*p++, EWRK3_DATA);
- }
+ outb((char) (skb->len & 0xff), EWRK3_DATA);
+ outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
+ outb((char) 0x04, EWRK3_DATA);
+ for (i = 0; i < skb->len; i++) {
+ outb(*p++, EWRK3_DATA);
+ }
+ outb(page, EWRK3_TQ); /* Start sending pkt */
+ } else {
+ writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf); /* ctrl byte */
+ buf += 1;
+ writeb((char) (skb->len & 0xff), (char *) buf); /* length (16 bit xfer) */
+ buf += 1;
+ if (lp->txc) {
+ writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);
+ buf += 1;
+ writeb(0x04, (char *) buf); /* index byte */
+ buf += 1;
+ writeb(0x00, (char *) (buf + skb->len)); /* Write the XCT flag */
+ isa_memcpy_toio(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */
outb(page, EWRK3_TQ); /* Start sending pkt */
+ isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
+ writeb(0xff, (char *) (buf + skb->len)); /* Write the XCT flag */
} else {
- writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf); /* ctrl byte */
+ writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);
buf += 1;
- writeb((char) (skb->len & 0xff), (char *) buf); /* length (16 bit xfer) */
+ writeb(0x04, (char *) buf); /* index byte */
buf += 1;
- if (lp->txc) {
- writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);
- buf += 1;
- writeb(0x04, (char *) buf); /* index byte */
- buf += 1;
- writeb(0x00, (char *) (buf + skb->len)); /* Write the XCT flag */
- isa_memcpy_toio(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */
- outb(page, EWRK3_TQ); /* Start sending pkt */
- isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
- writeb(0xff, (char *) (buf + skb->len)); /* Write the XCT flag */
- } else {
- writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);
- buf += 1;
- writeb(0x04, (char *) buf); /* index byte */
- buf += 1;
- isa_memcpy_toio(buf, skb->data, skb->len); /* Write data bytes */
- outb(page, EWRK3_TQ); /* Start sending pkt */
- }
+ isa_memcpy_toio(buf, skb->data, skb->len); /* Write data bytes */
+ outb(page, EWRK3_TQ); /* Start sending pkt */
}
-
- dev->trans_start = jiffies;
- dev_kfree_skb(skb);
-
- } else { /* return unused page to the free memory queue */
- outb(page, EWRK3_FMQ);
}
- lp->lock = 0; /* unlock the page register */
- } else {
- printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
- (u_char) page);
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb);
+ } else { /* return unused page to the free memory queue */
+ outb(page, EWRK3_FMQ);
}
+ lp->lock = 0; /* unlock the page register */
} else {
- printk("ewrk3_queue_pkt(): No free resources...\n");
- printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
+ printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
+ (u_char) page);
}
+ } else {
+ printk(KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n", dev->name);
+ printk(KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", dev->name, inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
+ }
- /* Check for free resources: clear 'tbusy' if there are some */
- if (inb(EWRK3_FMQC) > 0) {
- dev->tbusy = 0;
- }
- ENABLE_IRQs;
+ /* Check for free resources: clear 'tbusy' if there are some */
+ if (inb(EWRK3_FMQC) > 0) {
+ netif_wake_queue(dev);
}
+ ENABLE_IRQs;
return status;
}
@@ -878,60 +876,46 @@ static void ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
u_long iobase;
u_char icr, cr, csr;
- if (dev == NULL) {
- printk("ewrk3_interrupt(): irq %d for unknown device.\n", irq);
- } else {
- lp = (struct ewrk3_private *) dev->priv;
- iobase = dev->base_addr;
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- dev->interrupt = MASK_INTERRUPTS;
+ lp = (struct ewrk3_private *) dev->priv;
+ iobase = dev->base_addr;
- /* get the interrupt information */
- csr = inb(EWRK3_CSR);
-
- /*
- ** Mask the EWRK3 board interrupts and turn on the LED
- */
- DISABLE_IRQs;
-
- cr = inb(EWRK3_CR);
- cr |= CR_LED;
- outb(cr, EWRK3_CR);
+ /* get the interrupt information */
+ csr = inb(EWRK3_CSR);
- if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */
- ewrk3_rx(dev);
+ /*
+ ** Mask the EWRK3 board interrupts and turn on the LED
+ */
+ DISABLE_IRQs;
- if (csr & CSR_TNE) /* Tx interrupt (packet sent) */
- ewrk3_tx(dev);
+ cr = inb(EWRK3_CR);
+ cr |= CR_LED;
+ outb(cr, EWRK3_CR);
- /*
- ** Now deal with the TX/RX disable flags. These are set when there
- ** are no more resources. If resources free up then enable these
- ** interrupts, otherwise mask them - failure to do this will result
- ** in the system hanging in an interrupt loop.
- */
- if (inb(EWRK3_FMQC)) { /* any resources available? */
- lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */
- csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */
- outb(csr, EWRK3_CSR);
- dev->tbusy = 0; /* clear TX busy flag */
- mark_bh(NET_BH);
- } else {
- lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */
- }
+ if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */
+ ewrk3_rx(dev);
- /* Unmask the EWRK3 board interrupts and turn off the LED */
- cr &= ~CR_LED;
- outb(cr, EWRK3_CR);
+ if (csr & CSR_TNE) /* Tx interrupt (packet sent) */
+ ewrk3_tx(dev);
- dev->interrupt = UNMASK_INTERRUPTS;
- ENABLE_IRQs;
+ /*
+ ** Now deal with the TX/RX disable flags. These are set when there
+ ** are no more resources. If resources free up then enable these
+ ** interrupts, otherwise mask them - failure to do this will result
+ ** in the system hanging in an interrupt loop.
+ */
+ if (inb(EWRK3_FMQC)) { /* any resources available? */
+ lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */
+ csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */
+ outb(csr, EWRK3_CSR);
+ netif_wake_queue(dev);
+ } else {
+ lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */
}
- return;
+ /* Unmask the EWRK3 board interrupts and turn off the LED */
+ cr &= ~CR_LED;
+ outb(cr, EWRK3_CR);
+ ENABLE_IRQs;
}
static int ewrk3_rx(struct net_device *dev)
@@ -1120,9 +1104,8 @@ static int ewrk3_close(struct net_device *dev)
u_long iobase = dev->base_addr;
u_char icr, csr;
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
if (ewrk3_debug > 1) {
printk("%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, inb(EWRK3_CSR));
@@ -1369,8 +1352,7 @@ static void __init eisa_probe(struct net_device *dev, u_long ioaddr)
** are not available then insert a new device structure at the end of
** the current list.
*/
-static struct net_device * __init
-alloc_device(struct net_device *dev, u_long iobase)
+static struct net_device * __init alloc_device(struct net_device *dev, u_long iobase)
{
struct net_device *adev = NULL;
int fixed = 0, new_dev = 0;
diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
index c1c9fde27..785a3fafd 100644
--- a/drivers/net/fc/iph5526.c
+++ b/drivers/net/fc/iph5526.c
@@ -919,7 +919,8 @@ u_int tag;
/* An IP frame was transmitted to a Bad AL_PA. Free up
* the skb used.
*/
- dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id)));
+ dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
+ netif_wake_queue(fi->dev);
}
} /* End of IP frame timing out. */
} /* End of frame timing out. */
@@ -977,7 +978,8 @@ u_int tag;
* Free the skb that was used for this IP frame.
*/
if ((status == 0) && (seq_count > 1)) {
- dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id)));
+ dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
+ netif_wake_queue(fi->dev);
}
}
}
@@ -2914,65 +2916,59 @@ static void update_EDB_indx(struct fc_info *fi)
static int iph5526_open(struct net_device *dev)
{
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
}
static int iph5526_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
MOD_DEC_USE_COUNT;
return 0;
}
+static void iph5526_timeout(struct net_device *dev)
+{
+ struct fc_info *fi = (struct fc_info*)dev->priv;
+ printk(KERN_WARNING "%s: timed out on send.\n", dev->name);
+ fi->fc_stats.rx_dropped++;
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev)
{
-struct fc_info *fi = (struct fc_info*)dev->priv;
-int status = 0;
-short type = 0;
-u_long flags;
+ struct fc_info *fi = (struct fc_info*)dev->priv;
+ int status = 0;
+ short type = 0;
+ u_long flags;
+ struct fcllc *fcllc;
+
ENTER("iph5526_send_packet");
- if (dev->tbusy) {
- printk(KERN_WARNING "%s: DEVICE BUSY\n", dev->name);
- dev->tbusy = 0;
- fi->fc_stats.rx_dropped++;
- dev->trans_start = jiffies;
- return 0;
- }
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n",
-dev->name);
- fi->fc_stats.rx_dropped++;
- return 1;
- }
- else {
- struct fcllc *fcllc;
- /* Strip off the pseudo header.
- */
- skb->data = skb->data + 2*FC_ALEN;
- skb->len = skb->len - 2*FC_ALEN;
- fcllc = (struct fcllc *)skb->data;
- type = ntohs(fcllc->ethertype);
-
- spin_lock_irqsave(&fi->fc_lock, flags);
- switch(type) {
- case ETH_P_IP:
- status = tx_ip_packet(skb, skb->len, fi);
- break;
- case ETH_P_ARP:
- status = tx_arp_packet(skb->data, skb->len, fi);
- break;
- default:
- T_MSG("WARNING!!! Received Unknown Packet Type... Discarding...");
- fi->fc_stats.rx_dropped++;
- break;
- }
- spin_unlock_irqrestore(&fi->fc_lock, flags);
+
+ netif_stop_queue(dev);
+ /* Strip off the pseudo header.
+ */
+ skb->data = skb->data + 2*FC_ALEN;
+ skb->len = skb->len - 2*FC_ALEN;
+ fcllc = (struct fcllc *)skb->data;
+ type = ntohs(fcllc->ethertype);
+
+ spin_lock_irqsave(&fi->fc_lock, flags);
+ switch(type) {
+ case ETH_P_IP:
+ status = tx_ip_packet(skb, skb->len, fi);
+ break;
+ case ETH_P_ARP:
+ status = tx_arp_packet(skb->data, skb->len, fi);
+ break;
+ default:
+ T_MSG("WARNING!!! Received Unknown Packet Type... Discarding...");
+ fi->fc_stats.rx_dropped++;
+ break;
}
+ spin_unlock_irqrestore(&fi->fc_lock, flags);
if (status) {
fi->fc_stats.tx_bytes += skb->len;
@@ -2981,14 +2977,14 @@ dev->name);
else
fi->fc_stats.rx_dropped++;
dev->trans_start = jiffies;
- dev->tbusy = 0;
/* We free up the IP buffers in the OCI_interrupt handler.
* status == 0 implies that the frame was not transmitted. So the
* skb is freed here.
*/
if ((type == ETH_P_ARP) || (status == 0))
dev_kfree_skb(skb);
- mark_bh(NET_BH);
+ else
+ netif_wake_queue(dev);
LEAVE("iph5526_send_packet");
return 0;
}
diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
index 10366f2f8..b26351886 100644
--- a/drivers/net/fmv18x.c
+++ b/drivers/net/fmv18x.c
@@ -58,8 +58,9 @@ static const char *version =
#include <linux/skbuff.h>
#include <linux/delay.h>
-static int fmv18x_probe_list[] __initdata =
-{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};
+static int fmv18x_probe_list[] __initdata = {
+ 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
+};
/* use 0 for production, 1 for verification, >2 for debug */
#ifndef NET_DEBUG
@@ -112,9 +113,10 @@ extern int fmv18x_probe(struct net_device *dev);
static int fmv18x_probe1(struct net_device *dev, short ioaddr);
static int net_open(struct net_device *dev);
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void net_rx(struct net_device *dev);
+static void net_timeout(struct net_device *dev);
static int net_close(struct net_device *dev);
static struct net_device_stats *net_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -126,14 +128,8 @@ static void set_multicast_list(struct net_device *dev);
If dev->base_addr == 2, allocate space for the device and return success
(detachable devices only).
*/
-#ifdef HAVE_DEVLIST
-/* Support for an alternate probe manager, which will eliminate the
- boilerplate below. */
-struct netdev_entry fmv18x_drv =
-{"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list};
-#else
-int __init
-fmv18x_probe(struct net_device *dev)
+
+int __init fmv18x_probe(struct net_device *dev)
{
int i;
int base_addr = dev ? dev->base_addr : 0;
@@ -153,7 +149,6 @@ fmv18x_probe(struct net_device *dev)
return ENODEV;
}
-#endif
/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
"signature", the default bit pattern after a reset. This *doesn't* work --
@@ -276,9 +271,11 @@ int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
dev->open = net_open;
dev->stop = net_close;
- dev->hard_start_xmit = net_send_packet;
- dev->get_stats = net_get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->hard_start_xmit = net_send_packet;
+ dev->tx_timeout = net_timeout;
+ dev->watchdog_timeo = HZ/10;
+ dev->get_stats = net_get_stats;
+ dev->set_multicast_list = set_multicast_list;
/* Fill in the fields of 'dev' with ethernet-generic values. */
@@ -310,10 +307,8 @@ static int net_open(struct net_device *dev)
outb(0xff, ioaddr + RX_STATUS);
lp->open_time = jiffies;
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
+
/* Enable the IRQ of the LAN Card */
outb(0x80, ioaddr + FJ_CONFIG1);
@@ -325,93 +320,86 @@ static int net_open(struct net_device *dev)
return 0;
}
-static int
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void net_timeout(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
+ unsigned long flags;
+
+
+ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s?\n", dev->name,
+ htons(inw(ioaddr + TX_STATUS)),
+ inb(ioaddr + TX_STATUS) & 0x80
+ ? "IRQ conflict" : "network cable problem");
+ printk(KERN_WARNING "%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
+ dev->name, htons(inw(ioaddr + 0)),
+ htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
+ htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
+ htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
+ htons(inw(ioaddr +14)));
+ printk(KERN_WARNING "eth card: %04x %04x\n",
+ htons(inw(ioaddr+FJ_STATUS0)),
+ htons(inw(ioaddr+FJ_CONFIG0)));
+ lp->stats.tx_errors++;
+ /* ToDo: We should try to restart the adaptor... */
+ save_flags(flags);
+ cli();
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10)
- return 1;
- printk("%s: transmit timed out with status %04x, %s?\n", dev->name,
- htons(inw(ioaddr + TX_STATUS)),
- inb(ioaddr + TX_STATUS) & 0x80
- ? "IRQ conflict" : "network cable problem");
- printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
- dev->name, htons(inw(ioaddr + 0)),
- htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
- htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
- htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
- htons(inw(ioaddr +14)));
- printk("eth card: %04x %04x\n",
- htons(inw(ioaddr+FJ_STATUS0)),
- htons(inw(ioaddr+FJ_CONFIG0)));
- lp->stats.tx_errors++;
- /* ToDo: We should try to restart the adaptor... */
- cli();
-
- /* Initialize LAN Controller and LAN Card */
- outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */
- outb(0x00, ioaddr + CONFIG_1); /* Stand by mode */
- outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
- outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */
- net_open(dev);
-
- sti();
- }
-
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
-
- if (length > ETH_FRAME_LEN) {
- if (net_debug)
- printk("%s: Attempting to send a large packet (%d bytes).\n",
- dev->name, length);
- return 1;
- }
+ /* Initialize LAN Controller and LAN Card */
+ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */
+ outb(0x00, ioaddr + CONFIG_1); /* Stand by mode */
+ outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
+ outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */
+ net_open(dev);
+ restore_flags(flags);
+}
- if (net_debug > 4)
- printk("%s: Transmitting a packet of length %lu.\n", dev->name,
- (unsigned long)skb->len);
-
- /* We may not start transmitting unless we finish transferring
- a packet into the Tx queue. During executing the following
- codes we possibly catch a Tx interrupt. Thus we flag off
- tx_queue_ready, so that we prevent the interrupt routine
- (net_interrupt) to start transmitting. */
- lp->tx_queue_ready = 0;
- {
- outw(length, ioaddr + DATAPORT);
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
- }
- lp->tx_queue_ready = 1;
-
- if (lp->tx_started == 0) {
- /* If the Tx is idle, always trigger a transmit. */
- outb(0x80 | lp->tx_queue, ioaddr + TX_START);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- dev->trans_start = jiffies;
- lp->tx_started = 1;
- dev->tbusy = 0;
- } else if (lp->tx_queue_len < 4096 - 1502)
- /* Yes, there is room for one more packet. */
- dev->tbusy = 0;
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+
+ /* Block a transmit from overlapping. */
+
+ netif_stop_queue(dev);
+
+ if (length > ETH_FRAME_LEN) {
+ if (net_debug)
+ printk("%s: Attempting to send a large packet (%d bytes).\n",
+ dev->name, length);
+ return 1;
}
- dev_kfree_skb (skb);
-
+ if (net_debug > 4)
+ printk("%s: Transmitting a packet of length %lu.\n", dev->name,
+ (unsigned long)skb->len);
+ /* We may not start transmitting unless we finish transferring
+ a packet into the Tx queue. During executing the following
+ codes we possibly catch a Tx interrupt. Thus we flag off
+ tx_queue_ready, so that we prevent the interrupt routine
+ (net_interrupt) to start transmitting. */
+ lp->tx_queue_ready = 0;
+ {
+ outw(length, ioaddr + DATAPORT);
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+ }
+ lp->tx_queue_ready = 1;
+ if (lp->tx_started == 0) {
+ /* If the Tx is idle, always trigger a transmit. */
+ outb(0x80 | lp->tx_queue, ioaddr + TX_START);
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
+ lp->tx_started = 1;
+ netif_wake_queue(dev);
+ } else if (lp->tx_queue_len < 4096 - 1502)
+ /* Yes, there is room for one more packet. */
+ netif_wake_queue(dev);
+
+ dev_kfree_skb(skb);
return 0;
}
@@ -424,12 +412,6 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct net_local *lp;
int ioaddr, status;
- if (dev == NULL) {
- printk ("fmv18x_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
status = inw(ioaddr + TX_STATUS);
@@ -467,23 +449,18 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
} else {
lp->tx_started = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
}
}
}
-
- dev->interrupt = 0;
return;
}
/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
+static void net_rx(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
@@ -578,9 +555,8 @@ static int net_close(struct net_device *dev)
((struct net_local *)dev->priv)->open_time = 0;
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
/* Set configuration register 0 to disable Tx and Rx. */
outb(0xda, ioaddr + CONFIG_0);
@@ -602,11 +578,6 @@ static int net_close(struct net_device *dev)
static struct net_device_stats *net_get_stats(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
-
- cli();
- /* ToDo: Update the statistics from the device registers. */
- sti();
-
return &lp->stats;
}
diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c
index 7ee18bfe9..b1a431499 100644
--- a/drivers/net/gmac.c
+++ b/drivers/net/gmac.c
@@ -51,6 +51,7 @@ struct gmac {
int phy_addr;
int full_duplex;
struct net_device_stats stats;
+ struct net_device *next_gmac;
};
#define GM_OUT(r, v) out_le32(gm->regs + (r)/4, (v))
@@ -80,6 +81,7 @@ static void gmac_receive(struct net_device *dev);
static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static struct net_device_stats *gmac_stats(struct net_device *dev);
static int gmac_probe(void);
+static void gmac_probe1(struct device_node *gmac);
/* Stuff for talking to the physical-layer chip */
static int
@@ -383,7 +385,7 @@ static int gmac_xmit_start(struct sk_buff *skb, struct net_device *dev)
i = gm->next_tx;
if (gm->tx_buff[i] != 0) {
/* buffer is full, can't send this packet at the moment */
- dev->tbusy = 1;
+ netif_stop_queue(dev);
gm->tx_full = 1;
restore_flags(flags);
return 1;
@@ -421,7 +423,7 @@ static int gmac_tx_cleanup(struct gmac *gm)
gm->stats.tx_bytes += skb->len;
++gm->stats.tx_packets;
gm->tx_buff[i] = NULL;
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
if (++i >= NTX)
i = 0;
}
@@ -452,7 +454,7 @@ static void gmac_receive(struct net_device *dev)
++gm->stats.rx_dropped;
} else if (ld_le32(&dp->status) & 0x40000000) {
++gm->stats.rx_errors;
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
} else {
skb_put(skb, len);
skb->dev = dev;
@@ -486,14 +488,11 @@ static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = GM_IN(INTR_STATUS);
GM_OUT(INTR_ACK, status);
- if (status & GMAC_IRQ_MIF) {
+ if (status & GMAC_IRQ_MIF)
mii_interrupt(gm);
- }
gmac_receive(dev);
- if (gmac_tx_cleanup(gm)){
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
+ if (gmac_tx_cleanup(gm))
+ netif_wake_queue(dev);
}
static struct net_device_stats *gmac_stats(struct net_device *dev)
@@ -505,33 +504,44 @@ static struct net_device_stats *gmac_stats(struct net_device *dev)
static int __init gmac_probe(void)
{
- static int gmacs_found;
- static struct device_node *next_gmac;
struct device_node *gmac;
- struct gmac *gm;
- unsigned long descpage;
- unsigned char *addr;
- int i;
-
- if (gmacs != NULL)
- return -EBUSY;
/*
* We could (and maybe should) do this using PCI scanning
* for vendor/net_device ID 0x106b/0x21.
*/
- if (!gmacs_found) {
- next_gmac = find_compatible_devices("network", "gmac");
- gmacs_found = 1;
- }
- if ((gmac = next_gmac) == 0)
- return -ENODEV;
- next_gmac = gmac->next;
+ for (gmac = find_compatible_devices("network", "gmac"); gmac != 0;
+ gmac = gmac->next)
+ gmac_probe1(gmac);
+
+ return 0;
+}
+
+static void gmac_probe1(struct device_node *gmac)
+{
+ struct gmac *gm;
+ unsigned long descpage;
+ unsigned char *addr;
+ struct net_device *dev;
+ int i;
if (gmac->n_addrs < 1 || gmac->n_intrs < 1) {
printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n",
gmac->full_name, gmac->n_addrs, gmac->n_intrs);
- return -ENODEV;
+ return;
+ }
+
+ addr = get_property(gmac, "local-mac-address", NULL);
+ if (addr == NULL) {
+ printk(KERN_ERR "Can't get mac-address for GMAC %s\n",
+ gmac->full_name);
+ return;
+ }
+
+ descpage = get_free_page(GFP_KERNEL);
+ if (descpage == 0) {
+ printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
+ return;
}
dev = init_etherdev(0, sizeof(struct gmac));
@@ -544,13 +554,6 @@ static int __init gmac_probe(void)
gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
dev->irq = gmac->intrs[0].line;
- addr = get_property(gmac, "local-mac-address", NULL);
- if (addr == NULL) {
- printk(KERN_ERR "Can't get mac-address for GMAC %s\n",
- gmac->full_name);
- return -EAGAIN;
- }
-
printk(KERN_INFO "%s: GMAC at", dev->name);
for (i = 0; i < 6; ++i) {
dev->dev_addr[i] = addr[i];
@@ -558,12 +561,6 @@ static int __init gmac_probe(void)
}
printk("\n");
- descpage = get_free_page(GFP_KERNEL);
- if (descpage == 0) {
- printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
- return -EAGAIN;
- }
-
gm->desc_page = descpage;
gm->rxring = (volatile struct gmac_dma_desc *) descpage;
gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800);
@@ -577,34 +574,29 @@ static int __init gmac_probe(void)
ether_setup(dev);
- if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) {
+ if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev))
printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq);
- return -EAGAIN;
- }
+ gm->next_gmac = gmacs;
gmacs = dev;
-
- return 0;
}
-MODULE_AUTHOR("Paul Mackerras");
+MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt");
MODULE_DESCRIPTION("PowerMac GMAC driver.");
-
static void __exit gmac_cleanup_module(void)
{
struct gmac *gm;
-
- /* XXX should handle more than one */
- if (gmacs == NULL)
- return;
-
- gm = (struct gmac *) gmacs->priv;
- free_irq(gmacs->irq, gmac_interrupt);
- free_page(gm->descpage);
- unregister_netdev(gmacs);
- kfree(gmacs);
- gmacs = NULL;
+ struct net_device *dev;
+
+ while ((dev = gmacs) != NULL) {
+ gm = (struct gmac *) dev->priv;
+ gmacs = gm->next_gmac;
+ free_irq(dev->irq, dev);
+ free_page(gm->desc_page);
+ unregister_netdev(dev);
+ kfree(dev);
+ }
}
module_init(gmac_probe);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 16dc8a976..b1871485a 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -158,24 +158,6 @@ sp_free(struct sixpack *sp)
}
-/* Set the "sending" flag. */
-static inline void
-sp_lock(struct sixpack *sp)
-{
- if (test_and_set_bit(0, (void *) &sp->dev->tbusy))
- printk(KERN_WARNING "%s: trying to lock already locked device!\n", sp->dev->name);
-}
-
-
-/* Clear the "sending" flag. */
-static inline void
-sp_unlock(struct sixpack *sp)
-{
- if (!test_and_clear_bit(0, (void *)&sp->dev->tbusy))
- printk(KERN_WARNING "%s: trying to unlock already unlocked device!\n", sp->dev->name);
-}
-
-
/* Send one completely decapsulated IP datagram to the IP layer. */
/* This is the routine that sends the received data to the kernel AX.25.
@@ -226,7 +208,7 @@ sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
len = sp->mtu;
printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", sp->dev->name);
sp->tx_dropped++;
- sp_unlock(sp);
+ netif_start_queue(sp->dev);
return;
}
@@ -235,21 +217,21 @@ sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
if (p[0] > 5)
{
printk(KERN_DEBUG "%s: invalid KISS command -- dropped\n", sp->dev->name);
- sp_unlock(sp);
+ netif_start_queue(sp->dev);
return;
}
if ((p[0] != 0) && (len > 2))
{
printk(KERN_DEBUG "%s: KISS control packet too long -- dropped\n", sp->dev->name);
- sp_unlock(sp);
+ netif_start_queue(sp->dev);
return;
}
if ((p[0] == 0) && (len < 15))
{
printk(KERN_DEBUG "%s: bad AX.25 packet to transmit -- dropped\n", sp->dev->name);
- sp_unlock(sp);
+ netif_start_queue(sp->dev);
sp->tx_dropped++;
return;
}
@@ -301,17 +283,18 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
struct sixpack *sp = (struct sixpack *) tty->disc_data;
/* First make sure we're connected. */
- if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start) {
+ if (!sp || sp->magic != SIXPACK_MAGIC ||
+ !netif_running(sp->dev)) {
return;
}
+
if (sp->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
sp->tx_packets++;
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- sp_unlock(sp);
sp->tx_enable = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(sp->dev);
return;
}
@@ -331,18 +314,9 @@ sp_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sixpack *sp = (struct sixpack*)(dev->priv);
- if (!dev->start)
- {
- printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
- return 1;
- }
-
- if (dev->tbusy)
- return 1;
-
/* We were not busy, so we are now... :-) */
if (skb != NULL) {
- sp_lock(sp);
+ netif_stop_queue(dev);
sp->tx_bytes+=skb->len; /*---2.1.x---*/
sp_encaps(sp, skb->data, skb->len);
dev_kfree_skb(skb);
@@ -458,8 +432,7 @@ sp_open(struct net_device *dev)
sp->tnc_ok = 0;
sp->tx_enable = 0;
- dev->tbusy = 0;
- dev->start = 1;
+ netif_start_queue(dev);
init_timer(&sp->tx_t);
init_timer(&sp->resync_t);
@@ -477,9 +450,8 @@ sp_close(struct net_device *dev)
return -EBUSY;
}
sp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
return 0;
}
@@ -506,7 +478,8 @@ sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, i
struct sixpack *sp = (struct sixpack *) tty->disc_data;
- if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start || !count)
+ if (!sp || sp->magic != SIXPACK_MAGIC ||
+ !netif_running(sp->dev) || !count)
return;
save_flags(flags);
@@ -723,17 +696,13 @@ static int sp_open_dev(struct net_device *dev)
/* Initialize 6pack control device -- register 6pack line discipline */
-#ifdef MODULE
-static int sixpack_init_ctrl_dev(void)
-#else /* !MODULE */
-int __init sixpack_init_ctrl_dev(struct net_device *dummy)
-#endif /* !MODULE */
+static int __init sixpack_init_ctrl_dev(void)
{
int status;
if (sixpack_maxdev < 4) sixpack_maxdev = 4; /* Sanity */
- printk(KERN_INFO "6pack: %s (dynamic channels, max=%d)\n",
+ printk(KERN_INFO "AX.25: 6pack driver, %s (dynamic channels, max=%d)\n",
SIXPACK_VERSION, sixpack_maxdev);
sixpack_ctrls = (sixpack_ctrl_t **) kmalloc(sizeof(void*)*sixpack_maxdev, GFP_KERNEL);
@@ -766,16 +735,40 @@ int __init sixpack_init_ctrl_dev(struct net_device *dummy)
printk(KERN_WARNING "6pack: can't register line discipline (err = %d)\n", status);
}
-#ifdef MODULE
return status;
-#else
- /* Return "not found", so that dev_init() will unlink
- * the placeholder device entry for us.
- */
- return ENODEV;
-#endif
}
+static void __exit sixpack_cleanup_driver(void)
+{
+ int i;
+
+ if (sixpack_ctrls != NULL)
+ {
+ for (i = 0; i < sixpack_maxdev; i++)
+ {
+ if (sixpack_ctrls[i])
+ {
+ /*
+ * VSV = if dev->start==0, then device
+ * unregistered while close proc.
+ */
+ if (netif_running(sixpack_ctrls[i]->dev))
+ unregister_netdev(&(sixpack_ctrls[i]->dev));
+
+ kfree(sixpack_ctrls[i]);
+ sixpack_ctrls[i] = NULL;
+ }
+ }
+ kfree(sixpack_ctrls);
+ sixpack_ctrls = NULL;
+ }
+ if ((i = tty_register_ldisc(N_6PACK, NULL)))
+ {
+ printk(KERN_WARNING "6pack: can't unregister line discipline (err = %d)\n", i);
+ }
+}
+
+
/* Initialize the 6pack driver. Called by DDI. */
int
sixpack_init(struct net_device *dev)
@@ -809,6 +802,7 @@ sixpack_init(struct net_device *dev)
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
dev->rebuild_header = sp_rebuild_header;
+ dev->tx_timeout = NULL;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); /* Only activated in AX.25 mode */
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* "" "" "" "" */
@@ -821,45 +815,8 @@ sixpack_init(struct net_device *dev)
return 0;
}
-#ifdef MODULE
-
-int
-init_module(void)
-{
- return sixpack_init_ctrl_dev();
-}
-
-void
-cleanup_module(void)
-{
- int i;
- if (sixpack_ctrls != NULL)
- {
- for (i = 0; i < sixpack_maxdev; i++)
- {
- if (sixpack_ctrls[i])
- {
- /*
- * VSV = if dev->start==0, then device
- * unregistered while close proc.
- */
- if (sixpack_ctrls[i]->dev.start)
- unregister_netdev(&(sixpack_ctrls[i]->dev));
- kfree(sixpack_ctrls[i]);
- sixpack_ctrls[i] = NULL;
- }
- }
- kfree(sixpack_ctrls);
- sixpack_ctrls = NULL;
- }
- if ((i = tty_register_ldisc(N_6PACK, NULL)))
- {
- printk(KERN_WARNING "6pack: can't unregister line discipline (err = %d)\n", i);
- }
-}
-#endif /* MODULE */
/* ----> 6pack timer interrupt handler and friends. <---- */
static void
@@ -1127,3 +1084,9 @@ void decode_data(byte inbyte, struct sixpack *sp)
sp->rx_count = 0;
}
}
+
+
+MODULE_AUTHOR("Andreas Könsgen <ajk@ccac.rwth-aachen.de>");
+MODULE_DESCRIPTION("6pack driver for AX.25");
+module_init(sixpack_init_ctrl_dev);
+module_exit(sixpack_cleanup_driver);
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index d4191258d..98d228b91 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -3,7 +3,7 @@
/*
* baycom_epp.c -- baycom epp radio modem driver.
*
- * Copyright (C) 1998-1999
+ * Copyright (C) 1998-2000
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
@@ -26,14 +26,15 @@
*
*
* History:
- * 0.1 xx.xx.98 Initial version by Matthias Welwarsky (dg2fef)
- * 0.2 21.04.98 Massive rework by Thomas Sailer
- * Integrated FPGA EPP modem configuration routines
- * 0.3 11.05.98 Took FPGA config out and moved it into a separate program
- * 0.4 26.07.99 Adapted to new lowlevel parport driver interface
- * 0.5 03.08.99 adapt to Linus' new __setup/__initcall
- * removed some pre-2.2 kernel compatibility cruft
- * 0.6 10.08.99 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.1 xx.xx.1998 Initial version by Matthias Welwarsky (dg2fef)
+ * 0.2 21.04.1998 Massive rework by Thomas Sailer
+ * Integrated FPGA EPP modem configuration routines
+ * 0.3 11.05.1998 Took FPGA config out and moved it into a separate program
+ * 0.4 26.07.1999 Adapted to new lowlevel parport driver interface
+ * 0.5 03.08.1999 adapt to Linus' new __setup/__initcall
+ * removed some pre-2.2 kernel compatibility cruft
+ * 0.6 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.7 12.02.2000 adapted to softnet driver interface
*
*/
@@ -47,8 +48,10 @@
#include <linux/tqueue.h>
#include <linux/fs.h>
#include <linux/parport.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/if_arp.h>
+#include <linux/kmod.h>
#include <linux/hdlcdrv.h>
#include <linux/baycom.h>
#include <linux/soundmodem.h>
@@ -89,8 +92,8 @@ static const char paranoia_str[] = KERN_ERR
/* --------------------------------------------------------------------- */
static const char bc_drvname[] = "baycom_epp";
-static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-1999 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_epp: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -228,8 +231,7 @@ struct baycom_state {
struct net_device_stats stats;
unsigned int ptt_keyed;
- struct sk_buff_head send_queue; /* Packets awaiting transmission */
-
+ struct sk_buff *skb; /* next transmit packet */
#ifdef BAYCOM_DEBUG
struct debug_vals {
@@ -394,15 +396,11 @@ static int exec_eppfpga(void *b)
sprintf(portarg, "%ld", bc->pdev->port->base);
printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
- for (i = 0; i < current->files->max_fds; i++ )
- if (current->files->fd[i])
- close(i);
- set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */
- current->uid = current->euid = current->fsuid = 0;
- if (execve(eppconfig_path, argv, envp) < 0) {
+ i = exec_usermodehelper(eppconfig_path, argv, envp);
+ if (i < 0) {
printk(KERN_ERR "%s: failed to exec %s -s -p %s -m %s, errno = %d\n",
- bc_drvname, eppconfig_path, portarg, modearg, errno);
- return -errno;
+ bc_drvname, eppconfig_path, portarg, modearg, i);
+ return i;
}
return 0;
}
@@ -515,71 +513,63 @@ static void encode_hdlc(struct baycom_state *bc)
if (bc->hdlctx.bufcnt > 0)
return;
- while ((skb = skb_dequeue(&bc->send_queue))) {
- if (skb->data[0] != 0) {
- do_kiss_params(bc, skb->data, skb->len);
- dev_kfree_skb(skb);
- continue;
- }
- pkt_len = skb->len-1; /* strip KISS byte */
- if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) {
- dev_kfree_skb(skb);
- continue;
- }
- wp = bc->hdlctx.buf;
- bp = skb->data+1;
- crc = calc_crc_ccitt(bp, pkt_len);
- crcarr[0] = crc;
- crcarr[1] = crc >> 8;
- *wp++ = 0x7e;
- bitstream = bitbuf = numbit = 0;
- while (pkt_len > -2) {
- bitstream >>= 8;
- bitstream |= ((unsigned int)*bp) << 8;
- bitbuf |= ((unsigned int)*bp) << numbit;
- notbitstream = ~bitstream;
- bp++;
- pkt_len--;
- if (!pkt_len)
- bp = crcarr;
- ENCODEITERA(0);
- ENCODEITERA(1);
- ENCODEITERA(2);
- ENCODEITERA(3);
- ENCODEITERA(4);
- ENCODEITERA(5);
- ENCODEITERA(6);
- ENCODEITERA(7);
- goto enditer;
- ENCODEITERB(0);
- ENCODEITERB(1);
- ENCODEITERB(2);
- ENCODEITERB(3);
- ENCODEITERB(4);
- ENCODEITERB(5);
- ENCODEITERB(6);
- ENCODEITERB(7);
- enditer:
- numbit += 8;
- while (numbit >= 8) {
- *wp++ = bitbuf;
- bitbuf >>= 8;
- numbit -= 8;
- }
- }
- bitbuf |= 0x7e7e << numbit;
- numbit += 16;
- while (numbit >= 8) {
- *wp++ = bitbuf;
- bitbuf >>= 8;
- numbit -= 8;
- }
- bc->hdlctx.bufptr = bc->hdlctx.buf;
- bc->hdlctx.bufcnt = wp - bc->hdlctx.buf;
- dev_kfree_skb(skb);
- bc->stats.tx_packets++;
+ skb = bc->skb;
+ if (!skb)
return;
+ bc->skb = NULL;
+ pkt_len = skb->len-1; /* strip KISS byte */
+ wp = bc->hdlctx.buf;
+ bp = skb->data+1;
+ crc = calc_crc_ccitt(bp, pkt_len);
+ crcarr[0] = crc;
+ crcarr[1] = crc >> 8;
+ *wp++ = 0x7e;
+ bitstream = bitbuf = numbit = 0;
+ while (pkt_len > -2) {
+ bitstream >>= 8;
+ bitstream |= ((unsigned int)*bp) << 8;
+ bitbuf |= ((unsigned int)*bp) << numbit;
+ notbitstream = ~bitstream;
+ bp++;
+ pkt_len--;
+ if (!pkt_len)
+ bp = crcarr;
+ ENCODEITERA(0);
+ ENCODEITERA(1);
+ ENCODEITERA(2);
+ ENCODEITERA(3);
+ ENCODEITERA(4);
+ ENCODEITERA(5);
+ ENCODEITERA(6);
+ ENCODEITERA(7);
+ goto enditer;
+ ENCODEITERB(0);
+ ENCODEITERB(1);
+ ENCODEITERB(2);
+ ENCODEITERB(3);
+ ENCODEITERB(4);
+ ENCODEITERB(5);
+ ENCODEITERB(6);
+ ENCODEITERB(7);
+ enditer:
+ numbit += 8;
+ while (numbit >= 8) {
+ *wp++ = bitbuf;
+ bitbuf >>= 8;
+ numbit -= 8;
+ }
}
+ bitbuf |= 0x7e7e << numbit;
+ numbit += 16;
+ while (numbit >= 8) {
+ *wp++ = bitbuf;
+ bitbuf >>= 8;
+ numbit -= 8;
+ }
+ bc->hdlctx.bufptr = bc->hdlctx.buf;
+ bc->hdlctx.bufcnt = wp - bc->hdlctx.buf;
+ dev_kfree_skb(skb);
+ bc->stats.tx_packets++;
}
/* ---------------------------------------------------------------------- */
@@ -944,6 +934,8 @@ static void epp_bh(struct net_device *dev)
bc->debug_vals.demod_cycles = time3 - time2;
#endif /* BAYCOM_DEBUG */
queue_task(&bc->run_bh, &tq_timer);
+ if (!bc->skb)
+ netif_wake_queue(dev);
return;
epptimeout:
printk(KERN_ERR "%s: EPP timeout!\n", bc_drvname);
@@ -960,8 +952,20 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
baycom_paranoia_check(dev, "baycom_send_packet", 0);
bc = (struct baycom_state *)dev->priv;
- skb_queue_tail(&bc->send_queue, skb);
- dev->trans_start = jiffies;
+ if (skb->data[0] != 0) {
+ do_kiss_params(bc, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ if (bc->skb)
+ return -1;
+ /* strip KISS byte */
+ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ netif_stop_queue(dev);
+ bc->skb = skb;
return 0;
}
@@ -1030,8 +1034,6 @@ static int epp_open(struct net_device *dev)
baycom_paranoia_check(dev, "epp_open", -ENXIO);
bc = (struct baycom_state *)dev->priv;
- if (dev->start)
- return 0;
pp = parport_enumerate();
while (pp && pp->base != dev->base_addr)
pp = pp->next;
@@ -1122,11 +1124,9 @@ static int epp_open(struct net_device *dev)
bc->hdlctx.bufcnt = 0;
bc->hdlctx.slotcnt = bc->ch_params.slottime;
bc->hdlctx.calibrate = 0;
- dev->start = 1;
- dev->tbusy = 0;
- dev->interrupt = 0;
/* start the bottom half stuff */
queue_task(&bc->run_bh, &tq_timer);
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
@@ -1144,17 +1144,12 @@ static int epp_close(struct net_device *dev)
{
struct baycom_state *bc;
struct parport *pp;
- struct sk_buff *skb;
unsigned char tmp[1];
baycom_paranoia_check(dev, "epp_close", -EINVAL);
- if (!dev->start)
- return 0;
bc = (struct baycom_state *)dev->priv;
pp = bc->pdev->port;
bc->bh_running = 0;
- dev->start = 0;
- dev->tbusy = 1;
run_task_queue(&tq_timer); /* dequeue bottom half */
bc->stat = EPP_DCDBIT;
tmp[0] = 0;
@@ -1162,9 +1157,9 @@ static int epp_close(struct net_device *dev)
parport_write_control(pp, 0); /* reset the adapter */
parport_release(bc->pdev);
parport_unregister_device(bc->pdev);
- /* Free any buffers left in the hardware transmit queue */
- while ((skb = skb_dequeue(&bc->send_queue)))
- dev_kfree_skb(skb);
+ if (bc->skb)
+ dev_kfree_skb(bc->skb);
+ bc->skb = NULL;
printk(KERN_INFO "%s: close epp at iobase 0x%lx irq %u\n",
bc_drvname, dev->base_addr, dev->irq);
MOD_DEC_USE_COUNT;
@@ -1280,7 +1275,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
case HDLCDRVCTL_SETMODEMPAR:
- if ((!suser()) || dev->start)
+ if ((!suser()) || netif_running(dev))
return -EACCES;
dev->base_addr = hi.data.mp.iobase;
dev->irq = /*hi.data.mp.irq*/0;
@@ -1319,7 +1314,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
case HDLCDRVCTL_SETMODE:
- if (!suser() || dev->start)
+ if (!suser() || netif_running(dev))
return -EACCES;
hi.data.modename[sizeof(hi.data.modename)-1] = '\0';
return baycom_setmode(bc, hi.data.modename);
@@ -1385,7 +1380,7 @@ static int baycom_probe(struct net_device *dev)
/* Fill in the fields of the device structure */
dev_init_buffers(dev);
- skb_queue_head_init(&bc->send_queue);
+ bc->skb = NULL;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
dev->hard_header = ax25_encapsulate;
@@ -1402,6 +1397,7 @@ static int baycom_probe(struct net_device *dev)
dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+ dev->tx_queue_len = 16;
/* New style flags */
dev->flags = 0;
@@ -1461,8 +1457,6 @@ static int __init init_baycomepp(void)
dev->name = bc->ifname;
dev->if_port = 0;
dev->init = baycom_probe;
- dev->start = 0;
- dev->tbusy = 1;
dev->base_addr = iobase[i];
dev->irq = 0;
dev->dma = 0;
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index 0bd2a1725..b68063b07 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -3,7 +3,7 @@
/*
* baycom_par.c -- baycom par96 and picpar radio modem driver.
*
- * Copyright (C) 1996-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,14 +53,16 @@
*
*
* History:
- * 0.1 26.06.96 Adapted from baycom.c and made network driver interface
- * 18.10.96 Changed to new user space access routines (copy_{to,from}_user)
- * 0.3 26.04.97 init code/data tagged
- * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints)
- * 0.5 11.11.97 split into separate files for ser12/par96
- * 0.6 03.08.99 adapt to Linus' new __setup/__initcall
- * removed some pre-2.2 kernel compatibility cruft
- * 0.7 10.08.99 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface
+ * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
+ * 0.3 26.04.1997 init code/data tagged
+ * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints)
+ * 0.5 11.11.1997 split into separate files for ser12/par96
+ * 0.6 03.08.1999 adapt to Linus' new __setup/__initcall
+ * removed some pre-2.2 kernel compatibility cruft
+ * 0.7 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.8 12.02.2000 adapted to softnet driver interface
+ * removed direct parport access, uses parport driver methods
*/
/*****************************************************************************/
@@ -77,7 +79,6 @@
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
-#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -99,8 +100,8 @@
/* --------------------------------------------------------------------- */
static const char bc_drvname[] = "baycom_par";
-static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_par: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_par: version 0.8 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -110,13 +111,6 @@ static struct net_device baycom_device[NR_PORTS];
/* --------------------------------------------------------------------- */
-#define SER12_EXTENT 8
-
-#define LPT_DATA(dev) ((dev)->base_addr+0)
-#define LPT_STATUS(dev) ((dev)->base_addr+1)
-#define LPT_CONTROL(dev) ((dev)->base_addr+2)
-#define LPT_IRQ_ENABLE 0x10
-
#define PAR96_BURSTBITS 16
#define PAR96_BURST 4
#define PAR96_PTT 2
@@ -207,6 +201,7 @@ static __inline__ void par96_tx(struct net_device *dev, struct baycom_state *bc)
{
int i;
unsigned int data = hdlcdrv_getbits(&bc->hdrv);
+ struct parport *pp = bc->pdev->port;
for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) {
unsigned char val = PAR97_POWER;
@@ -219,8 +214,8 @@ static __inline__ void par96_tx(struct net_device *dev, struct baycom_state *bc)
(PAR96_SCRAM_TAPN << 1);
if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2))
val |= PAR96_TXBIT;
- outb(val, LPT_DATA(dev));
- outb(val | PAR96_BURST, LPT_DATA(dev));
+ pp->ops->write_data(pp, val);
+ pp->ops->write_data(pp, val | PAR96_BURST);
}
}
@@ -230,24 +225,25 @@ static __inline__ void par96_rx(struct net_device *dev, struct baycom_state *bc)
{
int i;
unsigned int data, mask, mask2, descx;
+ struct parport *pp = bc->pdev->port;
/*
* do receiver; differential decode and descramble on the fly
*/
for(data = i = 0; i < PAR96_BURSTBITS; i++) {
bc->modem.par96.descram = (bc->modem.par96.descram << 1);
- if (inb(LPT_STATUS(dev)) & PAR96_RXBIT)
+ if (pp->ops->read_status(pp) & PAR96_RXBIT)
bc->modem.par96.descram |= 1;
descx = bc->modem.par96.descram ^
(bc->modem.par96.descram >> 1);
/* now the diff decoded data is inverted in descram */
- outb(PAR97_POWER | PAR96_PTT, LPT_DATA(dev));
+ pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT);
descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^
(descx >> PAR96_DESCRAM_TAPSH2));
data >>= 1;
if (!(descx & 1))
data |= 0x8000;
- outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, LPT_DATA(dev));
+ pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT | PAR96_BURST);
}
hdlcdrv_putbits(&bc->hdrv, data);
/*
@@ -272,7 +268,7 @@ static __inline__ void par96_rx(struct net_device *dev, struct baycom_state *bc)
bc->modem.par96.dcd_count -= 2;
hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0);
} else {
- hdlcdrv_setdcd(&bc->hdrv, !!(inb(LPT_STATUS(dev)) & PAR96_DCD));
+ hdlcdrv_setdcd(&bc->hdrv, !!(pp->ops->read_status(pp) & PAR96_DCD));
}
}
@@ -353,13 +349,12 @@ static int par96_open(struct net_device *dev)
parport_unregister_device(bc->pdev);
return -EBUSY;
}
+ pp = bc->pdev->port;
dev->irq = pp->irq;
- /* bc->pdev->port->ops->change_mode(bc->pdev->port, PARPORT_MODE_PCSPP); not yet implemented */
+ pp->ops->data_forward(pp);
bc->hdrv.par.bitrate = 9600;
- /* switch off PTT */
- outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev));
- /*bc->pdev->port->ops->enable_irq(bc->pdev->port); not yet implemented */
- outb(LPT_IRQ_ENABLE, LPT_CONTROL(dev));
+ pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER); /* switch off PTT */
+ pp->ops->enable_irq(pp);
printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n",
bc_drvname, dev->base_addr, dev->irq, bc->options);
MOD_INC_USE_COUNT;
@@ -371,14 +366,15 @@ static int par96_open(struct net_device *dev)
static int par96_close(struct net_device *dev)
{
struct baycom_state *bc = (struct baycom_state *)dev->priv;
+ struct parport *pp;
if (!dev || !bc)
return -EINVAL;
+ pp = bc->pdev->port;
/* disable interrupt */
- outb(0, LPT_CONTROL(dev));
- /*bc->pdev->port->ops->disable_irq(bc->pdev->port); not yet implemented */
+ pp->ops->disable_irq(pp);
/* switch off PTT */
- outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev));
+ pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER);
parport_release(bc->pdev);
parport_unregister_device(bc->pdev);
printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n",
@@ -449,7 +445,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (dev->start || !suser())
+ if (netif_running(dev) || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return baycom_setmode(bc, hi->data.modename);
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 9c6e69cf6..cdcab2621 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -3,7 +3,7 @@
/*
* baycom_ser_fdx.c -- baycom ser12 fullduplex radio modem driver.
*
- * Copyright (C) 1996-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,16 +55,17 @@
*
*
* History:
- * 0.1 26.06.96 Adapted from baycom.c and made network driver interface
- * 18.10.96 Changed to new user space access routines (copy_{to,from}_user)
- * 0.3 26.04.97 init code/data tagged
- * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints)
- * 0.5 11.11.97 ser12/par96 split into separate files
- * 0.6 24.01.98 Thorsten Kranzkowski, dl8bcu and Thomas Sailer:
- * reduced interrupt load in transmit case
- * reworked receiver
- * 0.7 03.08.99 adapt to Linus' new __setup/__initcall
- * 0.8 10.08.99 use module_init/module_exit
+ * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface
+ * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
+ * 0.3 26.04.1997 init code/data tagged
+ * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints)
+ * 0.5 11.11.1997 ser12/par96 split into separate files
+ * 0.6 24.01.1998 Thorsten Kranzkowski, dl8bcu and Thomas Sailer:
+ * reduced interrupt load in transmit case
+ * reworked receiver
+ * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall
+ * 0.8 10.08.1999 use module_init/module_exit
+ * 0.9 12.02.2000 adapted to softnet driver interface
*/
/*****************************************************************************/
@@ -86,8 +87,8 @@
/* --------------------------------------------------------------------- */
static const char bc_drvname[] = "baycom_ser_fdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_fdx: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_ser_fdx: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -554,7 +555,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (dev->start || !suser())
+ if (netif_running(dev) || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return baycom_setmode(bc, hi->data.modename);
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index c44395f84..64b27286c 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -3,7 +3,7 @@
/*
* baycom_ser_hdx.c -- baycom ser12 halfduplex radio modem driver.
*
- * Copyright (C) 1996-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,14 +47,15 @@
*
*
* History:
- * 0.1 26.06.96 Adapted from baycom.c and made network driver interface
- * 18.10.96 Changed to new user space access routines (copy_{to,from}_user)
- * 0.3 26.04.97 init code/data tagged
- * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints)
- * 0.5 11.11.97 ser12/par96 split into separate files
- * 0.6 14.04.98 cleanups
- * 0.7 03.08.99 adapt to Linus' new __setup/__initcall
- * 0.8 10.08.99 use module_init/module_exit
+ * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface
+ * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
+ * 0.3 26.04.1997 init code/data tagged
+ * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints)
+ * 0.5 11.11.1997 ser12/par96 split into separate files
+ * 0.6 14.04.1998 cleanups
+ * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall
+ * 0.8 10.08.1999 use module_init/module_exit
+ * 0.9 12.02.2000 adapted to softnet driver interface
*/
/*****************************************************************************/
@@ -76,8 +77,8 @@
/* --------------------------------------------------------------------- */
static const char bc_drvname[] = "baycom_ser_hdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_hdx: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_ser_hdx: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -597,7 +598,7 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (dev->start || !suser())
+ if (netif_running(dev) || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return baycom_setmode(bc, hi->data.modename);
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 55ed5254e..0cc9aa7c1 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -222,7 +222,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty
dev = bpq_get_ax25_dev(dev);
- if (dev == NULL || dev->start == 0) {
+ if (dev == NULL || !netif_running(dev)) {
kfree_skb(skb);
return 0;
}
@@ -275,7 +275,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
* Just to be *really* sure not to send anything if the interface
* is down, the ethernet device may have gone.
*/
- if (!dev->start) {
+ if (!netif_running(dev)) {
bpq_check_devices(dev);
kfree_skb(skb);
return -ENODEV;
@@ -324,7 +324,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
bpq->stats.tx_bytes+=skb->len;
dev_queue_xmit(skb);
-
+ netif_wake_queue(dev);
return 0;
}
@@ -407,22 +407,17 @@ static int bpq_open(struct net_device *dev)
{
if (bpq_check_devices(dev))
return -ENODEV; /* oops, it's gone */
-
- dev->tbusy = 0;
- dev->start = 1;
-
+
MOD_INC_USE_COUNT;
+ netif_start_queue(dev);
return 0;
}
static int bpq_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -621,7 +616,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
* Initialize driver. To be called from af_ax25 if not compiled as a
* module
*/
-int __init bpq_init(void)
+static int __init bpq_init_driver(void)
{
struct net_device *dev;
@@ -630,7 +625,7 @@ int __init bpq_init(void)
register_netdevice_notifier(&bpq_dev_notifier);
- printk(KERN_INFO "AX.25 ethernet driver version 0.01\n");
+ printk(KERN_INFO "AX.25: bpqether driver version 0.01\n");
proc_net_create ("bpqether", 0, bpq_get_info);
@@ -643,22 +638,10 @@ int __init bpq_init(void)
}
}
read_unlock_bh(&dev_base_lock);
-out:
return 0;
}
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-MODULE_AUTHOR("Joerg Reuter DL1BKE <jreuter@lykos.oche.de>");
-MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet");
-
-int init_module(void)
-{
- return bpq_init();
-}
-
-void cleanup_module(void)
+static void __exit bpq_cleanup_driver(void)
{
struct bpqdev *bpq;
@@ -671,4 +654,8 @@ void cleanup_module(void)
for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next)
unregister_netdev(&bpq->axdev);
}
-#endif
+
+MODULE_AUTHOR("Joerg Reuter DL1BKE <jreuter@poboxes.com>");
+MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet");
+module_init(bpq_init_driver);
+module_exit(bpq_cleanup_driver);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index afba5cb14..3e7cd8e44 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -643,7 +643,6 @@ static int scc_open(struct net_device *dev)
}
/* Initialize local variables */
- dev->tbusy = 0;
priv->rx_ptr = 0;
priv->rx_over = 0;
priv->rx_head = priv->rx_tail = priv->rx_count = 0;
@@ -732,7 +731,7 @@ static int scc_open(struct net_device *dev)
/* Configure PI2 DMA */
if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK);
- dev->start = 1;
+ netif_start_queue(dev);
info->open++;
MOD_INC_USE_COUNT;
@@ -747,9 +746,8 @@ static int scc_close(struct net_device *dev)
int io = dev->base_addr;
int cmd = priv->cmd;
- dev->start = 0;
+ netif_stop_queue(dev);
info->open--;
- MOD_DEC_USE_COUNT;
if (info->type == TYPE_TWIN)
/* Drop DTR */
@@ -768,6 +766,7 @@ static int scc_close(struct net_device *dev)
if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK);
free_irq(dev->irq, info);
}
+ MOD_DEC_USE_COUNT;
return 0;
}
@@ -779,16 +778,16 @@ static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) {
case SIOCGSCCPARAM:
- rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param));
- if (rc) return rc;
- copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param));
+ if(copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param)))
+ return -EFAULT;
return 0;
case SIOCSSCCPARAM:
- if (!suser()) return -EPERM;
- rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param));
- if (rc) return rc;
- if (dev->start) return -EAGAIN;
- copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param));
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (netif_running(dev))
+ return -EAGAIN;
+ if(copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param)))
+ return -EFAULT;
dev->dma = priv->param.dma;
return 0;
default:
@@ -806,18 +805,8 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
int i;
/* Block a timer-based transmit from overlapping */
- if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {
- atomic_inc((void *) &priv->stats.tx_dropped);
- dev_kfree_skb(skb);
- return 0;
- }
-
- /* Return with an error if we cannot accept more data */
- if (dev->tbusy) {
- priv->tx_sem = 0;
- return -1;
- }
-
+ netif_stop_queue(dev);
+
/* Transfer data to DMA buffer */
i = priv->tx_head;
memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);
@@ -829,7 +818,8 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
/* Set the busy flag if we just filled up the last buffer */
priv->tx_head = (i + 1) % NUM_TX_BUF;
priv->tx_count++;
- if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1;
+ if (priv->tx_count != NUM_TX_BUF)
+ netif_wake_queue(dev);
/* Set new TX state */
if (priv->tx_state == TX_IDLE) {
@@ -1139,7 +1129,6 @@ static void es_isr(struct net_device *dev)
/* Remove frame from FIFO */
priv->tx_tail = (i + 1) % NUM_TX_BUF;
priv->tx_count--;
- dev->tbusy = 0;
/* Check if another frame is available and we are allowed to transmit */
if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {
if (dev->dma) {
@@ -1171,7 +1160,7 @@ static void es_isr(struct net_device *dev)
priv->stats.tx_packets++;
}
/* Inform upper layers */
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
/* DCD transition */
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 67a835b02..a3560c207 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -3,7 +3,7 @@
/*
* hdlcdrv.c -- HDLC packet radio network driver.
*
- * Copyright (C) 1996-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,16 +27,17 @@
* Written 1993-94 by Donald Becker.
*
* History:
- * 0.1 21.09.96 Started
- * 18.10.96 Changed to new user space access routines
- * (copy_{to,from}_user)
- * 0.2 21.11.96 various small changes
- * 0.3 03.03.97 fixed (hopefully) IP not working with ax.25 as a module
- * 0.4 16.04.97 init code/data tagged
- * 0.5 30.07.97 made HDLC buffers bigger (solves a problem with the
- * soundmodem driver)
- * 0.6 05.04.98 add spinlocks
- * 0.7 03.08.99 removed some old compatibility cruft
+ * 0.1 21.09.1996 Started
+ * 18.10.1996 Changed to new user space access routines
+ * (copy_{to,from}_user)
+ * 0.2 21.11.1996 various small changes
+ * 0.3 03.03.1997 fixed (hopefully) IP not working with ax.25 as a module
+ * 0.4 16.04.1997 init code/data tagged
+ * 0.5 30.07.1997 made HDLC buffers bigger (solves a problem with the
+ * soundmodem driver)
+ * 0.6 05.04.1998 add spinlocks
+ * 0.7 03.08.1999 removed some old compatibility cruft
+ * 0.8 12.02.2000 adapted to softnet driver interface
*/
/*****************************************************************************/
@@ -366,29 +367,25 @@ void hdlcdrv_transmitter(struct net_device *dev, struct hdlcdrv_state *s)
clear_bit(0, &s->hdlctx.in_hdlc_tx);
return;
}
- if (!(skb = skb_dequeue(&s->send_queue))) {
- int flgs = tenms_to_2flags
- (s, s->ch_params.tx_tail);
+ if (!(skb = s->skb)) {
+ int flgs = tenms_to_2flags(s, s->ch_params.tx_tail);
if (flgs < 2)
flgs = 2;
s->hdlctx.tx_state = 1;
s->hdlctx.numflags = flgs;
break;
}
- if (skb->data[0] != 0) {
- do_kiss_params(s, skb->data, skb->len);
- dev_kfree_skb(skb);
- break;
- }
+ s->skb = NULL;
+ netif_wake_queue(dev);
pkt_len = skb->len-1; /* strip KISS byte */
if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) {
s->hdlctx.tx_state = 0;
s->hdlctx.numflags = 1;
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
break;
}
memcpy(s->hdlctx.buffer, skb->data+1, pkt_len);
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
s->hdlctx.bp = s->hdlctx.buffer;
append_crc_ccitt(s->hdlctx.buffer, pkt_len);
s->hdlctx.len = pkt_len+2; /* the appended CRC */
@@ -454,8 +451,7 @@ static inline unsigned short random_num(void)
void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s)
{
- if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt ||
- skb_queue_empty(&s->send_queue))
+ if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || !s->skb)
return;
if (s->ch_params.fulldup) {
start_tx(dev, s);
@@ -499,8 +495,15 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev)
if (hdlcdrv_paranoia_check(dev, "hdlcdrv_send_packet"))
return 0;
sm = (struct hdlcdrv_state *)dev->priv;
- skb_queue_tail(&sm->send_queue, skb);
- dev->trans_start = jiffies;
+ if (skb->data[0] != 0) {
+ do_kiss_params(sm, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ if (sm->skb)
+ return -1;
+ netif_stop_queue(dev);
+ sm->skb = skb;
return 0;
}
@@ -550,12 +553,9 @@ static int hdlcdrv_open(struct net_device *dev)
return -EINVAL;
s = (struct hdlcdrv_state *)dev->priv;
- if (dev->start)
- return 0;
if (!s->ops || !s->ops->open)
return -ENODEV;
- dev->start = 1;
/*
* initialise some variables
*/
@@ -573,14 +573,9 @@ static int hdlcdrv_open(struct net_device *dev)
s->hdlctx.calibrate = 0;
i = s->ops->open(dev);
- if (i) {
- dev->start = 0;
+ if (i)
return i;
- }
-
- dev->tbusy = 0;
- dev->interrupt = 0;
-
+ netif_start_queue(dev);
return 0;
}
@@ -592,23 +587,17 @@ static int hdlcdrv_open(struct net_device *dev)
static int hdlcdrv_close(struct net_device *dev)
{
struct hdlcdrv_state *s;
- struct sk_buff *skb;
int i = 0;
if (hdlcdrv_paranoia_check(dev, "hdlcdrv_close"))
return -EINVAL;
s = (struct hdlcdrv_state *)dev->priv;
- if (!dev->start)
- return 0;
- dev->start = 0;
- dev->tbusy = 1;
-
if (s->ops && s->ops->close)
i = s->ops->close(dev);
- /* Free any buffers left in the hardware transmit queue */
- while ((skb = skb_dequeue(&s->send_queue)))
- dev_kfree_skb(skb);
+ if (s->skb)
+ dev_kfree_skb(s->skb);
+ s->skb = NULL;
return i;
}
@@ -667,7 +656,7 @@ static int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
case HDLCDRVCTL_SETMODEMPAR:
- if ((!suser()) || dev->start)
+ if ((!suser()) || netif_running(dev))
return -EACCES;
dev->base_addr = bi.data.mp.iobase;
dev->irq = bi.data.mp.irq;
@@ -801,10 +790,9 @@ static int hdlcdrv_probe(struct net_device *dev)
dev->get_stats = hdlcdrv_get_stats;
/* Fill in the fields of the device structure */
-
dev_init_buffers(dev);
- skb_queue_head_init(&s->send_queue);
+ s->skb = NULL;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
dev->hard_header = ax25_encapsulate;
@@ -821,6 +809,7 @@ static int hdlcdrv_probe(struct net_device *dev)
dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+ dev->tx_queue_len = 16;
/* New style flags */
dev->flags = 0;
@@ -857,8 +846,6 @@ int hdlcdrv_register_hdlcdrv(struct net_device *dev, const struct hdlcdrv_ops *o
dev->name = s->ifname;
dev->if_port = 0;
dev->init = hdlcdrv_probe;
- dev->start = 0;
- dev->tbusy = 1;
dev->base_addr = baseaddr;
dev->irq = irq;
dev->dma = dma;
@@ -884,7 +871,7 @@ int hdlcdrv_unregister_hdlcdrv(struct net_device *dev)
return -EINVAL;
if (s->magic != HDLCDRV_MAGIC)
return -EINVAL;
- if (dev->start && s->ops->close)
+ if (s->ops->close)
s->ops->close(dev);
unregister_netdev(dev);
kfree(s);
@@ -911,8 +898,8 @@ MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
int __init init_module(void)
{
- printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n");
- printk(KERN_INFO "hdlcdrv: version 0.7 compiled " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "hdlcdrv: (C) 1996-2000 Thomas Sailer HB9JNX/AE4WA\n");
+ printk(KERN_INFO "hdlcdrv: version 0.8 compiled " __TIME__ " " __DATE__ "\n");
return 0;
}
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 4de421874..09bb422f1 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1,7 +1,7 @@
#define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $"
#define VERSION "3.0"
-#define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n"
+#define BANNER "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n"
/*
* Please use z8530drv-utils-3.0 with this version.
@@ -19,7 +19,7 @@
********************************************************************
- Copyright (c) 1993, 1998 Joerg Reuter DL1BKE
+ Copyright (c) 1993, 2000 Joerg Reuter DL1BKE
portions (c) 1993 Guido ten Dolle PE1NNZ
@@ -104,6 +104,9 @@
flags that aren't... Restarting the DPLL does not help
either, it resynchronizes too slow and the first received
frame gets lost.
+ 2000-02-13 Fixed for new network driver interface changes, still
+ does TX timeouts itself since it uses its own queue
+ scheme.
Thanks to all who contributed to this driver with ideas and bug
reports!
@@ -236,9 +239,6 @@ static unsigned char Driver_Initialized = 0;
static int Nchips = 0;
static io_port Vector_Latch = 0;
-MODULE_AUTHOR("Joerg Reuter <jreuter@poboxes.com>");
-MODULE_DESCRIPTION("Network Device Driver for Z8530 based HDLC cards for Amateur Packet Radio");
-MODULE_SUPPORTED_DEVICE("scc");
/* ******************************************************************** */
/* * Port Access Functions * */
@@ -314,17 +314,6 @@ static inline void scc_sti(int irq)
/* * Some useful macros * */
/* ******************************************************************** */
-
-static inline void scc_lock_dev(struct scc_channel *scc)
-{
- scc->dev->tbusy = 1;
-}
-
-static inline void scc_unlock_dev(struct scc_channel *scc)
-{
- scc->dev->tbusy = 0;
-}
-
static inline void scc_discard_buffers(struct scc_channel *scc)
{
unsigned long flags;
@@ -382,7 +371,7 @@ static inline void flush_rx_FIFO(struct scc_channel *scc)
if(scc->rx_buff != NULL) /* did we receive something? */
{
scc->stat.rxerrs++; /* then count it as an error */
- kfree_skb(scc->rx_buff);
+ dev_kfree_skb_irq(scc->rx_buff);
scc->rx_buff = NULL;
}
}
@@ -411,7 +400,7 @@ static inline void scc_txint(struct scc_channel *scc)
{
skb = skb_dequeue(&scc->tx_queue);
scc->tx_buff = skb;
- scc_unlock_dev(scc);
+ netif_wake_queue(scc->dev);
if (skb == NULL)
{
@@ -422,7 +411,7 @@ static inline void scc_txint(struct scc_channel *scc)
if (skb->len == 0) /* Paranoia... */
{
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
scc->tx_buff = NULL;
scc_tx_done(scc);
Outb(scc->ctrl, RES_Tx_P);
@@ -448,7 +437,7 @@ static inline void scc_txint(struct scc_channel *scc)
{
Outb(scc->ctrl, RES_Tx_P); /* reset pending int */
cl(scc, R10, ABUNDER); /* send CRC */
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
scc->tx_buff = NULL;
scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */
return;
@@ -533,7 +522,7 @@ static inline void scc_exint(struct scc_channel *scc)
if (scc->tx_buff != NULL)
{
- dev_kfree_skb(scc->tx_buff);
+ dev_kfree_skb_irq(scc->tx_buff);
scc->tx_buff = NULL;
}
@@ -583,7 +572,7 @@ static inline void scc_rxint(struct scc_channel *scc)
#ifdef notdef
printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n");
#endif
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
scc->rx_buff = NULL;
Inb(scc->data);
or(scc, R3, ENT_HM);
@@ -613,7 +602,7 @@ static inline void scc_spint(struct scc_channel *scc)
or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
if (skb != NULL)
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
scc->rx_buff = NULL;
}
@@ -629,7 +618,7 @@ static inline void scc_spint(struct scc_channel *scc)
scc->rx_buff = NULL;
scc->stat.rxframes++;
} else { /* a bad frame */
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
scc->rx_buff = NULL;
scc->stat.rxerrs++;
}
@@ -1112,7 +1101,7 @@ static void scc_tx_done(struct scc_channel *scc)
scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
}
- scc_unlock_dev(scc);
+ netif_wake_queue(scc->dev);
}
@@ -1163,7 +1152,7 @@ static void t_dwait(unsigned long channel)
if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */
{
scc->stat.tx_state = TXS_IDLE;
- scc_unlock_dev(scc); /* t_maxkeyup locked it. */
+ netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */
return;
}
@@ -1243,7 +1232,7 @@ static void t_tail(unsigned long channel)
}
scc->stat.tx_state = TXS_IDLE;
- scc_unlock_dev(scc);
+ netif_wake_queue(scc->dev);
}
@@ -1257,14 +1246,13 @@ static void t_busy(unsigned long channel)
struct scc_channel *scc = (struct scc_channel *) channel;
del_timer(&scc->tx_t);
- scc_lock_dev(scc);
+ netif_stop_queue(scc->dev); /* don't pile on the wabbit! */
scc_discard_buffers(scc);
-
scc->stat.txerrs++;
scc->stat.tx_state = TXS_IDLE;
-
- scc_unlock_dev(scc);
+
+ netif_wake_queue(scc->dev);
}
/* MAXKEYUP timeout
@@ -1285,7 +1273,7 @@ static void t_maxkeyup(unsigned long channel)
* accept new data.
*/
- scc_lock_dev(scc);
+ netif_stop_queue(scc->dev);
scc_discard_buffers(scc);
del_timer(&scc->tx_t);
@@ -1460,8 +1448,7 @@ static void scc_stop_calibrate(unsigned long channel)
Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
Outb(scc->ctrl,RES_EXT_INT);
- scc_unlock_dev(scc);
-
+ netif_wake_queue(scc->dev);
restore_flags(flags);
}
@@ -1474,7 +1461,7 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern
save_flags(flags);
cli();
- scc_lock_dev(scc);
+ netif_stop_queue(scc->dev);
scc_discard_buffers(scc);
del_timer(&scc->tx_wdog);
@@ -1497,7 +1484,6 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern
Outb(scc->ctrl,RES_EXT_INT);
scc_key_trx(scc, TX_ON);
-
restore_flags(flags);
}
@@ -1583,7 +1569,9 @@ static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev
dev = scc->dev;
memset(dev, 0, sizeof(struct net_device));
- buf = (unsigned char *) kmalloc(10, GFP_KERNEL);
+ if ((buf = (unsigned char *) kmalloc(10, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
strcpy(buf, name);
dev->priv = (void *) scc;
@@ -1627,6 +1615,7 @@ static int scc_net_init(struct net_device *dev)
dev->set_mac_address = scc_net_set_mac_address;
dev->get_stats = scc_net_get_stats;
dev->do_ioctl = scc_net_ioctl;
+ dev->tx_timeout = NULL;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
@@ -1647,22 +1636,17 @@ static int scc_net_open(struct net_device *dev)
{
struct scc_channel *scc = (struct scc_channel *) dev->priv;
- if (scc == NULL || scc->magic != SCC_MAGIC)
- return -ENODEV;
-
if (!scc->init)
return -EINVAL;
MOD_INC_USE_COUNT;
-
+
scc->tx_buff = NULL;
skb_queue_head_init(&scc->tx_queue);
init_channel(scc);
- dev->tbusy = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
return 0;
}
@@ -1673,10 +1657,7 @@ static int scc_net_close(struct net_device *dev)
struct scc_channel *scc = (struct scc_channel *) dev->priv;
unsigned long flags;
- if (scc == NULL || scc->magic != SCC_MAGIC)
- return -ENODEV;
-
- MOD_DEC_USE_COUNT;
+ netif_stop_queue(dev);
save_flags(flags);
cli();
@@ -1692,9 +1673,7 @@ static int scc_net_close(struct net_device *dev)
scc_discard_buffers(scc);
- dev->tbusy = 1;
- dev->start = 0;
-
+ MOD_DEC_USE_COUNT;
return 0;
}
@@ -1704,7 +1683,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
{
if (skb->len == 0)
{
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
return;
}
@@ -1726,12 +1705,6 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
struct scc_channel *scc = (struct scc_channel *) dev->priv;
unsigned long flags;
char kisscmd;
-
- if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy)
- {
- dev_kfree_skb(skb);
- return 0;
- }
if (skb->len > scc->stat.bufsize || skb->len < 2)
{
@@ -1759,12 +1732,12 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len)
{
struct sk_buff *skb_del;
- skb_del = __skb_dequeue(&scc->tx_queue);
+ skb_del = skb_dequeue(&scc->tx_queue);
dev_kfree_skb(skb_del);
}
- __skb_queue_tail(&scc->tx_queue, skb);
-
+ skb_queue_tail(&scc->tx_queue, skb);
dev->trans_start = jiffies;
+
/*
* Start transmission if the trx state is idle or
@@ -1781,8 +1754,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
scc_start_tx_timer(scc, t_dwait, 0);
}
- restore_flags(flags);
-
+ restore_flags(flags);
return 0;
}
@@ -1811,9 +1783,6 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct scc_channel *scc;
scc = (struct scc_channel *) dev->priv;
- if (scc == NULL || scc->magic != SCC_MAGIC)
- return -EINVAL;
-
arg = (void *) ifr->ifr_data;
if (!Driver_Initialized)
@@ -2052,9 +2021,6 @@ static struct net_device_stats *scc_net_get_stats(struct net_device *dev)
{
struct scc_channel *scc = (struct scc_channel *) dev->priv;
- if (scc == NULL || scc->magic != SCC_MAGIC)
- return NULL;
-
scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over;
scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under;
scc->dev_stat.rx_fifo_errors = scc->stat.rx_over;
@@ -2186,7 +2152,7 @@ done:
/* * Init SCC driver * */
/* ******************************************************************** */
-int __init scc_init (void)
+static int __init scc_init_driver (void)
{
int chip, chan, k, result;
char devname[10];
@@ -2222,25 +2188,7 @@ int __init scc_init (void)
return 0;
}
-/* ******************************************************************** */
-/* * Module support * */
-/* ******************************************************************** */
-
-
-#ifdef MODULE
-int init_module(void)
-{
- int result = 0;
-
- result = scc_init();
-
- if (result == 0)
- printk(KERN_INFO "Copyright 1993,1998 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n");
-
- return result;
-}
-
-void cleanup_module(void)
+static void __exit scc_cleanup_driver(void)
{
long flags;
io_port ctrl;
@@ -2283,4 +2231,9 @@ void cleanup_module(void)
scc_net_procfs_remove();
}
-#endif
+
+MODULE_AUTHOR("Joerg Reuter <jreuter@poboxes.com>");
+MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards");
+MODULE_SUPPORTED_DEVICE("scc");
+module_init(scc_init_driver);
+module_exit(scc_cleanup_driver);
diff --git a/drivers/net/hamradio/soundmodem/sm.c b/drivers/net/hamradio/soundmodem/sm.c
index 6fa4aca6b..4e5e3e9b9 100644
--- a/drivers/net/hamradio/soundmodem/sm.c
+++ b/drivers/net/hamradio/soundmodem/sm.c
@@ -3,7 +3,7 @@
/*
* sm.c -- soundcard radio modem driver.
*
- * Copyright (C) 1996-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,17 +34,18 @@
*
*
* History:
- * 0.1 21.09.96 Started
- * 18.10.96 Changed to new user space access routines (copy_{to,from}_user)
- * 0.4 21.01.97 Separately compileable soundcard/modem modules
- * 0.5 03.03.97 fixed LPT probing (check_lpt result was interpreted the wrong way round)
- * 0.6 16.04.97 init code/data tagged
- * 0.7 30.07.97 fixed halfduplex interrupt handlers/hotfix for CS423X
- * 0.8 14.04.98 cleanups
- * 0.9 03.08.99 adapt to Linus' new __setup/__initcall
- * use parport lowlevel drivers instead of directly writing to a parallel port
- * removed some pre-2.2 kernel compatibility cruft
- * 0.10 10.08.99 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.1 21.09.1996 Started
+ * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
+ * 0.4 21.01.1997 Separately compileable soundcard/modem modules
+ * 0.5 03.03.1997 fixed LPT probing (check_lpt result was interpreted the wrong way round)
+ * 0.6 16.04.1997 init code/data tagged
+ * 0.7 30.07.1997 fixed halfduplex interrupt handlers/hotfix for CS423X
+ * 0.8 14.04.1998 cleanups
+ * 0.9 03.08.1999 adapt to Linus' new __setup/__initcall
+ * use parport lowlevel drivers instead of directly writing to a parallel port
+ * removed some pre-2.2 kernel compatibility cruft
+ * 0.10 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
+ * 0.11 12.02.2000 adapted to softnet driver interface
*/
/*****************************************************************************/
@@ -63,8 +64,8 @@
/* --------------------------------------------------------------------- */
/*static*/ const char sm_drvname[] = "soundmodem";
-static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "soundmodem: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
+static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "soundmodem: version 0.11 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -508,7 +509,7 @@ static int sm_ioctl(struct net_device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (dev->start || !suser())
+ if (netif_running(dev) || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return sethw(dev, sm, hi->data.modename);
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index e99d4c7a9..400facbf8 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -649,7 +649,7 @@ static void yam_dotimer(unsigned long dummy)
for (i = 0; i < NR_PORTS; i++) {
struct net_device *dev = &yam_ports[i].dev;
- if (dev->start)
+ if (netif_running(dev))
yam_arbitrate(dev);
}
yam_timer.expires = jiffies + HZ / 100;
@@ -748,7 +748,7 @@ static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs)
yp = &yam_ports[i];
dev = &yp->dev;
- if (!dev->start)
+ if (!netif_running(dev))
continue;
while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
@@ -794,7 +794,7 @@ static int yam_net_get_info(char *buffer, char **start, off_t offset, int length
if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0)
continue;
len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name);
- len += sprintf(buffer + len, " Up %d\n", yam_ports[i].dev.start);
+ len += sprintf(buffer + len, " Up %d\n", netif_running(&yam_ports[i].dev));
len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate);
len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase);
len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate);
@@ -903,7 +903,9 @@ static int yam_open(struct net_device *dev)
request_region(dev->base_addr, YAM_EXTENT, dev->name);
yam_set_uart(dev);
- dev->start = 1;
+
+ netif_start_queue(dev);
+
yp->slotcnt = yp->slot / 10;
/* Reset overruns for all ports - FPGA programming makes overruns */
@@ -935,8 +937,7 @@ static int yam_close(struct net_device *dev)
/* Remove IRQ handler if last */
free_irq(dev->irq, NULL);
release_region(dev->base_addr, YAM_EXTENT);
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
while ((skb = skb_dequeue(&yp->send_queue)))
dev_kfree_skb(skb);
@@ -973,7 +974,7 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL; /* unused */
case SIOCYAMSMCS:
- if (dev->start)
+ if (netif_running(dev))
return -EINVAL; /* Cannot change this parameter when up */
ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC);
ym->bitrate = 9600;
@@ -989,13 +990,13 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
return -EFAULT;
- if ((yi.cfg.mask & YAM_IOBASE) && dev->start)
+ if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev))
return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_IRQ) && dev->start)
+ if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev))
return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_BITRATE) && dev->start)
+ if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev))
return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start)
+ if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev))
return -EINVAL; /* Cannot change this parameter when up */
if (yi.cfg.mask & YAM_IOBASE) {
@@ -1164,8 +1165,6 @@ int __init yam_init(void)
dev->irq = yam_ports[i].irq;
dev->init = yam_probe;
dev->if_port = 0;
- dev->start = 0;
- dev->tbusy = 1;
if (register_netdev(dev)) {
printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
@@ -1211,7 +1210,7 @@ void cleanup_module(void)
struct net_device *dev = &yam_ports[i].dev;
if (!dev->priv)
continue;
- if (dev->start)
+ if (netif_running(dev))
yam_close(dev);
unregister_netdev(dev);
}
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index 922b28437..8e5511da1 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -175,17 +175,16 @@ int __init hydra_probe(struct net_device *dev)
}
strcpy(z->name, "Hydra Ethernet Card");
+ dev = init_etherdev(NULL, sizeof(struct hydra_private));
+ memset(dev->priv, 0, sizeof(struct hydra_private));
+
for(j = 0; j < ETHER_ADDR_LEN; j++)
dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- init_etherdev(dev, 0);
-
- dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct hydra_private));
-
+
dev->base_addr = ZTWO_VADDR(base_addr);
dev->mem_start = ZTWO_VADDR(board);
dev->mem_end = dev->mem_start+0x4000;
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index c0d6d265e..1a52df5f9 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -458,8 +458,7 @@ static void ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs)
ioc3_error(dev, ip, ioc3, eisr);
}
- if (test_bit(LINK_STATE_XOFF, &dev->state) &&
- (TX_BUFFS_AVAIL(ip) >= 0)) {
+ if ((TX_BUFFS_AVAIL(ip) >= 0) && netif_queue_stopped(dev)) {
netif_wake_queue(dev);
}
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index d8832292a..bf001d83d 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -85,6 +85,7 @@ static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts);
static int irport_raw_write(struct net_device *dev, __u8 *buf, int len);
static struct net_device_stats *irport_net_get_stats(struct net_device *dev);
static int irport_change_speed_complete(struct irda_task *task);
+static void irport_timeout(struct net_device *dev);
EXPORT_SYMBOL(irport_open);
EXPORT_SYMBOL(irport_close);
@@ -92,6 +93,7 @@ EXPORT_SYMBOL(irport_start);
EXPORT_SYMBOL(irport_stop);
EXPORT_SYMBOL(irport_interrupt);
EXPORT_SYMBOL(irport_hard_xmit);
+EXPORT_SYMBOL(irport_timeout);
EXPORT_SYMBOL(irport_change_speed);
EXPORT_SYMBOL(irport_net_open);
EXPORT_SYMBOL(irport_net_close);
@@ -227,6 +229,8 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
/* Override the network functions we need to use */
dev->init = irport_net_init;
dev->hard_start_xmit = irport_hard_xmit;
+ dev->tx_timeout = irport_timeout;
+ dev->watchdog_timeo = HZ/20;
dev->open = irport_net_open;
dev->stop = irport_net_close;
dev->get_stats = irport_net_get_stats;
@@ -505,16 +509,11 @@ static void irport_write_wakeup(struct irport_cb *self)
NULL, (void *) self->new_speed);
self->new_speed = 0;
} else {
- self->netdev->tbusy = 0; /* Unlock */
-
/* Tell network layer that we want more frames */
- mark_bh(NET_BH);
+ netif_wake_queue(self->netdev);
}
self->stats.tx_packets++;
- /* Schedule network layer, so we can get some more frames */
- mark_bh(NET_BH);
-
/*
* Reset Rx FIFO to make sure that all reflected transmit data
* is discarded. This is needed for half duplex operation
@@ -577,16 +576,37 @@ static int irport_change_speed_complete(struct irda_task *task)
ASSERT(self->netdev != NULL, return -1;);
/* Finished changing speed, so we are not busy any longer */
- self->netdev->tbusy = 0;
-
/* Signal network layer so it can try to send the frame */
- mark_bh(NET_BH);
+ netif_wake_queue(self->netdev);
+
return 0;
}
/*
- * Function irport_xmit (void)
+ * Function irport_timeout (struct net_device *dev)
+ *
+ * The networking layer thinks we timed out.
+ *
+ */
+
+static void irport_timeout(struct net_device *dev)
+{
+ struct irport_cb *self;
+ int iobase;
+
+ self = (struct irport_cb *) dev->priv;
+ iobase = self->io.sir_base;
+
+ WARNING("%s: transmit timed out\n", dev->name);
+ irport_start(self);
+ self->change_speed(self->priv, self->io.speed);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+/*
+ * Function irport_hard_start_xmit (struct sk_buff *skb, struct net_device *dev)
*
* Transmits the current frame until FIFO is full, then
* waits until the next transmitt interrupt, and continues until the
@@ -606,19 +626,8 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
iobase = self->io.sir_base;
- /* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE) {
- int tickssofar = jiffies - dev->trans_start;
- if ((tickssofar < 5) || !dev->start)
- return -EBUSY;
-
- WARNING("%s: transmit timed out\n", dev->name);
- irport_start(self);
- self->change_speed(self->priv, self->io.speed);
-
- dev->trans_start = jiffies;
- }
-
+ netif_stop_queue(dev);
+
/* Check if we need to change the speed */
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
@@ -696,8 +705,6 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&self->lock);
- dev->interrupt = 1;
-
iobase = self->io.sir_base;
iir = inb(iobase+UART_IIR) & UART_IIR_ID;
@@ -733,8 +740,6 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
iir = inb(iobase + UART_IIR) & UART_IIR_ID;
}
- dev->interrupt = 0;
-
spin_unlock(&self->lock);
}
@@ -770,10 +775,6 @@ int irport_net_open(struct net_device *dev)
irport_start(self);
- /* Ready to play! */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
/*
* Open new IrLAP layer instance, now that everything should be
@@ -782,7 +783,10 @@ int irport_net_open(struct net_device *dev)
self->irlap = irlap_open(dev, &self->qos);
/* FIXME: change speed of dongle */
+ /* Ready to play! */
+ netif_start_queue(dev);
+
MOD_INC_USE_COUNT;
return 0;
@@ -809,9 +813,8 @@ int irport_net_close(struct net_device *dev)
iobase = self->io.sir_base;
/* Stop device */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index 370a9c7fe..931ae9c4c 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -615,11 +615,9 @@ static int irtty_change_speed_complete(struct irda_task *task)
ASSERT(self->netdev != NULL, return -1;);
/* Finished changing speed, so we are not busy any longer */
- self->netdev->tbusy = 0;
-
/* Signal network layer so it can try to send the frame */
- mark_bh(NET_BH);
-
+ netif_wake_queue(self->netdev);
+
return 0;
}
@@ -639,9 +637,8 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
ASSERT(self != NULL, return 0;);
/* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE)
- return -EBUSY;
-
+ netif_stop_queue(dev);
+
/* Check if we need to change the speed */
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
@@ -727,10 +724,8 @@ static void irtty_write_wakeup(struct tty_struct *tty)
NULL, (void *) self->new_speed);
self->new_speed = 0;
} else {
- self->netdev->tbusy = 0; /* Unlock */
-
/* Tell network layer that we want more frames */
- mark_bh(NET_BH);
+ netif_wake_queue(self->netdev);
}
}
}
@@ -899,10 +894,8 @@ static int irtty_net_open(struct net_device *dev)
IRDA_DEBUG(0, __FUNCTION__ "()\n");
/* Ready to play! */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
+
/* Make sure we can receive more data */
irtty_stop_receiver(self, FALSE);
@@ -928,9 +921,8 @@ static int irtty_net_close(struct net_device *dev)
irtty_stop_receiver(self, TRUE);
/* Stop device */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 5e30b22ad..1886ec73a 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1033,8 +1033,6 @@ static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
switch_bank(iobase, BANK2);
outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
- self->netdev->tbusy = 0;
-
/* Enable some interrupts so we can receive frames */
switch_bank(iobase, BANK0);
if (speed > 115200) {
@@ -1050,6 +1048,8 @@ static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
/* Restore BSR */
outb(bank, iobase+BSR);
+ netif_wake_queue(dev);
+
}
/*
@@ -1072,10 +1072,8 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
iobase = self->io.fir_base;
- /* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE)
- return -EBUSY;
-
+ netif_stop_queue(dev);
+
/* Check if we need to change the speed */
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
@@ -1118,10 +1116,8 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
self = (struct nsc_ircc_cb *) dev->priv;
iobase = self->io.fir_base;
- /* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE)
- return -EBUSY;
-
+ netif_stop_queue(dev);
+
/* Check if we need to change the speed */
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
@@ -1199,7 +1195,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
out:
/* Not busy transmitting anymore if window is not full */
if (self->tx_fifo.free < MAX_TX_WINDOW)
- dev->tbusy = 0;
+ netif_wake_queue(self->netdev);
/* Restore bank register */
outb(bank, iobase+BSR);
@@ -1347,10 +1343,8 @@ static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
/* Make sure we have room for more frames */
if (self->tx_fifo.free < MAX_TX_WINDOW) {
/* Not busy transmitting anymore */
- self->netdev->tbusy = 0;
-
/* Tell the network layer, that we can accept more frames */
- mark_bh(NET_BH);
+ netif_wake_queue(self->netdev);
}
/* Restore bank */
@@ -1601,11 +1595,9 @@ static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
if (self->tx_buff.len > 0)
self->ier = IER_TXLDL_IE;
else {
- self->netdev->tbusy = 0; /* Unlock */
- self->stats.tx_packets++;
-
- mark_bh(NET_BH);
+ self->stats.tx_packets++;
+ netif_wakeup_queue(self->netdev);
self->ier = IER_TXEMP_IE;
}
@@ -1731,7 +1723,6 @@ static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
self = (struct nsc_ircc_cb *) dev->priv;
spin_lock(&self->lock);
- dev->interrupt = 1;
iobase = self->io.fir_base;
@@ -1754,7 +1745,6 @@ static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
outb(self->ier, iobase+IER); /* Restore interrupts */
outb(bsr, iobase+BSR); /* Restore bank register */
- dev->interrupt = 0;
spin_unlock(&self->lock);
}
@@ -1860,10 +1850,9 @@ static int nsc_ircc_net_open(struct net_device *dev)
outb(bank, iobase+BSR);
/* Ready to play! */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
+
/*
* Open new IrLAP layer instance, now that everything should be
* initialized properly
@@ -1895,9 +1884,8 @@ static int nsc_ircc_net_close(struct net_device *dev)
ASSERT(self != NULL, return 0;);
/* Stop device */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
index 3420b670b..951b08d8f 100644
--- a/drivers/net/irda/toshoboe.c
+++ b/drivers/net/irda/toshoboe.c
@@ -275,6 +275,8 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
+ netif_stop_queue(dev);
+
if (self->stopped) {
dev_kfree_skb(skb);
return 0;
@@ -318,17 +320,14 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
self->txpending++;
- /*FIXME: ask about tbusy,media_busy stuff, for the moment */
- /*tbusy means can't queue any more */
+ /*FIXME: ask about busy,media_busy stuff, for the moment */
+ /*busy means can't queue any more */
#ifndef ONETASK
- if (self->txpending == TX_SLOTS)
- {
-#else
+ if (self->txpending != TX_SLOTS)
{
-#endif
- if (irda_lock ((void *) &dev->tbusy) == FALSE)
- return -EBUSY;
+ netif_wake_queue(dev);
}
+#endif
outb_p (0x80, OBOE_RST);
outb_p (1, OBOE_REG_9);
@@ -379,10 +378,8 @@ toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
self->new_speed = 0;
}
- self->netdev->tbusy = 0; /* Unlock */
-
/* Tell network layer that we want more frames */
- mark_bh(NET_BH);
+ netif_wake_queue(self->netdev);
}
if (irqstat & OBOE_ISR_RXDONE)
@@ -529,10 +526,7 @@ toshoboe_net_open (struct net_device *dev)
toshoboe_initptrs (self);
/* Ready to play! */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
/*
* Open new IrLAP layer instance, now that everything should be
* initialized properly
@@ -559,9 +553,8 @@ toshoboe_net_close (struct net_device *dev)
self = (struct toshoboe_cb *) dev->priv;
/* Stop device */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
@@ -926,11 +919,7 @@ toshoboe_wakeup (struct toshoboe_cb *self)
toshoboe_initptrs (self);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
- self->stopped = 0;
-
+ netif_wake_queue(self->netdev);
restore_flags (flags);
printk (KERN_WARNING "ToshOboe: waking up\n");
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 7f781719c..239120e51 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -475,8 +475,8 @@ void w83977af_change_speed(struct w83977af_ir *self, __u32 speed)
outb(UFR_EN_FIFO, iobase+UFR); /* First we must enable FIFO */
outb(0xa7, iobase+UFR);
- self->netdev->tbusy = 0;
-
+ netif_wake_queue(self->netdev);
+
/* Enable some interrupts so we can receive frames */
switch_bank(iobase, SET0);
if (speed > PIO_MAX_SPEED) {
@@ -511,9 +511,8 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
(int) skb->len);
/* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE)
- return -EBUSY;
-
+ netif_stop_queue(dev);
+
/* Check if we need to change the speed */
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
@@ -715,11 +714,9 @@ void w83977af_dma_xmit_complete(struct w83977af_ir *self)
}
/* Unlock tx_buff and request another frame */
- self->netdev->tbusy = 0; /* Unlock */
-
/* Tell the network layer, that we want more frames */
- mark_bh(NET_BH);
-
+ netif_wake_queue(self->netdev);
+
/* Restore set */
outb(set, iobase+SSR);
}
@@ -991,12 +988,10 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr)
outb(AUDR_SFEND, iobase+AUDR);
outb(set, iobase+SSR);
- self->netdev->tbusy = 0; /* Unlock */
self->stats.tx_packets++;
- /* Schedule network layer */
- mark_bh(NET_BH);
-
+ /* Feed me more packets */
+ netif_wake_queue(self->netdev);
new_icr |= ICR_ETBREI;
}
}
@@ -1124,8 +1119,6 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
self = (struct w83977af_ir *) dev->priv;
- dev->interrupt = 1;
-
iobase = self->io.fir_base;
/* Save current bank */
@@ -1148,7 +1141,6 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs)
outb(icr, iobase+ICR); /* Restore (new) interrupts */
outb(set, iobase+SSR); /* Restore bank register */
- self->netdev->interrupt = 0;
}
/*
@@ -1250,10 +1242,8 @@ static int w83977af_net_open(struct net_device *dev)
outb(set, iobase+SSR);
/* Ready to play! */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
+
/*
* Open new IrLAP layer instance, now that everything should be
* initialized properly
@@ -1288,9 +1278,8 @@ static int w83977af_net_close(struct net_device *dev)
iobase = self->io.fir_base;
/* Stop device */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
/* Stop and remove instance of IrLAP */
if (self->irlap)
irlap_close(self->irlap);
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 0151d4d52..689ffbd22 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -195,6 +195,8 @@ tx_full and tbusy flags.
#define LANCE_BUS_IF 0x16
#define LANCE_TOTAL_SIZE 0x18
+#define TX_TIMEOUT 20
+
/* The LANCE Rx and Tx ring descriptors. */
struct lance_rx_head {
s32 base;
@@ -237,7 +239,7 @@ struct lance_private {
struct net_device_stats stats;
unsigned char chip_version; /* See lance_chip_type. */
char tx_full;
- unsigned long lock;
+ spinlock_t devlock;
};
#define LANCE_MUST_PAD 0x00000001
@@ -296,6 +298,7 @@ static void lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int lance_close(struct net_device *dev);
static struct net_device_stats *lance_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
+static void lance_tx_timeout (struct net_device *dev);
@@ -518,6 +521,7 @@ int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options
lp->tx_bounce_buffs = NULL;
lp->chip_version = lance_version;
+ lp->devlock = SPIN_LOCK_UNLOCKED;
lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */
for (i = 0; i < 6; i++)
@@ -676,6 +680,8 @@ int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options
dev->stop = lance_close;
dev->get_stats = lance_get_stats;
dev->set_multicast_list = set_multicast_list;
+ dev->tx_timeout = lance_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
return 0;
}
@@ -747,9 +753,8 @@ lance_open(struct net_device *dev)
outw(0x0000, ioaddr+LANCE_ADDR);
outw(0x0001, ioaddr+LANCE_DATA);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue (dev);
+
i = 0;
while (i++ < 100)
if (inw(ioaddr+LANCE_DATA) & 0x0100)
@@ -801,7 +806,7 @@ lance_init_ring(struct net_device *dev, int gfp)
struct lance_private *lp = (struct lance_private *)dev->priv;
int i;
- lp->lock = 0, lp->tx_full = 0;
+ lp->tx_full = 0;
lp->cur_rx = lp->cur_tx = 0;
lp->dirty_rx = lp->dirty_tx = 0;
@@ -852,48 +857,47 @@ lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit)
outw(csr0_bits, dev->base_addr + LANCE_DATA);
}
-static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+static void lance_tx_timeout (struct net_device *dev)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = (struct lance_private *) dev->priv;
int ioaddr = dev->base_addr;
- int entry;
- unsigned long flags;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 20)
- return 1;
- outw(0, ioaddr+LANCE_ADDR);
- printk("%s: transmit timed out, status %4.4x, resetting.\n",
- dev->name, inw(ioaddr+LANCE_DATA));
- outw(0x0004, ioaddr+LANCE_DATA);
- lp->stats.tx_errors++;
+ outw (0, ioaddr + LANCE_ADDR);
+ printk ("%s: transmit timed out, status %4.4x, resetting.\n",
+ dev->name, inw (ioaddr + LANCE_DATA));
+ outw (0x0004, ioaddr + LANCE_DATA);
+ lp->stats.tx_errors++;
#ifndef final_version
- {
- int i;
- printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
- lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
- lp->cur_rx);
- for (i = 0 ; i < RX_RING_SIZE; i++)
- printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
- lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
- lp->rx_ring[i].msg_length);
- for (i = 0 ; i < TX_RING_SIZE; i++)
- printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
- lp->tx_ring[i].base, -lp->tx_ring[i].length,
- lp->tx_ring[i].misc);
- printk("\n");
- }
+ {
+ int i;
+ printk (" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+ lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+ lp->cur_rx);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+ lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+ lp->rx_ring[i].msg_length);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+ lp->tx_ring[i].base, -lp->tx_ring[i].length,
+ lp->tx_ring[i].misc);
+ printk ("\n");
+ }
#endif
- lance_restart(dev, 0x0043, 1);
+ lance_restart (dev, 0x0043, 1);
- dev->tbusy=0;
- dev->trans_start = jiffies;
+ dev->trans_start = jiffies;
+ netif_start_queue (dev);
+}
- return 0;
- }
+static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int entry;
+ unsigned long flags;
if (lance_debug > 3) {
outw(0x0000, ioaddr+LANCE_ADDR);
printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
@@ -901,20 +905,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw(0x0000, ioaddr+LANCE_DATA);
}
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
-
- if (test_and_set_bit(0, (void*)&lp->lock) != 0) {
- if (lance_debug > 0)
- printk("%s: tx queue lock!.\n", dev->name);
- /* don't clear dev->tbusy flag. */
- return 1;
- }
-
+ netif_stop_queue (dev);
+
/* Fill in a Tx ring entry */
/* Mask to ring buffer boundary. */
@@ -955,14 +947,12 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- save_flags(flags);
- cli();
- lp->lock = 0;
+ spin_lock_irqsave (&lp->devlock, flags);
if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
- dev->tbusy=0;
+ netif_start_queue (dev);
else
lp->tx_full = 1;
- restore_flags(flags);
+ spin_unlock_irqrestore (&lp->devlock, flags);
return 0;
}
@@ -983,10 +973,8 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
ioaddr = dev->base_addr;
lp = (struct lance_private *)dev->priv;
- if (dev->interrupt)
- printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
-
- dev->interrupt = 1;
+
+ spin_lock (&lp->devlock);
outw(0x00, dev->base_addr + LANCE_ADDR);
while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600
@@ -1040,7 +1028,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* We must free the original skb if it's not a data-only copy
in the bounce buffer. */
if (lp->tx_skbuff[entry]) {
- dev_kfree_skb(lp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(lp->tx_skbuff[entry]);
lp->tx_skbuff[entry] = 0;
}
dirty_tx++;
@@ -1054,12 +1042,12 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
#endif
- if (lp->tx_full && dev->tbusy
- && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+ if (lp->tx_full &&
+ (netif_queue_stopped(dev)) &&
+ dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
/* The ring is no longer full, clear tbusy. */
lp->tx_full = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
}
lp->dirty_tx = dirty_tx;
@@ -1092,8 +1080,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
dev->name, inw(ioaddr + LANCE_ADDR),
inw(dev->base_addr + LANCE_DATA));
- dev->interrupt = 0;
- return;
+ spin_unlock (&lp->devlock);
}
static int
@@ -1181,8 +1168,7 @@ lance_close(struct net_device *dev)
struct lance_private *lp = (struct lance_private *)dev->priv;
int i;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue (dev);
if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
outw(112, ioaddr+LANCE_ADDR);
diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c
index f572a5ea6..e461f8807 100644
--- a/drivers/net/ltpc.c
+++ b/drivers/net/ltpc.c
@@ -246,23 +246,9 @@ static int sendup_buffer (struct net_device *dev);
/* Dma Memory related stuff, cribbed directly from 3c505.c */
-/* Pure 2^n version of get_order */
-static inline int __get_order(unsigned long size)
-{
- int order;
-
- size = (size - 1) >> (PAGE_SHIFT - 1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
static unsigned long dma_mem_alloc(int size)
{
- int order = __get_order(size);
+ int order = get_order(size);
return __get_dma_pages(GFP_KERNEL, order);
}
@@ -1364,7 +1350,7 @@ void cleanup_module(void)
if(debug&DEBUG_VERBOSE) printk("free_pages\n");
- free_pages( (unsigned long) ltdmabuf, __get_order(1000));
+ free_pages( (unsigned long) ltdmabuf, get_order(1000));
ltdmabuf=NULL;
ltdmacbuf=NULL;
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 3a69c5c80..ac0771bd8 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -20,9 +20,7 @@
#include <asm/pgtable.h>
#include "mace.h"
-#ifdef MODULE
static struct net_device *mace_devs = NULL;
-#endif
#define N_RX_RING 8
#define N_TX_RING 6
@@ -55,6 +53,7 @@ struct mace_data {
struct net_device_stats stats;
struct timer_list tx_timeout;
int timeout_active;
+ struct net_device *next_mace;
};
/*
@@ -67,6 +66,8 @@ struct mace_data {
+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
static int bitrev(int);
+static int mace_probe(void);
+static void mace_probe1(struct device_node *mace);
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -99,34 +100,36 @@ bitrev(int b)
return d;
}
-static int __init mace_probe (void)
+static int __init mace_probe(void)
+{
+ struct device_node *mace;
+
+ for (mace = find_devices("mace"); mace != NULL; mace = mace->next)
+ mace_probe1(mace);
+ return 0;
+}
+
+static void __init mace_probe1(struct device_node *mace)
{
int j, rev;
struct net_device *dev;
struct mace_data *mp;
- struct device_node *mace;
unsigned char *addr;
- static int maces_found = 0;
- static struct device_node *next_mace;
-
-#ifdef MODULE
- if(mace_devs != NULL)
- return -EBUSY;
-#endif
-
- if (!maces_found) {
- next_mace = find_devices("mace");
- maces_found = 1;
- }
- mace = next_mace;
- if (mace == 0)
- return -ENODEV;
- next_mace = mace->next;
if (mace->n_addrs != 3 || mace->n_intrs != 3) {
- printk(KERN_ERR "can't use MACE %s: expect 3 addrs and 3 intrs\n",
+ printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
mace->full_name);
- return -ENODEV;
+ return;
+ }
+
+ addr = get_property(mace, "mac-address", NULL);
+ if (addr == NULL) {
+ addr = get_property(mace, "local-mac-address", NULL);
+ if (addr == NULL) {
+ printk(KERN_ERR "Can't get mac-address for MACE %s\n",
+ mace->full_name);
+ return;
+ }
}
dev = init_etherdev(0, PRIV_BYTES);
@@ -138,16 +141,6 @@ static int __init mace_probe (void)
ioremap(mace->addrs[0].address, 0x1000);
dev->irq = mace->intrs[0].line;
- addr = get_property(mace, "mac-address", NULL);
- if (addr == NULL) {
- addr = get_property(mace, "local-mac-address", NULL);
- if (addr == NULL) {
- printk(KERN_ERR "Can't get mac-address for MACE at %lx\n",
- dev->base_addr);
- return -EAGAIN;
- }
- }
-
printk(KERN_INFO "%s: MACE at", dev->name);
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j) {
@@ -186,22 +179,17 @@ static int __init mace_probe (void)
mace_reset(dev);
- if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
+ if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev))
printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
- return -EAGAIN;
- }
if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma",
- dev)) {
+ dev))
printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line);
- return -EAGAIN;
- }
if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma",
- dev)) {
+ dev))
printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line);
- return -EAGAIN;
- }
- return 0;
+ mp->next_mace = mace_devs;
+ mace_devs = dev;
}
static void dbdma_reset(volatile struct dbdma_regs *dma)
@@ -365,9 +353,7 @@ static int mace_open(struct net_device *dev)
/* enable all interrupts except receive interrupts */
out_8(&mb->imr, RCVINT);
-#ifdef MOD_INC_USE_COUNT
MOD_INC_USE_COUNT;
-#endif
return 0;
}
@@ -406,9 +392,7 @@ static int mace_close(struct net_device *dev)
mace_clean_rings(mp);
-#ifdef MOD_DEC_USE_COUNT
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
@@ -445,7 +429,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
if (next >= N_TX_RING)
next = 0;
if (next == mp->tx_empty) {
- dev->tbusy = 1;
+ netif_stop_queue(dev);
mp->tx_fullup = 1;
restore_flags(flags);
return 1; /* can't take it at the moment */
@@ -480,7 +464,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
if (++next >= N_TX_RING)
next = 0;
if (next == mp->tx_empty)
- dev->tbusy = 1;
+ netif_stop_queue(dev);
restore_flags(flags);
return 0;
@@ -683,7 +667,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mp->stats.tx_bytes += mp->tx_bufs[i]->len;
++mp->stats.tx_packets;
}
- dev_kfree_skb(mp->tx_bufs[i]);
+ dev_kfree_skb_irq(mp->tx_bufs[i]);
--mp->tx_active;
if (++i >= N_TX_RING)
i = 0;
@@ -695,8 +679,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (i != mp->tx_empty) {
mp->tx_fullup = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
mp->tx_empty = i;
i += mp->tx_active;
@@ -765,8 +748,7 @@ static void mace_tx_timeout(unsigned long data)
mp->tx_empty = i;
}
mp->tx_fullup = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
if (i != mp->tx_fill) {
cp = mp->tx_cmds + NCMDS_TX * i;
out_le16(&cp->xfer_status, 0);
@@ -897,23 +879,25 @@ static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
}
}
-
MODULE_AUTHOR("Paul Mackerras");
MODULE_DESCRIPTION("PowerMac MACE driver.");
static void __exit mace_cleanup (void)
{
-#ifdef MODULE
- struct mace_data *mp = (struct mace_data *) mace_devs->priv;
- unregister_netdev(mace_devs);
+ struct net_device *dev;
+ struct mace_data *mp;
- free_irq(mace_devs->irq, mace_interrupt);
- free_irq(mp->tx_dma_intr, mace_txdma_intr);
- free_irq(mp->rx_dma_intr, mace_rxdma_intr);
+ while ((dev = mace_devs) != 0) {
+ mp = (struct mace_data *) mace_devs->priv;
+ mace_devs = mp->next_mace;
- kfree(mace_devs);
- mace_devs = NULL;
-#endif
+ free_irq(dev->irq, dev);
+ free_irq(mp->tx_dma_intr, dev);
+ free_irq(mp->rx_dma_intr, dev);
+
+ unregister_netdev(dev);
+ kfree(dev);
+ }
}
module_init(mace_probe);
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 3c4e23016..bd1406e1f 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -256,7 +256,7 @@ static void myri_clean_rings(struct myri_eth *mp)
u32 dma_addr;
dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE);
+ sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
dev_kfree_skb(mp->rx_skbs[i]);
mp->rx_skbs[i] = NULL;
}
@@ -272,7 +272,7 @@ static void myri_clean_rings(struct myri_eth *mp)
u32 dma_addr;
dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3);
+ sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);
dev_kfree_skb(mp->tx_skbs[i]);
mp->tx_skbs[i] = NULL;
}
@@ -301,7 +301,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
skb->dev = dev;
skb_put(skb, RX_ALLOC_SIZE);
- dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE);
+ dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr);
sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len);
sbus_writel(i, &rxd[i].ctx);
@@ -363,7 +363,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
DTX(("SKB[%d] ", entry));
dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len);
+ sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
dev_kfree_skb(skb);
mp->tx_skbs[entry] = NULL;
mp->enet_stats.tx_packets++;
@@ -444,7 +444,7 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
sbus_dma_sync_single(mp->myri_sdev,
sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE);
+ RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
DRX(("ERROR["));
mp->enet_stats.rx_errors++;
@@ -481,13 +481,15 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
}
sbus_unmap_single(mp->myri_sdev,
sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE);
+ RX_ALLOC_SIZE,
+ SBUS_DMA_FROMDEVICE);
mp->rx_skbs[index] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, RX_ALLOC_SIZE);
dma_addr = sbus_map_single(mp->myri_sdev,
new_skb->data,
- RX_ALLOC_SIZE);
+ RX_ALLOC_SIZE,
+ SBUS_DMA_FROMDEVICE);
sbus_writel(dma_addr, &rxd->myri_scatters[0].addr);
sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
sbus_writel(index, &rxd->ctx);
@@ -650,7 +652,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]);
}
- dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len);
+ dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE);
sbus_writel(dma_addr, &txd->myri_gathers[0].addr);
sbus_writel(len, &txd->myri_gathers[0].len);
sbus_writel(1, &txd->num_sg);
diff --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c
index fd120de2b..6a8c8b412 100644
--- a/drivers/net/ncr885e.c
+++ b/drivers/net/ncr885e.c
@@ -11,9 +11,10 @@
*/
static const char *version =
-"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n";
+"ncr885e.c:v1.0 02/10/00 dan@synergymicro.com, cort@fsmlabs.com\n";
#include <linux/config.h>
+
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
@@ -81,8 +82,6 @@ static const char *chipname = "ncr885e";
int ncr885e_debug = NCR885E_DEBUG;
static int print_version = 0;
-static int debug = NCR885E_DEBUG; /* module parm */
-
struct ncr885e_private {
@@ -426,7 +425,6 @@ ncr885e_tx( struct net_device *dev )
if ( xfer ) {
dev_kfree_skb( sp->tx_skbufs[i] );
- mark_bh( NET_BH );
if ( txbits & TX_STATUS_TXOK ) {
sp->stats.tx_packets++;
@@ -443,7 +441,7 @@ ncr885e_tx( struct net_device *dev )
}
- dev->tbusy = 0;
+ netif_start_queue(dev);
return;
}
@@ -626,12 +624,6 @@ ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs )
sp = (struct ncr885e_private *) dev->priv;
spin_lock( &sp->lock );
- if ( dev->interrupt ) {
- printk( KERN_ERR "%s: Re-entering interrupt handler...\n",
- dev->name );
- }
-
- dev->interrupt = 1;
status = inw( ioaddr + INTERRUPT_CLEAR );
if (ncr885e_debug > 2)
@@ -671,7 +663,6 @@ ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs )
ncr885e_rx( dev );
}
- dev->interrupt = 0;
spin_unlock( &sp->lock );
return;
@@ -779,8 +770,7 @@ ncr885e_tx_timeout( unsigned long data )
/* start anew from the beginning of the ring buffer (why not?) */
sp->tx_current = 0;
- dev->tbusy = 0;
- mark_bh( NET_BH );
+ netif_wake_queue(dev);
/* restart rx dma */
outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN,
@@ -958,9 +948,7 @@ ncr885e_open( struct net_device *dev )
outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
ioaddr + RX_CHANNEL_CONTROL );
- dev->start = 1;
- dev->tbusy = 0;
- dev->interrupt = 0;
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
@@ -990,7 +978,7 @@ ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev )
next = 0;
/* mark ourselves as busy, even if we have too many packets waiting */
- dev->tbusy = 1;
+ netif_stop_queue(dev);
/* see if it's necessary to defer this packet */
if ( sp->tx_active >= MAX_TX_ACTIVE ) {
@@ -1058,8 +1046,7 @@ ncr885e_close(struct net_device *dev)
struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
unsigned long ioaddr = dev->base_addr;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
spin_lock( &np->lock );
@@ -1148,8 +1135,7 @@ ncr885e_stats( struct net_device *dev )
* configuration.
*/
-static int
-ncr885e_probe1(unsigned long ioaddr, unsigned char irq )
+static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq )
{
struct net_device *dev;
@@ -1158,9 +1144,6 @@ ncr885e_probe1(unsigned long ioaddr, unsigned char irq )
unsigned char *p;
int i;
- if (!request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name))
- return -EBUSY;
-
dev = init_etherdev(NULL, 0 );
/* construct private data for the 885 ethernet */
@@ -1413,12 +1396,16 @@ write_mii( unsigned long ioaddr, int reg, int data )
#endif /* NCR885E_DEBUG_MII */
-MODULE_AUTHOR("dan@synergymicro.com");
-MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver");
-MODULE_PARM(debug, "i");
+int
+init_module(void)
+{
+ if ( debug >= 0)
+ ncr885e_debug = debug;
+ return ncr885e_probe();
+}
-static void __exit ncr885e_cleanup (void)
+static void __exit cleanup_module(void)
{
struct ncr885e_private *np;
@@ -1435,7 +1422,6 @@ static void __exit ncr885e_cleanup (void)
module_init(ncr885e_probe);
module_exit(ncr885e_cleanup);
-
/*
* Local variables:
* compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O6 -c symba.c"
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 0a69d9004..269300c0d 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -425,9 +425,8 @@ static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_get_8390_hdr "
- "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
return;
}
@@ -468,9 +467,8 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk
If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_block_input "
- "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
return;
}
ei_status.dmaing |= 0x01;
@@ -537,9 +535,8 @@ static void ne_block_output(struct net_device *dev, int count,
If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_block_output."
- "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
+ "[DMAstat:%d][irqlock:%d]\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
return;
}
ei_status.dmaing |= 0x01;
diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c
index 93b2f9923..b4fc3e0a8 100644
--- a/drivers/net/net_init.c
+++ b/drivers/net/net_init.c
@@ -153,7 +153,7 @@ struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv)
static int eth_mac_addr(struct net_device *dev, void *p)
{
struct sockaddr *addr=p;
- if(test_bit(LINK_STATE_START, &dev->state))
+ if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
return 0;
@@ -200,7 +200,7 @@ static int hippi_change_mtu(struct net_device *dev, int new_mtu)
static int hippi_mac_addr(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
- if(test_bit(LINK_STATE_START, &dev->state))
+ if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
return 0;
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 9a81ff0f7..8e5bca56a 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -106,6 +106,7 @@ static int ni5010_open(struct net_device *dev);
static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev);
static void ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void ni5010_rx(struct net_device *dev);
+static void ni5010_timeout(struct net_device *dev);
static int ni5010_close(struct net_device *dev);
static struct net_device_stats *ni5010_get_stats(struct net_device *dev);
static void ni5010_set_multicast_list(struct net_device *dev);
@@ -320,15 +321,13 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
dev->stop = ni5010_close;
dev->hard_start_xmit = ni5010_send_packet;
dev->get_stats = ni5010_get_stats;
- dev->set_multicast_list = &ni5010_set_multicast_list;
+ dev->set_multicast_list = ni5010_set_multicast_list;
+ dev->tx_timeout = ni5010_timeout;
+ dev->watchdog_timeo = HZ/20;
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 0;
-
dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */
/* Shut up the ni5010 */
@@ -403,10 +402,8 @@ static int ni5010_open(struct net_device *dev)
outb(0, EDLC_RESET); /* Un-reset the ni5010 */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
+
if (NI5010_DEBUG) show_registers(dev);
MOD_INC_USE_COUNT;
@@ -426,42 +423,31 @@ static void reset_receiver(struct net_device *dev)
outb(0xff, EDLC_RMASK); /* Enable all rcv interrupts */
}
+static void ni5010_timeout(struct net_device *dev)
+{
+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+ tx_done(dev) ? "IRQ conflict" : "network cable problem");
+ /* Try to restart the adaptor. */
+ /* FIXME: Give it a real kick here */
+ chipset_init(dev, 1);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
{
+ int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+
PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name));
- if (dev->tbusy) {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("tbusy\n");
- printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
- /* Try to restart the adaptor. */
- /* FIXME: Give it a real kick here */
- chipset_init(dev, 1);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
/*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but test_and_set_bit() works as well.
+ * Block sending
*/
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- } else {
- int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-
- hardware_send_packet(dev, (unsigned char *)skb->data, length);
- dev->trans_start = jiffies;
- }
+
+ netif_stop_queue(dev);
+ hardware_send_packet(dev, (unsigned char *)skb->data, length);
+ dev->trans_start = jiffies;
dev_kfree_skb (skb);
-
return 0;
}
@@ -469,23 +455,13 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
-static void
-ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct ni5010_local *lp;
int ioaddr, status;
int xmit_was_error = 0;
- if (dev == NULL || dev->irq != irq) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
- boardname, irq);
- return;
- }
-
- if (dev->interrupt) printk(KERN_WARNING "%s: Reentering IRQ-handler!\n", dev->name);
- dev->interrupt = 1;
-
PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name));
ioaddr = dev->base_addr;
@@ -507,8 +483,6 @@ ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (!xmit_was_error)
reset_receiver(dev);
-
- dev->interrupt = 0;
return;
}
@@ -530,8 +504,7 @@ static void dump_packet(void *buf, int len)
}
/* We have a good packet, get it out of the buffer. */
-static void
-ni5010_rx(struct net_device *dev)
+static void ni5010_rx(struct net_device *dev)
{
struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
int ioaddr = dev->base_addr;
@@ -624,8 +597,7 @@ static int process_xmt_interrupt(struct net_device *dev)
lp->stats.tx_packets++;
lp->stats.tx_bytes += lp->o_pkt_size;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev);
PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
dev->name, lp->o_pkt_size));
@@ -634,8 +606,7 @@ static int process_xmt_interrupt(struct net_device *dev)
}
/* The inverse routine to ni5010_open(). */
-static int
-ni5010_close(struct net_device *dev)
+static int ni5010_close(struct net_device *dev)
{
int ioaddr = dev->base_addr;
@@ -647,9 +618,8 @@ ni5010_close(struct net_device *dev)
outb(0, IE_MMODE);
outb(RS_RESET, EDLC_RESET);
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
MOD_DEC_USE_COUNT;
PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname));
return 0;
@@ -658,8 +628,7 @@ ni5010_close(struct net_device *dev)
/* Get the current statistics. This may be called with the card open or
closed. */
-static struct net_device_stats *
-ni5010_get_stats(struct net_device *dev)
+static struct net_device_stats *ni5010_get_stats(struct net_device *dev)
{
struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
@@ -681,8 +650,7 @@ ni5010_get_stats(struct net_device *dev)
num_addrs > 0 Multicast mode, receive normal and MC packets, and do
best-effort filtering.
*/
-static void
-ni5010_set_multicast_list(struct net_device *dev)
+static void ni5010_set_multicast_list(struct net_device *dev)
{
short ioaddr = dev->base_addr;
@@ -748,6 +716,8 @@ extern void hardware_send_packet(struct net_device *dev, char *buf, int length)
restore_flags(flags);
+ netif_wake_queue(dev);
+
if (NI5010_DEBUG) show_registers(dev);
}
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 7efc0dca6..6d1d0e714 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -199,6 +199,7 @@ static int ni52_close(struct net_device *dev);
static int ni52_send_packet(struct sk_buff *,struct net_device *);
static struct net_device_stats *ni52_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
+static void ni52_timeout(struct net_device *dev);
#if 0
static void ni52_dump(struct net_device *,void *);
#endif
@@ -244,9 +245,7 @@ static int ni52_close(struct net_device *dev)
ni_reset586(); /* the hard way to stop the receiver */
- dev->start = 0;
- dev->tbusy = 0;
-
+ netif_stop_queue(dev);
MOD_DEC_USE_COUNT;
return 0;
@@ -269,10 +268,7 @@ static int ni52_open(struct net_device *dev)
return -EAGAIN;
}
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0; /* most done by init */
@@ -512,20 +508,18 @@ static int __init ni52_probe1(struct net_device *dev,int ioaddr)
printk("IRQ %d (assigned and not checked!).\n",dev->irq);
}
- dev->open = &ni52_open;
- dev->stop = &ni52_close;
- dev->get_stats = &ni52_get_stats;
- dev->hard_start_xmit = &ni52_send_packet;
- dev->set_multicast_list = &set_multicast_list;
+ dev->open = ni52_open;
+ dev->stop = ni52_close;
+ dev->get_stats = ni52_get_stats;
+ dev->tx_timeout = ni52_timeout;
+ dev->watchdog_timeo = HZ/20;
+ dev->hard_start_xmit = ni52_send_packet;
+ dev->set_multicast_list = set_multicast_list;
dev->if_port = 0;
ether_setup(dev);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 0;
-
return 0;
}
@@ -831,8 +825,6 @@ static void ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
if(debuglevel > 1)
printk("I");
- dev->interrupt = 1;
-
WAIT_4_SCB_CMD(); /* wait for last command */
while((stat=p->scb->cus & STAT_MASK))
@@ -866,7 +858,7 @@ static void ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
#ifndef NO_NOPCOMMANDS
if(stat & STAT_CNA) /* CU went 'not ready' */
{
- if(dev->start)
+ if(netif_running(dev))
printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
}
#endif
@@ -885,8 +877,6 @@ static void ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
if(debuglevel > 1)
printk("i");
-
- dev->interrupt = 0;
}
/*******************************************************
@@ -1083,9 +1073,7 @@ static void ni52_xmt_int(struct net_device *dev)
if( (++p->xmit_last) == NUM_XMIT_BUFFS)
p->xmit_last = 0;
#endif
-
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
/***********************************************************
@@ -1104,6 +1092,40 @@ static void startrecv586(struct net_device *dev)
WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */
}
+static void ni52_timeout(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+#ifndef NO_NOPCOMMANDS
+ if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+ {
+ netif_wake_queue(dev);
+#ifdef DEBUG
+ printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+ printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point);
+#endif
+ p->scb->cmd_cuc = CUC_ABORT;
+ ni_attn586();
+ WAIT_4_SCB_CMD();
+ p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+ p->scb->cmd_cuc = CUC_START;
+ ni_attn586();
+ WAIT_4_SCB_CMD();
+ dev->trans_start = jiffies;
+ return 0;
+ }
+#endif
+ {
+#ifdef DEBUG
+ printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+ printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
+ printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+#endif
+ ni52_close(dev);
+ ni52_open(dev);
+ }
+ dev->trans_start = jiffies;
+}
+
/******************************************************
* send frame
*/
@@ -1116,62 +1138,21 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
#endif
struct priv *p = (struct priv *) dev->priv;
- if(dev->tbusy)
- {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
-
-#ifndef NO_NOPCOMMANDS
- if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
- {
- dev->tbusy = 0;
-#ifdef DEBUG
- printk("%s: strange ... timeout with CU active?!?\n",dev->name);
- printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point);
-#endif
- p->scb->cmd_cuc = CUC_ABORT;
- ni_attn586();
- WAIT_4_SCB_CMD();
- p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
- p->scb->cmd_cuc = CUC_START;
- ni_attn586();
- WAIT_4_SCB_CMD();
- dev->trans_start = jiffies;
- return 0;
- }
- else
-#endif
- {
-#ifdef DEBUG
- printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
- printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
- printk("%s: check, whether you set the right interrupt number!\n",dev->name);
-#endif
- ni52_close(dev);
- ni52_open(dev);
- }
- dev->trans_start = jiffies;
- return 0;
- }
-
if(skb->len > XMIT_BUFF_SIZE)
{
printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
return 0;
}
- if (test_and_set_bit(0, (void*)&dev->tbusy)) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
+ netif_stop_queue(dev);
+
#if(NUM_XMIT_BUFFS > 1)
- else if(test_and_set_bit(0,(void *) &p->lock)) {
+ if(test_and_set_bit(0,(void *) &p->lock)) {
printk("%s: Queue was locked\n",dev->name);
return 1;
}
-#endif
else
+#endif
{
memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
@@ -1231,7 +1212,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
next_nop = 0;
p->xmit_cmds[p->xmit_count]->cmd_status = 0;
- /* linkpointer of xmit-command already points to next nop cmd */
+ /* linkpointer of xmit-command already points to next nop cmd */
p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
p->nop_cmds[next_nop]->cmd_status = 0;
@@ -1240,11 +1221,11 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
p->xmit_count = next_nop;
{
- long flags;
+ unsigned long flags;
save_flags(flags);
cli();
if(p->xmit_count != p->xmit_last)
- dev->tbusy = 0;
+ netif_wake_queue(dev);
p->lock = 0;
restore_flags(flags);
}
@@ -1283,23 +1264,16 @@ static struct net_device_stats *ni52_get_stats(struct net_device *dev)
/********************************************************
* Set MC list ..
*/
+
static void set_multicast_list(struct net_device *dev)
{
- if(!dev->start)
- {
- printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
- return;
- }
-
- dev->start = 0;
-
+ netif_stop_queue(dev);
ni_disint();
alloc586(dev);
init586(dev);
startrecv586(dev);
ni_enaint();
-
- dev->start = 1;
+ netif_wake_queue(dev);
}
#ifdef MODULE
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 5c671a4ea..2e82ceca5 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -228,6 +228,7 @@ static int ni65_open(struct net_device *dev);
static int ni65_lance_reinit(struct net_device *dev);
static void ni65_init_lance(struct priv *p,unsigned char*,int,int);
static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void ni65_timeout(struct net_device *dev);
static int ni65_close(struct net_device *dev);
static int ni65_alloc_buffer(struct net_device *dev);
static void ni65_free_buffer(struct priv *p);
@@ -278,16 +279,13 @@ static int ni65_open(struct net_device *dev)
if(ni65_lance_reinit(dev))
{
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
}
else
{
free_irq(dev->irq,dev);
- dev->start = 0;
return -EAGAIN;
}
}
@@ -299,6 +297,8 @@ static int ni65_close(struct net_device *dev)
{
struct priv *p = (struct priv *) dev->priv;
+ netif_stop_queue(dev);
+
outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
#ifdef XMT_VIA_SKB
@@ -314,8 +314,6 @@ static int ni65_close(struct net_device *dev)
}
#endif
free_irq(dev->irq,dev);
- dev->tbusy = 1;
- dev->start = 0;
MOD_DEC_USE_COUNT;
return 0;
}
@@ -482,15 +480,13 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
dev->open = ni65_open;
dev->stop = ni65_close;
dev->hard_start_xmit = ni65_send_packet;
+ dev->tx_timeout = ni65_timeout;
+ dev->watchdog_timeo = HZ/2;
dev->get_stats = ni65_get_stats;
dev->set_multicast_list = set_multicast_list;
ether_setup(dev);
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 0;
-
return 0; /* everything is OK */
}
@@ -714,7 +710,8 @@ static void ni65_stop_start(struct net_device *dev,struct priv *p)
}
p->rmdnum = p->tmdlast = 0;
if(!p->lock)
- dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
+ if (p->tmdnum || !p->xmit_queued)
+ netif_wake_queue(dev);
dev->trans_start = jiffies;
}
else
@@ -813,15 +810,6 @@ static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
struct priv *p;
int bcnt = 32;
- if (dev == NULL) {
- printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
-
- if(test_and_set_bit(0,(int *) &dev->interrupt)) {
- printk("ni65: oops .. interrupt while proceeding interrupt\n");
- return;
- }
p = (struct priv *) dev->priv;
while(--bcnt) {
@@ -916,8 +904,6 @@ static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
else
writedatareg(CSR0_INEA);
- dev->interrupt = 0;
-
return;
}
@@ -974,7 +960,7 @@ static void ni65_xmit_intr(struct net_device *dev,int csr0)
#ifdef XMT_VIA_SKB
if(p->tmd_skb[p->tmdlast]) {
- dev_kfree_skb(p->tmd_skb[p->tmdlast]);
+ dev_kfree_skb_irq(p->tmd_skb[p->tmdlast]);
p->tmd_skb[p->tmdlast] = NULL;
}
#endif
@@ -983,8 +969,7 @@ static void ni65_xmit_intr(struct net_device *dev,int csr0)
if(p->tmdlast == p->tmdnum)
p->xmit_queued = 0;
}
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
/*
@@ -1082,32 +1067,31 @@ static void ni65_recv_intr(struct net_device *dev,int csr0)
/*
* kick xmitter ..
*/
-static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
+
+static void ni65_timeout(struct net_device *dev)
{
+ int i;
struct priv *p = (struct priv *) dev->priv;
- if(dev->tbusy)
- {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 50)
- return 1;
+ printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
+ for(i=0;i<TMDNUM;i++)
+ printk("%02x ",p->tmdhead[i].u.s.status);
+ printk("\n");
+ ni65_lance_reinit(dev);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
- printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
- {
- int i;
- for(i=0;i<TMDNUM;i++)
- printk("%02x ",p->tmdhead[i].u.s.status);
- printk("\n");
- }
- ni65_lance_reinit(dev);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
+/*
+ * Send a packet
+ */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
+static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ netif_stop_queue(dev);
+
if (test_and_set_bit(0, (void*)&p->lock)) {
printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
return 1;
@@ -1152,7 +1136,9 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
p->xmit_queued = 1;
p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
- dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0;
+ if(p->tmdnum != p->tmdlast)
+ netif_wake_queue(dev);
+
p->lock = 0;
dev->trans_start = jiffies;
@@ -1183,7 +1169,7 @@ static void set_multicast_list(struct net_device *dev)
{
if(!ni65_lance_reinit(dev))
printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name);
- dev->tbusy = 0;
+ netif_wake_queue(dev);
}
#ifdef MODULE
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 4e4fc4157..2b5624b29 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -105,11 +105,6 @@ MODULE_PARM(irq_mask, "i");
MODULE_PARM(irq_list, "1-4i");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(full_duplex, "i");
-#ifdef BROKEN_FEATURES
-MODULE_PARM(use_fifo_buffer, "i");
-MODULE_PARM(use_memory_ops, "i");
-MODULE_PARM(no_wait, "i");
-#endif
/* Now-standard PC card module parameters. */
static u_int irq_mask = 0xdeb8; /* IRQ3,4,5,7,9,10,11,12,14,15 */
@@ -124,16 +119,6 @@ static int max_interrupt_work = 32;
/* Force full duplex modes? */
static int full_duplex = 0;
-#ifdef BROKEN_FEATURES
-/* Performance features: best left disabled. */
-/* Set to buffer all Tx/RxFIFO accesses. */
-static int use_fifo_buffer = 0;
-/* Set iff memory ops are faster than I/O ops. */
-static int use_memory_ops = 0;
-/* Set iff disabling the WAIT signal is reliable and faster. */
-static int no_wait = 0;
-#endif
-
/* To minimize the size of the driver source and make the driver more
readable not all constants are symbolically defined.
You'll need the manual if you want to understand driver details anyway. */
@@ -220,6 +205,7 @@ struct el3_private {
u_short media_status;
u_short fast_poll;
u_long last_irq;
+ spinlock_t lock;
};
/* Set iff a MII transceiver on any interface requires mdio preamble.
@@ -261,6 +247,7 @@ static int el3_rx(struct net_device *dev, int worklimit);
static int el3_close(struct net_device *dev);
static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
+static void el3_tx_timeout(struct net_device *dev);
static dev_info_t dev_info = "3c574_cs";
@@ -320,6 +307,8 @@ static dev_link_t *tc574_attach(void)
lp = kmalloc(sizeof(*lp), GFP_KERNEL);
if (!lp) return NULL;
memset(lp, 0, sizeof(*lp));
+
+ lp->lock = SPIN_LOCK_UNLOCKED;
link = &lp->link; dev = &lp->dev;
link->priv = dev->priv = link->irq.Instance = lp;
@@ -351,7 +340,10 @@ static dev_link_t *tc574_attach(void)
dev->init = &tc574_init;
dev->open = &el3_open;
dev->stop = &el3_close;
- dev->tbusy = 1;
+ dev->tx_timeout = el3_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ netif_start_queue (dev);
/* Register with Card Services */
link->next = dev_list;
@@ -398,13 +390,12 @@ static void tc574_detach(dev_link_t *link)
if (*linkp == NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&lp->lock, flags);
if (link->state & DEV_RELEASE_PENDING) {
del_timer(&link->release);
link->state &= ~DEV_RELEASE_PENDING;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&lp->lock, flags);
if (link->state & DEV_CONFIG) {
tc574_release((u_long)link);
@@ -478,31 +469,10 @@ static void tc574_config(dev_link_t *link)
CS_CHECK(RequestIRQ, link->handle, &link->irq);
CS_CHECK(RequestConfiguration, link->handle, &link->conf);
- dev->mem_start = 0;
-#ifdef BROKEN_FEATURES
- if (use_memory_ops) {
- win_req_t req;
- memreq_t mem;
- req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM |
- WIN_ENABLE | WIN_USE_WAIT;
- req.Base = 0;
- req.Size = 0x1000;
- req.AccessSpeed = 0;
- link->win = (window_handle_t)link->handle;
- i = CardServices(RequestWindow, &link->win, &req);
- if (i == CS_SUCCESS) {
- mem.Page = mem.CardOffset = 0;
- CardServices(MapMemPage, link->win, &mem);
- dev->mem_start = (long)(ioremap(req.Base, 0x1000)) + 0x800;
- } else
- cs_error(link->handle, RequestWindow, i);
- }
-#endif
-
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
if (register_netdev(dev) != 0) {
printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
goto failed;
@@ -545,10 +515,6 @@ static void tc574_config(dev_link_t *link)
for (i = 0; i < 6; i++)
printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
- if (dev->mem_start)
- printk(KERN_INFO" Acceleration window at memory base %#lx.\n",
- dev->mem_start);
-
{
u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
union wn3_config config;
@@ -623,8 +589,6 @@ failed:
static void tc574_release(u_long arg)
{
dev_link_t *link = (dev_link_t *)arg;
- struct el3_private *lp = link->priv;
- struct net_device *dev = &lp->dev;
DEBUG(0, "3c574_release(0x%p)\n", link);
@@ -638,10 +602,6 @@ static void tc574_release(u_long arg)
CardServices(ReleaseConfiguration, link->handle);
CardServices(ReleaseIO, link->handle, &link->io);
CardServices(ReleaseIRQ, link->handle, &link->irq);
- if (link->win) {
- iounmap((void *)(dev->mem_start - 0x800));
- CardServices(ReleaseWindow, link->win);
- }
link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
@@ -667,7 +627,7 @@ static int tc574_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 1; dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = jiffies + HZ/20;
add_timer(&link->release);
}
@@ -681,9 +641,9 @@ static int tc574_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- dev->tbusy = 1; dev->start = 0;
- }
+ if (link->open)
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -695,7 +655,7 @@ static int tc574_event(event_t event, int priority,
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
tc574_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_device_attach(dev);
}
}
break;
@@ -831,19 +791,6 @@ static void tc574_reset(struct net_device *dev)
wait_for_completion(dev, TotalReset|0x10);
-#ifdef BROKEN_FEATURES
- /* Set the PIO ctrl bits in the PC card LAN COR using Runner window 1. */
- if (dev->mem_start || no_wait) {
- u8 lan_cor;
- outw(1<<11, ioaddr + RunnerRdCtrl);
- lan_cor = inw(ioaddr) & ~0x30;
- if (dev->mem_start) /* Iff use_memory_ops worked! */
- lan_cor |= 0x10;
- if (no_wait)
- lan_cor |= 0x20;
- outw(lan_cor, ioaddr);
- }
-#endif
/* Clear any transactions in progress. */
outw(0, ioaddr + RunnerWrCtrl);
outw(0, ioaddr + RunnerRdCtrl);
@@ -877,10 +824,10 @@ static void tc574_reset(struct net_device *dev)
inb(ioaddr + i);
inw(ioaddr + 10);
inw(ioaddr + 12);
-
EL3WINDOW(4);
- /* New: On the Vortex/Odie we must also clear the BadSSD counter.. */
inb(ioaddr + 12);
+ inb(ioaddr + 13);
+
/* .. enable any extra statistics bits.. */
outw(0x0040, ioaddr + Wn4_NetDiag);
/* .. re-sync MII and re-fill what NWay is advertising. */
@@ -913,7 +860,7 @@ static int el3_open(struct net_device *dev)
link->open++;
MOD_INC_USE_COUNT;
- dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
tc574_reset(dev);
lp->media.function = &media_check;
@@ -939,7 +886,7 @@ static void el3_tx_timeout(struct net_device *dev)
/* Issue TX_RESET and TX_START commands. */
wait_for_completion(dev, TxReset);
outw(TxEnable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
+ netif_start_queue (dev);
}
static void pop_tx_status(struct net_device *dev)
@@ -968,60 +915,22 @@ static void pop_tx_status(struct net_device *dev)
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
-#ifdef BROKEN_FEATURES
- long flags = 0;
-#endif
-
- /* Transmitter timeout, serious problems. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- if (jiffies - dev->trans_start < TX_TIMEOUT)
- return 1;
- el3_tx_timeout(dev);
- }
DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
"status %4.4x.\n", dev->name, (long)skb->len,
inw(ioaddr + EL3_STATUS));
-#ifdef BROKEN_FEATURES
- if (use_fifo_buffer) {
- /* Avoid other accesses to the chip while RunnerWrCtrl is non-zero. */
- save_flags(flags);
- cli();
- outw((((skb->len + 7)>>2)<<1), ioaddr + RunnerWrCtrl);
- DEBUG(0, "TxFree %x, tx length %x, RunnerWrCtrl is %4.4x.\n",
- inw(ioaddr+TxFree), skb->len, inw(ioaddr+RunnerWrCtrl));
- }
-
- /* Put out the doubleword header... */
- /* ... and the packet rounded to a doubleword. */
- if (dev->mem_start) {
- writew(skb->len, (void *)dev->mem_start);
- writew(0, (void *)dev->mem_start);
- copy_to_pc((void*)dev->mem_start, skb->data, (skb->len+3)&~3);
- } else {
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0, ioaddr + TX_FIFO);
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
- }
-
- if (use_fifo_buffer) {
- DEBUG(0, " RunnerWr/RdCtrl is %4.4x/%4.4x, TxFree %x.\n",
- inw(ioaddr + RunnerWrCtrl), inw(ioaddr + RunnerRdCtrl),
- inw(ioaddr + TxFree));
- restore_flags(flags);
- }
-#else
+ netif_stop_queue (dev);
+
outw(skb->len, ioaddr + TX_FIFO);
outw(0, ioaddr + TX_FIFO);
outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
-#endif
dev->trans_start = jiffies;
/* TxFree appears only in Window 1, not offset 0x1c. */
if (inw(ioaddr + TxFree) > 1536) {
- dev->tbusy = 0;
+ netif_start_queue (dev);
} else
/* Interrupt us when the FIFO has room for max-sized packet.
The threshold is in units of dwords. */
@@ -1041,23 +950,20 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ioaddr_t ioaddr, status;
int work_budget = max_interrupt_work;
- if ((lp == NULL) || !dev->start)
+ if (!netif_device_present(dev))
return;
+
+ spin_lock (&lp->lock);
+
ioaddr = dev->base_addr;
-#ifdef PCMCIA_DEBUG
- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
- printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
- dev->name);
- return;
- }
DEBUG(3, "%s: interrupt, status %4.4x.\n",
dev->name, inw(ioaddr + EL3_STATUS));
-#endif
while ((status = inw(ioaddr + EL3_STATUS)) &
(IntLatch | RxComplete | RxEarly | StatsFull)) {
- if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) {
+
+ if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) {
DEBUG(1, "%s: Interrupt from dead card\n", dev->name);
break;
}
@@ -1069,8 +975,9 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
DEBUG(3, " TX room bit was handled.\n");
/* There's room in the FIFO for a full-sized packet. */
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
+ } else {
+ netif_stop_queue (dev);
}
if (status & TxComplete)
@@ -1117,12 +1024,10 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
}
-#ifdef PCMCIA_DEBUG
DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
dev->name, inw(ioaddr + EL3_STATUS));
- dev->interrupt = 0;
-#endif
- return;
+
+ spin_unlock (&lp->lock);
}
/*
@@ -1138,7 +1043,8 @@ static void media_check(u_long arg)
u_long flags;
u_short /* cable, */ media, partner;
- if (dev->start == 0) goto reschedule;
+ if (!netif_device_present(dev))
+ goto reschedule;
/* Check for pending interrupt with expired latency timer: with
this, we can limp along even if the interrupt is blocked */
@@ -1208,7 +1114,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
{
struct el3_private *lp = (struct el3_private *)dev->priv;
- if (dev->start)
+ if (netif_device_present(dev))
update_stats(dev);
return &lp->stats;
}
@@ -1249,6 +1155,12 @@ static void update_stats(struct net_device *dev)
EL3WINDOW(4);
inb(ioaddr + 12);
+ {
+ u8 up = inb(ioaddr + 13);
+ lp->stats.rx_bytes += (up & 0x0f) << 16;
+ lp->stats.tx_bytes += (up & 0xf0) << 12;
+ }
+
EL3WINDOW(1);
}
@@ -1285,30 +1197,8 @@ static int el3_rx(struct net_device *dev, int worklimit)
skb->dev = dev;
skb_reserve(skb, 2);
-#ifdef BROKEN_FEATURES
- if (use_fifo_buffer) {
- outw(((pkt_len+3)>>2)<<1, ioaddr + RunnerRdCtrl);
- DEBUG(0,"Start Rx %x -- RunnerRdCtrl is %4.4x.\n",
- pkt_len, inw(ioaddr + RunnerRdCtrl));
- }
- if (dev->mem_start) {
- copy_from_pc(skb_put(skb, pkt_len),
- (void*)dev->mem_start, (pkt_len+3)&~3);
- } else {
- insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
- ((pkt_len+3)>>2));
- }
- if (use_fifo_buffer) {
- DEBUG(0," RunnerRdCtrl is now %4.4x.\n",
- inw(ioaddr + RunnerRdCtrl));
- outw(0, ioaddr + RunnerRdCtrl);
- DEBUG(0, " Rx packet with data %2.2x:%2.2x:%2.2x\n",
- skb->head[0], skb->head[1], skb->head[2]);
- }
-#else
insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
((pkt_len+3)>>2));
-#endif
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
@@ -1404,6 +1294,8 @@ static int el3_close(struct net_device *dev)
DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
+ netif_stop_queue (dev);
+
if (DEV_OK(link)) {
/* Turn off statistics ASAP. We update lp->stats below. */
outw(StatsDisable, ioaddr + EL3_CMD);
@@ -1419,7 +1311,6 @@ static int el3_close(struct net_device *dev)
}
link->open--;
- dev->start = 0;
del_timer(&lp->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
diff --git a/drivers/net/pcmcia/3c575_cb.c b/drivers/net/pcmcia/3c575_cb.c
index 82f534f0c..e98e1eda8 100644
--- a/drivers/net/pcmcia/3c575_cb.c
+++ b/drivers/net/pcmcia/3c575_cb.c
@@ -53,18 +53,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#error You must compile this driver with "-O".
#endif
-#include <linux/config.h>
-#include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -89,13 +78,6 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#include <linux/delay.h>
-#define PCI_SUPPORT_VER2
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-#if ! defined(CAP_NET_ADMIN)
-#define capable(CAP_XXX) (suser())
-#endif
-
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
MODULE_PARM(debug, "i");
@@ -106,7 +88,6 @@ MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(compaq_ioaddr, "i");
MODULE_PARM(compaq_irq, "i");
MODULE_PARM(compaq_device_id, "i");
-#endif
/* Operational parameter that usually are not changed. */
@@ -209,15 +190,15 @@ struct pci_id_info {
const char *name;
u16 vendor_id, device_id, device_id_mask, flags;
int drv_flags, io_size;
- struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
- long ioaddr, int irq, int chip_idx, int fnd_cnt);
+ struct net_device *(*probe1)(struct pci_dev *pdev, struct net_device *dev,
+ long ioaddr, int irq, int chip_idx, int fnd_cnt);
};
enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
- struct net_device *dev, long ioaddr,
- int irq, int dev_id, int card_idx);
+static struct net_device *vortex_probe1(struct pci_dev *pdev,
+ struct net_device *dev, long ioaddr,
+ int irq, int dev_id, int card_idx);
static struct pci_id_info pci_tbl[] = {
{"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff,
PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
@@ -427,7 +408,7 @@ struct vortex_private {
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
/* PCI configuration space information. */
- u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */
+ struct pci_dev *pdev;
char *cb_fn_base; /* CardBus function status addr space. */
int chip_id;
@@ -451,6 +432,7 @@ struct vortex_private {
u16 advertising; /* NWay media advertisement */
unsigned char phys[2]; /* MII device addresses. */
u16 deferred;
+ spinlock_t lock;
};
/* The action to take with a media selection timer tick.
@@ -501,7 +483,8 @@ static void update_stats(long ioaddr, struct net_device *dev);
static struct net_device_stats *vortex_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void acpi_wake(int pci_bus, int pci_devfn);
+static void vortex_tx_timeout(struct net_device *dev);
+static void acpi_wake(struct pci_dev *pdev);
static void acpi_set_WOL(struct net_device *dev);
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
@@ -542,20 +525,21 @@ static dev_node_t *vortex_attach(dev_locator_t *loc)
{
u16 dev_id, vendor_id;
u32 io;
- u8 bus, devfn, irq;
+ u8 irq;
struct net_device *dev;
int chip_idx;
+ struct pci_dev *pdev;
vortex_reap();
if (loc->bus != LOC_PCI) return NULL;
- bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
- pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
- pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+ pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
+ if (!pdev) return NULL;
+ io = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
+ vendor_id = pdev->vendor;
+ dev_id = pdev->device;
printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
- bus, devfn, dev_id);
- io &= ~3;
+ pdev->bus->number, pdev->devfn, dev_id);
if (io == 0 || irq == 0) {
printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
"assigned an %s.\n" KERN_ERR " It will not be activated.\n",
@@ -572,7 +556,7 @@ static dev_node_t *vortex_attach(dev_locator_t *loc)
"vortex_attach().\n", vendor_id, dev_id);
return NULL;
}
- dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);
+ dev = vortex_probe1(pdev, NULL, io, irq, chip_idx, MAX_UNITS+1);
if (dev) {
dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
strcpy(node->dev_name, dev->name);
@@ -663,44 +647,6 @@ static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[])
int cards_found = 0;
/* Allow an EISA-only driver. */
-#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
- /* Ideally we would detect all cards in slot order. That would
- be best done a central PCI probe dispatch, which wouldn't work
- well with the current structure. So instead we detect 3Com cards
- in slot order. */
- if (pcibios_present()) {
- static int pci_index = 0;
- unsigned char pci_bus, pci_device_fn;
-
- for (;pci_index < 0xff; pci_index++) {
- u16 vendor, device, pci_command, new_command;
- int chip_idx, irq;
- long ioaddr;
-
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
- &pci_bus, &pci_device_fn)
- != PCIBIOS_SUCCESSFUL)
- break;
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_DEVICE_ID, &device);
- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == pci_tbl[chip_idx].vendor_id
- && (device & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
- continue;
-
- /* The Cyclone requires config space re-write if powered down. */
- acpi_wake(pci_bus, pci_device_fn);
-
- {
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->resource[0].start;
- irq = pdev->irq;
-#elif LINUX_VERSION_CODE >= 0x20155
struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
ioaddr = pdev->base_address[0] & ~3;
irq = pdev->irq;
@@ -751,7 +697,6 @@ static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[])
}
}
}
-#endif /* NO_PCI */
/* Now check all slots of the EISA bus. */
if (EISA_bus) {
@@ -787,9 +732,9 @@ static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[])
}
#endif /* ! Cardbus */
-static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
- struct net_device *dev, long ioaddr,
- int irq, int chip_idx, int card_idx)
+static struct net_device *vortex_probe1(struct pci_dev *pdev,
+ struct net_device *dev, long ioaddr,
+ int irq, int chip_idx, int card_idx)
{
struct vortex_private *vp;
int option;
@@ -817,9 +762,9 @@ static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
vp->next_module = root_vortex_dev;
root_vortex_dev = dev;
+ vp->lock = SPIN_LOCK_UNLOCKED;
vp->chip_id = chip_idx;
- vp->pci_bus = pci_bus;
- vp->pci_devfn = pci_devfn;
+ vp->pdev = pdev;
/* The lower four bits are the media type. */
if (dev->mem_start)
@@ -892,10 +837,9 @@ static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
u32 fn_st_addr; /* Cardbus function status space */
- pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2,
- &fn_st_addr);
+ fn_st_addr = pci_resource_start (pdev, 2);
if (fn_st_addr)
- vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
+ vp->cb_fn_base = ioremap(fn_st_addr, 128);
printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n",
dev->name, fn_st_addr, vp->cb_fn_base);
}
@@ -988,6 +932,8 @@ static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
dev->get_stats = &vortex_get_stats;
dev->do_ioctl = &vortex_ioctl;
dev->set_multicast_list = &set_rx_mode;
+ dev->tx_timeout = vortex_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
return dev;
}
@@ -1013,7 +959,7 @@ vortex_up(struct net_device *dev)
int i;
/* Should be if(HAS_ACPI) */
- acpi_wake(vp->pci_bus, vp->pci_devfn);
+ acpi_wake(vp->pdev);
/* Before initializing select the active media port. */
EL3WINDOW(3);
@@ -1157,9 +1103,7 @@ vortex_up(struct net_device *dev)
outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
vp->in_interrupt = 0;
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue (dev);
outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
@@ -1377,8 +1321,10 @@ static void vortex_tx_timeout(struct net_device *dev)
ioaddr + DownListPtr);
if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
vp->tx_full = 0;
- clear_bit(0, (void*)&dev->tbusy);
+ netif_start_queue (dev);
}
+ if (vp->tx_full)
+ netif_stop_queue (dev);
outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
outw(DownUnstall, ioaddr + EL3_CMD);
} else
@@ -1478,12 +1424,8 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- if (jiffies - dev->trans_start >= TX_TIMEOUT)
- vortex_tx_timeout(dev);
- return 1;
- }
-
+ netif_stop_queue (dev);
+
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
if (vp->bus_master) {
@@ -1496,9 +1438,9 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
} else {
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- DEV_FREE_SKB(skb);
+ dev_kfree_skb (skb);
if (inw(ioaddr + TxFree) > 1536) {
- clear_bit(0, (void*)&dev->tbusy);
+ netif_start_queue (dev);
} else
/* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1535,11 +1477,8 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- if (jiffies - dev->trans_start >= TX_TIMEOUT)
- vortex_tx_timeout(dev);
- return 1;
- } else {
+ netif_stop_queue (dev);
+ if (1) {
/* Calculate the next Tx descriptor entry. */
int entry = vp->cur_tx % TX_RING_SIZE;
struct boom_tx_desc *prev_entry =
@@ -1561,8 +1500,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&vp->lock, flags);
/* Wait for the stall to complete. */
wait_for_completion(dev, DownStall);
prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
@@ -1571,16 +1509,17 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
queued_packet++;
}
outw(DownUnstall, ioaddr + EL3_CMD);
- restore_flags(flags);
+ spin_unlock_irqrestore(&vp->lock, flags);
vp->cur_tx++;
- if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
+ if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
vp->tx_full = 1;
- else { /* Clear previous interrupt enable. */
+ netif_stop_queue (dev);
+ } else { /* Clear previous interrupt enable. */
#if defined(tx_interrupt_mitigation)
prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
#endif
- clear_bit(0, (void*)&dev->tbusy);
+ netif_start_queue (dev);
}
dev->trans_start = jiffies;
return 0;
@@ -1597,23 +1536,8 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
int latency, status;
int work_done = max_interrupt_work;
-#if defined(__i386__)
- /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
- printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
- dev->name);
- dev->interrupt = 0; /* Avoid halting machine. */
- return;
- }
-#else
- if (dev->interrupt) {
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
- return;
- }
- dev->interrupt = 1;
-#endif
-
- dev->interrupt = 1;
+ spin_lock (&vp->lock);
+
ioaddr = dev->base_addr;
latency = inb(ioaddr + Timer);
status = inw(ioaddr + EL3_STATUS);
@@ -1643,8 +1567,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_DEBUG " TX room bit was handled.\n");
/* There's room in the FIFO for a full-sized packet. */
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- clear_bit(0, (void*)&dev->tbusy);
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
}
if (status & DownComplete) {
@@ -1657,7 +1580,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
virt_to_bus(&vp->tx_ring[entry]))
break; /* It still hasn't been processed. */
if (vp->tx_skbuff[entry]) {
- DEV_FREE_SKB(vp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(vp->tx_skbuff[entry]);
vp->tx_skbuff[entry] = 0;
}
/* vp->stats.tx_packets++; Counted below. */
@@ -1666,19 +1589,21 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
vp->dirty_tx = dirty_tx;
if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
vp->tx_full = 0;
- clear_bit(0, (void*)&dev->tbusy);
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
}
}
+ if (vp->tx_full)
+ netif_stop_queue (dev);
if (status & DMADone) {
if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
+ dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
if (inw(ioaddr + TxFree) > 1536) {
- clear_bit(0, (void*)&dev->tbusy);
- mark_bh(NET_BH);
- } else /* Interrupt when FIFO has room for max-sized packet. */
+ netif_wake_queue (dev);
+ } else { /* Interrupt when FIFO has room for max-sized packet. */
outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+ netif_stop_queue (dev);
+ }
}
}
/* Check for all uncommon interrupts at once. */
@@ -1715,12 +1640,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
dev->name, status);
handler_exit:
-#if defined(__i386__)
- clear_bit(0, (void*)&dev->interrupt);
-#else
- dev->interrupt = 0;
-#endif
- return;
+ spin_unlock (&vp->lock);
}
static int vortex_rx(struct net_device *dev)
@@ -1891,8 +1811,7 @@ vortex_down(struct net_device *dev)
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue (dev);
del_timer(&vp->timer);
@@ -1926,7 +1845,7 @@ vortex_close(struct net_device *dev)
long ioaddr = dev->base_addr;
int i;
- if (dev->start)
+ if (netif_device_present(dev))
vortex_down(dev);
if (vortex_debug > 1) {
@@ -1942,14 +1861,14 @@ vortex_close(struct net_device *dev)
if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
for (i = 0; i < RX_RING_SIZE; i++)
if (vp->rx_skbuff[i]) {
- DEV_FREE_SKB(vp->rx_skbuff[i]);
+ dev_kfree_skb(vp->rx_skbuff[i]);
vp->rx_skbuff[i] = 0;
}
}
if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
for (i = 0; i < TX_RING_SIZE; i++)
if (vp->tx_skbuff[i]) {
- DEV_FREE_SKB(vp->tx_skbuff[i]);
+ dev_kfree_skb(vp->tx_skbuff[i]);
vp->tx_skbuff[i] = 0;
}
}
@@ -1964,11 +1883,10 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev)
struct vortex_private *vp = (struct vortex_private *)dev->priv;
unsigned long flags;
- if (dev->start) {
- save_flags(flags);
- cli();
+ if (netif_device_present(dev)) {
+ spin_lock_irqsave (&vp->lock, flags);
update_stats(dev->base_addr, dev);
- restore_flags(flags);
+ spin_unlock_irqrestore (&vp->lock, flags);
}
return &vp->stats;
}
@@ -2168,35 +2086,35 @@ static void acpi_set_WOL(struct net_device *dev)
outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
outw(RxEnable, ioaddr + EL3_CMD);
/* Change the power state to D3; RxEnable doesn't take effect. */
- pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103);
+ pci_write_config_word(vp->pdev, 0xe0, 0x8103);
}
/* Change from D3 (sleep) to D0 (active).
Problem: The Cyclone forgets all PCI config info during the transition! */
-static void acpi_wake(int bus, int devfn)
+static void acpi_wake(struct pci_dev *pdev)
{
u32 base0, base1, romaddr;
u16 pci_command, pwr_command;
u8 pci_latency, pci_cacheline, irq;
- pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command);
+ pci_read_config_word(pdev, 0xe0, &pwr_command);
if ((pwr_command & 3) == 0)
return;
- pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command);
- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0);
- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1);
- pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
- pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency);
- pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline);
- pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq);
-
- pcibios_write_config_word( bus, devfn, 0xe0, 0x0000);
- pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0);
- pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1);
- pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr);
- pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq);
- pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency);
- pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline);
- pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5);
+ pci_read_config_word( pdev, PCI_COMMAND, &pci_command);
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base0);
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &base1);
+ pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr);
+ pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency);
+ pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+ pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq);
+
+ pci_write_config_word( pdev, 0xe0, 0x0000);
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, base0);
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base1);
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr);
+ pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq);
+ pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency);
+ pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
+ pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5);
}
#ifdef MODULE
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index e95b87104..33b1dbc60 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -4,7 +4,7 @@
Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
- 3c589_cs.c 1.143 1999/12/30 21:28:10
+ 3c589_cs.c 1.145 2000/02/11 03:11:51
The network driver code is based on Donald Becker's 3c589 code:
@@ -117,7 +117,7 @@ static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
-"3c589_cs.c 1.143 1999/12/30 21:28:10 (David Hinds)";
+"3c589_cs.c 1.145 2000/02/11 03:11:51 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -155,6 +155,7 @@ static void update_stats(struct net_device *dev);
static struct net_device_stats *el3_get_stats(struct net_device *dev);
static int el3_rx(struct net_device *dev);
static int el3_close(struct net_device *dev);
+static void el3_tx_timeout(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -257,7 +258,10 @@ static dev_link_t *tc589_attach(void)
dev->init = &tc589_init;
dev->open = &el3_open;
dev->stop = &el3_close;
- dev->tbusy = 1;
+ dev->tx_timeout = el3_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ netif_start_queue (dev);
/* Register with Card Services */
link->next = dev_list;
@@ -399,7 +403,7 @@ static void tc589_config(dev_link_t *link)
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
if (register_netdev(dev) != 0) {
printk(KERN_NOTICE "3c589_cs: register_netdev() failed\n");
goto failed;
@@ -508,7 +512,7 @@ static int tc589_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 1; dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = jiffies + HZ/20;
add_timer(&link->release);
}
@@ -522,9 +526,9 @@ static int tc589_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- dev->tbusy = 1; dev->start = 0;
- }
+ if (link->open)
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -536,7 +540,7 @@ static int tc589_event(event_t event, int priority,
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
tc589_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_device_attach(dev);
}
}
break;
@@ -683,7 +687,7 @@ static int el3_open(struct net_device *dev)
link->open++;
MOD_INC_USE_COUNT;
- dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
tc589_reset(dev);
lp->media.function = &media_check;
@@ -709,7 +713,7 @@ static void el3_tx_timeout(struct net_device *dev)
/* Issue TX_RESET and TX_START commands. */
wait_for_completion(dev, TxReset);
outw(TxEnable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
+ netif_start_queue (dev);
}
static void pop_tx_status(struct net_device *dev)
@@ -739,37 +743,27 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- if (jiffies - dev->trans_start < TX_TIMEOUT)
- return 1;
- el3_tx_timeout(dev);
- }
-
DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
"status %4.4x.\n", dev->name, (long)skb->len,
inw(ioaddr + EL3_STATUS));
- /* Avoid timer-based retransmission conflicts. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk(KERN_NOTICE "%s: transmitter access conflict.\n",
- dev->name);
- else {
+ netif_stop_queue (dev);
+ {
struct el3_private *lp = (struct el3_private *)dev->priv;
lp->stats.tx_bytes += skb->len;
- /* Put out the doubleword header... */
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0x00, ioaddr + TX_FIFO);
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-
- dev->trans_start = jiffies;
- if (inw(ioaddr + TX_FREE) > 1536) {
- dev->tbusy = 0;
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
}
+ /* Put out the doubleword header... */
+ outw(skb->len, ioaddr + TX_FIFO);
+ outw(0x00, ioaddr + TX_FIFO);
+ /* ... and the packet rounded to a doubleword. */
+ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+
+ dev->trans_start = jiffies;
+ if (inw(ioaddr + TX_FREE) > 1536) {
+ netif_start_queue (dev);
+ } else
+ /* Interrupt us when the FIFO has room for max-sized packet. */
+ outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
dev_kfree_skb(skb);
pop_tx_status(dev);
@@ -785,24 +779,17 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ioaddr_t ioaddr, status;
int i = 0;
- if ((lp == NULL) || !dev->start)
+ if (!netif_device_present(dev))
return;
ioaddr = dev->base_addr;
-#ifdef PCMCIA_DEBUG
- if (dev->interrupt) {
- printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
- dev->name);
- return;
- }
- dev->interrupt = 1;
DEBUG(3, "%s: interrupt, status %4.4x.\n",
dev->name, inw(ioaddr + EL3_STATUS));
-#endif
while ((status = inw(ioaddr + EL3_STATUS)) &
(IntLatch | RxComplete | StatsFull)) {
- if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) {
+ if (!netif_device_present(dev)) ||
+ ((status & 0xe000) != 0x2000)) {
DEBUG(1, "%s: interrupt from dead card\n", dev->name);
break;
}
@@ -814,8 +801,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
DEBUG(3, " TX room bit was handled.\n");
/* There's room in the FIFO for a full-sized packet. */
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
}
if (status & TxComplete)
@@ -863,11 +849,8 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
lp->last_irq = jiffies;
-#ifdef PCMCIA_DEBUG
DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
dev->name, inw(ioaddr + EL3_STATUS));
- dev->interrupt = 0;
-#endif
return;
}
@@ -879,7 +862,8 @@ static void media_check(u_long arg)
u_short media, errs;
u_long flags;
- if (dev->start == 0) goto reschedule;
+ if (!netif_device_present(dev))
+ goto reschedule;
EL3WINDOW(1);
/* Check for pending interrupt with expired latency timer: with
@@ -1093,6 +1077,8 @@ static int el3_close(struct net_device *dev)
ioaddr_t ioaddr = dev->base_addr;
DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
+
+ netif_stop_queue (dev);
if (DEV_OK(link)) {
/* Turn off statistics ASAP. We update lp->stats below. */
@@ -1122,7 +1108,6 @@ static int el3_close(struct net_device *dev)
}
link->open--;
- dev->start = 0;
del_timer(&lp->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 243b5c896..2a3011532 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -20,7 +20,6 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
if [ "$CONFIG_CARDBUS" = "y" ]; then
dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
dep_tristate ' DEC Tulip CardBus support' CONFIG_PCMCIA_TULIP m
- dep_tristate ' SMC EPIC CardBus support' CONFIG_PCMCIA_EPIC100 m
fi
bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile
index dfd4ef186..11c583dac 100644
--- a/drivers/net/pcmcia/Makefile
+++ b/drivers/net/pcmcia/Makefile
@@ -41,7 +41,6 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o
# Cardbus client drivers
obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o
obj-$(CONFIG_PCMCIA_TULIP) += tulip_cb.o
-obj-$(CONFIG_PCMCIA_EPIC100) += epic100_cb.o
O_OBJS := $(filter-out $(export-objs), $(obj-y))
OX_OBJS := $(filter $(export-objs), $(obj-y))
@@ -49,6 +48,3 @@ M_OBJS := $(filter-out $(export-objs), $(obj-m))
MX_OBJS := $(filter $(export-objs), $(obj-m))
include $(TOPDIR)/Rules.make
-
-epic100_cb.o: ../epic100.c
- $(CC) $(CFLAGS) -DMODULE -DCARDBUS -c -o $@ ../epic100.c
diff --git a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c
index 3dbb9923f..2acd2e46a 100644
--- a/drivers/net/pcmcia/aironet4500_cs.c
+++ b/drivers/net/pcmcia/aironet4500_cs.c
@@ -231,8 +231,7 @@ static dev_link_t *awc_attach(void)
dev->init = &awc_pcmcia_init;
dev->open = &awc_pcmcia_open;
dev->stop = &awc_pcmcia_close;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_start_queue (dev);
link->priv = dev;
#if CS_RELEASE_CODE > 0x2911
@@ -567,7 +566,7 @@ static int awc_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 1; dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = RUN_AT( HZ/20 );
add_timer(&link->release);
}
@@ -581,9 +580,9 @@ static int awc_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- dev->tbusy = 1; dev->start = 0;
- }
+ if (link->open)
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -595,7 +594,7 @@ static int awc_event(event_t event, int priority,
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
// awc_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_device_attach(dev);
}
}
break;
@@ -637,4 +636,4 @@ void cleanup_module(void)
// awc_detach(dev_list);
}
- \ No newline at end of file
+
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 9dd2c188e..a975a4df2 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -115,6 +115,7 @@ static void fjn_rx(struct net_device *dev);
static void fjn_reset(struct net_device *dev);
static struct net_device_stats *fjn_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
+static void fjn_tx_timeout (struct net_device *dev);
static dev_info_t dev_info = "fmvj18x_cs";
static dev_link_t *dev_list = NULL;
@@ -139,6 +140,7 @@ typedef struct local_info_t {
cardtype_t cardtype;
u_short sent;
u_char mc_filter[8];
+ spinlock_t lock;
} local_info_t;
#define MC_FILTERBREAK 64
@@ -235,6 +237,8 @@ typedef struct local_info_t {
#define INTR_OFF 0x0d /* LAN controler ignores interrupts */
#define INTR_ON 0x1d /* LAN controler will catch interrupts */
+#define TX_TIMEOUT 10
+
/*======================================================================
This bit of code is used to avoid unregistering network devices
@@ -278,6 +282,8 @@ static dev_link_t *fmvj18x_attach(void)
lp = kmalloc(sizeof(*lp), GFP_KERNEL);
if (!lp) return NULL;
memset(lp, 0, sizeof(*lp));
+
+ lp->lock = SPIN_LOCK_UNLOCKED;
link = &lp->link; dev = &lp->dev;
link->priv = dev->priv = link->irq.Instance = lp;
@@ -314,7 +320,9 @@ static dev_link_t *fmvj18x_attach(void)
dev->init = &fmvj18x_init;
dev->open = &fjn_open;
dev->stop = &fjn_close;
- dev->tbusy = 0xFF;
+ dev->tx_timeout = fjn_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ netif_start_queue (dev);
/* Register with Card Services */
link->next = dev_list;
@@ -462,7 +470,7 @@ static void fmvj18x_config(dev_link_t *link)
CS_CHECK(RequestConfiguration, link->handle, &link->conf);
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
if (register_netdev(dev) != 0) {
printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
goto failed;
@@ -585,8 +593,7 @@ static int fmvj18x_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 0xFF;
- dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = jiffies + HZ/20;
add_timer(&link->release);
}
@@ -600,10 +607,9 @@ static int fmvj18x_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- dev->tbusy = 0xFF;
- dev->start = 0;
- }
+ if (link->open)
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -614,9 +620,8 @@ static int fmvj18x_event(event_t event, int priority,
if (link->state & DEV_CONFIG) {
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
- dev->tbusy = 0;
- dev->start = 1;
fjn_reset(dev);
+ netif_device_attach(dev);
}
}
break;
@@ -670,12 +675,9 @@ static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
"unknown device.\n", irq);
return;
}
- if (dev->interrupt) {
- printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
- dev->name);
- return;
- }
- dev->interrupt = 1;
+
+ spin_lock (&lp->lock);
+
ioaddr = dev->base_addr;
/* avoid multiple interrupts */
@@ -708,71 +710,65 @@ static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue (dev);
} else {
lp->tx_started = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_stop_queue (dev);
}
}
DEBUG(4, "%s: exiting interrupt,\n", dev->name);
DEBUG(4, " tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
- dev->interrupt = 0;
outb(D_TX_INTR, ioaddr + TX_INTR);
outb(D_RX_INTR, ioaddr + RX_INTR);
- return;
+ spin_unlock (&lp->lock);
+
} /* fjn_interrupt */
/*====================================================================*/
-
-static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void fjn_tx_timeout (struct net_device *dev)
{
- struct local_info_t *lp = (struct local_info_t *)dev->priv;
- ioaddr_t ioaddr = dev->base_addr;
-
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10)
- return 1;
- printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
- dev->name, htons(inw(ioaddr + TX_STATUS)),
- inb(ioaddr + TX_STATUS) & F_TMT_RDY
- ? "IRQ conflict" : "network cable problem");
- printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
- "%04x %04x %04x %04x %04x.\n",
- dev->name, htons(inw(ioaddr + 0)),
- htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
- htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
- htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
- htons(inw(ioaddr +14)));
+ struct local_info_t *lp = (struct local_info_t *) dev->priv;
+ ioaddr_t ioaddr = dev->base_addr;
+ unsigned long flags;
+
+ printk (KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
+ dev->name, htons (inw (ioaddr + TX_STATUS)),
+ inb (ioaddr + TX_STATUS) & F_TMT_RDY
+ ? "IRQ conflict" : "network cable problem");
+ printk (KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
+ "%04x %04x %04x %04x %04x.\n",
+ dev->name, htons (inw (ioaddr + 0)),
+ htons (inw (ioaddr + 2)), htons (inw (ioaddr + 4)),
+ htons (inw (ioaddr + 6)), htons (inw (ioaddr + 8)),
+ htons (inw (ioaddr + 10)), htons (inw (ioaddr + 12)),
+ htons (inw (ioaddr + 14)));
lp->stats.tx_errors++;
+
/* ToDo: We should try to restart the adaptor... */
- cli();
+ spin_lock_irqsave (&lp->lock, flags);
- fjn_reset(dev);
+ fjn_reset (dev);
lp->tx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
lp->sent = 0;
lp->open_time = jiffies;
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
-
- sti();
- }
+ netif_start_queue (dev);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+}
+
+
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct local_info_t *lp = (struct local_info_t *)dev->priv;
+ ioaddr_t ioaddr = dev->base_addr;
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name);
- else {
+ netif_stop_queue (dev);
+ if (1) {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;
@@ -806,17 +802,17 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
lp->tx_started = 1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
} else {
if( sram_config == 0 ) {
if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
/* Yes, there is room for one more packet. */
- dev->tbusy = 0;
+ netif_start_queue (dev);
} else {
if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) &&
lp->tx_queue < 127 )
/* Yes, there is room for one more packet. */
- dev->tbusy = 0;
+ netif_start_queue (dev);
}
}
@@ -1025,9 +1021,7 @@ static int fjn_open(struct net_device *dev)
lp->tx_queue = 0;
lp->tx_queue_len = 0;
lp->open_time = jiffies;
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
+ netif_start_queue (dev);
MOD_INC_USE_COUNT;
@@ -1045,8 +1039,7 @@ static int fjn_close(struct net_device *dev)
DEBUG(4, "fjn_close('%s').\n", dev->name);
lp->open_time = 0;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
/* Set configuration register 0 to disable Tx and Rx. */
if( sram_config == 0 )
@@ -1064,7 +1057,6 @@ static int fjn_close(struct net_device *dev)
outb(INTR_OFF, ioaddr + LAN_CTRL);
link->open--;
- dev->start = 0;
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
diff --git a/drivers/net/pcmcia/netwave_cs.c b/drivers/net/pcmcia/netwave_cs.c
index 74928fd27..e95916c14 100644
--- a/drivers/net/pcmcia/netwave_cs.c
+++ b/drivers/net/pcmcia/netwave_cs.c
@@ -151,7 +151,7 @@ static const unsigned int txConfEUD = 0x10; /* Enable Uni-Data packets */
static const unsigned int txConfKey = 0x02; /* Scramble data packets */
static const unsigned int txConfLoop = 0x01; /* Loopback mode */
-/*static int netwave_debug = 0;*/
+static int netwave_debug = 0;
/*
All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
@@ -223,6 +223,7 @@ static void netwave_reset(struct net_device *dev);
static int netwave_open(struct net_device *dev); /* Open the device */
static int netwave_close(struct net_device *dev); /* Close the device */
static int netwave_config(struct net_device *dev, struct ifmap *map);
+static void netwave_tx_timeout (struct net_device *dev);
/* Packet transmission and Packet reception */
static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
@@ -308,6 +309,7 @@ typedef struct netwave_private {
u_char *ramBase;
int timeoutCounter;
int lastExec;
+ spinlock_t lock;
struct timer_list watchdog; /* To avoid blocking state */
struct site_survey nss;
struct enet_statistics stats;
@@ -454,6 +456,7 @@ static dev_link_t *netwave_attach(void)
priv = kmalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) return NULL;
memset(priv, 0, sizeof(*priv));
+ priv->lock = SPIN_LOCK_UNLOCKED;
link = &priv->link; dev = &priv->dev;
link->priv = dev->priv = priv;
link->release.function = &netwave_release;
@@ -503,7 +506,9 @@ static dev_link_t *netwave_attach(void)
dev->init = &netwave_init;
dev->open = &netwave_open;
dev->stop = &netwave_close;
- dev->tbusy = 1;
+ dev->tx_timeout = netwave_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ netif_start_queue (dev);
link->irq.Instance = dev;
/* Register with Card Services */
@@ -835,7 +840,7 @@ static void netwave_pcmcia_config(dev_link_t *link) {
struct net_device *dev = &priv->dev;
tuple_t tuple;
cisparse_t parse;
- int i, j, last_ret, last_fn;
+ int i=0, j, last_ret, last_fn;
u_char buf[64];
win_req_t req;
memreq_t mem;
@@ -910,7 +915,7 @@ static void netwave_pcmcia_config(dev_link_t *link) {
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
if (register_netdev(dev) != 0) {
printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n");
goto failed;
@@ -1014,7 +1019,7 @@ static int netwave_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 1; dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = jiffies + 5;
add_timer(&link->release);
}
@@ -1028,9 +1033,9 @@ static int netwave_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- dev->tbusy = 1; dev->start = 0;
- }
+ if (link->open)
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -1042,7 +1047,7 @@ static int netwave_event(event_t event, int priority,
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
netwave_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_device_attach(dev);
}
}
break;
@@ -1229,6 +1234,18 @@ static int netwave_hw_xmit(unsigned char* data, int len,
return 0;
}
+
+static void netwave_tx_timeout (struct net_device *dev)
+{
+ if (netwave_debug > 0)
+ printk (KERN_DEBUG "%s timed out.\n", dev->name);
+ netwave_reset (dev);
+ dev->trans_start = jiffies;
+ netif_start_queue (dev);
+}
+
+
+
static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
/* This flag indicate that the hardware can't perform a transmission.
* Theoritically, NET3 check it before sending a packet to the driver,
@@ -1236,29 +1253,6 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
* As the watchdog will abort too long transmissions, we are quite safe...
*/
- if (dev->tbusy) {
- /* Handled by watchdog */
- return 1;
-
- /* If we get here, some higher level has decided we are broken.
- There should really be a 'kick me' function call instead.
- */
- /*int tickssofar = jiffies - dev->trans_start;*/
- /* printk("xmit called with busy. tickssofar %d\n", tickssofar); */
- /*if (tickssofar < TX_TIMEOUT)
- return 1;
- */
- /* Should also detect if the kernel tries to xmit
- * on a stopped card.
- */
-
- /*if (netwave_debug > 0)
- printk(KERN_DEBUG "%s timed out.\n", dev->name);
- netwave_reset(dev);
- dev->trans_start = jiffies;
- dev->tbusy = 0;*/
- }
-
/* Sending a NULL skb means some higher layer thinks we've missed an
* tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
* itself.
@@ -1268,15 +1262,14 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
* better be done with atomic_swap(1, dev->tbusy, but set_bit()
* works as well
*/
- if ( test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
+ netif_stop_queue (dev);
+ if (1) {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char* buf = skb->data;
if (netwave_hw_xmit( buf, length, dev) == 1) {
/* Some error, let's make them call us another time? */
- dev->tbusy = 0;
+ netif_start_queue (dev);
}
dev->trans_start = jiffies;
}
@@ -1303,14 +1296,10 @@ static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
dev_link_t *link = &priv->link;
int i;
- if ((dev == NULL) | (!dev->start))
+ if ((dev == NULL) || !netif_device_present(dev))
return;
- if (dev->interrupt) {
- printk("%s: re-entering the interrupt handler.\n", dev->name);
- return;
- }
- dev->interrupt = 1;
+ spin_lock (&priv->lock);
iobase = dev->base_addr;
ramBase = priv->ramBase;
@@ -1409,8 +1398,7 @@ static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
/* If watchdog was activated, kill it ! */
del_timer(&priv->watchdog);
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
}
/* TxBA, this would trigger on all error packets received */
/* if (status & 0x01) {
@@ -1420,8 +1408,7 @@ static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
*/
}
/* done.. */
- dev->interrupt = 0;
- return;
+ spin_unlock (&priv->lock);
} /* netwave_interrupt */
/*
@@ -1444,7 +1431,7 @@ static void netwave_watchdog(u_long a) {
netwave_reset(dev);
/* We are not waiting anymore... */
- dev->tbusy = 0;
+ netif_start_queue (dev);
} /* netwave_watchdog */
@@ -1584,7 +1571,7 @@ static int netwave_open(struct net_device *dev) {
link->open++;
MOD_INC_USE_COUNT;
- dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
netwave_reset(dev);
return 0;
@@ -1596,11 +1583,12 @@ static int netwave_close(struct net_device *dev) {
DEBUG(1, "netwave_close: finishing.\n");
+ netif_stop_queue (dev);
+
/* If watchdog was activated, kill it ! */
del_timer(&priv->watchdog);
link->open--;
- dev->start = 0;
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + 5;
link->state |= DEV_RELEASE_PENDING;
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 2fb3772a5..22ff48201 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -307,6 +307,10 @@ four transmit and 12 receive frames at a time.
#undef MACE_IMR_DEFAULT
#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */
+#define TX_TIMEOUT (5*HZ)
+
+
+
/* ----------------------------------------------------------------------------
Type Definitions
---------------------------------------------------------------------------- */
@@ -360,6 +364,7 @@ typedef struct _mace_private {
dev_link_t link;
struct net_device dev;
dev_node_t node;
+ spinlock_t lock;
struct net_device_stats linux_stats; /* Linux statistics counters */
mace_statistics mace_stats; /* MACE chip statistics counters */
@@ -432,6 +437,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static struct net_device_stats *mace_get_stats(struct net_device *dev);
static int mace_rx(struct net_device *dev, unsigned char RxCnt);
static void restore_multicast_list(struct net_device *dev);
+static void mace_tx_timeout (struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -498,6 +504,8 @@ static dev_link_t *nmclan_attach(void)
lp = kmalloc(sizeof(*lp), GFP_KERNEL);
if (!lp) return NULL;
memset(lp, 0, sizeof(*lp));
+
+ lp->lock = SPIN_LOCK_UNLOCKED;
link = &lp->link; dev = &lp->dev;
link->priv = dev->priv = link->irq.Instance = lp;
@@ -531,7 +539,10 @@ static dev_link_t *nmclan_attach(void)
dev->init = &nmclan_init;
dev->open = &mace_open;
dev->stop = &mace_close;
- dev->tbusy = 0xFF;
+ dev->tx_timeout = mace_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ netif_start_queue (dev);
/* Register with Card Services */
link->next = dev_list;
@@ -752,7 +763,7 @@ static void nmclan_config(dev_link_t *link)
CS_CHECK(RequestConfiguration, handle, &link->conf);
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
i = register_netdev(dev);
if (i != 0) {
printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
@@ -859,7 +870,7 @@ static int nmclan_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 0xFF; dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = jiffies + HZ/20;
add_timer(&link->release);
}
@@ -873,9 +884,9 @@ static int nmclan_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- dev->tbusy = 0xFF; dev->start = 0;
- }
+ if (link->open)
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -886,9 +897,8 @@ static int nmclan_event(event_t event, int priority,
if (link->state & DEV_CONFIG) {
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
- dev->tbusy = 0;
- dev->start = 1;
nmclan_reset(dev);
+ netif_device_attach(dev);
}
}
break;
@@ -987,10 +997,7 @@ static int mace_open(struct net_device *dev)
MACEBANK(0);
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
-
+ netif_start_queue (dev);
nmclan_reset(dev);
return 0; /* Always succeed */
@@ -1007,12 +1014,13 @@ static int mace_close(struct net_device *dev)
dev_link_t *link = &lp->link;
DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
+
+ netif_stop_queue (dev);
/* Mask off all interrupts from the MACE chip. */
outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR);
link->open--;
- dev->start = 0;
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
@@ -1024,6 +1032,24 @@ static int mace_close(struct net_device *dev)
return 0;
} /* mace_close */
+
+static void mace_tx_timeout (struct net_device *dev)
+{
+ mace_private *lp = (mace_private *)dev->priv;
+ dev_link_t *link = &lp->link;
+
+ printk (KERN_NOTICE "%s: transmit timed out -- ", dev->name);
+#if RESET_ON_TIMEOUT
+ printk ("resetting card\n");
+ CardServices (ResetCard, link->handle);
+#else /* #if RESET_ON_TIMEOUT */
+ printk ("NOT resetting card\n");
+#endif /* #if RESET_ON_TIMEOUT */
+ dev->trans_start = jiffies;
+ netif_start_queue (dev);
+}
+
+
/* ----------------------------------------------------------------------------
mace_start_xmit
This routine begins the packet transmit function. When completed,
@@ -1038,39 +1064,11 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
mace_private *lp = (mace_private *)dev->priv;
ioaddr_t ioaddr = dev->base_addr;
- dev_link_t *link = &lp->link;
-
-#if TIMEOUT_TX
- /* Transmitter timeout. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
-
- if (tickssofar < (HZ/5))
- return 1;
- printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
-#if RESET_ON_TIMEOUT
- printk("resetting card\n");
- CardServices(ResetCard, link->handle);
-#else /* #if RESET_ON_TIMEOUT */
- printk("NOT resetting card\n");
-#endif /* #if RESET_ON_TIMEOUT */
- dev->trans_start = jiffies;
- return 1;
- }
-#else /* #if TIMEOUT_TX */
- if (dev->tbusy)
- return 1;
-#endif /* #if TIMEOUT_TX */
DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n",
dev->name, (long)skb->len);
- /* Avoid timer-based retransmission conflicts. */
- if (test_and_set_bit(TBUSY_UNSPECIFIED, (void*)&dev->tbusy) != 0) {
- printk(KERN_NOTICE "%s: transmitter access conflict.\n",
- dev->name);
- return 1;
- }
+ netif_stop_queue (dev);
#if (!TX_INTERRUPTABLE)
/* Disable MACE TX interrupts. */
@@ -1085,11 +1083,9 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
the upper layers. The interrupt handler is guaranteed never to
service a transmit interrupt while we are in here.
*/
- set_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy);
lp->linux_stats.tx_bytes += skb->len;
lp->tx_free_frames--;
- set_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
/* WARNING: Write the _exact_ number of bytes written in the header! */
/* Put out the word header [must be an outw()] . . . */
@@ -1105,11 +1101,10 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (lp->tx_free_frames > 0) {
#if MULTI_TX
- clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
+ netif_start_queue (dev);
#endif /* #if MULTI_TX */
}
- clear_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy);
}
#if (!TX_INTERRUPTABLE)
@@ -1140,8 +1135,10 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irq);
return;
}
+
+ spin_lock (&lp->lock);
- if (dev->interrupt || lp->tx_irq_disabled) {
+ if (lp->tx_irq_disabled) {
printk(
(lp->tx_irq_disabled?
KERN_NOTICE "%s: Interrupt with tx_irq_disabled "
@@ -1155,9 +1152,8 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* WARNING: MACE_IR has been read! */
return;
}
- dev->interrupt = 1;
- if (dev->start == 0) {
+ if (!netif_device_present(dev)) {
DEBUG(2, "%s: interrupt from dead card\n", dev->name);
goto exception;
}
@@ -1230,8 +1226,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->linux_stats.tx_packets++;
lp->tx_free_frames++;
- clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
} /* if (status & MACE_IR_XMTINT) */
if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) {
@@ -1266,8 +1261,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
exception:
- dev->interrupt = 0;
- return;
+ spin_unlock (&lp->lock);
} /* mace_interrupt */
/* ----------------------------------------------------------------------------
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 0af9aa04d..185644307 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -11,7 +11,7 @@
Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
- pcnet_cs.c 1.110 1999/12/06 21:39:18
+ pcnet_cs.c 1.112 2000/02/11 01:24:44
The network driver code is based on Donald Becker's NE2000 code:
@@ -72,7 +72,7 @@ static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
-"pcnet_cs.c 1.110 1999/12/06 21:39:18 (David Hinds)";
+"pcnet_cs.c 1.112 2000/02/11 01:24:44 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -211,7 +211,8 @@ static hw_info_t hw_info[] = {
DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
{ /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
{ /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
- { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 }
+ { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
+ { /* PCMCIA Technology OEM */ 0x01c8, 0xa0, 0x0c, 0 }
};
#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
@@ -306,7 +307,6 @@ static dev_link_t *pcnet_attach(void)
for (i = 0; i < 4; i++)
link->irq.IRQInfo2 |= 1 << irq_list[i];
link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Vcc = 50;
link->conf.IntType = INT_MEMORY_AND_IO;
ethdev_init(dev);
@@ -596,6 +596,7 @@ static void pcnet_config(dev_link_t *link)
int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
int manfid = 0, prodid = 0, has_shmem = 0;
u_short buf[64];
+ config_info_t conf;
hw_info_t *hw_info;
DEBUG(0, "pcnet_config(0x%p)\n", link);
@@ -614,6 +615,10 @@ static void pcnet_config(dev_link_t *link)
/* Configure card */
link->state |= DEV_CONFIG;
+ /* Look up current Vcc */
+ CS_CHECK(GetConfigurationInfo, handle, &conf);
+ link->conf.Vcc = conf.Vcc;
+
tuple.DesiredTuple = CISTPL_MANFID;
tuple.Attributes = TUPLE_RETURN_COMMON;
if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
@@ -807,8 +812,7 @@ static int pcnet_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- netif_stop_queue(&info->dev);
- clear_bit(LINK_STATE_START, &info->dev.state);
+ netif_device_detach(&info->dev);
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
add_timer(&link->release);
@@ -823,10 +827,9 @@ static int pcnet_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- netif_stop_queue(&info->dev);
- clear_bit(LINK_STATE_START, &info->dev.state);
- }
+ if (link->open)
+ netif_device_detach(&info->dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -839,8 +842,7 @@ static int pcnet_event(event_t event, int priority,
if (link->open) {
pcnet_reset_8390(&info->dev);
NS8390_init(&info->dev, 1);
- netif_start_queue(&info->dev);
- set_bit(LINK_STATE_START, &info->dev.state);
+ netif_device_attach(&info->dev);
}
}
break;
@@ -908,7 +910,6 @@ static int pcnet_close(struct net_device *dev)
free_irq(dev->irq, dev);
link->open--;
- clear_bit(LINK_STATE_START, &dev->state);
del_timer(&info->watchdog);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
@@ -984,7 +985,7 @@ static void ei_watchdog(u_long arg)
struct net_device *dev = &info->dev;
ioaddr_t nic_base = dev->base_addr;
- if (!test_bit(LINK_STATE_START, &dev->state))
+ if (!netif_device_present(dev))
goto reschedule;
/* Check for pending interrupt with expired latency timer: with
diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c
index ea3ffa2cb..7c763cf8e 100644
--- a/drivers/net/pcmcia/ray_cs.c
+++ b/drivers/net/pcmcia/ray_cs.c
@@ -926,8 +926,7 @@ static int ray_event(event_t event, int priority,
switch (event) {
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
- netif_stop_queue(dev);
- clear_bit(LINK_STATE_START, &dev->state);
+ netif_device_detach(dev);
if (link->state & DEV_CONFIG) {
link->release.expires = jiffies + HZ/20;
add_timer(&link->release);
@@ -943,10 +942,9 @@ static int ray_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- netif_stop_queue(dev);
- clear_bit(LINK_STATE_START, &dev->state);
- }
+ if (link->open)
+ netif_device_detach(dev);
+
pcmcia_release_configuration(link->handle);
}
break;
@@ -958,8 +956,7 @@ static int ray_event(event_t event, int priority,
pcmcia_request_configuration(link->handle, &link->conf);
if (link->open) {
ray_reset(dev);
- netif_start_queue(dev);
- set_bit(LINK_STATE_START, &dev->state);
+ netif_device_attach(dev);
}
}
break;
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 4a58706f6..b201d1ec1 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -125,6 +125,8 @@ struct smc_private {
u_short media_status;
u_short fast_poll;
u_long last_rx;
+
+ spinlock_t lock;
};
/* Special definitions for Megahertz multifunction cards */
@@ -281,6 +283,7 @@ static void smc91c92_release(u_long arg);
static int smc91c92_event(event_t event, int priority,
event_callback_args_t *args);
+static void smc91c92_tx_timeout (struct net_device *dev);
static int smc91c92_open(struct net_device *dev);
static int smc91c92_close(struct net_device *dev);
static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -379,9 +382,12 @@ static dev_link_t *smc91c92_attach(void)
dev->init = &smc91c92_init;
dev->open = &smc91c92_open;
dev->stop = &smc91c92_close;
- dev->tbusy = 1;
+ dev->tx_timeout = smc91c92_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
dev->priv = link->priv = link->irq.Instance = smc;
+ netif_start_queue (dev);
+
/* Register with Card Services */
link->next = dev_list;
dev_list = link;
@@ -663,7 +669,7 @@ static int mot_setup(dev_link_t *link) {
struct smc_private *smc = link->priv;
struct net_device *dev = &smc->dev;
ioaddr_t ioaddr = dev->base_addr;
- int i, wait, loop;
+ int i, wait=0, loop;
unsigned int addr;
/* Read Ethernet address from Serial EEPROM */
@@ -775,7 +781,7 @@ static int osi_config(dev_link_t *link)
struct smc_private *smc = link->priv;
struct net_device *dev = &smc->dev;
static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
- int i, j;
+ int i=0, j;
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
@@ -977,7 +983,7 @@ static void smc91c92_config(dev_link_t *link)
dev->if_port = if_port;
else
printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
- dev->tbusy = 0;
+ netif_start_queue (dev);
if (register_netdev(dev) != 0) {
printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
@@ -1106,8 +1112,7 @@ static int smc91c92_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 1;
- dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
add_timer(&link->release);
@@ -1122,9 +1127,9 @@ static int smc91c92_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
- if (link->open) {
- dev->tbusy = 1; dev->start = 0;
- }
+ if (link->open)
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -1147,7 +1152,7 @@ static int smc91c92_event(event_t event, int priority,
}
if (link->open) {
smc_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_device_attach(dev);
}
}
break;
@@ -1201,7 +1206,7 @@ static int smc91c92_open(struct net_device *dev)
link->open++;
MOD_INC_USE_COUNT;
- dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
smc->saved_skb = 0;
smc->packets_waiting = 0;
@@ -1225,8 +1230,7 @@ static int smc91c92_close(struct net_device *dev)
DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
dev->name, inw(ioaddr + BANK_SELECT));
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
/* Shut off all interrupts, and turn off the Tx and Rx sections.
Don't bother to check for chip present. */
@@ -1240,7 +1244,7 @@ static int smc91c92_close(struct net_device *dev)
SMC_SELECT_BANK( 1 );
outw(CTL_POWERDOWN, ioaddr + CONTROL );
- link->open--; dev->start = 0;
+ link->open--;
del_timer(&smc->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
@@ -1281,7 +1285,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
" failed, status %#2.2x.\n", dev->name, packet_no);
dev_kfree_skb (skb);
smc->saved_skb = NULL;
- dev->tbusy = 0;
+ netif_start_queue (dev);
return;
}
@@ -1329,12 +1333,30 @@ static void smc_hardware_send_packet( struct net_device * dev )
smc->saved_skb = NULL;
dev_kfree_skb (skb);
dev->trans_start = jiffies;
- dev->tbusy = 0;
+ netif_start_queue (dev);
return;
}
/*====================================================================*/
+static void smc91c92_tx_timeout (struct net_device *dev)
+{
+ struct smc_private *smc = dev->priv;
+ ioaddr_t ioaddr = dev->base_addr;
+
+ printk (KERN_NOTICE "%s: SMC91c92 transmit timed out, "
+ "Tx_status %2.2x status %4.4x.\n",
+ dev->name, inw (ioaddr) & 0xff, inw (ioaddr + 2));
+ smc->stats.tx_errors++;
+ smc_reset (dev);
+ dev->trans_start = jiffies;
+ smc->saved_skb = NULL;
+ netif_start_queue (dev);
+}
+
+
+/*====================================================================*/
+
static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smc_private *smc = dev->priv;
@@ -1342,29 +1364,10 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned short num_pages;
short time_out, ir;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < TX_TIMEOUT)
- return 1;
- printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
- "Tx_status %2.2x status %4.4x.\n",
- dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
- smc->stats.tx_errors++;
- smc_reset(dev);
- dev->trans_start = jiffies;
- dev->tbusy = 0;
- smc->saved_skb = NULL;
- }
-
DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
" status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
-
- /* Avoid timer-based retransmission conflicts. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_ERR "%s: transmitter access conflict.\n", dev->name);
- return 1;
- }
+
+ netif_stop_queue (dev);
if ( smc->saved_skb) {
/* THIS SHOULD NEVER HAPPEN. */
@@ -1500,21 +1503,14 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
u_short saved_bank, saved_pointer, mask, status;
char bogus_cnt = INTR_WORK; /* Work we are willing to do. */
- if ((smc == NULL) || !dev->start)
+ if ((smc == NULL) || !netif_device_present(dev))
return;
ioaddr = dev->base_addr;
-#ifdef PCMCIA_DEBUG
- if (dev->interrupt) {
- printk(KERN_ERR "%s: re-entering the interrupt handler.\n",
- dev->name);
- return;
- }
- dev->interrupt = 1;
+ spin_lock (&smc->lock);
DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
irq, ioaddr);
-#endif
smc->watchdog = 0;
saved_bank = inw(ioaddr + BANK_SELECT);
@@ -1525,7 +1521,6 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (dev->start)
DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
"/ejected device.\n", dev->name, irq);
- dev->interrupt = 0;
#endif
goto irq_done;
}
@@ -1569,7 +1564,7 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
/* and let the card send more packets to me */
- mark_bh( NET_BH );
+ netif_wake_queue (dev);
}
if (status & IM_RX_OVRN_INT) {
smc->stats.rx_errors++;
@@ -1588,10 +1583,9 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
outw(saved_pointer, ioaddr + POINTER);
SMC_SELECT_BANK( saved_bank );
-#ifdef PCMCIA_DEBUG
- dev->interrupt = 0;
+ spin_unlock (&smc->lock);
+
DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
-#endif
irq_done:
@@ -1913,8 +1907,9 @@ static void media_check(u_long arg)
ioaddr_t ioaddr = dev->base_addr;
u_short i, media, saved_bank;
- if (dev->start == 0) goto reschedule;
-
+ if (!netif_device_present(dev))
+ goto reschedule;
+
saved_bank = inw(ioaddr + BANK_SELECT);
SMC_SELECT_BANK(2);
i = inw(ioaddr + INTERRUPT);
diff --git a/drivers/net/pcmcia/tulip_cb.c b/drivers/net/pcmcia/tulip_cb.c
index ee49f58eb..38dcdc0c1 100644
--- a/drivers/net/pcmcia/tulip_cb.c
+++ b/drivers/net/pcmcia/tulip_cb.c
@@ -96,16 +96,7 @@ static int csr0 = 0x00A00000 | 0x4800;
#endif
#include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -128,7 +119,6 @@ static int csr0 = 0x00A00000 | 0x4800;
/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
This is only in the support-all-kernels source code. */
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
MODULE_PARM(debug, "i");
@@ -138,14 +128,9 @@ MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(csr0, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-#endif
#define RUN_AT(x) (jiffies + (x))
-#define NETSTATS_VER2
-#define PCI_SUPPORT_VER3
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-
#define tulip_debug debug
#ifdef TULIP_DEBUG
static int tulip_debug = TULIP_DEBUG;
@@ -438,7 +423,8 @@ struct tulip_private {
struct mediatable *mtable;
int cur_index; /* Current media index. */
int saved_if_port;
- unsigned char pci_bus, pci_devfn;
+ struct pci_dev *pdev;
+ spinlock_t lock;
int pad0, pad1; /* Used for 8-byte alignment */
};
@@ -515,9 +501,9 @@ static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx)
restore_flags(flags);
}
-static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
- struct net_device *dev, long ioaddr, int irq,
- int chip_idx, int board_idx)
+static struct net_device *tulip_probe1(struct pci_dev *pdev,
+ struct net_device *dev, long ioaddr, int irq,
+ int chip_idx, int board_idx)
{
static int did_version = 0; /* Already printed version info. */
struct tulip_private *tp;
@@ -534,11 +520,11 @@ static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
dev = init_etherdev(dev, 0);
- pcibios_read_config_byte(pci_bus, pci_devfn, PCI_REVISION_ID, &chip_rev);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
/* Bring the 21143 out of sleep mode.
Caution: Snooze mode does not work with some boards! */
if (tulip_tbl[chip_idx].flags & HAS_ACPI)
- pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000);
+ pci_write_config_dword(pdev, 0x40, 0x00000000);
printk(KERN_INFO "%s: %s rev %d at %#3lx,",
dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
@@ -691,8 +677,8 @@ static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
memset(tp, 0, sizeof(*tp));
dev->priv = tp;
- tp->pci_bus = pci_bus;
- tp->pci_devfn = pci_devfn;
+ tp->lock = SPIN_LOCK_UNLOCKED;
+ tp->pdev = pdev;
tp->chip_id = chip_idx;
tp->revision = chip_rev;
tp->csr0 = csr0;
@@ -807,6 +793,8 @@ static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_rx_mode;
#endif
+ dev->tx_timeout = tulip_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
/* Reset the xcvr interface and turn on heartbeat. */
switch (chip_idx) {
@@ -1302,7 +1290,7 @@ tulip_up(struct net_device *dev)
udelay(2);
if (tulip_tbl[tp->chip_id].flags & HAS_ACPI)
- pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x00000000);
+ pci_write_config_dword(tp->pdev, 0x40, 0x00000000);
/* Clear the tx ring */
for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1461,15 +1449,13 @@ media_picked:
outl_CSR6(tp->csr6, ioaddr, tp->chip_id);
outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id);
- dev->tbusy = 0;
- tp->interrupt = 0;
- dev->start = 1;
-
/* Enable interrupts by setting the interrupt mask. */
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
outl(0, ioaddr + CSR2); /* Rx poll demand */
+
+ netif_start_queue (dev);
if (tulip_debug > 2) {
printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
@@ -2354,8 +2340,8 @@ static void tulip_tx_timeout(struct net_device *dev)
outl(0, ioaddr + CSR1);
dev->trans_start = jiffies;
+ netif_wake_queue (dev);
tp->stats.tx_errors++;
- return;
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -2413,15 +2399,6 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
int entry;
u32 flag;
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- if (jiffies - dev->trans_start < TX_TIMEOUT)
- return 1;
- tulip_tx_timeout(dev);
- return 1;
- }
-
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
@@ -2454,8 +2431,10 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
tp->tx_ring[entry].length = skb->len | flag;
tp->tx_ring[entry].status = DescOwned; /* Pass ownership to the chip. */
tp->cur_tx++;
- if ( ! tp->tx_full)
- clear_bit(0, (void*)&dev->tbusy);
+ if (tp->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
/* Trigger an immediate transmit demand. */
outl(0, dev->base_addr + CSR1);
@@ -2474,21 +2453,7 @@ static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
long ioaddr = dev->base_addr;
int csr5, work_budget = max_interrupt_work;
-#if defined(__i386__) && defined(SMP_CHECK)
- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
- printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by "
- "processor %d.\n",
- dev->name, smp_processor_id());
- dev->interrupt = 0;
- return;
- }
-#else
- if (dev->interrupt) {
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
- return;
- }
- dev->interrupt = 1;
-#endif
+ spin_lock (&tp->lock);
do {
csr5 = inl(ioaddr + CSR5);
@@ -2549,7 +2514,7 @@ static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
/* Free the original skb. */
- dev_free_skb(tp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(tp->tx_skbuff[entry]);
tp->tx_skbuff[entry] = 0;
}
@@ -2561,13 +2526,15 @@ static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
#endif
- if (tp->tx_full && dev->tbusy
- && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
- /* The ring is no longer full, clear tbusy. */
+ if (tp->tx_full &&
+ tp->cur_tx - dirty_tx < TX_RING_SIZE - 2)
+ /* The ring is no longer full */
tp->tx_full = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
+
+ if (tp->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
tp->dirty_tx = dirty_tx;
if (csr5 & TxDied) {
@@ -2630,12 +2597,7 @@ static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
dev->name, inl(ioaddr + CSR5));
-#if defined(__i386__)
- clear_bit(0, (void*)&dev->interrupt);
-#else
- dev->interrupt = 0;
-#endif
- return;
+ spin_unlock (&tp->lock);
}
static int
@@ -2751,9 +2713,6 @@ tulip_down(struct net_device *dev)
long ioaddr = dev->base_addr;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- dev->start = 0;
- dev->tbusy = 1;
-
/* Disable interrupts by clearing the interrupt mask. */
outl(0x00000000, ioaddr + CSR7);
/* Stop the chip's Tx and Rx processes. */
@@ -2765,8 +2724,6 @@ tulip_down(struct net_device *dev)
if (inl(ioaddr + CSR6) != 0xffffffff)
tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
- del_timer(&tp->timer);
-
dev->if_port = tp->saved_if_port;
}
@@ -2781,9 +2738,13 @@ tulip_close(struct net_device *dev)
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, inl(ioaddr + CSR5));
- if (dev->start)
+ netif_stop_queue(dev);
+
+ if (netif_device_present(dev))
tulip_down(dev);
+ del_timer(&tp->timer);
+
free_irq(dev->irq, dev);
/* Free all the skbuffs in the Rx queue. */
@@ -2794,12 +2755,12 @@ tulip_close(struct net_device *dev)
tp->rx_ring[i].length = 0;
tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
if (skb) {
- dev_free_skb(skb);
+ dev_kfree_skb(skb);
}
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (tp->tx_skbuff[i])
- dev_free_skb(tp->tx_skbuff[i]);
+ dev_kfree_skb(tp->tx_skbuff[i]);
tp->tx_skbuff[i] = 0;
}
@@ -2813,7 +2774,7 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev)
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (dev->start)
+ if (netif_device_present(dev))
tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
return &tp->stats;
@@ -3075,8 +3036,8 @@ static void set_rx_mode(struct net_device *dev)
tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
tp->tx_ring[entry].status = DescOwned;
if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
- set_bit(0, (void*)&dev->tbusy);
tp->tx_full = 1;
+ netif_stop_queue (dev);
}
if (dummy >= 0)
tp->tx_ring[dummy].status = DescOwned;
@@ -3114,10 +3075,11 @@ static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_devi
printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
- pci_set_master(pdev);
- dev = tulip_probe1(pdev->bus->number, pdev->devfn, NULL,
- pdev->resource[0].start, pdev->irq,
- id->driver_data, board_idx++);
+ pci_enable_device (pdev);
+ pci_set_master (pdev);
+ dev = tulip_probe1(pdev, NULL,
+ pci_resource_start (pdev, 0), pdev->irq,
+ id->driver_data, board_idx++);
if (dev) {
pdev->driver_data = dev;
return 0;
diff --git a/drivers/net/pcmcia/wavelan_cs.c b/drivers/net/pcmcia/wavelan_cs.c
index c1c38aa28..ae9bb0548 100644
--- a/drivers/net/pcmcia/wavelan_cs.c
+++ b/drivers/net/pcmcia/wavelan_cs.c
@@ -66,31 +66,6 @@
/*------------------------------------------------------------------*/
/*
- * Wrapper for disabling interrupts.
- */
-static inline unsigned long
-wv_splhi(void)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- return(flags);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wrapper for re-enabling interrupts.
- */
-static inline void
-wv_splx(unsigned long flags)
-{
- restore_flags(flags);
-}
-
-/*------------------------------------------------------------------*/
-/*
* Wrapper for reporting error to cardservices
*/
static void cs_error(client_handle_t handle, int func, int ret)
@@ -581,20 +556,20 @@ void wv_roam_cleanup(struct net_device *dev)
void wv_nwid_filter(unsigned char mode, net_local *lp)
{
mm_t m;
- unsigned long x;
+ unsigned long flags;
#ifdef WAVELAN_ROAMING_DEBUG
printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name);
#endif
/* Disable interrupts & save flags */
- x = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
/* ReEnable interrupts & restore flags */
- wv_splx(x);
+ spin_unlock_irqrestore (&lp->lock, flags);
if(mode==NWID_PROMISC)
lp->cell_search=1;
@@ -755,7 +730,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
{
ioaddr_t base = lp->dev->base_addr;
mm_t m;
- unsigned long x;
+ unsigned long flags;
if(wavepoint==lp->curr_point) /* Sanity check... */
{
@@ -768,7 +743,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
#endif
/* Disable interrupts & save flags */
- x = wv_splhi();
+ spin_lock_irqsave(&lp->lock, flags);
m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
@@ -776,7 +751,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
/* ReEnable interrupts & restore flags */
- wv_splx(x);
+ spin_unlock_irqrestore (&lp->lock, flags);
wv_nwid_filter(!NWID_PROMISC,lp);
lp->curr_point=wavepoint;
@@ -863,15 +838,15 @@ wv_82593_cmd(device * dev,
net_local * lp = (net_local *)dev->priv;
int status;
long spin;
- u_long opri;
+ u_long flags;
/* Spin until the chip finishes executing its current command (if any) */
do
{
- opri = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- wv_splx(opri);
+ spin_unlock_irqrestore (&lp->lock, flags);
}
while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
@@ -1009,27 +984,25 @@ read_ringbuf(device * dev,
* wavelan_interrupt is not an option...), so you may experience
* some delay sometime...
*/
-static inline void
-wv_82593_reconfig(device * dev)
+static inline void wv_82593_reconfig (device * dev)
{
- net_local * lp = (net_local *)dev->priv;
- dev_link_t * link = ((net_local *) dev->priv)->link;
+ net_local *lp = (net_local *) dev->priv;
+ dev_link_t *link = ((net_local *) dev->priv)->link;
- /* Check if we can do it now ! */
- if(!(link->open) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
- {
- lp->reconfig_82593 = TRUE;
+ /* Check if we can do it now ! */
+ if (!(link->open)) {
+ lp->reconfig_82593 = TRUE;
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "%s: wv_82593_reconfig(): delayed (busy = %ld, link = %d)\n",
- dev->name, dev->tbusy, link->open);
+ printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
+ dev->name, link->open);
#endif
- }
- else
- {
- lp->reconfig_82593 = FALSE;
- wv_82593_config(dev);
- dev->tbusy = 0;
- }
+ } else {
+ netif_stop_queue (dev);
+
+ lp->reconfig_82593 = FALSE;
+ wv_82593_config (dev);
+ netif_wake_queue (dev);
+ }
}
#ifdef OLDIES
@@ -1286,9 +1259,6 @@ static void
wv_dev_show(device * dev)
{
printk(KERN_DEBUG "dev:");
- printk(" start=%d,", dev->start);
- printk(" tbusy=%ld,", dev->tbusy);
- printk(" interrupt=%d,", dev->interrupt);
printk(" trans_start=%ld,", dev->trans_start);
printk(" flags=0x%x,", dev->flags);
printk("\n");
@@ -1908,7 +1878,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
struct iwreq * wrq = (struct iwreq *) rq;
psa_t psa;
mm_t m;
- unsigned long x;
+ unsigned long flags;
int ret = 0;
#ifdef DEBUG_IOCTL_TRACE
@@ -1916,7 +1886,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
#endif
/* Disable interrupts & save flags */
- x = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
/* Look what is the request */
switch(cmd)
@@ -2528,7 +2498,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
}
/* ReEnable interrupts & restore flags */
- wv_splx(x);
+ spin_unlock_irqrestore (&lp->lock, flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2548,14 +2518,14 @@ wavelan_get_wireless_stats(device * dev)
net_local * lp = (net_local *) dev->priv;
mmr_t m;
iw_stats * wstats;
- unsigned long x;
+ unsigned long flags;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
#endif
/* Disable interrupts & save flags */
- x = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
if(lp == (net_local *) NULL)
return (iw_stats *) NULL;
@@ -2583,7 +2553,7 @@ wavelan_get_wireless_stats(device * dev)
wstats->discard.misc = 0L;
/* ReEnable interrupts & restore flags */
- wv_splx(x);
+ spin_unlock_irqrestore (&lp->lock, flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2917,7 +2887,7 @@ wv_packet_write(device * dev,
{
net_local * lp = (net_local *) dev->priv;
ioaddr_t base = dev->base_addr;
- unsigned long x;
+ unsigned long flags;
int clen = length;
register u_short xmtdata_base = TX_BASE;
@@ -2925,7 +2895,7 @@ wv_packet_write(device * dev,
printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
#endif
- x = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
/* Check if we need some padding */
if(clen < ETH_ZLEN)
@@ -2963,7 +2933,7 @@ wv_packet_write(device * dev,
add_timer(&lp->watchdog);
}
- wv_splx(x);
+ spin_unlock_irqrestore (&lp->lock, flags);
#ifdef DEBUG_TX_INFO
wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2972,6 +2942,8 @@ wv_packet_write(device * dev,
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
#endif
+
+ netif_start_queue (dev);
}
/*------------------------------------------------------------------*/
@@ -2981,60 +2953,45 @@ wv_packet_write(device * dev,
* the packet. We also prevent reentrance. Then, we call the function
* to send the packet...
*/
-static int
-wavelan_packet_xmit(struct sk_buff * skb,
- device * dev)
+static int wavelan_packet_xmit (struct sk_buff *skb,
+ device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local *lp = (net_local *) dev->priv;
#ifdef DEBUG_TX_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
- (unsigned) skb);
+ printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+ (unsigned) skb);
#endif
- /* This flag indicate that the hardware can't perform a transmission.
- * Theoritically, NET3 check it before sending a packet to the driver,
- * but in fact it never do that and pool continuously.
- * As the watchdog will abort too long transmissions, we are quite safe...
- */
- if(dev->tbusy)
- return(1);
-
- /*
- * For ethernet, fill in the header.
- */
+ /*
+ * For ethernet, fill in the header.
+ */
- /*
- * Block a timer-based transmit from overlapping a previous transmit.
- * In other words, prevent reentering this routine.
- */
- if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
-#ifdef DEBUG_TX_ERROR
- printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
-#endif
- else
- {
- /* If somebody has asked to reconfigure the controler, we can do it now */
- if(lp->reconfig_82593)
- {
- lp->reconfig_82593 = FALSE;
- wv_82593_config(dev);
- }
+ netif_stop_queue (dev);
+ /*
+ * Block a timer-based transmit from overlapping a previous transmit.
+ * In other words, prevent reentering this routine.
+ */
+ if (1) {
+ /* If somebody has asked to reconfigure the controler, we can do it now */
+ if (lp->reconfig_82593) {
+ lp->reconfig_82593 = FALSE;
+ wv_82593_config (dev);
+ }
#ifdef DEBUG_TX_ERROR
- if(skb->next)
- printk(KERN_INFO "skb has next\n");
+ if (skb->next)
+ printk (KERN_INFO "skb has next\n");
#endif
-
- wv_packet_write(dev, skb->data, skb->len);
- }
- dev_kfree_skb(skb);
+ wv_packet_write (dev, skb->data, skb->len);
+ }
+ dev_kfree_skb (skb);
#ifdef DEBUG_TX_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+ printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return(0);
+ return (0);
}
/********************** HARDWARE CONFIGURATION **********************/
@@ -3245,7 +3202,8 @@ static int
wv_ru_stop(device * dev)
{
ioaddr_t base = dev->base_addr;
- unsigned long opri;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long flags;
int status;
int spin;
@@ -3262,10 +3220,10 @@ wv_ru_stop(device * dev)
do
{
udelay(10);
- opri = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- wv_splx(opri);
+ spin_unlock_irqrestore (&lp->lock, flags);
}
while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
@@ -3273,10 +3231,10 @@ wv_ru_stop(device * dev)
do
{
udelay(10);
- opri = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- wv_splx(opri);
+ spin_unlock_irqrestore (&lp->lock, flags);
}
while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
@@ -3347,16 +3305,16 @@ wv_ru_start(device * dev)
#ifdef DEBUG_I82593_SHOW
{
int status;
- int opri;
+ unsigned long flags;
int i = 0;
/* spin until the chip starts receiving */
do
{
- opri = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
status = inb(LCSR(base));
- wv_splx(opri);
+ spin_unlock_irqrestore (&lp->lock, flags);
if(i++ > 10000)
break;
}
@@ -3838,7 +3796,7 @@ wv_pcmcia_config(dev_link_t * link)
/* Feed device with this info... */
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
#ifdef DEBUG_CONFIG_INFO
printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3991,13 +3949,7 @@ wavelan_interrupt(int irq,
lp = (net_local *) dev->priv;
base = dev->base_addr;
- /* Prevent reentrance. What should we do here ? */
-#ifdef DEBUG_INTERRUPT_ERROR
- if(dev->interrupt)
- printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
- dev->name);
-#endif
- dev->interrupt = 1;
+ spin_lock (&lp->lock);
/* Treat all pending interrupts */
while(1)
@@ -4201,8 +4153,7 @@ wavelan_interrupt(int irq,
lp->stats.collisions += (tx_status & TX_NCOL_MASK);
lp->stats.tx_packets++;
- dev->tbusy = FALSE;
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */
}
else /* if interrupt = transmit done or retransmit done */
@@ -4214,7 +4165,8 @@ wavelan_interrupt(int irq,
outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */
}
}
- dev->interrupt = FALSE;
+
+ spin_unlock_irq (&lp->lock);
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4296,7 +4248,7 @@ wavelan_watchdog(u_long a)
#endif
/* We are no more waiting for something... */
- dev->tbusy = 0;
+ netif_start_queue (dev);
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4349,9 +4301,7 @@ wavelan_open(device * dev)
return FALSE;
if(!wv_ru_start(dev))
wv_hw_reset(dev); /* If problem : reset */
- dev->interrupt = 0;
- dev->start = 1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
/* Mark the device as used */
link->open++;
@@ -4385,6 +4335,8 @@ wavelan_close(device * dev)
(unsigned int) dev);
#endif
+ netif_stop_queue (dev);
+
/* If the device isn't open, then nothing to do */
if(!link->open)
{
@@ -4408,10 +4360,9 @@ wavelan_close(device * dev)
MOD_DEC_USE_COUNT;
/* If the card is still present */
- if(dev->start)
+ if (netif_device_present(dev))
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
/* Stop receiving new messages and wait end of transmission */
wv_ru_stop(dev);
@@ -4549,7 +4500,7 @@ wavelan_attach(void)
/* Other specific data */
/* Provide storage area for device name */
dev->name = ((net_local *)dev->priv)->node.dev_name;
- dev->tbusy = 1;
+ netif_start_queue (dev);
dev->mtu = WAVELAN_MTU;
/* Register with Card Services */
@@ -4711,7 +4662,7 @@ wavelan_event(event_t event, /* The event received */
if(link->state & DEV_CONFIG)
{
/* Accept no more transmissions */
- dev->tbusy = 1; dev->start = 0;
+ netif_device_detach(dev);
/* Release the card */
wv_pcmcia_release((u_long) link);
@@ -4748,10 +4699,8 @@ wavelan_event(event_t event, /* The event received */
if(link->state & DEV_CONFIG)
{
if(link->open)
- {
- dev->tbusy = 1;
- dev->start = 0;
- }
+ netif_device_detach(dev);
+
CardServices(ReleaseConfiguration, link->handle);
}
break;
@@ -4766,8 +4715,7 @@ wavelan_event(event_t event, /* The event received */
if(link->open) /* If RESET -> True, If RESUME -> False ??? */
{
wv_hw_reset(dev);
- dev->tbusy = 0;
- dev->start = 1;
+ netif_device_attach(dev);
}
}
break;
diff --git a/drivers/net/pcmcia/wavelan_cs.h b/drivers/net/pcmcia/wavelan_cs.h
index 0f5be4f37..f35a81ac9 100644
--- a/drivers/net/pcmcia/wavelan_cs.h
+++ b/drivers/net/pcmcia/wavelan_cs.h
@@ -550,6 +550,7 @@ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */
*/
struct net_local
{
+ spinlock_t lock;
dev_node_t node; /* ???? What is this stuff ???? */
device * dev; /* Reverse link... */
dev_link_t * link; /* pcmcia structure */
@@ -609,10 +610,6 @@ void wv_roam_cleanup(struct net_device *dev);
#endif /* WAVELAN_ROAMING */
/* ----------------------- MISC SUBROUTINES ------------------------ */
-static inline unsigned long /* flags */
- wv_splhi(void); /* Disable interrupts */
-static inline void
- wv_splx(unsigned long); /* ReEnable interrupts : flags */
static void
cs_error(client_handle_t, /* Report error to cardmgr */
int,
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 0c4f72ae7..b63ff08d5 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -410,6 +410,7 @@ typedef struct local_info_t {
int suspended;
unsigned last_ptr_value; /* last packets transmitted value */
const char *manf_str;
+ spinlock_t lock;
} local_info_t;
/****************
@@ -429,6 +430,7 @@ static void do_reset(struct net_device *dev, int full);
static int init_mii(struct net_device *dev);
static void do_powerdown(struct net_device *dev);
static int do_stop(struct net_device *dev);
+static void xirc_tx_timeout (struct net_device *dev);
/*=============== Helper functions =========================*/
static void
@@ -691,6 +693,8 @@ xirc2ps_attach(void)
local = kmalloc(sizeof(*local), GFP_KERNEL);
if (!local) return NULL;
memset(local, 0, sizeof(*local));
+
+ local->lock = SPIN_LOCK_UNLOCKED;
link = &local->link; dev = &local->dev;
link->priv = dev->priv = local;
@@ -717,7 +721,9 @@ xirc2ps_attach(void)
dev->init = &do_init;
dev->open = &do_open;
dev->stop = &do_stop;
- dev->tbusy = 1;
+ dev->tx_timeout = xirc_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ netif_start_queue(dev);
/* Register with Card Services */
link->next = dev_list;
@@ -1233,7 +1239,7 @@ xirc2ps_config(dev_link_t * link)
/* we can now register the device with the net subsystem */
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue(dev);
if ((err=register_netdev(dev))) {
printk(KNOT_XIRC "register_netdev() failed\n");
goto config_error;
@@ -1334,7 +1340,7 @@ xirc2ps_event(event_t event, int priority,
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 1; dev->start = 0;
+ netif_device_detach(dev);
link->release.expires = jiffies + HZ / 20;
add_timer(&link->release);
}
@@ -1349,7 +1355,7 @@ xirc2ps_event(event_t event, int priority,
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
if (link->open) {
- dev->tbusy = 1; dev->start = 0;
+ netif_device_detach(dev);
lp->suspended=1;
do_powerdown(dev);
}
@@ -1365,7 +1371,7 @@ xirc2ps_event(event_t event, int priority,
if (link->open) {
do_reset(dev,1);
lp->suspended=0;
- dev->tbusy = 0; dev->start = 1;
+ netif_device_attach(dev);
}
}
break;
@@ -1393,14 +1399,10 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* -- on a laptop?
*/
- if (!dev->start)
- return;
-
- if (dev->interrupt) {
- printk(KERR_XIRC "re-entering isr on irq %d (dev=%p)\n", irq, dev);
+ spin_lock (&lp->lock);
+ if (!netif_device_present(dev))
return;
- }
- dev->interrupt = 1;
+
ioaddr = dev->base_addr;
if (lp->mohawk) { /* must disable the interrupt */
PutByte(XIRCREG_CR, 0);
@@ -1555,8 +1557,7 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
DEBUG(0, "PTR not changed?\n");
} else
lp->stats.tx_packets += lp->last_ptr_value - n;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev);
}
if (tx_status & 0x0002) { /* Execessive collissions */
DEBUG(0, "tx restarted due to execssive collissions\n");
@@ -1595,7 +1596,9 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
goto loop_entry;
}
SelectPage(saved_page);
- dev->interrupt = 0;
+
+ spin_unlock (&lp->lock);
+
PutByte(XIRCREG_CR, EnableIntr); /* re-enable interrupts */
/* Instead of dropping packets during a receive, we could
* force an interrupt with this command:
@@ -1605,44 +1608,39 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*====================================================================*/
-static int
-do_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void xirc_tx_timeout (struct net_device *dev)
{
- local_info_t *lp = dev->priv;
- ioaddr_t ioaddr = dev->base_addr;
- int okay;
- unsigned freespace;
- unsigned pktlen = skb? skb->len : 0;
-
- DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
- skb, dev, pktlen);
-
- /* Transmitter timeout, serious problems */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
+ local_info_t *lp = dev->priv;
if (lp->suspended) {
- dev_kfree_skb (skb);
dev->trans_start = jiffies;
lp->stats.tx_dropped++;
- return 0;
+ netif_start_queue(dev);
+ return;
}
- if (tickssofar < TX_TIMEOUT)
- return 1;
printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
lp->stats.tx_errors++;
/* reset the card */
do_reset(dev,1);
dev->trans_start = jiffies;
- dev->tbusy = 0;
- }
+ netif_start_queue(dev);
+}
- if (test_and_set_bit(0, (void*)&dev->tbusy)) {
- printk(KWRN_XIRC "transmitter access conflict\n");
- dev_kfree_skb (skb);
- return 0;
- }
+
+static int
+do_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ local_info_t *lp = dev->priv;
+ ioaddr_t ioaddr = dev->base_addr;
+ int okay;
+ unsigned freespace;
+ unsigned pktlen = skb? skb->len : 0;
+
+ DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
+ skb, dev, pktlen);
+
+ netif_stop_queue(dev);
/* adjust the packet length to min. required
* and hope that the buffer is large enough
@@ -1664,7 +1662,6 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n",
dev->name, freespace, okay ? " (okay)":" (not enough)");
if (!okay) { /* not enough space */
- dev->tbusy = 1;
return 1; /* upper layer may decide to requeue this packet */
}
/* send the packet */
@@ -1678,7 +1675,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
dev->trans_start = jiffies;
- dev->tbusy = 0;
+ netif_start_queue(dev);
lp->stats.tx_bytes += pktlen;
return 0;
}
@@ -1823,7 +1820,7 @@ do_open(struct net_device *dev)
link->open++;
MOD_INC_USE_COUNT;
- dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+ netif_start_queue(dev);
lp->suspended = 0;
do_reset(dev,1);
@@ -2141,8 +2138,7 @@ do_stop(struct net_device *dev)
if (!link)
return -ENODEV;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
SelectPage(0);
PutByte(XIRCREG_CR, 0); /* disable interrupts */
@@ -2152,7 +2148,7 @@ do_stop(struct net_device *dev)
PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */
SelectPage(0);
- link->open--; dev->start = 0;
+ link->open--;
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 30bc7a7ba..7374eac66 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1162,7 +1162,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* We must free the original skb */
if (lp->tx_skbuff[entry]) {
- dev_kfree_skb(lp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(lp->tx_skbuff[entry]);
lp->tx_skbuff[entry] = 0;
}
dirty_tx++;
@@ -1176,8 +1176,8 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
#endif
if (lp->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->flags) &&
- dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+ netif_queue_stopped(dev) &&
+ dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
/* The ring is no longer full, clear tbusy. */
lp->tx_full = 0;
netif_wake_queue (dev);
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 75a703886..d86ce1d85 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -442,8 +442,7 @@ plip_timer_bh(struct net_device *dev)
struct net_local *nl = (struct net_local *)dev->priv;
if (!(atomic_read (&nl->kill_timer))) {
- if (!dev->interrupt)
- plip_interrupt (-1, dev, NULL);
+ plip_interrupt (-1, dev, NULL);
queue_task (&nl->timer, &tq_timer);
}
@@ -521,7 +520,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
synchronize_irq();
}
disable_parport_interrupts (dev);
- dev->tbusy = 1;
+ netif_stop_queue (dev);
nl->connection = PLIP_CN_ERROR;
write_data (dev, 0x00);
@@ -597,7 +596,6 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
DISABLE(dev->irq);
/* Don't need to synchronize irq, as we can safely ignore it */
disable_parport_interrupts (dev);
- dev->interrupt = 0;
write_data (dev, 0x01); /* send ACK */
if (net_debug > 2)
printk(KERN_DEBUG "%s: receive start\n", dev->name);
@@ -869,8 +867,7 @@ plip_connection_close(struct net_device *dev, struct net_local *nl,
spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_CLOSING) {
nl->connection = PLIP_CN_NONE;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
}
spin_unlock_irq(&nl->lock);
if (nl->should_relinquish) {
@@ -893,11 +890,10 @@ plip_error(struct net_device *dev, struct net_local *nl,
printk(KERN_DEBUG "%s: reset interface.\n", dev->name);
nl->connection = PLIP_CN_NONE;
nl->should_relinquish = 0;
- dev->tbusy = 0;
- dev->interrupt = 0;
+ netif_start_queue (dev);
enable_parport_interrupts (dev);
ENABLE(dev->irq);
- mark_bh(NET_BH);
+ netif_wake_queue (dev);
} else {
nl->is_deferred = 1;
queue_task(&nl->deferred, &tq_timer);
@@ -923,23 +919,22 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
nl = (struct net_local *)dev->priv;
rcv = &nl->rcv_data;
- if (dev->interrupt)
- return;
+ spin_lock_irq (&nl->lock);
c0 = read_status(dev);
if ((c0 & 0xf8) != 0xc0) {
if ((dev->irq != -1) && (net_debug > 1))
printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name);
+ spin_unlock_irq (&nl->lock);
return;
}
- dev->interrupt = 1;
+
if (net_debug > 3)
printk(KERN_DEBUG "%s: interrupt.\n", dev->name);
- spin_lock_irq(&nl->lock);
switch (nl->connection) {
case PLIP_CN_CLOSING:
- dev->tbusy = 0;
+ netif_start_queue (dev);
case PLIP_CN_NONE:
case PLIP_CN_SEND:
dev->last_rx = jiffies;
@@ -948,21 +943,20 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
nl->timeout_count = 0;
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- spin_unlock_irq(&nl->lock);
break;
case PLIP_CN_RECEIVE:
/* May occur because there is race condition
around test and set of dev->interrupt.
Ignore this interrupt. */
- spin_unlock_irq(&nl->lock);
break;
case PLIP_CN_ERROR:
- spin_unlock_irq(&nl->lock);
printk(KERN_ERR "%s: receive interrupt in error state\n", dev->name);
break;
}
+
+ spin_unlock_irq(&nl->lock);
}
static int
@@ -971,7 +965,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
struct net_local *nl = (struct net_local *)dev->priv;
struct plip_local *snd = &nl->snd_data;
- if (dev->tbusy)
+ if (netif_queue_stopped(dev))
return 1;
/* We may need to grab the bus */
@@ -981,14 +975,11 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
nl->port_owner = 1;
}
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
-
+ netif_stop_queue (dev);
+
if (skb->len > dev->mtu + dev->hard_header_len) {
printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len);
- dev->tbusy = 0;
+ netif_start_queue (dev);
return 0;
}
@@ -1007,7 +998,8 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
spin_unlock_irq(&nl->lock);
-
+
+ netif_start_queue (dev);
return 0;
}
@@ -1115,9 +1107,7 @@ plip_open(struct net_device *dev)
}
}
- dev->interrupt = 0;
- dev->start = 1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
MOD_INC_USE_COUNT;
return 0;
@@ -1131,8 +1121,7 @@ plip_close(struct net_device *dev)
struct plip_local *snd = &nl->snd_data;
struct plip_local *rcv = &nl->rcv_data;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
DISABLE(dev->irq);
synchronize_irq();
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index fad5da9fe..ddfed868e 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -30,6 +30,7 @@
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/list.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/netdevice.h>
#include <linux/poll.h>
#include <linux/ppp_defs.h>
@@ -549,6 +550,8 @@ static struct file_operations ppp_device_fops = {
#define PPP_MAJOR 108
+static devfs_handle_t devfs_handle = NULL;
+
/* Called at boot time if ppp is compiled into the kernel,
or at module load time (from init_module) if compiled as a module. */
int __init ppp_init(void)
@@ -561,9 +564,13 @@ int __init ppp_init(void)
#endif
printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n");
- err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
+ err = devfs_register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
if (err)
printk(KERN_ERR "failed to register PPP device (%d)\n", err);
+ devfs_handle = devfs_register (NULL, "ppp", 0, DEVFS_FL_NONE,
+ PPP_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &ppp_device_fops, NULL);
#ifndef MODULE
#ifdef CONFIG_PPP_ASYNC
ppp_async_init();
@@ -1613,7 +1620,8 @@ cleanup_module(void)
/* should never happen */
if (!list_empty(&all_ppp_units))
printk(KERN_ERR "PPP: removing module but units remain!\n");
- if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
+ if (devfs_unregister_chrdev(PPP_MAJOR, "ppp") != 0)
printk(KERN_ERR "PPP: failed to unregister PPP device\n");
+ devfs_unregister (devfs_handle);
}
#endif /* MODULE */
diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c
index 396e783c5..27b0c6474 100644
--- a/drivers/net/rcpci45.c
+++ b/drivers/net/rcpci45.c
@@ -309,7 +309,6 @@ RCfound_device(int memaddr, int irq,
#endif
dev->base_addr = (unsigned long)vaddr;
dev->irq = irq;
- dev->interrupt = 0;
/*
* Request a shared interrupt line.
@@ -430,6 +429,7 @@ RCopen(struct net_device *dev)
printk("rc: RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers);
#endif
MOD_INC_USE_COUNT;
+ netif_start_queue(dev);
return 0;
}
@@ -441,29 +441,26 @@ RC_xmit_packet(struct sk_buff *skb, struct net_device *dev)
singleTCB tcb;
psingleTCB ptcb = &tcb;
RC_RETURN status = 0;
-
- if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
- {
+
+ netif_stop_queue(dev);
+
+ if (pDpa->shutdown || pDpa->reboot)
+ {
#ifdef RCDEBUG
printk("rc: RC_xmit_packet: tbusy!\n");
#endif
- dev->tbusy = 1;
return 1;
- }
-
- if ( skb->len <= 0 )
- {
- printk("RC_xmit_packet: skb->len less than 0!\n");
- return 0;
}
-
+
/*
* The user is free to reuse the TCB after RCI2OSendPacket() returns, since
* the function copies the necessary info into its own private space. Thus,
* our TCB can be a local structure. The skb, on the other hand, will be
* freed up in our interrupt handler.
*/
+
ptcb->bcount = 1;
+
/*
* we'll get the context when the adapter interrupts us to tell us that
* the transmision is done. At that time, we can free skb.
@@ -483,13 +480,12 @@ RC_xmit_packet(struct sk_buff *skb, struct net_device *dev)
#ifdef RCDEBUG
printk("rc: RC send error 0x%x\n", (uint)status);
#endif
- dev->tbusy = 1;
return 1;
}
else
{
dev->trans_start = jiffies;
- // dev->tbusy = 0;
+ netif_wake_queue(dev);
}
/*
* That's it!
@@ -546,10 +542,9 @@ RCxmit_callback(U32 Status,
printk("rc: skb = 0x%x\n", (uint)skb);
#endif
BufferContext++;
- dev_kfree_skb (skb);
+ dev_kfree_skb_irq(skb);
}
- dev->tbusy = 0;
-
+ netif_wake_queue(dev);
}
static void
@@ -811,14 +806,8 @@ RCinterrupt(int irq, void *dev_id, struct pt_regs *regs)
(uint)pDpa, (uint)dev, (uint)pDpa->id);
printk("dev = 0x%x\n", (uint)dev);
#endif
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
RCProcI2OMsgQ(pDpa->id);
- dev->interrupt = 0;
-
- return;
}
@@ -870,7 +859,7 @@ static void rc_timer(unsigned long data)
(uint)pDpa->numOutRcvBuffers);
}
printk("rc: Initialization done.\n");
- dev->tbusy=0;
+ netif_wake_queue(dev);
retry=0;
return;
case RC_RTN_FREE_Q_EMPTY:
@@ -913,6 +902,8 @@ RCclose(struct net_device *dev)
PDPA pDpa = (PDPA) dev->priv;
+ netif_stop_queue(dev);
+
#ifdef RCDEBUG
printk("rc: RCclose\r\n");
#endif
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8129.c
index e5a5c6115..b60a62608 100644
--- a/drivers/net/rtl8139.c
+++ b/drivers/net/rtl8129.c
@@ -1,4 +1,4 @@
-/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
+/* rtl8129.c: A RealTek RTL8129 Fast Ethernet driver for Linux. */
/*
Written 1997-1999 by Donald Becker.
@@ -6,8 +6,7 @@
of the GNU Public License, incorporated herein by reference.
All other rights reserved.
- This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet
- chips.
+ This driver is for boards based on the RTL8129 PCI ethernet chip.
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
@@ -20,7 +19,7 @@
*/
static const char *version =
-"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+"rtl8129.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
/* A few user-configurable values. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
@@ -66,6 +65,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -96,11 +96,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#else
#define PCI_SUPPORT_VER2
#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
/* The I/O extent. */
#define RTL8129_TOTAL_SIZE 0x80
@@ -175,12 +170,14 @@ static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
static struct pci_id_info pci_tbl[] =
{{ "RealTek RTL8129 Fast Ethernet",
0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+#ifdef USE_8139_SUPPORT_ALSO
{ "RealTek RTL8139 Fast Ethernet",
0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)",
0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
{ "Accton MPX5030 (RealTek RTL8139)",
0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+#endif
{0,}, /* 0 terminated list. */
};
@@ -243,7 +240,7 @@ enum CSCRBits {
CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
CSCR_LinkDownCmd=0x0f3c0,
};
-unsigned long param[4][4]={
+static const unsigned long param[4][4]={
{0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
@@ -289,17 +286,13 @@ struct rtl8129_private {
unsigned int mediasense:1; /* Media sensing in progress. */
};
-#ifdef MODULE
-#if LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
+MODULE_DESCRIPTION("RealTek RTL8129 Fast Ethernet driver");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(multicast_filter_limit, "i");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(debug, "i");
-#endif
-#endif
static int rtl8129_open(struct net_device *dev);
static int read_eeprom(long ioaddr, int location);
@@ -326,7 +319,7 @@ static struct net_device *root_rtl8129_dev = NULL;
well when dynamically adding drivers. So instead we detect just the
Rtl81*9 cards in slot order. */
-int rtl8139_probe(void)
+static int __init rtl8129_probe(void)
{
int cards_found = 0;
int pci_index = 0;
@@ -789,12 +782,12 @@ static void rtl8129_timer(unsigned long data)
if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
int status = inw(ioaddr + IntrStatus);
if (status & (TxOK | RxOK)) { /* Double check */
- printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n",
+ printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n",
dev->name, status);
rtl8129_interrupt(dev->irq, dev, 0);
}
}
- if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+ if (netif_queue_stopped(dev) &&
(jiffies - dev->trans_start) >= 2*TX_TIMEOUT)
rtl8129_tx_timeout(dev);
@@ -915,7 +908,7 @@ static void rtl8129_tx_timeout(struct net_device *dev)
saved_skb[j] = rp->skb;
if (rp->mapping != 0) {
- pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len);
+ pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);
rp->mapping = 0;
}
}
@@ -929,7 +922,7 @@ static void rtl8129_tx_timeout(struct net_device *dev)
ioaddr + TxAddr0 + i*4);
} else {
tp->tx_info[i].mapping =
- pci_map_single(tp->pdev, skb->data, skb->len);
+ pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4);
}
/* Note: the chip doesn't have auto-pad! */
@@ -947,6 +940,7 @@ static void rtl8129_tx_timeout(struct net_device *dev)
tp->tx_full = 0;
} else {
tp->tx_full = 1;
+ netif_stop_queue(dev);
}
}
@@ -997,7 +991,7 @@ rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev)
ioaddr + TxAddr0 + entry*4);
} else {
tp->tx_info[entry].mapping =
- pci_map_single(tp->pdev, skb->data, skb->len);
+ pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4);
}
/* Note: the chip doesn't have auto-pad! */
@@ -1091,12 +1085,13 @@ static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
if (tp->tx_info[entry].mapping != 0) {
pci_unmap_single(tp->pdev,
tp->tx_info[entry].mapping,
- tp->tx_info[entry].skb->len);
+ tp->tx_info[entry].skb->len,
+ PCI_DMA_TODEVICE);
tp->tx_info[entry].mapping = 0;
}
/* Free the original skb. */
- dev_free_skb(tp->tx_info[entry].skb);
+ dev_kfree_skb_irq(tp->tx_info[entry].skb);
tp->tx_info[entry].skb = NULL;
if (tp->tx_full) {
/* The ring is no longer full, wake the queue. */
@@ -1321,8 +1316,8 @@ rtl8129_close(struct net_device *dev)
if (skb) {
if (mapping)
- pci_unmap_single(tp->pdev, mapping, skb->len);
- dev_free_skb(skb);
+ pci_unmap_single(tp->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
}
tp->tx_info[i].skb = NULL;
tp->tx_info[i].mapping = 0;
@@ -1372,7 +1367,7 @@ rtl8129_get_stats(struct net_device *dev)
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (test_bit(LINK_STATE_START, &dev->state)) {
+ if (netif_running(dev)) {
tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
outl(0, ioaddr + RxMissed);
}
@@ -1440,14 +1435,8 @@ static void set_rx_mode(struct net_device *dev)
return;
}
-#ifdef MODULE
-int init_module(void)
-{
- return rtl8139_probe();
-}
-void
-cleanup_module(void)
+static void __exit rtl8129_cleanup (void)
{
struct net_device *next_dev;
@@ -1465,12 +1454,13 @@ cleanup_module(void)
}
}
-#endif /* MODULE */
-
+module_init(rtl8129_probe);
+module_exit(rtl8129_cleanup);
+
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 5bdb0176a..9b17cc79d 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -1002,10 +1002,8 @@ sb1000_open(struct net_device *dev)
"(should be %x.%02x)\n", name, version[0], version[1],
FirmwareVersion[0], FirmwareVersion[1]);
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0; /* Always succeed */
}
@@ -1122,10 +1120,6 @@ static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irq);
return;
}
- if (dev->interrupt)
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n",
- dev->name);
- dev->interrupt = 1;
ioaddr[0] = dev->base_addr;
/* rmem_end holds the second I/O address - fv */
@@ -1135,7 +1129,6 @@ static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* is it a good interrupt? */
st = inb(ioaddr[1] + 6);
if (!(st & 0x08 && st & 0x20)) {
- dev->interrupt = 0;
return;
}
@@ -1167,7 +1160,6 @@ static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->rx_error_count = 0;
}
- dev->interrupt = 0;
return;
}
@@ -1186,9 +1178,8 @@ static int sb1000_close(struct net_device *dev)
if (sb1000_debug > 2)
printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name);
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
ioaddr[0] = dev->base_addr;
/* rmem_end holds the second I/O address - fv */
ioaddr[1] = dev->rmem_end;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index d2756c92f..f7d86c103 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -83,6 +83,7 @@ extern int seeq8005_probe(struct net_device *dev);
static int seeq8005_probe1(struct net_device *dev, int ioaddr);
static int seeq8005_open(struct net_device *dev);
+static void seeq8005_timeout(struct net_device *dev);
static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void seeq8005_rx(struct net_device *dev);
@@ -324,9 +325,11 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
dev->open = seeq8005_open;
dev->stop = seeq8005_close;
- dev->hard_start_xmit = seeq8005_send_packet;
- dev->get_stats = seeq8005_get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->hard_start_xmit = seeq8005_send_packet;
+ dev->tx_timeout = seeq8005_timeout;
+ dev->watchdog_timeo = HZ/20;
+ dev->get_stats = seeq8005_get_stats;
+ dev->set_multicast_list = set_multicast_list;
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
@@ -344,8 +347,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
registers that "should" only need to be set once at boot, so that
there is non-reboot way to recover if something goes wrong.
*/
-static int
-seeq8005_open(struct net_device *dev)
+static int seeq8005_open(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
@@ -363,46 +365,34 @@ seeq8005_open(struct net_device *dev)
lp->open_time = jiffies;
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
return 0;
}
-static int
-seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void seeq8005_timeout(struct net_device *dev)
{
int ioaddr = dev->base_addr;
- struct net_local *lp = (struct net_local *)dev->priv;
+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+ tx_done(dev) ? "IRQ conflict" : "network cable problem");
+ /* Try to restart the adaptor. */
+ seeq8005_init(dev, 1);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
- /* Try to restart the adaptor. */
- seeq8005_init(dev, 1);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
+static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
-
- hardware_send_packet(dev, buf, length);
- dev->trans_start = jiffies;
- lp->stats.tx_bytes += length;
- }
+ /* Block a timer-based transmit from overlapping */
+ netif_stop_queue(dev);
+
+ hardware_send_packet(dev, buf, length);
+ dev->trans_start = jiffies;
+ lp->stats.tx_bytes += length;
dev_kfree_skb (skb);
-
/* You might need to clean up and record Tx statistics here. */
return 0;
@@ -410,22 +400,12 @@ seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static void
-seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status, boguscount = 0;
- if (dev == NULL) {
- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
-
- if (dev->interrupt)
- printk ("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
@@ -444,8 +424,7 @@ seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if (status & SEEQSTAT_TX_INT) {
outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
lp->stats.tx_packets++;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & SEEQSTAT_RX_INT) {
/* Got a packet(s). */
@@ -457,13 +436,10 @@ seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if(net_debug>2) {
printk("%s: eoi\n",dev->name);
}
- dev->interrupt = 0;
- return;
}
/* We have a good packet(s), get it/them out of the buffers. */
-static void
-seeq8005_rx(struct net_device *dev)
+static void seeq8005_rx(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int boguscount = 10;
@@ -561,17 +537,15 @@ seeq8005_rx(struct net_device *dev)
}
/* The inverse routine to net_open(). */
-static int
-seeq8005_close(struct net_device *dev)
+static int seeq8005_close(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
lp->open_time = 0;
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
/* Flush the Tx and disable Rx here. */
outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
@@ -598,8 +572,7 @@ static struct net_device_stats *seeq8005_get_stats(struct net_device *dev)
num_addrs > 0 Multicast mode, receive normal and MC packets, and do
best-effort filtering.
*/
-static void
-set_multicast_list(struct net_device *dev)
+static void set_multicast_list(struct net_device *dev)
{
/*
* I _could_ do up to 6 addresses here, but won't (yet?)
diff --git a/drivers/net/setup.c b/drivers/net/setup.c
index 29a63e1aa..472b23a8c 100644
--- a/drivers/net/setup.c
+++ b/drivers/net/setup.c
@@ -15,9 +15,7 @@ extern int strip_init_ctrl_dev(void);
extern int x25_asy_init_ctrl_dev(void);
extern int slhc_install(void);
-extern int bpq_init(void);
extern int dmascc_init(void);
-extern int scc_init(void);
extern int yam_init(void);
extern int awc4500_pci_probe(void);
@@ -59,15 +57,9 @@ struct net_probe pci_probes[] __initdata = {
* Early setup devices
*/
-#if defined(CONFIG_SCC)
- {scc_init, 0},
-#endif
#if defined(CONFIG_DMASCC)
{dmascc_init, 0},
#endif
-#if defined(CONFIG_BPQETHER)
- {bpq_init, 0},
-#endif
#if defined(CONFIG_DLCI)
{dlci_setup, 0},
#endif
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 7d072d5f0..56333fea0 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.c,v 1.13 1999/12/04 03:59:03 ralf Exp $
+/* $Id: sgiseeq.c,v 1.14 2000/02/23 00:41:14 ralf Exp $
*
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
@@ -428,8 +428,7 @@ static void sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (sp->tx_old != sp->tx_new)
sgiseeq_tx(dev, sp, hregs, sregs);
- if ((TX_BUFFS_AVAIL(sp) > 0) && \
- test_bit(LINK_STATE_XOFF, &dev->state)) {
+ if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) {
netif_wake_queue(dev);
}
}
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 60d730699..f8af277ea 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1,6 +1,6 @@
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
- Revision: 1.06.03 Dec 23 1999
+ Revision: 1.06.04 Feb 11 2000
Modified from the driver which is originally written by Donald Becker.
@@ -17,7 +17,8 @@
SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
preliminary Rev. 1.0 Jan. 18, 1998
http://www.sis.com.tw/support/databook.htm
-
+
+ Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@mandrakesoft.com> softnet and init for kernel 2.4
Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release
Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed
Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com)
@@ -51,7 +52,7 @@
#include "sis900.h"
static const char *version =
-"sis900.c: v1.06.03 12/23/99\n";
+"sis900.c: v1.06.04 02/11/2000\n";
static int max_interrupt_work = 20;
#define sis900_debug debug
@@ -134,7 +135,7 @@ struct sis900_private {
int LinkOn;
};
-MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>");
+MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver");
MODULE_PARM(multicast_filter_limit, "i");
MODULE_PARM(max_interrupt_work, "i");
@@ -256,7 +257,7 @@ static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct
net_dev->irq = irq;
sis_priv->pci_dev = pci_dev;
sis_priv->mac = mac;
- sis_priv->lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&sis_priv->lock);
/* probe for mii transciver */
if (sis900_mii_probe(net_dev) == 0) {
@@ -667,8 +668,8 @@ static void sis900_timer(unsigned long data)
next_tick = 5*HZ;
/* change what cur_phy means */
if (mii_phy->phy_addr != sis_priv->cur_phy) {
- printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name,
- mii_phy->chip_info->name);
+ printk(KERN_INFO "%s: Changing transceiver to %s\n",
+ net_dev->name, mii_phy->chip_info->name);
status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
mdio_write(net_dev, sis_priv->cur_phy,
MII_CONTROL, status | MII_CNTL_ISOLATE);
@@ -788,6 +789,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
{
struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
long ioaddr = net_dev->base_addr;
+ unsigned long flags;
int i;
printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
@@ -796,8 +798,10 @@ static void sis900_tx_timeout(struct net_device *net_dev)
/* Disable interrupts by clearing the interrupt mask. */
outl(0x0000, ioaddr + imr);
- /* discard unsent packets, should this code section be protected by
- cli(), sti() ?? */
+ /* use spinlock to prevent interrupt handler accessing buffer ring */
+ spin_lock_irqsave(&sis_priv->lock, flags);
+
+ /* discard unsent packets */
sis_priv->dirty_tx = sis_priv->cur_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++) {
if (sis_priv->tx_skbuff[i] != NULL) {
@@ -808,12 +812,15 @@ static void sis900_tx_timeout(struct net_device *net_dev)
sis_priv->stats.tx_dropped++;
}
}
+ sis_priv->tx_full = 0;
+ netif_wake_queue(net_dev);
+
+ spin_unlock_irqrestore(&sis_priv->lock, flags);
net_dev->trans_start = jiffies;
- sis_priv->tx_full = 0;
- netif_start_queue(net_dev);
/* FIXME: Should we restart the transmission thread here ?? */
+ outl(TxENA, ioaddr + cr);
/* Enable all known interrupts by setting the interrupt mask. */
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
@@ -826,6 +833,9 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
long ioaddr = net_dev->base_addr;
unsigned int entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sis_priv->lock, flags);
/* Calculate the next Tx descriptor entry. */
entry = sis_priv->cur_tx % NUM_TX_DESC;
@@ -837,14 +847,16 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
outl(TxENA, ioaddr + cr);
if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
- /* Typical path, clear tbusy to indicate more
- transmission is possible */
+ /* Typical path, tell upper layer that more transmission is possible */
netif_start_queue(net_dev);
} else {
- /* no more transmit descriptor avaiable, tbusy remain set */
+ /* buffer full, tell upper layer no more transmission */
sis_priv->tx_full = 1;
+ netif_stop_queue(net_dev);
}
+ spin_unlock_irqrestore(&sis_priv->lock, flags);
+
net_dev->trans_start = jiffies;
if (sis900_debug > 3)
@@ -918,7 +930,7 @@ static int sis900_rx(struct net_device *net_dev)
if (sis900_debug > 3)
printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
"status:0x%8.8x\n",
- sis_priv->cur_rx, sis_priv->dirty_rx,rx_status);
+ sis_priv->cur_rx, sis_priv->dirty_rx, rx_status);
while (rx_status & OWN) {
unsigned int rx_size;
@@ -1048,16 +1060,16 @@ static void sis900_finish_xmit (struct net_device *net_dev)
sis_priv->stats.tx_packets++;
}
/* Free the original skb. */
- dev_kfree_skb(sis_priv->tx_skbuff[entry]);
+ dev_kfree_skb_irq(sis_priv->tx_skbuff[entry]);
sis_priv->tx_skbuff[entry] = NULL;
sis_priv->tx_ring[entry].bufptr = 0;
sis_priv->tx_ring[entry].cmdsts = 0;
}
- if (sis_priv->tx_full && test_bit(LINK_STATE_XOFF, &net_dev->flags) &&
+ if (sis_priv->tx_full && netif_queue_stopped(net_dev) &&
sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
- /* The ring is no longer full, clear tbusy, tx_full and
- schedule more transmission by marking NET_BH */
+ /* The ring is no longer full, clear tx_full and schedule more transmission
+ by netif_wake_queue(net_dev) */
sis_priv->tx_full = 0;
netif_wake_queue (net_dev);
}
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index d7ed239a4..f6710a0b5 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -276,7 +276,9 @@ static const char SysKonnectBuildNumber[] =
// #define RLMT_MODE {"CheckLink", }
-#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb)
+#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb)
/* function prototypes ******************************************************/
static void FreeResources(struct net_device *dev);
@@ -410,6 +412,21 @@ static int __init skge_probe (void)
pci_set_master(pdev);
+#ifdef __sparc__
+ /* Set the proper cache line size value, plus enable
+ * write-invalidate and fast back-to-back on Sparc.
+ */
+ {
+ SK_U16 pci_command;
+
+ SkPciWriteCfgByte(pAC, PCI_CACHE_LINE_SIZE, 0x10);
+
+ SkPciReadCfgWord(pAC, PCI_COMMAND, &pci_command);
+ pci_command |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK);
+ SkPciWriteCfgWord(pAC, PCI_COMMAND, pci_command);
+ }
+#endif
+
base_address = pdev->resource[0].start;
#ifdef SK_BIG_ENDIAN
@@ -1507,13 +1524,16 @@ int Rc; /* return code of XmitFrame */
Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb);
- if (Rc == 0) {
- /* transmitter out of resources */
+ /* Transmitter out of resources? */
+ if (Rc <= 0)
netif_stop_queue(dev);
- /* give buffer ownership back to the queueing layer */
+ /* If not taken, give buffer ownership back to the
+ * queueing layer.
+ */
+ if (Rc < 0)
return (1);
- }
+
dev->trans_start = jiffies;
return (0);
} /* SkGeXmit */
@@ -1539,7 +1559,7 @@ int Rc; /* return code of XmitFrame */
* > 0 - on succes: the number of bytes in the message
* = 0 - on resource shortage: this frame sent or dropped, now
* the ring is full ( -> set tbusy)
- * < 0 - on failure: other problems (not used)
+ * < 0 - on failure: other problems ( -> return failure to upper layers)
*/
static int XmitFrame(
SK_AC *pAC, /* pointer to adapter context */
@@ -1566,7 +1586,7 @@ int BytesSend;
SK_DBGCAT_DRV_TX_PROGRESS,
("XmitFrame failed\n"));
/* this message can not be sent now */
- return (0);
+ return (-1);
}
}
/* advance head counter behind descriptor needed for this frame */
@@ -1586,7 +1606,8 @@ int BytesSend;
/* set up descriptor and CONTROL dword */
PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev,
pMessage->data,
- pMessage->len);
+ pMessage->len,
+ PCI_DMA_TODEVICE);
pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
pTxd->pMBuf = pMessage;
@@ -1679,9 +1700,11 @@ SK_U64 PhysAddr; /* address of DMA mapping */
PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
PhysAddr |= (SK_U64) pTxd->VDataLow;
pci_unmap_single(&pAC->PciDev, PhysAddr,
- pTxd->pMBuf->len);
+ pTxd->pMBuf->len,
+ PCI_DMA_TODEVICE);
- DEV_KFREE_SKB(pTxd->pMBuf); /* free message */
+ /* free message */
+ DEV_KFREE_SKB_ANY(pTxd->pMBuf);
pTxPort->TxdRingFree++;
pTxd->TBControl &= ~TX_CTRL_SOFTWARE;
pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
@@ -1759,7 +1782,8 @@ SK_U64 PhysAddr; /* physical address of a rx buffer */
Length = pAC->RxBufSize;
PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev,
pMsgBlock->data,
- pAC->RxBufSize - 2);
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
pRxd->pMBuf = pMsgBlock;
@@ -1882,7 +1906,8 @@ rx_start:
skb_put(pNewMsg, FrameLength);
pci_dma_sync_single(&pAC->PciDev,
(dma_addr_t) PhysAddr,
- FrameLength);
+ FrameLength,
+ PCI_DMA_FROMDEVICE);
eth_copy_and_sum(pNewMsg, pMsg->data,
FrameLength, 0);
ReQueueRxBuffer(pAC, pRxPort, pMsg,
@@ -1902,15 +1927,16 @@ rx_start:
/* release the DMA mapping */
pci_unmap_single(&pAC->PciDev,
PhysAddr,
- pAC->RxBufSize - 2);
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
/* set length in message */
skb_put(pMsg, FrameLength);
/* hardware checksum */
Type = ntohs(*((short*)&pMsg->data[12]));
if (Type == 0x800) {
- Csum1= pRxd->TcpSums & 0xffff;
- Csum2=(pRxd->TcpSums >> 16) & 0xffff;
+ Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff);
+ Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff);
if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) {
Result = SkCsGetReceiveInfo(pAC,
&pMsg->data[14],
@@ -1980,7 +2006,7 @@ rx_start:
SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
SK_DBGCAT_DRV_RX_PROGRESS,
("D"));
- DEV_KFREE_SKB(pMsg);
+ DEV_KFREE_SKB_IRQ(pMsg);
}
} /* if not for rlmt */
else {
@@ -2016,7 +2042,7 @@ rx_start:
pAC->dev->last_rx = jiffies;
}
else {
- DEV_KFREE_SKB(pMsg);
+ DEV_KFREE_SKB_IRQ(pMsg);
}
} /* if packet for rlmt */
@@ -2040,7 +2066,7 @@ rx_start:
("skge: Error in received frame, dropped!\n"
"Control: %x\nRxStat: %x\n",
Control, FrameStat));
- DEV_KFREE_SKB(pMsg);
+ DEV_KFREE_SKB_IRQ(pMsg);
}
} /* while */
FillRxRing(pAC, pRxPort);
@@ -2060,8 +2086,9 @@ rx_failed:
PhysAddr |= (SK_U64) pRxd->VDataLow;
pci_unmap_single(&pAC->PciDev,
PhysAddr,
- pAC->RxBufSize - 2);
- DEV_KFREE_SKB(pRxd->pMBuf);
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
+ DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
pRxd->pMBuf = NULL;
pRxPort->RxdRingFree++;
pRxPort->pRxdRingHead = pRxd->pNextRxd;
@@ -2139,7 +2166,8 @@ unsigned int Flags;
PhysAddr |= (SK_U64) pRxd->VDataLow;
pci_unmap_single(&pAC->PciDev,
PhysAddr,
- pAC->RxBufSize - 2);
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
DEV_KFREE_SKB(pRxd->pMBuf);
pRxd->pMBuf = NULL;
}
@@ -2276,7 +2304,7 @@ unsigned int Flags;
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
("SkGeSetMacAddr starts now...\n"));
- if(test_bit(LINK_STATE_START, &dev->state)) {
+ if(netif_running(dev)) {
return -EBUSY;
}
memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
@@ -3120,7 +3148,7 @@ SK_MBUF *pNextMbuf;
pFreeMbuf = pMbuf;
do {
pNextMbuf = pFreeMbuf->pNext;
- DEV_KFREE_SKB(pFreeMbuf->pOs);
+ DEV_KFREE_SKB_ANY(pFreeMbuf->pOs);
pFreeMbuf = pNextMbuf;
} while ( pFreeMbuf != NULL );
} /* SkDrvFreeRlmtMbuf */
@@ -3489,8 +3517,9 @@ unsigned int Flags;
pRlmtMbuf = (SK_MBUF*) Param.pParaPtr;
pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
skb_put(pMsg, pRlmtMbuf->Length);
- XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
- pMsg);
+ if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
+ pMsg) < 0)
+ DEV_KFREE_SKB_ANY(pMsg);
break;
default:
break;
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index 24dd1ff1c..d3722cf2d 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -472,6 +472,7 @@ static spinlock_t SK_lock = SPIN_LOCK_UNLOCKED;
int SK_init(struct net_device *dev);
static int SK_probe(struct net_device *dev, short ioaddr);
+static void SK_timeout(struct net_device *dev);
static int SK_open(struct net_device *dev);
static int SK_send_packet(struct sk_buff *skb, struct net_device *dev);
static void SK_interrupt(int irq, void *dev_id, struct pt_regs * regs);
@@ -778,11 +779,13 @@ int __init SK_probe(struct net_device *dev, short ioaddr)
/* Assign our Device Driver functions */
- dev->open = &SK_open;
- dev->stop = &SK_close;
- dev->hard_start_xmit = &SK_send_packet;
- dev->get_stats = &SK_get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->open = SK_open;
+ dev->stop = SK_close;
+ dev->hard_start_xmit = SK_send_packet;
+ dev->get_stats = SK_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->tx_timeout = SK_timeout;
+ dev->watchdog_timeo = HZ/7;
/* Set the generic fields of the device structure */
@@ -1169,30 +1172,18 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode)
* YY/MM/DD uid Description
-*/
-static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
+static int SK_timeout(struct net_device *dev)
{
- struct priv *p = (struct priv *) dev->priv;
- struct tmd *tmdp;
-
- if (test_bit(LINK_STATE_XOFF, &dev->flags))
- {
- /* if Transmitter more than 150ms busy -> time_out */
-
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 15)
- {
- return 1; /* We have to try transmit later */
- }
-
- printk("%s: xmitter timed out, try to restart!\n", dev->name);
-
+ printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name);
SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */
-
netif_start_queue(dev); /* Clear Transmitter flag */
-
dev->trans_start = jiffies; /* Mark Start of transmission */
+}
- }
+static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+ struct tmd *tmdp;
PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n",
SK_NAME, SK_read_reg(CSR0)));
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
index 902644162..088b89388 100644
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -96,12 +96,13 @@ History:
* have to pack all state info into the device struct!
* ------------------------------------------------------------------------ */
-static char *MediaNames[Media_Count]=
- {"10Base2", "10BaseT", "10Base5", "Unknown"};
+static char *MediaNames[Media_Count] = {
+ "10Base2", "10BaseT", "10Base5", "Unknown" };
-static unsigned char poly[] =
- {1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0};
+static unsigned char poly[] = {
+ 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
+};
/* ------------------------------------------------------------------------
* private subfunctions
@@ -112,64 +113,70 @@ static unsigned char poly[] =
#ifdef DEBUG
static void dumpmem(struct net_device *dev, u32 start, u32 len)
{
- int z;
-
- for (z = 0; z < len; z++)
- {
- if ((z & 15) == 0)
- printk("%04x:", z);
- printk(" %02x", readb(dev->mem_start + start + z));
- if ((z & 15) == 15)
- printk("\n");
- }
+ int z;
+
+ for (z = 0; z < len; z++) {
+ if ((z & 15) == 0)
+ printk("%04x:", z);
+ printk(" %02x", readb(dev->mem_start + start + z));
+ if ((z & 15) == 15)
+ printk("\n");
+ }
}
/* print exact time - ditto */
static void PrTime(void)
{
- struct timeval tv;
+ struct timeval tv;
- do_gettimeofday(&tv);
- printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
+ do_gettimeofday(&tv);
+ printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
}
+
#endif
/* deduce resources out of POS registers */
static void getaddrs(int slot, int junior, int *base, int *irq,
- skmca_medium *medium)
+ skmca_medium * medium)
{
- u_char pos0, pos1, pos2;
-
- if (junior)
- {
- pos0 = mca_read_stored_pos(slot, 2);
- *base = ((pos0 & 0x0e) << 13) + 0xc0000;
- *irq = ((pos0 & 0x10) >> 4) + 10;
- *medium = Media_Unknown;
- }
- else
- {
- /* reset POS 104 Bits 0+1 so the shared memory region goes to the
- configured area between 640K and 1M. Afterwards, enable the MC2.
- I really don't know what rode SK to do this... */
-
- mca_write_pos(slot, 4, mca_read_stored_pos(slot, 4) & 0xfc);
- mca_write_pos(slot, 2, mca_read_stored_pos(slot, 2) | 0x01);
-
- pos1 = mca_read_stored_pos(slot, 3);
- pos2 = mca_read_stored_pos(slot, 4);
- *base = ((pos1 & 0x07) << 14) + 0xc0000;
- switch (pos2 & 0x0c)
- {
- case 0: *irq = 3; break;
- case 4: *irq = 5; break;
- case 8: *irq = 10; break;
- case 12: *irq = 11; break;
- }
- *medium = (pos2 >> 6) & 3;
- }
+ u_char pos0, pos1, pos2;
+
+ if (junior) {
+ pos0 = mca_read_stored_pos(slot, 2);
+ *base = ((pos0 & 0x0e) << 13) + 0xc0000;
+ *irq = ((pos0 & 0x10) >> 4) + 10;
+ *medium = Media_Unknown;
+ } else {
+ /* reset POS 104 Bits 0+1 so the shared memory region goes to the
+ configured area between 640K and 1M. Afterwards, enable the MC2.
+ I really don't know what rode SK to do this... */
+
+ mca_write_pos(slot, 4,
+ mca_read_stored_pos(slot, 4) & 0xfc);
+ mca_write_pos(slot, 2,
+ mca_read_stored_pos(slot, 2) | 0x01);
+
+ pos1 = mca_read_stored_pos(slot, 3);
+ pos2 = mca_read_stored_pos(slot, 4);
+ *base = ((pos1 & 0x07) << 14) + 0xc0000;
+ switch (pos2 & 0x0c) {
+ case 0:
+ *irq = 3;
+ break;
+ case 4:
+ *irq = 5;
+ break;
+ case 8:
+ *irq = 10;
+ break;
+ case 12:
+ *irq = 11;
+ break;
+ }
+ *medium = (pos2 >> 6) & 3;
+ }
}
/* check for both cards:
@@ -179,157 +186,162 @@ static void getaddrs(int slot, int junior, int *base, int *irq,
static int dofind(int *junior, int firstslot)
{
- int slot;
- unsigned int id;
-
- for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++)
- {
- id = mca_read_stored_pos(slot, 0)
- + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
-
- *junior = 0;
- if (id == SKNET_MCA_ID)
- return slot;
- *junior = 1;
- if (id == SKNET_JUNIOR_MCA_ID)
- return slot;
- }
- return MCA_NOTFOUND;
+ int slot;
+ unsigned int id;
+
+ for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) {
+ id = mca_read_stored_pos(slot, 0)
+ + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
+
+ *junior = 0;
+ if (id == SKNET_MCA_ID)
+ return slot;
+ *junior = 1;
+ if (id == SKNET_JUNIOR_MCA_ID)
+ return slot;
+ }
+ return MCA_NOTFOUND;
}
/* reset the whole board */
static void ResetBoard(struct net_device *dev)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
+ skmca_priv *priv = (skmca_priv *) dev->priv;
- writeb(CTRL_RESET_ON, priv->ctrladdr);
- udelay(10);
- writeb(CTRL_RESET_OFF, priv->ctrladdr);
+ writeb(CTRL_RESET_ON, priv->ctrladdr);
+ udelay(10);
+ writeb(CTRL_RESET_OFF, priv->ctrladdr);
}
/* set LANCE register - must be atomic */
static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
- unsigned long flags;
+ skmca_priv *priv = (skmca_priv *) dev->priv;
+ unsigned long flags;
- /* disable interrupts */
+ /* disable interrupts */
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
- /* wait until no transfer is pending */
-
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+ /* wait until no transfer is pending */
- /* transfer register address to RAP */
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+ /* transfer register address to RAP */
- /* transfer data to register */
+ writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
+ priv->ctrladdr);
+ writew(addr, priv->ioregaddr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
- writew(value, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+ /* transfer data to register */
- /* reenable interrupts */
+ writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA,
+ priv->ctrladdr);
+ writew(value, priv->ioregaddr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
- restore_flags(flags);
+ /* reenable interrupts */
+
+ restore_flags(flags);
}
/* get LANCE register */
static u16 GetLANCE(struct net_device *dev, u16 addr)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
- unsigned long flags;
- unsigned int res;
+ skmca_priv *priv = (skmca_priv *) dev->priv;
+ unsigned long flags;
+ unsigned int res;
- /* disable interrupts */
+ /* disable interrupts */
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
- /* wait until no transfer is pending */
+ /* wait until no transfer is pending */
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
- /* transfer register address to RAP */
+ /* transfer register address to RAP */
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+ writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP,
+ priv->ctrladdr);
+ writew(addr, priv->ioregaddr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
- /* transfer data from register */
+ /* transfer data from register */
- writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
- res = readw(priv->ioregaddr);
+ writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA,
+ priv->ctrladdr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+ res = readw(priv->ioregaddr);
- /* reenable interrupts */
+ /* reenable interrupts */
- restore_flags(flags);
+ restore_flags(flags);
- return res;
+ return res;
}
/* build up descriptors in shared RAM */
static void InitDscrs(struct net_device *dev)
{
- u32 bufaddr;
-
- /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
- are always 0. */
-
- bufaddr = RAM_DATABASE;
- {
- LANCE_TxDescr descr;
- int z;
-
- for (z = 0; z < TXCOUNT; z++)
- {
- descr.LowAddr = bufaddr;
- descr.Flags = 0;
- descr.Len = 0xf000;
- descr.Status = 0;
- isa_memcpy_toio(dev->mem_start + RAM_TXBASE + (z * sizeof(LANCE_TxDescr)),
- &descr, sizeof(LANCE_TxDescr));
- memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
-
- /* do the same for the Rx descriptors */
-
- {
- LANCE_RxDescr descr;
- int z;
-
- for (z = 0; z < RXCOUNT; z++)
- {
- descr.LowAddr = bufaddr;
- descr.Flags = RXDSCR_FLAGS_OWN;
- descr.MaxLen = -RAM_BUFSIZE;
- descr.Len = 0;
- isa_memcpy_toio(dev->mem_start + RAM_RXBASE + (z * sizeof(LANCE_RxDescr)),
- &descr, sizeof(LANCE_RxDescr));
- isa_memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
+ u32 bufaddr;
+
+ /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
+ are always 0. */
+
+ bufaddr = RAM_DATABASE;
+ {
+ LANCE_TxDescr descr;
+ int z;
+
+ for (z = 0; z < TXCOUNT; z++) {
+ descr.LowAddr = bufaddr;
+ descr.Flags = 0;
+ descr.Len = 0xf000;
+ descr.Status = 0;
+ isa_memcpy_toio(dev->mem_start + RAM_TXBASE +
+ (z * sizeof(LANCE_TxDescr)),
+ &descr, sizeof(LANCE_TxDescr));
+ memset_io(dev->mem_start + bufaddr, 0,
+ RAM_BUFSIZE);
+ bufaddr += RAM_BUFSIZE;
+ }
+ }
+
+ /* do the same for the Rx descriptors */
+
+ {
+ LANCE_RxDescr descr;
+ int z;
+
+ for (z = 0; z < RXCOUNT; z++) {
+ descr.LowAddr = bufaddr;
+ descr.Flags = RXDSCR_FLAGS_OWN;
+ descr.MaxLen = -RAM_BUFSIZE;
+ descr.Len = 0;
+ isa_memcpy_toio(dev->mem_start + RAM_RXBASE +
+ (z * sizeof(LANCE_RxDescr)),
+ &descr, sizeof(LANCE_RxDescr));
+ isa_memset_io(dev->mem_start + bufaddr, 0,
+ RAM_BUFSIZE);
+ bufaddr += RAM_BUFSIZE;
+ }
+ }
}
/* calculate the hash bit position for a given multicast address
@@ -337,136 +349,138 @@ static void InitDscrs(struct net_device *dev)
static void UpdateCRC(unsigned char *CRC, int bit)
{
- int j;
+ int j;
- /* shift CRC one bit */
+ /* shift CRC one bit */
- memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
- CRC[0] = 0;
+ memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
+ CRC[0] = 0;
- /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
+ /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
- if (bit ^ CRC[32])
- for (j = 0; j < 32; j++)
- CRC[j] ^= poly[j];
+ if (bit ^ CRC[32])
+ for (j = 0; j < 32; j++)
+ CRC[j] ^= poly[j];
}
static unsigned int GetHash(char *address)
{
- unsigned char CRC[33];
- int i, byte, hashcode;
+ unsigned char CRC[33];
+ int i, byte, hashcode;
- /* a multicast address has bit 0 in the first byte set */
+ /* a multicast address has bit 0 in the first byte set */
- if ((address[0] & 1) == 0)
- return -1;
+ if ((address[0] & 1) == 0)
+ return -1;
- /* initialize CRC */
+ /* initialize CRC */
- memset(CRC, 1, sizeof(CRC));
+ memset(CRC, 1, sizeof(CRC));
- /* loop through address bits */
+ /* loop through address bits */
- for (byte = 0; byte < 6; byte++)
- for (i = 0; i < 8; i++)
- UpdateCRC(CRC, (address[byte] >> i) & 1);
+ for (byte = 0; byte < 6; byte++)
+ for (i = 0; i < 8; i++)
+ UpdateCRC(CRC, (address[byte] >> i) & 1);
- /* hashcode is the 6 least significant bits of the CRC */
+ /* hashcode is the 6 least significant bits of the CRC */
- hashcode = 0;
- for (i = 0; i < 6; i++)
- hashcode = (hashcode << 1) + CRC[i];
- return hashcode;
+ hashcode = 0;
+ for (i = 0; i < 6; i++)
+ hashcode = (hashcode << 1) + CRC[i];
+ return hashcode;
}
/* feed ready-built initialization block into LANCE */
static void InitLANCE(struct net_device *dev)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
-
- /* build up descriptors. */
+ skmca_priv *priv = (skmca_priv *) dev->priv;
- InitDscrs(dev);
+ /* build up descriptors. */
- /* next RX descriptor to be read is the first one. Since the LANCE
- will start from the beginning after initialization, we have to
- reset out pointers too. */
+ InitDscrs(dev);
- priv->nextrx = 0;
+ /* next RX descriptor to be read is the first one. Since the LANCE
+ will start from the beginning after initialization, we have to
+ reset out pointers too. */
- /* no TX descriptors active */
+ priv->nextrx = 0;
- priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
+ /* no TX descriptors active */
- /* set up the LANCE bus control register - constant for SKnet boards */
+ priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
- SetLANCE(dev, LANCE_CSR3, CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
+ /* set up the LANCE bus control register - constant for SKnet boards */
- /* write address of initialization block into LANCE */
+ SetLANCE(dev, LANCE_CSR3,
+ CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
- SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
- SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
+ /* write address of initialization block into LANCE */
- /* we don't get ready until the LANCE has read the init block */
+ SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
+ SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
- dev->tbusy = 1;
+ /* we don't get ready until the LANCE has read the init block */
- /* let LANCE read the initialization block. LANCE is ready
- when we receive the corresponding interrupt. */
+ netif_stop_queue(dev);
+
+ /* let LANCE read the initialization block. LANCE is ready
+ when we receive the corresponding interrupt. */
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
+ SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
}
/* stop the LANCE so we can reinitialize it */
static void StopLANCE(struct net_device *dev)
{
- /* can't take frames any more */
+ /* can't take frames any more */
- dev->tbusy = 1;
+ netif_stop_queue(dev);
+
+ /* disable interrupts, stop it */
- /* disable interrupts, stop it */
-
- SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
+ SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
}
/* initialize card and LANCE for proper operation */
static void InitBoard(struct net_device *dev)
{
- LANCE_InitBlock block;
+ LANCE_InitBlock block;
- /* Lay out the shared RAM - first we create the init block for the LANCE.
- We do not overwrite it later because we need it again when we switch
- promiscous mode on/off. */
+ /* Lay out the shared RAM - first we create the init block for the LANCE.
+ We do not overwrite it later because we need it again when we switch
+ promiscous mode on/off. */
- block.Mode = 0;
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- memcpy(block.PAdr, dev->dev_addr, 6);
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
- block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
+ block.Mode = 0;
+ if (dev->flags & IFF_PROMISC)
+ block.Mode |= LANCE_INIT_PROM;
+ memcpy(block.PAdr, dev->dev_addr, 6);
+ memset(block.LAdrF, 0, sizeof(block.LAdrF));
+ block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
+ block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
- isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+ isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block,
+ sizeof(block));
- /* initialize LANCE. Implicitly sets up other structures in RAM. */
+ /* initialize LANCE. Implicitly sets up other structures in RAM. */
- InitLANCE(dev);
+ InitLANCE(dev);
}
/* deinitialize card and LANCE */
static void DeinitBoard(struct net_device *dev)
{
- /* stop LANCE */
+ /* stop LANCE */
- StopLANCE(dev);
+ StopLANCE(dev);
- /* reset board */
+ /* reset board */
- ResetBoard(dev);
+ ResetBoard(dev);
}
/* ------------------------------------------------------------------------
@@ -477,210 +491,201 @@ static void DeinitBoard(struct net_device *dev)
static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
{
- /* now we're ready to transmit */
-
- dev->tbusy = 0;
+ /* now we're ready to transmit */
- /* reset IDON bit, start LANCE */
+ netif_wake_queue(dev);
+
+ /* reset IDON bit, start LANCE */
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
- return GetLANCE(dev, LANCE_CSR0);
+ SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
+ return GetLANCE(dev, LANCE_CSR0);
}
/* receive interrupt */
static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
- LANCE_RxDescr descr;
- unsigned int descraddr;
+ skmca_priv *priv = (skmca_priv *) dev->priv;
+ LANCE_RxDescr descr;
+ unsigned int descraddr;
+
+ /* did we loose blocks due to a FIFO overrun ? */
- /* did we loose blocks due to a FIFO overrun ? */
+ if (oldcsr0 & CSR0_MISS)
+ priv->stat.rx_fifo_errors++;
- if (oldcsr0 & CSR0_MISS)
- priv->stat.rx_fifo_errors++;
+ /* run through queue until we reach a descriptor we do not own */
- /* run through queue until we reach a descriptor we do not own */
+ descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
+ while (1) {
+ /* read descriptor */
+ isa_memcpy_fromio(&descr, dev->mem_start + descraddr,
+ sizeof(LANCE_RxDescr));
- descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
- while (1)
- {
- /* read descriptor */
- isa_memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_RxDescr));
-
- /* if we reach a descriptor we do not own, we're done */
- if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
- break;
+ /* if we reach a descriptor we do not own, we're done */
+ if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
+ break;
#ifdef DEBUG
- PrTime(); printk("Receive packet on descr %d len %d\n", priv->nextrx, descr.Len);
+ PrTime();
+ printk("Receive packet on descr %d len %d\n", priv->nextrx,
+ descr.Len);
#endif
- /* erroneous packet ? */
- if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0)
- {
- priv->stat.rx_errors++;
- if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_crc_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_frame_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
- priv->stat.rx_fifo_errors++;
- }
-
- /* good packet ? */
- else
- {
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(descr.Len + 2);
- if (skb == NULL)
- priv->stat.rx_dropped++;
- else
- {
- isa_memcpy_fromio(skb_put(skb, descr.Len),
- dev->mem_start + descr.LowAddr, descr.Len);
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- priv->stat.rx_packets++;
-#if LINUX_VERSION_CODE >= 0x020119 /* byte counters for >= 2.1.25 */
- priv->stat.rx_bytes += descr.Len;
+ /* erroneous packet ? */
+ if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) {
+ priv->stat.rx_errors++;
+ if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+ priv->stat.rx_crc_errors++;
+ else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+ priv->stat.rx_frame_errors++;
+ else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
+ priv->stat.rx_fifo_errors++;
+ }
+
+ /* good packet ? */
+ else {
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(descr.Len + 2);
+ if (skb == NULL)
+ priv->stat.rx_dropped++;
+ else {
+ isa_memcpy_fromio(skb_put(skb, descr.Len),
+ dev->mem_start +
+ descr.LowAddr,
+ descr.Len);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_NONE;
+ priv->stat.rx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119 /* byte counters for >= 2.1.25 */
+ priv->stat.rx_bytes += descr.Len;
#endif
- netif_rx(skb);
- }
- }
-
- /* give descriptor back to LANCE */
- descr.Len = 0;
- descr.Flags |= RXDSCR_FLAGS_OWN;
-
- /* update descriptor in shared RAM */
- isa_memcpy_toio(dev->mem_start + descraddr, &descr, sizeof(LANCE_RxDescr));
-
- /* go to next descriptor */
- priv->nextrx++; descraddr += sizeof(LANCE_RxDescr);
- if (priv->nextrx >= RXCOUNT)
- {
- priv->nextrx = 0;
- descraddr = RAM_RXBASE;
- }
- }
-
- /* reset RINT bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
- return GetLANCE(dev, LANCE_CSR0);
+ netif_rx(skb);
+ }
+ }
+
+ /* give descriptor back to LANCE */
+ descr.Len = 0;
+ descr.Flags |= RXDSCR_FLAGS_OWN;
+
+ /* update descriptor in shared RAM */
+ isa_memcpy_toio(dev->mem_start + descraddr, &descr,
+ sizeof(LANCE_RxDescr));
+
+ /* go to next descriptor */
+ priv->nextrx++;
+ descraddr += sizeof(LANCE_RxDescr);
+ if (priv->nextrx >= RXCOUNT) {
+ priv->nextrx = 0;
+ descraddr = RAM_RXBASE;
+ }
+ }
+
+ /* reset RINT bit */
+
+ SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
+ return GetLANCE(dev, LANCE_CSR0);
}
/* transmit interrupt */
static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
- LANCE_TxDescr descr;
- unsigned int descraddr;
+ skmca_priv *priv = (skmca_priv *) dev->priv;
+ LANCE_TxDescr descr;
+ unsigned int descraddr;
- /* check descriptors at most until no busy one is left */
+ /* check descriptors at most until no busy one is left */
- descraddr = RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
- while (priv->txbusy > 0)
- {
- /* read descriptor */
- isa_memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_TxDescr));
+ descraddr =
+ RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
+ while (priv->txbusy > 0) {
+ /* read descriptor */
+ isa_memcpy_fromio(&descr, dev->mem_start + descraddr,
+ sizeof(LANCE_TxDescr));
- /* if the LANCE still owns this one, we've worked out all sent packets */
- if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
- break;
+ /* if the LANCE still owns this one, we've worked out all sent packets */
+ if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
+ break;
#ifdef DEBUG
- PrTime(); printk("Send packet done on descr %d\n", priv->nexttxdone);
+ PrTime();
+ printk("Send packet done on descr %d\n", priv->nexttxdone);
#endif
- /* update statistics */
- if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0)
- {
- priv->stat.tx_packets++;
-#if LINUX_VERSION_CODE >= 0x020119 /* byte counters for >= 2.1.25 */
- priv->stat.tx_bytes++;
+ /* update statistics */
+ if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) {
+ priv->stat.tx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119 /* byte counters for >= 2.1.25 */
+ priv->stat.tx_bytes++;
#endif
- }
- else
- {
- priv->stat.tx_errors++;
- if ((descr.Status & TXDSCR_STATUS_UFLO) != 0)
- {
- priv->stat.tx_fifo_errors++;
- InitLANCE(dev);
- }
- else if ((descr.Status & TXDSCR_STATUS_LCOL) != 0)
- priv->stat.tx_window_errors++;
- else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
- priv->stat.tx_carrier_errors++;
- else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
- priv->stat.tx_aborted_errors++;
- }
-
- /* go to next descriptor */
- priv->nexttxdone++;
- descraddr += sizeof(LANCE_TxDescr);
- if (priv->nexttxdone >= TXCOUNT)
- {
- priv->nexttxdone = 0;
- descraddr = RAM_TXBASE;
- }
- priv->txbusy--;
- }
-
- /* reset TX interrupt bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
- oldcsr0 = GetLANCE(dev, LANCE_CSR0);
-
- /* at least one descriptor is freed. Therefore we can accept
- a new one */
-
- dev->tbusy = 0;
-
- /* inform upper layers we're in business again */
-
- mark_bh(NET_BH);
-
- return oldcsr0;
+ } else {
+ priv->stat.tx_errors++;
+ if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) {
+ priv->stat.tx_fifo_errors++;
+ InitLANCE(dev);
+ }
+ else
+ if ((descr.Status & TXDSCR_STATUS_LCOL) !=
+ 0) priv->stat.tx_window_errors++;
+ else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
+ priv->stat.tx_carrier_errors++;
+ else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
+ priv->stat.tx_aborted_errors++;
+ }
+
+ /* go to next descriptor */
+ priv->nexttxdone++;
+ descraddr += sizeof(LANCE_TxDescr);
+ if (priv->nexttxdone >= TXCOUNT) {
+ priv->nexttxdone = 0;
+ descraddr = RAM_TXBASE;
+ }
+ priv->txbusy--;
+ }
+
+ /* reset TX interrupt bit */
+
+ SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
+ oldcsr0 = GetLANCE(dev, LANCE_CSR0);
+
+ /* at least one descriptor is freed. Therefore we can accept
+ a new one */
+
+ netif_wake_queue(dev);
+
+ return oldcsr0;
}
/* general interrupt entry */
static void irq_handler(int irq, void *device, struct pt_regs *regs)
{
- struct net_device *dev = (struct net_device*) device;
- u16 csr0val;
-
- /* read CSR0 to get interrupt cause */
-
- csr0val = GetLANCE(dev, LANCE_CSR0);
+ struct net_device *dev = (struct net_device *) device;
+ u16 csr0val;
- /* in case we're not meant... */
+ /* read CSR0 to get interrupt cause */
- if ((csr0val & CSR0_INTR) == 0)
- return;
+ csr0val = GetLANCE(dev, LANCE_CSR0);
- dev->interrupt = 1;
+ /* in case we're not meant... */
- /* loop through the interrupt bits until everything is clear */
+ if ((csr0val & CSR0_INTR) == 0)
+ return;
- do
- {
- if ((csr0val & CSR0_IDON) != 0)
- csr0val = irqstart_handler(dev, csr0val);
- if ((csr0val & CSR0_RINT) != 0)
- csr0val = irqrx_handler(dev, csr0val);
- if ((csr0val & CSR0_TINT) != 0)
- csr0val = irqtx_handler(dev, csr0val);
- }
- while ((csr0val & CSR0_INTR) != 0);
+ /* loop through the interrupt bits until everything is clear */
- dev->interrupt = 0;
+ do {
+ if ((csr0val & CSR0_IDON) != 0)
+ csr0val = irqstart_handler(dev, csr0val);
+ if ((csr0val & CSR0_RINT) != 0)
+ csr0val = irqrx_handler(dev, csr0val);
+ if ((csr0val & CSR0_TINT) != 0)
+ csr0val = irqtx_handler(dev, csr0val);
+ }
+ while ((csr0val & CSR0_INTR) != 0);
}
/* ------------------------------------------------------------------------
@@ -691,184 +696,177 @@ static void irq_handler(int irq, void *device, struct pt_regs *regs)
static int skmca_getinfo(char *buf, int slot, void *d)
{
- int len = 0, i;
- struct net_device *dev = (struct net_device*) d;
- skmca_priv *priv;
-
- /* can't say anything about an uninitialized device... */
-
- if (dev == NULL)
- return len;
- if (dev->priv == NULL)
- return len;
- priv = (skmca_priv*) dev->priv;
-
- /* print info */
-
- len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
- len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
- dev->mem_end - 1);
- len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
- len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "MAC address:");
- for (i = 0; i < 6; i ++ )
- len += sprintf( buf+len, " %02x", dev->dev_addr[i] );
- buf[len++] = '\n';
- buf[len] = 0;
-
- return len;
+ int len = 0, i;
+ struct net_device *dev = (struct net_device *) d;
+ skmca_priv *priv;
+
+ /* can't say anything about an uninitialized device... */
+
+ if (dev == NULL)
+ return len;
+ if (dev->priv == NULL)
+ return len;
+ priv = (skmca_priv *) dev->priv;
+
+ /* print info */
+
+ len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
+ len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
+ dev->mem_end - 1);
+ len +=
+ sprintf(buf + len, "Transceiver: %s\n",
+ MediaNames[priv->medium]);
+ len += sprintf(buf + len, "Device: %s\n", dev->name);
+ len += sprintf(buf + len, "MAC address:");
+ for (i = 0; i < 6; i++)
+ len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
+ buf[len++] = '\n';
+ buf[len] = 0;
+
+ return len;
}
/* open driver. Means also initialization and start of LANCE */
static int skmca_open(struct net_device *dev)
{
- int result;
- skmca_priv *priv = (skmca_priv*) dev->priv;
-
- /* register resources - only necessary for IRQ */
- result = request_irq(priv->realirq, irq_handler, SA_SHIRQ | SA_SAMPLE_RANDOM,
- "sk_mca", dev);
- if (result != 0)
- {
- printk("%s: failed to register irq %d\n", dev->name, dev->irq);
- return result;
- }
- dev->irq = priv->realirq;
-
- /* set up the card and LANCE */
- InitBoard(dev);
+ int result;
+ skmca_priv *priv = (skmca_priv *) dev->priv;
+
+ /* register resources - only necessary for IRQ */
+ result =
+ request_irq(priv->realirq, irq_handler,
+ SA_SHIRQ | SA_SAMPLE_RANDOM, "sk_mca", dev);
+ if (result != 0) {
+ printk("%s: failed to register irq %d\n", dev->name,
+ dev->irq);
+ return result;
+ }
+ dev->irq = priv->realirq;
+
+ /* set up the card and LANCE */
+ InitBoard(dev);
#ifdef MODULE
- MOD_INC_USE_COUNT;
+ MOD_INC_USE_COUNT;
#endif
- return 0;
+ return 0;
}
/* close driver. Shut down board and free allocated resources */
static int skmca_close(struct net_device *dev)
{
- /* turn off board */
- DeinitBoard(dev);
+ /* turn off board */
+ DeinitBoard(dev);
- /* release resources */
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- dev->irq = 0;
+ /* release resources */
+ if (dev->irq != 0)
+ free_irq(dev->irq, dev);
+ dev->irq = 0;
#ifdef MODULE
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
#endif
- return 0;
+ return 0;
}
/* transmit a block. */
static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
- LANCE_TxDescr descr;
- unsigned int address;
- int tmplen, retval = 0;
- unsigned long flags;
-
- /* if we get called with a NULL descriptor, the Ethernet layer thinks
- our card is stuck an we should reset it. We'll do this completely: */
-
- if (skb == NULL)
- {
- DeinitBoard(dev);
- InitBoard(dev);
- return 0; /* don't try to free the block here ;-) */
- }
-
- /* is there space in the Tx queue ? If no, the upper layer gave us a
- packet in spite of us not being ready and is really in trouble.
- We'll do the dropping for him: */
- if (priv->txbusy >= TXCOUNT)
- {
- priv->stat.tx_dropped++;
- retval = -EIO;
- goto tx_done;
- }
-
- /* get TX descriptor */
- address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
- isa_memcpy_fromio(&descr, dev->mem_start + address, sizeof(LANCE_TxDescr));
-
- /* enter packet length as 2s complement - assure minimum length */
- tmplen = skb->len;
- if (tmplen < 60)
- tmplen = 60;
- descr.Len = 65536 - tmplen;
-
- /* copy filler into RAM - in case we're filling up...
- we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger... */
- if (tmplen > skb->len)
- {
- char *fill = "NetBSD is a nice OS too! ";
- unsigned int destoffs = 0, l = strlen(fill);
-
- while (destoffs < tmplen)
- {
- isa_memcpy_toio(dev->mem_start + descr.LowAddr + destoffs, fill, l);
- destoffs += l;
- }
- }
-
- /* do the real data copying */
- isa_memcpy_toio(dev->mem_start + descr.LowAddr, skb->data, skb->len);
-
- /* hand descriptor over to LANCE - this is the first and last chunk */
- descr.Flags = TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
+ skmca_priv *priv = (skmca_priv *) dev->priv;
+ LANCE_TxDescr descr;
+ unsigned int address;
+ int tmplen, retval = 0;
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ /* is there space in the Tx queue ? If no, the upper layer gave us a
+ packet in spite of us not being ready and is really in trouble.
+ We'll do the dropping for him: */
+ if (priv->txbusy >= TXCOUNT) {
+ priv->stat.tx_dropped++;
+ retval = -EIO;
+ goto tx_done;
+ }
+
+ /* get TX descriptor */
+ address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
+ isa_memcpy_fromio(&descr, dev->mem_start + address,
+ sizeof(LANCE_TxDescr));
+
+ /* enter packet length as 2s complement - assure minimum length */
+ tmplen = skb->len;
+ if (tmplen < 60)
+ tmplen = 60;
+ descr.Len = 65536 - tmplen;
+
+ /* copy filler into RAM - in case we're filling up...
+ we're filling a bit more than necessary, but that doesn't harm
+ since the buffer is far larger... */
+ if (tmplen > skb->len) {
+ char *fill = "NetBSD is a nice OS too! ";
+ unsigned int destoffs = 0, l = strlen(fill);
+
+ while (destoffs < tmplen) {
+ isa_memcpy_toio(dev->mem_start + descr.LowAddr +
+ destoffs, fill, l);
+ destoffs += l;
+ }
+ }
+
+ /* do the real data copying */
+ isa_memcpy_toio(dev->mem_start + descr.LowAddr, skb->data,
+ skb->len);
+
+ /* hand descriptor over to LANCE - this is the first and last chunk */
+ descr.Flags =
+ TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
#ifdef DEBUG
- PrTime(); printk("Send packet on descr %d len %d\n", priv->nexttxput, skb->len);
+ PrTime();
+ printk("Send packet on descr %d len %d\n", priv->nexttxput,
+ skb->len);
#endif
- /* one more descriptor busy */
- save_flags(flags);
- cli();
- priv->nexttxput++;
- if (priv->nexttxput >= TXCOUNT)
- priv->nexttxput = 0;
- priv->txbusy++;
- dev->tbusy = (priv->txbusy >= TXCOUNT);
+ /* one more descriptor busy */
+ save_flags(flags);
+ cli();
+ priv->nexttxput++;
+ if (priv->nexttxput >= TXCOUNT)
+ priv->nexttxput = 0;
+ priv->txbusy++;
+ if (priv->txbusy < TXCOUNT)
+ netif_wake_queue(dev);
- /* write descriptor back to RAM */
- isa_memcpy_toio(dev->mem_start + address, &descr, sizeof(LANCE_TxDescr));
+ /* write descriptor back to RAM */
+ isa_memcpy_toio(dev->mem_start + address, &descr,
+ sizeof(LANCE_TxDescr));
- /* if no descriptors were active, give the LANCE a hint to read it
- immediately */
+ /* if no descriptors were active, give the LANCE a hint to read it
+ immediately */
- if (priv->txbusy == 0)
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
+ if (priv->txbusy == 0)
+ SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
- restore_flags(flags);
+ restore_flags(flags);
tx_done:
-
- /* When did that change exactly ? */
-
-#if LINUX_VERSION_CODE >= 0x020200
- dev_kfree_skb(skb);
-#else
- dev_kfree_skb(skb, FREE_WRITE);
-#endif
- return retval;
+ /* When did that change exactly ? */
+ dev_kfree_skb(skb);
+ return retval;
}
/* return pointer to Ethernet statistics */
static struct enet_statistics *skmca_stats(struct net_device *dev)
{
- skmca_priv *priv = (skmca_priv*) dev->priv;
-
- return &(priv->stat);
+ skmca_priv *priv = (skmca_priv *) dev->priv;
+ return &(priv->stat);
}
/* we don't support runtime reconfiguration, since an MCA card can
@@ -876,7 +874,7 @@ static struct enet_statistics *skmca_stats(struct net_device *dev)
static int skmca_config(struct net_device *dev, struct ifmap *map)
{
- return 0;
+ return 0;
}
/* switch receiver mode. We use the LANCE's multicast filter to prefilter
@@ -884,39 +882,38 @@ static int skmca_config(struct net_device *dev, struct ifmap *map)
static void skmca_set_multicast_list(struct net_device *dev)
{
- LANCE_InitBlock block;
-
- /* first stop the LANCE... */
- StopLANCE(dev);
-
- /* ...then modify the initialization block... */
- isa_memcpy_fromio(&block, dev->mem_start + RAM_INITBASE, sizeof(block));
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- else
- block.Mode &= ~LANCE_INIT_PROM;
-
- if (dev->flags & IFF_ALLMULTI) /* get all multicasts */
- {
- memset(block.LAdrF, 8, 0xff);
- }
- else /* get selected/no multicasts */
- {
- struct dev_mc_list *mptr;
- int code;
-
- memset(block.LAdrF, 8, 0x00);
- for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next)
- {
- code = GetHash(mptr->dmi_addr);
- block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
- }
- }
-
- isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
-
- /* ...then reinit LANCE with the correct flags */
- InitLANCE(dev);
+ LANCE_InitBlock block;
+
+ /* first stop the LANCE... */
+ StopLANCE(dev);
+
+ /* ...then modify the initialization block... */
+ isa_memcpy_fromio(&block, dev->mem_start + RAM_INITBASE,
+ sizeof(block));
+ if (dev->flags & IFF_PROMISC)
+ block.Mode |= LANCE_INIT_PROM;
+ else
+ block.Mode &= ~LANCE_INIT_PROM;
+
+ if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */
+ memset(block.LAdrF, 8, 0xff);
+ } else { /* get selected/no multicasts */
+
+ struct dev_mc_list *mptr;
+ int code;
+
+ memset(block.LAdrF, 8, 0x00);
+ for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) {
+ code = GetHash(mptr->dmi_addr);
+ block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
+ }
+ }
+
+ isa_memcpy_toio(dev->mem_start + RAM_INITBASE, &block,
+ sizeof(block));
+
+ /* ...then reinit LANCE with the correct flags */
+ InitLANCE(dev);
}
/* ------------------------------------------------------------------------
@@ -924,149 +921,143 @@ static void skmca_set_multicast_list(struct net_device *dev)
* ------------------------------------------------------------------------ */
#ifdef MODULE
-static int startslot; /* counts through slots when probing multiple devices */
+static int startslot; /* counts through slots when probing multiple devices */
#else
-#define startslot 0 /* otherwise a dummy, since there is only eth0 in-kern*/
+#define startslot 0 /* otherwise a dummy, since there is only eth0 in-kern */
#endif
int skmca_probe(struct net_device *dev)
{
- int force_detect = 0;
- int junior, slot, i;
- int base = 0, irq = 0;
- skmca_priv *priv;
- skmca_medium medium;
+ int force_detect = 0;
+ int junior, slot, i;
+ int base = 0, irq = 0;
+ skmca_priv *priv;
+ skmca_medium medium;
- /* can't work without an MCA bus ;-) */
-
- if (MCA_bus == 0)
- return ENODEV;
-
- /* start address of 1 --> forced detection */
-
- if (dev->mem_start == 1)
- force_detect = 1;
+ /* can't work without an MCA bus ;-) */
- /* search through slots */
-
- if (dev != NULL)
- {
- base = dev->mem_start;
- irq = dev->irq;
- }
- slot = dofind(&junior, startslot);
+ if (MCA_bus == 0)
+ return ENODEV;
+
+ /* start address of 1 --> forced detection */
+
+ if (dev->mem_start == 1)
+ force_detect = 1;
+
+ /* search through slots */
+
+ if (dev != NULL) {
+ base = dev->mem_start;
+ irq = dev->irq;
+ }
+ slot = dofind(&junior, startslot);
- while (slot != -1)
- {
- /* deduce card addresses */
+ while (slot != -1) {
+ /* deduce card addresses */
- getaddrs(slot, junior, &base, &irq, &medium);
+ getaddrs(slot, junior, &base, &irq, &medium);
#if LINUX_VERSION_CODE >= 0x020200
- /* slot already in use ? */
+ /* slot already in use ? */
- if (mca_is_adapter_used(slot))
- {
- slot = dofind(&junior, slot + 1);
- continue;
- }
+ if (mca_is_adapter_used(slot)) {
+ slot = dofind(&junior, slot + 1);
+ continue;
+ }
#endif
- /* were we looking for something different ? */
-
- if ((dev->irq != 0) || (dev->mem_start != 0))
- {
- if ((dev->irq != 0) && (dev->irq != irq))
- {
- slot = dofind(&junior, slot + 1);
- continue;
- }
- if ((dev->mem_start != 0) && (dev->mem_start != base))
- {
- slot = dofind(&junior, slot + 1);
- continue;
- }
- }
-
- /* found something that matches */
-
- break;
- }
+ /* were we looking for something different ? */
- /* nothing found ? */
-
- if (slot == -1)
- return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV;
-
- /* make procfs entries */
-
- if (junior)
- mca_set_adapter_name(slot, "SKNET junior MC2 Ethernet Adapter");
- else
- mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
- mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
+ if ((dev->irq != 0) || (dev->mem_start != 0)) {
+ if ((dev->irq != 0) && (dev->irq != irq)) {
+ slot = dofind(&junior, slot + 1);
+ continue;
+ }
+ if ((dev->mem_start != 0)
+ && (dev->mem_start != base)) {
+ slot = dofind(&junior, slot + 1);
+ continue;
+ }
+ }
+
+ /* found something that matches */
+
+ break;
+ }
+
+ /* nothing found ? */
+
+ if (slot == -1)
+ return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV;
+
+ /* make procfs entries */
+
+ if (junior)
+ mca_set_adapter_name(slot,
+ "SKNET junior MC2 Ethernet Adapter");
+ else
+ mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
+ mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
#if LINUX_VERSION_CODE >= 0x020200
- mca_mark_as_used(slot);
+ mca_mark_as_used(slot);
#endif
-
- /* announce success */
- printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
- junior ? "Junior MC2" : "MC2+", slot + 1);
-
- /* allocate structure */
- priv = dev->priv = (skmca_priv*) kmalloc(sizeof(skmca_priv), GFP_KERNEL);
- priv->slot = slot;
- priv->macbase = base + 0x3fc0;
- priv->ioregaddr = base + 0x3ff0;
- priv->ctrladdr = base + 0x3ff2;
- priv->cmdaddr = base + 0x3ff3;
- priv->realirq = irq;
- priv->medium = medium;
- memset(&(priv->stat), 0, sizeof(struct enet_statistics));
-
- /* set base + irq for this device (irq not allocated so far) */
- dev->irq = 0;
- dev->mem_start = base;
- dev->mem_end = base + 0x4000;
-
- /* set methods */
- dev->open = skmca_open;
- dev->stop = skmca_close;
- dev->set_config = skmca_config;
- dev->hard_start_xmit = skmca_tx;
- dev->do_ioctl = NULL;
- dev->get_stats = skmca_stats;
- dev->set_multicast_list = skmca_set_multicast_list;
- dev->flags |= IFF_MULTICAST;
-
- /* generic setup */
- ether_setup(dev);
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 0;
-
- /* copy out MAC address */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(priv->macbase + (i << 1));
-
- /* print config */
- printk("%s: IRQ %d, memory %#lx-%#lx, "
- "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
- dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
- /* reset board */
-
- ResetBoard(dev);
+
+ /* announce success */
+ printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
+ junior ? "Junior MC2" : "MC2+", slot + 1);
+
+ /* allocate structure */
+ priv = dev->priv =
+ (skmca_priv *) kmalloc(sizeof(skmca_priv), GFP_KERNEL);
+ priv->slot = slot;
+ priv->macbase = base + 0x3fc0;
+ priv->ioregaddr = base + 0x3ff0;
+ priv->ctrladdr = base + 0x3ff2;
+ priv->cmdaddr = base + 0x3ff3;
+ priv->realirq = irq;
+ priv->medium = medium;
+ memset(&(priv->stat), 0, sizeof(struct enet_statistics));
+
+ /* set base + irq for this device (irq not allocated so far) */
+ dev->irq = 0;
+ dev->mem_start = base;
+ dev->mem_end = base + 0x4000;
+
+ /* set methods */
+ dev->open = skmca_open;
+ dev->stop = skmca_close;
+ dev->set_config = skmca_config;
+ dev->hard_start_xmit = skmca_tx;
+ dev->do_ioctl = NULL;
+ dev->get_stats = skmca_stats;
+ dev->set_multicast_list = skmca_set_multicast_list;
+ dev->flags |= IFF_MULTICAST;
+
+ /* generic setup */
+ ether_setup(dev);
+
+ /* copy out MAC address */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = readb(priv->macbase + (i << 1));
+
+ /* print config */
+ printk("%s: IRQ %d, memory %#lx-%#lx, "
+ "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
+ dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
+
+ /* reset board */
+
+ ResetBoard(dev);
#ifdef MODULE
- startslot = slot + 1;
+ startslot = slot + 1;
#endif
- return 0;
+ return 0;
}
/* ------------------------------------------------------------------------
@@ -1079,61 +1070,58 @@ int skmca_probe(struct net_device *dev)
static char NameSpace[8 * DEVMAX];
static struct net_device moddevs[DEVMAX] =
- {{NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
- {NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
- {NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
- {NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
- {NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}};
+ { {NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+{NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}
+};
-int irq=0;
-int io=0;
+int irq = 0;
+int io = 0;
int init_module(void)
{
- int z, res;
-
- startslot = 0;
- for (z = 0; z < DEVMAX; z++)
- {
- strcpy(moddevs[z].name, " ");
- res = register_netdev(moddevs + z);
- if (res != 0)
- return (z > 0) ? 0 : -EIO;
- }
-
- return 0;
+ int z, res;
+
+ startslot = 0;
+ for (z = 0; z < DEVMAX; z++) {
+ strcpy(moddevs[z].name, " ");
+ res = register_netdev(moddevs + z);
+ if (res != 0)
+ return (z > 0) ? 0 : -EIO;
+ }
+
+ return 0;
}
void cleanup_module(void)
{
- struct net_device *dev;
- skmca_priv *priv;
- int z;
-
- if (MOD_IN_USE)
- {
- printk("cannot unload, module in use\n");
- return;
- }
-
- for (z = 0; z < DEVMAX; z++)
- {
- dev = moddevs + z;
- if (dev->priv != NULL)
- {
- priv = (skmca_priv*) dev->priv;
- DeinitBoard(dev);
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- dev->irq = 0;
- unregister_netdev(dev);
+ struct net_device *dev;
+ skmca_priv *priv;
+ int z;
+
+ if (MOD_IN_USE) {
+ printk("cannot unload, module in use\n");
+ return;
+ }
+
+ for (z = 0; z < DEVMAX; z++) {
+ dev = moddevs + z;
+ if (dev->priv != NULL) {
+ priv = (skmca_priv *) dev->priv;
+ DeinitBoard(dev);
+ if (dev->irq != 0)
+ free_irq(dev->irq, dev);
+ dev->irq = 0;
+ unregister_netdev(dev);
#if LINUX_VERSION_CODE >= 0x020200
- mca_mark_as_unused(priv->slot);
+ mca_mark_as_unused(priv->slot);
#endif
- mca_set_adapter_procfn(priv->slot, NULL, NULL);
- kfree_s(dev->priv, sizeof(skmca_priv));
- dev->priv = NULL;
- }
- }
+ mca_set_adapter_procfn(priv->slot, NULL, NULL);
+ kfree_s(dev->priv, sizeof(skmca_priv));
+ dev->priv = NULL;
+ }
+ }
}
-#endif /* MODULE */
+#endif /* MODULE */
diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c
index 21628c1fc..776b7a6a6 100644
--- a/drivers/net/skeleton.c
+++ b/drivers/net/skeleton.c
@@ -416,7 +416,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&np->lock);
add_to_tx_ring(np, skb, length);
- dev->trans_start = jiffied;
+ dev->trans_start = jiffies;
/* If we just used up the very last entry in the
* TX ring on this device, tell the queueing
@@ -482,8 +482,7 @@ void net_tx(struct net_device *dev)
* condition, and space has now been made available,
* wake up the queue.
*/
- if (test_bit(LINK_STATE_XOFF, &dev->state) &&
- ! tx_full(dev))
+ if (netif_queue_stopped(dev) && ! tx_full(dev))
netif_wake_queue(dev);
spin_unlock(&np->lock);
diff --git a/drivers/net/skfp/.cvsignore b/drivers/net/skfp/.cvsignore
new file mode 100644
index 000000000..f7cf9ab27
--- /dev/null
+++ b/drivers/net/skfp/.cvsignore
@@ -0,0 +1,10 @@
+! RCS SCCS CVS CVS.adm
+RCSLOG cvslog.*
+tags TAGS
+.make.state .nse_depinfo
+*~ #* .#* ,* _$* *$
+*.old *.bak *.BAK *.orig *.rej .del-*
+*.a *.olb *.o *.obj *.so *.exe
+*.Z *.elc *.ln
+.depend
+.*.flags
diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile
new file mode 100644
index 000000000..82aa26e4c
--- /dev/null
+++ b/drivers/net/skfp/Makefile
@@ -0,0 +1,39 @@
+#
+# Makefile for the SysKonnect FDDI PCI adapter driver
+#
+
+ifeq ($(CONFIG_SKFP),y)
+ O_TARGET := skfp.o
+ O_OBJS = skfddi.o hwmtm.o fplustm.o smt.o cfm.o \
+ ecm.o pcmplc.o pmf.o queue.o rmt.o \
+ smtdef.o smtinit.o smttimer.o srf.o lnkstat.o \
+ smtparse.o hwt.o drvfbi.o ess.o
+else
+ ifeq ($(CONFIG_SKFP),m)
+ MOD_LIST_NAME := SKFP_MODULES
+ M_OBJS := skfp.o
+ O_TARGET := skfp.o
+ O_OBJS = skfddi.o hwmtm.o fplustm.o smt.o cfm.o \
+ ecm.o pcmplc.o pmf.o queue.o rmt.o \
+ smtdef.o smtinit.o smttimer.o srf.o lnkstat.o \
+ smtparse.o hwt.o drvfbi.o ess.o
+ endif
+endif
+
+# NOTE:
+# Compiling this driver produces some warnings (and some more are
+# switched off below), but I did not fix this, because the Hardware
+# Module source (see skfddi.c for details) is used for different
+# drivers, and fixing it for Linux might bring problems on other
+# projects. To keep the source common for all those drivers (and
+# thus simplify fixes to it), please do not clean it up!
+
+EXTRA_CFLAGS += -I. -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes
+
+include $(TOPDIR)/Rules.make
+
+clean:
+ rm -f core *.o *.a *.s
+
+
+
diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c
new file mode 100644
index 000000000..8a49abce7
--- /dev/null
+++ b/drivers/net/skfp/can.c
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef lint
+static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ;
+#endif
+
+/*
+ * canonical bit order
+ */
+const u_char canonical[256] = {
+ 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
+ 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
+ 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
+ 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
+ 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
+ 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
+ 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
+ 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
+ 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
+ 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
+ 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
+ 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
+ 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
+ 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
+ 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
+ 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
+ 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
+ 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
+ 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
+ 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
+ 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
+ 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
+ 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
+ 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
+ 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
+ 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
+ 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
+ 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
+ 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
+ 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
+ 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
+ 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
+} ;
+
+#ifdef MAKE_TABLE
+int byte_reverse(x)
+int x ;
+{
+ int y = 0 ;
+
+ if (x & 0x01)
+ y |= 0x80 ;
+ if (x & 0x02)
+ y |= 0x40 ;
+ if (x & 0x04)
+ y |= 0x20 ;
+ if (x & 0x08)
+ y |= 0x10 ;
+ if (x & 0x10)
+ y |= 0x08 ;
+ if (x & 0x20)
+ y |= 0x04 ;
+ if (x & 0x40)
+ y |= 0x02 ;
+ if (x & 0x80)
+ y |= 0x01 ;
+ return(y) ;
+}
+#endif
diff --git a/drivers/net/skfp/cfm.c b/drivers/net/skfp/cfm.c
new file mode 100644
index 000000000..7a51b765b
--- /dev/null
+++ b/drivers/net/skfp/cfm.c
@@ -0,0 +1,642 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ SMT CFM
+ Configuration Management
+ DAS with single MAC
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * queue_event()
+ *
+ * The following external HW dependant functions are referenced :
+ * config_mux()
+ *
+ * The following HW dependant events are required :
+ * NONE
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)cfm.c 2.18 98/10/06 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG 0x10
+#define GO_STATE(x) (smc->mib.fddiSMTCF_State = (x)|AFLAG)
+#define ACTIONS_DONE() (smc->mib.fddiSMTCF_State &= ~AFLAG)
+#define ACTIONS(x) (x|AFLAG)
+
+#ifdef DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const cfm_states[] = {
+ "SC0_ISOLATED","CF1","CF2","CF3","CF4",
+ "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
+ "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const cfm_events[] = {
+ "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
+} ;
+#endif
+
+/*
+ * map from state to downstream port type
+ */
+static const u_char cf_to_ptype[] = {
+ TNONE,TNONE,TNONE,TNONE,TNONE,
+ TNONE,TB,TB,TS,
+ TA,TB,TS,TB
+} ;
+
+/*
+ * CEM port states
+ */
+#define CEM_PST_DOWN 0
+#define CEM_PST_UP 1
+#define CEM_PST_HOLD 2
+/* define portstate array only for A and B port */
+/* Do this within the smc structure (use in multiple cards) */
+
+/*
+ * all Globals are defined in smc.h
+ * struct s_cfm
+ */
+
+/*
+ * function declarations
+ */
+static void cfm_fsm() ;
+
+/*
+ init CFM state machine
+ clear all CFM vars and flags
+*/
+void cfm_init(smc)
+struct s_smc *smc ;
+{
+ smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
+ smc->r.rm_join = 0 ;
+ smc->r.rm_loop = 0 ;
+ smc->y[PA].scrub = 0 ;
+ smc->y[PB].scrub = 0 ;
+ smc->y[PA].cem_pst = CEM_PST_DOWN ;
+ smc->y[PB].cem_pst = CEM_PST_DOWN ;
+}
+
+/* Some terms conditions used by the selection criteria */
+#define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \
+ smc->y[PB].pc_mode != PM_TREE)
+/* Selection criteria for the ports */
+static void selection_criteria (smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy ;
+{
+
+ switch (phy->mib->fddiPORTMy_Type) {
+ case TA:
+ if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
+ phy->wc_flag = TRUE ;
+ } else {
+ phy->wc_flag = FALSE ;
+ }
+
+ break;
+ case TB:
+ /* take precedence over PA */
+ phy->wc_flag = FALSE ;
+ break;
+ case TS:
+ phy->wc_flag = FALSE ;
+ break;
+ case TM:
+ phy->wc_flag = FALSE ;
+ break;
+ }
+
+}
+
+void all_selection_criteria (smc)
+struct s_smc *smc ;
+{
+ struct s_phy *phy ;
+ int p ;
+
+ for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
+ /* Do the selection criteria */
+ selection_criteria (smc,phy);
+ }
+}
+
+static void cem_priv_state (smc, event)
+struct s_smc *smc ;
+int event ;
+/* State machine for private PORT states: used to optimize dual homing */
+{
+ int np; /* Number of the port */
+ int i;
+
+ /* Do this only in a DAS */
+ if (smc->s.sas != SMT_DAS )
+ return ;
+
+ np = event - CF_JOIN;
+
+ if (np != PA && np != PB) {
+ return ;
+ }
+ /* Change the port state according to the event (portnumber) */
+ if (smc->y[np].cf_join) {
+ smc->y[np].cem_pst = CEM_PST_UP ;
+ } else if (!smc->y[np].wc_flag) {
+ /* set the port to done only if it is not withheld */
+ smc->y[np].cem_pst = CEM_PST_DOWN ;
+ }
+
+ /* Don't set an hold port to down */
+
+ /* Check all ports of restart conditions */
+ for (i = 0 ; i < 2 ; i ++ ) {
+ /* Check all port for PORT is on hold and no withhold is done */
+ if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
+ smc->y[i].cem_pst = CEM_PST_DOWN;
+ queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
+ }
+ if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
+ smc->y[i].cem_pst = CEM_PST_HOLD;
+ queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
+ }
+ if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
+ /*
+ * The port must be restarted when the wc_flag
+ * will be reset. So set the port on hold.
+ */
+ smc->y[i].cem_pst = CEM_PST_HOLD;
+ }
+ }
+ return ;
+}
+
+/*
+ CFM state machine
+ called by dispatcher
+
+ do
+ display state change
+ process event
+ until SM is stable
+*/
+void cfm(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+ int state ; /* remember last state */
+ int cond ;
+ int oldstate ;
+
+ /* We will do the following: */
+ /* - compute the variable WC_Flag for every port (This is where */
+ /* we can extend the requested path checking !!) */
+ /* - do the old (SMT 6.2 like) state machine */
+ /* - do the resulting station states */
+
+ all_selection_criteria (smc);
+
+ /* We will check now whether a state transition is allowed or not */
+ /* - change the portstates */
+ cem_priv_state (smc, event);
+
+ oldstate = smc->mib.fddiSMTCF_State ;
+ do {
+ DB_CFM("CFM : state %s%s",
+ (smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "",
+ cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ;
+ DB_CFM(" event %s\n",cfm_events[event],0) ;
+ state = smc->mib.fddiSMTCF_State ;
+ cfm_fsm(smc,event) ;
+ event = 0 ;
+ } while (state != smc->mib.fddiSMTCF_State) ;
+
+#ifndef SLIM_SMT
+ /*
+ * check peer wrap condition
+ */
+ cond = FALSE ;
+ if ( (smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
+ smc->y[PA].pc_mode == PM_PEER) ||
+ (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
+ smc->y[PB].pc_mode == PM_PEER) ||
+ (smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
+ smc->y[PS].pc_mode == PM_PEER &&
+ smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
+ cond = TRUE ;
+ }
+ if (cond != smc->mib.fddiSMTPeerWrapFlag)
+ smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
+
+#if 0
+ /*
+ * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired
+ * to the primary path.
+ */
+ /*
+ * path change
+ */
+ if (smc->mib.fddiSMTCF_State != oldstate) {
+ smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ;
+ }
+#endif
+#endif /* no SLIM_SMT */
+
+ /*
+ * set MAC port type
+ */
+ smc->mib.m[MAC0].fddiMACDownstreamPORTType =
+ cf_to_ptype[smc->mib.fddiSMTCF_State] ;
+ cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
+}
+
+/*
+ process CFM event
+*/
+/*ARGSUSED1*/
+static void cfm_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+ switch(smc->mib.fddiSMTCF_State) {
+ case ACTIONS(SC0_ISOLATED) :
+ smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+ smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+ smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+ smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+ smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
+ config_mux(smc,MUX_ISOLATE) ; /* configure PHY Mux */
+ smc->r.rm_loop = FALSE ;
+ smc->r.rm_join = FALSE ;
+ queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+ /* Don't do the WC-Flag changing here */
+ ACTIONS_DONE() ;
+ DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+ break;
+ case SC0_ISOLATED :
+ /*SC07*/
+ /*SAS port can be PA or PB ! */
+ if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
+ smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
+ GO_STATE(SC11_C_WRAP_S) ;
+ break ;
+ }
+ /*SC01*/
+ if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
+ !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
+ GO_STATE(SC9_C_WRAP_A) ;
+ break ;
+ }
+ /*SC02*/
+ if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
+ !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
+ GO_STATE(SC10_C_WRAP_B) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(SC9_C_WRAP_A) :
+ smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+ smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+ smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
+ smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+ smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+ config_mux(smc,MUX_WRAPA) ; /* configure PHY mux */
+ if (smc->y[PA].cf_loop) {
+ smc->r.rm_join = FALSE ;
+ smc->r.rm_loop = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+ }
+ if (smc->y[PA].cf_join) {
+ smc->r.rm_loop = FALSE ;
+ smc->r.rm_join = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+ }
+ ACTIONS_DONE() ;
+ DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+ break ;
+ case SC9_C_WRAP_A :
+ /*SC10*/
+ if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
+ !smc->y[PA].cf_loop ) {
+ GO_STATE(SC0_ISOLATED) ;
+ break ;
+ }
+ /*SC12*/
+ else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
+ smc->y[PA].cem_pst == CEM_PST_UP) ||
+ ((smc->y[PB].cf_loop ||
+ (smc->y[PB].cf_join &&
+ smc->y[PB].cem_pst == CEM_PST_UP)) &&
+ (smc->y[PA].pc_mode == PM_TREE ||
+ smc->y[PB].pc_mode == PM_TREE))) {
+ smc->y[PA].scrub = TRUE ;
+ GO_STATE(SC10_C_WRAP_B) ;
+ break ;
+ }
+ /*SC14*/
+ else if (!smc->s.attach_s &&
+ smc->y[PA].cf_join &&
+ smc->y[PA].cem_pst == CEM_PST_UP &&
+ smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
+ smc->y[PB].cem_pst == CEM_PST_UP &&
+ smc->y[PB].pc_mode == PM_PEER) {
+ smc->y[PA].scrub = TRUE ;
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC4_THRU_A) ;
+ break ;
+ }
+ /*SC15*/
+ else if ( smc->s.attach_s &&
+ smc->y[PA].cf_join &&
+ smc->y[PA].cem_pst == CEM_PST_UP &&
+ smc->y[PA].pc_mode == PM_PEER &&
+ smc->y[PB].cf_join &&
+ smc->y[PB].cem_pst == CEM_PST_UP &&
+ smc->y[PB].pc_mode == PM_PEER) {
+ smc->y[PA].scrub = TRUE ;
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC5_THRU_B) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(SC10_C_WRAP_B) :
+ smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+ smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+ smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+ smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
+ smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+ config_mux(smc,MUX_WRAPB) ; /* configure PHY mux */
+ if (smc->y[PB].cf_loop) {
+ smc->r.rm_join = FALSE ;
+ smc->r.rm_loop = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+ }
+ if (smc->y[PB].cf_join) {
+ smc->r.rm_loop = FALSE ;
+ smc->r.rm_join = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+ }
+ ACTIONS_DONE() ;
+ DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+ break ;
+ case SC10_C_WRAP_B :
+ /*SC20*/
+ if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
+ GO_STATE(SC0_ISOLATED) ;
+ break ;
+ }
+ /*SC21*/
+ else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
+ smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC9_C_WRAP_A) ;
+ break ;
+ }
+ /*SC24*/
+ else if (!smc->s.attach_s &&
+ smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
+ smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+ smc->y[PA].scrub = TRUE ;
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC4_THRU_A) ;
+ break ;
+ }
+ /*SC25*/
+ else if ( smc->s.attach_s &&
+ smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
+ smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+ smc->y[PA].scrub = TRUE ;
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC5_THRU_B) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(SC4_THRU_A) :
+ smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
+ smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
+ smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+ smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
+ smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
+ config_mux(smc,MUX_THRUA) ; /* configure PHY mux */
+ smc->r.rm_loop = FALSE ;
+ smc->r.rm_join = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+ ACTIONS_DONE() ;
+ DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+ break ;
+ case SC4_THRU_A :
+ /*SC41*/
+ if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
+ smc->y[PA].scrub = TRUE ;
+ GO_STATE(SC9_C_WRAP_A) ;
+ break ;
+ }
+ /*SC42*/
+ else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC10_C_WRAP_B) ;
+ break ;
+ }
+ /*SC45*/
+ else if (smc->s.attach_s) {
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC5_THRU_B) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(SC5_THRU_B) :
+ smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
+ smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
+ smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
+ smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+ smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
+ config_mux(smc,MUX_THRUB) ; /* configure PHY mux */
+ smc->r.rm_loop = FALSE ;
+ smc->r.rm_join = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+ ACTIONS_DONE() ;
+ DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+ break ;
+ case SC5_THRU_B :
+ /*SC51*/
+ if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
+ smc->y[PA].scrub = TRUE ;
+ GO_STATE(SC9_C_WRAP_A) ;
+ break ;
+ }
+ /*SC52*/
+ else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
+ smc->y[PB].scrub = TRUE ;
+ GO_STATE(SC10_C_WRAP_B) ;
+ break ;
+ }
+ /*SC54*/
+ else if (!smc->s.attach_s) {
+ smc->y[PA].scrub = TRUE ;
+ GO_STATE(SC4_THRU_A) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(SC11_C_WRAP_S) :
+ smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+ smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
+ smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+ config_mux(smc,MUX_WRAPS) ; /* configure PHY mux */
+ if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
+ smc->r.rm_join = FALSE ;
+ smc->r.rm_loop = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+ }
+ if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
+ smc->r.rm_loop = FALSE ;
+ smc->r.rm_join = TRUE ;
+ queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+ }
+ ACTIONS_DONE() ;
+ DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+ break ;
+ case SC11_C_WRAP_S :
+ /*SC70*/
+ if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
+ !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
+ GO_STATE(SC0_ISOLATED) ;
+ break ;
+ }
+ break ;
+ default:
+ SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
+ break;
+ }
+}
+
+/*
+ * get MAC's input Port
+ * return :
+ * PA or PB
+ */
+int cfm_get_mac_input(smc)
+struct s_smc *smc ;
+{
+ return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+ smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA) ;
+}
+
+/*
+ * get MAC's output Port
+ * return :
+ * PA or PB
+ */
+int cfm_get_mac_output(smc)
+struct s_smc *smc ;
+{
+ return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+ smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA) ;
+}
+
+static char path_iso[] = {
+ 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO,
+ 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO,
+ 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO
+} ;
+
+static char path_wrap_a[] = {
+ 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM,
+ 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
+ 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO
+} ;
+
+static char path_wrap_b[] = {
+ 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM,
+ 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
+ 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO
+} ;
+
+static char path_thru[] = {
+ 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM,
+ 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
+ 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM
+} ;
+
+static char path_wrap_s[] = {
+ 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_PRIM,
+ 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
+} ;
+
+static char path_iso_s[] = {
+ 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_ISO,
+ 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO,
+} ;
+
+int cem_build_path(smc,to,path_index)
+struct s_smc *smc ;
+char *to ;
+int path_index ;
+{
+ char *path ;
+ int len ;
+
+ switch (smc->mib.fddiSMTCF_State) {
+ default :
+ case SC0_ISOLATED :
+ path = smc->s.sas ? path_iso_s : path_iso ;
+ len = smc->s.sas ? sizeof(path_iso_s) : sizeof(path_iso) ;
+ break ;
+ case SC9_C_WRAP_A :
+ path = path_wrap_a ;
+ len = sizeof(path_wrap_a) ;
+ break ;
+ case SC10_C_WRAP_B :
+ path = path_wrap_b ;
+ len = sizeof(path_wrap_b) ;
+ break ;
+ case SC4_THRU_A :
+ path = path_thru ;
+ len = sizeof(path_thru) ;
+ break ;
+ case SC11_C_WRAP_S :
+ path = path_wrap_s ;
+ len = sizeof(path_wrap_s) ;
+ break ;
+ }
+ memcpy(to,path,len) ;
+
+ LINT_USE(path_index);
+
+ return(len) ;
+}
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
new file mode 100644
index 000000000..e1e48bc91
--- /dev/null
+++ b/drivers/net/skfp/drvfbi.c
@@ -0,0 +1,1612 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FBI board dependent Driver for SMT and LLC
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "h/skfbiinc.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ;
+#endif
+
+/*
+ * PCM active state
+ */
+#define PC8_ACTIVE 8
+
+#define LED_Y_ON 0x11 /* Used for ring up/down indication */
+#define LED_Y_OFF 0x10
+
+
+#define MS2BCLK(x) ((x)*12500L)
+
+/*
+ * valid configuration values are:
+ */
+#ifdef ISA
+const int opt_ints[] = {8, 3, 4, 5, 9, 10, 11, 12, 15} ;
+const int opt_iops[] = {8,
+ 0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340};
+const int opt_dmas[] = {4, 3, 5, 6, 7} ;
+const int opt_eproms[] = {15, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
+ 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
+#endif
+#ifdef EISA
+const int opt_ints[] = {5, 9, 10, 11} ;
+const int opt_dmas[] = {0, 5, 6, 7} ;
+const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
+ 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
+#endif
+
+#ifdef MCA
+int opt_ints[] = {3, 11, 10, 9} ; /* FM1 */
+int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
+#endif /* MCA */
+
+/*
+ * xPOS_ID:xxxx
+ * | \ /
+ * | \/
+ * | --------------------- the patched POS_ID of the Adapter
+ * | xxxx = (Vendor ID low byte,
+ * | Vendor ID high byte,
+ * | Device ID low byte,
+ * | Device ID high byte)
+ * +------------------------------ the patched oem_id must be
+ * 'S' for SK or 'I' for IBM
+ * this is a short id for the driver.
+ */
+#ifndef MULT_OEM
+#ifndef OEM_CONCEPT
+#ifndef MCA
+const u_char oem_id[] = "xPOS_ID:xxxx" ;
+#else
+const u_char oem_id[] = "xPOSID1:xxxx" ; /* FM1 card id. */
+#endif
+#else /* OEM_CONCEPT */
+#ifndef MCA
+const u_char oem_id[] = OEM_ID ;
+#else
+const u_char oem_id[] = OEM_ID1 ; /* FM1 card id. */
+#endif /* MCA */
+#endif /* OEM_CONCEPT */
+#define ID_BYTE0 8
+#define OEMID(smc,i) oem_id[ID_BYTE0 + i]
+#else /* MULT_OEM */
+const struct s_oem_ids oem_ids[] = {
+#include "oemids.h"
+{0}
+};
+#define OEMID(smc,i) smc->hw.oem_id->oi_id[i]
+#endif /* MULT_OEM */
+
+/* Prototypes of external functions */
+extern void hwt_restart() ;
+#ifdef AIX
+extern int AIX_vpdReadByte() ;
+#endif
+
+
+/* Prototypes of local functions. */
+void smt_stop_watchdog() ;
+
+#ifdef MCA
+static int read_card_id() ;
+static void DisableSlotAccess() ;
+static void EnableSlotAccess() ;
+#ifdef AIX
+extern int attach_POS_addr() ;
+extern int detach_POS_addr() ;
+extern u_char read_POS() ;
+extern void write_POS() ;
+extern int AIX_vpdReadByte() ;
+#else
+#define read_POS(smc,a1,a2) ((u_char) inp(a1))
+#define write_POS(smc,a1,a2,a3) outp((a1),(a3))
+#endif
+#endif /* MCA */
+
+
+/*
+ * FDDI card reset
+ */
+void card_start(smc)
+struct s_smc *smc ;
+{
+ int i ;
+#ifdef PCI
+ u_char rev_id ;
+ u_short word;
+#endif
+
+ smt_stop_watchdog(smc) ;
+
+#ifdef ISA
+ outpw(CSR_A,0) ; /* reset for all chips */
+ for (i = 10 ; i ; i--) /* delay for PLC's */
+ (void)inpw(ISR_A) ;
+ OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ;
+ /* counter 2, mode 2 */
+ OUT_82c54_TIMER(2,97) ; /* LSB */
+ OUT_82c54_TIMER(2,0) ; /* MSB ( 15.6 us ) */
+ outpw(CSR_A,CS_CRESET) ;
+#endif
+#ifdef EISA
+ outpw(CSR_A,0) ; /* reset for all chips */
+ for (i = 10 ; i ; i--) /* delay for PLC's */
+ (void)inpw(ISR_A) ;
+ outpw(CSR_A,CS_CRESET) ;
+ smc->hw.led = (2<<6) ;
+ outpw(CSR_A,CS_CRESET | smc->hw.led) ;
+#endif
+#ifdef MCA
+ outp(ADDR(CARD_DIS),0) ; /* reset for all chips */
+ for (i = 10 ; i ; i--) /* delay for PLC's */
+ (void)inpw(ISR_A) ;
+ outp(ADDR(CARD_EN),0) ;
+ /* first I/O after reset must not be a access to FORMAC or PLC */
+
+ /*
+ * bus timeout (MCA)
+ */
+ OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ;
+ /* counter 2, mode 3 */
+ OUT_82c54_TIMER(2,(2*24)) ; /* 3.9 us * 2 square wave */
+ OUT_82c54_TIMER(2,0) ; /* MSB */
+
+ /* POS 102 indicated an activ Check Line or Buss Error monitoring */
+ if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) {
+ outp(ADDR(IRQ_CHCK_EN),0) ;
+ }
+
+ if (!((i = inpw(CSR_A)) & CS_SAS)) {
+ if (!(i & CS_BYSTAT)) {
+ outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
+ }
+ }
+ outpw(LEDR_A,LED_1) ; /* yellow */
+#endif /* MCA */
+#ifdef PCI
+ /*
+ * make sure no transfer activity is pending
+ */
+ outpw(FM_A(FM_MDREG1),FM_MINIT) ;
+ outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+ hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
+ /*
+ * now reset everything
+ */
+ outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */
+ i = (int) inp(ADDR(B0_CTRL)) ; /* do dummy read */
+ SK_UNUSED(i) ; /* Make LINT happy. */
+ outp(ADDR(B0_CTRL), CTRL_RST_CLR) ;
+
+ /*
+ * Reset all bits in the PCI STATUS register
+ */
+ outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ; /* enable for writes */
+ word = inpw(PCI_C(PCI_STATUS)) ;
+ outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ;
+ outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ; /* disable writes */
+
+ /*
+ * Release the reset of all the State machines
+ * Release Master_Reset
+ * Release HPI_SM_Reset
+ */
+ outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ;
+
+ /*
+ * determine the adapter type
+ * Note: Do it here, because some drivers may call card_start() once
+ * at very first before any other initialization functions is
+ * executed.
+ */
+ rev_id = inp(PCI_C(PCI_REV_ID)) ;
+ if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) {
+ smc->hw.hw_is_64bit = TRUE ;
+ } else {
+ smc->hw.hw_is_64bit = FALSE ;
+ }
+
+ /*
+ * Watermark initialization
+ */
+ if (!smc->hw.hw_is_64bit) {
+ outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
+ outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
+ outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
+ }
+
+ outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* clear the reset chips */
+ outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */
+
+ /* init the timer value for the watch dog 2,5 minutes */
+ outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ;
+
+ /* initialize the ISR mask */
+ smc->hw.is_imask = ISR_MASK ;
+ smc->hw.hw_state = STOPPED ;
+#endif
+ GET_PAGE(0) ; /* necessary for BOOT */
+}
+
+void card_stop(smc)
+struct s_smc *smc ;
+{
+ smt_stop_watchdog(smc) ;
+ smc->hw.mac_ring_is_up = 0 ; /* ring down */
+#ifdef ISA
+ outpw(CSR_A,0) ; /* reset for all chips */
+#endif
+#ifdef EISA
+ outpw(CSR_A,0) ; /* reset for all chips */
+#endif
+#ifdef MCA
+ outp(ADDR(CARD_DIS),0) ; /* reset for all chips */
+#endif
+#ifdef PCI
+ /*
+ * make sure no transfer activity is pending
+ */
+ outpw(FM_A(FM_MDREG1),FM_MINIT) ;
+ outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+ hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
+ /*
+ * now reset everything
+ */
+ outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */
+ outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* reset for all chips */
+ outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */
+ smc->hw.hw_state = STOPPED ;
+#endif
+}
+/*--------------------------- ISR handling ----------------------------------*/
+
+#ifndef PCI
+void mac1_irq(smc,stu, stl)
+struct s_smc *smc ;
+u_short stu;
+u_short stl;
+{
+ int restart_tx = 0 ;
+again:
+#ifndef ISA
+/*
+ * FORMAC+ bug modified the queue pointer if many read/write accesses happens!?
+ */
+ if (stl & (FM_SPCEPDS | /* parit/coding err. syn.q.*/
+ FM_SPCEPDA0 | /* parit/coding err. a.q.0 */
+ FM_SPCEPDA1 | /* parit/coding err. a.q.1 */
+ FM_SPCEPDA2)) { /* parit/coding err. a.q.2 */
+ SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ;
+ }
+ if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/
+ FM_STBURA0 | /* tx buffer underrun a.q.0 */
+ FM_STBURA1 | /* tx buffer underrun a.q.1 */
+ FM_STBURA2)) { /* tx buffer underrun a.q.2 */
+ SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
+ }
+#endif
+ if ( (stu & (FM_SXMTABT | /* transmit abort */
+#ifdef SYNC
+ FM_STXABRS | /* syn. tx abort */
+#endif /* SYNC */
+ FM_STXABRA0)) || /* asyn. tx abort */
+ (stl & (FM_SQLCKS | /* lock for syn. q. */
+ FM_SQLCKA0)) ) { /* lock for asyn. q. */
+ formac_tx_restart(smc) ; /* init tx */
+ restart_tx = 1 ;
+ stu = inpw(FM_A(FM_ST1U)) ;
+ stl = inpw(FM_A(FM_ST1L)) ;
+ stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
+ if (stu || stl)
+ goto again ;
+ }
+
+#ifndef SYNC
+ if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */
+ FM_STEFRMA0)) { /* end of frame asyn tx */
+ /* free tx_queue */
+ smc->hw.n_a_send = 0 ;
+ if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) {
+ start_next_send(smc);
+ }
+ restart_tx = 1 ;
+ }
+#else /* SYNC */
+ if (stu & (FM_STEFRMA0 | /* end of asyn tx */
+ FM_STEFRMS)) { /* end of sync tx */
+ restart_tx = 1 ;
+ }
+#endif /* SYNC */
+ if (restart_tx)
+ llc_restart_tx(smc) ;
+}
+#else /* PCI */
+
+void mac1_irq(smc,stu, stl)
+struct s_smc *smc ;
+u_short stu;
+u_short stl;
+{
+ int restart_tx = 0 ;
+again:
+
+ /*
+ * parity error: note encoding error is not possible in tag mode
+ */
+ if (stl & (FM_SPCEPDS | /* parity err. syn.q.*/
+ FM_SPCEPDA0 | /* parity err. a.q.0 */
+ FM_SPCEPDA1)) { /* parity err. a.q.1 */
+ SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ;
+ }
+ /*
+ * buffer underrun: can only occur if a tx threshold is specified
+ */
+ if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/
+ FM_STBURA0 | /* tx buffer underrun a.q.0 */
+ FM_STBURA1)) { /* tx buffer underrun a.q.2 */
+ SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
+ }
+
+ if ( (stu & (FM_SXMTABT | /* transmit abort */
+ FM_STXABRS | /* syn. tx abort */
+ FM_STXABRA0)) || /* asyn. tx abort */
+ (stl & (FM_SQLCKS | /* lock for syn. q. */
+ FM_SQLCKA0)) ) { /* lock for asyn. q. */
+ formac_tx_restart(smc) ; /* init tx */
+ restart_tx = 1 ;
+ stu = inpw(FM_A(FM_ST1U)) ;
+ stl = inpw(FM_A(FM_ST1L)) ;
+ stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
+ if (stu || stl)
+ goto again ;
+ }
+
+ if (stu & (FM_STEFRMA0 | /* end of asyn tx */
+ FM_STEFRMS)) { /* end of sync tx */
+ restart_tx = 1 ;
+ }
+
+ if (restart_tx)
+ llc_restart_tx(smc) ;
+}
+#endif /* PCI */
+/*
+ * interrupt source= plc1
+ * this function is called in nwfbisr.asm
+ */
+void plc1_irq(smc)
+struct s_smc *smc ;
+{
+ u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ;
+
+#if (defined(ISA) || defined(EISA))
+ /* reset PLC Int. bits */
+ outpw(PLC1_I,inpw(PLC1_I)) ;
+#endif
+ plc_irq(smc,PB,st) ;
+}
+
+/*
+ * interrupt source= plc2
+ * this function is called in nwfbisr.asm
+ */
+void plc2_irq(smc)
+struct s_smc *smc ;
+{
+ u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ;
+
+#if (defined(ISA) || defined(EISA))
+ /* reset PLC Int. bits */
+ outpw(PLC2_I,inpw(PLC2_I)) ;
+#endif
+ plc_irq(smc,PA,st) ;
+}
+
+
+/*
+ * interrupt source= timer
+ */
+void timer_irq(smc)
+struct s_smc *smc ;
+{
+ hwt_restart(smc);
+ smc->hw.t_stop = smc->hw.t_start;
+ smt_timer_done(smc) ;
+}
+
+/*
+ * return S-port (PA or PB)
+ */
+int pcm_get_s_port(smc)
+struct s_smc *smc ;
+{
+ SK_UNUSED(smc) ;
+ return(PS) ;
+}
+
+/*
+ * Station Label = "FDDI-XYZ" where
+ *
+ * X = connector type
+ * Y = PMD type
+ * Z = port type
+ */
+#define STATION_LABEL_CONNECTOR_OFFSET 5
+#define STATION_LABEL_PMD_OFFSET 6
+#define STATION_LABEL_PORT_OFFSET 7
+
+void read_address(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;
+{
+ char ConnectorType ;
+ char PmdType ;
+ int i ;
+
+ extern const u_char canonical[256] ;
+
+#if (defined(ISA) || defined(MCA))
+ for (i = 0; i < 4 ;i++) { /* read mac address from board */
+ smc->hw.fddi_phys_addr.a[i] =
+ canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+ }
+ for (i = 4; i < 6; i++) {
+ smc->hw.fddi_phys_addr.a[i] =
+ canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+ }
+#endif
+#ifdef EISA
+ /*
+ * Note: We get trouble on an Alpha machine if we make a inpw()
+ * instead of inp()
+ */
+ for (i = 0; i < 4 ;i++) { /* read mac address from board */
+ smc->hw.fddi_phys_addr.a[i] =
+ canonical[inp(PR_A(i+SA_MAC))] ;
+ }
+ for (i = 4; i < 6; i++) {
+ smc->hw.fddi_phys_addr.a[i] =
+ canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+ }
+#endif
+#ifdef PCI
+ for (i = 0; i < 6; i++) { /* read mac address from board */
+ smc->hw.fddi_phys_addr.a[i] =
+ canonical[inp(ADDR(B2_MAC_0+i))] ;
+ }
+#endif
+#ifndef PCI
+ ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ;
+ PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ;
+#else
+ ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
+ PmdType = inp(ADDR(B2_PMD_TYP)) ;
+#endif
+
+ smc->y[PA].pmd_type[PMD_SK_CONN] =
+ smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
+ smc->y[PA].pmd_type[PMD_SK_PMD ] =
+ smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ;
+
+ if (mac_addr) {
+ for (i = 0; i < 6 ;i++) {
+ smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
+ smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+ }
+ return ;
+ }
+ smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ;
+
+ for (i = 0; i < 6 ;i++) {
+ smc->hw.fddi_canon_addr.a[i] =
+ canonical[smc->hw.fddi_phys_addr.a[i]] ;
+ }
+}
+
+/*
+ * FDDI card soft reset
+ */
+void init_board(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;
+{
+ card_start(smc) ;
+ read_address(smc,mac_addr) ;
+
+#ifndef PCI
+ if (inpw(CSR_A) & CS_SAS)
+#else
+ if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
+#endif
+ smc->s.sas = SMT_SAS ; /* Single att. station */
+ else
+ smc->s.sas = SMT_DAS ; /* Dual att. station */
+
+#ifndef PCI
+ if (inpw(CSR_A) & CS_BYSTAT)
+#else
+ if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
+#endif
+ smc->mib.fddiSMTBypassPresent = 0 ;
+ /* without opt. bypass */
+ else
+ smc->mib.fddiSMTBypassPresent = 1 ;
+ /* with opt. bypass */
+}
+
+/*
+ * insert or deinsert optical bypass (called by ECM)
+ */
+void sm_pm_bypass_req(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+#if (defined(ISA) || defined(EISA))
+ int csra_v ;
+#endif
+
+ DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
+ "BP_INSERT" : "BP_DEINSERT",0) ;
+
+ if (smc->s.sas != SMT_DAS)
+ return ;
+
+#if (defined(ISA) || defined(EISA))
+
+ csra_v = inpw(CSR_A) & ~CS_BYPASS ;
+#ifdef EISA
+ csra_v |= smc->hw.led ;
+#endif
+
+ switch(mode) {
+ case BP_INSERT :
+ outpw(CSR_A,csra_v | CS_BYPASS) ;
+ break ;
+ case BP_DEINSERT :
+ outpw(CSR_A,csra_v) ;
+ break ;
+ }
+#endif /* ISA / EISA */
+#ifdef MCA
+ switch(mode) {
+ case BP_INSERT :
+ outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
+ break ;
+ case BP_DEINSERT :
+ outp(ADDR(BYPASS(STAT_BYP)),0) ; /* bypass station */
+ break ;
+ }
+#endif
+#ifdef PCI
+ switch(mode) {
+ case BP_INSERT :
+ outp(ADDR(B0_DAS),DAS_BYP_INS) ; /* insert station */
+ break ;
+ case BP_DEINSERT :
+ outp(ADDR(B0_DAS),DAS_BYP_RMV) ; /* bypass station */
+ break ;
+ }
+#endif
+}
+
+/*
+ * check if bypass connected
+ */
+int sm_pm_bypass_present(smc)
+struct s_smc *smc ;
+{
+#ifndef PCI
+ return( (inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ;
+#else
+ return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
+#endif
+}
+
+void plc_clear_irq(smc,p)
+struct s_smc *smc ;
+int p ;
+{
+ SK_UNUSED(p) ;
+
+#if (defined(ISA) || defined(EISA))
+ switch (p) {
+ case PA :
+ /* reset PLC Int. bits */
+ outpw(PLC2_I,inpw(PLC2_I)) ;
+ break ;
+ case PB :
+ /* reset PLC Int. bits */
+ outpw(PLC1_I,inpw(PLC1_I)) ;
+ break ;
+ }
+#else
+ SK_UNUSED(smc) ;
+#endif
+}
+
+
+/*
+ * led_indication called by rmt_indication() and
+ * pcm_state_change()
+ *
+ * Input:
+ * smc: SMT context
+ * led_event:
+ * 0 Only switch green LEDs according to their respective PCM state
+ * LED_Y_OFF just switch yellow LED off
+ * LED_Y_ON just switch yello LED on
+ */
+void led_indication(smc,led_event)
+struct s_smc *smc ;
+int led_event;
+{
+ /* use smc->hw.mac_ring_is_up == TRUE
+ * as indication for Ring Operational
+ */
+ u_short led_state ;
+ struct s_phy *phy ;
+ struct fddi_mib_p *mib_a ;
+ struct fddi_mib_p *mib_b ;
+
+ phy = &smc->y[PA] ;
+ mib_a = phy->mib ;
+ phy = &smc->y[PB] ;
+ mib_b = phy->mib ;
+
+#ifdef EISA
+ /* Ring up = yellow led OFF*/
+ if (led_event == LED_Y_ON) {
+ smc->hw.led |= CS_LED_1 ;
+ }
+ else if (led_event == LED_Y_OFF) {
+ smc->hw.led &= ~CS_LED_1 ;
+ }
+ else {
+ /* Link at Port A or B = green led ON */
+ if (mib_a->fddiPORTPCMState == PC8_ACTIVE ||
+ mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+ smc->hw.led |= CS_LED_0 ;
+ }
+ else {
+ smc->hw.led &= ~CS_LED_0 ;
+ }
+ }
+#endif
+#ifdef MCA
+ led_state = inpw(LEDR_A) ;
+
+ /* Ring up = yellow led OFF*/
+ if (led_event == LED_Y_ON) {
+ led_state |= LED_1 ;
+ }
+ else if (led_event == LED_Y_OFF) {
+ led_state &= ~LED_1 ;
+ }
+ else {
+ led_state &= ~(LED_2|LED_0) ;
+
+ /* Link at Port A = green led A ON */
+ if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {
+ led_state |= LED_2 ;
+ }
+
+ /* Link at Port B/S = green led B ON */
+ if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+ led_state |= LED_0 ;
+ }
+ }
+
+ outpw(LEDR_A, led_state) ;
+#endif /* MCA */
+#ifdef PCI
+ led_state = 0 ;
+
+ /* Ring up = yellow led OFF*/
+ if (led_event == LED_Y_ON) {
+ led_state |= LED_MY_ON ;
+ }
+ else if (led_event == LED_Y_OFF) {
+ led_state |= LED_MY_OFF ;
+ }
+ else { /* PCM state changed */
+ /* Link at Port A/S = green led A ON */
+ if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {
+ led_state |= LED_GA_ON ;
+ }
+ else {
+ led_state |= LED_GA_OFF ;
+ }
+
+ /* Link at Port B = green led B ON */
+ if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+ led_state |= LED_GB_ON ;
+ }
+ else {
+ led_state |= LED_GB_OFF ;
+ }
+ }
+
+ outp(ADDR(B0_LED), led_state) ;
+#endif /* PCI */
+
+}
+
+
+void pcm_state_change(smc,plc,p_state)
+struct s_smc *smc;
+int plc;
+int p_state;
+{
+ /*
+ * the current implementation of pcm_state_change() in the driver
+ * parts must be renamed to drv_pcm_state_change() which will be called
+ * now after led_indication.
+ */
+ DRV_PCM_STATE_CHANGE(smc,plc,p_state) ;
+
+ led_indication(smc,0) ;
+}
+
+
+void rmt_indication(smc,i)
+struct s_smc *smc ;
+int i;
+{
+ /* Call a driver special function if defined */
+ DRV_RMT_INDICATION(smc,i) ;
+
+ led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ;
+}
+
+
+/*
+ * llc_recover_tx called by init_tx (fplus.c)
+ */
+void llc_recover_tx(smc)
+struct s_smc *smc ;
+{
+#ifdef LOAD_GEN
+ extern int load_gen_flag ;
+
+ load_gen_flag = 0 ;
+#endif
+#ifndef SYNC
+ smc->hw.n_a_send= 0 ;
+#else
+ SK_UNUSED(smc) ;
+#endif
+}
+
+/*--------------------------- DMA init ----------------------------*/
+#ifdef ISA
+
+/*
+ * init DMA
+ */
+void init_dma(smc,dma)
+struct s_smc *smc;
+int dma;
+{
+ SK_UNUSED(smc) ;
+
+ /*
+ * set cascade mode,
+ * clear mask bit (enable DMA cannal)
+ */
+ if (dma > 3) {
+ outp(0xd6,(dma & 0x03) | 0xc0) ;
+ outp(0xd4, dma & 0x03) ;
+ }
+ else {
+ outp(0x0b,(dma & 0x03) | 0xc0) ;
+ outp(0x0a,dma & 0x03) ;
+ }
+}
+
+/*
+ * disable DMA
+ */
+void dis_dma(smc,dma)
+struct s_smc *smc ;
+int dma;
+{
+ SK_UNUSED(smc) ;
+
+ /*
+ * set mask bit (disable DMA cannal)
+ */
+ if (dma > 3) {
+ outp(0xd4,(dma & 0x03) | 0x04) ;
+ }
+ else {
+ outp(0x0a,(dma & 0x03) | 0x04) ;
+ }
+}
+
+#endif /* ISA */
+
+#ifdef EISA
+
+/*arrays with io adresses of dma controller length and adress registers*/
+static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
+static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
+static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
+
+void init_dma(smc,dma)
+struct s_smc *smc ;
+int dma;
+{
+ /*
+ * extended mode register
+ * 32 bit IO
+ * type c
+ * TC output
+ * disable stop
+ */
+
+ /* mode read (write) demand */
+ smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
+ smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
+
+ /* 32 bit IO's, burst DMA mode (type "C") */
+ smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
+
+ outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
+
+ /* disable chaining */
+ outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
+
+ /*load dma controller addresses for fast access during set dma*/
+ smc->hw.dma_base_word_count = cntr[smc->hw.dma];
+ smc->hw.dma_base_address = base[smc->hw.dma];
+ smc->hw.dma_base_address_page = page[smc->hw.dma];
+
+}
+
+void dis_dma(smc,dma)
+struct s_smc *smc ;
+int dma;
+{
+ SK_UNUSED(smc) ;
+
+ outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
+}
+#endif /* EISA */
+
+#ifdef MCA
+void init_dma(smc,dma)
+struct s_smc *smc;
+int dma;
+{
+ SK_UNUSED(smc) ;
+ SK_UNUSED(dma) ;
+}
+void dis_dma(smc,dma)
+struct s_smc *smc;
+int dma;
+{
+ SK_UNUSED(smc) ;
+ SK_UNUSED(dma) ;
+}
+#endif
+
+#ifdef PCI
+void init_dma(smc,dma)
+struct s_smc *smc;
+int dma;
+{
+ SK_UNUSED(smc) ;
+ SK_UNUSED(dma) ;
+}
+void dis_dma(smc,dma)
+struct s_smc *smc;
+int dma;
+{
+ SK_UNUSED(smc) ;
+ SK_UNUSED(dma) ;
+}
+#endif
+
+#ifdef MULT_OEM
+static int is_equal_num(comp1,comp2,num)
+char comp1[] ;
+char comp2[] ;
+int num ;
+{
+ int i ;
+
+ for (i = 0 ; i < num ; i++) {
+ if (comp1[i] != comp2[i])
+ return (0) ;
+ }
+ return (1) ;
+} /* is_equal_num */
+
+
+/*
+ * set the OEM ID defaults, and test the contents of the OEM data base
+ * The default OEM is the first ACTIVE entry in the OEM data base
+ *
+ * returns: 0 success
+ * 1 error in data base
+ * 2 data base empty
+ * 3 no active entry
+ */
+int set_oi_id_def(smc)
+struct s_smc *smc ;
+{
+ int sel_id ;
+ int i ;
+ int act_entries ;
+
+ i = 0 ;
+ sel_id = -1 ;
+ act_entries = FALSE ;
+ smc->hw.oem_id = 0 ;
+ smc->hw.oem_min_status = OI_STAT_ACTIVE ;
+
+ /* check OEM data base */
+ while (oem_ids[i].oi_status) {
+ switch (oem_ids[i].oi_status) {
+ case OI_STAT_ACTIVE:
+ act_entries = TRUE ; /* we have active IDs */
+ if (sel_id == -1)
+ sel_id = i ; /* save the first active ID */
+ case OI_STAT_VALID:
+ case OI_STAT_PRESENT:
+ i++ ;
+ break ; /* entry ok */
+ default:
+ return (1) ; /* invalid oi_status */
+ }
+ }
+
+ if (i == 0)
+ return (2) ;
+ if (!act_entries)
+ return (3) ;
+
+ /* ok, we have a valid OEM data base with an active entry */
+ smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[sel_id] ;
+ return (0) ;
+}
+#endif /* MULT_OEM */
+
+
+#ifdef MCA
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ * exist_board
+ *
+ * Check if an MCA board is present in the specified slot.
+ *
+ * int exist_board(
+ * struct s_smc *smc,
+ * int slot) ;
+ * In
+ * smc - A pointer to the SMT Context struct.
+ *
+ * slot - The number of the slot to inspect.
+ * Out
+ * 0 = No adapter present.
+ * 1 = Found FM1 adapter.
+ *
+ * Pseudo
+ * Read MCA ID
+ * for all valid OEM_IDs
+ * compare with ID read
+ * if equal, return 1
+ * return(0
+ *
+ * Note
+ * The smc pointer must be valid now.
+ *
+ * END_MANUAL_ENTRY()
+ *
+ ************************/
+#define LONG_CARD_ID(lo, hi) ((((hi) & 0xff) << 8) | ((lo) & 0xff))
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+#ifdef MULT_OEM
+ SK_LOC_DECL(u_char,id[2]) ;
+ int idi ;
+#endif /* MULT_OEM */
+
+ /* No longer valid. */
+ if (smc == NULL)
+ return(0) ;
+
+#ifndef MULT_OEM
+ if (read_card_id(smc, slot)
+ == LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1)))
+ return (1) ; /* Found FM adapter. */
+
+#else /* MULT_OEM */
+ idi = read_card_id(smc, slot) ;
+ id[0] = idi & 0xff ;
+ id[1] = idi >> 8 ;
+
+ smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+ for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+ if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+ continue ;
+
+ if (is_equal_num(&id[0],&OEMID(smc,0),2))
+ return (1) ;
+ }
+#endif /* MULT_OEM */
+ return (0) ; /* No adapter found. */
+}
+
+/************************
+ *
+ * read_card_id
+ *
+ * Read the MCA card id from the specified slot.
+ * In
+ * smc - A pointer to the SMT Context struct.
+ * CAVEAT: This pointer may be NULL and *must not* be used within this
+ * function. It's only purpose is for drivers that need some information
+ * for the inp() and outp() macros.
+ *
+ * slot - The number of the slot for which the card id is returned.
+ * Out
+ * Returns the card id read from the specified slot. If an illegal slot
+ * number is specified, the function returns zero.
+ *
+ ************************/
+static int read_card_id(smc,slot)
+struct s_smc *smc ; /* Do not use. */
+int slot ;
+{
+ int card_id ;
+
+ SK_UNUSED(smc) ; /* Make LINT happy. */
+ if ((slot < 1) || (slot > 15)) /* max 16 slots, 0 = motherboard */
+ return (0) ; /* Illegal slot number specified. */
+
+ EnableSlotAccess(smc, slot) ;
+
+ card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) |
+ (read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ;
+
+ DisableSlotAccess(smc) ;
+
+ return (card_id) ;
+}
+
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ * get_board_para
+ *
+ * Get adapter configuration information. Fill all board specific
+ * parameters within the 'smc' structure.
+ *
+ * int get_board_para(
+ * struct s_smc *smc,
+ * int slot) ;
+ * In
+ * smc - A pointer to the SMT Context struct, to which this function will
+ * write some adapter configuration data.
+ *
+ * slot - The number of the slot, in which the adapter is installed.
+ * Out
+ * 0 = No adapter present.
+ * 1 = Ok.
+ * 2 = Adapter present, but card enable bit not set.
+ *
+ * END_MANUAL_ENTRY()
+ *
+ ************************/
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+ int val ;
+ int i ;
+
+ /* Check if adapter present & get type of adapter. */
+ switch (exist_board(smc, slot)) {
+ case 0: /* Adapter not present. */
+ return (0) ;
+ case 1: /* FM Rev. 1 */
+ smc->hw.rev = FM1_REV ;
+ smc->hw.VFullRead = 0x0a ;
+ smc->hw.VFullWrite = 0x05 ;
+ smc->hw.DmaWriteExtraBytes = 8 ; /* 2 extra words. */
+ break ;
+ }
+ smc->hw.slot = slot ;
+
+ EnableSlotAccess(smc, slot) ;
+
+ if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) {
+ DisableSlotAccess(smc) ;
+ return (2) ; /* Card enable bit not set. */
+ }
+
+ val = read_POS(smc,POS_104, slot - 1) ; /* I/O, IRQ */
+
+#ifndef MEM_MAPPED_IO /* is defined by the operating system */
+ i = val & POS_IOSEL ; /* I/O base addr. (0x0200 .. 0xfe00) */
+ smc->hw.iop = (i + 1) * 0x0400 - 0x200 ;
+#endif
+ i = ((val & POS_IRQSEL) >> 6) & 0x03 ; /* IRQ <0, 1> */
+ smc->hw.irq = opt_ints[i] ;
+
+ /* FPROM base addr. */
+ i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ;
+ smc->hw.eprom = opt_eproms[i] ;
+
+ DisableSlotAccess(smc) ;
+
+ /* before this, the smc->hw.iop must be set !!! */
+ smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ;
+
+ return (1) ;
+}
+
+/* Enable access to specified MCA slot. */
+static void EnableSlotAccess(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+ SK_UNUSED(slot) ;
+
+#ifndef AIX
+ SK_UNUSED(smc) ;
+
+ /* System mode. */
+ outp(POS_SYS_SETUP, POS_SYSTEM) ;
+
+ /* Select slot. */
+ outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ;
+#else
+ attach_POS_addr (smc) ;
+#endif
+}
+
+/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */
+static void DisableSlotAccess(smc)
+struct s_smc *smc ;
+{
+#ifndef AIX
+ SK_UNUSED(smc) ;
+
+ outp(POS_CHANNEL_POS, 0) ;
+#else
+ detach_POS_addr (smc) ;
+#endif
+}
+#endif /* MCA */
+
+#ifdef EISA
+#ifndef MEM_MAPPED_IO
+#define SADDR(slot) (((slot)<<12)&0xf000)
+#else /* MEM_MAPPED_IO */
+#define SADDR(slot) (smc->hw.iop)
+#endif /* MEM_MAPPED_IO */
+
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ * exist_board
+ *
+ * Check if an EISA board is present in the specified slot.
+ *
+ * int exist_board(
+ * struct s_smc *smc,
+ * int slot) ;
+ * In
+ * smc - A pointer to the SMT Context struct.
+ *
+ * slot - The number of the slot to inspect.
+ * Out
+ * 0 = No adapter present.
+ * 1 = Found adapter.
+ *
+ * Pseudo
+ * Read EISA ID
+ * for all valid OEM_IDs
+ * compare with ID read
+ * if equal, return 1
+ * return(0
+ *
+ * Note
+ * The smc pointer must be valid now.
+ *
+ ************************/
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+ int i ;
+#ifdef MULT_OEM
+ SK_LOC_DECL(u_char,id[4]) ;
+#endif /* MULT_OEM */
+
+ /* No longer valid. */
+ if (smc == NULL)
+ return(0);
+
+ SK_UNUSED(slot) ;
+
+#ifndef MULT_OEM
+ for (i = 0 ; i < 4 ; i++) {
+ if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i))
+ return(0) ;
+ }
+ return(1) ;
+#else /* MULT_OEM */
+ for (i = 0 ; i < 4 ; i++)
+ id[i] = inp(SADDR(slot)+PRA(i)) ;
+
+ smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+
+ for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+ if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+ continue ;
+
+ if (is_equal_num(&id[0],&OEMID(smc,0),4))
+ return (1) ;
+ }
+ return (0) ; /* No adapter found. */
+#endif /* MULT_OEM */
+}
+
+
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+ int i ;
+
+ if (!exist_board(smc,slot))
+ return(0) ;
+
+ smc->hw.slot = slot ;
+#ifndef MEM_MAPPED_IO /* if defined by the operating system */
+ smc->hw.iop = SADDR(slot) ;
+#endif
+
+ if (!(inp(C0_A(0))&CFG_CARD_EN)) {
+ return(2) ; /* CFG_CARD_EN bit not set! */
+ }
+
+ smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ;
+ smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ;
+
+ if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f)
+ smc->hw.eprom = opt_eproms[i] ;
+ else
+ smc->hw.eprom = 0 ;
+
+ smc->hw.DmaWriteExtraBytes = 8 ;
+
+ return(1) ;
+}
+#endif /* EISA */
+
+#ifdef ISA
+#ifndef MULT_OEM
+const u_char sklogo[6] = SKLOGO_STR ;
+#define SIZE_SKLOGO(smc) sizeof(sklogo)
+#define SKLOGO(smc,i) sklogo[i]
+#else /* MULT_OEM */
+#define SIZE_SKLOGO(smc) smc->hw.oem_id->oi_logo_len
+#define SKLOGO(smc,i) smc->hw.oem_id->oi_logo[i]
+#endif /* MULT_OEM */
+
+
+int exist_board(smc,port)
+struct s_smc *smc ;
+HW_PTR port ;
+{
+ int i ;
+#ifdef MULT_OEM
+ int bytes_read ;
+ u_char board_logo[15] ;
+ SK_LOC_DECL(u_char,id[4]) ;
+#endif /* MULT_OEM */
+
+ /* No longer valid. */
+ if (smc == NULL)
+ return(0);
+
+ SK_UNUSED(smc) ;
+#ifndef MULT_OEM
+ for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) {
+ if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) {
+ return(0) ;
+ }
+ }
+
+ /* check MAC address (S&K or other) */
+ for (i = 0 ; i < 3 ; i++) {
+ if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i))
+ return(0) ;
+ }
+ return(1) ;
+#else /* MULT_OEM */
+ smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+ board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ;
+ bytes_read = 1 ;
+
+ for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+ if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+ continue ;
+
+ /* Test all read bytes with current OEM_entry */
+ /* for (i=0; (i<bytes_read) && (i < SIZE_SKLOGO(smc)); i++) { */
+ for (i = 0; i < bytes_read; i++) {
+ if (board_logo[i] != SKLOGO(smc,i))
+ break ;
+ }
+
+ /* If mismatch, switch to next OEM entry */
+ if ((board_logo[i] != SKLOGO(smc,i)) && (i < bytes_read))
+ continue ;
+
+ --i ;
+ while (bytes_read < SIZE_SKLOGO(smc)) {
+ // inpw next byte SK_Logo
+ i++ ;
+ board_logo[i] = (u_char)inpw((PRA(SADDRL+i)+port)) ;
+ bytes_read++ ;
+ if (board_logo[i] != SKLOGO(smc,i))
+ break ;
+ }
+
+ for (i = 0 ; i < 3 ; i++)
+ id[i] = (u_char)inpw((PRA(i)+port)) ;
+
+ if ((board_logo[i] == SKLOGO(smc,i))
+ && (bytes_read == SIZE_SKLOGO(smc))) {
+
+ if (is_equal_num(&id[0],&OEMID(smc,0),3))
+ return(1);
+ }
+ } /* for */
+ return(0) ;
+#endif /* MULT_OEM */
+}
+
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+ SK_UNUSED(smc) ;
+ SK_UNUSED(slot) ;
+ return(0) ; /* for ISA not supported */
+}
+#endif /* ISA */
+
+#ifdef PCI
+#ifdef USE_BIOS_FUN
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+ u_short dev_id ;
+ u_short ven_id ;
+ int found ;
+ int i ;
+
+ found = FALSE ; /* make sure we returned with adatper not found*/
+ /* if an empty oemids.h was included */
+
+#ifdef MULT_OEM
+ smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+ for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+ if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+ continue ;
+#endif
+ ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ;
+ dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ;
+ for (i = 0; i < slot; i++) {
+ if (pci_find_device(i,&smc->hw.pci_handle,
+ dev_id,ven_id) != 0) {
+
+ found = FALSE ;
+ } else {
+ found = TRUE ;
+ }
+ }
+ if (found) {
+ return(1) ; /* adapter was found */
+ }
+#ifdef MULT_OEM
+ }
+#endif
+ return(0) ; /* adapter was not found */
+}
+#endif /* PCI */
+#endif /* USE_BIOS_FUNC */
+
+void driver_get_bia(smc, bia_addr)
+struct s_smc *smc ;
+struct fddi_addr *bia_addr ;
+{
+ int i ;
+
+ extern const u_char canonical[256] ;
+
+ for (i = 0 ; i < 6 ; i++) {
+ bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
+ }
+}
+
+void smt_start_watchdog(smc)
+struct s_smc *smc ;
+{
+ SK_UNUSED(smc) ; /* Make LINT happy. */
+
+#ifndef DEBUG
+
+#ifdef PCI
+ if (smc->hw.wdog_used) {
+ outpw(ADDR(B2_WDOG_CRTL),TIM_START) ; /* Start timer. */
+ }
+#endif
+
+#endif /* DEBUG */
+}
+
+void smt_stop_watchdog(smc)
+struct s_smc *smc ;
+{
+ SK_UNUSED(smc) ; /* Make LINT happy. */
+#ifndef DEBUG
+
+#ifdef PCI
+ if (smc->hw.wdog_used) {
+ outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ; /* Stop timer. */
+ }
+#endif
+
+#endif /* DEBUG */
+}
+
+#ifdef PCI
+static char get_rom_byte(smc,addr)
+struct s_smc *smc ;
+u_short addr ;
+{
+ GET_PAGE(addr) ;
+ return (READ_PROM(ADDR(B2_FDP))) ;
+}
+
+/*
+ * ROM image defines
+ */
+#define ROM_SIG_1 0
+#define ROM_SIG_2 1
+#define PCI_DATA_1 0x18
+#define PCI_DATA_2 0x19
+
+/*
+ * PCI data structure defines
+ */
+#define VPD_DATA_1 0x08
+#define VPD_DATA_2 0x09
+#define IMAGE_LEN_1 0x10
+#define IMAGE_LEN_2 0x11
+#define CODE_TYPE 0x14
+#define INDICATOR 0x15
+
+/*
+ * BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
+ * mac_drv_vpd_read(smc,buf,size,image)
+ *
+ * function DOWNCALL (FDDIWARE)
+ * reads the VPD data of the FPROM and writes it into the
+ * buffer
+ *
+ * para buf points to the buffer for the VPD data
+ * size size of the VPD data buffer
+ * image boot image; code type of the boot image
+ * image = 0 Intel x86, PC-AT compatible
+ * 1 OPENBOOT standard for PCI
+ * 2-FF reserved
+ *
+ * returns len number of VPD data bytes read form the FPROM
+ * <0 number of read bytes
+ * >0 error: data invalid
+ *
+ * END_MANUAL_ENTRY
+ */
+int mac_drv_vpd_read(smc,buf,size,image)
+struct s_smc *smc ;
+char *buf ;
+int size ;
+char image ;
+{
+ u_short ibase ;
+ u_short pci_base ;
+ u_short vpd ;
+ int len ;
+
+ len = 0 ;
+ ibase = 0 ;
+ /*
+ * as long images defined
+ */
+ while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
+ (u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
+ /*
+ * get the pointer to the PCI data structure
+ */
+ pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
+ (get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
+
+ if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
+ /*
+ * we have the right image, read the VPD data
+ */
+ vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
+ (get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
+ if (vpd == ibase) {
+ break ; /* no VPD data */
+ }
+ for (len = 0; len < size; len++,buf++,vpd++) {
+ *buf = get_rom_byte(smc,vpd) ;
+ }
+ break ;
+ }
+ else {
+ /*
+ * try the next image
+ */
+ if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
+ break ; /* this was the last image */
+ }
+ ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
+ (get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
+ }
+ }
+
+ return(len) ;
+}
+
+void mac_drv_pci_fix(smc,fix_value)
+struct s_smc *smc ;
+u_long fix_value ;
+{
+ smc->hw.pci_fix_value = fix_value ;
+}
+
+void mac_do_pci_fix(smc)
+struct s_smc *smc ;
+{
+ SK_UNUSED(smc) ;
+}
+#endif /* PCI */
diff --git a/drivers/net/skfp/ecm.c b/drivers/net/skfp/ecm.c
new file mode 100644
index 000000000..411169286
--- /dev/null
+++ b/drivers/net/skfp/ecm.c
@@ -0,0 +1,547 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ SMT ECM
+ Entity Coordination Management
+ Hardware independant state machine
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * queue_event()
+ * smt_timer_start()
+ * smt_timer_stop()
+ *
+ * The following external HW dependant functions are referenced :
+ * sm_pm_bypass_req()
+ * sm_pm_ls_latch()
+ * sm_pm_get_ls()
+ *
+ * The following HW dependant events are required :
+ * NONE
+ *
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)ecm.c 2.7 99/08/05 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG 0x10
+#define GO_STATE(x) (smc->mib.fddiSMTECMState = (x)|AFLAG)
+#define ACTIONS_DONE() (smc->mib.fddiSMTECMState &= ~AFLAG)
+#define ACTIONS(x) (x|AFLAG)
+
+#define EC0_OUT 0 /* not inserted */
+#define EC1_IN 1 /* inserted */
+#define EC2_TRACE 2 /* tracing */
+#define EC3_LEAVE 3 /* leaving the ring */
+#define EC4_PATH_TEST 4 /* performing path test */
+#define EC5_INSERT 5 /* bypass being turned on */
+#define EC6_CHECK 6 /* checking bypass */
+#define EC7_DEINSERT 7 /* bypass being turnde off */
+
+#ifdef DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const ecm_states[] = {
+ "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
+ "EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const ecm_events[] = {
+ "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
+ "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
+ "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
+} ;
+#endif
+
+/*
+ * all Globals are defined in smc.h
+ * struct s_ecm
+ */
+
+/*
+ * function declarations
+ */
+
+static void ecm_fsm() ;
+static void start_ecm_timer() ;
+static void stop_ecm_timer() ;
+static void prop_actions() ;
+
+/*
+ init ECM state machine
+ clear all ECM vars and flags
+*/
+void ecm_init(smc)
+struct s_smc *smc ;
+{
+ smc->e.path_test = PT_PASSED ;
+ smc->e.trace_prop = 0 ;
+ smc->e.sb_flag = 0 ;
+ smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
+ smc->e.ecm_line_state = FALSE ;
+}
+
+/*
+ ECM state machine
+ called by dispatcher
+
+ do
+ display state change
+ process event
+ until SM is stable
+*/
+void ecm(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+ int state ;
+
+ do {
+ DB_ECM("ECM : state %s%s",
+ (smc->mib.fddiSMTECMState & AFLAG) ? "ACTIONS " : "",
+ ecm_states[smc->mib.fddiSMTECMState & ~AFLAG]) ;
+ DB_ECM(" event %s\n",ecm_events[event],0) ;
+ state = smc->mib.fddiSMTECMState ;
+ ecm_fsm(smc,event) ;
+ event = 0 ;
+ } while (state != smc->mib.fddiSMTECMState) ;
+ ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
+}
+
+/*
+ process ECM event
+*/
+static void ecm_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+ int ls_a ; /* current line state PHY A */
+ int ls_b ; /* current line state PHY B */
+ int p ; /* ports */
+
+
+ smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
+ if (cmd == EC_CONNECT)
+ smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
+
+ /* For AIX event notification: */
+ /* Is a disconnect command remotely issued ? */
+ if (cmd == EC_DISCONNECT &&
+ smc->mib.fddiSMTRemoteDisconnectFlag == TRUE)
+ AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
+ FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
+ smt_get_error_word(smc) );
+
+ /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
+ if (cmd == EC_CONNECT) {
+ smc->e.DisconnectFlag = FALSE ;
+ }
+ else if (cmd == EC_DISCONNECT) {
+ smc->e.DisconnectFlag = TRUE ;
+ }
+
+ switch(smc->mib.fddiSMTECMState) {
+ case ACTIONS(EC0_OUT) :
+ /*
+ * We do not perform a path test
+ */
+ smc->e.path_test = PT_PASSED ;
+ smc->e.ecm_line_state = FALSE ;
+ stop_ecm_timer(smc) ;
+ ACTIONS_DONE() ;
+ break ;
+ case EC0_OUT:
+ /*EC01*/
+ if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
+ && smc->e.path_test==PT_PASSED) {
+ GO_STATE(EC1_IN) ;
+ break ;
+ }
+ /*EC05*/
+ else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
+ smc->mib.fddiSMTBypassPresent &&
+ (smc->s.sas == SMT_DAS)) {
+ GO_STATE(EC5_INSERT) ;
+ break ;
+ }
+ break;
+ case ACTIONS(EC1_IN) :
+ stop_ecm_timer(smc) ;
+ smc->e.trace_prop = 0 ;
+ sm_ma_control(smc,MA_TREQ) ;
+ for (p = 0 ; p < NUMPHYS ; p++)
+ if (smc->mib.p[p].fddiPORTHardwarePresent)
+ queue_event(smc,EVENT_PCMA+p,PC_START) ;
+ ACTIONS_DONE() ;
+ break ;
+ case EC1_IN:
+ /*EC12*/
+ if (cmd == EC_TRACE_PROP) {
+ prop_actions(smc) ;
+ GO_STATE(EC2_TRACE) ;
+ break ;
+ }
+ /*EC13*/
+ else if (cmd == EC_DISCONNECT) {
+ GO_STATE(EC3_LEAVE) ;
+ break ;
+ }
+ break;
+ case ACTIONS(EC2_TRACE) :
+ start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
+ EC_TIMEOUT_TMAX) ;
+ ACTIONS_DONE() ;
+ break ;
+ case EC2_TRACE :
+ /*EC22*/
+ if (cmd == EC_TRACE_PROP) {
+ prop_actions(smc) ;
+ GO_STATE(EC2_TRACE) ;
+ break ;
+ }
+ /*EC23a*/
+ else if (cmd == EC_DISCONNECT) {
+ smc->e.path_test = PT_EXITING ;
+ GO_STATE(EC3_LEAVE) ;
+ break ;
+ }
+ /*EC23b*/
+ else if (smc->e.path_test == PT_PENDING) {
+ GO_STATE(EC3_LEAVE) ;
+ break ;
+ }
+ /*EC23c*/
+ else if (cmd == EC_TIMEOUT_TMAX) {
+ /* Trace_Max is expired */
+ /* -> send AIX_EVENT */
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
+ (u_long) FDDI_SMT_ERROR, (u_long)
+ FDDI_TRACE_MAX, smt_get_error_word(smc));
+ smc->e.path_test = PT_PENDING ;
+ GO_STATE(EC3_LEAVE) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(EC3_LEAVE) :
+ start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
+ for (p = 0 ; p < NUMPHYS ; p++)
+ queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
+ ACTIONS_DONE() ;
+ break ;
+ case EC3_LEAVE:
+ /*EC30*/
+ if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
+ (smc->e.path_test != PT_PENDING)) {
+ GO_STATE(EC0_OUT) ;
+ break ;
+ }
+ /*EC34*/
+ else if (cmd == EC_TIMEOUT_TD &&
+ (smc->e.path_test == PT_PENDING)) {
+ GO_STATE(EC4_PATH_TEST) ;
+ break ;
+ }
+ /*EC31*/
+ else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
+ GO_STATE(EC1_IN) ;
+ break ;
+ }
+ /*EC33*/
+ else if (cmd == EC_DISCONNECT &&
+ smc->e.path_test == PT_PENDING) {
+ smc->e.path_test = PT_EXITING ;
+ /*
+ * stay in state - state will be left via timeout
+ */
+ }
+ /*EC37*/
+ else if (cmd == EC_TIMEOUT_TD &&
+ smc->mib.fddiSMTBypassPresent &&
+ smc->e.path_test != PT_PENDING) {
+ GO_STATE(EC7_DEINSERT) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(EC4_PATH_TEST) :
+ stop_ecm_timer(smc) ;
+ smc->e.path_test = PT_TESTING ;
+ start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
+ /* now perform path test ... just a simulation */
+ ACTIONS_DONE() ;
+ break ;
+ case EC4_PATH_TEST :
+ /* path test done delay */
+ if (cmd == EC_TEST_DONE)
+ smc->e.path_test = PT_PASSED ;
+
+ if (smc->e.path_test == PT_FAILED)
+ RS_SET(smc,RS_PATHTEST) ;
+
+ /*EC40a*/
+ if (smc->e.path_test == PT_FAILED &&
+ !smc->mib.fddiSMTBypassPresent) {
+ GO_STATE(EC0_OUT) ;
+ break ;
+ }
+ /*EC40b*/
+ else if (cmd == EC_DISCONNECT &&
+ !smc->mib.fddiSMTBypassPresent) {
+ GO_STATE(EC0_OUT) ;
+ break ;
+ }
+ /*EC41*/
+ else if (smc->e.path_test == PT_PASSED) {
+ GO_STATE(EC1_IN) ;
+ break ;
+ }
+ /*EC47a*/
+ else if (smc->e.path_test == PT_FAILED &&
+ smc->mib.fddiSMTBypassPresent) {
+ GO_STATE(EC7_DEINSERT) ;
+ break ;
+ }
+ /*EC47b*/
+ else if (cmd == EC_DISCONNECT &&
+ smc->mib.fddiSMTBypassPresent) {
+ GO_STATE(EC7_DEINSERT) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(EC5_INSERT) :
+ sm_pm_bypass_req(smc,BP_INSERT);
+ start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
+ ACTIONS_DONE() ;
+ break ;
+ case EC5_INSERT :
+ /*EC56*/
+ if (cmd == EC_TIMEOUT_INMAX) {
+ GO_STATE(EC6_CHECK) ;
+ break ;
+ }
+ /*EC57*/
+ else if (cmd == EC_DISCONNECT) {
+ GO_STATE(EC7_DEINSERT) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(EC6_CHECK) :
+ /*
+ * in EC6_CHECK, we *POLL* the line state !
+ * check whether both bypass switches have switched.
+ */
+ start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
+ smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */
+ (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */
+ (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */
+ ACTIONS_DONE() ;
+ break ;
+ case EC6_CHECK :
+ ls_a = sm_pm_get_ls(smc,PA) ;
+ ls_b = sm_pm_get_ls(smc,PB) ;
+
+ /*EC61*/
+ if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
+ ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
+ smc->e.sb_flag = FALSE ;
+ smc->e.ecm_line_state = FALSE ;
+ GO_STATE(EC1_IN) ;
+ break ;
+ }
+ /*EC66*/
+ else if (!smc->e.sb_flag &&
+ (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
+ ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
+ smc->e.sb_flag = TRUE ;
+ DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ;
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+ FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
+ smt_get_error_word(smc));
+ }
+ /*EC67*/
+ else if (cmd == EC_DISCONNECT) {
+ smc->e.ecm_line_state = FALSE ;
+ GO_STATE(EC7_DEINSERT) ;
+ break ;
+ }
+ else {
+ /*
+ * restart poll
+ */
+ start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
+ }
+ break ;
+ case ACTIONS(EC7_DEINSERT) :
+ sm_pm_bypass_req(smc,BP_DEINSERT);
+ start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
+ ACTIONS_DONE() ;
+ break ;
+ case EC7_DEINSERT:
+ /*EC70*/
+ if (cmd == EC_TIMEOUT_IMAX) {
+ GO_STATE(EC0_OUT) ;
+ break ;
+ }
+ /*EC75*/
+ else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
+ GO_STATE(EC5_INSERT) ;
+ break ;
+ }
+ break;
+ default:
+ SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
+ break;
+ }
+}
+
+#ifndef CONCENTRATOR
+/*
+ * trace propagation actions for SAS & DAS
+ */
+static void prop_actions(smc)
+struct s_smc *smc ;
+{
+ int port_in ;
+ int port_out ;
+
+ RS_SET(smc,RS_EVENT) ;
+ switch (smc->s.sas) {
+ case SMT_SAS :
+ port_in = port_out = pcm_get_s_port(smc) ;
+ break ;
+ case SMT_DAS :
+ port_in = cfm_get_mac_input(smc) ; /* PA or PB */
+ port_out = cfm_get_mac_output(smc) ; /* PA or PB */
+ break ;
+ case SMT_NAC :
+ SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
+ return ;
+ }
+
+ DB_ECM("ECM : prop_actions - trace_prop %d\n", smc->e.trace_prop,0) ;
+ DB_ECM("ECM : prop_actions - in %d out %d\n", port_in,port_out) ;
+
+ if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
+ /* trace initiatior */
+ DB_ECM("ECM : initiate TRACE on PHY %c\n",'A'+port_in-PA,0) ;
+ queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
+ }
+ else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
+ port_out != PA) {
+ /* trace propagate upstream */
+ DB_ECM("ECM : propagate TRACE on PHY B\n",0,0) ;
+ queue_event(smc,EVENT_PCMB,PC_TRACE) ;
+ }
+ else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
+ port_out != PB) {
+ /* trace propagate upstream */
+ DB_ECM("ECM : propagate TRACE on PHY A\n",0,0) ;
+ queue_event(smc,EVENT_PCMA,PC_TRACE) ;
+ }
+ else {
+ /* signal trace termination */
+ DB_ECM("ECM : TRACE terminated\n",0,0) ;
+ smc->e.path_test = PT_PENDING ;
+ }
+ smc->e.trace_prop = 0 ;
+}
+#else
+/*
+ * trace propagation actions for Concentrator
+ */
+static void prop_actions(smc)
+struct s_smc *smc ;
+{
+ int initiator ;
+ int upstream ;
+ int p ;
+
+ RS_SET(smc,RS_EVENT) ;
+ while (smc->e.trace_prop) {
+ DB_ECM("ECM : prop_actions - trace_prop %d\n",
+ smc->e.trace_prop,0) ;
+
+ if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
+ initiator = ENTITY_MAC ;
+ smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
+ DB_ECM("ECM: MAC initiates trace\n",0,0) ;
+ }
+ else {
+ for (p = NUMPHYS-1 ; p >= 0 ; p--) {
+ if (smc->e.trace_prop &
+ ENTITY_BIT(ENTITY_PHY(p)))
+ break ;
+ }
+ initiator = ENTITY_PHY(p) ;
+ smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
+ }
+ upstream = cem_get_upstream(smc,initiator) ;
+
+ if (upstream == ENTITY_MAC) {
+ /* signal trace termination */
+ DB_ECM("ECM : TRACE terminated\n",0,0) ;
+ smc->e.path_test = PT_PENDING ;
+ }
+ else {
+ /* trace propagate upstream */
+ DB_ECM("ECM : propagate TRACE on PHY %d\n",upstream,0) ;
+ queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
+ }
+ }
+}
+#endif
+
+
+/*
+ * SMT timer interface
+ * start ECM timer
+ */
+static void start_ecm_timer(smc,value,event)
+struct s_smc *smc ;
+u_long value;
+int event ;
+{
+ smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
+}
+
+/*
+ * SMT timer interface
+ * stop ECM timer
+ */
+static void stop_ecm_timer(smc)
+struct s_smc *smc ;
+{
+ if (smc->e.ecm_timer.tm_active)
+ smt_timer_stop(smc,&smc->e.ecm_timer) ;
+}
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
new file mode 100644
index 000000000..868237b30
--- /dev/null
+++ b/drivers/net/skfp/ess.c
@@ -0,0 +1,732 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * *******************************************************************
+ * This SBA code implements the Synchronous Bandwidth Allocation
+ * functions described in the "FDDI Synchronous Forum Implementer's
+ * Agreement" dated December 1th, 1993.
+ * *******************************************************************
+ *
+ * PURPOSE: The purpose of this function is to control
+ * synchronous allocations on a single FDDI segment.
+ * Allocations are limited to the primary FDDI ring.
+ * The SBM provides recovery mechanisms to recover
+ * unused bandwidth also resolves T_Neg and
+ * reconfiguration changes. Many of the SBM state
+ * machine inputs are sourced by the underlying
+ * FDDI sub-system supporting the SBA application.
+ *
+ * *******************************************************************
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+
+#ifndef SLIM_SMT
+
+#ifdef ESS
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)ess.c 1.10 96/02/23 (C) SK" ;
+#define LINT_USE(x)
+#else
+#define LINT_USE(x) (x)=(x)
+#endif
+#define MS2BCLK(x) ((x)*12500L)
+
+/*
+ -------------------------------------------------------------
+ LOCAL VARIABLES:
+ -------------------------------------------------------------
+*/
+
+static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F,
+ SMT_P3210, SMT_P0019, SMT_P001A,
+ SMT_P001D, 0 } ;
+
+static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210,
+ SMT_P001A, 0 } ;
+
+static const struct fddi_addr smt_sba_da = {0x80,0x01,0x43,0x00,0x80,0x0C} ;
+static const struct fddi_addr null_addr = {0,0,0,0,0,0} ;
+
+/*
+ -------------------------------------------------------------
+ GLOBAL VARIABLES:
+ -------------------------------------------------------------
+*/
+
+
+/*
+ -------------------------------------------------------------
+ LOCAL FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+static void ess_send_response(), ess_config_fifo(),
+ ess_send_alc_req(), ess_send_frame() ;
+
+/*
+ -------------------------------------------------------------
+ EXTERNAL FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+extern void *sm_to_para() ;
+
+extern void smt_send_frame(), smt_free_mbuf(),
+ set_formac_tsync(), formac_reinit_tx() ;
+
+extern int smt_check_para() ;
+
+extern SMbuf *smt_get_mbuf(), *smt_build_frame() ;
+
+extern u_long smt_get_tid() ;
+
+/*
+ -------------------------------------------------------------
+ PUBLIC FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+ void ess_timer_poll(), ess_para_change() ;
+
+ int ess_raf_received_pack(), process_bw_alloc() ;
+
+
+/*
+ * --------------------------------------------------------------------------
+ * End Station Support (ESS)
+ * --------------------------------------------------------------------------
+ */
+
+/*
+ * evaluate the RAF frame
+ */
+int ess_raf_received_pack(smc,mb,sm,fs)
+struct s_smc *smc ;
+SMbuf *mb ;
+struct smt_header *sm ;
+int fs ;
+{
+ void *p ; /* universal pointer */
+ struct smt_p_0016 *cmd ; /* para: command for the ESS */
+ SMbuf *db ;
+ u_long msg_res_type ; /* recource type */
+ u_long payload, overhead ;
+ int local ;
+ int i ;
+
+ /*
+ * Message Processing Code
+ */
+ local = ((fs & L_INDICATOR) != 0) ;
+
+ /*
+ * get the resource type
+ */
+ if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) {
+ DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ;
+ return(fs) ;
+ }
+ msg_res_type = ((struct smt_p_0015 *)p)->res_type ;
+
+ /*
+ * get the pointer to the ESS command
+ */
+ if (!(cmd = (struct smt_p_0016 *) sm_to_para(smc,sm,SMT_P0016))) {
+ /*
+ * error in frame: para ESS command was not found
+ */
+ DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0);
+ return(fs) ;
+ }
+
+ DB_ESSN(2,"fc %x ft %x\n",sm->smt_class,sm->smt_type) ;
+ DB_ESSN(2,"ver %x tran %lx\n",sm->smt_version,sm->smt_tid) ;
+ DB_ESSN(2,"stn_id %s\n",addr_to_string(&sm->smt_source),0) ;
+
+ DB_ESSN(2,"infolen %x res %x\n",sm->smt_len, msg_res_type) ;
+ DB_ESSN(2,"sbacmd %x\n",cmd->sba_cmd,0) ;
+
+ /*
+ * evaluate the ESS command
+ */
+ switch (cmd->sba_cmd) {
+
+ /*
+ * Process an ESS Allocation Request
+ */
+ case REQUEST_ALLOCATION :
+ /*
+ * check for an RAF Request (Allocation Request)
+ */
+ if (sm->smt_type == SMT_REQUEST) {
+ /*
+ * process the Allocation request only if the frame is
+ * local and no static allocation is used
+ */
+ if (!local || smc->mib.fddiESSPayload)
+ return(fs) ;
+
+ p = (void *) sm_to_para(smc,sm,SMT_P0019) ;
+ for (i = 0; i < 5; i++) {
+ if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) {
+ return(fs) ;
+ }
+ }
+
+ /*
+ * Note: The Application should send a LAN_LOC_FRAME.
+ * The ESS do not send the Frame to the network!
+ */
+ smc->ess.alloc_trans_id = sm->smt_tid ;
+ DB_ESS("ESS: save Alloc Req Trans ID %lx\n",sm->smt_tid,0);
+ p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+ ((struct smt_p_320f *)p)->mib_payload =
+ smc->mib.a[PATH0].fddiPATHSbaPayload ;
+ p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+ ((struct smt_p_3210 *)p)->mib_overhead =
+ smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+ sm->smt_dest = smt_sba_da ;
+
+ if (smc->ess.local_sba_active)
+ return(fs | I_INDICATOR) ;
+
+ if (!(db = smt_get_mbuf(smc)))
+ return(fs) ;
+
+ db->sm_len = mb->sm_len ;
+ db->sm_off = mb->sm_off ;
+ memcpy(((char *)(db->sm_data+db->sm_off)),(char *)sm,
+ (int)db->sm_len) ;
+ dump_smt(smc,
+ (struct smt_header *)(db->sm_data+db->sm_off),
+ "RAF") ;
+ smt_send_frame(smc,db,FC_SMT_INFO,0) ;
+ return(fs) ;
+ }
+
+ /*
+ * The RAF frame is an Allocation Response !
+ * check the parameters
+ */
+ if (smt_check_para(smc,sm,plist_raf_alc_res)) {
+ DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
+ return(fs) ;
+ }
+
+ /*
+ * VERIFY THE FRAME IS WELL BUILT:
+ *
+ * 1. path index = primary ring only
+ * 2. resource type = sync bw only
+ * 3. trans action id = alloc_trans_id
+ * 4. reason code = success
+ *
+ * If any are violated, discard the RAF frame
+ */
+ if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index
+ != PRIMARY_RING) ||
+ (msg_res_type != SYNC_BW) ||
+ (((struct smt_p_reason *)sm_to_para(smc,sm,SMT_P0012))->rdf_reason
+ != SMT_RDF_SUCCESS) ||
+ (sm->smt_tid != smc->ess.alloc_trans_id)) {
+
+ DB_ESS("ESS: Allocation Responce not accepted\n",0,0) ;
+ return(fs) ;
+ }
+
+ /*
+ * Extract message parameters
+ */
+ p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+ payload = ((struct smt_p_320f *)p)->mib_payload ;
+ p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+ overhead = ((struct smt_p_3210 *)p)->mib_overhead ;
+
+ DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ;
+
+ /*
+ * process the bandwidth allocation
+ */
+ (void)process_bw_alloc(smc,(long)payload,(long)overhead) ;
+
+ return(fs) ;
+ /* end of Process Allocation Request */
+
+ /*
+ * Process an ESS Change Request
+ */
+ case CHANGE_ALLOCATION :
+ /*
+ * except only replies
+ */
+ if (sm->smt_type != SMT_REQUEST) {
+ DB_ESS("ESS: Do not process Change Responses\n",0,0) ;
+ return(fs) ;
+ }
+
+ /*
+ * check the para for the Change Request
+ */
+ if (smt_check_para(smc,sm,plist_raf_chg_req)) {
+ DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
+ return(fs) ;
+ }
+
+ /*
+ * Verify the path index and resource
+ * type are correct. If any of
+ * these are false, don't process this
+ * change request frame.
+ */
+ if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index
+ != PRIMARY_RING) || (msg_res_type != SYNC_BW)) {
+ DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ;
+ return(fs) ;
+ }
+
+ /*
+ * Extract message queue parameters
+ */
+ p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+ payload = ((struct smt_p_320f *)p)->mib_payload ;
+ p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+ overhead = ((struct smt_p_3210 *)p)->mib_overhead ;
+
+ DB_ESSN(2,"ESS: Change Request from %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ;
+
+ /*
+ * process the bandwidth allocation
+ */
+ if(!process_bw_alloc(smc,(long)payload,(long)overhead))
+ return(fs) ;
+
+ /*
+ * send an RAF Change Reply
+ */
+ ess_send_response(smc,sm,CHANGE_ALLOCATION) ;
+
+ return(fs) ;
+ /* end of Process Change Request */
+
+ /*
+ * Process Report Response
+ */
+ case REPORT_ALLOCATION :
+ /*
+ * except only requests
+ */
+ if (sm->smt_type != SMT_REQUEST) {
+ DB_ESS("ESS: Do not process a Report Reply\n",0,0) ;
+ return(fs) ;
+ }
+
+ DB_ESSN(2,"ESS: Report Request from %s\n",
+ addr_to_string(&(sm->smt_source)),0) ;
+
+ /*
+ * verify that the resource type is sync bw only
+ */
+ if (msg_res_type != SYNC_BW) {
+ DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ;
+ return(fs) ;
+ }
+
+ /*
+ * send an RAF Change Reply
+ */
+ ess_send_response(smc,sm,REPORT_ALLOCATION) ;
+
+ return(fs) ;
+ /* end of Process Report Request */
+
+ default:
+ /*
+ * error in frame
+ */
+ DB_ESS("ESS: ignoring RAF with bad sba_cmd\n",0,0) ;
+ break ;
+ }
+
+ return(fs) ;
+}
+
+/*
+ * determines the synchronous bandwidth, set the TSYNC register and the
+ * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
+ */
+int process_bw_alloc(smc,payload,overhead)
+struct s_smc *smc ;
+long payload ;
+long overhead ;
+{
+ /*
+ * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
+ * if the payload is greater than zero.
+ * For the SBAPayload and the SBAOverhead we have the following
+ * unite quations
+ * _ _
+ * | bytes |
+ * SBAPayload = | 8000 ------ |
+ * | s |
+ * - -
+ * _ _
+ * | bytes |
+ * SBAOverhead = | ------ |
+ * | T-NEG |
+ * - -
+ *
+ * T-NEG is discribed by the equation:
+ *
+ * (-) fddiMACT-NEG
+ * T-NEG = -------------------
+ * 12500000 1/s
+ *
+ * The number of bytes we are able to send is the payload
+ * plus the overhead.
+ *
+ * bytes T-NEG SBAPayload 8000 bytes/s
+ * sync_bw = SBAOverhead ------ + -----------------------------
+ * T-NEG T-NEG
+ *
+ *
+ * 1
+ * sync_bw = SBAOverhead + ---- (-)fddiMACT-NEG * SBAPayload
+ * 1562
+ *
+ */
+
+ /*
+ * set the mib attributes fddiPATHSbaOverhead, fddiPATHSbaPayload
+ */
+/* if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) {
+ DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ;
+ return(FALSE) ;
+ }
+ if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) {
+ DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ;
+ return(FALSE) ;
+ } */
+
+ /* premliminary */
+ if (payload > MAX_PAYLOAD || overhead > 5000) {
+ DB_ESS("ESS: payload / overhead not accepted\n",0,0) ;
+ return(FALSE) ;
+ }
+
+ /*
+ * start the iterative allocation process if the payload or the overhead
+ * are smaller than the parsed values
+ */
+ if (smc->mib.fddiESSPayload &&
+ ((u_long)payload != smc->mib.fddiESSPayload ||
+ (u_long)overhead != smc->mib.fddiESSOverhead)) {
+ smc->ess.raf_act_timer_poll = TRUE ;
+ smc->ess.timer_count = 0 ;
+ }
+
+ /*
+ * evulate the Payload
+ */
+ if (payload) {
+ DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit on\n",0,0) ;
+ smc->ess.sync_bw_available = TRUE ;
+
+ smc->ess.sync_bw = overhead -
+ (long)smc->mib.m[MAC0].fddiMACT_Neg *
+ payload / 1562 ;
+ }
+ else {
+ DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit off\n",0,0) ;
+ smc->ess.sync_bw_available = FALSE ;
+ smc->ess.sync_bw = 0 ;
+ overhead = 0 ;
+ }
+
+ smc->mib.a[PATH0].fddiPATHSbaPayload = payload ;
+ smc->mib.a[PATH0].fddiPATHSbaOverhead = overhead ;
+
+
+ DB_ESSN(2,"tsync = %lx\n",smc->ess.sync_bw,0) ;
+
+ ess_config_fifo(smc) ;
+ set_formac_tsync(smc,smc->ess.sync_bw) ;
+ return(TRUE) ;
+}
+
+static void ess_send_response(smc,sm,sba_cmd)
+struct s_smc *smc ;
+struct smt_header *sm ;
+int sba_cmd ;
+{
+ struct smt_sba_chg *chg ;
+ SMbuf *mb ;
+ void *p ;
+
+ /*
+ * get and initialize the responce frame
+ */
+ if (sba_cmd == CHANGE_ALLOCATION) {
+ if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY,
+ sizeof(struct smt_sba_chg))))
+ return ;
+ }
+ else {
+ if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY,
+ sizeof(struct smt_sba_rep_res))))
+ return ;
+ }
+
+ chg = smtod(mb,struct smt_sba_chg *) ;
+ chg->smt.smt_tid = sm->smt_tid ;
+ chg->smt.smt_dest = sm->smt_source ;
+
+ /* set P15 */
+ chg->s_type.para.p_type = SMT_P0015 ;
+ chg->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ;
+ chg->s_type.res_type = SYNC_BW ;
+
+ /* set P16 */
+ chg->cmd.para.p_type = SMT_P0016 ;
+ chg->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ;
+ chg->cmd.sba_cmd = sba_cmd ;
+
+ /* set P320B */
+ chg->path.para.p_type = SMT_P320B ;
+ chg->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ;
+ chg->path.mib_index = SBAPATHINDEX ;
+ chg->path.path_pad = (u_short)NULL ;
+ chg->path.path_index = PRIMARY_RING ;
+
+ /* set P320F */
+ chg->payload.para.p_type = SMT_P320F ;
+ chg->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ;
+ chg->payload.mib_index = SBAPATHINDEX ;
+ chg->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+ /* set P3210 */
+ chg->overhead.para.p_type = SMT_P3210 ;
+ chg->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ;
+ chg->overhead.mib_index = SBAPATHINDEX ;
+ chg->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+ if (sba_cmd == CHANGE_ALLOCATION) {
+ /* set P1A */
+ chg->cat.para.p_type = SMT_P001A ;
+ chg->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ;
+ p = (void *) sm_to_para(smc,sm,SMT_P001A) ;
+ chg->cat.category = ((struct smt_p_001a *)p)->category ;
+ }
+ dump_smt(smc,(struct smt_header *)chg,"RAF") ;
+ ess_send_frame(smc,mb) ;
+}
+
+
+void ess_timer_poll(smc)
+struct s_smc *smc ;
+{
+ if (!smc->ess.raf_act_timer_poll)
+ return ;
+
+ DB_ESSN(2,"ESS: timer_poll\n",0,0) ;
+
+ smc->ess.timer_count++ ;
+ if (smc->ess.timer_count == 10) {
+ smc->ess.timer_count = 0 ;
+ ess_send_alc_req(smc) ;
+ }
+}
+
+static void ess_send_alc_req(smc)
+struct s_smc *smc ;
+{
+ struct smt_sba_alc_req *req ;
+ SMbuf *mb ;
+
+ /*
+ * send never allocation request where the requested payload and
+ * overhead is zero or deallocate bandwidht when no bandwidth is
+ * parsed
+ */
+ if (!smc->mib.fddiESSPayload) {
+ smc->mib.fddiESSOverhead = 0 ;
+ }
+ else {
+ if (!smc->mib.fddiESSOverhead)
+ smc->mib.fddiESSOverhead = DEFAULT_OV ;
+ }
+
+ if (smc->mib.fddiESSOverhead ==
+ smc->mib.a[PATH0].fddiPATHSbaOverhead &&
+ smc->mib.fddiESSPayload ==
+ smc->mib.a[PATH0].fddiPATHSbaPayload){
+ smc->ess.raf_act_timer_poll = FALSE ;
+ smc->ess.timer_count = 7 ; /* next RAF alc req after 3 s */
+ return ;
+ }
+
+ /*
+ * get and initialize the responce frame
+ */
+ if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST,
+ sizeof(struct smt_sba_alc_req))))
+ return ;
+ req = smtod(mb,struct smt_sba_alc_req *) ;
+ req->smt.smt_tid = smc->ess.alloc_trans_id = smt_get_tid(smc) ;
+ req->smt.smt_dest = smt_sba_da ;
+
+ /* set P15 */
+ req->s_type.para.p_type = SMT_P0015 ;
+ req->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ;
+ req->s_type.res_type = SYNC_BW ;
+
+ /* set P16 */
+ req->cmd.para.p_type = SMT_P0016 ;
+ req->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ;
+ req->cmd.sba_cmd = REQUEST_ALLOCATION ;
+
+ /*
+ * set the parameter type and parameter lenght of all used
+ * parameters
+ */
+
+ /* set P320B */
+ req->path.para.p_type = SMT_P320B ;
+ req->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ;
+ req->path.mib_index = SBAPATHINDEX ;
+ req->path.path_pad = (u_short)NULL ;
+ req->path.path_index = PRIMARY_RING ;
+
+ /* set P0017 */
+ req->pl_req.para.p_type = SMT_P0017 ;
+ req->pl_req.para.p_len = sizeof(struct smt_p_0017) - PARA_LEN ;
+ req->pl_req.sba_pl_req = smc->mib.fddiESSPayload -
+ smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+ /* set P0018 */
+ req->ov_req.para.p_type = SMT_P0018 ;
+ req->ov_req.para.p_len = sizeof(struct smt_p_0018) - PARA_LEN ;
+ req->ov_req.sba_ov_req = smc->mib.fddiESSOverhead -
+ smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+ /* set P320F */
+ req->payload.para.p_type = SMT_P320F ;
+ req->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ;
+ req->payload.mib_index = SBAPATHINDEX ;
+ req->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+ /* set P3210 */
+ req->overhead.para.p_type = SMT_P3210 ;
+ req->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ;
+ req->overhead.mib_index = SBAPATHINDEX ;
+ req->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+ /* set P19 */
+ req->a_addr.para.p_type = SMT_P0019 ;
+ req->a_addr.para.p_len = sizeof(struct smt_p_0019) - PARA_LEN ;
+ req->a_addr.sba_pad = (u_short)NULL ;
+ req->a_addr.alloc_addr = null_addr ;
+
+ /* set P1A */
+ req->cat.para.p_type = SMT_P001A ;
+ req->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ;
+ req->cat.category = smc->mib.fddiESSCategory ;
+
+ /* set P1B */
+ req->tneg.para.p_type = SMT_P001B ;
+ req->tneg.para.p_len = sizeof(struct smt_p_001b) - PARA_LEN ;
+ req->tneg.max_t_neg = smc->mib.fddiESSMaxTNeg ;
+
+ /* set P1C */
+ req->segm.para.p_type = SMT_P001C ;
+ req->segm.para.p_len = sizeof(struct smt_p_001c) - PARA_LEN ;
+ req->segm.min_seg_siz = smc->mib.fddiESSMinSegmentSize ;
+
+ dump_smt(smc,(struct smt_header *)req,"RAF") ;
+ ess_send_frame(smc,mb) ;
+}
+
+static void ess_send_frame(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+ /*
+ * check if the frame must be send to the own ESS
+ */
+ if (smc->ess.local_sba_active) {
+ /*
+ * Send the Change Reply to the local SBA
+ */
+ DB_ESS("ESS:Send to the local SBA\n",0,0) ;
+ if (!smc->ess.sba_reply_pend)
+ smc->ess.sba_reply_pend = mb ;
+ else {
+ DB_ESS("Frame is lost - another frame was pending\n",0,0);
+ smt_free_mbuf(smc,mb) ;
+ }
+ }
+ else {
+ /*
+ * Send the SBA RAF Change Reply to the network
+ */
+ DB_ESS("ESS:Send to the network\n",0,0) ;
+ smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
+ }
+}
+
+void ess_para_change(smc)
+struct s_smc *smc ;
+{
+ (void)process_bw_alloc(smc,(long)smc->mib.a[PATH0].fddiPATHSbaPayload,
+ (long)smc->mib.a[PATH0].fddiPATHSbaOverhead) ;
+}
+
+static void ess_config_fifo(smc)
+struct s_smc *smc ;
+{
+ /*
+ * if nothing to do exit
+ */
+ if (smc->mib.a[PATH0].fddiPATHSbaPayload) {
+ if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON &&
+ (smc->hw.fp.fifo.fifo_config_mode&SEND_ASYNC_AS_SYNC) ==
+ smc->mib.fddiESSSynchTxMode) {
+ return ;
+ }
+ }
+ else {
+ if (!(smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON)) {
+ return ;
+ }
+ }
+
+ /*
+ * split up the FIFO and reinitialize the queues
+ */
+ formac_reinit_tx(smc) ;
+}
+
+#endif /* ESS */
+
+#endif /* no SLIM_SMT */
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
new file mode 100644
index 000000000..83a935791
--- /dev/null
+++ b/drivers/net/skfp/fplustm.c
@@ -0,0 +1,1645 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FORMAC+ Driver for tag mode
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "can.c"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ;
+#endif
+
+#ifndef UNUSED
+#ifdef lint
+#define UNUSED(x) (x) = (x)
+#else
+#define UNUSED(x)
+#endif
+#endif
+
+#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1)
+#define MS2BCLK(x) ((x)*12500L)
+#define US2BCLK(x) ((x)*1250L)
+
+/*
+ * prototypes for static function
+ */
+static void build_claim_beacon() ;
+static int init_mac() ;
+static void rtm_init() ;
+static void smt_split_up_fifo() ;
+
+#if (!defined(NO_SMT_PANIC) || defined(DEBUG))
+static char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n";
+static char cam_warning [] = "E_SMT_004: CAM still busy\n";
+#endif
+
+#define DUMMY_READ() smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP))
+
+#define CHECK_NPP() { unsigned k = 10000 ;\
+ while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\
+ if (!k) { \
+ SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \
+ } \
+ }
+
+#define CHECK_CAM() { unsigned k = 10 ;\
+ while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\
+ if (!k) { \
+ SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \
+ } \
+ }
+
+const struct fddi_addr fddi_broadcast = {0xff,0xff,0xff,0xff,0xff,0xff};
+static const struct fddi_addr null_addr = {0,0,0,0,0,0} ;
+static const struct fddi_addr dbeacon_multi = {0x01,0x80,0xc2,0x00,0x01,0x00};
+
+static const u_short my_said = 0xffff ; /* short address (n.u.) */
+static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */
+
+/*
+ * define my address
+ */
+#ifdef USE_CAN_ADDR
+#define MA smc->hw.fddi_canon_addr
+#else
+#define MA smc->hw.fddi_home_addr
+#endif
+
+
+/*
+ * usefull interrupt bits
+ */
+static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ;
+static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0|
+ FM_STBURS | FM_STBURA0 ;
+
+ /* delete FM_SRBFL after tests */
+static int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL |
+ FM_SMYCLM ;
+static int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR |
+ FM_SERRCTR | FM_SLSTCTR |
+ FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ;
+
+static int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ;
+static int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ;
+
+static int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC |
+ FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ;
+
+
+static u_long mac_get_tneg(smc)
+struct s_smc *smc ;
+{
+ u_long tneg ;
+
+ tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ;
+ return((u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) |
+ 0xffe00000L)) ;
+}
+
+void mac_update_counter(smc)
+struct s_smc *smc ;
+{
+ smc->mib.m[MAC0].fddiMACFrame_Ct =
+ (smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L)
+ + (u_short) inpw(FM_A(FM_FCNTR)) ;
+ smc->mib.m[MAC0].fddiMACLost_Ct =
+ (smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L)
+ + (u_short) inpw(FM_A(FM_LCNTR)) ;
+ smc->mib.m[MAC0].fddiMACError_Ct =
+ (smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L)
+ + (u_short) inpw(FM_A(FM_ECNTR)) ;
+ smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ;
+#ifdef SMT_REAL_TOKEN_CT
+ /*
+ * If the token counter is emulated it is updated in smt_event.
+ */
+ TBD
+#else
+ smt_emulate_token_ct( smc, MAC0 );
+#endif
+}
+
+/*
+ * write long value into buffer memory over memory data register (MDR),
+ */
+void write_mdr(smc,val)
+struct s_smc *smc ;
+u_long val;
+{
+ CHECK_NPP() ;
+ MDRW(val) ;
+}
+
+/*
+ * read long value from buffer memory over memory data register (MDR),
+ */
+u_long read_mdr(smc,addr)
+struct s_smc *smc ;
+unsigned int addr;
+{
+ long p ;
+ CHECK_NPP() ;
+ MARR(addr) ;
+ outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ;
+ CHECK_NPP() ; /* needed for PCI to prevent from timeing violations */
+/* p = MDRR() ; */ /* bad read values if the workaround */
+ /* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/
+ /* is used */
+ p = (u_long)inpw(FM_A(FM_MDRU))<<16 ;
+ p += (u_long)inpw(FM_A(FM_MDRL)) ;
+ return(p) ;
+}
+/*
+ * clear buffer memory
+ */
+static void init_ram(smc)
+struct s_smc *smc ;
+{
+ u_short i ;
+
+ smc->hw.fp.fifo.rbc_ram_start = 0 ;
+ smc->hw.fp.fifo.rbc_ram_end =
+ smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ;
+ CHECK_NPP() ;
+ MARW(smc->hw.fp.fifo.rbc_ram_start) ;
+ for (i = smc->hw.fp.fifo.rbc_ram_start;
+ i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++)
+ write_mdr(smc,0L) ;
+ /* Erase the last byte too */
+ write_mdr(smc,0L) ;
+}
+
+/*
+ * set receive FIFO pointer
+ */
+static void set_recvptr(smc)
+struct s_smc *smc ;
+{
+ /*
+ * initialize the pointer for receive queue 1
+ */
+ outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* RPR1 */
+ outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* SWPR1 */
+ outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* WPR1 */
+ outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ; /* EARV1 */
+
+ /*
+ * initialize the pointer for receive queue 2
+ */
+ if (smc->hw.fp.fifo.rx2_fifo_size) {
+ outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+ outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+ outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+ outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+ }
+ else {
+ outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+ outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+ outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+ outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+ }
+}
+
+/*
+ * set transmit FIFO pointer
+ */
+static void set_txptr(smc)
+struct s_smc *smc ;
+{
+ outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ; /* reset transmit queues */
+
+ /*
+ * initialize the pointer for asynchronous transmit queue
+ */
+ outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* RPXA0 */
+ outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* SWPXA0 */
+ outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* WPXA0 */
+ outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ; /* EAA0 */
+
+ /*
+ * initialize the pointer for synchronous transmit queue
+ */
+ if (smc->hw.fp.fifo.tx_s_size) {
+ outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ;
+ outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ;
+ outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ;
+ outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ;
+ }
+ else {
+ outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+ outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+ outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+ outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ;
+ }
+}
+
+/*
+ * init memory buffer management registers
+ */
+static void init_rbc(smc)
+struct s_smc *smc ;
+{
+ u_short rbc_ram_addr ;
+
+ /*
+ * set unused pointers or permanent pointers
+ */
+ rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ;
+
+ outpw(FM_A(FM_RPXA1),rbc_ram_addr) ; /* a1-send pointer */
+ outpw(FM_A(FM_WPXA1),rbc_ram_addr) ;
+ outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ;
+ outpw(FM_A(FM_EAA1),rbc_ram_addr) ;
+
+ set_recvptr(smc) ;
+ set_txptr(smc) ;
+}
+
+/*
+ * init rx pointer
+ */
+static void init_rx(smc)
+struct s_smc *smc ;
+{
+ struct s_smt_rx_queue *queue ;
+
+ /*
+ * init all tx data structures for receive queue 1
+ */
+ smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ;
+ queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ;
+ queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ;
+
+ /*
+ * init all tx data structures for receive queue 2
+ */
+ smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ;
+ queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ;
+ queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ;
+}
+
+/*
+ * set the TSYNC register of the FORMAC to regulate synchronous transmission
+ */
+void set_formac_tsync(smc,sync_bw)
+struct s_smc *smc ;
+long sync_bw ;
+{
+ outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ;
+}
+
+/*
+ * init all tx data structures
+ */
+static void init_tx(smc)
+struct s_smc *smc ;
+{
+ struct s_smt_tx_queue *queue ;
+
+ /*
+ * init all tx data structures for the synchronous queue
+ */
+ smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ;
+ queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ;
+ queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ;
+
+#ifdef ESS
+ set_formac_tsync(smc,smc->ess.sync_bw) ;
+#endif
+
+ /*
+ * init all tx data structures for the asynchronous queue 0
+ */
+ smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ;
+ queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ;
+ queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ;
+
+
+ llc_recover_tx(smc) ;
+}
+
+static void mac_counter_init(smc)
+struct s_smc *smc ;
+{
+ int i ;
+ u_long *ec ;
+
+ /*
+ * clear FORMAC+ frame-, lost- and error counter
+ */
+ outpw(FM_A(FM_FCNTR),0) ;
+ outpw(FM_A(FM_LCNTR),0) ;
+ outpw(FM_A(FM_ECNTR),0) ;
+ /*
+ * clear internal error counter stucture
+ */
+ ec = (u_long *)&smc->hw.fp.err_stats ;
+ for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--)
+ *ec++ = 0L ;
+ smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ;
+}
+
+/*
+ * set FORMAC address, and t_request
+ */
+static void set_formac_addr(smc)
+struct s_smc *smc ;
+{
+ long t_requ = smc->mib.m[MAC0].fddiMACT_Req ;
+
+ outpw(FM_A(FM_SAID),my_said) ; /* set short address */
+ outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) +
+ smc->hw.fddi_home_addr.a[5])) ;
+ outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) +
+ smc->hw.fddi_home_addr.a[3])) ;
+ outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) +
+ smc->hw.fddi_home_addr.a[1])) ;
+
+ outpw(FM_A(FM_SAGP),my_sagp) ; /* set short group address */
+
+ outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) +
+ smc->hw.fp.group_addr.a[5])) ;
+ outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) +
+ smc->hw.fp.group_addr.a[3])) ;
+ outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) +
+ smc->hw.fp.group_addr.a[1])) ;
+
+ /* set r_request regs. (MSW & LSW of TRT ) */
+ outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ;
+ outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ;
+}
+
+void set_long(p,l)
+char *p;
+long l;
+{
+ p[0] = (char)(l >> 24) ;
+ p[1] = (char)(l >> 16) ;
+ p[2] = (char)(l >> 8) ;
+ p[3] = (char)(l >> 0) ;
+}
+
+/*
+ * copy TX descriptor to buffer mem
+ * append FC field and MAC frame
+ * if more bit is set in descr
+ * append pointer to descriptor (endless loop)
+ * else
+ * append 'end of chain' pointer
+ */
+static void copy_tx_mac(smc,td,mac,off,len)
+struct s_smc *smc ;
+u_long td; /* transmit descriptor */
+struct fddi_mac *mac; /* mac frame pointer */
+unsigned off; /* start address within buffer memory */
+int len ; /* lenght of the frame including the FC */
+{
+ int i ;
+ u_long *p ;
+
+ CHECK_NPP() ;
+ MARW(off) ; /* set memory address reg for writes */
+
+ p = (u_long *) mac ;
+ for (i = (len + 3)/4 ; i ; i--) {
+ if (i == 1) {
+ /* last word, set the tag bit */
+ outpw(FM_A(FM_CMDREG2),FM_ISTTB) ;
+ }
+ write_mdr(smc,MDR_REVERSE(*p)) ;
+ p++ ;
+ }
+
+ outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */
+ write_mdr(smc,td) ; /* write over memory data reg to buffer */
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(module;tests;3)
+ How to test directed beacon frames
+ ----------------------------------------------------------------
+
+ o Insert a break point in the function build_claim_beacon()
+ before calling copy_tx_mac() for building the claim frame.
+ o Modify the RM3_DETECT case so that the RM6_DETECT state
+ will always entered from the RM3_DETECT state (function rmt_fsm(),
+ rmt.c)
+ o Compile the driver.
+ o Set the parameter TREQ in the protocol.ini or net.cfg to a
+ small value to make sure your station will win the claim
+ process.
+ o Start the driver.
+ o When you reach the break point, modify the SA and DA address
+ of the claim frame (e.g. SA = DA = 10005affffff).
+ o When you see RM3_DETECT and RM6_DETECT, observe the direct
+ beacon frames on the UPPSLANA.
+
+ END_MANUAL_ENTRY
+ */
+static void directed_beacon(smc)
+struct s_smc *smc ;
+{
+ SK_LOC_DECL(u_long,a[2]) ;
+
+ /*
+ * set UNA in frame
+ * enable FORMAC to send endless queue of directed beacon
+ * important: the UNA starts at byte 1 (not at byte 0)
+ */
+ * (char *) a = (char) ((long)DBEACON_INFO<<24L) ;
+ a[1] = 0 ;
+ memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ;
+
+ CHECK_NPP() ;
+ /* set memory address reg for writes */
+ MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ;
+ write_mdr(smc,MDR_REVERSE(a[0])) ;
+ outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */
+ write_mdr(smc,MDR_REVERSE(a[1])) ;
+
+ outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ;
+}
+
+/*
+ setup claim & beacon pointer
+ NOTE :
+ special frame packets end with a pointer to their own
+ descriptor, and the MORE bit is set in the descriptor
+*/
+static void build_claim_beacon(smc,t_request)
+struct s_smc *smc ;
+u_long t_request;
+{
+ u_long td ;
+ int len ;
+ struct fddi_mac_sf *mac ;
+
+ /*
+ * build claim packet
+ */
+ len = 17 ;
+ td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ;
+ mac = &smc->hw.fp.mac_sfb ;
+ mac->mac_fc = FC_CLAIM ;
+ /* DA == SA in claim frame */
+ mac->mac_source = mac->mac_dest = MA ;
+ /* 2's complement */
+ set_long((char *)mac->mac_info,(long)t_request) ;
+
+ copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+ smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ;
+ /* set CLAIM start pointer */
+ outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ;
+
+ /*
+ * build beacon packet
+ */
+ len = 17 ;
+ td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ;
+ mac->mac_fc = FC_BEACON ;
+ mac->mac_source = MA ;
+ mac->mac_dest = null_addr ; /* DA == 0 in beacon frame */
+ set_long((char *) mac->mac_info,((long)BEACON_INFO<<24L) + 0 ) ;
+
+ copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+ smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ;
+ /* set beacon start pointer */
+ outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ;
+
+ /*
+ * build directed beacon packet
+ * contains optional UNA
+ */
+ len = 23 ;
+ td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ;
+ mac->mac_fc = FC_BEACON ;
+ mac->mac_source = MA ;
+ mac->mac_dest = dbeacon_multi ; /* multicast */
+ set_long((char *) mac->mac_info,((long)DBEACON_INFO<<24L) + 0 ) ;
+ set_long((char *) mac->mac_info+4,0L) ;
+ set_long((char *) mac->mac_info+8,0L) ;
+
+ copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+ smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF,len) ;
+
+ /* end of claim/beacon queue */
+ outpw(FM_A(FM_EACB),smc->hw.fp.fifo.rx1_fifo_start-1) ;
+
+ outpw(FM_A(FM_WPXSF),0) ;
+ outpw(FM_A(FM_RPXSF),0) ;
+}
+
+void formac_rcv_restart(smc)
+struct s_smc *smc ;
+{
+ /* enable receive function */
+ SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ;
+
+ outpw(FM_A(FM_CMDREG1),FM_ICLLR) ; /* clear receive lock */
+}
+
+void formac_tx_restart(smc)
+struct s_smc *smc ;
+{
+ outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */
+ outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */
+}
+
+static void enable_formac(smc)
+struct s_smc *smc ;
+{
+ /* set formac IMSK : 0 enables irq */
+ outpw(FM_A(FM_IMSK1U),~mac_imsk1u) ;
+ outpw(FM_A(FM_IMSK1L),~mac_imsk1l) ;
+ outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ;
+ outpw(FM_A(FM_IMSK2L),~mac_imsk2l) ;
+ outpw(FM_A(FM_IMSK3U),~mac_imsk3u) ;
+ outpw(FM_A(FM_IMSK3L),~mac_imsk3l) ;
+}
+
+#if 0 /* Removed because the driver should use the ASICs TX complete IRQ. */
+ /* The FORMACs tx complete IRQ should be used any longer */
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;4)
+
+ void enable_tx_irq(smc, queue)
+ struct s_smc *smc ;
+ u_short queue ;
+
+Function DOWNCALL (SMT, fplustm.c)
+ enable_tx_irq() enables the FORMACs transmit complete
+ interrupt of the queue.
+
+Para queue = QUEUE_S: synchronous queue
+ = QUEUE_A0: asynchronous queue
+
+Note After any ring operational change the transmit complete
+ interrupts are disabled.
+ The operating system dependent module must enable
+ the transmit complete interrupt of a queue,
+ - when it queues the first frame,
+ because of no transmit resources are beeing
+ available and
+ - when it escapes from the function llc_restart_tx
+ while some frames are still queued.
+
+ END_MANUAL_ENTRY
+ */
+void enable_tx_irq(smc, queue)
+struct s_smc *smc ;
+u_short queue ; /* 0 = synchronous queue, 1 = asynchronous queue 0 */
+{
+ u_short imask ;
+
+ imask = ~(inpw(FM_A(FM_IMSK1U))) ;
+
+ if (queue == 0) {
+ outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMS)) ;
+ }
+ if (queue == 1) {
+ outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMA0)) ;
+ }
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;4)
+
+ void disable_tx_irq(smc, queue)
+ struct s_smc *smc ;
+ u_short queue ;
+
+Function DOWNCALL (SMT, fplustm.c)
+ disable_tx_irq disables the FORMACs transmit complete
+ interrupt of the queue
+
+Para queue = QUEUE_S: synchronous queue
+ = QUEUE_A0: asynchronous queue
+
+Note The operating system dependent module should disable
+ the transmit complete interrupts if it escapes from the
+ function llc_restart_tx and no frames are queued.
+
+ END_MANUAL_ENTRY
+ */
+void disable_tx_irq(smc, queue)
+struct s_smc *smc ;
+u_short queue ; /* 0 = synchronous queue, 1 = asynchronous queue 0 */
+{
+ u_short imask ;
+
+ imask = ~(inpw(FM_A(FM_IMSK1U))) ;
+
+ if (queue == 0) {
+ outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMS)) ;
+ }
+ if (queue == 1) {
+ outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMA0)) ;
+ }
+}
+#endif
+
+static void disable_formac(smc)
+struct s_smc *smc ;
+{
+ /* clear formac IMSK : 1 disables irq */
+ outpw(FM_A(FM_IMSK1U),MW) ;
+ outpw(FM_A(FM_IMSK1L),MW) ;
+ outpw(FM_A(FM_IMSK2U),MW) ;
+ outpw(FM_A(FM_IMSK2L),MW) ;
+ outpw(FM_A(FM_IMSK3U),MW) ;
+ outpw(FM_A(FM_IMSK3L),MW) ;
+}
+
+
+static void mac_ring_up(smc,up)
+struct s_smc *smc ;
+int up;
+{
+ if (up) {
+ formac_rcv_restart(smc) ; /* enable receive function */
+ smc->hw.mac_ring_is_up = TRUE ;
+ llc_restart_tx(smc) ; /* TX queue */
+ }
+ else {
+ /* disable receive function */
+ SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ;
+
+ /* abort current transmit activity */
+ outpw(FM_A(FM_CMDREG2),FM_IACTR) ;
+
+ smc->hw.mac_ring_is_up = FALSE ;
+ }
+}
+
+/*--------------------------- ISR handling ----------------------------------*/
+/*
+ * mac1_irq is in drvfbi.c
+ */
+
+/*
+ * mac2_irq: status bits for the receive queue 1, and ring status
+ * ring status indication bits
+ */
+void mac2_irq(smc,code_s2u,code_s2l)
+struct s_smc *smc ;
+u_short code_s2u ;
+u_short code_s2l ;
+{
+ u_short change_s2l ;
+ u_short change_s2u ;
+
+ /* (jd) 22-Feb-1999
+ * Restart 2_DMax Timer after end of claiming or beaconing
+ */
+ if (code_s2u & (FM_SCLM|FM_SHICLM|FM_SBEC|FM_SOTRBEC)) {
+ queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ;
+ }
+ else if (code_s2l & (FM_STKISS)) {
+ queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ;
+ }
+
+ /*
+ * XOR current st bits with the last to avoid useless RMT event queuing
+ */
+ change_s2l = smc->hw.fp.s2l ^ code_s2l ;
+ change_s2u = smc->hw.fp.s2u ^ code_s2u ;
+
+ if ((change_s2l & FM_SRNGOP) ||
+ (!smc->hw.mac_ring_is_up && ((code_s2l & FM_SRNGOP)))) {
+ if (code_s2l & FM_SRNGOP) {
+ mac_ring_up(smc,1) ;
+ queue_event(smc,EVENT_RMT,RM_RING_OP) ;
+ smc->mib.m[MAC0].fddiMACRingOp_Ct++ ;
+ }
+ else {
+ mac_ring_up(smc,0) ;
+ queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ;
+ }
+ goto mac2_end ;
+ }
+ if (code_s2l & FM_SMISFRM) { /* missed frame */
+ smc->mib.m[MAC0].fddiMACNotCopied_Ct++ ;
+ }
+ if (code_s2u & (FM_SRCVOVR | /* recv. FIFO overflow */
+ FM_SRBFL)) { /* recv. buffer full */
+ smc->hw.mac_ct.mac_r_restart_counter++ ;
+/* formac_rcv_restart(smc) ; */
+ smt_stat_counter(smc,1) ;
+/* goto mac2_end ; */
+ }
+ if (code_s2u & FM_SOTRBEC)
+ queue_event(smc,EVENT_RMT,RM_OTHER_BEACON) ;
+ if (code_s2u & FM_SMYBEC)
+ queue_event(smc,EVENT_RMT,RM_MY_BEACON) ;
+ if (change_s2u & code_s2u & FM_SLOCLM) {
+ DB_RMTN(2,"RMT : lower claim received\n",0,0) ;
+ }
+ if ((code_s2u & FM_SMYCLM) && !(code_s2l & FM_SDUPCLM)) {
+ /*
+ * This is my claim and that claim is not detected as a
+ * duplicate one.
+ */
+ queue_event(smc,EVENT_RMT,RM_MY_CLAIM) ;
+ }
+ if (code_s2l & FM_SDUPCLM) {
+ /*
+ * If a duplicate claim frame (same SA but T_Bid != T_Req)
+ * this flag will be set.
+ * In the RMT state machine we need a RM_VALID_CLAIM event
+ * to do the appropriate state change.
+ * RM(34c)
+ */
+ queue_event(smc,EVENT_RMT,RM_VALID_CLAIM) ;
+ }
+ if (change_s2u & code_s2u & FM_SHICLM) {
+ DB_RMTN(2,"RMT : higher claim received\n",0,0) ;
+ }
+ if ( (code_s2l & FM_STRTEXP) ||
+ (code_s2l & FM_STRTEXR) )
+ queue_event(smc,EVENT_RMT,RM_TRT_EXP) ;
+ if (code_s2l & FM_SMULTDA) {
+ /*
+ * The MAC has found a 2. MAC with the same address.
+ * Signal dup_addr_test = failed to RMT state machine.
+ * RM(25)
+ */
+ smc->r.dup_addr_test = DA_FAILED ;
+ queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+ }
+ if (code_s2u & FM_SBEC)
+ smc->hw.fp.err_stats.err_bec_stat++ ;
+ if (code_s2u & FM_SCLM)
+ smc->hw.fp.err_stats.err_clm_stat++ ;
+ if (code_s2l & FM_STVXEXP)
+ smc->mib.m[MAC0].fddiMACTvxExpired_Ct++ ;
+ if ((code_s2u & (FM_SBEC|FM_SCLM))) {
+ if (!(change_s2l & FM_SRNGOP) && (smc->hw.fp.s2l & FM_SRNGOP)) {
+ mac_ring_up(smc,0) ;
+ queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ;
+
+ mac_ring_up(smc,1) ;
+ queue_event(smc,EVENT_RMT,RM_RING_OP) ;
+ smc->mib.m[MAC0].fddiMACRingOp_Ct++ ;
+ }
+ }
+ if (code_s2l & FM_SPHINV)
+ smc->hw.fp.err_stats.err_phinv++ ;
+ if (code_s2l & FM_SSIFG)
+ smc->hw.fp.err_stats.err_sifg_det++ ;
+ if (code_s2l & FM_STKISS)
+ smc->hw.fp.err_stats.err_tkiss++ ;
+ if (code_s2l & FM_STKERR)
+ smc->hw.fp.err_stats.err_tkerr++ ;
+ if (code_s2l & FM_SFRMCTR)
+ smc->mib.m[MAC0].fddiMACFrame_Ct += 0x10000L ;
+ if (code_s2l & FM_SERRCTR)
+ smc->mib.m[MAC0].fddiMACError_Ct += 0x10000L ;
+ if (code_s2l & FM_SLSTCTR)
+ smc->mib.m[MAC0].fddiMACLost_Ct += 0x10000L ;
+ if (code_s2u & FM_SERRSF) {
+ SMT_PANIC(smc,SMT_E0114, SMT_E0114_MSG) ;
+ }
+mac2_end:
+ /* notice old status */
+ smc->hw.fp.s2l = code_s2l ;
+ smc->hw.fp.s2u = code_s2u ;
+ outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ;
+}
+
+/*
+ * mac3_irq: receive queue 2 bits and address detection bits
+ */
+void mac3_irq(smc,code_s3u,code_s3l)
+struct s_smc *smc ;
+u_short code_s3u ;
+u_short code_s3l ;
+{
+ UNUSED(code_s3l) ;
+
+ if (code_s3u & (FM_SRCVOVR2 | /* recv. FIFO overflow */
+ FM_SRBFL2)) { /* recv. buffer full */
+ smc->hw.mac_ct.mac_r_restart_counter++ ;
+ smt_stat_counter(smc,1);
+ }
+
+
+ if (code_s3u & FM_SRPERRQ2) { /* parity error receive queue 2 */
+ SMT_PANIC(smc,SMT_E0115, SMT_E0115_MSG) ;
+ }
+ if (code_s3u & FM_SRPERRQ1) { /* parity error receive queue 2 */
+ SMT_PANIC(smc,SMT_E0116, SMT_E0116_MSG) ;
+ }
+}
+
+
+/*
+ * take formac offline
+ */
+static void formac_offline(smc)
+struct s_smc *smc ;
+{
+ outpw(FM_A(FM_CMDREG2),FM_IACTR) ;/* abort current transmit activity */
+
+ /* disable receive function */
+ SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ;
+
+ /* FORMAC+ 'Initialize Mode' */
+ SETMASK(FM_A(FM_MDREG1),FM_MINIT,FM_MMODE) ;
+
+ disable_formac(smc) ;
+ smc->hw.mac_ring_is_up = FALSE ;
+ smc->hw.hw_state = STOPPED ;
+}
+
+/*
+ * bring formac online
+ */
+static void formac_online(smc)
+struct s_smc *smc ;
+{
+ enable_formac(smc) ;
+ SETMASK(FM_A(FM_MDREG1),FM_MONLINE | FM_SELRA | MDR1INIT |
+ smc->hw.fp.rx_mode, FM_MMODE | FM_SELRA | FM_ADDRX) ;
+}
+
+/*
+ * FORMAC+ full init. (tx, rx, timer, counter, claim & beacon)
+ */
+int init_fplus(smc)
+struct s_smc *smc ;
+{
+ smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ;
+ smc->hw.fp.rx_mode = FM_MDAMA ;
+ smc->hw.fp.group_addr = fddi_broadcast ;
+ smc->hw.fp.func_addr = 0 ;
+ smc->hw.fp.frselreg_init = 0 ;
+
+ init_driver_fplus(smc) ;
+ if (smc->s.sas == SMT_DAS)
+ smc->hw.fp.mdr3init |= FM_MENDAS ;
+
+ smc->hw.mac_ct.mac_nobuf_counter = 0 ;
+ smc->hw.mac_ct.mac_r_restart_counter = 0 ;
+
+ smc->hw.fp.fm_st1u = (HW_PTR) ADDR(B0_ST1U) ;
+ smc->hw.fp.fm_st1l = (HW_PTR) ADDR(B0_ST1L) ;
+ smc->hw.fp.fm_st2u = (HW_PTR) ADDR(B0_ST2U) ;
+ smc->hw.fp.fm_st2l = (HW_PTR) ADDR(B0_ST2L) ;
+ smc->hw.fp.fm_st3u = (HW_PTR) ADDR(B0_ST3U) ;
+ smc->hw.fp.fm_st3l = (HW_PTR) ADDR(B0_ST3L) ;
+
+ smc->hw.fp.s2l = smc->hw.fp.s2u = 0 ;
+ smc->hw.mac_ring_is_up = 0 ;
+
+ mac_counter_init(smc) ;
+
+ /* convert BCKL units to symbol time */
+ smc->hw.mac_pa.t_neg = (u_long)0 ;
+ smc->hw.mac_pa.t_pri = (u_long)0 ;
+
+ /* make sure all PCI settings are correct */
+ mac_do_pci_fix(smc) ;
+
+ return(init_mac(smc,1)) ;
+ /* enable_formac(smc) ; */
+}
+
+static int init_mac(smc,all)
+struct s_smc *smc ;
+int all ;
+{
+ u_short t_max,x ;
+ u_long time=0 ;
+
+ /*
+ * clear memory
+ */
+ outpw(FM_A(FM_MDREG1),FM_MINIT) ; /* FORMAC+ init mode */
+ set_formac_addr(smc) ;
+ outpw(FM_A(FM_MDREG1),FM_MMEMACT) ; /* FORMAC+ memory activ mode */
+ /* Note: Mode register 2 is set here, incase parity is enabled. */
+ outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ;
+
+ if (all) {
+ init_ram(smc) ;
+ }
+ else {
+ /*
+ * reset the HPI, the Master and the BMUs
+ */
+ outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+ time = hwt_quick_read(smc) ;
+ }
+
+ /*
+ * set all pointers, frames etc
+ */
+ smt_split_up_fifo(smc) ;
+
+ init_tx(smc) ;
+ init_rx(smc) ;
+ init_rbc(smc) ;
+
+ build_claim_beacon(smc,smc->mib.m[MAC0].fddiMACT_Req) ;
+
+ /* set RX threshold */
+ /* see Errata #SN2 Phantom receive overflow */
+ outpw(FM_A(FM_FRMTHR),14<<12) ; /* switch on */
+
+ /* set formac work mode */
+ outpw(FM_A(FM_MDREG1),MDR1INIT | FM_SELRA | smc->hw.fp.rx_mode) ;
+ outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ;
+ outpw(FM_A(FM_MDREG3),smc->hw.fp.mdr3init) ;
+ outpw(FM_A(FM_FRSELREG),smc->hw.fp.frselreg_init) ;
+
+ /* set timer */
+ /*
+ * errata #22 fplus:
+ * T_MAX must not be FFFE
+ * or one of FFDF, FFB8, FF91 (-0x27 etc..)
+ */
+ t_max = (u_short)(smc->mib.m[MAC0].fddiMACT_Max/32) ;
+ x = t_max/0x27 ;
+ x *= 0x27 ;
+ if ((t_max == 0xfffe) || (t_max - x == 0x16))
+ t_max-- ;
+ outpw(FM_A(FM_TMAX),(u_short)t_max) ;
+
+ /* BugFix for report #10204 */
+ if (smc->mib.m[MAC0].fddiMACTvxValue < (u_long) (- US2BCLK(52))) {
+ outpw(FM_A(FM_TVX), (u_short) (- US2BCLK(52))/255 & MB) ;
+ } else {
+ outpw(FM_A(FM_TVX),
+ (u_short)((smc->mib.m[MAC0].fddiMACTvxValue/255) & MB)) ;
+ }
+
+ outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */
+ outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */
+ outpw(FM_A(FM_CMDREG1),FM_ICLLR); /* clear receive lock */
+
+ /* Auto unlock receice threshold for receive queue 1 and 2 */
+ outpw(FM_A(FM_UNLCKDLY),(0xff|(0xff<<8))) ;
+
+ rtm_init(smc) ; /* RT-Monitor */
+
+ if (!all) {
+ /*
+ * after 10ms, reset the BMUs and repair the rings
+ */
+ hwt_wait_time(smc,time,MS2BCLK(10)) ;
+ outpd(ADDR(B0_R1_CSR),CSR_SET_RESET) ;
+ outpd(ADDR(B0_XA_CSR),CSR_SET_RESET) ;
+ outpd(ADDR(B0_XS_CSR),CSR_SET_RESET) ;
+ outp(ADDR(B0_CTRL), CTRL_HPI_CLR) ;
+ outpd(ADDR(B0_R1_CSR),CSR_CLR_RESET) ;
+ outpd(ADDR(B0_XA_CSR),CSR_CLR_RESET) ;
+ outpd(ADDR(B0_XS_CSR),CSR_CLR_RESET) ;
+ if (!smc->hw.hw_is_64bit) {
+ outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
+ outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
+ outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
+ }
+ smc->hw.hw_state = STOPPED ;
+ mac_drv_repair_descr(smc) ;
+ }
+ smc->hw.hw_state = STARTED ;
+
+ return(0) ;
+}
+
+
+/*
+ * called by CFM
+ */
+void config_mux(smc,mux)
+struct s_smc *smc ;
+int mux;
+{
+ plc_config_mux(smc,mux) ;
+
+ SETMASK(FM_A(FM_MDREG1),FM_SELRA,FM_SELRA) ;
+}
+
+/*
+ * called by RMT
+ * enable CLAIM/BEACON interrupts
+ * (only called if these events are of interest, e.g. in DETECT state
+ * the interrupt must not be permanently enabled
+ * RMT calls this function periodically (timer driven polling)
+ */
+void sm_mac_check_beacon_claim(smc)
+struct s_smc *smc ;
+{
+ /* set formac IMSK : 0 enables irq */
+ outpw(FM_A(FM_IMSK2U),~(mac_imsk2u | mac_beacon_imsk2u)) ;
+ /* the driver must receive the directed beacons */
+ formac_rcv_restart(smc) ;
+ process_receive(smc) ;
+}
+
+/*-------------------------- interface functions ----------------------------*/
+/*
+ * control ODL output
+ */
+void sm_pm_control(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+ SK_UNUSED(smc) ;
+
+ /*
+ * if PCM logic has set LS_REQUEST = Transmit QUIET Line State
+ * /FOTOFF signal turn activ -> ODL disable
+ */
+ switch(mode) {
+ case PM_TRANSMIT_DISABLE :
+ break ;
+ case PM_TRANSMIT_ENABLE :
+ break ;
+ }
+}
+
+/*
+ * control MAC layer (called by RMT)
+ */
+void sm_ma_control(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+ switch(mode) {
+ case MA_OFFLINE :
+ /* Add to make the MAC offline in RM0_ISOLATED state */
+ formac_offline(smc) ;
+ break ;
+ case MA_RESET :
+ (void)init_mac(smc,0) ;
+ break ;
+ case MA_BEACON :
+ formac_online(smc) ;
+ break ;
+ case MA_DIRECTED :
+ directed_beacon(smc) ;
+ break ;
+ case MA_TREQ :
+ /*
+ * no actions necessary, TREQ is already set
+ */
+ break ;
+ }
+}
+
+int sm_mac_get_tx_state(smc)
+struct s_smc *smc ;
+{
+ return((inpw(FM_A(FM_STMCHN))>>4)&7) ;
+}
+
+/*
+ * multicast functions
+ */
+
+static struct s_fpmc *mac_get_mc_table(smc,user,own,del,can)
+struct s_smc *smc ;
+struct fddi_addr *user ;
+struct fddi_addr *own ;
+int del ;
+int can ;
+{
+ struct s_fpmc *tb ;
+ struct s_fpmc *slot ;
+ u_char *p ;
+ int i ;
+
+ /*
+ * set own = can(user)
+ */
+ *own = *user ;
+ if (can) {
+ p = own->a ;
+ for (i = 0 ; i < 6 ; i++, p++)
+ *p = canonical[*p] ;
+ }
+ slot = 0 ;
+ for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
+ if (!tb->n) { /* not used */
+ if (!del && !slot) /* if !del save first free */
+ slot = tb ;
+ continue ;
+ }
+ if (memcmp((char *)&tb->a,(char *)own,6))
+ continue ;
+ return(tb) ;
+ }
+ return(slot) ; /* return first free or NULL */
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+ void mac_clear_multicast(smc)
+ struct s_smc *smc ;
+
+Function DOWNCALL (SMT, fplustm.c)
+ Clear all multicast entries
+
+ END_MANUAL_ENTRY()
+ */
+void mac_clear_multicast(smc)
+struct s_smc *smc ;
+{
+ struct s_fpmc *tb ;
+ int i ;
+
+ smc->hw.fp.os_slots_used = 0 ; /* note the SMT addresses */
+ /* will not be deleted */
+ for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
+ if (!tb->perm) {
+ tb->n = 0 ;
+ }
+ }
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+ int mac_set_func_addr(smc,f_addr)
+ struct s_smc *smc ;
+ u_long f_addr ;
+
+Function DOWNCALL (SMT, fplustm.c)
+ Set a Token-Ring functional address, the address will
+ be activated after calling mac_update_multicast()
+
+Para f_addr functional bits in non-canonical format
+
+Returns 0: always success
+
+ END_MANUAL_ENTRY()
+ */
+int mac_set_func_addr(smc,f_addr)
+struct s_smc *smc ;
+u_long f_addr ;
+{
+ smc->hw.fp.func_addr = f_addr ;
+ return(0) ;
+}
+
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+ int mac_add_multicast(smc,addr,can)
+ struct s_smc *smc ;
+ struct fddi_addr *addr ;
+ int can ;
+
+Function DOWNCALL (SMC, fplustm.c)
+ Add an entry to the multicast table
+
+Para addr pointer to a multicast address
+ can = 0: the multicast address has the physical format
+ = 1: the multicast address has the canonical format
+ | 0x80 permanent
+
+Returns 0: success
+ 1: address table full
+
+Note After a 'driver reset' or a 'station set address' all
+ entries of the multicast table are cleared.
+ In this case the driver has to fill the multicast table again.
+ After the operating system dependent module filled
+ the multicast table it must call mac_update_multicast
+ to activate the new multicast addresses!
+
+ END_MANUAL_ENTRY()
+ */
+int mac_add_multicast(smc,addr,can)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+int can ;
+{
+ SK_LOC_DECL(struct fddi_addr,own) ;
+ struct s_fpmc *tb ;
+
+ /*
+ * check if there are free table entries
+ */
+ if (can & 0x80) {
+ if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) {
+ return(1) ;
+ }
+ }
+ else {
+ if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) {
+ return(1) ;
+ }
+ }
+
+ /*
+ * find empty slot
+ */
+ if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80)))
+ return(1) ;
+ tb->n++ ;
+ tb->a = own ;
+ tb->perm = (can & 0x80) ? 1 : 0 ;
+
+ if (can & 0x80)
+ smc->hw.fp.smt_slots_used++ ;
+ else
+ smc->hw.fp.os_slots_used++ ;
+
+ return(0) ;
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+ void mac_del_multicast(smc,addr,can)
+ struct s_smc *smc ;
+ struct fddi_addr *addr ;
+ int can ;
+
+Function DOWNCALL (SMT, fplustm.c)
+ Delete an entry from the multicast table
+
+Para addr pointer to a multicast address
+ can = 0: the multicast address has the physical format
+ = 1: the multicast address has the canonical format
+ | 0x80 permanent
+
+ END_MANUAL_ENTRY()
+ */
+void mac_del_multicast(smc,addr,can)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+int can ;
+{
+ SK_LOC_DECL(struct fddi_addr,own) ;
+ struct s_fpmc *tb ;
+
+ if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
+ return ;
+ /*
+ * permanent addresses must be deleted with perm bit
+ * and vice versa
+ */
+ if (( tb->perm && (can & 0x80)) ||
+ (!tb->perm && !(can & 0x80))) {
+ /*
+ * delete it
+ */
+ if (tb->n) {
+ tb->n-- ;
+ if (tb->perm) {
+ smc->hw.fp.smt_slots_used-- ;
+ }
+ else {
+ smc->hw.fp.os_slots_used-- ;
+ }
+ }
+ }
+}
+
+/*
+ * mode
+ */
+
+#define RX_MODE_PROM 0x1
+#define RX_MODE_ALL_MULTI 0x2
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+ void mac_update_multicast(smc)
+ struct s_smc *smc ;
+
+Function DOWNCALL (SMT, fplustm.c)
+ Update FORMAC multicast registers
+
+ END_MANUAL_ENTRY()
+ */
+void mac_update_multicast(smc)
+struct s_smc *smc ;
+{
+ struct s_fpmc *tb ;
+ u_char *fu ;
+ int i ;
+
+ /*
+ * invalidate the CAM
+ */
+ outpw(FM_A(FM_AFCMD),FM_IINV_CAM) ;
+
+ /*
+ * set the functional address
+ */
+ if (smc->hw.fp.func_addr) {
+ fu = (u_char *) &smc->hw.fp.func_addr ;
+ outpw(FM_A(FM_AFMASK2),0xffff) ;
+ outpw(FM_A(FM_AFMASK1),(u_short) ~((fu[0] << 8) + fu[1])) ;
+ outpw(FM_A(FM_AFMASK0),(u_short) ~((fu[2] << 8) + fu[3])) ;
+ outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ;
+ outpw(FM_A(FM_AFCOMP2), 0xc000) ;
+ outpw(FM_A(FM_AFCOMP1), 0x0000) ;
+ outpw(FM_A(FM_AFCOMP0), 0x0000) ;
+ outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ;
+ }
+
+ /*
+ * set the mask and the personality register(s)
+ */
+ outpw(FM_A(FM_AFMASK0),0xffff) ;
+ outpw(FM_A(FM_AFMASK1),0xffff) ;
+ outpw(FM_A(FM_AFMASK2),0xffff) ;
+ outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ;
+
+ for (i = 0, tb = smc->hw.fp.mc.table; i < FPMAX_MULTICAST; i++, tb++) {
+ if (tb->n) {
+ CHECK_CAM() ;
+
+ /*
+ * wirte the multicast addres into the CAM
+ */
+ outpw(FM_A(FM_AFCOMP2),
+ (u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ;
+ outpw(FM_A(FM_AFCOMP1),
+ (u_short)((tb->a.a[2]<<8)+tb->a.a[3])) ;
+ outpw(FM_A(FM_AFCOMP0),
+ (u_short)((tb->a.a[4]<<8)+tb->a.a[5])) ;
+ outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ;
+ }
+ }
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;3)
+
+ void mac_set_rx_mode(smc,mode)
+ struct s_smc *smc ;
+ int mode ;
+
+Function DOWNCALL/INTERN (SMT, fplustm.c)
+ This function enables / disables the selected receive.
+ Don't call this function if the hardware module is
+ used -- use mac_drv_rx_mode() instead of.
+
+Para mode = 1 RX_ENABLE_ALLMULTI enable all multicasts
+ 2 RX_DISABLE_ALLMULTI disable "enable all multicasts"
+ 3 RX_ENABLE_PROMISC enable promiscous
+ 4 RX_DISABLE_PROMISC disable promiscous
+ 5 RX_ENABLE_NSA enable reception of NSA frames
+ 6 RX_DISABLE_NSA disable reception of NSA frames
+
+Note The selected receive modes will be lost after 'driver reset'
+ or 'set station address'
+
+ END_MANUAL_ENTRY
+ */
+void mac_set_rx_mode(smc,mode)
+struct s_smc *smc ;
+int mode ;
+{
+ switch (mode) {
+ case RX_ENABLE_ALLMULTI :
+ smc->hw.fp.rx_prom |= RX_MODE_ALL_MULTI ;
+ break ;
+ case RX_DISABLE_ALLMULTI :
+ smc->hw.fp.rx_prom &= ~RX_MODE_ALL_MULTI ;
+ break ;
+ case RX_ENABLE_PROMISC :
+ smc->hw.fp.rx_prom |= RX_MODE_PROM ;
+ break ;
+ case RX_DISABLE_PROMISC :
+ smc->hw.fp.rx_prom &= ~RX_MODE_PROM ;
+ break ;
+ case RX_ENABLE_NSA :
+ smc->hw.fp.nsa_mode = FM_MDAMA ;
+ smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) |
+ smc->hw.fp.nsa_mode ;
+ break ;
+ case RX_DISABLE_NSA :
+ smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ;
+ smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) |
+ smc->hw.fp.nsa_mode ;
+ break ;
+ }
+ if (smc->hw.fp.rx_prom & RX_MODE_PROM) {
+ smc->hw.fp.rx_mode = FM_MLIMPROM ;
+ }
+ else if (smc->hw.fp.rx_prom & RX_MODE_ALL_MULTI) {
+ smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode | FM_EXGPA0 ;
+ }
+ else
+ smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode ;
+ SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ;
+ mac_update_multicast(smc) ;
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(module;tests;3)
+ How to test the Restricted Token Monitor
+ ----------------------------------------------------------------
+
+ o Insert a break point in the function rtm_irq()
+ o Remove all stations with a restricted token monitor from the
+ network.
+ o Connect a UPPS ISA or EISA station to the network.
+ o Give the FORMAC of UPPS station the command to send
+ restricted tokens until the ring becomes instable.
+ o Now connect your test test client.
+ o The restricted token monitor should detect the restricted token,
+ and your break point will be reached.
+ o You can ovserve how the station will clean the ring.
+
+ END_MANUAL_ENTRY
+ */
+void rtm_irq(smc)
+struct s_smc *smc ;
+{
+ outpw(ADDR(B2_RTM_CRTL),TIM_CL_IRQ) ; /* clear IRQ */
+ if (inpw(ADDR(B2_RTM_CRTL)) & TIM_RES_TOK) {
+ outpw(FM_A(FM_CMDREG1),FM_ICL) ; /* force claim */
+ DB_RMT("RMT: fddiPATHT_Rmode expired\n",0,0) ;
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
+ (u_long) FDDI_SMT_EVENT,
+ (u_long) FDDI_RTT, smt_get_event_word(smc));
+ }
+ outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable RTM monitoring */
+}
+
+static void rtm_init(smc)
+struct s_smc *smc ;
+{
+ outpd(ADDR(B2_RTM_INI),0) ; /* timer = 0 */
+ outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable IRQ */
+}
+
+void rtm_set_timer(smc)
+struct s_smc *smc ;
+{
+ /*
+ * MIB timer and hardware timer have the same resolution of 80nS
+ */
+ DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns \n",
+ (int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ;
+ outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ;
+}
+
+static void smt_split_up_fifo(smc)
+struct s_smc *smc ;
+{
+
+/*
+ BEGIN_MANUAL_ENTRY(module;mem;1)
+ -------------------------------------------------------------
+ RECEIVE BUFFER MEMORY DIVERSION
+ -------------------------------------------------------------
+
+ R1_RxD == SMT_R1_RXD_COUNT
+ R2_RxD == SMT_R2_RXD_COUNT
+
+ SMT_R1_RXD_COUNT must be unequal zero
+
+ | R1_RxD R2_RxD |R1_RxD R2_RxD | R1_RxD R2_RxD
+ | x 0 | x 1-3 | x < 3
+ ----------------------------------------------------------------------
+ | 63,75 kB | 54,75 | R1_RxD
+ rx queue 1 | RX_FIFO_SPACE | RX_LARGE_FIFO| ------------- * 63,75 kB
+ | | | R1_RxD+R2_RxD
+ ----------------------------------------------------------------------
+ | | 9 kB | R2_RxD
+ rx queue 2 | 0 kB | RX_SMALL_FIFO| ------------- * 63,75 kB
+ | (not used) | | R1_RxD+R2_RxD
+
+ END_MANUAL_ENTRY
+*/
+
+ if (SMT_R1_RXD_COUNT == 0) {
+ SMT_PANIC(smc,SMT_E0117, SMT_E0117_MSG) ;
+ }
+
+ switch(SMT_R2_RXD_COUNT) {
+ case 0:
+ smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE ;
+ smc->hw.fp.fifo.rx2_fifo_size = 0 ;
+ break ;
+ case 1:
+ case 2:
+ case 3:
+ smc->hw.fp.fifo.rx1_fifo_size = RX_LARGE_FIFO ;
+ smc->hw.fp.fifo.rx2_fifo_size = RX_SMALL_FIFO ;
+ break ;
+ default: /* this is not the real defaule */
+ smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE *
+ SMT_R1_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ;
+ smc->hw.fp.fifo.rx2_fifo_size = RX_FIFO_SPACE *
+ SMT_R2_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ;
+ break ;
+ }
+
+/*
+ BEGIN_MANUAL_ENTRY(module;mem;1)
+ -------------------------------------------------------------
+ TRANSMIT BUFFER MEMORY DIVERSION
+ -------------------------------------------------------------
+
+
+ | no sync bw | sync bw available and | sync bw available and
+ | available | SynchTxMode = SPLIT | SynchTxMode = ALL
+ -----------------------------------------------------------------------
+ sync tx | 0 kB | 32 kB | 55 kB
+ queue | | TX_MEDIUM_FIFO | TX_LARGE_FIFO
+ -----------------------------------------------------------------------
+ async tx | 64 kB | 32 kB | 9 k
+ queue | TX_FIFO_SPACE| TX_MEDIUM_FIFO | TX_SMALL_FIFO
+
+ END_MANUAL_ENTRY
+*/
+
+ /*
+ * set the tx mode bits
+ */
+ if (smc->mib.a[PATH0].fddiPATHSbaPayload) {
+#ifdef ESS
+ smc->hw.fp.fifo.fifo_config_mode |=
+ smc->mib.fddiESSSynchTxMode | SYNC_TRAFFIC_ON ;
+#endif
+ }
+ else {
+ smc->hw.fp.fifo.fifo_config_mode &=
+ ~(SEND_ASYNC_AS_SYNC|SYNC_TRAFFIC_ON) ;
+ }
+
+ /*
+ * split up the FIFO
+ */
+ if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON) {
+ if (smc->hw.fp.fifo.fifo_config_mode & SEND_ASYNC_AS_SYNC) {
+ smc->hw.fp.fifo.tx_s_size = TX_LARGE_FIFO ;
+ smc->hw.fp.fifo.tx_a0_size = TX_SMALL_FIFO ;
+ }
+ else {
+ smc->hw.fp.fifo.tx_s_size = TX_MEDIUM_FIFO ;
+ smc->hw.fp.fifo.tx_a0_size = TX_MEDIUM_FIFO ;
+ }
+ }
+ else {
+ smc->hw.fp.fifo.tx_s_size = 0 ;
+ smc->hw.fp.fifo.tx_a0_size = TX_FIFO_SPACE ;
+ }
+
+ smc->hw.fp.fifo.rx1_fifo_start = smc->hw.fp.fifo.rbc_ram_start +
+ RX_FIFO_OFF ;
+ smc->hw.fp.fifo.tx_s_start = smc->hw.fp.fifo.rx1_fifo_start +
+ smc->hw.fp.fifo.rx1_fifo_size ;
+ smc->hw.fp.fifo.tx_a0_start = smc->hw.fp.fifo.tx_s_start +
+ smc->hw.fp.fifo.tx_s_size ;
+ smc->hw.fp.fifo.rx2_fifo_start = smc->hw.fp.fifo.tx_a0_start +
+ smc->hw.fp.fifo.tx_a0_size ;
+
+ DB_SMT("FIFO split: mode = %x\n",smc->hw.fp.fifo.fifo_config_mode,0) ;
+ DB_SMT("rbc_ram_start = %x rbc_ram_end = %x\n",
+ smc->hw.fp.fifo.rbc_ram_start, smc->hw.fp.fifo.rbc_ram_end) ;
+ DB_SMT("rx1_fifo_start = %x tx_s_start = %x\n",
+ smc->hw.fp.fifo.rx1_fifo_start, smc->hw.fp.fifo.tx_s_start) ;
+ DB_SMT("tx_a0_start = %x rx2_fifo_start = %x\n",
+ smc->hw.fp.fifo.tx_a0_start, smc->hw.fp.fifo.rx2_fifo_start) ;
+}
+
+void formac_reinit_tx(smc)
+struct s_smc *smc ;
+{
+ /*
+ * Split up the FIFO and reinitialize the MAC if synchronous
+ * bandwidth becomes available but no synchronous queue is
+ * configured.
+ */
+ if (!smc->hw.fp.fifo.tx_s_size && smc->mib.a[PATH0].fddiPATHSbaPayload){
+ (void)init_mac(smc,0) ;
+ }
+}
+
+
diff --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/skfp/h/cmtdef.h
new file mode 100644
index 000000000..0b54c57ca
--- /dev/null
+++ b/drivers/net/skfp/h/cmtdef.h
@@ -0,0 +1,801 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _CMTDEF_
+#define _CMTDEF_
+
+/* **************************************************************** */
+
+/*
+ * implementation specific constants
+ * MODIIFY THE FOLLWOING THREE DEFINES
+ */
+#define AMDPLC /* if Amd PLC chip used */
+#ifdef CONC
+#define NUMPHYS 12 /* 2 for SAS or DAS, more for Concentrator */
+#else
+#ifdef CONC_II
+#define NUMPHYS 24 /* 2 for SAS or DAS, more for Concentrator */
+#else
+#define NUMPHYS 2 /* 2 for SAS or DAS, more for Concentrator */
+#endif
+#endif
+#define NUMMACS 1 /* only 1 supported at the moment */
+#define NUMPATHS 2 /* primary and secondary path supported */
+
+/*
+ * DO NOT MODIFY BEYOND THIS POINT
+ */
+
+/* **************************************************************** */
+
+#if NUMPHYS > 2
+#define CONCENTRATOR
+#endif
+
+/*
+ * Definitions for comfortable LINT usage
+ */
+#ifdef lint
+#define LINT_USE(x) (x)=(x)
+#else
+#define LINT_USE(x)
+#endif
+
+#ifdef DEBUG
+#define DB_PR(flag,a,b,c) { if (flag) printf(a,b,c) ; }
+#else
+#define DB_PR(flag,a,b,c)
+#endif
+
+#ifdef DEBUG_BRD
+#define DB_ECM(a,b,c) DB_PR((smc->debug.d_smt&1),a,b,c)
+#define DB_ECMN(n,a,b,c) DB_PR((smc->debug.d_ecm >=(n)),a,b,c)
+#define DB_RMT(a,b,c) DB_PR((smc->debug.d_smt&2),a,b,c)
+#define DB_RMTN(n,a,b,c) DB_PR((smc->debug.d_rmt >=(n)),a,b,c)
+#define DB_CFM(a,b,c) DB_PR((smc->debug.d_smt&4),a,b,c)
+#define DB_CFMN(n,a,b,c) DB_PR((smc->debug.d_cfm >=(n)),a,b,c)
+#define DB_PCM(a,b,c) DB_PR((smc->debug.d_smt&8),a,b,c)
+#define DB_PCMN(n,a,b,c) DB_PR((smc->debug.d_pcm >=(n)),a,b,c)
+#define DB_SMT(a,b,c) DB_PR((smc->debug.d_smtf),a,b,c)
+#define DB_SMTN(n,a,b,c) DB_PR((smc->debug.d_smtf >=(n)),a,b,c)
+#define DB_SBA(a,b,c) DB_PR((smc->debug.d_sba),a,b,c)
+#define DB_SBAN(n,a,b,c) DB_PR((smc->debug.d_sba >=(n)),a,b,c)
+#define DB_ESS(a,b,c) DB_PR((smc->debug.d_ess),a,b,c)
+#define DB_ESSN(n,a,b,c) DB_PR((smc->debug.d_ess >=(n)),a,b,c)
+#else
+#define DB_ECM(a,b,c) DB_PR((debug.d_smt&1),a,b,c)
+#define DB_ECMN(n,a,b,c) DB_PR((debug.d_ecm >=(n)),a,b,c)
+#define DB_RMT(a,b,c) DB_PR((debug.d_smt&2),a,b,c)
+#define DB_RMTN(n,a,b,c) DB_PR((debug.d_rmt >=(n)),a,b,c)
+#define DB_CFM(a,b,c) DB_PR((debug.d_smt&4),a,b,c)
+#define DB_CFMN(n,a,b,c) DB_PR((debug.d_cfm >=(n)),a,b,c)
+#define DB_PCM(a,b,c) DB_PR((debug.d_smt&8),a,b,c)
+#define DB_PCMN(n,a,b,c) DB_PR((debug.d_pcm >=(n)),a,b,c)
+#define DB_SMT(a,b,c) DB_PR((debug.d_smtf),a,b,c)
+#define DB_SMTN(n,a,b,c) DB_PR((debug.d_smtf >=(n)),a,b,c)
+#define DB_SBA(a,b,c) DB_PR((debug.d_sba),a,b,c)
+#define DB_SBAN(n,a,b,c) DB_PR((debug.d_sba >=(n)),a,b,c)
+#define DB_ESS(a,b,c) DB_PR((debug.d_ess),a,b,c)
+#define DB_ESSN(n,a,b,c) DB_PR((debug.d_ess >=(n)),a,b,c)
+#endif
+
+#ifndef SS_NOT_DS
+#define SK_LOC_DECL(type,var) type var
+#else
+#define SK_LOC_DECL(type,var) static type var
+#endif
+/*
+ * PHYs and PORTS
+ * Note: Don't touch the definition of PA and PB. Those might be used
+ * by some "for" loops.
+ */
+#define PA 0
+#define PB 1
+#if defined(SUPERNET_3) || defined(CONC_II)
+/*
+ * The port indices have to be different,
+ * because the MAC output goes through the 2. PLC
+ * Conc II: It has to be the first port in the row.
+ */
+#define PS 0 /* Internal PLC which is the same as PA */
+#else
+#define PS 1
+#endif
+#define PM 2 /* PM .. PA+NUM_PHYS-1 */
+
+/*
+ * PHY types - as in path descriptor 'fddiPHYType'
+ */
+#define TA 0 /* A port */
+#define TB 1 /* B port */
+#define TS 2 /* S port */
+#define TM 3 /* M port */
+#define TNONE 4
+
+
+/*
+ * indexes in MIB
+ */
+#define INDEX_MAC 1
+#define INDEX_PATH 1
+#define INDEX_PORT 1
+
+
+/*
+ * policies
+ */
+#define POLICY_AA (1<<0) /* reject AA */
+#define POLICY_AB (1<<1) /* reject AB */
+#define POLICY_AS (1<<2) /* reject AS */
+#define POLICY_AM (1<<3) /* reject AM */
+#define POLICY_BA (1<<4) /* reject BA */
+#define POLICY_BB (1<<5) /* reject BB */
+#define POLICY_BS (1<<6) /* reject BS */
+#define POLICY_BM (1<<7) /* reject BM */
+#define POLICY_SA (1<<8) /* reject SA */
+#define POLICY_SB (1<<9) /* reject SB */
+#define POLICY_SS (1<<10) /* reject SS */
+#define POLICY_SM (1<<11) /* reject SM */
+#define POLICY_MA (1<<12) /* reject MA */
+#define POLICY_MB (1<<13) /* reject MB */
+#define POLICY_MS (1<<14) /* reject MS */
+#define POLICY_MM (1<<15) /* reject MM */
+
+/*
+ * commands
+ */
+
+/*
+ * EVENTS
+ * event classes
+ */
+#define EVENT_ECM 1 /* event class ECM */
+#define EVENT_CFM 2 /* event class CFM */
+#define EVENT_RMT 3 /* event class RMT */
+#define EVENT_SMT 4 /* event class SMT */
+#define EVENT_PCM 5 /* event class PCM */
+#define EVENT_PCMA 5 /* event class PCMA */
+#define EVENT_PCMB 6 /* event class PCMB */
+
+/* WARNING :
+ * EVENT_PCM* must be last in the above list
+ * if more then two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1
+ * are used !
+ */
+
+#define EV_TOKEN(class,event) (((u_long)(class)<<16L)|((u_long)(event)))
+#define EV_T_CLASS(token) ((int)((token)>>16)&0xffff)
+#define EV_T_EVENT(token) ((int)(token)&0xffff)
+
+/*
+ * ECM events
+ */
+#define EC_CONNECT 1 /* connect request */
+#define EC_DISCONNECT 2 /* disconnect request */
+#define EC_TRACE_PROP 3 /* trace propagation */
+#define EC_PATH_TEST 4 /* path test */
+#define EC_TIMEOUT_TD 5 /* timer TD_min */
+#define EC_TIMEOUT_TMAX 6 /* timer trace_max */
+#define EC_TIMEOUT_IMAX 7 /* timer I_max */
+#define EC_TIMEOUT_INMAX 8 /* timer IN_max */
+#define EC_TEST_DONE 9 /* path test done */
+
+/*
+ * CFM events
+ */
+#define CF_LOOP 1 /* cf_loop flag from PCM */
+#define CF_LOOP_A 1 /* cf_loop flag from PCM */
+#define CF_LOOP_B 2 /* cf_loop flag from PCM */
+#define CF_JOIN 3 /* cf_join flag from PCM */
+#define CF_JOIN_A 3 /* cf_join flag from PCM */
+#define CF_JOIN_B 4 /* cf_join flag from PCM */
+
+/*
+ * PCM events
+ */
+#define PC_START 1
+#define PC_STOP 2
+#define PC_LOOP 3
+#define PC_JOIN 4
+#define PC_SIGNAL 5
+#define PC_REJECT 6
+#define PC_MAINT 7
+#define PC_TRACE 8
+#define PC_PDR 9
+#define PC_ENABLE 10
+#define PC_DISABLE 11
+
+/*
+ * must be ordered as in LineStateType
+ */
+#define PC_QLS 12
+#define PC_ILS 13
+#define PC_MLS 14
+#define PC_HLS 15
+#define PC_LS_PDR 16
+#define PC_LS_NONE 17
+#define LS2MIB(x) ((x)-PC_QLS)
+#define MIB2LS(x) ((x)+PC_QLS)
+
+#define PC_TIMEOUT_TB_MAX 18 /* timer TB_max */
+#define PC_TIMEOUT_TB_MIN 19 /* timer TB_min */
+#define PC_TIMEOUT_C_MIN 20 /* timer C_Min */
+#define PC_TIMEOUT_T_OUT 21 /* timer T_Out */
+#define PC_TIMEOUT_TL_MIN 22 /* timer TL_Min */
+#define PC_TIMEOUT_T_NEXT 23 /* timer t_next[] */
+#define PC_TIMEOUT_LCT 24
+#define PC_NSE 25 /* NOISE hardware timer */
+#define PC_LEM 26 /* LEM done */
+
+/*
+ * RMT events meaning from
+ */
+#define RM_RING_OP 1 /* ring operational MAC */
+#define RM_RING_NON_OP 2 /* ring not operational MAC */
+#define RM_MY_BEACON 3 /* recvd my beacon MAC */
+#define RM_OTHER_BEACON 4 /* recvd other beacon MAC */
+#define RM_MY_CLAIM 5 /* recvd my claim MAC */
+#define RM_TRT_EXP 6 /* TRT exp MAC */
+#define RM_VALID_CLAIM 7 /* claim from dup addr MAC */
+#define RM_JOIN 8 /* signal rm_join CFM */
+#define RM_LOOP 9 /* signal rm_loop CFM */
+#define RM_DUP_ADDR 10 /* dup_addr_test hange SMT-NIF */
+#define RM_ENABLE_FLAG 11 /* enable flag */
+
+#define RM_TIMEOUT_NON_OP 12 /* timeout T_Non_OP */
+#define RM_TIMEOUT_T_STUCK 13 /* timeout T_Stuck */
+#define RM_TIMEOUT_ANNOUNCE 14 /* timeout T_Announce */
+#define RM_TIMEOUT_T_DIRECT 15 /* timeout T_Direct */
+#define RM_TIMEOUT_D_MAX 16 /* timeout D_Max */
+#define RM_TIMEOUT_POLL 17 /* claim/beacon poller */
+#define RM_TX_STATE_CHANGE 18 /* To restart timer for D_Max */
+
+/*
+ * SMT events
+ */
+#define SM_TIMER 1 /* timer */
+#define SM_FAST 2 /* smt_force_irq */
+
+/* PC modes */
+#define PM_NONE 0
+#define PM_PEER 1
+#define PM_TREE 2
+
+/*
+ * PCM withhold codes
+ * MIB PC-WithholdType ENUM
+ */
+#define PC_WH_NONE 0 /* ok */
+#define PC_WH_M_M 1 /* M to M */
+#define PC_WH_OTHER 2 /* other incompatible phys */
+#define PC_WH_PATH 3 /* path not available */
+/*
+ * LCT duration
+ */
+#define LC_SHORT 1 /* short LCT */
+#define LC_MEDIUM 2 /* medium LCT */
+#define LC_LONG 3 /* long LCT */
+#define LC_EXTENDED 4 /* extended LCT */
+
+/*
+ * path_test values
+ */
+#define PT_NONE 0
+#define PT_TESTING 1 /* test is running */
+#define PT_PASSED 2 /* test passed */
+#define PT_FAILED 3 /* test failed */
+#define PT_PENDING 4 /* path test follows */
+#define PT_EXITING 5 /* disconnected while in trace/leave */
+
+/*
+ * duplicate address test
+ * MIB DupAddressTest ENUM
+ */
+#define DA_NONE 0 /* */
+#define DA_PASSED 1 /* test passed */
+#define DA_FAILED 2 /* test failed */
+
+
+/*
+ * optical bypass
+ */
+#define BP_DEINSERT 0 /* disable bypass */
+#define BP_INSERT 1 /* enable bypass */
+
+/*
+ * ODL enable/disable
+ */
+#define PM_TRANSMIT_DISABLE 0 /* disable xmit */
+#define PM_TRANSMIT_ENABLE 1 /* enable xmit */
+
+/*
+ * parameter for config_mux
+ * note : number is index in config_endec table !
+ */
+#define MUX_THRUA 0 /* through A */
+#define MUX_THRUB 1 /* through B */
+#define MUX_WRAPA 2 /* wrap A */
+#define MUX_WRAPB 3 /* wrap B */
+#define MUX_ISOLATE 4 /* isolated */
+#define MUX_WRAPS 5 /* SAS */
+
+/*
+ * MAC control
+ */
+#define MA_RESET 0
+#define MA_BEACON 1
+#define MA_CLAIM 2
+#define MA_DIRECTED 3 /* directed beacon */
+#define MA_TREQ 4 /* change T_Req */
+#define MA_OFFLINE 5 /* switch MAC to offline */
+
+
+/*
+ * trace prop
+ * bit map for trace propagation
+ */
+#define ENTITY_MAC (NUMPHYS)
+#define ENTITY_PHY(p) (p)
+#define ENTITY_BIT(m) (1<<(m))
+
+/*
+ * Resource Tag Types
+ */
+#define PATH_ISO 0 /* isolated */
+#define PATH_PRIM 3 /* primary path */
+#define PATH_THRU 5 /* through path */
+
+#define RES_MAC 2 /* resource type MAC */
+#define RES_PORT 4 /* resource type PORT */
+
+
+/*
+ * CFM state
+ * oops: MUST MATCH CF-StateType in SMT7.2 !
+ */
+#define SC0_ISOLATED 0 /* isolated */
+#define SC1_WRAP_A 5 /* wrap A (not used) */
+#define SC2_WRAP_B 6 /* wrap B (not used) */
+#define SC4_THRU_A 12 /* through A */
+#define SC5_THRU_B 7 /* through B (used in SMT 6.2) */
+#define SC7_WRAP_S 8 /* SAS (not used) */
+#define SC9_C_WRAP_A 9 /* c wrap A */
+#define SC10_C_WRAP_B 10 /* c wrap B */
+#define SC11_C_WRAP_S 11 /* c wrap S */
+
+/*
+ * convert MIB time in units of 80nS to uS
+ */
+#define MIB2US(t) ((t)/12)
+#define SEC2MIB(s) ((s)*12500000L)
+/*
+ * SMT timer
+ */
+struct smt_timer {
+ struct smt_timer *tm_next ; /* linked list */
+ struct s_smc *tm_smc ; /* pointer to context */
+ u_long tm_delta ; /* delta time */
+ u_long tm_token ; /* token value */
+ u_short tm_active ; /* flag : active/inactive */
+ u_short tm_pad ; /* pad field */
+} ;
+
+/*
+ * communication structures
+ */
+struct mac_parameter {
+ u_long t_neg ; /* T_Neg parameter */
+ u_long t_pri ; /* T_Pri register in MAC */
+} ;
+
+/*
+ * MAC counters
+ */
+struct mac_counter {
+ u_long mac_nobuf_counter ; /* MAC SW counter: no buffer */
+ u_long mac_r_restart_counter ; /* MAC SW counter: rx restarted */
+} ;
+
+/*
+ * para struct context for SMT parameters
+ */
+struct s_pcon {
+ int pc_len ;
+ int pc_err ;
+ int pc_badset ;
+ void *pc_p ;
+} ;
+
+
+/*
+ * link error monitor
+ */
+#define LEM_AVG 5
+struct lem_counter {
+#ifdef AM29K
+ int lem_on ;
+ u_long lem_errors ;
+ u_long lem_symbols ;
+ u_long lem_tsymbols ;
+ int lem_s_count ;
+ int lem_n_s ;
+ int lem_values ;
+ int lem_index ;
+ int lem_avg_ber[LEM_AVG] ;
+ int lem_sum ;
+#else
+ u_short lem_float_ber ; /* 10E-nn bit error rate */
+ u_long lem_errors ; /* accumulated error count */
+ u_short lem_on ;
+#endif
+} ;
+
+#define NUMBITS 10
+
+
+#ifdef AMDPLC
+
+/*
+ * PLC state table
+ */
+struct s_plc {
+ u_short p_state ; /* current state */
+ u_short p_bits ; /* number of bits to send */
+ u_short p_start ; /* first bit pos */
+ u_short p_pad ; /* padding for alignment */
+ u_long soft_err ; /* error counter */
+ u_long parity_err ; /* error counter */
+ u_long ebuf_err ; /* error counter */
+ u_long ebuf_cont ; /* continous error counter */
+ u_long phyinv ; /* error counter */
+ u_long vsym_ctr ; /* error counter */
+ u_long mini_ctr ; /* error counter */
+ u_long tpc_exp ; /* error counter */
+ u_long np_err ; /* error counter */
+ u_long b_pcs ; /* error counter */
+ u_long b_tpc ; /* error counter */
+ u_long b_tne ; /* error counter */
+ u_long b_qls ; /* error counter */
+ u_long b_ils ; /* error counter */
+ u_long b_hls ; /* error counter */
+} ;
+#endif
+
+#ifdef PROTOTYP_INC
+#include "fddi/driver.pro"
+#else /* PROTOTYP_INC */
+/*
+ * function prototypes
+ */
+#include "h/mbuf.h" /* Type definitions for MBUFs */
+void hwt_restart( /* hwt.c */
+#ifdef ANSIC
+ struct s_smc *smc
+#endif
+ ) ;
+
+SMbuf *smt_build_frame( /* smt.c */
+#ifdef ANSIC
+ struct s_smc *smc,
+ int class,
+ int type,
+ int length
+#endif
+ ) ;
+
+SMbuf *smt_get_mbuf( /* drvsr.c */
+#ifdef ANSIC
+ struct s_smc *smc
+#endif
+ ) ;
+
+void *sm_to_para( /* smt.c */
+#ifdef ANSIC
+ struct s_smc *smc,
+ struct smt_header *sm,
+ int para
+#endif
+ ) ;
+
+#ifndef SK_UNUSED
+#define SK_UNUSED(var) (void)(var)
+#endif
+
+void queue_event() ;
+void ecm() ;
+void ecm_init() ;
+void rmt() ;
+void rmt_init() ;
+void pcm() ;
+void pcm_init() ;
+void cfm() ;
+void cfm_init() ;
+void smt_timer_start() ;
+void smt_timer_stop() ;
+void pcm_status_state() ;
+void plc_config_mux() ;
+void sm_lem_evaluate() ;
+void smt_clear_una_dna() ;
+void mac_status_para() ;
+void mac_update_counter() ;
+void sm_pm_ls_latch() ;
+void sm_ma_control() ;
+void sm_mac_check_beacon_claim() ;
+void config_mux() ;
+void smt_agent_init() ;
+void smt_timer_init() ;
+void smt_received_pack() ;
+void smt_add_para() ;
+void smt_swap_para() ;
+void ev_init() ;
+void hwt_init() ;
+u_long hwt_read() ;
+void hwt_stop() ;
+void hwt_start() ;
+void smt_send_mbuf() ;
+void smt_free_mbuf() ;
+void sm_pm_bypass_req() ;
+void rmt_indication() ;
+void cfm_state_change() ;
+void rx_indication() ;
+void tx_indication() ;
+#ifndef NO_SMT_PANIC
+void smt_panic() ;
+#else
+#ifdef DEBUG
+void smt_panic() ;
+#else
+#define smt_panic(smc,text)
+#endif /* DEBUG */
+#endif /* NO_SMT_PANIC */
+void smt_stat_counter() ;
+void smt_timer_poll() ;
+u_long smt_get_time() ;
+u_long smt_get_tid() ;
+void smt_timer_done() ;
+void smt_set_defaults() ;
+void smt_fixup_mib() ;
+void smt_reset_defaults() ;
+void smt_agent_task() ;
+void smt_please_reconnect() ;
+int smt_check_para() ;
+void driver_get_bia() ;
+#ifdef SUPERNET_3
+void drv_reset_indication() ;
+#endif /* SUPERNET_3 */
+void smt_start_watchdog() ;
+
+void smt_event() ;
+void pcm_event() ;
+void rmt_event() ;
+void cfm_event() ;
+void timer_event() ;
+void ev_dispatcher() ;
+
+void smt_get_state() ;
+void ecm_get_state() ;
+void pcm_get_state() ;
+void rmt_get_state() ;
+
+void ecm_state_change() ;
+int sm_pm_bypass_present() ;
+void pcm_state_change() ;
+void rmt_state_change() ;
+int sm_pm_get_ls() ;
+int pcm_get_s_port() ;
+int pcm_rooted_station() ;
+int cfm_get_mac_input() ;
+int cfm_get_mac_output() ;
+int port_to_mib() ;
+int cem_build_path() ;
+int sm_mac_get_tx_state() ;
+int is_individual() ;
+int is_my_addr() ;
+int is_broadcast() ;
+int is_equal() ;
+char *get_pcmstate() ;
+
+int smt_action() ;
+u_short smt_online() ;
+void smt_force_irq() ;
+void smt_pmf_received_pack() ;
+void smt_send_frame() ;
+void smt_set_timestamp() ;
+void mac_set_rx_mode() ;
+int mac_add_multicast() ;
+int mac_set_func_addr() ;
+void mac_del_multicast() ;
+void mac_update_multicast() ;
+void mac_clear_multicast() ;
+void mac_rx_directed_beacon() ;
+void set_formac_tsync() ;
+void formac_reinit_tx() ;
+void formac_tx_restart() ;
+void process_receive() ;
+void init_driver_fplus() ;
+
+void rtm_irq() ;
+void rtm_set_timer() ;
+void ring_status_indication() ;
+void llc_recover_tx() ;
+void llc_restart_tx() ;
+void plc_clear_irq() ;
+void plc_irq() ;
+int smt_set_mac_opvalues() ;
+#ifdef TAG_MODE
+void mac_drv_pci_fix() ;
+void mac_do_pci_fix() ;
+void mac_drv_clear_tx_queue() ;
+void mac_drv_repair_descr() ;
+u_long hwt_quick_read() ;
+void hwt_wait_time() ;
+#endif
+
+#ifdef SMT_PNMI
+#ifdef ANSIC
+int pnmi_init (struct s_smc* smc);
+int pnmi_process_ndis_id (struct s_smc* smc, u_long ndis_oid, void* buf,
+ int len, int* BytesAccessed, int* BytesNeeded, u_char action);
+#else
+int pnmi_init ();
+int pnmi_process_ndis_id ();
+#endif
+#endif
+
+#ifdef SBA
+#ifndef _H2INC
+void sba() ;
+#endif
+void sba_raf_received_pack() ;
+void sba_timer_poll() ;
+void smt_init_sba() ;
+#endif
+#ifdef ESS
+int ess_raf_received_pack() ;
+void ess_timer_poll() ;
+void ess_para_change() ;
+#endif
+
+#ifdef BOOT
+#define smt_srf_event(a,b,c,d)
+#define smt_init_evc(a)
+#else
+void smt_init_evc() ;
+void smt_srf_event() ;
+#endif
+
+#ifndef SMT_REAL_TOKEN_CT
+void smt_emulate_token_ct();
+#endif
+
+#if defined(DEBUG) && !defined(BOOT)
+void dump_smt() ;
+#else
+#define dump_smt(smc,sm,text)
+#endif
+
+#ifdef DEBUG
+char *addr_to_string() ;
+void dump_hex() ;
+#endif
+#endif /* PROTOTYP_INC */
+
+/* PNMI default defines */
+#ifndef PNMI_INIT
+#define PNMI_INIT(smc) /* Nothing */
+#endif
+#ifndef PNMI_GET_ID
+#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \
+ ( 1 ? (-1) : (-1) )
+#endif
+#ifndef PNMI_SET_ID
+#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \
+ set_type) ( 1 ? (-1) : (-1) )
+#endif
+
+/*
+ * SMT_PANIC defines
+ */
+#ifndef SMT_PANIC
+#define SMT_PANIC(smc,nr,msg) smt_panic (smc, msg)
+#endif
+
+#ifndef SMT_ERR_LOG
+#define SMT_ERR_LOG(smc,nr,msg) SMT_PANIC (smc, nr, msg)
+#endif
+
+#ifndef SMT_EBASE
+#define SMT_EBASE 100
+#endif
+
+#define SMT_E0100 SMT_EBASE + 0
+#define SMT_E0100_MSG "cfm FSM: illegal ce_type"
+#define SMT_E0101 SMT_EBASE + 1
+#define SMT_E0101_MSG "CEM: case ???"
+#define SMT_E0102 SMT_EBASE + 2
+#define SMT_E0102_MSG "CEM A: illegal state"
+#define SMT_E0103 SMT_EBASE + 3
+#define SMT_E0103_MSG "CEM B: illegal state"
+#define SMT_E0104 SMT_EBASE + 4
+#define SMT_E0104_MSG "CEM M: illegal state"
+#define SMT_E0105 SMT_EBASE + 5
+#define SMT_E0105_MSG "CEM S: illegal state"
+#define SMT_E0106 SMT_EBASE + 6
+#define SMT_E0106_MSG "CFM : illegal state"
+#define SMT_E0107 SMT_EBASE + 7
+#define SMT_E0107_MSG "ECM : illegal state"
+#define SMT_E0108 SMT_EBASE + 8
+#define SMT_E0108_MSG "prop_actions : NAC in DAS CFM"
+#define SMT_E0109 SMT_EBASE + 9
+#define SMT_E0109_MSG "ST2U.FM_SERRSF error in special frame"
+#define SMT_E0110 SMT_EBASE + 10
+#define SMT_E0110_MSG "ST2U.FM_SRFRCTOV recv. count. overflow"
+#define SMT_E0111 SMT_EBASE + 11
+#define SMT_E0111_MSG "ST2U.FM_SNFSLD NP & FORMAC simult. load"
+#define SMT_E0112 SMT_EBASE + 12
+#define SMT_E0112_MSG "ST2U.FM_SRCVFRM single-frame recv.-mode"
+#define SMT_E0113 SMT_EBASE + 13
+#define SMT_E0113_MSG "FPLUS: Buffer Memory Error"
+#define SMT_E0114 SMT_EBASE + 14
+#define SMT_E0114_MSG "ST2U.FM_SERRSF error in special frame"
+#define SMT_E0115 SMT_EBASE + 15
+#define SMT_E0115_MSG "ST3L: parity error in receive queue 2"
+#define SMT_E0116 SMT_EBASE + 16
+#define SMT_E0116_MSG "ST3L: parity error in receive queue 1"
+#define SMT_E0117 SMT_EBASE + 17
+#define SMT_E0117_MSG "E_SMT_001: RxD count for receive queue 1 = 0"
+#define SMT_E0118 SMT_EBASE + 18
+#define SMT_E0118_MSG "PCM : illegal state"
+#define SMT_E0119 SMT_EBASE + 19
+#define SMT_E0119_MSG "smt_add_para"
+#define SMT_E0120 SMT_EBASE + 20
+#define SMT_E0120_MSG "smt_set_para"
+#define SMT_E0121 SMT_EBASE + 21
+#define SMT_E0121_MSG "illegal event in dispatcher"
+#define SMT_E0122 SMT_EBASE + 22
+#define SMT_E0122_MSG "RMT : illegal state"
+#define SMT_E0123 SMT_EBASE + 23
+#define SMT_E0123_MSG "SBA: state machine has illegal state"
+#define SMT_E0124 SMT_EBASE + 24
+#define SMT_E0124_MSG "sba_free_session() called with NULL pointer"
+#define SMT_E0125 SMT_EBASE + 25
+#define SMT_E0125_MSG "SBA : illegal session pointer"
+#define SMT_E0126 SMT_EBASE + 26
+#define SMT_E0126_MSG "smt_free_mbuf() called with NULL pointer\n"
+#define SMT_E0127 SMT_EBASE + 27
+#define SMT_E0127_MSG "sizeof evcs"
+#define SMT_E0128 SMT_EBASE + 28
+#define SMT_E0128_MSG "evc->evc_cond_state = 0"
+#define SMT_E0129 SMT_EBASE + 29
+#define SMT_E0129_MSG "evc->evc_multiple = 0"
+#define SMT_E0130 SMT_EBASE + 30
+#define SMT_E0130_MSG write_mdr_warning
+#define SMT_E0131 SMT_EBASE + 31
+#define SMT_E0131_MSG cam_warning
+#define SMT_E0132 SMT_EBASE + 32
+#define SMT_E0132_MSG "ST1L.FM_SPCEPDx parity/coding error"
+#define SMT_E0133 SMT_EBASE + 33
+#define SMT_E0133_MSG "ST1L.FM_STBURx tx buffer underrun"
+#define SMT_E0134 SMT_EBASE + 34
+#define SMT_E0134_MSG "ST1L.FM_SPCEPDx parity error"
+#define SMT_E0135 SMT_EBASE + 35
+#define SMT_E0135_MSG "RMT: duplicate MAC address detected. Ring left!"
+#define SMT_E0136 SMT_EBASE + 36
+#define SMT_E0136_MSG "Elasticity Buffer hang-up"
+#define SMT_E0137 SMT_EBASE + 37
+#define SMT_E0137_MSG "SMT: queue overrun"
+#define SMT_E0138 SMT_EBASE + 38
+#define SMT_E0138_MSG "RMT: duplicate MAC address detected. Ring NOT left!"
+#endif /* _CMTDEF_ */
diff --git a/drivers/net/skfp/h/fddi.h b/drivers/net/skfp/h/fddi.h
new file mode 100644
index 000000000..c9a28a8a3
--- /dev/null
+++ b/drivers/net/skfp/h/fddi.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _FDDI_
+#define _FDDI_
+
+struct fddi_addr {
+ u_char a[6] ;
+} ;
+
+#define GROUP_ADDR 0x80 /* MSB in a[0] */
+
+struct fddi_mac {
+ struct fddi_addr mac_dest ;
+ struct fddi_addr mac_source ;
+ u_char mac_info[4478] ;
+} ;
+
+#define FDDI_MAC_SIZE (12)
+#define FDDI_RAW_MTU (4500-5) /* exl. Pr,SD, ED/FS */
+#define FDDI_RAW (4500)
+
+/*
+ * FC values
+ */
+#define FC_VOID 0x40 /* void frame */
+#define FC_TOKEN 0x80 /* token */
+#define FC_RES_TOKEN 0xc0 /* restricted token */
+#define FC_SMT_INFO 0x41 /* SMT Info frame */
+/*
+ * FC_SMT_LAN_LOC && FC_SMT_LOC are SK specific !
+ */
+#define FC_SMT_LAN_LOC 0x42 /* local SMT Info frame */
+#define FC_SMT_LOC 0x43 /* local SMT Info frame */
+#define FC_SMT_NSA 0x4f /* SMT NSA frame */
+#define FC_MAC 0xc0 /* MAC frame */
+#define FC_BEACON 0xc2 /* MAC beacon frame */
+#define FC_CLAIM 0xc3 /* MAC claim frame */
+#define FC_SYNC_LLC 0xd0 /* sync. LLC frame */
+#define FC_ASYNC_LLC 0x50 /* async. LLC frame */
+#define FC_SYNC_BIT 0x80 /* sync. bit in FC */
+
+#define FC_LLC_PRIOR 0x07 /* priority bits */
+
+#define BEACON_INFO 0 /* beacon type */
+#define DBEACON_INFO 1 /* beacon type DIRECTED */
+
+
+/*
+ * indicator bits
+ */
+#define C_INDICATOR (1<<0)
+#define A_INDICATOR (1<<1)
+#define E_INDICATOR (1<<2)
+#define I_INDICATOR (1<<6) /* SK specific */
+#define L_INDICATOR (1<<7) /* SK specific */
+
+#endif /* _FDDI_ */
diff --git a/drivers/net/skfp/h/fddimib.h b/drivers/net/skfp/h/fddimib.h
new file mode 100644
index 000000000..d1acdc773
--- /dev/null
+++ b/drivers/net/skfp/h/fddimib.h
@@ -0,0 +1,349 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FDDI MIB
+ */
+
+/*
+ * typedefs
+ */
+
+typedef u_long Counter ;
+typedef u_char TimeStamp[8] ;
+typedef struct fddi_addr LongAddr ;
+typedef u_long Timer_2 ;
+typedef u_long Timer ;
+typedef u_short ResId ;
+typedef u_short SMTEnum ;
+typedef u_char SMTFlag ;
+
+typedef struct {
+ Counter count ;
+ TimeStamp timestamp ;
+} SetCountType ;
+
+/*
+ * bits for bit string "available_path"
+ */
+#define MIB_PATH_P (1<<0)
+#define MIB_PATH_S (1<<1)
+#define MIB_PATH_L (1<<2)
+
+/*
+ * bits for bit string PermittedPaths & RequestedPaths (SIZE(8))
+ */
+#define MIB_P_PATH_LOCAL (1<<0)
+#define MIB_P_PATH_SEC_ALTER (1<<1)
+#define MIB_P_PATH_PRIM_ALTER (1<<2)
+#define MIB_P_PATH_CON_ALTER (1<<3)
+#define MIB_P_PATH_SEC_PREFER (1<<4)
+#define MIB_P_PATH_PRIM_PREFER (1<<5)
+#define MIB_P_PATH_CON_PREFER (1<<6)
+#define MIB_P_PATH_THRU (1<<7)
+
+/*
+ * enum current path
+ */
+#define MIB_PATH_ISOLATED 0
+#define MIB_PATH_LOCAL 1
+#define MIB_PATH_SECONDARY 2
+#define MIB_PATH_PRIMARY 3
+#define MIB_PATH_CONCATENATED 4
+#define MIB_PATH_THRU 5
+
+/*
+ * enum PMDClass
+ */
+#define MIB_PMDCLASS_MULTI 0
+#define MIB_PMDCLASS_SINGLE1 1
+#define MIB_PMDCLASS_SINGLE2 2
+#define MIB_PMDCLASS_SONET 3
+#define MIB_PMDCLASS_LCF 4
+#define MIB_PMDCLASS_TP 5
+#define MIB_PMDCLASS_UNKNOWN 6
+#define MIB_PMDCLASS_UNSPEC 7
+
+/*
+ * enum SMTStationStatus
+ */
+#define MIB_SMT_STASTA_CON 0
+#define MIB_SMT_STASTA_SEPA 1
+#define MIB_SMT_STASTA_THRU 2
+
+
+struct fddi_mib {
+ /*
+ * private
+ */
+ u_char fddiPRPMFPasswd[8] ;
+ struct smt_sid fddiPRPMFStation ;
+
+#ifdef ESS
+ /*
+ * private variables for static allocation of the
+ * End Station Support
+ */
+ u_long fddiESSPayload ; /* payload for static alloc */
+ u_long fddiESSOverhead ; /* frame ov for static alloc */
+ u_long fddiESSMaxTNeg ; /* maximum of T-NEG */
+ u_long fddiESSMinSegmentSize ; /* min size of the sync frames */
+ u_long fddiESSCategory ; /* category for the Alloc req */
+ short fddiESSSynchTxMode ; /* send all LLC frames as sync */
+#endif /* ESS */
+#ifdef SBA
+ /*
+ * private variables for the Synchronous Bandwidth Allocator
+ */
+ char fddiSBACommand ; /* holds the parsed SBA cmd */
+ u_char fddiSBAAvailable ; /* SBA allocatable value */
+#endif /* SBA */
+
+ /*
+ * SMT standard mib
+ */
+ struct smt_sid fddiSMTStationId ;
+ u_short fddiSMTOpVersionId ;
+ u_short fddiSMTHiVersionId ;
+ u_short fddiSMTLoVersionId ;
+ u_char fddiSMTManufacturerData[32] ;
+ u_char fddiSMTUserData[32] ;
+ u_short fddiSMTMIBVersionId ;
+
+ /*
+ * ConfigGrp
+ */
+ u_char fddiSMTMac_Ct ;
+ u_char fddiSMTNonMaster_Ct ;
+ u_char fddiSMTMaster_Ct ;
+ u_char fddiSMTAvailablePaths ;
+ u_short fddiSMTConfigCapabilities ;
+ u_short fddiSMTConfigPolicy ;
+ u_short fddiSMTConnectionPolicy ;
+ u_short fddiSMTTT_Notify ;
+ u_char fddiSMTStatRptPolicy ;
+ u_long fddiSMTTrace_MaxExpiration ;
+ u_short fddiSMTPORTIndexes[NUMPHYS] ;
+ u_short fddiSMTMACIndexes ;
+ u_char fddiSMTBypassPresent ;
+
+ /*
+ * StatusGrp
+ */
+ SMTEnum fddiSMTECMState ;
+ SMTEnum fddiSMTCF_State ;
+ SMTEnum fddiSMTStationStatus ;
+ u_char fddiSMTRemoteDisconnectFlag ;
+ u_char fddiSMTPeerWrapFlag ;
+
+ /*
+ * MIBOperationGrp
+ */
+ TimeStamp fddiSMTTimeStamp ;
+ TimeStamp fddiSMTTransitionTimeStamp ;
+ SetCountType fddiSMTSetCount ;
+ struct smt_sid fddiSMTLastSetStationId ;
+
+ struct fddi_mib_m {
+ u_short fddiMACFrameStatusFunctions ;
+ Timer_2 fddiMACT_MaxCapabilitiy ;
+ Timer_2 fddiMACTVXCapabilitiy ;
+
+ /* ConfigGrp */
+ u_char fddiMACMultiple_N ; /* private */
+ u_char fddiMACMultiple_P ; /* private */
+ u_char fddiMACDuplicateAddressCond ;/* private */
+ u_char fddiMACAvailablePaths ;
+ u_short fddiMACCurrentPath ;
+ LongAddr fddiMACUpstreamNbr ;
+ LongAddr fddiMACDownstreamNbr ;
+ LongAddr fddiMACOldUpstreamNbr ;
+ LongAddr fddiMACOldDownstreamNbr ;
+ SMTEnum fddiMACDupAddressTest ;
+ u_short fddiMACRequestedPaths ;
+ SMTEnum fddiMACDownstreamPORTType ;
+ ResId fddiMACIndex ;
+
+ /* AddressGrp */
+ LongAddr fddiMACSMTAddress ;
+
+ /* OperationGrp */
+ Timer_2 fddiMACT_Min ; /* private */
+ Timer_2 fddiMACT_ReqMIB ;
+ Timer_2 fddiMACT_Req ; /* private */
+ Timer_2 fddiMACT_Neg ;
+ Timer_2 fddiMACT_MaxMIB ;
+ Timer_2 fddiMACT_Max ; /* private */
+ Timer_2 fddiMACTvxValueMIB ;
+ Timer_2 fddiMACTvxValue ; /* private */
+ Timer_2 fddiMACT_Pri0 ;
+ Timer_2 fddiMACT_Pri1 ;
+ Timer_2 fddiMACT_Pri2 ;
+ Timer_2 fddiMACT_Pri3 ;
+ Timer_2 fddiMACT_Pri4 ;
+ Timer_2 fddiMACT_Pri5 ;
+ Timer_2 fddiMACT_Pri6 ;
+
+ /* CountersGrp */
+ Counter fddiMACFrame_Ct ;
+ Counter fddiMACCopied_Ct ;
+ Counter fddiMACTransmit_Ct ;
+ Counter fddiMACToken_Ct ;
+ Counter fddiMACError_Ct ;
+ Counter fddiMACLost_Ct ;
+ Counter fddiMACTvxExpired_Ct ;
+ Counter fddiMACNotCopied_Ct ;
+ Counter fddiMACRingOp_Ct ;
+
+ Counter fddiMACSMTCopied_Ct ; /* private */
+ Counter fddiMACSMTTransmit_Ct ; /* private */
+
+ /* private for delta ratio */
+ Counter fddiMACOld_Frame_Ct ;
+ Counter fddiMACOld_Copied_Ct ;
+ Counter fddiMACOld_Error_Ct ;
+ Counter fddiMACOld_Lost_Ct ;
+ Counter fddiMACOld_NotCopied_Ct ;
+
+ /* FrameErrorConditionGrp */
+ u_short fddiMACFrameErrorThreshold ;
+ u_short fddiMACFrameErrorRatio ;
+
+ /* NotCopiedConditionGrp */
+ u_short fddiMACNotCopiedThreshold ;
+ u_short fddiMACNotCopiedRatio ;
+
+ /* StatusGrp */
+ SMTEnum fddiMACRMTState ;
+ SMTFlag fddiMACDA_Flag ;
+ SMTFlag fddiMACUNDA_Flag ;
+ SMTFlag fddiMACFrameErrorFlag ;
+ SMTFlag fddiMACNotCopiedFlag ;
+ SMTFlag fddiMACMA_UnitdataAvailable ;
+ SMTFlag fddiMACHardwarePresent ;
+ SMTFlag fddiMACMA_UnitdataEnable ;
+
+ } m[NUMMACS] ;
+#define MAC0 0
+
+ struct fddi_mib_a {
+ ResId fddiPATHIndex ;
+ u_long fddiPATHSbaPayload ;
+ u_long fddiPATHSbaOverhead ;
+ /* fddiPATHConfiguration is built on demand */
+ /* u_long fddiPATHConfiguration ; */
+ Timer fddiPATHT_Rmode ;
+ u_long fddiPATHSbaAvailable ;
+ Timer_2 fddiPATHTVXLowerBound ;
+ Timer_2 fddiPATHT_MaxLowerBound ;
+ Timer_2 fddiPATHMaxT_Req ;
+ } a[NUMPATHS] ;
+#define PATH0 0
+
+ struct fddi_mib_p {
+ /* ConfigGrp */
+ SMTEnum fddiPORTMy_Type ;
+ SMTEnum fddiPORTNeighborType ;
+ u_char fddiPORTConnectionPolicies ;
+ struct {
+ u_char T_val ;
+ u_char R_val ;
+ } fddiPORTMacIndicated ;
+ SMTEnum fddiPORTCurrentPath ;
+ /* must be 4: is 32 bit in SMT format
+ * indices :
+ * 1 none
+ * 2 tree
+ * 3 peer
+ */
+ u_char fddiPORTRequestedPaths[4] ;
+ u_short fddiPORTMACPlacement ;
+ u_char fddiPORTAvailablePaths ;
+ u_char fddiPORTConnectionCapabilities ;
+ SMTEnum fddiPORTPMDClass ;
+ ResId fddiPORTIndex ;
+
+ /* OperationGrp */
+ SMTEnum fddiPORTMaint_LS ;
+ SMTEnum fddiPORTPC_LS ;
+ u_char fddiPORTBS_Flag ;
+
+ /* ErrorCtrsGrp */
+ Counter fddiPORTLCTFail_Ct ;
+ Counter fddiPORTEBError_Ct ;
+ Counter fddiPORTOldEBError_Ct ;
+
+ /* LerGrp */
+ Counter fddiPORTLem_Reject_Ct ;
+ Counter fddiPORTLem_Ct ;
+ u_char fddiPORTLer_Estimate ;
+ u_char fddiPORTLer_Cutoff ;
+ u_char fddiPORTLer_Alarm ;
+
+ /* StatusGrp */
+ SMTEnum fddiPORTConnectState ;
+ SMTEnum fddiPORTPCMState ; /* real value */
+ SMTEnum fddiPORTPCMStateX ; /* value for MIB */
+ SMTEnum fddiPORTPC_Withhold ;
+ SMTFlag fddiPORTHardwarePresent ;
+ u_char fddiPORTLerFlag ;
+
+ u_char fddiPORTMultiple_U ; /* private */
+ u_char fddiPORTMultiple_P ; /* private */
+ u_char fddiPORTEB_Condition ; /* private */
+ } p[NUMPHYS] ;
+ struct {
+ Counter fddiPRIVECF_Req_Rx ; /* ECF req received */
+ Counter fddiPRIVECF_Reply_Rx ; /* ECF repl received */
+ Counter fddiPRIVECF_Req_Tx ; /* ECF req transm */
+ Counter fddiPRIVECF_Reply_Tx ; /* ECF repl transm */
+ Counter fddiPRIVPMF_Get_Rx ; /* PMF Get rec */
+ Counter fddiPRIVPMF_Set_Rx ; /* PMF Set rec */
+ Counter fddiPRIVRDF_Rx ; /* RDF received */
+ Counter fddiPRIVRDF_Tx ; /* RDF transmitted */
+ } priv ;
+} ;
+
+/*
+ * OIDs for statistics
+ */
+#define SMT_OID_CF_STATE 1 /* fddiSMTCF_State */
+#define SMT_OID_PCM_STATE_A 2 /* fddiPORTPCMState port A */
+#define SMT_OID_PCM_STATE_B 17 /* fddiPORTPCMState port B */
+#define SMT_OID_RMT_STATE 3 /* fddiMACRMTState */
+#define SMT_OID_UNA 4 /* fddiMACUpstreamNbr */
+#define SMT_OID_DNA 5 /* fddiMACOldDownstreamNbr */
+#define SMT_OID_ERROR_CT 6 /* fddiMACError_Ct */
+#define SMT_OID_LOST_CT 7 /* fddiMACLost_Ct */
+#define SMT_OID_LEM_CT 8 /* fddiPORTLem_Ct */
+#define SMT_OID_LEM_CT_A 11 /* fddiPORTLem_Ct port A */
+#define SMT_OID_LEM_CT_B 12 /* fddiPORTLem_Ct port B */
+#define SMT_OID_LCT_FAIL_CT 9 /* fddiPORTLCTFail_Ct */
+#define SMT_OID_LCT_FAIL_CT_A 13 /* fddiPORTLCTFail_Ct port A */
+#define SMT_OID_LCT_FAIL_CT_B 14 /* fddiPORTLCTFail_Ct port B */
+#define SMT_OID_LEM_REJECT_CT 10 /* fddiPORTLem_Reject_Ct */
+#define SMT_OID_LEM_REJECT_CT_A 15 /* fddiPORTLem_Reject_Ct port A */
+#define SMT_OID_LEM_REJECT_CT_B 16 /* fddiPORTLem_Reject_Ct port B */
+
+/*
+ * SK MIB
+ */
+#define SMT_OID_ECF_REQ_RX 20 /* ECF requests received */
+#define SMT_OID_ECF_REPLY_RX 21 /* ECF replies received */
+#define SMT_OID_ECF_REQ_TX 22 /* ECF requests transmitted */
+#define SMT_OID_ECF_REPLY_TX 23 /* ECF replies transmitted */
+#define SMT_OID_PMF_GET_RX 24 /* PMF get requests received */
+#define SMT_OID_PMF_SET_RX 25 /* PMF set requests received */
+#define SMT_OID_RDF_RX 26 /* RDF received */
+#define SMT_OID_RDF_TX 27 /* RDF transmitted */
diff --git a/drivers/net/skfp/h/fplustm.h b/drivers/net/skfp/h/fplustm.h
new file mode 100644
index 000000000..9e1ce036e
--- /dev/null
+++ b/drivers/net/skfp/h/fplustm.h
@@ -0,0 +1,274 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * AMD Fplus in tag mode data structs
+ * defs for fplustm.c
+ */
+
+#ifndef _FPLUS_
+#define _FPLUS_
+
+#ifndef HW_PTR
+#ifdef MEM_MAPPED_IO
+#define HW_PTR u_long
+#else
+#define HW_PTR u_short
+#endif
+#endif
+
+/*
+ * fplus error statistic structure
+ */
+struct err_st {
+ u_long err_valid ; /* memory status valid */
+ u_long err_abort ; /* memory status receive abort */
+ u_long err_e_indicator ; /* error indicator */
+ u_long err_crc ; /* error detected (CRC or length) */
+ u_long err_llc_frame ; /* LLC frame */
+ u_long err_mac_frame ; /* MAC frame */
+ u_long err_smt_frame ; /* SMT frame */
+ u_long err_imp_frame ; /* implementer frame */
+ u_long err_no_buf ; /* no buffer available */
+ u_long err_too_long ; /* longer than max. buffer */
+ u_long err_bec_stat ; /* beacon state entered */
+ u_long err_clm_stat ; /* claim state entered */
+ u_long err_sifg_det ; /* short interframe gap detect */
+ u_long err_phinv ; /* PHY invalid */
+ u_long err_tkiss ; /* token issued */
+ u_long err_tkerr ; /* token error */
+} ;
+
+/*
+ * Transmit Descriptor struct
+ */
+struct s_smt_fp_txd {
+ u_long txd_tbctrl ; /* transmit buffer control */
+ u_long txd_txdscr ; /* transmit frame status word */
+ u_long txd_tbadr ; /* physical tx buffer address */
+ u_long txd_ntdadr ; /* physical pointer to the next TxD */
+#ifdef ENA_64BIT_SUP
+ u_long txd_tbadr_hi ; /* physical tx buffer addr (high dword)*/
+#endif
+ char far *txd_virt ; /* virtual pointer to the data frag */
+ /* virt pointer to the next TxD */
+ struct s_smt_fp_txd volatile far *txd_next ;
+ struct s_txd_os txd_os ; /* OS - specific struct */
+} ;
+
+/*
+ * Receive Descriptor struct
+ */
+struct s_smt_fp_rxd {
+ u_long rxd_rbctrl ; /* receive buffer control */
+ u_long rxd_rfsw ; /* receive frame status word */
+ u_long rxd_rbadr ; /* physical rx buffer address */
+ u_long rxd_nrdadr ; /* physical pointer to the next RxD */
+#ifdef ENA_64BIT_SUP
+ u_long rxd_rbadr_hi ; /* physical tx buffer addr (high dword)*/
+#endif
+ char far *rxd_virt ; /* virtual pointer to the data frag */
+ /* virt pointer to the next RxD */
+ struct s_smt_fp_rxd volatile far *rxd_next ;
+ struct s_rxd_os rxd_os ; /* OS - specific struct */
+} ;
+
+/*
+ * Descriptor Union Definition
+ */
+union s_fp_descr {
+ struct s_smt_fp_txd t ; /* pointer to the TxD */
+ struct s_smt_fp_rxd r ; /* pointer to the RxD */
+} ;
+
+/*
+ * TxD Ring Control struct
+ */
+struct s_smt_tx_queue {
+ struct s_smt_fp_txd volatile *tx_curr_put ; /* next free TxD */
+ struct s_smt_fp_txd volatile *tx_prev_put ; /* shadow put pointer */
+ struct s_smt_fp_txd volatile *tx_curr_get ; /* next TxD to release*/
+ u_short tx_free ; /* count of free TxD's */
+ u_short tx_used ; /* count of used TxD's */
+ HW_PTR tx_bmu_ctl ; /* BMU addr for tx start */
+ HW_PTR tx_bmu_dsc ; /* BMU addr for curr dsc. */
+} ;
+
+/*
+ * RxD Ring Control struct
+ */
+struct s_smt_rx_queue {
+ struct s_smt_fp_rxd volatile *rx_curr_put ; /* next RxD to queue into */
+ struct s_smt_fp_rxd volatile *rx_prev_put ; /* shadow put pointer */
+ struct s_smt_fp_rxd volatile *rx_curr_get ; /* next RxD to fill */
+ u_short rx_free ; /* count of free RxD's */
+ u_short rx_used ; /* count of used RxD's */
+ HW_PTR rx_bmu_ctl ; /* BMU addr for rx start */
+ HW_PTR rx_bmu_dsc ; /* BMU addr for curr dsc. */
+} ;
+
+#define VOID_FRAME_OFF 0x00
+#define CLAIM_FRAME_OFF 0x08
+#define BEACON_FRAME_OFF 0x10
+#define DBEACON_FRAME_OFF 0x18
+#define RX_FIFO_OFF 0x21 /* to get a prime number for */
+ /* the RX_FIFO_SPACE */
+
+#define RBC_MEM_SIZE 0x8000
+#define SEND_ASYNC_AS_SYNC 0x1
+#define SYNC_TRAFFIC_ON 0x2
+
+/* big FIFO memory */
+#define RX_FIFO_SPACE 0x4000 - RX_FIFO_OFF
+#define TX_FIFO_SPACE 0x4000
+
+#define TX_SMALL_FIFO 0x0900
+#define TX_MEDIUM_FIFO TX_FIFO_SPACE / 2
+#define TX_LARGE_FIFO TX_FIFO_SPACE - TX_SMALL_FIFO
+
+#define RX_SMALL_FIFO 0x0900
+#define RX_LARGE_FIFO RX_FIFO_SPACE - RX_SMALL_FIFO
+
+struct s_smt_fifo_conf {
+ u_short rbc_ram_start ; /* FIFO start address */
+ u_short rbc_ram_end ; /* FIFO size */
+ u_short rx1_fifo_start ; /* rx queue start address */
+ u_short rx1_fifo_size ; /* rx queue size */
+ u_short rx2_fifo_start ; /* rx queue start address */
+ u_short rx2_fifo_size ; /* rx queue size */
+ u_short tx_s_start ; /* sync queue start address */
+ u_short tx_s_size ; /* sync queue size */
+ u_short tx_a0_start ; /* async queue A0 start address */
+ u_short tx_a0_size ; /* async queue A0 size */
+ u_short fifo_config_mode ; /* FIFO configuration mode */
+} ;
+
+#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1)
+
+struct s_smt_fp {
+ u_short mdr2init ; /* mode register 2 init value */
+ u_short mdr3init ; /* mode register 3 init value */
+ u_short frselreg_init ; /* frame selection register init val */
+ u_short rx_mode ; /* address mode broad/multi/promisc */
+ u_short nsa_mode ;
+ u_short rx_prom ;
+ u_short exgpa ;
+
+ struct err_st err_stats ; /* error statistics */
+
+ /*
+ * MAC buffers
+ */
+ struct fddi_mac_sf { /* special frame build buffer */
+ u_char mac_fc ;
+ struct fddi_addr mac_dest ;
+ struct fddi_addr mac_source ;
+ u_char mac_info[0x20] ;
+ } mac_sfb ;
+
+
+ /*
+ * queues
+ */
+#define QUEUE_S 0
+#define QUEUE_A0 1
+#define QUEUE_R1 0
+#define QUEUE_R2 1
+#define USED_QUEUES 2
+
+ /*
+ * queue pointers; points to the queue dependent variables
+ */
+ struct s_smt_tx_queue *tx[USED_QUEUES] ;
+ struct s_smt_rx_queue *rx[USED_QUEUES] ;
+
+ /*
+ * queue dependent variables
+ */
+ struct s_smt_tx_queue tx_q[USED_QUEUES] ;
+ struct s_smt_rx_queue rx_q[USED_QUEUES] ;
+
+ /*
+ * FIFO configuration struct
+ */
+ struct s_smt_fifo_conf fifo ;
+
+ /* last formac status */
+ u_short s2u ;
+ u_short s2l ;
+
+ /* calculated FORMAC+ reg.addr. */
+ HW_PTR fm_st1u ;
+ HW_PTR fm_st1l ;
+ HW_PTR fm_st2u ;
+ HW_PTR fm_st2l ;
+ HW_PTR fm_st3u ;
+ HW_PTR fm_st3l ;
+
+
+ /*
+ * multicast table
+ */
+#define FPMAX_MULTICAST 32
+#define SMT_MAX_MULTI 4
+ struct {
+ struct s_fpmc {
+ struct fddi_addr a ; /* mc address */
+ u_char n ; /* usage counter */
+ u_char perm ; /* flag: permanent */
+ } table[FPMAX_MULTICAST] ;
+ } mc ;
+ struct fddi_addr group_addr ;
+ u_long func_addr ; /* functional address */
+ int smt_slots_used ; /* count of table entries for the SMT */
+ int os_slots_used ; /* count of table entries */
+ /* used by the os-specific module */
+} ;
+
+/*
+ * modes for mac_set_rx_mode()
+ */
+#define RX_ENABLE_ALLMULTI 1 /* enable all multicasts */
+#define RX_DISABLE_ALLMULTI 2 /* disable "enable all multicasts" */
+#define RX_ENABLE_PROMISC 3 /* enable promiscous */
+#define RX_DISABLE_PROMISC 4 /* disable promiscous */
+#define RX_ENABLE_NSA 5 /* enable reception of NSA frames */
+#define RX_DISABLE_NSA 6 /* disable reception of NSA frames */
+
+
+/*
+ * support for byte reversal in AIX
+ * (descriptors and pointers must be byte reversed in memory
+ * CPU is big endian; M-Channel is little endian)
+ */
+#ifdef AIX
+#define MDR_REV
+#define AIX_REVERSE(x) ((((x)<<24L)&0xff000000L) + \
+ (((x)<< 8L)&0x00ff0000L) + \
+ (((x)>> 8L)&0x0000ff00L) + \
+ (((x)>>24L)&0x000000ffL))
+#else
+#define AIX_REVERSE(x) (x)
+#endif
+
+#ifdef MDR_REV
+#define MDR_REVERSE(x) ((((x)<<24L)&0xff000000L) + \
+ (((x)<< 8L)&0x00ff0000L) + \
+ (((x)>> 8L)&0x0000ff00L) + \
+ (((x)>>24L)&0x000000ffL))
+#else
+#define MDR_REVERSE(x) (x)
+#endif
+
+#endif
diff --git a/drivers/net/skfp/h/hwmtm.h b/drivers/net/skfp/h/hwmtm.h
new file mode 100644
index 000000000..4e360af07
--- /dev/null
+++ b/drivers/net/skfp/h/hwmtm.h
@@ -0,0 +1,424 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _HWM_
+#define _HWM_
+
+#include "h/mbuf.h"
+
+/*
+ * MACRO for DMA synchronization:
+ * The descriptor 'desc' is flushed for the device 'flag'.
+ * Devices are the CPU (DDI_DMA_SYNC_FORCPU) and the
+ * adapter (DDI_DMA_SYNC_FORDEV).
+ *
+ * 'desc' Pointer to a Rx or Tx descriptor.
+ * 'flag' Flag for direction (view for CPU or DEVICE) that
+ * should be synchronized.
+ *
+ * Empty macros and defines are specified here. The real macro
+ * is os-specific and should be defined in osdef1st.h.
+ */
+#ifndef DRV_BUF_FLUSH
+#define DRV_BUF_FLUSH(desc,flag)
+#define DDI_DMA_SYNC_FORCPU
+#define DDI_DMA_SYNC_FORDEV
+#endif
+
+ /*
+ * hardware modul dependent receive modes
+ */
+#define RX_ENABLE_PASS_SMT 21
+#define RX_DISABLE_PASS_SMT 22
+#define RX_ENABLE_PASS_NSA 23
+#define RX_DISABLE_PASS_NSA 24
+#define RX_ENABLE_PASS_DB 25
+#define RX_DISABLE_PASS_DB 26
+#define RX_DISABLE_PASS_ALL 27
+#define RX_DISABLE_LLC_PROMISC 28
+#define RX_ENABLE_LLC_PROMISC 29
+
+
+#ifndef DMA_RD
+#define DMA_RD 1 /* memory -> hw */
+#endif
+#ifndef DMA_WR
+#define DMA_WR 2 /* hw -> memory */
+#endif
+#define SMT_BUF 0x80
+
+ /*
+ * bits of the frame status byte
+ */
+#define EN_IRQ_EOF 0x02 /* get IRQ after end of frame transmission */
+#define LOC_TX 0x04 /* send frame to the local SMT */
+#define LAST_FRAG 0x08 /* last TxD of the frame */
+#define FIRST_FRAG 0x10 /* first TxD of the frame */
+#define LAN_TX 0x20 /* send frame to network if set */
+#define RING_DOWN 0x40 /* error: unable to send, ring down */
+#define OUT_OF_TXD 0x80 /* error: not enough TxDs available */
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef LITTLE_ENDIAN
+#define HWM_REVERSE(x) (x)
+#else
+#define HWM_REVERSE(x) ((((x)<<24L)&0xff000000L) + \
+ (((x)<< 8L)&0x00ff0000L) + \
+ (((x)>> 8L)&0x0000ff00L) + \
+ (((x)>>24L)&0x000000ffL))
+#endif
+
+#define C_INDIC (1L<<25)
+#define A_INDIC (1L<<26)
+#define RD_FS_LOCAL 0x80
+
+ /*
+ * DEBUG FLAGS
+ */
+#define DEBUG_SMTF 1
+#define DEBUG_SMT 2
+#define DEBUG_ECM 3
+#define DEBUG_RMT 4
+#define DEBUG_CFM 5
+#define DEBUG_PCM 6
+#define DEBUG_SBA 7
+#define DEBUG_ESS 8
+
+#define DB_HWM_RX 10
+#define DB_HWM_TX 11
+#define DB_HWM_GEN 12
+
+struct s_mbuf_pool {
+#ifndef MB_OUTSIDE_SMC
+ SMbuf mb[MAX_MBUF] ; /* mbuf pool */
+#endif
+ SMbuf *mb_start ; /* points to the first mb */
+ SMbuf *mb_free ; /* free queue */
+} ;
+
+struct hwm_r {
+ /*
+ * hardware modul specific receive variables
+ */
+ u_int len ; /* length of the whole frame */
+ char *mb_pos ; /* SMbuf receive position */
+} ;
+
+struct hw_modul {
+ /*
+ * All hardware modul specific variables
+ */
+ struct s_mbuf_pool mbuf_pool ;
+ struct hwm_r r ;
+
+ union s_fp_descr volatile *descr_p ; /* points to the desriptor area */
+
+ u_short pass_SMT ; /* pass SMT frames */
+ u_short pass_NSA ; /* pass all NSA frames */
+ u_short pass_DB ; /* pass Direct Beacon Frames */
+ u_short pass_llc_promisc ; /* pass all llc frames (default ON) */
+
+ SMbuf *llc_rx_pipe ; /* points to the first queued llc fr */
+ SMbuf *llc_rx_tail ; /* points to the last queued llc fr */
+ int queued_rx_frames ; /* number of queued frames */
+
+ SMbuf *txd_tx_pipe ; /* points to first mb in the txd ring */
+ SMbuf *txd_tx_tail ; /* points to last mb in the txd ring */
+ int queued_txd_mb ; /* number of SMT MBufs in txd ring */
+
+ int rx_break ; /* rev. was breaked because ind. off */
+ int leave_isr ; /* leave fddi_isr immedeately if set */
+ int isr_flag ; /* set, when HWM is entered from isr */
+ /*
+ * varaibles for the current transmit frame
+ */
+ struct s_smt_tx_queue *tx_p ; /* pointer to the transmit queue */
+ u_long tx_descr ; /* tx descriptor for FORMAC+ */
+ int tx_len ; /* tx frame length */
+ SMbuf *tx_mb ; /* SMT tx MBuf pointer */
+ char *tx_data ; /* data pointer to the SMT tx Mbuf */
+
+ int detec_count ; /* counter for out of RxD condition */
+ u_long rx_len_error ; /* rx len FORMAC != sum of fragments */
+} ;
+
+
+/*
+ * DEBUG structs and macros
+ */
+
+#ifdef DEBUG
+struct os_debug {
+ int hwm_rx ;
+ int hwm_tx ;
+ int hwm_gen ;
+} ;
+#endif
+
+#ifdef DEBUG
+#ifdef DEBUG_BRD
+#define DB_P smc->debug
+#else
+#define DB_P debug
+#endif
+
+#define DB_RX(a,b,c,lev) if (DB_P.d_os.hwm_rx >= (lev)) printf(a,b,c)
+#define DB_TX(a,b,c,lev) if (DB_P.d_os.hwm_tx >= (lev)) printf(a,b,c)
+#define DB_GEN(a,b,c,lev) if (DB_P.d_os.hwm_gen >= (lev)) printf(a,b,c)
+#else /* DEBUG */
+#define DB_RX(a,b,c,lev)
+#define DB_TX(a,b,c,lev)
+#define DB_GEN(a,b,c,lev)
+#endif /* DEBUG */
+
+#ifndef SK_BREAK
+#define SK_BREAK()
+#endif
+
+
+/*
+ * HWM Macros
+ */
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_TX_PHYS)
+ * u_long HWM_GET_TX_PHYS(txd)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to read
+ * the physical address of the specified TxD.
+ *
+ * para txd pointer to the TxD
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_TX_PHYS(txd) (u_long)AIX_REVERSE((txd)->txd_tbadr)
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_TX_LEN)
+ * int HWM_GET_TX_LEN(txd)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to read
+ * the fragment length of the specified TxD
+ *
+ * para rxd pointer to the TxD
+ *
+ * return the length of the fragment in bytes
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_TX_LEN(txd) ((int)AIX_REVERSE((txd)->txd_tbctrl)& RD_LENGTH)
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_TX_USED)
+ * txd *HWM_GET_TX_USED(smc,queue)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to get the
+ * number of used TxDs for the queue, specified by the index.
+ *
+ * para queue the number of the send queue: Can be specified by
+ * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0)
+ *
+ * return number of used TxDs for this send queue
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_TX_USED(smc,queue) (int) (smc)->hw.fp.tx_q[queue].tx_used
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_TXD)
+ * txd *HWM_GET_CURR_TXD(smc,queue)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to get the
+ * pointer to the TxD which points to the current queue put
+ * position.
+ *
+ * para queue the number of the send queue: Can be specified by
+ * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0)
+ *
+ * return pointer to the current TxD
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_CURR_TXD(smc,queue) (struct s_smt_fp_txd volatile *)\
+ (smc)->hw.fp.tx_q[queue].tx_curr_put
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
+ * void HWM_TX_CHECK(smc,frame_status,low_water)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro is invoked by the OS-specific before it left it's
+ * driver_send function. This macro calls mac_drv_clear_txd
+ * if the free TxDs of the current transmit queue is equal or
+ * lower than the given low water mark.
+ *
+ * para frame_status status of the frame, see design description
+ * low_water low water mark of free TxD's
+ *
+ * END_MANUAL_ENTRY
+ */
+#ifndef HWM_NO_FLOW_CTL
+#define HWM_TX_CHECK(smc,frame_status,low_water) {\
+ if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
+ mac_drv_clear_txd(smc) ;\
+ }\
+}
+#else
+#define HWM_TX_CHECK(smc,frame_status,low_water) mac_drv_clear_txd(smc)
+#endif
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
+ * int HWM_GET_RX_FRAG_LEN(rxd)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to read
+ * the fragment length of the specified RxD
+ *
+ * para rxd pointer to the RxD
+ *
+ * return the length of the fragment in bytes
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_RX_FRAG_LEN(rxd) ((int)AIX_REVERSE((rxd)->rxd_rbctrl)& \
+ RD_LENGTH)
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_RX_PHYS)
+ * u_long HWM_GET_RX_PHYS(rxd)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to read
+ * the physical address of the specified RxD.
+ *
+ * para rxd pointer to the RxD
+ *
+ * return the RxD's physical pointer to the data fragment
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_RX_PHYS(rxd) (u_long)AIX_REVERSE((rxd)->rxd_rbadr)
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_RX_USED)
+ * int HWM_GET_RX_USED(smc)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to get
+ * the count of used RXDs in receive queue 1.
+ *
+ * return the used RXD count of receive queue 1
+ *
+ * NOTE: Remember, because of an ASIC bug at least one RXD should be unused
+ * in the descriptor ring !
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_RX_USED(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_used)
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FREE)
+ * int HWM_GET_RX_FREE(smc)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to get
+ * the rxd_free count of receive queue 1.
+ *
+ * return the rxd_free count of receive queue 1
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_RX_FREE(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_free-1)
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_RXD)
+ * rxd *HWM_GET_CURR_RXD(smc)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro may be invoked by the OS-specific module to get the
+ * pointer to the RxD which points to the current queue put
+ * position.
+ *
+ * return pointer to the current RxD
+ *
+ * END_MANUAL_ENTRY
+ */
+#define HWM_GET_CURR_RXD(smc) (struct s_smt_fp_rxd volatile *)\
+ (smc)->hw.fp.rx_q[QUEUE_R1].rx_curr_put
+
+/*
+ * BEGIN_MANUAL_ENTRY(HWM_RX_CHECK)
+ * void HWM_RX_CHECK(smc,low_water)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This macro is invoked by the OS-specific before it left the
+ * function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd
+ * if the number of used RxDs is equal or lower than the
+ * the given low water mark.
+ *
+ * para low_water low water mark of used RxD's
+ *
+ * END_MANUAL_ENTRY
+ */
+#ifndef HWM_NO_FLOW_CTL
+#define HWM_RX_CHECK(smc,low_water) {\
+ if ((low_water) >= (smc)->hw.fp.rx_q[QUEUE_R1].rx_used) {\
+ mac_drv_fill_rxd(smc) ;\
+ }\
+}
+#else
+#define HWM_RX_CHECK(smc,low_water) mac_drv_fill_rxd(smc)
+#endif
+
+#ifndef HWM_EBASE
+#define HWM_EBASE 500
+#endif
+
+#define HWM_E0001 HWM_EBASE + 1
+#define HWM_E0001_MSG "HWM: Wrong size of s_rxd_os struct"
+#define HWM_E0002 HWM_EBASE + 2
+#define HWM_E0002_MSG "HWM: Wrong size of s_txd_os struct"
+#define HWM_E0003 HWM_EBASE + 3
+#define HWM_E0003_MSG "HWM: smt_free_mbuf() called with NULL pointer"
+#define HWM_E0004 HWM_EBASE + 4
+#define HWM_E0004_MSG "HWM: Parity error rx queue 1"
+#define HWM_E0005 HWM_EBASE + 5
+#define HWM_E0005_MSG "HWM: Encoding error rx queue 1"
+#define HWM_E0006 HWM_EBASE + 6
+#define HWM_E0006_MSG "HWM: Encoding error async tx queue"
+#define HWM_E0007 HWM_EBASE + 7
+#define HWM_E0007_MSG "HWM: Encoding error sync tx queue"
+#define HWM_E0008 HWM_EBASE + 8
+#define HWM_E0008_MSG ""
+#define HWM_E0009 HWM_EBASE + 9
+#define HWM_E0009_MSG "HWM: Out of RxD condition detected"
+#define HWM_E0010 HWM_EBASE + 10
+#define HWM_E0010_MSG "HWM: A protocol layer has tried to send a frame with an invalid frame control"
+#define HWM_E0011 HWM_EBASE + 11
+#define HWM_E0011_MSG "HWM: mac_drv_clear_tx_queue was called although the hardware wasn't stopped"
+#define HWM_E0012 HWM_EBASE + 12
+#define HWM_E0012_MSG "HWM: mac_drv_clear_rx_queue was called although the hardware wasn't stopped"
+#define HWM_E0013 HWM_EBASE + 13
+#define HWM_E0013_MSG "HWM: mac_drv_repair_descr was called although the hardware wasn't stopped"
+
+#endif
diff --git a/drivers/net/skfp/h/lnkstat.h b/drivers/net/skfp/h/lnkstat.h
new file mode 100644
index 000000000..c73dcd96a
--- /dev/null
+++ b/drivers/net/skfp/h/lnkstat.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Definition of the Error Log Structure
+ * This structure will be copied into the Error Log buffer
+ * during the NDIS General Request ReadErrorLog by the MAC Driver
+ */
+
+struct s_error_log {
+
+ /*
+ * place holder for token ring adapter error log (zeros)
+ */
+ u_char reserved_0 ; /* byte 0 inside Error Log */
+ u_char reserved_1 ; /* byte 1 */
+ u_char reserved_2 ; /* byte 2 */
+ u_char reserved_3 ; /* byte 3 */
+ u_char reserved_4 ; /* byte 4 */
+ u_char reserved_5 ; /* byte 5 */
+ u_char reserved_6 ; /* byte 6 */
+ u_char reserved_7 ; /* byte 7 */
+ u_char reserved_8 ; /* byte 8 */
+ u_char reserved_9 ; /* byte 9 */
+ u_char reserved_10 ; /* byte 10 */
+ u_char reserved_11 ; /* byte 11 */
+ u_char reserved_12 ; /* byte 12 */
+ u_char reserved_13 ; /* byte 13 */
+
+ /*
+ * FDDI link statistics
+ */
+/*
+ * smt error low
+ */
+#define SMT_ERL_AEB (1<<15) /* A elast. buffer */
+#define SMT_ERL_BLC (1<<14) /* B link error condition */
+#define SMT_ERL_ALC (1<<13) /* A link error condition */
+#define SMT_ERL_NCC (1<<12) /* not copied condition */
+#define SMT_ERL_FEC (1<<11) /* frame error condition */
+
+/*
+ * smt event low
+ */
+#define SMT_EVL_NCE (1<<5)
+
+ u_short smt_error_low ; /* byte 14/15 */
+ u_short smt_error_high ; /* byte 16/17 */
+ u_short smt_event_low ; /* byte 18/19 */
+ u_short smt_event_high ; /* byte 20/21 */
+ u_short connection_policy_violation ; /* byte 22/23 */
+ u_short port_event ; /* byte 24/25 */
+ u_short set_count_low ; /* byte 26/27 */
+ u_short set_count_high ; /* byte 28/29 */
+ u_short aci_id_code ; /* byte 30/31 */
+ u_short purge_frame_counter ; /* byte 32/33 */
+
+ /*
+ * CMT and RMT state machines
+ */
+ u_short ecm_state ; /* byte 34/35 */
+ u_short pcm_a_state ; /* byte 36/37 */
+ u_short pcm_b_state ; /* byte 38/39 */
+ u_short cfm_state ; /* byte 40/41 */
+ u_short rmt_state ; /* byte 42/43 */
+
+ u_short not_used[30] ; /* byte 44-103 */
+
+ u_short ucode_version_level ; /* byte 104/105 */
+
+ u_short not_used_1 ; /* byte 106/107 */
+ u_short not_used_2 ; /* byte 108/109 */
+} ;
diff --git a/drivers/net/skfp/h/mbuf.h b/drivers/net/skfp/h/mbuf.h
new file mode 100644
index 000000000..b339d1f2e
--- /dev/null
+++ b/drivers/net/skfp/h/mbuf.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _MBUF_
+#define _MBUF_
+
+#ifndef PCI
+#define M_SIZE 4550
+#else
+#define M_SIZE 4504
+#endif
+
+#ifndef MAX_MBUF
+#define MAX_MBUF 4
+#endif
+
+#ifndef NO_STD_MBUF
+#define sm_next m_next
+#define sm_off m_off
+#define sm_len m_len
+#define sm_data m_data
+#define SMbuf Mbuf
+#define mtod smtod
+#define mtodoff smtodoff
+#endif
+
+struct s_mbuf {
+ struct s_mbuf *sm_next ; /* low level linked list */
+ short sm_off ; /* offset in m_data */
+ u_int sm_len ; /* len of data */
+#ifdef PCI
+ int sm_use_count ;
+#endif
+ char sm_data[M_SIZE] ;
+} ;
+
+typedef struct s_mbuf SMbuf ;
+
+/* mbuf head, to typed data */
+#define smtod(x,t) ((t)((x)->sm_data + (x)->sm_off))
+#define smtodoff(x,t,o) ((t)((x)->sm_data + (o)))
+
+#endif /* _MBUF_ */
diff --git a/drivers/net/skfp/h/osdef1st.h b/drivers/net/skfp/h/osdef1st.h
new file mode 100644
index 000000000..69f27707d
--- /dev/null
+++ b/drivers/net/skfp/h/osdef1st.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Operating system-dependant definitions that have to be defined
+ * before any other header files are included.
+ */
+
+// HWM (HardWare Module) Definitions
+// -----------------------
+
+#ifdef __LITTLE_ENDIAN
+#define LITTLE_ENDIAN
+#else
+#define BIG_ENDIAN
+#endif
+
+// this is set in the makefile
+// #define PCI /* only PCI adapters supported by this driver */
+// #define MEM_MAPPED_IO /* use memory mapped I/O */
+
+
+#define USE_CAN_ADDR /* DA and SA in MAC header are canonical. */
+
+#define MB_OUTSIDE_SMC /* SMT Mbufs outside of smc struct. */
+
+// -----------------------
+
+
+// SMT Definitions
+// -----------------------
+#define SYNC /* allow synchronous frames */
+
+// #define SBA /* Synchronous Bandwidth Allocator support */
+ /* not available as free source */
+
+#define ESS /* SBA End Station Support */
+
+#define SMT_PANIC(smc, nr, msg) printk(KERN_INFO "SMT PANIC: code: %d, msg: %s\n",nr,msg)
+
+
+#ifdef DEBUG
+#define printf(s,args...) printk(KERN_INFO s, ## args)
+#endif
+
+// #define HW_PTR u_long
+// -----------------------
+
+
+
+// HWM and OS-specific buffer definitions
+// -----------------------
+
+// default number of receive buffers.
+#define NUM_RECEIVE_BUFFERS 10
+
+// default number of transmit buffers.
+#define NUM_TRANSMIT_BUFFERS 10
+
+// Number of SMT buffers (Mbufs).
+#define NUM_SMT_BUF 4
+
+// Number of TXDs for asynchronous transmit queue.
+#define HWM_ASYNC_TXD_COUNT (NUM_TRANSMIT_BUFFERS + NUM_SMT_BUF)
+
+// Number of TXDs for synchronous transmit queue.
+#define HWM_SYNC_TXD_COUNT HWM_ASYNC_TXD_COUNT
+
+
+// Number of RXDs for receive queue #1.
+// Note: Workaround for ASIC Errata #7: One extra RXD is required.
+#if (NUM_RECEIVE_BUFFERS > 100)
+#define SMT_R1_RXD_COUNT (1 + 100)
+#else
+#define SMT_R1_RXD_COUNT (1 + NUM_RECEIVE_BUFFERS)
+#endif
+
+// Number of RXDs for receive queue #2.
+#define SMT_R2_RXD_COUNT 0 // Not used.
+// -----------------------
+
+
+
+/*
+ * OS-specific part of the transmit/receive descriptor structure (TXD/RXD).
+ *
+ * Note: The size of these structures must follow this rule:
+ *
+ * size = 8 + n * 16, n >= 0
+ *
+ * NOTE: The size of this structures may not be changed, because
+ * libskfddi.a depends on it. But the dummy fields can be
+ * used freely.
+ */
+
+struct s_txd_os { // os-specific part of transmit descriptor
+ struct sk_buff *skb;
+ long dummy;
+} ;
+
+struct s_rxd_os { // os-specific part of receive descriptor
+ struct sk_buff *skb;
+ long dummy;
+} ;
+
+
+
diff --git a/drivers/net/skfp/h/sba.h b/drivers/net/skfp/h/sba.h
new file mode 100644
index 000000000..df716cd57
--- /dev/null
+++ b/drivers/net/skfp/h/sba.h
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Synchronous Bandwith Allocation (SBA) structs
+ */
+
+#ifndef _SBA_
+#define _SBA_
+
+#include "h/mbuf.h"
+#include "h/sba_def.h"
+
+#ifdef SBA
+
+/* Timer Cell Template */
+struct timer_cell {
+ struct timer_cell *next_ptr ;
+ struct timer_cell *prev_ptr ;
+ u_long start_time ;
+ struct s_sba_node_vars *node_var ;
+} ;
+
+/*
+ * Node variables
+ */
+struct s_sba_node_vars {
+ u_char change_resp_flag ;
+ u_char report_resp_flag ;
+ u_char change_req_flag ;
+ u_char report_req_flag ;
+ long change_amount ;
+ long node_overhead ;
+ long node_payload ;
+ u_long node_status ;
+ u_char deallocate_status ;
+ u_char timer_state ;
+ u_short report_cnt ;
+ long lastrep_req_tranid ;
+ struct fddi_addr mac_address ;
+ struct s_sba_sessions *node_sessions ;
+ struct timer_cell timer ;
+} ;
+
+/*
+ * Session variables
+ */
+struct s_sba_sessions {
+ u_long deallocate_status ;
+ long session_overhead ;
+ u_long min_segment_size ;
+ long session_payload ;
+ u_long session_status ;
+ u_long sba_category ;
+ long lastchg_req_tranid ;
+ u_short session_id ;
+ u_char class ;
+ u_char fddi2 ;
+ u_long max_t_neg ;
+ struct s_sba_sessions *next_session ;
+} ;
+
+struct s_sba {
+
+ struct s_sba_node_vars node[MAX_NODES] ;
+ struct s_sba_sessions session[MAX_SESSIONS] ;
+
+ struct s_sba_sessions *free_session ; /* points to the first */
+ /* free session */
+
+ struct timer_cell *tail_timer ; /* points to the last timer cell */
+
+ /*
+ * variables for allocation actions
+ */
+ long total_payload ; /* Total Payload */
+ long total_overhead ; /* Total Overhead */
+ long sba_allocatable ; /* allocatable sync bandwidth */
+
+ /*
+ * RAF message receive parameters
+ */
+ long msg_path_index ; /* Path Type */
+ long msg_sba_pl_req ; /* Payload Request */
+ long msg_sba_ov_req ; /* Overhead Request */
+ long msg_mib_pl ; /* Current Payload for this Path */
+ long msg_mib_ov ; /* Current Overhead for this Path*/
+ long msg_category ; /* Category of the Allocation */
+ u_long msg_max_t_neg ; /* longest T_Neg acceptable */
+ u_long msg_min_seg_siz ; /* minimum segement size */
+ struct smt_header *sm ; /* points to the rec message */
+ struct fddi_addr *msg_alloc_addr ; /* Allocation Address */
+
+ /*
+ * SBA variables
+ */
+ u_long sba_t_neg ; /* holds the last T_NEG */
+ long sba_max_alloc ; /* the parsed value of SBAAvailable */
+
+ /*
+ * SBA state machine variables
+ */
+ short sba_next_state ; /* the next state of the SBA */
+ char sba_command ; /* holds the execuded SBA cmd */
+ u_char sba_available ; /* parsed value after possible check */
+} ;
+
+#endif /* SBA */
+
+ /*
+ * variables for the End Station Support
+ */
+struct s_ess {
+
+ /*
+ * flags and counters
+ */
+ u_char sync_bw_available ; /* is set if sync bw is allocated */
+ u_char local_sba_active ; /* set when a local sba is available */
+ char raf_act_timer_poll ; /* activate the timer to send allc req */
+ char timer_count ; /* counts every timer function call */
+
+ SMbuf *sba_reply_pend ; /* local reply for the sba is pending */
+
+ /*
+ * variables for the ess bandwidth control
+ */
+ long sync_bw ; /* holds the allocaed sync bw */
+ u_long alloc_trans_id ; /* trans id of the last alloc req */
+} ;
+#endif
diff --git a/drivers/net/skfp/h/sba_def.h b/drivers/net/skfp/h/sba_def.h
new file mode 100644
index 000000000..0459a095d
--- /dev/null
+++ b/drivers/net/skfp/h/sba_def.h
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#define PHYS 0 /* physical addr */
+#define PERM_ADDR 0x80 /* permanet address */
+#define SB_STATIC 0x00000001
+#define MAX_PAYLOAD 1562
+#define PRIMARY_RING 0x00000001
+#ifndef NULL
+#define NULL 0x00
+#endif
+
+/*********************** SB_Input Variable Values ***********************/
+/* may be needed when ever the SBA state machine is called */
+
+#define UNKNOWN_SYNC_SOURCE 0x0001
+#define REQ_ALLOCATION 0x0002
+#define REPORT_RESP 0x0003
+#define CHANGE_RESP 0x0004
+#define TNEG 0x0005
+#define NIF 0x0006
+#define SB_STOP 0x0007
+#define SB_START 0x0008
+#define REPORT_TIMER 0x0009
+#define CHANGE_REQUIRED 0x000A
+
+#define DEFAULT_OV 50
+
+#ifdef SBA
+/**************************** SBA STATES *****************************/
+
+#define SBA_STANDBY 0x00000000
+#define SBA_ACTIVE 0x00000001
+#define SBA_RECOVERY 0x00000002
+#define SBA_REPORT 0x00000003
+#define SBA_CHANGE 0x00000004
+
+/**************************** OTHERS *********************************/
+
+#define FIFTY_PERCENT 50 /* bytes per second */
+#define MAX_SESSIONS 150
+#define TWO_MINUTES 13079 /* 9.175 ms/tick */
+#define FIFTY_BYTES 50
+#define SBA_DENIED 0x0000000D
+#define I_NEED_ONE 0x00000000
+#define MAX_NODES 50
+/*#define T_REPORT 0x59682F00L*/ /* 120s/80ns in Hex */
+#define TWO_MIN 120 /* seconds */
+#define SBA_ST_UNKNOWN 0x00000002
+#define SBA_ST_ACTIVE 0x00000001
+#define S_CLEAR 0x00000000L
+#define ZERO 0x00000000
+#define FULL 0x00000000 /* old: 0xFFFFFFFFF */
+#define S_SET 0x00000001L
+#define LOW_PRIO 0x02 /* ??????? */
+#define OK 0x01 /* ??????? */
+#define NOT_OK 0x00 /* ??????? */
+
+/****************************************/
+/* deallocate_status[ni][si] values */
+/****************************************/
+#define TX_CHANGE 0X00000001L
+#define PENDING 0x00000002L
+#define NONE 0X00000000L
+#endif
diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h
new file mode 100644
index 000000000..f127bddb8
--- /dev/null
+++ b/drivers/net/skfp/h/skfbi.h
@@ -0,0 +1,1920 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _SKFBI_H_
+#define _SKFBI_H_
+
+#ifdef SYNC
+#define exist_board_far exist_board
+#define get_board_para_far get_board_para
+#endif
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#ifndef PCI
+#define ADDR(a) ((a)+smc->hw.iop)
+#define ADDRS(smc,a) ((a)+(smc)->hw.iop)
+#endif
+
+/*
+ * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)})
+ * address calculation & function defines
+ */
+
+#ifdef EISA
+
+/*
+ * Configuration PROM: !! all 8-Bit IO's !!
+ * |<- MAC-Address ->|
+ * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
+ * val: |PROD_ID0..3| | free | |00|00|5A|40| |nn|mm|00|00|
+ * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
+ * IO- ^ ^ ^ ^ ^
+ * port 0C80 0C83 0C88 0C90 0C98
+ * | \
+ * | \
+ * | \______________________________________________
+ * EISA Expansion Board Product ID: \
+ * BIT: |7 6 5 4 3 2 1 0| \
+ * | PROD_ID0 | PROD_ID1 | PROD_ID2 | PROD_ID3 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |0| MAN_C0 | MAN_C1 | MAN_C2 | PROD1 | PROD0 | REV1 | REV0 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ^=reserved | product numb. | revision numb |
+ * MAN_Cx = compressed manufacterer code (x:=0..2)
+ * ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!)
+ */
+
+#ifndef MULT_OEM
+#ifndef OEM_CONCEPT
+#define MAN_C0 ('S'-0x40)
+#define MAN_C1 ('K'-0x40)
+#define MAN_C2 ('D'-0x40)
+#define PROD_ID0 (u_char)((MAN_C0<<2) | (MAN_C1>>3))
+#define PROD_ID1 (u_char)(((MAN_C1<<5) & 0xff) | MAN_C2)
+#define PROD_ID2 (u_char)(1) /* prod. nr. */
+#define PROD_ID3 (u_char)(0) /* rev. nr. */
+
+#ifndef OEM_USER_DATA
+#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata"
+#endif
+#else /* OEM_CONCEPT */
+
+/* MAN_C(0|1|2) no longer present (ra). */
+#define PROD_ID0 (u_char)OEM_PROD_ID0
+#define PROD_ID1 (u_char)OEM_PROD_ID1
+#define PROD_ID2 (u_char)OEM_PROD_ID2
+#define PROD_ID3 (u_char)OEM_PROD_ID3
+#endif /* OEM_CONCEPT */
+
+#define SKLOGO PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3
+#endif /* MULT_OEM */
+
+#define SADDRL (0) /* start address SKLOGO */
+#define SA_MAC (0x10) /* start addr. MAC_AD within the PROM */
+#define PRA_OFF (4)
+#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
+
+#define SKFDDI_PSZ 32 /* address PROM size */
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */
+#define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */
+#define P2A(a) (0x0840|((a)<<1)) /* PLC2 (r/w) */
+#define TIA(a) (0x0880|((a)<<1)) /* Timer (r/w) */
+#define PRA(a) (0x0c80| (a)) /* configuration PROM */
+#define C0A(a) (0x0c84| (a)) /* config. RAM */
+#define C1A(a) (0x0ca0| (a)) /* IRQ-, DMA-nr., EPROM type */
+#define C2A(a) (0x0ca4| (a)) /* EPROM and PAGE selector */
+
+#define CONF C0A(0) /* config RAM (card enable bit port) */
+#define PGRA C2A(0) /* Flash page register */
+#define CDID PRA(0) /* Card ID I/O port addr. offset */
+
+
+/*
+ * physical address offset + slot specific IO-Port base address
+ */
+#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */
+#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */
+#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */
+#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */
+#define PR_A(a) (PRA(a)+smc->hw.iop) /* config. PROM */
+#define C0_A(a) (C0A(a)+smc->hw.iop) /* config. RAM */
+#define C1_A(a) (C1A(a)+smc->hw.iop) /* config. RAM */
+#define C2_A(a) (C2A(a)+smc->hw.iop) /* config. RAM */
+
+
+#define CSRA 0x0008 /* control/status register address (r/w) */
+#define ISRA 0x0008 /* int. source register address (upper 8Bits) */
+#define PLC1I 0x001a /* clear PLC1 interrupt (write only) */
+#define PLC2I 0x0020 /* clear PLC2 interrupt (write only) */
+#define CSFA 0x001c /* control/status FIFO BUSY flags (read only) */
+#define RQAA 0x001c /* Request reg. (write only) */
+#define WCTA 0x001e /* word counter (r/w) */
+#define FFLAG 0x005e /* FLAG/V_FULL (FIFO almost full, write only)*/
+
+#define CSR_A (CSRA+smc->hw.iop) /* control/status register address (r/w) */
+#ifdef UNIX
+#define CSR_AS(smc) (CSRA+(smc)->hw.iop) /* control/status register address (r/w) */
+#endif
+#define ISR_A (ISRA+smc->hw.iop) /* int. source register address (upper 8Bits) */
+#define PLC1_I (PLC1I+smc->hw.iop) /* clear PLC1 internupt (write only) */
+#define PLC2_I (PLC2I+smc->hw.iop) /* clear PLC2 interrupt (write only) */
+#define CSF_A (CSFA+smc->hw.iop) /* control/status FIFO BUSY flags (r/w) */
+#define RQA_A (RQAA+smc->hw.iop) /* Request reg. (write only) */
+#define WCT_A (WCTA+smc->hw.iop) /* word counter (r/w) */
+#define FFLAG_A (FFLAG+smc->hw.iop) /* FLAG/V_FULL (FIFO almost full, write only)*/
+
+/*
+ * control/status register CSRA bits
+ */
+/* write */
+#define CS_CRESET 0x01 /* Card reset (0=reset) */
+#define CS_RESET_FIFO 0x02 /* FIFO reset (0=reset) */
+#define CS_IMSK 0x04 /* enable IRQ (1=enable, 0=disable) */
+#define CS_EN_IRQ_TC 0x08 /* enable IRQ from transfer counter */
+#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/
+#define CS_LED_0 0x40 /* switch LED 0 */
+#define CS_LED_1 0x80 /* switch LED 1 */
+/* read */
+#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */
+#define CS_SAS 0x80 /* single attachement station (=1) */
+
+/*
+ * control/status register CSFA bits (FIFO)
+ */
+#define CSF_MUX0 0x01
+#define CSF_MUX1 0x02
+#define CSF_HSREQ0 0x04
+#define CSF_HSREQ1 0x08
+#define CSF_HSREQ2 0x10
+#define CSF_BUSY_DMA 0x40
+#define CSF_BUSY_FIFO 0x80
+
+/*
+ * Interrupt source register ISRA (upper 8 data bits) read only & low activ.
+ */
+#define IS_MINTR1 0x0100 /* FORMAC ST1U/L & ~IMSK1U/L*/
+#define IS_MINTR2 0x0200 /* FORMAC ST2U/L & ~IMSK2U/L*/
+#define IS_PLINT1 0x0400 /* PLC1 */
+#define IS_PLINT2 0x0800 /* PLC2 */
+#define IS_TIMINT 0x1000 /* Timer 82C54-2 */
+#define IS_TC 0x2000 /* transf. counter */
+
+#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC)
+
+/*
+ * CONFIG<0> RAM (C0_A())
+ */
+#define CFG_CARD_EN 0x01 /* card enable */
+
+/*
+ * CONFIG<1> RAM (C1_A())
+ */
+#define CFG_IRQ_SEL 0x03 /* IRQ select (4 nr.) */
+#define CFG_IRQ_TT 0x04 /* IRQ trigger type (LEVEL/EDGE) */
+#define CFG_DRQ_SEL 0x18 /* DMA requ. (4 nr.) */
+#define CFG_BOOT_EN 0x20 /* 0=BOOT-, 1=Application Software */
+#define CFG_PROG_EN 0x40 /* V_Prog for FLASH_PROM (1=on) */
+
+/*
+ * CONFIG<2> RAM (C2_A())
+ */
+#define CFG_EPROM_SEL 0x0f /* FPROM start address selection */
+#define CFG_PAGE 0xf0 /* FPROM page selection */
+
+
+#define READ_PROM(a) ((u_char)inp(a))
+#define GET_PAGE(i) outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE))
+#define FPROM_SW() (inp(C1_A(0)) & CFG_BOOT_EN)
+
+#define MAX_PAGES 16 /* 16 pages */
+#define MAX_FADDR 0x2000 /* 8K per page */
+#define VPP_ON() outp(C1_A(0),inp(C1_A(0)) | CFG_PROG_EN)
+#define VPP_OFF() outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN)
+
+#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA)
+#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO)
+#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
+#define BUS_CHECK()
+
+#ifdef UNISYS
+/* For UNISYS use another macro with drv_usecewait function */
+#define CHECK_DMA() {u_long k = 1000000; \
+ while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \
+ if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+#else
+#define CHECK_DMA() {u_long k = 1000000 ;\
+ while (k && (DMA_BUSY())) k-- ;\
+ if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+#endif
+
+#define CHECK_FIFO() {u_long k = 1000000 ;\
+ while (k && (FIFO_BUSY())) k-- ;\
+ if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
+
+#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
+ while (k && (DMA_FIFO_BUSY())) k-- ;\
+ if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
+
+#define GET_ISR() ~inpw(ISR_A)
+#define CHECK_ISR() ~inpw(ISR_A)
+
+#ifndef UNIX
+#ifndef WINNT
+#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&\
+ (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
+#else /* WINNT */
+#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A)&\
+ (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
+#endif /* WINNT */
+#else /* UNIX */
+#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
+ (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led)
+#endif
+
+#ifndef UNIX
+#define STI_FBI() outpw(CSR_A,(inpw(CSR_A)&\
+ (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led)
+#else
+#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
+ (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led)
+#endif
+
+/* EISA DMA Controller */
+#define DMA_WRITE_SINGLE_MASK_BIT_M 0x0a /* Master DMA Controller */
+#define DMA_WRITE_SINGLE_MASK_BIT_S 0xd4 /* Slave DMA Controller */
+#define DMA_CLEAR_BYTE_POINTER_M 0x0c
+#define DMA_CLEAR_BYTE_POINTER_S 0xd8
+
+#endif /* EISA */
+
+#ifdef MCA
+
+/*
+ * POS Register: !! all I/O's are 8-Bit !!
+ */
+#define POS_SYS_SETUP 0x94 /* system setup register */
+#define POS_SYSTEM 0xff /* system mode */
+
+#define POS_CHANNEL_POS 0x96 /* register slot ID */
+#define POS_CHANNEL_BIT 0x08 /* mask for -"- */
+
+#define POS_BASE 0x100 /* POS base address */
+#define POS_ID_LOW POS_BASE /* card ID low */
+#define POS_ID_HIGH (POS_BASE+1) /* card ID high */
+#define POS_102 (POS_BASE+2) /* card en., arbitration level .. */
+#define POS_103 (POS_BASE+3) /* FPROM addr, page */
+#define POS_104 (POS_BASE+4) /* I/O, IRQ */
+#define POS_105 (POS_BASE+5) /* POS_CHCK */
+#define POS_106 (POS_BASE+6) /* to read VPD */
+#define POS_107 (POS_BASE+7) /* added without function */
+
+/* FM1 card IDs */
+#define FM1_CARD_ID0 0x83
+#define FM1_CARD_ID1 0
+
+#define FM1_IBM_ID0 0x9c
+#define FM1_IBM_ID1 0x8f
+
+
+/* FM2 card IDs */
+#define FM2_CARD_ID0 0xab
+#define FM2_CARD_ID1 0
+
+#define FM2_IBM_ID0 0x7e
+#define FM2_IBM_ID1 0x8f
+
+/* Board revision. */
+#define FM1_REV 0
+#define FM2_REV 1
+
+#define MAX_SLOT 8
+
+/*
+ * POS_102
+ */
+#define POS_CARD_EN 0x01 /* card enable =1 */
+#define POS_SDAT_EN 0x02 /* enable 32-bit streaming data mode */
+#define POS_EN_CHKINT 0x04 /* enable int. from check line asserted */
+#define POS_EN_BUS_ERR 0x08 /* enable int. on invalid busmaster transf. */
+#define POS_FAIRNESS 0x10 /* fairnes on =1 */
+/* attention: arbitration level used with bit 0 POS 105 */
+#define POS_LARBIT 0xe0 /* arbitration level (0,0,0)->level = 0x8
+ (1,1,1)->level = 0xf */
+/*
+ * POS_103
+ */
+#define POS_PAGE 0x07 /* FPROM page selection */
+#define POS_BOOT_EN 0x08 /* boot PROM enable =1 */
+#define POS_MSEL 0x70 /* memory start address for FPROM mapping */
+#define PROG_EN 0x80 /* FM1: Vpp prog on/off */
+#define POS_SDR 0x80 /* FM2: Streaming data bit */
+
+/*
+ * POS_104
+ */
+#define POS_IOSEL 0x3f /* selected I/O base address */
+#define POS_IRQSEL 0xc0 /* selected interrupt */
+
+/*
+ * POS_105
+ */
+#define POS_CHCK 0x80
+#define POS_SYNC_ERR 0x20 /* FM2: synchronous error reporting */
+#define POS_PAR_DATA 0x10 /* FM2: data parity enable bit */
+#define POS_PAR_ADDR 0x08 /* FM2: address parity enable bit */
+#define POS_IRQHSEL 0x02 /* FM2: Highest bit for IRQ_selection */
+#define POS_HARBIT 0x01 /* Highest bit in Bus arbitration selection */
+
+#define SA_MAC (0) /* start addr. MAC_AD within the PROM */
+#define PRA_OFF (0)
+#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */
+#define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */
+#define P1(a) (0x0080|((a)<<1)) /* PLC1 (r/w) */
+#define TI(a) (0x0060|((a)<<1)) /* Timer (r/w) */
+#define PR(a) (0x0040|((a)<<1)) /* configuration PROM */
+#define CS(a) (0x0020| (a)) /* control/status */
+#define FF(a) (0x0010|((a)<<1)) /* FIFO ASIC */
+#define CT(a) (0x0000|((a)<<1)) /* counter */
+
+/*
+ * counter
+ */
+#define ACLA CT(0) /* address counter low */
+#define ACHA CT(1) /* address counter high */
+#define BCN CT(2) /* byte counter */
+#define MUX CT(3) /* MUX-register */
+#define WCN CT(0x08) /* word counter */
+#define FFLG CT(0x09) /* FIFO Flags */
+
+/*
+ * test/control register (FM2 only)
+ */
+#define CNT_TST 0x018 /* Counter test control register */
+#define CNT_STP 0x01a /* Counter test step reg. (8 Bit) */
+
+/*
+ * CS register (read only)
+ */
+#define CSRA CS(0) /* control/status register address */
+#define CSFA CS(2) /* control/status FIFO BUSY ... */
+#define ISRA CS(4) /* first int. source register address */
+#define ISR2 CS(6) /* second int. source register address */
+#define LEDR CS(0x0c) /* LED register r/w */
+#define CSIL CS(0x10) /* I/O mapped POS_ID_low (100) */
+#define CSIH CS(0x12) /* - " - POS_ID_HIGH (101) */
+#define CSA CS(0x14) /* - " - POS_102 */
+#define CSM CS(0x0e) /* - " - POS_103 */
+#define CSM_FM1 CS(0x16) /* - " - POS_103 (copy in FM1) */
+#define CSI CS(0x18) /* - " - POS_104 */
+#define CSS CS(0x1a) /* - " - POS_105 */
+#define CSP_06 CS(0x1c) /* - " - POS_106 */
+#define WDOG_ST 0x1c /* Watchdog status (FM2 only) */
+#define WDOG_EN 0x1c /* Watchdog enabling (FM2 only, 8Bit) */
+#define WDOG_DIS 0x1e /* Watchdog disabling (FM2 only, 8Bit) */
+
+#define PGRA CSM /* Flash page register */
+
+
+#define WCTA FF(0) /* word counter */
+#define FFLAG FF(1) /* FLAG/V_FULL (FIFO almost full, write only)*/
+
+/*
+ * Timer register (FM2 only)
+ */
+#define RTM_CNT 0x28 /* RTM Counter */
+#define TI_DIV 0x60 /* Timer Prescaler */
+#define TI_CH1 0x62 /* Timer channel 1 counter */
+#define TI_STOP 0x64 /* Stop timer on channel 1 */
+#define TI_STRT 0x66 /* Start timer on channel 1 */
+#define TI_INI2 0x68 /* Timer: Bus master preemption */
+#define TI_CNT2 0x6a /* Timer */
+#define TI_INI3 0x6c /* Timer: Streaming data */
+#define TI_CNT3 0x6e /* Timer */
+#define WDOG_LO 0x70 /* Watchdog counter low */
+#define WDOG_HI 0x72 /* Watchdog counter high */
+#define RTM_PRE 0x74 /* restr. token prescaler */
+#define RTM_TIM 0x76 /* restr. token timer */
+
+/*
+ * Recommended Timeout values (for FM2 timer only)
+ */
+#define TOUT_BM_PRE 188 /* 3.76 usec */
+#define TOUT_S_DAT 374 /* 7.48 usec */
+
+/*
+ * CS register (write only)
+ */
+#define HSR(p) CS(0x18|(p)) /* Host request register */
+
+#define RTM_PUT 0x36 /* restr. token counter write */
+#define RTM_GET 0x28 /* - " - clear */
+#define RTM_CLEAR 0x34 /* - " - read */
+
+/*
+ * BCN Bit definitions
+ */
+#define BCN_BUSY 0x8000 /* DMA Busy flag */
+#define BCN_AZERO 0x4000 /* Almost zero flag (BCN < 4) */
+#define BCN_STREAM 0x2000 /* Allow streaming data (BCN >= 8) */
+
+/*
+ * WCN Bit definitions
+ */
+#define WCN_ZERO 0x2000 /* Zero flag (counted to zero) */
+#define WCN_AZERO 0x1000 /* Almost zero flag (BCN < 4) */
+
+/*
+ * CNT_TST Bit definitions
+ */
+#define CNT_MODE 0x01 /* Go into test mode */
+#define CNT_D32 0x02 /* 16/32 BIT test mode */
+
+/*
+ * FIFO Flag FIFO Flags/Vfull register
+ */
+#define FF_VFULL 0x003f /* V_full value mask */
+#define FFLG_FULL 0x2000 /* FULL flag */
+#define FFLG_A_FULL 0x1000 /* Almost full flag */
+#define FFLG_VFULL 0x0800 /* V_full Flag */
+#define FFLG_A_EMP 0x0400 /* almost empty flag */
+#define FFLG_EMP 0x0200 /* empty flag */
+#define FFLG_T_EMP 0x0100 /* totally empty flag */
+
+/*
+ * WDOG Watchdog status register
+ */
+#define WDOG_ALM 0x01 /* Watchdog alarm Bit */
+#define WDOG_ACT 0x02 /* Watchdog active Bit */
+
+/*
+ * CS(0) CONTROLS
+ */
+#define CS_CRESET 0x0001
+#define FIFO_RST 0x0002
+#define CS_IMSK 0x0004
+#define EN_IRQ_CHCK 0x0008
+#define EN_IRQ_TOKEN 0x0010
+#define EN_IRQ_TC 0x0020
+#define TOKEN_STATUS 0x0040
+#define RTM_CHANGE 0x0080
+
+#define CS_SAS 0x0100
+#define CS_BYSTAT 0x0200 /* bypass connected (0=conn.) */
+#define CS_BYPASS 0x0400 /* bypass on/off indication */
+
+/*
+ * CS(2) FIFOSTAT
+ */
+#define HSREQ 0x0007
+#define BIGDIR 0x0008
+#define CSF_BUSY_FIFO 0x0010
+#define CSF_BUSY_DMA 0x0020
+#define SLOT_32 0x0040
+
+#define LED_0 0x0001
+#define LED_1 0x0002
+#define LED_2 0x0100
+
+#define MAX_PAGES 8 /* pages */
+#define MAX_FADDR 0x4000 /* 16K per page */
+
+/*
+ * IRQ = ISRA || ISR2 ;
+ *
+ * ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ;
+ * ISR2 = IRQ_TC_EN && IS_TC ;
+ *
+ * IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) ||
+ * (IRQ_EN_TOKEN && IS_TOKEN) ;
+ * IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ;
+ */
+/*
+ * ISRA !!! activ high !!!
+ */
+#define IS_MINTR1 0x0001 /* FORMAC ST1U/L & ~IMSK1U/L*/
+#define IS_MINTR2 0x0002 /* FORMAC ST2U/L & ~IMSK2U/L*/
+#define IS_PLINT1 0x0004 /* PLC1 */
+#define IS_PLINT2 0x0008 /* PLC2 */
+#define IS_TIMINT 0x0010 /* Timer 82C54-2 */
+#define IS_TOKEN 0x0020 /* restrictet token monitoring */
+#define IS_CHCK_L 0x0040 /* check line asserted */
+#define IS_BUSERR 0x0080 /* bus error */
+/*
+ * ISR2
+ */
+#define IS_TC 0x0001 /* terminal count irq */
+#define IS_SFDBKRTN 0x0002 /* selected feedback return */
+#define IS_D16 0x0004 /* DS16 */
+#define IS_D32 0x0008 /* DS32 */
+#define IS_DPEI 0x0010 /* Data Parity Indication */
+
+#define ALL_IRSR 0x00ff
+
+#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */
+#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */
+#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */
+#define TI_A(a) ADDR(TI(a)) /* Timer (r/w) FM1 only! */
+#define PR_A(a) ADDR(PR(a)) /* config. PROM */
+#define CS_A(a) ADDR(CS(a)) /* control/status */
+
+#define ISR1_A ADDR(ISRA) /* first int. source register address */
+#define ISR2_A ADDR(ISR2) /* second -"- */
+#define CSR_A ADDR(CSRA) /* control/status register address */
+#define CSF_A ADDR(CSFA) /* control/status FIFO BUSY flags (r/w) */
+
+#define CSIL_A ADDR(CSIL) /* I/O mapped POS_ID_low (102) */
+#define CSIH_A ADDR(CSIH) /* - " - POS_ID_HIGH (101) */
+#define CSA_A ADDR(CSA) /* - " - POS_102 */
+#define CSI_A ADDR(CSI) /* - " - POS_104 */
+#define CSM_A ADDR(CSM) /* - " - POS_103 */
+#define CSM_FM1_A ADDR(CSM_FM1) /* - " - POS_103 (2nd copy, FM1) */
+#define CSP_06_A ADDR(CSP_06) /* - " - POS_106 */
+
+#define WCT_A ADDR(WCTA) /* word counter (r/w) */
+#define FFLAG_A ADDR(FFLAG) /* FLAG/V_FULL (FIFO almost full, write only)*/
+
+#define ACL_A ADDR(ACLA) /* address counter low */
+#define ACH_A ADDR(ACHA) /* address counter high */
+#define BCN_A ADDR(BCN) /* byte counter */
+#define MUX_A ADDR(MUX) /* MUX-register */
+
+#define ISR_A ADDR(ISRA) /* Interrupt Source Register */
+#define FIFO_RESET_A ADDR(FIFO_RESET) /* reset the FIFO */
+#define FIFO_EN_A ADDR(FIFO_EN) /* enable the FIFO */
+
+#define WDOG_EN_A ADDR(WDOG_EN) /* reset and start the WDOG */
+#define WDOG_DIS_A ADDR(WDOG_DIS) /* disable the WDOG */
+/*
+ * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A)
+ */
+#define HSR_A(p) ADDR(HSR(p)) /* Host request register */
+
+#define STAT_BYP 0 /* bypass station */
+#define STAT_INS 2 /* insert station */
+#define BYPASS(o) CS(0x10|(o)) /* o=STAT_BYP || STAT_INS */
+
+#define IRQ_TC_EN CS(0x0b) /* enable/disable IRQ on TC */
+#define IRQ_TC_DIS CS(0x0a)
+#define IRQ_TOKEN_EN CS(9) /* enable/disable IRQ on restr. Token */
+#define IRQ_TOKEN_DIS CS(8)
+#define IRQ_CHCK_EN CS(7) /* -"- IRQ after CHCK line */
+#define IRQ_CHCK_DIS CS(6)
+#define IRQ_OTH_EN CS(5) /* -"- other IRQ's */
+#define IRQ_OTH_DIS CS(4)
+#define FIFO_EN CS(3) /* disable (reset), enable FIFO */
+#define FIFO_RESET CS(2)
+#define CARD_EN CS(1) /* disable (reset), enable card */
+#define CARD_DIS CS(0)
+
+#define LEDR_A ADDR(LEDR) /* D0=green, D1=yellow, D8=L2 */
+#define PAGE_RG_A ADDR(CSM) /* D<2..0> */
+#define IRQ_CHCK_EN_A ADDR(IRQ_CHCK_EN)
+#define IRQ_CHCK_DIS_A ADDR(IRQ_CHCK_DIS)
+
+#define GET_PAGE(bank) outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\
+ (~POS_PAGE)) |(int) (bank))
+#define VPP_ON() if (smc->hw.rev == FM1_REV) { \
+ outpw(PAGE_RG_A, \
+ (inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \
+ }
+#define VPP_OFF() if (smc->hw.rev == FM1_REV) { \
+ outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \
+ }
+
+#define SKFDDI_PSZ 16 /* address PROM size */
+
+#define READ_PROM(a) ((u_char)inp(a))
+
+#define GET_ISR() ~inpw(ISR1_A)
+#ifndef TCI
+#define CHECK_ISR() ~inpw(ISR1_A)
+#define CHECK_ISR_SMP(iop) ~inpw((iop)+ISRA)
+#else
+#define CHECK_ISR() (~inpw(ISR1_A) | ~inpw(ISR2_A))
+#define CHECK_ISR_SMP(iop) (~inpw((iop)+ISRA) | ~inpw((iop)+ISR2))
+#endif
+
+#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA)
+#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO)
+#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
+#define BUS_CHECK() { int i ; \
+ if ((i = GET_ISR()) & IS_BUSERR) \
+ SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \
+ if (i & IS_CHCK_L) \
+ SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \
+ }
+
+#define CHECK_DMA() { u_long k = 10000 ; \
+ while (k && (DMA_BUSY())) { \
+ k-- ; \
+ BUS_CHECK() ; \
+ } \
+ if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+
+#define CHECK_FIFO() {u_long k = 1000000 ;\
+ while (k && (FIFO_BUSY())) k-- ;\
+ if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
+
+#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
+ while (k && (DMA_FIFO_BUSY())) { \
+ k-- ;\
+ BUS_CHECK() ; \
+ } \
+ if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
+
+#ifndef UNIX
+#define CLI_FBI() outp(ADDR(IRQ_OTH_DIS),0)
+#else
+#define CLI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_DIS),0)
+#endif
+
+#ifndef TCI
+#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0)
+#else
+#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) ;\
+ outp((iop)+IRQ_TC_DIS,0)
+#endif
+
+#ifndef UNIX
+#define STI_FBI() outp(ADDR(IRQ_OTH_EN),0)
+#else
+#define STI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_EN),0)
+#endif
+
+/*
+ * Terminal count primitives
+ */
+#define CLI_TCI(smc) outp(ADDRS((smc),IRQ_TC_DIS),0)
+#define STI_TCI(smc) outp(ADDRS((smc),IRQ_TC_EN),0)
+#define CHECK_TC(smc,k) {(k) = 10000 ;\
+ while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\
+ if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; }
+
+#endif /* MCA */
+
+#ifdef ISA
+
+/*
+ * address transmision from logic NPADDR6-0 to physical offset address on board
+ */
+#define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */
+#define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/
+#define P1A(a) (0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC1 (r/w) */
+#define P2A(a) (0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC2 (r/w) */
+#define TIA(a) (0x6000|(((a)&0x03)<<1)) /* Timer (r/w) */
+
+#define ISRA 0x0000 /* int. source register address (read only) */
+#define ACLA 0x0000 /* address counter low address (write only) */
+#define ACHA 0x0002 /* address counter high address (write only) */
+#define TRCA 0x0004 /* transfer counter address (write only) */
+#define PGRA 0x0006 /* page register address (write only) */
+#define RQAA 0x2000 /* Request reg. (write only) */
+#define CSRA 0x3000 /* control/status register address (r/w) */
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */
+#define PR_A(a) (PRA(a)+smc->hw.iop) /* PROM (read only)*/
+#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */
+#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */
+#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */
+
+#define ISR_A (0x0000+smc->hw.iop) /* int. source register address (read only) */
+#define ACL_A (0x0000+smc->hw.iop) /* address counter low address (write only) */
+#define ACH_A (0x0002+smc->hw.iop) /* address counter high address (write only)*/
+#define TRC_A (0x0004+smc->hw.iop) /* transfer counter address (write only) */
+#define PGR_A (0x0006+smc->hw.iop) /* page register address (write only) */
+#define RQA_A (0x2000+smc->hw.iop) /* Request reg. (write only) */
+#define CSR_A (0x3000+smc->hw.iop) /* control/status register address (r/w) */
+#ifdef UNIX
+#define CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */
+#endif
+#define PLC1_I (0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */
+#define PLC2_I (0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */
+
+#ifndef MULT_OEM
+#ifndef OEM_CONCEPT
+#define SKLOGO_STR "SKFDDI"
+#else /* OEM_CONCEPT */
+#define SKLOGO_STR OEM_FDDI_LOGO
+#endif /* OEM_CONCEPT */
+#endif /* MULT_OEM */
+#define SADDRL (24) /* start address SKLOGO */
+#define SA_MAC (0) /* start addr. MAC_AD within the PROM */
+#define PRA_OFF (0)
+#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
+
+#define CDID (PRA(SADDRL)) /* Card ID int/O port addr. offset */
+#define NEXT_CDID ((PRA(SADDRL+1)) - CDID)
+
+#define SKFDDI_PSZ 32 /* address PROM size */
+
+#define READ_PROM(a) ((u_char)inpw(a))
+#define GET_PAGE(i) outpw(PGR_A,(int)(i))
+
+#define MAX_PAGES 16 /* 16 pages */
+#define MAX_FADDR 0x2000 /* 8K per page */
+#define VPP_OFF() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)))
+#define VPP_ON() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \
+ CS_VPPSW)
+
+/*
+ * control/status register CSRA bits (log. addr: 0x3000)
+ */
+/* write */
+#define CS_CRESET 0x01 /* Card reset (0=reset) */
+#define CS_IMSK 0x02 /* enable IRQ (1=enable, 0=disable) */
+#define CS_RESINT1 0x04 /* PLINT1 reset */
+#define CS_VPPSW 0x10 /* 12V power switch (0=off, 1=on) */
+#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/
+#define CS_RESINT2 0x40 /* PLINT2 reset */
+/* read */
+#define CS_BUSY 0x04 /* master transfer activ (=1) */
+#define CS_SW_EPROM 0x08 /* 0=Application Soft. 1=BOOT-EPROM */
+#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */
+#define CS_SAS 0x80 /* single attachement station (=1) */
+
+/*
+ * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ.
+ */
+#define IS_MINTR1 0x01 /* FORMAC ST1U/L && ~IMSK1U/L*/
+#define IS_MINTR2 0x02 /* FORMAC ST2U/L && ~IMSK2U/L*/
+#define IS_PLINT1 0x04 /* PLC1 */
+#define IS_PLINT2 0x08 /* PLC2 */
+#define IS_TIMINT 0x10 /* Timer 82C54-2 */
+
+#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT)
+
+#define FPROM_SW() (inpw(CSR_A)&CS_SW_EPROM)
+#define DMA_BUSY() (inpw(CSR_A)&CS_BUSY)
+#define CHECK_FIFO()
+#define BUS_CHECK()
+
+/*
+ * set Host Request register (wr.)
+ */
+#define SET_HRQ(qup) outpw(RQA_A+((qup)<<1),0)
+
+#ifndef UNIX
+#ifndef WINNT
+#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#else
+#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A) & \
+ (CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#endif
+#else
+#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \
+ (CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#endif
+
+#ifndef UNIX
+#define STI_FBI() outpw(CSR_A,(inpw(CSR_A) & \
+ (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
+#else
+#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \
+ (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
+#endif
+
+#define CHECK_DMA() {unsigned k = 10000 ;\
+ while (k && (DMA_BUSY())) k-- ;\
+ if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+
+#define GET_ISR() ~inpw(ISR_A)
+
+#endif /* ISA */
+
+/*--------------------------------------------------------------------------*/
+#ifdef PCI
+
+/*
+ * (DV) = only defined for Da Vinci
+ * (ML) = only defined for Monalisa
+ */
+
+/*
+ * Configuration Space header
+ */
+#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */
+#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */
+#define PCI_COMMAND 0x04 /* 16 bit Command */
+#define PCI_STATUS 0x06 /* 16 bit Status */
+#define PCI_REV_ID 0x08 /* 8 bit Revision ID */
+#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */
+#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */
+#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */
+#define PCI_HEADER_T 0x0e /* 8 bit Header Type */
+#define PCI_BIST 0x0f /* 8 bit Built-in selftest */
+#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */
+#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */
+/* Byte 18..2b: Reserved */
+#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */
+#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */
+#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */
+/* Byte 34..33: Reserved */
+#define PCI_CAP_PTR 0x34 /* 8 bit (ML) Capabilities Ptr */
+/* Byte 35..3b: Reserved */
+#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */
+#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */
+#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */
+#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */
+/* Device Dependent Region */
+#define PCI_OUR_REG 0x40 /* 32 bit (DV) Our Register */
+#define PCI_OUR_REG_1 0x40 /* 32 bit (ML) Our Register 1 */
+#define PCI_OUR_REG_2 0x44 /* 32 bit (ML) Our Register 2 */
+/* Power Management Region */
+#define PCI_PM_CAP_ID 0x48 /* 8 bit (ML) Power Management Cap. ID */
+#define PCI_PM_NITEM 0x49 /* 8 bit (ML) Next Item Ptr */
+#define PCI_PM_CAP_REG 0x4a /* 16 bit (ML) Power Management Capabilities */
+#define PCI_PM_CTL_STS 0x4c /* 16 bit (ML) Power Manag. Control/Status */
+/* Byte 0x4e: Reserved */
+#define PCI_PM_DAT_REG 0x4f /* 8 bit (ML) Power Manag. Data Register */
+/* VPD Region */
+#define PCI_VPD_CAP_ID 0x50 /* 8 bit (ML) VPD Cap. ID */
+#define PCI_VPD_NITEM 0x51 /* 8 bit (ML) Next Item Ptr */
+#define PCI_VPD_ADR_REG 0x52 /* 16 bit (ML) VPD Address Register */
+#define PCI_VPD_DAT_REG 0x54 /* 32 bit (ML) VPD Data Register */
+/* Byte 58..ff: Reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ * I2C bus.
+ */
+#define I2C_ADDR_VPD 0xA0 /* I2C address for the VPD EEPROM */
+
+/*
+ * Define Bits and Values of the registers
+ */
+/* PCI_VENDOR_ID 16 bit Vendor ID */
+/* PCI_DEVICE_ID 16 bit Device ID */
+/* Values for Vendor ID and Device ID shall be patched into the code */
+/* PCI_COMMAND 16 bit Command */
+#define PCI_FBTEN 0x0200 /* Bit 9: Fast Back-To-Back enable */
+#define PCI_SERREN 0x0100 /* Bit 8: SERR enable */
+#define PCI_ADSTEP 0x0080 /* Bit 7: Address Stepping */
+#define PCI_PERREN 0x0040 /* Bit 6: Parity Report Response enable */
+#define PCI_VGA_SNOOP 0x0020 /* Bit 5: VGA palette snoop */
+#define PCI_MWIEN 0x0010 /* Bit 4: Memory write an inv cycl ena */
+#define PCI_SCYCEN 0x0008 /* Bit 3: Special Cycle enable */
+#define PCI_BMEN 0x0004 /* Bit 2: Bus Master enable */
+#define PCI_MEMEN 0x0002 /* Bit 1: Memory Space Access enable */
+#define PCI_IOEN 0x0001 /* Bit 0: IO Space Access enable */
+
+/* PCI_STATUS 16 bit Status */
+#define PCI_PERR 0x8000 /* Bit 15: Parity Error */
+#define PCI_SERR 0x4000 /* Bit 14: Signaled SERR */
+#define PCI_RMABORT 0x2000 /* Bit 13: Received Master Abort */
+#define PCI_RTABORT 0x1000 /* Bit 12: Received Target Abort */
+#define PCI_STABORT 0x0800 /* Bit 11: Sent Target Abort */
+#define PCI_DEVSEL 0x0600 /* Bit 10..9: DEVSEL Timing */
+#define PCI_DEV_FAST (0<<9) /* fast */
+#define PCI_DEV_MEDIUM (1<<9) /* medium */
+#define PCI_DEV_SLOW (2<<9) /* slow */
+#define PCI_DATAPERR 0x0100 /* Bit 8: DATA Parity error detected */
+#define PCI_FB2BCAP 0x0080 /* Bit 7: Fast Back-to-Back Capability */
+#define PCI_UDF 0x0040 /* Bit 6: User Defined Features */
+#define PCI_66MHZCAP 0x0020 /* Bit 5: 66 MHz PCI bus clock capable */
+#define PCI_NEWCAP 0x0010 /* Bit 4: New cap. list implemented */
+
+#define PCI_ERRBITS (PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR)
+
+/* PCI_REV_ID 8 bit Revision ID */
+/* PCI_CLASS_CODE 24 bit Class Code */
+/* Byte 2: Base Class (02) */
+/* Byte 1: SubClass (02) */
+/* Byte 0: Programming Interface (00) */
+
+/* PCI_CACHE_LSZ 8 bit Cache Line Size */
+/* Possible values: 0,2,4,8,16 */
+
+/* PCI_LAT_TIM 8 bit Latency Timer */
+
+/* PCI_HEADER_T 8 bit Header Type */
+#define PCI_HD_MF_DEV 0x80 /* Bit 7: 0= single, 1= multi-func dev */
+#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */
+
+/* PCI_BIST 8 bit Built-in selftest */
+#define PCI_BIST_CAP 0x80 /* Bit 7: BIST Capable */
+#define PCI_BIST_ST 0x40 /* Bit 6: Start BIST */
+#define PCI_BIST_RET 0x0f /* Bit 3..0: Completion Code */
+
+/* PCI_BASE_1ST 32 bit 1st Base address */
+#define PCI_MEMSIZE 0x800L /* use 2 kB Memory Base */
+#define PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11: Memory Base Address */
+#define PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4: Memory Size Req. */
+#define PCI_PREFEN 0x00000008L /* Bit 3: Prefetchable */
+#define PCI_MEM_TYP 0x00000006L /* Bit 2..1: Memory Type */
+#define PCI_MEM32BIT (0<<1) /* Base addr anywhere in 32 Bit range */
+#define PCI_MEM1M (1<<1) /* Base addr below 1 MegaByte */
+#define PCI_MEM64BIT (2<<1) /* Base addr anywhere in 64 Bit range */
+#define PCI_MEMSPACE 0x00000001L /* Bit 0: Memory Space Indic. */
+
+/* PCI_BASE_2ND 32 bit 2nd Base address */
+#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */
+#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */
+#define PCI_IOSPACE 0x00000001L /* Bit 0: I/O Space Indicator */
+
+/* PCI_SUB_VID 16 bit Subsystem Vendor ID */
+/* PCI_SUB_ID 16 bit Subsystem ID */
+
+/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */
+#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE addres (1st) */
+#define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */
+#define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */
+#define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */
+
+/* PCI_CAP_PTR 8 bit New Capabilities Pointers */
+/* PCI_IRQ_LINE 8 bit Interrupt Line */
+/* PCI_IRQ_PIN 8 bit Interrupt Pin */
+/* PCI_MIN_GNT 8 bit Min_Gnt */
+/* PCI_MAX_LAT 8 bit Max_Lat */
+/* Device Dependent Region */
+/* PCI_OUR_REG (DV) 32 bit Our Register */
+/* PCI_OUR_REG_1 (ML) 32 bit Our Register 1 */
+ /* Bit 31..29: reserved */
+#define PCI_PATCH_DIR (3L<<27) /*(DV) Bit 28..27: Ext Patchs direction */
+#define PCI_PATCH_DIR_0 (1L<<27) /*(DV) Type of the pins EXT_PATCHS<1..0> */
+#define PCI_PATCH_DIR_1 (1L<<28) /* 0 = input */
+ /* 1 = output */
+#define PCI_EXT_PATCHS (3L<<25) /*(DV) Bit 26..25: Extended Patches */
+#define PCI_EXT_PATCH_0 (1L<<25) /*(DV) */
+#define PCI_EXT_PATCH_1 (1L<<26) /* CLK for MicroWire (ML) */
+#define PCI_VIO (1L<<25) /*(ML) */
+#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */
+ /* 1 = Don't boot with ROM */
+ /* 0 = Boot with ROM */
+#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */
+#define PCI_EN_FPROM (1L<<22) /* Bit 22: FLASH mapped to mem? */
+ /* 1 = Map Flash to Memory */
+ /* 0 = Disable all addr. decoding */
+#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */
+#define PCI_PAGE_16 (0L<<20) /* 16 k pages */
+#define PCI_PAGE_32K (1L<<20) /* 32 k pages */
+#define PCI_PAGE_64K (2L<<20) /* 64 k pages */
+#define PCI_PAGE_128K (3L<<20) /* 128 k pages */
+ /* Bit 19: reserved (ML) and (DV) */
+#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */
+ /* Bit 15: reserved */
+#define PCI_FORCE_BE (1L<<14) /* Bit 14: Assert all BEs on MR */
+#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */
+#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */
+#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */
+#define PCI_DISC_CLS (1L<<10) /* Bit 10: Disc: cacheLsz bound */
+#define PCI_BURST_DIS (1L<<9) /* Bit 9: Burst Disable */
+#define PCI_BYTE_SWAP (1L<<8) /*(DV) Bit 8: Byte Swap in DATA */
+#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7..4: Skew Ctrl, DAS Ext */
+#define PCI_SKEW_BASE (0xfL<<0) /* Bit 3..0: Skew Ctrl, Base */
+
+/* PCI_OUR_REG_2 (ML) 32 bit Our Register 2 (Monalisa only) */
+#define PCI_VPD_WR_TH (0xffL<<24) /* Bit 24..31 VPD Write Threshold */
+#define PCI_DEV_SEL (0x7fL<<17) /* Bit 17..23 EEPROM Device Select */
+#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 14..16 VPD ROM Size */
+ /* Bit 12..13 reserved */
+#define PCI_PATCH_DIR2 (0xfL<<8) /* Bit 8..11 Ext Patchs dir 2..5 */
+#define PCI_PATCH_DIR_2 (1L<<8) /* Bit 8 CS for MicroWire */
+#define PCI_PATCH_DIR_3 (1L<<9)
+#define PCI_PATCH_DIR_4 (1L<<10)
+#define PCI_PATCH_DIR_5 (1L<<11)
+#define PCI_EXT_PATCHS2 (0xfL<<4) /* Bit 4..7 Extended Patches */
+#define PCI_EXT_PATCH_2 (1L<<4) /* Bit 4 CS for MicroWire */
+#define PCI_EXT_PATCH_3 (1L<<5)
+#define PCI_EXT_PATCH_4 (1L<<6)
+#define PCI_EXT_PATCH_5 (1L<<7)
+#define PCI_EN_DUMMY_RD (1L<<3) /* Bit 3 Enable Dummy Read */
+#define PCI_REV_DESC (1L<<2) /* Bit 2 Reverse Desc. Bytes */
+#define PCI_USEADDR64 (1L<<1) /* Bit 1 Use 64 Bit Addresse */
+#define PCI_USEDATA64 (1L<<0) /* Bit 0 Use 64 Bit Data bus ext*/
+
+/* Power Management Region */
+/* PCI_PM_CAP_ID 8 bit (ML) Power Management Cap. ID */
+/* PCI_PM_NITEM 8 bit (ML) Next Item Ptr */
+/* PCI_PM_CAP_REG 16 bit (ML) Power Management Capabilities*/
+#define PCI_PME_SUP (0x1f<<11) /* Bit 11..15 PM Manag. Event Support*/
+#define PCI_PM_D2_SUB (1<<10) /* Bit 10 D2 Support Bit */
+#define PCI_PM_D1_SUB (1<<9) /* Bit 9 D1 Support Bit */
+ /* Bit 6..8 reserved */
+#define PCI_PM_DSI (1<<5) /* Bit 5 Device Specific Init.*/
+#define PCI_PM_APS (1<<4) /* Bit 4 Auxialiary Power Src */
+#define PCI_PME_CLOCK (1<<3) /* Bit 3 PM Event Clock */
+#define PCI_PM_VER (7<<0) /* Bit 0..2 PM PCI Spec. version */
+
+/* PCI_PM_CTL_STS 16 bit (ML) Power Manag. Control/Status */
+#define PCI_PME_STATUS (1<<15) /* Bit 15 PFA doesn't sup. PME#*/
+#define PCI_PM_DAT_SCL (3<<13) /* Bit 13..14 dat reg Scaling factor */
+#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 9..12 PM data selector field */
+ /* Bit 7.. 2 reserved */
+#define PCI_PM_STATE (3<<0) /* Bit 0.. 1 Power Management State */
+#define PCI_PM_STATE_D0 (0<<0) /* D0: Operational (default) */
+#define PCI_PM_STATE_D1 (1<<0) /* D1: not supported */
+#define PCI_PM_STATE_D2 (2<<0) /* D2: not supported */
+#define PCI_PM_STATE_D3 (3<<0) /* D3: HOT, Power Down and Reset */
+
+/* PCI_PM_DAT_REG 8 bit (ML) Power Manag. Data Register */
+/* VPD Region */
+/* PCI_VPD_CAP_ID 8 bit (ML) VPD Cap. ID */
+/* PCI_VPD_NITEM 8 bit (ML) Next Item Ptr */
+/* PCI_VPD_ADR_REG 16 bit (ML) VPD Address Register */
+#define PCI_VPD_FLAG (1<<15) /* Bit 15 starts VPD rd/wd cycle*/
+#define PCI_VPD_ADDR (0x3fff<<0) /* Bit 0..14 VPD address */
+
+/* PCI_VPD_DAT_REG 32 bit (ML) VPD Data Register */
+
+/*
+ * Control Register File:
+ * Bank 0
+ */
+#define B0_RAP 0x0000 /* 8 bit register address port */
+ /* 0x0001 - 0x0003: reserved */
+#define B0_CTRL 0x0004 /* 8 bit control register */
+#define B0_DAS 0x0005 /* 8 Bit control register (DAS) */
+#define B0_LED 0x0006 /* 8 Bit LED register */
+#define B0_TST_CTRL 0x0007 /* 8 bit test control register */
+#define B0_ISRC 0x0008 /* 32 bit Interrupt source register */
+#define B0_IMSK 0x000c /* 32 bit Interrupt mask register */
+
+/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */
+#define B0_CMDREG1 0x0010 /* write command reg 1 instruction */
+#define B0_CMDREG2 0x0014 /* write command reg 2 instruction */
+#define B0_ST1U 0x0010 /* read upper 16-bit of status reg 1 */
+#define B0_ST1L 0x0014 /* read lower 16-bit of status reg 1 */
+#define B0_ST2U 0x0018 /* read upper 16-bit of status reg 2 */
+#define B0_ST2L 0x001c /* read lower 16-bit of status reg 2 */
+
+#define B0_MARR 0x0020 /* r/w the memory read addr register */
+#define B0_MARW 0x0024 /* r/w the memory write addr register*/
+#define B0_MDRU 0x0028 /* r/w upper 16-bit of mem. data reg */
+#define B0_MDRL 0x002c /* r/w lower 16-bit of mem. data reg */
+
+#define B0_MDREG3 0x0030 /* r/w Mode Register 3 */
+#define B0_ST3U 0x0034 /* read upper 16-bit of status reg 3 */
+#define B0_ST3L 0x0038 /* read lower 16-bit of status reg 3 */
+#define B0_IMSK3U 0x003c /* r/w upper 16-bit of IMSK reg 3 */
+#define B0_IMSK3L 0x0040 /* r/w lower 16-bit of IMSK reg 3 */
+#define B0_IVR 0x0044 /* read Interrupt Vector register */
+#define B0_IMR 0x0048 /* r/w Interrupt mask register */
+/* 0x4c Hidden */
+
+#define B0_CNTRL_A 0x0050 /* control register A (r/w) */
+#define B0_CNTRL_B 0x0054 /* control register B (r/w) */
+#define B0_INTR_MASK 0x0058 /* interrupt mask (r/w) */
+#define B0_XMIT_VECTOR 0x005c /* transmit vector register (r/w) */
+
+#define B0_STATUS_A 0x0060 /* status register A (read only) */
+#define B0_STATUS_B 0x0064 /* status register B (read only) */
+#define B0_CNTRL_C 0x0068 /* control register C (r/w) */
+#define B0_MDREG1 0x006c /* r/w Mode Register 1 */
+
+#define B0_R1_CSR 0x0070 /* 32 bit BMU control/status reg (rec q 1) */
+#define B0_R2_CSR 0x0074 /* 32 bit BMU control/status reg (rec q 2)(DV)*/
+#define B0_XA_CSR 0x0078 /* 32 bit BMU control/status reg (a xmit q) */
+#define B0_XS_CSR 0x007c /* 32 bit BMU control/status reg (s xmit q) */
+
+/*
+ * Bank 1
+ * - completely empty (this is the RAP Block window)
+ * Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ * Bank 2
+ */
+#define B2_MAC_0 0x0100 /* 8 bit MAC address Byte 0 */
+#define B2_MAC_1 0x0101 /* 8 bit MAC address Byte 1 */
+#define B2_MAC_2 0x0102 /* 8 bit MAC address Byte 2 */
+#define B2_MAC_3 0x0103 /* 8 bit MAC address Byte 3 */
+#define B2_MAC_4 0x0104 /* 8 bit MAC address Byte 4 */
+#define B2_MAC_5 0x0105 /* 8 bit MAC address Byte 5 */
+#define B2_MAC_6 0x0106 /* 8 bit MAC address Byte 6 (== 0) (DV) */
+#define B2_MAC_7 0x0107 /* 8 bit MAC address Byte 7 (== 0) (DV) */
+
+#define B2_CONN_TYP 0x0108 /* 8 bit Connector type */
+#define B2_PMD_TYP 0x0109 /* 8 bit PMD type */
+ /* 0x010a - 0x010b: reserved */
+ /* Eprom registers are currently of no use */
+#define B2_E_0 0x010c /* 8 bit EPROM Byte 0 */
+#define B2_E_1 0x010d /* 8 bit EPROM Byte 1 */
+#define B2_E_2 0x010e /* 8 bit EPROM Byte 2 */
+#define B2_E_3 0x010f /* 8 bit EPROM Byte 3 */
+#define B2_FAR 0x0110 /* 32 bit Flash-Prom Address Register/Counter */
+#define B2_FDP 0x0114 /* 8 bit Flash-Prom Data Port */
+ /* 0x0115 - 0x0117: reserved */
+#define B2_LD_CRTL 0x0118 /* 8 bit loader control */
+#define B2_LD_TEST 0x0119 /* 8 bit loader test */
+ /* 0x011a - 0x011f: reserved */
+#define B2_TI_INI 0x0120 /* 32 bit Timer init value */
+#define B2_TI_VAL 0x0124 /* 32 bit Timer value */
+#define B2_TI_CRTL 0x0128 /* 8 bit Timer control */
+#define B2_TI_TEST 0x0129 /* 8 Bit Timer Test */
+ /* 0x012a - 0x012f: reserved */
+#define B2_WDOG_INI 0x0130 /* 32 bit Watchdog init value */
+#define B2_WDOG_VAL 0x0134 /* 32 bit Watchdog value */
+#define B2_WDOG_CRTL 0x0138 /* 8 bit Watchdog control */
+#define B2_WDOG_TEST 0x0139 /* 8 Bit Watchdog Test */
+ /* 0x013a - 0x013f: reserved */
+#define B2_RTM_INI 0x0140 /* 32 bit RTM init value */
+#define B2_RTM_VAL 0x0144 /* 32 bit RTM value */
+#define B2_RTM_CRTL 0x0148 /* 8 bit RTM control */
+#define B2_RTM_TEST 0x0149 /* 8 Bit RTM Test */
+
+#define B2_TOK_COUNT 0x014c /* (ML) 32 bit Token Counter */
+#define B2_DESC_ADDR_H 0x0150 /* (ML) 32 bit Desciptor Base Addr Reg High */
+#define B2_CTRL_2 0x0154 /* (ML) 8 bit Control Register 2 */
+#define B2_IFACE_REG 0x0155 /* (ML) 8 bit Interface Register */
+ /* 0x0156: reserved */
+#define B2_TST_CTRL_2 0x0157 /* (ML) 8 bit Test Control Register 2 */
+#define B2_I2C_CTRL 0x0158 /* (ML) 32 bit I2C Control Register */
+#define B2_I2C_DATA 0x015c /* (ML) 32 bit I2C Data Register */
+
+#define B2_IRQ_MOD_INI 0x0160 /* (ML) 32 bit IRQ Moderation Timer Init Reg. */
+#define B2_IRQ_MOD_VAL 0x0164 /* (ML) 32 bit IRQ Moderation Timer Value */
+#define B2_IRQ_MOD_CTRL 0x0168 /* (ML) 8 bit IRQ Moderation Timer Control */
+#define B2_IRQ_MOD_TEST 0x0169 /* (ML) 8 bit IRQ Moderation Timer Test */
+ /* 0x016a - 0x017f: reserved */
+
+/*
+ * Bank 3
+ */
+/*
+ * This is a copy of the Configuration register file (lower half)
+ */
+#define B3_CFG_SPC 0x180
+
+/*
+ * Bank 4
+ */
+#define B4_R1_D 0x0200 /* 4*32 bit current receive Descriptor */
+#define B4_R1_DA 0x0210 /* 32 bit current rec desc address */
+#define B4_R1_AC 0x0214 /* 32 bit current receive Address Count */
+#define B4_R1_BC 0x0218 /* 32 bit current receive Byte Counter */
+#define B4_R1_CSR 0x021c /* 32 bit BMU Control/Status Register */
+#define B4_R1_F 0x0220 /* 32 bit flag register */
+#define B4_R1_T1 0x0224 /* 32 bit Test Register 1 */
+#define B4_R1_T1_TR 0x0224 /* 8 bit Test Register 1 TR */
+#define B4_R1_T1_WR 0x0225 /* 8 bit Test Register 1 WR */
+#define B4_R1_T1_RD 0x0226 /* 8 bit Test Register 1 RD */
+#define B4_R1_T1_SV 0x0227 /* 8 bit Test Register 1 SV */
+#define B4_R1_T2 0x0228 /* 32 bit Test Register 2 */
+#define B4_R1_T3 0x022c /* 32 bit Test Register 3 */
+#define B4_R1_DA_H 0x0230 /* (ML) 32 bit Curr Rx Desc Address High */
+#define B4_R1_AC_H 0x0234 /* (ML) 32 bit Curr Addr Counter High dword */
+ /* 0x0238 - 0x023f: reserved */
+ /* Receive queue 2 is removed on Monalisa */
+#define B4_R2_D 0x0240 /* 4*32 bit current receive Descriptor (q2) */
+#define B4_R2_DA 0x0250 /* 32 bit current rec desc address (q2) */
+#define B4_R2_AC 0x0254 /* 32 bit current receive Address Count (q2) */
+#define B4_R2_BC 0x0258 /* 32 bit current receive Byte Counter (q2) */
+#define B4_R2_CSR 0x025c /* 32 bit BMU Control/Status Register (q2) */
+#define B4_R2_F 0x0260 /* 32 bit flag register (q2) */
+#define B4_R2_T1 0x0264 /* 32 bit Test Register 1 (q2) */
+#define B4_R2_T1_TR 0x0264 /* 8 bit Test Register 1 TR (q2) */
+#define B4_R2_T1_WR 0x0265 /* 8 bit Test Register 1 WR (q2) */
+#define B4_R2_T1_RD 0x0266 /* 8 bit Test Register 1 RD (q2) */
+#define B4_R2_T1_SV 0x0267 /* 8 bit Test Register 1 SV (q2) */
+#define B4_R2_T2 0x0268 /* 32 bit Test Register 2 (q2) */
+#define B4_R2_T3 0x026c /* 32 bit Test Register 3 (q2) */
+ /* 0x0270 - 0x027c: reserved */
+
+/*
+ * Bank 5
+ */
+#define B5_XA_D 0x0280 /* 4*32 bit current transmit Descriptor (xa) */
+#define B5_XA_DA 0x0290 /* 32 bit current tx desc address (xa) */
+#define B5_XA_AC 0x0294 /* 32 bit current tx Address Count (xa) */
+#define B5_XA_BC 0x0298 /* 32 bit current tx Byte Counter (xa) */
+#define B5_XA_CSR 0x029c /* 32 bit BMU Control/Status Register (xa) */
+#define B5_XA_F 0x02a0 /* 32 bit flag register (xa) */
+#define B5_XA_T1 0x02a4 /* 32 bit Test Register 1 (xa) */
+#define B5_XA_T1_TR 0x02a4 /* 8 bit Test Register 1 TR (xa) */
+#define B5_XA_T1_WR 0x02a5 /* 8 bit Test Register 1 WR (xa) */
+#define B5_XA_T1_RD 0x02a6 /* 8 bit Test Register 1 RD (xa) */
+#define B5_XA_T1_SV 0x02a7 /* 8 bit Test Register 1 SV (xa) */
+#define B5_XA_T2 0x02a8 /* 32 bit Test Register 2 (xa) */
+#define B5_XA_T3 0x02ac /* 32 bit Test Register 3 (xa) */
+#define B5_XA_DA_H 0x02b0 /* (ML) 32 bit Curr Tx Desc Address High */
+#define B5_XA_AC_H 0x02b4 /* (ML) 32 bit Curr Addr Counter High dword */
+ /* 0x02b8 - 0x02bc: reserved */
+#define B5_XS_D 0x02c0 /* 4*32 bit current transmit Descriptor (xs) */
+#define B5_XS_DA 0x02d0 /* 32 bit current tx desc address (xs) */
+#define B5_XS_AC 0x02d4 /* 32 bit current transmit Address Count(xs) */
+#define B5_XS_BC 0x02d8 /* 32 bit current transmit Byte Counter (xs) */
+#define B5_XS_CSR 0x02dc /* 32 bit BMU Control/Status Register (xs) */
+#define B5_XS_F 0x02e0 /* 32 bit flag register (xs) */
+#define B5_XS_T1 0x02e4 /* 32 bit Test Register 1 (xs) */
+#define B5_XS_T1_TR 0x02e4 /* 8 bit Test Register 1 TR (xs) */
+#define B5_XS_T1_WR 0x02e5 /* 8 bit Test Register 1 WR (xs) */
+#define B5_XS_T1_RD 0x02e6 /* 8 bit Test Register 1 RD (xs) */
+#define B5_XS_T1_SV 0x02e7 /* 8 bit Test Register 1 SV (xs) */
+#define B5_XS_T2 0x02e8 /* 32 bit Test Register 2 (xs) */
+#define B5_XS_T3 0x02ec /* 32 bit Test Register 3 (xs) */
+#define B5_XS_DA_H 0x02f0 /* (ML) 32 bit Curr Tx Desc Address High */
+#define B5_XS_AC_H 0x02f4 /* (ML) 32 bit Curr Addr Counter High dword */
+ /* 0x02f8 - 0x02fc: reserved */
+
+/*
+ * Bank 6
+ */
+/* External PLC-S registers (SN2 compatibility for DV) */
+/* External registers (ML) */
+#define B6_EXT_REG 0x300
+
+/*
+ * Bank 7
+ */
+/* DAS PLC-S Registers */
+
+/*
+ * Bank 8 - 15
+ */
+/* IFCP registers */
+
+/*---------------------------------------------------------------------------*/
+/* Definitions of the Bits in the registers */
+
+/* B0_RAP 16 bit register address port */
+#define RAP_RAP 0x0f /* Bit 3..0: 0 = block0, .., f = block15 */
+
+/* B0_CTRL 8 bit control register */
+#define CTRL_FDDI_CLR (1<<7) /* Bit 7: (ML) Clear FDDI Reset */
+#define CTRL_FDDI_SET (1<<6) /* Bit 6: (ML) Set FDDI Reset */
+#define CTRL_HPI_CLR (1<<5) /* Bit 5: Clear HPI SM reset */
+#define CTRL_HPI_SET (1<<4) /* Bit 4: Set HPI SM reset */
+#define CTRL_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */
+#define CTRL_MRST_SET (1<<2) /* Bit 2: Set Master reset */
+#define CTRL_RST_CLR (1<<1) /* Bit 1: Clear Software reset */
+#define CTRL_RST_SET (1<<0) /* Bit 0: Set Software reset */
+
+/* B0_DAS 8 Bit control register (DAS) */
+#define BUS_CLOCK (1<<7) /* Bit 7: (ML) Bus Clock 0/1 = 33/66MHz */
+#define BUS_SLOT_SZ (1<<6) /* Bit 6: (ML) Slot Size 0/1 = 32/64 bit slot*/
+ /* Bit 5..4: reserved */
+#define DAS_AVAIL (1<<3) /* Bit 3: 1 = DAS, 0 = SAS */
+#define DAS_BYP_ST (1<<2) /* Bit 2: 1 = avail,SAS, 0 = not avail */
+#define DAS_BYP_INS (1<<1) /* Bit 1: 1 = insert Bypass */
+#define DAS_BYP_RMV (1<<0) /* Bit 0: 1 = remove Bypass */
+
+/* B0_LED 8 Bit LED register */
+ /* Bit 7..6: reserved */
+#define LED_2_ON (1<<5) /* Bit 5: 1 = switch LED_2 on (left,gn)*/
+#define LED_2_OFF (1<<4) /* Bit 4: 1 = switch LED_2 off */
+#define LED_1_ON (1<<3) /* Bit 3: 1 = switch LED_1 on (mid,yel)*/
+#define LED_1_OFF (1<<2) /* Bit 2: 1 = switch LED_1 off */
+#define LED_0_ON (1<<1) /* Bit 1: 1 = switch LED_0 on (rght,gn)*/
+#define LED_0_OFF (1<<0) /* Bit 0: 1 = switch LED_0 off */
+/* This hardware defines are very ugly therefore we define some others */
+
+#define LED_GA_ON LED_2_ON /* S port = A port */
+#define LED_GA_OFF LED_2_OFF /* S port = A port */
+#define LED_MY_ON LED_1_ON
+#define LED_MY_OFF LED_1_OFF
+#define LED_GB_ON LED_0_ON
+#define LED_GB_OFF LED_0_OFF
+
+/* B0_TST_CTRL 8 bit test control register */
+#define TST_FRC_DPERR_MR (1<<7) /* Bit 7: force DATAPERR on MST RE. */
+#define TST_FRC_DPERR_MW (1<<6) /* Bit 6: force DATAPERR on MST WR. */
+#define TST_FRC_DPERR_TR (1<<5) /* Bit 5: force DATAPERR on TRG RE. */
+#define TST_FRC_DPERR_TW (1<<4) /* Bit 4: force DATAPERR on TRG WR. */
+#define TST_FRC_APERR_M (1<<3) /* Bit 3: force ADDRPERR on MST */
+#define TST_FRC_APERR_T (1<<2) /* Bit 2: force ADDRPERR on TRG */
+#define TST_CFG_WRITE_ON (1<<1) /* Bit 1: ena configuration reg. WR */
+#define TST_CFG_WRITE_OFF (1<<0) /* Bit 0: dis configuration reg. WR */
+
+/* B0_ISRC 32 bit Interrupt source register */
+ /* Bit 31..28: reserved */
+#define IS_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */
+#define IS_IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */
+#define IS_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/
+#define IS_IRQ_STAT (1L<<24) /* Bit 24: IRQ status execption */
+ /* PERR, RMABORT, RTABORT DATAPERR */
+#define IS_IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */
+ /* RMABORT, RTABORT, DATAPERR */
+#define IS_TIMINT (1L<<22) /* Bit 22: IRQ_TIMER */
+#define IS_TOKEN (1L<<21) /* Bit 21: IRQ_RTM */
+/*
+ * Note: The DAS is our First Port (!=PA)
+ */
+#define IS_PLINT1 (1L<<20) /* Bit 20: IRQ_PHY_DAS */
+#define IS_PLINT2 (1L<<19) /* Bit 19: IRQ_IFCP_4 */
+#define IS_MINTR3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */
+#define IS_MINTR2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */
+#define IS_MINTR1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */
+/* Receive Queue 1 */
+#define IS_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */
+#define IS_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */
+#define IS_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */
+#define IS_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */
+/* Receive Queue 2 */
+#define IS_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */
+#define IS_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */
+#define IS_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */
+#define IS_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */
+/* Asynchronous Transmit queue */
+ /* Bit 7: reserved */
+#define IS_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */
+#define IS_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */
+#define IS_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */
+/* Synchronous Transmit queue */
+ /* Bit 3: reserved */
+#define IS_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */
+#define IS_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */
+#define IS_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */
+
+/*
+ * Define all valid interrupt source Bits from GET_ISR ()
+ */
+#define ALL_IRSR 0x01ffff77L /* (DV) */
+#define ALL_IRSR_ML 0x0ffff077L /* (ML) */
+
+
+/* B0_IMSK 32 bit Interrupt mask register */
+/*
+ * The Bit definnition of this register are the same as of the interrupt
+ * source register. These definition are directly derived from the Hardware
+ * spec.
+ */
+ /* Bit 31..28: reserved */
+#define IRQ_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */
+#define IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */
+#define IRQ_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/
+#define IRQ_STAT (1L<<24) /* Bit 24: IRQ status execption */
+ /* PERR, RMABORT, RTABORT DATAPERR */
+#define IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */
+ /* RMABORT, RTABORT, DATAPERR */
+#define IRQ_TIMER (1L<<22) /* Bit 22: IRQ_TIMER */
+#define IRQ_RTM (1L<<21) /* Bit 21: IRQ_RTM */
+#define IRQ_DAS (1L<<20) /* Bit 20: IRQ_PHY_DAS */
+#define IRQ_IFCP_4 (1L<<19) /* Bit 19: IRQ_IFCP_4 */
+#define IRQ_IFCP_3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */
+#define IRQ_IFCP_2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */
+#define IRQ_IFCP_1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */
+/* Receive Queue 1 */
+#define IRQ_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */
+#define IRQ_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */
+#define IRQ_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */
+#define IRQ_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */
+/* Receive Queue 2 */
+#define IRQ_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */
+#define IRQ_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */
+#define IRQ_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */
+#define IRQ_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */
+/* Asynchronous Transmit queue */
+ /* Bit 7: reserved */
+#define IRQ_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */
+#define IRQ_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */
+#define IRQ_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */
+/* Synchronous Transmit queue */
+ /* Bit 3: reserved */
+#define IRQ_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */
+#define IRQ_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */
+#define IRQ_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */
+
+/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */
+/* B0_R1_CSR 32 bit BMU control/status reg (rec q 1 ) */
+/* B0_R2_CSR 32 bit BMU control/status reg (rec q 2 ) */
+/* B0_XA_CSR 32 bit BMU control/status reg (a xmit q ) */
+/* B0_XS_CSR 32 bit BMU control/status reg (s xmit q ) */
+/* The registers are the same as B4_R1_CSR, B4_R2_CSR, B5_Xa_CSR, B5_XS_CSR */
+
+/* B2_MAC_0 8 bit MAC address Byte 0 */
+/* B2_MAC_1 8 bit MAC address Byte 1 */
+/* B2_MAC_2 8 bit MAC address Byte 2 */
+/* B2_MAC_3 8 bit MAC address Byte 3 */
+/* B2_MAC_4 8 bit MAC address Byte 4 */
+/* B2_MAC_5 8 bit MAC address Byte 5 */
+/* B2_MAC_6 8 bit MAC address Byte 6 (== 0) (DV) */
+/* B2_MAC_7 8 bit MAC address Byte 7 (== 0) (DV) */
+
+/* B2_CONN_TYP 8 bit Connector type */
+/* B2_PMD_TYP 8 bit PMD type */
+/* Values of connector and PMD type comply to SysKonnect internal std */
+
+/* The EPROM register are currently of no use */
+/* B2_E_0 8 bit EPROM Byte 0 */
+/* B2_E_1 8 bit EPROM Byte 1 */
+/* B2_E_2 8 bit EPROM Byte 2 */
+/* B2_E_3 8 bit EPROM Byte 3 */
+
+/* B2_FAR 32 bit Flash-Prom Address Register/Counter */
+#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */
+
+/* B2_FDP 8 bit Flash-Prom Data Port */
+
+/* B2_LD_CRTL 8 bit loader control */
+/* Bits are currently reserved */
+
+/* B2_LD_TEST 8 bit loader test */
+#define LD_T_ON (1<<3) /* Bit 3: Loader Testmode on */
+#define LD_T_OFF (1<<2) /* Bit 2: Loader Testmode off */
+#define LD_T_STEP (1<<1) /* Bit 1: Decrement FPROM addr. Counter */
+#define LD_START (1<<0) /* Bit 0: Start loading FPROM */
+
+/* B2_TI_INI 32 bit Timer init value */
+/* B2_TI_VAL 32 bit Timer value */
+/* B2_TI_CRTL 8 bit Timer control */
+/* B2_TI_TEST 8 Bit Timer Test */
+/* B2_WDOG_INI 32 bit Watchdog init value */
+/* B2_WDOG_VAL 32 bit Watchdog value */
+/* B2_WDOG_CRTL 8 bit Watchdog control */
+/* B2_WDOG_TEST 8 Bit Watchdog Test */
+/* B2_RTM_INI 32 bit RTM init value */
+/* B2_RTM_VAL 32 bit RTM value */
+/* B2_RTM_CRTL 8 bit RTM control */
+/* B2_RTM_TEST 8 Bit RTM Test */
+/* B2_<TIM>_CRTL 8 bit <TIM> control */
+/* B2_IRQ_MOD_INI 32 bit IRQ Moderation Timer Init Reg. (ML) */
+/* B2_IRQ_MOD_VAL 32 bit IRQ Moderation Timer Value (ML) */
+/* B2_IRQ_MOD_CTRL 8 bit IRQ Moderation Timer Control (ML) */
+/* B2_IRQ_MOD_TEST 8 bit IRQ Moderation Timer Test (ML) */
+#define GET_TOK_CT (1<<4) /* Bit 4: Get the Token Counter (RTM) */
+#define TIM_RES_TOK (1<<3) /* Bit 3: RTM Status: 1 == restricted */
+#define TIM_ALARM (1<<3) /* Bit 3: Timer Alarm (WDOG) */
+#define TIM_START (1<<2) /* Bit 2: Start Timer (TI,WDOG,RTM,IRQ_MOD)*/
+#define TIM_STOP (1<<1) /* Bit 1: Stop Timer (TI,WDOG,RTM,IRQ_MOD) */
+#define TIM_CL_IRQ (1<<0) /* Bit 0: Clear Timer IRQ (TI,WDOG,RTM) */
+/* B2_<TIM>_TEST 8 Bit <TIM> Test */
+#define TIM_T_ON (1<<2) /* Bit 2: Test mode on (TI,WDOG,RTM,IRQ_MOD) */
+#define TIM_T_OFF (1<<1) /* Bit 1: Test mode off (TI,WDOG,RTM,IRQ_MOD) */
+#define TIM_T_STEP (1<<0) /* Bit 0: Test step (TI,WDOG,RTM,IRQ_MOD) */
+
+/* B2_TOK_COUNT 0x014c (ML) 32 bit Token Counter */
+/* B2_DESC_ADDR_H 0x0150 (ML) 32 bit Desciptor Base Addr Reg High */
+/* B2_CTRL_2 0x0154 (ML) 8 bit Control Register 2 */
+ /* Bit 7..5: reserved */
+#define CTRL_CL_I2C_IRQ (1<<4) /* Bit 4: Clear I2C IRQ */
+#define CTRL_ST_SW_IRQ (1<<3) /* Bit 3: Set IRQ SW Request */
+#define CTRL_CL_SW_IRQ (1<<2) /* Bit 2: Clear IRQ SW Request */
+#define CTRL_STOP_DONE (1<<1) /* Bit 1: Stop Master is finished */
+#define CTRL_STOP_MAST (1<<0) /* Bit 0: Command Bit to stop the master*/
+
+/* B2_IFACE_REG 0x0155 (ML) 8 bit Interface Register */
+ /* Bit 7..3: reserved */
+#define IF_I2C_DATA_DIR (1<<2) /* Bit 2: direction of IF_I2C_DATA*/
+#define IF_I2C_DATA (1<<1) /* Bit 1: I2C Data Port */
+#define IF_I2C_CLK (1<<0) /* Bit 0: I2C Clock Port */
+
+ /* 0x0156: reserved */
+/* B2_TST_CTRL_2 0x0157 (ML) 8 bit Test Control Register 2 */
+ /* Bit 7..4: reserved */
+ /* force the following error on */
+ /* the next master read/write */
+#define TST_FRC_DPERR_MR64 (1<<3) /* Bit 3: DataPERR RD 64 */
+#define TST_FRC_DPERR_MW64 (1<<2) /* Bit 2: DataPERR WR 64 */
+#define TST_FRC_APERR_1M64 (1<<1) /* Bit 1: AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64 (1<<0) /* Bit 0: AddrPERR on 2. phase */
+
+/* B2_I2C_CTRL 0x0158 (ML) 32 bit I2C Control Register */
+#define I2C_FLAG (1L<<31) /* Bit 31: Start read/write if WR */
+#define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be read/written*/
+#define I2C_DEV_SEL (0x7fL<<9) /* Bit 9..15: I2C Device Select */
+ /* Bit 5.. 8: reserved */
+#define I2C_BURST_LEN (1L<<4) /* Bit 4 Burst Len, 1/4 bytes */
+#define I2C_DEV_SIZE (7L<<1) /* Bit 1.. 3: I2C Device Size */
+#define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smaller*/
+#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */
+#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */
+#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */
+#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */
+#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */
+#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */
+#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */
+#define I2C_STOP_BIT (1<<0) /* Bit 0: Interrupt I2C transfer */
+
+/*
+ * I2C Addresses
+ *
+ * The temperature sensor and the voltage sensor are on the same I2C bus.
+ * Note: The voltage sensor (Micorwire) will be selected by PCI_EXT_PATCH_1
+ * in PCI_OUR_REG 1.
+ */
+#define I2C_ADDR_TEMP 0x90 /* I2C Address Temperature Sensor */
+
+/* B2_I2C_DATA 0x015c (ML) 32 bit I2C Data Register */
+
+/* B4_R1_D 4*32 bit current receive Descriptor (q1) */
+/* B4_R1_DA 32 bit current rec desc address (q1) */
+/* B4_R1_AC 32 bit current receive Address Count (q1) */
+/* B4_R1_BC 32 bit current receive Byte Counter (q1) */
+/* B4_R1_CSR 32 bit BMU Control/Status Register (q1) */
+/* B4_R1_F 32 bit flag register (q1) */
+/* B4_R1_T1 32 bit Test Register 1 (q1) */
+/* B4_R1_T2 32 bit Test Register 2 (q1) */
+/* B4_R1_T3 32 bit Test Register 3 (q1) */
+/* B4_R2_D 4*32 bit current receive Descriptor (q2) */
+/* B4_R2_DA 32 bit current rec desc address (q2) */
+/* B4_R2_AC 32 bit current receive Address Count (q2) */
+/* B4_R2_BC 32 bit current receive Byte Counter (q2) */
+/* B4_R2_CSR 32 bit BMU Control/Status Register (q2) */
+/* B4_R2_F 32 bit flag register (q2) */
+/* B4_R2_T1 32 bit Test Register 1 (q2) */
+/* B4_R2_T2 32 bit Test Register 2 (q2) */
+/* B4_R2_T3 32 bit Test Register 3 (q2) */
+/* B5_XA_D 4*32 bit current receive Descriptor (xa) */
+/* B5_XA_DA 32 bit current rec desc address (xa) */
+/* B5_XA_AC 32 bit current receive Address Count (xa) */
+/* B5_XA_BC 32 bit current receive Byte Counter (xa) */
+/* B5_XA_CSR 32 bit BMU Control/Status Register (xa) */
+/* B5_XA_F 32 bit flag register (xa) */
+/* B5_XA_T1 32 bit Test Register 1 (xa) */
+/* B5_XA_T2 32 bit Test Register 2 (xa) */
+/* B5_XA_T3 32 bit Test Register 3 (xa) */
+/* B5_XS_D 4*32 bit current receive Descriptor (xs) */
+/* B5_XS_DA 32 bit current rec desc address (xs) */
+/* B5_XS_AC 32 bit current receive Address Count (xs) */
+/* B5_XS_BC 32 bit current receive Byte Counter (xs) */
+/* B5_XS_CSR 32 bit BMU Control/Status Register (xs) */
+/* B5_XS_F 32 bit flag register (xs) */
+/* B5_XS_T1 32 bit Test Register 1 (xs) */
+/* B5_XS_T2 32 bit Test Register 2 (xs) */
+/* B5_XS_T3 32 bit Test Register 3 (xs) */
+/* B5_<xx>_CSR 32 bit BMU Control/Status Register (xx) */
+#define CSR_DESC_CLEAR (1L<<21) /* Bit 21: Clear Reset for Descr */
+#define CSR_DESC_SET (1L<<20) /* Bit 20: Set Reset for Descr */
+#define CSR_FIFO_CLEAR (1L<<19) /* Bit 19: Clear Reset for FIFO */
+#define CSR_FIFO_SET (1L<<18) /* Bit 18: Set Reset for FIFO */
+#define CSR_HPI_RUN (1L<<17) /* Bit 17: Release HPI SM */
+#define CSR_HPI_RST (1L<<16) /* Bit 16: Reset HPI SM to Idle */
+#define CSR_SV_RUN (1L<<15) /* Bit 15: Release Supervisor SM */
+#define CSR_SV_RST (1L<<14) /* Bit 14: Reset Supervisor SM */
+#define CSR_DREAD_RUN (1L<<13) /* Bit 13: Release Descr Read SM */
+#define CSR_DREAD_RST (1L<<12) /* Bit 12: Reset Descr Read SM */
+#define CSR_DWRITE_RUN (1L<<11) /* Bit 11: Rel. Descr Write SM */
+#define CSR_DWRITE_RST (1L<<10) /* Bit 10: Reset Descr Write SM */
+#define CSR_TRANS_RUN (1L<<9) /* Bit 9: Release Transfer SM */
+#define CSR_TRANS_RST (1L<<8) /* Bit 8: Reset Transfer SM */
+ /* Bit 7..5: reserved */
+#define CSR_START (1L<<4) /* Bit 4: Start Rec/Xmit Queue */
+#define CSR_IRQ_CL_P (1L<<3) /* Bit 3: Clear Parity IRQ, Rcv */
+#define CSR_IRQ_CL_B (1L<<2) /* Bit 2: Clear EOB IRQ */
+#define CSR_IRQ_CL_F (1L<<1) /* Bit 1: Clear EOF IRQ */
+#define CSR_IRQ_CL_C (1L<<0) /* Bit 0: Clear ERR IRQ */
+
+#define CSR_SET_RESET (CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\
+ CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST)
+#define CSR_CLR_RESET (CSR_DESC_CLEAR|CSR_FIFO_CLEAR|CSR_HPI_RUN|CSR_SV_RUN|\
+ CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN)
+
+
+/* B5_<xx>_F 32 bit flag register (xx) */
+ /* Bit 28..31: reserved */
+#define F_ALM_FULL (1L<<27) /* Bit 27: (ML) FIFO almost full */
+#define F_FIFO_EOF (1L<<26) /* Bit 26: (ML) Fag bit in FIFO */
+#define F_WM_REACHED (1L<<25) /* Bit 25: (ML) Watermark reached */
+#define F_UP_DW_USED (1L<<24) /* Bit 24: (ML) Upper Dword used (bug)*/
+ /* Bit 23: reserved */
+#define F_FIFO_LEVEL (0x1fL<<16) /* Bit 16..22:(ML) # of Qwords in FIFO*/
+ /* Bit 8..15: reserved */
+#define F_ML_WATER_M 0x0000ffL /* Bit 0.. 7:(ML) Watermark */
+#define FLAG_WATER 0x00001fL /* Bit 4..0:(DV) Level of req data tr.*/
+
+/* B5_<xx>_T1 32 bit Test Register 1 (xx) */
+/* Holds four State Machine control Bytes */
+#define SM_CRTL_SV (0xffL<<24) /* Bit 31..24: Control Supervisor SM */
+#define SM_CRTL_RD (0xffL<<16) /* Bit 23..16: Control Read Desc SM */
+#define SM_CRTL_WR (0xffL<<8) /* Bit 15..8: Control Write Desc SM */
+#define SM_CRTL_TR (0xffL<<0) /* Bit 7..0: Control Transfer SM */
+
+/* B4_<xx>_T1_TR 8 bit Test Register 1 TR (xx) */
+/* B4_<xx>_T1_WR 8 bit Test Register 1 WR (xx) */
+/* B4_<xx>_T1_RD 8 bit Test Register 1 RD (xx) */
+/* B4_<xx>_T1_SV 8 bit Test Register 1 SV (xx) */
+/* The control status byte of each machine looks like ... */
+#define SM_STATE 0xf0 /* Bit 7..4: State which shall be loaded */
+#define SM_LOAD 0x08 /* Bit 3: Load the SM with SM_STATE */
+#define SM_TEST_ON 0x04 /* Bit 2: Switch on SM Test Mode */
+#define SM_TEST_OFF 0x02 /* Bit 1: Go off the Test Mode */
+#define SM_STEP 0x01 /* Bit 0: Step the State Machine */
+
+/* The coding of the states */
+#define SM_SV_IDLE 0x0 /* Supervisor Idle Tr/Re */
+#define SM_SV_RES_START 0x1 /* Supervisor Res_Start Tr/Re */
+#define SM_SV_GET_DESC 0x3 /* Supervisor Get_Desc Tr/Re */
+#define SM_SV_CHECK 0x2 /* Supervisor Check Tr/Re */
+#define SM_SV_MOV_DATA 0x6 /* Supervisor Move_Data Tr/Re */
+#define SM_SV_PUT_DESC 0x7 /* Supervisor Put_Desc Tr/Re */
+#define SM_SV_SET_IRQ 0x5 /* Supervisor Set_Irq Tr/Re */
+
+#define SM_RD_IDLE 0x0 /* Read Desc. Idle Tr/Re */
+#define SM_RD_LOAD 0x1 /* Read Desc. Load Tr/Re */
+#define SM_RD_WAIT_TC 0x3 /* Read Desc. Wait_TC Tr/Re */
+#define SM_RD_RST_EOF 0x6 /* Read Desc. Reset_EOF Re */
+#define SM_RD_WDONE_R 0x2 /* Read Desc. Wait_Done Re */
+#define SM_RD_WDONE_T 0x4 /* Read Desc. Wait_Done Tr */
+
+#define SM_TR_IDLE 0x0 /* Trans. Data Idle Tr/Re */
+#define SM_TR_LOAD 0x3 /* Trans. Data Load Tr/Re */
+#define SM_TR_LOAD_R_ML 0x1 /* Trans. Data Load /Re (ML) */
+#define SM_TR_WAIT_TC 0x2 /* Trans. Data Wait_TC Tr/Re */
+#define SM_TR_WDONE 0x4 /* Trans. Data Wait_Done Tr/Re */
+
+#define SM_WR_IDLE 0x0 /* Write Desc. Idle Tr/Re */
+#define SM_WR_ABLEN 0x1 /* Write Desc. Act_Buf_Length Tr/Re */
+#define SM_WR_LD_A4 0x2 /* Write Desc. Load_A4 Re */
+#define SM_WR_RES_OWN 0x2 /* Write Desc. Res_OWN Tr */
+#define SM_WR_WAIT_EOF 0x3 /* Write Desc. Wait_EOF Re */
+#define SM_WR_LD_N2C_R 0x4 /* Write Desc. Load_N2C Re */
+#define SM_WR_WAIT_TC_R 0x5 /* Write Desc. Wait_TC Re */
+#define SM_WR_WAIT_TC4 0x6 /* Write Desc. Wait_TC4 Re */
+#define SM_WR_LD_A_T 0x6 /* Write Desc. Load_A Tr */
+#define SM_WR_LD_A_R 0x7 /* Write Desc. Load_A Re */
+#define SM_WR_WAIT_TC_T 0x7 /* Write Desc. Wait_TC Tr */
+#define SM_WR_LD_N2C_T 0xc /* Write Desc. Load_N2C Tr */
+#define SM_WR_WDONE_T 0x9 /* Write Desc. Wait_Done Tr */
+#define SM_WR_WDONE_R 0xc /* Write Desc. Wait_Done Re */
+#define SM_WR_LD_D_AD 0xe /* Write Desc. Load_Dumr_A Re (ML) */
+#define SM_WR_WAIT_D_TC 0xf /* Write Desc. Wait_Dumr_TC Re (ML) */
+
+/* B5_<xx>_T2 32 bit Test Register 2 (xx) */
+/* Note: This register is only defined for the transmit queues */
+ /* Bit 31..8: reserved */
+#define AC_TEST_ON (1<<7) /* Bit 7: Address Counter Test Mode on */
+#define AC_TEST_OFF (1<<6) /* Bit 6: Address Counter Test Mode off*/
+#define BC_TEST_ON (1<<5) /* Bit 5: Byte Counter Test Mode on */
+#define BC_TEST_OFF (1<<4) /* Bit 4: Byte Counter Test Mode off */
+#define TEST_STEP04 (1<<3) /* Bit 3: Inc AC/Dec BC by 4 */
+#define TEST_STEP03 (1<<2) /* Bit 2: Inc AC/Dec BC by 3 */
+#define TEST_STEP02 (1<<1) /* Bit 1: Inc AC/Dec BC by 2 */
+#define TEST_STEP01 (1<<0) /* Bit 0: Inc AC/Dec BC by 1 */
+
+/* B5_<xx>_T3 32 bit Test Register 3 (xx) */
+/* Note: This register is only defined for the transmit queues */
+ /* Bit 31..8: reserved */
+#define T3_MUX_2 (1<<7) /* Bit 7: (ML) Mux position MSB */
+#define T3_VRAM_2 (1<<6) /* Bit 6: (ML) Virtual RAM buffer addr MSB */
+#define T3_LOOP (1<<5) /* Bit 5: Set Loopback (Xmit) */
+#define T3_UNLOOP (1<<4) /* Bit 4: Unset Loopback (Xmit) */
+#define T3_MUX (3<<2) /* Bit 3..2: Mux position */
+#define T3_VRAM (3<<0) /* Bit 1..0: Virtual RAM buffer Address */
+
+/* PCI card IDs */
+/*
+ * Note: The following 4 byte definitions shall not be used! Use OEM Concept!
+ */
+#define PCI_VEND_ID0 0x48 /* PCI vendor ID (SysKonnect) */
+#define PCI_VEND_ID1 0x11 /* PCI vendor ID (SysKonnect) */
+ /* (High byte) */
+#define PCI_DEV_ID0 0x00 /* PCI device ID */
+#define PCI_DEV_ID1 0x40 /* PCI device ID (High byte) */
+
+/*#define PCI_CLASS 0x02*/ /* PCI class code: network device */
+#define PCI_NW_CLASS 0x02 /* PCI class code: network device */
+#define PCI_SUB_CLASS 0x02 /* PCI subclass ID: FDDI device */
+#define PCI_PROG_INTFC 0x00 /* PCI programming Interface (=0) */
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define FMA(a) (0x0400|((a)<<2)) /* FORMAC+ (r/w) (SN3) */
+#define P1(a) (0x0380|((a)<<2)) /* PLC1 (r/w) (DAS) */
+#define P2(a) (0x0600|((a)<<2)) /* PLC2 (r/w) (covered by the SN3) */
+#define PRA(a) (B2_MAC_0 + (a)) /* configuration PROM (MAC address) */
+
+/*
+ * FlashProm specification
+ */
+#define MAX_PAGES 0x20000L /* Every byte has a single page */
+#define MAX_FADDR 1 /* 1 byte per page */
+
+/*
+ * Receive / Transmit Buffer Control word
+ */
+#define BMU_OWN (1UL<<31) /* OWN bit: 0 == host, 1 == adapter */
+#define BMU_STF (1L<<30) /* Start of Frame ? */
+#define BMU_EOF (1L<<29) /* End of Frame ? */
+#define BMU_EN_IRQ_EOB (1L<<28) /* Enable "End of Buffer" IRQ */
+#define BMU_EN_IRQ_EOF (1L<<27) /* Enable "End of Frame" IRQ */
+#define BMU_DEV_0 (1L<<26) /* RX: don't transfer to system mem */
+#define BMU_SMT_TX (1L<<25) /* TX: if set, buffer type SMT_MBuf */
+#define BMU_ST_BUF (1L<<25) /* RX: copy of start of frame */
+#define BMU_UNUSED (1L<<24) /* Set if the Descr is curr unused */
+#define BMU_SW (3L<<24) /* 2 Bits reserved for SW usage */
+#define BMU_CHECK 0x00550000L /* To identify the control word */
+#define BMU_BBC 0x0000FFFFL /* R/T Buffer Byte Count */
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#ifdef MEM_MAPPED_IO
+#define ADDR(a) (char far *) smc->hw.iop+(a)
+#define ADDRS(smc,a) (char far *) (smc)->hw.iop+(a)
+#else
+#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), \
+ (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \
+ (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#define ADDRS(smc,a) (((a)>>7) ? (outp((smc)->hw.iop+B0_RAP,(a)>>7), \
+ ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \
+ ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#endif
+
+/*
+ * Define a macro to access the configuration space
+ */
+#define PCI_C(a) ADDR(B3_CFG_SPC + (a)) /* PCI Config Space */
+
+#define EXT_R(a) ADDR(B6_EXT_REG + (a)) /* External Registers */
+
+/*
+ * Define some values needed for the MAC address (PROM)
+ */
+#define SA_MAC (0) /* start addr. MAC_AD within the PROM */
+#define PRA_OFF (0) /* offset correction when 4th byte reading */
+
+#define SKFDDI_PSZ 8 /* address PROM size */
+
+#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */
+#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */
+#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */
+#define PR_A(a) ADDR(PRA(a)) /* config. PROM (MAC address) */
+
+/*
+ * Macro to read the PROM
+ */
+#define READ_PROM(a) ((u_char)inp(a))
+
+#define GET_PAGE(bank) outpd(ADDR(B2_FAR),bank)
+#define VPP_ON()
+#define VPP_OFF()
+
+/*
+ * Note: Values of the Interrupt Source Register are defined above
+ */
+#define ISR_A ADDR(B0_ISRC)
+#define GET_ISR() inpd(ISR_A)
+#define GET_ISR_SMP(iop) inpd((iop)+B0_ISRC)
+#define CHECK_ISR() (inpd(ISR_A) & inpd(ADDR(B0_IMSK)))
+#define CHECK_ISR_SMP(iop) (inpd((iop)+B0_ISRC) & inpd((iop)+B0_IMSK))
+
+#define BUS_CHECK()
+
+/*
+ * CLI_FBI: Disable Board Interrupts
+ * STI_FBI: Enable Board Interrupts
+ */
+#ifndef UNIX
+#define CLI_FBI() outpd(ADDR(B0_IMSK),0)
+#else
+#define CLI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),0)
+#endif
+
+#ifndef UNIX
+#define STI_FBI() outpd(ADDR(B0_IMSK),smc->hw.is_imask)
+#else
+#define STI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),(smc)->hw.is_imask)
+#endif
+
+#define CLI_FBI_SMP(iop) outpd((iop)+B0_IMSK,0)
+#define STI_FBI_SMP(smc,iop) outpd((iop)+B0_IMSK,(smc)->hw.is_imask)
+
+#endif /* PCI */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * 12 bit transfer (dword) counter:
+ * (ISA: 2*trc = number of byte)
+ * (EISA: 4*trc = number of byte)
+ * (MCA: 4*trc = number of byte)
+ */
+#define MAX_TRANS (0x0fff)
+
+/*
+ * PC PIC
+ */
+#define MST_8259 (0x20)
+#define SLV_8259 (0xA0)
+
+#define TPS (18) /* ticks per second */
+
+/*
+ * error timer defs
+ */
+#define TN (4) /* number of supported timer = TN+1 */
+#define SNPPND_TIME (5) /* buffer memory access over mem. data reg. */
+
+#define MAC_AD 0x405a0000
+
+#define MODR1 FM_A(FM_MDREG1) /* mode register 1 */
+#define MODR2 FM_A(FM_MDREG2) /* mode register 2 */
+
+#define CMDR1 FM_A(FM_CMDREG1) /* command register 1 */
+#define CMDR2 FM_A(FM_CMDREG2) /* command register 2 */
+
+
+/*
+ * function defines
+ */
+#define CLEAR(io,mask) outpw((io),inpw(io)&(~(mask)))
+#define SET(io,mask) outpw((io),inpw(io)|(mask))
+#define GET(io,mask) (inpw(io)&(mask))
+#define SETMASK(io,val,mask) outpw((io),(inpw(io) & ~(mask)) | (val))
+
+/*
+ * PHY Port A (PA) = PLC 1
+ * With SuperNet 3 PHY-A and PHY S are identical.
+ */
+#define PLC(np,reg) (((np) == PA) ? P2_A(reg) : P1_A(reg))
+
+/*
+ * set memory address register for write and read
+ */
+#define MARW(ma) outpw(FM_A(FM_MARW),(unsigned int)(ma))
+#define MARR(ma) outpw(FM_A(FM_MARR),(unsigned int)(ma))
+
+/*
+ * read/write from/to memory data register
+ */
+/* write double word */
+#define MDRW(dd) outpw(FM_A(FM_MDRU),(unsigned int)((dd)>>16)) ;\
+ outpw(FM_A(FM_MDRL),(unsigned int)(dd))
+
+#ifndef WINNT
+/* read double word */
+#define MDRR() (((long)inpw(FM_A(FM_MDRU))<<16) + inpw(FM_A(FM_MDRL)))
+
+/* read FORMAC+ 32-bit status register */
+#define GET_ST1() (((long)inpw(FM_A(FM_ST1U))<<16) + inpw(FM_A(FM_ST1L)))
+#define GET_ST2() (((long)inpw(FM_A(FM_ST2U))<<16) + inpw(FM_A(FM_ST2L)))
+#ifdef SUPERNET_3
+#define GET_ST3() (((long)inpw(FM_A(FM_ST3U))<<16) + inpw(FM_A(FM_ST3L)))
+#endif
+#else
+/* read double word */
+#define MDRR() inp2w((FM_A(FM_MDRU)),(FM_A(FM_MDRL)))
+
+/* read FORMAC+ 32-bit status register */
+#define GET_ST1() inp2w((FM_A(FM_ST1U)),(FM_A(FM_ST1L)))
+#define GET_ST2() inp2w((FM_A(FM_ST2U)),(FM_A(FM_ST2L)))
+#ifdef SUPERNET_3
+#define GET_ST3() inp2w((FM_A(FM_ST3U)),(FM_A(FM_ST3L)))
+#endif
+#endif
+
+/* Special timer macro for 82c54 */
+ /* timer access over data bus bit 8..15 */
+#define OUT_82c54_TIMER(port,val) outpw(TI_A(port),(val)<<8)
+#define IN_82c54_TIMER(port) ((inpw(TI_A(port))>>8) & 0xff)
+
+
+#ifdef DEBUG
+#define DB_MAC(mac,st) {if (debug_mac & 0x1)\
+ printf("M") ;\
+ if (debug_mac & 0x2)\
+ printf("\tMAC %d status 0x%08lx\n",mac,st) ;\
+ if (debug_mac & 0x4)\
+ dp_mac(mac,st) ;\
+}
+
+#define DB_PLC(p,iev) { if (debug_plc & 0x1)\
+ printf("P") ;\
+ if (debug_plc & 0x2)\
+ printf("\tPLC %s Int 0x%04x\n", \
+ (p == PA) ? "A" : "B", iev) ;\
+ if (debug_plc & 0x4)\
+ dp_plc(p,iev) ;\
+}
+
+#define DB_TIMER() { if (debug_timer & 0x1)\
+ printf("T") ;\
+ if (debug_timer & 0x2)\
+ printf("\tTimer ISR\n") ;\
+}
+
+#else /* no DEBUG */
+
+#define DB_MAC(mac,st)
+#define DB_PLC(p,iev)
+#define DB_TIMER()
+
+#endif /* no DEBUG */
+
+#define INC_PTR(sp,cp,ep) if (++cp == ep) cp = sp
+/*
+ * timer defs
+ */
+#define COUNT(t) ((t)<<6) /* counter */
+#define RW_OP(o) ((o)<<4) /* read/write operation */
+#define TMODE(m) ((m)<<1) /* timer mode */
+
+#endif
diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h
new file mode 100644
index 000000000..79d55ad2c
--- /dev/null
+++ b/drivers/net/skfp/h/skfbiinc.h
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _SKFBIINC_
+#define _SKFBIINC_
+
+#include "h/supern_2.h"
+
+/*
+ * special defines for use into .asm files
+ */
+#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1)
+
+#ifdef ISA
+#define DMA_BUSY_CHECK CSRA
+#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT)
+#define HRQR (RQAA+(RQ_RRQ<<1))
+#define HRQW (RQAA+(RQ_WA2<<1))
+#define HRQA0 (RQAA+(RQ_WA0<<1))
+#define HRQSQ (RQAA+(RQ_WSQ<<1))
+#endif
+
+#ifdef EISA
+#define DMA_BUSY_CHECK CSRA
+#define DMA_HIGH_WORD 0x0400
+#define DMA_MASK_M 0x0a
+#define DMA_MODE_M 0x0b
+#define DMA_BYTE_PTR_M 0x0c
+#define DMA_MASK_S 0x0d4
+#define DMA_MODE_S 0x0d6
+#define DMA_BYTE_PTR_S 0x0d8
+#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC)
+#endif /* EISA */
+
+#ifdef MCA
+#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+ IS_CHCK_L | IS_BUSERR)
+#endif
+
+#ifdef PCI
+#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+ IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
+ IS_R1_C | IS_XA_C | IS_XS_C)
+#endif
+
+#ifdef PCI
+#define ISR_MASK (IS_MINTR1 | IS_R1_F | IS_XS_F| IS_XA_F | IMASK_FAST)
+#else
+#define ISR_MASK (IS_MINTR1 | IS_MINTR2 | IMASK_FAST)
+#endif
+
+#define FMA_FM_CMDREG1 FMA(FM_CMDREG1)
+#define FMA_FM_CMDREG2 FMA(FM_CMDREG2)
+#define FMA_FM_STMCHN FMA(FM_STMCHN)
+#define FMA_FM_RPR FMA(FM_RPR)
+#define FMA_FM_WPXA0 FMA(FM_WPXA0)
+#define FMA_FM_WPXA2 FMA(FM_WPXA2)
+#define FMA_FM_MARR FMA(FM_MARR)
+#define FMA_FM_MARW FMA(FM_MARW)
+#define FMA_FM_MDRU FMA(FM_MDRU)
+#define FMA_FM_MDRL FMA(FM_MDRL)
+#define FMA_ST1L FMA(FM_ST1L)
+#define FMA_ST1U FMA(FM_ST1U)
+#define FMA_ST2L FMA(FM_ST2L)
+#define FMA_ST2U FMA(FM_ST2U)
+#ifdef SUPERNET_3
+#define FMA_ST3L FMA(FM_ST3L)
+#define FMA_ST3U FMA(FM_ST3U)
+#endif
+
+#define TMODE_RRQ RQ_RRQ
+#define TMODE_WAQ2 RQ_WA2
+#define HSRA HSR(0)
+
+
+#define FMA_FM_ST1L FMA_ST1L
+#define FMA_FM_ST1U FMA_ST1U
+#define FMA_FM_ST2L FMA_ST2L
+#define FMA_FM_ST2U FMA_ST2U
+#ifdef SUPERNET_3
+#define FMA_FM_ST3L FMA_ST3L
+#define FMA_FM_ST3U FMA_ST3U
+#endif
+
+#define FMA_FM_SWPR FMA(FM_SWPR)
+
+#define FMA_FM_RPXA0 FMA(FM_RPXA0)
+
+#define FMA_FM_RPXS FMA(FM_RPXS)
+#define FMA_FM_WPXS FMA(FM_WPXS)
+
+#define FMA_FM_IMSK1U FMA(FM_IMSK1U)
+#define FMA_FM_IMSK1L FMA(FM_IMSK1L)
+
+#define FMA_FM_EAS FMA(FM_EAS)
+#define FMA_FM_EAA0 FMA(FM_EAA0)
+
+#define TMODE_WAQ0 RQ_WA0
+#define TMODE_WSQ RQ_WSQ
+
+/* Define default for DRV_PCM_STATE_CHANGE */
+#ifndef DRV_PCM_STATE_CHANGE
+#define DRV_PCM_STATE_CHANGE(smc,plc,p_state) /* nothing */
+#endif
+
+/* Define default for DRV_RMT_INDICATION */
+#ifndef DRV_RMT_INDICATION
+#define DRV_RMT_INDICATION(smc,i) /* nothing */
+#endif
+
+#endif /* n_SKFBIINC_ */
+
diff --git a/drivers/net/skfp/h/smc.h b/drivers/net/skfp/h/smc.h
new file mode 100644
index 000000000..b909586bc
--- /dev/null
+++ b/drivers/net/skfp/h/smc.h
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _SCMECM_
+#define _SCMECM_
+
+#if defined(PCI) && !defined(OSDEF)
+/*
+ * In the case of the PCI bus the file osdef1st.h must be present
+ */
+#define OSDEF
+#endif
+
+#ifdef PCI
+#ifndef SUPERNET_3
+#define SUPERNET_3
+#endif
+#ifndef TAG_MODE
+#define TAG_MODE
+#endif
+#endif
+
+/*
+ * include all other files in required order
+ * the following files must have been included before:
+ * types.h
+ * fddi.h
+ */
+#ifdef OSDEF
+#include "h/osdef1st.h"
+#endif /* OSDEF */
+#ifdef OEM_CONCEPT
+#include "oemdef.h"
+#endif /* OEM_CONCEPT */
+#include "h/smt.h"
+#include "h/cmtdef.h"
+#include "h/fddimib.h"
+#include "h/targethw.h" /* all target hw dependencies */
+#include "h/targetos.h" /* all target os dependencies */
+#ifdef ESS
+#include "h/sba.h"
+#endif
+
+/*
+ * Event Queue
+ * queue.c
+ * events are class/value pairs
+ * class is addressee, e.g. RMT, PCM etc.
+ * value is command, e.g. line state change, ring op change etc.
+ */
+struct event_queue {
+ u_short class ; /* event class */
+ u_short event ; /* event value */
+} ;
+
+/*
+ * define event queue as circular buffer
+ */
+#ifdef CONCENTRATOR
+#define MAX_EVENT 128
+#else /* nCONCENTRATOR */
+#define MAX_EVENT 64
+#endif /* nCONCENTRATOR */
+
+struct s_queue {
+
+ struct event_queue ev_queue[MAX_EVENT];
+ struct event_queue *ev_put ;
+ struct event_queue *ev_get ;
+} ;
+
+/*
+ * ECM - Entity Coordination Management
+ * ecm.c
+ */
+struct s_ecm {
+ u_char path_test ; /* ECM path test variable */
+ u_char sb_flag ; /* ECM stuck bypass */
+ u_char DisconnectFlag ; /* jd 05-Aug-1999 Bug #10419
+ * ECM disconnected */
+ u_char ecm_line_state ; /* flag to dispatcher : line states */
+ u_long trace_prop ; /* ECM Trace_Prop flag >= 16 bits !! */
+ /* NUMPHYS note:
+ * this variable must have enough bits to hold all entiies in
+ * the station. So NUMPHYS may not be greater than 31.
+ */
+ char ec_pad[2] ;
+ struct smt_timer ecm_timer ; /* timer */
+} ;
+
+
+/*
+ * RMT - Ring Management
+ * rmt.c
+ */
+struct s_rmt {
+ u_char dup_addr_test ; /* state of dupl. addr. test */
+ u_char da_flag ; /* flag : duplicate address det. */
+ u_char loop_avail ; /* flag : MAC available for loopback */
+ u_char sm_ma_avail ; /* flag : MAC available for SMT */
+ u_char no_flag ; /* flag : ring not operational */
+ u_char bn_flag ; /* flag : MAC reached beacon state */
+ u_char jm_flag ; /* flag : jamming in NON_OP_DUP */
+ u_char rm_join ; /* CFM flag RM_Join */
+ u_char rm_loop ; /* CFM flag RM_Loop */
+
+ long fast_rm_join ; /* bit mask of active ports */
+ /*
+ * timer and flags
+ */
+ struct smt_timer rmt_timer0 ; /* timer 0 */
+ struct smt_timer rmt_timer1 ; /* timer 1 */
+ struct smt_timer rmt_timer2 ; /* timer 2 */
+ u_char timer0_exp ; /* flag : timer 0 expired */
+ u_char timer1_exp ; /* flag : timer 1 expired */
+ u_char timer2_exp ; /* flag : timer 2 expired */
+
+ u_char rm_pad1[1] ;
+} ;
+
+/*
+ * CFM - Configuration Management
+ * cfm.c
+ * used for SAS and DAS
+ */
+struct s_cfm {
+ u_char cf_state; /* CFM state machine current state */
+ u_char cf_pad[3] ;
+} ;
+
+/*
+ * CEM - Configuration Element Management
+ * cem.c
+ * used for Concentrator
+ */
+#ifdef CONCENTRATOR
+struct s_cem {
+ int ce_state ; /* CEM state */
+ int ce_port ; /* PA PB PM PM+1 .. */
+ int ce_type ; /* TA TB TS TM */
+} ;
+
+/*
+ * linked list of CCEs in current token path
+ */
+struct s_c_ring {
+ struct s_c_ring *c_next ;
+ char c_entity ;
+} ;
+
+struct mib_path_config {
+ u_long fddimibPATHConfigSMTIndex;
+ u_long fddimibPATHConfigPATHIndex;
+ u_long fddimibPATHConfigTokenOrder;
+ u_long fddimibPATHConfigResourceType;
+#define SNMP_RES_TYPE_MAC 2 /* Resource is a MAC */
+#define SNMP_RES_TYPE_PORT 4 /* Resource is a PORT */
+ u_long fddimibPATHConfigResourceIndex;
+ u_long fddimibPATHConfigCurrentPath;
+#define SNMP_PATH_ISOLATED 1 /* Current path is isolated */
+#define SNMP_PATH_LOCAL 2 /* Current path is local */
+#define SNMP_PATH_SECONDARY 3 /* Current path is secondary */
+#define SNMP_PATH_PRIMARY 4 /* Current path is primary */
+#define SNMP_PATH_CONCATENATED 5 /* Current path is concatenated */
+#define SNMP_PATH_THRU 6 /* Current path is thru */
+};
+
+
+#endif
+
+/*
+ * PCM connect states
+ */
+#define PCM_DISABLED 0
+#define PCM_CONNECTING 1
+#define PCM_STANDBY 2
+#define PCM_ACTIVE 3
+
+struct s_pcm {
+ u_char pcm_pad[3] ;
+} ;
+
+/*
+ * PHY struct
+ * one per physical port
+ */
+struct s_phy {
+ /* Inter Module Globals */
+ struct fddi_mib_p *mib ;
+
+ u_char np ; /* index 0 .. NUMPHYS */
+ u_char cf_join ;
+ u_char cf_loop ;
+ u_char wc_flag ; /* withhold connection flag */
+ u_char pc_mode ; /* Holds the negotiated mode of the PCM */
+ u_char pc_lem_fail ; /* flag : LCT failed */
+ u_char lc_test ;
+ u_char scrub ; /* CFM flag Scrub -> PCM */
+ char phy_name ;
+ u_char pmd_type[2] ; /* SK connector/transceiver type codes */
+#define PMD_SK_CONN 0 /* pmd_type[PMD_SK_CONN] = Connector */
+#define PMD_SK_PMD 1 /* pmd_type[PMD_SK_PMD] = Xver */
+ u_char pmd_scramble ; /* scrambler on/off */
+
+ /* inner Module Globals */
+ u_char curr_ls ; /* current line state */
+ u_char ls_flag ;
+ u_char rc_flag ;
+ u_char tc_flag ;
+ u_char td_flag ;
+ u_char bitn ;
+ u_char tr_flag ; /* trace recvd while in active */
+ u_char twisted ; /* flag to indicate an A-A or B-B connection */
+ u_char t_val[NUMBITS] ; /* transmit bits for signaling */
+ u_char r_val[NUMBITS] ; /* receive bits for signaling */
+ u_long t_next[NUMBITS] ;
+ struct smt_timer pcm_timer0 ;
+ struct smt_timer pcm_timer1 ;
+ struct smt_timer pcm_timer2 ;
+ u_char timer0_exp ;
+ u_char timer1_exp ;
+ u_char timer2_exp ;
+ u_char pcm_pad1[1] ;
+ int cem_pst ; /* CEM privae state; used for dual homing */
+ struct lem_counter lem ;
+#ifdef AMDPLC
+ struct s_plc plc ;
+#endif
+} ;
+
+/*
+ * timer package
+ * smttimer.c
+ */
+struct s_timer {
+ struct smt_timer *st_queue ;
+ struct smt_timer st_fast ;
+} ;
+
+/*
+ * SRF types and data
+ */
+#define SMT_EVENT_BASE 1
+#define SMT_EVENT_MAC_PATH_CHANGE (SMT_EVENT_BASE+0)
+#define SMT_EVENT_MAC_NEIGHBOR_CHANGE (SMT_EVENT_BASE+1)
+#define SMT_EVENT_PORT_PATH_CHANGE (SMT_EVENT_BASE+2)
+#define SMT_EVENT_PORT_CONNECTION (SMT_EVENT_BASE+3)
+
+#define SMT_IS_CONDITION(x) ((x)>=SMT_COND_BASE)
+
+#define SMT_COND_BASE (SMT_EVENT_PORT_CONNECTION+1)
+#define SMT_COND_SMT_PEER_WRAP (SMT_COND_BASE+0)
+#define SMT_COND_SMT_HOLD (SMT_COND_BASE+1)
+#define SMT_COND_MAC_FRAME_ERROR (SMT_COND_BASE+2)
+#define SMT_COND_MAC_DUP_ADDR (SMT_COND_BASE+3)
+#define SMT_COND_MAC_NOT_COPIED (SMT_COND_BASE+4)
+#define SMT_COND_PORT_EB_ERROR (SMT_COND_BASE+5)
+#define SMT_COND_PORT_LER (SMT_COND_BASE+6)
+
+#define SR0_WAIT 0
+#define SR1_HOLDOFF 1
+#define SR2_DISABLED 2
+
+struct s_srf {
+ u_long SRThreshold ; /* threshold value */
+ u_char RT_Flag ; /* report transmitted flag */
+ u_char sr_state ; /* state-machine */
+ u_char any_report ; /* any report required */
+ u_long TSR ; /* timer */
+ u_short ring_status ; /* IBM ring status */
+} ;
+
+/*
+ * IBM token ring status
+ */
+#define RS_RES15 (1<<15) /* reserved */
+#define RS_HARDERROR (1<<14) /* ring down */
+#define RS_SOFTERROR (1<<13) /* sent SRF */
+#define RS_BEACON (1<<12) /* transmitted beacon */
+#define RS_PATHTEST (1<<11) /* path test failed */
+#define RS_SELFTEST (1<<10) /* selftest required */
+#define RS_RES9 (1<< 9) /* reserved */
+#define RS_DISCONNECT (1<< 8) /* remote disconnect */
+#define RS_RES7 (1<< 7) /* reserved */
+#define RS_DUPADDR (1<< 6) /* duplicate address */
+#define RS_NORINGOP (1<< 5) /* no ring op */
+#define RS_VERSION (1<< 4) /* SMT version mismatch */
+#define RS_STUCKBYPASSS (1<< 3) /* stuck bypass */
+#define RS_EVENT (1<< 2) /* FDDI event occured */
+#define RS_RINGOPCHANGE (1<< 1) /* ring op changed */
+#define RS_RES0 (1<< 0) /* reserved */
+
+#define RS_SET(smc,bit) \
+ ring_status_indication(smc,smc->srf.ring_status |= bit)
+#define RS_CLEAR(smc,bit) \
+ ring_status_indication(smc,smc->srf.ring_status &= ~bit)
+
+#define RS_CLEAR_EVENT (0xffff & ~(RS_NORINGOP))
+
+/* Define the AIX-event-Notification as null function if it isn't defined */
+/* in the targetos.h file */
+#ifndef AIX_EVENT
+#define AIX_EVENT(smc,opt0,opt1,opt2,opt3) /* nothing */
+#endif
+
+struct s_srf_evc {
+ u_char evc_code ; /* event code type */
+ u_char evc_index ; /* index for mult. instances */
+ u_char evc_rep_required ; /* report required */
+ u_short evc_para ; /* SMT Para Number */
+ u_char *evc_cond_state ; /* condition state */
+ u_char *evc_multiple ; /* multiple occurence */
+} ;
+
+/*
+ * Values used by frame based services
+ * smt.c
+ */
+#define SMT_MAX_TEST 5
+#define SMT_TID_NIF 0 /* pending NIF request */
+#define SMT_TID_NIF_TEST 1 /* pending NIF test */
+#define SMT_TID_ECF_UNA 2 /* pending ECF UNA test */
+#define SMT_TID_ECF_DNA 3 /* pending ECF DNA test */
+#define SMT_TID_ECF 4 /* pending ECF test */
+
+struct smt_values {
+ u_long smt_tvu ; /* timer valid una */
+ u_long smt_tvd ; /* timer valid dna */
+ u_long smt_tid ; /* transaction id */
+ u_long pend[SMT_MAX_TEST] ; /* TID of requests */
+ u_long uniq_time ; /* unique time stamp */
+ u_short uniq_ticks ; /* unique time stamp */
+ u_short please_reconnect ; /* flag : reconnect */
+ u_long smt_last_lem ;
+ u_long smt_last_notify ;
+ struct smt_timer smt_timer ; /* SMT NIF timer */
+ u_long last_tok_time[NUMMACS]; /* token cnt emulation */
+} ;
+
+/*
+ * SMT/CMT configurable parameters
+ */
+#define SMT_DAS 0 /* dual attach */
+#define SMT_SAS 1 /* single attach */
+#define SMT_NAC 2 /* null attach concentrator */
+
+struct smt_config {
+ u_char attach_s ; /* CFM attach to secondary path */
+ u_char sas ; /* SMT_DAS/SAS/NAC */
+ u_char build_ring_map ; /* build ringmap if TRUE */
+ u_char numphys ; /* number of active phys */
+ u_char sc_pad[1] ;
+
+ u_long pcm_tb_min ; /* PCM : TB_Min timer value */
+ u_long pcm_tb_max ; /* PCM : TB_Max timer value */
+ u_long pcm_c_min ; /* PCM : C_Min timer value */
+ u_long pcm_t_out ; /* PCM : T_Out timer value */
+ u_long pcm_tl_min ; /* PCM : TL_min timer value */
+ u_long pcm_lc_short ; /* PCM : LC_Short timer value */
+ u_long pcm_lc_medium ; /* PCM : LC_Medium timer value */
+ u_long pcm_lc_long ; /* PCM : LC_Long timer value */
+ u_long pcm_lc_extended ; /* PCM : LC_Extended timer value */
+ u_long pcm_t_next_9 ; /* PCM : T_Next[9] timer value */
+ u_long pcm_ns_max ; /* PCM : NS_Max timer value */
+
+ u_long ecm_i_max ; /* ECM : I_Max timer value */
+ u_long ecm_in_max ; /* ECM : IN_Max timer value */
+ u_long ecm_td_min ; /* ECM : TD_Min timer */
+ u_long ecm_test_done ; /* ECM : path test done timer */
+ u_long ecm_check_poll ; /* ECM : check bypass poller */
+
+ u_long rmt_t_non_op ; /* RMT : T_Non_OP timer value */
+ u_long rmt_t_stuck ; /* RMT : T_Stuck timer value */
+ u_long rmt_t_direct ; /* RMT : T_Direct timer value */
+ u_long rmt_t_jam ; /* RMT : T_Jam timer value */
+ u_long rmt_t_announce ; /* RMT : T_Announce timer value */
+ u_long rmt_t_poll ; /* RMT : claim/beacon poller */
+ u_long rmt_dup_mac_behavior ; /* Flag for the beavior of SMT if
+ * a Duplicate MAC Address was detected.
+ * FALSE: SMT will leave finaly the ring
+ * TRUE: SMT will reinstert into the ring
+ */
+ u_long mac_d_max ; /* MAC : D_Max timer value */
+
+ u_long lct_short ; /* LCT : error threshhold */
+ u_long lct_medium ; /* LCT : error threshhold */
+ u_long lct_long ; /* LCT : error threshhold */
+ u_long lct_extended ; /* LCT : error threshhold */
+} ;
+
+#ifdef DEBUG
+/*
+ * Debugging struct sometimes used in smc
+ */
+struct smt_debug {
+ int d_smtf ;
+ int d_smt ;
+ int d_ecm ;
+ int d_rmt ;
+ int d_cfm ;
+ int d_pcm ;
+ int d_plc ;
+#ifdef ESS
+ int d_ess ;
+#endif
+#ifdef SBA
+ int d_sba ;
+#endif
+ struct os_debug d_os; /* Include specific OS DEBUG struct */
+} ;
+
+#ifndef DEBUG_BRD
+/* all boards shall be debugged with one debug struct */
+extern struct smt_debug debug; /* Declaration of debug struct */
+#endif /* DEBUG_BRD */
+
+#endif /* DEBUG */
+
+/*
+ * the SMT Context Struct SMC
+ * this struct contains ALL global variables of SMT
+ */
+struct s_smc {
+ struct s_smt_os os ; /* os specific */
+ struct s_smt_hw hw ; /* hardware */
+
+/*
+ * NOTE: os and hw MUST BE the first two structs
+ * anything beyond hw WILL BE SET TO ZERO in smt_set_defaults()
+ */
+ struct smt_config s ; /* smt constants */
+ struct smt_values sm ; /* smt variables */
+ struct s_ecm e ; /* ecm */
+ struct s_rmt r ; /* rmt */
+ struct s_cfm cf ; /* cfm/cem */
+#ifdef CONCENTRATOR
+ struct s_cem ce[NUMPHYS] ; /* cem */
+ struct s_c_ring cr[NUMPHYS+NUMMACS] ;
+#endif
+ struct s_pcm p ; /* pcm */
+ struct s_phy y[NUMPHYS] ; /* phy */
+ struct s_queue q ; /* queue */
+ struct s_timer t ; /* timer */
+ struct s_srf srf ; /* SRF */
+ struct s_srf_evc evcs[6+NUMPHYS*4] ;
+ struct fddi_mib mib ; /* __THE_MIB__ */
+#ifdef SBA
+ struct s_sba sba ; /* SBA variables */
+#endif
+#ifdef ESS
+ struct s_ess ess ; /* Ess variables */
+#endif
+#if defined(DEBUG) && defined(DEBUG_BRD)
+ /* If you want all single board to be debugged separately */
+ struct smt_debug debug; /* Declaration of debug struct */
+#endif /* DEBUG_BRD && DEBUG */
+} ;
+
+#endif /* _SCMECM_ */
+
diff --git a/drivers/net/skfp/h/smt.h b/drivers/net/skfp/h/smt.h
new file mode 100644
index 000000000..08eb1ccbf
--- /dev/null
+++ b/drivers/net/skfp/h/smt.h
@@ -0,0 +1,882 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SMT 7.2 frame definitions
+ */
+
+#ifndef _SMT_
+#define _SMT_
+
+/* #define SMT5_10 */
+#define SMT6_10
+#define SMT7_20
+
+#define OPT_PMF /* if parameter management is supported */
+#define OPT_SRF /* if status report is supported */
+
+/*
+ * SMT frame version 5.1
+ */
+
+#define SMT_VID 0x0001 /* V 5.1 .. 6.1 */
+#define SMT_VID_2 0x0002 /* V 7.2 */
+
+struct smt_sid {
+ u_char sid_oem[2] ; /* implementation spec. */
+ struct fddi_addr sid_node ; /* node address */
+} ;
+
+typedef u_char t_station_id[8] ;
+
+/*
+ * note on alignment :
+ * sizeof(struct smt_header) = 32
+ * all parameters are long aligned
+ * if struct smt_header starts at offset 0, all longs are aligned correctly
+ * (FC starts at offset 3)
+ */
+_packed struct smt_header {
+ struct fddi_addr smt_dest ; /* destination address */
+ struct fddi_addr smt_source ; /* source address */
+ u_char smt_class ; /* NIF, SIF ... */
+ u_char smt_type ; /* req., response .. */
+ u_short smt_version ; /* version id */
+ u_long smt_tid ; /* transaction ID */
+ struct smt_sid smt_sid ; /* station ID */
+ u_short smt_pad ; /* pad with 0 */
+ u_short smt_len ; /* length of info field */
+} ;
+#define SWAP_SMTHEADER "662sl8ss"
+
+#if 0
+/*
+ * MAC FC values
+ */
+#define FC_SMT_INFO 0x41 /* SMT info */
+#define FC_SMT_NSA 0x4f /* SMT Next Station Addressing */
+#endif
+
+
+/*
+ * type codes
+ */
+#define SMT_ANNOUNCE 0x01 /* announcement */
+#define SMT_REQUEST 0x02 /* request */
+#define SMT_REPLY 0x03 /* reply */
+
+/*
+ * class codes
+ */
+#define SMT_NIF 0x01 /* neighbor information frames */
+#define SMT_SIF_CONFIG 0x02 /* station information configuration */
+#define SMT_SIF_OPER 0x03 /* station information operation */
+#define SMT_ECF 0x04 /* echo frames */
+#define SMT_RAF 0x05 /* resource allocation */
+#define SMT_RDF 0x06 /* request denied */
+#define SMT_SRF 0x07 /* status report */
+#define SMT_PMF_GET 0x08 /* parameter management get */
+#define SMT_PMF_SET 0x09 /* parameter management set */
+#define SMT_ESF 0xff /* extended service */
+
+#define SMT_MAX_ECHO_LEN 4458 /* max length of SMT Echo */
+#if defined(CONC) || defined(CONC_II)
+#define SMT_TEST_ECHO_LEN 50 /* test length of SMT Echo */
+#else
+#define SMT_TEST_ECHO_LEN SMT_MAX_ECHO_LEN /* test length */
+#endif
+
+#define SMT_MAX_INFO_LEN (4352-20) /* max length for SMT info */
+
+
+/*
+ * parameter types
+ */
+
+struct smt_para {
+ u_short p_type ; /* type */
+ u_short p_len ; /* length of parameter */
+} ;
+
+#define PARA_LEN (sizeof(struct smt_para))
+
+#define SMTSETPARA(p,t) (p)->para.p_type = (t),\
+ (p)->para.p_len = sizeof(*(p)) - PARA_LEN
+
+/*
+ * P01 : Upstream Neighbor Address, UNA
+ */
+#define SMT_P_UNA 0x0001 /* upstream neighbor address */
+#define SWAP_SMT_P_UNA "s6"
+
+struct smt_p_una {
+ struct smt_para para ; /* generic parameter header */
+ u_short una_pad ;
+ struct fddi_addr una_node ; /* node address, zero if unknown */
+} ;
+
+/*
+ * P02 : Station Descriptor
+ */
+#define SMT_P_SDE 0x0002 /* station descriptor */
+#define SWAP_SMT_P_SDE "1111"
+
+#define SMT_SDE_STATION 0 /* end node */
+#define SMT_SDE_CONCENTRATOR 1 /* concentrator */
+
+struct smt_p_sde {
+ struct smt_para para ; /* generic parameter header */
+ u_char sde_type ; /* station type */
+ u_char sde_mac_count ; /* number of MACs */
+ u_char sde_non_master ; /* number of A,B or S ports */
+ u_char sde_master ; /* number of S ports on conc. */
+} ;
+
+/*
+ * P03 : Station State
+ */
+#define SMT_P_STATE 0x0003 /* station state */
+#define SWAP_SMT_P_STATE "scc"
+
+struct smt_p_state {
+ struct smt_para para ; /* generic parameter header */
+ u_short st_pad ;
+ u_char st_topology ; /* topology */
+ u_char st_dupl_addr ; /* duplicate address detected */
+} ;
+#define SMT_ST_WRAPPED (1<<0) /* station wrapped */
+#define SMT_ST_UNATTACHED (1<<1) /* unattached concentrator */
+#define SMT_ST_TWISTED_A (1<<2) /* A-A connection, twisted ring */
+#define SMT_ST_TWISTED_B (1<<3) /* B-B connection, twisted ring */
+#define SMT_ST_ROOTED_S (1<<4) /* rooted station */
+#define SMT_ST_SRF (1<<5) /* SRF protocol supported */
+#define SMT_ST_SYNC_SERVICE (1<<6) /* use synchronous bandwidth */
+
+#define SMT_ST_MY_DUPA (1<<0) /* my station detected dupl. */
+#define SMT_ST_UNA_DUPA (1<<1) /* my UNA detected duplicate */
+
+/*
+ * P04 : timestamp
+ */
+#define SMT_P_TIMESTAMP 0x0004 /* time stamp */
+#define SWAP_SMT_P_TIMESTAMP "8"
+struct smt_p_timestamp {
+ struct smt_para para ; /* generic parameter header */
+ u_char ts_time[8] ; /* time, resolution 80nS, unique */
+} ;
+
+/*
+ * P05 : station policies
+ */
+#define SMT_P_POLICY 0x0005 /* station policies */
+#define SWAP_SMT_P_POLICY "ss"
+
+struct smt_p_policy {
+ struct smt_para para ; /* generic parameter header */
+ u_short pl_config ;
+ u_short pl_connect ; /* bit string POLICY_AA ... */
+} ;
+#define SMT_PL_HOLD 1 /* hold policy supported (Dual MAC) */
+
+/*
+ * P06 : latency equivalent
+ */
+#define SMT_P_LATENCY 0x0006 /* latency */
+#define SWAP_SMT_P_LATENCY "ssss"
+
+/*
+ * note: latency has two phy entries by definition
+ * for a SAS, the 2nd one is null
+ */
+struct smt_p_latency {
+ struct smt_para para ; /* generic parameter header */
+ u_short lt_phyout_idx1 ; /* index */
+ u_short lt_latency1 ; /* latency , unit : byte clock */
+ u_short lt_phyout_idx2 ; /* 0 if SAS */
+ u_short lt_latency2 ; /* 0 if SAS */
+} ;
+
+/*
+ * P07 : MAC neighbors
+ */
+#define SMT_P_NEIGHBORS 0x0007 /* MAC neighbor description */
+#define SWAP_SMT_P_NEIGHBORS "ss66"
+
+struct smt_p_neighbor {
+ struct smt_para para ; /* generic parameter header */
+ u_short nb_mib_index ; /* MIB index */
+ u_short nb_mac_index ; /* n+1 .. n+m, m = #MACs, n = #PHYs */
+ struct fddi_addr nb_una ; /* UNA , 0 for unknown */
+ struct fddi_addr nb_dna ; /* DNA , 0 for unknown */
+} ;
+
+/*
+ * PHY record
+ */
+#define SMT_PHY_A 0 /* A port */
+#define SMT_PHY_B 1 /* B port */
+#define SMT_PHY_S 2 /* slave port */
+#define SMT_PHY_M 3 /* master port */
+
+#define SMT_CS_DISABLED 0 /* connect state : disabled */
+#define SMT_CS_CONNECTING 1 /* connect state : connecting */
+#define SMT_CS_STANDBY 2 /* connect state : stand by */
+#define SMT_CS_ACTIVE 3 /* connect state : active */
+
+#define SMT_RM_NONE 0
+#define SMT_RM_MAC 1
+
+struct smt_phy_rec {
+ u_short phy_mib_index ; /* MIB index */
+ u_char phy_type ; /* A/B/S/M */
+ u_char phy_connect_state ; /* disabled/connecting/active */
+ u_char phy_remote_type ; /* A/B/S/M */
+ u_char phy_remote_mac ; /* none/remote */
+ u_short phy_resource_idx ; /* 1 .. n */
+} ;
+
+/*
+ * MAC record
+ */
+struct smt_mac_rec {
+ struct fddi_addr mac_addr ; /* MAC address */
+ u_short mac_resource_idx ; /* n+1 .. n+m */
+} ;
+
+/*
+ * P08 : path descriptors
+ * should be really an array ; however our environment has a fixed number of
+ * PHYs and MACs
+ */
+#define SMT_P_PATH 0x0008 /* path descriptor */
+#define SWAP_SMT_P_PATH "[6s]"
+
+struct smt_p_path {
+ struct smt_para para ; /* generic parameter header */
+ struct smt_phy_rec pd_phy[2] ; /* PHY A */
+ struct smt_mac_rec pd_mac ; /* MAC record */
+} ;
+
+/*
+ * P09 : MAC status
+ */
+#define SMT_P_MAC_STATUS 0x0009 /* MAC status */
+#define SWAP_SMT_P_MAC_STATUS "sslllllllll"
+
+struct smt_p_mac_status {
+ struct smt_para para ; /* generic parameter header */
+ u_short st_mib_index ; /* MIB index */
+ u_short st_mac_index ; /* n+1 .. n+m */
+ u_long st_t_req ; /* T_Req */
+ u_long st_t_neg ; /* T_Neg */
+ u_long st_t_max ; /* T_Max */
+ u_long st_tvx_value ; /* TVX_Value */
+ u_long st_t_min ; /* T_Min */
+ u_long st_sba ; /* synchr. bandwidth alloc */
+ u_long st_frame_ct ; /* frame counter */
+ u_long st_error_ct ; /* error counter */
+ u_long st_lost_ct ; /* lost frames counter */
+} ;
+
+/*
+ * P0A : PHY link error rate monitoring
+ */
+#define SMT_P_LEM 0x000a /* link error monitor */
+#define SWAP_SMT_P_LEM "ssccccll"
+/*
+ * units of lem_cutoff,lem_alarm,lem_estimate : 10**-x
+ */
+struct smt_p_lem {
+ struct smt_para para ; /* generic parameter header */
+ u_short lem_mib_index ; /* MIB index */
+ u_short lem_phy_index ; /* 1 .. n */
+ u_char lem_pad2 ; /* be nice and make it even . */
+ u_char lem_cutoff ; /* 0x4 .. 0xf, default 0x7 */
+ u_char lem_alarm ; /* 0x4 .. 0xf, default 0x8 */
+ u_char lem_estimate ; /* 0x0 .. 0xff */
+ u_long lem_reject_ct ; /* 0x00000000 .. 0xffffffff */
+ u_long lem_ct ; /* 0x00000000 .. 0xffffffff */
+} ;
+
+/*
+ * P0B : MAC frame counters
+ */
+#define SMT_P_MAC_COUNTER 0x000b /* MAC frame counters */
+#define SWAP_SMT_P_MAC_COUNTER "ssll"
+
+struct smt_p_mac_counter {
+ struct smt_para para ; /* generic parameter header */
+ u_short mc_mib_index ; /* MIB index */
+ u_short mc_index ; /* mac index */
+ u_long mc_receive_ct ; /* receive counter */
+ u_long mc_transmit_ct ; /* transmit counter */
+} ;
+
+/*
+ * P0C : MAC frame not copied counter
+ */
+#define SMT_P_MAC_FNC 0x000c /* MAC frame not copied counter */
+#define SWAP_SMT_P_MAC_FNC "ssl"
+
+struct smt_p_mac_fnc {
+ struct smt_para para ; /* generic parameter header */
+ u_short nc_mib_index ; /* MIB index */
+ u_short nc_index ; /* mac index */
+ u_long nc_counter ; /* not copied counter */
+} ;
+
+
+/*
+ * P0D : MAC priority values
+ */
+#define SMT_P_PRIORITY 0x000d /* MAC priority values */
+#define SWAP_SMT_P_PRIORITY "ssl"
+
+struct smt_p_priority {
+ struct smt_para para ; /* generic parameter header */
+ u_short pr_mib_index ; /* MIB index */
+ u_short pr_index ; /* mac index */
+ u_long pr_priority[7] ; /* priority values */
+} ;
+
+/*
+ * P0E : PHY elasticity buffer status
+ */
+#define SMT_P_EB 0x000e /* PHY EB status */
+#define SWAP_SMT_P_EB "ssl"
+
+struct smt_p_eb {
+ struct smt_para para ; /* generic parameter header */
+ u_short eb_mib_index ; /* MIB index */
+ u_short eb_index ; /* phy index */
+ u_long eb_error_ct ; /* # of eb overflows */
+} ;
+
+/*
+ * P0F : manufacturer field
+ */
+#define SMT_P_MANUFACTURER 0x000f /* manufacturer field */
+#define SWAP_SMT_P_MANUFACTURER ""
+
+struct smp_p_manufacturer {
+ struct smt_para para ; /* generic parameter header */
+ u_char mf_data[32] ; /* OUI + arbitrary data */
+} ;
+
+/*
+ * P10 : user field
+ */
+#define SMT_P_USER 0x0010 /* manufacturer field */
+#define SWAP_SMT_P_USER ""
+
+struct smp_p_user {
+ struct smt_para para ; /* generic parameter header */
+ u_char us_data[32] ; /* arbitrary data */
+} ;
+
+
+
+/*
+ * P11 : echo data
+ */
+#define SMT_P_ECHODATA 0x0011 /* echo data */
+#define SWAP_SMT_P_ECHODATA ""
+
+struct smt_p_echo {
+ struct smt_para para ; /* generic parameter header */
+ u_char ec_data[SMT_MAX_ECHO_LEN-4] ; /* echo data */
+} ;
+
+/*
+ * P12 : reason code
+ */
+#define SMT_P_REASON 0x0012 /* reason code */
+#define SWAP_SMT_P_REASON "l"
+
+struct smt_p_reason {
+ struct smt_para para ; /* generic parameter header */
+ u_long rdf_reason ; /* CLASS/VERSION */
+} ;
+#define SMT_RDF_CLASS 0x00000001 /* class not supported */
+#define SMT_RDF_VERSION 0x00000002 /* version not supported */
+#define SMT_RDF_SUCCESS 0x00000003 /* success (PMF) */
+#define SMT_RDF_BADSET 0x00000004 /* bad set count (PMF) */
+#define SMT_RDF_ILLEGAL 0x00000005 /* read only (PMF) */
+#define SMT_RDF_NOPARAM 0x6 /* paramter not supported (PMF) */
+#define SMT_RDF_RANGE 0x8 /* out of range */
+#define SMT_RDF_AUTHOR 0x9 /* not autohorized */
+#define SMT_RDF_LENGTH 0x0a /* length error */
+#define SMT_RDF_TOOLONG 0x0b /* length error */
+#define SMT_RDF_SBA 0x0d /* SBA denied */
+
+/*
+ * P13 : refused frame beginning
+ */
+#define SMT_P_REFUSED 0x0013 /* refused frame beginning */
+#define SWAP_SMT_P_REFUSED "l"
+
+struct smt_p_refused {
+ struct smt_para para ; /* generic parameter header */
+ u_long ref_fc ; /* 3 bytes 0 + FC */
+ struct smt_header ref_header ; /* refused header */
+} ;
+
+/*
+ * P14 : supported SMT versions
+ */
+#define SMT_P_VERSION 0x0014 /* SMT supported versions */
+#define SWAP_SMT_P_VERSION "sccss"
+
+struct smt_p_version {
+ struct smt_para para ; /* generic parameter header */
+ u_short v_pad ;
+ u_char v_n ; /* 1 .. 0xff, #versions */
+ u_char v_index ; /* 1 .. 0xff, index of op. v. */
+ u_short v_version[1] ; /* list of min. 1 version */
+ u_short v_pad2 ; /* pad if necessary */
+} ;
+
+/*
+ * P15 : Resource Type
+ */
+#define SWAP_SMT_P0015 "l"
+
+struct smt_p_0015 {
+ struct smt_para para ; /* generic parameter header */
+ u_long res_type ; /* recsource type */
+} ;
+
+#define SYNC_BW 0x00000001L /* Synchronous Bandwidth */
+
+/*
+ * P16 : SBA Command
+ */
+#define SWAP_SMT_P0016 "l"
+
+struct smt_p_0016 {
+ struct smt_para para ; /* generic parameter header */
+ u_long sba_cmd ; /* command for the SBA */
+} ;
+
+#define REQUEST_ALLOCATION 0x1 /* req allocation of sync bandwidth */
+#define REPORT_ALLOCATION 0x2 /* rep of sync bandwidth allocation */
+#define CHANGE_ALLOCATION 0x3 /* forces a station using sync band-*/
+ /* width to change its current allo-*/
+ /* cation */
+
+/*
+ * P17 : SBA Payload Request
+ */
+#define SWAP_SMT_P0017 "l"
+
+struct smt_p_0017 {
+ struct smt_para para ; /* generic parameter header */
+ long sba_pl_req ; /* total sync bandwidth measured in */
+} ; /* bytes per 125 us */
+
+/*
+ * P18 : SBA Overhead Request
+ */
+#define SWAP_SMT_P0018 "l"
+
+struct smt_p_0018 {
+ struct smt_para para ; /* generic parameter header */
+ long sba_ov_req ; /* total sync bandwidth req for overhead*/
+} ; /* measuered in bytes per T_Neg */
+
+/*
+ * P19 : SBA Allocation Address
+ */
+#define SWAP_SMT_P0019 "s6"
+
+struct smt_p_0019 {
+ struct smt_para para ; /* generic parameter header */
+ u_short sba_pad ;
+ struct fddi_addr alloc_addr ; /* Allocation Address */
+} ;
+
+/*
+ * P1A : SBA Category
+ */
+#define SWAP_SMT_P001A "l"
+
+struct smt_p_001a {
+ struct smt_para para ; /* generic parameter header */
+ u_long category ; /* Allocator defined classification */
+} ;
+
+/*
+ * P1B : Maximum T_Neg
+ */
+#define SWAP_SMT_P001B "l"
+
+struct smt_p_001b {
+ struct smt_para para ; /* generic parameter header */
+ u_long max_t_neg ; /* longest T_NEG for the sync service*/
+} ;
+
+/*
+ * P1C : Minimum SBA Segment Size
+ */
+#define SWAP_SMT_P001C "l"
+
+struct smt_p_001c {
+ struct smt_para para ; /* generic parameter header */
+ u_long min_seg_siz ; /* smallest number of bytes per frame*/
+} ;
+
+/*
+ * P1D : SBA Allocatable
+ */
+#define SWAP_SMT_P001D "l"
+
+struct smt_p_001d {
+ struct smt_para para ; /* generic parameter header */
+ u_long allocatable ; /* total sync bw availabel for alloc */
+} ;
+
+/*
+ * P20 0B : frame status capabilities
+ * NOTE: not in swap table, is used by smt.c AND PMF table
+ */
+#define SMT_P_FSC 0x200b
+/* #define SWAP_SMT_P_FSC "ssss" */
+
+struct smt_p_fsc {
+ struct smt_para para ; /* generic parameter header */
+ u_short fsc_pad0 ;
+ u_short fsc_mac_index ; /* mac index 1 .. ff */
+ u_short fsc_pad1 ;
+ u_short fsc_value ; /* FSC_TYPE[0-2] */
+} ;
+
+#define FSC_TYPE0 0 /* "normal" node (A/C handling) */
+#define FSC_TYPE1 1 /* Special A/C indicator forwarding */
+#define FSC_TYPE2 2 /* Special A/C indicator forwarding */
+
+/*
+ * P00 21 : user defined authoriziation (see pmf.c)
+ */
+#define SMT_P_AUTHOR 0x0021
+
+/*
+ * notification parameters
+ */
+#define SWAP_SMT_P1048 "ll"
+struct smt_p_1048 {
+ u_long p1048_flag ;
+ u_long p1048_cf_state ;
+} ;
+
+/*
+ * NOTE: all 2xxx 3xxx and 4xxx must include the INDEX in the swap string,
+ * even so the INDEX is NOT part of the struct.
+ * INDEX is already swapped in pmf.c, format in string is '4'
+ */
+#define SWAP_SMT_P208C "4lss66"
+struct smt_p_208c {
+ u_long p208c_flag ;
+ u_short p208c_pad ;
+ u_short p208c_dupcondition ;
+ struct fddi_addr p208c_fddilong ;
+ struct fddi_addr p208c_fddiunalong ;
+} ;
+
+#define SWAP_SMT_P208D "4lllll"
+struct smt_p_208d {
+ u_long p208d_flag ;
+ u_long p208d_frame_ct ;
+ u_long p208d_error_ct ;
+ u_long p208d_lost_ct ;
+ u_long p208d_ratio ;
+} ;
+
+#define SWAP_SMT_P208E "4llll"
+struct smt_p_208e {
+ u_long p208e_flag ;
+ u_long p208e_not_copied ;
+ u_long p208e_copied ;
+ u_long p208e_not_copied_ratio ;
+} ;
+
+#define SWAP_SMT_P208F "4ll6666s6"
+
+struct smt_p_208f {
+ u_long p208f_multiple ;
+ u_long p208f_nacondition ;
+ struct fddi_addr p208f_old_una ;
+ struct fddi_addr p208f_new_una ;
+ struct fddi_addr p208f_old_dna ;
+ struct fddi_addr p208f_new_dna ;
+ u_short p208f_curren_path ;
+ struct fddi_addr p208f_smt_address ;
+} ;
+
+#define SWAP_SMT_P2090 "4lssl"
+
+struct smt_p_2090 {
+ u_long p2090_multiple ;
+ u_short p2090_availablepaths ;
+ u_short p2090_currentpath ;
+ u_long p2090_requestedpaths ;
+} ;
+
+/*
+ * NOTE:
+ * special kludge for parameters 320b,320f,3210
+ * these parameters are part of RAF frames
+ * RAF frames are parsed in SBA.C and must be swapped
+ * PMF.C has special code to avoid double swapping
+ */
+#ifdef LITTLE_ENDIAN
+#define SBAPATHINDEX (0x01000000L)
+#else
+#define SBAPATHINDEX (0x01L)
+#endif
+
+#define SWAP_SMT_P320B "42s"
+
+struct smt_p_320b {
+ struct smt_para para ; /* generic parameter header */
+ u_long mib_index ;
+ u_short path_pad ;
+ u_short path_index ;
+} ;
+
+#define SWAP_SMT_P320F "4l"
+
+struct smt_p_320f {
+ struct smt_para para ; /* generic parameter header */
+ u_long mib_index ;
+ u_long mib_payload ;
+} ;
+
+#define SWAP_SMT_P3210 "4l"
+
+struct smt_p_3210 {
+ struct smt_para para ; /* generic parameter header */
+ u_long mib_index ;
+ u_long mib_overhead ;
+} ;
+
+#define SWAP_SMT_P4050 "4l1111ll"
+
+struct smt_p_4050 {
+ u_long p4050_flag ;
+ u_char p4050_pad ;
+ u_char p4050_cutoff ;
+ u_char p4050_alarm ;
+ u_char p4050_estimate ;
+ u_long p4050_reject_ct ;
+ u_long p4050_ct ;
+} ;
+
+#define SWAP_SMT_P4051 "4lssss"
+struct smt_p_4051 {
+ u_long p4051_multiple ;
+ u_short p4051_porttype ;
+ u_short p4051_connectstate ;
+ u_short p4051_pc_neighbor ;
+ u_short p4051_pc_withhold ;
+} ;
+
+#define SWAP_SMT_P4052 "4ll"
+struct smt_p_4052 {
+ u_long p4052_flag ;
+ u_long p4052_eberrorcount ;
+} ;
+
+#define SWAP_SMT_P4053 "4lsslss"
+
+struct smt_p_4053 {
+ u_long p4053_multiple ;
+ u_short p4053_availablepaths ;
+ u_short p4053_currentpath ;
+ u_long p4053_requestedpaths ;
+ u_short p4053_mytype ;
+ u_short p4053_neighbortype ;
+} ;
+
+
+#define SMT_P_SETCOUNT 0x1035
+#define SWAP_SMT_P_SETCOUNT "l8"
+
+struct smt_p_setcount {
+ struct smt_para para ; /* generic parameter header */
+ u_long count ;
+ u_char timestamp[8] ;
+} ;
+
+/*
+ * SMT FRAMES
+ */
+
+/*
+ * NIF : neighbor information frames
+ */
+struct smt_nif {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_una una ; /* UNA */
+ struct smt_p_sde sde ; /* station descriptor */
+ struct smt_p_state state ; /* station state */
+#ifdef SMT6_10
+ struct smt_p_fsc fsc ; /* frame status cap. */
+#endif
+} ;
+
+/*
+ * SIF : station information frames
+ */
+struct smt_sif_config {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_timestamp ts ; /* time stamp */
+ struct smt_p_sde sde ; /* station descriptor */
+ struct smt_p_version version ; /* supported versions */
+ struct smt_p_state state ; /* station state */
+ struct smt_p_policy policy ; /* station policy */
+ struct smt_p_latency latency ; /* path latency */
+ struct smt_p_neighbor neighbor ; /* neighbors, we have only one*/
+#ifdef OPT_PMF
+ struct smt_p_setcount setcount ; /* Set Count mandatory */
+#endif
+ /* WARNING : path MUST BE LAST FIELD !!! (see smt.c:smt_fill_path) */
+ struct smt_p_path path ; /* path descriptor */
+} ;
+#define SIZEOF_SMT_SIF_CONFIG (sizeof(struct smt_sif_config)- \
+ sizeof(struct smt_p_path))
+
+struct smt_sif_operation {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_timestamp ts ; /* time stamp */
+ struct smt_p_mac_status status ; /* mac status */
+ struct smt_p_mac_counter mc ; /* MAC counter */
+ struct smt_p_mac_fnc fnc ; /* MAC frame not copied */
+ struct smp_p_manufacturer man ; /* manufacturer field */
+ struct smp_p_user user ; /* user field */
+#ifdef OPT_PMF
+ struct smt_p_setcount setcount ; /* Set Count mandatory */
+#endif
+ /* must be last */
+ struct smt_p_lem lem[1] ; /* phy lem status */
+} ;
+#define SIZEOF_SMT_SIF_OPERATION (sizeof(struct smt_sif_operation)- \
+ sizeof(struct smt_p_lem))
+
+/*
+ * ECF : echo frame
+ */
+struct smt_ecf {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_echo ec_echo ; /* echo parameter */
+} ;
+#define SMT_ECF_LEN (sizeof(struct smt_header)+sizeof(struct smt_para))
+
+/*
+ * RDF : request denied frame
+ */
+struct smt_rdf {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_reason reason ; /* reason code */
+ struct smt_p_version version ; /* supported versions */
+ struct smt_p_refused refused ; /* refused frame fragment */
+} ;
+
+/*
+ * SBA Request Allocation Responce Frame
+ */
+struct smt_sba_alc_res {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_0015 s_type ; /* resource type */
+ struct smt_p_0016 cmd ; /* SBA command */
+ struct smt_p_reason reason ; /* reason code */
+ struct smt_p_320b path ; /* path type */
+ struct smt_p_320f payload ; /* current SBA payload */
+ struct smt_p_3210 overhead ; /* current SBA overhead */
+ struct smt_p_0019 a_addr ; /* Allocation Address */
+ struct smt_p_001a cat ; /* Category - from the request */
+ struct smt_p_001d alloc ; /* SBA Allocatable */
+} ;
+
+/*
+ * SBA Request Allocation Request Frame
+ */
+struct smt_sba_alc_req {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_0015 s_type ; /* resource type */
+ struct smt_p_0016 cmd ; /* SBA command */
+ struct smt_p_320b path ; /* path type */
+ struct smt_p_0017 pl_req ; /* requested payload */
+ struct smt_p_0018 ov_req ; /* requested SBA overhead */
+ struct smt_p_320f payload ; /* current SBA payload */
+ struct smt_p_3210 overhead ; /* current SBA overhead */
+ struct smt_p_0019 a_addr ; /* Allocation Address */
+ struct smt_p_001a cat ; /* Category - from the request */
+ struct smt_p_001b tneg ; /* max T-NEG */
+ struct smt_p_001c segm ; /* minimum segment size */
+} ;
+
+/*
+ * SBA Change Allocation Request Frame
+ */
+struct smt_sba_chg {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_0015 s_type ; /* resource type */
+ struct smt_p_0016 cmd ; /* SBA command */
+ struct smt_p_320b path ; /* path type */
+ struct smt_p_320f payload ; /* current SBA payload */
+ struct smt_p_3210 overhead ; /* current SBA overhead */
+ struct smt_p_001a cat ; /* Category - from the request */
+} ;
+
+/*
+ * SBA Report Allocation Request Frame
+ */
+struct smt_sba_rep_req {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_0015 s_type ; /* resource type */
+ struct smt_p_0016 cmd ; /* SBA command */
+} ;
+
+/*
+ * SBA Report Allocation Response Frame
+ */
+struct smt_sba_rep_res {
+ struct smt_header smt ; /* generic header */
+ struct smt_p_0015 s_type ; /* resource type */
+ struct smt_p_0016 cmd ; /* SBA command */
+ struct smt_p_320b path ; /* path type */
+ struct smt_p_320f payload ; /* current SBA payload */
+ struct smt_p_3210 overhead ; /* current SBA overhead */
+} ;
+
+/*
+ * actions
+ */
+#define SMT_STATION_ACTION 1
+#define SMT_STATION_ACTION_CONNECT 0
+#define SMT_STATION_ACTION_DISCONNECT 1
+#define SMT_STATION_ACTION_PATHTEST 2
+#define SMT_STATION_ACTION_SELFTEST 3
+#define SMT_STATION_ACTION_DISABLE_A 4
+#define SMT_STATION_ACTION_DISABLE_B 5
+#define SMT_STATION_ACTION_DISABLE_M 6
+
+#define SMT_PORT_ACTION 2
+#define SMT_PORT_ACTION_MAINT 0
+#define SMT_PORT_ACTION_ENABLE 1
+#define SMT_PORT_ACTION_DISABLE 2
+#define SMT_PORT_ACTION_START 3
+#define SMT_PORT_ACTION_STOP 4
+
+#endif /* _SMT_ */
diff --git a/drivers/net/skfp/h/smt_p.h b/drivers/net/skfp/h/smt_p.h
new file mode 100644
index 000000000..99f9be955
--- /dev/null
+++ b/drivers/net/skfp/h/smt_p.h
@@ -0,0 +1,326 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * defines for all SMT attributes
+ */
+
+/*
+ * this boring file was produced by perl
+ * thanks Larry !
+ */
+#define SMT_P0012 0x0012
+
+#define SMT_P0015 0x0015
+#define SMT_P0016 0x0016
+#define SMT_P0017 0x0017
+#define SMT_P0018 0x0018
+#define SMT_P0019 0x0019
+
+#define SMT_P001A 0x001a
+#define SMT_P001B 0x001b
+#define SMT_P001C 0x001c
+#define SMT_P001D 0x001d
+
+#define SMT_P100A 0x100a
+#define SMT_P100B 0x100b
+#define SMT_P100C 0x100c
+#define SMT_P100D 0x100d
+#define SMT_P100E 0x100e
+#define SMT_P100F 0x100f
+#define SMT_P1010 0x1010
+#define SMT_P1011 0x1011
+#define SMT_P1012 0x1012
+#define SMT_P1013 0x1013
+#define SMT_P1014 0x1014
+#define SMT_P1015 0x1015
+#define SMT_P1016 0x1016
+#define SMT_P1017 0x1017
+#define SMT_P1018 0x1018
+#define SMT_P1019 0x1019
+#define SMT_P101A 0x101a
+#define SMT_P101B 0x101b
+#define SMT_P101C 0x101c
+#define SMT_P101D 0x101d
+#define SMT_P101E 0x101e
+#define SMT_P101F 0x101f
+#define SMT_P1020 0x1020
+#define SMT_P1021 0x1021
+#define SMT_P1022 0x1022
+#define SMT_P1023 0x1023
+#define SMT_P1024 0x1024
+#define SMT_P1025 0x1025
+#define SMT_P1026 0x1026
+#define SMT_P1027 0x1027
+#define SMT_P1028 0x1028
+#define SMT_P1029 0x1029
+#define SMT_P102A 0x102a
+#define SMT_P102B 0x102b
+#define SMT_P102C 0x102c
+#define SMT_P102D 0x102d
+#define SMT_P102E 0x102e
+#define SMT_P102F 0x102f
+#define SMT_P1030 0x1030
+#define SMT_P1031 0x1031
+#define SMT_P1032 0x1032
+#define SMT_P1033 0x1033
+#define SMT_P1034 0x1034
+#define SMT_P1035 0x1035
+#define SMT_P1036 0x1036
+#define SMT_P1037 0x1037
+#define SMT_P1038 0x1038
+#define SMT_P1039 0x1039
+#define SMT_P103A 0x103a
+#define SMT_P103B 0x103b
+#define SMT_P103C 0x103c
+#define SMT_P103D 0x103d
+#define SMT_P103E 0x103e
+#define SMT_P103F 0x103f
+#define SMT_P1040 0x1040
+#define SMT_P1041 0x1041
+#define SMT_P1042 0x1042
+#define SMT_P1043 0x1043
+#define SMT_P1044 0x1044
+#define SMT_P1045 0x1045
+#define SMT_P1046 0x1046
+#define SMT_P1047 0x1047
+#define SMT_P1048 0x1048
+#define SMT_P1049 0x1049
+#define SMT_P104A 0x104a
+#define SMT_P104B 0x104b
+#define SMT_P104C 0x104c
+#define SMT_P104D 0x104d
+#define SMT_P104E 0x104e
+#define SMT_P104F 0x104f
+#define SMT_P1050 0x1050
+#define SMT_P1051 0x1051
+#define SMT_P1052 0x1052
+#define SMT_P1053 0x1053
+#define SMT_P1054 0x1054
+
+#define SMT_P10F0 0x10f0
+#define SMT_P10F1 0x10f1
+#ifdef ESS
+#define SMT_P10F2 0x10f2
+#define SMT_P10F3 0x10f3
+#define SMT_P10F4 0x10f4
+#define SMT_P10F5 0x10f5
+#define SMT_P10F6 0x10f6
+#define SMT_P10F7 0x10f7
+#endif
+#ifdef SBA
+#define SMT_P10F8 0x10f8
+#define SMT_P10F9 0x10f9
+#endif
+
+#define SMT_P200A 0x200a
+#define SMT_P200B 0x200b
+#define SMT_P200C 0x200c
+#define SMT_P200D 0x200d
+#define SMT_P200E 0x200e
+#define SMT_P200F 0x200f
+#define SMT_P2010 0x2010
+#define SMT_P2011 0x2011
+#define SMT_P2012 0x2012
+#define SMT_P2013 0x2013
+#define SMT_P2014 0x2014
+#define SMT_P2015 0x2015
+#define SMT_P2016 0x2016
+#define SMT_P2017 0x2017
+#define SMT_P2018 0x2018
+#define SMT_P2019 0x2019
+#define SMT_P201A 0x201a
+#define SMT_P201B 0x201b
+#define SMT_P201C 0x201c
+#define SMT_P201D 0x201d
+#define SMT_P201E 0x201e
+#define SMT_P201F 0x201f
+#define SMT_P2020 0x2020
+#define SMT_P2021 0x2021
+#define SMT_P2022 0x2022
+#define SMT_P2023 0x2023
+#define SMT_P2024 0x2024
+#define SMT_P2025 0x2025
+#define SMT_P2026 0x2026
+#define SMT_P2027 0x2027
+#define SMT_P2028 0x2028
+#define SMT_P2029 0x2029
+#define SMT_P202A 0x202a
+#define SMT_P202B 0x202b
+#define SMT_P202C 0x202c
+#define SMT_P202D 0x202d
+#define SMT_P202E 0x202e
+#define SMT_P202F 0x202f
+#define SMT_P2030 0x2030
+#define SMT_P2031 0x2031
+#define SMT_P2032 0x2032
+#define SMT_P2033 0x2033
+#define SMT_P2034 0x2034
+#define SMT_P2035 0x2035
+#define SMT_P2036 0x2036
+#define SMT_P2037 0x2037
+#define SMT_P2038 0x2038
+#define SMT_P2039 0x2039
+#define SMT_P203A 0x203a
+#define SMT_P203B 0x203b
+#define SMT_P203C 0x203c
+#define SMT_P203D 0x203d
+#define SMT_P203E 0x203e
+#define SMT_P203F 0x203f
+#define SMT_P2040 0x2040
+#define SMT_P2041 0x2041
+#define SMT_P2042 0x2042
+#define SMT_P2043 0x2043
+#define SMT_P2044 0x2044
+#define SMT_P2045 0x2045
+#define SMT_P2046 0x2046
+#define SMT_P2047 0x2047
+#define SMT_P2048 0x2048
+#define SMT_P2049 0x2049
+#define SMT_P204A 0x204a
+#define SMT_P204B 0x204b
+#define SMT_P204C 0x204c
+#define SMT_P204D 0x204d
+#define SMT_P204E 0x204e
+#define SMT_P204F 0x204f
+#define SMT_P2050 0x2050
+#define SMT_P2051 0x2051
+#define SMT_P2052 0x2052
+#define SMT_P2053 0x2053
+#define SMT_P2054 0x2054
+#define SMT_P2055 0x2055
+#define SMT_P2056 0x2056
+#define SMT_P2057 0x2057
+#define SMT_P2058 0x2058
+#define SMT_P2059 0x2059
+#define SMT_P205A 0x205a
+#define SMT_P205B 0x205b
+#define SMT_P205C 0x205c
+#define SMT_P205D 0x205d
+#define SMT_P205E 0x205e
+#define SMT_P205F 0x205f
+#define SMT_P2060 0x2060
+#define SMT_P2061 0x2061
+#define SMT_P2062 0x2062
+#define SMT_P2063 0x2063
+#define SMT_P2064 0x2064
+#define SMT_P2065 0x2065
+#define SMT_P2066 0x2066
+#define SMT_P2067 0x2067
+#define SMT_P2068 0x2068
+#define SMT_P2069 0x2069
+#define SMT_P206A 0x206a
+#define SMT_P206B 0x206b
+#define SMT_P206C 0x206c
+#define SMT_P206D 0x206d
+#define SMT_P206E 0x206e
+#define SMT_P206F 0x206f
+#define SMT_P2070 0x2070
+#define SMT_P2071 0x2071
+#define SMT_P2072 0x2072
+#define SMT_P2073 0x2073
+#define SMT_P2074 0x2074
+#define SMT_P2075 0x2075
+#define SMT_P2076 0x2076
+
+#define SMT_P208C 0x208c
+#define SMT_P208D 0x208d
+#define SMT_P208E 0x208e
+#define SMT_P208F 0x208f
+#define SMT_P2090 0x2090
+
+#define SMT_P20F0 0x20F0
+#define SMT_P20F1 0x20F1
+
+#define SMT_P320A 0x320a
+#define SMT_P320B 0x320b
+#define SMT_P320C 0x320c
+#define SMT_P320D 0x320d
+#define SMT_P320E 0x320e
+#define SMT_P320F 0x320f
+#define SMT_P3210 0x3210
+#define SMT_P3211 0x3211
+#define SMT_P3212 0x3212
+#define SMT_P3213 0x3213
+#define SMT_P3214 0x3214
+#define SMT_P3215 0x3215
+#define SMT_P3216 0x3216
+#define SMT_P3217 0x3217
+
+#define SMT_P400A 0x400a
+#define SMT_P400B 0x400b
+#define SMT_P400C 0x400c
+#define SMT_P400D 0x400d
+#define SMT_P400E 0x400e
+#define SMT_P400F 0x400f
+#define SMT_P4010 0x4010
+#define SMT_P4011 0x4011
+#define SMT_P4012 0x4012
+#define SMT_P4013 0x4013
+#define SMT_P4014 0x4014
+#define SMT_P4015 0x4015
+#define SMT_P4016 0x4016
+#define SMT_P4017 0x4017
+#define SMT_P4018 0x4018
+#define SMT_P4019 0x4019
+#define SMT_P401A 0x401a
+#define SMT_P401B 0x401b
+#define SMT_P401C 0x401c
+#define SMT_P401D 0x401d
+#define SMT_P401E 0x401e
+#define SMT_P401F 0x401f
+#define SMT_P4020 0x4020
+#define SMT_P4021 0x4021
+#define SMT_P4022 0x4022
+#define SMT_P4023 0x4023
+#define SMT_P4024 0x4024
+#define SMT_P4025 0x4025
+#define SMT_P4026 0x4026
+#define SMT_P4027 0x4027
+#define SMT_P4028 0x4028
+#define SMT_P4029 0x4029
+#define SMT_P402A 0x402a
+#define SMT_P402B 0x402b
+#define SMT_P402C 0x402c
+#define SMT_P402D 0x402d
+#define SMT_P402E 0x402e
+#define SMT_P402F 0x402f
+#define SMT_P4030 0x4030
+#define SMT_P4031 0x4031
+#define SMT_P4032 0x4032
+#define SMT_P4033 0x4033
+#define SMT_P4034 0x4034
+#define SMT_P4035 0x4035
+#define SMT_P4036 0x4036
+#define SMT_P4037 0x4037
+#define SMT_P4038 0x4038
+#define SMT_P4039 0x4039
+#define SMT_P403A 0x403a
+#define SMT_P403B 0x403b
+#define SMT_P403C 0x403c
+#define SMT_P403D 0x403d
+#define SMT_P403E 0x403e
+#define SMT_P403F 0x403f
+#define SMT_P4040 0x4040
+#define SMT_P4041 0x4041
+#define SMT_P4042 0x4042
+#define SMT_P4043 0x4043
+#define SMT_P4044 0x4044
+#define SMT_P4045 0x4045
+#define SMT_P4046 0x4046
+
+#define SMT_P4050 0x4050
+#define SMT_P4051 0x4051
+#define SMT_P4052 0x4052
+#define SMT_P4053 0x4053
diff --git a/drivers/net/skfp/h/smtstate.h b/drivers/net/skfp/h/smtstate.h
new file mode 100644
index 000000000..689fa25dc
--- /dev/null
+++ b/drivers/net/skfp/h/smtstate.h
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SMT state definitions
+ */
+
+#ifndef KERNEL
+/*
+ * PCM states
+ */
+#define PC0_OFF 0
+#define PC1_BREAK 1
+#define PC2_TRACE 2
+#define PC3_CONNECT 3
+#define PC4_NEXT 4
+#define PC5_SIGNAL 5
+#define PC6_JOIN 6
+#define PC7_VERIFY 7
+#define PC8_ACTIVE 8
+#define PC9_MAINT 9
+
+/*
+ * PCM modes
+ */
+#define PM_NONE 0
+#define PM_PEER 1
+#define PM_TREE 2
+
+/*
+ * PCM type
+ */
+#define TA 0
+#define TB 1
+#define TS 2
+#define TM 3
+#define TNONE 4
+
+/*
+ * CFM states
+ */
+#define SC0_ISOLATED 0 /* isolated */
+#define SC1_WRAP_A 5 /* wrap A */
+#define SC2_WRAP_B 6 /* wrap B */
+#define SC4_THRU_A 12 /* through A */
+#define SC5_THRU_B 7 /* through B (SMt 6.2) */
+#define SC7_WRAP_S 8 /* SAS */
+
+/*
+ * ECM states
+ */
+#define EC0_OUT 0
+#define EC1_IN 1
+#define EC2_TRACE 2
+#define EC3_LEAVE 3
+#define EC4_PATH_TEST 4
+#define EC5_INSERT 5
+#define EC6_CHECK 6
+#define EC7_DEINSERT 7
+
+/*
+ * RMT states
+ */
+#define RM0_ISOLATED 0
+#define RM1_NON_OP 1 /* not operational */
+#define RM2_RING_OP 2 /* ring operational */
+#define RM3_DETECT 3 /* detect dupl addresses */
+#define RM4_NON_OP_DUP 4 /* dupl. addr detected */
+#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */
+#define RM6_DIRECTED 6 /* sending directed beacons */
+#define RM7_TRACE 7 /* trace initiated */
+#endif
+
+struct pcm_state {
+ unsigned char pcm_type ; /* TA TB TS TM */
+ unsigned char pcm_state ; /* state PC[0-9]_* */
+ unsigned char pcm_mode ; /* PM_{NONE,PEER,TREE} */
+ unsigned char pcm_neighbor ; /* TA TB TS TM */
+ unsigned char pcm_bsf ; /* flag bs : TRUE/FALSE */
+ unsigned char pcm_lsf ; /* flag ls : TRUE/FALSE */
+ unsigned char pcm_lct_fail ; /* counter lct_fail */
+ unsigned char pcm_ls_rx ; /* rx line state */
+ short pcm_r_val ; /* signaling bits */
+ short pcm_t_val ; /* signaling bits */
+} ;
+
+struct smt_state {
+ struct pcm_state pcm_state[NUMPHYS] ; /* port A & port B */
+} ;
diff --git a/drivers/net/skfp/h/supern_2.h b/drivers/net/skfp/h/supern_2.h
new file mode 100644
index 000000000..ea564b337
--- /dev/null
+++ b/drivers/net/skfp/h/supern_2.h
@@ -0,0 +1,1059 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ defines for AMD Supernet II chip set
+ the chips are refered to as
+ FPLUS Formac Plus
+ PLC Physical Layer
+
+ added defines for AMD Supernet III chip set
+ added comments on differences between Supernet II and Supernet III
+ added defines for the Motorola ELM (MOT_ELM)
+*/
+
+#ifndef _SUPERNET_
+#define _SUPERNET_
+
+/*
+ * Define Supernet 3 when used
+ */
+#ifdef PCI
+#ifndef SUPERNET_3
+#define SUPERNET_3
+#endif
+#define TAG
+#endif
+
+#define MB 0xff
+#define MW 0xffff
+#define MD 0xffffffff
+
+/*
+ * FORMAC frame status (rx_msext)
+ */
+#define FS_EI (1<<2)
+#define FS_AI (1<<1)
+#define FS_CI (1<<0)
+
+#define FS_MSVALID (1<<15) /* end of queue */
+#define FS_MSRABT (1<<14) /* frame was aborted during reception*/
+#define FS_SSRCRTG (1<<12) /* if SA has set MSB (source-routing)*/
+#define FS_SEAC2 (FS_EI<<9) /* error indicator */
+#define FS_SEAC1 (FS_AI<<9) /* address indicator */
+#define FS_SEAC0 (FS_CI<<9) /* copy indicator */
+#define FS_SFRMERR (1<<8) /* error detected (CRC or length) */
+#define FS_SADRRG (1<<7) /* address recognized */
+#define FS_SFRMTY2 (1<<6) /* frame-class bit */
+#define FS_SFRMTY1 (1<<5) /* frame-type bit (impementor) */
+#define FS_SFRMTY0 (1<<4) /* frame-type bit (LLC) */
+#define FS_ERFBB1 (1<<1) /* byte offset (depends on LSB bit) */
+#define FS_ERFBB0 (1<<0) /* - " - */
+
+/*
+ * status frame type
+ */
+#define FRM_SMT (0) /* asynchr. frames */
+#define FRM_LLCA (1)
+#define FRM_IMPA (2)
+#define FRM_MAC (4) /* synchr. frames */
+#define FRM_LLCS (5)
+#define FRM_IMPS (6)
+
+/*
+ * bits in rx_descr.i (receive frame status word)
+ */
+#define RX_MSVALID ((long)1<<31) /* memory status valid */
+#define RX_MSRABT ((long)1<<30) /* memory status receive abort */
+#define RX_FS_E ((long)FS_SEAC2<<16) /* error indicator */
+#define RX_FS_A ((long)FS_SEAC1<<16) /* address indicator */
+#define RX_FS_C ((long)FS_SEAC0<<16) /* copy indicator */
+#define RX_FS_CRC ((long)FS_SFRMERR<<16)/* error detected */
+#define RX_FS_ADDRESS ((long)FS_SADRRG<<16) /* address recognized */
+#define RX_FS_MAC ((long)FS_SFRMTY2<<16)/* MAC frame */
+#define RX_FS_SMT ((long)0<<16) /* SMT frame */
+#define RX_FS_IMPL ((long)FS_SFRMTY1<<16)/* implementer frame */
+#define RX_FS_LLC ((long)FS_SFRMTY0<<16)/* LLC frame */
+
+/*
+ * receive frame descriptor
+ */
+union rx_descr {
+ struct {
+#ifdef LITTLE_ENDIAN
+ unsigned rx_length :16 ; /* frame length lower/upper byte */
+ unsigned rx_erfbb :2 ; /* received frame byte boundary */
+ unsigned rx_reserv2:2 ; /* reserved */
+ unsigned rx_sfrmty :3 ; /* frame type bits */
+ unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */
+ unsigned rx_sfrmerr:1 ; /* received frame not valid */
+ unsigned rx_seac0 :1 ; /* frame-copied C-indicator */
+ unsigned rx_seac1 :1 ; /* address-match A-indicator */
+ unsigned rx_seac2 :1 ; /* frame-error E-indicator */
+ unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */
+ unsigned rx_reserv1:1 ; /* reserved */
+ unsigned rx_msrabt :1 ; /* memory status receive abort */
+ unsigned rx_msvalid:1 ; /* memory status valid */
+#else
+ unsigned rx_msvalid:1 ; /* memory status valid */
+ unsigned rx_msrabt :1 ; /* memory status receive abort */
+ unsigned rx_reserv1:1 ; /* reserved */
+ unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */
+ unsigned rx_seac2 :1 ; /* frame-error E-indicator */
+ unsigned rx_seac1 :1 ; /* address-match A-indicator */
+ unsigned rx_seac0 :1 ; /* frame-copied C-indicator */
+ unsigned rx_sfrmerr:1 ; /* received frame not valid */
+ unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */
+ unsigned rx_sfrmty :3 ; /* frame type bits */
+ unsigned rx_erfbb :2 ; /* received frame byte boundary */
+ unsigned rx_reserv2:2 ; /* reserved */
+ unsigned rx_length :16 ; /* frame length lower/upper byte */
+#endif
+ } r ;
+ long i ;
+} ;
+
+/* defines for Receive Frame Descriptor access */
+#define RD_S_ERFBB 0x00030000L /* received frame byte boundary */
+#define RD_S_RES2 0x000c0000L /* reserved */
+#define RD_S_SFRMTY 0x00700000L /* frame type bits */
+#define RD_S_SADRRG 0x00800000L /* DA == MA or broad-/multicast */
+#define RD_S_SFRMERR 0x01000000L /* received frame not valid */
+#define RD_S_SEAC 0x0e000000L /* frame status indicators */
+#define RD_S_SEAC0 0x02000000L /* frame-copied case-indicator */
+#define RD_S_SEAC1 0x04000000L /* address-match A-indicator */
+#define RD_S_SEAC2 0x08000000L /* frame-error E-indicator */
+#define RD_S_SSRCRTG 0x10000000L /* == 1 SA has MSB set */
+#define RD_S_RES1 0x20000000L /* reserved */
+#define RD_S_MSRABT 0x40000000L /* memory status receive abort */
+#define RD_S_MSVALID 0x80000000L /* memory status valid */
+
+#define RD_STATUS 0xffff0000L
+#define RD_LENGTH 0x0000ffffL
+
+/* defines for Receive Frames Status Word values */
+/*RD_S_SFRMTY*/
+#define RD_FRM_SMT (unsigned long)(0<<20) /* asynchr. frames */
+#define RD_FRM_LLCA (unsigned long)(1<<20)
+#define RD_FRM_IMPA (unsigned long)(2<<20)
+#define RD_FRM_MAC (unsigned long)(4<<20) /* synchr. frames */
+#define RD_FRM_LLCS (unsigned long)(5<<20)
+#define RD_FRM_IMPS (unsigned long)(6<<20)
+
+#define TX_DESCRIPTOR 0x40000000L
+#define TX_OFFSET_3 0x18000000L
+
+#define TXP1 2
+
+/*
+ * transmit frame descriptor
+ */
+union tx_descr {
+ struct {
+#ifdef LITTLE_ENDIAN
+ unsigned tx_length:16 ; /* frame length lower/upper byte */
+ unsigned tx_res :8 ; /* reserved (bit 16..23) */
+ unsigned tx_xmtabt:1 ; /* transmit abort */
+ unsigned tx_nfcs :1 ; /* no frame check sequence */
+ unsigned tx_xdone :1 ; /* give up token */
+ unsigned tx_rpxm :2 ; /* byte offset */
+ unsigned tx_pat1 :2 ; /* must be TXP1 */
+ unsigned tx_more :1 ; /* more frame in chain */
+#else
+ unsigned tx_more :1 ; /* more frame in chain */
+ unsigned tx_pat1 :2 ; /* must be TXP1 */
+ unsigned tx_rpxm :2 ; /* byte offset */
+ unsigned tx_xdone :1 ; /* give up token */
+ unsigned tx_nfcs :1 ; /* no frame check sequence */
+ unsigned tx_xmtabt:1 ; /* transmit abort */
+ unsigned tx_res :8 ; /* reserved (bit 16..23) */
+ unsigned tx_length:16 ; /* frame length lower/upper byte */
+#endif
+ } t ;
+ long i ;
+} ;
+
+/* defines for Transmit Descriptor access */
+#define TD_C_MORE 0x80000000L /* more frame in chain */
+#define TD_C_DESCR 0x60000000L /* must be TXP1 */
+#define TD_C_TXFBB 0x18000000L /* byte offset */
+#define TD_C_XDONE 0x04000000L /* give up token */
+#define TD_C_NFCS 0x02000000L /* no frame check sequence */
+#define TD_C_XMTABT 0x01000000L /* transmit abort */
+
+#define TD_C_LNCNU 0x0000ff00L
+#define TD_C_LNCNL 0x000000ffL
+#define TD_C_LNCN 0x0000ffffL /* frame length lower/upper byte */
+
+/*
+ * transmit pointer
+ */
+union tx_pointer {
+ struct t {
+#ifdef LITTLE_ENDIAN
+ unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */
+ unsigned tp_res :8 ; /* reserved (bit 16..23) */
+ unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */
+#else
+ unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */
+ unsigned tp_res :8 ; /* reserved (bit 16..23) */
+ unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */
+#endif
+ } t ;
+ long i ;
+} ;
+
+/* defines for Nontag Mode Pointer access */
+#define TD_P_CNTRL 0xff000000L
+#define TD_P_RPXU 0x0000ff00L
+#define TD_P_RPXL 0x000000ffL
+#define TD_P_RPX 0x0000ffffL
+
+
+#define TX_PATTERN 0xa0
+#define TX_POINTER_END 0xa0000000L
+#define TX_INT_PATTERN 0xa0000000L
+
+struct tx_queue {
+ struct tx_queue *tq_next ;
+ u_short tq_pack_offset ; /* offset buffer memory */
+ u_char tq_pad[2] ;
+} ;
+
+/*
+ defines for FORMAC Plus (Am79C830)
+*/
+
+/*
+ * FORMAC+ read/write (r/w) registers
+ */
+#define FM_CMDREG1 0x00 /* write command reg 1 instruction */
+#define FM_CMDREG2 0x01 /* write command reg 2 instruction */
+#define FM_ST1U 0x00 /* read upper 16-bit of status reg 1 */
+#define FM_ST1L 0x01 /* read lower 16-bit of status reg 1 */
+#define FM_ST2U 0x02 /* read upper 16-bit of status reg 2 */
+#define FM_ST2L 0x03 /* read lower 16-bit of status reg 2 */
+#define FM_IMSK1U 0x04 /* r/w upper 16-bit of IMSK 1 */
+#define FM_IMSK1L 0x05 /* r/w lower 16-bit of IMSK 1 */
+#define FM_IMSK2U 0x06 /* r/w upper 16-bit of IMSK 2 */
+#define FM_IMSK2L 0x07 /* r/w lower 16-bit of IMSK 2 */
+#define FM_SAID 0x08 /* r/w short addr.-individual */
+#define FM_LAIM 0x09 /* r/w long addr.-ind. (MSW of LAID) */
+#define FM_LAIC 0x0a /* r/w long addr.-ind. (middle)*/
+#define FM_LAIL 0x0b /* r/w long addr.-ind. (LSW) */
+#define FM_SAGP 0x0c /* r/w short address-group */
+#define FM_LAGM 0x0d /* r/w long addr.-gr. (MSW of LAGP) */
+#define FM_LAGC 0x0e /* r/w long addr.-gr. (middle) */
+#define FM_LAGL 0x0f /* r/w long addr.-gr. (LSW) */
+#define FM_MDREG1 0x10 /* r/w 16-bit mode reg 1 */
+#define FM_STMCHN 0x11 /* read state-machine reg */
+#define FM_MIR1 0x12 /* read upper 16-bit of MAC Info Reg */
+#define FM_MIR0 0x13 /* read lower 16-bit of MAC Info Reg */
+#define FM_TMAX 0x14 /* r/w 16-bit TMAX reg */
+#define FM_TVX 0x15 /* write 8-bit TVX reg with NP7-0
+ read TVX on NP7-0, timer on NP15-8*/
+#define FM_TRT 0x16 /* r/w upper 16-bit of TRT timer */
+#define FM_THT 0x17 /* r/w upper 16-bit of THT timer */
+#define FM_TNEG 0x18 /* read upper 16-bit of TNEG (TTRT) */
+#define FM_TMRS 0x19 /* read lower 5-bit of TNEG,TRT,THT */
+ /* F E D C B A 9 8 7 6 5 4 3 2 1 0
+ x |-TNEG4-0| |-TRT4-0-| |-THT4-0-| (x-late count) */
+#define FM_TREQ0 0x1a /* r/w 16-bit TREQ0 reg (LSW of TRT) */
+#define FM_TREQ1 0x1b /* r/w 16-bit TREQ1 reg (MSW of TRT) */
+#define FM_PRI0 0x1c /* r/w priority r. for asyn.-queue 0 */
+#define FM_PRI1 0x1d /* r/w priority r. for asyn.-queue 1 */
+#define FM_PRI2 0x1e /* r/w priority r. for asyn.-queue 2 */
+#define FM_TSYNC 0x1f /* r/w 16-bit of the TSYNC register */
+#define FM_MDREG2 0x20 /* r/w 16-bit mode reg 2 */
+#define FM_FRMTHR 0x21 /* r/w the frame threshold register */
+#define FM_EACB 0x22 /* r/w end addr of claim/beacon area */
+#define FM_EARV 0x23 /* r/w end addr of receive queue */
+/* Supernet 3 */
+#define FM_EARV1 FM_EARV
+
+#define FM_EAS 0x24 /* r/w end addr of synchr. queue */
+#define FM_EAA0 0x25 /* r/w end addr of asyn. queue 0 */
+#define FM_EAA1 0x26 /* r/w end addr of asyn. queue 1 */
+#define FM_EAA2 0x27 /* r/w end addr of asyn. queue 2 */
+#define FM_SACL 0x28 /* r/w start addr of claim frame */
+#define FM_SABC 0x29 /* r/w start addr of beacon frame */
+#define FM_WPXSF 0x2a /* r/w the write ptr. for special fr.*/
+#define FM_RPXSF 0x2b /* r/w the read ptr. for special fr. */
+#define FM_RPR 0x2d /* r/w the read ptr. for receive qu. */
+#define FM_WPR 0x2e /* r/w the write ptr. for receive qu.*/
+#define FM_SWPR 0x2f /* r/w the shadow wr.-ptr. for rec.q.*/
+/* Supernet 3 */
+#define FM_RPR1 FM_RPR
+#define FM_WPR1 FM_WPR
+#define FM_SWPR1 FM_SWPR
+
+#define FM_WPXS 0x30 /* r/w the write ptr. for synchr. qu.*/
+#define FM_WPXA0 0x31 /* r/w the write ptr. for asyn. qu.0 */
+#define FM_WPXA1 0x32 /* r/w the write ptr. for asyn. qu.1 */
+#define FM_WPXA2 0x33 /* r/w the write ptr. for asyn. qu.2 */
+#define FM_SWPXS 0x34 /* r/w the shadow wr.-ptr. for syn.q.*/
+#define FM_SWPXA0 0x35 /* r/w the shad. wr.-ptr. for asyn.q0*/
+#define FM_SWPXA1 0x36 /* r/w the shad. wr.-ptr. for asyn.q1*/
+#define FM_SWPXA2 0x37 /* r/w the shad. wr.-ptr. for asyn.q2*/
+#define FM_RPXS 0x38 /* r/w the read ptr. for synchr. qu. */
+#define FM_RPXA0 0x39 /* r/w the read ptr. for asyn. qu. 0 */
+#define FM_RPXA1 0x3a /* r/w the read ptr. for asyn. qu. 1 */
+#define FM_RPXA2 0x3b /* r/w the read ptr. for asyn. qu. 2 */
+#define FM_MARR 0x3c /* r/w the memory read addr register */
+#define FM_MARW 0x3d /* r/w the memory write addr register*/
+#define FM_MDRU 0x3e /* r/w upper 16-bit of mem. data reg */
+#define FM_MDRL 0x3f /* r/w lower 16-bit of mem. data reg */
+
+/* following instructions relate to MAC counters and timer */
+#define FM_TMSYNC 0x40 /* r/w upper 16 bits of TMSYNC timer */
+#define FM_FCNTR 0x41 /* r/w the 16-bit frame counter */
+#define FM_LCNTR 0x42 /* r/w the 16-bit lost counter */
+#define FM_ECNTR 0x43 /* r/w the 16-bit error counter */
+
+/* Supernet 3: extensions to old register block */
+#define FM_FSCNTR 0x44 /* r/? Frame Strip Counter */
+#define FM_FRSELREG 0x45 /* r/w Frame Selection Register */
+
+/* Supernet 3: extensions for 2. receive queue etc. */
+#define FM_MDREG3 0x60 /* r/w Mode Register 3 */
+#define FM_ST3U 0x61 /* read upper 16-bit of status reg 3 */
+#define FM_ST3L 0x62 /* read lower 16-bit of status reg 3 */
+#define FM_IMSK3U 0x63 /* r/w upper 16-bit of IMSK reg 3 */
+#define FM_IMSK3L 0x64 /* r/w lower 16-bit of IMSK reg 3 */
+#define FM_IVR 0x65 /* read Interrupt Vector register */
+#define FM_IMR 0x66 /* r/w Interrupt mask register */
+/* 0x67 Hidden */
+#define FM_RPR2 0x68 /* r/w the read ptr. for rec. qu. 2 */
+#define FM_WPR2 0x69 /* r/w the write ptr. for rec. qu. 2 */
+#define FM_SWPR2 0x6a /* r/w the shadow wptr. for rec. q. 2 */
+#define FM_EARV2 0x6b /* r/w end addr of rec. qu. 2 */
+#define FM_UNLCKDLY 0x6c /* r/w Auto Unlock Delay register */
+ /* Bit 15-8: RECV2 unlock threshold */
+ /* Bit 7-0: RECV1 unlock threshold */
+/* 0x6f-0x73 Hidden */
+#define FM_LTDPA1 0x79 /* r/w Last Trans desc ptr for A1 qu. */
+/* 0x80-0x9a PLCS registers of built-in PLCS (Supernet 3 only) */
+
+/* Supernet 3: Adderss Filter Registers */
+#define FM_AFCMD 0xb0 /* r/w Address Filter Command Reg */
+#define FM_AFSTAT 0xb2 /* r/w Address Filter Status Reg */
+#define FM_AFBIST 0xb4 /* r/w Address Filter BIST signature */
+#define FM_AFCOMP2 0xb6 /* r/w Address Filter Comparand 2 */
+#define FM_AFCOMP1 0xb8 /* r/w Address Filter Comparand 1 */
+#define FM_AFCOMP0 0xba /* r/w Address Filter Comparand 0 */
+#define FM_AFMASK2 0xbc /* r/w Address Filter Mask 2 */
+#define FM_AFMASK1 0xbe /* r/w Address Filter Mask 1 */
+#define FM_AFMASK0 0xc0 /* r/w Address Filter Mask 0 */
+#define FM_AFPERS 0xc2 /* r/w Address Filter Personality Reg */
+
+/* Supernet 3: Orion (PDX?) Registers */
+#define FM_ORBIST 0xd0 /* r/w Orion BIST signature */
+#define FM_ORSTAT 0xd2 /* r/w Orion Status Register */
+
+
+/*
+ * Mode Register 1 (MDREG1)
+ */
+#define FM_RES0 0x0001 /* reserved */
+ /* SN3: other definition */
+#define FM_XMTINH_HOLD 0x0002 /* transmit-inhibit/hold bit */
+ /* SN3: other definition */
+#define FM_HOFLXI 0x0003 /* SN3: Hold / Flush / Inhibit */
+#define FM_FULL_HALF 0x0004 /* full-duplex/half-duplex bit */
+#define FM_LOCKTX 0x0008 /* lock-transmit-asynchr.-queues bit */
+#define FM_EXGPA0 0x0010 /* extended-group-addressing bit 0 */
+#define FM_EXGPA1 0x0020 /* extended-group-addressing bit 1 */
+#define FM_DISCRY 0x0040 /* disable-carry bit */
+ /* SN3: reserved */
+#define FM_SELRA 0x0080 /* select input from PHY (1=RA,0=RB) */
+
+#define FM_ADDET 0x0700 /* address detection */
+#define FM_MDAMA (0<<8) /* address detection : DA = MA */
+#define FM_MDASAMA (1<<8) /* address detection : DA=MA||SA=MA */
+#define FM_MRNNSAFNMA (2<<8) /* rec. non-NSA frames DA=MA&&SA!=MA */
+#define FM_MRNNSAF (3<<8) /* rec. non-NSA frames DA = MA */
+#define FM_MDISRCV (4<<8) /* disable receive function */
+#define FM_MRES0 (5<<8) /* reserve */
+#define FM_MLIMPROM (6<<8) /* limited-promiscuous mode */
+#define FM_MPROMISCOUS (7<<8) /* address detection : promiscous */
+
+#define FM_SELSA 0x0800 /* select-short-address bit */
+
+#define FM_MMODE 0x7000 /* mode select */
+#define FM_MINIT (0<<12) /* initialize */
+#define FM_MMEMACT (1<<12) /* memory activate */
+#define FM_MONLINESP (2<<12) /* on-line special */
+#define FM_MONLINE (3<<12) /* on-line (FDDI operational mode) */
+#define FM_MILOOP (4<<12) /* internal loopback */
+#define FM_MRES1 (5<<12) /* reserved */
+#define FM_MRES2 (6<<12) /* reserved */
+#define FM_MELOOP (7<<12) /* external loopback */
+
+#define FM_SNGLFRM 0x8000 /* single-frame-receive mode */
+ /* SN3: reserved */
+
+#define MDR1INIT (FM_MINIT | FM_MDAMA)
+
+/*
+ * Mode Register 2 (MDREG2)
+ */
+#define FM_AFULL 0x000f /* 4-bit value (empty loc.in txqueue)*/
+#define FM_RCVERR 0x0010 /* rec.-errored-frames bit */
+#define FM_SYMCTL 0x0020 /* sysmbol-control bit */
+ /* SN3: reserved */
+#define FM_SYNPRQ 0x0040 /* synchron.-NP-DMA-request bit */
+#define FM_ENNPRQ 0x0080 /* enable-NP-DMA-request bit */
+#define FM_ENHSRQ 0x0100 /* enable-host-request bit */
+#define FM_RXFBB01 0x0600 /* rec. frame byte boundary bit0 & 1 */
+#define FM_LSB 0x0800 /* determ. ordering of bytes in buffer*/
+#define FM_PARITY 0x1000 /* 1 = even, 0 = odd */
+#define FM_CHKPAR 0x2000 /* 1 = parity of 32-bit buffer BD-bus*/
+#define FM_STRPFCS 0x4000 /* 1 = strips FCS field of rec.frame */
+#define FM_BMMODE 0x8000 /* Buffer-Memory-Mode (1 = tag mode) */
+ /* SN3: 1 = tag, 0 = modified tag */
+
+/*
+ * Status Register 1, Upper 16 Bits (ST1U)
+ */
+#define FM_STEFRMS 0x0001 /* transmit end of frame: synchr. qu.*/
+#define FM_STEFRMA0 0x0002 /* transmit end of frame: asyn. qu.0 */
+#define FM_STEFRMA1 0x0004 /* transmit end of frame: asyn. qu.1 */
+#define FM_STEFRMA2 0x0008 /* transmit end of frame: asyn. qu.2 */
+ /* SN3: reserved */
+#define FM_STECFRMS 0x0010 /* transmit end of chain of syn. qu. */
+ /* SN3: reserved */
+#define FM_STECFRMA0 0x0020 /* transmit end of chain of asyn. q0 */
+ /* SN3: reserved */
+#define FM_STECFRMA1 0x0040 /* transmit end of chain of asyn. q1 */
+ /* SN3: STECMDA1 */
+#define FM_STECMDA1 0x0040 /* SN3: 'no description' */
+#define FM_STECFRMA2 0x0080 /* transmit end of chain of asyn. q2 */
+ /* SN3: reserved */
+#define FM_STEXDONS 0x0100 /* transmit until XDONE in syn. qu. */
+#define FM_STBFLA 0x0200 /* asynchr.-queue trans. buffer full */
+#define FM_STBFLS 0x0400 /* synchr.-queue transm. buffer full */
+#define FM_STXABRS 0x0800 /* synchr. queue transmit-abort */
+#define FM_STXABRA0 0x1000 /* asynchr. queue 0 transmit-abort */
+#define FM_STXABRA1 0x2000 /* asynchr. queue 1 transmit-abort */
+#define FM_STXABRA2 0x4000 /* asynchr. queue 2 transmit-abort */
+ /* SN3: reserved */
+#define FM_SXMTABT 0x8000 /* transmit abort */
+
+/*
+ * Status Register 1, Lower 16 Bits (ST1L)
+ */
+#define FM_SQLCKS 0x0001 /* queue lock for synchr. queue */
+#define FM_SQLCKA0 0x0002 /* queue lock for asynchr. queue 0 */
+#define FM_SQLCKA1 0x0004 /* queue lock for asynchr. queue 1 */
+#define FM_SQLCKA2 0x0008 /* queue lock for asynchr. queue 2 */
+ /* SN3: reserved */
+#define FM_STXINFLS 0x0010 /* transmit instruction full: syn. */
+ /* SN3: reserved */
+#define FM_STXINFLA0 0x0020 /* transmit instruction full: asyn.0 */
+ /* SN3: reserved */
+#define FM_STXINFLA1 0x0040 /* transmit instruction full: asyn.1 */
+ /* SN3: reserved */
+#define FM_STXINFLA2 0x0080 /* transmit instruction full: asyn.2 */
+ /* SN3: reserved */
+#define FM_SPCEPDS 0x0100 /* parity/coding error: syn. queue */
+#define FM_SPCEPDA0 0x0200 /* parity/coding error: asyn. queue0 */
+#define FM_SPCEPDA1 0x0400 /* parity/coding error: asyn. queue1 */
+#define FM_SPCEPDA2 0x0800 /* parity/coding error: asyn. queue2 */
+ /* SN3: reserved */
+#define FM_STBURS 0x1000 /* transmit buffer underrun: syn. q. */
+#define FM_STBURA0 0x2000 /* transmit buffer underrun: asyn.0 */
+#define FM_STBURA1 0x4000 /* transmit buffer underrun: asyn.1 */
+#define FM_STBURA2 0x8000 /* transmit buffer underrun: asyn.2 */
+ /* SN3: reserved */
+
+/*
+ * Status Register 2, Upper 16 Bits (ST2U)
+ */
+#define FM_SOTRBEC 0x0001 /* other beacon received */
+#define FM_SMYBEC 0x0002 /* my beacon received */
+#define FM_SBEC 0x0004 /* beacon state entered */
+#define FM_SLOCLM 0x0008 /* low claim received */
+#define FM_SHICLM 0x0010 /* high claim received */
+#define FM_SMYCLM 0x0020 /* my claim received */
+#define FM_SCLM 0x0040 /* claim state entered */
+#define FM_SERRSF 0x0080 /* error in special frame */
+#define FM_SNFSLD 0x0100 /* NP and FORMAC+ simultaneous load */
+#define FM_SRFRCTOV 0x0200 /* receive frame counter overflow */
+ /* SN3: reserved */
+#define FM_SRCVFRM 0x0400 /* receive frame */
+ /* SN3: reserved */
+#define FM_SRCVOVR 0x0800 /* receive FIFO overflow */
+#define FM_SRBFL 0x1000 /* receive buffer full */
+#define FM_SRABT 0x2000 /* receive abort */
+#define FM_SRBMT 0x4000 /* receive buffer empty */
+#define FM_SRCOMP 0x8000 /* receive complete. Nontag mode */
+
+/*
+ * Status Register 2, Lower 16 Bits (ST2L)
+ * Attention: SN3 docu shows these bits the other way around
+ */
+#define FM_SRES0 0x0001 /* reserved */
+#define FM_SESTRIPTK 0x0001 /* SN3: 'no description' */
+#define FM_STRTEXR 0x0002 /* TRT expired in claim | beacon st. */
+#define FM_SDUPCLM 0x0004 /* duplicate claim received */
+#define FM_SSIFG 0x0008 /* short interframe gap */
+#define FM_SFRMCTR 0x0010 /* frame counter overflow */
+#define FM_SERRCTR 0x0020 /* error counter overflow */
+#define FM_SLSTCTR 0x0040 /* lost counter overflow */
+#define FM_SPHINV 0x0080 /* PHY invalid */
+#define FM_SADET 0x0100 /* address detect */
+#define FM_SMISFRM 0x0200 /* missed frame */
+#define FM_STRTEXP 0x0400 /* TRT expired and late count > 0 */
+#define FM_STVXEXP 0x0800 /* TVX expired */
+#define FM_STKISS 0x1000 /* token issued */
+#define FM_STKERR 0x2000 /* token error */
+#define FM_SMULTDA 0x4000 /* multiple destination address */
+#define FM_SRNGOP 0x8000 /* ring operational */
+
+/*
+ * Supernet 3:
+ * Status Register 3, Upper 16 Bits (ST3U)
+ */
+#define FM_SRQUNLCK1 0x0001 /* receive queue unlocked queue 1 */
+#define FM_SRQUNLCK2 0x0002 /* receive queue unlocked queue 2 */
+#define FM_SRPERRQ1 0x0004 /* receive parity error rx queue 1 */
+#define FM_SRPERRQ2 0x0008 /* receive parity error rx queue 2 */
+ /* Bit 4-10: reserved */
+#define FM_SRCVOVR2 0x0800 /* receive FIFO overfull rx queue 2 */
+#define FM_SRBFL2 0x1000 /* receive buffer full rx queue 2 */
+#define FM_SRABT2 0x2000 /* receive abort rx queue 2 */
+#define FM_SRBMT2 0x4000 /* receive buf empty rx queue 2 */
+#define FM_SRCOMP2 0x8000 /* receive comp rx queue 2 */
+
+/*
+ * Supernet 3:
+ * Status Register 3, Lower 16 Bits (ST3L)
+ */
+#define FM_AF_BIST_DONE 0x0001 /* Address Filter BIST is done */
+#define FM_PLC_BIST_DONE 0x0002 /* internal PLC Bist is done */
+#define FM_PDX_BIST_DONE 0x0004 /* PDX BIST is done */
+ /* Bit 3: reserved */
+#define FM_SICAMDAMAT 0x0010 /* Status internal CAM DA match */
+#define FM_SICAMDAXACT 0x0020 /* Status internal CAM DA exact match */
+#define FM_SICAMSAMAT 0x0040 /* Status internal CAM SA match */
+#define FM_SICAMSAXACT 0x0080 /* Status internal CAM SA exact match */
+
+/*
+ * MAC State-Machine Register FM_STMCHN
+ */
+#define FM_MDRTAG 0x0004 /* tag bit of long word read */
+#define FM_SNPPND 0x0008 /* r/w from buffer mem. is pending */
+#define FM_TXSTAT 0x0070 /* transmitter state machine state */
+#define FM_RCSTAT 0x0380 /* receiver state machine state */
+#define FM_TM01 0x0c00 /* indicate token mode */
+#define FM_SIM 0x1000 /* indicate send immediate-mode */
+#define FM_REV 0xe000 /* FORMAC Plus revision number */
+
+/*
+ * Supernet 3
+ * Mode Register 3
+ */
+#define FM_MENRS 0x0001 /* Ena enhanced rec status encoding */
+#define FM_MENXS 0x0002 /* Ena enhanced xmit status encoding */
+#define FM_MENXCT 0x0004 /* Ena EXACT/INEXACT matching */
+#define FM_MENAFULL 0x0008 /* Ena enh QCTRL encoding for AFULL */
+#define FM_MEIND 0x0030 /* Ena enh A,C indicator settings */
+#define FM_MENQCTRL 0x0040 /* Ena enh QCTRL encoding */
+#define FM_MENRQAUNLCK 0x0080 /* Ena rec q auto unlock */
+#define FM_MENDAS 0x0100 /* Ena DAS connections by cntr MUX */
+#define FM_MENPLCCST 0x0200 /* Ena Counter Segm test in PLC blck */
+#define FM_MENSGLINT 0x0400 /* Ena Vectored Interrupt reading */
+#define FM_MENDRCV 0x0800 /* Ena dual receive queue operation */
+#define FM_MENFCLOC 0x3000 /* Ena FC location within frm data */
+#define FM_MENTRCMD 0x4000 /* Ena ASYNC1 xmit only after command */
+#define FM_MENTDLPBK 0x8000 /* Ena TDAT to RDAT lkoopback */
+
+/*
+ * Supernet 3
+ * Frame Selection Register
+ */
+#define FM_RECV1 0x000f /* options for receive queue 1 */
+#define FM_RCV1_ALL (0<<0) /* receive all frames */
+#define FM_RCV1_LLC (1<<0) /* rec all LLC frames */
+#define FM_RCV1_SMT (2<<0) /* rec all SMT frames */
+#define FM_RCV1_NSMT (3<<0) /* rec non-SMT frames */
+#define FM_RCV1_IMP (4<<0) /* rec Implementor frames */
+#define FM_RCV1_MAC (5<<0) /* rec all MAC frames */
+#define FM_RCV1_SLLC (6<<0) /* rec all sync LLC frames */
+#define FM_RCV1_ALLC (7<<0) /* rec all async LLC frames */
+#define FM_RCV1_VOID (8<<0) /* rec all void frames */
+#define FM_RCV1_ALSMT (9<<0) /* rec all async LLC & SMT frames */
+#define FM_RECV2 0x00f0 /* options for receive queue 2 */
+#define FM_RCV2_ALL (0<<4) /* receive all other frames */
+#define FM_RCV2_LLC (1<<4) /* rec all LLC frames */
+#define FM_RCV2_SMT (2<<4) /* rec all SMT frames */
+#define FM_RCV2_NSMT (3<<4) /* rec non-SMT frames */
+#define FM_RCV2_IMP (4<<4) /* rec Implementor frames */
+#define FM_RCV2_MAC (5<<4) /* rec all MAC frames */
+#define FM_RCV2_SLLC (6<<4) /* rec all sync LLC frames */
+#define FM_RCV2_ALLC (7<<4) /* rec all async LLC frames */
+#define FM_RCV2_VOID (8<<4) /* rec all void frames */
+#define FM_RCV2_ALSMT (9<<4) /* rec all async LLC & SMT frames */
+#define FM_ENXMTADSWAP 0x4000 /* enh rec addr swap (phys -> can) */
+#define FM_ENRCVADSWAP 0x8000 /* enh tx addr swap (can -> phys) */
+
+/*
+ * Supernet 3:
+ * Address Filter Command Register (AFCMD)
+ */
+#define FM_INST 0x0007 /* Address Filter Operation */
+#define FM_IINV_CAM (0<<0) /* Invalidate CAM */
+#define FM_IWRITE_CAM (1<<0) /* Write CAM */
+#define FM_IREAD_CAM (2<<0) /* Read CAM */
+#define FM_IRUN_BIST (3<<0) /* Run BIST */
+#define FM_IFIND (4<<0) /* Find */
+#define FM_IINV (5<<0) /* Invalidate */
+#define FM_ISKIP (6<<0) /* Skip */
+#define FM_ICL_SKIP (7<<0) /* Clear all SKIP bits */
+
+/*
+ * Supernet 3:
+ * Address Filter Status Register (AFSTAT)
+ */
+ /* Bit 0-4: reserved */
+#define FM_REV_NO 0x00e0 /* Revision Number of Address Filter */
+#define FM_BIST_DONE 0x0100 /* BIST complete */
+#define FM_EMPTY 0x0200 /* CAM empty */
+#define FM_ERROR 0x0400 /* Error (improper operation) */
+#define FM_MULT 0x0800 /* Multiple Match */
+#define FM_EXACT 0x1000 /* Exact Match */
+#define FM_FOUND 0x2000 /* Comparand found in CAM */
+#define FM_FULL 0x4000 /* CAM full */
+#define FM_DONE 0x8000 /* DONE indicator */
+
+/*
+ * Supernet 3:
+ * BIST Signature Register (AFBIST)
+ */
+#define AF_BIST_SIGNAT 0x0553 /* Address Filter BIST Signature */
+
+/*
+ * Supernet 3:
+ * Personality Register (AFPERS)
+ */
+#define FM_VALID 0x0001 /* CAM Entry Valid */
+#define FM_DA 0x0002 /* Destination Address */
+#define FM_DAX 0x0004 /* Destination Address Exact */
+#define FM_SA 0x0008 /* Source Address */
+#define FM_SAX 0x0010 /* Source Address Exact */
+#define FM_SKIP 0x0020 /* Skip this entry */
+
+/*
+ * instruction set for command register 1 (NPADDR6-0 = 0x00)
+ */
+#define FM_IRESET 0x01 /* software reset */
+#define FM_IRMEMWI 0x02 /* load Memory Data Reg., inc MARR */
+#define FM_IRMEMWO 0x03 /* load MDR from buffer memory, n.i. */
+#define FM_IIL 0x04 /* idle/listen */
+#define FM_ICL 0x05 /* claim/listen */
+#define FM_IBL 0x06 /* beacon/listen */
+#define FM_ILTVX 0x07 /* load TVX timer from TVX reg */
+#define FM_INRTM 0x08 /* nonrestricted token mode */
+#define FM_IENTM 0x09 /* enter nonrestricted token mode */
+#define FM_IERTM 0x0a /* enter restricted token mode */
+#define FM_IRTM 0x0b /* restricted token mode */
+#define FM_ISURT 0x0c /* send unrestricted token */
+#define FM_ISRT 0x0d /* send restricted token */
+#define FM_ISIM 0x0e /* enter send-immediate mode */
+#define FM_IESIM 0x0f /* exit send-immediate mode */
+#define FM_ICLLS 0x11 /* clear synchronous queue lock */
+#define FM_ICLLA0 0x12 /* clear asynchronous queue 0 lock */
+#define FM_ICLLA1 0x14 /* clear asynchronous queue 1 lock */
+#define FM_ICLLA2 0x18 /* clear asynchronous queue 2 lock */
+ /* SN3: reserved */
+#define FM_ICLLR 0x20 /* clear receive queue (SN3:1) lock */
+#define FM_ICLLR2 0x21 /* SN3: clear receive queue 2 lock */
+#define FM_ITRXBUS 0x22 /* SN3: Tristate X-Bus (SAS only) */
+#define FM_IDRXBUS 0x23 /* SN3: drive X-Bus */
+#define FM_ICLLAL 0x3f /* clear all queue locks */
+
+/*
+ * instruction set for command register 2 (NPADDR6-0 = 0x01)
+ */
+#define FM_ITRS 0x01 /* transmit synchronous queue */
+ /* SN3: reserved */
+#define FM_ITRA0 0x02 /* transmit asynchronous queue 0 */
+ /* SN3: reserved */
+#define FM_ITRA1 0x04 /* transmit asynchronous queue 1 */
+ /* SN3: reserved */
+#define FM_ITRA2 0x08 /* transmit asynchronous queue 2 */
+ /* SN3: reserved */
+#define FM_IACTR 0x10 /* abort current transmit activity */
+#define FM_IRSTQ 0x20 /* reset transmit queues */
+#define FM_ISTTB 0x30 /* set tag bit */
+#define FM_IERSF 0x40 /* enable receive single frame */
+ /* SN3: reserved */
+#define FM_ITR 0x50 /* SN3: Transmit Command */
+
+
+/*
+ * defines for PLC (Am79C864)
+ */
+
+/*
+ * PLC read/write (r/w) registers
+ */
+#define PL_CNTRL_A 0x00 /* control register A (r/w) */
+#define PL_CNTRL_B 0x01 /* control register B (r/w) */
+#define PL_INTR_MASK 0x02 /* interrupt mask (r/w) */
+#define PL_XMIT_VECTOR 0x03 /* transmit vector register (r/w) */
+#define PL_VECTOR_LEN 0x04 /* transmit vector length (r/w) */
+#define PL_LE_THRESHOLD 0x05 /* link error event threshold (r/w) */
+#define PL_C_MIN 0x06 /* minimum connect state time (r/w) */
+#define PL_TL_MIN 0x07 /* min. line state transmit t. (r/w) */
+#define PL_TB_MIN 0x08 /* minimum break time (r/w) */
+#define PL_T_OUT 0x09 /* signal timeout (r/w) */
+#define PL_CNTRL_C 0x0a /* control register C (r/w) */
+#define PL_LC_LENGTH 0x0b /* link confidence test time (r/w) */
+#define PL_T_SCRUB 0x0c /* scrub time = MAC TVX (r/w) */
+#define PL_NS_MAX 0x0d /* max. noise time before break (r/w)*/
+#define PL_TPC_LOAD_V 0x0e /* TPC timer load value (write only) */
+#define PL_TNE_LOAD_V 0x0f /* TNE timer load value (write only) */
+#define PL_STATUS_A 0x10 /* status register A (read only) */
+#define PL_STATUS_B 0x11 /* status register B (read only) */
+#define PL_TPC 0x12 /* timer for PCM (ro) [20.48 us] */
+#define PL_TNE 0x13 /* time of noise event [0.32 us] */
+#define PL_CLK_DIV 0x14 /* TNE clock divider (read only) */
+#define PL_BIST_SIGNAT 0x15 /* built in self test signature (ro)*/
+#define PL_RCV_VECTOR 0x16 /* receive vector reg. (read only) */
+#define PL_INTR_EVENT 0x17 /* interrupt event reg. (read only) */
+#define PL_VIOL_SYM_CTR 0x18 /* violation symbol count. (read o) */
+#define PL_MIN_IDLE_CTR 0x19 /* minimum idle counter (read only) */
+#define PL_LINK_ERR_CTR 0x1a /* link error event ctr.(read only) */
+#ifdef MOT_ELM
+#define PL_T_FOT_ASS 0x1e /* FOTOFF Assert Timer */
+#define PL_T_FOT_DEASS 0x1f /* FOTOFF Deassert Timer */
+#endif /* MOT_ELM */
+
+#ifdef MOT_ELM
+/*
+ * Special Quad-Elm Registers.
+ * A Quad-ELM consists of for ELMs and these additional registers.
+ */
+#define QELM_XBAR_W 0x80 /* Crossbar Control ELM W */
+#define QELM_XBAR_X 0x81 /* Crossbar Control ELM X */
+#define QELM_XBAR_Y 0x82 /* Crossbar Control ELM Y */
+#define QELM_XBAR_Z 0x83 /* Crossbar Control ELM Z */
+#define QELM_XBAR_P 0x84 /* Crossbar Control Bus P */
+#define QELM_XBAR_S 0x85 /* Crossbar Control Bus S */
+#define QELM_XBAR_R 0x86 /* Crossbar Control Bus R */
+#define QELM_WR_XBAR 0x87 /* Write the Crossbar now (write) */
+#define QELM_CTR_W 0x88 /* Counter W */
+#define QELM_CTR_X 0x89 /* Counter X */
+#define QELM_CTR_Y 0x8a /* Counter Y */
+#define QELM_CTR_Z 0x8b /* Counter Z */
+#define QELM_INT_MASK 0x8c /* Interrupt mask register */
+#define QELM_INT_DATA 0x8d /* Interrupt data (event) register */
+#define QELM_ELMB 0x00 /* Elm base */
+#define QELM_ELM_SIZE 0x20 /* ELM size */
+#endif /* MOT_ELM */
+/*
+ * PLC control register A (PL_CNTRL_A: log. addr. 0x00)
+ * It is used for timer configuration, specification of PCM MAINT state option,
+ * counter interrupt frequency, PLC data path config. and Built In Self Test.
+ */
+#define PL_RUN_BIST 0x0001 /* begin running its Built In Self T.*/
+#define PL_RF_DISABLE 0x0002 /* disable the Repeat Filter state m.*/
+#define PL_SC_REM_LOOP 0x0004 /* remote loopback path */
+#define PL_SC_BYPASS 0x0008 /* by providing a physical bypass */
+#define PL_LM_LOC_LOOP 0x0010 /* loop path just after elastic buff.*/
+#define PL_EB_LOC_LOOP 0x0020 /* loop path just prior to PDT/PDR IF*/
+#define PL_FOT_OFF 0x0040 /* assertion of /FOTOFF pin of PLC */
+#define PL_LOOPBACK 0x0080 /* it cause the /LPBCK pin ass. low */
+#define PL_MINI_CTR_INT 0x0100 /* partially contr. when bit is ass. */
+#define PL_VSYM_CTR_INT 0x0200 /* controls when int bit is asserted */
+#define PL_ENA_PAR_CHK 0x0400 /* enable parity check */
+#define PL_REQ_SCRUB 0x0800 /* limited access to scrub capability*/
+#define PL_TPC_16BIT 0x1000 /* causes the TPC as a 16 bit timer */
+#define PL_TNE_16BIT 0x2000 /* causes the TNE as a 16 bit timer */
+#define PL_NOISE_TIMER 0x4000 /* allows the noise timing function */
+
+/*
+ * PLC control register B (PL_CNTRL_B: log. addr. 0x01)
+ * It contains signals and requeste to direct the process of PCM and it is also
+ * used to control the Line State Match interrupt.
+ */
+#define PL_PCM_CNTRL 0x0003 /* control PCM state machine */
+#define PL_PCM_NAF (0) /* state is not affected */
+#define PL_PCM_START (1) /* goes to the BREAK state */
+#define PL_PCM_TRACE (2) /* goes to the TRACE state */
+#define PL_PCM_STOP (3) /* goes to the OFF state */
+
+#define PL_MAINT 0x0004 /* if OFF state --> MAINT state */
+#define PL_LONG 0x0008 /* perf. a long Link Confid.Test(LCT)*/
+#define PL_PC_JOIN 0x0010 /* if NEXT state --> JOIN state */
+
+#define PL_PC_LOOP 0x0060 /* loopback used in the LCT */
+#define PL_NOLCT (0<<5) /* no LCT is performed */
+#define PL_TPDR (1<<5) /* PCM asserts transmit PDR */
+#define PL_TIDLE (2<<5) /* PCM asserts transmit idle */
+#define PL_RLBP (3<<5) /* trans. PDR & remote loopb. path */
+
+#define PL_CLASS_S 0x0080 /* signif. that single att. station */
+
+#define PL_MAINT_LS 0x0700 /* line state while in the MAINT st. */
+#define PL_M_QUI0 (0<<8) /* transmit QUIET line state */
+#define PL_M_IDLE (1<<8) /* transmit IDLE line state */
+#define PL_M_HALT (2<<8) /* transmit HALT line state */
+#define PL_M_MASTR (3<<8) /* transmit MASTER line state */
+#define PL_M_QUI1 (4<<8) /* transmit QUIET line state */
+#define PL_M_QUI2 (5<<8) /* transmit QUIET line state */
+#define PL_M_TPDR (6<<8) /* tr. PHY_DATA requ.-symbol is tr.ed*/
+#define PL_M_QUI3 (7<<8) /* transmit QUIET line state */
+
+#define PL_MATCH_LS 0x7800 /* line state to be comp. with curr.*/
+#define PL_I_ANY (0<<11) /* Int. on any change in *_LINE_ST */
+#define PL_I_IDLE (1<<11) /* Interrupt on IDLE line state */
+#define PL_I_HALT (2<<11) /* Interrupt on HALT line state */
+#define PL_I_MASTR (4<<11) /* Interrupt on MASTER line state */
+#define PL_I_QUIET (8<<11) /* Interrupt on QUIET line state */
+
+#define PL_CONFIG_CNTRL 0x8000 /* control over scrub, byp. & loopb.*/
+
+/*
+ * PLC control register C (PL_CNTRL_C: log. addr. 0x0a)
+ * It contains the scrambling control registers (PLC-S only)
+ */
+#define PL_C_CIPHER_ENABLE (1<<0) /* enable scrambler */
+#define PL_C_CIPHER_LPBCK (1<<1) /* loopback scrambler */
+#define PL_C_SDOFF_ENABLE (1<<6) /* enable SDOFF timer */
+#define PL_C_SDON_ENABLE (1<<7) /* enable SDON timer */
+#ifdef MOT_ELM
+#define PL_C_FOTOFF_CTRL (3<<2) /* FOTOFF timer control */
+#define PL_C_FOTOFF_TIM (0<<2) /* FOTOFF use timer for (de)-assert */
+#define PL_C_FOTOFF_INA (2<<2) /* FOTOFF forced inactive */
+#define PL_C_FOTOFF_ACT (3<<2) /* FOTOFF forced active */
+#define PL_C_FOTOFF_SRCE (1<<4) /* FOTOFF source is PCM state != OFF */
+#define PL_C_RXDATA_EN (1<<5) /* Rec scr data forced to 0 */
+#define PL_C_SDNRZEN (1<<8) /* Monitor rec descr. data for act */
+#else /* nMOT_ELM */
+#define PL_C_FOTOFF_CTRL (3<<8) /* FOTOFF timer control */
+#define PL_C_FOTOFF_0 (0<<8) /* timer off */
+#define PL_C_FOTOFF_30 (1<<8) /* 30uS */
+#define PL_C_FOTOFF_50 (2<<8) /* 50uS */
+#define PL_C_FOTOFF_NEVER (3<<8) /* never */
+#define PL_C_SDON_TIMER (3<<10) /* SDON timer control */
+#define PL_C_SDON_084 (0<<10) /* 0.84 uS */
+#define PL_C_SDON_132 (1<<10) /* 1.32 uS */
+#define PL_C_SDON_252 (2<<10) /* 2.52 uS */
+#define PL_C_SDON_512 (3<<10) /* 5.12 uS */
+#define PL_C_SOFF_TIMER (3<<12) /* SDOFF timer control */
+#define PL_C_SOFF_076 (0<<12) /* 0.76 uS */
+#define PL_C_SOFF_132 (1<<12) /* 1.32 uS */
+#define PL_C_SOFF_252 (2<<12) /* 2.52 uS */
+#define PL_C_SOFF_512 (3<<12) /* 5.12 uS */
+#define PL_C_TSEL (3<<14) /* scrambler path select */
+#endif /* nMOT_ELM */
+
+/*
+ * PLC status register A (PL_STATUS_A: log. addr. 0x10)
+ * It is used to report status information to the Node Processor about the
+ * Line State Machine (LSM).
+ */
+#ifdef MOT_ELM
+#define PLC_INT_MASK 0xc000 /* ELM integration bits in status A */
+#define PLC_INT_C 0x0000 /* ELM Revision Band C */
+#define PLC_INT_CAMEL 0x4000 /* ELM integrated into CAMEL */
+#define PLC_INT_QE 0x8000 /* ELM integrated into Quad ELM */
+#define PLC_REV_MASK 0x3800 /* revision bits in status A */
+#define PLC_REVISION_B 0x0000 /* rev bits for ELM Rev B */
+#define PLC_REVISION_QA 0x0800 /* rev bits for ELM core in QELM-A */
+#else /* nMOT_ELM */
+#define PLC_REV_MASK 0xf800 /* revision bits in status A */
+#define PLC_REVISION_A 0x0000 /* revision bits for PLC */
+#define PLC_REVISION_S 0xf800 /* revision bits for PLC-S */
+#define PLC_REV_SN3 0x7800 /* revision bits for PLC-S in IFCP */
+#endif /* nMOT_ELM */
+#define PL_SYM_PR_CTR 0x0007 /* contains the LSM symbol pair Ctr. */
+#define PL_UNKN_LINE_ST 0x0008 /* unknown line state bit from LSM */
+#define PL_LSM_STATE 0x0010 /* state bit of LSM */
+
+#define PL_LINE_ST 0x00e0 /* contains recogn. line state of LSM*/
+#define PL_L_NLS (0<<5) /* noise line state */
+#define PL_L_ALS (1<<5) /* activ line state */
+#define PL_L_UND (2<<5) /* undefined */
+#define PL_L_ILS4 (3<<5) /* idle l. s. (after 4 idle symbols) */
+#define PL_L_QLS (4<<5) /* quiet line state */
+#define PL_L_MLS (5<<5) /* master line state */
+#define PL_L_HLS (6<<5) /* halt line state */
+#define PL_L_ILS16 (7<<5) /* idle line state (after 16 idle s.)*/
+
+#define PL_PREV_LINE_ST 0x0300 /* value of previous line state */
+#define PL_P_QLS (0<<8) /* quiet line state */
+#define PL_P_MLS (1<<8) /* master line state */
+#define PL_P_HLS (2<<8) /* halt line state */
+#define PL_P_ILS16 (3<<8) /* idle line state (after 16 idle s.)*/
+
+#define PL_SIGNAL_DET 0x0400 /* 1=that signal detect is deasserted*/
+
+
+/*
+ * PLC status register B (PL_STATUS_B: log. addr. 0x11)
+ * It contains signals and status from the repeat filter and PCM state machine.
+ */
+#define PL_BREAK_REASON 0x0007 /* reason for PCM state mach.s to br.*/
+#define PL_B_NOT (0) /* PCM SM has not gone to BREAK state*/
+#define PL_B_PCS (1) /* PC_Start issued */
+#define PL_B_TPC (2) /* TPC timer expired after T_OUT */
+#define PL_B_TNE (3) /* TNE timer expired after NS_MAX */
+#define PL_B_QLS (4) /* quit line state detected */
+#define PL_B_ILS (5) /* idle line state detected */
+#define PL_B_HLS (6) /* halt line state detected */
+
+#define PL_TCF 0x0008 /* transmit code flag (start exec.) */
+#define PL_RCF 0x0010 /* receive code flag (start exec.) */
+#define PL_LSF 0x0020 /* line state flag (l.s. has been r.)*/
+#define PL_PCM_SIGNAL 0x0040 /* indic. that XMIT_VECTOR hb.written*/
+
+#define PL_PCM_STATE 0x0780 /* state bits of PCM state machine */
+#define PL_PC0 (0<<7) /* OFF - when /RST or PCM_CNTRL */
+#define PL_PC1 (1<<7) /* BREAK - entry point in start PCM*/
+#define PL_PC2 (2<<7) /* TRACE - to localize stuck Beacon*/
+#define PL_PC3 (3<<7) /* CONNECT - synchronize ends of conn*/
+#define PL_PC4 (4<<7) /* NEXT - to seperate the signalng*/
+#define PL_PC5 (5<<7) /* SIGNAL - PCM trans/rec. bit infos*/
+#define PL_PC6 (6<<7) /* JOIN - 1. state to activ conn. */
+#define PL_PC7 (7<<7) /* VERIFY - 2. - " - (3. ACTIVE) */
+#define PL_PC8 (8<<7) /* ACTIVE - PHY has been incorporated*/
+#define PL_PC9 (9<<7) /* MAINT - for test purposes or so
+ that PCM op. completely in softw. */
+
+#define PL_PCI_SCRUB 0x0800 /* scrubbing function is being exec. */
+
+#define PL_PCI_STATE 0x3000 /* Physical Connect. Insertion SM */
+#define PL_CI_REMV (0<<12) /* REMOVED */
+#define PL_CI_ISCR (1<<12) /* INSERT_SCRUB */
+#define PL_CI_RSCR (2<<12) /* REMOVE_SCRUB */
+#define PL_CI_INS (3<<12) /* INSERTED */
+
+#define PL_RF_STATE 0xc000 /* state bit of repeate filter SM */
+#define PL_RF_REPT (0<<14) /* REPEAT */
+#define PL_RF_IDLE (1<<14) /* IDLE */
+#define PL_RF_HALT1 (2<<14) /* HALT1 */
+#define PL_RF_HALT2 (3<<14) /* HALT2 */
+
+
+/*
+ * PLC interrupt event register (PL_INTR_EVENT: log. addr. 0x17)
+ * It is read only and is clearde whenever it is read!
+ * It is used by the PLC to report events to the node processor.
+ */
+#define PL_PARITY_ERR 0x0001 /* p. error h.b.detected on TX9-0 inp*/
+#define PL_LS_MATCH 0x0002 /* l.s.== l.s. PLC_CNTRL_B's MATCH_LS*/
+#define PL_PCM_CODE 0x0004 /* transmit&receive | LCT complete */
+#define PL_TRACE_PROP 0x0008 /* master l.s. while PCM ACTIV|TRACE */
+#define PL_SELF_TEST 0x0010 /* QUIET|HALT while PCM in TRACE st. */
+#define PL_PCM_BREAK 0x0020 /* PCM has entered the BREAK state */
+#define PL_PCM_ENABLED 0x0040 /* asserted SC_JOIN, scrub. & ACTIV */
+#define PL_TPC_EXPIRED 0x0080 /* TPC timer reached zero */
+#define PL_TNE_EXPIRED 0x0100 /* TNE timer reached zero */
+#define PL_EBUF_ERR 0x0200 /* elastic buff. det. over-|underflow*/
+#define PL_PHYINV 0x0400 /* physical layer invalid signal */
+#define PL_VSYM_CTR 0x0800 /* violation symbol counter has incr.*/
+#define PL_MINI_CTR 0x1000 /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
+#define PL_LE_CTR 0x2000 /* link error event counter */
+#define PL_LSDO 0x4000 /* SDO input pin changed to a 1 */
+#define PL_NP_ERR 0x8000 /* NP has requested to r/w an inv. r.*/
+
+/*
+ * The PLC interrupt mask register (PL_INTR_MASK: log. addr. 0x02) constr. is
+ * equal PL_INTR_EVENT register.
+ * For each set bit, the setting of corresponding bit generate an int to NP.
+ */
+
+#ifdef MOT_ELM
+/*
+ * Quad ELM Crosbar Control register values (QELM_XBAR_?)
+ */
+#define QELM_XOUT_IDLE 0x0000 /* Idles/Passthrough */
+#define QELM_XOUT_P 0x0001 /* Output to: Bus P */
+#define QELM_XOUT_S 0x0002 /* Output to: Bus S */
+#define QELM_XOUT_R 0x0003 /* Output to: Bus R */
+#define QELM_XOUT_W 0x0004 /* Output to: ELM W */
+#define QELM_XOUT_X 0x0005 /* Output to: ELM X */
+#define QELM_XOUT_Y 0x0006 /* Output to: ELM Y */
+#define QELM_XOUT_Z 0x0007 /* Output to: ELM Z */
+
+/*
+ * Quad ELM Interrupt data and event registers.
+ */
+#define QELM_NP_ERR (1<<15) /* Node Processor Error */
+#define QELM_COUNT_Z (1<<7) /* Counter Z Interrupt */
+#define QELM_COUNT_Y (1<<6) /* Counter Y Interrupt */
+#define QELM_COUNT_X (1<<5) /* Counter X Interrupt */
+#define QELM_COUNT_W (1<<4) /* Counter W Interrupt */
+#define QELM_ELM_Z (1<<3) /* ELM Z Interrupt */
+#define QELM_ELM_Y (1<<2) /* ELM Y Interrupt */
+#define QELM_ELM_X (1<<1) /* ELM X Interrupt */
+#define QELM_ELM_W (1<<0) /* ELM W Interrupt */
+#endif /* MOT_ELM */
+/*
+ * PLC Timing Parameters
+ */
+#define TP_C_MIN 0xff9c /* 2 ms */
+#define TP_TL_MIN 0xfff0 /* 0.3 ms */
+#define TP_TB_MIN 0xff10 /* 5 ms */
+#define TP_T_OUT 0xd9db /* 200 ms */
+#define TP_LC_LENGTH 0xf676 /* 50 ms */
+#define TP_LC_LONGLN 0xa0a2 /* 500 ms */
+#define TP_T_SCRUB 0xff6d /* 3.5 ms */
+#define TP_NS_MAX 0xf021 /* 1.3 ms */
+
+/*
+ * BIST values
+ */
+#define PLC_BIST 0x6ecd /* BIST signature for PLC */
+#define PLCS_BIST 0x5b6b /* BIST signature for PLC-S */
+#define PLC_ELM_B_BIST 0x6ecd /* BIST signature of ELM Rev. B */
+#define PLC_ELM_D_BIST 0x5b6b /* BIST signature of ELM Rev. D */
+#define PLC_CAM_A_BIST 0x9e75 /* BIST signature of CAMEL Rev. A */
+#define PLC_CAM_B_BIST 0x5b6b /* BIST signature of CAMEL Rev. B */
+#define PLC_IFD_A_BIST 0x9e75 /* BIST signature of IFDDI Rev. A */
+#define PLC_IFD_B_BIST 0x5b6b /* BIST signature of IFDDI Rev. B */
+#define PLC_QELM_A_BIST 0x5b6b /* BIST signature of QELM Rev. A */
+
+/*
+ FDDI board recources
+ */
+
+/*
+ * request register array (log. addr: RQA_A + a<<1 {a=0..7}) write only.
+ * It specifies to FORMAC+ the type of buffer memory access the host requires.
+ */
+#define RQ_NOT 0 /* not request */
+#define RQ_RES 1 /* reserved */
+#define RQ_SFW 2 /* special frame write */
+#define RQ_RRQ 3 /* read request: receive queue */
+#define RQ_WSQ 4 /* write request: synchronous queue */
+#define RQ_WA0 5 /* write requ.: asynchronous queue 0 */
+#define RQ_WA1 6 /* write requ.: asynchronous queue 1 */
+#define RQ_WA2 7 /* write requ.: asynchronous queue 2 */
+
+#define SZ_LONG (sizeof(long))
+
+/*
+ * FDDI defaults
+ * NOTE : In the ANSI docs, times are specified in units of "symbol time".
+ * AMD chips use BCLK as unit. 1 BCKL == 2 symbols
+ */
+#define COMPLREF ((u_long)32*256*256) /* two's complement 21 bit */
+#define MSTOBCLK(x) ((u_long)(x)*12500L)
+#define MSTOTVX(x) (((u_long)(x)*1000L)/80/255)
+
+#endif /* _SUPERNET_ */
diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h
new file mode 100644
index 000000000..5e6f3a050
--- /dev/null
+++ b/drivers/net/skfp/h/targethw.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _TARGETHW_
+#define _TARGETHW_
+
+ /*
+ * PCI Watermark definition
+ */
+#ifdef PCI
+#define RX_WATERMARK 24
+#define TX_WATERMARK 24
+#define SK_ML_ID_1 0x20
+#define SK_ML_ID_2 0x30
+#endif
+
+#include "h/skfbi.h"
+#ifndef TAG_MODE
+#include "h/fplus.h"
+#else
+#include "h/fplustm.h"
+#endif
+
+#ifndef HW_PTR
+#ifdef MEM_MAPPED_IO
+#define HW_PTR u_long
+#else
+#define HW_PTR u_short
+#endif
+#endif
+
+#ifdef MULT_OEM
+#define OI_STAT_LAST 0 /* end of OEM data base */
+#define OI_STAT_PRESENT 1 /* entry present but not empty */
+#define OI_STAT_VALID 2 /* holds valid ID, but is not active */
+#define OI_STAT_ACTIVE 3 /* holds valid ID, entry is active */
+ /* active = adapter is supported */
+
+/* Memory representation of IDs must match representation in adapter. */
+struct s_oem_ids {
+ u_char oi_status ; /* Stat: last, present, valid, active */
+ u_char oi_mark[5] ; /* "PID00" .. "PID07" .. */
+ u_char oi_id[4] ; /* id bytes, representation as */
+ /* defined by hardware, */
+#ifdef PCI
+ u_char oi_sub_id[4] ; /* sub id bytes, representation as */
+ /* defined by hardware, */
+#endif
+#ifdef ISA
+ u_char oi_logo_len ; /* the length of the adapter logo */
+ u_char oi_logo[6] ; /* the adapter logo */
+ u_char oi_reserved1 ;
+#endif /* ISA */
+} ;
+#endif /* MULT_OEM */
+
+
+struct s_smt_hw {
+ /*
+ * global
+ */
+ HW_PTR iop ; /* IO base address */
+ short dma ; /* DMA channel */
+ short irq ; /* IRQ level */
+ short eprom ; /* FLASH prom */
+#ifndef PCI
+ short DmaWriteExtraBytes ; /* add bytes for DMA write */
+#endif
+
+#ifndef SYNC
+ u_short n_a_send ; /* pending send requests */
+#endif
+
+#if (defined(EISA) || defined(MCA) || defined(PCI))
+ short slot ; /* slot number */
+ short max_slots ; /* maximum number of slots */
+#endif
+
+#if (defined(PCI) || defined(MCA))
+ short wdog_used ; /* TRUE if the watch dog is used */
+#endif
+
+#ifdef MCA
+ short slot_32 ; /* 32bit slot (1) or 16bit slot (0) */
+ short rev ; /* Board revision (FMx_REV). */
+ short VFullRead ; /* V_full value for DMA read */
+ short VFullWrite ; /* V_full value for DMA write */
+#endif
+
+#ifdef EISA
+ short led ; /* LED for FE card */
+
+ short dma_rmode ; /* read mode */
+ short dma_wmode ; /* write mode */
+ short dma_emode ; /* extend mode */
+
+ /* DMA controller channel dependent io addresses */
+ u_short dma_base_word_count ;
+ u_short dma_base_address ;
+ u_short dma_base_address_page ;
+#endif
+
+#ifdef PCI
+ u_short pci_handle ; /* handle to access the BIOS func */
+ u_long is_imask ; /* int maske for the int source reg */
+ u_long phys_mem_addr ; /* physical memory address */
+ u_short mc_dummy ; /* work around for MC compiler bug */
+ /*
+ * state of the hardware
+ */
+ u_short hw_state ; /* started or stopped */
+
+#define STARTED 1
+#define STOPPED 0
+
+ int hw_is_64bit ; /* does we have a 64 bit adapter */
+#endif
+
+#ifdef TAG_MODE
+ u_long pci_fix_value ; /* value parsed by PCIFIX */
+#endif
+
+ /*
+ * hwt.c
+ */
+ u_long t_start ; /* HWT start */
+ u_long t_stop ; /* HWT stop */
+ u_short timer_activ ; /* HWT timer active */
+
+ /*
+ * PIC
+ */
+ u_char pic_a1 ;
+ u_char pic_21 ;
+
+ /*
+ * GENERIC ; do not modify beyond this line
+ */
+
+ /*
+ * physical and canonical address
+ */
+ struct fddi_addr fddi_home_addr ;
+ struct fddi_addr fddi_canon_addr ;
+ struct fddi_addr fddi_phys_addr ;
+
+ /*
+ * mac variables
+ */
+ struct mac_parameter mac_pa ; /* tmin, tmax, tvx, treq .. */
+ struct mac_counter mac_ct ; /* recv., lost, error */
+ u_short mac_ring_is_up ; /* ring is up flag */
+
+ struct s_smt_fp fp ; /* formac+ */
+
+#ifdef MULT_OEM
+ struct s_oem_ids *oem_id ; /* pointer to selected id */
+ int oem_min_status ; /* IDs to take care of */
+#endif /* MULT_OEM */
+
+} ;
+#endif
diff --git a/drivers/net/skfp/h/targetos.h b/drivers/net/skfp/h/targetos.h
new file mode 100644
index 000000000..dd88fb35e
--- /dev/null
+++ b/drivers/net/skfp/h/targetos.h
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Operating system specific definitions for driver and
+ * hardware module.
+ */
+
+#ifndef TARGETOS_H
+#define TARGETOS_H
+
+
+//-------- those should go into include/linux/pci.h
+#define PCI_VENDOR_ID_SK 0x1148
+#define PCI_DEVICE_ID_SK_FP 0x4000
+//--------
+
+
+
+//-------- those should go into include/linux/if_fddi.h
+#define FDDI_MAC_HDR_LEN 13
+
+#define FDDI_RII 0x01 /* routing information bit */
+#define FDDI_RCF_DIR_BIT 0x80
+#define FDDI_RCF_LEN_MASK 0x1f
+#define FDDI_RCF_BROADCAST 0x8000
+#define FDDI_RCF_LIMITED_BROADCAST 0xA000
+#define FDDI_RCF_FRAME2K 0x20
+#define FDDI_RCF_FRAME4K 0x30
+//--------
+
+
+#undef ADDR
+
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+// is redefined by linux, but we need our definition
+#undef ADDR
+#ifdef MEM_MAPPED_IO
+#define ADDR(a) (char far *) smc->hw.iop+(a)
+#else
+#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#endif
+
+#include "h/hwmtm.h"
+
+#define TRUE 1
+#define FALSE 0
+
+// HWM Definitions
+// -----------------------
+#define FDDI_TRACE(string, arg1, arg2, arg3) // Performance analysis.
+#ifdef PCI
+#define NDD_TRACE(string, arg1, arg2, arg3) // Performance analysis.
+#endif // PCI
+#define SMT_PAGESIZE PAGE_SIZE // Size of a memory page (power of 2).
+// -----------------------
+
+
+// SMT Definitions
+// -----------------------
+#define TICKS_PER_SECOND HZ
+#define SMC_VERSION 1
+// -----------------------
+
+
+// OS-Driver Definitions
+// -----------------------
+#define NO_ADDRESS 0xffe0 /* No Device (I/O) Address */
+#define SKFP_MAX_NUM_BOARDS 8 /* maximum number of PCI boards */
+
+#define SK_BUS_TYPE_PCI 0
+#define SK_BUS_TYPE_EISA 1
+
+#define FP_IO_LEN 256 /* length of IO area used */
+
+#define u8 unsigned char
+#define u16 unsigned short
+#define u32 unsigned long
+
+#define MAX_TX_QUEUE_LEN 20 // number of packets queued by driver
+#define MAX_FRAME_SIZE 4550
+
+#define RX_LOW_WATERMARK NUM_RECEIVE_BUFFERS / 2
+#define TX_LOW_WATERMARK NUM_TRANSMIT_BUFFERS - 2
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define SKFPIOCTL SIOCDEVPRIVATE
+
+struct s_skfp_ioctl {
+ unsigned short cmd; /* Command to run */
+ unsigned short len; /* Length of the data buffer */
+ unsigned char *data; /* Pointer to the data buffer */
+};
+
+/*
+** Recognised ioctl commands for the driver
+*/
+#define SKFP_GET_STATS 0x05 /* Get the driver statistics */
+#define SKFP_CLR_STATS 0x06 /* Zero out the driver statistics */
+
+// The per-adapter driver structure
+struct s_smt_os {
+ struct net_device *dev;
+ struct net_device *next_module;
+ u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */
+ struct pci_dev pdev; /* PCI device structure */
+
+ u32 base_addr;
+ unsigned char factory_mac_addr[8];
+ ulong SharedMemSize;
+ ulong SharedMemHeap;
+ void* SharedMemAddr;
+
+ ulong QueueSkb;
+ struct sk_buff_head SendSkbQueue;
+
+ ulong MaxFrameSize;
+ u8 ResetRequested;
+
+ // MAC statistics structure
+ struct fddi_statistics MacStat;
+
+ // receive into this local buffer if no skb available
+ // data will be not valid, because multiple RxDs can
+ // point here at the same time
+ unsigned char LocalRxBuffer[MAX_FRAME_SIZE];
+
+ // Version (required by SMT module).
+ u_long smc_version ;
+
+ // Required by Hardware Module (HWM).
+ struct hw_modul hwm ;
+
+ // For SMP-savety
+ spinlock_t DriverLock;
+
+};
+
+typedef struct s_smt_os skfddi_priv;
+
+#endif // _TARGETOS_
diff --git a/drivers/net/skfp/h/types.h b/drivers/net/skfp/h/types.h
new file mode 100644
index 000000000..43b48ff3b
--- /dev/null
+++ b/drivers/net/skfp/h/types.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include <linux/types.h>
+/*
+ ----------------------
+ Basic SMT system types
+ ----------------------
+*/
+#ifndef _TYPES_
+#define _TYPES_
+
+#define _packed
+#ifndef far
+#define far
+#endif
+#ifndef _far
+#define _far
+#endif
+
+#ifndef MEM_MAPPED_IO // "normal" IO
+#define inp(p) inb(p)
+#define inpw(p) inw(p)
+#define inpd(p) inl(p)
+#define outp(p,c) outb(c,p)
+#define outpw(p,s) outw(s,p)
+#define outpd(p,l) outl(l,p)
+#else // memory mapped io
+#define inp(a) readb(a)
+#define inpw(a) readw(a)
+#define inpd(a) readl(a)
+#define outp(a,v) writeb(v, a)
+#define outpw(a,v) writew(v, a)
+#define outpd(a,v) writel(v, a)
+#endif
+
+#endif /* _TYPES_ */
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
new file mode 100644
index 000000000..366b3b890
--- /dev/null
+++ b/drivers/net/skfp/hwmtm.c
@@ -0,0 +1,2261 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef lint
+static char const ID_sccs[] = "@(#)hwmtm.c 1.40 99/05/31 (C) SK" ;
+#endif
+
+#define HWMTM
+
+#ifndef FDDI
+#define FDDI
+#endif
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "h/skfbiinc.h"
+
+/*
+ -------------------------------------------------------------
+ DOCUMENTATION
+ -------------------------------------------------------------
+ BEGIN_MANUAL_ENTRY(DOCUMENTATION)
+
+ T B D
+
+ END_MANUAL_ENTRY
+*/
+/*
+ -------------------------------------------------------------
+ LOCAL VARIABLES:
+ -------------------------------------------------------------
+*/
+#ifdef COMMON_MB_POOL
+static SMbuf *mb_start = 0 ;
+static SMbuf *mb_free = 0 ;
+static int mb_init = FALSE ;
+static int call_count = 0 ;
+#endif
+
+/*
+ -------------------------------------------------------------
+ EXTERNE VARIABLES:
+ -------------------------------------------------------------
+*/
+
+#ifdef DEBUG
+#ifndef DEBUG_BRD
+extern struct smt_debug debug ;
+#endif
+#endif
+
+#ifdef NDIS_OS2
+extern u_char offDepth ;
+extern u_char force_irq_pending ;
+#endif
+
+/*
+ -------------------------------------------------------------
+ LOCAL FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+static void queue_llc_rx(), smt_to_llc(),
+ init_txd_ring(), init_rxd_ring(),
+ queue_txd_mb() ;
+
+static u_long init_descr_ring(), repair_txd_ring(),
+ repair_rxd_ring() ;
+
+static SMbuf *get_llc_rx(), *get_txd_mb() ;
+
+
+/*
+ -------------------------------------------------------------
+ EXTERNAL FUNCTIONS:
+ -------------------------------------------------------------
+*/
+/* The external SMT functions are listed in cmtdef.h */
+
+extern void *mac_drv_get_space(), *mac_drv_get_desc_mem(),
+ init_board(), mac_drv_fill_rxd(),
+ plc1_irq(), mac_drv_tx_complete(),
+ plc2_irq(), mac1_irq(),
+ mac2_irq(), mac3_irq(),
+ timer_irq(), mac_drv_rx_complete(),
+ mac_drv_requeue_rxd(), init_plc(),
+ mac_drv_clear_rxd(), llc_restart_tx(),
+ ev_dispatcher(), smt_force_irq() ;
+
+#ifdef USE_OS_CPY
+extern void hwm_cpy_rxd2mb(), hwm_cpy_txd2mb() ;
+#endif
+#ifdef ALL_RX_COMPLETE
+extern void mac_drv_all_receives_complete() ;
+#endif
+
+extern u_long mac_drv_virt2phys(), dma_master() ;
+
+#ifdef NDIS_OS2
+extern void post_proc() ;
+#else
+extern void dma_complete() ;
+#endif
+
+extern int init_fplus(), mac_drv_rx_init() ;
+
+/*
+ -------------------------------------------------------------
+ PUBLIC FUNCTIONS:
+ -------------------------------------------------------------
+*/
+ void process_receive(), smt_send_mbuf(),
+ fddi_isr(), mac_drv_clear_txd(),
+ smt_free_mbuf(), init_driver_fplus(),
+ mac_drv_rx_mode(), init_fddi_driver(),
+ mac_drv_clear_tx_queue(),
+ mac_drv_clear_rx_queue(),
+ hwm_tx_frag(), hwm_rx_frag() ;
+
+ int mac_drv_rx_frag(), mac_drv_init(),
+ hwm_tx_init() ;
+
+ u_int mac_drv_check_space() ;
+
+ SMbuf *smt_get_mbuf() ;
+
+#ifdef DEBUG
+ void mac_drv_debug_lev() ;
+#endif
+
+/*
+ -------------------------------------------------------------
+ MACROS:
+ -------------------------------------------------------------
+*/
+#ifndef UNUSED
+#ifdef lint
+#define UNUSED(x) (x) = (x)
+#else
+#define UNUSED(x)
+#endif
+#endif
+
+#ifdef USE_CAN_ADDR
+#define MA smc->hw.fddi_canon_addr.a
+#define GROUP_ADDR_BIT 0x01
+#else
+#define MA smc->hw.fddi_home_addr.a
+#define GROUP_ADDR_BIT 0x80
+#endif
+
+#define RXD_TXD_COUNT (HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\
+ SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT)
+
+#ifdef MB_OUTSIDE_SMC
+#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\
+ MAX_MBUF*sizeof(SMbuf))
+#define EXT_VIRT_MEM_2 ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
+#else
+#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
+#endif
+
+ /*
+ * define critical read for 16 Bit drivers
+ */
+#if defined(NDIS_OS2) || defined(ODI2)
+#define CR_READ(var) ((var) & 0xffff0000 | ((var) & 0xffff))
+#else
+#define CR_READ(var) (u_long)(var)
+#endif
+
+#define IMASK_SLOW (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+ IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
+ IS_R1_C | IS_XA_C | IS_XS_C)
+
+/*
+ -------------------------------------------------------------
+ INIT- AND SMT FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+
+/*
+ * BEGIN_MANUAL_ENTRY(mac_drv_check_space)
+ * u_int mac_drv_check_space()
+ *
+ * function DOWNCALL (drvsr.c)
+ * This function calculates the needed non virtual
+ * memory for MBufs, RxD and TxD descriptors etc.
+ * needed by the driver.
+ *
+ * return u_int memory in bytes
+ *
+ * END_MANUAL_ENTRY
+ */
+u_int mac_drv_check_space()
+{
+#ifdef MB_OUTSIDE_SMC
+#ifdef COMMON_MB_POOL
+ call_count++ ;
+ if (call_count == 1) {
+ return(EXT_VIRT_MEM) ;
+ }
+ else {
+ return(EXT_VIRT_MEM_2) ;
+ }
+#else
+ return (EXT_VIRT_MEM) ;
+#endif
+#else
+ return (0) ;
+#endif
+}
+
+/*
+ * BEGIN_MANUAL_ENTRY(mac_drv_init)
+ * void mac_drv_init(smc)
+ *
+ * function DOWNCALL (drvsr.c)
+ * In this function the hardware module allocates it's
+ * memory.
+ * The operating system dependent module should call
+ * mac_drv_init once, after the adatper is detected.
+ * END_MANUAL_ENTRY
+ */
+int mac_drv_init(smc)
+struct s_smc *smc ;
+{
+ if (sizeof(struct s_smt_fp_rxd) % 16) {
+ SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ;
+ }
+ if (sizeof(struct s_smt_fp_txd) % 16) {
+ SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ;
+ }
+
+ /*
+ * get the required memory for the RxDs and TxDs
+ */
+ if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *)
+ mac_drv_get_desc_mem(smc,(u_int)
+ (RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) {
+ return(1) ; /* no space the hwm modul can't work */
+ }
+
+ /*
+ * get the memory for the SMT MBufs
+ */
+#ifndef MB_OUTSIDE_SMC
+ smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ;
+#else
+#ifndef COMMON_MB_POOL
+ if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc,
+ MAX_MBUF*sizeof(SMbuf)))) {
+ return(1) ; /* no space the hwm modul can't work */
+ }
+#else
+ if (!mb_start) {
+ if (!(mb_start = (SMbuf *) mac_drv_get_space(smc,
+ MAX_MBUF*sizeof(SMbuf)))) {
+ return(1) ; /* no space the hwm modul can't work */
+ }
+ }
+#endif
+#endif
+ return (0) ;
+}
+
+/*
+ * BEGIN_MANUAL_ENTRY(init_driver_fplus)
+ * init_driver_fplus(smc)
+ *
+ * Sets hardware modul specific values for the mode register 2
+ * (e.g. the byte alignment for the received frames, the position of the
+ * least significant byte etc.)
+ * END_MANUAL_ENTRY
+ */
+void init_driver_fplus(smc)
+struct s_smc *smc ;
+{
+ smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ;
+
+#ifdef PCI
+ smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ;
+#endif
+ smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ;
+
+#ifdef USE_CAN_ADDR
+ /* enable address bit swapping */
+ smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ;
+#endif
+}
+
+static u_long init_descr_ring(smc,start,count)
+struct s_smc *smc ;
+union s_fp_descr volatile *start;
+int count ;
+{
+ int i ;
+ union s_fp_descr volatile *d1 ;
+ union s_fp_descr volatile *d2 ;
+ u_long phys ;
+
+ DB_GEN("descr ring starts at = %x ",(void *)start,0,3) ;
+ for (i=count-1, d1=start; i ; i--) {
+ d2 = d1 ;
+ d1++ ; /* descr is owned by the host */
+ d2->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ;
+ d2->r.rxd_next = &d1->r ;
+ phys = mac_drv_virt2phys(smc,(void *)d1) ;
+ d2->r.rxd_nrdadr = AIX_REVERSE(phys) ;
+ }
+ DB_GEN("descr ring ends at = %x ",(void *)d1,0,3) ;
+ d1->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ;
+ d1->r.rxd_next = &start->r ;
+ phys = mac_drv_virt2phys(smc,(void *)start) ;
+ d1->r.rxd_nrdadr = AIX_REVERSE(phys) ;
+
+ for (i=count, d1=start; i ; i--) {
+ DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ;
+ d1++;
+ }
+ return(phys) ;
+}
+
+static void init_txd_ring(smc)
+struct s_smc *smc ;
+{
+ struct s_smt_fp_txd volatile *ds ;
+ struct s_smt_tx_queue *queue ;
+ u_long phys ;
+
+ /*
+ * initialize the transmit descriptors
+ */
+ ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p +
+ SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ;
+ queue = smc->hw.fp.tx[QUEUE_A0] ;
+ DB_GEN("Init async TxD ring, %d TxDs ",HWM_ASYNC_TXD_COUNT,0,3) ;
+ (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+ HWM_ASYNC_TXD_COUNT) ;
+ phys = AIX_REVERSE(ds->txd_ntdadr) ;
+ ds++ ;
+ queue->tx_curr_put = queue->tx_curr_get = ds ;
+ ds-- ;
+ queue->tx_free = HWM_ASYNC_TXD_COUNT ;
+ queue->tx_used = 0 ;
+ outpd(ADDR(B5_XA_DA),phys) ;
+
+ ds = (struct s_smt_fp_txd volatile *) ((char *)ds +
+ HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ;
+ queue = smc->hw.fp.tx[QUEUE_S] ;
+ DB_GEN("Init sync TxD ring, %d TxDs ",HWM_SYNC_TXD_COUNT,0,3) ;
+ (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+ HWM_SYNC_TXD_COUNT) ;
+ phys = AIX_REVERSE(ds->txd_ntdadr) ;
+ ds++ ;
+ queue->tx_curr_put = queue->tx_curr_get = ds ;
+ queue->tx_free = HWM_SYNC_TXD_COUNT ;
+ queue->tx_used = 0 ;
+ outpd(ADDR(B5_XS_DA),phys) ;
+}
+
+static void init_rxd_ring(smc)
+struct s_smc *smc ;
+{
+ struct s_smt_fp_rxd volatile *ds ;
+ struct s_smt_rx_queue *queue ;
+ u_long phys ;
+
+ /*
+ * initialize the receive descriptors
+ */
+ ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ;
+ queue = smc->hw.fp.rx[QUEUE_R1] ;
+ DB_GEN("Init RxD ring, %d RxDs ",SMT_R1_RXD_COUNT,0,3) ;
+ (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+ SMT_R1_RXD_COUNT) ;
+ phys = AIX_REVERSE(ds->rxd_nrdadr) ;
+ ds++ ;
+ queue->rx_curr_put = queue->rx_curr_get = ds ;
+ queue->rx_free = SMT_R1_RXD_COUNT ;
+ queue->rx_used = 0 ;
+ outpd(ADDR(B4_R1_DA),phys) ;
+}
+
+/*
+ * BEGIN_MANUAL_ENTRY(init_fddi_driver)
+ * void init_fddi_driver(smc,mac_addr)
+ *
+ * initializes the driver and it's variables
+ *
+ * END_MANUAL_ENTRY
+ */
+void init_fddi_driver(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ; /* canonical address */
+{
+ SMbuf *mb ;
+ int i ;
+
+ init_board(smc,mac_addr) ;
+ (void)init_fplus(smc) ;
+
+ /*
+ * initialize the SMbufs for the SMT
+ */
+#ifndef COMMON_MB_POOL
+ mb = smc->os.hwm.mbuf_pool.mb_start ;
+ smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ;
+ for (i = 0; i < MAX_MBUF; i++) {
+ mb->sm_use_count = 1 ;
+ smt_free_mbuf(smc,mb) ;
+ mb++ ;
+ }
+#else
+ mb = mb_start ;
+ if (!mb_init) {
+ mb_free = 0 ;
+ for (i = 0; i < MAX_MBUF; i++) {
+ mb->sm_use_count = 1 ;
+ smt_free_mbuf(smc,mb) ;
+ mb++ ;
+ }
+ mb_init = TRUE ;
+ }
+#endif
+
+ /*
+ * initialize the other variables
+ */
+ smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ;
+ smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ;
+ smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ;
+ smc->os.hwm.pass_llc_promisc = TRUE ;
+ smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ;
+ smc->os.hwm.detec_count = 0 ;
+ smc->os.hwm.rx_break = 0 ;
+ smc->os.hwm.rx_len_error = 0 ;
+ smc->os.hwm.isr_flag = FALSE ;
+
+ /*
+ * make sure that the start pointer is 16 byte aligned
+ */
+ i = 16 - ((int)smc->os.hwm.descr_p & 0xf) ;
+ if (i != 16) {
+ DB_GEN("i = %d",i,0,3) ;
+ smc->os.hwm.descr_p = (union s_fp_descr volatile *)
+ ((char *)smc->os.hwm.descr_p+i) ;
+ }
+ DB_GEN("pt to descr area = %x",(void *)smc->os.hwm.descr_p,0,3) ;
+
+ init_txd_ring(smc) ;
+ init_rxd_ring(smc) ;
+ mac_drv_fill_rxd(smc) ;
+
+ init_plc(smc) ;
+}
+
+
+SMbuf *smt_get_mbuf(smc)
+struct s_smc *smc ;
+{
+ register SMbuf *mb ;
+
+#ifndef COMMON_MB_POOL
+ mb = smc->os.hwm.mbuf_pool.mb_free ;
+#else
+ mb = mb_free ;
+#endif
+ if (mb) {
+#ifndef COMMON_MB_POOL
+ smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ;
+#else
+ mb_free = mb->sm_next ;
+#endif
+ mb->sm_off = 8 ;
+ mb->sm_use_count = 1 ;
+ }
+ DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ;
+ return (mb) ; /* May be NULL */
+}
+
+void smt_free_mbuf(smc, mb)
+struct s_smc *smc ;
+SMbuf *mb;
+{
+
+ if (mb) {
+ mb->sm_use_count-- ;
+ DB_GEN("free_mbuf: sm_use_count = %d",mb->sm_use_count,0,3) ;
+ /*
+ * If the use_count is != zero the MBuf is queued
+ * more than once and must not queued into the
+ * free MBuf queue
+ */
+ if (!mb->sm_use_count) {
+ DB_GEN("free SMbuf: mb = %x",(void *)mb,0,3) ;
+#ifndef COMMON_MB_POOL
+ mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ;
+ smc->os.hwm.mbuf_pool.mb_free = mb ;
+#else
+ mb->sm_next = mb_free ;
+ mb_free = mb ;
+#endif
+ }
+ }
+ else
+ SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ;
+}
+
+
+/*
+ * BEGIN_MANUAL_ENTRY(mac_drv_repair_descr)
+ * void mac_drv_repair_descr(smc)
+ *
+ * function called from SMT (HWM / hwmtm.c)
+ * The BMU is idle when this function is called.
+ * Mac_drv_repair_descr sets up the physical address
+ * for all receive and transmit queues where the BMU
+ * should continue.
+ * It may be that the BMU was reseted during a fragmented
+ * transfer. In this case there are some fragments which will
+ * never completed by the BMU. The OWN bit of this fragments
+ * must be switched to be owned by the host.
+ *
+ * Give a start command to the receive BMU.
+ * Start the transmit BMUs if transmit frames pending.
+ *
+ * END_MANUAL_ENTRY
+ */
+void mac_drv_repair_descr(smc)
+struct s_smc *smc ;
+{
+ u_long phys ;
+
+ if (smc->hw.hw_state != STOPPED) {
+ SK_BREAK() ;
+ SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ;
+ return ;
+ }
+
+ /*
+ * repair tx queues: don't start
+ */
+ phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ;
+ outpd(ADDR(B5_XA_DA),phys) ;
+ if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) {
+ outpd(ADDR(B0_XA_CSR),CSR_START) ;
+ }
+ phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ;
+ outpd(ADDR(B5_XS_DA),phys) ;
+ if (smc->hw.fp.tx_q[QUEUE_S].tx_used) {
+ outpd(ADDR(B0_XS_CSR),CSR_START) ;
+ }
+
+ /*
+ * repair rx queues
+ */
+ phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ;
+ outpd(ADDR(B4_R1_DA),phys) ;
+ outpd(ADDR(B0_R1_CSR),CSR_START) ;
+}
+
+static u_long repair_txd_ring(smc,queue)
+struct s_smc *smc ;
+struct s_smt_tx_queue *queue ;
+{
+ int i ;
+ int tx_used ;
+ u_long phys ;
+ u_long tbctrl ;
+ struct s_smt_fp_txd volatile *t ;
+
+ SK_UNUSED(smc) ;
+
+ t = queue->tx_curr_get ;
+ tx_used = queue->tx_used ;
+ for (i = tx_used+queue->tx_free-1 ; i ; i-- ) {
+ t = t->txd_next ;
+ }
+ phys = AIX_REVERSE(t->txd_ntdadr) ;
+
+ t = queue->tx_curr_get ;
+ while (tx_used) {
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
+ tbctrl = AIX_REVERSE(t->txd_tbctrl) ;
+
+ if (tbctrl & BMU_OWN) {
+ if (tbctrl & BMU_STF) {
+ break ; /* exit the loop */
+ }
+ else {
+ /*
+ * repair the descriptor
+ */
+ t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ;
+ }
+ }
+ phys = AIX_REVERSE(t->txd_ntdadr) ;
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+ t = t->txd_next ;
+ tx_used-- ;
+ }
+ return(phys) ;
+}
+
+/*
+ * Repairs the receive descriptor ring and returns the physical address
+ * where the BMU should continue working.
+ *
+ * o The physical address where the BMU was stopped has to be
+ * determined. This is the next RxD after rx_curr_get with an OWN
+ * bit set.
+ * o The BMU should start working at beginning of the next frame.
+ * RxDs with an OWN bit set but with a reset STF bit should be
+ * skipped and owned by the driver (OWN = 0).
+ */
+static u_long repair_rxd_ring(smc,queue)
+struct s_smc *smc ;
+struct s_smt_rx_queue *queue ;
+{
+ int i ;
+ int rx_used ;
+ u_long phys ;
+ u_long rbctrl ;
+ struct s_smt_fp_rxd volatile *r ;
+
+ SK_UNUSED(smc) ;
+
+ r = queue->rx_curr_get ;
+ rx_used = queue->rx_used ;
+ for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) {
+ r = r->rxd_next ;
+ }
+ phys = AIX_REVERSE(r->rxd_nrdadr) ;
+
+ r = queue->rx_curr_get ;
+ while (rx_used) {
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+ rbctrl = AIX_REVERSE(r->rxd_rbctrl) ;
+
+ if (rbctrl & BMU_OWN) {
+ if (rbctrl & BMU_STF) {
+ break ; /* exit the loop */
+ }
+ else {
+ /*
+ * repair the descriptor
+ */
+ r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+ }
+ }
+ phys = AIX_REVERSE(r->rxd_nrdadr) ;
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+ r = r->rxd_next ;
+ rx_used-- ;
+ }
+ return(phys) ;
+}
+
+
+/*
+ -------------------------------------------------------------
+ INTERRUPT SERVICE ROUTINE:
+ -------------------------------------------------------------
+*/
+
+/*
+ * BEGIN_MANUAL_ENTRY(fddi_isr)
+ * void fddi_isr(smc)
+ *
+ * function DOWNCALL (drvsr.c)
+ * interrupt service routine, handles the interrupt requests
+ * generated by the FDDI adapter.
+ *
+ * NOTE: The operating system dependent module must garantee that the
+ * interrupts of the adapter are disabled when it calls fddi_isr.
+ *
+ * About the USE_BREAK_ISR mechanismn:
+ *
+ * The main requirement of this mechanismn is to force an timer IRQ when
+ * leaving process_receive() with leave_isr set. process_receive() may
+ * be called at any time from anywhere!
+ * To be sure we don't miss such event we set 'force_irq' per default.
+ * We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND
+ * 'force_irq' are set. 'force_irq' may be reset if a receive complete
+ * IRQ is pending.
+ *
+ * END_MANUAL_ENTRY
+ */
+void fddi_isr(smc)
+struct s_smc *smc ;
+{
+ u_long is ; /* ISR source */
+ u_short stu, stl ;
+ SMbuf *mb ;
+
+#ifdef USE_BREAK_ISR
+ int force_irq ;
+#endif
+
+#ifdef ODI2
+ if (smc->os.hwm.rx_break) {
+ mac_drv_fill_rxd(smc) ;
+ if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) {
+ smc->os.hwm.rx_break = 0 ;
+ process_receive(smc) ;
+ }
+ else {
+ smc->os.hwm.detec_count = 0 ;
+ smt_force_irq(smc) ;
+ }
+ }
+#endif
+ smc->os.hwm.isr_flag = TRUE ;
+
+#ifdef USE_BREAK_ISR
+ force_irq = TRUE ;
+ if (smc->os.hwm.leave_isr) {
+ smc->os.hwm.leave_isr = FALSE ;
+ process_receive(smc) ;
+ }
+#endif
+
+ while ((is = GET_ISR() & ISR_MASK)) {
+ NDD_TRACE("CH0B",is,0,0) ;
+ DB_GEN("ISA = 0x%x",is,0,7) ;
+
+ if (is & IMASK_SLOW) {
+ NDD_TRACE("CH1b",is,0,0) ;
+ if (is & IS_PLINT1) { /* PLC1 */
+ plc1_irq(smc) ;
+ }
+ if (is & IS_PLINT2) { /* PLC2 */
+ plc2_irq(smc) ;
+ }
+ if (is & IS_MINTR1) { /* FORMAC+ STU1(U/L) */
+ stu = inpw(FM_A(FM_ST1U)) ;
+ stl = inpw(FM_A(FM_ST1L)) ;
+ DB_GEN("Slow transmit complete",0,0,6) ;
+ mac1_irq(smc,stu,stl) ;
+ }
+ if (is & IS_MINTR2) { /* FORMAC+ STU2(U/L) */
+ stu= inpw(FM_A(FM_ST2U)) ;
+ stl= inpw(FM_A(FM_ST2L)) ;
+ DB_GEN("Slow receive complete",0,0,6) ;
+ DB_GEN("stl = %x : stu = %x",stl,stu,7) ;
+ mac2_irq(smc,stu,stl) ;
+ }
+ if (is & IS_MINTR3) { /* FORMAC+ STU3(U/L) */
+ stu= inpw(FM_A(FM_ST3U)) ;
+ stl= inpw(FM_A(FM_ST3L)) ;
+ DB_GEN("FORMAC Mode Register 3",0,0,6) ;
+ mac3_irq(smc,stu,stl) ;
+ }
+ if (is & IS_TIMINT) { /* Timer 82C54-2 */
+ timer_irq(smc) ;
+#ifdef NDIS_OS2
+ force_irq_pending = 0 ;
+#endif
+ /*
+ * out of RxD detection
+ */
+ if (++smc->os.hwm.detec_count > 4) {
+ /*
+ * check out of RxD condition
+ */
+ process_receive(smc) ;
+ }
+ }
+ if (is & IS_TOKEN) { /* Restricted Token Monitor */
+ rtm_irq(smc) ;
+ }
+ if (is & IS_R1_P) { /* Parity error rx queue 1 */
+ /* clear IRQ */
+ outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ;
+ SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ;
+ }
+ if (is & IS_R1_C) { /* Encoding error rx queue 1 */
+ /* clear IRQ */
+ outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ;
+ SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ;
+ }
+ if (is & IS_XA_C) { /* Encoding error async tx q */
+ /* clear IRQ */
+ outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ;
+ SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ;
+ }
+ if (is & IS_XS_C) { /* Encoding error sync tx q */
+ /* clear IRQ */
+ outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ;
+ SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ;
+ }
+ }
+
+ /*
+ * Fast Tx complete Async/Sync Queue (BMU service)
+ */
+ if (is & (IS_XS_F|IS_XA_F)) {
+ DB_GEN("Fast tx complete queue",0,0,6) ;
+ /*
+ * clear IRQ, Note: no IRQ is lost, because
+ * we always service both queues
+ */
+ outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ;
+ outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ;
+ mac_drv_clear_txd(smc) ;
+ llc_restart_tx(smc) ;
+ }
+
+ /*
+ * Fast Rx Complete (BMU service)
+ */
+ if (is & IS_R1_F) {
+ DB_GEN("Fast receive complete",0,0,6) ;
+ /* clear IRQ */
+#ifndef USE_BREAK_ISR
+ outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
+ process_receive(smc) ;
+#else
+ process_receive(smc) ;
+ if (smc->os.hwm.leave_isr) {
+ force_irq = FALSE ;
+ } else {
+ outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
+ process_receive(smc) ;
+ }
+#endif
+ }
+
+#ifndef NDIS_OS2
+ while ((mb = get_llc_rx(smc))) {
+ smt_to_llc(smc,mb) ;
+ }
+#else
+ if (offDepth)
+ post_proc() ;
+
+ while (!offDepth && (mb = get_llc_rx(smc))) {
+ smt_to_llc(smc,mb) ;
+ }
+
+ if (!offDepth && smc->os.hwm.rx_break) {
+ process_receive(smc) ;
+ }
+#endif
+ if (smc->q.ev_get != smc->q.ev_put) {
+ NDD_TRACE("CH2a",0,0,0) ;
+ ev_dispatcher(smc) ;
+ }
+#ifdef NDIS_OS2
+ post_proc() ;
+ if (offDepth) { /* leave fddi_isr because */
+ break ; /* indications not allowed */
+ }
+#endif
+#ifdef USE_BREAK_ISR
+ if (smc->os.hwm.leave_isr) {
+ break ; /* leave fddi_isr */
+ }
+#endif
+
+ /* NOTE: when the isr is left, no rx is pending */
+ } /* end of interrupt source polling loop */
+
+#ifdef USE_BREAK_ISR
+ if (smc->os.hwm.leave_isr && force_irq) {
+ smt_force_irq(smc) ;
+ }
+#endif
+ smc->os.hwm.isr_flag = FALSE ;
+ NDD_TRACE("CH0E",0,0,0) ;
+}
+
+
+/*
+ -------------------------------------------------------------
+ RECEIVE FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+#ifndef NDIS_OS2
+/*
+ * BEGIN_MANUAL_ENTRY(mac_drv_rx_mode)
+ * void mac_drv_rx_mode(smc,mode)
+ *
+ * function DOWNCALL (fplus.c)
+ * Corresponding to the parameter mode, the operating system
+ * dependent module can activate several receive modes.
+ *
+ * para mode = 1: RX_ENABLE_ALLMULTI enable all multicasts
+ * = 2: RX_DISABLE_ALLMULTI disable "enable all multicasts"
+ * = 3: RX_ENABLE_PROMISC enable promiscuous
+ * = 4: RX_DISABLE_PROMISC disable promiscuous
+ * = 5: RX_ENABLE_NSA enable rec. of all NSA frames
+ * (disabled after 'driver reset' & 'set station address')
+ * = 6: RX_DISABLE_NSA disable rec. of all NSA frames
+ *
+ * = 21: RX_ENABLE_PASS_SMT ( see description )
+ * = 22: RX_DISABLE_PASS_SMT ( " " )
+ * = 23: RX_ENABLE_PASS_NSA ( " " )
+ * = 24: RX_DISABLE_PASS_NSA ( " " )
+ * = 25: RX_ENABLE_PASS_DB ( " " )
+ * = 26: RX_DISABLE_PASS_DB ( " " )
+ * = 27: RX_DISABLE_PASS_ALL ( " " )
+ * = 28: RX_DISABLE_LLC_PROMISC ( " " )
+ * = 29: RX_ENABLE_LLC_PROMISC ( " " )
+ *
+ *
+ * RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT
+ *
+ * If the operating system dependent module activates the
+ * mode RX_ENABLE_PASS_SMT, the hardware module
+ * duplicates all SMT frames with the frame control
+ * FC_SMT_INFO and passes them to the LLC receive channel
+ * by calling mac_drv_rx_init.
+ * The SMT Frames which are sent by the local SMT and the NSA
+ * frames whose A- and C-Indicator is not set are also duplicated
+ * and passed.
+ * The receive mode RX_DISABLE_PASS_SMT disables the passing
+ * of SMT frames.
+ *
+ * RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA
+ *
+ * If the operating system dependent module activates the
+ * mode RX_ENABLE_PASS_NSA, the hardware module
+ * duplicates all NSA frames with frame control FC_SMT_NSA
+ * and a set A-Indicator and passed them to the LLC
+ * receive channel by calling mac_drv_rx_init.
+ * All NSA Frames which are sent by the local SMT
+ * are also duplicated and passed.
+ * The receive mode RX_DISABLE_PASS_NSA disables the passing
+ * of NSA frames with the A- or C-Indicator set.
+ *
+ * NOTE: For fear that the hardware module receives NSA frames with
+ * a reset A-Indicator, the operating system dependent module
+ * has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA
+ * before activate the RX_ENABLE_PASS_NSA mode and after every
+ * 'driver reset' and 'set station address'.
+ *
+ * RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB
+ *
+ * If the operating system dependent module activates the
+ * mode RX_ENABLE_PASS_DB, direct BEACON frames
+ * (FC_BEACON frame control) are passed to the LLC receive
+ * channel by mac_drv_rx_init.
+ * The receive mode RX_DISABLE_PASS_DB disables the passing
+ * of direct BEACON frames.
+ *
+ * RX_DISABLE_PASS_ALL
+ *
+ * Disables all special receives modes. It is equal to
+ * call mac_drv_set_rx_mode successively with the
+ * parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT,
+ * RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB.
+ *
+ * RX_ENABLE_LLC_PROMISC
+ *
+ * (default) all received LLC frames and all SMT/NSA/DBEACON
+ * frames depending on the attitude of the flags
+ * PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the
+ * LLC layer
+ *
+ * RX_DISABLE_LLC_PROMISC
+ *
+ * all received SMT/NSA/DBEACON frames depending on the
+ * attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON
+ * will be delivered to the LLC layer.
+ * all received LLC frames with a directed address, Multicast
+ * or Broadcast address will be delivered to the LLC
+ * layer too.
+ *
+ * END_MANUAL_ENTRY
+ */
+void mac_drv_rx_mode(smc,mode)
+struct s_smc *smc ;
+int mode ;
+{
+ switch(mode) {
+ case RX_ENABLE_PASS_SMT:
+ smc->os.hwm.pass_SMT = TRUE ;
+ break ;
+ case RX_DISABLE_PASS_SMT:
+ smc->os.hwm.pass_SMT = FALSE ;
+ break ;
+ case RX_ENABLE_PASS_NSA:
+ smc->os.hwm.pass_NSA = TRUE ;
+ break ;
+ case RX_DISABLE_PASS_NSA:
+ smc->os.hwm.pass_NSA = FALSE ;
+ break ;
+ case RX_ENABLE_PASS_DB:
+ smc->os.hwm.pass_DB = TRUE ;
+ break ;
+ case RX_DISABLE_PASS_DB:
+ smc->os.hwm.pass_DB = FALSE ;
+ break ;
+ case RX_DISABLE_PASS_ALL:
+ smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ;
+ smc->os.hwm.pass_DB = FALSE ;
+ smc->os.hwm.pass_llc_promisc = TRUE ;
+ mac_set_rx_mode(smc,RX_DISABLE_NSA) ;
+ break ;
+ case RX_DISABLE_LLC_PROMISC:
+ smc->os.hwm.pass_llc_promisc = FALSE ;
+ break ;
+ case RX_ENABLE_LLC_PROMISC:
+ smc->os.hwm.pass_llc_promisc = TRUE ;
+ break ;
+ case RX_ENABLE_ALLMULTI:
+ case RX_DISABLE_ALLMULTI:
+ case RX_ENABLE_PROMISC:
+ case RX_DISABLE_PROMISC:
+ case RX_ENABLE_NSA:
+ case RX_DISABLE_NSA:
+ default:
+ mac_set_rx_mode(smc,mode) ;
+ break ;
+ }
+}
+#endif /* ifndef NDIS_OS2 */
+
+/*
+ * process receive queue
+ */
+void process_receive(smc)
+struct s_smc *smc ;
+{
+ int i ;
+ int n ;
+ int frag_count ; /* number of RxDs of the curr rx buf */
+ int used_frags ; /* number of RxDs of the curr frame */
+ struct s_smt_rx_queue *queue ; /* points to the queue ctl struct */
+ struct s_smt_fp_rxd volatile *r ; /* rxd pointer */
+ struct s_smt_fp_rxd volatile *rxd ; /* first rxd of rx frame */
+ u_long rbctrl ; /* receive buffer control word */
+ u_long rfsw ; /* receive frame status word */
+ u_short rx_used ;
+ u_char far *virt ;
+ char far *data ;
+ SMbuf *mb ;
+ u_char fc ; /* Frame control */
+ int len ; /* Frame length */
+
+ smc->os.hwm.detec_count = 0 ;
+ queue = smc->hw.fp.rx[QUEUE_R1] ;
+ NDD_TRACE("RHxB",0,0,0) ;
+ for ( ; ; ) {
+ r = queue->rx_curr_get ;
+ rx_used = queue->rx_used ;
+ frag_count = 0 ;
+
+#ifdef USE_BREAK_ISR
+ if (smc->os.hwm.leave_isr) {
+ goto rx_end ;
+ }
+#endif
+#ifdef NDIS_OS2
+ if (offDepth) {
+ smc->os.hwm.rx_break = 1 ;
+ goto rx_end ;
+ }
+ smc->os.hwm.rx_break = 0 ;
+#endif
+#ifdef ODI2
+ if (smc->os.hwm.rx_break) {
+ goto rx_end ;
+ }
+#endif
+ n = 0 ;
+ do {
+ DB_RX("Check RxD %x for OWN and EOF",(void *)r,0,5) ;
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+ rbctrl = CR_READ(r->rxd_rbctrl) ;
+#ifdef AIX
+ rbctrl = AIX_REVERSE(rbctrl) ;
+#endif
+ if (rbctrl & BMU_OWN) {
+ NDD_TRACE("RHxE",r,rfsw,rbctrl) ;
+ DB_RX("End of RxDs",0,0,4) ;
+ goto rx_end ;
+ }
+ /*
+ * out of RxD detection
+ */
+ if (!rx_used) {
+ SK_BREAK() ;
+ SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ;
+ /* Either we don't have an RxD or all
+ * RxDs are filled. Therefore it's allowed
+ * for to set the STOPPED flag */
+ smc->hw.hw_state = STOPPED ;
+ mac_drv_clear_rx_queue(smc) ;
+ smc->hw.hw_state = STARTED ;
+ mac_drv_fill_rxd(smc) ;
+ smc->os.hwm.detec_count = 0 ;
+ goto rx_end ;
+ }
+ rfsw = AIX_REVERSE(r->rxd_rfsw) ;
+ if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) {
+ /*
+ * The BMU_STF bit is deleted, 1 frame is
+ * placed into more than 1 rx buffer
+ *
+ * skip frame by setting the rx len to 0
+ *
+ * if fragment count == 0
+ * The missing STF bit belongs to the
+ * current frame, search for the
+ * EOF bit to complete the frame
+ * else
+ * the fragment belongs to the next frame,
+ * exit the loop and process the frame
+ */
+ SK_BREAK() ;
+ rfsw = 0 ;
+ if (frag_count) {
+ break ;
+ }
+ }
+ n += rbctrl & 0xffff ;
+ r = r->rxd_next ;
+ frag_count++ ;
+ rx_used-- ;
+ } while (!(rbctrl & BMU_EOF)) ;
+ used_frags = frag_count ;
+ DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ;
+
+ /* may be next 2 DRV_BUF_FLUSH() can be skipped, because */
+ /* BMU_ST_BUF will not be changed by the ASIC */
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+ while (rx_used && !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) {
+ DB_RX("Check STF bit in %x",(void *)r,0,5) ;
+ r = r->rxd_next ;
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+ frag_count++ ;
+ rx_used-- ;
+ }
+ DB_RX("STF bit found",0,0,5) ;
+
+ /*
+ * The received frame is finished for the process receive
+ */
+ rxd = queue->rx_curr_get ;
+ queue->rx_curr_get = r ;
+ queue->rx_free += frag_count ;
+ queue->rx_used = rx_used ;
+
+ /*
+ * ASIC Errata no. 7 (STF - Bit Bug)
+ */
+ rxd->rxd_rbctrl &= AIX_REVERSE(~BMU_STF) ;
+
+ for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){
+ DB_RX("dma_complete for RxD %x",(void *)r,0,5) ;
+ dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
+ }
+ smc->hw.fp.err_stats.err_valid++ ;
+ smc->mib.m[MAC0].fddiMACCopied_Ct++ ;
+
+ /* the length of the data including the FC */
+ len = (rfsw & RD_LENGTH) - 4 ;
+
+ DB_RX("frame length = %d",len,0,4) ;
+ /*
+ * check the frame_lenght and all error flags
+ */
+ if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){
+ if (rfsw & RD_S_MSRABT) {
+ DB_RX("Frame aborted by the FORMAC",0,0,2) ;
+ smc->hw.fp.err_stats.err_abort++ ;
+ }
+ /*
+ * check frame status
+ */
+ if (rfsw & RD_S_SEAC2) {
+ DB_RX("E-Indicator set",0,0,2) ;
+ smc->hw.fp.err_stats.err_e_indicator++ ;
+ }
+ if (rfsw & RD_S_SFRMERR) {
+ DB_RX("CRC error",0,0,2) ;
+ smc->hw.fp.err_stats.err_crc++ ;
+ }
+ if (rfsw & RX_FS_IMPL) {
+ DB_RX("Implementer frame",0,0,2) ;
+ smc->hw.fp.err_stats.err_imp_frame++ ;
+ }
+ goto abort_frame ;
+ }
+ if (len > FDDI_RAW_MTU-4) {
+ DB_RX("Frame to long error",0,0,2) ;
+ smc->hw.fp.err_stats.err_too_long++ ;
+ goto abort_frame ;
+ }
+ /*
+ * SUPERNET 3 Bug: FORMAC delivers status words
+ * of aborded frames to the BMU
+ */
+ if (len <= 4) {
+ DB_RX("Frame length = 0",0,0,2) ;
+ goto abort_frame ;
+ }
+
+ if (len != (n-4)) {
+ DB_RX("BMU: rx len differs: [%d:%d]",len,n,4);
+ smc->os.hwm.rx_len_error++ ;
+ goto abort_frame ;
+ }
+
+ /*
+ * Check SA == MA
+ */
+ virt = (u_char far *) rxd->rxd_virt ;
+ DB_RX("FC = %x",*virt,0,2) ;
+ if (virt[12] == MA[5] &&
+ virt[11] == MA[4] &&
+ virt[10] == MA[3] &&
+ virt[9] == MA[2] &&
+ virt[8] == MA[1] &&
+ (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) {
+ goto abort_frame ;
+ }
+
+ /*
+ * test if LLC frame
+ */
+ if (rfsw & RX_FS_LLC) {
+ /*
+ * if pass_llc_promisc is disable
+ * if DA != Multicast or Broadcast or DA!=MA
+ * abort the frame
+ */
+ if (!smc->os.hwm.pass_llc_promisc) {
+ if(!(virt[1] & GROUP_ADDR_BIT)) {
+ if (virt[6] != MA[5] ||
+ virt[5] != MA[4] ||
+ virt[4] != MA[3] ||
+ virt[3] != MA[2] ||
+ virt[2] != MA[1] ||
+ virt[1] != MA[0]) {
+ DB_RX("DA != MA and not multi- or broadcast",0,0,2) ;
+ goto abort_frame ;
+ }
+ }
+ }
+
+ /*
+ * LLC frame received
+ */
+ DB_RX("LLC - receive",0,0,4) ;
+ mac_drv_rx_complete(smc,rxd,frag_count,len) ;
+ }
+ else {
+ if (!(mb = smt_get_mbuf(smc))) {
+ smc->hw.fp.err_stats.err_no_buf++ ;
+ DB_RX("No SMbuf; receive terminated",0,0,4) ;
+ goto abort_frame ;
+ }
+ data = smtod(mb,char *) - 1 ;
+
+ /*
+ * copy the frame into a SMT_MBuf
+ */
+#ifdef USE_OS_CPY
+ hwm_cpy_rxd2mb(rxd,data,len) ;
+#else
+ for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){
+ n = AIX_REVERSE(r->rxd_rbctrl) & RD_LENGTH ;
+ DB_RX("cp SMT frame to mb: len = %d",n,0,6) ;
+ memcpy(data,r->rxd_virt,n) ;
+ data += n ;
+ }
+ data = smtod(mb,char *) - 1 ;
+#endif
+ fc = *(char *)mb->sm_data = *data ;
+ mb->sm_len = len - 1 ; /* len - fc */
+ data++ ;
+
+ /*
+ * SMT frame received
+ */
+ switch(fc) {
+ case FC_SMT_INFO :
+ smc->hw.fp.err_stats.err_smt_frame++ ;
+ DB_RX("SMT frame received ",0,0,5) ;
+
+ if (smc->os.hwm.pass_SMT) {
+ DB_RX("pass SMT frame ",0,0,5) ;
+ mac_drv_rx_complete(smc, rxd,
+ frag_count,len) ;
+ }
+ else {
+ DB_RX("requeue RxD",0,0,5) ;
+ mac_drv_requeue_rxd(smc,rxd,frag_count);
+ }
+
+ smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
+ break ;
+ case FC_SMT_NSA :
+ smc->hw.fp.err_stats.err_smt_frame++ ;
+ DB_RX("SMT frame received ",0,0,5) ;
+
+ /* if pass_NSA set pass the NSA frame or */
+ /* pass_SMT set and the A-Indicator */
+ /* is not set, pass the NSA frame */
+ if (smc->os.hwm.pass_NSA ||
+ (smc->os.hwm.pass_SMT &&
+ !(rfsw & A_INDIC))) {
+ DB_RX("pass SMT frame ",0,0,5) ;
+ mac_drv_rx_complete(smc, rxd,
+ frag_count,len) ;
+ }
+ else {
+ DB_RX("requeue RxD",0,0,5) ;
+ mac_drv_requeue_rxd(smc,rxd,frag_count);
+ }
+
+ smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
+ break ;
+ case FC_BEACON :
+ if (smc->os.hwm.pass_DB) {
+ DB_RX("pass DB frame ",0,0,5) ;
+ mac_drv_rx_complete(smc, rxd,
+ frag_count,len) ;
+ }
+ else {
+ DB_RX("requeue RxD",0,0,5) ;
+ mac_drv_requeue_rxd(smc,rxd,frag_count);
+ }
+ smt_free_mbuf(smc,mb) ;
+ break ;
+ default :
+ /*
+ * unknown FC abord the frame
+ */
+ DB_RX("unknown FC error",0,0,2) ;
+ smt_free_mbuf(smc,mb) ;
+ DB_RX("requeue RxD",0,0,5) ;
+ mac_drv_requeue_rxd(smc,rxd,frag_count) ;
+ if ((fc & 0xf0) == FC_MAC)
+ smc->hw.fp.err_stats.err_mac_frame++ ;
+ else
+ smc->hw.fp.err_stats.err_imp_frame++ ;
+
+ break ;
+ }
+ }
+
+ DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ;
+ NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ;
+
+ continue ;
+ /*--------------------------------------------------------------------*/
+abort_frame:
+ DB_RX("requeue RxD",0,0,5) ;
+ mac_drv_requeue_rxd(smc,rxd,frag_count) ;
+
+ DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ;
+ NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ;
+ }
+rx_end:
+#ifdef ALL_RX_COMPLETE
+ mac_drv_all_receives_complete(smc) ;
+#endif
+ return ; /* lint bug: needs return detect end of function */
+}
+
+static void smt_to_llc(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+ u_char fc ;
+
+ DB_RX("send a queued frame to the llc layer",0,0,4) ;
+ smc->os.hwm.r.len = mb->sm_len ;
+ smc->os.hwm.r.mb_pos = smtod(mb,char *) ;
+ fc = *smc->os.hwm.r.mb_pos ;
+ (void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc,
+ smc->os.hwm.r.mb_pos,(int)mb->sm_len) ;
+ smt_free_mbuf(smc,mb) ;
+}
+
+/*
+ * BEGIN_MANUAL_ENTRY(hwm_rx_frag)
+ * void hwm_rx_frag(smc,virt,phys,len,frame_status)
+ *
+ * function MACRO (hardware module, hwmtm.h)
+ * This function calls dma_master for preparing the
+ * system hardware for the DMA transfer and initializes
+ * the current RxD with the length and the physical and
+ * virtual address of the fragment. Furthermore, it sets the
+ * STF and EOF bits depending on the frame status byte,
+ * switches the OWN flag of the RxD, so that it is owned by the
+ * adapter and issues an rx_start.
+ *
+ * para virt virtual pointer to the fragment
+ * len the length of the fragment
+ * frame_status status of the frame, see design description
+ *
+ * NOTE: It is possible to call this function with a fragment length
+ * of zero.
+ *
+ * END_MANUAL_ENTRY
+ */
+void hwm_rx_frag(smc,virt,phys,len,frame_status)
+struct s_smc *smc ;
+char far *virt ;
+u_long phys ;
+int len ;
+int frame_status ;
+{
+ struct s_smt_fp_rxd volatile *r ;
+#ifdef AIX
+ u_long rbctrl ;
+#endif
+
+ NDD_TRACE("RHfB",virt,len,frame_status) ;
+ DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ;
+ r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ;
+ r->rxd_virt = virt ;
+ r->rxd_rbadr = AIX_REVERSE(phys) ;
+#ifndef AIX
+ r->rxd_rbctrl = (((u_long)frame_status & (FIRST_FRAG|LAST_FRAG))<<26) |
+ (((u_long) frame_status & FIRST_FRAG) << 21) |
+ BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len ;
+#else
+ rbctrl = AIX_REVERSE( (((u_long)frame_status &
+ (FIRST_FRAG|LAST_FRAG))<<26) |
+ (((u_long) frame_status & FIRST_FRAG) << 21) |
+ BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ;
+ r->rxd_rbctrl = rbctrl ;
+#endif
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+ outpd(ADDR(B0_R1_CSR),CSR_START) ;
+ smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ;
+ smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ;
+ smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ;
+ NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
+}
+
+#ifndef NDIS_OS2
+/*
+ * BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
+ * int mac_drv_rx_frag(smc,virt,len)
+ *
+ * function DOWNCALL (hwmtm.c)
+ * mac_drv_rx_frag fills the fragment with a part of the frame.
+ *
+ * para virt the virtual address of the fragment
+ * len the length in bytes of the fragment
+ *
+ * return 0: success code, no errors possible
+ *
+ * END_MANUAL_ENTRY
+ */
+int mac_drv_rx_frag(smc,virt,len)
+struct s_smc *smc ;
+void far *virt ;
+int len ;
+{
+ NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
+
+ DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
+ memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
+ smc->os.hwm.r.mb_pos += len ;
+
+ NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
+ return(0) ;
+}
+#endif
+
+
+/*
+ * BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
+ *
+ * void mac_drv_clear_rx_queue(smc)
+ * struct s_smc *smc ;
+ *
+ * function DOWNCALL (hardware module, hwmtm.c)
+ * mac_drv_clear_rx_queue is called by the OS-specific module
+ * after it has issued a card_stop.
+ * In this case, the frames in the receive queue are obsolete and
+ * should be removed. For removing mac_drv_clear_rx_queue
+ * calls dma_master for each RxD and mac_drv_clear_rxd for each
+ * receive buffer.
+ *
+ * NOTE: calling sequence card_stop:
+ * CLI_FBI(), card_stop(),
+ * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
+ *
+ * NOTE: The caller is responsible that the BMUs are idle
+ * when this function is called.
+ *
+ * END_MANUAL_ENTRY
+ */
+void mac_drv_clear_rx_queue(smc)
+struct s_smc *smc ;
+{
+ struct s_smt_fp_rxd volatile *r ;
+ struct s_smt_fp_rxd volatile *next_rxd ;
+ struct s_smt_rx_queue *queue ;
+ int frag_count ;
+ int i ;
+
+ if (smc->hw.hw_state != STOPPED) {
+ SK_BREAK() ;
+ SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ;
+ return ;
+ }
+
+ queue = smc->hw.fp.rx[QUEUE_R1] ;
+ DB_RX("clear_rx_queue",0,0,5) ;
+
+ /*
+ * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers
+ */
+ r = queue->rx_curr_get ;
+ while (queue->rx_used) {
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+ DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ;
+ r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+ frag_count = 1 ;
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+ r = r->rxd_next ;
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+ while (r != queue->rx_curr_put &&
+ !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) {
+ DB_RX("Check STF bit in %x",(void *)r,0,5) ;
+ r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+ r = r->rxd_next ;
+ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+ frag_count++ ;
+ }
+ DB_RX("STF bit found",0,0,5) ;
+ next_rxd = r ;
+
+ for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){
+ DB_RX("dma_complete for RxD %x",(void *)r,0,5) ;
+ dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
+ }
+
+ DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ",
+ (void *)queue->rx_curr_get,frag_count,5) ;
+ mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ;
+
+ queue->rx_curr_get = next_rxd ;
+ queue->rx_used -= frag_count ;
+ queue->rx_free += frag_count ;
+ }
+}
+
+
+/*
+ -------------------------------------------------------------
+ SEND FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+/*
+ * BEGIN_MANUAL_ENTRY(hwm_tx_init)
+ * int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
+ *
+ * function DOWN_CALL (hardware module, hwmtm.c)
+ * hwm_tx_init checks if the frame can be sent through the
+ * corresponding send queue.
+ *
+ * para fc the frame control. To determine through which
+ * send queue the frame should be transmitted.
+ * 0x50 - 0x57: asynchronous LLC frame
+ * 0xD0 - 0xD7: synchronous LLC frame
+ * 0x41, 0x4F: SMT frame to the network
+ * 0x42: SMT frame to the network and to the local SMT
+ * 0x43: SMT frame to the local SMT
+ * frag_count count of the fragments for this frame
+ * frame_len length of the frame
+ * frame_status status of the frame, the send queue bit is already
+ * specified
+ *
+ * return frame_status
+ *
+ * END_MANUAL_ENTRY
+ */
+int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
+struct s_smc *smc ;
+u_char fc ;
+int frag_count ;
+int frame_len ;
+int frame_status ;
+{
+ NDD_TRACE("THiB",fc,frag_count,frame_len) ;
+ smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ;
+ smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ;
+ smc->os.hwm.tx_len = frame_len ;
+ DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ;
+ if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
+ frame_status |= LAN_TX ;
+ }
+ else {
+ switch (fc) {
+ case FC_SMT_INFO :
+ case FC_SMT_NSA :
+ frame_status |= LAN_TX ;
+ break ;
+ case FC_SMT_LOC :
+ frame_status |= LOC_TX ;
+ break ;
+ case FC_SMT_LAN_LOC :
+ frame_status |= LAN_TX | LOC_TX ;
+ break ;
+ default :
+ SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ;
+ }
+ }
+ if (!smc->hw.mac_ring_is_up) {
+ frame_status &= ~LAN_TX ;
+ frame_status |= RING_DOWN ;
+ DB_TX("Ring is down: terminate LAN_TX",0,0,2) ;
+ }
+ if (frag_count > smc->os.hwm.tx_p->tx_free) {
+#ifndef NDIS_OS2
+ mac_drv_clear_txd(smc) ;
+ if (frag_count > smc->os.hwm.tx_p->tx_free) {
+ DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ;
+ frame_status &= ~LAN_TX ;
+ frame_status |= OUT_OF_TXD ;
+ }
+#else
+ DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ;
+ frame_status &= ~LAN_TX ;
+ frame_status |= OUT_OF_TXD ;
+#endif
+ }
+ DB_TX("frame_status = %x",frame_status,0,3) ;
+ NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ;
+ return(frame_status) ;
+}
+
+/*
+ * BEGIN_MANUAL_ENTRY(hwm_tx_frag)
+ * void hwm_tx_frag(smc,virt,phys,len,frame_status)
+ *
+ * function DOWNCALL (hardware module, hwmtm.c)
+ * If the frame should be sent to the LAN, this function calls
+ * dma_master, fills the current TxD with the virtual and the
+ * physical address, sets the STF and EOF bits dependent on
+ * the frame status, and requests the BMU to start the
+ * transmit.
+ * If the frame should be sent to the local SMT, an SMT_MBuf
+ * is allocated if the FIRST_FRAG bit is set in the frame_status.
+ * The fragment of the frame is copied into the SMT MBuf.
+ * The function smt_received_pack is called if the LAST_FRAG
+ * bit is set in the frame_status word.
+ *
+ * para virt virtual pointer to the fragment
+ * len the length of the fragment
+ * frame_status status of the frame, see design description
+ *
+ * return nothing returned, no parameter is modified
+ *
+ * NOTE: It is possible to invoke this macro with a fragment length
+ * of zero.
+ *
+ * END_MANUAL_ENTRY
+ */
+void hwm_tx_frag(smc,virt,phys,len,frame_status)
+struct s_smc *smc ;
+char far *virt ;
+u_long phys ;
+int len ;
+int frame_status ;
+{
+ struct s_smt_fp_txd volatile *t ;
+ struct s_smt_tx_queue *queue ;
+#ifdef AIX
+ u_long tbctrl ;
+#endif
+
+ queue = smc->os.hwm.tx_p ;
+
+ NDD_TRACE("THfB",virt,len,frame_status) ;
+ /* Bug fix: AF / May 31 1999 (#missing)
+ * snmpinfo problem reported by IBM is caused by invalid
+ * t-pointer (txd) if LAN_TX is not set but LOC_TX only.
+ * Set: t = queue->tx_curr_put here !
+ */
+ t = queue->tx_curr_put ;
+
+ DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ;
+ if (frame_status & LAN_TX) {
+ /* '*t' is already defined */
+ DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ;
+ t->txd_virt = virt ;
+ t->txd_txdscr = AIX_REVERSE(smc->os.hwm.tx_descr) ;
+ t->txd_tbadr = AIX_REVERSE(phys) ;
+#ifndef AIX
+ t->txd_tbctrl = (((u_long)frame_status &
+ (FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) |
+ BMU_OWN|BMU_CHECK |len ;
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+ outpd(queue->tx_bmu_ctl,CSR_START) ;
+
+#else /* ifndef AIX */
+ tbctrl = AIX_REVERSE((((u_long)frame_status &
+ (FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) |
+ BMU_OWN|BMU_CHECK |len) ;
+ t->txd_tbctrl = tbctrl ;
+
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+ if (frame_status & QUEUE_A0) {
+ outpd(ADDR(B0_XA_CSR),CSR_START) ;
+ }
+ else {
+ outpd(ADDR(B0_XS_CSR),CSR_START) ;
+ }
+#endif
+ queue->tx_free-- ;
+ queue->tx_used++ ;
+ queue->tx_curr_put = t->txd_next ;
+ if (frame_status & LAST_FRAG) {
+ smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
+ }
+ }
+ if (frame_status & LOC_TX) {
+ DB_TX("LOC_TX: ",0,0,3) ;
+ if (frame_status & FIRST_FRAG) {
+ if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) {
+ smc->hw.fp.err_stats.err_no_buf++ ;
+ DB_TX("No SMbuf; transmit terminated",0,0,4) ;
+ }
+ else {
+ smc->os.hwm.tx_data =
+ smtod(smc->os.hwm.tx_mb,char *) - 1 ;
+#ifdef USE_OS_CPY
+#ifdef PASS_1ST_TXD_2_TX_COMP
+ hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
+ smc->os.hwm.tx_len) ;
+#endif
+#endif
+ }
+ }
+ if (smc->os.hwm.tx_mb) {
+#ifndef USE_OS_CPY
+ DB_TX("copy fragment into MBuf ",0,0,3) ;
+ memcpy(smc->os.hwm.tx_data,virt,len) ;
+ smc->os.hwm.tx_data += len ;
+#endif
+ if (frame_status & LAST_FRAG) {
+#ifdef USE_OS_CPY
+#ifndef PASS_1ST_TXD_2_TX_COMP
+ /*
+ * hwm_cpy_txd2mb(txd,data,len) copies 'len'
+ * bytes from the virtual pointer in 'rxd'
+ * to 'data'. The virtual pointer of the
+ * os-specific tx-buffer should be written
+ * in the LAST txd.
+ */
+ hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
+ smc->os.hwm.tx_len) ;
+#endif /* nPASS_1ST_TXD_2_TX_COMP */
+#endif /* USE_OS_CPY */
+ smc->os.hwm.tx_data =
+ smtod(smc->os.hwm.tx_mb,char *) - 1 ;
+ *(char *)smc->os.hwm.tx_mb->sm_data =
+ *smc->os.hwm.tx_data ;
+ smc->os.hwm.tx_data++ ;
+ smc->os.hwm.tx_mb->sm_len =
+ smc->os.hwm.tx_len - 1 ;
+ DB_TX("pass LLC frame to SMT ",0,0,3) ;
+ smt_received_pack(smc,smc->os.hwm.tx_mb,
+ RD_FS_LOCAL) ;
+ }
+ }
+ }
+ NDD_TRACE("THfE",t,queue->tx_free,0) ;
+}
+
+
+/*
+ * queues a receive for later send
+ */
+static void queue_llc_rx(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+ DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ;
+ smc->os.hwm.queued_rx_frames++ ;
+ mb->sm_next = (SMbuf *)NULL ;
+ if (smc->os.hwm.llc_rx_pipe == 0) {
+ smc->os.hwm.llc_rx_pipe = mb ;
+ }
+ else {
+ smc->os.hwm.llc_rx_tail->sm_next = mb ;
+ }
+ smc->os.hwm.llc_rx_tail = mb ;
+
+ /*
+ * force an timer IRQ to receive the data
+ */
+ if (!smc->os.hwm.isr_flag) {
+ smt_force_irq(smc) ;
+ }
+}
+
+/*
+ * get a SMbuf from the llc_rx_queue
+ */
+static SMbuf *get_llc_rx(smc)
+struct s_smc *smc ;
+{
+ SMbuf *mb ;
+
+ if ((mb = smc->os.hwm.llc_rx_pipe)) {
+ smc->os.hwm.queued_rx_frames-- ;
+ smc->os.hwm.llc_rx_pipe = mb->sm_next ;
+ }
+ DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ;
+ return(mb) ;
+}
+
+/*
+ * queues a transmit SMT MBuf during the time were the MBuf is
+ * queued the TxD ring
+ */
+static void queue_txd_mb(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+ DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ;
+ smc->os.hwm.queued_txd_mb++ ;
+ mb->sm_next = (SMbuf *)NULL ;
+ if (smc->os.hwm.txd_tx_pipe == 0) {
+ smc->os.hwm.txd_tx_pipe = mb ;
+ }
+ else {
+ smc->os.hwm.txd_tx_tail->sm_next = mb ;
+ }
+ smc->os.hwm.txd_tx_tail = mb ;
+}
+
+/*
+ * get a SMbuf from the txd_tx_queue
+ */
+static SMbuf *get_txd_mb(smc)
+struct s_smc *smc ;
+{
+ SMbuf *mb ;
+
+ if ((mb = smc->os.hwm.txd_tx_pipe)) {
+ smc->os.hwm.queued_txd_mb-- ;
+ smc->os.hwm.txd_tx_pipe = mb->sm_next ;
+ }
+ DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ;
+ return(mb) ;
+}
+
+/*
+ * SMT Send function
+ */
+void smt_send_mbuf(smc,mb,fc)
+struct s_smc *smc;
+SMbuf *mb;
+int fc;
+{
+ char far *data ;
+ int len ;
+ int n ;
+ int i ;
+ int frag_count ;
+ int frame_status ;
+ SK_LOC_DECL(char far,*virt[3]) ;
+ int frag_len[3] ;
+ struct s_smt_tx_queue *queue ;
+ struct s_smt_fp_txd volatile *t ;
+ u_long phys ;
+#ifdef AIX
+ u_long tbctrl ;
+#endif
+
+ NDD_TRACE("THSB",mb,fc,0) ;
+ DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ;
+
+ mb->sm_off-- ; /* set to fc */
+ mb->sm_len++ ; /* + fc */
+ data = smtod(mb,char *) ;
+ *data = fc ;
+ if (fc == FC_SMT_LOC)
+ *data = FC_SMT_INFO ;
+
+ /*
+ * determine the frag count and the virt addresses of the frags
+ */
+ frag_count = 0 ;
+ len = mb->sm_len ;
+ while (len) {
+ n = SMT_PAGESIZE - ((int)data & (SMT_PAGESIZE-1)) ;
+ if (n >= len) {
+ n = len ;
+ }
+ DB_TX("frag: virt/len = 0x%x/%d ",(void *)data,n,5) ;
+ virt[frag_count] = data ;
+ frag_len[frag_count] = n ;
+ frag_count++ ;
+ len -= n ;
+ data += n ;
+ }
+
+ /*
+ * determine the frame status
+ */
+ queue = smc->hw.fp.tx[QUEUE_A0] ;
+ if (fc == FC_BEACON || fc == FC_SMT_LOC) {
+ frame_status = LOC_TX ;
+ }
+ else {
+ frame_status = LAN_TX ;
+ if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) ||
+ (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO)))
+ frame_status |= LOC_TX ;
+ }
+
+ if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) {
+ if (frame_status &= ~LAN_TX) {
+ DB_TX("Ring is down: terminate LAN_TX",0,0,2) ;
+ }
+ else {
+ DB_TX("Ring is down: terminate transmission",0,0,2) ;
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+ }
+ DB_TX("frame_status = 0x%x ",frame_status,0,5) ;
+
+ if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) {
+ mb->sm_use_count = 2 ;
+ }
+
+ if (frame_status & LAN_TX) {
+ t = queue->tx_curr_put ;
+ frame_status |= FIRST_FRAG ;
+ for (i = 0; i < frag_count; i++) {
+ DB_TX("init TxD = 0x%x",(void *)t,0,5) ;
+ if (i == frag_count-1) {
+ frame_status |= LAST_FRAG ;
+ t->txd_txdscr = AIX_REVERSE(TX_DESCRIPTOR |
+ (((u_long)(mb->sm_len-1)&3) << 27)) ;
+ }
+ t->txd_virt = virt[i] ;
+ phys = dma_master(smc, (void far *)virt[i],
+ frag_len[i], DMA_RD|SMT_BUF) ;
+ t->txd_tbadr = AIX_REVERSE(phys) ;
+#ifndef AIX
+ t->txd_tbctrl = (((u_long) frame_status &
+ (FIRST_FRAG|LAST_FRAG)) << 26) |
+ BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i] ;
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+ outpd(queue->tx_bmu_ctl,CSR_START) ;
+#else
+ tbctrl = AIX_REVERSE((((u_long) frame_status &
+ (FIRST_FRAG|LAST_FRAG)) << 26) |
+ BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ;
+ t->txd_tbctrl = tbctrl ;
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+ outpd(ADDR(B0_XA_CSR),CSR_START) ;
+#endif
+ frame_status &= ~FIRST_FRAG ;
+ queue->tx_curr_put = t = t->txd_next ;
+ queue->tx_free-- ;
+ queue->tx_used++ ;
+ }
+ smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
+ queue_txd_mb(smc,mb) ;
+ }
+
+ if (frame_status & LOC_TX) {
+ DB_TX("pass Mbuf to LLC queue",0,0,5) ;
+ queue_llc_rx(smc,mb) ;
+ }
+
+ /*
+ * We need to unqueue the free SMT_MBUFs here, because it may
+ * be that the SMT want's to send more than 1 frame for one down call
+ */
+ mac_drv_clear_txd(smc) ;
+ NDD_TRACE("THSE",t,queue->tx_free,frag_count) ;
+}
+
+/* BEGIN_MANUAL_ENTRY(mac_drv_clear_txd)
+ * void mac_drv_clear_txd(smc)
+ *
+ * function DOWNCALL (hardware module, hwmtm.c)
+ * mac_drv_clear_txd searches in both send queues for TxD's
+ * which were finished by the adapter. It calls dma_complete
+ * for each TxD. If the last fragment of an LLC frame is
+ * reached, it calls mac_drv_tx_complete to release the
+ * send buffer.
+ *
+ * return nothing
+ *
+ * END_MANUAL_ENTRY
+ */
+void mac_drv_clear_txd(smc)
+struct s_smc *smc ;
+{
+ struct s_smt_tx_queue *queue ;
+ struct s_smt_fp_txd volatile *t1 ;
+ struct s_smt_fp_txd volatile *t2=0 ;
+ SMbuf *mb ;
+ u_long tbctrl ;
+ int i ;
+ int frag_count ;
+ int n ;
+
+ NDD_TRACE("THcB",0,0,0) ;
+ for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+ queue = smc->hw.fp.tx[i] ;
+ t1 = queue->tx_curr_get ;
+ DB_TX("clear_txd: QUEUE = %d (0=sync/1=async)",i,0,5) ;
+
+ for ( ; ; ) {
+ frag_count = 0 ;
+
+ do {
+ DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ;
+ DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ;
+ tbctrl = CR_READ(t1->txd_tbctrl) ;
+#ifdef AIX
+ tbctrl = AIX_REVERSE(tbctrl) ;
+#endif
+ if (tbctrl & BMU_OWN || !queue->tx_used){
+ DB_TX("End of TxDs queue %d",i,0,4) ;
+ goto free_next_queue ; /* next queue */
+ }
+ t1 = t1->txd_next ;
+ frag_count++ ;
+ } while (!(tbctrl & BMU_EOF)) ;
+
+ t1 = queue->tx_curr_get ;
+ for (n = frag_count; n; n--) {
+ tbctrl = AIX_REVERSE(t1->txd_tbctrl) ;
+ dma_complete(smc,
+ (union s_fp_descr volatile *) t1,
+ (int) (DMA_RD |
+ ((tbctrl & BMU_SMT_TX) >> 18))) ;
+ t2 = t1 ;
+ t1 = t1->txd_next ;
+ }
+
+ if (tbctrl & BMU_SMT_TX) {
+ mb = get_txd_mb(smc) ;
+ smt_free_mbuf(smc,mb) ;
+ }
+ else {
+#ifndef PASS_1ST_TXD_2_TX_COMP
+ DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ;
+ mac_drv_tx_complete(smc,t2) ;
+#else
+ DB_TX("mac_drv_tx_comp for TxD 0x%x",
+ queue->tx_curr_get,0,4) ;
+ mac_drv_tx_complete(smc,queue->tx_curr_get) ;
+#endif
+ }
+ queue->tx_curr_get = t1 ;
+ queue->tx_free += frag_count ;
+ queue->tx_used -= frag_count ;
+ }
+free_next_queue: ;
+ }
+ NDD_TRACE("THcE",0,0,0) ;
+}
+
+/*
+ * BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue)
+ *
+ * void mac_drv_clear_tx_queue(smc)
+ * struct s_smc *smc ;
+ *
+ * function DOWNCALL (hardware module, hwmtm.c)
+ * mac_drv_clear_tx_queue is called from the SMT when
+ * the RMT state machine has entered the ISOLATE state.
+ * This function is also called by the os-specific module
+ * after it has called the function card_stop().
+ * In this case, the frames in the send queues are obsolete and
+ * should be removed.
+ *
+ * note calling sequence:
+ * CLI_FBI(), card_stop(),
+ * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
+ *
+ * NOTE: The caller is responsible that the BMUs are idle
+ * when this function is called.
+ *
+ * END_MANUAL_ENTRY
+ */
+void mac_drv_clear_tx_queue(smc)
+struct s_smc *smc ;
+{
+ struct s_smt_fp_txd volatile *t ;
+ struct s_smt_tx_queue *queue ;
+ int tx_used ;
+ int i ;
+
+ if (smc->hw.hw_state != STOPPED) {
+ SK_BREAK() ;
+ SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ;
+ return ;
+ }
+
+ for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+ queue = smc->hw.fp.tx[i] ;
+ DB_TX("clear_tx_queue: QUEUE = %d (0=sync/1=async)",i,0,5) ;
+
+ /*
+ * switch the OWN bit of all pending frames to the host
+ */
+ t = queue->tx_curr_get ;
+ tx_used = queue->tx_used ;
+ while (tx_used) {
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
+ DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ;
+ t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ;
+ DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+ t = t->txd_next ;
+ tx_used-- ;
+ }
+ }
+
+ /*
+ * release all TxD's for both send queues
+ */
+ mac_drv_clear_txd(smc) ;
+
+ for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+ queue = smc->hw.fp.tx[i] ;
+ t = queue->tx_curr_get ;
+
+ /*
+ * write the phys pointer of the NEXT descriptor into the
+ * BMU's current address descriptor pointer and set
+ * tx_curr_get and tx_curr_put to this position
+ */
+ if (i == QUEUE_S) {
+ outpd(ADDR(B5_XS_DA),AIX_REVERSE(t->txd_ntdadr)) ;
+ }
+ else {
+ outpd(ADDR(B5_XA_DA),AIX_REVERSE(t->txd_ntdadr)) ;
+ }
+
+ queue->tx_curr_put = queue->tx_curr_get->txd_next ;
+ queue->tx_curr_get = queue->tx_curr_put ;
+ }
+}
+
+
+/*
+ -------------------------------------------------------------
+ TEST FUNCTIONS:
+ -------------------------------------------------------------
+*/
+
+#ifdef DEBUG
+/*
+ * BEGIN_MANUAL_ENTRY(mac_drv_debug_lev)
+ * void mac_drv_debug_lev(smc,flag,lev)
+ *
+ * function DOWNCALL (drvsr.c)
+ * To get a special debug info the user can assign a debug level
+ * to any debug flag.
+ *
+ * para flag debug flag, possible values are:
+ * = 0: reset all debug flags (the defined level is
+ * ignored)
+ * = 1: debug.d_smtf
+ * = 2: debug.d_smt
+ * = 3: debug.d_ecm
+ * = 4: debug.d_rmt
+ * = 5: debug.d_cfm
+ * = 6: debug.d_pcm
+ *
+ * = 10: debug.d_os.hwm_rx (hardware module receive path)
+ * = 11: debug.d_os.hwm_tx(hardware module transmit path)
+ * = 12: debug.d_os.hwm_gen(hardware module general flag)
+ *
+ * lev debug level
+ *
+ * END_MANUAL_ENTRY
+ */
+void mac_drv_debug_lev(smc,flag,lev)
+struct s_smc *smc ;
+int flag ;
+int lev ;
+{
+ switch(flag) {
+ case (int)NULL:
+ DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ;
+ DB_P.d_cfm = 0 ;
+ DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ;
+#ifdef SBA
+ DB_P.d_sba = 0 ;
+#endif
+#ifdef ESS
+ DB_P.d_ess = 0 ;
+#endif
+ break ;
+ case DEBUG_SMTF:
+ DB_P.d_smtf = lev ;
+ break ;
+ case DEBUG_SMT:
+ DB_P.d_smt = lev ;
+ break ;
+ case DEBUG_ECM:
+ DB_P.d_ecm = lev ;
+ break ;
+ case DEBUG_RMT:
+ DB_P.d_rmt = lev ;
+ break ;
+ case DEBUG_CFM:
+ DB_P.d_cfm = lev ;
+ break ;
+ case DEBUG_PCM:
+ DB_P.d_pcm = lev ;
+ break ;
+ case DEBUG_SBA:
+#ifdef SBA
+ DB_P.d_sba = lev ;
+#endif
+ break ;
+ case DEBUG_ESS:
+#ifdef ESS
+ DB_P.d_ess = lev ;
+#endif
+ break ;
+ case DB_HWM_RX:
+ DB_P.d_os.hwm_rx = lev ;
+ break ;
+ case DB_HWM_TX:
+ DB_P.d_os.hwm_tx = lev ;
+ break ;
+ case DB_HWM_GEN:
+ DB_P.d_os.hwm_gen = lev ;
+ break ;
+ default:
+ break ;
+ }
+}
+#endif
diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c
new file mode 100644
index 000000000..7d51b8b8b
--- /dev/null
+++ b/drivers/net/skfp/hwt.c
@@ -0,0 +1,314 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Timer Driver for FBI board (timer chip 82C54)
+ */
+
+/*
+ * Modifications:
+ *
+ * 28-Jun-1994 sw Edit v1.6.
+ * MCA: Added support for the SK-NET FDDI-FM2 adapter. The
+ * following functions have been added(+) or modified(*):
+ * hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)hwt.c 1.13 97/04/23 (C) SK " ;
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
+/*static*/ void hwt_restart() ;
+
+/************************
+ *
+ * hwt_start
+ *
+ * Start hardware timer (clock ticks are 16us).
+ *
+ * void hwt_start(
+ * struct s_smc *smc,
+ * u_long time) ;
+ * In
+ * smc - A pointer to the SMT Context structure.
+ *
+ * time - The time in units of 16us to load the timer with.
+ * Out
+ * Nothing.
+ *
+ ************************/
+#define HWT_MAX (65000)
+
+void hwt_start(smc, time)
+struct s_smc *smc ;
+u_long time ;
+{
+ u_short cnt ;
+
+ if (time > HWT_MAX)
+ time = HWT_MAX ;
+
+ smc->hw.t_start = time ;
+ smc->hw.t_stop = 0L ;
+
+ cnt = (u_short)time ;
+ /*
+ * if time < 16 us
+ * time = 16 us
+ */
+ if (!cnt)
+ cnt++ ;
+#ifndef PCI
+ /*
+ * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0
+ * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT)
+ */
+ OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
+ OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */
+ OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */
+ /*
+ * start timer by switching counter 0 to mode 3
+ * T0 resolution 16 us (CLK0=0.16us)
+ */
+ OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */
+ OUT_82c54_TIMER(0,100) ; /* LSB */
+ OUT_82c54_TIMER(0,0) ; /* MSB */
+#else /* PCI */
+ outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */
+ outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */
+#endif /* PCI */
+ smc->hw.timer_activ = TRUE ;
+}
+
+/************************
+ *
+ * hwt_stop
+ *
+ * Stop hardware timer.
+ *
+ * void hwt_stop(
+ * struct s_smc *smc) ;
+ * In
+ * smc - A pointer to the SMT Context structure.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void hwt_stop(smc)
+struct s_smc *smc ;
+{
+#ifndef PCI
+ /* stop counter 0 by switching to mode 0 */
+ OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */
+ OUT_82c54_TIMER(0,0) ; /* LSB */
+ OUT_82c54_TIMER(0,0) ; /* MSB */
+#else /* PCI */
+ outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
+ outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
+#endif /* PCI */
+
+ smc->hw.timer_activ = FALSE ;
+}
+
+/************************
+ *
+ * hwt_init
+ *
+ * Initialize hardware timer.
+ *
+ * void hwt_init(
+ * struct s_smc *smc) ;
+ * In
+ * smc - A pointer to the SMT Context structure.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void hwt_init(smc)
+struct s_smc *smc ;
+{
+ smc->hw.t_start = 0 ;
+ smc->hw.t_stop = 0 ;
+ smc->hw.timer_activ = FALSE ;
+
+ hwt_restart(smc) ;
+}
+
+/************************
+ *
+ * hwt_restart
+ *
+ * Clear timer interrupt.
+ *
+ * void hwt_restart(
+ * struct s_smc *smc) ;
+ * In
+ * smc - A pointer to the SMT Context structure.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void hwt_restart(smc)
+struct s_smc *smc ;
+{
+ hwt_stop(smc) ;
+#ifndef PCI
+ OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
+ OUT_82c54_TIMER(1,1 ) ; /* LSB */
+ OUT_82c54_TIMER(1,0 ) ; /* MSB */
+#endif
+}
+
+/************************
+ *
+ * hwt_read
+ *
+ * Stop hardware timer and read time elapsed since last start.
+ *
+ * u_long hwt_read(smc) ;
+ * In
+ * smc - A pointer to the SMT Context structure.
+ * Out
+ * The elapsed time since last start in units of 16us.
+ *
+ ************************/
+u_long hwt_read(smc)
+struct s_smc *smc ;
+{
+ u_short tr ;
+#ifndef PCI
+ u_short is ;
+#else
+ u_long is ;
+#endif
+
+ if (smc->hw.timer_activ) {
+ hwt_stop(smc) ;
+#ifndef PCI
+ OUT_82c54_TIMER(3,1<<6) ; /* latch command */
+ tr = IN_82c54_TIMER(1) & 0xff ;
+ tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
+#else /* PCI */
+ tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
+#endif /* PCI */
+ is = GET_ISR() ;
+ /* Check if timer expired (or wraparound). */
+ if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
+ hwt_restart(smc) ;
+ smc->hw.t_stop = smc->hw.t_start ;
+ }
+ else
+ smc->hw.t_stop = smc->hw.t_start - tr ;
+ }
+ return (smc->hw.t_stop) ;
+}
+
+#ifdef PCI
+/************************
+ *
+ * hwt_quick_read
+ *
+ * Stop hardware timer and read timer value and start the timer again.
+ *
+ * u_long hwt_read(smc) ;
+ * In
+ * smc - A pointer to the SMT Context structure.
+ * Out
+ * current timer value in units of 80ns.
+ *
+ ************************/
+u_long hwt_quick_read(smc)
+struct s_smc *smc ;
+{
+ u_long interval ;
+ u_long time ;
+
+ interval = inpd(ADDR(B2_TI_INI)) ;
+ outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
+ time = inpd(ADDR(B2_TI_VAL)) ;
+ outpd(ADDR(B2_TI_INI),time) ;
+ outpw(ADDR(B2_TI_CRTL), TIM_START) ;
+ outpd(ADDR(B2_TI_INI),interval) ;
+
+ return(time) ;
+}
+
+/************************
+ *
+ * hwt_wait_time(smc,start,duration)
+ *
+ * This function returnes after the amount of time is elapsed
+ * since the start time.
+ *
+ * para start start time
+ * duration time to wait
+ *
+ * NOTE: The fuction will return immediatly, if the timer is not
+ * started
+ ************************/
+void hwt_wait_time(smc,start,duration)
+struct s_smc *smc ;
+u_long start ;
+long duration ;
+{
+ long diff ;
+ long interval ;
+ int wrapped ;
+
+ /*
+ * check if timer is running
+ */
+ if (smc->hw.timer_activ == FALSE ||
+ hwt_quick_read(smc) == hwt_quick_read(smc)) {
+ return ;
+ }
+
+ interval = inpd(ADDR(B2_TI_INI)) ;
+ if (interval > duration) {
+ do {
+ diff = (long)(start - hwt_quick_read(smc)) ;
+ if (diff < 0) {
+ diff += interval ;
+ }
+ } while (diff <= duration) ;
+ }
+ else {
+ diff = interval ;
+ wrapped = 0 ;
+ do {
+ if (!wrapped) {
+ if (hwt_quick_read(smc) >= start) {
+ diff += interval ;
+ wrapped = 1 ;
+ }
+ }
+ else {
+ if (hwt_quick_read(smc) < start) {
+ wrapped = 0 ;
+ }
+ }
+ } while (diff <= duration) ;
+ }
+}
+#endif
diff --git a/drivers/net/skfp/lnkstat.c b/drivers/net/skfp/lnkstat.c
new file mode 100644
index 000000000..7d2d94eae
--- /dev/null
+++ b/drivers/net/skfp/lnkstat.c
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ IBM FDDI read error log function
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/lnkstat.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)lnkstat.c 1.8 97/04/11 (C) SK " ;
+#endif
+
+#ifdef sun
+#define _far
+#endif
+
+#define EL_IS_OK(x,l) ((((int)&(((struct s_error_log *)0)->x)) + \
+ sizeof(er->x)) <= l)
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+ u_long smt_get_error_word(smc)
+ struct s_smc *smc ;
+
+Function DOWNCALL (SMT, lnkstat.c)
+ This functions returns the SMT error work for AIX events.
+
+Return smt_error_word These bits are supported:
+
+ SMT_ERL_ALC == [PS/PA].fddiPORTLerFlag
+ SMT_ERL_BLC == [PB].fddiPORTLerFlag
+ SMT_ERL_NCC == fddiMACNotCopiedFlag
+ SMT_ERL_FEC == fddiMACFrameErrorFlag
+
+ END_MANUAL_ENTRY()
+ */
+u_long smt_get_error_word(smc)
+struct s_smc *smc ;
+{
+ u_long st;
+
+ /*
+ * smt error word low
+ */
+ st = 0 ;
+ if (smc->s.sas == SMT_SAS) {
+ if (smc->mib.p[PS].fddiPORTLerFlag)
+ st |= SMT_ERL_ALC ;
+ }
+ else {
+ if (smc->mib.p[PA].fddiPORTLerFlag)
+ st |= SMT_ERL_ALC ;
+ if (smc->mib.p[PB].fddiPORTLerFlag)
+ st |= SMT_ERL_BLC ;
+ }
+ if (smc->mib.m[MAC0].fddiMACNotCopiedFlag)
+ st |= SMT_ERL_NCC ; /* not copied condition */
+ if (smc->mib.m[MAC0].fddiMACFrameErrorFlag)
+ st |= SMT_ERL_FEC ; /* frame error condition */
+
+ return st;
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+ u_long smt_get_event_word(smc)
+ struct s_smc *smc ;
+
+Function DOWNCALL (SMT, lnkstat.c)
+ This functions returns the SMT event work for AIX events.
+
+Return smt_event_word always 0
+
+ END_MANUAL_ENTRY()
+ */
+u_long smt_get_event_word(smc)
+struct s_smc *smc ;
+{
+ return (u_long) 0;
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+ u_long smt_get_port_event_word(smc)
+ struct s_smc *smc ;
+
+Function DOWNCALL (SMT, lnkstat.c)
+ This functions returns the SMT port event work for AIX events.
+
+Return smt_port_event_word always 0
+
+ END_MANUAL_ENTRY()
+ */
+u_long smt_get_port_event_word(smc)
+struct s_smc *smc ;
+{
+ return (u_long) 0;
+}
+
+/*
+ BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+ u_long smt_read_errorlog(smc,p,len)
+ struct s_smc *smc ;
+ char _far *p ;
+ int len ;
+
+Function DOWNCALL (SMT, lnkstat.c)
+ This functions returns the SMT error log field for AIX events.
+
+Para p pointer to the error log field
+ len len of the error log field
+
+Return len used len of the error log field
+
+ END_MANUAL_ENTRY()
+ */
+int smt_read_errorlog(smc,p,len)
+struct s_smc *smc ;
+char _far *p ;
+int len ;
+{
+ int i ;
+ int st ;
+ struct s_error_log _far *er ;
+
+ er = (struct s_error_log _far *) p ;
+ if (len > sizeof(struct s_error_log))
+ len = sizeof(struct s_error_log) ;
+ for (i = 0 ; i < len ; i++)
+ *p++ = 0 ;
+ /*
+ * set count
+ */
+ if (EL_IS_OK(set_count_high,len)) {
+ er->set_count_low = (u_short)smc->mib.fddiSMTSetCount.count ;
+ er->set_count_high =
+ (u_short)(smc->mib.fddiSMTSetCount.count >> 16L) ;
+ }
+ /*
+ * aci
+ */
+ if (EL_IS_OK(aci_id_code,len)) {
+ er->aci_id_code = 0 ;
+ }
+ /*
+ * purge counter is missed frames; 16 bits only
+ */
+ if (EL_IS_OK(purge_frame_counter,len)) {
+ if (smc->mib.m[MAC0].fddiMACCopied_Ct > 0xffff)
+ er->purge_frame_counter = 0xffff ;
+ else
+ er->purge_frame_counter =
+ (u_short)smc->mib.m[MAC0].fddiMACCopied_Ct ;
+ }
+ /*
+ * CMT and RMT state machines
+ */
+ if (EL_IS_OK(ecm_state,len))
+ er->ecm_state = smc->mib.fddiSMTECMState ;
+
+ if (EL_IS_OK(pcm_b_state,len)) {
+ if (smc->s.sas == SMT_SAS) {
+ er->pcm_a_state = smc->y[PS].mib->fddiPORTPCMState ;
+ er->pcm_b_state = 0 ;
+ }
+ else {
+ er->pcm_a_state = smc->y[PA].mib->fddiPORTPCMState ;
+ er->pcm_b_state = smc->y[PB].mib->fddiPORTPCMState ;
+ }
+ }
+ if (EL_IS_OK(cfm_state,len))
+ er->cfm_state = smc->mib.fddiSMTCF_State ;
+ if (EL_IS_OK(rmt_state,len))
+ er->rmt_state = smc->mib.m[MAC0].fddiMACRMTState ;
+
+ /*
+ * smt error word low (we only need the low order 16 bits.)
+ */
+
+ st = smt_get_error_word(smc) & 0xffff ;
+
+ if (EL_IS_OK(smt_error_low,len))
+ er->smt_error_low = st ;
+
+ if (EL_IS_OK(ucode_version_level,len))
+ er->ucode_version_level = 0x0101 ;
+ return(len) ;
+}
diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c
new file mode 100644
index 000000000..5479b27ea
--- /dev/null
+++ b/drivers/net/skfp/pcmplc.c
@@ -0,0 +1,2094 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ PCM
+ Physical Connection Management
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * queue_event()
+ * smt_timer_start()
+ * smt_timer_stop()
+ *
+ * The following external HW dependant functions are referenced :
+ * sm_pm_control()
+ * sm_ph_linestate()
+ * sm_pm_ls_latch()
+ *
+ * The following HW dependant events are required :
+ * PC_QLS
+ * PC_ILS
+ * PC_HLS
+ * PC_MLS
+ * PC_NSE
+ * PC_LEM
+ *
+ */
+
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ;
+#endif
+
+#ifdef FDDI_MIB
+extern int snmp_fddi_trap(
+#ifdef ANSIC
+struct s_smc * smc, int type, int index
+#endif
+);
+#endif
+#ifdef CONCENTRATOR
+extern int plc_is_installed(
+#ifdef ANSIC
+struct s_smc *smc ,
+int p
+#endif
+) ;
+#endif
+/*
+ * FSM Macros
+ */
+#define AFLAG (0x20)
+#define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG)
+#define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG)
+#define ACTIONS(x) (x|AFLAG)
+
+/*
+ * PCM states
+ */
+#define PC0_OFF 0
+#define PC1_BREAK 1
+#define PC2_TRACE 2
+#define PC3_CONNECT 3
+#define PC4_NEXT 4
+#define PC5_SIGNAL 5
+#define PC6_JOIN 6
+#define PC7_VERIFY 7
+#define PC8_ACTIVE 8
+#define PC9_MAINT 9
+
+#ifdef DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const pcm_states[] = {
+ "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT",
+ "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const pcm_events[] = {
+ "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL",
+ "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR",
+ "PC_ENABLE","PC_DISABLE",
+ "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE",
+ "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN",
+ "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT",
+ "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT",
+ "PC_NSE","PC_LEM"
+} ;
+#endif
+
+#ifdef MOT_ELM
+/*
+ * PCL-S control register
+ * this register in the PLC-S controls the scrambling parameters
+ */
+#define PLCS_CONTROL_C_U 0
+#define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
+ PL_C_CIPHER_ENABLE)
+#define PLCS_FASSERT_U 0
+#define PLCS_FASSERT_S 0xFd76 /* 52.0 us */
+#define PLCS_FDEASSERT_U 0
+#define PLCS_FDEASSERT_S 0
+#else /* nMOT_ELM */
+/*
+ * PCL-S control register
+ * this register in the PLC-S controls the scrambling parameters
+ * can be patched for ANSI compliance if standard changes
+ */
+static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ;
+static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ;
+
+#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))
+#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
+#endif /* nMOT_ELM */
+
+/*
+ * external vars
+ */
+/* struct definition see 'cmtdef.h' (also used by CFM) */
+
+#define PS_OFF 0
+#define PS_BIT3 1
+#define PS_BIT4 2
+#define PS_BIT7 3
+#define PS_LCT 4
+#define PS_BIT8 5
+#define PS_JOIN 6
+#define PS_ACTIVE 7
+
+#define LCT_LEM_MAX 255
+
+/*
+ * PLC timing parameter
+ */
+
+#define PLC_MS(m) ((int)((0x10000L-(m*100000L/2048))))
+#define SLOW_TL_MIN PLC_MS(6)
+#define SLOW_C_MIN PLC_MS(10)
+
+static const struct plt {
+ int timer ; /* relative plc timer address */
+ int para ; /* default timing parameters */
+} pltm[] = {
+ { PL_C_MIN, SLOW_C_MIN }, /* min t. to remain Connect State */
+ { PL_TL_MIN, SLOW_TL_MIN }, /* min t. to transmit a Line State */
+ { PL_TB_MIN, TP_TB_MIN }, /* min break time */
+ { PL_T_OUT, TP_T_OUT }, /* Signaling timeout */
+ { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */
+ { PL_T_SCRUB, TP_T_SCRUB }, /* Scrub Time == MAC TVX time ! */
+ { PL_NS_MAX, TP_NS_MAX }, /* max t. that noise is tolerated */
+ { 0,0 }
+} ;
+
+/*
+ * interrupt mask
+ */
+#ifdef SUPERNET_3
+/*
+ * Do we need the EBUF error during signaling, too, to detect SUPERNET_3
+ * PLL bug?
+ */
+static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+ PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
+#else /* SUPERNET_3 */
+/*
+ * We do NOT need the elasticity buffer error during signaling.
+ */
+static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+ PL_PCM_ENABLED | PL_SELF_TEST ;
+#endif /* SUPERNET_3 */
+static int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+ PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
+
+/* external functions */
+void all_selection_criteria ();
+
+/* internal functions */
+static void pcm_fsm() ;
+static void pc_rcode_actions() ;
+static void pc_tcode_actions() ;
+static void reset_lem_struct() ;
+static void plc_init() ;
+static void sm_ph_lem_start() ;
+static void sm_ph_lem_stop() ;
+static void sm_ph_linestate() ;
+static void real_init_plc() ;
+
+/*
+ * SMT timer interface
+ * start PCM timer 0
+ */
+static void start_pcm_timer0(smc,value,event,phy)
+struct s_smc *smc ;
+u_long value;
+int event;
+struct s_phy *phy;
+{
+ phy->timer0_exp = FALSE ; /* clear timer event flag */
+ smt_timer_start(smc,&phy->pcm_timer0,value,
+ EV_TOKEN(EVENT_PCM+phy->np,event)) ;
+}
+/*
+ * SMT timer interface
+ * stop PCM timer 0
+ */
+static void stop_pcm_timer0(smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy;
+{
+ if (phy->pcm_timer0.tm_active)
+ smt_timer_stop(smc,&phy->pcm_timer0) ;
+}
+
+/*
+ init PCM state machine (called by driver)
+ clear all PCM vars and flags
+*/
+void pcm_init(smc)
+struct s_smc *smc ;
+{
+ int i ;
+ int np ;
+ struct s_phy *phy ;
+ struct fddi_mib_p *mib ;
+
+ for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) {
+ /* Indicates the type of PHY being used */
+ mib = phy->mib ;
+ mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ;
+ phy->np = np ;
+ switch (smc->s.sas) {
+#ifdef CONCENTRATOR
+ case SMT_SAS :
+ mib->fddiPORTMy_Type = (np == PS) ? TS : TM ;
+ break ;
+ case SMT_DAS :
+ mib->fddiPORTMy_Type = (np == PA) ? TA :
+ (np == PB) ? TB : TM ;
+ break ;
+ case SMT_NAC :
+ mib->fddiPORTMy_Type = TM ;
+ break;
+#else
+ case SMT_SAS :
+ mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ;
+ mib->fddiPORTHardwarePresent = (np == PS) ? TRUE :
+ FALSE ;
+#ifndef SUPERNET_3
+ smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ;
+#else
+ smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ;
+#endif
+ break ;
+ case SMT_DAS :
+ mib->fddiPORTMy_Type = (np == PB) ? TB : TA ;
+ break ;
+#endif
+ }
+ /*
+ * set PMD-type
+ */
+ phy->pmd_scramble = 0 ;
+ switch (phy->pmd_type[PMD_SK_PMD]) {
+ case 'P' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
+ break ;
+ case 'L' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ;
+ break ;
+ case 'D' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+ break ;
+ case 'S' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+ phy->pmd_scramble = TRUE ;
+ break ;
+ case 'U' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+ phy->pmd_scramble = TRUE ;
+ break ;
+ case '1' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
+ break ;
+ case '2' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
+ break ;
+ case '3' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
+ break ;
+ case '4' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
+ break ;
+ case 'H' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
+ break ;
+ case 'I' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+ break ;
+ case 'G' :
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+ break ;
+ default:
+ mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
+ break ;
+ }
+ /*
+ * A and B port can be on primary and secondary path
+ */
+ switch (mib->fddiPORTMy_Type) {
+ case TA :
+ mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+ mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+ mib->fddiPORTRequestedPaths[2] =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_CON_ALTER |
+ MIB_P_PATH_SEC_PREFER ;
+ mib->fddiPORTRequestedPaths[3] =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_CON_ALTER |
+ MIB_P_PATH_SEC_PREFER |
+ MIB_P_PATH_THRU ;
+ break ;
+ case TB :
+ mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+ mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+ mib->fddiPORTRequestedPaths[2] =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_PRIM_PREFER ;
+ mib->fddiPORTRequestedPaths[3] =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_PRIM_PREFER |
+ MIB_P_PATH_CON_PREFER |
+ MIB_P_PATH_THRU ;
+ break ;
+ case TS :
+ mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+ mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+ mib->fddiPORTRequestedPaths[2] =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_CON_ALTER |
+ MIB_P_PATH_PRIM_PREFER ;
+ mib->fddiPORTRequestedPaths[3] =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_CON_ALTER |
+ MIB_P_PATH_PRIM_PREFER ;
+ break ;
+ case TM :
+ mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+ mib->fddiPORTRequestedPaths[2] =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_SEC_ALTER |
+ MIB_P_PATH_PRIM_ALTER ;
+ mib->fddiPORTRequestedPaths[3] = 0 ;
+ break ;
+ }
+
+ phy->pc_lem_fail = FALSE ;
+ mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ;
+ mib->fddiPORTLCTFail_Ct = 0 ;
+ mib->fddiPORTBS_Flag = 0 ;
+ mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+ mib->fddiPORTNeighborType = TNONE ;
+ phy->ls_flag = 0 ;
+ phy->rc_flag = 0 ;
+ phy->tc_flag = 0 ;
+ phy->td_flag = 0 ;
+ if (np >= PM)
+ phy->phy_name = '0' + np - PM ;
+ else
+ phy->phy_name = 'A' + np ;
+ phy->wc_flag = FALSE ; /* set by SMT */
+ memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ;
+ reset_lem_struct(phy) ;
+ memset((char *)&phy->plc,0,sizeof(struct s_plc)) ;
+ phy->plc.p_state = PS_OFF ;
+ for (i = 0 ; i < NUMBITS ; i++) {
+ phy->t_next[i] = 0 ;
+ }
+ }
+ real_init_plc(smc) ;
+}
+
+void init_plc(smc)
+struct s_smc *smc ;
+{
+ SK_UNUSED(smc) ;
+
+ /*
+ * dummy
+ * this is an obsolete public entry point that has to remain
+ * for compat. It is used by various drivers.
+ * the work is now done in real_init_plc()
+ * which is called from pcm_init() ;
+ */
+}
+
+static void real_init_plc(smc)
+struct s_smc *smc ;
+{
+ int p ;
+
+ for (p = 0 ; p < NUMPHYS ; p++)
+ plc_init(smc,p) ;
+}
+
+static void plc_init(smc,p)
+struct s_smc *smc ;
+int p;
+{
+ int i ;
+#ifndef MOT_ELM
+ int rev ; /* Revision of PLC-x */
+#endif /* MOT_ELM */
+
+ /* transit PCM state machine to MAINT state */
+ outpw(PLC(p,PL_CNTRL_B),0) ;
+ outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ;
+ outpw(PLC(p,PL_CNTRL_A),0) ;
+
+ /*
+ * if PLC-S then set control register C
+ */
+#ifndef MOT_ELM
+ rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ;
+ if (rev != PLC_REVISION_A)
+#endif /* MOT_ELM */
+ {
+ if (smc->y[p].pmd_scramble) {
+ outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ;
+#ifdef MOT_ELM
+ outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ;
+ outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ;
+#endif /* MOT_ELM */
+ }
+ else {
+ outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ;
+#ifdef MOT_ELM
+ outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ;
+ outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ;
+#endif /* MOT_ELM */
+ }
+ }
+
+ /*
+ * set timer register
+ */
+ for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */
+ outpw(PLC(p,pltm[i].timer),pltm[i].para) ;
+
+ (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */
+ plc_clear_irq(smc,p) ;
+ outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */
+
+ /*
+ * if PCM is configured for class s, it will NOT go to the
+ * REMOVE state if offline (page 3-36;)
+ * in the concentrator, all inactive PHYS always must be in
+ * the remove state
+ * there's no real need to use this feature at all ..
+ */
+#ifndef CONCENTRATOR
+ if ((smc->s.sas == SMT_SAS) && (p == PS)) {
+ outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ;
+ }
+#endif
+}
+
+/*
+ * control PCM state machine
+ */
+static void plc_go_state(smc,p,state)
+struct s_smc *smc ;
+int p;
+int state;
+{
+ HW_PTR port ;
+ int val ;
+
+ SK_UNUSED(smc) ;
+
+ port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ;
+ val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ;
+ outpw(port,val) ;
+ outpw(port,val | state) ;
+}
+
+/*
+ * read current line state (called by ECM & PCM)
+ */
+int sm_pm_get_ls(smc,phy)
+struct s_smc *smc ;
+int phy;
+{
+ int state ;
+
+#ifdef CONCENTRATOR
+ if (!plc_is_installed(smc,phy))
+ return(PC_QLS) ;
+#endif
+
+ state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ;
+ switch(state) {
+ case PL_L_QLS:
+ state = PC_QLS ;
+ break ;
+ case PL_L_MLS:
+ state = PC_MLS ;
+ break ;
+ case PL_L_HLS:
+ state = PC_HLS ;
+ break ;
+ case PL_L_ILS4:
+ case PL_L_ILS16:
+ state = PC_ILS ;
+ break ;
+ case PL_L_ALS:
+ state = PC_LS_PDR ;
+ break ;
+ default :
+ state = PC_LS_NONE ;
+ }
+ return(state) ;
+}
+
+static int plc_send_bits(smc,phy,len)
+struct s_smc *smc ;
+struct s_phy *phy;
+int len;
+{
+ int np = phy->np ; /* PHY index */
+ int n ;
+ int i ;
+
+ SK_UNUSED(smc) ;
+
+ /* create bit vector */
+ for (i = len-1,n = 0 ; i >= 0 ; i--) {
+ n = (n<<1) | phy->t_val[phy->bitn+i] ;
+ }
+ if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
+#if 0
+ printf("PL_PCM_SIGNAL is set\n") ;
+#endif
+ return(1) ;
+ }
+ /* write bit[n] & length = 1 to regs */
+ outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */
+ outpw(PLC(np,PL_XMIT_VECTOR),n) ;
+#ifdef DEBUG
+#if 1
+#ifdef DEBUG_BRD
+ if (smc->debug.d_plc & 0x80)
+#else
+ if (debug.d_plc & 0x80)
+#endif
+ printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ;
+#endif
+#endif
+ return(0) ;
+}
+
+/*
+ * config plc muxes
+ */
+void plc_config_mux(smc,mux)
+struct s_smc *smc ;
+int mux ;
+{
+ if (smc->s.sas != SMT_DAS)
+ return ;
+ if (mux == MUX_WRAPB) {
+ SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
+ SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
+ }
+ else {
+ CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
+ CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ;
+ }
+ CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
+ CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ;
+}
+
+/*
+ PCM state machine
+ called by dispatcher & fddi_init() (driver)
+ do
+ display state change
+ process event
+ until SM is stable
+*/
+void pcm(smc,np,event)
+struct s_smc *smc ;
+const int np;
+int event;
+{
+ int state ;
+ int oldstate ;
+ struct s_phy *phy ;
+ struct fddi_mib_p *mib ;
+
+#ifndef CONCENTRATOR
+ /*
+ * ignore 2nd PHY if SAS
+ */
+ if ((np != PS) && (smc->s.sas == SMT_SAS))
+ return ;
+#endif
+ phy = &smc->y[np] ;
+ mib = phy->mib ;
+ oldstate = mib->fddiPORTPCMState ;
+ do {
+ DB_PCM("PCM %c: state %s",
+ phy->phy_name,
+ (mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ;
+ DB_PCM("%s, event %s\n",
+ pcm_states[mib->fddiPORTPCMState & ~AFLAG],
+ pcm_events[event]) ;
+ state = mib->fddiPORTPCMState ;
+ pcm_fsm(smc,phy,event) ;
+ event = 0 ;
+ } while (state != mib->fddiPORTPCMState) ;
+ /*
+ * because the PLC does the bit signaling for us,
+ * we're always in SIGNAL state
+ * the MIB want's to see CONNECT
+ * we therefore fake an entry in the MIB
+ */
+ if (state == PC5_SIGNAL)
+ mib->fddiPORTPCMStateX = PC3_CONNECT ;
+ else
+ mib->fddiPORTPCMStateX = state ;
+
+#ifndef SLIM_SMT
+ /*
+ * path change
+ */
+ if ( mib->fddiPORTPCMState != oldstate &&
+ ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) {
+ smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE,
+ (int) (INDEX_PORT+ phy->np),0) ;
+ }
+#endif
+
+#ifdef FDDI_MIB
+ /* check whether a snmp-trap has to be sent */
+
+ if ( mib->fddiPORTPCMState != oldstate ) {
+ /* a real state change took place */
+ DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState);
+ if ( mib->fddiPORTPCMState == PC0_OFF ) {
+ /* send first trap */
+ snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex );
+ } else if ( oldstate == PC0_OFF ) {
+ /* send second trap */
+ snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex );
+ } else if ( mib->fddiPORTPCMState != PC2_TRACE &&
+ oldstate == PC8_ACTIVE ) {
+ /* send third trap */
+ snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex );
+ } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) {
+ /* send fourth trap */
+ snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex );
+ }
+ }
+#endif
+
+ pcm_state_change(smc,np,state) ;
+}
+
+/*
+ * PCM state machine
+ */
+static void pcm_fsm(smc,phy,cmd)
+struct s_smc *smc ;
+struct s_phy *phy;
+int cmd;
+{
+ int i ;
+ int np = phy->np ; /* PHY index */
+ struct s_plc *plc ;
+ struct fddi_mib_p *mib ;
+#ifndef MOT_ELM
+ u_short plc_rev ; /* Revision of the plc */
+#endif /* nMOT_ELM */
+
+ plc = &phy->plc ;
+ mib = phy->mib ;
+
+ /*
+ * general transitions independant of state
+ */
+ switch (cmd) {
+ case PC_STOP :
+ /*PC00-PC80*/
+ if (mib->fddiPORTPCMState != PC9_MAINT) {
+ GO_STATE(PC0_OFF) ;
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+ FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP,
+ smt_get_port_event_word(smc));
+ }
+ return ;
+ case PC_START :
+ /*PC01-PC81*/
+ if (mib->fddiPORTPCMState != PC9_MAINT)
+ GO_STATE(PC1_BREAK) ;
+ return ;
+ case PC_DISABLE :
+ /* PC09-PC99 */
+ GO_STATE(PC9_MAINT) ;
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+ FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED,
+ smt_get_port_event_word(smc));
+ return ;
+ case PC_TIMEOUT_LCT :
+ /* if long or extended LCT */
+ stop_pcm_timer0(smc,phy) ;
+ CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+ /* end of LCT is indicate by PCM_CODE (initiate PCM event) */
+ return ;
+ }
+
+ switch(mib->fddiPORTPCMState) {
+ case ACTIONS(PC0_OFF) :
+ stop_pcm_timer0(smc,phy) ;
+ outpw(PLC(np,PL_CNTRL_A),0) ;
+ CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+ CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+ sm_ph_lem_stop(smc,np) ; /* disable LEM */
+ phy->cf_loop = FALSE ;
+ phy->cf_join = FALSE ;
+ queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+ plc_go_state(smc,np,PL_PCM_STOP) ;
+ mib->fddiPORTConnectState = PCM_DISABLED ;
+ ACTIONS_DONE() ;
+ break ;
+ case PC0_OFF:
+ /*PC09*/
+ if (cmd == PC_MAINT) {
+ GO_STATE(PC9_MAINT) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(PC1_BREAK) :
+ /* Stop the LCT timer if we came from Signal state */
+ stop_pcm_timer0(smc,phy) ;
+ ACTIONS_DONE() ;
+ plc_go_state(smc,np,0) ;
+ CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+ CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+ sm_ph_lem_stop(smc,np) ; /* disable LEM */
+ /*
+ * if vector is already loaded, go to OFF to clear PCM_SIGNAL
+ */
+#if 0
+ if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
+ plc_go_state(smc,np,PL_PCM_STOP) ;
+ /* TB_MIN ? */
+ }
+#endif
+ /*
+ * Go to OFF state in any case.
+ */
+ plc_go_state(smc,np,PL_PCM_STOP) ;
+
+ if (mib->fddiPORTPC_Withhold == PC_WH_NONE)
+ mib->fddiPORTConnectState = PCM_CONNECTING ;
+ phy->cf_loop = FALSE ;
+ phy->cf_join = FALSE ;
+ queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+ phy->ls_flag = FALSE ;
+ phy->pc_mode = PM_NONE ; /* needed by CFM */
+ phy->bitn = 0 ; /* bit signaling start bit */
+ for (i = 0 ; i < 3 ; i++)
+ pc_tcode_actions(smc,i,phy) ;
+
+ /* Set the non-active interrupt mask register */
+ outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ;
+
+ /*
+ * If the LCT was stopped. There might be a
+ * PCM_CODE interrupt event present.
+ * This must be cleared.
+ */
+ (void)inpw(PLC(np,PL_INTR_EVENT)) ;
+#ifndef MOT_ELM
+ /* Get the plc revision for revision dependent code */
+ plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ;
+
+ if (plc_rev != PLC_REV_SN3)
+#endif /* MOT_ELM */
+ {
+ /*
+ * No supernet III PLC, so set Xmit verctor and
+ * length BEFORE starting the state machine.
+ */
+ if (plc_send_bits(smc,phy,3)) {
+ return ;
+ }
+ }
+
+ /*
+ * Now give the Start command.
+ * - The start command shall be done before setting the bits
+ * to be signaled. (In PLC-S description and PLCS in SN3.
+ * - The start command shall be issued AFTER setting the
+ * XMIT vector and the XMIT length register.
+ *
+ * We do it exactly according this specs for the old PLC and
+ * the new PLCS inside the SN3.
+ * For the usual PLCS we try it the way it is done for the
+ * old PLC and set the XMIT registers again, if the PLC is
+ * not in SIGNAL state. This is done according to an PLCS
+ * errata workaround.
+ */
+
+ plc_go_state(smc,np,PL_PCM_START) ;
+
+ /*
+ * workaround for PLC-S eng. sample errata
+ */
+#ifdef MOT_ELM
+ if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
+#else /* nMOT_ELM */
+ if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) !=
+ PLC_REVISION_A) &&
+ !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
+#endif /* nMOT_ELM */
+ {
+ /*
+ * Set register again (PLCS errata) or the first time
+ * (new SN3 PLCS).
+ */
+ (void) plc_send_bits(smc,phy,3) ;
+ }
+ /*
+ * end of workaround
+ */
+
+ GO_STATE(PC5_SIGNAL) ;
+ plc->p_state = PS_BIT3 ;
+ plc->p_bits = 3 ;
+ plc->p_start = 0 ;
+
+ break ;
+ case PC1_BREAK :
+ break ;
+ case ACTIONS(PC2_TRACE) :
+ plc_go_state(smc,np,PL_PCM_TRACE) ;
+ ACTIONS_DONE() ;
+ break ;
+ case PC2_TRACE :
+ break ;
+
+ case PC3_CONNECT : /* these states are done by hardware */
+ case PC4_NEXT :
+ break ;
+
+ case ACTIONS(PC5_SIGNAL) :
+ ACTIONS_DONE() ;
+ case PC5_SIGNAL :
+ if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT))
+ break ;
+ switch (plc->p_state) {
+ case PS_BIT3 :
+ for (i = 0 ; i <= 2 ; i++)
+ pc_rcode_actions(smc,i,phy) ;
+ pc_tcode_actions(smc,3,phy) ;
+ plc->p_state = PS_BIT4 ;
+ plc->p_bits = 1 ;
+ plc->p_start = 3 ;
+ phy->bitn = 3 ;
+ if (plc_send_bits(smc,phy,1)) {
+ return ;
+ }
+ break ;
+ case PS_BIT4 :
+ pc_rcode_actions(smc,3,phy) ;
+ for (i = 4 ; i <= 6 ; i++)
+ pc_tcode_actions(smc,i,phy) ;
+ plc->p_state = PS_BIT7 ;
+ plc->p_bits = 3 ;
+ plc->p_start = 4 ;
+ phy->bitn = 4 ;
+ if (plc_send_bits(smc,phy,3)) {
+ return ;
+ }
+ break ;
+ case PS_BIT7 :
+ for (i = 3 ; i <= 6 ; i++)
+ pc_rcode_actions(smc,i,phy) ;
+ plc->p_state = PS_LCT ;
+ plc->p_bits = 0 ;
+ plc->p_start = 7 ;
+ phy->bitn = 7 ;
+ sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */
+ /* start LCT */
+ i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ;
+ outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */
+ outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ;
+ break ;
+ case PS_LCT :
+ /* check for local LCT failure */
+ pc_tcode_actions(smc,7,phy) ;
+ /*
+ * set tval[7]
+ */
+ plc->p_state = PS_BIT8 ;
+ plc->p_bits = 1 ;
+ plc->p_start = 7 ;
+ phy->bitn = 7 ;
+ if (plc_send_bits(smc,phy,1)) {
+ return ;
+ }
+ break ;
+ case PS_BIT8 :
+ /* check for remote LCT failure */
+ pc_rcode_actions(smc,7,phy) ;
+ if (phy->t_val[7] || phy->r_val[7]) {
+ plc_go_state(smc,np,PL_PCM_STOP) ;
+ GO_STATE(PC1_BREAK) ;
+ break ;
+ }
+ for (i = 8 ; i <= 9 ; i++)
+ pc_tcode_actions(smc,i,phy) ;
+ plc->p_state = PS_JOIN ;
+ plc->p_bits = 2 ;
+ plc->p_start = 8 ;
+ phy->bitn = 8 ;
+ if (plc_send_bits(smc,phy,2)) {
+ return ;
+ }
+ break ;
+ case PS_JOIN :
+ for (i = 8 ; i <= 9 ; i++)
+ pc_rcode_actions(smc,i,phy) ;
+ plc->p_state = PS_ACTIVE ;
+ GO_STATE(PC6_JOIN) ;
+ break ;
+ }
+ break ;
+
+ case ACTIONS(PC6_JOIN) :
+ /*
+ * prevent mux error when going from WRAP_A to WRAP_B
+ */
+ if (smc->s.sas == SMT_DAS && np == PB &&
+ (smc->y[PA].pc_mode == PM_TREE ||
+ smc->y[PB].pc_mode == PM_TREE)) {
+ SETMASK(PLC(np,PL_CNTRL_A),
+ PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
+ SETMASK(PLC(np,PL_CNTRL_B),
+ PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
+ }
+ SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
+ SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
+ ACTIONS_DONE() ;
+ cmd = 0 ;
+ /* fall thru */
+ case PC6_JOIN :
+ switch (plc->p_state) {
+ case PS_ACTIVE:
+ /*PC88b*/
+ if (!phy->cf_join) {
+ phy->cf_join = TRUE ;
+ queue_event(smc,EVENT_CFM,CF_JOIN+np) ; ;
+ }
+ if (cmd == PC_JOIN)
+ GO_STATE(PC8_ACTIVE) ;
+ /*PC82*/
+ if (cmd == PC_TRACE) {
+ GO_STATE(PC2_TRACE) ;
+ break ;
+ }
+ break ;
+ }
+ break ;
+
+ case PC7_VERIFY :
+ break ;
+
+ case ACTIONS(PC8_ACTIVE) :
+ /*
+ * start LEM for SMT
+ */
+ sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ;
+
+ phy->tr_flag = FALSE ;
+ mib->fddiPORTConnectState = PCM_ACTIVE ;
+
+ /* Set the active interrupt mask register */
+ outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ;
+
+ ACTIONS_DONE() ;
+ break ;
+ case PC8_ACTIVE :
+ /*PC81 is done by PL_TNE_EXPIRED irq */
+ /*PC82*/
+ if (cmd == PC_TRACE) {
+ GO_STATE(PC2_TRACE) ;
+ break ;
+ }
+ /*PC88c: is done by TRACE_PROP irq */
+
+ break ;
+ case ACTIONS(PC9_MAINT) :
+ stop_pcm_timer0(smc,phy) ;
+ CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+ CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+ CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */
+ sm_ph_lem_stop(smc,np) ; /* disable LEM */
+ phy->cf_loop = FALSE ;
+ phy->cf_join = FALSE ;
+ queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+ plc_go_state(smc,np,PL_PCM_STOP) ;
+ mib->fddiPORTConnectState = PCM_DISABLED ;
+ SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ;
+ sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ;
+ outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ;
+ ACTIONS_DONE() ;
+ break ;
+ case PC9_MAINT :
+ DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ;
+ /*PC90*/
+ if (cmd == PC_ENABLE) {
+ GO_STATE(PC0_OFF) ;
+ break ;
+ }
+ break ;
+
+ default:
+ SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ;
+ break ;
+ }
+}
+
+/*
+ * force line state on a PHY output (only in MAINT state)
+ */
+static void sm_ph_linestate(smc,phy,ls)
+struct s_smc *smc ;
+int phy;
+int ls;
+{
+ int cntrl ;
+
+ SK_UNUSED(smc) ;
+
+ cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) |
+ PL_PCM_STOP | PL_MAINT ;
+ switch(ls) {
+ case PC_QLS: /* Force Quiet */
+ cntrl |= PL_M_QUI0 ;
+ break ;
+ case PC_MLS: /* Force Master */
+ cntrl |= PL_M_MASTR ;
+ break ;
+ case PC_HLS: /* Force Halt */
+ cntrl |= PL_M_HALT ;
+ break ;
+ default :
+ case PC_ILS: /* Force Idle */
+ cntrl |= PL_M_IDLE ;
+ break ;
+ case PC_LS_PDR: /* Enable repeat filter */
+ cntrl |= PL_M_TPDR ;
+ break ;
+ }
+ outpw(PLC(phy,PL_CNTRL_B),cntrl) ;
+}
+
+
+static void reset_lem_struct(phy)
+struct s_phy *phy;
+{
+ struct lem_counter *lem = &phy->lem ;
+
+ phy->mib->fddiPORTLer_Estimate = 15 ;
+ lem->lem_float_ber = 15 * 100 ;
+}
+
+/*
+ * link error monitor
+ */
+static void lem_evaluate(smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy;
+{
+ int ber ;
+ u_long errors ;
+ struct lem_counter *lem = &phy->lem ;
+ struct fddi_mib_p *mib ;
+ int cond ;
+
+ mib = phy->mib ;
+
+ if (!lem->lem_on)
+ return ;
+
+ errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ;
+ lem->lem_errors += errors ;
+ mib->fddiPORTLem_Ct += errors ;
+
+ errors = lem->lem_errors ;
+ /*
+ * calculation is called on a intervall of 8 seconds
+ * -> this means, that one error in 8 sec. is one of 8*125*10E6
+ * the same as BER = 10E-9
+ * Please note:
+ * -> 9 errors in 8 seconds mean:
+ * BER = 9 * 10E-9 and this is
+ * < 10E-8, so the limit of 10E-8 is not reached!
+ */
+
+ if (!errors) ber = 15 ;
+ else if (errors <= 9) ber = 9 ;
+ else if (errors <= 99) ber = 8 ;
+ else if (errors <= 999) ber = 7 ;
+ else if (errors <= 9999) ber = 6 ;
+ else if (errors <= 99999) ber = 5 ;
+ else if (errors <= 999999) ber = 4 ;
+ else if (errors <= 9999999) ber = 3 ;
+ else if (errors <= 99999999) ber = 2 ;
+ else if (errors <= 999999999) ber = 1 ;
+ else ber = 0 ;
+
+ /*
+ * weighted average
+ */
+ ber *= 100 ;
+ lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ;
+ lem->lem_float_ber /= 10 ;
+ mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ;
+ if (mib->fddiPORTLer_Estimate < 4) {
+ mib->fddiPORTLer_Estimate = 4 ;
+ }
+
+ if (lem->lem_errors) {
+ DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ;
+ DB_PCMN(1,"errors : %ld\n",lem->lem_errors,0) ;
+ DB_PCMN(1,"sum_errors : %ld\n",mib->fddiPORTLem_Ct,0) ;
+ DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ;
+ DB_PCMN(1,"float BER : 10E-(%d/100)\n",lem->lem_float_ber,0) ;
+ DB_PCMN(1,"avg. BER : 10E-%d\n",
+ mib->fddiPORTLer_Estimate,0) ;
+ }
+
+ lem->lem_errors = 0L ;
+
+#ifndef SLIM_SMT
+ cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ?
+ TRUE : FALSE ;
+#ifdef SMT_EXT_CUTOFF
+ smt_ler_alarm_check(smc,phy,cond) ;
+#endif /* nSMT_EXT_CUTOFF */
+ if (cond != mib->fddiPORTLerFlag) {
+ smt_srf_event(smc,SMT_COND_PORT_LER,
+ (int) (INDEX_PORT+ phy->np) ,cond) ;
+ }
+#endif
+
+ if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) {
+ phy->pc_lem_fail = TRUE ; /* flag */
+ mib->fddiPORTLem_Reject_Ct++ ;
+ /*
+ * "forgive 10e-2" if we cutoff so we can come
+ * up again ..
+ */
+ lem->lem_float_ber += 2*100 ;
+
+ /*PC81b*/
+#ifdef CONCENTRATOR
+ DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n",
+ phy->np, mib->fddiPORTLer_Cutoff) ;
+#endif
+#ifdef SMT_EXT_CUTOFF
+ smt_port_off_event(smc,phy->np);
+#else /* nSMT_EXT_CUTOFF */
+ queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
+#endif /* nSMT_EXT_CUTOFF */
+ }
+}
+
+/*
+ * called by SMT to calculate LEM bit error rate
+ */
+void sm_lem_evaluate(smc)
+struct s_smc *smc ;
+{
+ int np ;
+
+ for (np = 0 ; np < NUMPHYS ; np++)
+ lem_evaluate(smc,&smc->y[np]) ;
+}
+
+static void lem_check_lct(smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy ;
+{
+ struct lem_counter *lem = &phy->lem ;
+ struct fddi_mib_p *mib ;
+ int errors ;
+
+ mib = phy->mib ;
+
+ phy->pc_lem_fail = FALSE ; /* flag */
+ errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ;
+ lem->lem_errors += errors ;
+ mib->fddiPORTLem_Ct += errors ;
+ if (lem->lem_errors) {
+ switch(phy->lc_test) {
+ case LC_SHORT:
+ if (lem->lem_errors >= smc->s.lct_short)
+ phy->pc_lem_fail = TRUE ;
+ break ;
+ case LC_MEDIUM:
+ if (lem->lem_errors >= smc->s.lct_medium)
+ phy->pc_lem_fail = TRUE ;
+ break ;
+ case LC_LONG:
+ if (lem->lem_errors >= smc->s.lct_long)
+ phy->pc_lem_fail = TRUE ;
+ break ;
+ case LC_EXTENDED:
+ if (lem->lem_errors >= smc->s.lct_extended)
+ phy->pc_lem_fail = TRUE ;
+ break ;
+ }
+ DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ;
+ }
+ if (phy->pc_lem_fail) {
+ mib->fddiPORTLCTFail_Ct++ ;
+ mib->fddiPORTLem_Reject_Ct++ ;
+ }
+ else
+ mib->fddiPORTLCTFail_Ct = 0 ;
+}
+
+/*
+ * LEM functions
+ */
+static void sm_ph_lem_start(smc,np,threshold)
+struct s_smc *smc ;
+int np;
+int threshold;
+{
+ struct lem_counter *lem = &smc->y[np].lem ;
+
+ lem->lem_on = 1 ;
+ lem->lem_errors = 0L ;
+
+ /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too
+ * often.
+ */
+
+ outpw(PLC(np,PL_LE_THRESHOLD),threshold) ;
+ (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */
+
+ /* enable LE INT */
+ SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ;
+}
+
+static void sm_ph_lem_stop(smc,np)
+struct s_smc *smc ;
+int np;
+{
+ struct lem_counter *lem = &smc->y[np].lem ;
+
+ lem->lem_on = 0 ;
+ CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;
+}
+
+/* ARGSUSED */
+void sm_pm_ls_latch(smc,phy,on_off)
+struct s_smc *smc ;
+int phy;
+int on_off; /* en- or disable ident. ls */
+{
+ SK_UNUSED(smc) ;
+
+ phy = phy ; on_off = on_off ;
+}
+
+
+/*
+ * PCM pseudo code
+ * receive actions are called AFTER the bit n is received,
+ * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received
+ */
+
+/*
+ * PCM pseudo code 5.1 .. 6.1
+ */
+static void pc_rcode_actions(smc,bit,phy)
+struct s_smc *smc ;
+int bit;
+struct s_phy *phy;
+{
+ struct fddi_mib_p *mib ;
+
+ mib = phy->mib ;
+
+ DB_PCMN(1,"SIG rec %x %x: \n", bit,phy->r_val[bit] ) ;
+ bit++ ;
+
+ switch(bit) {
+ case 0:
+ case 1:
+ case 2:
+ break ;
+ case 3 :
+ if (phy->r_val[1] == 0 && phy->r_val[2] == 0)
+ mib->fddiPORTNeighborType = TA ;
+ else if (phy->r_val[1] == 0 && phy->r_val[2] == 1)
+ mib->fddiPORTNeighborType = TB ;
+ else if (phy->r_val[1] == 1 && phy->r_val[2] == 0)
+ mib->fddiPORTNeighborType = TS ;
+ else if (phy->r_val[1] == 1 && phy->r_val[2] == 1)
+ mib->fddiPORTNeighborType = TM ;
+ break ;
+ case 4:
+ if (mib->fddiPORTMy_Type == TM &&
+ mib->fddiPORTNeighborType == TM) {
+ DB_PCMN(1,"PCM %c : E100 withhold M-M\n",
+ phy->phy_name,0) ;
+ mib->fddiPORTPC_Withhold = PC_WH_M_M ;
+ RS_SET(smc,RS_EVENT) ;
+ }
+ else if (phy->t_val[3] || phy->r_val[3]) {
+ mib->fddiPORTPC_Withhold = PC_WH_NONE ;
+ if (mib->fddiPORTMy_Type == TM ||
+ mib->fddiPORTNeighborType == TM)
+ phy->pc_mode = PM_TREE ;
+ else
+ phy->pc_mode = PM_PEER ;
+
+ /* reevaluate the selection criteria (wc_flag) */
+ all_selection_criteria (smc);
+
+ if (phy->wc_flag) {
+ mib->fddiPORTPC_Withhold = PC_WH_PATH ;
+ }
+ }
+ else {
+ mib->fddiPORTPC_Withhold = PC_WH_OTHER ;
+ RS_SET(smc,RS_EVENT) ;
+ DB_PCMN(1,"PCM %c : E101 withhold other\n",
+ phy->phy_name,0) ;
+ }
+ phy->twisted = ((mib->fddiPORTMy_Type != TS) &&
+ (mib->fddiPORTMy_Type != TM) &&
+ (mib->fddiPORTNeighborType ==
+ mib->fddiPORTMy_Type)) ;
+ if (phy->twisted) {
+ DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n",
+ phy->phy_name,0) ;
+ }
+ break ;
+ case 5 :
+ break ;
+ case 6:
+ if (phy->t_val[4] || phy->r_val[4]) {
+ if ((phy->t_val[4] && phy->t_val[5]) ||
+ (phy->r_val[4] && phy->r_val[5]) )
+ phy->lc_test = LC_EXTENDED ;
+ else
+ phy->lc_test = LC_LONG ;
+ }
+ else if (phy->t_val[5] || phy->r_val[5])
+ phy->lc_test = LC_MEDIUM ;
+ else
+ phy->lc_test = LC_SHORT ;
+ switch (phy->lc_test) {
+ case LC_SHORT : /* 50ms */
+ outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ;
+ phy->t_next[7] = smc->s.pcm_lc_short ;
+ break ;
+ case LC_MEDIUM : /* 500ms */
+ outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ;
+ phy->t_next[7] = smc->s.pcm_lc_medium ;
+ break ;
+ case LC_LONG :
+ SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
+ phy->t_next[7] = smc->s.pcm_lc_long ;
+ break ;
+ case LC_EXTENDED :
+ SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
+ phy->t_next[7] = smc->s.pcm_lc_extended ;
+ break ;
+ }
+ if (phy->t_next[7] > smc->s.pcm_lc_medium) {
+ start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy);
+ }
+ DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ;
+ phy->t_next[9] = smc->s.pcm_t_next_9 ;
+ break ;
+ case 7:
+ if (phy->t_val[6]) {
+ phy->cf_loop = TRUE ;
+ }
+ phy->td_flag = TRUE ;
+ break ;
+ case 8:
+ if (phy->t_val[7] || phy->r_val[7]) {
+ DB_PCMN(1,"PCM %c : E103 LCT fail %s\n",
+ phy->phy_name,phy->t_val[7]? "local":"remote") ;
+ queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
+ }
+ break ;
+ case 9:
+ if (phy->t_val[8] || phy->r_val[8]) {
+ if (phy->t_val[8])
+ phy->cf_loop = TRUE ;
+ phy->td_flag = TRUE ;
+ }
+ break ;
+ case 10:
+ if (phy->r_val[9]) {
+ /* neighbor intends to have MAC on output */ ;
+ mib->fddiPORTMacIndicated.R_val = TRUE ;
+ }
+ else {
+ /* neighbor does not intend to have MAC on output */ ;
+ mib->fddiPORTMacIndicated.R_val = FALSE ;
+ }
+ break ;
+ }
+}
+
+/*
+ * PCM pseudo code 5.1 .. 6.1
+ */
+static void pc_tcode_actions(smc,bit,phy)
+struct s_smc *smc ;
+const int bit;
+struct s_phy *phy;
+{
+ int np = phy->np ;
+ struct fddi_mib_p *mib ;
+
+ mib = phy->mib ;
+
+ switch(bit) {
+ case 0:
+ phy->t_val[0] = 0 ; /* no escape used */
+ break ;
+ case 1:
+ if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM)
+ phy->t_val[1] = 1 ;
+ else
+ phy->t_val[1] = 0 ;
+ break ;
+ case 2 :
+ if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM)
+ phy->t_val[2] = 1 ;
+ else
+ phy->t_val[2] = 0 ;
+ break ;
+ case 3:
+ {
+ int type,ne ;
+ int policy ;
+
+ type = mib->fddiPORTMy_Type ;
+ ne = mib->fddiPORTNeighborType ;
+ policy = smc->mib.fddiSMTConnectionPolicy ;
+
+ phy->t_val[3] = 1 ; /* Accept connection */
+ switch (type) {
+ case TA :
+ if (
+ ((policy & POLICY_AA) && ne == TA) ||
+ ((policy & POLICY_AB) && ne == TB) ||
+ ((policy & POLICY_AS) && ne == TS) ||
+ ((policy & POLICY_AM) && ne == TM) )
+ phy->t_val[3] = 0 ; /* Reject */
+ break ;
+ case TB :
+ if (
+ ((policy & POLICY_BA) && ne == TA) ||
+ ((policy & POLICY_BB) && ne == TB) ||
+ ((policy & POLICY_BS) && ne == TS) ||
+ ((policy & POLICY_BM) && ne == TM) )
+ phy->t_val[3] = 0 ; /* Reject */
+ break ;
+ case TS :
+ if (
+ ((policy & POLICY_SA) && ne == TA) ||
+ ((policy & POLICY_SB) && ne == TB) ||
+ ((policy & POLICY_SS) && ne == TS) ||
+ ((policy & POLICY_SM) && ne == TM) )
+ phy->t_val[3] = 0 ; /* Reject */
+ break ;
+ case TM :
+ if ( ne == TM ||
+ ((policy & POLICY_MA) && ne == TA) ||
+ ((policy & POLICY_MB) && ne == TB) ||
+ ((policy & POLICY_MS) && ne == TS) ||
+ ((policy & POLICY_MM) && ne == TM) )
+ phy->t_val[3] = 0 ; /* Reject */
+ break ;
+ }
+#ifndef SLIM_SMT
+ /*
+ * detect undesirable connection attempt event
+ */
+ if ( (type == TA && ne == TA ) ||
+ (type == TA && ne == TS ) ||
+ (type == TB && ne == TB ) ||
+ (type == TB && ne == TS ) ||
+ (type == TS && ne == TA ) ||
+ (type == TS && ne == TB ) ) {
+ smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION,
+ (int) (INDEX_PORT+ phy->np) ,0) ;
+ }
+#endif
+ }
+ break ;
+ case 4:
+ if (mib->fddiPORTPC_Withhold == PC_WH_NONE) {
+ if (phy->pc_lem_fail) {
+ phy->t_val[4] = 1 ; /* long */
+ phy->t_val[5] = 0 ;
+ }
+ else {
+ phy->t_val[4] = 0 ;
+ if (mib->fddiPORTLCTFail_Ct > 0)
+ phy->t_val[5] = 1 ; /* medium */
+ else
+ phy->t_val[5] = 0 ; /* short */
+
+ /*
+ * Implementers choice: use medium
+ * instead of short when undesired
+ * connection attempt is made.
+ */
+ if (phy->wc_flag)
+ phy->t_val[5] = 1 ; /* medium */
+ }
+ mib->fddiPORTConnectState = PCM_CONNECTING ;
+ }
+ else {
+ mib->fddiPORTConnectState = PCM_STANDBY ;
+ phy->t_val[4] = 1 ; /* extended */
+ phy->t_val[5] = 1 ;
+ }
+ break ;
+ case 5:
+ break ;
+ case 6:
+ /* we do NOT have a MAC for LCT */
+ phy->t_val[6] = 0 ;
+ break ;
+ case 7:
+ phy->cf_loop = FALSE ;
+ lem_check_lct(smc,phy) ;
+ if (phy->pc_lem_fail) {
+ DB_PCMN(1,"PCM %c : E104 LCT failed\n",
+ phy->phy_name,0) ;
+ phy->t_val[7] = 1 ;
+ }
+ else
+ phy->t_val[7] = 0 ;
+ break ;
+ case 8:
+ phy->t_val[8] = 0 ; /* Don't request MAC loopback */
+ break ;
+ case 9:
+ phy->cf_loop = 0 ;
+ if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) ||
+ ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) {
+ queue_event(smc,EVENT_PCM+np,PC_START) ;
+ break ;
+ }
+ phy->t_val[9] = FALSE ;
+ switch (smc->s.sas) {
+ case SMT_DAS :
+ /*
+ * MAC intended on output
+ */
+ if (phy->pc_mode == PM_TREE) {
+ if ((np == PB) || ((np == PA) &&
+ (smc->y[PB].mib->fddiPORTConnectState !=
+ PCM_ACTIVE)))
+ phy->t_val[9] = TRUE ;
+ }
+ else {
+ if (np == PB)
+ phy->t_val[9] = TRUE ;
+ }
+ break ;
+ case SMT_SAS :
+ if (np == PS)
+ phy->t_val[9] = TRUE ;
+ break ;
+#ifdef CONCENTRATOR
+ case SMT_NAC :
+ /*
+ * MAC intended on output
+ */
+ if (np == PB)
+ phy->t_val[9] = TRUE ;
+ break ;
+#endif
+ }
+ mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ;
+ break ;
+ }
+ DB_PCMN(1,"SIG snd %x %x: \n", bit,phy->t_val[bit] ) ;
+}
+
+/*
+ * return status twisted (called by SMT)
+ */
+int pcm_status_twisted(smc)
+struct s_smc *smc ;
+{
+ int twist = 0 ;
+ if (smc->s.sas != SMT_DAS)
+ return(0) ;
+ if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE))
+ twist |= 1 ;
+ if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE))
+ twist |= 2 ;
+ return(twist) ;
+}
+
+/*
+ * return status (called by SMT)
+ * type
+ * state
+ * remote phy type
+ * remote mac yes/no
+ */
+void pcm_status_state(smc,np,type,state,remote,mac)
+struct s_smc *smc ;
+int np;
+int *type;
+int *state;
+int *remote;
+int *mac;
+{
+ struct s_phy *phy = &smc->y[np] ;
+ struct fddi_mib_p *mib ;
+
+ mib = phy->mib ;
+
+ /* remote PHY type and MAC - set only if active */
+ *mac = 0 ;
+ *type = mib->fddiPORTMy_Type ; /* our PHY type */
+ *state = mib->fddiPORTConnectState ;
+ *remote = mib->fddiPORTNeighborType ;
+
+ switch(mib->fddiPORTPCMState) {
+ case PC8_ACTIVE :
+ *mac = mib->fddiPORTMacIndicated.R_val ;
+ break ;
+ }
+}
+
+/*
+ * return rooted station status (called by SMT)
+ */
+int pcm_rooted_station(smc)
+struct s_smc *smc ;
+{
+ int n ;
+
+ for (n = 0 ; n < NUMPHYS ; n++) {
+ if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE &&
+ smc->y[n].mib->fddiPORTNeighborType == TM)
+ return(0) ;
+ }
+ return(1) ;
+}
+
+/*
+ * Interrupt actions for PLC & PCM events
+ */
+void plc_irq(smc,np,cmd)
+struct s_smc *smc ;
+int np; /* PHY index */
+unsigned int cmd;
+{
+ struct s_phy *phy = &smc->y[np] ;
+ struct s_plc *plc = &phy->plc ;
+ int n ;
+#ifdef SUPERNET_3
+ int corr_mask ;
+#endif /* SUPERNET_3 */
+ int i ;
+
+ if (np >= smc->s.numphys) {
+ plc->soft_err++ ;
+ return ;
+ }
+ if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/
+ /*
+ * Check whether the SRF Condition occured.
+ */
+ if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
+ /*
+ * This is the real Elasticity Error.
+ * More than one in a row are treated as a
+ * single one.
+ * Only count this in the active state.
+ */
+ phy->mib->fddiPORTEBError_Ct ++ ;
+
+ }
+
+ plc->ebuf_err++ ;
+ if (plc->ebuf_cont <= 1000) {
+ /*
+ * Prevent counter from being wrapped after
+ * hanging years in that interrupt.
+ */
+ plc->ebuf_cont++ ; /* Ebuf continous error */
+ }
+
+#ifdef SUPERNET_3
+ if (plc->ebuf_cont == 1000 &&
+ ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) ==
+ PLC_REV_SN3)) {
+ /*
+ * This interrupt remeained high for at least
+ * 1000 consecutive interrupt calls.
+ *
+ * This is caused by a hardware error of the
+ * ORION part of the Supernet III chipset.
+ *
+ * Disable this bit from the mask.
+ */
+ corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ;
+ outpw(PLC(np,PL_INTR_MASK),corr_mask);
+
+ /*
+ * Disconnect from the ring.
+ * Call the driver with the reset indication.
+ */
+ queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+
+ /*
+ * Make an error log entry.
+ */
+ SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ;
+
+ /*
+ * Indicate the Reset.
+ */
+ drv_reset_indication(smc) ;
+ }
+#endif /* SUPERNET_3 */
+ } else {
+ /* Reset the continous error variable */
+ plc->ebuf_cont = 0 ; /* reset Ebuf continous error */
+ }
+ if (cmd & PL_PHYINV) { /* physical layer invalid signal */
+ plc->phyinv++ ;
+ }
+ if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/
+ plc->vsym_ctr++ ;
+ }
+ if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
+ plc->mini_ctr++ ;
+ }
+ if (cmd & PL_LE_CTR) { /* link error event counter */
+ int j ;
+
+ /*
+ * note: PL_LINK_ERR_CTR MUST be read to clear it
+ */
+ j = inpw(PLC(np,PL_LE_THRESHOLD)) ;
+ i = inpw(PLC(np,PL_LINK_ERR_CTR)) ;
+
+ if (i < j) {
+ /* wrapped around */
+ i += 256 ;
+ }
+
+ if (phy->lem.lem_on) {
+ /* Note: Lem errors shall only be counted when
+ * link is ACTIVE or LCT is active.
+ */
+ phy->lem.lem_errors += i ;
+ phy->mib->fddiPORTLem_Ct += i ;
+ }
+ }
+ if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */
+ if (plc->p_state == PS_LCT) {
+ /*
+ * end of LCT
+ */
+ ;
+ }
+ plc->tpc_exp++ ;
+ }
+ if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/
+ switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) {
+ case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ;
+ case PL_I_HALT : phy->curr_ls = PC_HLS ; break ;
+ case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ;
+ case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ;
+ }
+ }
+ if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */
+ int reason;
+
+ reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ;
+
+ switch (reason) {
+ case PL_B_PCS : plc->b_pcs++ ; break ;
+ case PL_B_TPC : plc->b_tpc++ ; break ;
+ case PL_B_TNE : plc->b_tne++ ; break ;
+ case PL_B_QLS : plc->b_qls++ ; break ;
+ case PL_B_ILS : plc->b_ils++ ; break ;
+ case PL_B_HLS : plc->b_hls++ ; break ;
+ }
+
+ /*jd 05-Aug-1999 changed: Bug #10419 */
+ DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag);
+ if (smc->e.DisconnectFlag == FALSE) {
+ DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason);
+ queue_event(smc,EVENT_PCM+np,PC_START) ;
+ }
+ else {
+ DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason);
+ }
+ return ;
+ }
+ /*
+ * If both CODE & ENABLE are set ignore enable
+ */
+ if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */
+ queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ;
+ n = inpw(PLC(np,PL_RCV_VECTOR)) ;
+ for (i = 0 ; i < plc->p_bits ; i++) {
+ phy->r_val[plc->p_start+i] = n & 1 ;
+ n >>= 1 ;
+ }
+ }
+ else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/
+ queue_event(smc,EVENT_PCM+np,PC_JOIN) ;
+ }
+ if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */
+ /*PC22b*/
+ if (!phy->tr_flag) {
+ DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n",
+ np,smc->mib.fddiSMTECMState) ;
+ phy->tr_flag = TRUE ;
+ smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ;
+ queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
+ }
+ }
+ /*
+ * filter PLC glitch ???
+ * QLS || HLS only while in PC2_TRACE state
+ */
+ if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) {
+ /*PC22a*/
+ if (smc->e.path_test == PT_PASSED) {
+ DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np),
+ phy->mib->fddiPORTPCMState) ;
+
+ smc->e.path_test = PT_PENDING ;
+ queue_event(smc,EVENT_ECM,EC_PATH_TEST) ;
+ }
+ }
+ if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */
+ /* break_required (TNE > NS_Max) */
+ if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) {
+ if (!phy->tr_flag) {
+ DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE");
+ queue_event(smc,EVENT_PCM+np,PC_START) ;
+ return ;
+ }
+ }
+ }
+#if 0
+ if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/
+ /*
+ * It's a bug by AMD
+ */
+ plc->np_err++ ;
+ }
+ /* pin inactiv (GND) */
+ if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */
+ plc->parity_err++ ;
+ }
+ if (cmd & PL_LSDO) { /* carrier detected */
+ ;
+ }
+#endif
+}
+
+void pcm_set_lct_short(smc,n)
+struct s_smc *smc ;
+int n ;
+{
+ if (n <= 0 || n > 1000)
+ return ;
+ smc->s.lct_short = n ;
+}
+
+#ifdef DEBUG
+/*
+ * fill state struct
+ */
+void pcm_get_state(smc,state)
+struct s_smc *smc ;
+struct smt_state *state ;
+{
+ struct s_phy *phy ;
+ struct pcm_state *pcs ;
+ int i ;
+ int ii ;
+ short rbits ;
+ short tbits ;
+ struct fddi_mib_p *mib ;
+
+ for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ;
+ i++ , phy++, pcs++ ) {
+ mib = phy->mib ;
+ pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ;
+ pcs->pcm_state = (u_char) mib->fddiPORTPCMState ;
+ pcs->pcm_mode = phy->pc_mode ;
+ pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ;
+ pcs->pcm_bsf = mib->fddiPORTBS_Flag ;
+ pcs->pcm_lsf = phy->ls_flag ;
+ pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ;
+ pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ;
+ for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) {
+ rbits <<= 1 ;
+ tbits <<= 1 ;
+ if (phy->r_val[NUMBITS-1-ii])
+ rbits |= 1 ;
+ if (phy->t_val[NUMBITS-1-ii])
+ tbits |= 1 ;
+ }
+ pcs->pcm_r_val = rbits ;
+ pcs->pcm_t_val = tbits ;
+ }
+}
+
+int get_pcm_state(smc,np)
+struct s_smc *smc ;
+int np;
+{
+ int pcs ;
+
+ SK_UNUSED(smc) ;
+
+ switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
+ case PL_PC0 : pcs = PC_STOP ; break ;
+ case PL_PC1 : pcs = PC_START ; break ;
+ case PL_PC2 : pcs = PC_TRACE ; break ;
+ case PL_PC3 : pcs = PC_SIGNAL ; break ;
+ case PL_PC4 : pcs = PC_SIGNAL ; break ;
+ case PL_PC5 : pcs = PC_SIGNAL ; break ;
+ case PL_PC6 : pcs = PC_JOIN ; break ;
+ case PL_PC7 : pcs = PC_JOIN ; break ;
+ case PL_PC8 : pcs = PC_ENABLE ; break ;
+ case PL_PC9 : pcs = PC_MAINT ; break ;
+ default : pcs = PC_DISABLE ; break ;
+ }
+ return(pcs) ;
+}
+
+char *get_linestate(smc,np)
+struct s_smc *smc ;
+int np;
+{
+ char *ls = "" ;
+
+ SK_UNUSED(smc) ;
+
+ switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) {
+ case PL_L_NLS : ls = "NOISE" ; break ;
+ case PL_L_ALS : ls = "ACTIV" ; break ;
+ case PL_L_UND : ls = "UNDEF" ; break ;
+ case PL_L_ILS4: ls = "ILS 4" ; break ;
+ case PL_L_QLS : ls = "QLS" ; break ;
+ case PL_L_MLS : ls = "MLS" ; break ;
+ case PL_L_HLS : ls = "HLS" ; break ;
+ case PL_L_ILS16:ls = "ILS16" ; break ;
+#ifdef lint
+ default: ls = "unknown" ; break ;
+#endif
+ }
+ return(ls) ;
+}
+
+char *get_pcmstate(smc,np)
+struct s_smc *smc ;
+int np;
+{
+ char *pcs ;
+
+ SK_UNUSED(smc) ;
+
+ switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
+ case PL_PC0 : pcs = "OFF" ; break ;
+ case PL_PC1 : pcs = "BREAK" ; break ;
+ case PL_PC2 : pcs = "TRACE" ; break ;
+ case PL_PC3 : pcs = "CONNECT"; break ;
+ case PL_PC4 : pcs = "NEXT" ; break ;
+ case PL_PC5 : pcs = "SIGNAL" ; break ;
+ case PL_PC6 : pcs = "JOIN" ; break ;
+ case PL_PC7 : pcs = "VERIFY" ; break ;
+ case PL_PC8 : pcs = "ACTIV" ; break ;
+ case PL_PC9 : pcs = "MAINT" ; break ;
+ default : pcs = "UNKNOWN" ; break ;
+ }
+ return(pcs) ;
+}
+
+void list_phy(smc)
+struct s_smc *smc ;
+{
+ struct s_plc *plc ;
+ int np ;
+
+ for (np = 0 ; np < NUMPHYS ; np++) {
+ plc = &smc->y[np].plc ;
+ printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ;
+ printf("\tsoft_error: %ld \t\tPC_Start : %ld\n",
+ plc->soft_err,plc->b_pcs);
+ printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n",
+ plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ;
+ printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n",
+ plc->ebuf_err,plc->b_tne) ;
+ printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n",
+ plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ;
+ printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n",
+ plc->vsym_ctr,plc->b_ils) ;
+ printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n",
+ plc->mini_ctr,plc->b_hls) ;
+ printf("\tnodepr_err: %ld\n",plc->np_err) ;
+ printf("\tTPC_exp : %ld\n",plc->tpc_exp) ;
+ printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ;
+ }
+}
+
+
+#ifdef CONCENTRATOR
+void pcm_lem_dump(smc)
+struct s_smc *smc ;
+{
+ int i ;
+ struct s_phy *phy ;
+ struct fddi_mib_p *mib ;
+
+ char *entostring() ;
+
+ printf("PHY errors BER\n") ;
+ printf("----------------------\n") ;
+ for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) {
+ if (!plc_is_installed(smc,i))
+ continue ;
+ mib = phy->mib ;
+ printf("%s\t%ld\t10E-%d\n",
+ entostring(smc,ENTITY_PHY(i)),
+ mib->fddiPORTLem_Ct,
+ mib->fddiPORTLer_Estimate) ;
+ }
+}
+#endif
+#endif
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
new file mode 100644
index 000000000..d53355bac
--- /dev/null
+++ b/drivers/net/skfp/pmf.c
@@ -0,0 +1,1701 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ Parameter Management Frame processing for SMT 7.2
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef SLIM_SMT
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)pmf.c 1.37 97/08/04 (C) SK " ;
+#endif
+
+static int smt_authorize() ;
+static int smt_check_set_count() ;
+static const struct s_p_tab *smt_get_ptab() ;
+static int smt_mib_phys() ;
+int smt_set_para() ;
+void smt_add_para() ;
+
+#define MOFFSS(e) ((int)&(((struct fddi_mib *)0)->e))
+#define MOFFSA(e) ((int) (((struct fddi_mib *)0)->e))
+
+#define MOFFMS(e) ((int)&(((struct fddi_mib_m *)0)->e))
+#define MOFFMA(e) ((int) (((struct fddi_mib_m *)0)->e))
+
+#define MOFFAS(e) ((int)&(((struct fddi_mib_a *)0)->e))
+#define MOFFAA(e) ((int) (((struct fddi_mib_a *)0)->e))
+
+#define MOFFPS(e) ((int)&(((struct fddi_mib_p *)0)->e))
+#define MOFFPA(e) ((int) (((struct fddi_mib_p *)0)->e))
+
+
+#define AC_G 0x01 /* Get */
+#define AC_GR 0x02 /* Get/Set */
+#define AC_S 0x04 /* Set */
+#define AC_NA 0x08
+#define AC_GROUP 0x10 /* Group */
+#define MS2BCLK(x) ((x)*12500L)
+/*
+ F LFag (byte)
+ B byte
+ S u_short 16 bit
+ C Counter 32 bit
+ L Long 32 bit
+ T Timer_2 32 bit
+ P TimeStamp ;
+ A LongAddress (6 byte)
+ E Enum 16 bit
+ R ResId 16 Bit
+*/
+static const struct s_p_tab {
+ u_short p_num ; /* parameter code */
+ u_char p_access ; /* access rights */
+ u_short p_offset ; /* offset in mib */
+ char p_swap[3] ; /* format string */
+} p_tab[] = {
+ /* StationIdGrp */
+ { SMT_P100A,AC_GROUP } ,
+ { SMT_P100B,AC_G, MOFFSS(fddiSMTStationId), "8" } ,
+ { SMT_P100D,AC_G, MOFFSS(fddiSMTOpVersionId), "S" } ,
+ { SMT_P100E,AC_G, MOFFSS(fddiSMTHiVersionId), "S" } ,
+ { SMT_P100F,AC_G, MOFFSS(fddiSMTLoVersionId), "S" } ,
+ { SMT_P1010,AC_G, MOFFSA(fddiSMTManufacturerData), "D" } ,
+ { SMT_P1011,AC_GR, MOFFSA(fddiSMTUserData), "D" } ,
+ { SMT_P1012,AC_G, MOFFSS(fddiSMTMIBVersionId), "S" } ,
+
+ /* StationConfigGrp */
+ { SMT_P1014,AC_GROUP } ,
+ { SMT_P1015,AC_G, MOFFSS(fddiSMTMac_Ct), "B" } ,
+ { SMT_P1016,AC_G, MOFFSS(fddiSMTNonMaster_Ct), "B" } ,
+ { SMT_P1017,AC_G, MOFFSS(fddiSMTMaster_Ct), "B" } ,
+ { SMT_P1018,AC_G, MOFFSS(fddiSMTAvailablePaths), "B" } ,
+ { SMT_P1019,AC_G, MOFFSS(fddiSMTConfigCapabilities),"S" } ,
+ { SMT_P101A,AC_GR, MOFFSS(fddiSMTConfigPolicy), "wS" } ,
+ { SMT_P101B,AC_GR, MOFFSS(fddiSMTConnectionPolicy),"wS" } ,
+ { SMT_P101D,AC_GR, MOFFSS(fddiSMTTT_Notify), "wS" } ,
+ { SMT_P101E,AC_GR, MOFFSS(fddiSMTStatRptPolicy), "bB" } ,
+ { SMT_P101F,AC_GR, MOFFSS(fddiSMTTrace_MaxExpiration),"lL" } ,
+ { SMT_P1020,AC_G, MOFFSA(fddiSMTPORTIndexes), "II" } ,
+ { SMT_P1021,AC_G, MOFFSS(fddiSMTMACIndexes), "I" } ,
+ { SMT_P1022,AC_G, MOFFSS(fddiSMTBypassPresent), "F" } ,
+
+ /* StatusGrp */
+ { SMT_P1028,AC_GROUP } ,
+ { SMT_P1029,AC_G, MOFFSS(fddiSMTECMState), "E" } ,
+ { SMT_P102A,AC_G, MOFFSS(fddiSMTCF_State), "E" } ,
+ { SMT_P102C,AC_G, MOFFSS(fddiSMTRemoteDisconnectFlag),"F" } ,
+ { SMT_P102D,AC_G, MOFFSS(fddiSMTStationStatus), "E" } ,
+ { SMT_P102E,AC_G, MOFFSS(fddiSMTPeerWrapFlag), "F" } ,
+
+ /* MIBOperationGrp */
+ { SMT_P1032,AC_GROUP } ,
+ { SMT_P1033,AC_G, MOFFSA(fddiSMTTimeStamp),"P" } ,
+ { SMT_P1034,AC_G, MOFFSA(fddiSMTTransitionTimeStamp),"P" } ,
+ /* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */
+ { SMT_P1035,AC_G, MOFFSS(fddiSMTSetCount),"4P" } ,
+ { SMT_P1036,AC_G, MOFFSS(fddiSMTLastSetStationId),"8" } ,
+
+ { SMT_P103C,AC_S, 0, "wS" } ,
+
+ /*
+ * PRIVATE EXTENSIONS
+ * only accessable locally to get/set passwd
+ */
+ { SMT_P10F0,AC_GR, MOFFSA(fddiPRPMFPasswd), "8" } ,
+ { SMT_P10F1,AC_GR, MOFFSS(fddiPRPMFStation), "8" } ,
+#ifdef ESS
+ { SMT_P10F2,AC_GR, MOFFSS(fddiESSPayload), "lL" } ,
+ { SMT_P10F3,AC_GR, MOFFSS(fddiESSOverhead), "lL" } ,
+ { SMT_P10F4,AC_GR, MOFFSS(fddiESSMaxTNeg), "lL" } ,
+ { SMT_P10F5,AC_GR, MOFFSS(fddiESSMinSegmentSize), "lL" } ,
+ { SMT_P10F6,AC_GR, MOFFSS(fddiESSCategory), "lL" } ,
+ { SMT_P10F7,AC_GR, MOFFSS(fddiESSSynchTxMode), "wS" } ,
+#endif
+#ifdef SBA
+ { SMT_P10F8,AC_GR, MOFFSS(fddiSBACommand), "bF" } ,
+ { SMT_P10F9,AC_GR, MOFFSS(fddiSBAAvailable), "bF" } ,
+#endif
+ /* MAC Attributes */
+ { SMT_P200A,AC_GROUP } ,
+ { SMT_P200B,AC_G, MOFFMS(fddiMACFrameStatusFunctions),"S" } ,
+ { SMT_P200D,AC_G, MOFFMS(fddiMACT_MaxCapabilitiy),"T" } ,
+ { SMT_P200E,AC_G, MOFFMS(fddiMACTVXCapabilitiy),"T" } ,
+
+ /* ConfigGrp */
+ { SMT_P2014,AC_GROUP } ,
+ { SMT_P2016,AC_G, MOFFMS(fddiMACAvailablePaths), "B" } ,
+ { SMT_P2017,AC_G, MOFFMS(fddiMACCurrentPath), "S" } ,
+ { SMT_P2018,AC_G, MOFFMS(fddiMACUpstreamNbr), "A" } ,
+ { SMT_P2019,AC_G, MOFFMS(fddiMACDownstreamNbr), "A" } ,
+ { SMT_P201A,AC_G, MOFFMS(fddiMACOldUpstreamNbr), "A" } ,
+ { SMT_P201B,AC_G, MOFFMS(fddiMACOldDownstreamNbr),"A" } ,
+ { SMT_P201D,AC_G, MOFFMS(fddiMACDupAddressTest), "E" } ,
+ { SMT_P2020,AC_GR, MOFFMS(fddiMACRequestedPaths), "wS" } ,
+ { SMT_P2021,AC_G, MOFFMS(fddiMACDownstreamPORTType),"E" } ,
+ { SMT_P2022,AC_G, MOFFMS(fddiMACIndex), "S" } ,
+
+ /* AddressGrp */
+ { SMT_P2028,AC_GROUP } ,
+ { SMT_P2029,AC_G, MOFFMS(fddiMACSMTAddress), "A" } ,
+
+ /* OperationGrp */
+ { SMT_P2032,AC_GROUP } ,
+ { SMT_P2033,AC_G, MOFFMS(fddiMACT_Req), "T" } ,
+ { SMT_P2034,AC_G, MOFFMS(fddiMACT_Neg), "T" } ,
+ { SMT_P2035,AC_G, MOFFMS(fddiMACT_Max), "T" } ,
+ { SMT_P2036,AC_G, MOFFMS(fddiMACTvxValue), "T" } ,
+ { SMT_P2038,AC_G, MOFFMS(fddiMACT_Pri0), "T" } ,
+ { SMT_P2039,AC_G, MOFFMS(fddiMACT_Pri1), "T" } ,
+ { SMT_P203A,AC_G, MOFFMS(fddiMACT_Pri2), "T" } ,
+ { SMT_P203B,AC_G, MOFFMS(fddiMACT_Pri3), "T" } ,
+ { SMT_P203C,AC_G, MOFFMS(fddiMACT_Pri4), "T" } ,
+ { SMT_P203D,AC_G, MOFFMS(fddiMACT_Pri5), "T" } ,
+ { SMT_P203E,AC_G, MOFFMS(fddiMACT_Pri6), "T" } ,
+
+
+ /* CountersGrp */
+ { SMT_P2046,AC_GROUP } ,
+ { SMT_P2047,AC_G, MOFFMS(fddiMACFrame_Ct), "C" } ,
+ { SMT_P2048,AC_G, MOFFMS(fddiMACCopied_Ct), "C" } ,
+ { SMT_P2049,AC_G, MOFFMS(fddiMACTransmit_Ct), "C" } ,
+ { SMT_P204A,AC_G, MOFFMS(fddiMACToken_Ct), "C" } ,
+ { SMT_P2051,AC_G, MOFFMS(fddiMACError_Ct), "C" } ,
+ { SMT_P2052,AC_G, MOFFMS(fddiMACLost_Ct), "C" } ,
+ { SMT_P2053,AC_G, MOFFMS(fddiMACTvxExpired_Ct), "C" } ,
+ { SMT_P2054,AC_G, MOFFMS(fddiMACNotCopied_Ct), "C" } ,
+ { SMT_P2056,AC_G, MOFFMS(fddiMACRingOp_Ct), "C" } ,
+
+ /* FrameErrorConditionGrp */
+ { SMT_P205A,AC_GROUP } ,
+ { SMT_P205F,AC_GR, MOFFMS(fddiMACFrameErrorThreshold),"wS" } ,
+ { SMT_P2060,AC_G, MOFFMS(fddiMACFrameErrorRatio), "S" } ,
+
+ /* NotCopiedConditionGrp */
+ { SMT_P2064,AC_GROUP } ,
+ { SMT_P2067,AC_GR, MOFFMS(fddiMACNotCopiedThreshold),"wS" } ,
+ { SMT_P2069,AC_G, MOFFMS(fddiMACNotCopiedRatio), "S" } ,
+
+ /* StatusGrp */
+ { SMT_P206E,AC_GROUP } ,
+ { SMT_P206F,AC_G, MOFFMS(fddiMACRMTState), "S" } ,
+ { SMT_P2070,AC_G, MOFFMS(fddiMACDA_Flag), "F" } ,
+ { SMT_P2071,AC_G, MOFFMS(fddiMACUNDA_Flag), "F" } ,
+ { SMT_P2072,AC_G, MOFFMS(fddiMACFrameErrorFlag), "F" } ,
+ { SMT_P2073,AC_G, MOFFMS(fddiMACNotCopiedFlag), "F" } ,
+ { SMT_P2074,AC_G, MOFFMS(fddiMACMA_UnitdataAvailable),"F" } ,
+ { SMT_P2075,AC_G, MOFFMS(fddiMACHardwarePresent), "F" } ,
+ { SMT_P2076,AC_GR, MOFFMS(fddiMACMA_UnitdataEnable),"bF" } ,
+
+ /*
+ * PRIVATE EXTENSIONS
+ * only accessable locally to get/set TMIN
+ */
+ { SMT_P20F0,AC_NA } ,
+ { SMT_P20F1,AC_GR, MOFFMS(fddiMACT_Min), "lT" } ,
+
+ /* Path Attributes */
+ /*
+ * DON't swap 320B,320F,3210: they are already swapped in swap_para()
+ */
+ { SMT_P320A,AC_GROUP } ,
+ { SMT_P320B,AC_G, MOFFAS(fddiPATHIndex), "r" } ,
+ { SMT_P320F,AC_GR, MOFFAS(fddiPATHSbaPayload), "l4" } ,
+ { SMT_P3210,AC_GR, MOFFAS(fddiPATHSbaOverhead), "l4" } ,
+ /* fddiPATHConfiguration */
+ { SMT_P3212,AC_G, 0, "" } ,
+ { SMT_P3213,AC_GR, MOFFAS(fddiPATHT_Rmode), "lT" } ,
+ { SMT_P3214,AC_GR, MOFFAS(fddiPATHSbaAvailable), "lL" } ,
+ { SMT_P3215,AC_GR, MOFFAS(fddiPATHTVXLowerBound), "lT" } ,
+ { SMT_P3216,AC_GR, MOFFAS(fddiPATHT_MaxLowerBound),"lT" } ,
+ { SMT_P3217,AC_GR, MOFFAS(fddiPATHMaxT_Req), "lT" } ,
+
+ /* Port Attributes */
+ /* ConfigGrp */
+ { SMT_P400A,AC_GROUP } ,
+ { SMT_P400C,AC_G, MOFFPS(fddiPORTMy_Type), "E" } ,
+ { SMT_P400D,AC_G, MOFFPS(fddiPORTNeighborType), "E" } ,
+ { SMT_P400E,AC_GR, MOFFPS(fddiPORTConnectionPolicies),"bB" } ,
+ { SMT_P400F,AC_G, MOFFPS(fddiPORTMacIndicated), "2" } ,
+ { SMT_P4010,AC_G, MOFFPS(fddiPORTCurrentPath), "E" } ,
+ { SMT_P4011,AC_GR, MOFFPA(fddiPORTRequestedPaths), "l4" } ,
+ { SMT_P4012,AC_G, MOFFPS(fddiPORTMACPlacement), "S" } ,
+ { SMT_P4013,AC_G, MOFFPS(fddiPORTAvailablePaths), "B" } ,
+ { SMT_P4016,AC_G, MOFFPS(fddiPORTPMDClass), "E" } ,
+ { SMT_P4017,AC_G, MOFFPS(fddiPORTConnectionCapabilities), "B"} ,
+ { SMT_P401D,AC_G, MOFFPS(fddiPORTIndex), "R" } ,
+
+ /* OperationGrp */
+ { SMT_P401E,AC_GROUP } ,
+ { SMT_P401F,AC_GR, MOFFPS(fddiPORTMaint_LS), "wE" } ,
+ { SMT_P4021,AC_G, MOFFPS(fddiPORTBS_Flag), "F" } ,
+ { SMT_P4022,AC_G, MOFFPS(fddiPORTPC_LS), "E" } ,
+
+ /* ErrorCtrsGrp */
+ { SMT_P4028,AC_GROUP } ,
+ { SMT_P4029,AC_G, MOFFPS(fddiPORTEBError_Ct), "C" } ,
+ { SMT_P402A,AC_G, MOFFPS(fddiPORTLCTFail_Ct), "C" } ,
+
+ /* LerGrp */
+ { SMT_P4032,AC_GROUP } ,
+ { SMT_P4033,AC_G, MOFFPS(fddiPORTLer_Estimate), "F" } ,
+ { SMT_P4034,AC_G, MOFFPS(fddiPORTLem_Reject_Ct), "C" } ,
+ { SMT_P4035,AC_G, MOFFPS(fddiPORTLem_Ct), "C" } ,
+ { SMT_P403A,AC_GR, MOFFPS(fddiPORTLer_Cutoff), "bB" } ,
+ { SMT_P403B,AC_GR, MOFFPS(fddiPORTLer_Alarm), "bB" } ,
+
+ /* StatusGrp */
+ { SMT_P403C,AC_GROUP } ,
+ { SMT_P403D,AC_G, MOFFPS(fddiPORTConnectState), "E" } ,
+ { SMT_P403E,AC_G, MOFFPS(fddiPORTPCMStateX), "E" } ,
+ { SMT_P403F,AC_G, MOFFPS(fddiPORTPC_Withhold), "E" } ,
+ { SMT_P4040,AC_G, MOFFPS(fddiPORTLerFlag), "F" } ,
+ { SMT_P4041,AC_G, MOFFPS(fddiPORTHardwarePresent),"F" } ,
+
+ { SMT_P4046,AC_S, 0, "wS" } ,
+
+ { 0, AC_GROUP } ,
+ { 0 }
+} ;
+
+
+static SMbuf *smt_build_pmf_response() ;
+
+void smt_pmf_received_pack(smc,mb,local)
+struct s_smc *smc ;
+SMbuf *mb ;
+int local ;
+{
+ struct smt_header *sm ;
+ SMbuf *reply ;
+
+ sm = smtod(mb,struct smt_header *) ;
+ DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ;
+#ifdef DEBUG
+ dump_smt(smc,sm,"PMF Received") ;
+#endif
+ /*
+ * Start the watchdog: It may be a long, long packet and
+ * maybe the watchdog occurs ...
+ */
+ smt_start_watchdog(smc) ;
+
+ if (sm->smt_class == SMT_PMF_GET ||
+ sm->smt_class == SMT_PMF_SET) {
+ reply = smt_build_pmf_response(smc,sm,
+ sm->smt_class == SMT_PMF_SET,local) ;
+ if (reply) {
+ sm = smtod(reply,struct smt_header *) ;
+#ifdef DEBUG
+ dump_smt(smc,sm,"PMF Reply") ;
+#endif
+ smt_send_frame(smc,reply,FC_SMT_INFO,local) ;
+ }
+ }
+}
+
+extern SMbuf *smt_get_mbuf() ;
+
+static SMbuf *smt_build_pmf_response(smc,req,set,local)
+struct s_smc *smc ;
+struct smt_header *req ;
+int set ;
+int local ;
+{
+ SMbuf *mb ;
+ struct smt_header *smt ;
+ struct smt_para *pa ;
+ struct smt_p_reason *res ;
+ const struct s_p_tab *pt ;
+ int len ;
+ int index ;
+ int idx_end ;
+ int error ;
+ int range ;
+ SK_LOC_DECL(struct s_pcon,pcon) ;
+ SK_LOC_DECL(struct s_pcon,set_pcon) ;
+
+ /*
+ * build SMT header
+ */
+ if (!(mb = smt_get_mbuf(smc)))
+ return(mb) ;
+
+ smt = smtod(mb, struct smt_header *) ;
+ smt->smt_dest = req->smt_source ; /* DA == source of request */
+ smt->smt_class = req->smt_class ; /* same class (GET/SET) */
+ smt->smt_type = SMT_REPLY ;
+ smt->smt_version = SMT_VID_2 ;
+ smt->smt_tid = req->smt_tid ; /* same TID */
+ smt->smt_pad = 0 ;
+ smt->smt_len = 0 ;
+
+ /*
+ * setup parameter status
+ */
+ pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */
+ pcon.pc_err = 0 ; /* no error */
+ pcon.pc_badset = 0 ; /* no bad set count */
+ pcon.pc_p = (void *) (smt + 1) ; /* paras start here */
+
+ /*
+ * check authoriziation and set count
+ */
+ error = 0 ;
+ if (set) {
+ if (!local && smt_authorize(smc,req))
+ error = SMT_RDF_AUTHOR ;
+ else if (smt_check_set_count(smc,req))
+ pcon.pc_badset = SMT_RDF_BADSET ;
+ }
+ /*
+ * add reason code and all mandatory parameters
+ */
+ res = (struct smt_p_reason *) pcon.pc_p ;
+ smt_add_para(smc,&pcon,(u_short) SMT_P_REASON,0,0) ;
+ smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
+ /* update 1035 and 1036 later if set */
+ set_pcon = pcon ;
+ smt_add_para(smc,&pcon,(u_short) SMT_P1035,0,0) ;
+ smt_add_para(smc,&pcon,(u_short) SMT_P1036,0,0) ;
+
+ pcon.pc_err = error ;
+ len = req->smt_len ;
+ pa = (struct smt_para *) (req + 1) ;
+ /*
+ * process list of paras
+ */
+ while (!pcon.pc_err && len > 0 ) {
+ if (((u_short)len < pa->p_len + PARA_LEN) || (pa->p_len & 3)) {
+ pcon.pc_err = SMT_RDF_LENGTH ;
+ break ;
+ }
+
+ if (((range = (pa->p_type & 0xf000)) == 0x2000) ||
+ range == 0x3000 || range == 0x4000) {
+ /*
+ * get index for PART,MAC ad PATH group
+ */
+ index = *((u_char *)pa + PARA_LEN + 3) ;/* index */
+ idx_end = index ;
+ if (!set && (pa->p_len != 4)) {
+ pcon.pc_err = SMT_RDF_LENGTH ;
+ break ;
+ }
+ if (!index && !set) {
+ switch (range) {
+ case 0x2000 :
+ index = INDEX_MAC ;
+ idx_end = index - 1 + NUMMACS ;
+ break ;
+ case 0x3000 :
+ index = INDEX_PATH ;
+ idx_end = index - 1 + NUMPATHS ;
+ break ;
+ case 0x4000 :
+ index = INDEX_PORT ;
+ idx_end = index - 1 + NUMPHYS ;
+#ifndef CONCENTRATOR
+ if (smc->s.sas == SMT_SAS)
+ idx_end = INDEX_PORT ;
+#endif
+ break ;
+ }
+ }
+ }
+ else {
+ /*
+ * smt group has no index
+ */
+ if (!set && (pa->p_len != 0)) {
+ pcon.pc_err = SMT_RDF_LENGTH ;
+ break ;
+ }
+ index = 0 ;
+ idx_end = 0 ;
+ }
+ while (index <= idx_end) {
+ /*
+ * if group
+ * add all paras of group
+ */
+ pt = smt_get_ptab(pa->p_type) ;
+ if (pt && pt->p_access == AC_GROUP && !set) {
+ pt++ ;
+ while (pt->p_access == AC_G ||
+ pt->p_access == AC_GR) {
+ smt_add_para(smc,&pcon,pt->p_num,
+ index,local);
+ pt++ ;
+ }
+ }
+ /*
+ * ignore
+ * AUTHORIZATION in get/set
+ * SET COUNT in set
+ */
+ else if (pa->p_type != SMT_P_AUTHOR &&
+ (!set || (pa->p_type != SMT_P1035))) {
+ int st ;
+ if (pcon.pc_badset) {
+ smt_add_para(smc,&pcon,pa->p_type,
+ index,local) ;
+ }
+ else if (set) {
+ st = smt_set_para(smc,pa,index,local,1);
+ /*
+ * return para even if error
+ */
+ smt_add_para(smc,&pcon,pa->p_type,
+ index,local) ;
+ pcon.pc_err = st ;
+ }
+ else {
+ if (pt && pt->p_access == AC_S) {
+ pcon.pc_err =
+ SMT_RDF_ILLEGAL ;
+ }
+ smt_add_para(smc,&pcon,pa->p_type,
+ index,local) ;
+ }
+ }
+ if (pcon.pc_err)
+ break ;
+ index++ ;
+ }
+ len -= pa->p_len + PARA_LEN ;
+ pa = (struct smt_para *) ((char *)pa + pa->p_len + PARA_LEN) ;
+ }
+ smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
+ mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
+
+ /* update reason code */
+ res->rdf_reason = pcon.pc_badset ? pcon.pc_badset :
+ pcon.pc_err ? pcon.pc_err : SMT_RDF_SUCCESS ;
+ if (set && (res->rdf_reason == SMT_RDF_SUCCESS)) {
+ /*
+ * increment set count
+ * set time stamp
+ * store station id of last set
+ */
+ smc->mib.fddiSMTSetCount.count++ ;
+ smt_set_timestamp(smc,smc->mib.fddiSMTSetCount.timestamp) ;
+ smc->mib.fddiSMTLastSetStationId = req->smt_sid ;
+ smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ;
+ smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ;
+ }
+ return(mb) ;
+}
+
+extern void *sm_to_para() ;
+
+static int smt_authorize(smc,sm)
+struct s_smc *smc ;
+struct smt_header *sm ;
+{
+ struct smt_para *pa ;
+ int i ;
+ char *p ;
+
+ /*
+ * check source station id if not zero
+ */
+ p = (char *) &smc->mib.fddiPRPMFStation ;
+ for (i = 0 ; i < 8 && !p[i] ; i++)
+ ;
+ if (i != 8) {
+ if (memcmp((char *) &sm->smt_sid,
+ (char *) &smc->mib.fddiPRPMFStation,8))
+ return(1) ;
+ }
+ /*
+ * check authoriziation parameter if passwd not zero
+ */
+ p = (char *) smc->mib.fddiPRPMFPasswd ;
+ for (i = 0 ; i < 8 && !p[i] ; i++)
+ ;
+ if (i != 8) {
+ pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ;
+ if (!pa)
+ return(1) ;
+ if (pa->p_len != 8)
+ return(1) ;
+ if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8))
+ return(1) ;
+ }
+ return(0) ;
+}
+
+static int smt_check_set_count(smc,sm)
+struct s_smc *smc ;
+struct smt_header *sm ;
+{
+ struct smt_para *pa ;
+ struct smt_p_setcount *sc ;
+
+ pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P1035) ;
+ if (pa) {
+ sc = (struct smt_p_setcount *) pa ;
+ if ((smc->mib.fddiSMTSetCount.count != sc->count) ||
+ memcmp((char *) smc->mib.fddiSMTSetCount.timestamp,
+ (char *)sc->timestamp,8))
+ return(1) ;
+ }
+ return(0) ;
+}
+
+void smt_add_para(smc,pcon,para,index,local)
+struct s_smc *smc ;
+struct s_pcon *pcon ;
+u_short para ;
+int index ;
+int local ;
+{
+ struct smt_para *pa ;
+ const struct s_p_tab *pt ;
+ struct fddi_mib_m *mib_m = 0 ;
+ struct fddi_mib_p *mib_p = 0 ;
+ int len ;
+ int plen ;
+ char *from ;
+ char *to ;
+ const char *swap ;
+ char c ;
+ int range ;
+ char *mib_addr ;
+ int mac ;
+ int path ;
+ int port ;
+ int sp_len ;
+
+ /*
+ * skip if errror
+ */
+ if (pcon->pc_err)
+ return ;
+
+ /*
+ * actions don't have a value
+ */
+ pt = smt_get_ptab(para) ;
+ if (pt && pt->p_access == AC_S)
+ return ;
+
+ to = (char *) (pcon->pc_p) ; /* destination pointer */
+ len = pcon->pc_len ; /* free space */
+ plen = len ; /* remember start length */
+ pa = (struct smt_para *) to ; /* type/length pointer */
+ to += PARA_LEN ; /* skip smt_para */
+ len -= PARA_LEN ;
+ /*
+ * set index if required
+ */
+ if (((range = (para & 0xf000)) == 0x2000) ||
+ range == 0x3000 || range == 0x4000) {
+ if (len < 4)
+ goto wrong_error ;
+ to[0] = 0 ;
+ to[1] = 0 ;
+ to[2] = 0 ;
+ to[3] = index ;
+ len -= 4 ;
+ to += 4 ;
+ }
+ mac = index - INDEX_MAC ;
+ path = index - INDEX_PATH ;
+ port = index - INDEX_PORT ;
+ /*
+ * get pointer to mib
+ */
+ switch (range) {
+ case 0x1000 :
+ default :
+ mib_addr = (char *) (&smc->mib) ;
+ break ;
+ case 0x2000 :
+ if (mac < 0 || mac >= NUMMACS) {
+ pcon->pc_err = SMT_RDF_NOPARAM ;
+ return ;
+ }
+ mib_addr = (char *) (&smc->mib.m[mac]) ;
+ mib_m = (struct fddi_mib_m *) mib_addr ;
+ break ;
+ case 0x3000 :
+ if (path < 0 || path >= NUMPATHS) {
+ pcon->pc_err = SMT_RDF_NOPARAM ;
+ return ;
+ }
+ mib_addr = (char *) (&smc->mib.a[path]) ;
+ break ;
+ case 0x4000 :
+ if (port < 0 || port >= smt_mib_phys(smc)) {
+ pcon->pc_err = SMT_RDF_NOPARAM ;
+ return ;
+ }
+ mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ;
+ mib_p = (struct fddi_mib_p *) mib_addr ;
+ break ;
+ }
+ /*
+ * check special paras
+ */
+ swap = 0 ;
+ switch (para) {
+ case SMT_P10F0 :
+ case SMT_P10F1 :
+#ifdef ESS
+ case SMT_P10F2 :
+ case SMT_P10F3 :
+ case SMT_P10F4 :
+ case SMT_P10F5 :
+ case SMT_P10F6 :
+ case SMT_P10F7 :
+#endif
+#ifdef SBA
+ case SMT_P10F8 :
+ case SMT_P10F9 :
+#endif
+ case SMT_P20F1 :
+ if (!local) {
+ pcon->pc_err = SMT_RDF_NOPARAM ;
+ return ;
+ }
+ break ;
+ case SMT_P2034 :
+ case SMT_P2046 :
+ case SMT_P2047 :
+ case SMT_P204A :
+ case SMT_P2051 :
+ case SMT_P2052 :
+ mac_update_counter(smc) ;
+ break ;
+ case SMT_P4022:
+ mib_p->fddiPORTPC_LS = LS2MIB(
+ sm_pm_get_ls(smc,port_to_mib(smc,port))) ;
+ break ;
+ case SMT_P_REASON :
+ * (u_long *) to = 0 ;
+ sp_len = 4 ;
+ goto sp_done ;
+ case SMT_P1033 : /* time stamp */
+ smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ;
+ break ;
+
+ case SMT_P1020: /* port indexes */
+#if NUMPHYS == 12
+ swap = "IIIIIIIIIIII" ;
+#else
+#if NUMPHYS == 2
+ if (smc->s.sas == SMT_SAS)
+ swap = "I" ;
+ else
+ swap = "II" ;
+#else
+#if NUMPHYS == 24
+ swap = "IIIIIIIIIIIIIIIIIIIIIIII" ;
+#else
+ ????
+#endif
+#endif
+#endif
+ break ;
+ case SMT_P3212 :
+ {
+ sp_len = cem_build_path(smc,to,path) ;
+ goto sp_done ;
+ }
+ case SMT_P1048 : /* peer wrap condition */
+ {
+ struct smt_p_1048 *sp ;
+ sp = (struct smt_p_1048 *) to ;
+ sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ;
+ sp->p1048_cf_state = smc->mib.fddiSMTCF_State ;
+ sp_len = sizeof(struct smt_p_1048) ;
+ goto sp_done ;
+ }
+ case SMT_P208C :
+ {
+ struct smt_p_208c *sp ;
+ sp = (struct smt_p_208c *) to ;
+ sp->p208c_flag =
+ smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
+ sp->p208c_dupcondition =
+ (mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) |
+ (mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0);
+ sp->p208c_fddilong =
+ mib_m->fddiMACSMTAddress ;
+ sp->p208c_fddiunalong =
+ mib_m->fddiMACUpstreamNbr ;
+ sp->p208c_pad = 0 ;
+ sp_len = sizeof(struct smt_p_208c) ;
+ goto sp_done ;
+ }
+ case SMT_P208D : /* frame error condition */
+ {
+ struct smt_p_208d *sp ;
+ sp = (struct smt_p_208d *) to ;
+ sp->p208d_flag =
+ mib_m->fddiMACFrameErrorFlag ;
+ sp->p208d_frame_ct =
+ mib_m->fddiMACFrame_Ct ;
+ sp->p208d_error_ct =
+ mib_m->fddiMACError_Ct ;
+ sp->p208d_lost_ct =
+ mib_m->fddiMACLost_Ct ;
+ sp->p208d_ratio =
+ mib_m->fddiMACFrameErrorRatio ;
+ sp_len = sizeof(struct smt_p_208d) ;
+ goto sp_done ;
+ }
+ case SMT_P208E : /* not copied condition */
+ {
+ struct smt_p_208e *sp ;
+ sp = (struct smt_p_208e *) to ;
+ sp->p208e_flag =
+ mib_m->fddiMACNotCopiedFlag ;
+ sp->p208e_not_copied =
+ mib_m->fddiMACNotCopied_Ct ;
+ sp->p208e_copied =
+ mib_m->fddiMACCopied_Ct ;
+ sp->p208e_not_copied_ratio =
+ mib_m->fddiMACNotCopiedRatio ;
+ sp_len = sizeof(struct smt_p_208e) ;
+ goto sp_done ;
+ }
+ case SMT_P208F : /* neighbor change event */
+ {
+ struct smt_p_208f *sp ;
+ sp = (struct smt_p_208f *) to ;
+ sp->p208f_multiple =
+ mib_m->fddiMACMultiple_N ;
+ sp->p208f_nacondition =
+ mib_m->fddiMACDuplicateAddressCond ;
+ sp->p208f_old_una =
+ mib_m->fddiMACOldUpstreamNbr ;
+ sp->p208f_new_una =
+ mib_m->fddiMACUpstreamNbr ;
+ sp->p208f_old_dna =
+ mib_m->fddiMACOldDownstreamNbr ;
+ sp->p208f_new_dna =
+ mib_m->fddiMACDownstreamNbr ;
+ sp->p208f_curren_path =
+ mib_m->fddiMACCurrentPath ;
+ sp->p208f_smt_address =
+ mib_m->fddiMACSMTAddress ;
+ sp_len = sizeof(struct smt_p_208f) ;
+ goto sp_done ;
+ }
+ case SMT_P2090 :
+ {
+ struct smt_p_2090 *sp ;
+ sp = (struct smt_p_2090 *) to ;
+ sp->p2090_multiple =
+ mib_m->fddiMACMultiple_P ;
+ sp->p2090_availablepaths =
+ mib_m->fddiMACAvailablePaths ;
+ sp->p2090_currentpath =
+ mib_m->fddiMACCurrentPath ;
+ sp->p2090_requestedpaths =
+ mib_m->fddiMACRequestedPaths ;
+ sp_len = sizeof(struct smt_p_2090) ;
+ goto sp_done ;
+ }
+ case SMT_P4050 :
+ {
+ struct smt_p_4050 *sp ;
+ sp = (struct smt_p_4050 *) to ;
+ sp->p4050_flag =
+ mib_p->fddiPORTLerFlag ;
+ sp->p4050_pad = 0 ;
+ sp->p4050_cutoff =
+ mib_p->fddiPORTLer_Cutoff ; ;
+ sp->p4050_alarm =
+ mib_p->fddiPORTLer_Alarm ; ;
+ sp->p4050_estimate =
+ mib_p->fddiPORTLer_Estimate ;
+ sp->p4050_reject_ct =
+ mib_p->fddiPORTLem_Reject_Ct ;
+ sp->p4050_ct =
+ mib_p->fddiPORTLem_Ct ;
+ sp_len = sizeof(struct smt_p_4050) ;
+ goto sp_done ;
+ }
+
+ case SMT_P4051 :
+ {
+ struct smt_p_4051 *sp ;
+ sp = (struct smt_p_4051 *) to ;
+ sp->p4051_multiple =
+ mib_p->fddiPORTMultiple_U ;
+ sp->p4051_porttype =
+ mib_p->fddiPORTMy_Type ;
+ sp->p4051_connectstate =
+ mib_p->fddiPORTConnectState ; ;
+ sp->p4051_pc_neighbor =
+ mib_p->fddiPORTNeighborType ;
+ sp->p4051_pc_withhold =
+ mib_p->fddiPORTPC_Withhold ;
+ sp_len = sizeof(struct smt_p_4051) ;
+ goto sp_done ;
+ }
+ case SMT_P4052 :
+ {
+ struct smt_p_4052 *sp ;
+ sp = (struct smt_p_4052 *) to ;
+ sp->p4052_flag =
+ mib_p->fddiPORTEB_Condition ;
+ sp->p4052_eberrorcount =
+ mib_p->fddiPORTEBError_Ct ;
+ sp_len = sizeof(struct smt_p_4052) ;
+ goto sp_done ;
+ }
+ case SMT_P4053 :
+ {
+ struct smt_p_4053 *sp ;
+ sp = (struct smt_p_4053 *) to ;
+ sp->p4053_multiple =
+ mib_p->fddiPORTMultiple_P ; ;
+ sp->p4053_availablepaths =
+ mib_p->fddiPORTAvailablePaths ;
+ sp->p4053_currentpath =
+ mib_p->fddiPORTCurrentPath ;
+ memcpy( (char *) &sp->p4053_requestedpaths,
+ (char *) mib_p->fddiPORTRequestedPaths,4) ;
+ sp->p4053_mytype =
+ mib_p->fddiPORTMy_Type ;
+ sp->p4053_neighbortype =
+ mib_p->fddiPORTNeighborType ;
+ sp_len = sizeof(struct smt_p_4053) ;
+ goto sp_done ;
+ }
+ default :
+ break ;
+ }
+ /*
+ * in table ?
+ */
+ if (!pt) {
+ pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM :
+ SMT_RDF_ILLEGAL ;
+ return ;
+ }
+ /*
+ * check access rights
+ */
+ switch (pt->p_access) {
+ case AC_G :
+ case AC_GR :
+ break ;
+ default :
+ pcon->pc_err = SMT_RDF_ILLEGAL ;
+ return ;
+ }
+ from = mib_addr + pt->p_offset ;
+ if (!swap)
+ swap = pt->p_swap ; /* pointer to swap string */
+
+ /*
+ * copy values
+ */
+ while ((c = *swap++)) {
+ switch(c) {
+ case 'b' :
+ case 'w' :
+ case 'l' :
+ break ;
+ case 'S' :
+ case 'E' :
+ case 'R' :
+ case 'r' :
+ if (len < 4)
+ goto len_error ;
+ to[0] = 0 ;
+ to[1] = 0 ;
+#ifdef LITTLE_ENDIAN
+ if (c == 'r') {
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+ }
+ else {
+ to[3] = *from++ ;
+ to[2] = *from++ ;
+ }
+#else
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+#endif
+ to += 4 ;
+ len -= 4 ;
+ break ;
+ case 'I' : /* for SET of port indexes */
+ if (len < 2)
+ goto len_error ;
+#ifdef LITTLE_ENDIAN
+ to[1] = *from++ ;
+ to[0] = *from++ ;
+#else
+ to[0] = *from++ ;
+ to[1] = *from++ ;
+#endif
+ to += 2 ;
+ len -= 2 ;
+ break ;
+ case 'F' :
+ case 'B' :
+ if (len < 4)
+ goto len_error ;
+ len -= 4 ;
+ to[0] = 0 ;
+ to[1] = 0 ;
+ to[2] = 0 ;
+ to[3] = *from++ ;
+ to += 4 ;
+ break ;
+ case 'C' :
+ case 'T' :
+ case 'L' :
+ if (len < 4)
+ goto len_error ;
+#ifdef LITTLE_ENDIAN
+ to[3] = *from++ ;
+ to[2] = *from++ ;
+ to[1] = *from++ ;
+ to[0] = *from++ ;
+#else
+ to[0] = *from++ ;
+ to[1] = *from++ ;
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+#endif
+ len -= 4 ;
+ to += 4 ;
+ break ;
+ case '2' : /* PortMacIndicated */
+ if (len < 4)
+ goto len_error ;
+ to[0] = 0 ;
+ to[1] = 0 ;
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+ len -= 4 ;
+ to += 4 ;
+ break ;
+ case '4' :
+ if (len < 4)
+ goto len_error ;
+ to[0] = *from++ ;
+ to[1] = *from++ ;
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+ len -= 4 ;
+ to += 4 ;
+ break ;
+ case 'A' :
+ if (len < 8)
+ goto len_error ;
+ to[0] = 0 ;
+ to[1] = 0 ;
+ memcpy((char *) to+2,(char *) from,6) ;
+ to += 8 ;
+ from += 8 ;
+ len -= 8 ;
+ break ;
+ case '8' :
+ if (len < 8)
+ goto len_error ;
+ memcpy((char *) to,(char *) from,8) ;
+ to += 8 ;
+ from += 8 ;
+ len -= 8 ;
+ break ;
+ case 'D' :
+ if (len < 32)
+ goto len_error ;
+ memcpy((char *) to,(char *) from,32) ;
+ to += 32 ;
+ from += 32 ;
+ len -= 32 ;
+ break ;
+ case 'P' : /* timestamp is NOT swapped */
+ if (len < 8)
+ goto len_error ;
+ to[0] = *from++ ;
+ to[1] = *from++ ;
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+ to[4] = *from++ ;
+ to[5] = *from++ ;
+ to[6] = *from++ ;
+ to[7] = *from++ ;
+ to += 8 ;
+ len -= 8 ;
+ break ;
+ default :
+ SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ;
+ break ;
+ }
+ }
+
+done:
+ /*
+ * make it even (in case of 'I' encoding)
+ * note: len is DECREMENTED
+ */
+ if (len & 3) {
+ to[0] = 0 ;
+ to[1] = 0 ;
+ to += 4 - (len & 3 ) ;
+ len = len & ~ 3 ;
+ }
+
+ /* set type and length */
+ pa->p_type = para ;
+ pa->p_len = plen - len - PARA_LEN ;
+ /* return values */
+ pcon->pc_p = (void *) to ;
+ pcon->pc_len = len ;
+ return ;
+
+sp_done:
+ len -= sp_len ;
+ to += sp_len ;
+ goto done ;
+
+len_error:
+ /* parameter does not fit in frame */
+ pcon->pc_err = SMT_RDF_TOOLONG ;
+ return ;
+
+wrong_error:
+ pcon->pc_err = SMT_RDF_LENGTH ;
+}
+
+/*
+ * set parameter
+ */
+int smt_set_para(smc,pa,index,local,set)
+struct s_smc *smc ;
+struct smt_para *pa ;
+int index ;
+int local ;
+int set ;
+{
+#define IFSET(x) if (set) (x)
+
+ const struct s_p_tab *pt ;
+ int len ;
+ char *from ;
+ char *to ;
+ const char *swap ;
+ char c ;
+ char *mib_addr ;
+ struct fddi_mib *mib ;
+ struct fddi_mib_m *mib_m = 0 ;
+ struct fddi_mib_a *mib_a = 0 ;
+ struct fddi_mib_p *mib_p = 0 ;
+ int mac ;
+ int path ;
+ int port ;
+ SK_LOC_DECL(u_char,byte_val) ;
+ SK_LOC_DECL(u_short,word_val) ;
+ SK_LOC_DECL(u_long,long_val) ;
+
+ mac = index - INDEX_MAC ;
+ path = index - INDEX_PATH ;
+ port = index - INDEX_PORT ;
+ len = pa->p_len ;
+ from = (char *) (pa + 1 ) ;
+
+ mib = &smc->mib ;
+ switch (pa->p_type & 0xf000) {
+ case 0x1000 :
+ default :
+ mib_addr = (char *) mib ;
+ break ;
+ case 0x2000 :
+ if (mac < 0 || mac >= NUMMACS) {
+ return(SMT_RDF_NOPARAM) ;
+ }
+ mib_m = &smc->mib.m[mac] ;
+ mib_addr = (char *) mib_m ;
+ from += 4 ; /* skip index */
+ len -= 4 ;
+ break ;
+ case 0x3000 :
+ if (path < 0 || path >= NUMPATHS) {
+ return(SMT_RDF_NOPARAM) ;
+ }
+ mib_a = &smc->mib.a[path] ;
+ mib_addr = (char *) mib_a ;
+ from += 4 ; /* skip index */
+ len -= 4 ;
+ break ;
+ case 0x4000 :
+ if (port < 0 || port >= smt_mib_phys(smc)) {
+ return(SMT_RDF_NOPARAM) ;
+ }
+ mib_p = &smc->mib.p[port_to_mib(smc,port)] ;
+ mib_addr = (char *) mib_p ;
+ from += 4 ; /* skip index */
+ len -= 4 ;
+ break ;
+ }
+ switch (pa->p_type) {
+ case SMT_P10F0 :
+ case SMT_P10F1 :
+#ifdef ESS
+ case SMT_P10F2 :
+ case SMT_P10F3 :
+ case SMT_P10F4 :
+ case SMT_P10F5 :
+ case SMT_P10F6 :
+ case SMT_P10F7 :
+#endif
+#ifdef SBA
+ case SMT_P10F8 :
+ case SMT_P10F9 :
+#endif
+ case SMT_P20F1 :
+ if (!local) {
+ return(SMT_RDF_NOPARAM) ;
+ }
+ break ;
+ }
+ pt = smt_get_ptab(pa->p_type) ;
+ if (!pt) {
+ return( (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM :
+ SMT_RDF_ILLEGAL ) ;
+ }
+ switch (pt->p_access) {
+ case AC_GR :
+ case AC_S :
+ break ;
+ default :
+ return(SMT_RDF_ILLEGAL) ;
+ }
+ to = mib_addr + pt->p_offset ;
+ swap = pt->p_swap ; /* pointer to swap string */
+
+ while (swap && (c = *swap++)) {
+ switch(c) {
+ case 'b' :
+ to = (char *) &byte_val ;
+ break ;
+ case 'w' :
+ to = (char *) &word_val ;
+ break ;
+ case 'l' :
+ to = (char *) &long_val ;
+ break ;
+ case 'S' :
+ case 'E' :
+ case 'R' :
+ case 'r' :
+ if (len < 4) {
+ goto len_error ;
+ }
+ if (from[0] | from[1])
+ goto val_error ;
+#ifdef LITTLE_ENDIAN
+ if (c == 'r') {
+ to[0] = from[2] ;
+ to[1] = from[3] ;
+ }
+ else {
+ to[1] = from[2] ;
+ to[0] = from[3] ;
+ }
+#else
+ to[0] = from[2] ;
+ to[1] = from[3] ;
+#endif
+ from += 4 ;
+ to += 2 ;
+ len -= 4 ;
+ break ;
+ case 'F' :
+ case 'B' :
+ if (len < 4) {
+ goto len_error ;
+ }
+ if (from[0] | from[1] | from[2])
+ goto val_error ;
+ to[0] = from[3] ;
+ len -= 4 ;
+ from += 4 ;
+ to += 4 ;
+ break ;
+ case 'C' :
+ case 'T' :
+ case 'L' :
+ if (len < 4) {
+ goto len_error ;
+ }
+#ifdef LITTLE_ENDIAN
+ to[3] = *from++ ;
+ to[2] = *from++ ;
+ to[1] = *from++ ;
+ to[0] = *from++ ;
+#else
+ to[0] = *from++ ;
+ to[1] = *from++ ;
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+#endif
+ len -= 4 ;
+ to += 4 ;
+ break ;
+ case 'A' :
+ if (len < 8)
+ goto len_error ;
+ if (set)
+ memcpy((char *) to,(char *) from+2,6) ;
+ to += 8 ;
+ from += 8 ;
+ len -= 8 ;
+ break ;
+ case '4' :
+ if (len < 4)
+ goto len_error ;
+ if (set)
+ memcpy((char *) to,(char *) from,4) ;
+ to += 4 ;
+ from += 4 ;
+ len -= 4 ;
+ break ;
+ case '8' :
+ if (len < 8)
+ goto len_error ;
+ if (set)
+ memcpy((char *) to,(char *) from,8) ;
+ to += 8 ;
+ from += 8 ;
+ len -= 8 ;
+ break ;
+ case 'D' :
+ if (len < 32)
+ goto len_error ;
+ if (set)
+ memcpy((char *) to,(char *) from,32) ;
+ to += 32 ;
+ from += 32 ;
+ len -= 32 ;
+ break ;
+ case 'P' : /* timestamp is NOT swapped */
+ if (set) {
+ to[0] = *from++ ;
+ to[1] = *from++ ;
+ to[2] = *from++ ;
+ to[3] = *from++ ;
+ to[4] = *from++ ;
+ to[5] = *from++ ;
+ to[6] = *from++ ;
+ to[7] = *from++ ;
+ }
+ to += 8 ;
+ len -= 8 ;
+ break ;
+ default :
+ SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ;
+ return(SMT_RDF_ILLEGAL) ;
+ }
+ }
+ /*
+ * actions and internal updates
+ */
+ switch (pa->p_type) {
+ case SMT_P101A: /* fddiSMTConfigPolicy */
+ if (word_val & ~1)
+ goto val_error ;
+ IFSET(mib->fddiSMTConfigPolicy = word_val) ;
+ break ;
+ case SMT_P101B : /* fddiSMTConnectionPolicy */
+ if (!(word_val & POLICY_MM))
+ goto val_error ;
+ IFSET(mib->fddiSMTConnectionPolicy = word_val) ;
+ break ;
+ case SMT_P101D : /* fddiSMTTT_Notify */
+ if (word_val < 2 || word_val > 30)
+ goto val_error ;
+ IFSET(mib->fddiSMTTT_Notify = word_val) ;
+ break ;
+ case SMT_P101E : /* fddiSMTStatRptPolicy */
+ if (byte_val & ~1)
+ goto val_error ;
+ IFSET(mib->fddiSMTStatRptPolicy = byte_val) ;
+ break ;
+ case SMT_P101F : /* fddiSMTTrace_MaxExpiration */
+ /*
+ * note: lower limit trace_max = 6.001773... s
+ * NO upper limit
+ */
+ if (long_val < (long)0x478bf51L)
+ goto val_error ;
+ IFSET(mib->fddiSMTTrace_MaxExpiration = long_val) ;
+ break ;
+#ifdef ESS
+ case SMT_P10F2 : /* fddiESSPayload */
+ if (long_val > 1562)
+ goto val_error ;
+ if (set && smc->mib.fddiESSPayload != long_val) {
+ smc->ess.raf_act_timer_poll = TRUE ;
+ smc->mib.fddiESSPayload = long_val ;
+ }
+ break ;
+ case SMT_P10F3 : /* fddiESSOverhead */
+ if (long_val < 50 || long_val > 5000)
+ goto val_error ;
+ if (set && smc->mib.fddiESSPayload &&
+ smc->mib.fddiESSOverhead != long_val) {
+ smc->ess.raf_act_timer_poll = TRUE ;
+ smc->mib.fddiESSOverhead = long_val ;
+ }
+ break ;
+ case SMT_P10F4 : /* fddiESSMaxTNeg */
+ if (long_val > -MS2BCLK(5) || long_val < -MS2BCLK(165))
+ goto val_error ;
+ IFSET(mib->fddiESSMaxTNeg = long_val) ;
+ break ;
+ case SMT_P10F5 : /* fddiESSMinSegmentSize */
+ if (long_val < 1 || long_val > 4478)
+ goto val_error ;
+ IFSET(mib->fddiESSMinSegmentSize = long_val) ;
+ break ;
+ case SMT_P10F6 : /* fddiESSCategory */
+ if ((long_val & 0xffff) != 1)
+ goto val_error ;
+ IFSET(mib->fddiESSCategory = long_val) ;
+ break ;
+ case SMT_P10F7 : /* fddiESSSyncTxMode */
+ if (word_val > 1)
+ goto val_error ;
+ IFSET(mib->fddiESSSynchTxMode = word_val) ;
+ break ;
+#endif
+#ifdef SBA
+ case SMT_P10F8 : /* fddiSBACommand */
+ if (byte_val != SB_STOP && byte_val != SB_START)
+ goto val_error ;
+ IFSET(mib->fddiSBACommand = byte_val) ;
+ break ;
+ case SMT_P10F9 : /* fddiSBAAvailable */
+ if (byte_val > 100)
+ goto val_error ;
+ IFSET(mib->fddiSBAAvailable = byte_val) ;
+ break ;
+#endif
+ case SMT_P2020 : /* fddiMACRequestedPaths */
+ if ((word_val & (MIB_P_PATH_PRIM_PREFER |
+ MIB_P_PATH_PRIM_ALTER)) == 0 )
+ goto val_error ;
+ IFSET(mib_m->fddiMACRequestedPaths = word_val) ;
+ break ;
+ case SMT_P205F : /* fddiMACFrameErrorThreshold */
+ /* 0 .. ffff acceptable */
+ IFSET(mib_m->fddiMACFrameErrorThreshold = word_val) ;
+ break ;
+ case SMT_P2067 : /* fddiMACNotCopiedThreshold */
+ /* 0 .. ffff acceptable */
+ IFSET(mib_m->fddiMACNotCopiedThreshold = word_val) ;
+ break ;
+ case SMT_P2076: /* fddiMACMA_UnitdataEnable */
+ if (byte_val & ~1)
+ goto val_error ;
+ if (set) {
+ mib_m->fddiMACMA_UnitdataEnable = byte_val ;
+ queue_event(smc,EVENT_RMT,RM_ENABLE_FLAG) ;
+ }
+ break ;
+ case SMT_P20F1 : /* fddiMACT_Min */
+ IFSET(mib_m->fddiMACT_Min = long_val) ;
+ break ;
+ case SMT_P320F :
+ if (long_val > 1562)
+ goto val_error ;
+ IFSET(mib_a->fddiPATHSbaPayload = long_val) ;
+#ifdef ESS
+ if (set)
+ ess_para_change(smc) ;
+#endif
+ break ;
+ case SMT_P3210 :
+ if (long_val > 5000)
+ goto val_error ;
+
+ if (long_val != 0 && mib_a->fddiPATHSbaPayload == 0)
+ goto val_error ;
+
+ IFSET(mib_a->fddiPATHSbaOverhead = long_val) ;
+#ifdef ESS
+ if (set)
+ ess_para_change(smc) ;
+#endif
+ break ;
+ case SMT_P3213: /* fddiPATHT_Rmode */
+ /* no limit :
+ * 0 .. 343.597 => 0 .. 2e32 * 80nS
+ */
+ if (set) {
+ mib_a->fddiPATHT_Rmode = long_val ;
+ rtm_set_timer(smc) ;
+ }
+ break ;
+ case SMT_P3214 : /* fddiPATHSbaAvailable */
+ if (long_val > 0x00BEBC20L)
+ goto val_error ;
+#ifdef SBA
+ if (set && mib->fddiSBACommand == SB_STOP)
+ goto val_error ;
+#endif
+ IFSET(mib_a->fddiPATHSbaAvailable = long_val) ;
+ break ;
+ case SMT_P3215 : /* fddiPATHTVXLowerBound */
+ IFSET(mib_a->fddiPATHTVXLowerBound = long_val) ;
+ goto change_mac_para ;
+ case SMT_P3216 : /* fddiPATHT_MaxLowerBound */
+ IFSET(mib_a->fddiPATHT_MaxLowerBound = long_val) ;
+ goto change_mac_para ;
+ case SMT_P3217 : /* fddiPATHMaxT_Req */
+ IFSET(mib_a->fddiPATHMaxT_Req = long_val) ;
+
+change_mac_para:
+ if (set && smt_set_mac_opvalues(smc)) {
+ RS_SET(smc,RS_EVENT) ;
+ smc->sm.please_reconnect = 1 ;
+ queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+ }
+ break ;
+ case SMT_P400E : /* fddiPORTConnectionPolicies */
+ if (byte_val > 1)
+ goto val_error ;
+ IFSET(mib_p->fddiPORTConnectionPolicies = byte_val) ;
+ break ;
+ case SMT_P4011 : /* fddiPORTRequestedPaths */
+ /* all 3*8 bits allowed */
+ IFSET(memcpy((char *)mib_p->fddiPORTRequestedPaths,
+ (char *)&long_val,4)) ;
+ break ;
+ case SMT_P401F: /* fddiPORTMaint_LS */
+ if (word_val > 4)
+ goto val_error ;
+ IFSET(mib_p->fddiPORTMaint_LS = word_val) ;
+ break ;
+ case SMT_P403A : /* fddiPORTLer_Cutoff */
+ if (byte_val < 4 || byte_val > 15)
+ goto val_error ;
+ IFSET(mib_p->fddiPORTLer_Cutoff = byte_val) ;
+ break ;
+ case SMT_P403B : /* fddiPORTLer_Alarm */
+ if (byte_val < 4 || byte_val > 15)
+ goto val_error ;
+ IFSET(mib_p->fddiPORTLer_Alarm = byte_val) ;
+ break ;
+
+ /*
+ * Actions
+ */
+ case SMT_P103C : /* fddiSMTStationAction */
+ if (smt_action(smc,SMT_STATION_ACTION, (int) word_val, 0))
+ goto val_error ;
+ break ;
+ case SMT_P4046: /* fddiPORTAction */
+ if (smt_action(smc,SMT_PORT_ACTION, (int) word_val,
+ port_to_mib(smc,port)))
+ goto val_error ;
+ break ;
+ default :
+ break ;
+ }
+ return(0) ;
+
+val_error:
+ /* parameter value in frame is out of range */
+ return(SMT_RDF_RANGE) ;
+
+len_error:
+ /* parameter value in frame is too short */
+ return(SMT_RDF_LENGTH) ;
+
+#if 0
+no_author_error:
+ /* parameter not setable, because the SBA is not active
+ * Please note: we give the return code 'not authorizeed
+ * because SBA denied is not a valid return code in the
+ * PMF protocol.
+ */
+ return(SMT_RDF_AUTHOR) ;
+#endif
+}
+
+static const struct s_p_tab *smt_get_ptab(para)
+u_short para ;
+{
+ const struct s_p_tab *pt ;
+ for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++)
+ ;
+ return(pt->p_num ? pt : 0) ;
+}
+
+static int smt_mib_phys(smc)
+struct s_smc *smc ;
+{
+#ifdef CONCENTRATOR
+ SK_UNUSED(smc) ;
+
+ return(NUMPHYS) ;
+#else
+ if (smc->s.sas == SMT_SAS)
+ return(1) ;
+ return(NUMPHYS) ;
+#endif
+}
+
+int port_to_mib(smc,p)
+struct s_smc *smc ;
+int p ;
+{
+#ifdef CONCENTRATOR
+ SK_UNUSED(smc) ;
+
+ return(p) ;
+#else
+ if (smc->s.sas == SMT_SAS)
+ return(PS) ;
+ return(p) ;
+#endif
+}
+
+
+#ifdef DEBUG
+#ifndef BOOT
+void dump_smt(smc,sm,text)
+struct s_smc *smc ;
+struct smt_header *sm ;
+char *text ;
+{
+ int len ;
+ struct smt_para *pa ;
+ char *c ;
+ int n ;
+ int nn ;
+#ifdef LITTLE_ENDIAN
+ int smtlen ;
+#endif
+
+ SK_UNUSED(smc) ;
+
+#ifdef DEBUG_BRD
+ if (smc->debug.d_smtf < 2)
+#else
+ if (debug.d_smtf < 2)
+#endif
+ return ;
+#ifdef LITTLE_ENDIAN
+ smtlen = sm->smt_len + sizeof(struct smt_header) ;
+#endif
+ printf("SMT Frame [%s]:\nDA ",text) ;
+ dump_hex((char *) &sm->smt_dest,6) ;
+ printf("\tSA ") ;
+ dump_hex((char *) &sm->smt_source,6) ;
+ printf(" Class %x Type %x Version %x\n",
+ sm->smt_class,sm->smt_type,sm->smt_version) ;
+ printf("TID %lx\t\tSID ",sm->smt_tid) ;
+ dump_hex((char *) &sm->smt_sid,8) ;
+ printf(" LEN %x\n",sm->smt_len) ;
+
+ len = sm->smt_len ;
+ pa = (struct smt_para *) (sm + 1) ;
+ while (len > 0 ) {
+ int plen ;
+#ifdef UNIX
+ printf("TYPE %x LEN %x VALUE\t",pa->p_type,pa->p_len) ;
+#else
+ printf("TYPE %04x LEN %2x VALUE\t",pa->p_type,pa->p_len) ;
+#endif
+ n = pa->p_len ;
+ if ( (n < 0 ) || (n > (int)(len - PARA_LEN))) {
+ n = len - PARA_LEN ;
+ printf(" BAD LENGTH\n") ;
+ break ;
+ }
+#ifdef LITTLE_ENDIAN
+ smt_swap_para(sm,smtlen,0) ;
+#endif
+ if (n < 24) {
+ dump_hex((char *)(pa+1),(int) n) ;
+ printf("\n") ;
+ }
+ else {
+ int first = 0 ;
+ c = (char *)(pa+1) ;
+ dump_hex(c,16) ;
+ printf("\n") ;
+ n -= 16 ;
+ c += 16 ;
+ while (n > 0) {
+ nn = (n > 16) ? 16 : n ;
+ if (n > 64) {
+ if (first == 0)
+ printf("\t\t\t...\n") ;
+ first = 1 ;
+ }
+ else {
+ printf("\t\t\t") ;
+ dump_hex(c,nn) ;
+ printf("\n") ;
+ }
+ n -= nn ;
+ c += 16 ;
+ }
+ }
+#ifdef LITTLE_ENDIAN
+ smt_swap_para(sm,smtlen,1) ;
+#endif
+ plen = (pa->p_len + PARA_LEN + 3) & ~3 ;
+ len -= plen ;
+ pa = (struct smt_para *)((char *)pa + plen) ;
+ }
+ printf("-------------------------------------------------\n\n") ;
+}
+
+void dump_hex(p,len)
+char *p ;
+int len ;
+{
+ int n = 0 ;
+ while (len--) {
+ n++ ;
+#ifdef UNIX
+ printf("%x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ;
+#else
+ printf("%02x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ;
+#endif
+ }
+}
+#endif /* no BOOT */
+#endif /* DEBUG */
+
+
+#endif /* no SLIM_SMT */
diff --git a/drivers/net/skfp/queue.c b/drivers/net/skfp/queue.c
new file mode 100644
index 000000000..e54b544ff
--- /dev/null
+++ b/drivers/net/skfp/queue.c
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ SMT Event Queue Management
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)queue.c 2.9 97/08/04 (C) SK " ;
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ */
+void ev_init(smc)
+struct s_smc *smc ;
+{
+ smc->q.ev_put = smc->q.ev_get = smc->q.ev_queue ;
+}
+
+/*
+ * add event to queue
+ */
+void queue_event(smc,class,event)
+struct s_smc *smc ;
+int class ;
+int event ;
+{
+ PRINTF("queue class %d event %d\n",class,event) ;
+ smc->q.ev_put->class = class ;
+ smc->q.ev_put->event = event ;
+ if (++smc->q.ev_put == &smc->q.ev_queue[MAX_EVENT])
+ smc->q.ev_put = smc->q.ev_queue ;
+
+ if (smc->q.ev_put == smc->q.ev_get) {
+ SMT_ERR_LOG(smc,SMT_E0137, SMT_E0137_MSG) ;
+ }
+}
+
+/*
+ * timer_event is called from HW timer package.
+ */
+void timer_event(smc,token)
+struct s_smc *smc ;
+u_long token ;
+{
+ PRINTF("timer event class %d token %d\n",
+ EV_T_CLASS(token),
+ EV_T_EVENT(token)) ;
+ queue_event(smc,EV_T_CLASS(token),EV_T_EVENT(token));
+}
+
+/*
+ * event dispatcher
+ * while event queue is not empty
+ * get event from queue
+ * send command to state machine
+ * end
+ */
+void ev_dispatcher(smc)
+struct s_smc *smc ;
+{
+ struct event_queue *ev ; /* pointer into queue */
+ int class ;
+
+ ev = smc->q.ev_get ;
+ PRINTF("dispatch get %x put %x\n",ev,smc->q.ev_put) ;
+ while (ev != smc->q.ev_put) {
+ PRINTF("dispatch class %d event %d\n",ev->class,ev->event) ;
+ switch(class = ev->class) {
+ case EVENT_ECM : /* Entity Corordination Man. */
+ ecm(smc,(int)ev->event) ;
+ break ;
+ case EVENT_CFM : /* Configuration Man. */
+ cfm(smc,(int)ev->event) ;
+ break ;
+ case EVENT_RMT : /* Ring Man. */
+ rmt(smc,(int)ev->event) ;
+ break ;
+ case EVENT_SMT :
+ smt_event(smc,(int)ev->event) ;
+ break ;
+#ifdef CONCENTRATOR
+ case 99 :
+ timer_test_event(smc,(int)ev->event) ;
+ break ;
+#endif
+ case EVENT_PCMA : /* PHY A */
+ case EVENT_PCMB : /* PHY B */
+ default :
+ if (class >= EVENT_PCMA &&
+ class < EVENT_PCMA + NUMPHYS) {
+ pcm(smc,class - EVENT_PCMA,(int)ev->event) ;
+ break ;
+ }
+ SMT_PANIC(smc,SMT_E0121, SMT_E0121_MSG) ;
+ return ;
+ }
+
+ if (++ev == &smc->q.ev_queue[MAX_EVENT])
+ ev = smc->q.ev_queue ;
+
+ /* Renew get: it is used in queue_events to detect overruns */
+ smc->q.ev_get = ev;
+ }
+}
+
+/*
+ * smt_online connects to or disconnects from the ring
+ * MUST be called to initiate connection establishment
+ *
+ * on 0 disconnect
+ * on 1 connect
+ */
+u_short smt_online(smc,on)
+struct s_smc *smc ;
+int on ;
+{
+ queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ;
+ ev_dispatcher(smc) ;
+ return(smc->mib.fddiSMTCF_State) ;
+}
+
+/*
+ * set SMT flag to value
+ * flag flag name
+ * value flag value
+ * dump current flag setting
+ */
+#ifdef CONCENTRATOR
+void do_smt_flag(smc,flag,value)
+struct s_smc *smc ;
+char *flag ;
+int value ;
+{
+#ifdef DEBUG
+ struct smt_debug *deb;
+
+ SK_UNUSED(smc) ;
+
+#ifdef DEBUG_BRD
+ deb = &smc->debug;
+#else
+ deb = &debug;
+#endif
+ if (!strcmp(flag,"smt"))
+ deb->d_smt = value ;
+ else if (!strcmp(flag,"smtf"))
+ deb->d_smtf = value ;
+ else if (!strcmp(flag,"pcm"))
+ deb->d_pcm = value ;
+ else if (!strcmp(flag,"rmt"))
+ deb->d_rmt = value ;
+ else if (!strcmp(flag,"cfm"))
+ deb->d_cfm = value ;
+ else if (!strcmp(flag,"ecm"))
+ deb->d_ecm = value ;
+ printf("smt %d\n",deb->d_smt) ;
+ printf("smtf %d\n",deb->d_smtf) ;
+ printf("pcm %d\n",deb->d_pcm) ;
+ printf("rmt %d\n",deb->d_rmt) ;
+ printf("cfm %d\n",deb->d_cfm) ;
+ printf("ecm %d\n",deb->d_ecm) ;
+#endif /* DEBUG */
+}
+#endif
diff --git a/drivers/net/skfp/rmt.c b/drivers/net/skfp/rmt.c
new file mode 100644
index 000000000..473eb0c9c
--- /dev/null
+++ b/drivers/net/skfp/rmt.c
@@ -0,0 +1,674 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ SMT RMT
+ Ring Management
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * queue_event()
+ * smt_timer_start()
+ * smt_timer_stop()
+ *
+ * The following external HW dependant functions are referenced :
+ * sm_ma_control()
+ * sm_mac_check_beacon_claim()
+ *
+ * The following HW dependant events are required :
+ * RM_RING_OP
+ * RM_RING_NON_OP
+ * RM_MY_BEACON
+ * RM_OTHER_BEACON
+ * RM_MY_CLAIM
+ * RM_TRT_EXP
+ * RM_VALID_CLAIM
+ *
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)rmt.c 2.13 99/07/02 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG 0x10
+#define GO_STATE(x) (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
+#define ACTIONS_DONE() (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
+#define ACTIONS(x) (x|AFLAG)
+
+#define RM0_ISOLATED 0
+#define RM1_NON_OP 1 /* not operational */
+#define RM2_RING_OP 2 /* ring operational */
+#define RM3_DETECT 3 /* detect dupl addresses */
+#define RM4_NON_OP_DUP 4 /* dupl. addr detected */
+#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */
+#define RM6_DIRECTED 6 /* sending directed beacons */
+#define RM7_TRACE 7 /* trace initiated */
+
+#ifdef DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const rmt_states[] = {
+ "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
+ "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
+ "RM7_TRACE"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const rmt_events[] = {
+ "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
+ "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
+ "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
+ "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
+ "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
+ "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
+} ;
+#endif
+
+/*
+ * Globals
+ * in struct s_rmt
+ */
+
+
+/*
+ * function declarations
+ */
+static void rmt_fsm() ;
+static void start_rmt_timer0() ;
+static void start_rmt_timer1() ;
+static void start_rmt_timer2() ;
+static void stop_rmt_timer0() ;
+static void stop_rmt_timer1() ;
+static void stop_rmt_timer2() ;
+static void rmt_dup_actions() ;
+static void rmt_reinsert_actions() ;
+static void rmt_leave_actions() ;
+static void rmt_new_dup_actions() ;
+
+#ifndef SUPERNET_3
+extern void restart_trt_for_dbcn() ;
+#endif /*SUPERNET_3*/
+
+/*
+ init RMT state machine
+ clear all RMT vars and flags
+*/
+void rmt_init(smc)
+struct s_smc *smc ;
+{
+ smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
+ smc->r.dup_addr_test = DA_NONE ;
+ smc->r.da_flag = 0 ;
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+ smc->r.sm_ma_avail = FALSE ;
+ smc->r.loop_avail = 0 ;
+ smc->r.bn_flag = 0 ;
+ smc->r.jm_flag = 0 ;
+ smc->r.no_flag = TRUE ;
+}
+
+/*
+ RMT state machine
+ called by dispatcher
+
+ do
+ display state change
+ process event
+ until SM is stable
+*/
+void rmt(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+ int state ;
+
+ do {
+ DB_RMT("RMT : state %s%s",
+ (smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "",
+ rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ;
+ DB_RMT(" event %s\n",rmt_events[event],0) ;
+ state = smc->mib.m[MAC0].fddiMACRMTState ;
+ rmt_fsm(smc,event) ;
+ event = 0 ;
+ } while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
+ rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
+}
+
+/*
+ process RMT event
+*/
+static void rmt_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+ /*
+ * RM00-RM70 : from all states
+ */
+ if (!smc->r.rm_join && !smc->r.rm_loop &&
+ smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
+ smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
+ RS_SET(smc,RS_NORINGOP) ;
+ rmt_indication(smc,0) ;
+ GO_STATE(RM0_ISOLATED) ;
+ return ;
+ }
+
+ switch(smc->mib.m[MAC0].fddiMACRMTState) {
+ case ACTIONS(RM0_ISOLATED) :
+ stop_rmt_timer0(smc) ;
+ stop_rmt_timer1(smc) ;
+ stop_rmt_timer2(smc) ;
+
+ /*
+ * Disable MAC.
+ */
+ sm_ma_control(smc,MA_OFFLINE) ;
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+ smc->r.loop_avail = FALSE ;
+ smc->r.sm_ma_avail = FALSE ;
+ smc->r.no_flag = TRUE ;
+ DB_RMTN(1,"RMT : ISOLATED\n",0,0) ;
+ ACTIONS_DONE() ;
+ break ;
+ case RM0_ISOLATED :
+ /*RM01*/
+ if (smc->r.rm_join || smc->r.rm_loop) {
+ /*
+ * According to the standard the MAC must be reset
+ * here. The FORMAC will be initialized and Claim
+ * and Beacon Frames will be uploaded to the MAC.
+ * So any change of Treq will take effect NOW.
+ */
+ sm_ma_control(smc,MA_RESET) ;
+ GO_STATE(RM1_NON_OP) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(RM1_NON_OP) :
+ start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
+ stop_rmt_timer1(smc) ;
+ stop_rmt_timer2(smc) ;
+ sm_ma_control(smc,MA_BEACON) ;
+ DB_RMTN(1,"RMT : RING DOWN\n",0,0) ;
+ RS_SET(smc,RS_NORINGOP) ;
+ smc->r.sm_ma_avail = FALSE ;
+ rmt_indication(smc,0) ;
+ ACTIONS_DONE() ;
+ break ;
+ case RM1_NON_OP :
+ /*RM12*/
+ if (cmd == RM_RING_OP) {
+ RS_SET(smc,RS_RINGOPCHANGE) ;
+ GO_STATE(RM2_RING_OP) ;
+ break ;
+ }
+ /*RM13*/
+ else if (cmd == RM_TIMEOUT_NON_OP) {
+ smc->r.bn_flag = FALSE ;
+ smc->r.no_flag = TRUE ;
+ GO_STATE(RM3_DETECT) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(RM2_RING_OP) :
+ stop_rmt_timer0(smc) ;
+ stop_rmt_timer1(smc) ;
+ stop_rmt_timer2(smc) ;
+ smc->r.no_flag = FALSE ;
+ if (smc->r.rm_loop)
+ smc->r.loop_avail = TRUE ;
+ if (smc->r.rm_join) {
+ smc->r.sm_ma_avail = TRUE ;
+ if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
+ else
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+ }
+ DB_RMTN(1,"RMT : RING UP\n",0,0) ;
+ RS_CLEAR(smc,RS_NORINGOP) ;
+ RS_SET(smc,RS_RINGOPCHANGE) ;
+ rmt_indication(smc,1) ;
+ smt_stat_counter(smc,0) ;
+ ACTIONS_DONE() ;
+ break ;
+ case RM2_RING_OP :
+ /*RM21*/
+ if (cmd == RM_RING_NON_OP) {
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+ smc->r.loop_avail = FALSE ;
+ RS_SET(smc,RS_RINGOPCHANGE) ;
+ GO_STATE(RM1_NON_OP) ;
+ break ;
+ }
+ /*RM22a*/
+ else if (cmd == RM_ENABLE_FLAG) {
+ if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
+ else
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+ }
+ /*RM25*/
+ else if (smc->r.dup_addr_test == DA_FAILED) {
+ smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+ smc->r.loop_avail = FALSE ;
+ smc->r.da_flag = TRUE ;
+ GO_STATE(RM5_RING_OP_DUP) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(RM3_DETECT) :
+ start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
+ start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
+ start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+ sm_mac_check_beacon_claim(smc) ;
+ DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ;
+ ACTIONS_DONE() ;
+ break ;
+ case RM3_DETECT :
+ if (cmd == RM_TIMEOUT_POLL) {
+ start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+ sm_mac_check_beacon_claim(smc) ;
+ break ;
+ }
+ if (cmd == RM_TIMEOUT_D_MAX) {
+ smc->r.timer0_exp = TRUE ;
+ }
+ /*
+ *jd(22-Feb-1999)
+ * We need a time ">= 2*mac_d_max" since we had finished
+ * Claim or Beacon state. So we will restart timer0 at
+ * every state change.
+ */
+ if (cmd == RM_TX_STATE_CHANGE) {
+ start_rmt_timer0(smc,
+ smc->s.mac_d_max*2,
+ RM_TIMEOUT_D_MAX) ;
+ }
+ /*RM32*/
+ if (cmd == RM_RING_OP) {
+ GO_STATE(RM2_RING_OP) ;
+ break ;
+ }
+ /*RM33a*/
+ else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
+ && smc->r.bn_flag) {
+ smc->r.bn_flag = FALSE ;
+ }
+ /*RM33b*/
+ else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
+ int tx ;
+ /*
+ * set bn_flag only if in state T4 or T5:
+ * only if we're the beaconer should we start the
+ * trace !
+ */
+ if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
+ DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0);
+ smc->r.bn_flag = TRUE ;
+ /*
+ * If one of the upstream stations beaconed
+ * and the link to the upstream neighbor is
+ * lost we need to restart the stuck timer to
+ * check the "stuck beacon" condition.
+ */
+ start_rmt_timer1(smc,smc->s.rmt_t_stuck,
+ RM_TIMEOUT_T_STUCK) ;
+ }
+ /*
+ * We do NOT need to clear smc->r.bn_flag in case of
+ * not being in state T4 or T5, because the flag
+ * must be cleared in order to get in this condition.
+ */
+
+ DB_RMTN(2,
+ "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
+ tx,smc->r.bn_flag) ;
+ }
+ /*RM34a*/
+ else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
+ rmt_new_dup_actions(smc) ;
+ GO_STATE(RM4_NON_OP_DUP) ;
+ break ;
+ }
+ /*RM34b*/
+ else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
+ rmt_new_dup_actions(smc) ;
+ GO_STATE(RM4_NON_OP_DUP) ;
+ break ;
+ }
+ /*RM34c*/
+ else if (cmd == RM_VALID_CLAIM) {
+ rmt_new_dup_actions(smc) ;
+ GO_STATE(RM4_NON_OP_DUP) ;
+ break ;
+ }
+ /*RM36*/
+ else if (cmd == RM_TIMEOUT_T_STUCK &&
+ smc->r.rm_join && smc->r.bn_flag) {
+ GO_STATE(RM6_DIRECTED) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(RM4_NON_OP_DUP) :
+ start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
+ start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
+ start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+ sm_mac_check_beacon_claim(smc) ;
+ DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ;
+ ACTIONS_DONE() ;
+ break ;
+ case RM4_NON_OP_DUP :
+ if (cmd == RM_TIMEOUT_POLL) {
+ start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+ sm_mac_check_beacon_claim(smc) ;
+ break ;
+ }
+ /*RM41*/
+ if (!smc->r.da_flag) {
+ GO_STATE(RM1_NON_OP) ;
+ break ;
+ }
+ /*RM44a*/
+ else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+ smc->r.bn_flag) {
+ smc->r.bn_flag = FALSE ;
+ }
+ /*RM44b*/
+ else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
+ int tx ;
+ /*
+ * set bn_flag only if in state T4 or T5:
+ * only if we're the beaconer should we start the
+ * trace !
+ */
+ if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
+ DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0);
+ smc->r.bn_flag = TRUE ;
+ /*
+ * If one of the upstream stations beaconed
+ * and the link to the upstream neighbor is
+ * lost we need to restart the stuck timer to
+ * check the "stuck beacon" condition.
+ */
+ start_rmt_timer1(smc,smc->s.rmt_t_stuck,
+ RM_TIMEOUT_T_STUCK) ;
+ }
+ /*
+ * We do NOT need to clear smc->r.bn_flag in case of
+ * not being in state T4 or T5, because the flag
+ * must be cleared in order to get in this condition.
+ */
+
+ DB_RMTN(2,
+ "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
+ tx,smc->r.bn_flag) ;
+ }
+ /*RM44c*/
+ else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
+ rmt_dup_actions(smc) ;
+ }
+ /*RM45*/
+ else if (cmd == RM_RING_OP) {
+ smc->r.no_flag = FALSE ;
+ GO_STATE(RM5_RING_OP_DUP) ;
+ break ;
+ }
+ /*RM46*/
+ else if (cmd == RM_TIMEOUT_T_STUCK &&
+ smc->r.rm_join && smc->r.bn_flag) {
+ GO_STATE(RM6_DIRECTED) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(RM5_RING_OP_DUP) :
+ stop_rmt_timer0(smc) ;
+ stop_rmt_timer1(smc) ;
+ stop_rmt_timer2(smc) ;
+ DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ;
+ ACTIONS_DONE() ;
+ break;
+ case RM5_RING_OP_DUP :
+ /*RM52*/
+ if (smc->r.dup_addr_test == DA_PASSED) {
+ smc->r.da_flag = FALSE ;
+ GO_STATE(RM2_RING_OP) ;
+ break ;
+ }
+ /*RM54*/
+ else if (cmd == RM_RING_NON_OP) {
+ smc->r.jm_flag = FALSE ;
+ smc->r.bn_flag = FALSE ;
+ GO_STATE(RM4_NON_OP_DUP) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(RM6_DIRECTED) :
+ start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
+ stop_rmt_timer1(smc) ;
+ start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+ sm_ma_control(smc,MA_DIRECTED) ;
+ RS_SET(smc,RS_BEACON) ;
+ DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ;
+ ACTIONS_DONE() ;
+ break ;
+ case RM6_DIRECTED :
+ /*RM63*/
+ if (cmd == RM_TIMEOUT_POLL) {
+ start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+ sm_mac_check_beacon_claim(smc) ;
+#ifndef SUPERNET_3
+ /* Because of problems with the Supernet II chip set
+ * sending of Directed Beacon will stop after 165ms
+ * therefore restart_trt_for_dbcn(smc) will be called
+ * to prevent this.
+ */
+ restart_trt_for_dbcn(smc) ;
+#endif /*SUPERNET_3*/
+ break ;
+ }
+ if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+ !smc->r.da_flag) {
+ smc->r.bn_flag = FALSE ;
+ GO_STATE(RM3_DETECT) ;
+ break ;
+ }
+ /*RM64*/
+ else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+ smc->r.da_flag) {
+ smc->r.bn_flag = FALSE ;
+ GO_STATE(RM4_NON_OP_DUP) ;
+ break ;
+ }
+ /*RM67*/
+ else if (cmd == RM_TIMEOUT_T_DIRECT) {
+ GO_STATE(RM7_TRACE) ;
+ break ;
+ }
+ break ;
+ case ACTIONS(RM7_TRACE) :
+ stop_rmt_timer0(smc) ;
+ stop_rmt_timer1(smc) ;
+ stop_rmt_timer2(smc) ;
+ smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
+ queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
+ DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ;
+ ACTIONS_DONE() ;
+ break ;
+ case RM7_TRACE :
+ break ;
+ default:
+ SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
+ break;
+ }
+}
+
+/*
+ * (jd) RMT duplicate address actions
+ * leave the ring or reinsert just as configured
+ */
+static void rmt_dup_actions(smc)
+struct s_smc *smc ;
+{
+ if (smc->r.jm_flag) {
+ }
+ else {
+ if (smc->s.rmt_dup_mac_behavior) {
+ SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
+ rmt_reinsert_actions(smc) ;
+ }
+ else {
+ SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
+ rmt_leave_actions(smc) ;
+ }
+ }
+}
+
+/*
+ * Reconnect to the Ring
+ */
+static void rmt_reinsert_actions(smc)
+struct s_smc *smc ;
+{
+ queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+ queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+}
+
+/*
+ * duplicate address detected
+ */
+static void rmt_new_dup_actions(smc)
+struct s_smc *smc ;
+{
+ smc->r.da_flag = TRUE ;
+ smc->r.bn_flag = FALSE ;
+ smc->r.jm_flag = FALSE ;
+ /*
+ * we have three options : change address, jam or leave
+ * we leave the ring as default
+ * Optionally it's possible to reinsert after leaving the Ring
+ * but this will not conform with SMT Spec.
+ */
+ if (smc->s.rmt_dup_mac_behavior) {
+ SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
+ rmt_reinsert_actions(smc) ;
+ }
+ else {
+ SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
+ rmt_leave_actions(smc) ;
+ }
+}
+
+
+/*
+ * leave the ring
+ */
+static void rmt_leave_actions(smc)
+struct s_smc *smc ;
+{
+ queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+ /*
+ * Note: Do NOT try again later. (with please reconnect)
+ * The station must be left from the ring!
+ */
+}
+
+/*
+ * SMT timer interface
+ * start RMT timer 0
+ */
+static void start_rmt_timer0(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+ smc->r.timer0_exp = FALSE ; /* clear timer event flag */
+ smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ * start RMT timer 1
+ */
+static void start_rmt_timer1(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+ smc->r.timer1_exp = FALSE ; /* clear timer event flag */
+ smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ * start RMT timer 2
+ */
+static void start_rmt_timer2(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+ smc->r.timer2_exp = FALSE ; /* clear timer event flag */
+ smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ * stop RMT timer 0
+ */
+static void stop_rmt_timer0(smc)
+struct s_smc *smc ;
+{
+ if (smc->r.rmt_timer0.tm_active)
+ smt_timer_stop(smc,&smc->r.rmt_timer0) ;
+}
+
+/*
+ * SMT timer interface
+ * stop RMT timer 1
+ */
+static void stop_rmt_timer1(smc)
+struct s_smc *smc ;
+{
+ if (smc->r.rmt_timer1.tm_active)
+ smt_timer_stop(smc,&smc->r.rmt_timer1) ;
+}
+
+/*
+ * SMT timer interface
+ * stop RMT timer 2
+ */
+static void stop_rmt_timer2(smc)
+struct s_smc *smc ;
+{
+ if (smc->r.rmt_timer2.tm_active)
+ smt_timer_stop(smc,&smc->r.rmt_timer2) ;
+}
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
new file mode 100644
index 000000000..6aceec4d5
--- /dev/null
+++ b/drivers/net/skfp/skfddi.c
@@ -0,0 +1,2495 @@
+/*
+ * File Name:
+ * skfddi.c
+ *
+ * Copyright Information:
+ * Copyright SysKonnect 1998,1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ * Abstract:
+ * A Linux device driver supporting the SysKonnect FDDI PCI controller
+ * familie.
+ *
+ * Maintainers:
+ * CG Christoph Goos (cgoos@syskonnect.de)
+ *
+ * Address all question to:
+ * linux@syskonnect.de
+ *
+ * The technical manual for the adapters is available from SysKonnect's
+ * web pages: www.syskonnect.com
+ * Goto "Support" and search Knowledge Base for "manual".
+ *
+ * Driver Architecture:
+ * The driver architecture is based on the DEC FDDI driver by
+ * Lawrence V. Stefani and several ethernet drivers.
+ * I also used an existing Windows NT miniport driver.
+ * All hardware dependant fuctions are handled by the SysKonnect
+ * Hardware Module.
+ * The only headerfiles that are directly related to this source
+ * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h.
+ * The others belong to the SysKonnect FDDI Hardware Module and
+ * should better not be changed.
+ * NOTE:
+ * Compiling this driver produces some warnings, but I did not fix
+ * this, because the Hardware Module source is used for different
+ * drivers, and fixing it for Linux might bring problems on other
+ * projects. To keep the source common for all those drivers (and
+ * thus simplify fixes to it), please do not clean it up!
+ *
+ * Modification History:
+ * Date Name Description
+ * 02-Mar-98 CG Created.
+ *
+ * 10-Mar-99 CG Support for 2.2.x added.
+ * 25-Mar-99 CG Corrected IRQ routing for SMP (APIC)
+ * 26-Oct-99 CG Fixed compilation error on 2.2.13
+ * 12-Nov-99 CG Source code release
+ * 22-Nov-99 CG Included in kernel source.
+ *
+ * Compilation options (-Dxxx):
+ * DRIVERDEBUG print lots of messages to log file
+ * DUMPPACKETS print received/transmitted packets to logfile
+ *
+ * Limitations:
+ * I changed the driver to support memory mapped I/O, so it
+ * might run on non-x86 architectures (not tested).
+ * But the hardware module does not yet support 64 bit OS'es.
+ */
+
+/* Version information string - should be updated prior to */
+/* each new release!!! */
+#define VERSION "2.05"
+
+static const char *boot_msg =
+ "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n"
+ " SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)";
+
+/* Include files */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h> // isdigit
+
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+
+#include "h/types.h"
+#undef ADDR // undo Linux definition
+#include "h/skfbi.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smtstate.h"
+
+
+// Define global routines
+int skfp_probe(struct net_device *dev);
+
+
+// Define module-wide (static) routines
+static struct net_device *alloc_device(struct net_device *dev, u_long iobase);
+static struct net_device *insert_device(struct net_device *dev,
+ int (*init) (struct net_device *));
+static int fddi_dev_index(unsigned char *s);
+static void init_dev(struct net_device *dev, u_long iobase);
+static void link_modules(struct net_device *dev, struct net_device *tmp);
+static int skfp_driver_init(struct net_device *dev);
+static int skfp_open(struct net_device *dev);
+static int skfp_close(struct net_device *dev);
+static void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct enet_statistics *skfp_ctl_get_stats(struct net_device *dev);
+static void skfp_ctl_set_multicast_list(struct net_device *dev);
+static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev);
+static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr);
+static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev);
+static void send_queued_packets(struct s_smc *smc);
+static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr);
+static void ResetAdapter(struct s_smc *smc);
+
+
+// Functions needed by the hardware module
+void *mac_drv_get_space(struct s_smc *smc, u_int size);
+void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size);
+unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt);
+unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag);
+void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr,
+ int flag);
+void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd);
+void llc_restart_tx(struct s_smc *smc);
+void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+ int frag_count, int len);
+void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+ int frag_count);
+void mac_drv_fill_rxd(struct s_smc *smc);
+void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+ int frag_count);
+int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
+ int la_len);
+void smt_timer_poll(struct s_smc *smc);
+void ring_status_indication(struct s_smc *smc, u_long status);
+unsigned long smt_get_time(void);
+void smt_stat_counter(struct s_smc *smc, int stat);
+void cfm_state_change(struct s_smc *smc, int c_state);
+void ecm_state_change(struct s_smc *smc, int e_state);
+void pcm_state_change(struct s_smc *smc, int plc, int p_state);
+void rmt_state_change(struct s_smc *smc, int r_state);
+void drv_reset_indication(struct s_smc *smc);
+void dump_data(unsigned char *Data, int length);
+
+
+// External functions from the hardware module
+extern u_int mac_drv_check_space();
+extern void read_address(struct s_smc *smc, u_char * mac_addr);
+extern void card_stop(struct s_smc *smc);
+extern int mac_drv_init(struct s_smc *smc);
+extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys,
+ int len, int frame_status);
+extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count,
+ int frame_len, int frame_status);
+extern int init_smt(struct s_smc *smc, u_char * mac_addr);
+extern void fddi_isr(struct s_smc *smc);
+extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
+ int len, int frame_status);
+extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
+extern void mac_drv_clear_tx_queue(struct s_smc *smc);
+extern void mac_drv_clear_rx_queue(struct s_smc *smc);
+extern void mac_clear_multicast(struct s_smc *smc);
+extern void enable_tx_irq(struct s_smc *smc, u_short queue);
+extern void mac_drv_clear_txd(struct s_smc *smc);
+
+
+// Define module-wide (static) variables
+
+static int num_boards = 0; /* total number of adapters configured */
+static int num_fddi = 0;
+static int autoprobed = 0;
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static struct net_device *unlink_modules(struct net_device *p);
+static int loading_module = 1;
+#else
+static int loading_module = 0;
+#endif // MODULE
+
+#ifdef DRIVERDEBUG
+#define PRINTK(s, args...) printk(s, ## args)
+#else
+#define PRINTK(s, args...)
+#endif // DRIVERDEBUG
+
+#define PRIV(dev) (&(((struct s_smc *)dev->priv)->os))
+
+/*
+ * ==============
+ * = skfp_probe =
+ * ==============
+ *
+ * Overview:
+ * Probes for supported FDDI PCI controllers
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * This routine is called by the OS for each FDDI device name (fddi0,
+ * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c.
+ * If loaded as a module, it will detect and initialize all
+ * adapters the first time it is called.
+ *
+ * Let's say that skfp_probe() is getting called to initialize fddi0.
+ * Furthermore, let's say there are three supported controllers in the
+ * system. Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2
+ * will be initialized and a global flag will be set to indicate that
+ * skfp_probe() has already been called.
+ *
+ * However...the OS doesn't know that we've already initialized
+ * devices fddi1 and fddi2 so skfp_probe() gets called again and again
+ * until it reaches the end of the device list for FDDI (presently,
+ * fddi7). It's important that the driver "pretend" to probe for
+ * devices fddi1 and fddi2 and return success. Devices fddi3
+ * through fddi7 will return failure since they weren't initialized.
+ *
+ * This algorithm seems to work for the time being. As other FDDI
+ * drivers are written for Linux, a more generic approach (perhaps
+ * similar to the Ethernet card approach) may need to be implemented.
+ *
+ * Return Codes:
+ * 0 - This device (fddi0, fddi1, etc) configured successfully
+ * -ENODEV - No devices present, or no SysKonnect FDDI PCI device
+ * present for this device name
+ *
+ *
+ * Side Effects:
+ * Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ * initialized and the board resources are read and stored in
+ * the device structure.
+ */
+int skfp_probe(struct net_device *dev)
+{
+ int i; /* used in for loops */
+ struct pci_dev *pdev = NULL; /* PCI device structure */
+#ifndef MEM_MAPPED_IO
+ u16 port; /* temporary I/O (port) address */
+ int port_len; /* length of port address range (in bytes) */
+#else
+ unsigned long port;
+#endif
+ u16 command; /* PCI Configuration space Command register val */
+ struct s_smc *smc; /* board pointer */
+ struct net_device *tmp = dev;
+ u8 first_dev_used = 0;
+ u16 SubSysId;
+
+ PRINTK(KERN_INFO "entering skfp_probe\n");
+
+ /*
+ * Verify whether we're going through skfp_probe() again
+ *
+ * If so, see if we're going through for a subsequent fddi device that
+ * we've already initialized. If we are, return success (0). If not,
+ * return failure (-ENODEV).
+ */
+
+ if (autoprobed) {
+ PRINTK(KERN_INFO "Already entered skfp_probe\n");
+ if (dev != NULL) {
+ if ((strncmp(dev->name, "fddi", 4) == 0) &&
+ (dev->base_addr != 0)) {
+ return (0);
+ }
+ return (-ENODEV);
+ }
+ }
+ autoprobed = 1; /* set global flag */
+
+ printk("%s\n", boot_msg);
+
+ /* Scan for Syskonnect FDDI PCI controllers */
+ if (!pci_present()) { /* is PCI BIOS even present? */
+ printk("no PCI BIOS present\n");
+ return (-ENODEV);
+ }
+ for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) { // scan for PCI cards
+ PRINTK(KERN_INFO "Check device %d\n", i);
+ if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP,
+ pdev)) == 0) {
+ break;
+ }
+
+#ifndef MEM_MAPPED_IO
+ /* Verify that I/O enable bit is set (PCI slot is enabled) */
+ pci_read_config_word(pdev, PCI_COMMAND, &command);
+ if ((command & PCI_COMMAND_IO) == 0) {
+ PRINTK("I/O enable bit not set!");
+ PRINTK(" Verify that slot is enabled\n");
+ continue;
+ }
+
+ /* Turn off memory mapped space and enable mastering */
+
+ PRINTK(KERN_INFO "Command Reg: %04x\n", command);
+ command |= PCI_COMMAND_MASTER;
+ command &= ~PCI_COMMAND_MEMORY;
+ pci_write_config_word(pdev, PCI_COMMAND, command);
+
+ /* Read I/O base address from PCI Configuration Space */
+
+ pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port);
+ port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0)
+
+ /* Verify port address range is not already being used */
+
+ port_len = FP_IO_LEN;
+ if (check_region(port, port_len) != 0) {
+ printk("I/O range allocated to adapter");
+ printk(" (0x%X-0x%X) is already being used!\n", port,
+ (port + port_len - 1));
+ continue;
+ }
+#else
+ /* Verify that MEM enable bit is set (PCI slot is enabled) */
+ pci_read_config_word(pdev, PCI_COMMAND, &command);
+ if ((command & PCI_COMMAND_MEMORY) == 0) {
+ PRINTK("MEMORY-I/O enable bit not set!");
+ PRINTK(" Verify that slot is enabled\n");
+ continue;
+ }
+
+ /* Turn off IO mapped space and enable mastering */
+
+ PRINTK(KERN_INFO "Command Reg: %04x\n", command);
+ command |= PCI_COMMAND_MASTER;
+ command &= ~PCI_COMMAND_IO;
+ pci_write_config_word(pdev, PCI_COMMAND, command);
+
+ port = pdev->resource[0].start;
+
+ port = (unsigned long)ioremap(port, 0x4000);
+ if (!port){
+ printk("skfp: Unable to map MEMORY register, "
+ "FDDI adapter will be disabled.\n");
+ break;
+ }
+#endif
+
+ if ((!loading_module) || first_dev_used) {
+ /* Allocate a device structure for this adapter */
+ tmp = alloc_device(dev, port);
+ }
+ first_dev_used = 1; // only significant first time
+
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId);
+
+ if (tmp != NULL) {
+ if (loading_module)
+ link_modules(dev, tmp);
+ dev = tmp;
+ init_dev(dev, port);
+ dev->irq = pdev->irq;
+
+ /* Initialize board structure with bus-specific info */
+
+ smc = (struct s_smc *) dev->priv;
+ smc->os.dev = dev;
+ smc->os.bus_type = SK_BUS_TYPE_PCI;
+ smc->os.pdev = *pdev;
+ smc->os.QueueSkb = MAX_TX_QUEUE_LEN;
+ smc->os.MaxFrameSize = MAX_FRAME_SIZE;
+ smc->os.dev = dev;
+ smc->hw.slot = -1;
+ smc->os.ResetRequested = FALSE;
+ skb_queue_head_init(&smc->os.SendSkbQueue);
+
+ if (skfp_driver_init(dev) == 0) {
+ // only increment global board
+ // count on success
+ num_boards++;
+ request_region(dev->base_addr,
+ FP_IO_LEN, dev->name);
+ if ((SubSysId & 0xff00) == 0x5500 ||
+ (SubSysId & 0xff00) == 0x5800) {
+ printk("%s: SysKonnect FDDI PCI adapter"
+ " found (SK-%04X)\n", dev->name,
+ SubSysId);
+ } else {
+ printk("%s: FDDI PCI adapter found\n",
+ dev->name);
+ }
+ } else {
+ kfree(dev);
+ i = SKFP_MAX_NUM_BOARDS; // stop search
+
+ }
+
+ } // if (dev != NULL)
+
+ } // for SKFP_MAX_NUM_BOARDS
+
+ /*
+ * If we're at this point we're going through skfp_probe() for the
+ * first time. Return success (0) if we've initialized 1 or more
+ * boards. Otherwise, return failure (-ENODEV).
+ */
+
+ if (num_boards > 0)
+ return (0);
+ else {
+ printk("no SysKonnect FDDI adapter found\n");
+ return (-ENODEV);
+ }
+} // skfp_probe
+
+
+/************************
+ *
+ * Search the entire 'fddi' device list for a fixed probe. If a match isn't
+ * found then check for an autoprobe or unused device location. If they
+ * are not available then insert a new device structure at the end of
+ * the current list.
+ *
+ ************************/
+static struct net_device *alloc_device(struct net_device *dev, u_long iobase)
+{
+ struct net_device *adev = NULL;
+ int fixed = 0, new_dev = 0;
+
+ PRINTK(KERN_INFO "entering alloc_device\n");
+ if (!dev)
+ return dev;
+
+ num_fddi = fddi_dev_index(dev->name);
+ if (loading_module) {
+ num_fddi++;
+ dev = insert_device(dev, skfp_probe);
+ return dev;
+ }
+ while (1) {
+ if (((dev->base_addr == NO_ADDRESS) ||
+ (dev->base_addr == 0)) && !adev) {
+ adev = dev;
+ } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) {
+ fixed = 1;
+ } else {
+ if (dev->next == NULL) {
+ new_dev = 1;
+ } else if (strncmp(dev->next->name, "fddi", 4) != 0) {
+ new_dev = 1;
+ }
+ }
+ if ((dev->next == NULL) || new_dev || fixed)
+ break;
+ dev = dev->next;
+ num_fddi++;
+ } // while (1)
+
+ if (adev && !fixed) {
+ dev = adev;
+ num_fddi = fddi_dev_index(dev->name);
+ new_dev = 0;
+ }
+ if (((dev->next == NULL) && ((dev->base_addr != NO_ADDRESS) &&
+ (dev->base_addr != 0)) && !fixed) ||
+ new_dev) {
+ num_fddi++; /* New device */
+ dev = insert_device(dev, skfp_probe);
+ }
+ if (dev) {
+ if (!dev->priv) {
+ /* Allocate space for private board structure */
+ dev->priv = (void *) kmalloc(sizeof(struct s_smc),
+ GFP_KERNEL);
+ if (dev->priv == NULL) {
+ printk("%s: Could not allocate memory for",
+ dev->name);
+ printk(" private board structure!\n");
+ return (NULL);
+ }
+ /* clear structure */
+ memset(dev->priv, 0, sizeof(struct s_smc));
+ }
+ }
+ return dev;
+} // alloc_device
+
+
+
+/************************
+ *
+ * Initialize device structure
+ *
+ ************************/
+static void init_dev(struct net_device *dev, u_long iobase)
+{
+ /* Initialize new device structure */
+
+ dev->rmem_end = 0; /* shared memory isn't used */
+ dev->rmem_start = 0; /* shared memory isn't used */
+ dev->mem_end = 0; /* shared memory isn't used */
+ dev->mem_start = 0; /* shared memory isn't used */
+ dev->base_addr = iobase; /* save port (I/O) base address */
+ dev->if_port = 0; /* not applicable to FDDI adapters */
+ dev->dma = 0; /* Bus Master DMA doesn't require channel */
+ dev->irq = 0;
+
+ netif_start_queue(dev);
+
+ dev->get_stats = &skfp_ctl_get_stats;
+ dev->open = &skfp_open;
+ dev->stop = &skfp_close;
+ dev->hard_start_xmit = &skfp_send_pkt;
+ dev->hard_header = NULL; /* set in fddi_setup() */
+ dev->rebuild_header = NULL; /* set in fddi_setup() */
+ dev->set_multicast_list = &skfp_ctl_set_multicast_list;
+ dev->set_mac_address = &skfp_ctl_set_mac_address;
+ dev->do_ioctl = &skfp_ioctl;
+ dev->set_config = NULL; /* not supported for now &&& */
+ dev->header_cache_update = NULL; /* not supported */
+ dev->change_mtu = NULL; /* set in fddi_setup() */
+
+ /* Initialize remaining device structure information */
+ fddi_setup(dev);
+} // init_device
+
+
+/************************
+ *
+ * If at end of fddi device list and can't use current entry, malloc
+ * one up. If memory could not be allocated, print an error message.
+ *
+************************/
+static struct net_device *insert_device(struct net_device *dev,
+ int (*init) (struct net_device *))
+{
+ struct net_device *new;
+ int len;
+
+ PRINTK(KERN_INFO "entering insert_device\n");
+ len = sizeof(struct net_device) + 8 + sizeof(struct s_smc);
+ new = (struct net_device *) kmalloc(len, GFP_KERNEL);
+ if (new == NULL) {
+ printk("fddi%d: Device not initialised, insufficient memory\n",
+ num_fddi);
+ return NULL;
+ } else {
+ memset((char *) new, 0, len);
+ new->name = (char *) (new + 1);
+ new->priv = (struct s_smc *) (new->name + 8);
+ new->init = init; /* initialisation routine */
+ if (!loading_module) {
+ new->next = dev->next;
+ dev->next = new;
+ }
+ /* create new device name */
+ if (num_fddi > 999) {
+ sprintf(new->name, "fddi????");
+ } else {
+ sprintf(new->name, "fddi%d", num_fddi);
+ }
+ }
+ return new;
+} // insert_device
+
+
+/************************
+ *
+ * Get the number of a "fddiX" string
+ *
+ ************************/
+static int fddi_dev_index(unsigned char *s)
+{
+ int i = 0, j = 0;
+
+ for (; *s; s++) {
+ if (isdigit(*s)) {
+ j = 1;
+ i = (i * 10) + (*s - '0');
+ } else if (j)
+ break;
+ }
+ return i;
+} // fddi_dev_index
+
+
+/************************
+ *
+ * Used if loaded as module only. Link the device structures
+ * together. Needed to release them all at unload.
+ *
+************************/
+static void link_modules(struct net_device *dev, struct net_device *tmp)
+{
+ struct net_device *p = dev;
+
+ if (p) {
+ while (((struct s_smc *) (p->priv))->os.next_module) {
+ p = ((struct s_smc *) (p->priv))->os.next_module;
+ }
+
+ if (dev != tmp) {
+ ((struct s_smc *) (p->priv))->os.next_module = tmp;
+ } else {
+ ((struct s_smc *) (p->priv))->os.next_module = NULL;
+ }
+ }
+ return;
+} // link_modules
+
+
+
+/*
+ * ====================
+ * = skfp_driver_init =
+ * ====================
+ *
+ * Overview:
+ * Initializes remaining adapter board structure information
+ * and makes sure adapter is in a safe state prior to skfp_open().
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * This function allocates additional resources such as the host memory
+ * blocks needed by the adapter.
+ * The adapter is also reset. The OS must call skfp_open() to open
+ * the adapter and bring it on-line.
+ *
+ * Return Codes:
+ * 0 - initialization succeeded
+ * -1 - initialization failed
+ */
+static int skfp_driver_init(struct net_device *dev)
+{
+ struct s_smc *smc = (struct s_smc *) dev->priv;
+ skfddi_priv *bp = PRIV(dev);
+ u8 val; /* used for I/O read/writes */
+
+ PRINTK(KERN_INFO "entering skfp_driver_init\n");
+
+ // set the io address in private structures
+ bp->base_addr = dev->base_addr;
+ smc->hw.iop = dev->base_addr;
+
+ // Get the interrupt level from the PCI Configuration Table
+ val = dev->irq;
+
+ smc->hw.irq = val;
+
+ spin_lock_init(&bp->DriverLock);
+
+ // Determine the required size of the 'shared' memory area.
+ bp->SharedMemSize = mac_drv_check_space();
+ PRINTK(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize);
+ if (bp->SharedMemSize > 0) {
+ bp->SharedMemSize += 16; // for descriptor alignment
+
+ bp->SharedMemAddr = kmalloc(bp->SharedMemSize, GFP_KERNEL);
+ if (!bp->SharedMemSize) {
+ printk("could not allocate mem for ");
+ printk("hardware module: %ld byte\n",
+ bp->SharedMemSize);
+ return (-1);
+ }
+ bp->SharedMemHeap = 0; // Nothing used yet.
+
+ } else {
+ bp->SharedMemAddr = NULL;
+ bp->SharedMemHeap = 0;
+ } // SharedMemSize > 0
+
+ memset(bp->SharedMemAddr, 0, bp->SharedMemSize);
+
+ card_stop(smc); // Reset adapter.
+
+ PRINTK(KERN_INFO "mac_drv_init()..\n");
+ if (mac_drv_init(smc) != 0) {
+ PRINTK(KERN_INFO "mac_drv_init() failed.\n");
+ return (-1);
+ }
+ read_address(smc, NULL);
+ PRINTK(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n",
+ smc->hw.fddi_canon_addr.a[0],
+ smc->hw.fddi_canon_addr.a[1],
+ smc->hw.fddi_canon_addr.a[2],
+ smc->hw.fddi_canon_addr.a[3],
+ smc->hw.fddi_canon_addr.a[4],
+ smc->hw.fddi_canon_addr.a[5]);
+ memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
+
+ smt_reset_defaults(smc, 0);
+
+ return (0);
+} // skfp_driver_init
+
+
+/*
+ * =============
+ * = skfp_open =
+ * =============
+ *
+ * Overview:
+ * Opens the adapter
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * This function brings the adapter to an operational state.
+ *
+ * Return Codes:
+ * 0 - Adapter was successfully opened
+ * -EAGAIN - Could not register IRQ
+ */
+static int skfp_open(struct net_device *dev)
+{
+ struct s_smc *smc = (struct s_smc *) dev->priv;
+
+ PRINTK(KERN_INFO "entering skfp_open\n");
+ /* Register IRQ - support shared interrupts by passing device ptr */
+ if (request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ,
+ dev->name, dev)) {
+ printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
+ return (-EAGAIN);
+ }
+ /*
+ * Set current address to factory MAC address
+ *
+ * Note: We've already done this step in skfp_driver_init.
+ * However, it's possible that a user has set a node
+ * address override, then closed and reopened the
+ * adapter. Unless we reset the device address field
+ * now, we'll continue to use the existing modified
+ * address.
+ */
+ read_address(smc, NULL);
+ memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
+
+ init_smt(smc, NULL);
+ smt_online(smc, 1);
+ STI_FBI();
+
+ MOD_INC_USE_COUNT;
+
+ /* Clear local multicast address tables */
+ mac_clear_multicast(smc);
+
+ /* Disable promiscuous filter settings */
+ mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
+
+ return (0);
+} // skfp_open
+
+
+/*
+ * ==============
+ * = skfp_close =
+ * ==============
+ *
+ * Overview:
+ * Closes the device/module.
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * This routine closes the adapter and brings it to a safe state.
+ * The interrupt service routine is deregistered with the OS.
+ * The adapter can be opened again with another call to skfp_open().
+ *
+ * Return Codes:
+ * Always return 0.
+ *
+ * Assumptions:
+ * No further requests for this adapter are made after this routine is
+ * called. skfp_open() can be called to reset and reinitialize the
+ * adapter.
+ */
+static int skfp_close(struct net_device *dev)
+{
+ struct s_smc *smc = (struct s_smc *) dev->priv;
+ struct sk_buff *skb;
+ skfddi_priv *bp = PRIV(dev);
+
+ CLI_FBI();
+ smt_reset_defaults(smc, 1);
+ card_stop(smc);
+ mac_drv_clear_tx_queue(smc);
+ mac_drv_clear_rx_queue(smc);
+
+ netif_stop_queue(dev);
+ /* Deregister (free) IRQ */
+ free_irq(dev->irq, dev);
+
+ for (;;) {
+ skb = skb_dequeue(&bp->SendSkbQueue);
+ if (skb == NULL)
+ break;
+ bp->QueueSkb++;
+ dev_kfree_skb(skb);
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ return (0);
+} // skfp_close
+
+
+/*
+ * ==================
+ * = skfp_interrupt =
+ * ==================
+ *
+ * Overview:
+ * Interrupt processing routine
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * irq - interrupt vector
+ * dev_id - pointer to device information
+ * regs - pointer to registers structure
+ *
+ * Functional Description:
+ * This routine calls the interrupt processing routine for this adapter. It
+ * disables and reenables adapter interrupts, as appropriate. We can support
+ * shared interrupts since the incoming dev_id pointer provides our device
+ * structure context. All the real work is done in the hardware module.
+ *
+ * Return Codes:
+ * None
+ *
+ * Assumptions:
+ * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC
+ * on Intel-based systems) is done by the operating system outside this
+ * routine.
+ *
+ * System interrupts are enabled through this call.
+ *
+ * Side Effects:
+ * Interrupts are disabled, then reenabled at the adapter.
+ */
+
+void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct s_smc *smc; /* private board structure pointer */
+ skfddi_priv *bp = PRIV(dev);
+
+
+ if (dev == NULL) {
+ printk("%s: irq %d for unknown device\n", dev->name, irq);
+ return;
+ }
+
+ smc = (struct s_smc *) dev->priv;
+
+ // IRQs enabled or disabled ?
+ if (inpd(ADDR(B0_IMSK)) == 0) {
+ // IRQs are disabled: must be shared interrupt
+ return;
+ }
+ // Note: At this point, IRQs are enabled.
+ if ((inpd(ISR_A) & smc->hw.is_imask) == 0) { // IRQ?
+ // Adapter did not issue an IRQ: must be shared interrupt
+ return;
+ }
+ CLI_FBI(); // Disable IRQs from our adapter.
+ spin_lock(&bp->DriverLock);
+
+ // Call interrupt handler in hardware module (HWM).
+ fddi_isr(smc);
+
+ if (smc->os.ResetRequested) {
+ ResetAdapter(smc);
+ smc->os.ResetRequested = FALSE;
+ }
+ spin_unlock(&bp->DriverLock);
+ STI_FBI(); // Enable IRQs from our adapter.
+
+ return;
+} // skfp_interrupt
+
+
+/*
+ * ======================
+ * = skfp_ctl_get_stats =
+ * ======================
+ *
+ * Overview:
+ * Get statistics for FDDI adapter
+ *
+ * Returns:
+ * Pointer to FDDI statistics structure
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * Gets current MIB objects from adapter, then
+ * returns FDDI statistics structure as defined
+ * in if_fddi.h.
+ *
+ * Note: Since the FDDI statistics structure is
+ * still new and the device structure doesn't
+ * have an FDDI-specific get statistics handler,
+ * we'll return the FDDI statistics structure as
+ * a pointer to an Ethernet statistics structure.
+ * That way, at least the first part of the statistics
+ * structure can be decoded properly.
+ * We'll have to pay attention to this routine as the
+ * device structure becomes more mature and LAN media
+ * independent.
+ *
+ */
+struct enet_statistics *skfp_ctl_get_stats(struct net_device *dev)
+{
+ struct s_smc *bp = (struct s_smc *) dev->priv;
+
+ /* Fill the bp->stats structure with driver-maintained counters */
+
+ bp->os.MacStat.port_bs_flag[0] = 0x1234;
+ bp->os.MacStat.port_bs_flag[1] = 0x5678;
+// goos: need to fill out fddi statistic
+#if 0
+ /* Get FDDI SMT MIB objects */
+
+/* Fill the bp->stats structure with the SMT MIB object values */
+
+ memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id));
+ bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id;
+ bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id;
+ bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id;
+ memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data));
+ bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id;
+ bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct;
+ bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct;
+ bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct;
+ bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths;
+ bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities;
+ bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy;
+ bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy;
+ bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify;
+ bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy;
+ bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration;
+ bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present;
+ bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state;
+ bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state;
+ bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag;
+ bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status;
+ bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag;
+ bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls;
+ bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls;
+ bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions;
+ bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability;
+ bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability;
+ bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths;
+ bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path;
+ memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN);
+ memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN);
+ memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN);
+ memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN);
+ bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test;
+ bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths;
+ bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type;
+ memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN);
+ bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req;
+ bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg;
+ bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max;
+ bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value;
+ bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold;
+ bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio;
+ bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state;
+ bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag;
+ bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag;
+ bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag;
+ bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available;
+ bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present;
+ bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable;
+ bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound;
+ bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound;
+ bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req;
+ memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration));
+ bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0];
+ bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1];
+ bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0];
+ bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1];
+ bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0];
+ bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1];
+ bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0];
+ bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1];
+ bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0];
+ bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1];
+ memcpy(&bp->stats.port_requested_paths[0 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3);
+ memcpy(&bp->stats.port_requested_paths[1 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3);
+ bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0];
+ bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1];
+ bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0];
+ bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1];
+ bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0];
+ bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1];
+ bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0];
+ bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1];
+ bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0];
+ bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1];
+ bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0];
+ bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1];
+ bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0];
+ bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1];
+ bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0];
+ bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1];
+ bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0];
+ bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1];
+ bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0];
+ bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1];
+ bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0];
+ bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1];
+ bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0];
+ bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1];
+ bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0];
+ bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1];
+
+
+ /* Fill the bp->stats structure with the FDDI counter values */
+
+ bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls;
+ bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls;
+ bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls;
+ bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls;
+ bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls;
+ bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls;
+ bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls;
+ bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls;
+ bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls;
+ bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls;
+ bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
+
+#endif
+ return ((struct enet_statistics *) &bp->os.MacStat);
+} // ctl_get_stat
+
+
+/*
+ * ==============================
+ * = skfp_ctl_set_multicast_list =
+ * ==============================
+ *
+ * Overview:
+ * Enable/Disable LLC frame promiscuous mode reception
+ * on the adapter and/or update multicast address table.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * This function aquires the driver lock and only calls
+ * skfp_ctl_set_multicast_list_wo_lock then.
+ * This routine follows a fairly simple algorithm for setting the
+ * adapter filters and CAM:
+ *
+ * if IFF_PROMISC flag is set
+ * enable promiscuous mode
+ * else
+ * disable promiscuous mode
+ * if number of multicast addresses <= max. multicast number
+ * add mc addresses to adapter table
+ * else
+ * enable promiscuous mode
+ * update adapter filters
+ *
+ * Assumptions:
+ * Multicast addresses are presented in canonical (LSB) format.
+ *
+ * Side Effects:
+ * On-board adapter filters are updated.
+ */
+static void skfp_ctl_set_multicast_list(struct net_device *dev)
+{
+ skfddi_priv *bp = PRIV(dev);
+ unsigned long Flags;
+
+ spin_lock_irqsave(&bp->DriverLock, Flags);
+ skfp_ctl_set_multicast_list_wo_lock(dev);
+ spin_unlock_irqrestore(&bp->DriverLock, Flags);
+ return;
+} // skfp_ctl_set_multicast_list
+
+
+
+static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
+{
+ struct s_smc *smc = (struct s_smc *) dev->priv;
+ struct dev_mc_list *dmi; /* ptr to multicast addr entry */
+ int i;
+
+ /* Enable promiscuous mode, if necessary */
+ if (dev->flags & IFF_PROMISC) {
+ mac_drv_rx_mode(smc, RX_ENABLE_PROMISC);
+ PRINTK(KERN_INFO "PROMISCUOUS MODE ENABLED\n");
+ }
+ /* Else, update multicast address table */
+ else {
+ mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
+ PRINTK(KERN_INFO "PROMISCUOUS MODE DISABLED\n");
+
+ // Reset all MC addresses
+ mac_clear_multicast(smc);
+ mac_drv_rx_mode(smc, RX_DISABLE_ALLMULTI);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
+ PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+ } else if (dev->mc_count > 0) {
+ if (dev->mc_count <= FPMAX_MULTICAST) {
+ /* use exact filtering */
+
+ // point to first multicast addr
+ dmi = dev->mc_list;
+
+ for (i = 0; i < dev->mc_count; i++) {
+ mac_add_multicast(smc,
+ dmi->dmi_addr, 1);
+ PRINTK(KERN_INFO "ENABLE MC ADDRESS:");
+ PRINTK(" %02x %02x %02x ",
+ dmi->dmi_addr[0],
+ dmi->dmi_addr[1],
+ dmi->dmi_addr[2]);
+ PRINTK("%02x %02x %02x\n",
+ dmi->dmi_addr[3],
+ dmi->dmi_addr[4],
+ dmi->dmi_addr[5]);
+ dmi = dmi->next;
+ } // for
+
+ } else { // more MC addresses than HW supports
+
+ mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
+ PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+ }
+ } else { // no MC addresses
+
+ PRINTK(KERN_INFO "DISABLE ALL MC ADDRESSES\n");
+ }
+
+ /* Update adapter filters */
+ mac_update_multicast(smc);
+ }
+ return;
+} // skfp_ctl_set_multicast_list_wo_lock
+
+
+/*
+ * ===========================
+ * = skfp_ctl_set_mac_address =
+ * ===========================
+ *
+ * Overview:
+ * set new mac address on adapter and update dev_addr field in device table.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * dev - pointer to device information
+ * addr - pointer to sockaddr structure containing unicast address to set
+ *
+ * Assumptions:
+ * The address pointed to by addr->sa_data is a valid unicast
+ * address and is presented in canonical (LSB) format.
+ */
+static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct s_smc *smc = (struct s_smc *) dev->priv;
+ struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+ skfddi_priv *bp = (skfddi_priv *) & smc->os;
+ unsigned long Flags;
+
+
+ memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN);
+ spin_lock_irqsave(&bp->DriverLock, Flags);
+ ResetAdapter(smc);
+ spin_unlock_irqrestore(&bp->DriverLock, Flags);
+
+ return (0); /* always return zero */
+} // skfp_ctl_set_mac_address
+
+
+/*
+ * ==============
+ * = skfp_ioctl =
+ * ==============
+ *
+ * Overview:
+ *
+ * Perform IOCTL call functions here. Some are privileged operations and the
+ * effective uid is checked in those cases.
+ *
+ * Returns:
+ * status value
+ * 0 - success
+ * other - failure
+ *
+ * Arguments:
+ * dev - pointer to device information
+ * rq - pointer to ioctl request structure
+ * cmd - ?
+ *
+ */
+
+
+static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ skfddi_priv *lp = PRIV(dev);
+ struct s_skfp_ioctl ioc;
+ int status = 0;
+
+ copy_from_user(&ioc, rq->ifr_data, sizeof(struct s_skfp_ioctl));
+ switch (ioc.cmd) {
+ case SKFP_GET_STATS: /* Get the driver statistics */
+ ioc.len = sizeof(lp->MacStat);
+ copy_to_user(ioc.data, skfp_ctl_get_stats(dev), ioc.len);
+ break;
+ case SKFP_CLR_STATS: /* Zero out the driver statistics */
+ if (suser()) {
+ memset(&lp->MacStat, 0, sizeof(lp->MacStat));
+ } else {
+ status = -EPERM;
+ }
+ break;
+ default:
+ printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd);
+ } // switch
+
+ return status;
+} // skfp_ioctl
+
+
+/*
+ * =====================
+ * = skfp_send_pkt =
+ * =====================
+ *
+ * Overview:
+ * Queues a packet for transmission and try to transmit it.
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * skb - pointer to sk_buff to queue for transmission
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * Here we assume that an incoming skb transmit request
+ * is contained in a single physically contiguous buffer
+ * in which the virtual address of the start of packet
+ * (skb->data) can be converted to a physical address
+ * by using virt_to_bus().
+ *
+ * We have an internal queue for packets we can not send
+ * immediately. Packets in this queue can be given to the
+ * adapter if transmit buffers are freed.
+ *
+ * We can't free the skb until after it's been DMA'd
+ * out by the adapter, so we'll keep it in the driver and
+ * return it in mac_drv_tx_complete.
+ *
+ * Return Codes:
+ * 0 - driver has queued and/or sent packet
+ * 1 - caller should requeue the sk_buff for later transmission
+ *
+ * Assumptions:
+ * The entire packet is stored in one physically
+ * contiguous buffer which is not cached and whose
+ * 32-bit physical address can be determined.
+ *
+ * It's vital that this routine is NOT reentered for the
+ * same board and that the OS is not in another section of
+ * code (eg. skfp_interrupt) for the same board on a
+ * different thread.
+ *
+ * Side Effects:
+ * None
+ */
+static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+ skfddi_priv *bp = PRIV(dev);
+
+ PRINTK(KERN_INFO "skfp_send_pkt\n");
+
+ /*
+ * Verify that incoming transmit request is OK
+ *
+ * Note: The packet size check is consistent with other
+ * Linux device drivers, although the correct packet
+ * size should be verified before calling the
+ * transmit routine.
+ */
+
+ if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) {
+ bp->MacStat.tx_errors++; /* bump error counter */
+ // dequeue packets from xmt queue and send them
+ netif_start_queue(dev);
+ dev_kfree_skb(skb);
+ return (0); /* return "success" */
+ }
+ if (bp->QueueSkb == 0) { // return with tbusy set: queue full
+
+ netif_stop_queue(dev);
+ return 1;
+ }
+ bp->QueueSkb--;
+ skb_queue_tail(&bp->SendSkbQueue, skb);
+ send_queued_packets((struct s_smc *) dev->priv);
+ if (bp->QueueSkb == 0) {
+ netif_stop_queue(dev);
+ }
+ dev->trans_start = jiffies;
+ return 0;
+
+} // skfp_send_pkt
+
+
+/*
+ * =======================
+ * = send_queued_packets =
+ * =======================
+ *
+ * Overview:
+ * Send packets from the driver queue as long as there are some and
+ * transmit resources are available.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * smc - pointer to smc (adapter) structure
+ *
+ * Functional Description:
+ * Take a packet from queue if there is any. If not, then we are done.
+ * Check if there are resources to send the packet. If not, requeue it
+ * and exit.
+ * Set packet descriptor flags and give packet to adapter.
+ * Check if any send resources can be freed (we do not use the
+ * transmit complete interrupt).
+ */
+static void send_queued_packets(struct s_smc *smc)
+{
+ skfddi_priv *bp = (skfddi_priv *) & smc->os;
+ struct sk_buff *skb;
+ unsigned char fc;
+ int queue;
+ struct s_smt_fp_txd *txd; // Current TxD.
+ unsigned long Flags;
+
+ int frame_status; // HWM tx frame status.
+
+ PRINTK(KERN_INFO "send queued packets\n");
+ for (;;) {
+ // send first buffer from queue
+ skb = skb_dequeue(&bp->SendSkbQueue);
+
+ if (!skb) {
+ PRINTK(KERN_INFO "queue empty\n");
+ return;
+ } // queue empty !
+
+ spin_lock_irqsave(&bp->DriverLock, Flags);
+ fc = skb->data[0];
+ queue = (fc & FC_SYNC_BIT) ? QUEUE_S : QUEUE_A0;
+#ifdef ESS
+ // Check if the frame may/must be sent as a synchronous frame.
+
+ if ((fc & ~(FC_SYNC_BIT | FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
+ // It's an LLC frame.
+ if (!smc->ess.sync_bw_available)
+ fc &= ~FC_SYNC_BIT; // No bandwidth available.
+
+ else { // Bandwidth is available.
+
+ if (smc->mib.fddiESSSynchTxMode) {
+ // Send as sync. frame.
+ fc |= FC_SYNC_BIT;
+ }
+ }
+ }
+#endif // ESS
+ frame_status = hwm_tx_init(smc, fc, 1, skb->len, queue);
+
+ if ((frame_status & (LOC_TX | LAN_TX)) == 0) {
+ // Unable to send the frame.
+
+ if ((frame_status & RING_DOWN) != 0) {
+ // Ring is down.
+ PRINTK("Tx attempt while ring down.\n");
+ } else if ((frame_status & OUT_OF_TXD) != 0) {
+ PRINTK("%s: out of TXDs.\n", bp->dev->name);
+ } else {
+ PRINTK("%s: out of transmit resources",
+ bp->dev->name);
+ }
+
+ // Note: We will retry the operation as soon as
+ // transmit resources become available.
+ skb_queue_head(&bp->SendSkbQueue, skb);
+ spin_unlock_irqrestore(&bp->DriverLock, Flags);
+ return; // Packet has been queued.
+
+ } // if (unable to send frame)
+
+ bp->QueueSkb++; // one packet less in local queue
+
+ // source address in packet ?
+ CheckSourceAddress(skb->data, smc->hw.fddi_canon_addr.a);
+
+ txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue);
+
+ if (frame_status & LAN_TX) {
+ txd->txd_os.skb = skb; // save skb
+ }
+ hwm_tx_frag(smc, skb->data, virt_to_bus(skb->data), skb->len,
+ frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF);
+
+ if (!(frame_status & LAN_TX)) { // local only frame
+ dev_kfree_skb_irq(skb);
+ }
+ spin_unlock_irqrestore(&bp->DriverLock, Flags);
+ } // for
+
+ return; // never reached
+
+} // send_queued_packets
+
+
+/************************
+ *
+ * CheckSourceAddress
+ *
+ * Verify if the source address is set. Insert it if necessary.
+ *
+ ************************/
+void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr)
+{
+ unsigned char SRBit;
+
+ if ((((unsigned long) frame[1 + 6]) & ~0x01) != 0) // source routing bit
+
+ return;
+ if ((unsigned short) frame[1 + 10] != 0)
+ return;
+ SRBit = frame[1 + 6] & 0x01;
+ memcpy(&frame[1 + 6], hw_addr, 6);
+ frame[8] |= SRBit;
+} // CheckSourceAddress
+
+
+/************************
+ *
+ * ResetAdapter
+ *
+ * Reset the adapter and bring it back to operational mode.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ * Out
+ * Nothing.
+ *
+ ************************/
+static void ResetAdapter(struct s_smc *smc)
+{
+
+ PRINTK(KERN_INFO "[fddi: ResetAdapter]\n");
+
+ // Stop the adapter.
+
+ card_stop(smc); // Stop all activity.
+
+ // Clear the transmit and receive descriptor queues.
+ mac_drv_clear_tx_queue(smc);
+ mac_drv_clear_rx_queue(smc);
+
+ // Restart the adapter.
+
+ smt_reset_defaults(smc, 1); // Initialize the SMT module.
+
+ init_smt(smc, (smc->os.dev)->dev_addr); // Initialize the hardware.
+
+ smt_online(smc, 1); // Insert into the ring again.
+ STI_FBI();
+
+ // Restore original receive mode (multicasts, promiscuous, etc.).
+ skfp_ctl_set_multicast_list_wo_lock(smc->os.dev);
+} // ResetAdapter
+
+
+//--------------- functions called by hardware module ----------------
+
+/************************
+ *
+ * llc_restart_tx
+ *
+ * The hardware driver calls this routine when the transmit complete
+ * interrupt bits (end of frame) for the synchronous or asynchronous
+ * queue is set.
+ *
+ * NOTE The hardware driver calls this function also if no packets are queued.
+ * The routine must be able to handle this case.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void llc_restart_tx(struct s_smc *smc)
+{
+ skfddi_priv *bp = (skfddi_priv *) & smc->os;
+
+ PRINTK(KERN_INFO "[llc_restart_tx]\n");
+
+ // Try to send queued packets
+ spin_unlock(&bp->DriverLock);
+ send_queued_packets(smc);
+ spin_lock(&bp->DriverLock);
+ netif_start_queue(bp->dev);// system may send again if it was blocked
+
+} // llc_restart_tx
+
+
+/************************
+ *
+ * mac_drv_get_space
+ *
+ * The hardware module calls this function to allocate the memory
+ * for the SMT MBufs if the define MB_OUTSIDE_SMC is specified.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * size - Size of memory in bytes to allocate.
+ * Out
+ * != 0 A pointer to the virtual address of the allocated memory.
+ * == 0 Allocation error.
+ *
+ ************************/
+void *mac_drv_get_space(struct s_smc *smc, unsigned int size)
+{
+ void *virt;
+
+ PRINTK(KERN_INFO "mac_drv_get_space\n");
+ virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap);
+
+ if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) {
+ printk("Unexpected SMT memory size requested: %d\n", size);
+ return (NULL);
+ }
+ smc->os.SharedMemHeap += size; // Move heap pointer.
+
+ PRINTK(KERN_INFO "mac_drv_get_space end\n");
+ PRINTK(KERN_INFO "virt addr: %08lx\n", (ulong) virt);
+ PRINTK(KERN_INFO "bus addr: %08lx\n", (ulong) virt_to_bus(virt));
+ return (virt);
+} // mac_drv_get_space
+
+
+/************************
+ *
+ * mac_drv_get_desc_mem
+ *
+ * This function is called by the hardware dependent module.
+ * It allocates the memory for the RxD and TxD descriptors.
+ *
+ * This memory must be non-cached, non-movable and non-swapable.
+ * This memory should start at a physical page boundary.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * size - Size of memory in bytes to allocate.
+ * Out
+ * != 0 A pointer to the virtual address of the allocated memory.
+ * == 0 Allocation error.
+ *
+ ************************/
+void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size)
+{
+
+ char *virt;
+
+ PRINTK(KERN_INFO "mac_drv_get_desc_mem\n");
+
+ // Descriptor memory must be aligned on 16-byte boundary.
+
+ virt = mac_drv_get_space(smc, size);
+
+ size = (u_int) ((0 - (unsigned int) virt) & 15);
+
+ PRINTK("Allocate %u bytes alignment gap ", size);
+ PRINTK("for descriptor memory.\n");
+
+ if (!mac_drv_get_space(smc, size)) {
+ printk("fddi: Unable to align descriptor memory.\n");
+ return (NULL);
+ }
+ return (virt + size);
+} // mac_drv_get_desc_mem
+
+
+/************************
+ *
+ * mac_drv_virt2phys
+ *
+ * Get the physical address of a given virtual address.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * virt - A (virtual) pointer into our 'shared' memory area.
+ * Out
+ * Physical address of the given virtual address.
+ *
+ ************************/
+unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt)
+{
+ return virt_to_bus(virt);
+} // mac_drv_virt2phys
+
+
+/************************
+ *
+ * dma_master
+ *
+ * The HWM calls this function, when the driver leads through a DMA
+ * transfer. If the OS-specific module must prepare the system hardware
+ * for the DMA transfer, it should do it in this function.
+ *
+ * The hardware module calls this dma_master if it wants to send an SMT
+ * frame.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * virt - The virtual address of the data.
+ *
+ * len - The length in bytes of the data.
+ *
+ * flag - Indicates the transmit direction and the buffer type:
+ * DMA_RD (0x01) system RAM ==> adapter buffer memory
+ * DMA_WR (0x02) adapter buffer memory ==> system RAM
+ * SMT_BUF (0x80) SMT buffer
+ *
+ * >> NOTE: SMT_BUF and DMA_RD are always set for PCI. <<
+ * Out
+ * Returns the pyhsical address for the DMA transfer.
+ *
+ ************************/
+u_long dma_master(struct s_smc * smc, void *virt, int len, int flag)
+{
+ return (virt_to_bus(virt));
+} // dma_master
+
+
+/************************
+ *
+ * dma_complete
+ *
+ * The hardware module calls this routine when it has completed a DMA
+ * transfer. If the operating system dependant module has set up the DMA
+ * channel via dma_master() (e.g. Windows NT or AIX) it should clean up
+ * the DMA channel.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * descr - A pointer to a TxD or RxD, respectively.
+ *
+ * flag - Indicates the DMA transfer direction / SMT buffer:
+ * DMA_RD (0x01) system RAM ==> adapter buffer memory
+ * DMA_WR (0x02) adapter buffer memory ==> system RAM
+ * SMT_BUF (0x80) SMT buffer (managed by HWM)
+ * Out
+ * Nothing.
+ *
+ ************************/
+void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag)
+{
+ return;
+} // dma_complete
+
+
+/************************
+ *
+ * mac_drv_tx_complete
+ *
+ * Transmit of a packet is complete. Release the tx staging buffer.
+ *
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * txd - A pointer to the last TxD which is used by the frame.
+ * Out
+ * Returns nothing.
+ *
+ ************************/
+void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd)
+{
+ struct sk_buff *skb;
+
+ PRINTK(KERN_INFO "entering mac_drv_tx_complete\n");
+ // Check if this TxD points to a skb
+
+ if (!(skb = txd->txd_os.skb)) {
+ PRINTK("TXD with no skb assigned.\n");
+ return;
+ }
+ txd->txd_os.skb = NULL;
+
+ smc->os.MacStat.tx_packets++; // Count transmitted packets.
+ smc->os.MacStat.tx_bytes+=skb->len; // Count bytes
+
+ // free the skb
+ dev_kfree_skb_irq(skb);
+
+ PRINTK(KERN_INFO "leaving mac_drv_tx_complete\n");
+} // mac_drv_tx_complete
+
+
+/************************
+ *
+ * dump packets to logfile
+ *
+ ************************/
+#ifdef DUMPPACKETS
+void dump_data(unsigned char *Data, int length)
+{
+ int i, j;
+ unsigned char s[255], sh[10];
+ if (length > 64) {
+ length = 64;
+ }
+ printk(KERN_INFO "---Packet start---\n");
+ for (i = 0, j = 0; i < length / 8; i++, j += 8)
+ printk(KERN_INFO "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ Data[j + 0], Data[j + 1], Data[j + 2], Data[j + 3],
+ Data[j + 4], Data[j + 5], Data[j + 6], Data[j + 7]);
+ strcpy(s, "");
+ for (i = 0; i < length % 8; i++) {
+ sprintf(sh, "%02x ", Data[j + i]);
+ strcat(s, sh);
+ }
+ printk(KERN_INFO "%s\n", s);
+ printk(KERN_INFO "------------------\n");
+} // dump_data
+#else
+#define dump_data(data,len)
+#endif // DUMPPACKETS
+
+/************************
+ *
+ * mac_drv_rx_complete
+ *
+ * The hardware module calls this function if an LLC frame is received
+ * in a receive buffer. Also the SMT, NSA, and directed beacon frames
+ * from the network will be passed to the LLC layer by this function
+ * if passing is enabled.
+ *
+ * mac_drv_rx_complete forwards the frame to the LLC layer if it should
+ * be received. It also fills the RxD ring with new receive buffers if
+ * some can be queued.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * rxd - A pointer to the first RxD which is used by the receive frame.
+ *
+ * frag_count - Count of RxDs used by the received frame.
+ *
+ * len - Frame length.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+ int frag_count, int len)
+{
+ skfddi_priv *bp = (skfddi_priv *) & smc->os;
+ struct sk_buff *skb;
+ unsigned char *virt, *cp;
+ unsigned short ri;
+ u_int RifLength;
+
+ PRINTK(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len);
+ if (frag_count != 1) { // This is not allowed to happen.
+
+ printk("fddi: Multi-fragment receive!\n");
+ goto RequeueRxd; // Re-use the given RXD(s).
+
+ }
+ skb = rxd->rxd_os.skb;
+ if (!skb) {
+ PRINTK(KERN_INFO "No skb in rxd\n");
+ smc->os.MacStat.rx_errors++;
+ goto RequeueRxd;
+ }
+ virt = skb->data;
+
+ dump_data(skb->data, len);
+
+ /*
+ * FDDI Frame format:
+ * +-------+-------+-------+------------+--------+------------+
+ * | FC[1] | DA[6] | SA[6] | RIF[0..18] | LLC[3] | Data[0..n] |
+ * +-------+-------+-------+------------+--------+------------+
+ *
+ * FC = Frame Control
+ * DA = Destination Address
+ * SA = Source Address
+ * RIF = Routing Information Field
+ * LLC = Logical Link Control
+ */
+
+ // Remove Routing Information Field (RIF), if present.
+
+ if ((virt[1 + 6] & FDDI_RII) == 0)
+ RifLength = 0;
+ else {
+ int n;
+// goos: RIF removal has still to be tested
+ PRINTK(KERN_INFO "RIF found\n");
+ // Get RIF length from Routing Control (RC) field.
+ cp = virt + FDDI_MAC_HDR_LEN; // Point behind MAC header.
+
+ ri = ntohs(*((unsigned short *) cp));
+ RifLength = ri & FDDI_RCF_LEN_MASK;
+ if (len < (int) (FDDI_MAC_HDR_LEN + RifLength)) {
+ printk("fddi: Invalid RIF.\n");
+ goto RequeueRxd; // Discard the frame.
+
+ }
+ virt[1 + 6] &= ~FDDI_RII; // Clear RII bit.
+ // regions overlap
+
+ virt = cp + RifLength;
+ for (n = FDDI_MAC_HDR_LEN; n; n--)
+ *--virt = *--cp;
+ // adjust sbd->data pointer
+ skb_pull(skb, RifLength);
+ len -= RifLength;
+ RifLength = 0;
+ }
+
+ // Count statistics.
+ smc->os.MacStat.rx_packets++; // Count indicated receive packets.
+ smc->os.MacStat.rx_bytes+=len; // Count bytes
+
+ // virt points to header again
+ if (virt[1] & 0x01) { // Check group (multicast) bit.
+
+ smc->os.MacStat.multicast++;
+ }
+
+ // deliver frame to system
+ rxd->rxd_os.skb = NULL;
+ skb_trim(skb, len);
+ skb->protocol = fddi_type_trans(skb, bp->dev);
+ skb->dev = bp->dev; /* pass up device pointer */
+
+ netif_rx(skb);
+
+ HWM_RX_CHECK(smc, RX_LOW_WATERMARK);
+ return;
+
+ RequeueRxd:
+ PRINTK(KERN_INFO "Rx: re-queue RXD.\n");
+ mac_drv_requeue_rxd(smc, rxd, frag_count);
+ smc->os.MacStat.rx_errors++; // Count receive packets not indicated.
+
+} // mac_drv_rx_complete
+
+
+/************************
+ *
+ * mac_drv_requeue_rxd
+ *
+ * The hardware module calls this function to request the OS-specific
+ * module to queue the receive buffer(s) represented by the pointer
+ * to the RxD and the frag_count into the receive queue again. This
+ * buffer was filled with an invalid frame or an SMT frame.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * rxd - A pointer to the first RxD which is used by the receive frame.
+ *
+ * frag_count - Count of RxDs used by the received frame.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+ int frag_count)
+{
+ volatile struct s_smt_fp_rxd *next_rxd;
+ volatile struct s_smt_fp_rxd *src_rxd;
+ struct sk_buff *skb;
+ int MaxFrameSize;
+ unsigned char *v_addr;
+ unsigned long b_addr;
+
+ if (frag_count != 1) // This is not allowed to happen.
+
+ printk("fddi: Multi-fragment requeue!\n");
+
+ MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize;
+ src_rxd = rxd;
+ for (; frag_count > 0; frag_count--) {
+ next_rxd = src_rxd->rxd_next;
+ rxd = HWM_GET_CURR_RXD(smc);
+
+ skb = src_rxd->rxd_os.skb;
+ if (skb == NULL) { // this should not happen
+
+ PRINTK("Requeue with no skb in rxd!\n");
+ skb = alloc_skb(MaxFrameSize, GFP_ATOMIC);
+ if (skb) {
+ // we got a skb
+ rxd->rxd_os.skb = skb;
+ skb_put(skb, MaxFrameSize);
+ v_addr = skb->data;
+ b_addr = virt_to_bus(v_addr);
+ } else {
+ // no skb available, use local buffer
+ PRINTK("Queueing invalid buffer!\n");
+ rxd->rxd_os.skb = NULL;
+ v_addr = smc->os.LocalRxBuffer;
+ b_addr = virt_to_bus(v_addr);
+ }
+ } else {
+ // we use skb from old rxd
+ rxd->rxd_os.skb = skb;
+ v_addr = skb->data;
+ b_addr = virt_to_bus(v_addr);
+ }
+ hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
+ FIRST_FRAG | LAST_FRAG);
+
+ src_rxd = next_rxd;
+ }
+} // mac_drv_requeue_rxd
+
+
+/************************
+ *
+ * mac_drv_fill_rxd
+ *
+ * The hardware module calls this function at initialization time
+ * to fill the RxD ring with receive buffers. It is also called by
+ * mac_drv_rx_complete if rx_free is large enough to queue some new
+ * receive buffers into the RxD ring. mac_drv_fill_rxd queues new
+ * receive buffers as long as enough RxDs and receive buffers are
+ * available.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void mac_drv_fill_rxd(struct s_smc *smc)
+{
+ int MaxFrameSize;
+ unsigned char *v_addr;
+ unsigned long b_addr;
+ struct sk_buff *skb;
+ volatile struct s_smt_fp_rxd *rxd;
+
+ PRINTK(KERN_INFO "entering mac_drv_fill_rxd\n");
+
+ // Walk through the list of free receive buffers, passing receive
+ // buffers to the HWM as long as RXDs are available.
+
+ MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize;
+ // Check if there is any RXD left.
+ while (HWM_GET_RX_FREE(smc) > 0) {
+ PRINTK(KERN_INFO ".\n");
+
+ rxd = HWM_GET_CURR_RXD(smc);
+ skb = alloc_skb(MaxFrameSize, GFP_ATOMIC);
+ if (skb) {
+ // we got a skb
+ skb_put(skb, MaxFrameSize);
+ v_addr = skb->data;
+ b_addr = virt_to_bus(v_addr);
+ } else {
+ // no skb available, use local buffer
+ // System has run out of buffer memory, but we want to
+ // keep the receiver running in hope of better times.
+ // Multiple descriptors may point to this local buffer,
+ // so data in it must be considered invalid.
+ PRINTK("Queueing invalid buffer!\n");
+ v_addr = smc->os.LocalRxBuffer;
+ b_addr = virt_to_bus(v_addr);
+ }
+
+ rxd->rxd_os.skb = skb;
+
+ // Pass receive buffer to HWM.
+ hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
+ FIRST_FRAG | LAST_FRAG);
+ }
+ PRINTK(KERN_INFO "leaving mac_drv_fill_rxd\n");
+} // mac_drv_fill_rxd
+
+
+/************************
+ *
+ * mac_drv_clear_rxd
+ *
+ * The hardware module calls this function to release unused
+ * receive buffers.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * rxd - A pointer to the first RxD which is used by the receive buffer.
+ *
+ * frag_count - Count of RxDs used by the receive buffer.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+ int frag_count)
+{
+
+ struct sk_buff *skb;
+
+ PRINTK("entering mac_drv_clear_rxd\n");
+
+ if (frag_count != 1) // This is not allowed to happen.
+
+ printk("fddi: Multi-fragment clear!\n");
+
+ for (; frag_count > 0; frag_count--) {
+ skb = rxd->rxd_os.skb;
+ if (skb != NULL) {
+ dev_kfree_skb(skb);
+ rxd->rxd_os.skb = NULL;
+ }
+ rxd = rxd->rxd_next; // Next RXD.
+
+ }
+} // mac_drv_clear_rxd
+
+
+/************************
+ *
+ * mac_drv_rx_init
+ *
+ * The hardware module calls this routine when an SMT or NSA frame of the
+ * local SMT should be delivered to the LLC layer.
+ *
+ * It is necessary to have this function, because there is no other way to
+ * copy the contents of SMT MBufs into receive buffers.
+ *
+ * mac_drv_rx_init allocates the required target memory for this frame,
+ * and receives the frame fragment by fragment by calling mac_drv_rx_frag.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * len - The length (in bytes) of the received frame (FC, DA, SA, Data).
+ *
+ * fc - The Frame Control field of the received frame.
+ *
+ * look_ahead - A pointer to the lookahead data buffer (may be NULL).
+ *
+ * la_len - The length of the lookahead data stored in the lookahead
+ * buffer (may be zero).
+ * Out
+ * Always returns zero (0).
+ *
+ ************************/
+int mac_drv_rx_init(struct s_smc *smc, int len, int fc,
+ char *look_ahead, int la_len)
+{
+ struct sk_buff *skb;
+
+ PRINTK("entering mac_drv_rx_init(len=%d)\n", len);
+
+ // "Received" a SMT or NSA frame of the local SMT.
+
+ if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) {
+ PRINTK("fddi: Discard invalid local SMT frame\n");
+ PRINTK(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n",
+ len, la_len, (unsigned long) look_ahead);
+ return (0);
+ }
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (!skb) {
+ PRINTK("fddi: Local SMT: skb memory exhausted.\n");
+ return (0);
+ }
+ skb_put(skb, len);
+ memcpy(skb->data, look_ahead, len);
+
+ // deliver frame to system
+ skb->protocol = fddi_type_trans(skb, ((skfddi_priv *) & smc->os)->dev);
+ netif_rx(skb);
+
+ return (0);
+} // mac_drv_rx_init
+
+
+/************************
+ *
+ * smt_timer_poll
+ *
+ * This routine is called periodically by the SMT module to clean up the
+ * driver.
+ *
+ * Return any queued frames back to the upper protocol layers if the ring
+ * is down.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void smt_timer_poll(struct s_smc *smc)
+{
+} // smt_timer_poll
+
+
+/************************
+ *
+ * ring_status_indication
+ *
+ * This function indicates a change of the ring state.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * status - The current ring status.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void ring_status_indication(struct s_smc *smc, u_long status)
+{
+ PRINTK("ring_status_indication(%08lXh)\n", (unsigned long) status);
+} // ring_status_indication
+
+
+/************************
+ *
+ * smt_get_time
+ *
+ * Gets the current time from the system.
+ * Args
+ * None.
+ * Out
+ * The current time in TICKS_PER_SECOND.
+ *
+ * TICKS_PER_SECOND has the unit 'count of timer ticks per second'. It is
+ * defined in "targetos.h". The definition of TICKS_PER_SECOND must comply
+ * to the time returned by smt_get_time().
+ *
+ ************************/
+unsigned long smt_get_time(void)
+{
+ return jiffies;
+} // smt_get_time
+
+
+/************************
+ *
+ * smt_stat_counter
+ *
+ * Status counter update (ring_op, fifo full).
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * stat - = 0: A ring operational change occurred.
+ * = 1: The FORMAC FIFO buffer is full / FIFO overflow.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void smt_stat_counter(struct s_smc *smc, int stat)
+{
+// BOOLEAN RingIsUp ;
+
+ PRINTK(KERN_INFO "smt_stat_counter\n");
+ switch (stat) {
+ case 0:
+ PRINTK(KERN_INFO "Ring operational change.\n");
+ break;
+ case 1:
+ PRINTK(KERN_INFO "Receive fifo overflow.\n");
+ smc->os.MacStat.rx_errors++;
+ break;
+ default:
+ PRINTK(KERN_INFO "Unknown status (%d).\n", stat);
+ break;
+ }
+} // smt_stat_counter
+
+
+/************************
+ *
+ * cfm_state_change
+ *
+ * Sets CFM state in custom statistics.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * c_state - Possible values are:
+ *
+ * EC0_OUT, EC1_IN, EC2_TRACE, EC3_LEAVE, EC4_PATH_TEST,
+ * EC5_INSERT, EC6_CHECK, EC7_DEINSERT
+ * Out
+ * Nothing.
+ *
+ ************************/
+void cfm_state_change(struct s_smc *smc, int c_state)
+{
+#ifdef DRIVERDEBUG
+ char *s;
+
+ switch (c_state) {
+ case SC0_ISOLATED:
+ s = "SC0_ISOLATED";
+ break;
+ case SC1_WRAP_A:
+ s = "SC1_WRAP_A";
+ break;
+ case SC2_WRAP_B:
+ s = "SC2_WRAP_B";
+ break;
+ case SC4_THRU_A:
+ s = "SC4_THRU_A";
+ break;
+ case SC5_THRU_B:
+ s = "SC5_THRU_B";
+ break;
+ case SC7_WRAP_S:
+ s = "SC7_WRAP_S";
+ break;
+ default:
+ s = "unknown";
+ break;
+ }
+ PRINTK(KERN_INFO "cfm_state_change: %s\n", s);
+#endif // DRIVERDEBUG
+} // cfm_state_change
+
+
+/************************
+ *
+ * ecm_state_change
+ *
+ * Sets ECM state in custom statistics.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * e_state - Possible values are:
+ *
+ * SC0_ISOLATED, SC1_WRAP_A (5), SC2_WRAP_B (6), SC4_THRU_A (12),
+ * SC5_THRU_B (7), SC7_WRAP_S (8)
+ * Out
+ * Nothing.
+ *
+ ************************/
+void ecm_state_change(struct s_smc *smc, int e_state)
+{
+#ifdef DRIVERDEBUG
+ char *s;
+
+ switch (e_state) {
+ case EC0_OUT:
+ s = "EC0_OUT";
+ break;
+ case EC1_IN:
+ s = "EC1_IN";
+ break;
+ case EC2_TRACE:
+ s = "EC2_TRACE";
+ break;
+ case EC3_LEAVE:
+ s = "EC3_LEAVE";
+ break;
+ case EC4_PATH_TEST:
+ s = "EC4_PATH_TEST";
+ break;
+ case EC5_INSERT:
+ s = "EC5_INSERT";
+ break;
+ case EC6_CHECK:
+ s = "EC6_CHECK";
+ break;
+ case EC7_DEINSERT:
+ s = "EC7_DEINSERT";
+ break;
+ default:
+ s = "unknown";
+ break;
+ }
+ PRINTK(KERN_INFO "ecm_state_change: %s\n", s);
+#endif //DRIVERDEBUG
+} // ecm_state_change
+
+
+/************************
+ *
+ * rmt_state_change
+ *
+ * Sets RMT state in custom statistics.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ *
+ * r_state - Possible values are:
+ *
+ * RM0_ISOLATED, RM1_NON_OP, RM2_RING_OP, RM3_DETECT,
+ * RM4_NON_OP_DUP, RM5_RING_OP_DUP, RM6_DIRECTED, RM7_TRACE
+ * Out
+ * Nothing.
+ *
+ ************************/
+void rmt_state_change(struct s_smc *smc, int r_state)
+{
+#ifdef DRIVERDEBUG
+ char *s;
+
+ switch (r_state) {
+ case RM0_ISOLATED:
+ s = "RM0_ISOLATED";
+ break;
+ case RM1_NON_OP:
+ s = "RM1_NON_OP - not operational";
+ break;
+ case RM2_RING_OP:
+ s = "RM2_RING_OP - ring operational";
+ break;
+ case RM3_DETECT:
+ s = "RM3_DETECT - detect dupl addresses";
+ break;
+ case RM4_NON_OP_DUP:
+ s = "RM4_NON_OP_DUP - dupl. addr detected";
+ break;
+ case RM5_RING_OP_DUP:
+ s = "RM5_RING_OP_DUP - ring oper. with dupl. addr";
+ break;
+ case RM6_DIRECTED:
+ s = "RM6_DIRECTED - sending directed beacons";
+ break;
+ case RM7_TRACE:
+ s = "RM7_TRACE - trace initiated";
+ break;
+ default:
+ s = "unknown";
+ break;
+ }
+ PRINTK(KERN_INFO "[rmt_state_change: %s]\n", s);
+#endif // DRIVERDEBUG
+} // rmt_state_change
+
+
+/************************
+ *
+ * drv_reset_indication
+ *
+ * This function is called by the SMT when it has detected a severe
+ * hardware problem. The driver should perform a reset on the adapter
+ * as soon as possible, but not from within this function.
+ * Args
+ * smc - A pointer to the SMT context struct.
+ * Out
+ * Nothing.
+ *
+ ************************/
+void drv_reset_indication(struct s_smc *smc)
+{
+ PRINTK(KERN_INFO "entering drv_reset_indication\n");
+
+ smc->os.ResetRequested = TRUE; // Set flag.
+
+} // drv_reset_indication
+
+
+
+//--------------- functions for use as a module ----------------
+
+#ifdef MODULE
+/************************
+ *
+ * Note now that module autoprobing is allowed under PCI. The
+ * IRQ lines will not be auto-detected; instead I'll rely on the BIOSes
+ * to "do the right thing".
+ *
+ ************************/
+#define LP(a) ((struct s_smc*)(a))
+static struct net_device *mdev = NULL;
+
+/************************
+ *
+ * init_module
+ *
+ * If compiled as a module, find
+ * adapters and initialize them.
+ *
+ ************************/
+int init_module(void)
+{
+ struct net_device *p;
+
+ PRINTK(KERN_INFO "FDDI init module\n");
+ if ((mdev = insert_device(NULL, skfp_probe)) == NULL)
+ return -ENOMEM;
+
+ for (p = mdev; p != NULL; p = LP(p->priv)->os.next_module) {
+ PRINTK(KERN_INFO "device to register: %s\n", p->name);
+ if (register_netdev(p) != 0) {
+ printk("skfddi init_module failed\n");
+ return -EIO;
+ }
+ }
+
+ PRINTK(KERN_INFO "+++++ exit with success +++++\n");
+ return 0;
+} // init_module
+
+/************************
+ *
+ * cleanup_module
+ *
+ * Release all resources claimed by this module.
+ *
+ ************************/
+void cleanup_module(void)
+{
+ PRINTK(KERN_INFO "cleanup_module\n");
+ while (mdev != NULL) {
+ mdev = unlink_modules(mdev);
+ }
+ return;
+} // cleanup_module
+
+
+/************************
+ *
+ * unlink_modules
+ *
+ * Unregister devices and release their memory.
+ *
+ ************************/
+static struct net_device *unlink_modules(struct net_device *p)
+{
+ struct net_device *next = NULL;
+
+ if (p->priv) { /* Private areas allocated? */
+ struct s_smc *lp = (struct s_smc *) p->priv;
+
+ next = lp->os.next_module;
+
+ if (lp->os.SharedMemAddr) {
+ kfree(lp->os.SharedMemAddr);
+ }
+ release_region(p->base_addr,
+ (lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0));
+ }
+ unregister_netdev(p);
+ printk("%s: unloaded\n", p->name);
+ kfree(p); /* Free the device structure */
+
+ return next;
+} // unlink_modules
+
+
+#endif /* MODULE */
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
new file mode 100644
index 000000000..ed8538958
--- /dev/null
+++ b/drivers/net/skfp/smt.c
@@ -0,0 +1,2225 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ;
+#endif
+
+extern const u_char canonical[256] ;
+
+/*
+ * FC in SMbuf
+ */
+#define m_fc(mb) ((mb)->sm_data[0])
+
+#define SMT_TID_MAGIC 0x1f0a7b3c
+
+#ifdef DEBUG
+static const char *const smt_type_name[] = {
+ "SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??",
+ "SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??",
+ "SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??",
+ "SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA"
+} ;
+
+static const char *const smt_class_name[] = {
+ "UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF",
+ "SRF","PMF_GET","PMF_SET","ESF"
+} ;
+#endif
+#define LAST_CLASS (SMT_PMF_SET)
+
+static const struct fddi_addr SMT_Unknown = {
+ 0,0,0x1f,0,0,0
+} ;
+
+/*
+ * external variables
+ */
+extern const struct fddi_addr fddi_broadcast ;
+
+/*
+ * external functions
+ */
+int pcm_status_twisted() ;
+void pcm_status_state() ;
+int pcm_status_type() ;
+
+extern SMbuf *smt_get_mbuf() ;
+
+#define EXPORT_PMF
+/*
+ * function prototypes
+ */
+u_long smt_get_tid() ;
+EXPORT_PMF SMbuf *smt_build_frame() ;
+EXPORT_PMF void *sm_to_para() ;
+#ifdef LITTLE_ENDIAN
+static int smt_swap_short() ;
+#endif
+static int mac_index() ;
+static int phy_index() ;
+static int mac_con_resource_index() ;
+static int phy_con_resource_index() ;
+EXPORT_PMF void smt_send_frame() ;
+EXPORT_PMF void smt_set_timestamp() ;
+static void smt_send_rdf() ;
+static void smt_send_nif() ;
+static void smt_send_ecf() ;
+static void smt_echo_test() ;
+static void smt_send_sif_config() ;
+static void smt_send_sif_operation() ;
+EXPORT_PMF void smt_swap_para() ;
+#ifdef LITTLE_ENDIAN
+static void smt_string_swap() ;
+#endif
+static void smt_add_frame_len() ;
+static void smt_fill_una() ;
+static void smt_fill_sde() ;
+static void smt_fill_state() ;
+static void smt_fill_timestamp() ;
+static void smt_fill_policy() ;
+static void smt_fill_latency() ;
+static void smt_fill_neighbor() ;
+static int smt_fill_path() ;
+static void smt_fill_mac_status() ;
+static void smt_fill_lem() ;
+static void smt_fill_version() ;
+static void smt_fill_fsc() ;
+static void smt_fill_mac_counter() ;
+static void smt_fill_mac_fnc() ;
+static void smt_fill_manufacturer() ;
+static void smt_fill_user() ;
+static void smt_fill_setcount() ;
+static void smt_fill_echo() ;
+int smt_check_para() ;
+
+void smt_clear_una_dna() ;
+static void smt_clear_old_una_dna() ;
+#ifdef CONCENTRATOR
+static int entity_to_index() ;
+#endif
+static void update_dac() ;
+static int div_ratio() ;
+#ifdef USE_CAN_ADDR
+void hwm_conv_can() ;
+#else
+#define hwm_conv_can(smc,data,len)
+#endif
+
+/*
+ * list of mandatory paras in frames
+ */
+static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ;
+
+/*
+ * init SMT agent
+ */
+void smt_agent_init(smc)
+struct s_smc *smc ;
+{
+ int i ;
+
+ /*
+ * get MAC address
+ */
+ smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ;
+
+ /*
+ * get OUI address from driver (bia == built-in-address)
+ */
+ smc->mib.fddiSMTStationId.sid_oem[0] = 0 ;
+ smc->mib.fddiSMTStationId.sid_oem[1] = 0 ;
+ driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
+ for (i = 0 ; i < 6 ; i ++) {
+ smc->mib.fddiSMTStationId.sid_node.a[i] =
+ canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+ }
+ smc->mib.fddiSMTManufacturerData[0] =
+ smc->mib.fddiSMTStationId.sid_node.a[0] ;
+ smc->mib.fddiSMTManufacturerData[1] =
+ smc->mib.fddiSMTStationId.sid_node.a[1] ;
+ smc->mib.fddiSMTManufacturerData[2] =
+ smc->mib.fddiSMTStationId.sid_node.a[2] ;
+ smc->sm.smt_tid = 0 ;
+ smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ;
+ smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
+#ifndef SLIM_SMT
+ smt_clear_una_dna(smc) ;
+ smt_clear_old_una_dna(smc) ;
+#endif
+ for (i = 0 ; i < SMT_MAX_TEST ; i++)
+ smc->sm.pend[i] = 0 ;
+ smc->sm.please_reconnect = 0 ;
+ smc->sm.uniq_ticks = 0 ;
+}
+
+/*
+ * SMT task
+ * forever
+ * delay 30 seconds
+ * send NIF
+ * check tvu & tvd
+ * end
+ */
+void smt_agent_task(smc)
+struct s_smc *smc ;
+{
+ smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
+ EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
+ DB_SMT("SMT agent task\n",0,0) ;
+}
+
+void smt_please_reconnect(smc,reconn_time)
+struct s_smc *smc ; /* Pointer to SMT context */
+int reconn_time ; /* Wait for reconnect time in seconds */
+{
+ /*
+ * The please reconnect variable is used as a timer.
+ * It is decremented each time smt_event is called.
+ * This happens every second or when smt_force_irq is called.
+ * Note: smt_force_irq () is called on some packet receives and
+ * when a multicast address is changed. Since nothing
+ * is received during the disconnect and the multicast
+ * address changes can be viewed as not very often and
+ * the timer runs out close to its given value
+ * (reconn_time).
+ */
+ smc->sm.please_reconnect = reconn_time ;
+}
+
+#ifndef SMT_REAL_TOKEN_CT
+void smt_emulate_token_ct(smc, mac_index)
+struct s_smc *smc;
+int mac_index;
+{
+ u_long count;
+ u_long time;
+
+
+ time = smt_get_time();
+ count = ((time - smc->sm.last_tok_time[mac_index]) *
+ 100)/TICKS_PER_SECOND;
+
+ /*
+ * Only when ring is up we will have a token count. The
+ * flag is unfortunatly a single instance value. This
+ * doesn't matter now, because we currently have only
+ * one MAC instance.
+ */
+ if (smc->hw.mac_ring_is_up){
+ smc->mib.m[mac_index].fddiMACToken_Ct += count;
+ }
+
+ /* Remember current time */
+ smc->sm.last_tok_time[mac_index] = time;
+
+}
+#endif
+
+/*ARGSUSED1*/
+void smt_event(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+ u_long time ;
+#ifndef SMT_REAL_TOKEN_CT
+ int i ;
+#endif
+
+
+ if (smc->sm.please_reconnect) {
+ smc->sm.please_reconnect -- ;
+ if (smc->sm.please_reconnect == 0) {
+ /* Counted down */
+ queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+ }
+ }
+
+ if (event == SM_FAST)
+ return ;
+
+ /*
+ * timer for periodic cleanup in driver
+ * reset and start the watchdog (FM2)
+ * ESS timer
+ * SBA timer
+ */
+ smt_timer_poll(smc) ;
+ smt_start_watchdog(smc) ;
+#ifndef SLIM_SMT
+#ifndef BOOT
+#ifdef ESS
+ ess_timer_poll(smc) ;
+#endif
+#endif
+#ifdef SBA
+ sba_timer_poll(smc) ;
+#endif
+
+ smt_srf_event(smc,0,0,0) ;
+
+#endif /* no SLIM_SMT */
+
+ time = smt_get_time() ;
+
+ if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) {
+ /*
+ * Use 8 sec. for the time intervall, it simplifies the
+ * LER estimation.
+ */
+ struct fddi_mib_m *mib ;
+ u_long upper ;
+ u_long lower ;
+ int cond ;
+ int port;
+ struct s_phy *phy ;
+ /*
+ * calculate LEM bit error rate
+ */
+ sm_lem_evaluate(smc) ;
+ smc->sm.smt_last_lem = time ;
+
+ /*
+ * check conditions
+ */
+#ifndef SLIM_SMT
+ mac_update_counter(smc) ;
+ mib = smc->mib.m ;
+ upper =
+ (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) +
+ (mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ;
+ lower =
+ (mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) +
+ (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ;
+ mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ;
+
+ cond =
+ ((!mib->fddiMACFrameErrorThreshold &&
+ mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) ||
+ (mib->fddiMACFrameErrorRatio >
+ mib->fddiMACFrameErrorThreshold)) ;
+
+ if (cond != mib->fddiMACFrameErrorFlag)
+ smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR,
+ INDEX_MAC,cond) ;
+
+ upper =
+ (mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ;
+ lower =
+ upper +
+ (mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ;
+ mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ;
+
+ cond =
+ ((!mib->fddiMACNotCopiedThreshold &&
+ mib->fddiMACNotCopied_Ct !=
+ mib->fddiMACOld_NotCopied_Ct)||
+ (mib->fddiMACNotCopiedRatio >
+ mib->fddiMACNotCopiedThreshold)) ;
+
+ if (cond != mib->fddiMACNotCopiedFlag)
+ smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED,
+ INDEX_MAC,cond) ;
+
+ /*
+ * set old values
+ */
+ mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ;
+ mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ;
+ mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ;
+ mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ;
+ mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ;
+
+ /*
+ * Check port EBError Condition
+ */
+ for (port = 0; port < NUMPHYS; port ++) {
+ phy = &smc->y[port] ;
+
+ if (!phy->mib->fddiPORTHardwarePresent) {
+ continue;
+ }
+
+ cond = (phy->mib->fddiPORTEBError_Ct -
+ phy->mib->fddiPORTOldEBError_Ct > 5) ;
+
+ /* If ratio is more than 5 in 8 seconds
+ * Set the condition.
+ */
+ smt_srf_event(smc,SMT_COND_PORT_EB_ERROR,
+ (int) (INDEX_PORT+ phy->np) ,cond) ;
+
+ /*
+ * set old values
+ */
+ phy->mib->fddiPORTOldEBError_Ct =
+ phy->mib->fddiPORTEBError_Ct ;
+ }
+
+#endif /* no SLIM_SMT */
+ }
+
+#ifndef SLIM_SMT
+
+ if (time - smc->sm.smt_last_notify >= (u_long)
+ (smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) {
+ /*
+ * we can either send an announcement or a request
+ * a request will trigger a reply so that we can update
+ * our dna
+ * note: same tid must be used until reply is received
+ */
+ if (!smc->sm.pend[SMT_TID_NIF])
+ smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ;
+ smt_send_nif(smc,&fddi_broadcast,FC_SMT_NSA,
+ smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ;
+ smc->sm.smt_last_notify = time ;
+ }
+
+ /*
+ * check timer
+ */
+ if (smc->sm.smt_tvu &&
+ time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) {
+ DB_SMT("SMT : UNA expired\n",0,0) ;
+ smc->sm.smt_tvu = 0 ;
+
+ if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr,
+ &SMT_Unknown)){
+ /* Do not update unknown address */
+ smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
+ smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+ }
+ smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
+ smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
+ /*
+ * Make sure the fddiMACUNDA_Flag = FALSE is
+ * included in the SRF so we don't generate
+ * a seperate SRF for the deassertion of this
+ * condition
+ */
+ update_dac(smc,0) ;
+ smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+ INDEX_MAC,0) ;
+ }
+ if (smc->sm.smt_tvd &&
+ time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) {
+ DB_SMT("SMT : DNA expired\n",0,0) ;
+ smc->sm.smt_tvd = 0 ;
+ if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr,
+ &SMT_Unknown)){
+ /* Do not update unknown address */
+ smc->mib.m[MAC0].fddiMACOldDownstreamNbr=
+ smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+ }
+ smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
+ smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+ INDEX_MAC,0) ;
+ }
+
+#endif /* no SLIM_SMT */
+
+#ifndef SMT_REAL_TOKEN_CT
+ /*
+ * Token counter emulation section. If hardware supports the token
+ * count, the token counter will be updated in mac_update_counter.
+ */
+ for (i = MAC0; i < NUMMACS; i++ ){
+ if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){
+ smt_emulate_token_ct( smc, i );
+ }
+ }
+#endif
+
+ smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
+ EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
+}
+
+static int div_ratio(upper,lower)
+u_long upper ;
+u_long lower ;
+{
+ if ((upper<<16L) < upper)
+ upper = 0xffff0000L ;
+ else
+ upper <<= 16L ;
+ if (!lower)
+ return(0) ;
+ return((int)(upper/lower)) ;
+}
+
+#ifndef SLIM_SMT
+
+/*
+ * receive packet handler
+ */
+void smt_received_pack(smc,mb,fs)
+struct s_smc *smc ;
+SMbuf *mb ;
+int fs ; /* frame status */
+{
+ struct smt_header *sm ;
+ int local ;
+
+ int illegal = 0 ;
+
+ switch (m_fc(mb)) {
+ case FC_SMT_INFO :
+ case FC_SMT_LAN_LOC :
+ case FC_SMT_LOC :
+ case FC_SMT_NSA :
+ break ;
+ default :
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+
+ smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ;
+ sm = smtod(mb,struct smt_header *) ;
+ local = ((fs & L_INDICATOR) != 0) ;
+ hwm_conv_can(smc,(char *)sm,12) ;
+
+ /* check destination address */
+ if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) {
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+#if 0 /* for DUP recognition, do NOT filter them */
+ /* ignore loop back packets */
+ if (is_my_addr(smc,&sm->smt_source) && !local) {
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+#endif
+
+ smt_swap_para(sm,(int) mb->sm_len,1) ;
+ DB_SMT("SMT : received packet [%s] at 0x%x\n",
+ smt_type_name[m_fc(mb) & 0xf],sm) ;
+ DB_SMT("SMT : version %d, class %s\n",sm->smt_version,
+ smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ;
+
+#ifdef SBA
+ /*
+ * check if NSA frame
+ */
+ if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF &&
+ (sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) {
+ smc->sba.sm = sm ;
+ sba(smc,NIF) ;
+ }
+#endif
+
+ /*
+ * ignore any packet with NSA and A-indicator set
+ */
+ if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) {
+ DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+
+ /*
+ * ignore frames with illegal length
+ */
+ if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) ||
+ ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) {
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+
+ /*
+ * check SMT version
+ */
+ switch (sm->smt_class) {
+ case SMT_NIF :
+ case SMT_SIF_CONFIG :
+ case SMT_SIF_OPER :
+ case SMT_ECF :
+ if (sm->smt_version != SMT_VID)
+ illegal = 1;
+ break ;
+ default :
+ if (sm->smt_version != SMT_VID_2)
+ illegal = 1;
+ break ;
+ }
+ if (illegal) {
+ DB_SMT("SMT : version = %d, dest = %s\n",
+ sm->smt_version,addr_to_string(&sm->smt_source)) ;
+ smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ;
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+ if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) ||
+ ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) {
+ DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ;
+ smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ;
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+ switch (sm->smt_class) {
+ case SMT_NIF :
+ if (smt_check_para(smc,sm,plist_nif)) {
+ DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ;
+ break ;
+ } ;
+ switch (sm->smt_type) {
+ case SMT_ANNOUNCE :
+ case SMT_REQUEST :
+ if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA
+ && is_broadcast(&sm->smt_dest)) {
+ struct smt_p_state *st ;
+
+ /* set my UNA */
+ if (!is_equal(
+ &smc->mib.m[MAC0].fddiMACUpstreamNbr,
+ &sm->smt_source)) {
+ DB_SMT("SMT : updated my UNA = %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ if (!is_equal(&smc->mib.m[MAC0].
+ fddiMACUpstreamNbr,&SMT_Unknown)){
+ /* Do not update unknown address */
+ smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
+ smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+ }
+
+ smc->mib.m[MAC0].fddiMACUpstreamNbr =
+ sm->smt_source ;
+ smt_srf_event(smc,
+ SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+ INDEX_MAC,0) ;
+ smt_echo_test(smc,0) ;
+ }
+ smc->sm.smt_tvu = smt_get_time() ;
+ st = (struct smt_p_state *)
+ sm_to_para(smc,sm,SMT_P_STATE) ;
+ if (st) {
+ smc->mib.m[MAC0].fddiMACUNDA_Flag =
+ (st->st_dupl_addr & SMT_ST_MY_DUPA) ?
+ TRUE : FALSE ;
+ update_dac(smc,1) ;
+ }
+ }
+ if ((sm->smt_type == SMT_REQUEST) &&
+ is_individual(&sm->smt_source) &&
+ ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) ||
+ (m_fc(mb) != FC_SMT_NSA))) {
+ DB_SMT("SMT : replying to NIF request %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ smt_send_nif(smc,&sm->smt_source,
+ FC_SMT_INFO,
+ sm->smt_tid,
+ SMT_REPLY,local) ;
+ }
+ break ;
+ case SMT_REPLY :
+ DB_SMT("SMT : received NIF response from %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ if (fs & A_INDICATOR) {
+ smc->sm.pend[SMT_TID_NIF] = 0 ;
+ DB_SMT("SMT : duplicate address\n",0,0) ;
+ smc->mib.m[MAC0].fddiMACDupAddressTest =
+ DA_FAILED ;
+ smc->r.dup_addr_test = DA_FAILED ;
+ queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+ smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ;
+ update_dac(smc,1) ;
+ break ;
+ }
+ if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) {
+ smc->sm.pend[SMT_TID_NIF] = 0 ;
+ /* set my DNA */
+ if (!is_equal(
+ &smc->mib.m[MAC0].fddiMACDownstreamNbr,
+ &sm->smt_source)) {
+ DB_SMT("SMT : updated my DNA\n",0,0) ;
+ if (!is_equal(&smc->mib.m[MAC0].
+ fddiMACDownstreamNbr, &SMT_Unknown)){
+ /* Do not update unknown address */
+ smc->mib.m[MAC0].fddiMACOldDownstreamNbr =
+ smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+ }
+
+ smc->mib.m[MAC0].fddiMACDownstreamNbr =
+ sm->smt_source ;
+ smt_srf_event(smc,
+ SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+ INDEX_MAC,0) ;
+ smt_echo_test(smc,1) ;
+ }
+ smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ;
+ update_dac(smc,1) ;
+ smc->sm.smt_tvd = smt_get_time() ;
+ smc->mib.m[MAC0].fddiMACDupAddressTest =
+ DA_PASSED ;
+ if (smc->r.dup_addr_test != DA_PASSED) {
+ smc->r.dup_addr_test = DA_PASSED ;
+ queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+ }
+ }
+ else if (sm->smt_tid ==
+ smc->sm.pend[SMT_TID_NIF_TEST]) {
+ DB_SMT("SMT : NIF test TID ok\n",0,0) ;
+ }
+ else {
+ DB_SMT("SMT : expected TID %lx, got %lx\n",
+ smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ;
+ }
+ break ;
+ default :
+ illegal = 2 ;
+ break ;
+ }
+ break ;
+ case SMT_SIF_CONFIG : /* station information */
+ if (sm->smt_type != SMT_REQUEST)
+ break ;
+ DB_SMT("SMT : replying to SIF Config request from %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ;
+ break ;
+ case SMT_SIF_OPER : /* station information */
+ if (sm->smt_type != SMT_REQUEST)
+ break ;
+ DB_SMT("SMT : replying to SIF Operation request from %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ;
+ break ;
+ case SMT_ECF : /* echo frame */
+ switch (sm->smt_type) {
+ case SMT_REPLY :
+ smc->mib.priv.fddiPRIVECF_Reply_Rx++ ;
+ DB_SMT("SMT: received ECF reply from %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+ if (sm_to_para(smc,sm,SMT_P_ECHODATA) == 0) {
+ DB_SMT("SMT: ECHODATA missing\n",0,0) ;
+ break ;
+ }
+ if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) {
+ DB_SMT("SMT : ECF test TID ok\n",0,0) ;
+ }
+ else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) {
+ DB_SMT("SMT : ECF test UNA ok\n",0,0) ;
+ }
+ else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) {
+ DB_SMT("SMT : ECF test DNA ok\n",0,0) ;
+ }
+ else {
+ DB_SMT("SMT : expected TID %lx, got %lx\n",
+ smc->sm.pend[SMT_TID_ECF],
+ sm->smt_tid) ;
+ }
+ break ;
+ case SMT_REQUEST :
+ smc->mib.priv.fddiPRIVECF_Req_Rx++ ;
+ {
+ if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) {
+ DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ;
+ smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,
+ local) ;
+ break ;
+ }
+ DB_SMT("SMT - sending ECF reply to %s\n",
+ addr_to_string(&sm->smt_source),0) ;
+
+ /* set destination addr. & reply */
+ sm->smt_dest = sm->smt_source ;
+ sm->smt_type = SMT_REPLY ;
+ dump_smt(smc,sm,"ECF REPLY") ;
+ smc->mib.priv.fddiPRIVECF_Reply_Tx++ ;
+ smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+ return ; /* DON'T free mbuf */
+ }
+ default :
+ illegal = 1 ;
+ break ;
+ }
+ break ;
+#ifndef BOOT
+ case SMT_RAF : /* resource allocation */
+#ifdef ESS
+ DB_ESSN(2,"ESS: RAF frame received\n",0,0) ;
+ fs = ess_raf_received_pack(smc,mb,sm,fs) ;
+#endif
+
+#ifdef SBA
+ DB_SBAN(2,"SBA: RAF frame received\n",0,0) ;
+ sba_raf_received_pack(smc,sm,fs) ;
+#endif
+ break ;
+ case SMT_RDF : /* request denied */
+ smc->mib.priv.fddiPRIVRDF_Rx++ ;
+ break ;
+ case SMT_ESF : /* extended service - not supported */
+ if (sm->smt_type == SMT_REQUEST) {
+ DB_SMT("SMT - received ESF, sending RDF\n",0,0) ;
+ smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
+ }
+ break ;
+ case SMT_PMF_GET :
+ case SMT_PMF_SET :
+ if (sm->smt_type != SMT_REQUEST)
+ break ;
+ /* update statistics */
+ if (sm->smt_class == SMT_PMF_GET)
+ smc->mib.priv.fddiPRIVPMF_Get_Rx++ ;
+ else
+ smc->mib.priv.fddiPRIVPMF_Set_Rx++ ;
+ /*
+ * ignore PMF SET with I/G set
+ */
+ if ((sm->smt_class == SMT_PMF_SET) &&
+ !is_individual(&sm->smt_dest)) {
+ DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ;
+ break ;
+ }
+ smt_pmf_received_pack(smc,mb, local) ;
+ break ;
+ case SMT_SRF :
+ dump_smt(smc,sm,"SRF received") ;
+ break ;
+ default :
+ if (sm->smt_type != SMT_REQUEST)
+ break ;
+ /*
+ * For frames with unknown class:
+ * we need to send a RDF frame according to 8.1.3.1.1,
+ * only if it is a REQUEST.
+ */
+ DB_SMT("SMT : class = %d, send RDF to %s\n",
+ sm->smt_class, addr_to_string(&sm->smt_source)) ;
+
+ smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
+ break ;
+#endif
+ }
+ if (illegal) {
+ DB_SMT("SMT: discarding illegal frame, reason = %d\n",
+ illegal,0) ;
+ }
+ smt_free_mbuf(smc,mb) ;
+}
+
+static void update_dac(smc,report)
+struct s_smc *smc ;
+int report ;
+{
+ int cond ;
+
+ cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag |
+ smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ;
+ if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond))
+ smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ;
+ else
+ smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ;
+}
+
+/*
+ * send SMT frame
+ * set source address
+ * set station ID
+ * send frame
+ */
+EXPORT_PMF void smt_send_frame(smc,mb,fc,local)
+struct s_smc *smc ;
+SMbuf *mb ; /* buffer to send */
+int fc ; /* FC value */
+int local ;
+{
+ struct smt_header *sm ;
+
+ if (!smc->r.sm_ma_avail && !local) {
+ smt_free_mbuf(smc,mb) ;
+ return ;
+ }
+ sm = smtod(mb,struct smt_header *) ;
+ sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
+ sm->smt_sid = smc->mib.fddiSMTStationId ;
+
+ smt_swap_para(sm,(int) mb->sm_len,0) ; /* swap para & header */
+ hwm_conv_can(smc,(char *)sm,12) ; /* convert SA and DA */
+ smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ;
+ smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ;
+}
+
+/*
+ * generate and send RDF
+ */
+static void smt_send_rdf(smc,rej,fc,reason,local)
+struct s_smc *smc ;
+SMbuf *rej ; /* mbuf of offending frame */
+int fc ; /* FC of denied frame */
+int reason ; /* reason code */
+int local ;
+{
+ SMbuf *mb ;
+ struct smt_header *sm ; /* header of offending frame */
+ struct smt_rdf *rdf ;
+ int len ;
+ int frame_len ;
+
+ sm = smtod(rej,struct smt_header *) ;
+ if (sm->smt_type != SMT_REQUEST)
+ return ;
+
+ DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n",
+ addr_to_string(&sm->smt_source),reason) ;
+
+
+ /*
+ * note: get framelength from MAC length, NOT from SMT header
+ * smt header length is included in sm_len
+ */
+ frame_len = rej->sm_len ;
+
+ if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf))))
+ return ;
+ rdf = smtod(mb,struct smt_rdf *) ;
+ rdf->smt.smt_tid = sm->smt_tid ; /* use TID from sm */
+ rdf->smt.smt_dest = sm->smt_source ; /* set dest = source */
+
+ /* set P12 */
+ rdf->reason.para.p_type = SMT_P_REASON ;
+ rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ;
+ rdf->reason.rdf_reason = reason ;
+
+ /* set P14 */
+ rdf->version.para.p_type = SMT_P_VERSION ;
+ rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ;
+ rdf->version.v_pad = 0 ;
+ rdf->version.v_n = 1 ;
+ rdf->version.v_index = 1 ;
+ rdf->version.v_version[0] = SMT_VID_2 ;
+ rdf->version.v_pad2 = 0 ;
+
+ /* set P13 */
+ if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) +
+ 2*sizeof(struct smt_header))
+ len = frame_len ;
+ else
+ len = SMT_MAX_INFO_LEN - sizeof(*rdf) +
+ 2*sizeof(struct smt_header) ;
+ /* make length multiple of 4 */
+ len &= ~3 ;
+ rdf->refused.para.p_type = SMT_P_REFUSED ;
+ /* length of para is smt_frame + ref_fc */
+ rdf->refused.para.p_len = len + 4 ;
+ rdf->refused.ref_fc = fc ;
+
+ /* swap it back */
+ smt_swap_para(sm,frame_len,0) ;
+
+ memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ;
+
+ len -= sizeof(struct smt_header) ;
+ mb->sm_len += len ;
+ rdf->smt.smt_len += len ;
+
+ dump_smt(smc,(struct smt_header *)rdf,"RDF") ;
+ smc->mib.priv.fddiPRIVRDF_Tx++ ;
+ smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * generate and send NIF
+ */
+static void smt_send_nif(smc,dest,fc,tid,type,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ; /* dest address */
+int fc ; /* frame control */
+u_long tid ; /* transaction id */
+int type ; /* frame type */
+int local ;
+{
+ struct smt_nif *nif ;
+ SMbuf *mb ;
+
+ if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif))))
+ return ;
+ nif = smtod(mb, struct smt_nif *) ;
+ smt_fill_una(smc,&nif->una) ; /* set UNA */
+ smt_fill_sde(smc,&nif->sde) ; /* set station descriptor */
+ smt_fill_state(smc,&nif->state) ; /* set state information */
+#ifdef SMT6_10
+ smt_fill_fsc(smc,&nif->fsc) ; /* set frame status cap. */
+#endif
+ nif->smt.smt_dest = *dest ; /* destination address */
+ nif->smt.smt_tid = tid ; /* transaction ID */
+ dump_smt(smc,(struct smt_header *)nif,"NIF") ;
+ smt_send_frame(smc,mb,fc,local) ;
+}
+
+#ifdef DEBUG
+/*
+ * send NIF request (test purpose)
+ */
+static void smt_send_nif_request(smc,dest)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+{
+ smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ;
+ smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST],
+ SMT_REQUEST,0) ;
+}
+
+/*
+ * send ECF request (test purpose)
+ */
+static void smt_send_ecf_request(smc,dest,len)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+int len ;
+{
+ smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ;
+ smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF],
+ SMT_REQUEST,len) ;
+}
+#endif
+
+/*
+ * echo test
+ */
+static void smt_echo_test(smc,dna)
+struct s_smc *smc ;
+int dna ;
+{
+ u_long tid ;
+
+ smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] =
+ tid = smt_get_tid(smc) ;
+ smt_send_ecf(smc, dna ?
+ &smc->mib.m[MAC0].fddiMACDownstreamNbr :
+ &smc->mib.m[MAC0].fddiMACUpstreamNbr,
+ FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ;
+}
+
+/*
+ * generate and send ECF
+ */
+static void smt_send_ecf(smc,dest,fc,tid,type,len)
+struct s_smc *smc ;
+struct fddi_addr *dest ; /* dest address */
+int fc ; /* frame control */
+u_long tid ; /* transaction id */
+int type ; /* frame type */
+int len ; /* frame length */
+{
+ struct smt_ecf *ecf ;
+ SMbuf *mb ;
+
+ if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len)))
+ return ;
+ ecf = smtod(mb, struct smt_ecf *) ;
+
+ smt_fill_echo(smc,&ecf->ec_echo,tid,len) ; /* set ECHO */
+ ecf->smt.smt_dest = *dest ; /* destination address */
+ ecf->smt.smt_tid = tid ; /* transaction ID */
+ smc->mib.priv.fddiPRIVECF_Req_Tx++ ;
+ smt_send_frame(smc,mb,fc,0) ;
+}
+
+/*
+ * generate and send SIF config response
+ */
+
+static void smt_send_sif_config(smc,dest,tid,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ; /* dest address */
+u_long tid ; /* transaction id */
+int local ;
+{
+ struct smt_sif_config *sif ;
+ SMbuf *mb ;
+ int len ;
+ if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY,
+ SIZEOF_SMT_SIF_CONFIG)))
+ return ;
+
+ sif = smtod(mb, struct smt_sif_config *) ;
+ smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */
+ smt_fill_sde(smc,&sif->sde) ; /* set station descriptor */
+ smt_fill_version(smc,&sif->version) ; /* set version information */
+ smt_fill_state(smc,&sif->state) ; /* set state information */
+ smt_fill_policy(smc,&sif->policy) ; /* set station policy */
+ smt_fill_latency(smc,&sif->latency); /* set station latency */
+ smt_fill_neighbor(smc,&sif->neighbor); /* set station neighbor */
+ smt_fill_setcount(smc,&sif->setcount) ; /* set count */
+ len = smt_fill_path(smc,&sif->path); /* set station path descriptor*/
+ sif->smt.smt_dest = *dest ; /* destination address */
+ sif->smt.smt_tid = tid ; /* transaction ID */
+ smt_add_frame_len(mb,len) ; /* adjust length fields */
+ dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ;
+ smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * generate and send SIF operation response
+ */
+
+static void smt_send_sif_operation(smc,dest,tid,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ; /* dest address */
+u_long tid ; /* transaction id */
+int local ;
+{
+ struct smt_sif_operation *sif ;
+ SMbuf *mb ;
+ int ports ;
+ int i ;
+
+ ports = NUMPHYS ;
+#ifndef CONCENTRATOR
+ if (smc->s.sas == SMT_SAS)
+ ports = 1 ;
+#endif
+
+ if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY,
+ SIZEOF_SMT_SIF_OPERATION+ports*sizeof(struct smt_p_lem))))
+ return ;
+ sif = smtod(mb, struct smt_sif_operation *) ;
+ smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */
+ smt_fill_mac_status(smc,&sif->status) ; /* set mac status */
+ smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */
+ smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */
+ smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */
+ smt_fill_user(smc,&sif->user) ; /* set user field */
+ smt_fill_setcount(smc,&sif->setcount) ; /* set count */
+ /*
+ * set link error mon information
+ */
+ if (ports == 1) {
+ smt_fill_lem(smc,sif->lem,PS) ;
+ }
+ else {
+ for (i = 0 ; i < ports ; i++) {
+ smt_fill_lem(smc,&sif->lem[i],i) ;
+ }
+ }
+
+ sif->smt.smt_dest = *dest ; /* destination address */
+ sif->smt.smt_tid = tid ; /* transaction ID */
+ dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ;
+ smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * get and initialize SMT frame
+ */
+EXPORT_PMF SMbuf *smt_build_frame(smc,class,type,length)
+struct s_smc *smc ;
+int class ;
+int type ;
+int length ;
+{
+ SMbuf *mb ;
+ struct smt_header *smt ;
+
+#if 0
+ if (!smc->r.sm_ma_avail) {
+ return(0) ;
+ }
+#endif
+ if (!(mb = smt_get_mbuf(smc)))
+ return(mb) ;
+
+ mb->sm_len = length ;
+ smt = smtod(mb, struct smt_header *) ;
+ smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */
+ smt->smt_class = class ;
+ smt->smt_type = type ;
+ switch (class) {
+ case SMT_NIF :
+ case SMT_SIF_CONFIG :
+ case SMT_SIF_OPER :
+ case SMT_ECF :
+ smt->smt_version = SMT_VID ;
+ break ;
+ default :
+ smt->smt_version = SMT_VID_2 ;
+ break ;
+ }
+ smt->smt_tid = smt_get_tid(smc) ; /* set transaction ID */
+ smt->smt_pad = 0 ;
+ smt->smt_len = length - sizeof(struct smt_header) ;
+ return(mb) ;
+}
+
+static void smt_add_frame_len(mb,len)
+SMbuf *mb ;
+int len ;
+{
+ struct smt_header *smt ;
+
+ smt = smtod(mb, struct smt_header *) ;
+ smt->smt_len += len ;
+ mb->sm_len += len ;
+}
+
+
+
+/*
+ * fill values in UNA parameter
+ */
+static void smt_fill_una(smc,una)
+struct s_smc *smc ;
+struct smt_p_una *una ;
+{
+ SMTSETPARA(una,SMT_P_UNA) ;
+ una->una_pad = 0 ;
+ una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+}
+
+/*
+ * fill values in SDE parameter
+ */
+static void smt_fill_sde(smc,sde)
+struct s_smc *smc ;
+struct smt_p_sde *sde ;
+{
+ SMTSETPARA(sde,SMT_P_SDE) ;
+ sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ;
+ sde->sde_master = smc->mib.fddiSMTMaster_Ct ;
+ sde->sde_mac_count = NUMMACS ; /* only 1 MAC */
+#ifdef CONCENTRATOR
+ sde->sde_type = SMT_SDE_CONCENTRATOR ;
+#else
+ sde->sde_type = SMT_SDE_STATION ;
+#endif
+}
+
+/*
+ * fill in values in station state parameter
+ */
+static void smt_fill_state(smc,state)
+struct s_smc *smc ;
+struct smt_p_state *state ;
+{
+ int top ;
+ int twist ;
+
+ SMTSETPARA(state,SMT_P_STATE) ;
+ state->st_pad = 0 ;
+
+ /* determine topology */
+ top = 0 ;
+ if (smc->mib.fddiSMTPeerWrapFlag) {
+ top |= SMT_ST_WRAPPED ; /* state wrapped */
+ }
+#ifdef CONCENTRATOR
+ if (cfm_status_unattached(smc)) {
+ top |= SMT_ST_UNATTACHED ; /* unattached concentrator */
+ }
+#endif
+ if ((twist = pcm_status_twisted(smc)) & 1) {
+ top |= SMT_ST_TWISTED_A ; /* twisted cable */
+ }
+ if (twist & 2) {
+ top |= SMT_ST_TWISTED_B ; /* twisted cable */
+ }
+#ifdef OPT_SRF
+ top |= SMT_ST_SRF ;
+#endif
+ if (pcm_rooted_station(smc))
+ top |= SMT_ST_ROOTED_S ;
+ if (smc->mib.a[0].fddiPATHSbaPayload != 0)
+ top |= SMT_ST_SYNC_SERVICE ;
+ state->st_topology = top ;
+ state->st_dupl_addr =
+ ((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) |
+ (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ;
+}
+
+/*
+ * fill values in timestamp parameter
+ */
+static void smt_fill_timestamp(smc,ts)
+struct s_smc *smc ;
+struct smt_p_timestamp *ts ;
+{
+
+ SMTSETPARA(ts,SMT_P_TIMESTAMP) ;
+ smt_set_timestamp(smc,ts->ts_time) ;
+}
+
+EXPORT_PMF void smt_set_timestamp(smc,p)
+struct s_smc *smc ;
+u_char *p ;
+{
+ u_long time ;
+ u_long utime ;
+
+ /*
+ * timestamp is 64 bits long ; resolution is 80 nS
+ * our clock resolution is 10mS
+ * 10mS/80ns = 125000 ~ 2^17 = 131072
+ */
+ utime = smt_get_time() ;
+ time = utime * 100 ;
+ time /= TICKS_PER_SECOND ;
+ p[0] = 0 ;
+ p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ;
+ p[2] = (u_char)(time>>(8+8+8-1)) ;
+ p[3] = (u_char)(time>>(8+8-1)) ;
+ p[4] = (u_char)(time>>(8-1)) ;
+ p[5] = (u_char)(time<<1) ;
+ p[6] = (u_char)(smc->sm.uniq_ticks>>8) ;
+ p[7] = (u_char)smc->sm.uniq_ticks ;
+ /*
+ * make sure we don't wrap: restart whenever the upper digits change
+ */
+ if (utime != smc->sm.uniq_time) {
+ smc->sm.uniq_ticks = 0 ;
+ }
+ smc->sm.uniq_ticks++ ;
+ smc->sm.uniq_time = utime ;
+}
+
+/*
+ * fill values in station policy parameter
+ */
+static void smt_fill_policy(smc,policy)
+struct s_smc *smc ;
+struct smt_p_policy *policy ;
+{
+ int i ;
+ u_char *map ;
+ u_short in ;
+ u_short out ;
+
+ /*
+ * MIB para 101b (fddiSMTConnectionPolicy) coding
+ * is different from 0005 coding
+ */
+ static u_char ansi_weirdness[16] = {
+ 0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15
+ } ;
+ SMTSETPARA(policy,SMT_P_POLICY) ;
+
+ out = 0 ;
+ in = smc->mib.fddiSMTConnectionPolicy ;
+ for (i = 0, map = ansi_weirdness ; i < 16 ; i++) {
+ if (in & 1)
+ out |= (1<<*map) ;
+ in >>= 1 ;
+ map++ ;
+ }
+ policy->pl_config = smc->mib.fddiSMTConfigPolicy ;
+ policy->pl_connect = out ;
+}
+
+/*
+ * fill values in latency equivalent parameter
+ */
+static void smt_fill_latency(smc,latency)
+struct s_smc *smc ;
+struct smt_p_latency *latency ;
+{
+ SMTSETPARA(latency,SMT_P_LATENCY) ;
+
+ latency->lt_phyout_idx1 = phy_index(smc,0) ;
+ latency->lt_latency1 = 10 ; /* in octets (byte clock) */
+ /*
+ * note: latency has two phy entries by definition
+ * for a SAS, the 2nd one is null
+ */
+ if (smc->s.sas == SMT_DAS) {
+ latency->lt_phyout_idx2 = phy_index(smc,1) ;
+ latency->lt_latency2 = 10 ; /* in octets (byte clock) */
+ }
+ else {
+ latency->lt_phyout_idx2 = 0 ;
+ latency->lt_latency2 = 0 ;
+ }
+}
+
+/*
+ * fill values in MAC neighbors parameter
+ */
+static void smt_fill_neighbor(smc,neighbor)
+struct s_smc *smc ;
+struct smt_p_neighbor *neighbor ;
+{
+ SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ;
+
+ neighbor->nb_mib_index = INDEX_MAC ;
+ neighbor->nb_mac_index = mac_index(smc,1) ;
+ neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+ neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+}
+
+/*
+ * fill values in path descriptor
+ */
+#ifdef CONCENTRATOR
+#define ALLPHYS NUMPHYS
+#else
+#define ALLPHYS ((smc->s.sas == SMT_SAS) ? 1 : 2)
+#endif
+
+static int smt_fill_path(smc,path)
+struct s_smc *smc ;
+struct smt_p_path *path ;
+{
+ SK_LOC_DECL(int,type) ;
+ SK_LOC_DECL(int,state) ;
+ SK_LOC_DECL(int,remote) ;
+ SK_LOC_DECL(int,mac) ;
+ int len ;
+ int p ;
+ int physp ;
+ struct smt_phy_rec *phy ;
+ struct smt_mac_rec *pd_mac ;
+
+ len = PARA_LEN +
+ sizeof(struct smt_mac_rec) * NUMMACS +
+ sizeof(struct smt_phy_rec) * ALLPHYS ;
+ path->para.p_type = SMT_P_PATH ;
+ path->para.p_len = len - PARA_LEN ;
+
+ /* PHYs */
+ for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) {
+ physp = p ;
+#ifndef CONCENTRATOR
+ if (smc->s.sas == SMT_SAS)
+ physp = PS ;
+#endif
+ pcm_status_state(smc,physp,&type,&state,&remote,&mac) ;
+#ifdef LITTLE_ENDIAN
+ phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ;
+#else
+ phy->phy_mib_index = p+INDEX_PORT ;
+#endif
+ phy->phy_type = type ;
+ phy->phy_connect_state = state ;
+ phy->phy_remote_type = remote ;
+ phy->phy_remote_mac = mac ;
+ phy->phy_resource_idx = phy_con_resource_index(smc,p) ;
+ }
+
+ /* MAC */
+ pd_mac = (struct smt_mac_rec *) phy ;
+ pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ;
+ pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ;
+ return(len) ;
+}
+
+/*
+ * fill values in mac status
+ */
+static void smt_fill_mac_status(smc,st)
+struct s_smc *smc ;
+struct smt_p_mac_status *st ;
+{
+ SMTSETPARA(st,SMT_P_MAC_STATUS) ;
+
+ st->st_mib_index = INDEX_MAC ;
+ st->st_mac_index = mac_index(smc,1) ;
+
+ mac_update_counter(smc) ;
+ /*
+ * timer values are represented in SMT as 2's complement numbers
+ * units : internal : 2's complement BCLK
+ */
+ st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ;
+ st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ;
+ st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ;
+ st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ;
+ st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ;
+
+ st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+ st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ;
+ st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ;
+ st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ;
+}
+
+/*
+ * fill values in LEM status
+ */
+
+static void smt_fill_lem(smc,lem,phy)
+struct s_smc *smc ;
+struct smt_p_lem *lem ;
+int phy ;
+{
+ struct fddi_mib_p *mib ;
+
+ mib = smc->y[phy].mib ;
+
+ SMTSETPARA(lem,SMT_P_LEM) ;
+ lem->lem_mib_index = phy+INDEX_PORT ;
+ lem->lem_phy_index = phy_index(smc,phy) ;
+ lem->lem_pad2 = 0 ;
+ lem->lem_cutoff = mib->fddiPORTLer_Cutoff ;
+ lem->lem_alarm = mib->fddiPORTLer_Alarm ;
+ /* long term bit error rate */
+ lem->lem_estimate = mib->fddiPORTLer_Estimate ;
+ /* # of rejected connections */
+ lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ;
+ lem->lem_ct = mib->fddiPORTLem_Ct ; /* total number of errors */
+}
+
+/*
+ * fill version parameter
+ */
+static void smt_fill_version(smc,vers)
+struct s_smc *smc ;
+struct smt_p_version *vers ;
+{
+ SK_UNUSED(smc) ;
+ SMTSETPARA(vers,SMT_P_VERSION) ;
+ vers->v_pad = 0 ;
+ vers->v_n = 1 ; /* one version is enough .. */
+ vers->v_index = 1 ;
+ vers->v_version[0] = SMT_VID_2 ;
+ vers->v_pad2 = 0 ;
+}
+
+#ifdef SMT6_10
+/*
+ * fill frame status capabilities
+ */
+/*
+ * note: this para 200B is NOT in swap table, because it's also set in
+ * PMF add_para
+ */
+static void smt_fill_fsc(smc,fsc)
+struct s_smc *smc ;
+struct smt_p_fsc *fsc ;
+{
+ SK_UNUSED(smc) ;
+ SMTSETPARA(fsc,SMT_P_FSC) ;
+ fsc->fsc_pad0 = 0 ;
+ fsc->fsc_mac_index = INDEX_MAC ; /* this is MIB ; MIB is NOT
+ * mac_index ()i !
+ */
+ fsc->fsc_pad1 = 0 ;
+ fsc->fsc_value = FSC_TYPE0 ; /* "normal" node */
+#ifdef LITTLE_ENDIAN
+ fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ;
+ fsc->fsc_value = smt_swap_short(FSC_TYPE0) ;
+#endif
+}
+#endif
+
+/*
+ * fill mac counter field
+ */
+static void smt_fill_mac_counter(smc,mc)
+struct s_smc *smc ;
+struct smt_p_mac_counter *mc ;
+{
+ SMTSETPARA(mc,SMT_P_MAC_COUNTER) ;
+ mc->mc_mib_index = INDEX_MAC ;
+ mc->mc_index = mac_index(smc,1) ;
+ mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ;
+ mc->mc_transmit_ct = smc->mib.m[MAC0].fddiMACTransmit_Ct ;
+}
+
+/*
+ * fill mac frame not copied counter
+ */
+static void smt_fill_mac_fnc(smc,fnc)
+struct s_smc *smc ;
+struct smt_p_mac_fnc *fnc ;
+{
+ SMTSETPARA(fnc,SMT_P_MAC_FNC) ;
+ fnc->nc_mib_index = INDEX_MAC ;
+ fnc->nc_index = mac_index(smc,1) ;
+ fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ;
+}
+
+
+/*
+ * fill manufacturer field
+ */
+static void smt_fill_manufacturer(smc,man)
+struct s_smc *smc ;
+struct smp_p_manufacturer *man ;
+{
+ SMTSETPARA(man,SMT_P_MANUFACTURER) ;
+ memcpy((char *) man->mf_data,
+ (char *) smc->mib.fddiSMTManufacturerData,
+ sizeof(man->mf_data)) ;
+}
+
+/*
+ * fill user field
+ */
+static void smt_fill_user(smc,user)
+struct s_smc *smc ;
+struct smp_p_user *user ;
+{
+ SMTSETPARA(user,SMT_P_USER) ;
+ memcpy((char *) user->us_data,
+ (char *) smc->mib.fddiSMTUserData,
+ sizeof(user->us_data)) ;
+}
+
+
+
+/*
+ * fill set count
+ */
+static void smt_fill_setcount(smc,setcount)
+struct s_smc *smc ;
+struct smt_p_setcount *setcount ;
+{
+ SK_UNUSED(smc) ;
+ SMTSETPARA(setcount,SMT_P_SETCOUNT) ;
+ setcount->count = smc->mib.fddiSMTSetCount.count ;
+ memcpy((char *)setcount->timestamp,
+ (char *)smc->mib.fddiSMTSetCount.timestamp,8) ;
+}
+
+/*
+ * fill echo data
+ */
+static void smt_fill_echo(smc,echo,seed,len)
+struct s_smc *smc ;
+struct smt_p_echo *echo ;
+u_long seed ;
+int len ;
+{
+
+ u_char *p ;
+
+ SK_UNUSED(smc) ;
+ SMTSETPARA(echo,SMT_P_ECHODATA) ;
+ echo->para.p_len = len ;
+ for (p = echo->ec_data ; len ; len--) {
+ *p++ = (u_char) seed ;
+ seed += 13 ;
+ }
+}
+
+/*
+ * clear DNA and UNA
+ * called from CFM if configuration changes
+ */
+void smt_clear_una_dna(smc)
+struct s_smc *smc ;
+{
+ smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
+ smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
+}
+
+static void smt_clear_old_una_dna(smc)
+struct s_smc *smc ;
+{
+ smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ;
+ smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ;
+}
+
+u_long smt_get_tid(smc)
+struct s_smc *smc ;
+{
+ u_long tid ;
+ while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0)
+ ;
+ return(tid & 0x3fffffffL) ;
+}
+
+
+/*
+ * table of parameter lengths
+ */
+static const struct smt_pdef {
+ int ptype ;
+ int plen ;
+ const char *pswap ;
+} smt_pdef[] = {
+ { SMT_P_UNA, sizeof(struct smt_p_una) ,
+ SWAP_SMT_P_UNA } ,
+ { SMT_P_SDE, sizeof(struct smt_p_sde) ,
+ SWAP_SMT_P_SDE } ,
+ { SMT_P_STATE, sizeof(struct smt_p_state) ,
+ SWAP_SMT_P_STATE } ,
+ { SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) ,
+ SWAP_SMT_P_TIMESTAMP } ,
+ { SMT_P_POLICY, sizeof(struct smt_p_policy) ,
+ SWAP_SMT_P_POLICY } ,
+ { SMT_P_LATENCY, sizeof(struct smt_p_latency) ,
+ SWAP_SMT_P_LATENCY } ,
+ { SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) ,
+ SWAP_SMT_P_NEIGHBORS } ,
+ { SMT_P_PATH, sizeof(struct smt_p_path) ,
+ SWAP_SMT_P_PATH } ,
+ { SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) ,
+ SWAP_SMT_P_MAC_STATUS } ,
+ { SMT_P_LEM, sizeof(struct smt_p_lem) ,
+ SWAP_SMT_P_LEM } ,
+ { SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) ,
+ SWAP_SMT_P_MAC_COUNTER } ,
+ { SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) ,
+ SWAP_SMT_P_MAC_FNC } ,
+ { SMT_P_PRIORITY,sizeof(struct smt_p_priority) ,
+ SWAP_SMT_P_PRIORITY } ,
+ { SMT_P_EB,sizeof(struct smt_p_eb) ,
+ SWAP_SMT_P_EB } ,
+ { SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) ,
+ SWAP_SMT_P_MANUFACTURER } ,
+ { SMT_P_REASON, sizeof(struct smt_p_reason) ,
+ SWAP_SMT_P_REASON } ,
+ { SMT_P_REFUSED, sizeof(struct smt_p_refused) ,
+ SWAP_SMT_P_REFUSED } ,
+ { SMT_P_VERSION, sizeof(struct smt_p_version) ,
+ SWAP_SMT_P_VERSION } ,
+#ifdef ESS
+ { SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } ,
+ { SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } ,
+ { SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } ,
+ { SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } ,
+ { SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } ,
+ { SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } ,
+ { SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } ,
+ { SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } ,
+ { SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } ,
+#endif
+#if 0
+ { SMT_P_FSC, sizeof(struct smt_p_fsc) ,
+ SWAP_SMT_P_FSC } ,
+#endif
+
+ { SMT_P_SETCOUNT,0, SWAP_SMT_P_SETCOUNT } ,
+ { SMT_P1048, 0, SWAP_SMT_P1048 } ,
+ { SMT_P208C, 0, SWAP_SMT_P208C } ,
+ { SMT_P208D, 0, SWAP_SMT_P208D } ,
+ { SMT_P208E, 0, SWAP_SMT_P208E } ,
+ { SMT_P208F, 0, SWAP_SMT_P208F } ,
+ { SMT_P2090, 0, SWAP_SMT_P2090 } ,
+#ifdef ESS
+ { SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } ,
+ { SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } ,
+ { SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } ,
+#endif
+ { SMT_P4050, 0, SWAP_SMT_P4050 } ,
+ { SMT_P4051, 0, SWAP_SMT_P4051 } ,
+ { SMT_P4052, 0, SWAP_SMT_P4052 } ,
+ { SMT_P4053, 0, SWAP_SMT_P4053 } ,
+} ;
+
+#define N_SMT_PLEN (sizeof(smt_pdef)/sizeof(smt_pdef[0]))
+
+int smt_check_para(smc,sm,list)
+struct s_smc *smc ;
+struct smt_header *sm ;
+const u_short list[] ;
+{
+ const u_short *p = list ;
+ while (*p) {
+ if (!sm_to_para(smc,sm,(int) *p)) {
+ DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0);
+ return(-1) ;
+ }
+ p++ ;
+ }
+ return(0) ;
+}
+
+EXPORT_PMF void *sm_to_para(smc,sm,para)
+struct s_smc *smc ;
+struct smt_header *sm ;
+int para ;
+{
+ char *p ;
+ int len ;
+ int plen ;
+ void *found = 0 ;
+
+ SK_UNUSED(smc) ;
+
+ len = sm->smt_len ;
+ p = (char *)(sm+1) ; /* pointer to info */
+ while (len > 0 ) {
+ if (((struct smt_para *)p)->p_type == para)
+ found = (void *) p ;
+ plen = ((struct smt_para *)p)->p_len + PARA_LEN ;
+ p += plen ;
+ len -= plen ;
+ if (len < 0) {
+ DB_SMT("SMT : sm_to_para - length error %d\n",plen,0) ;
+ return(0) ;
+ }
+ if ((plen & 3) && (para != SMT_P_ECHODATA)) {
+ DB_SMT("SMT : sm_to_para - odd length %d\n",plen,0) ;
+ return(0) ;
+ }
+ if (found)
+ return(found) ;
+ }
+ return(0) ;
+}
+
+int is_my_addr(smc,addr)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+{
+ return(*(short *)(&addr->a[0]) ==
+ *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0])
+ && *(short *)(&addr->a[2]) ==
+ *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2])
+ && *(short *)(&addr->a[4]) ==
+ *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ;
+}
+
+int is_zero(addr)
+struct fddi_addr *addr ;
+{
+ return(*(short *)(&addr->a[0]) == 0 &&
+ *(short *)(&addr->a[2]) == 0 &&
+ *(short *)(&addr->a[4]) == 0 ) ;
+}
+
+int is_broadcast(addr)
+struct fddi_addr *addr ;
+{
+ return(*(u_short *)(&addr->a[0]) == 0xffff &&
+ *(u_short *)(&addr->a[2]) == 0xffff &&
+ *(u_short *)(&addr->a[4]) == 0xffff ) ;
+}
+
+int is_individual(addr)
+struct fddi_addr *addr ;
+{
+ return(!(addr->a[0] & GROUP_ADDR)) ;
+}
+
+int is_equal(addr1,addr2)
+struct fddi_addr *addr1 ;
+struct fddi_addr *addr2 ;
+{
+ return(*(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) &&
+ *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) &&
+ *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]) ) ;
+}
+
+
+#if 0
+/*
+ * send ANTC data test frame
+ */
+void fddi_send_antc(smc,dest)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+{
+ SK_UNUSED(smc) ;
+ SK_UNUSED(dest) ;
+#if 0
+ SMbuf *mb ;
+ struct smt_header *smt ;
+ int i ;
+ char *p ;
+
+ mb = smt_get_mbuf() ;
+ mb->sm_len = 3000+12 ;
+ p = smtod(mb, char *) + 12 ;
+ for (i = 0 ; i < 3000 ; i++)
+ *p++ = 1 << (i&7) ;
+
+ smt = smtod(mb, struct smt_header *) ;
+ smt->smt_dest = *dest ;
+ smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
+ smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ;
+#endif
+}
+#endif
+
+#ifdef DEBUG
+#define hextoasc(x) "0123456789abcdef"[x]
+
+char *addr_to_string(addr)
+struct fddi_addr *addr ;
+{
+ int i ;
+ static char string[6*3] = "****" ;
+
+ for (i = 0 ; i < 6 ; i++) {
+ string[i*3] = hextoasc((addr->a[i]>>4)&0xf) ;
+ string[i*3+1] = hextoasc((addr->a[i])&0xf) ;
+ string[i*3+2] = ':' ;
+ }
+ string[5*3+2] = 0 ;
+ return(string) ;
+}
+#endif
+
+#ifdef AM29K
+smt_ifconfig(argc,argv)
+int argc ;
+char *argv[] ;
+{
+ if (argc >= 2 && !strcmp(argv[0],"opt_bypass") &&
+ !strcmp(argv[1],"yes")) {
+ smc->mib.fddiSMTBypassPresent = 1 ;
+ return(0) ;
+ }
+ return(amdfddi_config(0,argc,argv)) ;
+}
+#endif
+
+/*
+ * return static mac index
+ */
+static int mac_index(smc,mac)
+struct s_smc *smc ;
+int mac ;
+{
+ SK_UNUSED(mac) ;
+#ifdef CONCENTRATOR
+ SK_UNUSED(smc) ;
+ return(NUMPHYS+1) ;
+#else
+ return((smc->s.sas == SMT_SAS) ? 2 : 3) ;
+#endif
+}
+
+/*
+ * return static phy index
+ */
+static int phy_index(smc,phy)
+struct s_smc *smc ;
+int phy ;
+{
+ SK_UNUSED(smc) ;
+ return(phy+1);
+}
+
+/*
+ * return dynamic mac connection resource index
+ */
+static int mac_con_resource_index(smc,mac)
+struct s_smc *smc ;
+int mac ;
+{
+#ifdef CONCENTRATOR
+ SK_UNUSED(smc) ;
+ SK_UNUSED(mac) ;
+ return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_MAC))) ;
+#else
+ SK_UNUSED(mac) ;
+ switch (smc->mib.fddiSMTCF_State) {
+ case SC9_C_WRAP_A :
+ case SC5_THRU_B :
+ case SC11_C_WRAP_S :
+ return(1) ;
+ case SC10_C_WRAP_B :
+ case SC4_THRU_A :
+ return(2) ;
+ }
+ return(smc->s.sas == SMT_SAS ? 2 : 3) ;
+#endif
+}
+
+/*
+ * return dynamic phy connection resource index
+ */
+static int phy_con_resource_index(smc,phy)
+struct s_smc *smc ;
+int phy ;
+{
+#ifdef CONCENTRATOR
+ return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_PHY(phy)))) ;
+#else
+ switch (smc->mib.fddiSMTCF_State) {
+ case SC9_C_WRAP_A :
+ return(phy == PA ? 3 : 2) ;
+ case SC10_C_WRAP_B :
+ return(phy == PA ? 1 : 3) ;
+ case SC4_THRU_A :
+ return(phy == PA ? 3 : 1) ;
+ case SC5_THRU_B :
+ return(phy == PA ? 2 : 3) ;
+ case SC11_C_WRAP_S :
+ return(2) ;
+ }
+ return(phy) ;
+#endif
+}
+
+#ifdef CONCENTRATOR
+static int entity_to_index(smc,e)
+struct s_smc *smc ;
+int e ;
+{
+ if (e == ENTITY_MAC)
+ return(mac_index(smc,1)) ;
+ else
+ return(phy_index(smc,e - ENTITY_PHY(0))) ;
+}
+#endif
+
+#ifdef LITTLE_ENDIAN
+static int smt_swap_short(s)
+u_short s ;
+{
+ return(((s>>8)&0xff)|((s&0xff)<<8)) ;
+}
+
+void smt_swap_para(sm,len,direction)
+struct smt_header *sm ;
+int len ;
+int direction ; /* 0 encode 1 decode */
+{
+ struct smt_para *pa ;
+ const struct smt_pdef *pd ;
+ char *p ;
+ int plen ;
+ int type ;
+ int i ;
+
+/* printf("smt_swap_para sm %x len %d dir %d\n",
+ sm,len,direction) ;
+ */
+ smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ;
+
+ /* swap args */
+ len -= sizeof(struct smt_header) ;
+
+ p = (char *) (sm + 1) ;
+ while (len > 0) {
+ pa = (struct smt_para *) p ;
+ plen = pa->p_len ;
+ type = pa->p_type ;
+ pa->p_type = smt_swap_short(pa->p_type) ;
+ pa->p_len = smt_swap_short(pa->p_len) ;
+ if (direction) {
+ plen = pa->p_len ;
+ type = pa->p_type ;
+ }
+ /*
+ * note: paras can have 0 length !
+ */
+ if (plen < 0)
+ break ;
+ plen += PARA_LEN ;
+ for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) {
+ if (pd->ptype == type)
+ break ;
+ }
+ if (i && pd->pswap) {
+ smt_string_swap(p+PARA_LEN,pd->pswap,len) ;
+ }
+ len -= plen ;
+ p += plen ;
+ }
+}
+
+static void smt_string_swap(data,format,len)
+char *data ;
+const char *format ;
+int len ;
+{
+ const char *open_paren = 0 ;
+ int x ;
+
+ while (len > 0 && *format) {
+ switch (*format) {
+ case '[' :
+ open_paren = format ;
+ break ;
+ case ']' :
+ format = open_paren ;
+ break ;
+ case '1' :
+ case '2' :
+ case '3' :
+ case '4' :
+ case '5' :
+ case '6' :
+ case '7' :
+ case '8' :
+ case '9' :
+ data += *format - '0' ;
+ len -= *format - '0' ;
+ break ;
+ case 'c':
+ data++ ;
+ len-- ;
+ break ;
+ case 's' :
+ x = data[0] ;
+ data[0] = data[1] ;
+ data[1] = x ;
+ data += 2 ;
+ len -= 2 ;
+ break ;
+ case 'l' :
+ x = data[0] ;
+ data[0] = data[3] ;
+ data[3] = x ;
+ x = data[1] ;
+ data[1] = data[2] ;
+ data[2] = x ;
+ data += 4 ;
+ len -= 4 ;
+ break ;
+ }
+ format++ ;
+ }
+}
+#else
+void smt_swap_para(sm,len,direction)
+struct smt_header *sm ;
+int len ;
+int direction ; /* 0 encode 1 decode */
+{
+ SK_UNUSED(sm) ;
+ SK_UNUSED(len) ;
+ SK_UNUSED(direction) ;
+}
+#endif
+
+/*
+ * PMF actions
+ */
+int smt_action(smc,class,code,index)
+struct s_smc *smc ;
+int class ;
+int code ;
+int index ;
+{
+ int event ;
+ int port ;
+ DB_SMT("SMT: action %d code %d\n",class,code) ;
+ switch(class) {
+ case SMT_STATION_ACTION :
+ switch(code) {
+ case SMT_STATION_ACTION_CONNECT :
+ smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
+ queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+ break ;
+ case SMT_STATION_ACTION_DISCONNECT :
+ queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+ smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ;
+ RS_SET(smc,RS_DISCONNECT) ;
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+ FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT,
+ smt_get_event_word(smc));
+ break ;
+ case SMT_STATION_ACTION_PATHTEST :
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+ FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST,
+ smt_get_event_word(smc));
+ break ;
+ case SMT_STATION_ACTION_SELFTEST :
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+ FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST,
+ smt_get_event_word(smc));
+ break ;
+ case SMT_STATION_ACTION_DISABLE_A :
+ if (smc->y[PA].pc_mode == PM_PEER) {
+ RS_SET(smc,RS_EVENT) ;
+ queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ;
+ }
+ break ;
+ case SMT_STATION_ACTION_DISABLE_B :
+ if (smc->y[PB].pc_mode == PM_PEER) {
+ RS_SET(smc,RS_EVENT) ;
+ queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ;
+ }
+ break ;
+ case SMT_STATION_ACTION_DISABLE_M :
+ for (port = 0 ; port < NUMPHYS ; port++) {
+ if (smc->mib.p[port].fddiPORTMy_Type != TM)
+ continue ;
+ RS_SET(smc,RS_EVENT) ;
+ queue_event(smc,EVENT_PCM+port,PC_DISABLE) ;
+ }
+ break ;
+ default :
+ return(1) ;
+ }
+ break ;
+ case SMT_PORT_ACTION :
+ switch(code) {
+ case SMT_PORT_ACTION_ENABLE :
+ event = PC_ENABLE ;
+ break ;
+ case SMT_PORT_ACTION_DISABLE :
+ event = PC_DISABLE ;
+ break ;
+ case SMT_PORT_ACTION_MAINT :
+ event = PC_MAINT ;
+ break ;
+ case SMT_PORT_ACTION_START :
+ event = PC_START ;
+ break ;
+ case SMT_PORT_ACTION_STOP :
+ event = PC_STOP ;
+ break ;
+ default :
+ return(1) ;
+ }
+ queue_event(smc,EVENT_PCM+index,event) ;
+ break ;
+ default :
+ return(1) ;
+ }
+ return(0) ;
+}
+
+/*
+ * change tneg
+ * set T_Req in MIB (Path Attribute)
+ * calculate new values for MAC
+ * if change required
+ * disconnect
+ * set reconnect
+ * end
+ */
+void smt_change_t_neg(smc,tneg)
+struct s_smc *smc ;
+u_long tneg ;
+{
+ smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
+
+ if (smt_set_mac_opvalues(smc)) {
+ RS_SET(smc,RS_EVENT) ;
+ smc->sm.please_reconnect = 1 ;
+ queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+ }
+}
+
+/*
+ * canonical conversion of <len> bytes beginning form *data
+ */
+#ifdef USE_CAN_ADDR
+void hwm_conv_can(smc,data,len)
+struct s_smc *smc ;
+char *data ;
+int len ;
+{
+ int i ;
+
+ SK_UNUSED(smc) ;
+
+ for (i = len; i ; i--, data++) {
+ *data = canonical[*(u_char *)data] ;
+ }
+}
+#endif
+
+#endif /* no SLIM_SMT */
diff --git a/drivers/net/skfp/smtdef.c b/drivers/net/skfp/smtdef.c
new file mode 100644
index 000000000..221b0334c
--- /dev/null
+++ b/drivers/net/skfp/smtdef.c
@@ -0,0 +1,371 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ SMT/CMT defaults
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef OEM_USER_DATA
+#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata"
+#endif
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)smtdef.c 2.53 99/08/11 (C) SK " ;
+#endif
+
+/*
+ * defaults
+ */
+#define TTMS(x) ((u_long)(x)*1000L)
+#define TTS(x) ((u_long)(x)*1000000L)
+#define TTUS(x) ((u_long)(x))
+
+#define DEFAULT_TB_MIN TTMS(5)
+#define DEFAULT_TB_MAX TTMS(50)
+#define DEFAULT_C_MIN TTUS(1600)
+#define DEFAULT_T_OUT TTMS(100+5)
+#define DEFAULT_TL_MIN TTUS(30)
+#define DEFAULT_LC_SHORT TTMS(50+5)
+#define DEFAULT_LC_MEDIUM TTMS(500+20)
+#define DEFAULT_LC_LONG TTS(5)+TTMS(50)
+#define DEFAULT_LC_EXTENDED TTS(50)+TTMS(50)
+#define DEFAULT_T_NEXT_9 TTMS(200+10)
+#define DEFAULT_NS_MAX TTUS(1310)
+#define DEFAULT_I_MAX TTMS(25)
+#define DEFAULT_IN_MAX TTMS(40)
+#define DEFAULT_TD_MIN TTMS(5)
+#define DEFAULT_T_NON_OP TTS(1)
+#define DEFAULT_T_STUCK TTS(8)
+#define DEFAULT_T_DIRECT TTMS(370)
+#define DEFAULT_T_JAM TTMS(370)
+#define DEFAULT_T_ANNOUNCE TTMS(2500)
+#define DEFAULT_D_MAX TTUS(1617)
+#define DEFAULT_LEM_ALARM (8)
+#define DEFAULT_LEM_CUTOFF (7)
+#define DEFAULT_TEST_DONE TTS(1)
+#define DEFAULT_CHECK_POLL TTS(1)
+#define DEFAULT_POLL TTMS(50)
+
+/*
+ * LCT errors threshold
+ */
+#define DEFAULT_LCT_SHORT 1
+#define DEFAULT_LCT_MEDIUM 3
+#define DEFAULT_LCT_LONG 5
+#define DEFAULT_LCT_EXTEND 50
+
+/* Forward declarations */
+extern void smt_reset_defaults ();
+static void smt_init_mib ();
+
+static int set_min_max() ;
+
+void smt_set_defaults(smc)
+struct s_smc *smc ;
+{
+ smt_reset_defaults(smc,0) ;
+}
+
+#define MS2BCLK(x) ((x)*12500L)
+#define US2BCLK(x) ((x)*1250L)
+
+void smt_reset_defaults(smc,level)
+struct s_smc *smc ;
+int level ;
+{
+ struct smt_config *smt ;
+ int i ;
+ u_long smt_boot_time;
+
+
+ smt_init_mib(smc,level) ;
+
+ smc->os.smc_version = SMC_VERSION ;
+ smt_boot_time = smt_get_time();
+ for( i = 0; i < NUMMACS; i++ )
+ smc->sm.last_tok_time[i] = smt_boot_time ;
+ smt = &smc->s ;
+ smt->attach_s = 0 ;
+ smt->build_ring_map = 1 ;
+ smt->sas = SMT_DAS ;
+ smt->numphys = NUMPHYS ;
+ smt->pcm_tb_min = DEFAULT_TB_MIN ;
+ smt->pcm_tb_max = DEFAULT_TB_MAX ;
+ smt->pcm_c_min = DEFAULT_C_MIN ;
+ smt->pcm_t_out = DEFAULT_T_OUT ;
+ smt->pcm_tl_min = DEFAULT_TL_MIN ;
+ smt->pcm_lc_short = DEFAULT_LC_SHORT ;
+ smt->pcm_lc_medium = DEFAULT_LC_MEDIUM ;
+ smt->pcm_lc_long = DEFAULT_LC_LONG ;
+ smt->pcm_lc_extended = DEFAULT_LC_EXTENDED ;
+ smt->pcm_t_next_9 = DEFAULT_T_NEXT_9 ;
+ smt->pcm_ns_max = DEFAULT_NS_MAX ;
+ smt->ecm_i_max = DEFAULT_I_MAX ;
+ smt->ecm_in_max = DEFAULT_IN_MAX ;
+ smt->ecm_td_min = DEFAULT_TD_MIN ;
+ smt->ecm_test_done = DEFAULT_TEST_DONE ;
+ smt->ecm_check_poll = DEFAULT_CHECK_POLL ;
+ smt->rmt_t_non_op = DEFAULT_T_NON_OP ;
+ smt->rmt_t_stuck = DEFAULT_T_STUCK ;
+ smt->rmt_t_direct = DEFAULT_T_DIRECT ;
+ smt->rmt_t_jam = DEFAULT_T_JAM ;
+ smt->rmt_t_announce = DEFAULT_T_ANNOUNCE ;
+ smt->rmt_t_poll = DEFAULT_POLL ;
+ smt->rmt_dup_mac_behavior = FALSE ; /* See Struct smt_config */
+ smt->mac_d_max = DEFAULT_D_MAX ;
+
+ smt->lct_short = DEFAULT_LCT_SHORT ;
+ smt->lct_medium = DEFAULT_LCT_MEDIUM ;
+ smt->lct_long = DEFAULT_LCT_LONG ;
+ smt->lct_extended = DEFAULT_LCT_EXTEND ;
+
+#ifndef SLIM_SMT
+#ifdef ESS
+ if (level == 0) {
+ smc->ess.sync_bw_available = FALSE ;
+ smc->mib.fddiESSPayload = 0 ;
+ smc->mib.fddiESSOverhead = 0 ;
+ smc->mib.fddiESSMaxTNeg = (u_long)(- MS2BCLK(25)) ;
+ smc->mib.fddiESSMinSegmentSize = 1 ;
+ smc->mib.fddiESSCategory = SB_STATIC ;
+ smc->mib.fddiESSSynchTxMode = FALSE ;
+ smc->ess.raf_act_timer_poll = FALSE ;
+ smc->ess.timer_count = 7 ; /* first RAF alc req after 3s */
+ }
+ smc->ess.local_sba_active = FALSE ;
+ smc->ess.sba_reply_pend = NULL ;
+#endif
+#ifdef SBA
+ smt_init_sba(smc,level) ;
+#endif
+#endif /* no SLIM_SMT */
+#ifdef TAG_MODE
+ if (level == 0) {
+ smc->hw.pci_fix_value = 0 ;
+ }
+#endif
+}
+
+/*
+ * manufacturer data
+ */
+static const char man_data[32] =
+/* 01234567890123456789012345678901 */
+ "xxxSK-NET FDDI SMT 7.3 - V2.8.8" ;
+
+static void smt_init_mib(smc,level)
+struct s_smc *smc ;
+int level ;
+{
+ struct fddi_mib *mib ;
+ struct fddi_mib_p *pm ;
+ int port ;
+ int path ;
+
+ mib = &smc->mib ;
+ if (level == 0) {
+ /*
+ * set EVERYTHING to ZERO
+ * EXCEPT hw and os
+ */
+ memset(((char *)smc)+
+ sizeof(struct s_smt_os)+sizeof(struct s_smt_hw), 0,
+ sizeof(struct s_smc) -
+ sizeof(struct s_smt_os) - sizeof(struct s_smt_hw)) ;
+ }
+ else {
+ mib->fddiSMTRemoteDisconnectFlag = 0 ;
+ mib->fddiSMTPeerWrapFlag = 0 ;
+ }
+
+ mib->fddiSMTOpVersionId = 2 ;
+ mib->fddiSMTHiVersionId = 2 ;
+ mib->fddiSMTLoVersionId = 2 ;
+ memcpy((char *) mib->fddiSMTManufacturerData,man_data,32) ;
+ if (level == 0) {
+ strcpy(mib->fddiSMTUserData,OEM_USER_DATA) ;
+ }
+ mib->fddiSMTMIBVersionId = 1 ;
+ mib->fddiSMTMac_Ct = NUMMACS ;
+ mib->fddiSMTConnectionPolicy = POLICY_MM | POLICY_AA | POLICY_BB ;
+
+ /*
+ * fddiSMTNonMaster_Ct and fddiSMTMaster_Ct are set in smt_fixup_mib
+ * s.sas is not set yet (is set in init driver)
+ */
+ mib->fddiSMTAvailablePaths = MIB_PATH_P | MIB_PATH_S ;
+
+ mib->fddiSMTConfigCapabilities = 0 ; /* no hold,no wrap_ab*/
+ mib->fddiSMTTT_Notify = 10 ;
+ mib->fddiSMTStatRptPolicy = TRUE ;
+ mib->fddiSMTTrace_MaxExpiration = SEC2MIB(7) ;
+ mib->fddiSMTMACIndexes = INDEX_MAC ;
+ mib->fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; /* seperated */
+
+ mib->m[MAC0].fddiMACIndex = INDEX_MAC ;
+ mib->m[MAC0].fddiMACFrameStatusFunctions = FSC_TYPE0 ;
+ mib->m[MAC0].fddiMACRequestedPaths =
+ MIB_P_PATH_LOCAL |
+ MIB_P_PATH_SEC_ALTER |
+ MIB_P_PATH_PRIM_ALTER ;
+ mib->m[MAC0].fddiMACAvailablePaths = MIB_PATH_P ;
+ mib->m[MAC0].fddiMACCurrentPath = MIB_PATH_PRIMARY ;
+ mib->m[MAC0].fddiMACT_MaxCapabilitiy = (u_long)(- MS2BCLK(165)) ;
+ mib->m[MAC0].fddiMACTVXCapabilitiy = (u_long)(- US2BCLK(52)) ;
+ if (level == 0) {
+ mib->m[MAC0].fddiMACTvxValue = (u_long)(- US2BCLK(27)) ;
+ mib->m[MAC0].fddiMACTvxValueMIB = (u_long)(- US2BCLK(27)) ;
+ mib->m[MAC0].fddiMACT_Req = (u_long)(- MS2BCLK(165)) ;
+ mib->m[MAC0].fddiMACT_ReqMIB = (u_long)(- MS2BCLK(165)) ;
+ mib->m[MAC0].fddiMACT_Max = (u_long)(- MS2BCLK(165)) ;
+ mib->m[MAC0].fddiMACT_MaxMIB = (u_long)(- MS2BCLK(165)) ;
+ mib->m[MAC0].fddiMACT_Min = (u_long)(- MS2BCLK(4)) ;
+ }
+ mib->m[MAC0].fddiMACHardwarePresent = TRUE ;
+ mib->m[MAC0].fddiMACMA_UnitdataEnable = TRUE ;
+ mib->m[MAC0].fddiMACFrameErrorThreshold = 1 ;
+ mib->m[MAC0].fddiMACNotCopiedThreshold = 1 ;
+ /*
+ * Path attributes
+ */
+ for (path = 0 ; path < NUMPATHS ; path++) {
+ mib->a[path].fddiPATHIndex = INDEX_PATH + path ;
+ if (level == 0) {
+ mib->a[path].fddiPATHTVXLowerBound =
+ (u_long)(- US2BCLK(27)) ;
+ mib->a[path].fddiPATHT_MaxLowerBound =
+ (u_long)(- MS2BCLK(165)) ;
+ mib->a[path].fddiPATHMaxT_Req =
+ (u_long)(- MS2BCLK(165)) ;
+ }
+ }
+
+
+ /*
+ * Port attributes
+ */
+ pm = mib->p ;
+ for (port = 0 ; port < NUMPHYS ; port++) {
+ /*
+ * set MIB pointer in phy
+ */
+ /* Attention: don't initialize mib pointer here! */
+ /* It must be initialized during phase 2 */
+ smc->y[port].mib = 0 ;
+ mib->fddiSMTPORTIndexes[port] = port+INDEX_PORT ;
+
+ pm->fddiPORTIndex = port+INDEX_PORT ;
+ pm->fddiPORTHardwarePresent = TRUE ;
+ if (level == 0) {
+ pm->fddiPORTLer_Alarm = DEFAULT_LEM_ALARM ;
+ pm->fddiPORTLer_Cutoff = DEFAULT_LEM_CUTOFF ;
+ }
+ /*
+ * fddiPORTRequestedPaths are set in pcmplc.c
+ * we don't know the port type yet !
+ */
+ pm->fddiPORTRequestedPaths[1] = 0 ;
+ pm->fddiPORTRequestedPaths[2] = 0 ;
+ pm->fddiPORTRequestedPaths[3] = 0 ;
+ pm->fddiPORTAvailablePaths = MIB_PATH_P ;
+ pm->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
+ pm++ ;
+ }
+
+ (void) smt_set_mac_opvalues(smc) ;
+}
+
+int smt_set_mac_opvalues(smc)
+struct s_smc *smc ;
+{
+ int st ;
+ int st2 ;
+
+ st = set_min_max(1,smc->mib.m[MAC0].fddiMACTvxValueMIB,
+ smc->mib.a[PATH0].fddiPATHTVXLowerBound,
+ &smc->mib.m[MAC0].fddiMACTvxValue) ;
+ st |= set_min_max(0,smc->mib.m[MAC0].fddiMACT_MaxMIB,
+ smc->mib.a[PATH0].fddiPATHT_MaxLowerBound,
+ &smc->mib.m[MAC0].fddiMACT_Max) ;
+ st |= (st2 = set_min_max(0,smc->mib.m[MAC0].fddiMACT_ReqMIB,
+ smc->mib.a[PATH0].fddiPATHMaxT_Req,
+ &smc->mib.m[MAC0].fddiMACT_Req)) ;
+ if (st2) {
+ /* Treq attribute changed remotely. So send an AIX_EVENT to the
+ * user
+ */
+ AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+ FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ,
+ smt_get_event_word(smc));
+ }
+ return(st) ;
+}
+
+void smt_fixup_mib(smc)
+struct s_smc *smc ;
+{
+#ifdef CONCENTRATOR
+ switch (smc->s.sas) {
+ case SMT_SAS :
+ smc->mib.fddiSMTNonMaster_Ct = 1 ;
+ break ;
+ case SMT_DAS :
+ smc->mib.fddiSMTNonMaster_Ct = 2 ;
+ break ;
+ case SMT_NAC :
+ smc->mib.fddiSMTNonMaster_Ct = 0 ;
+ break ;
+ }
+ smc->mib.fddiSMTMaster_Ct = NUMPHYS - smc->mib.fddiSMTNonMaster_Ct ;
+#else
+ switch (smc->s.sas) {
+ case SMT_SAS :
+ smc->mib.fddiSMTNonMaster_Ct = 1 ;
+ break ;
+ case SMT_DAS :
+ smc->mib.fddiSMTNonMaster_Ct = 2 ;
+ break ;
+ }
+ smc->mib.fddiSMTMaster_Ct = 0 ;
+#endif
+}
+
+/*
+ * determine new setting for operational value
+ * if limit is lower than mib
+ * use limit
+ * else
+ * use mib
+ * NOTE : numbers are negative, negate comparison !
+ */
+static int set_min_max(maxflag,mib,limit,oper)
+int maxflag ;
+u_long mib ;
+u_long limit ;
+u_long *oper ;
+{
+ u_long old ;
+ old = *oper ;
+ if ((limit > mib) ^ maxflag)
+ *oper = limit ;
+ else
+ *oper = mib ;
+ return(old != *oper) ;
+}
diff --git a/drivers/net/skfp/smtinit.c b/drivers/net/skfp/smtinit.c
new file mode 100644
index 000000000..c4b5af9b5
--- /dev/null
+++ b/drivers/net/skfp/smtinit.c
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ Init SMT
+ call all module level initialization routines
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)smtinit.c 1.15 97/05/06 (C) SK " ;
+#endif
+
+extern void init_fddi_driver() ;
+
+/* define global debug variable */
+#if defined(DEBUG) && !defined(DEBUG_BRD)
+struct smt_debug debug;
+#endif
+
+#ifndef MULT_OEM
+#define OEMID(smc,i) oem_id[i]
+ extern u_char oem_id[] ;
+#else /* MULT_OEM */
+#define OEMID(smc,i) smc->hw.oem_id->oi_mark[i]
+ extern struct s_oem_ids oem_ids[] ;
+#endif /* MULT_OEM */
+
+/*
+ * Set OEM specific values
+ *
+ * Can not be called in smt_reset_defaults, because it is not sure that
+ * the OEM ID is already defined.
+ */
+static void set_oem_spec_val(smc)
+struct s_smc *smc ;
+{
+ struct fddi_mib *mib ;
+
+ mib = &smc->mib ;
+
+ /*
+ * set IBM specific values
+ */
+ if (OEMID(smc,0) == 'I') {
+ mib->fddiSMTConnectionPolicy = POLICY_MM ;
+ }
+}
+
+/*
+ * Init SMT
+ */
+int init_smt(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ; /* canonical address or NULL */
+{
+ int p ;
+
+#if defined(DEBUG) && !defined(DEBUG_BRD)
+ debug.d_smt = 0 ;
+ debug.d_smtf = 0 ;
+ debug.d_rmt = 0 ;
+ debug.d_ecm = 0 ;
+ debug.d_pcm = 0 ;
+ debug.d_cfm = 0 ;
+
+ debug.d_plc = 0 ;
+#ifdef ESS
+ debug.d_ess = 0 ;
+#endif
+#ifdef SBA
+ debug.d_sba = 0 ;
+#endif
+#endif /* DEBUG && !DEBUG_BRD */
+
+ /* First initialize the ports mib->pointers */
+ for ( p = 0; p < NUMPHYS; p ++ ) {
+ smc->y[p].mib = & smc->mib.p[p] ;
+ }
+
+ set_oem_spec_val(smc) ;
+ (void) smt_set_mac_opvalues(smc) ;
+ init_fddi_driver(smc,mac_addr) ; /* HW driver */
+ smt_fixup_mib(smc) ; /* update values that depend on s.sas */
+
+ ev_init(smc) ; /* event queue */
+#ifndef SLIM_SMT
+ smt_init_evc(smc) ; /* evcs in MIB */
+#endif /* no SLIM_SMT */
+ smt_timer_init(smc) ; /* timer package */
+ smt_agent_init(smc) ; /* SMT frame manager */
+
+ pcm_init(smc) ; /* PCM state machine */
+ ecm_init(smc) ; /* ECM state machine */
+ cfm_init(smc) ; /* CFM state machine */
+ rmt_init(smc) ; /* RMT state machine */
+
+ for (p = 0 ; p < NUMPHYS ; p++) {
+ pcm(smc,p,0) ; /* PCM A state machine */
+ }
+ ecm(smc,0) ; /* ECM state machine */
+ cfm(smc,0) ; /* CFM state machine */
+ rmt(smc,0) ; /* RMT state machine */
+
+ smt_agent_task(smc) ; /* NIF FSM etc */
+
+ PNMI_INIT(smc) ; /* PNMI initialization */
+
+ return(0) ;
+}
diff --git a/drivers/net/skfp/smtparse.c b/drivers/net/skfp/smtparse.c
new file mode 100644
index 000000000..0b4a2274d
--- /dev/null
+++ b/drivers/net/skfp/smtparse.c
@@ -0,0 +1,475 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+/*
+ parser for SMT parameters
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)smtparse.c 1.12 98/10/06 (C) SK " ;
+#endif
+
+#ifdef sun
+#define _far
+#endif
+
+/*
+ * convert to BCLK units
+ */
+#define MS2BCLK(x) ((x)*12500L)
+#define US2BCLK(x) ((x/10)*125L)
+
+/*
+ * parameter table
+ */
+static struct s_ptab {
+ char *pt_name ;
+ u_short pt_num ;
+ u_short pt_type ;
+ u_long pt_min ;
+ u_long pt_max ;
+} ptab[] = {
+ { "PMFPASSWD",0, 0 } ,
+ { "USERDATA",1, 0 } ,
+ { "LERCUTOFFA",2, 1, 4, 15 } ,
+ { "LERCUTOFFB",3, 1, 4, 15 } ,
+ { "LERALARMA",4, 1, 4, 15 } ,
+ { "LERALARMB",5, 1, 4, 15 } ,
+ { "TMAX",6, 1, 5, 165 } ,
+ { "TMIN",7, 1, 5, 165 } ,
+ { "TREQ",8, 1, 5, 165 } ,
+ { "TVX",9, 1, 2500, 10000 } ,
+#ifdef ESS
+ { "SBAPAYLOAD",10, 1, 0, 1562 } ,
+ { "SBAOVERHEAD",11, 1, 50, 5000 } ,
+ { "MAXTNEG",12, 1, 5, 165 } ,
+ { "MINSEGMENTSIZE",13, 1, 0, 4478 } ,
+ { "SBACATEGORY",14, 1, 0, 0xffff } ,
+ { "SYNCHTXMODE",15, 0 } ,
+#endif
+#ifdef SBA
+ { "SBACOMMAND",16, 0 } ,
+ { "SBAAVAILABLE",17, 1, 0, 100 } ,
+#endif
+ { 0 }
+} ;
+
+/* Define maximum string size for values and keybuffer */
+#define MAX_VAL 40
+
+/*
+ * local function declarations
+ */
+static u_long parse_num() ;
+static int parse_word() ;
+
+#ifdef SIM
+#define DB_MAIN(a,b,c) printf(a,b,c)
+#else
+#define DB_MAIN(a,b,c)
+#endif
+
+/*
+ * BEGIN_MANUAL_ENTRY()
+ *
+ * int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
+ char _far *value)
+ *
+ * parse SMT parameter
+ * *keyword
+ * pointer to keyword, must be \0, \n or \r terminated
+ * *value pointer to value, either char * or u_long *
+ * if char *
+ * pointer to value, must be \0, \n or \r terminated
+ * if u_long *
+ * contains binary value
+ *
+ * type 0: integer
+ * 1: string
+ * return
+ * 0 parameter parsed ok
+ * != 0 error
+ * NOTE:
+ * function can be called with DS != SS
+ *
+ *
+ * END_MANUAL_ENTRY()
+ */
+int smt_parse_arg(smc,keyword,type,value)
+struct s_smc *smc ;
+char _far *keyword ;
+int type ;
+char _far *value ;
+{
+ char keybuf[MAX_VAL+1];
+ char valbuf[MAX_VAL+1];
+ char c ;
+ char *p ;
+ char *v ;
+ char *d ;
+ u_long val = 0 ;
+ struct s_ptab *pt ;
+ int st ;
+ int i ;
+
+ /*
+ * parse keyword
+ */
+ if ((st = parse_word(keybuf,keyword)))
+ return(st) ;
+ /*
+ * parse value if given as string
+ */
+ if (type == 1) {
+ if ((st = parse_word(valbuf,value)))
+ return(st) ;
+ }
+ /*
+ * search in table
+ */
+ st = 0 ;
+ for (pt = ptab ; (v = pt->pt_name) ; pt++) {
+ for (p = keybuf ; (c = *p) ; p++,v++) {
+ if (c != *v)
+ break ;
+ }
+ if (!c && !*v)
+ break ;
+ }
+ if (!v)
+ return(-1) ;
+#if 0
+ printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
+#endif
+ /*
+ * set value in MIB
+ */
+ if (pt->pt_type)
+ val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
+ switch (pt->pt_num) {
+ case 0 :
+ v = valbuf ;
+ d = (char *) smc->mib.fddiPRPMFPasswd ;
+ for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
+ *d++ = *v++ ;
+ DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
+ break ;
+ case 1 :
+ v = valbuf ;
+ d = (char *) smc->mib.fddiSMTUserData ;
+ for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
+ *d++ = *v++ ;
+ DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
+ break ;
+ case 2 :
+ smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
+ DB_MAIN("SET %s = %d\n",
+ pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
+ break ;
+ case 3 :
+ smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
+ DB_MAIN("SET %s = %d\n",
+ pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
+ break ;
+ case 4 :
+ smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
+ DB_MAIN("SET %s = %d\n",
+ pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
+ break ;
+ case 5 :
+ smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
+ DB_MAIN("SET %s = %d\n",
+ pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
+ break ;
+ case 6 : /* TMAX */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
+ (u_long) -MS2BCLK((long)val) ;
+ break ;
+ case 7 : /* TMIN */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.m[MAC0].fddiMACT_Min =
+ (u_long) -MS2BCLK((long)val) ;
+ break ;
+ case 8 : /* TREQ */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.a[PATH0].fddiPATHMaxT_Req =
+ (u_long) -MS2BCLK((long)val) ;
+ break ;
+ case 9 : /* TVX */
+ DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
+ smc->mib.a[PATH0].fddiPATHTVXLowerBound =
+ (u_long) -US2BCLK((long)val) ;
+ break ;
+#ifdef ESS
+ case 10 : /* SBAPAYLOAD */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ if (smc->mib.fddiESSPayload != val) {
+ smc->ess.raf_act_timer_poll = TRUE ;
+ smc->mib.fddiESSPayload = val ;
+ }
+ break ;
+ case 11 : /* SBAOVERHEAD */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.fddiESSOverhead = val ;
+ break ;
+ case 12 : /* MAXTNEG */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
+ break ;
+ case 13 : /* MINSEGMENTSIZE */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.fddiESSMinSegmentSize = val ;
+ break ;
+ case 14 : /* SBACATEGORY */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.fddiESSCategory =
+ (smc->mib.fddiESSCategory & 0xffff) |
+ ((u_long)(val << 16)) ;
+ break ;
+ case 15 : /* SYNCHTXMODE */
+ /* do not use memcmp(valbuf,"ALL",3) because DS != SS */
+ if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
+ smc->mib.fddiESSSynchTxMode = TRUE ;
+ DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+ }
+ /* if (!memcmp(valbuf,"SPLIT",5)) { */
+ if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
+ valbuf[3] == 'I' && valbuf[4] == 'T') {
+ DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+ smc->mib.fddiESSSynchTxMode = FALSE ;
+ }
+ break ;
+#endif
+#ifdef SBA
+ case 16 : /* SBACOMMAND */
+ /* if (!memcmp(valbuf,"START",5)) { */
+ if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
+ valbuf[3] == 'R' && valbuf[4] == 'T') {
+ DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+ smc->mib.fddiSBACommand = SB_START ;
+ }
+ /* if (!memcmp(valbuf,"STOP",4)) { */
+ if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
+ valbuf[3] == 'P') {
+ DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+ smc->mib.fddiSBACommand = SB_STOP ;
+ }
+ break ;
+ case 17 : /* SBAAVAILABLE */
+ DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+ smc->mib.fddiSBAAvailable = (u_char) val ;
+ break ;
+#endif
+ }
+ return(0) ;
+}
+
+static int parse_word(buf,text)
+char *buf ;
+char _far *text ;
+{
+ char c ;
+ char *p ;
+ int p_len ;
+ int quote ;
+ int i ;
+ int ok ;
+
+ /*
+ * skip leading white space
+ */
+ p = buf ;
+ for (i = 0 ; i < MAX_VAL ; i++)
+ *p++ = 0 ;
+ p = buf ;
+ p_len = 0 ;
+ ok = 0 ;
+ while ( (c = *text++) && (c != '\n') && (c != '\r')) {
+ if ((c != ' ') && (c != '\t')) {
+ ok = 1 ;
+ break ;
+ }
+ }
+ if (!ok)
+ return(-1) ;
+ if (c == '"') {
+ quote = 1 ;
+ }
+ else {
+ quote = 0 ;
+ text-- ;
+ }
+ /*
+ * parse valbuf
+ */
+ ok = 0 ;
+ while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
+ && (c != '\r')) {
+ switch (quote) {
+ case 0 :
+ if ((c == ' ') || (c == '\t') || (c == '=')) {
+ ok = 1 ;
+ break ;
+ }
+ *p++ = c ;
+ p_len++ ;
+ break ;
+ case 2 :
+ *p++ = c ;
+ p_len++ ;
+ quote = 1 ;
+ break ;
+ case 1 :
+ switch (c) {
+ case '"' :
+ ok = 1 ;
+ break ;
+ case '\\' :
+ quote = 2 ;
+ break ;
+ default :
+ *p++ = c ;
+ p_len++ ;
+ }
+ }
+ }
+ *p++ = 0 ;
+ for (p = buf ; (c = *p) ; p++) {
+ if (c >= 'a' && c <= 'z')
+ *p = c + 'A' - 'a' ;
+ }
+ return(0) ;
+}
+
+static u_long parse_num(type,value,v,mn,mx,scale)
+int type ;
+char _far *value ;
+char *v ;
+u_long mn ;
+u_long mx ;
+int scale ;
+{
+ u_long x = 0 ;
+ char c ;
+
+ if (type == 0) { /* integer */
+ u_long _far *l ;
+ u_long u1 ;
+
+ l = (u_long _far *) value ;
+ u1 = *l ;
+ /*
+ * if the value is negative take the lower limit
+ */
+ if ((long)u1 < 0) {
+ if (- ((long)u1) > (long) mx) {
+ u1 = 0 ;
+ }
+ else {
+ u1 = (u_long) - ((long)u1) ;
+ }
+ }
+ x = u1 ;
+ }
+ else { /* string */
+ int sign = 0 ;
+
+ if (*v == '-') {
+ sign = 1 ;
+ }
+ while ((c = *v++) && (c >= '0') && (c <= '9')) {
+ x = x * 10 + c - '0' ;
+ }
+ if (scale == 10) {
+ x *= 10 ;
+ if (c == '.') {
+ if ((c = *v++) && (c >= '0') && (c <= '9')) {
+ x += c - '0' ;
+ }
+ }
+ }
+ if (sign)
+ x = (u_long) - ((long)x) ;
+ }
+ /*
+ * if the value is negative
+ * and the absolute value is outside the limits
+ * take the lower limit
+ * else
+ * take the absoute value
+ */
+ if ((long)x < 0) {
+ if (- ((long)x) > (long) mx) {
+ x = 0 ;
+ }
+ else {
+ x = (u_long) - ((long)x) ;
+ }
+ }
+ if (x < mn)
+ return(mn) ;
+ else if (x > mx)
+ return(mx) ;
+ return(x) ;
+}
+
+#if 0
+struct s_smc SMC ;
+main()
+{
+ char *p ;
+ char *v ;
+ char buf[100] ;
+ int toggle = 0 ;
+
+ while (gets(buf)) {
+ p = buf ;
+ while (*p && ((*p == ' ') || (*p == '\t')))
+ p++ ;
+
+ while (*p && ((*p != ' ') && (*p != '\t')))
+ p++ ;
+
+ v = p ;
+ while (*v && ((*v == ' ') || (*v == '\t')))
+ v++ ;
+ if ((*v >= '0') && (*v <= '9')) {
+ toggle = !toggle ;
+ if (toggle) {
+ u_long l ;
+ l = atol(v) ;
+ smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
+ }
+ else
+ smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
+ }
+ else {
+ smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
+ }
+ }
+ exit(0) ;
+}
+#endif
diff --git a/drivers/net/skfp/smttimer.c b/drivers/net/skfp/smttimer.c
new file mode 100644
index 000000000..9d7b71e26
--- /dev/null
+++ b/drivers/net/skfp/smttimer.c
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ SMT timer
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ;
+#endif
+
+/*
+ * external function declarations
+ */
+extern u_long hwt_read() ;
+extern void hwt_stop() ;
+extern void hwt_start() ;
+
+static void timer_done() ;
+
+
+void smt_timer_init(smc)
+struct s_smc *smc ;
+{
+ smc->t.st_queue = 0 ;
+ smc->t.st_fast.tm_active = FALSE ;
+ smc->t.st_fast.tm_next = 0 ;
+ hwt_init(smc) ;
+}
+
+void smt_timer_stop(smc,timer)
+struct s_smc *smc ;
+struct smt_timer *timer ;
+{
+ struct smt_timer **prev ;
+ struct smt_timer *tm ;
+
+ /*
+ * remove timer from queue
+ */
+ timer->tm_active = FALSE ;
+ if (smc->t.st_queue == timer && !timer->tm_next) {
+ hwt_stop(smc) ;
+ }
+ for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+ if (tm == timer) {
+ *prev = tm->tm_next ;
+ if (tm->tm_next) {
+ tm->tm_next->tm_delta += tm->tm_delta ;
+ }
+ return ;
+ }
+ }
+}
+
+void smt_timer_start(smc,timer,time,token)
+struct s_smc *smc ;
+struct smt_timer *timer ;
+u_long time ;
+u_long token ;
+{
+ struct smt_timer **prev ;
+ struct smt_timer *tm ;
+ u_long delta = 0 ;
+
+ time /= 16 ; /* input is uS, clock ticks are 16uS */
+ if (!time)
+ time = 1 ;
+ smt_timer_stop(smc,timer) ;
+ timer->tm_smc = smc ;
+ timer->tm_token = token ;
+ timer->tm_active = TRUE ;
+ if (!smc->t.st_queue) {
+ smc->t.st_queue = timer ;
+ timer->tm_next = 0 ;
+ timer->tm_delta = time ;
+ hwt_start(smc,time) ;
+ return ;
+ }
+ /*
+ * timer correction
+ */
+ timer_done(smc,0) ;
+
+ /*
+ * find position in queue
+ */
+ delta = 0 ;
+ for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+ if (delta + tm->tm_delta > time) {
+ break ;
+ }
+ delta += tm->tm_delta ;
+ }
+ /* insert in queue */
+ *prev = timer ;
+ timer->tm_next = tm ;
+ timer->tm_delta = time - delta ;
+ if (tm)
+ tm->tm_delta -= timer->tm_delta ;
+ /*
+ * start new with first
+ */
+ hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
+
+void smt_force_irq(smc)
+struct s_smc *smc ;
+{
+ smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST));
+}
+
+void smt_timer_done(smc)
+struct s_smc *smc ;
+{
+ timer_done(smc,1) ;
+}
+
+static void timer_done(smc,restart)
+struct s_smc *smc ;
+int restart ;
+{
+ u_long delta ;
+ struct smt_timer *tm ;
+ struct smt_timer *next ;
+ struct smt_timer **last ;
+ int done = 0 ;
+
+ delta = hwt_read(smc) ;
+ last = &smc->t.st_queue ;
+ tm = smc->t.st_queue ;
+ while (tm && !done) {
+ if (delta >= tm->tm_delta) {
+ tm->tm_active = FALSE ;
+ delta -= tm->tm_delta ;
+ last = &tm->tm_next ;
+ tm = tm->tm_next ;
+ }
+ else {
+ tm->tm_delta -= delta ;
+ delta = 0 ;
+ done = 1 ;
+ }
+ }
+ *last = 0 ;
+ next = smc->t.st_queue ;
+ smc->t.st_queue = tm ;
+
+ for ( tm = next ; tm ; tm = next) {
+ next = tm->tm_next ;
+ timer_event(smc,tm->tm_token) ;
+ }
+
+ if (restart && smc->t.st_queue)
+ hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c
new file mode 100644
index 000000000..79bbfedc6
--- /dev/null
+++ b/drivers/net/skfp/srf.c
@@ -0,0 +1,441 @@
+/******************************************************************************
+ *
+ * (C)Copyright 1998,1999 SysKonnect,
+ * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ * See the file "skfddi.c" for further information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ SMT 7.2 Status Response Frame Implementation
+ SRF state machine and frame generation
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef SLIM_SMT
+#ifndef BOOT
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)srf.c 1.18 97/08/04 (C) SK " ;
+#endif
+
+
+/*
+ * function declarations
+ */
+static void clear_all_rep() ;
+static void clear_reported() ;
+static void smt_send_srf() ;
+static struct s_srf_evc *smt_get_evc() ;
+
+#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0]))
+
+struct evc_init {
+ u_char code ;
+ u_char index ;
+ u_char n ;
+ u_short para ;
+} ;
+
+static const struct evc_init evc_inits[] = {
+ { SMT_COND_SMT_PEER_WRAP, 0,1,SMT_P1048 } ,
+
+ { SMT_COND_MAC_DUP_ADDR, INDEX_MAC, NUMMACS,SMT_P208C } ,
+ { SMT_COND_MAC_FRAME_ERROR, INDEX_MAC, NUMMACS,SMT_P208D } ,
+ { SMT_COND_MAC_NOT_COPIED, INDEX_MAC, NUMMACS,SMT_P208E } ,
+ { SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC, NUMMACS,SMT_P208F } ,
+ { SMT_EVENT_MAC_PATH_CHANGE, INDEX_MAC, NUMMACS,SMT_P2090 } ,
+
+ { SMT_COND_PORT_LER, INDEX_PORT,NUMPHYS,SMT_P4050 } ,
+ { SMT_COND_PORT_EB_ERROR, INDEX_PORT,NUMPHYS,SMT_P4052 } ,
+ { SMT_EVENT_PORT_CONNECTION, INDEX_PORT,NUMPHYS,SMT_P4051 } ,
+ { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } ,
+} ;
+
+#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0]))
+
+void smt_init_evc(smc)
+struct s_smc *smc ;
+{
+ struct s_srf_evc *evc ;
+ const struct evc_init *init ;
+ int i ;
+ int index ;
+ int offset ;
+
+ static u_char fail_safe = FALSE ;
+
+ memset((char *)smc->evcs,0,sizeof(smc->evcs)) ;
+
+ evc = smc->evcs ;
+ init = evc_inits ;
+
+ for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) {
+ for (index = 0 ; index < init->n ; index++) {
+ evc->evc_code = init->code ;
+ evc->evc_para = init->para ;
+ evc->evc_index = init->index + index ;
+#ifndef DEBUG
+ evc->evc_multiple = &fail_safe ;
+ evc->evc_cond_state = &fail_safe ;
+#endif
+ evc++ ;
+ }
+ init++ ;
+ }
+
+ if ((unsigned) (evc - smc->evcs) > MAX_EVCS) {
+ SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ;
+ }
+
+ /*
+ * conditions
+ */
+ smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ;
+ smc->evcs[1].evc_cond_state =
+ &smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
+ smc->evcs[2].evc_cond_state =
+ &smc->mib.m[MAC0].fddiMACFrameErrorFlag ;
+ smc->evcs[3].evc_cond_state =
+ &smc->mib.m[MAC0].fddiMACNotCopiedFlag ;
+
+ /*
+ * events
+ */
+ smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ;
+ smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ;
+
+ offset = 6 ;
+ for (i = 0 ; i < NUMPHYS ; i++) {
+ /*
+ * conditions
+ */
+ smc->evcs[offset + 0*NUMPHYS].evc_cond_state =
+ &smc->mib.p[i].fddiPORTLerFlag ;
+ smc->evcs[offset + 1*NUMPHYS].evc_cond_state =
+ &smc->mib.p[i].fddiPORTEB_Condition ;
+
+ /*
+ * events
+ */
+ smc->evcs[offset + 2*NUMPHYS].evc_multiple =
+ &smc->mib.p[i].fddiPORTMultiple_U ;
+ smc->evcs[offset + 3*NUMPHYS].evc_multiple =
+ &smc->mib.p[i].fddiPORTMultiple_P ;
+ offset++ ;
+ }
+#ifdef DEBUG
+ for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+ if (SMT_IS_CONDITION(evc->evc_code)) {
+ if (!evc->evc_cond_state) {
+ SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ;
+ }
+ evc->evc_multiple = &fail_safe ;
+ }
+ else {
+ if (!evc->evc_multiple) {
+ SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ;
+ }
+ evc->evc_cond_state = &fail_safe ;
+ }
+ }
+#endif
+ smc->srf.TSR = smt_get_time() ;
+ smc->srf.sr_state = SR0_WAIT ;
+}
+
+static struct s_srf_evc *smt_get_evc(smc,code,index)
+struct s_smc *smc ;
+int code ;
+int index ;
+{
+ int i ;
+ struct s_srf_evc *evc ;
+
+ for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+ if (evc->evc_code == code && evc->evc_index == index)
+ return(evc) ;
+ }
+ return(0) ;
+}
+
+#define THRESHOLD_2 (2*TICKS_PER_SECOND)
+#define THRESHOLD_32 (32*TICKS_PER_SECOND)
+
+#ifdef DEBUG
+static const char * const srf_names[] = {
+ "None","MACPathChangeEvent", "MACNeighborChangeEvent",
+ "PORTPathChangeEvent", "PORTUndesiredConnectionAttemptEvent",
+ "SMTPeerWrapCondition", "SMTHoldCondition",
+ "MACFrameErrorCondition", "MACDuplicateAddressCondition",
+ "MACNotCopiedCondition", "PORTEBErrorCondition",
+ "PORTLerCondition"
+} ;
+#endif
+
+void smt_srf_event(smc,code,index,cond)
+struct s_smc *smc ;
+int code ;
+int index ;
+int cond ;
+{
+ struct s_srf_evc *evc ;
+ int cond_asserted = 0 ;
+ int cond_deasserted = 0 ;
+ int event_occured = 0 ;
+ int tsr ;
+ int T_Limit = 2*TICKS_PER_SECOND ;
+
+ if (code == SMT_COND_MAC_DUP_ADDR && cond) {
+ RS_SET(smc,RS_DUPADDR) ;
+ }
+
+ if (code) {
+ DB_SMT("SRF: %s index %d\n",srf_names[code],index) ;
+
+ if (!(evc = smt_get_evc(smc,code,index))) {
+ DB_SMT("SRF : smt_get_evc() failed\n",0,0) ;
+ return ;
+ }
+ /*
+ * ignore condition if no change
+ */
+ if (SMT_IS_CONDITION(code)) {
+ if (*evc->evc_cond_state == cond)
+ return ;
+ }
+
+ /*
+ * set transition time stamp
+ */
+ smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ;
+ if (SMT_IS_CONDITION(code)) {
+ DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ;
+ if (cond) {
+ *evc->evc_cond_state = TRUE ;
+ evc->evc_rep_required = TRUE ;
+ smc->srf.any_report = TRUE ;
+ cond_asserted = TRUE ;
+ }
+ else {
+ *evc->evc_cond_state = FALSE ;
+ cond_deasserted = TRUE ;
+ }
+ }
+ else {
+ if (evc->evc_rep_required) {
+ *evc->evc_multiple = TRUE ;
+ }
+ else {
+ evc->evc_rep_required = TRUE ;
+ *evc->evc_multiple = FALSE ;
+ }
+ smc->srf.any_report = TRUE ;
+ event_occured = TRUE ;
+ }
+#ifdef FDDI_MIB
+ snmp_srf_event(smc,evc) ;
+#endif /* FDDI_MIB */
+ }
+ tsr = smt_get_time() - smc->srf.TSR ;
+
+ switch (smc->srf.sr_state) {
+ case SR0_WAIT :
+ /* SR01a */
+ if (cond_asserted && tsr < T_Limit) {
+ smc->srf.SRThreshold = THRESHOLD_2 ;
+ smc->srf.sr_state = SR1_HOLDOFF ;
+ break ;
+ }
+ /* SR01b */
+ if (cond_deasserted && tsr < T_Limit) {
+ smc->srf.sr_state = SR1_HOLDOFF ;
+ break ;
+ }
+ /* SR01c */
+ if (event_occured && tsr < T_Limit) {
+ smc->srf.sr_state = SR1_HOLDOFF ;
+ break ;
+ }
+ /* SR00b */
+ if (cond_asserted && tsr >= T_Limit) {
+ smc->srf.SRThreshold = THRESHOLD_2 ;
+ smc->srf.TSR = smt_get_time() ;
+ smt_send_srf(smc) ;
+ break ;
+ }
+ /* SR00c */
+ if (cond_deasserted && tsr >= T_Limit) {
+ smc->srf.TSR = smt_get_time() ;
+ smt_send_srf(smc) ;
+ break ;
+ }
+ /* SR00d */
+ if (event_occured && tsr >= T_Limit) {
+ smc->srf.TSR = smt_get_time() ;
+ smt_send_srf(smc) ;
+ break ;
+ }
+ /* SR00e */
+ if (smc->srf.any_report && (u_long) tsr >=
+ smc->srf.SRThreshold) {
+ smc->srf.SRThreshold *= 2 ;
+ if (smc->srf.SRThreshold > THRESHOLD_32)
+ smc->srf.SRThreshold = THRESHOLD_32 ;
+ smc->srf.TSR = smt_get_time() ;
+ smt_send_srf(smc) ;
+ break ;
+ }
+ /* SR02 */
+ if (!smc->mib.fddiSMTStatRptPolicy) {
+ smc->srf.sr_state = SR2_DISABLED ;
+ break ;
+ }
+ break ;
+ case SR1_HOLDOFF :
+ /* SR10b */
+ if (tsr >= T_Limit) {
+ smc->srf.sr_state = SR0_WAIT ;
+ smc->srf.TSR = smt_get_time() ;
+ smt_send_srf(smc) ;
+ break ;
+ }
+ /* SR11a */
+ if (cond_asserted) {
+ smc->srf.SRThreshold = THRESHOLD_2 ;
+ }
+ /* SR11b */
+ /* SR11c */
+ /* handled above */
+ /* SR12 */
+ if (!smc->mib.fddiSMTStatRptPolicy) {
+ smc->srf.sr_state = SR2_DISABLED ;
+ break ;
+ }
+ break ;
+ case SR2_DISABLED :
+ if (smc->mib.fddiSMTStatRptPolicy) {
+ smc->srf.sr_state = SR0_WAIT ;
+ smc->srf.TSR = smt_get_time() ;
+ smc->srf.SRThreshold = THRESHOLD_2 ;
+ clear_all_rep(smc) ;
+ break ;
+ }
+ break ;
+ }
+}
+
+static void clear_all_rep(smc)
+struct s_smc *smc ;
+{
+ struct s_srf_evc *evc ;
+ int i ;
+
+ for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+ evc->evc_rep_required = FALSE ;
+ if (SMT_IS_CONDITION(evc->evc_code))
+ *evc->evc_cond_state = FALSE ;
+ }
+ smc->srf.any_report = FALSE ;
+}
+
+static void clear_reported(smc)
+struct s_smc *smc ;
+{
+ struct s_srf_evc *evc ;
+ int i ;
+
+ smc->srf.any_report = FALSE ;
+ for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+ if (SMT_IS_CONDITION(evc->evc_code)) {
+ if (*evc->evc_cond_state == FALSE)
+ evc->evc_rep_required = FALSE ;
+ else
+ smc->srf.any_report = TRUE ;
+ }
+ else {
+ evc->evc_rep_required = FALSE ;
+ *evc->evc_multiple = FALSE ;
+ }
+ }
+}
+
+extern SMbuf *smt_build_frame() ;
+
+/*
+ * build and send SMT SRF frame
+ */
+static void smt_send_srf(smc)
+struct s_smc *smc ;
+{
+
+ struct smt_header *smt ;
+ struct s_srf_evc *evc ;
+ SK_LOC_DECL(struct s_pcon,pcon) ;
+ SMbuf *mb ;
+ int i ;
+
+ static const struct fddi_addr SMT_SRF_DA = {
+ 0x80, 0x01, 0x43, 0x00, 0x80, 0x08
+ } ;
+
+ /*
+ * build SMT header
+ */
+ if (!smc->r.sm_ma_avail)
+ return ;
+ if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0)))
+ return ;
+
+ RS_SET(smc,RS_SOFTERROR) ;
+
+ smt = smtod(mb, struct smt_header *) ;
+ smt->smt_dest = SMT_SRF_DA ; /* DA == SRF multicast */
+
+ /*
+ * setup parameter status
+ */
+ pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */
+ pcon.pc_err = 0 ; /* no error */
+ pcon.pc_badset = 0 ; /* no bad set count */
+ pcon.pc_p = (void *) (smt + 1) ; /* paras start here */
+
+ smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
+ smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ;
+
+ for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+ if (evc->evc_rep_required) {
+ smt_add_para(smc,&pcon,evc->evc_para,
+ (int)evc->evc_index,0) ;
+ }
+ }
+ smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
+ mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
+
+ DB_SMT("SRF: sending SRF at %x, len %d \n",smt,mb->sm_len) ;
+ DB_SMT("SRF: state SR%d Threshold %d\n",
+ smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ;
+#ifdef DEBUG
+ dump_smt(smc,smt,"SRF Send") ;
+#endif
+ smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
+ clear_reported(smc) ;
+}
+
+#endif /* no BOOT */
+#endif /* no SLIM_SMT */
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 749e8e150..620b1cc46 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -449,7 +449,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
struct slip *sl = (struct slip *) tty->disc_data;
/* First make sure we're connected. */
- if (!sl || sl->magic != SLIP_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) {
+ if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) {
return;
}
if (sl->xleft <= 0) {
@@ -472,10 +472,10 @@ static void sl_tx_timeout(struct net_device *dev)
spin_lock(&sl->lock);
- if (test_bit(LINK_STATE_XOFF, &dev->state)) {
+ if (netif_queue_stopped(dev)) {
struct slip *sl = (struct slip*)(dev->priv);
- if (!test_bit(LINK_STATE_START, &dev->state))
+ if (!netif_running(dev))
goto out;
/* May be we must check transmitter timeout here ?
@@ -507,7 +507,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
struct slip *sl = (struct slip*)(dev->priv);
spin_lock(&sl->lock);
- if (!test_bit(LINK_STATE_START, &dev->state)) {
+ if (!netif_running(dev)) {
spin_unlock(&sl->lock);
printk("%s: xmit call when iface is down\n", dev->name);
dev_kfree_skb(skb);
@@ -679,7 +679,7 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
struct slip *sl = (struct slip *) tty->disc_data;
if (!sl || sl->magic != SLIP_MAGIC ||
- !test_bit(LINK_STATE_START, &sl->dev->state))
+ !netif_running(sl->dev))
return;
/* Read the characters out of the buffer */
@@ -1468,7 +1468,7 @@ static void sl_outfill(unsigned long sls)
unsigned char s = END;
#endif
/* put END into tty queue. Is it right ??? */
- if (!test_bit(LINK_STATE_XOFF, &sl->dev->state))
+ if (!netif_queue_stopped(sl->dev))
{
/* if device busy no outfill */
sl->tty->driver.write(sl->tty, 0, &s, 1);
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 23644ef1d..ab1664fec 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -414,9 +414,8 @@ static int ultramca_close_card(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index 6a5555983..217159ea7 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -403,8 +403,7 @@ ultra_close_card(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 4657500f0..22fdc6505 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -265,9 +265,8 @@ static int ultra32_close(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 944ad87c3..661c1b363 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -50,11 +50,8 @@
static const char *version =
"smc9194.c:v0.12 03/06/96 by Erik Stahlman (erik@vt.edu)\n";
-#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -82,22 +79,6 @@ static const char *version =
-------------------------------------------------------------------------*/
/*
- . this is for kernels > 1.2.70
-*/
-#define REALLY_NEW_KERNEL
-#ifndef REALLY_NEW_KERNEL
-#define free_irq( x, y ) free_irq( x )
-#define request_irq( x, y, z, u, v ) request_irq( x, y, z, u )
-#endif
-
-/*
- . Do you want to use this with old kernels.
- . WARNING: this is not well tested.
-#define SUPPORT_OLD_KERNEL
-*/
-
-
-/*
. Do you want to use 32 bit xfers? This should work on all chips, as
. the chipset is designed to accommodate them.
*/
@@ -108,9 +89,10 @@ static const char *version =
.for a slightly different card, you can add it to the array. Keep in
.mind that the array must end in zero.
*/
-static unsigned int smc_portlist[] __initdata =
- { 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
- 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0};
+static unsigned int smc_portlist[] __initdata = {
+ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
+ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0
+};
/*
. Wait time for memory to be free. This probably shouldn't be
@@ -149,12 +131,6 @@ static unsigned int smc_portlist[] __initdata =
#endif
-/* the older versions of the kernel cannot support autoprobing */
-#ifdef SUPPORT_OLD_KERNEL
-#define NO_AUTOPROBE
-#endif
-
-
/*------------------------------------------------------------------------
.
. The internal workings of the driver. If you are changing anything
@@ -164,9 +140,6 @@ static unsigned int smc_portlist[] __initdata =
-------------------------------------------------------------------------*/
#define CARDNAME "SMC9194"
-#ifdef SUPPORT_OLD_KERNEL
-char kernel_version[] = UTS_RELEASE;
-#endif
/* store this information for the driver.. */
struct smc_local {
@@ -217,6 +190,11 @@ int smc_init(struct net_device *dev);
static int smc_open(struct net_device *dev);
/*
+ . Our watchdog timed out. Called by the networking layer
+*/
+static void smc_timeout(struct net_device *dev);
+
+/*
. This is called by the kernel to send a packet out into the net. it's
. responsible for doing a best-effort send, but if it's simply not possible
. to send it, the packet gets dropped.
@@ -240,12 +218,12 @@ static struct net_device_stats * smc_query_statistics( struct net_device *dev);
. Finally, a call to set promiscuous mode ( for TCPDUMP and related
. programs ) and multicast modes.
*/
-#ifdef SUPPORT_OLD_KERNEL
-static void smc_set_multicast_list(struct net_device *dev, int num_addrs,
- void *addrs);
-#else
static void smc_set_multicast_list(struct net_device *dev);
-#endif
+
+/*
+ . CRC compute
+ */
+static int crc32( char * s, int length );
/*---------------------------------------------------------------
.
@@ -256,11 +234,7 @@ static void smc_set_multicast_list(struct net_device *dev);
/*
. Handles the actual interrupt
*/
-#ifdef REALLY_NEW_KERNEL
static void smc_interrupt(int irq, void *, struct pt_regs *regs);
-#else
-static void smc_interrupt(int irq, struct pt_regs *regs);
-#endif
/*
. This is a separate procedure to handle the receipt of a packet, to
. leave the interrupt code looking slightly cleaner
@@ -321,25 +295,9 @@ static void smc_enable( int ioaddr );
/* this puts the device in an inactive state */
static void smc_shutdown( int ioaddr );
-#ifndef NO_AUTOPROBE
/* This routine will find the IRQ of the driver if one is not
. specified in the input to the device. */
static int smc_findirq( int ioaddr );
-#endif
-
-/*
- this routine will set the hardware multicast table to the specified
- values given it by the higher level routines
-*/
-#ifndef SUPPORT_OLD_KERNEL
-static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * );
-static int crc32( char *, int );
-#endif
-
-#ifdef SUPPORT_OLD_KERNEL
-extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_private,
- unsigned long *mem_startp );
-#endif
/*
. Function: smc_reset( int ioaddr )
@@ -442,7 +400,6 @@ static void smc_shutdown( int ioaddr )
}
-#ifndef SUPPORT_OLD_KERNEL
/*
. Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
. Purpose:
@@ -525,8 +482,6 @@ static int crc32( char * s, int length ) {
return crc_value;
}
-#endif
-
/*
. Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
@@ -575,6 +530,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
dev_kfree_skb (skb);
lp->saved_skb = NULL;
/* this IS an error, but, i don't want the skb saved */
+ netif_wake_queue(dev);
return 0;
}
/* either way, a packet is waiting now */
@@ -616,7 +572,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
}
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
-
+ netif_wake_queue(dev);
return 0;
}
@@ -663,7 +619,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
kfree(skb);
lp->saved_skb = NULL;
- dev->tbusy = 0;
+ netif_wake_queue(dev);
return;
}
@@ -729,8 +685,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
dev->trans_start = jiffies;
/* we can send another packet */
- dev->tbusy = 0;
-
+ netif_wake_queue(dev);
return;
}
@@ -787,7 +742,6 @@ int __init smc_init(struct net_device *dev)
return -ENODEV;
}
-#ifndef NO_AUTOPROBE
/*----------------------------------------------------------------------
. smc_findirq
.
@@ -860,7 +814,6 @@ int __init smc_findirq( int ioaddr )
/* and return what I found */
return autoirq_report( 0 );
}
-#endif
/*----------------------------------------------------------------------
. Function: smc_probe( int ioaddr )
@@ -962,14 +915,7 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
/* see if I need to initialize the ethernet card structure */
if (dev == NULL) {
-#ifdef SUPPORT_OLD_KERNEL
-#ifndef MODULE
-/* note: the old module interface does not support this call */
- dev = init_etherdev( 0, sizeof( struct smc_local ), 0 );
-#endif
-#else
dev = init_etherdev(0, 0);
-#endif
if (dev == NULL)
return -ENOMEM;
}
@@ -1043,7 +989,6 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
. what (s)he is doing. No checking is done!!!!
.
*/
-#ifndef NO_AUTOPROBE
if ( dev->irq < 2 ) {
int trials;
@@ -1060,13 +1005,6 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n");
return -ENODEV;
}
-#else
- if (dev->irq == 0 ) {
- printk(CARDNAME
- ": Autoprobing IRQs is not supported for old kernels.\n");
- return -ENODEV;
- }
-#endif
if (dev->irq == 2) {
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
* or don't know which one to set.
@@ -1114,10 +1052,10 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
dev->open = smc_open;
dev->stop = smc_close;
dev->hard_start_xmit = smc_send_packet;
+ dev->tx_timeout = smc_timeout;
+ dev->watchdog_timeo = HZ/20;
dev->get_stats = smc_query_statistics;
-#ifdef HAVE_MULTICAST
- dev->set_multicast_list = &smc_set_multicast_list;
-#endif
+ dev->set_multicast_list = smc_set_multicast_list;
return 0;
}
@@ -1174,12 +1112,7 @@ static int smc_open(struct net_device *dev)
/* clear out all the junk that was put here before... */
memset(dev->priv, 0, sizeof(struct smc_local));
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-#ifdef MODULE
MOD_INC_USE_COUNT;
-#endif
/* reset the hardware */
@@ -1211,6 +1144,8 @@ static int smc_open(struct net_device *dev)
address |= dev->dev_addr[ i ];
outw( address, ioaddr + ADDR0 + i );
}
+
+ netif_start_queue(dev);
return 0;
}
@@ -1220,38 +1155,29 @@ static int smc_open(struct net_device *dev)
. skeleton.c, from Becker.
.--------------------------------------------------------
*/
-static int smc_send_packet(struct sk_buff *skb, struct net_device *dev)
+
+static void smc_timeout(struct net_device *dev)
{
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",
- tx_done(dev) ? "IRQ conflict" :
- "network cable problem");
- /* "kick" the adaptor */
- smc_reset( dev->base_addr );
- smc_enable( dev->base_addr );
-
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- /* clear anything saved */
- ((struct smc_local *)dev->priv)->saved_skb = NULL;
- }
+ /* If we get here, some higher level has decided we are broken.
+ There should really be a "kick me" function call instead. */
+ printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",
+ tx_done(dev) ? "IRQ conflict" :
+ "network cable problem");
+ /* "kick" the adaptor */
+ smc_reset( dev->base_addr );
+ smc_enable( dev->base_addr );
+ dev->trans_start = jiffies;
+ /* clear anything saved */
+ ((struct smc_local *)dev->priv)->saved_skb = NULL;
+ netif_wake_queue(dev);
+}
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n");
- dev_kfree_skb (skb);
- } else {
- /* Well, I want to send the packet.. but I don't know
- if I can send it right now... */
- return smc_wait_to_send_packet( skb, dev );
- }
- return 0;
+static int smc_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ /* Well, I want to send the packet.. but I don't know
+ if I can send it right now... */
+ return smc_wait_to_send_packet( skb, dev );
}
/*--------------------------------------------------------------------
@@ -1266,11 +1192,8 @@ static int smc_send_packet(struct sk_buff *skb, struct net_device *dev)
. and finally restore state.
.
---------------------------------------------------------------------*/
-#ifdef REALLY_NEW_KERNEL
+
static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
-#else
-static void smc_interrupt(int irq, struct pt_regs * regs)
-#endif
{
struct net_device *dev = dev_id;
int ioaddr = dev->base_addr;
@@ -1288,20 +1211,6 @@ static void smc_interrupt(int irq, struct pt_regs * regs)
PRINTK3((CARDNAME": SMC interrupt started \n"));
- if (dev == NULL) {
- printk(KERN_WARNING CARDNAME": irq %d for unknown device.\n",
- irq);
- return;
- }
-
-/* will Linux let this happen ?? If not, this costs some speed */
- if ( dev->interrupt ) {
- printk(KERN_WARNING CARDNAME": interrupt inside interrupt.\n");
- return;
- }
-
- dev->interrupt = 1;
-
saved_bank = inw( ioaddr + BANK_SELECT );
SMC_SELECT_BANK(2);
@@ -1346,12 +1255,7 @@ static void smc_interrupt(int irq, struct pt_regs * regs)
lp->stats.collisions += card_stats & 0xF;
/* these are for when linux supports these statistics */
-#if 0
- card_stats >>= 4;
- /* deferred */
- card_stats >>= 4;
- /* excess deferred */
-#endif
+
SMC_SELECT_BANK( 2 );
PRINTK2((KERN_WARNING CARDNAME
": TX_BUFFER_EMPTY handled\n"));
@@ -1372,8 +1276,8 @@ static void smc_interrupt(int irq, struct pt_regs * regs)
mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
/* and let the card send more packets to me */
- mark_bh( NET_BH );
-
+ netif_wake_queue(dev);
+
PRINTK2((CARDNAME": Handoff done successfully.\n"));
} else if (status & IM_RX_OVRN_INT ) {
lp->stats.rx_errors++;
@@ -1397,7 +1301,6 @@ static void smc_interrupt(int irq, struct pt_regs * regs)
SMC_SELECT_BANK( saved_bank );
- dev->interrupt = 0;
PRINTK3((CARDNAME ": Interrupt done\n"));
return;
}
@@ -1462,11 +1365,7 @@ static void smc_rcv(struct net_device *dev)
if ( status & RS_MULTICAST )
lp->stats.multicast++;
-#ifdef SUPPORT_OLD_KERNEL
- skb = alloc_skb( packet_length + 5, GFP_ATOMIC );
-#else
skb = dev_alloc_skb( packet_length + 5);
-#endif
if ( skb == NULL ) {
printk(KERN_NOTICE CARDNAME
@@ -1478,18 +1377,12 @@ static void smc_rcv(struct net_device *dev)
! This should work without alignment, but it could be
! in the worse case
*/
-#ifndef SUPPORT_OLD_KERNEL
- /* TODO: Should I use 32bit alignment here ? */
+
skb_reserve( skb, 2 ); /* 16 bit alignment */
-#endif
skb->dev = dev;
-#ifdef SUPPORT_OLD_KERNEL
- skb->len = packet_length;
- data = skb->data;
-#else
data = skb_put( skb, packet_length);
-#endif
+
#ifdef USE_32_BIT
/* QUESTION: Like in the TX routine, do I want
to send the DWORDs or the bytes first, or some
@@ -1516,9 +1409,7 @@ static void smc_rcv(struct net_device *dev)
print_packet( data, packet_length );
#endif
-#ifndef SUPPORT_OLD_KERNEL
skb->protocol = eth_type_trans(skb, dev );
-#endif
netif_rx(skb);
lp->stats.rx_packets++;
} else {
@@ -1616,17 +1507,12 @@ static void smc_tx( struct net_device * dev )
-----------------------------------------------------*/
static int smc_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
/* clear everything */
smc_shutdown( dev->base_addr );
/* Update the statistics here. */
-#ifdef MODULE
MOD_DEC_USE_COUNT;
-#endif
-
return 0;
}
@@ -1648,21 +1534,12 @@ static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
. promiscuous mode ( for TCPDUMP and cousins ) or accept
. a select set of multicast packets
*/
-#ifdef SUPPORT_OLD_KERNEL
-static void smc_set_multicast_list( struct net_device * dev,
- int num_addrs, void * addrs )
-#else
static void smc_set_multicast_list(struct net_device *dev)
-#endif
{
short ioaddr = dev->base_addr;
SMC_SELECT_BANK(0);
-#ifdef SUPPORT_OLD_KERNEL
- if ( num_addrs < 0 )
-#else
if ( dev->flags & IFF_PROMISC )
-#endif
outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR );
/* BUG? I never disable promiscuous mode if multicasting was turned on.
@@ -1674,27 +1551,12 @@ static void smc_set_multicast_list(struct net_device *dev)
I don't need to zero the multicast table, because the flag is
checked before the table is
*/
-#ifdef SUPPORT_OLD_KERNEL
- else if ( num_addrs > 20 ) /* arbitrary constant */
-#else
else if (dev->flags & IFF_ALLMULTI)
-#endif
outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR );
/* We just get all multicast packets even if we only want them
. from one source. This will be changed at some future
. point. */
-#ifdef SUPPORT_OLD_KERNEL
- else if (num_addrs > 0 ) {
-/* the old kernel support will not have hardware multicast support. It would
- involve more kludges, and make the multicast setting code even worse.
- Instead, just use the ALMUL method. This is reasonable, considering that
- it is seldom used
-*/
- outw( inw( ioaddr + RCR ) & ~RCR_PROMISC, ioaddr + RCR );
- outw( inw( ioadddr + RCR ) | RCR_ALMUL, ioadddr + RCR );
- }
-#else
else if (dev->mc_count ) {
/* support hardware multicasting */
@@ -1705,7 +1567,6 @@ static void smc_set_multicast_list(struct net_device *dev)
last thing called. The bank is set to zero at the top */
smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
}
-#endif
else {
outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
ioaddr + RCR );
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 30e9e5b3d..de0856020 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -813,7 +813,7 @@ static void init_ring(struct net_device *dev)
np->rx_info[i].skb = skb;
if (skb == NULL)
break;
- np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz);
+ np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb->dev = dev; /* Mark as being used by this device. */
/* Grrr, we cannot offset to correctly align the IP header. */
np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid);
@@ -859,7 +859,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np->tx_info[entry].skb = skb;
np->tx_info[entry].mapping =
- pci_map_single(np->pdev, skb->data, skb->len);
+ pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping);
/* Add |TxDescIntr to generate Tx-done interrupts. */
@@ -959,10 +959,10 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
skb = np->tx_info[entry].skb;
pci_unmap_single(np->pdev,
np->tx_info[entry].mapping,
- skb->len);
+ skb->len, PCI_DMA_TODEVICE);
/* Scavenge the descriptor. */
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
np->tx_info[entry].skb = NULL;
np->tx_info[entry].mapping = 0;
np->dirty_tx++;
@@ -1044,7 +1044,7 @@ static int netdev_rx(struct net_device *dev)
skb_reserve(skb, 2); /* 16 byte align the IP header */
pci_dma_sync_single(np->pdev,
np->rx_info[entry].mapping,
- pkt_len);
+ pkt_len, PCI_DMA_FROMDEVICE);
#if HAS_IP_COPYSUM /* Call copy + cksum if available. */
eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
skb_put(skb, pkt_len);
@@ -1055,7 +1055,7 @@ static int netdev_rx(struct net_device *dev)
} else {
char *temp;
- pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz);
+ pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb = np->rx_info[entry].skb;
temp = skb_put(skb, pkt_len);
np->rx_info[entry].skb = NULL;
@@ -1099,7 +1099,7 @@ static int netdev_rx(struct net_device *dev)
if (skb == NULL)
break; /* Better luck next round. */
np->rx_info[entry].mapping =
- pci_map_single(np->pdev, skb->tail, np->rx_buf_sz);
+ pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb->dev = dev; /* Mark as being used by this device. */
np->rx_ring[entry].rxaddr =
cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
@@ -1324,8 +1324,8 @@ static int netdev_close(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
if (np->rx_info[i].skb != NULL) {
- pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz);
- kfree_skb(np->rx_info[i].skb);
+ pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(np->rx_info[i].skb);
}
np->rx_info[i].skb = NULL;
np->rx_info[i].mapping = 0;
@@ -1335,8 +1335,8 @@ static int netdev_close(struct net_device *dev)
if (skb != NULL) {
pci_unmap_single(np->pdev,
np->tx_info[i].mapping,
- skb->len);
- kfree_skb(skb);
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
}
np->tx_info[i].skb = NULL;
np->tx_info[i].mapping = 0;
diff --git a/drivers/net/strip.c b/drivers/net/strip.c
index 2f3eb9076..0d754ed31 100644
--- a/drivers/net/strip.c
+++ b/drivers/net/strip.c
@@ -1036,9 +1036,7 @@ static void strip_unlock(struct strip *strip_info)
*/
strip_info->idle_timer.expires = jiffies + 1*HZ;
add_timer(&strip_info->idle_timer);
- if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy))
- printk(KERN_ERR "%s: trying to unlock already unlocked device!\n",
- strip_info->dev.name);
+ netif_wake_queue(&strip_info->dev);
}
@@ -1355,7 +1353,8 @@ static void strip_write_some_more(struct tty_struct *tty)
struct strip *strip_info = (struct strip *) tty->disc_data;
/* First make sure we're connected. */
- if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start)
+ if (!strip_info || strip_info->magic != STRIP_MAGIC ||
+ !netif_running(&strip_info->dev))
return;
if (strip_info->tx_left > 0)
@@ -1387,7 +1386,6 @@ static void strip_write_some_more(struct tty_struct *tty)
{
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
strip_unlock(strip_info);
- mark_bh(NET_BH);
}
}
@@ -1646,12 +1644,14 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct strip *strip_info = (struct strip *)(dev->priv);
- if (!dev->start)
+ if (!netif_running(dev))
{
printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name);
return(1);
}
- if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
+
+ netif_stop_queue(dev);
+
del_timer(&strip_info->idle_timer);
/* See if someone has been ifconfigging */
@@ -1687,7 +1687,8 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
strip_send(strip_info, skb);
- if (skb) dev_kfree_skb(skb);
+ if (skb)
+ dev_kfree_skb(skb);
return(0);
}
@@ -2336,7 +2337,8 @@ strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int
struct strip *strip_info = (struct strip *) tty->disc_data;
const unsigned char *end = cp + count;
- if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start)
+ if (!strip_info || strip_info->magic != STRIP_MAGIC
+ || !netif_running(&strip_info->dev))
return;
/* Argh! mtu change time! - costs us the packet part received at the change */
@@ -2507,13 +2509,11 @@ static int strip_open_low(struct net_device *dev)
if (in_dev->ifa_list->ifa_address == 0)
in_dev->ifa_list->ifa_address = ntohl(0xC0A80001);
#endif
- dev->tbusy = 0;
- dev->start = 1;
-
printk(KERN_INFO "%s: Initializing Radio.\n", strip_info->dev.name);
ResetRadio(strip_info);
strip_info->idle_timer.expires = jiffies + 1*HZ;
add_timer(&strip_info->idle_timer);
+ netif_wake_queue(dev);
return(0);
}
@@ -2529,9 +2529,9 @@ static int strip_close_low(struct net_device *dev)
if (strip_info->tty == NULL)
return -EBUSY;
strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
+
/*
* Free all STRIP frame buffers.
*/
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 11efd3d4d..6a773b66d 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.14 2000/02/09 11:15:35 davem Exp $
+/* $Id: sunbmac.c,v 1.18 2000/02/18 13:49:21 davem Exp $
* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -190,20 +190,14 @@ static void bigmac_clean_rings(struct bigmac *bp)
for (i = 0; i < RX_RING_SIZE; i++) {
if (bp->rx_skbs[i] != NULL) {
- if (in_irq())
- dev_kfree_skb_irq(bp->rx_skbs[i]);
- else
- dev_kfree_skb(bp->rx_skbs[i]);
+ dev_kfree_skb_any(bp->rx_skbs[i]);
bp->rx_skbs[i] = NULL;
}
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (bp->tx_skbs[i] != NULL) {
- if (in_irq())
- dev_kfree_skb_irq(bp->tx_skbs[i]);
- else
- dev_kfree_skb(bp->tx_skbs[i]);
+ dev_kfree_skb_any(bp->tx_skbs[i]);
bp->tx_skbs[i] = NULL;
}
}
@@ -240,7 +234,8 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq)
bb->be_rxd[i].rx_addr =
sbus_map_single(bp->bigmac_sdev, skb->data,
- RX_BUF_ALLOC_SIZE - 34);
+ RX_BUF_ALLOC_SIZE - 34,
+ SBUS_DMA_FROMDEVICE);
bb->be_rxd[i].rx_flags =
(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
}
@@ -776,7 +771,8 @@ static void bigmac_tx(struct bigmac *bp)
bp->enet_stats.tx_packets++;
bp->enet_stats.tx_bytes += skb->len;
sbus_unmap_single(bp->bigmac_sdev,
- this->tx_addr, skb->len);
+ this->tx_addr, skb->len,
+ SBUS_DMA_TODEVICE);
DTX(("skb(%p) ", skb));
bp->tx_skbs[elem] = NULL;
@@ -787,7 +783,7 @@ static void bigmac_tx(struct bigmac *bp)
DTX((" DONE, tx_old=%d\n", elem));
bp->tx_old = elem;
- if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+ if (netif_queue_stopped(dev) &&
TX_BUFFS_AVAIL(bp) > 0)
netif_wake_queue(bp->dev);
@@ -831,14 +827,16 @@ static void bigmac_rx(struct bigmac *bp)
}
sbus_unmap_single(bp->bigmac_sdev,
this->rx_addr,
- RX_BUF_ALLOC_SIZE - 34);
+ RX_BUF_ALLOC_SIZE - 34,
+ SBUS_DMA_FROMDEVICE);
bp->rx_skbs[elem] = new_skb;
new_skb->dev = bp->dev;
skb_put(new_skb, ETH_FRAME_LEN);
skb_reserve(new_skb, 34);
this->rx_addr = sbus_map_single(bp->bigmac_sdev,
new_skb->data,
- RX_BUF_ALLOC_SIZE - 34);
+ RX_BUF_ALLOC_SIZE - 34,
+ SBUS_DMA_FROMDEVICE);
this->rx_flags =
(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
@@ -855,7 +853,7 @@ static void bigmac_rx(struct bigmac *bp)
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
sbus_dma_sync_single(bp->bigmac_sdev,
- this->rx_addr, len);
+ this->rx_addr, len, SBUS_DMA_FROMDEVICE);
eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);
/* Reuse original ring buffer. */
@@ -951,7 +949,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 mapping;
len = skb->len;
- mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len);
+ mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);
/* Avoid a race... */
spin_lock_irq(&bp->lock);
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 8766c1dc4..344e682f8 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.86 2000/02/09 11:15:36 davem Exp $
+/* $Id: sunhme.c,v 1.92 2000/02/18 13:49:22 davem Exp $
* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -152,6 +152,13 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp)
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
+/* NOTE: In the descriptor writes one _must_ write the address
+ * member _first_. The card must not be allowed to see
+ * the updated descriptor flags until the address is
+ * correct. I've added a write memory barrier between
+ * the two stores so that I can sleep well at night... -DaveM
+ */
+
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
static void sbus_hme_write32(unsigned long reg, u32 val)
{
@@ -166,13 +173,15 @@ static u32 sbus_hme_read32(unsigned long reg)
static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
{
rxd->rx_addr = addr;
+ wmb();
rxd->rx_flags = flags;
}
static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
{
- txd->tx_flags = flags;
txd->tx_addr = addr;
+ wmb();
+ txd->tx_flags = flags;
}
static u32 sbus_hme_read_desc32(u32 *p)
@@ -193,18 +202,20 @@ static u32 pci_hme_read32(unsigned long reg)
static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
{
rxd->rx_addr = cpu_to_le32(addr);
+ wmb();
rxd->rx_flags = cpu_to_le32(flags);
}
static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
{
- txd->tx_flags = cpu_to_le32(flags);
txd->tx_addr = cpu_to_le32(addr);
+ wmb();
+ txd->tx_flags = cpu_to_le32(flags);
}
static u32 pci_hme_read_desc32(u32 *p)
{
- return cpu_to_le32(*p);
+ return cpu_to_le32p(p);
}
#define hme_write32(__hp, __reg, __val) \
@@ -217,12 +228,12 @@ static u32 pci_hme_read_desc32(u32 *p)
((__hp)->write_txd((__txd), (__flags), (__addr)))
#define hme_read_desc32(__hp, __p) \
((__hp)->read_desc32(__p))
-#define hme_dma_map(__hp, __ptr, __size) \
- ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size)))
-#define hme_dma_unmap(__hp, __addr, __size) \
- ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size)))
-#define hme_dma_sync(__hp, __addr, __size) \
- ((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size)))
+#define hme_dma_map(__hp, __ptr, __size, __dir) \
+ ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
+#define hme_dma_unmap(__hp, __addr, __size, __dir) \
+ ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
+#define hme_dma_sync(__hp, __addr, __size, __dir) \
+ ((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size), (__dir)))
#else
#ifdef CONFIG_SBUS
/* SBUS only compilation */
@@ -232,19 +243,21 @@ static u32 pci_hme_read_desc32(u32 *p)
sbus_readl(__reg)
#define hme_write_rxd(__hp, __rxd, __flags, __addr) \
do { (__rxd)->rx_addr = (__addr); \
+ wmb(); \
(__rxd)->rx_flags = (__flags); \
} while(0)
#define hme_write_txd(__hp, __txd, __flags, __addr) \
do { (__txd)->tx_addr = (__addr); \
+ wmb(); \
(__txd)->tx_flags = (__flags); \
} while(0)
#define hme_read_desc32(__hp, __p) (*(__p))
-#define hme_dma_map(__hp, __ptr, __size) \
- sbus_map_single((__hp)->happy_dev, (__ptr), (__size))
+#define hme_dma_map(__hp, __ptr, __size, __dir) \
+ sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
#define hme_dma_unmap(__hp, __addr, __size) \
- sbus_unmap_single((__hp)->happy_dev, (__addr), (__size))
-#define hme_dma_sync(__hp, __addr, __size) \
- sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size))
+ sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync(__hp, __addr, __size, __dir) \
+ sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir))
#else
/* PCI only compilation */
#define hme_write32(__hp, __reg, __val) \
@@ -253,22 +266,28 @@ do { (__txd)->tx_addr = (__addr); \
readl(__reg)
#define hme_write_rxd(__hp, __rxd, __flags, __addr) \
do { (__rxd)->rx_addr = cpu_to_le32(__addr); \
+ wmb(); \
(__rxd)->rx_flags = cpu_to_le32(__flags); \
} while(0)
#define hme_write_txd(__hp, __txd, __flags, __addr) \
do { (__txd)->tx_addr = cpu_to_le32(__addr); \
+ wmb(); \
(__txd)->tx_flags = cpu_to_le32(__flags); \
} while(0)
-#define hme_read_desc32(__hp, __p) cpu_to_le32(*(__p))
-#define hme_dma_map(__hp, __ptr, __size) \
- pci_map_single((__hp)->happy_dev, (__ptr), (__size))
-#define hme_dma_unmap(__hp, __addr, __size) \
- pci_unmap_single((__hp)->happy_dev, (__addr), (__size))
-#define hme_dma_sync(__hp, __addr, __size) \
- pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size))
+#define hme_read_desc32(__hp, __p) cpu_to_le32p(__p)
+#define hme_dma_map(__hp, __ptr, __size, __dir) \
+ pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+#define hme_dma_unmap(__hp, __addr, __size, __dir) \
+ pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+#define hme_dma_sync(__hp, __addr, __size, __dir) \
+ pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir))
#endif
#endif
+#define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL
+#define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE
+#define DMA_TODEVICE SBUS_DMA_TODEVICE
+
/* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */
static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit)
{
@@ -1193,11 +1212,8 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
rxd = &hp->happy_block->happy_meal_rxd[i];
dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
- hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE);
- if (in_irq())
- dev_kfree_skb_irq(skb);
- else
- dev_kfree_skb(skb);
+ hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
hp->rx_skbs[i] = NULL;
}
}
@@ -1210,11 +1226,8 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
txd = &hp->happy_block->happy_meal_txd[i];
dma_addr = hme_read_desc32(hp, &txd->tx_addr);
- hme_dma_unmap(hp, dma_addr, skb->len);
- if (in_irq())
- dev_kfree_skb_irq(skb);
- else
- dev_kfree_skb(skb);
+ hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
hp->tx_skbs[i] = NULL;
}
}
@@ -1253,7 +1266,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
hme_write_rxd(hp, &hb->happy_meal_rxd[i],
(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),
- hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE));
+ hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
skb_reserve(skb, RX_OFFSET);
}
@@ -1895,7 +1908,7 @@ static void happy_meal_tx(struct happy_meal *hp)
break;
dma_addr = hme_read_desc32(hp, &this->tx_addr);
skb = hp->tx_skbs[elem];
- hme_dma_unmap(hp, dma_addr, skb->len);
+ hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);
hp->tx_skbs[elem] = NULL;
hp->net_stats.tx_bytes += skb->len;
@@ -1907,7 +1920,7 @@ static void happy_meal_tx(struct happy_meal *hp)
hp->tx_old = elem;
TXD((">"));
- if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+ if (netif_queue_stopped(dev) &&
TX_BUFFS_AVAIL(hp) > 0)
netif_wake_queue(dev);
@@ -1973,13 +1986,13 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
drops++;
goto drop_it;
}
- hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE);
+ hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
hp->rx_skbs[elem] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
hme_write_rxd(hp, this,
(RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
- hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE));
+ hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
skb_reserve(new_skb, RX_OFFSET);
/* Trim the original skb for the netif. */
@@ -1995,7 +2008,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
copy_skb->dev = dev;
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
- hme_dma_sync(hp, dma_addr, len);
+ hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE);
memcpy(copy_skb->data, skb->data, len);
/* Reuse original ring buffer. */
@@ -2178,7 +2191,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 mapping;
len = skb->len;
- mapping = hme_dma_map(hp, skb->data, len);
+ mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
spin_lock_irq(&hp->happy_lock);
@@ -2192,10 +2205,11 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(hp) <= 0)
netif_stop_queue(dev);
- spin_unlock_irq(&hp->happy_lock);
-
/* Get it going. */
hme_write32(hp, hp->etxregs + ETX_PENDING, ETX_TP_DMAWAKEUP);
+
+ spin_unlock_irq(&hp->happy_lock);
+
dev->trans_start = jiffies;
tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
@@ -2642,9 +2656,9 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
hp->read_desc32 = sbus_hme_read_desc32;
hp->write_txd = sbus_hme_write_txd;
hp->write_rxd = sbus_hme_write_rxd;
- hp->dma_map = (u32 (*)(void *, void *, long))sbus_map_single;
- hp->dma_unmap = (void (*)(void *, u32, long))sbus_unmap_single;
- hp->dma_sync = (void (*)(void *, u32, long))sbus_dma_sync_single;
+ hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single;
+ hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single;
+ hp->dma_sync = (void (*)(void *, u32, long, int))sbus_dma_sync_single;
hp->read32 = sbus_hme_read32;
hp->write32 = sbus_hme_write32;
#endif
@@ -2817,9 +2831,9 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
hp->read_desc32 = pci_hme_read_desc32;
hp->write_txd = pci_hme_write_txd;
hp->write_rxd = pci_hme_write_rxd;
- hp->dma_map = (u32 (*)(void *, void *, long))pci_map_single;
- hp->dma_unmap = (void (*)(void *, u32, long))pci_unmap_single;
- hp->dma_sync = (void (*)(void *, u32, long))pci_dma_sync_single;
+ hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single;
+ hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single;
+ hp->dma_sync = (void (*)(void *, u32, long, int))pci_dma_sync_single;
hp->read32 = pci_hme_read32;
hp->write32 = pci_hme_write32;
#endif
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 3708515e3..57b5d7f5e 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -1,4 +1,4 @@
-/* $Id: sunhme.h,v 1.29 2000/02/09 11:15:40 davem Exp $
+/* $Id: sunhme.h,v 1.30 2000/02/18 13:49:26 davem Exp $
* sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver.
* Also known as the "Happy Meal".
*
@@ -502,9 +502,9 @@ struct happy_meal {
u32 (*read_desc32)(u32 *);
void (*write_txd)(struct happy_meal_txd *, u32, u32);
void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
- u32 (*dma_map)(void *, void *, long);
- void (*dma_unmap)(void *, u32, long);
- void (*dma_sync)(void *, u32, long);
+ u32 (*dma_map)(void *, void *, long, int);
+ void (*dma_unmap)(void *, u32, long, int);
+ void (*dma_sync)(void *, u32, long, int);
#endif
/* This is either a sbus_dev or a pci_dev. */
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index c7630dba3..e17304fd0 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.94 2000/02/09 11:15:40 davem Exp $
+/* $Id: sunlance.c,v 1.99 2000/02/16 10:36:14 davem Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
@@ -602,7 +602,7 @@ static void lance_tx_dvma(struct net_device *dev)
lp->init_ring(dev);
load_csrs(lp);
init_restart_lance(lp);
- return;
+ goto out;
}
}
@@ -618,7 +618,7 @@ static void lance_tx_dvma(struct net_device *dev)
lp->init_ring(dev);
load_csrs(lp);
init_restart_lance(lp);
- return;
+ goto out;
}
} else if ((bits & LE_T1_POK) == LE_T1_POK) {
/*
@@ -640,8 +640,8 @@ static void lance_tx_dvma(struct net_device *dev)
j = TX_NEXT(j);
}
lp->tx_old = j;
-
- if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+out:
+ if (netif_queue_stopped(dev) &&
TX_BUFFS_AVAIL > 0)
netif_wake_queue(dev);
@@ -773,7 +773,7 @@ static void lance_tx_pio(struct net_device *dev)
lp->init_ring(dev);
load_csrs(lp);
init_restart_lance(lp);
- return;
+ goto out;
}
}
@@ -789,7 +789,7 @@ static void lance_tx_pio(struct net_device *dev)
lp->init_ring(dev);
load_csrs(lp);
init_restart_lance(lp);
- return;
+ goto out;
}
} else if ((bits & LE_T1_POK) == LE_T1_POK) {
/*
@@ -812,10 +812,10 @@ static void lance_tx_pio(struct net_device *dev)
}
lp->tx_old = j;
- if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+ if (netif_queue_stopped(dev) &&
TX_BUFFS_AVAIL > 0)
netif_wake_queue(dev);
-
+out:
spin_unlock(&lp->lock);
}
@@ -1014,7 +1014,7 @@ static int lance_reset(struct net_device *dev)
return status;
}
-static void lance_piocopy_from_skb(volatile void *dest, char *src, int len)
+static void lance_piocopy_from_skb(volatile void *dest, unsigned char *src, int len)
{
unsigned long piobuf = (unsigned long) dest;
u32 *p32;
@@ -1128,10 +1128,10 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
- lp->stats.tx_bytes += len;
-
spin_lock_irq(&lp->lock);
+ lp->stats.tx_bytes += len;
+
entry = lp->tx_new & TX_RING_MOD_MASK;
if (lp->pio_buffer) {
sbus_writew((-len) | 0xf000, &ib->btx_ring[entry].length);
@@ -1154,19 +1154,20 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL <= 0)
netif_stop_queue(dev);
- spin_unlock_irq(&lp->lock);
-
/* Kick the lance: transmit now */
sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP);
- dev->trans_start = jiffies;
- dev_kfree_skb(skb);
-
+
/* Read back CSR to invalidate the E-Cache.
* This is needed, because DMA_DSBL_WR_INV is set.
*/
if (lp->dregs)
sbus_readw(lp->lregs + RDP);
+ spin_unlock_irq(&lp->lock);
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb);
+
return 0;
}
@@ -1246,7 +1247,7 @@ static void lance_set_multicast(struct net_device *dev)
volatile struct lance_init_block *ib = lp->init_block;
u16 mode;
- if (!test_bit(LINK_STATE_START, &dev->state))
+ if (!netif_running(dev))
return;
if (lp->tx_old != lp->tx_new) {
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index ed538b5a7..62fac115f 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.43 2000/02/09 21:11:19 davem Exp $
+/* $Id: sunqe.c,v 1.45 2000/02/16 10:36:20 davem Exp $
* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
@@ -481,7 +481,7 @@ static void qec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (qe_status & CREG_STAT_RXIRQ)
qe_rx(qep);
- if (test_bit(LINK_STATE_XOFF, &qep->dev->state) &&
+ if (netif_queue_stopped(qep->dev) &&
(qe_status & CREG_STAT_TXIRQ)) {
spin_lock(&qep->lock);
qe_tx_reclaim(qep);
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 9b21a13ea..a699391da 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -62,6 +62,10 @@
* driver (almost)
* - Other minor stuff
*
+ * v1.4 Feb 10, 2000 - Updated with more changes required after Dave's
+ * network cleanup in 2.3.43pre7 (Tigran & myself)
+ * - Minor stuff.
+ *
*******************************************************************************/
@@ -102,7 +106,7 @@ static int bbuf = 0;
static u8 *TLanPadBuffer;
static char TLanSignature[] = "TLAN";
static int TLanVersionMajor = 1;
-static int TLanVersionMinor = 3;
+static int TLanVersionMinor = 4;
static TLanAdapterEntry TLanAdapterList[] __initdata = {
@@ -361,7 +365,7 @@ static int __init tlan_probe(void)
u32 io_base, index;
int found;
- printk(KERN_INFO "ThunderLAN driver v%d.%d:\n",
+ printk(KERN_INFO "ThunderLAN driver v%d.%d\n",
TLanVersionMajor,
TLanVersionMinor);
@@ -461,7 +465,7 @@ module_exit(tlan_exit);
*
**************************************************************/
-int TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
+static int __init TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
{
static int dl_index = 0;
static struct pci_dev * pdev = NULL;
@@ -626,7 +630,7 @@ static int TLan_Init( struct net_device *dev )
*
**************************************************************/
-int TLan_Open( struct net_device *dev )
+static int TLan_Open( struct net_device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
int err;
@@ -642,7 +646,7 @@ int TLan_Open( struct net_device *dev )
}
netif_start_queue(dev);
-
+
/* NOTE: It might not be necessary to read the stats before a
reset if you don't care what the values are.
*/
@@ -680,7 +684,7 @@ int TLan_Open( struct net_device *dev )
*
**************************************************************/
-int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
+static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
TLanList *tail_list;
@@ -690,7 +694,7 @@ int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
if ( ! priv->phyOnline ) {
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name );
- dev_kfree_skb( skb );
+ dev_kfree_skb_any(skb);
return 0;
}
@@ -747,9 +751,8 @@ int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
- if ( bbuf ) {
- dev_kfree_skb( skb );
- }
+ if ( bbuf )
+ dev_kfree_skb_any(skb);
dev->trans_start = jiffies;
return 0;
@@ -780,7 +783,7 @@ int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
*
**************************************************************/
-void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
{
u32 ack;
struct net_device *dev;
@@ -828,7 +831,7 @@ void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
*
**************************************************************/
-int TLan_Close(struct net_device *dev)
+static int TLan_Close(struct net_device *dev)
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
@@ -866,7 +869,7 @@ int TLan_Close(struct net_device *dev)
*
**************************************************************/
-struct net_device_stats *TLan_GetStats( struct net_device *dev )
+static struct net_device_stats *TLan_GetStats( struct net_device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
int i;
@@ -914,7 +917,7 @@ struct net_device_stats *TLan_GetStats( struct net_device *dev )
*
**************************************************************/
-void TLan_SetMulticastList( struct net_device *dev )
+static void TLan_SetMulticastList( struct net_device *dev )
{
struct dev_mc_list *dmi = dev->mc_list;
u32 hash1 = 0;
@@ -1033,7 +1036,7 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
head_list = priv->txList + priv->txHead;
if ( ! bbuf ) {
- dev_kfree_skb( (struct sk_buff *) head_list->buffer[9].address );
+ dev_kfree_skb_irq( (struct sk_buff *) head_list->buffer[9].address );
head_list->buffer[9].address = 0;
}
@@ -1046,7 +1049,9 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
priv->stats.tx_bytes += head_list->frameSize;
head_list->cStat = TLAN_CSTAT_UNUSED;
+
netif_start_queue(dev);
+
CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
if ( eoc ) {
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
@@ -1614,7 +1619,7 @@ void TLan_FreeLists( struct net_device *dev )
list = priv->txList + i;
skb = (struct sk_buff *) list->buffer[9].address;
if ( skb ) {
- dev_kfree_skb( skb );
+ dev_kfree_skb_any( skb );
list->buffer[9].address = 0;
}
}
@@ -1623,7 +1628,7 @@ void TLan_FreeLists( struct net_device *dev )
list = priv->rxList + i;
skb = (struct sk_buff *) list->buffer[9].address;
if ( skb ) {
- dev_kfree_skb( skb );
+ dev_kfree_skb_any( skb );
list->buffer[9].address = 0;
}
}
@@ -2413,6 +2418,7 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
*val = tmp;
spin_unlock_irqrestore(&priv->lock, flags);
+
return err;
} /* TLan_MiiReadReg */
@@ -2552,6 +2558,7 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
spin_unlock_irqrestore(&priv->lock, flags);
+
} /* TLan_MiiWriteReg */
@@ -2775,9 +2782,9 @@ int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data )
goto fail;
}
TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP );
-
fail:
spin_unlock_irqrestore(&priv->lock, flags);
+
return ret;
} /* TLan_EeReadByte */
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 26956af06..b81815e25 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -833,11 +833,8 @@ static int tok_open(struct net_device *dev)
if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset);
if (ti->open_status==SUCCESS) {
- dev->tbusy=0;
- dev->interrupt=0;
- dev->start=1;
/* NEED to see smem size *AND* reset high 512 bytes if needed */
-
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
@@ -850,6 +847,8 @@ static int tok_close(struct net_device *dev)
struct tok_info *ti=(struct tok_info *) dev->priv;
+ netif_stop_queue(dev);
+
isa_writeb(DIR_CLOSE_ADAPTER,
ti->srb + offsetof(struct srb_close_adapter, command));
isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
@@ -862,7 +861,6 @@ static int tok_close(struct net_device *dev)
DPRINTK("close adapter failed: %02X\n",
(int)isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
- dev->start = 0;
#ifdef PCMCIA
ti->sram = 0 ;
#endif
@@ -886,7 +884,6 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&(ti->lock));
/* Disable interrupts till processing is finished */
- dev->interrupt=1;
isa_writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
/* Reset interrupt for ISA boards */
@@ -911,7 +908,6 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
{
DPRINTK("PCMCIA card removed.\n");
spin_unlock(&(ti->lock));
- dev->interrupt = 0;
return;
}
@@ -920,7 +916,6 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
{
DPRINTK("PCMCIA card removed.\n");
spin_unlock(&(ti->lock));
- dev->interrupt = 0;
return;
}
#endif
@@ -941,7 +936,6 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
isa_writeb((~ADAP_CHK_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
- dev->interrupt=0;
} else if (isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
& (TCR_INT | ERR_INT | ACCESS_INT)) {
@@ -951,7 +945,6 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
isa_writeb(~(TCR_INT | ERR_INT | ACCESS_INT),
ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
- dev->interrupt=0;
} else if (status
& (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) {
@@ -972,7 +965,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
dev_kfree_skb(ti->current_skb);
ti->current_skb=NULL;
}
- dev->tbusy=0;
+ netif_wake_queue(dev);
if (ti->readlog_pending) ibmtr_readlog(dev);
}
}
@@ -989,8 +982,9 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
dev_kfree_skb(ti->current_skb);
ti->current_skb=NULL;
}
- dev->tbusy=0;
- if (ti->readlog_pending) ibmtr_readlog(dev);
+ netif_wake_queue(dev);
+ if (ti->readlog_pending)
+ ibmtr_readlog(dev);
}
}
break;
@@ -1115,7 +1109,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
(int)isa_readb(ti->srb+offsetof(struct srb_read_log,
token_errors)));
}
- dev->tbusy=0;
+ netif_wake_queue(dev);
break;
default:
@@ -1183,7 +1177,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
DPRINTK("New ring status: %02X\n", ring_status);
if (ring_status & LOG_OVERFLOW) {
- if (dev->tbusy)
+ if (netif_queue_stopped(dev))
ti->readlog_pending = 1;
else
ibmtr_readlog(dev);
@@ -1235,7 +1229,6 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
} /* SRB, ARB, ASB or SSB response */
- dev->interrupt=0;
isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
break;
@@ -1330,7 +1323,7 @@ static int tok_init_card(struct net_device *dev)
ti->do_tok_int=FIRST_INT;
/* Reset adapter */
- dev->tbusy=1; /* nothing can be done before reset and open completed */
+ netif_stop_queue(dev);
#ifdef ENABLE_PAGING
if(ti->page_mask)
@@ -1498,10 +1491,9 @@ static void tr_tx(struct net_device *dev)
isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
ti->tr_stats.tx_bytes+=ti->current_skb->len;
- dev->tbusy=0;
dev_kfree_skb(ti->current_skb);
ti->current_skb=NULL;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
if (ti->readlog_pending) ibmtr_readlog(dev);
}
@@ -1661,38 +1653,22 @@ static void tr_rx(struct net_device *dev)
static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct tok_info *ti;
+ unsigned long flags;
ti=(struct tok_info *) dev->priv;
- if (dev->tbusy) {
- int ticks_waited;
-
- ticks_waited=jiffies - dev->trans_start;
- if (ticks_waited<TR_BUSY_INTERVAL) return 1;
-
- DPRINTK("Arrg. Transmitter busy.\n");
- dev->trans_start+=5; /* we fake the transmission start time... */
- return 1;
- }
-
- if (test_and_set_bit(0,(void *)&dev->tbusy)!=0)
- DPRINTK("Transmitter access conflict\n");
- else {
- int flags;
-
- /* lock against other CPUs */
- spin_lock_irqsave(&(ti->lock), flags);
-
- /* Save skb; we'll need it when the adapter asks for the data */
- ti->current_skb=skb;
- isa_writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command));
- isa_writew(ti->exsap_station_id, ti->srb
- +offsetof(struct srb_xmit, station_id));
- isa_writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD));
- spin_unlock_irqrestore(&(ti->lock), flags);
-
- dev->trans_start=jiffies;
- }
-
+ netif_stop_queue(dev);
+
+ /* lock against other CPUs */
+ spin_lock_irqsave(&(ti->lock), flags);
+
+ /* Save skb; we'll need it when the adapter asks for the data */
+ ti->current_skb=skb;
+ isa_writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command));
+ isa_writew(ti->exsap_station_id, ti->srb
+ +offsetof(struct srb_xmit, station_id));
+ isa_writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD));
+ spin_unlock_irqrestore(&(ti->lock), flags);
+ dev->trans_start=jiffies;
return 0;
}
@@ -1712,7 +1688,8 @@ void ibmtr_readlog(struct net_device *dev) {
isa_writeb(DIR_READ_LOG, ti->srb);
isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
- dev->tbusy=1; /* really srb busy... */
+
+ netif_stop_queue(dev);
}
/* tok_get_stats(): Basically a scaffold routine which will return
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index fcb3ccd76..5f80fc5eb 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -615,10 +615,7 @@ static int olympic_open(struct net_device *dev)
#endif
- dev->start = 1;
- dev->interrupt=0;
- dev->tbusy=0;
-
+ netif_start_queue(dev);
MOD_INC_USE_COUNT ;
return 0;
@@ -762,11 +759,6 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&olympic_priv->olympic_lock);
- if (dev->interrupt)
- printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ;
-
- dev->interrupt = 1 ;
-
if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK |
SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) {
@@ -788,11 +780,7 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
-
- if(dev->tbusy) {
- dev->tbusy=0;
- mark_bh(NET_BH);
- }
+ netif_wake_queue(dev);
} /* SISR_TX1_EOF */
if (sisr & SISR_RX_STATUS) {
@@ -804,7 +792,6 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ;
printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ;
- dev->interrupt = 0 ;
free_irq(dev->irq, dev) ;
} /* SISR_ADAPTER_CHECK */
@@ -837,8 +824,6 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ;
} /* One if the interrupts we want */
- dev->interrupt = 0 ;
-
writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
spin_unlock(&olympic_priv->olympic_lock) ;
@@ -852,11 +837,8 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&olympic_priv->olympic_lock, flags);
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
- return 1;
- }
-
+ netif_stop_queue(dev);
+
if(olympic_priv->free_tx_ring_entries) {
olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data);
olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000);
@@ -869,7 +851,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
- dev->tbusy=0;
+ netif_wake_queue(dev);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return 0;
} else {
@@ -887,6 +869,8 @@ static int olympic_close(struct net_device *dev)
unsigned long flags;
int i;
+ netif_stop_queue(dev);
+
writel(olympic_priv->srb,olympic_mmio+LAPA);
srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
@@ -936,7 +920,6 @@ static int olympic_close(struct net_device *dev)
printk("%x ",readb(srb+i));
printk("\n");
#endif
- dev->start = 0;
free_irq(dev->irq,dev);
MOD_DEC_USE_COUNT ;
@@ -1169,7 +1152,7 @@ static int olympic_set_mac_address (struct net_device *dev, void *addr)
struct sockaddr *saddr = addr ;
struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ;
- if (dev->start) {
+ if (netif_running(dev)) {
printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ;
return -EIO ;
}
@@ -1304,9 +1287,7 @@ static void olympic_arb_cmd(struct net_device *dev)
writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL);
udelay(1);
writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
- dev->tbusy = 1 ;
- dev->interrupt = 1 ;
- dev->start = 0 ;
+ netif_stop_queue(dev);
olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ;
free_irq(dev->irq,dev);
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 5e4093b14..739c3cf2f 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -131,7 +131,6 @@ static int smctr_get_upstream_neighbor_addr(struct net_device *dev);
/* H */
static int smctr_hardware_send_packet(struct net_device *dev,
struct net_local *tp);
-
/* I */
static int smctr_init_acbs(struct net_device *dev);
static int smctr_init_adapter(struct net_device *dev);
@@ -282,6 +281,7 @@ static char *smctr_malloc(struct net_device *dev, __u16 size);
static int smctr_status_chg(struct net_device *dev);
/* T */
+static void smctr_timeout(struct net_device *dev);
static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb,
__u16 queue);
static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue);
@@ -730,9 +730,8 @@ static int smctr_close(struct net_device *dev)
struct sk_buff *skb;
int err;
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
@@ -2030,13 +2029,9 @@ static void smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
tp = (struct net_local *)dev->priv;
- dev->interrupt = 0;
-
if(tp->status == NOT_INITIALIZED)
return;
@@ -3749,6 +3744,8 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr)
dev->open = smctr_open;
dev->stop = smctr_close;
dev->hard_start_xmit = smctr_send_packet;
+ dev->tx_timeout = smctr_timeout;
+ dev->watchdog_timeo = HZ;
dev->get_stats = smctr_get_stats;
dev->set_multicast_list = &smctr_set_multicast_list;
@@ -4723,6 +4720,20 @@ static int smctr_send_dat(struct net_device *dev)
return (0);
}
+static void smctr_timeout(struct net_device *dev)
+{
+ /*
+ * If we get here, some higher level has decided we are broken.
+ * There should really be a "kick me" function call instead.
+ *
+ * Resetting the token ring adapter takes a long time so just
+ * fake transmission time and go on trying. Our own timeout
+ * routine is in sktr_timer_chk()
+ */
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
/*
* Gets skb from system, queues it and checks if it can be sent
*/
@@ -4733,37 +4744,11 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev)
if(smctr_debug > 10)
printk("%s: smctr_send_packet\n", dev->name);
- if(dev->tbusy)
- {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- *
- * Resetting the token ring adapter takes a long time so just
- * fake transmission time and go on trying. Our own timeout
- * routine is in sktr_timer_chk()
- */
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- return (1);
- }
-
- /*
- * If some higher layer thinks we've missed an tx-done interrupt we
- * are passed NULL.
- */
- if(skb == NULL)
- return (0);
-
/*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+ * Block a transmit overlap
*/
- if(test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return (1);
- }
+
+ netif_stop_queue(dev);
if(tp->QueueSkb == 0)
return (1); /* Return with tbusy set: queue full */
@@ -4772,8 +4757,8 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev)
skb_queue_tail(&tp->SendSkbQueue, skb);
smctr_hardware_send_packet(dev, tp);
if(tp->QueueSkb > 0)
- dev->tbusy = 0;
-
+ netif_wake_queue(dev);
+
return (0);
}
@@ -5749,7 +5734,7 @@ static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb,
tp->num_tx_fcbs_used[queue]--;
fcb->frame_status = 0;
tp->tx_fcb_end[queue] = fcb->next_ptr;
-
+ netif_wake_queue(dev);
return (0);
}
}
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 7e1933895..417cc7c29 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -280,10 +280,8 @@ int tms380tr_open(struct net_device *dev)
tms380tr_enable_interrupts(dev);
tms380tr_open_adapter(dev);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 0;
-
+ netif_start_queue(dev);
+
/* Wait for interrupt from hardware. If interrupt does not come,
* there will be a timeout from the timer.
*/
@@ -298,8 +296,6 @@ int tms380tr_open(struct net_device *dev)
return (-1);
}
- dev->start = 1;
-
tp->StartTime = jiffies;
/* Start function control timer */
@@ -571,6 +567,20 @@ static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command)
return;
}
+static void tms380tr_timeout(struct net_device *dev)
+{
+ /*
+ * If we get here, some higher level has decided we are broken.
+ * There should really be a "kick me" function call instead.
+ *
+ * Resetting the token ring adapter takes a long time so just
+ * fake transmission time and go on trying. Our own timeout
+ * routine is in tms380tr_timer_chk()
+ */
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
/*
* Gets skb from system, queues it and checks if it can be sent
*/
@@ -578,38 +588,12 @@ static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct net_local *tp = (struct net_local *)dev->priv;
- if(dev->tbusy)
- {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- *
- * Resetting the token ring adapter takes a long time so just
- * fake transmission time and go on trying. Our own timeout
- * routine is in tms380tr_timer_chk()
- */
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- return (1);
- }
-
/*
- * If some higher layer thinks we've missed an tx-done interrupt we
- * are passed NULL.
+ * Block transmits from overlapping.
*/
- if(skb == NULL)
- return (0);
-
- /*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
- if(test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return (1);
- }
-
+
+ netif_stop_queue(dev);
+
if(tp->QueueSkb == 0)
return (1); /* Return with tbusy set: queue full */
@@ -617,8 +601,7 @@ static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev)
skb_queue_tail(&tp->SendSkbQueue, skb);
tms380tr_hardware_send_packet(dev, tp);
if(tp->QueueSkb > 0)
- dev->tbusy = 0;
-
+ netif_wake_queue(dev);
return (0);
}
@@ -773,8 +756,6 @@ void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
- dev->interrupt = 1;
-
tp = (struct net_local *)dev->priv;
irq_type = SIFREADW(SIFSTS);
@@ -854,8 +835,6 @@ void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irq_type = SIFREADW(SIFSTS);
}
- dev->interrupt = 0;
-
return;
}
@@ -1148,9 +1127,8 @@ static void tms380tr_cmd_status_irq(struct net_device *dev)
int tms380tr_close(struct net_device *dev)
{
struct net_local *tp = (struct net_local *)dev->priv;
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
del_timer(&tp->timer);
/* Flush the Tx and disable Rx here. */
@@ -2081,10 +2059,9 @@ static void tms380tr_tx_status_irq(struct net_device *dev)
tpl->BusyFlag = 0; /* "free" TPL */
}
- dev->tbusy = 0;
+ netif_wake_queue(dev);
if(tp->QueueSkb < MAX_TX_QUEUE)
tms380tr_hardware_send_packet(dev, tp);
-
return;
}
@@ -2367,6 +2344,8 @@ int tmsdev_init(struct net_device *dev)
dev->stop = tms380tr_close;
dev->do_ioctl = NULL;
dev->hard_start_xmit = tms380tr_send_packet;
+ dev->tx_timeout = tms380tr_timeout;
+ dev->watchdog_timeo = HZ;
dev->get_stats = tms380tr_get_stats;
dev->set_multicast_list = &tms380tr_set_multicast_list;
dev->set_mac_address = tms380tr_set_mac_address;
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
index fa4e9dc62..5619b961d 100644
--- a/drivers/net/tulip.c
+++ b/drivers/net/tulip.c
@@ -1,146 +1,53 @@
/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
/*
- Written 1994-1998 by Donald Becker.
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
- This driver is for the Digital "Tulip" ethernet adapter interface.
+ This driver is for the Digital "Tulip" Ethernet adapter interface.
It should work with most DEC 21*4*-based chips/ethercards, as well as
- PNIC and MXIC chips.
+ with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
- Support and updates available at
+ Additional information available at
http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
-*/
-
-#define SMP_CHECK
-static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
-
-/* A few user-configurable values. */
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 25;
-
-#define MAX_UNITS 8
-/* Used to pass the full-duplex flag, etc. */
-static int full_duplex[MAX_UNITS] = {0, };
-static int options[MAX_UNITS] = {0, };
-static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
-
-/* The possible media types that can be set in options[] are: */
-static const char * const medianame[] = {
- "10baseT", "10base2", "AUI", "100baseTx",
- "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
- "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
- "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
-};
-
-/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
-#ifdef REVERSE_PROBE_ORDER
-static int reverse_probe = 1;
-#else
-static int reverse_probe = 0;
-#endif
-
-/* Keep the ring sizes a power of two for efficiency.
- Making the Tx ring too large decreases the effectiveness of channel
- bonding and packet priority.
- There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE 16
-#define RX_RING_SIZE 32
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
-#ifdef __alpha__
-static int rx_copybreak = 1518;
-#else
-static int rx_copybreak = 100;
-#endif
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (4*HZ)
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-/* Kernel compatibility defines, common to David Hind's PCMCIA package.
- This is only in the support-all-kernels source code. */
-#include <linux/version.h> /* Evil, but neccessary */
-
-#define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
-
-#define NEW_MULTICAST
-#include <linux/delay.h>
-
-#ifdef SA_SHIRQ
-#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
-#else
-#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
-#endif
-
-/* This my implementation of shared IRQs, now only used for 1.2.13. */
-#ifdef HAVE_SHARED_IRQ
-#define USE_SHARED_IRQ
-#include <linux/shared_irq.h>
-#endif
-
-/* The total size is unusually large: The 21040 aligns each of its 16
- longword-wide registers on a quadword boundary. */
-#define TULIP_TOTAL_SIZE 0x80
-
-#ifdef HAVE_DEVLIST
-struct netdev_entry tulip_drv =
-{"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};
-#endif
+
+ For this specific driver variant please use linux-kernel for
+ bug reports.
-#ifdef TULIP_DEBUG
-int tulip_debug = TULIP_DEBUG;
-#else
-int tulip_debug = 1;
-#endif
-/*
Theory of Operation
I. Board Compatibility
This device driver is designed for the DECchip "Tulip", Digital's
single-chip ethernet controllers for PCI. Supported members of the family
-are the 21040, 21041, 21140, 21140A, 21142, and 21143. These chips are used on
-many PCI boards including the SMC EtherPower series.
+are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported.
+These chips are used on at least 140 unique PCI board designs. The great
+number of chips and board designs supported is the reason for the
+driver size and complexity. Almost of the increasing complexity is in the
+board configuration and media selection code. There is very little
+increasing in the operational critical path length.
II. Board-specific settings
PCI bus devices are configured by the system at boot time, so no jumpers
need to be set on the board. The system BIOS preferably should assign the
PCI INTA signal to an otherwise unused system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
+
+Some boards have EEPROMs tables with default media entry. The factory default
+is usually "autoselect". This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation.
III. Driver operation
@@ -188,111 +95,261 @@ tx_full and tbusy flags.
IV. Notes
-Thanks to Duke Kamstra of SMC for providing an EtherPower board.
+Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
+Greg LaPolla at Linksys provided PNIC and other Linksys boards.
+Znyx provided a four-port card for testing.
IVb. References
http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
-http://www.national.com/pf/DP/DP83840.html
+http://www.national.com/pf/DP/DP83840A.html
+http://www.asix.com.tw/pmac.htm
+http://www.admtek.com.tw/
IVc. Errata
-The DEC databook doesn't document which Rx filter settings accept broadcast
-packets. Nor does it document how to configure the part to configure the
-serial subsystem for normal (vs. loopback) operation or how to have it
-autoswitch between internal 10baseT, SIA and AUI transceivers.
-
+The old DEC databooks were light on details.
The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
-register of the set CSR12-15 written. Hmmm, now how is that possible? */
+register of the set CSR12-15 written. Hmmm, now how is that possible?
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below. Some boards do not have EEPROM
+media tables and need to be patched up. Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
-/* A few values that may be tweaked. */
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them. The MII transceiver status is polled using an kernel timer.
+
+*/
+static const char version[] = "Linux Tulip driver version 0.9.2 (Feb 15, 2000)\n";
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <asm/delay.h>
+
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
+
+/* The possible media types that can be set in options[] are: */
+static const char * const medianame[] = {
+ "10baseT", "10base2", "AUI", "100baseTx",
+ "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+ "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+
+/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
+#ifdef REVERSE_PROBE_ORDER
+static int reverse_probe = 1;
+#else
+static int reverse_probe = 0;
+#endif
+
+/* Keep the ring sizes a power of two for efficiency.
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 32
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+
+/*
+ Set the bus performance register.
+ Typical: Set 16 longword cache alignment, no burst limit.
+ Cache alignment bits 15:14 Burst length 13:8
+ 0000 No alignment 0x00000000 unlimited 0800 8 longwords
+ 4000 8 longwords 0100 1 longword 1000 16 longwords
+ 8000 16 longwords 0200 2 longwords 2000 32 longwords
+ C000 32 longwords 0400 4 longwords
+ Warning: many older 486 systems are broken and require setting 0x00A04800
+ 8 longword cache alignment, 8 longword burst.
+ ToDo: Non-Intel setting could be better.
+*/
+
+#if defined(__alpha__)
+static int csr0 = 0x01A00000 | 0xE000;
+#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__)
+static int csr0 = 0x01A00000 | 0x8000;
+#else
+#warning Processor architecture undefined!
+static int csr0 = 0x00A00000 | 0x4800;
+#endif
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
to support a pre-NWay full-duplex signaling mechanism using short frames.
No one knows what it should be, but if left at its default value some
10base2(!) packets trigger a full-duplex-request interrupt. */
#define FULL_DUPLEX_MAGIC 0x6969
-#ifndef PCI_VENDOR_ID_DEC /* Now defined in linux/pci.h */
-#define PCI_VENDOR_ID_DEC 0x1011
-#define PCI_DEVICE_ID_TULIP 0x0002 /* 21040. */
-#define PCI_DEVICE_ID_TULIP_FAST 0x0009 /* 21140. */
-#endif
-#ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS
-#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 /* 21041. */
-#endif
-#ifndef PCI_DEVICE_ID_DEC_TULIP_21142
-#define PCI_DEVICE_ID_DEC_TULIP_21142 0x0019
-#endif
+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
-#ifndef PCI_VENDOR_ID_LITEON
-#define PCI_VENDOR_ID_LITEON 0x11AD
-#endif
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(csr0, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+#define TULIP_MODULE_NAME "tulip"
+#define PFX TULIP_MODULE_NAME ": "
+
+#define RUN_AT(x) (jiffies + (x))
-#ifndef PCI_VENDOR_ID_MXIC
-#define PCI_VENDOR_ID_MXIC 0x10d9
-#define PCI_DEVICE_ID_MX98713 0x0512
-#define PCI_DEVICE_ID_MX98715 0x0531
-#define PCI_DEVICE_ID_MX98725 0x0531
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
+
+#define tulip_debug debug
+#ifdef TULIP_DEBUG
+static int tulip_debug = TULIP_DEBUG;
+#else
+static int tulip_debug = 1;
#endif
-/* The rest of these values should never change. */
+
+
+/* This table use during operation for capabilities and media timer. */
static void tulip_timer(unsigned long data);
static void t21142_timer(unsigned long data);
static void mxic_timer(unsigned long data);
static void pnic_timer(unsigned long data);
+static void comet_timer(unsigned long data);
-/* A table describing the chip types. */
-enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};
+enum tbl_flag {
+ HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
+ HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+ HAS_PNICNWAY=0x80, HAS_NWAY143=0x40, /* Uses internal NWay xcvr. */
+ HAS_8023X=0x100,
+};
static struct tulip_chip_table {
- int vendor_id, device_id;
char *chip_name;
int io_size;
int valid_intrs; /* CSR7 interrupt enable settings */
int flags;
void (*media_timer)(unsigned long data);
} tulip_tbl[] = {
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
- "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
- "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
- "Digital DS21140 Tulip", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM,
- tulip_timer },
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_21142,
- "Digital DS21142/3 Tulip", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
- { PCI_VENDOR_ID_LITEON, 0x0002,
- "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII, pnic_timer },
- { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98713,
- "Macronix 98713 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer /* Tulip-like! */ },
- { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98715,
- "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
- { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98725,
- "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
- { 0x125B, 0x1400, "ASIX AX88140", 128, 0x0001fbff,
+ { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+ { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
+ { "Digital DS21140 Tulip", 128, 0x0001ebef,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
- {0, 0, 0, 0},
+ { "Digital DS21143 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
+ t21142_timer },
+ { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+ HAS_MII | HAS_PNICNWAY, pnic_timer },
+ { "Macronix 98713 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Macronix 98715 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "Macronix 98725 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+ { "Lite-On PNIC-II", 256, 0x0801fbff,
+ HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
+ { "ADMtek Comet", 256, 0x0001abef,
+ MC_HASH_ONLY, comet_timer },
+ { "Compex 9881 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Intel DS21145 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143,
+ t21142_timer },
+ { "Xircom tulip work-alike", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
+ t21142_timer },
+ {0},
+};
+/* This matches the table above. Note 21142 == 21143. */
+enum chips {
+ DC21040=0,
+ DC21041=1,
+ DC21140=2,
+ DC21142=3, DC21143=3,
+ LC82C168,
+ MX98713,
+ MX98715,
+ MX98725,
+ AX88140,
+ PNIC2,
+ COMET,
+ COMPEX9881,
+ I21145,
+ X3201_3,
+};
+
+
+static struct pci_device_id tulip_pci_tbl[] __devinitdata = {
+ { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
+ { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
+ { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 },
+ { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
+ { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
+ { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
+ { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
+ { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
+ { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
+ { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+ {0},
};
-/* This matches the table above. */
-enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
- LC82C168, MX98713, MX98715, MX98725};
+MODULE_DEVICE_TABLE(pci,tulip_pci_tbl);
+
/* A full-duplex map for media types. */
-enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
- MediaIs100=16};
+enum MediaIs {
+ MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+ MediaIs100=16};
static const char media_cap[] =
{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
+static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
-static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
-static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
@@ -308,16 +365,12 @@ enum tulip_offsets {
/* The bits in the CSR5 status registers, mostly interrupt sources. */
enum status_bits {
- TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+ TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10,
NormalIntr=0x10000, AbnormalIntr=0x8000,
RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
};
-enum desc_status_bits {
- DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
-};
-
/* The Tulip Rx and Tx buffer descriptors. */
struct tulip_rx_desc {
s32 status;
@@ -331,6 +384,22 @@ struct tulip_tx_desc {
u32 buffer1, buffer2; /* We use only buffer 1. */
};
+enum desc_status_bits {
+ DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+
+/* Ring-wrap flag in length field, use for last ring entry.
+ 0x01000000 means chain on buffer2 address,
+ 0x02000000 means use the ring start address in CSR2/3.
+ Note: Some work-alike chips do not function correctly in chained mode.
+ The ASIX chip works only in chained mode.
+ Thus we indicates ring mode, but always write the 'next' field for
+ chained mode as well.
+*/
+#define DESC_RING_WRAP 0x02000000
+
+#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */
+
struct medialeaf {
u8 type;
u8 media;
@@ -340,7 +409,8 @@ struct medialeaf {
struct mediatable {
u16 defaultmedia;
u8 leafcount, csr12dir; /* General purpose pin directions. */
- unsigned has_mii:1, has_nonmii:1;
+ unsigned has_mii:1, has_nonmii:1, has_reset:6;
+ u32 csr15dir, csr15val; /* 21143 NWay setting. */
struct medialeaf mleaf[0];
};
@@ -362,12 +432,13 @@ struct tulip_private {
/* The addresses of receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
char *rx_buffs; /* Address of temporary Rx buffers. */
- u32 setup_frame[48]; /* Pseudo-Tx frame to init address table. */
+ u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */
int chip_id;
int revision;
+ int flags;
struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
- spinlock_t tx_lock;
+ spinlock_t tx_lock;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
unsigned int tx_full:1; /* The Tx queue is full. */
@@ -378,411 +449,52 @@ struct tulip_private {
unsigned int media2:4; /* Secondary monitored media port. */
unsigned int medialock:1; /* Don't sense media type. */
unsigned int mediasense:1; /* Media sensing in progress. */
+ unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
+ unsigned int csr0; /* CSR0 setting. */
unsigned int csr6; /* Current CSR6 control settings. */
- unsigned char eeprom[128]; /* Serial EEPROM contents. */
+ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
+ void (*link_change)(struct net_device *dev, int csr5);
u16 to_advertise; /* NWay capabilities advertised. */
+ u16 lpar; /* 21143 Link partner ability. */
u16 advertising[4];
signed char phys[4], mii_cnt; /* MII device addresses. */
struct mediatable *mtable;
int cur_index; /* Current media index. */
- unsigned char pci_bus, pci_dev_fn;
+ int saved_if_port;
+ struct pci_dev *pdev;
+ int ttimer;
+ int susp_rx;
+ unsigned long nir;
+ unsigned long base_addr;
int pad0, pad1; /* Used for 8-byte alignment */
};
-static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
- int chip_id, int options);
static void parse_eeprom(struct net_device *dev);
-static int read_eeprom(long ioaddr, int location);
+static int read_eeprom(long ioaddr, int location, int addr_len);
static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static void select_media(struct net_device *dev, int startup);
-static int tulip_open(struct net_device *dev);
-static void tulip_timer(unsigned long data);
+/* Chip-specific media selection (timer functions prototyped above). */
+static void t21142_lnk_change(struct net_device *dev, int csr5);
+static void t21142_start_nway(struct net_device *dev);
+static void pnic_lnk_change(struct net_device *dev, int csr5);
+static void pnic_do_nway(struct net_device *dev);
+
static void tulip_tx_timeout(struct net_device *dev);
static void tulip_init_ring(struct net_device *dev);
static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int tulip_refill_rx(struct net_device *dev);
static int tulip_rx(struct net_device *dev);
-static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int tulip_open(struct net_device *dev);
static int tulip_close(struct net_device *dev);
-static struct enet_statistics *tulip_get_stats(struct net_device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
+static void tulip_up(struct net_device *dev);
+static void tulip_down(struct net_device *dev);
+static struct net_device_stats *tulip_get_stats(struct net_device *dev);
static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#endif
-#ifdef NEW_MULTICAST
static void set_rx_mode(struct net_device *dev);
-#else
-static void set_rx_mode(struct net_device *dev, int num_addrs, void *addrs);
-#endif
-
-
-
-/* A list of all installed Tulip devices, for removing the driver module. */
-static struct net_device *root_tulip_dev = NULL;
-
-/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
- but now receives directly into full-sized skbuffs that are allocated
- at open() time.
- This allows the probe routine to use the old driver initialization
- interface. */
-
-static int __init tulip_probe(void)
-{
- int cards_found = 0;
- static int pci_index = 0; /* Static, for multiple probe calls. */
- unsigned char pci_bus, pci_device_fn;
-
- /* Ideally we would detect all network cards in slot order. That would
- be best done a central PCI probe dispatch, which wouldn't work
- well with the current structure. So instead we detect just the
- Tulip cards in slot order. */
-
- if (! pci_present())
- return -ENODEV;
- for (;pci_index < 0xff; pci_index++) {
- u16 vendor, device, pci_command, new_command;
- unsigned long pci_ioaddr = 0;
- int chip_idx = 0;
- struct pci_dev *pdev;
-
- if (pcibios_find_class
- (PCI_CLASS_NETWORK_ETHERNET << 8,
- reverse_probe ? 0xfe - pci_index : pci_index,
- &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
- {
- if (reverse_probe)
- continue;
- else
- break;
- }
-
- pdev = pci_find_slot (pci_bus, pci_device_fn);
- vendor = pdev->vendor;
- device = pdev->device;
-
- for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
- if (vendor == tulip_tbl[chip_idx].vendor_id &&
- device == tulip_tbl[chip_idx].device_id)
- break;
- if (tulip_tbl[chip_idx].chip_name == 0) {
- if (vendor == PCI_VENDOR_ID_DEC ||
- vendor == PCI_VENDOR_ID_LITEON)
- printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
- " %4.4x %4.4x"" detected: not configured.\n",
- vendor, device);
- continue;
- }
- pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start;
- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
- if (tulip_debug > 2)
- printk(KERN_DEBUG "Found %s at I/O %#lx.\n",
- tulip_tbl[chip_idx].chip_name, pci_ioaddr);
-
- if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
- continue;
-
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled this"
- " device! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
-
- if(tulip_probe1(pci_bus, pci_device_fn, chip_idx, cards_found))
- {
- /* Get and check the bus-master and latency values. */
- unsigned char pci_latency;
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 10) {
- printk(KERN_INFO " PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to 64 clocks.\n",
- pci_latency);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
- } else if (tulip_debug > 1)
- printk(KERN_INFO " PCI latency timer (CFLT) is %#x, "
- " PCI command is %4.4x.\n",
- pci_latency, new_command);
- /* Bring the 21143 out power-down mode. */
- if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
- pci_write_config_dword(pdev, 0x40, 0x40000000);
- cards_found++;
- }
- }
-
- return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device *tulip_probe1(int pci_bus, int pci_device_fn,
- int chip_id, int board_idx)
-{
- struct net_device *dev;
- static int did_version = 0; /* Already printed version info. */
- struct tulip_private *tp;
- long ioaddr;
- int irq;
- /* See note below on the multiport cards. */
- static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
- static int last_irq = 0;
- static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
- int i;
- unsigned short sum;
-
- if (tulip_debug > 0 && did_version++ == 0)
- printk(KERN_INFO "%s", version);
- dev = init_etherdev(NULL, 0);
-
- irq = pci_find_slot(pci_bus, pci_device_fn)->irq;
- ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start;
-
- printk(KERN_INFO "%s: %s at %#3lx,",
- dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
-
- /* Stop the chip's Tx and Rx processes. */
- outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
- /* Clear the missed-packet counter. */
- (volatile int)inl(ioaddr + CSR8);
-
- if (chip_id == DC21041) {
- if (inl(ioaddr + CSR9) & 0x8000) {
- printk(" 21040 compatible mode,");
- chip_id = DC21040;
- } else {
- printk(" 21041 mode,");
- }
- }
-
- /* The station address ROM is read byte serially. The register must
- be polled, waiting for the value to be read bit serially from the
- EEPROM.
- */
- sum = 0;
- if (chip_id == DC21040) {
- outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
- for (i = 0; i < 6; i++) {
- int value, boguscnt = 100000;
- do
- value = inl(ioaddr + CSR9);
- while (value < 0 && --boguscnt > 0);
- dev->dev_addr[i] = value;
- sum += value & 0xff;
- }
- } else if (chip_id == LC82C168) {
- for (i = 0; i < 3; i++) {
- int value, boguscnt = 100000;
- outl(0x600 | i, ioaddr + 0x98);
- do
- value = inl(ioaddr + CSR9);
- while (value < 0 && --boguscnt > 0);
- ((u16*)dev->dev_addr)[i] = value;
- sum += value & 0xffff;
- }
- } else { /* Must be a new chip, with a serial EEPROM interface. */
- /* We read the whole EEPROM, and sort it out later. DEC has a
- specification _Digital Semiconductor 21X4 Serial ROM Format_
- but early vendor boards just put the address in the first six
- EEPROM locations. */
- unsigned char ee_data[128];
- int sa_offset = 0;
-
- for (i = 0; i < sizeof(ee_data)/2; i++)
- ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
-
- /* Detect the simple EEPROM format by the duplicated station addr. */
- for (i = 0; i < 8; i ++)
- if (ee_data[i] != ee_data[16+i])
- sa_offset = 20;
- if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
- sa_offset = 2; /* Grrr, damn Matrox boards. */
- multiport_cnt = 4;
- }
- for (i = 0; i < 6; i ++) {
- dev->dev_addr[i] = ee_data[i + sa_offset];
- sum += ee_data[i + sa_offset];
- }
- }
- /* Lite-On boards have the address byte-swapped. */
- if (dev->dev_addr[0] == 0xA0 && dev->dev_addr[1] == 0x00)
- for (i = 0; i < 6; i+=2) {
- char tmp = dev->dev_addr[i];
- dev->dev_addr[i] = dev->dev_addr[i+1];
- dev->dev_addr[i+1] = tmp;
- }
- /* On the Zynx 315 Etherarray and other multiport boards only the
- first Tulip has an EEPROM.
- The addresses of the subsequent ports are derived from the first.
- Many PCI BIOSes also incorrectly report the IRQ line, so we correct
- that here as well. */
- if (sum == 0 || sum == 6*0xff) {
- printk(" EEPROM not present,");
- for (i = 0; i < 5; i++)
- dev->dev_addr[i] = last_phys_addr[i];
- dev->dev_addr[i] = last_phys_addr[i] + 1;
-#if defined(__i386__) /* This BIOS bug doesn't exist on Alphas. */
- irq = last_irq;
-#endif
- }
-
- for (i = 0; i < 6; i++)
- printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
- printk(", IRQ %d.\n", irq);
- last_irq = irq;
-
- /* We do a request_region() only to register /proc/ioports info. */
- /* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
- request_region(ioaddr, TULIP_TOTAL_SIZE, dev->name);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- /* Make certain the data structures are quadword aligned. */
- tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
- memset(tp, 0, sizeof(*tp));
- dev->priv = tp;
-
- tp->next_module = root_tulip_dev;
- root_tulip_dev = dev;
-
- tp->pci_bus = pci_bus;
- tp->pci_dev_fn = pci_device_fn;
- tp->chip_id = chip_id;
-
-#ifdef TULIP_FULL_DUPLEX
- tp->full_duplex = 1;
- tp->full_duplex_lock = 1;
-#endif
-#ifdef TULIP_DEFAULT_MEDIA
- tp->default_port = TULIP_DEFAULT_MEDIA;
-#endif
-#ifdef TULIP_NO_MEDIA_SWITCH
- tp->medialock = 1;
-#endif
-
- /* The lower four bits are the media type. */
- if (board_idx >= 0 && board_idx < MAX_UNITS) {
- tp->default_port = options[board_idx] & 15;
- if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
- tp->full_duplex = 1;
- if (mtu[board_idx] > 0)
- dev->mtu = mtu[board_idx];
- }
- if (dev->mem_start)
- tp->default_port = dev->mem_start;
- if (tp->default_port) {
- tp->medialock = 1;
- if (media_cap[tp->default_port] & MediaAlwaysFD)
- tp->full_duplex = 1;
- }
- if (tp->full_duplex)
- tp->full_duplex_lock = 1;
-
- /* This is logically part of probe1(), but too complex to write inline. */
- if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
- parse_eeprom(dev);
-
- if (media_cap[tp->default_port] & MediaIsMII) {
- u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
- tp->to_advertise = media2advert[tp->default_port - 9];
- } else
- tp->to_advertise = 0x03e1;
-
- if ((tp->mtable && tp->mtable->has_mii) ||
- ( ! tp->mtable && (tulip_tbl[tp->chip_id].flags & HAS_MII))) {
- int phy, phy_idx;
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later,
- but takes much time. */
- for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
- phy++) {
- int mii_status = mdio_read(dev, phy, 1);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- int mii_reg0 = mdio_read(dev, phy, 0);
- int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
- tp->phys[phy_idx] = phy;
- tp->advertising[phy_idx++] = reg4;
- printk(KERN_INFO "%s: MII transceiver found at MDIO address "
- "%d, config %4.4x status %4.4x.\n",
- dev->name, phy, mii_reg0, mii_status);
- if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
- printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
- " previously advertising %4.4x.\n",
- dev->name, reg4, phy, mdio_read(dev, phy, 4));
- mdio_write(dev, phy, 4, reg4);
- }
- /* Enable autonegotiation: some boards default to off. */
- mdio_write(dev, phy, 0, mii_reg0 |
- (tp->full_duplex ? 0x1100 : 0x1000) |
- (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
- }
- }
- tp->mii_cnt = phy_idx;
- if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
- printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
- dev->name);
- tp->phys[0] = 1;
- }
- }
-
- /* The Tulip-specific entries in the device structure. */
- dev->open = &tulip_open;
- dev->hard_start_xmit = &tulip_start_xmit;
- dev->tx_timeout = &tulip_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->stop = &tulip_close;
- dev->get_stats = &tulip_get_stats;
-#ifdef HAVE_PRIVATE_IOCTL
- dev->do_ioctl = &private_ioctl;
-#endif
-#ifdef HAVE_MULTICAST
- dev->set_multicast_list = &set_rx_mode;
-#endif
-
- /* Reset the xcvr interface and turn on heartbeat. */
- switch (chip_id) {
- case DC21041:
- outl(0x00000000, ioaddr + CSR13);
- outl(0xFFFFFFFF, ioaddr + CSR14);
- outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
- outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
- outl(0x0000EF05, ioaddr + CSR13);
- break;
- case DC21040:
- outl(0x00000000, ioaddr + CSR13);
- outl(0x00000004, ioaddr + CSR13);
- break;
- case DC21140: default:
- if (tp->mtable)
- outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
- break;
- case DC21142:
- outl(0x82420200, ioaddr + CSR6);
- outl(0x0001, ioaddr + CSR13);
- outl(0x0003FFFF, ioaddr + CSR14);
- outl(0x0008, ioaddr + CSR15);
- outl(0x0001, ioaddr + CSR13);
- outl(0x1301, ioaddr + CSR12); /* Start NWay. */
- break;
- case LC82C168:
- if ( ! tp->mii_cnt) {
- outl(0x00420000, ioaddr + CSR6);
- outl(0x30, ioaddr + CSR12);
- outl(0x0001F078, ioaddr + 0xB8);
- outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
- }
- break;
- case MX98713: case MX98715: case MX98725:
- outl(0x00000000, ioaddr + CSR6);
- outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
- outl(0x00000001, ioaddr + CSR13);
- break;
- }
-
- return dev;
-}
-
/* Serial EEPROM section. */
/* The main routine to parse the very complicated SROM structure.
Search www.digital.com for "21X4 SROM" to get details.
@@ -798,29 +510,37 @@ static struct fixups {
} eeprom_fixups[] = {
{"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
- {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
+ {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
0x0000, 0x009E, /* 10baseT */
- 0x0903, 0x006D, /* 100baseTx */ }},
- {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0903, 0x006D, /* 100baseTx */
+ 0x0905, 0x006D, /* 100baseTx-FD */ }},
+ {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
0x0107, 0x8021, /* 100baseFx */
0x0108, 0x8021, /* 100baseFx-FD */
- 0x0103, 0x006D, /* 100baseTx */ }},
- {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
+ 0x0100, 0x009E, /* 10baseT */
+ 0x0104, 0x009E, /* 10baseT-FD */
+ 0x0103, 0x006D, /* 100baseTx */
+ 0x0105, 0x006D, /* 100baseTx-FD */ }},
+ {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
0x1001, 0x009E, /* 10base2, CSR12 0x10*/
0x0000, 0x009E, /* 10baseT */
- 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},
- {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,
- 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
- 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
- 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
+ 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
+ {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
+ 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
+ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
}},
{0, 0, 0, 0, {}}};
static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
"21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
-#define EEPROM_SIZE 128
-#if defined(__i386__)
+#if defined(__i386__) /* AKA get_unaligned() */
#define get_u16(ptr) (*(u16 *)(ptr))
#else
#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
@@ -833,14 +553,10 @@ static void parse_eeprom(struct net_device *dev)
static unsigned char *last_ee_data = NULL;
static int controller_index = 0;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
unsigned char *ee_data = tp->eeprom;
int i;
tp->mtable = 0;
- for (i = 0; i < EEPROM_SIZE/2; i++)
- ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
-
/* Detect an old-style (SA only) EEPROM layout:
memcmp(eedata, eedata+16, 8). */
for (i = 0; i < 8; i ++)
@@ -877,20 +593,13 @@ static void parse_eeprom(struct net_device *dev)
}
}
if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
- printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n",
+ printk(KERN_INFO "%s: Old style EEPROM with no media selection "
+ "information.\n",
dev->name);
return;
}
}
- if (tulip_debug > 1) {
- printk(KERN_DEBUG "read_eeprom:");
- for (i = 0; i < 64; i++) {
- printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ",
- read_eeprom(ioaddr, i));
- }
- printk("\n");
- }
-
+
controller_index = 0;
if (ee_data[19] > 1) { /* Multiport board. */
last_ee_data = ee_data;
@@ -900,42 +609,29 @@ subsequent_board:
if (ee_data[27] == 0) { /* No valid media table. */
} else if (tp->chip_id == DC21041) {
unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
- short media;
- int count;
+ int media = get_u16(p);
+ int count = p[2];
+ p += 3;
- media = get_u16(p);
- p += 2;
- count = *p++;
-
- printk(KERN_INFO "%s:21041 Media information at %d, default media "
- "%4.4x (%s).\n", dev->name, ee_data[27], media,
+ printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n",
+ dev->name, media,
media & 0x0800 ? "Autosense" : medianame[media & 15]);
for (i = 0; i < count; i++) {
unsigned char media_code = *p++;
- u16 csrvals[3];
- int idx;
- for (idx = 0; idx < 3; idx++) {
- csrvals[idx] = get_u16(p);
- p += 2;
- }
- if (media_code & 0x40) {
- printk(KERN_INFO "%s: 21041 media %2.2x (%s),"
- " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
- dev->name, media_code & 15, medianame[media_code & 15],
- csrvals[0], csrvals[1], csrvals[2]);
- } else
- printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
- dev->name, media_code & 15, medianame[media_code & 15]);
+ if (media_code & 0x40)
+ p += 6;
+ printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
+ dev->name, media_code & 15, medianame[media_code & 15]);
}
} else {
unsigned char *p = (void *)ee_data + ee_data[27];
unsigned char csr12dir = 0;
- int count;
+ int count, new_advertise = 0;
struct mediatable *mtable;
u16 media = get_u16(p);
p += 2;
- if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
+ if (tp->flags & CSR12_IN_SROM)
csr12dir = *p++;
count = *p++;
mtable = (struct mediatable *)
@@ -947,13 +643,14 @@ subsequent_board:
mtable->defaultmedia = media;
mtable->leafcount = count;
mtable->csr12dir = csr12dir;
- mtable->has_nonmii = mtable->has_mii = 0;
+ mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
+ mtable->csr15dir = mtable->csr15val = 0;
printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
media & 0x0800 ? "Autosense" : medianame[media & 15]);
for (i = 0; i < count; i++) {
struct medialeaf *leaf = &mtable->mleaf[i];
-
+
if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
leaf->type = 0;
leaf->media = p[0] & 0x3f;
@@ -963,12 +660,34 @@ subsequent_board:
p += 4;
} else {
leaf->type = p[1];
- if (p[1] & 1) {
+ if (p[1] == 0x05) {
+ mtable->has_reset = i;
+ leaf->media = p[2] & 0x0f;
+ } else if (p[1] & 1) {
mtable->has_mii = 1;
leaf->media = 11;
} else {
mtable->has_nonmii = 1;
leaf->media = p[2] & 0x0f;
+ switch (leaf->media) {
+ case 0: new_advertise |= 0x0020; break;
+ case 4: new_advertise |= 0x0040; break;
+ case 3: new_advertise |= 0x0080; break;
+ case 5: new_advertise |= 0x0100; break;
+ case 6: new_advertise |= 0x0200; break;
+ }
+ if (p[1] == 2 && leaf->media == 0) {
+ if (p[2] & 0x40) {
+ u32 base15 = get_unaligned((u16*)&p[7]);
+ mtable->csr15dir =
+ (get_unaligned((u16*)&p[9])<<16) + base15;
+ mtable->csr15val =
+ (get_unaligned((u16*)&p[11])<<16) + base15;
+ } else {
+ mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
+ mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
+ }
+ }
}
leaf->leafdata = p + 2;
p += (p[0] & 0x3f) + 1;
@@ -977,7 +696,7 @@ subsequent_board:
unsigned char *bp = leaf->leafdata;
printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
"sequences %d/%d long, capabilities %2.2x %2.2x.\n",
- dev->name, bp[0], bp[1], bp[1 + bp[1]*2],
+ dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
}
printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
@@ -985,6 +704,8 @@ subsequent_board:
dev->name, i, medianame[leaf->media], leaf->media,
block_name[leaf->type], leaf->type);
}
+ if (new_advertise)
+ tp->to_advertise = new_advertise;
}
}
/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
@@ -992,54 +713,48 @@ subsequent_board:
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
#define EE_CS 0x01 /* EEPROM chip select. */
-#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */
#define EE_WRITE_0 0x01
#define EE_WRITE_1 0x05
-#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */
#define EE_ENB (0x4800 | EE_CS)
/* Delay between EEPROM clock transitions.
- The 1.2 code is a "nasty" timing loop, but PC compatible machines are
- *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */
-#ifdef _LINUX_DELAY_H
-#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000)
-#else
-#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-#endif
+ Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+ We add a bus turn-around to insure that this remains true. */
+#define eeprom_delay() inl(ee_addr)
/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5 << 6)
-#define EE_READ_CMD (6 << 6)
-#define EE_ERASE_CMD (7 << 6)
+#define EE_READ_CMD (6)
-static int read_eeprom(long ioaddr, int location)
+/* Note: this routine returns extra data bits for size detection. */
+static int __devinit read_eeprom(long ioaddr, int location, int addr_len)
{
int i;
- unsigned short retval = 0;
+ unsigned retval = 0;
long ee_addr = ioaddr + CSR9;
- int read_cmd = location | EE_READ_CMD;
-
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
outl(EE_ENB & ~EE_CS, ee_addr);
outl(EE_ENB, ee_addr);
-
+
/* Shift the read command bits out. */
- for (i = 10; i >= 0; i--) {
+ for (i = 4 + addr_len; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outl(EE_ENB | dataval, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
- eeprom_delay(150);
- outl(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */
- eeprom_delay(250);
+ eeprom_delay();
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
}
outl(EE_ENB, ee_addr);
-
+
for (i = 16; i > 0; i--) {
outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
outl(EE_ENB, ee_addr);
- eeprom_delay(100);
+ eeprom_delay();
}
/* Terminate the EEPROM access. */
@@ -1073,19 +788,33 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
int i;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
int retval = 0;
- long mdio_addr = dev->base_addr + CSR9;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
if (tp->chip_id == LC82C168) {
- long ioaddr = dev->base_addr;
int i = 1000;
outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
while (--i > 0)
if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
return retval & 0xffff;
return 0xffff;
}
- /* Establish sync by sending at least 32 logic ones. */
+ if (tp->chip_id == COMET) {
+ if (phy_id == 1) {
+ if (location < 7)
+ return inl(ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ return inl(ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ return inl(ioaddr + 0xD4 + ((location-29)<<2));
+ }
+ return 0xffff;
+ }
+
+ /* Establish sync by sending at least 32 logic ones. */
for (i = 32; i >= 0; i--) {
outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
mdio_delay();
@@ -1117,10 +846,10 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int i;
int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
- long mdio_addr = dev->base_addr + CSR9;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
if (tp->chip_id == LC82C168) {
- long ioaddr = dev->base_addr;
int i = 1000;
outl(cmd, ioaddr + 0xA0);
do
@@ -1130,7 +859,19 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
return;
}
- /* Establish sync by sending 32 logic ones. */
+ if (tp->chip_id == COMET) {
+ if (phy_id != 1)
+ return;
+ if (location < 7)
+ outl(value, ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ outl(value, ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+ return;
+ }
+
+ /* Establish sync by sending 32 logic ones. */
for (i = 32; i >= 0; i--) {
outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
mdio_delay();
@@ -1155,99 +896,114 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
return;
}
-
-static int
-tulip_open(struct net_device *dev)
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+ manipulated. Keith Owens <kaos@ocs.com.au>. */
+
+static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
+{
+ long ioaddr = tp->base_addr;
+ const int strict_bits = 0x0060e202;
+ int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+ long flags;
+
+ /* really a hw lock */
+ spin_lock_irqsave (&tp->tx_lock, flags);
+
+ if (tp->chip_id != X3201_3)
+ goto out_write;
+
+ newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
+ /* read 0 on the Xircom cards */
+ newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
+ currcsr6 = inl (ioaddr + CSR6);
+ if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+ ((currcsr6 & ~0x2002) == 0))
+ goto out_write;
+
+ /* make sure the transmitter and receiver are stopped first */
+ currcsr6 &= ~0x2002;
+ while (1) {
+ csr5 = inl (ioaddr + CSR5);
+ if (csr5 == 0xffffffff)
+ break; /* cannot read csr5, card removed? */
+ csr5_22_20 = csr5 & 0x700000;
+ csr5_19_17 = csr5 & 0x0e0000;
+ if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+ (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+ break; /* both are stopped or suspended */
+ if (!--attempts) {
+ printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts,"
+ "csr5=0x%08x\n", csr5);
+ goto out_write;
+ }
+ outl (currcsr6, ioaddr + CSR6);
+ udelay (1);
+ }
+
+out_write:
+ /* now it is safe to change csr6 */
+ outl (newcsr6, ioaddr + CSR6);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+}
+
+
+static void tulip_up(struct net_device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
- int i = 0;
+ int next_tick = 3*HZ;
+ int i;
+
+ /* Wake the chip from sleep/snooze mode. */
+ if (tp->flags & HAS_ACPI)
+ pci_write_config_dword(tp->pdev, 0x40, 0);
/* On some chip revs we must set the MII/SYM port before the reset!? */
if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
- outl(0x00040000, ioaddr + CSR6);
+ outl_CSR6 (tp, 0x00040000);
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
outl(0x00000001, ioaddr + CSR0);
-#ifdef _LINUX_DELAY_H
- udelay(2);
-#else
- SLOW_DOWN_IO;
-#endif
+
/* Deassert reset.
- 486: Set 8 longword cache alignment, 8 longword burst.
- 586: Set 16 longword cache alignment, no burst limit.
- Cache alignment bits 15:14 Burst length 13:8
- 0000 No alignment 0x00000000 unlimited 0800 8 longwords
- 4000 8 longwords 0100 1 longword 1000 16 longwords
- 8000 16 longwords 0200 2 longwords 2000 32 longwords
- C000 32 longwords 0400 4 longwords
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
-#if defined(__alpha__)
- /* ToDo: Alpha setting could be better. */
- outl(0x01A00000 | 0xE000, ioaddr + CSR0);
-#elif defined(__powerpc__)
- outl(0x01A00080 | 0x8000, ioaddr + CSR0);
-#elif defined(__i386__)
-#if defined(MODULE)
- /* When a module we don't have 'x86' to check. */
- outl(0x01A00000 | 0x4800, ioaddr + CSR0);
-#else
-#define x86 boot_cpu_data.x86
- outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
- if (x86 <= 4)
- printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
- "alignment to %x.\n", dev->name,
- 0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
-#endif
-#else
- outl(0x01A00000 | 0x4800, ioaddr + CSR0);
-#warning Processor architecture undefined!
-#endif
-
-#ifdef SA_SHIRQ
- if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
- return -EAGAIN;
- }
-#else
- if (irq2dev_map[dev->irq] != NULL
- || (irq2dev_map[dev->irq] = dev) == NULL
- || dev->irq == 0
- || request_irq(dev->irq, &tulip_interrupt, 0,
- tulip_tbl[tp->chip_id].chip_name)) {
- return -EAGAIN;
- }
-#endif
+ outl(tp->csr0, ioaddr + CSR0);
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
- MOD_INC_USE_COUNT;
-
- spin_lock_init(&tp->tx_lock);
- tulip_init_ring(dev);
-
- /* This is set_rx_mode(), but without starting the transmitter. */
- /* Fill the whole address filter table with our physical address. */
- {
- u16 *eaddrs = (u16 *)dev->dev_addr;
- u32 *setup_frm = tp->setup_frame, i;
-
- /* You must add the broadcast address when doing perfect filtering! */
- *setup_frm++ = 0xffff;
- *setup_frm++ = 0xffff;
- *setup_frm++ = 0xffff;
- /* Fill the rest of the accept table with our physical address. */
- for (i = 1; i < 16; i++) {
- *setup_frm++ = eaddrs[0];
- *setup_frm++ = eaddrs[1];
- *setup_frm++ = eaddrs[2];
+ if (tp->flags & MC_HASH_ONLY) {
+ u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+ u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
+ if (tp->chip_id == AX88140) {
+ outl(0, ioaddr + CSR13);
+ outl(addr_low, ioaddr + CSR14);
+ outl(1, ioaddr + CSR13);
+ outl(addr_high, ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) {
+ outl(addr_low, ioaddr + 0xA4);
+ outl(addr_high, ioaddr + 0xA8);
+ outl(0, ioaddr + 0xAC);
+ outl(0, ioaddr + 0xB0);
}
+ } else {
+ /* This is set_rx_mode(), but without starting the transmitter. */
+ u16 *eaddrs = (u16 *)dev->dev_addr;
+ u16 *setup_frm = &tp->setup_frame[15*6];
+
+ /* 21140 bug: you must add the broadcast address. */
+ memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame));
+ /* Fill the final entry of the table with our physical address. */
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
/* Put the setup frame on the Tx list. */
- tp->tx_ring[0].length = 0x08000000 | 192;
- tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
- tp->tx_ring[0].status = 0x80000000;
+ tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
+ tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame);
+ tp->tx_ring[0].status = cpu_to_le32(DescOwned);
tp->cur_tx++;
}
@@ -1255,13 +1011,12 @@ tulip_open(struct net_device *dev)
outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+ tp->saved_if_port = dev->if_port;
if (dev->if_port == 0)
dev->if_port = tp->default_port;
- if (tp->chip_id == DC21041 && dev->if_port > 4)
- /* Invalid: Select initial TP, autosense, autonegotiate. */
- dev->if_port = 4;
/* Allow selecting a default media. */
+ i = 0;
if (tp->mtable == NULL)
goto media_picked;
if (dev->if_port) {
@@ -1274,42 +1029,91 @@ tulip_open(struct net_device *dev)
goto media_picked;
}
}
- if ((tp->mtable->defaultmedia & 0x0800) == 0)
+ if ((tp->mtable->defaultmedia & 0x0800) == 0) {
+ int looking_for = tp->mtable->defaultmedia & 15;
for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) {
- printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
- dev->name, medianame[tp->mtable->mleaf[i].media]);
- goto media_picked;
- }
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+ dev->name, medianame[looking_for]);
+ goto media_picked;
+ }
+ }
/* Start sensing first non-full-duplex media. */
for (i = tp->mtable->leafcount - 1;
(media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
- ;
+ ;
media_picked:
tp->csr6 = 0;
tp->cur_index = i;
+ tp->nwayset = 0;
+ if (dev->if_port == 0 && tp->chip_id == DC21041) {
+ tp->nway = 1;
+ }
if (dev->if_port == 0 && tp->chip_id == DC21142) {
- tp->csr6 = 0x82420200;
- outl(0x0003FFFF, ioaddr + CSR14);
+ if (tp->mii_cnt) {
+ select_media(dev, 1);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Using MII transceiver %d, status "
+ "%4.4x.\n",
+ dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
+ outl_CSR6(tp, 0x82020000);
+ tp->csr6 = 0x820E0000;
+ dev->if_port = 11;
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ } else
+ t21142_start_nway(dev);
+ } else if (tp->chip_id == PNIC2) {
+ t21142_start_nway(dev);
+ } else if (tp->chip_id == LC82C168 && ! tp->medialock) {
+ if (tp->mii_cnt) {
+ dev->if_port = 11;
+ tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0001, ioaddr + CSR15);
+ } else if (inl(ioaddr + CSR5) & TPLnkPass)
+ pnic_do_nway(dev);
+ else {
+ /* Start with 10mbps to do autonegotiation. */
+ outl(0x32, ioaddr + CSR12);
+ tp->csr6 = 0x00420000;
+ outl(0x0001B078, ioaddr + 0xB8);
+ outl(0x0201B078, ioaddr + 0xB8);
+ next_tick = 1*HZ;
+ }
+ } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
+ && ! tp->medialock) {
+ dev->if_port = 0;
+ tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
+ /* Provided by BOLO, Macronix - 12/10/1998. */
+ dev->if_port = 0;
+ tp->csr6 = 0x01a80200;
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
+ } else if (tp->chip_id == DC21143 &&
+ media_cap[dev->if_port] & MediaIsMII) {
+ /* We must reset the media CSRs when we force-select MII mode. */
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
outl(0x0008, ioaddr + CSR15);
- outl(0x0001, ioaddr + CSR13);
- outl(0x1301, ioaddr + CSR12);
- } else if (tp->chip_id == LC82C168 && tp->mii_cnt && ! tp->medialock) {
- dev->if_port = 11;
- tp->csr6 = 0x816C0000 | (tp->full_duplex ? 0x0200 : 0);
- outl(0x0001, ioaddr + CSR15);
+ } else if (tp->chip_id == COMET) {
+ dev->if_port = 0;
+ tp->csr6 = 0x00040000;
+ } else if (tp->chip_id == AX88140) {
+ tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
} else
select_media(dev, 1);
/* Start the chip's Tx to process setup frame. */
- outl(tp->csr6, ioaddr + CSR6);
- outl(tp->csr6 | 0x2000, ioaddr + CSR6);
+ outl_CSR6(tp, tp->csr6);
+ outl_CSR6(tp, tp->csr6 | 0x2000);
/* Enable interrupts by setting the interrupt mask. */
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
outl(0, ioaddr + CSR2); /* Rx poll demand */
if (tulip_debug > 2) {
@@ -1320,16 +1124,33 @@ media_picked:
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
init_timer(&tp->timer);
- tp->timer.expires = RUN_AT(5*HZ);
+ tp->timer.expires = RUN_AT(next_tick);
tp->timer.data = (unsigned long)dev;
tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
add_timer(&tp->timer);
- netif_start_queue(dev);
+ netif_device_attach(dev);
+}
+
+static int
+tulip_open(struct net_device *dev)
+{
+ MOD_INC_USE_COUNT;
+
+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ tulip_init_ring (dev);
+
+ tulip_up (dev);
+
return 0;
}
+
/* Set up the transceiver control registers for the selected media type. */
static void select_media(struct net_device *dev, int startup)
{
@@ -1337,7 +1158,7 @@ static void select_media(struct net_device *dev, int startup)
struct tulip_private *tp = (struct tulip_private *)dev->priv;
struct mediatable *mtable = tp->mtable;
u32 new_csr6;
- int check_mii =0, i;
+ int i;
if (mtable) {
struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
@@ -1355,33 +1176,56 @@ static void select_media(struct net_device *dev, int startup)
new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
break;
case 2: case 4: {
- u16 setup[3];
- for (i = 0; i < 3; i++)
+ u16 setup[5];
+ u32 csr13val, csr14val, csr15dir, csr15val;
+ for (i = 0; i < 5; i++)
setup[i] = get_u16(&p[i*2 + 1]);
dev->if_port = p[0] & 15;
+ if (media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+
+ if (startup && mtable->has_reset) {
+ struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
+ unsigned char *rst = rleaf->leafdata;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
+ dev->name);
+ for (i = 0; i < rst[0]; i++)
+ outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
+ }
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
+ printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
+ "%4.4x/%4.4x.\n",
dev->name, medianame[dev->if_port], setup[0], setup[1]);
if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
+ csr13val = setup[0];
+ csr14val = setup[1];
+ csr15dir = (setup[3]<<16) | setup[2];
+ csr15val = (setup[4]<<16) | setup[2];
outl(0, ioaddr + CSR13);
- outl(setup[1], ioaddr + CSR14);
- outl(setup[2], ioaddr + CSR15);
- outl(setup[0], ioaddr + CSR13);
- for (i = 0; i < 3; i++) /* Re-fill setup[] */
- setup[i] = get_u16(&p[i*2 + 7]);
- } else if (dev->if_port <= 4) {
- outl(0, ioaddr + CSR13);
- outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
- outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
- outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ outl(csr13val, ioaddr + CSR13);
} else {
- outl(0, ioaddr + CSR14);
- outl(8, ioaddr + CSR15);
- outl(0, ioaddr + CSR13);
+ csr13val = 1;
+ csr14val = 0x0003FF7F;
+ csr15dir = (setup[0]<<16) | 0x0008;
+ csr15val = (setup[1]<<16) | 0x0008;
+ if (dev->if_port <= 4)
+ csr14val = t21142_csr14[dev->if_port];
+ if (startup) {
+ outl(0, ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ }
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ if (startup) outl(csr13val, ioaddr + CSR13);
}
- outl(setup[0]<<16, ioaddr + CSR15); /* Direction */
- outl(setup[1]<<16, ioaddr + CSR15); /* Data */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n",
+ dev->name, csr15dir, csr15val);
if (mleaf->type == 4)
new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
else
@@ -1395,7 +1239,6 @@ static void select_media(struct net_device *dev, int startup)
u16 to_advertise;
dev->if_port = 11;
- check_mii = 1;
new_csr6 = 0x020E0000;
if (mleaf->type == 3) { /* 21142 */
u16 *init_sequence = (u16*)(p+2);
@@ -1422,7 +1265,7 @@ static void select_media(struct net_device *dev, int startup)
}
to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
tp->advertising[phy_num] = to_advertise;
- if (tulip_debug > 1 || 1)
+ if (tulip_debug > 1)
printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n",
dev->name, to_advertise, phy_num, tp->phys[phy_num]);
/* Bogus: put in by a committee? */
@@ -1430,32 +1273,33 @@ static void select_media(struct net_device *dev, int startup)
break;
}
default:
- new_csr6 = 0x020E0000;
+ printk(KERN_DEBUG "%s: Invalid media table selection %d.\n",
+ dev->name, mleaf->type);
+ new_csr6 = 0x020E0000;
}
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
dev->name, medianame[dev->if_port],
inl(ioaddr + CSR12) & 0xff);
} else if (tp->chip_id == DC21041) {
+ int port = dev->if_port <= 4 ? dev->if_port : 0;
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
- dev->name, medianame[dev->if_port & 15],
- inl(ioaddr + CSR12) & 0xffff);
+ dev->name, medianame[port == 3 ? 12: port],
+ inl(ioaddr + CSR12));
outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
- outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
- outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
- outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ outl(t21041_csr14[port], ioaddr + CSR14);
+ outl(t21041_csr15[port], ioaddr + CSR15);
+ outl(t21041_csr13[port], ioaddr + CSR13);
new_csr6 = 0x80020000;
} else if (tp->chip_id == LC82C168) {
if (startup && ! tp->medialock)
dev->if_port = tp->mii_cnt ? 11 : 0;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x,"
- " media %s.\n",
- dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
- medianame[dev->if_port]);
+ printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
+ dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]);
if (tp->mii_cnt) {
- new_csr6 = 0x812C0000;
+ new_csr6 = 0x810C0000;
outl(0x0001, ioaddr + CSR15);
outl(0x0201B07A, ioaddr + 0xB8);
} else if (startup) {
@@ -1467,10 +1311,8 @@ static void select_media(struct net_device *dev, int startup)
} else if (dev->if_port == 3 || dev->if_port == 5) {
outl(0x33, ioaddr + CSR12);
new_csr6 = 0x01860000;
- if (startup)
- outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */
- else
- outl(0x1F868, ioaddr + 0xB8);
+ /* Trigger autonegotiation. */
+ outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
} else {
outl(0x32, ioaddr + CSR12);
new_csr6 = 0x00420000;
@@ -1481,20 +1323,24 @@ static void select_media(struct net_device *dev, int startup)
int csr12 = inl(ioaddr + CSR12);
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
- dev->name, dev->if_port ? "AUI" : "10baseT", csr12);
- new_csr6 = (dev->if_port ? 0x01860000 : 0x00420000);
+ dev->name, medianame[dev->if_port], csr12);
+ if (media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ new_csr6 = 0x20000;
/* Set the full duplux match frame. */
outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
- outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+ if (t21040_csr13[dev->if_port] & 8) {
+ outl(0x0705, ioaddr + CSR14);
+ outl(0x0006, ioaddr + CSR15);
+ } else {
+ outl(0xffff, ioaddr + CSR14);
+ outl(0x0000, ioaddr + CSR15);
+ }
+ outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13);
} else { /* Unknown chip type with no media table. */
if (tp->default_port == 0)
- {
- if (tp->mii_cnt)
- dev->if_port = 11;
- else
- dev->if_port = 3;
- }
+ dev->if_port = tp->mii_cnt ? 11 : 3;
if (media_cap[dev->if_port] & MediaIsMII) {
new_csr6 = 0x020E0000;
} else if (media_cap[dev->if_port] & MediaIsFx) {
@@ -1512,28 +1358,79 @@ static void select_media(struct net_device *dev, int startup)
return;
}
+/*
+ Check the MII negotiated duplex, and change the CSR6 setting if
+ required.
+ Return 0 if everything is OK.
+ Return < 0 if the transceiver is missing or has no link beat.
+ */
+static int check_duplex(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int mii_reg1, mii_reg5, negotiated, duplex;
+
+ if (tp->full_duplex_lock)
+ return 0;
+ mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+ mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+ "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
+ if (mii_reg1 == 0xffff)
+ return -2;
+ if ((mii_reg1 & 0x0004) == 0) {
+ int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+ if ((new_reg1 & 0x0004) == 0) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: No link beat on the MII interface,"
+ " status %4.4x.\n", dev->name, new_reg1);
+ return -1;
+ }
+ }
+ negotiated = mii_reg5 & tp->advertising[0];
+ duplex = ((negotiated & 0x0300) == 0x0100
+ || (negotiated & 0x00C0) == 0x0040);
+ /* 100baseTx-FD or 10T-FD, but not 100-HD */
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ if (negotiated & 0x038) /* 100mbps. */
+ tp->csr6 &= ~0x00400000;
+ if (tp->full_duplex) tp->csr6 |= 0x0200;
+ else tp->csr6 &= ~0x0200;
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
+ if (tulip_debug > 0)
+ printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+ "#%d link partner capability of %4.4x.\n",
+ dev->name, tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ return 1;
+ }
+ return 0;
+}
+
static void tulip_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
u32 csr12 = inl(ioaddr + CSR12);
- int next_tick = 0;
+ int next_tick = 2*HZ;
- if (tulip_debug > 3) {
- printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x "
- "SIA %8.8x %8.8x %8.8x %8.8x.\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6),
- csr12, inl(ioaddr + CSR13),
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
+ " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
+ dev->name, medianame[dev->if_port], inl(ioaddr + CSR5),
+ inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13),
inl(ioaddr + CSR14), inl(ioaddr + CSR15));
}
switch (tp->chip_id) {
case DC21040:
- if (csr12 & 0x0002) { /* Network error */
- printk(KERN_INFO "%s: No 10baseT link beat found, switching to %s media.\n",
- dev->name, dev->if_port ? "10baseT" : "AUI");
- dev->if_port ^= 1;
- outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+ if (!tp->medialock && csr12 & 0x0002) { /* Network error */
+ printk(KERN_INFO "%s: No link beat found.\n",
+ dev->name);
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ select_media(dev, 0);
dev->trans_start = jiffies;
}
break;
@@ -1541,6 +1438,7 @@ static void tulip_timer(unsigned long data)
if (tulip_debug > 2)
printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n",
dev->name, csr12);
+ if (tp->medialock) break;
switch (dev->if_port) {
case 0: case 3: case 4:
if (csr12 & 0x0004) { /*LnkFail */
@@ -1562,25 +1460,26 @@ static void tulip_timer(unsigned long data)
break;
case 1: /* 10base2 */
case 2: /* AUI */
- if (csr12 & 0x0100) {
- next_tick = (30*HZ); /* 30 sec. */
- tp->mediasense = 0;
- } else if ((csr12 & 0x0004) == 0) {
- printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", dev->name);
- dev->if_port = 0;
- select_media(dev, 0);
- next_tick = (24*HZ)/10; /* 2.4 sec. */
- } else if (tp->mediasense || (csr12 & 0x0002)) {
- dev->if_port = 3 - dev->if_port; /* Swap ports. */
- select_media(dev, 0);
- next_tick = 20*HZ;
- } else {
- next_tick = 20*HZ;
- }
- break;
+ if (csr12 & 0x0100) {
+ next_tick = (30*HZ); /* 30 sec. */
+ tp->mediasense = 0;
+ } else if ((csr12 & 0x0004) == 0) {
+ printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
+ dev->name);
+ dev->if_port = 0;
+ select_media(dev, 0);
+ next_tick = (24*HZ)/10; /* 2.4 sec. */
+ } else if (tp->mediasense || (csr12 & 0x0002)) {
+ dev->if_port = 3 - dev->if_port; /* Swap ports. */
+ select_media(dev, 0);
+ next_tick = 20*HZ;
+ } else {
+ next_tick = 20*HZ;
+ }
+ break;
}
break;
- case DC21140: case DC21142: case MX98713: default: {
+ case DC21140: case DC21142: case MX98713: case COMPEX9881: default: {
struct medialeaf *mleaf;
unsigned char *p;
if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
@@ -1644,58 +1543,16 @@ static void tulip_timer(unsigned long data)
medianame[tp->mtable->mleaf[tp->cur_index].media]);
select_media(dev, 0);
/* Restart the transmit process. */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
next_tick = (24*HZ)/10;
break;
}
- case 1: case 3: { /* 21140, 21142 MII */
- int mii_reg1, mii_reg5;
+ case 1: case 3: /* 21140, 21142 MII */
actually_mii:
- mii_reg1 = mdio_read(dev, tp->phys[0], 1);
- mii_reg5 = mdio_read(dev, tp->phys[0], 5);
- if (tulip_debug > 1)
- printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
- "%4.4x, CSR12 %2.2x, %cD.\n",
- dev->name, mii_reg1, mii_reg5, csr12,
- tp->full_duplex ? 'F' : 'H');
- if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0) {
- int new_reg1 = mdio_read(dev, tp->phys[0], 1);
- if ((new_reg1 & 0x0004) == 0) {
- printk(KERN_INFO "%s: No link beat on the MII interface,"
- " status then %4.4x now %4.4x.\n",
- dev->name, mii_reg1, new_reg1);
- if (tp->mtable && tp->mtable->has_nonmii)
- goto select_next_media;
- }
- }
- if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
- ; /* No MII device or no link partner report */
- else if (tp->full_duplex_lock)
- ;
- else {
- int negotiated = mii_reg5 & tp->advertising[0];
- int duplex = ((negotiated & 0x0100) != 0
- || (negotiated & 0x00C0) == 0x0040);
- /* 100baseTx-FD or 10T-FD, but not 100-HD */
- if (tp->full_duplex != duplex) {
- tp->full_duplex = duplex;
- if (tp->full_duplex)
- tp->csr6 |= 0x0200;
- else
- tp->csr6 &= ~0x0200;
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- if (tulip_debug > 0) /* Gurppp, should be >1 */
- printk(KERN_INFO "%s: Setting %s-duplex based on MII"
- " Xcvr #%d parter capability of %4.4x.\n",
- dev->name, tp->full_duplex ? "full" : "half",
- tp->phys[0], mii_reg5);
- }
- }
+ check_duplex(dev);
next_tick = 60*HZ;
break;
- }
case 2: /* 21142 serial block has no link beat. */
default:
break;
@@ -1703,12 +1560,11 @@ static void tulip_timer(unsigned long data)
}
break;
}
- if (next_tick) {
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
- }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
}
+
/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
of available transceivers. */
static void t21142_timer(unsigned long data)
@@ -1720,111 +1576,204 @@ static void t21142_timer(unsigned long data)
int next_tick = 60*HZ;
int new_csr6 = 0;
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+ if (tulip_debug > 2)
+ printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
dev->name, csr12, medianame[dev->if_port]);
- if (dev->if_port == 3) {
- if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
- new_csr6 = 0x82420200;
- outl(new_csr6, ioaddr + CSR6);
- outl(0x0000, ioaddr + CSR13);
- outl(0x0003FFFF, ioaddr + CSR14);
- outl(0x0008, ioaddr + CSR15);
- outl(0x0001, ioaddr + CSR13);
- outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ check_duplex(dev);
+ next_tick = 60*HZ;
+ } else if (tp->nwayset) {
+ /* Don't screw up a negotiated session! */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ } else if (tp->medialock) {
+ ;
+ } else if (dev->if_port == 3) {
+ if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
+ "trying NWay.\n", dev->name, csr12);
+ t21142_start_nway(dev);
+ next_tick = 3*HZ;
}
} else if ((csr12 & 0x7000) != 0x5000) {
/* Negotiation failed. Search media types. */
if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+ printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
dev->name, csr12);
if (!(csr12 & 4)) { /* 10mbps link beat good. */
new_csr6 = 0x82420000;
dev->if_port = 0;
outl(0, ioaddr + CSR13);
outl(0x0003FFFF, ioaddr + CSR14);
- outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+ outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
- } else if (csr12 & 0x100) {
- new_csr6 = 0x82420200;
- dev->if_port = 2;
- outl(0, ioaddr + CSR13);
- outl(0x0003FFFF, ioaddr + CSR14);
- outl(0x0008, ioaddr + CSR15);
- outl(0x0001, ioaddr + CSR13);
} else {
/* Select 100mbps port to check for link beat. */
new_csr6 = 0x83860000;
dev->if_port = 3;
outl(0, ioaddr + CSR13);
outl(0x0003FF7F, ioaddr + CSR14);
- outl(8, ioaddr + CSR15);
+ outw(8, ioaddr + CSR15);
outl(1, ioaddr + CSR13);
}
if (tulip_debug > 1)
- printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+ printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
dev->name, medianame[dev->if_port]);
if (new_csr6 != (tp->csr6 & ~0x00D5)) {
tp->csr6 &= 0x00D5;
tp->csr6 |= new_csr6;
outl(0x0301, ioaddr + CSR12);
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
}
+ next_tick = 3*HZ;
}
+
tp->timer.expires = RUN_AT(next_tick);
add_timer(&tp->timer);
}
-static void t21142_lnk_change( struct net_device *dev)
+
+static void t21142_start_nway(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr14 = ((tp->to_advertise & 0x0780) << 9) |
+ ((tp->to_advertise&0x0020)<<1) | 0xffbf;
+
+ dev->if_port = 0;
+ tp->nway = tp->mediasense = 1;
+ tp->nwayset = tp->lpar = 0;
+ if (debug > 1)
+ printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
+ dev->name, csr14);
+ outl(0x0001, ioaddr + CSR13);
+ outl(csr14, ioaddr + CSR14);
+ tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+ outl_CSR6(tp, tp->csr6);
+ if (tp->mtable && tp->mtable->csr15dir) {
+ outl(tp->mtable->csr15dir, ioaddr + CSR15);
+ outl(tp->mtable->csr15val, ioaddr + CSR15);
+ } else
+ outw(0x0008, ioaddr + CSR15);
+ outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */
+}
+
+
+static void t21142_lnk_change(struct net_device *dev, int csr5)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
int csr12 = inl(ioaddr + CSR12);
if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
- dev->name, csr12, inl(ioaddr + CSR5));
-
- if ((csr12 & 0x7000) == 0x5000) {
- if (csr12 & 0x01800000) {
- /* Switch to 100mbps mode. */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- if (csr12 & 0x01000000) {
- dev->if_port = 5;
- tp->csr6 = 0x83860200;
- } else {
+ printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
+ "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
+
+ /* If NWay finished and we have a negotiated partner capability. */
+ if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
+ int setup_done = 0;
+ int negotiated = tp->to_advertise & (csr12 >> 16);
+ tp->lpar = csr12 >> 16;
+ tp->nwayset = 1;
+ if (negotiated & 0x0100) dev->if_port = 5;
+ else if (negotiated & 0x0080) dev->if_port = 3;
+ else if (negotiated & 0x0040) dev->if_port = 4;
+ else if (negotiated & 0x0020) dev->if_port = 0;
+ else {
+ tp->nwayset = 0;
+ if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180))
dev->if_port = 3;
- tp->csr6 = 0x83860000;
- }
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- } /* Else 10baseT-FD is handled automatically. */
- } else if (dev->if_port == 3) {
- if (!(csr12 & 2))
- printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
- dev->name);
- else
- dev->if_port = 0;
- } else if (dev->if_port == 0) {
- if (!(csr12 & 4))
- printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+ }
+ tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0;
+
+ if (tulip_debug > 1) {
+ if (tp->nwayset)
+ printk(KERN_INFO "%s: Switching to %s based on link "
+ "negotiation %4.4x & %4.4x = %4.4x.\n",
+ dev->name, medianame[dev->if_port], tp->to_advertise,
+ tp->lpar, negotiated);
+ else
+ printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
+ " link beat status %4.4x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ }
+
+ if (tp->mtable) {
+ int i;
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == dev->if_port) {
+ tp->cur_index = i;
+ select_media(dev, 0);
+ setup_done = 1;
+ break;
+ }
+ }
+ if ( ! setup_done) {
+ tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
+ if (tp->full_duplex)
+ tp->csr6 |= 0x0200;
+ outl(1, ioaddr + CSR13);
+ }
+#if 0 /* Restart shouldn't be needed. */
+ outl_CSR6(tp, tp->csr6 | 0x0000);
+ if (debug > 2)
+ printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n",
+ dev->name, inl(ioaddr + CSR5));
+#endif
+ outl_CSR6(tp, tp->csr6 | 0x2002);
+ if (debug > 2)
+ printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
+ dev->name, tp->csr6, inl(ioaddr + CSR6),
+ inl(ioaddr + CSR12));
+ } else if ((tp->nwayset && (csr5 & 0x08000000)
+ && (dev->if_port == 3 || dev->if_port == 5)
+ && (csr12 & 2) == 2) ||
+ (tp->nway && (csr5 & (TPLnkFail)))) {
+ /* Link blew? Maybe restart NWay. */
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
+ dev->name, medianame[dev->if_port],
+ (csr12 & 2) ? "failed" : "good");
+ if ((csr12 & 2) && ! tp->medialock) {
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ }
+ } else if (dev->if_port == 0 || dev->if_port == 4) {
+ if ((csr12 & 4) == 0)
+ printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
dev->name);
} else if (!(csr12 & 4)) { /* 10mbps link beat good. */
- printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
+ dev->name);
+ dev->if_port = 0;
+ } else if (tp->nwayset) {
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
+ dev->name, medianame[dev->if_port], tp->csr6);
+ } else { /* 100mbps link beat good. */
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
dev->name);
- dev->if_port = 0;
- } else { /* 100mbps link beat good. */
- printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
- dev->name);
dev->if_port = 3;
tp->csr6 = 0x83860000;
outl(0x0003FF7F, ioaddr + CSR14);
outl(0x0301, ioaddr + CSR12);
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
}
}
-
+
static void mxic_timer(unsigned long data)
{
@@ -1843,57 +1792,104 @@ static void mxic_timer(unsigned long data)
}
}
+
+static void pnic_do_nway(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u32 phy_reg = inl(ioaddr + 0xB8);
+ u32 new_csr6 = tp->csr6 & ~0x40C40200;
+
+ if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+ if (phy_reg & 0x20000000) dev->if_port = 5;
+ else if (phy_reg & 0x40000000) dev->if_port = 3;
+ else if (phy_reg & 0x10000000) dev->if_port = 4;
+ else if (phy_reg & 0x08000000) dev->if_port = 0;
+ tp->nwayset = 1;
+ new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
+ outl(0x32 | (dev->if_port & 1), ioaddr + CSR12);
+ if (dev->if_port & 1)
+ outl(0x1F868, ioaddr + 0xB8);
+ if (phy_reg & 0x30000000) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x00000200;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
+ dev->name, phy_reg, medianame[dev->if_port]);
+ if (tp->csr6 != new_csr6) {
+ tp->csr6 = new_csr6;
+ /* Restart Tx */
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
+ dev->trans_start = jiffies;
+ }
+ }
+}
+
+
+static void pnic_lnk_change(struct net_device *dev, int csr5)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int phy_reg = inl(ioaddr + 0xB8);
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
+ dev->name, phy_reg, csr5);
+ if (inl(ioaddr + CSR5) & TPLnkFail) {
+ outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
+ if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) {
+ tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
+ outl_CSR6(tp, tp->csr6);
+ outl(0x30, ioaddr + CSR12);
+ outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+ dev->trans_start = jiffies;
+ }
+ } else if (inl(ioaddr + CSR5) & TPLnkPass) {
+ pnic_do_nway(dev);
+ outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
+ }
+}
+
+
static void pnic_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
- int csr12 = inl(ioaddr + CSR12);
int next_tick = 60*HZ;
- int new_csr6 = tp->csr6 & ~0x40C40200;
if (media_cap[dev->if_port] & MediaIsMII) {
- int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
-
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: LC82C168 negotiated capability %8.8x, "
- "CSR5 %8.8x.\n",
- dev->name, negotiated, inl(ioaddr + CSR5));
-
- if (negotiated & 0x0380) /* 10 vs 100mbps */
- new_csr6 |= 0x812E0000;
- else
- new_csr6 |= 0x816E0000;
- if (((negotiated & 0x0300) == 0x0100) /* Duplex */
- || (negotiated & 0x00C0) == 0x0040
- || tp->full_duplex_lock) {
- tp->full_duplex = 1;
- new_csr6 |= 0x0200;
- }
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: LC82C168 MII PHY status %4.4x, Link "
- "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
- dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
- tp->csr6, inl(ioaddr + CSR6));
+ if (check_duplex(dev) > 0)
+ next_tick = 3*HZ;
} else {
+ int csr12 = inl(ioaddr + CSR12);
+ int new_csr6 = tp->csr6 & ~0x40C40200;
int phy_reg = inl(ioaddr + 0xB8);
int csr5 = inl(ioaddr + CSR5);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
- dev->name, phy_reg, csr5);
-
+ printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
+ "CSR5 %8.8x.\n",
+ dev->name, phy_reg, medianame[dev->if_port], csr5);
if (phy_reg & 0x04000000) { /* Remote link fault */
- /*outl(0x0201F078, ioaddr + 0xB8);*/
- next_tick = 3*HZ;
- }
- if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+ outl(0x0201F078, ioaddr + 0xB8);
+ next_tick = 1*HZ;
+ tp->nwayset = 0;
+ } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+ pnic_do_nway(dev);
+ next_tick = 60*HZ;
+ } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
"CSR5 %8.8x, PHY %3.3x.\n",
dev->name, medianame[dev->if_port], csr12,
inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+ next_tick = 3*HZ;
if (tp->medialock) {
+ } else if (tp->nwayset && (dev->if_port & 1)) {
+ next_tick = 1*HZ;
} else if (dev->if_port == 0) {
dev->if_port = 3;
outl(0x33, ioaddr + CSR12);
@@ -1905,125 +1901,145 @@ static void pnic_timer(unsigned long data)
new_csr6 = 0x00420000;
outl(0x1F078, ioaddr + 0xB8);
}
- new_csr6 |= (tp->csr6 & 0xfdff);
- next_tick = 3*HZ;
- } else
- new_csr6 = tp->csr6;
- if (tp->full_duplex_lock || (phy_reg & 0x30000000) != 0) {
- tp->full_duplex = 1;
- new_csr6 |= 0x00000200;
+ if (tp->csr6 != new_csr6) {
+ tp->csr6 = new_csr6;
+ /* Restart Tx */
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
+ dev->trans_start = jiffies;
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Changing PNIC configuration to %s "
+ "%s-duplex, CSR6 %8.8x.\n",
+ dev->name, medianame[dev->if_port],
+ tp->full_duplex ? "full" : "half", new_csr6);
+ }
}
}
- if (tp->csr6 != new_csr6) {
- tp->csr6 = new_csr6;
- outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- dev->trans_start = jiffies;
- if (tulip_debug > 0) /* Gurppp, should be >1 */
- printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
- "CSR6 %8.8x.\n",
- dev->name, tp->full_duplex ? "full" : "half", new_csr6);
- }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void comet_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
+ "%4.4x.\n",
+ dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
tp->timer.expires = RUN_AT(next_tick);
add_timer(&tp->timer);
}
static void tulip_tx_timeout(struct net_device *dev)
{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
- printk("%s: transmit timed out\n", dev->name);
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ /* Do nothing -- the media monitor should handle this. */
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+ dev->name);
+ } else if (tp->chip_id == DC21040) {
+ if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) {
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ printk(KERN_INFO "%s: transmit timed out, switching to "
+ "%s.\n",
+ dev->name, medianame[dev->if_port]);
+ select_media(dev, 0);
+ }
+ dev->trans_start = jiffies;
+ return;
+ } else if (tp->chip_id == DC21041) {
+ int csr12 = inl(ioaddr + CSR12);
- if (media_cap[dev->if_port] & MediaIsMII) {
- /* Do nothing -- the media monitor should handle this. */
-#if 0
- if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
+ "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), csr12,
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+ tp->mediasense = 1;
+ if ( ! tp->medialock) {
+ if (dev->if_port == 1 || dev->if_port == 2)
+ if (csr12 & 0x0004) {
+ dev->if_port = 2 - dev->if_port;
+ } else
+ dev->if_port = 0;
+ else
+ dev->if_port = 1;
+ select_media(dev, 0);
+ }
+ } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+ || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
+ printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ if ( ! tp->medialock && tp->mtable) {
+ do
+ --tp->cur_index;
+ while (tp->cur_index >= 0
+ && (media_cap[tp->mtable->mleaf[tp->cur_index].media]
+ & MediaIsFD));
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ select_media(dev, 0);
+ printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+ "media.\n", dev->name, medianame[dev->if_port]);
+ }
+ } else {
+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
+ "%8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+ dev->if_port = 0;
+ }
+
+#if defined(way_too_many_messages)
+ if (tulip_debug > 3) {
+ int i;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
+ int j;
+ printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x "
+ "%2.2x %2.2x %2.2x.\n",
+ i, (unsigned int)tp->rx_ring[i].status,
+ (unsigned int)tp->rx_ring[i].length,
+ (unsigned int)tp->rx_ring[i].buffer1,
+ (unsigned int)tp->rx_ring[i].buffer2,
+ buf[0], buf[1], buf[2]);
+ for (j = 0; buf[j] != 0xee && j < 1600; j++)
+ if (j < 100) printk(" %2.2x", buf[j]);
+ printk(" j=%d.\n", j);
+ }
+ printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+ printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+ printk("\n");
+ }
#endif
- printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
- dev->name);
- dev->trans_start = jiffies;
- return;
- } else if (tp->chip_id == DC21040) {
- if (inl(ioaddr + CSR12) & 0x0002) {
- printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n",
- dev->name, dev->if_port ? "10baseT" : "AUI");
- dev->if_port ^= 1;
- outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
- }
- dev->trans_start = jiffies;
- return;
- } else if (tp->chip_id == DC21041) {
- u32 csr12 = inl(ioaddr + CSR12);
- printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x,"
- " CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), csr12,
- inl(ioaddr + CSR13), inl(ioaddr + CSR14));
- tp->mediasense = 1;
- if (dev->if_port == 1 || dev->if_port == 2)
- if (csr12 & 0x0004) {
- dev->if_port = 2 - dev->if_port;
- } else
- dev->if_port = 0;
- else
- dev->if_port = 1;
- select_media(dev, 0);
- tp->stats.tx_errors++;
+ /* Stop and restart the chip's Tx processes . */
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
+
dev->trans_start = jiffies;
+ tp->stats.tx_errors++;
return;
- } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
- || tp->chip_id == MX98713) {
- /* Stop the transmit process. */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
- "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
- inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
- if (tp->mtable) {
- if (--tp->cur_index < 0) {
- /* We start again, but should instead look for default. */
- tp->cur_index = tp->mtable->leafcount - 1;
- }
- select_media(dev, 0);
- printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
- dev->name, dev->if_port ? "100baseTx" : "10baseT");
- }
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- tp->stats.tx_errors++;
- dev->trans_start = jiffies;
- return;
- } else
- printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
- " resetting...\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
-#ifdef way_too_many_messages
- printk(" Rx ring %8.8x: ", (int)tp->rx_ring);
- for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
- printk("\n Tx ring %8.8x: ", (int)tp->tx_ring);
- for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
- printk("\n");
-#endif
-
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- /* Trigger an immediate transmit demand. */
- outl(0, ioaddr + CSR1);
-
- dev->trans_start = jiffies;
- tp->stats.tx_errors++;
- return;
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void
-tulip_init_ring(struct net_device *dev)
+static void tulip_init_ring(struct net_device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int i;
@@ -2031,36 +2047,42 @@ tulip_init_ring(struct net_device *dev)
tp->tx_full = 0;
tp->cur_rx = tp->cur_tx = 0;
tp->dirty_rx = tp->dirty_tx = 0;
+ tp->susp_rx = 0;
+ tp->ttimer = 0;
+ tp->nir = 0;
for (i = 0; i < RX_RING_SIZE; i++) {
- tp->rx_ring[i].status = 0x80000000; /* Owned by Tulip chip */
- tp->rx_ring[i].length = PKT_BUF_SZ;
- {
- /* Note the receive buffer must be longword aligned.
- dev_alloc_skb() provides 16 byte alignment. But do *not*
- use skb_reserve() to align the IP header! */
- struct sk_buff *skb;
- skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
- tp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break; /* Bad news! */
- skb->dev = dev; /* Mark as being used by this device. */
- tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
- }
- tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
+ tp->rx_ring[i].status = 0x00000000;
+ tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);
+ tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]);
+ tp->rx_skbuff[i] = NULL;
}
/* Mark the last entry as wrapping the ring. */
- tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000;
- tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
+ tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP);
+ tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]);
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ /* Note the receive buffer must be longword aligned.
+ dev_alloc_skb() provides 16 byte alignment. But do *not*
+ use skb_reserve() to align the IP header! */
+ struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+ tp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */
+ tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail);
+ }
+ tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
/* The Tx buffer descriptor is filled in as needed, but we
do need to clear the ownership bit. */
for (i = 0; i < TX_RING_SIZE; i++) {
tp->tx_skbuff[i] = 0;
tp->tx_ring[i].status = 0x00000000;
- tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
+ tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]);
}
- tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
+ tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]);
}
static int
@@ -2071,8 +2093,8 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 flag;
unsigned long cpuflags;
- /* Caution: the write order is important here, set the base address
- with the "ownership" bits last. */
+ /* Caution: the write order is important here, set the field
+ with the ownership bits last. */
spin_lock_irqsave(&tp->tx_lock, cpuflags);
@@ -2080,25 +2102,24 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->cur_tx % TX_RING_SIZE;
tp->tx_skbuff[entry] = skb;
- tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+ tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data);
if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
- flag = 0x60000000; /* No interrupt */
+ flag = 0x60000000; /* No interrupt */
} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
- flag = 0xe0000000; /* Tx-done intr. */
+ flag = 0xe0000000; /* Tx-done intr. */
} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
- flag = 0x60000000; /* No Tx-done intr. */
- } else {
- /* Leave room for set_rx_mode() to fill entries. */
- flag = 0xe0000000; /* Tx-done intr. */
- tp->tx_full = 1;
- netif_stop_queue(dev);
+ flag = 0x60000000; /* No Tx-done intr. */
+ } else { /* Leave room for set_rx_mode() to fill entries. */
+ tp->tx_full = 1;
+ flag = 0xe0000000; /* Tx-done intr. */
+ netif_stop_queue(dev);
}
if (entry == TX_RING_SIZE-1)
- flag |= 0xe2000000;
+ flag = 0xe0000000 | DESC_RING_WRAP;
- tp->tx_ring[entry].length = skb->len | flag;
- tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
+ tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag);
+ tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
tp->cur_tx++;
spin_unlock_irqrestore(&tp->tx_lock, cpuflags);
@@ -2112,26 +2133,22 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
-#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
struct net_device *dev = (struct net_device *)dev_instance;
-#else
- struct net_device *dev = (struct net_device *)(irq2dev_map[irq]);
-#endif
-
- struct tulip_private *tp;
- long ioaddr;
- int csr5, work_budget = max_interrupt_work;
-
- if (dev == NULL) {
- printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
- irq);
- return;
- }
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr5;
+ int entry;
+ int missed;
+ int rx = 0;
+ int tx = 0;
+ int oi = 0;
+ int maxrx = RX_RING_SIZE;
+ int maxtx = TX_RING_SIZE;
+ int maxoi = TX_RING_SIZE;
- ioaddr = dev->base_addr;
- tp = (struct tulip_private *)dev->priv;
+ tp->nir++;
do {
csr5 = inl(ioaddr + CSR5);
@@ -2145,25 +2162,27 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
break;
- if (csr5 & (RxIntr | RxNoBuf))
- work_budget -= tulip_rx(dev);
-
- spin_lock(&tp->tx_lock);
+ if (csr5 & (RxIntr | RxNoBuf)) {
+ rx += tulip_rx(dev);
+ tulip_refill_rx(dev);
+ }
- if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+ if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
unsigned int dirty_tx;
+ spin_lock(&tp->tx_lock);
+
for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
dirty_tx++) {
int entry = dirty_tx % TX_RING_SIZE;
- int status = tp->tx_ring[entry].status;
+ int status = le32_to_cpu(tp->tx_ring[entry].status);
if (status < 0)
- break; /* It still hasn't been Txed */
+ break; /* It still has not been Txed */
/* Check for Rx filter setup frames. */
if (tp->tx_skbuff[entry] == NULL)
continue;
-
+
if (status & 0x8000) {
/* There was an major error, log it. */
#ifndef final_version
@@ -2185,7 +2204,7 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
#ifdef ETHER_STATS
if (status & 0x0001) tp->stats.tx_deferred++;
#endif
- tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+ tp->stats.tx_bytes += tp->tx_skbuff[entry]->len;
tp->stats.collisions += (status >> 3) & 15;
tp->stats.tx_packets++;
}
@@ -2193,6 +2212,7 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
/* Free the original skb. */
dev_kfree_skb_irq(tp->tx_skbuff[entry]);
tp->tx_skbuff[entry] = 0;
+ tx++;
}
#ifndef final_version
@@ -2210,20 +2230,21 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
}
tp->dirty_tx = dirty_tx;
-
if (csr5 & TxDied) {
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: The transmitter stopped!"
- " CSR5 is %x, CSR6 %x.\n",
- dev->name, csr5, inl(ioaddr + CSR6));
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ if (tulip_debug > 2)
+ printk(KERN_WARNING "%s: The transmitter stopped."
+ " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
+ dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
}
+ spin_unlock(&tp->tx_lock);
}
- spin_unlock(&tp->tx_lock);
/* Log errors. */
if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
+ if (csr5 == 0xffffffff)
+ break;
if (csr5 & TxJabber) tp->stats.tx_errors++;
if (csr5 & TxFIFOUnderflow) {
if ((tp->csr6 & 0xC000) != 0xC000)
@@ -2231,119 +2252,179 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
else
tp->csr6 |= 0x00200000; /* Store-n-forward. */
/* Restart the transmit process. */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ outl_CSR6(tp, tp->csr6 | 0x0002);
+ outl_CSR6(tp, tp->csr6 | 0x2002);
+ outl(0, ioaddr + CSR1);
}
if (csr5 & RxDied) { /* Missed a Rx frame. */
tp->stats.rx_errors++;
tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+ outl_CSR6(tp, tp->csr6 | 0x2002);
}
- if (csr5 & TimerInt) {
- printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
- dev->name, csr5);
- /* Hmmmmm, it's not clear what to do here. */
+ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
+ if (tp->link_change)
+ (tp->link_change)(dev, csr5);
}
- if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
- && tp->chip_id == DC21142) {
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
- dev->name, csr5);
- t21142_lnk_change(dev);
+ if (csr5 & SytemError) {
+ printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
}
/* Clear all error sources, included undocumented ones! */
outl(0x0800f7ba, ioaddr + CSR5);
+ oi++;
}
- if (--work_budget < 0) {
+ if (csr5 & TimerInt) {
+#if 0
+ if (tulip_debug > 2)
+ printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+ dev->name, csr5);
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+#endif
+ tp->ttimer = 0;
+ oi++;
+ }
+ if (tx > maxtx || rx > maxrx || oi > maxoi) {
if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Too much work at interrupt, "
- "csr5=0x%8.8x.\n", dev->name, csr5);
+ printk(KERN_WARNING "%s: Too much work during an interrupt, "
+ "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
/* Acknowledge all interrupt sources. */
- outl(0x8001ffff, ioaddr + CSR5);
-#ifdef notdef
- /* Clear all but standard interrupt sources. */
- outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#if 0
+ /* Clear all interrupting sources, set timer to re-enable. */
+ outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
+ ioaddr + CSR7);
+ outl(12, ioaddr + CSR11);
+ tp->ttimer = 1;
#endif
break;
}
} while (1);
- if (tulip_debug > 3)
+ tulip_refill_rx(dev);
+
+ /* check if we card is in suspend mode */
+ entry = tp->dirty_rx % RX_RING_SIZE;
+ if (tp->rx_skbuff[entry] == NULL) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
+ if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+ outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
+ ioaddr + CSR7);
+ outl(TimerInt, ioaddr + CSR5);
+ outl(12, ioaddr + CSR11);
+ tp->ttimer = 1;
+ }
+ }
+
+ if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
+ tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+ }
+
+ if (tulip_debug > 4)
printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
dev->name, inl(ioaddr + CSR5));
- return;
}
-static int
-tulip_rx(struct net_device *dev)
+static int tulip_refill_rx(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry;
+ int refilled = 0;
+
+ /* Refill the Rx ring buffers. */
+ for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+ entry = tp->dirty_rx % RX_RING_SIZE;
+ if (tp->rx_skbuff[entry] == NULL) {
+ struct sk_buff *skb;
+ skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail);
+ refilled++;
+ }
+ tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
+ }
+ return refilled;
+}
+
+static int tulip_rx(struct net_device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int entry = tp->cur_rx % RX_RING_SIZE;
int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
- int work_done = 0;
+ int received = 0;
if (tulip_debug > 4)
printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
tp->rx_ring[entry].status);
- /* If we own the next entry, it's a new packet. Send it up. */
- while (tp->rx_ring[entry].status >= 0) {
- s32 status = tp->rx_ring[entry].status;
+ /* If we own the next entry, it is a new packet. Send it up. */
+ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
+ s32 status = le32_to_cpu(tp->rx_ring[entry].status);
+ if (tulip_debug > 5)
+ printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
+ dev->name, entry, status);
if (--rx_work_limit < 0)
break;
- if ((status & 0x0300) != 0x0300) {
- if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
- "multiple buffers, status %8.8x!\n",
+ if ((status & 0x38008300) != 0x0300) {
+ if ((status & 0x38000300) != 0x0300) {
+ /* Ingore earlier buffers. */
+ if ((status & 0xffff) != 0x7fff) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Oversized Ethernet frame "
+ "spanned multiple buffers, status %8.8x!\n",
+ dev->name, status);
+ tp->stats.rx_length_errors++;
+ }
+ } else if (status & RxDescFatalErr) {
+ /* There was a fatal error. */
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
dev->name, status);
- tp->stats.rx_length_errors++;
+ tp->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x0890) tp->stats.rx_length_errors++;
+ if (status & 0x0004) tp->stats.rx_frame_errors++;
+ if (status & 0x0002) tp->stats.rx_crc_errors++;
+ if (status & 0x0001) tp->stats.rx_fifo_errors++;
}
- } else if (status & 0x8000) {
- /* There was a fatal error. */
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
- dev->name, status);
- tp->stats.rx_errors++; /* end of a packet.*/
- if (status & 0x0890) tp->stats.rx_length_errors++;
- if (status & 0x0004) tp->stats.rx_frame_errors++;
- if (status & 0x0002) tp->stats.rx_crc_errors++;
- if (status & 0x0001) tp->stats.rx_fifo_errors++;
} else {
/* Omit the four octet CRC from the length. */
- short pkt_len = (status >> 16) - 4;
+ short pkt_len = ((status >> 16) & 0x7ff) - 4;
struct sk_buff *skb;
- /* Check if the packet is long enough to just accept without
- copying to a properly sized skbuff. */
+#ifndef final_version
+ if (pkt_len > 1518) {
+ printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
+ dev->name, pkt_len, pkt_len);
+ pkt_len = 1518;
+ tp->stats.rx_length_errors++;
+ }
+#endif
+ /* Check if the packet is long enough to accept without copying
+ to a minimally-sized skbuff. */
if (pkt_len < rx_copybreak
- && (skb = DEV_ALLOC_SKB(pkt_len+2)) != NULL) {
+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the IP header */
-#if LINUX_VERSION_CODE < 0x20200 || defined(__alpha__)
- memcpy(skb_put(skb, pkt_len),
- bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
-#else
- eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
- pkt_len, 0);
+#if ! defined(__alpha__)
+ eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0);
skb_put(skb, pkt_len);
+#else
+ memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail,
+ pkt_len);
#endif
- work_done++;
} else { /* Pass up the skb already on the Rx ring. */
- skb = tp->rx_skbuff[entry];
+ char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
tp->rx_skbuff[entry] = NULL;
#ifndef final_version
- {
- void *temp = skb_put(skb, pkt_len);
- if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
- printk(KERN_ERR "%s: Internal consistency error! The "
- "skbuff addresses do not match in tulip_rx:"
- " %p vs. %p / %p.\n", dev->name,
- bus_to_virt(tp->rx_ring[entry].buffer1),
- skb->head, temp);
- }
-#else
- skb_put(skb, pkt_len);
+ if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp)
+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+ "do not match in tulip_rx: %p vs. %p / %p.\n",
+ dev->name,
+ le32desc_to_virt(tp->rx_ring[entry].buffer1),
+ skb->head, temp);
#endif
}
skb->protocol = eth_type_trans(skb, dev);
@@ -2352,95 +2433,92 @@ tulip_rx(struct net_device *dev)
tp->stats.rx_packets++;
tp->stats.rx_bytes += pkt_len;
}
+ received++;
entry = (++tp->cur_rx) % RX_RING_SIZE;
}
- /* Refill the Rx ring buffers. */
- for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
- entry = tp->dirty_rx % RX_RING_SIZE;
- if (tp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb;
- skb = tp->rx_skbuff[entry] = DEV_ALLOC_SKB(PKT_BUF_SZ);
- if (skb == NULL)
- break;
- skb->dev = dev; /* Mark as being used by this device. */
- tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
- work_done++;
- }
- tp->rx_ring[entry].status = 0x80000000;
- }
-
- return work_done;
+ return received;
}
-static int
-tulip_close(struct net_device *dev)
+
+static void tulip_down (struct net_device *dev)
{
long ioaddr = dev->base_addr;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
+ struct tulip_private *tp = (struct tulip_private *) dev->priv;
- netif_stop_queue(dev);
+ netif_device_detach (dev);
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, inl(ioaddr + CSR5));
+ del_timer (&tp->timer);
/* Disable interrupts by clearing the interrupt mask. */
- outl(0x00000000, ioaddr + CSR7);
- /* Stop the chip's Tx and Rx processes. */
- outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+ outl (0x00000000, ioaddr + CSR7);
+
+ /* Stop the Tx and Rx processes. */
+ outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002);
+
/* 21040 -- Leave the card in 10baseT state. */
if (tp->chip_id == DC21040)
- outl(0x00000004, ioaddr + CSR13);
+ outl (0x00000004, ioaddr + CSR13);
- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+ if (inl (ioaddr + CSR6) != 0xffffffff)
+ tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff;
- del_timer(&tp->timer);
+ dev->if_port = tp->saved_if_port;
-#ifdef SA_SHIRQ
- free_irq(dev->irq, dev);
-#else
- free_irq(dev->irq);
- irq2dev_map[dev->irq] = 0;
-#endif
+ /* Leave the driver in snooze, not sleep, mode. */
+ if (tp->flags & HAS_ACPI)
+ pci_write_config_dword (tp->pdev, 0x40, 0x40000000);
+}
+
+
+static int tulip_close (struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *) dev->priv;
+ int i;
+
+ tulip_down (dev);
+
+ if (tulip_debug > 1)
+ printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, inl (ioaddr + CSR5));
+
+ free_irq (dev->irq, dev);
/* Free all the skbuffs in the Rx queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb = tp->rx_skbuff[i];
tp->rx_skbuff[i] = 0;
- tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */
+ tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */
tp->rx_ring[i].length = 0;
- tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+ tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
if (skb) {
- dev_kfree_skb(skb);
+ dev_kfree_skb (skb);
}
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (tp->tx_skbuff[i])
- dev_kfree_skb(tp->tx_skbuff[i]);
+ dev_kfree_skb (tp->tx_skbuff[i]);
tp->tx_skbuff[i] = 0;
}
-
MOD_DEC_USE_COUNT;
return 0;
}
-static struct enet_statistics *
-tulip_get_stats(struct net_device *dev)
+static struct enet_statistics *tulip_get_stats(struct net_device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (test_bit(LINK_STATE_START, &dev->state))
+ if (netif_running(dev))
tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
return &tp->stats;
}
-#ifdef HAVE_PRIVATE_IOCTL
+
/* Provide ioctl() calls to examine the MII xcvr state. */
static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
@@ -2452,31 +2530,32 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch(cmd) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
- if (tp->mtable && tp->mtable->has_mii)
+ if (tp->mii_cnt)
data[0] = phy;
- else if (tp->chip_id == DC21142)
+ else if (tp->flags & HAS_NWAY143)
data[0] = 32;
+ else if (tp->chip_id == COMET)
+ data[0] = 1;
else
return -ENODEV;
- return 0;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- if (data[0] == 32) { /* 21142 pseudo-MII */
+ if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
int csr12 = inl(ioaddr + CSR12);
int csr14 = inl(ioaddr + CSR14);
switch (data[1]) {
case 0: {
- data[3] = ((csr14<<13)&0x4000) + ((csr14<<5)&0x1000);
+ data[3] = (csr14<<5) & 0x1000;
break; }
case 1:
data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+ (csr12&0x06 ? 0x04 : 0);
break;
case 4: {
- int csr14 = inl(ioaddr + CSR14);
- data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+ data[3] = ((csr14>>9)&0x07C0) +
+ ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;
break;
}
- case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+ case 5: data[3] = csr12 >> 16; break;
default: data[3] = 0; break;
}
} else {
@@ -2487,9 +2566,11 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (data[0] == 32) { /* 21142 pseudo-MII */
+ if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
+ if (data[1] == 5)
+ tp->to_advertise = data[2];
} else {
save_flags(flags);
cli();
@@ -2503,7 +2584,7 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EOPNOTSUPP;
}
-#endif /* HAVE_PRIVATE_IOCTL */
+
/* Set or clear the multicast filter for this adaptor.
Note that we only use exclusion around actually queueing the
@@ -2514,9 +2595,9 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
N.B. Do not use for bulk data, use a table-based routine instead.
This is common code and should be moved to net/core/crc.c */
static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
+static inline u32 ether_crc_le(int length, unsigned char *data)
{
- unsigned int crc = 0xffffffff; /* Initial value. */
+ u32 crc = 0xffffffff; /* Initial value. */
while(--length >= 0) {
unsigned char current_octet = *data++;
int bit;
@@ -2530,223 +2611,549 @@ static inline unsigned ether_crc_le(int length, unsigned char *data)
}
return crc;
}
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+ int crc = -1;
+
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^
+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+ }
+ return crc;
+}
-#ifdef NEW_MULTICAST
static void set_rx_mode(struct net_device *dev)
-#else
-static void set_rx_mode(struct net_device *dev, int num_addrs, void *addrs)
-#endif
{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
unsigned long cpuflags;
tp->csr6 &= ~0x00D5;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- outl(csr6 | 0x00C0, ioaddr + CSR6);
+ tp->csr6 |= 0x00C0;
+ csr6 |= 0x00C0;
/* Unconditionally log net taps. */
printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
- tp->csr6 |= 0xC0;
} else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter perfectly -- accept all multicasts. */
- outl(csr6 | 0x0080, ioaddr + CSR6);
- tp->csr6 |= 0x80;
+ /* Too many to filter well -- accept all multicasts. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else if (tp->flags & MC_HASH_ONLY) {
+ /* Some work-alikes have only a 64-entry hash filter table. */
+ /* Should verify correctness on big-endian/__powerpc__ */
+ struct dev_mc_list *mclist;
+ int i;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else {
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
+ if (tp->chip_id == AX88140) {
+ outl(2, ioaddr + CSR13);
+ outl(mc_filter[0], ioaddr + CSR14);
+ outl(3, ioaddr + CSR13);
+ outl(mc_filter[1], ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
+ outl(mc_filter[0], ioaddr + 0xAC);
+ outl(mc_filter[1], ioaddr + 0xB0);
+ }
+ }
} else {
- u32 *setup_frm = tp->setup_frame;
+ u16 *eaddrs, *setup_frm = tp->setup_frame;
struct dev_mc_list *mclist;
- u16 *eaddrs;
- u32 tx_flags;
+ u32 tx_flags = 0x08000000 | 192;
int i;
+ /* Note that only the low-address shortword of setup_frame is valid!
+ The values are doubled for big-endian architectures. */
if (dev->mc_count > 14) { /* Must use a multicast hash table. */
- u16 hash_table[32];
- memset(hash_table, 0, sizeof(hash_table));
- /* This should work on big-endian machines as well. */
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next)
- set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
- hash_table);
- /* Copy the hash table to the setup frame.
- NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */
- for (i = 0; i < 32; i++)
- *setup_frm++ = hash_table[i];
- setup_frm += 7;
- tx_flags = 0x08400000 | 192;
- /* Too clever: i > 15 for fall-though. */
+ u16 hash_table[32];
+ tx_flags = 0x08400000 | 192; /* Use hash filter. */
+ memset(hash_table, 0, sizeof(hash_table));
+ set_bit(255, hash_table); /* Broadcast entry */
+ /* This should work on big-endian machines as well. */
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+ hash_table);
+ for (i = 0; i < 32; i++)
+ *setup_frm++ = *setup_frm++ = hash_table[i];
+ setup_frm = &tp->setup_frame[13*6];
} else {
- /* We have <= 15 addresses so we can use the wonderful
- 16 address perfect filtering of the Tulip. */
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
- /* Note that only the low shortword of setup_frame[] is valid!
- This code may require tweaking for non-x86 architectures! */
- eaddrs = (u16 *)mclist->dmi_addr;
- *setup_frm++ = *eaddrs++;
- *setup_frm++ = *eaddrs++;
- *setup_frm++ = *eaddrs++;
- }
- /* Fill the rest of the table with our physical address.
- Once again, only the low shortword or setup_frame[] is valid! */
- *setup_frm++ = 0xffff;
- *setup_frm++ = 0xffff;
- *setup_frm++ = 0xffff;
- tx_flags = 0x08000000 | 192;
+ /* We have <= 14 addresses so we can use the wonderful
+ 16 address perfect filtering of the Tulip. */
+ for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *setup_frm++ = *eaddrs++;
+ }
+ /* Fill the unused entries with the broadcast address. */
+ memset(setup_frm, 0xff, (15-i)*12);
+ setup_frm = &tp->setup_frame[15*6];
}
+ /* Fill the final entry with our physical address. */
eaddrs = (u16 *)dev->dev_addr;
- do {
- *setup_frm++ = eaddrs[0];
- *setup_frm++ = eaddrs[1];
- *setup_frm++ = eaddrs[2];
- } while (++i < 15);
+ *setup_frm++ = *setup_frm++ = eaddrs[0];
+ *setup_frm++ = *setup_frm++ = eaddrs[1];
+ *setup_frm++ = *setup_frm++ = eaddrs[2];
/* Now add this frame to the Tx list. */
spin_lock_irqsave(&tp->tx_lock, cpuflags);
if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
/* Same setup recently queued, we need not add it. */
} else {
- unsigned int entry, dummy = 0;
+ unsigned long flags;
+ unsigned int entry;
+ save_flags(flags); cli();
entry = tp->cur_tx++ % TX_RING_SIZE;
if (entry != 0) {
/* Avoid a chip errata by prefixing a dummy entry. */
tp->tx_skbuff[entry] = 0;
tp->tx_ring[entry].length =
- (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+ (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
tp->tx_ring[entry].buffer1 = 0;
- /* race with chip, set DescOwned later */
- dummy = entry;
+ tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
entry = tp->cur_tx++ % TX_RING_SIZE;
}
tp->tx_skbuff[entry] = 0;
/* Put the setup frame on the Tx list. */
if (entry == TX_RING_SIZE-1)
- tx_flags |= 0x02000000; /* Wrap ring. */
- tp->tx_ring[entry].length = tx_flags;
- tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
- tp->tx_ring[entry].status = 0x80000000;
+ tx_flags |= DESC_RING_WRAP; /* Wrap ring. */
+ tp->tx_ring[entry].length = cpu_to_le32(tx_flags);
+ tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame);
+ tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
netif_stop_queue(dev);
tp->tx_full = 1;
}
- if (dummy >= 0)
- tp->tx_ring[dummy].status = DescOwned;
spin_unlock_irqrestore(&tp->tx_lock, cpuflags);
/* Trigger an immediate transmit demand. */
outl(0, ioaddr + CSR1);
}
- outl(csr6 | 0x0000, ioaddr + CSR6);
}
+ outl_CSR6(tp, csr6 | 0x0000);
}
-
-#ifdef CARDBUS
-#include <pcmcia/driver_ops.h>
-static dev_node_t *tulip_attach(dev_locator_t *loc)
+static int __devinit tulip_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- u16 dev_id;
- u32 io;
- u8 bus, devfn;
+ static int did_version = 0; /* Already printed version info. */
+ struct tulip_private *tp;
+ /* See note below on the multiport cards. */
+ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+ static int last_irq = 0;
+ static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
+ u8 chip_rev;
+ int i, irq;
+ unsigned short sum;
+ u8 ee_data[EEPROM_SIZE];
struct net_device *dev;
- struct pci_dev *pdev;
+ long ioaddr;
+ static int board_idx = -1;
+ int chip_idx = ent->driver_data;
+
+ board_idx++;
- if (loc->bus != LOC_PCI) return NULL;
- pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
- if (!pdev) return NULL;
- printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
- io = pdev->resource[0].start;
- dev_id = pdev->device;
- io &= ~3;
- dev = tulip_probe1(bus, devfn, DC21142, -1);
- if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
- node->major = node->minor = 0;
- node->next = NULL;
- MOD_INC_USE_COUNT;
- return node;
+ if (tulip_debug > 0 && did_version++ == 0)
+ printk (KERN_INFO "%s", version);
+
+ if( pdev->subsystem_vendor == 0x1376 ){
+ printk (KERN_ERR PFX "skipping LMC card.\n");
+ return -ENODEV;
}
- return NULL;
-}
+
+ ioaddr = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
-static void tulip_detach(dev_node_t *node)
-{
- struct net_device **devp, **next;
- printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
- for (devp = &root_tulip_dev; *devp; devp = next) {
- next = &((struct tulip_private *)(*devp)->priv)->next_module;
- if (strcmp((*devp)->name, node->dev_name) == 0) break;
+ /* Make certain the data structures are quadword aligned. */
+ dev = init_etherdev (NULL, sizeof (*tp));
+ if (!dev) {
+ printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
+ return -ENOMEM;
}
- if (*devp) {
- unregister_netdev(*devp);
- kfree(*devp);
- *devp = *next;
- kfree(node);
- MOD_DEC_USE_COUNT;
+
+ /* We do a request_region() only to register /proc/ioports info. */
+ /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
+ if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) {
+ printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
+ goto err_out_free_netdev;
}
-}
-struct driver_operations tulip_ops = {
- "tulip_cb", tulip_attach, NULL, NULL, tulip_detach
-};
+ if (pci_enable_device(pdev)) {
+ printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n",
+ pdev->vendor, pdev->device,
+ pdev->bus->number, pdev->devfn);
+ goto err_out_free_netdev;
+ }
-#endif /* Cardbus support */
+ pci_set_master(pdev);
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(reverse_probe, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+ tp = dev->priv;
+ memset(tp, 0, sizeof(*tp));
-/* An additional parameter that may be passed in... */
-static int debug = -1;
+ pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
-static int __init tulip_init_module (void)
-{
- if (debug >= 0)
- tulip_debug = debug;
+ printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+ dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
-#ifdef CARDBUS
- register_driver(&tulip_ops);
- return 0;
-#else
- return tulip_probe();
+ /* Stop the chip's Tx and Rx processes. */
+ outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002);
+ /* Clear the missed-packet counter. */
+ (volatile int)inl(ioaddr + CSR8);
+
+ if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) {
+ printk(" 21040 compatible mode,");
+ chip_idx = DC21040;
+ }
+
+ /* The station address ROM is read byte serially. The register must
+ be polled, waiting for the value to be read bit serially from the
+ EEPROM.
+ */
+ sum = 0;
+ if (chip_idx == DC21040) {
+ outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
+ for (i = 0; i < 6; i++) {
+ int value, boguscnt = 100000;
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ dev->dev_addr[i] = value;
+ sum += value & 0xff;
+ }
+ } else if (chip_idx == LC82C168) {
+ for (i = 0; i < 3; i++) {
+ int value, boguscnt = 100000;
+ outl(0x600 | i, ioaddr + 0x98);
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+ sum += value & 0xffff;
+ }
+ } else if (chip_idx == COMET) {
+ /* No need to read the EEPROM. */
+ put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
+ put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+ for (i = 0; i < 6; i ++)
+ sum += dev->dev_addr[i];
+ } else {
+ /* A serial EEPROM interface, we read now and sort it out later. */
+ int sa_offset = 0;
+ int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+
+ for (i = 0; i < sizeof(ee_data)/2; i++)
+ ((u16 *)ee_data)[i] =
+ le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size));
+
+ /* DEC now has a specification (see Notes) but early board makers
+ just put the address in the first EEPROM locations. */
+ /* This does memcmp(eedata, eedata+16, 8) */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ sa_offset = 20;
+ if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
+ sa_offset = 2; /* Grrr, damn Matrox boards. */
+ multiport_cnt = 4;
+ }
+ for (i = 0; i < 6; i ++) {
+ dev->dev_addr[i] = ee_data[i + sa_offset];
+ sum += ee_data[i + sa_offset];
+ }
+ }
+ /* Lite-On boards have the address byte-swapped. */
+ if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0)
+ && dev->dev_addr[1] == 0x00)
+ for (i = 0; i < 6; i+=2) {
+ char tmp = dev->dev_addr[i];
+ dev->dev_addr[i] = dev->dev_addr[i+1];
+ dev->dev_addr[i+1] = tmp;
+ }
+ /* On the Zynx 315 Etherarray and other multiport boards only the
+ first Tulip has an EEPROM.
+ The addresses of the subsequent ports are derived from the first.
+ Many PCI BIOSes also incorrectly report the IRQ line, so we correct
+ that here as well. */
+ if (sum == 0 || sum == 6*0xff) {
+ printk(" EEPROM not present,");
+ for (i = 0; i < 5; i++)
+ dev->dev_addr[i] = last_phys_addr[i];
+ dev->dev_addr[i] = last_phys_addr[i] + 1;
+#if defined(__i386__) /* Patch up x86 BIOS bug. */
+ if (last_irq)
+ irq = last_irq;
+#endif
+ }
+
+ for (i = 0; i < 6; i++)
+ printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
+ printk(", IRQ %d.\n", irq);
+ last_irq = irq;
+
+ pdev->driver_data = dev;
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ tp->chip_id = chip_idx;
+ tp->revision = chip_rev;
+ tp->flags = tulip_tbl[chip_idx].flags;
+ tp->csr0 = csr0;
+ tp->pdev = pdev;
+ tp->base_addr = dev->base_addr;
+
+ /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
+ And the ASIX must have a burst limit or horrible things happen. */
+ if (chip_idx == DC21143 && chip_rev == 65)
+ tp->csr0 &= ~0x01000000;
+ else if (chip_idx == AX88140)
+ tp->csr0 |= 0x2000;
+
+#ifdef TULIP_FULL_DUPLEX
+ tp->full_duplex = 1;
+ tp->full_duplex_lock = 1;
+#endif
+#ifdef TULIP_DEFAULT_MEDIA
+ tp->default_port = TULIP_DEFAULT_MEDIA;
+#endif
+#ifdef TULIP_NO_MEDIA_SWITCH
+ tp->medialock = 1;
#endif
+ tp->tx_lock = SPIN_LOCK_UNLOCKED;
+
+ /* The lower four bits are the media type. */
+ if (board_idx >= 0 && board_idx < MAX_UNITS) {
+ tp->default_port = options[board_idx] & 15;
+ if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+ tp->full_duplex = 1;
+ if (mtu[board_idx] > 0)
+ dev->mtu = mtu[board_idx];
+ }
+ if (dev->mem_start)
+ tp->default_port = dev->mem_start;
+ if (tp->default_port) {
+ tp->medialock = 1;
+ if (media_cap[tp->default_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ }
+ if (tp->full_duplex)
+ tp->full_duplex_lock = 1;
+
+ if (media_cap[tp->default_port] & MediaIsMII) {
+ u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+ tp->to_advertise = media2advert[tp->default_port - 9];
+ } else if (tp->flags & HAS_8023X)
+ tp->to_advertise = 0x05e1;
+ else
+ tp->to_advertise = 0x01e1;
+
+ /* This is logically part of probe1(), but too complex to write inline. */
+ if (tp->flags & HAS_MEDIA_TABLE) {
+ memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+ parse_eeprom(dev);
+ }
+
+ if ((tp->flags & ALWAYS_CHECK_MII) ||
+ (tp->mtable && tp->mtable->has_mii) ||
+ ( ! tp->mtable && (tp->flags & HAS_MII))) {
+ int phy, phy_idx;
+ if (tp->mtable && tp->mtable->has_mii) {
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == 11) {
+ tp->cur_index = i;
+ tp->saved_if_port = dev->if_port;
+ select_media(dev, 1);
+ dev->if_port = tp->saved_if_port;
+ break;
+ }
+ }
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later,
+ but takes much time. */
+ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+ phy++) {
+ int mii_status = mdio_read(dev, phy, 1);
+ if ((mii_status & 0x8301) == 0x8001 ||
+ ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) {
+ int mii_reg0 = mdio_read(dev, phy, 0);
+ int mii_advert = mdio_read(dev, phy, 4);
+ int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+ tp->phys[phy_idx] = phy;
+ tp->advertising[phy_idx++] = reg4;
+ printk(KERN_INFO "%s: MII transceiver #%d "
+ "config %4.4x status %4.4x advertising %4.4x.\n",
+ dev->name, phy, mii_reg0, mii_status, mii_advert);
+ /* Fixup for DLink with miswired PHY. */
+ if (mii_advert != reg4) {
+ printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
+ " previously advertising %4.4x.\n",
+ dev->name, reg4, phy, mii_advert);
+ printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise"
+ " is %4.4x).\n",
+ dev->name, reg4, tp->to_advertise);
+ mdio_write(dev, phy, 4, reg4);
+ }
+ /* Enable autonegotiation: some boards default to off. */
+ mdio_write(dev, phy, 0, mii_reg0 |
+ (tp->full_duplex ? 0x1100 : 0x1000) |
+ (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
+ }
+ }
+ tp->mii_cnt = phy_idx;
+ if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
+ printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+ dev->name);
+ tp->phys[0] = 1;
+ }
+ }
+
+ /* The Tulip-specific entries in the device structure. */
+ dev->open = tulip_open;
+ dev->hard_start_xmit = tulip_start_xmit;
+ dev->tx_timeout = tulip_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->stop = tulip_close;
+ dev->get_stats = tulip_get_stats;
+ dev->do_ioctl = private_ioctl;
+ dev->set_multicast_list = set_rx_mode;
+
+ if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041)
+ tp->link_change = t21142_lnk_change;
+ else if (tp->flags & HAS_PNICNWAY)
+ tp->link_change = pnic_lnk_change;
+
+ /* Reset the xcvr interface and turn on heartbeat. */
+ switch (chip_idx) {
+ case DC21041:
+ tp->to_advertise = 0x0061;
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+ outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200);
+ outl(0x0000EF05, ioaddr + CSR13);
+ break;
+ case DC21040:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0x00000004, ioaddr + CSR13);
+ break;
+ case DC21140: default:
+ if (tp->mtable)
+ outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+ break;
+ case DC21142:
+ case PNIC2:
+ if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) {
+ outl_CSR6(tp, 0x82020000);
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ outl_CSR6(tp, 0x820E0000);
+ } else
+ t21142_start_nway(dev);
+ break;
+ case LC82C168:
+ if ( ! tp->mii_cnt) {
+ tp->nway = 1;
+ tp->nwayset = 0;
+ outl_CSR6(tp, 0x00420000);
+ outl(0x30, ioaddr + CSR12);
+ outl_CSR6(tp, 0x0001F078);
+ outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */
+ }
+ break;
+ case MX98713: case COMPEX9881:
+ outl_CSR6(tp, 0x00000000);
+ outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+ outl(0x00000001, ioaddr + CSR13);
+ break;
+ case MX98715: case MX98725:
+ outl_CSR6(tp, 0x01a80000);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00001000, ioaddr + CSR12);
+ break;
+ case COMET:
+ /* No initialization necessary. */
+ break;
+ }
+
+ /* put the chip in snooze mode until opened */
+ if (tulip_tbl[chip_idx].flags & HAS_ACPI)
+ pci_write_config_dword(pdev, 0x40, 0x40000000);
+
+ return 0;
+
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+ return -ENODEV;
}
-static void __exit tulip_cleanup_module (void)
+
+static void tulip_suspend (struct pci_dev *pdev)
{
- struct net_device *next_dev;
+ struct net_device *dev = pdev->driver_data;
-#ifdef CARDBUS
- unregister_driver(&tulip_ops);
-#endif
+ if (dev && netif_device_present (dev))
+ tulip_down (dev);
+}
+
+
+static void tulip_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_tulip_dev) {
- next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
- unregister_netdev(root_tulip_dev);
- release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE);
- kfree(root_tulip_dev);
- root_tulip_dev = next_dev;
+ if (dev && !netif_device_present (dev))
+ tulip_up (dev);
+}
+
+
+static void __devexit tulip_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+
+ if (dev) {
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ unregister_netdev(dev);
+ release_region(dev->base_addr,
+ tulip_tbl[tp->chip_id].io_size);
+ kfree(dev);
}
}
-module_init(tulip_init_module);
-module_exit(tulip_cleanup_module);
+
+static struct pci_driver tulip_driver = {
+ name: TULIP_MODULE_NAME,
+ id_table: tulip_pci_tbl,
+ probe: tulip_init_one,
+ remove: tulip_remove_one,
+ suspend: tulip_suspend,
+ resume: tulip_resume,
+};
-/*
- * Local variables:
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
+static int __init tulip_init (void)
+{
+ return pci_module_init (&tulip_driver);
+}
+
+
+static void __exit tulip_cleanup (void)
+{
+ pci_unregister_driver (&tulip_driver);
+}
+
+
+module_init(tulip_init);
+module_exit(tulip_cleanup);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 5d412d161..abfde3e8a 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -865,11 +865,11 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
np->stats.tx_packets++;
}
/* Free the original skb. */
- kfree_skb(np->tx_skbuff[entry]);
+ dev_kfree_skb_irq(np->tx_skbuff[entry]);
np->tx_skbuff[entry] = 0;
}
if (np->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->flags) &&
+ netif_queue_stopped(dev) &&
np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
/* The ring is no longer full, clear tbusy. */
np->tx_full = 0;
@@ -1147,13 +1147,13 @@ static int netdev_close(struct net_device *dev)
np->rx_ring[i].rx_length = 0;
np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
if (np->rx_skbuff[i]) {
- kfree_skb(np->rx_skbuff[i]);
+ dev_kfree_skb(np->rx_skbuff[i]);
}
np->rx_skbuff[i] = 0;
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (np->tx_skbuff[i])
- kfree_skb(np->tx_skbuff[i]);
+ dev_kfree_skb(np->tx_skbuff[i]);
np->tx_skbuff[i] = 0;
}
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 6883aa69f..873a561ef 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -84,6 +84,7 @@
#include <linux/malloc.h>
#include <linux/poll.h>
#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -359,6 +360,8 @@ static void debug_status_out(struct cosa_data *cosa, int status);
/* ---------- Initialization stuff ---------- */
+static devfs_handle_t devfs_handle = NULL;
+
#ifdef MODULE
int init_module(void)
#else
@@ -366,18 +369,19 @@ static int __init cosa_init(void)
#endif
{
int i;
+
printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
#ifdef __SMP__
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
#endif
if (cosa_major > 0) {
- if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {
+ if (devfs_register_chrdev(cosa_major, "cosa", &cosa_fops)) {
printk(KERN_WARNING "cosa: unable to get major %d\n",
cosa_major);
return -EIO;
}
} else {
- if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) {
+ if (!(cosa_major=devfs_register_chrdev(0, "cosa", &cosa_fops))) {
printk(KERN_WARNING "cosa: unable to register chardev\n");
return -EIO;
}
@@ -386,9 +390,14 @@ static int __init cosa_init(void)
cosa_cards[i].num = -1;
for (i=0; io[i] != 0 && i < MAX_CARDS; i++)
cosa_probe(io[i], irq[i], dma[i]);
+ devfs_handle = devfs_mk_dir (NULL, "cosa", 4, NULL);
+ devfs_register_series (devfs_handle, "%u", nr_cards, DEVFS_FL_DEFAULT,
+ cosa_major, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &cosa_fops, NULL);
if (!nr_cards) {
printk(KERN_WARNING "cosa: no devices found.\n");
- unregister_chrdev(cosa_major, "cosa");
+ devfs_unregister_chrdev(cosa_major, "cosa");
return -ENODEV;
}
return 0;
@@ -397,9 +406,11 @@ static int __init cosa_init(void)
#ifdef MODULE
void cleanup_module (void)
{
+ int i;
struct cosa_data *cosa;
printk(KERN_INFO "Unloading the cosa module\n");
+ devfs_unregister (devfs_handle);
for (cosa=cosa_cards; nr_cards--; cosa++) {
int i;
/* Clean up the per-channel data */
@@ -414,7 +425,7 @@ void cleanup_module (void)
free_dma(cosa->dma);
release_region(cosa->datareg,is_8bit(cosa)?2:4);
}
- unregister_chrdev(cosa_major, "cosa");
+ devfs_unregister_chrdev(cosa_major, "cosa");
}
#endif
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index e11c9bcfe..e56125734 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -93,6 +93,9 @@
/* This is an extension of the 'struct net_device' we create for each network
interface to keep the rest of X.25 channel-specific data. */
typedef struct x25_channel {
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
char *local_addr; /* local media address, ASCIIZ -
@@ -502,12 +505,10 @@ static int if_open (struct net_device *dev)
x25_channel_t *chan = dev->priv;
cycx_t *card = chan->card;
- if (dev->start)
+ if (netif_running(dev))
return -EBUSY; /* only one open is allowed */
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
+ netif_start_queue(dev);
cyclomx_mod_inc_use_count(card);
return 0;
@@ -521,8 +522,8 @@ static int if_close (struct net_device *dev)
x25_channel_t *chan = dev->priv;
cycx_t *card = chan->card;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
chan_disconnect(dev);
@@ -556,7 +557,7 @@ static int if_rebuild_hdr (struct sk_buff *skb)
}
/* Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission).
+ * o set busy flag (marks start of the transmission).
* o check link state. If link is not up, then drop the packet.
* o check channel status. If it's down then initiate a call.
* o pass a packet to corresponding WAN device.
@@ -575,11 +576,6 @@ static int if_send (struct sk_buff *skb, struct net_device *dev)
x25_channel_t *chan = dev->priv;
cycx_t *card = chan->card;
- if (dev->tbusy) {
- ++chan->ifstats.rx_dropped;
- return -EBUSY;
- }
-
if (!chan->svc)
chan->protocol = skb->protocol;
@@ -595,14 +591,14 @@ static int if_send (struct sk_buff *skb, struct net_device *dev)
switch (chan->state) {
case WAN_DISCONNECTED:
if (chan_connect(dev)) {
- dev->tbusy = 1;
+ netif_stop_queue(dev);
return -EBUSY;
}
/* fall thru */
case WAN_CONNECTED:
reset_timer(dev);
dev->trans_start = jiffies;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
if (chan_send(dev, skb))
return -EBUSY;
@@ -632,8 +628,8 @@ static int if_send (struct sk_buff *skb, struct net_device *dev)
skb_pull(skb, 1); /* Remove control byte */
reset_timer(dev);
dev->trans_start = jiffies;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
if (chan_send(dev, skb)) {
/* prepare for future retransmissions */
skb_push(skb, 1);
@@ -705,9 +701,6 @@ static void cyx_isr (cycx_t *card)
cycx_poke(&card->hw, 0, &z, sizeof(z));
cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));
card->in_isr = 0;
-
- if (card->buff_int_mode_unbusy)
- mark_bh(NET_BH);
}
/* Transmit interrupt handler.
@@ -724,7 +717,7 @@ static void tx_intr (cycx_t *card, TX25Cmd *cmd)
/* unbusy device and then dev_tint(); */
if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
card->buff_int_mode_unbusy = 1;
- dev->tbusy = 0;
+ netif_wake_queue(dev);
} else
printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n",
card->devname, lcn);
@@ -1263,11 +1256,13 @@ static int x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len, void *buf)
static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
{
struct net_device *dev = wandev->dev;
+ x25_channel_t *chan;
- for (; dev; dev = dev->slave)
- if (((x25_channel_t*)dev->priv)->lcn == lcn)
+ while (dev) {
+ if (chan->lcn == lcn)
break;
-
+ dev = chan->slave;
+ }
return dev;
}
@@ -1275,11 +1270,13 @@ static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
{
struct net_device *dev = wandev->dev;
+ x25_channel_t *chan;
- for (; dev; dev = dev->slave)
- if (!strcmp(((x25_channel_t*)dev->priv)->addr, dte))
+ while (dev) {
+ if (!strcmp(chan->addr, dte))
break;
-
+ dev = chan->slave;
+ }
return dev;
}
@@ -1357,7 +1354,7 @@ static void set_chan_state (struct net_device *dev, u8 state)
case WAN_CONNECTED:
string_state = "connected!";
*(u16*)dev->dev_addr = htons(chan->lcn);
- dev->tbusy = 0;
+ netif_wake_queue(dev);
reset_timer(dev);
if (chan->protocol == ETH_P_X25)
@@ -1384,7 +1381,7 @@ static void set_chan_state (struct net_device *dev, u8 state)
if (chan->protocol == ETH_P_X25)
chan_x25_send_event(dev, 2);
- dev->tbusy = 0;
+ netif_wake_queue(dev);
break;
}
@@ -1560,15 +1557,16 @@ static void x25_dump_devs(wan_device_t *wandev)
struct net_device *dev = wandev->dev;
printk(KERN_INFO "X.25 dev states\n");
- printk(KERN_INFO "name: addr: tbusy: protocol:\n");
+ printk(KERN_INFO "name: addr: txoff: protocol:\n");
printk(KERN_INFO "---------------------------------------\n");
- for (; dev; dev = dev->slave) {
+ while(dev) {
x25_channel_t *chan = dev->priv;
- printk(KERN_INFO "%-5.5s %-15.15s %ld ETH_P_%s\n",
- chan->name, chan->addr, dev->tbusy,
+ printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n",
+ chan->name, chan->addr, netif_queue_stopped(dev),
chan->protocol == ETH_P_IP ? "IP" : "X25");
+ dev = chan->slave;
}
}
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index a8c52f0d6..362e7a36e 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -244,43 +244,34 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
if (!skb || !dev)
return(0);
- if (dev->tbusy)
- return(1);
-
dlp = dev->priv;
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
- else
+ netif_stop_queue(dev);
+
+ ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
+ switch (ret)
{
- ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
- switch (ret)
- {
- case DLCI_RET_OK:
- dlp->stats.tx_packets++;
- ret = 0;
- break;
-
+ case DLCI_RET_OK:
+ dlp->stats.tx_packets++;
+ ret = 0;
+ break;
case DLCI_RET_ERR:
- dlp->stats.tx_errors++;
- ret = 0;
- break;
-
+ dlp->stats.tx_errors++;
+ ret = 0;
+ break;
case DLCI_RET_DROP:
- dlp->stats.tx_dropped++;
- ret = 1;
- break;
- }
-
- /* Alan Cox recommends always returning 0, and always freeing the packet */
- /* experience suggest a slightly more conservative approach */
-
- if (!ret)
- dev_kfree_skb(skb);
-
- dev->tbusy = 0;
+ dlp->stats.tx_dropped++;
+ ret = 1;
+ break;
}
+ /* Alan Cox recommends always returning 0, and always freeing the packet */
+ /* experience suggest a slightly more conservative approach */
+ if (!ret)
+ {
+ dev_kfree_skb(skb);
+ netif_wake_queue(dev);
+ }
return(ret);
}
@@ -370,19 +361,16 @@ static int dlci_open(struct net_device *dev)
if (!*(short *)(dev->dev_addr))
return(-EINVAL);
- if (!dlp->slave->start)
+ if (!netif_running(dlp->slave))
return(-ENOTCONN);
- dev->flags = 0;
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
flp = dlp->slave->priv;
err = (*flp->activate)(dlp->slave, dev);
if (err)
return(err);
+ netif_start_queue(dev);
+
return 0;
}
@@ -392,14 +380,13 @@ static int dlci_close(struct net_device *dev)
struct frad_local *flp;
int err;
+ netif_stop_queue(dev);
+
dlp = dev->priv;
flp = dlp->slave->priv;
err = (*flp->deactivate)(dlp->slave, dev);
- dev->start = 0;
- dev->tbusy = 1;
-
return 0;
}
@@ -508,7 +495,7 @@ int dlci_del(struct dlci_add *dlci)
if (!master)
return(-ENODEV);
- if (master->start)
+ if (netif_running(master))
return(-EBUSY);
dlp = master->priv;
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index d5c7ebd5e..6220d7fdd 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -122,7 +122,8 @@ static int hostess_open(struct net_device *d)
/*
* Go go go
*/
- d->tbusy=0;
+
+ netif_start_queue(d);
MOD_INC_USE_COUNT;
return 0;
}
@@ -141,8 +142,8 @@ static int hostess_close(struct net_device *d)
/*
* Link layer down
*/
- d->tbusy=1;
-
+ netif_stop_queue(d);
+
switch(dma)
{
case 0:
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index a4564afcb..1fa07475b 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -163,7 +163,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
dev = lapbeth_get_x25_dev(dev);
- if (dev == NULL || dev->start == 0) {
+ if (dev == NULL || !netif_running(dev)) {
kfree_skb(skb);
return 0;
}
@@ -215,7 +215,7 @@ static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev)
* Just to be *really* sure not to send anything if the interface
* is down, the ethernet device may have gone.
*/
- if (!dev->start) {
+ if (!netif_running(dev)) {
lapbeth_check_devices(dev);
kfree_skb(skb);
return -ENODEV;
@@ -360,9 +360,6 @@ static int lapbeth_open(struct net_device *dev)
if (lapbeth_check_devices(dev))
return -ENODEV; /* oops, it's gone */
- dev->tbusy = 0;
- dev->start = 1;
-
lapbeth = (struct lapbethdev *)dev->priv;
lapbeth_callbacks.connect_confirmation = lapbeth_connected;
@@ -374,12 +371,11 @@ static int lapbeth_open(struct net_device *dev)
if ((err = lapb_register(lapbeth, &lapbeth_callbacks)) != LAPB_OK) {
printk(KERN_ERR "lapbeth: lapb_register error - %d\n", err);
- dev->tbusy = 1;
- dev->start = 0;
return -ENODEV;
}
MOD_INC_USE_COUNT;
+ netif_start_queue(dev);
return 0;
}
@@ -389,9 +385,8 @@ static int lapbeth_close(struct net_device *dev)
struct lapbethdev *lapbeth;
int err;
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
lapbeth = (struct lapbethdev *)dev->priv;
if ((err = lapb_unregister(lapbeth)) != LAPB_OK)
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 4cf0c05a1..b161fbabc 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -59,11 +59,6 @@
#include <linux/version.h>
-#if LINUX_VERSION_CODE >=0x020200
-#define v22
-#endif
-
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -74,6 +69,7 @@
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/types.h>
@@ -88,12 +84,8 @@
#include <net/arp.h>
-
-
-#ifdef v22
#include <asm/uaccess.h>
#include <linux/init.h>
-#endif
#include "sbni.h"
@@ -523,6 +515,7 @@ static int __init sbni_probe1(struct net_device *dev, int ioaddr)
dev->hard_header_cache = sbni_header_cache;
dev->header_cache_update = sbni_header_cache_update;
+ spin_lock_init(&lp->lock);
lp->m=dev;
lp->me=dev;
lp->next_lp=NULL;
@@ -538,15 +531,15 @@ static int sbni_open(struct net_device *dev)
{
struct net_local* lp = (struct net_local*)dev->priv;
struct timer_list* watchdog = &lp->watchdog;
-
+ unsigned long flags;
DP( printk("%s: sbni_open\n", dev->name); )
+ save_flags(flags);
cli();
lp->currframe = NULL;
card_start(dev);
- dev->start = 1;
/* set timer watchdog */
init_timer(watchdog);
watchdog->expires = jiffies + SBNI_TIMEOUT;
@@ -555,8 +548,9 @@ static int sbni_open(struct net_device *dev)
add_timer(watchdog);
DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
- sti();
-
+ restore_flags(flags);
+
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
}
@@ -566,21 +560,18 @@ static int sbni_close(struct net_device *dev)
int ioaddr = dev->base_addr;
struct net_local* lp = (struct net_local*) dev->priv;
struct timer_list* watchdog = &lp->watchdog;
-
-
+ unsigned long flags;
+
DP( printk("%s: sbni_close\n", dev->name); )
+ netif_stop_queue(dev);
+
+ save_flags(flags);
cli();
-
sbni_drop_tx_queue(dev);
-
- dev->tbusy = 1;
- dev->start = 0;
-
del_timer(watchdog);
-
outb(0, ioaddr + CSR0);
- sti();
+ restore_flags(flags);
MOD_DEC_USE_COUNT;
return 0;
@@ -590,6 +581,7 @@ static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_local *lp = (struct net_local*)dev->priv;
struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
+ unsigned long flags;
#ifdef KATYUSHA
struct net_local *nl;
@@ -602,13 +594,6 @@ static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
if(lp->me != dev)
panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
- if(dev->interrupt)
- {
- DP( printk("sbni_xmit_start: interrupt\n"); )
- /* May be unloading, don't stamp on */
- return 1; /* the packet buffer this time */
- }
-
hh->number = 1;
hh->reserv = 0;
@@ -623,6 +608,7 @@ static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->len - sizeof(struct sbni_hard_header),
hh->crc);
+ spin_lock_irqsave(&lp->lock, flags);
#ifdef KATYUSHA
/* looking for first idle device */
for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
@@ -657,6 +643,7 @@ static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set request for transmit */
outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
#endif
+ spin_unlock_irqrestore(&lp->lock, flags);
return 0;
}
@@ -677,9 +664,6 @@ void card_start(struct net_device *dev)
lp->waitack=0;
skb_queue_head_init(&lp->queue);
sbni_drop_tx_queue(dev);
- dev->tbusy = 0;
-
- dev->interrupt = 0;
/* Reset the card and set start parameters */
outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
outb(EN_INT, dev->base_addr + CSR0);
@@ -776,8 +760,7 @@ static inline unsigned short sbni_recv(struct net_device *dev)
/*
* reset output active flags
*/
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
/*} if */
}
case PACKET_RESEND:
@@ -920,17 +903,12 @@ static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
- if(dev->interrupt)
- {
- printk("%s: Reentering the interrupt driver!\n", dev->name);
- return;
- }
- dev->interrupt = 1;
-
csr0 = inb(dev->base_addr + CSR0);
DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
lp=dev->priv;
+
+ spin_lock(&lp->lock);
if(!lp->carrier)
lp->carrier=1;
@@ -971,7 +949,7 @@ static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/
outb(csr0 | EN_INT, dev->base_addr + CSR0);
- dev->interrupt = 0;
+ spin_unlock(&lp->lock);
}
static struct enet_statistics *sbni_get_stats(struct net_device *dev)
@@ -1103,7 +1081,7 @@ static void sbni_watchdog(unsigned long arg)
}
sti();
outb(csr0 | RC_CHK, dev->base_addr + CSR0);
- if(dev->start)
+ if(netif_running(dev))
{
struct timer_list* watchdog = &lp->watchdog;
init_timer(watchdog);
@@ -1167,9 +1145,8 @@ static void sbni_drop_tx_queue(struct net_device *dev)
}
}
lp->waitack=0;
- dev->tbusy = 0;
-
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
+
DP( printk("%s: queue dropping stoped\n",dev->name); );
}
@@ -1194,7 +1171,7 @@ static int sbni_set_mac_address(struct net_device *dev, void *addr)
/* struct net_local *lp = (struct net_local *)dev->priv; */
struct sockaddr *saddr = addr;
- if(dev->start)
+ if(netif_running(dev))
{
/* Only possible while card isn't started */
return -EBUSY;
@@ -1400,13 +1377,11 @@ static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
-#ifdef v22
MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-#endif
static int sbniautodetect = -1;
diff --git a/drivers/net/wan/sbni.h b/drivers/net/wan/sbni.h
index 2e34d8d34..56550d8f2 100644
--- a/drivers/net/wan/sbni.h
+++ b/drivers/net/wan/sbni.h
@@ -146,7 +146,7 @@ struct net_local {
int carrier;
-
+ spinlock_t lock;
};
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 29bedf8f9..64165cd0e 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -510,7 +510,7 @@ int sdla_activate(struct net_device *slave, struct net_device *master)
flp->dlci[i] = abs(flp->dlci[i]);
- if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+ if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
return(0);
@@ -532,7 +532,7 @@ int sdla_deactivate(struct net_device *slave, struct net_device *master)
flp->dlci[i] = -abs(flp->dlci[i]);
- if (slave->start && (flp->config.station == FRAD_STATION_NODE))
+ if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE))
sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL);
return(0);
@@ -565,7 +565,7 @@ int sdla_assoc(struct net_device *slave, struct net_device *master)
flp->dlci[i] = -*(short *)(master->dev_addr);
master->mtu = slave->mtu;
- if (slave->start) {
+ if (netif_running(dev)) {
if (flp->config.station == FRAD_STATION_CPE)
sdla_reconfig(slave);
else
@@ -594,7 +594,7 @@ int sdla_deassoc(struct net_device *slave, struct net_device *master)
MOD_DEC_USE_COUNT;
- if (slave->start) {
+ if (netif_running(slave)) {
if (flp->config.station == FRAD_STATION_CPE)
sdla_reconfig(slave);
else
@@ -624,7 +624,7 @@ int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
ret = SDLA_RET_OK;
len = sizeof(struct dlci_conf);
- if (slave->start) {
+ if (netif_running(slave)) {
if (get)
ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,
NULL, 0, &dlp->config, &len);
@@ -646,7 +646,7 @@ int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
static int sdla_transmit(struct sk_buff *skb, struct net_device *dev)
{
struct frad_local *flp;
- int ret, addr, accept;
+ int ret, addr, accept, i;
short size;
unsigned long flags;
struct buf_entry *pbuf;
@@ -655,90 +655,80 @@ static int sdla_transmit(struct sk_buff *skb, struct net_device *dev)
ret = 0;
accept = 1;
- if (dev->tbusy)
- return(1);
+ netif_stop_queue(dev);
- if (skb == NULL)
- return(0);
+ /*
+ * stupid GateD insists on setting up the multicast router thru us
+ * and we're ill equipped to handle a non Frame Relay packet at this
+ * time!
+ */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
- else
+ accept = 1;
+ switch (dev->type)
{
- /*
- * stupid GateD insists on setting up the multicast router thru us
- * and we're ill equipped to handle a non Frame Relay packet at this
- * time!
- */
-
- accept = 1;
- switch (dev->type)
+ case ARPHRD_FRAD:
+ if (skb->dev->type != ARPHRD_DLCI)
+ {
+ printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
+ accept = 0;
+ }
+ break;
+ default:
+ printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
+ accept = 0;
+ break;
+ }
+ if (accept)
+ {
+ /* this is frame specific, but till there's a PPP module, it's the default */
+ switch (flp->type)
{
- case ARPHRD_FRAD:
- if (skb->dev->type != ARPHRD_DLCI)
+ case SDLA_S502A:
+ case SDLA_S502E:
+ ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
+ break;
+ case SDLA_S508:
+ size = sizeof(addr);
+ ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
+ if (ret == SDLA_RET_OK)
{
- printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
- accept = 0;
+ save_flags(flags);
+ cli();
+ SDLA_WINDOW(dev, addr);
+ pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
+ sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
+ SDLA_WINDOW(dev, addr);
+ pbuf->opp_flag = 1;
+ restore_flags(flags);
}
break;
-
- default:
- printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
- accept = 0;
- break;
}
-
- if (accept)
+ switch (ret)
{
- /* this is frame specific, but till there's a PPP module, it's the default */
- switch (flp->type)
- {
- case SDLA_S502A:
- case SDLA_S502E:
- ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
- break;
-
- case SDLA_S508:
- size = sizeof(addr);
- ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
- if (ret == SDLA_RET_OK)
- {
- save_flags(flags);
- cli();
- SDLA_WINDOW(dev, addr);
- pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
-
- sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
-
- SDLA_WINDOW(dev, addr);
- pbuf->opp_flag = 1;
- restore_flags(flags);
- }
- break;
- }
-
- switch (ret)
- {
- case SDLA_RET_OK:
- flp->stats.tx_packets++;
- ret = DLCI_RET_OK;
- break;
+ case SDLA_RET_OK:
+ flp->stats.tx_packets++;
+ ret = DLCI_RET_OK;
+ break;
- case SDLA_RET_CIR_OVERFLOW:
- case SDLA_RET_BUF_OVERSIZE:
- case SDLA_RET_NO_BUFS:
- flp->stats.tx_dropped++;
- ret = DLCI_RET_DROP;
- break;
+ case SDLA_RET_CIR_OVERFLOW:
+ case SDLA_RET_BUF_OVERSIZE:
+ case SDLA_RET_NO_BUFS:
+ flp->stats.tx_dropped++;
+ ret = DLCI_RET_DROP;
+ break;
- default:
- flp->stats.tx_errors++;
- ret = DLCI_RET_ERR;
- break;
- }
+ default:
+ flp->stats.tx_errors++;
+ ret = DLCI_RET_ERR;
+ break;
}
- dev->tbusy = 0;
}
+ netif_wake_queue(dev);
+ for(i=0;i<CONFIG_DLCI_MAX;i++)
+ {
+ if(flp->master[i]!=NULL)
+ netif_wake_queue(flp->master[i]);
+ }
return(ret);
}
@@ -892,7 +882,6 @@ static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
return;
}
- dev->interrupt = 1;
byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE);
switch (byte)
{
@@ -925,7 +914,6 @@ static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
/* this clears the byte, informing the Z80 we're done */
byte = 0;
sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
- dev->interrupt = 0;
}
static void sdla_poll(unsigned long device)
@@ -992,9 +980,8 @@ static int sdla_close(struct net_device *dev)
sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
MOD_DEC_USE_COUNT;
return(0);
@@ -1096,10 +1083,8 @@ static int sdla_open(struct net_device *dev)
sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
}
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
+
MOD_INC_USE_COUNT;
return(0);
@@ -1119,7 +1104,7 @@ static int sdla_config(struct net_device *dev, struct frad_conf *conf, int get)
if (!get)
{
- if (dev->start)
+ if (netif_running(dev))
return(-EBUSY);
if(copy_from_user(&data.config, conf, sizeof(struct frad_conf)))
@@ -1182,7 +1167,7 @@ static int sdla_config(struct net_device *dev, struct frad_conf *conf, int get)
else
{
/* no sense reading if the CPU isn't started */
- if (dev->start)
+ if (netif_running(dev))
{
size = sizeof(data);
if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
@@ -1331,7 +1316,7 @@ int sdla_change_mtu(struct net_device *dev, int new_mtu)
flp = dev->priv;
- if (dev->start)
+ if (netif_running(dev))
return(-EBUSY);
/* for now, you can't change the MTU! */
diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
index 3df910ea1..c0b419afa 100644
--- a/drivers/net/wan/sdla_chdlc.c
+++ b/drivers/net/wan/sdla_chdlc.c
@@ -74,6 +74,9 @@
typedef struct chdlc_private_area
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
sdla_t *card;
int TracingEnabled; /* For enabling Tracing */
unsigned long curr_trace_addr; /* Used for Tracing */
diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
index 0c7f7e8f0..f4431c9dc 100644
--- a/drivers/net/wan/sdla_fr.c
+++ b/drivers/net/wan/sdla_fr.c
@@ -167,6 +167,9 @@
*/
typedef struct fr_channel
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
unsigned dlci_configured ; /* check whether configured or not */
unsigned cir_status; /* check whether CIR enabled or not */
@@ -1960,7 +1963,9 @@ goto L4;
// Used to send inarp request at given interval
if (card->wandev.state == WAN_CONNECTED) {
int num_remaining = 0;
- for (dev=card->wandev.dev;dev;dev=dev->slave) {
+
+ dev = card->wandev.dev;
+ while (dev) {
fr_channel_t *chan = dev->priv;
if (chan->inarp == INARP_REQUEST &&
@@ -1972,6 +1977,7 @@ goto L4;
chan->inarp_tick = jiffies;
}
}
+ dev = chan->slave;
}
if (!num_remaining) { // no more to process
flags->imask &= ~FR_INTR_TIMER;
@@ -2135,65 +2141,68 @@ static void process_route (sdla_t* card)
/* Dynamic Route adding/removing */
- for (dev = card->wandev.dev; dev ; dev = dev->slave) {
- if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE ||
- ((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) {
- fs = get_fs();
+ dev = card->wandev.dev;
+ while (dev) {
+ fr_channel_t *chan = dev->priv;
+
+ if (chan->route_flag == ADD_ROUTE ||
+ chan->route_flag == REMOVE_ROUTE ) {
+ fs = get_fs();
- in_dev = dev->ip_ptr;
-
- if( in_dev != NULL && in_dev->ifa_list != NULL) {
- memset(&route, 0, sizeof(route));
- route.rt_dev = dev->name;
- route.rt_flags = 0;
-
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_addr.s_addr=in_dev->ifa_list->ifa_address;
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_family = AF_INET;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_addr.s_addr = 0xFFFFFFFF;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_family = AF_INET;
-
- switch(((fr_channel_t*)dev->priv)->route_flag) {
-
- case ADD_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_ioctl( SIOCADDRT, &route);
- set_fs(fs); /* restore old block */
-
- if (err) {
- printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err);
- printk(KERN_INFO "%s: Address: %s\n",
- ((fr_channel_t*)dev->priv)->name,
- in_ntoa(in_dev->ifa_list->ifa_address) );
- }
- else {
- ((fr_channel_t*)dev->priv)->
- route_flag = ROUTE_ADDED;
- }
- break;
+ in_dev = dev->ip_ptr;
+
+ if( in_dev != NULL && in_dev->ifa_list != NULL) {
+ memset(&route, 0, sizeof(route));
+ route.rt_dev = dev->name;
+ route.rt_flags = 0;
+
+ ((struct sockaddr_in *) &(route.rt_dst)) ->
+ sin_addr.s_addr=in_dev->ifa_list->ifa_address;
+ ((struct sockaddr_in *) &(route.rt_dst)) ->
+ sin_family = AF_INET;
+ ((struct sockaddr_in *) &(route.rt_genmask)) ->
+ sin_addr.s_addr = 0xFFFFFFFF;
+ ((struct sockaddr_in *) &(route.rt_genmask)) ->
+ sin_family = AF_INET;
+
+ switch(chan->route_flag) {
+
+ case ADD_ROUTE:
+ set_fs(get_ds()); /* get user space block */
+ err = ip_rt_ioctl( SIOCADDRT, &route);
+ set_fs(fs); /* restore old block */
+
+ if (err) {
+ printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ chan->name,
+ in_ntoa(in_dev->ifa_list->ifa_address) );
+ } else {
+ chan->route_flag = ROUTE_ADDED;
+ }
+ break;
- case REMOVE_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_ioctl( SIOCDELRT, &route);
- set_fs(fs); /* restore old block */
+ case REMOVE_ROUTE:
+ set_fs(get_ds()); /* get user space block */
+ err = ip_rt_ioctl( SIOCDELRT, &route);
+ set_fs(fs); /* restore old block */
+
+ if (err) {
+ printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
+ } else {
+ printk(KERN_INFO "%s: Removed route.\n",
+ chan->name);
+ chan->route_flag = NO_ROUTE;
+ }
+ break;
+ } /* Case Statement */
+ }
+ } /* If ADD/DELETE ROUTE */
- if (err) {
- printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err);
- printk(KERN_INFO "%s: Address: %s\n",
- dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
- } else {
- printk(KERN_INFO "%s: Removed route.\n",
- ((fr_channel_t*)dev->priv)->name);
- ((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE;
- }
- break;
- } /* Case Statement */
- }
- } /* If ADD/DELETE ROUTE */
- } /* Device 'For' Loop */
+ dev = chan->slave;
+ } /* Device 'While' Loop */
card->poll = NULL;
}
@@ -2568,7 +2577,8 @@ static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
struct net_device *dev;
/* Remove all routes from associated DLCI's */
- for (dev = card->wandev.dev; dev; dev = dev->slave) {
+ dev = card->wandev.dev;
+ while (dev) {
fr_channel_t *chan = dev->priv;
if (chan->route_flag == ROUTE_ADDED) {
chan->route_flag = REMOVE_ROUTE;
@@ -2578,6 +2588,8 @@ static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
if (chan->inarp == INARP_CONFIGURED) {
chan->inarp = INARP_REQUEST;
}
+
+ dev = chan->slave;
}
wanpipe_set_state(card, WAN_DISCONNECTED);
@@ -2590,12 +2602,14 @@ static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
int num_requests = 0;
/* Remove all routes from associated DLCI's */
- for (dev = card->wandev.dev; dev; dev = dev->slave) {
+ dev = card->wandev.dev;
+ while (dev) {
fr_channel_t *chan = dev->priv;
if( chan->inarp == INARP_REQUEST ){
num_requests++;
chan->inarp_tick = jiffies;
}
+ dev = chan->slave;
}
/* Allow timer interrupts */
@@ -2731,8 +2745,8 @@ static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox)
}
}
- for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){
-
+ dev2 = card->wandev.dev;
+ while (dev2) {
chan = dev2->priv;
if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
@@ -2741,6 +2755,7 @@ static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox)
}
}
+ dev2 = chan->slave;
}
return 1;
}
diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
index 1b900fc62..f3dcc129b 100644
--- a/drivers/net/wan/sdla_ppp.c
+++ b/drivers/net/wan/sdla_ppp.c
@@ -155,6 +155,9 @@
typedef struct ppp_private_area
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
sdla_t* card;
unsigned long router_start_time; /*router start time in sec */
unsigned long tick_counter; /*used for 5 second counter*/
diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c
index 270c5a59f..dfb5d36a5 100644
--- a/drivers/net/wan/sdla_x25.c
+++ b/drivers/net/wan/sdla_x25.c
@@ -75,6 +75,9 @@
*/
typedef struct x25_channel
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
unsigned lcn; /* logical channel number */
@@ -708,11 +711,13 @@ static int if_send (struct sk_buff* skb, struct net_device* dev)
return dev->tbusy;
}
printk(KERN_INFO "%s: Transmit time out %s!\n",
- card->devname, dev->name)
- ;
- for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
- {
+ card->devname, dev->name);
+
+ dev2 = card->wandev.dev;
+ while (dev2) {
+ x25_channel_t *chan2 = dev2->priv;
dev2->tbusy = 0;
+ dev2 = chan2->slave;
}
}
chan->tick_counter = jiffies;
@@ -898,13 +903,17 @@ static void wpx_isr (sdla_t* card)
if(card->buff_int_mode_unbusy)
{
- for(dev = card->wandev.dev; dev; dev = dev->slave)
- {
- if(((x25_channel_t*)dev->priv)->devtint)
- {
+ x25_channel_t *chan;
+
+ dev = card->wandev.dev;
+ while (dev) {
+ chan = dev->priv;
+ if(chan->devtint) {
mark_bh(NET_BH);
return;
}
+
+ dev = chan->slave;
}
}
}
@@ -1042,12 +1051,15 @@ static void rx_intr (sdla_t* card)
static void tx_intr (sdla_t* card)
{
struct net_device *dev;
+ x25_channel_t *chan;
/* unbusy all devices and then dev_tint(); */
- for(dev = card->wandev.dev; dev; dev = dev->slave)
- {
- ((x25_channel_t*)dev->priv)->devtint = dev->tbusy;
+ dev = card->wandev.dev;
+ while (dev) {
+ chan->devtint = dev->tbusy;
dev->tbusy = 0;
+
+ dev = chan->slave;
}
}
@@ -1170,8 +1182,8 @@ static void poll_active (sdla_t* card)
/* Fetch X.25 asynchronous events */
x25_fetch_events(card);
- for (dev = card->wandev.dev; dev; dev = dev->slave)
- {
+ dev = card->wandev.dev;
+ while (dev) {
x25_channel_t* chan = dev->priv;
struct sk_buff* skb = chan->tx_skb;
@@ -1199,6 +1211,8 @@ static void poll_active (sdla_t* card)
chan_disc(dev);
}
}
+
+ dev = chan->slave;
}
}
@@ -1785,8 +1799,8 @@ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
card->devname, new_lcn, mb->data);
/* Find available channel */
- for (dev = wandev->dev; dev; dev = dev->slave)
- {
+ dev = wandev->dev;
+ while (dev) {
chan = dev->priv;
if (!chan->svc || (chan->state != WAN_DISCONNECTED))
@@ -1796,6 +1810,8 @@ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
/* If just an '@' is specified, accept all incoming calls */
if (strcmp(chan->addr, "") == 0)
break;
+
+ dev = chan->slave;
}
if (dev == NULL)
@@ -1912,8 +1928,14 @@ static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
card->devname, mb->cmd.cause, mb->cmd.diagn);
/* down all logical channels */
- for (dev = wandev->dev; dev; dev = dev->slave)
+ dev = wandev->dev;
+ while (dev) {
+ x25_channel_t *chan = dev->priv;
+
set_chan_state(dev, WAN_DISCONNECTED);
+ dev = chan->slave;
+ }
+
return (cmd == X25_WRITE) ? 0 : 1;
}
@@ -1979,10 +2001,14 @@ static int disconnect (sdla_t* card)
static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
{
struct net_device* dev;
+ x25_channel_t *chan;
- for (dev = wandev->dev; dev; dev = dev->slave)
- if (((x25_channel_t*)dev->priv)->lcn == lcn)
+ dev = wandev->dev;
+ while (dev) {
+ if (chan->lcn == lcn)
break;
+ dev = chan->slave;
+ }
return dev;
}
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 90cccf81d..8fd2ff105 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -119,7 +119,7 @@ static int sealevel_open(struct net_device *d)
/*
* Go go go
*/
- d->tbusy=0;
+ netif_start_queue(d);
MOD_INC_USE_COUNT;
return 0;
}
@@ -142,8 +142,9 @@ static int sealevel_close(struct net_device *d)
/*
* Link layer down
*/
- d->tbusy=1;
-
+
+ netif_stop_queue(d);
+
switch(unit)
{
case 0:
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index e50865d97..7b647d663 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -205,8 +205,7 @@ static void x25_asy_changed_mtu(struct x25_asy *sl)
static inline void x25_asy_lock(struct x25_asy *sl)
{
- if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
- printk("%s: trying to lock already locked device!\n", sl->dev->name);
+ netif_stop_queue(sl->dev);
}
@@ -214,8 +213,7 @@ static inline void x25_asy_lock(struct x25_asy *sl)
static inline void x25_asy_unlock(struct x25_asy *sl)
{
- if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
- printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
+ netif_wake_queue(sl->dev);
}
/* Send one completely decapsulated IP datagram to the IP layer. */
@@ -303,7 +301,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
/* First make sure we're connected. */
- if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
+ if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return;
if (sl->xleft <= 0)
@@ -313,7 +311,6 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
sl->tx_packets++;
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
x25_asy_unlock(sl);
- mark_bh(NET_BH);
return;
}
@@ -322,6 +319,20 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
sl->xhead += actual;
}
+static void x25_asy_timeout(struct net_device *dev)
+{
+ struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ /* May be we must check transmitter timeout here ?
+ * 14 Oct 1994 Dmitry Gorodchanin.
+ */
+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+ (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
+ "bad line quality" : "driver error");
+ sl->xleft = 0;
+ sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ x25_asy_unlock(sl);
+}
+
/* Encapsulate an IP datagram and kick it into a TTY queue. */
static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -329,7 +340,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
struct x25_asy *sl = (struct x25_asy*)(dev->priv);
int err;
- if (!dev->start)
+ if (!netif_running(sl->dev))
{
printk("%s: xmit call when iface is down\n", dev->name);
return 1;
@@ -361,25 +372,6 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* So, no queues !
* 14 Oct 1994 Dmitry Gorodchanin.
*/
- if (dev->tbusy) {
- /* May be we must check transmitter timeout here ?
- * 14 Oct 1994 Dmitry Gorodchanin.
- */
-#ifdef SL_CHECK_TRANSMIT
- if (jiffies - dev->trans_start < 20 * HZ) {
- /* 20 sec timeout not reached */
- return 1;
- }
- printk("%s: transmit timed out, %s?\n", dev->name,
- (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
- "bad line quality" : "driver error");
- sl->xleft = 0;
- sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- x25_asy_unlock(sl);
-#else
- return 1;
-#endif
- }
if((err=lapb_data_request(sl,skb))!=LAPB_OK)
{
@@ -414,7 +406,7 @@ static void x25_asy_data_indication(void *token, struct sk_buff *skb)
static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
{
struct x25_asy *sl=token;
- if(sl->dev->tbusy)
+ if (netif_queue_stopped(sl->dev))
{
printk(KERN_ERR "x25_asy: tbusy drop\n");
kfree_skb(skb);
@@ -514,10 +506,8 @@ static int x25_asy_open(struct net_device *dev)
sl->xleft = 0;
sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
- dev->tbusy = 0;
-/* dev->flags |= IFF_UP; */
- dev->start = 1;
-
+ netif_start_queue(dev);
+
/*
* Now attach LAPB
*/
@@ -551,12 +541,9 @@ static int x25_asy_close(struct net_device *dev)
return -EBUSY;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
if((err=lapb_unregister(sl))!=LAPB_OK)
printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
-
-/* dev->flags &= ~IFF_UP; */
return 0;
}
@@ -576,7 +563,7 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp,
{
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
- if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
+ if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return;
/*
@@ -876,6 +863,8 @@ int x25_asy_init(struct net_device *dev)
dev->mtu = SL_MTU;
dev->hard_start_xmit = x25_asy_xmit;
+ dev->tx_timeout = x25_asy_timeout;
+ dev->watchdog_timeo = HZ*20;
dev->open = x25_asy_open_dev;
dev->stop = x25_asy_close;
dev->get_stats = x25_asy_get_stats;
@@ -914,7 +903,7 @@ cleanup_module(void)
* VSV = if dev->start==0, then device
* unregistered while close proc.
*/
- if (x25_asy_ctrls[i]->dev.start)
+ if (netif_running(&(x25_asy_ctrls[i]->dev)))
unregister_netdev(&(x25_asy_ctrls[i]->dev));
kfree(x25_asy_ctrls[i]);
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index f6b385de5..2ff818b04 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -54,12 +54,23 @@
static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
-/*
+/**
+ * z8530_read_port:
+ * @p: port to read
+ *
* Provided port access methods. The Comtrol SV11 requires no delays
* between accesses and uses PC I/O. Some drivers may need a 5uS delay
+ *
+ * In the longer term this should become an architecture specific
+ * section so that this can become a generic driver interface for all
+ * platforms. For now we only handle PC I/O ports with or without the
+ * dread 5uS sanity delay.
+ *
+ * The caller must hold sufficient locks to avoid violating the horrible
+ * 5uS delay rule.
*/
-extern __inline__ int z8530_read_port(int p)
+extern __inline__ int z8530_read_port(unsigned long p)
{
u8 r=inb(Z8530_PORT_OF(p));
if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */
@@ -67,7 +78,23 @@ extern __inline__ int z8530_read_port(int p)
return r;
}
-extern __inline__ void z8530_write_port(int p, u8 d)
+/**
+ * z8530_write_port:
+ * @p: port to write
+ * @d: value to write
+ *
+ * Write a value to a port with delays if need be. Note that the
+ * caller must hold locks to avoid read/writes from other contexts
+ * violating the 5uS rule
+ *
+ * In the longer term this should become an architecture specific
+ * section so that this can become a generic driver interface for all
+ * platforms. For now we only handle PC I/O ports with or without the
+ * dread 5uS sanity delay.
+ */
+
+
+extern __inline__ void z8530_write_port(unsigned long p, u8 d)
{
outb(d,Z8530_PORT_OF(p));
if(p&Z8530_PORT_SLEEP)
@@ -80,8 +107,16 @@ static void z8530_rx_done(struct z8530_channel *c);
static void z8530_tx_done(struct z8530_channel *c);
-/*
- * Port accesses
+/**
+ * read_zsreg:
+ * @c: Z8530 channel to read from (2 per chip)
+ * @reg: Register to read
+ * FIXME: Use a spinlock.
+ *
+ * Most of the Z8530 registers are indexed off the control registers.
+ * A read is done by writing to the control register and reading the
+ * register back. We do the locking needed to protect this
+ * operation.
*/
extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
@@ -97,6 +132,14 @@ extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
return r;
}
+/**
+ * read_zsdata:
+ * @c: The Z8530 channel to read the data port from
+ *
+ * The data port provides fast access to some things. We still
+ * have all the 5uS delays to worry about.
+ */
+
extern inline u8 read_zsdata(struct z8530_channel *c)
{
u8 r;
@@ -104,6 +147,17 @@ extern inline u8 read_zsdata(struct z8530_channel *c)
return r;
}
+/**
+ * write_zsreg:
+ * @c: The Z8530 channel
+ * @reg: Register number
+ * @val: Value to write
+ *
+ * Write a value to an indexed register. Perform the locking needed
+ * to honour the irritating delay rules. We know about register 0
+ * being fast to access.
+ */
+
extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
{
unsigned long flags;
@@ -194,8 +248,16 @@ u8 z8530_hdlc_kilostream_85230[]=
EXPORT_SYMBOL(z8530_hdlc_kilostream_85230);
-/*
- * Flush the FIFO
+/**
+ * z8530_flush_fifo:
+ * @c: Channel to flush
+ *
+ * Flush the receive FIFO. There is no specific option for this, we
+ * blindly read bytes and discard them. Reading when there is no data
+ * is harmless. The 8530 has a 4 byte FIFO, the 85230 has 8 bytes.
+ *
+ * All locking is handled for the caller. On return data may still be
+ * present if it arrived during the flush.
*/
static void z8530_flush_fifo(struct z8530_channel *c)
@@ -213,7 +275,16 @@ static void z8530_flush_fifo(struct z8530_channel *c)
}
}
-/* Sets or clears DTR/RTS on the requested line */
+/**
+ * z8530_rtsdtr:
+ * @c: The Z8530 channel to contro;
+ * @set: 1 to set, 0 to clear
+ *
+ * Sets or clears DTR/RTS on the requested line. All locking is handled
+ * for the caller. For now we assume all boards use the actual RTS/DTR
+ * on the chip. Apparently one or two don't. We'll scream about them
+ * later.
+ */
static void z8530_rtsdtr(struct z8530_channel *c, int set)
{
@@ -224,9 +295,12 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
write_zsreg(c, R5, c->regs[5]);
}
-/*
- * Receive handler. This is much like the async one but not quite the
- * same or as complex
+/**
+ * z8530_rx:
+ * @c: Z8530 channel to process
+ *
+ * Receive handler for receiving in PIO mode. This is much like the
+ * async one but not quite the same or as complex
*
* Note: Its intended that this handler can easily be separated from
* the main code to run realtime. That'll be needed for some machines
@@ -238,9 +312,9 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
* other code - this is true in the RT case too.
*
* We only cover the sync cases for this. If you want 2Mbit async
- * do it yourself but consider medical assistance first.
- *
- * This non DMA synchronous mode is portable code.
+ * do it yourself but consider medical assistance first. This non DMA
+ * synchronous mode is portable code. The DMA mode assumes PCI like
+ * ISA DMA
*/
static void z8530_rx(struct z8530_channel *c)
@@ -303,8 +377,14 @@ static void z8530_rx(struct z8530_channel *c)
}
-/*
- * Z8530 transmit interrupt handler
+/**
+ * z8530_tx:
+ * @c: Z8530 channel to process
+ *
+ * Z8530 transmit interrupt handler for the PIO mode. The basic
+ * idea is to attempt to keep the FIFO fed. We fill as many bytes
+ * in as possible, its quite possible that we won't keep up with the
+ * data rate otherwise.
*/
static void z8530_tx(struct z8530_channel *c)
@@ -340,6 +420,17 @@ static void z8530_tx(struct z8530_channel *c)
write_zsctrl(c, RES_H_IUS);
}
+/**
+ * z8530_status:
+ * @chan: Z8530 channel to process
+ *
+ * A status event occured in PIO synchronous mode. There are several
+ * reasons the chip will bother us here. A transmit underrun means we
+ * failed to feed the chip fast enough and just broke a packet. A DCD
+ * change is a line up or down. We communicate that back to the protocol
+ * layer for synchronous PPP to renegotiate.
+ */
+
static void z8530_status(struct z8530_channel *chan)
{
u8 status=read_zsreg(chan, R0);
@@ -387,9 +478,14 @@ struct z8530_irqhandler z8530_sync=
EXPORT_SYMBOL(z8530_sync);
-/*
+/**
+ * z8530_dma_rx:
+ * @chan: Channel to handle
+ *
* Non bus mastering DMA interfaces for the Z8x30 devices. This
- * is really pretty PC specific.
+ * is really pretty PC specific. The DMA mode means that most receive
+ * events are handled by the DMA hardware. We get a kick here only if
+ * a frame ended.
*/
static void z8530_dma_rx(struct z8530_channel *chan)
@@ -417,6 +513,14 @@ static void z8530_dma_rx(struct z8530_channel *chan)
}
}
+/**
+ * z8530_dma_tx:
+ * @chan: The Z8530 channel to handle
+ *
+ * We have received an interrupt while doing DMA transmissions. It
+ * shouldn't happen. Scream loudly if it does.
+ */
+
static void z8530_dma_tx(struct z8530_channel *chan)
{
if(!chan->dma_tx)
@@ -430,6 +534,17 @@ static void z8530_dma_tx(struct z8530_channel *chan)
z8530_tx(chan);
}
+/**
+ * z8530_dma_status:
+ * @chan: Z8530 channel to process
+ *
+ * A status event occured on the Z8530. We receive these for two reasons
+ * when in DMA mode. Firstly if we finished a packet transfer we get one
+ * and kick the next packet out. Secondly we may see a DCD change and
+ * have to poke the protocol layer.
+ *
+ */
+
static void z8530_dma_status(struct z8530_channel *chan)
{
unsigned long flags;
@@ -490,8 +605,11 @@ struct z8530_irqhandler z8530_txdma_sync=
EXPORT_SYMBOL(z8530_txdma_sync);
-/*
- * Interrupt vectors for a Z8530 that is in 'parked' mode.
+/**
+ * z8530_rx_clear:
+ * @c: Z8530 channel to shut up
+ *
+ * Receive interrupt vectors for a Z8530 that is in 'parked' mode.
* For machines with PCI Z85x30 cards, or level triggered interrupts
* (eg the MacII) we must clear the interrupt cause or die.
*/
@@ -516,12 +634,30 @@ static void z8530_rx_clear(struct z8530_channel *c)
write_zsctrl(c, RES_H_IUS);
}
+/**
+ * z8530_tx_clear:
+ * @c: Z8530 channel to shut up
+ *
+ * Transmit interrupt vectors for a Z8530 that is in 'parked' mode.
+ * For machines with PCI Z85x30 cards, or level triggered interrupts
+ * (eg the MacII) we must clear the interrupt cause or die.
+ */
+
static void z8530_tx_clear(struct z8530_channel *c)
{
write_zsctrl(c, RES_Tx_P);
write_zsctrl(c, RES_H_IUS);
}
+/**
+ * z8530_status_clear:
+ * @chan: Z8530 channel to shut up
+ *
+ * Status interrupt vectors for a Z8530 that is in 'parked' mode.
+ * For machines with PCI Z85x30 cards, or level triggered interrupts
+ * (eg the MacII) we must clear the interrupt cause or die.
+ */
+
static void z8530_status_clear(struct z8530_channel *chan)
{
u8 status=read_zsreg(chan, R0);
@@ -541,8 +677,17 @@ struct z8530_irqhandler z8530_nop=
EXPORT_SYMBOL(z8530_nop);
-/*
- * A Z85[2]30 device has stuck its hand in the air for attention
+/**
+ * z8530_interrupt:
+ * @irq: Interrupt number
+ * @dev_id: The Z8530 device that is interrupting.
+ * @regs: unused
+ *
+ * A Z85[2]30 device has stuck its hand in the air for attention.
+ * We scan both the channels on the chip for events and then call
+ * the channel specific call backs for each channel that has events.
+ * We have to use callback functions because the two channels can be
+ * in different modes.
*/
void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -612,6 +757,15 @@ static char reg_init[16]=
};
+/**
+ * z8530_sync_open:
+ * @dev: The network interface we are using
+ * @c: The Z8530 channel to open in synchronous PIO mode
+ *
+ * Switch a Z8530 into synchronous mode without DMA assist. We
+ * raise the RTS/DTR and commence network operation.
+ */
+
int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
{
c->sync = 1;
@@ -634,9 +788,19 @@ int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_open);
+/**
+ * z8530_sync_close:
+ * @dev: Network device to close
+ * @c: Z8530 channel to disassociate and move to idle
+ *
+ * Close down a Z8530 interface and switch its interrupt handlers
+ * to discard future events.
+ */
+
int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
{
u8 chk;
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
@@ -649,6 +813,16 @@ int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_close);
+/**
+ * z8530_sync_dma_open:
+ * @dev: The network device to attach
+ * @c: The Z8530 channel to configure in sync DMA mode.
+ *
+ * Set up a Z85x30 device for synchronous DMA in both directions. Two
+ * ISA DMA channels must be available for this to work. We assume ISA
+ * DMA driven I/O and PC limits on access.
+ */
+
int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
{
unsigned long flags;
@@ -753,11 +927,21 @@ int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
c->irqs = &z8530_dma_sync;
z8530_rtsdtr(c,1);
write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+
return 0;
}
EXPORT_SYMBOL(z8530_sync_dma_open);
+/**
+ * z8530_sync_dma_close:
+ * @dev: Network device to detach
+ * @c: Z8530 channel to move into discard mode
+ *
+ * Shut down a DMA mode synchronous interface. Halt the DMA, and
+ * free the buffers.
+ */
+
int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
{
u8 chk;
@@ -814,6 +998,16 @@ int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_dma_close);
+/**
+ * z8530_sync_txdma_open:
+ * @dev: The network device to attach
+ * @c: The Z8530 channel to configure in sync DMA mode.
+ *
+ * Set up a Z85x30 device for synchronous DMA tranmission. One
+ * ISA DMA channel must be available for this to work. The receive
+ * side is run in PIO mode, but then it has the bigger FIFO.
+ */
+
int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
{
unsigned long flags;
@@ -898,15 +1092,26 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
z8530_rtsdtr(c,1);
printk("Rx interrupts ON\n");
write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+
return 0;
}
EXPORT_SYMBOL(z8530_sync_txdma_open);
-
+
+/**
+ * z8530_sync_txdma_close:
+ * @dev: Network device to detach
+ * @c: Z8530 channel to move into discard mode
+ *
+ * Shut down a DMA/PIO split mode synchronous interface. Halt the DMA,
+ * and free the buffers.
+ */
+
int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
{
unsigned long flags;
u8 chk;
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
@@ -950,21 +1155,32 @@ int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
EXPORT_SYMBOL(z8530_sync_txdma_close);
+
/*
- * Describe a Z8530 in a standard format. We must pass the I/O as
- * the port offset isnt predictable. The main reason for this function
- * is to try and get a common format of report.
+ * Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny
+ * it exists...
*/
-
+
static char *z8530_type_name[]={
"Z8530",
"Z85C30",
"Z85230"
};
-void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
+/**
+ * z8530_describe:
+ * @dev: Z8530 device to describe
+ * @mapping: string holding mapping type (eg "I/O" or "Mem")
+ * @io: the port value in question
+ *
+ * Describe a Z8530 in a standard format. We must pass the I/O as
+ * the port offset isnt predictable. The main reason for this function
+ * is to try and get a common format of report.
+ */
+
+void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io)
{
- printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n",
+ printk(KERN_INFO "%s: %s found at %s 0x%lX, IRQ %d.\n",
dev->name,
z8530_type_name[dev->type],
mapping,
@@ -974,8 +1190,21 @@ void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
EXPORT_SYMBOL(z8530_describe);
-/*
- * Configure up a Z8530
+/**
+ * z8530_init:
+ * @dev: Z8530 device to initialise.
+ *
+ * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device
+ * is present, identify the type and then program it to hopefully
+ * keep quite and behave. This matters a lot, a Z8530 in the wrong
+ * state will sometimes get into stupid modes generating 10Khz
+ * interrupt streams and the like.
+ *
+ * We set the interrupt handler up to discard any events, in case
+ * we get them during reset or setp.
+ *
+ * Return 0 for success, or a negative value indicating the problem
+ * in errno form.
*/
@@ -1043,6 +1272,15 @@ int z8530_init(struct z8530_dev *dev)
EXPORT_SYMBOL(z8530_init);
+/**
+ * z8530_shutdown:
+ * @dev: The Z8530 chip to shutdown
+ *
+ * We set the interrupt handlers to silence any interrupts. We then
+ * reset the chip and wait 100uS to be sure the reset completed. Just
+ * in case the caller then tries to do stuff.
+ */
+
int z8530_shutdown(struct z8530_dev *dev)
{
/* Reset the chip */
@@ -1055,9 +1293,15 @@ int z8530_shutdown(struct z8530_dev *dev)
EXPORT_SYMBOL(z8530_shutdown);
-/*
- * Load a Z8530 channel up from the system data
- * We use +16 to indicate the 'prime' registers
+/**
+ * z8530_channel_load:
+ * @c: Z8530 channel to configure
+ * @rtable: Table of register, value pairs
+ * FIXME: ioctl to allow user uploaded tables
+ *
+ * Load a Z8530 channel up from the system data> We use +16 to
+ * indicate the 'prime' registers. The value 255 terminates the
+ * table
*/
int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
@@ -1088,8 +1332,16 @@ int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
EXPORT_SYMBOL(z8530_channel_load);
-/*
- * Higher level shovelling - transmit chains
+/**
+ * z8530_tx_begin:
+ * @c: The Z8530 channel to kick
+ *
+ * This is the speed sensitive side of transmission. If we are called
+ * and no buffer is being transmitted we commence the next buffer. If
+ * nothing is queued we idle the sync.
+ *
+ * Note: We are handling this code path in the interrupt path, keep it
+ * fast or bad things will happen.
*/
static void z8530_tx_begin(struct z8530_channel *c)
@@ -1102,7 +1354,7 @@ static void z8530_tx_begin(struct z8530_channel *c)
c->tx_next_skb=NULL;
c->tx_ptr=c->tx_next_ptr;
- mark_bh(NET_BH);
+ netif_wake_queue(c->netdevice);
if(c->tx_skb==NULL)
{
/* Idle on */
@@ -1176,7 +1428,15 @@ static void z8530_tx_begin(struct z8530_channel *c)
}
}
}
-
+
+/**
+ * z8530_tx_done:
+ * @c: The channel that completed a transmit.
+ *
+ * This is called when we complete a packet send. We wake the queue,
+ * start the next packet going and then free the buffer of the existing
+ * packet. This code is fairly timing sensitive.
+ */
static void z8530_tx_done(struct z8530_channel *c)
{
@@ -1184,7 +1444,7 @@ static void z8530_tx_done(struct z8530_channel *c)
struct sk_buff *skb;
spin_lock_irqsave(&z8530_buffer_lock, flags);
- c->netdevice->tbusy=0;
+ netif_wake_queue(c->netdevice);
/* Actually this can happen.*/
if(c->tx_skb==NULL)
{
@@ -1197,11 +1457,16 @@ static void z8530_tx_done(struct z8530_channel *c)
spin_unlock_irqrestore(&z8530_buffer_lock, flags);
c->stats.tx_packets++;
c->stats.tx_bytes+=skb->len;
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
}
-/*
- * Higher level shovelling - receive chains
+/**
+ * z8530_null_rx:
+ * @c: The channel the packet arrived on
+ * @skb: The buffer
+ *
+ * We point the receive handler at this function when idle. Instead
+ * of syncppp processing the frames we get to throw them away.
*/
void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
@@ -1211,6 +1476,17 @@ void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
EXPORT_SYMBOL(z8530_null_rx);
+/**
+ * z8530_rx_done:
+ * @c: The channel that completed a receive
+ *
+ * A new packet is complete. Our goal here is to get back into receive
+ * mode as fast as possible. On the Z85230 we could change to using
+ * ESCC mode, but on the older chips we have no choice. We flip to the
+ * new buffer immediately in DMA mode so that the DMA of the next
+ * frame can occur while we are copying the previous buffer to an sk_buff
+ */
+
static void z8530_rx_done(struct z8530_channel *c)
{
struct sk_buff *skb;
@@ -1265,7 +1541,7 @@ static void z8530_rx_done(struct z8530_channel *c)
else
/* Can't occur as we dont reenable the DMA irq until
after the flip is done */
- printk("DMA flip overrun!\n");
+ printk(KERN_WARNING "%s: DMA flip overrun!\n", c->netdevice->name);
release_dma_lock(flags);
@@ -1353,8 +1629,12 @@ static void z8530_rx_done(struct z8530_channel *c)
}
}
-/*
- * Cannot DMA over a 64K boundary on a PC
+/**
+ * spans_boundary:
+ * @skb: The buffer to check
+ *
+ * Returns true if the buffer cross a DMA boundary on a PC. The poor
+ * thing can only DMA within a 64K block not across the edges of it.
*/
extern inline int spans_boundary(struct sk_buff *skb)
@@ -1369,7 +1649,11 @@ extern inline int spans_boundary(struct sk_buff *skb)
return 0;
}
-/*
+/**
+ * z8530_queue_xmit:
+ * @c: The channel to use
+ * @skb: The packet to kick down the channel
+ *
* Queue a packet for transmission. Because we have rather
* hard to hit interrupt latencies for the Z85230 per packet
* even in DMA mode we do the flip to DMA buffer if needed here
@@ -1379,9 +1663,10 @@ extern inline int spans_boundary(struct sk_buff *skb)
int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
{
unsigned long flags;
+
+ netif_stop_queue(c->netdevice);
if(c->tx_next_skb)
{
- skb->dev->tbusy=1;
return 1;
}
@@ -1414,11 +1699,21 @@ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
spin_lock_irqsave(&z8530_buffer_lock, flags);
z8530_tx_begin(c);
spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+
+ netif_wake_queue(c->netdevice);
return 0;
}
EXPORT_SYMBOL(z8530_queue_xmit);
+/**
+ * z8530_get_stats:
+ * @c: The channel to use
+ *
+ * Get the statistics block. We keep the statistics in software as
+ * the chip doesn't do it for us.
+ */
+
struct net_device_stats *z8530_get_stats(struct z8530_channel *c)
{
return &c->stats;
diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
index dcad711b0..8dc92a535 100644
--- a/drivers/net/wan/z85230.h
+++ b/drivers/net/wan/z85230.h
@@ -304,8 +304,8 @@ struct z8530_channel
*/
struct z8530_dev *dev; /* Z85230 chip instance we are from */
- int ctrlio; /* I/O ports */
- int dataio;
+ unsigned long ctrlio; /* I/O ports */
+ unsigned long dataio;
/*
* For PC we encode this way.
@@ -395,7 +395,7 @@ extern u8 z8530_dead_port[];
extern u8 z8530_hdlc_kilostream_85230[];
extern u8 z8530_hdlc_kilostream[];
extern void z8530_interrupt(int, void *, struct pt_regs *);
-extern void z8530_describe(struct z8530_dev *, char *mapping,int io);
+extern void z8530_describe(struct z8530_dev *, char *mapping, unsigned long io);
extern int z8530_init(struct z8530_dev *);
extern int z8530_shutdown(struct z8530_dev *);
extern int z8530_sync_open(struct net_device *, struct z8530_channel *);
diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c
index 73771fc96..cd5b7caa0 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wavelan.c
@@ -6,9 +6,9 @@
* Reorganisation and extension of the driver.
* Original copyright follows (also see the end of this file).
* See wavelan.p.h for details.
- */
-
-/*
+ *
+ *
+ *
* AT&T GIS (nee NCR) WaveLAN card:
* An Ethernet-like radio transceiver
* controlled by an Intel 82586 coprocessor.
@@ -26,54 +26,49 @@
/*
* Wrapper for disabling interrupts.
*/
-static inline unsigned long
-wv_splhi(void)
-{
- unsigned long flags;
- save_flags(flags);
- cli();
-
- return(flags);
+static inline unsigned long wv_splhi(void)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ return (flags);
}
/*------------------------------------------------------------------*/
/*
* Wrapper for re-enabling interrupts.
*/
-static inline void
-wv_splx(unsigned long flags)
+static inline void wv_splx(unsigned long flags)
{
- restore_flags(flags);
+ restore_flags(flags);
}
/*------------------------------------------------------------------*/
/*
* Translate irq number to PSA irq parameter
*/
-static u_char
-wv_irq_to_psa(int irq)
+static u8 wv_irq_to_psa(int irq)
{
- if(irq < 0 || irq >= NELS(irqvals))
- return 0;
+ if (irq < 0 || irq >= NELS(irqvals))
+ return 0;
- return irqvals[irq];
+ return irqvals[irq];
}
/*------------------------------------------------------------------*/
/*
* Translate PSA irq parameter to irq number
*/
-static int __init
-wv_psa_to_irq(u_char irqval)
+static int __init wv_psa_to_irq(u8 irqval)
{
- int irq;
+ int irq;
- for(irq = 0; irq < NELS(irqvals); irq++)
- if(irqvals[irq] == irqval)
- return irq;
+ for (irq = 0; irq < NELS(irqvals); irq++)
+ if (irqvals[irq] == irqval)
+ return irq;
- return -1;
+ return -1;
}
#ifdef STRUCT_CHECK
@@ -82,21 +77,20 @@ wv_psa_to_irq(u_char irqval)
* Sanity routine to verify the sizes of the various WaveLAN interface
* structures.
*/
-static char *
-wv_struct_check(void)
+static char *wv_struct_check(void)
{
#define SC(t,s,n) if (sizeof(t) != s) return(n);
- SC(psa_t, PSA_SIZE, "psa_t");
- SC(mmw_t, MMW_SIZE, "mmw_t");
- SC(mmr_t, MMR_SIZE, "mmr_t");
- SC(ha_t, HA_SIZE, "ha_t");
+ SC(psa_t, PSA_SIZE, "psa_t");
+ SC(mmw_t, MMW_SIZE, "mmw_t");
+ SC(mmr_t, MMR_SIZE, "mmr_t");
+ SC(ha_t, HA_SIZE, "ha_t");
#undef SC
- return((char *) NULL);
-} /* wv_struct_check */
-#endif /* STRUCT_CHECK */
+ return ((char *) NULL);
+} /* wv_struct_check */
+#endif /* STRUCT_CHECK */
/********************* HOST ADAPTER SUBROUTINES *********************/
/*
@@ -111,120 +105,106 @@ wv_struct_check(void)
/*
* Read from card's Host Adaptor Status Register.
*/
-static inline u_short
-hasr_read(u_long ioaddr)
+static inline u16 hasr_read(unsigned long ioaddr)
{
- return(inw(HASR(ioaddr)));
-} /* hasr_read */
+ return (inw(HASR(ioaddr)));
+} /* hasr_read */
/*------------------------------------------------------------------*/
/*
* Write to card's Host Adapter Command Register.
*/
-static inline void
-hacr_write(u_long ioaddr,
- u_short hacr)
+static inline void hacr_write(unsigned long ioaddr, u16 hacr)
{
- outw(hacr, HACR(ioaddr));
-} /* hacr_write */
+ outw(hacr, HACR(ioaddr));
+} /* hacr_write */
/*------------------------------------------------------------------*/
/*
* Write to card's Host Adapter Command Register. Include a delay for
* those times when it is needed.
*/
-static inline void
-hacr_write_slow(u_long ioaddr,
- u_short hacr)
+static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr)
{
- hacr_write(ioaddr, hacr);
- /* delay might only be needed sometimes */
- mdelay(1);
-} /* hacr_write_slow */
+ hacr_write(ioaddr, hacr);
+ /* delay might only be needed sometimes */
+ mdelay(1);
+} /* hacr_write_slow */
/*------------------------------------------------------------------*/
/*
* Set the channel attention bit.
*/
-static inline void
-set_chan_attn(u_long ioaddr,
- u_short hacr)
+static inline void set_chan_attn(unsigned long ioaddr, u16 hacr)
{
- hacr_write(ioaddr, hacr | HACR_CA);
-} /* set_chan_attn */
+ hacr_write(ioaddr, hacr | HACR_CA);
+} /* set_chan_attn */
/*------------------------------------------------------------------*/
/*
* Reset, and then set host adaptor into default mode.
*/
-static inline void
-wv_hacr_reset(u_long ioaddr)
+static inline void wv_hacr_reset(unsigned long ioaddr)
{
- hacr_write_slow(ioaddr, HACR_RESET);
- hacr_write(ioaddr, HACR_DEFAULT);
-} /* wv_hacr_reset */
+ hacr_write_slow(ioaddr, HACR_RESET);
+ hacr_write(ioaddr, HACR_DEFAULT);
+} /* wv_hacr_reset */
/*------------------------------------------------------------------*/
/*
* Set the I/O transfer over the ISA bus to 8-bit mode
*/
-static inline void
-wv_16_off(u_long ioaddr,
- u_short hacr)
+static inline void wv_16_off(unsigned long ioaddr, u16 hacr)
{
- hacr &= ~HACR_16BITS;
- hacr_write(ioaddr, hacr);
-} /* wv_16_off */
+ hacr &= ~HACR_16BITS;
+ hacr_write(ioaddr, hacr);
+} /* wv_16_off */
/*------------------------------------------------------------------*/
/*
* Set the I/O transfer over the ISA bus to 8-bit mode
*/
-static inline void
-wv_16_on(u_long ioaddr,
- u_short hacr)
+static inline void wv_16_on(unsigned long ioaddr, u16 hacr)
{
- hacr |= HACR_16BITS;
- hacr_write(ioaddr, hacr);
-} /* wv_16_on */
+ hacr |= HACR_16BITS;
+ hacr_write(ioaddr, hacr);
+} /* wv_16_on */
/*------------------------------------------------------------------*/
/*
* Disable interrupts on the WaveLAN hardware.
*/
-static inline void
-wv_ints_off(device * dev)
+static inline void wv_ints_off(device * dev)
{
- net_local * lp = (net_local *)dev->priv;
- u_long ioaddr = dev->base_addr;
- u_long x;
-
- x = wv_splhi();
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ unsigned long flags;
- lp->hacr &= ~HACR_INTRON;
- hacr_write(ioaddr, lp->hacr);
+ save_flags(flags);
+ cli();
+
+ lp->hacr &= ~HACR_INTRON;
+ hacr_write(ioaddr, lp->hacr);
- wv_splx(x);
-} /* wv_ints_off */
+ restore_flags(flags);
+} /* wv_ints_off */
/*------------------------------------------------------------------*/
/*
* Enable interrupts on the WaveLAN hardware.
*/
-static inline void
-wv_ints_on(device * dev)
+static inline void wv_ints_on(device * dev)
{
- net_local * lp = (net_local *)dev->priv;
- u_long ioaddr = dev->base_addr;
- u_long x;
-
- x = wv_splhi();
-
- lp->hacr |= HACR_INTRON;
- hacr_write(ioaddr, lp->hacr);
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ unsigned long flags;
- wv_splx(x);
-} /* wv_ints_on */
+ save_flags(flags);
+ cli();
+ lp->hacr |= HACR_INTRON;
+ hacr_write(ioaddr, lp->hacr);
+ restore_flags(flags);
+} /* wv_ints_on */
/******************* MODEM MANAGEMENT SUBROUTINES *******************/
/*
@@ -238,57 +218,48 @@ wv_ints_on(device * dev)
/*
* Read bytes from the PSA.
*/
-static void
-psa_read(u_long ioaddr,
- u_short hacr,
- int o, /* offset in PSA */
- u_char * b, /* buffer to fill */
- int n) /* size to read */
-{
- wv_16_off(ioaddr, hacr);
-
- while(n-- > 0)
- {
- outw(o, PIOR2(ioaddr));
- o++;
- *b++ = inb(PIOP2(ioaddr));
- }
+static void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */
+ u8 * b, /* buffer to fill */
+ int n)
+{ /* size to read */
+ wv_16_off(ioaddr, hacr);
+
+ while (n-- > 0) {
+ outw(o, PIOR2(ioaddr));
+ o++;
+ *b++ = inb(PIOP2(ioaddr));
+ }
- wv_16_on(ioaddr, hacr);
-} /* psa_read */
+ wv_16_on(ioaddr, hacr);
+} /* psa_read */
/*------------------------------------------------------------------*/
/*
* Write the Parameter Storage Area to the WaveLAN card's memory.
*/
-static void
-psa_write(u_long ioaddr,
- u_short hacr,
- int o, /* Offset in PSA */
- u_char * b, /* Buffer in memory */
- int n) /* Length of buffer */
-{
- int count = 0;
+static void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */
+ u8 * b, /* Buffer in memory */
+ int n)
+{ /* Length of buffer */
+ int count = 0;
- wv_16_off(ioaddr, hacr);
+ wv_16_off(ioaddr, hacr);
- while(n-- > 0)
- {
- outw(o, PIOR2(ioaddr));
- o++;
+ while (n-- > 0) {
+ outw(o, PIOR2(ioaddr));
+ o++;
- outb(*b, PIOP2(ioaddr));
- b++;
+ outb(*b, PIOP2(ioaddr));
+ b++;
- /* Wait for the memory to finish its write cycle */
- count = 0;
- while((count++ < 100) &&
- (hasr_read(ioaddr) & HASR_PSA_BUSY))
- mdelay(1);
- }
+ /* Wait for the memory to finish its write cycle */
+ count = 0;
+ while ((count++ < 100) &&
+ (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1);
+ }
- wv_16_on(ioaddr, hacr);
-} /* psa_write */
+ wv_16_on(ioaddr, hacr);
+} /* psa_write */
#ifdef SET_PSA_CRC
/*------------------------------------------------------------------*/
@@ -301,88 +272,80 @@ psa_write(u_long ioaddr,
* The Windows drivers don't use the CRC, but the AP and the PtP tool
* depend on it.
*/
-static inline u_short
-psa_crc(u_char * psa, /* The PSA */
- int size) /* Number of short for CRC */
-{
- int byte_cnt; /* Loop on the PSA */
- u_short crc_bytes = 0; /* Data in the PSA */
- int bit_cnt; /* Loop on the bits of the short */
-
- for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )
- {
- crc_bytes ^= psa[byte_cnt]; /* Its an xor */
-
- for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )
- {
- if(crc_bytes & 0x0001)
- crc_bytes = (crc_bytes >> 1) ^ 0xA001;
- else
- crc_bytes >>= 1 ;
- }
- }
+static inline u16 psa_crc(u8 * psa, /* The PSA */
+ int size)
+{ /* Number of short for CRC */
+ int byte_cnt; /* Loop on the PSA */
+ u16 crc_bytes = 0; /* Data in the PSA */
+ int bit_cnt; /* Loop on the bits of the short */
+
+ for (byte_cnt = 0; byte_cnt < size; byte_cnt++) {
+ crc_bytes ^= psa[byte_cnt]; /* Its an xor */
+
+ for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) {
+ if (crc_bytes & 0x0001)
+ crc_bytes = (crc_bytes >> 1) ^ 0xA001;
+ else
+ crc_bytes >>= 1;
+ }
+ }
- return crc_bytes;
-} /* psa_crc */
-#endif /* SET_PSA_CRC */
+ return crc_bytes;
+} /* psa_crc */
+#endif /* SET_PSA_CRC */
/*------------------------------------------------------------------*/
/*
* update the checksum field in the Wavelan's PSA
*/
-static void
-update_psa_checksum(device * dev,
- u_long ioaddr,
- u_short hacr)
+static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr)
{
#ifdef SET_PSA_CRC
- psa_t psa;
- u_short crc;
+ psa_t psa;
+ u16 crc;
- /* read the parameter storage area */
- psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa));
+ /* read the parameter storage area */
+ psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa));
- /* update the checksum */
- crc = psa_crc((unsigned char *) &psa,
- sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])
- - sizeof(psa.psa_crc_status));
+ /* update the checksum */
+ crc = psa_crc((unsigned char *) &psa,
+ sizeof(psa) - sizeof(psa.psa_crc[0]) -
+ sizeof(psa.psa_crc[1])
+ - sizeof(psa.psa_crc_status));
- psa.psa_crc[0] = crc & 0xFF;
- psa.psa_crc[1] = (crc & 0xFF00) >> 8;
+ psa.psa_crc[0] = crc & 0xFF;
+ psa.psa_crc[1] = (crc & 0xFF00) >> 8;
- /* Write it ! */
- psa_write(ioaddr, hacr, (char *)&psa.psa_crc - (char *)&psa,
- (unsigned char *)&psa.psa_crc, 2);
+ /* Write it ! */
+ psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa,
+ (unsigned char *) &psa.psa_crc, 2);
#ifdef DEBUG_IOCTL_INFO
- printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
- dev->name, psa.psa_crc[0], psa.psa_crc[1]);
+ printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
+ dev->name, psa.psa_crc[0], psa.psa_crc[1]);
- /* Check again (luxury !) */
- crc = psa_crc ((unsigned char *) &psa,
- sizeof(psa) - sizeof(psa.psa_crc_status));
+ /* Check again (luxury !) */
+ crc = psa_crc((unsigned char *) &psa,
+ sizeof(psa) - sizeof(psa.psa_crc_status));
- if(crc != 0)
- printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
-#endif /* DEBUG_IOCTL_INFO */
-#endif /* SET_PSA_CRC */
-} /* update_psa_checksum */
+ if (crc != 0)
+ printk(KERN_WARNING
+ "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n",
+ dev->name);
+#endif /* DEBUG_IOCTL_INFO */
+#endif /* SET_PSA_CRC */
+} /* update_psa_checksum */
/*------------------------------------------------------------------*/
/*
* Write 1 byte to the MMC.
*/
-static inline void
-mmc_out(u_long ioaddr,
- u_short o,
- u_char d)
+static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
{
- /* Wait for MMC to go idle */
- while(inw(HASR(ioaddr)) & HASR_MMC_BUSY)
- ;
+ /* Wait for MMC to go idle */
+ while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
- outw((u_short) (((u_short) d << 8) | (o << 1) | 1),
- MMCR(ioaddr));
+ outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr));
}
/*------------------------------------------------------------------*/
@@ -390,35 +353,27 @@ mmc_out(u_long ioaddr,
* Routine to write bytes to the Modem Management Controller.
* We start at the end because it is the way it should be!
*/
-static inline void
-mmc_write(u_long ioaddr,
- u_char o,
- u_char * b,
- int n)
+static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
{
- o += n;
- b += n;
+ o += n;
+ b += n;
- while(n-- > 0 )
- mmc_out(ioaddr, --o, *(--b));
-} /* mmc_write */
+ while (n-- > 0)
+ mmc_out(ioaddr, --o, *(--b));
+} /* mmc_write */
/*------------------------------------------------------------------*/
/*
* Read a byte from the MMC.
* Optimised version for 1 byte, avoid using memory.
*/
-static inline u_char
-mmc_in(u_long ioaddr,
- u_short o)
+static inline u8 mmc_in(unsigned long ioaddr, u16 o)
{
- while(inw(HASR(ioaddr)) & HASR_MMC_BUSY)
- ;
- outw(o << 1, MMCR(ioaddr));
+ while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+ outw(o << 1, MMCR(ioaddr));
- while(inw(HASR(ioaddr)) & HASR_MMC_BUSY)
- ;
- return (u_char) (inw(MMCR(ioaddr)) >> 8);
+ while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+ return (u8) (inw(MMCR(ioaddr)) >> 8);
}
/*------------------------------------------------------------------*/
@@ -429,33 +384,28 @@ mmc_in(u_long ioaddr,
* (code has just been moved in the above function)
* We start at the end because it is the way it should be!
*/
-static inline void
-mmc_read(u_long ioaddr,
- u_char o,
- u_char * b,
- int n)
+static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n)
{
- o += n;
- b += n;
+ o += n;
+ b += n;
- while(n-- > 0)
- *(--b) = mmc_in(ioaddr, --o);
-} /* mmc_read */
+ while (n-- > 0)
+ *(--b) = mmc_in(ioaddr, --o);
+} /* mmc_read */
/*------------------------------------------------------------------*/
/*
* Get the type of encryption available.
*/
-static inline int
-mmc_encr(u_long ioaddr) /* I/O port of the card */
-{
- int temp;
-
- temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail));
- if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
- return 0;
- else
- return temp;
+static inline int mmc_encr(unsigned long ioaddr)
+{ /* I/O port of the card */
+ int temp;
+
+ temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail));
+ if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
+ return 0;
+ else
+ return temp;
}
/*------------------------------------------------------------------*/
@@ -463,49 +413,47 @@ mmc_encr(u_long ioaddr) /* I/O port of the card */
* Wait for the frequency EEPROM to complete a command.
* I hope this one will be optimally inlined.
*/
-static inline void
-fee_wait(u_long ioaddr, /* I/O port of the card */
- int delay, /* Base delay to wait for */
- int number) /* Number of time to wait */
-{
- int count = 0; /* Wait only a limited time */
-
- while((count++ < number) &&
- (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY))
- udelay(delay);
+static inline void fee_wait(unsigned long ioaddr, /* I/O port of the card */
+ int delay, /* Base delay to wait for */
+ int number)
+{ /* Number of time to wait */
+ int count = 0; /* Wait only a limited time */
+
+ while ((count++ < number) &&
+ (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+ MMR_FEE_STATUS_BUSY)) udelay(delay);
}
/*------------------------------------------------------------------*/
/*
* Read bytes from the Frequency EEPROM (frequency select cards).
*/
-static void
-fee_read(u_long ioaddr, /* I/O port of the card */
- u_short o, /* destination offset */
- u_short * b, /* data buffer */
- int n) /* number of registers */
-{
- b += n; /* Position at the end of the area */
-
- /* Write the address */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
-
- /* Loop on all buffer */
- while(n-- > 0)
- {
- /* Write the read command */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
-
- /* Wait until EEPROM is ready (should be quick). */
- fee_wait(ioaddr, 10, 100);
-
- /* Read the value. */
- *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
- mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
- }
+static void fee_read(unsigned long ioaddr, /* I/O port of the card */
+ u16 o, /* destination offset */
+ u16 * b, /* data buffer */
+ int n)
+{ /* number of registers */
+ b += n; /* Position at the end of the area */
+
+ /* Write the address */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+ /* Loop on all buffer */
+ while (n-- > 0) {
+ /* Write the read command */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+ MMW_FEE_CTRL_READ);
+
+ /* Wait until EEPROM is ready (should be quick). */
+ fee_wait(ioaddr, 10, 100);
+
+ /* Read the value. */
+ *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
+ mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
+ }
}
-#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */
+#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */
/*------------------------------------------------------------------*/
/*
@@ -514,83 +462,82 @@ fee_read(u_long ioaddr, /* I/O port of the card */
* be unprotected and the write enabled.
* Jean II
*/
-static void
-fee_write(u_long ioaddr, /* I/O port of the card */
- u_short o, /* destination offset */
- u_short * b, /* data buffer */
- int n) /* number of registers */
-{
- b += n; /* Position at the end of the area. */
+static void fee_write(unsigned long ioaddr, /* I/O port of the card */
+ u16 o, /* destination offset */
+ u16 * b, /* data buffer */
+ int n)
+{ /* number of registers */
+ b += n; /* Position at the end of the area. */
#ifdef EEPROM_IS_PROTECTED /* disabled */
#ifdef DOESNT_SEEM_TO_WORK /* disabled */
- /* Ask to read the protected register */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
+ /* Ask to read the protected register */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
- fee_wait(ioaddr, 10, 100);
+ fee_wait(ioaddr, 10, 100);
- /* Read the protected register. */
- printk("Protected 2: %02X-%02X\n",
- mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
- mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
-#endif /* DOESNT_SEEM_TO_WORK */
+ /* Read the protected register. */
+ printk("Protected 2: %02X-%02X\n",
+ mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
+ mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
+#endif /* DOESNT_SEEM_TO_WORK */
- /* Enable protected register. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
+ /* Enable protected register. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
- fee_wait(ioaddr, 10, 100);
+ fee_wait(ioaddr, 10, 100);
- /* Unprotect area. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+ /* Unprotect area. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
#ifdef DOESNT_SEEM_TO_WORK /* disabled */
- /* or use: */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
-#endif /* DOESNT_SEEM_TO_WORK */
+ /* or use: */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
+#endif /* DOESNT_SEEM_TO_WORK */
- fee_wait(ioaddr, 10, 100);
-#endif /* EEPROM_IS_PROTECTED */
+ fee_wait(ioaddr, 10, 100);
+#endif /* EEPROM_IS_PROTECTED */
- /* Write enable. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
+ /* Write enable. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
- fee_wait(ioaddr, 10, 100);
+ fee_wait(ioaddr, 10, 100);
- /* Write the EEPROM address. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
+ /* Write the EEPROM address. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
- /* Loop on all buffer */
- while(n-- > 0)
- {
- /* Write the value. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
+ /* Loop on all buffer */
+ while (n-- > 0) {
+ /* Write the value. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
- /* Write the write command. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
+ /* Write the write command. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+ MMW_FEE_CTRL_WRITE);
- /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
- mdelay(10);
- fee_wait(ioaddr, 10, 100);
- }
+ /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
+ mdelay(10);
+ fee_wait(ioaddr, 10, 100);
+ }
- /* Write disable. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
+ /* Write disable. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
- fee_wait(ioaddr, 10, 100);
+ fee_wait(ioaddr, 10, 100);
#ifdef EEPROM_IS_PROTECTED /* disabled */
- /* Reprotect EEPROM. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+ /* Reprotect EEPROM. */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
- fee_wait(ioaddr, 10, 100);
-#endif /* EEPROM_IS_PROTECTED */
+ fee_wait(ioaddr, 10, 100);
+#endif /* EEPROM_IS_PROTECTED */
}
-#endif /* WIRELESS_EXT */
+#endif /* WIRELESS_EXT */
/************************ I82586 SUBROUTINES *************************/
/*
@@ -602,68 +549,61 @@ fee_write(u_long ioaddr, /* I/O port of the card */
* Read bytes from the on-board RAM.
* Why does inlining this function make it fail?
*/
-static /*inline*/ void
-obram_read(u_long ioaddr,
- u_short o,
- u_char * b,
- int n)
+static /*inline */ void obram_read(unsigned long ioaddr,
+ u16 o, u8 * b, int n)
{
- outw(o, PIOR1(ioaddr));
- insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
+ outw(o, PIOR1(ioaddr));
+ insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
}
/*------------------------------------------------------------------*/
/*
* Write bytes to the on-board RAM.
*/
-static inline void
-obram_write(u_long ioaddr,
- u_short o,
- u_char * b,
- int n)
+static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n)
{
- outw(o, PIOR1(ioaddr));
- outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
+ outw(o, PIOR1(ioaddr));
+ outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
}
/*------------------------------------------------------------------*/
/*
* Acknowledge the reading of the status issued by the i82586.
*/
-static void
-wv_ack(device * dev)
+static void wv_ack(device * dev)
{
- net_local * lp = (net_local *)dev->priv;
- u_long ioaddr = dev->base_addr;
- u_short scb_cs;
- int i;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ u16 scb_cs;
+ int i;
- obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
- (unsigned char *) &scb_cs, sizeof(scb_cs));
- scb_cs &= SCB_ST_INT;
+ obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
+ scb_cs &= SCB_ST_INT;
- if(scb_cs == 0)
- return;
+ if (scb_cs == 0)
+ return;
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &scb_cs, sizeof(scb_cs));
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
- set_chan_attn(ioaddr, lp->hacr);
+ set_chan_attn(ioaddr, lp->hacr);
- for(i = 1000; i > 0; i--)
- {
- obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
- if(scb_cs == 0)
- break;
+ for (i = 1000; i > 0; i--) {
+ obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
+ if (scb_cs == 0)
+ break;
- udelay(10);
- }
- udelay(100);
+ udelay(10);
+ }
+ udelay(100);
#ifdef DEBUG_CONFIG_ERROR
- if(i <= 0)
- printk(KERN_INFO "%s: wv_ack(): board not accepting command.\n",
- dev->name);
+ if (i <= 0)
+ printk(KERN_INFO
+ "%s: wv_ack(): board not accepting command.\n",
+ dev->name);
#endif
}
@@ -672,48 +612,45 @@ wv_ack(device * dev)
* Set channel attention bit and busy wait until command has
* completed, then acknowledge completion of the command.
*/
-static inline int
-wv_synchronous_cmd(device * dev,
- const char * str)
+static inline int wv_synchronous_cmd(device * dev, const char *str)
{
- net_local * lp = (net_local *)dev->priv;
- u_long ioaddr = dev->base_addr;
- u_short scb_cmd;
- ach_t cb;
- int i;
-
- scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO;
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &scb_cmd, sizeof(scb_cmd));
-
- set_chan_attn(ioaddr, lp->hacr);
-
- for (i = 1000; i > 0; i--)
- {
- obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
- if (cb.ac_status & AC_SFLD_C)
- break;
-
- udelay(10);
- }
- udelay(100);
-
- if(i <= 0 || !(cb.ac_status & AC_SFLD_OK))
- {
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ u16 scb_cmd;
+ ach_t cb;
+ int i;
+
+ scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO;
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cmd, sizeof(scb_cmd));
+
+ set_chan_attn(ioaddr, lp->hacr);
+
+ for (i = 1000; i > 0; i--) {
+ obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb,
+ sizeof(cb));
+ if (cb.ac_status & AC_SFLD_C)
+ break;
+
+ udelay(10);
+ }
+ udelay(100);
+
+ if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: %s failed; status = 0x%x\n",
- dev->name, str, cb.ac_status);
+ printk(KERN_INFO "%s: %s failed; status = 0x%x\n",
+ dev->name, str, cb.ac_status);
#endif
#ifdef DEBUG_I82586_SHOW
- wv_scb_show(ioaddr);
+ wv_scb_show(ioaddr);
#endif
- return -1;
- }
+ return -1;
+ }
- /* Ack the status */
- wv_ack(dev);
+ /* Ack the status */
+ wv_ack(dev);
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -722,60 +659,64 @@ wv_synchronous_cmd(device * dev,
* Check if done, and if OK.
*/
static inline int
-wv_config_complete(device * dev,
- u_long ioaddr,
- net_local * lp)
+wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp)
{
- unsigned short mcs_addr;
- unsigned short status;
- int ret;
+ unsigned short mcs_addr;
+ unsigned short status;
+ int ret;
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);
#endif
- mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
- + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
+ mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
+ + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
- /* Read the status of the last command (set mc list). */
- obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status));
+ /* Read the status of the last command (set mc list). */
+ obram_read(ioaddr, acoff(mcs_addr, ac_status),
+ (unsigned char *) &status, sizeof(status));
- /* If not completed -> exit */
- if((status & AC_SFLD_C) == 0)
- ret = 0; /* Not ready to be scrapped */
- else
- {
+ /* If not completed -> exit */
+ if ((status & AC_SFLD_C) == 0)
+ ret = 0; /* Not ready to be scrapped */
+ else {
#ifdef DEBUG_CONFIG_ERROR
- unsigned short cfg_addr;
- unsigned short ias_addr;
-
- /* Check mc_config command */
- if((status & AC_SFLD_OK) != AC_SFLD_OK)
- printk(KERN_INFO "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
- dev->name, status);
-
- /* check ia-config command */
- ias_addr = mcs_addr - sizeof(ac_ias_t);
- obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status));
- if((status & AC_SFLD_OK) != AC_SFLD_OK)
- printk(KERN_INFO "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n",
- dev->name, status);
-
- /* Check config command. */
- cfg_addr = ias_addr - sizeof(ac_cfg_t);
- obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
- if((status & AC_SFLD_OK) != AC_SFLD_OK)
- printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n",
- dev->name, status);
-#endif /* DEBUG_CONFIG_ERROR */
-
- ret = 1; /* Ready to be scrapped */
- }
+ unsigned short cfg_addr;
+ unsigned short ias_addr;
+
+ /* Check mc_config command */
+ if ((status & AC_SFLD_OK) != AC_SFLD_OK)
+ printk(KERN_INFO
+ "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
+ dev->name, status);
+
+ /* check ia-config command */
+ ias_addr = mcs_addr - sizeof(ac_ias_t);
+ obram_read(ioaddr, acoff(ias_addr, ac_status),
+ (unsigned char *) &status, sizeof(status));
+ if ((status & AC_SFLD_OK) != AC_SFLD_OK)
+ printk(KERN_INFO
+ "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n",
+ dev->name, status);
+
+ /* Check config command. */
+ cfg_addr = ias_addr - sizeof(ac_cfg_t);
+ obram_read(ioaddr, acoff(cfg_addr, ac_status),
+ (unsigned char *) &status, sizeof(status));
+ if ((status & AC_SFLD_OK) != AC_SFLD_OK)
+ printk(KERN_INFO
+ "%s: wv_config_complete(): configure failed; status = 0x%x\n",
+ dev->name, status);
+#endif /* DEBUG_CONFIG_ERROR */
+
+ ret = 1; /* Ready to be scrapped */
+ }
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, ret);
+ printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name,
+ ret);
#endif
- return ret;
+ return ret;
}
/*------------------------------------------------------------------*/
@@ -783,141 +724,137 @@ wv_config_complete(device * dev,
* Command completion interrupt.
* Reclaim as many freed tx buffers as we can.
*/
-static int
-wv_complete(device * dev,
- u_long ioaddr,
- net_local * lp)
+static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp)
{
- int nreaped = 0;
+ int nreaped = 0;
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);
#endif
- /* Loop on all the transmit buffers */
- while(lp->tx_first_in_use != I82586NULL)
- {
- unsigned short tx_status;
+ /* Loop on all the transmit buffers */
+ while (lp->tx_first_in_use != I82586NULL) {
+ unsigned short tx_status;
- /* Read the first transmit buffer */
- obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
+ /* Read the first transmit buffer */
+ obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status),
+ (unsigned char *) &tx_status,
+ sizeof(tx_status));
- /* If not completed -> exit */
- if((tx_status & AC_SFLD_C) == 0)
- break;
+ /* If not completed -> exit */
+ if ((tx_status & AC_SFLD_C) == 0)
+ break;
- /* Hack for reconfiguration */
- if(tx_status == 0xFFFF)
- if(!wv_config_complete(dev, ioaddr, lp))
- break; /* Not completed */
+ /* Hack for reconfiguration */
+ if (tx_status == 0xFFFF)
+ if (!wv_config_complete(dev, ioaddr, lp))
+ break; /* Not completed */
- /* We now remove this buffer */
- nreaped++;
- --lp->tx_n_in_use;
+ /* We now remove this buffer */
+ nreaped++;
+ --lp->tx_n_in_use;
/*
if (lp->tx_n_in_use > 0)
printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
*/
- /* Was it the last one? */
- if(lp->tx_n_in_use <= 0)
- lp->tx_first_in_use = I82586NULL;
- else
- {
- /* Next one in the chain */
- lp->tx_first_in_use += TXBLOCKZ;
- if(lp->tx_first_in_use >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
- lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ;
- }
-
- /* Hack for reconfiguration */
- if(tx_status == 0xFFFF)
- continue;
-
- /* Now, check status of the finished command */
- if(tx_status & AC_SFLD_OK)
- {
- int ncollisions;
-
- lp->stats.tx_packets++;
- ncollisions = tx_status & AC_SFLD_MAXCOL;
- lp->stats.collisions += ncollisions;
+ /* Was it the last one? */
+ if (lp->tx_n_in_use <= 0)
+ lp->tx_first_in_use = I82586NULL;
+ else {
+ /* Next one in the chain */
+ lp->tx_first_in_use += TXBLOCKZ;
+ if (lp->tx_first_in_use >=
+ OFFSET_CU +
+ NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -=
+ NTXBLOCKS * TXBLOCKZ;
+ }
+
+ /* Hack for reconfiguration */
+ if (tx_status == 0xFFFF)
+ continue;
+
+ /* Now, check status of the finished command */
+ if (tx_status & AC_SFLD_OK) {
+ int ncollisions;
+
+ lp->stats.tx_packets++;
+ ncollisions = tx_status & AC_SFLD_MAXCOL;
+ lp->stats.collisions += ncollisions;
#ifdef DEBUG_TX_INFO
- if(ncollisions > 0)
- printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n",
- dev->name, ncollisions);
+ if (ncollisions > 0)
+ printk(KERN_DEBUG
+ "%s: wv_complete(): tx completed after %d collisions.\n",
+ dev->name, ncollisions);
#endif
- }
- else
- {
- lp->stats.tx_errors++;
- if(tx_status & AC_SFLD_S10)
- {
- lp->stats.tx_carrier_errors++;
+ } else {
+ lp->stats.tx_errors++;
+ if (tx_status & AC_SFLD_S10) {
+ lp->stats.tx_carrier_errors++;
#ifdef DEBUG_TX_FAIL
- printk(KERN_DEBUG "%s: wv_complete(): tx error: no CS.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_complete(): tx error: no CS.\n",
+ dev->name);
#endif
- }
- if(tx_status & AC_SFLD_S9)
- {
- lp->stats.tx_carrier_errors++;
+ }
+ if (tx_status & AC_SFLD_S9) {
+ lp->stats.tx_carrier_errors++;
#ifdef DEBUG_TX_FAIL
- printk(KERN_DEBUG "%s: wv_complete(): tx error: lost CTS.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_complete(): tx error: lost CTS.\n",
+ dev->name);
#endif
- }
- if(tx_status & AC_SFLD_S8)
- {
- lp->stats.tx_fifo_errors++;
+ }
+ if (tx_status & AC_SFLD_S8) {
+ lp->stats.tx_fifo_errors++;
#ifdef DEBUG_TX_FAIL
- printk(KERN_DEBUG "%s: wv_complete(): tx error: slow DMA.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_complete(): tx error: slow DMA.\n",
+ dev->name);
#endif
- }
- if(tx_status & AC_SFLD_S6)
- {
- lp->stats.tx_heartbeat_errors++;
+ }
+ if (tx_status & AC_SFLD_S6) {
+ lp->stats.tx_heartbeat_errors++;
#ifdef DEBUG_TX_FAIL
- printk(KERN_DEBUG "%s: wv_complete(): tx error: heart beat.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_complete(): tx error: heart beat.\n",
+ dev->name);
#endif
- }
- if(tx_status & AC_SFLD_S5)
- {
- lp->stats.tx_aborted_errors++;
+ }
+ if (tx_status & AC_SFLD_S5) {
+ lp->stats.tx_aborted_errors++;
#ifdef DEBUG_TX_FAIL
- printk(KERN_DEBUG "%s: wv_complete(): tx error: too many collisions.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_complete(): tx error: too many collisions.\n",
+ dev->name);
#endif
- }
- }
+ }
+ }
#ifdef DEBUG_TX_INFO
- printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
- dev->name, tx_status);
+ printk(KERN_DEBUG
+ "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
+ dev->name, tx_status);
#endif
- }
+ }
#ifdef DEBUG_INTERRUPT_INFO
- if(nreaped > 1)
- printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", dev->name, nreaped);
+ if (nreaped > 1)
+ printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n",
+ dev->name, nreaped);
#endif
- /*
- * Inform upper layers.
- */
- if(lp->tx_n_in_use < NTXBLOCKS - 1)
- {
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
-
+ /*
+ * Inform upper layers.
+ */
+ if (lp->tx_n_in_use < NTXBLOCKS - 1) {
+ netif_wake_queue(dev);
+ }
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);
#endif
- return nreaped;
+ return nreaped;
}
/*------------------------------------------------------------------*/
@@ -929,22 +866,20 @@ if (lp->tx_n_in_use > 0)
* wavelan_interrupt is not an option), so you may experience
* delays sometimes.
*/
-static inline void
-wv_82586_reconfig(device * dev)
+static inline void wv_82586_reconfig(device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local *lp = (net_local *) dev->priv;
- /* Check if we can do it now ! */
- if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
- {
- lp->reconfig_82586 = 1;
+ /* Check if we can do it now ! */
+ if (!netif_running(dev) && netif_queue_stopped(dev)) {
+ lp->reconfig_82586 = 1;
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (busy = %ld, start = %d)\n",
- dev->name, dev->tbusy, dev->start);
+ printk(KERN_DEBUG
+ "%s: wv_82586_reconfig(): delayed (state = %lX)\n",
+ dev->name, dev->state);
#endif
- }
- else
- wv_82586_config(dev);
+ } else
+ wv_82586_config(dev);
}
/********************* DEBUG & INFO SUBROUTINES *********************/
@@ -958,89 +893,73 @@ wv_82586_reconfig(device * dev)
/*
* Print the formatted contents of the Parameter Storage Area.
*/
-static void
-wv_psa_show(psa_t * p)
+static void wv_psa_show(psa_t * p)
{
- printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
- printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
- p->psa_io_base_addr_1,
- p->psa_io_base_addr_2,
- p->psa_io_base_addr_3,
- p->psa_io_base_addr_4);
- printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
- p->psa_rem_boot_addr_1,
- p->psa_rem_boot_addr_2,
- p->psa_rem_boot_addr_3);
- printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
- printk("psa_int_req_no: %d\n", p->psa_int_req_no);
+ printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
+ printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
+ p->psa_io_base_addr_1,
+ p->psa_io_base_addr_2,
+ p->psa_io_base_addr_3, p->psa_io_base_addr_4);
+ printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
+ p->psa_rem_boot_addr_1,
+ p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3);
+ printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
+ printk("psa_int_req_no: %d\n", p->psa_int_req_no);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
- p->psa_unused0[0],
- p->psa_unused0[1],
- p->psa_unused0[2],
- p->psa_unused0[3],
- p->psa_unused0[4],
- p->psa_unused0[5],
- p->psa_unused0[6]);
-#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_univ_mac_addr[0],
- p->psa_univ_mac_addr[1],
- p->psa_univ_mac_addr[2],
- p->psa_univ_mac_addr[3],
- p->psa_univ_mac_addr[4],
- p->psa_univ_mac_addr[5]);
- printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_local_mac_addr[0],
- p->psa_local_mac_addr[1],
- p->psa_local_mac_addr[2],
- p->psa_local_mac_addr[3],
- p->psa_local_mac_addr[4],
- p->psa_local_mac_addr[5]);
- printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
- printk("psa_comp_number: %d, ", p->psa_comp_number);
- printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
- printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
- p->psa_feature_select);
- printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
- printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
- printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
- printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]);
- printk("psa_nwid_select: %d\n", p->psa_nwid_select);
- printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select);
- printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_encryption_key[0],
- p->psa_encryption_key[1],
- p->psa_encryption_key[2],
- p->psa_encryption_key[3],
- p->psa_encryption_key[4],
- p->psa_encryption_key[5],
- p->psa_encryption_key[6],
- p->psa_encryption_key[7]);
- printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
- printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
- p->psa_call_code[0]);
- printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
- p->psa_call_code[0],
- p->psa_call_code[1],
- p->psa_call_code[2],
- p->psa_call_code[3],
- p->psa_call_code[4],
- p->psa_call_code[5],
- p->psa_call_code[6],
- p->psa_call_code[7]);
+ printk(KERN_DEBUG
+ "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+ p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2],
+ p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5],
+ p->psa_unused0[6]);
+#endif /* DEBUG_SHOW_UNUSED */
+ printk(KERN_DEBUG
+ "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1],
+ p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
+ p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]);
+ printk(KERN_DEBUG
+ "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ p->psa_local_mac_addr[0], p->psa_local_mac_addr[1],
+ p->psa_local_mac_addr[2], p->psa_local_mac_addr[3],
+ p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]);
+ printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
+ p->psa_univ_local_sel);
+ printk("psa_comp_number: %d, ", p->psa_comp_number);
+ printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
+ printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
+ p->psa_feature_select);
+ printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
+ printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
+ printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
+ printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0],
+ p->psa_nwid[1]);
+ printk("psa_nwid_select: %d\n", p->psa_nwid_select);
+ printk(KERN_DEBUG "psa_encryption_select: %d, ",
+ p->psa_encryption_select);
+ printk
+ ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ p->psa_encryption_key[0], p->psa_encryption_key[1],
+ p->psa_encryption_key[2], p->psa_encryption_key[3],
+ p->psa_encryption_key[4], p->psa_encryption_key[5],
+ p->psa_encryption_key[6], p->psa_encryption_key[7]);
+ printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
+ printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
+ p->psa_call_code[0]);
+ printk
+ ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+ p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2],
+ p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5],
+ p->psa_call_code[6], p->psa_call_code[7]);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
- p->psa_reserved[0],
- p->psa_reserved[1],
- p->psa_reserved[2],
- p->psa_reserved[3]);
-#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
- printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
- printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
-} /* wv_psa_show */
-#endif /* DEBUG_PSA_SHOW */
+ printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+ p->psa_reserved[0],
+ p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]);
+#endif /* DEBUG_SHOW_UNUSED */
+ printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
+ printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
+ printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
+} /* wv_psa_show */
+#endif /* DEBUG_PSA_SHOW */
#ifdef DEBUG_MMC_SHOW
/*------------------------------------------------------------------*/
@@ -1048,411 +967,432 @@ wv_psa_show(psa_t * p)
* Print the formatted status of the Modem Management Controller.
* This function needs to be completed.
*/
-static void
-wv_mmc_show(device * dev)
+static void wv_mmc_show(device * dev)
{
- u_long ioaddr = dev->base_addr;
- net_local * lp = (net_local *)dev->priv;
- mmr_t m;
-
- /* Basic check */
- if(hasr_read(ioaddr) & HASR_NO_CLK)
- {
- printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n",
- dev->name);
- return;
- }
-
- /* Read the mmc */
- mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
- mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m));
- mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-
-#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
- /* Don't forget to update statistics */
- lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-#endif /* WIRELESS_EXT */
-
- printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
+ unsigned long ioaddr = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv;
+ mmr_t m;
+
+ /* Basic check */
+ if (hasr_read(ioaddr) & HASR_NO_CLK) {
+ printk(KERN_WARNING
+ "%s: wv_mmc_show: modem not connected\n",
+ dev->name);
+ return;
+ }
+
+ /* Read the mmc */
+ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+ mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m));
+ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+
+#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
+ /* Don't forget to update statistics */
+ lp->wstats.discard.nwid +=
+ (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+#endif /* WIRELESS_EXT */
+
+ printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
- m.mmr_unused0[0],
- m.mmr_unused0[1],
- m.mmr_unused0[2],
- m.mmr_unused0[3],
- m.mmr_unused0[4],
- m.mmr_unused0[5],
- m.mmr_unused0[6],
- m.mmr_unused0[7]);
-#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
- m.mmr_des_avail, m.mmr_des_status);
+ printk(KERN_DEBUG
+ "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+ m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2],
+ m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5],
+ m.mmr_unused0[6], m.mmr_unused0[7]);
+#endif /* DEBUG_SHOW_UNUSED */
+ printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
+ m.mmr_des_avail, m.mmr_des_status);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
- m.mmr_unused1[0],
- m.mmr_unused1[1],
- m.mmr_unused1[2],
- m.mmr_unused1[3],
- m.mmr_unused1[4]);
-#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
- m.mmr_dce_status,
- (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"",
- (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
- "loop test indicated," : "",
- (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "",
- (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
- "jabber timer expired," : "");
- printk(KERN_DEBUG "Dsp ID: %02X\n",
- m.mmr_dsp_id);
+ printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
+ m.mmr_unused1[0],
+ m.mmr_unused1[1],
+ m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]);
+#endif /* DEBUG_SHOW_UNUSED */
+ printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
+ m.mmr_dce_status,
+ (m.
+ mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ?
+ "energy detected," : "",
+ (m.
+ mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
+ "loop test indicated," : "",
+ (m.
+ mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ?
+ "transmitter on," : "",
+ (m.
+ mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
+ "jabber timer expired," : "");
+ printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
- m.mmr_unused2[0],
- m.mmr_unused2[1]);
-#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
- (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
- (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
- printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
- m.mmr_thr_pre_set & MMR_THR_PRE_SET,
- (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below");
- printk(KERN_DEBUG "signal_lvl: %d [%s], ",
- m.mmr_signal_lvl & MMR_SIGNAL_LVL,
- (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg");
- printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL,
- (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update");
- printk("sgnl_qual: 0x%x [%s]\n",
- m.mmr_sgnl_qual & MMR_SGNL_QUAL,
- (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0");
+ printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
+ m.mmr_unused2[0], m.mmr_unused2[1]);
+#endif /* DEBUG_SHOW_UNUSED */
+ printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
+ (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
+ (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
+ printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
+ m.mmr_thr_pre_set & MMR_THR_PRE_SET,
+ (m.
+ mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" :
+ "below");
+ printk(KERN_DEBUG "signal_lvl: %d [%s], ",
+ m.mmr_signal_lvl & MMR_SIGNAL_LVL,
+ (m.
+ mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" :
+ "no new msg");
+ printk("silence_lvl: %d [%s], ",
+ m.mmr_silence_lvl & MMR_SILENCE_LVL,
+ (m.
+ mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" :
+ "no new update");
+ printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
+ (m.
+ mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" :
+ "Antenna 0");
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
-#endif /* DEBUG_SHOW_UNUSED */
-} /* wv_mmc_show */
-#endif /* DEBUG_MMC_SHOW */
+ printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
+#endif /* DEBUG_SHOW_UNUSED */
+} /* wv_mmc_show */
+#endif /* DEBUG_MMC_SHOW */
#ifdef DEBUG_I82586_SHOW
/*------------------------------------------------------------------*/
/*
* Print the last block of the i82586 memory.
*/
-static void
-wv_scb_show(u_long ioaddr)
+static void wv_scb_show(unsigned long ioaddr)
{
- scb_t scb;
-
- obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
-
- printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
-
- printk(KERN_DEBUG "status: ");
- printk("stat 0x%x[%s%s%s%s] ",
- (scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12,
- (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "",
- (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
- (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "",
- (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : "");
- printk("cus 0x%x[%s%s%s] ",
- (scb.scb_status & SCB_ST_CUS) >> 8,
- ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "",
- ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_SUSP) ? "suspended" : "",
- ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_ACTV) ? "active" : "");
- printk("rus 0x%x[%s%s%s%s]\n",
- (scb.scb_status & SCB_ST_RUS) >> 4,
- ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_IDLE) ? "idle" : "",
- ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_SUSP) ? "suspended" : "",
- ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_NRES) ? "no resources" : "",
- ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_RDY) ? "ready" : "");
-
- printk(KERN_DEBUG "command: ");
- printk("ack 0x%x[%s%s%s%s] ",
- (scb.scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12,
- (scb.scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "",
- (scb.scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "",
- (scb.scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "",
- (scb.scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : "");
- printk("cuc 0x%x[%s%s%s%s%s] ",
- (scb.scb_command & SCB_CMD_CUC) >> 8,
- ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_NOP) ? "nop" : "",
- ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_GO) ? "start cbl_offset" : "",
- ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_RES) ? "resume execution" : "",
- ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_SUS) ? "suspend execution" : "",
- ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_ABT) ? "abort execution" : "");
- printk("ruc 0x%x[%s%s%s%s%s]\n",
- (scb.scb_command & SCB_CMD_RUC) >> 4,
- ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_NOP) ? "nop" : "",
- ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_GO) ? "start rfa_offset" : "",
- ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_RES) ? "resume reception" : "",
- ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_SUS) ? "suspend reception" : "",
- ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_ABT) ? "abort reception" : "");
-
- printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset);
- printk("rfa_offset 0x%x\n", scb.scb_rfa_offset);
-
- printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs);
- printk("alnerrs %d ", scb.scb_alnerrs);
- printk("rscerrs %d ", scb.scb_rscerrs);
- printk("ovrnerrs %d\n", scb.scb_ovrnerrs);
+ scb_t scb;
+
+ obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+ sizeof(scb));
+
+ printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
+
+ printk(KERN_DEBUG "status: ");
+ printk("stat 0x%x[%s%s%s%s] ",
+ (scb.
+ scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA |
+ SCB_ST_RNR)) >> 12,
+ (scb.
+ scb_status & SCB_ST_CX) ? "command completion interrupt," :
+ "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
+ (scb.
+ scb_status & SCB_ST_CNA) ? "command unit not active," : "",
+ (scb.
+ scb_status & SCB_ST_RNR) ? "receiving unit not ready," :
+ "");
+ printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8,
+ ((scb.scb_status & SCB_ST_CUS) ==
+ SCB_ST_CUS_IDLE) ? "idle" : "",
+ ((scb.scb_status & SCB_ST_CUS) ==
+ SCB_ST_CUS_SUSP) ? "suspended" : "",
+ ((scb.scb_status & SCB_ST_CUS) ==
+ SCB_ST_CUS_ACTV) ? "active" : "");
+ printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4,
+ ((scb.scb_status & SCB_ST_RUS) ==
+ SCB_ST_RUS_IDLE) ? "idle" : "",
+ ((scb.scb_status & SCB_ST_RUS) ==
+ SCB_ST_RUS_SUSP) ? "suspended" : "",
+ ((scb.scb_status & SCB_ST_RUS) ==
+ SCB_ST_RUS_NRES) ? "no resources" : "",
+ ((scb.scb_status & SCB_ST_RUS) ==
+ SCB_ST_RUS_RDY) ? "ready" : "");
+
+ printk(KERN_DEBUG "command: ");
+ printk("ack 0x%x[%s%s%s%s] ",
+ (scb.
+ scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR |
+ SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12,
+ (scb.
+ scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "",
+ (scb.
+ scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "",
+ (scb.
+ scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "",
+ (scb.
+ scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : "");
+ printk("cuc 0x%x[%s%s%s%s%s] ",
+ (scb.scb_command & SCB_CMD_CUC) >> 8,
+ ((scb.scb_command & SCB_CMD_CUC) ==
+ SCB_CMD_CUC_NOP) ? "nop" : "",
+ ((scb.scb_command & SCB_CMD_CUC) ==
+ SCB_CMD_CUC_GO) ? "start cbl_offset" : "",
+ ((scb.scb_command & SCB_CMD_CUC) ==
+ SCB_CMD_CUC_RES) ? "resume execution" : "",
+ ((scb.scb_command & SCB_CMD_CUC) ==
+ SCB_CMD_CUC_SUS) ? "suspend execution" : "",
+ ((scb.scb_command & SCB_CMD_CUC) ==
+ SCB_CMD_CUC_ABT) ? "abort execution" : "");
+ printk("ruc 0x%x[%s%s%s%s%s]\n",
+ (scb.scb_command & SCB_CMD_RUC) >> 4,
+ ((scb.scb_command & SCB_CMD_RUC) ==
+ SCB_CMD_RUC_NOP) ? "nop" : "",
+ ((scb.scb_command & SCB_CMD_RUC) ==
+ SCB_CMD_RUC_GO) ? "start rfa_offset" : "",
+ ((scb.scb_command & SCB_CMD_RUC) ==
+ SCB_CMD_RUC_RES) ? "resume reception" : "",
+ ((scb.scb_command & SCB_CMD_RUC) ==
+ SCB_CMD_RUC_SUS) ? "suspend reception" : "",
+ ((scb.scb_command & SCB_CMD_RUC) ==
+ SCB_CMD_RUC_ABT) ? "abort reception" : "");
+
+ printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset);
+ printk("rfa_offset 0x%x\n", scb.scb_rfa_offset);
+
+ printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs);
+ printk("alnerrs %d ", scb.scb_alnerrs);
+ printk("rscerrs %d ", scb.scb_rscerrs);
+ printk("ovrnerrs %d\n", scb.scb_ovrnerrs);
}
/*------------------------------------------------------------------*/
/*
* Print the formatted status of the i82586's receive unit.
*/
-static void
-wv_ru_show(device * dev)
+static void wv_ru_show(device * dev)
{
- /* net_local *lp = (net_local *) dev->priv; */
+ /* net_local *lp = (net_local *) dev->priv; */
- printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
- printk(KERN_DEBUG "ru:");
- /*
- * Not implemented yet
- */
- printk("\n");
-} /* wv_ru_show */
+ printk(KERN_DEBUG
+ "##### WaveLAN i82586 receiver unit status: #####\n");
+ printk(KERN_DEBUG "ru:");
+ /*
+ * Not implemented yet
+ */
+ printk("\n");
+} /* wv_ru_show */
/*------------------------------------------------------------------*/
/*
* Display info about one control block of the i82586 memory.
*/
-static void
-wv_cu_show_one(device * dev,
- net_local * lp,
- int i,
- u_short p)
+static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p)
{
- u_long ioaddr;
- ac_tx_t actx;
+ unsigned long ioaddr;
+ ac_tx_t actx;
- ioaddr = dev->base_addr;
+ ioaddr = dev->base_addr;
- printk("%d: 0x%x:", i, p);
+ printk("%d: 0x%x:", i, p);
- obram_read(ioaddr, p, (unsigned char *)&actx, sizeof(actx));
- printk(" status=0x%x,", actx.tx_h.ac_status);
- printk(" command=0x%x,", actx.tx_h.ac_command);
+ obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx));
+ printk(" status=0x%x,", actx.tx_h.ac_status);
+ printk(" command=0x%x,", actx.tx_h.ac_command);
- /*
- {
- tbd_t tbd;
+ /*
+ {
+ tbd_t tbd;
- obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd));
- printk(" tbd_status=0x%x,", tbd.tbd_status);
- }
- */
+ obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd));
+ printk(" tbd_status=0x%x,", tbd.tbd_status);
+ }
+ */
- printk("|");
+ printk("|");
}
/*------------------------------------------------------------------*/
/*
* Print status of the command unit of the i82586.
*/
-static void
-wv_cu_show(device * dev)
+static void wv_cu_show(device * dev)
{
- net_local * lp = (net_local *)dev->priv;
- unsigned int i;
- u_short p;
-
- printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n");
-
- printk(KERN_DEBUG);
- for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++)
- {
- wv_cu_show_one(dev, lp, i, p);
-
- p += TXBLOCKZ;
- if(p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
- p -= NTXBLOCKS * TXBLOCKZ;
- }
- printk("\n");
+ net_local *lp = (net_local *) dev->priv;
+ unsigned int i;
+ u16 p;
+
+ printk(KERN_DEBUG
+ "##### WaveLAN i82586 command unit status: #####\n");
+
+ printk(KERN_DEBUG);
+ for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) {
+ wv_cu_show_one(dev, lp, i, p);
+
+ p += TXBLOCKZ;
+ if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+ p -= NTXBLOCKS * TXBLOCKZ;
+ }
+ printk("\n");
}
-#endif /* DEBUG_I82586_SHOW */
+#endif /* DEBUG_I82586_SHOW */
#ifdef DEBUG_DEVICE_SHOW
/*------------------------------------------------------------------*/
/*
* Print the formatted status of the WaveLAN PCMCIA device driver.
*/
-static void
-wv_dev_show(device * dev)
+static void wv_dev_show(device * dev)
{
- printk(KERN_DEBUG "dev:");
- printk(" start=%d,", dev->start);
- printk(" tbusy=%ld,", dev->tbusy);
- printk(" interrupt=%d,", dev->interrupt);
- printk(" trans_start=%ld,", dev->trans_start);
- printk(" flags=0x%x,", dev->flags);
- printk("\n");
-} /* wv_dev_show */
+ printk(KERN_DEBUG "dev:");
+ printk(" state=%lX,", dev->state);
+ printk(" trans_start=%ld,", dev->trans_start);
+ printk(" flags=0x%x,", dev->flags);
+ printk("\n");
+} /* wv_dev_show */
/*------------------------------------------------------------------*/
/*
* Print the formatted status of the WaveLAN PCMCIA device driver's
* private information.
*/
-static void
-wv_local_show(device * dev)
+static void wv_local_show(device * dev)
{
- net_local *lp;
+ net_local *lp;
- lp = (net_local *)dev->priv;
+ lp = (net_local *) dev->priv;
- printk(KERN_DEBUG "local:");
- printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
- printk(" hacr=0x%x,", lp->hacr);
- printk(" rx_head=0x%x,", lp->rx_head);
- printk(" rx_last=0x%x,", lp->rx_last);
- printk(" tx_first_free=0x%x,", lp->tx_first_free);
- printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use);
- printk("\n");
-} /* wv_local_show */
-#endif /* DEBUG_DEVICE_SHOW */
+ printk(KERN_DEBUG "local:");
+ printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
+ printk(" hacr=0x%x,", lp->hacr);
+ printk(" rx_head=0x%x,", lp->rx_head);
+ printk(" rx_last=0x%x,", lp->rx_last);
+ printk(" tx_first_free=0x%x,", lp->tx_first_free);
+ printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use);
+ printk("\n");
+} /* wv_local_show */
+#endif /* DEBUG_DEVICE_SHOW */
#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
/*------------------------------------------------------------------*/
/*
* Dump packet header (and content if necessary) on the screen
*/
-static inline void
-wv_packet_info(u_char * p, /* Packet to dump */
- int length, /* Length of the packet */
- char * msg1, /* Name of the device */
- char * msg2) /* Name of the function */
-{
- int i;
- int maxi;
-
- printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
- msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
- printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
- msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+static inline void wv_packet_info(u8 * p, /* Packet to dump */
+ int length, /* Length of the packet */
+ char *msg1, /* Name of the device */
+ char *msg2)
+{ /* Name of the function */
+ int i;
+ int maxi;
+
+ printk(KERN_DEBUG
+ "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
+ msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+ printk(KERN_DEBUG
+ "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
+ msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12],
+ p[13]);
#ifdef DEBUG_PACKET_DUMP
- printk(KERN_DEBUG "data=\"");
-
- if((maxi = length) > DEBUG_PACKET_DUMP)
- maxi = DEBUG_PACKET_DUMP;
- for(i = 14; i < maxi; i++)
- if(p[i] >= ' ' && p[i] <= '~')
- printk(" %c", p[i]);
- else
- printk("%02X", p[i]);
- if(maxi < length)
- printk("..");
- printk("\"\n");
- printk(KERN_DEBUG "\n");
-#endif /* DEBUG_PACKET_DUMP */
+ printk(KERN_DEBUG "data=\"");
+
+ if ((maxi = length) > DEBUG_PACKET_DUMP)
+ maxi = DEBUG_PACKET_DUMP;
+ for (i = 14; i < maxi; i++)
+ if (p[i] >= ' ' && p[i] <= '~')
+ printk(" %c", p[i]);
+ else
+ printk("%02X", p[i]);
+ if (maxi < length)
+ printk("..");
+ printk("\"\n");
+ printk(KERN_DEBUG "\n");
+#endif /* DEBUG_PACKET_DUMP */
}
-#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
+#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
/*------------------------------------------------------------------*/
/*
* This is the information which is displayed by the driver at startup.
* There are lots of flags for configuring it to your liking.
*/
-static inline void
-wv_init_info(device * dev)
+static inline void wv_init_info(device * dev)
{
- short ioaddr = dev->base_addr;
- net_local * lp = (net_local *)dev->priv;
- psa_t psa;
- int i;
+ short ioaddr = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv;
+ psa_t psa;
+ int i;
- /* Read the parameter storage area */
- psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
+ /* Read the parameter storage area */
+ psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
#ifdef DEBUG_PSA_SHOW
- wv_psa_show(&psa);
+ wv_psa_show(&psa);
#endif
#ifdef DEBUG_MMC_SHOW
- wv_mmc_show(dev);
+ wv_mmc_show(dev);
#endif
#ifdef DEBUG_I82586_SHOW
- wv_cu_show(dev);
+ wv_cu_show(dev);
#endif
#ifdef DEBUG_BASIC_SHOW
- /* Now, let's go for the basic stuff. */
- printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
- for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
- printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
- printk(", IRQ %d", dev->irq);
-
- /* Print current network ID. */
- if(psa.psa_nwid_select)
- printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
- else
- printk(", nwid off");
-
- /* If 2.00 card */
- if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- {
- unsigned short freq;
-
- /* Ask the EEPROM to read the frequency from the first area. */
- fee_read(ioaddr, 0x00, &freq, 1);
-
- /* Print frequency */
- printk(", 2.00, %ld", (freq >> 6) + 2400L);
-
- /* Hack! */
- if(freq & 0x20)
- printk(".5");
- }
- else
- {
- printk(", PC");
- switch(psa.psa_comp_number)
- {
- case PSA_COMP_PC_AT_915:
- case PSA_COMP_PC_AT_2400:
- printk("-AT");
- break;
- case PSA_COMP_PC_MC_915:
- case PSA_COMP_PC_MC_2400:
- printk("-MC");
- break;
- case PSA_COMP_PCMCIA_915:
- printk("MCIA");
- break;
- default:
- printk("?");
+ /* Now, let's go for the basic stuff. */
+ printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
+ for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+ printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+ printk(", IRQ %d", dev->irq);
+
+ /* Print current network ID. */
+ if (psa.psa_nwid_select)
+ printk(", nwid 0x%02X-%02X", psa.psa_nwid[0],
+ psa.psa_nwid[1]);
+ else
+ printk(", nwid off");
+
+ /* If 2.00 card */
+ if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+ unsigned short freq;
+
+ /* Ask the EEPROM to read the frequency from the first area. */
+ fee_read(ioaddr, 0x00, &freq, 1);
+
+ /* Print frequency */
+ printk(", 2.00, %ld", (freq >> 6) + 2400L);
+
+ /* Hack! */
+ if (freq & 0x20)
+ printk(".5");
+ } else {
+ printk(", PC");
+ switch (psa.psa_comp_number) {
+ case PSA_COMP_PC_AT_915:
+ case PSA_COMP_PC_AT_2400:
+ printk("-AT");
+ break;
+ case PSA_COMP_PC_MC_915:
+ case PSA_COMP_PC_MC_2400:
+ printk("-MC");
+ break;
+ case PSA_COMP_PCMCIA_915:
+ printk("MCIA");
+ break;
+ default:
+ printk("?");
+ }
+ printk(", ");
+ switch (psa.psa_subband) {
+ case PSA_SUBBAND_915:
+ printk("915");
+ break;
+ case PSA_SUBBAND_2425:
+ printk("2425");
+ break;
+ case PSA_SUBBAND_2460:
+ printk("2460");
+ break;
+ case PSA_SUBBAND_2484:
+ printk("2484");
+ break;
+ case PSA_SUBBAND_2430_5:
+ printk("2430.5");
+ break;
+ default:
+ printk("?");
+ }
}
- printk(", ");
- switch (psa.psa_subband)
- {
- case PSA_SUBBAND_915:
- printk("915");
- break;
- case PSA_SUBBAND_2425:
- printk("2425");
- break;
- case PSA_SUBBAND_2460:
- printk("2460");
- break;
- case PSA_SUBBAND_2484:
- printk("2484");
- break;
- case PSA_SUBBAND_2430_5:
- printk("2430.5");
- break;
- default:
- printk("?");
- }
- }
- printk(" MHz\n");
-#endif /* DEBUG_BASIC_SHOW */
+ printk(" MHz\n");
+#endif /* DEBUG_BASIC_SHOW */
#ifdef DEBUG_VERSION_SHOW
- /* Print version information */
- printk(KERN_NOTICE "%s", version);
+ /* Print version information */
+ printk(KERN_NOTICE "%s", version);
#endif
-} /* wv_init_info */
+} /* wv_init_info */
/********************* IOCTL, STATS & RECONFIG *********************/
/*
@@ -1468,14 +1408,13 @@ wv_init_info(device * dev)
* card open or closed.
* Used when the user read /proc/net/dev
*/
-static en_stats *
-wavelan_get_stats(device * dev)
+static en_stats *wavelan_get_stats(device * dev)
{
#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
+ printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
#endif
- return(&((net_local *) dev->priv)->stats);
+ return (&((net_local *) dev->priv)->stats);
}
/*------------------------------------------------------------------*/
@@ -1486,76 +1425,70 @@ wavelan_get_stats(device * dev)
* num_addrs > 0 Multicast mode, receive normal and MC packets,
* and do best-effort filtering.
*/
-static void
-wavelan_set_multicast_list(device * dev)
+static void wavelan_set_multicast_list(device * dev)
{
- net_local * lp = (net_local *) dev->priv;
+ net_local *lp = (net_local *) dev->priv;
#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n",
+ dev->name);
#endif
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
- dev->name, dev->flags, dev->mc_count);
+ printk(KERN_DEBUG
+ "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
+ dev->name, dev->flags, dev->mc_count);
#endif
- /* Are we asking for promiscuous mode,
- * or all multicast addresses (we don't have that!)
- * or too many multicast addresses for the hardware filter? */
- if((dev->flags & IFF_PROMISC) ||
- (dev->flags & IFF_ALLMULTI) ||
- (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES))
- {
- /*
- * Enable promiscuous mode: receive all packets.
- */
- if(!lp->promiscuous)
- {
- lp->promiscuous = 1;
- lp->mc_count = 0;
-
- wv_82586_reconfig(dev);
-
- /* Tell the kernel that we are doing a really bad job. */
- dev->flags |= IFF_PROMISC;
- }
- }
- else
- /* Are there multicast addresses to send? */
- if(dev->mc_list != (struct dev_mc_list *) NULL)
- {
- /*
- * Disable promiscuous mode, but receive all packets
- * in multicast list
- */
+ /* Are we asking for promiscuous mode,
+ * or all multicast addresses (we don't have that!)
+ * or too many multicast addresses for the hardware filter? */
+ if ((dev->flags & IFF_PROMISC) ||
+ (dev->flags & IFF_ALLMULTI) ||
+ (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) {
+ /*
+ * Enable promiscuous mode: receive all packets.
+ */
+ if (!lp->promiscuous) {
+ lp->promiscuous = 1;
+ lp->mc_count = 0;
+
+ wv_82586_reconfig(dev);
+
+ /* Tell the kernel that we are doing a really bad job. */
+ dev->flags |= IFF_PROMISC;
+ }
+ } else
+ /* Are there multicast addresses to send? */
+ if (dev->mc_list != (struct dev_mc_list *) NULL) {
+ /*
+ * Disable promiscuous mode, but receive all packets
+ * in multicast list
+ */
#ifdef MULTICAST_AVOID
- if(lp->promiscuous ||
- (dev->mc_count != lp->mc_count))
+ if (lp->promiscuous || (dev->mc_count != lp->mc_count))
#endif
- {
- lp->promiscuous = 0;
- lp->mc_count = dev->mc_count;
-
- wv_82586_reconfig(dev);
- }
- }
- else
- {
- /*
- * Switch to normal mode: disable promiscuous mode and
- * clear the multicast list.
- */
- if(lp->promiscuous || lp->mc_count == 0)
- {
- lp->promiscuous = 0;
- lp->mc_count = 0;
-
- wv_82586_reconfig(dev);
- }
- }
+ {
+ lp->promiscuous = 0;
+ lp->mc_count = dev->mc_count;
+
+ wv_82586_reconfig(dev);
+ }
+ } else {
+ /*
+ * Switch to normal mode: disable promiscuous mode and
+ * clear the multicast list.
+ */
+ if (lp->promiscuous || lp->mc_count == 0) {
+ lp->promiscuous = 0;
+ lp->mc_count = 0;
+
+ wv_82586_reconfig(dev);
+ }
+ }
#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n",
+ dev->name);
#endif
}
@@ -1565,23 +1498,21 @@ wavelan_set_multicast_list(device * dev)
* (Note : it was a nice way to test the reconfigure stuff...)
*/
#ifdef SET_MAC_ADDRESS
-static int
-wavelan_set_mac_address(device * dev,
- void * addr)
+static int wavelan_set_mac_address(device * dev, void *addr)
{
- struct sockaddr * mac = addr;
+ struct sockaddr *mac = addr;
- /* Copy the address. */
- memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
+ /* Copy the address. */
+ memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
- /* Reconfigure the beast. */
- wv_82586_reconfig(dev);
+ /* Reconfigure the beast. */
+ wv_82586_reconfig(dev);
- return 0;
+ return 0;
}
-#endif /* SET_MAC_ADDRESS */
+#endif /* SET_MAC_ADDRESS */
-#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */
/*------------------------------------------------------------------*/
/*
@@ -1589,232 +1520,215 @@ wavelan_set_mac_address(device * dev,
* It's a bit complicated and you don't really want to look into it.
* (called in wavelan_ioctl)
*/
-static inline int
-wv_set_frequency(u_long ioaddr, /* I/O port of the card */
- iw_freq * frequency)
+static inline int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */
+ iw_freq * frequency)
{
- const int BAND_NUM = 10; /* Number of bands */
- long freq = 0L; /* offset to 2.4 GHz in .5 MHz */
+ const int BAND_NUM = 10; /* Number of bands */
+ long freq = 0L; /* offset to 2.4 GHz in .5 MHz */
#ifdef DEBUG_IOCTL_INFO
- int i;
+ int i;
#endif
- /* Setting by frequency */
- /* Theoretically, you may set any frequency between
- * the two limits with a 0.5 MHz precision. In practice,
- * I don't want you to have trouble with local regulations.
- */
- if((frequency->e == 1) &&
- (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
- {
- freq = ((frequency->m / 10000) - 24000L) / 5;
- }
-
- /* Setting by channel (same as wfreqsel) */
- /* Warning: each channel is 22 MHz wide, so some of the channels
- * will interfere. */
- if((frequency->e == 0) &&
- (frequency->m >= 0) && (frequency->m < BAND_NUM))
- {
- /* Get frequency offset. */
- freq = channel_bands[frequency->m] >> 1;
- }
-
- /* Verify that the frequency is allowed. */
- if(freq != 0L)
- {
- u_short table[10]; /* Authorized frequency table */
-
- /* Read the frequency table. */
- fee_read(ioaddr, 0x71, table, 10);
+ /* Setting by frequency */
+ /* Theoretically, you may set any frequency between
+ * the two limits with a 0.5 MHz precision. In practice,
+ * I don't want you to have trouble with local regulations.
+ */
+ if ((frequency->e == 1) &&
+ (frequency->m >= (int) 2.412e8)
+ && (frequency->m <= (int) 2.487e8)) {
+ freq = ((frequency->m / 10000) - 24000L) / 5;
+ }
-#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "Frequency table: ");
- for(i = 0; i < 10; i++)
- {
- printk(" %04X",
- table[i]);
+ /* Setting by channel (same as wfreqsel) */
+ /* Warning: each channel is 22 MHz wide, so some of the channels
+ * will interfere. */
+ if ((frequency->e == 0) &&
+ (frequency->m >= 0) && (frequency->m < BAND_NUM)) {
+ /* Get frequency offset. */
+ freq = channel_bands[frequency->m] >> 1;
}
- printk("\n");
-#endif
- /* Look in the table to see whether the frequency is allowed. */
- if(!(table[9 - ((freq - 24) / 16)] &
- (1 << ((freq - 24) % 16))))
- return -EINVAL; /* not allowed */
- }
- else
- return -EINVAL;
-
- /* if we get a usable frequency */
- if(freq != 0L)
- {
- unsigned short area[16];
- unsigned short dac[2];
- unsigned short area_verify[16];
- unsigned short dac_verify[2];
- /* Corresponding gain (in the power adjust value table)
- * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
- * and WCIN062D.DOC, page 6.2.9. */
- unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
- int power_band = 0; /* Selected band */
- unsigned short power_adjust; /* Correct value */
-
- /* Search for the gain. */
- power_band = 0;
- while((freq > power_limit[power_band]) &&
- (power_limit[++power_band] != 0))
- ;
-
- /* Read the first area. */
- fee_read(ioaddr, 0x00, area, 16);
-
- /* Read the DAC. */
- fee_read(ioaddr, 0x60, dac, 2);
-
- /* Read the new power adjust value. */
- fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1);
- if(power_band & 0x1)
- power_adjust >>= 8;
- else
- power_adjust &= 0xFF;
+ /* Verify that the frequency is allowed. */
+ if (freq != 0L) {
+ u16 table[10]; /* Authorized frequency table */
+
+ /* Read the frequency table. */
+ fee_read(ioaddr, 0x71, table, 10);
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
- for(i = 0; i < 16; i++)
- {
- printk(" %04X",
- area[i]);
- }
- printk("\n");
+ printk(KERN_DEBUG "Frequency table: ");
+ for (i = 0; i < 10; i++) {
+ printk(" %04X", table[i]);
+ }
+ printk("\n");
+#endif
- printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
- dac[0], dac[1]);
+ /* Look in the table to see whether the frequency is allowed. */
+ if (!(table[9 - ((freq - 24) / 16)] &
+ (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */
+ } else
+ return -EINVAL;
+
+ /* if we get a usable frequency */
+ if (freq != 0L) {
+ unsigned short area[16];
+ unsigned short dac[2];
+ unsigned short area_verify[16];
+ unsigned short dac_verify[2];
+ /* Corresponding gain (in the power adjust value table)
+ * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
+ * and WCIN062D.DOC, page 6.2.9. */
+ unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
+ int power_band = 0; /* Selected band */
+ unsigned short power_adjust; /* Correct value */
+
+ /* Search for the gain. */
+ power_band = 0;
+ while ((freq > power_limit[power_band]) &&
+ (power_limit[++power_band] != 0));
+
+ /* Read the first area. */
+ fee_read(ioaddr, 0x00, area, 16);
+
+ /* Read the DAC. */
+ fee_read(ioaddr, 0x60, dac, 2);
+
+ /* Read the new power adjust value. */
+ fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust,
+ 1);
+ if (power_band & 0x1)
+ power_adjust >>= 8;
+ else
+ power_adjust &= 0xFF;
+
+#ifdef DEBUG_IOCTL_INFO
+ printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
+ for (i = 0; i < 16; i++) {
+ printk(" %04X", area[i]);
+ }
+ printk("\n");
+
+ printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
+ dac[0], dac[1]);
#endif
- /* Frequency offset (for info only) */
- area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
+ /* Frequency offset (for info only) */
+ area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
- /* Receiver Principle main divider coefficient */
- area[3] = (freq >> 1) + 2400L - 352L;
- area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+ /* Receiver Principle main divider coefficient */
+ area[3] = (freq >> 1) + 2400L - 352L;
+ area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
- /* Transmitter Main divider coefficient */
- area[13] = (freq >> 1) + 2400L;
- area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+ /* Transmitter Main divider coefficient */
+ area[13] = (freq >> 1) + 2400L;
+ area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
- /* Other parts of the area are flags, bit streams or unused. */
+ /* Other parts of the area are flags, bit streams or unused. */
- /* Set the value in the DAC. */
- dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
- dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
+ /* Set the value in the DAC. */
+ dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
+ dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
- /* Write the first area. */
- fee_write(ioaddr, 0x00,
- area, 16);
+ /* Write the first area. */
+ fee_write(ioaddr, 0x00, area, 16);
- /* Write the DAC. */
- fee_write(ioaddr, 0x60,
- dac, 2);
+ /* Write the DAC. */
+ fee_write(ioaddr, 0x60, dac, 2);
- /* We now should verify here that the writing of the EEPROM went OK. */
+ /* We now should verify here that the writing of the EEPROM went OK. */
- /* Reread the first area. */
- fee_read(ioaddr, 0x00, area_verify, 16);
+ /* Reread the first area. */
+ fee_read(ioaddr, 0x00, area_verify, 16);
- /* Reread the DAC. */
- fee_read(ioaddr, 0x60, dac_verify, 2);
+ /* Reread the DAC. */
+ fee_read(ioaddr, 0x60, dac_verify, 2);
- /* Compare. */
- if(memcmp(area, area_verify, 16 * 2) ||
- memcmp(dac, dac_verify, 2 * 2))
- {
+ /* Compare. */
+ if (memcmp(area, area_verify, 16 * 2) ||
+ memcmp(dac, dac_verify, 2 * 2)) {
#ifdef DEBUG_IOCTL_ERROR
- printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
+ printk(KERN_INFO
+ "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
#endif
- return -EOPNOTSUPP;
- }
+ return -EOPNOTSUPP;
+ }
- /* We must download the frequency parameters to the
- * synthesizers (from the EEPROM - area 1)
- * Note: as the EEPROM is automatically decremented, we set the end
- * if the area... */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
- MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+ /* We must download the frequency parameters to the
+ * synthesizers (from the EEPROM - area 1)
+ * Note: as the EEPROM is automatically decremented, we set the end
+ * if the area... */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+ MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
- /* Wait until the download is finished. */
- fee_wait(ioaddr, 100, 100);
+ /* Wait until the download is finished. */
+ fee_wait(ioaddr, 100, 100);
- /* We must now download the power adjust value (gain) to
- * the synthesizers (from the EEPROM - area 7 - DAC). */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
- mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
- MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+ /* We must now download the power adjust value (gain) to
+ * the synthesizers (from the EEPROM - area 7 - DAC). */
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
+ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+ MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
- /* Wait for the download to finish. */
- fee_wait(ioaddr, 100, 100);
+ /* Wait for the download to finish. */
+ fee_wait(ioaddr, 100, 100);
#ifdef DEBUG_IOCTL_INFO
- /* Verification of what we have done */
+ /* Verification of what we have done */
- printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
- for(i = 0; i < 16; i++)
- {
- printk(" %04X",
- area_verify[i]);
- }
- printk("\n");
+ printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
+ for (i = 0; i < 16; i++) {
+ printk(" %04X", area_verify[i]);
+ }
+ printk("\n");
- printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
- dac_verify[0], dac_verify[1]);
+ printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
+ dac_verify[0], dac_verify[1]);
#endif
- return 0;
- }
- else
- return -EINVAL; /* Bah, never get there... */
+ return 0;
+ } else
+ return -EINVAL; /* Bah, never get there... */
}
/*------------------------------------------------------------------*/
/*
* Give the list of available frequencies.
*/
-static inline int
-wv_frequency_list(u_long ioaddr, /* I/O port of the card */
- iw_freq * list, /* List of frequencies to fill */
- int max) /* Maximum number of frequencies */
-{
- u_short table[10]; /* Authorized frequency table */
- long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */
- int i; /* index in the table */
- int c = 0; /* Channel number */
-
- /* Read the frequency table. */
- fee_read(ioaddr, 0x71 /* frequency table */, table, 10);
-
- /* Check all frequencies. */
- i = 0;
- for(freq = 0; freq < 150; freq++)
- /* Look in the table if the frequency is allowed */
- if(table[9 - (freq / 16)] & (1 << (freq % 16)))
- {
- /* Compute approximate channel number */
- while((((channel_bands[c] >> 1) - 24) < freq) &&
- (c < NELS(channel_bands)))
- c++;
- list[i].i = c; /* Set the list index */
-
- /* put in the list */
- list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
- list[i++].e = 1;
-
- /* Check number. */
- if(i >= max)
- return(i);
- }
-
- return(i);
+static inline int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */
+ iw_freq * list, /* List of frequencies to fill */
+ int max)
+{ /* Maximum number of frequencies */
+ u16 table[10]; /* Authorized frequency table */
+ long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */
+ int i; /* index in the table */
+ int c = 0; /* Channel number */
+
+ /* Read the frequency table. */
+ fee_read(ioaddr, 0x71 /* frequency table */ , table, 10);
+
+ /* Check all frequencies. */
+ i = 0;
+ for (freq = 0; freq < 150; freq++)
+ /* Look in the table if the frequency is allowed */
+ if (table[9 - (freq / 16)] & (1 << (freq % 16))) {
+ /* Compute approximate channel number */
+ while ((((channel_bands[c] >> 1) - 24) < freq) &&
+ (c < NELS(channel_bands)))
+ c++;
+ list[i].i = c; /* Set the list index */
+
+ /* put in the list */
+ list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
+ list[i++].e = 1;
+
+ /* Check number. */
+ if (i >= max)
+ return (i);
+ }
+
+ return (i);
}
#ifdef WIRELESS_SPY
@@ -1824,27 +1738,24 @@ wv_frequency_list(u_long ioaddr, /* I/O port of the card */
* address with our list, and if they match, get the statistics.
* Sorry, but this function really needs the wireless extensions.
*/
-static inline void
-wl_spy_gather(device * dev,
- u_char * mac, /* MAC address */
- u_char * stats) /* Statistics to gather */
-{
- net_local * lp = (net_local *) dev->priv;
- int i;
-
- /* Check all addresses. */
- for(i = 0; i < lp->spy_number; i++)
- /* If match */
- if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
- {
- /* Update statistics */
- lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
- lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
- lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
- lp->spy_stat[i].updated = 0x7;
- }
+static inline void wl_spy_gather(device * dev, u8 * mac, /* MAC address */
+ u8 * stats)
+{ /* Statistics to gather */
+ net_local *lp = (net_local *) dev->priv;
+ int i;
+
+ /* Check all addresses. */
+ for (i = 0; i < lp->spy_number; i++)
+ /* If match */
+ if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) {
+ /* Update statistics */
+ lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
+ lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
+ lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
+ lp->spy_stat[i].updated = 0x7;
+ }
}
-#endif /* WIRELESS_SPY */
+#endif /* WIRELESS_SPY */
#ifdef HISTOGRAM
/*------------------------------------------------------------------*/
@@ -1856,494 +1767,516 @@ wl_spy_gather(device * dev,
* With this histogram you may detect if one WaveLAN is really weak,
* or you may also calculate the mean and standard deviation of the level.
*/
-static inline void
-wl_his_gather(device * dev,
- u_char * stats) /* Statistics to gather */
-{
- net_local * lp = (net_local *) dev->priv;
- u_char level = stats[0] & MMR_SIGNAL_LVL;
- int i;
-
- /* Find the correct interval. */
- i = 0;
- while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
- ;
-
- /* Increment interval counter. */
- (lp->his_sum[i])++;
+static inline void wl_his_gather(device * dev, u8 * stats)
+{ /* Statistics to gather */
+ net_local *lp = (net_local *) dev->priv;
+ u8 level = stats[0] & MMR_SIGNAL_LVL;
+ int i;
+
+ /* Find the correct interval. */
+ i = 0;
+ while ((i < (lp->his_number - 1))
+ && (level >= lp->his_range[i++]));
+
+ /* Increment interval counter. */
+ (lp->his_sum[i])++;
}
-#endif /* HISTOGRAM */
+#endif /* HISTOGRAM */
/*------------------------------------------------------------------*/
/*
* Perform ioctl for configuration and information.
* It is here that the wireless extensions are treated (iwconfig).
*/
-static int
-wavelan_ioctl(struct net_device * dev, /* device on which the ioctl is applied */
- struct ifreq * rq, /* data passed */
- int cmd) /* ioctl number */
-{
- u_long ioaddr = dev->base_addr;
- net_local * lp = (net_local *)dev->priv; /* lp is not unused */
- struct iwreq * wrq = (struct iwreq *) rq;
- psa_t psa;
- mm_t m;
- unsigned long x;
- int ret = 0;
+static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */
+ struct ifreq *rq, /* data passed */
+ int cmd)
+{ /* ioctl number */
+ unsigned long ioaddr = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ struct iwreq *wrq = (struct iwreq *) rq;
+ psa_t psa;
+ mm_t m;
+ unsigned long flags;
+ int ret = 0;
#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
+ printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
+ cmd);
#endif
- /* Disable interrupts and save flags. */
- x = wv_splhi();
-
- /* Look what is the request */
- switch(cmd)
- {
- /* --------------- WIRELESS EXTENSIONS --------------- */
-
- case SIOCGIWNAME:
- strcpy(wrq->u.name, "WaveLAN");
- break;
-
- case SIOCSIWNWID:
- /* Set NWID in WaveLAN. */
- if(!wrq->u.nwid.disabled)
- {
- /* Set NWID in psa */
- psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
- psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
- psa.psa_nwid_select = 0x01;
- psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
- (unsigned char *)psa.psa_nwid, 3);
-
- /* Set NWID in mmc. */
- m.w.mmw_netw_id_l = psa.psa_nwid[1];
- m.w.mmw_netw_id_h = psa.psa_nwid[0];
- mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
- (unsigned char *)&m.w.mmw_netw_id_l, 2);
- mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
- }
- else
- {
- /* Disable NWID in the psa. */
- psa.psa_nwid_select = 0x00;
- psa_write(ioaddr, lp->hacr,
- (char *)&psa.psa_nwid_select - (char *)&psa,
- (unsigned char *)&psa.psa_nwid_select, 1);
-
- /* Disable NWID in the mmc (no filtering). */
- mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
- }
- /* update the Wavelan checksum */
- update_psa_checksum(dev, ioaddr, lp->hacr);
- break;
-
- case SIOCGIWNWID:
- /* Read the NWID. */
- psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
- (unsigned char *)psa.psa_nwid, 3);
- wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
- wrq->u.nwid.disabled = !(psa.psa_nwid_select);
- wrq->u.nwid.fixed = 1; /* Superfluous */
- break;
-
- case SIOCSIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
- if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
- else
- ret = -EOPNOTSUPP;
- break;
-
- case SIOCGIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
- * Does it work for everybody, especially old cards? */
- if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- {
- unsigned short freq;
-
- /* Ask the EEPROM to read the frequency from the first area. */
- fee_read(ioaddr, 0x00, &freq, 1);
- wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
- wrq->u.freq.e = 1;
- }
- else
- {
- psa_read(ioaddr, lp->hacr, (char *)&psa.psa_subband - (char *)&psa,
- (unsigned char *)&psa.psa_subband, 1);
-
- if(psa.psa_subband <= 4)
- {
- wrq->u.freq.m = fixed_bands[psa.psa_subband];
- wrq->u.freq.e = (psa.psa_subband != 0);
- }
- else
- ret = -EOPNOTSUPP;
- }
- break;
-
- case SIOCSIWSENS:
- /* Set the level threshold. */
- /* We should complain loudly if wrq->u.sens.fixed = 0, because we
- * can't set auto mode... */
- psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
- psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
- (unsigned char *) &psa.psa_thr_pre_set, 1);
- /* update the Wavelan checksum */
- update_psa_checksum(dev, ioaddr, lp->hacr);
- mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
- break;
-
- case SIOCGIWSENS:
- /* Read the level threshold. */
- psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
- (unsigned char *) &psa.psa_thr_pre_set, 1);
- wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
- wrq->u.sens.fixed = 1;
- break;
-
- case SIOCSIWENCODE:
- /* Set encryption key */
- if(!mmc_encr(ioaddr))
- {
- ret = -EOPNOTSUPP;
- break;
- }
-
- /* Basic checking... */
- if(wrq->u.encoding.pointer != (caddr_t) 0)
- {
- /* Check the size of the key */
- if(wrq->u.encoding.length != 8)
- {
- ret = -EINVAL;
- break;
- }
-
- /* Copy the key in the driver */
- if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
- wrq->u.encoding.length))
- {
- ret = -EFAULT;
- break;
- }
-
- psa.psa_encryption_select = 1;
- psa_write(ioaddr, lp->hacr,
- (char *) &psa.psa_encryption_select - (char *) &psa,
- (unsigned char *) &psa.psa_encryption_select, 8+1);
-
- mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
- MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
- mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
- (unsigned char *) &psa.psa_encryption_key, 8);
- }
-
- if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
- { /* disable encryption */
- psa.psa_encryption_select = 0;
- psa_write(ioaddr, lp->hacr,
- (char *) &psa.psa_encryption_select - (char *) &psa,
- (unsigned char *) &psa.psa_encryption_select, 1);
-
- mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
- }
- /* update the Wavelan checksum */
- update_psa_checksum(dev, ioaddr, lp->hacr);
- break;
-
- case SIOCGIWENCODE:
- /* Read the encryption key */
- if(!mmc_encr(ioaddr))
- {
- ret = -EOPNOTSUPP;
- break;
- }
-
- /* only super-user can see encryption key */
- if(!suser())
- {
- ret = -EPERM;
- break;
- }
-
- /* Basic checking... */
- if(wrq->u.encoding.pointer != (caddr_t) 0)
- {
- /* Verify the user buffer */
- ret = verify_area(VERIFY_WRITE, wrq->u.encoding.pointer, 8);
- if(ret)
- break;
-
- psa_read(ioaddr, lp->hacr,
- (char *) &psa.psa_encryption_select - (char *) &psa,
- (unsigned char *) &psa.psa_encryption_select, 1+8);
-
- /* encryption is enabled ? */
- if(psa.psa_encryption_select)
- wrq->u.encoding.flags = IW_ENCODE_ENABLED;
- else
- wrq->u.encoding.flags = IW_ENCODE_DISABLED;
- wrq->u.encoding.flags |= mmc_encr(ioaddr);
-
- /* Copy the key to the user buffer */
- wrq->u.encoding.length = 8;
- if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
- ret = -EFAULT;
- }
- break;
-
- case SIOCGIWRANGE:
- /* basic checking */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- struct iw_range range;
-
- /* Set the length (useless: it's constant). */
- wrq->u.data.length = sizeof(struct iw_range);
-
- /* Set information in the range struct. */
- range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
- range.min_nwid = 0x0000;
- range.max_nwid = 0xFFFF;
-
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
- if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- {
- range.num_channels = 10;
- range.num_frequency = wv_frequency_list(ioaddr, range.freq,
+ /* Disable interrupts and save flags. */
+ save_flags(flags);
+ cli();
+ /* FIXME: can't copy*user when cli this is broken! */
+
+ /* Look what is the request */
+ switch (cmd) {
+ /* --------------- WIRELESS EXTENSIONS --------------- */
+
+ case SIOCGIWNAME:
+ strcpy(wrq->u.name, "WaveLAN");
+ break;
+
+ case SIOCSIWNWID:
+ /* Set NWID in WaveLAN. */
+ if (!wrq->u.nwid.disabled) {
+ /* Set NWID in psa */
+ psa.psa_nwid[0] =
+ (wrq->u.nwid.value & 0xFF00) >> 8;
+ psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
+ psa.psa_nwid_select = 0x01;
+ psa_write(ioaddr, lp->hacr,
+ (char *) psa.psa_nwid - (char *) &psa,
+ (unsigned char *) psa.psa_nwid, 3);
+
+ /* Set NWID in mmc. */
+ m.w.mmw_netw_id_l = psa.psa_nwid[1];
+ m.w.mmw_netw_id_h = psa.psa_nwid[0];
+ mmc_write(ioaddr,
+ (char *) &m.w.mmw_netw_id_l -
+ (char *) &m,
+ (unsigned char *) &m.w.mmw_netw_id_l, 2);
+ mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
+ } else {
+ /* Disable NWID in the psa. */
+ psa.psa_nwid_select = 0x00;
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_nwid_select -
+ (char *) &psa,
+ (unsigned char *) &psa.psa_nwid_select,
+ 1);
+
+ /* Disable NWID in the mmc (no filtering). */
+ mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel),
+ MMW_LOOPT_SEL_DIS_NWID);
+ }
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+ break;
+
+ case SIOCGIWNWID:
+ /* Read the NWID. */
+ psa_read(ioaddr, lp->hacr,
+ (char *) psa.psa_nwid - (char *) &psa,
+ (unsigned char *) psa.psa_nwid, 3);
+ wrq->u.nwid.value =
+ (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+ wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+ wrq->u.nwid.fixed = 1; /* Superfluous */
+ break;
+
+ case SIOCSIWFREQ:
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+ if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+ ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
+ else
+ ret = -EOPNOTSUPP;
+ break;
+
+ case SIOCGIWFREQ:
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+ * Does it work for everybody, especially old cards? */
+ if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+ unsigned short freq;
+
+ /* Ask the EEPROM to read the frequency from the first area. */
+ fee_read(ioaddr, 0x00, &freq, 1);
+ wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
+ wrq->u.freq.e = 1;
+ } else {
+ psa_read(ioaddr, lp->hacr,
+ (char *) &psa.psa_subband - (char *) &psa,
+ (unsigned char *) &psa.psa_subband, 1);
+
+ if (psa.psa_subband <= 4) {
+ wrq->u.freq.m =
+ fixed_bands[psa.psa_subband];
+ wrq->u.freq.e = (psa.psa_subband != 0);
+ } else
+ ret = -EOPNOTSUPP;
+ }
+ break;
+
+ case SIOCSIWSENS:
+ /* Set the level threshold. */
+ /* We should complain loudly if wrq->u.sens.fixed = 0, because we
+ * can't set auto mode... */
+ psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_thr_pre_set - (char *) &psa,
+ (unsigned char *) &psa.psa_thr_pre_set, 1);
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+ mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set),
+ psa.psa_thr_pre_set);
+ break;
+
+ case SIOCGIWSENS:
+ /* Read the level threshold. */
+ psa_read(ioaddr, lp->hacr,
+ (char *) &psa.psa_thr_pre_set - (char *) &psa,
+ (unsigned char *) &psa.psa_thr_pre_set, 1);
+ wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
+ wrq->u.sens.fixed = 1;
+ break;
+
+ case SIOCSIWENCODE:
+ /* Set encryption key */
+ if (!mmc_encr(ioaddr)) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ /* Basic checking... */
+ if (wrq->u.encoding.pointer != (caddr_t) 0) {
+ /* Check the size of the key */
+ if (wrq->u.encoding.length != 8) {
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Copy the key in the driver */
+ if (copy_from_user
+ (psa.psa_encryption_key,
+ wrq->u.encoding.pointer,
+ wrq->u.encoding.length)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ psa.psa_encryption_select = 1;
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_encryption_select -
+ (char *) &psa,
+ (unsigned char *) &psa.
+ psa_encryption_select, 8 + 1);
+
+ mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
+ MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+ mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
+ (unsigned char *) &psa.
+ psa_encryption_key, 8);
+ }
+
+ if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */
+ psa.psa_encryption_select = 0;
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_encryption_select -
+ (char *) &psa,
+ (unsigned char *) &psa.
+ psa_encryption_select, 1);
+
+ mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
+ }
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+ break;
+
+ case SIOCGIWENCODE:
+ /* Read the encryption key */
+ if (!mmc_encr(ioaddr)) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ /* only super-user can see encryption key */
+ if (!suser()) {
+ ret = -EPERM;
+ break;
+ }
+
+ /* Basic checking... */
+ if (wrq->u.encoding.pointer != (caddr_t) 0) {
+ /* Verify the user buffer */
+ ret =
+ verify_area(VERIFY_WRITE,
+ wrq->u.encoding.pointer, 8);
+ if (ret)
+ break;
+
+ psa_read(ioaddr, lp->hacr,
+ (char *) &psa.psa_encryption_select -
+ (char *) &psa,
+ (unsigned char *) &psa.
+ psa_encryption_select, 1 + 8);
+
+ /* encryption is enabled ? */
+ if (psa.psa_encryption_select)
+ wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+ else
+ wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+ wrq->u.encoding.flags |= mmc_encr(ioaddr);
+
+ /* Copy the key to the user buffer */
+ wrq->u.encoding.length = 8;
+ if (copy_to_user
+ (wrq->u.encoding.pointer,
+ psa.psa_encryption_key, 8)) ret = -EFAULT;
+ }
+ break;
+
+ case SIOCGIWRANGE:
+ /* basic checking */
+ if (wrq->u.data.pointer != (caddr_t) 0) {
+ struct iw_range range;
+
+ /* Set the length (useless: it's constant). */
+ wrq->u.data.length = sizeof(struct iw_range);
+
+ /* Set information in the range struct. */
+ range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
+ range.min_nwid = 0x0000;
+ range.max_nwid = 0xFFFF;
+
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+ if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+ range.num_channels = 10;
+ range.num_frequency =
+ wv_frequency_list(ioaddr, range.freq,
IW_MAX_FREQUENCIES);
- }
- else
- range.num_channels = range.num_frequency = 0;
-
- range.sensitivity = 0x3F;
- range.max_qual.qual = MMR_SGNL_QUAL;
- range.max_qual.level = MMR_SIGNAL_LVL;
- range.max_qual.noise = MMR_SILENCE_LVL;
-
- range.num_bitrates = 1;
- range.bitrate[0] = 2000000; /* 2 Mb/s */
-
- /* Encryption supported ? */
- if(mmc_encr(ioaddr))
- {
- range.encoding_size[0] = 8; /* DES = 64 bits key */
- range.num_encoding_sizes = 1;
- range.max_encoding_tokens = 1; /* Only one key possible */
- }
- else
- {
- range.num_encoding_sizes = 0;
- range.max_encoding_tokens = 0;
- }
-
- /* Copy structure to the user buffer. */
- if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
- ret = -EFAULT;
- }
- break;
-
- case SIOCGIWPRIV:
- /* Basic checking */
- if(wrq->u.data.pointer != (caddr_t) 0)
- {
- struct iw_priv_args priv[] =
- { /* cmd, set_args, get_args, name */
- { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
- { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
-
- { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
- { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
- };
-
- /* Set the number of available ioctls. */
- wrq->u.data.length = 4;
-
- /* Copy structure to the user buffer. */
- if (copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv)))
- ret = -EFAULT;
- }
- break;
+ } else
+ range.num_channels = range.num_frequency =
+ 0;
+
+ range.sensitivity = 0x3F;
+ range.max_qual.qual = MMR_SGNL_QUAL;
+ range.max_qual.level = MMR_SIGNAL_LVL;
+ range.max_qual.noise = MMR_SILENCE_LVL;
+
+ range.num_bitrates = 1;
+ range.bitrate[0] = 2000000; /* 2 Mb/s */
+
+ /* Encryption supported ? */
+ if (mmc_encr(ioaddr)) {
+ range.encoding_size[0] = 8; /* DES = 64 bits key */
+ range.num_encoding_sizes = 1;
+ range.max_encoding_tokens = 1; /* Only one key possible */
+ } else {
+ range.num_encoding_sizes = 0;
+ range.max_encoding_tokens = 0;
+ }
+
+ /* Copy structure to the user buffer. */
+ if (copy_to_user
+ (wrq->u.data.pointer, &range,
+ sizeof(struct iw_range))) ret = -EFAULT;
+ }
+ break;
+
+ case SIOCGIWPRIV:
+ /* Basic checking */
+ if (wrq->u.data.pointer != (caddr_t) 0) {
+ struct iw_priv_args priv[] = { /* cmd, set_args, get_args, name */
+
+ {SIOCSIPQTHR,
+ IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
+ 1, 0, "setqualthr"},
+ {SIOCGIPQTHR, 0,
+ IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
+ 1, "getqualthr"},
+
+
+ {SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,
+ 0, "sethisto"},
+ {SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16,
+ "gethisto"},
+ };
+
+ /* Set the number of available ioctls. */
+ wrq->u.data.length = 4;
+
+ /* Copy structure to the user buffer. */
+ if (copy_to_user
+ (wrq->u.data.pointer, (u8 *) priv,
+ sizeof(priv))) ret = -EFAULT;
+ }
+ break;
#ifdef WIRELESS_SPY
- case SIOCSIWSPY:
- /* Set the spy list */
-
- /* Check the number of addresses. */
- if(wrq->u.data.length > IW_MAX_SPY)
- {
- ret = -E2BIG;
- break;
- }
- lp->spy_number = wrq->u.data.length;
-
- /* Are there are addresses to copy? */
- if(lp->spy_number > 0)
- {
- struct sockaddr address[IW_MAX_SPY];
- int i;
-
- /* Copy addresses to the driver. */
- if (copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number)) {
- ret = -EFAULT;
- break;
- }
-
- /* Copy addresses to the lp structure. */
- for(i = 0; i < lp->spy_number; i++)
- {
- memcpy(lp->spy_address[i], address[i].sa_data,
- WAVELAN_ADDR_SIZE);
- }
-
- /* Reset structure. */
- memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+ case SIOCSIWSPY:
+ /* Set the spy list */
+
+ /* Check the number of addresses. */
+ if (wrq->u.data.length > IW_MAX_SPY) {
+ ret = -E2BIG;
+ break;
+ }
+ lp->spy_number = wrq->u.data.length;
+
+ /* Are there are addresses to copy? */
+ if (lp->spy_number > 0) {
+ struct sockaddr address[IW_MAX_SPY];
+ int i;
+
+ /* Copy addresses to the driver. */
+ if (copy_from_user
+ (address, wrq->u.data.pointer,
+ sizeof(struct sockaddr) * lp->spy_number)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ /* Copy addresses to the lp structure. */
+ for (i = 0; i < lp->spy_number; i++) {
+ memcpy(lp->spy_address[i],
+ address[i].sa_data,
+ WAVELAN_ADDR_SIZE);
+ }
+
+ /* Reset structure. */
+ memset(lp->spy_stat, 0x00,
+ sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "SetSpy: set of new addresses is: \n");
- for(i = 0; i < wrq->u.data.length; i++)
- printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
- lp->spy_address[i][0],
- lp->spy_address[i][1],
- lp->spy_address[i][2],
- lp->spy_address[i][3],
- lp->spy_address[i][4],
- lp->spy_address[i][5]);
-#endif /* DEBUG_IOCTL_INFO */
- }
-
- break;
-
- case SIOCGIWSPY:
- /* Get the spy list and spy stats. */
-
- /* Set the number of addresses */
- wrq->u.data.length = lp->spy_number;
-
- /* Does the user want to have the addresses back? */
- if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
- {
- struct sockaddr address[IW_MAX_SPY];
- int i;
-
- /* Copy addresses from the lp structure. */
- for(i = 0; i < lp->spy_number; i++)
- {
- memcpy(address[i].sa_data, lp->spy_address[i],
- WAVELAN_ADDR_SIZE);
- address[i].sa_family = AF_UNIX;
- }
-
- /* Copy addresses to the user buffer. */
- if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number)) {
- ret = -EFAULT;
- break;
- }
-
- /* Copy stats to the user buffer (just after). */
- if (copy_to_user(wrq->u.data.pointer +
- (sizeof(struct sockaddr) * lp->spy_number),
- lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) {
- ret = -EFAULT;
- break;
- }
-
- /* Reset updated flags. */
- for(i = 0; i < lp->spy_number; i++)
- lp->spy_stat[i].updated = 0x0;
- } /* if(pointer != NULL) */
-
- break;
-#endif /* WIRELESS_SPY */
-
- /* ------------------ PRIVATE IOCTL ------------------ */
-
- case SIOCSIPQTHR:
- if(!suser())
- {
- ret = -EPERM;
- break;
- }
- psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
- psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
- (unsigned char *)&psa.psa_quality_thr, 1);
- /* update the Wavelan checksum */
- update_psa_checksum(dev, ioaddr, lp->hacr);
- mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
- break;
-
- case SIOCGIPQTHR:
- psa_read(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
- (unsigned char *)&psa.psa_quality_thr, 1);
- *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
- break;
+ printk(KERN_DEBUG
+ "SetSpy: set of new addresses is: \n");
+ for (i = 0; i < wrq->u.data.length; i++)
+ printk(KERN_DEBUG
+ "%02X:%02X:%02X:%02X:%02X:%02X \n",
+ lp->spy_address[i][0],
+ lp->spy_address[i][1],
+ lp->spy_address[i][2],
+ lp->spy_address[i][3],
+ lp->spy_address[i][4],
+ lp->spy_address[i][5]);
+#endif /* DEBUG_IOCTL_INFO */
+ }
+
+ break;
+
+ case SIOCGIWSPY:
+ /* Get the spy list and spy stats. */
+
+ /* Set the number of addresses */
+ wrq->u.data.length = lp->spy_number;
+
+ /* Does the user want to have the addresses back? */
+ if ((lp->spy_number > 0)
+ && (wrq->u.data.pointer != (caddr_t) 0)) {
+ struct sockaddr address[IW_MAX_SPY];
+ int i;
+
+ /* Copy addresses from the lp structure. */
+ for (i = 0; i < lp->spy_number; i++) {
+ memcpy(address[i].sa_data,
+ lp->spy_address[i],
+ WAVELAN_ADDR_SIZE);
+ address[i].sa_family = AF_UNIX;
+ }
+
+ /* Copy addresses to the user buffer. */
+ if (copy_to_user
+ (wrq->u.data.pointer, address,
+ sizeof(struct sockaddr) * lp->spy_number)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ /* Copy stats to the user buffer (just after). */
+ if (copy_to_user(wrq->u.data.pointer +
+ (sizeof(struct sockaddr) *
+ lp->spy_number), lp->spy_stat,
+ sizeof(iw_qual) * lp->spy_number)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ /* Reset updated flags. */
+ for (i = 0; i < lp->spy_number; i++)
+ lp->spy_stat[i].updated = 0x0;
+ }
+ /* if(pointer != NULL) */
+ break;
+#endif /* WIRELESS_SPY */
+
+ /* ------------------ PRIVATE IOCTL ------------------ */
+
+ case SIOCSIPQTHR:
+ if (!suser()) {
+ ret = -EPERM;
+ break;
+ }
+ psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_quality_thr - (char *) &psa,
+ (unsigned char *) &psa.psa_quality_thr, 1);
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
+ mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
+ psa.psa_quality_thr);
+ break;
+
+ case SIOCGIPQTHR:
+ psa_read(ioaddr, lp->hacr,
+ (char *) &psa.psa_quality_thr - (char *) &psa,
+ (unsigned char *) &psa.psa_quality_thr, 1);
+ *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
+ break;
#ifdef HISTOGRAM
- case SIOCSIPHISTO:
- /* Verify that the user is root. */
- if(!suser())
- {
- ret = -EPERM;
- break;
- }
-
- /* Check the number of intervals. */
- if(wrq->u.data.length > 16)
- {
- ret = -E2BIG;
- break;
- }
- lp->his_number = wrq->u.data.length;
+ case SIOCSIPHISTO:
+ /* Verify that the user is root. */
+ if (!suser()) {
+ ret = -EPERM;
+ break;
+ }
+
+ /* Check the number of intervals. */
+ if (wrq->u.data.length > 16) {
+ ret = -E2BIG;
+ break;
+ }
+ lp->his_number = wrq->u.data.length;
+
+ /* Are there addresses to copy? */
+ if (lp->his_number > 0) {
+ /* Copy interval ranges to the driver */
+ if (copy_from_user
+ (lp->his_range, wrq->u.data.pointer,
+ sizeof(char) * lp->his_number)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ /* Reset structure. */
+ memset(lp->his_sum, 0x00, sizeof(long) * 16);
+ }
+ break;
+
+ case SIOCGIPHISTO:
+ /* Set the number of intervals. */
+ wrq->u.data.length = lp->his_number;
+
+ /* Give back the distribution statistics */
+ if ((lp->his_number > 0)
+ && (wrq->u.data.pointer != (caddr_t) 0)) {
+ /* Copy data to the user buffer. */
+ if (copy_to_user
+ (wrq->u.data.pointer, lp->his_sum,
+ sizeof(long) * lp->his_number))
+ ret = -EFAULT;
+
+ } /* if(pointer != NULL) */
+ break;
+#endif /* HISTOGRAM */
+
+ /* ------------------- OTHER IOCTL ------------------- */
- /* Are there addresses to copy? */
- if(lp->his_number > 0)
- {
- /* Copy interval ranges to the driver */
- if (copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number)) {
- ret = -EFAULT;
- break;
- }
-
- /* Reset structure. */
- memset(lp->his_sum, 0x00, sizeof(long) * 16);
+ default:
+ ret = -EOPNOTSUPP;
}
- break;
-
- case SIOCGIPHISTO:
- /* Set the number of intervals. */
- wrq->u.data.length = lp->his_number;
-
- /* Give back the distribution statistics */
- if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
- {
- /* Copy data to the user buffer. */
- if (copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number))
- ret = -EFAULT;
-
- } /* if(pointer != NULL) */
- break;
-#endif /* HISTOGRAM */
- /* ------------------- OTHER IOCTL ------------------- */
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- /* Enable interrupts and restore flags. */
- wv_splx(x);
+ /* Enable interrupts and restore flags. */
+ restore_flags(flags);
#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif
- return ret;
+ return ret;
}
/*------------------------------------------------------------------*/
@@ -2351,56 +2284,64 @@ wavelan_ioctl(struct net_device * dev, /* device on which the ioctl is applied *
* Get wireless statistics.
* Called by /proc/net/wireless
*/
-static iw_stats *
-wavelan_get_wireless_stats(device * dev)
+static iw_stats *wavelan_get_wireless_stats(device * dev)
{
- u_long ioaddr = dev->base_addr;
- net_local * lp = (net_local *) dev->priv;
- mmr_t m;
- iw_stats * wstats;
- unsigned long x;
+ unsigned long ioaddr = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv;
+ mmr_t m;
+ iw_stats *wstats;
+ unsigned long flags;
#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n",
+ dev->name);
#endif
- /* Disable interrupts and save flags. */
- x = wv_splhi();
-
- if(lp == (net_local *) NULL)
- return (iw_stats *) NULL;
- wstats = &lp->wstats;
-
- /* Get data from the mmc. */
- mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
-
- mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
- mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2);
- mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4);
-
- mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-
- /* Copy data to wireless stuff. */
- wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
- wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
- wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
- wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
- wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) |
- ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) |
- ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
- wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
- wstats->discard.code = 0L;
- wstats->discard.misc = 0L;
-
- /* Enable interrupts and restore flags. */
- wv_splx(x);
+ /* Disable interrupts and save flags. */
+ save_flags(flags);
+ cli();
+
+ if (lp == (net_local *) NULL)
+ {
+ restore_flags(flags);
+ return (iw_stats *) NULL;
+ }
+
+ wstats = &lp->wstats;
+
+ /* Get data from the mmc. */
+ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+
+ mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
+ mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l,
+ 2);
+ mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set,
+ 4);
+
+ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+
+ /* Copy data to wireless stuff. */
+ wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
+ wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
+ wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
+ wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
+ wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7)
+ | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6)
+ | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
+ wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+ wstats->discard.code = 0L;
+ wstats->discard.misc = 0L;
+
+ /* Enable interrupts and restore flags. */
+ restore_flags(flags);
#ifdef DEBUG_IOCTL_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n",
+ dev->name);
#endif
- return &lp->wstats;
+ return &lp->wstats;
}
-#endif /* WIRELESS_EXT */
+#endif /* WIRELESS_EXT */
/************************* PACKET RECEPTION *************************/
/*
@@ -2423,90 +2364,90 @@ wavelan_get_wireless_stats(device * dev)
* (called by wv_packet_rcv())
*/
static inline void
-wv_packet_read(device * dev,
- u_short buf_off,
- int sksize)
+wv_packet_read(device * dev, u16 buf_off, int sksize)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- struct sk_buff * skb;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ struct sk_buff *skb;
#ifdef DEBUG_RX_TRACE
- printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
- dev->name, buf_off, sksize);
+ printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
+ dev->name, buf_off, sksize);
#endif
- /* Allocate buffer for the data */
- if((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL)
- {
+ /* Allocate buffer for the data */
+ if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) {
#ifdef DEBUG_RX_ERROR
- printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n",
- dev->name, sksize);
+ printk(KERN_INFO
+ "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n",
+ dev->name, sksize);
#endif
- lp->stats.rx_dropped++;
- return;
- }
+ lp->stats.rx_dropped++;
+ return;
+ }
- skb->dev = dev;
+ skb->dev = dev;
- /* Copy the packet to the buffer. */
- obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
- skb->protocol=eth_type_trans(skb, dev);
+ /* Copy the packet to the buffer. */
+ obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
+ skb->protocol = eth_type_trans(skb, dev);
#ifdef DEBUG_RX_INFO
- wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
-#endif /* DEBUG_RX_INFO */
+ wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+#endif /* DEBUG_RX_INFO */
- /* Statistics-gathering and associated stuff.
- * It seem a bit messy with all the define, but it's really simple... */
+ /* Statistics-gathering and associated stuff.
+ * It seem a bit messy with all the define, but it's really simple... */
#if defined(WIRELESS_SPY) || defined(HISTOGRAM)
- if(
+ if (
#ifdef WIRELESS_SPY
- (lp->spy_number > 0) ||
-#endif /* WIRELESS_SPY */
+ (lp->spy_number > 0) ||
+#endif /* WIRELESS_SPY */
#ifdef HISTOGRAM
- (lp->his_number > 0) ||
-#endif /* HISTOGRAM */
- 0)
- {
- u_char stats[3]; /* signal level, noise level, signal quality */
-
- /* Read signal level, silence level and signal quality bytes. */
- /* Note: in the PCMCIA hardware, these are part of the frame. It seems
- * that for the ISA hardware, it's nowhere to be found in the frame,
- * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
- * Any ideas?
- */
- mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
- mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
- mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+ (lp->his_number > 0) ||
+#endif /* HISTOGRAM */
+ 0) {
+ u8 stats[3]; /* signal level, noise level, signal quality */
+
+ /* Read signal level, silence level and signal quality bytes. */
+ /* Note: in the PCMCIA hardware, these are part of the frame. It seems
+ * that for the ISA hardware, it's nowhere to be found in the frame,
+ * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+ * Any ideas?
+ */
+ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+ mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
+ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
#ifdef DEBUG_RX_INFO
- printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
- dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F);
+ printk(KERN_DEBUG
+ "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
+ dev->name, stats[0] & 0x3F, stats[1] & 0x3F,
+ stats[2] & 0x0F);
#endif
- /* Spying stuff */
+ /* Spying stuff */
#ifdef WIRELESS_SPY
- wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
-#endif /* WIRELESS_SPY */
+ wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE,
+ stats);
+#endif /* WIRELESS_SPY */
#ifdef HISTOGRAM
- wl_his_gather(dev, stats);
-#endif /* HISTOGRAM */
- }
-#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
+ wl_his_gather(dev, stats);
+#endif /* HISTOGRAM */
+ }
+#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
- /*
- * Hand the packet to the network module.
- */
- netif_rx(skb);
+ /*
+ * Hand the packet to the network module.
+ */
+ netif_rx(skb);
- /* Keep statistics up to date */
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
+ /* Keep statistics up to date */
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += skb->len;
#ifdef DEBUG_RX_TRACE
- printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
#endif
}
@@ -2516,150 +2457,160 @@ wv_packet_read(device * dev,
* from the device RAM.
* Called by the interrupt handler.
*/
-static inline void
-wv_receive(device * dev)
+static inline void wv_receive(device * dev)
{
- u_long ioaddr = dev->base_addr;
- net_local * lp = (net_local *)dev->priv;
- fd_t fd;
- rbd_t rbd;
- int nreaped = 0;
+ unsigned long ioaddr = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv;
+ fd_t fd;
+ rbd_t rbd;
+ int nreaped = 0;
#ifdef DEBUG_RX_TRACE
- printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
#endif
- /* Loop on each received packet. */
- for(;;)
- {
- obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
-
- /* Note about the status :
- * It start up to be 0 (the value we set). Then, when the RU
- * grab the buffer to prepare for reception, it sets the
- * FD_STATUS_B flag. When the RU has finished receiving the
- * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate
- * completion and set the other flags to indicate the eventual
- * errors. FD_STATUS_OK indicates that the reception was OK.
- */
-
- /* If the current frame is not complete, we have reached the end. */
- if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
- break; /* This is how we exit the loop. */
-
- nreaped++;
-
- /* Check whether frame was correctly received. */
- if((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK)
- {
- /* Does the frame contain a pointer to the data? Let's check. */
- if(fd.fd_rbd_offset != I82586NULL)
- {
- /* Read the receive buffer descriptor */
- obram_read(ioaddr, fd.fd_rbd_offset,
- (unsigned char *) &rbd, sizeof(rbd));
+ /* Loop on each received packet. */
+ for (;;) {
+ obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd,
+ sizeof(fd));
+
+ /* Note about the status :
+ * It start up to be 0 (the value we set). Then, when the RU
+ * grab the buffer to prepare for reception, it sets the
+ * FD_STATUS_B flag. When the RU has finished receiving the
+ * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate
+ * completion and set the other flags to indicate the eventual
+ * errors. FD_STATUS_OK indicates that the reception was OK.
+ */
+
+ /* If the current frame is not complete, we have reached the end. */
+ if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
+ break; /* This is how we exit the loop. */
+
+ nreaped++;
+
+ /* Check whether frame was correctly received. */
+ if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) {
+ /* Does the frame contain a pointer to the data? Let's check. */
+ if (fd.fd_rbd_offset != I82586NULL) {
+ /* Read the receive buffer descriptor */
+ obram_read(ioaddr, fd.fd_rbd_offset,
+ (unsigned char *) &rbd,
+ sizeof(rbd));
#ifdef DEBUG_RX_ERROR
- if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF)
- printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n",
- dev->name);
-
- if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F)
- printk(KERN_INFO "%s: wv_receive(): missing F flag.\n",
- dev->name);
-#endif /* DEBUG_RX_ERROR */
-
- /* Read the packet and transmit to Linux */
- wv_packet_read(dev, rbd.rbd_bufl,
- rbd.rbd_status & RBD_STATUS_ACNT);
- }
+ if ((rbd.rbd_status & RBD_STATUS_EOF) !=
+ RBD_STATUS_EOF) printk(KERN_INFO
+ "%s: wv_receive(): missing EOF flag.\n",
+ dev->name);
+
+ if ((rbd.rbd_status & RBD_STATUS_F) !=
+ RBD_STATUS_F) printk(KERN_INFO
+ "%s: wv_receive(): missing F flag.\n",
+ dev->name);
+#endif /* DEBUG_RX_ERROR */
+
+ /* Read the packet and transmit to Linux */
+ wv_packet_read(dev, rbd.rbd_bufl,
+ rbd.
+ rbd_status &
+ RBD_STATUS_ACNT);
+ }
#ifdef DEBUG_RX_ERROR
- else /* if frame has no data */
- printk(KERN_INFO "%s: wv_receive(): frame has no data.\n",
- dev->name);
+ else /* if frame has no data */
+ printk(KERN_INFO
+ "%s: wv_receive(): frame has no data.\n",
+ dev->name);
#endif
- }
- else /* If reception was no successful */
- {
- lp->stats.rx_errors++;
+ } else { /* If reception was no successful */
+
+ lp->stats.rx_errors++;
#ifdef DEBUG_RX_INFO
- printk(KERN_DEBUG "%s: wv_receive(): frame not received successfully (%X).\n",
- dev->name, fd.fd_status);
+ printk(KERN_DEBUG
+ "%s: wv_receive(): frame not received successfully (%X).\n",
+ dev->name, fd.fd_status);
#endif
#ifdef DEBUG_RX_ERROR
- if((fd.fd_status & FD_STATUS_S6) != 0)
- printk(KERN_INFO "%s: wv_receive(): no EOF flag.\n", dev->name);
+ if ((fd.fd_status & FD_STATUS_S6) != 0)
+ printk(KERN_INFO
+ "%s: wv_receive(): no EOF flag.\n",
+ dev->name);
#endif
- if((fd.fd_status & FD_STATUS_S7) != 0)
- {
- lp->stats.rx_length_errors++;
+ if ((fd.fd_status & FD_STATUS_S7) != 0) {
+ lp->stats.rx_length_errors++;
#ifdef DEBUG_RX_FAIL
- printk(KERN_DEBUG "%s: wv_receive(): frame too short.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_receive(): frame too short.\n",
+ dev->name);
#endif
- }
+ }
- if((fd.fd_status & FD_STATUS_S8) != 0)
- {
- lp->stats.rx_over_errors++;
+ if ((fd.fd_status & FD_STATUS_S8) != 0) {
+ lp->stats.rx_over_errors++;
#ifdef DEBUG_RX_FAIL
- printk(KERN_DEBUG "%s: wv_receive(): rx DMA overrun.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_receive(): rx DMA overrun.\n",
+ dev->name);
#endif
- }
+ }
- if((fd.fd_status & FD_STATUS_S9) != 0)
- {
- lp->stats.rx_fifo_errors++;
+ if ((fd.fd_status & FD_STATUS_S9) != 0) {
+ lp->stats.rx_fifo_errors++;
#ifdef DEBUG_RX_FAIL
- printk(KERN_DEBUG "%s: wv_receive(): ran out of resources.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_receive(): ran out of resources.\n",
+ dev->name);
#endif
- }
+ }
- if((fd.fd_status & FD_STATUS_S10) != 0)
- {
- lp->stats.rx_frame_errors++;
+ if ((fd.fd_status & FD_STATUS_S10) != 0) {
+ lp->stats.rx_frame_errors++;
#ifdef DEBUG_RX_FAIL
- printk(KERN_DEBUG "%s: wv_receive(): alignment error.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_receive(): alignment error.\n",
+ dev->name);
#endif
- }
+ }
- if((fd.fd_status & FD_STATUS_S11) != 0)
- {
- lp->stats.rx_crc_errors++;
+ if ((fd.fd_status & FD_STATUS_S11) != 0) {
+ lp->stats.rx_crc_errors++;
#ifdef DEBUG_RX_FAIL
- printk(KERN_DEBUG "%s: wv_receive(): CRC error.\n", dev->name);
+ printk(KERN_DEBUG
+ "%s: wv_receive(): CRC error.\n",
+ dev->name);
#endif
- }
- }
+ }
+ }
- fd.fd_status = 0;
- obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
- (unsigned char *) &fd.fd_status, sizeof(fd.fd_status));
+ fd.fd_status = 0;
+ obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
+ (unsigned char *) &fd.fd_status,
+ sizeof(fd.fd_status));
- fd.fd_command = FD_COMMAND_EL;
- obram_write(ioaddr, fdoff(lp->rx_head, fd_command),
- (unsigned char *) &fd.fd_command, sizeof(fd.fd_command));
+ fd.fd_command = FD_COMMAND_EL;
+ obram_write(ioaddr, fdoff(lp->rx_head, fd_command),
+ (unsigned char *) &fd.fd_command,
+ sizeof(fd.fd_command));
- fd.fd_command = 0;
- obram_write(ioaddr, fdoff(lp->rx_last, fd_command),
- (unsigned char *) &fd.fd_command, sizeof(fd.fd_command));
+ fd.fd_command = 0;
+ obram_write(ioaddr, fdoff(lp->rx_last, fd_command),
+ (unsigned char *) &fd.fd_command,
+ sizeof(fd.fd_command));
- lp->rx_last = lp->rx_head;
- lp->rx_head = fd.fd_link_offset;
- } /* for(;;) -> loop on all frames */
+ lp->rx_last = lp->rx_head;
+ lp->rx_head = fd.fd_link_offset;
+ } /* for(;;) -> loop on all frames */
#ifdef DEBUG_RX_INFO
- if(nreaped > 1)
- printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", dev->name, nreaped);
+ if (nreaped > 1)
+ printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n",
+ dev->name, nreaped);
#endif
#ifdef DEBUG_RX_TRACE
- printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name);
#endif
}
@@ -2689,130 +2640,124 @@ wv_receive(device * dev)
*
* (called in wavelan_packet_xmit())
*/
-static inline void
-wv_packet_write(device * dev,
- void * buf,
- short length)
+static inline void wv_packet_write(device * dev, void *buf, short length)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- unsigned short txblock;
- unsigned short txpred;
- unsigned short tx_addr;
- unsigned short nop_addr;
- unsigned short tbd_addr;
- unsigned short buf_addr;
- ac_tx_t tx;
- ac_nop_t nop;
- tbd_t tbd;
- int clen = length;
- unsigned long x;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ unsigned short txblock;
+ unsigned short txpred;
+ unsigned short tx_addr;
+ unsigned short nop_addr;
+ unsigned short tbd_addr;
+ unsigned short buf_addr;
+ ac_tx_t tx;
+ ac_nop_t nop;
+ tbd_t tbd;
+ int clen = length;
+ unsigned long flags;
#ifdef DEBUG_TX_TRACE
- printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
+ printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name,
+ length);
#endif
- /* Do we need some padding? */
- if(clen < ETH_ZLEN)
- clen = ETH_ZLEN;
+ /* Do we need some padding? */
+ if (clen < ETH_ZLEN)
+ clen = ETH_ZLEN;
+
+ save_flags(flags);
+ cli();
+
+ /* Calculate addresses of next block and previous block. */
+ txblock = lp->tx_first_free;
+ txpred = txblock - TXBLOCKZ;
+ if (txpred < OFFSET_CU)
+ txpred += NTXBLOCKS * TXBLOCKZ;
+ lp->tx_first_free += TXBLOCKZ;
+ if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+ lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+
+ lp->tx_n_in_use++;
+
+ /* Calculate addresses of the different parts of the block. */
+ tx_addr = txblock;
+ nop_addr = tx_addr + sizeof(tx);
+ tbd_addr = nop_addr + sizeof(nop);
+ buf_addr = tbd_addr + sizeof(tbd);
- x = wv_splhi();
+ /*
+ * Transmit command
+ */
+ tx.tx_h.ac_status = 0;
+ obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
+ (unsigned char *) &tx.tx_h.ac_status,
+ sizeof(tx.tx_h.ac_status));
- /* Calculate addresses of next block and previous block. */
- txblock = lp->tx_first_free;
- txpred = txblock - TXBLOCKZ;
- if(txpred < OFFSET_CU)
- txpred += NTXBLOCKS * TXBLOCKZ;
- lp->tx_first_free += TXBLOCKZ;
- if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
- lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+ /*
+ * NOP command
+ */
+ nop.nop_h.ac_status = 0;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+ (unsigned char *) &nop.nop_h.ac_status,
+ sizeof(nop.nop_h.ac_status));
+ nop.nop_h.ac_link = nop_addr;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+ (unsigned char *) &nop.nop_h.ac_link,
+ sizeof(nop.nop_h.ac_link));
-/*
-if (lp->tx_n_in_use > 0)
- printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
-*/
+ /*
+ * Transmit buffer descriptor
+ */
+ tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
+ tbd.tbd_next_bd_offset = I82586NULL;
+ tbd.tbd_bufl = buf_addr;
+ tbd.tbd_bufh = 0;
+ obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd));
+
+ /*
+ * Data
+ */
+ obram_write(ioaddr, buf_addr, buf, length);
+
+ /*
+ * Overwrite the predecessor NOP link
+ * so that it points to this txblock.
+ */
+ nop_addr = txpred + sizeof(tx);
+ nop.nop_h.ac_status = 0;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+ (unsigned char *) &nop.nop_h.ac_status,
+ sizeof(nop.nop_h.ac_status));
+ nop.nop_h.ac_link = txblock;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+ (unsigned char *) &nop.nop_h.ac_link,
+ sizeof(nop.nop_h.ac_link));
+
+ /* Keep stats up to date. */
+ lp->stats.tx_bytes += length;
+
+ /* If watchdog not already active, activate it... */
+ if (lp->watchdog.prev == (timer_list *) NULL) {
+ /* Set timer to expire in WATCHDOG_JIFFIES. */
+ lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+ add_timer(&lp->watchdog);
+ }
- lp->tx_n_in_use++;
-
- /* Calculate addresses of the different parts of the block. */
- tx_addr = txblock;
- nop_addr = tx_addr + sizeof(tx);
- tbd_addr = nop_addr + sizeof(nop);
- buf_addr = tbd_addr + sizeof(tbd);
-
- /*
- * Transmit command
- */
- tx.tx_h.ac_status = 0;
- obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
- (unsigned char *) &tx.tx_h.ac_status,
- sizeof(tx.tx_h.ac_status));
-
- /*
- * NOP command
- */
- nop.nop_h.ac_status = 0;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
- (unsigned char *) &nop.nop_h.ac_status,
- sizeof(nop.nop_h.ac_status));
- nop.nop_h.ac_link = nop_addr;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
- (unsigned char *) &nop.nop_h.ac_link,
- sizeof(nop.nop_h.ac_link));
-
- /*
- * Transmit buffer descriptor
- */
- tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
- tbd.tbd_next_bd_offset = I82586NULL;
- tbd.tbd_bufl = buf_addr;
- tbd.tbd_bufh = 0;
- obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
-
- /*
- * Data
- */
- obram_write(ioaddr, buf_addr, buf, length);
-
- /*
- * Overwrite the predecessor NOP link
- * so that it points to this txblock.
- */
- nop_addr = txpred + sizeof(tx);
- nop.nop_h.ac_status = 0;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
- (unsigned char *)&nop.nop_h.ac_status,
- sizeof(nop.nop_h.ac_status));
- nop.nop_h.ac_link = txblock;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
- (unsigned char *) &nop.nop_h.ac_link,
- sizeof(nop.nop_h.ac_link));
-
- /* Keep stats up to date. */
- lp->stats.tx_bytes += length;
-
- /* If watchdog not already active, activate it... */
- if(lp->watchdog.prev == (timer_list *) NULL)
- {
- /* Set timer to expire in WATCHDOG_JIFFIES. */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
- }
-
- if(lp->tx_first_in_use == I82586NULL)
- lp->tx_first_in_use = txblock;
-
- if(lp->tx_n_in_use < NTXBLOCKS - 1)
- dev->tbusy = 0;
-
- wv_splx(x);
+ if (lp->tx_first_in_use == I82586NULL)
+ lp->tx_first_in_use = txblock;
+ if (lp->tx_n_in_use < NTXBLOCKS - 1)
+ netif_wake_queue(dev);
+
+ restore_flags(flags);
+
#ifdef DEBUG_TX_INFO
- wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
-#endif /* DEBUG_TX_INFO */
+ wv_packet_info((u8 *) buf, length, dev->name,
+ "wv_packet_write");
+#endif /* DEBUG_TX_INFO */
#ifdef DEBUG_TX_TRACE
- printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
#endif
}
@@ -2823,59 +2768,41 @@ if (lp->tx_n_in_use > 0)
* the packet. We also prevent reentrance. Then we call the function
* to send the packet.
*/
-static int
-wavelan_packet_xmit(struct sk_buff * skb,
- device * dev)
+static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local *lp = (net_local *) dev->priv;
#ifdef DEBUG_TX_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
- (unsigned) skb);
+ printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+ (unsigned) skb);
#endif
- /* This flag indicate that the hardware can't perform a transmission.
- * Theoretically, NET3 checks it before sending a packet to the driver,
- * but in fact it never does that and pools continuously.
- * As the watchdog will abort overly long transmissions, we are quite safe.
- */
- if(dev->tbusy)
- return 1;
-
- /*
- * Block a timer-based transmit from overlapping.
- * In other words, prevent reentering this routine.
- */
- if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
-#ifdef DEBUG_TX_ERROR
- printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
-#endif
- else
- {
- /* If somebody has asked to reconfigure the controller,
- * we can do it now.
- */
- if(lp->reconfig_82586)
- {
- wv_82586_config(dev);
- if(dev->tbusy)
- return 1;
- }
+ /*
+ * Block a timer-based transmit from overlapping.
+ * In other words, prevent reentering this routine.
+ */
+ netif_stop_queue(dev);
+
+ /* If somebody has asked to reconfigure the controller,
+ * we can do it now.
+ */
+ if (lp->reconfig_82586) {
+ wv_82586_config(dev);
+ }
#ifdef DEBUG_TX_ERROR
- if(skb->next)
- printk(KERN_INFO "skb has next\n");
+ if (skb->next)
+ printk(KERN_INFO "skb has next\n");
#endif
- wv_packet_write(dev, skb->data, skb->len);
- }
+ wv_packet_write(dev, skb->data, skb->len);
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
#ifdef DEBUG_TX_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*********************** HARDWARE CONFIGURATION ***********************/
@@ -2888,166 +2815,170 @@ wavelan_packet_xmit(struct sk_buff * skb,
* Routine to initialize the Modem Management Controller.
* (called by wv_hw_reset())
*/
-static inline int
-wv_mmc_init(device * dev)
+static inline int wv_mmc_init(device * dev)
{
- u_long ioaddr = dev->base_addr;
- net_local * lp = (net_local *)dev->priv;
- psa_t psa;
- mmw_t m;
- int configured;
+ unsigned long ioaddr = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv;
+ psa_t psa;
+ mmw_t m;
+ int configured;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
#endif
- /* Read the parameter storage area. */
- psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
+ /* Read the parameter storage area. */
+ psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
#ifdef USE_PSA_CONFIG
- configured = psa.psa_conf_status & 1;
+ configured = psa.psa_conf_status & 1;
#else
- configured = 0;
+ configured = 0;
#endif
- /* Is the PSA is not configured */
- if(!configured)
- {
- /* User will be able to configure NWID later (with iwconfig). */
- psa.psa_nwid[0] = 0;
- psa.psa_nwid[1] = 0;
-
- /* no NWID checking since NWID is not set */
- psa.psa_nwid_select = 0;
-
- /* Disable encryption */
- psa.psa_encryption_select = 0;
-
- /* Set to standard values:
- * 0x04 for AT,
- * 0x01 for MCA,
- * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
- */
- if (psa.psa_comp_number & 1)
- psa.psa_thr_pre_set = 0x01;
- else
- psa.psa_thr_pre_set = 0x04;
- psa.psa_quality_thr = 0x03;
-
- /* It is configured */
- psa.psa_conf_status |= 1;
+ /* Is the PSA is not configured */
+ if (!configured) {
+ /* User will be able to configure NWID later (with iwconfig). */
+ psa.psa_nwid[0] = 0;
+ psa.psa_nwid[1] = 0;
+
+ /* no NWID checking since NWID is not set */
+ psa.psa_nwid_select = 0;
+
+ /* Disable encryption */
+ psa.psa_encryption_select = 0;
+
+ /* Set to standard values:
+ * 0x04 for AT,
+ * 0x01 for MCA,
+ * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
+ */
+ if (psa.psa_comp_number & 1)
+ psa.psa_thr_pre_set = 0x01;
+ else
+ psa.psa_thr_pre_set = 0x04;
+ psa.psa_quality_thr = 0x03;
+
+ /* It is configured */
+ psa.psa_conf_status |= 1;
#ifdef USE_PSA_CONFIG
- /* Write the psa. */
- psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
- (unsigned char *)psa.psa_nwid, 4);
- psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
- (unsigned char *)&psa.psa_thr_pre_set, 1);
- psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
- (unsigned char *)&psa.psa_quality_thr, 1);
- psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa,
- (unsigned char *)&psa.psa_conf_status, 1);
- /* update the Wavelan checksum */
- update_psa_checksum(dev, ioaddr, lp->hacr);
+ /* Write the psa. */
+ psa_write(ioaddr, lp->hacr,
+ (char *) psa.psa_nwid - (char *) &psa,
+ (unsigned char *) psa.psa_nwid, 4);
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_thr_pre_set - (char *) &psa,
+ (unsigned char *) &psa.psa_thr_pre_set, 1);
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_quality_thr - (char *) &psa,
+ (unsigned char *) &psa.psa_quality_thr, 1);
+ psa_write(ioaddr, lp->hacr,
+ (char *) &psa.psa_conf_status - (char *) &psa,
+ (unsigned char *) &psa.psa_conf_status, 1);
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, lp->hacr);
#endif
- }
-
- /* Zero the mmc structure. */
- memset(&m, 0x00, sizeof(m));
-
- /* Copy PSA info to the mmc. */
- m.mmw_netw_id_l = psa.psa_nwid[1];
- m.mmw_netw_id_h = psa.psa_nwid[0];
-
- if(psa.psa_nwid_select & 1)
- m.mmw_loopt_sel = 0x00;
- else
- m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
-
- memcpy(&m.mmw_encr_key, &psa.psa_encryption_key,
- sizeof(m.mmw_encr_key));
-
- if(psa.psa_encryption_select)
- m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
- else
- m.mmw_encr_enable = 0;
-
- m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
- m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
-
- /*
- * Set default modem control parameters.
- * See NCR document 407-0024326 Rev. A.
- */
- m.mmw_jabber_enable = 0x01;
- m.mmw_freeze = 0;
- m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
- m.mmw_ifs = 0x20;
- m.mmw_mod_delay = 0x04;
- m.mmw_jam_time = 0x38;
-
- m.mmw_des_io_invert = 0;
- m.mmw_decay_prm = 0;
- m.mmw_decay_updat_prm = 0;
-
- /* Write all info to MMC. */
- mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
-
- /* The following code starts the modem of the 2.00 frequency
- * selectable cards at power on. It's not strictly needed for the
- * following boots.
- * The original patch was by Joe Finney for the PCMCIA driver, but
- * I've cleaned it up a bit and added documentation.
- * Thanks to Loeke Brederveld from Lucent for the info.
- */
-
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * Does it work for everybody, especially old cards? */
- /* Note: WFREQSEL verifies that it is able to read a sensible
- * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID
- * is 0xA (Xilinx version) or 0xB (Ariadne version).
- * My test is more crude but does work. */
- if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
- (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
- {
- /* We must download the frequency parameters to the
- * synthesizers (from the EEPROM - area 1)
- * Note: as the EEPROM is automatically decremented, we set the end
- * if the area... */
- m.mmw_fee_addr = 0x0F;
- m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
- mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
- (unsigned char *)&m.mmw_fee_ctrl, 2);
-
- /* Wait until the download is finished. */
- fee_wait(ioaddr, 100, 100);
+ }
+
+ /* Zero the mmc structure. */
+ memset(&m, 0x00, sizeof(m));
+
+ /* Copy PSA info to the mmc. */
+ m.mmw_netw_id_l = psa.psa_nwid[1];
+ m.mmw_netw_id_h = psa.psa_nwid[0];
+
+ if (psa.psa_nwid_select & 1)
+ m.mmw_loopt_sel = 0x00;
+ else
+ m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
+
+ memcpy(&m.mmw_encr_key, &psa.psa_encryption_key,
+ sizeof(m.mmw_encr_key));
+
+ if (psa.psa_encryption_select)
+ m.mmw_encr_enable =
+ MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
+ else
+ m.mmw_encr_enable = 0;
+
+ m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
+ m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
+
+ /*
+ * Set default modem control parameters.
+ * See NCR document 407-0024326 Rev. A.
+ */
+ m.mmw_jabber_enable = 0x01;
+ m.mmw_freeze = 0;
+ m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
+ m.mmw_ifs = 0x20;
+ m.mmw_mod_delay = 0x04;
+ m.mmw_jam_time = 0x38;
+
+ m.mmw_des_io_invert = 0;
+ m.mmw_decay_prm = 0;
+ m.mmw_decay_updat_prm = 0;
+
+ /* Write all info to MMC. */
+ mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m));
+
+ /* The following code starts the modem of the 2.00 frequency
+ * selectable cards at power on. It's not strictly needed for the
+ * following boots.
+ * The original patch was by Joe Finney for the PCMCIA driver, but
+ * I've cleaned it up a bit and added documentation.
+ * Thanks to Loeke Brederveld from Lucent for the info.
+ */
+
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+ * Does it work for everybody, especially old cards? */
+ /* Note: WFREQSEL verifies that it is able to read a sensible
+ * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID
+ * is 0xA (Xilinx version) or 0xB (Ariadne version).
+ * My test is more crude but does work. */
+ if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+ (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+ /* We must download the frequency parameters to the
+ * synthesizers (from the EEPROM - area 1)
+ * Note: as the EEPROM is automatically decremented, we set the end
+ * if the area... */
+ m.mmw_fee_addr = 0x0F;
+ m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+ mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
+ (unsigned char *) &m.mmw_fee_ctrl, 2);
+
+ /* Wait until the download is finished. */
+ fee_wait(ioaddr, 100, 100);
#ifdef DEBUG_CONFIG_INFO
- /* The frequency was in the last word downloaded. */
- mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m,
- (unsigned char *)&m.mmw_fee_data_l, 2);
-
- /* Print some info for the user. */
- printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n",
- dev->name,
- ((m.mmw_fee_data_h << 4) |
- (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
+ /* The frequency was in the last word downloaded. */
+ mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m,
+ (unsigned char *) &m.mmw_fee_data_l, 2);
+
+ /* Print some info for the user. */
+ printk(KERN_DEBUG
+ "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n",
+ dev->name,
+ ((m.
+ mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) *
+ 5 / 2 + 24000L);
#endif
- /* We must now download the power adjust value (gain) to
- * the synthesizers (from the EEPROM - area 7 - DAC). */
- m.mmw_fee_addr = 0x61;
- m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
- mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
- (unsigned char *)&m.mmw_fee_ctrl, 2);
-
- /* Wait until the download is finished. */
- } /* if 2.00 card */
+ /* We must now download the power adjust value (gain) to
+ * the synthesizers (from the EEPROM - area 7 - DAC). */
+ m.mmw_fee_addr = 0x61;
+ m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+ mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
+ (unsigned char *) &m.mmw_fee_ctrl, 2);
+ /* Wait until the download is finished. */
+ }
+ /* if 2.00 card */
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -3056,81 +2987,79 @@ wv_mmc_init(device * dev)
* Start the receive unit.
* (called by wv_hw_reset())
*/
-static inline int
-wv_ru_start(device * dev)
+static inline int wv_ru_start(device * dev)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- u_short scb_cs;
- fd_t fd;
- rbd_t rbd;
- u_short rx;
- u_short rx_next;
- int i;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ u16 scb_cs;
+ fd_t fd;
+ rbd_t rbd;
+ u16 rx;
+ u16 rx_next;
+ int i;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
#endif
- obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *)&scb_cs, sizeof(scb_cs));
- if((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY)
- return 0;
+ obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
+ if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY)
+ return 0;
- lp->rx_head = OFFSET_RU;
+ lp->rx_head = OFFSET_RU;
- for(i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next)
- {
- rx_next = (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ;
+ for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) {
+ rx_next =
+ (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ;
- fd.fd_status = 0;
- fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0;
- fd.fd_link_offset = rx_next;
- fd.fd_rbd_offset = rx + sizeof(fd);
- obram_write(ioaddr, rx, (unsigned char *)&fd, sizeof(fd));
+ fd.fd_status = 0;
+ fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0;
+ fd.fd_link_offset = rx_next;
+ fd.fd_rbd_offset = rx + sizeof(fd);
+ obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd));
- rbd.rbd_status = 0;
- rbd.rbd_next_rbd_offset = I82586NULL;
- rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd);
- rbd.rbd_bufh = 0;
- rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ);
- obram_write(ioaddr, rx + sizeof(fd),
- (unsigned char *) &rbd, sizeof(rbd));
+ rbd.rbd_status = 0;
+ rbd.rbd_next_rbd_offset = I82586NULL;
+ rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd);
+ rbd.rbd_bufh = 0;
+ rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ);
+ obram_write(ioaddr, rx + sizeof(fd),
+ (unsigned char *) &rbd, sizeof(rbd));
- lp->rx_last = rx;
- }
+ lp->rx_last = rx;
+ }
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset),
- (unsigned char *) &lp->rx_head, sizeof(lp->rx_head));
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset),
+ (unsigned char *) &lp->rx_head, sizeof(lp->rx_head));
- scb_cs = SCB_CMD_RUC_GO;
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &scb_cs, sizeof(scb_cs));
+ scb_cs = SCB_CMD_RUC_GO;
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
- set_chan_attn(ioaddr, lp->hacr);
+ set_chan_attn(ioaddr, lp->hacr);
- for(i = 1000; i > 0; i--)
- {
- obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &scb_cs, sizeof(scb_cs));
- if (scb_cs == 0)
- break;
+ for (i = 1000; i > 0; i--) {
+ obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
+ if (scb_cs == 0)
+ break;
- udelay(10);
- }
+ udelay(10);
+ }
- if(i <= 0)
- {
+ if (i <= 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: wavelan_ru_start(): board not accepting command.\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wavelan_ru_start(): board not accepting command.\n",
+ dev->name);
#endif
- return -1;
- }
-
+ return -1;
+ }
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -3150,94 +3079,93 @@ wv_ru_start(device * dev)
*
* (called by wv_hw_reset())
*/
-static inline int
-wv_cu_start(device * dev)
+static inline int wv_cu_start(device * dev)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- int i;
- u_short txblock;
- u_short first_nop;
- u_short scb_cs;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ int i;
+ u16 txblock;
+ u16 first_nop;
+ u16 scb_cs;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name);
#endif
- lp->tx_first_free = OFFSET_CU;
- lp->tx_first_in_use = I82586NULL;
-
- for(i = 0, txblock = OFFSET_CU;
- i < NTXBLOCKS;
- i++, txblock += TXBLOCKZ)
- {
- ac_tx_t tx;
- ac_nop_t nop;
- tbd_t tbd;
- unsigned short tx_addr;
- unsigned short nop_addr;
- unsigned short tbd_addr;
- unsigned short buf_addr;
-
- tx_addr = txblock;
- nop_addr = tx_addr + sizeof(tx);
- tbd_addr = nop_addr + sizeof(nop);
- buf_addr = tbd_addr + sizeof(tbd);
-
- tx.tx_h.ac_status = 0;
- tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I;
- tx.tx_h.ac_link = nop_addr;
- tx.tx_tbd_offset = tbd_addr;
- obram_write(ioaddr, tx_addr, (unsigned char *) &tx, sizeof(tx));
-
- nop.nop_h.ac_status = 0;
- nop.nop_h.ac_command = acmd_nop;
- nop.nop_h.ac_link = nop_addr;
- obram_write(ioaddr, nop_addr, (unsigned char *) &nop, sizeof(nop));
-
- tbd.tbd_status = TBD_STATUS_EOF;
- tbd.tbd_next_bd_offset = I82586NULL;
- tbd.tbd_bufl = buf_addr;
- tbd.tbd_bufh = 0;
- obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd));
- }
-
- first_nop = OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t);
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset),
- (unsigned char *) &first_nop, sizeof(first_nop));
-
- scb_cs = SCB_CMD_CUC_GO;
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &scb_cs, sizeof(scb_cs));
-
- set_chan_attn(ioaddr, lp->hacr);
-
- for(i = 1000; i > 0; i--)
- {
- obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &scb_cs, sizeof(scb_cs));
- if (scb_cs == 0)
- break;
-
- udelay(10);
- }
-
- if(i <= 0)
- {
+ lp->tx_first_free = OFFSET_CU;
+ lp->tx_first_in_use = I82586NULL;
+
+ for (i = 0, txblock = OFFSET_CU;
+ i < NTXBLOCKS; i++, txblock += TXBLOCKZ) {
+ ac_tx_t tx;
+ ac_nop_t nop;
+ tbd_t tbd;
+ unsigned short tx_addr;
+ unsigned short nop_addr;
+ unsigned short tbd_addr;
+ unsigned short buf_addr;
+
+ tx_addr = txblock;
+ nop_addr = tx_addr + sizeof(tx);
+ tbd_addr = nop_addr + sizeof(nop);
+ buf_addr = tbd_addr + sizeof(tbd);
+
+ tx.tx_h.ac_status = 0;
+ tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I;
+ tx.tx_h.ac_link = nop_addr;
+ tx.tx_tbd_offset = tbd_addr;
+ obram_write(ioaddr, tx_addr, (unsigned char *) &tx,
+ sizeof(tx));
+
+ nop.nop_h.ac_status = 0;
+ nop.nop_h.ac_command = acmd_nop;
+ nop.nop_h.ac_link = nop_addr;
+ obram_write(ioaddr, nop_addr, (unsigned char *) &nop,
+ sizeof(nop));
+
+ tbd.tbd_status = TBD_STATUS_EOF;
+ tbd.tbd_next_bd_offset = I82586NULL;
+ tbd.tbd_bufl = buf_addr;
+ tbd.tbd_bufh = 0;
+ obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd,
+ sizeof(tbd));
+ }
+
+ first_nop =
+ OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t);
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset),
+ (unsigned char *) &first_nop, sizeof(first_nop));
+
+ scb_cs = SCB_CMD_CUC_GO;
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
+
+ set_chan_attn(ioaddr, lp->hacr);
+
+ for (i = 1000; i > 0; i--) {
+ obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
+ if (scb_cs == 0)
+ break;
+
+ udelay(10);
+ }
+
+ if (i <= 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: wavelan_cu_start(): board not accepting command.\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wavelan_cu_start(): board not accepting command.\n",
+ dev->name);
#endif
- return -1;
- }
-
- lp->tx_n_in_use = 0;
- dev->tbusy = 0;
+ return -1;
+ }
+ lp->tx_n_in_use = 0;
+ netif_wake_queue(dev);
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -3252,121 +3180,122 @@ wv_cu_start(device * dev)
*
* (called by wv_hw_reset())
*/
-static inline int
-wv_82586_start(device * dev)
+static inline int wv_82586_start(device * dev)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- scp_t scp; /* system configuration pointer */
- iscp_t iscp; /* intermediate scp */
- scb_t scb; /* system control block */
- ach_t cb; /* Action command header */
- u_char zeroes[512];
- int i;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ scp_t scp; /* system configuration pointer */
+ iscp_t iscp; /* intermediate scp */
+ scb_t scb; /* system control block */
+ ach_t cb; /* Action command header */
+ u8 zeroes[512];
+ int i;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name);
#endif
- /*
- * Clear the onboard RAM.
- */
- memset(&zeroes[0], 0x00, sizeof(zeroes));
- for(i = 0; i < I82586_MEMZ; i += sizeof(zeroes))
- obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes));
-
- /*
- * Construct the command unit structures:
- * scp, iscp, scb, cb.
- */
- memset(&scp, 0x00, sizeof(scp));
- scp.scp_sysbus = SCP_SY_16BBUS;
- scp.scp_iscpl = OFFSET_ISCP;
- obram_write(ioaddr, OFFSET_SCP, (unsigned char *)&scp, sizeof(scp));
-
- memset(&iscp, 0x00, sizeof(iscp));
- iscp.iscp_busy = 1;
- iscp.iscp_offset = OFFSET_SCB;
- obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
-
- /* Our first command is to reset the i82586. */
- memset(&scb, 0x00, sizeof(scb));
- scb.scb_command = SCB_CMD_RESET;
- scb.scb_cbl_offset = OFFSET_CU;
- scb.scb_rfa_offset = OFFSET_RU;
- obram_write(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
-
- set_chan_attn(ioaddr, lp->hacr);
-
- /* Wait for command to finish. */
- for(i = 1000; i > 0; i--)
- {
- obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp));
-
- if(iscp.iscp_busy == (unsigned short) 0)
- break;
-
- udelay(10);
- }
-
- if(i <= 0)
- {
+ /*
+ * Clear the onboard RAM.
+ */
+ memset(&zeroes[0], 0x00, sizeof(zeroes));
+ for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes))
+ obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes));
+
+ /*
+ * Construct the command unit structures:
+ * scp, iscp, scb, cb.
+ */
+ memset(&scp, 0x00, sizeof(scp));
+ scp.scp_sysbus = SCP_SY_16BBUS;
+ scp.scp_iscpl = OFFSET_ISCP;
+ obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp,
+ sizeof(scp));
+
+ memset(&iscp, 0x00, sizeof(iscp));
+ iscp.iscp_busy = 1;
+ iscp.iscp_offset = OFFSET_SCB;
+ obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
+ sizeof(iscp));
+
+ /* Our first command is to reset the i82586. */
+ memset(&scb, 0x00, sizeof(scb));
+ scb.scb_command = SCB_CMD_RESET;
+ scb.scb_cbl_offset = OFFSET_CU;
+ scb.scb_rfa_offset = OFFSET_RU;
+ obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+ sizeof(scb));
+
+ set_chan_attn(ioaddr, lp->hacr);
+
+ /* Wait for command to finish. */
+ for (i = 1000; i > 0; i--) {
+ obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
+ sizeof(iscp));
+
+ if (iscp.iscp_busy == (unsigned short) 0)
+ break;
+
+ udelay(10);
+ }
+
+ if (i <= 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: wv_82586_start(): iscp_busy timeout.\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wv_82586_start(): iscp_busy timeout.\n",
+ dev->name);
#endif
- return -1;
- }
+ return -1;
+ }
- /* Check command completion. */
- for(i = 15; i > 0; i--)
- {
- obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb));
+ /* Check command completion. */
+ for (i = 15; i > 0; i--) {
+ obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+ sizeof(scb));
- if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
- break;
+ if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
+ break;
- udelay(10);
- }
+ udelay(10);
+ }
- if (i <= 0)
- {
+ if (i <= 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
- dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
+ printk(KERN_INFO
+ "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
+ dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
#endif
- return -1;
- }
+ return -1;
+ }
- wv_ack(dev);
+ wv_ack(dev);
- /* Set the action command header. */
- memset(&cb, 0x00, sizeof(cb));
- cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
- cb.ac_link = OFFSET_CU;
- obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
+ /* Set the action command header. */
+ memset(&cb, 0x00, sizeof(cb));
+ cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
+ cb.ac_link = OFFSET_CU;
+ obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
- if(wv_synchronous_cmd(dev, "diag()") == -1)
- return -1;
+ if (wv_synchronous_cmd(dev, "diag()") == -1)
+ return -1;
- obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
- if(cb.ac_status & AC_SFLD_FAIL)
- {
+ obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
+ if (cb.ac_status & AC_SFLD_FAIL) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: wv_82586_start(): i82586 Self Test failed.\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wv_82586_start(): i82586 Self Test failed.\n",
+ dev->name);
#endif
- return -1;
- }
-
+ return -1;
+ }
#ifdef DEBUG_I82586_SHOW
- wv_scb_show(ioaddr);
+ wv_scb_show(ioaddr);
#endif
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -3383,184 +3312,179 @@ wv_82586_start(device * dev)
*
* (called by wv_hw_reset(), wv_82586_reconfig())
*/
-static void
-wv_82586_config(device * dev)
+static void wv_82586_config(device * dev)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- unsigned short txblock;
- unsigned short txpred;
- unsigned short tx_addr;
- unsigned short nop_addr;
- unsigned short tbd_addr;
- unsigned short cfg_addr;
- unsigned short ias_addr;
- unsigned short mcs_addr;
- ac_tx_t tx;
- ac_nop_t nop;
- ac_cfg_t cfg; /* Configure action */
- ac_ias_t ias; /* IA-setup action */
- ac_mcs_t mcs; /* Multicast setup */
- struct dev_mc_list * dmi;
- unsigned long x;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ unsigned short txblock;
+ unsigned short txpred;
+ unsigned short tx_addr;
+ unsigned short nop_addr;
+ unsigned short tbd_addr;
+ unsigned short cfg_addr;
+ unsigned short ias_addr;
+ unsigned short mcs_addr;
+ ac_tx_t tx;
+ ac_nop_t nop;
+ ac_cfg_t cfg; /* Configure action */
+ ac_ias_t ias; /* IA-setup action */
+ ac_mcs_t mcs; /* Multicast setup */
+ struct dev_mc_list *dmi;
+ unsigned long flags;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
#endif
- x = wv_splhi();
-
- /* Calculate addresses of next block and previous block. */
- txblock = lp->tx_first_free;
- txpred = txblock - TXBLOCKZ;
- if(txpred < OFFSET_CU)
- txpred += NTXBLOCKS * TXBLOCKZ;
- lp->tx_first_free += TXBLOCKZ;
- if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
- lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
-
- lp->tx_n_in_use++;
-
- /* Calculate addresses of the different parts of the block. */
- tx_addr = txblock;
- nop_addr = tx_addr + sizeof(tx);
- tbd_addr = nop_addr + sizeof(nop);
- cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */
- ias_addr = cfg_addr + sizeof(cfg);
- mcs_addr = ias_addr + sizeof(ias);
-
- /*
- * Transmit command
- */
- tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */
- obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
- (unsigned char *) &tx.tx_h.ac_status,
- sizeof(tx.tx_h.ac_status));
-
- /*
- * NOP command
- */
- nop.nop_h.ac_status = 0;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
- (unsigned char *) &nop.nop_h.ac_status,
- sizeof(nop.nop_h.ac_status));
- nop.nop_h.ac_link = nop_addr;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
- (unsigned char *) &nop.nop_h.ac_link,
- sizeof(nop.nop_h.ac_link));
-
- /* Create a configure action. */
- memset(&cfg, 0x00, sizeof(cfg));
-
- /*
- * For Linux we invert AC_CFG_ALOC() so as to conform
- * to the way that net packets reach us from above.
- * (See also ac_tx_t.)
- *
- * Updated from Wavelan Manual WCIN085B
- */
- cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
- cfg.cfg_fifolim = AC_CFG_FIFOLIM(4);
- cfg.cfg_byte8 = AC_CFG_SAV_BF(1) |
- AC_CFG_SRDY(0);
- cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
- AC_CFG_ILPBCK(0) |
- AC_CFG_PRELEN(AC_CFG_PLEN_2) |
- AC_CFG_ALOC(1) |
- AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
- cfg.cfg_byte10 = AC_CFG_BOFMET(1) |
- AC_CFG_ACR(6) |
- AC_CFG_LINPRIO(0);
- cfg.cfg_ifs = 0x20;
- cfg.cfg_slotl = 0x0C;
- cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) |
- AC_CFG_SLTTMHI(0);
- cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
- AC_CFG_BTSTF(0) |
- AC_CFG_CRC16(0) |
- AC_CFG_NCRC(0) |
- AC_CFG_TNCRS(1) |
- AC_CFG_MANCH(0) |
- AC_CFG_BCDIS(0) |
- AC_CFG_PRM(lp->promiscuous);
- cfg.cfg_byte15 = AC_CFG_ICDS(0) |
- AC_CFG_CDTF(0) |
- AC_CFG_ICSS(0) |
- AC_CFG_CSTF(0);
+ save_flags(flags);
+ cli();
+
+ /* Calculate addresses of next block and previous block. */
+ txblock = lp->tx_first_free;
+ txpred = txblock - TXBLOCKZ;
+ if (txpred < OFFSET_CU)
+ txpred += NTXBLOCKS * TXBLOCKZ;
+ lp->tx_first_free += TXBLOCKZ;
+ if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+ lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+
+ lp->tx_n_in_use++;
+
+ /* Calculate addresses of the different parts of the block. */
+ tx_addr = txblock;
+ nop_addr = tx_addr + sizeof(tx);
+ tbd_addr = nop_addr + sizeof(nop);
+ cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */
+ ias_addr = cfg_addr + sizeof(cfg);
+ mcs_addr = ias_addr + sizeof(ias);
+
+ /*
+ * Transmit command
+ */
+ tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */
+ obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
+ (unsigned char *) &tx.tx_h.ac_status,
+ sizeof(tx.tx_h.ac_status));
+
+ /*
+ * NOP command
+ */
+ nop.nop_h.ac_status = 0;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+ (unsigned char *) &nop.nop_h.ac_status,
+ sizeof(nop.nop_h.ac_status));
+ nop.nop_h.ac_link = nop_addr;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+ (unsigned char *) &nop.nop_h.ac_link,
+ sizeof(nop.nop_h.ac_link));
+
+ /* Create a configure action. */
+ memset(&cfg, 0x00, sizeof(cfg));
+
+ /*
+ * For Linux we invert AC_CFG_ALOC() so as to conform
+ * to the way that net packets reach us from above.
+ * (See also ac_tx_t.)
+ *
+ * Updated from Wavelan Manual WCIN085B
+ */
+ cfg.cfg_byte_cnt =
+ AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
+ cfg.cfg_fifolim = AC_CFG_FIFOLIM(4);
+ cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0);
+ cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
+ AC_CFG_ILPBCK(0) |
+ AC_CFG_PRELEN(AC_CFG_PLEN_2) |
+ AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
+ cfg.cfg_byte10 = AC_CFG_BOFMET(1) |
+ AC_CFG_ACR(6) | AC_CFG_LINPRIO(0);
+ cfg.cfg_ifs = 0x20;
+ cfg.cfg_slotl = 0x0C;
+ cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0);
+ cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
+ AC_CFG_BTSTF(0) |
+ AC_CFG_CRC16(0) |
+ AC_CFG_NCRC(0) |
+ AC_CFG_TNCRS(1) |
+ AC_CFG_MANCH(0) |
+ AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous);
+ cfg.cfg_byte15 = AC_CFG_ICDS(0) |
+ AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0);
/*
cfg.cfg_min_frm_len = AC_CFG_MNFRM(64);
*/
- cfg.cfg_min_frm_len = AC_CFG_MNFRM(8);
-
- cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure);
- cfg.cfg_h.ac_link = ias_addr;
- obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg));
-
- /* Set up the MAC address */
- memset(&ias, 0x00, sizeof(ias));
- ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
- ias.ias_h.ac_link = mcs_addr;
- memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr));
- obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias));
-
- /* Initialize adapter's Ethernet multicast addresses */
- memset(&mcs, 0x00, sizeof(mcs));
- mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
- mcs.mcs_h.ac_link = nop_addr;
- mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
- obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs));
-
- /* Any address to set? */
- if(lp->mc_count)
- {
- for(dmi=dev->mc_list; dmi; dmi=dmi->next)
- outsw(PIOP1(ioaddr), (u_short *) dmi->dmi_addr,
- WAVELAN_ADDR_SIZE >> 1);
+ cfg.cfg_min_frm_len = AC_CFG_MNFRM(8);
+
+ cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure);
+ cfg.cfg_h.ac_link = ias_addr;
+ obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg));
+
+ /* Set up the MAC address */
+ memset(&ias, 0x00, sizeof(ias));
+ ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
+ ias.ias_h.ac_link = mcs_addr;
+ memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0],
+ sizeof(ias.ias_addr));
+ obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias));
+
+ /* Initialize adapter's Ethernet multicast addresses */
+ memset(&mcs, 0x00, sizeof(mcs));
+ mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
+ mcs.mcs_h.ac_link = nop_addr;
+ mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
+ obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs));
+
+ /* Any address to set? */
+ if (lp->mc_count) {
+ for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+ outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr,
+ WAVELAN_ADDR_SIZE >> 1);
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n",
- dev->name, lp->mc_count);
- for(dmi=dev->mc_list; dmi; dmi=dmi->next)
- printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
- dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
- dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
+ printk(KERN_DEBUG
+ "%s: wv_82586_config(): set %d multicast addresses:\n",
+ dev->name, lp->mc_count);
+ for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+ printk(KERN_DEBUG
+ " %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dmi->dmi_addr[0], dmi->dmi_addr[1],
+ dmi->dmi_addr[2], dmi->dmi_addr[3],
+ dmi->dmi_addr[4], dmi->dmi_addr[5]);
#endif
- }
-
- /*
- * Overwrite the predecessor NOP link
- * so that it points to the configure action.
- */
- nop_addr = txpred + sizeof(tx);
- nop.nop_h.ac_status = 0;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
- (unsigned char *)&nop.nop_h.ac_status,
- sizeof(nop.nop_h.ac_status));
- nop.nop_h.ac_link = cfg_addr;
- obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
- (unsigned char *) &nop.nop_h.ac_link,
- sizeof(nop.nop_h.ac_link));
-
- /* If watchdog not already active, activate it... */
- if(lp->watchdog.prev == (timer_list *) NULL)
- {
- /* set timer to expire in WATCHDOG_JIFFIES */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
- }
-
- lp->reconfig_82586 = 0;
-
- if(lp->tx_first_in_use == I82586NULL)
- lp->tx_first_in_use = txblock;
-
- if(lp->tx_n_in_use < NTXBLOCKS - 1)
- dev->tbusy = 0;
-
- wv_splx(x);
+ }
+
+ /*
+ * Overwrite the predecessor NOP link
+ * so that it points to the configure action.
+ */
+ nop_addr = txpred + sizeof(tx);
+ nop.nop_h.ac_status = 0;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+ (unsigned char *) &nop.nop_h.ac_status,
+ sizeof(nop.nop_h.ac_status));
+ nop.nop_h.ac_link = cfg_addr;
+ obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+ (unsigned char *) &nop.nop_h.ac_link,
+ sizeof(nop.nop_h.ac_link));
+
+ /* If watchdog not already active, activate it... */
+ if (lp->watchdog.prev == (timer_list *) NULL) {
+ /* set timer to expire in WATCHDOG_JIFFIES */
+ lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+ add_timer(&lp->watchdog);
+ }
+
+ lp->reconfig_82586 = 0;
+ if (lp->tx_first_in_use == I82586NULL)
+ lp->tx_first_in_use = txblock;
+
+ if (lp->tx_n_in_use < NTXBLOCKS - 1)
+ netif_wake_queue(dev);
+
+ restore_flags(flags);
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name);
#endif
}
@@ -3569,28 +3493,29 @@ wv_82586_config(device * dev)
* This routine, called by wavelan_close(), gracefully stops the
* WaveLAN controller (i82586).
*/
-static inline void
-wv_82586_stop(device * dev)
+static inline void wv_82586_stop(device * dev)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- u_short scb_cmd;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ u16 scb_cmd;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
#endif
- /* Suspend both command unit and receive unit. */
- scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS);
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *)&scb_cmd, sizeof(scb_cmd));
- set_chan_attn(ioaddr, lp->hacr);
+ /* Suspend both command unit and receive unit. */
+ scb_cmd =
+ (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC &
+ SCB_CMD_RUC_SUS);
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cmd, sizeof(scb_cmd));
+ set_chan_attn(ioaddr, lp->hacr);
- /* No more interrupts */
- wv_ints_off(dev);
+ /* No more interrupts */
+ wv_ints_off(dev);
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name);
#endif
}
@@ -3604,49 +3529,47 @@ wv_82586_stop(device * dev)
* 4. Start the LAN controller's command unit
* 5. Start the LAN controller's receive unit
*/
-static int
-wv_hw_reset(device * dev)
+static int wv_hw_reset(device * dev)
{
- net_local * lp = (net_local *)dev->priv;
- u_long ioaddr = dev->base_addr;
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name,
- (unsigned int)dev);
+ printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name,
+ (unsigned int) dev);
#endif
- /* If watchdog was activated, kill it! */
- if(lp->watchdog.prev != (timer_list *) NULL)
- del_timer(&lp->watchdog);
+ /* If watchdog was activated, kill it! */
+ if (lp->watchdog.prev != (timer_list *) NULL)
+ del_timer(&lp->watchdog);
- /* Increase the number of resets done. */
- lp->nresets++;
+ /* Increase the number of resets done. */
+ lp->nresets++;
- wv_hacr_reset(ioaddr);
- lp->hacr = HACR_DEFAULT;
+ wv_hacr_reset(ioaddr);
+ lp->hacr = HACR_DEFAULT;
- if((wv_mmc_init(dev) < 0) ||
- (wv_82586_start(dev) < 0))
- return -1;
+ if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0))
+ return -1;
- /* Enable the card to send interrupts. */
- wv_ints_on(dev);
+ /* Enable the card to send interrupts. */
+ wv_ints_on(dev);
- /* Start card functions */
- if(wv_cu_start(dev) < 0)
- return -1;
+ /* Start card functions */
+ if (wv_cu_start(dev) < 0)
+ return -1;
- /* Setup the controller and parameters */
- wv_82586_config(dev);
+ /* Setup the controller and parameters */
+ wv_82586_config(dev);
- /* Finish configuration with the receive unit */
- if(wv_ru_start(dev) < 0)
- return -1;
+ /* Finish configuration with the receive unit */
+ if (wv_ru_start(dev) < 0)
+ return -1;
#ifdef DEBUG_CONFIG_TRACE
- printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -3655,40 +3578,39 @@ wv_hw_reset(device * dev)
* As a side effect, this reads the MAC address.
* (called in wavelan_probe() and init_module())
*/
-static int
-wv_check_ioaddr(u_long ioaddr,
- u_char * mac)
+static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac)
{
- int i; /* Loop counter */
-
- /* Check if the base address if available. */
- if(check_region(ioaddr, sizeof(ha_t)))
- return EADDRINUSE; /* ioaddr already used */
-
- /* Reset host interface */
- wv_hacr_reset(ioaddr);
-
- /* Read the MAC address from the parameter storage area. */
- psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
- mac, 6);
-
- /*
- * Check the first three octets of the address for the manufacturer's code.
- * Note: if this can't find your WaveLAN card, you've got a
- * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on
- * how to configure your card.
- */
- for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
- if((mac[0] == MAC_ADDRESSES[i][0]) &&
- (mac[1] == MAC_ADDRESSES[i][1]) &&
- (mac[2] == MAC_ADDRESSES[i][2]))
- return 0;
+ int i; /* Loop counter */
+
+ /* Check if the base address if available. */
+ if (check_region(ioaddr, sizeof(ha_t)))
+ return EADDRINUSE; /* ioaddr already used */
+
+ /* Reset host interface */
+ wv_hacr_reset(ioaddr);
+
+ /* Read the MAC address from the parameter storage area. */
+ psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
+ mac, 6);
+
+ /*
+ * Check the first three octets of the address for the manufacturer's code.
+ * Note: if this can't find your WaveLAN card, you've got a
+ * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on
+ * how to configure your card.
+ */
+ for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
+ if ((mac[0] == MAC_ADDRESSES[i][0]) &&
+ (mac[1] == MAC_ADDRESSES[i][1]) &&
+ (mac[2] == MAC_ADDRESSES[i][2]))
+ return 0;
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
- ioaddr, mac[0], mac[1], mac[2]);
+ printk(KERN_WARNING
+ "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
+ ioaddr, mac[0], mac[1], mac[2]);
#endif
- return ENODEV;
+ return ENODEV;
}
/************************ INTERRUPT HANDLING ************************/
@@ -3697,133 +3619,121 @@ wv_check_ioaddr(u_long ioaddr,
* This function is the interrupt handler for the WaveLAN card. This
* routine will be called whenever:
*/
-static void
-wavelan_interrupt(int irq,
- void * dev_id,
- struct pt_regs * regs)
+static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- device * dev;
- u_long ioaddr;
- net_local * lp;
- u_short hasr;
- u_short status;
- u_short ack_cmd;
+ device *dev;
+ unsigned long ioaddr;
+ net_local *lp;
+ u16 hasr;
+ u16 status;
+ u16 ack_cmd;
- dev = dev_id;
+ dev = dev_id;
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
#endif
- lp = (net_local *) dev->priv;
- ioaddr = dev->base_addr;
+ lp = (net_local *) dev->priv;
+ ioaddr = dev->base_addr;
- /* Prevent reentrance. What should we do here? */
-#ifdef DEBUG_INTERRUPT_ERROR
- if(dev->interrupt)
- printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
- dev->name);
-#endif
- dev->interrupt = 1;
+ /* Prevent reentrance. What should we do here? */
- if((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR)
- {
- u_char dce_status;
+ if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) {
+ u8 dce_status;
- /*
- * Interrupt from the modem management controller.
- * This will clear it -- ignored for now.
- */
- mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status));
+ /*
+ * Interrupt from the modem management controller.
+ * This will clear it -- ignored for now.
+ */
+ mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status,
+ sizeof(dce_status));
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
- dev->name, dce_status);
+ printk(KERN_INFO
+ "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
+ dev->name, dce_status);
#endif
- }
+ }
- if((hasr & HASR_82586_INTR) == 0)
- {
- dev->interrupt = 0;
+ if ((hasr & HASR_82586_INTR) == 0) {
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "%s: wavelan_interrupt(): interrupt not coming from i82586\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wavelan_interrupt(): interrupt not coming from i82586\n",
+ dev->name);
#endif
- return;
- }
+ return;
+ }
- /* Read interrupt data. */
- obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
- (unsigned char *) &status, sizeof(status));
+ /* Read interrupt data. */
+ obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+ (unsigned char *) &status, sizeof(status));
- /*
- * Acknowledge the interrupt(s).
- */
- ack_cmd = status & SCB_ST_INT;
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &ack_cmd, sizeof(ack_cmd));
- set_chan_attn(ioaddr, lp->hacr);
+ /*
+ * Acknowledge the interrupt(s).
+ */
+ ack_cmd = status & SCB_ST_INT;
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &ack_cmd, sizeof(ack_cmd));
+ set_chan_attn(ioaddr, lp->hacr);
#ifdef DEBUG_INTERRUPT_INFO
- printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n",
- dev->name, status);
+ printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n",
+ dev->name, status);
#endif
- /* Command completed. */
- if((status & SCB_ST_CX) == SCB_ST_CX)
- {
+ /* Command completed. */
+ if ((status & SCB_ST_CX) == SCB_ST_CX) {
#ifdef DEBUG_INTERRUPT_INFO
- printk(KERN_DEBUG "%s: wavelan_interrupt(): command completed.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wavelan_interrupt(): command completed.\n",
+ dev->name);
#endif
- wv_complete(dev, ioaddr, lp);
-
- /* If watchdog was activated, kill it ! */
- if(lp->watchdog.prev != (timer_list *) NULL)
- del_timer(&lp->watchdog);
- if(lp->tx_n_in_use > 0)
- {
- /* set timer to expire in WATCHDOG_JIFFIES */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
+ wv_complete(dev, ioaddr, lp);
+
+ /* If watchdog was activated, kill it ! */
+ if (lp->watchdog.prev != (timer_list *) NULL)
+ del_timer(&lp->watchdog);
+ if (lp->tx_n_in_use > 0) {
+ /* set timer to expire in WATCHDOG_JIFFIES */
+ lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+ add_timer(&lp->watchdog);
+ }
}
- }
- /* Frame received. */
- if((status & SCB_ST_FR) == SCB_ST_FR)
- {
+ /* Frame received. */
+ if ((status & SCB_ST_FR) == SCB_ST_FR) {
#ifdef DEBUG_INTERRUPT_INFO
- printk(KERN_DEBUG "%s: wavelan_interrupt(): received packet.\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: wavelan_interrupt(): received packet.\n",
+ dev->name);
#endif
- wv_receive(dev);
- }
+ wv_receive(dev);
+ }
- /* Check the state of the command unit. */
- if(((status & SCB_ST_CNA) == SCB_ST_CNA) ||
- (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start))
- {
+ /* Check the state of the command unit. */
+ if (((status & SCB_ST_CNA) == SCB_ST_CNA) ||
+ (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && netif_running(dev))) {
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wavelan_interrupt(): CU inactive -- restarting\n",
+ dev->name);
#endif
- wv_hw_reset(dev);
- }
+ wv_hw_reset(dev);
+ }
- /* Check the state of the command unit. */
- if(((status & SCB_ST_RNR) == SCB_ST_RNR) ||
- (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start))
- {
+ /* Check the state of the command unit. */
+ if (((status & SCB_ST_RNR) == SCB_ST_RNR) ||
+ (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && netif_running(dev))) {
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wavelan_interrupt(): RU not ready -- restarting\n",
+ dev->name);
#endif
- wv_hw_reset(dev);
- }
-
- dev->interrupt = 0;
+ wv_hw_reset(dev);
+ }
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
#endif
}
@@ -3838,83 +3748,81 @@ wavelan_interrupt(int irq,
* way because the overhead of add_timer() and del_timer() is nothing
* and because it avoids calling the watchdog, saving some CPU.
*/
-static void
-wavelan_watchdog(u_long a)
+static void wavelan_watchdog(unsigned long a)
{
- device * dev;
- net_local * lp;
- u_long ioaddr;
- unsigned long x;
- unsigned int nreaped;
+ device *dev;
+ net_local *lp;
+ unsigned long ioaddr;
+ unsigned long flags;
+ unsigned int nreaped;
- dev = (device *) a;
- ioaddr = dev->base_addr;
- lp = (net_local *) dev->priv;
+ dev = (device *) a;
+ ioaddr = dev->base_addr;
+ lp = (net_local *) dev->priv;
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
+ printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
#endif
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
- dev->name);
+ printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
+ dev->name);
#endif
- x = wv_splhi();
-
- dev = (device *) a;
- ioaddr = dev->base_addr;
- lp = (net_local *) dev->priv;
+ save_flags(flags);
+ cli();
+
+ dev = (device *) a;
+ ioaddr = dev->base_addr;
+ lp = (net_local *) dev->priv;
- if(lp->tx_n_in_use <= 0)
- {
- wv_splx(x);
- return;
- }
+ if (lp->tx_n_in_use <= 0) {
+ restore_flags(flags);
+ return;
+ }
- nreaped = wv_complete(dev, ioaddr, lp);
+ nreaped = wv_complete(dev, ioaddr, lp);
#ifdef DEBUG_INTERRUPT_INFO
- printk(KERN_DEBUG "%s: wavelan_watchdog(): %d reaped, %d remain.\n",
- dev->name, nreaped, lp->tx_n_in_use);
+ printk(KERN_DEBUG
+ "%s: wavelan_watchdog(): %d reaped, %d remain.\n",
+ dev->name, nreaped, lp->tx_n_in_use);
#endif
#ifdef DEBUG_PSA_SHOW
- {
- psa_t psa;
- psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
- wv_psa_show(&psa);
- }
+ {
+ psa_t psa;
+ psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+ wv_psa_show(&psa);
+ }
#endif
#ifdef DEBUG_MMC_SHOW
- wv_mmc_show(dev);
+ wv_mmc_show(dev);
#endif
#ifdef DEBUG_I82586_SHOW
- wv_cu_show(dev);
+ wv_cu_show(dev);
#endif
- /* If no buffer has been freed */
- if(nreaped == 0)
- {
+ /* If no buffer has been freed */
+ if (nreaped == 0) {
#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_INFO "%s: wavelan_watchdog(): cleanup failed, trying reset\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wavelan_watchdog(): cleanup failed, trying reset\n",
+ dev->name);
#endif
- wv_hw_reset(dev);
- }
- else
- /* Reset watchdog for next transmission. */
- if(lp->tx_n_in_use > 0)
- {
- /* set timer to expire in WATCHDOG_JIFFIES */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
- }
-
- wv_splx(x);
+ wv_hw_reset(dev);
+ } else
+ /* Reset watchdog for next transmission. */
+ if (lp->tx_n_in_use > 0) {
+ /* set timer to expire in WATCHDOG_JIFFIES */
+ lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+ add_timer(&lp->watchdog);
+ }
+ restore_flags(flags);
+
#ifdef DEBUG_INTERRUPT_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
#endif
}
@@ -3930,56 +3838,55 @@ wavelan_watchdog(u_long a)
* Configure and start up the WaveLAN PCMCIA adaptor.
* Called by NET3 when it "opens" the device.
*/
-static int
-wavelan_open(device * dev)
+static int wavelan_open(device * dev)
{
- u_long x;
+ unsigned long flags;
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
- (unsigned int) dev);
+ printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
+ (unsigned int) dev);
#endif
- /* Check irq */
- if(dev->irq == 0)
- {
+ /* Check irq */
+ if (dev->irq == 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
+ printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n",
+ dev->name);
#endif
- return -ENXIO;
- }
+ return -ENXIO;
+ }
- if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
- {
+ if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
+ {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
+ printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n",
+ dev->name);
#endif
- return -EAGAIN;
- }
-
- x = wv_splhi();
- if(wv_hw_reset(dev) != -1)
- {
- dev->interrupt = 0;
- dev->start = 1;
- }
- else
- {
- free_irq(dev->irq, dev);
+ return -EAGAIN;
+ }
+
+ save_flags(flags);
+ cli();
+
+ if (wv_hw_reset(dev) != -1) {
+ netif_start_queue(dev);
+ } else {
+ free_irq(dev->irq, dev);
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n",
- dev->name);
+ printk(KERN_INFO
+ "%s: wavelan_open(): impossible to start the card\n",
+ dev->name);
#endif
- return -EAGAIN;
- }
- wv_splx(x);
-
- MOD_INC_USE_COUNT;
+ return -EAGAIN;
+ }
+ restore_flags(flags);
+
+ MOD_INC_USE_COUNT;
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -3987,40 +3894,34 @@ wavelan_open(device * dev)
* Shut down the WaveLAN ISA card.
* Called by NET3 when it "closes" the device.
*/
-static int
-wavelan_close(device * dev)
+static int wavelan_close(device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local *lp = (net_local *) dev->priv;
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
- (unsigned int) dev);
+ printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
+ (unsigned int) dev);
#endif
- /* Don't do the job twice. */
- if(dev->start == 0)
- return 0;
-
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
- /* If watchdog was activated, kill it! */
- if(lp->watchdog.prev != (timer_list *) NULL)
- del_timer(&lp->watchdog);
+ /* If watchdog was activated, kill it! */
+ if (lp->watchdog.prev != (timer_list *) NULL)
+ del_timer(&lp->watchdog);
- /*
- * Flush the Tx and disable Rx.
- */
- wv_82586_stop(dev);
+ /*
+ * Flush the Tx and disable Rx.
+ */
+ wv_82586_stop(dev);
- free_irq(dev->irq, dev);
+ free_irq(dev->irq, dev);
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -4029,113 +3930,111 @@ wavelan_close(device * dev)
* device structure
* (called by wavelan_probe() and via init_module()).
*/
-static int __init
-wavelan_config(device * dev)
+static int __init wavelan_config(device * dev)
{
- u_long ioaddr = dev->base_addr;
- u_char irq_mask;
- int irq;
- net_local * lp;
+ unsigned long ioaddr = dev->base_addr;
+ u8 irq_mask;
+ int irq;
+ net_local *lp;
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%x)\n", dev->name,
- (unsigned int)dev, ioaddr);
+ printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%x)\n",
+ dev->name, (unsigned int) dev, ioaddr);
#endif
- /* Check IRQ argument on command line. */
- if(dev->irq != 0)
- {
- irq_mask = wv_irq_to_psa(dev->irq);
+ /* Check IRQ argument on command line. */
+ if (dev->irq != 0) {
+ irq_mask = wv_irq_to_psa(dev->irq);
- if(irq_mask == 0)
- {
+ if (irq_mask == 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_WARNING "%s: wavelan_config(): invalid IRQ %d ignored.\n",
- dev->name, dev->irq);
+ printk(KERN_WARNING
+ "%s: wavelan_config(): invalid IRQ %d ignored.\n",
+ dev->name, dev->irq);
#endif
- dev->irq = 0;
- }
- else
- {
+ dev->irq = 0;
+ } else {
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "%s: wavelan_config(): changing IRQ to %d\n",
- dev->name, dev->irq);
+ printk(KERN_DEBUG
+ "%s: wavelan_config(): changing IRQ to %d\n",
+ dev->name, dev->irq);
#endif
- psa_write(ioaddr, HACR_DEFAULT,
- psaoff(0, psa_int_req_no), &irq_mask, 1);
- /* update the Wavelan checksum */
- update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
- wv_hacr_reset(ioaddr);
+ psa_write(ioaddr, HACR_DEFAULT,
+ psaoff(0, psa_int_req_no), &irq_mask, 1);
+ /* update the Wavelan checksum */
+ update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
+ wv_hacr_reset(ioaddr);
+ }
}
- }
- psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), &irq_mask, 1);
- if((irq = wv_psa_to_irq(irq_mask)) == -1)
- {
+ psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no),
+ &irq_mask, 1);
+ if ((irq = wv_psa_to_irq(irq_mask)) == -1) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_INFO "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
- dev->name, irq_mask);
+ printk(KERN_INFO
+ "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
+ dev->name, irq_mask);
#endif
- return EAGAIN;
- }
-
- dev->irq = irq;
-
- request_region(ioaddr, sizeof(ha_t), "wavelan");
-
- dev->mem_start = 0x0000;
- dev->mem_end = 0x0000;
- dev->if_port = 0;
-
- /* Initialize device structures */
- dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
- if(dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0x00, sizeof(net_local));
- lp = (net_local *)dev->priv;
-
- /* Back link to the device structure. */
- lp->dev = dev;
- /* Add the device at the beginning of the linked list. */
- lp->next = wavelan_list;
- wavelan_list = lp;
-
- lp->hacr = HACR_DEFAULT;
-
- lp->watchdog.function = wavelan_watchdog;
- lp->watchdog.data = (unsigned long) dev;
- lp->promiscuous = 0;
- lp->mc_count = 0;
-
- /*
- * Fill in the fields of the device structure
- * with generic Ethernet values.
- */
- ether_setup(dev);
-
- dev->open = wavelan_open;
- dev->stop = wavelan_close;
- dev->hard_start_xmit = wavelan_packet_xmit;
- dev->get_stats = wavelan_get_stats;
- dev->set_multicast_list = &wavelan_set_multicast_list;
+ return EAGAIN;
+ }
+
+ dev->irq = irq;
+
+ request_region(ioaddr, sizeof(ha_t), "wavelan");
+
+ dev->mem_start = 0x0000;
+ dev->mem_end = 0x0000;
+ dev->if_port = 0;
+
+ /* Initialize device structures */
+ dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0x00, sizeof(net_local));
+ lp = (net_local *) dev->priv;
+
+ /* Back link to the device structure. */
+ lp->dev = dev;
+ /* Add the device at the beginning of the linked list. */
+ lp->next = wavelan_list;
+ wavelan_list = lp;
+
+ lp->hacr = HACR_DEFAULT;
+
+ lp->watchdog.function = wavelan_watchdog;
+ lp->watchdog.data = (unsigned long) dev;
+ lp->promiscuous = 0;
+ lp->mc_count = 0;
+
+ /*
+ * Fill in the fields of the device structure
+ * with generic Ethernet values.
+ */
+ ether_setup(dev);
+
+ dev->open = wavelan_open;
+ dev->stop = wavelan_close;
+ dev->hard_start_xmit = wavelan_packet_xmit;
+ dev->get_stats = wavelan_get_stats;
+ dev->set_multicast_list = &wavelan_set_multicast_list;
#ifdef SET_MAC_ADDRESS
- dev->set_mac_address = &wavelan_set_mac_address;
-#endif /* SET_MAC_ADDRESS */
+ dev->set_mac_address = &wavelan_set_mac_address;
+#endif /* SET_MAC_ADDRESS */
-#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
- dev->do_ioctl = wavelan_ioctl;
- dev->get_wireless_stats = wavelan_get_wireless_stats;
+#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
+ dev->do_ioctl = wavelan_ioctl;
+ dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif
- dev->mtu = WAVELAN_MTU;
+ dev->mtu = WAVELAN_MTU;
- /* Display nice information. */
- wv_init_info(dev);
+ /* Display nice information. */
+ wv_init_info(dev);
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
#endif
- return 0;
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -4146,90 +4045,88 @@ wavelan_config(device * dev)
* We follow the example in drivers/net/ne.c.
* (called in "Space.c")
*/
-int __init
-wavelan_probe(device * dev)
+int __init wavelan_probe(device * dev)
{
- short base_addr;
- mac_addr mac; /* MAC address (check existence of WaveLAN) */
- int i;
- int r;
+ short base_addr;
+ mac_addr mac; /* MAC address (check existence of WaveLAN) */
+ int i;
+ int r;
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n",
- dev->name, (unsigned int)dev, (unsigned int)dev->base_addr);
+ printk(KERN_DEBUG
+ "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n",
+ dev->name, (unsigned int) dev,
+ (unsigned int) dev->base_addr);
#endif
#ifdef STRUCT_CHECK
- if (wv_struct_check() != (char *) NULL)
- {
- printk(KERN_WARNING "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n",
- dev->name, wv_struct_check());
- return ENODEV;
- }
-#endif /* STRUCT_CHECK */
-
- /* Check the value of the command line parameter for base address. */
- base_addr = dev->base_addr;
-
- /* Don't probe at all. */
- if(base_addr < 0)
- {
+ if (wv_struct_check() != (char *) NULL) {
+ printk(KERN_WARNING
+ "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n",
+ dev->name, wv_struct_check());
+ return ENODEV;
+ }
+#endif /* STRUCT_CHECK */
+
+ /* Check the value of the command line parameter for base address. */
+ base_addr = dev->base_addr;
+
+ /* Don't probe at all. */
+ if (base_addr < 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_WARNING "%s: wavelan_probe(): invalid base address\n",
- dev->name);
+ printk(KERN_WARNING
+ "%s: wavelan_probe(): invalid base address\n",
+ dev->name);
#endif
- return ENXIO;
- }
-
- /* Check a single specified location. */
- if(base_addr > 0x100)
- {
- /* Check if there is something at this base address */
- if((r = wv_check_ioaddr(base_addr, mac)) == 0)
- {
- memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
- r = wavelan_config(dev);
+ return ENXIO;
}
+ /* Check a single specified location. */
+ if (base_addr > 0x100) {
+ /* Check if there is something at this base address */
+ if ((r = wv_check_ioaddr(base_addr, mac)) == 0) {
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
+ r = wavelan_config(dev);
+ }
#ifdef DEBUG_CONFIG_INFO
- if(r != 0)
- printk(KERN_DEBUG "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n",
- dev->name, base_addr);
+ if (r != 0)
+ printk(KERN_DEBUG
+ "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n",
+ dev->name, base_addr);
#endif
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
+ printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
#endif
- return r;
- }
-
- /* Scan all possible addresses of the WaveLAN hardware. */
- for(i = 0; i < NELS(iobase); i++)
- {
- /* Check whether there is something at this base address. */
- if(wv_check_ioaddr(iobase[i], mac) == 0)
- {
- dev->base_addr = iobase[i]; /* Copy base address. */
- memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
- if(wavelan_config(dev) == 0)
- {
+ return r;
+ }
+
+ /* Scan all possible addresses of the WaveLAN hardware. */
+ for (i = 0; i < NELS(iobase); i++) {
+ /* Check whether there is something at this base address. */
+ if (wv_check_ioaddr(iobase[i], mac) == 0) {
+ dev->base_addr = iobase[i]; /* Copy base address. */
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
+ if (wavelan_config(dev) == 0) {
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
+ printk(KERN_DEBUG
+ "%s: <-wavelan_probe()\n",
+ dev->name);
#endif
- return 0;
- }
+ return 0;
+ }
+ }
}
- }
- /* We may have touched base_addr. Another driver may not like it. */
- dev->base_addr = base_addr;
+ /* We may have touched base_addr. Another driver may not like it. */
+ dev->base_addr = base_addr;
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n",
- dev->name);
+ printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n",
+ dev->name);
#endif
- return ENODEV;
+ return ENODEV;
}
/****************************** MODULE ******************************/
@@ -4243,120 +4140,115 @@ wavelan_probe(device * dev)
* Insertion of the module
* I'm now quite proud of the multi-device support.
*/
-int
-init_module(void)
+int init_module(void)
{
- mac_addr mac; /* MAC address (check WaveLAN existence) */
- int ret = -EIO; /* Return error if no cards found */
- int i;
+ mac_addr mac; /* MAC address (check WaveLAN existence) */
+ int ret = -EIO; /* Return error if no cards found */
+ int i;
#ifdef DEBUG_MODULE_TRACE
- printk(KERN_DEBUG "-> init_module()\n");
+ printk(KERN_DEBUG "-> init_module()\n");
#endif
- /* If probing is asked */
- if(io[0] == 0)
- {
+ /* If probing is asked */
+ if (io[0] == 0) {
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
- printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
+ printk(KERN_WARNING
+ "WaveLAN init_module(): doing device probing (bad !)\n");
+ printk(KERN_WARNING
+ "Specify base addresses while loading module to correct the problem\n");
#endif
- /* Copy the basic set of address to be probed. */
- for(i = 0; i < NELS(iobase); i++)
- io[i] = iobase[i];
- }
+ /* Copy the basic set of address to be probed. */
+ for (i = 0; i < NELS(iobase); i++)
+ io[i] = iobase[i];
+ }
- /* Loop on all possible base addresses. */
- i = -1;
- while((io[++i] != 0) && (i < NELS(io)))
- {
- /* Check if there is something at this base address. */
- if(wv_check_ioaddr(io[i], mac) == 0)
- {
- device * dev;
-
- /* Create device and set basic arguments. */
- dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
- if(dev==NULL)
- {
- ret = -ENOMEM;
- break;
- }
- memset(dev, 0x00, sizeof(struct net_device));
- dev->name = name[i];
- dev->base_addr = io[i];
- dev->irq = irq[i];
- dev->init = &wavelan_config;
- memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
-
- /* Try to create the device. */
- if(register_netdev(dev) != 0)
- {
- /* Deallocate everything. */
- /* Note: if dev->priv is mallocated, there is no way to fail. */
- kfree_s(dev, sizeof(struct net_device));
- }
- else
- {
- /* If at least one device OK, we do not fail */
- ret = 0;
- }
- } /* if there is something at the address */
- } /* Loop on all addresses. */
+ /* Loop on all possible base addresses. */
+ i = -1;
+ while ((io[++i] != 0) && (i < NELS(io))) {
+ /* Check if there is something at this base address. */
+ if (wv_check_ioaddr(io[i], mac) == 0) {
+ device *dev;
+
+ /* Create device and set basic arguments. */
+ dev =
+ kmalloc(sizeof(struct net_device), GFP_KERNEL);
+ if (dev == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+ memset(dev, 0x00, sizeof(struct net_device));
+ dev->name = name[i];
+ dev->base_addr = io[i];
+ dev->irq = irq[i];
+ dev->init = &wavelan_config;
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
+
+ /* Try to create the device. */
+ if (register_netdev(dev) != 0) {
+ /* Deallocate everything. */
+ /* Note: if dev->priv is mallocated, there is no way to fail. */
+ kfree_s(dev, sizeof(struct net_device));
+ } else {
+ /* If at least one device OK, we do not fail */
+ ret = 0;
+ }
+ } /* if there is something at the address */
+ } /* Loop on all addresses. */
#ifdef DEBUG_CONFIG_ERROR
- if(wavelan_list == (net_local *) NULL)
- printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
+ if (wavelan_list == (net_local *) NULL)
+ printk(KERN_WARNING
+ "WaveLAN init_module(): no device found\n");
#endif
#ifdef DEBUG_MODULE_TRACE
- printk(KERN_DEBUG "<- init_module()\n");
+ printk(KERN_DEBUG "<- init_module()\n");
#endif
- return ret;
+ return ret;
}
/*------------------------------------------------------------------*/
/*
* Removal of the module
*/
-void
-cleanup_module(void)
+void cleanup_module(void)
{
#ifdef DEBUG_MODULE_TRACE
- printk(KERN_DEBUG "-> cleanup_module()\n");
+ printk(KERN_DEBUG "-> cleanup_module()\n");
#endif
- /* Loop on all devices and release them. */
- while(wavelan_list != (net_local *) NULL)
- {
- device * dev = wavelan_list->dev;
+ /* Loop on all devices and release them. */
+ while (wavelan_list != (net_local *) NULL) {
+ device *dev = wavelan_list->dev;
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "%s: cleanup_module(): removing device at 0x%x\n",
- dev->name, (unsigned int) dev);
+ printk(KERN_DEBUG
+ "%s: cleanup_module(): removing device at 0x%x\n",
+ dev->name, (unsigned int) dev);
#endif
- /* Release the ioport region. */
- release_region(dev->base_addr, sizeof(ha_t));
+ /* Release the ioport region. */
+ release_region(dev->base_addr, sizeof(ha_t));
- /* Definitely remove the device. */
- unregister_netdev(dev);
+ /* Definitely remove the device. */
+ unregister_netdev(dev);
- /* Unlink the device. */
- wavelan_list = wavelan_list->next;
+ /* Unlink the device. */
+ wavelan_list = wavelan_list->next;
- /* Free pieces. */
- kfree_s(dev->priv, sizeof(struct net_local));
- kfree_s(dev, sizeof(struct net_device));
- }
+ /* Free pieces. */
+ kfree_s(dev->priv, sizeof(struct net_local));
+ kfree_s(dev, sizeof(struct net_device));
+ }
#ifdef DEBUG_MODULE_TRACE
- printk(KERN_DEBUG "<- cleanup_module()\n");
+ printk(KERN_DEBUG "<- cleanup_module()\n");
#endif
}
-#endif /* MODULE */
+#endif /* MODULE */
/*
* This software may only be used and distributed
@@ -4379,7 +4271,7 @@ cleanup_module(void)
*
* Thanks go also to:
* James Ashton (jaa101@syseng.anu.edu.au),
- * Alan Cox (iialan@iiit.swan.ac.uk),
+ * Alan Cox (alan@redhat.com),
* Allan Creighton (allanc@cs.usyd.edu.au),
* Matthew Geier (matthew@cs.usyd.edu.au),
* Remo di Giovanni (remo@cs.usyd.edu.au),
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 37cf755ed..a907847c0 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1,6 +1,6 @@
/* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */
/*
- Written 1997-1998 by Donald Becker.
+ Written 1997-1999 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -17,13 +17,13 @@
*/
static const char *version =
-"yellowfin.c:v1.02 7/26/98 Written by Donald Becker, becker@cesdis.edu\n"
+"yellowfin.c:v1.03a 7/30/99 Written by Donald Becker, becker@cesdis.edu\n"
" http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html\n";
/* A few user-configurable values. */
+static int debug = 1;
static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
static int mtu = 0;
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
/* System-wide count of bogus-rx frames. */
@@ -50,25 +50,37 @@ static int rx_copybreak = 0;
static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* Do ugly workaround for GX server chipset errata. */
+static int gx_fix = 0;
+
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for efficiency.
- Making the Tx ring too large decreases the effectiveness of channel
+ Making the Tx queue too long decreases the effectiveness of channel
bonding and packet priority.
There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 16
-#define RX_RING_SIZE 32
+#define TX_QUEUE_SIZE 12 /* Must be > 4 && <= TX_RING_SIZE */
+#define RX_RING_SIZE 64
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT ((2000*HZ)/1000)
+#define TX_TIMEOUT (2*HZ)
+
+#define yellowfin_debug debug
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
#include <linux/module.h>
+#include <linux/modversions.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
-#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
@@ -76,22 +88,20 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/bitops.h>
#include <asm/unaligned.h>
+#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#define RUN_AT(x) (jiffies + (x))
-
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
+/* Condensed operations for readability.
+ Compatibility defines are now in drv_compat.h */
-/* The PCI I/O space extent. */
-#define YELLOWFIN_TOTAL_SIZE 0x100
+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-int yellowfin_debug = 1;
/*
Theory of Operation
@@ -174,31 +184,49 @@ See Packet Engines confidential appendix (prototype chips only).
/* A few values that may be tweaked. */
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-#ifndef PCI_VENDOR_ID_PKT_ENG /* To be defined in linux/pci.h */
-#define PCI_VENDOR_ID_PKT_ENG 0x1000 /* Hmm, likely number.. */
-#define PCI_DEVICE_ID_SYM58C885 0x0701
-#define PCI_DEVICE_ID_YELLOWFIN 0x0702
-#endif
-
/* The rest of these values should never change. */
-static void yellowfin_timer(unsigned long data);
+enum capability_flags {
+ HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
+ HasMACAddrBug=32, /* Really only on early revs. */
+};
+
+
+/* The PCI I/O space extent. */
+#define YELLOWFIN_SIZE 0x100
+
+#define YELLOWFIN_MODULE_NAME "yellowfin"
+#define PFX YELLOWFIN_MODULE_NAME ": "
+
+
+typedef enum {
+ YELLOWFIN_GNIC,
+ SYM83C885,
+} chip_t;
-enum capability_flags {HasMII=1, FullTxStatus=2};
-static struct chip_info {
- u16 vendor_id, device_id, device_id_mask, pci_flags;
+
+struct chip_info {
const char *name;
- void (*media_timer)(unsigned long data);
- u32 chip_rev; /* As read from ChipRev, not PCI dev ID. */
int flags;
-} chip_tbl[] = {
- {0x1000, 0x0702, 0xffff, 0, "Yellowfin G-NIC Gbit Ethernet",
- yellowfin_timer, 0x0702, FullTxStatus},
- {0x1000, 0x0701, 0xffff, 0, "Symbios SYM83C885",
- yellowfin_timer, 0x0701, HasMII},
- {0,},
};
+
+/* index by chip_t */
+static struct chip_info chip_info[] = {
+ {"Yellowfin G-NIC Gigabit Ethernet",
+ FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug},
+ {"Symbios SYM83C885", HasMII },
+};
+
+
+static struct pci_device_id yellowfin_pci_tbl[] __devinitdata = {
+ { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, YELLOWFIN_GNIC },
+ { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SYM83C885 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl);
+
+
/* Offsets to the Yellowfin registers. Various sizes and alignments. */
enum yellowfin_offsets {
TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C,
@@ -206,7 +234,8 @@ enum yellowfin_offsets {
RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C,
RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58,
EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86,
- ChipRev=0x8C, DMACtrl=0x90, Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4,
+ ChipRev=0x8C, DMACtrl=0x90, TxThreshold=0x94,
+ Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4,
MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC,
MII_Status=0xAE,
RxDepth=0xB8, FlowCtrl=0xBC,
@@ -215,29 +244,35 @@ enum yellowfin_offsets {
EEFeature=0xF5,
};
-/* The Yellowfin Rx and Tx buffer descriptors. */
+/* The Yellowfin Rx and Tx buffer descriptors.
+ Elements are written as 32 bit for endian portability. */
struct yellowfin_desc {
- u16 request_cnt;
- u16 cmd;
+ u32 dbdma_cmd;
u32 addr;
u32 branch_addr;
- u16 result_cnt;
- u16 status;
+ u32 result_status;
};
struct tx_status_words {
+#if defined(__powerpc__)
+ u16 tx_errs;
+ u16 tx_cnt;
+ u16 paused;
+ u16 total_tx_cnt;
+#else /* Little endian chips. */
u16 tx_cnt;
u16 tx_errs;
u16 total_tx_cnt;
u16 paused;
+#endif
};
/* Bits in yellowfin_desc.cmd */
enum desc_cmd_bits {
- CMD_TX_PKT=0x1000, CMD_RX_BUF=0x2000, CMD_TXSTATUS=0x3000,
- CMD_NOP=0x6000, CMD_STOP=0x7000,
- BRANCH_ALWAYS=0x0C, INTR_ALWAYS=0x30, WAIT_ALWAYS=0x03,
- BRANCH_IFTRUE=0x04,
+ CMD_TX_PKT=0x10000000, CMD_RX_BUF=0x20000000, CMD_TXSTATUS=0x30000000,
+ CMD_NOP=0x60000000, CMD_STOP=0x70000000,
+ BRANCH_ALWAYS=0x0C0000, INTR_ALWAYS=0x300000, WAIT_ALWAYS=0x030000,
+ BRANCH_IFTRUE=0x040000,
};
/* Bits in yellowfin_desc.status */
@@ -249,6 +284,7 @@ enum intr_status_bits {
IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80,
IntrEarlyRx=0x100, IntrWakeup=0x200, };
+#define PRIV_ALIGN 31 /* Required alignment mask */
struct yellowfin_private {
/* Descriptor rings first for alignment. Tx requires a second descriptor
for status. */
@@ -256,21 +292,23 @@ struct yellowfin_private {
struct yellowfin_desc tx_ring[TX_RING_SIZE*2];
const char *product_name;
struct net_device *next_module;
+ void *priv_addr; /* Unaligned address for kfree */
/* The addresses of receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
struct tx_status_words tx_status[TX_RING_SIZE];
struct timer_list timer; /* Media selection timer. */
- struct enet_statistics stats;
- spinlock_t lock;
+ struct net_device_stats stats;
/* Frequently used and paired value: keep adjacent for cache effect. */
- int chip_id;
+ struct pci_dev *pci_dev;
+ int chip_id, flags;
struct yellowfin_desc *rx_head_desc;
- struct tx_status_words *tx_tail_desc;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
- unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
+ struct tx_status_words *tx_tail_desc;
+ unsigned int cur_tx, dirty_tx;
+ int tx_threshold;
unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int duplex_lock:1;
@@ -281,19 +319,21 @@ struct yellowfin_private {
u16 advertising; /* NWay media advertisement */
unsigned char phys[2]; /* MII device addresses. */
u32 pad[4]; /* Used for 32-byte alignment */
+ spinlock_t lock;
};
+
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(min_pci_latency, "i");
MODULE_PARM(mtu, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(gx_fix, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-static struct net_device *yellowfin_probe1(long ioaddr, int irq, int chip_id, int options);
+
static int read_eeprom(long ioaddr, int location);
static int mdio_read(long ioaddr, int phy_id, int location);
static void mdio_write(long ioaddr, int phy_id, int location, int value);
@@ -309,197 +349,17 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg
static int yellowfin_rx(struct net_device *dev);
static void yellowfin_error(struct net_device *dev, int intr_status);
static int yellowfin_close(struct net_device *dev);
-static struct enet_statistics *yellowfin_get_stats(struct net_device *dev);
+static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-
-
-/* A list of all installed Yellowfin devices, for removing the driver module. */
-static struct net_device *root_yellowfin_dev = NULL;
-
-static int __init yellowfin_probe(void)
-{
- int cards_found = 0;
- int pci_index = 0;
- unsigned char pci_bus, pci_device_fn;
-
- if ( ! pci_present())
- return -ENODEV;
-
- for (;pci_index < 0xff; pci_index++) {
- u8 pci_latency;
- u16 pci_command, new_command, vendor, device;
- int chip_idx;
- int irq;
- long ioaddr;
- struct pci_dev *pdev;
-
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
- pci_index,
- &pci_bus, &pci_device_fn)
- != PCIBIOS_SUCCESSFUL)
- break;
-
- pdev = pci_find_slot (pci_bus, pci_device_fn);
- if (!pdev) break;
- vendor = pdev->vendor;
- device = pdev->device;
-
- for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == chip_tbl[chip_idx].vendor_id
- && (device & chip_tbl[chip_idx].device_id_mask) ==
- chip_tbl[chip_idx].device_id)
- break;
- if (chip_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
- continue;
-
- {
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->resource[0].start;
- irq = pdev->irq;
- }
-
- if (yellowfin_debug > 2)
- printk(KERN_INFO "Found %s at I/O %#lx, IRQ %d.\n",
- chip_tbl[chip_idx].name, ioaddr, irq);
-
- if (check_region(ioaddr, YELLOWFIN_TOTAL_SIZE))
- continue;
-
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled the"
- " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
- pci_bus, pci_device_fn, pci_command, new_command);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
-
- if(yellowfin_probe1(ioaddr, irq, chip_idx, cards_found))
- {
- /* Get and check the bus-master and latency values. */
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < min_pci_latency) {
- printk(KERN_INFO " PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to %d clocks.\n",
- pci_latency, min_pci_latency);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency);
- } else if (yellowfin_debug > 1)
- printk(KERN_INFO " PCI latency timer (CFLT) is %#x.\n",
- pci_latency);
- cards_found++;
- }
- }
-
- return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device *yellowfin_probe1(long ioaddr, int irq, int chip_id, int card_idx)
-{
- static int did_version = 0; /* Already printed version info. */
- struct yellowfin_private *yp;
- int option, i;
- struct net_device *dev;
-
- if (yellowfin_debug > 0 && did_version++ == 0)
- printk(version);
-
- dev = init_etherdev(NULL, sizeof(struct yellowfin_private));
-
- printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",
- dev->name, chip_tbl[chip_id].name, inl(ioaddr + ChipRev), ioaddr);
-
- if (inw(ioaddr + ChipRev) == 0x0702)
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
- else {
- int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);
- }
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-
- /* Reset the chip. */
- outl(0x80000000, ioaddr + DMACtrl);
-
- /* We do a request_region() only to register /proc/ioports info. */
- request_region(ioaddr, YELLOWFIN_TOTAL_SIZE, dev->name);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- /* Make certain the descriptor lists are aligned. */
- yp = (void *)(((long)kmalloc(sizeof(*yp), GFP_KERNEL) + 31) & ~31);
- memset(yp, 0, sizeof(*yp));
- dev->priv = yp;
-
- yp->next_module = root_yellowfin_dev;
- root_yellowfin_dev = dev;
-
- yp->chip_id = chip_id;
- yp->lock = SPIN_LOCK_UNLOCKED;
-
- option = card_idx < MAX_UNITS ? options[card_idx] : 0;
- if (dev->mem_start)
- option = dev->mem_start;
-
- /* The lower four bits are the media type. */
- if (option > 0) {
- if (option & 0x200)
- yp->full_duplex = 1;
- yp->default_port = option & 15;
- if (yp->default_port)
- yp->medialock = 1;
- }
- if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
- yp->full_duplex = 1;
-
- if (yp->full_duplex)
- yp->duplex_lock = 1;
-
- /* The Yellowfin-specific entries in the device structure. */
- dev->open = &yellowfin_open;
- dev->hard_start_xmit = &yellowfin_start_xmit;
- dev->stop = &yellowfin_close;
- dev->get_stats = &yellowfin_get_stats;
- dev->set_multicast_list = &set_rx_mode;
-#ifdef HAVE_PRIVATE_IOCTL
- dev->do_ioctl = &mii_ioctl;
-#endif
- dev->tx_timeout = yellowfin_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- if (mtu)
- dev->mtu = mtu;
-
- if (chip_tbl[yp->chip_id].flags & HasMII) {
- int phy, phy_idx = 0;
- for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
- int mii_status = mdio_read(ioaddr, phy, 1);
- if (mii_status != 0xffff &&
- mii_status != 0x0000) {
- yp->phys[phy_idx++] = phy;
- yp->advertising = mdio_read(ioaddr, phy, 4);
- printk(KERN_INFO "%s: MII PHY found at address %d, status "
- "0x%4.4x advertising %4.4x.\n",
- dev->name, phy, mii_status, yp->advertising);
- }
- }
- yp->mii_cnt = phy_idx;
- }
-
- return dev;
-}
-static int read_eeprom(long ioaddr, int location)
+static int __devinit read_eeprom(long ioaddr, int location)
{
- int bogus_cnt = 1000;
+ int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */
outb(location, ioaddr + EEAddr);
outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl);
- while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0)
+ while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0)
;
return inb(ioaddr + EERead);
}
@@ -577,13 +437,16 @@ static int yellowfin_open(struct net_device *dev)
/* Enable automatic generation of flow control frames, period 0xffff. */
outl(0x0030FFFF, ioaddr + FlowCtrl);
+ yp->tx_threshold = 32;
+ outl(yp->tx_threshold, ioaddr + TxThreshold);
+
if (dev->if_port == 0)
dev->if_port = yp->default_port;
- netif_start_queue(dev);
+ netif_start_queue (dev);
/* Setting the Rx mode will start the Rx process. */
- if (yp->chip_id == 0) {
+ if (yp->flags & IsGigabit) {
/* We are always in full-duplex mode with gigabit! */
yp->full_duplex = 1;
outw(0x01CF, ioaddr + Cnfg);
@@ -606,7 +469,7 @@ static int yellowfin_open(struct net_device *dev)
}
/* Set the timer to check for link beat. */
init_timer(&yp->timer);
- yp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ yp->timer.expires = jiffies + 3*HZ;
yp->timer.data = (unsigned long)dev;
yp->timer.function = &yellowfin_timer; /* timer handler */
add_timer(&yp->timer);
@@ -619,7 +482,7 @@ static void yellowfin_timer(unsigned long data)
struct net_device *dev = (struct net_device *)data;
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
long ioaddr = dev->base_addr;
- int next_tick = 0;
+ int next_tick = 60*HZ;
if (yellowfin_debug > 3) {
printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n",
@@ -648,10 +511,8 @@ static void yellowfin_timer(unsigned long data)
next_tick = 3*HZ;
}
- if (next_tick) {
- yp->timer.expires = RUN_AT(next_tick);
- add_timer(&yp->timer);
- }
+ yp->timer.expires = jiffies + next_tick;
+ add_timer(&yp->timer);
}
static void yellowfin_tx_timeout(struct net_device *dev)
@@ -659,34 +520,38 @@ static void yellowfin_tx_timeout(struct net_device *dev)
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
long ioaddr = dev->base_addr;
- printk(KERN_WARNING "%s: Yellowfin transmit timed out, status %8.8x, resetting...\n",
- dev->name, inl(ioaddr));
+ printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx "
+ "status %4.4x, Rx status %4.4x, resetting...\n",
+ dev->name, yp->cur_tx, yp->dirty_tx,
+ inl(ioaddr + TxStatus), inl(ioaddr + RxStatus));
-#ifndef __alpha__
- {
+ /* Note: these should be KERN_DEBUG. */
+ if (yellowfin_debug) {
int i;
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int)yp->rx_ring);
+ printk(KERN_WARNING " Rx ring %p: ", yp->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)yp->rx_ring[i].status);
- printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)yp->tx_ring);
+ printk(" %8.8x", yp->rx_ring[i].result_status);
+ printk("\n"KERN_WARNING" Tx ring %p: ", yp->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %4.4x /%4.4x", yp->tx_status[i].tx_errs, yp->tx_ring[i].status);
+ printk(" %4.4x /%8.8x", yp->tx_status[i].tx_errs,
+ yp->tx_ring[i].result_status);
printk("\n");
}
-#endif
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
+ /* If the hardware is found to hang regularly, we will update the code
+ to reinitialize the chip here. */
+ dev->if_port = 0;
- /* Trigger an immediate transmit demand. */
+ /* Wake the potentially-idle transmit channel. */
+ outl(0x10001000, dev->base_addr + TxCtrl);
+ if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
+ netif_wake_queue (dev); /* Typical path */
- dev->trans_start = jiffies;
- yp->stats.tx_errors++;
- return;
+ dev->trans_start = jiffies;
+ yp->stats.tx_errors++;
+ return;
}
-
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void yellowfin_init_ring(struct net_device *dev)
{
@@ -695,62 +560,66 @@ static void yellowfin_init_ring(struct net_device *dev)
yp->tx_full = 0;
yp->cur_rx = yp->cur_tx = 0;
- yp->dirty_rx = yp->dirty_tx = 0;
+ yp->dirty_tx = 0;
yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
yp->rx_head_desc = &yp->rx_ring[0];
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb;
-
- yp->rx_ring[i].request_cnt = yp->rx_buf_sz;
- yp->rx_ring[i].cmd = CMD_RX_BUF | INTR_ALWAYS;
+ yp->rx_ring[i].dbdma_cmd =
+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
+ yp->rx_ring[i].branch_addr = virt_to_le32desc(&yp->rx_ring[i+1]);
+ }
+ /* Mark the last entry as wrapping the ring. */
+ yp->rx_ring[i-1].branch_addr = virt_to_le32desc(&yp->rx_ring[0]);
- skb = dev_alloc_skb(yp->rx_buf_sz);
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
yp->rx_skbuff[i] = skb;
- if (skb) {
- skb->dev = dev; /* Mark as being used by this device. */
- skb_reserve(skb, 2); /* 16 byte align the IP header. */
- yp->rx_ring[i].addr = virt_to_bus(skb->tail);
- } else if (yp->dirty_rx == 0)
- yp->dirty_rx = (unsigned int)(0 - RX_RING_SIZE);
- yp->rx_ring[i].branch_addr = virt_to_bus(&yp->rx_ring[i+1]);
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
+ yp->rx_ring[i].addr = virt_to_le32desc(skb->tail);
}
- /* Mark the last entry as wrapping the ring. */
- yp->rx_ring[i-1].cmd = CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
- yp->rx_ring[i-1].branch_addr = virt_to_bus(&yp->rx_ring[0]);
+ yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-/*#define NO_TXSTATS*/
+#define NO_TXSTATS
#ifdef NO_TXSTATS
/* In this mode the Tx ring needs only a single descriptor. */
for (i = 0; i < TX_RING_SIZE; i++) {
yp->tx_skbuff[i] = 0;
- yp->tx_ring[i].cmd = CMD_STOP;
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
}
- yp->tx_ring[--i].cmd = CMD_STOP | BRANCH_ALWAYS; /* Wrap ring */
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+ /* Wrap ring */
+ yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]);
#else
/* Tx ring needs a pair of descriptors, the second for the status. */
for (i = 0; i < TX_RING_SIZE*2; i++) {
yp->tx_skbuff[i/2] = 0;
- yp->tx_ring[i].cmd = CMD_STOP; /* Branch on Tx error. */
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ /* Branch on Tx error. */
+ yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
i++;
- if (chip_tbl[yp->chip_id].flags & FullTxStatus) {
- yp->tx_ring[i].cmd = CMD_TXSTATUS;
+ if (yp->flags & FullTxStatus) {
+ yp->tx_ring[i].dbdma_cmd =
+ cpu_to_le32(CMD_TXSTATUS | sizeof(yp->tx_status[i]));
yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]);
- yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2]);
+ yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2]);
} else { /* Symbios chips write only tx_errs word. */
- yp->tx_ring[i].cmd = CMD_TXSTATUS | INTR_ALWAYS;
+ yp->tx_ring[i].dbdma_cmd =
+ cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2);
yp->tx_ring[i].request_cnt = 2;
- yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2].tx_errs);
+ yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2].tx_errs);
}
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
}
/* Wrap ring */
- yp->tx_ring[--i].cmd = CMD_TXSTATUS | BRANCH_ALWAYS | INTR_ALWAYS;
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+ yp->tx_ring[--i].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]);
#endif
yp->tx_tail_desc = &yp->tx_status[0];
return;
@@ -761,6 +630,8 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
unsigned entry;
+ netif_stop_queue (dev);
+
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
@@ -769,34 +640,42 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
yp->tx_skbuff[entry] = skb;
+ if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */
+ int cacheline_end = (virt_to_bus(skb->data) + skb->len) % 32;
+ /* Fix GX chipset errata. */
+ if (cacheline_end > 24 || cacheline_end == 0)
+ skb->len += 32 - cacheline_end + 1;
+ }
#ifdef NO_TXSTATS
- yp->tx_ring[entry].request_cnt = skb->len;
- yp->tx_ring[entry].addr = virt_to_bus(skb->data);
- yp->tx_ring[entry].status = 0;
+ yp->tx_ring[entry].addr = virt_to_le32desc(skb->data);
+ yp->tx_ring[entry].result_status = 0;
if (entry >= TX_RING_SIZE-1) {
- yp->tx_ring[0].cmd = CMD_STOP; /* New stop command. */
- yp->tx_ring[TX_RING_SIZE-1].cmd = CMD_TX_PKT | BRANCH_ALWAYS;
+ /* New stop command. */
+ yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd =
+ cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | skb->len);
} else {
- yp->tx_ring[entry+1].cmd = CMD_STOP; /* New stop command. */
- yp->tx_ring[entry].cmd = CMD_TX_PKT | BRANCH_IFTRUE;
+ yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[entry].dbdma_cmd =
+ cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | skb->len);
}
yp->cur_tx++;
#else
yp->tx_ring[entry<<1].request_cnt = skb->len;
- yp->tx_ring[entry<<1].addr = virt_to_bus(skb->data);
+ yp->tx_ring[entry<<1].addr = virt_to_le32desc(skb->data);
/* The input_last (status-write) command is constant, but we must rewrite
the subsequent 'stop' command. */
yp->cur_tx++;
{
unsigned next_entry = yp->cur_tx % TX_RING_SIZE;
- yp->tx_ring[next_entry<<1].cmd = CMD_STOP;
+ yp->tx_ring[next_entry<<1].dbdma_cmd = cpu_to_le32(CMD_STOP);
}
/* Final step -- overwrite the old 'stop' command. */
- yp->tx_ring[entry<<1].cmd =
- (entry % 6) == 0 ? CMD_TX_PKT | INTR_ALWAYS | BRANCH_IFTRUE :
- CMD_TX_PKT | BRANCH_IFTRUE;
+ yp->tx_ring[entry<<1].dbdma_cmd =
+ cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE :
+ CMD_TX_PKT | BRANCH_IFTRUE) | skb->len);
#endif
/* Non-x86 Todo: explicitly flush cache lines here. */
@@ -804,8 +683,8 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Wake the potentially-idle transmit channel. */
outl(0x10001000, dev->base_addr + TxCtrl);
- if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1)
- netif_start_queue(dev); /* Typical path */
+ if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
+ netif_start_queue (dev); /* Typical path */
else
yp->tx_full = 1;
dev->trans_start = jiffies;
@@ -855,20 +734,23 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg
#ifdef NO_TXSTATS
for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) {
int entry = yp->dirty_tx % TX_RING_SIZE;
- if (yp->tx_ring[entry].status == 0)
+ if (yp->tx_ring[entry].result_status == 0)
break;
+ yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
+ yp->stats.tx_packets++;
/* Free the original skb. */
- DEV_FREE_SKB(yp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(yp->tx_skbuff[entry]);
yp->tx_skbuff[entry] = 0;
- yp->stats.tx_packets++;
}
- if (yp->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->flags) &&
- yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 4) {
+ if (yp->tx_full
+ && yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) {
/* The ring is no longer full, clear tbusy. */
yp->tx_full = 0;
- netif_wake_queue (dev);
}
+ if (yp->tx_full)
+ netif_stop_queue(dev);
+ else
+ netif_wake_queue(dev);
#else
if (intr_status & IntrTxDone
|| yp->tx_tail_desc->tx_errs) {
@@ -892,7 +774,7 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg
#endif
if (tx_errs == 0)
break; /* It still hasn't been Txed */
- if (tx_errs & 0xF8100000) {
+ if (tx_errs & 0xF810) {
/* There was an major error, log it. */
#ifndef final_version
if (yellowfin_debug > 1)
@@ -916,12 +798,12 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg
#ifdef ETHER_STATS
if (tx_errs & 0x0400) yp->stats.tx_deferred++;
#endif
+ yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
yp->stats.collisions += tx_errs & 15;
yp->stats.tx_packets++;
}
-
/* Free the original skb. */
- DEV_FREE_SKB(yp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(yp->tx_skbuff[entry]);
yp->tx_skbuff[entry] = 0;
/* Mark status as empty. */
yp->tx_status[entry].tx_errs = 0;
@@ -935,13 +817,15 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg
}
#endif
- if (yp->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->flags) &&
- yp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
+ if (yp->tx_full
+ && yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) {
/* The ring is no longer full, clear tbusy. */
yp->tx_full = 0;
- netif_wake_queue (dev);
}
+ if (yp->tx_full)
+ netif_stop_queue(dev);
+ else
+ netif_wake_queue(dev);
yp->dirty_tx = dirty_tx;
yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE];
@@ -966,15 +850,14 @@ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *reg
/* Code that should never be run! Perhaps remove after testing.. */
{
static int stopit = 10;
- if ((!test_bit(LINK_STATE_START, &dev->state)) && --stopit < 0) {
+ if ((!(netif_running(dev))) && --stopit < 0) {
printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
dev->name);
free_irq(irq, dev);
}
}
- spin_lock (&yp->lock);
- return;
+ spin_unlock (&yp->lock);
}
/* This routine is logically part of the interrupt handler, but separated
@@ -986,21 +869,22 @@ static int yellowfin_rx(struct net_device *dev)
int boguscnt = 20;
if (yellowfin_debug > 4) {
- printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %4.4x.\n",
- entry, yp->rx_ring[entry].status);
- printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x.\n",
- entry, yp->rx_ring[entry].cmd,
- yp->rx_ring[entry].request_cnt, yp->rx_ring[entry].addr,
- yp->rx_ring[entry].result_cnt, yp->rx_ring[entry].status);
+ printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %8.8x.\n",
+ entry, yp->rx_ring[entry].result_status);
+ printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
+ entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr,
+ yp->rx_ring[entry].result_status);
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
- while (yp->rx_head_desc->status) {
+ while (yp->rx_head_desc->result_status) {
struct yellowfin_desc *desc = yp->rx_head_desc;
- u16 desc_status = desc->status;
- int data_size = desc->request_cnt - desc->result_cnt;
- u8 *buf_addr = bus_to_virt(desc->addr);
- s16 frame_status = get_unaligned((s16*)(buf_addr+data_size-2));
+ u16 desc_status = le32_to_cpu(desc->result_status) >> 16;
+ int data_size =
+ (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status))
+ & 0xffff;
+ u8 *buf_addr = le32desc_to_virt(desc->addr);
+ s16 frame_status = get_unaligned((s16*)&(buf_addr[data_size - 2]));
if (yellowfin_debug > 4)
printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n",
@@ -1011,7 +895,7 @@ static int yellowfin_rx(struct net_device *dev)
printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
" status %4.4x!\n", dev->name, desc_status);
yp->stats.rx_length_errors++;
- } else if (yp->chip_id == 0 && (frame_status & 0x0038)) {
+ } else if ((yp->flags & IsGigabit) && (frame_status & 0x0038)) {
/* There was a error. */
if (yellowfin_debug > 3)
printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n",
@@ -1021,7 +905,7 @@ static int yellowfin_rx(struct net_device *dev)
if (frame_status & 0x0008) yp->stats.rx_frame_errors++;
if (frame_status & 0x0010) yp->stats.rx_crc_errors++;
if (frame_status < 0) yp->stats.rx_dropped++;
- } else if (yp->chip_id != 0 &&
+ } else if ( !(yp->flags & IsGigabit) &&
((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
u8 status1 = buf_addr[data_size-2];
u8 status2 = buf_addr[data_size-1];
@@ -1031,14 +915,16 @@ static int yellowfin_rx(struct net_device *dev)
if (status2 & 0x04) yp->stats.rx_crc_errors++;
if (status2 & 0x80) yp->stats.rx_dropped++;
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
- } else if (memcmp(bus_to_virt(yp->rx_ring[entry].addr),
+ } else if ((yp->flags & HasMACAddrBug) &&
+ memcmp(le32desc_to_virt(yp->rx_ring[entry].addr),
dev->dev_addr, 6) != 0
- && memcmp(bus_to_virt(yp->rx_ring[entry].addr),
+ && memcmp(le32desc_to_virt(yp->rx_ring[entry].addr),
"\377\377\377\377\377\377", 6) != 0) {
- printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
- dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
- buf_addr[3], buf_addr[4], buf_addr[5]);
- bogus_rx++;
+ if (bogus_rx++ == 0)
+ printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:"
+ "%2.2x:%2.2x.\n",
+ dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
+ buf_addr[3], buf_addr[4], buf_addr[5]);
#endif
} else {
struct sk_buff *skb;
@@ -1057,10 +943,10 @@ static int yellowfin_rx(struct net_device *dev)
if (pkt_len > rx_copybreak) {
char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len);
#ifndef final_verison /* Remove after testing. */
- if (bus_to_virt(yp->rx_ring[entry].addr) != temp)
+ if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp)
printk(KERN_WARNING "%s: Warning -- the skbuff addresses "
"do not match in yellowfin_rx: %p vs. %p / %p.\n",
- dev->name, bus_to_virt(yp->rx_ring[entry].addr),
+ dev->name, le32desc_to_virt(yp->rx_ring[entry].addr),
skb->head, temp);
#endif
yp->rx_skbuff[entry] = NULL;
@@ -1070,19 +956,19 @@ static int yellowfin_rx(struct net_device *dev)
break;
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the data fields */
-#if 1
- eth_copy_and_sum(skb, bus_to_virt(yp->rx_ring[entry].addr),
- pkt_len, 0);
+#if 1 || USE_IP_CSUM
+ eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0);
skb_put(skb, pkt_len);
#else
- memcpy(skb_put(skb, pkt_len),
- bus_to_virt(yp->rx_ring[entry].addr), pkt_len);
+ memcpy(skb_put(skb, pkt_len), yp->rx_skbuff[entry]->tail,
+ pkt_len);
#endif
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
yp->stats.rx_packets++;
+ yp->stats.rx_bytes += pkt_len;
}
entry = (++yp->cur_rx) % RX_RING_SIZE;
yp->rx_head_desc = &yp->rx_ring[entry];
@@ -1090,24 +976,25 @@ static int yellowfin_rx(struct net_device *dev)
/* Refill the Rx ring buffers. */
for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {
- struct sk_buff *skb;
entry = yp->dirty_rx % RX_RING_SIZE;
if (yp->rx_skbuff[entry] == NULL) {
- skb = dev_alloc_skb(yp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
if (skb == NULL)
break; /* Better luck next round. */
+ yp->rx_skbuff[entry] = skb;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- yp->rx_ring[entry].addr = virt_to_bus(skb->tail);
- yp->rx_skbuff[entry] = skb;
+ yp->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
}
- yp->rx_ring[entry].cmd = CMD_STOP;
- yp->rx_ring[entry].status = 0; /* Clear complete bit. */
+ yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */
if (entry != 0)
- yp->rx_ring[entry - 1].cmd = CMD_RX_BUF | INTR_ALWAYS;
+ yp->rx_ring[entry - 1].dbdma_cmd =
+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
else
- yp->rx_ring[RX_RING_SIZE - 1].cmd =
- CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
+ yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd =
+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS
+ | yp->rx_buf_sz);
}
return 0;
@@ -1132,7 +1019,7 @@ static int yellowfin_close(struct net_device *dev)
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
int i;
- netif_stop_queue(dev);
+ netif_stop_queue (dev);
if (yellowfin_debug > 1) {
printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n",
@@ -1151,16 +1038,14 @@ static int yellowfin_close(struct net_device *dev)
del_timer(&yp->timer);
-#ifdef __i386__
+#if !defined(final_version) && defined(__i386__)
if (yellowfin_debug > 2) {
printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));
for (i = 0; i < TX_RING_SIZE*2; i++)
- printk(" %c #%d desc. %4.4x %4.4x %8.8x %8.8x %4.4x %4.4x.\n",
+ printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",
inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
- i, yp->tx_ring[i].cmd,
- yp->tx_ring[i].request_cnt, yp->tx_ring[i].addr,
- yp->tx_ring[i].branch_addr,
- yp->tx_ring[i].result_cnt, yp->tx_ring[i].status);
+ i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
+ yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" #%d status %4.4x %4.4x %4.4x %4.4x.\n",
@@ -1169,16 +1054,16 @@ static int yellowfin_close(struct net_device *dev)
printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring));
for (i = 0; i < RX_RING_SIZE; i++) {
- printk(KERN_DEBUG " %c #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x\n",
+ printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",
inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
- i, yp->rx_ring[i].cmd,
- yp->rx_ring[i].request_cnt, yp->rx_ring[i].addr,
- yp->rx_ring[i].result_cnt, yp->rx_ring[i].status);
+ i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,
+ yp->rx_ring[i].result_status);
if (yellowfin_debug > 6) {
- if (*(u8*)yp->rx_ring[i].addr != 0x69) {
+ if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) {
int j;
for (j = 0; j < 0x50; j++)
- printk(" %4.4x", ((u16*)yp->rx_ring[i].addr)[j]);
+ printk(" %4.4x",
+ get_unaligned(((u16*)yp->rx_ring[i].addr) + j));
printk("\n");
}
}
@@ -1190,16 +1075,16 @@ static int yellowfin_close(struct net_device *dev)
/* Free all the skbuffs in the Rx queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
- yp->rx_ring[i].cmd = CMD_STOP;
+ yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
yp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
if (yp->rx_skbuff[i]) {
- DEV_FREE_SKB(yp->rx_skbuff[i]);
+ dev_kfree_skb(yp->rx_skbuff[i]);
}
yp->rx_skbuff[i] = 0;
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (yp->tx_skbuff[i])
- DEV_FREE_SKB(yp->tx_skbuff[i]);
+ dev_kfree_skb(yp->tx_skbuff[i]);
yp->tx_skbuff[i] = 0;
}
@@ -1214,7 +1099,7 @@ static int yellowfin_close(struct net_device *dev)
return 0;
}
-static struct enet_statistics *yellowfin_get_stats(struct net_device *dev)
+static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
{
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
return &yp->stats;
@@ -1269,7 +1154,7 @@ static void set_rx_mode(struct net_device *dev)
i++, mclist = mclist->next) {
/* Due to a bug in the early chip versions, multiple filter
slots must be set for each address. */
- if (yp->chip_id == 0) {
+ if (yp->flags & HasMulticastBug) {
set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,
hash_table);
set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,
@@ -1305,7 +1190,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
return 0;
@@ -1316,40 +1201,206 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
#endif /* HAVE_PRIVATE_IOCTL */
-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-static int __init yellowfin_init_module(void)
+static int __devinit yellowfin_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- if (debug >= 0)
- yellowfin_debug = debug;
+ struct net_device *dev;
+ struct yellowfin_private *yp;
+ int option, i, irq;
+ int flags, chip_idx;
+ static int find_cnt = 0;
+ long ioaddr;
+
+ chip_idx = ent->driver_data;
+ flags = chip_info[chip_idx].flags;
+
+ dev = init_etherdev(NULL, 0);
+ if (!dev) {
+ printk (KERN_ERR PFX "cannot allocate ethernet device\n");
+ return -ENOMEM;
+ }
+
+ dev->priv = kmalloc(sizeof(*yp) + PRIV_ALIGN, GFP_KERNEL);
+ if (!dev->priv)
+ goto err_out_free_netdev;
+ yp = (void *)(((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
+ memset(yp, 0, sizeof(*yp));
+ yp->priv_addr = dev->priv; /* store real addr for kfree */
+ dev->priv = yp; /* use aligned addr */
+
+ if (!request_region (pci_resource_start (pdev, 0),
+ YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot obtain I/O port region\n");
+ goto err_out_free_priv;
+ }
+ if (!request_mem_region (pci_resource_start (pdev, 1),
+ YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot obtain MMIO region\n");
+ goto err_out_free_pio_region;
+ }
+
+ pci_enable_device (pdev);
+ pci_set_master (pdev);
+
+#ifdef USE_IO_OPS
+ ioaddr = pci_resource_start (pdev, 0);
+#else
+ ioaddr = pci_resource_start (pdev, 1);
+#endif
+ irq = pdev->irq;
+
+ printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",
+ dev->name, chip_info[chip_idx].name, inl(ioaddr + ChipRev), ioaddr);
+
+ if (flags & IsGigabit)
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
+ else {
+ int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);
+ }
+ for (i = 0; i < 5; i++)
+ printk("%2.2x:", dev->dev_addr[i]);
+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+ /* Reset the chip. */
+ outl(0x80000000, ioaddr + DMACtrl);
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ pdev->driver_data = dev;
+ yp->chip_id = chip_idx;
+ yp->flags = flags;
+ yp->lock = SPIN_LOCK_UNLOCKED;
+
+ option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
+ if (dev->mem_start)
+ option = dev->mem_start;
+
+ /* The lower four bits are the media type. */
+ if (option > 0) {
+ if (option & 0x200)
+ yp->full_duplex = 1;
+ yp->default_port = option & 15;
+ if (yp->default_port)
+ yp->medialock = 1;
+ }
+ if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
+ yp->full_duplex = 1;
+
+ if (yp->full_duplex)
+ yp->duplex_lock = 1;
+
+ /* The Yellowfin-specific entries in the device structure. */
+ dev->open = &yellowfin_open;
+ dev->hard_start_xmit = &yellowfin_start_xmit;
+ dev->stop = &yellowfin_close;
+ dev->get_stats = &yellowfin_get_stats;
+ dev->set_multicast_list = &set_rx_mode;
+#ifdef HAVE_PRIVATE_IOCTL
+ dev->do_ioctl = &mii_ioctl;
+#endif
+ dev->tx_timeout = yellowfin_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ if (mtu)
+ dev->mtu = mtu;
+
+ if (yp->flags & HasMII) {
+ int phy, phy_idx = 0;
+ for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+ int mii_status = mdio_read(ioaddr, phy, 1);
+ if (mii_status != 0xffff &&
+ mii_status != 0x0000) {
+ yp->phys[phy_idx++] = phy;
+ yp->advertising = mdio_read(ioaddr, phy, 4);
+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
+ "0x%4.4x advertising %4.4x.\n",
+ dev->name, phy, mii_status, yp->advertising);
+ }
+ }
+ yp->mii_cnt = phy_idx;
+ }
- return yellowfin_probe();
+ find_cnt++;
+
+ return 0;
+
+err_out_free_pio_region:
+ release_region (pci_resource_start (pdev, 0), YELLOWFIN_SIZE);
+err_out_free_priv:
+ kfree (dev->priv);
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+ return -ENODEV;
}
-static void __exit yellowfin_cleanup_module (void)
+static void __devexit yellowfin_remove_one (struct pci_dev *pdev)
{
- struct net_device *next_dev;
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_yellowfin_dev) {
- next_dev = ((struct yellowfin_private *)root_yellowfin_dev->priv)->next_module;
- unregister_netdev(root_yellowfin_dev);
- release_region(root_yellowfin_dev->base_addr, YELLOWFIN_TOTAL_SIZE);
- kfree(root_yellowfin_dev);
- root_yellowfin_dev = next_dev;
+ struct net_device *dev = pdev->driver_data;
+ struct yellowfin_private *np;
+
+ if (!dev) {
+ printk (KERN_ERR "remove non-existent device\n");
+ return;
}
+ np = (struct yellowfin_private *) dev->priv;
+
+ unregister_netdev (dev);
+
+#ifdef USE_IO_OPS
+ release_region (dev->base_addr, YELLOWFIN_SIZE);
+#else
+ iounmap ((void *) dev->base_addr);
+ release_mem_region (dev->base_addr, YELLOWFIN_SIZE);
+#endif
+
+ if (np->priv_addr)
+ kfree (np->priv_addr);
+
+ kfree (dev);
}
-module_init(yellowfin_init_module);
-module_exit(yellowfin_cleanup_module);
+
+static struct pci_driver yellowfin_driver = {
+ name: YELLOWFIN_MODULE_NAME,
+ id_table: yellowfin_pci_tbl,
+ probe: yellowfin_init_one,
+ remove: yellowfin_remove_one,
+};
+
+
+static int __init yellowfin_init (void)
+{
+ if (debug) /* Emit version even if no cards detected. */
+ printk(KERN_INFO "%s", version);
+
+ if (pci_register_driver (&yellowfin_driver) > 0)
+ return 0;
+
+ pci_unregister_driver (&yellowfin_driver);
+ return -ENODEV;
+}
+
+
+static void __exit yellowfin_cleanup (void)
+{
+ pci_unregister_driver (&yellowfin_driver);
+}
+
+
+module_init(yellowfin_init);
+module_exit(yellowfin_exit);
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index f48e41e7e..7ca88c26a 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -119,10 +119,13 @@ static unsigned int znet_debug = ZNET_DEBUG;
#define CMD0_STAT2 (2 << 5)
#define CMD0_STAT3 (3 << 5)
+#define TX_TIMEOUT 10
+
#define net_local znet_private
struct znet_private {
int rx_dma, tx_dma;
struct net_device_stats stats;
+ spinlock_t lock;
/* The starting, current, and end pointers for the packet buffers. */
ushort *rx_start, *rx_cur, *rx_end;
ushort *tx_start, *tx_cur, *tx_end;
@@ -190,6 +193,7 @@ static struct net_device_stats *net_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void hardware_init(struct net_device *dev);
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
+static void znet_tx_timeout (struct net_device *dev);
#ifdef notdef
static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, };
@@ -245,6 +249,7 @@ int __init znet_probe(struct net_device *dev)
dev->priv = (void *) &zn;
zn.rx_dma = netinfo->dma1;
zn.tx_dma = netinfo->dma2;
+ zn.lock = SPIN_LOCK_UNLOCKED;
/* These should never fail. You can't add devices to a sealed box! */
if (request_irq(dev->irq, &znet_interrupt, 0, "ZNet", dev)
@@ -275,6 +280,8 @@ int __init znet_probe(struct net_device *dev)
dev->stop = &znet_close;
dev->get_stats = net_get_stats;
dev->set_multicast_list = &set_multicast_list;
+ dev->tx_timeout = znet_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
/* Fill in the 'dev' with ethernet-generic values. */
ether_setup(dev);
@@ -306,41 +313,47 @@ static int znet_open(struct net_device *dev)
printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
dev->name);
- dev->tbusy = 0;
- dev->interrupt = 0;
hardware_init(dev);
- dev->start = 1;
+ netif_start_queue (dev);
return 0;
}
+
+static void znet_tx_timeout (struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+ ushort event, tx_status, rx_offset, state;
+
+ outb (CMD0_STAT0, ioaddr);
+ event = inb (ioaddr);
+ outb (CMD0_STAT1, ioaddr);
+ tx_status = inw (ioaddr);
+ outb (CMD0_STAT2, ioaddr);
+ rx_offset = inw (ioaddr);
+ outb (CMD0_STAT3, ioaddr);
+ state = inb (ioaddr);
+ printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
+ " resetting.\n", dev->name, event, tx_status, rx_offset, state);
+ if (tx_status == 0x0400)
+ printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
+ dev->name);
+ outb (CMD0_RESET, ioaddr);
+ hardware_init (dev);
+ netif_start_queue (dev);
+}
+
static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
{
int ioaddr = dev->base_addr;
struct net_local *lp = (struct net_local *)dev->priv;
+ unsigned long flags;
if (znet_debug > 4)
- printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy);
-
- /* Transmitter timeout, likely just recovery after suspending the machine. */
- if (dev->tbusy) {
- ushort event, tx_status, rx_offset, state;
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10)
- return 1;
- outb(CMD0_STAT0, ioaddr); event = inb(ioaddr);
- outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr);
- outb(CMD0_STAT2, ioaddr); rx_offset = inw(ioaddr);
- outb(CMD0_STAT3, ioaddr); state = inb(ioaddr);
- printk(KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
- " resetting.\n", dev->name, event, tx_status, rx_offset, state);
- if (tx_status == 0x0400)
- printk(KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
- dev->name);
- outb(CMD0_RESET, ioaddr);
- hardware_init(dev);
- }
+ printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
+ netif_stop_queue (dev);
+
/* Check that the part hasn't reset itself, probably from suspend. */
outb(CMD0_STAT0, ioaddr);
if (inw(ioaddr) == 0x0010
@@ -348,11 +361,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
&& inw(ioaddr) == 0x0010)
hardware_init(dev);
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- else {
+ if (1) {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = (void *)skb->data;
ushort *tx_link = zn.tx_cur - 1;
@@ -385,13 +394,18 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
zn.tx_cur += rnd_len;
}
*zn.tx_cur++ = 0;
- cli(); {
+
+ spin_lock_irqsave(&lp->lock, flags);
+ {
*tx_link = CMD0_TRANSMIT + CMD0_CHNL_1;
/* Is this always safe to do? */
outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr);
- } sti();
+ }
+ spin_unlock_irqrestore (&lp->lock, flags);
dev->trans_start = jiffies;
+ netif_start_queue (dev);
+
if (znet_debug > 4)
printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
}
@@ -403,6 +417,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
static void znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
+ struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr;
int boguscnt = 20;
@@ -411,7 +426,8 @@ static void znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
return;
}
- dev->interrupt = 1;
+ spin_lock (&lp->lock);
+
ioaddr = dev->base_addr;
outb(CMD0_STAT0, ioaddr);
@@ -432,7 +448,6 @@ static void znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
break;
if ((status & 0x0F) == 4) { /* Transmit done. */
- struct net_local *lp = (struct net_local *)dev->priv;
int tx_status;
outb(CMD0_STAT1, ioaddr);
tx_status = inw(ioaddr);
@@ -449,8 +464,7 @@ static void znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if ((tx_status | 0x0760) != 0x0760)
lp->stats.tx_errors++;
}
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue (dev);
}
if ((status & 0x40)
@@ -461,7 +475,8 @@ static void znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
outb(CMD0_ACK,ioaddr);
} while (boguscnt--);
- dev->interrupt = 0;
+ spin_unlock (&lp->lock);
+
return;
}
@@ -594,8 +609,7 @@ static int znet_close(struct net_device *dev)
unsigned long flags;
int ioaddr = dev->base_addr;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
outb(CMD0_RESET, ioaddr); /* CMD0_RESET */
@@ -728,7 +742,7 @@ static void hardware_init(struct net_device *dev)
update_stop_hit(ioaddr, 8192);
if (znet_debug > 1) printk("enabling Rx.\n");
outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr);
- dev->tbusy = 0;
+ netif_start_queue (dev);
}
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 29206729a..beb0a68b7 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -561,7 +561,8 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
if ((start ^ end) & ~0xffffUL)
maxlen = (0x10000 - start) & 0xffff;
- dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length);
+ dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length,
+ PCI_DMA_TODEVICE);
} else {
/* above 16 MB we use a bounce buffer as ISA-DMA is not possible */
maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */
@@ -661,7 +662,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
frob_econtrol (port, 1<<3, 0);
if (dma_handle)
- pci_unmap_single(priv->dev, dma_handle, length);
+ pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE);
return length - left;
}
diff --git a/drivers/pci/pcisyms.c b/drivers/pci/pcisyms.c
index 9dffe2143..310f75840 100644
--- a/drivers/pci/pcisyms.c
+++ b/drivers/pci/pcisyms.c
@@ -20,9 +20,11 @@ EXPORT_SYMBOL(pci_write_config_dword);
EXPORT_SYMBOL(pci_devices);
EXPORT_SYMBOL(pci_root_buses);
EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_find_class);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_slot);
+EXPORT_SYMBOL(pci_find_subsys);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_assign_resource);
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index e7c945c0c..7025263d4 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -2,7 +2,7 @@
PCMCIA Card Services -- core services
- cs.c 1.247 2000/01/15 04:30:35
+ cs.c 1.249 2000/02/10 23:26:11
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -69,7 +69,7 @@ static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
static const char *version =
-"cs.c 1.247 2000/01/15 04:30:35 (David Hinds)";
+"cs.c 1.249 2000/02/10 23:26:11 (David Hinds)";
#endif
#ifdef CONFIG_PCI
@@ -82,13 +82,14 @@ static const char *version =
#else
#define CB_OPT ""
#endif
-#if defined(CONFIG_APM) || defined(CONFIG_ACPI)
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) || defined(CONFIG_ACPI)
#define APM_OPT " [apm]"
#else
#define APM_OPT ""
#endif
#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \
- !defined(CONFIG_APM) && !defined(CONFIG_ACPI)
+ !defined(CONFIG_APM) && !defined(CONFIG_APM_MODULE) && \
+ !defined(CONFIG_ACPI)
#define OPTIONS " none"
#else
#define OPTIONS PCI_OPT CB_OPT APM_OPT
@@ -124,7 +125,7 @@ static int cis_speed = 300; /* ns */
static int io_speed = 0; /* ns */
/* Optional features */
-#if defined(CONFIG_APM) || defined(CONFIG_ACPI)
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) || defined(CONFIG_ACPI)
static int do_apm = 1;
MODULE_PARM(do_apm, "i");
#else
@@ -341,6 +342,7 @@ int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
s->sock = ns;
s->setup.data = sockets;
s->setup.function = &setup_socket;
+ s->setup_timeout = 0;
s->shutdown.data = sockets;
s->shutdown.function = &shutdown_socket;
/* base address = 0, map = 0 */
@@ -486,7 +488,17 @@ static void setup_socket(u_long i)
socket_info_t *s = socket_table[i];
get_socket_status(s, &val);
- if (val & SS_DETECT) {
+ if (val & SS_PENDING) {
+ /* Does the socket need more time? */
+ DEBUG(2, "cs: setup_socket(%ld): status pending\n", i);
+ if (++s->setup_timeout > 100) {
+ printk(KERN_NOTICE "cs: socket %ld voltage interrogation"
+ " timed out\n", i);
+ } else {
+ s->setup.expires = jiffies + HZ/10;
+ add_timer(&s->setup);
+ }
+ } else if (val & SS_DETECT) {
DEBUG(1, "cs: setup_socket(%ld): applying power\n", i);
s->state |= SOCKET_PRESENT;
s->socket.flags = 0;
@@ -532,7 +544,7 @@ static void reset_socket(u_long i)
udelay((long)reset_time);
s->socket.flags &= ~SS_RESET;
set_socket(s, &s->socket);
- s->unreset_timeout = 0;
+ s->setup_timeout = 0;
s->setup.expires = jiffies + unreset_delay;
s->setup.function = &unreset_socket;
add_timer(&s->setup);
@@ -571,12 +583,11 @@ static void unreset_socket(u_long i)
}
} else {
DEBUG(2, "cs: socket %ld not ready yet\n", i);
- if (s->unreset_timeout > unreset_limit) {
+ if (++s->setup_timeout > unreset_limit) {
printk(KERN_NOTICE "cs: socket %ld timed out during"
" reset\n", i);
s->state &= ~EVENT_MASK;
} else {
- s->unreset_timeout++;
s->setup.expires = jiffies + unreset_check;
add_timer(&s->setup);
}
@@ -1156,6 +1167,8 @@ struct pci_bus *pcmcia_lookup_bus(client_handle_t handle)
return s->cap.cb_dev->subordinate;
}
+EXPORT_SYMBOL(pcmcia_lookup_bus);
+
#endif
/*======================================================================
@@ -2188,7 +2201,7 @@ int CardServices(int func, void *a1, void *a2, void *a3)
{
memory_handle_t m;
int ret = pcmcia_open_memory(a1, a2, &m);
- (memory_handle_t *)a1 = m;
+ *(memory_handle_t *)a1 = m;
return ret;
}
break;
@@ -2202,7 +2215,7 @@ int CardServices(int func, void *a1, void *a2, void *a3)
{
eraseq_handle_t w;
int ret = pcmcia_register_erase_queue(a1, a2, &w);
- (eraseq_handle_t *)a1 = w;
+ *(eraseq_handle_t *)a1 = w;
return ret;
}
break;
@@ -2227,7 +2240,7 @@ int CardServices(int func, void *a1, void *a2, void *a3)
{
window_handle_t w;
int ret = pcmcia_request_window(a1, a2, &w);
- (window_handle_t *)a1 = w;
+ *(window_handle_t *)a1 = w;
return ret;
}
break;
@@ -2297,7 +2310,6 @@ EXPORT_SYMBOL(pcmcia_get_next_window);
EXPORT_SYMBOL(pcmcia_get_status);
EXPORT_SYMBOL(pcmcia_get_tuple_data);
EXPORT_SYMBOL(pcmcia_insert_card);
-EXPORT_SYMBOL(pcmcia_lookup_bus);
EXPORT_SYMBOL(pcmcia_map_mem_page);
EXPORT_SYMBOL(pcmcia_modify_configuration);
EXPORT_SYMBOL(pcmcia_modify_window);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index cac2d350a..f355c337b 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -131,7 +131,7 @@ typedef struct socket_info_t {
u_int real_clients;
client_handle_t reset_handle;
struct timer_list setup, shutdown;
- u_long unreset_timeout;
+ u_long setup_timeout;
pccard_mem_map cis_mem;
u_char *cis_virt;
config_t *config;
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 73c177d8d..18d47d9a8 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -82,9 +82,9 @@ static const char *version =
static void irq_count(int, void *, struct pt_regs *);
static inline int _check_irq(int irq, int flags)
{
- if (request_irq(irq, irq_count, flags, "x", NULL) != 0)
+ if (request_irq(irq, irq_count, flags, "x", irq_count) != 0)
return -1;
- free_irq(irq, NULL);
+ free_irq(irq, irq_count);
return 0;
}
@@ -570,28 +570,26 @@ static void irq_count(int irq, void *dev, struct pt_regs *regs)
DEBUG(2, "-> hit on irq %d\n", irq);
}
-static u_int __init test_irq(u_short sock, int irq, int pci)
+static u_int __init test_irq(u_short sock, int irq)
{
- u_char csc = (pci) ? 0 : irq;
- DEBUG(2, " testing %s irq %d\n", pci ? "PCI" : "ISA", irq);
-
- if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0)
+ DEBUG(2, " testing ISA irq %d\n", irq);
+ if (request_irq(irq, irq_count, 0, "scan", irq_count) != 0)
return 1;
irq_hits = 0; irq_sock = sock;
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
if (irq_hits) {
- free_irq(irq, NULL);
+ free_irq(irq, irq_count);
DEBUG(2, " spurious hit!\n");
return 1;
}
/* Generate one interrupt */
- i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4));
+ i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
udelay(1000);
- free_irq(irq, NULL);
+ free_irq(irq, irq_count);
/* mask all interrupts */
i365_set(sock, I365_CSCINT, 0);
@@ -617,10 +615,10 @@ static u_int __init isa_scan(u_short sock, u_int mask0)
set_bridge_state(sock);
i365_set(sock, I365_CSCINT, 0);
for (i = 0; i < 16; i++)
- if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0))
+ if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0))
mask1 |= (1 << i);
for (i = 0; i < 16; i++)
- if ((mask1 & (1 << i)) && (test_irq(sock, i, 0) != 0))
+ if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
mask1 ^= (1 << i);
}
@@ -1543,7 +1541,7 @@ static int __init init_i82365(void)
/* Set up interrupt handler(s) */
#ifdef CONFIG_ISA
if (grab_irq != 0)
- request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
+ request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
#endif
if (register_ss_entry(sockets, &pcic_operations) != 0)
@@ -1573,7 +1571,7 @@ static void __exit exit_i82365(void)
del_timer(&poll_timer);
#ifdef CONFIG_ISA
if (grab_irq != 0)
- free_irq(cs_irq, NULL);
+ free_irq(cs_irq, pcic_interrupt);
#endif
for (i = 0; i < sockets; i++) {
/* Turn off all interrupt sources! */
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index ff25ac893..8939ea9f6 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -2,7 +2,7 @@
Device driver for Databook TCIC-2 PCMCIA controller
- tcic.c 1.108 1999/12/09 20:17:29
+ tcic.c 1.111 2000/02/15 04:13:12
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -60,7 +60,7 @@
static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
static const char *version =
-"tcic.c 1.108 1999/12/09 20:17:29 (David Hinds)";
+"tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)";
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
#else
#define DEBUG(n, args...)
@@ -243,11 +243,11 @@ static u_int __init try_irq(int irq)
u_short cfg;
irq_hits = 0;
- if (request_irq(irq, irq_count, 0, "irq scan", NULL) != 0)
+ if (request_irq(irq, irq_count, 0, "irq scan", irq_count) != 0)
return -1;
mdelay(10);
if (irq_hits) {
- free_irq(irq, NULL);
+ free_irq(irq, irq_count);
return -1;
}
@@ -258,7 +258,7 @@ static u_int __init try_irq(int irq)
tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM);
udelay(1000);
- free_irq(irq, NULL);
+ free_irq(irq, irq_count);
/* Turn off interrupts */
tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF);
@@ -299,9 +299,9 @@ static u_int __init irq_scan(u_int mask0)
/* Fallback: just find interrupts that aren't in use */
for (i = 0; i < 16; i++)
if ((mask0 & (1 << i)) &&
- (request_irq(i, irq_count, 0, "x", NULL) == 0)) {
+ (request_irq(i, irq_count, 0, "x", irq_count) == 0)) {
mask1 |= (1 << i);
- free_irq(i, NULL);
+ free_irq(i, irq_count);
}
printk("default");
}
@@ -475,7 +475,8 @@ static int __init init_tcic(void)
u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
for (i = 15; i > 0; i--)
if ((cs_mask & (1 << i)) &&
- (request_irq(i, tcic_interrupt, 0, "tcic", NULL) == 0))
+ (request_irq(i, tcic_interrupt, 0, "tcic",
+ tcic_interrupt) == 0))
break;
cs_irq = i;
if (cs_irq == 0) poll_interval = HZ;
@@ -501,7 +502,7 @@ static int __init init_tcic(void)
printk(KERN_NOTICE "tcic: register_ss_entry() failed\n");
release_region(tcic_base, 16);
if (cs_irq != 0)
- free_irq(cs_irq, NULL);
+ free_irq(cs_irq, tcic_interrupt);
return -ENODEV;
}
@@ -519,7 +520,7 @@ static void __exit exit_tcic(void)
cli();
if (cs_irq != 0) {
tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
- free_irq(cs_irq, NULL);
+ free_irq(cs_irq, tcic_interrupt);
}
if (tcic_timer_pending)
del_timer(&poll_timer);
diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c
index 62d295a8e..01c76073f 100644
--- a/drivers/sbus/audio/audio.c
+++ b/drivers/sbus/audio/audio.c
@@ -1,4 +1,4 @@
-/* $Id: audio.c,v 1.48 2000/02/09 22:33:19 davem Exp $
+/* $Id: audio.c,v 1.49 2000/02/17 05:52:41 davem Exp $
* drivers/sbus/audio/audio.c
*
* Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
@@ -32,6 +32,7 @@
#include <linux/init.h>
#include <linux/soundcard.h>
#include <linux/version.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/delay.h>
#include <asm/pgtable.h>
@@ -2198,9 +2199,8 @@ int __init sparcaudio_init(void)
#endif
/* Register our character device driver with the VFS. */
- if (register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops))
+ if (devfs_register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops))
return -EIO;
-
#ifdef CONFIG_SPARCAUDIO_AMD7930
amd7930_init();
@@ -2221,7 +2221,7 @@ int __init sparcaudio_init(void)
#ifdef MODULE
void cleanup_module(void)
{
- unregister_chrdev(SOUND_MAJOR, "sparcaudio");
+ devfs_unregister_chrdev(SOUND_MAJOR, "sparcaudio");
}
#endif
diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
index 82e0fc494..e155a73b4 100644
--- a/drivers/sbus/audio/cs4231.c
+++ b/drivers/sbus/audio/cs4231.c
@@ -1,4 +1,4 @@
-/* $Id: cs4231.c,v 1.42 2000/01/28 13:42:48 jj Exp $
+/* $Id: cs4231.c,v 1.43 2000/02/18 13:49:39 davem Exp $
* drivers/sbus/audio/cs4231.c
*
* Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -1171,11 +1171,11 @@ static int cs4231_open(struct inode * inode, struct file * file, struct sparcaud
static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
{
struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
- void (*dma_unmap_single)(struct sbus_dev *, dma_addr_t, size_t) = sbus_unmap_single;
+ void (*dma_unmap_single)(struct sbus_dev *, dma_addr_t, size_t, int) = sbus_unmap_single;
#ifdef EB4231_SUPPORT
if (cs4231_chip->status & CS_STATUS_IS_EBUS)
- dma_unmap_single = (void (*)(struct sbus_dev *, dma_addr_t, size_t)) pci_unmap_single;
+ dma_unmap_single = (void (*)(struct sbus_dev *, dma_addr_t, size_t, int)) pci_unmap_single;
#endif
/* zero out any info about what data we have as well */
if (file->f_mode & FMODE_READ) {
@@ -1184,14 +1184,16 @@ static void cs4231_release(struct inode * inode, struct file * file, struct spar
if (cs4231_chip->input_dma_handle) {
dma_unmap_single(drv->dev,
cs4231_chip->input_dma_handle,
- cs4231_chip->input_dma_size);
+ cs4231_chip->input_dma_size,
+ SBUS_DMA_FROMDEVICE);
cs4231_chip->input_dma_handle = 0;
cs4231_chip->input_dma_size = 0;
}
if (cs4231_chip->input_next_dma_handle) {
dma_unmap_single(drv->dev,
cs4231_chip->input_next_dma_handle,
- cs4231_chip->input_next_dma_size);
+ cs4231_chip->input_next_dma_size,
+ SBUS_DMA_FROMDEVICE);
cs4231_chip->input_next_dma_handle = 0;
cs4231_chip->input_next_dma_size = 0;
}
@@ -1203,14 +1205,16 @@ static void cs4231_release(struct inode * inode, struct file * file, struct spar
if (cs4231_chip->output_dma_handle) {
dma_unmap_single(drv->dev,
cs4231_chip->output_dma_handle,
- cs4231_chip->output_dma_size);
+ cs4231_chip->output_dma_size,
+ SBUS_DMA_TODEVICE);
cs4231_chip->output_dma_handle = 0;
cs4231_chip->output_dma_size = 0;
}
if (cs4231_chip->output_next_dma_handle) {
dma_unmap_single(drv->dev,
cs4231_chip->output_next_dma_handle,
- cs4231_chip->output_next_dma_size);
+ cs4231_chip->output_next_dma_size,
+ SBUS_DMA_TODEVICE);
cs4231_chip->output_next_dma_handle = 0;
cs4231_chip->output_next_dma_size = 0;
}
@@ -1248,7 +1252,8 @@ static void cs4231_playintr(struct sparcaudio_driver *drv, int push)
if (cs4231_chip->output_dma_handle) {
sbus_unmap_single(drv->dev,
cs4231_chip->output_dma_handle,
- cs4231_chip->output_dma_size);
+ cs4231_chip->output_dma_size,
+ SBUS_DMA_TODEVICE);
cs4231_chip->output_dma_handle = 0;
cs4231_chip->output_dma_size = 0;
cs4231_chip->playing_count--;
@@ -1267,7 +1272,8 @@ static void cs4231_playintr(struct sparcaudio_driver *drv, int push)
cs4231_chip->output_next_dma_handle =
sbus_map_single(drv->dev,
(char *)cs4231_chip->output_ptr,
- cs4231_chip->output_size);
+ cs4231_chip->output_size,
+ SBUS_DMA_TODEVICE);
cs4231_chip->output_next_dma_size = cs4231_chip->output_size;
sbus_writel(cs4231_chip->output_next_dma_handle,
cs4231_chip->regs + APCPNVA);
@@ -1297,7 +1303,8 @@ static void eb4231_playintr(struct sparcaudio_driver *drv)
if (cs4231_chip->output_dma_handle) {
pci_unmap_single((struct pci_dev *)drv->dev,
cs4231_chip->output_dma_handle,
- cs4231_chip->output_dma_size);
+ cs4231_chip->output_dma_size,
+ PCI_DMA_TODEVICE);
cs4231_chip->output_dma_handle = 0;
cs4231_chip->output_dma_size = 0;
cs4231_chip->playing_count--;
@@ -1316,7 +1323,8 @@ static void eb4231_playintr(struct sparcaudio_driver *drv)
cs4231_chip->output_next_dma_handle =
pci_map_single((struct pci_dev *)drv->dev,
(char *)cs4231_chip->output_ptr,
- cs4231_chip->output_size);
+ cs4231_chip->output_size,
+ PCI_DMA_TODEVICE);
cs4231_chip->output_next_dma_size = cs4231_chip->output_size;
writel(cs4231_chip->output_next_dma_size,
@@ -1362,7 +1370,8 @@ static int cs4231_recintr(struct sparcaudio_driver *drv)
if (cs4231_chip->input_dma_handle) {
sbus_unmap_single(drv->dev,
cs4231_chip->input_dma_handle,
- cs4231_chip->input_dma_size);
+ cs4231_chip->input_dma_size,
+ SBUS_DMA_FROMDEVICE);
cs4231_chip->input_dma_handle = 0;
cs4231_chip->input_dma_size = 0;
cs4231_chip->recording_count--;
@@ -1384,7 +1393,8 @@ static int cs4231_recintr(struct sparcaudio_driver *drv)
cs4231_chip->input_next_dma_handle =
sbus_map_single(drv->dev,
(char *)cs4231_chip->input_ptr,
- cs4231_chip->input_size);
+ cs4231_chip->input_size,
+ SBUS_DMA_FROMDEVICE);
cs4231_chip->input_next_dma_size = cs4231_chip->input_size;
sbus_writel(cs4231_chip->input_next_dma_handle,
cs4231_chip->regs + APCCNVA);
@@ -1418,7 +1428,8 @@ static int eb4231_recintr(struct sparcaudio_driver *drv)
if (cs4231_chip->input_dma_handle) {
pci_unmap_single((struct pci_dev *)drv->dev,
cs4231_chip->input_dma_handle,
- cs4231_chip->input_dma_size);
+ cs4231_chip->input_dma_size,
+ PCI_DMA_FROMDEVICE);
cs4231_chip->input_dma_handle = 0;
cs4231_chip->input_dma_size = 0;
cs4231_chip->recording_count--;
@@ -1441,7 +1452,8 @@ static int eb4231_recintr(struct sparcaudio_driver *drv)
cs4231_chip->input_next_dma_handle =
pci_map_single((struct pci_dev *)drv->dev,
(char *)cs4231_chip->input_ptr,
- cs4231_chip->input_size);
+ cs4231_chip->input_size,
+ PCI_DMA_FROMDEVICE);
cs4231_chip->input_next_dma_size = cs4231_chip->input_size;
writel(cs4231_chip->input_next_dma_size,
@@ -1556,7 +1568,8 @@ static void eb4231_stop_output(struct sparcaudio_driver *drv)
if (cs4231_chip->output_dma_handle) {
pci_unmap_single((struct pci_dev *)drv->dev,
cs4231_chip->output_dma_handle,
- cs4231_chip->output_dma_size);
+ cs4231_chip->output_dma_size,
+ PCI_DMA_TODEVICE);
cs4231_chip->output_dma_handle = 0;
cs4231_chip->output_dma_size = 0;
}
@@ -1564,7 +1577,8 @@ static void eb4231_stop_output(struct sparcaudio_driver *drv)
if (cs4231_chip->output_next_dma_handle) {
pci_unmap_single((struct pci_dev *)drv->dev,
cs4231_chip->output_next_dma_handle,
- cs4231_chip->output_next_dma_size);
+ cs4231_chip->output_next_dma_size,
+ PCI_DMA_TODEVICE);
cs4231_chip->output_next_dma_handle = 0;
cs4231_chip->output_next_dma_size = 0;
}
@@ -1589,7 +1603,8 @@ static void cs4231_stop_output(struct sparcaudio_driver *drv)
if (cs4231_chip->output_dma_handle) {
sbus_unmap_single(drv->dev,
cs4231_chip->output_dma_handle,
- cs4231_chip->output_dma_size);
+ cs4231_chip->output_dma_size,
+ SBUS_DMA_TODEVICE);
cs4231_chip->output_dma_handle = 0;
cs4231_chip->output_dma_size = 0;
}
@@ -1597,7 +1612,8 @@ static void cs4231_stop_output(struct sparcaudio_driver *drv)
if (cs4231_chip->output_next_dma_handle) {
sbus_unmap_single(drv->dev,
cs4231_chip->output_next_dma_handle,
- cs4231_chip->output_next_dma_size);
+ cs4231_chip->output_next_dma_size,
+ SBUS_DMA_TODEVICE);
cs4231_chip->output_next_dma_handle = 0;
cs4231_chip->output_next_dma_size = 0;
}
@@ -1699,7 +1715,8 @@ static void cs4231_stop_input(struct sparcaudio_driver *drv)
if (cs4231_chip->input_dma_handle) {
sbus_unmap_single(drv->dev,
cs4231_chip->input_dma_handle,
- cs4231_chip->input_dma_size);
+ cs4231_chip->input_dma_size,
+ SBUS_DMA_FROMDEVICE);
cs4231_chip->input_dma_handle = 0;
cs4231_chip->input_dma_size = 0;
}
@@ -1707,7 +1724,8 @@ static void cs4231_stop_input(struct sparcaudio_driver *drv)
if (cs4231_chip->input_next_dma_handle) {
sbus_unmap_single(drv->dev,
cs4231_chip->input_next_dma_handle,
- cs4231_chip->input_next_dma_size);
+ cs4231_chip->input_next_dma_size,
+ SBUS_DMA_FROMDEVICE);
cs4231_chip->input_next_dma_handle = 0;
cs4231_chip->input_next_dma_size = 0;
}
@@ -1765,7 +1783,8 @@ static void eb4231_stop_input(struct sparcaudio_driver *drv)
if (cs4231_chip->input_dma_handle) {
pci_unmap_single((struct pci_dev *)drv->dev,
cs4231_chip->input_dma_handle,
- cs4231_chip->input_dma_size);
+ cs4231_chip->input_dma_size,
+ PCI_DMA_FROMDEVICE);
cs4231_chip->input_dma_handle = 0;
cs4231_chip->input_dma_size = 0;
}
@@ -1773,7 +1792,8 @@ static void eb4231_stop_input(struct sparcaudio_driver *drv)
if (cs4231_chip->input_next_dma_handle) {
pci_unmap_single((struct pci_dev *)drv->dev,
cs4231_chip->input_next_dma_handle,
- cs4231_chip->input_next_dma_size);
+ cs4231_chip->input_next_dma_size,
+ PCI_DMA_FROMDEVICE);
cs4231_chip->input_next_dma_handle = 0;
cs4231_chip->input_next_dma_size = 0;
}
diff --git a/drivers/sbus/audio/dbri.c b/drivers/sbus/audio/dbri.c
index a3f083ead..45ee9dd1b 100644
--- a/drivers/sbus/audio/dbri.c
+++ b/drivers/sbus/audio/dbri.c
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.18 2000/01/28 13:42:50 jj Exp $
+/* $Id: dbri.c,v 1.19 2000/02/18 13:49:42 davem Exp $
* drivers/sbus/audio/dbri.c
*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -356,7 +356,8 @@ static void transmission_complete_intr(struct dbri *dbri, int pipe)
if (buffer)
sbus_unmap_single(dbri->sdev,
dbri->descs[td].buffer_dvma,
- dbri->descs[td].len);
+ dbri->descs[td].len,
+ SBUS_DMA_TODEVICE);
callback = dbri->descs[td].output_callback;
callback_arg = dbri->descs[td].output_callback_arg;
@@ -391,7 +392,8 @@ static void reception_complete_intr(struct dbri *dbri, int pipe)
if (buffer)
sbus_unmap_single(dbri->sdev,
dbri->descs[rd].buffer_dvma,
- dbri->descs[rd].len);
+ dbri->descs[rd].len,
+ SBUS_DMA_FROMDEVICE);
callback = dbri->descs[rd].input_callback;
if (callback != NULL)
@@ -592,7 +594,9 @@ static void reset_pipe(struct dbri *dbri, int pipe)
if (buffer)
sbus_unmap_single(dbri->sdev,
dbri->descs[desc].buffer_dvma,
- dbri->descs[desc].len);
+ dbri->descs[desc].len,
+ output_callback != NULL ? SBUS_DMA_TODEVICE
+ : SBUS_DMA_FROMDEVICE);
dbri->descs[desc].inuse = 0;
desc = dbri->descs[desc].next;
@@ -863,7 +867,8 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
return;
}
- dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len);
+ dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len,
+ SBUS_DMA_TODEVICE);
while (len > 0) {
int mylen;
@@ -907,6 +912,9 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
}
if (first_td == -1 || last_td == -1) {
+ sbus_unmap_single(dbri->sdev, dvma_buffer_base,
+ dvma_buffer - dvma_buffer_base + len,
+ SBUS_DMA_TODEVICE);
return;
}
@@ -914,7 +922,7 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
dbri->descs[last_td].buffer = buffer;
dbri->descs[last_td].buffer_dvma = dvma_buffer_base;
- dbri->descs[last_td].len = len;
+ dbri->descs[last_td].len = dvma_buffer - dvma_buffer_base + len;
dbri->descs[last_td].output_callback = callback;
dbri->descs[last_td].output_callback_arg = callback_arg;
@@ -999,7 +1007,8 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
/* Make sure buffer size is multiple of four */
len &= ~3;
- bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len);
+ bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len,
+ SBUS_DMA_FROMDEVICE);
while (len > 0) {
int rd, mylen;
@@ -1043,8 +1052,12 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
len -= mylen;
}
- if (last_rd == -1 || first_rd == -1)
+ if (last_rd == -1 || first_rd == -1) {
+ sbus_unmap_single(dbri->sdev, bus_buffer_base,
+ bus_buffer - bus_buffer_base + len,
+ SBUS_DMA_FROMDEVICE);
return;
+ }
for (rd=first_rd; rd != -1; rd = dbri->descs[rd].next) {
dprintk(D_DESC, ("DBRI RD %d: %08x %08x %08x %08x\n",
@@ -1057,7 +1070,7 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
dbri->descs[last_rd].buffer = buffer;
dbri->descs[last_rd].buffer_dvma = bus_buffer_base;
- dbri->descs[last_rd].len = len;
+ dbri->descs[last_rd].len = bus_buffer - bus_buffer_base + len;
dbri->descs[last_rd].input_callback = callback;
dbri->descs[last_rd].input_callback_arg = callback_arg;
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 1d2bee01a..fb18a63c1 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -19,6 +19,7 @@
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/major.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -1004,6 +1005,8 @@ static inline void freeLptPort(int idx)
#endif
+static devfs_handle_t devfs_handle = NULL;
+
#ifdef MODULE
int init_module(void)
#else
@@ -1017,7 +1020,7 @@ int __init bpp_init(void)
if (rc == 0)
return -ENODEV;
- rc = register_chrdev(BPP_MAJOR, dev_name, &bpp_fops);
+ rc = devfs_register_chrdev(BPP_MAJOR, dev_name, &bpp_fops);
if (rc < 0)
return rc;
@@ -1025,6 +1028,10 @@ int __init bpp_init(void)
instances[idx].opened = 0;
probeLptPort(idx);
}
+ devfs_handle = devfs_mk_dir (NULL, "bpp", 3, NULL);
+ devfs_register_series (devfs_handle, "%u", BPP_NO, DEVFS_FL_DEFAULT,
+ BPP_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &bpp_fops, NULL);
return 0;
}
@@ -1034,7 +1041,8 @@ void cleanup_module(void)
{
unsigned idx;
- unregister_chrdev(BPP_MAJOR, dev_name);
+ devfs_unregister (devfs_handle);
+ devfs_unregister_chrdev(BPP_MAJOR, dev_name);
for (idx = 0 ; idx < BPP_NO ; idx += 1) {
if (instances[idx].present)
diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c
index 97ebda430..76b83eacb 100644
--- a/drivers/sbus/char/pcikbd.c
+++ b/drivers/sbus/char/pcikbd.c
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.43 2000/02/09 22:33:25 davem Exp $
+/* $Id: pcikbd.c,v 1.44 2000/02/11 04:49:13 davem Exp $
* pcikbd.c: Ultra/AX PC keyboard support.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -1024,9 +1024,6 @@ int __init ps2kbd_probe(void)
goto found;
}
#endif
- if (!pci_present())
- goto do_enodev;
-
/*
* Get the nodes for keyboard and mouse from aliases on normal systems.
*/
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index 7e26f3491..91bf24a18 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/sysrq.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/kbio.h>
#include <asm/vuid_event.h>
@@ -507,7 +508,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
}
do_poke_blanked_console = 1;
- mark_bh(CONSOLE_BH);
+ tasklet_schedule(&console_tasklet);
add_keyboard_randomness(keycode);
tty = ttytab? ttytab[fg_console]: NULL;
@@ -616,7 +617,7 @@ static void put_queue(int ch)
wake_up(&keypress_wait);
if (tty) {
tty_insert_flip_char(tty, ch, 0);
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
}
@@ -630,7 +631,7 @@ static void puts_queue(char *cp)
tty_insert_flip_char(tty, *cp, 0);
cp++;
}
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
static void applkey(int key, char mode)
@@ -742,7 +743,7 @@ static void send_intr(void)
if (!tty)
return;
tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
static void scroll_forw(void)
@@ -1549,7 +1550,11 @@ void __init keyboard_zsinit(void (*put_char)(unsigned char))
send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */
/* Register the /dev/kbd interface */
- if (register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){
+ devfs_register (NULL, "kbd", 0, DEVFS_FL_NONE,
+ KBD_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0, 0,
+ &kbd_fops, NULL);
+ if (devfs_register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){
printk ("Could not register /dev/kbd device\n");
return;
}
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
index b9ed039ce..c22f835c0 100644
--- a/drivers/sbus/char/vfc.h
+++ b/drivers/sbus/char/vfc.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_VFC_H_
#define _LINUX_VFC_H_
+#include <linux/devfs_fs_kernel.h>
+
/*
* The control register for the vfc is at offset 0x4000
* The first field ram bank is located at offset 0x5000
@@ -126,6 +128,7 @@ struct vfc_dev {
volatile struct vfc_regs *regs;
struct vfc_regs *phys_regs;
unsigned int control_reg;
+ devfs_handle_t de;
struct semaphore device_lock_sem;
struct timer_list poll_timer;
wait_queue_head_t poll_wait;
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 5f7af8642..a5e61bb9a 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -41,6 +41,7 @@
#include "vfc.h"
#include <asm/vfc_ioctls.h>
+static devfs_handle_t devfs_handle = NULL; /* For the directory */
struct vfc_dev **vfc_dev_lst;
static char vfcstr[]="vfc";
static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
@@ -140,6 +141,8 @@ int init_vfc_devstruct(struct vfc_dev *dev, int instance)
int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance)
{
+ char devname[8];
+
if(dev == NULL) {
printk(KERN_ERR "VFC: Bogus pointer passed\n");
return -ENOMEM;
@@ -162,6 +165,11 @@ int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance)
if (init_vfc_hw(dev))
return -EIO;
+ sprintf (devname, "%d", instance);
+ dev->de = devfs_register (devfs_handle, devname, 0, DEVFS_FL_DEFAULT,
+ VFC_MAJOR, instance,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &vfc_fops, NULL);
return 0;
}
@@ -659,12 +667,13 @@ static int vfc_probe(void)
memset(vfc_dev_lst, 0, sizeof(struct vfc_dev *) * (cards + 1));
vfc_dev_lst[cards] = NULL;
- ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
+ ret = devfs_register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
if(ret) {
printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR);
kfree(vfc_dev_lst);
return -EIO;
}
+ devfs_handle = devfs_mk_dir (NULL, "vfc", 3, NULL);
instance = 0;
for_all_sbusdev(sdev, sbus) {
@@ -705,6 +714,7 @@ static void deinit_vfc_device(struct vfc_dev *dev)
{
if(dev == NULL)
return;
+ devfs_unregister (dev->de);
sbus_iounmap((unsigned long)dev->regs, sizeof(struct vfc_regs));
kfree(dev);
}
@@ -713,11 +723,12 @@ void cleanup_module(void)
{
struct vfc_dev **devp;
- unregister_chrdev(VFC_MAJOR,vfcstr);
+ devfs_unregister_chrdev(VFC_MAJOR,vfcstr);
for (devp = vfc_dev_lst; *devp; devp++)
deinit_vfc_device(*devp);
+ devfs_unregister (devfs_handle);
kfree(vfc_dev_lst);
return;
}
diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
index be31441ad..bb522768d 100644
--- a/drivers/sbus/dvma.c
+++ b/drivers/sbus/dvma.c
@@ -105,7 +105,8 @@ void __init dvma_init(struct sbus_bus *sbus)
}
dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0,
- PAGE_SIZE, "dma");
+ dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1,
+ "dma");
dma->node = dma->sdev->prom_node;
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index e4af6a65e..9faa91e1b 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -8,7 +8,7 @@ fi
dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
-if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then
+if [ "$CONFIG_CHR_DEV_ST" != "n" ]; then
int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2
fi
@@ -193,3 +193,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
endmenu
+
+if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+ source drivers/scsi/pcmcia/Config.in
+fi
+
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index af4a242ff..16f26fbcd 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -13,6 +13,16 @@ MIX_OBJS :=
MOD_LIST_NAME := SCSI_MODULES
SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
+ALL_SUB_DIRS := pcmcia
+ifeq ($(CONFIG_PCMCIA),y)
+ SUB_DIRS += pcmcia
+ MOD_IN_SUB_DIRS += pcmcia
+else
+ ifeq ($(CONFIG_PCMCIA),m)
+ MOD_IN_SUB_DIRS += pcmcia
+ endif
+endif
+
CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
index 100f9ff95..70ef93d92 100644
--- a/drivers/scsi/README.aic7xxx
+++ b/drivers/scsi/README.aic7xxx
@@ -208,6 +208,19 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
will often result in the machine crashing or spontaneously rebooting
during startup. Examples of machines that need this are the
Dell PowerEdge 6300 machines.
+
+ "aic7xxx=seltime:2" - This option controls how long the card waits
+ during a device selection sequence for the device to respond.
+ The original SCSI spec says that this "should be" 256ms. This
+ is generally not required with modern devices. However, some
+ very old SCSI I devices need the full 256ms. Most modern devices
+ can run fine with only 64ms. The default for this option is
+ 64ms. If you need to change this option, then use the following
+ table to set the proper value in the example above:
+ 0 - 256ms
+ 1 - 128ms
+ 2 - 64ms
+ 3 - 32ms
"aic7xxx=panic_on_abort" - This option is for debugging and will cause
the driver to panic the linux kernel and freeze the system the first
@@ -485,12 +498,14 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Web sites
------------------------------
- http://people.redhat.com/dledford/aic7xxx.html
- - Primary web site maintained by Doug Ledford.
+ http://people.redhat.com/dledford/
+ - My web site, also the primary aic7xxx site with several related
+ pages.
Dean W. Gehnert
deang@teleport.com
$Revision: 3.0 $
-Modified by Doug Ledford 1998-9
+Modified by Doug Ledford 1998-2000
+
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 38550e1d3..30faaa9ad 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -200,13 +200,9 @@
**************************************************************************/
-#if defined(PCMCIA)
-#define MODULE
-#endif
-
#include <linux/module.h>
-#if defined(PCMCIA)
+#ifdef PCMCIA
#undef MODULE
#endif
@@ -877,9 +873,9 @@ static int tc1550_porttest(int io_port)
static int checksetup(struct aha152x_setup *setup)
{
- int i;
#if !defined(PCMCIA)
+ int i;
for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++)
;
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 77f52f337..6ca7147d5 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -264,7 +264,7 @@
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-#define AIC7XXX_C_VERSION "5.1.21"
+#define AIC7XXX_C_VERSION "5.2.0"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -719,6 +719,11 @@ struct seeprom_config {
#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in)
/*
+ * The stored DMA mapping for single-buffer data transfers.
+ */
+#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase)
+
+/*
* So we can keep track of our host structs
*/
static struct aic7xxx_host *first_aic7xxx = NULL;
@@ -823,6 +828,7 @@ typedef enum {
* and what flags weren't. This way, I could clean up the flag usage on
* a use by use basis. Doug Ledford
*/
+ AHC_NO_STPWR = 0x00040000,
AHC_RESET_DELAY = 0x00080000,
AHC_A_SCANNED = 0x00100000,
AHC_B_SCANNED = 0x00200000,
@@ -883,6 +889,17 @@ typedef enum {
AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3,
} ahc_feature;
+#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset)
+
+struct aic7xxx_scb_dma {
+ unsigned long dma_offset; /* Correction you have to add
+ * to virtual address to get
+ * dma handle in this region */
+ dma_addr_t dma_address; /* DMA handle of the start,
+ * for unmap */
+ unsigned int dma_len; /* DMA length */
+};
+
struct aic7xxx_scb {
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
@@ -891,15 +908,17 @@ struct aic7xxx_scb {
struct hw_scatterlist *sg_list; /* SG list in adapter format */
unsigned char tag_action;
unsigned char sg_count;
- unsigned char sense_cmd[6]; /*
+ unsigned char *sense_cmd; /*
* Allocate 6 characters for
* sense command.
*/
+ unsigned char *cmnd;
unsigned int sg_length; /* We init this during buildscb so we
* don't have to calculate anything
* during underflow/overflow/stat code
*/
void *kmalloc_ptr;
+ struct aic7xxx_scb_dma *scb_dma;
};
/*
@@ -937,6 +956,8 @@ typedef struct {
unsigned char numscbs; /* current number of scbs */
unsigned char maxhscbs; /* hardware scbs */
unsigned char maxscbs; /* max scbs including pageable scbs */
+ unsigned int hscbs_dma; /* DMA handle to hscbs */
+ unsigned int hscbs_dma_len; /* length of the above DMA area */
void *hscb_kmalloc_ptr;
} scb_data_type;
@@ -1014,6 +1035,9 @@ struct aic7xxx_host {
volatile unsigned char activescbs; /* active scbs */
volatile unsigned char max_activescbs;
volatile unsigned char qinfifonext;
+ volatile unsigned char *untagged_scbs;
+ volatile unsigned char *qoutfifo;
+ volatile unsigned char *qinfifo;
#define DEVICE_PRESENT 0x01
#define BUS_DEVICE_RESET_PENDING 0x02
@@ -1063,16 +1087,9 @@ struct aic7xxx_host {
* We put the less frequently used host structure items after the more
* frequently used items to try and ease the burden on the cache subsystem.
* These entries are not *commonly* accessed, whereas the preceding entries
- * are accessed very often. The only exceptions are the qinfifo, qoutfifo,
- * and untagged_scbs array. But, they are often accessed only once and each
- * access into these arrays is likely to blow a cache line, so they are put
- * down here so we can minimize the number of cache lines required to hold
- * the preceeding entries.
+ * are accessed very often.
*/
- volatile unsigned char untagged_scbs[256];
- volatile unsigned char qoutfifo[256];
- volatile unsigned char qinfifo[256];
unsigned int irq; /* IRQ for this adapter */
int instance; /* aic7xxx instance number */
int scsi_id; /* host adapter SCSI ID */
@@ -1085,9 +1102,7 @@ struct aic7xxx_host {
unsigned short ultraenb; /* Ultra mode target list */
unsigned short bios_control; /* bios control - SEEPROM */
unsigned short adapter_control; /* adapter control - SEEPROM */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- struct pci_dev *pdev;
-#endif
+ struct pci_dev *pdev;
unsigned char pci_bus;
unsigned char pci_device_fn;
struct seeprom_config sc;
@@ -1098,6 +1113,7 @@ struct aic7xxx_host {
int host_no; /* SCSI host number */
unsigned long mbase; /* I/O memory address */
ahc_chip chip; /* chip type */
+ dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
/*
* Statistics Kept:
@@ -1354,10 +1370,10 @@ static int aic7xxx_scbram = 0;
/*
* So that we can set how long each device is given as a selection timeout.
* The table of values goes like this:
- * 0 - 256ms
- * 1 - 128ms
- * 2 - 64ms
- * 3 - 32ms
+ * 0 - 256ms
+ * 1 - 128ms
+ * 2 - 64ms
+ * 3 - 32ms
* We default to 64ms because it's fast. Some old SCSI-I devices need a
* longer time. The final value has to be left shifted by 3, hence 0x10
* is the final value.
@@ -1467,6 +1483,7 @@ aic_inb(struct aic7xxx_host *p, long port)
{
x = inb(p->base + port);
}
+ mb();
return(x);
#else
return(inb(p->base + port));
@@ -1770,6 +1787,7 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
struct ins_format1 *fmt1_ins;
struct ins_format3 *fmt3_ins;
unsigned char opcode;
+ volatile unsigned char hcntrl;
instr = *(union ins_formats*) &seqprog[instrptr * 4];
@@ -1871,12 +1889,13 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
}
}
aic_outb(p, (instr.integer & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
- udelay(50);
+ hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+ hcntrl = aic_inb(p, HCNTRL);
udelay(50);
break;
@@ -1991,21 +2010,6 @@ aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded)
/*+F*************************************************************************
* Function:
- * aic7xxx_delay
- *
- * Description:
- * Delay for specified amount of time. We use mdelay because the timer
- * interrupt is not guaranteed to be enabled. This will cause an
- * infinite loop since jiffies (clock ticks) is not updated.
- *-F*************************************************************************/
-static void
-aic7xxx_delay(int seconds)
-{
- mdelay(seconds * 1000);
-}
-
-/*+F*************************************************************************
- * Function:
* aic7xxx_info
*
* Description:
@@ -2728,15 +2732,14 @@ static int
aic7xxx_allocate_scb(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scbp = NULL;
- int scb_size = sizeof(struct aic7xxx_scb) +
- sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+ int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6;
int i;
int step = PAGE_SIZE / 1024;
unsigned long scb_count = 0;
struct hw_scatterlist *hsgp;
struct aic7xxx_scb *scb_ap;
- unsigned long temp;
-
+ struct aic7xxx_scb_dma *scb_dma;
+ unsigned char *bufs;
if (p->scb_data->numscbs < p->scb_data->maxscbs)
{
@@ -2750,6 +2753,11 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
* efficiency since scb_size * (i -1) is growing slightly faster
* than the right hand side. If the number of SG array elements
* is changed, this function may not be near so efficient any more.
+ *
+ * Since the DMA'able buffers are now allocated in a seperate
+ * chunk this algorithm has been modified to match. The '12'
+ * and '6' factors in scb_size are for the DMA'able command byte
+ * and sensebuffers respectively. -DaveM
*/
for ( i=step;; i *= 2 )
{
@@ -2760,44 +2768,53 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
}
}
scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs);
- scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
- if (scb_ap != NULL)
+ scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count
+ + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC);
+ if (scb_ap == NULL)
+ return(0);
+ scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count];
+ hsgp = (struct hw_scatterlist *)
+ pci_alloc_consistent(p->pdev, scb_size * scb_count,
+ &scb_dma->dma_address);
+ if (hsgp == NULL)
{
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- {
- if (p->scb_data->numscbs == 0)
- printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
- p->host_no, -1, -1, -1, scb_count);
- else
- printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
- p->host_no, -1, -1, -1, scb_count);
- }
-#endif
- memset(scb_ap, 0, scb_count * scb_size);
- temp = (unsigned long) &scb_ap[scb_count];
- temp += 1023;
- temp &= ~1023;
- hsgp = (struct hw_scatterlist *)temp;
- for (i=0; i < scb_count; i++)
- {
- scbp = &scb_ap[i];
- scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
- scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
- memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
- scbp->hscb->tag = p->scb_data->numscbs;
- /*
- * Place in the scb array; never is removed
- */
- p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
- scbq_insert_tail(&p->scb_data->free_scbs, scbp);
- }
- scbp->kmalloc_ptr = scb_ap;
+ kfree(scb_ap);
+ return(0);
}
- else
+ bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG];
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+ if (aic7xxx_verbose > 0xffff)
{
- return(0);
+ if (p->scb_data->numscbs == 0)
+ printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ else
+ printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+ p->host_no, -1, -1, -1, scb_count);
+ }
+#endif
+ memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count);
+ scb_dma->dma_offset = (unsigned long)scb_dma->dma_address
+ - (unsigned long)hsgp;
+ scb_dma->dma_len = scb_size * scb_count;
+ for (i=0; i < scb_count; i++)
+ {
+ scbp = &scb_ap[i];
+ scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+ scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+ scbp->sense_cmd = bufs;
+ scbp->cmnd = bufs + 6;
+ bufs += 12 + 6;
+ scbp->scb_dma = scb_dma;
+ memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+ scbp->hscb->tag = p->scb_data->numscbs;
+ /*
+ * Place in the scb array; never is removed
+ */
+ p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+ scbq_insert_tail(&p->scb_data->free_scbs, scbp);
}
+ scbp->kmalloc_ptr = scb_ap;
}
return(scb_count);
}
@@ -2882,6 +2899,24 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
struct aic7xxx_scb *scbp;
unsigned char queue_depth;
+ if (cmd->use_sg > 1)
+ {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
+ else if (cmd->request_bufflen)
+ pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ if (scb->flags & SCB_SENSE)
+ {
+ pci_unmap_single(p->pdev,
+ le32_to_cpu(scb->sg_list[0].address),
+ sizeof(cmd->sense_buffer),
+ PCI_DMA_FROMDEVICE);
+ }
if (scb->flags & SCB_RECOVERY_SCB)
{
p->flags &= ~AHC_ABORT_PENDING;
@@ -3889,11 +3924,19 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0)
mdelay(5);
- mdelay(10);
+ /*
+ * Some of the new Ultra2 chipsets need a longer delay after a chip
+ * reset than just the init setup creates, so we have to delay here
+ * before we go into a reset in order to make the chips happy.
+ */
+ if (p->features & AHC_ULTRA2)
+ mdelay(250);
+ else
+ mdelay(50);
/* Turn off the bus reset. */
aic_outb(p, 0, SCSISEQ);
- mdelay(5);
+ mdelay(10);
aic7xxx_clear_intstat(p);
/* Re-enable reset interrupts. */
@@ -4772,6 +4815,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
case CHECK_CONDITION:
if ( !(scb->flags & SCB_SENSE) )
{
+ unsigned char *sense_buffer;
/*
* XXX - How do we save the residual (if there is one).
*/
@@ -4782,14 +4826,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
* Send a sense command to the requesting target.
* XXX - revisit this and get rid of the memcopys.
*/
- memcpy(&scb->sense_cmd[0], &generic_sense[0],
+ memcpy(scb->sense_cmd, &generic_sense[0],
sizeof(generic_sense));
scb->sense_cmd[1] = (cmd->lun << 5);
scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
- scb->sg_list[0].address =
- cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+ sense_buffer = cmd->sense_buffer;
scb->sg_list[0].length =
cpu_to_le32(sizeof(cmd->sense_buffer));
@@ -4801,11 +4844,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
hscb->control = 0;
hscb->target_status = 0;
hscb->SG_list_pointer =
- cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
- hscb->data_pointer = scb->sg_list[0].address;
+ cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list));
hscb->data_count = scb->sg_list[0].length;
hscb->SCSI_cmd_pointer =
- cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+ cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd));
hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
hscb->residual_SG_segment_count = 0;
hscb->residual_data_count[0] = 0;
@@ -4854,12 +4896,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
* SENSE information anyway.
*/
if (cmd->next->cmnd[0] != TEST_UNIT_READY)
- {
- scb->sg_list[0].address =
- cpu_to_le32(VIRT_TO_BUS(&cmd->next->sense_buffer[0]));
- hscb->data_pointer = scb->sg_list[0].address;
- }
+ sense_buffer = cmd->next->sense_buffer;
}
+ scb->sg_list[0].address =
+ cpu_to_le32(pci_map_single(p->pdev, sense_buffer,
+ sizeof(cmd->sense_buffer),
+ PCI_DMA_FROMDEVICE));
+ hscb->data_pointer = scb->sg_list[0].address;
+
scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
@@ -5134,7 +5178,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
else if (scb->flags & SCB_MSGOUT_PPR)
{
unsigned int max_sync, period;
- unsigned char options = p->transinfo[tindex].goal_options;
+ unsigned char options = 0;
if (p->features & AHC_ULTRA2)
{
@@ -5145,9 +5189,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
(p->dev_flags[tindex] & DEVICE_SCSI_3) &&
(p->transinfo[tindex].goal_width ==
MSG_EXT_WDTR_BUS_16_BIT) &&
- (options != 0) )
+ (p->transinfo[tindex].goal_options != 0) )
{
max_sync = AHC_SYNCRATE_ULTRA3;
+ options = p->transinfo[tindex].goal_options;
}
else
{
@@ -5296,6 +5341,188 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
}
break;
+ case WIDE_RESIDUE:
+ {
+ unsigned char resid_sgcnt, index;
+ unsigned char scb_index = aic_inb(p, SCB_TAG);
+ unsigned int cur_addr, resid_dcnt;
+ unsigned int native_addr, native_length;
+ int i;
+
+ if(scb_index > p->scb_data->numscbs)
+ {
+ printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n",
+ p->host_no, -1, -1, -1);
+ /*
+ * XXX: Add error handling here
+ */
+ break;
+ }
+ scb = p->scb_data->scb_array[scb_index];
+ if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x "
+ "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb),
+ scb->flags, (unsigned long)scb->cmd);
+ break;
+ }
+
+ /*
+ * We have a valid scb to use on this WIDE_RESIDUE message, so
+ * we need to walk the sg list looking for this particular sg
+ * segment, then see if we happen to be at the very beginning of
+ * the segment. If we are, then we have to back things up to
+ * the previous segment. If not, then we simply need to remove
+ * one byte from this segments address and add one to the byte
+ * count.
+ */
+ cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
+ (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+ resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
+ resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
+ (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
+ (aic_inb(p, SCB_RESID_DCNT + 2) << 24);
+ index = scb->sg_count - resid_sgcnt;
+ native_addr = le32_to_cpu(scb->sg_list[index].address);
+ native_length = le32_to_cpu(scb->sg_list[index].length);
+ /*
+ * Make sure this is a valid sg_seg for the given pointer
+ */
+ if(cur_addr < native_addr ||
+ cur_addr > (native_addr + native_length))
+ {
+ printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
+ p->host_no, CTL_OF_SCB(scb), cur_addr);
+ if(index > 0)
+ printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ le32_to_cpu(scb->sg_list[index - 1].address),
+ le32_to_cpu(scb->sg_list[index - 1].length));
+ printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ native_addr, native_length);
+ if(resid_sgcnt > 1)
+ printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n",
+ p->host_no, CTL_OF_SCB(scb),
+ le32_to_cpu(scb->sg_list[index + 1].address),
+ le32_to_cpu(scb->sg_list[index + 1].length));
+ break;
+ }
+
+ /*
+ * If our current address matches the sg_seg->address then we
+ * have to back up the sg array to the previous segment and set
+ * it up to have only one byte of transfer left to go.
+ */
+ if(cur_addr == native_addr)
+ {
+ if(index == 0)
+ {
+ printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
+ "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+ break;
+ }
+ resid_sgcnt++;
+ index--;
+ cur_addr = le32_to_cpu(scb->sg_list[index].address) +
+ le32_to_cpu(scb->sg_list[index].length) - 1;
+ native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
+ | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
+ native_addr -= SG_SIZEOF;
+ aic_outb(p, resid_sgcnt, SG_COUNT);
+ aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+ aic_outb(p, native_addr & 0xff, SG_NEXT);
+ aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
+ aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
+ aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
+ aic_outb(p, 1, SCB_RESID_DCNT);
+ aic_outb(p, 0, SCB_RESID_DCNT + 1);
+ aic_outb(p, 0, SCB_RESID_DCNT + 2);
+ aic_outb(p, 1, HCNT);
+ aic_outb(p, 0, HCNT + 1);
+ aic_outb(p, 0, HCNT + 2);
+ aic_outb(p, cur_addr & 0xff, HADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ /*
+ * The sequencer actually wants to find the new address and byte
+ * count in the SHCNT and SHADDR register sets. These registers
+ * are a shadow of the regular HCNT and HADDR registers. On the
+ * Ultra2 controllers, these registers are read only and the way
+ * we have to set their values is to put the values we want into
+ * the HCNT and HADDR registers and then output PRELOADEN into
+ * the DFCNTRL register which causes the card to latch the current
+ * values in the HADDR and HCNT registers and drop it through to
+ * the shadow registers. On older cards we copy them directly
+ * across by hand.
+ */
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ udelay(1);
+ }
+ }
+ else
+ {
+ aic_outb(p, 1, STCNT);
+ aic_outb(p, 0, STCNT + 1);
+ aic_outb(p, 0, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
+ }
+ else
+ {
+ /*
+ * Back the data pointer up by one and add one to the remaining
+ * byte count. Then store that in the HCNT and HADDR registers.
+ */
+ cur_addr--;
+ resid_dcnt++;
+ aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+ aic_outb(p, resid_dcnt & 0xff, HCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+ aic_outb(p, cur_addr & 0xff, HADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ udelay(1);
+ }
+ }
+ else
+ {
+ aic_outb(p, resid_dcnt & 0xff, STCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
+ }
+ }
+ break;
+
+
#if AIC7XXX_NOT_YET
case TRACEPOINT:
{
@@ -5655,16 +5882,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
break;
}
- /*
- * If we aren't on one of the new Ultra3 cards, then reject any PPR
- * message since we can't support any option field other than 0
- */
- if( !(p->features & AHC_ULTRA3) )
- {
- reject = TRUE;
- break;
- }
-
if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
{
break;
@@ -6810,7 +7027,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
return;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
spin_lock_irqsave(&io_request_lock, cpu_flags);
- if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags))
+ if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
{
return;
}
@@ -6820,7 +7037,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
- clear_bit(AHC_IN_ISR_BIT, &p->flags);
+ clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
#else
if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
@@ -7212,6 +7429,21 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
#undef CLOCK_PULSE
}
+#define CLOCK_PULSE(p) \
+ do { \
+ int limit = 0; \
+ do { \
+ mb(); \
+ pause_sequencer(p); /* This is just to generate some PCI */ \
+ /* traffic so the PCI read is flushed */ \
+ /* it shouldn't be needed, but some */ \
+ /* chipsets do indeed appear to need */ \
+ /* something to force PCI reads to get */ \
+ /* flushed */ \
+ udelay(1); /* Do nothing */ \
+ } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \
+ } while(0)
+
/*+F*************************************************************************
* Function:
* acquire_seeprom
@@ -7222,7 +7454,6 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
static int
acquire_seeprom(struct aic7xxx_host *p)
{
- int wait;
/*
* Request access of the memory port. When access is
@@ -7232,12 +7463,7 @@ acquire_seeprom(struct aic7xxx_host *p)
* should be no contention.
*/
aic_outb(p, SEEMS, SEECTL);
- wait = 1000; /* 1000 msec = 1 second */
- while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
- {
- wait--;
- mdelay(1); /* 1 msec */
- }
+ CLOCK_PULSE(p);
if ((aic_inb(p, SEECTL) & SEERDY) == 0)
{
aic_outb(p, 0, SEECTL);
@@ -7256,7 +7482,12 @@ acquire_seeprom(struct aic7xxx_host *p)
static void
release_seeprom(struct aic7xxx_host *p)
{
+ /*
+ * Make sure the SEEPROM is ready before we release it.
+ */
+ CLOCK_PULSE(p);
aic_outb(p, 0, SEECTL);
+ CLOCK_PULSE(p);
}
/*+F*************************************************************************
@@ -7322,12 +7553,6 @@ read_seeprom(struct aic7xxx_host *p, int offset,
};
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
-#define CLOCK_PULSE(p) \
- while ((aic_inb(p, SEECTL) & SEERDY) == 0) \
- { \
- ; /* Do nothing */ \
- }
-
/*
* Request access of the memory port.
*/
@@ -7443,7 +7668,6 @@ read_seeprom(struct aic7xxx_host *p, int offset,
}
return (1);
-#undef CLOCK_PULSE
}
/*+F*************************************************************************
@@ -7458,12 +7682,18 @@ read_brdctl(struct aic7xxx_host *p)
{
unsigned char brdctl, value;
+ /*
+ * Make sure the SEEPROM is ready before we access it
+ */
+ CLOCK_PULSE(p);
if (p->features & AHC_ULTRA2)
{
brdctl = BRDRW_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
- return(aic_inb(p, BRDCTL));
+ CLOCK_PULSE(p);
+ value = aic_inb(p, BRDCTL);
+ CLOCK_PULSE(p);
+ return(value);
}
brdctl = BRDRW;
if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
@@ -7472,10 +7702,11 @@ read_brdctl(struct aic7xxx_host *p)
brdctl |= BRDCS;
}
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
value = aic_inb(p, BRDCTL);
+ CLOCK_PULSE(p);
aic_outb(p, 0, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
return (value);
}
@@ -7491,18 +7722,23 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
{
unsigned char brdctl;
+ /*
+ * Make sure the SEEPROM is ready before we access it
+ */
+ CLOCK_PULSE(p);
if (p->features & AHC_ULTRA2)
{
brdctl = value;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
brdctl |= BRDSTB_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
brdctl &= ~BRDSTB_ULTRA2;
aic_outb(p, brdctl, BRDCTL);
- udelay(4);
+ CLOCK_PULSE(p);
read_brdctl(p);
+ CLOCK_PULSE(p);
}
else
{
@@ -7514,19 +7750,21 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
}
brdctl = BRDSTB | BRDCS;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl |= value;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl &= ~BRDSTB;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl &= ~BRDCS;
aic_outb(p, brdctl, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
}
}
+#undef CLOCK_PULSE
+
/*+F*************************************************************************
* Function:
* aic785x_cable_detect
@@ -7903,12 +8141,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
unsigned char term, scsi_conf;
struct Scsi_Host *host;
- /*
- * Lock out other contenders for our i/o space.
- */
- request_region(p->base, MAXREG - MINREG, "aic7xxx");
-
-
host = p->host;
p->scb_data->maxscbs = AIC7XXX_MAXSCB;
@@ -7944,12 +8176,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
p->dev_timer.function = (void *)aic7xxx_timer;
p->dev_timer_active = 0;
- for (i = 0; i < NUMBER(p->untagged_scbs); i++)
- {
- p->untagged_scbs[i] = SCB_LIST_NULL;
- p->qinfifo[i] = SCB_LIST_NULL;
- p->qoutfifo[i] = SCB_LIST_NULL;
- }
/*
* We currently have no commands of any type
*/
@@ -7980,7 +8206,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
printk("VLB slot %d\n", p->pci_device_fn);
break;
default:
- printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+ printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
PCI_FUNC(p->pci_device_fn));
break;
}
@@ -8016,6 +8242,20 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
}
aic_outb(p, 0, SEQ_FLAGS);
+ /*
+ * We are starting to do real work on the card....it's possible we could
+ * generate some spurious interrupts at this point, especially in the
+ * event of a PCI error or some such. If there are other devices already
+ * registered on the same interrupt as us, this could cause the machine
+ * to lock up. So, we disable the interrupt this card is on until we
+ * finish our card setup. We only need to do this for modules, if we are
+ * compiled into the kernel then interrupts are already off during this
+ * part of the code.
+ */
+#ifdef MODULE
+ disable_irq(p->irq);
+#endif
+
detect_maxscb(p);
@@ -8051,15 +8291,15 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
#endif
if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
{
- devconfig |= 0x02;
+ devconfig |= STPWLEVEL;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force setting STPWLEV bit\n", p->host_no);
+ printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no);
}
else
{
- devconfig &= ~0x02;
+ devconfig &= ~STPWLEVEL;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("(scsi%d) Force clearing STPWLEV bit\n", p->host_no);
+ printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no);
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
@@ -8121,11 +8361,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
}
/*
- * Clear out any possible pending interrupts.
- */
- aic7xxx_clear_intstat(p);
-
- /*
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->features & AHC_TWIN)
@@ -8168,7 +8403,17 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term |
ENSTIMER | ACTNEGEN, SXFRCTL1);
aic_outb(p, 0, SIMODE0);
- aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+ /*
+ * If we are a cardbus adapter then don't enable SCSI reset detection.
+ * We shouldn't likely be sharing SCSI busses with someone else, and
+ * if we don't have a cable currently plugged into the controller then
+ * we won't have a power source for the SCSI termination, which means
+ * we'll see infinite incoming bus resets.
+ */
+ if(p->flags & AHC_NO_STPWR)
+ aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1);
+ else
+ aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
aic_outb(p, 0, SCSIRATE);
if ( p->features & AHC_ULTRA2)
aic_outb(p, 0, SCSIOFFSET);
@@ -8227,44 +8472,57 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
{
size_t array_size;
unsigned int hscb_physaddr;
- unsigned long temp;
array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
if (p->scb_data->hscbs == NULL)
{
- /*
- * A little padding so we can align thing the way we want
+ /* pci_alloc_consistent enforces the alignment already and
+ * clears the area as well.
*/
- p->scb_data->hscbs = kmalloc(array_size + 0x1f, GFP_ATOMIC);
+ p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size,
+ &p->scb_data->hscbs_dma);
+ /* We have to use pci_free_consistent, not kfree */
+ p->scb_data->hscb_kmalloc_ptr = NULL;
+ p->scb_data->hscbs_dma_len = array_size;
}
if (p->scb_data->hscbs == NULL)
{
printk("(scsi%d) Unable to allocate hardware SCB array; "
"failing detection.\n", p->host_no);
+ aic_outb(p, 0, SIMODE1);
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
p->irq = 0;
return(0);
}
- /*
- * Save the actual kmalloc buffer pointer off, then align our
- * buffer to a 32 byte boundary
- */
- p->scb_data->hscb_kmalloc_ptr = p->scb_data->hscbs;
- temp = (unsigned long)p->scb_data->hscbs;
- temp += 0x1f;
- temp &= ~0x1f;
- p->scb_data->hscbs = (struct aic7xxx_hwscb *)temp;
- /* At least the control byte of each SCB needs to be 0. */
- memset(p->scb_data->hscbs, 0, array_size);
-
- /* Tell the sequencer where it can find the hardware SCB array. */
- hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
+
+ hscb_physaddr = p->scb_data->hscbs_dma;
aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
/* Set up the fifo areas at the same time */
- hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+ p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma);
+ if (p->untagged_scbs == NULL)
+ {
+ printk("(scsi%d) Unable to allocate hardware FIFO arrays; "
+ "failing detection.\n", p->host_no);
+ p->irq = 0;
+ return(0);
+ }
+
+ p->qoutfifo = p->untagged_scbs + 256;
+ p->qinfifo = p->qoutfifo + 256;
+ for (i = 0; i < 256; i++)
+ {
+ p->untagged_scbs[i] = SCB_LIST_NULL;
+ p->qinfifo[i] = SCB_LIST_NULL;
+ p->qoutfifo[i] = SCB_LIST_NULL;
+ }
+
+ hscb_physaddr = p->fifo_dma;
aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
@@ -8315,11 +8573,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
first_aic7xxx = p;
/*
- * Clear out any possible pending interrupts, again.
- */
- aic7xxx_clear_intstat(p);
-
- /*
* Allocate the first set of scbs for this controller. This is to stream-
* line code elsewhere in the driver. If we have to check for the existence
* of scbs in certain code sections, it slows things down. However, as
@@ -8373,20 +8626,21 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
}
- /*
- * Some of the new Ultra2 chipsets need a longer delay after a chip
- * reset than just the init setup creates, so we have to delay here
- * before we go into a reset in order to make the chips happy.
- */
- if (p->features & AHC_ULTRA2)
- mdelay(250);
aic7xxx_reset_current_bus(p);
/*
- * Delay for the reset delay.
+ * Delay for the reset delay by setting the timer, this will delay
+ * future commands sent to any devices.
*/
- if (!reset_delay)
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ p->flags |= AHC_RESET_DELAY;
+ for(i=0; i<MAX_TARGETS; i++)
+ {
+ p->dev_expires[i] = jiffies + (4 * HZ);
+ p->dev_timer_active |= (0x01 << i);
+ }
+ p->dev_timer.expires = p->dev_expires[p->scsi_id];
+ add_timer(&p->dev_timer);
+ p->dev_timer_active |= (0x01 << MAX_TARGETS);
}
else
{
@@ -8396,11 +8650,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
"the no_reset\n", p->host_no);
printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
"for it.\n", p->host_no);
- printk(KERN_INFO "(scsi%d) The no_reset option is known to break some "
- "systems,\n", p->host_no);
- printk(KERN_INFO "(scsi%d) and is not supported by the driver author\n",
- p->host_no);
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
}
}
@@ -8426,10 +8675,23 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
{
printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
"controller.\n", p->host_no, p->irq);
+ aic_outb(p, 0, SIMODE1);
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
p->irq = 0;
return (0);
}
+ if(aic_inb(p, INTSTAT) & INT_PEND)
+ printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n",
+ p->host_no, -1, -1 , -1);
+ aic7xxx_clear_intstat(p);
+
+#ifdef MODULE
+ enable_irq(p->irq);
+#endif
+
unpause_sequencer(p, /* unpause_always */ TRUE);
return (found);
@@ -8462,7 +8724,7 @@ aic7xxx_chip_reset(struct aic7xxx_host *p)
wait = 1000; /* 1 second (1000 * 1 msec) */
while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
{
- mdelay(1); /* 1 msec */
+ udelay(1); /* 1 msec */
}
pause_sequencer(p);
@@ -8566,9 +8828,11 @@ aic7xxx_free(struct aic7xxx_host *p)
*/
if (p->scb_data != NULL)
{
+ struct aic7xxx_scb_dma *scb_dma = NULL;
if (p->scb_data->hscbs != NULL)
{
- kfree(p->scb_data->hscb_kmalloc_ptr);
+ pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len,
+ p->scb_data->hscbs, p->scb_data->hscbs_dma);
p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL;
}
/*
@@ -8579,6 +8843,14 @@ aic7xxx_free(struct aic7xxx_host *p)
*/
for (i = 0; i < p->scb_data->numscbs; i++)
{
+ if (p->scb_data->scb_array[i]->scb_dma != scb_dma)
+ {
+ scb_dma = p->scb_data->scb_array[i]->scb_dma;
+ pci_free_consistent(p->pdev, scb_dma->dma_len,
+ (void *)((unsigned long)scb_dma->dma_address
+ - scb_dma->dma_offset),
+ scb_dma->dma_address);
+ }
if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
p->scb_data->scb_array[i] = NULL;
@@ -8606,6 +8878,7 @@ aic7xxx_free(struct aic7xxx_host *p)
}
}
+ pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
}
/*+F*************************************************************************
@@ -8657,15 +8930,15 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
if (!have_seeprom)
{
p->sc_size = 128;
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, p->sc_type);
if (!have_seeprom)
{
if(p->sc_type == C46)
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, C56_66);
else
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+ have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
scarray, p->sc_size, C46);
}
}
@@ -9098,260 +9371,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
template->sg_tablesize = AIC7XXX_MAX_SG;
-#if defined(__i386__) || defined(__alpha__)
-#ifdef CONFIG_PCI
- /*
- * PCI-bus chipset probe.
- */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- if (pci_present())
- {
- if (pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82450GX,
- NULL))
- aic7xxx_no_probe = 1;
- if (pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82451NX,
- NULL))
- aic7xxx_no_probe = 1;
- }
-#else
-#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
- if (pcibios_present())
- {
- unsigned char pci_bus, pci_devfn;
- if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82450GX,
- 0, &pci_bus, &pci_devfn)) )
- aic7xxx_no_probe = 1;
- if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82451NX,
- 0, &pci_bus, &pci_devfn)) )
- aic7xxx_no_probe = 1;
- }
-#endif /* LINUX_VERSION_CODE */
-#endif /* CONFIG_PCI */
- /*
- * EISA/VL-bus card signature probe.
- */
- slot = MINSLOT;
- while ( (slot <= MAXSLOT) &&
- !(aic7xxx_no_probe) )
- {
- base = SLOTBASE(slot) + MINREG;
-
- if (check_region(base, MAXREG - MINREG))
- {
- /*
- * Some other driver has staked a
- * claim to this i/o region already.
- */
- slot++;
- continue; /* back to the beginning of the for loop */
- }
- flags = 0;
- type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
- if (type == -1)
- {
- slot++;
- continue;
- }
- temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
- if (temp_p == NULL)
- {
- printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
- slot++;
- continue; /* back to the beginning of the while loop */
- }
- /*
- * Pause the card preserving the IRQ type. Allow the operator
- * to override the IRQ trigger.
- */
- if (aic7xxx_irq_trigger == 1)
- hcntrl = IRQMS; /* Level */
- else if (aic7xxx_irq_trigger == 0)
- hcntrl = 0; /* Edge */
- else
- hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
- memset(temp_p, 0, sizeof(struct aic7xxx_host));
- temp_p->unpause = hcntrl | INTEN;
- temp_p->pause = hcntrl | PAUSE | INTEN;
- temp_p->base = base;
- temp_p->mbase = 0;
- temp_p->maddr = 0;
- temp_p->pci_bus = 0;
- temp_p->pci_device_fn = slot;
- aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
- while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
- if (aic7xxx_chip_reset(temp_p) == -1)
- temp_p->irq = 0;
- else
- temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
- temp_p->flags |= AHC_PAGESCBS;
-
- switch (temp_p->irq)
- {
- case 9:
- case 10:
- case 11:
- case 12:
- case 14:
- case 15:
- break;
-
- default:
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
- "level %d, ignoring.\n", temp_p->irq);
- kfree(temp_p);
- slot++;
- continue; /* back to the beginning of the while loop */
- }
-
- /*
- * We are commited now, everything has been checked and this card
- * has been found, now we just set it up
- */
-
- /*
- * Insert our new struct into the list at the end
- */
- if (list_p == NULL)
- {
- list_p = current_p = temp_p;
- }
- else
- {
- current_p = list_p;
- while (current_p->next != NULL)
- current_p = current_p->next;
- current_p->next = temp_p;
- }
-
- switch (type)
- {
- case 0:
- temp_p->board_name_index = 2;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %d\n",
- board_names[2], slot);
- /* FALLTHROUGH */
- case 1:
- {
- temp_p->chip = AHC_AIC7770 | AHC_EISA;
- temp_p->features |= AHC_AIC7770_FE;
- temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
-
- /*
- * Get the primary channel information. Right now we don't
- * do anything with this, but someday we will be able to inform
- * the mid-level SCSI code which channel is primary.
- */
- if (temp_p->board_name_index == 0)
- {
- temp_p->board_name_index = 3;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %d\n",
- board_names[3], slot);
- }
- if (temp_p->bios_control & CHANNEL_B_PRIMARY)
- {
- temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
- }
-
- if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
- {
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- }
- else
- {
- temp_p->flags &= ~AHC_USEDEFAULTS;
- temp_p->flags |= AHC_BIOS_ENABLED;
- if ( (temp_p->bios_control & 0x20) == 0 )
- {
- temp_p->bios_address = 0xcc000;
- temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
- }
- else
- {
- temp_p->bios_address = 0xd0000;
- temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
- }
- }
- temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
- temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
- if (temp_p->features & AHC_WIDE)
- {
- temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
- temp_p->scsi_id_b = temp_p->scsi_id;
- }
- else
- {
- temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
- temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
- }
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- }
-
- case 2:
- case 3:
- temp_p->chip = AHC_AIC7770 | AHC_VL;
- temp_p->features |= AHC_AIC7770_FE;
- if (type == 2)
- temp_p->flags |= AHC_BIOS_ENABLED;
- else
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
- sxfrctl1 = STPWEN;
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- temp_p->board_name_index = 4;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at VLB %d\n",
- board_names[2], slot);
- switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
- {
- case 0x00:
- temp_p->bios_address = 0xe0000;
- break;
- case 0x20:
- temp_p->bios_address = 0xc8000;
- break;
- case 0x40:
- temp_p->bios_address = 0xd0000;
- break;
- case 0x60:
- temp_p->bios_address = 0xd8000;
- break;
- default:
- break; /* can't get here */
- }
- break;
-
- default: /* Won't get here. */
- break;
- }
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
- (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
- temp_p->irq,
- (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
- }
-
- /*
- * Set the FIFO threshold and the bus off time.
- */
- hostconf = aic_inb(temp_p, HOSTCONF);
- aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
- aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
- slot++;
- found++;
- }
-
-#endif /* defined(__i386__) || defined(__alpha__) */
-
#ifdef CONFIG_PCI
/*
* PCI-bus probe.
@@ -9485,7 +9504,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
AHC_AIC7896_FE, 25,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWR,
AHC_AIC7860_FE, 26,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
@@ -9594,8 +9613,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
if (aic7xxx_verbose & VERBOSE_PROBE2)
printk("aic7xxx: <%s> at PCI %d/%d\n",
board_names[aic_pdevs[i].board_name_index],
- PCI_SLOT(temp_p->pdev->devfn),
- PCI_FUNC(temp_p->pdev->devfn));
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
pci_read_config_word(pdev, PCI_COMMAND, &command);
if (aic7xxx_verbose & VERBOSE_PROBE2)
{
@@ -9651,8 +9670,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
if ( temp_p == NULL )
continue;
if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at PCI %d/%d\n",
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
@@ -9682,14 +9702,28 @@ aic7xxx_detect(Scsi_Host_Template *template)
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
+ if(check_region(temp_p->base, MAXREG - MINREG))
+ {
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: I/O ports already in use, ignoring.\n");
+ kfree(temp_p);
+ temp_p = NULL;
+ continue;
+ }
+
temp_p->unpause = INTEN;
temp_p->pause = temp_p->unpause | PAUSE;
if ( ((temp_p->base == 0) &&
(temp_p->mbase == 0)) ||
(temp_p->irq == 0) )
{
- printk("aic7xxx: <%s> at PCI %d/%d\n",
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
@@ -9724,8 +9758,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* OK.....we failed our test....go back to programmed I/O
*/
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
@@ -9742,6 +9777,11 @@ aic7xxx_detect(Scsi_Host_Template *template)
#endif
/*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
+
+ /*
* We HAVE to make sure the first pause_sequencer() and all other
* subsequent I/O that isn't PCI config space I/O takes place
* after the MMAPed I/O region is configured and tested. The
@@ -9773,14 +9813,31 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* Get current termination setting
*/
- sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+ sxfrctl1 = aic_inb(temp_p, SXFRCTL1);
if (aic7xxx_chip_reset(temp_p) == -1)
{
+ release_region(temp_p->base, MAXREG - MINREG);
kfree(temp_p);
temp_p = NULL;
continue;
}
+ /*
+ * Very quickly put the term setting back into the register since
+ * the chip reset may cause odd things to happen. This is to keep
+ * LVD busses with lots of drives from draining the power out of
+ * the diffsense line before we get around to running the
+ * configure_termination() function. Also restore the STPWLEVEL
+ * bit of DEVCONFIG
+ */
+ aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+ pcibios_write_config_dword(temp_p->pci_bus, temp_p->pci_device_fn,
+ DEVCONFIG, devconfig);
+#else
+ pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
+#endif
+ sxfrctl1 &= STPWEN;
/*
* We need to set the CHNL? assignments before loading the SEEPROM
@@ -9815,7 +9872,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
case AHC_AIC7896: /* 7896/7 */
case AHC_AIC7899: /* 7899 */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- if (PCI_FUNC(temp_p->pdev->devfn) != 0)
+ if (PCI_FUNC(pdev->devfn) != 0)
{
temp_p->flags |= AHC_CHNLB;
}
@@ -10007,8 +10064,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
{
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: external SCB RAM detected, "
@@ -10025,8 +10083,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
else if (devconfig & RAMPSM)
{
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
PCI_SLOT(temp_p->pci_device_fn),
PCI_FUNC(temp_p->pci_device_fn));
printk("aic7xxx: external SCB RAM detected, "
@@ -10091,6 +10150,235 @@ aic7xxx_detect(Scsi_Host_Template *template)
} /* for PCI_DEVICES */
} /* PCI BIOS present */
#endif CONFIG_PCI
+
+#if defined(__i386__) || defined(__alpha__)
+ /*
+ * EISA/VL-bus card signature probe.
+ */
+ slot = MINSLOT;
+ while ( (slot <= MAXSLOT) &&
+ !(aic7xxx_no_probe) )
+ {
+ base = SLOTBASE(slot) + MINREG;
+
+ if (check_region(base, MAXREG - MINREG))
+ {
+ /*
+ * Some other driver has staked a
+ * claim to this i/o region already.
+ */
+ slot++;
+ continue; /* back to the beginning of the for loop */
+ }
+ flags = 0;
+ type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
+ if (type == -1)
+ {
+ slot++;
+ continue;
+ }
+ temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+ if (temp_p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+ /*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(base, MAXREG - MINREG, "aic7xxx");
+
+ /*
+ * Pause the card preserving the IRQ type. Allow the operator
+ * to override the IRQ trigger.
+ */
+ if (aic7xxx_irq_trigger == 1)
+ hcntrl = IRQMS; /* Level */
+ else if (aic7xxx_irq_trigger == 0)
+ hcntrl = 0; /* Edge */
+ else
+ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
+ memset(temp_p, 0, sizeof(struct aic7xxx_host));
+ temp_p->unpause = hcntrl | INTEN;
+ temp_p->pause = hcntrl | PAUSE | INTEN;
+ temp_p->base = base;
+ temp_p->mbase = 0;
+ temp_p->maddr = 0;
+ temp_p->pci_bus = 0;
+ temp_p->pci_device_fn = slot;
+ aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+ while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+ if (aic7xxx_chip_reset(temp_p) == -1)
+ temp_p->irq = 0;
+ else
+ temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+ temp_p->flags |= AHC_PAGESCBS;
+
+ switch (temp_p->irq)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+
+ default:
+ printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+ "level %d, ignoring.\n", temp_p->irq);
+ kfree(temp_p);
+ release_region(base, MAXREG - MINREG);
+ slot++;
+ continue; /* back to the beginning of the while loop */
+ }
+
+ /*
+ * We are commited now, everything has been checked and this card
+ * has been found, now we just set it up
+ */
+
+ /*
+ * Insert our new struct into the list at the end
+ */
+ if (list_p == NULL)
+ {
+ list_p = current_p = temp_p;
+ }
+ else
+ {
+ current_p = list_p;
+ while (current_p->next != NULL)
+ current_p = current_p->next;
+ current_p->next = temp_p;
+ }
+
+ switch (type)
+ {
+ case 0:
+ temp_p->board_name_index = 2;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[2], slot);
+ /* FALLTHROUGH */
+ case 1:
+ {
+ temp_p->chip = AHC_AIC7770 | AHC_EISA;
+ temp_p->features |= AHC_AIC7770_FE;
+ temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
+
+ /*
+ * Get the primary channel information. Right now we don't
+ * do anything with this, but someday we will be able to inform
+ * the mid-level SCSI code which channel is primary.
+ */
+ if (temp_p->board_name_index == 0)
+ {
+ temp_p->board_name_index = 3;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[3], slot);
+ }
+ if (temp_p->bios_control & CHANNEL_B_PRIMARY)
+ {
+ temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
+ }
+
+ if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+ {
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ }
+ else
+ {
+ temp_p->flags &= ~AHC_USEDEFAULTS;
+ temp_p->flags |= AHC_BIOS_ENABLED;
+ if ( (temp_p->bios_control & 0x20) == 0 )
+ {
+ temp_p->bios_address = 0xcc000;
+ temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
+ }
+ else
+ {
+ temp_p->bios_address = 0xd0000;
+ temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
+ }
+ }
+ temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+ temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+ if (temp_p->features & AHC_WIDE)
+ {
+ temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
+ temp_p->scsi_id_b = temp_p->scsi_id;
+ }
+ else
+ {
+ temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+ temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
+ }
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ break;
+ }
+
+ case 2:
+ case 3:
+ temp_p->chip = AHC_AIC7770 | AHC_VL;
+ temp_p->features |= AHC_AIC7770_FE;
+ if (type == 2)
+ temp_p->flags |= AHC_BIOS_ENABLED;
+ else
+ temp_p->flags &= ~AHC_BIOS_ENABLED;
+ if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
+ sxfrctl1 = STPWEN;
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ temp_p->board_name_index = 4;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk("aic7xxx: <%s> at VLB %d\n",
+ board_names[2], slot);
+ switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
+ {
+ case 0x00:
+ temp_p->bios_address = 0xe0000;
+ break;
+ case 0x20:
+ temp_p->bios_address = 0xc8000;
+ break;
+ case 0x40:
+ temp_p->bios_address = 0xd0000;
+ break;
+ case 0x60:
+ temp_p->bios_address = 0xd8000;
+ break;
+ default:
+ break; /* can't get here */
+ }
+ break;
+
+ default: /* Won't get here. */
+ break;
+ }
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ {
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+ (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+ temp_p->irq,
+ (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
+ }
+
+ /*
+ * Set the FIFO threshold and the bus off time.
+ */
+ hostconf = aic_inb(temp_p, HOSTCONF);
+ aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+ aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+ slot++;
+ found++;
+ }
+
+#endif /* defined(__i386__) || defined(__alpha__) */
+
/*
* Now, we re-order the probed devices by BIOS address and BUS class.
* In general, we follow this algorithm to make the adapters show up
@@ -10333,6 +10621,7 @@ aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
cmd->lun = 0;
cmd->request_bufflen = 255;
cmd->request_buffer = buffer;
+ cmd->sc_data_direction = SCSI_DATA_READ;
cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
cmd->bufflen = 0;
cmd->buffer = NULL;
@@ -10391,7 +10680,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
* instead of slowing down if those exist. That's hard to do with simple
* checksums though.
*/
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
"validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -10422,7 +10711,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
}
else
{
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Performing Domain validation.\n",
p->host_no, CTL_OF_CMD(cmd));
@@ -10447,7 +10736,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
}
else
{
- if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
(p->needdv & (1<<tindex)) )
{
printk(INFO_LEAD "Successfully completed Domain validation.\n",
@@ -10663,7 +10952,8 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* little-endian format.
*/
hscb->SCSI_cmd_length = cmd->cmd_len;
- hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
+ memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
+ hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
if (cmd->use_sg)
{
@@ -10675,10 +10965,11 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* differences and the kernel SG list uses virtual addresses where
* we need physical addresses.
*/
- int i;
+ int i, use_sg;
sg = (struct scatterlist *)cmd->request_buffer;
scb->sg_length = 0;
+ use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
/*
* Copy the segments into the SG array. NOTE!!! - We used to
* have the first entry both in the data_pointer area and the first
@@ -10686,29 +10977,34 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* entry in both places, but now we download the address of
* scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
*/
- for (i = 0; i < cmd->use_sg; i++)
+ for (i = 0; i < use_sg; i++)
{
- scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
- scb->sg_list[i].length = cpu_to_le32(sg[i].length);
- scb->sg_length += sg[i].length;
+ unsigned int len = sg_dma_len(sg+i);
+ scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
+ scb->sg_list[i].length = cpu_to_le32(len);
+ scb->sg_length += len;
}
/* Copy the first SG into the data pointer area. */
hscb->data_pointer = scb->sg_list[0].address;
hscb->data_count = scb->sg_list[0].length;
- scb->sg_count = cmd->use_sg;
- hscb->SG_segment_count = cmd->use_sg;
- hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
+ scb->sg_count = i;
+ hscb->SG_segment_count = i;
+ hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
}
else
{
if (cmd->request_bufflen)
{
- scb->sg_count = 1;
- scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+ unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ aic7xxx_mapping(cmd) = address;
+ scb->sg_list[0].address = cpu_to_le32(address);
scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+ scb->sg_count = 1;
scb->sg_length = cmd->request_bufflen;
hscb->SG_segment_count = 1;
- hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+ hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
hscb->data_count = scb->sg_list[0].length;
hscb->data_pointer = scb->sg_list[0].address;
}
@@ -11991,7 +12287,7 @@ aic7xxx_print_card(struct aic7xxx_host *p)
break;
case AHC_PCI:
default:
- printk("PCI %d/%d.\n", PCI_SLOT(p->pci_device_fn),
+ printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
PCI_FUNC(p->pci_device_fn));
break;
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index 6cc347d5b..fb554727b 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -691,7 +691,8 @@ register INTSTAT {
mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */
- mask ABORT_REQUESTED 0x50|SEQINT /* Reconect of aborted SCB */
+ mask WIDE_RESIDUE 0x50|SEQINT /* need kernel to back up */
+ /* the SG array for us */
mask REJECT_MSG 0x60|SEQINT /* Reject message received */
mask BAD_STATUS 0x70|SEQINT /* Bad status from target */
mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index 8e8dc98ee..de3afbf92 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -517,10 +517,12 @@ data_phase_loop:
}
data_phase_inbounds:
/* If we are the last SG block, tell the hardware. */
-if ((p->features & AHC_ULTRA2) == 0) {
cmp SG_COUNT,0x01 jne data_phase_wideodd;
- and DMAPARAMS, ~WIDEODD;
-}
+ if ((p->features & AHC_ULTRA2) == 0) {
+ and DMAPARAMS, ~WIDEODD;
+ } else {
+ mvi SG_CACHEPTR, LAST_SEG;
+ }
data_phase_wideodd:
if ((p->features & AHC_ULTRA2) != 0) {
mov SINDEX, ALLONES;
@@ -530,7 +532,7 @@ data_phase_dma_loop:
test SSTAT0, SDONE jnz data_phase_dma_done;
test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
data_phase_dma_phasemis:
- test SSTAT0,SDONE jnz . + 2;
+ test SSTAT0,SDONE jnz data_phase_dma_done;
clr SINDEX; /* Remember the phasemiss */
} else {
mov DMAPARAMS call dma;
@@ -615,9 +617,10 @@ prefetched_segs_avail:
test SSTAT1, REQINIT jz .;
test SSTAT1,PHASEMIS jz data_phase_loop;
+/* This drops the last SG segment down to the shadow layer for us */
if ((p->features & AHC_ULTRA2) != 0) {
mov DFCNTRL, DMAPARAMS;
- test SSTAT0, SDONE jnz .;
+ test SSTAT0, SDONE jnz .;
}
data_phase_finish:
@@ -713,7 +716,7 @@ p_command:
mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
test SSTAT0, SDONE jnz .;
p_command_dma_loop:
- test SSTAT0, DMADONE jnz p_command_ultra2_dma_done;
+ test SSTAT0, SDONE jnz p_command_ultra2_dma_done;
test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */
p_command_ultra2_dma_done:
and DFCNTRL, ~HDMAEN;
@@ -830,6 +833,7 @@ p_mesgin:
cmp A,MSG_EXTENDED je mesgin_extended;
cmp A,MSG_MESSAGE_REJECT je mesgin_reject;
cmp A,MSG_NOOP je mesgin_done;
+ cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_wide_residue;
rej_mesgin:
/*
@@ -1057,6 +1061,36 @@ mesgin_reject:
jmp mesgin_done;
/*
+ * Wide Residue. We handle the simple cases, but pass of the one hard case
+ * to the kernel (when the residue byte happened to cause us to advance our
+ * sg element array, so we know have to back that advance out).
+ */
+mesgin_wide_residue:
+ mvi ARG_1 call inb_next; /* ACK the wide_residue and get */
+ /* the size byte */
+/*
+ * See if we'll ignore this wide residue (because it's an overrun byte)
+ */
+ if ((p->features & AHC_ULTRA2) != 0) {
+ test SSTAT2, WIDE_RES jnz mesgin_done;
+ } else {
+ test SCB_RESID_SGCNT,0xff jnz wide_residue_int;
+ test SCB_RESID_DCNT[0],0xff jnz wide_residue_int;
+ test SCB_RESID_DCNT[1],0xff jnz wide_residue_int;
+ test SCB_RESID_DCNT[2],0xff jnz wide_residue_int;
+ jmp mesgin_done;
+ }
+wide_residue_int:
+/*
+ * In order for this to be reliable, we have to do all sorts of horrible
+ * magic in terms of resetting the datafifo and reloading the shadow layer
+ * with the correct new values (so that a subsequent save data pointers
+ * message will do the right thing). We let the kernel do that work.
+ */
+ mvi INTSTAT,WIDE_RESIDUE;
+ jmp mesgin_done;
+
+/*
* [ ADD MORE MESSAGE HANDLING HERE ]
*/
@@ -1093,7 +1127,7 @@ inb_next_wait:
* before continuing.
*/
test SSTAT1, REQINIT jz inb_next_wait;
- test SSTAT1, SCSIPERR jnz inb_next_wait;
+ test SSTAT1, SCSIPERR jnz .;
and LASTPHASE, PHASE_MASK, SCSISIGI;
cmp LASTPHASE, P_MESGIN jne mesgin_phasemis;
inb_first:
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c
index 1fb00893e..ec80af90d 100644
--- a/drivers/scsi/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_proc.c
@@ -178,7 +178,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, " SCSI Adapter: %s\n",
board_names[p->board_name_index]);
if (p->flags & AHC_TWIN)
- size += sprintf(BLS, " Twin Channel\n");
+ size += sprintf(BLS, " Twin Channel Controller ");
else
{
char *channel = "";
@@ -209,9 +209,22 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
ultra = "Ultra-2 LVD/SE ";
else if (p->features & AHC_ULTRA)
ultra = "Ultra ";
- size += sprintf(BLS, " %s%sController%s\n",
+ size += sprintf(BLS, " %s%sController%s ",
ultra, wide, channel);
}
+ switch(p->chip & ~AHC_CHIPID_MASK)
+ {
+ case AHC_VL:
+ size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
+ break;
+ case AHC_EISA:
+ size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
+ break;
+ default:
+ size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
+ PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
+ break;
+ }
if( !(p->maddr) )
{
size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base);
@@ -224,11 +237,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
{
size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address);
}
- if( p->chip & AHC_PCI )
- {
- size += sprintf(BLS, " PCI Bus 0x%02x Device 0x%02x\n", p->pci_bus,
- p->pci_device_fn);
- }
size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
(p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
diff --git a/drivers/scsi/aic7xxx_reg.h b/drivers/scsi/aic7xxx_reg.h
index f86e1bec8..4baa00911 100644
--- a/drivers/scsi/aic7xxx_reg.h
+++ b/drivers/scsi/aic7xxx_reg.h
@@ -188,8 +188,8 @@
#define BRDRW 0x04
#define BRDRW_ULTRA2 0x02
#define BRDCTL1 0x02
-#define BRDSTB_ULTRA2 0x01
#define BRDCTL0 0x01
+#define BRDSTB_ULTRA2 0x01
#define SEECTL 0x1e
#define EXTARBACK 0x80
@@ -402,7 +402,7 @@
#define RESIDUAL 0x81
#define BAD_STATUS 0x71
#define REJECT_MSG 0x61
-#define ABORT_REQUESTED 0x51
+#define WIDE_RESIDUE 0x51
#define EXTENDED_MSG 0x41
#define NO_MATCH 0x31
#define NO_IDENT 0x21
@@ -465,6 +465,8 @@
#define TARGCRCENDEN 0x08
#define TARGCRCCNTEN 0x04
+#define QOUTCNT 0x9e
+
#define SCSIPHASE 0x9e
#define SP_STATUS 0x20
#define SP_COMMAND 0x10
@@ -473,8 +475,6 @@
#define SP_DATA_IN 0x02
#define SP_DATA_OUT 0x01
-#define QOUTCNT 0x9e
-
#define SFUNCT 0x9f
#define ALT_MODE 0x80
@@ -595,8 +595,8 @@
#define RD_DFTHRSH_63 0x03
#define RD_DFTHRSH_50 0x02
#define RD_DFTHRSH_25 0x01
-#define WR_DFTHRSH_MIN 0x00
#define RD_DFTHRSH_MIN 0x00
+#define WR_DFTHRSH_MIN 0x00
#define SG_CACHEPTR 0xfc
#define SG_USER_DATA 0xfc
@@ -604,18 +604,18 @@
#define LAST_SEG_DONE 0x01
+#define CMD_GROUP_CODE_SHIFT 0x05
+#define BUS_8_BIT 0x00
+#define QOUTFIFO_OFFSET 0x01
+#define CCSGRAM_MAXSEGS 0x10
#define CMD_GROUP2_BYTE_DELTA 0xfa
#define MAX_OFFSET_8BIT 0x0f
#define BUS_16_BIT 0x01
#define QINFIFO_OFFSET 0x02
#define CMD_GROUP5_BYTE_DELTA 0x0b
-#define CMD_GROUP_CODE_SHIFT 0x05
#define MAX_OFFSET_ULTRA2 0x7f
#define MAX_OFFSET_16BIT 0x08
-#define BUS_8_BIT 0x00
-#define QOUTFIFO_OFFSET 0x01
#define UNTAGGEDSCB_OFFSET 0x00
-#define CCSGRAM_MAXSEGS 0x10
#define SCB_LIST_NULL 0xff
#define SG_SIZEOF 0x08
#define CMD_GROUP4_BYTE_DELTA 0x04
diff --git a/drivers/scsi/aic7xxx_seq.c b/drivers/scsi/aic7xxx_seq.c
index 49502b6cd..511bfcb73 100644
--- a/drivers/scsi/aic7xxx_seq.c
+++ b/drivers/scsi/aic7xxx_seq.c
@@ -26,12 +26,12 @@ static unsigned char seqprog[] = {
0x00, 0x4d, 0x12, 0x70,
0x01, 0x4e, 0x9c, 0x18,
0xbf, 0x60, 0xc0, 0x08,
- 0x00, 0x6a, 0xa8, 0x5c,
+ 0x00, 0x6a, 0xbe, 0x5c,
0xff, 0x4e, 0xc8, 0x18,
- 0x02, 0x6a, 0xbe, 0x5b,
+ 0x02, 0x6a, 0xd4, 0x5b,
0xff, 0x52, 0x20, 0x09,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x52, 0x34, 0x5c,
+ 0x00, 0x52, 0x4a, 0x5c,
0x03, 0xb0, 0x52, 0x31,
0xff, 0xb0, 0x52, 0x09,
0xff, 0xb1, 0x54, 0x09,
@@ -76,7 +76,7 @@ static unsigned char seqprog[] = {
0x10, 0x03, 0xfc, 0x78,
0xff, 0x50, 0xc8, 0x08,
0x88, 0x6a, 0xcc, 0x00,
- 0x49, 0x6a, 0x24, 0x5c,
+ 0x49, 0x6a, 0x3a, 0x5c,
0x01, 0x6a, 0x26, 0x01,
0xff, 0x6a, 0xca, 0x08,
0x08, 0x01, 0x02, 0x00,
@@ -117,11 +117,11 @@ static unsigned char seqprog[] = {
0xff, 0x65, 0xca, 0x18,
0xff, 0x65, 0xd8, 0x68,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
+ 0x00, 0x65, 0xb0, 0x5c,
0x40, 0x51, 0xf0, 0x78,
0xe4, 0x6a, 0x06, 0x00,
0x08, 0x01, 0x02, 0x00,
- 0x04, 0x6a, 0x56, 0x5b,
+ 0x04, 0x6a, 0x6c, 0x5b,
0x01, 0x50, 0xa0, 0x18,
0x00, 0x50, 0xf6, 0xe0,
0xff, 0x6a, 0xa0, 0x08,
@@ -147,13 +147,13 @@ static unsigned char seqprog[] = {
0x08, 0x6a, 0x66, 0x58,
0x80, 0x6a, 0x68, 0x00,
0x80, 0x36, 0x6c, 0x00,
- 0x00, 0x65, 0x08, 0x5c,
+ 0x00, 0x65, 0x1e, 0x5c,
0xff, 0x3d, 0xc8, 0x08,
0xbf, 0x64, 0x5a, 0x79,
- 0x80, 0x64, 0x20, 0x72,
- 0xa0, 0x64, 0x50, 0x72,
- 0xc0, 0x64, 0x48, 0x72,
- 0xe0, 0x64, 0x90, 0x72,
+ 0x80, 0x64, 0x22, 0x72,
+ 0xa0, 0x64, 0x52, 0x72,
+ 0xc0, 0x64, 0x4a, 0x72,
+ 0xe0, 0x64, 0x92, 0x72,
0x01, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
0xf7, 0x11, 0x22, 0x08,
@@ -173,13 +173,13 @@ static unsigned char seqprog[] = {
0x03, 0xa9, 0x18, 0x31,
0x03, 0xa9, 0x10, 0x30,
0x08, 0x6a, 0xcc, 0x00,
- 0xa9, 0x6a, 0x1e, 0x5c,
+ 0xa9, 0x6a, 0x34, 0x5c,
0x00, 0x65, 0x7a, 0x41,
0xa8, 0x6a, 0x6a, 0x00,
0x79, 0x6a, 0x6a, 0x00,
0x40, 0x3d, 0x62, 0x69,
0x04, 0x35, 0x6a, 0x00,
- 0x00, 0x65, 0x78, 0x5b,
+ 0x00, 0x65, 0x8e, 0x5b,
0x80, 0x6a, 0xd4, 0x01,
0x10, 0x36, 0x4e, 0x69,
0x10, 0x36, 0x6c, 0x00,
@@ -187,10 +187,10 @@ static unsigned char seqprog[] = {
0x03, 0x8c, 0x10, 0x30,
0x05, 0xa3, 0x70, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xac, 0x6a, 0x16, 0x5c,
- 0x00, 0x65, 0x10, 0x5c,
+ 0xac, 0x6a, 0x2c, 0x5c,
+ 0x00, 0x65, 0x26, 0x5c,
0x38, 0x6a, 0xcc, 0x00,
- 0xa3, 0x6a, 0x1a, 0x5c,
+ 0xa3, 0x6a, 0x30, 0x5c,
0xff, 0x38, 0x8a, 0x69,
0x80, 0x02, 0x04, 0x00,
0xe7, 0x35, 0x6a, 0x08,
@@ -199,51 +199,52 @@ static unsigned char seqprog[] = {
0xff, 0x6a, 0x10, 0x00,
0xff, 0x6a, 0x12, 0x00,
0xff, 0x6a, 0x14, 0x00,
- 0x01, 0x38, 0x8e, 0x61,
+ 0x01, 0x38, 0x90, 0x61,
0xbf, 0x35, 0x6a, 0x08,
+ 0x02, 0x6a, 0xf8, 0x01,
0xff, 0x69, 0xca, 0x08,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0x92, 0x69,
- 0x04, 0x0b, 0x9e, 0x69,
- 0x10, 0x0c, 0x94, 0x79,
- 0x04, 0x0b, 0x9c, 0x69,
+ 0x04, 0x0b, 0x94, 0x69,
+ 0x04, 0x0b, 0xa0, 0x69,
+ 0x10, 0x0c, 0x96, 0x79,
+ 0x04, 0x0b, 0xa0, 0x69,
0xff, 0x6a, 0xca, 0x08,
- 0x00, 0x35, 0x60, 0x5b,
- 0x80, 0x02, 0xf2, 0x69,
- 0xff, 0x65, 0xe2, 0x79,
+ 0x00, 0x35, 0x76, 0x5b,
+ 0x80, 0x02, 0xf4, 0x69,
+ 0xff, 0x65, 0xe4, 0x79,
0xff, 0x38, 0x70, 0x18,
- 0xff, 0x38, 0xe2, 0x79,
- 0x80, 0xea, 0xbe, 0x61,
+ 0xff, 0x38, 0xe4, 0x79,
+ 0x80, 0xea, 0xc0, 0x61,
0xef, 0x38, 0xc8, 0x18,
0x80, 0x6a, 0xc8, 0x00,
- 0x00, 0x65, 0xb0, 0x49,
+ 0x00, 0x65, 0xb2, 0x49,
0x33, 0x38, 0xc8, 0x28,
0xff, 0x64, 0xd0, 0x09,
0x04, 0x39, 0xc0, 0x31,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0xb6, 0x79,
+ 0x80, 0xeb, 0xb8, 0x79,
0xf7, 0xeb, 0xd6, 0x09,
- 0x08, 0xeb, 0xba, 0x69,
+ 0x08, 0xeb, 0xbc, 0x69,
0x01, 0x6a, 0xd6, 0x01,
0x08, 0xe9, 0x10, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0x39, 0x6a, 0x1c, 0x5c,
+ 0x39, 0x6a, 0x32, 0x5c,
0x08, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
- 0x88, 0x6a, 0x8a, 0x5c,
- 0x00, 0x65, 0x10, 0x5c,
+ 0x00, 0x65, 0xb0, 0x5c,
+ 0x88, 0x6a, 0xa0, 0x5c,
+ 0x00, 0x65, 0x26, 0x5c,
0xff, 0x6a, 0xc8, 0x08,
0x08, 0x39, 0x72, 0x18,
0x00, 0x3a, 0x74, 0x20,
- 0x01, 0x0c, 0xda, 0x79,
+ 0x01, 0x0c, 0xdc, 0x79,
0x10, 0x0c, 0x7a, 0x79,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0xe0, 0x69,
- 0x00, 0x65, 0xfa, 0x59,
+ 0x04, 0x0b, 0xe2, 0x69,
+ 0x00, 0x65, 0xfc, 0x59,
0x03, 0x08, 0x52, 0x31,
0xff, 0x38, 0x50, 0x09,
0xff, 0x08, 0x52, 0x09,
@@ -251,275 +252,285 @@ static unsigned char seqprog[] = {
0xff, 0x0a, 0x56, 0x09,
0xff, 0x38, 0x50, 0x09,
0x00, 0x65, 0x22, 0x41,
- 0x00, 0x65, 0xfa, 0x59,
+ 0x00, 0x65, 0xfc, 0x59,
0x7f, 0x02, 0x04, 0x08,
0xe1, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
- 0x04, 0x93, 0x10, 0x6a,
+ 0x04, 0x93, 0x12, 0x6a,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0xfe, 0x69,
+ 0x20, 0x93, 0x00, 0x6a,
0x02, 0x93, 0x26, 0x01,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x01, 0x94, 0x00, 0x7a,
- 0x10, 0x94, 0x0e, 0x6a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x01, 0x94, 0x02, 0x7a,
+ 0x10, 0x94, 0x10, 0x6a,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x12, 0x6a,
+ 0x08, 0x93, 0x14, 0x6a,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x16, 0x6a,
+ 0x20, 0x93, 0x18, 0x6a,
0x03, 0x08, 0x52, 0x31,
0xff, 0x38, 0x50, 0x09,
0x12, 0x01, 0x02, 0x00,
0xff, 0x6a, 0xd4, 0x0c,
- 0x00, 0x65, 0x78, 0x5b,
+ 0x00, 0x65, 0x8e, 0x5b,
0x05, 0xb4, 0x10, 0x31,
0x02, 0x6a, 0x1a, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xb4, 0x6a, 0x1a, 0x5c,
+ 0xb4, 0x6a, 0x30, 0x5c,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
- 0x00, 0x65, 0x10, 0x5c,
- 0x3d, 0x6a, 0x60, 0x5b,
+ 0x00, 0x65, 0x26, 0x5c,
+ 0x3d, 0x6a, 0x76, 0x5b,
0xac, 0x6a, 0x26, 0x01,
- 0x04, 0x0b, 0x36, 0x6a,
- 0x01, 0x0b, 0x3c, 0x6a,
- 0x10, 0x0c, 0x38, 0x7a,
+ 0x04, 0x0b, 0x38, 0x6a,
+ 0x04, 0x0b, 0x3e, 0x6a,
+ 0x10, 0x0c, 0x3a, 0x7a,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x3e, 0x6a,
+ 0x08, 0x93, 0x40, 0x6a,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x42, 0x6a,
+ 0x20, 0x93, 0x44, 0x6a,
0x12, 0x01, 0x02, 0x00,
0x00, 0x65, 0x22, 0x41,
- 0x00, 0x65, 0x78, 0x5b,
+ 0x00, 0x65, 0x8e, 0x5b,
0xff, 0x06, 0x44, 0x09,
0x00, 0x65, 0x22, 0x41,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x34, 0xca, 0x08,
- 0x80, 0x65, 0x74, 0x62,
+ 0x80, 0x65, 0x76, 0x62,
0x0f, 0xa1, 0xca, 0x08,
0x07, 0xa1, 0xca, 0x08,
0x40, 0xa0, 0xc8, 0x08,
0x00, 0x65, 0xca, 0x00,
0x80, 0x65, 0xca, 0x00,
- 0x80, 0xa0, 0x64, 0x7a,
+ 0x80, 0xa0, 0x66, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x76, 0x42,
- 0x20, 0xa0, 0x7c, 0x7a,
+ 0x00, 0x65, 0x78, 0x42,
+ 0x20, 0xa0, 0x7e, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xa0, 0x3d, 0x84, 0x62,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xa0, 0x3d, 0x86, 0x62,
0x23, 0xa0, 0x0c, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xa0, 0x3d, 0x84, 0x62,
- 0x00, 0xb9, 0x7c, 0x42,
- 0xff, 0x65, 0x7c, 0x62,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xa0, 0x3d, 0x86, 0x62,
+ 0x00, 0xb9, 0x7e, 0x42,
+ 0xff, 0x65, 0x7e, 0x62,
0xa1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x10, 0x51, 0x84, 0x72,
+ 0x10, 0x51, 0x86, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xa0, 0x3d, 0x4e, 0x72,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xa0, 0x3d, 0x50, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x34, 0xa6, 0x08,
- 0x80, 0x34, 0x8c, 0x62,
+ 0x80, 0x34, 0x8e, 0x62,
0x7f, 0xa0, 0x40, 0x09,
0x08, 0x6a, 0x68, 0x00,
0x00, 0x65, 0x22, 0x41,
- 0x64, 0x6a, 0x50, 0x5b,
- 0x80, 0x64, 0x00, 0x6b,
- 0x04, 0x64, 0xe2, 0x72,
- 0x02, 0x64, 0xe8, 0x72,
- 0x00, 0x6a, 0xaa, 0x72,
- 0x03, 0x64, 0xfc, 0x72,
- 0x01, 0x64, 0xde, 0x72,
- 0x07, 0x64, 0x3e, 0x73,
- 0x08, 0x64, 0xa6, 0x72,
+ 0x64, 0x6a, 0x66, 0x5b,
+ 0x80, 0x64, 0x04, 0x6b,
+ 0x04, 0x64, 0xe6, 0x72,
+ 0x02, 0x64, 0xec, 0x72,
+ 0x00, 0x6a, 0xae, 0x72,
+ 0x03, 0x64, 0x00, 0x73,
+ 0x01, 0x64, 0xe2, 0x72,
+ 0x07, 0x64, 0x42, 0x73,
+ 0x08, 0x64, 0xaa, 0x72,
+ 0x23, 0x64, 0x46, 0x73,
0x11, 0x6a, 0x22, 0x01,
- 0x07, 0x6a, 0x42, 0x5b,
+ 0x07, 0x6a, 0x58, 0x5b,
0xff, 0x06, 0xd4, 0x08,
0x00, 0x65, 0x22, 0x41,
- 0xff, 0xa8, 0xae, 0x6a,
- 0xff, 0xa2, 0xc6, 0x7a,
+ 0xff, 0xa8, 0xb2, 0x6a,
+ 0xff, 0xa2, 0xca, 0x7a,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x34, 0x5c,
- 0xff, 0xa2, 0xc6, 0x7a,
+ 0x00, 0xb9, 0x4a, 0x5c,
+ 0xff, 0xa2, 0xca, 0x7a,
0x71, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x40, 0x51, 0xc6, 0x62,
+ 0x40, 0x51, 0xca, 0x62,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x34, 0x5c,
+ 0x00, 0xb9, 0x4a, 0x5c,
0xff, 0x3e, 0x74, 0x09,
0xff, 0x90, 0x7c, 0x08,
0x00, 0x65, 0x50, 0x58,
0x00, 0x65, 0x34, 0x41,
- 0x20, 0xa0, 0xce, 0x6a,
+ 0x20, 0xa0, 0xd2, 0x6a,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0xde, 0x5b,
- 0xff, 0x6a, 0xf4, 0x5b,
+ 0x00, 0x6a, 0xf4, 0x5b,
+ 0xff, 0x6a, 0x0a, 0x5c,
0xff, 0xf8, 0xc8, 0x08,
0xff, 0x4f, 0xc8, 0x08,
- 0x01, 0x6a, 0xde, 0x5b,
- 0x00, 0xb9, 0xf4, 0x5b,
+ 0x01, 0x6a, 0xf4, 0x5b,
+ 0x00, 0xb9, 0x0a, 0x5c,
0x01, 0x4f, 0x9e, 0x18,
0x02, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0xa2, 0x5c,
+ 0x00, 0x65, 0xb8, 0x5c,
0x00, 0x65, 0x34, 0x41,
0x41, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
0x04, 0xa0, 0x40, 0x01,
- 0x00, 0x65, 0xba, 0x5c,
+ 0x00, 0x65, 0xd0, 0x5c,
0x00, 0x65, 0x34, 0x41,
- 0x10, 0x36, 0xa6, 0x7a,
+ 0x10, 0x36, 0xaa, 0x7a,
0x05, 0x38, 0x46, 0x31,
0x04, 0x14, 0x58, 0x31,
0x03, 0xa9, 0x60, 0x31,
0xa3, 0x6a, 0xcc, 0x00,
- 0x38, 0x6a, 0x1a, 0x5c,
+ 0x38, 0x6a, 0x30, 0x5c,
0xac, 0x6a, 0xcc, 0x00,
- 0x14, 0x6a, 0x1c, 0x5c,
- 0xa9, 0x6a, 0x1e, 0x5c,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x14, 0x6a, 0x32, 0x5c,
+ 0xa9, 0x6a, 0x34, 0x5c,
+ 0x00, 0x65, 0xaa, 0x42,
0xef, 0x36, 0x6c, 0x08,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x00, 0x65, 0xaa, 0x42,
0x0f, 0x64, 0xc8, 0x08,
0x07, 0x64, 0xc8, 0x08,
0x00, 0x37, 0x6e, 0x00,
0xff, 0x6a, 0xa4, 0x00,
- 0x00, 0x65, 0xae, 0x5b,
- 0xff, 0x51, 0x12, 0x73,
- 0x20, 0x36, 0x1c, 0x7b,
- 0x00, 0x90, 0x9c, 0x5b,
- 0x00, 0x65, 0x1e, 0x43,
+ 0x00, 0x65, 0xc4, 0x5b,
+ 0xff, 0x51, 0x16, 0x73,
+ 0x20, 0x36, 0x20, 0x7b,
+ 0x00, 0x90, 0xb2, 0x5b,
+ 0x00, 0x65, 0x22, 0x43,
0xff, 0x06, 0xd4, 0x08,
- 0x00, 0x65, 0x08, 0x5c,
- 0xe0, 0x3d, 0x38, 0x63,
- 0x20, 0x12, 0x38, 0x63,
- 0x51, 0x6a, 0x46, 0x5b,
- 0x00, 0x65, 0x96, 0x5b,
+ 0x00, 0x65, 0x1e, 0x5c,
+ 0xe0, 0x3d, 0x3c, 0x63,
+ 0x20, 0x12, 0x3c, 0x63,
+ 0x51, 0x6a, 0x5c, 0x5b,
+ 0x00, 0x65, 0xac, 0x5b,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0xa1, 0x30, 0x63,
- 0x04, 0xa0, 0x30, 0x7b,
+ 0x00, 0xa1, 0x34, 0x63,
+ 0x04, 0xa0, 0x34, 0x7b,
0xfb, 0xa0, 0x40, 0x09,
0x80, 0x36, 0x6c, 0x00,
- 0x80, 0xa0, 0xa6, 0x7a,
+ 0x80, 0xa0, 0xaa, 0x7a,
0x7f, 0xa0, 0x40, 0x09,
- 0xff, 0x6a, 0x42, 0x5b,
- 0x00, 0x65, 0xa6, 0x42,
- 0x04, 0xa0, 0x36, 0x7b,
- 0x00, 0x65, 0xba, 0x5c,
- 0x00, 0x65, 0x38, 0x43,
- 0x00, 0x65, 0xa2, 0x5c,
+ 0xff, 0x6a, 0x58, 0x5b,
+ 0x00, 0x65, 0xaa, 0x42,
+ 0x04, 0xa0, 0x3a, 0x7b,
+ 0x00, 0x65, 0xd0, 0x5c,
+ 0x00, 0x65, 0x3c, 0x43,
+ 0x00, 0x65, 0xb8, 0x5c,
0x31, 0x6a, 0x22, 0x01,
- 0x0c, 0x6a, 0x42, 0x5b,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x0c, 0x6a, 0x58, 0x5b,
+ 0x00, 0x65, 0xaa, 0x42,
0x61, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0xa6, 0x42,
+ 0x00, 0x65, 0xaa, 0x42,
+ 0x51, 0x6a, 0x5c, 0x5b,
+ 0x20, 0x0d, 0xaa, 0x6a,
+ 0xff, 0xa8, 0x54, 0x6b,
+ 0xff, 0xa9, 0x54, 0x6b,
+ 0xff, 0xaa, 0x54, 0x6b,
+ 0xff, 0xab, 0x54, 0x6b,
+ 0x00, 0x65, 0xaa, 0x42,
+ 0x51, 0x6a, 0x22, 0x01,
+ 0x00, 0x65, 0xaa, 0x42,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x65, 0x68, 0x0c,
0xff, 0x06, 0xd4, 0x08,
- 0x01, 0x0c, 0x48, 0x7b,
- 0x04, 0x0c, 0x48, 0x6b,
+ 0x01, 0x0c, 0x5e, 0x7b,
+ 0x04, 0x0c, 0x60, 0x6b,
0xe0, 0x03, 0x7a, 0x08,
- 0xe0, 0x3d, 0x5c, 0x63,
+ 0xe0, 0x3d, 0x72, 0x63,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x12, 0xda, 0x0c,
0xff, 0x06, 0xd4, 0x0c,
0xff, 0x65, 0x0c, 0x08,
- 0x02, 0x0b, 0x58, 0x7b,
+ 0x02, 0x0b, 0x6e, 0x7b,
0xff, 0x6a, 0xd4, 0x0c,
0xd1, 0x6a, 0x22, 0x01,
0x00, 0x65, 0x22, 0x41,
0xff, 0x65, 0x26, 0x09,
- 0x01, 0x0b, 0x70, 0x6b,
- 0x10, 0x0c, 0x62, 0x7b,
- 0x04, 0x0b, 0x6a, 0x6b,
+ 0x01, 0x0b, 0x86, 0x6b,
+ 0x10, 0x0c, 0x78, 0x7b,
+ 0x04, 0x0b, 0x80, 0x6b,
0xff, 0x6a, 0xca, 0x08,
- 0x04, 0x93, 0x6e, 0x6b,
- 0x01, 0x94, 0x6c, 0x7b,
- 0x10, 0x94, 0x6e, 0x6b,
+ 0x04, 0x93, 0x84, 0x6b,
+ 0x01, 0x94, 0x82, 0x7b,
+ 0x10, 0x94, 0x84, 0x6b,
0xc7, 0x93, 0x26, 0x09,
0xff, 0x99, 0xd4, 0x08,
- 0x38, 0x93, 0x72, 0x6b,
+ 0x38, 0x93, 0x88, 0x6b,
0xff, 0x6a, 0xd4, 0x0c,
- 0x80, 0x36, 0x76, 0x6b,
+ 0x80, 0x36, 0x8c, 0x6b,
0x21, 0x6a, 0x22, 0x05,
0xff, 0x65, 0x20, 0x09,
- 0xff, 0x51, 0x84, 0x63,
+ 0xff, 0x51, 0x9a, 0x63,
0xff, 0x37, 0xc8, 0x08,
- 0xa1, 0x6a, 0x90, 0x43,
+ 0xa1, 0x6a, 0xa6, 0x43,
0xff, 0x51, 0xc8, 0x08,
- 0xb9, 0x6a, 0x90, 0x43,
+ 0xb9, 0x6a, 0xa6, 0x43,
0xff, 0x90, 0xa4, 0x08,
- 0xff, 0xba, 0x94, 0x73,
+ 0xff, 0xba, 0xaa, 0x73,
0xff, 0xba, 0x20, 0x09,
0xff, 0x65, 0xca, 0x18,
- 0x00, 0x6c, 0x88, 0x63,
+ 0x00, 0x6c, 0x9e, 0x63,
0xff, 0x90, 0xca, 0x0c,
0xff, 0x6a, 0xca, 0x04,
- 0x20, 0x36, 0xa8, 0x7b,
- 0x00, 0x90, 0x7c, 0x5b,
- 0xff, 0x65, 0xa8, 0x73,
- 0xff, 0x52, 0xa6, 0x73,
+ 0x20, 0x36, 0xbe, 0x7b,
+ 0x00, 0x90, 0x92, 0x5b,
+ 0xff, 0x65, 0xbe, 0x73,
+ 0xff, 0x52, 0xbc, 0x73,
0xff, 0xba, 0xcc, 0x08,
0xff, 0x52, 0x20, 0x09,
0xff, 0x66, 0x74, 0x09,
0xff, 0x65, 0x20, 0x0d,
0xff, 0xba, 0x7e, 0x0c,
- 0x00, 0x6a, 0xa8, 0x5c,
+ 0x00, 0x6a, 0xbe, 0x5c,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x51, 0x34, 0x44,
- 0xff, 0x3f, 0x02, 0x74,
+ 0x00, 0x51, 0x4a, 0x44,
+ 0xff, 0x3f, 0x18, 0x74,
0xff, 0x6a, 0xa2, 0x00,
- 0x00, 0x3f, 0x7c, 0x5b,
- 0xff, 0x65, 0x02, 0x74,
+ 0x00, 0x3f, 0x92, 0x5b,
+ 0xff, 0x65, 0x18, 0x74,
0x20, 0x36, 0x6c, 0x00,
- 0x20, 0xa0, 0xbc, 0x6b,
+ 0x20, 0xa0, 0xd2, 0x6b,
0xff, 0xb9, 0xa2, 0x0c,
0xff, 0x6a, 0xa2, 0x04,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0xd0, 0x01,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0xc8, 0x7b,
+ 0x80, 0xeb, 0xde, 0x7b,
0x01, 0x6a, 0xd6, 0x01,
0x01, 0xe9, 0xa4, 0x34,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x6a, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
+ 0x00, 0x65, 0xb0, 0x5c,
0xff, 0x99, 0xa4, 0x0c,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0xd0, 0x01,
0x01, 0x6a, 0xdc, 0x05,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x28, 0x5c,
+ 0x45, 0x6a, 0x3e, 0x5c,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x01, 0x6a, 0x26, 0x05,
0x01, 0x65, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0xf8, 0x7b,
+ 0x80, 0xee, 0x0e, 0x7c,
0xff, 0x6a, 0xdc, 0x0d,
0xff, 0x65, 0x32, 0x09,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x44,
+ 0x00, 0x65, 0xb0, 0x44,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0xbe, 0x5b,
+ 0x00, 0x6a, 0xd4, 0x5b,
0xff, 0x52, 0xa2, 0x0c,
- 0x01, 0x0c, 0x08, 0x7c,
- 0x04, 0x0c, 0x08, 0x6c,
+ 0x01, 0x0c, 0x1e, 0x7c,
+ 0x04, 0x0c, 0x1e, 0x6c,
0xe0, 0x03, 0x06, 0x08,
0xe0, 0x03, 0x7a, 0x0c,
0xff, 0x8c, 0x10, 0x08,
@@ -542,29 +553,29 @@ static unsigned char seqprog[] = {
0x00, 0x6c, 0xda, 0x24,
0xff, 0x65, 0xc8, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0x24, 0x5c,
+ 0x41, 0x6a, 0x3a, 0x5c,
0xff, 0x90, 0xe2, 0x09,
0x20, 0x6a, 0xd0, 0x01,
- 0x04, 0x35, 0x46, 0x7c,
+ 0x04, 0x35, 0x5c, 0x7c,
0x1d, 0x6a, 0xdc, 0x01,
- 0xdc, 0xee, 0x42, 0x64,
- 0x00, 0x65, 0x52, 0x44,
+ 0xdc, 0xee, 0x58, 0x64,
+ 0x00, 0x65, 0x68, 0x44,
0x01, 0x6a, 0xdc, 0x01,
0x20, 0xa0, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0x4c, 0x7c,
+ 0x80, 0xee, 0x62, 0x7c,
0x19, 0x6a, 0xdc, 0x01,
- 0xd8, 0xee, 0x50, 0x64,
+ 0xd8, 0xee, 0x66, 0x64,
0xff, 0x6a, 0xdc, 0x09,
- 0x18, 0xee, 0x54, 0x6c,
+ 0x18, 0xee, 0x6a, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0x88, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0x24, 0x5c,
+ 0x41, 0x6a, 0x3a, 0x5c,
0x20, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x35, 0x7e, 0x6c,
+ 0x04, 0x35, 0x94, 0x6c,
0xa0, 0x6a, 0xca, 0x00,
0x20, 0x65, 0xc8, 0x18,
0xff, 0x6c, 0x32, 0x09,
@@ -575,14 +586,14 @@ static unsigned char seqprog[] = {
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
- 0x00, 0x65, 0x6a, 0x64,
+ 0x00, 0x65, 0x80, 0x64,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x9a, 0x5c,
- 0x04, 0x35, 0x76, 0x7b,
- 0xa0, 0x6a, 0x8a, 0x5c,
- 0x00, 0x65, 0x8c, 0x5c,
- 0x00, 0x65, 0x8c, 0x5c,
- 0x00, 0x65, 0x8c, 0x44,
+ 0x00, 0x65, 0xb0, 0x5c,
+ 0x04, 0x35, 0x8c, 0x7b,
+ 0xa0, 0x6a, 0xa0, 0x5c,
+ 0x00, 0x65, 0xa2, 0x5c,
+ 0x00, 0x65, 0xa2, 0x5c,
+ 0x00, 0x65, 0xa2, 0x44,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
@@ -591,19 +602,19 @@ static unsigned char seqprog[] = {
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x0c,
- 0x08, 0x94, 0x9a, 0x7c,
+ 0x08, 0x94, 0xb0, 0x7c,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x9e, 0x6c,
+ 0x08, 0x93, 0xb4, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0xff, 0x40, 0x74, 0x09,
0xff, 0x90, 0x80, 0x08,
0xff, 0x6a, 0x72, 0x05,
- 0xff, 0x40, 0xb6, 0x64,
- 0xff, 0x3f, 0xae, 0x64,
+ 0xff, 0x40, 0xcc, 0x64,
+ 0xff, 0x3f, 0xc4, 0x64,
0xff, 0x6a, 0xca, 0x04,
0xff, 0x3f, 0x20, 0x09,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x34, 0x5c,
+ 0x00, 0xb9, 0x4a, 0x5c,
0xff, 0xba, 0x7e, 0x0c,
0xff, 0x40, 0x20, 0x09,
0xff, 0xba, 0x80, 0x0c,
@@ -761,49 +772,52 @@ struct sequencer_patch {
{ aic7xxx_patch2_func, 192, 2, 3 },
{ aic7xxx_patch8_func, 192, 1, 1 },
{ aic7xxx_patch0_func, 194, 3, 1 },
- { aic7xxx_patch10_func, 197, 2, 1 },
- { aic7xxx_patch8_func, 199, 7, 2 },
- { aic7xxx_patch0_func, 206, 1, 1 },
- { aic7xxx_patch2_func, 211, 14, 3 },
- { aic7xxx_patch10_func, 224, 1, 1 },
- { aic7xxx_patch0_func, 225, 9, 1 },
- { aic7xxx_patch8_func, 239, 2, 1 },
- { aic7xxx_patch8_func, 241, 1, 1 },
- { aic7xxx_patch10_func, 242, 6, 3 },
- { aic7xxx_patch2_func, 242, 2, 2 },
- { aic7xxx_patch0_func, 244, 4, 1 },
- { aic7xxx_patch8_func, 249, 1, 1 },
- { aic7xxx_patch8_func, 253, 19, 1 },
- { aic7xxx_patch2_func, 273, 3, 3 },
- { aic7xxx_patch10_func, 275, 1, 1 },
- { aic7xxx_patch0_func, 276, 5, 1 },
- { aic7xxx_patch10_func, 281, 1, 2 },
- { aic7xxx_patch0_func, 282, 9, 1 },
- { aic7xxx_patch11_func, 298, 1, 2 },
- { aic7xxx_patch0_func, 299, 1, 1 },
- { aic7xxx_patch5_func, 359, 1, 2 },
- { aic7xxx_patch0_func, 360, 1, 1 },
- { aic7xxx_patch3_func, 363, 1, 1 },
- { aic7xxx_patch2_func, 373, 3, 2 },
- { aic7xxx_patch0_func, 376, 5, 1 },
- { aic7xxx_patch11_func, 384, 1, 2 },
- { aic7xxx_patch0_func, 385, 1, 1 },
- { aic7xxx_patch6_func, 390, 1, 1 },
- { aic7xxx_patch1_func, 427, 3, 1 },
- { aic7xxx_patch10_func, 432, 11, 1 },
- { aic7xxx_patch2_func, 480, 7, 2 },
- { aic7xxx_patch0_func, 487, 8, 1 },
- { aic7xxx_patch2_func, 496, 4, 2 },
- { aic7xxx_patch0_func, 500, 6, 1 },
- { aic7xxx_patch2_func, 506, 4, 2 },
- { aic7xxx_patch0_func, 510, 3, 1 },
- { aic7xxx_patch12_func, 520, 10, 1 },
- { aic7xxx_patch2_func, 539, 17, 4 },
- { aic7xxx_patch13_func, 547, 4, 2 },
- { aic7xxx_patch0_func, 551, 2, 1 },
- { aic7xxx_patch0_func, 556, 33, 1 },
- { aic7xxx_patch12_func, 589, 4, 1 },
- { aic7xxx_patch6_func, 593, 2, 1 },
- { aic7xxx_patch6_func, 596, 9, 1 },
+ { aic7xxx_patch10_func, 198, 1, 2 },
+ { aic7xxx_patch0_func, 199, 1, 1 },
+ { aic7xxx_patch8_func, 200, 7, 2 },
+ { aic7xxx_patch0_func, 207, 1, 1 },
+ { aic7xxx_patch2_func, 212, 14, 3 },
+ { aic7xxx_patch10_func, 225, 1, 1 },
+ { aic7xxx_patch0_func, 226, 9, 1 },
+ { aic7xxx_patch8_func, 240, 2, 1 },
+ { aic7xxx_patch8_func, 242, 1, 1 },
+ { aic7xxx_patch10_func, 243, 6, 3 },
+ { aic7xxx_patch2_func, 243, 2, 2 },
+ { aic7xxx_patch0_func, 245, 4, 1 },
+ { aic7xxx_patch8_func, 250, 1, 1 },
+ { aic7xxx_patch8_func, 254, 19, 1 },
+ { aic7xxx_patch2_func, 274, 3, 3 },
+ { aic7xxx_patch10_func, 276, 1, 1 },
+ { aic7xxx_patch0_func, 277, 5, 1 },
+ { aic7xxx_patch10_func, 282, 1, 2 },
+ { aic7xxx_patch0_func, 283, 9, 1 },
+ { aic7xxx_patch11_func, 299, 1, 2 },
+ { aic7xxx_patch0_func, 300, 1, 1 },
+ { aic7xxx_patch5_func, 361, 1, 2 },
+ { aic7xxx_patch0_func, 362, 1, 1 },
+ { aic7xxx_patch3_func, 365, 1, 1 },
+ { aic7xxx_patch2_func, 375, 3, 2 },
+ { aic7xxx_patch0_func, 378, 5, 1 },
+ { aic7xxx_patch11_func, 386, 1, 2 },
+ { aic7xxx_patch0_func, 387, 1, 1 },
+ { aic7xxx_patch6_func, 392, 1, 1 },
+ { aic7xxx_patch8_func, 420, 1, 2 },
+ { aic7xxx_patch0_func, 421, 5, 1 },
+ { aic7xxx_patch1_func, 438, 3, 1 },
+ { aic7xxx_patch10_func, 443, 11, 1 },
+ { aic7xxx_patch2_func, 491, 7, 2 },
+ { aic7xxx_patch0_func, 498, 8, 1 },
+ { aic7xxx_patch2_func, 507, 4, 2 },
+ { aic7xxx_patch0_func, 511, 6, 1 },
+ { aic7xxx_patch2_func, 517, 4, 2 },
+ { aic7xxx_patch0_func, 521, 3, 1 },
+ { aic7xxx_patch12_func, 531, 10, 1 },
+ { aic7xxx_patch2_func, 550, 17, 4 },
+ { aic7xxx_patch13_func, 558, 4, 2 },
+ { aic7xxx_patch0_func, 562, 2, 1 },
+ { aic7xxx_patch0_func, 567, 33, 1 },
+ { aic7xxx_patch12_func, 600, 4, 1 },
+ { aic7xxx_patch6_func, 604, 2, 1 },
+ { aic7xxx_patch6_func, 607, 9, 1 },
};
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 7e9fb2ab3..849ce76c9 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -410,11 +410,13 @@ static const char *snstext[] = {
#endif
/* Print sense information */
-void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
+static
+void print_sense_internal(const char * devclass,
+ const unsigned char * sense_buffer,
+ kdev_t dev)
{
int i, s;
int sense_class, valid, code;
- unsigned char * sense_buffer = SCpnt->sense_buffer;
const char * error = NULL;
sense_class = (sense_buffer[0] >> 4) & 0x07;
@@ -423,8 +425,8 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
if (sense_class == 7) { /* extended sense data */
s = sense_buffer[7] + 8;
- if(s > sizeof(SCpnt->sense_buffer))
- s = sizeof(SCpnt->sense_buffer);
+ if(s > SCSI_SENSE_BUFFERSIZE)
+ s = SCSI_SENSE_BUFFERSIZE;
if (!valid)
printk("[valid=0] ");
@@ -455,10 +457,10 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
#if (CONSTANTS & CONST_SENSE)
printk( "%s%s: sense key %s\n", devclass,
- kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[2] & 0x0f]);
+ kdevname(dev), snstext[sense_buffer[2] & 0x0f]);
#else
printk("%s%s: sns = %2x %2x\n", devclass,
- kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]);
+ kdevname(dev), sense_buffer[0], sense_buffer[2]);
#endif
/* Check to see if additional sense information is available */
@@ -495,11 +497,11 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
#if (CONSTANTS & CONST_SENSE)
if (sense_buffer[0] < 15)
printk("%s%s: old sense key %s\n", devclass,
- kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[0] & 0x0f]);
+ kdevname(dev), snstext[sense_buffer[0] & 0x0f]);
else
#endif
printk("%s%s: sns = %2x %2x\n", devclass,
- kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]);
+ kdevname(dev), sense_buffer[0], sense_buffer[2]);
printk("Non-extended sense class %d code 0x%0x ", sense_class, code);
s = 4;
@@ -515,6 +517,18 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
return;
}
+void print_sense(const char * devclass, Scsi_Cmnd * SCpnt)
+{
+ print_sense_internal(devclass, SCpnt->sense_buffer,
+ SCpnt->request.rq_dev);
+}
+
+void print_req_sense(const char * devclass, Scsi_Request * SRpnt)
+{
+ print_sense_internal(devclass, SRpnt->sr_sense_buffer,
+ SRpnt->sr_request.rq_dev);
+}
+
#if (CONSTANTS & CONST_MSG)
static const char *one_byte_msgs[] = {
/* 0x00 */ "Command Complete", NULL, "Save Pointers",
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index b6a058c03..d87bf6d70 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -910,7 +910,7 @@ static inline int port_detect \
if (info.sign != EATA_SIGNATURE) return FALSE;
if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
- printk("%s: config structure size (%ld bytes) too short, detaching.\n",
+ printk("%s: config structure size (%d bytes) too short, detaching.\n",
name, DEV2H(info.data_len));
return FALSE;
}
diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c
index dd6034561..725a70a4a 100644
--- a/drivers/scsi/eata_dma_proc.c
+++ b/drivers/scsi/eata_dma_proc.c
@@ -167,6 +167,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
cmnd[9] = 0;
scmd->cmd_len = 10;
+ scmd->sc_data_direction = DATA_READ;
/*
* Do the command and wait for it to finish.
@@ -291,6 +292,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
cmnd[9] = 0;
scmd->cmd_len = 10;
+ scmd->sc_data_direction = SCSI_DATA_READ;
/*
* Do the command and wait for it to finish.
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 61ce25c36..fccfb59c8 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.90 2000/01/28 13:42:56 jj Exp $
+/* $Id: esp.c,v 1.92 2000/02/18 13:49:58 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -1412,14 +1412,20 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
sp->SCp.this_residual = sp->request_bufflen;
sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = 0;
- sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
- sp->SCp.this_residual);
- sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
+ if (sp->request_bufflen) {
+ sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
+ sp->SCp.this_residual,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
+ sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
+ } else {
+ sp->SCp.ptr = NULL;
+ }
} else {
sp->SCp.buffer = (struct scatterlist *) sp->buffer;
sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
sp->SCp.buffer,
- sp->use_sg);
+ sp->use_sg,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer));
}
@@ -1427,12 +1433,14 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
static void esp_release_dmabufs(struct esp *esp, Scsi_Cmnd *sp)
{
- if (sp->use_sg == 0) {
+ if (sp->use_sg) {
+ sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
+ } else if (sp->request_bufflen) {
sbus_unmap_single(esp->sdev,
sp->SCp.have_data_in,
- sp->request_bufflen);
- } else {
- sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg);
+ sp->request_bufflen,
+ scsi_to_sbus_dma_dir(sp->sc_data_direction));
}
}
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 979f1295c..59d9f2415 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -270,10 +270,6 @@
**************************************************************************/
-#ifdef PCMCIA
-#define MODULE
-#endif
-
#include <linux/module.h>
#ifdef PCMCIA
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 500c19b09..321b783a5 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -681,6 +681,7 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
* MAX_SCSI_HOSTS here.
*/
+Scsi_Host_Name * scsi_host_no_list = NULL;
struct Scsi_Host * scsi_hostlist = NULL;
struct Scsi_Device_Template * scsi_devicelist = NULL;
@@ -690,7 +691,8 @@ int next_scsi_host = 0;
void
scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * shpnt;
-
+ Scsi_Host_Name *shn;
+
if(scsi_hostlist == sh)
scsi_hostlist = sh->next;
else {
@@ -698,6 +700,16 @@ scsi_unregister(struct Scsi_Host * sh){
while(shpnt->next != sh) shpnt = shpnt->next;
shpnt->next = shpnt->next->next;
}
+
+ /*
+ * We have to unregister the host from the scsi_host_no_list as well.
+ * Decide by the host_no not by the name because most host drivers are
+ * able to handle more than one adapters from the same kind (or family).
+ */
+ for ( shn=scsi_host_no_list; shn && (sh->host_no != shn->host_no);
+ shn=shn->next);
+ if (shn) shn->host_registered = 0;
+ /* else {} : This should not happen, we should panic here... */
/* If we are removing the last host registered, it is safe to reuse
* its host number (this avoids "holes" at boot time) (DB)
@@ -724,16 +736,50 @@ scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
struct Scsi_Host * retval, *shpnt;
+ Scsi_Host_Name *shn, *shn2;
+ int new = 1;
retval = (struct Scsi_Host *)kmalloc(sizeof(struct Scsi_Host) + j,
(tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
memset(retval, 0, sizeof(struct Scsi_Host) + j);
+
+ /* trying to find a reserved entry (host_no) */
+ for (shn = scsi_host_no_list;shn;shn = shn->next)
+ if (!(shn->host_registered) && shn->loaded_as_module && tpnt->proc_dir &&
+ tpnt->proc_dir->name && !strncmp(tpnt->proc_dir->name, shn->name, strlen(tpnt->proc_dir->name))) {
+ new = 0;
+ retval->host_no = shn->host_no;
+ shn->host_registered = 1;
+ shn->loaded_as_module = scsi_loadable_module_flag;
+ break;
+ }
atomic_set(&retval->host_active,0);
retval->host_busy = 0;
retval->host_failed = 0;
if(j > 0xffff) panic("Too many extra bytes requested\n");
retval->extra_bytes = j;
retval->loaded_as_module = scsi_loadable_module_flag;
- retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
+ if (new) {
+ int len = 0;
+ shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
+ if (tpnt->proc_dir)
+ len = strlen(tpnt->proc_dir->name);
+ shn->name = kmalloc(len+1, GFP_ATOMIC);
+ if (tpnt->proc_dir)
+ strncpy(shn->name, tpnt->proc_dir->name, len);
+ shn->name[len] = 0;
+ shn->host_no = max_scsi_hosts++;
+ shn->host_registered = 1;
+ shn->loaded_as_module = scsi_loadable_module_flag;
+ shn->next = NULL;
+ if (scsi_host_no_list) {
+ for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
+ ;
+ shn2->next = shn;
+ }
+ else
+ scsi_host_no_list = shn;
+ retval->host_no = shn->host_no;
+ }
next_scsi_host++;
retval->host_queue = NULL;
init_waitqueue_head(&retval->host_wait);
@@ -747,6 +793,14 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
retval->max_id = 8;
retval->max_lun = 8;
+ /*
+ * All drivers right now should be able to handle 12 byte commands.
+ * Every so often there are requests for 16 byte commands, but individual
+ * low-level drivers need to certify that they actually do something
+ * sensible with such commands.
+ */
+ retval->max_cmd_len = 12;
+
retval->unique_id = 0;
retval->io_port = 0;
retval->hostt = tpnt;
@@ -757,6 +811,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
retval->host_blocked = FALSE;
+ retval->host_self_blocked = FALSE;
#ifdef DEBUG
printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index 191e4469e..f1b82a5a1 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -362,6 +362,17 @@ struct Scsi_Host
* initialized, as required.
*/
+ /*
+ * The maximum length of SCSI commands that this host can accept.
+ * Probably 12 for most host adapters, but could be 16 for others.
+ * For drivers that don't set this field, a value of 12 is
+ * assumed. I am leaving this as a number rather than a bit
+ * because you never know what subsequent SCSI standards might do
+ * (i.e. could there be a 20 byte or a 24-byte command a few years
+ * down the road?).
+ */
+ unsigned char max_cmd_len;
+
int this_id;
int can_queue;
short cmd_per_lun;
@@ -379,6 +390,12 @@ struct Scsi_Host
* Host has rejected a command because it was busy.
*/
unsigned host_blocked:1;
+
+ /*
+ * Host has requested that no further requests come through for the
+ * time being.
+ */
+ unsigned host_self_blocked:1;
/*
* Host uses correct SCSI ordering not PC ordering. The bit is
@@ -413,6 +430,20 @@ struct Scsi_Host
extern void scsi_free_host_dev(Scsi_Device * SDpnt);
extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt);
+extern void scsi_unblock_requests(struct Scsi_Host * SHpnt);
+extern void scsi_block_requests(struct Scsi_Host * SHpnt);
+extern void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel);
+
+typedef struct SHN
+ {
+ struct SHN * next;
+ char * name;
+ unsigned short host_no;
+ unsigned short host_registered;
+ unsigned loaded_as_module;
+ } Scsi_Host_Name;
+
+extern Scsi_Host_Name * scsi_host_no_list;
extern struct Scsi_Host * scsi_hostlist;
extern struct Scsi_Device_Template * scsi_devicelist;
@@ -504,6 +535,15 @@ extern void scsi_unregister_module(int, void *);
* tackle the character devices first, as there aren't any locking implications
* in the block device layer. The block devices will require more work.
*/
+#ifndef CONFIG_SD_EXTRA_DEVS
+#define CONFIG_SD_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_ST_EXTRA_DEVS
+#define CONFIG_ST_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_SR_EXTRA_DEVS
+#define CONFIG_SR_EXTRA_DEVS 2
+#endif
#define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
#define ST_EXTRA_DEVS CONFIG_ST_EXTRA_DEVS
#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 036ffdf2c..99cfa7e8c 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -417,7 +417,9 @@ int mac_esp_detect(Scsi_Host_Template * tpnt)
esp->irq = IRQ_MAC_SCSI;
request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp);
+#if 0 /* conflicts with IOP ADB */
request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp);
+#endif
if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
esp->cfreq = 16500000;
@@ -429,8 +431,9 @@ int mac_esp_detect(Scsi_Host_Template * tpnt)
} else { /* chipnum == 1 */
esp->irq = IRQ_MAC_SCSIDRQ;
-
+#if 0 /* conflicts with IOP ADB */
request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp);
+#endif
esp->cfreq = 25000000;
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 9e5bdf2b2..11a58c478 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -78,7 +78,6 @@
#define NDEBUG (NDEBUG_ABORT)
#endif
-#define USE_WRAPPER
#define RESET_BOOT
#define DRIVER_SETUP
@@ -90,30 +89,9 @@
#undef DRIVER_SETUP
#endif
-/*
- * Need to define this to make SCSI work on RBV machines; leave undefined
- * to enable interrupts a bit more on other machines
- * Changes method of SCSI interrupt disable from software mask to VIA IER!
- * (don't know if that's essential)
- *
- * 990502 (jmt) - not needed (and won't work) on new irq architecture
- */
-/* #define RBV_HACK */
-
-#ifdef RBV_HACK
-#define ENABLE_IRQ() mac_turnon_irq( IRQ_MAC_SCSI );
-#define DISABLE_IRQ() mac_turnoff_irq( IRQ_MAC_SCSI );
-#else
#define ENABLE_IRQ() mac_enable_irq( IRQ_MAC_SCSI );
#define DISABLE_IRQ() mac_disable_irq( IRQ_MAC_SCSI );
-#endif
-
-#define mac_turnon_irq(x) mac_enable_irq(x)
-#define mac_turnoff_irq(x) mac_disable_irq(x)
-extern void via_scsi_clear(void);
-
-static void scsi_mac_intr(int irq, void *dummy, struct pt_regs *fp);
#ifdef RESET_BOOT
static void mac_scsi_reset_boot(struct Scsi_Host *instance);
#endif
@@ -253,7 +231,7 @@ int macscsi_detect(Scsi_Host_Template * tpnt)
if (macintosh_config->scsi_type != MAC_SCSI_OLD)
return( 0 );
- tpnt->proc_name = "Mac 5380 SCSI";
+ tpnt->proc_name = "mac5380";
/* setup variables */
tpnt->can_queue =
@@ -306,11 +284,7 @@ int macscsi_detect(Scsi_Host_Template * tpnt)
((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
if (instance->irq != IRQ_NONE)
-#ifdef USE_WRAPPER
- if (request_irq(instance->irq, scsi_mac_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) {
-#else
- if (request_irq(instance->irq, macscsi_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) {
-#endif
+ if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, "ncr5380", NCR5380_intr)) {
printk("scsi%d: IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = IRQ_NONE;
@@ -337,7 +311,7 @@ int macscsi_detect(Scsi_Host_Template * tpnt)
int macscsi_release (struct Scsi_Host *shpnt)
{
if (shpnt->irq != IRQ_NONE)
- free_irq (shpnt->irq, NULL);
+ free_irq (shpnt->irq, NCR5380_intr);
return 0;
}
@@ -362,7 +336,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
printk( "Macintosh SCSI: resetting the SCSI bus..." );
/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
- mac_turnoff_irq( IRQ_MAC_SCSI );
+ mac_disable_irq(IRQ_MAC_SCSI);
/* get in phase */
NCR5380_write( TARGET_COMMAND_REG,
@@ -380,7 +354,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
barrier();
/* switch on SCSI IRQ again */
- mac_turnon_irq( IRQ_MAC_SCSI );
+ mac_enable_irq(IRQ_MAC_SCSI);
printk( " done\n" );
}
@@ -399,49 +373,6 @@ void restore_irq(struct pt_regs *regs)
restore_flags(flags);
}
-#ifdef USE_WRAPPER
-/*
- * SCSI interrupt wrapper - just to make sure it's the proper irq, and
- * that we leave the handler in a clean state
- */
-
-static void scsi_mac_intr (int irq, void *dev_id, struct pt_regs *fp)
-{
-#ifndef RBV_HACK
- unsigned long flags;
-#endif
-
-#ifdef RBV_HACK
- mac_turnoff_irq( IRQ_MAC_SCSI );
-#else
- mac_disable_irq( IRQ_MAC_SCSI );
-#endif
-
- if ( irq == IRQ_MAC_SCSI ) {
-#ifndef RBV_HACK
- save_flags(flags);
- restore_irq(fp);
-#endif
- NCR5380_intr (irq, dev_id, fp);
-#ifndef RBV_HACK
- restore_flags(flags);
-#endif
- }
-
- /* To be sure the int is not masked */
-#ifdef RBV_HACK
- mac_turnon_irq( IRQ_MAC_SCSI );
-#else
- mac_enable_irq( IRQ_MAC_SCSI );
-#endif
-
-#if 1 /* ??? 0 worked */
- /* Clear the IRQ */
- via_scsi_clear();
-#endif
-}
-#endif
-
/*
* pseudo-DMA transfer functions, copied and modified from Russel King's
* ARM 5380 driver (cumana_1)
@@ -720,11 +651,7 @@ void scsi_mac_polled (void)
printk("SCSI poll\n");
save_flags(flags);
cli();
-#ifdef USE_WRAPPER
- scsi_mac_intr(IRQ_MAC_SCSI, instance, NULL);
-#else
- macscsi_intr(IRQ_MAC_SCSI, instance, NULL);
-#endif
+ NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
restore_flags(flags);
}
#if 0
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 0ede63b87..adafbe43e 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -253,7 +253,7 @@ mesh_detect(Scsi_Host_Template *tp)
continue;
}
mesh_host->unique_id = nmeshes;
-#if !defined(MODULE) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC))
+#if !defined(MODULE)
note_scsi_host(mesh, mesh_host);
#endif
@@ -305,9 +305,7 @@ mesh_detect(Scsi_Host_Template *tp)
if (mesh_sync_period < minper)
mesh_sync_period = minper;
-#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
feature_set(mesh, FEATURE_MESH_enable);
-#endif
mdelay(200);
mesh_init(ms);
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index 71121b726..fce0871f1 100644
--- a/drivers/scsi/mvme16x.c
+++ b/drivers/scsi/mvme16x.c
@@ -40,7 +40,7 @@ int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
if (called)
return 0;
- tpnt->proc_name = "MVME16x"
+ tpnt->proc_name = "MVME16x";
options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
index 83efa5df6..e07417b7e 100644
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -53,7 +53,15 @@
#include "pci2000.h"
#include "psi_roy.h"
-#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
+#include <linux/bios32.h>
+#endif
+
+struct proc_dir_entry Proc_Scsi_Pci2000 =
+ { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
//#define DEBUG 1
@@ -120,6 +128,28 @@ static int WaitReady (PADAPTER2000 padapter)
return TRUE;
}
/****************************************************************
+ * Name: WaitReadyLong :LOCAL
+ *
+ * Description: Wait for controller ready.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ *
+ * Returns: TRUE on not ready.
+ *
+ ****************************************************************/
+static int WaitReadyLong (PADAPTER2000 padapter)
+ {
+ ULONG z;
+
+ for ( z = 0; z < (5000 * 4); z++ )
+ {
+ if ( !inb_p (padapter->cmd) )
+ return FALSE;
+ udelay (250);
+ };
+ return TRUE;
+ }
+/****************************************************************
* Name: OpDone :LOCAL
*
* Description: Clean up operation and issue done to caller.
@@ -204,7 +234,7 @@ static int PsiRaidCmd (PADAPTER2000 padapter, char cmd)
if ( WaitReady (padapter) ) // test for command register ready
return DID_TIME_OUT;
outb_p (cmd, padapter->cmd); // issue command
- if ( WaitReady (padapter) ) // wait for adapter ready
+ if ( WaitReadyLong (padapter) ) // wait for adapter ready
return DID_TIME_OUT;
return DID_OK;
}
@@ -232,13 +262,23 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
int pun;
int bus;
int z;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
DEB(printk ("\npci2000 recieved interrupt "));
for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
@@ -327,12 +367,20 @@ irqProceed:;
OpDone (SCpnt, DID_OK << 16);
irq_return:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: Pci2000_QueueCommand
@@ -589,21 +637,37 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
PADAPTER2000 padapter;
int z, zz;
int setirq;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
struct pci_dev *pdev = NULL;
+#else
+ UCHAR pci_bus, pci_device_fn;
+#endif
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
if ( !pci_present () )
+#else
+ if ( !pcibios_present () )
+#endif
{
printk ("pci2000: PCI BIOS not present\n");
return 0;
}
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL )
+#else
+ while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) )
+#endif
{
pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
padapter = HOSTDATA(pshost);
- padapter->basePort = pdev->resource[1].start;
-
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ padapter->basePort = pdev->base_address[1] & 0xFFFE;
+#else
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
+ padapter->basePort &= 0xFFFE;
+#endif
DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address
padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes
padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4;
@@ -620,7 +684,11 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
if ( WaitReady (padapter) )
goto unregister;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
pshost->irq = pdev->irq;
+#else
+ pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+#endif
setirq = 1;
padapter->irqOwned = 0;
for ( z = 0; z < installed; z++ ) // scan for shared interrupts
@@ -714,7 +782,11 @@ int Pci2000_Release (struct Scsi_Host *pshost)
PADAPTER2000 padapter = HOSTDATA (pshost);
if ( padapter->irqOwned )
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+ free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
release_region (pshost->io_port, pshost->n_io_port);
scsi_unregister(pshost);
return 0;
@@ -760,4 +832,3 @@ Scsi_Host_Template driver_template = PCI2000;
#include "scsi_module.c"
#endif
-
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
index 9b80a489b..a3daa5f76 100644
--- a/drivers/scsi/pci2000.h
+++ b/drivers/scsi/pci2000.h
@@ -200,10 +200,13 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
#define NULL 0
#endif
+extern struct proc_dir_entry Proc_Scsi_Pci2000;
+
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
#define PCI2000 { \
next: NULL, \
module: NULL, \
- proc_name: "pci2000", \
+ proc_dir: &Proc_Scsi_Pci2000, \
proc_info: NULL, /* let's not bloat the kernel */ \
name: "PCI-2000 SCSI Intelligent Disk Controller",\
detect: Pci2000_Detect, \
@@ -229,4 +232,27 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
use_clustering: DISABLE_CLUSTERING, \
use_new_eh_code: 0 \
}
+#else
+#define PCI2000 { NULL, NULL, \
+ &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
+ NULL, \
+ "PCI-2000 SCSI Intelligent Disk Controller",\
+ Pci2000_Detect, \
+ Pci2000_Release, \
+ NULL, \
+ Pci2000_Command, \
+ Pci2000_QueueCommand, \
+ Pci2000_Abort, \
+ Pci2000_Reset, \
+ NULL, \
+ Pci2000_BiosParam, \
+ 16, \
+ -1, \
+ 16, \
+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING }
+#endif
+
#endif
diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
index e50ba45dc..80f58cb8e 100644
--- a/drivers/scsi/pci2220i.c
+++ b/drivers/scsi/pci2220i.c
@@ -24,8 +24,15 @@
* Revisions 1.11 Mar-26-1999
* - Fixed spinlock and PCI configuration.
*
+ * Revision 2.00 December-1-1999
+ * - Added code for the PCI-2240I controller
+ * - Added code for ATAPI devices.
+ * - Double buffer for scatter/gather support
+ *
****************************************************************************/
+//#define DEBUG 1
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -46,18 +53,22 @@
#include "scsi.h"
#include "hosts.h"
#include "pci2220i.h"
+#include "psi_dale.h"
-#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
+#include <linux/bios32.h>
+#endif
-#define PCI2220I_VERSION "1.11"
-//#define READ_CMD IDE_COMMAND_READ
-//#define WRITE_CMD IDE_COMMAND_WRITE
-//#define MAX_BUS_MASTER_BLOCKS 1 // This is the maximum we can bus master
+#define PCI2220I_VERSION "2.00"
#define READ_CMD IDE_CMD_READ_MULTIPLE
#define WRITE_CMD IDE_CMD_WRITE_MULTIPLE
#define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master
-//#define DEBUG 1
+struct proc_dir_entry Proc_Scsi_Pci2220i =
+ { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
#ifdef DEBUG
#define DEB(x) x
@@ -72,10 +83,10 @@
typedef struct
{
- UCHAR device; // device code
UCHAR byte6; // device select register image
UCHAR spigot; // spigot number
- UCHAR sparebyte; // placeholder
+ UCHAR spigots[2]; // RAID spigots
+ UCHAR deviceID[2]; // device ID codes
USHORT sectors; // number of sectors per track
USHORT heads; // number of heads
USHORT cylinders; // number of cylinders for this device
@@ -85,12 +96,17 @@ typedef struct
ULONG lastsectorlba[2]; // last addressable sector on the drive
USHORT raid; // RAID active flag
USHORT mirrorRecon;
- UCHAR hotRecon;
+ UCHAR reconOn;
USHORT reconCount;
+ USHORT reconIsStarting; // indicate hot reconstruct is starting
+ UCHAR cmdDrqInt; // flag for command interrupt
+ UCHAR packet; // command packet size in bytes
} OUR_DEVICE, *POUR_DEVICE;
typedef struct
{
+ USHORT bigD; // identity is a PCI-2240I if true, otherwise a PCI-2220I
+ USHORT atapi; // this interface is for ATAPI devices only
USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer
USHORT regDmaCmdStat; // Byte #1 of DMA command status register
USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA
@@ -119,16 +135,21 @@ typedef struct
USHORT timingPIO; // TRUE if PIO timing is active
ULONG timingAddress; // address to use on adapter for current timing mode
ULONG irqOwned; // owned IRQ or zero if shared
- OUR_DEVICE device[DALE_MAXDRIVES];
- DISK_MIRROR *raidData[8];
+ UCHAR numberOfDrives; // saved number of drives on this controller
+ UCHAR failRegister; // current inverted data in fail register
+ OUR_DEVICE device[BIGD_MAXDRIVES];
+ DISK_MIRROR *raidData[BIGD_MAXDRIVES];
ULONG startSector;
USHORT sectorCount;
+ ULONG readCount;
+ UCHAR *currentSgBuffer;
+ ULONG currentSgCount;
+ USHORT nextSg;
UCHAR cmd;
Scsi_Cmnd *SCpnt;
- VOID *buffer;
POUR_DEVICE pdev; // current device opearating on
+ USHORT devInReconIndex;
USHORT expectingIRQ;
- USHORT reconIsStarting; // indicate hot reconstruct is starting
USHORT reconOn; // Hot reconstruct is to be done.
USHORT reconPhase; // Hot reconstruct operation is in progress.
ULONG reconSize;
@@ -138,6 +159,9 @@ typedef struct
struct timer_list reconTimer;
struct timer_list timer;
UCHAR *kBuffer;
+ UCHAR reqSense;
+ UCHAR atapiCdb[16];
+ UCHAR atapiSpecial;
} ADAPTER2220I, *PADAPTER2220I;
#define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)
@@ -152,12 +176,41 @@ typedef struct
static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter
static int NumAdapters = 0;
+static int Installed = 0;
static SETUP DaleSetup;
-static DISK_MIRROR DiskMirror[2];
-static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
+static DISK_MIRROR DiskMirror[BIGD_MAXDRIVES];
+static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE5};
+static ULONG ModeArray2[] = {BIGD_DATA_MODE2, BIGD_DATA_MODE3, BIGD_DATA_MODE4, BIGD_DATA_MODE5};
static void ReconTimerExpiry (unsigned long data);
+/*******************************************************************************************************
+ * Name: Alarm
+ *
+ * Description: Sound the for the given device
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * device - Device number.
+ *
+ * Returns: Nothing.
+ *
+ ******************************************************************************************************/
+static void Alarm (PADAPTER2220I padapter, UCHAR device)
+ {
+ UCHAR zc;
+
+ if ( padapter->bigD )
+ {
+ zc = device | (FAIL_ANY | FAIL_AUDIBLE);
+ if ( padapter->failRegister & FAIL_ANY )
+ zc |= FAIL_MULTIPLE;
+
+ padapter->failRegister = zc;
+ outb_p (~zc, padapter->regFail);
+ }
+ else
+ outb_p (0x3C | (1 << device), padapter->regFail); // sound alarm and set fail light
+ }
/****************************************************************
* Name: MuteAlarm :LOCAL
*
@@ -172,8 +225,16 @@ static void MuteAlarm (PADAPTER2220I padapter)
{
UCHAR old;
- old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
- outb_p (old | 0x40, padapter->regFail);
+ if ( padapter->bigD )
+ {
+ padapter->failRegister &= ~FAIL_AUDIBLE;
+ outb_p (~padapter->failRegister, padapter->regFail);
+ }
+ else
+ {
+ old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
+ outb_p (old | 0x40, padapter->regFail);
+ }
}
/****************************************************************
* Name: WaitReady :LOCAL
@@ -214,17 +275,17 @@ static int WaitReadyReset (PADAPTER2220I padapter)
ULONG z;
UCHAR status;
- for ( z = 0; z < (250 * 4); z++ ) // wait up to 1/4 second
+ for ( z = 0; z < (125 * 16); z++ ) // wait up to 1/4 second
{
status = inb_p (padapter->regStatCmd);
if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
{
- DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 4));
+ DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 8));
return 0;
}
- udelay (250);
+ udelay (125);
}
- DEB (printk ("\nPCI2220I: Reset took more than 1 Second to come ready, Disk Failure"));
+ DEB (printk ("\nPCI2220I: Reset took more than 2 Seconds to come ready, Disk Failure"));
return status;
}
/****************************************************************
@@ -252,6 +313,52 @@ static int WaitDrq (PADAPTER2220I padapter)
return status;
}
/****************************************************************
+ * Name: AtapiWaitReady :LOCAL
+ *
+ * Description: Wait for device busy and DRQ to be cleared.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * msec - Number of milliseconds to wait.
+ *
+ * Returns: TRUE if drive does not clear busy in time.
+ *
+ ****************************************************************/
+static int AtapiWaitReady (PADAPTER2220I padapter, int msec)
+ {
+ int z;
+
+ for ( z = 0; z < (msec * 16); z++ )
+ {
+ if ( !(inb_p (padapter->regStatCmd) & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) )
+ return FALSE;
+ udelay (125);
+ }
+ return TRUE;
+ }
+/****************************************************************
+ * Name: AtapiWaitDrq :LOCAL
+ *
+ * Description: Wait for device ready for data transfer.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * msec - Number of milliseconds to wait.
+ *
+ * Returns: TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int AtapiWaitDrq (PADAPTER2220I padapter, int msec)
+ {
+ ULONG z;
+
+ for ( z = 0; z < (msec * 16); z++ )
+ {
+ if ( inb_p (padapter->regStatCmd) & IDE_STATUS_DRQ )
+ return 0;
+ udelay (128);
+ }
+ return TRUE;
+ }
+/****************************************************************
* Name: HardReset :LOCAL
*
* Description: Wait for device ready for data transfer.
@@ -265,24 +372,113 @@ static int WaitDrq (PADAPTER2220I padapter)
****************************************************************/
static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
{
- SelectSpigot (padapter, spigot | 0x80);
+ DEB (printk ("\npci2220i:RESET spigot = %X devices = %d, %d", spigot, pdev->deviceID[0], pdev->deviceID[1]));
+ udelay (100000); // just wait 100 mSec to let drives flush
+ SelectSpigot (padapter, spigot | SEL_IRQ_OFF);
outb_p (0x0E, padapter->regAltStat); // reset the suvivor
udelay (100); // wait a little
outb_p (0x08, padapter->regAltStat); // clear the reset
udelay (100);
- outb_p (0xA0, padapter->regLba24); //Specify drive
- outb_p (pdev->byte6, padapter->regLba24); // select the drive
+ outb_p (0xA0, padapter->regLba24); // select the master drive
if ( WaitReadyReset (padapter) )
+ {
+ DEB (printk ("\npci2220i: master not ready after reset"));
return TRUE;
+ }
+ outb_p (0xB0, padapter->regLba24); // try the slave drive
+ if ( (inb_p (padapter->regStatCmd) & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
+ {
+ DEB (printk ("\nPCI2220I: initializing slave drive on spigot %X", spigot));
+ outb_p (SECTORSXFER, padapter->regSectCount);
+ WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);
+ if ( WaitReady (padapter) )
+ {
+ DEB (printk ("\npci2220i: slave not ready after set multiple"));
+ return TRUE;
+ }
+ }
+
+ outb_p (0xA0, padapter->regLba24); // select the drive
outb_p (SECTORSXFER, padapter->regSectCount);
WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);
if ( WaitReady (padapter) )
+ {
+ DEB (printk ("\npci2220i: master not ready after set multiple"));
return TRUE;
+ }
return FALSE;
}
/****************************************************************
+ * Name: AtapiReset :LOCAL
+ *
+ * Description: Wait for device ready for data transfer.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device.
+ *
+ * Returns: TRUE if drive does not come ready.
+ *
+ ****************************************************************/
+static int AtapiReset (PADAPTER2220I padapter, POUR_DEVICE pdev)
+ {
+ SelectSpigot (padapter, pdev->spigot);
+ AtapiDevice (padapter, pdev->byte6);
+ AtapiCountLo (padapter, 0);
+ AtapiCountHi (padapter, 0);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_RESET);
+ udelay (125);
+ if ( AtapiWaitReady (padapter, 1000) )
+ return TRUE;
+ if ( inb_p (padapter->regStatCmd) || (inb_p (padapter->regLba8) != 0x14) || (inb_p (padapter->regLba16) != 0xEB) )
+ return TRUE;
+ return FALSE;
+ }
+/****************************************************************
+ * Name: WalkScatGath :LOCAL
+ *
+ * Description: Transfer data to/from scatter/gather buffers.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * datain - TRUE if data read.
+ * length - Number of bytes to transfer.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void WalkScatGath (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+ {
+ ULONG count;
+ UCHAR *buffer = padapter->kBuffer;
+
+ while ( length )
+ {
+ count = ( length > padapter->currentSgCount ) ? padapter->currentSgCount : length;
+
+ if ( datain )
+ memcpy (padapter->currentSgBuffer, buffer, count);
+ else
+ memcpy (buffer, padapter->currentSgBuffer, count);
+
+ padapter->currentSgCount -= count;
+ if ( !padapter->currentSgCount )
+ {
+ if ( padapter->nextSg < padapter->SCpnt->use_sg )
+ {
+ padapter->currentSgBuffer = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].address;
+ padapter->currentSgCount = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].length;
+ padapter->nextSg++;
+ }
+ }
+ else
+ padapter->currentSgBuffer += count;
+
+ length -= count;
+ buffer += count;
+ }
+ }
+/****************************************************************
* Name: BusMaster :LOCAL
*
* Description: Do a bus master I/O.
@@ -291,34 +487,84 @@ static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
* datain - TRUE if data read.
* irq - TRUE if bus master interrupt expected.
*
- * Returns: TRUE if drive does not assert DRQ in time.
+ * Returns: Nothing.
*
****************************************************************/
static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq)
{
ULONG zl;
- outl (padapter->timingAddress, padapter->regDmaAddrLoc);
- outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
- zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
+ zl = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
padapter->sectorCount -= zl;
zl *= (ULONG)BYTES_PER_SECTOR;
- padapter->buffer += zl;
- outl (zl, padapter->regDmaCount);
+
if ( datain )
{
- outb_p (8, padapter->regDmaDesc); // read operation
- if ( irq && !padapter->sectorCount )
- outb_p (5, padapter->regDmaMode); // interrupt on
+ padapter->readCount = zl;
+ outb_p (8, padapter->regDmaDesc); // read operation
+ if ( padapter->bigD )
+ {
+ if ( irq && !padapter->sectorCount )
+ outb_p (0x0C, padapter->regDmaMode); // interrupt on
+ else
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
+ }
+ else
+ {
+ if ( irq && !padapter->sectorCount )
+ outb_p (0x05, padapter->regDmaMode); // interrupt on
+ else
+ outb_p (0x01, padapter->regDmaMode); // no interrupt
+ }
+ }
+ else
+ {
+ outb_p (0x00, padapter->regDmaDesc); // write operation
+ if ( padapter->bigD )
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
else
- outb_p (1, padapter->regDmaMode); // no interrupt
+ outb_p (0x01, padapter->regDmaMode); // no interrupt
+ WalkScatGath (padapter, FALSE, zl);
+ }
+
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+ outl (zl, padapter->regDmaCount);
+ outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
+ }
+/****************************************************************
+ * Name: AtapiBusMaster :LOCAL
+ *
+ * Description: Do a bus master I/O.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * datain - TRUE if data read.
+ * length - Number of bytes to transfer.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void AtapiBusMaster (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+ {
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
+ outl (length, padapter->regDmaCount);
+ if ( datain )
+ {
+ if ( padapter->readCount )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
+ outb_p (0x08, padapter->regDmaDesc); // read operation
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
+ padapter->readCount = length;
}
else
{
- outb_p (0, padapter->regDmaDesc); // write operation
- outb_p (1, padapter->regDmaMode); // no interrupt
+ outb_p (0x00, padapter->regDmaDesc); // write operation
+ outb_p (0x08, padapter->regDmaMode); // no interrupt
+ if ( !padapter->atapiSpecial )
+ WalkScatGath (padapter, FALSE, length);
}
- outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
+ outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
}
/****************************************************************
* Name: WriteData :LOCAL
@@ -339,9 +585,9 @@ static int WriteData (PADAPTER2220I padapter)
if ( padapter->timingPIO )
{
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
- outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
+ WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+ outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
padapter->sectorCount -= zl;
- padapter->buffer += zl * BYTES_PER_SECTOR;
}
else
BusMaster (padapter, 0, 0);
@@ -355,31 +601,32 @@ static int WriteData (PADAPTER2220I padapter)
*
* Description: Write data to device.
*
- * Parameters: padapter - Pointer adapter data structure.
+ * Parameters: padapter - Pointer to adapter structure.
+ * pdev - Pointer to device structure
*
- * Returns: TRUE if drive does not assert DRQ in time.
+ * Returns: Index + 1 of drive not failed or zero for OK.
*
****************************************************************/
-static int WriteDataBoth (PADAPTER2220I padapter)
+static int WriteDataBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
ULONG zl;
UCHAR status0, status1;
- SelectSpigot (padapter, 1);
+ SelectSpigot (padapter, pdev->spigots[0]);
status0 = WaitDrq (padapter);
if ( !status0 )
{
- SelectSpigot (padapter, 2);
+ SelectSpigot (padapter, pdev->spigots[1]);
status1 = WaitDrq (padapter);
if ( !status1 )
{
- SelectSpigot (padapter, 3);
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
if ( padapter->timingPIO )
{
zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
- outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
+ WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+ outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
padapter->sectorCount -= zl;
- padapter->buffer += zl * BYTES_PER_SECTOR;
}
else
BusMaster (padapter, 0, 0);
@@ -388,8 +635,8 @@ static int WriteDataBoth (PADAPTER2220I padapter)
}
padapter->cmd = 0; // null out the command byte
if ( status0 )
- return 1;
- return 2;
+ return 2;
+ return 1;
}
/****************************************************************
* Name: IdeCmd :LOCAL
@@ -406,7 +653,7 @@ static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
UCHAR status;
- SelectSpigot (padapter, pdev->spigot); // select the spigot
+ SelectSpigot (padapter, pdev->spigot | padapter->bigD); // select the spigot
outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24); // select the drive
status = WaitReady (padapter);
if ( !status )
@@ -429,26 +676,27 @@ static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
* Description: Process an IDE command to both drivers.
*
* Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device structure
*
- * Returns: Zero if no error or spigot of error.
+ * Returns: Index + 1 of drive not failed or zero for OK.
*
****************************************************************/
-static UCHAR IdeCmdBoth (PADAPTER2220I padapter)
+static UCHAR IdeCmdBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
UCHAR status0;
UCHAR status1;
- SelectSpigot (padapter, 3); // select the spigots
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]); // select the spigots
outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive
- SelectSpigot (padapter, 1);
+ SelectSpigot (padapter, pdev->spigots[0]);
status0 = WaitReady (padapter);
if ( !status0 )
{
- SelectSpigot (padapter, 2);
+ SelectSpigot (padapter, pdev->spigots[1]);
status1 = WaitReady (padapter);
if ( !status1 )
{
- SelectSpigot (padapter, 3);
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
outb_p (padapter->sectorCount, padapter->regSectCount);
outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0);
outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8);
@@ -460,8 +708,8 @@ static UCHAR IdeCmdBoth (PADAPTER2220I padapter)
}
padapter->cmd = 0; // null out the command byte
if ( status0 )
- return 1;
- return 2;
+ return 2;
+ return 1;
}
/****************************************************************
* Name: OpDone :LOCAL
@@ -498,6 +746,7 @@ static void OpDone (PADAPTER2220I padapter, ULONG result)
{
padapter->cmd = 0;
padapter->SCpnt = NULL;
+ padapter->pdev = NULL;
SCpnt->result = result;
SCpnt->scsi_done (SCpnt);
if ( padapter->reconOn && !padapter->reconTimer.data )
@@ -524,8 +773,8 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
{
PIDENTIFY_DATA pid = (PIDENTIFY_DATA)padapter->kBuffer;
- SelectSpigot (padapter, spigot | 0x80); // select the spigot
- outb_p (device << 4, padapter->regLba24); // select the drive
+ SelectSpigot (padapter, spigot | SEL_IRQ_OFF); // select the spigot
+ outb_p ((device << 4) | 0xA0, padapter->regLba24); // select the drive
if ( WaitReady (padapter) )
return 0;
WriteCommand (padapter, IDE_COMMAND_IDENTIFY);
@@ -535,6 +784,192 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
return (pid->LBATotalSectors - 1);
}
/****************************************************************
+ * Name: AtapiIdentify :LOCAL
+ *
+ * Description: Do an intline inquiry on a drive.
+ *
+ * Parameters: padapter - Pointer to host data block.
+ * pdev - Pointer to device table.
+ *
+ * Returns: TRUE on error.
+ *
+ ****************************************************************/
+static ULONG AtapiIdentify (PADAPTER2220I padapter, POUR_DEVICE pdev)
+ {
+ ATAPI_GENERAL_0 ag0;
+ USHORT zs;
+ int z;
+
+ AtapiDevice (padapter, pdev->byte6);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_IDENTIFY);
+ if ( AtapiWaitDrq (padapter, 3000) )
+ return TRUE;
+
+ *(USHORT *)&ag0 = inw_p (padapter->regData);
+ for ( z = 0; z < 255; z++ )
+ zs = inw_p (padapter->regData);
+
+ if ( ag0.ProtocolType == 2 )
+ {
+ if ( ag0.CmdDrqType == 1 )
+ pdev->cmdDrqInt = TRUE;
+ switch ( ag0.CmdPacketSize )
+ {
+ case 0:
+ pdev->packet = 6;
+ break;
+ case 1:
+ pdev->packet = 8;
+ break;
+ default:
+ pdev->packet = 6;
+ break;
+ }
+ return FALSE;
+ }
+ return TRUE;
+ }
+/****************************************************************
+ * Name: Atapi2Scsi
+ *
+ * Description: Convert ATAPI data to SCSI data.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+void Atapi2Scsi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+ {
+ UCHAR *buff = padapter->currentSgBuffer;
+
+ switch ( SCpnt->cmnd[0] )
+ {
+ case SCSIOP_MODE_SENSE:
+ buff[0] = padapter->kBuffer[1];
+ buff[1] = padapter->kBuffer[2];
+ buff[2] = padapter->kBuffer[3];
+ buff[3] = padapter->kBuffer[7];
+ memcpy (&buff[4], &padapter->kBuffer[8], padapter->atapiCdb[8] - 8);
+ break;
+ case SCSIOP_INQUIRY:
+ padapter->kBuffer[2] = 2;
+ memcpy (buff, padapter->kBuffer, padapter->currentSgCount);
+ break;
+ default:
+ if ( padapter->readCount )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
+ break;
+ }
+ }
+/****************************************************************
+ * Name: Scsi2Atapi
+ *
+ * Description: Convert SCSI packet command to Atapi packet command.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * SCpnt - Pointer to SCSI command structure.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void Scsi2Atapi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+ {
+ UCHAR *cdb = SCpnt->cmnd;
+ UCHAR *buff = padapter->currentSgBuffer;
+
+ switch (cdb[0])
+ {
+ case SCSIOP_READ6:
+ padapter->atapiCdb[0] = SCSIOP_READ;
+ padapter->atapiCdb[1] = cdb[1] & 0xE0;
+ padapter->atapiCdb[3] = cdb[1] & 0x1F;
+ padapter->atapiCdb[4] = cdb[2];
+ padapter->atapiCdb[5] = cdb[3];
+ padapter->atapiCdb[8] = cdb[4];
+ padapter->atapiCdb[9] = cdb[5];
+ break;
+ case SCSIOP_WRITE6:
+ padapter->atapiCdb[0] = SCSIOP_WRITE;
+ padapter->atapiCdb[1] = cdb[1] & 0xE0;
+ padapter->atapiCdb[3] = cdb[1] & 0x1F;
+ padapter->atapiCdb[4] = cdb[2];
+ padapter->atapiCdb[5] = cdb[3];
+ padapter->atapiCdb[8] = cdb[4];
+ padapter->atapiCdb[9] = cdb[5];
+ break;
+ case SCSIOP_MODE_SENSE:
+ padapter->atapiCdb[0] = SCSIOP_MODE_SENSE10;
+ padapter->atapiCdb[2] = cdb[2];
+ padapter->atapiCdb[8] = cdb[4] + 4;
+ break;
+
+ case SCSIOP_MODE_SELECT:
+ padapter->atapiSpecial = TRUE;
+ padapter->atapiCdb[0] = SCSIOP_MODE_SELECT10;
+ padapter->atapiCdb[1] = cdb[1] | 0x10;
+ memcpy (padapter->kBuffer, buff, 4);
+ padapter->kBuffer[4] = padapter->kBuffer[5] = 0;
+ padapter->kBuffer[6] = padapter->kBuffer[7] = 0;
+ memcpy (&padapter->kBuffer[8], &buff[4], cdb[4] - 4);
+ padapter->atapiCdb[8] = cdb[4] + 4;
+ break;
+ }
+ }
+/****************************************************************
+ * Name: AtapiSendCdb
+ *
+ * Description: Send the CDB packet to the device.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device.
+ * cdb - Pointer to 16 byte SCSI cdb.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+static void AtapiSendCdb (PADAPTER2220I padapter, POUR_DEVICE pdev, CHAR *cdb)
+ {
+ DEB (printk ("\nPCI2242I: CDB: %X %X %X %X %X %X %X %X %X %X %X %X", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]));
+ outsw (padapter->regData, cdb, pdev->packet);
+ }
+/****************************************************************
+ * Name: AtapiRequestSense
+ *
+ * Description: Send the CDB packet to the device.
+ *
+ * Parameters: padapter - Pointer adapter data structure.
+ * pdev - Pointer to device.
+ * SCpnt - Pointer to SCSI command structure.
+ * pass - If true then this is the second pass to send cdb.
+ *
+ * Returns: TRUE on error.
+ *
+ ****************************************************************/
+static int AtapiRequestSense (PADAPTER2220I padapter, POUR_DEVICE pdev, Scsi_Cmnd *SCpnt, UCHAR pass)
+ {
+ UCHAR cdb[16] = {SCSIOP_REQUEST_SENSE,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0};
+
+ DEB (printk ("\nPCI2242I: AUTO REQUEST SENSE"));
+ cdb[4] = (UCHAR)(sizeof (SCpnt->sense_buffer));
+ if ( !pass )
+ {
+ padapter->reqSense = TRUE;
+ AtapiCountLo (padapter, cdb[4]);
+ AtapiCountHi (padapter, 0);
+ outb_p (0, padapter->regError);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+ if ( pdev->cmdDrqInt )
+ return FALSE;
+
+ if ( AtapiWaitDrq (padapter, 500) )
+ return TRUE;
+ }
+ AtapiSendCdb (padapter, pdev, cdb);
+ return FALSE;
+ }
+/****************************************************************
* Name: InlineReadSignature :LOCAL
*
* Description: Do an inline read RAID sigature.
@@ -549,10 +984,9 @@ static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
static UCHAR InlineReadSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, int index)
{
UCHAR status;
- UCHAR spigot = 1 << index;
ULONG zl = pdev->lastsectorlba[index];
- SelectSpigot (padapter, spigot | 0x80); // select the spigot without interrupts
+ SelectSpigot (padapter, pdev->spigots[index] | SEL_IRQ_OFF); // select the spigot without interrupts
outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24);
status = WaitReady (padapter);
if ( !status )
@@ -591,6 +1025,10 @@ static ULONG DecodeError (PADAPTER2220I padapter, UCHAR status)
UCHAR error;
padapter->expectingIRQ = 0;
+#ifdef DEBUG
+ printk (" @@@@@@ status: %X @@@@@@@ ", status);
+ STOP_HERE();
+#endif
if ( status & IDE_STATUS_WRITE_FAULT )
{
return DID_PARITY << 16;
@@ -678,25 +1116,33 @@ static int WriteSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigo
******************************************************************************************************/
static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev)
{
- UCHAR spigot;
+ UCHAR spigot;
- DEB (printk ("\npci2220i: Initialize failover process - survivor = %d", padapter->survivor));
+ DEB (printk ("\npci2220i: Initialize failover process - survivor = %d", pdev->deviceID[padapter->survivor]));
pdev->raid = FALSE; //initializes system for non raid mode
- pdev->hotRecon = 0;
- padapter->reconOn = FALSE;
- spigot = (padapter->survivor) ? 2 : 1;
+ pdev->reconOn = FALSE;
+ spigot = pdev->spigots[padapter->survivor];
if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD )
- return (TRUE);
+ {
+ DEB (printk ("\n failed, is survivor"));
+ return (TRUE);
+ }
if ( HardReset (padapter, pdev, spigot) )
+ {
+ DEB (printk ("\n failed, reset"));
return TRUE;
+ }
- outb_p (0x3C | spigot, padapter->regFail); // sound alarm and set fail light
+ Alarm (padapter, pdev->deviceID[padapter->survivor ^ 1]);
pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR; //clear present status
if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) )
+ {
+ DEB (printk ("\n failed, write signature"));
return TRUE;
+ }
padapter->failinprog = TRUE;
return FALSE;
}
@@ -716,13 +1162,23 @@ static void TimerExpiry (unsigned long data)
POUR_DEVICE pdev = padapter->pdev;
UCHAR status = IDE_STATUS_BUSY;
UCHAR temp, temp1;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
DEB (printk ("\nPCI2220I: Timeout expired "));
if ( padapter->failinprog )
@@ -739,7 +1195,7 @@ static void TimerExpiry (unsigned long data)
{
case RECON_PHASE_MARKING:
case RECON_PHASE_LAST:
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
DEB (printk ("\npci2220i: FAILURE 1"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
@@ -750,7 +1206,7 @@ static void TimerExpiry (unsigned long data)
goto timerExpiryDone;
case RECON_PHASE_COPY:
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 2"));
DEB (printk ("\n spig/stat = %X", inb_p (padapter->regStatSel));
if ( InitFailover (padapter, pdev) )
@@ -758,14 +1214,14 @@ static void TimerExpiry (unsigned long data)
goto timerExpiryDone;
case RECON_PHASE_UPDATE:
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 3")));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
goto timerExpiryDone;
case RECON_PHASE_END:
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 4"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DID_ERROR << 16);
@@ -784,17 +1240,21 @@ static void TimerExpiry (unsigned long data)
if ( padapter->cmd == WRITE_CMD )
{
DEB (printk ("in RAID write operation"));
- if ( inb_p (padapter->regStatSel) & 1 )
+ temp = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_1 : SEL_3;
+ if ( inb_p (padapter->regStatSel) & temp )
{
- SelectSpigot (padapter, 0x81 ); // Masking the interrupt during spigot select
+ DEB (printk ("\npci2220i: Determined A OK"));
+ SelectSpigot (padapter, temp | SEL_IRQ_OFF); // Masking the interrupt during spigot select
temp = inb_p (padapter->regStatCmd);
}
else
temp = IDE_STATUS_BUSY;
- if ( inb (padapter->regStatSel) & 2 )
+ temp1 = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_2 : SEL_4;
+ if ( inb (padapter->regStatSel) & temp1 )
{
- SelectSpigot (padapter, 0x82 ); // Masking the interrupt during spigot select
+ DEB (printk ("\npci2220i: Determined B OK"));
+ SelectSpigot (padapter, temp1 | SEL_IRQ_OFF); // Masking the interrupt during spigot select
temp1 = inb_p (padapter->regStatCmd);
}
else
@@ -802,6 +1262,7 @@ static void TimerExpiry (unsigned long data)
if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) )
{
+ DEB (printk ("\npci2220i: Status A: %X B: %X", temp & 0xFF, temp1 & 0xFF));
if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) )
{
status = temp;
@@ -809,11 +1270,10 @@ static void TimerExpiry (unsigned long data)
}
else
{
- if (temp & IDE_STATUS_BUSY)
+ if ( temp & IDE_STATUS_BUSY )
padapter->survivor = 1;
else
padapter->survivor = 0;
- DEB (printk ("\npci2220i: FAILURE 5"));
if ( InitFailover (padapter, pdev) )
{
status = inb_p (padapter->regStatCmd);
@@ -826,7 +1286,7 @@ static void TimerExpiry (unsigned long data)
else
{
DEB (printk ("in RAID read operation"));
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 6"));
if ( InitFailover (padapter, pdev) )
{
@@ -847,12 +1307,20 @@ static void TimerExpiry (unsigned long data)
OpDone (padapter, DecodeError (padapter, status));
timerExpiryDone:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: SetReconstruct :LOCAL
@@ -871,7 +1339,6 @@ static LONG SetReconstruct (POUR_DEVICE pdev, int index)
pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD;
pdev->DiskMirror[index ^ 1].reconstructPoint = 0; // start the reconstruct
pdev->reconCount = 1990; // mark target drive early
- pdev->hotRecon = 1 >> index;
return pdev->DiskMirror[index].reconstructPoint;
}
/****************************************************************
@@ -893,35 +1360,66 @@ static void ReconTimerExpiry (unsigned long data)
USHORT minmode;
ULONG zl;
UCHAR zc;
+ USHORT z;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
padapter = (PADAPTER2220I)data;
if ( padapter->SCpnt )
goto reconTimerExpiry;
- pdev = padapter->device;
- pid = (PIDENTIFY_DATA)padapter->kBuffer;
padapter->reconTimer.data = 0;
+ for ( z = padapter->devInReconIndex + 1; z < BIGD_MAXDRIVES; z++ )
+ {
+ if ( padapter->device[z].reconOn )
+ break;
+ }
+ if ( z < BIGD_MAXDRIVES )
+ pdev = &padapter->device[z];
+ else
+ {
+ for ( z = 0; z < BIGD_MAXDRIVES; z++ )
+ {
+ if ( padapter->device[z].reconOn )
+ break;
+ }
+ if ( z < BIGD_MAXDRIVES )
+ pdev = &padapter->device[z];
+ else
+ {
+ padapter->reconOn = FALSE;
+ goto reconTimerExpiry;
+ }
+ }
+
+ padapter->devInReconIndex = z;
+ pid = (PIDENTIFY_DATA)padapter->kBuffer;
padapter->pdev = pdev;
- if ( padapter->reconIsStarting )
+ if ( pdev->reconIsStarting )
{
- padapter->reconIsStarting = FALSE;
- padapter->reconOn = FALSE;
- pdev->hotRecon = FALSE;
+ pdev->reconIsStarting = FALSE;
+ pdev->reconOn = FALSE;
- if ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
+ while ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
(pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) )
{
if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) )
- {
- goto reconTimerExpiry;
- }
+ break;;
if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR ) // is first drive survivor?
testsize = SetReconstruct (pdev, 0);
@@ -932,33 +1430,38 @@ static void ReconTimerExpiry (unsigned long data)
if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
{
if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
- {
- pdev->hotRecon = 1;
pdev->mirrorRecon = 0;
- }
else
- {
- pdev->hotRecon = 2;
pdev->mirrorRecon = 1;
- }
+ pdev->reconOn = TRUE;
}
+ break;
}
- if ( !pdev->hotRecon )
+ if ( !pdev->reconOn )
goto reconTimerExpiry;
- zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm
- outb_p (zc | pdev->hotRecon | 0x40, padapter->regFail);
+ if ( padapter->bigD )
+ {
+ padapter->failRegister = 0;
+ outb_p (~padapter->failRegister, padapter->regFail);
+ }
+ else
+ {
+ zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm
+ outb_p (0xFF, padapter->regFail);
+ }
while ( 1 )
{
- if ( HardReset (padapter, pdev, pdev->hotRecon) )
+ DEB (printk ("\npci2220i: hard reset issue"));
+ if ( HardReset (padapter, pdev, pdev->spigots[pdev->mirrorRecon]) )
{
DEB (printk ("\npci2220i: sub 1"));
break;
}
- pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->hotRecon, 0);
+ pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->spigots[pdev->mirrorRecon], pdev->deviceID[pdev->mirrorRecon] & 1);
if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize )
{
@@ -1014,12 +1517,11 @@ static void ReconTimerExpiry (unsigned long data)
break;
}
- if ( !padapter->reconOn )
+ if ( !pdev->reconOn )
{
- pdev->hotRecon = FALSE;
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
- DEB (printk ("\npci2220i: FAILURE 7"));
+ DEB (printk ("\npci2220i: FAILURE 7"));
InitFailover (padapter, pdev);
goto reconTimerExpiry;
}
@@ -1038,11 +1540,11 @@ static void ReconTimerExpiry (unsigned long data)
if ( pdev->reconCount++ > 2000 )
{
pdev->reconCount = 0;
- if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
+ if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
{
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
- DEB (printk ("\npci2220i: FAILURE 8"));
+ DEB (printk ("\npci2220i: FAILURE 8"));
InitFailover (padapter, pdev);
goto reconTimerExpiry;
}
@@ -1057,30 +1559,30 @@ static void ReconTimerExpiry (unsigned long data)
if ( padapter->reconSize )
{
- SelectSpigot (padapter, 3); // select the spigots
- outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);// select the drive
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]); // select the spigots
+ outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24); // select the drive
SelectSpigot (padapter, pdev->spigot);
if ( WaitReady (padapter) )
goto reconTimerExpiry;
- SelectSpigot (padapter, pdev->hotRecon);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
if ( WaitReady (padapter) )
{
padapter->survivor = pdev->mirrorRecon ^ 1;
padapter->reconPhase = RECON_PHASE_FAILOVER;
- DEB (printk ("\npci2220i: FAILURE 9"));
+ DEB (printk ("\npci2220i: FAILURE 9"));
InitFailover (padapter, pdev);
goto reconTimerExpiry;
}
- SelectSpigot (padapter, 3);
+ SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);
outb_p (padapter->reconSize & 0xFF, padapter->regSectCount);
outb_p (((UCHAR *)(&zl))[0], padapter->regLba0);
outb_p (((UCHAR *)(&zl))[1], padapter->regLba8);
outb_p (((UCHAR *)(&zl))[2], padapter->regLba16);
padapter->expectingIRQ = TRUE;
padapter->reconPhase = RECON_PHASE_READY;
- SelectSpigot (padapter, pdev->hotRecon);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
WriteCommand (padapter, WRITE_CMD);
StartTimer (padapter);
SelectSpigot (padapter, pdev->spigot);
@@ -1095,12 +1597,20 @@ static void ReconTimerExpiry (unsigned long data)
padapter->reconPhase = RECON_PHASE_LAST;
reconTimerExpiry:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: Irq_Handler :LOCAL
@@ -1122,15 +1632,28 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
Scsi_Cmnd *SCpnt;
UCHAR status;
UCHAR status1;
+ ATAPI_STATUS statusa;
+ ATAPI_REASON reasona;
+ ATAPI_ERROR errora;
int z;
ULONG zl;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ int flags;
+#else /* version >= v2.1.95 */
unsigned long flags;
+#endif /* version >= v2.1.95 */
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /* Disable interrupts, if they aren't already disabled. */
+ save_flags (flags);
+ cli ();
+#else /* version >= v2.1.95 */
/*
* Disable interrupts, if they aren't already disabled and acquire
* the I/O spinlock.
*/
spin_lock_irqsave (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
// DEB (printk ("\npci2220i recieved interrupt\n"));
@@ -1155,7 +1678,70 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
padapter = HOSTDATA(shost);
pdev = padapter->pdev;
SCpnt = padapter->SCpnt;
+ outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
+ if ( padapter->atapi && SCpnt )
+ {
+ *(char *)&statusa = inb_p (padapter->regStatCmd); // read the device status
+ *(char *)&reasona = inb_p (padapter->regSectCount); // read the device interrupt reason
+
+ if ( !statusa.bsy )
+ {
+ if ( statusa.drq ) // test for transfer phase
+ {
+ if ( !reasona.cod ) // test for data phase
+ {
+ z = (ULONG)inb_p (padapter->regLba8) | (ULONG)(inb_p (padapter->regLba16) << 8);
+ if ( padapter->reqSense )
+ insw (padapter->regData, SCpnt->sense_buffer, z / 2);
+ else
+ AtapiBusMaster (padapter, reasona.io, z);
+ goto irq_return;
+ }
+ if ( reasona.cod && !reasona.io ) // test for command packet phase
+ {
+ if ( padapter->reqSense )
+ AtapiRequestSense (padapter, pdev, SCpnt, TRUE);
+ else
+ AtapiSendCdb (padapter, pdev, padapter->atapiCdb);
+ goto irq_return;
+ }
+ }
+ else
+ {
+ if ( reasona.io && statusa.drdy ) // test for status phase
+ {
+ Atapi2Scsi (padapter, SCpnt);
+ if ( statusa.check )
+ {
+ *(UCHAR *)&errora = inb_p (padapter->regError); // read the device error
+ if ( errora.senseKey )
+ {
+ if ( padapter->reqSense || AtapiRequestSense (padapter, pdev, SCpnt, FALSE) )
+ OpDone (padapter, DID_ERROR << 16);
+ }
+ else
+ {
+ if ( errora.ili || errora.abort )
+ OpDone (padapter, DID_ERROR << 16);
+ else
+ OpDone (padapter, DID_OK << 16);
+ }
+ }
+ else
+ if ( padapter->reqSense )
+ {
+ DEB (printk ("PCI2242I: Sense codes - %X %X %X ", ((UCHAR *)SCpnt->sense_buffer)[0], ((UCHAR *)SCpnt->sense_buffer)[12], ((UCHAR *)SCpnt->sense_buffer)[13]));
+ OpDone (padapter, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2);
+ }
+ else
+ OpDone (padapter, DID_OK << 16);
+ }
+ }
+ }
+ goto irq_return;
+ }
+
if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) )
{
DEB(printk ("\npci2220i Unsolicited interrupt\n"));
@@ -1163,7 +1749,6 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
goto irq_return;
}
padapter->expectingIRQ = 0;
- outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine
if ( padapter->failinprog )
{
@@ -1178,7 +1763,7 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
else
{
DEB (printk ("\npci2220i: restarting failed opertation."));
- pdev->spigot = (padapter->survivor) ? 2 : 1;
+ pdev->spigot = (padapter->survivor) ? pdev->spigots[1] : pdev->spigots[0];
del_timer (&padapter->timer);
if ( padapter->reconPhase )
OpDone (padapter, DID_OK << 16);
@@ -1200,15 +1785,15 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
DEB (printk ("\npci2220i: FAILURE 10"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) )
+ if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
{
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 11"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
@@ -1228,17 +1813,17 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- SelectSpigot (padapter, pdev->hotRecon);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
if ( WaitDrq (padapter) )
{
del_timer (&padapter->timer);
- padapter->survivor = (pdev->spigot) >> 1;
- DEB (printk ("\npci2220i: FAILURE 12"));
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+ DEB (printk ("\npci2220i: FAILURE 12"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- SelectSpigot (padapter, pdev->spigot | 0x40);
+ SelectSpigot (padapter, pdev->spigot | SEL_COPY | padapter->bigD);
padapter->reconPhase = RECON_PHASE_COPY;
padapter->expectingIRQ = TRUE;
if ( padapter->timingPIO )
@@ -1247,11 +1832,22 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
else
{
- outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+ if ( (padapter->timingMode > 3) )
+ {
+ if ( padapter->bigD )
+ outl (BIGD_DATA_MODE3, padapter->regDmaAddrLoc);
+ else
+ outl (DALE_DATA_MODE3, padapter->regDmaAddrLoc);
+ }
+ else
+ outl (padapter->timingAddress, padapter->regDmaAddrLoc);
outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci);
outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount);
outb_p (8, padapter->regDmaDesc); // read operation
- outb_p (1, padapter->regDmaMode); // no interrupt
+ if ( padapter->bigD )
+ outb_p (8, padapter->regDmaMode); // no interrupt
+ else
+ outb_p (1, padapter->regDmaMode); // no interrupt
outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear
}
goto irq_return;
@@ -1260,13 +1856,14 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize;
case RECON_PHASE_UPDATE:
- SelectSpigot (padapter, pdev->hotRecon | 0x80);
+ SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon] | SEL_IRQ_OFF);
status = inb_p (padapter->regStatCmd); // read the device status
del_timer (&padapter->timer);
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = (pdev->spigot) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
DEB (printk ("\npci2220i: FAILURE 13"));
+ DEB (printk ("\n status register = %X error = %X", status, inb_p (padapter->regError)));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
@@ -1279,14 +1876,29 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
del_timer (&padapter->timer);
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = (pdev->spigot) >> 1;
- DEB (printk ("\npci2220i: FAILURE 14"));
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+ DEB (printk ("\npci2220i: FAILURE 14"));
if ( InitFailover (padapter, pdev) )
OpDone (padapter, DecodeError (padapter, status));
goto irq_return;
}
- padapter->reconOn = FALSE;
- pdev->hotRecon = 0;
+ pdev->reconOn = 0;
+ if ( padapter->bigD )
+ {
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
+ {
+ if ( padapter->device[z].DiskMirror[0].status & UCBF_SURVIVOR )
+ {
+ Alarm (padapter, padapter->device[z].deviceID[0] ^ 2);
+ MuteAlarm (padapter);
+ }
+ if ( padapter->device[z].DiskMirror[1].status & UCBF_SURVIVOR )
+ {
+ Alarm (padapter, padapter->device[z].deviceID[1] ^ 2);
+ MuteAlarm (padapter);
+ }
+ }
+ }
OpDone (padapter, DID_OK << 16);
goto irq_return;
@@ -1305,9 +1917,9 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
if ( pdev->raid )
{
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
del_timer (&padapter->timer);
- DEB (printk ("\npci2220i: FAILURE 15"));
+ DEB (printk ("\npci2220i: FAILURE 15"));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
}
@@ -1315,10 +1927,9 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
if ( padapter->timingPIO )
{
- zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
- insw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2));
- padapter->sectorCount -= zl;
- padapter->buffer += zl * BYTES_PER_SECTOR;
+ insw (padapter->regData, padapter->kBuffer, padapter->readCount / 2);
+ padapter->sectorCount -= padapter->readCount / BYTES_PER_SECTOR;
+ WalkScatGath (padapter, TRUE, padapter->readCount);
if ( !padapter->sectorCount )
{
status = 0;
@@ -1326,32 +1937,40 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
}
else
+ {
+ if ( padapter->readCount )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
BusMaster (padapter, 1, 1);
+ }
padapter->expectingIRQ = TRUE;
goto irq_return;
}
+ if ( padapter->readCount && !padapter->timingPIO )
+ WalkScatGath (padapter, TRUE, padapter->readCount);
status = 0;
break;
case WRITE_CMD:
- SelectSpigot (padapter, pdev->spigot | 0x80);
- status = inb_p (padapter->regStatCmd); // read the device status
if ( pdev->raid )
{
- SelectSpigot (padapter, (pdev->spigot ^ 3) | 0x80);
- status1 = inb_p (padapter->regStatCmd); // read the device status
+ SelectSpigot (padapter, pdev->spigots[0] | SEL_IRQ_OFF);
+ status = inb_p (padapter->regStatCmd); // read the device status
+ SelectSpigot (padapter, pdev->spigots[1] | SEL_IRQ_OFF);
+ status1 = inb_p (padapter->regStatCmd); // read the device status
}
else
+ SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);
+ status = inb_p (padapter->regStatCmd); // read the device status
status1 = 0;
if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) )
{
- padapter->survivor = (pdev->spigot ^ 3) >> 1;
+ padapter->survivor = 1;
del_timer (&padapter->timer);
- SelectSpigot (padapter, pdev->spigot | 0x80);
- DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError)));
+ SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);
+ DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError)));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
}
@@ -1361,9 +1980,9 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
{
if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
{
- padapter->survivor = pdev->spigot >> 1;
+ padapter->survivor = 0;
del_timer (&padapter->timer);
- DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError)));
+ DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError)));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
status = status1;
@@ -1371,15 +1990,15 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
if ( padapter->sectorCount )
{
- status = WriteDataBoth (padapter);
+ status = WriteDataBoth (padapter, pdev);
if ( status )
{
- padapter->survivor = (status ^ 3) >> 1;
+ padapter->survivor = status >> 1;
del_timer (&padapter->timer);
- DEB (printk ("\npci2220i: FAILURE 18"));
+ DEB (printk ("\npci2220i: FAILURE 18"));
if ( !InitFailover (padapter, pdev) )
goto irq_return;
- SelectSpigot (padapter, status | 0x80);
+ SelectSpigot (padapter, pdev->spigots[status] | SEL_IRQ_OFF);
status = inb_p (padapter->regStatCmd); // read the device status
break;
}
@@ -1391,7 +2010,7 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
}
if ( padapter->sectorCount )
{
- SelectSpigot (padapter, pdev->spigot);
+ SelectSpigot (padapter, pdev->spigot | padapter->bigD);
status = WriteData (padapter);
if ( status )
break;
@@ -1458,12 +2077,20 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
OpDone (padapter, zl);
irq_return:;
+#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95)
+ /*
+ * Restore the original flags which will enable interrupts
+ * if and only if they were enabled on entry.
+ */
+ restore_flags (flags);
+#else /* version >= v2.1.95 */
/*
* Release the I/O spinlock and restore the original flags
* which will enable interrupts if and only if they were
* enabled on entry.
*/
spin_unlock_irqrestore (&io_request_lock, flags);
+#endif /* version >= v2.1.95 */
}
/****************************************************************
* Name: Pci2220i_QueueCommand
@@ -1486,14 +2113,88 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
PDEVICE_RAID1 pdr;
SCpnt->scsi_done = done;
- padapter->buffer = SCpnt->request_buffer;
padapter->SCpnt = SCpnt; // Save this command data
+ padapter->readCount = 0;
+
+ if ( SCpnt->use_sg )
+ {
+ padapter->currentSgBuffer = ((struct scatterlist *)SCpnt->request_buffer)[0].address;
+ padapter->currentSgCount = ((struct scatterlist *)SCpnt->request_buffer)[0].length;
+ }
+ else
+ {
+ padapter->currentSgBuffer = SCpnt->request_buffer;
+ padapter->currentSgCount = SCpnt->request_bufflen;
+ }
+ padapter->nextSg = 1;
+
if ( !done )
{
printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);
return 0;
}
+ if ( padapter->atapi )
+ {
+ UCHAR zlo, zhi;
+
+ DEB (printk ("\nPCI2242I: ID %d, LUN %d opcode %X ", SCpnt->target, SCpnt->lun, *cdb));
+ padapter->pdev = pdev;
+ if ( !pdev->byte6 || SCpnt->lun )
+ {
+ OpDone (padapter, DID_BAD_TARGET << 16);
+ return 0;
+ }
+
+ padapter->atapiSpecial = FALSE;
+ padapter->reqSense = FALSE;
+ memset (padapter->atapiCdb, 0, 16);
+ SelectSpigot (padapter, pdev->spigot); // select the spigot
+ AtapiDevice (padapter, pdev->byte6); // select the drive
+ if ( AtapiWaitReady (padapter, 100) )
+ {
+ OpDone (padapter, DID_NO_CONNECT << 16);
+ return 0;
+ }
+
+ switch ( cdb[0] )
+ {
+ case SCSIOP_MODE_SENSE:
+ case SCSIOP_MODE_SELECT:
+ Scsi2Atapi (padapter, SCpnt);
+ z = SCpnt->request_bufflen + 4;
+ break;
+ case SCSIOP_READ6:
+ case SCSIOP_WRITE6:
+ Scsi2Atapi (padapter, SCpnt);
+ z = SCpnt->request_bufflen;
+ break;
+ default:
+ memcpy (padapter->atapiCdb, cdb, SCpnt->cmd_len);
+ z = SCpnt->request_bufflen;
+ break;
+ }
+ if ( z > ATAPI_TRANSFER )
+ z = ATAPI_TRANSFER;
+ zlo = (UCHAR)(z & 0xFF);
+ zhi = (UCHAR)(z >> 8);
+
+ AtapiCountLo (padapter, zlo);
+ AtapiCountHi (padapter, zhi);
+ outb_p (0, padapter->regError);
+ WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+ if ( pdev->cmdDrqInt )
+ return 0;
+
+ if ( AtapiWaitDrq (padapter, 500) )
+ {
+ OpDone (padapter, DID_ERROR << 16);
+ return 0;
+ }
+ AtapiSendCdb (padapter, pdev, padapter->atapiCdb);
+ return 0;
+ }
+
if ( padapter->reconPhase )
return 0;
if ( padapter->reconTimer.data )
@@ -1502,12 +2203,11 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
padapter->reconTimer.data = 0;
}
- if ( !pdev->device || SCpnt->lun )
+ if ( (SCpnt->target >= padapter->numberOfDrives) || SCpnt->lun )
{
OpDone (padapter, DID_BAD_TARGET << 16);
return 0;
}
-
switch ( *cdb )
{
@@ -1518,7 +2218,15 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
switch ( cdb[3] )
{
case MY_SCSI_REBUILD:
- padapter->reconOn = padapter->reconIsStarting = TRUE;
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
+ {
+ pdev = &padapter->device[z];
+ if ( ((pdev->DiskMirror[0].status & UCBF_SURVIVOR) && (pdev->DiskMirror[1].status & UCBF_MIRRORED)) ||
+ ((pdev->DiskMirror[1].status & UCBF_SURVIVOR) && (pdev->DiskMirror[0].status & UCBF_MIRRORED)) )
+ {
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ }
OpDone (padapter, DID_OK << 16);
break;
case MY_SCSI_ALARMMUTE:
@@ -1535,7 +2243,10 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
if ( padapter->raidData[z] )
{
memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR));
- pdr->TotalSectors = padapter->device[0].blocks;
+ if ( padapter->raidData[z]->reconstructPoint > padapter->raidData[z ^ 2]->reconstructPoint )
+ pdr->TotalSectors = padapter->raidData[z]->reconstructPoint;
+ else
+ pdr->TotalSectors = padapter->raidData[z ^ 2]->reconstructPoint;
}
else
memset (pdr, 0, sizeof (DEVICE_RAID1));
@@ -1598,6 +2309,7 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
while ( padapter->demoFail )
{
+ pdev = padapter->pdev = &padapter->device[0];
padapter->demoFail = FALSE;
if ( !pdev->raid ||
(pdev->DiskMirror[0].status & UCBF_SURVIVOR) ||
@@ -1610,7 +2322,7 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
else
padapter->survivor = 0;
DEB (printk ("\npci2220i: FAILURE 19"));
- if ( InitFailover (padapter, pdev ) )
+ if ( InitFailover (padapter, pdev) )
break;
return 0;
}
@@ -1618,14 +2330,14 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
StartTimer (padapter);
if ( pdev->raid && (padapter->cmd == WRITE_CMD) )
{
- rc = IdeCmdBoth (padapter);
+ rc = IdeCmdBoth (padapter, pdev);
if ( !rc )
- rc = WriteDataBoth (padapter);
+ rc = WriteDataBoth (padapter, pdev);
if ( rc )
{
del_timer (&padapter->timer);
padapter->expectingIRQ = 0;
- padapter->survivor = (rc ^ 3) >> 1;
+ padapter->survivor = rc >> 1;
DEB (printk ("\npci2220i: FAILURE 20"));
if ( InitFailover (padapter, pdev) )
{
@@ -1656,7 +2368,6 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
}
return 0;
}
-
static void internal_done(Scsi_Cmnd *SCpnt)
{
SCpnt->SCp.Status++;
@@ -1692,25 +2403,192 @@ int Pci2220i_Command (Scsi_Cmnd *SCpnt)
* Returns: Nothing.
*
****************************************************************/
-VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
+static VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
{
ULONG oldremap;
UCHAR olddesc;
ULONG z;
UCHAR *pd = (UCHAR *)pdata;
- oldremap = inl (padapter->regRemap); // save values to restore later
+ oldremap = inl (padapter->regRemap); // save values to restore later
olddesc = inb_p (padapter->regDesc);
- outl (base | 1, padapter->regRemap); // remap to Flash space as specified
- outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit
- for ( z = 0; z < length; z++) // get "length" data count
- *pd++ = inb_p (padapter->regBase + z); // read in the data
+ outl (base | 1, padapter->regRemap); // remap to Flash space as specified
+ outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit
+ for ( z = 0; z < length; z++) // get "length" data count
+ *pd++ = inb_p (padapter->regBase + z); // read in the data
- outl (oldremap, padapter->regRemap); // restore remap register values
+ outl (oldremap, padapter->regRemap); // restore remap register values
outb_p (olddesc, padapter->regDesc);
}
/****************************************************************
+ * Name: GetRegs
+ *
+ * Description: Initialize the regester information.
+ *
+ * Parameters: pshost - Pointer to SCSI host data structure.
+ * bigd - PCI-2240I identifier
+ * pcidev - Pointer to device data structure.
+ * pci_bus - PCI bus number.
+ * pci_device_fn - PCI device and function number.
+ *
+ * Returns: TRUE if failure to install.
+ *
+ ****************************************************************/
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcidev)
+#else
+static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, UCHAR pci_bus, UCHAR pci_device_fn)
+#endif
+ {
+ PADAPTER2220I padapter;
+ int setirq;
+ int z;
+ USHORT zr, zl;
+
+ padapter = HOSTDATA(pshost);
+ memset (padapter, 0, sizeof (ADAPTER2220I));
+ memset (&DaleSetup, 0, sizeof (DaleSetup));
+ memset (DiskMirror, 0, sizeof (DiskMirror));
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ zr = pcidev->base_address[1] & 0xFFFE;
+ zl = pcidev->base_address[2] & 0xFFFE;
+#else
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zr);
+ zr &= 0xFFFE;
+ pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zl);
+ zl &= 0xFFFE;
+#endif
+ padapter->basePort = zr;
+ padapter->regRemap = zr + RTR_LOCAL_REMAP; // 32 bit local space remap
+ padapter->regDesc = zr + RTR_REGIONS; // 32 bit local region descriptor
+ padapter->regRange = zr + RTR_LOCAL_RANGE; // 32 bit local range
+ padapter->regIrqControl = zr + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status
+ padapter->regScratchPad = zr + RTR_MAILBOX; // 16 byte scratchpad I/O base address
+
+ padapter->regBase = zl;
+ padapter->regData = zl + REG_DATA; // data register I/O address
+ padapter->regError = zl + REG_ERROR; // error register I/O address
+ padapter->regSectCount = zl + REG_SECTOR_COUNT; // sector count register I/O address
+ padapter->regLba0 = zl + REG_LBA_0; // least significant byte of LBA
+ padapter->regLba8 = zl + REG_LBA_8; // next least significant byte of LBA
+ padapter->regLba16 = zl + REG_LBA_16; // next most significan byte of LBA
+ padapter->regLba24 = zl + REG_LBA_24; // head and most 4 significant bits of LBA
+ padapter->regStatCmd = zl + REG_STAT_CMD; // status on read and command on write register
+ padapter->regStatSel = zl + REG_STAT_SEL; // board status on read and spigot select on write register
+ padapter->regFail = zl + REG_FAIL;
+ padapter->regAltStat = zl + REG_ALT_STAT;
+
+ if ( bigd )
+ {
+ padapter->regDmaDesc = zr + RTR_DMA0_DESC_PTR; // address of the DMA discriptor register for direction of transfer
+ padapter->regDmaCmdStat = zr + RTR_DMA_COMMAND_STATUS; // Byte #0 of DMA command status register
+ padapter->regDmaAddrPci = zr + RTR_DMA0_PCI_ADDR; // 32 bit register for PCI address of DMA
+ padapter->regDmaAddrLoc = zr + RTR_DMA0_LOCAL_ADDR; // 32 bit register for local bus address of DMA
+ padapter->regDmaCount = zr + RTR_DMA0_COUNT; // 32 bit register for DMA transfer count
+ padapter->regDmaMode = zr + RTR_DMA0_MODE + 1; // 32 bit register for DMA mode control
+ padapter->bigD = SEL_NEW_SPEED_1; // set spigot speed control bit
+ }
+ else
+ {
+ padapter->regDmaDesc = zl + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer
+ padapter->regDmaCmdStat = zl + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register
+ padapter->regDmaAddrPci = zl + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA
+ padapter->regDmaAddrLoc = zl + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA
+ padapter->regDmaCount = zl + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count
+ padapter->regDmaMode = zl + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control
+ }
+
+ padapter->numberOfDrives = inb_p (padapter->regScratchPad + BIGD_NUM_DRIVES);
+ if ( !bigd && !padapter->numberOfDrives ) // if no devices on this board
+ return TRUE;
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ pshost->irq = pcidev->irq;
+#else
+ pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
+#endif
+ setirq = 1;
+ for ( z = 0; z < Installed; z++ ) // scan for shared interrupts
+ {
+ if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
+ setirq = 0;
+ }
+ if ( setirq ) // if not shared, posses
+ {
+ if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 )
+ {
+ if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 )
+ {
+ printk ("Unable to allocate IRQ for PCI-2220I controller.\n");
+ return TRUE;
+ }
+ }
+ padapter->irqOwned = pshost->irq; // set IRQ as owned
+ }
+ if ( padapter->numberOfDrives )
+ padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC);
+ else
+ padapter->kBuffer = kmalloc (ATAPI_TRANSFER, GFP_DMA | GFP_ATOMIC);
+ if ( !padapter->kBuffer )
+ {
+ printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+ free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
+ free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
+ return TRUE;
+ }
+
+ PsiHost[Installed] = pshost; // save SCSI_HOST pointer
+
+ pshost->io_port = padapter->basePort;
+ pshost->n_io_port = 0xFF;
+ pshost->unique_id = padapter->regBase;
+
+ outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it
+
+ padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
+ if ( padapter->timingMode >= 2 )
+ {
+ if ( bigd )
+ padapter->timingAddress = ModeArray2[padapter->timingMode - 2];
+ else
+ padapter->timingAddress = ModeArray[padapter->timingMode - 2];
+ }
+ else
+ padapter->timingPIO = TRUE;
+
+ ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
+ ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
+
+ return FALSE;
+ }
+/****************************************************************
+ * Name: SetupFinish
+ *
+ * Description: Complete the driver initialization process for a card
+ *
+ * Parameters: padapter - Pointer to SCSI host data structure.
+ * str - Pointer to board type string.
+ *
+ * Returns: Nothing.
+ *
+ ****************************************************************/
+VOID SetupFinish (PADAPTER2220I padapter, char *str, int irq)
+ {
+ init_timer (&padapter->timer);
+ padapter->timer.function = TimerExpiry;
+ padapter->timer.data = (unsigned long)padapter;
+ init_timer (&padapter->reconTimer);
+ padapter->reconTimer.function = ReconTimerExpiry;
+ padapter->reconTimer.data = (unsigned long)padapter;
+ printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq);
+ printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
+ }
+/****************************************************************
* Name: Pci2220i_Detect
*
* Description: Detect and initialize our boards.
@@ -1722,204 +2600,284 @@ VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
****************************************************************/
int Pci2220i_Detect (Scsi_Host_Template *tpnt)
{
- int found = 0;
- int installed = 0;
struct Scsi_Host *pshost;
PADAPTER2220I padapter;
+ POUR_DEVICE pdev;
int unit;
int z;
- USHORT zs;
- USHORT raidon = FALSE;
- int setirq;
- UCHAR spigot1 = FALSE;
- UCHAR spigot2 = FALSE;
- struct pci_dev *pdev = NULL;
+ USHORT raidon;
+ UCHAR spigot1, spigot2;
+ UCHAR device;
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ struct pci_dev *pcidev = NULL;
+#else
+ int found;
+ UCHAR pci_bus, pci_device_fn;
+#endif
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
if ( !pci_present () )
+#else
+ if ( !pcibios_present () )
+#endif
{
printk ("pci2220i: PCI BIOS not present\n");
return 0;
}
- while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pdev)) != NULL )
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL )
+#else
+ found = 0;
+ while ( !pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, found++, &pci_bus, &pci_device_fn) )
+#endif
{
pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
padapter = HOSTDATA(pshost);
- memset (padapter, 0, sizeof (ADAPTER2220I));
-
- zs = pdev->resource[1].start;
- padapter->basePort = zs;
- padapter->regRemap = zs + RTR_LOCAL_REMAP; // 32 bit local space remap
- padapter->regDesc = zs + RTR_REGIONS; // 32 bit local region descriptor
- padapter->regRange = zs + RTR_LOCAL_RANGE; // 32 bit local range
- padapter->regIrqControl = zs + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status
- padapter->regScratchPad = zs + RTR_MAILBOX; // 16 byte scratchpad I/O base address
-
- zs = pdev->resource[2].start;
- padapter->regBase = zs;
- padapter->regData = zs + REG_DATA; // data register I/O address
- padapter->regError = zs + REG_ERROR; // error register I/O address
- padapter->regSectCount = zs + REG_SECTOR_COUNT; // sector count register I/O address
- padapter->regLba0 = zs + REG_LBA_0; // least significant byte of LBA
- padapter->regLba8 = zs + REG_LBA_8; // next least significant byte of LBA
- padapter->regLba16 = zs + REG_LBA_16; // next most significan byte of LBA
- padapter->regLba24 = zs + REG_LBA_24; // head and most 4 significant bits of LBA
- padapter->regStatCmd = zs + REG_STAT_CMD; // status on read and command on write register
- padapter->regStatSel = zs + REG_STAT_SEL; // board status on read and spigot select on write register
- padapter->regFail = zs + REG_FAIL;
- padapter->regAltStat = zs + REG_ALT_STAT;
-
- padapter->regDmaDesc = zs + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer
- padapter->regDmaCmdStat = zs + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register
- padapter->regDmaAddrPci = zs + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA
- padapter->regDmaAddrLoc = zs + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA
- padapter->regDmaCount = zs + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count
- padapter->regDmaMode = zs + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control
-
- if ( !inb_p (padapter->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board
- goto unregister;
- pshost->irq = pdev->irq;
- setirq = 1;
- for ( z = 0; z < installed; z++ ) // scan for shared interrupts
- {
- if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses
- setirq = 0;
- }
- if ( setirq ) // if not shared, posses
- {
- if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 )
- {
- if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 )
- {
- printk ("Unable to allocate IRQ for PCI-2220I controller.\n");
- goto unregister;
- }
- }
- padapter->irqOwned = pshost->irq; // set IRQ as owned
- }
- padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC);
- if ( !padapter->kBuffer )
- {
- printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
- free_irq (pshost->irq, padapter);
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ if ( GetRegs (pshost, FALSE, pcidev) )
+#else
+ if ( GetRegs (pshost, FALSE, pci_bus, pci_device_fn) )
+#endif
goto unregister;
- }
- PsiHost[installed] = pshost; // save SCSI_HOST pointer
-
- pshost->io_port = padapter->basePort;
- pshost->n_io_port = 0xFF;
- pshost->unique_id = padapter->regBase;
- pshost->max_id = 4;
-
- outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it
- padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
- if ( padapter->timingMode >= 2 )
- padapter->timingAddress = ModeArray[padapter->timingMode - 2];
- else
- padapter->timingPIO = TRUE;
-
- ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
- for ( z = 0; z < inb_p (padapter->regScratchPad + DALE_NUM_DRIVES); ++z )
+ pshost->max_id = padapter->numberOfDrives;
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
{
unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
- padapter->device[z].device = inb_p (padapter->regScratchPad + DALE_SCRATH_DEVICE_0 + unit);
- padapter->device[z].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
- padapter->device[z].spigot = (UCHAR)(1 << (unit >> 1));
- padapter->device[z].sectors = DaleSetup.setupDevice[unit].sectors;
- padapter->device[z].heads = DaleSetup.setupDevice[unit].heads;
- padapter->device[z].cylinders = DaleSetup.setupDevice[unit].cylinders;
- padapter->device[z].blocks = DaleSetup.setupDevice[unit].blocks;
+ pdev = &padapter->device[z];
+ pdev->byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+ pdev->spigot = (UCHAR)(1 << (unit >> 1));
+ pdev->sectors = DaleSetup.setupDevice[unit].sectors;
+ pdev->heads = DaleSetup.setupDevice[unit].heads;
+ pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+ pdev->blocks = DaleSetup.setupDevice[unit].blocks;
if ( !z )
{
- ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS);
DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS);
if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) &&
(DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) )
{
raidon = TRUE;
+ if ( unit > (unit ^ 2) )
+ unit = unit ^ 2;
}
+ else
+ raidon = FALSE;
- memcpy (padapter->device[z].DiskMirror, DiskMirror, sizeof (DiskMirror));
- padapter->raidData[0] = &padapter->device[z].DiskMirror[0];
- padapter->raidData[2] = &padapter->device[z].DiskMirror[1];
+ memcpy (pdev->DiskMirror, DiskMirror, sizeof (DiskMirror));
+ padapter->raidData[0] = &pdev->DiskMirror[0];
+ padapter->raidData[2] = &pdev->DiskMirror[1];
- if ( raidon )
- {
- padapter->device[z].lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
- padapter->device[z].lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
+ spigot1 = spigot2 = FALSE;
+ pdev->spigots[0] = 1;
+ pdev->spigots[1] = 2;
+ pdev->lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
+ pdev->lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
- if ( !(DiskMirror[1].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[0] )
- spigot1 = TRUE;
- if ( !(DiskMirror[0].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[1] )
- spigot2 = TRUE;
- if ( DiskMirror[0].status & UCBF_SURVIVOR & DiskMirror[1].status & UCBF_SURVIVOR )
- spigot1 = TRUE;
-
- if ( spigot1 && (DiskMirror[0].status & UCBF_REBUILD) )
- InlineReadSignature (padapter, &padapter->device[z], 0);
- if ( spigot2 && (DiskMirror[1].status & UCBF_REBUILD) )
- InlineReadSignature (padapter, &padapter->device[z], 1);
-
- if ( spigot1 && spigot2 )
+ if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+ spigot1 = TRUE;
+ if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+ spigot2 = TRUE;
+ if ( pdev->DiskMirror[0].status & DiskMirror[1].status & UCBF_SURVIVOR )
+ spigot1 = TRUE;
+
+ if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 0);
+ if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 1);
+
+ if ( spigot1 && spigot2 && raidon )
+ {
+ pdev->raid = 1;
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ pdev->spigot = 2;
+ else
+ pdev->spigot = 1;
+ if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ else
+ {
+ if ( spigot1 )
{
- padapter->device[z].raid = 1;
- if ( DiskMirror[0].status & UCBF_REBUILD )
- padapter->device[z].spigot = 2;
- else
- padapter->device[z].spigot = 1;
- if ( (DiskMirror[0].status & UCBF_REBUILD) || (DiskMirror[1].status & UCBF_REBUILD) )
- {
- padapter->reconOn = padapter->reconIsStarting = TRUE;
- }
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ goto unregister;
+ pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = 1;
}
else
{
- if ( spigot1 )
- {
- if ( DiskMirror[0].status & UCBF_REBUILD )
- goto unregister;
- DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
- padapter->device[z].spigot = 1;
- }
- else
+ if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+ goto unregister;
+ pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = 2;
+ }
+ if ( DaleSetup.rebootRebuild && raidon )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+
+ if ( raidon )
+ break;
+ }
+ }
+
+ SetupFinish (padapter, "2220", pshost->irq);
+
+ if ( ++Installed < MAXADAPTER )
+ continue;
+ break;;
+unregister:;
+ scsi_unregister (pshost);
+ }
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_BIGD_1, pcidev)) != NULL )
+#else
+ found = 0;
+ while ( !pcibios_find_device (VENDOR_PSI, DEVICE_BIGD_1, found++, &pci_bus, &pci_device_fn) )
+#endif
+ {
+ pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
+ padapter = HOSTDATA(pshost);
+
+#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
+ if ( GetRegs (pshost, TRUE, pcidev) )
+#else
+ if ( GetRegs (pshost, TRUE, pci_bus, pci_device_fn) )
+#endif
+ goto unregister1;
+
+ for ( z = 0; z < BIGD_MAXDRIVES; z++ )
+ DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z);
+
+ pshost->max_id = padapter->numberOfDrives;
+ padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE);
+ for ( z = 0; z < padapter->numberOfDrives; z++ )
+ {
+ unit = inb_p (padapter->regScratchPad + BIGD_DEVICE_0 + z);
+ pdev = &padapter->device[z];
+ pdev->byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+ pdev->spigot = (UCHAR)(1 << (unit >> 1));
+ pdev->sectors = DaleSetup.setupDevice[unit].sectors;
+ pdev->heads = DaleSetup.setupDevice[unit].heads;
+ pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+ pdev->blocks = DaleSetup.setupDevice[unit].blocks;
+
+ if ( (DiskMirror[unit].signature == SIGNATURE) && (DiskMirror[unit ^ 2].signature == SIGNATURE) &&
+ (DiskMirror[unit].pairIdentifier == (DiskMirror[unit ^ 2].pairIdentifier ^ 1)) )
+ {
+ raidon = TRUE;
+ if ( unit > (unit ^ 2) )
+ unit = unit ^ 2;
+ }
+ else
+ raidon = FALSE;
+
+ spigot1 = spigot2 = FALSE;
+ memcpy (&pdev->DiskMirror[0], &DiskMirror[unit], sizeof (DISK_MIRROR));
+ memcpy (&pdev->DiskMirror[1], &DiskMirror[unit ^ 2], sizeof (DISK_MIRROR));
+ padapter->raidData[unit] = &pdev->DiskMirror[0];
+ padapter->raidData[unit ^ 2] = &pdev->DiskMirror[1];
+ pdev->spigots[0] = 1 << (unit >> 1);
+ pdev->spigots[1] = 1 << ((unit ^ 2) >> 1);
+ pdev->deviceID[0] = unit;
+ pdev->deviceID[1] = unit ^ 2;
+ pdev->lastsectorlba[0] = InlineIdentify (padapter, pdev->spigots[0], unit & 1);
+ pdev->lastsectorlba[1] = InlineIdentify (padapter, pdev->spigots[1], unit & 1);
+
+ if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+ spigot1 = TRUE;
+ if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+ spigot2 = TRUE;
+ if ( pdev->DiskMirror[0].status & pdev->DiskMirror[1].status & UCBF_SURVIVOR )
+ spigot1 = TRUE;
+
+ if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 0);
+ if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ InlineReadSignature (padapter, pdev, 1);
+
+ if ( spigot1 && spigot2 && raidon )
+ {
+ pdev->raid = 1;
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ pdev->spigot = pdev->spigots[1];
+ else
+ pdev->spigot = pdev->spigots[0];
+ if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ else
+ {
+ if ( spigot1 )
+ {
+ if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+ goto unregister1;
+ pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = pdev->spigots[0];
+ }
+ else
+ {
+ if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+ goto unregister;
+ pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+ pdev->spigot = pdev->spigots[1];
+ }
+ if ( DaleSetup.rebootRebuild && raidon )
+ padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+ }
+ }
+
+ if ( !padapter->numberOfDrives ) // If no ATA devices then scan ATAPI
+ {
+ unit = 0;
+ for ( spigot1 = 0; spigot1 < 4; spigot1++ )
+ {
+ for ( device = 0; device < 2; device++ )
+ {
+ DEB (printk ("\nPCI2242I: scanning for ID %d ", (spigot1 * 2) + device));
+ pdev = &(padapter->device[(spigot1 * 2) + device]);
+ pdev->byte6 = 0x0A | (device << 4);
+ pdev->spigot = 1 << spigot1;
+ if ( !AtapiReset (padapter, pdev) )
+ {
+ DEB (printk (" Device found "));
+ if ( !AtapiIdentify (padapter, pdev) )
{
- if ( DiskMirror[1].status & UCBF_REBUILD )
- goto unregister;
- DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
- padapter->device[z].spigot = 2;
+ DEB (printk (" Device verified"));
+ unit++;
+ continue;
}
- if ( DaleSetup.rebootRebuil )
- padapter->reconOn = padapter->reconIsStarting = TRUE;
}
-
- break;
+ pdev->spigot = pdev->byte6 = 0;
}
}
+
+ if ( unit )
+ {
+ padapter->atapi = TRUE;
+ padapter->timingAddress = DALE_DATA_MODE3;
+ outw_p (0x0900, padapter->regIrqControl); // Turn our interrupts on
+ outw_p (0x0C41, padapter->regDmaMode - 1); // setup for 16 bits, ready enabled, done IRQ enabled, no incriment
+ outb_p (0xFF, padapter->regFail); // all fail lights and alarm off
+ pshost->max_id = 8;
+ }
}
-
- init_timer (&padapter->timer);
- padapter->timer.function = TimerExpiry;
- padapter->timer.data = (unsigned long)padapter;
- init_timer (&padapter->reconTimer);
- padapter->reconTimer.function = ReconTimerExpiry;
- padapter->reconTimer.data = (unsigned long)padapter;
- printk("\nPCI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", padapter->basePort, padapter->regBase, pshost->irq);
- printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
- found++;
- if ( ++installed < MAXADAPTER )
+ SetupFinish (padapter, "2240", pshost->irq);
+
+ if ( ++Installed < MAXADAPTER )
continue;
break;;
-unregister:;
+unregister1:;
scsi_unregister (pshost);
- found++;
}
-
- NumAdapters = installed;
- return installed;
+
+ NumAdapters = Installed;
+ return Installed;
}
/****************************************************************
* Name: Pci2220i_Abort
@@ -1933,6 +2891,19 @@ unregister:;
****************************************************************/
int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
{
+ PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
+ POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information
+
+ if ( !padapter->SCpnt )
+ return SCSI_ABORT_NOT_RUNNING;
+
+ if ( padapter->atapi )
+ {
+ if ( AtapiReset (padapter, pdev) )
+ return SCSI_ABORT_ERROR;
+ OpDone (padapter, DID_ABORT << 16);
+ return SCSI_ABORT_SUCCESS;
+ }
return SCSI_ABORT_SNOOZE;
}
/****************************************************************
@@ -1952,6 +2923,15 @@ int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
****************************************************************/
int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
{
+ PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure
+ POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information
+
+ if ( padapter->atapi )
+ {
+ if ( AtapiReset (padapter, pdev) )
+ return SCSI_RESET_ERROR;
+ return SCSI_RESET_SUCCESS;
+ }
return SCSI_RESET_PUNT;
}
/****************************************************************
@@ -1967,6 +2947,7 @@ int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
int Pci2220i_Release (struct Scsi_Host *pshost)
{
PADAPTER2220I padapter = HOSTDATA (pshost);
+ USHORT z;
if ( padapter->reconOn )
{
@@ -1981,11 +2962,29 @@ int Pci2220i_Release (struct Scsi_Host *pshost)
}
// save RAID status on the board
- outb_p (DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS);
- outb_p (DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS);
+ if ( padapter->bigD )
+ {
+ outb_p (padapter->failRegister, padapter->regScratchPad + BIGD_ALARM_IMAGE);
+ for ( z = 0; z < BIGD_MAXDRIVES; z++ )
+ {
+ if ( padapter->raidData )
+ outb_p (padapter->raidData[z]->status, padapter->regScratchPad + BIGD_RAID_0_STATUS + z);
+ else
+ outb_p (0, padapter->regScratchPad + BIGD_RAID_0_STATUS);
+ }
+ }
+ else
+ {
+ outb_p (padapter->device[0].DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS);
+ outb_p (padapter->device[0].DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS);
+ }
if ( padapter->irqOwned )
+#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70)
+ free_irq (pshost->irq);
+#else /* version >= v1.3.70 */
free_irq (pshost->irq, padapter);
+#endif /* version >= v1.3.70 */
release_region (pshost->io_port, pshost->n_io_port);
kfree (padapter->kBuffer);
scsi_unregister(pshost);
@@ -2011,11 +3010,14 @@ int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
{
POUR_DEVICE pdev;
- pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
+ if ( !(HOSTDATA(disk->device->host))->atapi )
+ {
+ pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
- geom[0] = pdev->heads;
- geom[1] = pdev->sectors;
- geom[2] = pdev->cylinders;
+ geom[0] = pdev->heads;
+ geom[1] = pdev->sectors;
+ geom[2] = pdev->cylinders;
+ }
return 0;
}
diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h
index 1c75c8c3b..aaa8457fc 100644
--- a/drivers/scsi/pci2220i.h
+++ b/drivers/scsi/pci2220i.h
@@ -21,265 +21,11 @@
#ifndef _PCI2220I_H
#define _PCI2220I_H
-#ifndef PSI_EIDE_SCSIOP
-#define PSI_EIDE_SCSIOP 1
-
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#endif
#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s))
-/************************************************/
-/* Some defines that we like */
-/************************************************/
-#define CHAR char
-#define UCHAR unsigned char
-#define SHORT short
-#define USHORT unsigned short
-#define BOOL unsigned short
-#define LONG long
-#define ULONG unsigned long
-#define VOID void
-
-#include "psi_dale.h"
-
-/************************************************/
-/* Timeout konstants */
-/************************************************/
-#define TIMEOUT_READY 100 // 100 mSec
-#define TIMEOUT_DRQ 300 // 300 mSec
-#define TIMEOUT_DATA (3 * HZ) // 3 seconds
-
-/************************************************/
-/* Misc. macros */
-/************************************************/
-#define ANY2SCSI(up, p) \
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up) \
-( (((long)*(((UCHAR *)up))) << 16) \
-+ (((long)(((UCHAR *)up)[1])) << 8) \
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p) \
-((UCHAR *)up)[0] = ((long)(p)) >> 24; \
-((UCHAR *)up)[1] = ((long)(p)) >> 16; \
-((UCHAR *)up)[2] = ((long)(p)) >> 8; \
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up) \
-( (((long)(((UCHAR *)up)[0])) << 24) \
-+ (((long)(((UCHAR *)up)[1])) << 16) \
-+ (((long)(((UCHAR *)up)[2])) << 8) \
-+ ((long)(((UCHAR *)up)[3])) )
-
-#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel)
-#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd)
-
-/************************************************/
-/* SCSI CDB operation codes */
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY 0x00
-#define SCSIOP_REZERO_UNIT 0x01
-#define SCSIOP_REWIND 0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
-#define SCSIOP_REQUEST_SENSE 0x03
-#define SCSIOP_FORMAT_UNIT 0x04
-#define SCSIOP_READ_BLOCK_LIMITS 0x05
-#define SCSIOP_REASSIGN_BLOCKS 0x07
-#define SCSIOP_READ6 0x08
-#define SCSIOP_RECEIVE 0x08
-#define SCSIOP_WRITE6 0x0A
-#define SCSIOP_PRINT 0x0A
-#define SCSIOP_SEND 0x0A
-#define SCSIOP_SEEK6 0x0B
-#define SCSIOP_TRACK_SELECT 0x0B
-#define SCSIOP_SLEW_PRINT 0x0B
-#define SCSIOP_SEEK_BLOCK 0x0C
-#define SCSIOP_PARTITION 0x0D
-#define SCSIOP_READ_REVERSE 0x0F
-#define SCSIOP_WRITE_FILEMARKS 0x10
-#define SCSIOP_FLUSH_BUFFER 0x10
-#define SCSIOP_SPACE 0x11
-#define SCSIOP_INQUIRY 0x12
-#define SCSIOP_VERIFY6 0x13
-#define SCSIOP_RECOVER_BUF_DATA 0x14
-#define SCSIOP_MODE_SELECT 0x15
-#define SCSIOP_RESERVE_UNIT 0x16
-#define SCSIOP_RELEASE_UNIT 0x17
-#define SCSIOP_COPY 0x18
-#define SCSIOP_ERASE 0x19
-#define SCSIOP_MODE_SENSE 0x1A
-#define SCSIOP_START_STOP_UNIT 0x1B
-#define SCSIOP_STOP_PRINT 0x1B
-#define SCSIOP_LOAD_UNLOAD 0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
-#define SCSIOP_SEND_DIAGNOSTIC 0x1D
-#define SCSIOP_MEDIUM_REMOVAL 0x1E
-#define SCSIOP_READ_CAPACITY 0x25
-#define SCSIOP_READ 0x28
-#define SCSIOP_WRITE 0x2A
-#define SCSIOP_SEEK 0x2B
-#define SCSIOP_LOCATE 0x2B
-#define SCSIOP_WRITE_VERIFY 0x2E
-#define SCSIOP_VERIFY 0x2F
-#define SCSIOP_SEARCH_DATA_HIGH 0x30
-#define SCSIOP_SEARCH_DATA_EQUAL 0x31
-#define SCSIOP_SEARCH_DATA_LOW 0x32
-#define SCSIOP_SET_LIMITS 0x33
-#define SCSIOP_READ_POSITION 0x34
-#define SCSIOP_SYNCHRONIZE_CACHE 0x35
-#define SCSIOP_COMPARE 0x39
-#define SCSIOP_COPY_COMPARE 0x3A
-#define SCSIOP_WRITE_DATA_BUFF 0x3B
-#define SCSIOP_READ_DATA_BUFF 0x3C
-#define SCSIOP_CHANGE_DEFINITION 0x40
-#define SCSIOP_READ_SUB_CHANNEL 0x42
-#define SCSIOP_READ_TOC 0x43
-#define SCSIOP_READ_HEADER 0x44
-#define SCSIOP_PLAY_AUDIO 0x45
-#define SCSIOP_PLAY_AUDIO_MSF 0x47
-#define SCSIOP_PLAY_TRACK_INDEX 0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
-#define SCSIOP_PAUSE_RESUME 0x4B
-#define SCSIOP_LOG_SELECT 0x4C
-#define SCSIOP_LOG_SENSE 0x4D
-#define SCSIOP_MODE_SELECT10 0x55
-#define SCSIOP_MODE_SENSE10 0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6
-#define SCSIOP_MECHANISM_STATUS 0xBD
-#define SCSIOP_READ_CD 0xBE
-
-// IDE command definitions
-#define IDE_COMMAND_ATAPI_RESET 0x08
-#define IDE_COMMAND_READ 0x20
-#define IDE_COMMAND_WRITE 0x30
-#define IDE_COMMAND_RECALIBRATE 0x10
-#define IDE_COMMAND_SEEK 0x70
-#define IDE_COMMAND_SET_PARAMETERS 0x91
-#define IDE_COMMAND_VERIFY 0x40
-#define IDE_COMMAND_ATAPI_PACKET 0xA0
-#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
-#define IDE_CMD_READ_MULTIPLE 0xC4
-#define IDE_CMD_WRITE_MULTIPLE 0xC5
-#define IDE_CMD_SET_MULTIPLE 0xC6
-#define IDE_COMMAND_IDENTIFY 0xEC
-
-// IDE status definitions
-#define IDE_STATUS_ERROR 0x01
-#define IDE_STATUS_INDEX 0x02
-#define IDE_STATUS_CORRECTED_ERROR 0x04
-#define IDE_STATUS_DRQ 0x08
-#define IDE_STATUS_DSC 0x10
-#define IDE_STATUS_WRITE_FAULT 0x20
-#define IDE_STATUS_DRDY 0x40
-#define IDE_STATUS_BUSY 0x80
-
-// IDE error definitions
-#define IDE_ERROR_AMNF 0x01
-#define IDE_ERROR_TKONF 0x02
-#define IDE_ERROR_ABRT 0x04
-#define IDE_ERROR_MCR 0x08
-#define IDE_ERROR_IDFN 0x10
-#define IDE_ERROR_MC 0x20
-#define IDE_ERROR_UNC 0x40
-#define IDE_ERROR_BBK 0x80
-
-// SCSI read capacity structure
-typedef struct _READ_CAPACITY_DATA
- {
- ULONG blks; /* total blocks (converted to little endian) */
- ULONG blksiz; /* size of each (converted to little endian) */
- } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-typedef struct _INQUIRYDATA
- {
- UCHAR DeviceType :5;
- UCHAR DeviceTypeQualifier :3;
- UCHAR DeviceTypeModifier :7;
- UCHAR RemovableMedia :1;
- UCHAR Versions;
- UCHAR ResponseDataFormat;
- UCHAR AdditionalLength;
- UCHAR Reserved[2];
- UCHAR SoftReset :1;
- UCHAR CommandQueue :1;
- UCHAR Reserved2 :1;
- UCHAR LinkedCommands :1;
- UCHAR Synchronous :1;
- UCHAR Wide16Bit :1;
- UCHAR Wide32Bit :1;
- UCHAR RelativeAddressing :1;
- UCHAR VendorId[8];
- UCHAR ProductId[16];
- UCHAR ProductRevisionLevel[4];
- UCHAR VendorSpecific[20];
- UCHAR Reserved3[40];
- } INQUIRYDATA, *PINQUIRYDATA;
-
-// IDE IDENTIFY data
-#pragma pack (1)
-#pragma align 1
-typedef struct _IDENTIFY_DATA
- {
- USHORT GeneralConfiguration; // 0
- USHORT NumberOfCylinders; // 1
- USHORT Reserved1; // 2
- USHORT NumberOfHeads; // 3
- USHORT UnformattedBytesPerTrack; // 4
- USHORT UnformattedBytesPerSector; // 5
- USHORT SectorsPerTrack; // 6
- USHORT NumBytesISG; // 7 Byte Len - inter-sector gap
- USHORT NumBytesSync; // 8 - sync field
- USHORT NumWordsVUS; // 9 Len - Vendor Unique Info
- USHORT SerialNumber[10]; // 10
- USHORT BufferType; // 20
- USHORT BufferSectorSize; // 21
- USHORT NumberOfEccBytes; // 22
- USHORT FirmwareRevision[4]; // 23
- USHORT ModelNumber[20]; // 27
- USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk
- USHORT Reserved2 :8; // 47
- USHORT DoubleWordMode; // 48 flag for double word mode capable
- USHORT VendorUnique1 :8; // 49
- USHORT SupportDMA :1; // 49 DMA supported
- USHORT SupportLBA :1; // 49 LBA supported
- USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled
- USHORT SupportIORDY :1; // 49 IORDY supported
- USHORT ReservedPseudoDMA :1; // 49 reserved for pseudo DMA mode support
- USHORT Reserved3 :3; // 49
- USHORT Reserved4; // 50
- USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO
- USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO
- USHORT Reserved6 :8; // 52 - DMA
- USHORT DMACycleTime :8; // 52 - DMA
- USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild
- USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid
- USHORT Reserved7 :14; // 53
- USHORT LogNumCyl; // 54 Current Translation - Num Cyl
- USHORT LogNumHeads; // 55 Num Heads
- USHORT LogSectorsPerTrack; // 56 Sec/Trk
- ULONG LogTotalSectors; // 57 Total Sec
- USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt
- USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt
- USHORT Reserved8 :7; // 59
- ULONG LBATotalSectors; // 60 LBA Mode - Sectors
- USHORT DMASWordFlags; // 62
- USHORT DMAMWordFlags; // 63
- USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported
- USHORT Reserved9 :8; // 64
- USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word
- USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time
- USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control
- USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control
- USHORT ReservedSpace[256-69]; // 69
- } IDENTIFY_DATA, *PIDENTIFY_DATA;
-#pragma pack ()
-#pragma align 0
-#endif // PSI_EIDE_SCSIOP
-
// function prototypes
int Pci2220i_Detect (Scsi_Host_Template *tpnt);
int Pci2220i_Command (Scsi_Cmnd *SCpnt);
@@ -293,12 +39,15 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
#define NULL 0
#endif
+extern struct proc_dir_entry Proc_Scsi_Pci2220i;
+
+#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
#define PCI2220I { \
next: NULL, \
module: NULL, \
- proc_name: "pci2220i", \
+ proc_dir: &Proc_Scsi_Pci2220i, \
proc_info: NULL, /* let's not bloat the kernel */\
- name: "PCI-2220I EIDE Disk Controller", \
+ name: "PCI-2220I/PCI-2240I", \
detect: Pci2220i_Detect, \
release: Pci2220i_Release, \
info: NULL, /* let's not bloat the kernel */\
@@ -315,11 +64,34 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
bios_param: Pci2220i_BiosParam, \
can_queue: 1, \
this_id: -1, \
- sg_tablesize: SG_NONE, \
+ sg_tablesize: SG_ALL, \
cmd_per_lun: 1, \
present: 0, \
unchecked_isa_dma: 0, \
use_clustering: DISABLE_CLUSTERING, \
use_new_eh_code: 0 \
}
+#else
+#define PCI2220I { NULL, NULL, \
+ &Proc_Scsi_Pci2220i,/* proc_dir_entry */\
+ NULL, \
+ "PCI-2220I/PCI-2240I", \
+ Pci2220i_Detect, \
+ Pci2220i_Release, \
+ NULL, \
+ Pci2220i_Command, \
+ Pci2220i_QueueCommand, \
+ Pci2220i_Abort, \
+ Pci2220i_Reset, \
+ NULL, \
+ Pci2220i_BiosParam, \
+ 1, \
+ -1, \
+ SG_ALL, \
+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING }
+#endif
+
#endif
diff --git a/drivers/scsi/pcmcia/.cvsignore b/drivers/scsi/pcmcia/.cvsignore
new file mode 100644
index 000000000..f7cf9ab27
--- /dev/null
+++ b/drivers/scsi/pcmcia/.cvsignore
@@ -0,0 +1,10 @@
+! RCS SCCS CVS CVS.adm
+RCSLOG cvslog.*
+tags TAGS
+.make.state .nse_depinfo
+*~ #* .#* ,* _$* *$
+*.old *.bak *.BAK *.orig *.rej .del-*
+*.a *.olb *.o *.obj *.so *.exe
+*.Z *.elc *.ln
+.depend
+.*.flags
diff --git a/drivers/scsi/pcmcia/Config.in b/drivers/scsi/pcmcia/Config.in
new file mode 100644
index 000000000..5416bdef2
--- /dev/null
+++ b/drivers/scsi/pcmcia/Config.in
@@ -0,0 +1,23 @@
+#
+# PCMCIA SCSI adapter configuration
+#
+
+mainmenu_option next_comment
+comment 'PCMCIA SCSI adapter support'
+
+bool 'PCMCIA SCSI adapter support' CONFIG_SCSI_PCMCIA
+if [ "$CONFIG_SCSI_PCMCIA" = "y" ]; then
+ dep_tristate ' Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m
+ dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m
+ dep_tristate ' Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m
+ if [ "$CONFIG_CARDBUS" = "y" ]; then
+ dep_tristate ' Adaptec APA1480 CardBus support' CONFIG_PCMCIA_APA1480 m
+ fi
+fi
+
+if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \
+ "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_APA1480" = "y" ]; then
+ define_bool CONFIG_PCMCIA_SCSICARD y
+fi
+
+endmenu
diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile
new file mode 100644
index 000000000..d37c6fc5f
--- /dev/null
+++ b/drivers/scsi/pcmcia/Makefile
@@ -0,0 +1,67 @@
+#
+# drivers/scsi/pcmcia/Makefile
+#
+# Makefile for the Linux PCMCIA SCSI drivers.
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+MOD_LIST_NAME := PCMCIA_SCSI_MODULES
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+vpath %c ..
+
+CFLAGS_aha152x.o = -DPCMCIA -D__NO_VERSION__ -DAHA152X_STAT
+CFLAGS_aic7xxx.o = -DPCMCIA -D__NO_VERSION__
+CFLAGS_fdomain.o = -DPCMCIA -D__NO_VERSION__
+CFLAGS_qlogicfas.o = -DPCMCIA -D__NO_VERSION__
+
+# 16-bit client drivers
+obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o
+obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o
+obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o
+
+# Cardbus client drivers
+obj-$(CONFIG_PCMCIA_APA1480) += apa1480_cb.o
+
+list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o apa1480_cb.o
+aha152x-objs := aha152x_stub.o aha152x.o
+apa1480-objs := apa1480_stub.o aic7xxx.o
+fdomain-objs := fdomain_stub.o fdomain.o
+qlogic-objs := qlogic_stub.o qlogicfas.o
+
+# Extract lists of the multi-part drivers.
+
+multi-y := $(filter $(list-multi), $(obj-y))
+multi-m := $(filter $(list-multi), $(obj-m))
+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
+M_OBJS := $(filter-out $(export-objs), $(obj-m))
+MX_OBJS := $(filter $(export-objs), $(obj-m))
+MI_OBJS := $(filter-out $(export-objs), $(int-m))
+MIX_OBJS := $(filter $(export-objs), $(int-m))
+
+include $(TOPDIR)/Rules.make
+
+aha152x_cs.o: $(aha152x-objs)
+ $(LD) -r -o $@ $(aha152x-objs)
+
+apa1480_cb.o: $(apa1480-objs)
+ $(LD) -r -o $@ $(apa1480-objs)
+
+fdomain_cs.o: $(fdomain-objs)
+ $(LD) -r -o $@ $(fdomain-objs)
+
+qlogic_cs.o: $(qlogic-objs)
+ $(LD) -r -o $@ $(qlogic-objs)
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
new file mode 100644
index 000000000..7450470a1
--- /dev/null
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -0,0 +1,437 @@
+/*======================================================================
+
+ A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards.
+
+ This driver supports the Adaptec AHA-1460, the New Media Bus
+ Toaster, and the New Media Toast & Jam.
+
+ aha152x_cs.c 1.52 2000/01/11 01:04:31
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/aha152x.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"aha152x_cs.c 1.52 2000/01/11 01:04:31 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* SCSI bus setup options */
+static int host_id = 7;
+static int reconnect = 1;
+static int parity = 1;
+static int synchronous = 0;
+static int reset_delay = 100;
+static int ext_trans = 0;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(host_id, "i");
+MODULE_PARM(reconnect, "i");
+MODULE_PARM(parity, "i");
+MODULE_PARM(synchronous, "i");
+MODULE_PARM(reset_delay, "i");
+MODULE_PARM(ext_trans, "i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+ dev_link_t link;
+ struct Scsi_Host *host;
+ int ndev;
+ dev_node_t node[8];
+} scsi_info_t;
+
+extern void aha152x_setup(char *str, int *ints);
+
+static void aha152x_release_cs(u_long arg);
+static int aha152x_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_link_t *aha152x_attach(void);
+static void aha152x_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = AHA152X;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "aha152x_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *aha152x_attach(void)
+{
+ scsi_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "aha152x_attach()\n");
+
+ /* Create new SCSI device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+ link->release.function = &aha152x_release_cs;
+ link->release.data = (u_long)link;
+
+ link->io.NumPorts1 = 0x20;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 10;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &aha152x_event;
+ client_reg.EventMask =
+ CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ aha152x_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* aha152x_attach */
+
+/*====================================================================*/
+
+static void aha152x_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DEBUG(0, "aha152x_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG) {
+ aha152x_release_cs((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ kfree(link->priv);
+
+} /* aha152x_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void aha152x_config_cs(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ scsi_info_t *info = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int i, last_ret, last_fn, ints[8];
+ u_char tuple_data[64];
+ Scsi_Device *dev;
+ dev_node_t *node, **tail;
+ struct Scsi_Host *host;
+
+ DEBUG(0, "aha152x_config(0x%p)\n", link);
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.TupleData = tuple_data;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ CS_CHECK(GetTupleData, handle, &tuple);
+ CS_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigBase = parse.config.base;
+
+ /* Configure card */
+ driver_template.module = &__this_module;
+ link->state |= DEV_CONFIG;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ while (1) {
+ CFG_CHECK(GetTupleData, handle, &tuple);
+ CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+ /* For New Media T&J, look for a SCSI window */
+ if (parse.cftable_entry.io.win[0].len >= 0x20)
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ else if ((parse.cftable_entry.io.nwin > 1) &&
+ (parse.cftable_entry.io.win[1].len >= 0x20))
+ link->io.BasePort1 = parse.cftable_entry.io.win[1].base;
+ if ((parse.cftable_entry.io.nwin > 0) &&
+ (link->io.BasePort1 < 0xffff)) {
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+ i = CardServices(RequestIO, handle, &link->io);
+ if (i == CS_SUCCESS) break;
+ }
+ next_entry:
+ CS_CHECK(GetNextTuple, handle, &tuple);
+ }
+
+ CS_CHECK(RequestIRQ, handle, &link->irq);
+ CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+ /* A bad hack... */
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+
+ /* Set configuration options for the aha152x driver */
+ ints[0] = 7;
+ ints[1] = link->io.BasePort1;
+ ints[2] = link->irq.AssignedIRQ;
+ ints[3] = host_id;
+ ints[4] = reconnect;
+ ints[5] = parity;
+ ints[6] = synchronous;
+ ints[7] = reset_delay;
+ if (ext_trans) {
+ ints[8] = ext_trans; ints[0] = 8;
+ }
+ aha152x_setup("PCMCIA setup", ints);
+
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ tail = &link->dev;
+ info->ndev = 0;
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node = &info->node[info->ndev];
+ node->minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node->major = SCSI_TAPE_MAJOR;
+ sprintf(node->dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node->major = SCSI_DISK0_MAJOR;
+ sprintf(node->dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node->major = SCSI_CDROM_MAJOR;
+ sprintf(node->dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node->major = SCSI_GENERIC_MAJOR;
+ sprintf(node->dev_name, "sg#%04lx", id);
+ break;
+ }
+ *tail = node; tail = &node->next;
+ info->ndev++;
+ info->host = dev->host;
+ }
+ *tail = NULL;
+ if (info->ndev == 0)
+ printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ aha152x_release_cs((u_long)link);
+ return;
+
+} /* aha152x_config_cs */
+
+/*====================================================================*/
+
+static void aha152x_release_cs(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ DEBUG(0, "aha152x_release_cs(0x%p)\n", link);
+
+ if (GET_USE_COUNT(driver_template.module) != 0) {
+ DEBUG(1, "aha152x_cs: release postponed, "
+ "device still open\n");
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ link->dev = NULL;
+
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+ if (link->state & DEV_STALE_LINK)
+ aha152x_detach(link);
+
+} /* aha152x_release_cs */
+
+/*====================================================================*/
+
+static int aha152x_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+ scsi_info_t *info = link->priv;
+
+ DEBUG(0, "aha152x_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + HZ/20;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ aha152x_config_cs(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ Scsi_Cmnd tmp;
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ tmp.host = info->host;
+ aha152x_host_reset(&tmp);
+ }
+ break;
+ }
+ return 0;
+} /* aha152x_event */
+
+/*====================================================================*/
+
+static int __init init_aha152x_cs(void) {
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "aha152x_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &aha152x_attach, &aha152x_detach);
+ return 0;
+}
+
+static void __exit exit_aha152x_cs(void) {
+ DEBUG(0, "aha152x_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ aha152x_detach(dev_list);
+}
+
+module_init(init_aha152x_cs);
+module_exit(exit_aha152x_cs);
+
diff --git a/drivers/scsi/pcmcia/apa1480_stub.c b/drivers/scsi/pcmcia/apa1480_stub.c
new file mode 100644
index 000000000..a6419f194
--- /dev/null
+++ b/drivers/scsi/pcmcia/apa1480_stub.c
@@ -0,0 +1,174 @@
+/*======================================================================
+
+ A driver for the Adaptec APA1480 CardBus SCSI Host Adapter
+
+ apa1480_cb.c 1.19 2000/02/14 22:39:25
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/aic7xxx.h>
+
+#include <pcmcia/driver_ops.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"apa1480_cb.c 1.19 2000/02/14 22:39:25 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int reset = 1;
+static int ultra = 0;
+
+MODULE_PARM(reset, "i");
+MODULE_PARM(ultra, "i");
+
+/*====================================================================*/
+
+static Scsi_Host_Template driver_template = AIC7XXX;
+
+extern void aic7xxx_setup(char *, int *);
+
+static dev_node_t *apa1480_attach(dev_locator_t *loc);
+static void apa1480_detach(dev_node_t *node);
+
+struct driver_operations apa1480_ops = {
+ "apa1480_cb", apa1480_attach, NULL, NULL, apa1480_detach
+};
+
+/*====================================================================*/
+
+static dev_node_t *apa1480_attach(dev_locator_t *loc)
+{
+ u_char bus, devfn;
+ Scsi_Device *dev;
+ dev_node_t *node;
+ char s[60];
+ int n = 0;
+ struct Scsi_Host *host;
+
+ if (loc->bus != LOC_PCI) return NULL;
+ bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+ printk(KERN_INFO "apa1480_attach(bus %d, function %d)\n",
+ bus, devfn);
+
+ driver_template.module = &__this_module;
+
+ sprintf(s, "no_probe:1,no_reset:%d,ultra:%d",
+ (reset==0), (ultra!=0));
+ aic7xxx_setup(s, NULL);
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ node = kmalloc(7 * sizeof(dev_node_t), GFP_KERNEL);
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node[n].minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node[n].major = SCSI_TAPE_MAJOR;
+ sprintf(node[n].dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node[n].major = SCSI_DISK0_MAJOR;
+ sprintf(node[n].dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node[n].major = SCSI_CDROM_MAJOR;
+ sprintf(node[n].dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node[n].major = SCSI_GENERIC_MAJOR;
+ sprintf(node[n].dev_name, "sg#%04lx", id);
+ break;
+ }
+ if (n) node[n-1].next = &node[n];
+ n++;
+ }
+ if (n == 0) {
+ printk(KERN_INFO "apa1480_cs: no SCSI devices found\n");
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ kfree(node);
+ return NULL;
+ } else
+ node[n-1].next = NULL;
+
+ MOD_INC_USE_COUNT;
+ return node;
+}
+
+static void apa1480_detach(dev_node_t *node)
+{
+ MOD_DEC_USE_COUNT;
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ kfree(node);
+}
+
+/*====================================================================*/
+
+static int __init init_apa1480_cb(void) {
+ DEBUG(0, "%s\n", version);
+ register_driver(&apa1480_ops);
+ return 0;
+}
+
+static void __exit exit_apa1480_cb(void) {
+ DEBUG(0, "apa1480_cs: unloading\n");
+ unregister_driver(&apa1480_ops);
+}
+
+module_init(init_apa1480_cb);
+module_exit(exit_apa1480_cb);
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
new file mode 100644
index 000000000..558bf3317
--- /dev/null
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -0,0 +1,398 @@
+/*======================================================================
+
+ A driver for Future Domain-compatible PCMCIA SCSI cards
+
+ fdomain_cs.c 1.41 1999/11/15 06:05:48
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/fdomain.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"fdomain_cs.c 1.41 1999/11/15 06:05:48 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+ dev_link_t link;
+ int ndev;
+ dev_node_t node[8];
+} scsi_info_t;
+
+extern void fdomain_setup(char *str, int *ints);
+
+static void fdomain_release(u_long arg);
+static int fdomain_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_link_t *fdomain_attach(void);
+static void fdomain_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = FDOMAIN_16X0;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "fdomain_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *fdomain_attach(void)
+{
+ scsi_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "fdomain_attach()\n");
+
+ /* Create new SCSI device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+ link->release.function = &fdomain_release;
+ link->release.data = (u_long)link;
+
+ link->io.NumPorts1 = 0x10;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 10;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &fdomain_event;
+ client_reg.EventMask =
+ CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ fdomain_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* fdomain_attach */
+
+/*====================================================================*/
+
+static void fdomain_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DEBUG(0, "fdomain_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG) {
+ fdomain_release((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ kfree(link->priv);
+
+} /* fdomain_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void fdomain_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ scsi_info_t *info = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int i, last_ret, last_fn, ints[3];
+ u_char tuple_data[64];
+ Scsi_Device *dev;
+ dev_node_t *node, **tail;
+ struct Scsi_Host *host;
+
+ DEBUG(0, "fdomain_config(0x%p)\n", link);
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.TupleData = tuple_data;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ CS_CHECK(GetTupleData, handle, &tuple);
+ CS_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigBase = parse.config.base;
+
+ /* Configure card */
+ driver_template.module = &__this_module;
+ link->state |= DEV_CONFIG;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ while (1) {
+ CFG_CHECK(GetTupleData, handle, &tuple);
+ CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ i = CardServices(RequestIO, handle, &link->io);
+ if (i == CS_SUCCESS) break;
+ next_entry:
+ CS_CHECK(GetNextTuple, handle, &tuple);
+ }
+
+ CS_CHECK(RequestIRQ, handle, &link->irq);
+ CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+ /* A bad hack... */
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+
+ /* Set configuration options for the fdomain driver */
+ ints[0] = 2;
+ ints[1] = link->io.BasePort1;
+ ints[2] = link->irq.AssignedIRQ;
+ fdomain_setup("PCMCIA setup", ints);
+
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ tail = &link->dev;
+ info->ndev = 0;
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node = &info->node[info->ndev];
+ node->minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node->major = SCSI_TAPE_MAJOR;
+ sprintf(node->dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node->major = SCSI_DISK0_MAJOR;
+ sprintf(node->dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node->major = SCSI_CDROM_MAJOR;
+ sprintf(node->dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node->major = SCSI_GENERIC_MAJOR;
+ sprintf(node->dev_name, "sg#%04lx", id);
+ break;
+ }
+ *tail = node; tail = &node->next;
+ info->ndev++;
+ }
+ *tail = NULL;
+ if (info->ndev == 0)
+ printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ fdomain_release((u_long)link);
+ return;
+
+} /* fdomain_config */
+
+/*====================================================================*/
+
+static void fdomain_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ DEBUG(0, "fdomain_release(0x%p)\n", link);
+
+ if (GET_USE_COUNT(&__this_module) != 0) {
+ DEBUG(1, "fdomain_cs: release postponed, "
+ "device still open\n");
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ link->dev = NULL;
+
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+ if (link->state & DEV_STALE_LINK)
+ fdomain_detach(link);
+
+} /* fdomain_release */
+
+/*====================================================================*/
+
+static int fdomain_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DEBUG(1, "fdomain_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + HZ/20;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ fdomain_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ fdomain_16x0_reset(NULL, 0);
+ }
+ break;
+ }
+ return 0;
+} /* fdomain_event */
+
+/*====================================================================*/
+
+static int __init init_fdomain_cs(void) {
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "fdomain_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &fdomain_attach, &fdomain_detach);
+ return 0;
+}
+
+static void __exit exit_fdomain_cs(void) {
+ DEBUG(0, "fdomain_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ fdomain_detach(dev_list);
+}
+
+module_init(init_fdomain_cs);
+module_exit(exit_fdomain_cs);
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
new file mode 100644
index 000000000..c3f1d03a5
--- /dev/null
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -0,0 +1,428 @@
+/*======================================================================
+
+ A driver for the Qlogic SCSI card
+
+ qlogic_cs.c 1.77 2000/02/01 19:08:09
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+
+#include <../drivers/scsi/qlogicfas.h>
+
+#define qlogic_reset(h) qlogicfas_reset(h, 0)
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ciscode.h>
+
+extern void qlogicfas_preset(int port, int irq);
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"qlogic_cs.c 1.77 2000/02/01 19:08:09 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+ dev_link_t link;
+ u_short manf_id;
+ int ndev;
+ dev_node_t node[8];
+} scsi_info_t;
+
+static void qlogic_release(u_long arg);
+static int qlogic_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_link_t *qlogic_attach(void);
+static void qlogic_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = QLOGICFAS;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "qlogic_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *qlogic_attach(void)
+{
+ scsi_info_t *info;
+ client_reg_t client_reg;
+ dev_link_t *link;
+ int i, ret;
+
+ DEBUG(0, "qlogic_attach()\n");
+
+ /* Create new SCSI device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->link; link->priv = info;
+ link->release.function = &qlogic_release;
+ link->release.data = (u_long)link;
+
+ link->io.NumPorts1 = 16;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.IOAddrLines = 10;
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < 4; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.event_handler = &qlogic_event;
+ client_reg.EventMask =
+ CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ qlogic_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* qlogic_attach */
+
+/*====================================================================*/
+
+static void qlogic_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DEBUG(0, "qlogic_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG) {
+ qlogic_release((u_long)link);
+ if (link->state & DEV_STALE_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+ }
+
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free bits */
+ *linkp = link->next;
+ kfree(link->priv);
+
+} /* qlogic_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void qlogic_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ scsi_info_t *info = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int i, last_ret, last_fn;
+ u_short tuple_data[32];
+ Scsi_Device *dev;
+ dev_node_t **tail, *node;
+ struct Scsi_Host *host;
+
+ DEBUG(0, "qlogic_config(0x%p)\n", link);
+
+ tuple.TupleData = (cisdata_t *)tuple_data;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ CS_CHECK(GetTupleData, handle, &tuple);
+ CS_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigBase = parse.config.base;
+
+ tuple.DesiredTuple = CISTPL_MANFID;
+ if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
+ (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS))
+ info->manf_id = le16_to_cpu(tuple.TupleData[0]);
+
+ /* Configure card */
+ driver_template.module = &__this_module;
+ link->state |= DEV_CONFIG;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ while (1) {
+ CFG_CHECK(GetTupleData, handle, &tuple);
+ CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+ if (link->io.BasePort1 != 0) {
+ i = CardServices(RequestIO, handle, &link->io);
+ if (i == CS_SUCCESS) break;
+ }
+ next_entry:
+ CS_CHECK(GetNextTuple, handle, &tuple);
+ }
+
+ CS_CHECK(RequestIRQ, handle, &link->irq);
+ CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+ if ((info->manf_id == MANFID_MACNICA) ||
+ (info->manf_id == MANFID_PIONEER) ||
+ (info->manf_id == 0x0098)) {
+ /* set ATAcmd */
+ outb(0xb4, link->io.BasePort1+0xd);
+ outb(0x24, link->io.BasePort1+0x9);
+ outb(0x04, link->io.BasePort1+0xd);
+ }
+
+ /* A bad hack... */
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+
+ /* The KXL-810AN has a bigger IO port window */
+ if (link->io.NumPorts1 == 32)
+ qlogicfas_preset(link->io.BasePort1+16, link->irq.AssignedIRQ);
+ else
+ qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ);
+
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+ tail = &link->dev;
+ info->ndev = 0;
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->hostt == &driver_template)
+ for (dev = host->host_queue; dev; dev = dev->next) {
+ u_long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+ ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+ node = &info->node[info->ndev];
+ node->minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node->major = SCSI_TAPE_MAJOR;
+ sprintf(node->dev_name, "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node->major = SCSI_DISK0_MAJOR;
+ sprintf(node->dev_name, "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node->major = SCSI_CDROM_MAJOR;
+ sprintf(node->dev_name, "sr#%04lx", id);
+ break;
+ default:
+ node->major = SCSI_GENERIC_MAJOR;
+ sprintf(node->dev_name, "sg#%04lx", id);
+ break;
+ }
+ *tail = node; tail = &node->next;
+ info->ndev++;
+ }
+ *tail = NULL;
+ if (info->ndev == 0)
+ printk(KERN_INFO "qlogic_cs: no SCSI devices found\n");
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ qlogic_release((u_long)link);
+ return;
+
+} /* qlogic_config */
+
+/*====================================================================*/
+
+static void qlogic_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ DEBUG(0, "qlogic_release(0x%p)\n", link);
+
+ if (GET_USE_COUNT(&__this_module) != 0) {
+ DEBUG(0, "qlogic_cs: release postponed, device still open\n");
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ link->dev = NULL;
+
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+ if (link->state & DEV_STALE_LINK)
+ qlogic_detach(link);
+
+} /* qlogic_release */
+
+/*====================================================================*/
+
+static int qlogic_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DEBUG(1, "qlogic_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + HZ/20;
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ qlogic_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG) {
+ scsi_info_t *info = link->priv;
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ if ((info->manf_id == MANFID_MACNICA) ||
+ (info->manf_id == MANFID_PIONEER) ||
+ (info->manf_id == 0x0098)) {
+ outb( 0x80, link->io.BasePort1+0xd);
+ outb( 0x24, link->io.BasePort1+0x9);
+ outb( 0x04, link->io.BasePort1+0xd);
+ }
+ qlogic_reset(NULL);
+ }
+ break;
+ }
+ return 0;
+} /* qlogic_event */
+
+/*====================================================================*/
+
+static int __init init_qlogic_cs(void) {
+ servinfo_t serv;
+ DEBUG(0, "%s\n", version);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "qlogic_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach);
+ return 0;
+}
+
+static void __exit exit_qlogic_cs(void) {
+ DEBUG(0, "qlogic_cs: unloading\n");
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL)
+ qlogic_detach(dev_list);
+}
+
+module_init(init_qlogic_cs);
+module_exit(exit_qlogic_cs);
diff --git a/drivers/scsi/psi_dale.h b/drivers/scsi/psi_dale.h
index bb7c8006b..03da4c3b8 100644
--- a/drivers/scsi/psi_dale.h
+++ b/drivers/scsi/psi_dale.h
@@ -20,16 +20,32 @@
****************************************************************************/
/************************************************/
+/* Some defines that we like */
+/************************************************/
+#define CHAR char
+#define UCHAR unsigned char
+#define SHORT short
+#define USHORT unsigned short
+#define BOOL unsigned short
+#define LONG long
+#define ULONG unsigned long
+#define VOID void
+
+/************************************************/
/* Dale PCI setup */
/************************************************/
#define VENDOR_PSI 0x1256
#define DEVICE_DALE_1 0x4401 /* 'D1' */
+#define DEVICE_BIGD_1 0x4201 /* 'B1' */
+#define DEVICE_BIGD_2 0x4202 /* 'B2' */
/************************************************/
/* Misc konstants */
/************************************************/
#define DALE_MAXDRIVES 4
+#define BIGD_MAXDRIVES 8
#define SECTORSXFER 8
+#define ATAPI_TRANSFER 8192
#define BYTES_PER_SECTOR 512
#define DEFAULT_TIMING_MODE 5
@@ -49,90 +65,136 @@
/************************************************/
/* DALE Register address offsets */
/************************************************/
-#define REG_DATA 0x80
-#define REG_ERROR 0x84
-#define REG_SECTOR_COUNT 0x88
-#define REG_LBA_0 0x8C
-#define REG_LBA_8 0x90
-#define REG_LBA_16 0x94
-#define REG_LBA_24 0x98
-#define REG_STAT_CMD 0x9C
-#define REG_STAT_SEL 0xA0
-#define REG_FAIL 0xB0
-#define REG_ALT_STAT 0xB8
-#define REG_DRIVE_ADRS 0xBC
-
-#define DALE_DATA_SLOW 0x00040000L
-#define DALE_DATA_MODE2 0x00040000L
-#define DALE_DATA_MODE3 0x00050000L
-#define DALE_DATA_MODE4 0x00060000L
-#define DALE_DATA_MODE4P 0x00070000L
-
-#define RTR_LOCAL_RANGE 0x000
-#define RTR_LOCAL_REMAP 0x004
-#define RTR_EXP_RANGE 0x010
-#define RTR_EXP_REMAP 0x014
-#define RTR_REGIONS 0x018
-#define RTR_DM_MASK 0x01C
-#define RTR_DM_LOCAL_BASE 0x020
-#define RTR_DM_IO_BASE 0x024
-#define RTR_DM_PCI_REMAP 0x028
-#define RTR_DM_IO_CONFIG 0x02C
-#define RTR_MAILBOX 0x040
-#define RTR_LOCAL_DOORBELL 0x060
-#define RTR_PCI_DOORBELL 0x064
-#define RTR_INT_CONTROL_STATUS 0x068
-#define RTR_EEPROM_CONTROL_STATUS 0x06C
-
-#define RTL_DMA0_MODE 0x00
-#define RTL_DMA0_PCI_ADDR 0x04
-#define RTL_DMA0_LOCAL_ADDR 0x08
-#define RTL_DMA0_COUNT 0x0C
-#define RTL_DMA0_DESC_PTR 0x10
-#define RTL_DMA1_MODE 0x14
-#define RTL_DMA1_PCI_ADDR 0x18
-#define RTL_DMA1_LOCAL_ADDR 0x1C
-#define RTL_DMA1_COUNT 0x20
-#define RTL_DMA1_DESC_PTR 0x24
-#define RTL_DMA_COMMAND_STATUS 0x28
-#define RTL_DMA_ARB0 0x2C
-#define RTL_DMA_ARB1 0x30
+#define REG_DATA 0x80
+#define REG_ERROR 0x84
+#define REG_SECTOR_COUNT 0x88
+#define REG_LBA_0 0x8C
+#define REG_LBA_8 0x90
+#define REG_LBA_16 0x94
+#define REG_LBA_24 0x98
+#define REG_STAT_CMD 0x9C
+#define REG_STAT_SEL 0xA0
+#define REG_FAIL 0xB0
+#define REG_ALT_STAT 0xB8
+#define REG_DRIVE_ADRS 0xBC
+
+#define DALE_DATA_SLOW 0x00040000L
+#define DALE_DATA_MODE2 0x00040000L
+#define DALE_DATA_MODE3 0x00050000L
+#define DALE_DATA_MODE4 0x00060000L
+#define DALE_DATA_MODE5 0x00070000L
+
+#define BIGD_DATA_SLOW 0x00000000L
+#define BIGD_DATA_MODE0 0x00000000L
+#define BIGD_DATA_MODE2 0x00000000L
+#define BIGD_DATA_MODE3 0x00000008L
+#define BIGD_DATA_MODE4 0x00000010L
+#define BIGD_DATA_MODE5 0x00000020L
+
+#define RTR_LOCAL_RANGE 0x000
+#define RTR_LOCAL_REMAP 0x004
+#define RTR_EXP_RANGE 0x010
+#define RTR_EXP_REMAP 0x014
+#define RTR_REGIONS 0x018
+#define RTR_DM_MASK 0x01C
+#define RTR_DM_LOCAL_BASE 0x020
+#define RTR_DM_IO_BASE 0x024
+#define RTR_DM_PCI_REMAP 0x028
+#define RTR_DM_IO_CONFIG 0x02C
+#define RTR_MAILBOX 0x040
+#define RTR_LOCAL_DOORBELL 0x060
+#define RTR_PCI_DOORBELL 0x064
+#define RTR_INT_CONTROL_STATUS 0x068
+#define RTR_EEPROM_CONTROL_STATUS 0x06C
+
+#define RTR_DMA0_MODE 0x0080
+#define RTR_DMA0_PCI_ADDR 0x0084
+#define RTR_DMA0_LOCAL_ADDR 0x0088
+#define RTR_DMA0_COUNT 0x008C
+#define RTR_DMA0_DESC_PTR 0x0090
+#define RTR_DMA1_MODE 0x0094
+#define RTR_DMA1_PCI_ADDR 0x0098
+#define RTR_DMA1_LOCAL_ADDR 0x009C
+#define RTR_DMA1_COUNT 0x00A0
+#define RTR_DMA1_DESC_PTR 0x00A4
+#define RTR_DMA_COMMAND_STATUS 0x00A8
+#define RTR_DMA_ARB0 0x00AC
+#define RTR_DMA_ARB1 0x00B0
+
+#define RTL_DMA0_MODE 0x00
+#define RTL_DMA0_PCI_ADDR 0x04
+#define RTL_DMA0_LOCAL_ADDR 0x08
+#define RTL_DMA0_COUNT 0x0C
+#define RTL_DMA0_DESC_PTR 0x10
+#define RTL_DMA1_MODE 0x14
+#define RTL_DMA1_PCI_ADDR 0x18
+#define RTL_DMA1_LOCAL_ADDR 0x1C
+#define RTL_DMA1_COUNT 0x20
+#define RTL_DMA1_DESC_PTR 0x24
+#define RTL_DMA_COMMAND_STATUS 0x28
+#define RTL_DMA_ARB0 0x2C
+#define RTL_DMA_ARB1 0x30
/************************************************/
/* Dale Scratchpad locations */
/************************************************/
-#define DALE_CHANNEL_DEVICE_0 0 // device channel locations
-#define DALE_CHANNEL_DEVICE_1 1
-#define DALE_CHANNEL_DEVICE_2 2
-#define DALE_CHANNEL_DEVICE_3 3
+#define DALE_CHANNEL_DEVICE_0 0 // device channel locations
+#define DALE_CHANNEL_DEVICE_1 1
+#define DALE_CHANNEL_DEVICE_2 2
+#define DALE_CHANNEL_DEVICE_3 3
-#define DALE_SCRATH_DEVICE_0 4 // device type codes
-#define DALE_SCRATH_DEVICE_1 5
-#define DALE_SCRATH_DEVICE_2 6
-#define DALE_SCRATH_DEVICE_3 7
+#define DALE_SCRATCH_DEVICE_0 4 // device type codes
+#define DALE_SCRATCH_DEVICE_1 5
+#define DALE_SCRATCH_DEVICE_2 6
+#define DALE_SCRATCH_DEVICE_3 7
-#define DALE_RAID_0_STATUS 8
-#define DALE_RAID_1_STATUS 9
+#define DALE_RAID_0_STATUS 8
+#define DALE_RAID_1_STATUS 9
-#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
-#define DALE_NUM_DRIVES 13 // number of addressable drives on this board
-#define DALE_RAID_ON 14 // RAID status On
-#define DALE_LAST_ERROR 15 // Last error code from BIOS
+#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
+#define DALE_NUM_DRIVES 13 // number of addressable drives on this board
+#define DALE_RAID_ON 14 // RAID status On
+#define DALE_LAST_ERROR 15 // Last error code from BIOS
/************************************************/
-/* Dale cable select bits */
+/* BigD Scratchpad locations */
/************************************************/
-#define SEL_NONE 0x00
-#define SEL_1 0x01
-#define SEL_2 0x02
+#define BIGD_DEVICE_0 0 // device channel locations
+#define BIGD_DEVICE_1 1
+#define BIGD_DEVICE_2 2
+#define BIGD_DEVICE_3 3
+
+#define BIGD_DEVICE_4 4 // device type codes
+#define BIGD_DEVICE_5 5
+#define BIGD_DEVICE_6 6
+#define BIGD_DEVICE_7 7
+
+#define BIGD_ALARM_IMAGE 11 // ~image of alarm fail register
+#define BIGD_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5)
+#define BIGD_NUM_DRIVES 13 // number of addressable drives on this board
+#define BIGD_RAID_ON 14 // RAID status is on for the whole board
+#define BIGD_LAST_ERROR 15 // Last error code from BIOS
+
+#define BIGD_RAID_0_STATUS 16
+#define BIGD_RAID_1_STATUS 17
+#define BIGD_RAID_2_STATUS 18
+#define BIGD_RAID_3_STATUS 19
+#define BIGD_RAID_4_STATUS 20
+#define BIGD_RAID_5_STATUS 21
+#define BIGD_RAID_6_STATUS 22
+#define BIGD_RAID_7_STATUS 23
/************************************************/
-/* Programmable Interrupt Controller */
+/* Dale cable select bits */
/************************************************/
-#define PIC1 0x20 // first 8259 base port address
-#define PIC2 0xA0 // second 8259 base port address
-#define INT_OCW1 1 // Operation Control Word 1: IRQ mask
-#define EOI 0x20 // non-specific end-of-interrupt
+#define SEL_NONE 0x00
+#define SEL_1 0x01
+#define SEL_2 0x02
+#define SEL_3 0x04
+#define SEL_4 0x08
+#define SEL_NEW_SPEED_1 0x20
+#define SEL_COPY 0x40
+#define SEL_IRQ_OFF 0x80
/************************************************/
/* Device/Geometry controls */
@@ -149,6 +211,18 @@
#define DEVICE_DASD_LBA 0x4 // LBA compatible device
/************************************************/
+/* BigD fail register bits */
+/************************************************/
+#define FAIL_NONE 0x00
+#define FAIL_0 0x01
+#define FAIL_1 0x02
+#define FAIL_2 0x04
+#define FAIL_MULTIPLE 0x08
+#define FAIL_GOOD 0x20
+#define FAIL_AUDIBLE 0x40
+#define FAIL_ANY 0x80
+
+/************************************************/
/* Setup Structure Definitions */
/************************************************/
typedef struct // device setup parameters
@@ -168,11 +242,11 @@ typedef struct // master setup structure
BOOL promptBIOS;
BOOL fastFormat;
BOOL shareInterrupt;
- BOOL rebootRebuil;
+ BOOL rebootRebuild;
USHORT timingMode;
USHORT spare5;
USHORT spare6;
- SETUP_DEVICE setupDevice[4];
+ SETUP_DEVICE setupDevice[BIGD_MAXDRIVES];
} SETUP, *PSETUP;
/************************************************/
@@ -210,3 +284,281 @@ typedef struct DEVICE_RAID1
#define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair
#define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration
#define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on
+
+/************************************************/
+/* Timeout konstants */
+/************************************************/
+#define TIMEOUT_READY 100 // 100 mSec
+#define TIMEOUT_DRQ 300 // 300 mSec
+#define TIMEOUT_DATA (3 * HZ) // 3 seconds
+
+/************************************************/
+/* Misc. macros */
+/************************************************/
+#define ANY2SCSI(up, p) \
+((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \
+((UCHAR *)up)[1] = ((ULONG)(p));
+
+#define SCSI2LONG(up) \
+( (((long)*(((UCHAR *)up))) << 16) \
++ (((long)(((UCHAR *)up)[1])) << 8) \
++ ((long)(((UCHAR *)up)[2])) )
+
+#define XANY2SCSI(up, p) \
+((UCHAR *)up)[0] = ((long)(p)) >> 24; \
+((UCHAR *)up)[1] = ((long)(p)) >> 16; \
+((UCHAR *)up)[2] = ((long)(p)) >> 8; \
+((UCHAR *)up)[3] = ((long)(p));
+
+#define XSCSI2LONG(up) \
+( (((long)(((UCHAR *)up)[0])) << 24) \
++ (((long)(((UCHAR *)up)[1])) << 16) \
++ (((long)(((UCHAR *)up)[2])) << 8) \
++ ((long)(((UCHAR *)up)[3])) )
+
+#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel)
+#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd)
+#define AtapiDevice(padapter,b) outb_p (b, padapter->regLba24);
+#define AtapiCountLo(padapter,b) outb_p (b, padapter->regLba8)
+#define AtapiCountHi(padapter,b) outb_p (b, padapter->regLba16)
+
+/************************************************/
+/* SCSI CDB operation codes */
+/************************************************/
+#define SCSIOP_TEST_UNIT_READY 0x00
+#define SCSIOP_REZERO_UNIT 0x01
+#define SCSIOP_REWIND 0x01
+#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
+#define SCSIOP_REQUEST_SENSE 0x03
+#define SCSIOP_FORMAT_UNIT 0x04
+#define SCSIOP_READ_BLOCK_LIMITS 0x05
+#define SCSIOP_REASSIGN_BLOCKS 0x07
+#define SCSIOP_READ6 0x08
+#define SCSIOP_RECEIVE 0x08
+#define SCSIOP_WRITE6 0x0A
+#define SCSIOP_PRINT 0x0A
+#define SCSIOP_SEND 0x0A
+#define SCSIOP_SEEK6 0x0B
+#define SCSIOP_TRACK_SELECT 0x0B
+#define SCSIOP_SLEW_PRINT 0x0B
+#define SCSIOP_SEEK_BLOCK 0x0C
+#define SCSIOP_PARTITION 0x0D
+#define SCSIOP_READ_REVERSE 0x0F
+#define SCSIOP_WRITE_FILEMARKS 0x10
+#define SCSIOP_FLUSH_BUFFER 0x10
+#define SCSIOP_SPACE 0x11
+#define SCSIOP_INQUIRY 0x12
+#define SCSIOP_VERIFY6 0x13
+#define SCSIOP_RECOVER_BUF_DATA 0x14
+#define SCSIOP_MODE_SELECT 0x15
+#define SCSIOP_RESERVE_UNIT 0x16
+#define SCSIOP_RELEASE_UNIT 0x17
+#define SCSIOP_COPY 0x18
+#define SCSIOP_ERASE 0x19
+#define SCSIOP_MODE_SENSE 0x1A
+#define SCSIOP_START_STOP_UNIT 0x1B
+#define SCSIOP_STOP_PRINT 0x1B
+#define SCSIOP_LOAD_UNLOAD 0x1B
+#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
+#define SCSIOP_SEND_DIAGNOSTIC 0x1D
+#define SCSIOP_MEDIUM_REMOVAL 0x1E
+#define SCSIOP_READ_CAPACITY 0x25
+#define SCSIOP_READ 0x28
+#define SCSIOP_WRITE 0x2A
+#define SCSIOP_SEEK 0x2B
+#define SCSIOP_LOCATE 0x2B
+#define SCSIOP_WRITE_VERIFY 0x2E
+#define SCSIOP_VERIFY 0x2F
+#define SCSIOP_SEARCH_DATA_HIGH 0x30
+#define SCSIOP_SEARCH_DATA_EQUAL 0x31
+#define SCSIOP_SEARCH_DATA_LOW 0x32
+#define SCSIOP_SET_LIMITS 0x33
+#define SCSIOP_READ_POSITION 0x34
+#define SCSIOP_SYNCHRONIZE_CACHE 0x35
+#define SCSIOP_COMPARE 0x39
+#define SCSIOP_COPY_COMPARE 0x3A
+#define SCSIOP_WRITE_DATA_BUFF 0x3B
+#define SCSIOP_READ_DATA_BUFF 0x3C
+#define SCSIOP_CHANGE_DEFINITION 0x40
+#define SCSIOP_READ_SUB_CHANNEL 0x42
+#define SCSIOP_READ_TOC 0x43
+#define SCSIOP_READ_HEADER 0x44
+#define SCSIOP_PLAY_AUDIO 0x45
+#define SCSIOP_PLAY_AUDIO_MSF 0x47
+#define SCSIOP_PLAY_TRACK_INDEX 0x48
+#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
+#define SCSIOP_PAUSE_RESUME 0x4B
+#define SCSIOP_LOG_SELECT 0x4C
+#define SCSIOP_LOG_SENSE 0x4D
+#define SCSIOP_MODE_SELECT10 0x55
+#define SCSIOP_MODE_SENSE10 0x5A
+#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6
+#define SCSIOP_MECHANISM_STATUS 0xBD
+#define SCSIOP_READ_CD 0xBE
+
+// IDE command definitions
+#define IDE_COMMAND_ATAPI_RESET 0x08
+#define IDE_COMMAND_READ 0x20
+#define IDE_COMMAND_WRITE 0x30
+#define IDE_COMMAND_RECALIBRATE 0x10
+#define IDE_COMMAND_SEEK 0x70
+#define IDE_COMMAND_SET_PARAMETERS 0x91
+#define IDE_COMMAND_VERIFY 0x40
+#define IDE_COMMAND_ATAPI_PACKET 0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
+#define IDE_CMD_READ_MULTIPLE 0xC4
+#define IDE_CMD_WRITE_MULTIPLE 0xC5
+#define IDE_CMD_SET_MULTIPLE 0xC6
+#define IDE_COMMAND_IDENTIFY 0xEC
+
+// IDE status definitions
+#define IDE_STATUS_ERROR 0x01
+#define IDE_STATUS_INDEX 0x02
+#define IDE_STATUS_CORRECTED_ERROR 0x04
+#define IDE_STATUS_DRQ 0x08
+#define IDE_STATUS_DSC 0x10
+#define IDE_STATUS_WRITE_FAULT 0x20
+#define IDE_STATUS_DRDY 0x40
+#define IDE_STATUS_BUSY 0x80
+
+typedef struct _ATAPI_STATUS
+ {
+ CHAR check :1;
+ CHAR reserved1 :1;
+ CHAR corr :1;
+ CHAR drq :1;
+ CHAR dsc :1;
+ CHAR reserved2 :1;
+ CHAR drdy :1;
+ CHAR bsy :1;
+ } ATAPI_STATUS;
+
+typedef struct _ATAPI_REASON
+ {
+ CHAR cod :1;
+ CHAR io :1;
+ CHAR reserved1 :6;
+ } ATAPI_REASON;
+
+typedef struct _ATAPI_ERROR
+ {
+ CHAR ili :1;
+ CHAR eom :1;
+ CHAR abort :1;
+ CHAR mcr :1;
+ CHAR senseKey :4;
+ } ATAPI_ERROR;
+
+// IDE error definitions
+#define IDE_ERROR_AMNF 0x01
+#define IDE_ERROR_TKONF 0x02
+#define IDE_ERROR_ABRT 0x04
+#define IDE_ERROR_MCR 0x08
+#define IDE_ERROR_IDFN 0x10
+#define IDE_ERROR_MC 0x20
+#define IDE_ERROR_UNC 0x40
+#define IDE_ERROR_BBK 0x80
+
+// SCSI read capacity structure
+typedef struct _READ_CAPACITY_DATA
+ {
+ ULONG blks; /* total blocks (converted to little endian) */
+ ULONG blksiz; /* size of each (converted to little endian) */
+ } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+// SCSI inquiry data
+typedef struct _INQUIRYDATA
+ {
+ UCHAR DeviceType :5;
+ UCHAR DeviceTypeQualifier :3;
+ UCHAR DeviceTypeModifier :7;
+ UCHAR RemovableMedia :1;
+ UCHAR Versions;
+ UCHAR ResponseDataFormat;
+ UCHAR AdditionalLength;
+ UCHAR Reserved[2];
+ UCHAR SoftReset :1;
+ UCHAR CommandQueue :1;
+ UCHAR Reserved2 :1;
+ UCHAR LinkedCommands :1;
+ UCHAR Synchronous :1;
+ UCHAR Wide16Bit :1;
+ UCHAR Wide32Bit :1;
+ UCHAR RelativeAddressing :1;
+ UCHAR VendorId[8];
+ UCHAR ProductId[16];
+ UCHAR ProductRevisionLevel[4];
+ UCHAR VendorSpecific[20];
+ UCHAR Reserved3[40];
+ } INQUIRYDATA, *PINQUIRYDATA;
+
+// IDE IDENTIFY data
+#pragma pack (1)
+typedef struct _IDENTIFY_DATA
+ {
+ USHORT GeneralConfiguration; // 0
+ USHORT NumberOfCylinders; // 1
+ USHORT Reserved1; // 2
+ USHORT NumberOfHeads; // 3
+ USHORT UnformattedBytesPerTrack; // 4
+ USHORT UnformattedBytesPerSector; // 5
+ USHORT SectorsPerTrack; // 6
+ USHORT NumBytesISG; // 7 Byte Len - inter-sector gap
+ USHORT NumBytesSync; // 8 - sync field
+ USHORT NumWordsVUS; // 9 Len - Vendor Unique Info
+ USHORT SerialNumber[10]; // 10
+ USHORT BufferType; // 20
+ USHORT BufferSectorSize; // 21
+ USHORT NumberOfEccBytes; // 22
+ USHORT FirmwareRevision[4]; // 23
+ USHORT ModelNumber[20]; // 27
+ USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk
+ USHORT Reserved2 :8; // 47
+ USHORT DoubleWordMode; // 48 flag for double word mode capable
+ USHORT VendorUnique1 :8; // 49
+ USHORT SupportDMA :1; // 49 DMA supported
+ USHORT SupportLBA :1; // 49 LBA supported
+ USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled
+ USHORT SupportIORDY :1; // 49 IORDY supported
+ USHORT ReservedPsuedoDMA :1; // 49 reserved for pseudo DMA mode support
+ USHORT Reserved3 :3; // 49
+ USHORT Reserved4; // 50
+ USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO
+ USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO
+ USHORT Reserved6 :8; // 52 - DMA
+ USHORT DMACycleTime :8; // 52 - DMA
+ USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild
+ USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid
+ USHORT Reserved7 :14; // 53
+ USHORT LogNumCyl; // 54 Current Translation - Num Cyl
+ USHORT LogNumHeads; // 55 Num Heads
+ USHORT LogSectorsPerTrack; // 56 Sec/Trk
+ ULONG LogTotalSectors; // 57 Total Sec
+ USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt
+ USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt
+ USHORT Reserved8 :7; // 59
+ ULONG LBATotalSectors; // 60 LBA Mode - Sectors
+ USHORT DMASWordFlags; // 62
+ USHORT DMAMWordFlags; // 63
+ USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported
+ USHORT Reserved9 :8; // 64
+ USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word
+ USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time
+ USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control
+ USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control
+ USHORT ReservedSpace[256-69]; // 69
+ } IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+// ATAPI configuration bits
+typedef struct _ATAPI_GENERAL_0
+ {
+ USHORT CmdPacketSize :2; // Command packet size
+ USHORT Reserved1 :3;
+ USHORT CmdDrqType :2;
+ USHORT Removable :1;
+ USHORT DeviceType :5;
+ USHORT Reserved2 :1;
+ USHORT ProtocolType :2;
+ } ATAPI_GENERAL_0;
+
+#pragma pack ()
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 543a98419..e216ef03a 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -182,6 +182,7 @@ END OF TERMS AND CONDITIONS
- Initial Beta Release.
*****************************************************************************/
+
#ifdef MODULE
#include <linux/module.h>
#endif
@@ -2789,7 +2790,7 @@ qla1280_setup_chip(scsi_qla_host_t *ha)
DEBUG(sprintf(debug_buff,"qla1280_setup_chip: loading risc @ =(0x%p),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);)
DEBUG(qla1280_print(debug_buff));
- printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address);
+ DEBUG(printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address));
BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1));
mb[0] = MBC_LOAD_RAM;
/* mb[0] = MBC_LOAD_RAM_A64; */
@@ -2799,7 +2800,7 @@ qla1280_setup_chip(scsi_qla_host_t *ha)
mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff;
mb[7] = (uint16_t) (MS_64BITS(ha->request_dma) & 0xffff);
mb[6] = (uint16_t) (MS_64BITS(ha->request_dma) >> 16) & 0xffff;
- printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]);
+ DEBUG(printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]));
if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0,
&mb[0])) )
{
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 6196d8eb2..9bc66953d 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -21,7 +21,7 @@
Version 0.46 1/30/97 - kernel 1.2.0+
Functions as standalone, loadable, and PCMCIA driver, the latter from
- Dave Hind's PCMCIA package.
+ Dave Hinds' PCMCIA package.
Redistributable under terms of the GNU Public License
@@ -107,7 +107,6 @@
#ifdef PCMCIA
#undef QL_INT_ACTIVE_HIGH
#define QL_INT_ACTIVE_HIGH 0
-#define MODULE
#endif
#include <linux/module.h>
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
index ecdc65cd4..283fe9c3d 100644
--- a/drivers/scsi/qlogicfc.c
+++ b/drivers/scsi/qlogicfc.c
@@ -64,7 +64,7 @@
/* Configuration section **************************************************** */
/* Set the following macro to 1 to reload the ISP2x00's firmware. This is
- version 1.15.37 of the isp2100's firmware and version 2.00.16 of the
+ version 1.17.30 of the isp2100's firmware and version 2.00.40 of the
isp2200's firmware.
*/
@@ -91,7 +91,7 @@
/* #define TRACE_ISP 1 */
-#define DEFAULT_LOOP_COUNT 10000000
+#define DEFAULT_LOOP_COUNT 1000000000
/* End Configuration section ************************************************ */
@@ -632,6 +632,17 @@ struct init_cb {
#define QLOGICFC_MAX_LUN 128
#define QLOGICFC_MAX_LOOP_ID 0x7d
+/* the following connection options only apply to the 2200. i have only
+ * had success with LOOP_ONLY and P2P_ONLY.
+ */
+
+#define LOOP_ONLY 0
+#define P2P_ONLY 1
+#define LOOP_PREFERED 2
+#define P2P_PREFERED 3
+
+#define CONNECTION_PREFERENCE LOOP_ONLY
+
/* adapter_state values */
#define AS_FIRMWARE_DEAD -1
#define AS_LOOP_DOWN 0
@@ -762,7 +773,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
hostdata->queued = 0;
/* set up the control block */
hostdata->control_block.version = 0x1;
- hostdata->control_block.firm_opts = 0x000e;
+ hostdata->control_block.firm_opts = 0x800e;
hostdata->control_block.max_frame_len = 2048;
hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN;
hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN;
@@ -780,6 +791,8 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req);
hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req);
+
+ hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4;
hostdata->adapter_state = AS_LOOP_DOWN;
hostdata->explore_timer.data = 1;
hostdata->host_id = hosts;
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index a7418f18b..d61c832c5 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1036,7 +1036,7 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
int sg_count;
sg = (struct scatterlist *) Cmnd->buffer;
- sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg);
+ sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
ds = cmd->dataseg;
cmd->segment_cnt = sg_count;
@@ -1074,15 +1074,20 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
}
sg_count -= n;
}
- } else {
+ } else if (Cmnd->request_bufflen) {
Cmnd->SCp.ptr = (char *)(unsigned long)
sbus_map_single(qpti->sdev,
Cmnd->request_buffer,
- Cmnd->request_bufflen);
+ Cmnd->request_bufflen,
+ scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
cmd->dataseg[0].d_count = Cmnd->request_bufflen;
cmd->segment_cnt = 1;
+ } else {
+ cmd->dataseg[0].d_base = 0;
+ cmd->dataseg[0].d_count = 0;
+ cmd->segment_cnt = 1; /* Shouldn't this be 0? */
}
/* Committed, record Scsi_Cmd so we can find it later. */
@@ -1409,11 +1414,13 @@ static Scsi_Cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
if (Cmnd->use_sg) {
sbus_unmap_sg(qpti->sdev,
(struct scatterlist *)Cmnd->buffer,
- Cmnd->use_sg);
+ Cmnd->use_sg,
+ scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
} else {
sbus_unmap_single(qpti->sdev,
(__u32)((unsigned long)Cmnd->SCp.ptr),
- Cmnd->request_bufflen);
+ Cmnd->request_bufflen,
+ scsi_to_sbus_dma_dir(Cmnd->sc_data_direction));
}
qpti->cmd_count[Cmnd->target]--;
sbus_writew(out_ptr, qpti->qregs + MBOX5);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2d86cbf95..a6e2c14d9 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -224,6 +224,8 @@ void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
{
DECLARE_MUTEX_LOCKED(sem);
+ if (buffer != NULL && SCpnt->sc_data_direction == SCSI_DATA_NONE)
+ BUG();
SCpnt->request.sem = &sem;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
scsi_do_cmd (SCpnt, (void *) cmnd,
@@ -248,6 +250,73 @@ static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED;
/*
+ * Function: scsi_allocate_request
+ *
+ * Purpose: Allocate a request descriptor.
+ *
+ * Arguments: device - device for which we want a request
+ *
+ * Lock status: No locks assumed to be held. This function is SMP-safe.
+ *
+ * Returns: Pointer to request block.
+ *
+ * Notes: With the new queueing code, it becomes important
+ * to track the difference between a command and a
+ * request. A request is a pending item in the queue that
+ * has not yet reached the top of the queue.
+ */
+
+Scsi_Request *scsi_allocate_request(Scsi_Device * device)
+{
+ Scsi_Request *SRpnt = NULL;
+
+ if (!device)
+ panic("No device passed to scsi_allocate_request().\n");
+
+ SRpnt = (Scsi_Request *) kmalloc(sizeof(Scsi_Request), GFP_ATOMIC);
+ if( SRpnt == NULL )
+ {
+ return NULL;
+ }
+
+ memset(SRpnt, 0, sizeof(Scsi_Request));
+ SRpnt->sr_device = device;
+ SRpnt->sr_host = device->host;
+ SRpnt->sr_magic = SCSI_REQ_MAGIC;
+ SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
+
+ return SRpnt;
+}
+
+/*
+ * Function: scsi_release_request
+ *
+ * Purpose: Release a request descriptor.
+ *
+ * Arguments: device - device for which we want a request
+ *
+ * Lock status: No locks assumed to be held. This function is SMP-safe.
+ *
+ * Returns: Pointer to request block.
+ *
+ * Notes: With the new queueing code, it becomes important
+ * to track the difference between a command and a
+ * request. A request is a pending item in the queue that
+ * has not yet reached the top of the queue. We still need
+ * to free a request when we are done with it, of course.
+ */
+void scsi_release_request(Scsi_Request * req)
+{
+ if( req->sr_command != NULL )
+ {
+ scsi_release_command(req->sr_command);
+ req->sr_command = NULL;
+ }
+
+ kfree(req);
+}
+
+/*
* Function: scsi_allocate_device
*
* Purpose: Allocate a command descriptor.
@@ -269,6 +338,9 @@ static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED;
* command block, this function will interrupt and return
* NULL in the event that a signal arrives that needs to
* be handled.
+ *
+ * This function is deprecated, and drivers should be
+ * rewritten to use Scsi_Request instead of Scsi_Cmnd.
*/
Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
@@ -417,6 +489,10 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
SCpnt->transfersize = 0; /* No default transfer size */
SCpnt->cmd_len = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN;
+ SCpnt->sc_request = NULL;
+ SCpnt->sc_magic = SCSI_CMND_MAGIC;
+
SCpnt->result = 0;
SCpnt->underflow = 0; /* Do not flag underflow conditions */
SCpnt->resid = 0;
@@ -451,6 +527,9 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
* gets hidden in this function. Upper level drivers don't
* have any chickens to wave in the air to get things to
* work reliably.
+ *
+ * This function is deprecated, and drivers should be
+ * rewritten to use Scsi_Request instead of Scsi_Cmnd.
*/
void scsi_release_command(Scsi_Cmnd * SCpnt)
{
@@ -636,6 +715,8 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
return rtn;
}
+devfs_handle_t scsi_devfs_handle = NULL;
+
/*
* scsi_do_cmd sends all the commands out to the low-level driver. It
* handles the specifics required for each low level driver - ie queued
@@ -643,6 +724,215 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
* drivers go for the same host at the same time.
*/
+void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd ,
+ void *buffer, unsigned bufflen,
+ int timeout, int retries)
+{
+ DECLARE_MUTEX_LOCKED(sem);
+
+ SRpnt->sr_request.sem = &sem;
+ SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
+ scsi_do_req (SRpnt, (void *) cmnd,
+ buffer, bufflen, scsi_wait_done, timeout, retries);
+ down (&sem);
+ SRpnt->sr_request.sem = NULL;
+ if( SRpnt->sr_command != NULL )
+ {
+ scsi_release_command(SRpnt->sr_command);
+ SRpnt->sr_command = NULL;
+ }
+
+}
+
+/*
+ * Function: scsi_do_req
+ *
+ * Purpose: Queue a SCSI request
+ *
+ * Arguments: SRpnt - command descriptor.
+ * cmnd - actual SCSI command to be performed.
+ * buffer - data buffer.
+ * bufflen - size of data buffer.
+ * done - completion function to be run.
+ * timeout - how long to let it run before timeout.
+ * retries - number of retries we allow.
+ *
+ * Lock status: With the new queueing code, this is SMP-safe, and no locks
+ * need be held upon entry. The old queueing code the lock was
+ * assumed to be held upon entry.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: Prior to the new queue code, this function was not SMP-safe.
+ * Also, this function is now only used for queueing requests
+ * for things like ioctls and character device requests - this
+ * is because we essentially just inject a request into the
+ * queue for the device. Normal block device handling manipulates
+ * the queue directly.
+ */
+void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd,
+ void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *),
+ int timeout, int retries)
+{
+ Scsi_Device * SDpnt = SRpnt->sr_device;
+ struct Scsi_Host *host = SDpnt->host;
+
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ SCSI_LOG_MLQUEUE(4,
+ {
+ int i;
+ int target = SDpnt->id;
+ printk("scsi_do_req (host = %d, channel = %d target = %d, "
+ "buffer =%p, bufflen = %d, done = %p, timeout = %d, "
+ "retries = %d)\n"
+ "command : ", host->host_no, SDpnt->channel, target, buffer,
+ bufflen, done, timeout, retries);
+ for (i = 0; i < 10; ++i)
+ printk("%02x ", ((unsigned char *) cmnd)[i]);
+ printk("\n");
+ });
+
+ if (!host) {
+ panic("Invalid or not present host.\n");
+ }
+
+ /*
+ * If the upper level driver is reusing these things, then
+ * we should release the low-level block now. Another one will
+ * be allocated later when this request is getting queued.
+ */
+ if( SRpnt->sr_command != NULL )
+ {
+ scsi_release_command(SRpnt->sr_command);
+ SRpnt->sr_command = NULL;
+ }
+
+ /*
+ * We must prevent reentrancy to the lowlevel host driver. This prevents
+ * it - we enter a loop until the host we want to talk to is not busy.
+ * Race conditions are prevented, as interrupts are disabled in between the
+ * time we check for the host being not busy, and the time we mark it busy
+ * ourselves.
+ */
+
+
+ /*
+ * Our own function scsi_done (which marks the host as not busy, disables
+ * the timeout counter, etc) will be called by us or by the
+ * scsi_hosts[host].queuecommand() function needs to also call
+ * the completion function for the high level driver.
+ */
+
+ memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd,
+ sizeof(SRpnt->sr_cmnd));
+ SRpnt->sr_bufflen = bufflen;
+ SRpnt->sr_buffer = buffer;
+ SRpnt->sr_allowed = retries;
+ SRpnt->sr_done = done;
+ SRpnt->sr_timeout_per_command = timeout;
+
+ memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd,
+ sizeof(SRpnt->sr_cmnd));
+
+ if (SRpnt->sr_cmd_len == 0)
+ SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]);
+
+ /*
+ * At this point, we merely set up the command, stick it in the normal
+ * request queue, and return. Eventually that request will come to the
+ * top of the list, and will be dispatched.
+ */
+ scsi_insert_special_req(SRpnt, 0);
+
+ SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
+}
+
+/*
+ * Function: scsi_init_cmd_from_req
+ *
+ * Purpose: Queue a SCSI command
+ * Purpose: Initialize a Scsi_Cmnd from a Scsi_Request
+ *
+ * Arguments: SCpnt - command descriptor.
+ * SRpnt - Request from the queue.
+ *
+ * Lock status: None needed.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: Mainly transfer data from the request structure to the
+ * command structure. The request structure is allocated
+ * using the normal memory allocator, and requests can pile
+ * up to more or less any depth. The command structure represents
+ * a consumable resource, as these are allocated into a pool
+ * when the SCSI subsystem initializes. The preallocation is
+ * required so that in low-memory situations a disk I/O request
+ * won't cause the memory manager to try and write out a page.
+ * The request structure is generally used by ioctls and character
+ * devices.
+ */
+void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt)
+{
+ struct Scsi_Host *host = SCpnt->host;
+
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+ SRpnt->sr_command = SCpnt;
+
+ if (!host) {
+ panic("Invalid or not present host.\n");
+ }
+
+ SCpnt->cmd_len = SRpnt->sr_cmd_len;
+ SCpnt->use_sg = SRpnt->sr_use_sg;
+
+ memcpy((void *) &SCpnt->request, (const void *) &SRpnt->sr_request,
+ sizeof(SRpnt->sr_request));
+ memcpy((void *) SCpnt->data_cmnd, (const void *) SRpnt->sr_cmnd,
+ sizeof(SCpnt->data_cmnd));
+ SCpnt->reset_chain = NULL;
+ SCpnt->serial_number = 0;
+ SCpnt->serial_number_at_timeout = 0;
+ SCpnt->bufflen = SRpnt->sr_bufflen;
+ SCpnt->buffer = SRpnt->sr_buffer;
+ SCpnt->flags = 0;
+ SCpnt->retries = 0;
+ SCpnt->allowed = SRpnt->sr_allowed;
+ SCpnt->done = SRpnt->sr_done;
+ SCpnt->timeout_per_command = SRpnt->sr_timeout_per_command;
+
+ SCpnt->sc_data_direction = SRpnt->sr_data_direction;
+
+ SCpnt->sglist_len = SRpnt->sr_sglist_len;
+ SCpnt->underflow = SRpnt->sr_underflow;
+
+ SCpnt->sc_request = SRpnt;
+
+ memcpy((void *) SCpnt->cmnd, (const void *) SRpnt->sr_cmnd,
+ sizeof(SCpnt->cmnd));
+ /* Zero the sense buffer. Some host adapters automatically request
+ * sense on error. 0 is not a valid sense code.
+ */
+ memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+ SCpnt->request_buffer = SRpnt->sr_buffer;
+ SCpnt->request_bufflen = SRpnt->sr_bufflen;
+ SCpnt->old_use_sg = SCpnt->use_sg;
+ if (SCpnt->cmd_len == 0)
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->old_cmd_len = SCpnt->cmd_len;
+ SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
+
+ /* Start the timer ticking. */
+
+ SCpnt->internal_timeout = NORMAL_TIMEOUT;
+ SCpnt->abort_reason = 0;
+ SCpnt->result = 0;
+
+ SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
+}
+
/*
* Function: scsi_do_cmd
*
@@ -737,6 +1027,7 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
if (SCpnt->cmd_len == 0)
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
SCpnt->old_cmd_len = SCpnt->cmd_len;
+ SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
/* Start the timer ticking. */
@@ -996,6 +1287,7 @@ int scsi_retry_command(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* Zero the sense information from the last time we tried
@@ -1017,6 +1309,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
{
struct Scsi_Host *host;
Scsi_Device *device;
+ Scsi_Request * SRpnt;
unsigned long flags;
ASSERT_LOCK(&io_request_lock, 0);
@@ -1061,6 +1354,20 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
/* We can get here with use_sg=0, causing a panic in the upper level (DB) */
SCpnt->use_sg = SCpnt->old_use_sg;
+ /*
+ * If there is an associated request structure, copy the data over before we call the
+ * completion function.
+ */
+ SRpnt = SCpnt->sc_request;
+ if( SRpnt != NULL ) {
+ SRpnt->sr_result = SRpnt->sr_command->result;
+ if( SRpnt->sr_result != 0 ) {
+ memcpy(SRpnt->sr_sense_buffer,
+ SRpnt->sr_command->sense_buffer,
+ sizeof(SRpnt->sr_sense_buffer));
+ }
+ }
+
SCpnt->done(SCpnt);
}
@@ -1096,6 +1403,7 @@ void scsi_release_commandblocks(Scsi_Device * SDpnt)
kfree((char *) SCpnt);
}
SDpnt->has_cmdblocks = 0;
+ SDpnt->queue_depth = 0;
spin_unlock_irqrestore(&device_request_lock, flags);
}
@@ -1168,7 +1476,39 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
static int proc_scsi_gen_write(struct file * file, const char * buf,
unsigned long length, void *data);
+void __init scsi_host_no_insert(char *str, int n)
+{
+ Scsi_Host_Name *shn, *shn2;
+ int len;
+
+ len = strlen(str);
+ if (len && (shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC))) {
+ if ((shn->name = kmalloc(len+1, GFP_ATOMIC))) {
+ strncpy(shn->name, str, len);
+ shn->name[len] = 0;
+ shn->host_no = n;
+ shn->host_registered = 0;
+ shn->loaded_as_module = 1; /* numbers shouldn't be freed in any case */
+ shn->next = NULL;
+ if (scsi_host_no_list) {
+ for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
+ ;
+ shn2->next = shn;
+ }
+ else
+ scsi_host_no_list = shn;
+ max_scsi_hosts = n+1;
+ }
+ else
+ kfree((char *) shn);
+ }
+}
+
#ifndef MODULE /* { */
+
+char scsi_host_no_table[20][10] __initdata = {};
+int scsi_host_no_set __initdata = 0;
+
/*
* scsi_dev_init() is our initialization routine, which in turn calls host
* initialization, bus scanning, and sd/st initialization routines.
@@ -1184,8 +1524,16 @@ int __init scsi_dev_init(void)
return;
#endif
+ /* Initialize list of host_no if kernel parameter set */
+ if (scsi_host_no_set) {
+ int i;
+ for (i = 0;i < sizeof(scsi_host_no_table)/sizeof(scsi_host_no_table[0]);i++)
+ scsi_host_no_insert(scsi_host_no_table[i], i);
+ }
+
/* Yes we're here... */
+ scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", 4, NULL);
/*
* This makes /proc/scsi and /proc/scsi/scsi visible.
*/
@@ -1535,6 +1883,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
* Nobody is using this device any more.
* Free all of the command structures.
*/
+ devfs_unregister (scd->de);
scsi_release_commandblocks(scd);
/* Now we can remove the device structure */
@@ -1834,6 +2183,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
printk("Attached usage count = %d\n", SDpnt->attached);
return;
}
+ devfs_unregister (SDpnt->de);
}
}
@@ -2143,11 +2493,12 @@ static void scsi_dump_status(int level)
printk("Dump of scsi host parameters:\n");
i = 0;
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
- printk(" %d %d %d : %d\n",
+ printk(" %d %d %d : %d %d\n",
shpnt->host_failed,
shpnt->host_busy,
atomic_read(&shpnt->host_active),
- shpnt->host_blocked);
+ shpnt->host_blocked,
+ shpnt->host_self_blocked);
}
@@ -2193,19 +2544,24 @@ static void scsi_dump_status(int level)
/* Now dump the request lists for each block device */
printk("Dump of pending block device requests\n");
for (i = 0; i < MAX_BLKDEV; i++) {
- if (blk_dev[i].request_queue.current_request) {
+ struct list_head * queue_head;
+
+ queue_head = &blk_dev[i].request_queue.queue_head;
+ if (!list_empty(queue_head)) {
struct request *req;
+ struct list_head * entry;
+
printk("%d: ", i);
- req = blk_dev[i].request_queue.current_request;
- while (req) {
+ entry = queue_head->next;
+ do {
+ req = blkdev_entry_to_request(entry);
printk("(%s %d %ld %ld %ld) ",
kdevname(req->rq_dev),
req->cmd,
req->sector,
req->nr_sectors,
req->current_nr_sectors);
- req = req->next;
- }
+ } while ((entry = entry->next) != queue_head);
printk("\n");
}
}
@@ -2216,12 +2572,52 @@ static void scsi_dump_status(int level)
}
#endif /* CONFIG_PROC_FS */
+static int scsi_host_no_init (char *str)
+{
+ static int next_no = 0;
+ char *temp;
+
+#ifndef MODULE
+ int len;
+ scsi_host_no_set = 1;
+ memset(scsi_host_no_table, 0, sizeof(scsi_host_no_table));
+#endif /* MODULE */
+
+ while (str) {
+ temp = str;
+ while (*temp && (*temp != ':') && (*temp != ','))
+ temp++;
+ if (!*temp)
+ temp = NULL;
+ else
+ *temp++ = 0;
+#ifdef MODULE
+ scsi_host_no_insert(str, next_no);
+#else
+ if (next_no < sizeof(scsi_host_no_table)/sizeof(scsi_host_no_table[0])) {
+ if ((len = strlen(str)) >= sizeof(scsi_host_no_table[0]))
+ len = sizeof(scsi_host_no_table[0])-1;
+ strncpy(scsi_host_no_table[next_no], str, len);
+ scsi_host_no_table[next_no][len] = 0;
+ }
+#endif /* MODULE */
+ str = temp;
+ next_no++;
+ }
+ return 1;
+}
+
+#ifndef MODULE
+__setup("scsihosts=", scsi_host_no_init);
+#endif
+
#ifdef MODULE
+static char *scsihosts;
+
+MODULE_PARM(scsihosts, "s");
int init_module(void)
{
- unsigned long size;
- int has_space = 0;
struct proc_dir_entry *generic;
if( scsi_init_minimal_dma_pool() != 0 )
@@ -2249,6 +2645,8 @@ int init_module(void)
scsi_loadable_module_flag = 1;
+ scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", 4, NULL);
+ scsi_host_no_init (scsihosts);
/*
* This is where the processing takes place for most everything
* when commands are completed.
@@ -2260,8 +2658,21 @@ int init_module(void)
void cleanup_module(void)
{
+ Scsi_Host_Name *shn, *shn2 = NULL;
+
remove_bh(SCSI_BH);
+ devfs_unregister (scsi_devfs_handle);
+ for (shn = scsi_host_no_list;shn;shn = shn->next) {
+ if (shn->name)
+ kfree(shn->name);
+ if (shn2)
+ kfree (shn2);
+ shn2 = shn;
+ }
+ if (shn2)
+ kfree (shn2);
+
#ifdef CONFIG_PROC_FS
/* No, we're not here anymore. Don't show the /proc/scsi files. */
remove_proc_entry ("scsi/scsi", 0);
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index df294f2e4..7a073f86e 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -16,6 +16,7 @@
#define _SCSI_H
#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
+#include <linux/devfs_fs_kernel.h>
#include <linux/proc_fs.h>
/*
@@ -31,6 +32,54 @@
#include <asm/io.h>
/*
+ * These are the values that the SCpnt->sc_data_direction and
+ * SRpnt->sr_data_direction can take. These need to be set
+ * The SCSI_DATA_UNKNOWN value is essentially the default.
+ * In the event that the command creator didn't bother to
+ * set a value, you will see SCSI_DATA_UNKNOWN.
+ */
+#define SCSI_DATA_UNKNOWN 0
+#define SCSI_DATA_WRITE 1
+#define SCSI_DATA_READ 2
+#define SCSI_DATA_NONE 3
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE))
+#define scsi_to_pci_dma_dir(scsi_dir) ((int)(scsi_dir))
+#else
+extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir)
+{
+ if (scsi_dir == SCSI_DATA_UNKNOWN)
+ return PCI_DMA_BIDIRECTIONAL;
+ if (scsi_dir == SCSI_DATA_WRITE)
+ return PCI_DMA_TODEVICE;
+ if (scsi_dir == SCSI_DATA_READ)
+ return PCI_DMA_FROMDEVICE;
+ return PCI_DMA_NONE;
+}
+#endif
+#endif
+
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE))
+#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir))
+#else
+extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir)
+{
+ if (scsi_dir == SCSI_DATA_UNKNOWN)
+ return SBUS_DMA_BIDIRECTIONAL;
+ if (scsi_dir == SCSI_DATA_WRITE)
+ return SBUS_DMA_TODEVICE;
+ if (scsi_dir == SCSI_DATA_READ)
+ return SBUS_DMA_FROMDEVICE;
+ return SBUS_DMA_NONE;
+}
+#endif
+#endif
+
+/*
* Some defs, in case these are not defined elsewhere.
*/
#ifndef TRUE
@@ -303,6 +352,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#define SUGGEST_MASK 0xf0
#define MAX_COMMAND_SIZE 12
+#define SCSI_SENSE_BUFFERSIZE 64
/*
* SCSI command sets
@@ -356,6 +406,10 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
*/
typedef struct scsi_device Scsi_Device;
typedef struct scsi_cmnd Scsi_Cmnd;
+typedef struct scsi_request Scsi_Request;
+
+#define SCSI_CMND_MAGIC 0xE25C23A5
+#define SCSI_REQ_MAGIC 0x75F6D354
/*
* Here is where we prototype most of the mid-layer.
@@ -444,10 +498,25 @@ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
extern void scsi_wait_cmd(Scsi_Cmnd *, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ int timeout, int retries);
+extern int scsi_dev_init(void);
+
+/*
+ * Newer request-based interfaces.
+ */
+extern Scsi_Request *scsi_allocate_request(Scsi_Device *);
+extern void scsi_release_request(Scsi_Request *);
+extern void scsi_wait_req(Scsi_Request *, const void *cmnd,
void *buffer, unsigned bufflen,
int timeout, int retries);
-extern int scsi_dev_init(void);
+extern void scsi_do_req(Scsi_Request *, const void *cmnd,
+ void *buffer, unsigned bufflen,
+ void (*done) (struct scsi_cmnd *),
+ int timeout, int retries);
+extern int scsi_insert_special_req(Scsi_Request * SRpnt, int);
+extern void scsi_init_cmd_from_req(Scsi_Cmnd *, Scsi_Request *);
/*
@@ -466,6 +535,7 @@ extern struct proc_dir_entry *proc_scsi;
*/
extern void print_command(unsigned char *);
extern void print_sense(const char *, Scsi_Cmnd *);
+extern void print_req_sense(const char *, Scsi_Request *);
extern void print_driverbyte(int scsiresult);
extern void print_hostbyte(int scsiresult);
extern void print_status (int status);
@@ -512,6 +582,7 @@ struct scsi_device {
int access_count; /* Count of open channels/mounts */
void *hostdata; /* available to low-level driver */
+ devfs_handle_t de; /* directory for the device */
char type;
char scsi_level;
char vendor[8], model[16], rev[4];
@@ -568,6 +639,39 @@ typedef struct scsi_pointer {
volatile int phase;
} Scsi_Pointer;
+/*
+ * This is essentially a slimmed down version of Scsi_Cmnd. The point of
+ * having this is that requests that are injected into the queue as result
+ * of things like ioctls and character devices shouldn't be using a
+ * Scsi_Cmnd until such a time that the command is actually at the head
+ * of the queue and being sent to the driver.
+ */
+struct scsi_request {
+ int sr_magic;
+ int sr_result; /* Status code from lower level driver */
+ unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE
+ * when CHECK CONDITION is
+ * received on original command
+ * (auto-sense) */
+
+ struct Scsi_Host *sr_host;
+ Scsi_Device *sr_device;
+ Scsi_Cmnd *sr_command;
+ struct request sr_request; /* A copy of the command we are
+ working on */
+ unsigned sr_bufflen; /* Size of data buffer */
+ void *sr_buffer; /* Data buffer */
+ int sr_allowed;
+ unsigned char sr_data_direction;
+ unsigned char sr_cmd_len;
+ unsigned char sr_cmnd[MAX_COMMAND_SIZE];
+ void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */
+ int sr_timeout_per_command;
+ unsigned short sr_use_sg; /* Number of pieces of scatter-gather */
+ unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */
+ unsigned sr_underflow; /* Return error if less than
+ this amount is transfered */
+};
/*
* FIXME(eric) - one of the great regrets that I have is that I failed to define
@@ -578,6 +682,7 @@ typedef struct scsi_pointer {
* go back and retrofit at least some of the elements here with with the prefix.
*/
struct scsi_cmnd {
+ int sc_magic;
/* private: */
/*
* This information is private to the scsi mid-layer. Wrapping it in a
@@ -587,6 +692,7 @@ struct scsi_cmnd {
unsigned short state;
unsigned short owner;
Scsi_Device *device;
+ Scsi_Request *sc_request;
struct scsi_cmnd *next;
struct scsi_cmnd *reset_chain;
@@ -630,6 +736,8 @@ struct scsi_cmnd {
unsigned char channel;
unsigned char cmd_len;
unsigned char old_cmd_len;
+ unsigned char sc_data_direction;
+ unsigned char sc_old_data_direction;
/* These elements define the operation we are about to perform */
unsigned char cmnd[MAX_COMMAND_SIZE];
@@ -665,7 +773,7 @@ struct scsi_cmnd {
struct request request; /* A copy of the command we are
working on */
- unsigned char sense_buffer[64]; /* obtained by REQUEST SENSE
+ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE
* when CHECK CONDITION is
* received on original command
* (auto-sense) */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 773dc0087..7268bc154 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -408,6 +408,7 @@ STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
@@ -464,6 +465,7 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = 256;
SCpnt->use_sg = 0;
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
@@ -486,6 +488,7 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* Hey, we are done. Let's look to see what happened.
@@ -531,6 +534,7 @@ STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
SCpnt->use_sg = 0;
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+ SCpnt->sc_data_direction = SCSI_DATA_NONE;
/* Last chance to have valid sense data */
if (!scsi_sense_valid(SCpnt))
@@ -551,6 +555,7 @@ STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* Hey, we are done. Let's look to see what happened.
@@ -730,6 +735,7 @@ STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt)
* things.
*/
SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
*SClist = SCpnt;
}
@@ -1245,6 +1251,7 @@ STATIC void scsi_restart_operations(struct Scsi_Host *host)
request_queue_t *q;
if ((host->can_queue > 0 && (host->host_busy >= host->can_queue))
|| (host->host_blocked)
+ || (host->host_self_blocked)
|| (SDpnt->device_blocked)) {
break;
}
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 56ad67646..abdef85ef 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -105,6 +105,7 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
return -EINTR;
}
+ SCpnt->sc_data_direction = SCSI_DATA_NONE;
scsi_wait_cmd(SCpnt, cmd, NULL, 0, timeout, retries);
SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result));
@@ -197,6 +198,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
int inlen, outlen, cmdlen;
int needed, buf_needed;
int timeout, retries, result;
+ int data_direction;
if (!sic)
return -EINVAL;
@@ -232,8 +234,21 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
if (!buf)
return -ENOMEM;
memset(buf, 0, buf_needed);
- } else
+ if( inlen == 0 ) {
+ data_direction = SCSI_DATA_WRITE;
+ } else if (outlen == 0 ) {
+ data_direction = SCSI_DATA_READ;
+ } else {
+ /*
+ * Can this ever happen?
+ */
+ data_direction = SCSI_DATA_UNKNOWN;
+ }
+
+ } else {
buf = NULL;
+ data_direction = SCSI_DATA_NONE;
+ }
/*
* Obtain the command from the user's address space.
@@ -288,6 +303,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
return -EINTR;
}
+ SCpnt->sc_data_direction = data_direction;
scsi_wait_cmd(SCpnt, cmd, buf, needed, timeout, retries);
/*
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9ec2fe281..2438aecc6 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -86,6 +86,7 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
q = &SCpnt->device->request_queue;
SCpnt->request.cmd = SPECIAL;
SCpnt->request.special = (void *) SCpnt;
+ SCpnt->request.q = NULL;
/*
* We have the option of inserting the head or the tail of the queue.
@@ -96,8 +97,7 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
spin_lock_irqsave(&io_request_lock, flags);
if (at_head) {
- SCpnt->request.next = q->current_request;
- q->current_request = &SCpnt->request;
+ list_add(&SCpnt->request.queue, &q->queue_head);
} else {
/*
* FIXME(eric) - we always insert at the tail of the
@@ -107,19 +107,75 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
* request might not float high enough in the queue
* to be scheduled.
*/
- SCpnt->request.next = NULL;
- if (q->current_request == NULL) {
- q->current_request = &SCpnt->request;
- } else {
- struct request *req;
+ list_add_tail(&SCpnt->request.queue, &q->queue_head);
+ }
- for (req = q->current_request; req; req = req->next) {
- if (req->next == NULL) {
- req->next = &SCpnt->request;
- break;
- }
- }
- }
+ /*
+ * Now hit the requeue function for the queue. If the host is
+ * already busy, so be it - we have nothing special to do. If
+ * the host can queue it, then send it off.
+ */
+ q->request_fn(q);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return 0;
+}
+
+/*
+ * Function: scsi_insert_special_req()
+ *
+ * Purpose: Insert pre-formed request into request queue.
+ *
+ * Arguments: SRpnt - request that is ready to be queued.
+ * at_head - boolean. True if we should insert at head
+ * of queue, false if we should insert at tail.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns: Nothing
+ *
+ * Notes: This function is called from character device and from
+ * ioctl types of functions where the caller knows exactly
+ * what SCSI command needs to be issued. The idea is that
+ * we merely inject the command into the queue (at the head
+ * for now), and then call the queue request function to actually
+ * process it.
+ */
+int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
+{
+ unsigned long flags;
+ request_queue_t *q;
+
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ /*
+ * The SCpnt already contains a request structure - we will doctor the
+ * thing up with the appropriate values and use that in the actual
+ * request queue.
+ */
+ q = &SRpnt->sr_device->request_queue;
+ SRpnt->sr_request.cmd = SPECIAL;
+ SRpnt->sr_request.special = (void *) SRpnt;
+
+ /*
+ * We have the option of inserting the head or the tail of the queue.
+ * Typically we use the tail for new ioctls and so forth. We use the
+ * head of the queue for things like a QUEUE_FULL message from a
+ * device, or a host that is unable to accept a particular command.
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ if (at_head) {
+ list_add(&SRpnt->sr_request.queue, &q->queue_head);
+ } else {
+ /*
+ * FIXME(eric) - we always insert at the tail of the
+ * list. Otherwise ioctl commands would always take
+ * precedence over normal I/O. An ioctl on a busy
+ * disk might be delayed indefinitely because the
+ * request might not float high enough in the queue
+ * to be scheduled.
+ */
+ list_add_tail(&SRpnt->sr_request.queue, &q->queue_head);
}
/*
@@ -172,6 +228,7 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
*/
SCpnt->old_use_sg = SCpnt->use_sg;
SCpnt->old_cmd_len = SCpnt->cmd_len;
+ SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
memcpy((void *) SCpnt->data_cmnd,
(const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
SCpnt->buffer = SCpnt->request_buffer;
@@ -239,9 +296,8 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
* in which case we need to request the blocks that come after
* the bad sector.
*/
- SCpnt->request.next = q->current_request;
- q->current_request = &SCpnt->request;
SCpnt->request.special = (void *) SCpnt;
+ list_add(&SCpnt->request.queue, &q->queue_head);
}
/*
@@ -260,7 +316,7 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
* use function pointers to pick the right one.
*/
if (SDpnt->single_lun
- && q->current_request == NULL
+ && list_empty(&q->queue_head)
&& SDpnt->device_busy == 0) {
request_queue_t *q;
@@ -270,6 +326,7 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
if (((SHpnt->can_queue > 0)
&& (SHpnt->host_busy >= SHpnt->can_queue))
|| (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)
|| (SDpnt->device_blocked)) {
break;
}
@@ -291,7 +348,8 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
request_queue_t *q;
if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
- || (SHpnt->host_blocked)) {
+ || (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)) {
break;
}
if (SDpnt->device_blocked || !SDpnt->starved) {
@@ -772,6 +830,7 @@ void scsi_request_fn(request_queue_t * q)
{
struct request *req;
Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
struct Scsi_Device_Template *STpnt;
@@ -802,13 +861,24 @@ void scsi_request_fn(request_queue_t * q)
*/
while (1 == 1) {
/*
+ * Check this again - each time we loop through we will have
+ * released the lock and grabbed it again, so each time
+ * we need to check to see if the queue is plugged or not.
+ */
+ if (SHpnt->in_recovery
+ || q->plugged) {
+ return;
+ }
+
+ /*
* If the device cannot accept another request, then quit.
*/
if (SDpnt->device_blocked) {
break;
}
if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
- || (SHpnt->host_blocked)) {
+ || (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)) {
/*
* If we are unable to process any commands at all for this
* device, then we consider it to be starved. What this means
@@ -850,18 +920,18 @@ void scsi_request_fn(request_queue_t * q)
}
/*
- * Loop through all of the requests in this queue, and find
- * one that is queueable.
- */
- req = q->current_request;
-
- /*
* If we couldn't find a request that could be queued, then we
* can also quit.
*/
- if (!req) {
+ if (list_empty(&q->queue_head))
break;
- }
+
+ /*
+ * Loop through all of the requests in this queue, and find
+ * one that is queueable.
+ */
+ req = blkdev_entry_next_request(&q->queue_head);
+
/*
* Find the actual device driver associated with this command.
* The SPECIAL requests are things like character device or
@@ -875,6 +945,14 @@ void scsi_request_fn(request_queue_t * q)
if (req->cmd == SPECIAL) {
STpnt = NULL;
SCpnt = (Scsi_Cmnd *) req->special;
+ SRpnt = (Scsi_Request *) req->special;
+
+ if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
+ SCpnt = scsi_allocate_device(SRpnt->sr_device,
+ FALSE, FALSE);
+ scsi_init_cmd_from_req(SCpnt, SRpnt);
+ }
+
} else {
STpnt = scsi_get_request_dev(req);
if (!STpnt) {
@@ -922,8 +1000,7 @@ void scsi_request_fn(request_queue_t * q)
* reason to search the list, because all of the commands
* in this queue are for the same device.
*/
- q->current_request = req->next;
- SCpnt->request.next = NULL;
+ blkdev_dequeue_request(req);
if (req != &SCpnt->request) {
memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -932,7 +1009,6 @@ void scsi_request_fn(request_queue_t * q)
* We have copied the data out of the request block - it is now in
* a field in SCpnt. Release the request block.
*/
- req->next = NULL;
req->rq_status = RQ_INACTIVE;
wake_up(&wait_for_request);
}
@@ -1005,6 +1081,85 @@ void scsi_request_fn(request_queue_t * q)
}
/*
+ * Function: scsi_block_requests()
+ *
+ * Purpose: Utility function used by low-level drivers to prevent further
+ * commands from being queued to the device.
+ *
+ * Arguments: SHpnt - Host in question
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: There is no timer nor any other means by which the requests
+ * get unblocked other than the low-level driver calling
+ * scsi_unblock_requests().
+ */
+void scsi_block_requests(struct Scsi_Host * SHpnt)
+{
+ SHpnt->host_self_blocked = TRUE;
+}
+
+/*
+ * Function: scsi_unblock_requests()
+ *
+ * Purpose: Utility function used by low-level drivers to allow further
+ * commands from being queued to the device.
+ *
+ * Arguments: SHpnt - Host in question
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: There is no timer nor any other means by which the requests
+ * get unblocked other than the low-level driver calling
+ * scsi_unblock_requests().
+ *
+ * This is done as an API function so that changes to the
+ * internals of the scsi mid-layer won't require wholesale
+ * changes to drivers that use this feature.
+ */
+void scsi_unblock_requests(struct Scsi_Host * SHpnt)
+{
+ SHpnt->host_self_blocked = FALSE;
+}
+
+
+/*
+ * Function: scsi_report_bus_reset()
+ *
+ * Purpose: Utility function used by low-level drivers to report that
+ * they have observed a bus reset on the bus being handled.
+ *
+ * Arguments: SHpnt - Host in question
+ * channel - channel on which reset was observed.
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: This only needs to be called if the reset is one which
+ * originates from an unknown location. Resets originated
+ * by the mid-level itself don't need to call this, but there
+ * should be no harm.
+ *
+ * The main purpose of this is to make sure that a CHECK_CONDITION
+ * is properly treated.
+ */
+void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel)
+{
+ Scsi_Device *SDloop;
+ for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {
+ if (channel == SDloop->channel) {
+ SDloop->was_reset = 1;
+ SDloop->expecting_cc_ua = 1;
+ }
+ }
+}
+
+/*
* FIXME(eric) - these are empty stubs for the moment. I need to re-implement
* host blocking from scratch. The theory is that hosts that wish to block
* will register/deregister using these functions instead of the old way
diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
index c9a1edb60..d917d9306 100644
--- a/drivers/scsi/scsi_merge.c
+++ b/drivers/scsi/scsi_merge.c
@@ -307,6 +307,69 @@ recount_segments(Scsi_Cmnd * SCpnt)
(((((long)(X)->b_data+(X)->b_size)|((long)(Y)->b_data)) & \
(DMA_CHUNK_SIZE - 1)) == 0)
+#ifdef DMA_CHUNK_SIZE
+static inline int scsi_new_mergeable(request_queue_t * q,
+ struct request * req,
+ struct Scsi_Host *SHpnt,
+ int max_segments)
+{
+ /*
+ * pci_map_sg will be able to merge these two
+ * into a single hardware sg entry, check if
+ * we'll have enough memory for the sg list.
+ * scsi.c allocates for this purpose
+ * min(64,sg_tablesize) entries.
+ */
+ if (req->nr_segments >= max_segments &&
+ req->nr_segments >= SHpnt->sg_tablesize)
+ return 0;
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
+}
+
+static inline int scsi_new_segment(request_queue_t * q,
+ struct request * req,
+ struct Scsi_Host *SHpnt,
+ int max_segments)
+{
+ /*
+ * pci_map_sg won't be able to map these two
+ * into a single hardware sg entry, so we have to
+ * check if things fit into sg_tablesize.
+ */
+ if (req->nr_hw_segments >= SHpnt->sg_tablesize ||
+ (req->nr_segments >= max_segments &&
+ req->nr_segments >= SHpnt->sg_tablesize))
+ return 0;
+ if (req->nr_segments >= max_segments)
+ return 0;
+ req->nr_hw_segments++;
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
+}
+#else
+static inline int scsi_new_segment(request_queue_t * q,
+ struct request * req,
+ struct Scsi_Host *SHpnt,
+ int max_segments)
+{
+ if (req->nr_segments < SHpnt->sg_tablesize &&
+ req->nr_segments < max_segments) {
+ /*
+ * This will form the start of a new segment. Bump the
+ * counter.
+ */
+ req->nr_segments++;
+ q->nr_segments++;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+#endif
+
/*
* Function: __scsi_merge_fn()
*
@@ -340,13 +403,14 @@ recount_segments(Scsi_Cmnd * SCpnt)
* than to have 4 separate functions all doing roughly the
* same thing.
*/
-__inline static int __scsi_merge_fn(request_queue_t * q,
- struct request *req,
- struct buffer_head *bh,
- int use_clustering,
- int dma_host)
+__inline static int __scsi_back_merge_fn(request_queue_t * q,
+ struct request *req,
+ struct buffer_head *bh,
+ int max_segments,
+ int use_clustering,
+ int dma_host)
{
- unsigned int sector, count;
+ unsigned int count;
unsigned int segment_size = 0;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
@@ -354,130 +418,97 @@ __inline static int __scsi_merge_fn(request_queue_t * q,
SDpnt = (Scsi_Device *) q->queuedata;
SHpnt = SDpnt->host;
- count = bh->b_size >> 9;
- sector = bh->b_rsector;
+ if (max_segments > 64)
+ max_segments = 64;
- /*
- * We come in here in one of two cases. The first is that we
- * are checking to see if we can add the buffer to the end of the
- * request, the other is to see if we should add the request to the
- * start.
- */
- if (req->sector + req->nr_sectors == sector) {
- if (use_clustering) {
- /*
- * See if we can do this without creating another
- * scatter-gather segment. In the event that this is a
- * DMA capable host, make sure that a segment doesn't span
- * the DMA threshold boundary.
- */
- if (dma_host &&
- virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
- goto new_end_segment;
- }
- if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
+ if (use_clustering) {
+ /*
+ * See if we can do this without creating another
+ * scatter-gather segment. In the event that this is a
+ * DMA capable host, make sure that a segment doesn't span
+ * the DMA threshold boundary.
+ */
+ if (dma_host &&
+ virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
+ goto new_end_segment;
+ }
+ if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
#ifdef DMA_SEGMENT_SIZE_LIMITED
- if( dma_host
- && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
- segment_size = 0;
- count = __count_segments(req, use_clustering, dma_host, &segment_size);
- if( segment_size + bh->b_size > PAGE_SIZE ) {
- goto new_end_segment;
- }
+ if( dma_host
+ && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+ segment_size = 0;
+ count = __count_segments(req, use_clustering, dma_host, &segment_size);
+ if( segment_size + bh->b_size > PAGE_SIZE ) {
+ goto new_end_segment;
}
-#endif
- /*
- * This one is OK. Let it go.
- */
- return 1;
}
+#endif
+ /*
+ * This one is OK. Let it go.
+ */
+ return 1;
}
- new_end_segment:
+ }
+ new_end_segment:
#ifdef DMA_CHUNK_SIZE
- if (MERGEABLE_BUFFERS(req->bhtail, bh))
- goto new_mergeable;
+ if (MERGEABLE_BUFFERS(req->bhtail, bh))
+ return scsi_new_mergeable(q, req, SHpnt, max_segments);
#endif
- goto new_segment;
- } else {
- if (req->sector - count != sector) {
- /* Attempt to merge sector that doesn't belong */
- BUG();
+ return scsi_new_segment(q, req, SHpnt, max_segments);
+}
+
+__inline static int __scsi_front_merge_fn(request_queue_t * q,
+ struct request *req,
+ struct buffer_head *bh,
+ int max_segments,
+ int use_clustering,
+ int dma_host)
+{
+ unsigned int count;
+ unsigned int segment_size = 0;
+ Scsi_Device *SDpnt;
+ struct Scsi_Host *SHpnt;
+
+ SDpnt = (Scsi_Device *) q->queuedata;
+ SHpnt = SDpnt->host;
+
+ if (max_segments > 64)
+ max_segments = 64;
+
+ if (use_clustering) {
+ /*
+ * See if we can do this without creating another
+ * scatter-gather segment. In the event that this is a
+ * DMA capable host, make sure that a segment doesn't span
+ * the DMA threshold boundary.
+ */
+ if (dma_host &&
+ virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) {
+ goto new_start_segment;
}
- if (use_clustering) {
- /*
- * See if we can do this without creating another
- * scatter-gather segment. In the event that this is a
- * DMA capable host, make sure that a segment doesn't span
- * the DMA threshold boundary.
- */
- if (dma_host &&
- virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) {
- goto new_start_segment;
- }
- if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
+ if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
#ifdef DMA_SEGMENT_SIZE_LIMITED
- if( dma_host
- && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
- segment_size = bh->b_size;
- count = __count_segments(req, use_clustering, dma_host, &segment_size);
- if( count != req->nr_segments ) {
- goto new_start_segment;
- }
+ if( dma_host
+ && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+ segment_size = bh->b_size;
+ count = __count_segments(req, use_clustering, dma_host, &segment_size);
+ if( count != req->nr_segments ) {
+ goto new_start_segment;
}
-#endif
- /*
- * This one is OK. Let it go.
- */
- return 1;
}
- }
- new_start_segment:
-#ifdef DMA_CHUNK_SIZE
- if (MERGEABLE_BUFFERS(bh, req->bh))
- goto new_mergeable;
#endif
- goto new_segment;
+ /*
+ * This one is OK. Let it go.
+ */
+ return 1;
+ }
}
+ new_start_segment:
#ifdef DMA_CHUNK_SIZE
- new_mergeable:
- /*
- * pci_map_sg will be able to merge these two
- * into a single hardware sg entry, check if
- * we'll have enough memory for the sg list.
- * scsi.c allocates for this purpose
- * min(64,sg_tablesize) entries.
- */
- if (req->nr_segments >= 64 &&
- req->nr_segments >= SHpnt->sg_tablesize)
- return 0;
- req->nr_segments++;
- return 1;
- new_segment:
- /*
- * pci_map_sg won't be able to map these two
- * into a single hardware sg entry, so we have to
- * check if things fit into sg_tablesize.
- */
- if (req->nr_hw_segments >= SHpnt->sg_tablesize ||
- (req->nr_segments >= 64 &&
- req->nr_segments >= SHpnt->sg_tablesize))
- return 0;
- req->nr_hw_segments++;
- req->nr_segments++;
- return 1;
-#else
- new_segment:
- if (req->nr_segments < SHpnt->sg_tablesize) {
- /*
- * This will form the start of a new segment. Bump the
- * counter.
- */
- req->nr_segments++;
- return 1;
- } else {
- return 0;
- }
+ if (MERGEABLE_BUFFERS(bh, req->bh))
+ return scsi_new_mergeable(q, req, SHpnt, max_segments);
#endif
+ return scsi_new_segment(q, req, SHpnt, max_segments);
}
/*
@@ -497,23 +528,34 @@ __inline static int __scsi_merge_fn(request_queue_t * q,
* Notes: Optimized for different cases depending upon whether
* ISA DMA is in use and whether clustering should be used.
*/
-#define MERGEFCT(_FUNCTION, _CLUSTER, _DMA) \
-static int _FUNCTION(request_queue_t * q, \
- struct request * req, \
- struct buffer_head * bh) \
-{ \
- int ret; \
- SANITY_CHECK(req, _CLUSTER, _DMA); \
- ret = __scsi_merge_fn(q, req, bh, _CLUSTER, _DMA); \
- return ret; \
+#define MERGEFCT(_FUNCTION, _BACK_FRONT, _CLUSTER, _DMA) \
+static int _FUNCTION(request_queue_t * q, \
+ struct request * req, \
+ struct buffer_head * bh, \
+ int max_segments) \
+{ \
+ int ret; \
+ SANITY_CHECK(req, _CLUSTER, _DMA); \
+ ret = __scsi_ ## _BACK_FRONT ## _merge_fn(q, \
+ req, \
+ bh, \
+ max_segments, \
+ _CLUSTER, \
+ _DMA); \
+ return ret; \
}
/* Version with use_clustering 0 and dma_host 1 is not necessary,
* since the only use of dma_host above is protected by use_clustering.
*/
-MERGEFCT(scsi_merge_fn_, 0, 0)
-MERGEFCT(scsi_merge_fn_c, 1, 0)
-MERGEFCT(scsi_merge_fn_dc, 1, 1)
+MERGEFCT(scsi_back_merge_fn_, back, 0, 0)
+MERGEFCT(scsi_back_merge_fn_c, back, 1, 0)
+MERGEFCT(scsi_back_merge_fn_dc, back, 1, 1)
+
+MERGEFCT(scsi_front_merge_fn_, front, 0, 0)
+MERGEFCT(scsi_front_merge_fn_c, front, 1, 0)
+MERGEFCT(scsi_front_merge_fn_dc, front, 1, 1)
+
/*
* Function: __scsi_merge_requests_fn()
*
@@ -550,6 +592,7 @@ MERGEFCT(scsi_merge_fn_dc, 1, 1)
__inline static int __scsi_merge_requests_fn(request_queue_t * q,
struct request *req,
struct request *next,
+ int max_segments,
int use_clustering,
int dma_host)
{
@@ -559,11 +602,14 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
SDpnt = (Scsi_Device *) q->queuedata;
SHpnt = SDpnt->host;
+ if (max_segments > 64)
+ max_segments = 64;
+
#ifdef DMA_CHUNK_SIZE
/* If it would not fit into prepared memory space for sg chain,
* then don't allow the merge.
*/
- if (req->nr_segments + next->nr_segments - 1 > 64 &&
+ if (req->nr_segments + next->nr_segments - 1 > max_segments &&
req->nr_segments + next->nr_segments - 1 > SHpnt->sg_tablesize) {
return 0;
}
@@ -619,6 +665,7 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
* This one is OK. Let it go.
*/
req->nr_segments += next->nr_segments - 1;
+ q->nr_segments--;
#ifdef DMA_CHUNK_SIZE
req->nr_hw_segments += next->nr_hw_segments - 1;
#endif
@@ -627,7 +674,7 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
}
dont_combine:
#ifdef DMA_CHUNK_SIZE
- if (req->nr_segments + next->nr_segments > 64 &&
+ if (req->nr_segments + next->nr_segments > max_segments &&
req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
return 0;
}
@@ -650,7 +697,8 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
* Make sure we can fix something that is the sum of the two.
* A slightly stricter test than we had above.
*/
- if (req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
+ if (req->nr_segments + next->nr_segments > max_segments &&
+ req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
return 0;
} else {
/*
@@ -683,11 +731,12 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
#define MERGEREQFCT(_FUNCTION, _CLUSTER, _DMA) \
static int _FUNCTION(request_queue_t * q, \
struct request * req, \
- struct request * next) \
+ struct request * next, \
+ int max_segments) \
{ \
int ret; \
SANITY_CHECK(req, _CLUSTER, _DMA); \
- ret = __scsi_merge_requests_fn(q, req, next, _CLUSTER, _DMA); \
+ ret = __scsi_merge_requests_fn(q, req, next, max_segments, _CLUSTER, _DMA); \
return ret; \
}
@@ -1068,7 +1117,7 @@ void initialize_merge_fn(Scsi_Device * SDpnt)
* pick a new one.
*/
#if 0
- if (q->merge_fn != NULL)
+ if (q->back_merge_fn && q->front_merge_fn)
return;
#endif
/*
@@ -1083,19 +1132,23 @@ void initialize_merge_fn(Scsi_Device * SDpnt)
* rather than rely upon the default behavior of ll_rw_blk.
*/
if (!CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0) {
- q->merge_fn = scsi_merge_fn_;
+ q->back_merge_fn = scsi_back_merge_fn_;
+ q->front_merge_fn = scsi_front_merge_fn_;
q->merge_requests_fn = scsi_merge_requests_fn_;
SDpnt->scsi_init_io_fn = scsi_init_io_v;
} else if (!CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0) {
- q->merge_fn = scsi_merge_fn_;
+ q->back_merge_fn = scsi_back_merge_fn_;
+ q->front_merge_fn = scsi_front_merge_fn_;
q->merge_requests_fn = scsi_merge_requests_fn_;
SDpnt->scsi_init_io_fn = scsi_init_io_vd;
} else if (CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma == 0) {
- q->merge_fn = scsi_merge_fn_c;
+ q->back_merge_fn = scsi_back_merge_fn_c;
+ q->front_merge_fn = scsi_front_merge_fn_c;
q->merge_requests_fn = scsi_merge_requests_fn_c;
SDpnt->scsi_init_io_fn = scsi_init_io_vc;
} else if (CLUSTERABLE_DEVICE(SHpnt, SDpnt) && SHpnt->unchecked_isa_dma != 0) {
- q->merge_fn = scsi_merge_fn_dc;
+ q->back_merge_fn = scsi_back_merge_fn_dc;
+ q->front_merge_fn = scsi_front_merge_fn_dc;
q->merge_requests_fn = scsi_merge_requests_fn_dc;
SDpnt->scsi_init_io_fn = scsi_init_io_vdc;
}
diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c
index ee1041d88..a957a4c01 100644
--- a/drivers/scsi/scsi_obsolete.c
+++ b/drivers/scsi/scsi_obsolete.c
@@ -231,6 +231,8 @@ static void scsi_request_sense(Scsi_Cmnd * SCpnt)
SCpnt->use_sg = 0;
SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
SCpnt->result = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
+
/*
* Ugly, ugly. The newer interfaces all assume that the lock
* isn't held. Mustn't disappoint, or we deadlock the system.
@@ -374,6 +376,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
if (SCpnt->flags & WAS_SENSE) {
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
}
switch (host_byte(result)) {
case DID_OK:
@@ -633,6 +636,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
SCpnt->result = 0;
/*
* Ugly, ugly. The newer interfaces all
@@ -649,6 +653,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
}
if (status == CMD_FINISHED) {
+ Scsi_Request *SRpnt;
#ifdef DEBUG
printk("Calling done function - at address %p\n", SCpnt->done);
#endif
@@ -658,6 +663,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
SCpnt->result = result | ((exit & 0xff) << 24);
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
/*
* The upper layers assume the lock isn't held. We mustn't
* disappoint them. When the new error handling code is in
@@ -665,6 +671,16 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
* it isn't an issue.
*/
spin_unlock_irq(&io_request_lock);
+ SRpnt = SCpnt->sc_request;
+ if( SRpnt != NULL ) {
+ SRpnt->sr_result = SRpnt->sr_command->result;
+ if( SRpnt->sr_result != 0 ) {
+ memcpy(SRpnt->sr_sense_buffer,
+ SRpnt->sr_command->sense_buffer,
+ sizeof(SRpnt->sr_sense_buffer));
+ }
+ }
+
SCpnt->done(SCpnt);
spin_lock_irq(&io_request_lock);
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 645edb67c..40a7cb124 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -455,6 +455,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
int *sparse_lun, Scsi_Device ** SDpnt2,
struct Scsi_Host *shpnt, char *scsi_result)
{
+ char devname[64];
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
struct Scsi_Device_Template *sdtpnt;
Scsi_Device *SDtail, *SDpnt = *SDpnt2;
@@ -462,6 +463,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
int bflags, type = -1;
static int ghost_channel=-1, ghost_dev=-1;
int org_lun = lun;
+ extern devfs_handle_t scsi_devfs_handle;
SDpnt->host = shpnt;
SDpnt->id = dev;
@@ -500,6 +502,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
SCpnt->target = SDpnt->id;
SCpnt->lun = SDpnt->lun;
SCpnt->channel = SDpnt->channel;
+ SCpnt->sc_data_direction = SCSI_DATA_NONE;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
(void *) NULL,
@@ -537,6 +540,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[4] = 255;
scsi_cmd[5] = 0;
SCpnt->cmd_len = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
(void *) scsi_result,
@@ -637,6 +641,11 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
print_inquiry(scsi_result);
+ sprintf (devname, "host%d/bus%d/target%d/lun%d",
+ SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
+ if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
+ else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, 0, NULL);
+
for (sdtpnt = scsi_devicelist; sdtpnt;
sdtpnt = sdtpnt->next)
if (sdtpnt->detect)
@@ -696,6 +705,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[4] = 0x2a;
scsi_cmd[5] = 0;
SCpnt->cmd_len = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
(void *) scsi_result, 0x2a,
SCSI_TIMEOUT, 3);
diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
index 3379299d8..f6e8939a6 100644
--- a/drivers/scsi/scsi_syms.c
+++ b/drivers/scsi/scsi_syms.c
@@ -28,16 +28,11 @@
#include "sd.h"
#include <scsi/scsicam.h>
+
/*
* This source file contains the symbol table used by scsi loadable
* modules.
*/
-
-extern void print_command(unsigned char *command);
-extern void print_sense(const char *devclass, Scsi_Cmnd * SCpnt);
-
-extern const char *const scsi_device_types[];
-
EXPORT_SYMBOL(scsi_register_module);
EXPORT_SYMBOL(scsi_unregister_module);
EXPORT_SYMBOL(scsi_free);
@@ -53,6 +48,7 @@ EXPORT_SYMBOL(scsi_command_size);
EXPORT_SYMBOL(scsi_ioctl);
EXPORT_SYMBOL(print_command);
EXPORT_SYMBOL(print_sense);
+EXPORT_SYMBOL(print_req_sense);
EXPORT_SYMBOL(print_msg);
EXPORT_SYMBOL(print_status);
EXPORT_SYMBOL(scsi_dma_free_sectors);
@@ -67,6 +63,15 @@ EXPORT_SYMBOL(scsi_ioctl_send_command);
EXPORT_SYMBOL(scsi_logging_level);
#endif
+EXPORT_SYMBOL(scsi_allocate_request);
+EXPORT_SYMBOL(scsi_release_request);
+EXPORT_SYMBOL(scsi_wait_req);
+EXPORT_SYMBOL(scsi_do_req);
+
+EXPORT_SYMBOL(scsi_report_bus_reset);
+EXPORT_SYMBOL(scsi_block_requests);
+EXPORT_SYMBOL(scsi_unblock_requests);
+
EXPORT_SYMBOL(scsi_get_host_dev);
EXPORT_SYMBOL(scsi_free_host_dev);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a897c9597..43187600b 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -17,6 +17,8 @@
*
* Modified by Jirka Hanika geo@ff.cuni.cz to support more
* scsi disks using eight major numbers.
+ *
+ * Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs.
*/
#include <linux/config.h>
@@ -307,9 +309,11 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
return 0;
}
SCpnt->cmnd[0] = WRITE_6;
+ SCpnt->sc_data_direction = SCSI_DATA_WRITE;
break;
case READ:
SCpnt->cmnd[0] = READ_6;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
break;
default:
panic("Unknown sd command %d\n", SCpnt->request.cmd);
@@ -489,7 +493,8 @@ static struct gendisk sd_gendisk =
NULL, /* block sizes */
0, /* number */
NULL, /* internal */
- NULL /* next */
+ NULL, /* next */
+ &sd_fops, /* file operations */
};
static struct gendisk *sd_gendisks = &sd_gendisk;
@@ -692,6 +697,7 @@ static int sd_init_onedisk(int i)
SCpnt->cmd_len = 0;
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, MAX_RETRIES);
@@ -703,6 +709,22 @@ static int sd_init_onedisk(int i)
break;
}
+ /*
+ * If the drive has indicated to us that it doesn't have
+ * any media in it, don't bother with any of the rest of
+ * this crap.
+ */
+ if( the_result != 0
+ && ((driver_byte(the_result) & DRIVER_SENSE) != 0)
+ && SCpnt->sense_buffer[2] == UNIT_ATTENTION
+ && SCpnt->sense_buffer[12] == 0x3A ) {
+ rscsi_disks[i].capacity = 0x1fffff;
+ sector_size = 512;
+ rscsi_disks[i].device->changed = 1;
+ rscsi_disks[i].ready = 0;
+ break;
+ }
+
/* Look for non-removable devices that return NOT_READY.
* Issue command to spin up drive for these cases. */
if (the_result && !rscsi_disks[i].device->removable &&
@@ -719,8 +741,9 @@ static int sd_init_onedisk(int i)
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
- 512, SD_TIMEOUT, MAX_RETRIES);
+ 0/*512*/, SD_TIMEOUT, MAX_RETRIES);
}
spintime = 1;
spintime_value = jiffies;
@@ -749,6 +772,7 @@ static int sd_init_onedisk(int i)
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
8, SD_TIMEOUT, MAX_RETRIES);
@@ -900,6 +924,7 @@ static int sd_init_onedisk(int i)
SCpnt->sense_buffer[2] = 0;
/* same code as READCAPA !! */
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
512, SD_TIMEOUT, MAX_RETRIES);
@@ -948,7 +973,7 @@ static int sd_init()
if (!sd_registered) {
for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
- if (register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) {
+ if (devfs_register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) {
printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i));
return 1;
}
@@ -988,6 +1013,15 @@ static int sd_init()
sd_gendisks = (struct gendisk *)
kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
for (i = 0; i < N_USED_SD_MAJORS; i++) {
+ sd_gendisks[i] = sd_gendisk;
+ sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr,
+ GFP_ATOMIC);
+ memset (sd_gendisks[i].de_arr, 0,
+ SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr);
+ sd_gendisks[i].flags = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags,
+ GFP_ATOMIC);
+ memset (sd_gendisks[i].flags, 0,
+ SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags);
sd_gendisks[i].major = SD_MAJOR(i);
sd_gendisks[i].major_name = "sd";
sd_gendisks[i].minor_shift = 4;
@@ -1061,8 +1095,10 @@ static int sd_detect(Scsi_Device * SDp)
return 1;
}
+
static int sd_attach(Scsi_Device * SDp)
{
+ unsigned int devnum;
Scsi_Disk *dpnt;
int i;
@@ -1084,6 +1120,10 @@ static int sd_attach(Scsi_Device * SDp)
rscsi_disks[i].has_part_table = 0;
sd_template.nr_dev++;
SD_GENDISK(i).nr_real++;
+ devnum = i % SCSI_DISKS_PER_MAJOR;
+ SD_GENDISK(i).de_arr[devnum] = SDp->de;
+ if (SDp->removable)
+ SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE;
return 0;
}
@@ -1182,6 +1222,8 @@ static void sd_detach(Scsi_Device * SDp)
sd_gendisks->part[index].nr_sects = 0;
sd_sizes[index] = 0;
}
+ devfs_register_partitions (&SD_GENDISK (i),
+ SD_MINOR_NUMBER (start), 1);
/* unregister_disk() */
dpnt->has_part_table = 0;
dpnt->device = NULL;
@@ -1212,7 +1254,7 @@ void cleanup_module(void)
scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++)
- unregister_blkdev(SD_MAJOR(i), "sd");
+ devfs_unregister_blkdev(SD_MAJOR(i), "sd");
sd_registered--;
if (rscsi_disks != NULL) {
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index e092f40a1..2ccf9ac09 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -9,6 +9,8 @@
* Version 2 and 3 extensions to driver:
* Copyright (C) 1998, 1999 Douglas Gilbert
*
+ * Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -50,6 +52,7 @@
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
+
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -179,6 +182,7 @@ typedef struct sg_device /* holds the state of each scsi generic device */
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
Sg_fd * headfp; /* first open fd belonging to this device */
+ devfs_handle_t de;
kdev_t i_rdev; /* holds device major+minor number */
char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
@@ -1075,7 +1079,7 @@ static int sg_init()
if (sg_template.dev_noticed == 0) return 0;
if(!sg_registered) {
- if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
+ if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
{
printk("Unable to get major %d for generic SCSI device\n",
SCSI_GENERIC_MAJOR);
@@ -1150,6 +1154,10 @@ static int sg_attach(Scsi_Device * scsidp)
sdp->sgdebug = 0;
sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
+ sdp->de = devfs_register (scsidp->de, "generic", 7, DEVFS_FL_NONE,
+ SCSI_GENERIC_MAJOR, k,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ &sg_fops, NULL);
sg_template.nr_dev++;
return 0;
}
@@ -1194,6 +1202,8 @@ static void sg_detach(Scsi_Device * scsidp)
SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
sdp->device = NULL;
}
+ devfs_unregister (sdp->de);
+ sdp->de = NULL;
scsidp->attached--;
sg_template.nr_dev--;
/* avoid associated device /dev/sg? being incremented
@@ -1219,7 +1229,7 @@ int init_module(void) {
void cleanup_module( void)
{
scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
- unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
+ devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
#ifdef CONFIG_PROC_FS
sg_proc_cleanup();
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 365c90660..35f18a53c 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -23,6 +23,8 @@
* Modified by Jens Axboe <axboe@image.dk> - Uniform sr_packet()
* interface, capabilities probe additions, ioctl cleanups, etc.
*
+ * Modified by Richard Gooch <rgooch@atnf.csiro.au> to support devfs
+ *
*/
#include <linux/module.h>
@@ -87,7 +89,6 @@ static int sr_open(struct cdrom_device_info *, int);
void get_sectorsize(int);
void get_capabilities(int);
-void requeue_sr_request(Scsi_Cmnd * SCpnt);
static int sr_media_change(struct cdrom_device_info *, int);
static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
@@ -325,9 +326,11 @@ static int sr_init_command(Scsi_Cmnd * SCpnt)
return 0;
}
SCpnt->cmnd[0] = WRITE_10;
+ SCpnt->sc_data_direction = SCSI_DATA_WRITE;
break;
case READ:
SCpnt->cmnd[0] = READ_10;
+ SCpnt->sc_data_direction = SCSI_DATA_READ;
break;
default:
panic("Unknown sr command %d\n", SCpnt->request.cmd);
@@ -462,36 +465,37 @@ void get_sectorsize(int i)
unsigned char *buffer;
int the_result, retries;
int sector_size;
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
buffer = (unsigned char *) scsi_malloc(512);
- SCpnt = scsi_allocate_device(scsi_CDs[i].device, 1, FALSE);
+ SRpnt = scsi_allocate_request(scsi_CDs[i].device);
retries = 3;
do {
cmd[0] = READ_CAPACITY;
cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
memset((void *) &cmd[2], 0, 8);
- SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */
- SCpnt->cmd_len = 0;
+ SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */
+ SRpnt->sr_cmd_len = 0;
memset(buffer, 0, 8);
/* Do the command and wait.. */
- scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
512, SR_TIMEOUT, MAX_RETRIES);
- the_result = SCpnt->result;
+ the_result = SRpnt->sr_result;
retries--;
} while (the_result && retries);
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
if (the_result) {
scsi_CDs[i].capacity = 0x1fffff;
@@ -568,7 +572,7 @@ void get_capabilities(int i)
cmd[2] = 0x2a;
cmd[4] = 128;
cmd[3] = cmd[5] = 0;
- rc = sr_do_ioctl(i, cmd, buffer, 128, 1);
+ rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ);
if (-EINVAL == rc) {
/* failed, drive has'nt this mode page */
@@ -633,19 +637,19 @@ void get_capabilities(int i)
*/
static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
{
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
unsigned char *buffer = cgc->buffer;
int buflen;
/* get the device */
- SCpnt = scsi_allocate_device(device, 1, FALSE);
- if (SCpnt == NULL)
+ SRpnt = scsi_allocate_request(device);
+ if (SRpnt == NULL)
return -ENODEV; /* this just doesn't seem right /axboe */
/* use buffer for ISA DMA */
buflen = (cgc->buflen + 511) & ~511;
- if (cgc->buffer && SCpnt->host->unchecked_isa_dma &&
+ if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma &&
(virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
buffer = scsi_malloc(buflen);
if (buffer == NULL) {
@@ -658,20 +662,25 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command
cgc->cmd[1] |= device->lun << 5;
/* do the locking and issue the command */
- SCpnt->request.rq_dev = cdi->dev;
+ SRpnt->sr_request.rq_dev = cdi->dev;
/* scsi_wait_cmd sets the command length */
- SCpnt->cmd_len = 0;
+ SRpnt->sr_cmd_len = 0;
+
+ /*
+ * FIXME(eric) - need to set the data direction here.
+ */
+ SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
- scsi_wait_cmd(SCpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
+ scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
SR_TIMEOUT, MAX_RETRIES);
- if ((cgc->stat = SCpnt->result))
- cgc->sense = (struct request_sense *) SCpnt->sense_buffer;
+ if ((cgc->stat = SRpnt->sr_result))
+ cgc->sense = (struct request_sense *) SRpnt->sr_sense_buffer;
/* release */
- SCpnt->request.rq_dev = MKDEV(0, 0);
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ SRpnt->sr_request.rq_dev = MKDEV(0, 0);
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
/* write DMA buffer back if used */
if (buffer && (buffer != cgc->buffer)) {
@@ -693,7 +702,7 @@ static int sr_init()
return 0;
if (!sr_registered) {
- if (register_blkdev(MAJOR_NR, "sr", &cdrom_fops)) {
+ if (devfs_register_blkdev(MAJOR_NR, "sr", &cdrom_fops)) {
printk("Unable to get major %d for SCSI-CD\n", MAJOR_NR);
return 1;
}
@@ -767,6 +776,11 @@ void sr_finish()
sprintf(name, "sr%d", i);
strcpy(scsi_CDs[i].cdi.name, name);
+ scsi_CDs[i].cdi.de =
+ devfs_register (scsi_CDs[i].device->de, "cd", 2,
+ DEVFS_FL_DEFAULT, MAJOR_NR, i,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ &cdrom_fops, NULL);
register_cdrom(&scsi_CDs[i].cdi);
}
@@ -828,7 +842,7 @@ int init_module(void)
void cleanup_module(void)
{
scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
- unregister_blkdev(MAJOR_NR, "sr");
+ devfs_unregister_blkdev(MAJOR_NR, "sr");
sr_registered--;
if (scsi_CDs != NULL) {
kfree((char *) scsi_CDs);
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index e4aad11ab..d3239e647 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -36,7 +36,7 @@ typedef struct {
extern Scsi_CD *scsi_CDs;
-int sr_do_ioctl(int, unsigned char *, void *, unsigned, int);
+int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int);
int sr_lock_door(struct cdrom_device_info *, int);
int sr_tray_move(struct cdrom_device_info *, int);
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 9d08b209b..32e71e06f 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -34,20 +34,21 @@ extern void get_sectorsize(int);
error code is. Normally the UNIT_ATTENTION code will automatically
clear after one error */
-int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet)
+int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite)
{
- Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *SDev;
struct request *req;
int result, err = 0, retries = 0;
char *bounce_buffer;
SDev = scsi_CDs[target].device;
- SCpnt = scsi_allocate_device(scsi_CDs[target].device, 1, FALSE);
+ SRpnt = scsi_allocate_request(scsi_CDs[target].device);
+ SRpnt->sr_data_direction = readwrite;
/* use ISA DMA buffer if necessary */
- SCpnt->request.buffer = buffer;
- if (buffer && SCpnt->host->unchecked_isa_dma &&
+ SRpnt->sr_request.buffer = buffer;
+ if (buffer && SRpnt->sr_host->unchecked_isa_dma &&
(virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) {
bounce_buffer = (char *) scsi_malloc((buflength + 511) & ~511);
if (bounce_buffer == NULL) {
@@ -62,21 +63,21 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
return -ENODEV;
- scsi_wait_cmd(SCpnt, (void *) sr_cmd, (void *) buffer, buflength,
+ scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength,
IOCTL_TIMEOUT, IOCTL_RETRIES);
- req = &SCpnt->request;
- if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) {
- memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
- scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511);
- SCpnt->buffer = req->buffer;
+ req = &SRpnt->sr_request;
+ if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
+ memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen);
+ scsi_free(SRpnt->sr_buffer, (SRpnt->sr_bufflen + 511) & ~511);
+ SRpnt->sr_buffer = req->buffer;
}
- result = SCpnt->result;
+ result = SRpnt->sr_result;
/* Minimal error checking. Ignore cases we know about, and report the rest. */
if (driver_byte(result) != 0) {
- switch (SCpnt->sense_buffer[2] & 0xf) {
+ switch (SRpnt->sr_sense_buffer[2] & 0xf) {
case UNIT_ATTENTION:
scsi_CDs[target].device->changed = 1;
if (!quiet)
@@ -86,8 +87,8 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
err = -ENOMEDIUM;
break;
case NOT_READY: /* This happens if there is no disc in drive */
- if (SCpnt->sense_buffer[12] == 0x04 &&
- SCpnt->sense_buffer[13] == 0x01) {
+ if (SRpnt->sr_sense_buffer[12] == 0x04 &&
+ SRpnt->sr_sense_buffer[13] == 0x01) {
/* sense: Logical unit is in process of becoming ready */
if (!quiet)
printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
@@ -104,7 +105,7 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
if (!quiet)
printk(KERN_INFO "sr%d: CDROM not ready. Make sure there is a disc in the drive.\n", target);
#ifdef DEBUG
- print_sense("sr", SCpnt);
+ print_req_sense("sr", SRpnt);
#endif
err = -ENOMEDIUM;
break;
@@ -112,8 +113,8 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
if (!quiet)
printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
"REQUEST.\n", target);
- if (SCpnt->sense_buffer[12] == 0x20 &&
- SCpnt->sense_buffer[13] == 0x00) {
+ if (SRpnt->sr_sense_buffer[12] == 0x20 &&
+ SRpnt->sr_sense_buffer[13] == 0x00) {
/* sense: Invalid command operation code */
err = -EDRIVE_CANT_DO_THIS;
} else {
@@ -121,20 +122,20 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
}
#ifdef DEBUG
print_command(sr_cmd);
- print_sense("sr", SCpnt);
+ print_req_sense("sr", SRpnt);
#endif
break;
default:
printk(KERN_ERR "sr%d: CDROM (ioctl) error, command: ", target);
print_command(sr_cmd);
- print_sense("sr", SCpnt);
+ print_req_sense("sr", SRpnt);
err = -EIO;
}
}
- result = SCpnt->result;
+ result = SRpnt->sr_result;
/* Wake up a process waiting for device */
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return err;
}
@@ -148,7 +149,7 @@ static int test_unit_ready(int minor)
sr_cmd[0] = GPCMD_TEST_UNIT_READY;
sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
- return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1);
+ return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE);
}
int sr_tray_move(struct cdrom_device_info *cdi, int pos)
@@ -160,7 +161,7 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos)
sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
- return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0);
+ return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE);
}
int sr_lock_door(struct cdrom_device_info *cdi, int lock)
@@ -237,7 +238,7 @@ int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
sr_cmd[8] = 24;
sr_cmd[9] = 0;
- result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
+ result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ);
memcpy(mcn->medium_catalog_number, buffer + 9, 13);
mcn->medium_catalog_number[13] = 0;
@@ -266,7 +267,7 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed)
sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
sr_cmd[3] = speed & 0xff; /* LSB */
- if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0))
+ if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE))
return -EIO;
return 0;
}
@@ -296,7 +297,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
sr_cmd[8] = 12; /* LSB of length */
sr_cmd[9] = 0;
- result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
+ result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ);
tochdr->cdth_trk0 = buffer[2];
tochdr->cdth_trk1 = buffer[3];
@@ -317,7 +318,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
sr_cmd[8] = 12; /* LSB of length */
sr_cmd[9] = 0;
- result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
+ result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ);
tocentry->cdte_ctrl = buffer[5] & 0xf;
tocentry->cdte_adr = buffer[5] >> 4;
@@ -390,7 +391,7 @@ int sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
cmd[9] = 0x10;
break;
}
- return sr_do_ioctl(minor, cmd, dest, blksize, 0);
+ return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
}
/*
@@ -428,7 +429,7 @@ int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
cmd[4] = (unsigned char) (lba >> 8) & 0xff;
cmd[5] = (unsigned char) lba & 0xff;
cmd[8] = 1;
- rc = sr_do_ioctl(minor, cmd, dest, blksize, 0);
+ rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ);
return rc;
}
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
index 77be00ea3..a57c25c39 100644
--- a/drivers/scsi/sr_vendor.c
+++ b/drivers/scsi/sr_vendor.c
@@ -132,7 +132,7 @@ int sr_set_blocklength(int minor, int blocklength)
modesel->density = density;
modesel->block_length_med = (blocklength >> 8) & 0xff;
modesel->block_length_lo = blocklength & 0xff;
- if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0))) {
+ if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE))) {
scsi_CDs[minor].device->sector_size = blocklength;
}
#ifdef DEBUG
@@ -176,7 +176,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[1] = (scsi_CDs[minor].device->lun << 5);
cmd[8] = 12;
cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
if (rc != 0)
break;
if ((buffer[0] << 8) + buffer[1] < 0x0a) {
@@ -200,7 +200,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[0] = 0xde;
cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
cmd[2] = 0xb0;
- rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ);
if (rc != 0)
break;
if (buffer[14] != 0 && buffer[14] != 0xb0) {
@@ -224,7 +224,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = 0xc7;
cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
- rc = sr_do_ioctl(minor, cmd, buffer, 4, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ);
if (rc == -EINVAL) {
printk(KERN_INFO "sr%d: Hmm, seems the drive "
"doesn't support multisession CD's\n", minor);
@@ -249,7 +249,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[1] = (scsi_CDs[minor].device->lun << 5);
cmd[8] = 0x04;
cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ);
if (rc != 0) {
break;
}
@@ -263,7 +263,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
cmd[6] = rc & 0x7f; /* number of last session */
cmd[8] = 0x0c;
cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
+ rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ);
if (rc != 0) {
break;
}
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 5817b1424..f897cba9a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -11,8 +11,10 @@
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue Jan 4 21:43:17 2000 by makisara@kai.makisara.local
+ Last modified: Sat Feb 19 17:22:34 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
+
+ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
#include <linux/module.h>
@@ -66,15 +68,15 @@ static int buffer_kbs = 0;
static int write_threshold_kbs = 0;
static int max_buffers = (-1);
static int max_sg_segs = 0;
-#ifdef MODULE
+
MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI Tape Driver");
MODULE_PARM(buffer_kbs, "i");
MODULE_PARM(write_threshold_kbs, "i");
MODULE_PARM(max_buffers, "i");
MODULE_PARM(max_sg_segs, "i");
-#else
+#ifndef MODULE
static struct st_dev_parm {
char *name;
int *val;
@@ -92,7 +94,6 @@ static struct st_dev_parm {
"max_sg_segs", &max_sg_segs
}
};
-
#endif
@@ -168,16 +169,15 @@ static int st_int_ioctl(struct inode *inode, unsigned int cmd_in,
-
/* Convert the result to success code */
-static int st_chk_result(Scsi_Cmnd * SCpnt)
+static int st_chk_result(Scsi_Request * SRpnt)
{
- int dev = TAPE_NR(SCpnt->request.rq_dev);
- int result = SCpnt->result;
- unsigned char *sense = SCpnt->sense_buffer, scode;
+ int dev = TAPE_NR(SRpnt->sr_request.rq_dev);
+ int result = SRpnt->sr_result;
+ unsigned char *sense = SRpnt->sr_sense_buffer, scode;
DEB(const char *stp;)
- if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
+ if (!result)
return 0;
if (driver_byte(result) & DRIVER_SENSE)
@@ -191,11 +191,11 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
if (debugging) {
printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
dev, result,
- SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
- SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
- SCpnt->request_bufflen);
+ SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
+ SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
+ SRpnt->sr_bufflen);
if (driver_byte(result) & DRIVER_SENSE)
- print_sense("st", SCpnt);
+ print_req_sense("st", SRpnt);
} else ) /* end DEB */
if (!(driver_byte(result) & DRIVER_SENSE) ||
((sense[0] & 0x70) == 0x70 &&
@@ -204,11 +204,11 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
/* scode != UNIT_ATTENTION && */
scode != BLANK_CHECK &&
scode != VOLUME_OVERFLOW &&
- SCpnt->data_cmnd[0] != MODE_SENSE &&
- SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
+ SRpnt->sr_cmnd[0] != MODE_SENSE &&
+ SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
if (driver_byte(result) & DRIVER_SENSE) {
printk(KERN_WARNING "st%d: Error with sense data: ", dev);
- print_sense("st", SCpnt);
+ print_req_sense("st", SRpnt);
} else
printk(KERN_WARNING
"st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
@@ -219,8 +219,8 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
if ((sense[0] & 0x70) == 0x70 &&
scode == RECOVERED_ERROR
#if ST_RECOVERED_WRITE_FATAL
- && SCpnt->data_cmnd[0] != WRITE_6
- && SCpnt->data_cmnd[0] != WRITE_FILEMARKS
+ && SRpnt->sr_cmnd[0] != WRITE_6
+ && SRpnt->sr_cmnd[0] != WRITE_FILEMARKS
#endif
) {
scsi_tapes[dev].recover_count++;
@@ -228,9 +228,9 @@ static int st_chk_result(Scsi_Cmnd * SCpnt)
DEB(
if (debugging) {
- if (SCpnt->data_cmnd[0] == READ_6)
+ if (SRpnt->sr_cmnd[0] == READ_6)
stp = "read";
- else if (SCpnt->data_cmnd[0] == WRITE_6)
+ else if (SRpnt->sr_cmnd[0] == WRITE_6)
stp = "write";
else
stp = "ioctl";
@@ -267,13 +267,13 @@ static void st_sleep_done(Scsi_Cmnd * SCpnt)
remainder = 0;
if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
remainder > 0)
- (STp->buffer)->last_result = SCpnt->result; /* Error */
+ (STp->buffer)->midlevel_result = SCpnt->result; /* Error */
else
- (STp->buffer)->last_result = INT_MAX; /* OK */
+ (STp->buffer)->midlevel_result = INT_MAX; /* OK */
} else
- (STp->buffer)->last_result = SCpnt->result;
+ (STp->buffer)->midlevel_result = SCpnt->result;
SCpnt->request.rq_status = RQ_SCSI_DONE;
- (STp->buffer)->last_SCpnt = SCpnt;
+ (STp->buffer)->last_SRpnt = SCpnt->sc_request;
DEB( STp->write_pending = 0; )
up(SCpnt->request.sem);
@@ -288,47 +288,49 @@ static void st_sleep_done(Scsi_Cmnd * SCpnt)
/* Do the scsi command. Waits until command performed if do_wait is true.
Otherwise write_behind_check() is used to check that the command
has finished. */
-static Scsi_Cmnd *
- st_do_scsi(Scsi_Cmnd * SCpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
- int timeout, int retries, int do_wait)
+static Scsi_Request *
+ st_do_scsi(Scsi_Request * SRpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
+ int direction, int timeout, int retries, int do_wait)
{
unsigned char *bp;
- if (SCpnt == NULL)
- SCpnt = scsi_allocate_device(STp->device, 1, TRUE);
- if (SCpnt == NULL) {
+ if (SRpnt == NULL)
+ SRpnt = scsi_allocate_request(STp->device);
+ if (SRpnt == NULL) {
DEBC( printk(KERN_ERR "st%d: Can't get SCSI request.\n",
TAPE_NR(STp->devt)); );
if (signal_pending(current))
- (STp->buffer)->last_result_fatal = (-EINTR);
+ (STp->buffer)->syscall_result = (-EINTR);
else
- (STp->buffer)->last_result_fatal = (-EBUSY);
+ (STp->buffer)->syscall_result = (-EBUSY);
return NULL;
}
- cmd[1] |= (SCpnt->lun << 5) & 0xe0;
+ cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;
init_MUTEX_LOCKED(&STp->sem);
- SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+ SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
(STp->buffer)->use_sg : 0;
- if (SCpnt->use_sg) {
+ if (SRpnt->sr_use_sg) {
bp = (char *) &((STp->buffer)->sg[0]);
- if ((STp->buffer)->sg_segs < SCpnt->use_sg)
- SCpnt->use_sg = (STp->buffer)->sg_segs;
+ if ((STp->buffer)->sg_segs < SRpnt->sr_use_sg)
+ SRpnt->sr_use_sg = (STp->buffer)->sg_segs;
} else
bp = (STp->buffer)->b_data;
- SCpnt->cmd_len = 0;
- SCpnt->request.sem = &(STp->sem);
- SCpnt->request.rq_status = RQ_SCSI_BUSY;
- SCpnt->request.rq_dev = STp->devt;
+ SRpnt->sr_data_direction = direction;
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_request.sem = &(STp->sem);
+ SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;
+ SRpnt->sr_request.rq_dev = STp->devt;
- scsi_do_cmd(SCpnt, (void *) cmd, bp, bytes,
+ scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
st_sleep_done, timeout, retries);
if (do_wait) {
- down(SCpnt->request.sem);
- (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
+ down(SRpnt->sr_request.sem);
+ SRpnt->sr_request.sem = NULL;
+ (STp->buffer)->syscall_result = st_chk_result(SRpnt);
}
- return SCpnt;
+ return SRpnt;
}
@@ -348,9 +350,10 @@ static void write_behind_check(Scsi_Tape * STp)
) /* end DEB */
down(&(STp->sem));
+ (STp->buffer)->last_SRpnt->sr_request.sem = NULL;
- (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt);
- scsi_release_command((STp->buffer)->last_SCpnt);
+ (STp->buffer)->syscall_result = st_chk_result((STp->buffer)->last_SRpnt);
+ scsi_release_request((STp->buffer)->last_SRpnt);
if (STbuffer->writing < STbuffer->buffer_bytes)
#if 0
@@ -379,8 +382,8 @@ static void write_behind_check(Scsi_Tape * STp)
it messes up the block number). */
static int cross_eof(Scsi_Tape * STp, int forward)
{
- Scsi_Cmnd *SCpnt;
- unsigned char cmd[10];
+ Scsi_Request *SRpnt;
+ unsigned char cmd[MAX_COMMAND_SIZE];
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
@@ -394,18 +397,19 @@ static int cross_eof(Scsi_Tape * STp, int forward)
DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",
TAPE_NR(STp->devt), forward ? "forward" : "backward"));
- SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
+ STp->timeout, MAX_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
- if ((STp->buffer)->last_result != 0)
+ if ((STp->buffer)->midlevel_result != 0)
printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
TAPE_NR(STp->devt), forward ? "forward" : "backward");
- return (STp->buffer)->last_result_fatal;
+ return (STp->buffer)->syscall_result;
}
@@ -414,17 +418,17 @@ static int flush_write_buffer(Scsi_Tape * STp)
{
int offset, transfer, blks;
int result;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
ST_partstat *STps;
if ((STp->buffer)->writing) {
write_behind_check(STp);
- if ((STp->buffer)->last_result_fatal) {
+ if ((STp->buffer)->syscall_result) {
DEBC(printk(ST_DEB_MSG
"st%d: Async write error (flush) %x.\n",
- TAPE_NR(STp->devt), (STp->buffer)->last_result))
- if ((STp->buffer)->last_result == INT_MAX)
+ TAPE_NR(STp->devt), (STp->buffer)->midlevel_result))
+ if ((STp->buffer)->midlevel_result == INT_MAX)
return (-ENOSPC);
return (-EIO);
}
@@ -443,7 +447,7 @@ static int flush_write_buffer(Scsi_Tape * STp)
memset((STp->buffer)->b_data + offset, 0, transfer - offset);
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = WRITE_6;
cmd[1] = 1;
blks = transfer / STp->block_size;
@@ -451,16 +455,16 @@ static int flush_write_buffer(Scsi_Tape * STp)
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout,
- MAX_WRITE_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, transfer, SCSI_DATA_WRITE,
+ STp->timeout, MAX_WRITE_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
STps = &(STp->ps[STp->partition]);
- if ((STp->buffer)->last_result_fatal != 0) {
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x40) &&
- (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) {
+ if ((STp->buffer)->syscall_result != 0) {
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x40) &&
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
result = (-ENOSPC);
@@ -476,8 +480,8 @@ static int flush_write_buffer(Scsi_Tape * STp)
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return result;
}
@@ -582,8 +586,9 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
{
unsigned short flags;
int i, need_dma_buffer, new_session = FALSE;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ int retval;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -601,8 +606,14 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
return (-EBUSY);
}
+ STp->in_use = 1;
STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+ if (scsi_tapes[dev].device->host->hostt->module)
+ __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (st_template.module)
+ __MOD_INC_USE_COUNT(st_template.module);
+
if (mode != STp->current_mode) {
DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
dev, STp->current_mode, mode));
@@ -621,13 +632,14 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
if (STp->buffer == NULL) {
printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev);
- return (-EBUSY);
+ retval = (-EBUSY);
+ goto err_out;
}
} else
STp->buffer = st_buffers[i];
(STp->buffer)->in_use = 1;
(STp->buffer)->writing = 0;
- (STp->buffer)->last_result_fatal = 0;
+ (STp->buffer)->syscall_result = 0;
(STp->buffer)->use_sg = STp->device->host->sg_tablesize;
/* Compute the usable buffer size for this SCSI adapter */
@@ -651,35 +663,27 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->recover_count = 0;
DEB( STp->nbr_waits = STp->nbr_finished = 0; )
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_INC_USE_COUNT(st_template.module);
-
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
- SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
- TRUE);
- if (!SCpnt) {
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
+ MAX_READY_RETRIES, TRUE);
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
+ goto err_out;
}
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
/* Flush the queued UNIT ATTENTION sense data */
for (i=0; i < 10; i++) {
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout,
- MAX_READY_RETRIES, TRUE);
- if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
- (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+ STp->long_timeout, MAX_READY_RETRIES, TRUE);
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+ (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
break;
}
@@ -700,36 +704,35 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
new_session = TRUE;
}
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
if ((STp->device)->scsi_level >= SCSI_2 &&
- (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
- SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */
+ (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
+ SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
STp->ready = ST_NO_TAPE;
} else
STp->ready = ST_NOT_READY;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STp->density = 0; /* Clear the erroneous "residue" */
STp->write_prot = 0;
STp->block_size = 0;
STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
STp->partition = STp->new_partition = 0;
STp->door_locked = ST_UNLOCKED;
- STp->in_use = 1;
return 0;
}
if (STp->omit_blklims)
STp->min_block = STp->max_block = (-1);
else {
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = READ_BLOCK_LIMITS;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES,
- TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
- if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
+ if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
STp->max_block = ((STp->buffer)->b_data[1] << 16) |
((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
STp->min_block = ((STp->buffer)->b_data[4] << 8) |
@@ -745,16 +748,17 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
}
}
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
cmd[4] = 12;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */
- (STp->buffer)->last_result_fatal = 0; /* Prevent error propagation */
+ (STp->buffer)->syscall_result = 0; /* Prevent error propagation */
STp->drv_write_prot = 0;
} else {
DEBC(printk(ST_DEB_MSG
@@ -779,19 +783,14 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n",
dev, STp->block_size);
- scsi_release_command(SCpnt);
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return (-EIO);
+ scsi_release_request(SRpnt);
+ retval = (-EIO);
+ goto err_out;
}
STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STp->inited = TRUE;
if (STp->block_size > 0)
@@ -812,13 +811,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev));
if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return (-EROFS);
+ retval = (-EROFS);
+ goto err_out;
}
}
@@ -829,13 +823,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
DEBC(printk(ST_DEB_MSG
"st%d: Updating partition number in status.\n", dev));
if ((STp->partition = find_partition(inode)) < 0) {
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return STp->partition;
+ retval = STp->partition;
+ goto err_out;
}
STp->new_partition = STp->partition;
STp->nbr_partitions = 1; /* This guess will be updated when necessary */
@@ -845,15 +834,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
STp->density_changed = STp->blksize_changed = FALSE;
STp->compression_changed = FALSE;
if (!(STm->defaults_for_writes) &&
- (i = set_mode_densblk(inode, STp, STm)) < 0) {
- (STp->buffer)->in_use = 0;
- STp->buffer = NULL;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
- if (st_template.module)
- __MOD_DEC_USE_COUNT(st_template.module);
- return i;
- }
+ (retval = set_mode_densblk(inode, STp, STm)) < 0)
+ goto err_out;
if (STp->default_drvbuffer != 0xff) {
if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
@@ -862,9 +844,21 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
dev, STp->default_drvbuffer);
}
}
- STp->in_use = 1;
return 0;
+
+ err_out:
+ if (STp->buffer != NULL) {
+ (STp->buffer)->in_use = 0;
+ STp->buffer = NULL;
+ }
+ STp->in_use = 0;
+ if (scsi_tapes[dev].device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (st_template.module)
+ __MOD_DEC_USE_COUNT(st_template.module);
+ return retval;
+
}
@@ -872,8 +866,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
static int scsi_tape_flush(struct file *filp)
{
int result = 0, result2;
- static unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ static unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -890,59 +884,62 @@ static int scsi_tape_flush(struct file *filp)
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
+ if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+ result = flush_write_buffer(STp);
+ if (result != 0 && result != (-ENOSPC))
+ goto out;
+ }
+
if (STp->can_partitions &&
- (result = update_partition(inode)) < 0) {
+ (result2 = update_partition(inode)) < 0) {
DEBC(printk(ST_DEB_MSG
"st%d: update_partition at close failed.\n", dev));
+ if (result == 0)
+ result = result2;
goto out;
}
if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
- result = flush_write_buffer(STp);
-
DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
dev, (long) (filp->f_pos));
printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n",
dev, STp->nbr_waits, STp->nbr_finished);
)
- if (result == 0 || result == (-ENOSPC)) {
-
- memset(cmd, 0, 10);
- cmd[0] = WRITE_FILEMARKS;
- cmd[4] = 1 + STp->two_fm;
+ memset(cmd, 0, MAX_COMMAND_SIZE);
+ cmd[0] = WRITE_FILEMARKS;
+ cmd[4] = 1 + STp->two_fm;
- SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout,
- MAX_WRITE_RETRIES, TRUE);
- if (!SCpnt) {
- result = (STp->buffer)->last_result_fatal;
- goto out;
- }
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,
+ STp->timeout, MAX_WRITE_RETRIES, TRUE);
+ if (!SRpnt) {
+ result = (STp->buffer)->syscall_result;
+ goto out;
+ }
- if ((STp->buffer)->last_result_fatal != 0 &&
- ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
- (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
- ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
- (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
- SCpnt->sense_buffer[5] |
- SCpnt->sense_buffer[6]) == 0))) {
- /* Filter out successful write at EOM */
- scsi_release_command(SCpnt);
- SCpnt = NULL;
- printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
- if (result == 0)
- result = (-EIO);
- } else {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- if (STp->two_fm)
- cross_eof(STp, FALSE);
- STps->eof = ST_FM;
- }
+ if ((STp->buffer)->syscall_result != 0 &&
+ ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+ (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 ||
+ ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
+ (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
+ SRpnt->sr_sense_buffer[5] |
+ SRpnt->sr_sense_buffer[6]) == 0))) {
+ /* Filter out successful write at EOM */
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
+ printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
+ if (result == 0)
+ result = (-EIO);
+ } else {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
+ if (STps->drv_file >= 0)
+ STps->drv_file++;
+ STps->drv_block = 0;
+ if (STp->two_fm)
+ cross_eof(STp, FALSE);
+ STps->eof = ST_FM;
}
DEBC(printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n",
@@ -1021,9 +1018,9 @@ static ssize_t
ssize_t i, do_count, blks, retval, transfer;
int write_threshold;
int doing_write = 0;
- static unsigned char cmd[10];
+ static unsigned char cmd[MAX_COMMAND_SIZE];
const char *b_point;
- Scsi_Cmnd *SCpnt = NULL;
+ Scsi_Request *SRpnt = NULL;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -1118,10 +1115,10 @@ static ssize_t
if ((STp->buffer)->writing) {
write_behind_check(STp);
- if ((STp->buffer)->last_result_fatal) {
+ if ((STp->buffer)->syscall_result) {
DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n",
- dev, (STp->buffer)->last_result));
- if ((STp->buffer)->last_result == INT_MAX)
+ dev, (STp->buffer)->midlevel_result));
+ if ((STp->buffer)->midlevel_result == INT_MAX)
STps->eof = ST_EOM_OK;
else
STps->eof = ST_EOM_ERROR;
@@ -1153,7 +1150,7 @@ static ssize_t
total = count;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = WRITE_6;
cmd[1] = (STp->block_size != 0);
@@ -1175,9 +1172,9 @@ static ssize_t
i = append_to_buffer(b_point, STp->buffer, do_count);
if (i) {
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return i;
}
@@ -1193,23 +1190,23 @@ static ssize_t
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout,
- MAX_WRITE_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
+ STp->timeout, MAX_WRITE_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev));
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x40)) {
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x40)) {
if (STp->block_size != 0 &&
- (SCpnt->sense_buffer[0] & 0x80) != 0)
- transfer = (SCpnt->sense_buffer[3] << 24) |
- (SCpnt->sense_buffer[4] << 16) |
- (SCpnt->sense_buffer[5] << 8) |
- SCpnt->sense_buffer[6];
+ (SRpnt->sr_sense_buffer[0] & 0x80) != 0)
+ transfer = (SRpnt->sr_sense_buffer[3] << 24) |
+ (SRpnt->sr_sense_buffer[4] << 16) |
+ (SRpnt->sr_sense_buffer[5] << 8) |
+ SRpnt->sr_sense_buffer[6];
else if (STp->block_size == 0 &&
- (SCpnt->sense_buffer[2] & 0x0f) ==
+ (SRpnt->sr_sense_buffer[2] & 0x0f) ==
VOLUME_OVERFLOW)
transfer = do_count;
else
@@ -1246,8 +1243,8 @@ static ssize_t
retval = (-EIO);
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
(STp->buffer)->buffer_bytes = 0;
STp->dirty = 0;
if (count < total)
@@ -1271,9 +1268,9 @@ static ssize_t
STp->dirty = 1;
i = append_to_buffer(b_point, STp->buffer, count);
if (i) {
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return i;
}
@@ -1281,10 +1278,10 @@ static ssize_t
count = 0;
}
- if (doing_write && (STp->buffer)->last_result_fatal != 0) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
- return (STp->buffer)->last_result_fatal;
+ if (doing_write && (STp->buffer)->syscall_result != 0) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
+ return (STp->buffer)->syscall_result;
}
if (STm->do_async_writes &&
@@ -1309,14 +1306,15 @@ static ssize_t
cmd[4] = blks;
DEB( STp->write_pending = 1; )
- SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout,
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing,
+ SCSI_DATA_WRITE, STp->timeout,
MAX_WRITE_RETRIES, FALSE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- } else if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ } else if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
STps->at_sm &= (total == 0);
if (total > 0)
@@ -1328,11 +1326,11 @@ static ssize_t
/* Read data from the tape. Returns zero in the normal case, one if the
eof status has changed, and the negative error code in case of a
fatal error. Otherwise updates the buffer and the eof state. */
-static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
+static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt)
{
int transfer, blks, bytes;
- static unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ static unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -1348,7 +1346,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
if (STps->eof == ST_FM_HIT)
return 1;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_6;
cmd[1] = (STp->block_size != 0);
if (STp->block_size == 0)
@@ -1369,49 +1367,51 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
cmd[3] = blks >> 8;
cmd[4] = blks;
- SCpnt = *aSCpnt;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE);
- *aSCpnt = SCpnt;
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = *aSRpnt;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, SCSI_DATA_READ,
+ STp->timeout, MAX_RETRIES, TRUE);
+ *aSRpnt = SRpnt;
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
(STp->buffer)->read_pointer = 0;
STps->at_sm = 0;
/* Something to check */
- if ((STp->buffer)->last_result_fatal) {
+ if ((STp->buffer)->syscall_result) {
retval = 1;
DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
dev,
- SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
- SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
- SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
- SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]));
- if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
+ SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
+ SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
+ SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
+ SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]));
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
- if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
- SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
+ if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
+ SRpnt->sr_sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
- if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
+ if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
/* Compute the residual count */
- if ((SCpnt->sense_buffer[0] & 0x80) != 0)
- transfer = (SCpnt->sense_buffer[3] << 24) |
- (SCpnt->sense_buffer[4] << 16) |
- (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+ if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0)
+ transfer = (SRpnt->sr_sense_buffer[3] << 24) |
+ (SRpnt->sr_sense_buffer[4] << 16) |
+ (SRpnt->sr_sense_buffer[5] << 8) |
+ SRpnt->sr_sense_buffer[6];
else
transfer = 0;
if (STp->block_size == 0 &&
- (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
transfer = bytes;
- if (SCpnt->sense_buffer[2] & 0x20) { /* ILI */
+ if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */
if (STp->block_size == 0) {
if (transfer <= 0)
transfer = 0;
(STp->buffer)->buffer_bytes = bytes - transfer;
} else {
- scsi_release_command(SCpnt);
- SCpnt = *aSCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = *aSRpnt = NULL;
if (transfer == blks) { /* We did not get anything, error */
printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
if (STps->drv_block >= 0)
@@ -1430,7 +1430,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
if (st_int_ioctl(inode, MTBSR, 1))
return (-EIO);
}
- } else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */
+ } else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */
if (STps->eof != ST_FM_HIT)
STps->eof = ST_FM_HIT;
else
@@ -1443,7 +1443,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
DEBC(printk(ST_DEB_MSG
"st%d: EOF detected (%d bytes read).\n",
dev, (STp->buffer)->buffer_bytes));
- } else if (SCpnt->sense_buffer[2] & 0x40) {
+ } else if (SRpnt->sr_sense_buffer[2] & 0x40) {
if (STps->eof == ST_FM)
STps->eof = ST_EOD_1;
else
@@ -1464,7 +1464,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
"st%d: Tape error while reading.\n", dev));
STps->drv_block = (-1);
if (STps->eof == ST_FM &&
- (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
+ (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) {
DEBC(printk(ST_DEB_MSG
"st%d: Zero returned for first BLANK CHECK after EOF.\n",
dev));
@@ -1475,7 +1475,7 @@ static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
}
/* End of extended sense test */
else { /* Non-extended sense */
- retval = (STp->buffer)->last_result_fatal;
+ retval = (STp->buffer)->syscall_result;
}
}
@@ -1501,7 +1501,7 @@ static ssize_t
ssize_t total;
ssize_t i, transfer;
int special;
- Scsi_Cmnd *SCpnt = NULL;
+ Scsi_Request *SRpnt = NULL;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
@@ -1594,10 +1594,10 @@ static ssize_t
/* Get new data if the buffer is empty */
if ((STp->buffer)->buffer_bytes == 0) {
- special = read_tape(inode, count - total, &SCpnt);
+ special = read_tape(inode, count - total, &SRpnt);
if (special < 0) { /* No need to continue read */
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
}
return special;
}
@@ -1616,9 +1616,9 @@ static ssize_t
(STp->buffer)->buffer_bytes : count - total;
i = from_buffer(STp->buffer, buf, transfer);
if (i) {
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return i;
}
@@ -1633,9 +1633,9 @@ static ssize_t
} /* for (total = 0, special = 0;
total < count && !special; ) */
- if (SCpnt != NULL) {
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ if (SRpnt != NULL) {
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
/* Change the eof state if no data from tape or buffer */
@@ -1836,30 +1836,31 @@ static int st_set_options(struct inode *inode, long options)
static int st_compression(Scsi_Tape * STp, int state)
{
int dev;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt = NULL;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt = NULL;
if (STp->ready != ST_READY)
return (-EIO);
/* Read the current page contents */
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
cmd[1] = 8;
cmd[2] = COMPRESSION_PAGE;
cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
+ STp->timeout, 0, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- dev = TAPE_NR(SCpnt->request.rq_dev);
+ dev = TAPE_NR(SRpnt->sr_request.rq_dev);
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n",
dev));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return (-EIO);
}
DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
@@ -1868,8 +1869,8 @@ static int st_compression(Scsi_Tape * STp, int state)
/* Check if compression can be changed */
if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return (-EIO);
}
@@ -1879,7 +1880,7 @@ static int st_compression(Scsi_Tape * STp, int state)
else
(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
cmd[1] = 0x10;
cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
@@ -1887,19 +1888,20 @@ static int st_compression(Scsi_Tape * STp, int state)
(STp->buffer)->b_data[0] = 0; /* Reserved data length */
(STp->buffer)->b_data[1] = 0; /* Reserved media type byte */
(STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+ STp->timeout, 0, TRUE);
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return (-EIO);
}
DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
dev, state));
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STp->compression_changed = TRUE;
return 0;
}
@@ -1913,11 +1915,12 @@ static int st_int_ioctl(struct inode *inode,
long ltmp;
int i, ioctl_result;
int chg_eof = TRUE;
- unsigned char cmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_partstat *STps;
- int fileno, blkno, at_sm, undone, datalen;
+ int fileno, blkno, at_sm, undone;
+ int datalen = 0, direction = SCSI_DATA_NONE;
int dev = TAPE_NR(inode->i_rdev);
STp = &(scsi_tapes[dev]);
@@ -1933,8 +1936,7 @@ static int st_int_ioctl(struct inode *inode,
blkno = STps->drv_block;
at_sm = STps->at_sm;
- memset(cmd, 0, 10);
- datalen = 0;
+ memset(cmd, 0, MAX_COMMAND_SIZE);
switch (cmd_in) {
case MTFSFM:
chg_eof = FALSE; /* Changed from the FSF after this */
@@ -2176,6 +2178,7 @@ static int st_int_ioctl(struct inode *inode,
}
cmd[0] = MODE_SELECT;
cmd[4] = datalen = 12;
+ direction = SCSI_DATA_WRITE;
memset((STp->buffer)->b_data, 0, 12);
if (cmd_in == MTSETDRVBUFFER)
@@ -2222,15 +2225,16 @@ static int st_int_ioctl(struct inode *inode,
return (-ENOSYS);
}
- SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
+ timeout, MAX_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- ioctl_result = (STp->buffer)->last_result_fatal;
+ ioctl_result = (STp->buffer)->syscall_result;
if (!ioctl_result) { /* SCSI command successful */
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
STps->drv_block = blkno;
STps->drv_file = fileno;
STps->at_sm = at_sm;
@@ -2279,7 +2283,7 @@ static int st_int_ioctl(struct inode *inode,
} else { /* SCSI command was not completely successful. Don't return
from this block without releasing the SCSI command block! */
- if (SCpnt->sense_buffer[2] & 0x40) {
+ if (SRpnt->sr_sense_buffer[2] & 0x40) {
if (cmd_in != MTBSF && cmd_in != MTBSFM &&
cmd_in != MTBSR && cmd_in != MTBSS)
STps->eof = ST_EOM_OK;
@@ -2287,14 +2291,14 @@ static int st_int_ioctl(struct inode *inode,
}
undone = (
- (SCpnt->sense_buffer[3] << 24) +
- (SCpnt->sense_buffer[4] << 16) +
- (SCpnt->sense_buffer[5] << 8) +
- SCpnt->sense_buffer[6]);
+ (SRpnt->sr_sense_buffer[3] << 24) +
+ (SRpnt->sr_sense_buffer[4] << 16) +
+ (SRpnt->sr_sense_buffer[5] << 8) +
+ SRpnt->sr_sense_buffer[6]);
if (cmd_in == MTWEOF &&
- (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
- (SCpnt->sense_buffer[2] & 0x4f) == 0x40 &&
- ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) {
+ (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+ (SRpnt->sr_sense_buffer[2] & 0x4f) == 0x40 &&
+ ((SRpnt->sr_sense_buffer[0] & 0x80) == 0 || undone == 0)) {
ioctl_result = 0; /* EOF written succesfully at EOM */
if (fileno >= 0)
fileno++;
@@ -2315,7 +2319,7 @@ static int st_int_ioctl(struct inode *inode,
STps->drv_block = 0;
STps->eof = ST_NOEOF;
} else if (cmd_in == MTFSR) {
- if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
+ if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
if (STps->drv_file >= 0)
STps->drv_file++;
STps->drv_block = 0;
@@ -2328,7 +2332,7 @@ static int st_int_ioctl(struct inode *inode,
STps->eof = ST_NOEOF;
}
} else if (cmd_in == MTBSR) {
- if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
+ if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */
STps->drv_file--;
STps->drv_block = (-1);
} else {
@@ -2345,14 +2349,14 @@ static int st_int_ioctl(struct inode *inode,
} else if (chg_eof)
STps->eof = ST_NOEOF;
- if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+ if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
STps->eof = ST_EOD;
if (cmd_in == MTLOCK)
STp->door_locked = ST_LOCK_FAILS;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
}
return ioctl_result;
@@ -2368,14 +2372,14 @@ static int get_location(struct inode *inode, unsigned int *block, int *partition
Scsi_Tape *STp;
int dev = TAPE_NR(inode->i_rdev);
int result;
- unsigned char scmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char scmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
- memset(scmd, 0, 10);
+ memset(scmd, 0, MAX_COMMAND_SIZE);
if ((STp->device)->scsi_level < SCSI_2) {
scmd[0] = QFA_REQUEST_BLOCK;
scmd[4] = 3;
@@ -2384,11 +2388,12 @@ static int get_location(struct inode *inode, unsigned int *block, int *partition
if (!logical && !STp->scsi2_logical)
scmd[1] = 1;
}
- SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, scmd, 20, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
- if ((STp->buffer)->last_result_fatal != 0 ||
+ if ((STp->buffer)->syscall_result != 0 ||
(STp->device->scsi_level >= SCSI_2 &&
((STp->buffer)->b_data[0] & 4) != 0)) {
*block = *partition = 0;
@@ -2414,8 +2419,8 @@ static int get_location(struct inode *inode, unsigned int *block, int *partition
DEBC(printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
*block, *partition));
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return result;
}
@@ -2432,8 +2437,8 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
int result, p;
unsigned int blk;
int timeout;
- unsigned char scmd[10];
- Scsi_Cmnd *SCpnt;
+ unsigned char scmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt;
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
@@ -2462,7 +2467,7 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
}
}
- memset(scmd, 0, 10);
+ memset(scmd, 0, MAX_COMMAND_SIZE);
if ((STp->device)->scsi_level < SCSI_2) {
scmd[0] = QFA_SEEK_BLOCK;
scmd[2] = (block >> 16);
@@ -2490,13 +2495,14 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
timeout = STp->timeout;
#endif
- SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE);
- if (!SCpnt)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE,
+ timeout, MAX_READY_RETRIES, TRUE);
+ if (!SRpnt)
+ return (STp->buffer)->syscall_result;
STps->drv_block = STps->drv_file = (-1);
STps->eof = ST_NOEOF;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
result = (-EIO);
if (STp->can_partitions &&
(STp->device)->scsi_level >= SCSI_2 &&
@@ -2518,8 +2524,8 @@ static int set_location(struct inode *inode, unsigned int block, int partition,
result = 0;
}
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
return result;
}
@@ -2568,27 +2574,28 @@ static int nbr_partitions(struct inode *inode)
{
int dev = TAPE_NR(inode->i_rdev), result;
Scsi_Tape *STp;
- Scsi_Cmnd *SCpnt = NULL;
- unsigned char cmd[10];
+ Scsi_Request *SRpnt = NULL;
+ unsigned char cmd[MAX_COMMAND_SIZE];
STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
- memset((void *) &cmd[0], 0, 10);
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
cmd[1] = 8; /* Page format */
cmd[2] = PART_PAGE;
cmd[4] = 200;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 200, SCSI_DATA_READ, STp->timeout,
+ MAX_READY_RETRIES, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n",
dev));
result = (-EIO);
@@ -2608,8 +2615,8 @@ static int partition_tape(struct inode *inode, int size)
int dev = TAPE_NR(inode->i_rdev), result;
int length;
Scsi_Tape *STp;
- Scsi_Cmnd *SCpnt = NULL;
- unsigned char cmd[10], *bp;
+ Scsi_Request *SRpnt = NULL;
+ unsigned char cmd[MAX_COMMAND_SIZE], *bp;
if ((result = nbr_partitions(inode)) < 0)
return result;
@@ -2640,20 +2647,20 @@ static int partition_tape(struct inode *inode, int size)
bp[MODE_HEADER_LENGTH] &= 0x3f;
bp[MODE_HEADER_LENGTH + 1] = length - 2;
- memset(cmd, 0, 10);
+ memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
cmd[1] = 0x10;
cmd[4] = length + MODE_HEADER_LENGTH;
- SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout,
- MAX_READY_RETRIES, TRUE);
- if (SCpnt == NULL)
- return (STp->buffer)->last_result_fatal;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+ STp->long_timeout, MAX_READY_RETRIES, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- scsi_release_command(SCpnt);
- SCpnt = NULL;
+ scsi_release_request(SRpnt);
+ SRpnt = NULL;
- if ((STp->buffer)->last_result_fatal != 0) {
+ if ((STp->buffer)->syscall_result != 0) {
printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
result = (-EIO);
} else
@@ -3230,7 +3237,7 @@ static int st_attach(Scsi_Device * SDp)
Scsi_Tape *tpnt;
ST_mode *STm;
ST_partstat *STps;
- int i;
+ int i, mode;
if (SDp->type != TYPE_TAPE)
return 1;
@@ -3247,6 +3254,26 @@ static int st_attach(Scsi_Device * SDp)
if (i >= st_template.dev_max)
panic("scsi_devices corrupt (st)");
+ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+ char name[8];
+ static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+
+ /* Rewind entry */
+ sprintf (name, "mt%s", formats[mode]);
+ tpnt->de_r[mode] =
+ devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+ MAJOR_NR, i + (mode << 5),
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ 0, 0, &st_fops, NULL);
+ /* No-rewind entry */
+ sprintf (name, "mt%sn", formats[mode]);
+ tpnt->de_n[mode] =
+ devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+ MAJOR_NR, i + (mode << 5) + 128,
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ 0, 0, &st_fops, NULL);
+ }
+ devfs_register_tape (tpnt->de_r[0]);
scsi_tapes[i].device = SDp;
if (SDp->scsi_level <= 2)
scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
@@ -3336,7 +3363,7 @@ static int st_init()
st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
if (!st_registered) {
- if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
+ if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
MAJOR_NR);
return 1;
@@ -3355,7 +3382,7 @@ static int st_init()
GFP_ATOMIC);
if (scsi_tapes == NULL) {
printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
return 1;
}
@@ -3372,7 +3399,7 @@ static int st_init()
for (j=0; j < i; j++)
kfree(scsi_tapes[j].mt_status);
kfree(scsi_tapes);
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
return 1;
}
/* Initialize status */
@@ -3385,7 +3412,7 @@ static int st_init()
GFP_ATOMIC);
if (st_buffers == NULL) {
printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
for (i=0; i < st_template.dev_max; i++)
kfree(scsi_tapes[i].mt_status);
kfree(scsi_tapes);
@@ -3416,11 +3443,17 @@ static int st_init()
static void st_detach(Scsi_Device * SDp)
{
Scsi_Tape *tpnt;
- int i;
+ int i, mode;
for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
if (tpnt->device == SDp) {
tpnt->device = NULL;
+ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+ devfs_unregister (tpnt->de_r[mode]);
+ tpnt->de_r[mode] = NULL;
+ devfs_unregister (tpnt->de_n[mode]);
+ tpnt->de_n[mode] = NULL;
+ }
SDp->attached--;
st_template.nr_dev--;
st_template.dev_noticed--;
@@ -3445,7 +3478,7 @@ void cleanup_module(void)
int i;
scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+ devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
st_registered--;
if (scsi_tapes != NULL) {
for (i=0; i < st_template.dev_max; ++i)
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 479dca079..e751efc28 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -8,6 +8,7 @@
#ifndef _SCSI_H
#include "scsi.h"
#endif
+#include <linux/devfs_fs_kernel.h>
/* The tape buffer descriptor. */
typedef struct {
@@ -18,9 +19,9 @@ typedef struct {
int buffer_bytes;
int read_pointer;
int writing;
- int last_result;
- int last_result_fatal;
- Scsi_Cmnd *last_SCpnt;
+ int midlevel_result;
+ int syscall_result;
+ Scsi_Request *last_SRpnt;
unsigned char *b_data;
unsigned short use_sg; /* zero or number of segments for this adapter */
unsigned short sg_segs; /* total number of allocated segments */
@@ -85,6 +86,8 @@ typedef struct {
/* Mode characteristics */
ST_mode modes[ST_NBR_MODES];
int current_mode;
+ devfs_handle_t de_r[ST_NBR_MODES]; /* Rewind entries */
+ devfs_handle_t de_n[ST_NBR_MODES]; /* No-rewind entries */
/* Status variables */
int partition;
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
new file mode 100644
index 000000000..510386823
--- /dev/null
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -0,0 +1,3012 @@
+/* sun3_NCR5380.c -- adapted from atari_NCR5380.c for the sun3 by
+ Sam Creasey. */
+/*
+ * NCR 5380 generic driver routines. These should make it *trivial*
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
+ *
+ * Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
+ * this file, too:
+ *
+ * - Some of the debug statements were incorrect (undefined variables and the
+ * like). I fixed that.
+ *
+ * - In information_transfer(), I think a #ifdef was wrong. Looking at the
+ * possible DMA transfer size should also happen for REAL_DMA. I added this
+ * in the #if statement.
+ *
+ * - When using real DMA, information_transfer() should return in a DATAOUT
+ * phase after starting the DMA. It has nothing more to do.
+ *
+ * - The interrupt service routine should run main after end of DMA, too (not
+ * only after RESELECTION interrupts). Additionally, it should _not_ test
+ * for more interrupts after running main, since a DMA process may have
+ * been started and interrupts are turned on now. The new int could happen
+ * inside the execution of NCR5380_intr(), leading to recursive
+ * calls.
+ *
+ * - I've added a function merge_contiguous_buffers() that tries to
+ * merge scatter-gather buffers that are located at contiguous
+ * physical addresses and can be processed with the same DMA setup.
+ * Since most scatter-gather operations work on a page (4K) of
+ * 4 buffers (1K), in more than 90% of all cases three interrupts and
+ * DMA setup actions are saved.
+ *
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ * and USLEEP, because these were messing up readability and will never be
+ * needed for Atari SCSI.
+ *
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ * stuff), and 'main' is executed in a bottom half if awoken by an
+ * interrupt.
+ *
+ * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
+ * constructs. In my eyes, this made the source rather unreadable, so I
+ * finally replaced that by the *_PRINTK() macros.
+ *
+ */
+
+/*
+ * Further development / testing that should be done :
+ * 1. Test linked command handling code after Eric is ready with
+ * the high level code.
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) \
+ { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+ if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) \
+ { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \
+ (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+ if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip. This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+ * routines were implemented, meaning their implementations of queued
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver. To use it on a different platform,
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing. This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
+ * while a command is already executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem,
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system. So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the
+ * NCR5380_print_options command, which should be called from the
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 :
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected. Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * while doing long seek operations.
+ *
+ * The workaround for this is to keep track of devices that have
+ * disconnected. If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ *
+ * Some tweaking of N and M needs to be done. An algorithm based
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function. It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the
+ * issue queue and calling NCR5380_select() if a nexus
+ * is not established.
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work. If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr() which will in turn call NCR5380_reselect
+ * to reestablish a nexus. This will run main if necessary.
+ *
+ * On command termination, the done function will be called as
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips. To use it, you write an architecture specific functions
+ * and macros and include this file in your driver.
+ *
+ * These macros control options :
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ * for commands that return with a CHECK CONDITION status.
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+ *
+ * NCR5380_read(register) - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions :
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes
+ * that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define
+ *
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+ * to be the global entry points into the specific driver, ie
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID. If the
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used. Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/* Macros ease life... :-) */
+#define SETUP_HOSTDATA(in) \
+ struct NCR5380_hostdata *hostdata = \
+ (struct NCR5380_hostdata *)(in)->hostdata
+#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble))
+#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+#define HOSTNO instance->host_no
+#define H_NO(cmd) (cmd)->host->host_no
+
+#ifdef SUPPORT_TAGS
+
+/*
+ * Functions for handling tagged queuing
+ * =====================================
+ *
+ * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
+ *
+ * Using consecutive numbers for the tags is no good idea in my eyes. There
+ * could be wrong re-usings if the counter (8 bit!) wraps and some early
+ * command has been preempted for a long time. My solution: a bitfield for
+ * remembering used tags.
+ *
+ * There's also the problem that each target has a certain queue size, but we
+ * cannot know it in advance :-( We just see a QUEUE_FULL status being
+ * returned. So, in this case, the driver internal queue size assumption is
+ * reduced to the number of active tags if QUEUE_FULL is returned by the
+ * target. The command is returned to the mid-level, but with status changed
+ * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
+ * correctly.
+ *
+ * We're also not allowed running tagged commands as long as an untagged
+ * command is active. And REQUEST SENSE commands after a contingent allegiance
+ * condition _must_ be untagged. To keep track whether an untagged command has
+ * been issued, the host->busy array is still employed, as it is without
+ * support for tagged queuing.
+ *
+ * One could suspect that there are possible race conditions between
+ * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
+ * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
+ * which already guaranteed to be running at most once. It is also the only
+ * place where tags/LUNs are allocated. So no other allocation can slip
+ * between that pair, there could only happen a reselection, which can free a
+ * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
+ * important: the tag bit must be cleared before 'nr_allocated' is decreased.
+ */
+
+/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
+#undef TAG_NONE
+#define TAG_NONE 0xff
+
+/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
+#if (MAX_TAGS % 32) != 0
+#error "MAX_TAGS must be a multiple of 32!"
+#endif
+
+typedef struct {
+ char allocated[MAX_TAGS/8];
+ int nr_allocated;
+ int queue_size;
+} TAG_ALLOC;
+
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+static void __init init_tags( void )
+{
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for( target = 0; target < 8; ++target ) {
+ for( lun = 0; lun < 8; ++lun ) {
+ ta = &TagAlloc[target][lun];
+ memset( &ta->allocated, 0, MAX_TAGS/8 );
+ ta->nr_allocated = 0;
+ /* At the beginning, assume the maximum queue size we could
+ * support (MAX_TAGS). This value will be decreased if the target
+ * returns QUEUE_FULL status.
+ */
+ ta->queue_size = MAX_TAGS;
+ }
+ }
+}
+
+
+/* Check if we can issue a command to this LUN: First see if the LUN is marked
+ * busy by an untagged command. If the command should use tagged queuing, also
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+ */
+
+static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+ SETUP_HOSTDATA(cmd->host);
+
+ if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+ return( 1 );
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported)
+ return( 0 );
+ if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
+ TagAlloc[cmd->target][cmd->lun].queue_size ) {
+ TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+ H_NO(cmd), cmd->target, cmd->lun );
+ return( 1 );
+ }
+ return( 0 );
+}
+
+
+/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
+ * must be called before!), or reserve the LUN in 'busy' if the command is
+ * untagged.
+ */
+
+static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+ SETUP_HOSTDATA(cmd->host);
+
+ /* If we or the target don't support tagged queuing, allocate the LUN for
+ * an untagged command.
+ */
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+ cmd->tag = TAG_NONE;
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+ "command\n", H_NO(cmd), cmd->target, cmd->lun );
+ }
+ else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+
+ cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
+ set_bit( cmd->tag, &ta->allocated );
+ ta->nr_allocated++;
+ TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+ "(now %d tags in use)\n",
+ H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+ ta->nr_allocated );
+ }
+}
+
+
+/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
+ * unlock the LUN.
+ */
+
+static void cmd_free_tag( Scsi_Cmnd *cmd )
+{
+ SETUP_HOSTDATA(cmd->host);
+
+ if (cmd->tag == TAG_NONE) {
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+ H_NO(cmd), cmd->target, cmd->lun );
+ }
+ else if (cmd->tag >= MAX_TAGS) {
+ printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+ H_NO(cmd), cmd->tag );
+ }
+ else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ clear_bit( cmd->tag, &ta->allocated );
+ ta->nr_allocated--;
+ TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+ H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+ }
+}
+
+
+static void free_all_tags( void )
+{
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for( target = 0; target < 8; ++target ) {
+ for( lun = 0; lun < 8; ++lun ) {
+ ta = &TagAlloc[target][lun];
+ memset( &ta->allocated, 0, MAX_TAGS/8 );
+ ta->nr_allocated = 0;
+ }
+ }
+}
+
+#endif /* SUPPORT_TAGS */
+
+
+/*
+ * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ * transfer. This is possible if the scatter buffers lie on
+ * physical contiguous addresses.
+ *
+ * Parameters: Scsi_Cmnd *cmd
+ * The command to work on. The first scatter buffer's data are
+ * assumed to be already transfered into ptr/this_residual.
+ */
+
+static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+{
+ unsigned long endaddr;
+#if (NDEBUG & NDEBUG_MERGING)
+ unsigned long oldlen = cmd->SCp.this_residual;
+ int cnt = 1;
+#endif
+
+ for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+ cmd->SCp.buffers_residual &&
+ virt_to_phys(cmd->SCp.buffer[1].address) == endaddr; ) {
+
+ MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+ cmd->SCp.buffer[1].address, endaddr);
+#if (NDEBUG & NDEBUG_MERGING)
+ ++cnt;
+#endif
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual += cmd->SCp.buffer->length;
+ endaddr += cmd->SCp.buffer->length;
+ }
+#if (NDEBUG & NDEBUG_MERGING)
+ if (oldlen != cmd->SCp.this_residual)
+ MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+ cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+}
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the
+ * start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+{
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
+ * various queues are valid.
+ */
+
+ if (cmd->use_sg) {
+ cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffers_residual = cmd->use_sg - 1;
+ cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ /* ++roman: Try to merge some scatter-buffers if they are at
+ * contiguous physical addresses.
+ */
+ merge_contiguous_buffers( cmd );
+ } else {
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ cmd->SCp.ptr = (char *) cmd->request_buffer;
+ cmd->SCp.this_residual = cmd->request_bufflen;
+ }
+
+}
+
+#include <linux/config.h>
+#include <linux/delay.h>
+
+#if 1
+static struct {
+ unsigned char mask;
+ const char * name;}
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
+ { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
+ { SR_SEL, "SEL" }, {0, NULL}},
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
+ "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+ {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+ {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+ {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+ unsigned char status, data, basr, mr, icr, i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+ status = NCR5380_read(STATUS_REG);
+ mr = NCR5380_read(MODE_REG);
+ icr = NCR5380_read(INITIATOR_COMMAND_REG);
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ restore_flags(flags);
+ printk("STATUS_REG: %02x ", status);
+ for (i = 0; signals[i].mask ; ++i)
+ if (status & signals[i].mask)
+ printk(",%s", signals[i].name);
+ printk("\nBASR: %02x ", basr);
+ for (i = 0; basrs[i].mask ; ++i)
+ if (basr & basrs[i].mask)
+ printk(",%s", basrs[i].name);
+ printk("\nICR: %02x ", icr);
+ for (i = 0; icrs[i].mask; ++i)
+ if (icr & icrs[i].mask)
+ printk(",%s", icrs[i].name);
+ printk("\nMODE: %02x ", mr);
+ for (i = 0; mrs[i].mask; ++i)
+ if (mr & mrs[i].mask)
+ printk(",%s", mrs[i].name);
+ printk("\n");
+}
+
+static struct {
+ unsigned char value;
+ const char *name;
+} phases[] = {
+ {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+ {PHASE_UNKNOWN, "UNKNOWN"}};
+
+/*
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+ unsigned char status;
+ int i;
+
+ status = NCR5380_read(STATUS_REG);
+ if (!(status & SR_REQ))
+ printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+ else {
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i);
+ printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+ }
+}
+
+#else /* !NDEBUG */
+
+/* dummies... */
+__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+
+#endif
+
+/*
+ * ++roman: New scheme of calling NCR5380_main()
+ *
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+ * 'main_running' needs not be protected in a special way.
+ *
+ * queue_main() is a utility function for putting our main onto the task
+ * queue, if main_running is false. It should be called only from a
+ * interrupt or bottom half.
+ */
+
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+static volatile int main_running = 0;
+static struct tq_struct NCR5380_tqueue = {
+ NULL, /* next */
+ 0, /* sync */
+ (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */
+ NULL /* data */
+};
+
+static __inline__ void queue_main(void)
+{
+ if (!main_running) {
+ /* If in interrupt and NCR5380_main() not already running,
+ queue it on the 'immediate' task queue, to be processed
+ immediately after the current interrupt processing has
+ finished. */
+ queue_task(&NCR5380_tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ /* else: nothing to do: the running NCR5380_main() will pick up
+ any newly queued command. */
+}
+
+
+static inline void NCR5380_all_init (void)
+{
+ static int done = 0;
+ if (!done) {
+ INI_PRINTK("scsi : NCR5380_all_init()\n");
+ done = 1;
+ }
+}
+
+
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ * options that were selected.
+ *
+ * Inputs : instance, pointer to this instance. Unused.
+ */
+
+static void __init NCR5380_print_options (struct Scsi_Host *instance)
+{
+ printk(" generic options"
+#ifdef AUTOSENSE
+ " AUTOSENSE"
+#endif
+#ifdef REAL_DMA
+ " REAL DMA"
+#endif
+#ifdef PARITY
+ " PARITY"
+#endif
+#ifdef SUPPORT_TAGS
+ " SCSI-2 TAGGED QUEUING"
+#endif
+ );
+ printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+/*
+ * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+ *
+ * Purpose : print commands in the various queues, called from
+ * NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+ * Inputs : instance, pointer to this instance.
+ */
+
+static void NCR5380_print_status (struct Scsi_Host *instance)
+{
+ char *pr_bfr;
+ char *start;
+ int len;
+
+ NCR_PRINT(NDEBUG_ANY);
+ NCR_PRINT_PHASE(NDEBUG_ANY);
+
+ pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
+ if (!pr_bfr) {
+ printk("NCR5380_print_status: no memory for print buffer\n");
+ return;
+ }
+ len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
+ pr_bfr[len] = 0;
+ printk("\n%s\n", pr_bfr);
+ free_page((unsigned long) pr_bfr);
+}
+
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
+
+#undef SPRINTF
+#define SPRINTF(fmt,args...) \
+ do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+ pos += sprintf(pos, fmt , ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+#ifndef NCR5380_proc_info
+static
+#endif
+int NCR5380_proc_info (char *buffer, char **start, off_t offset,
+ int length, int hostno, int inout)
+{
+ char *pos = buffer;
+ struct Scsi_Host *instance;
+ struct NCR5380_hostdata *hostdata;
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+ off_t begin = 0;
+#define check_offset() \
+ do { \
+ if (pos - buffer < offset - begin) { \
+ begin += pos - buffer; \
+ pos = buffer; \
+ } \
+ } while (0)
+
+ for (instance = first_instance; instance && HOSTNO != hostno;
+ instance = instance->next)
+ ;
+ if (!instance)
+ return(-ESRCH);
+ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+ if (inout) { /* Has data been written to the file ? */
+ return(-ENOSYS); /* Currently this is a no-op */
+ }
+ SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+ check_offset();
+ save_flags(flags);
+ cli();
+ SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+ check_offset();
+ if (!hostdata->connected)
+ SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+ else
+ pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+ pos, buffer, length);
+ SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+ check_offset();
+ for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ check_offset();
+ }
+
+ SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+ check_offset();
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ check_offset();
+ }
+
+ restore_flags(flags);
+ *start = buffer + (offset - begin);
+ if (pos - buffer < offset - begin)
+ return 0;
+ else if (pos - buffer - (offset - begin) < length)
+ return pos - buffer - (offset - begin);
+ return length;
+}
+
+static char *
+lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+{
+ int i, s;
+ unsigned char *command;
+ SPRINTF("scsi%d: destination target %d, lun %d\n",
+ H_NO(cmd), cmd->target, cmd->lun);
+ SPRINTF(" command = ");
+ command = cmd->cmnd;
+ SPRINTF("%2d (0x%02x)", command[0], command[0]);
+ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ SPRINTF(" %02x", command[i]);
+ SPRINTF("\n");
+ return pos;
+}
+
+
+/*
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * set correctly. I don't care about the irq and other fields.
+ *
+ */
+
+static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
+{
+ int i;
+ SETUP_HOSTDATA(instance);
+
+ NCR5380_all_init();
+
+ hostdata->aborted = 0;
+ hostdata->id_mask = 1 << instance->this_id;
+ hostdata->id_higher_mask = 0;
+ for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+ if (i > hostdata->id_mask)
+ hostdata->id_higher_mask |= i;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
+#ifdef SUPPORT_TAGS
+ init_tags();
+#endif
+#if defined (REAL_DMA)
+ hostdata->dma_len = 0;
+#endif
+ hostdata->targets_present = 0;
+ hostdata->connected = NULL;
+ hostdata->issue_queue = NULL;
+ hostdata->disconnected_queue = NULL;
+ hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+ if (!the_template) {
+ the_template = instance->hostt;
+ first_instance = instance;
+ }
+
+
+#ifndef AUTOSENSE
+ if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+ printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+ " without AUTOSENSE option, contingent allegiance conditions may\n"
+ " be incorrectly cleared.\n", HOSTNO);
+#endif /* def AUTOSENSE */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+}
+
+/*
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ * Side effects :
+ * cmd is added to the per instance issue_queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
+ * main coroutine is not running, it is restarted.
+ *
+ */
+
+/* Only make static if a wrapper function is used */
+#ifndef NCR5380_queue_command
+static
+#endif
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+ SETUP_HOSTDATA(cmd->host);
+ Scsi_Cmnd *tmp;
+ unsigned long flags;
+ extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ case WRITE_10:
+ printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+ H_NO(cmd));
+ cmd->result = (DID_ERROR << 16);
+ done(cmd);
+ return 0;
+ }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+#ifdef NCR5380_STATS
+# if 0
+ if (!hostdata->connected && !hostdata->issue_queue &&
+ !hostdata->disconnected_queue) {
+ hostdata->timebase = jiffies;
+ }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+ switch (cmd->cmnd[0])
+ {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+ hostdata->pendingw++;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+ hostdata->pendingr++;
+ break;
+ }
+#endif
+
+ /*
+ * We use the host_scribble field as a pointer to the next command
+ * in a queue
+ */
+
+ NEXT(cmd) = NULL;
+ cmd->scsi_done = done;
+
+ cmd->result = 0;
+
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ * commands are added to the head of the queue since any command will
+ * clear the contingent allegiance condition that exists and the
+ * sense data is only guaranteed to be valid while the condition exists.
+ */
+
+ save_flags(flags);
+ cli();
+ /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+ * Otherwise a running NCR5380_main may steal the lock.
+ * Lock before actually inserting due to fairness reasons explained in
+ * atari_scsi.c. If we insert first, then it's impossible for this driver
+ * to release the lock.
+ * Stop timer for this command while waiting for the lock, or timeouts
+ * may happen (and they really do), and it's no good if the command doesn't
+ * appear in any of the queues.
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which would
+ * alter queues and touch the lock.
+ */
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ LIST(cmd, hostdata->issue_queue);
+ NEXT(cmd) = hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ NEXT(tmp); tmp = NEXT(tmp))
+ ;
+ LIST(cmd, tmp);
+ NEXT(tmp) = cmd;
+ }
+
+ restore_flags(flags);
+
+ QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+ (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+ /* If queue_command() is called from an interrupt (real one or bottom
+ * half), we let queue_main() do the job of taking care about main. If it
+ * is already running, this is a no-op, else main will be queued.
+ *
+ * If we're not in an interrupt, we can call NCR5380_main()
+ * unconditionally, because it cannot be already running.
+ */
+ if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+ queue_main();
+ else
+ NCR5380_main();
+ return 0;
+}
+
+/*
+ * Function : NCR5380_main (void)
+ *
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
+ *
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
+ * reenable them. This prevents reentrancy and kernel stack overflow.
+ */
+
+static void NCR5380_main (void)
+{
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *instance = first_instance;
+ struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+ int done;
+ unsigned long flags;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set main_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ * this should prevent any race conditions.
+ *
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which can
+ * alter queues and touch the Falcon lock.
+ */
+
+ /* Tell int handlers main() is now already executing. Note that
+ no races are possible here. If an int comes in before
+ 'main_running' is set here, and queues/executes main via the
+ task queue, it doesn't do any harm, just this instance of main
+ won't find any work left to do. */
+ if (main_running)
+ return;
+ main_running = 1;
+
+ save_flags(flags);
+ do {
+ cli(); /* Freeze request queues */
+ done = 1;
+
+ if (!hostdata->connected) {
+ MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
+ /*
+ * Search through the issue_queue for a command destined
+ * for a target that's not busy.
+ */
+#if (NDEBUG & NDEBUG_LISTS)
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+ tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+ ;
+ if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+#endif
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+#if (NDEBUG & NDEBUG_LISTS)
+ if (prev != tmp)
+ printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
+ tmp, tmp->target, hostdata->busy[tmp->target],
+ tmp->lun);
+#endif
+ /* When we find one, remove it from the issue queue. */
+ /* ++guenther: possible race with Falcon locking */
+ if (
+#ifdef SUPPORT_TAGS
+ !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+#else
+ !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+#endif
+ ) {
+ cli(); /* ++guenther: just to be sure, this must be atomic */
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ NEXT(prev) = NEXT(tmp);
+ } else {
+ REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+ hostdata->issue_queue = NEXT(tmp);
+ }
+ NEXT(tmp) = NULL;
+
+ /* reenable interrupts after finding one */
+ restore_flags(flags);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ MAIN_PRINTK("scsi%d: main(): command for target %d "
+ "lun %d removed from issue_queue\n",
+ HOSTNO, tmp->target, tmp->lun);
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+ /* ++roman: ...and the standard also requires that
+ * REQUEST SENSE command are untagged.
+ */
+
+#ifdef SUPPORT_TAGS
+ cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+#endif
+ if (!NCR5380_select(instance, tmp,
+ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
+ TAG_NEXT)) {
+ break;
+ } else {
+ cli();
+ LIST(tmp, hostdata->issue_queue);
+ NEXT(tmp) = hostdata->issue_queue;
+ hostdata->issue_queue = tmp;
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( tmp );
+#endif
+ restore_flags(flags);
+ MAIN_PRINTK("scsi%d: main(): select() failed, "
+ "returned to issue_queue\n", HOSTNO);
+ if (hostdata->connected)
+ break;
+ }
+ } /* if target/lun/target queue is not busy */
+ } /* for issue_queue */
+ } /* if (!hostdata->connected) */
+ if (hostdata->connected
+#ifdef REAL_DMA
+ && !hostdata->dma_len
+#endif
+ ) {
+ restore_flags(flags);
+ MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+ HOSTNO);
+ NCR5380_information_transfer(instance);
+ MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+ done = 0;
+ }
+ } while (!done);
+
+ /* Better allow ints _after_ 'main_running' has been cleared, else
+ an interrupt could believe we'll pick up the work it left for
+ us, but we won't see it anymore here... */
+ main_running = 0;
+ restore_flags(flags);
+}
+
+
+#ifdef REAL_DMA
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+ * mismatch occurs (which would finish the DMA transfer).
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+static void NCR5380_dma_complete( struct Scsi_Host *instance )
+{
+ SETUP_HOSTDATA(instance);
+ int transfered;
+ unsigned char **data;
+ volatile int *count;
+
+ if (!hostdata->connected) {
+ printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+ "no connected cmd\n", HOSTNO);
+ return;
+ }
+
+ DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+ HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
+
+ if((sun3scsi_dma_finish())) {
+ printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO);
+ printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+ printk("error was produced.\n");
+ machine_halt();
+ }
+
+ /* make sure we're not stuck in a data phase */
+ if((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH |
+ BASR_ACK)) ==
+ (BASR_PHASE_MATCH | BASR_ACK)) {
+ printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
+ printk("scsi%d: bus stuck in data phase -- probably a
+ single byte overrun!\n", HOSTNO);
+ printk("not prepared for this error!\n");
+ printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+ printk("error was produced.\n");
+ machine_halt();
+ }
+
+
+
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+ hostdata->dma_len = 0;
+
+ data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+ count = &(hostdata->connected->SCp.this_residual);
+ *data += transfered;
+ *count -= transfered;
+
+}
+#endif /* REAL_DMA */
+
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ *
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static void NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct Scsi_Host *instance = first_instance;
+ int done = 1;
+ unsigned char basr;
+
+ INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+ /* Look for pending interrupts */
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+ /* dispatch to appropriate routine if found and done=0 */
+ if (basr & BASR_IRQ) {
+ NCR_PRINT(NDEBUG_INTR);
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+ done = 0;
+ ENABLE_IRQ();
+ INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+ NCR5380_reselect(instance);
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ else if (basr & BASR_PARITY_ERROR) {
+ INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+ INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ else {
+ /*
+ * The rest of the interrupt conditions can occur only during a
+ * DMA transfer
+ */
+
+#if defined(REAL_DMA)
+ /*
+ * We should only get PHASE MISMATCH and EOP interrupts if we have
+ * DMA enabled, so do a sanity check based on the current setting
+ * of the MODE register.
+ */
+
+ if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+ ((basr & BASR_END_DMA_TRANSFER) ||
+ !(basr & BASR_PHASE_MATCH))) {
+
+ INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+ NCR5380_dma_complete( instance );
+ done = 0;
+ ENABLE_IRQ();
+ } else
+#endif /* REAL_DMA */
+ {
+/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+ if (basr & BASR_PHASE_MATCH)
+ printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+ "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+ HOSTNO, basr, NCR5380_read(MODE_REG),
+ NCR5380_read(STATUS_REG));
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ } /* if !(SELECTION || PARITY) */
+ } /* BASR & IRQ */
+ else {
+
+ printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+ "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+ NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+
+ if (!done) {
+ INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+ /* Put a call to NCR5380_main() on the queue... */
+ queue_main();
+ }
+}
+
+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+ switch (cmd->cmnd[0])
+ {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+ hostdata->pendingw--;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+ hostdata->pendingr--;
+ break;
+ }
+}
+#endif
+
+/*
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+ * int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
+ * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
+ * the command that is presently connected.
+ *
+ * Returns : -1 if selection could not execute for some reason,
+ * 0 if selection succeeded or failed because the target
+ * did not respond.
+ *
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
+ *
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
+ *
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+{
+ SETUP_HOSTDATA(instance);
+ unsigned char tmp[3], phase;
+ unsigned char *data;
+ int len;
+ unsigned long timeout;
+ unsigned long flags;
+
+ hostdata->restart_select = 0;
+ NCR_PRINT(NDEBUG_ARBITRATION);
+ ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+ instance->this_id);
+
+ /*
+ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+ * data bus during SELECTION.
+ */
+
+ save_flags(flags);
+ cli();
+ if (hostdata->connected) {
+ restore_flags(flags);
+ return -1;
+ }
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+
+ /*
+ * Start arbitration.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+ NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+ restore_flags(flags);
+
+ /* Wait for arbitration logic to complete */
+#if NCR_TIMEOUT
+ {
+ unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+ && time_before(jiffies, timeout) && !hostdata->connected)
+ ;
+ if (time_after_eq(jiffies, timeout))
+ {
+ printk("scsi : arbitration timeout at %d\n", __LINE__);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ }
+#else /* NCR_TIMEOUT */
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+ && !hostdata->connected);
+#endif
+
+ ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
+
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ return -1;
+ }
+ /*
+ * The arbitration delay is 2.2us, but this is a minimum and there is
+ * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+ * the integral nature of udelay().
+ *
+ */
+
+ udelay(3);
+
+ /* Check for lost arbitration */
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /* after/during arbitration, BSY should be asserted.
+ IBM DPES-31080 Version S31Q works now */
+ /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+ ICR_ASSERT_BSY ) ;
+
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /*
+ * Again, bus clear + bus settle time is 1.2us, however, this is
+ * a minimum so we'll udelay ceil(1.2)
+ */
+
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+ /* ++roman: But some targets (see above :-) seem to need a bit more... */
+ udelay(15);
+#else
+ udelay(2);
+#endif
+
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
+ ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+ /*
+ * Now that we have won arbitration, start Selection process, asserting
+ * the host and target ID's on the SCSI bus.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+
+ /*
+ * Raise ATN while SEL is true before BSY goes false from arbitration,
+ * since this is the only way to guarantee that we'll get a MESSAGE OUT
+ * phase immediately after selection.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+ NCR5380_write(MODE_REG, MR_BASE);
+
+ /*
+ * Reselect interrupts must be turned off prior to the dropping of BSY,
+ * otherwise we will trigger an interrupt.
+ */
+
+ if (hostdata->connected) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ /*
+ * The initiator shall then wait at least two deskew delays and release
+ * the BSY signal.
+ */
+ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+
+ /* Reset BSY */
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+ /*
+ * Something weird happens when we cease to drive BSY - looks
+ * like the board/chip is letting us do another read before the
+ * appropriate propagation delay has expired, and we're confusing
+ * a BSY signal from ourselves as the target's response to SELECTION.
+ *
+ * A small delay (the 'C++' frontend breaks the pipeline with an
+ * unnecessary jump, making it work on my 386-33/Trantor T128, the
+ * tighter 'C' code breaks and requires this) solves the problem -
+ * the 1 us delay is arbitrary, and only used because this delay will
+ * be the same on other platforms and since it works here, it should
+ * work there.
+ *
+ * wingel suggests that this could be due to failing to wait
+ * one deskew delay.
+ */
+
+ udelay(1);
+
+ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+
+ /*
+ * The SCSI specification calls for a 250 ms timeout for the actual
+ * selection.
+ */
+
+ timeout = jiffies + 25;
+
+ /*
+ * XXX very interesting - we're seeing a bounce where the BSY we
+ * asserted is being reflected / still asserted (propagation delay?)
+ * and it's detecting as true. Sigh.
+ */
+
+#if 0
+ /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+ * IO while SEL is true. But again, there are some disks out the in the
+ * world that do that nevertheless. (Somebody claimed that this announces
+ * reselection capability of the target.) So we better skip that test and
+ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+ */
+
+ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
+ (SR_BSY | SR_IO)));
+
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
+ (SR_SEL | SR_IO)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_reselect(instance);
+ printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+ HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+#else
+ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+#endif
+
+ /*
+ * No less than two deskew delays after the initiator detects the
+ * BSY signal is true, it shall release the SEL signal and may
+ * change the DATA BUS. -wingel
+ */
+
+ udelay(1);
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+ if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ if (hostdata->targets_present & (1 << cmd->target)) {
+ printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+ if (hostdata->restart_select)
+ printk(KERN_NOTICE "\trestart select\n");
+ NCR_PRINT(NDEBUG_ANY);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+#endif
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return 0;
+ }
+
+ hostdata->targets_present |= (1 << cmd->target);
+
+ /*
+ * Since we followed the SCSI spec, and raised ATN while SEL
+ * was true but before BSY was false during selection, the information
+ * transfer phase should be a MESSAGE OUT phase so that we can send the
+ * IDENTIFY message.
+ *
+ * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+ * message (2 bytes) with a tag ID that we increment with every command
+ * until it wraps back to 0.
+ *
+ * XXX - it turns out that there are some broken SCSI-II devices,
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
+ */
+
+ /* Wait for start of REQ/ACK handshake */
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+ SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+ HOSTNO, cmd->target);
+ tmp[0] = IDENTIFY(1, cmd->lun);
+
+#ifdef SUPPORT_TAGS
+ if (cmd->tag != TAG_NONE) {
+ tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+ tmp[2] = cmd->tag;
+ len = 3;
+ } else
+ len = 1;
+#else
+ len = 1;
+ cmd->tag=0;
+#endif /* SUPPORT_TAGS */
+
+ /* Send message(s) */
+ data = tmp;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+ /* XXX need to handle errors here */
+ hostdata->connected = cmd;
+#ifndef SUPPORT_TAGS
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+#endif
+
+ initialize_SCp(cmd);
+
+
+ return 0;
+}
+
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes are transfered or exit
+ * is in same phase.
+ *
+ * Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio( struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
+ register unsigned char p = *phase, tmp;
+ register int c = *count;
+ register unsigned char *d = *data;
+
+ /*
+ * The NCR5380 chip will only drive the SCSI bus when the
+ * phase specified in the appropriate bits of the TARGET COMMAND
+ * REGISTER match the STATUS REGISTER
+ */
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+ do {
+ /*
+ * Wait for assertion of REQ, after which the phase bits will be
+ * valid
+ */
+ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+ HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+
+ /* Check for phase mismatch */
+ if ((tmp & PHASE_MASK) != p) {
+ PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+ NCR_PRINT_PHASE(NDEBUG_PIO);
+ break;
+ }
+
+ /* Do actual transfer from SCSI bus to / from memory */
+ if (!(p & SR_IO))
+ NCR5380_write(OUTPUT_DATA_REG, *d);
+ else
+ *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+ ++d;
+
+ /*
+ * The SCSI standard suggests that in MSGOUT phase, the initiator
+ * should drop ATN on the last byte of the message phase
+ * after REQ has been asserted for the handshake but before
+ * the initiator raises ACK.
+ */
+
+ if (!(p & SR_IO)) {
+ if (!((p & SR_MSG) && c > 1)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ } else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ }
+ } else {
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+ }
+
+ while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+ HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
+ *
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3. ACK and ATN are clear and the target may proceed as normal.
+ */
+ if (!(p == PHASE_MSGIN && c == 1)) {
+ if (p == PHASE_MSGOUT && c > 1)
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ else
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ }
+ } while (--c);
+
+ PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+ *count = c;
+ *data = d;
+ tmp = NCR5380_read(STATUS_REG);
+ /* The phase read from the bus is valid if either REQ is (already)
+ * asserted or if ACK hasn't been released yet. The latter is the case if
+ * we're in MSGIN and all wanted bytes have been received. */
+ if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+ *phase = tmp & PHASE_MASK;
+ else
+ *phase = PHASE_UNKNOWN;
+
+ if (!c || (*phase == p))
+ return 0;
+ else
+ return -1;
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ *
+ * Purpose : abort the currently established nexus. Should only be
+ * called from a routine which can drop into a
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+static int do_abort (struct Scsi_Host *host)
+{
+ unsigned char tmp, *msgptr, phase;
+ int len;
+
+ /* Request message out phase */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+ /*
+ * Wait for the target to indicate a valid phase by asserting
+ * REQ. Once this happens, we'll have either a MSGOUT phase
+ * and can immediately send the ABORT message, or we'll have some
+ * other phase and will have to source/sink data.
+ *
+ * We really don't care what value was on the bus or what value
+ * the target sees, so we just handshake.
+ */
+
+ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ }
+
+ tmp = ABORT;
+ msgptr = &tmp;
+ len = 1;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+
+ /*
+ * If we got here, and the command completed successfully,
+ * we're about to go into bus free state.
+ */
+
+ return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA)
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ * or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes or transfered or exit
+ * is in same phase.
+ *
+ * Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma( struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
+ SETUP_HOSTDATA(instance);
+ register int c = *count;
+ register unsigned char p = *phase;
+ unsigned long flags;
+
+ /* sanity check */
+ if(!sun3_dma_setup_done) {
+ printk("scsi%d: transfer_dma without setup!\n", HOSTNO);
+ machine_halt();
+ }
+
+ hostdata->dma_len = c;
+
+ DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+ HOSTNO, (p & SR_IO) ? "reading" : "writing",
+ c, (p & SR_IO) ? "to" : "from", d);
+
+ /* netbsd turns off ints here, why not be safe and do it too */
+ save_flags(flags);
+ cli();
+
+ /* send start chain */
+ sun3_udc_write(UDC_CHN_START, UDC_CSR);
+
+ if (p & SR_IO) {
+ NCR5380_write(TARGET_COMMAND_REG, 1);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(INITIATOR_COMMAND_REG, 0);
+ NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+ NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+ } else {
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
+ NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+ NCR5380_write(START_DMA_SEND_REG, 0);
+ }
+
+ restore_flags(flags);
+
+ sun3_dma_active = 1;
+ return 0;
+}
+#endif /* defined(REAL_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to. Operates on the currently connected command,
+ * instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be
+ * modified if a command disconnects, *instance->connected will
+ * change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
+ */
+
+static void NCR5380_information_transfer (struct Scsi_Host *instance)
+{
+ SETUP_HOSTDATA(instance);
+ unsigned long flags;
+ unsigned char msgout = NOP;
+ int sink = 0;
+ int len;
+#if defined(REAL_DMA)
+ int transfersize;
+#endif
+ unsigned char *data;
+ unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+ Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+ while (1) {
+ tmp = NCR5380_read(STATUS_REG);
+ /* We only have a valid SCSI phase when REQ is asserted */
+ if (tmp & SR_REQ) {
+ phase = (tmp & PHASE_MASK);
+ if (phase != old_phase) {
+ old_phase = phase;
+ NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+ }
+
+ if(phase == PHASE_CMDOUT) {
+ void *d;
+ unsigned long count;
+
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ count = cmd->SCp.buffer->length;
+ d = cmd->SCp.buffer->address;
+ } else {
+ count = cmd->SCp.this_residual;
+ d = cmd->SCp.ptr;
+ }
+#ifdef REAL_DMA
+ /* this command setup for dma yet? */
+ if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+ != cmd))
+ {
+ sun3scsi_dma_setup(d, count,
+ cmd->request.cmd);
+ sun3_dma_setup_done = cmd;
+ }
+#endif
+ }
+
+
+ if (sink && (phase != PHASE_MSGOUT)) {
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 0;
+ continue;
+ }
+
+ switch (phase) {
+ case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+ printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+ "aborted\n", HOSTNO);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ return;
+#endif
+ case PHASE_DATAIN:
+ /*
+ * If there is no room left in the current buffer in the
+ * scatter-gather list, move onto the next one.
+ */
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ cmd->SCp.ptr = cmd->SCp.buffer->address;
+
+ /* ++roman: Try to merge some scatter-buffers if
+ * they are at contiguous physical addresses.
+ */
+// merge_contiguous_buffers( cmd );
+ INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+ HOSTNO, cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
+ }
+
+ /*
+ * The preferred transfer method is going to be
+ * PSEUDO-DMA for systems that are strictly PIO,
+ * since we can let the hardware do the handshaking.
+ *
+ * For this to work, we need to know the transfersize
+ * ahead of time, since the pseudo-DMA code will sit
+ * in an unconditional loop.
+ */
+
+/* ++roman: I suggest, this should be
+ * #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
+
+#if defined(REAL_DMA)
+// if (!cmd->device->borken &&
+ if((transfersize =
+ NCR5380_dma_xfer_len(instance,cmd,phase)) > SUN3_DMA_MINSIZE) {
+ len = transfersize;
+ cmd->SCp.phase = phase;
+
+ if (NCR5380_transfer_dma(instance, &phase,
+ &len, (unsigned char **) &cmd->SCp.ptr)) {
+ /*
+ * If the watchdog timer fires, all future
+ * accesses to this device will use the
+ * polled-IO. */
+ printk(KERN_NOTICE "scsi%d: switching target %d "
+ "lun %d to slow handshake\n", HOSTNO,
+ cmd->target, cmd->lun);
+ cmd->device->borken = 1;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ /* XXX - need to source or sink data here, as appropriate */
+ } else {
+#ifdef REAL_DMA
+ /* ++roman: When using real DMA,
+ * information_transfer() should return after
+ * starting DMA since it has nothing more to
+ * do.
+ */
+ return;
+#else
+ cmd->SCp.this_residual -= transfersize - len;
+#endif
+ }
+ } else
+#endif /* defined(REAL_DMA) */
+ NCR5380_transfer_pio(instance, &phase,
+ (int *) &cmd->SCp.this_residual, (unsigned char **)
+ &cmd->SCp.ptr);
+#ifdef REAL_DMA
+ /* if we had intended to dma that command clear it */
+ if(sun3_dma_setup_done == cmd)
+ sun3_dma_setup_done = NULL;
+#endif
+
+ break;
+ case PHASE_MSGIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Message = tmp;
+
+ switch (tmp) {
+ /*
+ * Linking lets us reduce the time required to get the
+ * next command out to the device, hopefully this will
+ * mean we don't waste another revolution due to the delays
+ * required by ARBITRATION and another SELECTION.
+ *
+ * In the current implementation proposal, low level drivers
+ * merely have to start the next command, pointed to by
+ * next_link, done() is called as with unlinked commands.
+ */
+#ifdef LINKED
+ case LINKED_CMD_COMPLETE:
+ case LINKED_FLG_CMD_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ LNK_PRINTK("scsi%d: target %d lun %d linked command "
+ "complete.\n", HOSTNO, cmd->target, cmd->lun);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Sanity check : A linked command should only terminate
+ * with one of these messages if there are more linked
+ * commands available.
+ */
+
+ if (!cmd->next_link) {
+ printk(KERN_NOTICE "scsi%d: target %d lun %d "
+ "linked command complete, no next_link\n",
+ HOSTNO, cmd->target, cmd->lun);
+ sink = 1;
+ do_abort (instance);
+ return;
+ }
+
+ initialize_SCp(cmd->next_link);
+ /* The next command is still part of this process; copy it
+ * and don't free it! */
+ cmd->next_link->tag = cmd->tag;
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ LNK_PRINTK("scsi%d: target %d lun %d linked request "
+ "done, calling scsi_done().\n",
+ HOSTNO, cmd->target, cmd->lun);
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+ cmd->scsi_done(cmd);
+ cmd = hostdata->connected;
+ break;
+#endif /* def LINKED */
+ case ABORT:
+ case COMMAND_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ hostdata->connected = NULL;
+ QU_PRINTK("scsi%d: command for target %d, lun %d "
+ "completed\n", HOSTNO, cmd->target, cmd->lun);
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+ if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+ /* Turn a QUEUE FULL status into BUSY, I think the
+ * mid level cannot handle QUEUE FULL :-( (The
+ * command is retried after BUSY). Also update our
+ * queue size to the number of currently issued
+ * commands now.
+ */
+ /* ++Andreas: the mid level code knows about
+ QUEUE_FULL now. */
+ TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+ TAG_PRINTK("scsi%d: target %d lun %d returned "
+ "QUEUE_FULL after %d commands\n",
+ HOSTNO, cmd->target, cmd->lun,
+ ta->nr_allocated);
+ if (ta->queue_size > ta->nr_allocated)
+ ta->nr_allocated = ta->queue_size;
+ }
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+ /*
+ * I'm not sure what the correct thing to do here is :
+ *
+ * If the command that just executed is NOT a request
+ * sense, the obvious thing to do is to set the result
+ * code to the values of the stored parameters.
+ *
+ * If it was a REQUEST SENSE command, we need some way to
+ * differentiate between the failure code of the original
+ * and the failure code of the REQUEST sense - the obvious
+ * case is success, where we fall through and leave the
+ * result code unchanged.
+ *
+ * The non-obvious place is where the REQUEST SENSE failed
+ */
+
+ if (cmd->cmnd[0] != REQUEST_SENSE)
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ else if (status_byte(cmd->SCp.Status) != GOOD)
+ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+
+#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] != REQUEST_SENSE) &&
+ (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ ASEN_PRINTK("scsi%d: performing request sense\n",
+ HOSTNO);
+ cmd->cmnd[0] = REQUEST_SENSE;
+ cmd->cmnd[1] &= 0xe0;
+ cmd->cmnd[2] = 0;
+ cmd->cmnd[3] = 0;
+ cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+ cmd->cmnd[5] = 0;
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+ cmd->use_sg = 0;
+ /* this is initialized from initialize_SCp
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ */
+ cmd->request_buffer = (char *) cmd->sense_buffer;
+ cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+ save_flags(flags);
+ cli();
+ LIST(cmd,hostdata->issue_queue);
+ NEXT(cmd) = hostdata->issue_queue;
+ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ restore_flags(flags);
+ QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+ "issue queue\n", H_NO(cmd));
+ } else
+#endif /* def AUTOSENSE */
+ {
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+ cmd->scsi_done(cmd);
+ }
+
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+
+ return;
+ case MESSAGE_REJECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ switch (hostdata->last_message) {
+ case HEAD_OF_QUEUE_TAG:
+ case ORDERED_QUEUE_TAG:
+ case SIMPLE_QUEUE_TAG:
+ /* The target obviously doesn't support tagged
+ * queuing, even though it announced this ability in
+ * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+ * clear 'tagged_supported' and lock the LUN, since
+ * the command is treated as untagged further on.
+ */
+ cmd->device->tagged_supported = 0;
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ cmd->tag = TAG_NONE;
+ TAG_PRINTK("scsi%d: target %d lun %d rejected "
+ "QUEUE_TAG message; tagged queuing "
+ "disabled\n",
+ HOSTNO, cmd->target, cmd->lun);
+ break;
+ }
+ break;
+ case DISCONNECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ save_flags(flags);
+ cli();
+ cmd->device->disconnect = 1;
+ LIST(cmd,hostdata->disconnected_queue);
+ NEXT(cmd) = hostdata->disconnected_queue;
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = cmd;
+ restore_flags(flags);
+ QU_PRINTK("scsi%d: command for target %d lun %d was "
+ "moved from connected to the "
+ "disconnected_queue\n", HOSTNO,
+ cmd->target, cmd->lun);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /* Wait for bus free to avoid nasty timeouts */
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+ return;
+ /*
+ * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+ * operation, in violation of the SCSI spec so we can safely
+ * ignore SAVE/RESTORE pointers calls.
+ *
+ * Unfortunately, some disks violate the SCSI spec and
+ * don't issue the required SAVE_POINTERS message before
+ * disconnecting, and we have to break spec to remain
+ * compatible.
+ */
+ case SAVE_POINTERS:
+ case RESTORE_POINTERS:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ break;
+ case EXTENDED_MESSAGE:
+/*
+ * Extended messages are sent in the following format :
+ * Byte
+ * 0 EXTENDED_MESSAGE == 1
+ * 1 length (includes one byte for code, doesn't
+ * include first two bytes)
+ * 2 code
+ * 3..length+1 arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.
+ */
+ extended_msg[0] = EXTENDED_MESSAGE;
+ /* Accept first byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+ len = 2;
+ data = extended_msg + 1;
+ phase = PHASE_MSGIN;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+ (int)extended_msg[1], (int)extended_msg[2]);
+
+ if (!len && extended_msg[1] <=
+ (sizeof (extended_msg) - 1)) {
+ /* Accept third byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ len = extended_msg[1] - 1;
+ data = extended_msg + 3;
+ phase = PHASE_MSGIN;
+
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: message received, residual %d\n",
+ HOSTNO, len);
+
+ switch (extended_msg[2]) {
+ case EXTENDED_SDTR:
+ case EXTENDED_WDTR:
+ case EXTENDED_MODIFY_DATA_POINTER:
+ case EXTENDED_EXTENDED_IDENTIFY:
+ tmp = 0;
+ }
+ } else if (len) {
+ printk(KERN_NOTICE "scsi%d: error receiving "
+ "extended message\n", HOSTNO);
+ tmp = 0;
+ } else {
+ printk(KERN_NOTICE "scsi%d: extended message "
+ "code %02x length %d is too long\n",
+ HOSTNO, extended_msg[2], extended_msg[1]);
+ tmp = 0;
+ }
+ /* Fall through to reject message */
+
+ /*
+ * If we get something weird that we aren't expecting,
+ * reject it.
+ */
+ default:
+ if (!tmp) {
+ printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+ print_msg (extended_msg);
+ printk("\n");
+ } else if (tmp != EXTENDED_MESSAGE)
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "message %02x from target %d, lun %d\n",
+ HOSTNO, tmp, cmd->target, cmd->lun);
+ else
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "extended message "
+ "code %02x, length %d from target %d, lun %d\n",
+ HOSTNO, extended_msg[1], extended_msg[0],
+ cmd->target, cmd->lun);
+
+
+ msgout = MESSAGE_REJECT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ break;
+ } /* switch (tmp) */
+ break;
+ case PHASE_MSGOUT:
+ len = 1;
+ data = &msgout;
+ hostdata->last_message = msgout;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ if (msgout == ABORT) {
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ hostdata->connected = NULL;
+ cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return;
+ }
+ msgout = NOP;
+ break;
+ case PHASE_CMDOUT:
+ len = cmd->cmd_len;
+ data = cmd->cmnd;
+ /*
+ * XXX for performance reasons, on machines with a
+ * PSEUDO-DMA architecture we should probably
+ * use the dma transfer function.
+ */
+ NCR5380_transfer_pio(instance, &phase, &len,
+ &data);
+ break;
+ case PHASE_STATIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Status = tmp;
+ break;
+ default:
+ printk("scsi%d: unknown phase\n", HOSTNO);
+ NCR_PRINT(NDEBUG_ANY);
+ } /* switch(phase) */
+ } /* if (tmp * SR_REQ) */
+ } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+/* it might eventually prove necessary to do a dma setup on
+ reselection, but it doesn't seem to be needed now -- sam */
+
+static void NCR5380_reselect (struct Scsi_Host *instance)
+{
+ SETUP_HOSTDATA(instance);
+ unsigned char target_mask;
+ unsigned char lun;
+#ifdef SUPPORT_TAGS
+ unsigned char tag;
+#endif
+ unsigned char msg[3];
+ Scsi_Cmnd *tmp = NULL, *prev;
+/* unsigned long flags; */
+
+ /*
+ * Disable arbitration, etc. since the host adapter obviously
+ * lost, and tell an interrupted NCR5380_select() to restart.
+ */
+
+ NCR5380_write(MODE_REG, MR_BASE);
+ hostdata->restart_select = 1;
+
+ target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+ RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+ /*
+ * At this point, we have detected that our SCSI ID is on the bus,
+ * SEL is true and BSY was false for at least one bus settle delay
+ * (400 ns).
+ *
+ * We must assert BSY ourselves, until the target drops the SEL
+ * signal.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+
+ while (NCR5380_read(STATUS_REG) & SR_SEL);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ /*
+ * Wait for target to go into MSGIN.
+ */
+
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+#if 1
+ // acknowledge toggle to MSGIN
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN));
+
+ // peek at the byte without really hitting the bus
+ msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG);
+#endif
+
+ if (!msg[0] & 0x80) {
+ printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+ print_msg(msg);
+ do_abort(instance);
+ return;
+ }
+ lun = (msg[0] & 0x07);
+
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just reestablished, and remove it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+ tmp; prev = tmp, tmp = NEXT(tmp) ) {
+ if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+#ifdef SUPPORT_TAGS
+ && (tag == tmp->tag)
+#endif
+ ) {
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ NEXT(prev) = NEXT(tmp);
+ } else {
+ REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+ hostdata->disconnected_queue = NEXT(tmp);
+ }
+ NEXT(tmp) = NULL;
+ break;
+ }
+ }
+
+ if (!tmp) {
+ printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+#ifdef SUPPORT_TAGS
+ "tag %d "
+#endif
+ "not in disconnected_queue.\n",
+ HOSTNO, target_mask, lun
+#ifdef SUPPORT_TAGS
+ , tag
+#endif
+ );
+ /*
+ * Since we have an established nexus that we can't do anything
+ * with, we must abort it.
+ */
+ do_abort(instance);
+ return;
+ }
+#if 1
+ /* engage dma setup for the command we just saw */
+ {
+ void *d;
+ unsigned long count;
+
+ if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
+ count = tmp->SCp.buffer->length;
+ d = tmp->SCp.buffer->address;
+ } else {
+ count = tmp->SCp.this_residual;
+ d = tmp->SCp.ptr;
+ }
+#ifdef REAL_DMA
+ /* setup this command for dma if not already */
+ if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+ != tmp))
+ {
+ sun3scsi_dma_setup(d, count,
+ tmp->request.cmd);
+ sun3_dma_setup_done = tmp;
+ }
+#endif
+ }
+#endif
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+#ifdef SUPPORT_TAGS
+ /* If the phase is still MSGIN, the target wants to send some more
+ * messages. In case it supports tagged queuing, this is probably a
+ * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+ */
+ tag = TAG_NONE;
+ if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+ /* Accept previous IDENTIFY message by clearing ACK */
+ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+ len = 2;
+ data = msg+1;
+ if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+ msg[1] == SIMPLE_QUEUE_TAG)
+ tag = msg[2];
+ TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+ "reselection\n", HOSTNO, target_mask, lun, tag);
+ }
+#endif
+
+ hostdata->connected = tmp;
+ RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+ HOSTNO, tmp->target, tmp->lun, tmp->tag);
+}
+
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ * host byte of the result field to, if zero DID_ABORTED is
+ * used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently
+ * connected, you have to wait for it to complete. If this is
+ * a problem, we could implement longjmp() / setjmp(), setjmp()
+ * called where the loop started in NCR5380_main().
+ */
+
+#ifndef NCR5380_abort
+static
+#endif
+int NCR5380_abort (Scsi_Cmnd *cmd)
+{
+ struct Scsi_Host *instance = cmd->host;
+ SETUP_HOSTDATA(instance);
+ Scsi_Cmnd *tmp, **prev;
+ unsigned long flags;
+
+ printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+ print_Scsi_Cmnd (cmd);
+
+ NCR5380_print_status (instance);
+
+ save_flags(flags);
+ cli();
+
+ ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+ NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
+
+#if 1
+/*
+ * Case 1 : If the command is the currently executing command,
+ * we'll set the aborted flag and return control so that
+ * information transfer routine can exit cleanly.
+ */
+
+ if (hostdata->connected == cmd) {
+
+ ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+/*
+ * Since we can't change phases until we've completed the current
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/*
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */
+
+ if (do_abort(instance) == 0) {
+ hostdata->aborted = 1;
+ hostdata->connected = NULL;
+ cmd->result = DID_ABORT << 16;
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( cmd );
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ restore_flags(flags);
+ cmd->scsi_done(cmd);
+ return SCSI_ABORT_SUCCESS;
+ } else {
+/* restore_flags(flags); */
+ printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+ return SCSI_ABORT_ERROR;
+ }
+ }
+#endif
+
+/*
+ * Case 2 : If the command hasn't been issued yet, we simply remove it
+ * from the issue queue.
+ */
+ for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
+ tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ (*prev) = NEXT(tmp);
+ NEXT(tmp) = NULL;
+ tmp->result = DID_ABORT << 16;
+ restore_flags(flags);
+ ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+ HOSTNO);
+ /* Tagged queuing note: no tag to free here, hasn't been assigned
+ * yet... */
+ tmp->scsi_done(tmp);
+ return SCSI_ABORT_SUCCESS;
+ }
+
+/*
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ * and let the high level SCSI driver retry at a later time or
+ * issue a reset.
+ *
+ * Timeouts, and therefore aborted commands, will be highly unlikely
+ * and handling them cleanly in this situation would make the common
+ * case of noresets less efficient, and would pollute our code. So,
+ * we fail.
+ */
+
+ if (hostdata->connected) {
+ restore_flags(flags);
+ ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+ return SCSI_ABORT_SNOOZE;
+ }
+
+/*
+ * Case 4: If the command is currently disconnected from the bus, and
+ * there are no connected commands, we reconnect the I_T_L or
+ * I_T_L_Q nexus associated with it, go into message out, and send
+ * an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select(). The easiest way to implement this
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that
+ * device reselected.
+ *
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+ tmp = NEXT(tmp))
+ if (cmd == tmp) {
+ restore_flags(flags);
+ ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
+
+ if (NCR5380_select (instance, cmd, (int) cmd->tag))
+ return SCSI_ABORT_BUSY;
+
+ ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+ do_abort (instance);
+
+ save_flags(flags);
+ cli();
+ for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
+ tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ *prev = NEXT(tmp);
+ NEXT(tmp) = NULL;
+ tmp->result = DID_ABORT << 16;
+ /* We must unlock the tag/LUN immediately here, since the
+ * target goes to BUS FREE and doesn't send us another
+ * message (COMMAND_COMPLETE or the like)
+ */
+#ifdef SUPPORT_TAGS
+ cmd_free_tag( tmp );
+#else
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+ restore_flags(flags);
+ tmp->scsi_done(tmp);
+ return SCSI_ABORT_SUCCESS;
+ }
+ }
+
+/*
+ * Case 5 : If we reached this point, the command was not found in any of
+ * the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+ restore_flags(flags);
+ printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+ KERN_INFO " before abortion\n", HOSTNO);
+
+ return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+/*
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ *
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+ */
+
+int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+{
+ SETUP_HOSTDATA(cmd->host);
+ int i;
+ unsigned long flags;
+#if 1
+ Scsi_Cmnd *connected, *disconnected_queue;
+#endif
+
+
+ NCR5380_print_status (cmd->host);
+
+ /* get in phase */
+ NCR5380_write( TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+ /* assert RST */
+ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+ udelay (40);
+ /* reset NCR registers */
+ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+ NCR5380_write( MODE_REG, MR_BASE );
+ NCR5380_write( TARGET_COMMAND_REG, 0 );
+ NCR5380_write( SELECT_ENABLE_REG, 0 );
+ /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+ * through anymore ... */
+ (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+ /* XXX see below XXX */
+
+ /* MSch: old-style reset: actually abort all command processing here */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; to avoid problems with re-inserting the commands
+ * into the issue_queue (via scsi_done()), the aborted commands are
+ * remembered in local variables first.
+ */
+ save_flags(flags);
+ cli();
+ connected = (Scsi_Cmnd *)hostdata->connected;
+ hostdata->connected = NULL;
+ disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+ free_all_tags();
+#endif
+ for( i = 0; i < 8; ++i )
+ hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+ restore_flags(flags);
+
+ /* In order to tell the mid-level code which commands were aborted,
+ * set the command status to DID_RESET and call scsi_done() !!!
+ * This ultimately aborts processing of these commands in the mid-level.
+ */
+
+ if ((cmd = connected)) {
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done( cmd );
+ }
+
+ for (i = 0; (cmd = disconnected_queue); ++i) {
+ disconnected_queue = NEXT(cmd);
+ NEXT(cmd) = NULL;
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done( cmd );
+ }
+ if (i > 0)
+ ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+
+ /* since all commands have been explicitly terminated, we need to tell
+ * the midlevel code that the reset was SUCCESSFUL, and there is no
+ * need to 'wake up' the commands by a request_sense
+ */
+ return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+#else /* 1 */
+
+ /* MSch: new-style reset handling: let the mid-level do what it can */
+
+ /* ++guenther: MID-LEVEL IS STILL BROKEN.
+ * Mid-level is supposed to requeue all commands that were active on the
+ * various low-level queues. In fact it does this, but that's not enough
+ * because all these commands are subject to timeout. And if a timeout
+ * happens for any removed command, *_abort() is called but all queues
+ * are now empty. Abort then gives up the falcon lock, which is fatal,
+ * since the mid-level will queue more commands and must have the lock
+ * (it's all happening inside timer interrupt handler!!).
+ * Even worse, abort will return NOT_RUNNING for all those commands not
+ * on any queue, so they won't be retried ...
+ *
+ * Conclusion: either scsi.c disables timeout for all resetted commands
+ * immediately, or we loose! As of linux-2.0.20 it doesn't.
+ */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; so clear the low-level status here to avoid
+ * conflicts when the mid-level code tries to wake up the affected
+ * commands!
+ */
+
+ if (hostdata->issue_queue)
+ ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+ if (hostdata->connected)
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ if (hostdata->disconnected_queue)
+ ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+ save_flags(flags);
+ cli();
+ hostdata->issue_queue = NULL;
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+ free_all_tags();
+#endif
+ for( i = 0; i < 8; ++i )
+ hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+ restore_flags(flags);
+
+ /* we did no complete reset of all commands, so a wakeup is required */
+ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+#endif /* 1 */
+}
+
+/* Local Variables: */
+/* tab-width: 8 */
+/* End: */
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index ba0be94dd..45f504fa3 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -1,6 +1,8 @@
/*
* Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
*
+ * Sun3 DMA routines added by Sam Creasey (sammy@oh.verio.com)
+ *
* Adapted from mac_scsinew.c:
*/
/*
@@ -44,13 +46,10 @@
*/
/*
- * $Log: mac_NCR5380.c,v $
+ * $Log: sun3_NCR5380.c,v $
*/
#define AUTOSENSE
-#if 0
-#define PSEUDO_DMA
-#endif
#include <linux/types.h>
#include <linux/stddef.h>
@@ -68,6 +67,9 @@
#include <asm/system.h>
#include <asm/sun3ints.h>
+#include <asm/dvma.h>
+/* dma on! */
+#define REAL_DMA
#include "scsi.h"
#include "hosts.h"
@@ -75,17 +77,12 @@
#include "NCR5380.h"
#include "constants.h"
-#if 0
-#define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION)
-#define NCR_TIMEOUT 100
-#else
-#define NDEBUG (NDEBUG_ABORT)
-#endif
-
#define USE_WRAPPER
#define RESET_BOOT
#define DRIVER_SETUP
+#define NDEBUG 0
+
/*
* BUG can be used to trigger a strange code-size related hang on 2.1 kernels
*/
@@ -94,14 +91,14 @@
#undef DRIVER_SETUP
#endif
-#define ENABLE_IRQ() sun3_enable_irq( IRQ_SUN3_SCSI );
-#define DISABLE_IRQ() sun3_enable_irq( IRQ_SUN3_SCSI );
+#undef SUPPORT_TAGS
+
+#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI );
-/* extern void via_scsi_clear(void); */
static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
-static char sun3scsi_read(struct Scsi_Host *instance, int reg);
-static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value);
+static inline unsigned char sun3scsi_read(int reg);
+static inline void sun3scsi_write(int reg, int value);
static int setup_can_queue = -1;
static int setup_cmd_per_lun = -1;
@@ -111,38 +108,65 @@ static int setup_use_tagged_queuing = -1;
#endif
static int setup_hostid = -1;
-static int polled_scsi_on = 0;
+static Scsi_Cmnd *sun3_dma_setup_done = NULL;
#define AFTER_RESET_DELAY (HZ/2)
-static volatile unsigned char *sun3_scsi_regp = IOBASE_SUN3_SCSI;
-/*
-static volatile unsigned char *sun3_scsi_drq = NULL;
-static volatile unsigned char *sun3_scsi_nodrq = NULL;
-*/
+/* ms to wait after hitting dma regs */
+#define SUN3_DMA_DELAY 5
+
+/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
+#define SUN3_DVMA_BUFSIZE 0xe000
+
+/* minimum number of bytes to to dma on */
+#define SUN3_DMA_MINSIZE 128
+
+static struct proc_dir_entry proc_scsi_sun3_5380 = {
+ PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2
+};
+
+static volatile unsigned char *sun3_scsi_regp;
+static volatile struct sun3_dma_regs *dregs;
+static unsigned char *dmabuf = NULL; /* dma memory buffer */
+static struct sun3_udc_regs *udc_regs = NULL;
+static void *sun3_dma_orig_addr = NULL;
+static unsigned long sun3_dma_orig_count = 0;
+static int sun3_dma_active = 0;
/*
- * Function : sun3_scsi_setup(char *str, int *ints)
- *
- * Purpose : booter command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- * equal to the number of ints.
- *
- * TODO: make it actually work!
- *
+ * NCR 5380 register access functions
*/
-void sun3_scsi_setup(char *str, int *ints) {
- printk("sun3_scsi_setup() called\n");
- setup_can_queue = -1;
- setup_cmd_per_lun = -1;
- setup_sg_tablesize = -1;
- setup_hostid = -1;
-#ifdef SUPPORT_TAGS
- setup_use_tagged_queuing = -1;
-#endif
- printk("sun3_scsi_setup() done\n");
+static inline unsigned char sun3scsi_read(int reg)
+{
+ return( sun3_scsi_regp[reg] );
+}
+
+static inline void sun3scsi_write(int reg, int value)
+{
+ sun3_scsi_regp[reg] = value;
+}
+
+/* dma controller register access functions */
+
+static inline unsigned short sun3_udc_read(unsigned char reg)
+{
+ unsigned short ret;
+
+ dregs->udc_addr = UDC_CSR;
+ udelay(SUN3_DMA_DELAY);
+ ret = dregs->udc_data;
+ udelay(SUN3_DMA_DELAY);
+
+ return ret;
+}
+
+static inline void sun3_udc_write(unsigned short val, unsigned char reg)
+{
+ dregs->udc_addr = reg;
+ udelay(SUN3_DMA_DELAY);
+ dregs->udc_data = val;
+ udelay(SUN3_DMA_DELAY);
}
/*
@@ -165,7 +189,6 @@ static struct Scsi_Host *default_instance;
int sun3scsi_detect(Scsi_Host_Template * tpnt)
{
unsigned long ioaddr, iopte;
- unsigned short *ioptr;
int count = 0;
static int called = 0;
struct Scsi_Host *instance;
@@ -173,9 +196,7 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt)
if(called)
return 0;
-printk("sun3scsi_detect(0x%p)\n",tpnt);
-
- tpnt->proc_name = "Sun3 5380 SCSI"; /* Could you spell "ewww..."? */
+ tpnt->proc_dir = &proc_scsi_sun3_5380;
/* setup variables */
tpnt->can_queue =
@@ -204,7 +225,6 @@ printk("sun3scsi_detect(0x%p)\n",tpnt);
if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
IOBASE_SUN3_SCSI) {
count = 1;
-printk("Found ioaddr in pmeg\n");
break;
}
}
@@ -214,22 +234,19 @@ printk("Found ioaddr in pmeg\n");
return 0;
}
- sun3_scsi_regp = ioaddr;
-
- /* doing some stuff like resetting DVMA: */
- ioptr = ioaddr;
- *(ioptr+8) = 0;
- udelay(10);
- *(ioptr+9) = 0;
- udelay(10);
- *(ioptr+12) = 0;
- udelay(10);
- *(ioptr+12) = 0x7;
- udelay(10);
- printk("SCSI status reg = %x\n", *(ioptr+12));
- udelay(10);
- *(ioptr+13) = 0;
- udelay(10);
+ sun3_scsi_regp = (unsigned char *)ioaddr;
+ dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
+
+ if((dmabuf = sun3_dvma_malloc(SUN3_DVMA_BUFSIZE)) == NULL) {
+ printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+ return 0;
+ }
+
+ if((udc_regs = sun3_dvma_malloc(sizeof(struct sun3_udc_regs)))
+ == NULL) {
+ printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+ return 0;
+ }
#ifdef SUPPORT_TAGS
if (setup_use_tagged_queuing < 0)
@@ -239,18 +256,6 @@ printk("Found ioaddr in pmeg\n");
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
default_instance = instance;
-/*
- if (macintosh_config->ident == MAC_MODEL_IIFX) {
- mac_scsi_regp = via1_regp+0x8000;
- mac_scsi_drq = via1_regp+0x6000;
- mac_scsi_nodrq = via1_regp+0x12000;
- } else {
- mac_scsi_regp = via1_regp+0x10000;
- mac_scsi_drq = via1_regp+0x6000;
- mac_scsi_nodrq = via1_regp+0x12000;
- }
-*/
-
instance->io_port = (unsigned long) ioaddr;
instance->irq = IRQ_SUN3_SCSI;
@@ -260,15 +265,20 @@ printk("Found ioaddr in pmeg\n");
((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
- if (instance->irq != IRQ_NONE)
- if (sun3_request_irq(instance->irq, sun3scsi_intr,
- 0, "Sun3SCSI-5380", NULL)) {
- printk("scsi%d: IRQ%d not free, interrupts disabled\n",
- instance->host_no, instance->irq);
- instance->irq = IRQ_NONE;
- }
-
- printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
+ if (request_irq(instance->irq, scsi_sun3_intr,
+ 0, "Sun3SCSI-5380", NULL)) {
+#ifndef REAL_DMA
+ printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+ instance->host_no, instance->irq);
+ instance->irq = IRQ_NONE;
+#else
+ printk("scsi%d: IRQ%d not free, bailing out\n",
+ instance->host_no, instance->irq);
+ return 0;
+#endif
+ }
+
+ printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port);
if (instance->irq == IRQ_NONE)
printk ("s disabled");
else
@@ -280,6 +290,12 @@ printk("Found ioaddr in pmeg\n");
NCR5380_print_options(instance);
printk("\n");
+ dregs->csr = 0;
+ udelay(SUN3_DMA_DELAY);
+ dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+ udelay(SUN3_DMA_DELAY);
+ dregs->fifo_count = 0;
+
called = 1;
return 1;
}
@@ -342,34 +358,34 @@ const char * sun3scsi_info (struct Scsi_Host *spnt) {
return "";
}
+// safe bits for the CSR
+#define CSR_GOOD 0x060f
-/*
- * NCR 5380 register access functions
- */
-
-static char sun3scsi_read(struct Scsi_Host *instance, int reg)
+static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
{
-/*
-printk("sun3scsi_read(instance=0x%p, reg=0x%x): @0x%p= %d\n",instance,reg,sun3_scsi_regp,sun3_scsi_regp[reg]);
-*/
- return( sun3_scsi_regp[reg] );
-}
+ unsigned short csr = dregs->csr;
-static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-/*
- printk("sun3scsi_write(instance=0x%p, reg=0x%x, value=0x%x)\n", instance, reg, value);
-*/
- sun3_scsi_regp[reg] = value;
-}
+ if(csr & ~CSR_GOOD) {
+ if(csr & CSR_DMA_BUSERR) {
+ printk("scsi%d: bus error in dma\n", default_instance->host_no);
+ }
-#include "NCR5380.c"
+ if(csr & CSR_DMA_CONFLICT) {
+ printk("scsi%d: dma conflict\n", default_instance->host_no);
+ }
+ }
+
+ if(csr & (CSR_SDB_INT | CSR_DMA_INT))
+ NCR5380_intr(irq, dummy, fp);
+}
/*
* Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
* reentering NCR5380_print_status seems to have ugly side effects
*/
+/* this doesn't seem to get used at all -- sam */
+#if 0
void sun3_sun3_debug (void)
{
unsigned long flags;
@@ -381,32 +397,141 @@ void sun3_sun3_debug (void)
NCR5380_print_status(default_instance);
restore_flags(flags);
}
-#if 0
- polled_scsi_on = 1;
-#endif
}
-/*
- * Helper function for interrupt trouble. More ugly side effects here.
- */
+#endif
+
-void scsi_sun3_polled (void)
+/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
+static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
{
- unsigned long flags;
- NCR5380_local_declare();
- struct Scsi_Host *instance;
+ if(write_flag)
+ memcpy(dmabuf, data, count);
+ else {
+ sun3_dma_orig_addr = data;
+ sun3_dma_orig_count = count;
+ }
+
+ dregs->fifo_count = 0;
+ sun3_udc_write(UDC_RESET, UDC_CSR);
- instance = default_instance;
- NCR5380_setup(instance);
- if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
- {
- printk("SCSI poll\n");
- save_flags(flags);
- cli();
- sun3scsi_intr(IRQ_SUN3_SCSI, instance, NULL);
- restore_flags(flags);
+ /* reset fifo */
+ dregs->csr &= ~CSR_FIFO;
+ dregs->csr |= CSR_FIFO;
+
+ /* set direction */
+ if(write_flag)
+ dregs->csr |= CSR_SEND;
+ else
+ dregs->csr &= ~CSR_SEND;
+
+ /* byte count for fifo */
+ dregs->fifo_count = count;
+
+ sun3_udc_write(UDC_RESET, UDC_CSR);
+
+ /* reset fifo */
+ dregs->csr &= ~CSR_FIFO;
+ dregs->csr |= CSR_FIFO;
+
+
+ if(dregs->fifo_count != count) {
+ printk("scsi%d: fifo_mismatch %04x not %04x\n",
+ default_instance->host_no, dregs->fifo_count,
+ (unsigned int) count);
+ NCR5380_print(default_instance);
+ }
+
+ /* setup udc */
+ udc_regs->addr_hi = ((sun3_dvma_vtop(dmabuf) & 0xff0000) >> 8);
+ udc_regs->addr_lo = (sun3_dvma_vtop(dmabuf) & 0xffff);
+ udc_regs->count = count/2; /* count in words */
+ udc_regs->mode_hi = UDC_MODE_HIWORD;
+ if(write_flag) {
+ if(count & 1)
+ udc_regs->count++;
+ udc_regs->mode_lo = UDC_MODE_LSEND;
+ udc_regs->rsel = UDC_RSEL_SEND;
+ } else {
+ udc_regs->mode_lo = UDC_MODE_LRECV;
+ udc_regs->rsel = UDC_RSEL_RECV;
}
+
+ /* announce location of regs block */
+ sun3_udc_write(((sun3_dvma_vtop(udc_regs) & 0xff0000) >> 8),
+ UDC_CHN_HI);
+
+ sun3_udc_write((sun3_dvma_vtop(udc_regs) & 0xffff), UDC_CHN_LO);
+
+ /* set dma master on */
+ sun3_udc_write(0xd, UDC_MODE);
+
+ /* interrupt enable */
+ sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
+
+ return count;
+
+}
+
+static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
+{
+ unsigned short resid;
+
+ dregs->udc_addr = 0x32;
+ udelay(SUN3_DMA_DELAY);
+ resid = dregs->udc_data;
+ udelay(SUN3_DMA_DELAY);
+ resid *= 2;
+
+ return (unsigned long) resid;
+}
+
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+ int write_flag)
+{
+ return wanted;
}
+/* clean up after our dma is done */
+static int sun3scsi_dma_finish(void)
+{
+ unsigned short count;
+ int ret = 0;
+
+ count = sun3scsi_dma_residual(default_instance);
+
+ sun3_dma_active = 0;
+
+ /* if we've finished a read, copy out the data we read */
+ if(sun3_dma_orig_addr) {
+ /* check for residual bytes after dma end */
+ if(count && (NCR5380_read(BUS_AND_STATUS_REG) &
+ (BASR_PHASE_MATCH | BASR_ACK))) {
+ printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no);
+ printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG));
+ ret = count;
+ }
+
+ /* copy in what we dma'd no matter what */
+ memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count);
+ sun3_dma_orig_addr = NULL;
+
+ }
+
+ sun3_udc_write(UDC_RESET, UDC_CSR);
+
+ dregs->csr &= ~CSR_SEND;
+
+ /* reset fifo */
+ dregs->csr &= ~CSR_FIFO;
+ dregs->csr |= CSR_FIFO;
+
+ sun3_dma_setup_done = NULL;
+
+ return ret;
+
+}
+
+#include "sun3_NCR5380.c"
#ifdef MODULE
@@ -414,3 +539,4 @@ Scsi_Host_Template driver_template = SUN3_NCR5380;
#include "scsi_module.c"
#endif
+
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index c677bfbf6..b94f586aa 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -1,6 +1,8 @@
/*
* Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
*
+ * Sun3 DMA additions by Sam Creasey (sammy@oh.verio.com)
+ *
* Adapted from mac_scsinew.h:
*/
/*
@@ -102,18 +104,272 @@ use_clustering: DISABLE_CLUSTERING \
#define NCR5380_setup(instance) \
_instance = instance
-#define NCR5380_read(reg) sun3scsi_read(_instance, reg)
-#define NCR5380_write(reg, value) sun3scsi_write(_instance, reg, value)
+#define NCR5380_read(reg) sun3scsi_read(reg)
+#define NCR5380_write(reg, value) sun3scsi_write(reg, value)
#define NCR5380_intr sun3scsi_intr
#define NCR5380_queue_command sun3scsi_queue_command
-#define NCR5380_abort sun3scsi_abort
#define NCR5380_reset sun3scsi_reset
+#define NCR5380_abort sun3scsi_abort
#define NCR5380_proc_info sun3scsi_proc_info
+#define NCR5380_dma_xfer_len(i, cmd, phase) \
+ sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+
+#define NCR5380_dma_write_setup(instance, data, count) sun3scsi_dma_setup(data, count, 1)
+#define NCR5380_dma_read_setup(instance, data, count) sun3scsi_dma_setup(data, count, 0)
+#define NCR5380_dma_residual sun3scsi_dma_residual
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
+/* additional registers - mainly DMA control regs */
+/* these start at regbase + 8 -- directly after the NCR regs */
+struct sun3_dma_regs {
+ unsigned short vmeregs[4]; /* unimpl vme stuff */
+ unsigned short udc_data; /* udc dma data reg */
+ unsigned short udc_addr; /* uda dma addr reg */
+ unsigned short fifo_data; /* fifo data reg, holds extra byte on
+ odd dma reads */
+ unsigned short fifo_count;
+ unsigned short csr; /* control/status reg */
+};
+
+/* ucd chip specific regs - live in dvma space */
+struct sun3_udc_regs {
+ unsigned short rsel; /* select regs to load */
+ unsigned short addr_hi; /* high word of addr */
+ unsigned short addr_lo; /* low word */
+ unsigned short count; /* words to be xfer'd */
+ unsigned short mode_hi; /* high word of channel mode */
+ unsigned short mode_lo; /* low word of channel mode */
+};
+
+/* addresses of the udc registers */
+#define UDC_MODE 0x38
+#define UDC_CSR 0x2e /* command/status */
+#define UDC_CHN_HI 0x26 /* chain high word */
+#define UDC_CHN_LO 0x22 /* chain lo word */
+#define UDC_CURA_HI 0x1a /* cur reg A high */
+#define UDC_CURA_LO 0x0a /* cur reg A low */
+#define UDC_CURB_HI 0x12 /* cur reg B high */
+#define UDC_CURB_LO 0x02 /* cur reg B low */
+#define UDC_MODE_HI 0x56 /* mode reg high */
+#define UDC_MODE_LO 0x52 /* mode reg low */
+#define UDC_COUNT 0x32 /* words to xfer */
+
+/* some udc commands */
+#define UDC_RESET 0
+#define UDC_CHN_START 0xa0 /* start chain */
+#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
+
+/* udc mode words */
+#define UDC_MODE_HIWORD 0x40
+#define UDC_MODE_LSEND 0xc2
+#define UDC_MODE_LRECV 0xd2
+
+/* udc reg selections */
+#define UDC_RSEL_SEND 0x282
+#define UDC_RSEL_RECV 0x182
+
+/* bits in csr reg */
+#define CSR_DMA_ACTIVE 0x8000
+#define CSR_DMA_CONFLICT 0x4000
+#define CSR_DMA_BUSERR 0x2000
+
+#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
+#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
+#define CSR_DMA_INT 0x100 /* dma interrupt pending */
+
+#define CSR_SEND 0x8 /* 1 = send 0 = recv */
+#define CSR_FIFO 0x2 /* reset fifo */
+#define CSR_INTR 0x4 /* interrupt enable */
+#define CSR_SCSI 0x1
+
+// debugging printk's, taken from atari_scsi.h
+/* Debugging printk definitions:
+ *
+ * ARB -> arbitration
+ * ASEN -> auto-sense
+ * DMA -> DMA
+ * HSH -> PIO handshake
+ * INF -> information transfer
+ * INI -> initialization
+ * INT -> interrupt
+ * LNK -> linked commands
+ * MAIN -> NCR5380_main() control flow
+ * NDAT -> no data-out phase
+ * NWR -> no write commands
+ * PIO -> PIO transfers
+ * PDMA -> pseudo DMA (unused on Atari)
+ * QU -> queues
+ * RSL -> reselections
+ * SEL -> selections
+ * USL -> usleep cpde (unused on Atari)
+ * LBS -> last byte sent (unused on Atari)
+ * RSS -> restarting of selections
+ * EXT -> extended messages
+ * ABRT -> aborting and resetting
+ * TAG -> queue tag handling
+ * MER -> merging of consec. buffers
+ *
+ */
+
+
+
+#if NDEBUG & NDEBUG_ARBITRATION
+#define ARB_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define ARB_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_AUTOSENSE
+#define ASEN_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define ASEN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_DMA
+#define DMA_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define DMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_HANDSHAKE
+#define HSH_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define HSH_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INFORMATION
+#define INF_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define INF_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INIT
+#define INI_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define INI_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INTR
+#define INT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define INT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LINKED
+#define LNK_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define LNK_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MAIN
+#define MAIN_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define MAIN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_DATAOUT
+#define NDAT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define NDAT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_WRITE
+#define NWR_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define NWR_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PIO
+#define PIO_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define PIO_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PSEUDO_DMA
+#define PDMA_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define PDMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_QUEUES
+#define QU_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define QU_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESELECTION
+#define RSL_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define RSL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_SELECTION
+#define SEL_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define SEL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_USLEEP
+#define USL_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define USL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+#define LBS_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define LBS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESTART_SELECT
+#define RSS_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define RSS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_EXTENDED
+#define EXT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define EXT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_ABORT
+#define ABRT_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define ABRT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_TAGS
+#define TAG_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define TAG_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MERGING
+#define MER_PRINTK(format, args...) \
+ printk(KERN_DEBUG format , ## args)
+#else
+#define MER_PRINTK(format, args...)
+#endif
+
+/* conditional macros for NCR5380_print_{,phase,status} */
+
+#define NCR_PRINT(mask) \
+ ((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0)
+
+#define NCR_PRINT_PHASE(mask) \
+ ((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0)
+
+#define NCR_PRINT_STATUS(mask) \
+ ((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
+
+#define NDEBUG_ANY 0xffffffff
+
+
+
#endif /* ndef HOSTS_C */
#endif /* SUN3_NCR5380_H */
diff --git a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c
index c4f707598..9b4069c37 100644
--- a/drivers/sgi/char/shmiq.c
+++ b/drivers/sgi/char/shmiq.c
@@ -1,4 +1,4 @@
-/* $Id: shmiq.c,v 1.18 2000/02/18 00:24:43 ralf Exp $
+/* $Id: shmiq.c,v 1.19 2000/02/23 00:41:21 ralf Exp $
*
* shmiq.c: shared memory input queue driver
* written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -53,6 +53,7 @@
#include <linux/wait.h>
#include <linux/major.h>
#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/shmiq.h>
#include <asm/mman.h>
@@ -443,5 +444,12 @@ void
shmiq_init (void)
{
printk ("SHMIQ setup\n");
- register_chrdev (SHMIQ_MAJOR, "shmiq", &shmiq_fops);
+ devfs_register_chrdev(SHMIQ_MAJOR, "shmiq", &shmiq_fops);
+ devfs_register (NULL, "shmiq", 0, DEVFS_FL_DEFAULT,
+ SHMIQ_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &shmiq_fops, NULL);
+ devfs_register_series (NULL, "qcntl%u", 2, DEVFS_FL_DEFAULT,
+ SHMIQ_MAJOR, 1,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &shmiq_fops, NULL);
}
diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c
index a1177c6df..56ee3df89 100644
--- a/drivers/sound/ac97_codec.c
+++ b/drivers/sound/ac97_codec.c
@@ -19,9 +19,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * History
- * Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
- * Isloated from trident.c to support multiple ac97 codec
+ * History
+ * v0.2 Feb 10 2000 Ollie Lho
+ * add ac97_read_proc for /proc/driver/vnedor/ac97
+ * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
+ * Isolated from trident.c to support multiple ac97 codec
*/
#include <linux/module.h>
#include <linux/version.h>
@@ -36,11 +38,13 @@ static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, uns
static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
+#define arraysize(x) (sizeof(x)/sizeof((x)[0]))
+
static struct {
unsigned int id;
char *name;
int (*init) (struct ac97_codec *codec);
-} snd_ac97_codec_ids[] = {
+} ac97_codec_ids[] = {
{0x414B4D00, "Asahi Kasei AK4540" , NULL},
{0x41445340, "Analog Devices AD1881" , NULL},
{0x43525900, "Cirrus Logic CS4297" , NULL},
@@ -52,9 +56,46 @@ static struct {
{0x83847605, "SigmaTel STAC9704" , NULL},
{0x83847608, "SigmaTel STAC9708" , NULL},
{0x83847609, "SigmaTel STAC9721/23" , NULL},
+ {0x54524108, "TriTech TR28028" , NULL},
+ {0x574D4C00, "Wolfson WM9704" , NULL},
{0x00000000, NULL, NULL}
};
+static const char *ac97_stereo_enhancements[] =
+{
+ /* 0 */ "No 3D Stereo Enhancement",
+ /* 1 */ "Analog Devices Phat Stereo",
+ /* 2 */ "Creative Stereo Enhancement",
+ /* 3 */ "National Semi 3D Stereo Enhancement",
+ /* 4 */ "YAMAHA Ymersion",
+ /* 5 */ "BBE 3D Stereo Enhancement",
+ /* 6 */ "Crystal Semi 3D Stereo Enhancement",
+ /* 7 */ "Qsound QXpander",
+ /* 8 */ "Spatializer 3D Stereo Enhancement",
+ /* 9 */ "SRS 3D Stereo Enhancement",
+ /* 10 */ "Platform Tech 3D Stereo Enhancement",
+ /* 11 */ "AKM 3D Audio",
+ /* 12 */ "Aureal Stereo Enhancement",
+ /* 13 */ "Aztech 3D Enhancement",
+ /* 14 */ "Binaura 3D Audio Enhancement",
+ /* 15 */ "ESS Technology Stereo Enhancement",
+ /* 16 */ "Harman International VMAx",
+ /* 17 */ "Nvidea 3D Stereo Enhancement",
+ /* 18 */ "Philips Incredible Sound",
+ /* 19 */ "Texas Instruments 3D Stereo Enhancement",
+ /* 20 */ "VLSI Technology 3D Stereo Enhancement",
+ /* 21 */ "TriTech 3D Stereo Enhancement",
+ /* 22 */ "Realtek 3D Stereo Enhancement",
+ /* 23 */ "Samsung 3D Stereo Enhancement",
+ /* 24 */ "Wolfson Microelectronics 3D Enhancement",
+ /* 25 */ "Delta Integration 3D Enhancement",
+ /* 26 */ "SigmaTel 3D Enhancement",
+ /* 27 */ "Reserved 27",
+ /* 28 */ "Rockwell 3D Stereo Enhancement",
+ /* 29 */ "Reserved 29",
+ /* 30 */ "Reserved 30",
+ /* 31 */ "Reserved 31"
+};
/* this table has default mixer values for all OSS mixers. */
static struct mixer_defaults {
@@ -86,9 +127,9 @@ static struct ac97_mixer_hw {
} ac97_hw[SOUND_MIXER_NRDEVICES]= {
[SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63},
[SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15},
- [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
[SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31},
- [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
+ [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
[SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31},
[SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31},
[SOUND_MIXER_CD] = {AC97_CD_VOL, 31},
@@ -155,10 +196,13 @@ static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel)
right = 100 - ((right * 100) / mh->scale);
left = 100 - ((left * 100) / mh->scale);
}
-
ret = left | (right << 8);
} else if (oss_channel == SOUND_MIXER_SPEAKER) {
ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
+ } else if (oss_channel == SOUND_MIXER_PHONEIN) {
+ ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+ } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
+ ret = 100 - (((val & 0x1f) * 100) / mh->scale);
} else if (oss_channel == SOUND_MIXER_MIC) {
ret = 100 - (((val & 0x1f) * 100) / mh->scale);
/* the low bit is optional in the tone sliders and masking
@@ -200,10 +244,14 @@ static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
} else {
right = ((100 - right) * mh->scale) / 100;
left = ((100 - left) * mh->scale) / 100;
- }
+ }
val = (left << 8) | right;
} else if (oss_channel == SOUND_MIXER_SPEAKER) {
val = (((100 - left) * mh->scale) / 100) << 1;
+ } else if (oss_channel == SOUND_MIXER_PHONEIN) {
+ val = (((100 - left) * mh->scale) / 100);
+ } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
+ val = (((100 - left) * mh->scale) / 100);
} else if (oss_channel == SOUND_MIXER_MIC) {
val = codec->codec_read(codec , mh->offset) & ~0x801f;
val |= (((100 - left) * mh->scale) / 100);
@@ -212,11 +260,10 @@ static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
} else if (oss_channel == SOUND_MIXER_BASS) {
val = codec->codec_read(codec , mh->offset) & ~0x0f00;
val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (oss_channel == SOUND_MIXER_TREBLE) {
+ } else if (oss_channel == SOUND_MIXER_TREBLE) {
val = codec->codec_read(codec , mh->offset) & ~0x000f;
val |= (((100 - left) * mh->scale) / 100) & 0x000e;
}
-
#ifdef DEBUG
printk(" 0x%04x", val);
#endif
@@ -335,11 +382,11 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned
return -EINVAL;
/* do we ever want to touch the hardware? */
- /* val = codec->read_mixer(card,i); */
- val = codec->mixer_state[i];
+ val = codec->read_mixer(codec, i);
+ /* val = codec->mixer_state[i]; */
break;
}
- return put_user(val,(int *)arg);
+ return put_user(val, (int *)arg);
}
if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
@@ -368,6 +415,76 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned
return -EINVAL;
}
+/* entry point for /proc/driver/controller_vendor/ac97/%d */
+int ac97_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0, cap, extid, val, id1, id2;
+ struct ac97_codec *codec;
+
+ if ((codec = data) == NULL)
+ return -ENODEV;
+
+ id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
+ id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+ len += sprintf (page+len, "Vendor name : %s\n", codec->name);
+ len += sprintf (page+len, "Vendor id : %04X %04X\n", id1, id2);
+
+ extid = codec->codec_read(codec, AC97_EXTENDED_ID);
+ extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
+ len += sprintf (page+len, "AC97 Version : %s\n",
+ extid ? "2.0 or later" : "1.0");
+
+ cap = codec->codec_read(codec, AC97_RESET);
+ len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n",
+ cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
+ cap & 0x0002 ? " -reserved1-" : "",
+ cap & 0x0004 ? " -bass & treble-" : "",
+ cap & 0x0008 ? " -simulated stereo-" : "",
+ cap & 0x0010 ? " -headphone out-" : "",
+ cap & 0x0020 ? " -loudness-" : "");
+ val = cap & 0x00c0;
+ len += sprintf (page+len, "DAC resolutions :%s%s%s\n",
+ " -16-bit-",
+ val & 0x0040 ? " -18-bit-" : "",
+ val & 0x0080 ? " -20-bit-" : "");
+ val = cap & 0x0300;
+ len += sprintf (page+len, "ADC resolutions :%s%s%s\n",
+ " -16-bit-",
+ val & 0x0100 ? " -18-bit-" : "",
+ val & 0x0200 ? " -20-bit-" : "");
+ len += sprintf (page+len, "3D enhancement : %s\n",
+ ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
+
+ val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
+ len += sprintf (page+len, "POP path : %s 3D\n"
+ "Sim. stereo : %s\n"
+ "3D enhancement : %s\n"
+ "Loudness : %s\n"
+ "Mono output : %s\n"
+ "MIC select : %s\n"
+ "ADC/DAC loopback : %s\n",
+ val & 0x8000 ? "post" : "pre",
+ val & 0x4000 ? "on" : "off",
+ val & 0x2000 ? "on" : "off",
+ val & 0x1000 ? "on" : "off",
+ val & 0x0200 ? "MIC" : "MIX",
+ val & 0x0100 ? "MIC2" : "MIC1",
+ val & 0x0080 ? "on" : "off");
+
+ cap = extid;
+ len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
+ cap & 0x0001 ? " -var rate PCM audio-" : "",
+ cap & 0x0002 ? " -2x PCM audio out-" : "",
+ cap & 0x0008 ? " -var rate MIC in-" : "",
+ cap & 0x0040 ? " -PCM center DAC-" : "",
+ cap & 0x0080 ? " -PCM surround DAC-" : "",
+ cap & 0x0100 ? " -PCM LFE DAC-" : "",
+ cap & 0x0200 ? " -slot/DAC mappings-" : "");
+
+ return len;
+}
+
int ac97_probe_codec(struct ac97_codec *codec)
{
u16 id1, id2, cap;
@@ -379,12 +496,14 @@ int ac97_probe_codec(struct ac97_codec *codec)
if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000)
return 0;
+ codec->name = NULL;
+ codec->codec_init = NULL;
id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
- for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
- if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
- codec->name = snd_ac97_codec_ids[i].name;
- codec->codec_init = snd_ac97_codec_ids[i].init;
+ for (i = 0; i < arraysize(ac97_codec_ids); i++) {
+ if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+ codec->name = ac97_codec_ids[i].name;
+ codec->codec_init = ac97_codec_ids[i].init;
break;
}
}
@@ -392,7 +511,6 @@ int ac97_probe_codec(struct ac97_codec *codec)
codec->name = "Unknown";
printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
id1, id2, codec->name);
- printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap);
/* mixer masks */
codec->supported_mixers = AC97_SUPPORTED_MASK;
@@ -437,4 +555,5 @@ static int sigmatel_init(struct ac97_codec * codec)
return 1;
}
+EXPORT_SYMBOL(ac97_read_proc);
EXPORT_SYMBOL(ac97_probe_codec);
diff --git a/drivers/sound/ac97_codec.h b/drivers/sound/ac97_codec.h
index 27d41f5bb..a614edbdb 100644
--- a/drivers/sound/ac97_codec.h
+++ b/drivers/sound/ac97_codec.h
@@ -107,16 +107,17 @@
/* OSS interface to the ac97s.. */
#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\
SOUND_MASK_LINE|SOUND_MASK_CD|\
- SOUND_MIXER_ALTPCM|SOUND_MASK_IGAIN|\
+ SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\
SOUND_MASK_LINE1|SOUND_MASK_VIDEO)
#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
SOUND_MASK_BASS|SOUND_MASK_TREBLE|\
SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\
- SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT)
+ SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT)
#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
- SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
+ SOUND_MASK_CD|SOUND_MASK_VIDEO|\
+ SOUND_MASK_LINE1| SOUND_MASK_LINE|\
SOUND_MASK_PHONEIN)
#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) )
@@ -153,6 +154,8 @@ struct ac97_codec {
unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
};
+extern int ac97_read_proc (char *page_out, char **start, off_t off,
+ int count, int *eof, void *data);
extern int ac97_probe_codec(struct ac97_codec *);
#endif /* _AC97_CODEC_H_ */
diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c
index ae627ed3b..b6298ca83 100644
--- a/drivers/sound/dmasound.c
+++ b/drivers/sound/dmasound.c
@@ -116,6 +116,7 @@ History:
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/dbdma.h>
+#include <asm/feature.h>
#include "awacs_defs.h"
#include <linux/nvram.h>
#include <linux/vt_kern.h>
@@ -178,6 +179,7 @@ static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
static int awacs_rate_index;
static int awacs_subframe;
static int awacs_spkr_vol;
+static struct device_node* awacs_node;
static int awacs_revision;
#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
@@ -251,6 +253,7 @@ static short *beep_buf;
static volatile struct dbdma_cmd *beep_dbdma_cmd;
static void (*orig_mksound)(unsigned int, unsigned int);
static int is_pbook_3400;
+static unsigned char *latch_base;
static int is_pbook_G3;
static unsigned char *macio_base;
@@ -898,7 +901,7 @@ static inline int ioctl_return(int *addr, int value)
void dmasound_init(void);
-void dmasound_setup(char *str, int *ints);
+static int dmasound_setup(char *str);
/*** Translations ************************************************************/
@@ -3208,9 +3211,15 @@ static void PMacIrqCleanup(void)
out_le32(&awacs_txdma->control, RUN<<16);
/* disable interrupts from awacs interface */
out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
- free_irq(awacs_irq, pmac_awacs_intr);
- free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
- free_irq(awacs_rx_irq, pmac_awacs_rx_intr);
+#ifdef CONFIG_PMAC_PBOOK
+ if (is_pbook_G3) {
+ feature_clear(awacs_node, FEATURE_Sound_power);
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ }
+#endif
+ free_irq(awacs_irq, 0);
+ free_irq(awacs_tx_irq, 0);
+ free_irq(awacs_rx_irq, 0);
kfree(awacs_tx_cmd_space);
if (awacs_rx_cmd_space)
kfree(awacs_rx_cmd_space);
@@ -3281,12 +3290,10 @@ static void PMacInit(void)
/* We really want to execute a DMA stop command, after the AWACS
* is initialized.
* For reasons I don't understand, it stops the hissing noise
- * common to many PowerBook G3 systems (like mine :-). Maybe it
- * is just the AWACS control register change......
+ * common to many PowerBook G3 systems (like mine :-).
*/
out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
- out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00));
out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
out_le32(&awacs_txdma->control, RUN | (RUN << 16));
@@ -3544,6 +3551,11 @@ static void awacs_nosound(unsigned long xx)
save_flags(flags); cli();
if (beep_playing) {
st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (awacs_rate_index << 8));
+ out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
beep_playing = 0;
}
restore_flags(flags);
@@ -3645,8 +3657,23 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
PMacSilence();
disable_irq(awacs_irq);
disable_irq(awacs_tx_irq);
+ if (is_pbook_G3) {
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_clear(awacs_node, FEATURE_Sound_power);
+ }
break;
case PBOOK_WAKE:
+ /* There is still a problem on wake. Sound seems to work fine
+ if I launch mpg123 and resumes fine if mpg123 was playing,
+ but the console beep is dead until I do something with the
+ mixer. Probably yet another timing issue */
+ if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+ || !feature_test(awacs_node, FEATURE_Sound_power)) {
+ /* these aren't present on the 3400 AFAIK -- paulus */
+ feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_set(awacs_node, FEATURE_Sound_power);
+ mdelay(1000);
+ }
out_le32(&awacs->control, MASK_IEPC
| (awacs_rate_index << 8) | 0x11
| (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
@@ -3663,6 +3690,16 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
mdelay(2);
awacs_write(awacs_reg[1] | MASK_ADDR1);
}
+ /* enable CD sound input */
+ if (macio_base && is_pbook_G3) {
+ out_8(macio_base + 0x37, 3);
+ } else if (is_pbook_3400) {
+ feature_set(awacs_node, FEATURE_IOBUS_enable);
+ udelay(10);
+ in_8(latch_base + 0x190);
+ }
+ /* Resume pending sounds. */
+ PMacPlay();
}
return PBOOK_SLEEP_OK;
}
@@ -5139,6 +5176,7 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long fmt;
int data;
int size, nbufs;
+ audio_buf_info info;
switch (cmd) {
case SNDCTL_DSP_RESET:
@@ -5214,6 +5252,14 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
sq_setup(numBufs, size, sound_buffers);
sq.max_active = nbufs;
return 0;
+ case SNDCTL_DSP_GETOSPACE:
+ info.fragments = sq.max_active - sq.count;
+ info.fragstotal = sq.max_active;
+ info.fragsize = sq.block_size;
+ info.bytes = info.fragments * info.fragsize;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
default:
return mixer_ioctl(inode, file, cmd, arg);
@@ -5308,7 +5354,7 @@ static int state_open(struct inode *inode, struct file *file)
{
char *buffer = state.buf, *mach = "";
#ifdef CONFIG_PPC
- char awacs_buf[50];
+ char awacs_buf[64];
#endif
int len = 0;
@@ -5576,6 +5622,16 @@ void __init dmasound_init(void)
printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
return;
}
+ awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+ if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ feature_set(np, FEATURE_Sound_CLK_enable);
+ feature_set(np, FEATURE_Sound_power);
+ /* Shorter delay will not work */
+ mdelay(1000);
+ }
+#endif
awacs_tx_cmds = (volatile struct dbdma_cmd *)
DBDMA_ALIGN(awacs_tx_cmd_space);
@@ -5607,7 +5663,10 @@ void __init dmasound_init(void)
awacs_revision =
(in_le32(&awacs->codec_stat) >> 12) & 0xf;
if (awacs_revision == 3) {
+ mdelay(100);
awacs_write(0x6000);
+ mdelay(2);
+ awacs_write(awacs_reg[1] + MASK_ADDR1);
awacs_enable_amp(100 * 0x101);
}
}
@@ -5629,26 +5688,36 @@ void __init dmasound_init(void)
/* Powerbooks have odd ways of enabling inputs such as
an expansion-bay CD or sound from an internal modem
or a PC-card modem. */
- if (machine_is_compatible("AAPL,3400/2400")) {
+ if (machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500")) {
is_pbook_3400 = 1;
/*
* Enable CD and PC-card sound inputs.
* This is done by reading from address
* f301a000, + 0x10 to enable the expansion-bay
* CD sound input, + 0x80 to enable the PC-card
- * sound input. The 0x100 seems to enable the
- * MESH and/or its SCSI bus drivers.
+ * sound input. The 0x100 enables the SCSI bus
+ * terminator power.
*/
- in_8((unsigned char *)0xf301a190);
- } else if (machine_is_compatible("PowerBook1,1")) {
- np = find_devices("mac-io");
- if (np && np->n_addrs > 0) {
- is_pbook_G3 = 1;
- macio_base = (unsigned char *)
- ioremap(np->addrs[0].address, 0x40);
- /* enable CD sound input */
- out_8(macio_base + 0x37, 3);
+ latch_base = (unsigned char *) ioremap
+ (0xf301a000, 0x1000);
+ in_8(latch_base + 0x190);
+ } else if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ struct device_node* mio;
+ macio_base = 0;
+ is_pbook_G3 = 1;
+ for (mio = np->parent; mio; mio = mio->parent) {
+ if (strcmp(mio->name, "mac-io") == 0
+ && mio->n_addrs > 0) {
+ macio_base = (unsigned char *) ioremap
+ (mio->addrs[0].address, 0x40);
+ break;
+ }
}
+ /* enable CD sound input */
+ if (macio_base)
+ out_8(macio_base + 0x37, 3);
}
}
#endif /* CONFIG_PPC */
diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c
index a6d6603ac..f7e5622d1 100644
--- a/drivers/sound/es1370.c
+++ b/drivers/sound/es1370.c
@@ -2456,7 +2456,7 @@ static struct initvol {
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct es1370_state *s;
mm_segment_t fs;
@@ -2466,6 +2466,10 @@ static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii
return -1;
if (pcidev->irq == 0)
return -1;
+ if (!pci_dma_supported(pcidev, 0xffffffff)) {
+ printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
+ return -1;
+ }
if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) {
printk(KERN_WARNING "es1370: out of memory\n");
return -1;
@@ -2569,7 +2573,7 @@ static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii
return -1;
}
-static void es1370_remove(struct pci_dev *dev)
+static void __devinit es1370_remove(struct pci_dev *dev)
{
struct es1370_state *s = (struct es1370_state *)dev->driver_data;
@@ -2589,7 +2593,7 @@ static void es1370_remove(struct pci_dev *dev)
dev->driver_data = NULL;
}
-static const struct pci_device_id id_table[] = {
+static struct pci_device_id id_table[] __devinitdata = {
{ PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
{ 0, 0, 0, 0, 0, 0 }
};
@@ -2608,8 +2612,10 @@ static int __init init_es1370(void)
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
printk(KERN_INFO "es1370: version v0.33 time " __TIME__ " " __DATE__ "\n");
- if (!pci_register_driver(&es1370_driver))
+ if (!pci_register_driver(&es1370_driver)) {
+ pci_unregister_driver(&es1370_driver);
return -ENODEV;
+ }
return 0;
}
diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c
index 21e2c7c2b..feeb11956 100644
--- a/drivers/sound/es1371.c
+++ b/drivers/sound/es1371.c
@@ -2611,7 +2611,7 @@ static struct initvol {
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct es1371_state *s;
mm_segment_t fs;
@@ -2624,6 +2624,10 @@ static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii
return -1;
if (pcidev->irq == 0)
return -1;
+ if (!pci_dma_supported(pcidev, 0xffffffff)) {
+ printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n");
+ return -1;
+ }
if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) {
printk(KERN_WARNING "es1371: out of memory\n");
return -1;
@@ -2764,7 +2768,7 @@ static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii
return -1;
}
-static void es1371_remove(struct pci_dev *dev)
+static void __devinit es1371_remove(struct pci_dev *dev)
{
struct es1371_state *s = (struct es1371_state *)dev->driver_data;
@@ -2788,7 +2792,7 @@ static void es1371_remove(struct pci_dev *dev)
dev->driver_data = NULL;
}
-static const struct pci_device_id id_table[] = {
+static struct pci_device_id id_table[] __devinitdata = {
{ PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
{ PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
{ PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
@@ -2809,8 +2813,10 @@ static int __init init_es1371(void)
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n");
- if (!pci_register_driver(&es1371_driver))
+ if (!pci_register_driver(&es1371_driver)) {
+ pci_unregister_driver(&es1371_driver);
return -ENODEV;
+ }
return 0;
}
diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c
index 72fbd14a5..f61503b2f 100644
--- a/drivers/sound/esssolo1.c
+++ b/drivers/sound/esssolo1.c
@@ -67,7 +67,7 @@
* Tim Janik's BSE (Bedevilled Sound Engine) found this
* Integrated (aka redid 8-)) APM support patch by Zach Brown
* 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver
- *
+ * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled
*/
/*****************************************************************************/
@@ -412,7 +412,7 @@ extern inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db)
db->mapped = db->ready = 0;
}
-static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long dmamask)
+static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db)
{
int order;
unsigned bytespersec;
@@ -422,7 +422,6 @@ static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long d
db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
if (!db->rawbuf) {
db->ready = db->mapped = 0;
- s->dev->dma_mask = dmamask;
for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
break;
@@ -469,7 +468,10 @@ extern inline int prog_dmabuf_adc(struct solo1_state *s)
int c;
stop_adc(s);
- if ((c = prog_dmabuf(s, &s->dma_adc, 0xffffff)))
+ /* check if PCI implementation supports 24bit busmaster DMA */
+ if (s->dev->dma_mask > 0xffffff)
+ return -EIO;
+ if ((c = prog_dmabuf(s, &s->dma_adc)))
return c;
va = s->dma_adc.dmaaddr;
if ((va & ~((1<<24)-1)))
@@ -494,7 +496,7 @@ extern inline int prog_dmabuf_dac(struct solo1_state *s)
int c;
stop_dac(s);
- if ((c = prog_dmabuf(s, &s->dma_dac, 0xffffffff)))
+ if ((c = prog_dmabuf(s, &s->dma_dac)))
return c;
memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
va = s->dma_dac.dmaaddr;
@@ -2190,10 +2192,11 @@ static int solo1_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct solo1_state *s;
struct pm_dev *pmdev;
+ dma_addr_t dma_mask;
if (!RSRCISIOREGION(pcidev, 0) ||
!RSRCISIOREGION(pcidev, 1) ||
@@ -2202,6 +2205,14 @@ static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid
return -1;
if (pcidev->irq == 0)
return -1;
+ if (pci_dma_supported(pcidev, 0x00ffffff)) {
+ dma_mask = 0x00ffffff; /* this enables playback and recording */
+ } else if (pci_dma_supported(pcidev, 0xffffffff)) {
+ dma_mask = 0xffffffff; /* this enables only playback, as the recording BMDMA can handle only 24bits */
+ } else {
+ printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
+ return -1;
+ }
if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
printk(KERN_WARNING "solo1: out of memory\n");
return -1;
@@ -2259,7 +2270,7 @@ static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid
goto err;
/* store it in the driver field */
pcidev->driver_data = s;
- pcidev->dma_mask = 0xffffff; /* pessimistic; play can handle 32bit addrs */
+ pcidev->dma_mask = dma_mask;
/* put it into driver list */
list_add_tail(&s->devs, &devs);
@@ -2293,7 +2304,7 @@ static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid
return -1;
}
-static void solo1_remove(struct pci_dev *dev)
+static void __devinit solo1_remove(struct pci_dev *dev)
{
struct solo1_state *s = (struct solo1_state *)dev->driver_data;
@@ -2319,7 +2330,7 @@ static void solo1_remove(struct pci_dev *dev)
dev->driver_data = NULL;
}
-static const struct pci_device_id id_table[] = {
+static struct pci_device_id id_table[] __devinitdata = {
{ PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
{ 0, 0, 0, 0, 0, 0 }
};
@@ -2338,9 +2349,11 @@ static int __init init_solo1(void)
{
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "solo1: version v0.13 time " __TIME__ " " __DATE__ "\n");
- if (!pci_register_driver(&solo1_driver))
+ printk(KERN_INFO "solo1: version v0.14 time " __TIME__ " " __DATE__ "\n");
+ if (!pci_register_driver(&solo1_driver)) {
+ pci_unregister_driver(&solo1_driver);
return -ENODEV;
+ }
return 0;
}
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index 40511d52b..3a4a94247 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -17,10 +17,15 @@
* 06-01-2000 Refined and bugfixed ISA PnP support, added
* CMI 8330 support - Alessandro Zummo <azummo@ita.flashnet.it>
*
- *
* 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump
* Alessandro Zummo <azummo@ita.flashnet.it>
*
+ * 11-02-2000 Added Soundblaster AWE 32 PnP support, refined PnP code
+ * Alessandro Zummo <azummo@ita.flashnet.it>
+ *
+ * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup.
+ * Alessandro Zummo <azummo@ita.flashnet.it>
+ *
*/
#include <linux/config.h>
@@ -134,7 +139,8 @@ static struct address_info config_mpu;
struct pci_dev *sb_dev = NULL,
*wss_dev = NULL,
- *jp_dev = NULL,
+ *jp_dev = NULL,
+/* *ide_dev = NULL, */
*mpu_dev = NULL,
*wt_dev = NULL;
/*
@@ -156,9 +162,10 @@ int support = 0; /* Set support to load this as a support module */
int sm_games = 0; /* Mixer - see sb_mixer.c */
int acer = 0; /* Do acer notebook init */
-#ifdef CONFIG_ISAPNP
+#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
int isapnp = 1;
int isapnpjump = 0;
+int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */
#else
int isapnp = 0;
#endif
@@ -179,11 +186,13 @@ MODULE_PARM(sm_games, "i");
MODULE_PARM(esstype, "i");
MODULE_PARM(acer, "i");
-#ifdef CONFIG_ISAPNP
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
MODULE_PARM(isapnp, "i");
MODULE_PARM(isapnpjump, "i");
+MODULE_PARM(nosbwave, "i");
MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled");
MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
+MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver.");
#endif
MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
@@ -202,79 +211,86 @@ MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks");
void *smw_free = NULL;
-#ifdef CONFIG_ISAPNP
+#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
/* That's useful. */
-static int check_base(char *devname, char *resname, struct resource *res)
+#define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start)
+
+static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev)
{
- if (check_region(res->start, res->end - res->start))
+ int err;
+
+ if(dev->active)
{
- printk(KERN_ERR "sb: %s %s error, i/o at %#lx already in use\n", devname, resname, res->start);
- return 0;
+ printk(KERN_INFO "sb: %s %s already in use\n", devname, resname);
+ return(NULL);
}
- printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, res->start);
- return 1;
-}
+ if((err = dev->activate(dev)) < 0)
+ {
+ printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err);
+ dev->deactivate(dev);
+
+ return(NULL);
+ }
+ return(dev);
+}
/* Card's specific initialization functions
*/
-static struct pci_dev *sb_init_generic(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
{
- if((sb_dev = isapnp_find_dev(card,
- card->vendor,
- card->device,
- NULL)))
+ if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
{
sb_dev->prepare(sb_dev);
- sb_dev->activate(sb_dev);
- if (!sb_dev->resource[0].start)
- return(NULL);
-
- hw_config->io_base = sb_dev->resource[0].start;
- hw_config->irq = sb_dev->irq_resource[0].start;
- hw_config->dma = sb_dev->dma_resource[0].start;
- hw_config->dma2 = sb_dev->dma_resource[1].start;
- mpu_config->io_base = sb_dev->resource[1].start;
+ if((sb_dev = activate_dev("Soundblaster", "sb", sb_dev)))
+ {
+ hw_config->io_base = sb_dev->resource[0].start;
+ hw_config->irq = sb_dev->irq_resource[0].start;
+ hw_config->dma = sb_dev->dma_resource[0].start;
+ hw_config->dma2 = sb_dev->dma_resource[1].start;
+ mpu_config->io_base = sb_dev->resource[1].start;
+ }
}
return(sb_dev);
}
-static struct pci_dev *sb_init_ess(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
{
- if((sb_dev = isapnp_find_dev(card,
- card->vendor,
- card->device,
- NULL)))
+ if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL)))
{
sb_dev->prepare(sb_dev);
- sb_dev->activate(sb_dev);
-
- if (!sb_dev->resource[0].start)
- return(NULL);
- hw_config->io_base = sb_dev->resource[0].start;
- hw_config->irq = sb_dev->irq_resource[0].start;
- hw_config->dma = sb_dev->dma_resource[0].start;
- hw_config->dma2 = sb_dev->dma_resource[1].start;
- mpu_config->io_base = sb_dev->resource[2].start;
+ if((sb_dev = activate_dev("ESS", "sb", sb_dev)))
+ {
+ hw_config->io_base = sb_dev->resource[0].start;
+ hw_config->irq = sb_dev->irq_resource[0].start;
+ hw_config->dma = sb_dev->dma_resource[0].start;
+ hw_config->dma2 = sb_dev->dma_resource[1].start;
+ mpu_config->io_base = sb_dev->resource[2].start;
+ }
}
return(sb_dev);
}
-static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
{
- /* What a stupid chip... where did they get all those @@@ ?*/
-
- printk(KERN_INFO "sb: CMI8330 detected\n");
-
- /* Soundblaster compatible logical device. */
-
- if((sb_dev = isapnp_find_dev(card,
+ /*
+ * The CMI8330/C3D is a very 'stupid' chip... where did they get al those @@@ ?
+ * It's ISAPnP section is badly designed and has many flaws, i'll do my best
+ * to workaround them. I strongly suggest you to buy a real soundcard.
+ * The CMI8330 on my motherboard has also the bad habit to activate
+ * the rear channel of my amplifier instead of the front one.
+ */
+
+ /* @X@0001:Soundblaster.
+ */
+
+ if((sb_dev = isapnp_find_dev(bus,
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
#ifdef CMI8330_DMA0BAD
@@ -283,11 +299,11 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw
sb_dev->prepare(sb_dev);
/* This device doesn't work with DMA 0, so we must allocate
- it to prevent PnP routines to assign it to the card.
-
- I know i could have inlined the following lines, but it's cleaner
- this way.
- */
+ * it to prevent PnP routines to assign it to the card.
+ *
+ * I know i could have inlined the following lines, but it's cleaner
+ * this way.
+ */
#ifdef CMI8330_DMA0BAD
if(sb_dev->dma_resource[0].start == 0)
@@ -300,69 +316,72 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw
}
#endif
- if(sb_dev->activate(sb_dev) >= 0)
+ if((sb_dev = activate_dev("CMI8330", "sb", sb_dev)))
{
hw_config->io_base = sb_dev->resource[0].start;
hw_config->irq = sb_dev->irq_resource[0].start;
hw_config->dma = sb_dev->dma_resource[0].start;
hw_config->dma2 = sb_dev->dma_resource[1].start;
- check_base("CMI8330", "sb", &sb_dev->resource[0]);
+ show_base("CMI8330", "sb", &sb_dev->resource[0]);
}
- else
- printk(KERN_ERR "sb: CMI8330 sb config failed (out of resources?)\n");
#ifdef CMI8330_DMA0BAD
if(dmahack)
free_dma(0);
#endif
+
+ if(!sb_dev) return(NULL);
+
}
else
- printk(KERN_ERR "sb: CMI8330 panic! sb base not found\n");
+ printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n");
+
+ /* @H@0001:mpu
+ */
- if((mpu_dev = isapnp_find_dev(card,
+#ifdef CONFIG_MIDI
+ if((mpu_dev = isapnp_find_dev(bus,
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
mpu_dev->prepare(mpu_dev);
- /* This disables the interrupt on this resource. Do we need it ? */
+ /* This disables the interrupt on this resource. Do we need it ?
+ */
mpu_dev->irq_resource[0].flags = 0;
- if(mpu_dev->activate(mpu_dev) >= 0)
+ if((mpu_dev = activate_dev("CMI8330", "mpu", mpu_dev)))
{
- if( check_base("CMI8330", "mpu", &mpu_dev->resource[0]) )
- mpu_config->io_base = mpu_dev->resource[0].start;
+ show_base("CMI8330", "mpu", &mpu_dev->resource[0]);
+ mpu_config->io_base = mpu_dev->resource[0].start;
}
- else
- printk(KERN_ERR "sb: CMI8330 mpu config failed (out of resources?)\n");
}
else
- printk(KERN_ERR "sb: CMI8330 panic! mpu not found\n");
+ printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n");
+#endif
- /* Gameport. */
+ /* @P@:Gameport
+ */
- if((jp_dev = isapnp_find_dev(card,
+ if((jp_dev = isapnp_find_dev(bus,
ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
jp_dev->prepare(jp_dev);
- if(jp_dev->activate(jp_dev) >= 0)
- {
- check_base("CMI8330", "gameport", &jp_dev->resource[0]);
- }
- else
- printk(KERN_ERR "sb: CMI8330 gameport config failed (out of resources?)\n");
+
+ if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev)))
+ show_base("CMI8330", "gameport", &jp_dev->resource[0]);
}
else
- printk(KERN_ERR "sb: CMI8330 panic! gameport not found\n");
-
+ printk(KERN_ERR "sb: CMI8330 panic: gameport not found\n");
- /* OPL3 support */
+ /* @@@0001:OPL3
+ */
#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
- if((wss_dev = isapnp_find_dev(card,
+ if((wss_dev = isapnp_find_dev(bus,
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
wss_dev->prepare(wss_dev);
@@ -372,15 +391,11 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw
wss_dev->irq_resource[0].flags = 0;
wss_dev->dma_resource[0].flags = 0;
- if(wss_dev->activate(wss_dev) >= 0)
- {
- check_base("CMI8330", "opl3", &wss_dev->resource[1]);
- }
- else
- printk(KERN_ERR "sb: CMI8330 opl3 config failed (out of resources?)\n");
+ if((wss_dev = activate_dev("CMI8330", "opl3", wss_dev)))
+ show_base("CMI8330", "opl3", &wss_dev->resource[1]);
}
else
- printk(KERN_ERR "sb: CMI8330 panic! opl3 not found\n");
+ printk(KERN_ERR "sb: CMI8330 panic: opl3 not found\n");
#endif
printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
@@ -388,18 +403,25 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw
return(sb_dev);
}
-static struct pci_dev *sb_init_awe64(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config)
-{
- printk(KERN_INFO "sb: SoundBlaster AWE 64 detected\n");
-
- /* CTL0042:Audio. */
+/* Specific support for awe will be dropped when:
+ * a) The new awe_wawe driver with PnP support will be introduced in the kernel
+ * b) The joystick driver will support PnP
+ */
- if((sb_dev = isapnp_find_dev(card,
- ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)))
+static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
+{
+ /* CTL0042:Audio SB64
+ * CTL0031:Audio SB32
+ * CTL0045:Audio SB64
+ */
+
+ if( (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) ||
+ (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) ||
+ (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL)) )
{
sb_dev->prepare(sb_dev);
- if(sb_dev->activate(sb_dev) >= 0)
+ if((sb_dev = activate_dev("AWE", "sb", sb_dev)))
{
hw_config->io_base = sb_dev->resource[0].start;
hw_config->irq = sb_dev->irq_resource[0].start;
@@ -408,87 +430,144 @@ static struct pci_dev *sb_init_awe64(struct pci_bus *card, struct address_info *
mpu_config->io_base = sb_dev->resource[1].start;
- check_base("AWE64", "sb", &sb_dev->resource[0]);
- check_base("AWE64", "mpu", &sb_dev->resource[1]);
- check_base("AWE64", "opl3", &sb_dev->resource[2]);
+ show_base("AWE", "sb", &sb_dev->resource[0]);
+ show_base("AWE", "mpu", &sb_dev->resource[1]);
+ show_base("AWE", "opl3", &sb_dev->resource[2]);
}
else
- printk(KERN_ERR "sb: AWE64 sb config failed (out of resources?)\n");
+ return(NULL);
}
else
- printk(KERN_ERR "sb: AWE64 panic! sb base not found\n");
+ printk(KERN_ERR "sb: AWE panic: sb base not found\n");
- /* CTL7002:Game */
+ /* CTL7002:Game SB64
+ * CTL7001:Game SB32
+ */
- if((jp_dev = isapnp_find_dev(card,
- ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)))
+ if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) ||
+ (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) )
{
jp_dev->prepare(jp_dev);
- if(jp_dev->activate(jp_dev) >= 0)
+ if((jp_dev = activate_dev("AWE", "gameport", jp_dev)))
+ show_base("AWE", "gameport", &jp_dev->resource[0]);
+ }
+ else
+ printk(KERN_ERR "sb: AWE panic: gameport not found\n");
+
+
+ /* CTL0022:WaveTable SB64
+ * CTL0021:WaveTable SB32
+ */
+
+ if( nosbwave == 0 &&
+ ( (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) ||
+ (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) ||
+ (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) ))
+ {
+ wt_dev->prepare(wt_dev);
+
+ if((wt_dev = activate_dev("AWE", "wavetable", wt_dev)))
{
- check_base("AWE64", "gameport", &jp_dev->resource[0]);
+ show_base("AWE", "wavetable", &wt_dev->resource[0]);
+ show_base("AWE", "wavetable", &wt_dev->resource[1]);
+ show_base("AWE", "wavetable", &wt_dev->resource[2]);
}
- else
- printk(KERN_ERR "sb: AWE64 gameport config failed (out of resources?)\n");
}
else
- printk(KERN_ERR "sb: AWE64 panic! gameport not found\n");
+ printk(KERN_ERR "sb: AWE panic: wavetable not found\n");
- /* CTL0022:WaveTable */
+ /* CTL2011:IDE SB32/64
+ */
- if((wt_dev = isapnp_find_dev(card,
- ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)))
+/* No reasons to enable this... or not? */
+/*
+ if( (ide_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x2011), NULL)) )
{
- wt_dev->prepare(wt_dev);
+ ide_dev->prepare(ide_dev);
- if(wt_dev->activate(wt_dev) >= 0)
+ if((ide_dev = activate_dev("AWE", "IDE", ide_dev)))
{
- check_base("AWE64", "wavetable", &wt_dev->resource[0]);
- check_base("AWE64", "wavetable", &wt_dev->resource[1]);
- check_base("AWE64", "wavetable", &wt_dev->resource[2]);
+ show_base("AWE", "IDE 1", &ide_dev->resource[0]);
+ show_base("AWE", "IDE 2", &ide_dev->resource[1]);
}
- else
- printk(KERN_ERR "sb: AWE64 wavetable config failed (out of resources?)\n");
}
else
- printk(KERN_ERR "sb: AWE64 panic! wavetable not found\n");
+ printk(KERN_ERR "sb: AWE panic: IDE not found\n");
+*/
- printk(KERN_INFO "sb: AWE64 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
+ printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
return(sb_dev);
}
+#define SBF_DEV 0x01
-static struct { unsigned short vendor, function; struct pci_dev * (*initfunc)(struct pci_bus *, struct address_info *, struct address_info *); char *name; }
+
+static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
isapnp_sb_list[] __initdata = {
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), &sb_init_awe64, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), &sb_init_ess, "ESS 1869" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), &sb_init_ess, "ESS 1878" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), &sb_init_ess, "ESS 1879" },
- {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), &sb_init_cmi, "CMI 8330 SoundPRO" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" },
+ {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
{0}
};
+static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
+{
+ struct pci_dev *idev = NULL;
+
+ /* You missed the init func? That's bad. */
+ if(isapnp_sb_list[slot].initfunc)
+ {
+ char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name;
+
+ printk(KERN_INFO "sb: %s detected\n", busname);
+
+ /* Initialize this baby. */
+
+ if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config)))
+ {
+ /* We got it. */
+
+ printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",
+ busname,
+ hw_config->io_base, hw_config->irq, hw_config->dma,
+ hw_config->dma2);
+ return 1;
+ }
+ else
+ printk(KERN_INFO "sb: Failed to initialize %s\n", busname);
+ }
+ else
+ printk(KERN_ERR "sb: Bad entry in sb_card.c PnP table\n");
+
+ return 0;
+}
+
/* Actually this routine will detect and configure only the first card with successful
- initalization. isapnpjump could be used to jump to a specific entry.
+ initialization. isapnpjump could be used to jump to a specific entry.
Please always add entries at the end of the array.
Should this be fixed? - azummo
*/
-static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) {
-
+static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config)
+{
int i;
/* Count entries in isapnp_sb_list */
@@ -502,34 +581,43 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address
}
for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
- struct pci_bus *card = NULL;
-
- while ((card = isapnp_find_card(
- isapnp_sb_list[i].vendor,
- isapnp_sb_list[i].function,
- card))) {
- /* You missed the init func? That's bad. */
+ if(!(isapnp_sb_list[i].flags & SBF_DEV))
+ {
+ struct pci_bus *bus = NULL;
+
+ while ((bus = isapnp_find_card(
+ isapnp_sb_list[i].vendor,
+ isapnp_sb_list[i].function,
+ bus))) {
+
+ if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i))
+ return 0;
+ }
+ }
+ }
- if(isapnp_sb_list[i].initfunc)
- {
- struct pci_dev *idev = NULL;
+ /* No cards found. I'll try now to search inside every card for a logical device
+ * that matches any entry marked with SBF_DEV in the table.
+ */
+
+ for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
- /* Initialize this baby. */
+ if(isapnp_sb_list[i].flags & SBF_DEV)
+ {
+ struct pci_dev *card = NULL;
- if((idev = isapnp_sb_list[i].initfunc(card, hw_config, mpu_config)))
- {
- /* We got it. */
+ while ((card = isapnp_find_dev(NULL,
+ isapnp_sb_list[i].vendor,
+ isapnp_sb_list[i].function,
+ card))) {
- printk(KERN_INFO "sb: ISAPnP reports %s at i/o %#x, irq %d, dma %d, %d\n",
- isapnp_sb_list[i].name,
- hw_config->io_base, hw_config->irq, hw_config->dma,
- hw_config->dma2);
+ if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i))
return 0;
- }
}
}
}
+
return -ENODEV;
}
#endif
@@ -544,18 +632,15 @@ int init_module(void)
able to disable PNP support for this single driver!
*/
-#ifdef CONFIG_ISAPNP
- if (isapnp)
+#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
+ if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) )
{
- if(sb_probe_isapnp(&config, &config_mpu) < 0 )
- {
- printk(KERN_ERR "sb_card: No ISAPnP cards found\n");
- return -EINVAL;
- }
+ printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
+ isapnp = 0;
}
- else
+#endif
+ if(isapnp == 0)
{
-#endif
if (io == -1 || dma == -1 || irq == -1)
{
printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
@@ -566,11 +651,8 @@ int init_module(void)
config.irq = irq;
config.dma = dma;
config.dma2 = dma16;
-#ifdef CONFIG_ISAPNP
}
-#endif
- /* If this is not before the #ifdef line, there's a reason... */
config.card_subtype = type;
if (!probe_sb(&config))
@@ -604,6 +686,7 @@ void cleanup_module(void)
if(sb_dev) sb_dev->deactivate(sb_dev);
if(jp_dev) jp_dev->deactivate(jp_dev);
if(wt_dev) wt_dev->deactivate(wt_dev);
+/* if(ide_dev) wt_dev->deactivate(ide_dev); */
if(mpu_dev) mpu_dev->deactivate(mpu_dev);
if(wss_dev) wss_dev->deactivate(wss_dev);
}
diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c
index 6e17c8f93..ae86b61f7 100644
--- a/drivers/sound/sonicvibes.c
+++ b/drivers/sound/sonicvibes.c
@@ -2430,7 +2430,7 @@ static struct initvol {
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
static const char __initlocaldata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
struct sv_state *s;
@@ -2447,6 +2447,10 @@ static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
return -1;
if (pcidev->irq == 0)
return -1;
+ if (!pci_dma_supported(pcidev, 0x00ffffff)) {
+ printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
+ return -1;
+ }
/* try to allocate a DDMA resource if not already available */
if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
pcidev->resource[RESOURCE_DDMA].start = 0;
@@ -2598,7 +2602,7 @@ static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
return -1;
}
-static void sv_remove(struct pci_dev *dev)
+static void __devinit sv_remove(struct pci_dev *dev)
{
struct sv_state *s = (struct sv_state *)dev->driver_data;
@@ -2625,7 +2629,7 @@ static void sv_remove(struct pci_dev *dev)
dev->driver_data = NULL;
}
-static const struct pci_device_id id_table[] = {
+static struct pci_device_id id_table[] __devinitdata = {
{ PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
{ 0, 0, 0, 0, 0, 0 }
};
@@ -2648,8 +2652,10 @@ static int __init init_sonicvibes(void)
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
#endif
- if (!pci_register_driver(&sv_driver))
+ if (!pci_register_driver(&sv_driver)) {
+ pci_unregister_driver(&sv_driver);
return -ENODEV;
+ }
return 0;
}
diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c
index a8bc739cc..923b46e90 100644
--- a/drivers/sound/sound_core.c
+++ b/drivers/sound/sound_core.c
@@ -43,13 +43,17 @@
#include <linux/sound.h>
#include <linux/major.h>
#include <linux/kmod.h>
-
-
+#include <linux/devfs_fs_kernel.h>
+
+#define SOUND_STEP 16
+
+
struct sound_unit
{
int unit_minor;
struct file_operations *unit_fops;
struct sound_unit *next;
+ devfs_handle_t de;
};
#ifdef CONFIG_SOUND_MSNDCLAS
@@ -82,7 +86,7 @@ static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list,
if(*list==NULL || (*list)->unit_minor>n)
break;
list=&((*list)->next);
- n+=16;
+ n+=SOUND_STEP;
}
if(n>=top)
@@ -129,6 +133,7 @@ static void __sound_remove_unit(struct sound_unit **list, int unit)
if(p->unit_minor==unit)
{
*list=p->next;
+ devfs_unregister (p->de);
kfree(p);
MOD_DEC_USE_COUNT;
return;
@@ -148,11 +153,15 @@ spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
* Allocate the controlling structure and add it to the sound driver
* list. Acquires locks as needed
*/
+
+static devfs_handle_t devfs_handle = NULL;
-static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top)
+static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode)
{
int r;
struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL);
+ char name_buf[16];
+
if(s==NULL)
return -ENOMEM;
@@ -162,6 +171,13 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
if(r<0)
kfree(s);
+ if (r == low)
+ sprintf (name_buf, "%s", name);
+ else
+ sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP);
+ s->de = devfs_register (devfs_handle, name_buf, 0,
+ DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor,
+ S_IFCHR | mode, 0, 0, fops, NULL);
return r;
}
@@ -203,21 +219,76 @@ static struct sound_unit *chains[16];
int register_sound_special(struct file_operations *fops, int unit)
{
- return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1);
+ char *name;
+
+ switch (unit) {
+ case 0:
+ name = "mixer";
+ break;
+ case 1:
+ name = "sequencer";
+ break;
+ case 2:
+ name = "midi00";
+ break;
+ case 3:
+ name = "dsp";
+ break;
+ case 4:
+ name = "audio";
+ break;
+ case 5:
+ name = "unknown5";
+ break;
+ case 6:
+ name = "sndstat";
+ break;
+ case 7:
+ name = "unknown7";
+ break;
+ case 8:
+ name = "sequencer2";
+ break;
+ case 9:
+ name = "dmmidi";
+ break;
+ case 10:
+ name = "dmfm";
+ break;
+ case 11:
+ name = "unknown11";
+ break;
+ case 12:
+ name = "adsp";
+ break;
+ case 13:
+ name = "amidi";
+ break;
+ case 14:
+ name = "admmidi";
+ break;
+ default:
+ name = "unknown";
+ break;
+ }
+ return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1,
+ name, S_IRUGO | S_IWUGO);
}
EXPORT_SYMBOL(register_sound_special);
int register_sound_mixer(struct file_operations *fops, int dev)
{
- return sound_insert_unit(&chains[0], fops, dev, 0, 128);
+ return sound_insert_unit(&chains[0], fops, dev, 0, 128,
+ "mixer", S_IRUGO | S_IWUGO);
}
EXPORT_SYMBOL(register_sound_mixer);
int register_sound_midi(struct file_operations *fops, int dev)
{
- return sound_insert_unit(&chains[2], fops, dev, 2, 130);
+ return sound_insert_unit(&chains[2], fops, dev, 2, 130,
+ "midi", S_IRUGO | S_IWUGO);
}
EXPORT_SYMBOL(register_sound_midi);
@@ -229,14 +300,16 @@ EXPORT_SYMBOL(register_sound_midi);
int register_sound_dsp(struct file_operations *fops, int dev)
{
- return sound_insert_unit(&chains[3], fops, dev, 3, 131);
+ return sound_insert_unit(&chains[3], fops, dev, 3, 131,
+ "dsp", S_IWUGO | S_IRUSR | S_IRGRP);
}
EXPORT_SYMBOL(register_sound_dsp);
int register_sound_synth(struct file_operations *fops, int dev)
{
- return sound_insert_unit(&chains[9], fops, dev, 9, 137);
+ return sound_insert_unit(&chains[9], fops, dev, 9, 137,
+ "synth", S_IRUGO | S_IWUGO);
}
EXPORT_SYMBOL(register_sound_synth);
@@ -359,7 +432,8 @@ void cleanup_module(void)
{
/* We have nothing to really do here - we know the lists must be
empty */
- unregister_chrdev(SOUND_MAJOR, "sound");
+ devfs_unregister_chrdev(SOUND_MAJOR, "sound");
+ devfs_unregister (devfs_handle);
}
int init_module(void)
@@ -367,11 +441,12 @@ int init_module(void)
int soundcore_init(void)
#endif
{
- if(register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1)
+ if(devfs_register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1)
{
printk(KERN_ERR "soundcore: sound device already in use.\n");
return -EBUSY;
}
+ devfs_handle = devfs_mk_dir (NULL, "sound", 0, NULL);
/*
* Now init non OSS drivers
*/
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index 5593cf5dd..a1d682969 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -15,6 +15,9 @@
* integrated sound_switch.c
* Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat,
* which should disappear in the near future)
+ * Eric Dumas : devfs support (22-Jan-98) <dumas@linux.eu.org> with fixups
+ * by C. Scott Ananian <cananian@alumni.princeton.edu>
+ * Richard Gooch : moved common (non OSS-specific) devices to sound_core.c
*
* Rob Riggs Added persistent DMA buffers support (1998/10/17)
*/
@@ -36,6 +39,8 @@
#include <linux/wait.h>
#include <linux/malloc.h>
#include <linux/ioport.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/major.h>
#endif /* __KERNEL__ */
#include <linux/delay.h>
#include <linux/proc_fs.h>
@@ -93,7 +98,6 @@ unsigned long seq_time = 0; /* Time for /dev/sequencer */
static mixer_vol_table mixer_vols[MAX_MIXER_DEV];
static int num_mixer_volumes = 0;
-
int *load_mixer_volumes(char *name, int *levels, int present)
{
int i, n;
@@ -811,6 +815,66 @@ bad1:
return -1;
}
+
+/* These device names follow the official Linux device list,
+ * Documentation/devices.txt. Let us know if there are other
+ * common names we should support for compatibility.
+ * Only those devices not created by the generic code in sound_core.c are
+ * registered here.
+ */
+static const struct {
+ unsigned short minor;
+ char *name;
+ umode_t mode;
+ int *num;
+} dev_list[] = { /* list of minor devices */
+#ifdef CONFIG_AUDIO
+/* seems to be some confusion here -- this device is not in the device list */
+ {SND_DEV_DSP16, "dspW", S_IWUGO | S_IRUSR | S_IRGRP,
+ &num_audiodevs},
+ {SND_DEV_AUDIO, "audio", S_IWUGO | S_IRUSR | S_IRGRP,
+ &num_audiodevs},
+#endif /* CONFIG_AUDIO */
+};
+
+static char *
+soundcard_make_name(char *buf, char *name, int idx) {
+ if (idx==0)
+ sprintf(buf, "sound/%s", name);
+ else
+ sprintf(buf, "sound/%s%d", name, idx);
+ return buf;
+}
+
+/* Register/unregister audio entries */
+static void soundcard_register_devfs (int do_register)
+{
+ char name_buf[32];
+ int i, j, num;
+
+ for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++)
+ {
+ num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num;
+ for (j = 0; j < num || j == 0; j++)
+ {
+ soundcard_make_name (name_buf, dev_list[i].name, j);
+ if (do_register)
+ devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
+ SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
+ S_IFCHR | dev_list[i].mode, 0, 0,
+ &oss_sound_fops, NULL);
+ else
+ {
+ devfs_handle_t de;
+
+ de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
+ DEVFS_SPECIAL_CHR, 0);
+ devfs_unregister (de);
+ }
+ }
+ }
+}
+
#ifdef MODULE
static void
#else
@@ -849,6 +913,7 @@ soundcard_init(void)
if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info))
printk(KERN_ERR "sound: registering /proc/sound failed\n");
#endif
+ soundcard_register_devfs(1); /* register after we know # of devices */
}
#ifdef MODULE
@@ -931,6 +996,7 @@ void cleanup_module(void)
return;
}
remove_proc_entry("sound", NULL);
+ soundcard_register_devfs (0);
if (chrdev_registered)
destroy_special_devices();
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 95974324c..7f7b8687e 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -9,6 +9,9 @@ if [ ! "$CONFIG_USB" = "n" ]; then
comment 'USB Controllers'
dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+ if [ "$CONFIG_USB_UHCI" != "n" ]; then
+ bool ' USB-UHCI High Bandwidth (EXPERIMENTAL)' CONFIG_USB_UHCI_HIGH_BANDWIDTH
+ fi
dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
if [ "$CONFIG_USB_UHCI_ALT" != "n" ]; then
bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
@@ -28,10 +31,8 @@ comment 'USB Devices'
bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
bool ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR
bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT
- bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI
+ bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO
bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA
- bool ' USB Belkin Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN
- bool ' USB Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PERACOM
fi
dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB
@@ -43,7 +44,8 @@ comment 'USB Devices'
fi
dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
-
+ dep_tristate ' PLUSB Prolific USB-Network driver' CONFIG_USB_PLUSB $CONFIG_USB
+
comment 'USB HID'
dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
if [ "$CONFIG_USB_HID" != "y" ]; then
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 8712d6032..3a0ef10b7 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -23,16 +23,12 @@ export-objs := usb.o input.o
list-multi := usbcore.o
usbcore-objs := usb.o usb-debug.o usb-core.o hub.o
-usb-storage-objs := usb_storage.o
# Optional parts of multipart objects.
ifeq ($(CONFIG_USB_DEVICEFS),y)
usbcore-objs += devio.o inode.o drivers.o devices.o
endif
-ifeq ($(CONFIG_USB_STORAGE_DEBUG),y)
- usb-storage-objs += usb_storage_debug.o
-endif
# Object file lists.
@@ -69,6 +65,7 @@ obj-$(CONFIG_USB_DC2XX) += dc2xx.o
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
+obj-$(CONFIG_USB_PLUSB) += plusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
# Extract lists of the multi-part drivers.
@@ -106,6 +103,3 @@ include $(TOPDIR)/Rules.make
usbcore.o: $(usbcore-objs)
$(LD) -r -o $@ $(usbcore-objs)
-usb-storage.o: $(usb-storage-objs)
- $(LD) -r -o $@ $(usb-storage-objs)
-
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 585a8a278..cc03acb09 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -1,5 +1,5 @@
/*
- * acm.c Version 0.15
+ * acm.c Version 0.16
*
* Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
@@ -18,6 +18,7 @@
* v0.13 - added termios, added hangup
* v0.14 - sized down struct acm
* v0.15 - fixed flow control again - characters could be lost
+ * v0.16 - added code for modems with swapped data and control interfaces
*/
/*
@@ -473,29 +474,34 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
cfacm = dev->config + i;
- dbg("probing config %d", cfacm->bConfigurationValue);
- ifcom = cfacm->interface[0].altsetting + 0;
- if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
- ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
- continue;
+ dbg("probing config %d", cfacm->bConfigurationValue);
- epctrl = ifcom->endpoint + 0;
- if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3)
+ if (cfacm->bNumInterfaces != 2 ||
+ usb_interface_claimed(cfacm->interface + 0) ||
+ usb_interface_claimed(cfacm->interface + 1))
continue;
+ ifcom = cfacm->interface[0].altsetting + 0;
ifdata = cfacm->interface[1].altsetting + 0;
- if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
- continue;
- if (usb_interface_claimed(cfacm->interface + 0) ||
- usb_interface_claimed(cfacm->interface + 1))
+ if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
+ ifcom = cfacm->interface[1].altsetting + 0;
+ ifdata = cfacm->interface[0].altsetting + 0;
+ if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
+ continue;
+ }
+
+ if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+ ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
continue;
+ epctrl = ifcom->endpoint + 0;
epread = ifdata->endpoint + 0;
epwrite = ifdata->endpoint + 1;
- if ((epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+ if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
+ (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
continue;
@@ -640,17 +646,13 @@ static struct tty_driver acm_tty_driver = {
* Init / cleanup.
*/
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit usb_acm_cleanup(void)
{
usb_deregister(&acm_driver);
tty_unregister_driver(&acm_tty_driver);
}
-int init_module(void)
-#else
-int usb_acm_init(void)
-#endif
+static int __init usb_acm_init(void)
{
acm_tty_driver.init_termios = tty_std_termios;
acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -665,3 +667,6 @@ int usb_acm_init(void)
return 0;
}
+
+module_init(usb_acm_init);
+module_exit(usb_acm_cleanup);
diff --git a/drivers/usb/hid-debug.h b/drivers/usb/hid-debug.h
index 52fc94adb..8aaf4be81 100644
--- a/drivers/usb/hid-debug.h
+++ b/drivers/usb/hid-debug.h
@@ -67,19 +67,19 @@ static struct hid_usage_entry hid_usage_table[] = {
{0, 0x45, "Vbrz"},
{0, 0x46, "Vno"},
{0, 0x80, "SystemControl"},
- {0, 0x81, "System PowerDown"},
- {0, 0x82, "System Sleep"},
- {0, 0x83, "System WakeUp"},
- {0, 0x84, "System ContextMenu"},
- {0, 0x85, "System MainMenu"},
- {0, 0x86, "System AppMenu"},
- {0, 0x87, "System MenuHelp"},
- {0, 0x88, "System MenuExit"},
- {0, 0x89, "System MenuSelect"},
- {0, 0x8a, "System MenuRight"},
- {0, 0x8b, "System MenuLeft"},
- {0, 0x8c, "System MenuUp"},
- {0, 0x8d, "System MenuDown"},
+ {0, 0x81, "SystemPowerDown"},
+ {0, 0x82, "SystemSleep"},
+ {0, 0x83, "SystemWakeUp"},
+ {0, 0x84, "SystemContextMenu"},
+ {0, 0x85, "SystemMainMenu"},
+ {0, 0x86, "SystemAppMenu"},
+ {0, 0x87, "SystemMenuHelp"},
+ {0, 0x88, "SystemMenuExit"},
+ {0, 0x89, "SystemMenuSelect"},
+ {0, 0x8a, "SystemMenuRight"},
+ {0, 0x8b, "SystemMenuLeft"},
+ {0, 0x8c, "SystemMenuUp"},
+ {0, 0x8d, "SystemMenuDown"},
{0, 0x90, "D-padUp"},
{0, 0x91, "D-padDown"},
{0, 0x92, "D-padRight"},
@@ -87,6 +87,7 @@ static struct hid_usage_entry hid_usage_table[] = {
{ 7, 0, "Keyboard" },
{ 8, 0, "LED" },
{ 9, 0, "Button" },
+ { 12, 0, "Hotkey" },
{ 13, 0, "Digitizers" },
{0, 0x01, "Digitizer"},
{0, 0x02, "Pen"},
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index 96e633775..85b44010c 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -754,8 +754,25 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
case HID_UP_GENDESK:
+ if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
+ switch (usage->hid & 0xf) {
+ case 0x1: usage->code = KEY_POWER; break;
+ case 0x2: usage->code = KEY_SLEEP; break;
+ case 0x3: usage->code = KEY_WAKEUP; break;
+ default: usage->code = KEY_UNKNOWN; break;
+ }
+ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+ break;
+ }
+
usage->code = usage->hid & 0xf;
+ if (field->report_size == 1) {
+ usage->code = BTN_MISC;
+ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+ break;
+ }
+
if (field->flags & HID_MAIN_ITEM_RELATIVE) {
usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
break;
@@ -816,14 +833,53 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
}
break;
- default:
- unknown:
+ case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
+
+ switch (usage->hid & HID_USAGE) {
+
+ case 0x034: usage->code = KEY_SLEEP; break;
+ case 0x036: usage->code = BTN_MISC; break;
+ case 0x08a: usage->code = KEY_WWW; break;
+ case 0x095: usage->code = KEY_HELP; break;
+
+ case 0x0b4: usage->code = KEY_REWIND; break;
+ case 0x0b5: usage->code = KEY_NEXTSONG; break;
+ case 0x0b6: usage->code = KEY_PREVIOUSSONG; break;
+ case 0x0b7: usage->code = KEY_STOPCD; break;
+ case 0x0b8: usage->code = KEY_EJECTCD; break;
+ case 0x0cd: usage->code = KEY_PLAYPAUSE; break;
+
+ case 0x0e2: usage->code = KEY_MUTE; break;
+ case 0x0e9: usage->code = KEY_VOLUMEUP; break;
+ case 0x0ea: usage->code = KEY_VOLUMEDOWN; break;
+
+ case 0x183: usage->code = KEY_CONFIG; break;
+ case 0x18a: usage->code = KEY_MAIL; break;
+ case 0x192: usage->code = KEY_CALC; break;
+ case 0x194: usage->code = KEY_FILE; break;
+
+ case 0x21a: usage->code = KEY_UNDO; break;
+ case 0x21b: usage->code = KEY_COPY; break;
+ case 0x21c: usage->code = KEY_CUT; break;
+ case 0x21d: usage->code = KEY_PASTE; break;
+
+ case 0x221: usage->code = KEY_FIND; break;
+ case 0x223: usage->code = KEY_HOMEPAGE; break;
+ case 0x224: usage->code = KEY_BACK; break;
+ case 0x225: usage->code = KEY_FORWARD; break;
+ case 0x226: usage->code = KEY_STOP; break;
+ case 0x227: usage->code = KEY_REFRESH; break;
+ case 0x22a: usage->code = KEY_BOOKMARKS; break;
+
+ default: usage->code = KEY_UNKNOWN; break;
- if (field->flags & HID_MAIN_ITEM_RELATIVE) {
- usage->code = REL_MISC;
- usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
- break;
}
+
+ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+ break;
+
+ default:
+ unknown:
if (field->report_size == 1) {
usage->code = BTN_MISC;
@@ -831,6 +887,12 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
break;
}
+ if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+ usage->code = REL_MISC;
+ usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
+ break;
+ }
+
usage->code = ABS_MISC;
usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
break;
@@ -864,7 +926,7 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
}
}
-static void hid_process_event(struct input_dev *input, struct hid_usage *usage, __s32 value)
+static void hid_process_event(struct input_dev *input, int flags, struct hid_usage *usage, __s32 value)
{
hid_dump_input(usage, value);
@@ -876,6 +938,9 @@ static void hid_process_event(struct input_dev *input, struct hid_usage *usage,
}
input_event(input, usage->type, usage->code, value);
+
+ if ((flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
+ input_event(input, usage->type, usage->code, 0);
}
/*
@@ -917,19 +982,19 @@ static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u
} else {
if (value[n] == field->value[n]) continue;
}
- hid_process_event(&dev->input, &field->usage[n], value[n]);
+ hid_process_event(&dev->input, field->flags, &field->usage[n], value[n]);
} else {
if (field->value[n] >= min && field->value[n] <= max /* non-NULL value */
&& field->usage[field->value[n] - min].hid /* nonzero usage */
&& search(value, field->value[n], count))
- hid_process_event(&dev->input, &field->usage[field->value[n] - min], 0);
+ hid_process_event(&dev->input, field->flags, &field->usage[field->value[n] - min], 0);
if (value[n] >= min && value[n] <= max /* non-NULL value */
&& field->usage[value[n] - min].hid /* nonzero usage */
&& search(field->value, value[n], count))
- hid_process_event(&dev->input, &field->usage[value[n] - min], 1);
+ hid_process_event(&dev->input, field->flags, &field->usage[value[n] - min], 1);
}
}
@@ -1190,6 +1255,19 @@ static void hid_init_input(struct hid_device *hid)
}
}
+#define USB_VENDOR_ID_WACOM 0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
+#define USB_DEVICE_ID_WACOM_INTUOS 0x0021
+
+struct hid_blacklist {
+ __u16 idVendor;
+ __u16 idProduct;
+} hid_blacklist[] = {
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },
+ { 0, 0 }
+};
+
static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
{
struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
@@ -1198,6 +1276,10 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
unsigned rsize = 0;
int n;
+ for (n = 0; hid_blacklist[n].idVendor; n++)
+ if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) &&
+ (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL;
+
if (interface->bInterfaceClass != USB_INTERFACE_CLASS_HID)
return NULL;
@@ -1303,7 +1385,7 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum)
hid_init_input(hid);
input_register_device(&hid->input);
- printk(KERN_INFO "input%d: USB HID v%d.%d %s\n",
+ printk(KERN_INFO "input%d: USB HID v%x.%02x %s\n",
hid->input.number, hid->version >> 8, hid->version & 0xff,
(hid->application & 0xffff) <= 8 ? hid_name[hid->application & 0xffff] : "device");
@@ -1340,3 +1422,5 @@ int hid_init(void)
usb_register(&hid_driver);
return 0;
}
+
+__initcall(hid_init);
diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h
index e53135f1e..2449039b8 100644
--- a/drivers/usb/hid.h
+++ b/drivers/usb/hid.h
@@ -158,6 +158,7 @@ struct hid_item {
#define HID_UP_KEYBOARD 0x00070000
#define HID_UP_LED 0x00080000
#define HID_UP_BUTTON 0x00090000
+#define HID_UP_CONSUMER 0x000c0000
#define HID_UP_DIGITIZER 0x000d0000
#define HID_UP_PID 0x000f0000
@@ -200,7 +201,7 @@ struct hid_global {
* This is the local enviroment. It is resistent up the the next main-item.
*/
-#define MAX_USAGES 256
+#define MAX_USAGES 512
struct hid_local {
unsigned usage[MAX_USAGES]; /* usage array */
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 4267971ab..4134574c2 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -453,7 +453,7 @@ static void usb_hub_events(void)
// be shutdown by the hub, this hack enables them again.
// Works at least with mouse driver.
if (!(portstatus & USB_PORT_STAT_ENABLE) &&
- (portstatus & USB_PORT_STAT_CONNECTION)) {
+ (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
err("already running port %i disabled by hub (EMI?), re-enabling...",
i + 1);
usb_hub_port_connect_change(dev, i);
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index 644059570..3c80bb8be 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -31,6 +31,7 @@
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/locks.h>
#include <linux/init.h>
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
index fa370c9af..d613976f5 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -333,3 +333,5 @@ void cleanup_module(void)
{
}
#endif
+
+__initcall(input_init);
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index cd89cedb2..1e00b7e49 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -36,7 +36,7 @@
#include <linux/module.h>
#include <linux/kbd_kern.h>
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
static unsigned char keybdev_x86_e0s[] =
{ 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48,
@@ -52,9 +52,9 @@ static unsigned char keybdev_mac_codes[256] =
2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
- 84, 85, 82, 65, 42,105, 10,103,111, 0, 0, 0, 0, 0, 0, 0,
- 76,125, 75, 0,124, 0,115, 62,116, 59, 60,119, 61,121,114,117,
- 0, 0, 0, 0,127, 24, 0,113, 0, 0, 0, 0, 0, 55, 55, 0 };
+ 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0,
+ 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117,
+ 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 };
#endif
@@ -77,7 +77,7 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int
{
if (type != EV_KEY || code > 255) return;
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
if (code >= 189) {
printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
@@ -118,10 +118,17 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int
static int keybdev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct input_handle *handle;
+ int i;
- if (!test_bit(EV_KEY, dev->evbit) || !test_bit(KEY_A, dev->keybit) || !test_bit(KEY_Z, dev->keybit))
+ if (!test_bit(EV_KEY, dev->evbit))
return -1;
+ for (i = KEY_RESERVED; i < BTN_MISC; i++)
+ if (test_bit(i, dev->keybit)) break;
+
+ if (i == BTN_MISC)
+ return -1;
+
if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
return -1;
memset(handle, 0, sizeof(struct input_handle));
diff --git a/drivers/usb/plusb.c b/drivers/usb/plusb.c
new file mode 100644
index 000000000..d780d8d9c
--- /dev/null
+++ b/drivers/usb/plusb.c
@@ -0,0 +1,632 @@
+/*****************************************************************************/
+
+/*
+ * plusb.c -- prolific pl-2302 driver.
+ *
+ * Copyright (C) 2000 Deti Fliegl (deti@fliegl.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ * $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+//#define DEBUG
+
+#include "usb.h"
+#include "plusb.h"
+
+/* --------------------------------------------------------------------- */
+
+#define NRPLUSB 4
+
+/*-------------------------------------------------------------------*/
+
+static plusb_t plusb[NRPLUSB];
+
+/* --------------------------------------------------------------------- */
+static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_head *src)
+{
+ unsigned long flags;
+ struct list_head *tmp;
+ int ret = 0;
+
+ spin_lock_irqsave (&s->lock, flags);
+
+ if (list_empty (src)) {
+ // no elements in source buffer
+ ret = -1;
+ goto err;
+ }
+ tmp = src->next;
+ list_del (tmp);
+ list_add_tail (tmp, dst);
+
+ err: spin_unlock_irqrestore (&s->lock, flags);
+ return ret;
+}
+/*-------------------------------------------------------------------*/
+
+static int plusb_my_bulk(plusb_t *s, int pipe, void *data, int size, int *actual_length)
+{
+ int ret;
+
+ dbg("plusb_my_bulk: len:%d",size);
+
+ ret=usb_bulk_msg(s->usbdev, pipe, data, size, actual_length, 500);
+ if(ret<0) {
+ err("plusb: usb_bulk_msg failed(%d)",ret);
+ }
+
+ if( ret == -EPIPE ) {
+ warn("CLEAR_FEATURE request to remove STALL condition.");
+ if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
+ err("request failed");
+ }
+
+ dbg("plusb_my_bulk: finished act: %d", *actual_length);
+ return ret;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_bh(void *context)
+{
+ plusb_t *s=context;
+ struct net_device_stats *stats=&s->net_stats;
+ int ret=0;
+ int actual_length;
+ skb_list_t *skb_list;
+ struct sk_buff *skb;
+
+ dbg("plusb_bh: i:%d",in_interrupt());
+
+ while(!list_empty(&s->tx_skb_list)) {
+
+ if(!(s->status&_PLUSB_TXOK))
+ break;
+
+ skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list);
+ if(!skb_list->state) {
+ dbg("plusb_bh: not yet ready");
+ schedule();
+ continue;
+ }
+
+ skb=skb_list->skb;
+ ret=plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
+ skb->data, skb->len, &actual_length);
+
+ if(ret || skb->len != actual_length ||!(skb->len%64)) {
+ plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
+ NULL, 0, &actual_length);
+ }
+
+ if(!ret) {
+ stats->tx_packets++;
+ stats->tx_bytes+=skb->len;
+ }
+ else {
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
+ }
+
+ dbg("plusb_bh: dev_kfree_skb");
+
+ dev_kfree_skb(skb);
+ skb_list->state=0;
+ plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list);
+ }
+
+ dbg("plusb_bh: finished");
+ s->in_bh=0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int plusb_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ plusb_t *s=dev->priv;
+ skb_list_t *skb_list;
+ int ret=NET_XMIT_SUCCESS;
+
+ dbg("plusb_net_xmit: len:%d i:%d",skb->len,in_interrupt());
+
+ if(!s->connected || list_empty(&s->free_skb_list)) {
+ ret=NET_XMIT_CN;
+ goto lab;
+ }
+
+ plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list);
+ skb_list = list_entry (s->tx_skb_list.prev, skb_list_t, skb_list);
+ skb_list->skb=skb;
+ skb_list->state=1;
+
+lab:
+ if(s->in_bh)
+ return ret;
+
+ dbg("plusb_net_xmit: queue_task");
+
+ s->in_bh=1;
+ queue_task(&s->bh, &tq_scheduler);
+
+ dbg("plusb_net_xmit: finished");
+ return ret;
+
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_bulk_complete(urb_t *purb)
+{
+ plusb_t *s=purb->context;
+
+ dbg("plusb_bulk_complete: status:%d length:%d",purb->status,purb->actual_length);
+ if(!s->connected)
+ return;
+
+ if( !purb->status) {
+ struct sk_buff *skb;
+ unsigned char *dst;
+ int len=purb->transfer_buffer_length;
+ struct net_device_stats *stats=&s->net_stats;
+
+ skb=dev_alloc_skb(len);
+
+ if(!skb) {
+ err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len);
+ stats->rx_dropped++;
+ return;
+ }
+
+ dst=(char *)skb_put(skb, len);
+ memcpy( dst, purb->transfer_buffer, len);
+
+ skb->dev=&s->net_dev;
+ skb->protocol=eth_type_trans(skb, skb->dev);
+ stats->rx_packets++;
+ stats->rx_bytes+=len;
+ netif_rx(skb);
+ }
+ else
+ purb->status=0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_int_complete(urb_t *purb)
+{
+ plusb_t *s=purb->context;
+ s->status=((unsigned char*)purb->transfer_buffer)[0]&255;
+#if 0
+ if((s->status&0x3f)!=0x20) {
+ warn("invalid device status %02X", s->status);
+ return;
+ }
+#endif
+ if(!s->connected)
+ return;
+
+ if(s->status&_PLUSB_RXD) {
+ int ret;
+
+ if(s->bulkurb->status) {
+ err("plusb_int_complete: URB still in use");
+ return;
+ }
+
+ ret=usb_submit_urb(s->bulkurb);
+ if(ret && ret!=-EBUSY) {
+ err("plusb_int_complete: usb_submit_urb failed");
+ }
+ }
+
+ if(purb->status || s->status!=160)
+ dbg("status: %p %d buf: %02X", purb->dev, purb->status, s->status);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_free_all(plusb_t *s)
+{
+ struct list_head *skb;
+ skb_list_t *skb_list;
+
+ dbg("plusb_free_all");
+ run_task_queue(&tq_immediate);
+
+ if(s->inturb) {
+ dbg("unlink inturb");
+ usb_unlink_urb(s->inturb);
+ }
+
+ if(s->inturb && s->inturb->transfer_buffer) {
+ dbg("kfree inturb->transfer_buffer");
+ kfree(s->inturb->transfer_buffer);
+ s->inturb->transfer_buffer=NULL;
+ }
+
+ if(s->inturb) {
+ dbg("free_urb inturb");
+ usb_free_urb(s->inturb);
+ s->inturb=NULL;
+ }
+
+ if(s->bulkurb) {
+ dbg("unlink bulkurb");
+ usb_unlink_urb(s->bulkurb);
+ }
+
+ if(s->bulkurb && s->bulkurb->transfer_buffer) {
+ dbg("kfree bulkurb->transfer_buffer");
+ kfree(s->bulkurb->transfer_buffer);
+ s->bulkurb->transfer_buffer=NULL;
+ }
+ if(s->bulkurb) {
+ dbg("free_urb bulkurb");
+ usb_free_urb(s->bulkurb);
+ s->bulkurb=NULL;
+ }
+
+ while(!list_empty(&s->free_skb_list)) {
+ skb=s->free_skb_list.next;
+ list_del(skb);
+ skb_list = list_entry (skb, skb_list_t, skb_list);
+ kfree(skb_list);
+ }
+
+ while(!list_empty(&s->tx_skb_list)) {
+ skb=s->tx_skb_list.next;
+ list_del(skb);
+ skb_list = list_entry (skb, skb_list_t, skb_list);
+ kfree(skb_list);
+ }
+ dbg("plusb_free_all: finished");
+}
+
+/*-------------------------------------------------------------------*/
+
+static int plusb_alloc(plusb_t *s)
+{
+ int i;
+ skb_list_t *skb;
+
+ dbg("plusb_alloc");
+
+ for(i=0 ; i < _SKB_NUM ; i++) {
+ skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL);
+ if(!skb) {
+ err("kmalloc for skb_list failed");
+ goto reject;
+ }
+ memset(skb, 0, sizeof(skb_list_t));
+ list_add(&skb->skb_list, &s->free_skb_list);
+ }
+
+ dbg("inturb allocation:");
+ s->inturb=usb_alloc_urb(0);
+ if(!s->inturb) {
+ err("alloc_urb failed");
+ goto reject;
+ }
+
+ dbg("bulkurb allocation:");
+ s->bulkurb=usb_alloc_urb(0);
+ if(!s->bulkurb) {
+ err("alloc_urb failed");
+ goto reject;
+ }
+
+ dbg("bulkurb/inturb init:");
+ s->inturb->dev=s->usbdev;
+ s->inturb->pipe=usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE);
+ s->inturb->transfer_buffer=kmalloc(64, GFP_KERNEL);
+ if(!s->inturb->transfer_buffer) {
+ err("kmalloc failed");
+ goto reject;
+ }
+
+ s->inturb->transfer_buffer_length=1;
+ s->inturb->complete=plusb_int_complete;
+ s->inturb->context=s;
+ s->inturb->interval=10;
+
+ dbg("inturb submission:");
+ if(usb_submit_urb(s->inturb)<0) {
+ err("usb_submit_urb failed");
+ goto reject;
+ }
+
+ dbg("bulkurb init:");
+ s->bulkurb->dev=s->usbdev;
+ s->bulkurb->pipe=usb_rcvbulkpipe (s->usbdev, _PLUSB_BULKINPIPE);
+ s->bulkurb->transfer_buffer=kmalloc(_BULK_DATA_LEN, GFP_KERNEL);
+ if(!s->bulkurb->transfer_buffer) {
+ err("kmalloc failed");
+ goto reject;
+ }
+
+ s->bulkurb->transfer_buffer_length=_BULK_DATA_LEN;
+ s->bulkurb->complete=plusb_bulk_complete;
+ s->bulkurb->context=s;
+
+ dbg("plusb_alloc: finished");
+
+ return 0;
+
+ reject:
+ dbg("plusb_alloc: failed");
+
+ plusb_free_all(s);
+ return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------*/
+
+static int plusb_net_open(struct net_device *dev)
+{
+ plusb_t *s=dev->priv;
+
+ dbg("plusb_net_open");
+
+ if(plusb_alloc(s))
+ return -ENOMEM;
+
+ s->opened=1;
+ MOD_INC_USE_COUNT;
+
+ dbg("plusb_net_open: success");
+
+ return 0;
+
+}
+
+/* --------------------------------------------------------------------- */
+
+static int plusb_net_stop(struct net_device *dev)
+{
+ plusb_t *s=dev->priv;
+
+ dbg("plusb_net_stop");
+
+ plusb_free_all(s);
+ s->opened=0;
+ MOD_DEC_USE_COUNT;
+ dbg("plusb_net_stop:finished");
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct net_device_stats *plusb_net_get_stats(struct net_device *dev)
+{
+ plusb_t *s=dev->priv;
+
+ dbg("net_device_stats");
+
+ return &s->net_stats;
+}
+
+/* --------------------------------------------------------------------- */
+
+static plusb_t *plusb_find_struct (void)
+{
+ int u;
+
+ for (u = 0; u < NRPLUSB; u++) {
+ plusb_t *s = &plusb[u];
+ if (!s->connected)
+ return s;
+ }
+ return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_disconnect (struct usb_device *usbdev, void *ptr)
+{
+ plusb_t *s = ptr;
+
+ dbg("plusb_disconnect");
+ s->connected = 0;
+
+ plusb_free_all(s);
+
+ if(!s->opened && s->net_dev.name) {
+ dbg("unregistering netdev: %s",s->net_dev.name);
+ unregister_netdev(&s->net_dev);
+ kfree(s->net_dev.name);
+ s->net_dev.name=NULL;
+ }
+
+ dbg("plusb_disconnect: finished");
+ MOD_DEC_USE_COUNT;
+}
+
+/* --------------------------------------------------------------------- */
+
+int plusb_net_init(struct net_device *dev)
+{
+ dbg("plusb_net_init");
+
+ dev->open=plusb_net_open;
+ dev->stop=plusb_net_stop;
+ dev->hard_start_xmit=plusb_net_xmit;
+ dev->get_stats = plusb_net_get_stats;
+ ether_setup(dev);
+ dev->tx_queue_len = 0;
+ dev->flags = IFF_POINTOPOINT|IFF_NOARP;
+
+
+ dbg("plusb_net_init: finished");
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum)
+{
+ plusb_t *s;
+
+ dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
+ usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
+
+ if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct > 0x1)
+ return NULL;
+
+ /* We don't handle multiple configurations */
+ if (usbdev->descriptor.bNumConfigurations != 1)
+ return NULL;
+
+ s = plusb_find_struct ();
+ if (!s)
+ return NULL;
+
+ s->usbdev = usbdev;
+
+ if (usb_set_configuration (s->usbdev, usbdev->config[0].bConfigurationValue) < 0) {
+ err("set_configuration failed");
+ return NULL;
+ }
+
+ if (usb_set_interface (s->usbdev, 0, 0) < 0) {
+ err("set_interface failed");
+ return NULL;
+ }
+
+ if(!s->net_dev.name) {
+ s->net_dev.name=kmalloc(16, GFP_KERNEL);
+
+ if(!s->net_dev.name || dev_alloc_name(&s->net_dev,"plusb%d")<0) {
+ err("alloc name failed\n");
+ return NULL;
+ }
+
+ s->net_dev.init=plusb_net_init;
+ s->net_dev.priv=s;
+ if(!register_netdev(&s->net_dev))
+ info("registered: %s", s->net_dev.name);
+ else {
+ err("register_netdev failed");
+ kfree(s->net_dev.name);
+ s->net_dev.name=NULL;
+ }
+ }
+
+ s->connected = 1;
+
+ if(s->opened) {
+ dbg("net device already allocated, restarting USB transfers");
+ plusb_alloc(s);
+ }
+
+ info("bound to interface: %d dev: %p", ifnum, usbdev);
+ MOD_INC_USE_COUNT;
+ return s;
+}
+/* --------------------------------------------------------------------- */
+
+static struct usb_driver plusb_driver =
+{
+ name: "plusb",
+ probe: plusb_probe,
+ disconnect: plusb_disconnect,
+};
+
+/* --------------------------------------------------------------------- */
+
+int __init plusb_init (void)
+{
+ unsigned u;
+ dbg("plusb_init");
+
+ /* initialize struct */
+ for (u = 0; u < NRPLUSB; u++) {
+ plusb_t *s = &plusb[u];
+ memset (s, 0, sizeof (plusb_t));
+ s->bh.routine = (void (*)(void *))plusb_bh;
+ s->bh.data = s;
+ INIT_LIST_HEAD (&s->tx_skb_list);
+ INIT_LIST_HEAD (&s->free_skb_list);
+ spin_lock_init (&s->lock);
+ }
+
+ /* register misc device */
+ usb_register (&plusb_driver);
+
+ dbg("plusb_init: driver registered");
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+void __exit plusb_cleanup (void)
+{
+ unsigned u;
+
+ dbg("plusb_cleanup");
+ for (u = 0; u < NRPLUSB; u++) {
+ plusb_t *s = &plusb[u];
+ if(s->net_dev.name) {
+ dbg("unregistering netdev: %s",s->net_dev.name);
+ unregister_netdev(&s->net_dev);
+ kfree(s->net_dev.name);
+ s->net_dev.name=NULL;
+ }
+ }
+ usb_deregister (&plusb_driver);
+ dbg("plusb_cleanup: finished");
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");
+MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000");
+
+/* --------------------------------------------------------------------- */
+int __init init_module (void)
+{
+ return plusb_init ();
+}
+/* --------------------------------------------------------------------- */
+void __exit cleanup_module (void)
+{
+ plusb_cleanup ();
+}
+
+#endif
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/plusb.h b/drivers/usb/plusb.h
new file mode 100644
index 000000000..a77ae0f01
--- /dev/null
+++ b/drivers/usb/plusb.h
@@ -0,0 +1,48 @@
+#define _PLUSB_INTPIPE 0x1
+#define _PLUSB_BULKOUTPIPE 0x2
+#define _PLUSB_BULKINPIPE 0x3
+
+#define _SKB_NUM 1000
+// 7 6 5 4 3 2 1 0
+// tx rx 1 0
+// 1110 0000 rxdata
+// 1010 0000 idle
+// 0010 0000 tx over
+// 0110 tx over + rxd
+
+#define _PLUSB_RXD 0x40
+#define _PLUSB_TXOK 0x80
+
+#ifdef __KERNEL__
+#define _BULK_DATA_LEN 16384
+
+typedef struct
+{
+ struct list_head skb_list;
+ struct sk_buff *skb;
+ int state;
+} skb_list_t,*pskb_list_t;
+
+typedef struct
+{
+ struct usb_device *usbdev;
+
+ int status;
+ int connected;
+ int in_bh;
+ int opened;
+
+ spinlock_t lock;
+
+ urb_t *inturb;
+ urb_t *bulkurb;
+
+ struct list_head tx_skb_list;
+ struct list_head free_skb_list;
+ struct tq_struct bh;
+
+ struct net_device net_dev;
+ struct net_device_stats net_stats;
+} plusb_t,*pplusb_t;
+
+#endif
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 7a4bcd108..07220ad9b 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -432,18 +432,18 @@ static struct usb_driver usblp_driver = {
minor: USBLP_MINOR_BASE
};
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit usb_printer_cleanup(void)
{
usb_deregister(&usblp_driver);
}
-int init_module(void)
-#else
-int usb_printer_init(void)
-#endif
+
+static int __init usb_printer_init(void)
{
if (usb_register(&usblp_driver))
return -1;
return 0;
}
+
+module_init(usb_printer_init);
+module_exit(usb_printer_cleanup);
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index b5cd41d85..d55e54206 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -130,10 +130,29 @@
* - Added Microtek X6 ID's. Thanks to Oliver Neukum
* <Oliver.Neukum@lrz.uni-muenchen.de>.
*
+ *
+ * 0.4.1 2/15/2000
+ *
+ * - Fixed 'count' bug in read_scanner(). Thanks to Henrik
+ * Johansson <henrikjo@post.utfors.se> for identifying it. Amazing
+ * it has worked this long.
+ * - Fixed '>=' bug in both read/write_scanner methods.
+ * - Cleaned up both read/write_scanner() methods so that they are
+ * a little more readable.
+ * - Added a lot of Microtek ID's. Thanks to Adrian Perez Jorge.
+ * - Adopted the __initcall().
+ * - Added #include <linux/init.h> to scanner.h for __initcall().
+ * - Added one liner in irq_scanner() to keep gcc from complaining
+ * about an unused variable (data) if debugging was disabled
+ * in scanner.c.
+ * - Increased the timeout parameter in read_scanner() to 120 Secs.
+ *
*
* TODO
*
* - Select/poll methods
+ * - More testing
+ * - Proper registry/assignment for LM9830 ioctl's
*
*
* Thanks to:
@@ -143,6 +162,9 @@
* - To Linus Torvalds for this great OS.
* - The GNU folks.
* - The folks that forwarded Vendor:Product ID's to me.
+ * - Johannes Erdfelt for the loaning of a USB analyzer for tracking an
+ * issue with HP-4100 and uhci.
+ * - Adolfo Montero for his assistance.
* - And anybody else who chimed in with reports and suggestions.
*
* Performance:
@@ -167,6 +189,7 @@ irq_scanner(struct urb *urb)
struct scn_usb_data *scn = urb->context;
unsigned char *data = &scn->button;
+ data += 0; /* Keep gcc from complaining about unused var */
if (urb->status) {
return;
@@ -253,11 +276,11 @@ write_scanner(struct file * file, const char * buffer,
struct scn_usb_data *scn;
struct usb_device *dev;
- ssize_t bytes_written = 0;
+ ssize_t bytes_written = 0; /* Overall count of bytes written */
ssize_t ret = 0;
- int copy_size;
- int partial;
+ int this_write; /* Number of bytes to write */
+ int partial; /* Number of bytes successfully written */
int result = 0;
char *obuf;
@@ -275,15 +298,15 @@ write_scanner(struct file * file, const char * buffer,
break;
}
- copy_size = (count > OBUF_SIZE) ? OBUF_SIZE : count;
+ this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count;
- if (copy_from_user(scn->obuf, buffer, copy_size)) {
+ if (copy_from_user(scn->obuf, buffer, this_write)) {
ret = -EFAULT;
break;
}
- result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, copy_size, &partial, 60*HZ);
- dbg("write stats(%d): result:%d copy_size:%d partial:%d", scn->scn_minor, result, copy_size, partial);
+ result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
+ dbg("write stats(%d): result:%d this_write:%d partial:%d", scn->scn_minor, result, this_write, partial);
if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
warn("write_scanner: NAK recieved.");
@@ -306,7 +329,7 @@ write_scanner(struct file * file, const char * buffer,
printk("\n");
}
#endif
- if (partial != copy_size) { /* Unable to write complete amount */
+ if (partial != this_write) { /* Unable to write all contents of obuf */
ret = -EIO;
break;
}
@@ -332,10 +355,11 @@ read_scanner(struct file * file, char * buffer,
struct scn_usb_data *scn;
struct usb_device *dev;
- ssize_t read_count, ret = 0;
+ ssize_t bytes_read = 0; /* Overall count of bytes_read */
+ ssize_t ret = 0;
- int partial;
- int this_read;
+ int partial; /* Number of bytes successfully read */
+ int this_read; /* Max number of bytes to read */
int result;
char *ibuf;
@@ -346,7 +370,7 @@ read_scanner(struct file * file, char * buffer,
dev = scn->scn_dev;
- read_count = 0;
+ bytes_read = 0;
while (count) {
if (signal_pending(current)) {
@@ -354,9 +378,9 @@ read_scanner(struct file * file, char * buffer,
break;
}
- this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
+ this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
- result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, 60*HZ);
+ result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, 120*HZ);
dbg("read stats(%d): result:%d this_read:%d partial:%d", scn->scn_minor, result, this_read, partial);
if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */
@@ -382,24 +406,22 @@ read_scanner(struct file * file, char * buffer,
#endif
if (partial) { /* Data returned */
- count = this_read = partial;
- } else {
- ret = 0;
- read_count = 0;
- break;
- }
-
- if (this_read) {
if (copy_to_user(buffer, ibuf, this_read)) {
ret = -EFAULT;
break;
}
- count -= this_read;
- read_count += this_read;
- buffer += this_read;
+ count -= partial;
+ bytes_read += partial;
+ buffer += partial;
+
+ } else {
+ ret = 0;
+ break;
}
+
}
- return ret ? ret : read_count;
+
+ return ret ? ret : bytes_read;
}
static void *
@@ -442,7 +464,8 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
* that this will allow developers a means to produce applications
* that will support USB products.
*
- * Until we detect a device which is pleasing, we silently punt. */
+ * Until we detect a device which is pleasing, we silently punt.
+ */
do {
if (dev->descriptor.idVendor == 0x03f0) { /* Hewlett Packard */
@@ -460,6 +483,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
if (dev->descriptor.idVendor == 0x06bd) { /* Agfa */
if (dev->descriptor.idProduct == 0x0001 || /* SnapScan 1212U */
+ dev->descriptor.idProduct == 0x2061 || /* Another SnapScan 1212U (?) */
dev->descriptor.idProduct == 0x0100) { /* SnapScan Touch */
valid_device = 1;
break;
@@ -490,7 +514,13 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
}
if (dev->descriptor.idVendor == 0x05da) { /* Microtek */
- if (dev->descriptor.idProduct == 0x0099) { /* X6 */
+ if (dev->descriptor.idProduct == 0x0099 || /* ScanMaker X6 - X6U */
+ dev->descriptor.idProduct == 0x0094 || /* Phantom 336CX - C3 */
+ dev->descriptor.idProduct == 0x00a0 || /* Phantom 336CX - C3 #2 */
+ dev->descriptor.idProduct == 0x009a || /* Phantom C6 */
+ dev->descriptor.idProduct == 0x00a3 || /* ScanMaker V6USL */
+ dev->descriptor.idProduct == 0x80a3 || /* ScanMaker V6USL #2 */
+ dev->descriptor.idProduct == 0x80ac) { /* ScanMaker V6UL - SpicyU */
valid_device = 1;
break;
}
@@ -763,11 +793,18 @@ ioctl_scanner(struct inode *inode, struct file *file,
static struct
file_operations usb_scanner_fops = {
- read: read_scanner,
- write: write_scanner,
- ioctl: ioctl_scanner,
- open: open_scanner,
- release: close_scanner,
+ NULL, /* seek */
+ read_scanner,
+ write_scanner,
+ NULL, /* readdir */
+ NULL, /* poll */
+ ioctl_scanner,
+ NULL, /* mmap */
+ open_scanner,
+ NULL, /* flush */
+ close_scanner,
+ NULL,
+ NULL, /* fasync */
};
static struct
@@ -780,8 +817,15 @@ usb_driver scanner_driver = {
SCN_BASE_MNR
};
-int
-usb_scanner_init(void)
+#ifdef MODULE
+void cleanup_module(void)
+{
+ usb_deregister(&scanner_driver);
+}
+int init_module(void)
+#else
+int usb_scanner_init(void)
+#endif
{
if (usb_register(&scanner_driver) < 0)
return -1;
@@ -790,18 +834,4 @@ usb_scanner_init(void)
return 0;
}
-#ifdef MODULE
-
-int
-init_module(void)
-{
- return usb_scanner_init();
-}
-
-void
-cleanup_module(void)
-{
- usb_deregister(&scanner_driver);
-}
-#endif
-
+__initcall(usb_scanner_init);
diff --git a/drivers/usb/scanner.h b/drivers/usb/scanner.h
index b1bac6018..9ba1bf0d5 100644
--- a/drivers/usb/scanner.h
+++ b/drivers/usb/scanner.h
@@ -2,6 +2,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
+#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
@@ -10,6 +11,7 @@
#include "usb.h"
+/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
// #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
diff --git a/drivers/usb/uhci-debug.h b/drivers/usb/uhci-debug.h
index 9d715d4d8..61b14ba40 100644
--- a/drivers/usb/uhci-debug.h
+++ b/drivers/usb/uhci-debug.h
@@ -193,7 +193,7 @@ static const char *qh_names[] = { "control", "bulk" };
void uhci_show_queues(struct uhci *uhci)
{
- int i, isqh;
+ int i, isqh = 0;
struct uhci_qh *qh;
struct uhci_td *td;
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index 9e7557e8f..60b411761 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -29,19 +29,13 @@ void usb_major_cleanup(void);
* USB device drivers
*/
-int usb_acm_init(void);
int usb_audio_init(void);
int usb_cpia_init(void);
int usb_ibmcam_init(void);
int usb_ov511_init(void);
-int usb_dc2xx_init(void);
-int usb_scanner_init(void);
-int usb_printer_init(void);
int usb_stor_init(void);
-int usb_serial_init(void);
int dabusb_init(void);
-int hid_init(void);
-int input_init(void);
+int plusb_init(void);
int usb_mouse_init(void);
int usb_kbd_init(void);
int graphire_init(void);
@@ -62,9 +56,8 @@ int ohci_hcd_init(void);
void cleanup_module(void)
{
usb_major_cleanup();
- usbdevfs_cleanup();
+ usbdevfs_cleanup();
usb_hub_cleanup();
-
}
/*
@@ -81,21 +74,9 @@ int usb_init(void)
usb_hub_init();
#ifndef CONFIG_USB_MODULE
-#ifdef CONFIG_USB_SCANNER
- usb_scanner_init();
-#endif
#ifdef CONFIG_USB_AUDIO
usb_audio_init();
#endif
-#ifdef CONFIG_USB_ACM
- usb_acm_init();
-#endif
-#ifdef CONFIG_USB_PRINTER
- usb_printer_init();
-#endif
-#ifdef CONFIG_USB_SERIAL
- usb_serial_init();
-#endif
#ifdef CONFIG_USB_CPIA
usb_cpia_init();
#endif
@@ -105,20 +86,14 @@ int usb_init(void)
#ifdef CONFIG_USB_OV511
usb_ov511_init();
#endif
-#ifdef CONFIG_USB_DC2XX
- usb_dc2xx_init();
-#endif
#ifdef CONFIG_USB_STORAGE
usb_stor_init();
#endif
#ifdef CONFIG_USB_DABUSB
dabusb_init();
#endif
-#if defined(CONFIG_USB_HID) || defined(CONFIG_USB_MOUSE) || defined(CONFIG_USB_KBD) || defined(CONFIG_USB_GRAPHIRE)
- input_init();
-#endif
-#ifdef CONFIG_USB_HID
- hid_init();
+#ifdef CONFIG_USB_PLUSB
+ plusb_init();
#endif
#ifdef CONFIG_USB_MOUSE
usb_mouse_init();
diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c
index 4796ec244..f87600e83 100644
--- a/drivers/usb/usb-serial.c
+++ b/drivers/usb/usb-serial.c
@@ -14,6 +14,24 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (02/14/2000) gkh
+ * Removed the Belkin and Peracom functionality from the driver due to
+ * the lack of support from the vendor, and me not wanting people to
+ * accidenatly buy the device, expecting it to work with Linux.
+ * Added read_bulk_callback and write_bulk_callback to the type structure
+ * for the needs of the FTDI and WhiteHEAT driver.
+ * Changed all reverences to FTDI to FTDI_SIO at the request of Bill
+ * Ryder.
+ * Changed the output urb size back to the max endpoint size to make
+ * the ftdi_sio driver have it easier, and due to the fact that it didn't
+ * really increase the speed any.
+ *
+ * (02/11/2000) gkh
+ * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
+ * patch from Miles Lott (milos@insync.net).
+ * Fixed bug with not restoring the minor range that a device grabs, if
+ * the startup function fails (thanks Miles for finding this).
+ *
* (02/05/2000) gkh
* Added initial framework for the Keyspan PDA serial converter so that
* Brian Warner has a place to put his code.
@@ -228,6 +246,23 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
}
+static void return_serial (struct usb_serial *serial)
+{
+ int i;
+
+ dbg("return_serial");
+
+ if (serial == NULL)
+ return;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ serial_table[serial->minor + i] = NULL;
+ }
+
+ return;
+}
+
+
#ifdef USES_EZUSB_FUNCTIONS
/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
#define CPUCS_REG 0x7F92
@@ -264,67 +299,6 @@ static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
#endif /* USES_EZUSB_FUNCTIONS */
-static void serial_read_bulk (struct urb *urb)
-{
- struct usb_serial *serial = (struct usb_serial *)urb->context;
- struct tty_struct *tty = serial->tty;
- unsigned char *data = urb->transfer_buffer;
- int i;
-
- dbg("serial_read_irq");
-
- if (urb->status) {
- dbg("nonzero read bulk status received: %d", urb->status);
- return;
- }
-
-#ifdef DEBUG
- if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
- printk ("0x%.2x ", data[i]);
- }
- printk ("\n");
- }
-#endif
-
- if (urb->actual_length) {
- for (i = 0; i < urb->actual_length ; ++i) {
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
- }
-
- /* Continue trying to always read */
- if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
-
- return;
-}
-
-
-static void serial_write_bulk (struct urb *urb)
-{
- struct usb_serial *serial = (struct usb_serial *) urb->context;
- struct tty_struct *tty = serial->tty;
-
- dbg("serial_write_irq");
-
- if (urb->status) {
- dbg("nonzero write bulk status received: %d", urb->status);
- return;
- }
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-
- wake_up_interruptible(&tty->write_wait);
-
- return;
-}
-
-
-
/*****************************************************************************
* Driver tty interface functions
*****************************************************************************/
@@ -547,53 +521,6 @@ static void serial_unthrottle (struct tty_struct * tty)
}
-#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM)
-/*****************************************************************************
- * eTek specific driver functions
- *****************************************************************************/
-static int etek_serial_open (struct tty_struct *tty, struct file *filp)
-{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("etek_serial_open port %d", port);
-
- if (serial->active[port]) {
- dbg ("device already open");
- return -EINVAL;
- }
- serial->active[port] = 1;
-
- /*Start reading from the device*/
- if (usb_submit_urb(&serial->read_urb[port]))
- dbg("usb_submit_urb(read bulk) failed");
-
- /* Need to do device specific setup here (control lines, baud rate, etc.) */
- /* FIXME!!! */
-
- return (0);
-}
-
-
-static void etek_serial_close(struct tty_struct *tty, struct file * filp)
-{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("etek_serial_close port %d", port);
-
- /* Need to change the control lines here */
- /* FIXME */
-
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (&serial->write_urb[port]);
- usb_unlink_urb (&serial->read_urb[port]);
- serial->active[port] = 0;
-}
-#endif /* defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) */
-
-
-
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
@@ -851,6 +778,9 @@ static int visor_startup (struct usb_serial *serial)
case VISOR_FUNCTION_HOTSYNC:
string = "HotSync";
break;
+ case VISOR_FUNCTION_CONSOLE:
+ string = "Console";
+ break;
case VISOR_FUNCTION_REMOTE_FILE_SYS:
string = "Remote File System";
break;
@@ -879,11 +809,11 @@ static int visor_startup (struct usb_serial *serial)
#endif /* CONFIG_USB_SERIAL_VISOR*/
-#ifdef CONFIG_USB_SERIAL_FTDI
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
/******************************************************************************
- * FTDI Serial Converter specific driver functions
+ * FTDI SIO Serial Converter specific driver functions
******************************************************************************/
-static int ftdi_serial_open (struct tty_struct *tty, struct file *filp)
+static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
int port = MINOR(tty->device) - serial->minor;
@@ -907,7 +837,7 @@ static int ftdi_serial_open (struct tty_struct *tty, struct file *filp)
}
-static void ftdi_serial_close (struct tty_struct *tty, struct file *filp)
+static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
int port = MINOR(tty->device) - serial->minor;
@@ -924,7 +854,7 @@ static void ftdi_serial_close (struct tty_struct *tty, struct file *filp)
}
-#endif
+#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
@@ -1111,6 +1041,67 @@ static int generic_chars_in_buffer (struct tty_struct *tty)
}
+static void generic_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial *serial = (struct usb_serial *)urb->context;
+ struct tty_struct *tty = serial->tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+
+ dbg("generic_read_bulk_callback");
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("0x%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+
+ return;
+}
+
+
+static void generic_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial *serial = (struct usb_serial *) urb->context;
+ struct tty_struct *tty = serial->tty;
+
+ dbg("generic_write_bulk_callback");
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ return;
+}
+
+
+
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial *serial = NULL;
@@ -1211,8 +1202,10 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
/* if this device type has a startup function, call it */
if (type->startup) {
- if (type->startup (serial))
+ if (type->startup (serial)) {
+ return_serial (serial);
return NULL;
+ }
}
/* set up the endpoint information */
@@ -1223,19 +1216,29 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
err("Couldn't allocate bulk_in_buffer");
goto probe_error;
}
- FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- serial->bulk_in_buffer[i], buffer_size, serial_read_bulk, serial);
+ if (serial->type->read_bulk_callback) {
+ FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ serial->bulk_in_buffer[i], buffer_size, serial->type->read_bulk_callback, serial);
+ } else {
+ FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ serial->bulk_in_buffer[i], buffer_size, generic_read_bulk_callback, serial);
+ }
}
for (i = 0; i < num_bulk_out; ++i) {
- serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize * 2;
+ serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize;
serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL);
if (!serial->bulk_out_buffer[i]) {
err("Couldn't allocate bulk_out_buffer");
goto probe_error;
}
- FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial_write_bulk, serial);
+ if (serial->type->write_bulk_callback) {
+ FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial->type->write_bulk_callback, serial);
+ } else {
+ FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ serial->bulk_out_buffer[i], serial->bulk_out_size[i], generic_write_bulk_callback, serial);
+ }
}
#if 0 /* use this code when WhiteHEAT is up and running */
@@ -1295,7 +1298,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
usb_unlink_urb (&serial->write_urb[i]);
usb_unlink_urb (&serial->read_urb[i]);
serial->active[i] = 0;
- serial_table[serial->minor + i] = NULL;
}
/* free up any memory that we allocated */
@@ -1313,6 +1315,10 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i);
}
+ /* return the minor range that this device had */
+ return_serial (serial);
+
+ /* free up any memory that we allocated */
kfree (serial);
} else {
@@ -1403,5 +1409,7 @@ void cleanup_module(void)
usb_deregister(&usb_serial_driver);
}
+#else
+__initcall(usb_serial_init);
#endif
diff --git a/drivers/usb/usb-serial.h b/drivers/usb/usb-serial.h
index 5a35b94b4..6d8e978b5 100644
--- a/drivers/usb/usb-serial.h
+++ b/drivers/usb/usb-serial.h
@@ -35,17 +35,13 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
/* USB Serial devices vendor ids and device ids that this driver supports */
-#define BELKIN_VENDOR_ID 0x056c
-#define BELKIN_SERIAL_CONVERTER_ID 0x8007
-#define PERACOM_VENDOR_ID 0x0565
-#define PERACOM_SERIAL_CONVERTER_ID 0x0001
#define CONNECT_TECH_VENDOR_ID 0x0710
#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
#define CONNECT_TECH_WHITE_HEAT_ID 0x8001
#define HANDSPRING_VENDOR_ID 0x082d
#define HANDSPRING_VISOR_ID 0x0100
#define FTDI_VENDOR_ID 0x0403
-#define FTDI_SERIAL_CONVERTER_ID 0x8372
+#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372
#define KEYSPAN_VENDOR_ID 0x06cd
#define KEYSPAN_PDA_FAKE_ID 0x0103
#define KEYSPAN_PDA_ID 0x0103
@@ -125,6 +121,8 @@ struct usb_serial_device_type {
int (*chars_in_buffer)(struct tty_struct *tty);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
+ void (*read_bulk_callback)(struct urb *urb);
+ void (*write_bulk_callback)(struct urb *urb);
};
@@ -135,6 +133,9 @@ static void generic_serial_close (struct tty_struct *tty, struct file *filp);
static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
static int generic_write_room (struct tty_struct *tty);
static int generic_chars_in_buffer (struct tty_struct *tty);
+static void generic_read_bulk_callback (struct urb *urb);
+static void generic_write_bulk_callback (struct urb *urb);
+
#ifdef CONFIG_USB_SERIAL_GENERIC
/* All of the device info needed for the Generic Serial Converter */
@@ -154,59 +155,8 @@ static struct usb_serial_device_type generic_device = {
write: generic_serial_write,
write_room: generic_write_room,
chars_in_buffer: generic_chars_in_buffer,
-};
-#endif
-
-#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM)
-/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */
-static int etek_serial_open (struct tty_struct *tty, struct file *filp);
-static void etek_serial_close (struct tty_struct *tty, struct file *filp);
-#endif
-
-#ifdef CONFIG_USB_SERIAL_BELKIN
-/* All of the device info needed for the Belkin Serial Converter */
-static __u16 belkin_vendor_id = BELKIN_VENDOR_ID;
-static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER_ID;
-static struct usb_serial_device_type belkin_device = {
- name: "Belkin",
- idVendor: &belkin_vendor_id, /* the Belkin vendor id */
- idProduct: &belkin_product_id, /* the Belkin serial converter product id */
- needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */
- needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
- needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
- num_interrupt_in: 1,
- num_bulk_in: 1,
- num_bulk_out: 1,
- num_ports: 1,
- open: etek_serial_open,
- close: etek_serial_close,
- write: generic_serial_write,
- write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer,
-};
-#endif
-
-
-#ifdef CONFIG_USB_SERIAL_PERACOM
-/* All of the device info needed for the Peracom Serial Converter */
-static __u16 peracom_vendor_id = PERACOM_VENDOR_ID;
-static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER_ID;
-static struct usb_serial_device_type peracom_device = {
- name: "Peracom",
- idVendor: &peracom_vendor_id, /* the Peracom vendor id */
- idProduct: &peracom_product_id, /* the Peracom serial converter product id */
- needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */
- needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
- needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
- num_ports: 1,
- num_interrupt_in: 1,
- num_bulk_in: 1,
- num_bulk_out: 1,
- open: etek_serial_open,
- close: etek_serial_close,
- write: generic_serial_write,
- write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer,
+ read_bulk_callback: generic_read_bulk_callback,
+ write_bulk_callback: generic_write_bulk_callback
};
#endif
@@ -338,23 +288,25 @@ static struct usb_serial_device_type handspring_device = {
chars_in_buffer: generic_chars_in_buffer,
throttle: visor_throttle,
unthrottle: visor_unthrottle,
- startup: visor_startup
+ startup: visor_startup,
+ read_bulk_callback: generic_read_bulk_callback,
+ write_bulk_callback: generic_write_bulk_callback
};
#endif
-#ifdef CONFIG_USB_SERIAL_FTDI
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
/* function prototypes for a FTDI serial converter */
-static int ftdi_serial_open (struct tty_struct *tty, struct file *filp);
-static void ftdi_serial_close (struct tty_struct *tty, struct file *filp);
+static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp);
+static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp);
/* All of the device info needed for the Handspring Visor */
-static __u16 ftdi_vendor_id = FTDI_VENDOR_ID;
-static __u16 ftdi_product_id = FTDI_SERIAL_CONVERTER_ID;
-static struct usb_serial_device_type ftdi_device = {
- name: "FTDI",
+static __u16 ftdi_vendor_id = FTDI_VENDOR_ID;
+static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID;
+static struct usb_serial_device_type ftdi_sio_device = {
+ name: "FTDI SIO",
idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */
- idProduct: &ftdi_product_id, /* the FTDI product id */
+ idProduct: &ftdi_sio_product_id, /* the FTDI SIO product id */
needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */
needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
@@ -362,11 +314,13 @@ static struct usb_serial_device_type ftdi_device = {
num_bulk_in: 1,
num_bulk_out: 1,
num_ports: 1,
- open: ftdi_serial_open,
- close: ftdi_serial_close,
+ open: ftdi_sio_serial_open,
+ close: ftdi_sio_serial_close,
write: generic_serial_write,
write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer
+ chars_in_buffer: generic_chars_in_buffer,
+ read_bulk_callback: generic_read_bulk_callback,
+ write_bulk_callback: generic_write_bulk_callback
};
#endif
@@ -408,7 +362,9 @@ static struct usb_serial_device_type keyspan_pda_device = {
close: keyspan_pda_serial_close,
write: generic_serial_write,
write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer
+ chars_in_buffer: generic_chars_in_buffer,
+ read_bulk_callback: generic_read_bulk_callback,
+ write_bulk_callback: generic_write_bulk_callback
};
#endif
@@ -423,17 +379,11 @@ static struct usb_serial_device_type *usb_serial_devices[] = {
&whiteheat_fake_device,
&whiteheat_device,
#endif
-#ifdef CONFIG_USB_SERIAL_BELKIN
- &belkin_device,
-#endif
-#ifdef CONFIG_USB_SERIAL_PERACOM
- &peracom_device,
-#endif
#ifdef CONFIG_USB_SERIAL_VISOR
&handspring_device,
#endif
-#ifdef CONFIG_USB_SERIAL_FTDI
- &ftdi_device,
+#ifdef CONFIG_USB_SERIAL_FTDI_SIO
+ &ftdi_sio_device,
#endif
#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
&keyspan_pda_fake_device,
diff --git a/drivers/usb/usb_storage_debug.c b/drivers/usb/usb-storage-debug.h
index cff8f9a61..8994c06ba 100644
--- a/drivers/usb/usb_storage_debug.c
+++ b/drivers/usb/usb-storage-debug.h
@@ -1,29 +1,11 @@
+#ifdef CONFIG_USB_STORAGE_DEBUG
-/* Driver for USB mass storage (scsi-like) devices
+/* Debug output for Driver for USB mass storage (scsi-like) devices
*
* (C) Michael Gee (michael@linuxspecific.com) 1999
*
*/
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-#include <linux/spinlock.h>
-
-#include <linux/blk.h>
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
-
-#include "usb.h"
-#include "usb_storage.h"
-
void us_show_command(Scsi_Cmnd *srb)
{
char *what = NULL;
@@ -102,3 +84,5 @@ void us_show_command(Scsi_Cmnd *srb)
srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5],
srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
}
+
+#endif
diff --git a/drivers/usb/usb_storage.c b/drivers/usb/usb-storage.c
index 0ebb1e413..dd340589f 100644
--- a/drivers/usb/usb_storage.c
+++ b/drivers/usb/usb-storage.c
@@ -37,7 +37,17 @@
#include "../scsi/sd.h"
#include "usb.h"
-#include "usb_storage.h"
+#include "usb-storage.h"
+#include "usb-storage-debug.h"
+
+
+/*
+ * This is the size of the structure Scsi_Host_Template. We create
+ * an instance of this structure in this file and this is a check
+ * to see if this structure may have changed within the SCSI module.
+ * This is by no means foolproof, but it does help us some.
+ */
+#define SCSI_HOST_TEMPLATE_SIZE (104)
/* direction table -- this indicates the direction of the data
* transfer for each command code -- a 1 indicates input
@@ -884,7 +894,7 @@ static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
static int pop_CB_status(Scsi_Cmnd *srb)
{
struct us_data *us = (struct us_data *)srb->host_scribble;
- int result;
+ int result = 0;
__u8 status[2];
int retry = 5;
@@ -1013,7 +1023,7 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
bcb.Flags, bcb.Length);
result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
US_BULK_CB_WRAP_LEN, &partial, HZ*5);
- US_DEBUGP("Bulk command transfer result 0x%x\n", result);
+ US_DEBUGP("Bulk command transfer result=%d\n", result);
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
@@ -1327,6 +1337,7 @@ static Scsi_Host_Template my_host_template = {
NULL, /* reset */
NULL, /* slave_attach */
NULL, /* bios_param */
+ NULL, /* select_queue_depths */
1, /* can_queue */
-1, /* this_id */
SG_ALL, /* sg_tablesize */
@@ -1811,10 +1822,18 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
* Initialization and registration
***********************************************************************/
-int usb_stor_init(void)
+int __init usb_stor_init(void)
{
// MOD_INC_USE_COUNT;
+ if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
+ printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ;
+ printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n",
+ SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
+
+ return -1 ;
+ }
+
/* register the driver, return -1 if error */
if (usb_register(&storage_driver) < 0)
return -1;
@@ -1823,15 +1842,10 @@ int usb_stor_init(void)
return 0;
}
-#ifdef MODULE
-int init_module(void)
+void __exit usb_stor_exit(void)
{
- /* MDD: Perhaps we should register the host here */
- return usb_stor_init();
+ usb_deregister(&storage_driver) ;
}
-void cleanup_module(void)
-{
- usb_deregister(&storage_driver);
-}
-#endif
+module_init(usb_stor_init) ;
+module_exit(usb_stor_exit) ;
diff --git a/drivers/usb/usb_storage.h b/drivers/usb/usb-storage.h
index 80a03f3c9..80a03f3c9 100644
--- a/drivers/usb/usb_storage.h
+++ b/drivers/usb/usb-storage.h
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index b79f9cc31..1b72efd92 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -12,9 +12,10 @@
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: usb-uhci.c,v 1.185 2000/02/05 21:29:19 acher Exp $
+ * $Id: usb-uhci.c,v 1.197 2000/02/15 17:44:22 acher Exp $
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -54,7 +55,6 @@
#define dbg(format, arg...) do {} while (0)
#include <linux/pm.h>
-static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
#ifdef DEBUG_SYMBOLS
#define _static
@@ -70,9 +70,18 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
static kmem_cache_t *urb_priv_kmem;
#endif
-#define USE_CTRL_DEPTH_FIRST 1 // 0: Breadth first, 1: Depth first (standard)
+#define USE_CTRL_DEPTH_FIRST 0 // 0: Breadth first, 1: Depth first
+#define USE_BULK_DEPTH_FIRST 0 // 0: Breadth first, 1: Depth first
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+#define USE_RECLAMATION_LOOP
+#else
//#define USE_RECLAMATION_LOOP
+#endif
+
+// stop bandwidth reclamation after (roughly) 50ms (depends also on
+// hub polling interval)
+#define IDLE_TIMEOUT (HZ/20)
_static int rh_submit_urb (urb_t *urb);
_static int rh_unlink_urb (urb_t *urb);
@@ -101,22 +110,81 @@ void clean_descs(uhci_t *s, int force)
}
}
/*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, struct list_head *p)
+#ifdef USE_RECLAMATION_LOOP
+_static void enable_desc_loop(uhci_t *s, urb_t *urb)
+{
+ int flags;
+
+ dbg("enable_desc_loop: enter");
+
+ spin_lock_irqsave (&s->qh_lock, flags);
+ s->chain_end->hw.qh.head=virt_to_bus(s->control_chain)|UHCI_PTR_QH;
+ s->loop_usage++;
+ ((urb_priv_t*)urb->hcpriv)->use_loop=1;
+ spin_unlock_irqrestore (&s->qh_lock, flags);
+
+ dbg("enable_desc_loop: finished");
+}
+/*-------------------------------------------------------------------*/
+_static void disable_desc_loop(uhci_t *s, urb_t *urb)
+{
+ int flags;
+
+ dbg("disable_desc_loop: enter\n");
+
+ spin_lock_irqsave (&s->qh_lock, flags);
+
+ if (((urb_priv_t*)urb->hcpriv)->use_loop) {
+ s->loop_usage--;
+
+ if (!s->loop_usage)
+ s->chain_end->hw.qh.head=UHCI_PTR_TERM;
+
+ ((urb_priv_t*)urb->hcpriv)->use_loop=0;
+ }
+ spin_unlock_irqrestore (&s->qh_lock, flags);
+
+ dbg("disable_desc_loop: finished");
+
+}
+#endif
+/*-------------------------------------------------------------------*/
+_static void queue_urb (uhci_t *s, urb_t *urb)
{
unsigned long flags=0;
+ struct list_head *p=&urb->urb_list;
+
spin_lock_irqsave (&s->urb_list_lock, flags);
+#ifdef USE_RECLAMATION_LOOP
+ {
+ int type;
+ type=usb_pipetype (urb->pipe);
+
+ if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+ enable_desc_loop(s, urb);
+ }
+#endif
+ ((urb_priv_t*)urb->hcpriv)->started=jiffies;
list_add_tail (p, &s->urb_list);
spin_unlock_irqrestore (&s->urb_list_lock, flags);
}
/*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, struct list_head *p)
+_static void dequeue_urb (uhci_t *s, urb_t *urb)
{
- list_del (p);
+#ifdef USE_RECLAMATION_LOOP
+ int type;
+
+ type=usb_pipetype (urb->pipe);
+
+ if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+ disable_desc_loop(s, urb);
+#endif
+ list_del (&urb->urb_list);
}
/*-------------------------------------------------------------------*/
_static int alloc_td (uhci_desc_t ** new, int flags)
@@ -219,6 +287,7 @@ _static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink)
return 0;
}
+
/*-------------------------------------------------------------------*/
_static int delete_desc (uhci_desc_t *element)
{
@@ -451,11 +520,6 @@ _static int init_skel (uhci_t *s)
insert_qh (s, s->bulk_chain, qh, 0);
s->control_chain = qh;
-#ifdef USE_RECLAMATION_LOOP
- s->chain_end->hw.qh.head=virt_to_bus(s->control_chain)|UHCI_PTR_QH;
- info("Using loop for bandwidth reclamation.");
-#endif
-
for (n = 0; n < 8; n++)
s->int_chain[n] = 0;
@@ -625,7 +689,7 @@ _static int uhci_submit_control_urb (urb_t *urb)
list_add (&qh->desc_list, &urb_priv->desc_list);
urb->status = -EINPROGRESS;
- queue_urb (s, &urb->urb_list); // queue before inserting in desc chain
+ queue_urb (s, urb); // queue before inserting in desc chain
qh->hw.qh.element&=~UHCI_PTR_TERM;
@@ -635,8 +699,8 @@ _static int uhci_submit_control_urb (urb_t *urb)
insert_qh (s, s->control_chain, qh, 1); // insert after control chain
else
insert_qh (s, s->bulk_chain, qh, 0); // insert before bulk chain
-
//uhci_show_queue(qh);
+
dbg("uhci_submit_control end");
return 0;
}
@@ -651,11 +715,12 @@ _static int uhci_submit_bulk_urb (urb_t *urb)
unsigned int pipe = urb->pipe;
int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
int info, len;
+ int depth_first=USE_BULK_DEPTH_FIRST; // UHCI descriptor chasing method
- /* shouldn't the clear_halt be done in the USB core or in the client driver? - Thomas */
- if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) &&
- usb_clear_halt (urb->dev, usb_pipeendpoint (pipe) | (pipe & USB_DIR_IN)))
+
+ if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
return -EPIPE;
+
if (urb->transfer_buffer_length < 0) {
err("Negative transfer length in submit_bulk");
return -EINVAL;
@@ -685,7 +750,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb)
do { // TBD: Really allow zero-length packets?
int pktsze = len;
- alloc_td (&td, UHCI_PTR_DEPTH);
+ alloc_td (&td, UHCI_PTR_DEPTH * depth_first);
if (!td) {
delete_qh (s, qh);
@@ -708,7 +773,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb)
td->hw.td.status |= TD_CTRL_IOC; // last one generates INT
//dbg("insert td %p, len %i",td,pktsze);
- insert_td (s, qh, td, UHCI_PTR_DEPTH);
+ insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
/* Alternate Data0/1 (start with Data0) */
usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
@@ -717,7 +782,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb)
list_add (&qh->desc_list, &urb_priv->desc_list);
urb->status = -EINPROGRESS;
- queue_urb (s, &urb->urb_list);
+ queue_urb (s, urb);
qh->hw.qh.element&=~UHCI_PTR_TERM;
@@ -727,6 +792,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb)
dbg("uhci_submit_bulk_urb: exit");
return 0;
}
+
/*-------------------------------------------------------------------*/
// unlinks an urb by dequeuing its qh, waits some frames and forgets it
// Problem: unlinking in interrupt requires waiting for one frame (udelay)
@@ -758,7 +824,7 @@ _static int uhci_unlink_urb (urb_t *urb)
if (urb->status == -EINPROGRESS) {
// URB probably still in work
- dequeue_urb (s, &urb->urb_list);
+ dequeue_urb (s, urb);
s->unlink_urb_done=1;
spin_unlock_irqrestore (&s->urb_list_lock, flags);
@@ -773,7 +839,7 @@ _static int uhci_unlink_urb (urb_t *urb)
unlink_td (s, td, 1);
}
// wait at least 1 Frame
- uhci_wait_ms(1);
+ uhci_wait_ms(1);
while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
td = list_entry (p, uhci_desc_t, desc_list);
list_del (p);
@@ -991,7 +1057,7 @@ _static int uhci_submit_int_urb (urb_t *urb)
list_add_tail (&td->desc_list, &urb_priv->desc_list);
urb->status = -EINPROGRESS;
- queue_urb (s, &urb->urb_list);
+ queue_urb (s, urb);
insert_td_horizontal (s, s->int_chain[nint], td); // store in INT-TDs
@@ -1083,7 +1149,7 @@ _static int uhci_submit_iso_urb (urb_t *urb)
if (n == last) {
urb->status = -EINPROGRESS;
- queue_urb (s, &urb->urb_list);
+ queue_urb (s, urb);
}
insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td); // store in iso-tds
//uhci_show_td(td);
@@ -1194,14 +1260,44 @@ _static int uhci_submit_urb (urb_t *urb)
#endif
return ret;
}
-/*
- urb->status = -EINPROGRESS;
- queue_urb (s, &urb->urb_list);
- dbg("submit_urb: exit");
-*/
return 0;
}
+#ifdef USE_RECLAMATION_LOOP
+// Removes bandwidth reclamation if URB idles too long
+void check_idling_urbs(uhci_t *s)
+{
+ struct list_head *p,*p2;
+ urb_t *urb;
+ int type;
+
+ //dbg("check_idling_urbs: enter i:%d",in_interrupt());
+
+ spin_lock (&s->urb_list_lock);
+ p = s->urb_list.prev;
+
+ while (p != &s->urb_list) {
+ p2 = p;
+ p = p->prev;
+ urb=list_entry (p2, urb_t, urb_list);
+ type=usb_pipetype (urb->pipe);
+
+#if 0
+ err("URB timers: %li now: %li %i\n",
+ ((urb_priv_t*)urb->hcpriv)->started +IDLE_TIMEOUT, jiffies,
+ type);
+#endif
+ if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&
+ (((urb_priv_t*)urb->hcpriv)->use_loop) &&
+ ((((urb_priv_t*)urb->hcpriv)->started +IDLE_TIMEOUT) < jiffies))
+ disable_desc_loop(s,urb);
+
+ }
+ spin_unlock (&s->urb_list_lock);
+
+ //dbg("check_idling_urbs: finished");
+}
+#endif
/*-------------------------------------------------------------------
Virtual Root Hub
-------------------------------------------------------------------*/
@@ -1313,10 +1409,13 @@ _static int rh_init_int_timer (urb_t *urb);
_static void rh_int_timer_do (unsigned long ptr)
{
int len;
-
urb_t *urb = (urb_t*) ptr;
uhci_t *uhci = urb->dev->bus->hcpriv;
+#ifdef USE_RECLAMATION_LOOP
+ check_idling_urbs(uhci);
+#endif
+
if (uhci->rh.send) {
len = rh_send_irq (urb);
if (len > 0) {
@@ -1558,9 +1657,11 @@ _static int rh_unlink_urb (urb_t *urb)
{
uhci_t *uhci = urb->dev->bus->hcpriv;
- dbg("Root-Hub unlink IRQ");
- uhci->rh.send = 0;
- del_timer (&uhci->rh.rh_int_timer);
+ if (uhci->rh.urb==urb) {
+ dbg("Root-Hub unlink IRQ");
+ uhci->rh.send = 0;
+ del_timer (&uhci->rh.rh_int_timer);
+ }
return 0;
}
/*-------------------------------------------------------------------*/
@@ -1741,7 +1842,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb)
// got less data than requested
if ( (actual_length < maxlength)) {
if (urb->transfer_flags & USB_DISABLE_SPD) {
- ret = -EREMOTEIO; // treat as real error
+ status = -EREMOTEIO; // treat as real error
dbg("process_transfer: SPD!!");
break; // exit after this TD because SP was detected
}
@@ -1777,6 +1878,10 @@ _static int process_transfer (uhci_t *s, urb_t *urb)
urb->status = status;
+#ifdef USE_RECLAMATION_LOOP
+ disable_desc_loop(s,urb);
+#endif
+
dbg("process_transfer: urb %p, wanted len %d, len %d status %x err %d",
urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
//dbg("process_transfer: exit");
@@ -1971,7 +2076,7 @@ _static int process_urb (uhci_t *s, struct list_head *p)
int proceed = 0;
dbg("dequeued urb: %p", urb);
- dequeue_urb (s, p);
+ dequeue_urb (s, urb);
#ifdef DEBUG_SLAB
kmem_cache_free(urb_priv_kmem, urb->hcpriv);
@@ -2181,6 +2286,23 @@ _static int __init uhci_start_usb (uhci_t *s)
return 0;
}
+_static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ uhci_t *s = (uhci_t*) dev->data;
+ dbg("handle_apm_event(%d)", rqst);
+ if (s) {
+ switch (rqst) {
+ case PM_SUSPEND:
+ reset_hc (s);
+ break;
+ case PM_RESUME:
+ start_hc (s);
+ break;
+ }
+ }
+ return 0;
+}
+
_static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
{
uhci_t *s;
@@ -2236,7 +2358,7 @@ _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_add
}
s->rh.numports = s->maxports;
-
+ s->loop_usage=0;
if (init_skel (s)) {
usb_free_bus (bus);
kfree(s);
@@ -2306,23 +2428,6 @@ _static int __init start_uhci (struct pci_dev *dev)
return -1;
}
-_static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- uhci_t *s = (uhci_t*) dev->data;
- dbg("handle_apm_event(%d)", rqst);
- if (s) {
- switch (rqst) {
- case PM_SUSPEND:
- reset_hc (s);
- break;
- case PM_RESUME:
- start_hc (s);
- break;
- }
- }
- return 0;
-}
-
int __init uhci_init (void)
{
int retval = -ENODEV;
@@ -2385,11 +2490,9 @@ void __exit uhci_cleanup (void)
uhci_cleanup_dev(s);
}
#ifdef DEBUG_SLAB
-
-
if(kmem_cache_destroy(uhci_desc_kmem))
err("uhci_desc_kmem remained");
-
+
if(kmem_cache_destroy(urb_priv_kmem))
err("urb_priv_kmem remained");
#endif
diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h
index fcb96c3e0..e74e23bd8 100644
--- a/drivers/usb/usb-uhci.h
+++ b/drivers/usb/usb-uhci.h
@@ -2,7 +2,7 @@
#define __LINUX_UHCI_H
/*
- $Id: usb-uhci.h,v 1.39 2000/02/05 20:25:27 acher Exp $
+ $Id: usb-uhci.h,v 1.41 2000/02/13 21:37:38 acher Exp $
*/
#define MODNAME "usb-uhci"
#define VERSTR "version v1.184 time " __TIME__ " " __DATE__
@@ -155,6 +155,8 @@ typedef struct {
typedef struct {
struct list_head desc_list; // list pointer to all corresponding TDs/QHs associated with this request
int short_control_packet;
+ unsigned long started;
+ int use_loop;
} urb_priv_t, *purb_priv_t;
struct virt_root_hub {
@@ -197,6 +199,7 @@ typedef struct uhci {
spinlock_t qh_lock;
spinlock_t td_lock;
struct virt_root_hub rh; //private data of the virtual root hub
+ int loop_usage; // URBs using bandwidth reclamation
} uhci_t, *puhci_t;
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 4377e3325..ebd64b6c5 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -588,7 +588,7 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
}
/*-------------------------------------------------------------------*/
-// returns status (negative) are length (positive)
+// returns status (negative) or length (positive)
int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
devrequest *cmd, void *data, int len, int timeout)
{
@@ -1625,7 +1625,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
err = usb_get_string(dev, dev->string_langid, index, tbuf, 255);
if (err < 0)
goto errout;
- info("actual string desc. length = %d", err);
size--; /* leave room for trailing NULL char in output buffer */
for (idx = 0, u = 2; u < err; u += 2) {
@@ -1729,6 +1728,8 @@ int usb_new_device(struct usb_device *dev)
return -1;
}
+ info("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
+ dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
if (dev->descriptor.iManufacturer)
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
if (dev->descriptor.iProduct)
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 2ccc8d4be..b7a855b77 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -73,6 +73,8 @@ if [ "$CONFIG_FB" = "y" ]; then
fi
if [ "$CONFIG_MAC" = "y" ]; then
define_bool CONFIG_FB_MAC y
+ bool ' Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
+# bool ' Apple DAFB display support' CONFIG_FB_DAFB
fi
if [ "$CONFIG_HP300" = "y" ]; then
define_bool CONFIG_FB_HP300 y
@@ -89,6 +91,13 @@ if [ "$CONFIG_FB" = "y" ]; then
tristate ' SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
define_bool CONFIG_BUS_I2C y
fi
+ if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
+ bool 'Sun3 framebuffer support' CONFIG_FB_SUN3
+ if [ "$CONFIG_FB_SUN3" != "n" ]; then
+ bool ' BWtwo support' CONFIG_FB_BWTWO
+ bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+ fi
+ fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_PCI" != "n" ]; then
tristate ' Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 3e31a5fdc..e52eee833 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -60,7 +60,7 @@ obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_SGIVW) += sgivwfb.o
obj-$(CONFIG_FB_RIVA) += rivafb.o riva_hw.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
-obj-$(CONFIG_FB_MAC) += macfb.o
+obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o
obj-$(CONFIG_FB_HP300) += hpfb.o
obj-$(CONFIG_FB_OF) += offb.o macmodes.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
@@ -82,6 +82,8 @@ obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
obj-$(CONFIG_FB_MATROX) += matroxfb.o
+obj-$(CONFIG_FB_SUN3) += sun3fb.o
+obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
# Generic Low Level Drivers
diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c
index e9a1886a1..da084b045 100644
--- a/drivers/video/aty128fb.c
+++ b/drivers/video/aty128fb.c
@@ -29,7 +29,7 @@
/*
* A special note of gratitude to ATI's devrel for providing documentation,
- * example code and hardware. Thanks Nitya. -atong
+ * example code and hardware. Thanks Nitya. -atong and brad
*/
@@ -129,6 +129,8 @@ static const struct aty128_chip_info aty128_pci_probe_list[] =
{"PCI_DEVICE_ID_ATI_RAGE128_RF", PCI_VENDOR_ID_ATI, 0x5246},
{"PCI_DEVICE_ID_ATI_RAGE128_RK", PCI_VENDOR_ID_ATI, 0x524b},
{"PCI_DEVICE_ID_ATI_RAGE128_RL", PCI_VENDOR_ID_ATI, 0x524c},
+ {"PCI_DEVICE_ID_ATI_RAGE128_PF", PCI_VENDOR_ID_ATI, 0x5046},
+ {"PCI_DEVICE_ID_ATI_RAGE128_PR", PCI_VENDOR_ID_ATI, 0x5052},
{NULL, 0, 0}
};
@@ -1669,22 +1671,23 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
var = default_var;
#else
memset(&var, 0, sizeof(var));
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
if (default_vmode == VMODE_CHOOSE) {
var = default_var;
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_PPC */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
- if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
- &defaultmode, 8))
- var = default_var;
+ if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
+ &defaultmode, 8))
+ var = default_var;
#endif
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
} else {
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
-#endif /* CONFIG_PMAC */
+ }
+#endif /* CONFIG_PPC */
#endif /* MODULE */
if (noaccel)
@@ -2294,19 +2297,6 @@ do_install_cmap(int con, struct fb_info *info)
*/
static void
-aty128_rectdraw(s16 x, s16 y, u16 width, u16 height,
- struct fb_info_aty128 *info)
-{
- /* perform rectangle operation */
- wait_for_fifo(2, info);
- aty_st_le32(DST_Y_X, (y << 16) | x);
- aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
-
- info->blitter_may_be_busy = 1;
-}
-
-
-static void
aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
u_int width, u_int height,
struct fb_info_aty128 *info)
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index 3bec2e851..57ae6e15e 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -1,4 +1,4 @@
-/* $Id: atyfb.c,v 1.138 2000/02/10 02:52:12 davem Exp $
+/* $Id: atyfb.c,v 1.139 2000/02/12 22:47:04 davem Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
@@ -4049,7 +4049,7 @@ int __init atyfb_setup(char *options)
default_pll = simple_strtoul(this_opt+4, NULL, 0);
else if (!strncmp(this_opt, "mclk:", 5))
default_mclk = simple_strtoul(this_opt+5, NULL, 0);
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
@@ -4186,7 +4186,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
struct fb_info_aty *info = (struct fb_info_aty *)fb;
u8 gen_cntl;
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
if ((_machine == _MACH_Pmac) && blank)
pmu_enable_backlight(0);
#endif
@@ -4211,7 +4211,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
gen_cntl &= ~(0x4c);
aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_PPC
if ((_machine == _MACH_Pmac) && !blank)
pmu_enable_backlight(1);
#endif
diff --git a/drivers/video/bwtwofb.c b/drivers/video/bwtwofb.c
index f8c0ea52d..ebb5d5e56 100644
--- a/drivers/video/bwtwofb.c
+++ b/drivers/video/bwtwofb.c
@@ -1,4 +1,4 @@
-/* $Id: bwtwofb.c,v 1.12 2000/01/21 03:57:05 anton Exp $
+/* $Id: bwtwofb.c,v 1.13 2000/02/14 02:50:25 davem Exp $
* bwtwofb.c: BWtwo frame buffer driver
*
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -25,7 +25,7 @@
#include <video/sbusfb.h>
#include <asm/io.h>
-#ifndef __sparc_v9__
+#if !defined(__sparc_v9__) && !defined(__mc68000__)
#include <asm/sun4paddr.h>
#endif
@@ -214,9 +214,11 @@ char __init *bwtwofb_init(struct fb_info_sbusfb *fb)
case BWTWO_SR_ID_NOCONN:
return NULL;
default:
+#ifndef CONFIG_FB_SUN3
prom_printf("bw2: can't handle SR %02x\n",
status);
prom_halt();
+#endif
return NULL; /* fool gcc. */
}
for ( ; *p; p += 2) {
diff --git a/drivers/video/cgsixfb.c b/drivers/video/cgsixfb.c
index f9a78e531..2fd457eb6 100644
--- a/drivers/video/cgsixfb.c
+++ b/drivers/video/cgsixfb.c
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.21 1999/11/19 09:56:57 davem Exp $
+/* $Id: cgsixfb.c,v 1.22 2000/02/14 08:44:26 jj Exp $
* cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
*
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -491,7 +491,7 @@ static void cg6_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int inde
int i;
spin_lock_irqsave(&fb->lock, flags);
- bt->addr = index << 24;
+ sbus_writel(index << 24, &bt->addr);
for (i = index; count--; i++){
sbus_writel(fb->color_map CM(i,0) << 24,
&bt->color_map);
diff --git a/drivers/video/fbcon-mac.c b/drivers/video/fbcon-mac.c
index 77adb6395..0b3e816e7 100644
--- a/drivers/video/fbcon-mac.c
+++ b/drivers/video/fbcon-mac.c
@@ -331,7 +331,8 @@ static void plot_pixel_mac(struct display *p, int bw, int pixel_x, int pixel_y)
u16 *dest16, pix16;
u32 *dest32, pix32;
- if (pixel_x < 0 || pixel_y < 0 || pixel_x >= 832 || pixel_y >= 624) {
+ /* There *are* 68k Macs that support more than 832x624, you know :-) */
+ if (pixel_x < 0 || pixel_y < 0 || pixel_x >= p->var.xres || pixel_y >= p->var.yres) {
int cnt;
printk ("ERROR: pixel_x == %d, pixel_y == %d", pixel_x, pixel_y);
for(cnt = 0; cnt < 100000; cnt++)
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 796904292..717cc94f0 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -25,6 +25,7 @@
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
+#include <linux/devfs_fs_kernel.h>
#if defined(__mc68000__) || defined(CONFIG_APUS)
#include <asm/setup.h>
@@ -98,6 +99,8 @@ extern int g364fb_init(void);
extern int fm2fb_init(void);
extern int fm2fb_setup(char*);
extern int q40fb_init(void);
+extern int sun3fb_init(void);
+extern int sun3fb_setup(char *);
extern int sgivwfb_init(void);
extern int sgivwfb_setup(char*);
extern int rivafb_init(void);
@@ -211,6 +214,9 @@ static struct {
#ifdef CONFIG_FB_FM2
{ "fm2fb", fm2fb_init, fm2fb_setup },
#endif
+#ifdef CONFIG_FB_SUN3
+ { "sun3", sun3fb_init, sun3fb_setup },
+#endif
#ifdef CONFIG_GSP_RESOLVER
/* Not a real frame buffer device... */
{ "resolver", NULL, resolver_video_setup },
@@ -471,6 +477,9 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
vma->vm_flags |= VM_IO;
#else
#if defined(__mc68000__)
+#if defined(CONFIG_SUN3)
+ pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
+#else
if (CPU_IS_020_OR_030)
pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
if (CPU_IS_040_OR_060) {
@@ -478,6 +487,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
/* Use no-cache mode, serialized */
pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
}
+#endif
#elif defined(__powerpc__)
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
#elif defined(__alpha__)
@@ -558,10 +568,13 @@ static struct file_operations fb_fops = {
release: fb_release,
};
+static devfs_handle_t devfs_handle = NULL;
+
int
register_framebuffer(struct fb_info *fb_info)
{
int i, j;
+ char name_buf[8];
static int fb_ever_opened[FB_MAX];
static int first = 1;
@@ -588,12 +601,17 @@ register_framebuffer(struct fb_info *fb_info)
first = 0;
take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
}
+ sprintf (name_buf, "%d", i);
+ fb_info->devfs_handle =
+ devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE,
+ FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ &fb_fops, NULL);
return 0;
}
int
-unregister_framebuffer(const struct fb_info *fb_info)
+unregister_framebuffer(struct fb_info *fb_info)
{
int i, j;
@@ -602,7 +620,11 @@ unregister_framebuffer(const struct fb_info *fb_info)
if (con2fb_map[j] == i)
return -EBUSY;
if (!registered_fb[i])
- return -EINVAL;
+ return -EINVAL;
+ devfs_unregister (fb_info->devfs_handle);
+ fb_info->devfs_handle = NULL;
+ devfs_unregister (fb_info->devfs_lhandle);
+ fb_info->devfs_lhandle = NULL;
registered_fb[i]=NULL;
num_registered_fb--;
return 0;
@@ -615,7 +637,8 @@ fbmem_init(void)
create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL);
- if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
+ devfs_handle = devfs_mk_dir (NULL, "fb", 0, NULL);
+ if (devfs_register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
/*
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index e871b6a0c..d462fb621 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -657,7 +657,7 @@ int __init igafb_init(void)
memset(info, 0, sizeof(struct fb_info_iga));
if ((addr = pdev->resource[0].start) == 0) {
- printk("igafb_init: no memory start\n", addr);
+ printk("igafb_init: no memory start\n");
kfree(info);
return -ENXIO;
}
@@ -697,7 +697,7 @@ int __init igafb_init(void)
}
if ((info->io_base = (int) ioremap(info->io_base_phys, 0x1000)) == 0) {
printk("igafb_init: can't remap %lx[4K]\n", info->io_base_phys);
- iounmap(info->frame_buffer);
+ iounmap((void *)info->frame_buffer);
kfree(info);
return -ENXIO;
}
@@ -713,7 +713,7 @@ int __init igafb_init(void)
info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
if (!info->mmap_map) {
printk("igafb_init: can't alloc mmap_map\n");
- iounmap(info->io_base);
+ iounmap((void *)info->io_base);
iounmap(info->frame_buffer);
kfree(info);
return -ENOMEM;
@@ -768,7 +768,7 @@ int __init igafb_init(void)
#endif
if (!iga_init(info)) {
- iounmap(info->io_base);
+ iounmap((void *)info->io_base);
iounmap(info->frame_buffer);
if (info->mmap_map)
kfree(info->mmap_map);
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index 282c47739..37a44ea5a 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -1,6 +1,22 @@
-/*
- * We've been given MAC frame buffer info by the booter. Now go set it up
- */
+/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
+ don't know how to set */
+
+/* (c) 1999 David Huggins-Daines <dhd@debian.org>
+
+ Primarily based on vesafb.c, by Gerd Knorr
+ (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+
+ Also uses information and code from:
+
+ The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
+ Mellinger, Mikael Forselius, Michael Schmitz, and others.
+
+ valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
+ Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
+
+ This code is free software. You may copy, modify, and distribute
+ it subject to the terms and conditions of the GNU General Public
+ License, version 2, or any later version, at your convenience. */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -13,6 +29,7 @@
#include <linux/delay.h>
#include <linux/nubus.h>
#include <linux/init.h>
+#include <linux/fb.h>
#include <asm/setup.h>
#include <asm/bootinfo.h>
@@ -20,16 +37,137 @@
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/macintosh.h>
-#include <linux/fb.h>
+#include <asm/io.h>
+#include <asm/machw.h>
#include <video/fbcon.h>
-/* conditionalize these ?? */
#include <video/fbcon-mfb.h>
#include <video/fbcon-cfb2.h>
#include <video/fbcon-cfb4.h>
#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)
+
+/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
+#define DAC_BASE 0x50f24000
+
+/* Some addresses for the DAFB */
+#define DAFB_BASE 0xf9800200
+
+/* Address for the built-in Civic framebuffer in Quadra AVs */
+#define CIVIC_BASE 0x50f30800 /* Only tested on 660AV! */
+
+/* GSC (Gray Scale Controller) base address */
+#define GSC_BASE 0x50F20000
+
+/* CSC (Color Screen Controller) base address */
+#define CSC_BASE 0x50F20000
+
+static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue) = NULL;
+static int valkyrie_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue);
+static int dafb_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue);
+static int rbv_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue);
+static int mdc_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue);
+static int toby_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue);
+static int civic_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue);
+static int csc_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue);
+
+static volatile struct {
+ unsigned char addr;
+ /* Note: word-aligned */
+ char pad[3];
+ unsigned char lut;
+} *valkyrie_cmap_regs;
+
+static volatile struct {
+ unsigned char addr;
+ unsigned char lut;
+} *v8_brazil_cmap_regs;
+
+static volatile struct {
+ unsigned char addr;
+ char pad1[3]; /* word aligned */
+ unsigned char lut;
+ char pad2[3]; /* word aligned */
+ unsigned char cntl; /* a guess as to purpose */
+} *rbv_cmap_regs;
+
+static volatile struct {
+ unsigned long reset;
+ unsigned long pad1[3];
+ unsigned char pad2[3];
+ unsigned char lut;
+} *dafb_cmap_regs;
+
+static volatile struct {
+ unsigned char addr; /* OFFSET: 0x00 */
+ unsigned char pad1[15];
+ unsigned char lut; /* OFFSET: 0x10 */
+ unsigned char pad2[15];
+ unsigned char status; /* OFFSET: 0x20 */
+ unsigned char pad3[7];
+ unsigned long vbl_addr; /* OFFSET: 0x28 */
+ unsigned int status2; /* OFFSET: 0x2C */
+} *civic_cmap_regs;
+
+static volatile struct {
+ char pad1[0x40];
+ unsigned char clut_waddr; /* 0x40 */
+ char pad2;
+ unsigned char clut_data; /* 0x42 */
+ char pad3[0x3];
+ unsigned char clut_raddr; /* 0x46 */
+} *csc_cmap_regs;
+
+/* We will leave these the way they are for the time being */
+struct mdc_cmap_regs {
+ char pad1[0x200200];
+ unsigned char addr;
+ char pad2[6];
+ unsigned char lut;
+};
+
+struct toby_cmap_regs {
+ char pad1[0x90018];
+ unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */
+ char pad2[3];
+ unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */
+};
+
+struct jet_cmap_regs {
+ char pad1[0xe0e000];
+ unsigned char addr;
+ unsigned char lut;
+};
+
+#endif
+
+#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */
+
+static char* video_base;
+static int video_size;
+static char* video_vbase; /* mapped */
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+/* mode */
+static int video_bpp;
+static int video_width;
+static int video_height;
+static int video_type = FB_TYPE_PACKED_PIXELS;
+static int video_visual;
+static int video_linelength;
+static int video_cmap_len;
+static int video_slot = 0;
static struct fb_var_screeninfo macfb_defined={
0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/
@@ -42,38 +180,36 @@ static struct fb_var_screeninfo macfb_defined={
{0,0,0}, /* transparency */
0, /* standard pixel format */
FB_ACTIVATE_NOW,
- 274,195, /* 14" monitor *Mikael Nykvist's anyway* */
- 0, /* The only way to accelerate a mac is .. */
+ -1, -1,
+ FB_ACCEL_NONE, /* The only way to accelerate a mac is .. */
0L,0L,0L,0L,0L,
0L,0L,0, /* No sync info */
FB_VMODE_NONINTERLACED,
{0,0,0,0,0,0}
};
-#define NUM_TOTAL_MODES 1
-#define NUM_PREDEF_MODES 1
-
static struct display disp;
static struct fb_info fb_info;
+static struct { u_short blue, green, red, pad; } palette[256];
+static union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+} fbcon_cmap;
-static int inverse = 0;
-
-struct macfb_par
-{
- void *unused;
-};
-
-static int currcon = 0;
-static int current_par_valid = 0;
-struct macfb_par current_par;
-
-static int mac_xres,mac_yres,mac_depth, mac_xbytes, mac_vxres;
-static unsigned long mac_videobase;
-static unsigned long mac_videosize;
+static int inverse = 0;
+static int vidtest = 0;
+static int currcon = 0;
- /*
- * Open/Release the frame buffer device
- */
+/*
+ * Open/Release the frame buffer device
+ */
static int macfb_open(struct fb_info *info, int user)
{
@@ -90,105 +226,32 @@ static int macfb_release(struct fb_info *info, int user)
return(0);
}
-static void macfb_encode_var(struct fb_var_screeninfo *var,
- struct macfb_par *par)
-{
- memset(var, 0, sizeof(struct fb_var_screeninfo));
- var->xres=mac_xres;
- var->yres=mac_yres;
- var->xres_virtual=mac_vxres;
- var->yres_virtual=var->yres;
- var->xoffset=0;
- var->yoffset=0;
- var->bits_per_pixel = mac_depth;
- var->grayscale=0;
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
- var->nonstd=0;
- var->activate=0;
- var->height= -1;
- var->width= -1;
- var->vmode=FB_VMODE_NONINTERLACED;
- var->pixclock=0;
- var->sync=0;
- var->left_margin=0;
- var->right_margin=0;
- var->upper_margin=0;
- var->lower_margin=0;
- var->hsync_len=0;
- var->vsync_len=0;
- return;
-}
-
-
-static void macfb_get_par(struct macfb_par *par)
-{
- *par=current_par;
-}
-
-static void macfb_set_par(struct macfb_par *par)
-{
- current_par_valid=1;
-}
-
-static int fb_update_var(int con, struct fb_info *info)
+static int macfb_update_var(int con, struct fb_info *info)
{
return 0;
}
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- struct macfb_par par;
-
- macfb_get_par(&par);
- macfb_encode_var(var, &par);
- return 0;
-}
-
-extern int console_loglevel;
-
-static void macfb_encode_fix(struct fb_fix_screeninfo *fix,
- struct macfb_par *par)
-{
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id,"Macintosh");
-
- /*
- * fbmem.c accepts non page aligned mappings now!
- */
- fix->smem_start=mac_videobase;
- fix->smem_len=mac_videosize;
- fix->type = FB_TYPE_PACKED_PIXELS;
- if (mac_depth == 1)
- fix->visual = FB_VISUAL_MONO01;
- else
- fix->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
- fix->xpanstep=0;
- fix->ypanstep=0;
- fix->ywrapstep=0;
- fix->line_length=mac_xbytes;
- return;
-}
-
static int macfb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info)
{
- struct macfb_par par;
- macfb_get_par(&par);
- macfb_encode_fix(fix, &par);
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, "Mac Generic");
+
+ fix->smem_start = video_base;
+ fix->smem_len = video_size;
+ fix->type = video_type;
+ fix->visual = video_visual;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->line_length=video_linelength;
return 0;
}
static int macfb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
- struct macfb_par par;
if(con==-1)
- {
- macfb_get_par(&par);
- macfb_encode_var(var, &par);
- }
+ memcpy(var, &macfb_defined, sizeof(struct fb_var_screeninfo));
else
*var=fb_display[con].var;
return 0;
@@ -204,9 +267,10 @@ static void macfb_set_disp(int con)
else
display = &disp; /* used during initialization */
- macfb_get_fix(&fix, con, 0);
+ macfb_get_fix(&fix, con, &fb_info);
- display->screen_base = fix.smem_start;
+ memset(display, 0, sizeof(struct display));
+ display->screen_base = video_vbase;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
@@ -215,235 +279,586 @@ static void macfb_set_disp(int con)
display->line_length = fix.line_length;
display->next_line = fix.line_length;
display->can_soft_blank = 0;
- display->inverse =
- (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
+ display->inverse = inverse;
+ display->scrollmode = SCROLL_YREDRAW;
+ macfb_get_var(&display->var, -1, &fb_info);
- switch (mac_depth) {
+ switch (video_bpp) {
#ifdef FBCON_HAS_MFB
- case 1:
+ case 1:
display->dispsw = &fbcon_mfb;
break;
#endif
#ifdef FBCON_HAS_CFB2
- case 2:
+ case 2:
display->dispsw = &fbcon_cfb2;
break;
#endif
#ifdef FBCON_HAS_CFB4
- case 4:
+ case 4:
display->dispsw = &fbcon_cfb4;
break;
#endif
#ifdef FBCON_HAS_CFB8
- case 8:
+ case 8:
display->dispsw = &fbcon_cfb8;
break;
#endif
- default:
- display->dispsw = &fbcon_dummy;
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ display->dispsw_data = fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ display->dispsw = &fbcon_cfb24;
+ display->dispsw_data = fbcon_cmap.cfb24;
break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ display->dispsw = &fbcon_cfb32;
+ display->dispsw_data = fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ display->dispsw = &fbcon_dummy;
+ return;
}
}
static int macfb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
- int err;
+ static int first = 1;
+
+ if (var->xres != macfb_defined.xres ||
+ var->yres != macfb_defined.yres ||
+ var->xres_virtual != macfb_defined.xres_virtual ||
+ var->yres_virtual != macfb_defined.yres ||
+ var->xoffset ||
+ var->bits_per_pixel != macfb_defined.bits_per_pixel ||
+ var->nonstd) {
+ if (first) {
+ printk("macfb does not support changing the video mode\n");
+ first = 0;
+ }
+ return -EINVAL;
+ }
+
+ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+ return 0;
+
+ if (var->yoffset)
+ return -EINVAL;
+ return 0;
+}
+
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)
+static int valkyrie_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
+{
+ unsigned long flags;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ save_flags(flags);
+ cli();
+
+ /* tell clut which address to fill */
+ writeb(regno, &valkyrie_cmap_regs->addr);
+ nop();
+
+ /* send one color channel at a time */
+ writeb(red, &valkyrie_cmap_regs->lut);
+ nop();
+ writeb(green, &valkyrie_cmap_regs->lut);
+ nop();
+ writeb(blue, &valkyrie_cmap_regs->lut);
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+/* Unlike the Valkyrie, the DAFB cannot set individual colormap
+ registers. Therefore, we do what the MacOS driver does (no
+ kidding!) and simply set them one by one until we hit the one we
+ want. */
+static int dafb_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
+{
+ /* FIXME: really, really need to use ioremap() here,
+ phys_to_virt() doesn't work anymore */
+ static int lastreg = -1;
+ unsigned long flags;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ save_flags(flags);
+ cli();
+
+ /* fbcon will set an entire colourmap, but X won't. Hopefully
+ this should accomodate both of them */
+ if (regno != lastreg+1) {
+ int i;
+
+ /* Stab in the dark trying to reset the CLUT pointer */
+ writel(0, &dafb_cmap_regs->reset);
+ nop();
+
+ /* Loop until we get to the register we want */
+ for (i = 0; i < regno; i++) {
+ writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
+ nop();
+ writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
+ nop();
+ writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
+ nop();
+ }
+ }
+
+ writeb(red, &dafb_cmap_regs->lut);
+ nop();
+ writeb(green, &dafb_cmap_regs->lut);
+ nop();
+ writeb(blue, &dafb_cmap_regs->lut);
+
+ restore_flags(flags);
+
+ lastreg = regno;
+ return 0;
+}
+
+/* V8 and Brazil seem to use the same DAC. Sonora does as well. */
+static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
+{
+ unsigned char _red =red>>8;
+ unsigned char _green=green>>8;
+ unsigned char _blue =blue>>8;
+ unsigned char _regno;
+ unsigned long flags;
+
+ if (video_bpp>8) return 1; /* failsafe */
+
+ save_flags(flags);
+ cli();
+
+ /* On these chips, the CLUT register numbers are spread out
+ across the register space. Thus:
+
+ In 8bpp, all regnos are valid.
+
+ In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
+
+ In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
+ _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
+ writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
+
+ /* send one color channel at a time */
+ writeb(_red, &v8_brazil_cmap_regs->lut); nop();
+ writeb(_green, &v8_brazil_cmap_regs->lut); nop();
+ writeb(_blue, &v8_brazil_cmap_regs->lut);
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+static int rbv_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
+{
+ /* use MSBs */
+ unsigned char _red =red>>8;
+ unsigned char _green=green>>8;
+ unsigned char _blue =blue>>8;
+ unsigned char _regno;
+ unsigned long flags;
+
+ if (video_bpp>8) return 1; /* failsafe */
+
+ save_flags(flags);
+ cli();
+
+ /* From the VideoToolbox driver. Seems to be saying that
+ * regno #254 and #255 are the important ones for 1-bit color,
+ * regno #252-255 are the important ones for 2-bit color, etc.
+ */
+ _regno = regno + (256-(1<<video_bpp));
+
+ /* reset clut? (VideoToolbox sez "not necessary") */
+ writeb(0xFF, &rbv_cmap_regs->cntl); nop();
+
+ /* tell clut which address to use. */
+ writeb(_regno, &rbv_cmap_regs->addr); nop();
+
+ /* send one color channel at a time. */
+ writeb(_red, &rbv_cmap_regs->lut); nop();
+ writeb(_green, &rbv_cmap_regs->lut); nop();
+ writeb(_blue, &rbv_cmap_regs->lut);
+
+ restore_flags(flags);
+ /* done. */
+ return 0;
+}
+
+/* Macintosh Display Card (8x24) */
+static int mdc_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
+{
+ volatile struct mdc_cmap_regs *cmap_regs =
+ nubus_slot_addr(video_slot);
+ /* use MSBs */
+ unsigned char _red =red>>8;
+ unsigned char _green=green>>8;
+ unsigned char _blue =blue>>8;
+ unsigned char _regno=regno;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* the nop's are there to order writes. */
+ writeb(_regno, &cmap_regs->addr); nop();
+ writeb(_red, &cmap_regs->lut); nop();
+ writeb(_green, &cmap_regs->lut); nop();
+ writeb(_blue, &cmap_regs->lut);
+
+ restore_flags(flags);
+ return 0;
+}
+
+/* Toby frame buffer */
+static int toby_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
+{
+ volatile struct toby_cmap_regs *cmap_regs =
+ nubus_slot_addr(video_slot);
+ /* use MSBs */
+ unsigned char _red =~(red>>8);
+ unsigned char _green=~(green>>8);
+ unsigned char _blue =~(blue>>8);
+ unsigned char _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
- if ((err=do_fb_set_var(var, 1)))
- return err;
+ writeb(_regno, &cmap_regs->addr); nop();
+ writeb(_red, &cmap_regs->lut); nop();
+ writeb(_green, &cmap_regs->lut); nop();
+ writeb(_blue, &cmap_regs->lut);
+
+ restore_flags(flags);
+ return 0;
+}
+
+/* Jet frame buffer */
+static int jet_setpalette(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
+{
+ volatile struct jet_cmap_regs *cmap_regs =
+ nubus_slot_addr(video_slot);
+ /* use MSBs */
+ unsigned char _red = (red>>8);
+ unsigned char _green = (green>>8);
+ unsigned char _blue = (blue>>8);
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ writeb(regno, &cmap_regs->addr); nop();
+ writeb(_red, &cmap_regs->lut); nop();
+ writeb(_green, &cmap_regs->lut); nop();
+ writeb(_blue, &cmap_regs->lut);
+
+ restore_flags(flags);
return 0;
}
/*
- * Color map handling - hardcoded maps!!
+ * Civic framebuffer -- Quadra AV built-in video. A chip
+ * called Sebastian holds the actual color palettes, and
+ * apparently, there are two different banks of 512K RAM
+ * which can act as separate framebuffers for doing video
+ * input and viewing the screen at the same time! The 840AV
+ * Can add another 1MB RAM to give the two framebuffers
+ * 1MB RAM apiece.
*
- * 2.0 color map primitives, copied from atafb.c
- */
-
-/*
- * should be kmalloc'ed on request
+ * FIXME: this doesn't seem to work anymore.
*/
-static short red256[256], green256[256], blue256[256];
-
-static short red16[]=
- { 0x0000,0x0000,0x0000,0x0000,0x8080,0x8080,0x8080,0xc0c0,
- 0x8080,0x0000,0x0000,0x0000,0xffff,0xffff,0xffff,0xffff};
-static short green16[]=
- { 0x0000,0x0000,0x8080,0x8080,0x0000,0x0000,0x8080,0xc0c0,
- 0x8080,0x0000,0xffff,0xffff,0x0000,0x0000,0xffff,0xffff};
-static short blue16[]=
- { 0x0000,0x8080,0x0000,0x8080,0x0000,0x8080,0x0000,0xc0c0,
- 0x8080,0xffff,0x0000,0xffff,0x0000,0xffff,0x0000,0xffff};
-
-static short red4[]=
- { 0x0000,0x8080,0xffff,0xffff};
-static short green4[]=
- { 0x0000,0x8080,0x0000,0xffff};
-static short blue4[]=
- { 0x0000,0x8080,0x0000,0xffff};
-
-static short red2[]=
- { 0x0000,0xffff};
-static short green2[]=
- { 0x0000,0xffff};
-static short blue2[]=
- { 0x0000,0xffff};
-
-struct fb_cmap default_256_colors = { 0, 256, red256, green256, blue256, NULL };
-struct fb_cmap default_16_colors = { 0, 16, red16, green16, blue16, NULL };
-struct fb_cmap default_4_colors = { 0, 4, red4, green4, blue4, NULL };
-struct fb_cmap default_2_colors = { 0, 2, red2, green2, blue2, NULL };
-
-static int mac_set_cmap256(struct fb_cmap* cmap)
+static int civic_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
{
- int i,start;
- unsigned short *red,*green,*blue;
- unsigned short cval[] = {0xffff, 0xcccc, 0x9999,
- 0x6666, 0x3333, 0x0000 };
- unsigned short gval[] = {0x0a0a, 0x1414, 0x1e1e,
- 0x2828, 0x3232, 0x3c3c,
- 0x4646, 0x5050, 0x5a5a,
- 0x6464, 0x6e6e, 0x7878,
- 0x8282, 0x8c8c, 0x9696,
- 0xa0a0, 0xaaaa, 0xb4b4,
- 0xbebe, 0xc8c8, 0xd2d2,
- 0xdcdc, 0xe6e6, 0xf0f0};
-
- red=cmap->red;
- green=cmap->green;
- blue=cmap->blue;
- start=cmap->start;
-
- if (start < 0)
- return -EINVAL;
- if (cmap->len < 255)
- return -EINVAL;
- /* 16 ANSI colors */
- for (i=0 ; i < 16 ; i++) {
- *red++ = red16[i];
- *green++ = green16[i];
- *blue++ = blue16[i];
+ static int lastreg = -1;
+ unsigned long flags;
+ int clut_status;
+
+ if (video_bpp > 8) return 1; /* failsafe */
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * Set the register address
+ */
+ writeb(regno, &civic_cmap_regs->addr); nop();
+
+ /*
+ * Wait for VBL interrupt here;
+ * They're usually not enabled from Penguin, so we won't check
+ */
+#if 0
+ {
+#define CIVIC_VBL_OFFSET 0x120
+ volatile unsigned long *vbl = readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
+ /* do interrupt setup stuff here? */
+ *vbl = 0L; nop(); /* clear */
+ *vbl = 1L; nop(); /* set */
+ while (*vbl != 0L) /* wait for next vbl */
+ {
+ usleep(10); /* needed? */
+ }
+ /* do interrupt shutdown stuff here? */
}
- /* 216 colors (6x6x6) map) */
- for (i=16 ; i < 232 ; i++) {
- *red++ = cval[(i-16)/36];
- *green++ = cval[((i-16)/6)%6];
- *blue++ = cval[(i-16)%6];
+#endif
+
+ /*
+ * Grab a status word and do some checking;
+ * Then finally write the clut!
+ */
+ clut_status = readb(&civic_cmap_regs->status2);
+
+ if ((clut_status & 0x0008) == 0)
+ {
+#if 0
+ if ((clut_status & 0x000D) != 0)
+ {
+ writeb(0x00, &civic_cmap_regs->lut); nop();
+ writeb(0x00, &civic_cmap_regs->lut); nop();
+ }
+#endif
+
+ writeb( red, &civic_cmap_regs->lut); nop();
+ writeb(green, &civic_cmap_regs->lut); nop();
+ writeb( blue, &civic_cmap_regs->lut); nop();
+ writeb( 0x00, &civic_cmap_regs->lut); nop();
}
- /* 24 grays */
- for (i=232 ; i < 256 ; i++) {
- *red = *green = *blue = gval[i-232];
- red++;
- green++;
- blue++;
+ else
+ {
+ unsigned char junk;
+
+ junk = readb(&civic_cmap_regs->lut); nop();
+ junk = readb(&civic_cmap_regs->lut); nop();
+ junk = readb(&civic_cmap_regs->lut); nop();
+ junk = readb(&civic_cmap_regs->lut); nop();
+
+ if ((clut_status & 0x000D) != 0)
+ {
+ writeb(0x00, &civic_cmap_regs->lut); nop();
+ writeb(0x00, &civic_cmap_regs->lut); nop();
+ }
+
+ writeb( red, &civic_cmap_regs->lut); nop();
+ writeb(green, &civic_cmap_regs->lut); nop();
+ writeb( blue, &civic_cmap_regs->lut); nop();
+ writeb( junk, &civic_cmap_regs->lut); nop();
}
+
+ restore_flags(flags);
+
+ lastreg = regno;
return 0;
}
-static struct fb_cmap * mac_get_default_cmap(int bpp)
+/*
+ * The CSC is the framebuffer on the PowerBook 190 series
+ * (and the 5300 too, but that's a PowerMac). This function
+ * brought to you in part by the ECSC driver for MkLinux.
+ */
+
+static int csc_setpalette (unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue)
{
- if (bpp == 1)
- return &default_2_colors;
- if (bpp == 2)
- return &default_4_colors;
- if (bpp == 4)
- return &default_16_colors;
- return &default_256_colors;
+ mdelay(1);
+ csc_cmap_regs->clut_waddr = regno;
+ csc_cmap_regs->clut_data = red;
+ csc_cmap_regs->clut_data = green;
+ csc_cmap_regs->clut_data = blue;
+ return 0;
}
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
+#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB4 || FBCON_HAS_CFB2 */
+
+static int macfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *fb_info)
{
- switch (fsfromto) {
- case 0:
- memcpy(to, from, len);
- return;
- case 1:
- copy_from_user(to, from, len);
- return;
- case 2:
- copy_to_user(to, from, len);
- return;
- }
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+
+ if (regno >= video_cmap_len)
+ return 1;
+
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ *transp = 0;
+ return 0;
}
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
+static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info)
{
- int size;
- int tooff=0, fromoff=0;
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ if (regno >= video_cmap_len)
+ return 1;
- if (to->start > from->start)
- fromoff=to->start-from->start;
- else
- tooff=from->start-to->start;
- size=to->len-tooff;
- if (size > from->len-fromoff)
- size=from->len-fromoff;
- if (size < 0)
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+
+ switch (video_bpp) {
+#ifdef FBCON_HAS_MFB
+ case 1:
+ /* We shouldn't get here */
+ break;
+#endif
+#ifdef FBCON_HAS_CFB2
+ case 2:
+ if (macfb_setpalette)
+ macfb_setpalette(regno, red, green, blue);
+ else
+ return 1;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ if (macfb_setpalette)
+ macfb_setpalette(regno, red, green, blue);
+ else
+ return 1;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ if (macfb_setpalette)
+ macfb_setpalette(regno, red, green, blue);
+ else
+ return 1;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ /* 1:5:5:5 */
+ fbcon_cmap.cfb16[regno] =
+ ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) |
+ ((blue & 0xf800) >> 11) |
+ ((transp != 0) << 15);
+ break;
+#endif
+ /* I'm pretty sure that one or the other of these
+ doesn't exist on 68k Macs */
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb24[regno] =
+ (red << macfb_defined.red.offset) |
+ (green << macfb_defined.green.offset) |
+ (blue << macfb_defined.blue.offset);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb32[regno] =
+ (red << macfb_defined.red.offset) |
+ (green << macfb_defined.green.offset) |
+ (blue << macfb_defined.blue.offset);
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+ if (con != currcon)
return;
- size*=sizeof(unsigned short);
- memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
- memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
- memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
- if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, macfb_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
+ macfb_setcolreg, info);
}
-
+
static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
-#if 0
- printk("macfb_get_cmap: not supported!\n");
- /* interferes with X11 */
- if (console_loglevel < 7)
- return -EINVAL;
if (con == currcon) /* current console? */
- return fb_get_cmap(cmap, kspc, 0 /*offb_getcolreg*/, info);
+ return fb_get_cmap(cmap, kspc, macfb_getcolreg, info);
else if (fb_display[con].cmap.len) /* non default colormap? */
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
else
- fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
+ fb_copy_cmap(fb_default_cmap(video_cmap_len),
cmap, kspc ? 0 : 2);
-#endif
- copy_cmap(mac_get_default_cmap(fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
return 0;
-
}
static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
-#if 0
- printk("macfb_set_cmap: not supported!\n");
- if (console_loglevel < 7)
- return -EINVAL;
+ int err;
+
if (!fb_display[con].cmap.len) { /* no colormap allocated? */
- if ((err = fb_alloc_cmap(&fb_display[con].cmap,
- 1<<fb_display[con].var.bits_per_pixel, 0)))
- return err;
+ err = fb_alloc_cmap(&fb_display[con].cmap,video_cmap_len,0);
+ if (err)
+ return err;
}
if (con == currcon) /* current console? */
- return fb_set_cmap(cmap, kspc, 1 /*offb_setcolreg*/, info);
+ return fb_set_cmap(cmap, kspc, macfb_setcolreg, info);
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
-#endif
return 0;
}
-static int macfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+static int macfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
{
- /* no panning */
- printk("macfb_pan: not supported!\n");
return -EINVAL;
}
-static int macfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info)
+static int macfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
- printk("macfb_ioctl: not supported!\n");
return -EINVAL;
}
@@ -456,137 +871,405 @@ static struct fb_ops macfb_ops = {
macfb_get_cmap,
macfb_set_cmap,
macfb_pan_display,
- macfb_ioctl
+ macfb_ioctl,
+ NULL
};
-int __init macfb_setup(char *options)
+void macfb_setup(char *options, int *ints)
{
- char *this_opt;
-
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options)
- return 0;
-
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
- if (!*this_opt) continue;
-
- if (! strcmp(this_opt, "inverse"))
- inverse=1;
- else if (!strncmp(this_opt, "font:", 5)) {
- strcpy(fb_info.fontname, this_opt+5);
- printk("macfb_setup: option %s\n", this_opt);
+ char *this_opt;
+
+ fb_info.fontname[0] = '\0';
+
+ if (!options || !*options)
+ return;
+
+ for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ if (!*this_opt) continue;
+
+ if (! strcmp(this_opt, "inverse"))
+ inverse=1;
+ else if (!strncmp(this_opt, "font:", 5))
+ strcpy(fb_info.fontname, this_opt+5);
+ /* This means "turn on experimental CLUT code" */
+ else if (!strcmp(this_opt, "vidtest"))
+ vidtest=1;
}
- }
- return 0;
}
static int macfb_switch(int con, struct fb_info *info)
{
- do_fb_set_var(&fb_display[con].var,1);
- currcon=con;
- return 0;
+ /* Do we have to save the colormap? */
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, macfb_getcolreg,
+ info);
+
+ currcon = con;
+ /* Install new colormap */
+ do_install_cmap(con, info);
+ macfb_update_var(con, info);
+ return 1;
}
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
static void macfb_blank(int blank, struct fb_info *info)
{
/* Not supported */
}
-/*
- * Nubus call back. This will give us our board identity and also
- * other useful info we need later
- */
-
-static int nubus_video_card(struct nubus_device_specifier *ns, int slot, struct nubus_type *nt)
+void __init macfb_init(void)
{
- if(nt->category==NUBUS_CAT_DISPLAY)
- return 0;
- /* Claim all video cards. We don't yet do driver specifics though. */
- return -ENODEV;
-}
-
-static struct nubus_device_specifier nb_video={
- nubus_video_card,
- NULL
-};
-
-int __init macfb_init(void)
-{
- /* nubus_remap the video .. */
+ struct nubus_dev* ndev = NULL;
+ int video_is_nubus = 0;
if (!MACH_IS_MAC)
- return -ENXIO;
-
- mac_xres=mac_bi_data.dimensions&0xFFFF;
- mac_yres=(mac_bi_data.dimensions&0xFFFF0000)>>16;
- mac_depth=mac_bi_data.videodepth;
- mac_xbytes=mac_bi_data.videorow;
- mac_vxres = (mac_xbytes/mac_depth)*8;
- mac_videosize=mac_xbytes*mac_yres;
- mac_videobase=mac_bi_data.videoaddr;
-
- printk("macfb_init: xres %d yres %d bpp %d addr %lx size %ld \n",
- mac_xres, mac_yres, mac_depth, mac_videobase, mac_videosize);
+ return;
+ /* There can only be one internal video controller anyway so
+ we're not too worried about this */
+ video_width = mac_bi_data.dimensions & 0xFFFF;
+ video_height = mac_bi_data.dimensions >> 16;
+ video_bpp = mac_bi_data.videodepth;
+ video_linelength = mac_bi_data.videorow;
+ video_size = video_linelength * video_height;
+ /* Note: physical address (since 2.1.127) */
+ video_base = (void*) mac_bi_data.videoaddr;
+ /* This is actually redundant with the initial mappings.
+ However, there are some non-obvious aspects to the way
+ those mappings are set up, so this is in fact the safest
+ way to ensure that this driver will work on every possible
+ Mac */
+ video_vbase = ioremap(mac_bi_data.videoaddr, video_size);
+
+ printk("macfb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n",
+ video_base, video_vbase, video_size/1024);
+ printk("macfb: mode is %dx%dx%d, linelength=%d\n",
+ video_width, video_height, video_bpp, video_linelength);
+
/*
* Fill in the available video resolution
*/
- macfb_defined.xres=mac_xres;
- macfb_defined.yres=mac_yres;
- macfb_defined.xres_virtual=mac_vxres;
- macfb_defined.yres_virtual=mac_yres;
- macfb_defined.bits_per_pixel=mac_depth;
-
-
- /*
- * Let there be consoles..
- */
- strcpy(fb_info.modename, "Macintosh Builtin ");
- fb_info.changevar = NULL;
- fb_info.node = -1;
- fb_info.fbops = &macfb_ops;
- fb_info.disp=&disp;
- fb_info.switch_con=&macfb_switch;
- fb_info.updatevar=&fb_update_var;
- fb_info.blank=&macfb_blank;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
- do_fb_set_var(&macfb_defined,1);
-
- macfb_get_var(&disp.var, -1, &fb_info);
- macfb_set_disp(-1);
-
- /*
- * Fill in the 8 bit color table if required
- */
- if (mac_depth == 8)
- mac_set_cmap256(&default_256_colors);
-
- /*
- * Register the nubus hook
+ macfb_defined.xres = video_width;
+ macfb_defined.yres = video_height;
+ macfb_defined.xres_virtual = video_width;
+ macfb_defined.yres_virtual = video_height;
+ macfb_defined.bits_per_pixel = video_bpp;
+ macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
+ macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres);
+
+ printk("macfb: scrolling: redraw\n");
+ macfb_defined.yres_virtual = video_height;
+
+ /* some dummy values for timing to make fbset happy */
+ macfb_defined.pixclock = 10000000 / video_width * 1000 / video_height;
+ macfb_defined.left_margin = (video_width / 8) & 0xf8;
+ macfb_defined.right_margin = 32;
+ macfb_defined.upper_margin = 16;
+ macfb_defined.lower_margin = 4;
+ macfb_defined.hsync_len = (video_width / 8) & 0xf8;
+ macfb_defined.vsync_len = 4;
+
+ switch (video_bpp) {
+ case 1:
+ /* XXX: I think this will catch any program that tries
+ to do FBIO_PUTCMAP when the visual is monochrome */
+ video_cmap_len = 0;
+ video_visual = FB_VISUAL_MONO01;
+ break;
+ case 2:
+ case 4:
+ case 8:
+ macfb_defined.red.length = video_bpp;
+ macfb_defined.green.length = video_bpp;
+ macfb_defined.blue.length = video_bpp;
+ video_cmap_len = 1 << video_bpp;
+ video_visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ case 16:
+ macfb_defined.transp.offset = 15;
+ macfb_defined.transp.length = 1;
+ macfb_defined.red.offset = 10;
+ macfb_defined.red.length = 5;
+ macfb_defined.green.offset = 5;
+ macfb_defined.green.length = 5;
+ macfb_defined.blue.offset = 0;
+ macfb_defined.blue.length = 5;
+ printk("macfb: directcolor: "
+ "size=1:5:5:5, shift=15:10:5:0\n");
+ video_cmap_len = 16;
+ /* Should actually be FB_VISUAL_DIRECTCOLOR, but this
+ works too */
+ video_visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 24:
+ case 32:
+ /* XXX: have to test these... can any 68k Macs
+ actually do this on internal video? */
+ macfb_defined.red.offset = 16;
+ macfb_defined.red.length = 8;
+ macfb_defined.green.offset = 8;
+ macfb_defined.green.length = 8;
+ macfb_defined.blue.offset = 0;
+ macfb_defined.blue.length = 8;
+ printk("macfb: truecolor: "
+ "size=0:8:8:8, shift=0:16:8:0\n");
+ video_cmap_len = 16;
+ video_visual = FB_VISUAL_TRUECOLOR;
+ default:
+ video_cmap_len = 0;
+ video_visual = FB_VISUAL_MONO01;
+ printk("macfb: unknown or unsupported bit depth: %d\n", video_bpp);
+ break;
+ }
+
+ /* Hardware dependent stuff */
+ /* We take a wild guess that if the video physical address is
+ * in nubus slot space, that the nubus card is driving video.
+ * Penguin really ought to tell us whether we are using internal
+ * video or not.
*/
-
- register_nubus_device(&nb_video);
+ /* Hopefully we only find one of them. Otherwise our NuBus
+ code is really broken :-) */
- if (register_framebuffer(&fb_info) < 0)
+ while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
+ != NULL)
{
- return -EINVAL;
+ if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
+ && (mac_bi_data.videoaddr <
+ (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
+ continue;
+ video_is_nubus = 1;
+ /* We should probably just use the slot address... */
+ video_slot = ndev->board->slot;
+
+ switch(ndev->dr_hw) {
+ case NUBUS_DRHW_APPLE_MDC:
+ strcpy( fb_info.modename, "Macintosh Display Card" );
+ macfb_setpalette = mdc_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ break;
+ case NUBUS_DRHW_APPLE_TFB:
+ strcpy( fb_info.modename, "Toby" );
+ macfb_setpalette = toby_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ break;
+ case NUBUS_DRHW_APPLE_JET:
+ strcpy(fb_info.modename, "Jet");
+ macfb_setpalette = jet_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ break;
+ default:
+ strcpy( fb_info.modename, "Generic NuBus" );
+ break;
+ }
}
- printk("fb%d: %s frame buffer device using %ldK of video memory\n",
- GET_FB_IDX(fb_info.node), fb_info.modename, mac_videosize>>10);
- return 0;
-}
+ /* If it's not a NuBus card, it must be internal video */
+ /* FIXME: this function is getting way too big. (this driver
+ is too...) */
+ if (!video_is_nubus)
+ switch( mac_bi_data.id )
+ {
+ /* These don't have onboard video. Eventually, we may
+ be able to write separate framebuffer drivers for
+ them (tobyfb.c, hiresfb.c, etc, etc) */
+ case MAC_MODEL_II:
+ case MAC_MODEL_IIX:
+ case MAC_MODEL_IICX:
+ case MAC_MODEL_IIFX:
+ strcpy( fb_info.modename, "Generic NuBus" );
+ break;
+
+ /* Valkyrie Quadras */
+ case MAC_MODEL_Q630:
+ /* I'm not sure about this one */
+ case MAC_MODEL_P588:
+ strcpy( fb_info.modename, "Valkyrie built-in" );
+ macfb_setpalette = valkyrie_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000);
+ break;
+
+ /* DAFB Quadras */
+ /* Note: these first four have the v7 DAFB, which is
+ known to be rather unlike the ones used in the
+ other models */
+ case MAC_MODEL_P475:
+ case MAC_MODEL_P475F:
+ case MAC_MODEL_P575:
+ case MAC_MODEL_Q605:
+
+ case MAC_MODEL_Q800:
+ case MAC_MODEL_Q650:
+ case MAC_MODEL_Q610:
+ case MAC_MODEL_C650:
+ case MAC_MODEL_C610:
+ case MAC_MODEL_Q700:
+ case MAC_MODEL_Q900:
+ case MAC_MODEL_Q950:
+ strcpy( fb_info.modename, "DAFB built-in" );
+ macfb_setpalette = dafb_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
+ break;
+
+ /* LC II uses the V8 framebuffer */
+ case MAC_MODEL_LCII:
+ strcpy( fb_info.modename, "V8 built-in" );
+ macfb_setpalette = v8_brazil_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+ break;
+
+ /* IIvi, IIvx use the "Brazil" framebuffer (which is
+ very much like the V8, it seems, and probably uses
+ the same DAC) */
+ case MAC_MODEL_IIVI:
+ case MAC_MODEL_IIVX:
+ case MAC_MODEL_P600:
+ strcpy( fb_info.modename, "Brazil built-in" );
+ macfb_setpalette = v8_brazil_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+ break;
+
+ /* LC III (and friends) use the Sonora framebuffer */
+ /* Incidentally this is also used in the non-AV models
+ of the x100 PowerMacs */
+ /* These do in fact seem to use the same DAC interface
+ as the LC II. */
+ case MAC_MODEL_LCIII:
+ case MAC_MODEL_P520:
+ case MAC_MODEL_P550:
+ case MAC_MODEL_P460:
+ macfb_setpalette = v8_brazil_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ strcpy( fb_info.modename, "Sonora built-in" );
+ v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+ break;
+
+ /* IIci and IIsi use the infamous RBV chip
+ (the IIsi is just a rebadged and crippled
+ IIci in a different case, BTW) */
+ case MAC_MODEL_IICI:
+ case MAC_MODEL_IISI:
+ macfb_setpalette = rbv_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ strcpy( fb_info.modename, "RBV built-in" );
+ rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
+ break;
+
+ /* AVs use the Civic framebuffer */
+ case MAC_MODEL_Q840:
+ case MAC_MODEL_C660:
+ macfb_setpalette = civic_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ strcpy( fb_info.modename, "Civic built-in" );
+ civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
+ break;
+
+
+ /* Write a setpalette function for your machine, then
+ you can add something similar here. These are
+ grouped by classes of video chipsets. Some of this
+ information is from the VideoToolbox "Bugs" web
+ page at
+ http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
+
+ /* Assorted weirdos */
+ /* We think this may be like the LC II */
+ case MAC_MODEL_LC:
+ if (vidtest) {
+ macfb_setpalette = v8_brazil_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ v8_brazil_cmap_regs =
+ ioremap(DAC_BASE, 0x1000);
+ }
+ strcpy( fb_info.modename, "LC built-in" );
+ break;
+ /* We think this may be like the LC II */
+ case MAC_MODEL_CCL:
+ if (vidtest) {
+ macfb_setpalette = v8_brazil_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ v8_brazil_cmap_regs =
+ ioremap(DAC_BASE, 0x1000);
+ }
+ strcpy( fb_info.modename, "Color Classic built-in" );
+ break;
+
+ /* And we *do* mean "weirdos" */
+ case MAC_MODEL_TV:
+ strcpy( fb_info.modename, "Mac TV built-in" );
+ break;
+
+ /* These don't have colour, so no need to worry */
+ case MAC_MODEL_SE30:
+ case MAC_MODEL_CLII:
+ strcpy( fb_info.modename, "Monochrome built-in" );
+ break;
+
+ /* Powerbooks are particularly difficult. Many of
+ them have separate framebuffers for external and
+ internal video, which is admittedly pretty cool,
+ but will be a bit of a headache to support here.
+ Also, many of them are grayscale, and we don't
+ really support that. */
+
+ case MAC_MODEL_PB140:
+ case MAC_MODEL_PB145:
+ case MAC_MODEL_PB170:
+ strcpy( fb_info.modename, "DDC built-in" );
+ break;
+
+ /* Internal is GSC, External (if present) is ViSC */
+ case MAC_MODEL_PB150: /* no external video */
+ case MAC_MODEL_PB160:
+ case MAC_MODEL_PB165:
+ case MAC_MODEL_PB180:
+ case MAC_MODEL_PB210:
+ case MAC_MODEL_PB230:
+ strcpy( fb_info.modename, "GSC built-in" );
+ break;
+
+ /* Internal is TIM, External is ViSC */
+ case MAC_MODEL_PB165C:
+ case MAC_MODEL_PB180C:
+ strcpy( fb_info.modename, "TIM built-in" );
+ break;
+
+ /* Internal is CSC, External is Keystone+Ariel. */
+ case MAC_MODEL_PB190: /* external video is optional */
+ case MAC_MODEL_PB520:
+ case MAC_MODEL_PB250:
+ case MAC_MODEL_PB270C:
+ case MAC_MODEL_PB280:
+ case MAC_MODEL_PB280C:
+ macfb_setpalette = csc_setpalette;
+ macfb_defined.activate = FB_ACTIVATE_NOW;
+ strcpy( fb_info.modename, "CSC built-in" );
+ csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
+ break;
+
+ default:
+ strcpy( fb_info.modename, "Unknown/Unsupported built-in" );
+ break;
+ }
+
+ fb_info.changevar = NULL;
+ fb_info.node = -1;
+ fb_info.fbops = &macfb_ops;
+ fb_info.disp = &disp;
+ fb_info.switch_con = &macfb_switch;
+ fb_info.updatevar = &macfb_update_var;
+ fb_info.blank = &macfb_blank;
+ fb_info.flags = FBINFO_FLAG_DEFAULT;
+ macfb_set_disp(-1);
+ do_install_cmap(0, &fb_info);
+
+ if (register_framebuffer(&fb_info) < 0)
+ return;
-#if 0
-/*
- * These two auxiliary debug functions should go away ASAP. Only usage:
- * before the console output is up (after head.S come some other crucial
- * setup routines :-)
- *
- * Now in debug.c ...
- */
-#endif
+ printk("fb%d: %s frame buffer device\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename);
+}
diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c
index 946270f45..8fbff9bc4 100644
--- a/drivers/video/matroxfb.c
+++ b/drivers/video/matroxfb.c
@@ -90,11 +90,6 @@
/* Debug register calls, too? */
#undef MATROXFB_DEBUG_REG
-/* Log reentrancy attempts - you must have printstate() patch applied */
-#undef MATROXFB_DEBUG_REENTER
-/* you must define DEBUG_REENTER to get debugged CONSOLEBH... */
-#undef MATROXFB_DEBUG_CONSOLEBH
-
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -1082,46 +1077,6 @@ static int default_cmode = CMODE_NVRAM;
#define isMilleniumII(x) (0)
#endif
-#ifdef MATROXFB_DEBUG_REENTER
-static atomic_t guard_counter = ATOMIC_INIT(1);
-static atomic_t guard_printing = ATOMIC_INIT(1);
-static void guard_start(void) {
- if (atomic_dec_and_test(&guard_counter)) { /* first level */
- if (!(bh_mask & (1 << CONSOLE_BH))) /* and CONSOLE_BH disabled */
- return; /* is OK */
- /* otherwise it is first level with CONSOLE_BH enabled -
- - if we are __sti or SMP, reentering from console_bh possible */
- atomic_dec(&guard_printing); /* disable reentrancy warning */
- printk(KERN_DEBUG "matroxfb entered without CONSOLE_BH disabled\n");
-#ifdef printstate
- printstate();
-#endif
- atomic_inc(&guard_printing);
- return;
- }
- /* real reentering... You should be already warned by code above */
- if (atomic_dec_and_test(&guard_printing)) {
-#ifdef printstate
- printstate();
-#endif
- }
- atomic_inc(&guard_printing);
-}
-
-static inline void guard_end(void) {
- atomic_inc(&guard_counter);
-}
-
-#define CRITBEGIN guard_start();
-#define CRITEND guard_end();
-
-#else
-
-#define CRITBEGIN
-#define CRITEND
-
-#endif
-
#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
static void matrox_cfbX_init(WPMINFO struct display* p) {
@@ -1184,8 +1139,6 @@ static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx,
DBG("matrox_cfbX_bmove")
- CRITBEGIN
-
sx *= fontwidth(p);
dx *= fontwidth(p);
width *= fontwidth(p);
@@ -1216,8 +1169,6 @@ static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx,
mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
mga_ydstlen(dy, height);
WaitTillIdle();
-
- CRITEND
}
#ifdef FBCON_HAS_CFB4
@@ -1229,8 +1180,6 @@ static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx,
DBG("matrox_cfb4_bmove")
- CRITBEGIN
-
if ((sx | dx | width) & fontwidth(p) & 1) {
fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
return;
@@ -1270,8 +1219,6 @@ static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx,
mga_outl(M_YDST, dy*pixx >> 5);
mga_outl(M_LEN | M_EXEC, height);
WaitTillIdle();
-
- CRITEND
}
#endif
@@ -1280,16 +1227,12 @@ static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int he
DBG("matroxfb_accel_clear")
- CRITBEGIN
-
mga_fifo(5);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
mga_outl(M_FCOL, color);
mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
mga_ydstlen(sy, height);
WaitTillIdle();
-
- CRITEND
}
static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
@@ -1308,8 +1251,6 @@ static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, i
DBG("matrox_cfb4_clear")
- CRITBEGIN
-
whattodo = 0;
bgx = attr_bgcol_ec(p, conp);
bgx |= bgx << 4;
@@ -1361,8 +1302,6 @@ static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, i
}
}
}
-
- CRITEND
}
#endif
@@ -1410,8 +1349,6 @@ static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p
yy *= fontheight(p);
xx *= fontwidth(p);
- CRITBEGIN
-
mga_fifo(8);
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
@@ -1423,8 +1360,6 @@ static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p
mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
mga_ydstlen(yy, fontheight(p));
WaitTillIdle();
-
- CRITEND
}
static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
@@ -1437,8 +1372,6 @@ static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, in
yy *= fontheight(p);
xx *= fontwidth(p);
- CRITBEGIN
-
#ifdef __BIG_ENDIAN
WaitTillIdle();
mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1504,7 +1437,6 @@ static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, in
#ifdef __BIG_ENDIAN
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
#endif
- CRITEND
}
#ifdef FBCON_HAS_CFB8
@@ -1560,8 +1492,6 @@ static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display*
xx *= fontwidth(p);
charcell = fontwidth(p) * fontheight(p);
- CRITBEGIN
-
mga_fifo(3);
mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
mga_outl(M_FCOL, fgx);
@@ -1577,8 +1507,6 @@ static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display*
xx += fontwidth(p);
}
WaitTillIdle();
-
- CRITEND
}
static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
@@ -1613,8 +1541,6 @@ static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, c
easy = 0;
}
- CRITBEGIN
-
#ifdef __BIG_ENDIAN
WaitTillIdle();
mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1676,7 +1602,6 @@ static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, c
#ifdef __BIG_ENDIAN
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
#endif
- CRITEND
}
#ifdef FBCON_HAS_CFB8
@@ -1739,8 +1664,6 @@ static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
xx |= (xx + fontwidth(p)) << 16;
xx >>= 1;
- CRITBEGIN
-
mga_fifo(5);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
mga_outl(M_FCOL, 0xFFFFFFFF);
@@ -1748,8 +1671,6 @@ static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
mga_outl(M_LEN | M_EXEC, fontheight(p));
WaitTillIdle();
-
- CRITEND
}
#endif
@@ -1762,16 +1683,12 @@ static void matrox_cfb8_revc(struct display* p, int xx, int yy) {
yy *= fontheight(p);
xx *= fontwidth(p);
- CRITBEGIN
-
mga_fifo(4);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
mga_outl(M_FCOL, 0x0F0F0F0F);
mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
mga_ydstlen(yy, fontheight(p));
WaitTillIdle();
-
- CRITEND
}
#endif
@@ -1783,16 +1700,12 @@ static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
yy *= fontheight(p);
xx *= fontwidth(p);
- CRITBEGIN
-
mga_fifo(4);
mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
mga_outl(M_FCOL, 0xFFFFFFFF);
mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
mga_ydstlen(yy, fontheight(p));
WaitTillIdle();
-
- CRITEND
}
static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
@@ -2034,8 +1947,6 @@ static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) {
cursorbase = ACCESS_FBINFO(video.vbase);
h = ACCESS_FBINFO(features.DAC1064.cursorimage);
- CRITBEGIN
-
#ifdef __BIG_ENDIAN
WaitTillIdle();
mga_outl(M_OPMODE, M_OPMODE_32BPP);
@@ -2066,8 +1977,6 @@ static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) {
#ifdef __BIG_ENDIAN
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
#endif
-
- CRITEND
}
static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
@@ -2138,8 +2047,6 @@ static int matroxfb_fastfont_tryset(WPMINFO struct display* p) {
if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
return 0;
- CRITBEGIN
-
mga_outl(M_OPMODE, M_OPMODE_8BPP);
if (width <= 8) {
if (width == 8)
@@ -2231,8 +2138,6 @@ static int matroxfb_fastfont_tryset(WPMINFO struct display* p) {
}
mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
- CRITEND
-
return 1;
}
@@ -2250,8 +2155,6 @@ static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx,
unsigned int step;
MINFO_FROM_DISP(p);
- CRITBEGIN
-
step = ACCESS_FBINFO(devflags.textstep);
srcoff = (sy * p->next_line) + (sx * step);
dstoff = (dy * p->next_line) + (dx * step);
@@ -2279,7 +2182,6 @@ static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx,
height--;
}
}
- CRITEND
}
static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
@@ -2293,8 +2195,6 @@ static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, i
offs = sy * p->next_line + sx * step;
val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
- CRITBEGIN
-
while (height > 0) {
int i;
for (i = width; i > 0; offs += step, i--)
@@ -2302,7 +2202,6 @@ static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, i
offs += p->next_line - width * step;
height--;
}
- CRITEND
}
static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
@@ -2316,11 +2215,7 @@ static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int
chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
if (chr & 0x10000) chr |= 0x08;
- CRITBEGIN
-
mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
-
- CRITEND
}
static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
@@ -2334,16 +2229,12 @@ static void matrox_text_putcs(struct vc_data* conp, struct display* p, const uns
offs = yy * p->next_line + xx * step;
attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
- CRITBEGIN
-
while (count-- > 0) {
unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
if (chr & 0x10000) chr ^= 0x10008;
mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
offs += step;
}
-
- CRITEND
}
static void matrox_text_revc(struct display* p, int xx, int yy) {
@@ -2354,11 +2245,7 @@ static void matrox_text_revc(struct display* p, int xx, int yy) {
step = ACCESS_FBINFO(devflags.textstep);
offs = yy * p->next_line + xx * step + 1;
- CRITBEGIN
-
mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
-
- CRITEND
}
static int matrox_text_loadfont(WPMINFO struct display* p) {
@@ -2377,8 +2264,6 @@ static int matrox_text_loadfont(WPMINFO struct display* p) {
i = 2;
font = (u_int8_t*)p->fontdata;
- CRITBEGIN
-
mga_setr(M_SEQ_INDEX, 0x02, 0x04);
while (fsize--) {
int l;
@@ -2392,8 +2277,6 @@ static int matrox_text_loadfont(WPMINFO struct display* p) {
}
mga_setr(M_SEQ_INDEX, 0x02, 0x03);
- CRITEND
-
return 1;
}
@@ -2404,12 +2287,8 @@ static void matrox_text_createcursor(WPMINFO struct display* p) {
matroxfb_createcursorshape(PMINFO p, 0);
- CRITBEGIN
-
mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
-
- CRITEND
}
static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
@@ -2422,12 +2301,8 @@ static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
if (mode == CM_ERASE) {
if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
- CRITBEGIN
-
mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
- CRITEND
-
ACCESS_FBINFO(cursor.state) = CM_ERASE;
}
return;
@@ -2440,15 +2315,11 @@ static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
ACCESS_FBINFO(cursor.y) = y;
pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
- CRITBEGIN
-
mga_setr(M_CRTC_INDEX, 0x0F, pos);
mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
- CRITEND
-
ACCESS_FBINFO(cursor.state) = CM_DRAW;
}
@@ -2717,8 +2588,6 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
#endif
- CRITBEGIN
-
mga_setr(M_CRTC_INDEX, 0x0D, p0);
mga_setr(M_CRTC_INDEX, 0x0C, p1);
#ifdef CONFIG_FB_MATROX_32MB
@@ -2726,8 +2595,6 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
mga_setr(M_EXTVGA_INDEX, 0x08, p3);
#endif
mga_setr(M_EXTVGA_INDEX, 0x00, p2);
-
- CRITEND
}
/*
@@ -3480,8 +3347,6 @@ static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const st
DBG("DAC1064_restore_1")
- CRITBEGIN
-
outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
@@ -3491,8 +3356,6 @@ static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const st
for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
}
-
- CRITEND
}
static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
@@ -3501,17 +3364,13 @@ static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const st
DBG("DAC1064_restore_2")
- CRITBEGIN
-
for (i = 0; i < 3; i++)
outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
for (tmout = 500000; tmout; tmout--) {
if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
break;
udelay(10);
- };
-
- CRITEND
+ }
if (!tmout)
printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
@@ -4306,8 +4165,6 @@ static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_st
dprintk("%02X:", hw->ATTR[i]);
dprintk("\n");
- CRITBEGIN
-
mga_inb(M_ATTR_RESET);
mga_outb(M_ATTR_INDEX, 0);
mga_outb(M_MISC_REG, hw->MiscOutReg);
@@ -4329,8 +4186,6 @@ static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_st
mga_outb(M_DAC_VAL, hw->DACpal[i]);
mga_inb(M_ATTR_RESET);
mga_outb(M_ATTR_INDEX, 0x20);
-
- CRITEND
}
static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -4434,14 +4289,10 @@ static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw
DBG("MGA1064_restore")
- CRITBEGIN
-
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
mga_outb(M_IEN, 0x00);
mga_outb(M_CACHEFLUSH, 0x00);
- CRITEND
-
DAC1064_restore_1(PMINFO hw, oldhw);
vgaHWrestore(PMINFO hw, oldhw);
for (i = 0; i < 6; i++)
@@ -4456,10 +4307,7 @@ static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw
DBG("MGAG100_restore")
- CRITBEGIN
-
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- CRITEND
DAC1064_restore_1(PMINFO hw, oldhw);
vgaHWrestore(PMINFO hw, oldhw);
@@ -4484,16 +4332,10 @@ static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_
dprintk("%02X:", hw->CRTCEXT[i]);
dprintk("\n");
- CRITBEGIN
-
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- CRITEND
-
vgaHWrestore(PMINFO hw, oldhw);
- CRITBEGIN
-
for (i = 0; i < 6; i++)
mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
@@ -4511,13 +4353,11 @@ static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_
oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
}
- CRITEND
if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
/* agrhh... setting up PLL is very slow on Millenium... */
/* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
/* Maybe even we should call schedule() ? */
- CRITBEGIN
outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
@@ -4536,30 +4376,24 @@ static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_
udelay(10);
}
- CRITEND
-
if (!tmout)
printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
else
dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
- CRITBEGIN
}
outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
for (i = 3; i < 6; i++)
outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
- CRITEND
if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
int tmout;
- CRITBEGIN
outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
for (tmout = 500000; tmout; --tmout) {
if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
break;
udelay(10);
}
- CRITEND
if (!tmout)
printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
else
@@ -4954,15 +4788,11 @@ static void matroxfb_blank(int blank, struct fb_info *info)
default: seq = 0x00; crtc = 0x00; break;
}
- CRITBEGIN
-
mga_outb(M_SEQ_INDEX, 1);
mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
mga_outb(M_EXTVGA_INDEX, 1);
mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
- CRITEND
-
#undef minfo
}
diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c
new file mode 100644
index 000000000..5728c0721
--- /dev/null
+++ b/drivers/video/sun3fb.c
@@ -0,0 +1,729 @@
+/*
+ * linux/drivers/video/sun3fb.c -- Frame buffer driver for Sun3
+ *
+ * (C) 1998 Thomas Bogendoerfer
+ *
+ * This driver is bases on sbusfb.c, which is
+ *
+ * Copyright (C) 1998 Jakub Jelinek
+ *
+ * This driver is partly based on the Open Firmware console driver
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * and SPARC console subsystem
+ *
+ * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
+ * Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h> /* io_remap_page_range() */
+
+#ifdef CONFIG_SUN3
+#include <asm/oplib.h>
+#endif
+#ifdef CONFIG_SUN3X
+#include <asm/sun3x.h>
+#endif
+#include <video/sbusfb.h>
+
+#define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5)
+
+#define CURSOR_SHAPE 1
+#define CURSOR_BLINK 2
+
+ /*
+ * Interface used by the world
+ */
+
+int sun3fb_init(void);
+int sun3fb_setup(char *options);
+
+static int currcon;
+static char fontname[40] __initdata = { 0 };
+static int curblink __initdata = 1;
+
+static int sun3fb_open(struct fb_info *info, int user);
+static int sun3fb_release(struct fb_info *info, int user);
+static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int sun3fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int sun3fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info);
+static void sun3fb_cursor(struct display *p, int mode, int x, int y);
+static void sun3fb_clear_margin(struct display *p, int s);
+
+
+ /*
+ * Interface to the low level console driver
+ */
+
+static int sun3fbcon_switch(int con, struct fb_info *info);
+static int sun3fbcon_updatevar(int con, struct fb_info *info);
+static void sun3fbcon_blank(int blank, struct fb_info *info);
+
+
+ /*
+ * Internal routines
+ */
+
+static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info);
+static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+static struct fb_ops sun3fb_ops = {
+ sun3fb_open, sun3fb_release, sun3fb_get_fix, sun3fb_get_var, sun3fb_set_var,
+ sun3fb_get_cmap, sun3fb_set_cmap, sun3fb_pan_display, sun3fb_ioctl
+};
+
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int sun3fb_open(struct fb_info *info, int user)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int sun3fb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static void sun3fb_clear_margin(struct display *p, int s)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+ if (fb->switch_from_graph)
+ (*fb->switch_from_graph)(fb);
+ if (fb->fill) {
+ unsigned short rects [16];
+
+ rects [0] = 0;
+ rects [1] = 0;
+ rects [2] = fb->var.xres_virtual;
+ rects [3] = fb->y_margin;
+ rects [4] = 0;
+ rects [5] = fb->y_margin;
+ rects [6] = fb->x_margin;
+ rects [7] = fb->var.yres_virtual;
+ rects [8] = fb->var.xres_virtual - fb->x_margin;
+ rects [9] = fb->y_margin;
+ rects [10] = fb->var.xres_virtual;
+ rects [11] = fb->var.yres_virtual;
+ rects [12] = fb->x_margin;
+ rects [13] = fb->var.yres_virtual - fb->y_margin;
+ rects [14] = fb->var.xres_virtual - fb->x_margin;
+ rects [15] = fb->var.yres_virtual;
+ (*fb->fill)(fb, p, s, 4, rects);
+ } else {
+ unsigned char *fb_base = p->screen_base, *q;
+ int skip_bytes = fb->y_margin * fb->var.xres_virtual;
+ int scr_size = fb->var.xres_virtual * fb->var.yres_virtual;
+ int h, he, incr, size;
+
+ he = fb->var.yres;
+ if (fb->var.bits_per_pixel == 1) {
+ fb_base -= (skip_bytes + fb->x_margin) / 8;
+ skip_bytes /= 8;
+ scr_size /= 8;
+ mymemset (fb_base, skip_bytes - fb->x_margin / 8);
+ mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
+ incr = fb->var.xres_virtual / 8;
+ size = fb->x_margin / 8 * 2;
+ for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
+ h <= he; q += incr, h++)
+ mymemset (q, size);
+ } else {
+ fb_base -= (skip_bytes + fb->x_margin);
+ memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+ memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+ incr = fb->var.xres_virtual;
+ size = fb->x_margin * 2;
+ for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
+ h <= he; q += incr, h++)
+ memset (q, attr_bgcol(p,s), size);
+ }
+ }
+}
+
+static void sun3fb_disp_setup(struct display *p)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+ if (fb->setup)
+ fb->setup(p);
+ sun3fb_clear_margin(p, 0);
+}
+
+ /*
+ * Get the Fixed Part of the Display
+ */
+
+static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo));
+ return 0;
+}
+
+ /*
+ * Get the User Defined Part of the Display
+ */
+
+static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
+ return 0;
+}
+
+ /*
+ * Set the User Defined Part of the Display
+ */
+
+static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ if (var->xres > fb->var.xres || var->yres > fb->var.yres ||
+ var->xres_virtual > fb->var.xres_virtual ||
+ var->yres_virtual > fb->var.yres_virtual ||
+ var->bits_per_pixel != fb->var.bits_per_pixel ||
+ var->nonstd ||
+ (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+ memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
+ return 0;
+}
+
+ /*
+ * Pan or Wrap the Display
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ */
+
+static int sun3fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if (var->xoffset || var->yoffset)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+ /*
+ * Hardware cursor
+ */
+
+static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
+
+static void
+sun3fb_cursor_timer_handler(unsigned long dev_addr)
+{
+ struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr;
+
+ if (!fb->setcursor) return;
+
+ if (fb->cursor.mode & CURSOR_BLINK) {
+ fb->cursor.enable ^= 1;
+ fb->setcursor(fb);
+ }
+
+ fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
+ add_timer(&fb->cursor.timer);
+}
+
+static void sun3fb_cursor(struct display *p, int mode, int x, int y)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+ switch (mode) {
+ case CM_ERASE:
+ fb->cursor.mode &= ~CURSOR_BLINK;
+ fb->cursor.enable = 0;
+ (*fb->setcursor)(fb);
+ break;
+
+ case CM_MOVE:
+ case CM_DRAW:
+ if (fb->cursor.mode & CURSOR_SHAPE) {
+ fb->cursor.size.fbx = fontwidth(p);
+ fb->cursor.size.fby = fontheight(p);
+ fb->cursor.chot.fbx = 0;
+ fb->cursor.chot.fby = 0;
+ fb->cursor.enable = 1;
+ memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits));
+ fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
+ fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
+ fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
+ fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
+ (*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
+ (*fb->setcurshape) (fb);
+ }
+ fb->cursor.mode = CURSOR_BLINK;
+ if (fontwidthlog(p))
+ fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin;
+ else
+ fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin;
+ if (fontheightlog(p))
+ fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin;
+ else
+ fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin;
+ (*fb->setcursor)(fb);
+ break;
+ }
+}
+
+ /*
+ * Get the Colormap
+ */
+
+static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ if (con == currcon) /* current console? */
+ return fb_get_cmap(cmap, kspc, sun3fb_getcolreg, info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+ /*
+ * Set the Colormap
+ */
+
+static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if (!fb_display[con].cmap.len) { /* no colormap allocated? */
+ if ((err = fb_alloc_cmap(&fb_display[con].cmap, 1<<fb_display[con].var.bits_per_pixel, 0)))
+ return err;
+ }
+ if (con == currcon) { /* current console? */
+ err = fb_set_cmap(cmap, kspc, sun3fb_setcolreg, info);
+ if (!err) {
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ if (fb->loadcmap)
+ (*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len);
+ }
+ return err;
+ } else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int sun3fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+ /*
+ * Setup: parse used options
+ */
+
+__initfunc(void sun3fb_setup(char *options))
+{
+ char *p;
+
+ for (p = options;;) {
+ if (!strncmp(p, "font=", 5)) {
+ int i;
+
+ for (i = 0; i < sizeof(fontname) - 1; i++)
+ if (p[i+5] == ' ' || !p[i+5])
+ break;
+ memcpy(fontname, p+5, i);
+ fontname[i] = 0;
+ } else if (!strncmp(p, "noblink", 7))
+ curblink = 0;
+ while (*p && *p != ' ' && *p != ',') p++;
+ if (*p != ',') break;
+ p++;
+ }
+
+ return 0;
+}
+
+static int sun3fbcon_switch(int con, struct fb_info *info)
+{
+ int x_margin, y_margin;
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+ int lastconsole;
+
+ /* Do we have to save the colormap? */
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, sun3fb_getcolreg, info);
+
+ if (info->display_fg) {
+ lastconsole = info->display_fg->vc_num;
+ if (lastconsole != con &&
+ (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) ||
+ fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con])))
+ fb->cursor.mode |= CURSOR_SHAPE;
+ }
+ x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2;
+ y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2;
+ if (fb->margins)
+ fb->margins(fb, &fb_display[con], x_margin, y_margin);
+ if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) {
+ fb->x_margin = x_margin; fb->y_margin = y_margin;
+ sun3fb_clear_margin(&fb_display[con], 0);
+ }
+ currcon = con;
+ /* Install new colormap */
+ do_install_cmap(con, info);
+ return 0;
+}
+
+ /*
+ * Update the `var' structure (called by fbcon.c)
+ */
+
+static int sun3fbcon_updatevar(int con, struct fb_info *info)
+{
+ /* Nothing */
+ return 0;
+}
+
+ /*
+ * Blank the display.
+ */
+
+static void sun3fbcon_blank(int blank, struct fb_info *info)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ if (blank && fb->blank)
+ return fb->blank(fb);
+ else if (!blank && fb->unblank)
+ return fb->unblank(fb);
+}
+
+ /*
+ * Read a single color register and split it into
+ * colors/transparent. Return != 0 for invalid regno.
+ */
+
+static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ if (!fb->color_map || regno > 255)
+ return 1;
+ *red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0);
+ *green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1);
+ *blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2);
+ *transp = 0;
+ return 0;
+}
+
+
+ /*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ */
+
+static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ if (!fb->color_map || regno > 255)
+ return 1;
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fb->color_map CM(regno, 0) = red;
+ fb->color_map CM(regno, 1) = green;
+ fb->color_map CM(regno, 2) = blue;
+ return 0;
+}
+
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+ struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+ if (con != currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, sun3fb_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ 1, sun3fb_setcolreg, info);
+ if (fb->loadcmap)
+ (*fb->loadcmap)(fb, &fb_display[con], 0, 256);
+}
+
+static int sun3fb_set_font(struct display *p, int width, int height)
+{
+ int w = p->var.xres_virtual, h = p->var.yres_virtual;
+ int depth = p->var.bits_per_pixel;
+ struct fb_info_sbusfb *fb = sbusfbinfod(p);
+ int x_margin, y_margin;
+
+ if (depth > 8) depth = 8;
+ x_margin = (w % width) / 2;
+ y_margin = (h % height) / 2;
+
+ p->var.xres = w - 2*x_margin;
+ p->var.yres = h - 2*y_margin;
+
+ fb->cursor.mode |= CURSOR_SHAPE;
+
+ if (fb->margins)
+ fb->margins(fb, p, x_margin, y_margin);
+ if (fb->x_margin != x_margin || fb->y_margin != y_margin) {
+ fb->x_margin = x_margin; fb->y_margin = y_margin;
+ sun3fb_clear_margin(p, 0);
+ }
+
+ return 1;
+}
+
+void sun3fb_palette(int enter)
+{
+ int i;
+ struct display *p;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ p = &fb_display[i];
+ if (p->dispsw && p->dispsw->setup == sun3fb_disp_setup &&
+ p->fb_info->display_fg &&
+ p->fb_info->display_fg->vc_num == i) {
+ struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+ if (fb->restore_palette) {
+ if (enter)
+ fb->restore_palette(fb);
+ else if (vt_cons[i]->vc_mode != KD_GRAPHICS)
+ vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
+ }
+ }
+ }
+}
+
+ /*
+ * Initialisation
+ */
+__initfunc(static void sun3fb_init_fb(int fbtype, unsigned long addr))
+{
+ static struct linux_sbus_device sdb;
+ struct fb_fix_screeninfo *fix;
+ struct fb_var_screeninfo *var;
+ struct display *disp;
+ struct fb_info_sbusfb *fb;
+ struct fbtype *type;
+ int linebytes, w, h, depth;
+ char *p = NULL;
+
+ fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
+ if (!fb)
+ return -ENOMEM;
+
+ memset(fb, 0, sizeof(struct fb_info_sbusfb));
+ fix = &fb->fix;
+ var = &fb->var;
+ disp = &fb->disp;
+ type = &fb->type;
+
+ sdb.reg_addrs[0].phys_addr = addr;
+ fb->sbdp = &sdb;
+
+ type->fb_type = fbtype;
+
+ type->fb_height = h = 900;
+ type->fb_width = w = 1152;
+sizechange:
+ type->fb_depth = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
+ linebytes = w * depth / 8;
+ type->fb_size = PAGE_ALIGN((linebytes) * h);
+
+ fb->x_margin = (w & 7) / 2;
+ fb->y_margin = (h & 15) / 2;
+
+ var->xres_virtual = w;
+ var->yres_virtual = h;
+ var->xres = w - 2*fb->x_margin;
+ var->yres = h - 2*fb->y_margin;
+
+ var->bits_per_pixel = depth;
+ var->height = var->width = -1;
+ var->pixclock = 10000;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->red.length = var->green.length = var->blue.length = 8;
+
+ fix->line_length = linebytes;
+ fix->smem_len = type->fb_size;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+
+ fb->info.node = -1;
+ fb->info.fbops = &sun3fb_ops;
+ fb->info.disp = disp;
+ strcpy(fb->info.fontname, fontname);
+ fb->info.changevar = NULL;
+ fb->info.switch_con = &sun3fbcon_switch;
+ fb->info.updatevar = &sun3fbcon_updatevar;
+ fb->info.blank = &sun3fbcon_blank;
+ fb->info.flags = FBINFO_FLAG_DEFAULT;
+
+ fb->cursor.hwsize.fbx = 32;
+ fb->cursor.hwsize.fby = 32;
+
+ if (depth > 1 && !fb->color_map)
+ fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
+
+ switch(fbtype) {
+#ifdef CONFIG_FB_CGSIX
+ case FBTYPE_SUNFAST_COLOR:
+ p = cgsixfb_init(fb); break;
+#endif
+#ifdef CONFIG_FB_BWTWO
+ case FBTYPE_SUN2BW:
+ p = bwtwofb_init(fb); break;
+#endif
+ }
+ fix->smem_start = fb->disp.screen_base;
+
+ if (!p) {
+ kfree(fb);
+ -ENODEV;
+ }
+
+ if (p == SBUSFBINIT_SIZECHANGE)
+ goto sizechange;
+
+ disp->dispsw = &fb->dispsw;
+ if (fb->setcursor) {
+ fb->dispsw.cursor = sun3fb_cursor;
+ if (curblink) {
+ fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
+ init_timer(&fb->cursor.timer);
+ fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
+ fb->cursor.timer.data = (unsigned long)fb;
+ fb->cursor.timer.function = sun3fb_cursor_timer_handler;
+ add_timer(&fb->cursor.timer);
+ }
+ }
+ fb->cursor.mode = CURSOR_SHAPE;
+ fb->dispsw.set_font = sun3fb_set_font;
+ fb->setup = fb->dispsw.setup;
+ fb->dispsw.setup = sun3fb_disp_setup;
+ fb->dispsw.clear_margins = NULL;
+
+ disp->var = *var;
+ disp->visual = fix->visual;
+ disp->type = fix->type;
+ disp->type_aux = fix->type_aux;
+ disp->line_length = fix->line_length;
+
+ if (fb->blank)
+ disp->can_soft_blank = 1;
+
+ sun3fb_set_var(var, -1, &fb->info);
+
+ if (register_framebuffer(&fb->info) < 0) {
+ kfree(fb);
+ return -EINVAL;
+ }
+ printk("fb%d: %s\n", GET_FB_IDX(fb->info.node), p);
+
+ return 0;
+}
+
+
+__initfunc(int sun3fb_init(void))
+{
+ extern int con_is_present(void);
+ unsigned long addr;
+ char p4id;
+
+ if (!con_is_present()) return;
+ printk("sun3fb_init()\n");
+#ifdef CONFIG_SUN3
+ addr = 0xfe20000;
+ switch(*(romvec->pv_fbtype))
+ {
+ case FBTYPE_SUN2BW:
+ return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
+ case FBTYPE_SUN3COLOR:
+ printk("cg3 detected but not supported\n");
+ return -EINVAL;
+ }
+#else
+ addr = SUN3X_VIDEO_BASE;
+ p4id = *(char *)SUN3X_VIDEO_P4ID;
+
+ p4id = (p4id == 0x45) ? p4id : (p4id & 0xf0);
+ switch (p4id) {
+ case 0x00:
+ return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
+#if 0 /* not yet */
+ case 0x40:
+ sun3fb_init_fb(FBTYPE_SUN4COLOR, addr);
+ break;
+ case 0x45:
+ sun3fb_init_fb(FBTYPE_SUN8COLOR, addr);
+ break;
+#endif
+ case 0x60:
+ return sun3fb_init_fb(FBTYPE_SUNFAST_COLOR, addr);
+ }
+#endif
+}