Commit fb599c9a030ac438755627f5919bfc40a57a0b9e

Authored by balrog
1 parent 58a26b47

Implement a HCI passthrough to host.

This allows using a host's physical HCI as one of the HCIs attached
to the virtual machine.  This brings various limitations because not
all commands/events are passed through by Linux kernel, some are
interpreted by the host's kernel for a speed gain.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5344 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
... ... @@ -81,7 +81,7 @@ OBJS+=scsi-generic.o
81 81 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o
82 82 OBJS+=usb-serial.o usb-net.o
83 83 OBJS+=sd.o ssi-sd.o
84   -OBJS+=bt.o
  84 +OBJS+=bt.o bt-host.o
85 85  
86 86 ifdef CONFIG_BRLAPI
87 87 OBJS+= baum.o
... ... @@ -166,6 +166,9 @@ vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h
166 166 curses.o: curses.c keymaps.c curses_keys.h
167 167 $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
168 168  
  169 +bt-host.o: bt-host.c
  170 + $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_BLUEZ_CFLAGS) -c -o $@ $<
  171 +
169 172 audio/sdlaudio.o: audio/sdlaudio.c
170 173 $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $<
171 174  
... ...
Makefile.target
... ... @@ -524,6 +524,10 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
524 524 LIBS += $(CONFIG_VNC_TLS_LIBS)
525 525 endif
526 526  
  527 +ifdef CONFIG_BLUEZ
  528 +LIBS += $(CONFIG_BLUEZ_LIBS)
  529 +endif
  530 +
527 531 # SCSI layer
528 532 OBJS+= lsi53c895a.o esp.o
529 533  
... ...
bt-host.c 0 → 100644
  1 +/*
  2 + * Wrap a host Bluetooth HCI socket in a struct HCIInfo.
  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 +
  27 +#include <errno.h>
  28 +#include <sys/ioctl.h>
  29 +#include <sys/uio.h>
  30 +#ifdef CONFIG_BLUEZ
  31 +# include <bluetooth/bluetooth.h>
  32 +# include <bluetooth/hci.h>
  33 +# include <bluetooth/hci_lib.h>
  34 +#else
  35 +# include "hw/bt.h"
  36 +# define HCI_MAX_FRAME_SIZE 1028
  37 +#endif
  38 +
  39 +struct bt_host_hci_s {
  40 + struct HCIInfo hci;
  41 + int fd;
  42 +
  43 + uint8_t hdr[HCI_MAX_FRAME_SIZE];
  44 + int len;
  45 +};
  46 +
  47 +static void bt_host_send(struct HCIInfo *hci,
  48 + int type, const uint8_t *data, int len)
  49 +{
  50 + struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
  51 + uint8_t pkt = type;
  52 + struct iovec iv[2];
  53 + int ret;
  54 +
  55 + iv[0].iov_base = &pkt;
  56 + iv[0].iov_len = 1;
  57 + iv[1].iov_base = (void *) data;
  58 + iv[1].iov_len = len;
  59 +
  60 + while ((ret = writev(s->fd, iv, 2)) < 0)
  61 + if (errno != EAGAIN && errno != EINTR) {
  62 + fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
  63 + errno);
  64 + return;
  65 + }
  66 +}
  67 +
  68 +static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len)
  69 +{
  70 + bt_host_send(hci, HCI_COMMAND_PKT, data, len);
  71 +}
  72 +
  73 +static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len)
  74 +{
  75 + bt_host_send(hci, HCI_ACLDATA_PKT, data, len);
  76 +}
  77 +
  78 +static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len)
  79 +{
  80 + bt_host_send(hci, HCI_SCODATA_PKT, data, len);
  81 +}
  82 +
  83 +static int bt_host_read_poll(void *opaque)
  84 +{
  85 + struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
  86 +
  87 + return !!s->hci.evt_recv;
  88 +}
  89 +
  90 +static void bt_host_read(void *opaque)
  91 +{
  92 + struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
  93 + uint8_t *pkt;
  94 + int pktlen;
  95 +
  96 + /* Seems that we can't read only the header first and then the amount
  97 + * of data indicated in the header because Linux will discard everything
  98 + * that's not been read in one go. */
  99 + s->len = read(s->fd, s->hdr, sizeof(s->hdr));
  100 +
  101 + if (s->len < 0) {
  102 + fprintf(stderr, "qemu: error %i reading HCI frame\n", errno);
  103 + return;
  104 + }
  105 +
  106 + pkt = s->hdr;
  107 + while (s->len --)
  108 + switch (*pkt ++) {
  109 + case HCI_EVENT_PKT:
  110 + if (s->len < 2)
  111 + goto bad_pkt;
  112 +
  113 + pktlen = MIN(pkt[1] + 2, s->len);
  114 + s->hci.evt_recv(s->hci.opaque, pkt, pktlen);
  115 + s->len -= pktlen;
  116 + pkt += pktlen;
  117 +
  118 + /* TODO: if this is an Inquiry Result event, it's also
  119 + * interpreted by Linux kernel before we received it, possibly
  120 + * we should clean the kernel Inquiry cache through
  121 + * ioctl(s->fd, HCI_INQUIRY, ...). */
  122 + break;
  123 +
  124 + case HCI_ACLDATA_PKT:
  125 + if (s->len < 4)
  126 + goto bad_pkt;
  127 +
  128 + pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
  129 + s->hci.acl_recv(s->hci.opaque, pkt, pktlen);
  130 + s->len -= pktlen;
  131 + pkt += pktlen;
  132 + break;
  133 +
  134 + case HCI_SCODATA_PKT:
  135 + if (s->len < 3)
  136 + goto bad_pkt;
  137 +
  138 + pktlen = MIN(pkt[2] + 3, s->len);
  139 + s->len -= pktlen;
  140 + pkt += pktlen;
  141 +
  142 + default:
  143 + bad_pkt:
  144 + fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
  145 + }
  146 +}
  147 +
  148 +static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
  149 +{
  150 + return -ENOTSUP;
  151 +}
  152 +
  153 +struct HCIInfo *bt_host_hci(const char *id)
  154 +{
  155 + struct bt_host_hci_s *s;
  156 + int fd = -1;
  157 +#ifdef CONFIG_BLUEZ
  158 + int dev_id = hci_devid(id);
  159 + struct hci_filter flt;
  160 +
  161 + if (dev_id < 0) {
  162 + fprintf(stderr, "qemu: `%s' not available\n", id);
  163 + return 0;
  164 + }
  165 +
  166 + fd = hci_open_dev(dev_id);
  167 +
  168 + /* XXX: can we ensure nobody else has the device opened? */
  169 +#endif
  170 +
  171 + if (fd < 0) {
  172 + fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
  173 + id, strerror(errno), errno);
  174 + return 0;
  175 + }
  176 +
  177 +#ifdef CONFIG_BLUEZ
  178 + hci_filter_clear(&flt);
  179 + hci_filter_all_ptypes(&flt);
  180 + hci_filter_all_events(&flt);
  181 +
  182 + if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
  183 + fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno);
  184 + return 0;
  185 + }
  186 +#endif
  187 +
  188 + s = qemu_mallocz(sizeof(struct bt_host_hci_s));
  189 + s->fd = fd;
  190 + s->hci.cmd_send = bt_host_cmd;
  191 + s->hci.sco_send = bt_host_sco;
  192 + s->hci.acl_send = bt_host_acl;
  193 + s->hci.bdaddr_set = bt_host_bdaddr_set;
  194 +
  195 + qemu_set_fd_handler2(s->fd, bt_host_read_poll, bt_host_read, 0, s);
  196 +
  197 + return &s->hci;
  198 +}
