From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Kk61W-0003hH-84 for qemu-devel@nongnu.org; Sun, 28 Sep 2008 19:49:58 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Kk61V-0003gW-Qu for qemu-devel@nongnu.org; Sun, 28 Sep 2008 19:49:57 -0400 Received: from [199.232.76.173] (port=39650 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Kk61V-0003gN-Br for qemu-devel@nongnu.org; Sun, 28 Sep 2008 19:49:57 -0400 Received: from savannah.gnu.org ([199.232.41.3]:50770 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1Kk61U-0006bB-FB for qemu-devel@nongnu.org; Sun, 28 Sep 2008 19:49:56 -0400 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1Kk61T-0002yW-Ii for qemu-devel@nongnu.org; Sun, 28 Sep 2008 23:49:55 +0000 Received: from balrog by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1Kk61T-0002yS-AL for qemu-devel@nongnu.org; Sun, 28 Sep 2008 23:49:55 +0000 MIME-Version: 1.0 Errors-To: balrog Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Andrzej Zaborowski Message-Id: Date: Sun, 28 Sep 2008 23:49:55 +0000 Subject: [Qemu-devel] [5344] Implement a HCI passthrough to host. Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 5344 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=5344 Author: balrog Date: 2008-09-28 23:49:55 +0000 (Sun, 28 Sep 2008) Log Message: ----------- 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. Modified Paths: -------------- trunk/Makefile trunk/Makefile.target trunk/configure Added Paths: ----------- trunk/bt-host.c Modified: trunk/Makefile =================================================================== --- trunk/Makefile 2008-09-28 23:34:13 UTC (rev 5343) +++ trunk/Makefile 2008-09-28 23:49:55 UTC (rev 5344) @@ -81,7 +81,7 @@ OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o OBJS+=usb-serial.o usb-net.o OBJS+=sd.o ssi-sd.o -OBJS+=bt.o +OBJS+=bt.o bt-host.o ifdef CONFIG_BRLAPI OBJS+= baum.o @@ -166,6 +166,9 @@ curses.o: curses.c keymaps.c curses_keys.h $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< +bt-host.o: bt-host.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_BLUEZ_CFLAGS) -c -o $@ $< + audio/sdlaudio.o: audio/sdlaudio.c $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $< Modified: trunk/Makefile.target =================================================================== --- trunk/Makefile.target 2008-09-28 23:34:13 UTC (rev 5343) +++ trunk/Makefile.target 2008-09-28 23:49:55 UTC (rev 5344) @@ -524,6 +524,10 @@ LIBS += $(CONFIG_VNC_TLS_LIBS) endif +ifdef CONFIG_BLUEZ +LIBS += $(CONFIG_BLUEZ_LIBS) +endif + # SCSI layer OBJS+= lsi53c895a.o esp.o Added: trunk/bt-host.c =================================================================== --- trunk/bt-host.c (rev 0) +++ trunk/bt-host.c 2008-09-28 23:49:55 UTC (rev 5344) @@ -0,0 +1,198 @@ +/* + * Wrap a host Bluetooth HCI socket in a struct HCIInfo. + * + * Copyright (C) 2008 Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "qemu-common.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "net.h" + +#include +#include +#include +#ifdef CONFIG_BLUEZ +# include +# include +# include +#else +# include "hw/bt.h" +# define HCI_MAX_FRAME_SIZE 1028 +#endif + +struct bt_host_hci_s { + struct HCIInfo hci; + int fd; + + uint8_t hdr[HCI_MAX_FRAME_SIZE]; + int len; +}; + +static void bt_host_send(struct HCIInfo *hci, + int type, const uint8_t *data, int len) +{ + struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci; + uint8_t pkt = type; + struct iovec iv[2]; + int ret; + + iv[0].iov_base = &pkt; + iv[0].iov_len = 1; + iv[1].iov_base = (void *) data; + iv[1].iov_len = len; + + while ((ret = writev(s->fd, iv, 2)) < 0) + if (errno != EAGAIN && errno != EINTR) { + fprintf(stderr, "qemu: error %i writing bluetooth packet.\n", + errno); + return; + } +} + +static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len) +{ + bt_host_send(hci, HCI_COMMAND_PKT, data, len); +} + +static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len) +{ + bt_host_send(hci, HCI_ACLDATA_PKT, data, len); +} + +static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len) +{ + bt_host_send(hci, HCI_SCODATA_PKT, data, len); +} + +static int bt_host_read_poll(void *opaque) +{ + struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque; + + return !!s->hci.evt_recv; +} + +static void bt_host_read(void *opaque) +{ + struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque; + uint8_t *pkt; + int pktlen; + + /* Seems that we can't read only the header first and then the amount + * of data indicated in the header because Linux will discard everything + * that's not been read in one go. */ + s->len = read(s->fd, s->hdr, sizeof(s->hdr)); + + if (s->len < 0) { + fprintf(stderr, "qemu: error %i reading HCI frame\n", errno); + return; + } + + pkt = s->hdr; + while (s->len --) + switch (*pkt ++) { + case HCI_EVENT_PKT: + if (s->len < 2) + goto bad_pkt; + + pktlen = MIN(pkt[1] + 2, s->len); + s->hci.evt_recv(s->hci.opaque, pkt, pktlen); + s->len -= pktlen; + pkt += pktlen; + + /* TODO: if this is an Inquiry Result event, it's also + * interpreted by Linux kernel before we received it, possibly + * we should clean the kernel Inquiry cache through + * ioctl(s->fd, HCI_INQUIRY, ...). */ + break; + + case HCI_ACLDATA_PKT: + if (s->len < 4) + goto bad_pkt; + + pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len); + s->hci.acl_recv(s->hci.opaque, pkt, pktlen); + s->len -= pktlen; + pkt += pktlen; + break; + + case HCI_SCODATA_PKT: + if (s->len < 3) + goto bad_pkt; + + pktlen = MIN(pkt[2] + 3, s->len); + s->len -= pktlen; + pkt += pktlen; + + default: + bad_pkt: + fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]); + } +} + +static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr) +{ + return -ENOTSUP; +} + +struct HCIInfo *bt_host_hci(const char *id) +{ + struct bt_host_hci_s *s; + int fd = -1; +#ifdef CONFIG_BLUEZ + int dev_id = hci_devid(id); + struct hci_filter flt; + + if (dev_id < 0) { + fprintf(stderr, "qemu: `%s' not available\n", id); + return 0; + } + + fd = hci_open_dev(dev_id); + + /* XXX: can we ensure nobody else has the device opened? */ +#endif + + if (fd < 0) { + fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n", + id, strerror(errno), errno); + return 0; + } + +#ifdef CONFIG_BLUEZ + hci_filter_clear(&flt); + hci_filter_all_ptypes(&flt); + hci_filter_all_events(&flt); + + if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { + fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno); + return 0; + } +#endif + + s = qemu_mallocz(sizeof(struct bt_host_hci_s)); + s->fd = fd; + s->hci.cmd_send = bt_host_cmd; + s->hci.sco_send = bt_host_sco; + s->hci.acl_send = bt_host_acl; + s->hci.bdaddr_set = bt_host_bdaddr_set; + + qemu_set_fd_handler2(s->fd, bt_host_read_poll, bt_host_read, 0, s); + + return &s->hci; +} Modified: trunk/configure =================================================================== --- trunk/configure 2008-09-28 23:34:13 UTC (rev 5343) +++ trunk/configure 2008-09-28 23:49:55 UTC (rev 5344) @@ -110,6 +110,7 @@ aio="yes" nptl="yes" mixemu="no" +bluez="yes" signalfd="no" eventfd="no" @@ -293,6 +294,8 @@ ;; --disable-brlapi) brlapi="no" ;; + --disable-bluez) bluez="no" + ;; --enable-profiler) profiler="yes" ;; --enable-cocoa) @@ -429,6 +432,7 @@ echo " --disable-brlapi disable BrlAPI" echo " --disable-vnc-tls disable TLS encryption for VNC server" echo " --disable-curses disable curses output" +echo " --disable-bluez disable bluez stack connectivity" echo " --disable-nptl disable usermode NPTL support" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" @@ -891,6 +895,16 @@ fi # test "$curses" ########################################## +# bluez support probe +if test "$bluez" = "yes" ; then + `pkg-config bluez` || bluez="no" +fi +if test "$bluez" = "yes" ; then + bluez_cflags=`pkg-config --cflags bluez` + bluez_libs=`pkg-config --libs bluez` +fi + +########################################## # AIO probe if test "$aio" = "yes" ; then aio=no @@ -1254,6 +1268,12 @@ echo "#define CONFIG_BRLAPI 1" >> $config_h echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak fi +if test "$bluez" = "yes" ; then + echo "CONFIG_BLUEZ=yes" >> $config_mak + echo "CONFIG_BLUEZ_CFLAGS=$bluez_cflags" >> $config_mak + echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak + echo "#define CONFIG_BLUEZ 1" >> $config_h +fi if test "$aio" = "yes" ; then echo "#define CONFIG_AIO 1" >> $config_h echo "CONFIG_AIO=yes" >> $config_mak