core.c 22.1 KB
Newer Older
B
bellard 已提交
1 2 3 4
/*
 * QEMU USB emulation
 *
 * Copyright (c) 2005 Fabrice Bellard
5
 *
6 7
 * 2008 Generic packet handler rewrite by Max Krasnyansky
 *
B
bellard 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
P
pbrook 已提交
26
#include "qemu-common.h"
G
Gerd Hoffmann 已提交
27
#include "hw/usb.h"
28
#include "qemu/iov.h"
29
#include "trace.h"
B
bellard 已提交
30

31
void usb_attach(USBPort *port)
B
bellard 已提交
32
{
33 34 35 36
    USBDevice *dev = port->dev;

    assert(dev != NULL);
    assert(dev->attached);
G
Gerd Hoffmann 已提交
37
    assert(dev->state == USB_STATE_NOTATTACHED);
38
    port->ops->attach(port);
39 40
    dev->state = USB_STATE_ATTACHED;
    usb_device_handle_attach(dev);
41 42 43 44 45 46 47
}

void usb_detach(USBPort *port)
{
    USBDevice *dev = port->dev;

    assert(dev != NULL);
G
Gerd Hoffmann 已提交
48
    assert(dev->state != USB_STATE_NOTATTACHED);
49
    port->ops->detach(port);
50
    dev->state = USB_STATE_NOTATTACHED;
B
bellard 已提交
51 52
}

G
Gerd Hoffmann 已提交
53
void usb_port_reset(USBPort *port)
G
Gerd Hoffmann 已提交
54 55 56 57 58 59
{
    USBDevice *dev = port->dev;

    assert(dev != NULL);
    usb_detach(port);
    usb_attach(port);
G
Gerd Hoffmann 已提交
60 61 62 63 64 65 66 67 68 69 70 71
    usb_device_reset(dev);
}

void usb_device_reset(USBDevice *dev)
{
    if (dev == NULL || !dev->attached) {
        return;
    }
    dev->remote_wakeup = 0;
    dev->addr = 0;
    dev->state = USB_STATE_DEFAULT;
    usb_device_handle_reset(dev);
G
Gerd Hoffmann 已提交
72 73
}

G
Gerd Hoffmann 已提交
74
void usb_wakeup(USBEndpoint *ep, unsigned int stream)
75
{
76
    USBDevice *dev = ep->dev;
77
    USBBus *bus = usb_bus_from_device(dev);
78

79
    if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
80
        dev->port->ops->wakeup(dev->port);
81
    }
82
    if (bus->ops->wakeup_endpoint) {
G
Gerd Hoffmann 已提交
83
        bus->ops->wakeup_endpoint(bus, ep, stream);
84
    }
85 86
}

B
bellard 已提交
87
/**********************/
88

B
bellard 已提交
89 90
/* generic USB device helpers (you are not forced to use them when
   writing your USB device driver, but they help handling the
91
   protocol)
B
bellard 已提交
92 93
*/

94 95 96 97
#define SETUP_STATE_IDLE  0
#define SETUP_STATE_SETUP 1
#define SETUP_STATE_DATA  2
#define SETUP_STATE_ACK   3
98
#define SETUP_STATE_PARAM 4
B
bellard 已提交
99

100
static void do_token_setup(USBDevice *s, USBPacket *p)
101 102 103
{
    int request, value, index;

G
Gerd Hoffmann 已提交
104
    if (p->iov.size != 8) {
105 106
        p->status = USB_RET_STALL;
        return;
G
Gerd Hoffmann 已提交
107 108 109
    }

    usb_packet_copy(p, s->setup_buf, p->iov.size);
110
    p->actual_length = 0;
111 112 113 114 115 116
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
    s->setup_index = 0;

    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
117

118
    if (s->setup_buf[0] & USB_DIR_IN) {
119 120 121 122 123 124 125
        usb_device_handle_control(s, p, request, value, index,
                                  s->setup_len, s->data_buf);
        if (p->status == USB_RET_ASYNC) {
            s->setup_state = SETUP_STATE_SETUP;
        }
        if (p->status != USB_RET_SUCCESS) {
            return;
126
        }
127

128 129 130
        if (p->actual_length < s->setup_len) {
            s->setup_len = p->actual_length;
        }
131 132
        s->setup_state = SETUP_STATE_DATA;
    } else {
H
Hans de Goede 已提交
133 134 135 136
        if (s->setup_len > sizeof(s->data_buf)) {
            fprintf(stderr,
                "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
                s->setup_len, sizeof(s->data_buf));
137 138
            p->status = USB_RET_STALL;
            return;
H
Hans de Goede 已提交
139
        }
140 141 142 143 144 145
        if (s->setup_len == 0)
            s->setup_state = SETUP_STATE_ACK;
        else
            s->setup_state = SETUP_STATE_DATA;
    }

146
    p->actual_length = 8;
147 148
}

