• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright (C) 2002-2012 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 /******************************************************************************
20  *
21  *  This file contains the HID HOST API entry points
22  *
23  ******************************************************************************/
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 
29 #include "gki.h"
30 #include "bt_types.h"
31 #include "hiddefs.h"
32 #include "hidh_api.h"
33 #include "hidh_int.h"
34 #include "btm_api.h"
35 #include "btu.h"
36 
37 #if HID_DYNAMIC_MEMORY == FALSE
38 tHID_HOST_CTB   hh_cb;
39 #endif
40 
41 static void hidh_search_callback (UINT16 sdp_result);
42 
43 /*******************************************************************************
44 **
45 ** Function         HID_HostGetSDPRecord
46 **
47 ** Description      This function reads the device SDP record
48 **
49 ** Returns          tHID_STATUS
50 **
51 *******************************************************************************/
HID_HostGetSDPRecord(BD_ADDR addr,tSDP_DISCOVERY_DB * p_db,UINT32 db_len,tHID_HOST_SDP_CALLBACK * sdp_cback)52 tHID_STATUS HID_HostGetSDPRecord ( BD_ADDR addr, tSDP_DISCOVERY_DB *p_db, UINT32 db_len,
53                                    tHID_HOST_SDP_CALLBACK *sdp_cback )
54 {
55     tSDP_UUID   uuid_list;
56 
57     if( hh_cb.sdp_busy )
58         return HID_ERR_SDP_BUSY;
59 
60     uuid_list.len = 2;
61     uuid_list.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
62 
63     hh_cb.p_sdp_db = p_db;
64     SDP_InitDiscoveryDb (p_db, db_len, 1, &uuid_list, 0, NULL);
65 
66     if (SDP_ServiceSearchRequest (addr, p_db, hidh_search_callback))
67     {
68         hh_cb.sdp_cback = sdp_cback ;
69         hh_cb.sdp_busy = TRUE;
70         return HID_SUCCESS;
71     }
72     else
73         return HID_ERR_NO_RESOURCES;
74 }
75 
hidh_get_str_attr(tSDP_DISC_REC * p_rec,UINT16 attr_id,UINT16 max_len,char * str)76 void hidh_get_str_attr( tSDP_DISC_REC *p_rec, UINT16 attr_id, UINT16 max_len, char *str )
77 {
78     tSDP_DISC_ATTR          *p_attr;
79     UINT16                  name_len;
80 
81     if ((p_attr = SDP_FindAttributeInRec(p_rec, attr_id)) != NULL)
82     {
83         if((name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)) < max_len )
84         {
85             memcpy( str, (char *) p_attr->attr_value.v.array, name_len );
86             str[name_len] = '\0';
87         }
88         else
89         {
90             memcpy( str, (char *) p_attr->attr_value.v.array, max_len-1 );
91             str[max_len] = '\0';
92         }
93     }
94     else
95         str[0] = '\0';
96 }
97 
98 
hidh_search_callback(UINT16 sdp_result)99 static void hidh_search_callback (UINT16 sdp_result)
100 {
101     tSDP_DISCOVERY_DB       *p_db = hh_cb.p_sdp_db;
102     tSDP_DISC_REC           *p_rec;
103     tSDP_DISC_ATTR          *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
104     tBT_UUID                hid_uuid;
105     tHID_DEV_SDP_INFO       *p_nvi = &hh_cb.sdp_rec;
106     UINT16                  attr_mask = 0;
107 
108     hid_uuid.len       = LEN_UUID_16;
109     hid_uuid.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
110 
111     hh_cb.sdp_busy = FALSE;
112 
113     if (sdp_result != SDP_SUCCESS)
114     {
115         hh_cb.sdp_cback(sdp_result, 0, NULL);
116         return;
117     }
118 
119     if ((p_rec = SDP_FindServiceUUIDInDb (p_db, &hid_uuid, NULL)) == NULL)
120     {
121         hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
122         return;
123     }
124 
125     memset (&hh_cb.sdp_rec, 0, sizeof( tHID_DEV_SDP_INFO ));
126 
127     /* First, verify the mandatory fields we care about */
128     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == NULL)
129      || (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
130      || ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL)
131      || (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
132      || ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL)
133      || ((p_repdesc = p_subattr2->p_next_attr) == NULL)
134      || (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE))
135     {
136         hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
137         return;
138     }
139 
140     if ((p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type)) != 0)
141         p_nvi->dscp_info.dsc_list = (UINT8 *) &p_repdesc->attr_value;
142 
143     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != NULL) &&
144         (p_attr->attr_value.v.u8) )
145     {
146         attr_mask |= HID_VIRTUAL_CABLE;
147     }
148 
149     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) &&
150         (p_attr->attr_value.v.u8) )
151     {
152         attr_mask |= HID_RECONN_INIT;
153     }
154 
155     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) &&
156         (p_attr->attr_value.v.u8) )
157     {
158         attr_mask |= HID_NORMALLY_CONNECTABLE;
159     }
160 
161     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SDP_DISABLE)) != NULL)&&
162         (p_attr->attr_value.v.u8) )
163     {
164         attr_mask |= HID_SDP_DISABLE;
165     }
166 
167     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_BATTERY_POWER)) != NULL)&&
168         (p_attr->attr_value.v.u8) )
169     {
170         attr_mask |= HID_BATTERY_POWER;
171     }
172 
173     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_REMOTE_WAKE)) != NULL)&&
174         (p_attr->attr_value.v.u8) )
175     {
176         attr_mask |= HID_REMOTE_WAKE;
177     }
178 
179     hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN, p_nvi->svc_name );
180     hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN, p_nvi->svc_descr );
181     hidh_get_str_attr( p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN, p_nvi->prov_name );
182 
183     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != NULL))
184     {
185         p_nvi->rel_num = p_attr->attr_value.v.u16;
186     }
187 
188     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_COUNTRY_CODE)) != NULL))
189     {
190         p_nvi->ctry_code = p_attr->attr_value.v.u8;
191     }
192 
193     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != NULL))
194     {
195         p_nvi->sub_class = p_attr->attr_value.v.u8;
196     }
197 
198     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_PARSER_VERSION)) != NULL))
199     {
200         p_nvi->hpars_ver = p_attr->attr_value.v.u16;
201     }
202 
203     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL))
204     {
205         attr_mask |= HID_SUP_TOUT_AVLBL;
206         p_nvi->sup_timeout = p_attr->attr_value.v.u16;
207     }
208 
209     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != NULL))
210     {
211         attr_mask |= HID_SSR_MAX_LATENCY;
212         p_nvi->ssr_max_latency = p_attr->attr_value.v.u16;
213     }
214     else
215         p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
216 
217     if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL))
218     {
219         attr_mask |= HID_SSR_MIN_TOUT;
220         p_nvi->ssr_min_tout = p_attr->attr_value.v.u16;
221     }
222     else
223         p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
224 
225     hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
226     hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
227 }
228 
229 
230 /*******************************************************************************
231 **
232 ** Function         HID_HostInit
233 **
234 ** Description      This function initializes the control block and trace variable
235 **
236 ** Returns          void
237 **
238 *******************************************************************************/
HID_HostInit(void)239 void HID_HostInit (void)
240 {
241     memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
242 
243 #if defined(HID_INITIAL_TRACE_LEVEL)
244     hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
245 #else
246     hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
247 #endif
248 }
249 
250 /*******************************************************************************
251 **
252 ** Function         HID_HostSetTraceLevel
253 **
254 ** Description      This function sets the trace level for HID Host. If called with
255 **                  a value of 0xFF, it simply reads the current trace level.
256 **
257 ** Returns          the new (current) trace level
258 **
259 *******************************************************************************/
HID_HostSetTraceLevel(UINT8 new_level)260 UINT8 HID_HostSetTraceLevel (UINT8 new_level)
261 {
262     if (new_level != 0xFF)
263         hh_cb.trace_level = new_level;
264 
265     return (hh_cb.trace_level);
266 }
267 
268 /*******************************************************************************
269 **
270 ** Function         HID_HostRegister
271 **
272 ** Description      This function registers HID-Host with lower layers
273 **
274 ** Returns          tHID_STATUS
275 **
276 *******************************************************************************/
HID_HostRegister(tHID_HOST_DEV_CALLBACK * dev_cback)277 tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback)
278 {
279     tHID_STATUS st;
280 
281     if( hh_cb.reg_flag )
282         return HID_ERR_ALREADY_REGISTERED;
283 
284     if( dev_cback == NULL )
285         return HID_ERR_INVALID_PARAM;
286 
287     /* Register with L2CAP */
288     if( (st = hidh_conn_reg()) != HID_SUCCESS )
289     {
290         return st;
291     }
292 
293     hh_cb.callback = dev_cback ;
294     hh_cb.reg_flag = TRUE;
295 
296     return (HID_SUCCESS);
297 }
298 
299 /*******************************************************************************
300 **
301 ** Function         HID_HostDeregister
302 **
303 ** Description      This function is called when the host is about power down.
304 **
305 ** Returns          tHID_STATUS
306 **
307 *******************************************************************************/
HID_HostDeregister(void)308 tHID_STATUS HID_HostDeregister(void)
309 {
310     UINT8 i;
311 
312     if( !hh_cb.reg_flag )
313         return (HID_ERR_NOT_REGISTERED);
314 
315     for( i=0; i<HID_HOST_MAX_DEVICES; i++ )
316     {
317         HID_HostRemoveDev( i ) ;
318     }
319 
320     hidh_conn_dereg();
321     hh_cb.reg_flag = FALSE;
322 
323     return (HID_SUCCESS) ;
324 }
325 
326 /*******************************************************************************
327 **
328 ** Function         HID_HostAddDev
329 **
330 ** Description      This is called so HID-host may manage this device.
331 **
332 ** Returns          tHID_STATUS
333 **
334 *******************************************************************************/
HID_HostAddDev(BD_ADDR addr,UINT16 attr_mask,UINT8 * handle)335 tHID_STATUS HID_HostAddDev ( BD_ADDR addr, UINT16 attr_mask, UINT8 *handle )
336 {
337     int i;
338     /* Find an entry for this device in hh_cb.devices array */
339 
340     if( !hh_cb.reg_flag )
341         return (HID_ERR_NOT_REGISTERED);
342 
343     for( i=0; i<HID_HOST_MAX_DEVICES; i++)
344     {
345         if((hh_cb.devices[i].in_use) &&
346            (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN)))
347             break;
348     }
349 
350     if (i== HID_HOST_MAX_DEVICES )
351     {
352         for( i=0; i<HID_HOST_MAX_DEVICES; i++)
353         {
354             if( !hh_cb.devices[i].in_use)
355                 break;
356         }
357     }
358 
359     if( i==HID_HOST_MAX_DEVICES )
360         return HID_ERR_NO_RESOURCES;
361 
362     if (!hh_cb.devices[i].in_use)
363     {
364         hh_cb.devices[i].in_use = TRUE;
365         memcpy( hh_cb.devices[i].addr, addr, sizeof( BD_ADDR ) ) ;
366         hh_cb.devices[i].state = HID_DEV_NO_CONN;
367         hh_cb.devices[i].conn_tries = 0 ;
368     }
369 
370     hh_cb.devices[i].attr_mask = attr_mask;
371 
372     *handle = i;
373 
374     return (HID_SUCCESS);
375 }
376 
377 
378 /*******************************************************************************
379 **
380 ** Function         HID_HostRemoveDev
381 **
382 ** Description      This removes the device from list devices that host has to manage.
383 **
384 ** Returns          tHID_STATUS
385 **
386 *******************************************************************************/
HID_HostRemoveDev(UINT8 dev_handle)387 tHID_STATUS HID_HostRemoveDev ( UINT8 dev_handle )
388 {
389     if( !hh_cb.reg_flag )
390         return (HID_ERR_NOT_REGISTERED);
391 
392     if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
393         return HID_ERR_INVALID_PARAM;
394 
395     HID_HostCloseDev( dev_handle ) ;
396     hh_cb.devices[dev_handle].in_use = FALSE;
397     hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED;
398     hh_cb.devices[dev_handle].conn.ctrl_cid = hh_cb.devices[dev_handle].conn.intr_cid = 0;
399 
400     return HID_SUCCESS;
401 }
402 
403 /*******************************************************************************
404 **
405 ** Function         HID_HostOpenDev
406 **
407 ** Description      This function is called when the user wants to initiate a
408 **                  connection attempt to a device.
409 **
410 ** Returns          void
411 **
412 *******************************************************************************/
HID_HostOpenDev(UINT8 dev_handle)413 tHID_STATUS HID_HostOpenDev ( UINT8 dev_handle )
414 {
415     if( !hh_cb.reg_flag )
416         return (HID_ERR_NOT_REGISTERED);
417 
418     if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
419         return HID_ERR_INVALID_PARAM;
420 
421     if( hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN )
422         return HID_ERR_ALREADY_CONN;
423 
424     hh_cb.devices[dev_handle].conn_tries = 1;
425     return hidh_conn_initiate( dev_handle );
426 }
427 
428 /*******************************************************************************
429 **
430 ** Function         HID_HostWriteDev
431 **
432 ** Description      This function is called when the host has a report to send.
433 **
434 **                  report_id: is only used on GET_REPORT transaction if is specified.
435 **                              only valid when it's a non-zero value.
436 **
437 ** Returns          void
438 **
439 *******************************************************************************/
HID_HostWriteDev(UINT8 dev_handle,UINT8 t_type,UINT8 param,UINT16 data,UINT8 report_id,BT_HDR * pbuf)440 tHID_STATUS HID_HostWriteDev( UINT8 dev_handle, UINT8 t_type,
441                               UINT8 param, UINT16 data, UINT8 report_id, BT_HDR *pbuf  )
442 {
443     tHID_STATUS status = HID_SUCCESS;
444 
445     if( !hh_cb.reg_flag )
446     {
447         HIDH_TRACE_ERROR0("HID_ERR_NOT_REGISTERED");
448         status = HID_ERR_NOT_REGISTERED;
449     }
450 
451     if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
452     {
453         HIDH_TRACE_ERROR0("HID_ERR_INVALID_PARAM");
454         status = HID_ERR_INVALID_PARAM;
455     }
456 
457     if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
458     {
459         HIDH_TRACE_ERROR1("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle);
460         status = HID_ERR_NO_CONNECTION;
461     }
462 
463     if (status != HID_SUCCESS)
464     {
465         if (pbuf)
466             GKI_freebuf ((void *)pbuf);
467     }
468     else
469         status = hidh_conn_snd_data( dev_handle, t_type, param, data, report_id, pbuf ) ;
470 
471     return status;
472 }
473 
474 /*******************************************************************************
475 **
476 ** Function         HID_HostCloseDev
477 **
478 ** Description      This function disconnects the device.
479 **
480 ** Returns          void
481 **
482 *******************************************************************************/
HID_HostCloseDev(UINT8 dev_handle)483 tHID_STATUS HID_HostCloseDev( UINT8 dev_handle )
484 {
485     if( !hh_cb.reg_flag )
486         return (HID_ERR_NOT_REGISTERED);
487 
488     if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
489         return HID_ERR_INVALID_PARAM;
490 
491     hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
492     btu_stop_timer( &(hh_cb.devices[dev_handle].conn.timer_entry) ) ;
493 
494     if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
495         return HID_ERR_NO_CONNECTION;
496 
497     hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
498     return hidh_conn_disconnect( dev_handle );
499 }
500 
HID_HostSetSecurityLevel(char serv_name[],UINT8 sec_lvl)501 tHID_STATUS HID_HostSetSecurityLevel( char serv_name[], UINT8 sec_lvl )
502 {
503     if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
504                                sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
505     {
506         HIDH_TRACE_ERROR0 ("Security Registration 1 failed");
507         return (HID_ERR_NO_RESOURCES);
508     }
509 
510     if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
511                                sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
512     {
513         HIDH_TRACE_ERROR0 ("Security Registration 2 failed");
514         return (HID_ERR_NO_RESOURCES);
515     }
516 
517     if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
518                                BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
519     {
520         HIDH_TRACE_ERROR0 ("Security Registration 3 failed");
521         return (HID_ERR_NO_RESOURCES);
522     }
523 
524     if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
525                                BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
526     {
527         HIDH_TRACE_ERROR0 ("Security Registration 4 failed");
528         return (HID_ERR_NO_RESOURCES);
529     }
530 
531     if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_INTR,
532                                BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
533     {
534         HIDH_TRACE_ERROR0 ("Security Registration 5 failed");
535         return (HID_ERR_NO_RESOURCES);
536     }
537 
538     if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_INTR,
539                                BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
540     {
541         HIDH_TRACE_ERROR0 ("Security Registration 6 failed");
542         return (HID_ERR_NO_RESOURCES);
543     }
544 
545     return( HID_SUCCESS );
546 }
547