Index: stable/4/sys/conf/files.i386 =================================================================== --- stable/4/sys/conf/files.i386 (revision 82305) +++ stable/4/sys/conf/files.i386 (revision 82306) @@ -1,473 +1,473 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # $FreeBSD$ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # linux_genassym.o optional compat_linux \ dependency "$S/i386/linux/linux_genassym.c" \ compile-with "${CC} ${CFLAGS} -c ${.IMPSRC}" \ no-obj no-implicit-rule \ clean "linux_genassym.o" # svr4_genassym.o optional compat_svr4 \ dependency "$S/i386/svr4/svr4_genassym.c" \ compile-with "${CC} ${CFLAGS} -c ${.IMPSRC}" \ no-obj no-implicit-rule \ clean "svr4_genassym.o" # linux_assym.h optional compat_linux \ dependency "$S/kern/genassym.sh linux_genassym.o" \ compile-with "sh $S/kern/genassym.sh linux_genassym.o > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "linux_assym.h" # svr4_assym.h optional compat_svr4 \ dependency "$S/kern/genassym.sh svr4_genassym.o" \ compile-with "sh $S/kern/genassym.sh svr4_genassym.o > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "svr4_assym.h" # font.h optional sc_dflt_font \ compile-with "uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'static u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'static u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'static u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h" \ no-obj no-implicit-rule before-depend \ clean "font.h" # atkbdmap.h optional atkbd_dflt_keymap \ compile-with "/usr/sbin/kbdcontrol -L ${ATKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > atkbdmap.h" \ no-obj no-implicit-rule before-depend \ clean "atkbdmap.h" # ukbdmap.h optional ukbd_dflt_keymap \ compile-with "/usr/sbin/kbdcontrol -L ${UKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > ukbdmap.h" \ no-obj no-implicit-rule before-depend \ clean "ukbdmap.h" # compat/linux/linux_file.c optional compat_linux compat/linux/linux_ioctl.c optional compat_linux compat/linux/linux_ipc.c optional compat_linux compat/linux/linux_mib.c optional compat_linux compat/linux/linux_misc.c optional compat_linux compat/linux/linux_signal.c optional compat_linux compat/linux/linux_socket.c optional compat_linux compat/linux/linux_stats.c optional compat_linux compat/linux/linux_util.c optional compat_linux # contrib/dev/fla/fla.c optional fla msysosak.o optional fla \ dependency "$S/contrib/dev/fla/i386/msysosak.o.uu" \ compile-with "uudecode < $S/contrib/dev/fla/i386/msysosak.o.uu" \ no-implicit-rule # contrib/dev/oltr/if_oltr.c optional oltr trlld.o optional oltr \ dependency "$S/contrib/dev/oltr/i386${FMT}.trlld.o.uu" \ compile-with "uudecode < $S/contrib/dev/oltr/i386${FMT}.trlld.o.uu" \ no-implicit-rule contrib/dev/oltr/trlldbm.c optional oltr contrib/dev/oltr/trlldhm.c optional oltr contrib/dev/oltr/trlldmac.c optional oltr crypto/des/des_ecb.c optional netsmbcrypto crypto/des/des_setkey.c optional netsmbcrypto dev/advansys/adv_isa.c optional adv isa dev/aic/aic_isa.c optional aic isa dev/ata/ata-all.c optional ata dev/ata/ata-dma.c optional ata dev/ata/ata-disk.c optional atadisk dev/ata/ata-raid.c optional atadisk dev/ata/atapi-all.c optional atapicd dev/ata/atapi-all.c optional atapifd dev/ata/atapi-all.c optional atapist dev/ata/atapi-cd.c optional atapicd dev/ata/atapi-fd.c optional atapifd dev/ata/atapi-tape.c optional atapist dev/ed/if_ed.c optional ed dev/ed/if_ed_isa.c optional ed isa dev/ed/if_ed_pccard.c optional ed card dev/eisa/eisaconf.c optional eisa dev/fb/fb.c optional fb dev/fb/fb.c optional vga dev/fb/splash.c optional splash dev/fb/vga.c optional vga dev/fe/if_fe_isa.c optional fe isa dev/kbd/atkbd.c optional atkbd dev/kbd/atkbdc.c optional atkbdc dev/kbd/kbd.c optional atkbd dev/kbd/kbd.c optional kbd dev/kbd/kbd.c optional sc dev/kbd/kbd.c optional ukbd dev/kbd/kbd.c optional vt dev/syscons/schistory.c optional sc dev/syscons/scmouse.c optional sc dev/syscons/scterm.c optional sc dev/syscons/scterm-dumb.c optional sc dev/syscons/scterm-sc.c optional sc dev/syscons/scvesactl.c optional sc vga vesa dev/syscons/scvgarndr.c optional sc vga dev/syscons/scvidctl.c optional sc dev/syscons/scvtb.c optional sc dev/syscons/syscons.c optional sc dev/syscons/sysmouse.c optional sc fs/smbfs/smbfs_io.c optional smbfs fs/smbfs/smbfs_node.c optional smbfs fs/smbfs/smbfs_smb.c optional smbfs fs/smbfs/smbfs_subr.c optional smbfs fs/smbfs/smbfs_vfsops.c optional smbfs fs/smbfs/smbfs_vnops.c optional smbfs gnu/i386/fpemul/div_small.s optional gpl_math_emulate gnu/i386/fpemul/errors.c optional gpl_math_emulate gnu/i386/fpemul/fpu_arith.c optional gpl_math_emulate gnu/i386/fpemul/fpu_aux.c optional gpl_math_emulate gnu/i386/fpemul/fpu_entry.c optional gpl_math_emulate gnu/i386/fpemul/fpu_etc.c optional gpl_math_emulate gnu/i386/fpemul/fpu_trig.c optional gpl_math_emulate gnu/i386/fpemul/get_address.c optional gpl_math_emulate gnu/i386/fpemul/load_store.c optional gpl_math_emulate gnu/i386/fpemul/poly_2xm1.c optional gpl_math_emulate gnu/i386/fpemul/poly_atan.c optional gpl_math_emulate gnu/i386/fpemul/poly_div.s optional gpl_math_emulate gnu/i386/fpemul/poly_l2.c optional gpl_math_emulate gnu/i386/fpemul/poly_mul64.s optional gpl_math_emulate gnu/i386/fpemul/poly_sin.c optional gpl_math_emulate gnu/i386/fpemul/poly_tan.c optional gpl_math_emulate gnu/i386/fpemul/polynomial.s optional gpl_math_emulate gnu/i386/fpemul/reg_add_sub.c optional gpl_math_emulate gnu/i386/fpemul/reg_compare.c optional gpl_math_emulate gnu/i386/fpemul/reg_constant.c optional gpl_math_emulate gnu/i386/fpemul/reg_div.s optional gpl_math_emulate gnu/i386/fpemul/reg_ld_str.c optional gpl_math_emulate gnu/i386/fpemul/reg_mul.c optional gpl_math_emulate gnu/i386/fpemul/reg_norm.s optional gpl_math_emulate gnu/i386/fpemul/reg_round.s optional gpl_math_emulate gnu/i386/fpemul/reg_u_add.s optional gpl_math_emulate gnu/i386/fpemul/reg_u_div.s optional gpl_math_emulate gnu/i386/fpemul/reg_u_mul.s optional gpl_math_emulate gnu/i386/fpemul/reg_u_sub.s optional gpl_math_emulate gnu/i386/fpemul/wm_shrx.s optional gpl_math_emulate gnu/i386/fpemul/wm_sqrt.s optional gpl_math_emulate gnu/i386/isa/dgb.c optional dgb gnu/i386/isa/dgm.c optional dgm gnu/i386/isa/sound/awe_wave.c optional awe i386/apm/apm.c optional apm i386/i386/atomic.c standard \ compile-with "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}" i386/i386/autoconf.c standard i386/i386/bios.c standard i386/i386/bioscall.s standard i386/i386/busdma_machdep.c standard i386/i386/db_disasm.c optional ddb i386/i386/db_interface.c optional ddb i386/i386/db_trace.c optional ddb i386/i386/elf_machdep.c standard i386/i386/exception.s standard i386/i386/globals.s standard i386/i386/i386-gdbstub.c optional ddb i386/i386/i686_mem.c standard i386/i386/identcpu.c standard i386/i386/in_cksum.c optional inet i386/i386/initcpu.c standard i386/i386/k6_mem.c standard # locore.s needs to be handled in Makefile to put it first. Otherwise it's # now normal. # i386/i386/locore.s standard i386/i386/machdep.c standard i386/i386/math_emulate.c optional math_emulate i386/i386/mem.c standard i386/i386/mp_clock.c optional smp i386/i386/mp_machdep.c optional smp i386/i386/mpapic.c optional smp i386/i386/mpboot.s optional smp i386/i386/mplock.s optional smp i386/i386/nexus.c standard i386/i386/perfmon.c optional perfmon i386/i386/perfmon.c optional perfmon profiling-routine i386/i386/pmap.c standard i386/i386/procfs_machdep.c standard i386/i386/simplelock.s optional smp i386/i386/support.s standard i386/i386/swtch.s standard i386/i386/sys_machdep.c standard i386/i386/trap.c standard i386/i386/userconfig.c optional userconfig i386/i386/vm86.c standard i386/i386/vm_machdep.c standard i386/ibcs2/ibcs2_errno.c optional ibcs2 i386/ibcs2/ibcs2_fcntl.c optional ibcs2 i386/ibcs2/ibcs2_ioctl.c optional ibcs2 i386/ibcs2/ibcs2_ipc.c optional ibcs2 i386/ibcs2/ibcs2_isc.c optional ibcs2 i386/ibcs2/ibcs2_isc_sysent.c optional ibcs2 i386/ibcs2/ibcs2_misc.c optional ibcs2 i386/ibcs2/ibcs2_msg.c optional ibcs2 i386/ibcs2/ibcs2_other.c optional ibcs2 i386/ibcs2/ibcs2_signal.c optional ibcs2 i386/ibcs2/ibcs2_socksys.c optional ibcs2 i386/ibcs2/ibcs2_stat.c optional ibcs2 i386/ibcs2/ibcs2_sysent.c optional ibcs2 i386/ibcs2/ibcs2_sysi86.c optional ibcs2 i386/ibcs2/ibcs2_sysvec.c optional ibcs2 i386/ibcs2/ibcs2_util.c optional ibcs2 i386/ibcs2/ibcs2_xenix.c optional ibcs2 i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2 i386/ibcs2/imgact_coff.c optional ibcs2 i386/isa/asc.c optional asc i386/isa/atapi.c optional wdc \ warning "The wdc driver is obsolete. Please use the ata driver!" i386/isa/clock.c standard i386/isa/cronyx.c optional cx i386/isa/ctx.c optional ctx i386/isa/cx.c optional cx i386/isa/cy.c optional cy i386/isa/elink.c optional ep i386/isa/elink.c optional ie isa/fd.c optional fd i386/isa/gpib.c optional gp i386/isa/gsc.c optional gsc i386/isa/if_ar.c optional ar i386/isa/if_cx.c optional cx i386/isa/if_el.c optional el i386/isa/if_le.c optional le i386/isa/if_lnc.c optional lnc i386/isa/if_rdp.c optional rdp i386/isa/if_sr.c optional sr -i386/isa/if_wi.c optional wi card +i386/isa/if_wi.c optional wi i386/isa/if_wl.c optional wl i386/isa/if_wlp.c optional wlp i386/isa/intr_machdep.c standard i386/isa/ipl_funcs.c standard \ compile-with "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}" i386/isa/isa.c optional isa i386/isa/isa_compat.c optional isa i386/isa/isa_dma.c optional isa i386/isa/istallion.c optional stli i386/isa/labpc.c optional labpc i386/isa/loran.c optional loran i386/isa/matcd/matcd.c optional matcd i386/isa/mca_machdep.c optional mca i386/isa/mcd.c optional mcd i386/isa/mse.c optional mse i386/isa/npx.c mandatory npx i386/isa/pcaudio.c optional pca i386/isa/pcf.c optional pcf i386/isa/pci_cfgreg.c optional pci i386/isa/pcibus.c optional pci i386/isa/pcvt/pcvt_drv.c optional vt i386/isa/pcvt/pcvt_ext.c optional vt i386/isa/pcvt/pcvt_kbd.c optional vt i386/isa/pcvt/pcvt_out.c optional vt i386/isa/pcvt/pcvt_sup.c optional vt i386/isa/pcvt/pcvt_vtf.c optional vt i386/isa/prof_machdep.c optional profiling-routine i386/isa/rc.c optional rc i386/isa/rp.c optional rp i386/isa/scd.c optional scd i386/isa/sound/ad1848.c optional css i386/isa/sound/ad1848.c optional gus i386/isa/sound/ad1848.c optional gusxvi i386/isa/sound/ad1848.c optional mss i386/isa/sound/ad1848.c optional sscape i386/isa/sound/ad1848.c optional trix i386/isa/sound/ad1848.c optional sscape_mss i386/isa/sound/adlib_card.c optional opl i386/isa/sound/adlib_card.c optional trix i386/isa/sound/audio.c optional snd \ warning "The snd drivers are deprecated. Please see pcm/sbc/etc." i386/isa/sound/cs4232.c optional css i386/isa/sound/dev_table.c optional snd i386/isa/sound/dmabuf.c optional snd i386/isa/sound/gus_card.c optional gus i386/isa/sound/gus_midi.c optional gus i386/isa/sound/gus_vol.c optional gus i386/isa/sound/gus_wave.c optional gus i386/isa/sound/ics2101.c optional gus i386/isa/sound/midi_synth.c optional css i386/isa/sound/midi_synth.c optional gus i386/isa/sound/midi_synth.c optional mpu i386/isa/sound/midi_synth.c optional mss i386/isa/sound/midi_synth.c optional pas i386/isa/sound/midi_synth.c optional sb i386/isa/sound/midi_synth.c optional sscape i386/isa/sound/midi_synth.c optional uart i386/isa/sound/midibuf.c optional css i386/isa/sound/midibuf.c optional gus i386/isa/sound/midibuf.c optional mpu i386/isa/sound/midibuf.c optional mss i386/isa/sound/midibuf.c optional pas i386/isa/sound/midibuf.c optional sb i386/isa/sound/midibuf.c optional sscape i386/isa/sound/midibuf.c optional uart i386/isa/sound/mpu401.c optional mpu i386/isa/sound/mpu401.c optional sscape i386/isa/sound/opl3.c optional opl i386/isa/sound/opl3.c optional trix i386/isa/sound/pas2_card.c optional pas i386/isa/sound/pas2_midi.c optional pas i386/isa/sound/pas2_mixer.c optional pas i386/isa/sound/pas2_pcm.c optional pas i386/isa/sound/patmgr.c optional snd i386/isa/sound/sb16_dsp.c optional sbxvi i386/isa/sound/sb16_midi.c optional sbmidi i386/isa/sound/sb_card.c optional sb i386/isa/sound/sb_dsp.c optional sb i386/isa/sound/sb_midi.c optional sb i386/isa/sound/sb_mixer.c optional sb i386/isa/sound/sequencer.c optional snd i386/isa/sound/sound_switch.c optional snd i386/isa/sound/sound_timer.c optional css i386/isa/sound/sound_timer.c optional gus i386/isa/sound/sound_timer.c optional mss i386/isa/sound/sound_timer.c optional mss i386/isa/sound/sound_timer.c optional sscape i386/isa/sound/sound_timer.c optional trix i386/isa/sound/soundcard.c optional snd i386/isa/sound/sscape.c optional sscape i386/isa/sound/sys_timer.c optional snd i386/isa/sound/trix.c optional trix i386/isa/sound/uart6850.c optional uart i386/isa/spigot.c optional spigot i386/isa/spkr.c optional speaker i386/isa/stallion.c optional stl i386/isa/tw.c optional tw i386/isa/vesa.c optional vga vesa i386/isa/wd.c optional wd \ warning "The wd driver is obsolete. Please use the atadisk driver!" i386/isa/wd.c optional wdc i386/isa/wd_cd.c optional wcd wdc \ warning "The wcd driver is obsolete. Please use the atapicd driver!" i386/isa/wfd.c optional wfd wdc \ warning "The wfd driver is obsolete. Please use the atapifd driver!" i386/isa/wst.c optional wst wdc \ warning "The wst driver is obsolete. Please use the atapist driver!" i386/isa/wt.c optional wt i386/linux/imgact_linux.c optional compat_linux i386/linux/linux_dummy.c optional compat_linux i386/linux/linux_locore.s optional compat_linux \ dependency "linux_assym.h" i386/linux/linux_machdep.c optional compat_linux i386/linux/linux_sysent.c optional compat_linux i386/linux/linux_sysvec.c optional compat_linux svr4/imgact_svr4.c optional compat_svr4 svr4/svr4_fcntl.c optional compat_svr4 svr4/svr4_filio.c optional compat_svr4 svr4/svr4_ioctl.c optional compat_svr4 svr4/svr4_ipc.c optional compat_svr4 svr4/svr4_misc.c optional compat_svr4 svr4/svr4_resource.c optional compat_svr4 svr4/svr4_signal.c optional compat_svr4 svr4/svr4_socket.c optional compat_svr4 svr4/svr4_sockio.c optional compat_svr4 svr4/svr4_stat.c optional compat_svr4 svr4/svr4_stream.c optional compat_svr4 svr4/svr4_syscallnames.c optional compat_svr4 svr4/svr4_sysent.c optional compat_svr4 svr4/svr4_sysvec.c optional compat_svr4 svr4/svr4_termios.c optional compat_svr4 svr4/svr4_ttold.c optional compat_svr4 i386/svr4/svr4_locore.s optional compat_svr4 \ dependency "svr4_assym.h" i386/svr4/svr4_machdep.c optional compat_svr4 # # isdn4bsd, needed for isic | iwic | ifpi | ihfc | ifpnp | itjc # i4b/layer1/i4b_l1dmux.c optional isic i4b/layer1/i4b_l1lib.c optional isic i4b/layer1/i4b_l1dmux.c optional iwic i4b/layer1/i4b_l1lib.c optional iwic i4b/layer1/i4b_l1dmux.c optional ifpi i4b/layer1/i4b_l1lib.c optional ifpi i4b/layer1/i4b_l1dmux.c optional ihfc i4b/layer1/i4b_l1lib.c optional ihfc i4b/layer1/i4b_l1dmux.c optional ifpnp i4b/layer1/i4b_l1lib.c optional ifpnp i4b/layer1/i4b_l1dmux.c optional itjc i4b/layer1/i4b_l1lib.c optional itjc # # isdn4bsd, isic # i4b/layer1/isic/i4b_asuscom_ipac.c optional isic i4b/layer1/isic/i4b_avm_a1.c optional isic i4b/layer1/isic/i4b_bchan.c optional isic i4b/layer1/isic/i4b_ctx_s0P.c optional isic i4b/layer1/isic/i4b_drn_ngo.c optional isic i4b/layer1/isic/i4b_dynalink.c optional isic i4b/layer1/isic/i4b_elsa_qs1i.c optional isic i4b/layer1/isic/i4b_elsa_qs1p.c optional isic i4b/layer1/isic/i4b_elsa_pcc16.c optional isic i4b/layer1/isic/i4b_hscx.c optional isic i4b/layer1/isic/i4b_isac.c optional isic i4b/layer1/isic/i4b_isic.c optional isic i4b/layer1/isic/i4b_isic_isa.c optional isic i4b/layer1/isic/i4b_isic_pnp.c optional isic i4b/layer1/isic/i4b_itk_ix1.c optional isic i4b/layer1/isic/i4b_l1.c optional isic i4b/layer1/isic/i4b_l1fsm.c optional isic i4b/layer1/isic/i4b_siemens_isurf.c optional isic i4b/layer1/isic/i4b_sws.c optional isic i4b/layer1/isic/i4b_tel_s016.c optional isic i4b/layer1/isic/i4b_tel_s0163.c optional isic i4b/layer1/isic/i4b_tel_s08.c optional isic i4b/layer1/isic/i4b_usr_sti.c optional isic i4b/layer1/isic/i4b_diva.c optional isic # # isdn4bsd, iwic # i4b/layer1/iwic/i4b_iwic_pci.c optional iwic i4b/layer1/iwic/i4b_iwic_dchan.c optional iwic i4b/layer1/iwic/i4b_iwic_bchan.c optional iwic i4b/layer1/iwic/i4b_iwic_fsm.c optional iwic i4b/layer1/iwic/i4b_iwic_l1if.c optional iwic # # isdn4bsd, ifpi # i4b/layer1/ifpi/i4b_ifpi_pci.c optional ifpi i4b/layer1/ifpi/i4b_ifpi_isac.c optional ifpi i4b/layer1/ifpi/i4b_ifpi_l1.c optional ifpi i4b/layer1/ifpi/i4b_ifpi_l1fsm.c optional ifpi # # isdn4bsd, ifpnp # i4b/layer1/ifpnp/i4b_ifpnp_avm.c optional ifpnp i4b/layer1/ifpnp/i4b_ifpnp_isac.c optional ifpnp i4b/layer1/ifpnp/i4b_ifpnp_l1.c optional ifpnp i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c optional ifpnp # # isdn4bsd, ihfc # i4b/layer1/ihfc/i4b_ihfc_l1if.c optional ihfc i4b/layer1/ihfc/i4b_ihfc_pnp.c optional ihfc i4b/layer1/ihfc/i4b_ihfc_drv.c optional ihfc # # isdn4bsd, itjc # i4b/layer1/itjc/i4b_itjc_pci.c optional itjc i4b/layer1/itjc/i4b_itjc_isac.c optional itjc i4b/layer1/itjc/i4b_itjc_l1.c optional itjc i4b/layer1/itjc/i4b_itjc_l1fsm.c optional itjc # isa/atkbd_isa.c optional atkbd isa/atkbdc_isa.c optional atkbdc isa/ppc.c optional ppc isa/psm.c optional psm isa/sio.c optional sio isa/syscons_isa.c optional sc isa/vga_isa.c optional vga kern/md4c.c optional netsmb kern/subr_diskmbr.c standard libkern/divdi3.c standard libkern/moddi3.c standard libkern/qdivrem.c standard libkern/udivdi3.c standard libkern/umoddi3.c standard netsmb/smb_conn.c optional netsmb netsmb/smb_crypt.c optional netsmb netsmb/smb_dev.c optional netsmb netsmb/smb_iod.c optional netsmb netsmb/smb_rq.c optional netsmb netsmb/smb_smb.c optional netsmb netsmb/smb_subr.c optional netsmb netsmb/smb_trantcp.c optional netsmb netsmb/smb_usr.c optional netsmb pci/ide_pci.c optional wdc pci Index: stable/4/sys/i386/isa/if_wi.c =================================================================== --- stable/4/sys/i386/isa/if_wi.c (revision 82305) +++ stable/4/sys/i386/isa/if_wi.c (revision 82306) @@ -1,2301 +1,2331 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD. * * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ /* * The WaveLAN/IEEE adapter is the second generation of the WaveLAN * from Lucent. Unlike the older cards, the new ones are programmed * entirely via a firmware-driven controller called the Hermes. * Unfortunately, Lucent will not release the Hermes programming manual * without an NDA (if at all). What they do release is an API library * called the HCF (Hardware Control Functions) which is supposed to * do the device-specific operations of a device driver for you. The * publically available version of the HCF library (the 'HCF Light') is * a) extremely gross, b) lacks certain features, particularly support * for 802.11 frames, and c) is contaminated by the GNU Public License. * * This driver does not use the HCF or HCF Light at all. Instead, it * programs the Hermes controller directly, using information gleaned * from the HCF Light code and corresponding documentation. * * This driver supports both the PCMCIA and ISA versions of the * WaveLAN/IEEE cards. Note however that the ISA card isn't really * anything of the sort: it's actually a PCMCIA bridge adapter * that fits into an ISA slot, into which a PCMCIA WaveLAN card is * inserted. Consequently, you need to use the pccard support for * both the ISA and PCMCIA adapters. */ #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */ #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */ #define WICACHE /* turn on signal strength cache code */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(lint) static const char rcsid[] = "$FreeBSD$"; #endif #ifdef foo static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 }; #endif static void wi_intr __P((void *)); static void wi_reset __P((struct wi_softc *)); static int wi_ioctl __P((struct ifnet *, u_long, caddr_t)); static void wi_init __P((void *)); static void wi_start __P((struct ifnet *)); static void wi_stop __P((struct wi_softc *)); static void wi_watchdog __P((struct ifnet *)); static void wi_rxeof __P((struct wi_softc *)); static void wi_txeof __P((struct wi_softc *, int)); static void wi_update_stats __P((struct wi_softc *)); static void wi_setmulti __P((struct wi_softc *)); static int wi_cmd __P((struct wi_softc *, int, int)); static int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *)); static int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *)); static int wi_read_data __P((struct wi_softc *, int, int, caddr_t, int)); static int wi_write_data __P((struct wi_softc *, int, int, caddr_t, int)); static int wi_seek __P((struct wi_softc *, int, int, int)); static int wi_alloc_nicmem __P((struct wi_softc *, int, int *)); static void wi_inquire __P((void *)); static void wi_setdef __P((struct wi_softc *, struct wi_req *)); static int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int)); #ifdef WICACHE static void wi_cache_store __P((struct wi_softc *, struct ether_header *, struct mbuf *, unsigned short)); #endif static int wi_generic_attach __P((device_t)); static int wi_pccard_probe __P((device_t)); static int wi_pci_probe __P((device_t)); static int wi_pccard_attach __P((device_t)); static int wi_pci_attach __P((device_t)); static int wi_pccard_detach __P((device_t)); static void wi_shutdown __P((device_t)); static int wi_alloc __P((device_t, int)); static void wi_free __P((device_t)); static int wi_get_cur_ssid __P((struct wi_softc *, char *, int *)); static int wi_media_change __P((struct ifnet *)); static void wi_media_status __P((struct ifnet *, struct ifmediareq *)); static device_method_t wi_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, wi_pccard_probe), DEVMETHOD(device_attach, wi_pccard_attach), DEVMETHOD(device_detach, wi_pccard_detach), DEVMETHOD(device_shutdown, wi_shutdown), { 0, 0 } }; static device_method_t wi_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, wi_pci_probe), DEVMETHOD(device_attach, wi_pci_attach), DEVMETHOD(device_detach, wi_pccard_detach), DEVMETHOD(device_shutdown, wi_shutdown), { 0, 0 } }; static driver_t wi_pccard_driver = { "wi", wi_pccard_methods, sizeof(struct wi_softc) }; static driver_t wi_pci_driver = { "wi", wi_pci_methods, sizeof(struct wi_softc) }; +static struct { + unsigned int vendor,device; + char *desc; +} pci_ids[] = { + {0x1638, 0x1100, "PRISM2STA PCI WaveLAN/IEEE 802.11"}, + {0x1385, 0x4100, "Netgear MA301 PCI IEEE 802.11b"}, + {0, 0, NULL} +}; + static devclass_t wi_pccard_devclass; static devclass_t wi_pci_devclass; DRIVER_MODULE(if_wi, pccard, wi_pccard_driver, wi_pccard_devclass, 0, 0); DRIVER_MODULE(if_wi, pci, wi_pci_driver, wi_pci_devclass, 0, 0); static char wi_device_desc[] = "WaveLAN/IEEE 802.11"; static int wi_pccard_probe(dev) device_t dev; { struct wi_softc *sc; int error; sc = device_get_softc(dev); sc->wi_gone = 0; error = wi_alloc(dev, 0); if (error) return (error); device_set_desc(dev, wi_device_desc); wi_free(dev); /* Make sure interrupts are disabled. */ CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); return (0); } static int wi_pci_probe(dev) device_t dev; { struct wi_softc *sc; + int i; sc = device_get_softc(dev); - if ((pci_get_vendor(dev) == WI_PCI_VENDOR_EUMITCOM) && - (pci_get_device(dev) == WI_PCI_DEVICE_PRISM2STA)) { + for(i=0; pci_ids[i].vendor != 0; i++) { + if ((pci_get_vendor(dev) == pci_ids[i].vendor) && + (pci_get_device(dev) == pci_ids[i].device)) { sc->wi_prism2 = 1; - device_set_desc(dev, - "PRISM2STA PCI WaveLAN/IEEE 802.11"); + device_set_desc(dev, pci_ids[i].desc); return (0); + } } return(ENXIO); } static int wi_pccard_detach(dev) device_t dev; { struct wi_softc *sc; struct ifnet *ifp; int s; s = splimp(); sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; if (sc->wi_gone) { device_printf(dev, "already unloaded\n"); splx(s); return(ENODEV); } wi_stop(sc); /* Delete all remaining media. */ ifmedia_removeall(&sc->ifmedia); ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); wi_free(dev); sc->wi_gone = 1; splx(s); return(0); } static int wi_pccard_attach(device_t dev) { struct wi_softc *sc; int error; u_int32_t flags; sc = device_get_softc(dev); /* * XXX: quick hack to support Prism II chip. * Currently, we need to set a flags in pccard.conf to specify * which type chip is used. * * We need to replace this code in a future. * It is better to use CIS than using a flag. */ flags = device_get_flags(dev); #define WI_FLAGS_PRISM2 0x10000 if (flags & WI_FLAGS_PRISM2) { sc->wi_prism2 = 1; if (bootverbose) { device_printf(dev, "found PrismII chip\n"); } } else { sc->wi_prism2 = 0; if (bootverbose) { device_printf(dev, "found Lucent chip\n"); } } error = wi_alloc(dev, 0); if (error) { device_printf(dev, "wi_alloc() failed! (%d)\n", error); return (error); } return (wi_generic_attach(dev)); } static int wi_pci_attach(device_t dev) { struct wi_softc *sc; u_int32_t command, wanted; u_int16_t reg; int error; sc = device_get_softc(dev); command = pci_read_config(dev, PCIR_COMMAND, 4); wanted = PCIM_CMD_PORTEN|PCIM_CMD_MEMEN; command |= wanted; pci_write_config(dev, PCIR_COMMAND, command, 4); command = pci_read_config(dev, PCIR_COMMAND, 4); if ((command & wanted) != wanted) { device_printf(dev, "wi_pci_attach() failed to enable pci!\n"); return (ENXIO); } error = wi_alloc(dev, WI_PCI_IORES); if (error) return (error); - device_set_desc(dev, wi_device_desc); - /* Make sure interrupts are disabled. */ CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); + /* We have to do a magic PLX poke to enable interrupts */ + sc->local_rid = WI_PCI_LOCALRES; + sc->local = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->local_rid, + 0, ~0, 1, RF_ACTIVE); + sc->wi_localtag = rman_get_bustag(sc->local); + sc->wi_localhandle = rman_get_bushandle(sc->local); + command = bus_space_read_4(sc->wi_localtag, sc->wi_localhandle, + WI_LOCAL_INTCSR); + command |= WI_LOCAL_INTEN; + bus_space_write_4(sc->wi_localtag, sc->wi_localhandle, + WI_LOCAL_INTCSR, command); + bus_release_resource(dev, SYS_RES_IOPORT, sc->local_rid, sc->local); + sc->local = NULL; + sc->mem_rid = WI_PCI_MEMRES; sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, 0, ~0, 1, RF_ACTIVE); if (sc->mem == NULL) { device_printf(dev, "couldn't allocate memory\n"); wi_free(dev); return (ENXIO); } sc->wi_bmemtag = rman_get_bustag(sc->mem); sc->wi_bmemhandle = rman_get_bushandle(sc->mem); /* * From Linux driver: * Write COR to enable PC card * This is a subset of the protocol that the pccard bus code * would do. */ CSM_WRITE_1(sc, WI_COR_OFFSET, WI_COR_VALUE); reg = CSM_READ_1(sc, WI_COR_OFFSET); + if (reg != WI_COR_VALUE) { + device_printf(dev, + "CSM_READ_1(WI_COR_OFFSET) " + "wanted %d, got %d\n", WI_COR_VALUE, reg); + wi_free(dev); + return (ENXIO); + } CSR_WRITE_2(sc, WI_HFA384X_SWSUPPORT0_OFF, WI_PRISM2STA_MAGIC); reg = CSR_READ_2(sc, WI_HFA384X_SWSUPPORT0_OFF); if (reg != WI_PRISM2STA_MAGIC) { device_printf(dev, "CSR_READ_2(WI_HFA384X_SWSUPPORT0_OFF) " "wanted %d, got %d\n", WI_PRISM2STA_MAGIC, reg); wi_free(dev); return (ENXIO); } error = wi_generic_attach(dev); if (error != 0) return (error); return (0); } static int wi_generic_attach(device_t dev) { struct wi_softc *sc; struct wi_ltv_macaddr mac; struct wi_ltv_gen gen; struct ifnet *ifp; int error; sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, wi_intr, sc, &sc->wi_intrhand); if (error) { device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); wi_free(dev); return (error); } /* Reset the NIC. */ wi_reset(sc); /* * Read the station address. * And do it twice. I've seen PRISM-based cards that return * an error when trying to read it the first time, which causes * the probe to fail. */ mac.wi_type = WI_RID_MAC_NODE; mac.wi_len = 4; wi_read_record(sc, (struct wi_ltv_gen *)&mac); if ((error = wi_read_record(sc, (struct wi_ltv_gen *)&mac)) != 0) { device_printf(dev, "mac read failed %d\n", error); wi_free(dev); return (error); } bcopy((char *)&mac.wi_mac_addr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); device_printf(dev, "Ethernet address: %6D\n", sc->arpcom.ac_enaddr, ":"); ifp->if_softc = sc; ifp->if_unit = sc->wi_unit; ifp->if_name = "wi"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = wi_ioctl; ifp->if_output = ether_output; ifp->if_start = wi_start; ifp->if_watchdog = wi_watchdog; ifp->if_init = wi_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); bcopy(WI_DEFAULT_NODENAME, sc->wi_node_name, sizeof(WI_DEFAULT_NODENAME) - 1); bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); bcopy(WI_DEFAULT_NETNAME, sc->wi_net_name, sizeof(WI_DEFAULT_NETNAME) - 1); bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); bcopy(WI_DEFAULT_IBSS, sc->wi_ibss_name, sizeof(WI_DEFAULT_IBSS) - 1); sc->wi_portnum = WI_DEFAULT_PORT; sc->wi_ptype = WI_PORTTYPE_BSS; sc->wi_ap_density = WI_DEFAULT_AP_DENSITY; sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH; sc->wi_tx_rate = WI_DEFAULT_TX_RATE; sc->wi_max_data_len = WI_DEFAULT_DATALEN; sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS; sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED; sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP; /* * Read the default channel from the NIC. This may vary * depending on the country where the NIC was purchased, so * we can't hard-code a default and expect it to work for * everyone. */ gen.wi_type = WI_RID_OWN_CHNL; gen.wi_len = 2; wi_read_record(sc, &gen); sc->wi_channel = gen.wi_val; /* * Find out if we support WEP on this card. */ gen.wi_type = WI_RID_WEP_AVAIL; gen.wi_len = 2; wi_read_record(sc, &gen); sc->wi_has_wep = gen.wi_val; if (bootverbose) { device_printf(sc->dev, __FUNCTION__ ":wi_has_wep = %d\n", sc->wi_has_wep); } bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats)); wi_init(sc); wi_stop(sc); ifmedia_init(&sc->ifmedia, 0, wi_media_change, wi_media_status); /* XXX: Should read from card capabilities */ #define ADD(m, c) ifmedia_add(&sc->ifmedia, (m), (c), NULL) ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, IFM_IEEE80211_ADHOC, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, IFM_IEEE80211_ADHOC, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, IFM_IEEE80211_ADHOC, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, IFM_IEEE80211_ADHOC, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0); ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0); #undef ADD ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0)); /* * Call MI attach routine. */ ether_ifattach(ifp, ETHER_BPF_SUPPORTED); callout_handle_init(&sc->wi_stat_ch); return(0); } static void wi_rxeof(sc) struct wi_softc *sc; { struct ifnet *ifp; struct ether_header *eh; struct wi_frame rx_frame; struct mbuf *m; int id; ifp = &sc->arpcom.ac_if; id = CSR_READ_2(sc, WI_RX_FID); /* First read in the frame header */ if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { ifp->if_ierrors++; return; } if (rx_frame.wi_status & WI_STAT_ERRSTAT) { ifp->if_ierrors++; return; } MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { ifp->if_ierrors++; return; } MCLGET(m, M_DONTWAIT); if (!(m->m_flags & M_EXT)) { m_freem(m); ifp->if_ierrors++; return; } eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp; if (rx_frame.wi_status == WI_STAT_1042 || rx_frame.wi_status == WI_STAT_TUNNEL || rx_frame.wi_status == WI_STAT_WMP_MSG) { if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) { device_printf(sc->dev, "oversized packet received " "(wi_dat_len=%d, wi_status=0x%x)\n", rx_frame.wi_dat_len, rx_frame.wi_status); m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.len = m->m_len = rx_frame.wi_dat_len + WI_SNAPHDR_LEN; #if 0 bcopy((char *)&rx_frame.wi_addr1, (char *)&eh->ether_dhost, ETHER_ADDR_LEN); if (sc->wi_ptype == WI_PORTTYPE_ADHOC) { bcopy((char *)&rx_frame.wi_addr2, (char *)&eh->ether_shost, ETHER_ADDR_LEN); } else { bcopy((char *)&rx_frame.wi_addr3, (char *)&eh->ether_shost, ETHER_ADDR_LEN); } #else bcopy((char *)&rx_frame.wi_dst_addr, (char *)&eh->ether_dhost, ETHER_ADDR_LEN); bcopy((char *)&rx_frame.wi_src_addr, (char *)&eh->ether_shost, ETHER_ADDR_LEN); #endif bcopy((char *)&rx_frame.wi_type, (char *)&eh->ether_type, ETHER_TYPE_LEN); if (wi_read_data(sc, id, WI_802_11_OFFSET, mtod(m, caddr_t) + sizeof(struct ether_header), m->m_len + 2)) { m_freem(m); ifp->if_ierrors++; return; } } else { if((rx_frame.wi_dat_len + sizeof(struct ether_header)) > MCLBYTES) { device_printf(sc->dev, "oversized packet received " "(wi_dat_len=%d, wi_status=0x%x)\n", rx_frame.wi_dat_len, rx_frame.wi_status); m_freem(m); ifp->if_ierrors++; return; } m->m_pkthdr.len = m->m_len = rx_frame.wi_dat_len + sizeof(struct ether_header); if (wi_read_data(sc, id, WI_802_3_OFFSET, mtod(m, caddr_t), m->m_len + 2)) { m_freem(m); ifp->if_ierrors++; return; } } ifp->if_ipackets++; /* Receive packet. */ m_adj(m, sizeof(struct ether_header)); #ifdef WICACHE wi_cache_store(sc, eh, m, rx_frame.wi_q_info); #endif ether_input(ifp, eh, m); } static void wi_txeof(sc, status) struct wi_softc *sc; int status; { struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; if (status & WI_EV_TX_EXC) ifp->if_oerrors++; else ifp->if_opackets++; return; } void wi_inquire(xsc) void *xsc; { struct wi_softc *sc; struct ifnet *ifp; sc = xsc; ifp = &sc->arpcom.ac_if; sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); /* Don't do this while we're transmitting */ if (ifp->if_flags & IFF_OACTIVE) return; wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS); return; } void wi_update_stats(sc) struct wi_softc *sc; { struct wi_ltv_gen gen; u_int16_t id; struct ifnet *ifp; u_int32_t *ptr; int len, i; u_int16_t t; ifp = &sc->arpcom.ac_if; id = CSR_READ_2(sc, WI_INFO_FID); wi_read_data(sc, id, 0, (char *)&gen, 4); if (gen.wi_type != WI_INFO_COUNTERS) return; len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ? gen.wi_len - 1 : sizeof(sc->wi_stats) / 4; ptr = (u_int32_t *)&sc->wi_stats; for (i = 0; i < len - 1; i++) { t = CSR_READ_2(sc, WI_DATA1); #ifdef WI_HERMES_STATS_WAR if (t > 0xF000) t = ~t & 0xFFFF; #endif ptr[i] += t; } ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + sc->wi_stats.wi_tx_multi_retries + sc->wi_stats.wi_tx_retry_limit; return; } static void wi_intr(xsc) void *xsc; { struct wi_softc *sc = xsc; struct ifnet *ifp; u_int16_t status; ifp = &sc->arpcom.ac_if; if (sc->wi_gone || !(ifp->if_flags & IFF_UP)) { CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); CSR_WRITE_2(sc, WI_INT_EN, 0); return; } /* Disable interrupts. */ CSR_WRITE_2(sc, WI_INT_EN, 0); status = CSR_READ_2(sc, WI_EVENT_STAT); CSR_WRITE_2(sc, WI_EVENT_ACK, ~WI_INTRS); if (status & WI_EV_RX) { wi_rxeof(sc); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); } if (status & WI_EV_TX) { wi_txeof(sc, status); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX); } if (status & WI_EV_ALLOC) { int id; id = CSR_READ_2(sc, WI_ALLOC_FID); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); if (id == sc->wi_tx_data_id) wi_txeof(sc, status); } if (status & WI_EV_INFO) { wi_update_stats(sc); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); } if (status & WI_EV_TX_EXC) { wi_txeof(sc, status); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC); } if (status & WI_EV_INFO_DROP) { CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO_DROP); } /* Re-enable interrupts. */ CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); if (ifp->if_snd.ifq_head != NULL) { wi_start(ifp); } return; } static int wi_cmd(sc, cmd, val) struct wi_softc *sc; int cmd; int val; { int i, s = 0; /* wait for the busy bit to clear */ for (i = 500; i > 0; i--) { /* 5s */ if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) { break; } DELAY(10*1000); /* 10 m sec */ } if (i == 0) { return(ETIMEDOUT); } CSR_WRITE_2(sc, WI_PARAM0, val); CSR_WRITE_2(sc, WI_PARAM1, 0); CSR_WRITE_2(sc, WI_PARAM2, 0); CSR_WRITE_2(sc, WI_COMMAND, cmd); for (i = 0; i < WI_TIMEOUT; i++) { /* * Wait for 'command complete' bit to be * set in the event status register. */ s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD; if (s) { /* Ack the event and read result code. */ s = CSR_READ_2(sc, WI_STATUS); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); #ifdef foo if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) return(EIO); #endif if (s & WI_STAT_CMD_RESULT) return(EIO); break; } } if (i == WI_TIMEOUT) { return(ETIMEDOUT); } return(0); } static void wi_reset(sc) struct wi_softc *sc; { #define WI_INIT_TRIES 5 int i; for (i = 0; i < WI_INIT_TRIES; i++) { if (wi_cmd(sc, WI_CMD_INI, 0) == 0) break; DELAY(50 * 1000); /* 50ms */ } if (i == WI_INIT_TRIES) device_printf(sc->dev, "init failed\n"); CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); /* Calibrate timer. */ WI_SETVAL(WI_RID_TICK_TIME, 8); return; } /* * Read an LTV record from the NIC. */ static int wi_read_record(sc, ltv) struct wi_softc *sc; struct wi_ltv_gen *ltv; { u_int16_t *ptr; int i, len, code; struct wi_ltv_gen *oltv, p2ltv; oltv = ltv; if (sc->wi_prism2) { switch (ltv->wi_type) { case WI_RID_ENCRYPTION: p2ltv.wi_type = WI_RID_P2_ENCRYPTION; p2ltv.wi_len = 2; ltv = &p2ltv; break; case WI_RID_TX_CRYPT_KEY: p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; p2ltv.wi_len = 2; ltv = &p2ltv; break; } } /* Tell the NIC to enter record read mode. */ if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type)) return(EIO); /* Seek to the record. */ if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) return(EIO); /* * Read the length and record type and make sure they * match what we expect (this verifies that we have enough * room to hold all of the returned data). */ len = CSR_READ_2(sc, WI_DATA1); if (len > ltv->wi_len) return(ENOSPC); code = CSR_READ_2(sc, WI_DATA1); if (code != ltv->wi_type) return(EIO); ltv->wi_len = len; ltv->wi_type = code; /* Now read the data. */ ptr = <v->wi_val; for (i = 0; i < ltv->wi_len - 1; i++) ptr[i] = CSR_READ_2(sc, WI_DATA1); if (sc->wi_prism2) { switch (oltv->wi_type) { case WI_RID_TX_RATE: case WI_RID_CUR_TX_RATE: switch (ltv->wi_val) { case 1: oltv->wi_val = 1; break; case 2: oltv->wi_val = 2; break; case 3: oltv->wi_val = 6; break; case 4: oltv->wi_val = 5; break; case 7: oltv->wi_val = 7; break; case 8: oltv->wi_val = 11; break; case 15: oltv->wi_val = 3; break; default: oltv->wi_val = 0x100 + ltv->wi_val; break; } break; case WI_RID_ENCRYPTION: oltv->wi_len = 2; if (ltv->wi_val & 0x01) oltv->wi_val = 1; else oltv->wi_val = 0; break; case WI_RID_TX_CRYPT_KEY: oltv->wi_len = 2; oltv->wi_val = ltv->wi_val; break; } } return(0); } /* * Same as read, except we inject data instead of reading it. */ static int wi_write_record(sc, ltv) struct wi_softc *sc; struct wi_ltv_gen *ltv; { u_int16_t *ptr; int i; struct wi_ltv_gen p2ltv; if (sc->wi_prism2) { switch (ltv->wi_type) { case WI_RID_TX_RATE: p2ltv.wi_type = WI_RID_TX_RATE; p2ltv.wi_len = 2; switch (ltv->wi_val) { case 1: p2ltv.wi_val = 1; break; case 2: p2ltv.wi_val = 2; break; case 3: p2ltv.wi_val = 15; break; case 5: p2ltv.wi_val = 4; break; case 6: p2ltv.wi_val = 3; break; case 7: p2ltv.wi_val = 7; break; case 11: p2ltv.wi_val = 8; break; default: return EINVAL; } ltv = &p2ltv; break; case WI_RID_ENCRYPTION: p2ltv.wi_type = WI_RID_P2_ENCRYPTION; p2ltv.wi_len = 2; if (ltv->wi_val) p2ltv.wi_val = 0x03; else p2ltv.wi_val = 0x90; ltv = &p2ltv; break; case WI_RID_TX_CRYPT_KEY: p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; p2ltv.wi_len = 2; p2ltv.wi_val = ltv->wi_val; ltv = &p2ltv; break; case WI_RID_DEFLT_CRYPT_KEYS: { int error; struct wi_ltv_str ws; struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv; for (i = 0; i < 4; i++) { ws.wi_len = 4; ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; memcpy(ws.wi_str, &wk->wi_keys[i].wi_keydat, 5); ws.wi_str[5] = '\0'; error = wi_write_record(sc, (struct wi_ltv_gen *)&ws); if (error) return error; } return 0; } } } if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) return(EIO); CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); ptr = <v->wi_val; for (i = 0; i < ltv->wi_len - 1; i++) CSR_WRITE_2(sc, WI_DATA1, ptr[i]); if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type)) return(EIO); return(0); } static int wi_seek(sc, id, off, chan) struct wi_softc *sc; int id, off, chan; { int i; int selreg, offreg; int status; switch (chan) { case WI_BAP0: selreg = WI_SEL0; offreg = WI_OFF0; break; case WI_BAP1: selreg = WI_SEL1; offreg = WI_OFF1; break; default: device_printf(sc->dev, "invalid data path: %x\n", chan); return(EIO); } CSR_WRITE_2(sc, selreg, id); CSR_WRITE_2(sc, offreg, off); for (i = 0; i < WI_TIMEOUT; i++) { status = CSR_READ_2(sc, offreg); if (!(status & (WI_OFF_BUSY|WI_OFF_ERR))) break; } if (i == WI_TIMEOUT) { device_printf(sc->dev, "timeout in wi_seek to %x/%x; last status %x\n", id, off, status); return(ETIMEDOUT); } return(0); } static int wi_read_data(sc, id, off, buf, len) struct wi_softc *sc; int id, off; caddr_t buf; int len; { int i; u_int16_t *ptr; if (wi_seek(sc, id, off, WI_BAP1)) return(EIO); ptr = (u_int16_t *)buf; for (i = 0; i < len / 2; i++) ptr[i] = CSR_READ_2(sc, WI_DATA1); return(0); } /* * According to the comments in the HCF Light code, there is a bug in * the Hermes (or possibly in certain Hermes firmware revisions) where * the chip's internal autoincrement counter gets thrown off during * data writes: the autoincrement is missed, causing one data word to * be overwritten and subsequent words to be written to the wrong memory * locations. The end result is that we could end up transmitting bogus * frames without realizing it. The workaround for this is to write a * couple of extra guard words after the end of the transfer, then * attempt to read then back. If we fail to locate the guard words where * we expect them, we preform the transfer over again. */ static int wi_write_data(sc, id, off, buf, len) struct wi_softc *sc; int id, off; caddr_t buf; int len; { int i; u_int16_t *ptr; #ifdef WI_HERMES_AUTOINC_WAR int retries; retries = 512; again: #endif if (wi_seek(sc, id, off, WI_BAP0)) return(EIO); ptr = (u_int16_t *)buf; for (i = 0; i < (len / 2); i++) CSR_WRITE_2(sc, WI_DATA0, ptr[i]); #ifdef WI_HERMES_AUTOINC_WAR CSR_WRITE_2(sc, WI_DATA0, 0x1234); CSR_WRITE_2(sc, WI_DATA0, 0x5678); if (wi_seek(sc, id, off + len, WI_BAP0)) return(EIO); if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || CSR_READ_2(sc, WI_DATA0) != 0x5678) { if (--retries >= 0) goto again; device_printf(sc->dev, "wi_write_data device timeout\n"); return (EIO); } #endif return(0); } /* * Allocate a region of memory inside the NIC and zero * it out. */ static int wi_alloc_nicmem(sc, len, id) struct wi_softc *sc; int len; int *id; { int i; if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) { device_printf(sc->dev, "failed to allocate %d bytes on NIC\n", len); return(ENOMEM); } for (i = 0; i < WI_TIMEOUT; i++) { if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) break; } if (i == WI_TIMEOUT) { device_printf(sc->dev, "time out allocating memory on card\n"); return(ETIMEDOUT); } CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); *id = CSR_READ_2(sc, WI_ALLOC_FID); if (wi_seek(sc, *id, 0, WI_BAP0)) { device_printf(sc->dev, "seek failed while allocating memory on card\n"); return(EIO); } for (i = 0; i < len / 2; i++) CSR_WRITE_2(sc, WI_DATA0, 0); return(0); } static void wi_setmulti(sc) struct wi_softc *sc; { struct ifnet *ifp; int i = 0; struct ifmultiaddr *ifma; struct wi_ltv_mcast mcast; ifp = &sc->arpcom.ac_if; bzero((char *)&mcast, sizeof(mcast)); mcast.wi_type = WI_RID_MCAST; mcast.wi_len = (3 * 16) + 1; if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { wi_write_record(sc, (struct wi_ltv_gen *)&mcast); return; } LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (i < 16) { bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), (char *)&mcast.wi_mcast[i], ETHER_ADDR_LEN); i++; } else { bzero((char *)&mcast, sizeof(mcast)); break; } } mcast.wi_len = (i * 3) + 1; wi_write_record(sc, (struct wi_ltv_gen *)&mcast); return; } static void wi_setdef(sc, wreq) struct wi_softc *sc; struct wi_req *wreq; { struct sockaddr_dl *sdl; struct ifaddr *ifa; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; switch(wreq->wi_type) { case WI_RID_MAC_NODE: ifa = ifnet_addrs[ifp->if_index - 1]; sdl = (struct sockaddr_dl *)ifa->ifa_addr; bcopy((char *)&wreq->wi_val, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN); break; case WI_RID_PORTTYPE: sc->wi_ptype = wreq->wi_val[0]; break; case WI_RID_TX_RATE: sc->wi_tx_rate = wreq->wi_val[0]; break; case WI_RID_MAX_DATALEN: sc->wi_max_data_len = wreq->wi_val[0]; break; case WI_RID_RTS_THRESH: sc->wi_rts_thresh = wreq->wi_val[0]; break; case WI_RID_SYSTEM_SCALE: sc->wi_ap_density = wreq->wi_val[0]; break; case WI_RID_CREATE_IBSS: sc->wi_create_ibss = wreq->wi_val[0]; break; case WI_RID_OWN_CHNL: sc->wi_channel = wreq->wi_val[0]; break; case WI_RID_NODENAME: bzero(sc->wi_node_name, sizeof(sc->wi_node_name)); bcopy((char *)&wreq->wi_val[1], sc->wi_node_name, 30); break; case WI_RID_DESIRED_SSID: bzero(sc->wi_net_name, sizeof(sc->wi_net_name)); bcopy((char *)&wreq->wi_val[1], sc->wi_net_name, 30); break; case WI_RID_OWN_SSID: bzero(sc->wi_ibss_name, sizeof(sc->wi_ibss_name)); bcopy((char *)&wreq->wi_val[1], sc->wi_ibss_name, 30); break; case WI_RID_PM_ENABLED: sc->wi_pm_enabled = wreq->wi_val[0]; break; case WI_RID_MAX_SLEEP: sc->wi_max_sleep = wreq->wi_val[0]; break; case WI_RID_ENCRYPTION: sc->wi_use_wep = wreq->wi_val[0]; break; case WI_RID_TX_CRYPT_KEY: sc->wi_tx_key = wreq->wi_val[0]; break; case WI_RID_DEFLT_CRYPT_KEYS: bcopy((char *)wreq, (char *)&sc->wi_keys, sizeof(struct wi_ltv_keys)); break; default: break; } /* Reinitialize WaveLAN. */ wi_init(sc); return; } static int wi_ioctl(ifp, command, data) struct ifnet *ifp; u_long command; caddr_t data; { int s, error = 0; int len; u_int8_t tmpkey[14]; char tmpssid[IEEE80211_NWID_LEN]; struct wi_softc *sc; struct wi_req wreq; struct ifreq *ifr; struct ieee80211req *ireq; struct proc *p = curproc; s = splimp(); sc = ifp->if_softc; ifr = (struct ifreq *)data; ireq = (struct ieee80211req *)data; if (sc->wi_gone) { error = ENODEV; goto out; } switch(command) { case SIOCSIFADDR: case SIOCGIFADDR: case SIOCSIFMTU: error = ether_ioctl(ifp, command, data); break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (ifp->if_flags & IFF_RUNNING && ifp->if_flags & IFF_PROMISC && !(sc->wi_if_flags & IFF_PROMISC)) { WI_SETVAL(WI_RID_PROMISC, 1); } else if (ifp->if_flags & IFF_RUNNING && !(ifp->if_flags & IFF_PROMISC) && sc->wi_if_flags & IFF_PROMISC) { WI_SETVAL(WI_RID_PROMISC, 0); } else wi_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) { wi_stop(sc); } } sc->wi_if_flags = ifp->if_flags; error = 0; break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; case SIOCADDMULTI: case SIOCDELMULTI: wi_setmulti(sc); error = 0; break; case SIOCGWAVELAN: error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); if (error) break; /* Don't show WEP keys to non-root users. */ if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS && suser(p)) break; if (wreq.wi_type == WI_RID_IFACE_STATS) { bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val, sizeof(sc->wi_stats)); wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1; } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) { bcopy((char *)&sc->wi_keys, (char *)&wreq, sizeof(struct wi_ltv_keys)); } #ifdef WICACHE else if (wreq.wi_type == WI_RID_ZERO_CACHE) { sc->wi_sigitems = sc->wi_nextitem = 0; } else if (wreq.wi_type == WI_RID_READ_CACHE) { char *pt = (char *)&wreq.wi_val; bcopy((char *)&sc->wi_sigitems, (char *)pt, sizeof(int)); pt += (sizeof (int)); wreq.wi_len = sizeof(int) / 2; bcopy((char *)&sc->wi_sigcache, (char *)pt, sizeof(struct wi_sigcache) * sc->wi_sigitems); wreq.wi_len += ((sizeof(struct wi_sigcache) * sc->wi_sigitems) / 2) + 1; } #endif else { if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) { error = EINVAL; break; } } error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); break; case SIOCSWAVELAN: if ((error = suser(p))) goto out; error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); if (error) break; if (wreq.wi_type == WI_RID_IFACE_STATS) { error = EINVAL; break; } else if (wreq.wi_type == WI_RID_MGMT_XMIT) { error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, wreq.wi_len); } else { error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); if (!error) wi_setdef(sc, &wreq); } break; case SIOCG80211: switch(ireq->i_type) { case IEEE80211_IOC_SSID: if(ireq->i_val == -1) { bzero(tmpssid, IEEE80211_NWID_LEN); error = wi_get_cur_ssid(sc, tmpssid, &len); if (error != 0) break; error = copyout(tmpssid, ireq->i_data, IEEE80211_NWID_LEN); ireq->i_len = len; } else if (ireq->i_val == 0) { error = copyout(sc->wi_net_name, ireq->i_data, IEEE80211_NWID_LEN); ireq->i_len = IEEE80211_NWID_LEN; } else error = EINVAL; break; case IEEE80211_IOC_NUMSSIDS: ireq->i_val = 1; break; case IEEE80211_IOC_WEP: if(!sc->wi_has_wep) { ireq->i_val = IEEE80211_WEP_NOSUP; } else { if(sc->wi_use_wep) { ireq->i_val = IEEE80211_WEP_MIXED; } else { ireq->i_val = IEEE80211_WEP_OFF; } } break; case IEEE80211_IOC_WEPKEY: if(!sc->wi_has_wep || ireq->i_val < 0 || ireq->i_val > 3) { error = EINVAL; break; } len = sc->wi_keys.wi_keys[ireq->i_val].wi_keylen; if (suser(p)) bcopy(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, tmpkey, len); else bzero(tmpkey, len); ireq->i_len = len; error = copyout(tmpkey, ireq->i_data, len); break; case IEEE80211_IOC_NUMWEPKEYS: if(!sc->wi_has_wep) error = EINVAL; else ireq->i_val = 4; break; case IEEE80211_IOC_WEPTXKEY: if(!sc->wi_has_wep) error = EINVAL; else ireq->i_val = sc->wi_tx_key; break; case IEEE80211_IOC_AUTHMODE: ireq->i_val = IEEE80211_AUTH_NONE; break; case IEEE80211_IOC_STATIONNAME: error = copyout(sc->wi_node_name, ireq->i_data, IEEE80211_NWID_LEN); ireq->i_len = IEEE80211_NWID_LEN; break; case IEEE80211_IOC_CHANNEL: wreq.wi_type = WI_RID_CURRENT_CHAN; wreq.wi_len = WI_MAX_DATALEN; if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) error = EINVAL; else { ireq->i_val = wreq.wi_val[0]; } break; case IEEE80211_IOC_POWERSAVE: if(sc->wi_pm_enabled) ireq->i_val = IEEE80211_POWERSAVE_ON; else ireq->i_val = IEEE80211_POWERSAVE_OFF; break; case IEEE80211_IOC_POWERSAVESLEEP: ireq->i_val = sc->wi_max_sleep; break; default: error = EINVAL; } break; case SIOCS80211: if ((error = suser(p))) goto out; switch(ireq->i_type) { case IEEE80211_IOC_SSID: if (ireq->i_val != 0 || ireq->i_len > IEEE80211_NWID_LEN) { error = EINVAL; break; } /* We set both of them */ bzero(sc->wi_net_name, IEEE80211_NWID_LEN); error = copyin(ireq->i_data, sc->wi_net_name, ireq->i_len); bcopy(sc->wi_net_name, sc->wi_ibss_name, IEEE80211_NWID_LEN); break; case IEEE80211_IOC_WEP: /* * These cards only support one mode so * we just turn wep on what ever is * passed in if it's not OFF. */ if (ireq->i_val == IEEE80211_WEP_OFF) { sc->wi_use_wep = 0; } else { sc->wi_use_wep = 1; } break; case IEEE80211_IOC_WEPKEY: if (ireq->i_val < 0 || ireq->i_val > 3 || ireq->i_len > 13) { error = EINVAL; break; } bzero(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 13); error = copyin(ireq->i_data, sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, ireq->i_len); if(error) break; sc->wi_keys.wi_keys[ireq->i_val].wi_keylen = ireq->i_len; break; case IEEE80211_IOC_WEPTXKEY: if (ireq->i_val < 0 || ireq->i_val > 3) { error = EINVAL; break; } sc->wi_tx_key = ireq->i_val; break; case IEEE80211_IOC_AUTHMODE: error = EINVAL; break; case IEEE80211_IOC_STATIONNAME: if (ireq->i_len > 32) { error = EINVAL; break; } bzero(sc->wi_node_name, 32); error = copyin(ireq->i_data, sc->wi_node_name, ireq->i_len); break; case IEEE80211_IOC_CHANNEL: /* * The actual range is 1-14, but if you * set it to 0 you get the default. So * we let that work too. */ if (ireq->i_val < 0 || ireq->i_val > 14) { error = EINVAL; break; } sc->wi_channel = ireq->i_val; break; case IEEE80211_IOC_POWERSAVE: switch (ireq->i_val) { case IEEE80211_POWERSAVE_OFF: sc->wi_pm_enabled = 0; break; case IEEE80211_POWERSAVE_ON: sc->wi_pm_enabled = 1; break; default: error = EINVAL; break; } break; case IEEE80211_IOC_POWERSAVESLEEP: if (ireq->i_val < 0) { error = EINVAL; break; } sc->wi_max_sleep = ireq->i_val; break; default: error = EINVAL; break; } /* Reinitialize WaveLAN. */ wi_init(sc); break; default: error = EINVAL; break; } out: splx(s); return(error); } static void wi_init(xsc) void *xsc; { struct wi_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; int s; struct wi_ltv_macaddr mac; int id = 0; if (sc->wi_gone) { return; } s = splimp(); if (ifp->if_flags & IFF_RUNNING) wi_stop(sc); wi_reset(sc); /* Program max data length. */ WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len); /* Enable/disable IBSS creation. */ WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss); /* Set the port type. */ WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype); /* Program the RTS/CTS threshold. */ WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh); /* Program the TX rate */ WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate); /* Access point density */ WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density); /* Power Management Enabled */ WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled); /* Power Managment Max Sleep */ WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep); /* Specify the IBSS name */ WI_SETSTR(WI_RID_OWN_SSID, sc->wi_ibss_name); /* Specify the network name */ WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name); /* Specify the frequency to use */ WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_channel); /* Program the nodename. */ WI_SETSTR(WI_RID_NODENAME, sc->wi_node_name); /* Set our MAC address. */ mac.wi_len = 4; mac.wi_type = WI_RID_MAC_NODE; bcopy((char *)&sc->arpcom.ac_enaddr, (char *)&mac.wi_mac_addr, ETHER_ADDR_LEN); wi_write_record(sc, (struct wi_ltv_gen *)&mac); /* Configure WEP. */ if (sc->wi_has_wep) { WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep); WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key); sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1; sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS; wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys); } /* Initialize promisc mode. */ if (ifp->if_flags & IFF_PROMISC) { WI_SETVAL(WI_RID_PROMISC, 1); } else { WI_SETVAL(WI_RID_PROMISC, 0); } /* Set multicast filter. */ wi_setmulti(sc); /* Enable desired port */ wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0); if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) device_printf(sc->dev, "tx buffer allocation failed\n"); sc->wi_tx_data_id = id; if (wi_alloc_nicmem(sc, ETHER_MAX_LEN + sizeof(struct wi_frame) + 8, &id)) device_printf(sc->dev, "mgmt. buffer allocation failed\n"); sc->wi_tx_mgmt_id = id; /* enable interrupts */ CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); splx(s); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; sc->wi_stat_ch = timeout(wi_inquire, sc, hz * 60); return; } static void wi_start(ifp) struct ifnet *ifp; { struct wi_softc *sc; struct mbuf *m0; struct wi_frame tx_frame; struct ether_header *eh; int id; sc = ifp->if_softc; if (sc->wi_gone) { return; } if (ifp->if_flags & IFF_OACTIVE) { return; } IF_DEQUEUE(&ifp->if_snd, m0); if (m0 == NULL) { return; } bzero((char *)&tx_frame, sizeof(tx_frame)); id = sc->wi_tx_data_id; eh = mtod(m0, struct ether_header *); /* * Use RFC1042 encoding for IP and ARP datagrams, * 802.3 for anything else. */ if (ntohs(eh->ether_type) > ETHER_MAX_LEN) { bcopy((char *)&eh->ether_dhost, (char *)&tx_frame.wi_addr1, ETHER_ADDR_LEN); bcopy((char *)&eh->ether_shost, (char *)&tx_frame.wi_addr2, ETHER_ADDR_LEN); bcopy((char *)&eh->ether_dhost, (char *)&tx_frame.wi_dst_addr, ETHER_ADDR_LEN); bcopy((char *)&eh->ether_shost, (char *)&tx_frame.wi_src_addr, ETHER_ADDR_LEN); tx_frame.wi_dat_len = m0->m_pkthdr.len - WI_SNAPHDR_LEN; tx_frame.wi_frame_ctl = WI_FTYPE_DATA; tx_frame.wi_dat[0] = htons(WI_SNAP_WORD0); tx_frame.wi_dat[1] = htons(WI_SNAP_WORD1); tx_frame.wi_len = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); tx_frame.wi_type = eh->ether_type; m_copydata(m0, sizeof(struct ether_header), m0->m_pkthdr.len - sizeof(struct ether_header), (caddr_t)&sc->wi_txbuf); wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); wi_write_data(sc, id, WI_802_11_OFFSET, (caddr_t)&sc->wi_txbuf, (m0->m_pkthdr.len - sizeof(struct ether_header)) + 2); } else { tx_frame.wi_dat_len = m0->m_pkthdr.len; eh->ether_type = htons(m0->m_pkthdr.len - WI_SNAPHDR_LEN); m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&sc->wi_txbuf); wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); wi_write_data(sc, id, WI_802_3_OFFSET, (caddr_t)&sc->wi_txbuf, m0->m_pkthdr.len + 2); } /* * If there's a BPF listner, bounce a copy of * this frame to him. */ if (ifp->if_bpf) bpf_mtap(ifp, m0); m_freem(m0); if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) device_printf(sc->dev, "xmit failed\n"); ifp->if_flags |= IFF_OACTIVE; /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; return; } static int wi_mgmt_xmit(sc, data, len) struct wi_softc *sc; caddr_t data; int len; { struct wi_frame tx_frame; int id; struct wi_80211_hdr *hdr; caddr_t dptr; if (sc->wi_gone) return(ENODEV); hdr = (struct wi_80211_hdr *)data; dptr = data + sizeof(struct wi_80211_hdr); bzero((char *)&tx_frame, sizeof(tx_frame)); id = sc->wi_tx_mgmt_id; bcopy((char *)hdr, (char *)&tx_frame.wi_frame_ctl, sizeof(struct wi_80211_hdr)); tx_frame.wi_dat_len = len - WI_SNAPHDR_LEN; tx_frame.wi_len = htons(len - WI_SNAPHDR_LEN); wi_write_data(sc, id, 0, (caddr_t)&tx_frame, sizeof(struct wi_frame)); wi_write_data(sc, id, WI_802_11_OFFSET_RAW, dptr, (len - sizeof(struct wi_80211_hdr)) + 2); if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) { device_printf(sc->dev, "xmit failed\n"); return(EIO); } return(0); } static void wi_stop(sc) struct wi_softc *sc; { struct ifnet *ifp; if (sc->wi_gone) { return; } ifp = &sc->arpcom.ac_if; /* * If the card is gone and the memory port isn't mapped, we will * (hopefully) get 0xffff back from the status read, which is not * a valid status value. */ if (CSR_READ_2(sc, WI_STATUS) != 0xffff) { CSR_WRITE_2(sc, WI_INT_EN, 0); wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0); } untimeout(wi_inquire, sc, sc->wi_stat_ch); ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); return; } static void wi_watchdog(ifp) struct ifnet *ifp; { struct wi_softc *sc; sc = ifp->if_softc; device_printf(sc->dev, "watchdog timeout\n"); wi_init(sc); ifp->if_oerrors++; return; } static int wi_alloc(dev, io_rid) device_t dev; int io_rid; { struct wi_softc *sc = device_get_softc(dev); sc->iobase_rid = io_rid; sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid, 0, ~0, 1, RF_ACTIVE); if (!sc->iobase) { device_printf(dev, "No I/O space?!\n"); return (ENXIO); } sc->irq_rid = 0; sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 0, ~0, 1, RF_ACTIVE); if (!sc->irq) { wi_free(dev); device_printf(dev, "No irq?!\n"); return (ENXIO); } sc->dev = dev; sc->wi_unit = device_get_unit(dev); sc->wi_io_addr = rman_get_start(sc->iobase); sc->wi_btag = rman_get_bustag(sc->iobase); sc->wi_bhandle = rman_get_bushandle(sc->iobase); return (0); } static void wi_free(dev) device_t dev; { struct wi_softc *sc = device_get_softc(dev); if (sc->iobase != NULL) { bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); sc->iobase = NULL; } if (sc->irq != NULL) { bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); sc->irq = NULL; } if (sc->mem != NULL) { bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); sc->mem = NULL; } return; } static void wi_shutdown(dev) device_t dev; { struct wi_softc *sc; sc = device_get_softc(dev); wi_stop(sc); return; } #ifdef WICACHE /* wavelan signal strength cache code. * store signal/noise/quality on per MAC src basis in * a small fixed cache. The cache wraps if > MAX slots * used. The cache may be zeroed out to start over. * Two simple filters exist to reduce computation: * 1. ip only (literally 0x800) which may be used * to ignore some packets. It defaults to ip only. * it could be used to focus on broadcast, non-IP 802.11 beacons. * 2. multicast/broadcast only. This may be used to * ignore unicast packets and only cache signal strength * for multicast/broadcast packets (beacons); e.g., Mobile-IP * beacons and not unicast traffic. * * The cache stores (MAC src(index), IP src (major clue), signal, * quality, noise) * * No apologies for storing IP src here. It's easy and saves much * trouble elsewhere. The cache is assumed to be INET dependent, * although it need not be. */ #ifdef documentation int wi_sigitems; /* number of cached entries */ struct wi_sigcache wi_sigcache[MAXWICACHE]; /* array of cache entries */ int wi_nextitem; /* index/# of entries */ #endif /* control variables for cache filtering. Basic idea is * to reduce cost (e.g., to only Mobile-IP agent beacons * which are broadcast or multicast). Still you might * want to measure signal strength with unicast ping packets * on a pt. to pt. ant. setup. */ /* set true if you want to limit cache items to broadcast/mcast * only packets (not unicast). Useful for mobile-ip beacons which * are broadcast/multicast at network layer. Default is all packets * so ping/unicast will work say with pt. to pt. antennae setup. */ static int wi_cache_mcastonly = 0; SYSCTL_INT(_machdep, OID_AUTO, wi_cache_mcastonly, CTLFLAG_RW, &wi_cache_mcastonly, 0, ""); /* set true if you want to limit cache items to IP packets only */ static int wi_cache_iponly = 1; SYSCTL_INT(_machdep, OID_AUTO, wi_cache_iponly, CTLFLAG_RW, &wi_cache_iponly, 0, ""); /* * Original comments: * ----------------- * wi_cache_store, per rx packet store signal * strength in MAC (src) indexed cache. * * follows linux driver in how signal strength is computed. * In ad hoc mode, we use the rx_quality field. * signal and noise are trimmed to fit in the range from 47..138. * rx_quality field MSB is signal strength. * rx_quality field LSB is noise. * "quality" is (signal - noise) as is log value. * note: quality CAN be negative. * * In BSS mode, we use the RID for communication quality. * TBD: BSS mode is currently untested. * * Bill's comments: * --------------- * Actually, we use the rx_quality field all the time for both "ad-hoc" * and BSS modes. Why? Because reading an RID is really, really expensive: * there's a bunch of PIO operations that have to be done to read a record * from the NIC, and reading the comms quality RID each time a packet is * received can really hurt performance. We don't have to do this anyway: * the comms quality field only reflects the values in the rx_quality field * anyway. The comms quality RID is only meaningful in infrastructure mode, * but the values it contains are updated based on the rx_quality from * frames received from the access point. * * Also, according to Lucent, the signal strength and noise level values * can be converted to dBms by subtracting 149, so I've modified the code * to do that instead of the scaling it did originally. */ static void wi_cache_store (struct wi_softc *sc, struct ether_header *eh, struct mbuf *m, unsigned short rx_quality) { struct ip *ip = 0; int i; static int cache_slot = 0; /* use this cache entry */ static int wrapindex = 0; /* next "free" cache entry */ int sig, noise; int sawip=0; /* filters: * 1. ip only * 2. configurable filter to throw out unicast packets, * keep multicast only. */ if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { sawip = 1; } /* filter for ip packets only */ if (wi_cache_iponly && !sawip) { return; } /* filter for broadcast/multicast only */ if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { return; } #ifdef SIGDEBUG printf("wi%d: q value %x (MSB=0x%x, LSB=0x%x) \n", sc->wi_unit, rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff); #endif /* find the ip header. we want to store the ip_src * address. */ if (sawip) { ip = mtod(m, struct ip *); } /* do a linear search for a matching MAC address * in the cache table * . MAC address is 6 bytes, * . var w_nextitem holds total number of entries already cached */ for(i = 0; i < sc->wi_nextitem; i++) { if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) { /* Match!, * so we already have this entry, * update the data */ break; } } /* did we find a matching mac address? * if yes, then overwrite a previously existing cache entry */ if (i < sc->wi_nextitem ) { cache_slot = i; } /* else, have a new address entry,so * add this new entry, * if table full, then we need to replace LRU entry */ else { /* check for space in cache table * note: wi_nextitem also holds number of entries * added in the cache table */ if ( sc->wi_nextitem < MAXWICACHE ) { cache_slot = sc->wi_nextitem; sc->wi_nextitem++; sc->wi_sigitems = sc->wi_nextitem; } /* no space found, so simply wrap with wrap index * and "zap" the next entry */ else { if (wrapindex == MAXWICACHE) { wrapindex = 0; } cache_slot = wrapindex++; } } /* invariant: cache_slot now points at some slot * in cache. */ if (cache_slot < 0 || cache_slot >= MAXWICACHE) { log(LOG_ERR, "wi_cache_store, bad index: %d of " "[0..%d], gross cache error\n", cache_slot, MAXWICACHE); return; } /* store items in cache * .ip source address * .mac src * .signal, etc. */ if (sawip) { sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; } bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6); sig = (rx_quality >> 8) & 0xFF; noise = rx_quality & 0xFF; sc->wi_sigcache[cache_slot].signal = sig - 149; sc->wi_sigcache[cache_slot].noise = noise - 149; sc->wi_sigcache[cache_slot].quality = sig - noise; return; } #endif static int wi_get_cur_ssid(sc, ssid, len) struct wi_softc *sc; char *ssid; int *len; { int error = 0; struct wi_req wreq; wreq.wi_len = WI_MAX_DATALEN; switch (sc->wi_ptype) { case WI_PORTTYPE_ADHOC: wreq.wi_type = WI_RID_CURRENT_SSID; error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); if (error != 0) break; if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { error = EINVAL; break; } *len = wreq.wi_val[0]; bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); break; case WI_PORTTYPE_BSS: wreq.wi_type = WI_RID_COMMQUAL; error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); if (error != 0) break; if (wreq.wi_val[0] != 0) /* associated */ { wreq.wi_type = WI_RID_CURRENT_SSID; wreq.wi_len = WI_MAX_DATALEN; error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq); if (error != 0) break; if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { error = EINVAL; break; } *len = wreq.wi_val[0]; bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN); } else { *len = IEEE80211_NWID_LEN; bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN); } break; default: error = EINVAL; break; } return error; } static int wi_media_change(ifp) struct ifnet *ifp; { struct wi_softc *sc = ifp->if_softc; int otype = sc->wi_ptype; int orate = sc->wi_tx_rate; if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) sc->wi_ptype = WI_PORTTYPE_ADHOC; else sc->wi_ptype = WI_PORTTYPE_BSS; switch (IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) { case IFM_IEEE80211_DS1: sc->wi_tx_rate = 1; break; case IFM_IEEE80211_DS2: sc->wi_tx_rate = 2; break; case IFM_IEEE80211_DS5: sc->wi_tx_rate = 5; break; case IFM_IEEE80211_DS11: sc->wi_tx_rate = 11; break; case IFM_AUTO: sc->wi_tx_rate = 3; break; } if (otype != sc->wi_ptype || orate != sc->wi_tx_rate) wi_init(sc); return(0); } static void wi_media_status(ifp, imr) struct ifnet *ifp; struct ifmediareq *imr; { struct wi_req wreq; struct wi_softc *sc = ifp->if_softc; if (sc->wi_tx_rate == 3) { imr->ifm_active = IFM_IEEE80211|IFM_AUTO; if (sc->wi_ptype == WI_PORTTYPE_ADHOC) imr->ifm_active |= IFM_IEEE80211_ADHOC; wreq.wi_type = WI_RID_CUR_TX_RATE; wreq.wi_len = WI_MAX_DATALEN; if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) { switch(wreq.wi_val[0]) { case 1: imr->ifm_active |= IFM_IEEE80211_DS1; break; case 2: imr->ifm_active |= IFM_IEEE80211_DS2; break; case 6: imr->ifm_active |= IFM_IEEE80211_DS5; break; case 11: imr->ifm_active |= IFM_IEEE80211_DS11; break; } } } else { imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media; } imr->ifm_status = IFM_AVALID; if (sc->wi_ptype == WI_PORTTYPE_ADHOC) /* * XXX: It would be nice if we could give some actually * useful status like whether we joined another IBSS or * created one ourselves. */ imr->ifm_status |= IFM_ACTIVE; else { wreq.wi_type = WI_RID_COMMQUAL; wreq.wi_len = WI_MAX_DATALEN; if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 && wreq.wi_val[0] != 0) imr->ifm_status |= IFM_ACTIVE; } } Index: stable/4/sys/i386/isa/if_wireg.h =================================================================== --- stable/4/sys/i386/isa/if_wireg.h (revision 82305) +++ stable/4/sys/i386/isa/if_wireg.h (revision 82306) @@ -1,669 +1,674 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ struct wi_counters { u_int32_t wi_tx_unicast_frames; u_int32_t wi_tx_multicast_frames; u_int32_t wi_tx_fragments; u_int32_t wi_tx_unicast_octets; u_int32_t wi_tx_multicast_octets; u_int32_t wi_tx_deferred_xmits; u_int32_t wi_tx_single_retries; u_int32_t wi_tx_multi_retries; u_int32_t wi_tx_retry_limit; u_int32_t wi_tx_discards; u_int32_t wi_rx_unicast_frames; u_int32_t wi_rx_multicast_frames; u_int32_t wi_rx_fragments; u_int32_t wi_rx_unicast_octets; u_int32_t wi_rx_multicast_octets; u_int32_t wi_rx_fcs_errors; u_int32_t wi_rx_discards_nobuf; u_int32_t wi_tx_discards_wrong_sa; u_int32_t wi_rx_WEP_cant_decrypt; u_int32_t wi_rx_msg_in_msg_frags; u_int32_t wi_rx_msg_in_bad_msg_frags; }; /* * Encryption controls. We can enable or disable encryption as * well as specify up to 4 encryption keys. We can also specify * which of the four keys will be used for transmit encryption. */ #define WI_RID_ENCRYPTION 0xFC20 #define WI_RID_AUTHTYPE 0xFC21 #define WI_RID_DEFLT_CRYPT_KEYS 0xFCB0 #define WI_RID_TX_CRYPT_KEY 0xFCB1 #define WI_RID_WEP_AVAIL 0xFD4F #define WI_RID_P2_TX_CRYPT_KEY 0xFC23 #define WI_RID_P2_CRYPT_KEY0 0xFC24 #define WI_RID_P2_CRYPT_KEY1 0xFC25 #define WI_RID_P2_CRYPT_KEY2 0xFC26 #define WI_RID_P2_CRYPT_KEY3 0xFC27 #define WI_RID_P2_ENCRYPTION 0xFC28 #define WI_RID_CUR_TX_RATE 0xFD44 /* current TX rate */ struct wi_key { u_int16_t wi_keylen; u_int8_t wi_keydat[14]; }; struct wi_ltv_keys { u_int16_t wi_len; u_int16_t wi_type; struct wi_key wi_keys[4]; }; struct wi_softc { struct arpcom arpcom; struct ifmedia ifmedia; device_t dev; int wi_unit; + struct resource * local; + int local_rid; struct resource * iobase; int iobase_rid; struct resource * irq; int irq_rid; struct resource * mem; int mem_rid; + bus_space_handle_t wi_localhandle; + bus_space_tag_t wi_localtag; bus_space_handle_t wi_bhandle; bus_space_tag_t wi_btag; bus_space_handle_t wi_bmemhandle; bus_space_tag_t wi_bmemtag; void * wi_intrhand; int wi_io_addr; int wi_tx_data_id; int wi_tx_mgmt_id; int wi_gone; int wi_if_flags; u_int16_t wi_ptype; u_int16_t wi_portnum; u_int16_t wi_max_data_len; u_int16_t wi_rts_thresh; u_int16_t wi_ap_density; u_int16_t wi_tx_rate; u_int16_t wi_create_ibss; u_int16_t wi_channel; u_int16_t wi_pm_enabled; u_int16_t wi_max_sleep; char wi_node_name[32]; char wi_net_name[32]; char wi_ibss_name[32]; u_int8_t wi_txbuf[1596]; struct wi_counters wi_stats; int wi_has_wep; int wi_use_wep; int wi_tx_key; struct wi_ltv_keys wi_keys; #ifdef WICACHE int wi_sigitems; struct wi_sigcache wi_sigcache[MAXWICACHE]; int wi_nextitem; #endif struct callout_handle wi_stat_ch; int wi_prism2; /* set to 1 if it uses a Prism II chip */ }; #define WI_TIMEOUT 65536 #define WI_PORT0 0 #define WI_PORT1 1 #define WI_PORT2 2 #define WI_PORT3 3 #define WI_PORT4 4 #define WI_PORT5 5 -#define WI_PCI_MEMRES 0x18 -#define WI_PCI_IORES 0x1C +#define WI_PCI_LOCALRES 0x14 /* The PLX chip's local registers */ +#define WI_PCI_MEMRES 0x18 /* The PCCard's attribute memory */ +#define WI_PCI_IORES 0x1C /* The PCCard's I/O space */ -#define WI_PCI_VENDOR_EUMITCOM 0x1638 -#define WI_PCI_DEVICE_PRISM2STA 0x1100 +#define WI_LOCAL_INTCSR 0x4c +#define WI_LOCAL_INTEN 0x40 /* poke this into INTCSR */ #define WI_HFA384X_SWSUPPORT0_OFF 0x28 #define WI_PRISM2STA_MAGIC 0x4A2D /* Default port: 0 (only 0 exists on stations) */ #define WI_DEFAULT_PORT (WI_PORT0 << 8) /* Default TX rate: 2Mbps, auto fallback */ #define WI_DEFAULT_TX_RATE 3 /* Default network name: empty string implies any */ #define WI_DEFAULT_NETNAME "" #define WI_DEFAULT_AP_DENSITY 1 #define WI_DEFAULT_RTS_THRESH 2347 #define WI_DEFAULT_DATALEN 2304 #define WI_DEFAULT_CREATE_IBSS 0 #define WI_DEFAULT_PM_ENABLED 0 #define WI_DEFAULT_MAX_SLEEP 100 #define WI_DEFAULT_NODENAME "FreeBSD WaveLAN/IEEE node" #define WI_DEFAULT_IBSS "FreeBSD IBSS" #define WI_DEFAULT_CHAN 3 /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) \ bus_space_write_4(sc->wi_btag, sc->wi_bhandle, reg, val) #define CSR_WRITE_2(sc, reg, val) \ bus_space_write_2(sc->wi_btag, sc->wi_bhandle, reg, val) #define CSR_WRITE_1(sc, reg, val) \ bus_space_write_1(sc->wi_btag, sc->wi_bhandle, reg, val) #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->wi_btag, sc->wi_bhandle, reg) #define CSR_READ_2(sc, reg) \ bus_space_read_2(sc->wi_btag, sc->wi_bhandle, reg) #define CSR_READ_1(sc, reg) \ bus_space_read_1(sc->wi_btag, sc->wi_bhandle, reg) #define CSM_WRITE_1(sc, off, val) \ bus_space_write_1(sc->wi_bmemtag, sc->wi_bmemhandle, off, val) #define CSM_READ_1(sc, off) \ bus_space_read_1(sc->wi_bmemtag, sc->wi_bmemhandle, off) /* * The WaveLAN/IEEE cards contain an 802.11 MAC controller which Lucent * calls 'Hermes.' In typical fashion, getting documentation about this * controller is about as easy as squeezing blood from a stone. Here * is more or less what I know: * * - The Hermes controller is firmware driven, and the host interacts * with the Hermes via a firmware interface, which can change. * * - The Hermes is described in a document called: "Hermes Firmware * WaveLAN/IEEE Station Functions," document #010245, which of course * Lucent will not release without an NDA. * * - Lucent has created a library called HCF (Hardware Control Functions) * though which it wants developers to interact with the card. The HCF * is needlessly complex, ill conceived and badly documented. Actually, * the comments in the HCP code itself aren't bad, but the publically * available manual that comes with it is awful, probably due largely to * the fact that it has been emasculated in order to hide information * that Lucent wants to keep proprietary. The purpose of the HCF seems * to be to insulate the driver programmer from the Hermes itself so that * Lucent has an excuse not to release programming in for it. * * - Lucent only makes available documentation and code for 'HCF Light' * which is a stripped down version of HCF with certain features not * implemented, most notably support for 802.11 frames. * * - The HCF code which I have seen blows goats. Whoever decided to * use a 132 column format should be shot. * * Rather than actually use the Lucent HCF library, I have stripped all * the useful information from it and used it to create a driver in the * usual BSD form. Note: I don't want to hear anybody whining about the * fact that the Lucent code is GPLed and mine isn't. I did not actually * put any of Lucent's code in this driver: I only used it as a reference * to obtain information about the underlying hardware. The Hermes * programming interface is not GPLed, so bite me. */ /* * Size of Hermes I/O space. */ #define WI_IOSIZ 0x40 /* * Hermes register definitions and what little I know about them. */ /* Hermes command/status registers. */ #define WI_COMMAND 0x00 #define WI_PARAM0 0x02 #define WI_PARAM1 0x04 #define WI_PARAM2 0x06 #define WI_STATUS 0x08 #define WI_RESP0 0x0A #define WI_RESP1 0x0C #define WI_RESP2 0x0E /* Command register values. */ #define WI_CMD_BUSY 0x8000 /* busy bit */ #define WI_CMD_INI 0x0000 /* initialize */ #define WI_CMD_ENABLE 0x0001 /* enable */ #define WI_CMD_DISABLE 0x0002 /* disable */ #define WI_CMD_DIAG 0x0003 #define WI_CMD_ALLOC_MEM 0x000A /* allocate NIC memory */ #define WI_CMD_TX 0x000B /* transmit */ #define WI_CMD_NOTIFY 0x0010 #define WI_CMD_INQUIRE 0x0011 #define WI_CMD_ACCESS 0x0021 #define WI_CMD_PROGRAM 0x0022 #define WI_CMD_CODE_MASK 0x003F /* * Reclaim qualifier bit, applicable to the * TX and INQUIRE commands. */ #define WI_RECLAIM 0x0100 /* reclaim NIC memory */ /* * ACCESS command qualifier bits. */ #define WI_ACCESS_READ 0x0000 #define WI_ACCESS_WRITE 0x0100 /* * PROGRAM command qualifier bits. */ #define WI_PROGRAM_DISABLE 0x0000 #define WI_PROGRAM_ENABLE_RAM 0x0100 #define WI_PROGRAM_ENABLE_NVRAM 0x0200 #define WI_PROGRAM_NVRAM 0x0300 /* Status register values */ #define WI_STAT_CMD_CODE 0x003F #define WI_STAT_DIAG_ERR 0x0100 #define WI_STAT_INQ_ERR 0x0500 #define WI_STAT_CMD_RESULT 0x7F00 /* memory handle management registers */ #define WI_INFO_FID 0x10 #define WI_RX_FID 0x20 #define WI_ALLOC_FID 0x22 #define WI_TX_CMP_FID 0x24 /* * Buffer Access Path (BAP) registers. * These are I/O channels. I believe you can use each one for * any desired purpose independently of the other. In general * though, we use BAP1 for reading and writing LTV records and * reading received data frames, and BAP0 for writing transmit * frames. This is a convention though, not a rule. */ #define WI_SEL0 0x18 #define WI_SEL1 0x1A #define WI_OFF0 0x1C #define WI_OFF1 0x1E #define WI_DATA0 0x36 #define WI_DATA1 0x38 #define WI_BAP0 WI_DATA0 #define WI_BAP1 WI_DATA1 #define WI_OFF_BUSY 0x8000 #define WI_OFF_ERR 0x4000 #define WI_OFF_DATAOFF 0x0FFF /* Event registers */ #define WI_EVENT_STAT 0x30 /* Event status */ #define WI_INT_EN 0x32 /* Interrupt enable/disable */ #define WI_EVENT_ACK 0x34 /* Ack event */ /* Events */ #define WI_EV_TICK 0x8000 /* aux timer tick */ #define WI_EV_RES 0x4000 /* controller h/w error (time out) */ #define WI_EV_INFO_DROP 0x2000 /* no RAM to build unsolicited frame */ #define WI_EV_NO_CARD 0x0800 /* card removed (hunh?) */ #define WI_EV_DUIF_RX 0x0400 /* wavelan management packet received */ #define WI_EV_INFO 0x0080 /* async info frame */ #define WI_EV_CMD 0x0010 /* command completed */ #define WI_EV_ALLOC 0x0008 /* async alloc/reclaim completed */ #define WI_EV_TX_EXC 0x0004 /* async xmit completed with failure */ #define WI_EV_TX 0x0002 /* async xmit completed succesfully */ #define WI_EV_RX 0x0001 /* async rx completed */ #define WI_INTRS \ (WI_EV_RX|WI_EV_TX|WI_EV_TX_EXC|WI_EV_ALLOC|WI_EV_INFO|WI_EV_INFO_DROP) /* Host software registers */ #define WI_SW0 0x28 #define WI_SW1 0x2A #define WI_SW2 0x2C #define WI_SW3 0x2E #define WI_CNTL 0x14 #define WI_CNTL_AUX_ENA 0xC000 #define WI_CNTL_AUX_ENA_STAT 0xC000 #define WI_CNTL_AUX_DIS_STAT 0x0000 #define WI_CNTL_AUX_ENA_CNTL 0x8000 #define WI_CNTL_AUX_DIS_CNTL 0x4000 #define WI_AUX_PAGE 0x3A #define WI_AUX_OFFSET 0x3C #define WI_AUX_DATA 0x3E #define WI_COR_OFFSET 0x3e0 #define WI_COR_VALUE 0x41 /* * One form of communication with the Hermes is with what Lucent calls * LTV records, where LTV stands for Length, Type and Value. The length * and type are 16 bits and are in native byte order. The value is in * multiples of 16 bits and is in little endian byte order. */ struct wi_ltv_gen { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_val; }; struct wi_ltv_str { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_str[17]; }; #define WI_SETVAL(recno, val) \ do { \ struct wi_ltv_gen g; \ \ g.wi_len = 2; \ g.wi_type = recno; \ g.wi_val = val; \ wi_write_record(sc, &g); \ } while (0) #define WI_SETSTR(recno, str) \ do { \ struct wi_ltv_str s; \ int l; \ \ l = (strlen(str) + 1) & ~0x1; \ bzero((char *)&s, sizeof(s)); \ s.wi_len = (l / 2) + 2; \ s.wi_type = recno; \ s.wi_str[0] = strlen(str); \ bcopy(str, (char *)&s.wi_str[1], strlen(str)); \ wi_write_record(sc, (struct wi_ltv_gen *)&s); \ } while (0) /* * Download buffer location and length (0xFD01). */ #define WI_RID_DNLD_BUF 0xFD01 struct wi_ltv_dnld_buf { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_buf_pg; /* page addr of intermediate dl buf*/ u_int16_t wi_buf_off; /* offset of idb */ u_int16_t wi_buf_len; /* len of idb */ }; /* * Mem sizes (0xFD02). */ #define WI_RID_MEMSZ 0xFD02 struct wi_ltv_memsz { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_mem_ram; u_int16_t wi_mem_nvram; }; /* * List of intended regulatory domains (0xFD11). */ #define WI_RID_DOMAINS 0xFD11 struct wi_ltv_domains { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_domains[6]; }; /* * CIS struct (0xFD13). */ #define WI_RID_CIS 0xFD13 struct wi_ltv_cis { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_cis[240]; }; /* * Communications quality (0xFD43). */ #define WI_RID_COMMQUAL 0xFD43 struct wi_ltv_commqual { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_coms_qual; u_int16_t wi_sig_lvl; u_int16_t wi_noise_lvl; }; /* * Actual system scale thresholds (0xFD46). */ #define WI_RID_SYSTEM_SCALE 0xFC06 #define WI_RID_SCALETHRESH 0xFD46 struct wi_ltv_scalethresh { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_energy_detect; u_int16_t wi_carrier_detect; u_int16_t wi_defer; u_int16_t wi_cell_search; u_int16_t wi_out_of_range; u_int16_t wi_delta_snr; }; /* * PCF info struct (0xFD87). */ #define WI_RID_PCF 0xFD87 struct wi_ltv_pcf { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_energy_detect; u_int16_t wi_carrier_detect; u_int16_t wi_defer; u_int16_t wi_cell_search; u_int16_t wi_range; }; /* * Connection control characteristics. * 1 == Basic Service Set (BSS) * 2 == Wireless Distribudion System (WDS) * 3 == Pseudo IBSS */ #define WI_RID_PORTTYPE 0xFC00 #define WI_PORTTYPE_BSS 0x1 #define WI_PORTTYPE_WDS 0x2 #define WI_PORTTYPE_ADHOC 0x3 /* * Mac addresses. */ #define WI_RID_MAC_NODE 0xFC01 #define WI_RID_MAC_WDS 0xFC08 struct wi_ltv_macaddr { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_mac_addr[3]; }; /* * Station set identification (SSID). */ #define WI_RID_DESIRED_SSID 0xFC02 #define WI_RID_OWN_SSID 0xFC04 struct wi_ltv_ssid { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_id[17]; }; /* * Set communications channel (radio frequency). */ #define WI_RID_OWN_CHNL 0xFC03 /* * Frame data size. */ #define WI_RID_MAX_DATALEN 0xFC07 /* * ESS power management enable */ #define WI_RID_PM_ENABLED 0xFC09 /* * ESS max PM sleep internal */ #define WI_RID_MAX_SLEEP 0xFC0C /* * Set our station name. */ #define WI_RID_NODENAME 0xFC0E struct wi_ltv_nodename { u_int16_t wi_len; u_int16_t wi_type; u_int16_t wi_nodename[17]; }; /* * Multicast addresses to be put in filter. We're * allowed up to 16 addresses in the filter. */ #define WI_RID_MCAST 0xFC80 struct wi_ltv_mcast { u_int16_t wi_len; u_int16_t wi_type; struct ether_addr wi_mcast[16]; }; /* * Create IBSS. */ #define WI_RID_CREATE_IBSS 0xFC81 #define WI_RID_FRAG_THRESH 0xFC82 #define WI_RID_RTS_THRESH 0xFC83 /* * TX rate control * 0 == Fixed 1mbps * 1 == Fixed 2mbps * 2 == auto fallback */ #define WI_RID_TX_RATE 0xFC84 /* * promiscuous mode. */ #define WI_RID_PROMISC 0xFC85 /* * Auxiliary Timer tick interval */ #define WI_RID_TICK_TIME 0xFCE0 /* * Information frame types. */ #define WI_INFO_NOTIFY 0xF000 /* Handover address */ #define WI_INFO_COUNTERS 0xF100 /* Statistics counters */ #define WI_INFO_SCAN_RESULTS 0xF101 /* Scan results */ #define WI_INFO_LINK_STAT 0xF200 /* Link status */ #define WI_INFO_ASSOC_STAT 0xF201 /* Association status */ /* * Hermes transmit/receive frame structure */ struct wi_frame { u_int16_t wi_status; /* 0x00 */ u_int16_t wi_rsvd0; /* 0x02 */ u_int16_t wi_rsvd1; /* 0x04 */ u_int16_t wi_q_info; /* 0x06 */ u_int16_t wi_rsvd2; /* 0x08 */ u_int16_t wi_rsvd3; /* 0x0A */ u_int16_t wi_tx_ctl; /* 0x0C */ u_int16_t wi_frame_ctl; /* 0x0E */ u_int16_t wi_id; /* 0x10 */ u_int8_t wi_addr1[6]; /* 0x12 */ u_int8_t wi_addr2[6]; /* 0x18 */ u_int8_t wi_addr3[6]; /* 0x1E */ u_int16_t wi_seq_ctl; /* 0x24 */ u_int8_t wi_addr4[6]; /* 0x26 */ u_int16_t wi_dat_len; /* 0x2C */ u_int8_t wi_dst_addr[6]; /* 0x2E */ u_int8_t wi_src_addr[6]; /* 0x34 */ u_int16_t wi_len; /* 0x3A */ u_int16_t wi_dat[3]; /* 0x3C */ /* SNAP header */ u_int16_t wi_type; /* 0x42 */ }; #define WI_802_3_OFFSET 0x2E #define WI_802_11_OFFSET 0x44 #define WI_802_11_OFFSET_RAW 0x3C #define WI_STAT_BADCRC 0x0001 #define WI_STAT_UNDECRYPTABLE 0x0002 #define WI_STAT_ERRSTAT 0x0003 #define WI_STAT_MAC_PORT 0x0700 #define WI_STAT_1042 0x2000 /* RFC1042 encoded */ #define WI_STAT_TUNNEL 0x4000 /* Bridge-tunnel encoded */ #define WI_STAT_WMP_MSG 0x6000 /* WaveLAN-II management protocol */ #define WI_RXSTAT_MSG_TYPE 0xE000 #define WI_ENC_TX_802_3 0x00 #define WI_ENC_TX_802_11 0x11 #define WI_ENC_TX_E_II 0x0E #define WI_ENC_TX_1042 0x00 #define WI_ENC_TX_TUNNEL 0xF8 #define WI_TXCNTL_MACPORT 0x00FF #define WI_TXCNTL_STRUCTTYPE 0xFF00 /* * SNAP (sub-network access protocol) constants for transmission * of IP datagrams over IEEE 802 networks, taken from RFC1042. * We need these for the LLC/SNAP header fields in the TX/RX frame * structure. */ #define WI_SNAP_K1 0xaa /* assigned global SAP for SNAP */ #define WI_SNAP_K2 0x00 #define WI_SNAP_CONTROL 0x03 /* unnumbered information format */ #define WI_SNAP_WORD0 (WI_SNAP_K1 | (WI_SNAP_K1 << 8)) #define WI_SNAP_WORD1 (WI_SNAP_K2 | (WI_SNAP_CONTROL << 8)) #define WI_SNAPHDR_LEN 0x6