Hello, I am trying to add support for Bluetooth braille devices, but I seem to be missing something. Basically, it should be using the RFCOMM PSM, but running
rfcomm connect 0 BA:BE:BA:D0:00:01 in the Linux guest hangs for some time and then the connect() system call returns EINPROGRESS. Am I perhaps missing some call to the qemu bt core? Samuel diff --git a/Makefile.objs b/Makefile.objs index e791dd5..b7c8fa6 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -78,7 +78,7 @@ common-obj-y += msmouse.o ps2.o common-obj-y += qdev.o qdev-properties.o common-obj-y += qemu-config.o block-migration.o -common-obj-$(CONFIG_BRLAPI) += baum.o +common-obj-$(CONFIG_BRLAPI) += baum.o bt-baum.o common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o diff --git a/hw/baum.h b/hw/baum.h index 8af710f..1fe30a7 100644 --- a/hw/baum.h +++ b/hw/baum.h @@ -22,5 +22,9 @@ * THE SOFTWARE. */ +#include "qemu-char.h" +#include "bt.h" /* char device */ CharDriverState *chr_baum_init(QemuOpts *opts); +/* bluetooth device */ +struct bt_device_s *bt_baum_init(struct bt_scatternet_s *net); diff --git a/hw/bt-baum.c b/hw/bt-baum.c new file mode 100644 index 0000000..568b8a1 --- /dev/null +++ b/hw/bt-baum.c @@ -0,0 +1,158 @@ +/* + * QEMU Bluetooth Baum driver. + * + * Copyright (C) 2010 Samuel Thibault <samuel.thiba...@ens-lyon.org> + * + * 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, if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu-common.h" +#include "baum.h" +#include "bt.h" + +#define BT_BAUM_MTU 1000 + +struct bt_baum_device_s { + struct bt_l2cap_device_s btdev; + struct bt_l2cap_conn_params_s *ch; + + CharDriverState *cdrv; +}; + +static int bt_baum_can_read(void *opaque) +{ + struct bt_baum_device_s *s = opaque; + /* Is there room in the bluetooth socket? */ + + if (!s->ch) + return 0; + + return s->ch->remote_mtu; +} + +static void bt_baum_read(void *opaque, const uint8_t *buf, int size) +{ + /* Got data from the Baum device to send over bluetooth to the guest */ + struct bt_baum_device_s *s = opaque; + uint8_t *pkt; + int len; + struct bt_l2cap_conn_params_s *ch = s->ch; + + if (!ch) + return; + + while (size) { + len = MIN(size, ch->remote_mtu); + pkt = ch->sdu_out(ch, size); + memcpy(pkt, buf, size); + ch->sdu_submit(ch); + size -= len; + buf += len; + }; +} + +static void bt_baum_sdu(void *opaque, const uint8_t *data, int len) +{ + /* Got data from bluetooth, to be sent to the Baum device */ + struct bt_baum_device_s *s = opaque; + qemu_chr_write(s->cdrv, data, len); +} + +static void bt_baum_close_ch(void *opaque) +{ + struct bt_baum_device_s *s = opaque; + + s->btdev.device.page_scan = 1; + s->btdev.device.inquiry_scan = 1; + + s->ch = NULL; + printf("close connection\n"); +} + +static int bt_baum_new_ch(struct bt_l2cap_device_s *dev, + struct bt_l2cap_conn_params_s *params) +{ + struct bt_baum_device_s *s = (struct bt_baum_device_s *) dev; + + if (s->ch) { + printf("already there: %p\n", s->ch); + return 1; + } + + printf("new connection\n"); + s->ch = params; + s->ch->opaque = s; + s->ch->close = bt_baum_close_ch; + s->ch->sdu_in = bt_baum_sdu; + + s->btdev.device.page_scan = 0; + s->btdev.device.inquiry_scan = 0; + + return 0; +} + +static void bt_baum_destroy(struct bt_device_s *dev) +{ + struct bt_baum_device_s *s = (struct bt_baum_device_s *) dev; + + bt_l2cap_device_done(&s->btdev); + + qemu_chr_close(s->cdrv); + + qemu_free(s); +} + +struct bt_device_s *bt_baum_init(struct bt_scatternet_s *net) +{ + struct bt_baum_device_s *s; + /* FIXME */ + uint32_t class = + /* Format type */ + (0 << 0) | + /* Device class */ + (0 << 2) | + (5 << 8) | /* "Peripheral" */ + /* Service classes */ + (1 << 13) | /* Limited discoverable mode */ + (1 << 19); /* Capturing device (?) */ + + s = qemu_mallocz(sizeof(*s)); + if (!s) + return NULL; + + s->cdrv = qemu_chr_open("braille", "braille", NULL); + + if (!s->cdrv) { + qemu_free(s); + return NULL; + } + + bt_l2cap_device_init(&s->btdev, net); + bt_l2cap_sdp_init(&s->btdev); + + s->btdev.device.lmp_name = "QEMU USB Braille"; + s->btdev.device.handle_destroy = bt_baum_destroy; + + printf("chan is %p\n", bt_baum_new_ch); + bt_l2cap_psm_register(&s->btdev, BT_PSM_RFCOMM, + BT_BAUM_MTU, bt_baum_new_ch); + + qemu_chr_add_handlers(s->cdrv, bt_baum_can_read, bt_baum_read, NULL, s); + + s->btdev.device.class[0] = (class >> 0) & 0xff; + s->btdev.device.class[1] = (class >> 8) & 0xff; + s->btdev.device.class[2] = (class >> 16) & 0xff; + + return &s->btdev.device; +} diff --git a/hw/bt.h b/hw/bt.h index 4a702ad..720b974 100644 --- a/hw/bt.h +++ b/hw/bt.h @@ -23,6 +23,9 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#ifndef BT_H +#define BT_H + /* BD Address */ typedef struct { uint8_t b[6]; @@ -2181,3 +2184,4 @@ enum bt_sdp_attribute_id { SDP_ATTR_NORMALLY_CONNECTABLE = 0x020d, SDP_ATTR_BOOT_DEVICE = 0x020e, }; +#endif diff --git a/vl.c b/vl.c index 10d8e34..2d89bfd 100644 --- a/vl.c +++ b/vl.c @@ -1741,6 +1741,9 @@ static struct bt_device_s *bt_device_add(const char *opt) if (!strcmp(devname, "keyboard")) return bt_keyboard_init(vlan); + if (!strcmp(devname, "braille")) + return bt_baum_init(vlan); + fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname); return 0; }