149
static void do_token_in(USBDevice *s, USBPacket *p)
B
bellard 已提交
150
{
151 152
    int request, value, index;

153
    assert(p->ep->nr == 0);
154 155 156 157 158 159 160 161

    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
 
    switch(s->setup_state) {
    case SETUP_STATE_ACK:
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
162 163 164 165
            usb_device_handle_control(s, p, request, value, index,
                                      s->setup_len, s->data_buf);
            if (p->status == USB_RET_ASYNC) {
                return;
166 167
            }
            s->setup_state = SETUP_STATE_IDLE;
168
            p->actual_length = 0;
169
        }
170
        break;
171 172 173 174

    case SETUP_STATE_DATA:
        if (s->setup_buf[0] & USB_DIR_IN) {
            int len = s->setup_len - s->setup_index;
G
Gerd Hoffmann 已提交
175 176 177 178
            if (len > p->iov.size) {
                len = p->iov.size;
            }
            usb_packet_copy(p, s->data_buf + s->setup_index, len);
179
            s->setup_index += len;
180
            if (s->setup_index >= s->setup_len) {
181
                s->setup_state = SETUP_STATE_ACK;
182 183
            }
            return;
184 185
        }
        s->setup_state = SETUP_STATE_IDLE;
186 187
        p->status = USB_RET_STALL;
        break;
188 189

    default:
190
        p->status = USB_RET_STALL;
191 192 193
    }
}

194
static void do_token_out(USBDevice *s, USBPacket *p)
195
{
196
    assert(p->ep->nr == 0);
197 198 199 200 201 202 203 204 205

    switch(s->setup_state) {
    case SETUP_STATE_ACK:
        if (s->setup_buf[0] & USB_DIR_IN) {
            s->setup_state = SETUP_STATE_IDLE;
            /* transfer OK */
        } else {
            /* ignore additional output */
        }
206
        break;
207 208 209 210

    case SETUP_STATE_DATA:
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
            int len = s->setup_len - s->setup_index;
G
Gerd Hoffmann 已提交
211 212 213 214
            if (len > p->iov.size) {
                len = p->iov.size;
            }
            usb_packet_copy(p, s->data_buf + s->setup_index, len);
215
            s->setup_index += len;
216
            if (s->setup_index >= s->setup_len) {
217
                s->setup_state = SETUP_STATE_ACK;
218 219
            }
            return;
220 221
        }
        s->setup_state = SETUP_STATE_IDLE;
222 223
        p->status = USB_RET_STALL;
        break;
224 225

    default:
226
        p->status = USB_RET_STALL;
227 228
    }
}
B
bellard 已提交
229

230
static void do_parameter(USBDevice *s, USBPacket *p)
231
{
232
    int i, request, value, index;
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

    for (i = 0; i < 8; i++) {
        s->setup_buf[i] = p->parameter >> (i*8);
    }

    s->setup_state = SETUP_STATE_PARAM;
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
    s->setup_index = 0;

    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];

    if (s->setup_len > sizeof(s->data_buf)) {
        fprintf(stderr,
                "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
                s->setup_len, sizeof(s->data_buf));
250 251
        p->status = USB_RET_STALL;
        return;
252 253 254 255 256 257
    }

    if (p->pid == USB_TOKEN_OUT) {
        usb_packet_copy(p, s->data_buf, s->setup_len);
    }

258 259 260 261
    usb_device_handle_control(s, p, request, value, index,
                              s->setup_len, s->data_buf);
    if (p->status == USB_RET_ASYNC) {
        return;
262 263
    }

264 265
    if (p->actual_length < s->setup_len) {
        s->setup_len = p->actual_length;
266 267
    }
    if (p->pid == USB_TOKEN_IN) {
268
        p->actual_length = 0;
269 270 271 272
        usb_packet_copy(p, s->data_buf, s->setup_len);
    }
}

