Home | History | Annotate | Download | only in hw
      1 /*
      2  * Bluetooth serial HCI transport.
      3  * CSR41814 HCI with H4p vendor extensions.
      4  *
      5  * Copyright (C) 2008 Andrzej Zaborowski  <balrog (at) 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, write to the Free Software Foundation, Inc.,
     19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     20  */
     21 
     22 #include "qemu-common.h"
     23 #include "qemu-char.h"
     24 #include "qemu-timer.h"
     25 #include "irq.h"
     26 #include "sysemu.h"
     27 #include "net.h"
     28 #include "bt.h"
     29 
     30 struct 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 */
     53 enum {
     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 */
     63 static 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 */
     70 enum {
     71     OCF_CSR_SEND_FIRMWARE = 0x000,
     72 };
     73 
     74 static 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         qemu_mod_timer(s->out_tm, qemu_get_clock(vm_clock) + s->baud_delay);
     93 }
     94 
     95 #define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
     96 static 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 
    119 static 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 
    130 static 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 
    143 static 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 
    182 static 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 negotation 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 
    255 static 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 
    275 static 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 
    299 static 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 
    333 static 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 
    345 static 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 
    358 static 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 = ticks_per_sec / 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 
    388 static 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 = ticks_per_sec;
    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 
    405 static void csrhci_out_tick(void *opaque)
    406 {
    407     csrhci_fifo_wake((struct csrhci_s *) opaque);
    408 }
    409 
    410 static 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 
    429 qemu_irq *csrhci_pins_get(CharDriverState *chr)
    430 {
    431     struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
    432 
    433     return s->pins;
    434 }
    435 
    436 CharDriverState *uart_hci_init(qemu_irq wakeup)
    437 {
    438     struct csrhci_s *s = (struct csrhci_s *)
    439             qemu_mallocz(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 
    445     s->hci = qemu_next_hci();
    446     s->hci->opaque = s;
    447     s->hci->evt_recv = csrhci_out_hci_packet_event;
    448     s->hci->acl_recv = csrhci_out_hci_packet_acl;
    449 
    450     s->out_tm = qemu_new_timer(vm_clock, csrhci_out_tick, s);
    451     s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
    452     csrhci_reset(s);
    453 
    454     return &s->chr;
    455 }
    456