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