Statistics
| Branch: | Revision:

root / hw / bt-hid.c @ ff753bb9

History | View | Annotate | Download (15.9 kB)

1 47e699dc balrog
/*
2 47e699dc balrog
 * QEMU Bluetooth HID Profile wrapper for USB HID.
3 47e699dc balrog
 *
4 47e699dc balrog
 * Copyright (C) 2007-2008 OpenMoko, Inc.
5 47e699dc balrog
 * Written by Andrzej Zaborowski <andrew@openedhand.com>
6 47e699dc balrog
 *
7 47e699dc balrog
 * This program is free software; you can redistribute it and/or
8 47e699dc balrog
 * modify it under the terms of the GNU General Public License as
9 47e699dc balrog
 * published by the Free Software Foundation; either version 2 or
10 47e699dc balrog
 * (at your option) version 3 of the License.
11 47e699dc balrog
 *
12 47e699dc balrog
 * This program is distributed in the hope that it will be useful,
13 47e699dc balrog
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 47e699dc balrog
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 47e699dc balrog
 * GNU General Public License for more details.
16 47e699dc balrog
 *
17 fad6cb1a aurel32
 * You should have received a copy of the GNU General Public License along
18 8167ee88 Blue Swirl
 * with this program; if not, if not, see <http://www.gnu.org/licenses/>.
19 47e699dc balrog
 */
