diff options
Diffstat (limited to 'stack/hid/hidd_api.c')
-rw-r--r-- | stack/hid/hidd_api.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/stack/hid/hidd_api.c b/stack/hid/hidd_api.c new file mode 100644 index 0000000..7ee41ea --- /dev/null +++ b/stack/hid/hidd_api.c @@ -0,0 +1,536 @@ +/*****************************************************************************/ +/* */ +/* Name: hidd_api.c */ +/* */ +/* Description: this file contains the Device HID API entry points */ +/* */ +/* */ +/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */ +/* WIDCOMM Bluetooth Core. Proprietary and confidential. */ +/*****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "wcassert.h" + +#include "gki.h" +#include "bt_types.h" +#include "hiddefs.h" +#include "hidd_api.h" +#include "hidd_int.h" +#include "btm_api.h" + +#include "hcimsgs.h" +#include "btu.h" +#include "sdpdefs.h" +#include "sdp_api.h" + +static const UINT8 HidDevLangList[] = HID_DEV_LANGUAGELIST; + +#ifndef HID_DEV_BOOT_DEVICE +#define HID_DEV_BOOT_DEVICE TRUE +#endif + + +/******************************************************************************* +** +** Function HID_DevSetSDPRecord +** +** Description This function should be called at startup to create the +** device SDP record +** +** Returns 0 if error else sdp handle for the record. +** +*******************************************************************************/ +UINT32 HID_DevSetSDPRecord (tHID_DEV_SDP_INFO *p_sdp_info) +{ + UINT32 sdp_handle; + tSDP_PROTOCOL_ELEM protocol_list[2]; + tSDP_PROTO_LIST_ELEM additional_list; + UINT16 u16; + UINT8 u8; + UINT8 *pRepDescriptor, *pd; + char buf[2]; + + if( p_sdp_info == NULL ) + return (0); + + /* Create an SDP record for the ctrl/data or notification channel */ + if ((sdp_handle = SDP_CreateRecord()) == FALSE) + { + HIDD_TRACE_ERROR0 ("Could not create service record"); + return (0); + } + + /* Add the UUID to the Service Class ID List */ + u16 = UUID_SERVCLASS_HUMAN_INTERFACE; + SDP_AddServiceClassIdList(sdp_handle, 1, &u16); + + /* Build the protocol descriptor list */ + protocol_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + protocol_list[0].num_params = 1; + protocol_list[0].params[0] = HID_PSM_CONTROL; + + protocol_list[1].num_params = 0; + protocol_list[1].protocol_uuid = UUID_PROTOCOL_HIDP; + + SDP_AddProtocolList(sdp_handle, 2, protocol_list); + + /* Language base */ + SDP_AddLanguageBaseAttrIDList (sdp_handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, + LANGUAGE_BASE_ID); + + /* Add the Bluetooth Profile Descriptor List (profile version number) */ + SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_HUMAN_INTERFACE, 0x0100); + + /* Add the PSM of the interrupt channel to the Additional Protocol Descriptor List */ + additional_list.num_elems = 2; + additional_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + additional_list.list_elem[0].num_params = 1; + additional_list.list_elem[0].params[0] = HID_PSM_INTERRUPT; + additional_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP; + additional_list.list_elem[1].num_params = 0; + + SDP_AddAdditionProtoLists (sdp_handle, 1, &additional_list); + + if( p_sdp_info->svc_name[0] != '\0' ) + SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, + (UINT8)(strlen(p_sdp_info->svc_name)+1), (UINT8 *)p_sdp_info->svc_name); + + if( p_sdp_info->svc_descr[0] != '\0' ) + SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE, + (UINT8)(strlen(p_sdp_info->svc_descr)+1), (UINT8 *)p_sdp_info->svc_descr); + + if( p_sdp_info->prov_name[0] != '\0' ) + SDP_AddAttribute (sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, + (UINT8)(strlen(p_sdp_info->prov_name)+1), (UINT8 *)p_sdp_info->prov_name); + + /* HID parser version */ + UINT16_TO_BE_FIELD(buf,p_sdp_info->hpars_ver) ; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_PARSER_VERSION, UINT_DESC_TYPE, 2, (UINT8 *)buf); + + /* HID subclass */ + u8 = p_sdp_info->sub_class; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_DEVICE_SUBCLASS, UINT_DESC_TYPE, 1, &u8); + + /* HID country code */ + u8 = p_sdp_info->ctry_code; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE, 1, &u8); + + /* HID Virtual Cable */ + u8 = HID_DEV_VIRTUAL_CABLE; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_VIRTUAL_CABLE, BOOLEAN_DESC_TYPE, 1, &u8); + + /* HID reconnect initiate */ + u8 = HID_DEV_RECONN_INITIATE; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_RECONNECT_INITIATE, BOOLEAN_DESC_TYPE, 1, &u8); + + /* HID report descriptor */ + if ( NULL != (pRepDescriptor = (UINT8 *)GKI_getbuf((UINT16)(p_sdp_info->dscp_info.dl_len + 8 ))) ) + { + pd = pRepDescriptor; + *pd++ = (UINT8)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + *pd++ = (UINT8)(p_sdp_info->dscp_info.dl_len + 4); + *pd++ = (UINT8)((UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); + *pd++ = (UINT8)(HID_SDP_DESCRIPTOR_REPORT); + *pd++ = (UINT8)((TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + *pd++ = (UINT8)(p_sdp_info->dscp_info.dl_len); + memcpy (pd, p_sdp_info->dscp_info.dsc_list, p_sdp_info->dscp_info.dl_len); + pd += p_sdp_info->dscp_info.dl_len; + + SDP_AddAttribute (sdp_handle, ATTR_ID_HID_DESCRIPTOR_LIST, DATA_ELE_SEQ_DESC_TYPE, + (UINT32)(pd - pRepDescriptor), pRepDescriptor); + GKI_freebuf( pRepDescriptor ); + } + else + { + SDP_DeleteRecord( sdp_handle ); /* delete freshly allocated record */ + HIDD_TRACE_ERROR1( "HID_DevSetSDPRecord(): SDP creation failed: no memory for rep dscr len: %d", + p_sdp_info->dscp_info.dl_len ); + return 0; + } + /* HID language base list */ + SDP_AddAttribute (sdp_handle, ATTR_ID_HID_LANGUAGE_ID_BASE, DATA_ELE_SEQ_DESC_TYPE, + sizeof (HidDevLangList), (UINT8 *)HidDevLangList); + + /* HID SDP disable (i.e. SDP while Control and Interrupt are up) */ +#if (MAX_L2CAP_CHANNELS > 2) + u8 = 0; +#else + u8 = 1; +#endif + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_SDP_DISABLE, BOOLEAN_DESC_TYPE, 1, &u8); + +#if defined(HID_DEV_BATTERY_POW) + /* HID battery power */ + u8 = HID_DEV_BATTERY_POW; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_BATTERY_POWER, BOOLEAN_DESC_TYPE, 1, &u8); +#endif + +#if defined(HID_DEV_REMOTE_WAKE) + /* HID remote wakeup capable */ + u8 = HID_DEV_REMOTE_WAKE; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_REMOTE_WAKE, BOOLEAN_DESC_TYPE, 1, &u8); +#endif + + /* Link supervision timeout */ + UINT16_TO_BE_FIELD(buf,HID_DEV_LINK_SUPERVISION_TO) ; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_LINK_SUPERVISION_TO, UINT_DESC_TYPE, 2, (UINT8 *)buf); + + /* HID remote wakeup capable */ + u8 = HID_DEV_NORMALLY_CONN; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_NORMALLY_CONNECTABLE, BOOLEAN_DESC_TYPE, 1, &u8); + + /* HID BOOT Device */ + u8 = HID_DEV_BOOT_DEVICE; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_BOOT_DEVICE, BOOLEAN_DESC_TYPE, 1, &u8); + + u16 = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &u16); + + /* SSR host max latency */ + if (p_sdp_info->ssr_max_latency != HID_SSR_PARAM_INVALID) + { + UINT16_TO_BE_FIELD(buf,HID_DEV_LINK_SUPERVISION_TO) ; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_SSR_HOST_MAX_LAT, UINT_DESC_TYPE, 2, (UINT8 *)buf); + } + + /* SSR host min timeout */ + if (p_sdp_info->ssr_max_latency != HID_SSR_PARAM_INVALID) + { + UINT16_TO_BE_FIELD(buf,HID_DEV_LINK_SUPERVISION_TO) ; + SDP_AddAttribute(sdp_handle, ATTR_ID_HID_SSR_HOST_MIN_TOUT, UINT_DESC_TYPE, 2, (UINT8 *)buf); + } + return (sdp_handle); +} + +/******************************************************************************* +** +** Function HID_DevInit +** +** Description This function initializes the control block and trace variable +** +** Returns void +** +*******************************************************************************/ +void HID_DevInit (void) +{ + memset(&hd_cb, 0, sizeof(tHIDDEV_CB)); + + /* Initialize control channel L2CAP configuration */ + hd_cb.l2cap_ctrl_cfg.mtu_present = TRUE; + hd_cb.l2cap_ctrl_cfg.mtu = HID_DEV_MTU_SIZE; + + /* Initialize interrupt channel L2CAP configuration */ + hd_cb.l2cap_int_cfg.mtu_present = TRUE; + hd_cb.l2cap_int_cfg.mtu = HID_DEV_MTU_SIZE; + + hd_cb.conn.timer_entry.param = (UINT32) hidd_proc_repage_timeout; +#if defined(HID_INITIAL_TRACE_LEVEL) + hd_cb.trace_level = HID_INITIAL_TRACE_LEVEL; +#else + hd_cb.trace_level = BT_TRACE_LEVEL_NONE; +#endif +} + +/******************************************************************************* +** +** Function HID_DevRegister +** +** Description This function must be called at startup so the device receive +** HID related events and call other HID API Calls. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevRegister( tHID_DEV_REG_INFO *p_reg_info ) +{ + tHID_STATUS st; + BD_ADDR bt_bd_any = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + UINT16 conn_able; + + if( p_reg_info == NULL || + p_reg_info->app_cback == NULL ) + return HID_ERR_INVALID_PARAM; + + if( hd_cb.reg_flag ) + return HID_ERR_ALREADY_REGISTERED; + + /* Check if the host address is provided */ + if( memcmp( p_reg_info->host_addr, bt_bd_any, BD_ADDR_LEN ) ) + { + hd_cb.host_known = TRUE; + memcpy( hd_cb.host_addr, p_reg_info->host_addr, BD_ADDR_LEN ); + hd_cb.dev_state = HID_DEV_ST_NO_CONN ; + + /* When host address is provided, connectibility is determined by the + SDP attribute, otherwise device has to be connectable for initial + pairing process with the host */ + conn_able = (UINT16) HID_DEV_NORMALLY_CONN; + } + else + { + hd_cb.host_known = FALSE; + conn_able = BTM_CONNECTABLE; + } + + hd_cb.virtual_cable = HID_DEV_VIRTUAL_CABLE; + + /* Copy QoS parameters if provided */ + if( p_reg_info->qos_info ) + { + memcpy( &(hd_cb.qos_info), p_reg_info->qos_info, sizeof( tHID_DEV_QOS_INFO ) ); + hd_cb.use_qos_flg = TRUE; + } + else + { + hd_cb.use_qos_flg = FALSE; + } + + hd_cb.callback = p_reg_info->app_cback ; + + /* Register with L2CAP */ + if( (st = hidd_conn_reg()) != HID_SUCCESS ) + { + return st; + } + +#if (!defined(HID_DEV_SET_CONN_MODE) || HID_DEV_SET_CONN_MODE == TRUE) + if( BTM_SetConnectability (conn_able, HID_DEV_PAGE_SCAN_WIN, HID_DEV_PAGE_SCAN_INT) != BTM_SUCCESS ) + return HID_ERR_SET_CONNABLE_FAIL ; +#endif + + hd_cb.reg_flag = TRUE; + hd_cb.unplug_on = FALSE; + + HIDD_TRACE_DEBUG0 ("HID_DevRegister successful"); + return HID_SUCCESS; +} + +/******************************************************************************* +** +** Function HID_DevDeregister +** +** Description This function may be used to remove HID service records and +** deregister from L2CAP. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevDeregister( void ) +{ + if( !hd_cb.reg_flag ) + return HID_ERR_NOT_REGISTERED; + + hidd_mgmt_process_evt( HID_API_DISCONNECT, NULL ) ; /* Disconnect first */ + /* Deregister with L2CAP */ + hidd_conn_dereg() ; + hd_cb.reg_flag = FALSE; + return HID_SUCCESS; +} + +/******************************************************************************* +** +** Function HID_DevConnect +** +** Description This function may be used to initiate a connection to the host.. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevConnect( void ) +{ + if( hd_cb.reg_flag == FALSE ) + return HID_ERR_NOT_REGISTERED; + + return hidd_mgmt_process_evt( HID_API_CONNECT, NULL ) ; /* This will initiate connection */ +} + +/******************************************************************************* +** +** Function HID_DevDisconnect +** +** Description This function may be used to disconnect from the host +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevDisconnect( void ) +{ + if( hd_cb.reg_flag == FALSE ) + return HID_ERR_NOT_REGISTERED; + + return hidd_mgmt_process_evt( HID_API_DISCONNECT, NULL ) ; /* This will initiate disconnection */ +} + +/******************************************************************************* +** +** Function HID_DevHandShake +** +** Description This function may be used to send HAND-SHAKE to host +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevHandShake( UINT8 res_code ) +{ + tHID_SND_DATA_PARAMS hsk_data; + + if( hd_cb.reg_flag == FALSE ) + return HID_ERR_NOT_REGISTERED; + + hsk_data.trans_type = HID_TRANS_HANDSHAKE ; + hsk_data.ctrl_ch = TRUE ; + hsk_data.param = res_code; + hsk_data.buf = NULL; + + return hidd_mgmt_process_evt( HID_API_SEND_DATA, &hsk_data ) ; +} + +/******************************************************************************* +** +** Function HID_DevVirtualUnplug +** +** Description This function may be used to send VIRTUAL-UNPLUG to host +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevVirtualUnplug ( void ) +{ + tHID_STATUS st; + + tHID_SND_DATA_PARAMS vup_data; + + if( hd_cb.reg_flag == FALSE ) + return HID_ERR_NOT_REGISTERED; + + vup_data.trans_type = HID_TRANS_CONTROL ; + vup_data.ctrl_ch = TRUE ; + vup_data.param = HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG; + vup_data.buf = NULL; + + if( (st = hidd_mgmt_process_evt(HID_API_SEND_DATA, &vup_data)) == HID_SUCCESS ) + { + hd_cb.unplug_on = TRUE; + } + + return st; +} + +/******************************************************************************* +** +** Function HID_DevSendData +** +** Description This function may be used to send input reports to host +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevSendData ( BOOLEAN control_ch, UINT8 rep_type, BT_HDR *data_buf ) +{ + tHID_SND_DATA_PARAMS snd_data; + + WC_ASSERT(control_ch != TRUE && control_ch != FALSE); + + if( hd_cb.reg_flag == FALSE ) + return HID_ERR_NOT_REGISTERED; + + snd_data.trans_type = HID_TRANS_DATA ; + snd_data.ctrl_ch = control_ch ; + snd_data.param = rep_type; + snd_data.buf = data_buf; + + return hidd_mgmt_process_evt( HID_API_SEND_DATA, &snd_data ) ; +} + +/******************************************************************************* +** +** Function HID_DevSetSecurityLevel +** +** Description This function set security level for the Hid Device service. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevSetSecurityLevel( char serv_name[], UINT8 sec_lvl ) +{ + hd_cb.sec_mask = sec_lvl; + + if (sec_lvl == 0) + { + if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL, + BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID , HIDD_NOSEC_CHN)) + { + HIDD_TRACE_ERROR0 ("Security Registration 1 failed"); + return (HID_ERR_NO_RESOURCES); + } + if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL, + BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN)) + { + HIDD_TRACE_ERROR0 ("Security Registration 2 failed"); + return (HID_ERR_NO_RESOURCES); + } + } + else + { + /* Register with Security Manager for the specific security level */ + if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL, + sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) + { + HIDD_TRACE_ERROR0 ("Security Registration 3 failed"); + return (HID_ERR_NO_RESOURCES); + } + if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL, + sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) + { + HIDD_TRACE_ERROR0 ("Security Registration 4 failed"); + return (HID_ERR_NO_RESOURCES); + } + } + + /* Register with Security Manager for the specific security level for interupt channel*/ + if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_INTR, + BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) + { + HIDD_TRACE_ERROR0 ("Security Registration 5 failed"); + return (HID_ERR_NO_RESOURCES); + } + + if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_INTR, + BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) + { + HIDD_TRACE_ERROR0 ("Security Registration 6 failed"); + return (HID_ERR_NO_RESOURCES); + } + + return HID_SUCCESS; +} + +#if HID_DEV_PM_INCLUDED == TRUE +/******************************************************************************* +** +** Function HID_DevSetPowerMgmtParams +** +** Description This function may be used to change power mgmt parameters. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +tHID_STATUS HID_DevSetPowerMgmtParams( UINT8 conn_substate, tHID_DEV_PM_PWR_MD pm_params ) +{ + if( conn_substate > HID_DEV_SUSP_CONN_ST ) + return (HID_ERR_INVALID_PARAM); + + memcpy( &hd_cb.pm_params[conn_substate], &pm_params, sizeof( tHID_DEV_PM_PWR_MD ) ) ; + + /* Set the power mode to new parameters if currently in that state */ + if( conn_substate == hd_cb.conn_substate ) + hidd_pm_set_power_mode ( &(hd_cb.pm_params[conn_substate]) ); + + return (HID_SUCCESS); +} + +#endif + |