Home | History | Annotate | Download | only in hw
      1 /*
      2  * QEMU Bluetooth HID Profile wrapper for USB HID.
      3  *
      4  * Copyright (C) 2007-2008 OpenMoko, Inc.
      5  * Written by Andrzej Zaborowski <andrew (at) openedhand.com>
      6  *
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License as
      9  * published by the Free Software Foundation; either version 2 or
     10  * (at your option) version 3 of the License.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  * GNU General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, if not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 #include "qemu-common.h"
     22 #include "usb.h"
     23 #include "bt.h"
     24 
     25 enum hid_transaction_req {
     26     BT_HANDSHAKE			= 0x0,
     27     BT_HID_CONTROL			= 0x1,
     28     BT_GET_REPORT			= 0x4,
     29     BT_SET_REPORT			= 0x5,
     30     BT_GET_PROTOCOL			= 0x6,
     31     BT_SET_PROTOCOL			= 0x7,
     32     BT_GET_IDLE				= 0x8,
     33     BT_SET_IDLE				= 0x9,
     34     BT_DATA				= 0xa,
     35     BT_DATC				= 0xb,
     36 };
     37 
     38 enum hid_transaction_handshake {
     39     BT_HS_SUCCESSFUL			= 0x0,
     40     BT_HS_NOT_READY			= 0x1,
     41     BT_HS_ERR_INVALID_REPORT_ID		= 0x2,
     42     BT_HS_ERR_UNSUPPORTED_REQUEST	= 0x3,
     43     BT_HS_ERR_INVALID_PARAMETER		= 0x4,
     44     BT_HS_ERR_UNKNOWN			= 0xe,
     45     BT_HS_ERR_FATAL			= 0xf,
     46 };
     47 
     48 enum hid_transaction_control {
     49     BT_HC_NOP				= 0x0,
     50     BT_HC_HARD_RESET			= 0x1,
     51     BT_HC_SOFT_RESET			= 0x2,
     52     BT_HC_SUSPEND			= 0x3,
     53     BT_HC_EXIT_SUSPEND			= 0x4,
     54     BT_HC_VIRTUAL_CABLE_UNPLUG		= 0x5,
     55 };
     56 
     57 enum hid_protocol {
     58     BT_HID_PROTO_BOOT			= 0,
     59     BT_HID_PROTO_REPORT			= 1,
     60 };
     61 
     62 enum hid_boot_reportid {
     63     BT_HID_BOOT_INVALID			= 0,
     64     BT_HID_BOOT_KEYBOARD,
     65     BT_HID_BOOT_MOUSE,
     66 };
     67 
     68 enum hid_data_pkt {
     69     BT_DATA_OTHER			= 0,
     70     BT_DATA_INPUT,
     71     BT_DATA_OUTPUT,
     72     BT_DATA_FEATURE,
     73 };
     74 
     75 #define BT_HID_MTU			48
     76 
     77 /* HID interface requests */
     78 #define GET_REPORT			0xa101
     79 #define GET_IDLE			0xa102
     80 #define GET_PROTOCOL			0xa103
     81 #define SET_REPORT			0x2109
     82 #define SET_IDLE			0x210a
     83 #define SET_PROTOCOL			0x210b
     84 
     85 struct bt_hid_device_s {
     86     struct bt_l2cap_device_s btdev;
     87     struct bt_l2cap_conn_params_s *control;
     88     struct bt_l2cap_conn_params_s *interrupt;
     89     USBDevice *usbdev;
     90 
     91     int proto;
     92     int connected;
     93     int data_type;
     94     int intr_state;
     95     struct {
     96         int len;
     97         uint8_t buffer[1024];
     98     } dataother, datain, dataout, feature, intrdataout;
     99     enum {
    100         bt_state_ready,
    101         bt_state_transaction,
    102         bt_state_suspend,
    103     } state;
    104 };
    105 
    106 static void bt_hid_reset(struct bt_hid_device_s *s)
    107 {
    108     struct bt_scatternet_s *net = s->btdev.device.net;
    109 
    110     /* Go as far as... */
    111     bt_l2cap_device_done(&s->btdev);
    112     bt_l2cap_device_init(&s->btdev, net);
    113 
    114     s->usbdev->handle_reset(s->usbdev);
    115     s->proto = BT_HID_PROTO_REPORT;
    116     s->state = bt_state_ready;
    117     s->dataother.len = 0;
    118     s->datain.len = 0;
    119     s->dataout.len = 0;
    120     s->feature.len = 0;
    121     s->intrdataout.len = 0;
    122     s->intr_state = 0;
    123 }
    124 
    125 static int bt_hid_out(struct bt_hid_device_s *s)
    126 {
    127     USBPacket p;
    128 
    129     if (s->data_type == BT_DATA_OUTPUT) {
    130         p.pid = USB_TOKEN_OUT;
    131         p.devep = 1;
    132         p.data = s->dataout.buffer;
    133         p.len = s->dataout.len;
    134         s->dataout.len = s->usbdev->handle_data(s->usbdev, &p);
    135 
    136         return s->dataout.len;
    137     }
    138 
    139     if (s->data_type == BT_DATA_FEATURE) {
    140         /* XXX:
    141          * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
    142          * or a SET_REPORT? */
    143         p.devep = 0;
    144     }
    145 
    146     return -1;
    147 }
    148 
    149 static int bt_hid_in(struct bt_hid_device_s *s)
    150 {
    151     USBPacket p;
    152 
    153     p.pid = USB_TOKEN_IN;
    154     p.devep = 1;
    155     p.data = s->datain.buffer;
    156     p.len = sizeof(s->datain.buffer);
    157     s->datain.len = s->usbdev->handle_data(s->usbdev, &p);
    158 
    159     return s->datain.len;
    160 }
    161 
    162 static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
    163 {
    164     *s->control->sdu_out(s->control, 1) =
    165             (BT_HANDSHAKE << 4) | result;
    166     s->control->sdu_submit(s->control);
    167 }
    168 
    169 static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
    170 {
    171     *s->control->sdu_out(s->control, 1) =
    172             (BT_HID_CONTROL << 4) | operation;
    173     s->control->sdu_submit(s->control);
    174 }
    175 
    176 static void bt_hid_disconnect(struct bt_hid_device_s *s)
    177 {
    178     /* Disconnect s->control and s->interrupt */
    179 }
    180 
    181 static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
    182                 const uint8_t *data, int len)
    183 {
    184     uint8_t *pkt, hdr = (BT_DATA << 4) | type;
    185     int plen;
    186 
    187     do {
    188         plen = MIN(len, ch->remote_mtu - 1);
    189         pkt = ch->sdu_out(ch, plen + 1);
    190 
    191         pkt[0] = hdr;
    192         if (plen)
    193             memcpy(pkt + 1, data, plen);
    194         ch->sdu_submit(ch);
    195 
    196         len -= plen;
    197         data += plen;
    198         hdr = (BT_DATC << 4) | type;
    199     } while (plen == ch->remote_mtu - 1);
    200 }
    201 
    202 static void bt_hid_control_transaction(struct bt_hid_device_s *s,
    203                 const uint8_t *data, int len)
    204 {
    205     uint8_t type, parameter;
    206     int rlen, ret = -1;
    207     if (len < 1)
    208         return;
    209 
    210     type = data[0] >> 4;
    211     parameter = data[0] & 0xf;
    212 
    213     switch (type) {
    214     case BT_HANDSHAKE:
    215     case BT_DATA:
    216         switch (parameter) {
    217         default:
    218             /* These are not expected to be sent this direction.  */
    219             ret = BT_HS_ERR_INVALID_PARAMETER;
    220         }
    221         break;
    222 
    223     case BT_HID_CONTROL:
    224         if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
    225                                 s->state == bt_state_transaction)) {
    226             ret = BT_HS_ERR_INVALID_PARAMETER;
    227             break;
    228         }
    229         switch (parameter) {
    230         case BT_HC_NOP:
    231             break;
    232         case BT_HC_HARD_RESET:
    233         case BT_HC_SOFT_RESET:
    234             bt_hid_reset(s);
    235             break;
    236         case BT_HC_SUSPEND:
    237             if (s->state == bt_state_ready)
    238                 s->state = bt_state_suspend;
    239             else
    240                 ret = BT_HS_ERR_INVALID_PARAMETER;
    241             break;
    242         case BT_HC_EXIT_SUSPEND:
    243             if (s->state == bt_state_suspend)
    244                 s->state = bt_state_ready;
    245             else
    246                 ret = BT_HS_ERR_INVALID_PARAMETER;
    247             break;
    248         case BT_HC_VIRTUAL_CABLE_UNPLUG:
    249             bt_hid_disconnect(s);
    250             break;
    251         default:
    252             ret = BT_HS_ERR_INVALID_PARAMETER;
    253         }
    254         break;
    255 
    256     case BT_GET_REPORT:
    257         /* No ReportIDs declared.  */
    258         if (((parameter & 8) && len != 3) ||
    259                         (!(parameter & 8) && len != 1) ||
    260                         s->state != bt_state_ready) {
    261             ret = BT_HS_ERR_INVALID_PARAMETER;
    262             break;
    263         }
    264         if (parameter & 8)
    265             rlen = data[2] | (data[3] << 8);
    266         else
    267             rlen = INT_MAX;
    268         switch (parameter & 3) {
    269         case BT_DATA_OTHER:
    270             ret = BT_HS_ERR_INVALID_PARAMETER;
    271             break;
    272         case BT_DATA_INPUT:
    273             /* Here we can as well poll s->usbdev */
    274             bt_hid_send_data(s->control, BT_DATA_INPUT,
    275                             s->datain.buffer, MIN(rlen, s->datain.len));
    276             break;
    277         case BT_DATA_OUTPUT:
    278             bt_hid_send_data(s->control, BT_DATA_OUTPUT,
    279                             s->dataout.buffer, MIN(rlen, s->dataout.len));
    280             break;
    281         case BT_DATA_FEATURE:
    282             bt_hid_send_data(s->control, BT_DATA_FEATURE,
    283                             s->feature.buffer, MIN(rlen, s->feature.len));
    284             break;
    285         }
    286         break;
    287 
    288     case BT_SET_REPORT:
    289         if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
    290                         (parameter & 3) == BT_DATA_OTHER ||
    291                         (parameter & 3) == BT_DATA_INPUT) {
    292             ret = BT_HS_ERR_INVALID_PARAMETER;
    293             break;
    294         }
    295         s->data_type = parameter & 3;
    296         if (s->data_type == BT_DATA_OUTPUT) {
    297             s->dataout.len = len - 1;
    298             memcpy(s->dataout.buffer, data + 1, s->dataout.len);
    299         } else {
    300             s->feature.len = len - 1;
    301             memcpy(s->feature.buffer, data + 1, s->feature.len);
    302         }
    303         if (len == BT_HID_MTU)
    304             s->state = bt_state_transaction;
    305         else
    306             bt_hid_out(s);
    307         break;
    308 
    309     case BT_GET_PROTOCOL:
    310         if (len != 1 || s->state == bt_state_transaction) {
    311             ret = BT_HS_ERR_INVALID_PARAMETER;
    312             break;
    313         }
    314         *s->control->sdu_out(s->control, 1) = s->proto;
    315         s->control->sdu_submit(s->control);
    316         break;
    317 
    318     case BT_SET_PROTOCOL:
    319         if (len != 1 || s->state == bt_state_transaction ||
    320                         (parameter != BT_HID_PROTO_BOOT &&
    321                          parameter != BT_HID_PROTO_REPORT)) {
    322             ret = BT_HS_ERR_INVALID_PARAMETER;
    323             break;
    324         }
    325         s->proto = parameter;
    326         s->usbdev->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
    327                                   NULL);
    328         ret = BT_HS_SUCCESSFUL;
    329         break;
    330 
    331     case BT_GET_IDLE:
    332         if (len != 1 || s->state == bt_state_transaction) {
    333             ret = BT_HS_ERR_INVALID_PARAMETER;
    334             break;
    335         }
    336         s->usbdev->handle_control(s->usbdev, GET_IDLE, 0, 0, 1,
    337                         s->control->sdu_out(s->control, 1));
    338         s->control->sdu_submit(s->control);
    339         break;
    340 
    341     case BT_SET_IDLE:
    342         if (len != 2 || s->state == bt_state_transaction) {
    343             ret = BT_HS_ERR_INVALID_PARAMETER;
    344             break;
    345         }
    346 
    347         /* We don't need to know about the Idle Rate here really,
    348          * so just pass it on to the device.  */
    349         ret = s->usbdev->handle_control(s->usbdev,
    350                         SET_IDLE, data[1], 0, 0, NULL) ?
    351                 BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
    352         /* XXX: Does this generate a handshake? */
    353         break;
    354 
    355     case BT_DATC:
    356         if (len > BT_HID_MTU || s->state != bt_state_transaction) {
    357             ret = BT_HS_ERR_INVALID_PARAMETER;
    358             break;
    359         }
    360         if (s->data_type == BT_DATA_OUTPUT) {
    361             memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
    362             s->dataout.len += len - 1;
    363         } else {
    364             memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
    365             s->feature.len += len - 1;
    366         }
    367         if (len < BT_HID_MTU) {
    368             bt_hid_out(s);
    369             s->state = bt_state_ready;
    370         }
    371         break;
    372 
    373     default:
    374         ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
    375     }
    376 
    377     if (ret != -1)
    378         bt_hid_send_handshake(s, ret);
    379 }
    380 
    381 static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
    382 {
    383     struct bt_hid_device_s *hid = opaque;
    384 
    385     bt_hid_control_transaction(hid, data, len);
    386 }
    387 
    388 static void bt_hid_datain(void *opaque)
    389 {
    390     struct bt_hid_device_s *hid = opaque;
    391 
    392     /* If suspended, wake-up and send a wake-up event first.  We might
    393      * want to also inspect the input report and ignore event like
    394      * mouse movements until a button event occurs.  */
    395     if (hid->state == bt_state_suspend) {
    396         hid->state = bt_state_ready;
    397     }
    398 
    399     if (bt_hid_in(hid) > 0)
    400         /* TODO: when in boot-mode precede any Input reports with the ReportID
    401          * byte, here and in GetReport/SetReport on the Control channel.  */
    402         bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
    403                         hid->datain.buffer, hid->datain.len);
    404 }
    405 
    406 static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
    407 {
    408     struct bt_hid_device_s *hid = opaque;
    409 
    410     if (len > BT_HID_MTU || len < 1)
    411         goto bad;
    412     if ((data[0] & 3) != BT_DATA_OUTPUT)
    413         goto bad;
    414     if ((data[0] >> 4) == BT_DATA) {
    415         if (hid->intr_state)
    416             goto bad;
    417 
    418         hid->data_type = BT_DATA_OUTPUT;
    419         hid->intrdataout.len = 0;
    420     } else if ((data[0] >> 4) == BT_DATC) {
    421         if (!hid->intr_state)
    422             goto bad;
    423     } else
    424         goto bad;
    425 
    426     memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
    427     hid->intrdataout.len += len - 1;
    428     hid->intr_state = (len == BT_HID_MTU);
    429     if (!hid->intr_state) {
    430         memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
    431                         hid->dataout.len = hid->intrdataout.len);
    432         bt_hid_out(hid);
    433     }
    434 
    435     return;
    436 bad:
    437     fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
    438                     __FUNCTION__);
    439 }
    440 
    441 /* "Virtual cable" plug/unplug event.  */
    442 static void bt_hid_connected_update(struct bt_hid_device_s *hid)
    443 {
    444     int prev = hid->connected;
    445 
    446     hid->connected = hid->control && hid->interrupt;
    447 
    448     /* Stop page-/inquiry-scanning when a host is connected.  */
    449     hid->btdev.device.page_scan = !hid->connected;
    450     hid->btdev.device.inquiry_scan = !hid->connected;
    451 
    452     if (hid->connected && !prev) {
    453         hid->usbdev->handle_reset(hid->usbdev);
    454         hid->proto = BT_HID_PROTO_REPORT;
    455     }
    456 
    457     /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
    458      * isn't destroyed yet, in case we're being called from handle_destroy) */
    459 }
    460 
    461 static void bt_hid_close_control(void *opaque)
    462 {
    463     struct bt_hid_device_s *hid = opaque;
    464 
    465     hid->control = NULL;
    466     bt_hid_connected_update(hid);
    467 }
    468 
    469 static void bt_hid_close_interrupt(void *opaque)
    470 {
    471     struct bt_hid_device_s *hid = opaque;
    472 
    473     hid->interrupt = NULL;
    474     bt_hid_connected_update(hid);
    475 }
    476 
    477 static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
    478                 struct bt_l2cap_conn_params_s *params)
    479 {
    480     struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
    481 
    482     if (hid->control)
    483         return 1;
    484 
    485     hid->control = params;
    486     hid->control->opaque = hid;
    487     hid->control->close = bt_hid_close_control;
    488     hid->control->sdu_in = bt_hid_control_sdu;
    489 
    490     bt_hid_connected_update(hid);
    491 
    492     return 0;
    493 }
    494 
    495 static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
    496                 struct bt_l2cap_conn_params_s *params)
    497 {
    498     struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
    499 
    500     if (hid->interrupt)
    501         return 1;
    502 
    503     hid->interrupt = params;
    504     hid->interrupt->opaque = hid;
    505     hid->interrupt->close = bt_hid_close_interrupt;
    506     hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
    507 
    508     bt_hid_connected_update(hid);
    509 
    510     return 0;
    511 }
    512 
    513 static void bt_hid_destroy(struct bt_device_s *dev)
    514 {
    515     struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
    516 
    517     if (hid->connected)
    518         bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
    519     bt_l2cap_device_done(&hid->btdev);
    520 
    521     hid->usbdev->handle_destroy(hid->usbdev);
    522 
    523     qemu_free(hid);
    524 }
    525 
    526 enum peripheral_minor_class {
    527     class_other		= 0 << 4,
    528     class_keyboard	= 1 << 4,
    529     class_pointing	= 2 << 4,
    530     class_combo		= 3 << 4,
    531 };
    532 
    533 static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
    534                 USBDevice *dev, enum peripheral_minor_class minor)
    535 {
    536     struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
    537     uint32_t class =
    538             /* Format type */
    539             (0 << 0) |
    540             /* Device class */
    541             (minor << 2) |
    542             (5 << 8) |  /* "Peripheral" */
    543             /* Service classes */
    544             (1 << 13) | /* Limited discoverable mode */
    545             (1 << 19);  /* Capturing device (?) */
    546 
    547     bt_l2cap_device_init(&s->btdev, net);
    548     bt_l2cap_sdp_init(&s->btdev);
    549     bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
    550                     BT_HID_MTU, bt_hid_new_control_ch);
    551     bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
    552                     BT_HID_MTU, bt_hid_new_interrupt_ch);
    553 
    554     s->usbdev = dev;
    555     s->btdev.device.lmp_name = s->usbdev->devname;
    556     usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
    557 
    558     s->btdev.device.handle_destroy = bt_hid_destroy;
    559 
    560     s->btdev.device.class[0] = (class >>  0) & 0xff;
    561     s->btdev.device.class[1] = (class >>  8) & 0xff;
    562     s->btdev.device.class[2] = (class >> 16) & 0xff;
    563 
    564     return &s->btdev.device;
    565 }
    566 
    567 struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
    568 {
    569     return bt_hid_init(net, usb_keyboard_init(), class_keyboard);
    570 }
    571