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 }