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