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