20 47e699dc balrog
21 47e699dc balrog
#include "qemu-common.h"
22 47e699dc balrog
#include "usb.h"
23 47e699dc balrog
#include "bt.h"
24 47e699dc balrog
25 47e699dc balrog
enum hid_transaction_req {
26 47e699dc balrog
    BT_HANDSHAKE                        = 0x0,
27 47e699dc balrog
    BT_HID_CONTROL                        = 0x1,
28 47e699dc balrog
    BT_GET_REPORT                        = 0x4,
29 47e699dc balrog
    BT_SET_REPORT                        = 0x5,
30 47e699dc balrog
    BT_GET_PROTOCOL                        = 0x6,
31 47e699dc balrog
    BT_SET_PROTOCOL                        = 0x7,
32 47e699dc balrog
    BT_GET_IDLE                                = 0x8,
33 47e699dc balrog
    BT_SET_IDLE                                = 0x9,
34 47e699dc balrog
    BT_DATA                                = 0xa,
35 47e699dc balrog
    BT_DATC                                = 0xb,
36 47e699dc balrog
};
37 47e699dc balrog
38 47e699dc balrog
enum hid_transaction_handshake {
39 47e699dc balrog
    BT_HS_SUCCESSFUL                        = 0x0,
40 47e699dc balrog
    BT_HS_NOT_READY                        = 0x1,
41 47e699dc balrog
    BT_HS_ERR_INVALID_REPORT_ID                = 0x2,
42 47e699dc balrog
    BT_HS_ERR_UNSUPPORTED_REQUEST        = 0x3,
43 47e699dc balrog
    BT_HS_ERR_INVALID_PARAMETER                = 0x4,
44 47e699dc balrog
    BT_HS_ERR_UNKNOWN                        = 0xe,
45 47e699dc balrog
    BT_HS_ERR_FATAL                        = 0xf,
46 47e699dc balrog
};
47 47e699dc balrog
48 47e699dc balrog
enum hid_transaction_control {
49 47e699dc balrog
    BT_HC_NOP                                = 0x0,
50 47e699dc balrog
    BT_HC_HARD_RESET                        = 0x1,
51 47e699dc balrog
    BT_HC_SOFT_RESET                        = 0x2,
52 47e699dc balrog
    BT_HC_SUSPEND                        = 0x3,
53 47e699dc balrog
    BT_HC_EXIT_SUSPEND                        = 0x4,
54 47e699dc balrog
    BT_HC_VIRTUAL_CABLE_UNPLUG                = 0x5,
55 47e699dc balrog
};
56 47e699dc balrog
57 47e699dc balrog
enum hid_protocol {
58 47e699dc balrog
    BT_HID_PROTO_BOOT                        = 0,
59 47e699dc balrog
    BT_HID_PROTO_REPORT                        = 1,
60 47e699dc balrog
};
61 47e699dc balrog
62 47e699dc balrog
enum hid_boot_reportid {
63 47e699dc balrog
    BT_HID_BOOT_INVALID                        = 0,
64 47e699dc balrog
    BT_HID_BOOT_KEYBOARD,
65 47e699dc balrog
    BT_HID_BOOT_MOUSE,
66 47e699dc balrog
};
67 47e699dc balrog
68 47e699dc balrog
enum hid_data_pkt {
69 47e699dc balrog
    BT_DATA_OTHER                        = 0,
70 47e699dc balrog
    BT_DATA_INPUT,
71 47e699dc balrog
    BT_DATA_OUTPUT,
72 47e699dc balrog
    BT_DATA_FEATURE,
73 47e699dc balrog
};
74 47e699dc balrog
75 47e699dc balrog
#define BT_HID_MTU                        48
76 47e699dc balrog
77 47e699dc balrog
/* HID interface requests */
78 47e699dc balrog
#define GET_REPORT                        0xa101
79 47e699dc balrog
#define GET_IDLE                        0xa102
80 47e699dc balrog
#define GET_PROTOCOL                        0xa103
81 47e699dc balrog
#define SET_REPORT                        0x2109
82 47e699dc balrog
#define SET_IDLE                        0x210a
83 47e699dc balrog
#define SET_PROTOCOL                        0x210b
84 47e699dc balrog
85 47e699dc balrog
struct bt_hid_device_s {
86 47e699dc balrog
    struct bt_l2cap_device_s btdev;
87 47e699dc balrog
    struct bt_l2cap_conn_params_s *control;
88 47e699dc balrog
    struct bt_l2cap_conn_params_s *interrupt;
89 47e699dc balrog
    USBDevice *usbdev;
90 47e699dc balrog
91 47e699dc balrog
    int proto;
92 47e699dc balrog
    int connected;
93 47e699dc balrog
    int data_type;
94 47e699dc balrog
    int intr_state;
95 47e699dc balrog
    struct {
96 47e699dc balrog
        int len;
97 47e699dc balrog
        uint8_t buffer[1024];
98 47e699dc balrog
    } dataother, datain, dataout, feature, intrdataout;
99 47e699dc balrog
    enum {
100 47e699dc balrog
        bt_state_ready,
101 47e699dc balrog
        bt_state_transaction,
102 47e699dc balrog
        bt_state_suspend,
103 47e699dc balrog
    } state;
104 47e699dc balrog
};
105 47e699dc balrog
106 47e699dc balrog
static void bt_hid_reset(struct bt_hid_device_s *s)
107 47e699dc balrog
{
108 47e699dc balrog
    struct bt_scatternet_s *net = s->btdev.device.net;
109 47e699dc balrog
110 47e699dc balrog
    /* Go as far as... */
111 47e699dc balrog
    bt_l2cap_device_done(&s->btdev);
112 47e699dc balrog
    bt_l2cap_device_init(&s->btdev, net);
113 47e699dc balrog
114 806b6024 Gerd Hoffmann
    s->usbdev->info->handle_reset(s->usbdev);
115 47e699dc balrog
    s->proto = BT_HID_PROTO_REPORT;
116 47e699dc balrog
    s->state = bt_state_ready;
117 47e699dc balrog
    s->dataother.len = 0;
118 47e699dc balrog
    s->datain.len = 0;
119 47e699dc balrog
    s->dataout.len = 0;
120 47e699dc balrog
    s->feature.len = 0;
121 47e699dc balrog
    s->intrdataout.len = 0;
122 47e699dc balrog
    s->intr_state = 0;
123 47e699dc balrog
}
124 47e699dc balrog
125 47e699dc balrog
static int bt_hid_out(struct bt_hid_device_s *s)
126 47e699dc balrog
{
127 47e699dc balrog
    USBPacket p;
128 47e699dc balrog
129 47e699dc balrog
    if (s->data_type == BT_DATA_OUTPUT) {
130 47e699dc balrog
        p.pid = USB_TOKEN_OUT;
131 47e699dc balrog
        p.devep = 1;
132 47e699dc balrog
        p.data = s->dataout.buffer;
133 47e699dc balrog
        p.len = s->dataout.len;
134 806b6024 Gerd Hoffmann
        s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
135 47e699dc balrog
136 47e699dc balrog
        return s->dataout.len;
137 47e699dc balrog
    }
138 47e699dc balrog
139 47e699dc balrog
    if (s->data_type == BT_DATA_FEATURE) {
140 47e699dc balrog
        /* XXX:
141 47e699dc balrog
         * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
142 47e699dc balrog
         * or a SET_REPORT? */
143 47e699dc balrog
        p.devep = 0;
144 47e699dc balrog
    }
145 47e699dc balrog
146 47e699dc balrog
    return -1;
147 47e699dc balrog
}
148 47e699dc balrog
149 47e699dc balrog
static int bt_hid_in(struct bt_hid_device_s *s)
150 47e699dc balrog
{
151 47e699dc balrog
    USBPacket p;
152 47e699dc balrog
153 47e699dc balrog
    p.pid = USB_TOKEN_IN;
154 47e699dc balrog
    p.devep = 1;
155 47e699dc balrog
    p.data = s->datain.buffer;
156 47e699dc balrog
    p.len = sizeof(s->datain.buffer);
157 806b6024 Gerd Hoffmann
    s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
158 47e699dc balrog
159 47e699dc balrog
    return s->datain.len;
160 47e699dc balrog
}
161 47e699dc balrog
162 47e699dc balrog
static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
163 47e699dc balrog
{
164 47e699dc balrog
    *s->control->sdu_out(s->control, 1) =
165 47e699dc balrog
            (BT_HANDSHAKE << 4) | result;
166 47e699dc balrog
    s->control->sdu_submit(s->control);
167 47e699dc balrog
}
168 47e699dc balrog
169 47e699dc balrog
static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
170 47e699dc balrog
{
171 47e699dc balrog
    *s->control->sdu_out(s->control, 1) =
172 47e699dc balrog
            (BT_HID_CONTROL << 4) | operation;
173 47e699dc balrog
    s->control->sdu_submit(s->control);
174 47e699dc balrog
}
175 47e699dc balrog
176 47e699dc balrog
static void bt_hid_disconnect(struct bt_hid_device_s *s)
177 47e699dc balrog
{
178 47e699dc balrog
    /* Disconnect s->control and s->interrupt */
179 47e699dc balrog
}
180 47e699dc balrog
181 47e699dc balrog
static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
182 47e699dc balrog
                const uint8_t *data, int len)
