uwbai.c revision ff0e937b36dcde1a47ff7b00aa76a491c0dc07a8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* UWB radio controller driver interfaces
*/
/*
* The following is a list of functions which handles the rccb command
* for uwb model, each rccb command has a related handler. Not all the
* rccb command is supportted, the below uwb_rccb_handler_tbl lists
* the supported handler
*/
static int uwb_do_cmd_start_beacon(uwb_dev_handle_t,
uwb_rccb_cmd_t *);
static int uwb_process_rccb_cmd_private(uwb_dev_handle_t,
uwb_rccb_cmd_t *, uwb_cmd_result_t *);
static int uwb_wait_cmd_result(uwb_dev_handle_t);
static void uwb_free_cmd_result(uwb_dev_handle_t);
static int uwb_rccb_cmd_enter(uwba_dev_t *);
static void uwb_rccb_cmd_leave(uwba_dev_t *);
static int uwb_do_ioctl_rccb_cmd(uwb_dev_handle_t,
intptr_t, int);
static void uwb_free_notification(uwb_notif_wrapper_t *);
/*
*
* This is all the rccb command handler supported and not supported in
* current version. rccb handler table map
*/
static uwb_rccb_handler_t uwb_rccb_handler_tbl [] = {
UWB_RCCB_NULL_HANDLER, /* CHANNEL_CHANGE */
uwb_do_cmd_dev_addr_mgmt, /* DEV_ADDR_MGMT */
uwb_do_cmd_rccb, /* GET_IE */
uwb_do_cmd_rccb, /* RESET */
uwb_do_cmd_scan, /* SCAN */
UWB_RCCB_NULL_HANDLER, /* SET_BEACON_FILTER */
UWB_RCCB_NULL_HANDLER, /* SET_DRP_IE */
UWB_RCCB_NULL_HANDLER, /* SET_IE */
UWB_RCCB_NULL_HANDLER, /* SET_NOTIFICATION_FILTER */
UWB_RCCB_NULL_HANDLER, /* SET_TX_POWER */
UWB_RCCB_NULL_HANDLER, /* SLEEP */
uwb_do_cmd_start_beacon, /* START_BEACON */
uwb_do_cmd_rccb, /* STOP_BEACON */
UWB_RCCB_NULL_HANDLER, /* BP_MERGE */
UWB_RCCB_NULL_HANDLER /* SEND_COMMAND_FRAME */
};
/*
* This table recode different size of the rccb command data block
* For those rccb command not supported, it is zero
*/
static uint8_t uwb_rccb_size_tbl [] = {
0, /* CHANNEL_CHANGE */
sizeof (uwb_rccb_dev_addr_mgmt_t), /* DEV_ADDR_MGMT */
sizeof (uwb_rccb_cmd_t), /* GET_IE */
sizeof (uwb_rccb_cmd_t), /* RESET */
sizeof (uwb_rccb_scan_t), /* SCAN */
0, /* SET_BEACON_FILTER */
0, /* SET_DRP_IE */
0, /* SET_IE */
0, /* SET_NOTIFICATION_FILTER */
0, /* SET_TX_POWER */
0, /* SLEEP */
sizeof (uwb_rccb_start_beacon_t), /* START_BEACON */
sizeof (uwb_rccb_cmd_t), /* STOP_BEACON */
0, /* BP_MERGE */
0 /* SEND_COMMAND_FRAME */
};
/*
* Called by radio controller driver's attach() to register the device to uwba.
* Including alloc and init the uwb_dev_handle
*/
void
{
}
/*
* Called by radio controller driver's dettach() to unregister the device from
* uwba. Including dealloc and fnit the uwb_dev_handle
*/
void
{
}
/*
* Called by the radio controler to the dip from a uwb_dev_handle
*/
{
if (uwb_dev_hdl) {
}
return (NULL);
}
/*
* Called by host controller or radio controller, this function set the
* ddi_no_autodetach to for the hwarc dip. Radio controller interface
* should alway be detached after the host controller detachment.
* So it should be called while the hwahc is attaching
* dip- a hwahc dip or a hwarc dip
*/
int
{
int rval = UWB_FAILURE;
if (uwb_dev_hdl != NULL) {
DDI_NO_AUTODETACH, 1);
return (UWB_SUCCESS);
}
/* Force the dip online */
NDI_SUCCESS) {
"fail to online dip = %p, node_name = %s",
}
/*
* Update the dip properties if it is a radio
* controller node
*/
0) {
(void) ddi_prop_update_int(DDI_DEV_T_NONE,
rval = UWB_SUCCESS;
break;
}
}
}
return (rval);
}
/*
* Called by hwahc when detaching.
* The hwarc should be detached after the hwahc. So it should only be
* called when hwahc is detaching.
*/
int
{
if (uwb_dev_hdl == NULL) {
"uwb_dev_offline::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
" uwb_dev_offline dip = 0x%p", dip);
DDI_NO_AUTODETACH, 0);
return (UWB_SUCCESS);
}
/*
* Called by hwarc when disconnect or suspend.
* Stop beacon. In addition, uwb will save the current channel
* and dev state.
*/
int
{
if (uwb_dev_hdl == NULL) {
"uwb_dev_offline::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
" uwb_dev_disconnect dip = 0x%p, channel=%d, state=%d",
if (state == UWB_STATE_BEACON) {
}
return (UWB_SUCCESS);
}
/*
* Called by hwarc when reconnect or resume.
* Start beacon and set the dev address whchi is saved
* in disconnect or suspend.
*/
int
{
if (uwb_dev_hdl == NULL) {
"uwb_dev_offline::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
" uwb_dev_reconnect dip = 0x%p, channel= %d, state = %d",
if (state == UWB_STATE_BEACON) {
}
return (UWB_SUCCESS);
}
/*
* This is a common interface for other models to send a
* rccb command to the radio controller
*/
int
{
int rval = UWB_SUCCESS;
if (uwb_dev_hdl == NULL) {
"uwb_process_rccb_cmd::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
/* check if it is a valid rccb command */
return (UWB_FAILURE);
}
return (rval);
}
/*
* Find a free chanel by scaning the supported channels
*/
{
if (!uwb_dev_hdl) {
"uwb_send_rccb_cmd: uwba dev not found");
goto done;
}
"uwb_allocate_channel: enter");
done:
return (channel);
}
/* scan a channel and wait for a while to get beacon info */
int
{
rccb_cmd.wStartTime = 0;
"uwb_scan_channel: channel = %d", channel);
/* Scan a specific channel */
"uwb_scan_channel: process cmd failed");
return (UWB_FAILURE);
}
/* wait for beacon info */
/* stop scan in the channel */
"uwb_scan_channel: process cmd failed, channel = %d",
channel);
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/* Stop beacon common interface */
int
{
if (uwb_dev_hdl == NULL) {
"uwb_stop_beacon::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
"uwb_stop_beacon: enter");
"uwb_stop_beacon: process cmd failed");
return (UWB_FAILURE);
}
if (ret.bResultCode != 0) {
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/*
* Start beacon common interface
* start beaconing on specified channel
*/
int
{
if (uwb_dev_hdl == NULL) {
"uwb_start_beacon::no dev for dip:0x%p, channel = %d",
return (UWB_FAILURE);
}
"uwb_start_beacon: channel = %d", channel);
/* todo: this needs to be fixed later */
rccb_cmd.wBPSTOffset = 0;
"uwb_start_beacon: process cmd failed"
"channel = %d", channel);
return (UWB_FAILURE);
}
if (ret.bResultCode != 0) {
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/* Get the mac address of the radion controller */
int
{
if (uwb_dev_hdl == NULL) {
"uwb_get_mac_addr::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
"uwb_get_mac_addr: enter");
"uwb_get_mac_addr: process cmd failed");
return (UWB_FAILURE);
}
if (ret.bResultCode != 0) {
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/* Get the device address of the radion controller */
int
{
if (uwb_dev_hdl == NULL) {
"uwb_get_dev_addr::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
"uwb_get_dev_addr: enter");
"uwb_get_dev_addr: process cmd failed");
return (UWB_FAILURE);
}
if (ret.bResultCode != 0) {
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/* Set the device address of the radion controller */
int
{
if (uwb_dev_hdl == NULL) {
"uwb_set_dev_addr::no dev for dip:0x%p, dev_addr=%d",
return (UWB_FAILURE);
}
"uwb_set_dev_addr: dev_addr = %d", dev_addr);
"uwb_set_dev_addr: process cmd failed"
"dev_addr=%d", dev_addr);
return (UWB_FAILURE);
}
if (ret.bResultCode != 0) {
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/*
* Reset the radio controller.
* This is called when the radio controller is attached.
* Notice:Radio controller should not be reset when it
* is beaconing or scaning.
*/
int
{
if (uwb_dev_hdl == NULL) {
"uwb_reset_dev:no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
"uwb_reset_dev: enter");
"uwb_reset_dev: process cmd failed");
return (UWB_FAILURE);
}
if (ret.bResultCode != 0) {
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/*
* Called while attaching.
* The physical capabilities is initialized.
* Only the supported channels is used in current version
*/
int
{
if (uwb_dev_hdl == NULL) {
"uwb_init_phy::no dev for dip:0x%p", dip);
return (UWB_FAILURE);
}
"uwb_init_phy: enter");
"uwb_init_phy: process cmd failed");
return (UWB_FAILURE);
}
/* todo: rceb result is handled in event notification */
return (UWB_SUCCESS);
}
/* Get a notif from the list head. That notif is dis-linked from the list. */
static uwb_notif_wrapper_t *
{
/*
* unlink a notification wrapper's structure from the
* list
*/
}
}
return (nw);
}
/*
* UWB ioctls
* UWB_COMMAND --- Send a rccb command to the radio controller
* UWB_GET_NOTIFICATION -- Get the uwb notifications. Not used
*/
int
{
int rv = 0;
switch (cmd) {
case UWB_COMMAND: /* Issue commands to UWB Radio Controller */
{
"uwb_do_ioctl: ddi_copyin fail");
break;
}
break;
}
!= UWB_SUCCESS) {
"uwb_do_ioctl: uwb_do_ioctl_rccb_cmd failed");
}
break;
}
case UWB_GET_NOTIFICATION:
{
/* Copy the notification to userland application */
}
/* release the notif and the wrapper. */
} else {
}
break;
}
default:
"uwb_do_ioctl: not a valid cmd value, cmd=%x", cmd);
}
"uwb_do_ioctl: exit, rv=%d", rv);
return (rv);
}
/*
* Parse all the standard events, including command results and notifications.
* If a unknown event, return UWB_NOT_SUPPORTED. The specific client radio
* controllers might has the knowledge to parse the vendor specific
*/
int
{
void *evt_struct;
int spec_data_len, offset;
int rval = UWB_SUCCESS;
"uwb_parse_evt_notif: invalid evt_code");
return (UWB_INVALID_EVT_CODE);
}
"uwb_parse_evt_notif: invalid evt_size. evt_code=%d",
evt_code);
return (UWB_INVALID_EVT_SIZE);
}
if (evt_struct == NULL) {
return (UWB_NO_RESOURCES);
}
/* parse rceb and get the data offset just after the rceb struct. */
== UWB_PARSE_ERROR) {
"uwb_parse_evt_notif: uwba_parse_rceb failed");
return (UWB_PARSE_ERROR);
}
if (rceb->bEventContext > 0 &&
"uwb_parse_evt_notif: cmd result's ctxt_id is "
"not matching cmd's ctxt_id,"
" result ctxt_id=%d, cmd ctxt_id=%d",
}
/* the data after rceb head are evt specific data */
switch (evt_code) {
case UWB_CE_CHANNEL_CHANGE:
case UWB_CE_RESET:
case UWB_CE_SCAN:
case UWB_CE_SET_BEACON_FILTER:
case UWB_CE_SET_TX_POWER:
case UWB_CE_SLEEP:
case UWB_CE_START_BEACON:
case UWB_CE_STOP_BEACON:
case UWB_CE_BP_MERGE:
/* All the above cmd results have only result code. */
"uwb_parse_evt_notif: msg = %s, bResultCode = %d ",
break;
case UWB_CE_DEV_ADDR_MGMT:
break;
case UWB_CE_GET_IE:
break;
break;
case UWB_NOTIF_BPOIE_CHANGE:
break;
case UWB_CE_SET_DRP_IE:
case UWB_CE_SET_IE:
case UWB_NOTIF_IE_RECEIVED:
case UWB_NOTIF_BP_SLOT_CHANGE:
case UWB_NOTIF_DRP:
case UWB_NOTIF_CMD_FRAME_RCV:
"uwb_parse_evt_notif: %s not supported",
break;
default: /* unkonwn events or notifications */
"uwb_parse_evt_notif: unkonwn events or notifications,"
" evt_code=%d", evt_code);
break;
}
if (rval != UWB_SUCCESS) {
"uwb_parse_evt_notif: fail, rval = %d", rval);
return (rval);
}
/*
* By now, parse complete. Go on notify the waiting cmd thread or add
* notification to list
*/
if (evt_code > UWB_NOTIF_RESERVED) {
/* If this event is a cmd result */
} else {
/* If this event is a notification */
}
return (rval);
}
/*
* Send command to device. This function is shared by those commands whose cmd
* data have rccb only.
*/
static int
{
/* reset cmd has no extra bytes, just rccb */
int rval = UWB_SUCCESS;
/* size of rccb. Reset cmd has no data other than rccb head */
"uwb_do_cmd_rccb: wLength=%d", data_len);
/* Data block */
"uwb_do_cmd_rccb: allocb failed");
return (UWB_FAILURE);
}
/* record the current cmd rccb to the uwb dev handle. */
/*
* data will be freed by radio client driver after the cmd is sent to
* device
*/
if (rval != UWB_SUCCESS) {
"uwb_do_cmd_rccb: send cmd fail ");
return (rval);
}
return (rval);
}
/* Dev addr management rccb cmd handler */
static int
{
int i, rval = UWB_SUCCESS;
/* size of device address mgmt RCCB */
"uwb_do_cmd_dev_addr_mgmt: wLength=%d, type=%x",
/* Data block */
"uwb_do_cmd_dev_addr_mgmt: allocb failed");
return (UWB_NO_RESOURCES);
}
for (i = 0; i < 6; i++) {
}
/* record the current cmd rccb to the uwb dev handle. */
!= UWB_SUCCESS) {
"uwb_do_cmd_dev_addr_mgmt: fail ");
return (rval);
}
"uwb_do_cmd_dev_addr_mgmt: success.");
return (rval);
}
/* Scan rccb cmd handler */
static int
{
int rval = UWB_SUCCESS;
"uwb_do_cmd_scan: wLength=%d", data_len);
/* Data block */
"uwb_do_cmd_scan: allocb failed");
return (UWB_NO_RESOURCES);
}
/* record the current cmd rccb to the uwb dev handle. */
!= UWB_SUCCESS) {
"uwb_send_rccb_cmd: fail ");
return (rval);
}
"uwb_do_cmd_scan: success.");
return (rval);
}
/* Start beacon rccb handler */
static int
{
int rval = UWB_SUCCESS;
}
"uwb_do_cmd_start_beacon: channel= %d , BPSTOffset = %d",
/* Data block */
"uwb_do_cmd_start_beacon: allocb failed");
return (UWB_FAILURE);
}
/* record the current cmd rccb to the uwb dev handle. */
!= UWB_SUCCESS) {
"uwb_do_cmd_start_beacon: send_cmd failed, channel = %d,"
return (rval);
}
return (rval);
}
/* Send rccb cmd and get the rceb result */
static int
{
int rval = UWB_SUCCESS;
"uwb_process_rccb_cmd_private: illegal dev_state:%d",
return (UWB_FAILURE);
}
"uwb_process_rccb_cmd_private: fail to enter"
return (UWB_FAILURE);
}
"uwb_process_rccb_cmd_private: fail to send"
goto cleanup;
}
/* Copy the command result to application */
if (cmd_result) {
}
/* release the command result (event) block. */
return (rval);
}
/* Call rccb handler to send a rccb cmd */
static int
{
!= UWB_SUCCESS) {
"uwb_send_rccb_cmd: uwb_send_rccb_cmd failed");
goto failure;
}
"uwb_send_rccb_cmd: fail to get cmd result ");
goto failure;
}
return (UWB_SUCCESS);
return (UWB_FAILURE);
}
/* Check a rccb cmd */
static int
{
"uwb_check_rccb_cmd: invalid bCommandType = %d",
return (UWB_FAILURE);
}
"uwb_check_rccb_cmd: invalid wCommand = %d",
return (UWB_FAILURE);
}
"uwb_send_rccb_cmd: unsupportted wCommand = %d",
return (UWB_FAILURE);
}
return (UWB_SUCCESS);
}
/* Check the current dev state */
static int
case UWB_CE_SCAN:
== UWB_RC_SCAN_DISABLED) {
if (state == UWB_STATE_SCAN) {
return (UWB_SUCCESS);
}
} else {
if (state == UWB_STATE_IDLE) {
return (UWB_SUCCESS);
}
}
break;
case UWB_CE_START_BEACON:
case UWB_CE_RESET:
if (state == UWB_STATE_IDLE) {
return (UWB_SUCCESS);
}
break;
case UWB_CE_STOP_BEACON:
if (state == UWB_STATE_BEACON) {
return (UWB_SUCCESS);
}
break;
default:
return (UWB_SUCCESS);
}
return (UWB_FAILURE);
}
/* Set the uwb dev state */
static void
case UWB_CE_SCAN:
{
} else {
}
}
break;
case UWB_CE_START_BEACON:
{
}
break;
case UWB_CE_STOP_BEACON:
case UWB_CE_RESET:
break;
case UWB_CE_DEV_ADDR_MGMT:
{
{
}
}
break;
default:
break;
}
}
/* Handle rccb cmd for ioctl */
static int
{
int rv = UWB_FAILURE;
"uwb_do_ioctl_rccb_cmd: enter cmd fail");
return (UWB_FAILURE);
}
"uwb_do_ioctl_rccb_cmd: ddi_copyin fail");
goto cleanup;
}
"uwb_check_dev_state: illegal dev_state:%d",
goto cleanup;
}
"uwb_do_ioctl_rccb_cmd: fail to send wCommand = %d ",
goto cleanup;
}
/* Copy the command result to application */
"uwb_do_ioctl_rccb_cmd: ddi_copyout fail");
} else {
rv = UWB_SUCCESS;
}
/* release the command result (event) block. */
return (rv);
}
/*
* alloc evt block according to cmd code; alloc context id;
* link the evt block to uwb_dev_hdl
*/
static int
{
int rval = UWB_SUCCESS;
/* no cmd result is received and cv is signaled */
rval = UWB_FAILURE;
return (rval);
}
"uwb_wait_cmd_result: wait for cmd complete end, "
"cv_signal received.");
}
return (rval);
}
static void
{
}
/* Get notif for ioctl */
static uwb_notif_wrapper_t *
{
return (NULL);
}
return (NULL);
}
return (notif);
}
/* Free a notif from notificatin list */
static void
{
}
/* uwb rccb cmd handler lock */
static int
{
return (UWB_FAILURE);
}
}
return (UWB_SUCCESS);
}
/* uwb rccb cmd handler unlock */
static void
{
}