1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * UWB radio controller driver interfaces
28 */
29 #include <sys/uwb/uwba/uwba.h>
30 #include <sys/sunndi.h>
31 #include <sys/ddi.h>
32
33
34 /*
35 * The following is a list of functions which handles the rccb command
36 * for uwb model, each rccb command has a related handler. Not all the
37 * rccb command is supportted, the below uwb_rccb_handler_tbl lists
38 * the supported handler
39 */
40 static int uwb_do_cmd_rccb(uwb_dev_handle_t, uwb_rccb_cmd_t *);
41 static int uwb_do_cmd_scan(uwb_dev_handle_t, uwb_rccb_cmd_t *);
42 static int uwb_do_cmd_start_beacon(uwb_dev_handle_t,
43 uwb_rccb_cmd_t *);
44 static int uwb_do_cmd_dev_addr_mgmt(uwb_dev_handle_t, uwb_rccb_cmd_t *);
45
46
47 static int uwb_process_rccb_cmd_private(uwb_dev_handle_t,
48 uwb_rccb_cmd_t *, uwb_cmd_result_t *);
49
50 static int uwb_send_rccb_cmd(uwb_dev_handle_t, uwb_rccb_cmd_t *);
51 static int uwb_check_rccb_cmd(uwb_dev_handle_t, uwb_rccb_cmd_t *);
52 static int uwb_check_dev_state(uwba_dev_t *, uwb_rccb_cmd_t *);
53 static void uwb_set_dev_state(uwba_dev_t *, uwb_rccb_cmd_t *);
54
55 static int uwb_wait_cmd_result(uwb_dev_handle_t);
56 static void uwb_free_cmd_result(uwb_dev_handle_t);
57
58 static int uwb_rccb_cmd_enter(uwba_dev_t *);
59 static void uwb_rccb_cmd_leave(uwba_dev_t *);
60
61 static int uwb_do_ioctl_rccb_cmd(uwb_dev_handle_t,
62 uint16_t, intptr_t, int);
63
64 static uwb_notif_wrapper_t *uwb_get_notification(uwb_dev_handle_t,
65 intptr_t, int);
66 static void uwb_free_notification(uwb_notif_wrapper_t *);
67 /*
68 *
69 * This is all the rccb command handler supported and not supported in
70 * current version. rccb handler table map
71 */
72 static uwb_rccb_handler_t uwb_rccb_handler_tbl [] = {
73 UWB_RCCB_NULL_HANDLER, /* CHANNEL_CHANGE */
74 uwb_do_cmd_dev_addr_mgmt, /* DEV_ADDR_MGMT */
75 uwb_do_cmd_rccb, /* GET_IE */
76 uwb_do_cmd_rccb, /* RESET */
77 uwb_do_cmd_scan, /* SCAN */
78 UWB_RCCB_NULL_HANDLER, /* SET_BEACON_FILTER */
79 UWB_RCCB_NULL_HANDLER, /* SET_DRP_IE */
80 UWB_RCCB_NULL_HANDLER, /* SET_IE */
81 UWB_RCCB_NULL_HANDLER, /* SET_NOTIFICATION_FILTER */
82 UWB_RCCB_NULL_HANDLER, /* SET_TX_POWER */
83 UWB_RCCB_NULL_HANDLER, /* SLEEP */
84 uwb_do_cmd_start_beacon, /* START_BEACON */
85 uwb_do_cmd_rccb, /* STOP_BEACON */
86 UWB_RCCB_NULL_HANDLER, /* BP_MERGE */
87 UWB_RCCB_NULL_HANDLER /* SEND_COMMAND_FRAME */
88 };
89
90 /*
91 * This table recode different size of the rccb command data block
92 * For those rccb command not supported, it is zero
93 */
94 static uint8_t uwb_rccb_size_tbl [] = {
95 0, /* CHANNEL_CHANGE */
96 sizeof (uwb_rccb_dev_addr_mgmt_t), /* DEV_ADDR_MGMT */
97 sizeof (uwb_rccb_cmd_t), /* GET_IE */
98 sizeof (uwb_rccb_cmd_t), /* RESET */
99 sizeof (uwb_rccb_scan_t), /* SCAN */
100 0, /* SET_BEACON_FILTER */
101 0, /* SET_DRP_IE */
102 0, /* SET_IE */
103 0, /* SET_NOTIFICATION_FILTER */
104 0, /* SET_TX_POWER */
105 0, /* SLEEP */
106 sizeof (uwb_rccb_start_beacon_t), /* START_BEACON */
107 sizeof (uwb_rccb_cmd_t), /* STOP_BEACON */
108 0, /* BP_MERGE */
109 0 /* SEND_COMMAND_FRAME */
110 };
111 _NOTE(SCHEME_PROTECTS_DATA("unique per call", uwba_dev::send_cmd))
112 _NOTE(SCHEME_PROTECTS_DATA("unique per call", uwb_rceb_get_ie))
113 _NOTE(SCHEME_PROTECTS_DATA("unique per call", uwb_rceb_result_code))
114
115 /*
116 * Called by radio controller driver's attach() to register the device to uwba.
117 * Including alloc and init the uwb_dev_handle
118 */
119 void
uwb_dev_attach(dev_info_t * dip,uwb_dev_handle_t * uwb_dev_handle,uint_t rcd_intr_pri,int (* send_cmd)(uwb_dev_handle_t uwb_dev_hdl,mblk_t * data,uint16_t data_len))120 uwb_dev_attach(dev_info_t *dip, uwb_dev_handle_t *uwb_dev_handle,
121 uint_t rcd_intr_pri, int (*send_cmd)(uwb_dev_handle_t uwb_dev_hdl,
122 mblk_t *data, uint16_t data_len))
123 {
124 uwba_dev_t *uwba_dev;
125
126 uwba_alloc_uwb_dev(dip, &uwba_dev, rcd_intr_pri);
127
128 uwba_init_ctxt_id(uwba_dev);
129 uwba_dev->send_cmd = send_cmd;
130
131 uwba_dev_add_to_list(uwba_dev);
132
133 *uwb_dev_handle = (uwb_dev_handle_t)uwba_dev;
134
135 }
136
137 /*
138 * Called by radio controller driver's dettach() to unregister the device from
139 * uwba. Including dealloc and fnit the uwb_dev_handle
140 */
141 void
uwb_dev_detach(uwb_dev_handle_t uwb_dev_hdl)142 uwb_dev_detach(uwb_dev_handle_t uwb_dev_hdl)
143 {
144 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
145
146 uwba_dev_rm_from_list(uwba_dev);
147 uwba_fini_ctxt_id(uwba_dev);
148 uwba_free_uwb_dev(uwba_dev);
149 }
150
151 /*
152 * Called by the radio controler to the dip from a uwb_dev_handle
153 */
154 dev_info_t *
uwb_get_dip(uwb_dev_handle_t uwb_dev_hdl)155 uwb_get_dip(uwb_dev_handle_t uwb_dev_hdl)
156 {
157 if (uwb_dev_hdl) {
158
159 return (((uwba_dev_t *)uwb_dev_hdl)->dip);
160 }
161
162 return (NULL);
163 }
164
165 /*
166 * Called by host controller or radio controller, this function set the
167 * ddi_no_autodetach to for the hwarc dip. Radio controller interface
168 * should alway be detached after the host controller detachment.
169 * So it should be called while the hwahc is attaching
170 * dip- a hwahc dip or a hwarc dip
171 */
172 int
uwb_dev_online(dev_info_t * dip)173 uwb_dev_online(dev_info_t *dip)
174 {
175 dev_info_t *pdip, *child_dip;
176 int rval = UWB_FAILURE;
177 uwba_dev_t *uwba_dev = NULL;
178 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
179 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
180 if (uwb_dev_hdl != NULL) {
181 (void) ddi_prop_update_int(DDI_DEV_T_NONE, uwba_dev->dip,
182 DDI_NO_AUTODETACH, 1);
183
184 return (UWB_SUCCESS);
185 }
186
187 pdip = ddi_get_parent(dip);
188 child_dip = ddi_get_child(pdip);
189 while (child_dip != NULL) {
190 if (child_dip != dip) {
191 /* Force the dip online */
192 if (ndi_devi_online(child_dip, NDI_ONLINE_ATTACH) !=
193 NDI_SUCCESS) {
194 uwba_log(uwba_dev, UWBA_LOG_LOG,
195 "fail to online dip = %p, node_name = %s",
196 dip, ddi_node_name(child_dip));
197 }
198
199 /*
200 * Update the dip properties if it is a radio
201 * controller node
202 */
203 if (strcmp(ddi_node_name(child_dip), "hwa-radio") ==
204 0) {
205 (void) ddi_prop_update_int(DDI_DEV_T_NONE,
206 child_dip, DDI_NO_AUTODETACH, 1);
207 rval = UWB_SUCCESS;
208 break;
209 }
210 }
211
212 child_dip = ddi_get_next_sibling(child_dip);
213 }
214
215 return (rval);
216
217 }
218
219 /*
220 * Called by hwahc when detaching.
221 * The hwarc should be detached after the hwahc. So it should only be
222 * called when hwahc is detaching.
223 */
224 int
uwb_dev_offline(dev_info_t * dip)225 uwb_dev_offline(dev_info_t *dip)
226 {
227 uwba_dev_t *uwba_dev = NULL;
228 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
229 if (uwb_dev_hdl == NULL) {
230 uwba_log(NULL, UWBA_LOG_LOG,
231 "uwb_dev_offline::no dev for dip:0x%p", dip);
232
233 return (UWB_FAILURE);
234 }
235 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
236 uwba_log(uwba_dev, UWBA_LOG_LOG,
237 " uwb_dev_offline dip = 0x%p", dip);
238 (void) ddi_prop_update_int(DDI_DEV_T_NONE, uwba_dev->dip,
239 DDI_NO_AUTODETACH, 0);
240
241 return (UWB_SUCCESS);
242
243 }
244 /*
245 * Called by hwarc when disconnect or suspend.
246 * Stop beacon. In addition, uwb will save the current channel
247 * and dev state.
248 */
249 int
uwb_dev_disconnect(dev_info_t * dip)250 uwb_dev_disconnect(dev_info_t *dip)
251 {
252 uwba_dev_t *uwba_dev = NULL;
253 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
254 if (uwb_dev_hdl == NULL) {
255 uwba_log(NULL, UWBA_LOG_LOG,
256 "uwb_dev_offline::no dev for dip:0x%p", dip);
257
258 return (UWB_FAILURE);
259 }
260 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
261
262 mutex_enter(&uwba_dev->dev_mutex);
263 uint8_t channel = uwba_dev->channel;
264 uint8_t state = uwba_dev->dev_state;
265 mutex_exit(&uwba_dev->dev_mutex);
266
267
268 uwba_log(uwba_dev, UWBA_LOG_LOG,
269 " uwb_dev_disconnect dip = 0x%p, channel=%d, state=%d",
270 dip, channel, state);
271
272 if (state == UWB_STATE_BEACON) {
273 (void) uwb_stop_beacon(dip);
274 }
275
276 mutex_enter(&uwba_dev->dev_mutex);
277 uwba_dev->channel = channel;
278 uwba_dev->dev_state = state;
279 mutex_exit(&uwba_dev->dev_mutex);
280
281
282 return (UWB_SUCCESS);
283
284 }
285
286 /*
287 * Called by hwarc when reconnect or resume.
288 * Start beacon and set the dev address whchi is saved
289 * in disconnect or suspend.
290 */
291 int
uwb_dev_reconnect(dev_info_t * dip)292 uwb_dev_reconnect(dev_info_t *dip)
293 {
294 uwba_dev_t *uwba_dev = NULL;
295 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
296 if (uwb_dev_hdl == NULL) {
297 uwba_log(NULL, UWBA_LOG_LOG,
298 "uwb_dev_offline::no dev for dip:0x%p", dip);
299
300 return (UWB_FAILURE);
301 }
302 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
303
304 mutex_enter(&uwba_dev->dev_mutex);
305 uint8_t channel = uwba_dev->channel;
306 uint8_t state = uwba_dev->dev_state;
307 uwba_dev->dev_state = UWB_STATE_IDLE;
308 mutex_exit(&uwba_dev->dev_mutex);
309
310 uwba_log(uwba_dev, UWBA_LOG_LOG,
311 " uwb_dev_reconnect dip = 0x%p, channel= %d, state = %d",
312 dip, channel, state);
313
314
315 (void) uwb_set_dev_addr(dip, uwba_dev->dev_addr);
316
317 if (state == UWB_STATE_BEACON) {
318 (void) uwb_start_beacon(dip, uwba_dev->channel);
319 }
320
321
322 return (UWB_SUCCESS);
323
324 }
325
326
327
328 /*
329 * This is a common interface for other models to send a
330 * rccb command to the radio controller
331 */
332 int
uwb_process_rccb_cmd(dev_info_t * dip,uwb_rccb_cmd_t * rccb_cmd,uwb_cmd_result_t * cmd_result)333 uwb_process_rccb_cmd(dev_info_t *dip, uwb_rccb_cmd_t *rccb_cmd,
334 uwb_cmd_result_t *cmd_result)
335 {
336 int rval = UWB_SUCCESS;
337 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
338 if (uwb_dev_hdl == NULL) {
339 uwba_log(NULL, UWBA_LOG_LOG,
340 "uwb_process_rccb_cmd::no dev for dip:0x%p", dip);
341
342 return (UWB_FAILURE);
343 }
344
345 /* check if it is a valid rccb command */
346 if (uwb_check_rccb_cmd(uwb_dev_hdl, rccb_cmd) != UWB_SUCCESS) {
347
348 return (UWB_FAILURE);
349 }
350
351 rval = uwb_process_rccb_cmd_private(uwb_dev_hdl, rccb_cmd, cmd_result);
352
353 return (rval);
354 }
355
356 /*
357 * Find a free chanel by scaning the supported channels
358 */
359 uint8_t
uwb_allocate_channel(dev_info_t * dip)360 uwb_allocate_channel(dev_info_t *dip)
361 {
362 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
363 uint8_t channel = 0;
364 if (!uwb_dev_hdl) {
365 uwba_log(NULL, UWBA_LOG_LOG,
366 "uwb_send_rccb_cmd: uwba dev not found");
367 goto done;
368 }
369 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
370 "uwb_allocate_channel: enter");
371 channel = uwba_allocate_channel(uwb_dev_hdl);
372 done:
373 return (channel);
374 }
375 /* scan a channel and wait for a while to get beacon info */
376 int
uwb_scan_channel(uwb_dev_handle_t uwb_dev_hdl,uint8_t channel)377 uwb_scan_channel(uwb_dev_handle_t uwb_dev_hdl, uint8_t channel)
378 {
379
380 uwb_rccb_scan_t rccb_cmd;
381
382 bzero(&rccb_cmd, sizeof (rccb_cmd));
383 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
384
385 rccb_cmd.rccb.wCommand = UWB_CE_SCAN;
386 rccb_cmd.bScanState = UWB_RC_SCAN_ONLY;
387 rccb_cmd.wStartTime = 0;
388 rccb_cmd.bChannelNumber = channel;
389
390 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
391 "uwb_scan_channel: channel = %d", channel);
392 /* Scan a specific channel */
393
394 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
395 (uwb_rccb_cmd_t *)&rccb_cmd, NULL) != 0) {
396 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
397 "uwb_scan_channel: process cmd failed");
398
399 return (UWB_FAILURE);
400 }
401
402 /* wait for beacon info */
403 delay(drv_usectohz(300000));
404
405 /* stop scan in the channel */
406 rccb_cmd.bScanState = UWB_RC_SCAN_DISABLED;
407
408 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
409 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)NULL) != 0) {
410 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
411 "uwb_scan_channel: process cmd failed, channel = %d",
412 channel);
413
414 return (UWB_FAILURE);
415 }
416
417 return (UWB_SUCCESS);
418 }
419
420 /* Stop beacon common interface */
421 int
uwb_stop_beacon(dev_info_t * dip)422 uwb_stop_beacon(dev_info_t *dip)
423 {
424 uwb_rccb_cmd_t rccb_cmd;
425 uwb_rceb_result_code_t ret;
426
427 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
428 if (uwb_dev_hdl == NULL) {
429 uwba_log(NULL, UWBA_LOG_LOG,
430 "uwb_stop_beacon::no dev for dip:0x%p", dip);
431
432 return (UWB_FAILURE);
433 }
434
435 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
436 "uwb_stop_beacon: enter");
437
438 bzero(&rccb_cmd, sizeof (rccb_cmd));
439 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
440
441 rccb_cmd.rccb.wCommand = UWB_CE_STOP_BEACON;
442
443 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
444 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)&ret) != 0) {
445 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
446 "uwb_stop_beacon: process cmd failed");
447
448 return (UWB_FAILURE);
449 }
450
451 if (ret.bResultCode != 0) {
452 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
453 "uwb_stop_beacon: bResultCode =%d", ret.bResultCode);
454
455 return (UWB_FAILURE);
456 }
457
458 return (UWB_SUCCESS);
459 }
460
461 /*
462 * Start beacon common interface
463 * start beaconing on specified channel
464 */
465 int
uwb_start_beacon(dev_info_t * dip,uint8_t channel)466 uwb_start_beacon(dev_info_t *dip, uint8_t channel)
467 {
468 uwb_rccb_start_beacon_t rccb_cmd;
469 uwb_rceb_result_code_t ret;
470 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
471
472 if (uwb_dev_hdl == NULL) {
473 uwba_log(NULL, UWBA_LOG_LOG,
474 "uwb_start_beacon::no dev for dip:0x%p, channel = %d",
475 dip, channel);
476
477 return (UWB_FAILURE);
478 }
479
480 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
481 "uwb_start_beacon: channel = %d", channel);
482 bzero(&rccb_cmd, sizeof (rccb_cmd));
483 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
484
485
486 rccb_cmd.rccb.wCommand = UWB_CE_START_BEACON;
487 /* todo: this needs to be fixed later */
488 rccb_cmd.wBPSTOffset = 0;
489 rccb_cmd.bChannelNumber = channel;
490
491 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
492 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)&ret) != 0) {
493 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
494 "uwb_start_beacon: process cmd failed"
495 "channel = %d", channel);
496
497 return (UWB_FAILURE);
498 }
499
500
501 if (ret.bResultCode != 0) {
502 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
503 "uwb_start_beacon: bResultCode =%d", ret.bResultCode);
504
505 return (UWB_FAILURE);
506 }
507
508 return (UWB_SUCCESS);
509 }
510
511 /* Get the mac address of the radion controller */
512 int
uwb_get_mac_addr(dev_info_t * dip,uint8_t * mac_addr)513 uwb_get_mac_addr(dev_info_t *dip, uint8_t *mac_addr)
514 {
515 uwb_rccb_dev_addr_mgmt_t rccb_cmd;
516 uwb_rceb_dev_addr_mgmt_t ret;
517
518 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
519 if (uwb_dev_hdl == NULL) {
520 uwba_log(NULL, UWBA_LOG_LOG,
521 "uwb_get_mac_addr::no dev for dip:0x%p", dip);
522
523 return (UWB_FAILURE);
524 }
525
526 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
527 "uwb_get_mac_addr: enter");
528
529 bzero(&rccb_cmd, sizeof (rccb_cmd));
530 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
531
532 rccb_cmd.rccb.wCommand = UWB_CE_DEV_ADDR_MGMT;
533 rccb_cmd.bmOperationType = 2; /* get MAC. XXX: should use Macro */
534
535 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
536 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)&ret) != 0) {
537 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
538 "uwb_get_mac_addr: process cmd failed");
539
540 return (UWB_FAILURE);
541 }
542
543
544 if (ret.bResultCode != 0) {
545 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
546 "uwb_get_mac_addr: bResultCode =%d", ret.bResultCode);
547
548 return (UWB_FAILURE);
549 }
550 (void) memcpy(mac_addr, ret.baAddr, 6);
551
552 return (UWB_SUCCESS);
553 }
554
555 /* Get the device address of the radion controller */
556 int
uwb_get_dev_addr(dev_info_t * dip,uint16_t * dev_addr)557 uwb_get_dev_addr(dev_info_t *dip, uint16_t *dev_addr)
558 {
559 uwb_rccb_dev_addr_mgmt_t rccb_cmd;
560 uwb_rceb_dev_addr_mgmt_t ret;
561
562 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
563 if (uwb_dev_hdl == NULL) {
564 uwba_log(NULL, UWBA_LOG_LOG,
565 "uwb_get_dev_addr::no dev for dip:0x%p", dip);
566
567 return (UWB_FAILURE);
568 }
569
570 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
571 "uwb_get_dev_addr: enter");
572
573 bzero(&rccb_cmd, sizeof (rccb_cmd));
574 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
575
576 rccb_cmd.rccb.wCommand = UWB_CE_DEV_ADDR_MGMT;
577 rccb_cmd.bmOperationType = 0; /* get 16-bit dev addr */
578
579 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
580 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)&ret) != 0) {
581 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
582 "uwb_get_dev_addr: process cmd failed");
583
584 return (UWB_FAILURE);
585 }
586 if (ret.bResultCode != 0) {
587 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
588 "uwb_get_dev_addr: bResultCode =%d", ret.bResultCode);
589
590 return (UWB_FAILURE);
591 }
592 *dev_addr = ret.baAddr[0] | (ret.baAddr[1] << 8);
593
594 return (UWB_SUCCESS);
595 }
596
597 /* Set the device address of the radion controller */
598 int
uwb_set_dev_addr(dev_info_t * dip,uint16_t dev_addr)599 uwb_set_dev_addr(dev_info_t *dip, uint16_t dev_addr)
600 {
601 uwb_rccb_dev_addr_mgmt_t rccb_cmd;
602 uwb_rceb_dev_addr_mgmt_t ret;
603
604 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
605 if (uwb_dev_hdl == NULL) {
606 uwba_log(NULL, UWBA_LOG_LOG,
607 "uwb_set_dev_addr::no dev for dip:0x%p, dev_addr=%d",
608 dip, dev_addr);
609
610 return (UWB_FAILURE);
611 }
612
613 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
614 "uwb_set_dev_addr: dev_addr = %d", dev_addr);
615
616 bzero(&rccb_cmd, sizeof (rccb_cmd));
617 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
618
619 rccb_cmd.rccb.wCommand = UWB_CE_DEV_ADDR_MGMT;
620 rccb_cmd.bmOperationType = 1; /* set 16-bit dev addr */
621 rccb_cmd.baAddr[0] = dev_addr & 0xff;
622 rccb_cmd.baAddr[1] = (dev_addr >> 8) & 0xff;
623
624 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
625 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)&ret) != 0) {
626 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
627 "uwb_set_dev_addr: process cmd failed"
628 "dev_addr=%d", dev_addr);
629
630 return (UWB_FAILURE);
631 }
632
633
634 if (ret.bResultCode != 0) {
635 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
636 "uwb_set_dev_addr: bResultCode =%d", ret.bResultCode);
637
638 return (UWB_FAILURE);
639 }
640
641 return (UWB_SUCCESS);
642 }
643
644 /*
645 * Reset the radio controller.
646 * This is called when the radio controller is attached.
647 * Notice:Radio controller should not be reset when it
648 * is beaconing or scaning.
649 */
650 int
uwb_reset_dev(dev_info_t * dip)651 uwb_reset_dev(dev_info_t *dip)
652 {
653 uwb_rccb_cmd_t rccb_cmd;
654 uwb_rceb_result_code_t ret;
655
656 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
657 if (uwb_dev_hdl == NULL) {
658 uwba_log(NULL, UWBA_LOG_LOG,
659 "uwb_reset_dev:no dev for dip:0x%p", dip);
660
661 return (UWB_FAILURE);
662 }
663
664 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
665 "uwb_reset_dev: enter");
666 bzero(&rccb_cmd, sizeof (rccb_cmd));
667 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
668 rccb_cmd.rccb.wCommand = UWB_CE_RESET;
669
670 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
671 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)&ret) != 0) {
672 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
673 "uwb_reset_dev: process cmd failed");
674
675 return (UWB_FAILURE);
676 }
677 if (ret.bResultCode != 0) {
678 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
679 "uwb_reset_dev: bResultCode =%d", ret.bResultCode);
680
681 return (UWB_FAILURE);
682 }
683
684 return (UWB_SUCCESS);
685 }
686
687 /*
688 * Called while attaching.
689 * The physical capabilities is initialized.
690 * Only the supported channels is used in current version
691 */
692 int
uwb_init_phy(dev_info_t * dip)693 uwb_init_phy(dev_info_t *dip)
694 {
695 uwb_rccb_cmd_t rccb_cmd;
696
697 uwb_dev_handle_t uwb_dev_hdl = uwba_dev_search(dip);
698 if (uwb_dev_hdl == NULL) {
699 uwba_log(NULL, UWBA_LOG_LOG,
700 "uwb_init_phy::no dev for dip:0x%p", dip);
701
702 return (UWB_FAILURE);
703 }
704
705 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_DEBUG,
706 "uwb_init_phy: enter");
707 bzero(&rccb_cmd, sizeof (rccb_cmd));
708 rccb_cmd.rccb.bCommandType = UWB_CE_TYPE_GENERAL;
709 rccb_cmd.rccb.wCommand = UWB_CE_GET_IE;
710
711 if (uwb_process_rccb_cmd_private(uwb_dev_hdl,
712 (uwb_rccb_cmd_t *)&rccb_cmd, (uwb_cmd_result_t *)NULL) != 0) {
713 uwba_log((uwba_dev_t *)uwb_dev_hdl, UWBA_LOG_LOG,
714 "uwb_init_phy: process cmd failed");
715
716 return (UWB_FAILURE);
717 }
718 /* todo: rceb result is handled in event notification */
719
720 return (UWB_SUCCESS);
721 }
722
723
724 /* Get a notif from the list head. That notif is dis-linked from the list. */
725 static uwb_notif_wrapper_t *
uwb_get_notif_head(uwb_dev_handle_t uwb_dev_hdl)726 uwb_get_notif_head(uwb_dev_handle_t uwb_dev_hdl)
727 {
728 uwb_notif_wrapper_t *nw = NULL;
729 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
730
731 mutex_enter(&uwba_dev->dev_mutex);
732
733 if (!list_is_empty(&uwba_dev->notif_list)) {
734 nw = list_head(&uwba_dev->notif_list);
735 if (nw != NULL) {
736
737 /*
738 * unlink a notification wrapper's structure from the
739 * list
740 */
741 list_remove(&(uwba_dev->notif_list), nw);
742 }
743 }
744 mutex_exit(&uwba_dev->dev_mutex);
745
746 return (nw);
747 }
748
749 /*
750 * UWB ioctls
751 * UWB_COMMAND --- Send a rccb command to the radio controller
752 * UWB_GET_NOTIFICATION -- Get the uwb notifications. Not used
753 */
754 int
uwb_do_ioctl(uwb_dev_handle_t uwb_dev_hdl,int cmd,intptr_t arg,int mode)755 uwb_do_ioctl(uwb_dev_handle_t uwb_dev_hdl,
756 int cmd, intptr_t arg, int mode)
757 {
758 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
759 int rv = 0;
760
761 switch (cmd) {
762 case UWB_COMMAND: /* Issue commands to UWB Radio Controller */
763 {
764 uwb_rccb_cmd_t rccb_cmd;
765 if (ddi_copyin((caddr_t)arg, &rccb_cmd,
766 sizeof (rccb_cmd), mode)) {
767 uwba_log(uwba_dev, UWBA_LOG_LOG,
768 "uwb_do_ioctl: ddi_copyin fail");
769
770 rv = EFAULT;
771 break;
772 }
773 if (uwb_check_rccb_cmd(uwb_dev_hdl, &rccb_cmd) != UWB_SUCCESS) {
774
775 rv = EINVAL;
776 break;
777 }
778 if (uwb_do_ioctl_rccb_cmd(uwb_dev_hdl, rccb_cmd.rccb.wCommand,
779 arg, mode)
780 != UWB_SUCCESS) {
781
782 uwba_log(uwba_dev, UWBA_LOG_LOG,
783 "uwb_do_ioctl: uwb_do_ioctl_rccb_cmd failed");
784 rv = EIO;
785 }
786
787 break;
788 }
789 case UWB_GET_NOTIFICATION:
790 {
791 uwb_notif_wrapper_t *nw;
792
793 nw = uwb_get_notification(uwb_dev_hdl, arg, mode);
794
795 if (nw && nw->notif) {
796 /* Copy the notification to userland application */
797 if (ddi_copyout(nw->notif,
798 (caddr_t)&(((uwb_notif_get_t *)arg)->notif),
799 nw->length, mode)) { /* todo: 32bit/64bit */
800
801 rv = EFAULT;
802 }
803 /* release the notif and the wrapper. */
804 uwb_free_notification(nw);
805 } else {
806 rv = EIO;
807 }
808
809 break;
810 }
811 default:
812 uwba_log(uwba_dev, UWBA_LOG_LOG,
813 "uwb_do_ioctl: not a valid cmd value, cmd=%x", cmd);
814 rv = EINVAL;
815 }
816
817 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
818 "uwb_do_ioctl: exit, rv=%d", rv);
819
820 return (rv);
821 }
822
823
824 /*
825 * Parse all the standard events, including command results and notifications.
826 * If a unknown event, return UWB_NOT_SUPPORTED. The specific client radio
827 * controllers might has the knowledge to parse the vendor specific
828 * events/notifications.
829 */
830 int
uwb_parse_evt_notif(uint8_t * data,int data_len,uwb_dev_handle_t uwb_dev_hdl)831 uwb_parse_evt_notif(uint8_t *data, int data_len,
832 uwb_dev_handle_t uwb_dev_hdl)
833 {
834 uint16_t evt_code, evt_size;
835 void *evt_struct;
836 uwb_rceb_head_t *rceb;
837 uwba_dev_t *uwba_dev;
838 uint8_t *spec_data; /* the raw event data excluding rceb. */
839 int spec_data_len, offset;
840 int rval = UWB_SUCCESS;
841
842 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
843
844 /* Get evt/notif code */
845 if ((evt_code = uwba_get_evt_code(data, data_len)) ==
846 UWB_INVALID_EVT_CODE) {
847 uwba_log(uwba_dev, UWBA_LOG_LOG,
848 "uwb_parse_evt_notif: invalid evt_code");
849
850 return (UWB_INVALID_EVT_CODE);
851 }
852
853 if ((evt_size = uwba_get_evt_size(data, data_len, evt_code)) ==
854 UWB_INVALID_EVT_SIZE) {
855 uwba_log(uwba_dev, UWBA_LOG_LOG,
856 "uwb_parse_evt_notif: invalid evt_size. evt_code=%d",
857 evt_code);
858
859 return (UWB_INVALID_EVT_SIZE);
860 }
861 evt_struct = kmem_alloc(evt_size, KM_NOSLEEP);
862 if (evt_struct == NULL) {
863
864 return (UWB_NO_RESOURCES);
865 }
866
867 /* parse rceb and get the data offset just after the rceb struct. */
868 if ((offset = uwba_parse_rceb(data, data_len, evt_struct, evt_size))
869 == UWB_PARSE_ERROR) {
870 uwba_log(uwba_dev, UWBA_LOG_LOG,
871 "uwb_parse_evt_notif: uwba_parse_rceb failed");
872 kmem_free(evt_struct, evt_size);
873
874 return (UWB_PARSE_ERROR);
875 }
876 rceb = (uwb_rceb_head_t *)evt_struct;
877 if (rceb->bEventContext > 0 &&
878 rceb->bEventContext != uwba_dev->ctxt_id) {
879 uwba_log(uwba_dev, UWBA_LOG_LOG,
880 "uwb_parse_evt_notif: cmd result's ctxt_id is "
881 "not matching cmd's ctxt_id,"
882 " result ctxt_id=%d, cmd ctxt_id=%d",
883 rceb->bEventContext, uwba_dev->ctxt_id);
884 }
885
886 /* the data after rceb head are evt specific data */
887 spec_data = data + offset;
888 spec_data_len = data_len - offset;
889
890 switch (evt_code) {
891 case UWB_CE_CHANNEL_CHANGE:
892 case UWB_CE_RESET:
893 case UWB_CE_SCAN:
894 case UWB_CE_SET_BEACON_FILTER:
895 case UWB_CE_SET_NOTIFICATION_FILTER:
896 case UWB_CE_SET_TX_POWER:
897 case UWB_CE_SLEEP:
898 case UWB_CE_START_BEACON:
899 case UWB_CE_STOP_BEACON:
900 case UWB_CE_BP_MERGE:
901 case UWB_CE_SEND_COMMAND_FRAME:
902 case UWB_CE_SET_ASIE_NOTIFICATION:
903 /* All the above cmd results have only result code. */
904 ((uwb_rceb_result_code_t *)evt_struct)->bResultCode =
905 *spec_data;
906 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
907 "uwb_parse_evt_notif: msg = %s, bResultCode = %d ",
908 uwba_event_msg(evt_code), *spec_data);
909
910 break;
911 case UWB_CE_DEV_ADDR_MGMT:
912 rval = uwba_parse_dev_addr_mgmt(spec_data, spec_data_len,
913 (uwb_rceb_dev_addr_mgmt_t *)evt_struct);
914
915 break;
916 case UWB_CE_GET_IE:
917 rval = uwba_parse_get_ie(uwb_dev_hdl, spec_data, spec_data_len,
918 (uwb_rceb_get_ie_t *)evt_struct);
919
920 break;
921 case UWB_NOTIF_BEACON_RECEIVED:
922 rval = uwba_parse_beacon_rcv(uwb_dev_hdl, spec_data,
923 spec_data_len, (uwb_rceb_beacon_t *)evt_struct);
924 break;
925 case UWB_NOTIF_BPOIE_CHANGE:
926 rval = uwba_parse_bpoie_chg(uwb_dev_hdl, spec_data,
927 spec_data_len, (uwb_rceb_bpoie_change_t *)evt_struct);
928 break;
929
930 case UWB_NOTIF_BEACON_SIZE_CHANGE:
931 case UWB_CE_SET_DRP_IE:
932 case UWB_CE_SET_IE:
933 case UWB_NOTIF_IE_RECEIVED:
934 case UWB_NOTIF_BP_SLOT_CHANGE:
935 case UWB_NOTIF_BP_SWITCH_IE_RECEIVED:
936 case UWB_NOTIF_DEV_ADDR_CONFLICT:
937 case UWB_NOTIF_DRP_AVAILABILITY_CHANGE:
938 case UWB_NOTIF_DRP:
939 case UWB_NOTIF_BP_SWITCH_STATUS:
940 case UWB_NOTIF_CMD_FRAME_RCV:
941 case UWB_NOTIF_CHANNEL_CHANGE_IE_RCV:
942 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
943 "uwb_parse_evt_notif: %s not supported",
944 uwba_event_msg(evt_code));
945 break;
946
947 default: /* unkonwn events or notifications */
948 uwba_log(uwba_dev, UWBA_LOG_LOG,
949 "uwb_parse_evt_notif: unkonwn events or notifications,"
950 " evt_code=%d", evt_code);
951 break;
952 }
953
954 if (rval != UWB_SUCCESS) {
955 uwba_log(uwba_dev, UWBA_LOG_LOG,
956 "uwb_parse_evt_notif: fail, rval = %d", rval);
957
958 kmem_free(evt_struct, evt_size);
959
960 return (rval);
961 }
962
963 /*
964 * By now, parse complete. Go on notify the waiting cmd thread or add
965 * notification to list
966 */
967 if (evt_code > UWB_NOTIF_RESERVED) {
968 /* If this event is a cmd result */
969 uwba_put_cmd_result(uwba_dev, evt_struct, evt_size);
970 } else {
971
972 /* If this event is a notification */
973 rval = uwba_add_notif_to_list(uwba_dev, evt_struct, evt_size);
974 }
975
976 return (rval);
977 }
978
979
980 /*
981 * Send command to device. This function is shared by those commands whose cmd
982 * data have rccb only.
983 */
984 static int
uwb_do_cmd_rccb(uwb_dev_handle_t uwb_dev_hdl,uwb_rccb_cmd_t * rccb_cmd)985 uwb_do_cmd_rccb(uwb_dev_handle_t uwb_dev_hdl, uwb_rccb_cmd_t *rccb_cmd)
986 {
987 /* reset cmd has no extra bytes, just rccb */
988 mblk_t *data;
989 uint16_t data_len;
990 uwba_dev_t *uwba_dev;
991 int rval = UWB_SUCCESS;
992
993 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
994
995 /* size of rccb. Reset cmd has no data other than rccb head */
996 data_len = UWB_RAW_RCCB_HEAD_SIZE;
997
998 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
999 "uwb_do_cmd_rccb: wLength=%d", data_len);
1000
1001 /* Data block */
1002 if ((data = allocb(data_len, BPRI_HI)) == NULL) {
1003 uwba_log(uwba_dev, UWBA_LOG_LOG,
1004 "uwb_do_cmd_rccb: allocb failed");
1005
1006 return (UWB_FAILURE);
1007 }
1008
1009 uwba_fill_rccb_head(uwba_dev, rccb_cmd->rccb.wCommand, data);
1010 data->b_wptr += data_len;
1011
1012 /* record the current cmd rccb to the uwb dev handle. */
1013 uwba_copy_rccb(rccb_cmd, &(uwba_dev->curr_rccb));
1014 uwba_dev->curr_rccb.rccb.bCommandContext = data->b_rptr[3];
1015
1016 /*
1017 * data will be freed by radio client driver after the cmd is sent to
1018 * device
1019 */
1020 rval = uwba_dev->send_cmd(uwb_dev_hdl, data, data_len);
1021 if (rval != UWB_SUCCESS) {
1022 uwba_log(uwba_dev, UWBA_LOG_LOG,
1023 "uwb_do_cmd_rccb: send cmd fail ");
1024
1025 return (rval);
1026 }
1027
1028 return (rval);
1029 }
1030
1031 /* Dev addr management rccb cmd handler */
1032 static int
uwb_do_cmd_dev_addr_mgmt(uwb_dev_handle_t uwb_dev_hdl,uwb_rccb_cmd_t * rccb_cmd)1033 uwb_do_cmd_dev_addr_mgmt(uwb_dev_handle_t uwb_dev_hdl,
1034 uwb_rccb_cmd_t *rccb_cmd)
1035 {
1036 mblk_t *data;
1037 uint16_t data_len;
1038 uwba_dev_t *uwba_dev;
1039 int i, rval = UWB_SUCCESS;
1040 uwb_rccb_dev_addr_mgmt_t *rccb_dev_addr =
1041 (uwb_rccb_dev_addr_mgmt_t *)rccb_cmd;
1042
1043 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1044 /* size of device address mgmt RCCB */
1045 data_len = UWB_RAW_RCCB_HEAD_SIZE + 7;
1046
1047 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1048 "uwb_do_cmd_dev_addr_mgmt: wLength=%d, type=%x",
1049 data_len, rccb_dev_addr->bmOperationType);
1050
1051 /* Data block */
1052 if ((data = allocb(data_len, BPRI_HI)) == NULL) {
1053 uwba_log(uwba_dev, UWBA_LOG_LOG,
1054 "uwb_do_cmd_dev_addr_mgmt: allocb failed");
1055
1056 return (UWB_NO_RESOURCES);
1057 }
1058
1059 uwba_fill_rccb_head(uwba_dev, rccb_dev_addr->rccb.wCommand, data);
1060 data->b_rptr[4] = rccb_dev_addr->bmOperationType;
1061 for (i = 0; i < 6; i++) {
1062 data->b_rptr[5 + i] = rccb_dev_addr->baAddr[i];
1063 }
1064 data->b_wptr += data_len;
1065
1066 /* record the current cmd rccb to the uwb dev handle. */
1067 uwba_copy_rccb((uwb_rccb_cmd_t *)rccb_dev_addr, &(uwba_dev->curr_rccb));
1068 uwba_dev->curr_rccb.rccb.bCommandContext = data->b_rptr[3];
1069
1070 if ((rval = uwba_dev->send_cmd(uwb_dev_hdl, data, data_len))
1071 != UWB_SUCCESS) {
1072 uwba_log(uwba_dev, UWBA_LOG_LOG,
1073 "uwb_do_cmd_dev_addr_mgmt: fail ");
1074
1075 return (rval);
1076 }
1077
1078 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1079 "uwb_do_cmd_dev_addr_mgmt: success.");
1080
1081 return (rval);
1082 }
1083
1084 /* Scan rccb cmd handler */
1085 static int
uwb_do_cmd_scan(uwb_dev_handle_t uwb_dev_hdl,uwb_rccb_cmd_t * rccb_cmd)1086 uwb_do_cmd_scan(uwb_dev_handle_t uwb_dev_hdl, uwb_rccb_cmd_t *rccb_cmd)
1087 {
1088 mblk_t *data;
1089 uint16_t data_len;
1090 uwba_dev_t *uwba_dev;
1091 int rval = UWB_SUCCESS;
1092 uwb_rccb_scan_t *rccb_scan = (uwb_rccb_scan_t *)rccb_cmd;
1093
1094 uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1095 data_len = UWB_RAW_RCCB_HEAD_SIZE + 4; /* size of scan RCCB */
1096
1097 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1098 "uwb_do_cmd_scan: wLength=%d", data_len);
1099
1100 /* Data block */
1101 if ((data = allocb(data_len, BPRI_HI)) == NULL) {
1102 uwba_log(uwba_dev, UWBA_LOG_LOG,
1103 "uwb_do_cmd_scan: allocb failed");
1104
1105 return (UWB_NO_RESOURCES);
1106 }
1107
1108 uwba_fill_rccb_head(uwba_dev, rccb_scan->rccb.wCommand, data);
1109 data->b_rptr[4] = rccb_scan->bChannelNumber;
1110 data->b_rptr[5] = rccb_scan->bScanState;
1111 UINT16_TO_LE(rccb_scan->wStartTime, 6, data->b_rptr);
1112 data->b_wptr += data_len;
1113
1114 /* record the current cmd rccb to the uwb dev handle. */
1115 uwba_copy_rccb((uwb_rccb_cmd_t *)rccb_scan, &(uwba_dev->curr_rccb));
1116 uwba_dev->curr_rccb.rccb.bCommandContext = data->b_rptr[3];
1117
1118 if ((rval = uwba_dev->send_cmd(uwb_dev_hdl, data, data_len))
1119 != UWB_SUCCESS) {
1120 uwba_log(uwba_dev, UWBA_LOG_LOG,
1121 "uwb_send_rccb_cmd: fail ");
1122
1123 return (rval);
1124 }
1125
1126 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1127 "uwb_do_cmd_scan: success.");
1128
1129 return (rval);
1130 }
1131
1132 /* Start beacon rccb handler */
1133 static int
uwb_do_cmd_start_beacon(uwb_dev_handle_t uwb_dev_hdl,uwb_rccb_cmd_t * rccb_cmd)1134 uwb_do_cmd_start_beacon(uwb_dev_handle_t uwb_dev_hdl,
1135 uwb_rccb_cmd_t *rccb_cmd)
1136 {
1137 mblk_t *data;
1138 uint16_t data_len;
1139 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1140 int rval = UWB_SUCCESS;
1141 uwba_client_dev_t *client = NULL;
1142 uwb_rccb_start_beacon_t *rccb_startbc =
1143 (uwb_rccb_start_beacon_t *)rccb_cmd;
1144
1145 if (client = uwba_find_cdev_by_channel(uwba_dev,
1146 rccb_startbc->bChannelNumber)) {
1147 rccb_startbc->wBPSTOffset = client->wBPSTOffset;
1148 }
1149
1150 data_len = UWB_RAW_RCCB_HEAD_SIZE + 3; /* size of start beacon RCCB */
1151
1152 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1153 "uwb_do_cmd_start_beacon: channel= %d , BPSTOffset = %d",
1154 rccb_startbc->bChannelNumber, rccb_startbc->wBPSTOffset);
1155 /* Data block */
1156 if ((data = allocb(data_len, BPRI_HI)) == NULL) {
1157 uwba_log(uwba_dev, UWBA_LOG_LOG,
1158 "uwb_do_cmd_start_beacon: allocb failed");
1159
1160 return (UWB_FAILURE);
1161 }
1162
1163 uwba_fill_rccb_head(uwba_dev, rccb_startbc->rccb.wCommand, data);
1164 UINT16_TO_LE(rccb_startbc->wBPSTOffset, 4, data->b_rptr);
1165 data->b_rptr[6] = rccb_startbc->bChannelNumber;
1166 data->b_wptr += data_len;
1167
1168 /* record the current cmd rccb to the uwb dev handle. */
1169 uwba_copy_rccb((uwb_rccb_cmd_t *)rccb_startbc, &(uwba_dev->curr_rccb));
1170 uwba_dev->curr_rccb.rccb.bCommandContext = data->b_rptr[3];
1171 if ((rval = uwba_dev->send_cmd(uwb_dev_hdl, data, data_len))
1172 != UWB_SUCCESS) {
1173 uwba_log(uwba_dev, UWBA_LOG_LOG,
1174 "uwb_do_cmd_start_beacon: send_cmd failed, channel = %d,"
1175 "wBPSTOffset = %d", rccb_startbc->bChannelNumber,
1176 rccb_startbc->wBPSTOffset);
1177
1178 return (rval);
1179 }
1180
1181 return (rval);
1182 }
1183
1184 /* Send rccb cmd and get the rceb result */
1185 static int
uwb_process_rccb_cmd_private(uwb_dev_handle_t uwb_dev_hdl,uwb_rccb_cmd_t * rccb_cmd,uwb_cmd_result_t * cmd_result)1186 uwb_process_rccb_cmd_private(uwb_dev_handle_t uwb_dev_hdl,
1187 uwb_rccb_cmd_t *rccb_cmd, uwb_cmd_result_t *cmd_result)
1188 {
1189 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1190 int rval = UWB_SUCCESS;
1191
1192 if (uwb_check_dev_state(uwba_dev, rccb_cmd) != UWB_SUCCESS) {
1193
1194 uwba_log(uwba_dev, UWBA_LOG_LOG,
1195 "uwb_process_rccb_cmd_private: illegal dev_state:%d",
1196 uwba_dev->dev_state);
1197
1198 return (UWB_FAILURE);
1199 }
1200
1201
1202
1203 if (uwb_rccb_cmd_enter(uwba_dev) != UWB_SUCCESS) {
1204 uwba_log(uwba_dev, UWBA_LOG_LOG,
1205 "uwb_process_rccb_cmd_private: fail to enter"
1206 "wCommand = %d, %s ", rccb_cmd->rccb.wCommand,
1207 uwba_event_msg(rccb_cmd->rccb.wCommand));
1208
1209 return (UWB_FAILURE);
1210 }
1211
1212 if ((rval = uwb_send_rccb_cmd(uwb_dev_hdl, rccb_cmd)) != UWB_SUCCESS) {
1213 uwba_log(uwba_dev, UWBA_LOG_LOG,
1214 "uwb_process_rccb_cmd_private: fail to send"
1215 "wCommand = %d, %s ", rccb_cmd->rccb.wCommand,
1216 uwba_event_msg(rccb_cmd->rccb.wCommand));
1217 goto cleanup;
1218 }
1219
1220 mutex_enter(&uwba_dev->dev_mutex);
1221 /* Copy the command result to application */
1222 if (cmd_result) {
1223 bcopy(uwba_dev->cmd_result_wrap.cmd_result, cmd_result,
1224 uwba_dev->cmd_result_wrap.length);
1225 }
1226 /* release the command result (event) block. */
1227 uwb_free_cmd_result(uwb_dev_hdl);
1228
1229 uwb_set_dev_state(uwba_dev, rccb_cmd);
1230
1231 mutex_exit(&uwba_dev->dev_mutex);
1232
1233 cleanup:
1234 uwb_rccb_cmd_leave(uwba_dev);
1235
1236 return (rval);
1237 }
1238
1239 /* Call rccb handler to send a rccb cmd */
1240 static int
uwb_send_rccb_cmd(uwb_dev_handle_t uwb_dev_hdl,uwb_rccb_cmd_t * rccb_cmd)1241 uwb_send_rccb_cmd(uwb_dev_handle_t uwb_dev_hdl, uwb_rccb_cmd_t *rccb_cmd)
1242 {
1243 int rccb_index = rccb_cmd->rccb.wCommand - UWB_CE_CHANNEL_CHANGE;
1244 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1245 ASSERT(rccb_cmd->rccb.bCommandType == UWB_CE_TYPE_GENERAL);
1246
1247 mutex_enter(&uwba_dev->dev_mutex);
1248 if (uwb_rccb_handler_tbl[rccb_index](uwb_dev_hdl, rccb_cmd)
1249 != UWB_SUCCESS) {
1250 uwba_log(uwba_dev, UWBA_LOG_LOG,
1251 "uwb_send_rccb_cmd: uwb_send_rccb_cmd failed");
1252 goto failure;
1253
1254 }
1255 if (uwb_wait_cmd_result(uwb_dev_hdl) != UWB_SUCCESS) {
1256 uwba_log(uwba_dev, UWBA_LOG_LOG,
1257 "uwb_send_rccb_cmd: fail to get cmd result ");
1258 goto failure;
1259 }
1260
1261 mutex_exit(&uwba_dev->dev_mutex);
1262
1263 return (UWB_SUCCESS);
1264 failure:
1265 mutex_exit(&uwba_dev->dev_mutex);
1266
1267 return (UWB_FAILURE);
1268
1269 }
1270 /* Check a rccb cmd */
1271 static int
uwb_check_rccb_cmd(uwb_dev_handle_t uwb_dev_hdl,uwb_rccb_cmd_t * rccb_cmd)1272 uwb_check_rccb_cmd(uwb_dev_handle_t uwb_dev_hdl, uwb_rccb_cmd_t *rccb_cmd)
1273 {
1274 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1275 int rccb_index = rccb_cmd->rccb.wCommand - UWB_CE_CHANNEL_CHANGE;
1276
1277 if (rccb_cmd->rccb.bCommandType != UWB_CE_TYPE_GENERAL) {
1278 uwba_log(uwba_dev, UWBA_LOG_LOG,
1279 "uwb_check_rccb_cmd: invalid bCommandType = %d",
1280 rccb_cmd->rccb.bCommandType);
1281
1282 return (UWB_FAILURE);
1283 }
1284 if ((rccb_cmd->rccb.wCommand < UWB_CE_CHANNEL_CHANGE) ||
1285 (rccb_cmd->rccb.wCommand > UWB_CE_SET_ASIE_NOTIFICATION)) {
1286 uwba_log(uwba_dev, UWBA_LOG_LOG,
1287 "uwb_check_rccb_cmd: invalid wCommand = %d",
1288 rccb_cmd->rccb.wCommand);
1289
1290 return (UWB_FAILURE);
1291 }
1292 if (uwb_rccb_handler_tbl[rccb_index] == UWB_RCCB_NULL_HANDLER) {
1293 uwba_log(uwba_dev, UWBA_LOG_LOG,
1294 "uwb_send_rccb_cmd: unsupportted wCommand = %d",
1295 rccb_cmd->rccb.wCommand);
1296
1297 return (UWB_FAILURE);
1298 }
1299
1300 return (UWB_SUCCESS);
1301 }
1302
1303 /* Check the current dev state */
1304 static int
uwb_check_dev_state(uwba_dev_t * uwba_dev,uwb_rccb_cmd_t * rccb_cmd)1305 uwb_check_dev_state(uwba_dev_t *uwba_dev, uwb_rccb_cmd_t *rccb_cmd) {
1306 uint8_t state = uwba_dev->dev_state;
1307
1308 switch (rccb_cmd->rccb.wCommand) {
1309 case UWB_CE_SCAN:
1310 if (((uwb_rccb_scan_t *)rccb_cmd)->bScanState
1311 == UWB_RC_SCAN_DISABLED) {
1312 if (state == UWB_STATE_SCAN) {
1313
1314 return (UWB_SUCCESS);
1315 }
1316 } else {
1317
1318 if (state == UWB_STATE_IDLE) {
1319
1320 return (UWB_SUCCESS);
1321 }
1322 }
1323 break;
1324
1325 case UWB_CE_START_BEACON:
1326 case UWB_CE_RESET:
1327 if (state == UWB_STATE_IDLE) {
1328
1329 return (UWB_SUCCESS);
1330 }
1331 break;
1332
1333 case UWB_CE_STOP_BEACON:
1334 if (state == UWB_STATE_BEACON) {
1335
1336 return (UWB_SUCCESS);
1337 }
1338 break;
1339
1340 default:
1341 return (UWB_SUCCESS);
1342 }
1343
1344 return (UWB_FAILURE);
1345 }
1346 /* Set the uwb dev state */
1347 static void
uwb_set_dev_state(uwba_dev_t * uwba_dev,uwb_rccb_cmd_t * rccb_cmd)1348 uwb_set_dev_state(uwba_dev_t *uwba_dev, uwb_rccb_cmd_t *rccb_cmd) {
1349 switch (rccb_cmd->rccb.wCommand) {
1350 case UWB_CE_SCAN:
1351 {
1352 uwb_rccb_scan_t *cmd =
1353 (uwb_rccb_scan_t *)rccb_cmd;
1354 if (cmd->bScanState == UWB_RC_SCAN_DISABLED) {
1355
1356 uwba_dev->dev_state = UWB_STATE_IDLE;
1357 } else {
1358
1359 uwba_dev->dev_state = UWB_STATE_SCAN;
1360 uwba_dev->channel = cmd->bChannelNumber;
1361 }
1362 }
1363 break;
1364
1365 case UWB_CE_START_BEACON:
1366 {
1367 uwb_rccb_start_beacon_t *cmd =
1368 (uwb_rccb_start_beacon_t *)rccb_cmd;
1369 uwba_dev->dev_state = UWB_STATE_BEACON;
1370 uwba_dev->channel = cmd->bChannelNumber;
1371 }
1372 break;
1373
1374 case UWB_CE_STOP_BEACON:
1375 case UWB_CE_RESET:
1376
1377 uwba_dev->dev_state = UWB_STATE_IDLE;
1378 break;
1379 case UWB_CE_DEV_ADDR_MGMT:
1380 {
1381 uwb_rccb_dev_addr_mgmt_t *cmd =
1382 (uwb_rccb_dev_addr_mgmt_t *)rccb_cmd;
1383 if (cmd->bmOperationType == 1)
1384 {
1385 uwba_dev->dev_addr = cmd->baAddr[1];
1386 uwba_dev->dev_addr =
1387 uwba_dev->dev_addr <<8;
1388 uwba_dev->dev_addr =
1389 uwba_dev->dev_addr | cmd->baAddr[0];
1390 }
1391 }
1392 break;
1393
1394 default:
1395 break;
1396 }
1397
1398 }
1399
1400 /* Handle rccb cmd for ioctl */
1401 static int
uwb_do_ioctl_rccb_cmd(uwb_dev_handle_t uwb_dev_hdl,uint16_t wCommand,intptr_t arg,int mode)1402 uwb_do_ioctl_rccb_cmd(uwb_dev_handle_t uwb_dev_hdl, uint16_t wCommand,
1403 intptr_t arg, int mode)
1404 {
1405 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1406 int rv = UWB_FAILURE;
1407
1408 int rccb_size = uwb_rccb_size_tbl[wCommand - UWB_CE_CHANNEL_CHANGE];
1409 uwb_rccb_cmd_t *rccb_cmd = NULL;
1410
1411 if (uwb_rccb_cmd_enter(uwba_dev) != UWB_SUCCESS) {
1412 uwba_log(uwba_dev, UWBA_LOG_LOG,
1413 "uwb_do_ioctl_rccb_cmd: enter cmd fail");
1414
1415 return (UWB_FAILURE);
1416 }
1417 rccb_cmd = kmem_alloc(rccb_size, KM_NOSLEEP);
1418 if (ddi_copyin((caddr_t)arg, rccb_cmd, rccb_size, mode)) {
1419
1420 uwba_log(uwba_dev, UWBA_LOG_LOG,
1421 "uwb_do_ioctl_rccb_cmd: ddi_copyin fail");
1422
1423 goto cleanup;
1424 }
1425
1426 if (uwb_check_dev_state(uwba_dev, rccb_cmd) != UWB_SUCCESS) {
1427
1428 uwba_log(uwba_dev, UWBA_LOG_LOG,
1429 "uwb_check_dev_state: illegal dev_state:%d",
1430 uwba_dev->dev_state);
1431
1432 goto cleanup;
1433 }
1434
1435
1436 if ((uwb_send_rccb_cmd(uwb_dev_hdl, rccb_cmd)) != UWB_SUCCESS) {
1437 uwba_log(uwba_dev, UWBA_LOG_LOG,
1438 "uwb_do_ioctl_rccb_cmd: fail to send wCommand = %d ",
1439 rccb_cmd->rccb.wCommand);
1440
1441 goto cleanup;
1442 }
1443
1444 /* Copy the command result to application */
1445 mutex_enter(&uwba_dev->dev_mutex);
1446 if (ddi_copyout(uwba_dev->cmd_result_wrap.cmd_result, (caddr_t)arg,
1447 uwba_dev->cmd_result_wrap.length, mode)) {
1448
1449 uwba_log(uwba_dev, UWBA_LOG_LOG,
1450 "uwb_do_ioctl_rccb_cmd: ddi_copyout fail");
1451 } else {
1452 rv = UWB_SUCCESS;
1453 }
1454
1455 /* release the command result (event) block. */
1456 uwb_free_cmd_result(uwb_dev_hdl);
1457
1458 uwb_set_dev_state(uwba_dev, rccb_cmd);
1459 mutex_exit(&uwba_dev->dev_mutex);
1460
1461 cleanup:
1462 uwb_rccb_cmd_leave(uwba_dev);
1463 kmem_free(rccb_cmd, rccb_size);
1464
1465 return (rv);
1466 }
1467
1468 /*
1469 * alloc evt block according to cmd code; alloc context id;
1470 * link the evt block to uwb_dev_hdl
1471 */
1472 static int
uwb_wait_cmd_result(uwb_dev_handle_t uwb_dev_hdl)1473 uwb_wait_cmd_result(uwb_dev_handle_t uwb_dev_hdl)
1474 {
1475 int rval = UWB_SUCCESS;
1476 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1477
1478 ASSERT(mutex_owned(&uwba_dev->dev_mutex));
1479
1480 while (uwba_dev->cmd_result_wrap.cmd_result == NULL) {
1481
1482 if (cv_timedwait_sig(&uwba_dev->cmd_result_cv,
1483 &uwba_dev->dev_mutex, UWB_CMD_TIMEOUT) <= 0) {
1484
1485 /* no cmd result is received and cv is signaled */
1486 rval = UWB_FAILURE;
1487
1488 return (rval);
1489 }
1490 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1491 "uwb_wait_cmd_result: wait for cmd complete end, "
1492 "cv_signal received.");
1493 }
1494 ASSERT(uwba_dev->cmd_result_wrap.cmd_result != NULL);
1495
1496 return (rval);
1497 }
1498
1499 static void
uwb_free_cmd_result(uwb_dev_handle_t uwb_dev_hdl)1500 uwb_free_cmd_result(uwb_dev_handle_t uwb_dev_hdl)
1501 {
1502 uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1503
1504
1505 ASSERT(mutex_owned(&uwba_dev->dev_mutex));
1506
1507 kmem_free(uwba_dev->cmd_result_wrap.cmd_result,
1508 uwba_dev->cmd_result_wrap.length);
1509 uwba_dev->cmd_result_wrap.cmd_result = NULL;
1510 uwba_dev->cmd_result_wrap.length = 0;
1511 uwba_free_ctxt_id(uwba_dev, uwba_dev->ctxt_id);
1512 }
1513
1514 /* Get notif for ioctl */
1515 static uwb_notif_wrapper_t *
uwb_get_notification(uwb_dev_handle_t uwb_dev_hdl,intptr_t arg,int mode)1516 uwb_get_notification(uwb_dev_handle_t uwb_dev_hdl,
1517 intptr_t arg, int mode)
1518 {
1519 uwb_notif_wrapper_t *notif;
1520 uwb_notif_get_t ng;
1521
1522
1523 if (ddi_copyin((caddr_t)arg, &ng, sizeof (ng), mode)) {
1524
1525 return (NULL);
1526 }
1527 if (ng.notif.rceb.bEventType != UWB_CE_TYPE_GENERAL) {
1528
1529 return (NULL);
1530 }
1531
1532 notif = uwb_get_notif_head(uwb_dev_hdl);
1533
1534 return (notif);
1535 }
1536 /* Free a notif from notificatin list */
1537 static void
uwb_free_notification(uwb_notif_wrapper_t * nw)1538 uwb_free_notification(uwb_notif_wrapper_t *nw)
1539 {
1540 ASSERT(nw->notif);
1541
1542 kmem_free(nw->notif, nw->length);
1543 kmem_free(nw, sizeof (uwb_notif_wrapper_t));
1544 }
1545 /* uwb rccb cmd handler lock */
1546 static int
uwb_rccb_cmd_enter(uwba_dev_t * uwba_dev)1547 uwb_rccb_cmd_enter(uwba_dev_t *uwba_dev)
1548 {
1549 mutex_enter(&uwba_dev->dev_mutex);
1550 while (uwba_dev->cmd_busy == B_TRUE) {
1551 if (cv_wait_sig(&uwba_dev->cmd_handler_cv,
1552 &uwba_dev->dev_mutex) <= 0) {
1553 mutex_exit(&uwba_dev->dev_mutex);
1554
1555 return (UWB_FAILURE);
1556 }
1557 }
1558 uwba_dev->cmd_busy = B_TRUE;
1559 mutex_exit(&uwba_dev->dev_mutex);
1560
1561 return (UWB_SUCCESS);
1562 }
1563 /* uwb rccb cmd handler unlock */
1564 static void
uwb_rccb_cmd_leave(uwba_dev_t * uwba_dev)1565 uwb_rccb_cmd_leave(uwba_dev_t *uwba_dev)
1566 {
1567 mutex_enter(&uwba_dev->dev_mutex);
1568 uwba_dev->cmd_busy = B_FALSE;
1569 cv_signal(&uwba_dev->cmd_handler_cv);
1570 mutex_exit(&uwba_dev->dev_mutex);
1571 }
1572