From owner-svn-src-all@FreeBSD.ORG Tue Jul 30 02:07:59 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id AEA2170; Tue, 30 Jul 2013 02:07:59 +0000 (UTC) (envelope-from rpaulo@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 99A392C6B; Tue, 30 Jul 2013 02:07:59 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r6U27xJf024562; Tue, 30 Jul 2013 02:07:59 GMT (envelope-from rpaulo@svn.freebsd.org) Received: (from rpaulo@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r6U27vYR024547; Tue, 30 Jul 2013 02:07:57 GMT (envelope-from rpaulo@svn.freebsd.org) Message-Id: <201307300207.r6U27vYR024547@svn.freebsd.org> From: Rui Paulo Date: Tue, 30 Jul 2013 02:07:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r253789 - in head: share/man/man4 sys/conf sys/dev/usb/wlan sys/modules/usb sys/modules/usb/rsu X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 30 Jul 2013 02:07:59 -0000 Author: rpaulo Date: Tue Jul 30 02:07:57 2013 New Revision: 253789 URL: http://svnweb.freebsd.org/changeset/base/253789 Log: Import OpenBSD's rsu(4) WLAN driver. Support chipsets are the Realtek RTL8188SU, RTL8191SU, and RTL8192SU. Many thanks to Idwer Vollering for porting/writing the man page and for testing. Reviewed by: adrian, hselasky Obtained from: OpenBSD Tested by: kevlo, Idwer Vollering Added: head/share/man/man4/rsu.4 (contents, props changed) head/share/man/man4/rsufw.4 (contents, props changed) head/sys/dev/usb/wlan/if_rsu.c (contents, props changed) head/sys/dev/usb/wlan/if_rsureg.h (contents, props changed) head/sys/modules/usb/rsu/ head/sys/modules/usb/rsu/Makefile (contents, props changed) Modified: head/share/man/man4/Makefile head/sys/conf/NOTES head/sys/conf/WITHOUT_SOURCELESS_UCODE head/sys/conf/files head/sys/modules/usb/Makefile Modified: head/share/man/man4/Makefile ============================================================================== --- head/share/man/man4/Makefile Mon Jul 29 21:45:39 2013 (r253788) +++ head/share/man/man4/Makefile Tue Jul 30 02:07:57 2013 (r253789) @@ -385,6 +385,8 @@ MAN= aac.4 \ rndtest.4 \ route.4 \ rp.4 \ + rsu.4 \ + rsufw.4 \ rue.4 \ rum.4 \ run.4 \ Added: head/share/man/man4/rsu.4 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man4/rsu.4 Tue Jul 30 02:07:57 2013 (r253789) @@ -0,0 +1,178 @@ +.\" $OpenBSD: rsu.4,v 1.11 2013/02/14 07:40:42 jmc Exp $ +.\" $FreeBSD$ +.\" +.\" Copyright (c) 2010 Damien Bergamini +.\" +.\" 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. +.\" +.Dd July 29 2013 +.Dt RSU 4 +.Os +.Sh NAME +.Nm rsu +.Nd Realtek RTL8188SU/RTL8192SU USB IEEE 802.11b/g/n wireless network device +.Sh SYNOPSIS +.\.Cd "rsu* at uhub? port ?" +To compile this driver into the kernel, +place the following lines in your kernel configuration file: +.Bd -ragged -offset indent +.Cd "device ehci" +.Cd "device uhci" +.Cd "device ohci" +.Cd "device usb" +.Cd "device rsu" +.Cd "device wlan" +.Ed +.Pp +Alternatively, to load the driver as a module at boot time, +place the following line in +.Xr loader.conf 5: +.Bd -literal -offset indent +.Xr if_rsu_load="YES" +.Ed +.Pp +After you have read the license in /usr/share/doc/legal/realtek +you will want to add the following lines to +.Xr loader.conf 5 : +.Bd -literal -offset indent +legal.realtek.license_ack=1 +rsu-rtl8712fw_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver supports USB 2.0 wireless network devices based on Realtek +RTL8188SU, RTL8191SU and RTL8192SU chipsets. +.Pp +The RTL8188SU is a highly integrated 802.11n adapter that combines +a MAC, a 1T1R capable baseband and an RF in a single chip. +It operates in the 2GHz spectrum only. +.Pp +The RTL8191SU is a highly integrated multiple-in, single-out (MISO) +802.11n adapter that combines a MAC, a 1T2R capable baseband and an +RF in a single chip. +It operates in the 2GHz spectrum only. +.Pp +The RTL8192SU is a highly integrated multiple-in, multiple-out (MIMO) +802.11n adapter that combines a MAC, a 2T2R capable baseband and an +RF in a single chip. +It operates in the 2GHz spectrum only. +.Pp +These are the modes the +.Nm +driver can operate in: +.Bl -tag -width "IBSS-masterXX" +.It BSS mode +Also known as +.Em infrastructure +mode, this is used when associating with an access point, through +which all traffic passes. +This mode is the default. +.El +.Pp +The +.Nm +driver can be configured to use +Wired Equivalent Privacy (WEP) or +Wi-Fi Protected Access (WPA-PSK and WPA2-PSK). +WPA is the de facto encryption standard for wireless networks. +It is strongly recommended that WEP +not be used as the sole mechanism +to secure wireless communication, +due to serious weaknesses in it. +.Pp +The +.Nm +driver can be configured at runtime with +.Xr ifconfig 8 +or on boot with +.Xr hostname 1 . +.Sh FILES +The driver needs at least version 1.2 of the following firmware file, +which is loaded when an interface is attached: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It /boot/kernel/rsu-rtl8712fw.ko +.El +.Sh HARDWARE +The following adapters should work: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It ASUS USB-N10 +.It Belkin F7D1101 v1 +.It D-Link DWA-131 A1 +.It EDUP EP-MS150N(W) +.It Hercules HWGUn-54 +.It Hercules HWNUm-300 +.It Planex GW-USNano +.It Sitecom WL-349 v1 +.It Sitecom WL-353 +.It Sweex LW154 +.It TRENDnet TEW-648UB +.It TRENDnet TEW-649UB +.Sh EXAMPLES +Join an existing BSS network (i.e., connect to an access point): +.Bd -literal -offset indent +ifconfig wlan create wlandev rsu0 inet 192.168.0.20 \e + netmask 0xffffff00 +.Ed +.Pp +Join a specific BSS network with network name +.Dq Li my_net : +.Pp +.Dl "ifconfig wlan create wlandev rsu0 ssid my_net up" +.Pp +Join a specific BSS network with 64-bit WEP encryption: +.Bd -literal -offset indent +ifconfig wlan create wlandev rsu0 ssid my_net \e + wepmode on wepkey 0x1234567890 weptxkey 1 up +.Ed +.Sh DIAGNOSTICS +.Bl -diag +.It "%s: failed load firmware of file rsu-rtl8712fw" +For some reason, the driver was unable to read the microcode file from the +filesystem. +The file might be missing or corrupted. +.It "device timeout" +A frame dispatched to the hardware for transmission did not complete in time. +The driver will reset the hardware. +This should not happen. +.El +.Sh SEE ALSO +.Xr arp 8 , +.Xr intro 1 , +.Xr netintro 4 , +.Xr usb 3 , +.Xr hostname 1 , +.Xr ifconfig 8, +.Xr wlan 4 , +.Xr rsufw 4 +.Sh HISTORY +The +.Nm +driver first appeared in +.Ox 4.9 and +.Fx 10.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Damien Bergamini Aq damien@openbsd.org +and ported by +.An Rui Paulo Aq rpaulo@freebsd.org . +.Sh CAVEATS +The +.Nm +driver does not support any of the 802.11n capabilities offered by the +adapters. Added: head/share/man/man4/rsufw.4 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man4/rsufw.4 Tue Jul 30 02:07:57 2013 (r253789) @@ -0,0 +1,46 @@ +.\" $FreeBSD$ +.\" Copyright (c) 2013 Idwer Vollering +.\" +.\" 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. +.\" +.Dd July 21, 2013 +.Dt RSUFW 4 +.Os +.Sh NAME +.Nm rsufw +.Nd "Firmware Module for Realtek driver" +.Sh SYNOPSIS +To compile this module into the kernel, place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device rsufw" +.Ed +.Pp +This will include the firmware image, RTL8712, inside the kernel. +.Xr rsu 4 +will load the image into the chip. +.Pp +Alternatively, to load the firmware images as a module at boot time, place +the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +rsu-rtl8712fw_load="YES" +.Ed +.Sh DESCRIPTION +This module provides the firmware for the Realtek RTL8188SU and +RTL8192SU chip based USB WiFi adapters. +Please read Realtek's license, +.Pa /usr/share/license/realtek . +.Sh SEE ALSO +.Xr rsu 4 , +.Xr firmware 9 Modified: head/sys/conf/NOTES ============================================================================== --- head/sys/conf/NOTES Mon Jul 29 21:45:39 2013 (r253788) +++ head/sys/conf/NOTES Tue Jul 30 02:07:57 2013 (r253789) @@ -2739,6 +2739,8 @@ device mos # HSxPA devices from Option N.V device uhso +# Realtek RTL8188SU/RTL8191SU/RTL8192SU wireless driver +device rsu # # Ralink Technology RT2501USB/RT2601USB wireless driver device rum Modified: head/sys/conf/WITHOUT_SOURCELESS_UCODE ============================================================================== --- head/sys/conf/WITHOUT_SOURCELESS_UCODE Mon Jul 29 21:45:39 2013 (r253788) +++ head/sys/conf/WITHOUT_SOURCELESS_UCODE Tue Jul 30 02:07:57 2013 (r253789) @@ -35,8 +35,11 @@ nodevice ds1 nodevice maestro3 # usb +nodevice rsu +nodevice rsufw nodevice rum nodevice uath nodevice zyd nodevice kue +nodevice urtwn nodevice urtwnfw Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Mon Jul 29 21:45:39 2013 (r253788) +++ head/sys/conf/files Tue Jul 30 02:07:57 2013 (r253789) @@ -2312,6 +2312,21 @@ dev/usb/net/uhso.c optional uhso # # USB WLAN drivers # +dev/usb/wlan/if_rsu.c optional rsu +rsu-rtl8712fw.c optional rsu-rtl8712fw | rsufw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk rsu-rtl8712fw.fw:rsu-rtl8712fw:120 -mrsu-rtl8712fw -c${.TARGET}" \ + no-implicit-rule before-depend local \ + clean "rsu-rtl8712fw.c" +rsu-rtl8712fw.fwo optional rsu-rtl8712fw | rsufw \ + dependency "rsu-rtl8712fw.fw" \ + compile-with "${NORMAL_FWO}" \ + no-implicit-rule \ + clean "rsu-rtl8712fw.fwo" +rsu-rtl8712fw.fw optional rsu-rtl8712.fw | rsufw \ + dependency "$S/contrib/dev/rsu/rsu-rtl8712fw.fw.uu" \ + compile-with "${NORMAL_FW}" \ + no-obj no-implicit-rule \ + clean "rsu-rtl8712fw.fw" dev/usb/wlan/if_rum.c optional rum dev/usb/wlan/if_run.c optional run runfw.c optional runfw \ Added: head/sys/dev/usb/wlan/if_rsu.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/usb/wlan/if_rsu.c Tue Jul 30 02:07:57 2013 (r253789) @@ -0,0 +1,2479 @@ +/* $OpenBSD: if_rsu.c,v 1.17 2013/04/15 09:23:01 mglocker Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * + * 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 +__FBSDID("$FreeBSD$"); + +/* + * Driver for Realtek RTL8188SU/RTL8191SU/RTL8192SU. + * + * TODO: + * o 11n support + * o h/w crypto + * o hostap / ibss / mesh + */ +#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 "usbdevs.h" + +#define USB_DEBUG_VAR rsu_debug +#include + +#include + +#ifdef USB_DEBUG +static int rsu_debug = 0; +SYSCTL_NODE(_hw_usb, OID_AUTO, rsu, CTLFLAG_RW, 0, "USB rsu"); +SYSCTL_INT(_hw_usb_rsu, OID_AUTO, debug, CTLFLAG_RW, &rsu_debug, 0, + "Debug level"); +#endif + +static const STRUCT_USB_HOST_ID rsu_devs[] = { +#define RSU_HT_NOT_SUPPORTED 0 +#define RSU_HT_SUPPORTED 1 +#define RSU_DEV_HT(v,p) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, \ + RSU_HT_SUPPORTED) } +#define RSU_DEV(v,p) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, \ + RSU_HT_NOT_SUPPORTED) } + RSU_DEV(ASUS, RTL8192SU), + RSU_DEV(AZUREWAVE, RTL8192SU_4), + RSU_DEV_HT(ACCTON, RTL8192SU), + RSU_DEV_HT(ASUS, USBN10), + RSU_DEV_HT(AZUREWAVE, RTL8192SU_1), + RSU_DEV_HT(AZUREWAVE, RTL8192SU_2), + RSU_DEV_HT(AZUREWAVE, RTL8192SU_3), + RSU_DEV_HT(AZUREWAVE, RTL8192SU_5), + RSU_DEV_HT(BELKIN, RTL8192SU_1), + RSU_DEV_HT(BELKIN, RTL8192SU_2), + RSU_DEV_HT(BELKIN, RTL8192SU_3), + RSU_DEV_HT(CONCEPTRONIC2, RTL8192SU_1), + RSU_DEV_HT(CONCEPTRONIC2, RTL8192SU_2), + RSU_DEV_HT(CONCEPTRONIC2, RTL8192SU_3), + RSU_DEV_HT(COREGA, RTL8192SU), + RSU_DEV_HT(DLINK2, DWA131A1), + RSU_DEV_HT(DLINK2, RTL8192SU_1), + RSU_DEV_HT(DLINK2, RTL8192SU_2), + RSU_DEV_HT(EDIMAX, RTL8192SU_1), + RSU_DEV_HT(EDIMAX, RTL8192SU_2), + RSU_DEV_HT(EDIMAX, RTL8192SU_3), + RSU_DEV_HT(GUILLEMOT, HWGUN54), + RSU_DEV_HT(GUILLEMOT, HWNUM300), + RSU_DEV_HT(HAWKING, RTL8192SU_1), + RSU_DEV_HT(HAWKING, RTL8192SU_2), + RSU_DEV_HT(PLANEX2, GWUSNANO), + RSU_DEV_HT(REALTEK, RTL8171), + RSU_DEV_HT(REALTEK, RTL8172), + RSU_DEV_HT(REALTEK, RTL8173), + RSU_DEV_HT(REALTEK, RTL8174), + RSU_DEV_HT(REALTEK, RTL8192SU), + RSU_DEV_HT(REALTEK, RTL8712), + RSU_DEV_HT(REALTEK, RTL8713), + RSU_DEV_HT(SENAO, RTL8192SU_1), + RSU_DEV_HT(SENAO, RTL8192SU_2), + RSU_DEV_HT(SITECOMEU, WL349V1), + RSU_DEV_HT(SITECOMEU, WL353), + RSU_DEV_HT(SWEEX2, LW154), +#undef RSU_DEV_HT +#undef RSU_DEV +}; + +static device_probe_t rsu_match; +static device_attach_t rsu_attach; +static device_detach_t rsu_detach; +static usb_callback_t rsu_bulk_tx_callback; +static usb_callback_t rsu_bulk_rx_callback; +static usb_error_t rsu_do_request(struct rsu_softc *, + struct usb_device_request *, void *); +static struct ieee80211vap * + rsu_vap_create(struct ieee80211com *, const char name[], + int, enum ieee80211_opmode, int, const uint8_t bssid[], + const uint8_t mac[]); +static void rsu_vap_delete(struct ieee80211vap *); +static void rsu_scan_start(struct ieee80211com *); +static void rsu_scan_end(struct ieee80211com *); +static void rsu_set_channel(struct ieee80211com *); +static void rsu_update_mcast(struct ifnet *); +static int rsu_alloc_rx_list(struct rsu_softc *); +static void rsu_free_rx_list(struct rsu_softc *); +static int rsu_alloc_tx_list(struct rsu_softc *); +static void rsu_free_tx_list(struct rsu_softc *); +static void rsu_free_list(struct rsu_softc *, struct rsu_data [], int); +static struct rsu_data *_rsu_getbuf(struct rsu_softc *); +static struct rsu_data *rsu_getbuf(struct rsu_softc *); +static int rsu_write_region_1(struct rsu_softc *, uint16_t, uint8_t *, + int); +static void rsu_write_1(struct rsu_softc *, uint16_t, uint8_t); +static void rsu_write_2(struct rsu_softc *, uint16_t, uint16_t); +static void rsu_write_4(struct rsu_softc *, uint16_t, uint32_t); +static int rsu_read_region_1(struct rsu_softc *, uint16_t, uint8_t *, + int); +static uint8_t rsu_read_1(struct rsu_softc *, uint16_t); +static uint16_t rsu_read_2(struct rsu_softc *, uint16_t); +static uint32_t rsu_read_4(struct rsu_softc *, uint16_t); +static int rsu_fw_iocmd(struct rsu_softc *, uint32_t); +static uint8_t rsu_efuse_read_1(struct rsu_softc *, uint16_t); +static int rsu_read_rom(struct rsu_softc *); +static int rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int); +static void rsu_calib_task(void *, int); +static int rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int); +#ifdef notyet +static void rsu_set_key(struct rsu_softc *, const struct ieee80211_key *); +static void rsu_delete_key(struct rsu_softc *, const struct ieee80211_key *); +#endif +static int rsu_site_survey(struct rsu_softc *, struct ieee80211vap *); +static int rsu_join_bss(struct rsu_softc *, struct ieee80211_node *); +static int rsu_disconnect(struct rsu_softc *); +static void rsu_event_survey(struct rsu_softc *, uint8_t *, int); +static void rsu_event_join_bss(struct rsu_softc *, uint8_t *, int); +static void rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int); +static void rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int); +static int8_t rsu_get_rssi(struct rsu_softc *, int, void *); +static struct mbuf * + rsu_rx_frame(struct rsu_softc *, uint8_t *, int, int *); +static struct mbuf * + rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int, int *); +static struct mbuf * + rsu_rxeof(struct usb_xfer *, struct rsu_data *, int *); +static void rsu_txeof(struct usb_xfer *, struct rsu_data *); +static int rsu_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); +static void rsu_init(void *); +static void rsu_init_locked(struct rsu_softc *); +static void rsu_watchdog(void *); +static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *, + struct mbuf *, struct rsu_data *); +static void rsu_start(struct ifnet *); +static void rsu_start_locked(struct ifnet *); +static int rsu_ioctl(struct ifnet *, u_long, caddr_t); +static void rsu_stop(struct ifnet *, int); +static void rsu_stop_locked(struct ifnet *, int); + +static device_method_t rsu_methods[] = { + DEVMETHOD(device_probe, rsu_match), + DEVMETHOD(device_attach, rsu_attach), + DEVMETHOD(device_detach, rsu_detach), + + DEVMETHOD_END +}; + +static driver_t rsu_driver = { + .name = "rsu", + .methods = rsu_methods, + .size = sizeof(struct rsu_softc) +}; + +static devclass_t rsu_devclass; + +DRIVER_MODULE(rsu, uhub, rsu_driver, rsu_devclass, NULL, 0); +MODULE_DEPEND(rsu, wlan, 1, 1, 1); +MODULE_DEPEND(rsu, usb, 1, 1, 1); +MODULE_DEPEND(rsu, firmware, 1, 1, 1); +MODULE_VERSION(rsu, 1); + +static const struct usb_config rsu_config[RSU_N_TRANSFER] = { + [RSU_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = RSU_RXBUFSZ, + .flags = { + .pipe_bof = 1, + .short_xfer_ok = 1 + }, + .callback = rsu_bulk_rx_callback + }, + [RSU_BULK_TX_BE] = { + .type = UE_BULK, + .endpoint = 0x06, + .direction = UE_DIR_OUT, + .bufsize = RSU_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rsu_bulk_tx_callback, + .timeout = RSU_TX_TIMEOUT + }, + [RSU_BULK_TX_BK] = { + .type = UE_BULK, + .endpoint = 0x06, + .direction = UE_DIR_OUT, + .bufsize = RSU_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rsu_bulk_tx_callback, + .timeout = RSU_TX_TIMEOUT + }, + [RSU_BULK_TX_VI] = { + .type = UE_BULK, + .endpoint = 0x04, + .direction = UE_DIR_OUT, + .bufsize = RSU_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rsu_bulk_tx_callback, + .timeout = RSU_TX_TIMEOUT + }, + [RSU_BULK_TX_VO] = { + .type = UE_BULK, + .endpoint = 0x04, + .direction = UE_DIR_OUT, + .bufsize = RSU_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rsu_bulk_tx_callback, + .timeout = RSU_TX_TIMEOUT + }, +}; + +static int +rsu_match(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + + if (uaa->usb_mode != USB_MODE_HOST || + uaa->info.bIfaceIndex != 0 || + uaa->info.bConfigIndex != 0) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(rsu_devs, sizeof(rsu_devs), uaa)); +} + +static int +rsu_attach(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + struct rsu_softc *sc = device_get_softc(self); + struct ifnet *ifp; + struct ieee80211com *ic; + int error; + uint8_t iface_index, bands; + + device_set_usb_desc(self); + sc->sc_udev = uaa->device; + sc->sc_dev = self; + + mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, + MTX_DEF); + TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0, + rsu_calib_task, sc); + callout_init(&sc->sc_watchdog_ch, 0); + + iface_index = 0; + error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, + rsu_config, RSU_N_TRANSFER, sc, &sc->sc_mtx); + if (error) { + device_printf(sc->sc_dev, + "could not allocate USB transfers, err=%s\n", + usbd_errstr(error)); + goto detach; + } + RSU_LOCK(sc); + /* Read chip revision. */ + sc->cut = MS(rsu_read_4(sc, R92S_PMC_FSM), R92S_PMC_FSM_CUT); + if (sc->cut != 3) + sc->cut = (sc->cut >> 1) + 1; + error = rsu_read_rom(sc); + if (error != 0) { + device_printf(self, "could not read ROM\n"); + goto detach; + } + RSU_UNLOCK(sc); + IEEE80211_ADDR_COPY(sc->sc_bssid, &sc->rom[0x12]); + device_printf(self, "MAC/BB RTL8712 cut %d\n", sc->cut); + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(self, "cannot allocate interface\n"); + goto detach; + } + ic = ifp->if_l2com; + ifp->if_softc = sc; + if_initname(ifp, "rsu", device_get_unit(self)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = rsu_init; + ifp->if_ioctl = rsu_ioctl; + ifp->if_start = rsu_start; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + ifp->if_capabilities |= IFCAP_RXCSUM; + ifp->if_capenable |= IFCAP_RXCSUM; + ifp->if_hwassist = CSUM_TCP; + + ic->ic_ifp = ifp; + ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */ + ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */ + + /* Set device capabilities. */ + ic->ic_caps = + IEEE80211_C_STA | /* station mode */ + IEEE80211_C_BGSCAN | /* Background scan. */ + IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ + IEEE80211_C_SHSLOT | /* Short slot time supported. */ + IEEE80211_C_WPA; /* WPA/RSN. */ + +#if 0 + /* Check if HT support is present. */ + if (usb_lookup(rsu_devs_noht, uaa->vendor, uaa->product) == NULL) { + /* Set HT capabilities. */ + ic->ic_htcaps = + IEEE80211_HTCAP_CBW20_40 | + IEEE80211_HTCAP_DSSSCCK40; + /* Set supported HT rates. */ + for (i = 0; i < 2; i++) + ic->ic_sup_mcs[i] = 0xff; + } +#endif + + /* Set supported .11b and .11g rates. */ + bands = 0; + setbit(&bands, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11G); + ieee80211_init_channels(ic, NULL, &bands); + + ieee80211_ifattach(ic, sc->sc_bssid); + ic->ic_raw_xmit = rsu_raw_xmit; + ic->ic_scan_start = rsu_scan_start; + ic->ic_scan_end = rsu_scan_end; + ic->ic_set_channel = rsu_set_channel; + ic->ic_vap_create = rsu_vap_create; + ic->ic_vap_delete = rsu_vap_delete; + ic->ic_update_mcast = rsu_update_mcast; + + ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, + sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + RSU_RX_RADIOTAP_PRESENT); + + if (bootverbose) + ieee80211_announce(ic); + + return (0); + +detach: + rsu_detach(self); + return (ENXIO); +} + +static int +rsu_detach(device_t self) +{ + struct rsu_softc *sc = device_get_softc(self); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + if (!device_is_attached(self)) + return (0); + rsu_stop(ifp, 1); + usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); + ieee80211_ifdetach(ic); + + callout_drain(&sc->sc_watchdog_ch); + taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); + + /* Free Tx/Rx buffers. */ + rsu_free_tx_list(sc); + rsu_free_rx_list(sc); + + if_free(ifp); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static usb_error_t +rsu_do_request(struct rsu_softc *sc, struct usb_device_request *req, + void *data) +{ + usb_error_t err; + int ntries = 10; + + RSU_ASSERT_LOCKED(sc); + + while (ntries--) { + err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, + req, data, 0, NULL, 250 /* ms */); + if (err == 0 || !device_is_attached(sc->sc_dev)) + break; + DPRINTFN(1, "Control request failed, %s (retrying)\n", + usbd_errstr(err)); + usb_pause_mtx(&sc->sc_mtx, hz / 100); + } + + return (err); +} + +static struct ieee80211vap * +rsu_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, + enum ieee80211_opmode opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct rsu_vap *uvp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return (NULL); + + uvp = (struct rsu_vap *) malloc(sizeof(struct rsu_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (uvp == NULL) + return (NULL); + vap = &uvp->vap; + ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags, bssid, mac); + + /* override state transition machine */ + uvp->newstate = vap->iv_newstate; + vap->iv_newstate = rsu_newstate; + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status); + ic->ic_opmode = opmode; + + return (vap); +} + +static void +rsu_vap_delete(struct ieee80211vap *vap) +{ + struct rsu_vap *uvp = RSU_VAP(vap); + + ieee80211_vap_detach(vap); + free(uvp, M_80211_VAP); +} + +static void +rsu_scan_start(struct ieee80211com *ic) +{ + int error; + struct ifnet *ifp = ic->ic_ifp; + struct rsu_softc *sc = ifp->if_softc; + + /* Scanning is done by the firmware. */ + RSU_LOCK(sc); + error = rsu_site_survey(sc, TAILQ_FIRST(&ic->ic_vaps)); + RSU_UNLOCK(sc); + if (error != 0) + device_printf(sc->sc_dev, + "could not send site survey command\n"); +} + +static void +rsu_scan_end(struct ieee80211com *ic) +{ + /* Nothing to do here. */ +} + +static void +rsu_set_channel(struct ieee80211com *ic __unused) +{ + /* We are unable to switch channels, yet. */ +} + +static void +rsu_update_mcast(struct ifnet *ifp) +{ + /* XXX do nothing? */ +} + +static int +rsu_alloc_list(struct rsu_softc *sc, struct rsu_data data[], + int ndata, int maxsz) +{ + int i, error; + + for (i = 0; i < ndata; i++) { + struct rsu_data *dp = &data[i]; + dp->sc = sc; + dp->m = NULL; + dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); + if (dp->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate buffer\n"); + error = ENOMEM; + goto fail; + } + dp->ni = NULL; + } + + return (0); +fail: + rsu_free_list(sc, data, ndata); + return (error); +} + +static int +rsu_alloc_rx_list(struct rsu_softc *sc) +{ + int error, i; + + error = rsu_alloc_list(sc, sc->sc_rx, RSU_RX_LIST_COUNT, + RSU_RXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&sc->sc_rx_active); + STAILQ_INIT(&sc->sc_rx_inactive); + + for (i = 0; i < RSU_RX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next); + + return (0); +} + +static int +rsu_alloc_tx_list(struct rsu_softc *sc) +{ + int error, i; + + error = rsu_alloc_list(sc, sc->sc_tx, RSU_TX_LIST_COUNT, + RSU_TXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&sc->sc_tx_active); + STAILQ_INIT(&sc->sc_tx_inactive); + STAILQ_INIT(&sc->sc_tx_pending); + + for (i = 0; i < RSU_TX_LIST_COUNT; i++) { + STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next); + } + + return (0); +} + +static void +rsu_free_tx_list(struct rsu_softc *sc) +{ + rsu_free_list(sc, sc->sc_tx, RSU_TX_LIST_COUNT); +} + +static void +rsu_free_rx_list(struct rsu_softc *sc) +{ + rsu_free_list(sc, sc->sc_rx, RSU_RX_LIST_COUNT); +} + +static void +rsu_free_list(struct rsu_softc *sc, struct rsu_data data[], int ndata) +{ + int i; + + for (i = 0; i < ndata; i++) { + struct rsu_data *dp = &data[i]; + + if (dp->buf != NULL) { + free(dp->buf, M_USBDEV); + dp->buf = NULL; + } + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + } +} + +static struct rsu_data * +_rsu_getbuf(struct rsu_softc *sc) +{ + struct rsu_data *bf; + + bf = STAILQ_FIRST(&sc->sc_tx_inactive); + if (bf != NULL) + STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); + else + bf = NULL; + if (bf == NULL) + DPRINTF("out of xmit buffers\n"); + return (bf); +} + +static struct rsu_data * +rsu_getbuf(struct rsu_softc *sc) +{ + struct rsu_data *bf; + + RSU_ASSERT_LOCKED(sc); + + bf = _rsu_getbuf(sc); + if (bf == NULL) { + struct ifnet *ifp = sc->sc_ifp; + DPRINTF("stop queue\n"); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + } + return (bf); +} + +static int +rsu_write_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = R92S_REQ_REGS; + USETW(req.wValue, addr); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + + return (rsu_do_request(sc, &req, buf)); +} + +static void +rsu_write_1(struct rsu_softc *sc, uint16_t addr, uint8_t val) +{ + rsu_write_region_1(sc, addr, &val, 1); +} + +static void +rsu_write_2(struct rsu_softc *sc, uint16_t addr, uint16_t val) +{ + val = htole16(val); + rsu_write_region_1(sc, addr, (uint8_t *)&val, 2); +} + +static void +rsu_write_4(struct rsu_softc *sc, uint16_t addr, uint32_t val) +{ + val = htole32(val); + rsu_write_region_1(sc, addr, (uint8_t *)&val, 4); +} + +static int +rsu_read_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***