if_ath_btcoex.c revision 300896
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: head/sys/dev/ath/if_ath_btcoex.c 300896 2016-05-28 02:14:24Z adrian $ 30251487Sadrian */ 31251487Sadrian#include <sys/cdefs.h> 32251487Sadrian__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_btcoex.c 300896 2016-05-28 02:14:24Z adrian $"); 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 51251487Sadrian#include <machine/bus.h> 52251487Sadrian#include <machine/resource.h> 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> 74251487Sadrian 75251487Sadrian/* 76251487Sadrian * Initial AR9285 / (WB195) bluetooth coexistence settings, 77251487Sadrian * just for experimentation. 78251487Sadrian * 79251487Sadrian * Return 0 for OK; errno for error. 80251487Sadrian * 81251487Sadrian * XXX TODO: There needs to be a PCIe workaround to disable ASPM if 82251487Sadrian * bluetooth coexistence is enabled. 83251487Sadrian */ 84251487Sadrianstatic int 85251487Sadrianath_btcoex_cfg_wb195(struct ath_softc *sc) 86251487Sadrian{ 87251487Sadrian HAL_BT_COEX_INFO btinfo; 88251487Sadrian HAL_BT_COEX_CONFIG btconfig; 89251487Sadrian struct ath_hal *ah = sc->sc_ah; 90251487Sadrian 91251487Sadrian if (! ath_hal_btcoex_supported(ah)) 92251487Sadrian return (EINVAL); 93251487Sadrian 94251487Sadrian bzero(&btinfo, sizeof(btinfo)); 95251487Sadrian bzero(&btconfig, sizeof(btconfig)); 96251487Sadrian 97251487Sadrian device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n"); 98251487Sadrian 99251487Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; 100251487Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 101251487Sadrian /* 102251487Sadrian * These are the three GPIO pins hooked up between the AR9285 and 103251487Sadrian * the AR3011. 104251487Sadrian */ 105251487Sadrian btinfo.bt_gpio_bt_active = 6; 106251487Sadrian btinfo.bt_gpio_bt_priority = 7; 107251487Sadrian btinfo.bt_gpio_wlan_active = 5; 108251487Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 109251487Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 110251487Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 111251487Sadrian 112251487Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 113251487Sadrian 114251487Sadrian btconfig.bt_time_extend = 0; 115251487Sadrian btconfig.bt_txstate_extend = 1; /* true */ 116251487Sadrian btconfig.bt_txframe_extend = 1; /* true */ 117251487Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 118251487Sadrian btconfig.bt_quiet_collision = 1; /* true */ 119251487Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 120251487Sadrian btconfig.bt_priority_time = 2; 121251487Sadrian btconfig.bt_first_slot_time = 5; 122251487Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 123251487Sadrian 124251487Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 125251487Sadrian 126251487Sadrian /* 127251487Sadrian * Enable antenna diversity. 128251487Sadrian */ 129251487Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 130251487Sadrian 131251487Sadrian return (0); 132251487Sadrian} 133251487Sadrian 134251742Sadrian/* 135251742Sadrian * Initial AR9485 / (WB225) bluetooth coexistence settings, 136251742Sadrian * just for experimentation. 137251742Sadrian * 138251742Sadrian * Return 0 for OK; errno for error. 139251742Sadrian */ 140251742Sadrianstatic int 141251742Sadrianath_btcoex_cfg_wb225(struct ath_softc *sc) 142251742Sadrian{ 143251742Sadrian HAL_BT_COEX_INFO btinfo; 144251742Sadrian HAL_BT_COEX_CONFIG btconfig; 145251742Sadrian struct ath_hal *ah = sc->sc_ah; 146251742Sadrian 147251742Sadrian if (! ath_hal_btcoex_supported(ah)) 148251742Sadrian return (EINVAL); 149251742Sadrian 150251742Sadrian bzero(&btinfo, sizeof(btinfo)); 151251742Sadrian bzero(&btconfig, sizeof(btconfig)); 152251742Sadrian 153251742Sadrian device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n"); 154251742Sadrian 155251742Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 156251742Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 157251742Sadrian /* 158251742Sadrian * These are the three GPIO pins hooked up between the AR9485 and 159251742Sadrian * the bluetooth module. 160251742Sadrian */ 161251742Sadrian btinfo.bt_gpio_bt_active = 4; 162251742Sadrian btinfo.bt_gpio_bt_priority = 8; 163251742Sadrian btinfo.bt_gpio_wlan_active = 5; 164251742Sadrian 165251742Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 166251742Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 167251742Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 168251742Sadrian 169251742Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 170251742Sadrian 171251742Sadrian btconfig.bt_time_extend = 0; 172251742Sadrian btconfig.bt_txstate_extend = 1; /* true */ 173251742Sadrian btconfig.bt_txframe_extend = 1; /* true */ 174251742Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 175251742Sadrian btconfig.bt_quiet_collision = 1; /* true */ 176251742Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 177251742Sadrian btconfig.bt_priority_time = 2; 178251742Sadrian btconfig.bt_first_slot_time = 5; 179251742Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 180251742Sadrian 181251742Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 182251742Sadrian 183251742Sadrian /* 184251742Sadrian * Enable antenna diversity. 185251742Sadrian */ 186251742Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 187251742Sadrian 188251742Sadrian return (0); 189251742Sadrian} 190251742Sadrian 191277277Sadrian/* 192277277Sadrian * Initial AR9462 / (WB222) bluetooth coexistence settings, 193277277Sadrian * just for experimentation. 194277277Sadrian * 195277277Sadrian * Return 0 for OK; errno for error. 196277277Sadrian */ 197277277Sadrianstatic int 198277277Sadrianath_btcoex_cfg_wb222(struct ath_softc *sc) 199277277Sadrian{ 200277277Sadrian HAL_BT_COEX_INFO btinfo; 201277277Sadrian HAL_BT_COEX_CONFIG btconfig; 202277277Sadrian struct ath_hal *ah = sc->sc_ah; 203251742Sadrian 204277277Sadrian if (! ath_hal_btcoex_supported(ah)) 205277277Sadrian return (EINVAL); 206277277Sadrian 207277277Sadrian bzero(&btinfo, sizeof(btinfo)); 208277277Sadrian bzero(&btconfig, sizeof(btconfig)); 209277277Sadrian 210277277Sadrian device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n"); 211277277Sadrian 212277277Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 213277277Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_MCI; 214277277Sadrian 215277277Sadrian /* 216277277Sadrian * MCI uses a completely different interface to speak 217277277Sadrian * to the bluetooth module - it's a command based 218277277Sadrian * thing over a serial line, rather than 219277277Sadrian * state pins to/from the bluetooth module. 220277277Sadrian * 221277277Sadrian * So, the GPIO configuration, polarity, etc 222277277Sadrian * doesn't matter on MCI devices; it's just 223277277Sadrian * completely ignored by the HAL. 224277277Sadrian */ 225277277Sadrian btinfo.bt_gpio_bt_active = 4; 226277277Sadrian btinfo.bt_gpio_bt_priority = 8; 227277277Sadrian btinfo.bt_gpio_wlan_active = 5; 228277277Sadrian 229277277Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 230277277Sadrian btinfo.bt_single_ant = 0; /* 2 antenna on WB222 */ 231277277Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 232277277Sadrian 233277277Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 234277277Sadrian 235277277Sadrian btconfig.bt_time_extend = 0; 236277277Sadrian btconfig.bt_txstate_extend = 1; /* true */ 237277277Sadrian btconfig.bt_txframe_extend = 1; /* true */ 238277277Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 239277277Sadrian btconfig.bt_quiet_collision = 1; /* true */ 240277277Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 241277277Sadrian btconfig.bt_priority_time = 2; 242277277Sadrian btconfig.bt_first_slot_time = 5; 243277277Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 244277277Sadrian 245277277Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 246277277Sadrian 247277277Sadrian /* 248277277Sadrian * Enable antenna diversity. 249277277Sadrian */ 250277277Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 251277277Sadrian 252277277Sadrian return (0); 253277277Sadrian} 254277277Sadrian 255300896Sadrian/* 256300896Sadrian * Initial QCA9565 / (WB335B) bluetooth coexistence settings, 257300896Sadrian * just for experimentation. 258300896Sadrian * 259300896Sadrian * Return 0 for OK; errno for error. 260300896Sadrian */ 261300896Sadrianstatic int 262300896Sadrianath_btcoex_cfg_wb335b(struct ath_softc *sc) 263300896Sadrian{ 264300896Sadrian HAL_BT_COEX_INFO btinfo; 265300896Sadrian HAL_BT_COEX_CONFIG btconfig; 266300896Sadrian struct ath_hal *ah = sc->sc_ah; 267277277Sadrian 268300896Sadrian if (! ath_hal_btcoex_supported(ah)) 269300896Sadrian return (EINVAL); 270277277Sadrian 271300896Sadrian bzero(&btinfo, sizeof(btinfo)); 272300896Sadrian bzero(&btconfig, sizeof(btconfig)); 273277277Sadrian 274300896Sadrian device_printf(sc->sc_dev, "Enabling WB335B BTCOEX\n"); 275300896Sadrian 276300896Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 277300896Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_MCI; 278300896Sadrian 279300896Sadrian /* 280300896Sadrian * MCI uses a completely different interface to speak 281300896Sadrian * to the bluetooth module - it's a command based 282300896Sadrian * thing over a serial line, rather than 283300896Sadrian * state pins to/from the bluetooth module. 284300896Sadrian * 285300896Sadrian * So, the GPIO configuration, polarity, etc 286300896Sadrian * doesn't matter on MCI devices; it's just 287300896Sadrian * completely ignored by the HAL. 288300896Sadrian */ 289300896Sadrian btinfo.bt_gpio_bt_active = 4; 290300896Sadrian btinfo.bt_gpio_bt_priority = 8; 291300896Sadrian btinfo.bt_gpio_wlan_active = 5; 292300896Sadrian 293300896Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 294300896Sadrian btinfo.bt_single_ant = 0; /* 2 antenna on WB335 */ 295300896Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 296300896Sadrian 297300896Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 298300896Sadrian 299300896Sadrian btconfig.bt_time_extend = 0; 300300896Sadrian btconfig.bt_txstate_extend = 1; /* true */ 301300896Sadrian btconfig.bt_txframe_extend = 1; /* true */ 302300896Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 303300896Sadrian btconfig.bt_quiet_collision = 1; /* true */ 304300896Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 305300896Sadrian btconfig.bt_priority_time = 2; 306300896Sadrian btconfig.bt_first_slot_time = 5; 307300896Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 308300896Sadrian 309300896Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 310300896Sadrian 311300896Sadrian /* 312300896Sadrian * Enable antenna diversity. 313300896Sadrian */ 314300896Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 315300896Sadrian 316300896Sadrian return (0); 317300896Sadrian} 318300896Sadrian 319300896Sadrian 320251487Sadrian#if 0 321251487Sadrian/* 322251487Sadrian * When using bluetooth coexistence, ASPM needs to be disabled 323251487Sadrian * otherwise the sleeping interferes with the bluetooth (USB) 324251487Sadrian * operation and the MAC sleep/wakeup hardware. 325251606Sadrian * 326251606Sadrian * The PCIe powersave routine also needs to not be called 327251606Sadrian * by the driver during suspend/resume, else things will get 328251606Sadrian * a little odd. Check Linux ath9k for more details. 329251487Sadrian */ 330251487Sadrianstatic int 331251487Sadrianath_btcoex_aspm_wb195(struct ath_softc *sc) 332251487Sadrian{ 333251487Sadrian 334251487Sadrian /* XXX TODO: clear device ASPM L0S and L1 */ 335251487Sadrian /* XXX TODO: clear _parent_ ASPM L0S and L1 */ 336251487Sadrian} 337251487Sadrian#endif 338251487Sadrian 339251487Sadrian/* 340251487Sadrian * Methods which are required 341251487Sadrian */ 342251487Sadrian 343251487Sadrian/* 344251487Sadrian * Attach btcoex to the given interface 345251487Sadrian */ 346251487Sadrianint 347251487Sadrianath_btcoex_attach(struct ath_softc *sc) 348251487Sadrian{ 349251487Sadrian int ret; 350251487Sadrian struct ath_hal *ah = sc->sc_ah; 351251487Sadrian const char *profname; 352251487Sadrian 353251487Sadrian /* 354251487Sadrian * No chipset bluetooth coexistence? Then do nothing. 355251487Sadrian */ 356251487Sadrian if (! ath_hal_btcoex_supported(ah)) 357251487Sadrian return (0); 358251487Sadrian 359251487Sadrian /* 360251487Sadrian * Look at the hints to determine which bluetooth 361251487Sadrian * profile to configure. 362251487Sadrian */ 363251487Sadrian ret = resource_string_value(device_get_name(sc->sc_dev), 364251487Sadrian device_get_unit(sc->sc_dev), 365251487Sadrian "btcoex_profile", 366251487Sadrian &profname); 367251487Sadrian if (ret != 0) { 368251487Sadrian /* nothing to do */ 369251487Sadrian return (0); 370251487Sadrian } 371251487Sadrian 372251487Sadrian if (strncmp(profname, "wb195", 5) == 0) { 373251487Sadrian ret = ath_btcoex_cfg_wb195(sc); 374277277Sadrian } else if (strncmp(profname, "wb222", 5) == 0) { 375277277Sadrian ret = ath_btcoex_cfg_wb222(sc); 376251742Sadrian } else if (strncmp(profname, "wb225", 5) == 0) { 377251742Sadrian ret = ath_btcoex_cfg_wb225(sc); 378300896Sadrian } else if (strncmp(profname, "wb335", 5) == 0) { 379300896Sadrian ret = ath_btcoex_cfg_wb335b(sc); 380251487Sadrian } else { 381251487Sadrian return (0); 382251487Sadrian } 383251487Sadrian 384251487Sadrian /* 385251487Sadrian * Propagate up failure from the actual attach phase. 386251487Sadrian */ 387251487Sadrian if (ret != 0) 388251487Sadrian return (ret); 389251487Sadrian 390251487Sadrian return (0); 391251487Sadrian} 392251487Sadrian 393251487Sadrian/* 394251487Sadrian * Detach btcoex from the given interface 395251487Sadrian */ 396251487Sadrianint 397251487Sadrianath_btcoex_detach(struct ath_softc *sc) 398251487Sadrian{ 399251487Sadrian 400251487Sadrian return (0); 401251487Sadrian} 402251487Sadrian 403251487Sadrian/* 404251487Sadrian * Configure or disable bluetooth coexistence on the given channel. 405251487Sadrian * 406251487Sadrian * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just 407251487Sadrian * assume bluetooth coexistence is always on. 408251487Sadrian * 409251487Sadrian * For AR9462, we may see a 5GHz channel; bluetooth coexistence should 410251487Sadrian * not be enabled on those channels. 411251487Sadrian */ 412251487Sadrianint 413251487Sadrianath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) 414251487Sadrian{ 415251487Sadrian 416251487Sadrian return (0); 417251487Sadrian} 418251487Sadrian 419251487Sadrian/* 420251487Sadrian * Handle ioctl requests from the diagnostic interface. 421251487Sadrian * 422251487Sadrian * The initial part of this code resembles ath_ioctl_diag(); 423251487Sadrian * it's likely a good idea to reduce duplication between 424251487Sadrian * these two routines. 425251487Sadrian */ 426251487Sadrianint 427251487Sadrianath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad) 428251487Sadrian{ 429251487Sadrian unsigned int id = ad->ad_id & ATH_DIAG_ID; 430251487Sadrian void *indata = NULL; 431251487Sadrian void *outdata = NULL; 432251487Sadrian u_int32_t insize = ad->ad_in_size; 433251487Sadrian u_int32_t outsize = ad->ad_out_size; 434251487Sadrian int error = 0; 435251487Sadrian// int val; 436251487Sadrian 437251487Sadrian if (ad->ad_id & ATH_DIAG_IN) { 438251487Sadrian /* 439251487Sadrian * Copy in data. 440251487Sadrian */ 441251487Sadrian indata = malloc(insize, M_TEMP, M_NOWAIT); 442251487Sadrian if (indata == NULL) { 443251487Sadrian error = ENOMEM; 444251487Sadrian goto bad; 445251487Sadrian } 446251487Sadrian error = copyin(ad->ad_in_data, indata, insize); 447251487Sadrian if (error) 448251487Sadrian goto bad; 449251487Sadrian } 450251487Sadrian if (ad->ad_id & ATH_DIAG_DYN) { 451251487Sadrian /* 452251487Sadrian * Allocate a buffer for the results (otherwise the HAL 453251487Sadrian * returns a pointer to a buffer where we can read the 454251487Sadrian * results). Note that we depend on the HAL leaving this 455251487Sadrian * pointer for us to use below in reclaiming the buffer; 456251487Sadrian * may want to be more defensive. 457251487Sadrian */ 458251487Sadrian outdata = malloc(outsize, M_TEMP, M_NOWAIT); 459251487Sadrian if (outdata == NULL) { 460251487Sadrian error = ENOMEM; 461251487Sadrian goto bad; 462251487Sadrian } 463251487Sadrian } 464251487Sadrian switch (id) { 465251487Sadrian default: 466251487Sadrian error = EINVAL; 467251487Sadrian } 468251487Sadrian if (outsize < ad->ad_out_size) 469251487Sadrian ad->ad_out_size = outsize; 470251487Sadrian if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) 471251487Sadrian error = EFAULT; 472251487Sadrianbad: 473251487Sadrian if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 474251487Sadrian free(indata, M_TEMP); 475251487Sadrian if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 476251487Sadrian free(outdata, M_TEMP); 477251487Sadrian return (error); 478251487Sadrian} 479251487Sadrian 480