183 47e699dc balrog
{
184 47e699dc balrog
    uint8_t *pkt, hdr = (BT_DATA << 4) | type;
185 47e699dc balrog
    int plen;
186 47e699dc balrog
187 47e699dc balrog
    do {
188 47e699dc balrog
        plen = MIN(len, ch->remote_mtu - 1);
189 47e699dc balrog
        pkt = ch->sdu_out(ch, plen + 1);
190 47e699dc balrog
191 47e699dc balrog
        pkt[0] = hdr;
192 47e699dc balrog
        if (plen)
193 47e699dc balrog
            memcpy(pkt + 1, data, plen);
194 47e699dc balrog
        ch->sdu_submit(ch);
195 47e699dc balrog
196 47e699dc balrog
        len -= plen;
197 47e699dc balrog
        data += plen;
198 47e699dc balrog
        hdr = (BT_DATC << 4) | type;
199 47e699dc balrog
    } while (plen == ch->remote_mtu - 1);
200 47e699dc balrog
}
201 47e699dc balrog
202 47e699dc balrog
static void bt_hid_control_transaction(struct bt_hid_device_s *s,
203 47e699dc balrog
                const uint8_t *data, int len)
204 47e699dc balrog
{
205 47e699dc balrog
    uint8_t type, parameter;
206 47e699dc balrog
    int rlen, ret = -1;
207 47e699dc balrog
    if (len < 1)
208 47e699dc balrog
        return;
209 47e699dc balrog
210 47e699dc balrog
    type = data[0] >> 4;
211 47e699dc balrog
    parameter = data[0] & 0xf;
212 47e699dc balrog
213 47e699dc balrog
    switch (type) {
214 47e699dc balrog
    case BT_HANDSHAKE:
215 47e699dc balrog
    case BT_DATA:
216 47e699dc balrog
        switch (parameter) {
217 47e699dc balrog
        default:
218 47e699dc balrog
            /* These are not expected to be sent this direction.  */
219 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
220 47e699dc balrog
        }
221 47e699dc balrog
        break;
222 47e699dc balrog
223 47e699dc balrog
    case BT_HID_CONTROL:
224 47e699dc balrog
        if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
225 47e699dc balrog
                                s->state == bt_state_transaction)) {
226 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
227 47e699dc balrog
            break;
228 47e699dc balrog
        }
