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