273 274 275 276 277 278
/* ctrl complete function for devices which use usb_generic_handle_packet and
   may return USB_RET_ASYNC from their handle_control callback. Device code
   which does this *must* call this function instead of the normal
   usb_packet_complete to complete their async control packets. */
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
{
279
    if (p->status < 0) {
280 281 282 283 284
        s->setup_state = SETUP_STATE_IDLE;
    }

    switch (s->setup_state) {
    case SETUP_STATE_SETUP:
285 286
        if (p->actual_length < s->setup_len) {
            s->setup_len = p->actual_length;
287 288
        }
        s->setup_state = SETUP_STATE_DATA;
289
        p->actual_length = 8;
290 291 292 293
        break;

    case SETUP_STATE_ACK:
        s->setup_state = SETUP_STATE_IDLE;
294
        p->actual_length = 0;
295 296
        break;

297
    case SETUP_STATE_PARAM:
298 299
        if (p->actual_length < s->setup_len) {
            s->setup_len = p->actual_length;
300 301
        }
        if (p->pid == USB_TOKEN_IN) {
302
            p->actual_length = 0;
303 304 305 306
            usb_packet_copy(p, s->data_buf, s->setup_len);
        }
        break;

307 308 309 310 311 312
    default:
        break;
    }
    usb_packet_complete(s, p);
}

B
bellard 已提交
313 314 315 316 317 318 319 320
/* XXX: fix overflow */
int set_usb_string(uint8_t *buf, const char *str)
{
    int len, i;
    uint8_t *q;

    q = buf;
    len = strlen(str);
P
pbrook 已提交
321
    *q++ = 2 * len + 2;
B
bellard 已提交
322 323 324 325 326 327 328
    *q++ = 3;
    for(i = 0; i < len; i++) {
        *q++ = str[i];
        *q++ = 0;
    }
    return q - buf;
}
P
pbrook 已提交
329

G
Gerd Hoffmann 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342
USBDevice *usb_find_device(USBPort *port, uint8_t addr)
{
    USBDevice *dev = port->dev;

    if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT) {
        return NULL;
    }
    if (dev->addr == addr) {
        return dev;
    }
    return usb_device_find_device(dev, addr);
}

343
static void usb_process_one(USBPacket *p)
344 345 346
{
    USBDevice *dev = p->ep->dev;

347 348 349 350 351 352 353
    /*
     * Handlers expect status to be initialized to USB_RET_SUCCESS, but it
     * can be USB_RET_NAK here from a previous usb_process_one() call,
     * or USB_RET_ASYNC from going through usb_queue_one().
     */
    p->status = USB_RET_SUCCESS;

354 355
    if (p->ep->nr == 0) {
        /* control pipe */
356
        if (p->parameter) {
357 358
            do_parameter(dev, p);
            return;
359
        }
360 361
        switch (p->pid) {
        case USB_TOKEN_SETUP:
362 363
            do_token_setup(dev, p);
            break;
364
        case USB_TOKEN_IN:
365 366
            do_token_in(dev, p);
            break;
367
        case USB_TOKEN_OUT:
368 369
            do_token_out(dev, p);
            break;
370
        default:
371
            p->status = USB_RET_STALL;
372 373 374
        }
    } else {
        /* data pipe */
375
        usb_device_handle_data(dev, p);
376 377 378
    }
}

379 380 381 382 383 384 385 386
static void usb_queue_one(USBPacket *p)
{
    usb_packet_set_state(p, USB_PACKET_QUEUED);
    QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
    p->status = USB_RET_ASYNC;
}

/* Hand over a packet to a device for processing.  p->status ==
G
Gerd Hoffmann 已提交
387 388
   USB_RET_ASYNC indicates the processing isn't finished yet, the
   driver will call usb_packet_complete() when done processing it. */
