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