Commit ab2b6f507ded382df734fe6a237ec56e2f421de4

Authored by balrog
1 parent 47e699dc

Use VHCI to allow the host os to participate in a qemu bluetooth "vlan".

This does the reverse of bt-host.c, proxying from guest to host.
Appears to be more reliable.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5348 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 3 changed files with 181 additions and 1 deletions
Makefile
@@ -81,7 +81,7 @@ OBJS+=scsi-generic.o @@ -81,7 +81,7 @@ OBJS+=scsi-generic.o
81 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o 81 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o
82 OBJS+=usb-serial.o usb-net.o 82 OBJS+=usb-serial.o usb-net.o
83 OBJS+=sd.o ssi-sd.o 83 OBJS+=sd.o ssi-sd.o
84 -OBJS+=bt.o bt-host.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o 84 +OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o
85 85
86 ifdef CONFIG_BRLAPI 86 ifdef CONFIG_BRLAPI
87 OBJS+= baum.o 87 OBJS+= baum.o
bt-vhci.c 0 → 100644
  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 +#include <sys/uio.h>
  29 +
  30 +#define VHCI_DEV "/dev/vhci"
  31 +#define VHCI_UDEV "/dev/hci_vhci"
  32 +
  33 +struct bt_vhci_s {
  34 + int fd;
  35 + struct HCIInfo *info;
  36 +
  37 + uint8_t hdr[4096];
  38 + int len;
  39 +};
  40 +
  41 +static void vhci_read(void *opaque)
  42 +{
  43 + struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
  44 + uint8_t *pkt;
  45 + int pktlen;
  46 +
  47 + /* Seems that we can't read only the header first and then the amount
  48 + * of data indicated in the header because Linux will discard everything
  49 + * that's not been read in one go. */
  50 + s->len = read(s->fd, s->hdr, sizeof(s->hdr));
  51 +
  52 + if (s->len < 0) {
  53 + fprintf(stderr, "qemu: error %i reading the PDU\n", errno);
  54 + return;
  55 + }
  56 +
  57 + pkt = s->hdr;
  58 + while (s->len --)
  59 + switch (*pkt ++) {
  60 + case HCI_COMMAND_PKT:
  61 + if (s->len < 3)
  62 + goto bad_pkt;
  63 +
  64 + pktlen = MIN(pkt[2] + 3, s->len);
  65 + s->info->cmd_send(s->info, pkt, pktlen);
  66 + s->len -= pktlen;
  67 + pkt += pktlen;
  68 + break;
  69 +
  70 + case HCI_ACLDATA_PKT:
  71 + if (s->len < 4)
  72 + goto bad_pkt;
  73 +
  74 + pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
  75 + s->info->acl_send(s->info, pkt, pktlen);
  76 + s->len -= pktlen;
  77 + pkt += pktlen;
  78 + break;
  79 +
  80 + case HCI_SCODATA_PKT:
  81 + if (s->len < 3)
  82 + goto bad_pkt;
  83 +
  84 + pktlen = MIN(pkt[2] + 3, s->len);
  85 + s->info->sco_send(s->info, pkt, pktlen);
  86 + s->len -= pktlen;
  87 + pkt += pktlen;
  88 + break;
  89 +
  90 + default:
  91 + bad_pkt:
  92 + fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
  93 + }
  94 +}
  95 +
  96 +static void vhci_host_send(void *opaque,
  97 + int type, const uint8_t *data, int len)
  98 +{
  99 + struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
  100 +#if 0
  101 + uint8_t pkt = type;
  102 + struct iovec iv[2];
  103 +
  104 + iv[0].iov_base = &pkt;
  105 + iv[0].iov_len = 1;
  106 + iv[1].iov_base = (void *) data;
  107 + iv[1].iov_len = len;
  108 +
  109 + while (writev(s->fd, iv, 2) < 0)
  110 + if (errno != EAGAIN && errno != EINTR) {
  111 + fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
  112 + errno);
  113 + return;
  114 + }
  115 +#else
  116 + /* Apparently VHCI wants us to write everything in one chunk :-( */
  117 + static uint8_t buf[4096];
  118 +
  119 + buf[0] = type;
  120 + memcpy(buf + 1, data, len);
  121 +
  122 + while (write(s->fd, buf, len + 1) < 0)
  123 + if (errno != EAGAIN && errno != EINTR) {
  124 + fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
  125 + errno);
  126 + return;
  127 + }
  128 +#endif
  129 +}
  130 +
  131 +static void vhci_out_hci_packet_event(void *opaque,
  132 + const uint8_t *data, int len)
  133 +{
  134 + vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
  135 +}
  136 +
  137 +static void vhci_out_hci_packet_acl(void *opaque,
  138 + const uint8_t *data, int len)
  139 +{
  140 + vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
  141 +}
  142 +
  143 +void bt_vhci_init(struct HCIInfo *info)
  144 +{
  145 + struct bt_vhci_s *s;
  146 + int err[2];
  147 + int fd;
  148 +
  149 + fd = open(VHCI_DEV, O_RDWR);
  150 + err[0] = errno;
  151 + if (fd < 0) {
  152 + fd = open(VHCI_UDEV, O_RDWR);
  153 + err[1] = errno;
  154 + }
  155 +
  156 + if (fd < 0) {
  157 + fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
  158 + VHCI_DEV, strerror(err[0]), err[0]);
  159 + fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
  160 + VHCI_UDEV, strerror(err[1]), err[1]);
  161 + exit(-1);
  162 + }
  163 +
  164 + s = qemu_mallocz(sizeof(struct bt_vhci_s));
  165 + s->fd = fd;
  166 + s->info = info ?: qemu_next_hci();
  167 + s->info->opaque = s;
  168 + s->info->evt_recv = vhci_out_hci_packet_event;
  169 + s->info->acl_recv = vhci_out_hci_packet_acl;
  170 +
  171 + qemu_set_fd_handler(s->fd, vhci_read, 0, s);
  172 +}
@@ -115,6 +115,9 @@ struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net); @@ -115,6 +115,9 @@ struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net);
115 /* bt-host.c */ 115 /* bt-host.c */
116 struct HCIInfo *bt_host_hci(const char *id); 116 struct HCIInfo *bt_host_hci(const char *id);
117 117
  118 +/* bt-vhci.c */
  119 +void bt_vhci_init(struct HCIInfo *info);
  120 +
118 /* bt-hci-csr.c */ 121 /* bt-hci-csr.c */
119 enum { 122 enum {
120 csrhci_pin_reset, 123 csrhci_pin_reset,
@@ -167,6 +170,11 @@ enum bt_l2cap_psm_predef { @@ -167,6 +170,11 @@ enum bt_l2cap_psm_predef {
167 /* bt-sdp.c */ 170 /* bt-sdp.c */
168 void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev); 171 void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev);
169 172
  173 +/* bt-hid.c */
  174 +struct bt_device_s *bt_mouse_init(struct bt_scatternet_s *net);
  175 +struct bt_device_s *bt_tablet_init(struct bt_scatternet_s *net);
  176 +struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net);
  177 +
170 /* Link Management Protocol layer defines */ 178 /* Link Management Protocol layer defines */
171 179
172 #define LLID_ACLU_CONT 0x1 180 #define LLID_ACLU_CONT 0x1