389
void usb_handle_packet(USBDevice *dev, USBPacket *p)
G
Gerd Hoffmann 已提交
390
{
391
    if (dev == NULL) {
392 393
        p->status = USB_RET_NODEV;
        return;
394
    }
395
    assert(dev == p->ep->dev);
396
    assert(dev->state == USB_STATE_DEFAULT);
397
    usb_packet_check_state(p, USB_PACKET_SETUP);
398
    assert(p->ep != NULL);
399

400 401 402 403 404 405
    /* Submitting a new packet clears halt */
    if (p->ep->halted) {
        assert(QTAILQ_EMPTY(&p->ep->queue));
        p->ep->halted = false;
    }

406
    if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
407 408
        usb_process_one(p);
        if (p->status == USB_RET_ASYNC) {
409
            /* hcd drivers cannot handle async for isoc */
410
            assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
411 412
            /* using async for interrupt packets breaks migration */
            assert(p->ep->type != USB_ENDPOINT_XFER_INT ||
413
                   (dev->flags & (1 << USB_DEV_FLAG_IS_HOST)));
414 415
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
416 417
        } else if (p->status == USB_RET_ADD_TO_QUEUE) {
            usb_queue_one(p);
418
        } else {
419 420 421 422
            /*
             * When pipelining is enabled usb-devices must always return async,
             * otherwise packets can complete out of order!
             */
423
            assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
424
            if (p->status != USB_RET_NAK) {
425 426
                usb_packet_set_state(p, USB_PACKET_COMPLETE);
            }
427 428
        }
    } else {
429
        usb_queue_one(p);
G
Gerd Hoffmann 已提交
430
    }
431
}
G
Gerd Hoffmann 已提交
432

433
void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
434 435 436
{
    USBEndpoint *ep = p->ep;

437
    assert(QTAILQ_FIRST(&ep->queue) == p);
438
    assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);
439

440 441
    if (p->status != USB_RET_SUCCESS ||
            (p->short_not_ok && (p->actual_length < p->iov.size))) {
442 443 444 445 446 447 448
        ep->halted = true;
    }
    usb_packet_set_state(p, USB_PACKET_COMPLETE);
    QTAILQ_REMOVE(&ep->queue, p, queue);
    dev->port->ops->complete(dev->port, p);
}

G
Gerd Hoffmann 已提交
449 450 451 452 453
/* Notify the controller that an async packet is complete.  This should only
   be called for packets previously deferred by returning USB_RET_ASYNC from
   handle_packet. */
void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
454 455
    USBEndpoint *ep = p->ep;

456
    usb_packet_check_state(p, USB_PACKET_ASYNC);
457
    usb_packet_complete_one(dev, p);
458

459
    while (!QTAILQ_EMPTY(&ep->queue)) {
460
        p = QTAILQ_FIRST(&ep->queue);
461 462
        if (ep->halted) {
            /* Empty the queue on a halt */
463
            p->status = USB_RET_REMOVE_FROM_QUEUE;
464 465 466
            dev->port->ops->complete(dev->port, p);
            continue;
        }
467 468 469
        if (p->state == USB_PACKET_ASYNC) {
            break;
        }
470
        usb_packet_check_state(p, USB_PACKET_QUEUED);
471 472
        usb_process_one(p);
        if (p->status == USB_RET_ASYNC) {
473 474 475
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            break;
        }
476
        usb_packet_complete_one(ep->dev, p);
477
    }
G
Gerd Hoffmann 已提交
478 479 480 481 482 483 484
}

/* Cancel an active packet.  The packed must have been deferred by
   returning USB_RET_ASYNC from handle_packet, and not yet
   completed.  */
void usb_cancel_packet(USBPacket * p)
{
485 486 487 488 489 490 491
    bool callback = (p->state == USB_PACKET_ASYNC);
    assert(usb_packet_is_inflight(p));
    usb_packet_set_state(p, USB_PACKET_CANCELED);
    QTAILQ_REMOVE(&p->ep->queue, p, queue);
    if (callback) {
        usb_device_cancel_packet(p->ep->dev, p);
    }
G
Gerd Hoffmann 已提交
492
}
G
Gerd Hoffmann 已提交
493 494 495 496 497 498 499


void usb_packet_init(USBPacket *p)
{
    qemu_iovec_init(&p->iov, 1);
}

500
static const char *usb_packet_state_name(USBPacketState state)
501 502 503 504 505 506 507 508 509
{
    static const char *name[] = {
        [USB_PACKET_UNDEFINED] = "undef",
        [USB_PACKET_SETUP]     = "setup",
        [USB_PACKET_QUEUED]    = "queued",
        [USB_PACKET_ASYNC]     = "async",
        [USB_PACKET_COMPLETE]  = "complete",
        [USB_PACKET_CANCELED]  = "canceled",
    };
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
    if (state < ARRAY_SIZE(name)) {
        return name[state];
    }
    return "INVALID";
}