229 47e699dc balrog
        switch (parameter) {
230 47e699dc balrog
        case BT_HC_NOP:
231 47e699dc balrog
            break;
232 47e699dc balrog
        case BT_HC_HARD_RESET:
233 47e699dc balrog
        case BT_HC_SOFT_RESET:
234 47e699dc balrog
            bt_hid_reset(s);
235 47e699dc balrog
            break;
236 47e699dc balrog
        case BT_HC_SUSPEND:
237 47e699dc balrog
            if (s->state == bt_state_ready)
238 47e699dc balrog
                s->state = bt_state_suspend;
239 47e699dc balrog
            else
240 47e699dc balrog
                ret = BT_HS_ERR_INVALID_PARAMETER;
241 47e699dc balrog
            break;
242 47e699dc balrog
        case BT_HC_EXIT_SUSPEND:
243 47e699dc balrog
            if (s->state == bt_state_suspend)
244 47e699dc balrog
                s->state = bt_state_ready;
245 47e699dc balrog
            else
246 47e699dc balrog
                ret = BT_HS_ERR_INVALID_PARAMETER;
247 47e699dc balrog
            break;
248 47e699dc balrog
        case BT_HC_VIRTUAL_CABLE_UNPLUG:
249 47e699dc balrog
            bt_hid_disconnect(s);
250 47e699dc balrog
            break;
251 47e699dc balrog
        default:
252 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
253 47e699dc balrog
        }
254 47e699dc balrog
        break;
255 47e699dc balrog
256 47e699dc balrog
    case BT_GET_REPORT:
257 47e699dc balrog
        /* No ReportIDs declared.  */
258 47e699dc balrog
        if (((parameter & 8) && len != 3) ||
259 47e699dc balrog
                        (!(parameter & 8) && len != 1) ||
260 47e699dc balrog
                        s->state != bt_state_ready) {
261 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
262 47e699dc balrog
            break;
263 47e699dc balrog
        }
264 47e699dc balrog
        if (parameter & 8)
265 47e699dc balrog
            rlen = data[2] | (data[3] << 8);
266 47e699dc balrog
        else
267 47e699dc balrog
            rlen = INT_MAX;
268 47e699dc balrog
        switch (parameter & 3) {
269 47e699dc balrog
        case BT_DATA_OTHER:
270 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
271 47e699dc balrog
            break;
272 47e699dc balrog
        case BT_DATA_INPUT:
273 47e699dc balrog
            /* Here we can as well poll s->usbdev */
274 47e699dc balrog
            bt_hid_send_data(s->control, BT_DATA_INPUT,
275 47e699dc balrog
                            s->datain.buffer, MIN(rlen, s->datain.len));
276 47e699dc balrog
            break;
277 47e699dc balrog
        case BT_DATA_OUTPUT:
278 47e699dc balrog
            bt_hid_send_data(s->control, BT_DATA_OUTPUT,
279 47e699dc balrog
                            s->dataout.buffer, MIN(rlen, s->dataout.len));
280 47e699dc balrog
            break;
281 47e699dc balrog
        case BT_DATA_FEATURE:
282 47e699dc balrog
            bt_hid_send_data(s->control, BT_DATA_FEATURE,
283 47e699dc balrog
                            s->feature.buffer, MIN(rlen, s->feature.len));
284 47e699dc balrog
            break;
285 47e699dc balrog
        }
