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