void usb_packet_check_state(USBPacket *p, USBPacketState expected)
{
    USBDevice *dev;
    USBBus *bus;

    if (p->state == expected) {
        return;
    }
    dev = p->ep->dev;
    bus = usb_bus_from_device(dev);
    trace_usb_packet_state_fault(bus->busnr, dev->port->path, p->ep->nr, p,
                                 usb_packet_state_name(p->state),
                                 usb_packet_state_name(expected));
    assert(!"usb packet state check failed");
}

void usb_packet_set_state(USBPacket *p, USBPacketState state)
{
534 535 536 537 538 539 540 541 542 543 544
    if (p->ep) {
        USBDevice *dev = p->ep->dev;
        USBBus *bus = usb_bus_from_device(dev);
        trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
                                      usb_packet_state_name(p->state),
                                      usb_packet_state_name(state));
    } else {
        trace_usb_packet_state_change(-1, "", -1, p,
                                      usb_packet_state_name(p->state),
                                      usb_packet_state_name(state));
    }
545 546 547
    p->state = state;
}

G
Gerd Hoffmann 已提交
548 549 550
void usb_packet_setup(USBPacket *p, int pid,
                      USBEndpoint *ep, unsigned int stream,
                      uint64_t id, bool short_not_ok, bool int_req)
G
Gerd Hoffmann 已提交
551
{
552
    assert(!usb_packet_is_inflight(p));
553
    assert(p->iov.iov != NULL);
G
Gerd Hoffmann 已提交
554
    p->id = id;
G
Gerd Hoffmann 已提交
555
    p->pid = pid;
556
    p->ep = ep;
G
Gerd Hoffmann 已提交
557
    p->stream = stream;
558 559
    p->status = USB_RET_SUCCESS;
    p->actual_length = 0;
560
    p->parameter = 0;
561
    p->short_not_ok = short_not_ok;
562
    p->int_req = int_req;
563
    p->combined = NULL;
G
Gerd Hoffmann 已提交
564
    qemu_iovec_reset(&p->iov);
565
    usb_packet_set_state(p, USB_PACKET_SETUP);
G
Gerd Hoffmann 已提交
566 567 568 569 570 571 572 573 574
}

void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
{
    qemu_iovec_add(&p->iov, ptr, len);
}

void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
{
575 576
    QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;

577
    assert(p->actual_length >= 0);
578
    assert(p->actual_length + bytes <= iov->size);
G
Gerd Hoffmann 已提交
579 580 581
    switch (p->pid) {
    case USB_TOKEN_SETUP:
    case USB_TOKEN_OUT:
582
        iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
G
Gerd Hoffmann 已提交
583 584
        break;
    case USB_TOKEN_IN:
585
        iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
G
Gerd Hoffmann 已提交
586 587 588 589 590
        break;
    default:
        fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
        abort();
    }
591
    p->actual_length += bytes;
G
Gerd Hoffmann 已提交
592 593 594 595
}

void usb_packet_skip(USBPacket *p, size_t bytes)
{
596 597
    QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;

598
    assert(p->actual_length >= 0);
599
    assert(p->actual_length + bytes <= iov->size);
G
Gerd Hoffmann 已提交
600
    if (p->pid == USB_TOKEN_IN) {
601
        iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes);
G
Gerd Hoffmann 已提交
602
    }
603
    p->actual_length += bytes;
G
Gerd Hoffmann 已提交
604 605
}

606 607 608 609 610
size_t usb_packet_size(USBPacket *p)
{
    return p->combined ? p->combined->iov.size : p->iov.size;
}

G
Gerd Hoffmann 已提交
611 612
void usb_packet_cleanup(USBPacket *p)
{
613
    assert(!usb_packet_is_inflight(p));
G
Gerd Hoffmann 已提交
614 615
    qemu_iovec_destroy(&p->iov);
}
G
Gerd Hoffmann 已提交
616

617
void usb_ep_reset(USBDevice *dev)
G
Gerd Hoffmann 已提交
618 619 620
{
    int ep;

G
Gerd Hoffmann 已提交
621
    dev->ep_ctl.nr = 0;
622 623 624
    dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
    dev->ep_ctl.ifnum = 0;
    dev->ep_ctl.dev = dev;
625
    dev->ep_ctl.pipeline = false;
G
Gerd Hoffmann 已提交
626
    for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
G
Gerd Hoffmann 已提交
627 628 629 630
        dev->ep_in[ep].nr = ep + 1;
        dev->ep_out[ep].nr = ep + 1;
        dev->ep_in[ep].pid = USB_TOKEN_IN;
        dev->ep_out[ep].pid = USB_TOKEN_OUT;
G
Gerd Hoffmann 已提交
631 632
        dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
        dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
633 634
        dev->ep_in[ep].ifnum = USB_INTERFACE_INVALID;
        dev->ep_out[ep].ifnum = USB_INTERFACE_INVALID;
635 636
        dev->ep_in[ep].dev = dev;
        dev->ep_out[ep].dev = dev;
637 638
        dev->ep_in[ep].pipeline = false;
        dev->ep_out[ep].pipeline = false;
639 640 641 642 643 644 645 646 647 648
    }
}