286 47e699dc balrog
        break;
287 47e699dc balrog
288 47e699dc balrog
    case BT_SET_REPORT:
289 47e699dc balrog
        if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
290 47e699dc balrog
                        (parameter & 3) == BT_DATA_OTHER ||
291 47e699dc balrog
                        (parameter & 3) == BT_DATA_INPUT) {
292 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
293 47e699dc balrog
            break;
294 47e699dc balrog
        }
295 47e699dc balrog
        s->data_type = parameter & 3;
296 47e699dc balrog
        if (s->data_type == BT_DATA_OUTPUT) {
297 47e699dc balrog
            s->dataout.len = len - 1;
298 47e699dc balrog
            memcpy(s->dataout.buffer, data + 1, s->dataout.len);
299 47e699dc balrog
        } else {
300 47e699dc balrog
            s->feature.len = len - 1;
301 47e699dc balrog
            memcpy(s->feature.buffer, data + 1, s->feature.len);
302 47e699dc balrog
        }
303 47e699dc balrog
        if (len == BT_HID_MTU)
304 47e699dc balrog
            s->state = bt_state_transaction;
305 47e699dc balrog
        else
306 47e699dc balrog
            bt_hid_out(s);
307 47e699dc balrog
        break;
308 47e699dc balrog
309 47e699dc balrog
    case BT_GET_PROTOCOL:
310 47e699dc balrog
        if (len != 1 || s->state == bt_state_transaction) {
311 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
312 47e699dc balrog
            break;
313 47e699dc balrog
        }
314 47e699dc balrog
        *s->control->sdu_out(s->control, 1) = s->proto;
315 47e699dc balrog
        s->control->sdu_submit(s->control);
316 47e699dc balrog
        break;
317 47e699dc balrog
318 47e699dc balrog
    case BT_SET_PROTOCOL:
319 47e699dc balrog
        if (len != 1 || s->state == bt_state_transaction ||
320 47e699dc balrog
                        (parameter != BT_HID_PROTO_BOOT &&
321 47e699dc balrog
                         parameter != BT_HID_PROTO_REPORT)) {
322 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
323 47e699dc balrog
            break;
324 47e699dc balrog
        }
325 47e699dc balrog
        s->proto = parameter;
326 806b6024 Gerd Hoffmann
        s->usbdev->info->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
327 806b6024 Gerd Hoffmann
                                        NULL);
328 47e699dc balrog
        ret = BT_HS_SUCCESSFUL;
329 47e699dc balrog
        break;
330 47e699dc balrog
331 47e699dc balrog
    case BT_GET_IDLE:
332 47e699dc balrog
        if (len != 1 || s->state == bt_state_transaction) {
333 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
334 47e699dc balrog
            break;
335 47e699dc balrog
        }
336 806b6024 Gerd Hoffmann
        s->usbdev->info->handle_control(s->usbdev, GET_IDLE, 0, 0, 1,
337 47e699dc balrog
                        s->control->sdu_out(s->control, 1));
338 47e699dc balrog
        s->control->sdu_submit(s->control);
339 47e699dc balrog
        break;
340 47e699dc balrog
341 47e699dc balrog
    case BT_SET_IDLE:
342 47e699dc balrog
        if (len != 2 || s->state == bt_state_transaction) {
343 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
344 47e699dc balrog
            break;
345 47e699dc balrog
        }
346 47e699dc balrog
347 47e699dc balrog
        /* We don't need to know about the Idle Rate here really,
348 47e699dc balrog
         * so just pass it on to the device.  */
