qemu/hw/bt/hci-csr.c
<<
>>
Prefs
   1/*
   2 * Bluetooth serial HCI transport.
   3 * CSR41814 HCI with H4p vendor extensions.
   4 *
   5 * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
   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, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "qemu-common.h"
  23#include "chardev/char-serial.h"
  24#include "qemu/timer.h"
  25#include "qemu/bswap.h"
  26#include "hw/irq.h"
  27#include "sysemu/bt.h"
  28#include "hw/bt.h"
  29#include "qapi/error.h"
  30
  31struct csrhci_s {
  32    Chardev parent;
  33    int enable;
  34    qemu_irq *pins;
  35    int pin_state;
  36    int modem_state;
  37#define FIFO_LEN        4096
  38    int out_start;
  39    int out_len;
  40    int out_size;
  41    uint8_t outfifo[FIFO_LEN * 2];
  42    uint8_t inpkt[FIFO_LEN];
  43    enum {
  44        CSR_HDR_LEN,
  45        CSR_DATA_LEN,
  46        CSR_DATA
  47    } in_state;
  48    int in_len;
  49    int in_hdr;
  50    int in_needed;
  51    QEMUTimer *out_tm;
  52    int64_t baud_delay;
  53
  54    bdaddr_t bd_addr;
  55    struct HCIInfo *hci;
  56};
  57
  58#define TYPE_CHARDEV_HCI "chardev-hci"
  59#define HCI_CHARDEV(obj) OBJECT_CHECK(struct csrhci_s, (obj), TYPE_CHARDEV_HCI)
  60
  61/* H4+ packet types */
  62enum {
  63    H4_CMD_PKT   = 1,
  64    H4_ACL_PKT   = 2,
  65    H4_SCO_PKT   = 3,
  66    H4_EVT_PKT   = 4,
  67    H4_NEG_PKT   = 6,
  68    H4_ALIVE_PKT = 7,
  69};
  70
  71/* CSR41814 negotiation start magic packet */
  72static const uint8_t csrhci_neg_packet[] = {
  73    H4_NEG_PKT, 10,
  74    0x00, 0xa0, 0x01, 0x00, 0x00,
  75    0x4c, 0x00, 0x96, 0x00, 0x00,
  76};
  77
  78/* CSR41814 vendor-specific command OCFs */
  79enum {
  80    OCF_CSR_SEND_FIRMWARE = 0x000,
  81};
  82
  83static inline void csrhci_fifo_wake(struct csrhci_s *s)
  84{
  85    Chardev *chr = CHARDEV(s);
  86
  87    if (!s->enable || !s->out_len)
  88        return;
  89
  90    /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
  91    if (qemu_chr_be_can_write(chr)) {
  92        qemu_chr_be_write(chr, s->outfifo + s->out_start++, 1);
  93        s->out_len--;
  94        if (s->out_start >= s->out_size) {
  95            s->out_start = 0;
  96            s->out_size = FIFO_LEN;
  97        }
  98    }
  99
 100    if (s->out_len)
 101        timer_mod(s->out_tm, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->baud_delay);
 102}
 103
 104#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
 105static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
 106{
 107    int off = s->out_start + s->out_len;
 108
 109    /* TODO: do the padding here, i.e. align len */
 110    s->out_len += len;
 111
 112    if (off < FIFO_LEN) {
 113        if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) {
 114            fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
 115            exit(-1);
 116        }
 117        return s->outfifo + off;
 118    }
 119
 120    if (s->out_len > s->out_size) {
 121        fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
 122        exit(-1);
 123    }
 124
 125    return s->outfifo + off - s->out_size;
 126}
 127
 128static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
 129                int type, int len)
 130{
 131    uint8_t *ret = csrhci_out_packetz(s, len + 2);
 132
 133    *ret ++ = type;
 134    *ret ++ = len;
 135
 136    return ret;
 137}
 138
 139static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
 140                int evt, int len)
 141{
 142    uint8_t *ret = csrhci_out_packetz(s,
 143                    len + 1 + sizeof(struct hci_event_hdr));
 144
 145    *ret ++ = H4_EVT_PKT;
 146    ((struct hci_event_hdr *) ret)->evt = evt;
 147    ((struct hci_event_hdr *) ret)->plen = len;
 148
 149    return ret + sizeof(struct hci_event_hdr);
 150}
 151
 152static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf,
 153                uint8_t *data, int len)
 154{
 155    int offset;
 156    uint8_t *rpkt;
 157
 158    switch (ocf) {
 159    case OCF_CSR_SEND_FIRMWARE:
 160        /* Check if this is the bd_address packet */
 161        if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) {
 162            offset = 18;
 163            s->bd_addr.b[0] = data[offset + 7]; /* Beyond cmd packet end(!?) */
 164            s->bd_addr.b[1] = data[offset + 6];
 165            s->bd_addr.b[2] = data[offset + 4];
 166            s->bd_addr.b[3] = data[offset + 0];
 167            s->bd_addr.b[4] = data[offset + 3];
 168            s->bd_addr.b[5] = data[offset + 2];
 169
 170            s->hci->bdaddr_set(s->hci, s->bd_addr.b);
 171            fprintf(stderr, "%s: bd_address loaded from firmware: "
 172                            "%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
 173                            s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2],
 174                            s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]);
 175        }
 176
 177        rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11);
 178        /* Status bytes: no error */
 179        rpkt[9] = 0x00;
 180        rpkt[10] = 0x00;
 181        break;
 182
 183    default:
 184        fprintf(stderr, "%s: got a bad CMD packet\n", __FUNCTION__);
 185        return;
 186    }
 187
 188    csrhci_fifo_wake(s);
 189}
 190
 191static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt)
 192{
 193    uint8_t *rpkt;
 194    int opc;
 195
 196    switch (*pkt ++) {
 197    case H4_CMD_PKT:
 198        opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode);
 199        if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) {
 200            csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc),
 201                            pkt + sizeof(struct hci_command_hdr),
 202                            s->in_len - sizeof(struct hci_command_hdr) - 1);
 203            return;
 204        }
 205
 206        /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes,
 207         * we need to send it to the HCI layer and then add our supported
 208         * commands to the returned mask (such as OGF_VENDOR_CMD).  With
 209         * bt-hci.c we could just have hooks for this kind of commands but
 210         * we can't with bt-host.c.  */
 211
 212        s->hci->cmd_send(s->hci, pkt, s->in_len - 1);
 213        break;
 214
 215    case H4_EVT_PKT:
 216        goto bad_pkt;
 217
 218    case H4_ACL_PKT:
 219        s->hci->acl_send(s->hci, pkt, s->in_len - 1);
 220        break;
 221
 222    case H4_SCO_PKT:
 223        s->hci->sco_send(s->hci, pkt, s->in_len - 1);
 224        break;
 225
 226    case H4_NEG_PKT:
 227        if (s->in_hdr != sizeof(csrhci_neg_packet) ||
 228                        memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) {
 229            fprintf(stderr, "%s: got a bad NEG packet\n", __FUNCTION__);
 230            return;
 231        }
 232        pkt += 2;
 233
 234        rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10);
 235
 236        *rpkt ++ = 0x20;        /* Operational settings negotiation Ok */
 237        memcpy(rpkt, pkt, 7); rpkt += 7;
 238        *rpkt ++ = 0xff;
 239        *rpkt = 0xff;
 240        break;
 241
 242    case H4_ALIVE_PKT:
 243        if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) {
 244            fprintf(stderr, "%s: got a bad ALIVE packet\n", __FUNCTION__);
 245            return;
 246        }
 247
 248        rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2);
 249
 250        *rpkt ++ = 0xcc;
 251        *rpkt = 0x00;
 252        break;
 253
 254    default:
 255    bad_pkt:
 256        /* TODO: error out */
 257        fprintf(stderr, "%s: got a bad packet\n", __FUNCTION__);
 258        break;
 259    }
 260
 261    csrhci_fifo_wake(s);
 262}
 263
 264static int csrhci_header_len(const uint8_t *pkt)
 265{
 266    switch (pkt[0]) {
 267    case H4_CMD_PKT:
 268        return HCI_COMMAND_HDR_SIZE;
 269    case H4_EVT_PKT:
 270        return HCI_EVENT_HDR_SIZE;
 271    case H4_ACL_PKT:
 272        return HCI_ACL_HDR_SIZE;
 273    case H4_SCO_PKT:
 274        return HCI_SCO_HDR_SIZE;
 275    case H4_NEG_PKT:
 276        return pkt[1] + 1;
 277    case H4_ALIVE_PKT:
 278        return 3;
 279    }
 280
 281    exit(-1);
 282}
 283
 284static int csrhci_data_len(const uint8_t *pkt)
 285{
 286    switch (*pkt ++) {
 287    case H4_CMD_PKT:
 288        /* It seems that vendor-specific command packets for H4+ are all
 289         * one byte longer than indicated in the standard header.  */
 290        if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00)
 291            return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1;
 292
 293        return ((struct hci_command_hdr *) pkt)->plen;
 294    case H4_EVT_PKT:
 295        return ((struct hci_event_hdr *) pkt)->plen;
 296    case H4_ACL_PKT:
 297        return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen);
 298    case H4_SCO_PKT:
 299        return ((struct hci_sco_hdr *) pkt)->dlen;
 300    case H4_NEG_PKT:
 301    case H4_ALIVE_PKT:
 302        return 0;
 303    }
 304
 305    exit(-1);
 306}
 307
 308static void csrhci_ready_for_next_inpkt(struct csrhci_s *s)
 309{
 310    s->in_state = CSR_HDR_LEN;
 311    s->in_len = 0;
 312    s->in_needed = 2;
 313    s->in_hdr = INT_MAX;
 314}
 315
 316static int csrhci_write(struct Chardev *chr,
 317                const uint8_t *buf, int len)
 318{
 319    struct csrhci_s *s = (struct csrhci_s *)chr;
 320    int total = 0;
 321
 322    if (!s->enable)
 323        return 0;
 324
 325    for (;;) {
 326        int cnt = MIN(len, s->in_needed - s->in_len);
 327        if (cnt) {
 328            memcpy(s->inpkt + s->in_len, buf, cnt);
 329            s->in_len += cnt;
 330            buf += cnt;
 331            len -= cnt;
 332            total += cnt;
 333        }
 334
 335        if (s->in_len < s->in_needed) {
 336            break;
 337        }
 338
 339        if (s->in_state == CSR_HDR_LEN) {
 340            s->in_hdr = csrhci_header_len(s->inpkt) + 1;
 341            assert(s->in_hdr >= s->in_needed);
 342            s->in_needed = s->in_hdr;
 343            s->in_state = CSR_DATA_LEN;
 344            continue;
 345        }
 346
 347        if (s->in_state == CSR_DATA_LEN) {
 348            s->in_needed += csrhci_data_len(s->inpkt);
 349            /* hci_acl_hdr could specify more than 4096 bytes, so assert.  */
 350            assert(s->in_needed <= sizeof(s->inpkt));
 351            s->in_state = CSR_DATA;
 352            continue;
 353        }
 354
 355        if (s->in_state == CSR_DATA) {
 356            csrhci_in_packet(s, s->inpkt);
 357            csrhci_ready_for_next_inpkt(s);
 358        }
 359    }
 360
 361    return total;
 362}
 363
 364static void csrhci_out_hci_packet_event(void *opaque,
 365                const uint8_t *data, int len)
 366{
 367    struct csrhci_s *s = (struct csrhci_s *) opaque;
 368    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);        /* Align */
 369
 370    *pkt ++ = H4_EVT_PKT;
 371    memcpy(pkt, data, len);
 372
 373    csrhci_fifo_wake(s);
 374}
 375
 376static void csrhci_out_hci_packet_acl(void *opaque,
 377                const uint8_t *data, int len)
 378{
 379    struct csrhci_s *s = (struct csrhci_s *) opaque;
 380    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);        /* Align */
 381
 382    *pkt ++ = H4_ACL_PKT;
 383    pkt[len & ~1] = 0;
 384    memcpy(pkt, data, len);
 385
 386    csrhci_fifo_wake(s);
 387}
 388
 389static int csrhci_ioctl(struct Chardev *chr, int cmd, void *arg)
 390{
 391    QEMUSerialSetParams *ssp;
 392    struct csrhci_s *s = (struct csrhci_s *) chr;
 393    int prev_state = s->modem_state;
 394
 395    switch (cmd) {
 396    case CHR_IOCTL_SERIAL_SET_PARAMS:
 397        ssp = (QEMUSerialSetParams *) arg;
 398        s->baud_delay = NANOSECONDS_PER_SECOND / ssp->speed;
 399        /* Moments later... (but shorter than 100ms) */
 400        s->modem_state |= CHR_TIOCM_CTS;
 401        break;
 402
 403    case CHR_IOCTL_SERIAL_GET_TIOCM:
 404        *(int *) arg = s->modem_state;
 405        break;
 406
 407    case CHR_IOCTL_SERIAL_SET_TIOCM:
 408        s->modem_state = *(int *) arg;
 409        if (~s->modem_state & prev_state & CHR_TIOCM_RTS)
 410            s->modem_state &= ~CHR_TIOCM_CTS;
 411        break;
 412
 413    default:
 414        return -ENOTSUP;
 415    }
 416    return 0;
 417}
 418
 419static void csrhci_reset(struct csrhci_s *s)
 420{
 421    s->out_len = 0;
 422    s->out_size = FIFO_LEN;
 423    csrhci_ready_for_next_inpkt(s);
 424    s->baud_delay = NANOSECONDS_PER_SECOND;
 425    s->enable = 0;
 426
 427    s->modem_state = 0;
 428    /* After a while... (but sooner than 10ms) */
 429    s->modem_state |= CHR_TIOCM_CTS;
 430
 431    memset(&s->bd_addr, 0, sizeof(bdaddr_t));
 432}
 433
 434static void csrhci_out_tick(void *opaque)
 435{
 436    csrhci_fifo_wake((struct csrhci_s *) opaque);
 437}
 438
 439static void csrhci_pins(void *opaque, int line, int level)
 440{
 441    struct csrhci_s *s = (struct csrhci_s *) opaque;
 442    int state = s->pin_state;
 443
 444    s->pin_state &= ~(1 << line);
 445    s->pin_state |= (!!level) << line;
 446
 447    if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) {
 448        /* TODO: Disappear from lower layers */
 449        csrhci_reset(s);
 450    }
 451
 452    if (s->pin_state == 3 && state != 3) {
 453        s->enable = 1;
 454        /* TODO: Wake lower layers up */
 455    }
 456}
 457
 458qemu_irq *csrhci_pins_get(Chardev *chr)
 459{
 460    struct csrhci_s *s = (struct csrhci_s *) chr;
 461
 462    return s->pins;
 463}
 464
 465static void csrhci_open(Chardev *chr,
 466                        ChardevBackend *backend,
 467                        bool *be_opened,
 468                        Error **errp)
 469{
 470    struct csrhci_s *s = HCI_CHARDEV(chr);
 471
 472    s->hci = qemu_next_hci();
 473    s->hci->opaque = s;
 474    s->hci->evt_recv = csrhci_out_hci_packet_event;
 475    s->hci->acl_recv = csrhci_out_hci_packet_acl;
 476
 477    s->out_tm = timer_new_ns(QEMU_CLOCK_VIRTUAL, csrhci_out_tick, s);
 478    s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
 479    csrhci_reset(s);
 480    *be_opened = false;
 481}
 482
 483static void char_hci_class_init(ObjectClass *oc, void *data)
 484{
 485    ChardevClass *cc = CHARDEV_CLASS(oc);
 486
 487    cc->internal = true;
 488    cc->open = csrhci_open;
 489    cc->chr_write = csrhci_write;
 490    cc->chr_ioctl = csrhci_ioctl;
 491}
 492
 493static const TypeInfo char_hci_type_info = {
 494    .name = TYPE_CHARDEV_HCI,
 495    .parent = TYPE_CHARDEV,
 496    .instance_size = sizeof(struct csrhci_s),
 497    .class_init = char_hci_class_init,
 498};
 499
 500Chardev *uart_hci_init(void)
 501{
 502    return qemu_chardev_new(NULL, TYPE_CHARDEV_HCI,
 503                            NULL, &error_abort);
 504}
 505
 506static void register_types(void)
 507{
 508    type_register_static(&char_hci_type_info);
 509}
 510
 511type_init(register_types);
 512