ath - Basic re-port, base code compile
[dragonfly.git] / sys / dev / netif / ath / ath / if_ath_spectral.c
CommitLineData
572ff6f6
MD
1/*-
2 * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
15 *
16 * NO WARRANTY
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
28 *
29 * $FreeBSD$
30 */
31#include <sys/cdefs.h>
572ff6f6
MD
32
33/*
34 * Implement some basic spectral scan control logic.
35 */
36#include "opt_ath.h"
37#include "opt_inet.h"
38#include "opt_wlan.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/sysctl.h>
43#include <sys/kernel.h>
44#include <sys/lock.h>
45#include <sys/malloc.h>
46#include <sys/mutex.h>
47#include <sys/errno.h>
572ff6f6 48#include <sys/bus.h>
572ff6f6
MD
49#include <sys/socket.h>
50
51#include <net/if.h>
52#include <net/if_var.h>
53#include <net/if_media.h>
54#include <net/if_arp.h>
55#include <net/ethernet.h> /* XXX for ether_sprintf */
56
5cd80a8c 57#include <netproto/802_11/ieee80211_var.h>
572ff6f6
MD
58
59#include <net/bpf.h>
60
61#ifdef INET
62#include <netinet/in.h>
63#include <netinet/if_ether.h>
64#endif
65
5cd80a8c
MD
66#include <dev/netif/ath/ath/if_athvar.h>
67#include <dev/netif/ath/ath/if_ath_spectral.h>
572ff6f6 68
5cd80a8c 69#include <dev/netif/ath/ath_hal/ah_desc.h>
572ff6f6
MD
70
71struct ath_spectral_state {
72 HAL_SPECTRAL_PARAM spectral_state;
73
74 /*
75 * Should we enable spectral scan upon
76 * each network interface reset/change?
77 *
78 * This is intended to allow spectral scan
79 * frame reporting during channel scans.
80 *
81 * Later on it can morph into a larger
82 * scale config method where it pushes
83 * a "channel scan" config into the hardware
84 * rather than just the spectral_state
85 * config.
86 */
87 int spectral_enable_after_reset;
88};
89
90/*
91 * Methods which are required
92 */
93
94/*
95 * Attach spectral to the given interface
96 */
97int
98ath_spectral_attach(struct ath_softc *sc)
99{
100 struct ath_spectral_state *ss;
101
102 /*
103 * If spectral isn't supported, don't error - just
104 * quietly complete.
105 */
106 if (! ath_hal_spectral_supported(sc->sc_ah))
107 return (0);
108
3133c5e3 109 ss = kmalloc(sizeof(struct ath_spectral_state),
572ff6f6
MD
110 M_TEMP, M_WAITOK | M_ZERO);
111
112 if (ss == NULL) {
113 device_printf(sc->sc_dev, "%s: failed to alloc memory\n",
114 __func__);
115 return (-ENOMEM);
116 }
117
118 sc->sc_spectral = ss;
119
120 (void) ath_hal_spectral_get_config(sc->sc_ah, &ss->spectral_state);
121
122 return (0);
123}
124
125/*
126 * Detach spectral from the given interface
127 */
128int
129ath_spectral_detach(struct ath_softc *sc)
130{
131
132 if (! ath_hal_spectral_supported(sc->sc_ah))
133 return (0);
134
135 if (sc->sc_spectral != NULL) {
3133c5e3 136 kfree(sc->sc_spectral, M_TEMP);
572ff6f6
MD
137 }
138 return (0);
139}
140
141/*
142 * Check whether spectral needs enabling and if so,
143 * flip it on.
144 */
145int
146ath_spectral_enable(struct ath_softc *sc, struct ieee80211_channel *ch)
147{
148 struct ath_spectral_state *ss = sc->sc_spectral;
149
150 /* Default to disable spectral PHY reporting */
151 sc->sc_dospectral = 0;
152
153 if (ss == NULL)
154 return (0);
155
156 if (ss->spectral_enable_after_reset) {
157 ath_hal_spectral_configure(sc->sc_ah,
158 &ss->spectral_state);
159 (void) ath_hal_spectral_start(sc->sc_ah);
160 sc->sc_dospectral = 1;
161 }
162 return (0);
163}
164
165/*
166 * Handle ioctl requests from the diagnostic interface.
167 *
168 * The initial part of this code resembles ath_ioctl_diag();
169 * it's likely a good idea to reduce duplication between
170 * these two routines.
171 */
172int
173ath_ioctl_spectral(struct ath_softc *sc, struct ath_diag *ad)
174{
175 unsigned int id = ad->ad_id & ATH_DIAG_ID;
176 void *indata = NULL;
177 void *outdata = NULL;
178 u_int32_t insize = ad->ad_in_size;
179 u_int32_t outsize = ad->ad_out_size;
180 int error = 0;
181 HAL_SPECTRAL_PARAM peout;
182 HAL_SPECTRAL_PARAM *pe;
183 struct ath_spectral_state *ss = sc->sc_spectral;
184 int val;
185
186 if (! ath_hal_spectral_supported(sc->sc_ah))
187 return (EINVAL);
188
189 if (ad->ad_id & ATH_DIAG_IN) {
190 /*
191 * Copy in data.
192 */
3133c5e3 193 indata = kmalloc(insize, M_TEMP, M_INTWAIT);
572ff6f6
MD
194 if (indata == NULL) {
195 error = ENOMEM;
196 goto bad;
197 }
198 error = copyin(ad->ad_in_data, indata, insize);
199 if (error)
200 goto bad;
201 }
202 if (ad->ad_id & ATH_DIAG_DYN) {
203 /*
204 * Allocate a buffer for the results (otherwise the HAL
205 * returns a pointer to a buffer where we can read the
206 * results). Note that we depend on the HAL leaving this
207 * pointer for us to use below in reclaiming the buffer;
208 * may want to be more defensive.
209 */
3133c5e3 210 outdata = kmalloc(outsize, M_TEMP, M_INTWAIT);
572ff6f6
MD
211 if (outdata == NULL) {
212 error = ENOMEM;
213 goto bad;
214 }
215 }
216 switch (id) {
217 case SPECTRAL_CONTROL_GET_PARAMS:
218 memset(&peout, 0, sizeof(peout));
219 outsize = sizeof(HAL_SPECTRAL_PARAM);
220 ath_hal_spectral_get_config(sc->sc_ah, &peout);
221 pe = (HAL_SPECTRAL_PARAM *) outdata;
222 memcpy(pe, &peout, sizeof(*pe));
223 break;
224 case SPECTRAL_CONTROL_SET_PARAMS:
225 if (insize < sizeof(HAL_SPECTRAL_PARAM)) {
226 error = EINVAL;
227 break;
228 }
229 pe = (HAL_SPECTRAL_PARAM *) indata;
230 ath_hal_spectral_configure(sc->sc_ah, pe);
231 /* Save a local copy of the updated parameters */
232 ath_hal_spectral_get_config(sc->sc_ah,
233 &ss->spectral_state);
234 break;
235 case SPECTRAL_CONTROL_START:
236 ath_hal_spectral_configure(sc->sc_ah,
237 &ss->spectral_state);
238 (void) ath_hal_spectral_start(sc->sc_ah);
239 sc->sc_dospectral = 1;
240 /* XXX need to update the PHY mask in the driver */
241 break;
242 case SPECTRAL_CONTROL_STOP:
243 (void) ath_hal_spectral_stop(sc->sc_ah);
244 sc->sc_dospectral = 0;
245 /* XXX need to update the PHY mask in the driver */
246 break;
247 case SPECTRAL_CONTROL_ENABLE_AT_RESET:
248 if (insize < sizeof(int)) {
249 device_printf(sc->sc_dev, "%d != %d\n",
250 insize,
251 (int) sizeof(int));
252 error = EINVAL;
253 break;
254 }
255 if (indata == NULL) {
256 device_printf(sc->sc_dev, "indata=NULL\n");
257 error = EINVAL;
258 break;
259 }
260 val = * ((int *) indata);
261 if (val == 0)
262 ss->spectral_enable_after_reset = 0;
263 else
264 ss->spectral_enable_after_reset = 1;
265 break;
266 case SPECTRAL_CONTROL_ENABLE:
267 /* XXX TODO */
268 case SPECTRAL_CONTROL_DISABLE:
269 /* XXX TODO */
270 break;
271 default:
272 error = EINVAL;
273 }
274 if (outsize < ad->ad_out_size)
275 ad->ad_out_size = outsize;
276 if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
277 error = EFAULT;
278bad:
279 if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
3133c5e3 280 kfree(indata, M_TEMP);
572ff6f6 281 if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
3133c5e3 282 kfree(outdata, M_TEMP);
572ff6f6
MD
283 return (error);
284}
285