Add a "null" bluetooth HCI and a header file for bluetooth.
authorbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 28 Sep 2008 23:19:47 +0000 (23:19 +0000)
committerbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 28 Sep 2008 23:19:47 +0000 (23:19 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5342 c046a42c-6fe2-441c-8c8c-71466251a162

Makefile
hw/bt.c [new file with mode: 0644]
hw/bt.h [new file with mode: 0644]
hw/nseries.c
net.h
qemu-common.h
vl.c

index d1a1adb..9e6f760 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -81,6 +81,7 @@ OBJS+=scsi-generic.o
 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
 
 ifdef CONFIG_BRLAPI
 OBJS+= baum.o
diff --git a/hw/bt.c b/hw/bt.c
new file mode 100644 (file)
index 0000000..a6fcba8
--- /dev/null
+++ b/hw/bt.c
@@ -0,0 +1,123 @@
+/*
+ * Convenience functions for bluetooth.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "qemu-common.h"
+#include "net.h"
+#include "bt.h"
+
+/* Slave implementations can ignore this */
+static void bt_dummy_lmp_mode_change(struct bt_link_s *link)
+{
+}
+
+/* Slaves should never receive these PDUs */
+static void bt_dummy_lmp_connection_complete(struct bt_link_s *link)
+{
+    if (link->slave->reject_reason)
+        fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n",
+                        __FUNCTION__);
+    else
+        fprintf(stderr, "%s: stray LMP_accepted received, fixme\n",
+                        __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link)
+{
+    fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+/* Slaves that don't hold any additional per link state can use these */
+static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
+{
+    struct bt_link_s *link = qemu_mallocz(sizeof(struct bt_link_s));
+
+    link->slave = req->slave;
+    link->host = req->host;
+
+    req->host->reject_reason = 0;
+    req->host->lmp_connection_complete(link);
+}
+
+static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link)
+{
+    qemu_free(link);
+}
+
+static void bt_dummy_destroy(struct bt_device_s *device)
+{
+    bt_device_done(device);
+    qemu_free(device);
+}
+
+static int bt_dev_idx = 0;
+
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net)
+{
+    memset(dev, 0, sizeof(*dev));
+    dev->inquiry_scan = 1;
+    dev->page_scan = 1;
+
+    dev->bd_addr.b[0] = bt_dev_idx & 0xff;
+    dev->bd_addr.b[1] = bt_dev_idx >> 8;
+    dev->bd_addr.b[2] = 0xd0;
+    dev->bd_addr.b[3] = 0xba;
+    dev->bd_addr.b[4] = 0xbe;
+    dev->bd_addr.b[5] = 0xba;
+    bt_dev_idx ++;
+
+    /* Simple slave-only devices need to implement only .lmp_acl_data */
+    dev->lmp_connection_complete = bt_dummy_lmp_connection_complete;
+    dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master;
+    dev->lmp_acl_resp = bt_dummy_lmp_acl_resp;
+    dev->lmp_mode_change = bt_dummy_lmp_mode_change;
+    dev->lmp_connection_request = bt_dummy_lmp_connection_request;
+    dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave;
+
+    dev->handle_destroy = bt_dummy_destroy;
+
+    dev->net = net;
+    dev->next = net->slave;
+    net->slave = dev;
+}
+
+void bt_device_done(struct bt_device_s *dev)
+{
+    struct bt_device_s **p = &dev->net->slave;
+
+    while (*p && *p != dev)
+        p = &(*p)->next;
+    if (*p != dev) {
+        fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__,
+                        dev->lmp_name ?: "(null)");
+        exit(-1);
+    }
+
+    *p = dev->next;
+}
diff --git a/hw/bt.h b/hw/bt.h
new file mode 100644 (file)
index 0000000..c70be1c
--- /dev/null
+++ b/hw/bt.h
@@ -0,0 +1,105 @@
+/*
+ * QEMU Bluetooth HCI helpers.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * 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 of
+ * the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+/* BD Address */
+typedef struct {
+    uint8_t b[6];
+} __attribute__((packed)) bdaddr_t;
+
+#define BDADDR_ANY     (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
+#define BDADDR_ALL     (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
+#define BDADDR_LOCAL   (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+
+/* Copy, swap, convert BD Address */
+static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
+{
+    return memcmp(ba1, ba2, sizeof(bdaddr_t));
+}
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
+{
+    memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+#define BAINIT(orig)   { .b = {                \
+    (orig)->b[0], (orig)->b[1], (orig)->b[2],  \
+    (orig)->b[3], (orig)->b[4], (orig)->b[5],  \
+}, }
+
+/* The twisted structures of a bluetooth environment */
+struct bt_device_s;
+struct bt_scatternet_s;
+struct bt_piconet_s;
+struct bt_link_s;
+
+struct bt_scatternet_s {
+    struct bt_device_s *slave;
+};
+
+struct bt_link_s {
+    struct bt_device_s *slave, *host;
+    uint16_t handle;           /* Master (host) side handle */
+    uint16_t acl_interval;
+    enum {
+        acl_active,
+        acl_hold,
+        acl_sniff,
+        acl_parked,
+    } acl_mode;
+};
+
+struct bt_device_s {
+    int lt_addr;
+    bdaddr_t bd_addr;
+    int mtu;
+    int setup;
+    struct bt_scatternet_s *net;
+
+    uint8_t key[16];
+    int key_present;
+    uint8_t class[3];
+
+    uint8_t reject_reason;
+
+    uint64_t lmp_caps;
+    const char *lmp_name;
+    void (*lmp_connection_request)(struct bt_link_s *link);
+    void (*lmp_connection_complete)(struct bt_link_s *link);
+    void (*lmp_disconnect_master)(struct bt_link_s *link);
+    void (*lmp_disconnect_slave)(struct bt_link_s *link);
+    void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_mode_change)(struct bt_link_s *link);
+
+    void (*handle_destroy)(struct bt_device_s *device);
+    struct bt_device_s *next;  /* Next in the piconet/scatternet */
+
+    int inquiry_scan;
+    int page_scan;
+
+    uint16_t clkoff;   /* Note: Always little-endian */
+};
+
+/* bt.c */
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net);
+void bt_device_done(struct bt_device_s *dev);
index ae87b3f..bb1b1b2 100644 (file)
@@ -31,6 +31,7 @@
 #include "devices.h"
 #include "flash.h"
 #include "hw.h"
