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" | ... | ... |