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 "pcan.h"
57 #include <sys/mac_wifi.h>
58 #include <inet/wifi_ioctl.h>
59
60 #ifdef DEBUG
61 #define PCAN_DBG_BASIC 0x1
62 #define PCAN_DBG_INFO 0x2
63 #define PCAN_DBG_SEND 0x4
64 #define PCAN_DBG_RCV 0x8
65 #define PCAN_DBG_LINKINFO 0x10
66 #define PCAN_DBG_FW_VERSION 0x20
67 #define PCAN_DBG_CMD 0x40
68 uint32_t pcan_debug = 0;
69 #define PCANDBG(x) \
70 if (pcan_debug & PCAN_DBG_BASIC) cmn_err x
71 #else
72 #define PCANDBG(x)
73 #endif
74
75 static ddi_device_acc_attr_t accattr = {
76 DDI_DEVICE_ATTR_V0,
77 DDI_STRUCTURE_LE_ACC,
78 DDI_STRICTORDER_ACC,
79 };
80
81 static ddi_dma_attr_t control_cmd_dma_attr = {
82 DMA_ATTR_V0, /* version of this structure */
83 0, /* lowest usable address */
84 0xffffffffffffffffull, /* highest usable address */
85 0xffffffffull, /* maximum DMAable byte count */
86 4, /* alignment in bytes */
87 0xfff, /* burst sizes (any) */
88 1, /* minimum transfer */
89 0xffffull, /* maximum transfer */
90 0xffffffffffffffffull, /* maximum segment length */
91 1, /* maximum number of segments */
92 1, /* granularity */
93 0, /* flags (reserved) */
94 };
95
96 void *pcan_soft_state_p = NULL;
97 static int pcan_device_type;
98
99 /*
100 * brussels
101 */
102 static int pcan_m_setprop(void *arg, const char *pr_name,
103 mac_prop_id_t wldp_pr_num, uint_t wldp_length,
104 const void *wldp_buf);
105 static int pcan_m_getprop(void *arg, const char *pr_name,
106 mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
107 static void pcan_m_propinfo(void *arg, const char *pr_name,
108 mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph);
109
110 mac_callbacks_t pcan_m_callbacks = {
111 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
112 pcan_gstat,
113 pcan_start,
114 pcan_stop,
115 pcan_prom,
116 pcan_sdmulti,
117 pcan_saddr,
118 pcan_tx,
119 NULL,
120 pcan_ioctl,
121 NULL,
122 NULL,
123 NULL,
124 pcan_m_setprop,
125 pcan_m_getprop,
126 pcan_m_propinfo
127 };
128
129 static char *pcan_name_str = "pcan";
130
131 #ifdef __sparc
132 #define pcan_quiesce ddi_quiesce_not_supported
133 #else
134 static int pcan_quiesce(dev_info_t *);
135 #endif
136
137 DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach,
138 pcan_detach, nodev, NULL, D_MP, NULL, pcan_quiesce);
139
140 extern struct mod_ops mod_driverops;
141 static struct modldrv modldrv = {
142 &mod_driverops,
143 "Cisco-Aironet 802.11b driver",
144 &pcan_dev_ops
145 };
146
147 static struct modlinkage modlinkage = {
148 MODREV_1, (void *)&modldrv, NULL
149 };
150
151 int
_init(void)152 _init(void)
153 {
154 int stat;
155
156 /* Allocate soft state */
157 if ((stat = ddi_soft_state_init(&pcan_soft_state_p,
158 sizeof (pcan_maci_t), 2)) != DDI_SUCCESS)
159 return (stat);
160
161 mac_init_ops(&pcan_dev_ops, "pcan");
162 stat = mod_install(&modlinkage);
163 if (stat != 0) {
164 mac_fini_ops(&pcan_dev_ops);
165 ddi_soft_state_fini(&pcan_soft_state_p);
166 }
167
168 return (stat);
169 }
170
171 int
_fini(void)172 _fini(void)
173 {
174 int stat;
175
176 stat = mod_remove(&modlinkage);
177 if (stat != DDI_SUCCESS)
178 return (stat);
179 mac_fini_ops(&pcan_dev_ops);
180 ddi_soft_state_fini(&pcan_soft_state_p);
181 return (stat);
182 }
183
184 int
_info(struct modinfo * modinfop)185 _info(struct modinfo *modinfop)
186 {
187 return (mod_info(&modlinkage, modinfop));
188 }
189
190 static int
pcan_probe(dev_info_t * dip)191 pcan_probe(dev_info_t *dip)
192 {
193 int len, ret;
194 char *buf;
195 dev_info_t *pdip = ddi_get_parent(dip);
196
197 PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip,
198 ddi_driver_name(pdip), ddi_get_instance(pdip)));
199
200 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
201 (caddr_t)&buf, &len);
202 if (ret != DDI_SUCCESS)
203 return (DDI_PROBE_FAILURE);
204
205 PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf));
206 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
207 pcan_device_type = PCAN_DEVICE_PCCARD;
208 #ifdef DEBUG
209 if (pcan_debug & PCAN_DBG_FW_VERSION) {
210 cmn_err(CE_NOTE, "Cisco 802.11 pccard\n");
211 }
212 #endif
213 ret = DDI_PROBE_SUCCESS;
214 } else if (strcmp(buf, "pci") == 0) {
215 pcan_device_type = PCAN_DEVICE_PCI;
216 #ifdef DEBUG
217 if (pcan_debug & PCAN_DBG_FW_VERSION) {
218 cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n");
219 }
220 #endif
221 ret = DDI_PROBE_SUCCESS;
222 } else {
223 cmn_err(CE_NOTE, "pcan probe: unsupported card\n");
224 ret = DDI_PROBE_FAILURE;
225 }
226
227 kmem_free(buf, len);
228 return (ret);
229 }
230
231 static int
pcan_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)232 pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
233 {
234 int ret;
235 int instance;
236 uint16_t stat;
237 uint32_t err;
238 pcan_maci_t *pcan_p;
239 wifi_data_t wd = { 0 };
240 mac_register_t *macp;
241 modify_config_t cfgmod;
242 char strbuf[256];
243
244 PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd));
245 if (cmd != DDI_ATTACH)
246 goto attach_fail1;
247
248 /*
249 * Since this driver is porting from freebsd, so just like
250 * the original driver, the minipci card doesn't work on amd64
251 * machine.
252 * For sparc, since no pci card is available for the test, so this
253 * version doesn't support sparc. If there is card available and
254 * requirement, future version will try to support sparc.
255 * This driver works well for minipci card on 32bit x86
256 * machine, so keep the code to just support minipci card on 32bit
257 * mode.
258 */
259 #if defined(sparc) || defined(__sparc)
260 if (pcan_device_type == PCAN_DEVICE_PCI) {
261 cmn_err(CE_NOTE, "pcan attach: this driver does not support "
262 "PCI/MiniPCI card on Sparc\n");
263 goto attach_fail1;
264 }
265 #endif /* sparc */
266 #if defined(__amd64)
267 if (pcan_device_type == PCAN_DEVICE_PCI) {
268 cmn_err(CE_NOTE, "pcan attach: this driver does not support "
269 "PCI/MiniPCI card on amd64\n");
270 goto attach_fail1;
271 }
272 #endif /* amd64 */
273
274 /* Allocate soft state associated with this instance. */
275 if (ddi_soft_state_zalloc(pcan_soft_state_p,
276 ddi_get_instance(dip)) != DDI_SUCCESS) {
277 cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n");
278 goto attach_fail1;
279 }
280 pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p,
281 ddi_get_instance(dip));
282
283 pcan_p->pcan_device_type = pcan_device_type;
284 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
285 if (ddi_regs_map_setup(dip, 0,
286 (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0,
287 &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS)
288 goto attach_fail2;
289
290 stat = ddi_get16(pcan_p->pcan_cfg_handle,
291 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM));
292 stat |= (PCI_COMM_IO | PCI_COMM_MAE);
293 ddi_put16(pcan_p->pcan_cfg_handle,
294 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat);
295
296 ddi_regs_map_free(&pcan_p->pcan_cfg_handle);
297 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0,
298 0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS)
299 goto attach_fail3;
300 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1,
301 0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS)
302 goto attach_fail3;
303 if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2,
304 0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS)
305 goto attach_fail3;
306 }
307
308 pcan_p->pcan_dip = dip;
309 pcan_p->pcan_flag = 0;
310 pcan_p->glds_nocarrier = 0;
311 pcan_p->glds_noxmtbuf = 0;
312 pcan_p->glds_norcvbuf = 0;
313 pcan_p->pcan_socket = ddi_getprop(DDI_DEV_T_NONE, dip,
314 DDI_PROP_DONTPASS, "socket", -1);
315
316 pcan_p->pcan_reschedule_need = B_FALSE;
317 pcan_p->pcan_info_softint_pending = 0;
318 pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip,
319 DDI_PROP_DONTPASS, "reset-delay", 5000);
320
321 if (ddi_get_iblock_cookie(dip,
322 0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) {
323 cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n");
324 goto attach_fail3;
325 }
326
327 mutex_init(&pcan_p->pcan_glock, NULL,
328 MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
329 mutex_init(&pcan_p->pcan_scanlist_lock, NULL,
330 MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
331 mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL,
332 MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
333
334 if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
335 &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL,
336 pcan_info_softint, (caddr_t)pcan_p)) {
337 cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n");
338 goto attach_fail3a;
339 }
340
341 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
342 if (ret = ddi_add_intr(dip, 0, NULL, NULL,
343 pcan_intr, (caddr_t)pcan_p)) {
344 cmn_err(CE_WARN, "pcan attach: add intr failed\n");
345 goto attach_fail4;
346 }
347 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
348 if (ret = pcan_register_cs(dip, pcan_p)) {
349 PCANDBG((CE_NOTE, "pcan attach: register_cs failed"
350 " %x\n", ret));
351 goto attach_fail4;
352 }
353 } else {
354 cmn_err(CE_WARN, "pcan attach: unsupported device type\n");
355 goto attach_fail4;
356 }
357
358 mutex_enter(&pcan_p->pcan_glock);
359 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
360 /* leaves IF down, intr disabled */
361
362 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
363 if (ret = pcan_init_dma(dip, pcan_p)) {
364 cmn_err(CE_WARN, "pcan init_dma: failed\n");
365 mutex_exit(&pcan_p->pcan_glock);
366 goto attach_fail5;
367 }
368 }
369 if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */
370 cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret);
371 mutex_exit(&pcan_p->pcan_glock);
372 goto attach_fail6;
373 }
374
375 mutex_exit(&pcan_p->pcan_glock);
376 /*
377 * Provide initial settings for the WiFi plugin; whenever this
378 * information changes, we need to call mac_pdata_update()
379 */
380 wd.wd_secalloc = WIFI_SEC_NONE;
381 wd.wd_opmode = IEEE80211_M_STA;
382
383 macp = mac_alloc(MAC_VERSION);
384 if (macp == NULL) {
385 PCANDBG((CE_NOTE, "pcan attach: "
386 "MAC version mismatch\n"));
387 goto attach_fail6;
388 }
389
390 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
391 macp->m_driver = pcan_p;
392 macp->m_dip = dip;
393 macp->m_src_addr = pcan_p->pcan_mac_addr;
394 macp->m_callbacks = &pcan_m_callbacks;
395 macp->m_min_sdu = 0;
396 macp->m_max_sdu = IEEE80211_MTU;
397 macp->m_pdata = &wd;
398 macp->m_pdata_size = sizeof (wd);
399
400 err = mac_register(macp, &pcan_p->pcan_mh);
401 mac_free(macp);
402 if (err != 0) {
403 PCANDBG((CE_NOTE, "pcan attach: "
404 "mac_register err\n"));
405 goto attach_fail6;
406 }
407
408 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
409 /* turn on CS interrupt */
410 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
411 CONF_IRQ_CHANGE_VALID;
412 cfgmod.Vpp1 = 50;
413 cfgmod.Vpp2 = 50;
414 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
415
416 mutex_enter(&pcan_p->pcan_glock);
417 if (ret = pcan_init_nicmem(pcan_p)) {
418 cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n",
419 ret);
420 mutex_exit(&pcan_p->pcan_glock);
421 goto attach_fail7;
422 }
423 mutex_exit(&pcan_p->pcan_glock);
424 }
425 (void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
426 "bad-rids", (caddr_t)&pcan_p->pcan_badrids,
427 &pcan_p->pcan_badrids_len);
428
429 pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE;
430 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
431 mutex_enter(&pcan_p->pcan_glock);
432 list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t),
433 offsetof(an_scan_list_t, an_scan_node));
434 pcan_p->an_scan_num = 0;
435 mutex_exit(&pcan_p->pcan_glock);
436 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
437 pcan_p, drv_usectohz(1000000));
438
439 instance = ddi_get_instance(dip);
440 (void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance);
441 if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
442 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
443 goto attach_fail8;
444 }
445 mutex_enter(&pcan_p->pcan_glock);
446 PCAN_DISABLE_INTR_CLEAR(pcan_p);
447 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
448 pcan_p->pcan_flag |= PCAN_ATTACHED;
449 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
450 pcan_p->pcan_flag |= PCAN_CARD_READY;
451 }
452 mutex_exit(&pcan_p->pcan_glock);
453 return (DDI_SUCCESS);
454 attach_fail8:
455 if (pcan_p->an_scanlist_timeout_id != 0) {
456 (void) untimeout(pcan_p->an_scanlist_timeout_id);
457 pcan_p->an_scanlist_timeout_id = 0;
458 }
459 list_destroy(&pcan_p->an_scan_list);
460 attach_fail7:
461 (void) mac_unregister(pcan_p->pcan_mh);
462 attach_fail6:
463 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI)
464 pcan_free_dma(pcan_p);
465 attach_fail5:
466 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
467 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
468 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
469 pcan_unregister_cs(pcan_p);
470 }
471 attach_fail4:
472 if (pcan_p->pcan_info_softint_id)
473 ddi_remove_softintr(pcan_p->pcan_info_softint_id);
474 attach_fail3a:
475 pcan_destroy_locks(pcan_p);
476 attach_fail3:
477 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
478 if (pcan_p->pcan_handle0)
479 ddi_regs_map_free(&pcan_p->pcan_handle0);
480 if (pcan_p->pcan_handle1)
481 ddi_regs_map_free(&pcan_p->pcan_handle1);
482 if (pcan_p->pcan_handle2)
483 ddi_regs_map_free(&pcan_p->pcan_handle2);
484 }
485 attach_fail2:
486 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
487 attach_fail1:
488 return (DDI_FAILURE);
489 }
490
491 static int
pcan_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)492 pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
493 {
494 pcan_maci_t *pcan_p;
495 an_scan_list_t *scan_item0;
496 int ret;
497 pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
498
499 if (cmd != DDI_DETACH)
500 return (DDI_FAILURE);
501 if (!(pcan_p->pcan_flag & PCAN_ATTACHED))
502 return (DDI_FAILURE);
503
504 ret = mac_disable(pcan_p->pcan_mh);
505 if (ret != 0)
506 return (DDI_FAILURE);
507
508 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
509 mutex_enter(&pcan_p->pcan_glock);
510 pcan_stop_locked(pcan_p);
511 PCAN_DISABLE_INTR(pcan_p);
512 mutex_exit(&pcan_p->pcan_glock);
513 }
514 if (pcan_p->an_scanlist_timeout_id != 0) {
515 (void) untimeout(pcan_p->an_scanlist_timeout_id);
516 pcan_p->an_scanlist_timeout_id = 0;
517 }
518 if (pcan_p->pcan_connect_timeout_id != 0) {
519 (void) untimeout(pcan_p->pcan_connect_timeout_id);
520 pcan_p->pcan_connect_timeout_id = 0;
521 }
522 mutex_enter(&pcan_p->pcan_scanlist_lock);
523 scan_item0 = list_head(&pcan_p->an_scan_list);
524 while (scan_item0) {
525 pcan_delete_scan_item(pcan_p, scan_item0);
526 scan_item0 = list_head(&pcan_p->an_scan_list);
527 }
528 list_destroy(&pcan_p->an_scan_list);
529 mutex_exit(&pcan_p->pcan_scanlist_lock);
530
531 (void) mac_unregister(pcan_p->pcan_mh);
532
533 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
534 mutex_enter(&pcan_p->pcan_glock);
535 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
536 pcan_free_dma(pcan_p);
537 if (pcan_p->pcan_handle0)
538 ddi_regs_map_free(&pcan_p->pcan_handle0);
539 if (pcan_p->pcan_handle1)
540 ddi_regs_map_free(&pcan_p->pcan_handle1);
541 if (pcan_p->pcan_handle2)
542 ddi_regs_map_free(&pcan_p->pcan_handle2);
543 mutex_exit(&pcan_p->pcan_glock);
544 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
545 pcan_unregister_cs(pcan_p);
546 } else {
547 cmn_err(CE_WARN, "pcan detach: unsupported device type\n");
548 }
549 pcan_destroy_locks(pcan_p);
550 if (pcan_p->pcan_info_softint_id)
551 ddi_remove_softintr(pcan_p->pcan_info_softint_id);
552
553 if (pcan_p->pcan_badrids_len)
554 kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len);
555
556 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
557 ddi_remove_minor_node(dip, NULL);
558
559 return (DDI_SUCCESS);
560 }
561
562 /*
563 * card services and event handlers
564 */
565
566 static int
pcan_register_cs(dev_info_t * dip,pcan_maci_t * pcan_p)567 pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p)
568 {
569 int ret;
570 client_reg_t cr;
571 client_handle_t chdl; /* uint encoding of socket, function, client */
572 get_status_t card_status;
573 request_socket_mask_t sock_req;
574
575 bzero(&cr, sizeof (cr));
576 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
577 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
578 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
579 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND |
580 CS_EVENT_CLIENT_INFO;
581 cr.event_callback_args.client_data = pcan_p;
582 cr.Version = CS_VERSION;
583 cr.event_handler = (csfunction_t *)pcan_ev_hdlr;
584 cr.dip = dip;
585 (void) strcpy(cr.driver_name, pcan_name_str);
586 if (ret = csx_RegisterClient(&chdl, &cr)) {
587 cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret);
588 goto regcs_ret;
589 }
590
591 pcan_p->pcan_chdl = chdl;
592
593 bzero(&card_status, sizeof (card_status));
594 (void) csx_GetStatus(chdl, &card_status);
595 PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x",
596 card_status.Socket, card_status.CardState,
597 card_status.SocketState, card_status.raw_CardState));
598 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
599 /* card is not present, why are we attaching ? */
600 ret = CS_NO_CARD;
601 goto unreg;
602 }
603 cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL);
604 mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
605 mutex_enter(&pcan_p->pcan_cslock);
606 if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) {
607 cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret);
608 goto fail;
609 }
610 PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x",
611 pcan_p->pcan_log_sock.LogSocket,
612 pcan_p->pcan_log_sock.PhyAdapter,
613 pcan_p->pcan_log_sock.PhySocket));
614
615 /* turn on initialization events */
616 sock_req.Socket = 0;
617 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
618 CS_EVENT_REGISTRATION_COMPLETE;
619 if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
620 cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret);
621 goto fail;
622 }
623
624 /* wait for and process card insertion events */
625 while (!(pcan_p->pcan_flag & PCAN_CARD_READY))
626 cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock);
627 mutex_exit(&pcan_p->pcan_cslock);
628
629 pcan_p->pcan_flag |= PCAN_CS_REGISTERED;
630 return (CS_SUCCESS);
631 fail:
632 mutex_destroy(&pcan_p->pcan_cslock);
633 cv_destroy(&pcan_p->pcan_cscv);
634 unreg:
635 (void) csx_DeregisterClient(chdl);
636 regcs_ret:
637 pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED;
638 return (ret);
639 }
640
641 static void
pcan_unregister_cs(pcan_maci_t * pcan_p)642 pcan_unregister_cs(pcan_maci_t *pcan_p)
643 {
644 int ret;
645 release_socket_mask_t mask;
646 mask.Socket = pcan_p->pcan_socket;
647
648 /*
649 * The card service not registered means register_cs function
650 * doesnot return TRUE. Then all the lelated resource has been
651 * released in register_cs.
652 */
653 if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED))
654 return;
655 (void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask);
656
657 if (pcan_p->pcan_flag & PCAN_CARD_READY) {
658 pcan_card_remove(pcan_p);
659 }
660 mutex_destroy(&pcan_p->pcan_cslock);
661 cv_destroy(&pcan_p->pcan_cscv);
662 if (ret = csx_DeregisterClient(pcan_p->pcan_chdl))
663 cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret);
664 }
665 static void
pcan_destroy_locks(pcan_maci_t * pcan_p)666 pcan_destroy_locks(pcan_maci_t *pcan_p)
667 {
668 mutex_destroy(&pcan_p->pcan_txring.an_tx_lock);
669 mutex_destroy(&pcan_p->pcan_scanlist_lock);
670 mutex_destroy(&pcan_p->pcan_glock);
671 }
672
673 static int
pcan_ev_hdlr(event_t event,int priority,event_callback_args_t * arg)674 pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
675 {
676 int ret = CS_SUCCESS;
677 pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data;
678 client_info_t *ci_p = (client_info_t *)&arg->client_info;
679
680 mutex_enter(&pcan_p->pcan_cslock);
681 switch (event) {
682 case CS_EVENT_CARD_INSERTION:
683 ret = pcan_card_insert(pcan_p);
684 cv_broadcast(&pcan_p->pcan_cscv);
685 break;
686 case CS_EVENT_REGISTRATION_COMPLETE:
687 cv_broadcast(&pcan_p->pcan_cscv);
688 break;
689 case CS_EVENT_CARD_REMOVAL:
690 if (priority & CS_EVENT_PRI_HIGH)
691 break;
692 pcan_card_remove(pcan_p);
693 cv_broadcast(&pcan_p->pcan_cscv);
694 break;
695 case CS_EVENT_CLIENT_INFO:
696 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
697 CS_CLIENT_INFO_SUBSVC_CS)
698 break;
699
700 ci_p->Revision = 0x0101;
701 ci_p->CSLevel = CS_VERSION;
702 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
703 (void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING);
704 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
705 ci_p->Attributes |= CS_CLIENT_INFO_VALID;
706 break;
707 case CS_EVENT_PM_SUSPEND:
708 pcan_do_suspend(pcan_p);
709 break;
710 default:
711 ret = CS_UNSUPPORTED_EVENT;
712 break;
713 }
714 mutex_exit(&pcan_p->pcan_cslock);
715 return (ret);
716 }
717
718 static int
pcan_card_insert(pcan_maci_t * pcan_p)719 pcan_card_insert(pcan_maci_t *pcan_p)
720 {
721 int ret, hi, lo;
722 tuple_t tuple;
723 cisparse_t cisparse;
724 io_req_t io;
725 irq_req_t irq;
726 config_req_t cfg;
727 cistpl_config_t config;
728 cistpl_cftable_entry_t *tbl_p;
729 register client_handle_t chdl = pcan_p->pcan_chdl;
730 modify_config_t cfgmod;
731
732 bzero(&tuple, sizeof (tuple));
733 tuple.DesiredTuple = CISTPL_MANFID;
734 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
735 cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret);
736 goto insert_ret;
737 }
738 bzero(&cisparse, sizeof (cisparse));
739 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
740 cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret);
741 goto insert_ret;
742 }
743 /* verify manufacture ID */
744 PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n",
745 cisparse.manfid.manf, cisparse.manfid.card));
746
747 bzero(&tuple, sizeof (tuple));
748 tuple.DesiredTuple = CISTPL_FUNCID;
749 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
750 cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret);
751 goto insert_ret;
752 }
753 bzero(&cisparse, sizeof (cisparse));
754 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
755 cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret);
756 goto insert_ret;
757 }
758 /* verify function ID */
759 PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function));
760
761 bzero(&tuple, sizeof (tuple));
762 tuple.DesiredTuple = CISTPL_CONFIG;
763 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
764 cmn_err(CE_WARN, "pcan: get config failed %x\n", ret);
765 goto insert_ret;
766 }
767 bzero(&config, sizeof (config));
768 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
769 cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret);
770 goto insert_ret;
771 }
772 PCANDBG((CE_NOTE,
773 "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
774 config.present, config.nr, config.hr, config.regs[0],
775 config.base, config.last));
776
777 hi = 0;
778 lo = (int)-1; /* really big number */
779 tbl_p = &cisparse.cftable;
780 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
781 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
782 PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index));
783 if (ret = csx_GetNextTuple(chdl, &tuple)) {
784 cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret);
785 break;
786 }
787 bzero((caddr_t)&cisparse, sizeof (cisparse));
788 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
789 cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret);
790 break;
791 }
792 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
793 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
794 if (tbl_p->pd.pd_vcc.avgI > hi) {
795 hi = tbl_p->pd.pd_vcc.avgI;
796 pcan_p->pcan_config_hi = tbl_p->index;
797 }
798 if (tbl_p->pd.pd_vcc.avgI < lo) {
799 lo = tbl_p->pd.pd_vcc.avgI;
800 pcan_p->pcan_config = tbl_p->index;
801 }
802 }
803 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
804 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
805 pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV;
806 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
807 pcan_p->pcan_iodecode = tbl_p->io.addr_lines;
808 }
809 }
810 PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
811 pcan_p->pcan_config_hi, pcan_p->pcan_config,
812 pcan_p->pcan_vcc, pcan_p->pcan_iodecode));
813
814 bzero(&io, sizeof (io));
815 io.BasePort1.base = 0;
816 io.NumPorts1 = 1 << pcan_p->pcan_iodecode;
817 io.Attributes1 = IO_DATA_PATH_WIDTH_16;
818 io.IOAddrLines = pcan_p->pcan_iodecode;
819 if (ret = csx_RequestIO(chdl, &io)) {
820 cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret);
821 goto insert_ret;
822 }
823 pcan_p->pcan_port = io.BasePort1.handle;
824
825 if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH,
826 &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL,
827 pcan_intr, (caddr_t)pcan_p)) {
828 cmn_err(CE_NOTE, "pcan: Add softintr failed\n");
829 goto insert_ret;
830 }
831 irq.Attributes = IRQ_TYPE_EXCLUSIVE;
832 irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ?
833 (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr;
834 irq.irq_handler_arg = pcan_p;
835 if (ret = csx_RequestIRQ(chdl, &irq)) {
836 cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret);
837 goto un_io;
838 }
839
840 bzero(&cfg, sizeof (cfg));
841 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
842 cfg.Vcc = 50; /* pcan_vcc == 0 */
843 cfg.Vpp1 = 50;
844 cfg.Vpp2 = 50;
845 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
846 cfg.ConfigBase = config.base;
847 cfg.ConfigIndex = pcan_p->pcan_config;
848 cfg.Status = CCSR_IO_IS_8; /* no use */
849 cfg.Present = config.present;
850 pcan_p->pcan_flag |= PCAN_CARD_READY;
851 if (ret = csx_RequestConfiguration(chdl, &cfg)) {
852 cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret);
853 goto un_irq;
854 }
855
856 if (pcan_p->pcan_flag & PCAN_SUSPENDED) {
857 mutex_enter(&pcan_p->pcan_glock);
858 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
859 /* turn on CS interrupt */
860 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
861 CONF_IRQ_CHANGE_VALID;
862 cfgmod.Vpp1 = 50;
863 cfgmod.Vpp2 = 50;
864 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
865
866 if (ret = pcan_init_nicmem(pcan_p)) {
867 cmn_err(CE_WARN, "pcan insert: init_nicmem failed %x\n",
868 ret);
869 }
870 PCAN_DISABLE_INTR_CLEAR(pcan_p);
871 ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
872 PCANDBG((CE_NOTE, "pcan insert set cmd ret =%x\n", ret));
873 pcan_p->pcan_flag &= ~PCAN_SUSPENDED;
874 mutex_exit(&pcan_p->pcan_glock);
875 }
876
877 if (pcan_p->pcan_flag & PCAN_PLUMBED) {
878 (void) pcan_start(pcan_p);
879 pcan_p->pcan_flag &= ~PCAN_PLUMBED;
880 PCANDBG((CE_NOTE, "pcan insert: active interrupt\n"));
881 }
882 return (CS_SUCCESS);
883 un_irq:
884 (void) csx_ReleaseIRQ(chdl, &irq);
885 un_io:
886 ddi_remove_softintr(pcan_p->pcan_softint_id);
887
888 (void) csx_ReleaseIO(chdl, &io);
889 pcan_p->pcan_port = 0;
890 insert_ret:
891 pcan_p->pcan_flag &= ~PCAN_CARD_READY;
892 return (ret);
893 }
894
895 /*
896 * assume card is already removed, don't touch the hardware
897 */
898 static void
pcan_do_suspend(pcan_maci_t * pcan_p)899 pcan_do_suspend(pcan_maci_t *pcan_p)
900 {
901 int ret;
902 if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
903 if (pcan_p->pcan_connect_timeout_id != 0) {
904 (void) untimeout(pcan_p->pcan_connect_timeout_id);
905 pcan_p->pcan_connect_timeout_id = 0;
906 }
907 mutex_enter(&pcan_p->pcan_glock);
908 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
909 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
910 PCANDBG((CE_NOTE, "pcan: disable failed, ret %d\n",
911 ret));
912 if (ret = pcan_loaddef(pcan_p))
913 PCANDBG((CE_NOTE, "pcan: loaddef failed, ret %d\n",
914 ret));
915 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
916 mutex_exit(&pcan_p->pcan_glock);
917 }
918 pcan_p->pcan_flag |= PCAN_SUSPENDED;
919 }
920
921
922 /*
923 * assume card is already removed, don't touch the hardware
924 */
925 static void
pcan_card_remove(pcan_maci_t * pcan_p)926 pcan_card_remove(pcan_maci_t *pcan_p)
927 {
928 int ret;
929 io_req_t io;
930 irq_req_t irq;
931
932 if (!(pcan_p->pcan_flag & PCAN_CARD_READY))
933 return;
934 if (pcan_p->pcan_connect_timeout_id != 0) {
935 (void) untimeout(pcan_p->pcan_connect_timeout_id);
936 pcan_p->pcan_connect_timeout_id = 0;
937 }
938
939 if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
940 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
941 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
942 }
943 mutex_enter(&pcan_p->pcan_glock);
944 if (pcan_p->pcan_flag & PCAN_CARD_INTREN) {
945 pcan_stop_locked(pcan_p);
946 pcan_p->pcan_flag |= PCAN_PLUMBED;
947 }
948 pcan_p->pcan_flag &= ~PCAN_CARD_READY;
949 mutex_exit(&pcan_p->pcan_glock);
950
951 if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL))
952 cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret);
953
954 bzero(&irq, sizeof (irq));
955 if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq))
956 cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret);
957
958 ddi_remove_softintr(pcan_p->pcan_softint_id);
959 pcan_p->pcan_softint_id = 0;
960
961 bzero(&io, sizeof (io));
962 io.BasePort1.handle = pcan_p->pcan_port;
963 io.NumPorts1 = 16;
964 if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io))
965 cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret);
966
967 pcan_p->pcan_port = 0;
968 PCANDBG((CE_NOTE, "pcan: removed\n"));
969 }
970
971 /*
972 * gld operation interface routines
973 */
974 static int
pcan_start(void * arg)975 pcan_start(void *arg)
976 {
977 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
978
979 mutex_enter(&pcan_p->pcan_glock);
980 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
981 mutex_exit(&pcan_p->pcan_glock);
982 return (PCAN_FAIL);
983 }
984 (void) pcan_loaddef(pcan_p);
985 pcan_start_locked(pcan_p);
986 mutex_exit(&pcan_p->pcan_glock);
987 return (PCAN_SUCCESS);
988 }
989
990 static void
pcan_stop(void * arg)991 pcan_stop(void *arg)
992 {
993 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
994
995 mutex_enter(&pcan_p->pcan_glock);
996 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
997 mutex_exit(&pcan_p->pcan_glock);
998 return;
999 }
1000 pcan_stop_locked(pcan_p);
1001 mutex_exit(&pcan_p->pcan_glock);
1002 if (pcan_p->pcan_connect_timeout_id != 0) {
1003 (void) untimeout(pcan_p->pcan_connect_timeout_id);
1004 pcan_p->pcan_connect_timeout_id = 0;
1005 }
1006 }
1007
1008 /*
1009 * mac address can only be set in 'disable' state and
1010 * be effective after 'enable' state.
1011 */
1012 static int
pcan_saddr(void * arg,const uint8_t * macaddr)1013 pcan_saddr(void *arg, const uint8_t *macaddr)
1014 {
1015 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1016 int ret = PCAN_SUCCESS;
1017 ether_copy(macaddr, pcan_p->pcan_mac_addr);
1018
1019 mutex_enter(&pcan_p->pcan_glock);
1020 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1021 ret = PCAN_FAIL;
1022 goto done;
1023 }
1024 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
1025 if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
1026 cmn_err(CE_WARN, "pcan set mac addr: failed\n");
1027 ret = PCAN_FAIL;
1028 goto done;
1029 }
1030 if (pcan_config_mac(pcan_p)) {
1031 cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n");
1032 ret = PCAN_FAIL;
1033 goto done;
1034 }
1035 if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
1036 cmn_err(CE_WARN, "pcan set mac addr: failed\n");
1037 ret = PCAN_FAIL;
1038 }
1039 done:
1040 mutex_exit(&pcan_p->pcan_glock);
1041 return (ret);
1042 }
1043
1044 /*
1045 * send a packet out for pccard
1046 */
1047 static int
pcan_send(pcan_maci_t * pcan_p,mblk_t * mblk_p)1048 pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
1049 {
1050 char *buf, *buf_p;
1051 an_txfrm_t *frm_p;
1052 #ifdef PCAN_SEND_DEBUG
1053 struct an_ltv_status radio_status;
1054 #endif /* PCAN_SEND_DEBUG */
1055 uint16_t pkt_len, xmt_id, ring_idx, r = 0;
1056 struct ieee80211_frame *wh;
1057 int i = 0;
1058
1059 mutex_enter(&pcan_p->pcan_glock);
1060 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1061 mutex_exit(&pcan_p->pcan_glock);
1062 freemsg(mblk_p);
1063 return (PCAN_SUCCESS); /* drop packet */
1064 }
1065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */
1066 PCANDBG((CE_NOTE, "pcan: link down, dropped\n"));
1067 pcan_p->glds_nocarrier++;
1068 mutex_exit(&pcan_p->pcan_glock);
1069 freemsg(mblk_p);
1070 return (PCAN_SUCCESS); /* drop packet */
1071 }
1072 mutex_exit(&pcan_p->pcan_glock);
1073 if (pullupmsg(mblk_p, -1) == 0) {
1074 cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n");
1075 freemsg(mblk_p);
1076 return (PCAN_SUCCESS); /* drop packet */
1077 }
1078 wh = (struct ieee80211_frame *)mblk_p->b_rptr;
1079
1080 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1081 ring_idx = pcan_p->pcan_txring.an_tx_prod;
1082 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK;
1083
1084 /* check whether there is a xmt buffer available */
1085 while ((i < AN_TX_RING_CNT) &&
1086 (pcan_p->pcan_txring.an_tx_ring[ring_idx])) {
1087 ring_idx = pcan_p->pcan_txring.an_tx_prod;
1088 pcan_p->pcan_txring.an_tx_prod =
1089 (ring_idx + 1) & AN_TX_RING_MASK;
1090 i++;
1091 }
1092
1093 if (i == AN_TX_RING_CNT) {
1094 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1095 PCANDBG((CE_NOTE, "pcan: ring full, retrying\n"));
1096 mutex_enter(&pcan_p->pcan_glock);
1097 pcan_p->pcan_reschedule_need = B_TRUE;
1098 mutex_exit(&pcan_p->pcan_glock);
1099 pcan_p->glds_noxmtbuf++;
1100 return (PCAN_FAIL);
1101 }
1102 xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx];
1103 pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id;
1104 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1105
1106 buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */
1107 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf; /* 16-bit round up */
1108 frm_p = (an_txfrm_t *)buf_p;
1109
1110 #ifdef DEBUG
1111 if (pcan_debug & PCAN_DBG_SEND) {
1112 cmn_err(CE_NOTE, "pcan send: packet from plugin");
1113 for (i = 0; i < MBLKL(mblk_p); i++)
1114 cmn_err(CE_NOTE, "%x: %x\n", i,
1115 *((unsigned char *)mblk_p->b_rptr + i));
1116 }
1117 #endif
1118 pkt_len = msgdsize(mblk_p);
1119 if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) {
1120 cmn_err(CE_WARN, "pcan send: mblk is too long");
1121 kmem_free(buf, PCAN_NICMEM_SZ);
1122 freemsg(mblk_p);
1123 return (PCAN_SUCCESS); /* drop packet */
1124 }
1125 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
1126 IEEE80211_FC1_DIR_TODS) {
1127 kmem_free(buf, PCAN_NICMEM_SZ);
1128 freemsg(mblk_p);
1129 return (PCAN_SUCCESS); /* drop packet */
1130 }
1131
1132 /* initialize xmt frame header, payload_len must be stored in LE */
1133 bzero(frm_p, sizeof (an_txfrm_t) + 2);
1134 frm_p->an_tx_ctl = AN_TXCTL_8023;
1135
1136 /*
1137 * mblk sent down from plugin includes station mode 802.11 frame and
1138 * llc, so we here need to remove them and add an ethernet header.
1139 */
1140 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
1141 + 2;
1142 bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */
1143 bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */
1144 *((uint16_t *)(buf_p + 0x36)) = pkt_len;
1145 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
1146 - 2, buf_p + 0x44, pkt_len);
1147
1148 if (pkt_len & 1) { /* round up to 16-bit boundary and pad 0 */
1149 buf_p[pkt_len + 0x44] = 0;
1150 pkt_len++;
1151 }
1152 ASSERT(pkt_len <= PCAN_NICMEM_SZ);
1153 #ifdef DEBUG
1154 if (pcan_debug & PCAN_DBG_SEND) {
1155 cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x",
1156 pkt_len);
1157 for (i = 0; i < pkt_len + 4; i++)
1158 cmn_err(CE_NOTE, "%x: %x\n", i,
1159 *((unsigned char *)buf_p + 0x36 + i));
1160 }
1161 #endif
1162 mutex_enter(&pcan_p->pcan_glock);
1163 (void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */
1164 (void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38),
1165 pkt_len + 12);
1166 r = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id);
1167 mutex_exit(&pcan_p->pcan_glock);
1168
1169 PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n",
1170 pkt_len, 0x44 + pkt_len, xmt_id, ring_idx));
1171 kmem_free(buf, PCAN_NICMEM_SZ);
1172 #ifdef PCAN_SEND_DEBUG
1173 if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) {
1174 PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len));
1175 } else {
1176 PCANDBG((CE_NOTE, "pcan: radio status:\n"));
1177 }
1178 #endif /* PCAN_SEND_DEBUG */
1179 if (r)
1180 return (PCAN_FAIL);
1181 else {
1182 freemsg(mblk_p);
1183 return (PCAN_SUCCESS);
1184 }
1185 }
1186
1187 /*
1188 * send a packet out for PCI/MiniPCI card
1189 */
1190 static int
pcian_send(pcan_maci_t * pcan_p,mblk_t * mblk_p)1191 pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
1192 {
1193 char *buf;
1194 uint16_t pkt_len = msgdsize(mblk_p), ring_idx;
1195 uint32_t i;
1196 struct ieee80211_frame *wh;
1197 struct an_card_tx_desc an_tx_desc;
1198
1199 ring_idx = pcan_p->pcan_txring.an_tx_prod;
1200
1201 mutex_enter(&pcan_p->pcan_glock);
1202 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */
1203 mutex_exit(&pcan_p->pcan_glock);
1204 pcan_p->glds_nocarrier++;
1205 freemsg(mblk_p);
1206 return (PCAN_SUCCESS); /* drop packet */
1207 }
1208 mutex_exit(&pcan_p->pcan_glock);
1209 if (pullupmsg(mblk_p, -1) == 0) {
1210 cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n");
1211 freemsg(mblk_p);
1212 return (PCAN_SUCCESS); /* drop packet */
1213 }
1214 wh = (struct ieee80211_frame *)mblk_p->b_rptr;
1215
1216 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1217 if ((pcan_p->pcan_flag & PCAN_CARD_SEND) &&
1218 (ring_idx == pcan_p->pcan_txring.an_tx_cons)) {
1219 pcan_p->glds_noxmtbuf++;
1220 pcan_p->pcan_reschedule_need = B_TRUE;
1221 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1222 return (PCAN_FAIL);
1223 }
1224 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1225
1226 #ifdef DEBUG
1227 if (pcan_debug & PCAN_DBG_SEND) {
1228 cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin");
1229 for (i = 0; i < MBLKL(mblk_p); i++)
1230 cmn_err(CE_NOTE, "%x: %x\n", i,
1231 *((unsigned char *)mblk_p->b_rptr + i));
1232 }
1233 #endif
1234 mutex_enter(&pcan_p->pcan_glock);
1235
1236 buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr;
1237 bzero(buf, AN_TX_BUFFER_SIZE);
1238
1239 /*
1240 * mblk sent down from plugin includes station mode 802.11 frame and
1241 * llc, so we here need to remove them and add an ethernet header.
1242 */
1243 *((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023);
1244 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
1245 + 2;
1246 bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */
1247 bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */
1248 *((uint16_t *)(buf + 0x36)) = pkt_len;
1249 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
1250 - 2, buf + 0x44, pkt_len);
1251
1252 #ifdef DEBUG
1253 if (pcan_debug & PCAN_DBG_SEND) {
1254 cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware "
1255 "pkt_len=%x", pkt_len);
1256 for (i = 0; i < pkt_len + 14; i++)
1257 cmn_err(CE_NOTE, "%x: %x\n", i,
1258 *((unsigned char *)buf + 0x36 + i));
1259 }
1260 #endif
1261 bzero(&an_tx_desc, sizeof (an_tx_desc));
1262 an_tx_desc.an_offset = 0;
1263 an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0);
1264 an_tx_desc.an_valid = 1;
1265 an_tx_desc.an_len = 0x44 + pkt_len;
1266 an_tx_desc.an_phys = pcan_p->pcan_tx[ring_idx].dma_physaddr;
1267 for (i = 0; i < sizeof (an_tx_desc) / 4; i++) {
1268 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET +
1269 (ring_idx * sizeof (an_tx_desc)) + (i * 4),
1270 ((uint32_t *)&an_tx_desc)[i]);
1271 }
1272
1273 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1274 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC;
1275 pcan_p->pcan_flag |= PCAN_CARD_SEND;
1276 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
1277 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1278
1279 freemsg(mblk_p);
1280 mutex_exit(&pcan_p->pcan_glock);
1281 return (PCAN_SUCCESS);
1282 }
1283
1284 static mblk_t *
pcan_tx(void * arg,mblk_t * mp)1285 pcan_tx(void *arg, mblk_t *mp)
1286 {
1287 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1288 mblk_t *next;
1289 int ret = 0;
1290
1291 ASSERT(mp != NULL);
1292 mutex_enter(&pcan_p->pcan_glock);
1293 if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) !=
1294 (PCAN_CARD_LINKUP | PCAN_CARD_READY)) {
1295 mutex_exit(&pcan_p->pcan_glock);
1296 freemsgchain(mp);
1297 return (NULL);
1298 }
1299 mutex_exit(&pcan_p->pcan_glock);
1300 while (mp != NULL) {
1301 next = mp->b_next;
1302 mp->b_next = NULL;
1303
1304 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1305 ret = pcian_send(pcan_p, mp);
1306 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1307 ret = pcan_send(pcan_p, mp);
1308 }
1309 if (ret) {
1310 mp->b_next = next;
1311 break;
1312 }
1313 mp = next;
1314 }
1315 return (mp);
1316 }
1317
1318 /*
1319 * this driver is porting from freebsd, the code in freebsd
1320 * doesn't show how to set promiscous mode.
1321 */
1322 /*ARGSUSED*/
1323 static int
pcan_prom(void * arg,boolean_t on)1324 pcan_prom(void *arg, boolean_t on)
1325 {
1326 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1327 int ret = PCAN_SUCCESS;
1328
1329 mutex_enter(&pcan_p->pcan_glock);
1330 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1331 ret = PCAN_FAIL;
1332 }
1333 mutex_exit(&pcan_p->pcan_glock);
1334 return (ret);
1335 }
1336
1337 /*ARGSUSED*/
1338 static int
pcan_gstat(void * arg,uint_t statitem,uint64_t * val)1339 pcan_gstat(void *arg, uint_t statitem, uint64_t *val)
1340 {
1341 uint16_t i;
1342 int ret = PCAN_SUCCESS;
1343 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1344 uint64_t *cntr_p = pcan_p->pcan_cntrs_s;
1345
1346 PCANDBG((CE_NOTE, "pcan: gstat called\n"));
1347
1348 mutex_enter(&pcan_p->pcan_glock);
1349 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1350 ret = PCAN_FAIL;
1351 goto done;
1352 }
1353 if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats),
1354 AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) {
1355 cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)"
1356 " failed \n");
1357 ret = PCAN_FAIL;
1358 goto done;
1359 }
1360 for (i = 0; i < ANC_STAT_CNT; i++) {
1361 cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i);
1362 }
1363 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
1364 cmn_err(CE_WARN, "pcan kstat: read status failed \n");
1365 ret = PCAN_FAIL;
1366 goto done;
1367 }
1368
1369 switch (statitem) {
1370 case MAC_STAT_IFSPEED:
1371 *val = 500000 * pcan_p->an_status.an_cur_tx_rate;
1372 break;
1373 case MAC_STAT_NOXMTBUF:
1374 *val = pcan_p->glds_noxmtbuf;
1375 break;
1376 case MAC_STAT_NORCVBUF:
1377 *val = pcan_p->glds_norcvbuf;
1378 break;
1379 case MAC_STAT_IERRORS:
1380 *val = cntr_p[ANC_RX_OVERRUNS] +
1381 cntr_p[ANC_RX_PLCP_CSUM_ERRS] +
1382 cntr_p[ANC_RX_PLCP_FORMAT_ERRS] +
1383 cntr_p[ANC_RX_PLCP_LEN_ERRS] +
1384 cntr_p[ANC_RX_MAC_CRC_ERRS] +
1385 cntr_p[ANC_RX_WEP_ERRS];
1386 break;
1387 case MAC_STAT_OERRORS:
1388 *val = cntr_p[ANC_TX_HOST_FAILED];
1389 break;
1390 case MAC_STAT_RBYTES:
1391 *val = cntr_p[ANC_HOST_RX_BYTES];
1392 break;
1393 case MAC_STAT_IPACKETS:
1394 *val = cntr_p[ANC_RX_HOST_UCASTS];
1395 break;
1396 case MAC_STAT_OBYTES:
1397 *val = cntr_p[ANC_HOST_TX_BYTES];
1398 break;
1399 case MAC_STAT_OPACKETS:
1400 *val = cntr_p[ANC_TX_HOST_UCASTS];
1401 break;
1402 case WIFI_STAT_TX_FAILED:
1403 *val = cntr_p[ANC_TX_HOST_FAILED];
1404 break;
1405 case WIFI_STAT_TX_RETRANS:
1406 *val = cntr_p[ANC_HOST_RETRIES];
1407 break;
1408 case WIFI_STAT_FCS_ERRORS:
1409 *val = cntr_p[ANC_RX_MAC_CRC_ERRS];
1410 break;
1411 case WIFI_STAT_WEP_ERRORS:
1412 *val = cntr_p[ANC_RX_WEP_ERRS];
1413 break;
1414 case WIFI_STAT_MCAST_TX:
1415 *val = cntr_p[ANC_TX_HOST_MCASTS];
1416 break;
1417 case WIFI_STAT_MCAST_RX:
1418 *val = cntr_p[ANC_RX_HOST_MCASTS];
1419 break;
1420 case WIFI_STAT_TX_FRAGS:
1421 case WIFI_STAT_RX_FRAGS:
1422 *val = 0;
1423 break;
1424 case WIFI_STAT_RTS_SUCCESS:
1425 *val = cntr_p[ANC_TX_RTS_OK];
1426 break;
1427 case WIFI_STAT_RTS_FAILURE:
1428 *val = cntr_p[ANC_NO_CTS];
1429 break;
1430 case WIFI_STAT_ACK_FAILURE:
1431 *val = cntr_p[ANC_NO_ACK];
1432 break;
1433 case WIFI_STAT_RX_DUPS:
1434 *val = cntr_p[ANC_RX_DUPS];
1435 break;
1436 default:
1437 ret = ENOTSUP;
1438 }
1439
1440
1441 done:
1442 mutex_exit(&pcan_p->pcan_glock);
1443 return (ret);
1444 }
1445
1446 /*
1447 * this driver is porting from freebsd, the code in freebsd
1448 * doesn't show how to set multi address.
1449 */
1450 /*ARGSUSED*/
1451 static int
pcan_sdmulti(void * arg,boolean_t add,const uint8_t * eth_p)1452 pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
1453 {
1454 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1455
1456 mutex_enter(&pcan_p->pcan_glock);
1457 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
1458 mutex_exit(&pcan_p->pcan_glock);
1459 return (PCAN_FAIL);
1460 }
1461 mutex_exit(&pcan_p->pcan_glock);
1462 return (PCAN_SUCCESS);
1463 }
1464
1465 static uint_t
pcan_info_softint(caddr_t arg)1466 pcan_info_softint(caddr_t arg)
1467 {
1468 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1469 wifi_data_t wd = { 0 };
1470 uint16_t link;
1471 uint32_t link_up;
1472
1473 mutex_enter(&pcan_p->pcan_glock);
1474 if (pcan_p->pcan_info_softint_pending != 1) {
1475 mutex_exit(&pcan_p->pcan_glock);
1476 return (DDI_INTR_UNCLAIMED);
1477 }
1478
1479 PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link);
1480 link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP;
1481 if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) {
1482 pcan_p->pcan_flag |= PCAN_CARD_LINKUP;
1483 mutex_exit(&pcan_p->pcan_glock);
1484 if (pcan_p->pcan_connect_timeout_id != 0) {
1485 (void) untimeout(pcan_p->pcan_connect_timeout_id);
1486 pcan_p->pcan_connect_timeout_id = 0;
1487 }
1488 mac_link_update(GLD3(pcan_p), LINK_STATE_UP);
1489 mutex_enter(&pcan_p->pcan_glock);
1490 (void) pcan_status_ltv(PCAN_READ_LTV, pcan_p,
1491 &pcan_p->an_status);
1492 bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6);
1493 wd.wd_secalloc = WIFI_SEC_NONE;
1494 wd.wd_opmode = IEEE80211_M_STA;
1495 (void) mac_pdata_update(pcan_p->pcan_mh, &wd,
1496 sizeof (wd));
1497 #ifdef DEBUG
1498 if (pcan_debug & PCAN_DBG_LINKINFO) {
1499 cmn_err(CE_NOTE, "pcan: link Up, chan=%d, "
1500 "ssid=\"%s\""
1501 " (%02x:%02x:%02x:%02x:%02x:%02x)\n",
1502 pcan_p->an_status.an_channel_set,
1503 pcan_p->an_status.an_ssid,
1504 pcan_p->an_status.an_cur_bssid[0],
1505 pcan_p->an_status.an_cur_bssid[1],
1506 pcan_p->an_status.an_cur_bssid[2],
1507 pcan_p->an_status.an_cur_bssid[3],
1508 pcan_p->an_status.an_cur_bssid[4],
1509 pcan_p->an_status.an_cur_bssid[5]);
1510 }
1511 #endif
1512 }
1513 if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) {
1514 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
1515 #ifdef DEBUG
1516 if (pcan_debug & PCAN_DBG_LINKINFO) {
1517 cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link);
1518 }
1519 #endif
1520 if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) {
1521 pcan_p->pcan_connect_timeout_id =
1522 timeout(pcan_connect_timeout,
1523 pcan_p, drv_usectohz(1000));
1524 }
1525 mutex_exit(&pcan_p->pcan_glock);
1526 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
1527 mutex_enter(&pcan_p->pcan_glock);
1528 }
1529
1530 pcan_p->pcan_info_softint_pending = 0;
1531 mutex_exit(&pcan_p->pcan_glock);
1532 return (DDI_INTR_CLAIMED);
1533 }
1534
1535 static uint_t
pcan_intr(caddr_t arg)1536 pcan_intr(caddr_t arg)
1537 {
1538 uint16_t stat;
1539 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1540
1541 mutex_enter(&pcan_p->pcan_glock);
1542 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
1543 (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
1544 mutex_exit(&pcan_p->pcan_glock);
1545 return (DDI_INTR_UNCLAIMED);
1546 }
1547 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1548
1549 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
1550 mutex_exit(&pcan_p->pcan_glock);
1551 return (DDI_INTR_UNCLAIMED);
1552 }
1553
1554 PCAN_DISABLE_INTR(pcan_p);
1555 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p));
1556
1557 PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat,
1558 pcan_p->pcan_flag));
1559
1560 if (stat & AN_EV_AWAKE) {
1561 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
1562 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
1563 }
1564 if (stat & AN_EV_LINKSTAT) {
1565 pcan_p->pcan_info_softint_pending = 1;
1566 ddi_trigger_softintr(pcan_p->pcan_info_softint_id);
1567 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT);
1568 }
1569 if (stat & AN_EV_RX) {
1570 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1571 pcian_rcv(pcan_p);
1572 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1573 pcan_rcv(pcan_p);
1574 }
1575 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX);
1576 }
1577 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1578 if (stat & AN_EV_TX_CPY) {
1579 (void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY);
1580 if (pcan_p->pcan_reschedule_need == B_TRUE) {
1581 mac_tx_update(GLD3(pcan_p));
1582 pcan_p->pcan_reschedule_need = B_FALSE;
1583 }
1584 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY);
1585 }
1586 }
1587 if (stat & AN_EV_TX) {
1588 if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) {
1589 if (pcan_p->pcan_reschedule_need == B_TRUE) {
1590 mac_tx_update(GLD3(pcan_p));
1591 pcan_p->pcan_reschedule_need = B_FALSE;
1592 }
1593 }
1594 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX);
1595 }
1596 if (stat & AN_EV_TX_EXC) {
1597 if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) {
1598 if (pcan_p->pcan_reschedule_need == B_TRUE) {
1599 mutex_exit(&pcan_p->pcan_glock);
1600 mac_tx_update(GLD3(pcan_p));
1601 mutex_enter(&pcan_p->pcan_glock);
1602 pcan_p->pcan_reschedule_need = B_FALSE;
1603 }
1604 }
1605 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC);
1606 }
1607 if (stat & AN_EV_ALLOC) {
1608 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
1609 PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n"));
1610 }
1611 if (stat & AN_EV_MIC) {
1612 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC);
1613 }
1614 PCAN_ENABLE_INTR(pcan_p);
1615 mutex_exit(&pcan_p->pcan_glock);
1616 return (DDI_INTR_CLAIMED);
1617 }
1618
1619 static uint_t
pcan_intr_hi(caddr_t arg)1620 pcan_intr_hi(caddr_t arg)
1621 {
1622 uint16_t stat;
1623 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
1624
1625 mutex_enter(&pcan_p->pcan_glock);
1626 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
1627 (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
1628 mutex_exit(&pcan_p->pcan_glock);
1629 return (DDI_INTR_UNCLAIMED);
1630 }
1631 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1632 PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat,
1633 pcan_p->pcan_flag));
1634
1635 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
1636 mutex_exit(&pcan_p->pcan_glock);
1637 return (DDI_INTR_UNCLAIMED);
1638 }
1639 /* disable interrupt without ack */
1640 PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0);
1641 mutex_exit(&pcan_p->pcan_glock);
1642 ddi_trigger_softintr(pcan_p->pcan_softint_id);
1643 return (DDI_INTR_CLAIMED);
1644 }
1645
1646 /*
1647 * retrieve data from pccard
1648 */
1649 static void
pcan_rcv(pcan_maci_t * pcan_p)1650 pcan_rcv(pcan_maci_t *pcan_p)
1651 {
1652 uint16_t id, off, ret, data_len, pkt_stat, frm_ctl;
1653 an_rxfrm_t frm;
1654 struct ieee80211_llc *llc;
1655
1656 mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED);
1657 if (!mp) {
1658 cmn_err(CE_WARN, "pcan: failed to alloc rcv buf");
1659 pcan_p->glds_norcvbuf++;
1660 return;
1661 }
1662 ASSERT(mp->b_rptr == mp->b_wptr);
1663
1664 PCAN_READ(pcan_p, AN_RX_FID, id);
1665 if (id == AN_INVALID_FID) {
1666 PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n"));
1667 pcan_p->glds_norcvbuf++;
1668 ret = PCAN_FAIL;
1669 goto done;
1670 }
1671 if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
1672 PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret));
1673 goto done;
1674 }
1675 off = sizeof (frm);
1676 if (frm.an_rx_status) {
1677 PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status));
1678 ret = frm.an_rx_status;
1679 goto done;
1680 }
1681 PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n",
1682 frm.an_rx_payload_len, frm.an_gaplen));
1683 if (frm.an_rx_payload_len > PCAN_NICMEM_SZ ||
1684 frm.an_gaplen > AN_RXGAP_MAX) {
1685 PCANDBG((CE_NOTE, "pcan rcv: bad len\n"));
1686 ret = PCAN_FAIL;
1687 goto done;
1688 }
1689 if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) {
1690 PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret));
1691 ret = PCAN_FAIL;
1692 goto done;
1693 }
1694 off += sizeof (pkt_stat);
1695 if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) {
1696 PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret));
1697 ret = PCAN_FAIL;
1698 goto done;
1699 }
1700 off += sizeof (data_len);
1701 off += ETHERADDRL << 1;
1702 PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n",
1703 pkt_stat, data_len, off));
1704
1705 #ifdef DEBUG
1706 if (pcan_debug & PCAN_DBG_RCV) {
1707 int i;
1708 cmn_err(CE_NOTE, "pcan rcv: frm header\n");
1709 for (i = 0; i < sizeof (frm); i++)
1710 cmn_err(CE_NOTE, "%x: %x\n", i,
1711 *((uint8_t *)&frm + i));
1712 }
1713 #endif
1714 /*
1715 * this driver deal with WEP by itself. so plugin always thinks no wep.
1716 */
1717 frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
1718 frm_ctl = frm.an_frame_ctl;
1719 PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl,
1720 sizeof (struct ieee80211_frame));
1721 /*
1722 * discard those frames which are not from the AP we connect or
1723 * without 'ap->sta' direction
1724 */
1725 if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) &&
1726 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
1727 IEEE80211_FC1_DIR_FROMDS) ||
1728 bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) {
1729 ret = PCAN_FAIL;
1730 goto done;
1731 }
1732 bcopy(&frm.an_frame_ctl, mp->b_wptr,
1733 sizeof (struct ieee80211_frame));
1734 mp->b_wptr += sizeof (struct ieee80211_frame);
1735
1736 /* the plugin need a llc here */
1737 llc = (struct ieee80211_llc *)mp->b_wptr;
1738 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
1739 llc->illc_control = AN_SNAP_CONTROL;
1740 bzero(llc->illc_oc, sizeof (llc->illc_oc));
1741 mp->b_wptr += AN_SNAPHDR_LEN;
1742
1743 /* read in the rest of data */
1744 data_len += data_len & 1; /* adjust to word boundary */
1745 if (data_len > MBLKSIZE(mp)) {
1746 cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len);
1747 ret = PCAN_FAIL;
1748 goto done;
1749 }
1750
1751 if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) {
1752 PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret));
1753 }
1754 done:
1755 if (ret) {
1756 PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret));
1757 freemsg(mp);
1758 return;
1759 }
1760 mp->b_wptr += data_len;
1761 #ifdef DEBUG
1762 if (pcan_debug & PCAN_DBG_RCV) {
1763 int i;
1764 cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len);
1765 for (i = 0; i < data_len + sizeof (frm); i++)
1766 cmn_err(CE_NOTE, "%x: %x\n", i,
1767 *((uint8_t *)mp->b_rptr + i));
1768 }
1769 #endif
1770 mutex_exit(&pcan_p->pcan_glock);
1771 mac_rx(GLD3(pcan_p), NULL, mp);
1772 mutex_enter(&pcan_p->pcan_glock);
1773 }
1774
1775 /*
1776 * retrieve data from mini-pci card
1777 */
1778 static void
pcian_rcv(pcan_maci_t * pcan_p)1779 pcian_rcv(pcan_maci_t *pcan_p)
1780 {
1781 struct an_card_rx_desc an_rx_desc;
1782 char *buf;
1783 uint16_t ret = 0, data_len;
1784 int i, j;
1785 struct ieee80211_frame *frm;
1786 struct ieee80211_llc *llc;
1787
1788 mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED);
1789 if (!mp) {
1790 cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf");
1791 pcan_p->glds_norcvbuf++;
1792 return;
1793 }
1794 ASSERT(mp->b_rptr == mp->b_wptr);
1795
1796 for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
1797 PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
1798 ((uint32_t *)&an_rx_desc)[i]);
1799 if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
1800 buf = pcan_p->pcan_rx[0].dma_virtaddr;
1801 data_len = an_rx_desc.an_len;
1802 #ifdef DEBUG
1803 if (pcan_debug & PCAN_DBG_RCV) {
1804 cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x",
1805 data_len);
1806 for (j = 0; j < data_len + 14; j++)
1807 cmn_err(CE_NOTE, "pcan_rcv %d: %x", j,
1808 *((uint8_t *)buf + j));
1809 }
1810 #endif
1811 if (data_len > MBLKSIZE(mp)) {
1812 cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n",
1813 data_len);
1814 ret = PCAN_FAIL;
1815 goto done;
1816 }
1817 /*
1818 * minipci card receive an ethernet frame, so assembly a 802.11
1819 * frame here manually.
1820 */
1821 frm = (struct ieee80211_frame *)mp->b_wptr;
1822 bzero(frm, sizeof (*frm));
1823 frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
1824 frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
1825 bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6);
1826 bcopy(buf, frm->i_addr1, 6);
1827 bcopy(buf + 6, frm->i_addr3, 6);
1828 mp->b_wptr += sizeof (struct ieee80211_frame);
1829
1830 llc = (struct ieee80211_llc *)mp->b_wptr;
1831 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
1832 llc->illc_control = AN_SNAP_CONTROL;
1833 bzero(llc->illc_oc, sizeof (llc->illc_oc));
1834 mp->b_wptr += AN_SNAPHDR_LEN;
1835
1836 bcopy(buf + 12, mp->b_wptr, data_len);
1837 mp->b_wptr += data_len;
1838 #ifdef DEBUG
1839 if (pcan_debug & PCAN_DBG_RCV) {
1840 int i;
1841 cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len);
1842 for (i = 0; i < data_len + sizeof (*frm)
1843 + sizeof (*llc); i++)
1844 cmn_err(CE_NOTE, "%x: %x\n", i,
1845 *((uint8_t *)mp->b_rptr + i));
1846 }
1847 #endif
1848 mutex_exit(&pcan_p->pcan_glock);
1849 mac_rx(GLD3(pcan_p), NULL, mp);
1850 mutex_enter(&pcan_p->pcan_glock);
1851 }
1852 done:
1853 bzero(&an_rx_desc, sizeof (an_rx_desc));
1854 an_rx_desc.an_valid = 1;
1855 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
1856 an_rx_desc.an_done = 0;
1857 an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr;
1858
1859 for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
1860 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
1861 ((uint32_t *)&an_rx_desc)[i]);
1862 if (ret) {
1863 freemsg(mp);
1864 }
1865 }
1866
1867 /*ARGSUSED*/
1868 static uint32_t
pcan_txdone(pcan_maci_t * pcan_p,uint16_t err)1869 pcan_txdone(pcan_maci_t *pcan_p, uint16_t err)
1870 {
1871 uint16_t fid, i, ring_idx;
1872 uint32_t ret = 0;
1873
1874 PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid);
1875 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
1876 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1877 if (pcan_p->pcan_flag & PCAN_CARD_SEND) {
1878 ring_idx = pcan_p->pcan_txring.an_tx_cons;
1879 pcan_p->pcan_txring.an_tx_cons =
1880 (ring_idx + 1) % AN_MAX_TX_DESC;
1881 if (pcan_p->pcan_txring.an_tx_prod ==
1882 pcan_p->pcan_txring.an_tx_cons) {
1883 pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
1884 }
1885 }
1886 ret = 0;
1887 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1888 for (i = 0; i < AN_TX_RING_CNT; i++) {
1889 if (fid == pcan_p->pcan_txring.an_tx_ring[i]) {
1890 pcan_p->pcan_txring.an_tx_ring[i] = 0;
1891 break;
1892 }
1893 }
1894 pcan_p->pcan_txring.an_tx_cons =
1895 (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK;
1896 ret = (i == AN_TX_RING_CNT ? 1 : 0);
1897 }
1898 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
1899 return (ret);
1900 }
1901
1902 /*
1903 * delay in which the mutex is not hold.
1904 * assuming the mutex has already been hold.
1905 */
1906 static void
pcan_delay(pcan_maci_t * pcan_p,clock_t microsecs)1907 pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs)
1908 {
1909 ASSERT(mutex_owned(&pcan_p->pcan_glock));
1910
1911 mutex_exit(&pcan_p->pcan_glock);
1912 delay(drv_usectohz(microsecs));
1913 mutex_enter(&pcan_p->pcan_glock);
1914 }
1915
1916 static void
pcan_reset_backend(pcan_maci_t * pcan_p,int timeout)1917 pcan_reset_backend(pcan_maci_t *pcan_p, int timeout)
1918 {
1919 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1920 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
1921 PCAN_DISABLE_INTR_CLEAR(pcan_p);
1922 (void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0);
1923 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0);
1924 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
1925 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
1926 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
1927 (void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0);
1928 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART);
1929 pcan_delay(pcan_p, timeout); /* wait for firmware restart */
1930
1931 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0);
1932 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
1933
1934 PCAN_DISABLE_INTR_CLEAR(pcan_p);
1935 }
1936 }
1937
1938 /*
1939 * set command without the need of ACK.
1940 */
1941 static uint16_t
pcan_set_cmd0(pcan_maci_t * pcan_p,uint16_t cmd,uint16_t p0,uint16_t p1,uint16_t p2)1942 pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0,
1943 uint16_t p1, uint16_t p2)
1944 {
1945 int i;
1946 uint16_t stat, r0, r1, r2;
1947
1948 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1949 for (i = 0; i < AN_TIMEOUT; i++) {
1950 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1951 if (!(stat & AN_CMD_BUSY))
1952 break;
1953 }
1954 if (i == AN_TIMEOUT) {
1955 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
1956 AN_EV_CLR_STUCK_BUSY);
1957 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1958 drv_usecwait(10);
1959 }
1960 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0);
1961 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1);
1962 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2);
1963 }
1964 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
1965 for (i = 0; i < AN_TIMEOUT; i++) {
1966 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
1967 if (stat & AN_EV_CMD)
1968 break;
1969 }
1970 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
1971 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
1972 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
1973 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
1974 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
1975 if (stat & AN_CMD_BUSY)
1976 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
1977 AN_EV_CLR_STUCK_BUSY);
1978 PCANDBG((CE_NOTE, "pcan set_cmd0: "
1979 "stat=%x, r0=%x, r1=%x, r2=%x\n",
1980 stat, r0, r1, r2));
1981 }
1982 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
1983 return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS);
1984 }
1985
1986 static uint16_t
pcan_set_cmd(pcan_maci_t * pcan_p,uint16_t cmd,uint16_t param)1987 pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param)
1988 {
1989 int i;
1990 uint16_t stat, r0, r1, r2;
1991 uint16_t ret;
1992
1993 if (((cmd == AN_CMD_ENABLE) &&
1994 ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) ||
1995 ((cmd == AN_CMD_DISABLE) &&
1996 ((pcan_p->pcan_flag & PCAN_ENABLED) == 0)))
1997 return (PCAN_SUCCESS);
1998 for (i = 0; i < AN_TIMEOUT; i++) {
1999 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2000 if (!(stat & AN_CMD_BUSY)) {
2001 break;
2002 }
2003 }
2004 if (i == AN_TIMEOUT) {
2005 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
2006 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2007 drv_usecwait(10);
2008 }
2009
2010 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param);
2011 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0);
2012 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0);
2013 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
2014
2015 for (i = 0; i < AN_TIMEOUT; i++) {
2016 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
2017 if (stat & AN_EV_CMD) {
2018 break;
2019 }
2020 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2021 if (stat == cmd)
2022 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
2023 }
2024 if (i == AN_TIMEOUT) {
2025 if (cmd == AN_CMD_FW_RESTART) {
2026 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2027 return (PCAN_SUCCESS);
2028 }
2029 #ifdef DEBUG
2030 if (pcan_debug & PCAN_DBG_CMD) {
2031 cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n",
2032 cmd, stat);
2033 }
2034 #endif
2035 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2036 return (PCAN_TIMEDOUT_CMD);
2037 }
2038
2039 for (i = 0; i < AN_TIMEOUT; i++) {
2040 PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat);
2041 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
2042 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
2043 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
2044 if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
2045 break;
2046 }
2047 if (cmd == AN_CMD_FW_RESTART) {
2048 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2049 return (PCAN_SUCCESS);
2050 }
2051 if (i == AN_TIMEOUT) {
2052 #ifdef DEBUG
2053 if (pcan_debug & PCAN_DBG_CMD) {
2054 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout "
2055 "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2);
2056 }
2057 #endif
2058 ret = PCAN_TIMEDOUT_ACCESS;
2059 } else {
2060 if (stat & AN_STAT_CMD_RESULT) {
2061 #ifdef DEBUG
2062 if (pcan_debug & PCAN_DBG_CMD) {
2063 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed "
2064 "%x,%x,%x,%x\n",
2065 cmd, param, stat, r0, r1, r2);
2066 }
2067 #endif
2068 ret = PCAN_TIMEDOUT_ACCESS;
2069 } else {
2070 ret = PCAN_SUCCESS;
2071 }
2072 }
2073 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
2074 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2075 if (stat & AN_CMD_BUSY)
2076 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
2077 if (ret == PCAN_SUCCESS) {
2078 if (cmd == AN_CMD_ENABLE)
2079 pcan_p->pcan_flag |= PCAN_ENABLED;
2080 if (cmd == AN_CMD_DISABLE)
2081 pcan_p->pcan_flag &= (~PCAN_ENABLED);
2082 }
2083 return (ret);
2084 }
2085
2086 static uint16_t
pcan_set_ch(pcan_maci_t * pcan_p,uint16_t type,uint16_t off,uint16_t channel)2087 pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel)
2088 {
2089 int i;
2090 uint16_t stat, select, offset;
2091
2092 if (channel) {
2093 select = AN_SEL1;
2094 offset = AN_OFF1;
2095 } else {
2096 select = AN_SEL0;
2097 offset = AN_OFF0;
2098 }
2099 PCAN_WRITE(pcan_p, select, type);
2100 PCAN_WRITE(pcan_p, offset, off);
2101 for (i = 0; i < AN_TIMEOUT; i++) {
2102 PCAN_READ(pcan_p, offset, stat);
2103 if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR)))
2104 break;
2105 }
2106 if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */
2107 PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n",
2108 channel, type, off, stat));
2109 return (PCAN_TIMEDOUT_TARGET);
2110 }
2111 return (PCAN_SUCCESS);
2112 }
2113
2114 static uint16_t
pcan_get_ltv(pcan_maci_t * pcan_p,uint16_t len,uint16_t type,uint16_t * val_p)2115 pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
2116 {
2117 uint16_t stat;
2118
2119 PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n",
2120 (void *)pcan_p, len, type, (void *)val_p));
2121 ASSERT(!(len & 1));
2122
2123 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
2124 uint32_t i;
2125 struct an_card_rid_desc an_rid_desc;
2126 struct an_ltv_gen *an_ltv;
2127 if (!pcan_p->pcan_cmd.dma_virtaddr)
2128 return (EIO);
2129 an_rid_desc.an_valid = 1;
2130 an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
2131 an_rid_desc.an_rid = 0;
2132 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2133 bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE);
2134
2135 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2136 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2137 ((uint32_t *)&an_rid_desc)[i]);
2138
2139 if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
2140 AN_ACCESS_READ, type, 0, 0)) {
2141 cmn_err(CE_WARN, "pcan get_ltv: set cmd error");
2142 return (EIO);
2143 }
2144
2145 an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr;
2146 #ifdef DEBUG
2147 if (pcan_debug & PCAN_DBG_INFO) {
2148 cmn_err(CE_NOTE, "pcan get_ltv: type=%x,"
2149 "expected len=%d," "actual len=%d",
2150 type, len, an_ltv->an_len);
2151 for (i = 0; i < an_ltv->an_len; i++)
2152 cmn_err(CE_NOTE, "%d: %x", i,
2153 *(((uint8_t *)an_ltv) + i));
2154 }
2155 #endif
2156 if (an_ltv->an_len != len) {
2157 PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d"
2158 "actual: len=%d", type,
2159 len, an_ltv->an_len));
2160 /* return (EIO); */
2161 }
2162 bcopy(an_ltv, val_p, len);
2163 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
2164 len >>= 1; /* convert bytes to 16-bit words */
2165
2166 /* 1. select read mode */
2167 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2168 AN_ACCESS_READ, type))
2169 return (stat);
2170
2171 /* 2. select Buffer Access Path (channel) 1 for PIO */
2172 if (stat = pcan_set_ch(pcan_p, type, 0, 1))
2173 return (stat);
2174
2175 /* 3. read length */
2176 PCAN_READ(pcan_p, AN_DATA1, stat);
2177 *val_p++ = stat;
2178 if (stat != (len << 1)) {
2179 PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x,"
2180 "got %x\n", type, (len + 1) << 1, stat));
2181 stat = (stat >> 1) - 1;
2182 len = MIN(stat, len);
2183 }
2184 /* 4. read value */
2185 for (stat = 0; stat < len - 1; stat++, val_p++) {
2186 PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1);
2187 }
2188 }
2189 return (PCAN_SUCCESS);
2190 }
2191
2192 static uint16_t
pcan_put_ltv(pcan_maci_t * pcan_p,uint16_t len,uint16_t type,uint16_t * val_p)2193 pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
2194 {
2195 uint16_t stat;
2196 int i;
2197
2198 ASSERT(!(len & 1));
2199
2200 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
2201 struct an_card_rid_desc an_rid_desc;
2202
2203 for (i = 0; i < AN_TIMEOUT; i++) {
2204 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
2205 if (!(stat & AN_CMD_BUSY)) {
2206 break;
2207 }
2208 }
2209 if (i == AN_TIMEOUT) {
2210 cmn_err(CE_WARN, "pcan put_ltv: busy");
2211 }
2212
2213 an_rid_desc.an_valid = 1;
2214 an_rid_desc.an_len = len;
2215 an_rid_desc.an_rid = type;
2216 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2217
2218 bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr,
2219 an_rid_desc.an_len);
2220
2221 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2222 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2223 ((uint32_t *)&an_rid_desc)[i]);
2224 pcan_delay(pcan_p, 100000);
2225 stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
2226 AN_ACCESS_WRITE, type, 0, 0);
2227 pcan_delay(pcan_p, 100000);
2228 return (stat);
2229 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
2230 /* 0. select read mode first */
2231 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2232 AN_ACCESS_READ, type))
2233 return (stat);
2234
2235 /* 1. select Buffer Access Path (channel) 1 for PIO */
2236 if (stat = pcan_set_ch(pcan_p, type, 0, 1))
2237 return (stat);
2238
2239 /* 2. write length */
2240 len >>= 1; /* convert bytes to 16-bit words */
2241 stat = len;
2242 PCAN_WRITE(pcan_p, AN_DATA1, stat);
2243
2244 /* 3. write value */
2245 val_p++;
2246 for (stat = 0; stat < len-1; stat++, val_p++) {
2247 PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1);
2248 }
2249
2250 /* 4. select write mode */
2251 return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
2252 AN_ACCESS_WRITE, type));
2253 }
2254 return (PCAN_FAIL);
2255 }
2256
2257 /*ARGSUSED*/
2258 static uint16_t
pcan_rdch0(pcan_maci_t * pcan_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)2259 pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
2260 int len, int order)
2261 {
2262 ASSERT(!(len & 1));
2263
2264 if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS)
2265 return (PCAN_FAIL);
2266 len >>= 1;
2267 for (off = 0; off < len; off++, buf_p++) {
2268 PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order);
2269 }
2270 return (PCAN_SUCCESS);
2271 }
2272
2273 /*ARGSUSED*/
2274 static uint16_t
pcan_wrch1(pcan_maci_t * pcan_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)2275 pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
2276 int len, int order)
2277 {
2278 ASSERT(!(len & 1));
2279
2280 if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS)
2281 return (PCAN_FAIL);
2282 len >>= 1;
2283 for (off = 0; off < len; off++, buf_p++) {
2284 PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order);
2285 }
2286 return (PCAN_SUCCESS);
2287 }
2288
2289 static uint16_t
pcan_status_ltv(int rw,pcan_maci_t * pcan_p,struct an_ltv_status * status_p)2290 pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p)
2291 {
2292 uint16_t ret, len;
2293
2294 if (rw != PCAN_READ_LTV) {
2295 cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw);
2296 return (PCAN_FAIL);
2297 }
2298 if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS,
2299 (uint16_t *)status_p))
2300 return (ret);
2301
2302 PCAN_SWAP16_BUF(status_p->an_macaddr);
2303 PCAN_SWAP16_BUF(status_p->an_ssid);
2304 len = min(status_p->an_ssidlen, 31);
2305 status_p->an_ssid[len] = '\0';
2306 PCAN_SWAP16_BUF(status_p->an_ap_name);
2307 PCAN_SWAP16_BUF(status_p->an_cur_bssid);
2308 PCAN_SWAP16_BUF(status_p->an_prev_bssid1);
2309 PCAN_SWAP16_BUF(status_p->an_prev_bssid2);
2310 PCAN_SWAP16_BUF(status_p->an_prev_bssid3);
2311 PCAN_SWAP16_BUF(status_p->an_ap_ip_address);
2312 PCAN_SWAP16_BUF(status_p->an_carrier);
2313 return (PCAN_SUCCESS);
2314 }
2315
2316 static uint16_t
pcan_cfg_ltv(int rw,pcan_maci_t * pcan_p,struct an_ltv_genconfig * cfg_p)2317 pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p)
2318 {
2319 uint16_t ret;
2320 uint16_t rid = cfg_p == &pcan_p->an_config ?
2321 AN_RID_GENCONFIG : AN_RID_ACTUALCFG;
2322
2323 if (rw == PCAN_READ_LTV) {
2324 if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid,
2325 (uint16_t *)cfg_p))
2326 return (ret);
2327 goto done;
2328 }
2329 PCAN_SWAP16_BUF(cfg_p->an_macaddr);
2330 PCAN_SWAP16_BUF(cfg_p->an_rates);
2331 if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p),
2332 rid, (uint16_t *)cfg_p))
2333 return (ret);
2334 done:
2335 PCAN_SWAP16_BUF(cfg_p->an_macaddr);
2336 PCAN_SWAP16_BUF(cfg_p->an_rates);
2337 return (ret);
2338 }
2339
2340 static uint16_t
pcan_cap_ltv(int rw,pcan_maci_t * pcan_p)2341 pcan_cap_ltv(int rw, pcan_maci_t *pcan_p)
2342 {
2343 uint16_t ret;
2344
2345 if (rw != PCAN_READ_LTV) {
2346 cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw);
2347 return (PCAN_FAIL);
2348 }
2349 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps),
2350 AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps))
2351 return (ret);
2352
2353 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui);
2354 PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname);
2355 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname);
2356 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers);
2357 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr);
2358 PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr);
2359 PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid);
2360 PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates);
2361 return (PCAN_SUCCESS);
2362 }
2363
2364 static uint16_t
pcan_ssid_ltv(int rw,pcan_maci_t * pcan_p)2365 pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p)
2366 {
2367 uint16_t ret;
2368
2369 if (rw == PCAN_READ_LTV) {
2370 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
2371 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
2372 return (ret);
2373 goto done;
2374 }
2375 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
2376 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
2377 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
2378 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
2379 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
2380 return (ret);
2381 done:
2382 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
2383 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
2384 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
2385 return (ret);
2386 }
2387
2388 static uint16_t
pcan_aplist_ltv(int rw,pcan_maci_t * pcan_p)2389 pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p)
2390 {
2391 uint16_t ret;
2392
2393 if (rw == PCAN_READ_LTV) {
2394 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist),
2395 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
2396 return (ret);
2397 goto done;
2398 }
2399 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
2400 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
2401 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
2402 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
2403 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist),
2404 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
2405 return (ret);
2406 done:
2407 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
2408 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
2409 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
2410 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
2411 return (ret);
2412 }
2413
2414 static uint16_t
pcan_scanresult_ltv(int rw,pcan_maci_t * pcan_p,uint16_t type,struct an_ltv_scanresult * scanresult_p)2415 pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type,
2416 struct an_ltv_scanresult *scanresult_p)
2417 {
2418 uint16_t ret, len;
2419 if (rw != PCAN_READ_LTV) {
2420 cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type);
2421 return (PCAN_FAIL);
2422 }
2423 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult),
2424 type, (uint16_t *)scanresult_p))
2425 return (ret);
2426 PCAN_SWAP16_BUF(scanresult_p->an_bssid);
2427 PCAN_SWAP16_BUF(scanresult_p->an_ssid);
2428 len = min(scanresult_p->an_ssidlen, 31);
2429 scanresult_p->an_ssid[len] = '\0';
2430 PCAN_SWAP16_BUF(scanresult_p->an_rates);
2431 return (PCAN_SUCCESS);
2432 }
2433
2434 static uint16_t
pcan_one_wepkey(int rw,pcan_maci_t * pcan_p,struct an_ltv_wepkey * wkp,uint16_t rid)2435 pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp,
2436 uint16_t rid)
2437 {
2438 uint16_t ret;
2439
2440 if (rw == PCAN_READ_LTV) {
2441 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
2442 rid, (uint16_t *)wkp)) {
2443 return (ret);
2444 }
2445 goto done;
2446 }
2447 PCAN_SWAP16_BUF(wkp->an_macaddr);
2448 PCAN_SWAP16_BUF(wkp->an_key);
2449 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
2450 rid, (uint16_t *)wkp))
2451 return (ret);
2452 done:
2453 PCAN_SWAP16_BUF(wkp->an_macaddr);
2454 PCAN_SWAP16_BUF(wkp->an_key);
2455 return (ret);
2456 }
2457
2458 static uint16_t
pcan_wepkey_ltv(int rw,pcan_maci_t * pcan_p)2459 pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p)
2460 {
2461 uint16_t ret, i;
2462 struct an_ltv_wepkey wk;
2463
2464 if (rw == PCAN_READ_LTV) {
2465 uint16_t rid = AN_RID_WEPKEY2;
2466
2467 if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid))
2468 return (ret);
2469 for (i = 0; i < 5; i++) {
2470 if (wk.an_index < 4)
2471 pcan_p->an_wepkey[wk.an_index] = wk;
2472 else if (wk.an_index == 0xffff)
2473 pcan_p->an_cur_wepkey = wk.an_macaddr[0];
2474 rid = AN_RID_WEPKEY;
2475 }
2476 return (PCAN_SUCCESS);
2477 }
2478 for (i = 0; i < MAX_NWEPKEYS; i++) {
2479 if (pcan_p->an_wepkey[i].an_index == i) {
2480 if (ret = pcan_one_wepkey(rw, pcan_p,
2481 &pcan_p->an_wepkey[i], AN_RID_WEPKEY2))
2482 return (ret);
2483 }
2484 }
2485 /* Now set the default key */
2486 (void) memset(&wk, 0, sizeof (wk));
2487 wk.an_index = 0xffff;
2488 wk.an_macaddr[0] = pcan_p->an_cur_wepkey;
2489 ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2);
2490 return (ret);
2491 }
2492
2493 static uint16_t
pcan_alloc_nicmem(pcan_maci_t * pcan_p,uint16_t len,uint16_t * id_p)2494 pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p)
2495 {
2496 int i;
2497 uint16_t stat;
2498
2499 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */
2500
2501 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len))
2502 return (stat);
2503 for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) {
2504 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
2505 }
2506 if (!(stat & AN_EV_ALLOC))
2507 return (PCAN_TIMEDOUT_ALLOC);
2508 PCAN_READ(pcan_p, AN_ALLOC_FID, stat);
2509 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
2510 *id_p = stat;
2511
2512 /* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */
2513 (void) pcan_set_ch(pcan_p, stat, 0, 0);
2514 for (len >>= 1, stat = 0; stat < len; stat++) {
2515 PCAN_WRITE(pcan_p, AN_DATA0, 0);
2516 }
2517 return (PCAN_SUCCESS);
2518 }
2519
2520 static void
pcan_stop_rx_dma(pcan_maci_t * pcan_p)2521 pcan_stop_rx_dma(pcan_maci_t *pcan_p)
2522 {
2523 int i, j;
2524 struct an_card_rx_desc an_rx_desc;
2525
2526 for (i = 0; i < AN_MAX_RX_DESC; i++) {
2527 bzero(&an_rx_desc, sizeof (an_rx_desc));
2528 an_rx_desc.an_valid = 0;
2529 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
2530 an_rx_desc.an_done = 1;
2531 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
2532 for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
2533 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
2534 + (i * sizeof (an_rx_desc))
2535 + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
2536 }
2537 }
2538
2539 static int
pcan_init_dma_desc(pcan_maci_t * pcan_p)2540 pcan_init_dma_desc(pcan_maci_t *pcan_p)
2541 {
2542 int i, j;
2543 struct an_card_rid_desc an_rid_desc;
2544 struct an_card_rx_desc an_rx_desc;
2545 struct an_card_tx_desc an_tx_desc;
2546
2547 /* Allocate DMA for rx */
2548 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2549 AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET,
2550 AN_MAX_RX_DESC) != PCAN_SUCCESS) {
2551 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor");
2552 goto error;
2553 }
2554 for (i = 0; i < AN_MAX_RX_DESC; i++) {
2555 bzero(&an_rx_desc, sizeof (an_rx_desc));
2556 an_rx_desc.an_valid = 1;
2557 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
2558 an_rx_desc.an_done = 0;
2559 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
2560 for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
2561 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
2562 + (i * sizeof (an_rx_desc))
2563 + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
2564 }
2565
2566
2567 /* Allocate DMA for tx */
2568 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2569 AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET,
2570 AN_MAX_TX_DESC) != PCAN_SUCCESS) {
2571 cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor");
2572 goto error;
2573 }
2574
2575 for (i = 0; i < AN_MAX_TX_DESC; i++) {
2576 an_tx_desc.an_offset = 0;
2577 an_tx_desc.an_eoc = 0;
2578 an_tx_desc.an_valid = 0;
2579 an_tx_desc.an_len = 0;
2580 an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr;
2581
2582 for (j = 0; j < sizeof (an_tx_desc) / 4; j++)
2583 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET
2584 + (i * sizeof (an_tx_desc))
2585 + (j * 4), ((uint32_t *)&an_tx_desc)[j]);
2586 }
2587
2588 /* Allocate DMA for rid */
2589 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
2590 AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) {
2591 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor");
2592 goto error;
2593 }
2594 bzero(&an_rid_desc, sizeof (an_rid_desc));
2595 an_rid_desc.an_valid = 1;
2596 an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
2597 an_rid_desc.an_rid = 0;
2598 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
2599
2600 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
2601 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
2602 ((uint32_t *)&an_rid_desc)[i]);
2603
2604 pcan_p->pcan_txring.an_tx_prod = 0;
2605 pcan_p->pcan_txring.an_tx_cons = 0;
2606 pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
2607 return (PCAN_SUCCESS);
2608 error:
2609 return (PCAN_FAIL);
2610 }
2611
2612 static int
pcan_init_dma(dev_info_t * dip,pcan_maci_t * pcan_p)2613 pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p)
2614 {
2615 int i, ret = PCAN_FAIL;
2616 ddi_dma_cookie_t dma_cookie;
2617 size_t len;
2618
2619 /* Allocate DMA for rx */
2620 for (i = 0; i < AN_MAX_RX_DESC; i++) {
2621 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2622 DDI_DMA_SLEEP, 0,
2623 &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS)
2624 goto error;
2625
2626 if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle,
2627 AN_RX_BUFFER_SIZE, &accattr,
2628 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
2629 (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len,
2630 &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) {
2631 goto error;
2632 }
2633 if (ddi_dma_addr_bind_handle(
2634 pcan_p->pcan_rx[i].dma_handle,
2635 NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr,
2636 len, DDI_DMA_READ |
2637 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
2638 &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) {
2639 goto error;
2640 }
2641 ASSERT(pcan_p->pcan_rx[i].ncookies == 1);
2642 pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address;
2643 }
2644
2645 /* Allocate DMA for tx */
2646 for (i = 0; i < AN_MAX_TX_DESC; i++) {
2647 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2648 DDI_DMA_SLEEP, 0,
2649 &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS)
2650 goto error;
2651
2652 if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle,
2653 AN_TX_BUFFER_SIZE, &accattr,
2654 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
2655 (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len,
2656 &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) {
2657 goto error;
2658 }
2659 if (ddi_dma_addr_bind_handle(
2660 pcan_p->pcan_tx[i].dma_handle,
2661 NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr,
2662 len, DDI_DMA_WRITE |
2663 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
2664 &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) {
2665 goto error;
2666 }
2667 ASSERT(pcan_p->pcan_tx[i].ncookies == 1);
2668 pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address;
2669 }
2670
2671 /* Allocate DMA for rid */
2672 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
2673 DDI_DMA_SLEEP, 0,
2674 &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS)
2675 goto error;
2676
2677 if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle,
2678 AN_RID_BUFFER_SIZE, &accattr,
2679 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
2680 (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len,
2681 &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) {
2682 goto error;
2683 }
2684 if (ddi_dma_addr_bind_handle(
2685 pcan_p->pcan_cmd.dma_handle,
2686 NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr,
2687 len, DDI_DMA_RDWR |
2688 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie,
2689 &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) {
2690 goto error;
2691 }
2692 ASSERT(pcan_p->pcan_cmd.ncookies == 1);
2693 pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address;
2694
2695 if (ret = pcan_init_dma_desc(pcan_p)) {
2696 cmn_err(CE_WARN, "pcan init_dma_desc: failed\n");
2697 goto error;
2698 }
2699
2700 return (PCAN_SUCCESS);
2701 error:
2702 pcan_free_dma(pcan_p);
2703 return (ret);
2704 }
2705
2706 static void
pcan_free_dma(pcan_maci_t * pcan_p)2707 pcan_free_dma(pcan_maci_t *pcan_p)
2708 {
2709 int i;
2710
2711 /* free RX dma */
2712 pcan_stop_rx_dma(pcan_p);
2713 for (i = 0; i < AN_MAX_RX_DESC; i++) {
2714 if (pcan_p->pcan_rx[i].dma_handle != NULL) {
2715 if (pcan_p->pcan_rx[i].ncookies) {
2716 (void) ddi_dma_unbind_handle(
2717 pcan_p->pcan_rx[i].dma_handle);
2718 pcan_p->pcan_rx[i].ncookies = 0;
2719 }
2720 ddi_dma_free_handle(
2721 &pcan_p->pcan_rx[i].dma_handle);
2722 pcan_p->pcan_rx[i].dma_handle = NULL;
2723 }
2724 if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) {
2725 ddi_dma_mem_free(
2726 &pcan_p->pcan_rx[i].dma_acc_handle);
2727 pcan_p->pcan_rx[i].dma_acc_handle = NULL;
2728 }
2729 }
2730
2731 /* free TX dma */
2732 for (i = 0; i < AN_MAX_TX_DESC; i++) {
2733 if (pcan_p->pcan_tx[i].dma_handle != NULL) {
2734 if (pcan_p->pcan_tx[i].ncookies) {
2735 (void) ddi_dma_unbind_handle(
2736 pcan_p->pcan_tx[i].dma_handle);
2737 pcan_p->pcan_tx[i].ncookies = 0;
2738 }
2739 ddi_dma_free_handle(
2740 &pcan_p->pcan_tx[i].dma_handle);
2741 pcan_p->pcan_tx[i].dma_handle = NULL;
2742 }
2743 if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) {
2744 ddi_dma_mem_free(
2745 &pcan_p->pcan_tx[i].dma_acc_handle);
2746 pcan_p->pcan_tx[i].dma_acc_handle = NULL;
2747 }
2748 }
2749
2750 /* free cmd dma */
2751 if (pcan_p->pcan_cmd.dma_handle != NULL) {
2752 if (pcan_p->pcan_cmd.ncookies) {
2753 (void) ddi_dma_unbind_handle(
2754 pcan_p->pcan_cmd.dma_handle);
2755 pcan_p->pcan_cmd.ncookies = 0;
2756 }
2757 ddi_dma_free_handle(
2758 &pcan_p->pcan_cmd.dma_handle);
2759 pcan_p->pcan_cmd.dma_handle = NULL;
2760 }
2761 if (pcan_p->pcan_cmd.dma_acc_handle != NULL) {
2762 ddi_dma_mem_free(
2763 &pcan_p->pcan_cmd.dma_acc_handle);
2764 pcan_p->pcan_cmd.dma_acc_handle = NULL;
2765 }
2766 }
2767
2768 /*
2769 * get card capability (WEP, default channel), setup broadcast, mac addresses
2770 */
2771 static uint32_t
pcan_get_cap(pcan_maci_t * pcan_p)2772 pcan_get_cap(pcan_maci_t *pcan_p)
2773 {
2774 uint16_t stat;
2775
2776 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) {
2777 PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat));
2778 return ((uint32_t)AN_RID_GENCONFIG << 16 | stat);
2779 }
2780
2781 if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) {
2782 PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat));
2783 return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat);
2784 }
2785 #ifdef DEBUG
2786 if (pcan_debug & PCAN_DBG_FW_VERSION) {
2787 cmn_err(CE_NOTE, "the version of the firmware in the wifi card "
2788 "'%s %s %s' is %s\n",
2789 pcan_p->an_caps.an_manufname,
2790 pcan_p->an_caps.an_prodname,
2791 pcan_p->pcan_device_type == PCAN_DEVICE_PCI ?
2792 "minipci" : "pccard",
2793 pcan_p->an_caps.an_prodvers);
2794 }
2795 #endif
2796
2797 if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) {
2798 PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat));
2799 return ((uint32_t)AN_RID_SSIDLIST << 16 | stat);
2800 }
2801
2802 if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) {
2803 PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat));
2804 return ((uint32_t)AN_RID_APLIST << 16 | stat);
2805 }
2806 if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) {
2807 PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat));
2808 return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat);
2809 }
2810 ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr);
2811 return (PCAN_SUCCESS);
2812 }
2813
2814 static int
pcan_config_mac(pcan_maci_t * pcan_p)2815 pcan_config_mac(pcan_maci_t *pcan_p)
2816 {
2817 uint16_t stat;
2818
2819 if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) {
2820 PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n",
2821 stat));
2822 return ((int)stat);
2823 }
2824
2825 if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) {
2826 PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n",
2827 stat));
2828 return ((int)stat);
2829 }
2830 if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) {
2831 PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n",
2832 stat));
2833 return ((int)stat);
2834 }
2835 if (pcan_p->pcan_usewep)
2836 pcan_p->an_config.an_authtype |=
2837 AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED;
2838 PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n",
2839 pcan_p->pcan_usewep, pcan_p->an_config.an_authtype,
2840 pcan_p->an_config.an_opmode));
2841
2842 pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */
2843 if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) {
2844 PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n",
2845 stat));
2846 return ((int)stat);
2847 }
2848
2849 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p,
2850 &pcan_p->an_actual_config)) {
2851 PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n",
2852 stat));
2853 return ((int)stat);
2854 }
2855 PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0,
2856 pcan_p->an_actual_config.an_authtype));
2857
2858 if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
2859 PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n",
2860 stat));
2861 return ((int)stat);
2862 }
2863 return (PCAN_SUCCESS);
2864 }
2865
2866 static int
pcan_loaddef(pcan_maci_t * pcan_p)2867 pcan_loaddef(pcan_maci_t *pcan_p)
2868 {
2869 int i;
2870
2871 pcan_p->an_ssidlist.an_ssid1_len = 0;
2872 bzero(pcan_p->an_ssidlist.an_ssid1,
2873 sizeof (pcan_p->an_ssidlist.an_ssid1));
2874 for (i = 0; i < MAX_NWEPKEYS; i++) {
2875 pcan_p->an_wepkey[i].an_index = 0xffff;
2876 bzero(pcan_p->an_wepkey[i].an_key,
2877 sizeof (pcan_p->an_wepkey[i].an_key));
2878 pcan_p->an_wepkey[i].an_keylen = 0;
2879 bzero(pcan_p->an_wepkey[i].an_macaddr,
2880 sizeof (pcan_p->an_wepkey[i].an_macaddr));
2881 pcan_p->an_wepkey[i].an_macaddr[0] = 1;
2882 }
2883 pcan_p->an_cur_wepkey = 0;
2884
2885 pcan_p->pcan_usewep = 0;
2886 pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION;
2887 pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN;
2888 pcan_p->an_config.an_stationary = 1;
2889 pcan_p->an_config.an_max_beacon_lost_time = 0xffff;
2890 i = pcan_config_mac(pcan_p);
2891
2892 return (i);
2893 }
2894
2895 static int
pcan_init_nicmem(pcan_maci_t * pcan_p)2896 pcan_init_nicmem(pcan_maci_t *pcan_p)
2897 {
2898 int i;
2899 uint16_t ret;
2900 pcan_txring_t *ring_p = &pcan_p->pcan_txring;
2901
2902 for (i = 0; i < AN_TX_RING_CNT; i++) {
2903 uint16_t rc;
2904 ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc);
2905 if (ret) {
2906 cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed "
2907 "%x\n", i, ret);
2908 return (DDI_FAILURE);
2909 }
2910 ring_p->an_tx_fids[i] = rc;
2911 ring_p->an_tx_ring[i] = 0;
2912 PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc));
2913 }
2914 ring_p->an_tx_prod = ring_p->an_tx_cons = 0;
2915 return (PCAN_SUCCESS);
2916 }
2917
2918
2919
2920 static void
pcan_start_locked(pcan_maci_t * pcan_p)2921 pcan_start_locked(pcan_maci_t *pcan_p)
2922 {
2923 pcan_p->pcan_flag |= PCAN_CARD_INTREN;
2924 PCAN_ENABLE_INTR(pcan_p);
2925 }
2926
2927 static void
pcan_stop_locked(pcan_maci_t * pcan_p)2928 pcan_stop_locked(pcan_maci_t *pcan_p)
2929 {
2930 PCAN_DISABLE_INTR_CLEAR(pcan_p);
2931 pcan_p->pcan_flag &= ~PCAN_CARD_INTREN;
2932 }
2933
2934 /*
2935 * for scan result
2936 */
2937 static int
pcan_add_scan_item(pcan_maci_t * pcan_p,struct an_ltv_scanresult s)2938 pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s)
2939 {
2940 an_scan_list_t *scan_item;
2941
2942 scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP);
2943 if (scan_item == NULL) {
2944 cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n");
2945 return (PCAN_FAIL);
2946 }
2947 scan_item->an_val = s;
2948 scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX;
2949 list_insert_tail(&pcan_p->an_scan_list, scan_item);
2950 pcan_p->an_scan_num++;
2951 return (PCAN_SUCCESS);
2952 }
2953
2954 static void
pcan_delete_scan_item(pcan_maci_t * pcan_p,an_scan_list_t * s)2955 pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s)
2956 {
2957 list_remove(&pcan_p->an_scan_list, s);
2958 kmem_free(s, sizeof (*s));
2959 pcan_p->an_scan_num--;
2960 }
2961
2962 static void
pcan_scanlist_timeout(void * arg)2963 pcan_scanlist_timeout(void *arg)
2964 {
2965 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
2966 an_scan_list_t *scan_item0, *scan_item1;
2967
2968 mutex_enter(&pcan_p->pcan_scanlist_lock);
2969 scan_item0 = list_head(&pcan_p->an_scan_list);
2970 for (; scan_item0; ) {
2971 PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n",
2972 scan_item0->an_val.an_ssid));
2973 PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds",
2974 scan_item0->an_timeout));
2975 scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0);
2976 if (scan_item0->an_timeout == 0) {
2977 pcan_delete_scan_item(pcan_p, scan_item0);
2978 } else {
2979 scan_item0->an_timeout--;
2980 }
2981 scan_item0 = scan_item1;
2982 }
2983 mutex_exit(&pcan_p->pcan_scanlist_lock);
2984 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
2985 pcan_p, drv_usectohz(1000000));
2986 }
2987
2988 /*
2989 * Brussels support
2990 */
2991 /*
2992 * MAC_PROP_WL_ESSID
2993 */
2994 static int
pcan_set_essid(pcan_maci_t * pcan_p,const void * wldp_buf)2995 pcan_set_essid(pcan_maci_t *pcan_p, const void *wldp_buf)
2996 {
2997 char *value;
2998 struct an_ltv_ssidlist *ssidlist_p;
2999 wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
3000
3001 ssidlist_p = &pcan_p->an_ssidlist;
3002 bzero(ssidlist_p, sizeof (*ssidlist_p));
3003 value = iw_essid->wl_essid_essid;
3004 (void) strncpy(ssidlist_p->an_ssid1, value,
3005 MIN(32, strlen(value)));
3006 ssidlist_p->an_ssid1_len = strlen(value);
3007
3008 return (ENETRESET);
3009 }
3010
3011 static int
pcan_get_essid(pcan_maci_t * pcan_p,void * wldp_buf)3012 pcan_get_essid(pcan_maci_t *pcan_p, void *wldp_buf)
3013 {
3014 int err = 0;
3015 struct an_ltv_status *status_p;
3016 wl_essid_t *ow_essid = (wl_essid_t *)wldp_buf;
3017
3018 status_p = &pcan_p->an_status;
3019
3020 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3021 err = EIO;
3022 return (err);
3023 }
3024 ow_essid->wl_essid_length = status_p->an_ssidlen;
3025 bcopy(status_p->an_ssid, ow_essid->wl_essid_essid,
3026 status_p->an_ssidlen);
3027
3028 return (err);
3029 }
3030
3031 /*
3032 * MAC_PROP_WL_BSSID
3033 */
3034 static int
pcan_set_bssid(pcan_maci_t * pcan_p,const void * wldp_buf)3035 pcan_set_bssid(pcan_maci_t *pcan_p, const void *wldp_buf)
3036 {
3037 wl_bssid_t *value;
3038 struct an_ltv_aplist *aplist_p;
3039
3040 aplist_p = &pcan_p->an_aplist;
3041
3042 value = (wl_bssid_t *)wldp_buf;
3043 (void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6);
3044
3045 return (ENETRESET);
3046 }
3047
3048 static int
pcan_get_bssid(pcan_maci_t * pcan_p,void * wldp_buf)3049 pcan_get_bssid(pcan_maci_t *pcan_p, void *wldp_buf)
3050 {
3051 int err = 0;
3052 struct an_ltv_status *status_p;
3053
3054 status_p = &pcan_p->an_status;
3055
3056 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3057 err = EIO;
3058 return (err);
3059 }
3060
3061 bcopy(status_p->an_cur_bssid, wldp_buf, sizeof (wl_bssid_t));
3062 PCANDBG((CE_CONT,
3063 "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n",
3064 status_p->an_cur_bssid[0],
3065 status_p->an_cur_bssid[1],
3066 status_p->an_cur_bssid[2],
3067 status_p->an_cur_bssid[3],
3068 status_p->an_cur_bssid[4],
3069 status_p->an_cur_bssid[5]));
3070
3071 return (err);
3072 }
3073
3074 /*
3075 * MAC_PROP_WL_LINKSTATUS
3076 */
3077 static void
pcan_get_linkstatus(pcan_maci_t * pcan_p,void * wldp_buf)3078 pcan_get_linkstatus(pcan_maci_t *pcan_p, void *wldp_buf)
3079 {
3080 if (pcan_p->pcan_flag & PCAN_CARD_LINKUP)
3081 *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
3082 else
3083 *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
3084
3085 }
3086
3087 /*
3088 * MAC_PROP_WL_BSSTYP
3089 */
3090 static int
pcan_set_bsstype(pcan_maci_t * pcan_p,const void * wldp_buf)3091 pcan_set_bsstype(pcan_maci_t *pcan_p, const void *wldp_buf)
3092 {
3093 struct an_ltv_genconfig *cfg_p;
3094
3095 cfg_p = &pcan_p->an_config;
3096
3097 if (*(wl_bss_type_t *)wldp_buf == WL_BSS_BSS)
3098 cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
3099 if (*(wl_bss_type_t *)wldp_buf == WL_BSS_IBSS)
3100 cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC;
3101 if (*(wl_bss_type_t *)wldp_buf == WL_BSS_ANY)
3102 cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
3103 cfg_p->an_assoc_timeout = 5000;
3104
3105 return (ENETRESET);
3106 }
3107
3108 static void
pcan_get_bsstype(pcan_maci_t * pcan_p,void * wldp_buf)3109 pcan_get_bsstype(pcan_maci_t *pcan_p, void *wldp_buf)
3110 {
3111 struct an_ltv_genconfig *cfg_p;
3112
3113 cfg_p = &pcan_p->an_config;
3114
3115 if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) {
3116 *(wl_bss_type_t *)wldp_buf = WL_BSS_BSS;
3117 } else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) {
3118 *(wl_bss_type_t *)wldp_buf = WL_BSS_IBSS;
3119 }
3120 }
3121
3122 /*
3123 * MAC_PROP_WL_PHY_CONFIG
3124 */
3125 static int
pcan_set_phy(pcan_maci_t * pcan_p,const void * wldp_buf)3126 pcan_set_phy(pcan_maci_t *pcan_p, const void *wldp_buf)
3127 {
3128 uint16_t ret;
3129 int err = ENETRESET;
3130 wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf;
3131 struct an_ltv_genconfig *cfg_p;
3132
3133 cfg_p = &pcan_p->an_config;
3134
3135 ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
3136 if (ret < 1 || ret > 14) {
3137 err = ENOTSUP;
3138 return (err);
3139 }
3140 cfg_p->an_ds_channel = ret;
3141 cfg_p->an_assoc_timeout = 5000;
3142
3143 return (err);
3144 }
3145
3146 static int
pcan_get_phy(pcan_maci_t * pcan_p,void * wldp_buf)3147 pcan_get_phy(pcan_maci_t *pcan_p, void *wldp_buf)
3148 {
3149 int err = 0;
3150 struct an_ltv_status *status_p;
3151 wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf;
3152
3153 status_p = &pcan_p->an_status;
3154
3155 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3156 err = EIO;
3157 return (err);
3158 }
3159
3160 dsss->wl_dsss_channel = status_p->an_channel_set;
3161 dsss->wl_dsss_subtype = WL_DSSS;
3162
3163 return (err);
3164 }
3165
3166 /*
3167 * MAC_PROP_WL_DESIRED_RATESa
3168 */
3169 static int
pcan_set_desrates(pcan_maci_t * pcan_p,const void * wldp_buf)3170 pcan_set_desrates(pcan_maci_t *pcan_p, const void *wldp_buf)
3171 {
3172 uint16_t i;
3173 struct an_ltv_genconfig *cfg_p;
3174
3175 cfg_p = &pcan_p->an_config;
3176
3177 bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates));
3178 for (i = 0; i < ((wl_rates_t *)wldp_buf)->wl_rates_num; i++) {
3179 cfg_p->an_rates[i] =
3180 (((wl_rates_t *)wldp_buf)->wl_rates_rates)[i];
3181 }
3182 cfg_p->an_assoc_timeout = 5000;
3183
3184 return (ENETRESET);
3185 }
3186
3187 static int
pcan_get_desrates(pcan_maci_t * pcan_p,void * wldp_buf)3188 pcan_get_desrates(pcan_maci_t *pcan_p, void *wldp_buf)
3189 {
3190 uint16_t i;
3191 uint8_t rates = 0;
3192 int err = 0;
3193 struct an_ltv_genconfig *actcfg_p;
3194
3195 actcfg_p = &pcan_p->an_actual_config;
3196
3197 if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
3198 err = EIO;
3199 return (err);
3200 }
3201
3202 for (i = 0; i < sizeof (actcfg_p->an_rates); i++) {
3203 if (actcfg_p->an_rates[i] == 0)
3204 break;
3205 rates = MAX(rates, actcfg_p->an_rates[i]);
3206 }
3207 (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = rates;
3208 ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
3209
3210 return (err);
3211 }
3212
3213 /*
3214 * MAC_PROP_WL_SUP_RATE
3215 */
3216 static void
pcan_get_suprates(void * wldp_buf)3217 pcan_get_suprates(void *wldp_buf)
3218 {
3219 wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
3220
3221 wl_rates->wl_rates_num = 4;
3222 wl_rates->wl_rates_rates[0] = WL_RATE_1M;
3223 wl_rates->wl_rates_rates[1] = WL_RATE_2M;
3224 wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
3225 wl_rates->wl_rates_rates[3] = WL_RATE_11M;
3226 }
3227
3228 /*
3229 * MAC_PROP_WL_POWER_MODE
3230 */
3231 static int
pcan_get_powermode(pcan_maci_t * pcan_p,void * wldp_buf)3232 pcan_get_powermode(pcan_maci_t *pcan_p, void *wldp_buf)
3233 {
3234 int err = 0;
3235 wl_ps_mode_t *powermode = (wl_ps_mode_t *)wldp_buf;
3236 struct an_ltv_genconfig *actcfg_p;
3237
3238 actcfg_p = &pcan_p->an_actual_config;
3239 if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
3240 err = EIO;
3241 return (err);
3242 }
3243 powermode->wl_ps_mode = actcfg_p->an_psave_mode;
3244
3245 return (err);
3246 }
3247
3248 /*
3249 * MAC_PROP_AUTH_MODE
3250 */
3251 static int
pcan_set_authmode(pcan_maci_t * pcan_p,const void * wldp_buf)3252 pcan_set_authmode(pcan_maci_t *pcan_p, const void *wldp_buf)
3253 {
3254 struct an_ltv_genconfig *cfg_p;
3255 int err = ENETRESET;
3256
3257 cfg_p = &pcan_p->an_config;
3258 if (*(wl_authmode_t *)wldp_buf == WL_OPENSYSTEM) {
3259 cfg_p->an_authtype |= AN_AUTHTYPE_OPEN;
3260 cfg_p->an_assoc_timeout = 5000;
3261 } else {
3262 err = EINVAL;
3263 }
3264
3265 return (err);
3266 }
3267
3268 static void
pcan_get_authmode(pcan_maci_t * pcan_p,void * wldp_buf)3269 pcan_get_authmode(pcan_maci_t *pcan_p, void *wldp_buf)
3270 {
3271 struct an_ltv_genconfig *cfg_p;
3272
3273 cfg_p = &pcan_p->an_config;
3274 if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) {
3275 *(wl_bss_type_t *)wldp_buf = WL_SHAREDKEY;
3276 } else {
3277 *(wl_bss_type_t *)wldp_buf = WL_OPENSYSTEM;
3278 }
3279 }
3280
3281 /*
3282 * MAC_PROP_WL_ENCRYPTION
3283 */
3284 static int
pcan_set_encrypt(pcan_maci_t * pcan_p,const void * wldp_buf)3285 pcan_set_encrypt(pcan_maci_t *pcan_p, const void *wldp_buf)
3286 {
3287 struct an_ltv_genconfig *cfg_p;
3288
3289 cfg_p = &pcan_p->an_config;
3290 if (*(wl_encryption_t *)wldp_buf == WL_ENC_WEP) {
3291 cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP |
3292 AN_AUTHTYPE_ALLOW_UNENCRYPTED);
3293 pcan_p->pcan_usewep = 1;
3294 }
3295 if (*(wl_authmode_t *)wldp_buf == WL_NOENCRYPTION) {
3296 cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP |
3297 AN_AUTHTYPE_ALLOW_UNENCRYPTED));
3298 pcan_p->pcan_usewep = 0;
3299 }
3300 cfg_p->an_assoc_timeout = 5000;
3301
3302 return (ENETRESET);
3303 }
3304
3305 static void
pcan_get_encrypt(pcan_maci_t * pcan_p,void * wldp_buf)3306 pcan_get_encrypt(pcan_maci_t *pcan_p, void *wldp_buf)
3307 {
3308 struct an_ltv_genconfig *cfg_p;
3309
3310 cfg_p = &pcan_p->an_config;
3311 if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) {
3312 *(wl_bss_type_t *)wldp_buf = WL_ENC_WEP;
3313 } else {
3314 *(wl_bss_type_t *)wldp_buf = WL_NOENCRYPTION;
3315 }
3316 }
3317
3318 /*
3319 * MAC_PROP_WL_KEY_TAB
3320 */
3321 static int
pcan_set_wepkey(pcan_maci_t * pcan_p,const void * wldp_buf)3322 pcan_set_wepkey(pcan_maci_t *pcan_p, const void *wldp_buf)
3323 {
3324 uint16_t i;
3325 wl_wep_key_t *p_wepkey_tab;
3326 struct an_ltv_wepkey *wepkey_p;
3327
3328 p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
3329 for (i = 0; i < MAX_NWEPKEYS; i++) {
3330 if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
3331 wepkey_p = &pcan_p->an_wepkey[i];
3332 bzero(wepkey_p, sizeof (*wepkey_p));
3333 wepkey_p->an_keylen =
3334 p_wepkey_tab[i].wl_wep_length;
3335 bcopy(p_wepkey_tab[i].wl_wep_key,
3336 wepkey_p->an_key,
3337 p_wepkey_tab[i].wl_wep_length);
3338 wepkey_p->an_index = i;
3339 wepkey_p->an_macaddr[0] = 1;
3340 }
3341 }
3342
3343 return (ENETRESET);
3344 }
3345
3346 /*
3347 * MAC_PROP_WL_RSSI
3348 */
3349 static int
pcan_get_rssi(pcan_maci_t * pcan_p,void * wldp_buf)3350 pcan_get_rssi(pcan_maci_t *pcan_p, void *wldp_buf)
3351 {
3352 uint16_t val;
3353 int err = 0;
3354 wl_rssi_t *rssi = (wl_rssi_t *)wldp_buf;
3355 struct an_ltv_status *status_p;
3356
3357 status_p = &pcan_p->an_status;
3358
3359 if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
3360 err = EIO;
3361 return (err);
3362 }
3363 val = status_p->an_cur_signal_quality;
3364 PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val));
3365 /*
3366 * we reflect the value to 1-15 as rssi
3367 */
3368 *rssi = 15 - ((val & 0xff) * 15 / 128 + 1);
3369
3370 return (err);
3371 }
3372
3373 /*
3374 * MAC_PROP_WL_RADIO
3375 */
3376 static void
pcan_get_radio(void * wldp_buf)3377 pcan_get_radio(void *wldp_buf)
3378 {
3379 wl_radio_t *radio = (wl_radio_t *)wldp_buf;
3380
3381 *radio = B_TRUE;
3382 }
3383
3384 /*
3385 * MAC_PROP_WL_ESSLIST
3386 */
3387 static void
pcan_get_esslist(pcan_maci_t * pcan_p,void * wldp_buf)3388 pcan_get_esslist(pcan_maci_t *pcan_p, void *wldp_buf)
3389 {
3390 uint16_t i;
3391 wl_ess_conf_t *p_ess_conf;
3392 an_scan_list_t *scan_item;
3393
3394 mutex_enter(&pcan_p->pcan_scanlist_lock);
3395
3396 ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
3397 pcan_p->an_scan_num;
3398 scan_item = list_head(&pcan_p->an_scan_list);
3399 for (i = 0; i < pcan_p->an_scan_num; i++) {
3400 if (!scan_item)
3401 break;
3402 p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
3403 offsetof(wl_ess_list_t, wl_ess_list_ess) +
3404 i * sizeof (wl_ess_conf_t));
3405 bcopy(scan_item->an_val.an_ssid,
3406 p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
3407 mi_strlen(scan_item->an_val.an_ssid));
3408 bcopy(scan_item->an_val.an_bssid,
3409 p_ess_conf->wl_ess_conf_bssid, 6);
3410 (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
3411 = WL_DSSS;
3412 p_ess_conf->wl_ess_conf_wepenabled =
3413 (scan_item->an_val.an_cap & 0x10 ?
3414 WL_ENC_WEP : WL_NOENCRYPTION);
3415 p_ess_conf->wl_ess_conf_bsstype =
3416 (scan_item->an_val.an_cap & 0x1 ?
3417 WL_BSS_BSS : WL_BSS_IBSS);
3418 p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
3419 scan_item->an_val.an_dschannel;
3420 p_ess_conf->wl_ess_conf_sl = 15 -
3421 ((scan_item->an_val.an_rssi & 0xff) * 15 / 128);
3422 p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
3423 p_ess_conf->wl_supported_rates[1] = WL_RATE_2M;
3424 p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M;
3425 p_ess_conf->wl_supported_rates[3] = WL_RATE_11M;
3426 scan_item = list_next(&pcan_p->an_scan_list, scan_item);
3427 }
3428
3429 mutex_exit(&pcan_p->pcan_scanlist_lock);
3430 }
3431
3432 /*
3433 * for wificonfig and dlamd ioctl
3434 */
3435 static int
pcan_cfg_essid(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3436 pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3437 {
3438 uint16_t i;
3439 wldp_t *infp;
3440 wldp_t *outfp;
3441 char *buf;
3442 int iret;
3443 int err = 0;
3444
3445 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3446 if (buf == NULL) {
3447 PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc "
3448 "memory(%d)\n", MAX_BUF_LEN));
3449 return (ENOMEM);
3450 }
3451 outfp = (wldp_t *)buf;
3452 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3453 infp = (wldp_t *)mp->b_rptr;
3454
3455 if (cmd == WLAN_GET_PARAM) {
3456 err = pcan_get_essid(pcan_p, outfp->wldp_buf);
3457 if (err == EIO) {
3458 outfp->wldp_length = WIFI_BUF_OFFSET;
3459 outfp->wldp_result = WL_HW_ERROR;
3460 goto done;
3461 }
3462 outfp->wldp_result = WL_SUCCESS;
3463 } else if (cmd == WLAN_SET_PARAM) {
3464 (void) pcan_set_essid(pcan_p, infp->wldp_buf);
3465 outfp->wldp_length = WIFI_BUF_OFFSET;
3466 outfp->wldp_result = WL_SUCCESS;
3467 } else {
3468 kmem_free(buf, MAX_BUF_LEN);
3469 return (EINVAL);
3470 }
3471
3472 done:
3473 for (i = 0; i < (outfp->wldp_length); i++) {
3474 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3475 }
3476 iret = (int)(outfp->wldp_result);
3477 kmem_free(buf, MAX_BUF_LEN);
3478 return (iret);
3479 }
3480
3481 static int
pcan_cfg_bssid(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3482 pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3483 {
3484 uint16_t i;
3485 wldp_t *infp;
3486 wldp_t *outfp;
3487 char *buf;
3488 int iret;
3489 int err = 0;
3490
3491 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3492 if (buf == NULL) {
3493 PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc "
3494 "memory(%d)\n", MAX_BUF_LEN));
3495 return (ENOMEM);
3496 }
3497 outfp = (wldp_t *)buf;
3498 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3499 infp = (wldp_t *)mp->b_rptr;
3500
3501 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
3502
3503 if (cmd == WLAN_GET_PARAM) {
3504 err = pcan_get_bssid(pcan_p, outfp->wldp_buf);
3505 if (err == EIO) {
3506 outfp->wldp_length = WIFI_BUF_OFFSET;
3507 outfp->wldp_result = WL_HW_ERROR;
3508 goto done;
3509 }
3510 outfp->wldp_result = WL_SUCCESS;
3511 } else if (cmd == WLAN_SET_PARAM) {
3512 (void) pcan_set_bssid(pcan_p, infp->wldp_buf);
3513 outfp->wldp_length = WIFI_BUF_OFFSET;
3514 outfp->wldp_result = WL_SUCCESS;
3515 } else {
3516 kmem_free(buf, MAX_BUF_LEN);
3517 return (EINVAL);
3518 }
3519
3520 done:
3521 for (i = 0; i < (outfp->wldp_length); i++) {
3522 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3523 }
3524 iret = (int)(outfp->wldp_result);
3525 kmem_free(buf, MAX_BUF_LEN);
3526 return (iret);
3527 }
3528
3529 /*ARGSUSED*/
3530 static int
pcan_cmd_scan(pcan_maci_t * pcan_p)3531 pcan_cmd_scan(pcan_maci_t *pcan_p)
3532 {
3533 uint16_t i = 0, j, ret = WL_SUCCESS;
3534 uint8_t bssid_t[6];
3535 uint32_t check_num, enable;
3536 an_scan_list_t *scan_item0;
3537
3538 enable = pcan_p->pcan_flag & PCAN_ENABLED;
3539 if ((!enable) &&
3540 (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) {
3541 ret = (int)WL_HW_ERROR;
3542 goto exit;
3543 }
3544 if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) {
3545 ret = (int)WL_HW_ERROR;
3546 goto exit;
3547 }
3548
3549 pcan_delay(pcan_p, 500000);
3550 ret = pcan_scanresult_ltv(PCAN_READ_LTV,
3551 pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]);
3552 if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) {
3553 goto done;
3554 }
3555 do
3556 {
3557 i++;
3558 ret = pcan_scanresult_ltv(PCAN_READ_LTV,
3559 pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]);
3560 } while ((!ret) && (i < 32) &&
3561 (pcan_p->an_scanresult[i].an_index != 0xffff));
3562 done:
3563 if ((!enable) &&
3564 (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) {
3565 ret = (int)WL_HW_ERROR;
3566 goto exit;
3567 }
3568 /* record the scan result for future use */
3569 bzero(bssid_t, sizeof (bssid_t));
3570 for (j = 0; j < i; j++) {
3571 /*
3572 * sometimes, those empty items are recorded by hardware,
3573 * this is wrong, just ignore those items here.
3574 */
3575 if (bcmp(pcan_p->an_scanresult[j].an_bssid,
3576 bssid_t, 6) == 0) {
3577 continue;
3578 }
3579 /*
3580 * save/update the scan item in scanlist
3581 */
3582 mutex_enter(&pcan_p->pcan_scanlist_lock);
3583 check_num = 0;
3584 scan_item0 = list_head(&pcan_p->an_scan_list);
3585 if (scan_item0 == NULL) {
3586 if (pcan_add_scan_item(pcan_p,
3587 pcan_p->an_scanresult[j]) != 0) {
3588 mutex_exit(&pcan_p->pcan_scanlist_lock);
3589 return (WL_SUCCESS);
3590 }
3591 }
3592 for (; scan_item0; ) {
3593 if (bcmp(pcan_p->an_scanresult[j].an_bssid,
3594 scan_item0->an_val.an_bssid, 6) == 0) {
3595 scan_item0->an_val = pcan_p->an_scanresult[j];
3596 scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX;
3597 break;
3598 } else {
3599 check_num++;
3600 }
3601 scan_item0 = list_next(&pcan_p->an_scan_list,
3602 scan_item0);
3603 }
3604 if (check_num == pcan_p->an_scan_num) {
3605 if (pcan_add_scan_item(pcan_p,
3606 pcan_p->an_scanresult[j]) != 0) {
3607 mutex_exit(&pcan_p->pcan_scanlist_lock);
3608 return (WL_SUCCESS);
3609 }
3610 }
3611 mutex_exit(&pcan_p->pcan_scanlist_lock);
3612 }
3613 exit:
3614 if (ret)
3615 cmn_err(CE_WARN, "pcan: scan failed due to hardware error");
3616 return (ret);
3617 }
3618
3619 /*ARGSUSED*/
3620 static int
pcan_cfg_scan(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3621 pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3622 {
3623 wldp_t *outfp;
3624 char *buf;
3625 uint16_t i;
3626
3627 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3628 if (buf == NULL) {
3629 PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc "
3630 "memory(%d)\n", MAX_BUF_LEN));
3631 return (ENOMEM);
3632 }
3633 outfp = (wldp_t *)buf;
3634 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3635
3636 pcan_get_esslist(pcan_p, outfp->wldp_buf);
3637
3638 outfp->wldp_length = WIFI_BUF_OFFSET +
3639 offsetof(wl_ess_list_t, wl_ess_list_ess) +
3640 pcan_p->an_scan_num * sizeof (wl_ess_conf_t);
3641 outfp->wldp_result = WL_SUCCESS;
3642 for (i = 0; i < (outfp->wldp_length); i++)
3643 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3644 kmem_free(buf, MAX_BUF_LEN);
3645 return (WL_SUCCESS);
3646 }
3647
3648 /*ARGSUSED*/
3649 static int
pcan_cfg_linkstatus(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3650 pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3651 {
3652 wldp_t *outfp;
3653 char *buf;
3654 uint16_t i;
3655
3656 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3657 if (buf == NULL) {
3658 PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc "
3659 "memory(%d)\n", MAX_BUF_LEN));
3660 return (ENOMEM);
3661 }
3662 outfp = (wldp_t *)buf;
3663 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3664
3665 pcan_get_linkstatus(pcan_p, outfp->wldp_buf);
3666
3667 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
3668 outfp->wldp_result = WL_SUCCESS;
3669 for (i = 0; i < (outfp->wldp_length); i++)
3670 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3671 kmem_free(buf, MAX_BUF_LEN);
3672 return (WL_SUCCESS);
3673 }
3674
3675 static int
pcan_cfg_bsstype(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3676 pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3677 {
3678 uint16_t i;
3679 wldp_t *infp;
3680 wldp_t *outfp;
3681 char *buf;
3682 int iret;
3683
3684 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3685 if (buf == NULL) {
3686 PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc "
3687 "memory(%d)\n", 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_bss_type_t);
3695
3696 if (cmd == WLAN_GET_PARAM) {
3697 pcan_get_bsstype(pcan_p, outfp->wldp_buf);
3698 outfp->wldp_result = WL_SUCCESS;
3699 } else if (cmd == WLAN_SET_PARAM) {
3700 (void) pcan_set_bsstype(pcan_p, infp->wldp_buf);
3701 outfp->wldp_result = WL_SUCCESS;
3702 } else {
3703 kmem_free(buf, MAX_BUF_LEN);
3704 return (EINVAL);
3705 }
3706
3707 for (i = 0; i < (outfp->wldp_length); i++)
3708 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3709 iret = (int)(outfp->wldp_result);
3710 kmem_free(buf, MAX_BUF_LEN);
3711 return (iret);
3712 }
3713
3714 static int
pcan_cfg_phy(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3715 pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3716 {
3717 uint16_t i;
3718 wldp_t *infp;
3719 wldp_t *outfp;
3720 char *buf;
3721 int iret;
3722 int err = 0;
3723
3724 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3725 if (buf == NULL) {
3726 PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc "
3727 "memory(%d)\n", MAX_BUF_LEN));
3728 return (ENOMEM);
3729 }
3730 outfp = (wldp_t *)buf;
3731 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3732 infp = (wldp_t *)mp->b_rptr;
3733
3734 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
3735
3736 if (cmd == WLAN_GET_PARAM) {
3737 err = pcan_get_phy(pcan_p, outfp->wldp_buf);
3738 if (err == EIO) {
3739 outfp->wldp_length = WIFI_BUF_OFFSET;
3740 outfp->wldp_result = WL_HW_ERROR;
3741 goto done;
3742 }
3743 outfp->wldp_result = WL_SUCCESS;
3744 } else if (cmd == WLAN_SET_PARAM) {
3745 err = pcan_set_phy(pcan_p, infp->wldp_buf);
3746 if (err == ENOTSUP) {
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
3756 done:
3757 for (i = 0; i < (outfp->wldp_length); i++)
3758 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3759 iret = (int)(outfp->wldp_result);
3760 kmem_free(buf, MAX_BUF_LEN);
3761 return (iret);
3762
3763 }
3764
3765 /*ARGSUSED*/
3766 static int
pcan_cfg_desiredrates(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3767 pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3768 {
3769 uint16_t i;
3770 wldp_t *infp;
3771 wldp_t *outfp;
3772 char *buf;
3773 int iret;
3774 int err = 0;
3775
3776 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3777 if (buf == NULL) {
3778 PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc "
3779 "memory(%d)\n", MAX_BUF_LEN));
3780 return (ENOMEM);
3781 }
3782 outfp = (wldp_t *)buf;
3783 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3784 infp = (wldp_t *)mp->b_rptr;
3785
3786 if (cmd == WLAN_GET_PARAM) {
3787 err = pcan_get_desrates(pcan_p, outfp->wldp_buf);
3788 if (err == EIO) {
3789 outfp->wldp_length = WIFI_BUF_OFFSET;
3790 outfp->wldp_result = WL_HW_ERROR;
3791 goto done;
3792 }
3793 outfp->wldp_length = WIFI_BUF_OFFSET +
3794 offsetof(wl_rates_t, wl_rates_rates) + sizeof (char);
3795 outfp->wldp_result = WL_SUCCESS;
3796 } else if (cmd == WLAN_SET_PARAM) {
3797 (void) pcan_set_desrates(pcan_p, infp->wldp_buf);
3798 outfp->wldp_length = WIFI_BUF_OFFSET;
3799 outfp->wldp_result = WL_SUCCESS;
3800 } else {
3801 kmem_free(buf, MAX_BUF_LEN);
3802 return (EINVAL);
3803 }
3804
3805 done:
3806 for (i = 0; i < (outfp->wldp_length); i++)
3807 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3808 iret = (int)(outfp->wldp_result);
3809 kmem_free(buf, MAX_BUF_LEN);
3810 return (iret);
3811 }
3812
3813 /*ARGSUSED*/
3814 static int
pcan_cfg_supportrates(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3815 pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3816 {
3817 uint16_t i;
3818 int iret;
3819 wldp_t *outfp;
3820 char *buf;
3821
3822 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3823 if (buf == NULL) {
3824 PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc "
3825 "memory(%d)\n", MAX_BUF_LEN));
3826 return (ENOMEM);
3827 }
3828 outfp = (wldp_t *)buf;
3829 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3830
3831 if (cmd == WLAN_GET_PARAM) {
3832 pcan_get_suprates(outfp->wldp_buf);
3833 outfp->wldp_length = WIFI_BUF_OFFSET +
3834 offsetof(wl_rates_t, wl_rates_rates) +
3835 4 * sizeof (char);
3836 outfp->wldp_result = WL_SUCCESS;
3837 } else {
3838 kmem_free(buf, MAX_BUF_LEN);
3839 return (EINVAL);
3840 }
3841
3842 done:
3843 for (i = 0; i < (outfp->wldp_length); i++)
3844 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3845 iret = (int)(outfp->wldp_result);
3846 kmem_free(buf, MAX_BUF_LEN);
3847 return (iret);
3848 }
3849
3850 /*ARGSUSED*/
3851 static int
pcan_cfg_powermode(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3852 pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3853 {
3854 uint16_t i;
3855 wldp_t *outfp;
3856 char *buf;
3857 int iret;
3858 int err = 0;
3859
3860 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3861 if (buf == NULL) {
3862 PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc "
3863 "memory(%d)\n", MAX_BUF_LEN));
3864 return (ENOMEM);
3865 }
3866 outfp = (wldp_t *)buf;
3867 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3868
3869 if (cmd == WLAN_GET_PARAM) {
3870 err = pcan_get_powermode(pcan_p, outfp->wldp_buf);
3871 if (err == EIO) {
3872 outfp->wldp_length = WIFI_BUF_OFFSET;
3873 outfp->wldp_result = WL_HW_ERROR;
3874 goto done;
3875 }
3876 outfp->wldp_length = WIFI_BUF_OFFSET +
3877 sizeof (wl_ps_mode_t);
3878 outfp->wldp_result = WL_SUCCESS;
3879 } else if (cmd == WLAN_SET_PARAM) {
3880 outfp->wldp_length = WIFI_BUF_OFFSET;
3881 outfp->wldp_result = WL_LACK_FEATURE;
3882 } else {
3883 kmem_free(buf, MAX_BUF_LEN);
3884 return (EINVAL);
3885 }
3886
3887 done:
3888 for (i = 0; i < (outfp->wldp_length); i++)
3889 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3890 iret = (int)(outfp->wldp_result);
3891 kmem_free(buf, MAX_BUF_LEN);
3892 return (iret);
3893
3894 }
3895
3896 static int
pcan_cfg_authmode(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3897 pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3898 {
3899 uint16_t i;
3900 wldp_t *outfp;
3901 char *buf;
3902 int iret;
3903 int err = 0;
3904 struct an_ltv_genconfig *actcfg_p;
3905
3906 actcfg_p = &pcan_p->an_actual_config;
3907
3908 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3909 if (buf == NULL) {
3910 PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc "
3911 "memory(%d)\n", MAX_BUF_LEN));
3912 return (ENOMEM);
3913 }
3914 outfp = (wldp_t *)buf;
3915 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3916
3917 if (cmd == WLAN_GET_PARAM) {
3918 pcan_get_authmode(pcan_p, outfp->wldp_buf);
3919 outfp->wldp_result = WL_SUCCESS;
3920 } else if (cmd == WLAN_SET_PARAM) {
3921 err = pcan_set_authmode(pcan_p, outfp->wldp_buf);
3922 if (err == EINVAL) {
3923 outfp->wldp_length = WIFI_BUF_OFFSET;
3924 outfp->wldp_result = WL_LACK_FEATURE;
3925 } else {
3926 outfp->wldp_length = WIFI_BUF_OFFSET;
3927 outfp->wldp_result = WL_SUCCESS;
3928 }
3929 } else {
3930 kmem_free(buf, MAX_BUF_LEN);
3931 return (EINVAL);
3932 }
3933 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x",
3934 actcfg_p->an_authtype));
3935 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x",
3936 actcfg_p->an_rsvd6[2]));
3937
3938 for (i = 0; i < (outfp->wldp_length); i++)
3939 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3940 iret = (int)(outfp->wldp_result);
3941 kmem_free(buf, MAX_BUF_LEN);
3942 return (iret);
3943 }
3944
3945 static int
pcan_cfg_encryption(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3946 pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3947 {
3948 uint16_t i;
3949 wldp_t *outfp;
3950 char *buf;
3951 int iret;
3952
3953 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3954 if (buf == NULL) {
3955 PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc "
3956 "memory(%d)\n", MAX_BUF_LEN));
3957 return (ENOMEM);
3958 }
3959 outfp = (wldp_t *)buf;
3960 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
3961
3962 if (cmd == WLAN_GET_PARAM) {
3963 pcan_get_encrypt(pcan_p, outfp->wldp_buf);
3964 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
3965 outfp->wldp_result = WL_SUCCESS;
3966 } else if (cmd == WLAN_SET_PARAM) {
3967 (void) pcan_set_encrypt(pcan_p, outfp->wldp_buf);
3968 outfp->wldp_length = WIFI_BUF_OFFSET;
3969 outfp->wldp_result = WL_SUCCESS;
3970 } else {
3971 kmem_free(buf, MAX_BUF_LEN);
3972 return (EINVAL);
3973 }
3974
3975 for (i = 0; i < (outfp->wldp_length); i++)
3976 (void) mi_mpprintf_putc((char *)mp, buf[i]);
3977 iret = (int)(outfp->wldp_result);
3978 kmem_free(buf, MAX_BUF_LEN);
3979 return (iret);
3980 }
3981
3982 static int
pcan_cfg_wepkeyid(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)3983 pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
3984 {
3985 uint16_t i, ret;
3986 wldp_t *infp;
3987 wldp_t *outfp;
3988 char *buf;
3989 int iret;
3990 struct an_ltv_wepkey wepkey;
3991
3992 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
3993 if (buf == NULL) {
3994 PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc "
3995 "memory(%d)\n", MAX_BUF_LEN));
3996 return (ENOMEM);
3997 }
3998 outfp = (wldp_t *)buf;
3999 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
4000 infp = (wldp_t *)mp->b_rptr;
4001
4002 if (cmd == WLAN_GET_PARAM) {
4003 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
4004 outfp->wldp_result = WL_SUCCESS;
4005 *(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey;
4006 } else if (cmd == WLAN_SET_PARAM) {
4007 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
4008 if (ret > 3) {
4009 kmem_free(buf, MAX_BUF_LEN);
4010 return (EINVAL);
4011 }
4012 wepkey.an_index = 0xffff;
4013 wepkey.an_macaddr[0] = ret & 0xff;
4014 pcan_p->an_cur_wepkey = ret;
4015 outfp->wldp_length = WIFI_BUF_OFFSET;
4016 outfp->wldp_result = WL_SUCCESS;
4017 } else {
4018 kmem_free(buf, MAX_BUF_LEN);
4019 return (EINVAL);
4020 }
4021 for (i = 0; i < (outfp->wldp_length); i++)
4022 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4023 iret = (int)(outfp->wldp_result);
4024 kmem_free(buf, MAX_BUF_LEN);
4025 return (iret);
4026 }
4027
4028 /*ARGSUSED*/
4029 static int
pcan_cfg_createibss(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)4030 pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4031 {
4032 uint16_t i;
4033 wldp_t *outfp;
4034 char *buf;
4035 int iret;
4036
4037 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4038 if (buf == NULL) {
4039 PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc "
4040 "memory(%d)\n", MAX_BUF_LEN));
4041 return (ENOMEM);
4042 }
4043 outfp = (wldp_t *)buf;
4044 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
4045
4046 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
4047 outfp->wldp_result = WL_LACK_FEATURE;
4048 for (i = 0; i < (outfp->wldp_length); i++)
4049 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4050 iret = (int)(outfp->wldp_result);
4051 kmem_free(buf, MAX_BUF_LEN);
4052 return (iret);
4053 }
4054
4055 static int
pcan_cfg_rssi(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)4056 pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4057 {
4058 uint16_t i;
4059 int iret;
4060 wldp_t *outfp;
4061 char *buf;
4062 int err = 0;
4063
4064 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4065 if (buf == NULL) {
4066 PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc "
4067 "memory(%d)\n", MAX_BUF_LEN));
4068 return (ENOMEM);
4069 }
4070 outfp = (wldp_t *)buf;
4071 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
4072
4073 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
4074
4075 if (cmd == WLAN_GET_PARAM) {
4076 err = pcan_get_rssi(pcan_p, outfp->wldp_buf);
4077 if (err == EIO) {
4078 outfp->wldp_length = WIFI_BUF_OFFSET;
4079 outfp->wldp_result = WL_HW_ERROR;
4080 goto done;
4081 }
4082 outfp->wldp_result = WL_SUCCESS;
4083 } else if (cmd == WLAN_SET_PARAM) {
4084 outfp->wldp_result = WL_READONLY;
4085 } else {
4086 kmem_free(buf, MAX_BUF_LEN);
4087 return (EINVAL);
4088 }
4089
4090 done:
4091 for (i = 0; i < (outfp->wldp_length); i++)
4092 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4093 iret = (int)(outfp->wldp_result);
4094 kmem_free(buf, MAX_BUF_LEN);
4095 return (iret);
4096 }
4097
4098 /*ARGSUSED*/
4099 static int
pcan_cfg_radio(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)4100 pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4101 {
4102 uint16_t i;
4103 int iret;
4104 wldp_t *outfp;
4105 char *buf;
4106
4107 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4108 if (buf == NULL) {
4109 PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc "
4110 "memory(%d)\n", MAX_BUF_LEN));
4111 return (ENOMEM);
4112 }
4113 outfp = (wldp_t *)buf;
4114 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
4115
4116 if (cmd == WLAN_GET_PARAM) {
4117 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
4118 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
4119 outfp->wldp_result = WL_SUCCESS;
4120 } else if (cmd == WLAN_SET_PARAM) {
4121 outfp->wldp_length = WIFI_BUF_OFFSET;
4122 outfp->wldp_result = WL_LACK_FEATURE;
4123 } else {
4124 kmem_free(buf, MAX_BUF_LEN);
4125 return (EINVAL);
4126 }
4127
4128 for (i = 0; i < (outfp->wldp_length); i++)
4129 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4130 iret = (int)(outfp->wldp_result);
4131 kmem_free(buf, MAX_BUF_LEN);
4132 return (iret);
4133 }
4134
4135 static int
pcan_cfg_wepkey(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)4136 pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4137 {
4138 uint16_t i;
4139 wldp_t *outfp;
4140 char *buf;
4141 int iret;
4142 wldp_t *infp;
4143
4144 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
4145 if (buf == NULL) {
4146 PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc "
4147 "memory(%d)\n", MAX_BUF_LEN));
4148 return (ENOMEM);
4149 }
4150 outfp = (wldp_t *)buf;
4151 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
4152 infp = (wldp_t *)mp->b_rptr;
4153
4154 if (cmd == WLAN_GET_PARAM) {
4155 outfp->wldp_length = WIFI_BUF_OFFSET +
4156 sizeof (wl_wep_key_tab_t);
4157 outfp->wldp_result = WL_WRITEONLY;
4158 } else if (cmd == WLAN_SET_PARAM) {
4159 (void) pcan_set_wepkey(pcan_p, infp->wldp_buf);
4160 outfp->wldp_length = WIFI_BUF_OFFSET;
4161 outfp->wldp_result = WL_SUCCESS;
4162 } else {
4163 kmem_free(buf, MAX_BUF_LEN);
4164 return (EINVAL);
4165 }
4166
4167 for (i = 0; i < (outfp->wldp_length); i++)
4168 (void) mi_mpprintf_putc((char *)mp, buf[i]);
4169 iret = (int)(outfp->wldp_result);
4170 kmem_free(buf, MAX_BUF_LEN);
4171 return (iret);
4172 }
4173
4174 static void
pcan_connect_timeout(void * arg)4175 pcan_connect_timeout(void *arg)
4176 {
4177 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4178 uint16_t ret;
4179
4180 mutex_enter(&pcan_p->pcan_glock);
4181 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
4182 goto done;
4183 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4184 if (ret = pcan_config_mac(pcan_p))
4185 goto done;
4186 ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0);
4187 done:
4188 if (ret)
4189 cmn_err(CE_WARN, "pcan: connect failed due to hardware error");
4190 mutex_exit(&pcan_p->pcan_glock);
4191 pcan_p->pcan_connect_timeout_id = 0;
4192 }
4193
4194 static int
pcan_getset(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)4195 pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
4196 {
4197 int ret = WL_SUCCESS;
4198 int connect = 0;
4199
4200 mutex_enter(&pcan_p->pcan_glock);
4201 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4202 mutex_exit(&pcan_p->pcan_glock);
4203 return (PCAN_FAIL);
4204 }
4205
4206 switch (((wldp_t *)mp->b_rptr)->wldp_id) {
4207 case WL_ESSID:
4208 ret = pcan_cfg_essid(mp, pcan_p, cmd);
4209 connect = 1;
4210 PCANDBG((CE_NOTE, "cfg_essid\n"));
4211 break;
4212 case WL_BSSID:
4213 ret = pcan_cfg_bssid(mp, pcan_p, cmd);
4214 connect = 1;
4215 PCANDBG((CE_NOTE, "cfg_bssid\n"));
4216 break;
4217 case WL_ESS_LIST:
4218 ret = pcan_cfg_scan(mp, pcan_p, cmd);
4219 PCANDBG((CE_NOTE, "cfg_scan\n"));
4220 break;
4221 case WL_LINKSTATUS:
4222 ret = pcan_cfg_linkstatus(mp, pcan_p, cmd);
4223 PCANDBG((CE_NOTE, "cfg_linkstatus\n"));
4224 break;
4225 case WL_BSS_TYPE:
4226 ret = pcan_cfg_bsstype(mp, pcan_p, cmd);
4227 connect = 1;
4228 PCANDBG((CE_NOTE, "cfg_bsstype\n"));
4229 break;
4230 case WL_PHY_CONFIG:
4231 ret = pcan_cfg_phy(mp, pcan_p, cmd);
4232 connect = 1;
4233 PCANDBG((CE_NOTE, "cfg_phy\n"));
4234 break;
4235 case WL_DESIRED_RATES:
4236 ret = pcan_cfg_desiredrates(mp, pcan_p, cmd);
4237 connect = 1;
4238 PCANDBG((CE_NOTE, "cfg_disred-rates\n"));
4239 break;
4240 case WL_SUPPORTED_RATES:
4241 ret = pcan_cfg_supportrates(mp, pcan_p, cmd);
4242 PCANDBG((CE_NOTE, "cfg_supported-rates\n"));
4243 break;
4244 case WL_POWER_MODE:
4245 ret = pcan_cfg_powermode(mp, pcan_p, cmd);
4246 PCANDBG((CE_NOTE, "cfg_powermode\n"));
4247 break;
4248 case WL_AUTH_MODE:
4249 ret = pcan_cfg_authmode(mp, pcan_p, cmd);
4250 connect = 1;
4251 PCANDBG((CE_NOTE, "cfg_authmode\n"));
4252 break;
4253 case WL_ENCRYPTION:
4254 ret = pcan_cfg_encryption(mp, pcan_p, cmd);
4255 connect = 1;
4256 PCANDBG((CE_NOTE, "cfg_encryption\n"));
4257 break;
4258 case WL_WEP_KEY_ID:
4259 ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd);
4260 connect = 1;
4261 PCANDBG((CE_NOTE, "cfg_wepkeyid\n"));
4262 break;
4263 case WL_CREATE_IBSS:
4264 ret = pcan_cfg_createibss(mp, pcan_p, cmd);
4265 connect = 1;
4266 PCANDBG((CE_NOTE, "cfg_create-ibss\n"));
4267 break;
4268 case WL_RSSI:
4269 ret = pcan_cfg_rssi(mp, pcan_p, cmd);
4270 PCANDBG((CE_NOTE, "cfg_rssi\n"));
4271 break;
4272 case WL_RADIO:
4273 ret = pcan_cfg_radio(mp, pcan_p, cmd);
4274 PCANDBG((CE_NOTE, "cfg_radio\n"));
4275 break;
4276 case WL_WEP_KEY_TAB:
4277 ret = pcan_cfg_wepkey(mp, pcan_p, cmd);
4278 connect = 1;
4279 PCANDBG((CE_NOTE, "cfg_wepkey\n"));
4280 break;
4281 case WL_SCAN:
4282 mutex_exit(&pcan_p->pcan_glock);
4283 if (pcan_p->pcan_connect_timeout_id != 0) {
4284 (void) untimeout(pcan_p->pcan_connect_timeout_id);
4285 pcan_p->pcan_connect_timeout_id = 0;
4286 }
4287 mutex_enter(&pcan_p->pcan_glock);
4288 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4289 mutex_exit(&pcan_p->pcan_glock);
4290 return (PCAN_FAIL);
4291 }
4292 ret = pcan_cmd_scan(pcan_p);
4293 /*
4294 * a trick here.
4295 * since the scan doesn't return too many items due to hardware
4296 * reason, so the current scan result is an accumulation of
4297 * several scans. For the first time or after many of the items
4298 * aged, we scan again if too few items now in the scan table.
4299 */
4300 if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD)
4301 ret = pcan_cmd_scan(pcan_p);
4302 break;
4303 case WL_LOAD_DEFAULTS:
4304 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
4305 ret = (int)WL_HW_ERROR;
4306 break;
4307 }
4308 if (ret = pcan_loaddef(pcan_p)) {
4309 ret = (int)WL_HW_ERROR;
4310 break;
4311 }
4312 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
4313 ret = (int)WL_HW_ERROR;
4314 break;
4315 }
4316 PCANDBG((CE_NOTE, "loaddef\n"));
4317 break;
4318 case WL_DISASSOCIATE:
4319 mutex_exit(&pcan_p->pcan_glock);
4320 if (pcan_p->pcan_connect_timeout_id != 0) {
4321 (void) untimeout(pcan_p->pcan_connect_timeout_id);
4322 pcan_p->pcan_connect_timeout_id = 0;
4323 }
4324 mutex_enter(&pcan_p->pcan_glock);
4325 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4326 mutex_exit(&pcan_p->pcan_glock);
4327 return (PCAN_FAIL);
4328 }
4329 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4330 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
4331 ret = (int)WL_HW_ERROR;
4332 break;
4333 }
4334 if (ret = pcan_loaddef(pcan_p)) {
4335 ret = (int)WL_HW_ERROR;
4336 break;
4337 }
4338 PCANDBG((CE_NOTE, "disassociate\n"));
4339 break;
4340 case WL_REASSOCIATE:
4341 case WL_ASSOCIAT:
4342 mutex_exit(&pcan_p->pcan_glock);
4343 if (pcan_p->pcan_connect_timeout_id != 0) {
4344 (void) untimeout(pcan_p->pcan_connect_timeout_id);
4345 pcan_p->pcan_connect_timeout_id = 0;
4346 }
4347 mutex_enter(&pcan_p->pcan_glock);
4348 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4349 mutex_exit(&pcan_p->pcan_glock);
4350 return (PCAN_FAIL);
4351 }
4352 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
4353 ret = (int)WL_HW_ERROR;
4354 break;
4355 }
4356 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4357 if (ret = pcan_config_mac(pcan_p)) {
4358 ret = (int)WL_HW_ERROR;
4359 break;
4360 }
4361 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
4362 ret = (int)WL_HW_ERROR;
4363 break;
4364 }
4365 PCANDBG((CE_NOTE, "associate"));
4366 break;
4367
4368 default:
4369 break;
4370 }
4371 mutex_exit(&pcan_p->pcan_glock);
4372 if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) {
4373 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4374 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
4375 if (pcan_p->pcan_connect_timeout_id != 0) {
4376 (void) untimeout(pcan_p->pcan_connect_timeout_id);
4377 pcan_p->pcan_connect_timeout_id = 0;
4378 }
4379 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
4380 pcan_p, drv_usectohz(1000000));
4381 }
4382 return (ret);
4383 }
4384
4385 static void
pcan_wlan_ioctl(pcan_maci_t * pcan_p,queue_t * wq,mblk_t * mp,uint32_t cmd)4386 pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
4387 {
4388
4389 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
4390 uint32_t len, ret;
4391 mblk_t *mp1;
4392
4393 /* sanity check */
4394 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
4395 miocnak(wq, mp, 0, EINVAL);
4396 return;
4397 }
4398
4399 /* assuming single data block */
4400 if (mp1->b_cont) {
4401 freemsg(mp1->b_cont);
4402 mp1->b_cont = NULL;
4403 }
4404
4405 /* we will overwrite everything */
4406 mp1->b_wptr = mp1->b_rptr;
4407
4408 ret = pcan_getset(mp1, pcan_p, cmd);
4409 len = msgdsize(mp1);
4410 miocack(wq, mp, len, ret);
4411 }
4412
4413 static void
pcan_ioctl(void * arg,queue_t * wq,mblk_t * mp)4414 pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4415 {
4416 struct iocblk *iocp;
4417 uint32_t cmd, ret;
4418 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4419 boolean_t need_privilege = B_TRUE;
4420
4421 iocp = (struct iocblk *)mp->b_rptr;
4422 iocp->ioc_error = 0;
4423 cmd = iocp->ioc_cmd;
4424 switch (cmd) {
4425 default:
4426 miocnak(wq, mp, 0, EINVAL);
4427 return;
4428 case WLAN_GET_PARAM:
4429 need_privilege = B_FALSE;
4430 break;
4431 case WLAN_SET_PARAM:
4432 case WLAN_COMMAND:
4433 break;
4434 }
4435
4436 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
4437 miocnak(wq, mp, 0, ret);
4438 else
4439 pcan_wlan_ioctl(pcan_p, wq, mp, cmd);
4440 }
4441 /*
4442 * brussels
4443 */
4444 /* ARGSUSED */
4445 static int
pcan_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)4446 pcan_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4447 uint_t wldp_length, const void *wldp_buf)
4448 {
4449 int err = 0;
4450 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4451
4452 mutex_enter(&pcan_p->pcan_glock);
4453 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4454 mutex_exit(&pcan_p->pcan_glock);
4455 err = EINVAL;
4456 return (err);
4457 }
4458
4459 switch (wldp_pr_num) {
4460 /* mac_prop_id */
4461 case MAC_PROP_WL_ESSID:
4462 err = pcan_set_essid(pcan_p, wldp_buf);
4463 break;
4464 case MAC_PROP_WL_BSSID:
4465 err = pcan_set_bssid(pcan_p, wldp_buf);
4466 break;
4467 case MAC_PROP_WL_PHY_CONFIG:
4468 err = pcan_set_phy(pcan_p, wldp_buf);
4469 break;
4470 case MAC_PROP_WL_KEY_TAB:
4471 err = pcan_set_wepkey(pcan_p, wldp_buf);
4472 break;
4473 case MAC_PROP_WL_AUTH_MODE:
4474 err = pcan_set_authmode(pcan_p, wldp_buf);
4475 break;
4476 case MAC_PROP_WL_ENCRYPTION:
4477 err = pcan_set_encrypt(pcan_p, wldp_buf);
4478 break;
4479 case MAC_PROP_WL_BSSTYPE:
4480 err = pcan_set_bsstype(pcan_p, wldp_buf);
4481 break;
4482 case MAC_PROP_WL_DESIRED_RATES:
4483 err = pcan_set_desrates(pcan_p, wldp_buf);
4484 break;
4485 case MAC_PROP_WL_POWER_MODE:
4486 case MAC_PROP_WL_CREATE_IBSS:
4487 case MAC_PROP_WL_RADIO:
4488 case MAC_PROP_WL_WPA:
4489 case MAC_PROP_WL_KEY:
4490 case MAC_PROP_WL_DELKEY:
4491 case MAC_PROP_WL_SETOPTIE:
4492 case MAC_PROP_WL_MLME:
4493 case MAC_PROP_WL_LINKSTATUS:
4494 case MAC_PROP_WL_ESS_LIST:
4495 case MAC_PROP_WL_SUPPORTED_RATES:
4496 case MAC_PROP_WL_RSSI:
4497 case MAC_PROP_WL_CAPABILITY:
4498 case MAC_PROP_WL_SCANRESULTS:
4499 cmn_err(CE_WARN, "pcan_setprop:"
4500 "opmode not support\n");
4501 err = ENOTSUP;
4502 break;
4503 default:
4504 cmn_err(CE_WARN, "pcan_setprop:"
4505 "opmode err\n");
4506 err = EINVAL;
4507 break;
4508 }
4509
4510 mutex_exit(&pcan_p->pcan_glock);
4511
4512 if (err == ENETRESET) {
4513 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
4514 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
4515 if (pcan_p->pcan_connect_timeout_id != 0) {
4516 (void) untimeout(pcan_p->pcan_connect_timeout_id);
4517 pcan_p->pcan_connect_timeout_id = 0;
4518 }
4519 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
4520 pcan_p, drv_usectohz(1000000));
4521
4522 err = 0;
4523 }
4524
4525 return (err);
4526 } /* ARGSUSED */
4527
4528 /* ARGSUSED */
4529 static int
pcan_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)4530 pcan_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4531 uint_t wldp_length, void *wldp_buf)
4532 {
4533 int err = 0;
4534 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
4535
4536 mutex_enter(&pcan_p->pcan_glock);
4537 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
4538 mutex_exit(&pcan_p->pcan_glock);
4539 err = EINVAL;
4540 return (err);
4541 }
4542
4543 switch (wldp_pr_num) {
4544 /* mac_prop_id */
4545 case MAC_PROP_WL_ESSID:
4546 err = pcan_get_essid(pcan_p, wldp_buf);
4547 break;
4548 case MAC_PROP_WL_BSSID:
4549 err = pcan_get_bssid(pcan_p, wldp_buf);
4550 break;
4551 case MAC_PROP_WL_PHY_CONFIG:
4552 err = pcan_get_phy(pcan_p, wldp_buf);
4553 break;
4554 case MAC_PROP_WL_AUTH_MODE:
4555 pcan_get_authmode(pcan_p, wldp_buf);
4556 break;
4557 case MAC_PROP_WL_ENCRYPTION:
4558 pcan_get_encrypt(pcan_p, wldp_buf);
4559 break;
4560 case MAC_PROP_WL_BSSTYPE:
4561 pcan_get_bsstype(pcan_p, wldp_buf);
4562 break;
4563 case MAC_PROP_WL_LINKSTATUS:
4564 pcan_get_linkstatus(pcan_p, wldp_buf);
4565 break;
4566 case MAC_PROP_WL_ESS_LIST:
4567 pcan_get_esslist(pcan_p, wldp_buf);
4568 break;
4569 case MAC_PROP_WL_SUPPORTED_RATES:
4570 pcan_get_suprates(wldp_buf);
4571 break;
4572 case MAC_PROP_WL_RSSI:
4573 err = pcan_get_rssi(pcan_p, wldp_buf);
4574 break;
4575 case MAC_PROP_WL_RADIO:
4576 pcan_get_radio(wldp_buf);
4577 break;
4578 case MAC_PROP_WL_POWER_MODE:
4579 err = pcan_get_powermode(pcan_p, wldp_buf);
4580 break;
4581 case MAC_PROP_WL_DESIRED_RATES:
4582 err = pcan_get_desrates(pcan_p, wldp_buf);
4583 break;
4584 case MAC_PROP_WL_CREATE_IBSS:
4585 case MAC_PROP_WL_CAPABILITY:
4586 case MAC_PROP_WL_WPA:
4587 case MAC_PROP_WL_SCANRESULTS:
4588 case MAC_PROP_WL_KEY_TAB:
4589 case MAC_PROP_WL_KEY:
4590 case MAC_PROP_WL_DELKEY:
4591 case MAC_PROP_WL_SETOPTIE:
4592 case MAC_PROP_WL_MLME:
4593 cmn_err(CE_WARN, "pcan_getprop:"
4594 "opmode not support %x\n", wldp_pr_num);
4595 err = ENOTSUP;
4596 break;
4597 default:
4598 cmn_err(CE_WARN, "pcan_getprop:"
4599 "opmode err\n");
4600 err = EINVAL;
4601 break;
4602 }
4603
4604 mutex_exit(&pcan_p->pcan_glock);
4605
4606 return (err);
4607 }
4608
4609 static void
pcan_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t mph)4610 pcan_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4611 mac_prop_info_handle_t mph)
4612 {
4613 _NOTE(ARGUNUSED(arg, pr_name));
4614
4615 switch (wldp_pr_num) {
4616 case MAC_PROP_WL_BSSTYPE:
4617 case MAC_PROP_WL_ESS_LIST:
4618 case MAC_PROP_WL_SUPPORTED_RATES:
4619 case MAC_PROP_WL_RSSI:
4620 mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ);
4621 break;
4622 }
4623 }
4624
4625
4626 /*
4627 * quiesce(9E) entry point.
4628 *
4629 * This function is called when the system is single-threaded at high
4630 * PIL with preemption disabled. Therefore, this function must not be
4631 * blocked.
4632 *
4633 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4634 * DDI_FAILURE indicates an error condition and should almost never happen.
4635 */
4636 #ifndef __sparc
4637 static int
pcan_quiesce(dev_info_t * dip)4638 pcan_quiesce(dev_info_t *dip)
4639 {
4640 pcan_maci_t *pcan_p;
4641
4642 pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
4643 if (pcan_p == NULL)
4644 return (DDI_FAILURE);
4645
4646 if (pcan_p->pcan_flag & PCAN_CARD_READY)
4647 pcan_stop_locked(pcan_p);
4648
4649 return (DDI_SUCCESS);
4650 }
4651 #endif
4652