+#include "bt.h"
 
 /* Nokia N8x0 support */
 struct n800_s {
@@ -122,10 +123,6 @@ struct n800_s {
 
 #define N8X0_BD_ADDR                   0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
 
-typedef struct {
-    uint8_t b[6];
-} __attribute__((packed)) bdaddr_t;    /* XXX: move to BT headers */
-
 static void n800_mmc_cs_cb(void *opaque, int line, int level)
 {
     /* TODO: this seems to actually be connected to the menelaus, to
diff --git a/net.h b/net.h
index 5212b48..0d7ce77 100644 (file)
--- a/net.h
+++ b/net.h
@@ -48,6 +48,20 @@ struct NICInfo {
 extern int nb_nics;
 extern NICInfo nd_table[MAX_NICS];
 
+/* BT HCI info */
+
+struct HCIInfo {
+    int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr);
+    void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void *opaque;
+    void (*evt_recv)(void *opaque, const uint8_t *data, int len);
+    void (*acl_recv)(void *opaque, const uint8_t *data, int len);
+};
+
+struct HCIInfo *qemu_next_hci(void);
+
 /* checksumming functions (net-checksum.c) */
 uint32_t net_checksum_add(int len, uint8_t *buf);
 uint16_t net_checksum_finish(uint32_t sum);
index 23d1444..0731223 100644 (file)
@@ -116,6 +116,7 @@ typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size)
 /* A load of opaque types so that device init declarations don't have to
    pull in all the real definitions.  */
 typedef struct NICInfo NICInfo;
+typedef struct HCIInfo HCIInfo;
 typedef struct AudioState AudioState;
 typedef struct BlockDriverState BlockDriverState;
 typedef struct DisplayState DisplayState;
diff --git a/vl.c b/vl.c
index 481eb93..b19a631 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -29,6 +29,7 @@
 #include "hw/audiodev.h"
 #include "hw/isa.h"
 #include "hw/baum.h"
+#include "hw/bt.h"
 #include "net.h"
 #include "console.h"
 #include "sysemu.h"
@@ -5361,6 +5362,61 @@ void do_info_network(void)
     }
 }
 
+/***********************************************************/
+/* Bluetooth support */
+static int nb_hcis;
+static int cur_hci;
+static struct HCIInfo *hci_table[MAX_NICS];
+static struct bt_vlan_s {
+    struct bt_scatternet_s net;
+    int id;
+    struct bt_vlan_s *next;
+} *first_bt_vlan;
+
+/* find or alloc a new bluetooth "VLAN" */
+struct bt_scatternet_s *qemu_find_bt_vlan(int id)
+{
+    struct bt_vlan_s **pvlan, *vlan;
+    for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->id == id)
+            return &vlan->net;
+    }
+    vlan = qemu_mallocz(sizeof(struct bt_vlan_s));
+    vlan->id = id;
+    pvlan = &first_bt_vlan;
+    while (*pvlan != NULL)
+        pvlan = &(*pvlan)->next;
+    *pvlan = vlan;
+    return &vlan->net;
+}
+
+static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+}
+
+static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
+{
+    return -ENOTSUP;
+}
+
+static struct HCIInfo null_hci = {
+    .cmd_send = null_hci_send,
+    .sco_send = null_hci_send,
+    .acl_send = null_hci_send,
+    .bdaddr_set = null_hci_addr_set,
+};
+
+struct HCIInfo *qemu_next_hci(void)
+{
+    if (cur_hci == nb_hcis)
+        return &null_hci;
+
+    return hci_table[cur_hci++];
+}
+
+/***********************************************************/
+/* QEMU Block devices */
+
 #define HD_ALIAS "index=%d,media=disk"
 #ifdef TARGET_PPC
 #define CDROM_ALIAS "index=1,media=cdrom"