xref: /onnv-gate/usr/src/uts/common/io/uwb/uwba/uwbai.c (revision 10912:bb04b6e33d44)
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