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