xref: /onnv-gate/usr/src/uts/common/io/uwb/uwba/uwba.c (revision 9430:637732b28916)
1*9430SRaymond.Chen@Sun.COM /*
2*9430SRaymond.Chen@Sun.COM  * CDDL HEADER START
3*9430SRaymond.Chen@Sun.COM  *
4*9430SRaymond.Chen@Sun.COM  * The contents of this file are subject to the terms of the
5*9430SRaymond.Chen@Sun.COM  * Common Development and Distribution License (the "License").
6*9430SRaymond.Chen@Sun.COM  * You may not use this file except in compliance with the License.
7*9430SRaymond.Chen@Sun.COM  *
8*9430SRaymond.Chen@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9430SRaymond.Chen@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*9430SRaymond.Chen@Sun.COM  * See the License for the specific language governing permissions
11*9430SRaymond.Chen@Sun.COM  * and limitations under the License.
12*9430SRaymond.Chen@Sun.COM  *
13*9430SRaymond.Chen@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*9430SRaymond.Chen@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9430SRaymond.Chen@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*9430SRaymond.Chen@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*9430SRaymond.Chen@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9430SRaymond.Chen@Sun.COM  *
19*9430SRaymond.Chen@Sun.COM  * CDDL HEADER END
20*9430SRaymond.Chen@Sun.COM  */
21*9430SRaymond.Chen@Sun.COM /*
22*9430SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*9430SRaymond.Chen@Sun.COM  * Use is subject to license terms.
24*9430SRaymond.Chen@Sun.COM  */
25*9430SRaymond.Chen@Sun.COM 
26*9430SRaymond.Chen@Sun.COM /*
27*9430SRaymond.Chen@Sun.COM  * This file is for uwba private functions
28*9430SRaymond.Chen@Sun.COM  */
29*9430SRaymond.Chen@Sun.COM 
30*9430SRaymond.Chen@Sun.COM #include <sys/uwb/uwba/uwba.h>
31*9430SRaymond.Chen@Sun.COM 
32*9430SRaymond.Chen@Sun.COM uint_t uwba_errlevel = UWBA_LOG_CONSOLE;
33*9430SRaymond.Chen@Sun.COM 
34*9430SRaymond.Chen@Sun.COM static kmutex_t	uwba_mutex;
35*9430SRaymond.Chen@Sun.COM 
36*9430SRaymond.Chen@Sun.COM /* list for uwba_dev, the radio host devices */
37*9430SRaymond.Chen@Sun.COM static list_t	uwba_dev_list;
38*9430SRaymond.Chen@Sun.COM 
39*9430SRaymond.Chen@Sun.COM /* modload support */
40*9430SRaymond.Chen@Sun.COM extern struct mod_ops mod_miscops;
41*9430SRaymond.Chen@Sun.COM 
42*9430SRaymond.Chen@Sun.COM static struct modlmisc modlmisc	= {
43*9430SRaymond.Chen@Sun.COM 	&mod_miscops,	/* Type	of module */
44*9430SRaymond.Chen@Sun.COM 	"UWBA: UWB Architecture"
45*9430SRaymond.Chen@Sun.COM };
46*9430SRaymond.Chen@Sun.COM 
47*9430SRaymond.Chen@Sun.COM static struct modlinkage modlinkage = {
48*9430SRaymond.Chen@Sun.COM 	MODREV_1, (void	*)&modlmisc, NULL
49*9430SRaymond.Chen@Sun.COM };
50*9430SRaymond.Chen@Sun.COM 
51*9430SRaymond.Chen@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("unique per call", uwba_client_dev))
52*9430SRaymond.Chen@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("unique per call", uwb_notif_wrapper))
53*9430SRaymond.Chen@Sun.COM /* This table is for data decode */
54*9430SRaymond.Chen@Sun.COM uwba_evt_size_t uwba_evt_size_table[] = {
55*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_IE_RECEIVED] = {
56*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
57*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= 6
58*9430SRaymond.Chen@Sun.COM 	},
59*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BEACON_RECEIVED] = {
60*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_beacon_t),
61*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_BEACONINFOLEN_OFFSET
62*9430SRaymond.Chen@Sun.COM 	},
63*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BEACON_SIZE_CHANGE] = {
64*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_beacon_size_change_t),
65*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
66*9430SRaymond.Chen@Sun.COM 	},
67*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BPOIE_CHANGE] = {
68*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_bpoie_change_t),
69*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
70*9430SRaymond.Chen@Sun.COM 	},
71*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BP_SLOT_CHANGE] = {
72*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_bp_slot_change_t),
73*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
74*9430SRaymond.Chen@Sun.COM 	},
75*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BP_SWITCH_IE_RECEIVED] = {
76*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
77*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
78*9430SRaymond.Chen@Sun.COM 	},
79*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_DEV_ADDR_CONFLICT] = {
80*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
81*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
82*9430SRaymond.Chen@Sun.COM 	},
83*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_DRP_AVAILABILITY_CHANGE] = {
84*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_drp_availability_t),
85*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
86*9430SRaymond.Chen@Sun.COM 	},
87*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_DRP] = {
88*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_drp_t),
89*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= 8
90*9430SRaymond.Chen@Sun.COM 	},
91*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BP_SWITCH_STATUS] = {
92*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
93*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
94*9430SRaymond.Chen@Sun.COM 	},
95*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_CMD_FRAME_RCV] = {
96*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
97*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
98*9430SRaymond.Chen@Sun.COM 	},
99*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_CHANNEL_CHANGE_IE_RCV] = {
100*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
101*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
102*9430SRaymond.Chen@Sun.COM 	},
103*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED] = {
104*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
105*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
106*9430SRaymond.Chen@Sun.COM 	},
107*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED + 1] = {
108*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
109*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
110*9430SRaymond.Chen@Sun.COM 	},
111*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED + 2] = {
112*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
113*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
114*9430SRaymond.Chen@Sun.COM 	},
115*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED + 3] = {
116*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
117*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
118*9430SRaymond.Chen@Sun.COM 	},
119*9430SRaymond.Chen@Sun.COM 	[UWB_CE_CHANNEL_CHANGE] = {
120*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_head_t),
121*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
122*9430SRaymond.Chen@Sun.COM 	},
123*9430SRaymond.Chen@Sun.COM 	[UWB_CE_DEV_ADDR_MGMT] = {
124*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_dev_addr_mgmt_t),
125*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
126*9430SRaymond.Chen@Sun.COM 	},
127*9430SRaymond.Chen@Sun.COM 	[UWB_CE_GET_IE] = {
128*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_get_ie_t),
129*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= 4
130*9430SRaymond.Chen@Sun.COM 	},
131*9430SRaymond.Chen@Sun.COM 	[UWB_CE_RESET] = {
132*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
133*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
134*9430SRaymond.Chen@Sun.COM 	},
135*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SCAN] = {
136*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
137*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
138*9430SRaymond.Chen@Sun.COM 	},
139*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_BEACON_FILTER] = {
140*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
141*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
142*9430SRaymond.Chen@Sun.COM 	},
143*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_DRP_IE] = {
144*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_set_drp_ie_t),
145*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
146*9430SRaymond.Chen@Sun.COM 	},
147*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_IE] = {
148*9430SRaymond.Chen@Sun.COM 		.struct_len = sizeof (uwb_rceb_set_ie_t),
149*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
150*9430SRaymond.Chen@Sun.COM 	},
151*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_NOTIFICATION_FILTER] = {
152*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
153*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
154*9430SRaymond.Chen@Sun.COM 	},
155*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_TX_POWER] = {
156*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
157*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
158*9430SRaymond.Chen@Sun.COM 	},
159*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SLEEP] = {
160*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
161*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
162*9430SRaymond.Chen@Sun.COM 	},
163*9430SRaymond.Chen@Sun.COM 	[UWB_CE_START_BEACON] = {
164*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
165*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
166*9430SRaymond.Chen@Sun.COM 	},
167*9430SRaymond.Chen@Sun.COM 	[UWB_CE_STOP_BEACON] = {
168*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
169*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
170*9430SRaymond.Chen@Sun.COM 	},
171*9430SRaymond.Chen@Sun.COM 	[UWB_CE_BP_MERGE] = {
172*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
173*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
174*9430SRaymond.Chen@Sun.COM 	},
175*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SEND_COMMAND_FRAME] = {
176*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
177*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
178*9430SRaymond.Chen@Sun.COM 	},
179*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_ASIE_NOTIFICATION] = {
180*9430SRaymond.Chen@Sun.COM 		.struct_len = UWB_RESULT_CODE_SIZE,
181*9430SRaymond.Chen@Sun.COM 		.buf_len_offset	= UWB_EVT_NO_BUF_LEN_OFFSET
182*9430SRaymond.Chen@Sun.COM 	},
183*9430SRaymond.Chen@Sun.COM };
184*9430SRaymond.Chen@Sun.COM /* This table is used for debug only */
185*9430SRaymond.Chen@Sun.COM const char *uwba_evt_msg_table[] = {
186*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_IE_RECEIVED] 	= "UWB_NOTIF_IE_RECEIVED",
187*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BEACON_RECEIVED] 	= "UWB_NOTIF_BEACON_RECEIVED",
188*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BEACON_SIZE_CHANGE] 	= "UWB_NOTIF_BEACON_SIZE_CHANGE",
189*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BPOIE_CHANGE] 	= "UWB_NOTIF_BPOIE_CHANGE",
190*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BP_SLOT_CHANGE] 	= "UWB_NOTIF_BP_SLOT_CHANGE",
191*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BP_SWITCH_IE_RECEIVED] = "UWB_NOTIF_BP_SWITCH_IE_RECEIVED",
192*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_DEV_ADDR_CONFLICT] 	= "UWB_NOTIF_DEV_ADDR_CONFLICT",
193*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_DRP_AVAILABILITY_CHANGE] =
194*9430SRaymond.Chen@Sun.COM 					"UWB_NOTIF_DRP_AVAILABILITY_CHANGE",
195*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_DRP] 		= "UWB_NOTIF_DRP",
196*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_BP_SWITCH_STATUS] 	= "UWB_NOTIF_BP_SWITCH_STATUS",
197*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_CMD_FRAME_RCV] 	= "UWB_NOTIF_CMD_FRAME_RCV",
198*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_CHANNEL_CHANGE_IE_RCV] = "UWB_NOTIF_CHANNEL_CHANGE_IE_RCV",
199*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED] 		= "UWB_NOTIF_RESERVED",
200*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED + 1] 	= "UWB_NOTIF_RESERVED + 1",
201*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED + 2] 	= "UWB_NOTIF_RESERVED + 2",
202*9430SRaymond.Chen@Sun.COM 	[UWB_NOTIF_RESERVED + 3] 	= "UWB_NOTIF_RESERVED + 2",
203*9430SRaymond.Chen@Sun.COM 	[UWB_CE_CHANNEL_CHANGE] 	= "UWB_CE_CHANNEL_CHANGE",
204*9430SRaymond.Chen@Sun.COM 	[UWB_CE_DEV_ADDR_MGMT] 		= "UWB_CE_DEV_ADDR_MGMT",
205*9430SRaymond.Chen@Sun.COM 	[UWB_CE_GET_IE] 		= "UWB_CE_GET_IE",
206*9430SRaymond.Chen@Sun.COM 	[UWB_CE_RESET] 			= "UWB_CE_RESET",
207*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SCAN] 			= "UWB_CE_SCAN",
208*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_BEACON_FILTER] 	= "UWB_CE_SET_BEACON_FILTER",
209*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_DRP_IE] 		= "UWB_CE_SET_DRP_IE",
210*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_IE] 		= "UWB_CE_SET_IE",
211*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_NOTIFICATION_FILTER] = "UWB_CE_SET_NOTIFICATION_FILTER",
212*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_TX_POWER] 		= "UWB_CE_SET_TX_POWER",
213*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SLEEP] 			= "UWB_CE_SLEEP",
214*9430SRaymond.Chen@Sun.COM 	[UWB_CE_START_BEACON] 		= "UWB_CE_START_BEACON",
215*9430SRaymond.Chen@Sun.COM 	[UWB_CE_STOP_BEACON] 		= "UWB_CE_STOP_BEACON",
216*9430SRaymond.Chen@Sun.COM 	[UWB_CE_BP_MERGE] 		= "UWB_CE_BP_MERGE",
217*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SEND_COMMAND_FRAME] 	= "UWB_CE_SEND_COMMAND_FRAME",
218*9430SRaymond.Chen@Sun.COM 	[UWB_CE_SET_ASIE_NOTIFICATION] 	= "UWB_CE_SET_ASIE_NOTIFICATION",
219*9430SRaymond.Chen@Sun.COM };
220*9430SRaymond.Chen@Sun.COM 
221*9430SRaymond.Chen@Sun.COM 
222*9430SRaymond.Chen@Sun.COM static void uwba_init_lists(void);
223*9430SRaymond.Chen@Sun.COM static void uwba_fini_lists(void);
224*9430SRaymond.Chen@Sun.COM static void uwba_remove_cdev_list(uwba_dev_t *);
225*9430SRaymond.Chen@Sun.COM 
226*9430SRaymond.Chen@Sun.COM static void uwba_list_phy_rates(uwb_dev_handle_t);
227*9430SRaymond.Chen@Sun.COM static void uwba_list_phy_bandgroups(uwb_dev_handle_t);
228*9430SRaymond.Chen@Sun.COM static void uwba_get_phy_cap(uwb_dev_handle_t, uint8_t *, uint16_t);
229*9430SRaymond.Chen@Sun.COM static void uwba_save_phy_cap_bm(uwb_dev_handle_t, uint8_t *);
230*9430SRaymond.Chen@Sun.COM int
_init(void)231*9430SRaymond.Chen@Sun.COM _init(void)
232*9430SRaymond.Chen@Sun.COM {
233*9430SRaymond.Chen@Sun.COM 	int rval;
234*9430SRaymond.Chen@Sun.COM 	/*
235*9430SRaymond.Chen@Sun.COM 	 * uwba providing uwb device list support needs to be init'ed first
236*9430SRaymond.Chen@Sun.COM 	 * and destroyed last
237*9430SRaymond.Chen@Sun.COM 	 */
238*9430SRaymond.Chen@Sun.COM 	uwba_init_lists();
239*9430SRaymond.Chen@Sun.COM 	mutex_init(&uwba_mutex, NULL, MUTEX_DRIVER, NULL);
240*9430SRaymond.Chen@Sun.COM 	if ((rval = mod_install(&modlinkage)) != 0) {
241*9430SRaymond.Chen@Sun.COM 		uwba_fini_lists();
242*9430SRaymond.Chen@Sun.COM 		mutex_destroy(&uwba_mutex);
243*9430SRaymond.Chen@Sun.COM 	}
244*9430SRaymond.Chen@Sun.COM 
245*9430SRaymond.Chen@Sun.COM 	return (rval);
246*9430SRaymond.Chen@Sun.COM }
247*9430SRaymond.Chen@Sun.COM 
248*9430SRaymond.Chen@Sun.COM int
_fini()249*9430SRaymond.Chen@Sun.COM _fini()
250*9430SRaymond.Chen@Sun.COM {
251*9430SRaymond.Chen@Sun.COM 	int rval;
252*9430SRaymond.Chen@Sun.COM 
253*9430SRaymond.Chen@Sun.COM 	if ((rval = mod_remove(&modlinkage)) == 0) {
254*9430SRaymond.Chen@Sun.COM 		mutex_destroy(&uwba_mutex);
255*9430SRaymond.Chen@Sun.COM 		uwba_fini_lists();
256*9430SRaymond.Chen@Sun.COM 	}
257*9430SRaymond.Chen@Sun.COM 
258*9430SRaymond.Chen@Sun.COM 	return (rval);
259*9430SRaymond.Chen@Sun.COM }
260*9430SRaymond.Chen@Sun.COM 
261*9430SRaymond.Chen@Sun.COM int
_info(struct modinfo * modinfop)262*9430SRaymond.Chen@Sun.COM _info(struct modinfo *modinfop)
263*9430SRaymond.Chen@Sun.COM {
264*9430SRaymond.Chen@Sun.COM 	return (mod_info(&modlinkage, modinfop));
265*9430SRaymond.Chen@Sun.COM }
266*9430SRaymond.Chen@Sun.COM 
267*9430SRaymond.Chen@Sun.COM /* Create the global uwb dev list */
268*9430SRaymond.Chen@Sun.COM static void
uwba_init_lists(void)269*9430SRaymond.Chen@Sun.COM uwba_init_lists(void)
270*9430SRaymond.Chen@Sun.COM {
271*9430SRaymond.Chen@Sun.COM 	list_create(&(uwba_dev_list), sizeof (uwba_dev_t),
272*9430SRaymond.Chen@Sun.COM 	    offsetof(uwba_dev_t, uwba_dev_node));
273*9430SRaymond.Chen@Sun.COM }
274*9430SRaymond.Chen@Sun.COM 
275*9430SRaymond.Chen@Sun.COM /* Destroy  the global uwb dev list */
276*9430SRaymond.Chen@Sun.COM static void
uwba_fini_lists(void)277*9430SRaymond.Chen@Sun.COM uwba_fini_lists(void)
278*9430SRaymond.Chen@Sun.COM {
279*9430SRaymond.Chen@Sun.COM 	uwba_dev_t	*dev;
280*9430SRaymond.Chen@Sun.COM 
281*9430SRaymond.Chen@Sun.COM 	/* Free all uwb dev node from dev_list */
282*9430SRaymond.Chen@Sun.COM 	while (!list_is_empty(&uwba_dev_list)) {
283*9430SRaymond.Chen@Sun.COM 		dev = list_head(&uwba_dev_list);
284*9430SRaymond.Chen@Sun.COM 		if (dev != NULL) {
285*9430SRaymond.Chen@Sun.COM 			list_remove(&uwba_dev_list, dev);
286*9430SRaymond.Chen@Sun.COM 			kmem_free(dev, sizeof (uwba_dev_t));
287*9430SRaymond.Chen@Sun.COM 		}
288*9430SRaymond.Chen@Sun.COM 	}
289*9430SRaymond.Chen@Sun.COM }
290*9430SRaymond.Chen@Sun.COM /* Search the uwb handle with a hwarc/hwahc dip */
291*9430SRaymond.Chen@Sun.COM uwb_dev_handle_t
uwba_dev_search(dev_info_t * dip)292*9430SRaymond.Chen@Sun.COM uwba_dev_search(dev_info_t *dip)
293*9430SRaymond.Chen@Sun.COM {
294*9430SRaymond.Chen@Sun.COM 	mutex_enter(&uwba_mutex);
295*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = list_head(&uwba_dev_list);
296*9430SRaymond.Chen@Sun.COM 
297*9430SRaymond.Chen@Sun.COM 	while (uwba_dev != NULL) {
298*9430SRaymond.Chen@Sun.COM 		if (ddi_get_parent(uwba_dev->dip)  == ddi_get_parent(dip)) {
299*9430SRaymond.Chen@Sun.COM 
300*9430SRaymond.Chen@Sun.COM 			goto done;
301*9430SRaymond.Chen@Sun.COM 		}
302*9430SRaymond.Chen@Sun.COM 		uwba_dev = list_next(&uwba_dev_list, uwba_dev);
303*9430SRaymond.Chen@Sun.COM 	}
304*9430SRaymond.Chen@Sun.COM done:
305*9430SRaymond.Chen@Sun.COM 	mutex_exit(&uwba_mutex);
306*9430SRaymond.Chen@Sun.COM 
307*9430SRaymond.Chen@Sun.COM 	return (uwb_dev_handle_t)(uwba_dev);
308*9430SRaymond.Chen@Sun.COM }
309*9430SRaymond.Chen@Sun.COM 
310*9430SRaymond.Chen@Sun.COM /* Add a uwb device (hwarc/whci) to the uwb dev list */
311*9430SRaymond.Chen@Sun.COM void
uwba_dev_add_to_list(uwba_dev_t * uwba_dev)312*9430SRaymond.Chen@Sun.COM uwba_dev_add_to_list(uwba_dev_t *uwba_dev)
313*9430SRaymond.Chen@Sun.COM {
314*9430SRaymond.Chen@Sun.COM 	mutex_enter(&uwba_mutex);
315*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
316*9430SRaymond.Chen@Sun.COM 	    "add uwba_dev = %x", uwba_dev);
317*9430SRaymond.Chen@Sun.COM 	list_insert_tail(&uwba_dev_list, uwba_dev);
318*9430SRaymond.Chen@Sun.COM 	mutex_exit(&uwba_mutex);
319*9430SRaymond.Chen@Sun.COM }
320*9430SRaymond.Chen@Sun.COM 
321*9430SRaymond.Chen@Sun.COM /* Remove a uwb device (hwarc/whci) from the uwb dev list */
322*9430SRaymond.Chen@Sun.COM void
uwba_dev_rm_from_list(uwba_dev_t * uwba_dev)323*9430SRaymond.Chen@Sun.COM uwba_dev_rm_from_list(uwba_dev_t *uwba_dev)
324*9430SRaymond.Chen@Sun.COM {
325*9430SRaymond.Chen@Sun.COM 	mutex_enter(&uwba_mutex);
326*9430SRaymond.Chen@Sun.COM 	if (list_is_empty(&uwba_dev_list)) {
327*9430SRaymond.Chen@Sun.COM 		mutex_exit(&uwba_mutex);
328*9430SRaymond.Chen@Sun.COM 
329*9430SRaymond.Chen@Sun.COM 		return;
330*9430SRaymond.Chen@Sun.COM 	}
331*9430SRaymond.Chen@Sun.COM 
332*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
333*9430SRaymond.Chen@Sun.COM 	    "remove uwba_dev = %x", uwba_dev);
334*9430SRaymond.Chen@Sun.COM 
335*9430SRaymond.Chen@Sun.COM 	list_remove(&uwba_dev_list, uwba_dev);
336*9430SRaymond.Chen@Sun.COM 	mutex_exit(&uwba_mutex);
337*9430SRaymond.Chen@Sun.COM }
338*9430SRaymond.Chen@Sun.COM 
339*9430SRaymond.Chen@Sun.COM /* Init context bitset for a radio device (hwarc/whci) */
340*9430SRaymond.Chen@Sun.COM void
uwba_init_ctxt_id(uwba_dev_t * uwba_dev)341*9430SRaymond.Chen@Sun.COM uwba_init_ctxt_id(uwba_dev_t *uwba_dev)
342*9430SRaymond.Chen@Sun.COM {
343*9430SRaymond.Chen@Sun.COM 	bitset_init(&uwba_dev->ctxt_bits); /* this bzero sizeof(bitset_t) */
344*9430SRaymond.Chen@Sun.COM 	bitset_resize(&uwba_dev->ctxt_bits, 256); /* alloc mem */
345*9430SRaymond.Chen@Sun.COM 	bitset_add(&uwba_dev->ctxt_bits, 0);
346*9430SRaymond.Chen@Sun.COM 	bitset_add(&uwba_dev->ctxt_bits, 255);
347*9430SRaymond.Chen@Sun.COM }
348*9430SRaymond.Chen@Sun.COM 
349*9430SRaymond.Chen@Sun.COM /* Free context bitset for a radio device (hwarc/whci) */
350*9430SRaymond.Chen@Sun.COM void
uwba_fini_ctxt_id(uwba_dev_t * uwba_dev)351*9430SRaymond.Chen@Sun.COM uwba_fini_ctxt_id(uwba_dev_t *uwba_dev)
352*9430SRaymond.Chen@Sun.COM {
353*9430SRaymond.Chen@Sun.COM 	/* bitset_fini will free the mem allocated by bitset_resize. */
354*9430SRaymond.Chen@Sun.COM 	bitset_fini(&uwba_dev->ctxt_bits);
355*9430SRaymond.Chen@Sun.COM }
356*9430SRaymond.Chen@Sun.COM 
357*9430SRaymond.Chen@Sun.COM /* Get a free context id from bitset */
358*9430SRaymond.Chen@Sun.COM uint8_t
uwba_get_ctxt_id(uwba_dev_t * uwba_dev)359*9430SRaymond.Chen@Sun.COM uwba_get_ctxt_id(uwba_dev_t *uwba_dev)
360*9430SRaymond.Chen@Sun.COM {
361*9430SRaymond.Chen@Sun.COM 	uint8_t	ctxt_id;
362*9430SRaymond.Chen@Sun.COM 
363*9430SRaymond.Chen@Sun.COM 	/* if reaches the top, turn around */
364*9430SRaymond.Chen@Sun.COM 	if (uwba_dev->ctxt_id >= UWB_CTXT_ID_TOP) {
365*9430SRaymond.Chen@Sun.COM 		uwba_dev->ctxt_id = UWB_CTXT_ID_BOTTOM -1;
366*9430SRaymond.Chen@Sun.COM 	}
367*9430SRaymond.Chen@Sun.COM 	ctxt_id = uwba_dev->ctxt_id;
368*9430SRaymond.Chen@Sun.COM 
369*9430SRaymond.Chen@Sun.COM 	/* Search ctxt_id+1  to UWB_CTXT_ID_UNVALID */
370*9430SRaymond.Chen@Sun.COM 	do {
371*9430SRaymond.Chen@Sun.COM 		ctxt_id++;
372*9430SRaymond.Chen@Sun.COM 
373*9430SRaymond.Chen@Sun.COM 		/* test bit and returen if it is not set */
374*9430SRaymond.Chen@Sun.COM 		if (!bitset_in_set(&uwba_dev->ctxt_bits, ctxt_id)) {
375*9430SRaymond.Chen@Sun.COM 			bitset_add(&uwba_dev->ctxt_bits, ctxt_id);
376*9430SRaymond.Chen@Sun.COM 			uwba_dev->ctxt_id = ctxt_id;
377*9430SRaymond.Chen@Sun.COM 
378*9430SRaymond.Chen@Sun.COM 			return (ctxt_id);
379*9430SRaymond.Chen@Sun.COM 		}
380*9430SRaymond.Chen@Sun.COM 
381*9430SRaymond.Chen@Sun.COM 	} while (ctxt_id < UWB_CTXT_ID_UNVALID);
382*9430SRaymond.Chen@Sun.COM 
383*9430SRaymond.Chen@Sun.COM 	/* Search 1  to ctxt_id */
384*9430SRaymond.Chen@Sun.COM 	if (uwba_dev->ctxt_id != 0) {
385*9430SRaymond.Chen@Sun.COM 		ctxt_id = UWB_CTXT_ID_BOTTOM;
386*9430SRaymond.Chen@Sun.COM 		do {
387*9430SRaymond.Chen@Sun.COM 			ctxt_id++;
388*9430SRaymond.Chen@Sun.COM 
389*9430SRaymond.Chen@Sun.COM 			/* test bit and returen if it is not set */
390*9430SRaymond.Chen@Sun.COM 			if (!bitset_in_set(&uwba_dev->ctxt_bits, ctxt_id)) {
391*9430SRaymond.Chen@Sun.COM 				bitset_add(&uwba_dev->ctxt_bits, ctxt_id);
392*9430SRaymond.Chen@Sun.COM 				uwba_dev->ctxt_id = ctxt_id;
393*9430SRaymond.Chen@Sun.COM 
394*9430SRaymond.Chen@Sun.COM 				return (ctxt_id);
395*9430SRaymond.Chen@Sun.COM 			}
396*9430SRaymond.Chen@Sun.COM 		} while (ctxt_id < uwba_dev->ctxt_id);
397*9430SRaymond.Chen@Sun.COM 	}
398*9430SRaymond.Chen@Sun.COM 
399*9430SRaymond.Chen@Sun.COM 	/* All ids are in use, just force to re-use one. */
400*9430SRaymond.Chen@Sun.COM 	uwba_dev->ctxt_id++;
401*9430SRaymond.Chen@Sun.COM 
402*9430SRaymond.Chen@Sun.COM 	return (uwba_dev->ctxt_id);
403*9430SRaymond.Chen@Sun.COM }
404*9430SRaymond.Chen@Sun.COM 
405*9430SRaymond.Chen@Sun.COM /* Reset the bit (offset at ctxt_id) to zero */
406*9430SRaymond.Chen@Sun.COM void
uwba_free_ctxt_id(uwba_dev_t * dev,uint8_t ctxt_id)407*9430SRaymond.Chen@Sun.COM uwba_free_ctxt_id(uwba_dev_t *dev, uint8_t	ctxt_id)
408*9430SRaymond.Chen@Sun.COM {
409*9430SRaymond.Chen@Sun.COM 	bitset_del(&dev->ctxt_bits, ctxt_id);
410*9430SRaymond.Chen@Sun.COM 
411*9430SRaymond.Chen@Sun.COM }
412*9430SRaymond.Chen@Sun.COM 
413*9430SRaymond.Chen@Sun.COM /* Fill the rccb to ctrl req's data block */
414*9430SRaymond.Chen@Sun.COM void
uwba_fill_rccb_head(uwba_dev_t * uwba_dev,uint16_t cmd,mblk_t * data)415*9430SRaymond.Chen@Sun.COM uwba_fill_rccb_head(uwba_dev_t *uwba_dev, uint16_t cmd, mblk_t *data)
416*9430SRaymond.Chen@Sun.COM {
417*9430SRaymond.Chen@Sun.COM 	data->b_rptr[0] = UWB_CE_TYPE_GENERAL;
418*9430SRaymond.Chen@Sun.COM 	UINT16_TO_LE(cmd, 1, data->b_rptr);
419*9430SRaymond.Chen@Sun.COM 	data->b_rptr[3] = uwba_get_ctxt_id(uwba_dev);
420*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
421*9430SRaymond.Chen@Sun.COM 	    "the new ctxt_id is %d", data->b_rptr[3]);
422*9430SRaymond.Chen@Sun.COM }
423*9430SRaymond.Chen@Sun.COM 
424*9430SRaymond.Chen@Sun.COM /*
425*9430SRaymond.Chen@Sun.COM  * Allocate uwb_dev_t for a radio controller device. Arg rcd_intr_pri is the
426*9430SRaymond.Chen@Sun.COM  * interrupt priority of the interrupt handler of the radio controller driver.
427*9430SRaymond.Chen@Sun.COM  * If there is no interrupt handler in the driver, then pass 0 to this arg.
428*9430SRaymond.Chen@Sun.COM  */
429*9430SRaymond.Chen@Sun.COM void
uwba_alloc_uwb_dev(dev_info_t * dip,uwba_dev_t ** uwba_dev,uint_t rcd_intr_pri)430*9430SRaymond.Chen@Sun.COM uwba_alloc_uwb_dev(dev_info_t *dip, uwba_dev_t **uwba_dev, uint_t rcd_intr_pri)
431*9430SRaymond.Chen@Sun.COM {
432*9430SRaymond.Chen@Sun.COM 	char	*devinst;
433*9430SRaymond.Chen@Sun.COM 	int	devinstlen;
434*9430SRaymond.Chen@Sun.COM 	int	instance = ddi_get_instance(dip);
435*9430SRaymond.Chen@Sun.COM 
436*9430SRaymond.Chen@Sun.COM 	*uwba_dev = (uwba_dev_t *)kmem_zalloc(sizeof (uwba_dev_t), KM_SLEEP);
437*9430SRaymond.Chen@Sun.COM 
438*9430SRaymond.Chen@Sun.COM 	/*
439*9430SRaymond.Chen@Sun.COM 	 * HWA radio controller will not call uwb_* functions in interrupt
440*9430SRaymond.Chen@Sun.COM 	 * level, while WHCI radio controller will.
441*9430SRaymond.Chen@Sun.COM 	 */
442*9430SRaymond.Chen@Sun.COM 	if (rcd_intr_pri == 0) {
443*9430SRaymond.Chen@Sun.COM 		mutex_init(&(*uwba_dev)->dev_mutex, NULL, MUTEX_DRIVER, NULL);
444*9430SRaymond.Chen@Sun.COM 	} else {
445*9430SRaymond.Chen@Sun.COM 		mutex_init(&(*uwba_dev)->dev_mutex, NULL, MUTEX_DRIVER,
446*9430SRaymond.Chen@Sun.COM 		    DDI_INTR_PRI(rcd_intr_pri));
447*9430SRaymond.Chen@Sun.COM 	}
448*9430SRaymond.Chen@Sun.COM 	mutex_enter(&(*uwba_dev)->dev_mutex);
449*9430SRaymond.Chen@Sun.COM 
450*9430SRaymond.Chen@Sun.COM 	(*uwba_dev)->dip = dip;
451*9430SRaymond.Chen@Sun.COM 	(*uwba_dev)->dev_state = UWB_STATE_IDLE;
452*9430SRaymond.Chen@Sun.COM 
453*9430SRaymond.Chen@Sun.COM 	/* create a string for driver name and instance number */
454*9430SRaymond.Chen@Sun.COM 	devinst = kmem_zalloc(UWB_MAXSTRINGLEN, KM_SLEEP);
455*9430SRaymond.Chen@Sun.COM 	devinstlen = snprintf(devinst, UWB_MAXSTRINGLEN, "%s%d: ",
456*9430SRaymond.Chen@Sun.COM 	    ddi_driver_name(dip), instance);
457*9430SRaymond.Chen@Sun.COM 	(*uwba_dev)->devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
458*9430SRaymond.Chen@Sun.COM 	(void) strncpy((*uwba_dev)->devinst, devinst, devinstlen);
459*9430SRaymond.Chen@Sun.COM 	kmem_free(devinst, UWB_MAXSTRINGLEN);
460*9430SRaymond.Chen@Sun.COM 
461*9430SRaymond.Chen@Sun.COM 	/* list to cache the notifications from radio controller device */
462*9430SRaymond.Chen@Sun.COM 	list_create(&(*uwba_dev)->notif_list, sizeof (uwb_notif_wrapper_t),
463*9430SRaymond.Chen@Sun.COM 	    offsetof(uwb_notif_wrapper_t, notif_node));
464*9430SRaymond.Chen@Sun.COM 	(*uwba_dev)->notif_cnt = 0;
465*9430SRaymond.Chen@Sun.COM 
466*9430SRaymond.Chen@Sun.COM 	/* list to record the client devices according to beacons received */
467*9430SRaymond.Chen@Sun.COM 	list_create(&(*uwba_dev)->client_dev_list, sizeof (uwba_client_dev_t),
468*9430SRaymond.Chen@Sun.COM 	    offsetof(uwba_client_dev_t, dev_node));
469*9430SRaymond.Chen@Sun.COM 	(*uwba_dev)->client_dev_cnt = 0;
470*9430SRaymond.Chen@Sun.COM 
471*9430SRaymond.Chen@Sun.COM 	cv_init(&(*uwba_dev)->cmd_result_cv, NULL, CV_DRIVER, NULL);
472*9430SRaymond.Chen@Sun.COM 	cv_init(&(*uwba_dev)->cmd_handler_cv, NULL, CV_DRIVER, NULL);
473*9430SRaymond.Chen@Sun.COM 
474*9430SRaymond.Chen@Sun.COM 	mutex_exit(&(*uwba_dev)->dev_mutex);
475*9430SRaymond.Chen@Sun.COM 
476*9430SRaymond.Chen@Sun.COM }
477*9430SRaymond.Chen@Sun.COM 
478*9430SRaymond.Chen@Sun.COM /* Free a uwb dev for a radio device (hwarc/whci) */
479*9430SRaymond.Chen@Sun.COM void
uwba_free_uwb_dev(uwba_dev_t * uwba_dev)480*9430SRaymond.Chen@Sun.COM uwba_free_uwb_dev(uwba_dev_t *uwba_dev)
481*9430SRaymond.Chen@Sun.COM {
482*9430SRaymond.Chen@Sun.COM 	uwb_notif_wrapper_t *nw;
483*9430SRaymond.Chen@Sun.COM 
484*9430SRaymond.Chen@Sun.COM 	mutex_enter(&(uwba_dev)->dev_mutex);
485*9430SRaymond.Chen@Sun.COM 	cv_destroy(&uwba_dev->cmd_result_cv);
486*9430SRaymond.Chen@Sun.COM 	cv_destroy(&uwba_dev->cmd_handler_cv);
487*9430SRaymond.Chen@Sun.COM 
488*9430SRaymond.Chen@Sun.COM 	/*
489*9430SRaymond.Chen@Sun.COM 	 * remove all the notifications in this device's list, and then destroy
490*9430SRaymond.Chen@Sun.COM 	 * the list
491*9430SRaymond.Chen@Sun.COM 	 */
492*9430SRaymond.Chen@Sun.COM 	while (!list_is_empty(&uwba_dev->notif_list)) {
493*9430SRaymond.Chen@Sun.COM 
494*9430SRaymond.Chen@Sun.COM 		nw = list_head(&uwba_dev->notif_list);
495*9430SRaymond.Chen@Sun.COM 		if (nw != NULL) {
496*9430SRaymond.Chen@Sun.COM 			list_remove(&(uwba_dev->notif_list), nw);
497*9430SRaymond.Chen@Sun.COM 		} else {
498*9430SRaymond.Chen@Sun.COM 			break;
499*9430SRaymond.Chen@Sun.COM 		}
500*9430SRaymond.Chen@Sun.COM 
501*9430SRaymond.Chen@Sun.COM 		/* Free notification struct */
502*9430SRaymond.Chen@Sun.COM 		if (nw->notif) {
503*9430SRaymond.Chen@Sun.COM 			kmem_free(nw->notif, nw->length);
504*9430SRaymond.Chen@Sun.COM 		}
505*9430SRaymond.Chen@Sun.COM 		kmem_free(nw, sizeof (uwb_notif_wrapper_t));
506*9430SRaymond.Chen@Sun.COM 	}
507*9430SRaymond.Chen@Sun.COM 	uwba_dev->notif_cnt = 0;
508*9430SRaymond.Chen@Sun.COM 	list_destroy(&uwba_dev->notif_list);
509*9430SRaymond.Chen@Sun.COM 
510*9430SRaymond.Chen@Sun.COM 	uwba_remove_cdev_list(uwba_dev);
511*9430SRaymond.Chen@Sun.COM 	if (uwba_dev->devinst != NULL) {
512*9430SRaymond.Chen@Sun.COM 		kmem_free(uwba_dev->devinst,
513*9430SRaymond.Chen@Sun.COM 		    strlen(uwba_dev->devinst) + 1);
514*9430SRaymond.Chen@Sun.COM 	}
515*9430SRaymond.Chen@Sun.COM 	mutex_exit(&(uwba_dev)->dev_mutex);
516*9430SRaymond.Chen@Sun.COM 
517*9430SRaymond.Chen@Sun.COM 	/* Destroy mutex and dev structure */
518*9430SRaymond.Chen@Sun.COM 	mutex_destroy(&uwba_dev->dev_mutex);
519*9430SRaymond.Chen@Sun.COM 	kmem_free(uwba_dev, sizeof (uwba_dev_t));
520*9430SRaymond.Chen@Sun.COM }
521*9430SRaymond.Chen@Sun.COM 
522*9430SRaymond.Chen@Sun.COM 
523*9430SRaymond.Chen@Sun.COM /* Get a event or notification code from the data stream */
524*9430SRaymond.Chen@Sun.COM uint16_t
uwba_get_evt_code(uint8_t * data,int data_len)525*9430SRaymond.Chen@Sun.COM uwba_get_evt_code(uint8_t *data, int data_len)
526*9430SRaymond.Chen@Sun.COM {
527*9430SRaymond.Chen@Sun.COM 	uint16_t	evt_code;
528*9430SRaymond.Chen@Sun.COM 
529*9430SRaymond.Chen@Sun.COM 	/*
530*9430SRaymond.Chen@Sun.COM 	 * UWB_RAW_RESULT_CODE_SIZE is the minimum size for any events or
531*9430SRaymond.Chen@Sun.COM 	 * notifications.
532*9430SRaymond.Chen@Sun.COM 	 */
533*9430SRaymond.Chen@Sun.COM 	if (data_len < UWB_RAW_RESULT_CODE_SIZE) {
534*9430SRaymond.Chen@Sun.COM 
535*9430SRaymond.Chen@Sun.COM 		uwba_log(NULL, UWBA_LOG_LOG,
536*9430SRaymond.Chen@Sun.COM 		    "uwba_get_evt_code: invalid data_len=%d",
537*9430SRaymond.Chen@Sun.COM 		    data_len);
538*9430SRaymond.Chen@Sun.COM 		return (UWB_INVALID_EVT_CODE);
539*9430SRaymond.Chen@Sun.COM 	}
540*9430SRaymond.Chen@Sun.COM 
541*9430SRaymond.Chen@Sun.COM 	LE_TO_UINT16(data, UWB_RAW_WEVENT_OFFSET, evt_code);
542*9430SRaymond.Chen@Sun.COM 
543*9430SRaymond.Chen@Sun.COM 	/* if out of range */
544*9430SRaymond.Chen@Sun.COM 	if (evt_code > UWB_CE_SET_ASIE_NOTIFICATION) {
545*9430SRaymond.Chen@Sun.COM 		uwba_log(NULL, UWBA_LOG_LOG,
546*9430SRaymond.Chen@Sun.COM 		    "uwba_get_evt_code: invalid evt_code=%d",
547*9430SRaymond.Chen@Sun.COM 		    evt_code);
548*9430SRaymond.Chen@Sun.COM 		return (UWB_INVALID_EVT_CODE);
549*9430SRaymond.Chen@Sun.COM 	}
550*9430SRaymond.Chen@Sun.COM 
551*9430SRaymond.Chen@Sun.COM 	/* if fall into the reserved range */
552*9430SRaymond.Chen@Sun.COM 	if (evt_code >= UWB_NOTIF_RESERVED &&
553*9430SRaymond.Chen@Sun.COM 	    evt_code < UWB_CE_CHANNEL_CHANGE) {
554*9430SRaymond.Chen@Sun.COM 		uwba_log(NULL, UWBA_LOG_LOG,
555*9430SRaymond.Chen@Sun.COM 		    "uwba_get_evt_code: reserved evt_code=%d", evt_code);
556*9430SRaymond.Chen@Sun.COM 
557*9430SRaymond.Chen@Sun.COM 		return (UWB_INVALID_EVT_CODE);
558*9430SRaymond.Chen@Sun.COM 	}
559*9430SRaymond.Chen@Sun.COM 
560*9430SRaymond.Chen@Sun.COM 	return (evt_code);
561*9430SRaymond.Chen@Sun.COM }
562*9430SRaymond.Chen@Sun.COM 
563*9430SRaymond.Chen@Sun.COM /* Get the size of notif/evt struct */
564*9430SRaymond.Chen@Sun.COM uint16_t
uwba_get_evt_size(uint8_t * data,int data_len,uint16_t evt_code)565*9430SRaymond.Chen@Sun.COM uwba_get_evt_size(uint8_t *data, int data_len, uint16_t evt_code)
566*9430SRaymond.Chen@Sun.COM {
567*9430SRaymond.Chen@Sun.COM 	uint16_t	buf_len_off, buf_len, evt_size;
568*9430SRaymond.Chen@Sun.COM 
569*9430SRaymond.Chen@Sun.COM 	evt_size = uwba_evt_size_table[evt_code].struct_len;
570*9430SRaymond.Chen@Sun.COM 	buf_len_off = uwba_evt_size_table[evt_code].buf_len_offset;
571*9430SRaymond.Chen@Sun.COM 
572*9430SRaymond.Chen@Sun.COM 	/* If the offset of the variable data length is out of range. */
573*9430SRaymond.Chen@Sun.COM 	if (buf_len_off >= data_len) {
574*9430SRaymond.Chen@Sun.COM 
575*9430SRaymond.Chen@Sun.COM 		return (UWB_INVALID_EVT_SIZE);
576*9430SRaymond.Chen@Sun.COM 	}
577*9430SRaymond.Chen@Sun.COM 
578*9430SRaymond.Chen@Sun.COM 	/* If this event has variable length data, add up the length. */
579*9430SRaymond.Chen@Sun.COM 	if (buf_len_off) {
580*9430SRaymond.Chen@Sun.COM 		LE_TO_UINT16(data, buf_len_off, buf_len);
581*9430SRaymond.Chen@Sun.COM 
582*9430SRaymond.Chen@Sun.COM 		/* in case buf_len is not a reasonable value. */
583*9430SRaymond.Chen@Sun.COM 		if ((buf_len_off + 2 + buf_len) > data_len) {
584*9430SRaymond.Chen@Sun.COM 			uwba_log(NULL, UWBA_LOG_DEBUG,
585*9430SRaymond.Chen@Sun.COM 			    "uwba_get_evt_size: data_len=%d, buf_len_off=%d,"
586*9430SRaymond.Chen@Sun.COM 			    " buf_len=%d", data_len, buf_len_off, buf_len);
587*9430SRaymond.Chen@Sun.COM 
588*9430SRaymond.Chen@Sun.COM 			return (UWB_INVALID_EVT_SIZE);
589*9430SRaymond.Chen@Sun.COM 		}
590*9430SRaymond.Chen@Sun.COM 
591*9430SRaymond.Chen@Sun.COM 		/*
592*9430SRaymond.Chen@Sun.COM 		 * after add up, the evt size may be a couple of bytes greater
593*9430SRaymond.Chen@Sun.COM 		 * (depends on the structure alignment) than we actually need,
594*9430SRaymond.Chen@Sun.COM 		 * but it does not matter.
595*9430SRaymond.Chen@Sun.COM 		 */
596*9430SRaymond.Chen@Sun.COM 		evt_size += buf_len;
597*9430SRaymond.Chen@Sun.COM 	}
598*9430SRaymond.Chen@Sun.COM 
599*9430SRaymond.Chen@Sun.COM 	/*
600*9430SRaymond.Chen@Sun.COM 	 * TODO: check if data_len is less than expected raw event data, for the
601*9430SRaymond.Chen@Sun.COM 	 * fixed length events/notifs.
602*9430SRaymond.Chen@Sun.COM 	 */
603*9430SRaymond.Chen@Sun.COM 
604*9430SRaymond.Chen@Sun.COM 	return (evt_size);
605*9430SRaymond.Chen@Sun.COM }
606*9430SRaymond.Chen@Sun.COM 
607*9430SRaymond.Chen@Sun.COM /*
608*9430SRaymond.Chen@Sun.COM  * hook the new event to uwb device handle, replace the old one if there is.
609*9430SRaymond.Chen@Sun.COM  * Signal the cmd thread which is waiting this cmd result.
610*9430SRaymond.Chen@Sun.COM  */
611*9430SRaymond.Chen@Sun.COM void
uwba_put_cmd_result(uwba_dev_t * uwba_dev,void * evt_struct,uint16_t evt_size)612*9430SRaymond.Chen@Sun.COM uwba_put_cmd_result(uwba_dev_t *uwba_dev, void *evt_struct,
613*9430SRaymond.Chen@Sun.COM 	uint16_t  evt_size)
614*9430SRaymond.Chen@Sun.COM {
615*9430SRaymond.Chen@Sun.COM 	uwb_cmd_result_t *cmd_rlt = (uwb_cmd_result_t *)evt_struct;
616*9430SRaymond.Chen@Sun.COM 
617*9430SRaymond.Chen@Sun.COM 	mutex_enter(&uwba_dev->dev_mutex);
618*9430SRaymond.Chen@Sun.COM 	if (uwba_dev->cmd_result_wrap.cmd_result) {
619*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
620*9430SRaymond.Chen@Sun.COM 		    "previous command result not processed "
621*9430SRaymond.Chen@Sun.COM 		    "bEventType = %d, wEvent = %d, ctxt_id = %d",
622*9430SRaymond.Chen@Sun.COM 		    uwba_dev->cmd_result_wrap.cmd_result->rceb.bEventType,
623*9430SRaymond.Chen@Sun.COM 		    uwba_dev->cmd_result_wrap.cmd_result->rceb.wEvent,
624*9430SRaymond.Chen@Sun.COM 		    uwba_dev->cmd_result_wrap.cmd_result->rceb.bEventContext);
625*9430SRaymond.Chen@Sun.COM 
626*9430SRaymond.Chen@Sun.COM 		kmem_free(uwba_dev->cmd_result_wrap.cmd_result,
627*9430SRaymond.Chen@Sun.COM 		    uwba_dev->cmd_result_wrap.length);
628*9430SRaymond.Chen@Sun.COM 	}
629*9430SRaymond.Chen@Sun.COM 
630*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
631*9430SRaymond.Chen@Sun.COM 	    "uwba_put_cmd_result: wEvent= %d, msg= %s",
632*9430SRaymond.Chen@Sun.COM 	    cmd_rlt->rceb.wEvent, uwba_event_msg(cmd_rlt->rceb.wEvent));
633*9430SRaymond.Chen@Sun.COM 	uwba_dev->cmd_result_wrap.length = evt_size;
634*9430SRaymond.Chen@Sun.COM 	uwba_dev->cmd_result_wrap.cmd_result = cmd_rlt;
635*9430SRaymond.Chen@Sun.COM 	if (cmd_rlt->rceb.bEventContext == uwba_dev->ctxt_id) {
636*9430SRaymond.Chen@Sun.COM 		cv_signal(&uwba_dev->cmd_result_cv);
637*9430SRaymond.Chen@Sun.COM 	} else {
638*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
639*9430SRaymond.Chen@Sun.COM 		    "the cmd result ctxt_id %d is not matching the"
640*9430SRaymond.Chen@Sun.COM 		    "current cmd ctxt_id %d",
641*9430SRaymond.Chen@Sun.COM 		    cmd_rlt->rceb.bEventContext, uwba_dev->ctxt_id);
642*9430SRaymond.Chen@Sun.COM 	}
643*9430SRaymond.Chen@Sun.COM 	mutex_exit(&uwba_dev->dev_mutex);
644*9430SRaymond.Chen@Sun.COM }
645*9430SRaymond.Chen@Sun.COM 
646*9430SRaymond.Chen@Sun.COM /* add the notification to the tail of uwba_dev->notif_list */
647*9430SRaymond.Chen@Sun.COM int
uwba_add_notif_to_list(uwba_dev_t * uwba_dev,void * evt_struct,uint16_t evt_size)648*9430SRaymond.Chen@Sun.COM uwba_add_notif_to_list(uwba_dev_t *uwba_dev, void *evt_struct,
649*9430SRaymond.Chen@Sun.COM 	uint16_t  evt_size)
650*9430SRaymond.Chen@Sun.COM {
651*9430SRaymond.Chen@Sun.COM 	uwb_notif_wrapper_t *nw, *ow;
652*9430SRaymond.Chen@Sun.COM 
653*9430SRaymond.Chen@Sun.COM 	nw = (uwb_notif_wrapper_t *)kmem_alloc(sizeof (uwb_notif_wrapper_t),
654*9430SRaymond.Chen@Sun.COM 	    KM_NOSLEEP);
655*9430SRaymond.Chen@Sun.COM 	if (nw == NULL) {
656*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
657*9430SRaymond.Chen@Sun.COM 		    "uwba_add_notif_to_list: allocate notif wrapper failed");
658*9430SRaymond.Chen@Sun.COM 
659*9430SRaymond.Chen@Sun.COM 		return (UWB_NO_RESOURCES);
660*9430SRaymond.Chen@Sun.COM 	}
661*9430SRaymond.Chen@Sun.COM 	nw->length = evt_size;
662*9430SRaymond.Chen@Sun.COM 	nw->notif = (uwb_rceb_notif_t *)evt_struct;
663*9430SRaymond.Chen@Sun.COM 
664*9430SRaymond.Chen@Sun.COM 	mutex_enter(&uwba_dev->dev_mutex);
665*9430SRaymond.Chen@Sun.COM 
666*9430SRaymond.Chen@Sun.COM 	list_insert_tail(&uwba_dev->notif_list, nw);
667*9430SRaymond.Chen@Sun.COM 	uwba_dev->notif_cnt++;
668*9430SRaymond.Chen@Sun.COM 
669*9430SRaymond.Chen@Sun.COM 	if (uwba_dev->notif_cnt >= UWB_MAX_NOTIF_NUMBER) {
670*9430SRaymond.Chen@Sun.COM 		/* remove oldest one */
671*9430SRaymond.Chen@Sun.COM 		ow = list_head(&uwba_dev->notif_list);
672*9430SRaymond.Chen@Sun.COM 		list_remove(&uwba_dev->notif_list, ow);
673*9430SRaymond.Chen@Sun.COM 		uwba_dev->notif_cnt--;
674*9430SRaymond.Chen@Sun.COM 
675*9430SRaymond.Chen@Sun.COM 		/* Free it */
676*9430SRaymond.Chen@Sun.COM 		if (ow->notif) {
677*9430SRaymond.Chen@Sun.COM 			kmem_free(ow->notif, ow->length);
678*9430SRaymond.Chen@Sun.COM 		}
679*9430SRaymond.Chen@Sun.COM 		kmem_free(ow, sizeof (uwb_notif_wrapper_t));
680*9430SRaymond.Chen@Sun.COM 	}
681*9430SRaymond.Chen@Sun.COM 
682*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
683*9430SRaymond.Chen@Sun.COM 	    "uwba_add_notif_to_list: notification code=%d, notif_cnt=%d",
684*9430SRaymond.Chen@Sun.COM 	    nw->notif->rceb.wEvent, uwba_dev->notif_cnt);
685*9430SRaymond.Chen@Sun.COM 
686*9430SRaymond.Chen@Sun.COM 	mutex_exit(&uwba_dev->dev_mutex);
687*9430SRaymond.Chen@Sun.COM 
688*9430SRaymond.Chen@Sun.COM 	return (UWB_SUCCESS);
689*9430SRaymond.Chen@Sun.COM }
690*9430SRaymond.Chen@Sun.COM 
691*9430SRaymond.Chen@Sun.COM /*
692*9430SRaymond.Chen@Sun.COM  * find the specific client device in the client_dev_list by comparing the MAC
693*9430SRaymond.Chen@Sun.COM  * address
694*9430SRaymond.Chen@Sun.COM  */
695*9430SRaymond.Chen@Sun.COM uwba_client_dev_t *
uwba_find_cdev_by_mac(uwba_dev_t * uwba_dev,uwb_mac_addr_t * mac)696*9430SRaymond.Chen@Sun.COM uwba_find_cdev_by_mac(uwba_dev_t *uwba_dev, uwb_mac_addr_t *mac)
697*9430SRaymond.Chen@Sun.COM {
698*9430SRaymond.Chen@Sun.COM 	uwba_client_dev_t *cdev = NULL;
699*9430SRaymond.Chen@Sun.COM 
700*9430SRaymond.Chen@Sun.COM 	cdev = list_head(&uwba_dev->client_dev_list);
701*9430SRaymond.Chen@Sun.COM 	while (cdev != NULL) {
702*9430SRaymond.Chen@Sun.COM 		if (memcmp(mac, cdev->beacon_frame.Device_Identifier.addr,
703*9430SRaymond.Chen@Sun.COM 		    sizeof (uwb_mac_addr_t)) == 0) {
704*9430SRaymond.Chen@Sun.COM 
705*9430SRaymond.Chen@Sun.COM 			return (cdev);
706*9430SRaymond.Chen@Sun.COM 		}
707*9430SRaymond.Chen@Sun.COM 		cdev = list_next(&uwba_dev->client_dev_list, cdev);
708*9430SRaymond.Chen@Sun.COM 	}
709*9430SRaymond.Chen@Sun.COM 
710*9430SRaymond.Chen@Sun.COM 	return (cdev);
711*9430SRaymond.Chen@Sun.COM }
712*9430SRaymond.Chen@Sun.COM /* find the client device beconing in a specific channel */
713*9430SRaymond.Chen@Sun.COM uwba_client_dev_t *
uwba_find_cdev_by_channel(uwba_dev_t * uwba_dev,uint8_t channel)714*9430SRaymond.Chen@Sun.COM uwba_find_cdev_by_channel(uwba_dev_t *uwba_dev, uint8_t channel)
715*9430SRaymond.Chen@Sun.COM {
716*9430SRaymond.Chen@Sun.COM 	uwba_client_dev_t *cdev = NULL;
717*9430SRaymond.Chen@Sun.COM 
718*9430SRaymond.Chen@Sun.COM 	cdev = list_head(&uwba_dev->client_dev_list);
719*9430SRaymond.Chen@Sun.COM 	while (cdev != NULL) {
720*9430SRaymond.Chen@Sun.COM 		if (cdev->bChannelNumber == channel) {
721*9430SRaymond.Chen@Sun.COM 
722*9430SRaymond.Chen@Sun.COM 			return (cdev);
723*9430SRaymond.Chen@Sun.COM 		}
724*9430SRaymond.Chen@Sun.COM 		cdev = list_next(&uwba_dev->client_dev_list, cdev);
725*9430SRaymond.Chen@Sun.COM 	}
726*9430SRaymond.Chen@Sun.COM 
727*9430SRaymond.Chen@Sun.COM 	return (cdev);
728*9430SRaymond.Chen@Sun.COM }
729*9430SRaymond.Chen@Sun.COM 
730*9430SRaymond.Chen@Sun.COM /* remove all cdev list for uwb dev */
731*9430SRaymond.Chen@Sun.COM static void
uwba_remove_cdev_list(uwba_dev_t * uwba_dev)732*9430SRaymond.Chen@Sun.COM uwba_remove_cdev_list(uwba_dev_t *uwba_dev)
733*9430SRaymond.Chen@Sun.COM {
734*9430SRaymond.Chen@Sun.COM 	uwba_client_dev_t *cdev = NULL;
735*9430SRaymond.Chen@Sun.COM 
736*9430SRaymond.Chen@Sun.COM 	while (!list_is_empty(&uwba_dev->client_dev_list)) {
737*9430SRaymond.Chen@Sun.COM 
738*9430SRaymond.Chen@Sun.COM 		cdev = list_head(&uwba_dev->client_dev_list);
739*9430SRaymond.Chen@Sun.COM 		if (cdev != NULL) {
740*9430SRaymond.Chen@Sun.COM 
741*9430SRaymond.Chen@Sun.COM 			list_remove(&(uwba_dev->client_dev_list), cdev);
742*9430SRaymond.Chen@Sun.COM 		} else {
743*9430SRaymond.Chen@Sun.COM 
744*9430SRaymond.Chen@Sun.COM 			break;
745*9430SRaymond.Chen@Sun.COM 		}
746*9430SRaymond.Chen@Sun.COM 
747*9430SRaymond.Chen@Sun.COM 		kmem_free(cdev, sizeof (uwba_client_dev_t));
748*9430SRaymond.Chen@Sun.COM 	}
749*9430SRaymond.Chen@Sun.COM }
750*9430SRaymond.Chen@Sun.COM 
751*9430SRaymond.Chen@Sun.COM /* add a client radio device to the tail of uwba_dev->client_dev_list */
752*9430SRaymond.Chen@Sun.COM int
uwba_add_cdev_to_list(uwba_dev_t * uwba_dev,uwb_beacon_frame_t * bc_frm)753*9430SRaymond.Chen@Sun.COM uwba_add_cdev_to_list(uwba_dev_t *uwba_dev, uwb_beacon_frame_t *bc_frm)
754*9430SRaymond.Chen@Sun.COM {
755*9430SRaymond.Chen@Sun.COM 	uwb_mac_addr_t	*mac;
756*9430SRaymond.Chen@Sun.COM 	uwba_client_dev_t *cdev;
757*9430SRaymond.Chen@Sun.COM 	int rval = UWB_SUCCESS;
758*9430SRaymond.Chen@Sun.COM 
759*9430SRaymond.Chen@Sun.COM 	mutex_enter(&uwba_dev->dev_mutex);
760*9430SRaymond.Chen@Sun.COM 
761*9430SRaymond.Chen@Sun.COM 	if (uwba_dev->client_dev_cnt >= UWB_MAX_CDEV_NUMBER) {
762*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
763*9430SRaymond.Chen@Sun.COM 		    "uwba_add_cdev_to_list: can not add this dev,"
764*9430SRaymond.Chen@Sun.COM 		    "client dev number reached max,  client_dev_cnt=%d",
765*9430SRaymond.Chen@Sun.COM 		    uwba_dev->client_dev_cnt);
766*9430SRaymond.Chen@Sun.COM 		rval = UWB_FAILURE;
767*9430SRaymond.Chen@Sun.COM 		goto done;
768*9430SRaymond.Chen@Sun.COM 	}
769*9430SRaymond.Chen@Sun.COM 
770*9430SRaymond.Chen@Sun.COM 	mac = &bc_frm->Device_Identifier;
771*9430SRaymond.Chen@Sun.COM 	if (uwba_find_cdev_by_mac(uwba_dev, mac) != NULL) {
772*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_DEBUG,
773*9430SRaymond.Chen@Sun.COM 		    "uwba_add_cdev_to_list: this client dev is added before");
774*9430SRaymond.Chen@Sun.COM 
775*9430SRaymond.Chen@Sun.COM 		rval = UWB_SUCCESS;
776*9430SRaymond.Chen@Sun.COM 		goto done;
777*9430SRaymond.Chen@Sun.COM 	}
778*9430SRaymond.Chen@Sun.COM 	cdev = (uwba_client_dev_t *)kmem_alloc(sizeof (uwba_client_dev_t),
779*9430SRaymond.Chen@Sun.COM 	    KM_NOSLEEP);
780*9430SRaymond.Chen@Sun.COM 	if (cdev == NULL) {
781*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
782*9430SRaymond.Chen@Sun.COM 		    "uwba_add_client_device: allocate "
783*9430SRaymond.Chen@Sun.COM 		    "uwba_client_dev_t failed");
784*9430SRaymond.Chen@Sun.COM 
785*9430SRaymond.Chen@Sun.COM 		rval = UWB_NO_RESOURCES;
786*9430SRaymond.Chen@Sun.COM 		goto done;
787*9430SRaymond.Chen@Sun.COM 	}
788*9430SRaymond.Chen@Sun.COM 	(void) memcpy(&cdev->beacon_frame, bc_frm, sizeof (uwb_beacon_frame_t));
789*9430SRaymond.Chen@Sun.COM 
790*9430SRaymond.Chen@Sun.COM 	list_insert_tail(&uwba_dev->client_dev_list, cdev);
791*9430SRaymond.Chen@Sun.COM 	uwba_dev->client_dev_cnt++;
792*9430SRaymond.Chen@Sun.COM 
793*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
794*9430SRaymond.Chen@Sun.COM 	    "uwba_add_cdev_to_list: a new client dev added. MAC: "
795*9430SRaymond.Chen@Sun.COM 	    "%x %x %x %x %x %x, client_dev_cnt=%d",
796*9430SRaymond.Chen@Sun.COM 	    cdev->beacon_frame.Device_Identifier.addr[0],
797*9430SRaymond.Chen@Sun.COM 	    cdev->beacon_frame.Device_Identifier.addr[1],
798*9430SRaymond.Chen@Sun.COM 	    cdev->beacon_frame.Device_Identifier.addr[2],
799*9430SRaymond.Chen@Sun.COM 	    cdev->beacon_frame.Device_Identifier.addr[3],
800*9430SRaymond.Chen@Sun.COM 	    cdev->beacon_frame.Device_Identifier.addr[4],
801*9430SRaymond.Chen@Sun.COM 	    cdev->beacon_frame.Device_Identifier.addr[5],
802*9430SRaymond.Chen@Sun.COM 	    uwba_dev->client_dev_cnt);
803*9430SRaymond.Chen@Sun.COM done:
804*9430SRaymond.Chen@Sun.COM 
805*9430SRaymond.Chen@Sun.COM 	mutex_exit(&uwba_dev->dev_mutex);
806*9430SRaymond.Chen@Sun.COM 
807*9430SRaymond.Chen@Sun.COM 	return (rval);
808*9430SRaymond.Chen@Sun.COM }
809*9430SRaymond.Chen@Sun.COM 
810*9430SRaymond.Chen@Sun.COM /*
811*9430SRaymond.Chen@Sun.COM  * Return the actual parsed raw data length. Stop parse if datalen or structlen
812*9430SRaymond.Chen@Sun.COM  * is out of range, and then return UWB_PARSE_ERROR.
813*9430SRaymond.Chen@Sun.COM  */
814*9430SRaymond.Chen@Sun.COM int
uwba_parse_data(char * format,uchar_t * data,size_t datalen,void * structure,size_t structlen)815*9430SRaymond.Chen@Sun.COM uwba_parse_data(char	*format,
816*9430SRaymond.Chen@Sun.COM 	uchar_t 	*data,
817*9430SRaymond.Chen@Sun.COM 	size_t		datalen,
818*9430SRaymond.Chen@Sun.COM 	void		*structure,
819*9430SRaymond.Chen@Sun.COM 	size_t		structlen)
820*9430SRaymond.Chen@Sun.COM {
821*9430SRaymond.Chen@Sun.COM 	int	fmt;
822*9430SRaymond.Chen@Sun.COM 	int	counter = 1;
823*9430SRaymond.Chen@Sun.COM 	int	multiplier = 0;
824*9430SRaymond.Chen@Sun.COM 	uchar_t *datastart = data;
825*9430SRaymond.Chen@Sun.COM 	uchar_t	*dataend = data + datalen;
826*9430SRaymond.Chen@Sun.COM 	void	*structend = (void *)((intptr_t)structure + structlen);
827*9430SRaymond.Chen@Sun.COM 
828*9430SRaymond.Chen@Sun.COM 	if ((format == NULL) || (data == NULL) || (structure == NULL)) {
829*9430SRaymond.Chen@Sun.COM 
830*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
831*9430SRaymond.Chen@Sun.COM 	}
832*9430SRaymond.Chen@Sun.COM 
833*9430SRaymond.Chen@Sun.COM 	while ((fmt = *format) != '\0') {
834*9430SRaymond.Chen@Sun.COM 
835*9430SRaymond.Chen@Sun.COM 		/*
836*9430SRaymond.Chen@Sun.COM 		 * Could some one pass a "format" that is greater than
837*9430SRaymond.Chen@Sun.COM 		 * the structlen? Conversely, one could pass a ret_buf_len
838*9430SRaymond.Chen@Sun.COM 		 * that is less than the "format" length.
839*9430SRaymond.Chen@Sun.COM 		 * If so, we need to protect against writing over memory.
840*9430SRaymond.Chen@Sun.COM 		 */
841*9430SRaymond.Chen@Sun.COM 		if (counter++ > structlen) {
842*9430SRaymond.Chen@Sun.COM 			return (UWB_PARSE_ERROR);
843*9430SRaymond.Chen@Sun.COM 		}
844*9430SRaymond.Chen@Sun.COM 
845*9430SRaymond.Chen@Sun.COM 		if (fmt == 'c') {
846*9430SRaymond.Chen@Sun.COM 			uint8_t	*cp = (uint8_t *)structure;
847*9430SRaymond.Chen@Sun.COM 
848*9430SRaymond.Chen@Sun.COM 			cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
849*9430SRaymond.Chen@Sun.COM 			    ~(_CHAR_ALIGNMENT - 1));
850*9430SRaymond.Chen@Sun.COM 
851*9430SRaymond.Chen@Sun.COM 			/*
852*9430SRaymond.Chen@Sun.COM 			 * If data or structure is out of range, stop parse.
853*9430SRaymond.Chen@Sun.COM 			 */
854*9430SRaymond.Chen@Sun.COM 			if (((data + 1) > dataend) ||
855*9430SRaymond.Chen@Sun.COM 			    ((cp + 1) > (uint8_t *)structend))
856*9430SRaymond.Chen@Sun.COM 				return (UWB_PARSE_ERROR);
857*9430SRaymond.Chen@Sun.COM 
858*9430SRaymond.Chen@Sun.COM 			*cp++ = *data++;
859*9430SRaymond.Chen@Sun.COM 			structure = (void *)cp;
860*9430SRaymond.Chen@Sun.COM 			if (multiplier) {
861*9430SRaymond.Chen@Sun.COM 				multiplier--;
862*9430SRaymond.Chen@Sun.COM 			}
863*9430SRaymond.Chen@Sun.COM 			if (multiplier == 0) {
864*9430SRaymond.Chen@Sun.COM 				format++;
865*9430SRaymond.Chen@Sun.COM 			}
866*9430SRaymond.Chen@Sun.COM 		} else if (fmt == 's') {
867*9430SRaymond.Chen@Sun.COM 			uint16_t	*sp = (uint16_t *)structure;
868*9430SRaymond.Chen@Sun.COM 
869*9430SRaymond.Chen@Sun.COM 			sp = (uint16_t *)
870*9430SRaymond.Chen@Sun.COM 			    (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
871*9430SRaymond.Chen@Sun.COM 			    ~(_SHORT_ALIGNMENT - 1));
872*9430SRaymond.Chen@Sun.COM 			if (((data + 2) > dataend) ||
873*9430SRaymond.Chen@Sun.COM 			    ((sp + 1) > (uint16_t *)structend))
874*9430SRaymond.Chen@Sun.COM 				return (UWB_PARSE_ERROR);
875*9430SRaymond.Chen@Sun.COM 
876*9430SRaymond.Chen@Sun.COM 			*sp++ = (data[1] << 8) + data[0];
877*9430SRaymond.Chen@Sun.COM 			data += 2;
878*9430SRaymond.Chen@Sun.COM 			structure = (void *)sp;
879*9430SRaymond.Chen@Sun.COM 			if (multiplier) {
880*9430SRaymond.Chen@Sun.COM 				multiplier--;
881*9430SRaymond.Chen@Sun.COM 			}
882*9430SRaymond.Chen@Sun.COM 			if (multiplier == 0) {
883*9430SRaymond.Chen@Sun.COM 				format++;
884*9430SRaymond.Chen@Sun.COM 			}
885*9430SRaymond.Chen@Sun.COM 		} else if (isdigit(fmt)) {
886*9430SRaymond.Chen@Sun.COM 			multiplier = (multiplier * 10) + (fmt - '0');
887*9430SRaymond.Chen@Sun.COM 			format++;
888*9430SRaymond.Chen@Sun.COM 			counter--;
889*9430SRaymond.Chen@Sun.COM 		} else {
890*9430SRaymond.Chen@Sun.COM 			multiplier = 0;
891*9430SRaymond.Chen@Sun.COM 
892*9430SRaymond.Chen@Sun.COM 			return (UWB_PARSE_ERROR);
893*9430SRaymond.Chen@Sun.COM 		}
894*9430SRaymond.Chen@Sun.COM 	}
895*9430SRaymond.Chen@Sun.COM 
896*9430SRaymond.Chen@Sun.COM 	return ((intptr_t)data - (intptr_t)datastart);
897*9430SRaymond.Chen@Sun.COM }
898*9430SRaymond.Chen@Sun.COM 
899*9430SRaymond.Chen@Sun.COM 
900*9430SRaymond.Chen@Sun.COM /*
901*9430SRaymond.Chen@Sun.COM  * parse rceb, check if the context id is in the reasonable range (0x0 - 0xfe).
902*9430SRaymond.Chen@Sun.COM  * If success, return the offset just after the rceb struct.
903*9430SRaymond.Chen@Sun.COM  */
904*9430SRaymond.Chen@Sun.COM int
uwba_parse_rceb(uint8_t * data,size_t datalen,void * structure,size_t structlen)905*9430SRaymond.Chen@Sun.COM uwba_parse_rceb(uint8_t *data,
906*9430SRaymond.Chen@Sun.COM 	size_t		datalen,
907*9430SRaymond.Chen@Sun.COM 	void		*structure,
908*9430SRaymond.Chen@Sun.COM 	size_t		structlen)
909*9430SRaymond.Chen@Sun.COM {
910*9430SRaymond.Chen@Sun.COM 	int parsed_len;
911*9430SRaymond.Chen@Sun.COM 	uwb_rceb_head_t *rceb;
912*9430SRaymond.Chen@Sun.COM 
913*9430SRaymond.Chen@Sun.COM 	parsed_len = uwba_parse_data("csc", data, datalen,
914*9430SRaymond.Chen@Sun.COM 	    structure, structlen);
915*9430SRaymond.Chen@Sun.COM 	if (parsed_len  == UWB_PARSE_ERROR) {
916*9430SRaymond.Chen@Sun.COM 
917*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
918*9430SRaymond.Chen@Sun.COM 	}
919*9430SRaymond.Chen@Sun.COM 	rceb = (uwb_rceb_head_t *)structure;
920*9430SRaymond.Chen@Sun.COM 	if (rceb->bEventContext > UWB_CTXT_ID_TOP) {
921*9430SRaymond.Chen@Sun.COM 
922*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
923*9430SRaymond.Chen@Sun.COM 	}
924*9430SRaymond.Chen@Sun.COM 
925*9430SRaymond.Chen@Sun.COM 	return (parsed_len);
926*9430SRaymond.Chen@Sun.COM }
927*9430SRaymond.Chen@Sun.COM 
928*9430SRaymond.Chen@Sun.COM int
uwba_parse_dev_addr_mgmt(uint8_t * spec_data,int spec_data_len,uwb_rceb_dev_addr_mgmt_t * evt_struct)929*9430SRaymond.Chen@Sun.COM uwba_parse_dev_addr_mgmt(uint8_t *spec_data, int spec_data_len,
930*9430SRaymond.Chen@Sun.COM     uwb_rceb_dev_addr_mgmt_t *evt_struct)
931*9430SRaymond.Chen@Sun.COM {
932*9430SRaymond.Chen@Sun.COM 	/* 6 bytes for address, 1 for result code. */
933*9430SRaymond.Chen@Sun.COM 	if (uwba_parse_data("7c", spec_data,
934*9430SRaymond.Chen@Sun.COM 	    spec_data_len, evt_struct->baAddr, 7) == UWB_PARSE_ERROR) {
935*9430SRaymond.Chen@Sun.COM 
936*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
937*9430SRaymond.Chen@Sun.COM 	}
938*9430SRaymond.Chen@Sun.COM 
939*9430SRaymond.Chen@Sun.COM 	return (UWB_SUCCESS);
940*9430SRaymond.Chen@Sun.COM }
941*9430SRaymond.Chen@Sun.COM 
942*9430SRaymond.Chen@Sun.COM /* Parse UWB IEs that got by get_ie radio controller command */
943*9430SRaymond.Chen@Sun.COM int
uwba_parse_get_ie(uwb_dev_handle_t uwb_dev_hdl,uint8_t * spec_data,int spec_data_len,uwb_rceb_get_ie_t * evt_struct)944*9430SRaymond.Chen@Sun.COM uwba_parse_get_ie(uwb_dev_handle_t uwb_dev_hdl, uint8_t *spec_data,
945*9430SRaymond.Chen@Sun.COM 	int spec_data_len, uwb_rceb_get_ie_t *evt_struct)
946*9430SRaymond.Chen@Sun.COM {
947*9430SRaymond.Chen@Sun.COM 	int i;
948*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
949*9430SRaymond.Chen@Sun.COM 
950*9430SRaymond.Chen@Sun.COM 	/* At least, it should have wIELength. */
951*9430SRaymond.Chen@Sun.COM 	if (spec_data_len < 2) {
952*9430SRaymond.Chen@Sun.COM 
953*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
954*9430SRaymond.Chen@Sun.COM 	}
955*9430SRaymond.Chen@Sun.COM 	LE_TO_UINT16(spec_data, 0, evt_struct->wIELength);
956*9430SRaymond.Chen@Sun.COM 
957*9430SRaymond.Chen@Sun.COM 	/*
958*9430SRaymond.Chen@Sun.COM 	 * Except wIELength, it should have the number of bytes of indicated by
959*9430SRaymond.Chen@Sun.COM 	 * wIELength.
960*9430SRaymond.Chen@Sun.COM 	 */
961*9430SRaymond.Chen@Sun.COM 	if (spec_data_len < (evt_struct->wIELength + 2)) {
962*9430SRaymond.Chen@Sun.COM 
963*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
964*9430SRaymond.Chen@Sun.COM 	}
965*9430SRaymond.Chen@Sun.COM 
966*9430SRaymond.Chen@Sun.COM 	/*
967*9430SRaymond.Chen@Sun.COM 	 * Proper memory for evt_struct is already allocated for evt_struct in
968*9430SRaymond.Chen@Sun.COM 	 * uwb_parse_evt_notif()
969*9430SRaymond.Chen@Sun.COM 	 */
970*9430SRaymond.Chen@Sun.COM 	bcopy(spec_data + 2, evt_struct->IEData, evt_struct->wIELength);
971*9430SRaymond.Chen@Sun.COM 
972*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
973*9430SRaymond.Chen@Sun.COM 	    "uwba_parse_get_ie: wIELength=%d", evt_struct->wIELength);
974*9430SRaymond.Chen@Sun.COM 
975*9430SRaymond.Chen@Sun.COM 	for (i = 0; i < evt_struct->wIELength; i++) {
976*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_DEBUG,
977*9430SRaymond.Chen@Sun.COM 		    "0x%x ", evt_struct->IEData[i]);
978*9430SRaymond.Chen@Sun.COM 	}
979*9430SRaymond.Chen@Sun.COM 
980*9430SRaymond.Chen@Sun.COM 	/* Todo: continue to parse other IE Data? */
981*9430SRaymond.Chen@Sun.COM 	uwba_get_phy_cap(uwb_dev_hdl, evt_struct->IEData,
982*9430SRaymond.Chen@Sun.COM 	    evt_struct->wIELength);
983*9430SRaymond.Chen@Sun.COM 	uwba_list_phy_rates(uwb_dev_hdl);
984*9430SRaymond.Chen@Sun.COM 	uwba_list_phy_bandgroups(uwb_dev_hdl);
985*9430SRaymond.Chen@Sun.COM 
986*9430SRaymond.Chen@Sun.COM 	return (UWB_SUCCESS);
987*9430SRaymond.Chen@Sun.COM }
988*9430SRaymond.Chen@Sun.COM 
989*9430SRaymond.Chen@Sun.COM 
990*9430SRaymond.Chen@Sun.COM /*
991*9430SRaymond.Chen@Sun.COM  * Parse the beacon frame and add the client radio device to the dev_list in
992*9430SRaymond.Chen@Sun.COM  * uwb_dev_handle
993*9430SRaymond.Chen@Sun.COM  */
994*9430SRaymond.Chen@Sun.COM void
uwba_parse_beacon_info(uwba_dev_t * uwba_dev,uint8_t * bc_info)995*9430SRaymond.Chen@Sun.COM uwba_parse_beacon_info(uwba_dev_t *uwba_dev, uint8_t *bc_info)
996*9430SRaymond.Chen@Sun.COM {
997*9430SRaymond.Chen@Sun.COM 	uwb_beacon_frame_t *bc_frm;
998*9430SRaymond.Chen@Sun.COM 
999*9430SRaymond.Chen@Sun.COM 	bc_frm = (uwb_beacon_frame_t *)bc_info;
1000*9430SRaymond.Chen@Sun.COM 
1001*9430SRaymond.Chen@Sun.COM 	/*
1002*9430SRaymond.Chen@Sun.COM 	 * add the uwb device to list if it is a newly found device according to
1003*9430SRaymond.Chen@Sun.COM 	 * its MAC addr in the beacon
1004*9430SRaymond.Chen@Sun.COM 	 */
1005*9430SRaymond.Chen@Sun.COM 	if (uwba_add_cdev_to_list(uwba_dev, bc_frm) == UWB_SUCCESS) {
1006*9430SRaymond.Chen@Sun.COM 
1007*9430SRaymond.Chen@Sun.COM 		/* TODO: log messages */
1008*9430SRaymond.Chen@Sun.COM 
1009*9430SRaymond.Chen@Sun.COM 		return;
1010*9430SRaymond.Chen@Sun.COM 	}
1011*9430SRaymond.Chen@Sun.COM }
1012*9430SRaymond.Chen@Sun.COM 
1013*9430SRaymond.Chen@Sun.COM int
uwba_parse_bpoie_chg(uwb_dev_handle_t uwb_dev_hdl,uint8_t * spec_data,int spec_data_len,uwb_rceb_bpoie_change_t * evt_struct)1014*9430SRaymond.Chen@Sun.COM uwba_parse_bpoie_chg(uwb_dev_handle_t uwb_dev_hdl,
1015*9430SRaymond.Chen@Sun.COM 	uint8_t *spec_data, int spec_data_len,
1016*9430SRaymond.Chen@Sun.COM 	uwb_rceb_bpoie_change_t *evt_struct) {
1017*9430SRaymond.Chen@Sun.COM 	int parsed_len;
1018*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1019*9430SRaymond.Chen@Sun.COM 	parsed_len = uwba_parse_data("s", spec_data,
1020*9430SRaymond.Chen@Sun.COM 	    spec_data_len, &(evt_struct->wBPOIELength), 2);
1021*9430SRaymond.Chen@Sun.COM 
1022*9430SRaymond.Chen@Sun.COM 	if (parsed_len  == UWB_PARSE_ERROR) {
1023*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
1024*9430SRaymond.Chen@Sun.COM 		    "uwba_parse_bpoie_chg: parse error, parsed_len=%d",
1025*9430SRaymond.Chen@Sun.COM 		    parsed_len);
1026*9430SRaymond.Chen@Sun.COM 
1027*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
1028*9430SRaymond.Chen@Sun.COM 	}
1029*9430SRaymond.Chen@Sun.COM 	/* Todo: not supported now */
1030*9430SRaymond.Chen@Sun.COM 	return (UWB_SUCCESS);
1031*9430SRaymond.Chen@Sun.COM }
1032*9430SRaymond.Chen@Sun.COM /* Parse the beacon_receive notif */
1033*9430SRaymond.Chen@Sun.COM int
uwba_parse_beacon_rcv(uwb_dev_handle_t uwb_dev_hdl,uint8_t * spec_data,int spec_data_len,uwb_rceb_beacon_t * evt_struct)1034*9430SRaymond.Chen@Sun.COM uwba_parse_beacon_rcv(uwb_dev_handle_t uwb_dev_hdl,
1035*9430SRaymond.Chen@Sun.COM 	uint8_t *spec_data, int spec_data_len,
1036*9430SRaymond.Chen@Sun.COM 	uwb_rceb_beacon_t *evt_struct)
1037*9430SRaymond.Chen@Sun.COM {
1038*9430SRaymond.Chen@Sun.COM 	int parsed_len;
1039*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1040*9430SRaymond.Chen@Sun.COM 	uwb_beacon_frame_t *bc_frm = NULL;
1041*9430SRaymond.Chen@Sun.COM 	uwba_client_dev_t *client_dev = NULL;
1042*9430SRaymond.Chen@Sun.COM 
1043*9430SRaymond.Chen@Sun.COM 	/* parse the elements except BeaconInfo */
1044*9430SRaymond.Chen@Sun.COM 	parsed_len = uwba_parse_data("ccsccs", spec_data,
1045*9430SRaymond.Chen@Sun.COM 	    spec_data_len, &(evt_struct->bChannelNumber), 8);
1046*9430SRaymond.Chen@Sun.COM 	if (parsed_len  == UWB_PARSE_ERROR) {
1047*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
1048*9430SRaymond.Chen@Sun.COM 		    "uwba_parse_beacon_rcv: parse error, parsed_len=%d",
1049*9430SRaymond.Chen@Sun.COM 		    parsed_len);
1050*9430SRaymond.Chen@Sun.COM 
1051*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
1052*9430SRaymond.Chen@Sun.COM 	}
1053*9430SRaymond.Chen@Sun.COM 
1054*9430SRaymond.Chen@Sun.COM 	/*
1055*9430SRaymond.Chen@Sun.COM 	 * Except the elements before BeaconInfo, it should have the number of
1056*9430SRaymond.Chen@Sun.COM 	 * bytes of indicated by wBeaconInfoLength.
1057*9430SRaymond.Chen@Sun.COM 	 */
1058*9430SRaymond.Chen@Sun.COM 	if ((spec_data_len -UWB_BEACONINFO_OFFSET) <
1059*9430SRaymond.Chen@Sun.COM 	    evt_struct->wBeaconInfoLength) {
1060*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
1061*9430SRaymond.Chen@Sun.COM 		    "uwba_parse_beacon_rcv: parse error: spec_data_len=%d,"
1062*9430SRaymond.Chen@Sun.COM 		    "evt_struct->wBeaconInfoLength=%d, bc_info_offset=%d",
1063*9430SRaymond.Chen@Sun.COM 		    spec_data_len, evt_struct->wBeaconInfoLength,
1064*9430SRaymond.Chen@Sun.COM 		    UWB_BEACONINFO_OFFSET);
1065*9430SRaymond.Chen@Sun.COM 
1066*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
1067*9430SRaymond.Chen@Sun.COM 	}
1068*9430SRaymond.Chen@Sun.COM 	if (evt_struct->wBeaconInfoLength < sizeof (uwb_beacon_frame_t)) {
1069*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_LOG,
1070*9430SRaymond.Chen@Sun.COM 		    "uwba_parse_beacon_rcv: too small size, "
1071*9430SRaymond.Chen@Sun.COM 		    "wBeaconInfoLength=%d, data[0]=%d, data[1]=%d, data[4]=%d,"
1072*9430SRaymond.Chen@Sun.COM 		    " data[5]=%d, data[6]=%d, data[7]=%d, spec_data_len=%d",
1073*9430SRaymond.Chen@Sun.COM 		    evt_struct->wBeaconInfoLength, spec_data[0], spec_data[1],
1074*9430SRaymond.Chen@Sun.COM 		    spec_data[4], spec_data[5], spec_data[6], spec_data[7],
1075*9430SRaymond.Chen@Sun.COM 		    spec_data_len);
1076*9430SRaymond.Chen@Sun.COM 
1077*9430SRaymond.Chen@Sun.COM 		return (UWB_PARSE_ERROR);
1078*9430SRaymond.Chen@Sun.COM 	}
1079*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG, "uwba_parse_beacon_rcv:"
1080*9430SRaymond.Chen@Sun.COM 	    "bChannelNumber = %d bBeaconType = %d "
1081*9430SRaymond.Chen@Sun.COM 	    "wBPSTOffset = %d bLQI = %d bRSSI = %d "
1082*9430SRaymond.Chen@Sun.COM 	    "wBeaconInfoLength = %d",
1083*9430SRaymond.Chen@Sun.COM 	    evt_struct->bChannelNumber, evt_struct->bBeaconType,
1084*9430SRaymond.Chen@Sun.COM 	    evt_struct->wBPSTOffset, evt_struct->bLQI, evt_struct->bRSSI,
1085*9430SRaymond.Chen@Sun.COM 	    evt_struct->wBeaconInfoLength);
1086*9430SRaymond.Chen@Sun.COM 
1087*9430SRaymond.Chen@Sun.COM 	/*
1088*9430SRaymond.Chen@Sun.COM 	 * Proper memory for evt_struct is already allocated for evt_struct in
1089*9430SRaymond.Chen@Sun.COM 	 * uwb_parse_evt_notif()
1090*9430SRaymond.Chen@Sun.COM 	 */
1091*9430SRaymond.Chen@Sun.COM 	bcopy(spec_data + UWB_BEACONINFO_OFFSET,
1092*9430SRaymond.Chen@Sun.COM 	    evt_struct->BeaconInfo, evt_struct->wBeaconInfoLength);
1093*9430SRaymond.Chen@Sun.COM 
1094*9430SRaymond.Chen@Sun.COM 	/*
1095*9430SRaymond.Chen@Sun.COM 	 * Parse the beacon frame and add the client radio device
1096*9430SRaymond.Chen@Sun.COM 	 * to the dev_list in uwb_dev_handle
1097*9430SRaymond.Chen@Sun.COM 	 */
1098*9430SRaymond.Chen@Sun.COM 	uwba_parse_beacon_info(uwba_dev, evt_struct->BeaconInfo);
1099*9430SRaymond.Chen@Sun.COM 
1100*9430SRaymond.Chen@Sun.COM 	bc_frm = (uwb_beacon_frame_t *)evt_struct->BeaconInfo;
1101*9430SRaymond.Chen@Sun.COM 
1102*9430SRaymond.Chen@Sun.COM 	client_dev = uwba_find_cdev_by_mac(uwba_dev,
1103*9430SRaymond.Chen@Sun.COM 	    &(bc_frm->Device_Identifier));
1104*9430SRaymond.Chen@Sun.COM 
1105*9430SRaymond.Chen@Sun.COM 	/* Update the client device's beconing information */
1106*9430SRaymond.Chen@Sun.COM 	client_dev->bChannelNumber = evt_struct->bChannelNumber;
1107*9430SRaymond.Chen@Sun.COM 	client_dev->bBeaconType = evt_struct->bBeaconType;
1108*9430SRaymond.Chen@Sun.COM 	client_dev->wBPSTOffset = evt_struct->wBPSTOffset;
1109*9430SRaymond.Chen@Sun.COM 	return (UWB_SUCCESS);
1110*9430SRaymond.Chen@Sun.COM }
1111*9430SRaymond.Chen@Sun.COM 
1112*9430SRaymond.Chen@Sun.COM 
1113*9430SRaymond.Chen@Sun.COM /*
1114*9430SRaymond.Chen@Sun.COM  * find the phy capability ie from ie_data, then save the capability bitmap to
1115*9430SRaymond.Chen@Sun.COM  * uwb_dev_hdl
1116*9430SRaymond.Chen@Sun.COM  */
1117*9430SRaymond.Chen@Sun.COM static void
uwba_get_phy_cap(uwb_dev_handle_t uwb_dev_hdl,uint8_t * ie_data,uint16_t ie_len)1118*9430SRaymond.Chen@Sun.COM uwba_get_phy_cap(uwb_dev_handle_t uwb_dev_hdl,
1119*9430SRaymond.Chen@Sun.COM     uint8_t *ie_data, uint16_t ie_len)
1120*9430SRaymond.Chen@Sun.COM {
1121*9430SRaymond.Chen@Sun.COM 	uint8_t *phy_ie;
1122*9430SRaymond.Chen@Sun.COM 
1123*9430SRaymond.Chen@Sun.COM 	/* traverse ie_data to find PHY Capabilities IE */
1124*9430SRaymond.Chen@Sun.COM 	phy_ie = uwba_find_ie(uwb_dev_hdl,
1125*9430SRaymond.Chen@Sun.COM 	    UWB_IE_PHY_CAP, ie_data, ie_len);
1126*9430SRaymond.Chen@Sun.COM 
1127*9430SRaymond.Chen@Sun.COM 	if (phy_ie == NULL) {
1128*9430SRaymond.Chen@Sun.COM 
1129*9430SRaymond.Chen@Sun.COM 		return;
1130*9430SRaymond.Chen@Sun.COM 	}
1131*9430SRaymond.Chen@Sun.COM 	/* copy the phy capabilities bitmap to uwba_dev->phy_cap_bm */
1132*9430SRaymond.Chen@Sun.COM 	uwba_save_phy_cap_bm(uwb_dev_hdl, phy_ie);
1133*9430SRaymond.Chen@Sun.COM }
1134*9430SRaymond.Chen@Sun.COM 
1135*9430SRaymond.Chen@Sun.COM /* Copy the PHY capability bitmap from phy_ie to uwb device handle */
1136*9430SRaymond.Chen@Sun.COM static void
uwba_save_phy_cap_bm(uwb_dev_handle_t uwb_dev_hdl,uint8_t * phy_ie)1137*9430SRaymond.Chen@Sun.COM uwba_save_phy_cap_bm(uwb_dev_handle_t uwb_dev_hdl, uint8_t *phy_ie)
1138*9430SRaymond.Chen@Sun.COM {
1139*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1140*9430SRaymond.Chen@Sun.COM 
1141*9430SRaymond.Chen@Sun.COM 	mutex_enter(&uwba_dev->dev_mutex);
1142*9430SRaymond.Chen@Sun.COM 	uwba_dev->phy_cap_bm = 0;
1143*9430SRaymond.Chen@Sun.COM 
1144*9430SRaymond.Chen@Sun.COM 	uwba_dev->phy_cap_bm = phy_ie[4];
1145*9430SRaymond.Chen@Sun.COM 	uwba_dev->phy_cap_bm = phy_ie[3] | uwba_dev->phy_cap_bm << 8;
1146*9430SRaymond.Chen@Sun.COM 	uwba_dev->phy_cap_bm = phy_ie[2] | uwba_dev->phy_cap_bm << 8;
1147*9430SRaymond.Chen@Sun.COM 	mutex_exit(&uwba_dev->dev_mutex);
1148*9430SRaymond.Chen@Sun.COM }
1149*9430SRaymond.Chen@Sun.COM 
1150*9430SRaymond.Chen@Sun.COM /* List all supported PHY data rates by checking the PHY capability bitmap */
1151*9430SRaymond.Chen@Sun.COM static void
uwba_list_phy_rates(uwb_dev_handle_t uwb_dev_hdl)1152*9430SRaymond.Chen@Sun.COM uwba_list_phy_rates(uwb_dev_handle_t uwb_dev_hdl)
1153*9430SRaymond.Chen@Sun.COM {
1154*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1155*9430SRaymond.Chen@Sun.COM 	int i;
1156*9430SRaymond.Chen@Sun.COM 	const char *uwb_phy_rate_table[] = {
1157*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_53 - UWB_RATE_OFFSET_BASE] = "53.3",
1158*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_80 - UWB_RATE_OFFSET_BASE] = "80",
1159*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_106 - UWB_RATE_OFFSET_BASE] = "106.7",
1160*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_160 - UWB_RATE_OFFSET_BASE] = "160",
1161*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_200 - UWB_RATE_OFFSET_BASE] = "200",
1162*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_320 - UWB_RATE_OFFSET_BASE] = "320",
1163*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_400 - UWB_RATE_OFFSET_BASE] = "400",
1164*9430SRaymond.Chen@Sun.COM 		[UWB_RATE_OFFSET_480 - UWB_RATE_OFFSET_BASE] = "480",
1165*9430SRaymond.Chen@Sun.COM 	};
1166*9430SRaymond.Chen@Sun.COM 
1167*9430SRaymond.Chen@Sun.COM 	for (i = UWB_RATE_OFFSET_BASE; i <= UWB_RATE_OFFSET_480; i++) {
1168*9430SRaymond.Chen@Sun.COM 		if (BT_TEST(&uwba_dev->phy_cap_bm, i)) {
1169*9430SRaymond.Chen@Sun.COM 			uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1170*9430SRaymond.Chen@Sun.COM 			    "uwba_list_phy_rates: Rate supported=%s",
1171*9430SRaymond.Chen@Sun.COM 			    uwb_phy_rate_table[i - UWB_RATE_OFFSET_BASE]);
1172*9430SRaymond.Chen@Sun.COM 		}
1173*9430SRaymond.Chen@Sun.COM 	}
1174*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1175*9430SRaymond.Chen@Sun.COM 	    "uwba_list_phy_rates: phy_cap_bm=%u",
1176*9430SRaymond.Chen@Sun.COM 	    uwba_dev->phy_cap_bm);
1177*9430SRaymond.Chen@Sun.COM }
1178*9430SRaymond.Chen@Sun.COM 
1179*9430SRaymond.Chen@Sun.COM /* List all supported PHY band groups by checking the PHY capability bitmap */
1180*9430SRaymond.Chen@Sun.COM static void
uwba_list_phy_bandgroups(uwb_dev_handle_t uwb_dev_hdl)1181*9430SRaymond.Chen@Sun.COM uwba_list_phy_bandgroups(uwb_dev_handle_t uwb_dev_hdl)
1182*9430SRaymond.Chen@Sun.COM {
1183*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1184*9430SRaymond.Chen@Sun.COM 	int i;
1185*9430SRaymond.Chen@Sun.COM 
1186*9430SRaymond.Chen@Sun.COM 	/* group 1 to 4 [ECMA, Table 112] */
1187*9430SRaymond.Chen@Sun.COM 	for (i = 0; i <= 7; i++) {
1188*9430SRaymond.Chen@Sun.COM 		if (BT_TEST(&uwba_dev->phy_cap_bm, i)) {
1189*9430SRaymond.Chen@Sun.COM 			uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1190*9430SRaymond.Chen@Sun.COM 			    "uwba_list_phy_bandgroups: band groups "
1191*9430SRaymond.Chen@Sun.COM 			    "supported=%d", i);
1192*9430SRaymond.Chen@Sun.COM 		}
1193*9430SRaymond.Chen@Sun.COM 	}
1194*9430SRaymond.Chen@Sun.COM 
1195*9430SRaymond.Chen@Sun.COM 	/* group 5 [ECMA, Table 112] */
1196*9430SRaymond.Chen@Sun.COM 	if (BT_TEST(&uwba_dev->phy_cap_bm, 9)) {
1197*9430SRaymond.Chen@Sun.COM 		uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1198*9430SRaymond.Chen@Sun.COM 		    "uwba_list_phy_bandgroups: band groups supported=%d", i);
1199*9430SRaymond.Chen@Sun.COM 	}
1200*9430SRaymond.Chen@Sun.COM }
1201*9430SRaymond.Chen@Sun.COM 
1202*9430SRaymond.Chen@Sun.COM 
1203*9430SRaymond.Chen@Sun.COM 
1204*9430SRaymond.Chen@Sun.COM /*
1205*9430SRaymond.Chen@Sun.COM  * Allocate a channel for the HC. Scan every channel supported,
1206*9430SRaymond.Chen@Sun.COM  * if beacon information from the channel received, scan the next
1207*9430SRaymond.Chen@Sun.COM  * channel, or else, stop.
1208*9430SRaymond.Chen@Sun.COM  * Return:
1209*9430SRaymond.Chen@Sun.COM  * 	first channel with no beacon recieved
1210*9430SRaymond.Chen@Sun.COM  * 	last channel if every channel is busy
1211*9430SRaymond.Chen@Sun.COM  * 	0 if scan failure
1212*9430SRaymond.Chen@Sun.COM  * uwba_channel_table is used to decode the PHY capability IE.
1213*9430SRaymond.Chen@Sun.COM  * The array index is the bit in the PHY IE. base is the first
1214*9430SRaymond.Chen@Sun.COM  * TFC code.offset is the length from the first TFC code.
1215*9430SRaymond.Chen@Sun.COM  * Refer to:
1216*9430SRaymond.Chen@Sun.COM  * [ECM-368]. CHAP 11.2. Table 25-30.
1217*9430SRaymond.Chen@Sun.COM  * [ECM-368]. CHAP 16.8.16. Table 112
1218*9430SRaymond.Chen@Sun.COM  *
1219*9430SRaymond.Chen@Sun.COM  */
1220*9430SRaymond.Chen@Sun.COM uint8_t
uwba_allocate_channel(uwb_dev_handle_t uwb_dev_hdl)1221*9430SRaymond.Chen@Sun.COM uwba_allocate_channel(uwb_dev_handle_t uwb_dev_hdl) {
1222*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1223*9430SRaymond.Chen@Sun.COM 	int i, j;
1224*9430SRaymond.Chen@Sun.COM 	uwba_channel_range_t uwba_channel_table[] = {
1225*9430SRaymond.Chen@Sun.COM 		{ .base =  9, .offset = 4 }, /* Band group 1 TFI */
1226*9430SRaymond.Chen@Sun.COM 		{ .base = 13, .offset = 3 }, /* Band group 1 FFI */
1227*9430SRaymond.Chen@Sun.COM 		{ .base = 17, .offset = 4 }, /* Band group 2 TFI */
1228*9430SRaymond.Chen@Sun.COM 		{ .base = 21, .offset = 3 }, /* Band group 2 FFI */
1229*9430SRaymond.Chen@Sun.COM 		{ .base = 25, .offset = 4 }, /* Band group 3 TFI */
1230*9430SRaymond.Chen@Sun.COM 		{ .base = 29, .offset = 3 }, /* Band group 3 FFI */
1231*9430SRaymond.Chen@Sun.COM 		{ .base = 33, .offset = 4 }, /* Band group 4 TFI */
1232*9430SRaymond.Chen@Sun.COM 		{ .base = 37, .offset = 3 }, /* Band group 4 FFI */
1233*9430SRaymond.Chen@Sun.COM 		{ .base =  0, .offset = 0 }, /* Bit reserved	 */
1234*9430SRaymond.Chen@Sun.COM 		{ .base = 45, .offset = 2 }  /* Band group 5 FFI */
1235*9430SRaymond.Chen@Sun.COM 	};
1236*9430SRaymond.Chen@Sun.COM 	int tbl_size = sizeof (uwba_channel_table) /
1237*9430SRaymond.Chen@Sun.COM 	    sizeof (uwba_channel_range_t);
1238*9430SRaymond.Chen@Sun.COM 
1239*9430SRaymond.Chen@Sun.COM 	uint8_t channel = 0;
1240*9430SRaymond.Chen@Sun.COM 	for (i = 0; i < tbl_size; i++) {
1241*9430SRaymond.Chen@Sun.COM 		if ((uwba_dev->phy_cap_bm & (0x01<<i)) == 0x0) continue;
1242*9430SRaymond.Chen@Sun.COM 
1243*9430SRaymond.Chen@Sun.COM 		for (j = 0; j < uwba_channel_table[i].offset; j++) {
1244*9430SRaymond.Chen@Sun.COM 
1245*9430SRaymond.Chen@Sun.COM 			channel = uwba_channel_table[i].base + j;
1246*9430SRaymond.Chen@Sun.COM 			if (uwb_scan_channel(uwb_dev_hdl, channel)
1247*9430SRaymond.Chen@Sun.COM 			    != UWB_SUCCESS) {
1248*9430SRaymond.Chen@Sun.COM 				uwba_log(uwba_dev, UWBA_LOG_LOG,
1249*9430SRaymond.Chen@Sun.COM 				    "uwba_allocate_channel: scan chanel"
1250*9430SRaymond.Chen@Sun.COM 				    " %d failed", channel);
1251*9430SRaymond.Chen@Sun.COM 
1252*9430SRaymond.Chen@Sun.COM 				return (0);
1253*9430SRaymond.Chen@Sun.COM 			}
1254*9430SRaymond.Chen@Sun.COM 			/* No beacon recevied in this channel, return */
1255*9430SRaymond.Chen@Sun.COM 			if (!uwba_find_cdev_by_channel(uwba_dev, channel)) {
1256*9430SRaymond.Chen@Sun.COM 
1257*9430SRaymond.Chen@Sun.COM 				return (channel);
1258*9430SRaymond.Chen@Sun.COM 			}
1259*9430SRaymond.Chen@Sun.COM 			uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1260*9430SRaymond.Chen@Sun.COM 			    "uwba_allocate_channel: exsting device becaoning"
1261*9430SRaymond.Chen@Sun.COM 			    "in channel = %d ", channel);
1262*9430SRaymond.Chen@Sun.COM 		}
1263*9430SRaymond.Chen@Sun.COM 
1264*9430SRaymond.Chen@Sun.COM 	}
1265*9430SRaymond.Chen@Sun.COM 
1266*9430SRaymond.Chen@Sun.COM 	/*
1267*9430SRaymond.Chen@Sun.COM 	 * when we reach here, it means all the channel has beconning device,
1268*9430SRaymond.Chen@Sun.COM 	 * return the last channel
1269*9430SRaymond.Chen@Sun.COM 	 */
1270*9430SRaymond.Chen@Sun.COM done:
1271*9430SRaymond.Chen@Sun.COM 	uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1272*9430SRaymond.Chen@Sun.COM 	    "uwba_allocate_channel: return channel = %d",
1273*9430SRaymond.Chen@Sun.COM 	    channel);
1274*9430SRaymond.Chen@Sun.COM 
1275*9430SRaymond.Chen@Sun.COM 	return (channel);
1276*9430SRaymond.Chen@Sun.COM }
1277*9430SRaymond.Chen@Sun.COM /*
1278*9430SRaymond.Chen@Sun.COM  * Find a IE with a specific ID in ie_data. Return the pointer to the IE head if
1279*9430SRaymond.Chen@Sun.COM  * found, else return NULL.
1280*9430SRaymond.Chen@Sun.COM  */
1281*9430SRaymond.Chen@Sun.COM uint8_t *
uwba_find_ie(uwb_dev_handle_t uwb_dev_hdl,uint_t ie_id,uint8_t * ie_data,uint16_t ie_len)1282*9430SRaymond.Chen@Sun.COM uwba_find_ie(uwb_dev_handle_t uwb_dev_hdl, uint_t ie_id,
1283*9430SRaymond.Chen@Sun.COM 	uint8_t *ie_data, uint16_t ie_len)
1284*9430SRaymond.Chen@Sun.COM {
1285*9430SRaymond.Chen@Sun.COM 	int i = 0;
1286*9430SRaymond.Chen@Sun.COM 	uint8_t curr_ie_len;
1287*9430SRaymond.Chen@Sun.COM 	boolean_t matched = B_FALSE;
1288*9430SRaymond.Chen@Sun.COM 	uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1289*9430SRaymond.Chen@Sun.COM 
1290*9430SRaymond.Chen@Sun.COM 	while (i < (ie_len - 1)) {
1291*9430SRaymond.Chen@Sun.COM 		if (ie_data[i] == ie_id) {
1292*9430SRaymond.Chen@Sun.COM 			matched = B_TRUE;
1293*9430SRaymond.Chen@Sun.COM 
1294*9430SRaymond.Chen@Sun.COM 			break;
1295*9430SRaymond.Chen@Sun.COM 		}
1296*9430SRaymond.Chen@Sun.COM 		i++; /* move to the length item of the current IE */
1297*9430SRaymond.Chen@Sun.COM 		curr_ie_len = ie_data[i];
1298*9430SRaymond.Chen@Sun.COM 		i =  i + curr_ie_len + 1; /* move to the next IE's head */
1299*9430SRaymond.Chen@Sun.COM 	}
1300*9430SRaymond.Chen@Sun.COM 	if (matched) {
1301*9430SRaymond.Chen@Sun.COM 		curr_ie_len = ie_data[i + 1];
1302*9430SRaymond.Chen@Sun.COM 
1303*9430SRaymond.Chen@Sun.COM 		/*
1304*9430SRaymond.Chen@Sun.COM 		 * if the rest ie data are less than that indicated in the
1305*9430SRaymond.Chen@Sun.COM 		 * matched IE's length, then this is not valid IE
1306*9430SRaymond.Chen@Sun.COM 		 */
1307*9430SRaymond.Chen@Sun.COM 		if ((ie_len - i -1) < curr_ie_len) {
1308*9430SRaymond.Chen@Sun.COM 			uwba_log(uwba_dev, UWBA_LOG_LOG,
1309*9430SRaymond.Chen@Sun.COM 			    "the matched IE is not valid. "
1310*9430SRaymond.Chen@Sun.COM 			    "curr_ie_len=%d, i=%d", curr_ie_len, i);
1311*9430SRaymond.Chen@Sun.COM 
1312*9430SRaymond.Chen@Sun.COM 			return (NULL);
1313*9430SRaymond.Chen@Sun.COM 		}
1314*9430SRaymond.Chen@Sun.COM 
1315*9430SRaymond.Chen@Sun.COM 		return (&ie_data[i]);
1316*9430SRaymond.Chen@Sun.COM 	}
1317*9430SRaymond.Chen@Sun.COM 
1318*9430SRaymond.Chen@Sun.COM 	return (NULL);
1319*9430SRaymond.Chen@Sun.COM }
1320*9430SRaymond.Chen@Sun.COM 
1321*9430SRaymond.Chen@Sun.COM void
uwba_copy_rccb(uwb_rccb_cmd_t * src_rccb,uwb_rccb_cmd_t * des_rccb)1322*9430SRaymond.Chen@Sun.COM uwba_copy_rccb(uwb_rccb_cmd_t *src_rccb, uwb_rccb_cmd_t *des_rccb)
1323*9430SRaymond.Chen@Sun.COM {
1324*9430SRaymond.Chen@Sun.COM 	bcopy(src_rccb, des_rccb,	sizeof (uwb_rccb_cmd_t));
1325*9430SRaymond.Chen@Sun.COM }
1326*9430SRaymond.Chen@Sun.COM 
1327*9430SRaymond.Chen@Sun.COM /* uwba_log, log the message output to dmesg according to err level */
1328*9430SRaymond.Chen@Sun.COM void
uwba_log(uwba_dev_t * uwba_dev,uint_t msglevel,char * formatarg,...)1329*9430SRaymond.Chen@Sun.COM uwba_log(uwba_dev_t *uwba_dev, uint_t msglevel, char *formatarg, ...)
1330*9430SRaymond.Chen@Sun.COM {
1331*9430SRaymond.Chen@Sun.COM 	va_list	ap;
1332*9430SRaymond.Chen@Sun.COM 	const char *devinst = NULL;
1333*9430SRaymond.Chen@Sun.COM 
1334*9430SRaymond.Chen@Sun.COM 	if (msglevel <= uwba_errlevel) {
1335*9430SRaymond.Chen@Sun.COM 		char *format;
1336*9430SRaymond.Chen@Sun.COM 		int formatlen = strlen(formatarg) + 2;	/* '!' and NULL char */
1337*9430SRaymond.Chen@Sun.COM 		int devinst_start = 0;
1338*9430SRaymond.Chen@Sun.COM 		if (uwba_dev) {
1339*9430SRaymond.Chen@Sun.COM 			devinst = uwba_dev->devinst;
1340*9430SRaymond.Chen@Sun.COM 		} else {
1341*9430SRaymond.Chen@Sun.COM 			devinst = "uwba: ";
1342*9430SRaymond.Chen@Sun.COM 		}
1343*9430SRaymond.Chen@Sun.COM 		ASSERT(devinst != NULL);
1344*9430SRaymond.Chen@Sun.COM 
1345*9430SRaymond.Chen@Sun.COM 		/* Allocate extra room if driver name and instance is present */
1346*9430SRaymond.Chen@Sun.COM 		formatlen += strlen(devinst);
1347*9430SRaymond.Chen@Sun.COM 
1348*9430SRaymond.Chen@Sun.COM 		format = kmem_zalloc(formatlen, KM_SLEEP);
1349*9430SRaymond.Chen@Sun.COM 
1350*9430SRaymond.Chen@Sun.COM 		if (msglevel >= UWBA_LOG_LOG) {
1351*9430SRaymond.Chen@Sun.COM 			format[0] = '!';
1352*9430SRaymond.Chen@Sun.COM 			devinst_start = 1;
1353*9430SRaymond.Chen@Sun.COM 		}
1354*9430SRaymond.Chen@Sun.COM 
1355*9430SRaymond.Chen@Sun.COM 		(void) strcpy(&format[devinst_start], devinst);
1356*9430SRaymond.Chen@Sun.COM 
1357*9430SRaymond.Chen@Sun.COM 		va_start(ap, formatarg);
1358*9430SRaymond.Chen@Sun.COM 		(void) strcat(format, formatarg);
1359*9430SRaymond.Chen@Sun.COM 		vcmn_err(CE_CONT, format, ap);
1360*9430SRaymond.Chen@Sun.COM 		va_end(ap);
1361*9430SRaymond.Chen@Sun.COM 
1362*9430SRaymond.Chen@Sun.COM 		kmem_free(format, formatlen);
1363*9430SRaymond.Chen@Sun.COM 	}
1364*9430SRaymond.Chen@Sun.COM }
1365*9430SRaymond.Chen@Sun.COM 
1366*9430SRaymond.Chen@Sun.COM /* Get a msg string of a event or notfication */
1367*9430SRaymond.Chen@Sun.COM const char *
uwba_event_msg(uint16_t wEvent)1368*9430SRaymond.Chen@Sun.COM uwba_event_msg(uint16_t wEvent) {
1369*9430SRaymond.Chen@Sun.COM 	if (wEvent > UWB_CE_SET_ASIE_NOTIFICATION) {
1370*9430SRaymond.Chen@Sun.COM 		return ("Unknown Message");
1371*9430SRaymond.Chen@Sun.COM 	} else {
1372*9430SRaymond.Chen@Sun.COM 		return (uwba_evt_msg_table[wEvent]);
1373*9430SRaymond.Chen@Sun.COM 	}
1374*9430SRaymond.Chen@Sun.COM }
1375