... ...
configure
... ... @@ -110,6 +110,7 @@ curses=&quot;yes&quot;
110 110 aio="yes"
111 111 nptl="yes"
112 112 mixemu="no"
  113 +bluez="yes"
113 114 signalfd="no"
114 115 eventfd="no"
115 116  
... ... @@ -293,6 +294,8 @@ for opt do
293 294 ;;
294 295 --disable-brlapi) brlapi="no"
295 296 ;;
  297 + --disable-bluez) bluez="no"
  298 + ;;
296 299 --enable-profiler) profiler="yes"
297 300 ;;
298 301 --enable-cocoa)
... ... @@ -429,6 +432,7 @@ echo &quot; --enable-mixemu enable mixer emulation&quot;
429 432 echo " --disable-brlapi disable BrlAPI"
430 433 echo " --disable-vnc-tls disable TLS encryption for VNC server"
431 434 echo " --disable-curses disable curses output"
  435 +echo " --disable-bluez disable bluez stack connectivity"
432 436 echo " --disable-nptl disable usermode NPTL support"
433 437 echo " --enable-system enable all system emulation targets"
434 438 echo " --disable-system disable all system emulation targets"
... ... @@ -891,6 +895,16 @@ EOF
891 895 fi # test "$curses"
892 896  
893 897 ##########################################
  898 +# bluez support probe
  899 +if test "$bluez" = "yes" ; then
  900 + `pkg-config bluez` || bluez="no"
  901 +fi
  902 +if test "$bluez" = "yes" ; then
  903 + bluez_cflags=`pkg-config --cflags bluez`
  904 + bluez_libs=`pkg-config --libs bluez`
  905 +fi
  906 +
  907 +##########################################
894 908 # AIO probe
895 909 if test "$aio" = "yes" ; then
896 910 aio=no
... ... @@ -1254,6 +1268,12 @@ if test &quot;$brlapi&quot; = &quot;yes&quot; ; then
1254 1268 echo "#define CONFIG_BRLAPI 1" >> $config_h
1255 1269 echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak
1256 1270 fi
  1271 +if test "$bluez" = "yes" ; then
  1272 + echo "CONFIG_BLUEZ=yes" >> $config_mak
  1273 + echo "CONFIG_BLUEZ_CFLAGS=$bluez_cflags" >> $config_mak
  1274 + echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak
  1275 + echo "#define CONFIG_BLUEZ 1" >> $config_h
  1276 +fi
1257 1277 if test "$aio" = "yes" ; then
1258 1278 echo "#define CONFIG_AIO 1" >> $config_h
1259 1279 echo "CONFIG_AIO=yes" >> $config_mak
... ...