Commit 1ae26a18a33263330e1551abf5244d68f8aa825a
1 parent
c0d82995
Add a "null" bluetooth HCI and a header file for bluetooth.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5342 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
7 changed files
with
301 additions
and
4 deletions
Makefile
hw/bt.c
0 → 100644
| 1 | +/* | |
| 2 | + * Convenience functions for bluetooth. | |
| 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 "net.h" | |
| 24 | +#include "bt.h" | |
| 25 | + | |
| 26 | +/* Slave implementations can ignore this */ | |
| 27 | +static void bt_dummy_lmp_mode_change(struct bt_link_s *link) | |
| 28 | +{ | |
| 29 | +} | |
| 30 | + | |
| 31 | +/* Slaves should never receive these PDUs */ | |
| 32 | +static void bt_dummy_lmp_connection_complete(struct bt_link_s *link) | |
| 33 | +{ | |
| 34 | + if (link->slave->reject_reason) | |
| 35 | + fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n", | |
| 36 | + __FUNCTION__); | |
| 37 | + else | |
| 38 | + fprintf(stderr, "%s: stray LMP_accepted received, fixme\n", | |
| 39 | + __FUNCTION__); | |
| 40 | + exit(-1); | |
| 41 | +} | |
| 42 | + | |
| 43 | +static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link) | |
| 44 | +{ | |
| 45 | + fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__); | |
| 46 | + exit(-1); | |
| 47 | +} | |
| 48 | + | |
| 49 | +static void bt_dummy_lmp_acl_resp(struct bt_link_s *link, | |
| 50 | + const uint8_t *data, int start, int len) | |
| 51 | +{ | |
| 52 | + fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__); | |
| 53 | + exit(-1); | |
| 54 | +} | |
| 55 | + | |
| 56 | +/* Slaves that don't hold any additional per link state can use these */ | |
| 57 | +static void bt_dummy_lmp_connection_request(struct bt_link_s *req) | |
| 58 | +{ | |
| 59 | + struct bt_link_s *link = qemu_mallocz(sizeof(struct bt_link_s)); | |
| 60 | + | |
| 61 | + link->slave = req->slave; | |
| 62 | + link->host = req->host; | |
| 63 | + | |
| 64 | + req->host->reject_reason = 0; | |
| 65 | + req->host->lmp_connection_complete(link); | |
| 66 | +} | |
| 67 | + | |
| 68 | +static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link) | |
| 69 | +{ | |
| 70 | + qemu_free(link); | |
| 71 | +} | |
| 72 | + | |
| 73 | +static void bt_dummy_destroy(struct bt_device_s *device) | |
| 74 | +{ | |
| 75 | + bt_device_done(device); | |
| 76 | + qemu_free(device); | |
| 77 | +} | |
| 78 | + | |
| 79 | +static int bt_dev_idx = 0; | |
| 80 | + | |
| 81 | +void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net) | |
| 82 | +{ | |
| 83 | + memset(dev, 0, sizeof(*dev)); | |
| 84 | + dev->inquiry_scan = 1; | |
| 85 | + dev->page_scan = 1; | |
| 86 | + | |
| 87 | + dev->bd_addr.b[0] = bt_dev_idx & 0xff; | |
| 88 | + dev->bd_addr.b[1] = bt_dev_idx >> 8; | |
| 89 | + dev->bd_addr.b[2] = 0xd0; | |
| 90 | + dev->bd_addr.b[3] = 0xba; | |
| 91 | + dev->bd_addr.b[4] = 0xbe; | |
| 92 | + dev->bd_addr.b[5] = 0xba; | |
| 93 | + bt_dev_idx ++; | |
| 94 | + | |
| 95 | + /* Simple slave-only devices need to implement only .lmp_acl_data */ | |
| 96 | + dev->lmp_connection_complete = bt_dummy_lmp_connection_complete; | |
| 97 | + dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master; | |
| 98 | + dev->lmp_acl_resp = bt_dummy_lmp_acl_resp; | |
| 99 | + dev->lmp_mode_change = bt_dummy_lmp_mode_change; | |
| 100 | + dev->lmp_connection_request = bt_dummy_lmp_connection_request; | |
| 101 | + dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave; | |
| 102 | + | |
| 103 | + dev->handle_destroy = bt_dummy_destroy; | |
| 104 | + | |
| 105 | + dev->net = net; | |
| 106 | + dev->next = net->slave; | |
| 107 | + net->slave = dev; | |
| 108 | +} | |
| 109 | + | |
| 110 | +void bt_device_done(struct bt_device_s *dev) | |
| 111 | +{ | |
| 112 | + struct bt_device_s **p = &dev->net->slave; | |
| 113 | + | |
| 114 | + while (*p && *p != dev) | |
| 115 | + p = &(*p)->next; | |
| 116 | + if (*p != dev) { | |
| 117 | + fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__, | |
| 118 | + dev->lmp_name ?: "(null)"); | |
| 119 | + exit(-1); | |
| 120 | + } | |
| 121 | + | |
| 122 | + *p = dev->next; | |
| 123 | +} | ... | ... |
hw/bt.h
0 → 100644
| 1 | +/* | |
| 2 | + * QEMU Bluetooth HCI helpers. | |
| 3 | + * | |
| 4 | + * Copyright (C) 2007 OpenMoko, Inc. | |
| 5 | + * Written by Andrzej Zaborowski <andrew@openedhand.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or | |
| 8 | + * modify it under the terms of the GNU General Public License as | |
| 9 | + * published by the Free Software Foundation; either version 2 of | |
| 10 | + * the License, or (at your option) any later version. | |
| 11 | + * | |
| 12 | + * This program is distributed in the hope that it will be useful, | |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 | + * GNU General Public License for more details. | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License | |
| 18 | + * along with this program; if not, write to the Free Software | |
| 19 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | |
| 20 | + * MA 02110-1301 USA | |
| 21 | + */ | |
| 22 | + | |
| 23 | +/* BD Address */ | |
| 24 | +typedef struct { | |
| 25 | + uint8_t b[6]; | |
| 26 | +} __attribute__((packed)) bdaddr_t; | |
| 27 | + | |
| 28 | +#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) | |
| 29 | +#define BDADDR_ALL (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}) | |
| 30 | +#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) | |
| 31 | + | |
| 32 | +/* Copy, swap, convert BD Address */ | |
| 33 | +static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2) | |
| 34 | +{ | |
| 35 | + return memcmp(ba1, ba2, sizeof(bdaddr_t)); | |
| 36 | +} | |
| 37 | +static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src) | |
| 38 | +{ | |
| 39 | + memcpy(dst, src, sizeof(bdaddr_t)); | |
| 40 | +} | |
| 41 | + | |
| 42 | +#define BAINIT(orig) { .b = { \ | |
| 43 | + (orig)->b[0], (orig)->b[1], (orig)->b[2], \ | |
| 44 | + (orig)->b[3], (orig)->b[4], (orig)->b[5], \ | |
| 45 | +}, } | |
| 46 | + | |
| 47 | +/* The twisted structures of a bluetooth environment */ | |
| 48 | +struct bt_device_s; | |
| 49 | +struct bt_scatternet_s; | |
| 50 | +struct bt_piconet_s; | |
| 51 | +struct bt_link_s; | |
| 52 | + | |
| 53 | +struct bt_scatternet_s { | |
| 54 | + struct bt_device_s *slave; | |
| 55 | +}; | |
| 56 | + | |
| 57 | +struct bt_link_s { | |
| 58 | + struct bt_device_s *slave, *host; | |
| 59 | + uint16_t handle; /* Master (host) side handle */ | |
| 60 | + uint16_t acl_interval; | |
| 61 | + enum { | |
| 62 | + acl_active, | |
| 63 | + acl_hold, | |
| 64 | + acl_sniff, | |
| 65 | + acl_parked, | |
| 66 | + } acl_mode; | |
| 67 | +}; | |
| 68 | + | |
| 69 | +struct bt_device_s { | |
| 70 | + int lt_addr; | |
| 71 | + bdaddr_t bd_addr; | |
| 72 | + int mtu; | |
| 73 | + int setup; | |
| 74 | + struct bt_scatternet_s *net; | |
| 75 | + | |
| 76 | + uint8_t key[16]; | |
| 77 | + int key_present; | |
| 78 | + uint8_t class[3]; | |
| 79 | + | |
| 80 | + uint8_t reject_reason; | |
| 81 | + | |
| 82 | + uint64_t lmp_caps; | |
| 83 | + const char *lmp_name; | |
| 84 | + void (*lmp_connection_request)(struct bt_link_s *link); | |
| 85 | + void (*lmp_connection_complete)(struct bt_link_s *link); | |
| 86 | + void (*lmp_disconnect_master)(struct bt_link_s *link); | |
| 87 | + void (*lmp_disconnect_slave)(struct bt_link_s *link); | |
| 88 | + void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data, | |
| 89 | + int start, int len); | |
| 90 | + void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data, | |
| 91 | + int start, int len); | |
| 92 | + void (*lmp_mode_change)(struct bt_link_s *link); | |
| 93 | + | |
| 94 | + void (*handle_destroy)(struct bt_device_s *device); | |
| 95 | + struct bt_device_s *next; /* Next in the piconet/scatternet */ | |
| 96 | + | |
| 97 | + int inquiry_scan; | |
| 98 | + int page_scan; | |
| 99 | + | |
| 100 | + uint16_t clkoff; /* Note: Always little-endian */ | |
| 101 | +}; | |
| 102 | + | |
| 103 | +/* bt.c */ | |
| 104 | +void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net); | |
| 105 | +void bt_device_done(struct bt_device_s *dev); | ... | ... |
hw/nseries.c
| ... | ... | @@ -31,6 +31,7 @@ |
| 31 | 31 | #include "devices.h" |
| 32 | 32 | #include "flash.h" |
| 33 | 33 | #include "hw.h" |
| 34 | +#include "bt.h" | |
| 34 | 35 | |
| 35 | 36 | /* Nokia N8x0 support */ |
| 36 | 37 | struct n800_s { |
| ... | ... | @@ -122,10 +123,6 @@ struct n800_s { |
| 122 | 123 | |
| 123 | 124 | #define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81 |
| 124 | 125 | |
| 125 | -typedef struct { | |
| 126 | - uint8_t b[6]; | |
| 127 | -} __attribute__((packed)) bdaddr_t; /* XXX: move to BT headers */ | |
| 128 | - | |
| 129 | 126 | static void n800_mmc_cs_cb(void *opaque, int line, int level) |
| 130 | 127 | { |
| 131 | 128 | /* TODO: this seems to actually be connected to the menelaus, to | ... | ... |
net.h
| ... | ... | @@ -48,6 +48,20 @@ struct NICInfo { |
| 48 | 48 | extern int nb_nics; |
| 49 | 49 | extern NICInfo nd_table[MAX_NICS]; |
| 50 | 50 | |
| 51 | +/* BT HCI info */ | |
| 52 | + | |
| 53 | +struct HCIInfo { | |
| 54 | + int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr); | |
| 55 | + void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len); | |
| 56 | + void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len); | |
| 57 | + void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len); | |
| 58 | + void *opaque; | |
| 59 | + void (*evt_recv)(void *opaque, const uint8_t *data, int len); | |
| 60 | + void (*acl_recv)(void *opaque, const uint8_t *data, int len); | |
| 61 | +}; | |
| 62 | + | |
| 63 | +struct HCIInfo *qemu_next_hci(void); | |
| 64 | + | |
| 51 | 65 | /* checksumming functions (net-checksum.c) */ |
| 52 | 66 | uint32_t net_checksum_add(int len, uint8_t *buf); |
| 53 | 67 | uint16_t net_checksum_finish(uint32_t sum); | ... | ... |
qemu-common.h
| ... | ... | @@ -116,6 +116,7 @@ typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size) |
| 116 | 116 | /* A load of opaque types so that device init declarations don't have to |
| 117 | 117 | pull in all the real definitions. */ |
| 118 | 118 | typedef struct NICInfo NICInfo; |
| 119 | +typedef struct HCIInfo HCIInfo; | |
| 119 | 120 | typedef struct AudioState AudioState; |
| 120 | 121 | typedef struct BlockDriverState BlockDriverState; |
| 121 | 122 | typedef struct DisplayState DisplayState; | ... | ... |
vl.c
| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | #include "hw/audiodev.h" |
| 30 | 30 | #include "hw/isa.h" |
| 31 | 31 | #include "hw/baum.h" |
| 32 | +#include "hw/bt.h" | |
| 32 | 33 | #include "net.h" |
| 33 | 34 | #include "console.h" |
| 34 | 35 | #include "sysemu.h" |
| ... | ... | @@ -5361,6 +5362,61 @@ void do_info_network(void) |
| 5361 | 5362 | } |
| 5362 | 5363 | } |
| 5363 | 5364 | |
| 5365 | +/***********************************************************/ | |
| 5366 | +/* Bluetooth support */ | |
| 5367 | +static int nb_hcis; | |
| 5368 | +static int cur_hci; | |
| 5369 | +static struct HCIInfo *hci_table[MAX_NICS]; | |
| 5370 | +static struct bt_vlan_s { | |
| 5371 | + struct bt_scatternet_s net; | |
| 5372 | + int id; | |
| 5373 | + struct bt_vlan_s *next; | |
| 5374 | +} *first_bt_vlan; | |
| 5375 | + | |
| 5376 | +/* find or alloc a new bluetooth "VLAN" */ | |
| 5377 | +struct bt_scatternet_s *qemu_find_bt_vlan(int id) | |
| 5378 | +{ | |
| 5379 | + struct bt_vlan_s **pvlan, *vlan; | |
| 5380 | + for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) { | |
| 5381 | + if (vlan->id == id) | |
| 5382 | + return &vlan->net; | |
| 5383 | + } | |
| 5384 | + vlan = qemu_mallocz(sizeof(struct bt_vlan_s)); | |
| 5385 | + vlan->id = id; | |
| 5386 | + pvlan = &first_bt_vlan; | |
| 5387 | + while (*pvlan != NULL) | |
| 5388 | + pvlan = &(*pvlan)->next; | |
| 5389 | + *pvlan = vlan; | |
| 5390 | + return &vlan->net; | |
| 5391 | +} | |
| 5392 | + | |
| 5393 | +static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len) | |
| 5394 | +{ | |
| 5395 | +} | |
| 5396 | + | |
| 5397 | +static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr) | |
| 5398 | +{ | |
| 5399 | + return -ENOTSUP; | |
| 5400 | +} | |
| 5401 | + | |
| 5402 | +static struct HCIInfo null_hci = { | |
| 5403 | + .cmd_send = null_hci_send, | |
| 5404 | + .sco_send = null_hci_send, | |
| 5405 | + .acl_send = null_hci_send, | |
| 5406 | + .bdaddr_set = null_hci_addr_set, | |
| 5407 | +}; | |
| 5408 | + | |
| 5409 | +struct HCIInfo *qemu_next_hci(void) | |
| 5410 | +{ | |
| 5411 | + if (cur_hci == nb_hcis) | |
| 5412 | + return &null_hci; | |
| 5413 | + | |
| 5414 | + return hci_table[cur_hci++]; | |
| 5415 | +} | |
| 5416 | + | |
| 5417 | +/***********************************************************/ | |
| 5418 | +/* QEMU Block devices */ | |
| 5419 | + | |
| 5364 | 5420 | #define HD_ALIAS "index=%d,media=disk" |
| 5365 | 5421 | #ifdef TARGET_PPC |
| 5366 | 5422 | #define CDROM_ALIAS "index=1,media=cdrom" | ... | ... |