symbian-qemu-0.9.1-12/qemu-symbian-svp/bt-vhci.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Support for host VHCIs inside qemu scatternets.
       
     3  *
       
     4  * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
       
     5  *
       
     6  * This program is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU General Public License as
       
     8  * published by the Free Software Foundation; either version 2 or
       
     9  * (at your option) version 3 of the License.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14  * GNU General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU General Public License
       
    17  * along with this program; if not, write to the Free Software
       
    18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       
    19  * MA 02111-1307 USA
       
    20  */
       
    21 
       
    22 #include "qemu-common.h"
       
    23 #include "qemu-char.h"
       
    24 #include "sysemu.h"
       
    25 #include "net.h"
       
    26 #include "hw/bt.h"
       
    27 
       
    28 #define VHCI_DEV	"/dev/vhci"
       
    29 #define VHCI_UDEV	"/dev/hci_vhci"
       
    30 
       
    31 struct bt_vhci_s {
       
    32     int fd;
       
    33     struct HCIInfo *info;
       
    34 
       
    35     uint8_t hdr[4096];
       
    36     int len;
       
    37 };
       
    38 
       
    39 static void vhci_read(void *opaque)
       
    40 {
       
    41     struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
       
    42     uint8_t *pkt;
       
    43     int pktlen;
       
    44 
       
    45     /* Seems that we can't read only the header first and then the amount
       
    46      * of data indicated in the header because Linux will discard everything
       
    47      * that's not been read in one go.  */
       
    48     s->len = read(s->fd, s->hdr, sizeof(s->hdr));
       
    49 
       
    50     if (s->len < 0) {
       
    51         fprintf(stderr, "qemu: error %i reading the PDU\n", errno);
       
    52         return;
       
    53     }
       
    54 
       
    55     pkt = s->hdr;
       
    56     while (s->len --)
       
    57         switch (*pkt ++) {
       
    58         case HCI_COMMAND_PKT:
       
    59             if (s->len < 3)
       
    60                 goto bad_pkt;
       
    61 
       
    62             pktlen = MIN(pkt[2] + 3, s->len);
       
    63             s->info->cmd_send(s->info, pkt, pktlen);
       
    64             s->len -= pktlen;
       
    65             pkt += pktlen;
       
    66             break;
       
    67 
       
    68         case HCI_ACLDATA_PKT:
       
    69             if (s->len < 4)
       
    70                 goto bad_pkt;
       
    71 
       
    72             pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
       
    73             s->info->acl_send(s->info, pkt, pktlen);
       
    74             s->len -= pktlen;
       
    75             pkt += pktlen;
       
    76             break;
       
    77 
       
    78         case HCI_SCODATA_PKT:
       
    79             if (s->len < 3)
       
    80                 goto bad_pkt;
       
    81 
       
    82             pktlen = MIN(pkt[2] + 3, s->len);
       
    83             s->info->sco_send(s->info, pkt, pktlen);
       
    84             s->len -= pktlen;
       
    85             pkt += pktlen;
       
    86             break;
       
    87 
       
    88         default:
       
    89         bad_pkt:
       
    90             fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
       
    91         }
       
    92 }
       
    93 
       
    94 static void vhci_host_send(void *opaque,
       
    95                 int type, const uint8_t *data, int len)
       
    96 {
       
    97     struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
       
    98 #if 0
       
    99     uint8_t pkt = type;
       
   100     struct iovec iv[2];
       
   101 
       
   102     iv[0].iov_base = &pkt;
       
   103     iv[0].iov_len  = 1;
       
   104     iv[1].iov_base = (void *) data;
       
   105     iv[1].iov_len  = len;
       
   106 
       
   107     while (writev(s->fd, iv, 2) < 0)
       
   108         if (errno != EAGAIN && errno != EINTR) {
       
   109             fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
       
   110                             errno);
       
   111             return;
       
   112         }
       
   113 #else
       
   114     /* Apparently VHCI wants us to write everything in one chunk :-(  */
       
   115     static uint8_t buf[4096];
       
   116 
       
   117     buf[0] = type;
       
   118     memcpy(buf + 1, data, len);
       
   119 
       
   120     while (write(s->fd, buf, len + 1) < 0)
       
   121         if (errno != EAGAIN && errno != EINTR) {
       
   122             fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
       
   123                             errno);
       
   124             return;
       
   125         }
       
   126 #endif
       
   127 }
       
   128 
       
   129 static void vhci_out_hci_packet_event(void *opaque,
       
   130                 const uint8_t *data, int len)
       
   131 {
       
   132     vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
       
   133 }
       
   134 
       
   135 static void vhci_out_hci_packet_acl(void *opaque,
       
   136                 const uint8_t *data, int len)
       
   137 {
       
   138     vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
       
   139 }
       
   140 
       
   141 void bt_vhci_init(struct HCIInfo *info)
       
   142 {
       
   143     struct bt_vhci_s *s;
       
   144     int err[2];
       
   145     int fd;
       
   146 
       
   147     fd = open(VHCI_DEV, O_RDWR);
       
   148     err[0] = errno;
       
   149     if (fd < 0) {
       
   150         fd = open(VHCI_UDEV, O_RDWR);
       
   151         err[1] = errno;
       
   152     }
       
   153 
       
   154     if (fd < 0) {
       
   155         fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
       
   156                         VHCI_DEV, strerror(err[0]), err[0]);
       
   157         fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
       
   158                         VHCI_UDEV, strerror(err[1]), err[1]);
       
   159         exit(-1);
       
   160     }
       
   161 
       
   162     s = qemu_mallocz(sizeof(struct bt_vhci_s));
       
   163     s->fd = fd;
       
   164     s->info = info ?: qemu_next_hci();
       
   165     s->info->opaque = s;
       
   166     s->info->evt_recv = vhci_out_hci_packet_event;
       
   167     s->info->acl_recv = vhci_out_hci_packet_acl;
       
   168 
       
   169     qemu_set_fd_handler(s->fd, vhci_read, 0, s);
       
   170 }