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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 }