Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 169 lines (142 sloc) 4.588 kb
ab2b6f5 Use VHCI to allow the host os to participate in a qemu bluetooth "vlan".
balrog authored
1 /*
2 * Support for host VHCIs inside qemu scatternets.
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 *
fad6cb1 Update FSF address in GPL/LGPL boilerplate
aurel32 authored
16 * You should have received a copy of the GNU General Public License along
8167ee8 @blueswirl Update to a hopefully more future proof FSF address
blueswirl authored
17 * with this program; if not, see <http://www.gnu.org/licenses/>.
ab2b6f5 Use VHCI to allow the host os to participate in a qemu bluetooth "vlan".
balrog authored
18 */
19
20 #include "qemu-common.h"
21 #include "qemu-char.h"
22 #include "sysemu.h"
23 #include "net.h"
24 #include "hw/bt.h"
25
2e9b08e Disable bluetooth proxy compilation on win32.
balrog authored
26 #define VHCI_DEV "/dev/vhci"
ab2b6f5 Use VHCI to allow the host os to participate in a qemu bluetooth "vlan".
balrog authored
27 #define VHCI_UDEV "/dev/hci_vhci"
28
29 struct bt_vhci_s {
30 int fd;
31 struct HCIInfo *info;
32
33 uint8_t hdr[4096];
34 int len;
35 };
36
37 static void vhci_read(void *opaque)
38 {
39 struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
40 uint8_t *pkt;
41 int pktlen;
42
43 /* Seems that we can't read only the header first and then the amount
44 * of data indicated in the header because Linux will discard everything
45 * that's not been read in one go. */
46 s->len = read(s->fd, s->hdr, sizeof(s->hdr));
47
48 if (s->len < 0) {
49 fprintf(stderr, "qemu: error %i reading the PDU\n", errno);
50 return;
51 }
52
53 pkt = s->hdr;
54 while (s->len --)
55 switch (*pkt ++) {
56 case HCI_COMMAND_PKT:
57 if (s->len < 3)
58 goto bad_pkt;
59
60 pktlen = MIN(pkt[2] + 3, s->len);
61 s->info->cmd_send(s->info, pkt, pktlen);
62 s->len -= pktlen;
63 pkt += pktlen;
64 break;
65
66 case HCI_ACLDATA_PKT:
67 if (s->len < 4)
68 goto bad_pkt;
69
70 pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
71 s->info->acl_send(s->info, pkt, pktlen);
72 s->len -= pktlen;
73 pkt += pktlen;
74 break;
75
76 case HCI_SCODATA_PKT:
77 if (s->len < 3)
78 goto bad_pkt;
79
80 pktlen = MIN(pkt[2] + 3, s->len);
81 s->info->sco_send(s->info, pkt, pktlen);
82 s->len -= pktlen;
83 pkt += pktlen;
84 break;
85
86 default:
87 bad_pkt:
88 fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
89 }
90 }
91
92 static void vhci_host_send(void *opaque,
93 int type, const uint8_t *data, int len)
94 {
95 struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
96 #if 0
97 uint8_t pkt = type;
98 struct iovec iv[2];
99
100 iv[0].iov_base = &pkt;
101 iv[0].iov_len = 1;
102 iv[1].iov_base = (void *) data;
103 iv[1].iov_len = len;
104
105 while (writev(s->fd, iv, 2) < 0)
106 if (errno != EAGAIN && errno != EINTR) {
107 fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
108 errno);
109 return;
110 }
111 #else
112 /* Apparently VHCI wants us to write everything in one chunk :-( */
113 static uint8_t buf[4096];
114
115 buf[0] = type;
116 memcpy(buf + 1, data, len);
117
118 while (write(s->fd, buf, len + 1) < 0)
119 if (errno != EAGAIN && errno != EINTR) {
120 fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
121 errno);
122 return;
123 }
124 #endif
125 }
126
127 static void vhci_out_hci_packet_event(void *opaque,
128 const uint8_t *data, int len)
129 {
130 vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
131 }
132
133 static void vhci_out_hci_packet_acl(void *opaque,
134 const uint8_t *data, int len)
135 {
136 vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
137 }
138
139 void bt_vhci_init(struct HCIInfo *info)
140 {
141 struct bt_vhci_s *s;
142 int err[2];
143 int fd;
144
145 fd = open(VHCI_DEV, O_RDWR);
146 err[0] = errno;
147 if (fd < 0) {
148 fd = open(VHCI_UDEV, O_RDWR);
149 err[1] = errno;
150 }
151
152 if (fd < 0) {
153 fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
154 VHCI_DEV, strerror(err[0]), err[0]);
155 fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
156 VHCI_UDEV, strerror(err[1]), err[1]);
157 exit(-1);
158 }
159
160 s = qemu_mallocz(sizeof(struct bt_vhci_s));
161 s->fd = fd;
162 s->info = info ?: qemu_next_hci();
163 s->info->opaque = s;
164 s->info->evt_recv = vhci_out_hci_packet_event;
165 s->info->acl_recv = vhci_out_hci_packet_acl;
166
511d2b1 Sparse fixes: NULL use, header order, ANSI prototypes, static
blueswir1 authored
167 qemu_set_fd_handler(s->fd, vhci_read, NULL, s);
ab2b6f5 Use VHCI to allow the host os to participate in a qemu bluetooth "vlan".
balrog authored
168 }
Something went wrong with that request. Please try again.