diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/wi/if_wi.c | 150 | ||||
-rw-r--r-- | sys/dev/wi/if_wireg.h | 23 |
2 files changed, 157 insertions, 16 deletions
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index 9e27254..7ebe871 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -28,8 +28,6 @@ * 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$ */ /* @@ -85,6 +83,9 @@ #include <machine/bus_pio.h> #include <sys/rman.h> +#include <pci/pcireg.h> +#include <pci/pcivar.h> + #include <net/if.h> #include <net/if_arp.h> #include <net/ethernet.h> @@ -148,13 +149,16 @@ 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_match __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)); +static int wi_alloc __P((device_t, int)); static void wi_free __P((device_t)); static device_method_t wi_pccard_methods[] = { @@ -172,15 +176,33 @@ static device_method_t wi_pccard_methods[] = { { 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 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 const struct pccard_product wi_pccard_products[] = { { PCCARD_STR_LUCENT_WAVELAN_IEEE, PCCARD_VENDOR_LUCENT, @@ -188,6 +210,8 @@ static const struct pccard_product wi_pccard_products[] = { PCCARD_CIS_LUCENT_WAVELAN_IEEE }, }; +static char wi_device_desc[] = "WaveLAN/IEEE 802.11"; + static int wi_pccard_match(dev) device_t dev; { @@ -210,11 +234,10 @@ static int wi_pccard_probe(dev) sc = device_get_softc(dev); sc->wi_gone = 0; - error = wi_alloc(dev); + error = wi_alloc(dev, 0); if (error) return (error); - device_set_desc(dev, "WaveLAN/IEEE 802.11"); wi_free(dev); /* Make sure interrupts are disabled. */ @@ -224,6 +247,22 @@ static int wi_pccard_probe(dev) return (0); } +static int +wi_pci_probe(dev) + device_t dev; +{ + struct wi_softc *sc; + + sc = device_get_softc(dev); + if ((pci_get_vendor(dev) == WI_PCI_VENDOR_Eumitcom) && + (pci_get_device(dev) == WI_PCI_DEVICE_PRISM2STA)) { + sc->wi_prism2 = 1; + device_set_desc(dev, "PRISM2STA PCI WaveLAN/IEEE 802.11"); + return (0); + } + return(ENXIO); +} + static int wi_pccard_detach(dev) device_t dev; { @@ -257,14 +296,10 @@ static int wi_pccard_detach(dev) static int wi_pccard_attach(device_t dev) { struct wi_softc *sc; - struct wi_ltv_macaddr mac; - struct wi_ltv_gen gen; - struct ifnet *ifp; int error; u_int32_t flags; sc = device_get_softc(dev); - ifp = &sc->arpcom.ac_if; /* * XXX: quick hack to support Prism II chip. @@ -289,11 +324,91 @@ static int wi_pccard_attach(device_t dev) } } - error = wi_alloc(dev); + 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); + + sc->mem_rid = 0x18; + 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 + * (FOR GREAT JUSTICE) + */ + CSM_WRITE_1(sc, WI_COR_OFFSET, WI_COR_VALUE); + reg = CSM_READ_1(sc, WI_COR_OFFSET); + + 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); @@ -1541,14 +1656,15 @@ static void wi_watchdog(ifp) return; } -static int wi_alloc(dev) +static int +wi_alloc(dev, io_rid) device_t dev; + int io_rid; { struct wi_softc *sc = device_get_softc(dev); - int rid; - rid = 0; - sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + sc->iobase_rid = io_rid; + sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid, 0, ~0, (1 << 6), rman_make_alignment_flags(1 << 6) | RF_ACTIVE); if (!sc->iobase) { @@ -1556,8 +1672,8 @@ static int wi_alloc(dev) return (ENXIO); } - rid = 0; - sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + sc->irq_rid = 0; + sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 0, ~0, 1, RF_ACTIVE); if (!sc->irq) { device_printf(dev, "No irq?!\n"); @@ -1582,6 +1698,8 @@ static void wi_free(dev) bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase); if (sc->irq != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); + if (sc->mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); return; } diff --git a/sys/dev/wi/if_wireg.h b/sys/dev/wi/if_wireg.h index 9751029..1f2af45 100644 --- a/sys/dev/wi/if_wireg.h +++ b/sys/dev/wi/if_wireg.h @@ -90,9 +90,15 @@ struct wi_softc { device_t dev; int wi_unit; struct resource * iobase; + int iobase_rid; struct resource * irq; + int irq_rid; + struct resource * mem; + int mem_rid; 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; @@ -140,6 +146,13 @@ struct wi_softc { #define WI_PORT4 4 #define WI_PORT5 5 +#define WI_PCI_IORES 0x1c + +#define WI_PCI_VENDOR_Eumitcom 0x1638 +#define WI_PCI_DEVICE_PRISM2STA 0x1100 +#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) @@ -184,6 +197,13 @@ struct wi_softc { #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 @@ -349,6 +369,9 @@ struct wi_softc { #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 |