Author: colin Date: 2009-12-05 15:24:30 +0100 (Sat, 05 Dec 2009) New Revision: 34507 Changeset: http://dev.haiku-os.org/changeset/34507/haiku Added: haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/ haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/ haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/if_ral_pci.c haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560reg.h haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560var.h haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2661.c haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2661reg.h haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2661var.h Modified: haiku/trunk/src/add-ons/kernel/drivers/network/wlan/Jamfile Log: Adding ralinkwifi driver. This driver compiles, only, as there is a glue.c is missing atm. If someone wanne add it go ahead. Modified: haiku/trunk/src/add-ons/kernel/drivers/network/wlan/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/network/wlan/Jamfile 2009-12-05 14:06:45 UTC (rev 34506) +++ haiku/trunk/src/add-ons/kernel/drivers/network/wlan/Jamfile 2009-12-05 14:24:30 UTC (rev 34507) @@ -8,3 +8,4 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network wlan iprowifi3945 ; SubInclude HAIKU_TOP src add-ons kernel drivers network wlan iprowifi4965 ; SubInclude HAIKU_TOP src add-ons kernel drivers network wlan marvell88w8363 ; +SubInclude HAIKU_TOP src add-ons kernel drivers network wlan ralinkwifi ; Property changes on: haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi ___________________________________________________________________ Added: svn:mergeinfo + Added: haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile (rev 0) +++ haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile 2009-12-05 14:24:30 UTC (rev 34507) @@ -0,0 +1,24 @@ +SubDir HAIKU_TOP src add-ons kernel drivers network wlan ralinkwifi ; + +UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network compat ] : true ; +UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_wlan ] : true ; +UsePrivateHeaders net system ; +UsePrivateKernelHeaders ; + +SubDirCcFlags [ FDefines _KERNEL=1 FBSD_DRIVER=1 ] + -Wno-format + -Wno-unused + -Wno-uninitialized ; + +UseHeaders [ FDirName $(SUBDIR) ] : true ; + +SEARCH_SOURCE += [ FDirName $(SUBDIR) dev ral ] ; + +KernelAddon ralinkwifi : + if_ral_pci.c + rt2560.c + rt2661.c + : + libfreebsd_wlan.a + libfreebsd_network.a + ; Added: haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/if_ral_pci.c =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/if_ral_pci.c (rev 0) +++ haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/if_ral_pci.c 2009-12-05 14:24:30 UTC (rev 34507) @@ -0,0 +1,272 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2005, 2006 + * Damien Bergamini <damien.bergamini@xxxxxxx> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * PCI/Cardbus front-end for the Ralink RT2560/RT2561/RT2561S/RT2661 driver. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/endian.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_amrr.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/ral/rt2560var.h> +#include <dev/ral/rt2661var.h> + +MODULE_DEPEND(ral, pci, 1, 1, 1); +MODULE_DEPEND(ral, firmware, 1, 1, 1); +MODULE_DEPEND(ral, wlan, 1, 1, 1); +MODULE_DEPEND(ral, wlan_amrr, 1, 1, 1); + +struct ral_pci_ident { + uint16_t vendor; + uint16_t device; + const char *name; +}; + +static const struct ral_pci_ident ral_pci_ids[] = { + { 0x1814, 0x0201, "Ralink Technology RT2560" }, + { 0x1814, 0x0301, "Ralink Technology RT2561S" }, + { 0x1814, 0x0302, "Ralink Technology RT2561" }, + { 0x1814, 0x0401, "Ralink Technology RT2661" }, + + { 0, 0, NULL } +}; + +static struct ral_opns { + int (*attach)(device_t, int); + int (*detach)(void *); + void (*shutdown)(void *); + void (*suspend)(void *); + void (*resume)(void *); + void (*intr)(void *); + +} ral_rt2560_opns = { + rt2560_attach, + rt2560_detach, + rt2560_stop, + rt2560_stop, + rt2560_resume, + rt2560_intr + +}, ral_rt2661_opns = { + rt2661_attach, + rt2661_detach, + rt2661_shutdown, + rt2661_suspend, + rt2661_resume, + rt2661_intr +}; + +struct ral_pci_softc { + union { + struct rt2560_softc sc_rt2560; + struct rt2661_softc sc_rt2661; + } u; + + struct ral_opns *sc_opns; + int irq_rid; + int mem_rid; + struct resource *irq; + struct resource *mem; + void *sc_ih; +}; + +static int ral_pci_probe(device_t); +static int ral_pci_attach(device_t); +static int ral_pci_detach(device_t); +static int ral_pci_shutdown(device_t); +static int ral_pci_suspend(device_t); +static int ral_pci_resume(device_t); + +static device_method_t ral_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ral_pci_probe), + DEVMETHOD(device_attach, ral_pci_attach), + DEVMETHOD(device_detach, ral_pci_detach), + DEVMETHOD(device_shutdown, ral_pci_shutdown), + DEVMETHOD(device_suspend, ral_pci_suspend), + DEVMETHOD(device_resume, ral_pci_resume), + + { 0, 0 } +}; + +static driver_t ral_pci_driver = { + "ral", + ral_pci_methods, + sizeof (struct ral_pci_softc) +}; + +static devclass_t ral_devclass; + +DRIVER_MODULE(ral, pci, ral_pci_driver, ral_devclass, 0, 0); + +static int +ral_pci_probe(device_t dev) +{ + const struct ral_pci_ident *ident; + + for (ident = ral_pci_ids; ident->name != NULL; ident++) { + if (pci_get_vendor(dev) == ident->vendor && + pci_get_device(dev) == ident->device) { + device_set_desc(dev, ident->name); + return 0; + } + } + return ENXIO; +} + +/* Base Address Register */ +#define RAL_PCI_BAR0 0x10 + +static int +ral_pci_attach(device_t dev) +{ + struct ral_pci_softc *psc = device_get_softc(dev); + struct rt2560_softc *sc = &psc->u.sc_rt2560; + int error; + + if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { + device_printf(dev, "chip is in D%d power mode " + "-- setting to D0\n", pci_get_powerstate(dev)); + pci_set_powerstate(dev, PCI_POWERSTATE_D0); + } + + /* enable bus-mastering */ + pci_enable_busmaster(dev); + + psc->sc_opns = (pci_get_device(dev) == 0x0201) ? &ral_rt2560_opns : + &ral_rt2661_opns; + + psc->mem_rid = RAL_PCI_BAR0; + psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &psc->mem_rid, + RF_ACTIVE); + if (psc->mem == NULL) { + device_printf(dev, "could not allocate memory resource\n"); + return ENXIO; + } + + sc->sc_st = rman_get_bustag(psc->mem); + sc->sc_sh = rman_get_bushandle(psc->mem); + sc->sc_invalid = 1; + + psc->irq_rid = 0; + psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &psc->irq_rid, + RF_ACTIVE | RF_SHAREABLE); + if (psc->irq == NULL) { + device_printf(dev, "could not allocate interrupt resource\n"); + return ENXIO; + } + + error = (*psc->sc_opns->attach)(dev, pci_get_device(dev)); + if (error != 0) + return error; + + /* + * Hook our interrupt after all initialization is complete. + */ + error = bus_setup_intr(dev, psc->irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, psc->sc_opns->intr, psc, &psc->sc_ih); + if (error != 0) { + device_printf(dev, "could not set up interrupt\n"); + return error; + } + sc->sc_invalid = 0; + + return 0; +} + +static int +ral_pci_detach(device_t dev) +{ + struct ral_pci_softc *psc = device_get_softc(dev); + struct rt2560_softc *sc = &psc->u.sc_rt2560; + + /* check if device was removed */ + sc->sc_invalid = !bus_child_present(dev); + + (*psc->sc_opns->detach)(psc); + + bus_generic_detach(dev); + bus_teardown_intr(dev, psc->irq, psc->sc_ih); + bus_release_resource(dev, SYS_RES_IRQ, psc->irq_rid, psc->irq); + + bus_release_resource(dev, SYS_RES_MEMORY, psc->mem_rid, psc->mem); + + return 0; +} + +static int +ral_pci_shutdown(device_t dev) +{ + struct ral_pci_softc *psc = device_get_softc(dev); + + (*psc->sc_opns->shutdown)(psc); + + return 0; +} + +static int +ral_pci_suspend(device_t dev) +{ + struct ral_pci_softc *psc = device_get_softc(dev); + + (*psc->sc_opns->suspend)(psc); + + return 0; +} + +static int +ral_pci_resume(device_t dev) +{ + struct ral_pci_softc *psc = device_get_softc(dev); + + (*psc->sc_opns->resume)(psc); + + return 0; +} Added: haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c (rev 0) +++ haiku/trunk/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/dev/ral/rt2560.c 2009-12-05 14:24:30 UTC (rev 34507) @@ -0,0 +1,2841 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2005, 2006 + * Damien Bergamini <damien.bergamini@xxxxxxx> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Ralink Technology RT2560 chipset driver + * http://www.ralinktech.com/ + */ + +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/endian.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_regdomain.h> +#include <net80211/ieee80211_amrr.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> + +#include <dev/ral/rt2560reg.h> +#include <dev/ral/rt2560var.h> + +#define RT2560_RSSI(sc, rssi) \ + ((rssi) > (RT2560_NOISE_FLOOR + (sc)->rssi_corr) ? \ + ((rssi) - RT2560_NOISE_FLOOR - (sc)->rssi_corr) : 0) + +#define RAL_DEBUG +#ifdef RAL_DEBUG +#define DPRINTF(sc, fmt, ...) do { \ + if (sc->sc_debug > 0) \ + printf(fmt, __VA_ARGS__); \ +} while (0) +#define DPRINTFN(sc, n, fmt, ...) do { \ + if (sc->sc_debug >= (n)) \ + printf(fmt, __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(sc, fmt, ...) +#define DPRINTFN(sc, n, fmt, ...) +#endif + +static struct ieee80211vap *rt2560_vap_create(struct ieee80211com *, + const char name[IFNAMSIZ], int unit, int opmode, + int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void rt2560_vap_delete(struct ieee80211vap *); +static void rt2560_dma_map_addr(void *, bus_dma_segment_t *, int, + int); +static int rt2560_alloc_tx_ring(struct rt2560_softc *, + struct rt2560_tx_ring *, int); +static void rt2560_reset_tx_ring(struct rt2560_softc *, + struct rt2560_tx_ring *); +static void rt2560_free_tx_ring(struct rt2560_softc *, + struct rt2560_tx_ring *); +static int rt2560_alloc_rx_ring(struct rt2560_softc *, + struct rt2560_rx_ring *, int); +static void rt2560_reset_rx_ring(struct rt2560_softc *, + struct rt2560_rx_ring *); +static void rt2560_free_rx_ring(struct rt2560_softc *, + struct rt2560_rx_ring *); +static struct ieee80211_node *rt2560_node_alloc(struct ieee80211vap *, + const uint8_t [IEEE80211_ADDR_LEN]); +static void rt2560_newassoc(struct ieee80211_node *, int); +static int rt2560_newstate(struct ieee80211vap *, + enum ieee80211_state, int); +static uint16_t rt2560_eeprom_read(struct rt2560_softc *, uint8_t); +static void rt2560_encryption_intr(struct rt2560_softc *); +static void rt2560_tx_intr(struct rt2560_softc *); +static void rt2560_prio_intr(struct rt2560_softc *); +static void rt2560_decryption_intr(struct rt2560_softc *); +static void rt2560_rx_intr(struct rt2560_softc *); +static void rt2560_beacon_update(struct ieee80211vap *, int item); +static void rt2560_beacon_expire(struct rt2560_softc *); +static void rt2560_wakeup_expire(struct rt2560_softc *); +static void rt2560_scan_start(struct ieee80211com *); +static void rt2560_scan_end(struct ieee80211com *); +static void rt2560_set_channel(struct ieee80211com *); +static void rt2560_setup_tx_desc(struct rt2560_softc *, + struct rt2560_tx_desc *, uint32_t, int, int, int, + bus_addr_t); +static int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, + struct ieee80211_node *); +static int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, + struct ieee80211_node *); +static int rt2560_tx_data(struct rt2560_softc *, struct mbuf *, + struct ieee80211_node *); +static void rt2560_start_locked(struct ifnet *); +static void rt2560_start(struct ifnet *); +static void rt2560_watchdog(void *); +static int rt2560_ioctl(struct ifnet *, u_long, caddr_t); +static void rt2560_bbp_write(struct rt2560_softc *, uint8_t, + uint8_t); +static uint8_t rt2560_bbp_read(struct rt2560_softc *, uint8_t); +static void rt2560_rf_write(struct rt2560_softc *, uint8_t, + uint32_t); +static void rt2560_set_chan(struct rt2560_softc *, + struct ieee80211_channel *); +#if 0 +static void rt2560_disable_rf_tune(struct rt2560_softc *); +#endif +static void rt2560_enable_tsf_sync(struct rt2560_softc *); +static void rt2560_enable_tsf(struct rt2560_softc *); +static void rt2560_update_plcp(struct rt2560_softc *); +static void rt2560_update_slot(struct ifnet *); +static void rt2560_set_basicrates(struct rt2560_softc *); +static void rt2560_update_led(struct rt2560_softc *, int, int); +static void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *); +static void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *); +static void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *); +static void rt2560_update_promisc(struct ifnet *); +static const char *rt2560_get_rf(int); +static void rt2560_read_config(struct rt2560_softc *); +static int rt2560_bbp_init(struct rt2560_softc *); +static void rt2560_set_txantenna(struct rt2560_softc *, int); +static void rt2560_set_rxantenna(struct rt2560_softc *, int); +static void rt2560_init_locked(struct rt2560_softc *); +static void rt2560_init(void *); +static void rt2560_stop_locked(struct rt2560_softc *); +static int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); + +static const struct { + uint32_t reg; + uint32_t val; +} rt2560_def_mac[] = { + RT2560_DEF_MAC +}; + +static const struct { + uint8_t reg; + uint8_t val; +} rt2560_def_bbp[] = { + RT2560_DEF_BBP +}; + +static const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; +static const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; +static const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; +static const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; +static const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; +static const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; +static const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; +static const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; + +static const struct { + uint8_t chan; + uint32_t r1, r2, r4; +} rt2560_rf5222[] = { + RT2560_RF5222 +}; + +int +rt2560_attach(device_t dev, int id) +{ + struct rt2560_softc *sc = device_get_softc(dev); + struct ieee80211com *ic; + struct ifnet *ifp; + int error; + uint8_t bands; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + + sc->sc_dev = dev; + + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); + + callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); + + /* retrieve RT2560 rev. no */ + sc->asic_rev = RAL_READ(sc, RT2560_CSR0); + + /* retrieve RF rev. no and various other things from EEPROM */ + rt2560_read_config(sc); + + device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", + sc->asic_rev, rt2560_get_rf(sc->rf_rev)); + + /* + * Allocate Tx and Rx rings. + */ + error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate Tx ring\n"); + goto fail1; + } + + error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate ATIM ring\n"); + goto fail2; + } + + error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate Prio ring\n"); + goto fail3; + } + + error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate Beacon ring\n"); + goto fail4; + } + + error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate Rx ring\n"); + goto fail5; + } + + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(sc->sc_dev, "can not if_alloc()\n"); + goto fail6; + } + ic = ifp->if_l2com; + + /* retrieve MAC address */ + rt2560_get_macaddr(sc, macaddr); + + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = rt2560_init; + ifp->if_ioctl = rt2560_ioctl; + ifp->if_start = rt2560_start; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; + IFQ_SET_READY(&ifp->if_snd); + + ic->ic_ifp = ifp; + ic->ic_opmode = IEEE80211_M_STA; + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + + /* set device capabilities */ + ic->ic_caps = + IEEE80211_C_STA /* station mode */ + | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ + | IEEE80211_C_HOSTAP /* hostap mode */ + | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_AHDEMO /* adhoc demo mode */ + | IEEE80211_C_WDS /* 4-address traffic works */ + | IEEE80211_C_MBSS /* mesh point link mode */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ + | IEEE80211_C_SHSLOT /* short slot time supported */ + | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ + | IEEE80211_C_BGSCAN /* capable of bg scanning */ +#ifdef notyet + | IEEE80211_C_TXFRAG /* handle tx frags */ +#endif + ; + + bands = 0; + setbit(&bands, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11G); + if (sc->rf_rev == RT2560_RF_5222) + setbit(&bands, IEEE80211_MODE_11A); + ieee80211_init_channels(ic, NULL, &bands); + + ieee80211_ifattach(ic, macaddr); + ic->ic_newassoc = rt2560_newassoc; + ic->ic_raw_xmit = rt2560_raw_xmit; + ic->ic_updateslot = rt2560_update_slot; + ic->ic_update_promisc = rt2560_update_promisc; + ic->ic_node_alloc = rt2560_node_alloc; + ic->ic_scan_start = rt2560_scan_start; + ic->ic_scan_end = rt2560_scan_end; + ic->ic_set_channel = rt2560_set_channel; + + ic->ic_vap_create = rt2560_vap_create; + ic->ic_vap_delete = rt2560_vap_delete; + + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + RT2560_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + RT2560_RX_RADIOTAP_PRESENT); + + /* + * Add a few sysctl knobs. + */ +#ifdef RAL_DEBUG + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); +#endif + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)"); + + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)"); + + if (bootverbose) + ieee80211_announce(ic); + + return 0; + +fail6: rt2560_free_rx_ring(sc, &sc->rxq); +fail5: rt2560_free_tx_ring(sc, &sc->bcnq); +fail4: rt2560_free_tx_ring(sc, &sc->prioq); +fail3: rt2560_free_tx_ring(sc, &sc->atimq); +fail2: rt2560_free_tx_ring(sc, &sc->txq); +fail1: mtx_destroy(&sc->sc_mtx); + + return ENXIO; +} + +int +rt2560_detach(void *xsc) +{ + struct rt2560_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + rt2560_stop(sc); + + ieee80211_ifdetach(ic); + + rt2560_free_tx_ring(sc, &sc->txq); + rt2560_free_tx_ring(sc, &sc->atimq); + rt2560_free_tx_ring(sc, &sc->prioq); + rt2560_free_tx_ring(sc, &sc->bcnq); + rt2560_free_rx_ring(sc, &sc->rxq); + + if_free(ifp); + + mtx_destroy(&sc->sc_mtx); + + return 0; +} + +static struct ieee80211vap * +rt2560_vap_create(struct ieee80211com *ic, + const char name[IFNAMSIZ], int unit, int opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct ifnet *ifp = ic->ic_ifp; + struct rt2560_vap *rvp; + struct ieee80211vap *vap; + + switch (opmode) { + case IEEE80211_M_STA: + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + case IEEE80211_M_MONITOR: + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MBSS: + /* XXXRP: TBD */ + if (!TAILQ_EMPTY(&ic->ic_vaps)) { + if_printf(ifp, "only 1 vap supported\n"); + return NULL; + } + if (opmode == IEEE80211_M_STA) + flags |= IEEE80211_CLONE_NOBEACONS; + break; + case IEEE80211_M_WDS: + if (TAILQ_EMPTY(&ic->ic_vaps) || + ic->ic_opmode != IEEE80211_M_HOSTAP) { + if_printf(ifp, "wds only supported in ap mode\n"); + return NULL; + } + /* + * Silently remove any request for a unique + * bssid; WDS vap's always share the local + * mac address. + */ + flags &= ~IEEE80211_CLONE_BSSID; + break; + default: + if_printf(ifp, "unknown opmode %d\n", opmode); + return NULL; + } + rvp = (struct rt2560_vap *) malloc(sizeof(struct rt2560_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (rvp == NULL) + return NULL; + vap = &rvp->ral_vap; + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); + + /* override state transition machine */ + rvp->ral_newstate = vap->iv_newstate; + vap->iv_newstate = rt2560_newstate; + vap->iv_update_beacon = rt2560_beacon_update; + + ieee80211_amrr_init(&rvp->amrr, vap, + IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, + IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD, + 500 /* ms */); + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); + if (TAILQ_FIRST(&ic->ic_vaps) == vap) + ic->ic_opmode = opmode; + return vap; +} + +static void +rt2560_vap_delete(struct ieee80211vap *vap) +{ + struct rt2560_vap *rvp = RT2560_VAP(vap); + + ieee80211_amrr_cleanup(&rvp->amrr); + ieee80211_vap_detach(vap); + free(rvp, M_80211_VAP); +} + +void +rt2560_resume(void *xsc) +{ + struct rt2560_softc *sc = xsc; + struct ifnet *ifp = sc->sc_ifp; + + if (ifp->if_flags & IFF_UP) + rt2560_init(sc); +} + +static void +rt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + if (error != 0) + return; + + KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); + + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +static int +rt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, + int count) +{ + int i, error; + + ring->count = count; + ring->queued = 0; + ring->cur = ring->next = 0; + ring->cur_encrypt = ring->next_encrypt = 0; + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + count * RT2560_TX_DESC_SIZE, 1, count * RT2560_TX_DESC_SIZE, + 0, NULL, NULL, &ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create desc DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate DMA memory\n"); + goto fail; + } + + error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, + count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, + 0); + if (error != 0) { + device_printf(sc->sc_dev, "could not load desc DMA map\n"); + goto fail; + } + + ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF, + M_NOWAIT | M_ZERO); + if (ring->data == NULL) { + device_printf(sc->sc_dev, "could not allocate soft data\n"); + error = ENOMEM; + goto fail; + } + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MCLBYTES, RT2560_MAX_SCATTER, MCLBYTES, 0, NULL, NULL, + &ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create data DMA tag\n"); + goto fail; + } + + for (i = 0; i < count; i++) { + error = bus_dmamap_create(ring->data_dmat, 0, + &ring->data[i].map); + if (error != 0) { + device_printf(sc->sc_dev, "could not create DMA map\n"); + goto fail; + } + } + + return 0; + +fail: rt2560_free_tx_ring(sc, ring); + return error; +} + +static void +rt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) +{ + struct rt2560_tx_desc *desc; + struct rt2560_tx_data *data; + int i; + + for (i = 0; i < ring->count; i++) { + desc = &ring->desc[i]; + data = &ring->data[i]; + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + data->m = NULL; + } + + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } + + desc->flags = 0; + } + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); + + ring->queued = 0; + ring->cur = ring->next = 0; + ring->cur_encrypt = ring->next_encrypt = 0; +} + +static void +rt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) +{ + struct rt2560_tx_data *data; + int i; + + if (ring->desc != NULL) { + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->desc_dmat, ring->desc_map); + bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); + } + + if (ring->desc_dmat != NULL) + bus_dma_tag_destroy(ring->desc_dmat); + + if (ring->data != NULL) { + for (i = 0; i < ring->count; i++) { + data = &ring->data[i]; + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + } + + if (data->ni != NULL) + ieee80211_free_node(data->ni); + + if (data->map != NULL) + bus_dmamap_destroy(ring->data_dmat, data->map); + } + + free(ring->data, M_DEVBUF); + } + + if (ring->data_dmat != NULL) + bus_dma_tag_destroy(ring->data_dmat); +} + +static int +rt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, + int count) +{ + struct rt2560_rx_desc *desc; + struct rt2560_rx_data *data; + bus_addr_t physaddr; + int i, error; + + ring->count = count; + ring->cur = ring->next = 0; + ring->cur_decrypt = 0; + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 4, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + count * RT2560_RX_DESC_SIZE, 1, count * RT2560_RX_DESC_SIZE, + 0, NULL, NULL, &ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create desc DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate DMA memory\n"); + goto fail; + } + + error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, + count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr, + 0); + if (error != 0) { + device_printf(sc->sc_dev, "could not load desc DMA map\n"); + goto fail; + } + + ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF, + M_NOWAIT | M_ZERO); + if (ring->data == NULL) { + device_printf(sc->sc_dev, "could not allocate soft data\n"); + error = ENOMEM; + goto fail; + } + + /* + * Pre-allocate Rx buffers and populate Rx ring. + */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, + 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create data DMA tag\n"); + goto fail; [... truncated: 6411 lines follow ...]