• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2016 The Android Open Source Project
4  *  Copyright 2002-2012 Broadcom Corporation
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at:
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  ******************************************************************************/
19 
20 /******************************************************************************
21  *
22  *  This file contains the HID Device API entry points
23  *
24  ******************************************************************************/
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "bt_types.h"
31 #include "btm_api.h"
32 #include "btu.h"
33 #include "hidd_api.h"
34 #include "hidd_int.h"
35 #include "hiddefs.h"
36 #include "stack/btm/btm_sec.h"
37 
38 tHID_DEV_CTB hd_cb;
39 
40 /*******************************************************************************
41  *
42  * Function         HID_DevInit
43  *
44  * Description      Initializes control block
45  *
46  * Returns          void
47  *
48  ******************************************************************************/
HID_DevInit(void)49 void HID_DevInit(void) {
50   uint8_t log_level = hd_cb.trace_level;
51 
52   HIDD_TRACE_API("%s", __func__);
53 
54   memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
55   hd_cb.trace_level = log_level;
56 }
57 
58 /*******************************************************************************
59  *
60  * Function         HID_DevSetTraceLevel
61  *
62  * Description      This function sets the trace level for HID Dev. If called
63 *with
64  *                  a value of 0xFF, it simply reads the current trace level.
65  *
66  * Returns          the new (current) trace level
67  *
68  ******************************************************************************/
HID_DevSetTraceLevel(uint8_t new_level)69 uint8_t HID_DevSetTraceLevel(uint8_t new_level) {
70   if (new_level != 0xFF) hd_cb.trace_level = new_level;
71 
72   return (hd_cb.trace_level);
73 }
74 
75 /*******************************************************************************
76  *
77  * Function         HID_DevRegister
78  *
79  * Description      Registers HID device with lower layers
80  *
81  * Returns          tHID_STATUS
82  *
83  ******************************************************************************/
HID_DevRegister(tHID_DEV_HOST_CALLBACK * host_cback)84 tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) {
85   tHID_STATUS st;
86 
87   HIDD_TRACE_API("%s", __func__);
88 
89   if (hd_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED;
90 
91   if (host_cback == NULL) return HID_ERR_INVALID_PARAM;
92 
93   /* Register with L2CAP */
94   st = hidd_conn_reg();
95   if (st != HID_SUCCESS) return st;
96 
97   hd_cb.callback = host_cback;
98   hd_cb.reg_flag = TRUE;
99 
100   if (hd_cb.pending_data) {
101     osi_free(hd_cb.pending_data);
102     hd_cb.pending_data = NULL;
103   }
104 
105   return (HID_SUCCESS);
106 }
107 
108 /*******************************************************************************
109  *
110  * Function         HID_DevDeregister
111  *
112  * Description      Deregisters HID device with lower layers
113  *
114  * Returns          tHID_STATUS
115  *
116  ******************************************************************************/
HID_DevDeregister(void)117 tHID_STATUS HID_DevDeregister(void) {
118   HIDD_TRACE_API("%s", __func__);
119 
120   if (!hd_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
121 
122   hidd_conn_dereg();
123 
124   hd_cb.reg_flag = FALSE;
125 
126   return (HID_SUCCESS);
127 }
128 
129 /*******************************************************************************
130  *
131  * Function         HID_DevAddRecord
132  *
133  * Description      Creates SDP record for HID device
134  *
135  * Returns          tHID_STATUS
136  *
137  ******************************************************************************/
HID_DevAddRecord(uint32_t handle,char * p_name,char * p_description,char * p_provider,uint16_t subclass,uint16_t desc_len,uint8_t * p_desc_data)138 tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description,
139                              char* p_provider, uint16_t subclass,
140                              uint16_t desc_len, uint8_t* p_desc_data) {
141   bool result = TRUE;
142 
143   HIDD_TRACE_API("%s", __func__);
144 
145   // Service Class ID List
146   if (result) {
147     uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
148     result &= SDP_AddServiceClassIdList(handle, 1, &uuid);
149   }
150 
151   // Protocol Descriptor List
152   if (result) {
153     tSDP_PROTOCOL_ELEM proto_list[2];
154 
155     proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
156     proto_list[0].num_params = 1;
157     proto_list[0].params[0] = BT_PSM_HIDC;
158 
159     proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
160     proto_list[1].num_params = 0;
161 
162     result &= SDP_AddProtocolList(handle, 2, proto_list);
163   }
164 
165   // Language Base Attribute ID List
166   if (result) {
167     result &= SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH,
168                                             LANG_ID_CHAR_ENCODE_UTF8,
169                                             LANGUAGE_BASE_ID);
170   }
171 
172   // Additional Protocol Descriptor List
173   if (result) {
174     tSDP_PROTO_LIST_ELEM add_proto_list;
175 
176     add_proto_list.num_elems = 2;
177     add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
178     add_proto_list.list_elem[0].num_params = 1;
179     add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI;
180     add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
181     add_proto_list.list_elem[1].num_params = 0;
182 
183     result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list);
184   }
185 
186   // Service Name (O)
187   // Service Description (O)
188   // Provider Name (O)
189   if (result) {
190     const char* srv_name = p_name;
191     const char* srv_desc = p_description;
192     const char* provider_name = p_provider;
193 
194     result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
195                                strlen(srv_name) + 1, (uint8_t*)srv_name);
196 
197     result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
198                                TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1,
199                                (uint8_t*)srv_desc);
200 
201     result &=
202         SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
203                          strlen(provider_name) + 1, (uint8_t*)provider_name);
204   }
205 
206   // Bluetooth Profile Descriptor List
207   if (result) {
208     const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
209     const uint16_t version = 0x0100;
210 
211     result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version);
212   }
213 
214   // HID Parser Version
215   if (result) {
216     uint8_t* p;
217     const uint16_t rel_num = 0x0100;
218     const uint16_t parser_version = 0x0111;
219     const uint16_t prof_ver = 0x0100;
220     const uint8_t dev_subclass = subclass;
221     const uint8_t country_code = 0x21;
222     const uint8_t bool_false = 0x00;
223     const uint8_t bool_true = 0x01;
224     uint16_t temp;
225 
226     p = (uint8_t*)&temp;
227     UINT16_TO_BE_STREAM(p, rel_num);
228     result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM,
229                                UINT_DESC_TYPE, 2, (uint8_t*)&temp);
230 
231     p = (uint8_t*)&temp;
232     UINT16_TO_BE_STREAM(p, parser_version);
233     result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION,
234                                UINT_DESC_TYPE, 2, (uint8_t*)&temp);
235 
236     result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS,
237                                UINT_DESC_TYPE, 1, (uint8_t*)&dev_subclass);
238 
239     result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE,
240                                1, (uint8_t*)&country_code);
241 
242     result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE,
243                                BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
244 
245     result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE,
246                                BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
247 
248     {
249       static uint8_t cdt = 0x22;
250       uint8_t* p_buf;
251       uint8_t seq_len = 4 + desc_len;
252 
253       if (desc_len > HIDD_APP_DESCRIPTOR_LEN) {
254         HIDD_TRACE_ERROR("%s: descriptor length = %d, larger than max %d",
255                          __func__, desc_len, HIDD_APP_DESCRIPTOR_LEN);
256         return HID_ERR_NOT_REGISTERED;
257       };
258 
259       p_buf = (uint8_t*)osi_malloc(HIDD_APP_DESCRIPTOR_LEN + 6);
260 
261       if (p_buf == NULL) {
262         HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ",
263                          __func__);
264         return HID_ERR_NOT_REGISTERED;
265       }
266 
267       p = p_buf;
268 
269       UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
270 
271       UINT8_TO_BE_STREAM(p, seq_len);
272 
273       UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
274       UINT8_TO_BE_STREAM(p, cdt);
275 
276       UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
277       UINT8_TO_BE_STREAM(p, desc_len);
278       ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
279 
280       result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST,
281                                  DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
282 
283       osi_free(p_buf);
284     }
285 
286     {
287       uint8_t lang_buf[8];
288       p = lang_buf;
289       uint8_t seq_len = 6;
290       uint16_t lang_english = 0x0409;
291       UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
292       UINT8_TO_BE_STREAM(p, seq_len);
293       UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
294       UINT16_TO_BE_STREAM(p, lang_english);
295       UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
296       UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID);
297       result &=
298           SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE,
299                            DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf);
300     }
301 
302     result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER,
303                                BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
304 
305     result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE,
306                                BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_false);
307 
308     result &= SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE,
309                                BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
310 
311     result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE,
312                                BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
313 
314     p = (uint8_t*)&temp;
315     UINT16_TO_BE_STREAM(p, prof_ver);
316     result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION,
317                                UINT_DESC_TYPE, 2, (uint8_t*)&temp);
318   }
319 
320   if (result) {
321     uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
322     result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
323                                   &browse_group);
324   }
325 
326   if (!result) {
327     HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__);
328 
329     return HID_ERR_NOT_REGISTERED;
330   }
331 
332   return HID_SUCCESS;
333 }
334 
335 /*******************************************************************************
336  *
337  * Function         HID_DevSendReport
338  *
339  * Description      Sends report
340  *
341  * Returns          tHID_STATUS
342  *
343  ******************************************************************************/
HID_DevSendReport(uint8_t channel,uint8_t type,uint8_t id,uint16_t len,uint8_t * p_data)344 tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
345                               uint16_t len, uint8_t* p_data) {
346   HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel,
347                      type, id, len);
348 
349   if (channel == HID_CHANNEL_CTRL) {
350     return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len,
351                                p_data);
352   }
353 
354   if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) {
355     // on INTR we can only send INPUT
356     return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA,
357                                HID_PAR_REP_TYPE_INPUT, id, len, p_data);
358   }
359 
360   return HID_ERR_INVALID_PARAM;
361 }
362 
363 /*******************************************************************************
364  *
365  * Function         HID_DevVirtualCableUnplug
366  *
367  * Description      Sends Virtual Cable Unplug
368  *
369  * Returns          tHID_STATUS
370  *
371  ******************************************************************************/
HID_DevVirtualCableUnplug(void)372 tHID_STATUS HID_DevVirtualCableUnplug(void) {
373   HIDD_TRACE_API("%s", __func__);
374 
375   return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL,
376                              HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL);
377 }
378 
379 /*******************************************************************************
380  *
381  * Function         HID_DevPlugDevice
382  *
383  * Description      Establishes virtual cable to given host
384  *
385  * Returns          tHID_STATUS
386  *
387  ******************************************************************************/
HID_DevPlugDevice(const RawAddress & addr)388 tHID_STATUS HID_DevPlugDevice(const RawAddress& addr) {
389   hd_cb.device.in_use = TRUE;
390   hd_cb.device.addr = addr;
391 
392   return HID_SUCCESS;
393 }
394 
395 /*******************************************************************************
396  *
397  * Function         HID_DevUnplugDevice
398  *
399  * Description      Unplugs virtual cable from given host
400  *
401  * Returns          tHID_STATUS
402  *
403  ******************************************************************************/
HID_DevUnplugDevice(const RawAddress & addr)404 tHID_STATUS HID_DevUnplugDevice(const RawAddress& addr) {
405   if (hd_cb.device.addr == addr) {
406     hd_cb.device.in_use = FALSE;
407     hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
408     hd_cb.device.conn.ctrl_cid = 0;
409     hd_cb.device.conn.intr_cid = 0;
410   }
411 
412   return HID_SUCCESS;
413 }
414 
415 /*******************************************************************************
416  *
417  * Function         HID_DevConnect
418  *
419  * Description      Connects to device
420  *
421  * Returns          tHID_STATUS
422  *
423  ******************************************************************************/
HID_DevConnect(void)424 tHID_STATUS HID_DevConnect(void) {
425   if (!hd_cb.reg_flag) {
426     return HID_ERR_NOT_REGISTERED;
427   }
428 
429   if (!hd_cb.device.in_use) {
430     return HID_ERR_INVALID_PARAM;
431   }
432 
433   if (hd_cb.device.state != HIDD_DEV_NO_CONN) {
434     return HID_ERR_ALREADY_CONN;
435   }
436 
437   return hidd_conn_initiate();
438 }
439 
440 /*******************************************************************************
441  *
442  * Function         HID_DevDisconnect
443  *
444  * Description      Disconnects from device
445  *
446  * Returns          tHID_STATUS
447  *
448  ******************************************************************************/
HID_DevDisconnect(void)449 tHID_STATUS HID_DevDisconnect(void) {
450   if (!hd_cb.reg_flag) {
451     return HID_ERR_NOT_REGISTERED;
452   }
453 
454   if (!hd_cb.device.in_use) {
455     return HID_ERR_INVALID_PARAM;
456   }
457 
458   if (hd_cb.device.state == HIDD_DEV_NO_CONN) {
459     /* If we are still trying to connect, just close the connection. */
460     if (hd_cb.device.conn.conn_state != HID_CONN_STATE_UNUSED) {
461       tHID_STATUS ret = hidd_conn_disconnect();
462       hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
463       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
464                      HID_ERR_DISCONNECTING, NULL);
465       return ret;
466     }
467     return HID_ERR_NO_CONNECTION;
468   }
469 
470   return hidd_conn_disconnect();
471 }
472 
473 /*******************************************************************************
474  *
475  * Function         HID_DevSetIncomingPolicy
476  *
477  * Description      Sets policy for incoming connections (allowed/disallowed)
478  *
479  * Returns          tHID_STATUS
480  *
481  ******************************************************************************/
HID_DevSetIncomingPolicy(bool allow)482 tHID_STATUS HID_DevSetIncomingPolicy(bool allow) {
483   hd_cb.allow_incoming = allow;
484 
485   return HID_SUCCESS;
486 }
487 
488 /*******************************************************************************
489  *
490  * Function         HID_DevReportError
491  *
492  * Description      Reports error for Set Report via HANDSHAKE
493  *
494  * Returns          tHID_STATUS
495  *
496  ******************************************************************************/
HID_DevReportError(uint8_t error)497 tHID_STATUS HID_DevReportError(uint8_t error) {
498   uint8_t handshake_param;
499 
500   HIDD_TRACE_API("%s: error = %d", __func__, error);
501 
502   switch (error) {
503     case HID_PAR_HANDSHAKE_RSP_SUCCESS:
504     case HID_PAR_HANDSHAKE_RSP_NOT_READY:
505     case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:
506     case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:
507     case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:
508     case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:
509     case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:
510       handshake_param = error;
511       break;
512     default:
513       handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;
514       break;
515   }
516 
517   return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0,
518                              NULL);
519 }
520 
521 /*******************************************************************************
522  *
523  * Function         HID_DevGetDevice
524  *
525  * Description      Returns the BD Address of virtually cabled device
526  *
527  * Returns          tHID_STATUS
528  *
529  ******************************************************************************/
HID_DevGetDevice(RawAddress * addr)530 tHID_STATUS HID_DevGetDevice(RawAddress* addr) {
531   HIDD_TRACE_API("%s", __func__);
532 
533   if (hd_cb.device.in_use) {
534     *addr = hd_cb.device.addr;
535   } else {
536     return HID_ERR_NOT_REGISTERED;
537   }
538 
539   return HID_SUCCESS;
540 }
541 
542 /*******************************************************************************
543  *
544  * Function         HID_DevSetIncomingQos
545  *
546  * Description      Sets Incoming QoS values for Interrupt L2CAP Channel
547  *
548  * Returns          tHID_STATUS
549  *
550  ******************************************************************************/
HID_DevSetIncomingQos(uint8_t service_type,uint32_t token_rate,uint32_t token_bucket_size,uint32_t peak_bandwidth,uint32_t latency,uint32_t delay_variation)551 tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate,
552                                   uint32_t token_bucket_size,
553                                   uint32_t peak_bandwidth, uint32_t latency,
554                                   uint32_t delay_variation) {
555   HIDD_TRACE_API("%s", __func__);
556 
557   hd_cb.use_in_qos = TRUE;
558 
559   hd_cb.in_qos.service_type = service_type;
560   hd_cb.in_qos.token_rate = token_rate;
561   hd_cb.in_qos.token_bucket_size = token_bucket_size;
562   hd_cb.in_qos.peak_bandwidth = peak_bandwidth;
563   hd_cb.in_qos.latency = latency;
564   hd_cb.in_qos.delay_variation = delay_variation;
565 
566   return HID_SUCCESS;
567 }
568 
569 /*******************************************************************************
570  *
571  * Function         HID_DevSetOutgoingQos
572  *
573  * Description      Sets Outgoing QoS values for Interrupt L2CAP Channel
574  *
575  * Returns          tHID_STATUS
576  *
577  ******************************************************************************/
HID_DevSetOutgoingQos(uint8_t service_type,uint32_t token_rate,uint32_t token_bucket_size,uint32_t peak_bandwidth,uint32_t latency,uint32_t delay_variation)578 tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate,
579                                   uint32_t token_bucket_size,
580                                   uint32_t peak_bandwidth, uint32_t latency,
581                                   uint32_t delay_variation) {
582   HIDD_TRACE_API("%s", __func__);
583 
584   hd_cb.l2cap_intr_cfg.qos_present = TRUE;
585 
586   hd_cb.l2cap_intr_cfg.qos.service_type = service_type;
587   hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate;
588   hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size;
589   hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth;
590   hd_cb.l2cap_intr_cfg.qos.latency = latency;
591   hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation;
592 
593   return HID_SUCCESS;
594 }
595