void usb_ep_init(USBDevice *dev)
{
    int ep;

    usb_ep_reset(dev);
    QTAILQ_INIT(&dev->ep_ctl.queue);
    for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
649 650
        QTAILQ_INIT(&dev->ep_in[ep].queue);
        QTAILQ_INIT(&dev->ep_out[ep].queue);
G
Gerd Hoffmann 已提交
651 652 653
    }
}

G
Gerd Hoffmann 已提交
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
void usb_ep_dump(USBDevice *dev)
{
    static const char *tname[] = {
        [USB_ENDPOINT_XFER_CONTROL] = "control",
        [USB_ENDPOINT_XFER_ISOC]    = "isoc",
        [USB_ENDPOINT_XFER_BULK]    = "bulk",
        [USB_ENDPOINT_XFER_INT]     = "int",
    };
    int ifnum, ep, first;

    fprintf(stderr, "Device \"%s\", config %d\n",
            dev->product_desc, dev->configuration);
    for (ifnum = 0; ifnum < 16; ifnum++) {
        first = 1;
        for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
            if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID &&
                dev->ep_in[ep].ifnum == ifnum) {
                if (first) {
                    first = 0;
                    fprintf(stderr, "  Interface %d, alternative %d\n",
                            ifnum, dev->altsetting[ifnum]);
                }
676 677 678
                fprintf(stderr, "    Endpoint %d, IN, %s, %d max\n", ep,
                        tname[dev->ep_in[ep].type],
                        dev->ep_in[ep].max_packet_size);
G
Gerd Hoffmann 已提交
679 680 681 682 683 684 685 686
            }
            if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID &&
                dev->ep_out[ep].ifnum == ifnum) {
                if (first) {
                    first = 0;
                    fprintf(stderr, "  Interface %d, alternative %d\n",
                            ifnum, dev->altsetting[ifnum]);
                }
687 688 689
                fprintf(stderr, "    Endpoint %d, OUT, %s, %d max\n", ep,
                        tname[dev->ep_out[ep].type],
                        dev->ep_out[ep].max_packet_size);
G
Gerd Hoffmann 已提交
690 691 692 693 694 695
            }
        }
    }
    fprintf(stderr, "--\n");
}

G
Gerd Hoffmann 已提交
696 697
struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
{
698 699 700 701 702 703
    struct USBEndpoint *eps;

    if (dev == NULL) {
        return NULL;
    }
    eps = (pid == USB_TOKEN_IN) ? dev->ep_in : dev->ep_out;
704 705 706
    if (ep == 0) {
        return &dev->ep_ctl;
    }
G
Gerd Hoffmann 已提交
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
    assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
    assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
    return eps + ep - 1;
}

uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    return uep->type;
}

void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    uep->type = type;
}
G
Gerd Hoffmann 已提交
723 724 725 726 727 728 729 730 731 732 733 734

uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    return uep->ifnum;
}

void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    uep->ifnum = ifnum;
}
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761

void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
                                uint16_t raw)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    int size, microframes;

    size = raw & 0x7ff;
    switch ((raw >> 11) & 3) {
    case 1:
        microframes = 2;
        break;
    case 2:
        microframes = 3;
        break;
    default:
        microframes = 1;
        break;
    }
    uep->max_packet_size = size * microframes;
}

int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    return uep->max_packet_size;
}
762 763 764 765 766 767

void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    uep->pipeline = enabled;
}
768

G
Gerd Hoffmann 已提交
769 770 771 772 773 774
void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    uep->halted = halted;
}

775 776 777 778 779 780
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
                                    uint64_t id)
{
    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
    USBPacket *p;

781
    QTAILQ_FOREACH(p, &uep->queue, queue) {
782 783 784 785 786 787 788
        if (p->id == id) {
            return p;
        }
    }

    return NULL;
}