xref: /onnv-gate/usr/src/uts/common/io/pcwl/pcwl.c (revision 11878:ac93462db6d7)
1 /*
2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 1997, 1998, 1999
8  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by Bill Paul.
21  * 4. Neither the name of the author nor the names of any co-contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35  * THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/conf.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
41 #include <sys/dlpi.h>
42 #include <sys/ethernet.h>
43 #include <sys/strsubr.h>
44 #include <sys/strsun.h>
45 #include <sys/stat.h>
46 #include <sys/byteorder.h>
47 #include <sys/pccard.h>
48 #include <sys/pci.h>
49 #include <sys/policy.h>
50 #include <sys/mac_provider.h>
51 #include <sys/stream.h>
52 #include <inet/common.h>
53 #include <inet/nd.h>
54 #include <inet/mi.h>
55 
56 #include "pcwl.h"
57 #include <sys/mac_wifi.h>
58 #include <inet/wifi_ioctl.h>
59 
60 #ifdef DEBUG
61 #define	PCWL_DBG_BASIC		0x1
62 #define	PCWL_DBG_INFO		0x2
63 #define	PCWL_DBG_SEND		0x4
64 #define	PCWL_DBG_RCV		0x8
65 #define	PCWL_DBG_LINKINFO	0x10
66 uint32_t pcwl_debug = 0;
67 #define	PCWLDBG(x) \
68 	if (pcwl_debug & PCWL_DBG_BASIC) cmn_err x
69 #else
70 #define	PCWLDBG(x)
71 #endif
72 
73 /* for pci card */
74 static ddi_device_acc_attr_t accattr = {
75 		DDI_DEVICE_ATTR_V0,
76 		DDI_NEVERSWAP_ACC,
77 		DDI_STRICTORDER_ACC,
78 		DDI_DEFAULT_ACC
79 };
80 
81 void *pcwl_soft_state_p = NULL;
82 static int pcwl_device_type;
83 
84 static int	pcwl_m_setprop(void *arg, const char *pr_name,
85     mac_prop_id_t wldp_pr_num, uint_t wldp_length,
86     const void *wldp_buf);
87 static int	pcwl_m_getprop(void *arg, const char *pr_name,
88     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
89 static void	pcwl_m_propinfo(void *arg, const char *pr_name,
90     mac_prop_id_t wlpd_pr_num, mac_prop_info_handle_t mph);
91 static void
92 pcwl_delay(pcwl_maci_t *, clock_t);
93 
94 mac_callbacks_t pcwl_m_callbacks = {
95 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
96 	pcwl_gstat,
97 	pcwl_start,
98 	pcwl_stop,
99 	pcwl_prom,
100 	pcwl_sdmulti,
101 	pcwl_saddr,
102 	pcwl_tx,
103 	NULL,
104 	pcwl_ioctl,
105 	NULL,
106 	NULL,
107 	NULL,
108 	pcwl_m_setprop,
109 	pcwl_m_getprop,
110 	pcwl_m_propinfo
111 };
112 
113 static char *pcwl_name_str = "pcwl";
114 
115 #ifdef	__sparc
116 #define	pcwl_quiesce	ddi_quiesce_not_supported
117 #else
118 static int pcwl_quiesce(dev_info_t *);
119 #endif
120 
121 DDI_DEFINE_STREAM_OPS(pcwl_dev_ops, nulldev, pcwl_probe, pcwl_attach,
122     pcwl_detach, nodev, NULL, D_MP, NULL, pcwl_quiesce);
123 
124 extern struct mod_ops mod_driverops;
125 static struct modldrv modldrv = {
126 	&mod_driverops,
127 	"Lucent/PRISM-II 802.11b driver",
128 	&pcwl_dev_ops
129 };
130 
131 static struct modlinkage modlinkage = {
132 	MODREV_1, (void *)&modldrv, NULL
133 	};
134 
135 int
_init(void)136 _init(void)
137 {
138 	int stat;
139 
140 	/* Allocate soft state */
141 	if ((stat = ddi_soft_state_init(&pcwl_soft_state_p,
142 	    sizeof (pcwl_maci_t), N_PCWL)) != DDI_SUCCESS)
143 		return (stat);
144 
145 	mac_init_ops(&pcwl_dev_ops, "pcwl");
146 	wl_frame_default.wl_dat[0] = htons(WL_SNAP_WORD0);
147 	wl_frame_default.wl_dat[1] = htons(WL_SNAP_WORD1);
148 	stat = mod_install(&modlinkage);
149 	if (stat != DDI_SUCCESS) {
150 		mac_fini_ops(&pcwl_dev_ops);
151 		ddi_soft_state_fini(&pcwl_soft_state_p);
152 	}
153 	return (stat);
154 }
155 
156 int
_fini(void)157 _fini(void)
158 {
159 	int stat;
160 
161 	if ((stat = mod_remove(&modlinkage)) != DDI_SUCCESS)
162 		return (stat);
163 	mac_fini_ops(&pcwl_dev_ops);
164 	ddi_soft_state_fini(&pcwl_soft_state_p);
165 
166 	return (stat);
167 }
168 
169 int
_info(struct modinfo * modinfop)170 _info(struct modinfo *modinfop)
171 {
172 	return (mod_info(&modlinkage, modinfop));
173 }
174 
175 static int
pcwl_probe(dev_info_t * dip)176 pcwl_probe(dev_info_t *dip)
177 {
178 	int len, ret;
179 	char *buf;
180 	dev_info_t *pdip = ddi_get_parent(dip);
181 
182 	ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
183 	    (caddr_t)&buf, &len);
184 	if (ret != DDI_SUCCESS)
185 		return (DDI_PROBE_FAILURE);
186 
187 	PCWLDBG((CE_NOTE, "pcwl probe: device_type %s\n", buf));
188 	if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
189 		pcwl_device_type = PCWL_DEVICE_PCCARD;
190 		ret = DDI_PROBE_SUCCESS;
191 	} else if (strcmp(buf, "pci") == 0) {
192 		pcwl_device_type = PCWL_DEVICE_PCI;
193 		ret = DDI_PROBE_SUCCESS;
194 	} else {
195 		ret = DDI_PROBE_FAILURE;
196 	}
197 	kmem_free(buf, len);
198 	return (ret);
199 }
200 
201 static int
pcwl_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)202 pcwl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
203 {
204 	int ret, i;
205 	int instance;
206 	uint16_t stat;
207 	uint32_t err;
208 	pcwl_maci_t *pcwl_p;
209 	wifi_data_t	wd = { 0 };
210 	mac_register_t	*macp;
211 	modify_config_t cfgmod;
212 	char strbuf[256];
213 
214 	PCWLDBG((CE_NOTE, "pcwl attach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
215 	if (cmd != DDI_ATTACH)
216 		goto attach_fail1;
217 	/*
218 	 * Allocate soft state associated with this instance.
219 	 */
220 	if (ddi_soft_state_zalloc(pcwl_soft_state_p,
221 	    ddi_get_instance(dip)) != DDI_SUCCESS) {
222 		cmn_err(CE_CONT, "pcwl attach: alloc softstate failed\n");
223 		goto attach_fail1;
224 	}
225 	pcwl_p = (pcwl_maci_t *)ddi_get_soft_state(pcwl_soft_state_p,
226 	    ddi_get_instance(dip));
227 	pcwl_p->pcwl_device_type = pcwl_device_type;
228 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
229 		if (ddi_regs_map_setup(dip, 0,
230 		    (caddr_t *)&pcwl_p->pcwl_cfg_base, 0, 0,
231 		    &accattr, &pcwl_p->pcwl_cfg_handle) != DDI_SUCCESS) {
232 			cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
233 			    " failed\n");
234 			goto attach_fail2;
235 		}
236 
237 		stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
238 		    (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
239 		stat |= (PCI_COMM_IO | PCI_COMM_MAE);
240 		ddi_put16(pcwl_p->pcwl_cfg_handle,
241 		    (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM), stat);
242 		stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
243 		    (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
244 		if ((stat & (PCI_COMM_IO | PCI_COMM_MAE)) !=
245 		    (PCI_COMM_IO | PCI_COMM_MAE)) {
246 			cmn_err(CE_WARN, "pcwl(pci) attach: pci command"
247 			    " reg enable failed\n");
248 			goto attach_fail2a;
249 		}
250 
251 
252 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcwl_p->pcwl_bar,
253 		    0, 0, &accattr, (ddi_acc_handle_t *)&pcwl_p->pcwl_handle)
254 		    != DDI_SUCCESS) {
255 			cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
256 			    " failed\n");
257 			goto attach_fail2a;
258 		}
259 		PCWLDBG((CE_NOTE, "pcwl(pci): regs_map_setup,bar=%p\n",
260 		    (void *)pcwl_p->pcwl_bar));
261 
262 		/*
263 		 * tricky! copy from freebsd code.
264 		 */
265 		PCWL_WRITE(pcwl_p, 0x26, 0x80);
266 		drv_usecwait(500000);
267 		PCWL_WRITE(pcwl_p, 0x26, 0x0);
268 		drv_usecwait(500000);
269 
270 		for (i = 0; i < WL_TIMEOUT; i++) {
271 			PCWL_READ(pcwl_p, 0x0, stat);
272 			if (stat & WL_CMD_BUSY)
273 				drv_usecwait(10);
274 			else
275 				break;
276 		}
277 		if (i == WL_TIMEOUT) {
278 			cmn_err(CE_WARN, "pcwl(pci) attach: hardware init"
279 			    " failed\n");
280 			goto attach_fail3;
281 		}
282 
283 		/*
284 		 * magic number verification.
285 		 * tricky! copy from freebsd code.
286 		 */
287 		PCWL_WRITE(pcwl_p, 0x28, 0x4a2d);
288 		PCWL_READ(pcwl_p, 0x28, stat);
289 		PCWLDBG((CE_NOTE, "pcwl(pci):magic number = %x\n", stat));
290 		if (stat != 0x4a2d) {
291 			cmn_err(CE_WARN, "pcwl(pci) attach: magic verify"
292 			    " failed\n");
293 			goto attach_fail3;
294 		}
295 	}
296 	pcwl_p->pcwl_dip	= dip;
297 	pcwl_p->pcwl_flag	= 0;
298 	pcwl_p->pcwl_socket	= ddi_getprop(DDI_DEV_T_NONE, dip,
299 	    DDI_PROP_DONTPASS, "socket", -1);
300 	pcwl_p->pcwl_reschedule_need = B_FALSE;
301 
302 	if (ddi_get_iblock_cookie(dip,
303 	    0, &pcwl_p->pcwl_ib_cookie) != DDI_SUCCESS) {
304 		cmn_err(CE_WARN, "pcwl attach: get_iblk_cookie failed\n");
305 		goto attach_fail3;
306 	}
307 
308 	mutex_init(&pcwl_p->pcwl_glock, NULL, MUTEX_DRIVER,
309 	    pcwl_p->pcwl_ib_cookie);
310 	mutex_init(&pcwl_p->pcwl_scanlist_lock, NULL, MUTEX_DRIVER,
311 	    pcwl_p->pcwl_ib_cookie);
312 	mutex_init(&pcwl_p->pcwl_txring.wl_tx_lock, NULL, MUTEX_DRIVER,
313 	    pcwl_p->pcwl_ib_cookie);
314 
315 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
316 		if (ret = ddi_add_intr(dip, 0, NULL, NULL,
317 		    pcwl_intr, (caddr_t)pcwl_p)) {
318 			cmn_err(CE_NOTE, "pcwl(pci) attach: add intr failed\n");
319 			goto attach_fail3a;
320 		}
321 	} else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
322 		if (ret = pcwl_register_cs(dip, pcwl_p)) {
323 			cmn_err(CE_WARN, "pcwl attach(pccard): "
324 			    "register_cs err %x\n", ret);
325 			goto attach_fail3a;
326 		}
327 	} else {
328 		cmn_err(CE_WARN, "pcwl attach: unsupported device type\n");
329 		goto attach_fail3a;
330 	}
331 	mutex_enter(&pcwl_p->pcwl_glock);
332 	if (ret = pcwl_reset_backend(pcwl_p)) {
333 		cmn_err(CE_WARN, "pcwl attach: reset_backend failed %x\n", ret);
334 		mutex_exit(&pcwl_p->pcwl_glock);
335 		goto attach_fail4;
336 	}
337 	if (ret = pcwl_get_cap(pcwl_p)) { /* sets macaddr for mac_register */
338 		cmn_err(CE_WARN, "pcwl attach: get_cap failed %x\n", ret);
339 		mutex_exit(&pcwl_p->pcwl_glock);
340 		goto attach_fail4;
341 	}
342 	mutex_exit(&pcwl_p->pcwl_glock);
343 	/*
344 	 * Provide initial settings for the WiFi plugin; whenever this
345 	 * information changes, we need to call mac_pdata_update()
346 	 */
347 	wd.wd_secalloc = WIFI_SEC_NONE;
348 	wd.wd_opmode = IEEE80211_M_STA;
349 
350 	macp = mac_alloc(MAC_VERSION);
351 	if (macp == NULL) {
352 		PCWLDBG((CE_NOTE, "pcwl attach: "
353 		    "MAC version mismatch\n"));
354 		goto attach_fail4;
355 	}
356 
357 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
358 	macp->m_driver		= pcwl_p;
359 	macp->m_dip		= dip;
360 	macp->m_src_addr	= pcwl_p->pcwl_mac_addr;
361 	macp->m_callbacks	= &pcwl_m_callbacks;
362 	macp->m_min_sdu		= 0;
363 	macp->m_max_sdu		= IEEE80211_MTU;
364 	macp->m_pdata		= &wd;
365 	macp->m_pdata_size	= sizeof (wd);
366 
367 	err = mac_register(macp, &pcwl_p->pcwl_mh);
368 	mac_free(macp);
369 	if (err != 0) {
370 		PCWLDBG((CE_NOTE, "pcwl attach: "
371 		    "mac_register err\n"));
372 		goto attach_fail4;
373 	}
374 
375 	mutex_enter(&pcwl_p->pcwl_glock);
376 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
377 		/*
378 		 * turn on CS interrupt
379 		 */
380 		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
381 		    CONF_IRQ_CHANGE_VALID;
382 		cfgmod.Vpp1 = 0;
383 		cfgmod.Vpp2 = 0;
384 		(void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
385 
386 	}
387 	if (ret = pcwl_init_nicmem(pcwl_p)) {
388 		cmn_err(CE_WARN, "pcwl(pccard) attach: pcwl_init_nicmem"
389 		    " failed %x\n", ret);
390 		mutex_exit(&pcwl_p->pcwl_glock);
391 		goto attach_fail5;
392 	}
393 	pcwl_chip_type(pcwl_p);
394 	if (ret = pcwl_loaddef_rf(pcwl_p)) {
395 		cmn_err(CE_WARN, "pcwl attach: config_rf failed%x\n", ret);
396 		mutex_exit(&pcwl_p->pcwl_glock);
397 		goto attach_fail5;
398 	}
399 	(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
400 	pcwl_stop_locked(pcwl_p);	/* leaves interface down */
401 	list_create(&pcwl_p->pcwl_scan_list, sizeof (wl_scan_list_t),
402 	    offsetof(wl_scan_list_t, wl_scan_node));
403 	pcwl_p->pcwl_scan_num = 0;
404 	mutex_exit(&pcwl_p->pcwl_glock);
405 	pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
406 	    pcwl_p, drv_usectohz(1000000));
407 	instance = ddi_get_instance(dip);
408 	(void) snprintf(strbuf, sizeof (strbuf), "pcwl%d", instance);
409 	if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
410 	    instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
411 		goto attach_fail6;
412 	}
413 	pcwl_p->pcwl_flag |= PCWL_ATTACHED;
414 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
415 		pcwl_p->pcwl_flag |= PCWL_CARD_READY;
416 	}
417 	return (DDI_SUCCESS);
418 attach_fail6:
419 	if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
420 		(void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
421 		pcwl_p->pcwl_scanlist_timeout_id = 0;
422 	}
423 	list_destroy(&pcwl_p->pcwl_scan_list);
424 attach_fail5:
425 	(void) mac_unregister(pcwl_p->pcwl_mh);
426 attach_fail4:
427 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
428 		ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
429 	} else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
430 		pcwl_unregister_cs(pcwl_p);
431 	}
432 attach_fail3a:
433 	pcwl_destroy_locks(pcwl_p);
434 attach_fail3:
435 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
436 		ddi_regs_map_free(&pcwl_p->pcwl_handle);
437 attach_fail2a:
438 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
439 		ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
440 attach_fail2:
441 	ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
442 attach_fail1:
443 	return (DDI_FAILURE);
444 }
445 
446 static int
pcwl_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)447 pcwl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
448 {
449 	pcwl_maci_t *pcwl_p;
450 	wl_scan_list_t *scan_item0;
451 	int ret;
452 	pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
453 
454 	PCWLDBG((CE_NOTE, "pcwl detach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
455 	if (cmd != DDI_DETACH)
456 		return (DDI_FAILURE);
457 	if (!(pcwl_p->pcwl_flag & PCWL_ATTACHED))
458 		return (DDI_FAILURE);
459 
460 	ret = mac_disable(pcwl_p->pcwl_mh);
461 	if (ret != 0)
462 		return (DDI_FAILURE);
463 
464 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
465 		mutex_enter(&pcwl_p->pcwl_glock);
466 		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
467 		PCWL_DISABLE_INTR(pcwl_p);
468 		mutex_exit(&pcwl_p->pcwl_glock);
469 	}
470 	if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
471 		(void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
472 		pcwl_p->pcwl_scanlist_timeout_id = 0;
473 	}
474 	if (pcwl_p->pcwl_connect_timeout_id != 0) {
475 		(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
476 		pcwl_p->pcwl_connect_timeout_id = 0;
477 	}
478 	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
479 	scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
480 	while (scan_item0) {
481 		pcwl_delete_scan_item(pcwl_p, scan_item0);
482 		scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
483 	}
484 	list_destroy(&pcwl_p->pcwl_scan_list);
485 	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
486 	(void) mac_unregister(pcwl_p->pcwl_mh);
487 
488 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
489 		mutex_enter(&pcwl_p->pcwl_glock);
490 		ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
491 		ddi_regs_map_free(&pcwl_p->pcwl_handle);
492 		ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
493 		mutex_exit(&pcwl_p->pcwl_glock);
494 	} else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
495 		pcwl_unregister_cs(pcwl_p);
496 	}
497 	pcwl_destroy_locks(pcwl_p);
498 	ddi_remove_minor_node(dip, NULL);
499 	ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
500 	return (DDI_SUCCESS);
501 }
502 
503 /*
504  * card services and event handlers
505  */
506 static int
pcwl_register_cs(dev_info_t * dip,pcwl_maci_t * pcwl_p)507 pcwl_register_cs(dev_info_t *dip, pcwl_maci_t *pcwl_p)
508 {
509 	int ret;
510 	client_reg_t cr;
511 	client_handle_t chdl; /* uint encoding of socket, function, client */
512 	get_status_t card_status;
513 	request_socket_mask_t sock_req;
514 
515 	bzero(&cr, sizeof (cr));
516 	cr.Attributes	= INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
517 	cr.EventMask	= CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
518 	    CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
519 	    CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME |
520 	    CS_EVENT_PM_SUSPEND | CS_EVENT_CLIENT_INFO;
521 	cr.event_callback_args.client_data = pcwl_p;
522 	cr.Version = CS_VERSION;
523 	cr.event_handler = (csfunction_t *)pcwl_ev_hdlr;
524 	cr.dip = dip;
525 	(void) strcpy(cr.driver_name, pcwl_name_str);
526 	if (ret = csx_RegisterClient(&chdl, &cr)) {
527 		cmn_err(CE_WARN, "pcwl: RegisterClient failed %x\n", ret);
528 		goto regcs_ret;
529 	}
530 	pcwl_p->pcwl_chdl = chdl;
531 
532 	bzero(&card_status, sizeof (card_status));
533 	(void) csx_GetStatus(chdl, &card_status);
534 	PCWLDBG((CE_NOTE,
535 	    "pcwl: register_cs: Sock=%x CState=%x SState=%x rState=%x\n",
536 	    card_status.Socket, card_status.CardState,
537 	    card_status.SocketState, card_status.raw_CardState));
538 	if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
539 		/* card is not present, why are we attaching ? */
540 		ret = CS_NO_CARD;
541 		goto regcs_unreg;
542 	}
543 	cv_init(&pcwl_p->pcwl_cscv, NULL, CV_DRIVER, NULL);
544 	mutex_init(&pcwl_p->pcwl_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
545 	mutex_enter(&pcwl_p->pcwl_cslock);
546 	if (ret = csx_MapLogSocket(chdl, &pcwl_p->pcwl_log_sock)) {
547 		cmn_err(CE_WARN, "pcwl: MapLogSocket failed %x\n", ret);
548 		goto regcs_fail;
549 	}
550 	PCWLDBG((CE_NOTE,
551 	    "pcwl: register_cs: LogSock=%x PhyAdapter=%x PhySock=%x\n",
552 	    pcwl_p->pcwl_log_sock.LogSocket,
553 	    pcwl_p->pcwl_log_sock.PhyAdapter,
554 	    pcwl_p->pcwl_log_sock.PhySocket));
555 	/* turn on initialization events */
556 	sock_req.Socket = 0;
557 	sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
558 	    CS_EVENT_REGISTRATION_COMPLETE;
559 	if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
560 		cmn_err(CE_WARN, "pcwl: RequestSocketMask failed %x\n", ret);
561 		goto regcs_fail;
562 	}
563 	/* wait for and process card insertion events */
564 	while (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
565 		cv_wait(&pcwl_p->pcwl_cscv, &pcwl_p->pcwl_cslock);
566 	mutex_exit(&pcwl_p->pcwl_cslock);
567 
568 	pcwl_p->pcwl_flag |= PCWL_CS_REGISTERED;
569 	return (PCWL_SUCCESS);
570 regcs_fail:
571 	mutex_destroy(&pcwl_p->pcwl_cslock);
572 	cv_destroy(&pcwl_p->pcwl_cscv);
573 regcs_unreg:
574 	(void) csx_DeregisterClient(chdl);
575 regcs_ret:
576 	pcwl_p->pcwl_flag &= ~PCWL_CS_REGISTERED;
577 	return (ret);
578 }
579 
580 static void
pcwl_unregister_cs(pcwl_maci_t * pcwl_p)581 pcwl_unregister_cs(pcwl_maci_t *pcwl_p)
582 {
583 	int ret;
584 	release_socket_mask_t mask;
585 	mask.Socket = pcwl_p->pcwl_socket;
586 
587 	/*
588 	 * The card service not registered means register_cs function
589 	 * doesnot return TRUE. Then all the lelated resource has been
590 	 * released in register_cs.
591 	 */
592 	if (!(pcwl_p->pcwl_flag | PCWL_CS_REGISTERED))
593 		return;
594 
595 	if (ret = csx_ReleaseSocketMask(pcwl_p->pcwl_chdl, &mask))
596 		cmn_err(CE_WARN, "pcwl: ReleaseSocket mask failed %x\n", ret);
597 
598 	if (pcwl_p->pcwl_flag & PCWL_CARD_READY) {
599 		pcwl_card_remove(pcwl_p);
600 		pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
601 	}
602 	mutex_destroy(&pcwl_p->pcwl_cslock);
603 	cv_destroy(&pcwl_p->pcwl_cscv);
604 	if (ret = csx_DeregisterClient(pcwl_p->pcwl_chdl))
605 		cmn_err(CE_WARN, "pcwl: Deregister failed %x\n", ret);
606 }
607 
608 static void
pcwl_destroy_locks(pcwl_maci_t * pcwl_p)609 pcwl_destroy_locks(pcwl_maci_t *pcwl_p)
610 {
611 	mutex_destroy(&pcwl_p->pcwl_txring.wl_tx_lock);
612 	mutex_destroy(&pcwl_p->pcwl_scanlist_lock);
613 	mutex_destroy(&pcwl_p->pcwl_glock);
614 }
615 
616 static void
617 pcwl_do_suspend(pcwl_maci_t *pcwl_p);
618 
619 static int
pcwl_ev_hdlr(event_t event,int priority,event_callback_args_t * arg)620 pcwl_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
621 {
622 	int ret = CS_SUCCESS;
623 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg->client_data;
624 	client_info_t *ci_p = (client_info_t *)&arg->client_info;
625 
626 	mutex_enter(&pcwl_p->pcwl_cslock);
627 	switch (event) {
628 	case CS_EVENT_CARD_INSERTION:
629 		ret = pcwl_card_insert(pcwl_p);
630 		cv_broadcast(&pcwl_p->pcwl_cscv);
631 		break;
632 	case CS_EVENT_REGISTRATION_COMPLETE:
633 		cv_broadcast(&pcwl_p->pcwl_cscv);
634 		break;
635 	case CS_EVENT_CARD_REMOVAL:
636 		if (priority & CS_EVENT_PRI_HIGH)
637 			break;
638 		pcwl_card_remove(pcwl_p);
639 		cv_broadcast(&pcwl_p->pcwl_cscv);
640 		break;
641 	case CS_EVENT_CLIENT_INFO:
642 		if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
643 		    CS_CLIENT_INFO_SUBSVC_CS)
644 			break;
645 
646 		ci_p->Revision = 0x0101;
647 		ci_p->CSLevel = CS_VERSION;
648 		ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
649 		(void) strcpy(ci_p->ClientName, PCWL_IDENT_STRING);
650 		(void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
651 		ci_p->Attributes |= CS_CLIENT_INFO_VALID;
652 		break;
653 	case CS_EVENT_PM_SUSPEND:
654 		pcwl_do_suspend(pcwl_p);
655 		break;
656 	default:
657 		ret = CS_UNSUPPORTED_EVENT;
658 		break;
659 	}
660 	mutex_exit(&pcwl_p->pcwl_cslock);
661 	return (ret);
662 }
663 
664 /*
665  * assume card is already removed, don't touch the hardware
666  */
667 static void
pcwl_do_suspend(pcwl_maci_t * pcwl_p)668 pcwl_do_suspend(pcwl_maci_t *pcwl_p)
669 {
670 	int ret;
671 
672 	if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
673 		if (pcwl_p->pcwl_connect_timeout_id != 0) {
674 			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
675 			pcwl_p->pcwl_connect_timeout_id = 0;
676 		}
677 		mutex_enter(&pcwl_p->pcwl_glock);
678 		pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
679 		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
680 		/*
681 		 * A workaround here: If the card is in ad-hoc mode, the
682 		 * following scan will not work correctly, so any
683 		 * 'dladm connect-wifi' which need a scan first will not
684 		 * succeed. software reset the card here as a workround.
685 		 */
686 		if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
687 		    (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
688 			(void) pcwl_reset_backend(pcwl_p);
689 			(void) pcwl_init_nicmem(pcwl_p);
690 			pcwl_start_locked(pcwl_p);
691 		}
692 		if (ret = pcwl_loaddef_rf(pcwl_p)) {
693 			PCWLDBG((CE_WARN, "cfg_loaddef_err %d\n", ret));
694 		}
695 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
696 			PCWLDBG((CE_WARN, "set enable cmd err\n"));
697 		}
698 		pcwl_delay(pcwl_p, 1000000);
699 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
700 			PCWLDBG((CE_WARN, "set disable cmd err\n"));
701 		}
702 		mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
703 		mutex_exit(&pcwl_p->pcwl_glock);
704 	}
705 	pcwl_p->pcwl_flag |= PCWL_CARD_SUSPEND;
706 	PCWLDBG((CE_WARN, "pcwl: do suspend\n"));
707 }
708 
709 
710 static int
pcwl_card_insert(pcwl_maci_t * pcwl_p)711 pcwl_card_insert(pcwl_maci_t *pcwl_p)
712 {
713 	int ret, hi, lo;
714 	tuple_t tuple;
715 	cisparse_t cisparse;
716 	io_req_t	io;
717 	irq_req_t	irq;
718 	config_req_t	cfg;
719 	cistpl_config_t config;
720 	cistpl_cftable_entry_t *tbl_p;
721 	register client_handle_t chdl = pcwl_p->pcwl_chdl;
722 	modify_config_t cfgmod;
723 
724 	bzero(&tuple, sizeof (tuple));
725 	tuple.DesiredTuple = CISTPL_MANFID;
726 	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
727 		cmn_err(CE_WARN, "pcwl: get manufacture id failed %x\n", ret);
728 		goto insert_ret;
729 	}
730 	bzero(&cisparse, sizeof (cisparse));
731 	if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
732 		cmn_err(CE_WARN, "pcwl: parse manufacture id failed %x\n", ret);
733 		goto insert_ret;
734 	}
735 
736 	/*
737 	 * verify manufacture ID
738 	 */
739 	PCWLDBG((CE_NOTE, "pcwl insert: manufacturer_id=%x card=%x\n",
740 	    cisparse.manfid.manf, cisparse.manfid.card));
741 	bzero(&tuple, sizeof (tuple));
742 	tuple.DesiredTuple = CISTPL_FUNCID;
743 	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
744 		cmn_err(CE_WARN, "pcwl: get function id failed %x\n", ret);
745 		goto insert_ret;
746 	}
747 	bzero(&cisparse, sizeof (cisparse));
748 	if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
749 		cmn_err(CE_WARN, "pcwl: parse function id failed %x\n", ret);
750 		goto insert_ret;
751 	}
752 
753 	/*
754 	 * verify function ID
755 	 */
756 	PCWLDBG((CE_NOTE, "insert:fun_id=%x\n", cisparse.funcid.function));
757 	bzero(&tuple, sizeof (tuple));
758 	tuple.DesiredTuple = CISTPL_CONFIG;
759 	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
760 		cmn_err(CE_WARN, "pcwl: get config failed %x\n", ret);
761 		goto insert_ret;
762 	}
763 	bzero(&config, sizeof (config));
764 	if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
765 		cmn_err(CE_WARN, "pcwl: parse config failed %x\n", ret);
766 		goto insert_ret;
767 	}
768 	PCWLDBG((CE_NOTE,
769 	    "pcwl: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
770 	    config.present, config.nr, config.hr, config.regs[0],
771 	    config.base, config.last));
772 	hi = 0;
773 	lo = (int)-1;		/* really big number */
774 	tbl_p = &cisparse.cftable;
775 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
776 	for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
777 		PCWLDBG((CE_NOTE, "pcwl insert:tuple idx=%x:\n", tbl_p->index));
778 		if (ret = csx_GetNextTuple(chdl, &tuple)) {
779 			cmn_err(CE_WARN, "pcwl: get cftable failed %x\n",
780 			    ret);
781 			break;
782 		}
783 		bzero((caddr_t)&cisparse, sizeof (cisparse));
784 		if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
785 			cmn_err(CE_WARN, "pcwl: parse cftable failed %x\n",
786 			    ret);
787 			break;
788 		}
789 		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
790 		    tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
791 			if (tbl_p->pd.pd_vcc.avgI > hi) {
792 				hi = tbl_p->pd.pd_vcc.avgI;
793 				pcwl_p->pcwl_config_hi = tbl_p->index;
794 			}
795 			if (tbl_p->pd.pd_vcc.avgI < lo) {
796 				lo = tbl_p->pd.pd_vcc.avgI;
797 				pcwl_p->pcwl_config = tbl_p->index;
798 			}
799 		}
800 		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
801 			if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
802 				pcwl_p->pcwl_vcc = tbl_p->pd.pd_vcc.nomV;
803 			if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
804 				pcwl_p->pcwl_iodecode = tbl_p->io.addr_lines;
805 		}
806 	}
807 	PCWLDBG((CE_NOTE, "pcwl: insert:cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
808 	    pcwl_p->pcwl_config_hi, pcwl_p->pcwl_config,
809 	    pcwl_p->pcwl_vcc, pcwl_p->pcwl_iodecode));
810 	bzero(&io, sizeof (io));
811 	io.BasePort1.base = 0;
812 	io.NumPorts1 = 1 << pcwl_p->pcwl_iodecode;
813 	io.Attributes1 = IO_DATA_PATH_WIDTH_16;
814 	io.IOAddrLines = pcwl_p->pcwl_iodecode;
815 	if (ret = csx_RequestIO(chdl, &io)) {
816 		cmn_err(CE_WARN, "pcwl: RequestIO failed %x\n", ret);
817 		goto insert_ret;
818 	}
819 	pcwl_p->pcwl_port = io.BasePort1.handle;
820 	if (ret = ddi_add_softintr(DIP(pcwl_p), DDI_SOFTINT_HIGH,
821 	    &pcwl_p->pcwl_softint_id, &pcwl_p->pcwl_ib_cookie, NULL,
822 	    pcwl_intr, (caddr_t)pcwl_p)) {
823 		cmn_err(CE_NOTE, "pcwl(pccard): add softintr failed\n");
824 		goto insert_ret;
825 	}
826 	irq.Attributes = IRQ_TYPE_EXCLUSIVE;
827 	irq.irq_handler = ddi_intr_hilevel(DIP(pcwl_p), 0) ?
828 	    (csfunction_t *)pcwl_intr_hi : (csfunction_t *)pcwl_intr;
829 	irq.irq_handler_arg = pcwl_p;
830 	if (ret = csx_RequestIRQ(pcwl_p->pcwl_chdl, &irq)) {
831 		cmn_err(CE_WARN, "pcwl: RequestIRQ failed %x\n", ret);
832 		goto un_io;
833 	}
834 	bzero(&cfg, sizeof (cfg));
835 	cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
836 	cfg.Vcc = 50;
837 	cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
838 	cfg.ConfigBase = config.base;
839 	cfg.ConfigIndex = pcwl_p->pcwl_config;
840 	cfg.Status = CCSR_IO_IS_8;
841 	cfg.Present = config.present;
842 	pcwl_p->pcwl_flag |= PCWL_CARD_READY;
843 	if (ret = csx_RequestConfiguration(chdl, &cfg)) {
844 		cmn_err(CE_WARN, "pcwl: RequestConfiguration failed %x\n", ret);
845 		goto un_irq;
846 	}
847 
848 	if (pcwl_p->pcwl_flag & PCWL_CARD_SUSPEND) {
849 		mutex_enter(&pcwl_p->pcwl_glock);
850 		(void) pcwl_reset_backend(pcwl_p);
851 		/* turn on CS interrupt */
852 		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
853 		    CONF_IRQ_CHANGE_VALID;
854 		cfgmod.Vpp1 = 50;
855 		cfgmod.Vpp2 = 50;
856 		(void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
857 
858 		(void) pcwl_init_nicmem(pcwl_p);
859 		pcwl_chip_type(pcwl_p);
860 		(void) pcwl_loaddef_rf(pcwl_p);
861 		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
862 		pcwl_stop_locked(pcwl_p);	/* leaves interface down */
863 		pcwl_p->pcwl_flag &= ~PCWL_CARD_SUSPEND;
864 		mutex_exit(&pcwl_p->pcwl_glock);
865 	}
866 	if (pcwl_p->pcwl_flag & PCWL_CARD_PLUMBED) {
867 		(void) pcwl_start(pcwl_p);
868 		pcwl_p->pcwl_flag &= ~PCWL_CARD_PLUMBED;
869 	}
870 	return (CS_SUCCESS);
871 un_irq:
872 	(void) csx_ReleaseIRQ(chdl, &irq);
873 un_io:
874 	ddi_remove_softintr(pcwl_p->pcwl_softint_id);
875 	(void) csx_ReleaseIO(chdl, &io);
876 	pcwl_p->pcwl_port = 0;
877 insert_ret:
878 	pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
879 	return (ret);
880 
881 }
882 
883 /*
884  * assume card is already removed, don't touch the hardware
885  */
886 static void
pcwl_card_remove(pcwl_maci_t * pcwl_p)887 pcwl_card_remove(pcwl_maci_t *pcwl_p)
888 {
889 	int ret;
890 	io_req_t io;
891 	irq_req_t irq;
892 
893 	/*
894 	 * The card not ready means Insert function doesnot return TRUE.
895 	 * then the IO and IRQ has been released in Insert
896 	 */
897 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
898 		return;
899 
900 	if (pcwl_p->pcwl_connect_timeout_id != 0) {
901 		(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
902 		pcwl_p->pcwl_connect_timeout_id = 0;
903 	}
904 
905 	if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
906 		pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
907 		mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
908 	}
909 	mutex_enter(&pcwl_p->pcwl_glock);
910 	if (pcwl_p->pcwl_flag & PCWL_CARD_INTREN) {
911 		pcwl_stop_locked(pcwl_p);
912 		pcwl_p->pcwl_flag |= PCWL_CARD_PLUMBED;
913 	}
914 	pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
915 	mutex_exit(&pcwl_p->pcwl_glock);
916 	if (ret = csx_ReleaseConfiguration(pcwl_p->pcwl_chdl, NULL))
917 		cmn_err(CE_WARN, "pcwl: ReleaseConfiguration failed %x\n", ret);
918 
919 	bzero(&irq, sizeof (irq));
920 	if (ret = csx_ReleaseIRQ(pcwl_p->pcwl_chdl, &irq))
921 		cmn_err(CE_WARN, "pcwl: ReleaseIRQ failed %x\n", ret);
922 
923 	ddi_remove_softintr(pcwl_p->pcwl_softint_id);
924 
925 	bzero(&io, sizeof (io));
926 	io.BasePort1.handle = pcwl_p->pcwl_port;
927 	io.NumPorts1 = 16;
928 	if (ret = csx_ReleaseIO(pcwl_p->pcwl_chdl, &io))
929 		cmn_err(CE_WARN, "pcwl: ReleaseIO failed %x\n", ret);
930 
931 	pcwl_p->pcwl_port = 0;
932 }
933 
934 /*
935  * mac operation interface routines
936  */
937 static int
pcwl_start(void * arg)938 pcwl_start(void *arg)
939 {
940 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
941 
942 	mutex_enter(&pcwl_p->pcwl_glock);
943 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
944 		mutex_exit(&pcwl_p->pcwl_glock);
945 		return (PCWL_FAIL);
946 	}
947 	pcwl_start_locked(pcwl_p);
948 	mutex_exit(&pcwl_p->pcwl_glock);
949 	return (PCWL_SUCCESS);
950 }
951 
952 static void
pcwl_stop(void * arg)953 pcwl_stop(void *arg)
954 {
955 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
956 
957 	PCWLDBG((CE_NOTE, "pcwl_stop called\n"));
958 	mutex_enter(&pcwl_p->pcwl_glock);
959 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
960 		mutex_exit(&pcwl_p->pcwl_glock);
961 		return;
962 	}
963 
964 	pcwl_stop_locked(pcwl_p);
965 	mutex_exit(&pcwl_p->pcwl_glock);
966 	if (pcwl_p->pcwl_connect_timeout_id != 0) {
967 		(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
968 		pcwl_p->pcwl_connect_timeout_id = 0;
969 	}
970 }
971 
972 static int
pcwl_saddr(void * arg,const uint8_t * macaddr)973 pcwl_saddr(void *arg, const uint8_t *macaddr)
974 {
975 	int ret = PCWL_SUCCESS;
976 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
977 
978 	mutex_enter(&pcwl_p->pcwl_glock);
979 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
980 		ret = PCWL_FAIL;
981 		goto done;
982 	}
983 	ether_copy(macaddr, pcwl_p->pcwl_mac_addr);
984 	if (pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
985 		ret = PCWL_FAIL;
986 		goto done;
987 	}
988 	if (pcwl_saddr_locked(pcwl_p)) {
989 		ret = PCWL_FAIL;
990 		goto done;
991 	}
992 	if (pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
993 		ret = PCWL_FAIL;
994 	}
995 done:
996 	if (ret)
997 		cmn_err(CE_WARN, "pcwl set_mac_addr: failed\n");
998 	mutex_exit(&pcwl_p->pcwl_glock);
999 	return (ret);
1000 }
1001 
1002 static int
pcwl_send(pcwl_maci_t * pcwl_p,mblk_t * mblk_p)1003 pcwl_send(pcwl_maci_t *pcwl_p, mblk_t *mblk_p)
1004 {
1005 	int i = 0;
1006 	char *buf, *buf_p;
1007 	wl_frame_t *frm_p;
1008 	uint16_t pkt_len, ret;
1009 	uint16_t xmt_id, ring_idx;
1010 	struct ieee80211_frame *wh;
1011 	struct ieee80211_llc *llc;
1012 
1013 	mutex_enter(&pcwl_p->pcwl_glock);
1014 	if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_LINKUP)) !=
1015 	    (PCWL_CARD_READY | PCWL_CARD_LINKUP)) {
1016 		mutex_exit(&pcwl_p->pcwl_glock);
1017 		freemsg(mblk_p);
1018 		return (PCWL_SUCCESS);		/* drop packet */
1019 	}
1020 	mutex_exit(&pcwl_p->pcwl_glock);
1021 
1022 	if (pullupmsg(mblk_p, -1) == 0) {
1023 		freemsg(mblk_p);
1024 		return (PCWL_SUCCESS);		/* drop packet */
1025 	}
1026 	wh = (struct ieee80211_frame *)mblk_p->b_rptr;
1027 	llc = (struct ieee80211_llc *)&wh[1];
1028 
1029 	mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
1030 	ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
1031 	pcwl_p->pcwl_txring.wl_tx_prod = (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
1032 
1033 	/*
1034 	 * check whether there is a xmt buffer available
1035 	 */
1036 	while ((i < WL_XMT_BUF_NUM) &&
1037 	    (pcwl_p->pcwl_txring.wl_tx_ring[ring_idx])) {
1038 		ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
1039 		pcwl_p->pcwl_txring.wl_tx_prod =
1040 		    (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
1041 		i++;
1042 	}
1043 	if (i == WL_XMT_BUF_NUM) {
1044 		mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
1045 		mutex_enter(&pcwl_p->pcwl_glock);
1046 		pcwl_p->pcwl_reschedule_need = B_TRUE;
1047 		mutex_exit(&pcwl_p->pcwl_glock);
1048 		pcwl_p->pcwl_noxmtbuf++;
1049 		return (PCWL_FAIL);
1050 	}
1051 	xmt_id = pcwl_p->pcwl_txring.wl_tx_fids[ring_idx];
1052 	pcwl_p->pcwl_txring.wl_tx_ring[ring_idx] = xmt_id;
1053 	mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
1054 
1055 	buf = kmem_zalloc(PCWL_NICMEM_SZ, KM_SLEEP);
1056 	buf_p = (ulong_t)buf & 1 ? buf + 1 : buf;
1057 	frm_p = (wl_frame_t *)buf_p;
1058 #ifdef DEBUG
1059 	if (pcwl_debug & PCWL_DBG_SEND) {
1060 		cmn_err(CE_NOTE, "pcwl send: packet");
1061 		for (i = 0; i < MBLKL(mblk_p); i++)
1062 			cmn_err(CE_NOTE, "%x: %x\n", i,
1063 			    *((unsigned char *)mblk_p->b_rptr + i));
1064 	}
1065 #endif
1066 	pkt_len = msgdsize(mblk_p);
1067 	if (pkt_len > (PCWL_NICMEM_SZ - sizeof (wl_frame_t))) {
1068 		cmn_err(CE_WARN, "pcwl: send mblk is too long");
1069 		kmem_free(buf, PCWL_NICMEM_SZ);
1070 		freemsg(mblk_p);
1071 		return (PCWL_SUCCESS);		/* drop packet */
1072 	}
1073 	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1074 	    IEEE80211_FC1_DIR_TODS) {
1075 		kmem_free(buf, PCWL_NICMEM_SZ);
1076 		freemsg(mblk_p);
1077 		return (PCWL_SUCCESS);		/* drop packet */
1078 	}
1079 	bzero(frm_p, WL_802_11_HDRLEN);
1080 
1081 	frm_p->wl_tx_ctl = WL_TXCNTL_SET;
1082 	bcopy(wh->i_addr3, frm_p->wl_dst_addr, ETHERADDRL); /* dst macaddr */
1083 	bcopy(wh->i_addr2, frm_p->wl_src_addr, ETHERADDRL); /* src macaddr */
1084 	frm_p->wl_len = htons(pkt_len  - sizeof (*wh));
1085 	bcopy(llc, &frm_p->wl_dat[0], pkt_len - sizeof (*wh));
1086 	pkt_len = pkt_len - (sizeof (*wh) + sizeof (*llc)) +
1087 	    WL_802_11_HDRLEN;
1088 	PCWLDBG((CE_NOTE, "send: DIX frmsz=%x pkt_len=%x\n",
1089 	    WL_802_11_HDRLEN, pkt_len));
1090 
1091 	if (pkt_len & 1)	/* round up to 16-bit boundary and pad 0 */
1092 		buf_p[pkt_len++] = 0;
1093 
1094 	ASSERT(pkt_len <= PCWL_NICMEM_SZ);
1095 #ifdef DEBUG
1096 	if (pcwl_debug & PCWL_DBG_SEND) {
1097 		cmn_err(CE_NOTE, "pkt_len = %x\n", pkt_len);
1098 		for (i = 0; i < pkt_len; i++)
1099 			cmn_err(CE_NOTE, "%x: %x\n", i,
1100 			    *((unsigned char *)buf + i));
1101 	}
1102 #endif
1103 	mutex_enter(&pcwl_p->pcwl_glock);
1104 	ret = (WRCH1(pcwl_p, xmt_id, 0, (uint16_t *)buf_p, 0x2e) ||
1105 	    WRPKT(pcwl_p, xmt_id, 0x2e, (uint16_t *)(buf_p + 0x2e),
1106 	    pkt_len - 0x2e));
1107 	if (ret) {
1108 		goto done;
1109 	}
1110 	PCWLDBG((CE_NOTE, "send: xmt_id=%x send=%x\n", xmt_id, pkt_len));
1111 	(void) pcwl_set_cmd(pcwl_p, WL_CMD_TX | WL_RECLAIM, xmt_id);
1112 
1113 done:
1114 	mutex_exit(&pcwl_p->pcwl_glock);
1115 	kmem_free(buf, PCWL_NICMEM_SZ);
1116 	freemsg(mblk_p);
1117 	return (PCWL_SUCCESS);
1118 }
1119 
1120 static mblk_t *
pcwl_tx(void * arg,mblk_t * mp)1121 pcwl_tx(void *arg, mblk_t *mp)
1122 {
1123 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1124 	mblk_t *next;
1125 
1126 	ASSERT(mp != NULL);
1127 	mutex_enter(&pcwl_p->pcwl_glock);
1128 	if ((pcwl_p->pcwl_flag & (PCWL_CARD_LINKUP | PCWL_CARD_READY)) !=
1129 	    (PCWL_CARD_LINKUP | PCWL_CARD_READY)) {
1130 		mutex_exit(&pcwl_p->pcwl_glock);
1131 		freemsgchain(mp);
1132 		return (NULL);
1133 	}
1134 	mutex_exit(&pcwl_p->pcwl_glock);
1135 	while (mp != NULL) {
1136 		next =  mp->b_next;
1137 		mp->b_next = NULL;
1138 
1139 		if (pcwl_send(pcwl_p, mp)) {
1140 			mp->b_next = next;
1141 			break;
1142 		}
1143 		mp = next;
1144 	}
1145 	return (mp);
1146 }
1147 
1148 static int
pcwl_prom(void * arg,boolean_t on)1149 pcwl_prom(void *arg, boolean_t on)
1150 {
1151 	int ret = PCWL_SUCCESS;
1152 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1153 
1154 	mutex_enter(&pcwl_p->pcwl_glock);
1155 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
1156 		ret = PCWL_FAIL;
1157 		goto done;
1158 	}
1159 
1160 	PCWLDBG((CE_NOTE, "pcwl_prom called %x\n", on));
1161 
1162 	if (on)
1163 		pcwl_p->pcwl_rf.rf_promiscuous = 1;
1164 	else
1165 		pcwl_p->pcwl_rf.rf_promiscuous = 0;
1166 	if (ret = pcwl_fil_ltv(pcwl_p, 2, WL_RID_PROMISC,
1167 	    pcwl_p->pcwl_rf.rf_promiscuous)) {
1168 		ret = PCWL_FAIL;
1169 	}
1170 done:
1171 	if (ret)
1172 		cmn_err(CE_WARN, "pcwl promisc: failed\n");
1173 	mutex_exit(&pcwl_p->pcwl_glock);
1174 	return (ret);
1175 }
1176 
1177 static int
pcwl_gstat(void * arg,uint_t statitem,uint64_t * val)1178 pcwl_gstat(void *arg, uint_t statitem, uint64_t *val)
1179 {
1180 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1181 	int ret = PCWL_SUCCESS;
1182 	uint64_t *cntr_p = pcwl_p->pcwl_cntrs_s;
1183 	uint16_t rate = 0;
1184 	uint64_t speed;
1185 
1186 	PCWLDBG((CE_NOTE, "pcwl_gstat called\n"));
1187 	mutex_enter(&pcwl_p->pcwl_glock);
1188 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
1189 		ret = PCWL_FAIL;
1190 		goto done;
1191 	}
1192 
1193 	if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CUR_TX_RATE, &rate)) {
1194 		cmn_err(CE_WARN, "pcwl kstat: get speed failed\n");
1195 		ret = PCWL_FAIL;
1196 		goto done;
1197 	}
1198 	switch (pcwl_p->pcwl_chip_type) {
1199 	case PCWL_CHIP_PRISMII:
1200 		switch (rate) {
1201 		case WL_SPEED_1Mbps_P2:		rate = 2;	break;
1202 		case WL_SPEED_2Mbps_P2:		rate = 4;	break;
1203 		case WL_SPEED_55Mbps_P2:	rate = 11;	break;
1204 		case WL_SPEED_11Mbps_P2:	rate = 22;	break;
1205 		default:			rate = 0;	break;
1206 		}
1207 		speed = rate * 500000;
1208 		break;
1209 	case PCWL_CHIP_LUCENT:
1210 	default:
1211 		speed = rate * 1000000;
1212 		if (rate == 6)
1213 			speed = 5500000;
1214 		break;
1215 	}
1216 
1217 	switch (statitem) {
1218 	case MAC_STAT_IFSPEED:
1219 		*val = speed;
1220 		break;
1221 	case MAC_STAT_NOXMTBUF:
1222 		*val = pcwl_p->pcwl_noxmtbuf;
1223 		break;
1224 	case MAC_STAT_NORCVBUF:
1225 		*val = cntr_p[WLC_RX_DISCARDS_NOBUF];
1226 		break;
1227 	case MAC_STAT_IERRORS:
1228 		*val = 0;
1229 		break;
1230 	case MAC_STAT_OERRORS:
1231 		*val = cntr_p[WLC_TX_DISCARDS] +
1232 		    cntr_p[WLC_TX_DISCARDS_WRONG_SA];
1233 		break;
1234 	case MAC_STAT_RBYTES:
1235 		*val = cntr_p[WLC_RX_UNICAST_OCTETS];
1236 		break;
1237 	case MAC_STAT_IPACKETS:
1238 		*val = cntr_p[WLC_RX_UNICAST_FRAMES];
1239 		break;
1240 	case MAC_STAT_OBYTES:
1241 		*val = cntr_p[WLC_TX_UNICAST_OCTETS];
1242 		break;
1243 	case MAC_STAT_OPACKETS:
1244 		*val = cntr_p[WLC_TX_UNICAST_FRAMES];
1245 		break;
1246 	case WIFI_STAT_TX_FAILED:
1247 		*val = cntr_p[WLC_TX_RETRY_LIMIT] +
1248 		    cntr_p[WLC_TX_DEFERRED_XMITS];
1249 		break;
1250 	case WIFI_STAT_TX_RETRANS:
1251 		*val = cntr_p[WLC_TX_SINGLE_RETRIES] +
1252 		    cntr_p[WLC_TX_MULTI_RETRIES];
1253 		break;
1254 	case WIFI_STAT_FCS_ERRORS:
1255 		*val = cntr_p[WLC_RX_FCS_ERRORS];
1256 		break;
1257 	case WIFI_STAT_WEP_ERRORS:
1258 		*val = cntr_p[WLC_RX_WEP_CANT_DECRYPT];
1259 		break;
1260 	case WIFI_STAT_MCAST_TX:
1261 		*val = cntr_p[WLC_TX_MULTICAST_FRAMES];
1262 		break;
1263 	case WIFI_STAT_MCAST_RX:
1264 		*val = cntr_p[WLC_RX_MULTICAST_FRAMES];
1265 		break;
1266 	case WIFI_STAT_TX_FRAGS:
1267 		*val = cntr_p[WLC_TX_FRAGMENTS];
1268 		break;
1269 	case WIFI_STAT_RX_FRAGS:
1270 		*val =	cntr_p[WLC_RX_FRAGMENTS] +
1271 		    cntr_p[WLC_RX_MSG_IN_MSG_FRAGS] +
1272 		    cntr_p[WLC_RX_MSG_IN_BAD_MSG_FRAGS];
1273 		break;
1274 	case WIFI_STAT_RTS_SUCCESS:
1275 	case WIFI_STAT_RTS_FAILURE:
1276 	case WIFI_STAT_ACK_FAILURE:
1277 	case WIFI_STAT_RX_DUPS:
1278 		*val = 0;
1279 		break;
1280 	default:
1281 		ret = ENOTSUP;
1282 	}
1283 done:
1284 	mutex_exit(&pcwl_p->pcwl_glock);
1285 	return (ret);
1286 }
1287 
1288 static int
pcwl_sdmulti(void * arg,boolean_t add,const uint8_t * eth_p)1289 pcwl_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
1290 {
1291 	int ret = PCWL_SUCCESS;
1292 	uint16_t i;
1293 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1294 	uint16_t *mc_p = pcwl_p->pcwl_mcast;
1295 
1296 	mutex_enter(&pcwl_p->pcwl_glock);
1297 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
1298 		ret = PCWL_FAIL;
1299 		goto done;
1300 	}
1301 
1302 	if (add) { /* enable multicast on eth_p, search for available entries */
1303 		for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
1304 			if (!ether_cmp(eth_p, mc_p))
1305 				break;
1306 		}
1307 		if (i < 16)	/* already part of the filter */
1308 			goto done;
1309 		mc_p = pcwl_p->pcwl_mcast;	/* reset mc_p for 2nd scan */
1310 		for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
1311 			PCWLDBG((CE_NOTE, "smulti: mc[%x]=%s\n", i,
1312 			    ether_sprintf((struct ether_addr *)mc_p)));
1313 			if (mc_p[0] == 0 && mc_p[1] == 0 && mc_p[2] == 0)
1314 				break;
1315 		}
1316 		if (i >= 16)	/* can't find a vacant entry */
1317 			goto done;
1318 		ether_copy(eth_p, mc_p);
1319 	} else { /* disable multicast, locate the entry and clear it */
1320 		for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
1321 			if (!ether_cmp(eth_p, mc_p))
1322 				break;
1323 		}
1324 		if (i >= 16)
1325 			goto done;
1326 		mc_p[0] = 0;
1327 		mc_p[1] = 0;
1328 		mc_p[2] = 0;
1329 	}
1330 	/*
1331 	 * re-blow the entire 16 entries buffer
1332 	 */
1333 	if (i = pcwl_put_ltv(pcwl_p, ETHERADDRL << 4, WL_RID_MCAST,
1334 	    pcwl_p->pcwl_mcast)) {
1335 		ret = PCWL_FAIL;
1336 	}
1337 done:
1338 	if (ret)
1339 		cmn_err(CE_WARN, "pcwl set multi addr: failed\n");
1340 	mutex_exit(&pcwl_p->pcwl_glock);
1341 	return (ret);
1342 }
1343 
1344 static uint_t
pcwl_intr(caddr_t arg)1345 pcwl_intr(caddr_t arg)
1346 {
1347 	uint16_t stat;
1348 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1349 
1350 	mutex_enter(&pcwl_p->pcwl_glock);
1351 	if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
1352 	    (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
1353 		mutex_exit(&pcwl_p->pcwl_glock);
1354 		return (DDI_INTR_UNCLAIMED);
1355 	}
1356 	PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1357 	if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
1358 		mutex_exit(&pcwl_p->pcwl_glock);
1359 		return (DDI_INTR_UNCLAIMED);
1360 	}
1361 
1362 	PCWL_WRITE(pcwl_p, WL_INT_EN, 0);
1363 	if (stat & WL_EV_RX) {
1364 		pcwl_rcv(pcwl_p);
1365 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
1366 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
1367 	}
1368 	if (stat & WL_EV_TX) {
1369 		if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
1370 			if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
1371 				mutex_exit(&pcwl_p->pcwl_glock);
1372 				mac_tx_update(GLD3(pcwl_p));
1373 				mutex_enter(&pcwl_p->pcwl_glock);
1374 				pcwl_p->pcwl_reschedule_need = B_FALSE;
1375 			}
1376 		}
1377 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
1378 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
1379 	}
1380 	if (stat & WL_EV_ALLOC) {
1381 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC | 0x1000);
1382 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, 0x1000);
1383 	}
1384 	if (stat & WL_EV_INFO) {
1385 		pcwl_infodone(pcwl_p);
1386 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
1387 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
1388 	}
1389 	if (stat & WL_EV_TX_EXC) {
1390 		if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
1391 			if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
1392 				mutex_exit(&pcwl_p->pcwl_glock);
1393 				mac_tx_update(GLD3(pcwl_p));
1394 				mutex_enter(&pcwl_p->pcwl_glock);
1395 				pcwl_p->pcwl_reschedule_need = B_FALSE;
1396 			}
1397 		}
1398 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
1399 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
1400 	}
1401 	if (stat & WL_EV_INFO_DROP) {
1402 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
1403 		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
1404 	}
1405 	PCWL_ENABLE_INTR(pcwl_p);
1406 	mutex_exit(&pcwl_p->pcwl_glock);
1407 
1408 	return (DDI_INTR_CLAIMED);
1409 }
1410 
1411 static uint_t
pcwl_intr_hi(caddr_t arg)1412 pcwl_intr_hi(caddr_t arg)
1413 {
1414 	uint16_t stat;
1415 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1416 
1417 	mutex_enter(&pcwl_p->pcwl_glock);
1418 	if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
1419 	    (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
1420 		mutex_exit(&pcwl_p->pcwl_glock);
1421 		return (DDI_INTR_UNCLAIMED);
1422 	}
1423 	PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1424 	if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
1425 		mutex_exit(&pcwl_p->pcwl_glock);
1426 		return (DDI_INTR_UNCLAIMED);
1427 	}
1428 	PCWL_WRITE(pcwl_p, WL_INT_EN, 0); /* disable interrupt without ack */
1429 	mutex_exit(&pcwl_p->pcwl_glock);
1430 	ddi_trigger_softintr(pcwl_p->pcwl_softint_id);
1431 	return (DDI_INTR_CLAIMED);
1432 }
1433 
1434 /*
1435  * called at interrupt context to retrieve data from card
1436  */
1437 static void
pcwl_rcv(pcwl_maci_t * pcwl_p)1438 pcwl_rcv(pcwl_maci_t *pcwl_p)
1439 {
1440 	uint16_t id, len, off, ret, frm_ctl;
1441 	wl_frame_t frm;
1442 	mblk_t *mp = allocb(PCWL_NICMEM_SZ, BPRI_MED);
1443 	if (!mp)
1444 		return;
1445 	ASSERT(mp->b_rptr == mp->b_wptr);
1446 
1447 	PCWL_READ(pcwl_p, WL_RX_FID, id);
1448 	PCWL_WRITE(pcwl_p, WL_RX_FID, 0);
1449 	if (id == WL_INVALID_FID) {
1450 		PCWLDBG((CE_NOTE, "pcwl rcv: get rx_fid failed\n"));
1451 		ret = PCWL_FAIL;
1452 		goto done;
1453 	}
1454 	if (ret = RDCH0(pcwl_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
1455 		PCWLDBG((CE_NOTE, "pcwl rcv: read frm failed %x\n", ret));
1456 		goto done;
1457 	}
1458 	if (frm.wl_status & WL_STAT_ERRSTAT) {
1459 		PCWLDBG((CE_NOTE, "pcwl rcv: errstat %x\n", frm.wl_status));
1460 		ret = frm.wl_status;
1461 		goto done;
1462 	}
1463 	PCWLDBG((CE_NOTE, "pcwl rcv: frame type %x\n", frm.wl_status));
1464 #ifdef DEBUG
1465 	if (pcwl_debug & PCWL_DBG_RCV) {
1466 		int i;
1467 		cmn_err(CE_NOTE, "pcwl rcv: frm header\n");
1468 		for (i = 0; i < WL_802_11_HDRLEN; i++)
1469 			cmn_err(CE_NOTE, "%x: %x\n", i,
1470 			    *((uint8_t *)&frm + i));
1471 	}
1472 #endif
1473 	len = frm.wl_dat_len;
1474 	/*
1475 	 * this driver deal with WEP by itself. so plugin always thinks no wep.
1476 	 */
1477 	frm.wl_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
1478 	frm_ctl = frm.wl_frame_ctl;
1479 	switch (frm.wl_status) {
1480 	case WL_STAT_1042:
1481 	case WL_STAT_TUNNEL:
1482 	case WL_STAT_WMP_MSG:
1483 		PCWL_SWAP16((uint16_t *)&frm.wl_frame_ctl,
1484 		    sizeof (struct ieee80211_frame));
1485 		/*
1486 		 * discard those frames which are not from the AP we connect or
1487 		 * without 'ap->sta' direction
1488 		 */
1489 		if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_BSS) &&
1490 		    ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
1491 		    IEEE80211_FC1_DIR_FROMDS) ||
1492 		    bcmp(pcwl_p->pcwl_bssid, frm.wl_addr2, 6) != 0)) {
1493 			ret = PCWL_FAIL;
1494 			goto done;
1495 		}
1496 
1497 		bcopy(&frm.wl_frame_ctl, mp->b_wptr,
1498 		    sizeof (struct ieee80211_frame));
1499 		mp->b_wptr += sizeof (struct ieee80211_frame);
1500 
1501 		PCWL_SWAP16((uint16_t *)&frm.wl_dat[0],
1502 		    sizeof (struct ieee80211_llc));
1503 		bcopy(&frm.wl_dat[0], mp->b_wptr,
1504 		    sizeof (struct ieee80211_llc));
1505 		mp->b_wptr += sizeof (struct ieee80211_llc);
1506 
1507 		len -= (2 + WL_SNAPHDR_LEN);
1508 		off = WL_802_11_HDRLEN;
1509 		break;
1510 	default:
1511 		PCWLDBG((CE_NOTE, "pcwl rcv: incorrect pkt\n"));
1512 		break;
1513 	}
1514 	if (len > MBLKSIZE(mp)) {
1515 		PCWLDBG((CE_NOTE, "pcwl rcv: oversz pkt %x\n", len));
1516 		ret = PCWL_FAIL;
1517 		goto done;
1518 	}
1519 	if (len & 1)
1520 		len++;
1521 	ret = RDPKT(pcwl_p, id, off, (uint16_t *)mp->b_wptr, len);
1522 done:
1523 	if (ret) {
1524 		PCWLDBG((CE_NOTE, "pcwl rcv: rd data %x\n", ret));
1525 		freemsg(mp);
1526 		return;
1527 	}
1528 	mp->b_wptr = mp->b_wptr + len;
1529 #ifdef DEBUG
1530 	if (pcwl_debug & PCWL_DBG_RCV) {
1531 		int i;
1532 		cmn_err(CE_NOTE, "pcwl rcv: len=0x%x\n", len);
1533 		for (i = 0; i < len+14; i++)
1534 			cmn_err(CE_NOTE, "%x: %x\n", i,
1535 			    *((uint8_t *)mp->b_rptr + i));
1536 	}
1537 #endif
1538 	mutex_exit(&pcwl_p->pcwl_glock);
1539 	mac_rx(GLD3(pcwl_p), NULL, mp);
1540 	mutex_enter(&pcwl_p->pcwl_glock);
1541 }
1542 
1543 static uint32_t
pcwl_txdone(pcwl_maci_t * pcwl_p)1544 pcwl_txdone(pcwl_maci_t *pcwl_p)
1545 {
1546 	uint16_t fid, i;
1547 	PCWL_READ(pcwl_p, WL_ALLOC_FID, fid);
1548 	PCWL_WRITE(pcwl_p, WL_ALLOC_FID, 0);
1549 
1550 	mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
1551 	for (i = 0; i < WL_XMT_BUF_NUM; i++) {
1552 		if (fid == pcwl_p->pcwl_txring.wl_tx_ring[i]) {
1553 			pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
1554 			break;
1555 		}
1556 	}
1557 	pcwl_p->pcwl_txring.wl_tx_cons =
1558 	    (pcwl_p->pcwl_txring.wl_tx_cons + 1) & (WL_XMT_BUF_NUM - 1);
1559 	mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
1560 	if (i == WL_XMT_BUF_NUM)
1561 		return (PCWL_FAIL);
1562 	return (PCWL_SUCCESS);
1563 
1564 }
1565 
1566 static void
pcwl_infodone(pcwl_maci_t * pcwl_p)1567 pcwl_infodone(pcwl_maci_t *pcwl_p)
1568 {
1569 	uint16_t id, ret, i;
1570 	uint16_t linkStatus[2];
1571 	uint16_t linkStat;
1572 	wifi_data_t wd = { 0 };
1573 
1574 	PCWL_READ(pcwl_p, WL_INFO_FID, id);
1575 	if (id == WL_INVALID_FID) {
1576 		cmn_err(CE_WARN, "pcwl infodone: read info_fid failed\n");
1577 		return;
1578 	}
1579 	if (ret = RDCH0(pcwl_p, id, 0, linkStatus, sizeof (linkStatus))) {
1580 		PCWLDBG((CE_WARN, "pcwl infodone read infoFrm failed %x\n",
1581 		    ret));
1582 		return;
1583 	}
1584 	PCWLDBG((CE_NOTE, "pcwl infodone: Frame length= %x, Frame Type = %x\n",
1585 	    linkStatus[0], linkStatus[1]));
1586 
1587 	switch (linkStatus[1]) {
1588 	case WL_INFO_LINK_STAT:
1589 		(void) RDCH0(pcwl_p, id, sizeof (linkStatus), &linkStat,
1590 		    sizeof (linkStat));
1591 		PCWLDBG((CE_NOTE, "pcwl infodone: link status=%x\n", linkStat));
1592 		if (!(pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
1593 		    linkStat == WL_LINK_CONNECT) {
1594 #ifdef DEBUG
1595 		if (pcwl_debug & PCWL_DBG_LINKINFO)
1596 			cmn_err(CE_NOTE, "pcwl: Link up \n");
1597 #endif
1598 			pcwl_p->pcwl_flag |= PCWL_CARD_LINKUP;
1599 			mutex_exit(&pcwl_p->pcwl_glock);
1600 			if (pcwl_p->pcwl_connect_timeout_id != 0) {
1601 				(void) untimeout(pcwl_p->
1602 				    pcwl_connect_timeout_id);
1603 				pcwl_p->pcwl_connect_timeout_id = 0;
1604 			}
1605 			mutex_enter(&pcwl_p->pcwl_glock);
1606 			mac_link_update(GLD3(pcwl_p), LINK_STATE_UP);
1607 			(void) pcwl_get_ltv(pcwl_p, 6,
1608 			    WL_RID_BSSID, (uint16_t *)pcwl_p->pcwl_bssid);
1609 			PCWL_SWAP16((uint16_t *)pcwl_p->pcwl_bssid, 6);
1610 			pcwl_get_rssi(pcwl_p);
1611 			bcopy(pcwl_p->pcwl_bssid, wd.wd_bssid, 6);
1612 			wd.wd_secalloc = WIFI_SEC_NONE;
1613 			wd.wd_opmode = IEEE80211_M_STA;
1614 			(void) mac_pdata_update(pcwl_p->pcwl_mh, &wd,
1615 			    sizeof (wd));
1616 		}
1617 		if ((pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
1618 		    ((linkStat == WL_LINK_DISCONNECT) ||
1619 		    (linkStat == WL_LINK_AP_OOR))) {
1620 #ifdef DEBUG
1621 		if (pcwl_debug & PCWL_DBG_LINKINFO)
1622 			cmn_err(CE_NOTE, "pcwl: Link down \n");
1623 #endif
1624 			PCWLDBG((CE_NOTE, "pcwl infodone: link status = %d\n",
1625 			    linkStat));
1626 			pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
1627 			if (linkStat == WL_LINK_AP_OOR)
1628 				pcwl_p->pcwl_connect_timeout_id =
1629 				    timeout(pcwl_connect_timeout,
1630 				    pcwl_p, drv_usectohz(1000));
1631 			mutex_exit(&pcwl_p->pcwl_glock);
1632 			mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
1633 			mutex_enter(&pcwl_p->pcwl_glock);
1634 		}
1635 		break;
1636 	case WL_INFO_SCAN_RESULTS:
1637 	case WL_INFO_HSCAN_RESULTS:
1638 		pcwl_ssid_scan(pcwl_p, id, linkStatus[0], linkStatus[1]);
1639 			break;
1640 	case WL_INFO_COUNTERS:
1641 		linkStatus[0]--;
1642 		if (linkStatus[0] > WLC_STAT_CNT) {
1643 			linkStatus[0] = MIN(linkStatus[0], WLC_STAT_CNT);
1644 		}
1645 		(void) RDCH0(pcwl_p, id, sizeof (linkStatus),
1646 		    pcwl_p->pcwl_cntrs_t, linkStatus[0]<<1);
1647 		/*
1648 		 * accumulate all the statistics items for kstat use.
1649 		 */
1650 		for (i = 0; i < WLC_STAT_CNT; i++)
1651 			pcwl_p->pcwl_cntrs_s[i] += pcwl_p->pcwl_cntrs_t[i];
1652 		break;
1653 	default:
1654 		break;
1655 	}
1656 }
1657 
1658 static uint16_t
pcwl_set_cmd(pcwl_maci_t * pcwl_p,uint16_t cmd,uint16_t param)1659 pcwl_set_cmd(pcwl_maci_t *pcwl_p, uint16_t cmd, uint16_t param)
1660 {
1661 	int i;
1662 	uint16_t stat;
1663 
1664 	if (((cmd == WL_CMD_ENABLE) &&
1665 	    ((pcwl_p->pcwl_flag & PCWL_ENABLED) != 0)) ||
1666 	    ((cmd == WL_CMD_DISABLE) &&
1667 	    ((pcwl_p->pcwl_flag & PCWL_ENABLED) == 0)))
1668 		return (PCWL_SUCCESS);
1669 
1670 	for (i = 0; i < WL_TIMEOUT; i++) {
1671 		PCWL_READ(pcwl_p, WL_COMMAND, stat);
1672 		if (stat & WL_CMD_BUSY) {
1673 			drv_usecwait(1);
1674 		} else {
1675 			break;
1676 		}
1677 	}
1678 	if (i == WL_TIMEOUT) {
1679 		cmn_err(CE_WARN, "pcwl: setcmd %x, %x timeout %x due to "
1680 		    "busy bit\n", cmd, param, stat);
1681 		return (PCWL_TIMEDOUT_CMD);
1682 	}
1683 
1684 	PCWL_WRITE(pcwl_p, WL_PARAM0, param);
1685 	PCWL_WRITE(pcwl_p, WL_PARAM1, 0);
1686 	PCWL_WRITE(pcwl_p, WL_PARAM2, 0);
1687 	PCWL_WRITE(pcwl_p, WL_COMMAND, cmd);
1688 	if (cmd == WL_CMD_INI)
1689 		drv_usecwait(100000); /* wait .1 sec */
1690 
1691 	for (i = 0; i < WL_TIMEOUT; i++) {
1692 		PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1693 		if (!(stat & WL_EV_CMD)) {
1694 			drv_usecwait(1);
1695 		} else {
1696 			break;
1697 		}
1698 	}
1699 	if (i == WL_TIMEOUT) {
1700 		cmn_err(CE_WARN, "pcwl: setcmd %x,%x timeout %x\n",
1701 		    cmd, param, stat);
1702 		if (stat & (WL_EV_ALLOC | WL_EV_RX))
1703 			PCWL_WRITE(pcwl_p, WL_EVENT_ACK, stat);
1704 		return (PCWL_TIMEDOUT_CMD);
1705 	}
1706 	PCWL_READ(pcwl_p, WL_STATUS, stat);
1707 	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_CMD);
1708 	if (stat & WL_STAT_CMD_RESULT) { /* err in feedback status */
1709 		cmn_err(CE_WARN, "pcwl: set_cmd %x,%x failed %x\n",
1710 		    cmd, param, stat);
1711 		return (PCWL_FAILURE_CMD);
1712 	}
1713 	if (cmd == WL_CMD_ENABLE)
1714 		pcwl_p->pcwl_flag |= PCWL_ENABLED;
1715 	if (cmd == WL_CMD_DISABLE)
1716 		pcwl_p->pcwl_flag &= (~PCWL_ENABLED);
1717 	return (PCWL_SUCCESS);
1718 }
1719 
1720 static uint16_t
pcwl_set_ch(pcwl_maci_t * pcwl_p,uint16_t type,uint16_t off,uint16_t channel)1721 pcwl_set_ch(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t channel)
1722 {
1723 	int i;
1724 	uint16_t stat, select, offset;
1725 
1726 	if (channel) {
1727 		select = WL_SEL1;
1728 		offset = WL_OFF1;
1729 	} else {
1730 		select = WL_SEL0;
1731 		offset = WL_OFF0;
1732 	}
1733 	PCWL_WRITE(pcwl_p, select, type);
1734 	PCWL_WRITE(pcwl_p, offset, off);
1735 	for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
1736 		PCWL_READ(pcwl_p, offset, stat);
1737 		if (!(stat & (WL_OFF_BUSY|WL_OFF_ERR)))
1738 			break;
1739 		else {
1740 			drv_usecwait(1);
1741 		}
1742 	}
1743 	if (i == WL_TIMEOUT) {
1744 		cmn_err(CE_WARN, "set_ch%d %x,%x failed %x\n",
1745 		    channel, type, off, stat);
1746 		return (PCWL_TIMEDOUT_TARGET);
1747 	}
1748 	return (PCWL_SUCCESS);
1749 }
1750 
1751 static uint16_t
pcwl_get_ltv(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t type,uint16_t * val_p)1752 pcwl_get_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
1753 {
1754 	uint16_t stat;
1755 
1756 	ASSERT(!(len & 1));
1757 	len >>= 1;	/* convert bytes to 16-bit words */
1758 
1759 	/*
1760 	 * 1. select read mode
1761 	 */
1762 	if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS | WL_ACCESS_READ, type))
1763 		return (stat);
1764 
1765 	/*
1766 	 * 2. select Buffer Access Path (channel) 1 for PIO
1767 	 */
1768 	if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
1769 		return (stat);
1770 
1771 	/*
1772 	 * 3. read length
1773 	 */
1774 	PCWL_READ(pcwl_p, WL_DATA1, stat);
1775 	if (stat != (len + 1)) {
1776 		PCWLDBG((CE_NOTE, "get_ltv 0x%x expected 0x%x+1, got 0x%x\n",
1777 		    type, (len + 1) << 1, stat));
1778 		stat = (stat >> 1) - 1;
1779 		len = MIN(stat, len);
1780 	}
1781 
1782 	/*
1783 	 * 4. read type
1784 	 */
1785 	PCWL_READ(pcwl_p, WL_DATA1, stat);
1786 	if (stat != type)
1787 		return (PCWL_BADTYPE);
1788 
1789 	/*
1790 	 * 5. read value
1791 	 */
1792 	for (stat = 0; stat < len; stat++, val_p++) {
1793 		PCWL_READ_P(pcwl_p, WL_DATA1, val_p, 1);
1794 	}
1795 	return (PCWL_SUCCESS);
1796 }
1797 
1798 static uint16_t
pcwl_fil_ltv(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t type,uint16_t val)1799 pcwl_fil_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t val)
1800 {
1801 	uint16_t stat;
1802 
1803 	ASSERT(!(len & 1));
1804 
1805 	/*
1806 	 * 1. select Buffer Access Path (channel) 1 for PIO
1807 	 */
1808 	if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
1809 		return (stat);
1810 
1811 	/*
1812 	 * 2. write length
1813 	 */
1814 	len >>= 1;		/* convert bytes to 16-bit words */
1815 	stat = len + 1;		/* 1 extra word */
1816 	PCWL_WRITE(pcwl_p, WL_DATA1, stat);
1817 
1818 	/*
1819 	 * 3. write type
1820 	 */
1821 	PCWL_WRITE(pcwl_p, WL_DATA1, type);
1822 
1823 	/*
1824 	 * 4. fill value
1825 	 */
1826 	for (stat = 0; stat < len; stat++) {
1827 		PCWL_WRITE(pcwl_p, WL_DATA1, val);
1828 	}
1829 
1830 	/*
1831 	 * 5. select write mode
1832 	 */
1833 	return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
1834 }
1835 
1836 static uint16_t
pcwl_put_ltv(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t type,uint16_t * val_p)1837 pcwl_put_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
1838 {
1839 	uint16_t stat;
1840 
1841 	ASSERT(!(len & 1));
1842 
1843 	/*
1844 	 * 1. select Buffer Access Path (channel) 1 for PIO
1845 	 */
1846 	if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
1847 		return (stat);
1848 
1849 	/*
1850 	 * 2. write length
1851 	 */
1852 	len >>= 1;		/* convert bytes to 16-bit words */
1853 	stat = len + 1;		/* 1 extra word */
1854 	PCWL_WRITE(pcwl_p, WL_DATA1, stat);
1855 
1856 	/*
1857 	 * 3. write type
1858 	 */
1859 	PCWL_WRITE(pcwl_p, WL_DATA1, type);
1860 
1861 	/*
1862 	 * 4. write value
1863 	 */
1864 	for (stat = 0; stat < len; stat++, val_p++) {
1865 		PCWL_WRITE_P(pcwl_p, WL_DATA1, val_p, 1);
1866 	}
1867 
1868 	/*
1869 	 * 5. select write mode
1870 	 */
1871 	return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
1872 }
1873 
1874 #define	PCWL_COMPSTR_LEN	34
1875 static uint16_t
pcwl_put_str(pcwl_maci_t * pcwl_p,uint16_t type,char * str_p)1876 pcwl_put_str(pcwl_maci_t *pcwl_p, uint16_t type, char *str_p)
1877 {
1878 	uint16_t buf[PCWL_COMPSTR_LEN / 2];
1879 	uint8_t str_len = strlen(str_p);
1880 
1881 	bzero(buf, PCWL_COMPSTR_LEN);
1882 	buf[0] = str_len;
1883 	bcopy(str_p, (caddr_t)(buf + 1), str_len);
1884 	PCWLDBG((CE_NOTE, "put_str: buf[0]=%x buf=%s\n",
1885 	    buf[0], (caddr_t)(buf + 1)));
1886 	PCWL_SWAP16(buf + 1, PCWL_COMPSTR_LEN - 2);
1887 	return (pcwl_put_ltv(pcwl_p, PCWL_COMPSTR_LEN, type, buf));
1888 }
1889 
1890 /*ARGSUSED*/
1891 static uint16_t
pcwl_rdch0(pcwl_maci_t * pcwl_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)1892 pcwl_rdch0(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
1893 	int len, int order)
1894 {
1895 	uint16_t o;
1896 	ASSERT(!(len & 1));
1897 	/*
1898 	 * It seems that for PrismII chip, frequently overlap use of path0
1899 	 * and path1 may hang the hardware. So for PrismII chip, just use
1900 	 * path1. Test proves this workaround is OK.
1901 	 */
1902 	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
1903 		if (type = pcwl_set_ch(pcwl_p, type, off, 1))
1904 			return (type);
1905 		o = WL_DATA1;
1906 	} else {
1907 		if (type = pcwl_set_ch(pcwl_p, type, off, 0))
1908 			return (type);
1909 		o = WL_DATA0;
1910 	}
1911 	len >>= 1;
1912 	for (off = 0; off < len; off++, buf_p++) {
1913 		PCWL_READ_P(pcwl_p, o, buf_p, order);
1914 	}
1915 	return (PCWL_SUCCESS);
1916 }
1917 
1918 /*ARGSUSED*/
1919 static uint16_t
pcwl_wrch1(pcwl_maci_t * pcwl_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)1920 pcwl_wrch1(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
1921 	int len, int order)
1922 {
1923 	ASSERT(!(len & 1));
1924 	if (type = pcwl_set_ch(pcwl_p, type, off, 1))
1925 		return (type);
1926 	len >>= 1;
1927 	for (off = 0; off < len; off++, buf_p++) {
1928 		PCWL_WRITE_P(pcwl_p, WL_DATA1, buf_p, order);
1929 	}
1930 	return (PCWL_SUCCESS);
1931 }
1932 
1933 static uint16_t
pcwl_alloc_nicmem(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t * id_p)1934 pcwl_alloc_nicmem(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t *id_p)
1935 {
1936 	int i;
1937 	uint16_t stat;
1938 
1939 	len = ((len + 1) >> 1) << 1;	/* round up to 16-bit boundary */
1940 
1941 	if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ALLOC_MEM, len))
1942 		return (stat);
1943 	for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
1944 		PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
1945 		if (stat & WL_EV_ALLOC)
1946 			break;
1947 		else
1948 			drv_usecwait(1);
1949 	}
1950 	if (i == WL_TIMEOUT)
1951 		return (PCWL_TIMEDOUT_ALLOC);
1952 	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC);
1953 	PCWL_READ(pcwl_p, WL_ALLOC_FID, stat);
1954 	*id_p = stat;
1955 
1956 	/*
1957 	 * zero fill the allocated NIC mem - sort of pcwl_fill_ch
1958 	 */
1959 	(void) pcwl_set_ch(pcwl_p, stat, 0, 1);
1960 
1961 	for (len >>= 1, stat = 0; stat < len; stat++) {
1962 		PCWL_WRITE(pcwl_p, WL_DATA1, 0);
1963 	}
1964 	return (PCWL_SUCCESS);
1965 }
1966 
1967 static int
pcwl_add_scan_item(pcwl_maci_t * pcwl_p,wl_scan_result_t s)1968 pcwl_add_scan_item(pcwl_maci_t *pcwl_p, wl_scan_result_t s)
1969 {
1970 	wl_scan_list_t *scan_item;
1971 
1972 	scan_item = kmem_zalloc(sizeof (wl_scan_list_t), KM_SLEEP);
1973 	if (scan_item == NULL) {
1974 		cmn_err(CE_WARN, "pcwl add_scan_item: zalloc failed\n");
1975 		return (PCWL_FAIL);
1976 	}
1977 	scan_item->wl_val = s;
1978 	scan_item->wl_timeout = WL_SCAN_TIMEOUT_MAX;
1979 	list_insert_tail(&pcwl_p->pcwl_scan_list, scan_item);
1980 	pcwl_p->pcwl_scan_num++;
1981 	return (PCWL_SUCCESS);
1982 }
1983 
1984 static void
pcwl_delete_scan_item(pcwl_maci_t * pcwl_p,wl_scan_list_t * s)1985 pcwl_delete_scan_item(pcwl_maci_t *pcwl_p, wl_scan_list_t *s)
1986 {
1987 	list_remove(&pcwl_p->pcwl_scan_list, s);
1988 	kmem_free(s, sizeof (*s));
1989 	pcwl_p->pcwl_scan_num--;
1990 }
1991 
1992 static void
pcwl_scanlist_timeout(void * arg)1993 pcwl_scanlist_timeout(void *arg)
1994 {
1995 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
1996 	wl_scan_list_t *scan_item0, *scan_item1;
1997 
1998 	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
1999 	scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
2000 	for (; scan_item0; ) {
2001 		PCWLDBG((CE_NOTE, "ssid = %s\n",
2002 		    scan_item0->wl_val.wl_srt_ssid));
2003 		PCWLDBG((CE_NOTE, "timeout left: %ds",
2004 		    scan_item0->wl_timeout));
2005 		scan_item1 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
2006 		if (scan_item0->wl_timeout == 0) {
2007 			pcwl_delete_scan_item(pcwl_p, scan_item0);
2008 		} else {
2009 			scan_item0->wl_timeout--;
2010 		}
2011 		scan_item0 = scan_item1;
2012 	}
2013 	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2014 	pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
2015 	    pcwl_p, drv_usectohz(1000000));
2016 }
2017 
2018 static void
pcwl_get_rssi(pcwl_maci_t * pcwl_p)2019 pcwl_get_rssi(pcwl_maci_t *pcwl_p)
2020 {
2021 	wl_scan_list_t *scan_item0;
2022 	uint16_t cq[3];
2023 
2024 	bzero(cq, sizeof (cq));
2025 	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
2026 	scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
2027 	for (; scan_item0; ) {
2028 		if (bcmp(scan_item0->wl_val.wl_srt_bssid,
2029 		    pcwl_p->pcwl_bssid, 6) == 0) {
2030 			pcwl_p->pcwl_rssi = scan_item0->wl_val.wl_srt_sl;
2031 		}
2032 		scan_item0 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
2033 	}
2034 	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2035 	if (!pcwl_p->pcwl_rssi) {
2036 		(void) pcwl_get_ltv(pcwl_p, 6, WL_RID_COMMQUAL, cq);
2037 		pcwl_p->pcwl_rssi = cq[1];
2038 	}
2039 }
2040 
2041 /*
2042  * Note:
2043  * PrismII chipset has 2 extra space for the reason why scan is initiated
2044  */
2045 static void
pcwl_ssid_scan(pcwl_maci_t * pcwl_p,uint16_t fid,uint16_t flen,uint16_t stype)2046 pcwl_ssid_scan(pcwl_maci_t *pcwl_p, uint16_t fid, uint16_t flen, uint16_t stype)
2047 {
2048 	uint16_t stat;
2049 	uint16_t ssidNum, i;
2050 	uint16_t off, szbuf;
2051 	uint16_t tmp[2];
2052 	wl_scan_list_t *scan_item0;
2053 	uint32_t check_num;
2054 	uint8_t	bssid_t[6];
2055 
2056 	wl_scan_result_t sctbl;
2057 
2058 	off = sizeof (uint16_t) * 2;
2059 	switch (pcwl_p->pcwl_chip_type) {
2060 	case PCWL_CHIP_PRISMII:
2061 		(void) RDCH0(pcwl_p, fid, off, tmp, 4);
2062 		off += 4;
2063 		szbuf = (stype == WL_INFO_SCAN_RESULTS ? 31 : 32);
2064 		PCWLDBG((CE_NOTE, "pcwl ssid_scan: PRISM chip\n"));
2065 		break;
2066 	case PCWL_CHIP_LUCENT:
2067 		PCWLDBG((CE_NOTE, "pcwl ssid_scan LUCENT chip\n"));
2068 	default:
2069 		szbuf = 25;
2070 	}
2071 
2072 	flen = flen + 1 - (off >> 1);
2073 	ssidNum = flen/szbuf;
2074 	ssidNum = min(WL_SRT_MAX_NUM, ssidNum);
2075 
2076 	PCWLDBG((CE_NOTE, "pcwl: ssid_scan frame length = %d\n", flen));
2077 
2078 	PCWLDBG((CE_NOTE, "pcwl ssid_scan: %d ssid(s) available", ssidNum));
2079 
2080 	bzero(bssid_t, sizeof (bssid_t));
2081 	for (i = 0; i < ssidNum; i++) {
2082 		(void) RDCH0(pcwl_p, fid, off, (uint16_t *)&sctbl, 2*szbuf);
2083 
2084 #ifdef DEBUG
2085 		if (pcwl_debug & PCWL_DBG_INFO) {
2086 			int j;
2087 			for (j = 0; j < sizeof (sctbl); j++)
2088 				cmn_err(CE_NOTE, "%d: %x\n", j,
2089 				    *((uint8_t *)&sctbl + j));
2090 		}
2091 #endif
2092 
2093 		off += (szbuf << 1);
2094 		stat = min(sctbl.wl_srt_ssidlen, 31);
2095 		PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_bssid), 6);
2096 		PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_ssid), stat);
2097 		sctbl.wl_srt_ssid[stat] = '\0';
2098 		sctbl.wl_srt_sl &= 0x7f;
2099 
2100 		/*
2101 		 * sometimes, those empty items are recorded by hardware,
2102 		 * this is wrong, just ignore those items here.
2103 		 */
2104 		if (bcmp(sctbl.wl_srt_bssid,
2105 		    bssid_t, 6) == 0) {
2106 			continue;
2107 		}
2108 		if (bcmp(sctbl.wl_srt_bssid,
2109 		    pcwl_p->pcwl_bssid, 6) == 0) {
2110 			pcwl_p->pcwl_rssi = sctbl.wl_srt_sl;
2111 		}
2112 		/*
2113 		 * save/update the scan item in scanlist
2114 		 */
2115 		mutex_enter(&pcwl_p->pcwl_scanlist_lock);
2116 		check_num = 0;
2117 		scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
2118 		if (scan_item0 == NULL) {
2119 			if (pcwl_add_scan_item(pcwl_p, sctbl)
2120 			    != 0) {
2121 				mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2122 				return;
2123 			}
2124 		}
2125 		for (; scan_item0; ) {
2126 			if (bcmp(sctbl.wl_srt_bssid,
2127 			    scan_item0->wl_val.wl_srt_bssid, 6) == 0) {
2128 				scan_item0->wl_val = sctbl;
2129 				scan_item0->wl_timeout = WL_SCAN_TIMEOUT_MAX;
2130 				break;
2131 			} else {
2132 				check_num++;
2133 			}
2134 			scan_item0 = list_next(&pcwl_p->pcwl_scan_list,
2135 			    scan_item0);
2136 		}
2137 		if (check_num == pcwl_p->pcwl_scan_num) {
2138 			if (pcwl_add_scan_item(pcwl_p, sctbl)
2139 			    != 0) {
2140 				mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2141 				return;
2142 			}
2143 		}
2144 		mutex_exit(&pcwl_p->pcwl_scanlist_lock);
2145 		PCWLDBG((CE_NOTE, "pcwl ssid_scan: ssid%d = %s\n", i+1,
2146 		    sctbl.wl_srt_ssid));
2147 		PCWLDBG((CE_NOTE, "pcwl ssid_scan: channel = %d\n",
2148 		    sctbl.wl_srt_chid));
2149 		PCWLDBG((CE_NOTE, "pcwl ssid_scan: signal level= %d\n",
2150 		    sctbl.wl_srt_sl));
2151 		PCWLDBG((CE_NOTE, "pcwl ssid_scan: noise level = %d\n",
2152 		    sctbl.wl_srt_anl));
2153 		PCWLDBG((CE_NOTE, "pcwl ssid_scan: bssid%d ="
2154 		    " %x %x %x %x %x %x\n\n", i+1,
2155 		    sctbl.wl_srt_bssid[0],
2156 		    sctbl.wl_srt_bssid[1],
2157 		    sctbl.wl_srt_bssid[2],
2158 		    sctbl.wl_srt_bssid[3],
2159 		    sctbl.wl_srt_bssid[4],
2160 		    sctbl.wl_srt_bssid[5]));
2161 	}
2162 
2163 }
2164 
2165 /*
2166  * delay in which the mutex is not hold.
2167  * assuming the mutex has already been hold.
2168  */
2169 static void
pcwl_delay(pcwl_maci_t * pcwl_p,clock_t microsecs)2170 pcwl_delay(pcwl_maci_t *pcwl_p, clock_t microsecs)
2171 {
2172 	ASSERT(mutex_owned(&pcwl_p->pcwl_glock));
2173 
2174 	mutex_exit(&pcwl_p->pcwl_glock);
2175 	delay(drv_usectohz(microsecs));
2176 	mutex_enter(&pcwl_p->pcwl_glock);
2177 }
2178 
2179 static int
pcwl_reset_backend(pcwl_maci_t * pcwl_p)2180 pcwl_reset_backend(pcwl_maci_t *pcwl_p)
2181 {
2182 	uint16_t ret = 0;
2183 
2184 	if (ret =  pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
2185 		return ((int)ret);
2186 	}
2187 
2188 	pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
2189 
2190 	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
2191 		return ((int)ret);
2192 	}
2193 	pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
2194 
2195 	PCWL_DISABLE_INTR(pcwl_p);
2196 	return (PCWL_SUCCESS);
2197 }
2198 
2199 
2200 /*
2201  * get card capability (WEP, default channel), setup broadcast, mac addresses
2202  */
2203 static int
pcwl_get_cap(pcwl_maci_t * pcwl_p)2204 pcwl_get_cap(pcwl_maci_t *pcwl_p)
2205 {
2206 	uint16_t stat, ch_no;
2207 	uint16_t buf[ETHERADDRL >> 1];
2208 
2209 	bzero(buf, ETHERADDRL);
2210 	if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_OWN_CHNL, &ch_no)) {
2211 		cmn_err(CE_CONT, "pcwl get_cap: get def channel failed"
2212 		    " %x\n", stat);
2213 		return ((int)stat);
2214 	}
2215 	if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_WEP_AVAIL,
2216 	    &pcwl_p->pcwl_has_wep)) {
2217 		cmn_err(CE_CONT, "pcwl get_cap: get WEP capability failed"
2218 		    " %x\n", stat);
2219 		return ((int)stat);
2220 	}
2221 	if (stat = pcwl_get_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf)) {
2222 		cmn_err(CE_CONT, "pcwl get_cap: get macaddr failed"
2223 		    " %x\n", stat);
2224 		return ((int)stat);
2225 	}
2226 
2227 	/*
2228 	 * don't assume m_xxx members are 16-bit aligned
2229 	 */
2230 	PCWL_SWAP16(buf, ETHERADDRL);
2231 	ether_copy(buf, pcwl_p->pcwl_mac_addr);
2232 	return (PCWL_SUCCESS);
2233 }
2234 
2235 static int
pcwl_init_nicmem(pcwl_maci_t * pcwl_p)2236 pcwl_init_nicmem(pcwl_maci_t *pcwl_p)
2237 {
2238 	uint16_t ret, i;
2239 	uint16_t rc;
2240 
2241 	for (i = 0; i < WL_XMT_BUF_NUM; i++) {
2242 		ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &rc);
2243 		if (ret) {
2244 			cmn_err(CE_WARN,
2245 			    "pcwl: alloc NIC Tx buf failed %x\n", ret);
2246 			return (PCWL_FAIL);
2247 		}
2248 		pcwl_p->pcwl_txring.wl_tx_fids[i] = rc;
2249 		pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
2250 		PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem_id[%d]=%x\n", i, rc));
2251 	}
2252 	pcwl_p->pcwl_txring.wl_tx_prod = pcwl_p->pcwl_txring.wl_tx_cons = 0;
2253 
2254 	ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &pcwl_p->pcwl_mgmt_id);
2255 	if (ret) {
2256 		cmn_err(CE_WARN, "pcwl: alloc NIC Mgmt buf failed %x\n", ret);
2257 		return (PCWL_FAIL);
2258 	}
2259 	PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem mgmt_id=%x\n",
2260 	    pcwl_p->pcwl_mgmt_id));
2261 	return (PCWL_SUCCESS);
2262 }
2263 
2264 static int
pcwl_loaddef_rf(pcwl_maci_t * pcwl_p)2265 pcwl_loaddef_rf(pcwl_maci_t *pcwl_p)
2266 {
2267 	pcwl_p->pcwl_rf.rf_max_datalen = WL_DEFAULT_DATALEN;
2268 	pcwl_p->pcwl_rf.rf_create_ibss = WL_DEFAULT_CREATE_IBSS;
2269 	pcwl_p->pcwl_rf.rf_porttype = WL_BSS_BSS;
2270 	pcwl_p->pcwl_rf.rf_rts_thresh = WL_DEFAULT_RTS_THRESH;
2271 	pcwl_p->pcwl_rf.rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
2272 	pcwl_p->pcwl_rf.rf_pm_enabled = WL_DEFAULT_PM_ENABLED;
2273 	pcwl_p->pcwl_rf.rf_own_chnl = WL_DEFAULT_CHAN;
2274 	(void) strcpy(pcwl_p->pcwl_rf.rf_own_ssid, "");
2275 	(void) strcpy(pcwl_p->pcwl_rf.rf_desired_ssid, "");
2276 	(void) strcpy(pcwl_p->pcwl_rf.rf_nodename, "");
2277 	pcwl_p->pcwl_rf.rf_encryption = WL_NOENCRYPTION;
2278 	pcwl_p->pcwl_rf.rf_authtype = WL_OPENSYSTEM;
2279 	pcwl_p->pcwl_rf.rf_tx_crypt_key = WL_DEFAULT_TX_CRYPT_KEY;
2280 	bzero((pcwl_p->pcwl_rf.rf_ckeys), sizeof (rf_ckey_t) * 4);
2281 
2282 	pcwl_p->pcwl_rf.rf_promiscuous = 0;
2283 
2284 	return (pcwl_config_rf(pcwl_p));
2285 }
2286 
2287 static int
pcwl_config_rf(pcwl_maci_t * pcwl_p)2288 pcwl_config_rf(pcwl_maci_t *pcwl_p)
2289 {
2290 	pcwl_rf_t *rf_p = &pcwl_p->pcwl_rf;
2291 	uint16_t create_ibss, porttype;
2292 
2293 	/*
2294 	 * Lucent card:
2295 	 * 0 Join ESS or IBSS; 1 Join ESS or join/create IBSS
2296 	 * PrismII card:
2297 	 * 3 Join ESS or IBSS(do not create IBSS);
2298 	 * 1 Join ESS or join/create IBSS
2299 	 */
2300 	create_ibss = rf_p->rf_create_ibss;
2301 	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
2302 		if (rf_p->rf_create_ibss == 0)
2303 			create_ibss = 3;
2304 	}
2305 	/*
2306 	 * Lucent card:
2307 	 * 1 BSS; 3 pseudo IBSS(only for test,not the 802.11 IBSS)
2308 	 * so porttype register should always be set to 1
2309 	 * PrismII card:
2310 	 * 0 IBSS; 1 BSS; 2 WDS; 3 pseudo IBSS; 6 hostAP
2311 	 */
2312 	switch (pcwl_p->pcwl_chip_type) {
2313 	case PCWL_CHIP_PRISMII:
2314 		if (rf_p->rf_porttype == WL_BSS_BSS)
2315 			porttype = 1;
2316 		else if (rf_p->rf_porttype == WL_BSS_IBSS)
2317 			porttype = 0;
2318 		else
2319 			porttype = 0;
2320 		break;
2321 	case PCWL_CHIP_LUCENT:
2322 	default:
2323 		porttype = 1;
2324 	}
2325 
2326 
2327 	FIL_LTV(pcwl_p, PCWL_MCBUF_LEN, WL_RID_MCAST, 0);
2328 	FIL_LTV(pcwl_p, 2,	WL_RID_PROMISC,		0);
2329 	FIL_LTV(pcwl_p, 2,	WL_RID_TICK_TIME,	0);
2330 
2331 	FIL_LTV(pcwl_p, 2, WL_RID_MAX_DATALEN, rf_p->rf_max_datalen);
2332 	FIL_LTV(pcwl_p, 2, WL_RID_CREATE_IBSS, create_ibss);
2333 	FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, porttype);
2334 	FIL_LTV(pcwl_p, 2, WL_RID_RTS_THRESH, rf_p->rf_rts_thresh);
2335 	FIL_LTV(pcwl_p, 2, WL_RID_TX_RATE, rf_p->rf_tx_rate);
2336 	FIL_LTV(pcwl_p, 2, WL_RID_SYSTEM_SCALE, rf_p->rf_system_scale);
2337 	FIL_LTV(pcwl_p, 2, WL_RID_PM_ENABLED, rf_p->rf_pm_enabled);
2338 	FIL_LTV(pcwl_p, 2, WL_RID_MAX_SLEEP, rf_p->rf_max_sleep);
2339 	FIL_LTV(pcwl_p, 2, WL_RID_OWN_CHNL, rf_p->rf_own_chnl);
2340 
2341 	PUT_STR(pcwl_p, WL_RID_OWN_SSID, rf_p->rf_own_ssid);
2342 	PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, rf_p->rf_desired_ssid);
2343 	PUT_STR(pcwl_p, WL_RID_NODENAME, rf_p->rf_nodename);
2344 
2345 	if (!pcwl_p->pcwl_has_wep)
2346 		goto done;
2347 
2348 	switch (pcwl_p->pcwl_chip_type) {
2349 	case PCWL_CHIP_PRISMII: {
2350 		int i;
2351 
2352 		for (i = 0; i < 4; i++) {
2353 			int k_len = strlen((char *)rf_p->rf_ckeys[i].ckey_dat);
2354 			if (k_len == 0)
2355 				continue;
2356 			k_len = k_len > 5 ? 14 : 6;
2357 			PUT_LTV(pcwl_p, k_len, WL_RID_CRYPT_KEY0_P2 + i,
2358 			    (uint16_t *)&rf_p->rf_ckeys[i].ckey_dat);
2359 		}
2360 		FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY_P2,
2361 		    rf_p->rf_tx_crypt_key);
2362 		FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_P2,
2363 		    rf_p->rf_authtype);
2364 		FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION_P2,
2365 		    rf_p->rf_encryption);
2366 		if (pcwl_p->pcwl_rf.rf_promiscuous)
2367 			FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 1);
2368 		}
2369 		break;
2370 	case PCWL_CHIP_LUCENT:
2371 	default:
2372 		FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION,
2373 		    rf_p->rf_encryption);
2374 		FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_L,
2375 		    rf_p->rf_authtype);
2376 		FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY,
2377 		    rf_p->rf_tx_crypt_key);
2378 		PUT_LTV(pcwl_p, sizeof (rf_p->rf_ckeys),
2379 		    WL_RID_DEFLT_CRYPT_KEYS,
2380 		    (uint16_t *)rf_p->rf_ckeys);
2381 		break;
2382 	}
2383 done:
2384 	return (PCWL_SUCCESS);
2385 }
2386 
2387 static void
pcwl_start_locked(pcwl_maci_t * pcwl_p)2388 pcwl_start_locked(pcwl_maci_t *pcwl_p)
2389 {
2390 	pcwl_p->pcwl_flag |= PCWL_CARD_INTREN;
2391 	PCWL_ENABLE_INTR(pcwl_p);
2392 }
2393 
2394 static void
pcwl_stop_locked(pcwl_maci_t * pcwl_p)2395 pcwl_stop_locked(pcwl_maci_t *pcwl_p)
2396 {
2397 	PCWL_DISABLE_INTR(pcwl_p);
2398 	pcwl_p->pcwl_flag &= (~PCWL_CARD_INTREN);
2399 	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
2400 	    WL_EV_ALLOC|WL_EV_INFO|WL_EV_INFO_DROP);
2401 	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
2402 	    WL_EV_ALLOC| WL_EV_INFO|WL_EV_INFO_DROP);
2403 }
2404 
2405 /*ARGSUSED*/
2406 static int
pcwl_saddr_locked(pcwl_maci_t * pcwl_p)2407 pcwl_saddr_locked(pcwl_maci_t *pcwl_p)
2408 {
2409 	int ret;
2410 	uint16_t buf[ETHERADDRL >> 1];
2411 
2412 	ether_copy(pcwl_p->pcwl_mac_addr, buf);
2413 	PCWL_SWAP16(buf, ETHERADDRL);
2414 	ret = pcwl_put_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf);
2415 	if (ret) {
2416 		cmn_err(CE_WARN, "pcwl set_mac_addr: failed %x\n", ret);
2417 		return (PCWL_FAIL);
2418 	}
2419 	return (PCWL_SUCCESS);
2420 }
2421 
2422 static void
pcwl_chip_type(pcwl_maci_t * pcwl_p)2423 pcwl_chip_type(pcwl_maci_t *pcwl_p)
2424 {
2425 	pcwl_ltv_ver_t ver;
2426 	pcwl_ltv_fwver_t f;
2427 
2428 	bzero(&ver, sizeof (ver));
2429 	(void) pcwl_get_ltv(pcwl_p, sizeof (ver),
2430 	    WL_RID_CARD_ID, (uint16_t *)&ver);
2431 	PCWLDBG((CE_NOTE, "card id:%04x-%04x-%04x-%04x\n",
2432 	    ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
2433 	if ((ver.wl_compid & 0xf000) != 0x8000)
2434 		return;	/* lucent */
2435 
2436 	pcwl_p->pcwl_chip_type = PCWL_CHIP_PRISMII;
2437 	(void) pcwl_get_ltv(pcwl_p, sizeof (ver), WL_RID_COMP_IDENT,
2438 	    (uint16_t *)&ver);
2439 	PCWLDBG((CE_NOTE, "PRISM-II ver:%04x-%04x-%04x-%04x\n",
2440 	    ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
2441 
2442 	bzero(&f, sizeof (f));
2443 	(void) pcwl_get_ltv(pcwl_p, sizeof (f), WL_RID_FWVER, (uint16_t *)&f);
2444 	PCWL_SWAP16((uint16_t *)&f, sizeof (f));
2445 	PCWLDBG((CE_NOTE, "Firmware Pri:%s 2,3:%s\n",
2446 	    (char *)f.pri, (char *)f.st));
2447 }
2448 
2449 /*
2450  * Brussels support
2451  */
2452 /*
2453  * MAC_PROP_WL_ESSID
2454  */
2455 static int
pcwl_set_essid(pcwl_maci_t * pcwl_p,const void * wldp_buf)2456 pcwl_set_essid(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2457 {
2458 	char 		*value;
2459 	pcwl_rf_t 	*rf_p;
2460 	wl_essid_t 	*iw_essid = (wl_essid_t *)wldp_buf;
2461 
2462 	rf_p = &pcwl_p->pcwl_rf;
2463 
2464 	value = iw_essid->wl_essid_essid;
2465 	(void) strncpy(rf_p->rf_desired_ssid, value,
2466 	    MIN(32, strlen(value)));
2467 	rf_p->rf_desired_ssid[strlen(value)] = '\0';
2468 	(void) strncpy(rf_p->rf_own_ssid, value,
2469 	    MIN(32, strlen(value)));
2470 	rf_p->rf_own_ssid[strlen(value)] = '\0';
2471 
2472 	PCWLDBG((CE_CONT, "pcwl: set: desired essid=%s\n",
2473 	    rf_p->rf_desired_ssid));
2474 
2475 	return (ENETRESET);
2476 
2477 }
2478 
2479 static int
pcwl_get_essid(pcwl_maci_t * pcwl_p,void * wldp_buf)2480 pcwl_get_essid(pcwl_maci_t *pcwl_p, void *wldp_buf)
2481 {
2482 	char		ssid[36];
2483 	uint16_t	ret;
2484 	uint16_t	val;
2485 	int		len;
2486 	int		err = 0;
2487 	wl_essid_t	ow_essid;
2488 	pcwl_rf_t	*rf_p;
2489 
2490 	rf_p = &pcwl_p->pcwl_rf;
2491 	bzero(&ow_essid, sizeof (wl_essid_t));
2492 	bzero(ssid, sizeof (ssid));
2493 
2494 	ret =  pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
2495 	if (ret) {
2496 		err = EIO;
2497 		return (err);
2498 	}
2499 	PCWLDBG((CE_NOTE, "PortStatus = %d\n", val));
2500 
2501 	switch (val) {
2502 	case WL_PORT_DISABLED:
2503 	case WL_PORT_INITIAL:
2504 		len = mi_strlen(rf_p->rf_desired_ssid);
2505 		ow_essid.wl_essid_length = len;
2506 		bcopy(rf_p->rf_desired_ssid, ow_essid.wl_essid_essid,
2507 		    len);
2508 		break;
2509 	case WL_PORT_TO_IBSS:
2510 	case WL_PORT_TO_BSS:
2511 	case WL_PORT_OOR:
2512 		(void) pcwl_get_ltv((pcwl_p), 34, WL_RID_SSID,
2513 		    (uint16_t *)ssid);
2514 		PCWL_SWAP16((uint16_t *)(ssid+2), *(uint16_t *)ssid);
2515 		ssid[*(uint16_t *)ssid + 2] = '\0';
2516 		len = mi_strlen(ssid+2);
2517 		ow_essid.wl_essid_length = len;
2518 		bcopy(ssid + 2, ow_essid.wl_essid_essid, len);
2519 		break;
2520 	default:
2521 		err = EINVAL;
2522 		break;
2523 	}
2524 
2525 	bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t));
2526 
2527 	return (err);
2528 }
2529 
2530 /*
2531  * MAC_PROP_WL_BSSID
2532  */
2533 static int
pcwl_get_bssid(pcwl_maci_t * pcwl_p,void * wldp_buf)2534 pcwl_get_bssid(pcwl_maci_t *pcwl_p, void *wldp_buf)
2535 {
2536 	uint16_t 	ret;
2537 	uint16_t 	retval;
2538 	uint8_t 	bssid[6];
2539 	int 		err = 0;
2540 
2541 	if (ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval)) {
2542 		err = EIO;
2543 		return (err);
2544 	}
2545 
2546 	PCWLDBG((CE_NOTE, "PortStatus = %d\n", ret));
2547 
2548 	if (retval == WL_PORT_DISABLED || retval == WL_PORT_INITIAL) {
2549 		bzero(wldp_buf, sizeof (wl_bssid_t));
2550 	} else if (retval == WL_PORT_TO_IBSS ||
2551 	    retval == WL_PORT_TO_BSS || retval == WL_PORT_OOR) {
2552 		(void) pcwl_get_ltv(pcwl_p, 6,
2553 		    WL_RID_BSSID, (uint16_t *)bssid);
2554 		PCWL_SWAP16((uint16_t *)bssid, 6);
2555 		bcopy(bssid, wldp_buf, sizeof (wl_bssid_t));
2556 	}
2557 
2558 	PCWLDBG((CE_CONT, "pcwl_get_bssid: bssid=%x %x %x %x %x %x\n",
2559 	    bssid[0], bssid[1], bssid[2],
2560 	    bssid[3], bssid[4], bssid[5]));
2561 
2562 	return (err);
2563 }
2564 
2565 /*
2566  * MAC_PROP_WL_LINKSTATUS
2567  */
2568 static int
pcwl_get_linkstatus(pcwl_maci_t * pcwl_p,void * wldp_buf)2569 pcwl_get_linkstatus(pcwl_maci_t *pcwl_p, void *wldp_buf)
2570 {
2571 	uint16_t 	ret;
2572 	uint16_t	retval;
2573 	int		err = 0;
2574 
2575 	ret =  pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval);
2576 	if (ret) {
2577 		err = EIO;
2578 		PCWLDBG((CE_WARN, "cfg_linkstatus_get_error\n"));
2579 		return (err);
2580 	}
2581 	PCWLDBG((CE_NOTE, "PortStatus = %d\n", retval));
2582 
2583 	switch (retval) {
2584 	case WL_PORT_DISABLED:
2585 	case WL_PORT_INITIAL:
2586 		*(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
2587 		break;
2588 	case WL_PORT_TO_IBSS:
2589 	case WL_PORT_TO_BSS:
2590 	case WL_PORT_OOR:
2591 		*(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
2592 		break;
2593 	default:
2594 		err = EINVAL;
2595 		break;
2596 	}
2597 
2598 	return (err);
2599 }
2600 
2601 /*
2602  * MAC_PROP_WL_BSSTYP
2603  */
2604 static int
pcwl_set_bsstype(pcwl_maci_t * pcwl_p,const void * wldp_buf)2605 pcwl_set_bsstype(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2606 {
2607 	uint16_t 	ret;
2608 	pcwl_rf_t 	*rf_p;
2609 	int		err = ENETRESET;
2610 
2611 	rf_p = &pcwl_p->pcwl_rf;
2612 
2613 	ret = (uint16_t)(*(wl_bss_type_t *)wldp_buf);
2614 	if ((ret != WL_BSS_BSS) &&
2615 	    (ret != WL_BSS_IBSS) &&
2616 	    (ret != WL_BSS_ANY)) {
2617 		err = ENOTSUP;
2618 		return (err);
2619 	}
2620 
2621 	rf_p->rf_porttype = ret;
2622 
2623 	return (err);
2624 }
2625 
2626 static void
pcwl_get_bsstype(pcwl_maci_t * pcwl_p,void * wldp_buf)2627 pcwl_get_bsstype(pcwl_maci_t *pcwl_p, void *wldp_buf)
2628 {
2629 	pcwl_rf_t *rf_p;
2630 
2631 	rf_p = &pcwl_p->pcwl_rf;
2632 
2633 	*(wl_bss_type_t *)wldp_buf = rf_p->rf_porttype;
2634 
2635 	PCWLDBG((CE_CONT, "pcwl_get_bsstype: porttype=%d\n",
2636 	    rf_p->rf_porttype));
2637 }
2638 
2639 /*
2640  * MAC_PROP_WL_PHY_CONFIG
2641  */
2642 static int
pcwl_set_phy(pcwl_maci_t * pcwl_p,const void * wldp_buf)2643 pcwl_set_phy(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2644 {
2645 	uint16_t 	ret;
2646 	pcwl_rf_t 	*rf_p;
2647 	int		err = ENETRESET;
2648 	wl_phy_conf_t 	*phy = (wl_phy_conf_t *)wldp_buf;
2649 
2650 	rf_p = &pcwl_p->pcwl_rf;
2651 	ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
2652 	if (ret < 1 || ret > 14) {
2653 		err = ENOTSUP;
2654 		return (err);
2655 	}
2656 
2657 	rf_p->rf_own_chnl = ret;
2658 
2659 	PCWLDBG((CE_CONT, "pcwl: set channel=%d\n", rf_p->rf_own_chnl));
2660 
2661 	return (err);
2662 }
2663 
2664 static int
pcwl_get_phy(pcwl_maci_t * pcwl_p,void * wldp_buf)2665 pcwl_get_phy(pcwl_maci_t *pcwl_p, void *wldp_buf)
2666 {
2667 	uint16_t	retval;
2668 	wl_dsss_t 	*dsss = (wl_dsss_t *)wldp_buf;
2669 	int		err = 0;
2670 
2671 	if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CURRENT_CHNL, &retval)) {
2672 		err = EIO;
2673 		return (err);
2674 	}
2675 
2676 	dsss->wl_dsss_channel = retval;
2677 	PCWLDBG((CE_CONT, "pcwl_get_phy: channel=%d\n", retval));
2678 	dsss->wl_dsss_subtype = WL_DSSS;
2679 
2680 	return (err);
2681 }
2682 
2683 /*
2684  * MAC_PROP_WL_DESIRED_RATESa
2685  */
2686 static int
pcwl_set_desrates(pcwl_maci_t * pcwl_p,const void * wldp_buf)2687 pcwl_set_desrates(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2688 {
2689 	int		err = ENETRESET;
2690 	char 		rates[4];
2691 	char 		maxrate;
2692 	uint16_t 	i;
2693 	pcwl_rf_t 	*rf_p;
2694 	wl_rates_t 	*iw_rates = (wl_rates_t *)wldp_buf;
2695 
2696 	rf_p = &pcwl_p->pcwl_rf;
2697 
2698 	bzero(rates, sizeof (rates));
2699 
2700 	for (i = 0; i < 4; i++) {
2701 		rates[i] = iw_rates->wl_rates_rates[i];
2702 		PCWLDBG((CE_CONT, "pcwl: set tx_rate[%d]=%d\n", i, rates[i]));
2703 	}
2704 	PCWLDBG((CE_CONT, "pcwl: set rate_num=%d\n", iw_rates->wl_rates_num));
2705 
2706 	switch (iw_rates->wl_rates_num) {
2707 	case 1:
2708 		switch (rates[0]) {
2709 		case WL_RATE_1M:
2710 			rf_p->rf_tx_rate = WL_TX_RATE_FIX_1M(pcwl_p);
2711 			break;
2712 		case WL_RATE_2M:
2713 			rf_p->rf_tx_rate = WL_TX_RATE_FIX_2M(pcwl_p);
2714 			break;
2715 		case WL_RATE_11M:
2716 			rf_p->rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
2717 			break;
2718 		case WL_RATE_5_5M:
2719 			rf_p->rf_tx_rate = WL_TX_RATE_FIX_5M(pcwl_p);
2720 			break;
2721 		default:
2722 			err = EINVAL;
2723 			break;
2724 		}
2725 		break;
2726 	case 2:
2727 		maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
2728 		switch (maxrate) {
2729 		case WL_RATE_2M:
2730 			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_L(pcwl_p);
2731 			break;
2732 		case WL_RATE_11M:
2733 			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
2734 			break;
2735 		case WL_RATE_5_5M:
2736 			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
2737 			break;
2738 		default:
2739 			err = EINVAL;
2740 			break;
2741 		}
2742 		break;
2743 	case 3:
2744 		maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
2745 		maxrate = (rates[2] > maxrate ? rates[2] : maxrate);
2746 		switch (maxrate) {
2747 		case WL_RATE_11M:
2748 			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
2749 			break;
2750 		case WL_RATE_5_5M:
2751 			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
2752 			break;
2753 		default:
2754 			err = EINVAL;
2755 			break;
2756 		}
2757 		break;
2758 	case 4:
2759 		rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
2760 		break;
2761 	default:
2762 		err = ENOTSUP;
2763 		break;
2764 	}
2765 	PCWLDBG((CE_CONT, "pcwl: set tx_rate=%d\n", rf_p->rf_tx_rate));
2766 
2767 	return (err);
2768 }
2769 
2770 static int
pcwl_get_desrates(pcwl_maci_t * pcwl_p,void * wldp_buf)2771 pcwl_get_desrates(pcwl_maci_t *pcwl_p, void *wldp_buf)
2772 {
2773 	uint16_t 	rate;
2774 	int		err = 0;
2775 
2776 	if (pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate)) {
2777 		err = EIO;
2778 		return (err);
2779 	}
2780 
2781 	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
2782 		((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2783 		switch (rate) {
2784 		case WL_SPEED_1Mbps_P2:
2785 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2786 			    WL_RATE_1M;
2787 			break;
2788 		case WL_SPEED_2Mbps_P2:
2789 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2790 			    WL_RATE_2M;
2791 			break;
2792 		case WL_SPEED_55Mbps_P2:
2793 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2794 			    WL_RATE_5_5M;
2795 			break;
2796 		case WL_SPEED_11Mbps_P2:
2797 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2798 			    WL_RATE_11M;
2799 			break;
2800 		default:
2801 			err = EINVAL;
2802 			break;
2803 		}
2804 	} else {
2805 		switch (rate) {
2806 		case WL_L_TX_RATE_FIX_1M:
2807 			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2808 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2809 			    WL_RATE_1M;
2810 			break;
2811 		case WL_L_TX_RATE_FIX_2M:
2812 			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2813 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2814 			    WL_RATE_2M;
2815 			break;
2816 		case WL_L_TX_RATE_AUTO_H:
2817 			((wl_rates_t *)wldp_buf)->wl_rates_num = 4;
2818 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2819 			    WL_RATE_1M;
2820 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
2821 			    WL_RATE_2M;
2822 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
2823 			    WL_RATE_5_5M;
2824 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[3] =
2825 			    WL_RATE_11M;
2826 			break;
2827 		case WL_L_TX_RATE_FIX_5M:
2828 			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2829 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2830 			    WL_RATE_5_5M;
2831 			break;
2832 		case WL_L_TX_RATE_FIX_11M:
2833 			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
2834 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2835 			    WL_RATE_11M;
2836 			break;
2837 		case WL_L_TX_RATE_AUTO_L:
2838 			((wl_rates_t *)wldp_buf)->wl_rates_num = 2;
2839 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2840 			    WL_RATE_1M;
2841 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
2842 			    WL_RATE_2M;
2843 			break;
2844 		case WL_L_TX_RATE_AUTO_M:
2845 			((wl_rates_t *)wldp_buf)->wl_rates_num = 3;
2846 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
2847 			    WL_RATE_1M;
2848 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
2849 			    WL_RATE_2M;
2850 			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
2851 			    WL_RATE_5_5M;
2852 			break;
2853 		default:
2854 			err = EINVAL;
2855 			break;
2856 		}
2857 	}
2858 	PCWLDBG((CE_CONT, "pcwl: get rate=%d\n", rate));
2859 
2860 	return (err);
2861 }
2862 
2863 /*
2864  * MAC_PROP_WL_SUP_RATE
2865  */
2866 static void
pcwl_get_suprates(void * wldp_buf)2867 pcwl_get_suprates(void *wldp_buf)
2868 {
2869 	wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
2870 
2871 	wl_rates->wl_rates_num = 4;
2872 	wl_rates->wl_rates_rates[0] = WL_RATE_1M;
2873 	wl_rates->wl_rates_rates[1] = WL_RATE_2M;
2874 	wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
2875 	wl_rates->wl_rates_rates[3] = WL_RATE_11M;
2876 }
2877 
2878 /*
2879  * MAC_PROP_WL_POWER_MODE
2880  */
2881 static int
pcwl_set_powermode(pcwl_maci_t * pcwl_p,const void * wldp_buf)2882 pcwl_set_powermode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2883 {
2884 	uint16_t 	ret;
2885 	pcwl_rf_t 	*rf_p;
2886 	int		err = 0;
2887 
2888 	rf_p = &pcwl_p->pcwl_rf;
2889 
2890 	ret = (uint16_t)(((wl_ps_mode_t *)wldp_buf)->wl_ps_mode);
2891 	if (ret != WL_PM_AM && ret != WL_PM_MPS && ret != WL_PM_FAST) {
2892 		err = ENOTSUP;
2893 		return (err);
2894 	}
2895 
2896 	rf_p->rf_pm_enabled = ret;
2897 
2898 	return (err);
2899 
2900 }
2901 
2902 static void
pcwl_get_powermode(pcwl_maci_t * pcwl_p,void * wldp_buf)2903 pcwl_get_powermode(pcwl_maci_t *pcwl_p, void *wldp_buf)
2904 {
2905 	pcwl_rf_t *rf_p;
2906 
2907 	rf_p = &pcwl_p->pcwl_rf;
2908 	((wl_ps_mode_t *)wldp_buf)->wl_ps_mode = rf_p->rf_pm_enabled;
2909 }
2910 
2911 /*
2912  * MAC_PROP_AUTH_MODE
2913  */
2914 static int
pcwl_set_authmode(pcwl_maci_t * pcwl_p,const void * wldp_buf)2915 pcwl_set_authmode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2916 {
2917 	uint16_t	ret;
2918 	pcwl_rf_t 	*rf_p;
2919 	int		err = ENETRESET;
2920 
2921 	rf_p = &pcwl_p->pcwl_rf;
2922 
2923 	ret = (uint16_t)(*(wl_authmode_t *)wldp_buf);
2924 	if (ret != WL_OPENSYSTEM && ret != WL_SHAREDKEY) {
2925 		err = ENOTSUP;
2926 		return (err);
2927 	}
2928 
2929 	rf_p->rf_authtype = ret;
2930 
2931 	return (err);
2932 }
2933 
2934 static void
pcwl_get_authmode(pcwl_maci_t * pcwl_p,void * wldp_buf)2935 pcwl_get_authmode(pcwl_maci_t *pcwl_p, void *wldp_buf)
2936 {
2937 	pcwl_rf_t 	*rf_p;
2938 
2939 	rf_p = &pcwl_p->pcwl_rf;
2940 	*(wl_authmode_t *)wldp_buf = rf_p->rf_authtype;
2941 }
2942 
2943 /*
2944  * MAC_PROP_WL_ENCRYPTION
2945  */
2946 static int
pcwl_set_encrypt(pcwl_maci_t * pcwl_p,const void * wldp_buf)2947 pcwl_set_encrypt(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2948 {
2949 	uint16_t 	ret;
2950 	pcwl_rf_t 	*rf_p;
2951 	int		err = ENETRESET;
2952 
2953 	rf_p = &pcwl_p->pcwl_rf;
2954 
2955 	ret = (uint16_t)(*(wl_encryption_t *)wldp_buf);
2956 	PCWLDBG((CE_NOTE, "pcwl_set_encrypt: %d\n", ret));
2957 	if (ret != WL_NOENCRYPTION && ret != WL_ENC_WEP) {
2958 		err = ENOTSUP;
2959 		return (err);
2960 	}
2961 
2962 	rf_p->rf_encryption = ret;
2963 
2964 	return (err);
2965 }
2966 
2967 static void
pcwl_get_encrypt(pcwl_maci_t * pcwl_p,void * wldp_buf)2968 pcwl_get_encrypt(pcwl_maci_t *pcwl_p, void *wldp_buf)
2969 {
2970 	pcwl_rf_t *rf_p;
2971 
2972 	rf_p = &pcwl_p->pcwl_rf;
2973 	*(wl_encryption_t *)wldp_buf = rf_p->rf_encryption;
2974 }
2975 
2976 /*
2977  * MAC_PROP_WL_CREATE_IBSS
2978  */
2979 static int
pcwl_set_ibss(pcwl_maci_t * pcwl_p,const void * wldp_buf)2980 pcwl_set_ibss(pcwl_maci_t *pcwl_p, const void *wldp_buf)
2981 {
2982 	uint16_t 	ret;
2983 	pcwl_rf_t 	*rf_p;
2984 	int		err = ENETRESET;
2985 
2986 	rf_p = &pcwl_p->pcwl_rf;
2987 
2988 	ret = (uint16_t)(*(wl_create_ibss_t *)wldp_buf);
2989 	if (ret != 0 && ret != 1) {
2990 		err = ENOTSUP;
2991 		return (err);
2992 	}
2993 
2994 	rf_p->rf_create_ibss = ret;
2995 
2996 	return (err);
2997 }
2998 
2999 static void
pcwl_get_ibss(pcwl_maci_t * pcwl_p,void * wldp_buf)3000 pcwl_get_ibss(pcwl_maci_t *pcwl_p, void *wldp_buf)
3001 {
3002 	pcwl_rf_t 	*rf_p;
3003 
3004 	rf_p = &pcwl_p->pcwl_rf;
3005 	*(wl_create_ibss_t *)wldp_buf = rf_p->rf_create_ibss;
3006 }
3007 
3008 /*
3009  * MAC_PROP_WL_RSSI
3010  */
3011 static void
pcwl_get_param_rssi(pcwl_maci_t * pcwl_p,void * wldp_buf)3012 pcwl_get_param_rssi(pcwl_maci_t *pcwl_p, void *wldp_buf)
3013 {
3014 
3015 	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
3016 		*(wl_rssi_t *)wldp_buf =
3017 		    min((pcwl_p->pcwl_rssi * 15 / 85 + 1), 15);
3018 	} else {
3019 		/*
3020 		 * According to the description of the
3021 		 * datasheet(Lucent card), the signal level
3022 		 * value is between 27 -- 154.
3023 		 * we reflect these value to 1-15 as rssi.
3024 		 */
3025 		if (pcwl_p->pcwl_rssi <= 27)
3026 			*(wl_rssi_t *)wldp_buf = 1;
3027 		else if (pcwl_p->pcwl_rssi > 154)
3028 			*(wl_rssi_t *)wldp_buf = 15;
3029 		else
3030 			*(wl_rssi_t *)wldp_buf =
3031 			    min(15, ((pcwl_p->pcwl_rssi - 27) * 15 / 127));
3032 	}
3033 }
3034 
3035 /*
3036  * MAC_PROP_WL_KEY_TAB
3037  */
3038 static int
pcwl_set_wepkey(pcwl_maci_t * pcwl_p,const void * wldp_buf)3039 pcwl_set_wepkey(pcwl_maci_t *pcwl_p, const void *wldp_buf)
3040 {
3041 	uint16_t	i;
3042 	pcwl_rf_t 	*rf_p;
3043 	wl_wep_key_t 	*p_wepkey_tab;
3044 
3045 	rf_p = &pcwl_p->pcwl_rf;
3046 	bzero((rf_p->rf_ckeys), sizeof (rf_ckey_t) * MAX_NWEPKEYS);
3047 
3048 	p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
3049 	for (i = 0; i < MAX_NWEPKEYS; i++) {
3050 		if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
3051 			rf_p->rf_ckeys[i].ckey_len =
3052 			    p_wepkey_tab[i].wl_wep_length;
3053 			bcopy(p_wepkey_tab[i].wl_wep_key,
3054 			    rf_p->rf_ckeys[i].ckey_dat,
3055 			    p_wepkey_tab[i].wl_wep_length);
3056 			PCWL_SWAP16((uint16_t *)
3057 			    &rf_p->rf_ckeys[i].ckey_dat,
3058 			    rf_p->rf_ckeys[i].ckey_len + 1);
3059 			PCWLDBG((CE_CONT, "%s, %d\n",
3060 			    rf_p->rf_ckeys[i].ckey_dat, i));
3061 		}
3062 		PCWLDBG((CE_CONT, "pcwl: rf_ckeys[%d]=%s\n", i,
3063 		    (char *)(rf_p->rf_ckeys[i].ckey_dat)));
3064 	}
3065 
3066 	return (ENETRESET);
3067 }
3068 
3069 /*
3070  * MAC_PROP_WL_RADIO
3071  */
3072 static void
pcwl_get_radio(void * wldp_buf)3073 pcwl_get_radio(void *wldp_buf)
3074 {
3075 	wl_radio_t *radio = (wl_radio_t *)wldp_buf;
3076 
3077 	*radio = B_TRUE;
3078 }
3079 
3080 /*
3081  * MAC_PROP_WL_ESSLIST
3082  */
3083 static void
pcwl_get_esslist(pcwl_maci_t * pcwl_p,void * wldp_buf)3084 pcwl_get_esslist(pcwl_maci_t *pcwl_p, void *wldp_buf)
3085 {
3086 	uint16_t	i;
3087 	wl_ess_conf_t 	*p_ess_conf;
3088 	wl_scan_list_t	*scan_item;
3089 
3090 	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
3091 
3092 	((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
3093 	    pcwl_p->pcwl_scan_num;
3094 
3095 	scan_item = list_head(&pcwl_p->pcwl_scan_list);
3096 
3097 	for (i = 0; i < pcwl_p->pcwl_scan_num; i++) {
3098 		if (!scan_item)
3099 			break;
3100 
3101 		p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
3102 		    offsetof(wl_ess_list_t, wl_ess_list_ess) +
3103 		    i * sizeof (wl_ess_conf_t));
3104 		bcopy(scan_item->wl_val.wl_srt_ssid,
3105 		    p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
3106 		    mi_strlen(scan_item->wl_val.wl_srt_ssid));
3107 		bcopy(scan_item->wl_val.wl_srt_bssid,
3108 		    p_ess_conf->wl_ess_conf_bssid, 6);
3109 		(p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
3110 		    = WL_DSSS;
3111 		p_ess_conf->wl_ess_conf_wepenabled =
3112 		    (scan_item->wl_val.wl_srt_cap & 0x10 ?
3113 		    WL_ENC_WEP : WL_NOENCRYPTION);
3114 		p_ess_conf->wl_ess_conf_bsstype =
3115 		    (scan_item->wl_val.wl_srt_cap & 0x1 ?
3116 		    WL_BSS_BSS : WL_BSS_IBSS);
3117 		p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
3118 		    scan_item->wl_val.wl_srt_chid;
3119 		if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
3120 			p_ess_conf->wl_ess_conf_sl =
3121 			    min(scan_item->wl_val.wl_srt_sl * 15 / 85 + 1,
3122 			    15);
3123 		} else {
3124 			if (scan_item->wl_val.wl_srt_sl <= 27)
3125 				p_ess_conf->wl_ess_conf_sl = 1;
3126 			else if (scan_item->wl_val.wl_srt_sl > 154)
3127 				p_ess_conf->wl_ess_conf_sl = 15;
3128 			else
3129 				p_ess_conf->wl_ess_conf_sl = min(15,
3130 				    ((scan_item->wl_val.wl_srt_sl - 27)
3131 				    * 15 / 127));
3132 		}
3133 
3134 		p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
3135 		p_ess_conf->wl_supported_rates[0] = WL_RATE_2M;
3136 		p_ess_conf->wl_supported_rates[0] = WL_RATE_5_5M;
3137 		p_ess_conf->wl_supported_rates[0] = WL_RATE_11M;
3138 
3139 		scan_item = list_next(&pcwl_p->pcwl_scan_list, scan_item);
3140 	}
3141 
3142 	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
3143 }
3144 
3145 
3146 /*
3147  * for wificonfig and dladm ioctl
3148  */
3149 
3150 static int
pcwl_cfg_essid(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3151 pcwl_cfg_essid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3152 {
3153 	char 		ssid[36];
3154 	uint16_t 	i;
3155 	uint16_t 	val;
3156 	pcwl_rf_t 	*rf_p;
3157 	wldp_t		*infp;
3158 	wldp_t 		*outfp;
3159 	char 		*buf;
3160 	int 		iret;
3161 	int 		err = 0;
3162 
3163 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3164 	if (buf == NULL) {
3165 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3166 		    MAX_BUF_LEN));
3167 		return (ENOMEM);
3168 	}
3169 	outfp = (wldp_t *)buf;
3170 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3171 	infp = (wldp_t *)mp->b_rptr;
3172 	rf_p = &pcwl_p->pcwl_rf;
3173 
3174 
3175 	bzero(ssid, sizeof (ssid));
3176 	if (cmd == WLAN_GET_PARAM) {
3177 		err = pcwl_get_essid(pcwl_p, outfp->wldp_buf);
3178 		if (err == EIO) {
3179 			outfp->wldp_length = WIFI_BUF_OFFSET;
3180 			outfp->wldp_result = WL_HW_ERROR;
3181 			goto done;
3182 		}
3183 		(void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
3184 		if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
3185 			outfp->wldp_length = WIFI_BUF_OFFSET +
3186 			    offsetof(wl_essid_t, wl_essid_essid) +
3187 			    mi_strlen(rf_p->rf_desired_ssid);
3188 		} else if (val == WL_PORT_TO_IBSS ||
3189 		    val == WL_PORT_TO_BSS ||
3190 		    val == WL_PORT_OOR) {
3191 			outfp->wldp_length = WIFI_BUF_OFFSET +
3192 			    offsetof(wl_essid_t, wl_essid_essid) +
3193 			    mi_strlen(ssid+2);
3194 		} else {
3195 			outfp->wldp_length = WIFI_BUF_OFFSET;
3196 		}
3197 		outfp->wldp_result = WL_SUCCESS;
3198 		PCWLDBG((CE_CONT, "outfp->length=%d\n", outfp->wldp_length));
3199 		PCWLDBG((CE_CONT, "pcwl: get desired essid=%s\n",
3200 		    rf_p->rf_desired_ssid));
3201 	} else if (cmd == WLAN_SET_PARAM) {
3202 		(void) pcwl_set_essid(pcwl_p, infp->wldp_buf);
3203 		outfp->wldp_length = WIFI_BUF_OFFSET;
3204 		outfp->wldp_result = WL_SUCCESS;
3205 	} else {
3206 		kmem_free(buf, MAX_BUF_LEN);
3207 		return (EINVAL);
3208 	}
3209 done:
3210 	for (i = 0; i < (outfp->wldp_length); i++)
3211 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3212 	iret = (int)(outfp->wldp_result);
3213 	kmem_free(buf, MAX_BUF_LEN);
3214 	return (iret);
3215 }
3216 
3217 static int
pcwl_cfg_bssid(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3218 pcwl_cfg_bssid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3219 {
3220 	uint16_t 	i;
3221 	int 		iret;
3222 	wldp_t 		*outfp;
3223 	char 		*buf;
3224 	int 		err = 0;
3225 
3226 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3227 	if (buf == NULL) {
3228 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3229 		    MAX_BUF_LEN));
3230 		return (ENOMEM);
3231 	}
3232 	outfp = (wldp_t *)buf;
3233 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3234 
3235 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
3236 	if (cmd == WLAN_GET_PARAM) {
3237 		err = pcwl_get_bssid(pcwl_p, outfp->wldp_buf);
3238 		if (err == EIO) {
3239 			outfp->wldp_length = WIFI_BUF_OFFSET;
3240 			outfp->wldp_result = WL_HW_ERROR;
3241 			goto done;
3242 		}
3243 		outfp->wldp_result = WL_SUCCESS;
3244 	} else if (cmd == WLAN_SET_PARAM) {
3245 		outfp->wldp_result = WL_READONLY;
3246 	} else {
3247 		kmem_free(buf, MAX_BUF_LEN);
3248 		return (EINVAL);
3249 	}
3250 done:
3251 	for (i = 0; i < (outfp->wldp_length); i++)
3252 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3253 	iret = (int)(outfp->wldp_result);
3254 	kmem_free(buf, MAX_BUF_LEN);
3255 	return (iret);
3256 }
3257 
3258 /*ARGSUSED*/
3259 static int
pcwl_cmd_scan(pcwl_maci_t * pcwl_p)3260 pcwl_cmd_scan(pcwl_maci_t *pcwl_p)
3261 {
3262 	uint16_t vall[18], ret = WL_SUCCESS;
3263 	pcwl_rf_t *rf_p;
3264 	uint32_t enable, i;
3265 	size_t	len;
3266 
3267 	rf_p = &pcwl_p->pcwl_rf;
3268 
3269 	/*
3270 	 * The logic of this funtion is really tricky.
3271 	 * Firstly, the chip can only scan in BSS mode, so necessary
3272 	 * backup and restore is required before and after the scan
3273 	 * command.
3274 	 * Secondly, for Lucent chip, Alrealy associated with an AP
3275 	 * can only scan the APes on the fixed channel, so we must
3276 	 * set the desired_ssid as "" before scan and restore after.
3277 	 * Thirdly, scan cmd is effective only when the card is enabled
3278 	 * and any 'set' operation(such as set bsstype, ssid)must disable
3279 	 * the card first and then enable the card after the 'set'
3280 	 */
3281 	enable = pcwl_p->pcwl_flag & PCWL_ENABLED;
3282 	len = strlen(rf_p->rf_desired_ssid);
3283 
3284 	if (pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) {
3285 		if ((enable) &&
3286 		    (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
3287 			ret = (int)WL_HW_ERROR;
3288 			goto done;
3289 		}
3290 		FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, WL_BSS_BSS);
3291 	}
3292 
3293 	if ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0)) {
3294 		if ((enable) &&
3295 		    (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
3296 			ret = (int)WL_HW_ERROR;
3297 			goto done;
3298 		}
3299 		PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, "");
3300 	}
3301 
3302 	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
3303 		ret = (int)WL_HW_ERROR;
3304 		goto done;
3305 	}
3306 	pcwl_delay(pcwl_p, 1000000);
3307 
3308 	switch (pcwl_p->pcwl_chip_type) {
3309 	case PCWL_CHIP_PRISMII:
3310 		bzero(vall, sizeof (vall));
3311 		vall[0] = 0x3fff; /* channel mask */
3312 		vall[1] = 0x1; /* tx rate */
3313 		for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
3314 			PUT_LTV(pcwl_p, sizeof (vall),
3315 			    WL_RID_HSCAN_REQUEST, vall);
3316 			pcwl_delay(pcwl_p, 1000000);
3317 			if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
3318 				break;
3319 		}
3320 		PCWLDBG((CE_NOTE, "PRISM chip\n"));
3321 		break;
3322 
3323 	case PCWL_CHIP_LUCENT:
3324 		PCWLDBG((CE_NOTE, "LUCENT chip\n"));
3325 	default:
3326 		for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
3327 			if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INQUIRE,
3328 			    WL_INFO_SCAN_RESULTS)) {
3329 				ret = (int)WL_HW_ERROR;
3330 				goto done;
3331 			}
3332 			pcwl_delay(pcwl_p, 500000);
3333 			if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
3334 				break;
3335 		}
3336 		break;
3337 	}
3338 	if ((pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) ||
3339 	    ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0))) {
3340 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
3341 			ret = (int)WL_HW_ERROR;
3342 			goto done;
3343 		}
3344 		if (ret = pcwl_config_rf(pcwl_p)) {
3345 			ret = (int)WL_HW_ERROR;
3346 			goto done;
3347 		}
3348 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
3349 			ret = (int)WL_HW_ERROR;
3350 			goto done;
3351 		}
3352 
3353 		pcwl_delay(pcwl_p, 1000000);
3354 	}
3355 
3356 	if ((!enable) && (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
3357 		ret = (int)WL_HW_ERROR;
3358 	}
3359 done:
3360 	if (ret)
3361 		cmn_err(CE_WARN, "pcwl: scan failed due to hardware error");
3362 	return (ret);
3363 
3364 }
3365 
3366 /*ARGSUSED*/
3367 static int
pcwl_cfg_scan(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3368 pcwl_cfg_scan(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3369 {
3370 	wldp_t 		*outfp;
3371 	char 		*buf;
3372 	uint16_t 	i;
3373 
3374 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3375 	if (buf == NULL) {
3376 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3377 		    MAX_BUF_LEN));
3378 		return (ENOMEM);
3379 	}
3380 	outfp = (wldp_t *)buf;
3381 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3382 
3383 	pcwl_get_esslist(pcwl_p, outfp->wldp_buf);
3384 
3385 	outfp->wldp_length = WIFI_BUF_OFFSET +
3386 	    offsetof(wl_ess_list_t, wl_ess_list_ess) +
3387 	    pcwl_p->pcwl_scan_num * sizeof (wl_ess_conf_t);
3388 	outfp->wldp_result = WL_SUCCESS;
3389 
3390 	for (i = 0; i < (outfp->wldp_length); i++)
3391 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3392 	kmem_free(buf, MAX_BUF_LEN);
3393 	return (WL_SUCCESS);
3394 
3395 }
3396 
3397 /*ARGSUSED*/
3398 static int
pcwl_cfg_linkstatus(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3399 pcwl_cfg_linkstatus(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3400 {
3401 	wldp_t 		*outfp;
3402 	char 		*buf;
3403 	uint16_t 	i, val;
3404 	int 		iret;
3405 	int 		err = 0;
3406 
3407 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3408 	if (buf == NULL) {
3409 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3410 		    MAX_BUF_LEN));
3411 		return (ENOMEM);
3412 	}
3413 	outfp = (wldp_t *)buf;
3414 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3415 
3416 	err = pcwl_get_linkstatus(pcwl_p, outfp->wldp_buf);
3417 	if (err == EIO) {
3418 		outfp->wldp_length = WIFI_BUF_OFFSET;
3419 		outfp->wldp_result = WL_HW_ERROR;
3420 		goto done;
3421 	}
3422 
3423 	(void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
3424 	if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
3425 		outfp->wldp_length = WIFI_BUF_OFFSET +
3426 		    sizeof (wl_linkstatus_t);
3427 	} else if (val == WL_PORT_TO_IBSS ||
3428 	    val == WL_PORT_TO_BSS ||
3429 	    val == WL_PORT_OOR) {
3430 		outfp->wldp_length = WIFI_BUF_OFFSET +
3431 		    sizeof (wl_linkstatus_t);
3432 	} else {
3433 		outfp->wldp_length = WIFI_BUF_OFFSET;
3434 	}
3435 
3436 	outfp->wldp_result = WL_SUCCESS;
3437 done:
3438 	for (i = 0; i < (outfp->wldp_length); i++)
3439 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3440 	iret = (int)(outfp->wldp_result);
3441 	kmem_free(buf, MAX_BUF_LEN);
3442 	return (iret);
3443 }
3444 
3445 static int
pcwl_cfg_bsstype(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3446 pcwl_cfg_bsstype(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3447 {
3448 	uint16_t 	i;
3449 	wldp_t		*infp;
3450 	wldp_t 		*outfp;
3451 	char 		*buf;
3452 	int 		iret;
3453 	int		err = 0;
3454 
3455 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3456 	if (buf == NULL) {
3457 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3458 		    MAX_BUF_LEN));
3459 		return (ENOMEM);
3460 	}
3461 	outfp = (wldp_t *)buf;
3462 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3463 	infp = (wldp_t *)mp->b_rptr;
3464 
3465 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t);
3466 	if (cmd == WLAN_GET_PARAM) {
3467 		pcwl_get_bsstype(pcwl_p, outfp->wldp_buf);
3468 		outfp->wldp_result = WL_SUCCESS;
3469 	} else if (cmd == WLAN_SET_PARAM) {
3470 		err = pcwl_set_bsstype(pcwl_p, infp->wldp_buf);
3471 		if (err == ENOTSUP) {
3472 			outfp->wldp_length = WIFI_BUF_OFFSET;
3473 			outfp->wldp_result = WL_NOTSUPPORTED;
3474 			goto done;
3475 		}
3476 		outfp->wldp_result = WL_SUCCESS;
3477 	} else {
3478 		kmem_free(buf, MAX_BUF_LEN);
3479 		return (EINVAL);
3480 	}
3481 done:
3482 	for (i = 0; i < (outfp->wldp_length); i++)
3483 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3484 	iret = (int)(outfp->wldp_result);
3485 	kmem_free(buf, MAX_BUF_LEN);
3486 	return (iret);
3487 }
3488 
3489 static int
pcwl_cfg_phy(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3490 pcwl_cfg_phy(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3491 {
3492 	uint16_t 	i;
3493 	wldp_t		*infp;
3494 	wldp_t 		*outfp;
3495 	char 		*buf;
3496 	int 		iret;
3497 	int 		err = 0;
3498 
3499 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3500 	if (buf == NULL) {
3501 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3502 		    MAX_BUF_LEN));
3503 		return (ENOMEM);
3504 	}
3505 	outfp = (wldp_t *)buf;
3506 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3507 	infp = (wldp_t *)mp->b_rptr;
3508 
3509 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
3510 	if (cmd == WLAN_GET_PARAM) {
3511 		err = pcwl_get_phy(pcwl_p, outfp->wldp_buf);
3512 		if (err == EIO) {
3513 			outfp->wldp_length = WIFI_BUF_OFFSET;
3514 			outfp->wldp_result = WL_HW_ERROR;
3515 			goto done;
3516 		}
3517 		outfp->wldp_result = WL_SUCCESS;
3518 	} else if (cmd == WLAN_SET_PARAM) {
3519 		err = pcwl_set_phy(pcwl_p, infp->wldp_buf);
3520 		if (err == ENOTSUP) {
3521 			outfp->wldp_length = WIFI_BUF_OFFSET;
3522 			outfp->wldp_result = WL_NOTSUPPORTED;
3523 			goto done;
3524 		}
3525 		outfp->wldp_result = WL_SUCCESS;
3526 	} else {
3527 		kmem_free(buf, MAX_BUF_LEN);
3528 		return (EINVAL);
3529 	}
3530 done:
3531 	for (i = 0; i < (outfp->wldp_length); i++)
3532 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3533 	iret = (int)(outfp->wldp_result);
3534 	kmem_free(buf, MAX_BUF_LEN);
3535 	return (iret);
3536 
3537 }
3538 
3539 static int
pcwl_cfg_desiredrates(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3540 pcwl_cfg_desiredrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3541 {
3542 	uint16_t 	rate;
3543 	uint16_t 	i;
3544 	wldp_t		*infp;
3545 	wldp_t 		*outfp;
3546 	char 		*buf;
3547 	int 		iret;
3548 	int 		err = 0;
3549 
3550 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3551 	if (buf == NULL) {
3552 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3553 		    MAX_BUF_LEN));
3554 		return (ENOMEM);
3555 	}
3556 	outfp = (wldp_t *)buf;
3557 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3558 	infp = (wldp_t *)mp->b_rptr;
3559 
3560 	if (cmd == WLAN_GET_PARAM) {
3561 		err = pcwl_get_desrates(pcwl_p, outfp->wldp_buf);
3562 		if (err == EIO || err == EINVAL) {
3563 			outfp->wldp_length = WIFI_BUF_OFFSET;
3564 			outfp->wldp_result = WL_NOTSUPPORTED;
3565 			goto done;
3566 		}
3567 		if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
3568 			outfp->wldp_length = WIFI_BUF_OFFSET +
3569 			    offsetof(wl_rates_t, wl_rates_rates) +
3570 			    1 * sizeof (char);
3571 		} else {
3572 			(void) pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate);
3573 			switch (rate) {
3574 			case WL_L_TX_RATE_FIX_1M:
3575 				outfp->wldp_length = WIFI_BUF_OFFSET +
3576 				    offsetof(wl_rates_t, wl_rates_rates) +
3577 				    1 * sizeof (char);
3578 				break;
3579 			case WL_L_TX_RATE_FIX_2M:
3580 				outfp->wldp_length = WIFI_BUF_OFFSET +
3581 				    offsetof(wl_rates_t, wl_rates_rates) +
3582 				    1 * sizeof (char);
3583 				break;
3584 			case WL_L_TX_RATE_AUTO_H:
3585 				outfp->wldp_length = WIFI_BUF_OFFSET +
3586 				    offsetof(wl_rates_t, wl_rates_rates) +
3587 				    4 * sizeof (char);
3588 				break;
3589 			case WL_L_TX_RATE_FIX_5M:
3590 				outfp->wldp_length = WIFI_BUF_OFFSET +
3591 				    offsetof(wl_rates_t, wl_rates_rates) +
3592 				    1 * sizeof (char);
3593 				break;
3594 			case WL_L_TX_RATE_FIX_11M:
3595 				outfp->wldp_length = WIFI_BUF_OFFSET +
3596 				    offsetof(wl_rates_t, wl_rates_rates) +
3597 				    1 * sizeof (char);
3598 				break;
3599 			case WL_L_TX_RATE_AUTO_L:
3600 				outfp->wldp_length = WIFI_BUF_OFFSET +
3601 				    offsetof(wl_rates_t, wl_rates_rates) +
3602 				    2 * sizeof (char);
3603 				break;
3604 			case WL_L_TX_RATE_AUTO_M:
3605 				outfp->wldp_length = WIFI_BUF_OFFSET +
3606 				    offsetof(wl_rates_t, wl_rates_rates) +
3607 				    3 * sizeof (char);
3608 				break;
3609 			default:
3610 				break;
3611 			}
3612 		}
3613 		outfp->wldp_result = WL_SUCCESS;
3614 	} else if (cmd == WLAN_SET_PARAM) {
3615 		err = pcwl_set_desrates(pcwl_p, infp->wldp_buf);
3616 		if (err == EINVAL) {
3617 			outfp->wldp_length = WIFI_BUF_OFFSET;
3618 			outfp->wldp_result = WL_NOTSUPPORTED;
3619 			goto done;
3620 		}
3621 		if (err == ENOTSUP) {
3622 			outfp->wldp_length = WIFI_BUF_OFFSET;
3623 			outfp->wldp_result = WL_LACK_FEATURE;
3624 			goto done;
3625 		}
3626 
3627 		outfp->wldp_length = WIFI_BUF_OFFSET;
3628 		outfp->wldp_result = WL_SUCCESS;
3629 	} else {
3630 		kmem_free(buf, MAX_BUF_LEN);
3631 		return (EINVAL);
3632 	}
3633 done:
3634 	for (i = 0; i < (outfp->wldp_length); i++)
3635 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3636 	iret = (int)(outfp->wldp_result);
3637 	kmem_free(buf, MAX_BUF_LEN);
3638 	return (iret);
3639 }
3640 
3641 /*ARGSUSED*/
3642 static int
pcwl_cfg_supportrates(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3643 pcwl_cfg_supportrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3644 {
3645 	uint16_t i;
3646 	wldp_t *outfp;
3647 	char *buf;
3648 
3649 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3650 	if (buf == NULL) {
3651 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3652 		    MAX_BUF_LEN));
3653 		return (ENOMEM);
3654 	}
3655 	outfp = (wldp_t *)buf;
3656 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3657 
3658 	if (cmd == WLAN_GET_PARAM) {
3659 		pcwl_get_suprates(outfp->wldp_buf);
3660 		outfp->wldp_length = WIFI_BUF_OFFSET +
3661 		    offsetof(wl_rates_t, wl_rates_rates) +
3662 		    4 * sizeof (char);
3663 		outfp->wldp_result = WL_SUCCESS;
3664 		for (i = 0; i < (outfp->wldp_length); i++)
3665 			(void) mi_mpprintf_putc((char *)mp, buf[i]);
3666 		kmem_free(buf, MAX_BUF_LEN);
3667 		return (WL_SUCCESS);
3668 	} else {
3669 		kmem_free(buf, MAX_BUF_LEN);
3670 		return (EINVAL);
3671 	}
3672 }
3673 
3674 static int
pcwl_cfg_powermode(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3675 pcwl_cfg_powermode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3676 {
3677 	uint16_t 	i;
3678 	wldp_t		*infp;
3679 	wldp_t 		*outfp;
3680 	char 		*buf;
3681 	int 		iret;
3682 	int 		err = 0;
3683 
3684 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3685 	if (buf == NULL) {
3686 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3687 		    MAX_BUF_LEN));
3688 		return (ENOMEM);
3689 	}
3690 	outfp = (wldp_t *)buf;
3691 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3692 	infp = (wldp_t *)mp->b_rptr;
3693 
3694 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_ps_mode_t);
3695 	if (cmd == WLAN_GET_PARAM) {
3696 		pcwl_get_powermode(pcwl_p, outfp->wldp_buf);
3697 		outfp->wldp_result = WL_SUCCESS;
3698 	} else if (cmd == WLAN_SET_PARAM) {
3699 		err = pcwl_set_powermode(pcwl_p, infp->wldp_buf);
3700 		if (err == ENOTSUP) {
3701 			outfp->wldp_length = WIFI_BUF_OFFSET;
3702 			outfp->wldp_result = WL_NOTSUPPORTED;
3703 			goto done;
3704 		}
3705 		outfp->wldp_result = WL_SUCCESS;
3706 	} else {
3707 		kmem_free(buf, MAX_BUF_LEN);
3708 		return (EINVAL);
3709 	}
3710 done:
3711 	for (i = 0; i < (outfp->wldp_length); i++)
3712 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3713 	iret = (int)(outfp->wldp_result);
3714 	kmem_free(buf, MAX_BUF_LEN);
3715 	return (iret);
3716 
3717 }
3718 
3719 static int
pcwl_cfg_authmode(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3720 pcwl_cfg_authmode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3721 {
3722 	uint16_t 	i;
3723 	wldp_t		*infp;
3724 	wldp_t 		*outfp;
3725 	char 		*buf;
3726 	int 		iret;
3727 	int 		err = 0;
3728 
3729 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3730 	if (buf == NULL) {
3731 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3732 		    MAX_BUF_LEN));
3733 		return (ENOMEM);
3734 	}
3735 	outfp = (wldp_t *)buf;
3736 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3737 	infp = (wldp_t *)mp->b_rptr;
3738 
3739 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t);
3740 	if (cmd == WLAN_GET_PARAM) {
3741 		pcwl_get_authmode(pcwl_p, outfp->wldp_buf);
3742 		outfp->wldp_result = WL_SUCCESS;
3743 	} else if (cmd == WLAN_SET_PARAM) {
3744 		err = pcwl_set_authmode(pcwl_p, infp->wldp_buf);
3745 		if (err == ENOTSUP) {
3746 			outfp->wldp_length = WIFI_BUF_OFFSET;
3747 			outfp->wldp_result = WL_NOTSUPPORTED;
3748 			goto done;
3749 		}
3750 		outfp->wldp_result = WL_SUCCESS;
3751 	} else {
3752 		kmem_free(buf, MAX_BUF_LEN);
3753 		return (EINVAL);
3754 	}
3755 done:
3756 	for (i = 0; i < (outfp->wldp_length); i++)
3757 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3758 	iret = (int)(outfp->wldp_result);
3759 	kmem_free(buf, MAX_BUF_LEN);
3760 	return (iret);
3761 }
3762 
3763 static int
pcwl_cfg_encryption(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3764 pcwl_cfg_encryption(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3765 {
3766 	uint16_t 	i;
3767 	wldp_t		*infp;
3768 	wldp_t 		*outfp;
3769 	char 		*buf;
3770 	int 		iret;
3771 	int 		err = 0;
3772 
3773 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3774 	if (buf == NULL) {
3775 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3776 		    MAX_BUF_LEN));
3777 		return (ENOMEM);
3778 	}
3779 	outfp = (wldp_t *)buf;
3780 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3781 	infp = (wldp_t *)mp->b_rptr;
3782 
3783 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
3784 	if (cmd == WLAN_GET_PARAM) {
3785 		pcwl_get_encrypt(pcwl_p, outfp->wldp_buf);
3786 		outfp->wldp_result = WL_SUCCESS;
3787 	} else if (cmd == WLAN_SET_PARAM) {
3788 		err = pcwl_set_encrypt(pcwl_p, infp->wldp_buf);
3789 		if (err == ENOTSUP) {
3790 			outfp->wldp_length = WIFI_BUF_OFFSET;
3791 			outfp->wldp_result = WL_NOTSUPPORTED;
3792 			goto done;
3793 		}
3794 		outfp->wldp_result = WL_SUCCESS;
3795 	} else {
3796 		kmem_free(buf, MAX_BUF_LEN);
3797 		return (EINVAL);
3798 	}
3799 done:
3800 	for (i = 0; i < (outfp->wldp_length); i++)
3801 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3802 	iret = (int)(outfp->wldp_result);
3803 	kmem_free(buf, MAX_BUF_LEN);
3804 	return (iret);
3805 }
3806 
3807 static int
pcwl_cfg_wepkeyid(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3808 pcwl_cfg_wepkeyid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3809 {
3810 	uint16_t i, ret;
3811 	pcwl_rf_t *rf_p;
3812 	wldp_t	*infp;
3813 	wldp_t *outfp;
3814 	char *buf;
3815 	int iret;
3816 
3817 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3818 	if (buf == NULL) {
3819 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3820 		    MAX_BUF_LEN));
3821 		return (ENOMEM);
3822 	}
3823 	outfp = (wldp_t *)buf;
3824 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3825 	infp = (wldp_t *)mp->b_rptr;
3826 	rf_p = &pcwl_p->pcwl_rf;
3827 
3828 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
3829 	if (cmd == WLAN_GET_PARAM) {
3830 		*(wl_wep_key_id_t *)(outfp->wldp_buf) = rf_p->rf_tx_crypt_key;
3831 		outfp->wldp_result = WL_SUCCESS;
3832 	} else if (cmd == WLAN_SET_PARAM) {
3833 		ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
3834 		if (ret >= MAX_NWEPKEYS) {
3835 			outfp->wldp_length = WIFI_BUF_OFFSET;
3836 			outfp->wldp_result = WL_NOTSUPPORTED;
3837 			goto done;
3838 		}
3839 		rf_p->rf_tx_crypt_key = ret;
3840 		outfp->wldp_result = WL_SUCCESS;
3841 	} else {
3842 		kmem_free(buf, MAX_BUF_LEN);
3843 		return (EINVAL);
3844 	}
3845 done:
3846 	for (i = 0; i < (outfp->wldp_length); i++)
3847 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3848 	iret = (int)(outfp->wldp_result);
3849 	kmem_free(buf, MAX_BUF_LEN);
3850 	return (iret);
3851 }
3852 
3853 static int
pcwl_cfg_createibss(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3854 pcwl_cfg_createibss(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3855 {
3856 	uint16_t 	i;
3857 	wldp_t		*infp;
3858 	wldp_t 		*outfp;
3859 	char 		*buf;
3860 	int 		iret;
3861 	int 		err = 0;
3862 
3863 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3864 	if (buf == NULL) {
3865 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3866 		    MAX_BUF_LEN));
3867 		return (ENOMEM);
3868 	}
3869 	outfp = (wldp_t *)buf;
3870 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3871 	infp = (wldp_t *)mp->b_rptr;
3872 
3873 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
3874 	if (cmd == WLAN_GET_PARAM) {
3875 		pcwl_get_ibss(pcwl_p, outfp->wldp_buf);
3876 		outfp->wldp_result = WL_SUCCESS;
3877 	} else if (cmd == WLAN_SET_PARAM) {
3878 		err = pcwl_set_ibss(pcwl_p, infp->wldp_buf);
3879 		if (err == ENOTSUP) {
3880 			outfp->wldp_length = WIFI_BUF_OFFSET;
3881 			outfp->wldp_result = WL_NOTSUPPORTED;
3882 			goto done;
3883 		}
3884 		outfp->wldp_result = WL_SUCCESS;
3885 	} else {
3886 		kmem_free(buf, MAX_BUF_LEN);
3887 		return (EINVAL);
3888 	}
3889 done:
3890 	for (i = 0; i < (outfp->wldp_length); i++)
3891 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3892 	iret = (int)(outfp->wldp_result);
3893 	kmem_free(buf, MAX_BUF_LEN);
3894 	return (iret);
3895 }
3896 
3897 static int
pcwl_cfg_rssi(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3898 pcwl_cfg_rssi(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3899 {
3900 	uint16_t i;
3901 	int iret;
3902 	wldp_t *outfp;
3903 	char *buf;
3904 
3905 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3906 	if (buf == NULL) {
3907 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3908 		    MAX_BUF_LEN));
3909 		return (ENOMEM);
3910 	}
3911 	outfp = (wldp_t *)buf;
3912 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3913 
3914 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
3915 
3916 	if (cmd == WLAN_GET_PARAM) {
3917 		pcwl_get_param_rssi(pcwl_p, outfp->wldp_buf);
3918 		outfp->wldp_result = WL_SUCCESS;
3919 	} else if (cmd == WLAN_SET_PARAM) {
3920 		outfp->wldp_result = WL_READONLY;
3921 	} else {
3922 		kmem_free(buf, MAX_BUF_LEN);
3923 		return (EINVAL);
3924 	}
3925 done:
3926 	for (i = 0; i < (outfp->wldp_length); i++)
3927 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3928 	iret = (int)(outfp->wldp_result);
3929 	kmem_free(buf, MAX_BUF_LEN);
3930 	return (iret);
3931 }
3932 
3933 /*ARGSUSED*/
3934 static int
pcwl_cfg_radio(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3935 pcwl_cfg_radio(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3936 {
3937 	uint16_t i;
3938 	int iret;
3939 	wldp_t *outfp;
3940 	char *buf;
3941 
3942 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3943 	if (buf == NULL) {
3944 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3945 		    MAX_BUF_LEN));
3946 		return (ENOMEM);
3947 	}
3948 	outfp = (wldp_t *)buf;
3949 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3950 
3951 	if (cmd == WLAN_GET_PARAM) {
3952 		*(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
3953 		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
3954 		outfp->wldp_result = WL_SUCCESS;
3955 	} else if (cmd == WLAN_SET_PARAM) {
3956 		outfp->wldp_length = WIFI_BUF_OFFSET;
3957 		outfp->wldp_result = WL_LACK_FEATURE;
3958 	} else {
3959 		kmem_free(buf, MAX_BUF_LEN);
3960 		return (EINVAL);
3961 	}
3962 	for (i = 0; i < (outfp->wldp_length); i++)
3963 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
3964 	iret = (int)(outfp->wldp_result);
3965 	kmem_free(buf, MAX_BUF_LEN);
3966 	return (iret);
3967 }
3968 
3969 static int
pcwl_cfg_wepkey(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)3970 pcwl_cfg_wepkey(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
3971 {
3972 	uint16_t 	i;
3973 	wldp_t		*infp;
3974 	wldp_t 		*outfp;
3975 	char 		*buf;
3976 	int 		iret;
3977 
3978 	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3979 	if (buf == NULL) {
3980 		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
3981 		    MAX_BUF_LEN));
3982 		return (ENOMEM);
3983 	}
3984 	outfp = (wldp_t *)buf;
3985 	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
3986 	infp = (wldp_t *)mp->b_rptr;
3987 
3988 	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_tab_t);
3989 	if (cmd == WLAN_GET_PARAM) {
3990 		outfp->wldp_result = WL_WRITEONLY;
3991 	} else if (cmd == WLAN_SET_PARAM) {
3992 		(void) pcwl_set_wepkey(pcwl_p, infp->wldp_buf);
3993 		outfp->wldp_result = WL_SUCCESS;
3994 	} else {
3995 		kmem_free(buf, MAX_BUF_LEN);
3996 		return (EINVAL);
3997 	}
3998 done:
3999 	for (i = 0; i < (outfp->wldp_length); i++)
4000 		(void) mi_mpprintf_putc((char *)mp, buf[i]);
4001 	iret = (int)(outfp->wldp_result);
4002 	kmem_free(buf, MAX_BUF_LEN);
4003 	return (iret);
4004 }
4005 
4006 static void
pcwl_connect_timeout(void * arg)4007 pcwl_connect_timeout(void *arg)
4008 {
4009 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
4010 	uint16_t ret = 0;
4011 
4012 	mutex_enter(&pcwl_p->pcwl_glock);
4013 	PCWL_DISABLE_INTR(pcwl_p);
4014 	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4015 		goto done;
4016 	}
4017 	if (ret = pcwl_config_rf(pcwl_p)) {
4018 		goto done;
4019 	}
4020 	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4021 		goto done;
4022 	}
4023 	PCWL_ENABLE_INTR(pcwl_p);
4024 done:
4025 	if (ret)
4026 		cmn_err(CE_WARN, "pcwl: connect failed due to hardware error");
4027 	mutex_exit(&pcwl_p->pcwl_glock);
4028 	pcwl_p->pcwl_connect_timeout_id = 0;
4029 }
4030 
4031 static int
pcwl_getset(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)4032 pcwl_getset(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
4033 {
4034 	int ret = WL_SUCCESS;
4035 	int connect = 0;
4036 
4037 	mutex_enter(&pcwl_p->pcwl_glock);
4038 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
4039 		mutex_exit(&pcwl_p->pcwl_glock);
4040 		return (PCWL_FAIL);
4041 	}
4042 	switch (((wldp_t *)mp->b_rptr)->wldp_id) {
4043 	case WL_ESSID:
4044 		ret = pcwl_cfg_essid(mp, pcwl_p, cmd);
4045 		connect = 1;
4046 		PCWLDBG((CE_NOTE, "cfg_essid\n"));
4047 		break;
4048 	case WL_BSSID:
4049 		ret = pcwl_cfg_bssid(mp, pcwl_p, cmd);
4050 		connect = 1;
4051 		PCWLDBG((CE_NOTE, "cfg_bssid\n"));
4052 		break;
4053 	case WL_ESS_LIST:
4054 		ret = pcwl_cfg_scan(mp, pcwl_p, cmd);
4055 		PCWLDBG((CE_NOTE, "cfg_scan\n"));
4056 		break;
4057 	case WL_LINKSTATUS:
4058 		ret = pcwl_cfg_linkstatus(mp, pcwl_p, cmd);
4059 		PCWLDBG((CE_NOTE, "cfg_linkstatus\n"));
4060 		break;
4061 	case WL_BSS_TYPE:
4062 		ret = pcwl_cfg_bsstype(mp, pcwl_p, cmd);
4063 		connect = 1;
4064 		PCWLDBG((CE_NOTE, "cfg_bsstype\n"));
4065 		break;
4066 	case WL_PHY_CONFIG:
4067 		ret = pcwl_cfg_phy(mp, pcwl_p, cmd);
4068 		connect = 1;
4069 		PCWLDBG((CE_NOTE, "cfg_phy\n"));
4070 		break;
4071 	case WL_DESIRED_RATES:
4072 		ret = pcwl_cfg_desiredrates(mp, pcwl_p, cmd);
4073 		connect = 1;
4074 		PCWLDBG((CE_NOTE, "cfg_disred-rates\n"));
4075 		break;
4076 	case WL_SUPPORTED_RATES:
4077 		ret = pcwl_cfg_supportrates(mp, pcwl_p, cmd);
4078 		PCWLDBG((CE_NOTE, "cfg_supported-rates\n"));
4079 		break;
4080 	case WL_POWER_MODE:
4081 		ret = pcwl_cfg_powermode(mp, pcwl_p, cmd);
4082 		PCWLDBG((CE_NOTE, "cfg_powermode\n"));
4083 		break;
4084 	case WL_AUTH_MODE:
4085 		ret = pcwl_cfg_authmode(mp, pcwl_p, cmd);
4086 		connect = 1;
4087 		PCWLDBG((CE_NOTE, "cfg_authmode\n"));
4088 		break;
4089 	case WL_ENCRYPTION:
4090 		ret = pcwl_cfg_encryption(mp, pcwl_p, cmd);
4091 		connect = 1;
4092 		PCWLDBG((CE_NOTE, "cfg_encryption\n"));
4093 		break;
4094 	case WL_WEP_KEY_ID:
4095 		ret = pcwl_cfg_wepkeyid(mp, pcwl_p, cmd);
4096 		connect = 1;
4097 		PCWLDBG((CE_NOTE, "cfg_wepkeyid\n"));
4098 		break;
4099 	case WL_CREATE_IBSS:
4100 		ret = pcwl_cfg_createibss(mp, pcwl_p, cmd);
4101 		connect = 1;
4102 		PCWLDBG((CE_NOTE, "cfg_create-ibss\n"));
4103 		break;
4104 	case WL_RSSI:
4105 		ret = pcwl_cfg_rssi(mp, pcwl_p, cmd);
4106 		PCWLDBG((CE_NOTE, "cfg_rssi\n"));
4107 		break;
4108 	case WL_RADIO:
4109 		ret = pcwl_cfg_radio(mp, pcwl_p, cmd);
4110 		PCWLDBG((CE_NOTE, "cfg_radio\n"));
4111 		break;
4112 	case WL_WEP_KEY_TAB:
4113 		ret = pcwl_cfg_wepkey(mp, pcwl_p, cmd);
4114 		connect = 1;
4115 		PCWLDBG((CE_NOTE, "cfg_wepkey\n"));
4116 		break;
4117 	case WL_SCAN:
4118 		mutex_exit(&pcwl_p->pcwl_glock);
4119 		if (pcwl_p->pcwl_connect_timeout_id != 0) {
4120 			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4121 			pcwl_p->pcwl_connect_timeout_id = 0;
4122 		}
4123 		mutex_enter(&pcwl_p->pcwl_glock);
4124 		ret = pcwl_cmd_scan(pcwl_p);
4125 		break;
4126 	case WL_LOAD_DEFAULTS:
4127 		mutex_exit(&pcwl_p->pcwl_glock);
4128 		if (pcwl_p->pcwl_connect_timeout_id != 0) {
4129 			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4130 			pcwl_p->pcwl_connect_timeout_id = 0;
4131 		}
4132 		mutex_enter(&pcwl_p->pcwl_glock);
4133 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4134 			ret = (int)WL_HW_ERROR;
4135 			break;
4136 		}
4137 		if (ret = pcwl_loaddef_rf(pcwl_p)) {
4138 			ret = (int)WL_HW_ERROR;
4139 			PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
4140 			break;
4141 		}
4142 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4143 			ret = (int)WL_HW_ERROR;
4144 			break;
4145 		}
4146 		pcwl_delay(pcwl_p, 1000000);
4147 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4148 			ret = (int)WL_HW_ERROR;
4149 			break;
4150 		}
4151 		PCWLDBG((CE_NOTE, "loaddef\n"));
4152 		break;
4153 	case WL_DISASSOCIATE:
4154 		mutex_exit(&pcwl_p->pcwl_glock);
4155 		if (pcwl_p->pcwl_connect_timeout_id != 0) {
4156 			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4157 			pcwl_p->pcwl_connect_timeout_id = 0;
4158 		}
4159 
4160 		mutex_enter(&pcwl_p->pcwl_glock);
4161 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4162 			ret = (int)WL_HW_ERROR;
4163 			break;
4164 		}
4165 		/*
4166 		 * A workaround here: If the card is in ad-hoc mode, the
4167 		 * following scan will not work correctly, so any
4168 		 * 'dladm connect-wifi' which need a scan first will not
4169 		 * succeed. software reset the card here as a workround.
4170 		 */
4171 		if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
4172 		    (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
4173 			if (ret = pcwl_reset_backend(pcwl_p)) {
4174 				ret = (int)WL_HW_ERROR;
4175 				break;
4176 			}
4177 			if (ret = pcwl_init_nicmem(pcwl_p)) {
4178 				ret = (int)WL_HW_ERROR;
4179 				break;
4180 			}
4181 			pcwl_start_locked(pcwl_p);
4182 		}
4183 		if (ret = pcwl_loaddef_rf(pcwl_p)) {
4184 			ret = (int)WL_HW_ERROR;
4185 			PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
4186 			break;
4187 		}
4188 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4189 			ret = (int)WL_HW_ERROR;
4190 			break;
4191 		}
4192 		pcwl_delay(pcwl_p, 1000000);
4193 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4194 			ret = (int)WL_HW_ERROR;
4195 			break;
4196 		}
4197 		PCWLDBG((CE_NOTE, "disassociate\n"));
4198 		break;
4199 	case WL_REASSOCIATE:
4200 	case WL_ASSOCIAT:
4201 		mutex_exit(&pcwl_p->pcwl_glock);
4202 		if (pcwl_p->pcwl_connect_timeout_id != 0) {
4203 			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4204 			pcwl_p->pcwl_connect_timeout_id = 0;
4205 		}
4206 		mutex_enter(&pcwl_p->pcwl_glock);
4207 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
4208 			ret = (int)WL_HW_ERROR;
4209 			break;
4210 		}
4211 		if (ret = pcwl_config_rf(pcwl_p)) {
4212 			ret = (int)WL_HW_ERROR;
4213 			break;
4214 		}
4215 		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
4216 			ret = (int)WL_HW_ERROR;
4217 			break;
4218 		}
4219 		PCWLDBG((CE_NOTE, "associate"));
4220 		break;
4221 	default:
4222 		break;
4223 	}
4224 	mutex_exit(&pcwl_p->pcwl_glock);
4225 	if ((cmd == WLAN_SET_PARAM) && (connect)) {
4226 		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
4227 		if (pcwl_p->pcwl_connect_timeout_id != 0) {
4228 			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4229 			pcwl_p->pcwl_connect_timeout_id = 0;
4230 		}
4231 		pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
4232 		    pcwl_p, 2 * drv_usectohz(1000000));
4233 	}
4234 	return (ret);
4235 }
4236 
4237 static void
pcwl_wlan_ioctl(pcwl_maci_t * pcwl_p,queue_t * wq,mblk_t * mp,uint32_t cmd)4238 pcwl_wlan_ioctl(pcwl_maci_t *pcwl_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
4239 {
4240 
4241 	struct	iocblk	*iocp = (struct iocblk *)mp->b_rptr;
4242 	wldp_t 	*infp;
4243 	uint32_t len, ret;
4244 	mblk_t		*mp1;
4245 
4246 	/*
4247 	 * sanity check
4248 	 */
4249 	if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
4250 		miocnak(wq, mp, 0, EINVAL);
4251 		return;
4252 	}
4253 
4254 	/*
4255 	 * assuming single data block
4256 	 */
4257 	if (mp1->b_cont) {
4258 		freemsg(mp1->b_cont);
4259 		mp1->b_cont = NULL;
4260 	}
4261 
4262 	/*
4263 	 * we will overwrite everything
4264 	 */
4265 	mp1->b_wptr = mp1->b_rptr;
4266 
4267 	infp = (wldp_t *)mp1->b_rptr;
4268 	PCWLDBG((CE_NOTE, "pcwl: wldp->length=0x%x\n", infp->wldp_length));
4269 	PCWLDBG((CE_NOTE, "pcwl: wldp->type =:%s\n",
4270 	    infp->wldp_type == NET_802_11 ? "NET_802_11" : "Unknown"));
4271 	PCWLDBG((CE_NOTE, "pcwl: wldp->id=0x%x\n", infp->wldp_id));
4272 	PCWLDBG((CE_NOTE, "pcwl: wldp->result=0x%x\n", infp->wldp_result));
4273 
4274 	ret = pcwl_getset(mp1, pcwl_p, cmd);
4275 	len = msgdsize(mp1);
4276 	PCWLDBG((CE_CONT, "pcwl: ioctl message length = %d\n", len));
4277 	miocack(wq, mp, len, ret);
4278 
4279 }
4280 
4281 
4282 static void
pcwl_ioctl(void * arg,queue_t * wq,mblk_t * mp)4283 pcwl_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4284 {
4285 	struct iocblk *iocp;
4286 	uint32_t cmd, ret;
4287 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
4288 	boolean_t need_privilege = B_TRUE;
4289 
4290 	/*
4291 	 * Validate the command before bothering with the mutexen ...
4292 	 */
4293 	iocp = (struct iocblk *)mp->b_rptr;
4294 	iocp->ioc_error = 0;
4295 	cmd = iocp->ioc_cmd;
4296 	switch (cmd) {
4297 	default:
4298 		PCWLDBG((CE_CONT, "pcwl_ioctl: unknown cmd 0x%x", cmd));
4299 		miocnak(wq, mp, 0, EINVAL);
4300 		return;
4301 	case WLAN_GET_PARAM:
4302 		need_privilege = B_FALSE;
4303 		break;
4304 	case WLAN_SET_PARAM:
4305 	case WLAN_COMMAND:
4306 		break;
4307 	}
4308 
4309 	if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
4310 		miocnak(wq, mp, 0, ret);
4311 	else
4312 		pcwl_wlan_ioctl(pcwl_p, wq, mp, cmd);
4313 }
4314 
4315 /*
4316  * brussels
4317  */
4318 /* ARGSUSED */
4319 static int
pcwl_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)4320 pcwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4321     uint_t wldp_length, const void *wldp_buf)
4322 {
4323 	int 		err = 0;
4324 	pcwl_maci_t 	*pcwl_p = (pcwl_maci_t *)arg;
4325 
4326 	mutex_enter(&pcwl_p->pcwl_glock);
4327 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
4328 		mutex_exit(&pcwl_p->pcwl_glock);
4329 		err = EINVAL;
4330 		return (err);
4331 	}
4332 
4333 	switch (wldp_pr_num) {
4334 	/* mac_prop_id */
4335 	case MAC_PROP_WL_ESSID:
4336 		err = pcwl_set_essid(pcwl_p, wldp_buf);
4337 		break;
4338 	case MAC_PROP_WL_PHY_CONFIG:
4339 		err = pcwl_set_phy(pcwl_p, wldp_buf);
4340 		break;
4341 	case MAC_PROP_WL_KEY_TAB:
4342 		err = pcwl_set_wepkey(pcwl_p, wldp_buf);
4343 		break;
4344 	case MAC_PROP_WL_AUTH_MODE:
4345 		err = pcwl_set_authmode(pcwl_p, wldp_buf);
4346 		break;
4347 	case MAC_PROP_WL_ENCRYPTION:
4348 		err = pcwl_set_encrypt(pcwl_p, wldp_buf);
4349 		break;
4350 	case MAC_PROP_WL_BSSTYPE:
4351 		err = pcwl_set_bsstype(pcwl_p, wldp_buf);
4352 		break;
4353 	case MAC_PROP_WL_DESIRED_RATES:
4354 		err = pcwl_set_desrates(pcwl_p, wldp_buf);
4355 		break;
4356 	case MAC_PROP_WL_POWER_MODE:
4357 		err = pcwl_set_powermode(pcwl_p, wldp_buf);
4358 		break;
4359 	case MAC_PROP_WL_CREATE_IBSS:
4360 		err = pcwl_set_ibss(pcwl_p, wldp_buf);
4361 		break;
4362 	case MAC_PROP_WL_BSSID:
4363 	case MAC_PROP_WL_RADIO:
4364 	case MAC_PROP_WL_WPA:
4365 	case MAC_PROP_WL_KEY:
4366 	case MAC_PROP_WL_DELKEY:
4367 	case MAC_PROP_WL_SETOPTIE:
4368 	case MAC_PROP_WL_MLME:
4369 	case MAC_PROP_WL_LINKSTATUS:
4370 	case MAC_PROP_WL_ESS_LIST:
4371 	case MAC_PROP_WL_SUPPORTED_RATES:
4372 	case MAC_PROP_WL_RSSI:
4373 	case MAC_PROP_WL_CAPABILITY:
4374 	case MAC_PROP_WL_SCANRESULTS:
4375 		cmn_err(CE_WARN, "pcwl_setprop:"
4376 		    "opmode not support\n");
4377 		err = ENOTSUP;
4378 		break;
4379 	default:
4380 		cmn_err(CE_WARN, "pcwl_setprop:"
4381 		    "opmode err\n");
4382 		err = EINVAL;
4383 		break;
4384 	}
4385 
4386 	mutex_exit(&pcwl_p->pcwl_glock);
4387 
4388 	if (err == ENETRESET) {
4389 		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
4390 		if (pcwl_p->pcwl_connect_timeout_id != 0) {
4391 			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4392 			pcwl_p->pcwl_connect_timeout_id = 0;
4393 		}
4394 		pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
4395 		    pcwl_p, 2 * drv_usectohz(1000000));
4396 
4397 		err = 0;
4398 	}
4399 
4400 	return (err);
4401 } /* ARGSUSED */
4402 
4403 /* ARGSUSED */
4404 static int
pcwl_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)4405 pcwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4406     uint_t wldp_length, void *wldp_buf)
4407 {
4408 	int err = 0;
4409 	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
4410 
4411 	mutex_enter(&pcwl_p->pcwl_glock);
4412 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
4413 		mutex_exit(&pcwl_p->pcwl_glock);
4414 		err = EINVAL;
4415 		return (err);
4416 	}
4417 
4418 	switch (wldp_pr_num) {
4419 	/* mac_prop_id */
4420 	case MAC_PROP_WL_ESSID:
4421 		err = pcwl_get_essid(pcwl_p, wldp_buf);
4422 		break;
4423 	case MAC_PROP_WL_BSSID:
4424 		err = pcwl_get_bssid(pcwl_p, wldp_buf);
4425 		break;
4426 	case MAC_PROP_WL_PHY_CONFIG:
4427 		err = pcwl_get_phy(pcwl_p, wldp_buf);
4428 		break;
4429 	case MAC_PROP_WL_AUTH_MODE:
4430 		pcwl_get_authmode(pcwl_p, wldp_buf);
4431 		break;
4432 	case MAC_PROP_WL_ENCRYPTION:
4433 		pcwl_get_encrypt(pcwl_p, wldp_buf);
4434 		break;
4435 	case MAC_PROP_WL_BSSTYPE:
4436 		pcwl_get_bsstype(pcwl_p, wldp_buf);
4437 		break;
4438 	case MAC_PROP_WL_LINKSTATUS:
4439 		err = pcwl_get_linkstatus(pcwl_p, wldp_buf);
4440 		break;
4441 	case MAC_PROP_WL_ESS_LIST:
4442 		pcwl_get_esslist(pcwl_p, wldp_buf);
4443 		break;
4444 	case MAC_PROP_WL_SUPPORTED_RATES:
4445 		pcwl_get_suprates(wldp_buf);
4446 		break;
4447 	case MAC_PROP_WL_RSSI:
4448 		pcwl_get_param_rssi(pcwl_p, wldp_buf);
4449 		break;
4450 	case MAC_PROP_WL_RADIO:
4451 		pcwl_get_radio(wldp_buf);
4452 		break;
4453 	case MAC_PROP_WL_POWER_MODE:
4454 		pcwl_get_powermode(pcwl_p, wldp_buf);
4455 		break;
4456 	case MAC_PROP_WL_CREATE_IBSS:
4457 		pcwl_get_ibss(pcwl_p, wldp_buf);
4458 		break;
4459 	case MAC_PROP_WL_DESIRED_RATES:
4460 		err = pcwl_get_desrates(pcwl_p, wldp_buf);
4461 		break;
4462 	case MAC_PROP_WL_CAPABILITY:
4463 	case MAC_PROP_WL_WPA:
4464 	case MAC_PROP_WL_SCANRESULTS:
4465 	case MAC_PROP_WL_KEY_TAB:
4466 	case MAC_PROP_WL_KEY:
4467 	case MAC_PROP_WL_DELKEY:
4468 	case MAC_PROP_WL_SETOPTIE:
4469 	case MAC_PROP_WL_MLME:
4470 		cmn_err(CE_WARN, "pcwl_getprop:"
4471 		    "opmode not support\n");
4472 		err = ENOTSUP;
4473 		break;
4474 	default:
4475 		cmn_err(CE_WARN, "pcwl_getprop:"
4476 		    "opmode err\n");
4477 		err = EINVAL;
4478 		break;
4479 	}
4480 
4481 	mutex_exit(&pcwl_p->pcwl_glock);
4482 
4483 	return (err);
4484 }
4485 
4486 
4487 static void
pcwl_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wlpd_pr_num,mac_prop_info_handle_t prh)4488 pcwl_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wlpd_pr_num,
4489     mac_prop_info_handle_t prh)
4490 {
4491         _NOTE(ARGUNUSED(arg, pr_name));
4492 
4493 	switch (wlpd_pr_num) {
4494 	case MAC_PROP_WL_LINKSTATUS:
4495 	case MAC_PROP_WL_ESS_LIST:
4496 	case MAC_PROP_WL_SUPPORTED_RATES:
4497 	case MAC_PROP_WL_RSSI:
4498 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
4499 	}
4500 }
4501 
4502 
4503 /*
4504  * quiesce(9E) entry point.
4505  *
4506  * This function is called when the system is single-threaded at high
4507  * PIL with preemption disabled. Therefore, this function must not be
4508  * blocked.
4509  *
4510  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4511  * DDI_FAILURE indicates an error condition and should almost never happen.
4512  */
4513 #ifndef __sparc
4514 static int
pcwl_quiesce(dev_info_t * dip)4515 pcwl_quiesce(dev_info_t *dip)
4516 {
4517 	pcwl_maci_t *pcwl_p;
4518 
4519 	pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
4520 	if (pcwl_p == NULL)
4521 		return (DDI_FAILURE);
4522 
4523 	if (pcwl_p->pcwl_flag & PCWL_CARD_READY)
4524 		pcwl_stop_locked(pcwl_p);
4525 
4526 	return (DDI_SUCCESS);
4527 }
4528 #endif
4529