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