349 806b6024 Gerd Hoffmann
        ret = s->usbdev->info->handle_control(s->usbdev,
350 511d2b14 blueswir1
                        SET_IDLE, data[1], 0, 0, NULL) ?
351 47e699dc balrog
                BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
352 47e699dc balrog
        /* XXX: Does this generate a handshake? */
353 47e699dc balrog
        break;
354 47e699dc balrog
355 47e699dc balrog
    case BT_DATC:
356 47e699dc balrog
        if (len > BT_HID_MTU || s->state != bt_state_transaction) {
357 47e699dc balrog
            ret = BT_HS_ERR_INVALID_PARAMETER;
358 47e699dc balrog
            break;
359 47e699dc balrog
        }
360 47e699dc balrog
        if (s->data_type == BT_DATA_OUTPUT) {
361 47e699dc balrog
            memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
362 47e699dc balrog
            s->dataout.len += len - 1;
363 47e699dc balrog
        } else {
364 47e699dc balrog
            memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
365 47e699dc balrog
            s->feature.len += len - 1;
366 47e699dc balrog
        }
367 47e699dc balrog
        if (len < BT_HID_MTU) {
368 47e699dc balrog
            bt_hid_out(s);
369 47e699dc balrog
            s->state = bt_state_ready;
370 47e699dc balrog
        }
371 47e699dc balrog
        break;
372 47e699dc balrog
373 47e699dc balrog
    default:
374 47e699dc balrog
        ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
375 47e699dc balrog
    }
376 47e699dc balrog
377 47e699dc balrog
    if (ret != -1)
378 47e699dc balrog
        bt_hid_send_handshake(s, ret);
379 47e699dc balrog
}
380 47e699dc balrog
381 47e699dc balrog
static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
382 47e699dc balrog
{
383 47e699dc balrog
    struct bt_hid_device_s *hid = opaque;
384 47e699dc balrog
385 7442511c blueswir1
    bt_hid_control_transaction(hid, data, len);
386 47e699dc balrog
}
387 47e699dc balrog
388 47e699dc balrog
static void bt_hid_datain(void *opaque)
389 47e699dc balrog
{
390 47e699dc balrog
    struct bt_hid_device_s *hid = opaque;
391 47e699dc balrog
392 47e699dc balrog
    /* If suspended, wake-up and send a wake-up event first.  We might
393 47e699dc balrog
     * want to also inspect the input report and ignore event like
394 47e699dc balrog
     * mouse movements until a button event occurs.  */
395 47e699dc balrog
    if (hid->state == bt_state_suspend) {
396 47e699dc balrog
        hid->state = bt_state_ready;
397 47e699dc balrog
    }
398 47e699dc balrog
399 47e699dc balrog
    if (bt_hid_in(hid) > 0)
400 47e699dc balrog
        /* TODO: when in boot-mode precede any Input reports with the ReportID
401 47e699dc balrog
         * byte, here and in GetReport/SetReport on the Control channel.  */
402 47e699dc balrog
        bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
403 47e699dc balrog
                        hid->datain.buffer, hid->datain.len);
404 47e699dc balrog
}
405 47e699dc balrog
406 47e699dc balrog
static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
407 47e699dc balrog
{
408 47e699dc balrog
    struct bt_hid_device_s *hid = opaque;
409 47e699dc balrog
410 47e699dc balrog
    if (len > BT_HID_MTU || len < 1)
411 47e699dc balrog
        goto bad;
412 47e699dc balrog
    if ((data[0] & 3) != BT_DATA_OUTPUT)
413 47e699dc balrog
        goto bad;
414 47e699dc balrog
    if ((data[0] >> 4) == BT_DATA) {
415 47e699dc balrog
        if (hid->intr_state)
416 47e699dc balrog
            goto bad;
417 47e699dc balrog
418 47e699dc balrog
        hid->data_type = BT_DATA_OUTPUT;
419 47e699dc balrog
        hid->intrdataout.len = 0;
420 47e699dc balrog
    } else if ((data[0] >> 4) == BT_DATC) {
421 47e699dc balrog
        if (!hid->intr_state)
422 47e699dc balrog
            goto bad;
423 47e699dc balrog
    } else
424 47e699dc balrog
        goto bad;
425 47e699dc balrog
426 47e699dc balrog
    memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
427 47e699dc balrog
    hid->intrdataout.len += len - 1;
428 47e699dc balrog
    hid->intr_state = (len == BT_HID_MTU);
429 47e699dc balrog
    if (!hid->intr_state) {
430 47e699dc balrog
        memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
431 47e699dc balrog
                        hid->dataout.len = hid->intrdataout.len);
432 47e699dc balrog
        bt_hid_out(hid);
433 47e699dc balrog
    }
