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