1251487Sadrian/*- 2251487Sadrian * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org> 3251487Sadrian * All rights reserved. 4251487Sadrian * 5251487Sadrian * Redistribution and use in source and binary forms, with or without 6251487Sadrian * modification, are permitted provided that the following conditions 7251487Sadrian * are met: 8251487Sadrian * 1. Redistributions of source code must retain the above copyright 9251487Sadrian * notice, this list of conditions and the following disclaimer, 10251487Sadrian * without modification. 11251487Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12251487Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13251487Sadrian * redistribution must be conditioned upon including a substantially 14251487Sadrian * similar Disclaimer requirement for further binary redistribution. 15251487Sadrian * 16251487Sadrian * NO WARRANTY 17251487Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18251487Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19251487Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20251487Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21251487Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22251487Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23251487Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24251487Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25251487Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26251487Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27251487Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 28251487Sadrian * 29251487Sadrian * $FreeBSD: stable/11/sys/dev/ath/if_ath_btcoex.c 332303 2018-04-08 20:50:16Z emaste $ 30251487Sadrian */ 31251487Sadrian#include <sys/cdefs.h> 32251487Sadrian__FBSDID("$FreeBSD: stable/11/sys/dev/ath/if_ath_btcoex.c 332303 2018-04-08 20:50:16Z emaste $"); 33251487Sadrian 34251487Sadrian/* 35251487Sadrian * This implements some very basic bluetooth coexistence methods for 36251487Sadrian * the ath(4) hardware. 37251487Sadrian */ 38251487Sadrian#include "opt_ath.h" 39251487Sadrian#include "opt_inet.h" 40251487Sadrian#include "opt_wlan.h" 41251487Sadrian 42251487Sadrian#include <sys/param.h> 43251487Sadrian#include <sys/systm.h> 44251487Sadrian#include <sys/sysctl.h> 45251487Sadrian#include <sys/kernel.h> 46251487Sadrian#include <sys/lock.h> 47257176Sglebius#include <sys/malloc.h> 48251487Sadrian#include <sys/mutex.h> 49251487Sadrian#include <sys/errno.h> 50251487Sadrian#include <machine/bus.h> 51251487Sadrian#include <machine/resource.h> 52301181Sadrian 53251487Sadrian#include <sys/bus.h> 54251487Sadrian 55251487Sadrian#include <sys/socket.h> 56251487Sadrian 57251487Sadrian#include <net/if.h> 58257176Sglebius#include <net/if_var.h> 59251487Sadrian#include <net/if_media.h> 60251487Sadrian#include <net/if_arp.h> 61251487Sadrian#include <net/ethernet.h> /* XXX for ether_sprintf */ 62251487Sadrian 63251487Sadrian#include <net80211/ieee80211_var.h> 64251487Sadrian 65251487Sadrian#include <net/bpf.h> 66251487Sadrian 67251487Sadrian#ifdef INET 68251487Sadrian#include <netinet/in.h> 69251487Sadrian#include <netinet/if_ether.h> 70251487Sadrian#endif 71251487Sadrian 72251487Sadrian#include <dev/ath/if_athvar.h> 73251487Sadrian#include <dev/ath/if_ath_btcoex.h> 74301181Sadrian#include <dev/ath/if_ath_btcoex_mci.h> 75251487Sadrian 76301181SadrianMALLOC_DECLARE(M_ATHDEV); 77301181Sadrian 78251487Sadrian/* 79251487Sadrian * Initial AR9285 / (WB195) bluetooth coexistence settings, 80251487Sadrian * just for experimentation. 81251487Sadrian * 82251487Sadrian * Return 0 for OK; errno for error. 83251487Sadrian * 84251487Sadrian * XXX TODO: There needs to be a PCIe workaround to disable ASPM if 85251487Sadrian * bluetooth coexistence is enabled. 86251487Sadrian */ 87251487Sadrianstatic int 88251487Sadrianath_btcoex_cfg_wb195(struct ath_softc *sc) 89251487Sadrian{ 90251487Sadrian HAL_BT_COEX_INFO btinfo; 91251487Sadrian HAL_BT_COEX_CONFIG btconfig; 92251487Sadrian struct ath_hal *ah = sc->sc_ah; 93251487Sadrian 94251487Sadrian if (! ath_hal_btcoex_supported(ah)) 95251487Sadrian return (EINVAL); 96251487Sadrian 97251487Sadrian bzero(&btinfo, sizeof(btinfo)); 98251487Sadrian bzero(&btconfig, sizeof(btconfig)); 99251487Sadrian 100251487Sadrian device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n"); 101251487Sadrian 102251487Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; 103251487Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 104251487Sadrian /* 105251487Sadrian * These are the three GPIO pins hooked up between the AR9285 and 106251487Sadrian * the AR3011. 107251487Sadrian */ 108251487Sadrian btinfo.bt_gpio_bt_active = 6; 109251487Sadrian btinfo.bt_gpio_bt_priority = 7; 110251487Sadrian btinfo.bt_gpio_wlan_active = 5; 111251487Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 112251487Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 113251487Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 114251487Sadrian 115251487Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 116251487Sadrian 117251487Sadrian btconfig.bt_time_extend = 0; 118251487Sadrian btconfig.bt_txstate_extend = 1; /* true */ 119251487Sadrian btconfig.bt_txframe_extend = 1; /* true */ 120251487Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 121251487Sadrian btconfig.bt_quiet_collision = 1; /* true */ 122251487Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 123251487Sadrian btconfig.bt_priority_time = 2; 124251487Sadrian btconfig.bt_first_slot_time = 5; 125251487Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 126251487Sadrian 127251487Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 128251487Sadrian 129251487Sadrian /* 130251487Sadrian * Enable antenna diversity. 131251487Sadrian */ 132251487Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 133251487Sadrian 134251487Sadrian return (0); 135251487Sadrian} 136251487Sadrian 137251742Sadrian/* 138251742Sadrian * Initial AR9485 / (WB225) bluetooth coexistence settings, 139251742Sadrian * just for experimentation. 140251742Sadrian * 141251742Sadrian * Return 0 for OK; errno for error. 142251742Sadrian */ 143251742Sadrianstatic int 144251742Sadrianath_btcoex_cfg_wb225(struct ath_softc *sc) 145251742Sadrian{ 146251742Sadrian HAL_BT_COEX_INFO btinfo; 147251742Sadrian HAL_BT_COEX_CONFIG btconfig; 148251742Sadrian struct ath_hal *ah = sc->sc_ah; 149251742Sadrian 150251742Sadrian if (! ath_hal_btcoex_supported(ah)) 151251742Sadrian return (EINVAL); 152251742Sadrian 153251742Sadrian bzero(&btinfo, sizeof(btinfo)); 154251742Sadrian bzero(&btconfig, sizeof(btconfig)); 155251742Sadrian 156251742Sadrian device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n"); 157251742Sadrian 158251742Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 159251742Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 160251742Sadrian /* 161251742Sadrian * These are the three GPIO pins hooked up between the AR9485 and 162251742Sadrian * the bluetooth module. 163251742Sadrian */ 164251742Sadrian btinfo.bt_gpio_bt_active = 4; 165251742Sadrian btinfo.bt_gpio_bt_priority = 8; 166251742Sadrian btinfo.bt_gpio_wlan_active = 5; 167251742Sadrian 168251742Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 169251742Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 170251742Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 171251742Sadrian 172251742Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 173251742Sadrian 174251742Sadrian btconfig.bt_time_extend = 0; 175251742Sadrian btconfig.bt_txstate_extend = 1; /* true */ 176251742Sadrian btconfig.bt_txframe_extend = 1; /* true */ 177251742Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 178251742Sadrian btconfig.bt_quiet_collision = 1; /* true */ 179251742Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 180251742Sadrian btconfig.bt_priority_time = 2; 181251742Sadrian btconfig.bt_first_slot_time = 5; 182251742Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 183251742Sadrian 184251742Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 185251742Sadrian 186251742Sadrian /* 187251742Sadrian * Enable antenna diversity. 188251742Sadrian */ 189251742Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 190251742Sadrian 191251742Sadrian return (0); 192251742Sadrian} 193251742Sadrian 194277277Sadrianstatic int 195301181Sadrianath_btcoex_cfg_mci(struct ath_softc *sc, uint32_t mci_cfg, int do_btdiv) 196277277Sadrian{ 197277277Sadrian HAL_BT_COEX_INFO btinfo; 198277277Sadrian HAL_BT_COEX_CONFIG btconfig; 199277277Sadrian struct ath_hal *ah = sc->sc_ah; 200251742Sadrian 201277277Sadrian if (! ath_hal_btcoex_supported(ah)) 202277277Sadrian return (EINVAL); 203277277Sadrian 204277277Sadrian bzero(&btinfo, sizeof(btinfo)); 205277277Sadrian bzero(&btconfig, sizeof(btconfig)); 206277277Sadrian 207301181Sadrian sc->sc_ah->ah_config.ath_hal_mci_config = mci_cfg; 208277277Sadrian 209301181Sadrian if (ath_btcoex_mci_attach(sc) != 0) { 210301181Sadrian device_printf(sc->sc_dev, "Failed to setup btcoex\n"); 211301181Sadrian return (EINVAL); 212301181Sadrian } 213301181Sadrian 214277277Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 215277277Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_MCI; 216277277Sadrian 217277277Sadrian /* 218277277Sadrian * MCI uses a completely different interface to speak 219277277Sadrian * to the bluetooth module - it's a command based 220277277Sadrian * thing over a serial line, rather than 221277277Sadrian * state pins to/from the bluetooth module. 222277277Sadrian * 223277277Sadrian * So, the GPIO configuration, polarity, etc 224277277Sadrian * doesn't matter on MCI devices; it's just 225277277Sadrian * completely ignored by the HAL. 226277277Sadrian */ 227277277Sadrian btinfo.bt_gpio_bt_active = 4; 228277277Sadrian btinfo.bt_gpio_bt_priority = 8; 229277277Sadrian btinfo.bt_gpio_wlan_active = 5; 230277277Sadrian 231277277Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 232301181Sadrian btinfo.bt_single_ant = 0; /* 2 antenna on WB335 */ 233277277Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 234277277Sadrian 235277277Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 236277277Sadrian 237277277Sadrian btconfig.bt_time_extend = 0; 238277277Sadrian btconfig.bt_txstate_extend = 1; /* true */ 239277277Sadrian btconfig.bt_txframe_extend = 1; /* true */ 240277277Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 241277277Sadrian btconfig.bt_quiet_collision = 1; /* true */ 242277277Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 243277277Sadrian btconfig.bt_priority_time = 2; 244277277Sadrian btconfig.bt_first_slot_time = 5; 245277277Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 246277277Sadrian 247277277Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 248277277Sadrian 249301181Sadrian /* Enable */ 250301181Sadrian ath_hal_btcoex_enable(sc->sc_ah); 251301181Sadrian 252301181Sadrian /* Stomp */ 253301181Sadrian ath_hal_btcoex_set_weights(ah, HAL_BT_COEX_STOMP_NONE); 254301181Sadrian 255277277Sadrian /* 256277277Sadrian * Enable antenna diversity. 257277277Sadrian */ 258301181Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 259301181Sadrian do_btdiv); 260277277Sadrian 261277277Sadrian return (0); 262277277Sadrian} 263277277Sadrian 264300896Sadrian/* 265301181Sadrian * Initial AR9462 / (WB222) bluetooth coexistence settings. 266300896Sadrian * 267300896Sadrian * Return 0 for OK; errno for error. 268300896Sadrian */ 269300896Sadrianstatic int 270301181Sadrianath_btcoex_cfg_wb222(struct ath_softc *sc) 271300896Sadrian{ 272277277Sadrian 273301181Sadrian device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n"); 274301181Sadrian /* XXX from ath9k */ 275301181Sadrian return (ath_btcoex_cfg_mci(sc, 0x2201, 1)); 276301181Sadrian} 277277277Sadrian 278301181Sadrian/* 279301181Sadrian * Initial QCA9565 / (WB335B) bluetooth coexistence settings. 280301181Sadrian * 281301181Sadrian * Return 0 for OK; errno for error. 282301181Sadrian */ 283301181Sadrianstatic int 284301181Sadrianath_btcoex_cfg_wb335b(struct ath_softc *sc) 285301181Sadrian{ 286301181Sadrian uint32_t flags; 287301181Sadrian int do_btdiv = 0; 288277277Sadrian 289301181Sadrian /* ath9k default */ 290301181Sadrian flags = 0xa4c1; 291300896Sadrian 292301181Sadrian /* 1-ant and 2-ant AR9565 */ 293300896Sadrian /* 294301181Sadrian * XXX TODO: ensure these actually make it down to the 295301181Sadrian * HAL correctly! 296300896Sadrian */ 297301181Sadrian if (sc->sc_pci_devinfo & ATH_PCI_AR9565_1ANT) { 298301186Sadrian flags &= ~ATH_MCI_CONFIG_ANT_ARCH; 299301186Sadrian flags |= ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED << 300301186Sadrian ATH_MCI_CONFIG_ANT_ARCH_S; 301301181Sadrian } else if (sc->sc_pci_devinfo & ATH_PCI_AR9565_2ANT) { 302301186Sadrian flags &= ~ATH_MCI_CONFIG_ANT_ARCH; 303301186Sadrian flags |= ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_NON_SHARED << 304301186Sadrian ATH_MCI_CONFIG_ANT_ARCH_S; 305301181Sadrian } 306300896Sadrian 307301181Sadrian if (sc->sc_pci_devinfo & ATH_PCI_BT_ANT_DIV) { 308301181Sadrian do_btdiv = 1; 309301181Sadrian } 310300896Sadrian 311301181Sadrian device_printf(sc->sc_dev, "Enabling WB335 BTCOEX\n"); 312301181Sadrian /* XXX from ath9k */ 313301181Sadrian return (ath_btcoex_cfg_mci(sc, flags, do_btdiv)); 314300896Sadrian} 315300896Sadrian 316251487Sadrian#if 0 317251487Sadrian/* 318251487Sadrian * When using bluetooth coexistence, ASPM needs to be disabled 319251487Sadrian * otherwise the sleeping interferes with the bluetooth (USB) 320251487Sadrian * operation and the MAC sleep/wakeup hardware. 321251606Sadrian * 322251606Sadrian * The PCIe powersave routine also needs to not be called 323251606Sadrian * by the driver during suspend/resume, else things will get 324251606Sadrian * a little odd. Check Linux ath9k for more details. 325251487Sadrian */ 326251487Sadrianstatic int 327251487Sadrianath_btcoex_aspm_wb195(struct ath_softc *sc) 328251487Sadrian{ 329251487Sadrian 330251487Sadrian /* XXX TODO: clear device ASPM L0S and L1 */ 331251487Sadrian /* XXX TODO: clear _parent_ ASPM L0S and L1 */ 332251487Sadrian} 333251487Sadrian#endif 334251487Sadrian 335251487Sadrian/* 336251487Sadrian * Methods which are required 337251487Sadrian */ 338251487Sadrian 339251487Sadrian/* 340251487Sadrian * Attach btcoex to the given interface 341251487Sadrian */ 342251487Sadrianint 343251487Sadrianath_btcoex_attach(struct ath_softc *sc) 344251487Sadrian{ 345251487Sadrian int ret; 346251487Sadrian struct ath_hal *ah = sc->sc_ah; 347251487Sadrian const char *profname; 348251487Sadrian 349251487Sadrian /* 350251487Sadrian * No chipset bluetooth coexistence? Then do nothing. 351251487Sadrian */ 352251487Sadrian if (! ath_hal_btcoex_supported(ah)) 353251487Sadrian return (0); 354251487Sadrian 355251487Sadrian /* 356251487Sadrian * Look at the hints to determine which bluetooth 357251487Sadrian * profile to configure. 358251487Sadrian */ 359251487Sadrian ret = resource_string_value(device_get_name(sc->sc_dev), 360251487Sadrian device_get_unit(sc->sc_dev), 361251487Sadrian "btcoex_profile", 362251487Sadrian &profname); 363251487Sadrian if (ret != 0) { 364251487Sadrian /* nothing to do */ 365251487Sadrian return (0); 366251487Sadrian } 367251487Sadrian 368251487Sadrian if (strncmp(profname, "wb195", 5) == 0) { 369251487Sadrian ret = ath_btcoex_cfg_wb195(sc); 370277277Sadrian } else if (strncmp(profname, "wb222", 5) == 0) { 371277277Sadrian ret = ath_btcoex_cfg_wb222(sc); 372251742Sadrian } else if (strncmp(profname, "wb225", 5) == 0) { 373251742Sadrian ret = ath_btcoex_cfg_wb225(sc); 374300896Sadrian } else if (strncmp(profname, "wb335", 5) == 0) { 375300896Sadrian ret = ath_btcoex_cfg_wb335b(sc); 376251487Sadrian } else { 377251487Sadrian return (0); 378251487Sadrian } 379251487Sadrian 380251487Sadrian /* 381251487Sadrian * Propagate up failure from the actual attach phase. 382251487Sadrian */ 383251487Sadrian if (ret != 0) 384251487Sadrian return (ret); 385251487Sadrian 386251487Sadrian return (0); 387251487Sadrian} 388251487Sadrian 389251487Sadrian/* 390251487Sadrian * Detach btcoex from the given interface 391251487Sadrian */ 392251487Sadrianint 393251487Sadrianath_btcoex_detach(struct ath_softc *sc) 394251487Sadrian{ 395301181Sadrian if (sc->sc_btcoex_mci) { 396301181Sadrian ath_btcoex_mci_detach(sc); 397301181Sadrian } 398251487Sadrian 399251487Sadrian return (0); 400251487Sadrian} 401251487Sadrian 402251487Sadrian/* 403251487Sadrian * Configure or disable bluetooth coexistence on the given channel. 404251487Sadrian * 405251487Sadrian * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just 406251487Sadrian * assume bluetooth coexistence is always on. 407251487Sadrian * 408251487Sadrian * For AR9462, we may see a 5GHz channel; bluetooth coexistence should 409251487Sadrian * not be enabled on those channels. 410251487Sadrian */ 411251487Sadrianint 412251487Sadrianath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) 413251487Sadrian{ 414301181Sadrian if (sc->sc_btcoex_mci) { 415301181Sadrian ath_btcoex_mci_enable(sc, chan); 416301181Sadrian } 417251487Sadrian 418251487Sadrian return (0); 419251487Sadrian} 420251487Sadrian 421251487Sadrian/* 422251487Sadrian * Handle ioctl requests from the diagnostic interface. 423251487Sadrian * 424251487Sadrian * The initial part of this code resembles ath_ioctl_diag(); 425251487Sadrian * it's likely a good idea to reduce duplication between 426251487Sadrian * these two routines. 427251487Sadrian */ 428251487Sadrianint 429251487Sadrianath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad) 430251487Sadrian{ 431251487Sadrian unsigned int id = ad->ad_id & ATH_DIAG_ID; 432251487Sadrian void *indata = NULL; 433251487Sadrian void *outdata = NULL; 434251487Sadrian u_int32_t insize = ad->ad_in_size; 435251487Sadrian u_int32_t outsize = ad->ad_out_size; 436251487Sadrian int error = 0; 437251487Sadrian// int val; 438251487Sadrian 439251487Sadrian if (ad->ad_id & ATH_DIAG_IN) { 440251487Sadrian /* 441251487Sadrian * Copy in data. 442251487Sadrian */ 443251487Sadrian indata = malloc(insize, M_TEMP, M_NOWAIT); 444251487Sadrian if (indata == NULL) { 445251487Sadrian error = ENOMEM; 446251487Sadrian goto bad; 447251487Sadrian } 448251487Sadrian error = copyin(ad->ad_in_data, indata, insize); 449251487Sadrian if (error) 450251487Sadrian goto bad; 451251487Sadrian } 452251487Sadrian if (ad->ad_id & ATH_DIAG_DYN) { 453251487Sadrian /* 454251487Sadrian * Allocate a buffer for the results (otherwise the HAL 455251487Sadrian * returns a pointer to a buffer where we can read the 456251487Sadrian * results). Note that we depend on the HAL leaving this 457251487Sadrian * pointer for us to use below in reclaiming the buffer; 458251487Sadrian * may want to be more defensive. 459251487Sadrian */ 460332303Semaste outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO); 461251487Sadrian if (outdata == NULL) { 462251487Sadrian error = ENOMEM; 463251487Sadrian goto bad; 464251487Sadrian } 465251487Sadrian } 466251487Sadrian switch (id) { 467251487Sadrian default: 468251487Sadrian error = EINVAL; 469332303Semaste goto bad; 470251487Sadrian } 471251487Sadrian if (outsize < ad->ad_out_size) 472251487Sadrian ad->ad_out_size = outsize; 473251487Sadrian if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) 474251487Sadrian error = EFAULT; 475251487Sadrianbad: 476251487Sadrian if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 477251487Sadrian free(indata, M_TEMP); 478251487Sadrian if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 479251487Sadrian free(outdata, M_TEMP); 480251487Sadrian return (error); 481251487Sadrian} 482251487Sadrian 483