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
66uint32_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 */
74static 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
81void *pcwl_soft_state_p = NULL;
82static int pcwl_device_type;
83
84static 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);
87static 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);
89static void	pcwl_m_propinfo(void *arg, const char *pr_name,
90    mac_prop_id_t wlpd_pr_num, mac_prop_info_handle_t mph);
91static void
92pcwl_delay(pcwl_maci_t *, clock_t);
93
94mac_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
113static char *pcwl_name_str = "pcwl";
114
115#ifdef	__sparc
116#define	pcwl_quiesce	ddi_quiesce_not_supported
117#else
118static int pcwl_quiesce(dev_info_t *);
119#endif
120
121DDI_DEFINE_STREAM_OPS(pcwl_dev_ops, nulldev, pcwl_probe, pcwl_attach,
122    pcwl_detach, nodev, NULL, D_MP, NULL, pcwl_quiesce);
123
124extern struct mod_ops mod_driverops;
125static struct modldrv modldrv = {
126	&mod_driverops,
127	"Lucent/PRISM-II 802.11b driver",
128	&pcwl_dev_ops
129};
130
131static struct modlinkage modlinkage = {
132	MODREV_1, (void *)&modldrv, NULL
133	};
134
135int
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
156int
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
169int
170_info(struct modinfo *modinfop)
171{
172	return (mod_info(&modlinkage, modinfop));
173}
174
175static int
176pcwl_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
201static int
202pcwl_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);
418attach_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);
424attach_fail5:
425	(void) mac_unregister(pcwl_p->pcwl_mh);
426attach_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	}
432attach_fail3a:
433	pcwl_destroy_locks(pcwl_p);
434attach_fail3:
435	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
436		ddi_regs_map_free(&pcwl_p->pcwl_handle);
437attach_fail2a:
438	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
439		ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
440attach_fail2:
441	ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
442attach_fail1:
443	return (DDI_FAILURE);
444}
445
446static int
447pcwl_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 */
506static int
507pcwl_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);
570regcs_fail:
571	mutex_destroy(&pcwl_p->pcwl_cslock);
572	cv_destroy(&pcwl_p->pcwl_cscv);
573regcs_unreg:
574	(void) csx_DeregisterClient(chdl);
575regcs_ret:
576	pcwl_p->pcwl_flag &= ~PCWL_CS_REGISTERED;
577	return (ret);
578}
579
580static void
581pcwl_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
608static void
609pcwl_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
616static void
617pcwl_do_suspend(pcwl_maci_t *pcwl_p);
618
619static int
620pcwl_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 */
667static void
668pcwl_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
710static int
711pcwl_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);
871un_irq:
872	(void) csx_ReleaseIRQ(chdl, &irq);
873un_io:
874	ddi_remove_softintr(pcwl_p->pcwl_softint_id);
875	(void) csx_ReleaseIO(chdl, &io);
876	pcwl_p->pcwl_port = 0;
877insert_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 */
886static void
887pcwl_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 */
937static int
938pcwl_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
952static void
953pcwl_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
972static int
973pcwl_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	}
995done:
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
1002static int
1003pcwl_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
1113done:
1114	mutex_exit(&pcwl_p->pcwl_glock);
1115	kmem_free(buf, PCWL_NICMEM_SZ);
1116	freemsg(mblk_p);
1117	return (PCWL_SUCCESS);
1118}
1119
1120static mblk_t *
1121pcwl_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
1148static int
1149pcwl_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	}
1170done:
1171	if (ret)
1172		cmn_err(CE_WARN, "pcwl promisc: failed\n");
1173	mutex_exit(&pcwl_p->pcwl_glock);
1174	return (ret);
1175}
1176
1177static int
1178pcwl_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	}
1283done:
1284	mutex_exit(&pcwl_p->pcwl_glock);
1285	return (ret);
1286}
1287
1288static int
1289pcwl_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	}
1337done:
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
1344static uint_t
1345pcwl_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
1411static uint_t
1412pcwl_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 */
1437static void
1438pcwl_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);
1522done:
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
1543static uint32_t
1544pcwl_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
1566static void
1567pcwl_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
1658static uint16_t
1659pcwl_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
1720static uint16_t
1721pcwl_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
1751static uint16_t
1752pcwl_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
1798static uint16_t
1799pcwl_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
1836static uint16_t
1837pcwl_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
1875static uint16_t
1876pcwl_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*/
1891static uint16_t
1892pcwl_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*/
1919static uint16_t
1920pcwl_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
1933static uint16_t
1934pcwl_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
1967static int
1968pcwl_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
1984static void
1985pcwl_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
1992static void
1993pcwl_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
2018static void
2019pcwl_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 */
2045static void
2046pcwl_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 */
2169static void
2170pcwl_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
2179static int
2180pcwl_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 */
2203static int
2204pcwl_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
2235static int
2236pcwl_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
2264static int
2265pcwl_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
2287static int
2288pcwl_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	}
2383done:
2384	return (PCWL_SUCCESS);
2385}
2386
2387static void
2388pcwl_start_locked(pcwl_maci_t *pcwl_p)
2389{
2390	pcwl_p->pcwl_flag |= PCWL_CARD_INTREN;
2391	PCWL_ENABLE_INTR(pcwl_p);
2392}
2393
2394static void
2395pcwl_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*/
2406static int
2407pcwl_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
2422static void
2423pcwl_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 */
2455static int
2456pcwl_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
2479static int
2480pcwl_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 */
2533static int
2534pcwl_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 */
2568static int
2569pcwl_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 */
2604static int
2605pcwl_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
2626static void
2627pcwl_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 */
2642static int
2643pcwl_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
2664static int
2665pcwl_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 */
2686static int
2687pcwl_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
2770static int
2771pcwl_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 */
2866static void
2867pcwl_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 */
2881static int
2882pcwl_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
2902static void
2903pcwl_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 */
2914static int
2915pcwl_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
2934static void
2935pcwl_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 */
2946static int
2947pcwl_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
2967static void
2968pcwl_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 */
2979static int
2980pcwl_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
2999static void
3000pcwl_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 */
3011static void
3012pcwl_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 */
3038static int
3039pcwl_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 */
3072static void
3073pcwl_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 */
3083static void
3084pcwl_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
3150static int
3151pcwl_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	}
3209done:
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
3217static int
3218pcwl_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	}
3250done:
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*/
3259static int
3260pcwl_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	}
3359done:
3360	if (ret)
3361		cmn_err(CE_WARN, "pcwl: scan failed due to hardware error");
3362	return (ret);
3363
3364}
3365
3366/*ARGSUSED*/
3367static int
3368pcwl_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*/
3398static int
3399pcwl_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;
3437done:
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
3445static int
3446pcwl_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	}
3481done:
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
3489static int
3490pcwl_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	}
3530done:
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
3539static int
3540pcwl_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	}
3633done:
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*/
3642static int
3643pcwl_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
3674static int
3675pcwl_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	}
3710done:
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
3719static int
3720pcwl_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	}
3755done:
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
3763static int
3764pcwl_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	}
3799done:
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
3807static int
3808pcwl_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	}
3845done:
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
3853static int
3854pcwl_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	}
3889done:
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
3897static int
3898pcwl_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	}
3925done:
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*/
3934static int
3935pcwl_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
3969static int
3970pcwl_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	}
3998done:
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
4006static void
4007pcwl_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);
4024done:
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
4031static int
4032pcwl_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
4237static void
4238pcwl_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
4282static void
4283pcwl_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 */
4319static int
4320pcwl_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 */
4404static int
4405pcwl_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
4487static void
4488pcwl_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
4514static int
4515pcwl_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