Home | History | Annotate | Download | only in hid
      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 *******************************************************************************/
     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 
     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-1] = '\0';
     92         }
     93     }
     94     else
     95         str[0] = '\0';
     96 }
     97 
     98 
     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_min_tout = 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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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     else 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 *******************************************************************************/
    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 
    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