434 47e699dc balrog
435 47e699dc balrog
    return;
436 47e699dc balrog
bad:
437 47e699dc balrog
    fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
438 47e699dc balrog
                    __FUNCTION__);
439 47e699dc balrog
}
440 47e699dc balrog
441 47e699dc balrog
/* "Virtual cable" plug/unplug event.  */
442 47e699dc balrog
static void bt_hid_connected_update(struct bt_hid_device_s *hid)
443 47e699dc balrog
{
444 47e699dc balrog
    int prev = hid->connected;
445 47e699dc balrog
446 47e699dc balrog
    hid->connected = hid->control && hid->interrupt;
447 47e699dc balrog
448 47e699dc balrog
    /* Stop page-/inquiry-scanning when a host is connected.  */
449 47e699dc balrog
    hid->btdev.device.page_scan = !hid->connected;
450 47e699dc balrog
    hid->btdev.device.inquiry_scan = !hid->connected;
451 47e699dc balrog
452 47e699dc balrog
    if (hid->connected && !prev) {
453 806b6024 Gerd Hoffmann
        hid->usbdev->info->handle_reset(hid->usbdev);
454 47e699dc balrog
        hid->proto = BT_HID_PROTO_REPORT;
455 47e699dc balrog
    }
456 47e699dc balrog
457 47e699dc balrog
    /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
458 47e699dc balrog
     * isn't destroyed yet, in case we're being called from handle_destroy) */
459 47e699dc balrog
}
460 47e699dc balrog
461 47e699dc balrog
static void bt_hid_close_control(void *opaque)
462 47e699dc balrog
{
463 47e699dc balrog
    struct bt_hid_device_s *hid = opaque;
464 47e699dc balrog
465 511d2b14 blueswir1
    hid->control = NULL;
466 47e699dc balrog
    bt_hid_connected_update(hid);
467 47e699dc balrog
}
468 47e699dc balrog
469 47e699dc balrog
static void bt_hid_close_interrupt(void *opaque)
470 47e699dc balrog
{
471 47e699dc balrog
    struct bt_hid_device_s *hid = opaque;
472 47e699dc balrog
473 511d2b14 blueswir1
    hid->interrupt = NULL;
474 47e699dc balrog
    bt_hid_connected_update(hid);
475 47e699dc balrog
}
476 47e699dc balrog
477 47e699dc balrog
static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
478 47e699dc balrog
                struct bt_l2cap_conn_params_s *params)
479 47e699dc balrog
{
480 47e699dc balrog
    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
481 47e699dc balrog
482 47e699dc balrog
    if (hid->control)
483 47e699dc balrog
        return 1;
484 47e699dc balrog
485 47e699dc balrog
    hid->control = params;
486 47e699dc balrog
    hid->control->opaque = hid;
487 47e699dc balrog
    hid->control->close = bt_hid_close_control;
488 47e699dc balrog
    hid->control->sdu_in = bt_hid_control_sdu;
489 47e699dc balrog
490 47e699dc balrog
    bt_hid_connected_update(hid);
491 47e699dc balrog
492 47e699dc balrog
    return 0;
493 47e699dc balrog
}
494 47e699dc balrog
495 47e699dc balrog
static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
496 47e699dc balrog
                struct bt_l2cap_conn_params_s *params)
