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