Home | History | Annotate | Download | only in co
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 //#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
     20 
     21 #include <ctype.h>
     22 #include <fcntl.h>
     23 #include <sys/poll.h>
     24 #include <pthread.h>
     25 #include <stdio.h>
     26 #include <string.h>
     27 #include <stdint.h>
     28 #include <errno.h>
     29 #include <linux/uhid.h>
     30 #include "btif_hh.h"
     31 #include "bta_api.h"
     32 #include "bta_hh_api.h"
     33 
     34 
     35 
     36 const char *dev_path = "/dev/uhid";
     37 
     38 
     39 /*Internal function to perform UHID write and error checking*/
     40 static int uhid_write(int fd, const struct uhid_event *ev)
     41 {
     42     ssize_t ret;
     43     ret = write(fd, ev, sizeof(*ev));
     44     if (ret < 0){
     45         int rtn = -errno;
     46         APPL_TRACE_ERROR2("%s: Cannot write to uhid:%s", __FUNCTION__, strerror(errno));
     47         return rtn;
     48     } else if (ret != sizeof(*ev)) {
     49         APPL_TRACE_ERROR3("%s: Wrong size written to uhid: %ld != %lu",
     50                                                     __FUNCTION__, ret, sizeof(*ev));
     51         return -EFAULT;
     52     } else {
     53         return 0;
     54     }
     55 }
     56 
     57 /* Internal function to parse the events received from UHID driver*/
     58 static int uhid_event(btif_hh_device_t *p_dev)
     59 {
     60     struct uhid_event ev;
     61     ssize_t ret;
     62     memset(&ev, 0, sizeof(ev));
     63     if(!p_dev)
     64     {
     65         APPL_TRACE_ERROR1("%s: Device not found",__FUNCTION__)
     66         return -1;
     67     }
     68     ret = read(p_dev->fd, &ev, sizeof(ev));
     69     if (ret == 0) {
     70         APPL_TRACE_ERROR2("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
     71                                                  strerror(errno));
     72         return -EFAULT;
     73     } else if (ret < 0) {
     74         APPL_TRACE_ERROR2("%s:Cannot read uhid-cdev: %s", __FUNCTION__,
     75                                                 strerror(errno));
     76         return -errno;
     77     } else if (ret != sizeof(ev)) {
     78         APPL_TRACE_ERROR3("%s:Invalid size read from uhid-dev: %ld != %lu",
     79                             __FUNCTION__, ret, sizeof(ev));
     80         return -EFAULT;
     81     }
     82 
     83     switch (ev.type) {
     84     case UHID_START:
     85         APPL_TRACE_DEBUG0("UHID_START from uhid-dev\n");
     86         break;
     87     case UHID_STOP:
     88         APPL_TRACE_DEBUG0("UHID_STOP from uhid-dev\n");
     89         break;
     90     case UHID_OPEN:
     91         APPL_TRACE_DEBUG0("UHID_OPEN from uhid-dev\n");
     92         break;
     93     case UHID_CLOSE:
     94         APPL_TRACE_DEBUG0("UHID_CLOSE from uhid-dev\n");
     95         break;
     96     case UHID_OUTPUT:
     97         APPL_TRACE_DEBUG2("UHID_OUTPUT: Report type = %d, report_size = %d"
     98                             ,ev.u.output.rtype, ev.u.output.size);
     99         //Send SET_REPORT with feature report if the report type in output event is FEATURE
    100         if(ev.u.output.rtype == UHID_FEATURE_REPORT)
    101             btif_hh_setreport(p_dev,BTHH_FEATURE_REPORT,ev.u.output.size,ev.u.output.data);
    102         else if(ev.u.output.rtype == UHID_OUTPUT_REPORT)
    103             btif_hh_setreport(p_dev,BTHH_OUTPUT_REPORT,ev.u.output.size,ev.u.output.data);
    104         else
    105             btif_hh_setreport(p_dev,BTHH_INPUT_REPORT,ev.u.output.size,ev.u.output.data);
    106            break;
    107     case UHID_OUTPUT_EV:
    108         APPL_TRACE_DEBUG0("UHID_OUTPUT_EV from uhid-dev\n");
    109         break;
    110     case UHID_FEATURE:
    111         APPL_TRACE_DEBUG0("UHID_FEATURE from uhid-dev\n");
    112         break;
    113     case UHID_FEATURE_ANSWER:
    114         APPL_TRACE_DEBUG0("UHID_FEATURE_ANSWER from uhid-dev\n");
    115         break;
    116 
    117     default:
    118         APPL_TRACE_DEBUG1("Invalid event from uhid-dev: %u\n", ev.type);
    119     }
    120 
    121     return 0;
    122 }
    123 
    124 /*******************************************************************************
    125 **
    126 ** Function create_thread
    127 **
    128 ** Description creat a select loop
    129 **
    130 ** Returns pthread_t
    131 **
    132 *******************************************************************************/
    133 static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg){
    134     APPL_TRACE_DEBUG0("create_thread: entered");
    135     pthread_attr_t thread_attr;
    136 
    137     pthread_attr_init(&thread_attr);
    138     pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
    139     pthread_t thread_id = -1;
    140     if ( pthread_create(&thread_id, &thread_attr, start_routine, arg)!=0 )
    141     {
    142         APPL_TRACE_ERROR1("pthread_create : %s", strerror(errno));
    143         return -1;
    144     }
    145     APPL_TRACE_DEBUG0("create_thread: thread created successfully");
    146     return thread_id;
    147 }
    148 
    149 /*******************************************************************************
    150 **
    151 ** Function btif_hh_poll_event_thread
    152 **
    153 ** Description the polling thread which polls for event from UHID driver
    154 **
    155 ** Returns void
    156 **
    157 *******************************************************************************/
    158 static void *btif_hh_poll_event_thread(void *arg)
    159 {
    160 
    161     btif_hh_device_t *p_dev = arg;
    162     APPL_TRACE_DEBUG2("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
    163     struct pollfd pfds[1];
    164     int ret;
    165     pfds[0].fd = p_dev->fd;
    166     pfds[0].events = POLLIN;
    167 
    168     while(p_dev->hh_keep_polling){
    169         ret = poll(pfds, 1, 500);
    170         if (ret < 0) {
    171             APPL_TRACE_ERROR2("%s: Cannot poll for fds: %s\n", __FUNCTION__, strerror(errno));
    172             break;
    173         }
    174         if (pfds[0].revents & POLLIN) {
    175             APPL_TRACE_DEBUG0("btif_hh_poll_event_thread: POLLIN");
    176             ret = uhid_event(p_dev);
    177             if (ret){
    178                 break;
    179             }
    180         }
    181     }
    182 
    183     p_dev->hh_poll_thread_id = -1;
    184     return 0;
    185 }
    186 
    187 static inline void btif_hh_close_poll_thread(btif_hh_device_t *p_dev)
    188 {
    189     APPL_TRACE_DEBUG1("%s", __FUNCTION__);
    190     p_dev->hh_keep_polling = 0;
    191     if(p_dev->hh_poll_thread_id > 0)
    192         pthread_join(p_dev->hh_poll_thread_id,NULL);
    193 
    194     return;
    195 }
    196 
    197 void bta_hh_co_destroy(int fd)
    198 {
    199     struct uhid_event ev;
    200     memset(&ev, 0, sizeof(ev));
    201     ev.type = UHID_DESTROY;
    202     uhid_write(fd, &ev);
    203     close(fd);
    204 }
    205 
    206 int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
    207 {
    208     APPL_TRACE_DEBUG0("bta_hh_co_data: UHID write");
    209     struct uhid_event ev;
    210     memset(&ev, 0, sizeof(ev));
    211     ev.type = UHID_INPUT;
    212     ev.u.input.size = len;
    213     if(len > sizeof(ev.u.input.data)){
    214         APPL_TRACE_WARNING1("%s:report size greater than allowed size",__FUNCTION__);
    215         return -1;
    216     }
    217     memcpy(ev.u.input.data, rpt, len);
    218     return uhid_write(fd, &ev);
    219 
    220 }
    221 
    222 
    223 /*******************************************************************************
    224 **
    225 ** Function      bta_hh_co_open
    226 **
    227 ** Description   When connection is opened, this call-out function is executed
    228 **               by HH to do platform specific initialization.
    229 **
    230 ** Returns       void.
    231 *******************************************************************************/
    232 void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask,
    233                     UINT8 app_id)
    234 {
    235     UINT32 i;
    236     btif_hh_device_t *p_dev = NULL;
    237 
    238     if (dev_handle == BTA_HH_INVALID_HANDLE) {
    239         APPL_TRACE_WARNING2("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
    240         return;
    241     }
    242 
    243     for (i = 0; i < BTIF_HH_MAX_HID; i++) {
    244         p_dev = &btif_hh_cb.devices[i];
    245         if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
    246             // We found a device with the same handle. Must be a device reconnected.
    247             APPL_TRACE_WARNING2("%s: Found an existing device with the same handle "
    248                                                                 "dev_status = %d",__FUNCTION__,
    249                                                                 p_dev->dev_status);
    250             APPL_TRACE_WARNING6("%s:     bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
    251                  p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
    252                  p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
    253                  APPL_TRACE_WARNING4("%s:     attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
    254                                   __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
    255 
    256             if(p_dev->fd<0) {
    257                 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
    258                 if (p_dev->fd < 0){
    259                     APPL_TRACE_ERROR2("%s: Error: failed to open uhid, err:%s",
    260                                                                     __FUNCTION__,strerror(errno));
    261                 }else
    262                     APPL_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
    263             }
    264             p_dev->hh_keep_polling = 1;
    265             p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
    266             break;
    267         }
    268         p_dev = NULL;
    269     }
    270 
    271     if (p_dev == NULL) {
    272         // Did not find a device reconnection case. Find an empty slot now.
    273         for (i = 0; i < BTIF_HH_MAX_HID; i++) {
    274             if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
    275                 p_dev = &btif_hh_cb.devices[i];
    276                 p_dev->dev_handle = dev_handle;
    277                 p_dev->attr_mask  = attr_mask;
    278                 p_dev->sub_class  = sub_class;
    279                 p_dev->app_id     = app_id;
    280                 p_dev->local_vup  = FALSE;
    281 
    282                 btif_hh_cb.device_num++;
    283                 // This is a new device,open the uhid driver now.
    284                 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
    285                 if (p_dev->fd < 0){
    286                     APPL_TRACE_ERROR2("%s: Error: failed to open uhid, err:%s",
    287                                                                     __FUNCTION__,strerror(errno));
    288                 }else{
    289                     APPL_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
    290                     p_dev->hh_keep_polling = 1;
    291                     p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
    292                 }
    293 
    294 
    295                 break;
    296             }
    297         }
    298     }
    299 
    300     if (p_dev == NULL) {
    301         APPL_TRACE_ERROR1("%s: Error: too many HID devices are connected", __FUNCTION__);
    302         return;
    303     }
    304 
    305     p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
    306     APPL_TRACE_DEBUG2("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
    307 }
    308 
    309 
    310 /*******************************************************************************
    311 **
    312 ** Function      bta_hh_co_close
    313 **
    314 ** Description   When connection is closed, this call-out function is executed
    315 **               by HH to do platform specific finalization.
    316 **
    317 ** Parameters    dev_handle  - device handle
    318 **                  app_id      - application id
    319 **
    320 ** Returns          void.
    321 *******************************************************************************/
    322 void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id)
    323 {
    324     UINT32 i;
    325     btif_hh_device_t *p_dev = NULL;
    326 
    327     APPL_TRACE_WARNING3("%s: dev_handle = %d, app_id = %d", __FUNCTION__, dev_handle, app_id);
    328     if (dev_handle == BTA_HH_INVALID_HANDLE) {
    329         APPL_TRACE_WARNING2("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
    330         return;
    331     }
    332 
    333     for (i = 0; i < BTIF_HH_MAX_HID; i++) {
    334         p_dev = &btif_hh_cb.devices[i];
    335         if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
    336             APPL_TRACE_WARNING3("%s: Found an existing device with the same handle "
    337                                                         "dev_status = %d, dev_handle =%d"
    338                                                         ,__FUNCTION__,p_dev->dev_status
    339                                                         ,p_dev->dev_handle);
    340             btif_hh_close_poll_thread(p_dev);
    341             break;
    342         }
    343      }
    344 
    345 }
    346 
    347 
    348 /*******************************************************************************
    349 **
    350 ** Function         bta_hh_co_data
    351 **
    352 ** Description      This function is executed by BTA when HID host receive a data
    353 **                  report.
    354 **
    355 ** Parameters       dev_handle  - device handle
    356 **                  *p_rpt      - pointer to the report data
    357 **                  len         - length of report data
    358 **                  mode        - Hid host Protocol Mode
    359 **                  sub_clas    - Device Subclass
    360 **                  app_id      - application id
    361 **
    362 ** Returns          void
    363 *******************************************************************************/
    364 void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode,
    365                     UINT8 sub_class, UINT8 ctry_code, BD_ADDR peer_addr, UINT8 app_id)
    366 {
    367     btif_hh_device_t *p_dev;
    368 
    369     APPL_TRACE_DEBUG6("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
    370          "ctry_code = %d, app_id = %d",
    371          __FUNCTION__, dev_handle, sub_class, mode, ctry_code, app_id);
    372 
    373     p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
    374     if (p_dev == NULL) {
    375         APPL_TRACE_WARNING2("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle);
    376         return;
    377     }
    378     // Send the HID report to the kernel.
    379     if (p_dev->fd >= 0) {
    380         bta_hh_co_write(p_dev->fd, p_rpt, len);
    381     }else {
    382         APPL_TRACE_WARNING3("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len);
    383     }
    384 }
    385 
    386 
    387 /*******************************************************************************
    388 **
    389 ** Function         bta_hh_co_send_hid_info
    390 **
    391 ** Description      This function is called in btif_hh.c to process DSCP received.
    392 **
    393 ** Parameters       dev_handle  - device handle
    394 **                  dscp_len    - report descriptor length
    395 **                  *p_dscp     - report descriptor
    396 **
    397 ** Returns          void
    398 *******************************************************************************/
    399 void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 vendor_id,
    400                              UINT16 product_id, UINT16 version, UINT8 ctry_code,
    401                              int dscp_len, UINT8 *p_dscp)
    402 {
    403     int result;
    404     struct uhid_event ev;
    405 
    406     if (p_dev->fd < 0) {
    407         APPL_TRACE_WARNING3("%s: Error: fd = %d, dscp_len = %d", __FUNCTION__, p_dev->fd, dscp_len);
    408         return;
    409     }
    410 
    411     APPL_TRACE_WARNING4("%s: fd = %d, name = [%s], dscp_len = %d", __FUNCTION__,
    412                                                                     p_dev->fd, dev_name, dscp_len);
    413     APPL_TRACE_WARNING5("%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
    414                                                                     "ctry_code=0x%02x",__FUNCTION__,
    415                                                                     vendor_id, product_id,
    416                                                                     version, ctry_code);
    417 
    418 //Create and send hid descriptor to kernel
    419     memset(&ev, 0, sizeof(ev));
    420     ev.type = UHID_CREATE;
    421     strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
    422     ev.u.create.rd_size = dscp_len;
    423     ev.u.create.rd_data = p_dscp;
    424     ev.u.create.bus = BUS_BLUETOOTH;
    425     ev.u.create.vendor = vendor_id;
    426     ev.u.create.product = product_id;
    427     ev.u.create.version = version;
    428     ev.u.create.country = ctry_code;
    429     result = uhid_write(p_dev->fd, &ev);
    430 
    431     APPL_TRACE_WARNING4("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
    432                                                                     p_dev->fd, dscp_len, result);
    433 
    434     if (result) {
    435         APPL_TRACE_WARNING2("%s: Error: failed to send DSCP, result = %d", __FUNCTION__, result);
    436 
    437         /* The HID report descriptor is corrupted. Close the driver. */
    438         close(p_dev->fd);
    439         p_dev->fd = -1;
    440     }
    441 }
    442 
    443 
    444