497 47e699dc balrog
{
498 47e699dc balrog
    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
499 47e699dc balrog
500 47e699dc balrog
    if (hid->interrupt)
501 47e699dc balrog
        return 1;
502 47e699dc balrog
503 47e699dc balrog
    hid->interrupt = params;
504 47e699dc balrog
    hid->interrupt->opaque = hid;
505 47e699dc balrog
    hid->interrupt->close = bt_hid_close_interrupt;
506 47e699dc balrog
    hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
507 47e699dc balrog
508 47e699dc balrog
    bt_hid_connected_update(hid);
509 47e699dc balrog
510 47e699dc balrog
    return 0;
511 47e699dc balrog
}
512 47e699dc balrog
513 47e699dc balrog
static void bt_hid_destroy(struct bt_device_s *dev)
514 47e699dc balrog
{
515 47e699dc balrog
    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
516 47e699dc balrog
517 47e699dc balrog
    if (hid->connected)
518 47e699dc balrog
        bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
519 47e699dc balrog
    bt_l2cap_device_done(&hid->btdev);
520 47e699dc balrog
521 806b6024 Gerd Hoffmann
    hid->usbdev->info->handle_destroy(hid->usbdev);
522 47e699dc balrog
523 47e699dc balrog
    qemu_free(hid);
524 47e699dc balrog
}
525 47e699dc balrog
526 47e699dc balrog
enum peripheral_minor_class {
527 47e699dc balrog
    class_other                = 0 << 4,
528 47e699dc balrog
    class_keyboard        = 1 << 4,
529 47e699dc balrog
    class_pointing        = 2 << 4,
530 47e699dc balrog
    class_combo                = 3 << 4,
531 47e699dc balrog
};
532 47e699dc balrog
533 47e699dc balrog
static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
534 47e699dc balrog
                USBDevice *dev, enum peripheral_minor_class minor)
535 47e699dc balrog
{
536 47e699dc balrog
    struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
537 47e699dc balrog
    uint32_t class =
538 47e699dc balrog
            /* Format type */
539 47e699dc balrog
            (0 << 0) |
540 47e699dc balrog
            /* Device class */
541 47e699dc balrog
            (minor << 2) |
542 47e699dc balrog
            (5 << 8) |  /* "Peripheral" */
543 47e699dc balrog
            /* Service classes */
544 47e699dc balrog
            (1 << 13) | /* Limited discoverable mode */
545 47e699dc balrog
            (1 << 19);  /* Capturing device (?) */
546 47e699dc balrog
547 47e699dc balrog
    bt_l2cap_device_init(&s->btdev, net);
548 47e699dc balrog
    bt_l2cap_sdp_init(&s->btdev);
549 47e699dc balrog
    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
550 47e699dc balrog
                    BT_HID_MTU, bt_hid_new_control_ch);
551 47e699dc balrog
    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
552 47e699dc balrog
                    BT_HID_MTU, bt_hid_new_interrupt_ch);
553 47e699dc balrog
554 47e699dc balrog
    s->usbdev = dev;
555 0fe6d12e Markus Armbruster
    s->btdev.device.lmp_name = s->usbdev->product_desc;
556 47e699dc balrog
    usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
557 47e699dc balrog
558 47e699dc balrog
    s->btdev.device.handle_destroy = bt_hid_destroy;
559 47e699dc balrog
560 47e699dc balrog
    s->btdev.device.class[0] = (class >>  0) & 0xff;
561 47e699dc balrog
    s->btdev.device.class[1] = (class >>  8) & 0xff;
562 47e699dc balrog
    s->btdev.device.class[2] = (class >> 16) & 0xff;
563 47e699dc balrog
564 47e699dc balrog
    return &s->btdev.device;
565 47e699dc balrog
}
566 47e699dc balrog
567 47e699dc balrog
struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
568 47e699dc balrog
{
569 556cd098 Markus Armbruster
    USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
570 a5d2f727 Gerd Hoffmann
    return bt_hid_init(net, dev, class_keyboard);
571 47e699dc balrog
}