xref: /btstack/src/classic/hid_device.c (revision c12110e4805594de2d144c60747af1ab2485db4f)
1d40c9ac6SMatthias Ringwald /*
2d40c9ac6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3d40c9ac6SMatthias Ringwald  *
4d40c9ac6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5d40c9ac6SMatthias Ringwald  * modification, are permitted provided that the following conditions
6d40c9ac6SMatthias Ringwald  * are met:
7d40c9ac6SMatthias Ringwald  *
8d40c9ac6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9d40c9ac6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10d40c9ac6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11d40c9ac6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12d40c9ac6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13d40c9ac6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14d40c9ac6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15d40c9ac6SMatthias Ringwald  *    from this software without specific prior written permission.
16d40c9ac6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17d40c9ac6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18d40c9ac6SMatthias Ringwald  *    monetary gain.
19d40c9ac6SMatthias Ringwald  *
20d40c9ac6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21d40c9ac6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22d40c9ac6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23d40c9ac6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24d40c9ac6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25d40c9ac6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26d40c9ac6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27d40c9ac6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28d40c9ac6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29d40c9ac6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30d40c9ac6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31d40c9ac6SMatthias Ringwald  * SUCH DAMAGE.
32d40c9ac6SMatthias Ringwald  *
33d40c9ac6SMatthias Ringwald  * Please inquire about commercial licensing options at
34d40c9ac6SMatthias Ringwald  * [email protected]
35d40c9ac6SMatthias Ringwald  *
36d40c9ac6SMatthias Ringwald  */
37d40c9ac6SMatthias Ringwald 
38d40c9ac6SMatthias Ringwald #define __BTSTACK_FILE__ "hid_device.c"
39d40c9ac6SMatthias Ringwald 
40d40c9ac6SMatthias Ringwald #include <string.h>
41d40c9ac6SMatthias Ringwald 
42d40c9ac6SMatthias Ringwald #include "classic/hid_device.h"
43d40c9ac6SMatthias Ringwald #include "classic/sdp_util.h"
44d40c9ac6SMatthias Ringwald #include "bluetooth.h"
45d40c9ac6SMatthias Ringwald #include "bluetooth_sdp.h"
468eb8d463SMatthias Ringwald #include "l2cap.h"
478eb8d463SMatthias Ringwald #include "btstack_event.h"
488eb8d463SMatthias Ringwald #include "btstack_debug.h"
498eb8d463SMatthias Ringwald 
50*c12110e4SMilanka Ringwald typedef enum {
51*c12110e4SMilanka Ringwald     HID_DEVICE_IDLE,
52*c12110e4SMilanka Ringwald     HID_DEVICE_CONNECTED,
53*c12110e4SMilanka Ringwald     HID_DEVICE_W2_SEND_REPORT,
54*c12110e4SMilanka Ringwald     HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST
55*c12110e4SMilanka Ringwald } hid_device_state_t;
56*c12110e4SMilanka Ringwald 
578eb8d463SMatthias Ringwald // hid device state
588eb8d463SMatthias Ringwald typedef struct hid_device {
598eb8d463SMatthias Ringwald     uint16_t  cid;
608eb8d463SMatthias Ringwald     bd_addr_t bd_addr;
618eb8d463SMatthias Ringwald     hci_con_handle_t con_handle;
628eb8d463SMatthias Ringwald     uint16_t  control_cid;
638eb8d463SMatthias Ringwald     uint16_t  interrupt_cid;
648eb8d463SMatthias Ringwald     uint8_t   incoming;
6557c643eeSMatthias Ringwald     uint8_t   connected;
66*c12110e4SMilanka Ringwald 
67*c12110e4SMilanka Ringwald     hid_device_state_t state;
68*c12110e4SMilanka Ringwald     hid_report_type_t report_type;
69*c12110e4SMilanka Ringwald     uint16_t          report_id;
708eb8d463SMatthias Ringwald } hid_device_t;
718eb8d463SMatthias Ringwald 
728eb8d463SMatthias Ringwald static hid_device_t _hid_device;
73*c12110e4SMilanka Ringwald 
74*c12110e4SMilanka Ringwald static void dummy_write_report(uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, uint8_t report_max_size, int * out_report_size, uint8_t * out_report){
75*c12110e4SMilanka Ringwald     UNUSED(hid_cid);
76*c12110e4SMilanka Ringwald     UNUSED(report_type);
77*c12110e4SMilanka Ringwald     UNUSED(report_id);
78*c12110e4SMilanka Ringwald     UNUSED(report_max_size);
79*c12110e4SMilanka Ringwald     UNUSED(out_report_size);
80*c12110e4SMilanka Ringwald     UNUSED(out_report);
81*c12110e4SMilanka Ringwald }
82*c12110e4SMilanka Ringwald 
83*c12110e4SMilanka Ringwald static void (*hci_device_write_report) (uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, uint8_t report_max_size, int * out_report_size, uint8_t * out_report) = dummy_write_report;
848eb8d463SMatthias Ringwald 
858eb8d463SMatthias Ringwald static btstack_packet_handler_t hid_callback;
86d40c9ac6SMatthias Ringwald 
87*c12110e4SMilanka Ringwald static uint16_t hid_device_cid = 0;
88*c12110e4SMilanka Ringwald 
89*c12110e4SMilanka Ringwald static uint16_t hid_device_get_next_cid(void){
90*c12110e4SMilanka Ringwald     hid_device_cid++;
91*c12110e4SMilanka Ringwald     if (!hid_device_cid){
92*c12110e4SMilanka Ringwald         hid_device_cid = 1;
93*c12110e4SMilanka Ringwald     }
94*c12110e4SMilanka Ringwald     return hid_device_cid;
95*c12110e4SMilanka Ringwald }
96*c12110e4SMilanka Ringwald 
97*c12110e4SMilanka Ringwald // TODO: store hid device connection into list
98*c12110e4SMilanka Ringwald static hid_device_t * hid_device_get_instance_for_cid(uint16_t cid){
99*c12110e4SMilanka Ringwald     // printf("control_cid 0x%02x, interrupt_cid 0x%02x, query_cid 0x%02x \n", _hid_device.control_cid,  _hid_device.interrupt_cid, cid);
100*c12110e4SMilanka Ringwald     if (_hid_device.cid == cid || _hid_device.control_cid == cid || _hid_device.interrupt_cid == cid){
101*c12110e4SMilanka Ringwald         return &_hid_device;
102*c12110e4SMilanka Ringwald     }
103*c12110e4SMilanka Ringwald     return NULL;
104*c12110e4SMilanka Ringwald }
105*c12110e4SMilanka Ringwald 
106*c12110e4SMilanka Ringwald static hid_device_t * hid_device_create_instance_for_con_handle(uint16_t con_handle){
107*c12110e4SMilanka Ringwald     UNUSED(con_handle);
108*c12110e4SMilanka Ringwald     return &_hid_device;
109*c12110e4SMilanka Ringwald }
110*c12110e4SMilanka Ringwald 
111*c12110e4SMilanka Ringwald static hid_device_t * hid_device_get_instance_for_con_handle(uint16_t con_handle){
112*c12110e4SMilanka Ringwald     UNUSED(con_handle);
113*c12110e4SMilanka Ringwald     return &_hid_device;
114*c12110e4SMilanka Ringwald }
115*c12110e4SMilanka Ringwald 
116*c12110e4SMilanka Ringwald static hid_device_t * hid_device_create_instance(void){
117*c12110e4SMilanka Ringwald     return &_hid_device;
118*c12110e4SMilanka Ringwald }
119*c12110e4SMilanka Ringwald 
120d40c9ac6SMatthias Ringwald void hid_create_sdp_record(
121d40c9ac6SMatthias Ringwald     uint8_t *service,
122d40c9ac6SMatthias Ringwald     uint32_t service_record_handle,
123d40c9ac6SMatthias Ringwald     uint16_t hid_device_subclass,
124d40c9ac6SMatthias Ringwald     uint8_t  hid_country_code,
125d40c9ac6SMatthias Ringwald     uint8_t  hid_virtual_cable,
126d40c9ac6SMatthias Ringwald     uint8_t  hid_reconnect_initiate,
127d40c9ac6SMatthias Ringwald     uint8_t  hid_boot_device,
128d40c9ac6SMatthias Ringwald     const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
129d40c9ac6SMatthias Ringwald     const char *device_name){
130d40c9ac6SMatthias Ringwald 
131d40c9ac6SMatthias Ringwald     uint8_t * attribute;
132d40c9ac6SMatthias Ringwald     de_create_sequence(service);
133d40c9ac6SMatthias Ringwald 
134d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
135d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
136d40c9ac6SMatthias Ringwald 
137d40c9ac6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
138d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
139d40c9ac6SMatthias Ringwald     {
140d40c9ac6SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
141d40c9ac6SMatthias Ringwald     }
142d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
143d40c9ac6SMatthias Ringwald 
144d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
145d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
146d40c9ac6SMatthias Ringwald     {
147d40c9ac6SMatthias Ringwald         uint8_t * l2cpProtocol = de_push_sequence(attribute);
148d40c9ac6SMatthias Ringwald         {
149d40c9ac6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
150d40c9ac6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_CONTROL);
151d40c9ac6SMatthias Ringwald         }
152d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, l2cpProtocol);
153d40c9ac6SMatthias Ringwald 
154d40c9ac6SMatthias Ringwald         uint8_t * hidProtocol = de_push_sequence(attribute);
155d40c9ac6SMatthias Ringwald         {
156d40c9ac6SMatthias Ringwald             de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
157d40c9ac6SMatthias Ringwald         }
158d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidProtocol);
159d40c9ac6SMatthias Ringwald     }
160d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
161d40c9ac6SMatthias Ringwald 
162d40c9ac6SMatthias Ringwald     // TODO?
163d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
164d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
165d40c9ac6SMatthias Ringwald     {
166d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
167d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
168d40c9ac6SMatthias Ringwald         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
169d40c9ac6SMatthias Ringwald     }
170d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
171d40c9ac6SMatthias Ringwald 
172d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS);
173d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
174d40c9ac6SMatthias Ringwald     {
175d40c9ac6SMatthias Ringwald         uint8_t * additionalDescriptorAttribute = de_push_sequence(attribute);
176d40c9ac6SMatthias Ringwald         {
177d40c9ac6SMatthias Ringwald             uint8_t * l2cpProtocol = de_push_sequence(additionalDescriptorAttribute);
178d40c9ac6SMatthias Ringwald             {
179d40c9ac6SMatthias Ringwald                 de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
180d40c9ac6SMatthias Ringwald                 de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, PSM_HID_INTERRUPT);
181d40c9ac6SMatthias Ringwald             }
182d40c9ac6SMatthias Ringwald             de_pop_sequence(additionalDescriptorAttribute, l2cpProtocol);
183d40c9ac6SMatthias Ringwald 
184d40c9ac6SMatthias Ringwald             uint8_t * hidProtocol = de_push_sequence(attribute);
185d40c9ac6SMatthias Ringwald             {
186d40c9ac6SMatthias Ringwald                 de_add_number(hidProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_HIDP);
187d40c9ac6SMatthias Ringwald             }
188d40c9ac6SMatthias Ringwald             de_pop_sequence(attribute, hidProtocol);
189d40c9ac6SMatthias Ringwald         }
190d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, additionalDescriptorAttribute);
191d40c9ac6SMatthias Ringwald     }
192d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
193d40c9ac6SMatthias Ringwald 
194d40c9ac6SMatthias Ringwald     // 0x0100 "ServiceName"
195d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
196d40c9ac6SMatthias Ringwald     de_add_data(service,  DE_STRING, strlen(device_name), (uint8_t *) device_name);
197d40c9ac6SMatthias Ringwald 
198d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
199d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
200d40c9ac6SMatthias Ringwald     {
201d40c9ac6SMatthias Ringwald         uint8_t * hidProfile = de_push_sequence(attribute);
202d40c9ac6SMatthias Ringwald         {
203d40c9ac6SMatthias Ringwald             de_add_number(hidProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
204d40c9ac6SMatthias Ringwald             de_add_number(hidProfile,  DE_UINT, DE_SIZE_16, 0x0101);    // Version 1.1
205d40c9ac6SMatthias Ringwald         }
206d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidProfile);
207d40c9ac6SMatthias Ringwald     }
208d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
209d40c9ac6SMatthias Ringwald 
210d40c9ac6SMatthias Ringwald     // Deprecated in v1.1.1
211d40c9ac6SMatthias Ringwald     // de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_RELEASE_NUMBER);
212d40c9ac6SMatthias Ringwald     // de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0101);
213d40c9ac6SMatthias Ringwald 
214d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_PARSER_VERSION);
215d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0111);  // v1.1.1
216d40c9ac6SMatthias Ringwald 
217d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DEVICE_SUBCLASS);
2189679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_8,  hid_device_subclass);
219d40c9ac6SMatthias Ringwald 
220d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_COUNTRY_CODE);
2219679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_8,  hid_country_code);
222d40c9ac6SMatthias Ringwald 
223d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_VIRTUAL_CABLE);
224d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_virtual_cable);
225d40c9ac6SMatthias Ringwald 
226d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_RECONNECT_INITIATE);
227d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_reconnect_initiate);
228d40c9ac6SMatthias Ringwald 
229d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST);
230d40c9ac6SMatthias Ringwald     attribute = de_push_sequence(service);
231d40c9ac6SMatthias Ringwald     {
232d40c9ac6SMatthias Ringwald         uint8_t* hidDescriptor = de_push_sequence(attribute);
233d40c9ac6SMatthias Ringwald         {
234d40c9ac6SMatthias Ringwald             de_add_number(hidDescriptor,  DE_UINT, DE_SIZE_8, 0x22);    // Report Descriptor
235d40c9ac6SMatthias Ringwald             de_add_data(hidDescriptor,  DE_STRING, hid_descriptor_size, (uint8_t *) hid_descriptor);
236d40c9ac6SMatthias Ringwald         }
237d40c9ac6SMatthias Ringwald         de_pop_sequence(attribute, hidDescriptor);
238d40c9ac6SMatthias Ringwald     }
239d40c9ac6SMatthias Ringwald     de_pop_sequence(service, attribute);
240d40c9ac6SMatthias Ringwald 
2419679ea81SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HIDLANGID_BASE_LIST);
2429679ea81SMatthias Ringwald     attribute = de_push_sequence(service);
2439679ea81SMatthias Ringwald     {
2449679ea81SMatthias Ringwald         uint8_t* hig_lang_base = de_push_sequence(attribute);
2459679ea81SMatthias Ringwald         {
2469679ea81SMatthias Ringwald             // see: http://www.usb.org/developers/docs/USB_LANGIDs.pdf
2479679ea81SMatthias Ringwald             de_add_number(hig_lang_base,  DE_UINT, DE_SIZE_16, 0x0409);    // HIDLANGID = English (US)
2489679ea81SMatthias Ringwald             de_add_number(hig_lang_base,  DE_UINT, DE_SIZE_16, 0x0100);    // HIDLanguageBase = 0x0100 default
2499679ea81SMatthias Ringwald         }
2509679ea81SMatthias Ringwald         de_pop_sequence(attribute, hig_lang_base);
2519679ea81SMatthias Ringwald     }
2529679ea81SMatthias Ringwald     de_pop_sequence(service, attribute);
2539679ea81SMatthias Ringwald 
254d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_HID_BOOT_DEVICE);
255d40c9ac6SMatthias Ringwald     de_add_number(service,  DE_BOOL, DE_SIZE_8,  hid_boot_device);
256d40c9ac6SMatthias Ringwald }
2578eb8d463SMatthias Ringwald 
2588eb8d463SMatthias Ringwald static inline void hid_device_emit_connected_event(hid_device_t * context, uint8_t status){
2598eb8d463SMatthias Ringwald     uint8_t event[15];
2608eb8d463SMatthias Ringwald     int pos = 0;
2618eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
2628eb8d463SMatthias Ringwald     pos++;  // skip len
2638eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CONNECTION_OPENED;
2648eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
2658eb8d463SMatthias Ringwald     pos+=2;
2668eb8d463SMatthias Ringwald     event[pos++] = status;
2678eb8d463SMatthias Ringwald     memcpy(&event[pos], context->bd_addr, 6);
2688eb8d463SMatthias Ringwald     pos += 6;
2698eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->con_handle);
2708eb8d463SMatthias Ringwald     pos += 2;
2718eb8d463SMatthias Ringwald     event[pos++] = context->incoming;
2728eb8d463SMatthias Ringwald     event[1] = pos - 2;
2738eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_connected_event size %u", pos);
2748eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
2758eb8d463SMatthias Ringwald }
2768eb8d463SMatthias Ringwald 
2778eb8d463SMatthias Ringwald static inline void hid_device_emit_connection_closed_event(hid_device_t * context){
2788eb8d463SMatthias Ringwald     uint8_t event[5];
2798eb8d463SMatthias Ringwald     int pos = 0;
2808eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
2818eb8d463SMatthias Ringwald     pos++;  // skip len
2828eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CONNECTION_CLOSED;
2838eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
2848eb8d463SMatthias Ringwald     pos+=2;
2858eb8d463SMatthias Ringwald     event[1] = pos - 2;
2868eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_connection_closed_event size %u", pos);
2878eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
2888eb8d463SMatthias Ringwald }
2898eb8d463SMatthias Ringwald 
2908eb8d463SMatthias Ringwald static inline void hid_device_emit_can_send_now_event(hid_device_t * context){
2918eb8d463SMatthias Ringwald     uint8_t event[5];
2928eb8d463SMatthias Ringwald     int pos = 0;
2938eb8d463SMatthias Ringwald     event[pos++] = HCI_EVENT_HID_META;
2948eb8d463SMatthias Ringwald     pos++;  // skip len
2958eb8d463SMatthias Ringwald     event[pos++] = HID_SUBEVENT_CAN_SEND_NOW;
2968eb8d463SMatthias Ringwald     little_endian_store_16(event,pos,context->cid);
2978eb8d463SMatthias Ringwald     pos+=2;
2988eb8d463SMatthias Ringwald     event[1] = pos - 2;
2998eb8d463SMatthias Ringwald     if (pos != sizeof(event)) log_error("hid_device_emit_can_send_now_event size %u", pos);
3008eb8d463SMatthias Ringwald     hid_callback(HCI_EVENT_PACKET, context->cid, &event[0], pos);
3018eb8d463SMatthias Ringwald }
3028eb8d463SMatthias Ringwald 
3038eb8d463SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t packet_size){
3048eb8d463SMatthias Ringwald     UNUSED(channel);
3058eb8d463SMatthias Ringwald     UNUSED(packet_size);
3068eb8d463SMatthias Ringwald     int connected_before;
30757c643eeSMatthias Ringwald     uint16_t psm;
30857c643eeSMatthias Ringwald     uint8_t status;
309*c12110e4SMilanka Ringwald     hid_device_t * device = NULL;
310*c12110e4SMilanka Ringwald     uint8_t report[20];
311*c12110e4SMilanka Ringwald     int report_size;
312*c12110e4SMilanka Ringwald 
3138eb8d463SMatthias Ringwald     switch (packet_type){
314*c12110e4SMilanka Ringwald         case L2CAP_DATA_PACKET:
315*c12110e4SMilanka Ringwald             device = hid_device_get_instance_for_cid(channel);
316*c12110e4SMilanka Ringwald             if (!device) {
317*c12110e4SMilanka Ringwald                 log_error("no device with cid 0x%02x", channel);
318*c12110e4SMilanka Ringwald                 return;
319*c12110e4SMilanka Ringwald             }
320*c12110e4SMilanka Ringwald             hid_message_type_t message_type = packet[0] >> 4;
321*c12110e4SMilanka Ringwald             switch (message_type){
322*c12110e4SMilanka Ringwald                 case HID_MESSAGE_TYPE_GET_REPORT:
323*c12110e4SMilanka Ringwald                     device->report_type = packet[0] & 0x0F;
324*c12110e4SMilanka Ringwald                     device->report_id = 0;
325*c12110e4SMilanka Ringwald                     if (packet_size == 2){
326*c12110e4SMilanka Ringwald                         device->report_id = packet[1];
327*c12110e4SMilanka Ringwald                     }
328*c12110e4SMilanka Ringwald                     device->state = HID_DEVICE_W2_SEND_REPORT;
329*c12110e4SMilanka Ringwald                     printf(" answer get report type %d report_type\n", device->report_type);
330*c12110e4SMilanka Ringwald                     l2cap_request_can_send_now_event(device->control_cid);
331*c12110e4SMilanka Ringwald                     break;
332*c12110e4SMilanka Ringwald                 default:
333*c12110e4SMilanka Ringwald                     printf("L2CAP_DATA_PACKET %d  \n", message_type);
334*c12110e4SMilanka Ringwald                     device->state = HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST;
335*c12110e4SMilanka Ringwald                     l2cap_request_can_send_now_event(device->control_cid);
336*c12110e4SMilanka Ringwald                     break;
337*c12110e4SMilanka Ringwald             }
338*c12110e4SMilanka Ringwald             break;
3398eb8d463SMatthias Ringwald         case HCI_EVENT_PACKET:
3408eb8d463SMatthias Ringwald             switch (packet[0]){
3418eb8d463SMatthias Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
3428eb8d463SMatthias Ringwald                     switch (l2cap_event_incoming_connection_get_psm(packet)){
3438eb8d463SMatthias Ringwald                         case PSM_HID_CONTROL:
3448eb8d463SMatthias Ringwald                         case PSM_HID_INTERRUPT:
345*c12110e4SMilanka Ringwald                             device = hid_device_create_instance_for_con_handle(l2cap_event_incoming_connection_get_handle(packet));
346*c12110e4SMilanka Ringwald                             if (!device) {
347*c12110e4SMilanka Ringwald                                 log_error("L2CAP_EVENT_INCOMING_CONNECTION, no hid device for con handle 0x%02x", l2cap_event_incoming_connection_get_handle(packet));
348*c12110e4SMilanka Ringwald                                 l2cap_decline_connection(channel);
349*c12110e4SMilanka Ringwald                                 break;
350*c12110e4SMilanka Ringwald                             }
351*c12110e4SMilanka Ringwald                             if (device->con_handle == 0 || l2cap_event_incoming_connection_get_handle(packet) == device->con_handle){
352*c12110e4SMilanka Ringwald                                 device->con_handle = l2cap_event_incoming_connection_get_handle(packet);
353*c12110e4SMilanka Ringwald                                 device->incoming = 1;
3548eb8d463SMatthias Ringwald                                 l2cap_accept_connection(channel);
3558eb8d463SMatthias Ringwald                             } else {
3568eb8d463SMatthias Ringwald                                 l2cap_decline_connection(channel);
357*c12110e4SMilanka Ringwald                                 log_error("L2CAP_EVENT_INCOMING_CONNECTION, decline connection for con handle 0x%02x", l2cap_event_incoming_connection_get_handle(packet));
3588eb8d463SMatthias Ringwald                             }
3598eb8d463SMatthias Ringwald                             break;
3608eb8d463SMatthias Ringwald                         default:
3618eb8d463SMatthias Ringwald                             l2cap_decline_connection(channel);
3628eb8d463SMatthias Ringwald                             break;
3638eb8d463SMatthias Ringwald                     }
3648eb8d463SMatthias Ringwald                     break;
3658eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
366*c12110e4SMilanka Ringwald                     device = hid_device_get_instance_for_con_handle(l2cap_event_channel_opened_get_handle(packet));
367*c12110e4SMilanka Ringwald                     if (!device) {
368*c12110e4SMilanka Ringwald                         log_error("L2CAP_EVENT_CHANNEL_OPENED, no hid device for local cid 0x%02x", l2cap_event_channel_opened_get_local_cid(packet));
369*c12110e4SMilanka Ringwald                         return;
370*c12110e4SMilanka Ringwald                     }
37157c643eeSMatthias Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
37257c643eeSMatthias Ringwald                     if (status) {
373*c12110e4SMilanka Ringwald                         if (device->incoming == 0){
37457c643eeSMatthias Ringwald                             // report error for outgoing connection
375*c12110e4SMilanka Ringwald                             hid_device_emit_connected_event(device, status);
37657c643eeSMatthias Ringwald                         }
37757c643eeSMatthias Ringwald                         return;
37857c643eeSMatthias Ringwald                     }
37957c643eeSMatthias Ringwald                     psm = l2cap_event_channel_opened_get_psm(packet);
380*c12110e4SMilanka Ringwald                     connected_before = device->connected;
38157c643eeSMatthias Ringwald                     switch (psm){
3828eb8d463SMatthias Ringwald                         case PSM_HID_CONTROL:
383*c12110e4SMilanka Ringwald                             device->control_cid = l2cap_event_channel_opened_get_local_cid(packet);
384*c12110e4SMilanka Ringwald                             log_info("HID Control opened, cid 0x%02x", device->control_cid);
3858eb8d463SMatthias Ringwald                             break;
3868eb8d463SMatthias Ringwald                         case PSM_HID_INTERRUPT:
387*c12110e4SMilanka Ringwald                             device->interrupt_cid = l2cap_event_channel_opened_get_local_cid(packet);
388*c12110e4SMilanka Ringwald                             log_info("HID Interrupt opened, cid 0x%02x", device->interrupt_cid);
3898eb8d463SMatthias Ringwald                             break;
3908eb8d463SMatthias Ringwald                         default:
3918eb8d463SMatthias Ringwald                             break;
3928eb8d463SMatthias Ringwald                     }
39357c643eeSMatthias Ringwald                     // connect HID Interrupt for outgoing
394*c12110e4SMilanka Ringwald                     if (device->incoming == 0 && psm == PSM_HID_CONTROL){
39557c643eeSMatthias Ringwald                         log_info("Create outgoing HID Interrupt");
396*c12110e4SMilanka Ringwald                         status = l2cap_create_channel(packet_handler, device->bd_addr, PSM_HID_INTERRUPT, 48, &device->interrupt_cid);
39757c643eeSMatthias Ringwald                         break;
39857c643eeSMatthias Ringwald                     }
399*c12110e4SMilanka Ringwald                     if (!connected_before && device->control_cid && device->interrupt_cid){
400*c12110e4SMilanka Ringwald                         device->connected = 1;
4018eb8d463SMatthias Ringwald                         log_info("HID Connected");
402*c12110e4SMilanka Ringwald                         hid_device_emit_connected_event(device, 0);
4038eb8d463SMatthias Ringwald                     }
4048eb8d463SMatthias Ringwald                     break;
4058eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
406*c12110e4SMilanka Ringwald                     device = hid_device_get_instance_for_cid(l2cap_event_channel_closed_get_local_cid(packet));
407*c12110e4SMilanka Ringwald                     if (!device) return;
408*c12110e4SMilanka Ringwald 
409*c12110e4SMilanka Ringwald                     device->incoming  = 0;
410*c12110e4SMilanka Ringwald                     device->connected = 0;
411*c12110e4SMilanka Ringwald                     connected_before = device->connected;
412*c12110e4SMilanka Ringwald                     if (l2cap_event_channel_closed_get_local_cid(packet) == device->control_cid){
4138eb8d463SMatthias Ringwald                         log_info("HID Control closed");
414*c12110e4SMilanka Ringwald                         device->control_cid = 0;
4158eb8d463SMatthias Ringwald                     }
416*c12110e4SMilanka Ringwald                     if (l2cap_event_channel_closed_get_local_cid(packet) == device->interrupt_cid){
4178eb8d463SMatthias Ringwald                         log_info("HID Interrupt closed");
418*c12110e4SMilanka Ringwald                         device->interrupt_cid = 0;
4198eb8d463SMatthias Ringwald                     }
420*c12110e4SMilanka Ringwald                     if (connected_before && !device->connected){
421*c12110e4SMilanka Ringwald                         device->con_handle = 0;
4228eb8d463SMatthias Ringwald                         log_info("HID Disconnected");
423*c12110e4SMilanka Ringwald                         hid_device_emit_connection_closed_event(device);
4248eb8d463SMatthias Ringwald                     }
4258eb8d463SMatthias Ringwald                     break;
4268eb8d463SMatthias Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
427*c12110e4SMilanka Ringwald 
428*c12110e4SMilanka Ringwald                     device = hid_device_get_instance_for_cid(l2cap_event_can_send_now_get_local_cid(packet));
429*c12110e4SMilanka Ringwald                     if (!device) return;
430*c12110e4SMilanka Ringwald                     switch (device->state){
431*c12110e4SMilanka Ringwald                         case HID_DEVICE_W2_SEND_REPORT:
432*c12110e4SMilanka Ringwald                             (*hci_device_write_report)(device->cid, device->report_type, device->report_id, (uint16_t) sizeof(report), &report_size, report );
433*c12110e4SMilanka Ringwald                             hid_device_send_control_message(device->cid, &report[0], report_size);
434*c12110e4SMilanka Ringwald                             break;
435*c12110e4SMilanka Ringwald                         case HID_DEVICE_W2_SEND_UNSUPPORTED_REQUEST:
436*c12110e4SMilanka Ringwald                             report[0] = (HID_MESSAGE_TYPE_HANDSHAKE << 4) | HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER;
437*c12110e4SMilanka Ringwald                             hid_device_send_control_message(device->cid, &report[0], report_size);
438*c12110e4SMilanka Ringwald                             break;
439*c12110e4SMilanka Ringwald                         default:
4408eb8d463SMatthias Ringwald                             log_info("HID Can send now, emit event");
441*c12110e4SMilanka Ringwald                             hid_device_emit_can_send_now_event(device);
442*c12110e4SMilanka Ringwald                             break;
443*c12110e4SMilanka Ringwald                     }
444*c12110e4SMilanka Ringwald                     device->state = HID_DEVICE_IDLE;
4458eb8d463SMatthias Ringwald                     break;
4468eb8d463SMatthias Ringwald                 default:
4478eb8d463SMatthias Ringwald                     break;
4488eb8d463SMatthias Ringwald             }
4498eb8d463SMatthias Ringwald             break;
4508eb8d463SMatthias Ringwald         default:
4518eb8d463SMatthias Ringwald             break;
4528eb8d463SMatthias Ringwald     }
4538eb8d463SMatthias Ringwald }
4548eb8d463SMatthias Ringwald 
4558eb8d463SMatthias Ringwald /**
4568eb8d463SMatthias Ringwald  * @brief Set up HID Device
4578eb8d463SMatthias Ringwald  */
4588eb8d463SMatthias Ringwald void hid_device_init(void){
45945a58b30SMatthias Ringwald     l2cap_register_service(packet_handler, PSM_HID_INTERRUPT, 100, LEVEL_2);
46045a58b30SMatthias Ringwald     l2cap_register_service(packet_handler, PSM_HID_CONTROL,   100, LEVEL_2);
4618eb8d463SMatthias Ringwald }
4628eb8d463SMatthias Ringwald 
4638eb8d463SMatthias Ringwald /**
4648eb8d463SMatthias Ringwald  * @brief Register callback for the HID Device client.
4658eb8d463SMatthias Ringwald  * @param callback
4668eb8d463SMatthias Ringwald  */
4678eb8d463SMatthias Ringwald void hid_device_register_packet_handler(btstack_packet_handler_t callback){
4688eb8d463SMatthias Ringwald     hid_callback = callback;
4698eb8d463SMatthias Ringwald }
4708eb8d463SMatthias Ringwald 
471*c12110e4SMilanka Ringwald 
472*c12110e4SMilanka Ringwald 
473*c12110e4SMilanka Ringwald void hid_device_register_report_request_callback(void (*callback) (uint16_t hid_cid, hid_report_type_t report_type, uint16_t report_id, uint8_t report_max_size, int * out_report_size, uint8_t * out_report)){
474*c12110e4SMilanka Ringwald     if (callback == NULL){
475*c12110e4SMilanka Ringwald         callback = dummy_write_report;
476*c12110e4SMilanka Ringwald     }
477*c12110e4SMilanka Ringwald     hci_device_write_report = callback;
478*c12110e4SMilanka Ringwald }
479*c12110e4SMilanka Ringwald 
480*c12110e4SMilanka Ringwald 
4818eb8d463SMatthias Ringwald /**
4828eb8d463SMatthias Ringwald  * @brief Request can send now event to send HID Report
4838eb8d463SMatthias Ringwald  * @param hid_cid
4848eb8d463SMatthias Ringwald  */
4858eb8d463SMatthias Ringwald void hid_device_request_can_send_now_event(uint16_t hid_cid){
486*c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
487*c12110e4SMilanka Ringwald     if (!hid_device || !hid_device->control_cid) return;
4888eb8d463SMatthias Ringwald     l2cap_request_can_send_now_event(hid_device->control_cid);
4898eb8d463SMatthias Ringwald }
4908eb8d463SMatthias Ringwald 
4918eb8d463SMatthias Ringwald /**
4928eb8d463SMatthias Ringwald  * @brief Send HID messageon interrupt channel
4938eb8d463SMatthias Ringwald  * @param hid_cid
4948eb8d463SMatthias Ringwald  */
4958eb8d463SMatthias Ringwald void hid_device_send_interrupt_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
496*c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
497*c12110e4SMilanka Ringwald     if (!hid_device || !hid_device->interrupt_cid) return;
4988eb8d463SMatthias Ringwald     l2cap_send(hid_device->interrupt_cid, (uint8_t*) message, message_len);
4998eb8d463SMatthias Ringwald }
5008eb8d463SMatthias Ringwald 
5018eb8d463SMatthias Ringwald /**
5028eb8d463SMatthias Ringwald  * @brief Send HID messageon control channel
5038eb8d463SMatthias Ringwald  * @param hid_cid
5048eb8d463SMatthias Ringwald  */
505*c12110e4SMilanka Ringwald void hid_device_send_control_message(uint16_t hid_cid, const uint8_t * message, uint16_t message_len){
506*c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_get_instance_for_cid(hid_cid);
507*c12110e4SMilanka Ringwald     if (!hid_device || !hid_device->control_cid) return;
5088eb8d463SMatthias Ringwald     l2cap_send(hid_device->control_cid, (uint8_t*) message, message_len);
5098eb8d463SMatthias Ringwald }
5108eb8d463SMatthias Ringwald 
51157c643eeSMatthias Ringwald /*
51257c643eeSMatthias Ringwald  * @brief Create HID connection to HID Host
51357c643eeSMatthias Ringwald  * @param addr
51457c643eeSMatthias Ringwald  * @param hid_cid to use for other commands
51557c643eeSMatthias Ringwald  * @result status
51657c643eeSMatthias Ringwald  */
51757c643eeSMatthias Ringwald uint8_t hid_device_connect(bd_addr_t addr, uint16_t * hid_cid){
518*c12110e4SMilanka Ringwald     hid_device_t * hid_device = hid_device_create_instance();
519*c12110e4SMilanka Ringwald     if (!hid_device){
520*c12110e4SMilanka Ringwald         log_error("hid_device_connect: could not create a hid device instace");
521*c12110e4SMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
522*c12110e4SMilanka Ringwald     }
52357c643eeSMatthias Ringwald     // assign hic_cid
524*c12110e4SMilanka Ringwald     *hid_cid = hid_device_get_next_cid();
52557c643eeSMatthias Ringwald 
52657c643eeSMatthias Ringwald     // store address
52757c643eeSMatthias Ringwald     memcpy(hid_device->bd_addr, addr, 6);
52857c643eeSMatthias Ringwald 
52957c643eeSMatthias Ringwald     // reset state
53057c643eeSMatthias Ringwald     hid_device->incoming      = 0;
53157c643eeSMatthias Ringwald     hid_device->connected     = 0;
53257c643eeSMatthias Ringwald     hid_device->control_cid   = 0;
53357c643eeSMatthias Ringwald     hid_device->interrupt_cid = 0;
53457c643eeSMatthias Ringwald 
53557c643eeSMatthias Ringwald     // create l2cap control using fixed HID L2CAP PSM
53657c643eeSMatthias Ringwald     log_info("Create outgoing HID Control");
53757c643eeSMatthias Ringwald     uint8_t status = l2cap_create_channel(packet_handler, hid_device->bd_addr, PSM_HID_CONTROL, 48, &hid_device->control_cid);
53857c643eeSMatthias Ringwald 
53957c643eeSMatthias Ringwald     return status;
54057c643eeSMatthias Ringwald }
541