1f1ae32a1SGerd Hoffmann /* 2f1ae32a1SGerd Hoffmann * QEMU USB emulation 3f1ae32a1SGerd Hoffmann * 4f1ae32a1SGerd Hoffmann * Copyright (c) 2005 Fabrice Bellard 5f1ae32a1SGerd Hoffmann * 6f1ae32a1SGerd Hoffmann * 2008 Generic packet handler rewrite by Max Krasnyansky 7f1ae32a1SGerd Hoffmann * 8f1ae32a1SGerd Hoffmann * Permission is hereby granted, free of charge, to any person obtaining a copy 9f1ae32a1SGerd Hoffmann * of this software and associated documentation files (the "Software"), to deal 10f1ae32a1SGerd Hoffmann * in the Software without restriction, including without limitation the rights 11f1ae32a1SGerd Hoffmann * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12f1ae32a1SGerd Hoffmann * copies of the Software, and to permit persons to whom the Software is 13f1ae32a1SGerd Hoffmann * furnished to do so, subject to the following conditions: 14f1ae32a1SGerd Hoffmann * 15f1ae32a1SGerd Hoffmann * The above copyright notice and this permission notice shall be included in 16f1ae32a1SGerd Hoffmann * all copies or substantial portions of the Software. 17f1ae32a1SGerd Hoffmann * 18f1ae32a1SGerd Hoffmann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19f1ae32a1SGerd Hoffmann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20f1ae32a1SGerd Hoffmann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21f1ae32a1SGerd Hoffmann * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22f1ae32a1SGerd Hoffmann * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23f1ae32a1SGerd Hoffmann * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24f1ae32a1SGerd Hoffmann * THE SOFTWARE. 25f1ae32a1SGerd Hoffmann */ 26e532b2e0SPeter Maydell #include "qemu/osdep.h" 27f1ae32a1SGerd Hoffmann #include "hw/usb.h" 281de7afc9SPaolo Bonzini #include "qemu/iov.h" 29f1ae32a1SGerd Hoffmann #include "trace.h" 30f1ae32a1SGerd Hoffmann 31b791c3b3SGerd Hoffmann void usb_pick_speed(USBPort *port) 32b791c3b3SGerd Hoffmann { 33b791c3b3SGerd Hoffmann static const int speeds[] = { 34b791c3b3SGerd Hoffmann USB_SPEED_SUPER, 35b791c3b3SGerd Hoffmann USB_SPEED_HIGH, 36b791c3b3SGerd Hoffmann USB_SPEED_FULL, 37b791c3b3SGerd Hoffmann USB_SPEED_LOW, 38b791c3b3SGerd Hoffmann }; 39b791c3b3SGerd Hoffmann USBDevice *udev = port->dev; 40b791c3b3SGerd Hoffmann int i; 41b791c3b3SGerd Hoffmann 42b791c3b3SGerd Hoffmann for (i = 0; i < ARRAY_SIZE(speeds); i++) { 43b791c3b3SGerd Hoffmann if ((udev->speedmask & (1 << speeds[i])) && 44b791c3b3SGerd Hoffmann (port->speedmask & (1 << speeds[i]))) { 45b791c3b3SGerd Hoffmann udev->speed = speeds[i]; 46b791c3b3SGerd Hoffmann return; 47b791c3b3SGerd Hoffmann } 48b791c3b3SGerd Hoffmann } 49b791c3b3SGerd Hoffmann } 50b791c3b3SGerd Hoffmann 51f1ae32a1SGerd Hoffmann void usb_attach(USBPort *port) 52f1ae32a1SGerd Hoffmann { 53f1ae32a1SGerd Hoffmann USBDevice *dev = port->dev; 54f1ae32a1SGerd Hoffmann 55f1ae32a1SGerd Hoffmann assert(dev != NULL); 56f1ae32a1SGerd Hoffmann assert(dev->attached); 57f1ae32a1SGerd Hoffmann assert(dev->state == USB_STATE_NOTATTACHED); 58b791c3b3SGerd Hoffmann usb_pick_speed(port); 59f1ae32a1SGerd Hoffmann port->ops->attach(port); 60f1ae32a1SGerd Hoffmann dev->state = USB_STATE_ATTACHED; 61f1ae32a1SGerd Hoffmann usb_device_handle_attach(dev); 62f1ae32a1SGerd Hoffmann } 63f1ae32a1SGerd Hoffmann 64f1ae32a1SGerd Hoffmann void usb_detach(USBPort *port) 65f1ae32a1SGerd Hoffmann { 66f1ae32a1SGerd Hoffmann USBDevice *dev = port->dev; 67f1ae32a1SGerd Hoffmann 68f1ae32a1SGerd Hoffmann assert(dev != NULL); 69f1ae32a1SGerd Hoffmann assert(dev->state != USB_STATE_NOTATTACHED); 70f1ae32a1SGerd Hoffmann port->ops->detach(port); 71f1ae32a1SGerd Hoffmann dev->state = USB_STATE_NOTATTACHED; 72f1ae32a1SGerd Hoffmann } 73f1ae32a1SGerd Hoffmann 74f1ae32a1SGerd Hoffmann void usb_port_reset(USBPort *port) 75f1ae32a1SGerd Hoffmann { 76f1ae32a1SGerd Hoffmann USBDevice *dev = port->dev; 77f1ae32a1SGerd Hoffmann 78f1ae32a1SGerd Hoffmann assert(dev != NULL); 79f1ae32a1SGerd Hoffmann usb_detach(port); 80f1ae32a1SGerd Hoffmann usb_attach(port); 81f1ae32a1SGerd Hoffmann usb_device_reset(dev); 82f1ae32a1SGerd Hoffmann } 83f1ae32a1SGerd Hoffmann 84f1ae32a1SGerd Hoffmann void usb_device_reset(USBDevice *dev) 85f1ae32a1SGerd Hoffmann { 86f1ae32a1SGerd Hoffmann if (dev == NULL || !dev->attached) { 87f1ae32a1SGerd Hoffmann return; 88f1ae32a1SGerd Hoffmann } 897ed46573SGerd Hoffmann usb_device_handle_reset(dev); 90f1ae32a1SGerd Hoffmann dev->remote_wakeup = 0; 91f1ae32a1SGerd Hoffmann dev->addr = 0; 92f1ae32a1SGerd Hoffmann dev->state = USB_STATE_DEFAULT; 93f1ae32a1SGerd Hoffmann } 94f1ae32a1SGerd Hoffmann 958550a02dSGerd Hoffmann void usb_wakeup(USBEndpoint *ep, unsigned int stream) 96f1ae32a1SGerd Hoffmann { 97f1ae32a1SGerd Hoffmann USBDevice *dev = ep->dev; 98f1ae32a1SGerd Hoffmann USBBus *bus = usb_bus_from_device(dev); 99f1ae32a1SGerd Hoffmann 1002f181fbdSPaolo Bonzini if (!phase_check(PHASE_MACHINE_READY)) { 10126022652SGerd Hoffmann /* 10226022652SGerd Hoffmann * This is machine init cold plug. No need to wakeup anyone, 10326022652SGerd Hoffmann * all devices will be reset anyway. And trying to wakeup can 10426022652SGerd Hoffmann * cause problems due to hitting uninitialized devices. 10526022652SGerd Hoffmann */ 10626022652SGerd Hoffmann return; 10726022652SGerd Hoffmann } 108f1ae32a1SGerd Hoffmann if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) { 109f1ae32a1SGerd Hoffmann dev->port->ops->wakeup(dev->port); 110f1ae32a1SGerd Hoffmann } 111f1ae32a1SGerd Hoffmann if (bus->ops->wakeup_endpoint) { 1128550a02dSGerd Hoffmann bus->ops->wakeup_endpoint(bus, ep, stream); 113f1ae32a1SGerd Hoffmann } 114f1ae32a1SGerd Hoffmann } 115f1ae32a1SGerd Hoffmann 116f1ae32a1SGerd Hoffmann /**********************/ 117f1ae32a1SGerd Hoffmann 118f1ae32a1SGerd Hoffmann /* generic USB device helpers (you are not forced to use them when 119f1ae32a1SGerd Hoffmann writing your USB device driver, but they help handling the 120f1ae32a1SGerd Hoffmann protocol) 121f1ae32a1SGerd Hoffmann */ 122f1ae32a1SGerd Hoffmann 123f1ae32a1SGerd Hoffmann #define SETUP_STATE_IDLE 0 124f1ae32a1SGerd Hoffmann #define SETUP_STATE_SETUP 1 125f1ae32a1SGerd Hoffmann #define SETUP_STATE_DATA 2 126f1ae32a1SGerd Hoffmann #define SETUP_STATE_ACK 3 127f1ae32a1SGerd Hoffmann #define SETUP_STATE_PARAM 4 128f1ae32a1SGerd Hoffmann 1299a77a0f5SHans de Goede static void do_token_setup(USBDevice *s, USBPacket *p) 130f1ae32a1SGerd Hoffmann { 131f1ae32a1SGerd Hoffmann int request, value, index; 132b946434fSGerd Hoffmann unsigned int setup_len; 133f1ae32a1SGerd Hoffmann 134f1ae32a1SGerd Hoffmann if (p->iov.size != 8) { 1359a77a0f5SHans de Goede p->status = USB_RET_STALL; 1369a77a0f5SHans de Goede return; 137f1ae32a1SGerd Hoffmann } 138f1ae32a1SGerd Hoffmann 139f1ae32a1SGerd Hoffmann usb_packet_copy(p, s->setup_buf, p->iov.size); 14064c9bc18SPrasad J Pandit s->setup_index = 0; 1419a77a0f5SHans de Goede p->actual_length = 0; 142b946434fSGerd Hoffmann setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; 143b946434fSGerd Hoffmann if (setup_len > sizeof(s->data_buf)) { 14464c9bc18SPrasad J Pandit fprintf(stderr, 145*268c0242SAlex Chen "usb_generic_handle_packet: ctrl buffer too small (%u > %zu)\n", 146b946434fSGerd Hoffmann setup_len, sizeof(s->data_buf)); 14764c9bc18SPrasad J Pandit p->status = USB_RET_STALL; 14864c9bc18SPrasad J Pandit return; 14964c9bc18SPrasad J Pandit } 150b946434fSGerd Hoffmann s->setup_len = setup_len; 151f1ae32a1SGerd Hoffmann 152f1ae32a1SGerd Hoffmann request = (s->setup_buf[0] << 8) | s->setup_buf[1]; 153f1ae32a1SGerd Hoffmann value = (s->setup_buf[3] << 8) | s->setup_buf[2]; 154f1ae32a1SGerd Hoffmann index = (s->setup_buf[5] << 8) | s->setup_buf[4]; 155f1ae32a1SGerd Hoffmann 156f1ae32a1SGerd Hoffmann if (s->setup_buf[0] & USB_DIR_IN) { 1579a77a0f5SHans de Goede usb_device_handle_control(s, p, request, value, index, 158f1ae32a1SGerd Hoffmann s->setup_len, s->data_buf); 1599a77a0f5SHans de Goede if (p->status == USB_RET_ASYNC) { 160f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_SETUP; 161f1ae32a1SGerd Hoffmann } 1629a77a0f5SHans de Goede if (p->status != USB_RET_SUCCESS) { 1639a77a0f5SHans de Goede return; 1649a77a0f5SHans de Goede } 165f1ae32a1SGerd Hoffmann 1669a77a0f5SHans de Goede if (p->actual_length < s->setup_len) { 1679a77a0f5SHans de Goede s->setup_len = p->actual_length; 1689a77a0f5SHans de Goede } 169f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_DATA; 170f1ae32a1SGerd Hoffmann } else { 171f1ae32a1SGerd Hoffmann if (s->setup_len == 0) 172f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_ACK; 173f1ae32a1SGerd Hoffmann else 174f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_DATA; 175f1ae32a1SGerd Hoffmann } 176f1ae32a1SGerd Hoffmann 1779a77a0f5SHans de Goede p->actual_length = 8; 178f1ae32a1SGerd Hoffmann } 179f1ae32a1SGerd Hoffmann 1809a77a0f5SHans de Goede static void do_token_in(USBDevice *s, USBPacket *p) 181f1ae32a1SGerd Hoffmann { 182f1ae32a1SGerd Hoffmann int request, value, index; 183f1ae32a1SGerd Hoffmann 184f1ae32a1SGerd Hoffmann assert(p->ep->nr == 0); 185f1ae32a1SGerd Hoffmann 186f1ae32a1SGerd Hoffmann request = (s->setup_buf[0] << 8) | s->setup_buf[1]; 187f1ae32a1SGerd Hoffmann value = (s->setup_buf[3] << 8) | s->setup_buf[2]; 188f1ae32a1SGerd Hoffmann index = (s->setup_buf[5] << 8) | s->setup_buf[4]; 189f1ae32a1SGerd Hoffmann 190f1ae32a1SGerd Hoffmann switch(s->setup_state) { 191f1ae32a1SGerd Hoffmann case SETUP_STATE_ACK: 192f1ae32a1SGerd Hoffmann if (!(s->setup_buf[0] & USB_DIR_IN)) { 1939a77a0f5SHans de Goede usb_device_handle_control(s, p, request, value, index, 194f1ae32a1SGerd Hoffmann s->setup_len, s->data_buf); 1959a77a0f5SHans de Goede if (p->status == USB_RET_ASYNC) { 1969a77a0f5SHans de Goede return; 197f1ae32a1SGerd Hoffmann } 198f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_IDLE; 1999a77a0f5SHans de Goede p->actual_length = 0; 200f1ae32a1SGerd Hoffmann } 2019a77a0f5SHans de Goede break; 202f1ae32a1SGerd Hoffmann 203f1ae32a1SGerd Hoffmann case SETUP_STATE_DATA: 204f1ae32a1SGerd Hoffmann if (s->setup_buf[0] & USB_DIR_IN) { 205f1ae32a1SGerd Hoffmann int len = s->setup_len - s->setup_index; 206f1ae32a1SGerd Hoffmann if (len > p->iov.size) { 207f1ae32a1SGerd Hoffmann len = p->iov.size; 208f1ae32a1SGerd Hoffmann } 209f1ae32a1SGerd Hoffmann usb_packet_copy(p, s->data_buf + s->setup_index, len); 210f1ae32a1SGerd Hoffmann s->setup_index += len; 2119a77a0f5SHans de Goede if (s->setup_index >= s->setup_len) { 212f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_ACK; 213f1ae32a1SGerd Hoffmann } 2149a77a0f5SHans de Goede return; 2159a77a0f5SHans de Goede } 216f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_IDLE; 2179a77a0f5SHans de Goede p->status = USB_RET_STALL; 2189a77a0f5SHans de Goede break; 219f1ae32a1SGerd Hoffmann 220f1ae32a1SGerd Hoffmann default: 2219a77a0f5SHans de Goede p->status = USB_RET_STALL; 222f1ae32a1SGerd Hoffmann } 223f1ae32a1SGerd Hoffmann } 224f1ae32a1SGerd Hoffmann 2259a77a0f5SHans de Goede static void do_token_out(USBDevice *s, USBPacket *p) 226f1ae32a1SGerd Hoffmann { 227f1ae32a1SGerd Hoffmann assert(p->ep->nr == 0); 228f1ae32a1SGerd Hoffmann 229f1ae32a1SGerd Hoffmann switch(s->setup_state) { 230f1ae32a1SGerd Hoffmann case SETUP_STATE_ACK: 231f1ae32a1SGerd Hoffmann if (s->setup_buf[0] & USB_DIR_IN) { 232f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_IDLE; 233f1ae32a1SGerd Hoffmann /* transfer OK */ 234f1ae32a1SGerd Hoffmann } else { 235f1ae32a1SGerd Hoffmann /* ignore additional output */ 236f1ae32a1SGerd Hoffmann } 2379a77a0f5SHans de Goede break; 238f1ae32a1SGerd Hoffmann 239f1ae32a1SGerd Hoffmann case SETUP_STATE_DATA: 240f1ae32a1SGerd Hoffmann if (!(s->setup_buf[0] & USB_DIR_IN)) { 241f1ae32a1SGerd Hoffmann int len = s->setup_len - s->setup_index; 242f1ae32a1SGerd Hoffmann if (len > p->iov.size) { 243f1ae32a1SGerd Hoffmann len = p->iov.size; 244f1ae32a1SGerd Hoffmann } 245f1ae32a1SGerd Hoffmann usb_packet_copy(p, s->data_buf + s->setup_index, len); 246f1ae32a1SGerd Hoffmann s->setup_index += len; 2479a77a0f5SHans de Goede if (s->setup_index >= s->setup_len) { 248f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_ACK; 249f1ae32a1SGerd Hoffmann } 2509a77a0f5SHans de Goede return; 2519a77a0f5SHans de Goede } 252f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_IDLE; 2539a77a0f5SHans de Goede p->status = USB_RET_STALL; 2549a77a0f5SHans de Goede break; 255f1ae32a1SGerd Hoffmann 256f1ae32a1SGerd Hoffmann default: 2579a77a0f5SHans de Goede p->status = USB_RET_STALL; 258f1ae32a1SGerd Hoffmann } 259f1ae32a1SGerd Hoffmann } 260f1ae32a1SGerd Hoffmann 2619a77a0f5SHans de Goede static void do_parameter(USBDevice *s, USBPacket *p) 262f1ae32a1SGerd Hoffmann { 2639a77a0f5SHans de Goede int i, request, value, index; 264b946434fSGerd Hoffmann unsigned int setup_len; 265f1ae32a1SGerd Hoffmann 266f1ae32a1SGerd Hoffmann for (i = 0; i < 8; i++) { 267f1ae32a1SGerd Hoffmann s->setup_buf[i] = p->parameter >> (i*8); 268f1ae32a1SGerd Hoffmann } 269f1ae32a1SGerd Hoffmann 270f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_PARAM; 271f1ae32a1SGerd Hoffmann s->setup_index = 0; 272f1ae32a1SGerd Hoffmann 273f1ae32a1SGerd Hoffmann request = (s->setup_buf[0] << 8) | s->setup_buf[1]; 274f1ae32a1SGerd Hoffmann value = (s->setup_buf[3] << 8) | s->setup_buf[2]; 275f1ae32a1SGerd Hoffmann index = (s->setup_buf[5] << 8) | s->setup_buf[4]; 276f1ae32a1SGerd Hoffmann 277b946434fSGerd Hoffmann setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; 278b946434fSGerd Hoffmann if (setup_len > sizeof(s->data_buf)) { 279f1ae32a1SGerd Hoffmann fprintf(stderr, 280*268c0242SAlex Chen "usb_generic_handle_packet: ctrl buffer too small (%u > %zu)\n", 281b946434fSGerd Hoffmann setup_len, sizeof(s->data_buf)); 2829a77a0f5SHans de Goede p->status = USB_RET_STALL; 2839a77a0f5SHans de Goede return; 284f1ae32a1SGerd Hoffmann } 285b946434fSGerd Hoffmann s->setup_len = setup_len; 286f1ae32a1SGerd Hoffmann 287f1ae32a1SGerd Hoffmann if (p->pid == USB_TOKEN_OUT) { 288f1ae32a1SGerd Hoffmann usb_packet_copy(p, s->data_buf, s->setup_len); 289f1ae32a1SGerd Hoffmann } 290f1ae32a1SGerd Hoffmann 2919a77a0f5SHans de Goede usb_device_handle_control(s, p, request, value, index, 292f1ae32a1SGerd Hoffmann s->setup_len, s->data_buf); 2939a77a0f5SHans de Goede if (p->status == USB_RET_ASYNC) { 2949a77a0f5SHans de Goede return; 295f1ae32a1SGerd Hoffmann } 296f1ae32a1SGerd Hoffmann 2979a77a0f5SHans de Goede if (p->actual_length < s->setup_len) { 2989a77a0f5SHans de Goede s->setup_len = p->actual_length; 299f1ae32a1SGerd Hoffmann } 300f1ae32a1SGerd Hoffmann if (p->pid == USB_TOKEN_IN) { 3019a77a0f5SHans de Goede p->actual_length = 0; 302f1ae32a1SGerd Hoffmann usb_packet_copy(p, s->data_buf, s->setup_len); 303f1ae32a1SGerd Hoffmann } 304f1ae32a1SGerd Hoffmann } 305f1ae32a1SGerd Hoffmann 306f1ae32a1SGerd Hoffmann /* ctrl complete function for devices which use usb_generic_handle_packet and 307f1ae32a1SGerd Hoffmann may return USB_RET_ASYNC from their handle_control callback. Device code 308f1ae32a1SGerd Hoffmann which does this *must* call this function instead of the normal 309f1ae32a1SGerd Hoffmann usb_packet_complete to complete their async control packets. */ 310f1ae32a1SGerd Hoffmann void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p) 311f1ae32a1SGerd Hoffmann { 3129a77a0f5SHans de Goede if (p->status < 0) { 313f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_IDLE; 314f1ae32a1SGerd Hoffmann } 315f1ae32a1SGerd Hoffmann 316f1ae32a1SGerd Hoffmann switch (s->setup_state) { 317f1ae32a1SGerd Hoffmann case SETUP_STATE_SETUP: 3189a77a0f5SHans de Goede if (p->actual_length < s->setup_len) { 3199a77a0f5SHans de Goede s->setup_len = p->actual_length; 320f1ae32a1SGerd Hoffmann } 321f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_DATA; 3229a77a0f5SHans de Goede p->actual_length = 8; 323f1ae32a1SGerd Hoffmann break; 324f1ae32a1SGerd Hoffmann 325f1ae32a1SGerd Hoffmann case SETUP_STATE_ACK: 326f1ae32a1SGerd Hoffmann s->setup_state = SETUP_STATE_IDLE; 3279a77a0f5SHans de Goede p->actual_length = 0; 328f1ae32a1SGerd Hoffmann break; 329f1ae32a1SGerd Hoffmann 330f1ae32a1SGerd Hoffmann case SETUP_STATE_PARAM: 3319a77a0f5SHans de Goede if (p->actual_length < s->setup_len) { 3329a77a0f5SHans de Goede s->setup_len = p->actual_length; 333f1ae32a1SGerd Hoffmann } 334f1ae32a1SGerd Hoffmann if (p->pid == USB_TOKEN_IN) { 3359a77a0f5SHans de Goede p->actual_length = 0; 336f1ae32a1SGerd Hoffmann usb_packet_copy(p, s->data_buf, s->setup_len); 337f1ae32a1SGerd Hoffmann } 338f1ae32a1SGerd Hoffmann break; 339f1ae32a1SGerd Hoffmann 340f1ae32a1SGerd Hoffmann default: 341f1ae32a1SGerd Hoffmann break; 342f1ae32a1SGerd Hoffmann } 343f1ae32a1SGerd Hoffmann usb_packet_complete(s, p); 344f1ae32a1SGerd Hoffmann } 345f1ae32a1SGerd Hoffmann 346f1ae32a1SGerd Hoffmann USBDevice *usb_find_device(USBPort *port, uint8_t addr) 347f1ae32a1SGerd Hoffmann { 348f1ae32a1SGerd Hoffmann USBDevice *dev = port->dev; 349f1ae32a1SGerd Hoffmann 350f1ae32a1SGerd Hoffmann if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT) { 351f1ae32a1SGerd Hoffmann return NULL; 352f1ae32a1SGerd Hoffmann } 353f1ae32a1SGerd Hoffmann if (dev->addr == addr) { 354f1ae32a1SGerd Hoffmann return dev; 355f1ae32a1SGerd Hoffmann } 356f1ae32a1SGerd Hoffmann return usb_device_find_device(dev, addr); 357f1ae32a1SGerd Hoffmann } 358f1ae32a1SGerd Hoffmann 3599a77a0f5SHans de Goede static void usb_process_one(USBPacket *p) 360f1ae32a1SGerd Hoffmann { 361f1ae32a1SGerd Hoffmann USBDevice *dev = p->ep->dev; 362f1ae32a1SGerd Hoffmann 3639a77a0f5SHans de Goede /* 3649a77a0f5SHans de Goede * Handlers expect status to be initialized to USB_RET_SUCCESS, but it 3659a77a0f5SHans de Goede * can be USB_RET_NAK here from a previous usb_process_one() call, 3669a77a0f5SHans de Goede * or USB_RET_ASYNC from going through usb_queue_one(). 3679a77a0f5SHans de Goede */ 3689a77a0f5SHans de Goede p->status = USB_RET_SUCCESS; 3699a77a0f5SHans de Goede 370f1ae32a1SGerd Hoffmann if (p->ep->nr == 0) { 371f1ae32a1SGerd Hoffmann /* control pipe */ 372f1ae32a1SGerd Hoffmann if (p->parameter) { 3739a77a0f5SHans de Goede do_parameter(dev, p); 3749a77a0f5SHans de Goede return; 375f1ae32a1SGerd Hoffmann } 376f1ae32a1SGerd Hoffmann switch (p->pid) { 377f1ae32a1SGerd Hoffmann case USB_TOKEN_SETUP: 3789a77a0f5SHans de Goede do_token_setup(dev, p); 3799a77a0f5SHans de Goede break; 380f1ae32a1SGerd Hoffmann case USB_TOKEN_IN: 3819a77a0f5SHans de Goede do_token_in(dev, p); 3829a77a0f5SHans de Goede break; 383f1ae32a1SGerd Hoffmann case USB_TOKEN_OUT: 3849a77a0f5SHans de Goede do_token_out(dev, p); 3859a77a0f5SHans de Goede break; 386f1ae32a1SGerd Hoffmann default: 3879a77a0f5SHans de Goede p->status = USB_RET_STALL; 388f1ae32a1SGerd Hoffmann } 389f1ae32a1SGerd Hoffmann } else { 390f1ae32a1SGerd Hoffmann /* data pipe */ 3919a77a0f5SHans de Goede usb_device_handle_data(dev, p); 392f1ae32a1SGerd Hoffmann } 393f1ae32a1SGerd Hoffmann } 394f1ae32a1SGerd Hoffmann 3959a77a0f5SHans de Goede static void usb_queue_one(USBPacket *p) 3969a77a0f5SHans de Goede { 3979a77a0f5SHans de Goede usb_packet_set_state(p, USB_PACKET_QUEUED); 3989a77a0f5SHans de Goede QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); 3999a77a0f5SHans de Goede p->status = USB_RET_ASYNC; 4009a77a0f5SHans de Goede } 4019a77a0f5SHans de Goede 4029a77a0f5SHans de Goede /* Hand over a packet to a device for processing. p->status == 403f1ae32a1SGerd Hoffmann USB_RET_ASYNC indicates the processing isn't finished yet, the 404f1ae32a1SGerd Hoffmann driver will call usb_packet_complete() when done processing it. */ 4059a77a0f5SHans de Goede void usb_handle_packet(USBDevice *dev, USBPacket *p) 406f1ae32a1SGerd Hoffmann { 407f1ae32a1SGerd Hoffmann if (dev == NULL) { 4089a77a0f5SHans de Goede p->status = USB_RET_NODEV; 4099a77a0f5SHans de Goede return; 410f1ae32a1SGerd Hoffmann } 411f1ae32a1SGerd Hoffmann assert(dev == p->ep->dev); 412f1ae32a1SGerd Hoffmann assert(dev->state == USB_STATE_DEFAULT); 4135ac2731cSGerd Hoffmann usb_packet_check_state(p, USB_PACKET_SETUP); 414f1ae32a1SGerd Hoffmann assert(p->ep != NULL); 415f1ae32a1SGerd Hoffmann 4160132b4b6SHans de Goede /* Submitting a new packet clears halt */ 4170132b4b6SHans de Goede if (p->ep->halted) { 4180132b4b6SHans de Goede assert(QTAILQ_EMPTY(&p->ep->queue)); 4190132b4b6SHans de Goede p->ep->halted = false; 4200132b4b6SHans de Goede } 4210132b4b6SHans de Goede 422c96c41edSGerd Hoffmann if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline || p->stream) { 4239a77a0f5SHans de Goede usb_process_one(p); 4249a77a0f5SHans de Goede if (p->status == USB_RET_ASYNC) { 425be41efdeSHans de Goede /* hcd drivers cannot handle async for isoc */ 426aaac7434SHans de Goede assert(p->ep->type != USB_ENDPOINT_XFER_ISOC); 427be41efdeSHans de Goede /* using async for interrupt packets breaks migration */ 428be41efdeSHans de Goede assert(p->ep->type != USB_ENDPOINT_XFER_INT || 42975633529SMichael Marineau (dev->flags & (1 << USB_DEV_FLAG_IS_HOST))); 430f1ae32a1SGerd Hoffmann usb_packet_set_state(p, USB_PACKET_ASYNC); 431f1ae32a1SGerd Hoffmann QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); 4329a77a0f5SHans de Goede } else if (p->status == USB_RET_ADD_TO_QUEUE) { 4339a77a0f5SHans de Goede usb_queue_one(p); 434f1ae32a1SGerd Hoffmann } else { 4350132b4b6SHans de Goede /* 4360132b4b6SHans de Goede * When pipelining is enabled usb-devices must always return async, 4370132b4b6SHans de Goede * otherwise packets can complete out of order! 4380132b4b6SHans de Goede */ 439c96c41edSGerd Hoffmann assert(p->stream || !p->ep->pipeline || 440c96c41edSGerd Hoffmann QTAILQ_EMPTY(&p->ep->queue)); 4419a77a0f5SHans de Goede if (p->status != USB_RET_NAK) { 442f1ae32a1SGerd Hoffmann usb_packet_set_state(p, USB_PACKET_COMPLETE); 443f1ae32a1SGerd Hoffmann } 444cc409974SHans de Goede } 445f1ae32a1SGerd Hoffmann } else { 4469a77a0f5SHans de Goede usb_queue_one(p); 447f1ae32a1SGerd Hoffmann } 448f1ae32a1SGerd Hoffmann } 449f1ae32a1SGerd Hoffmann 450d0ff81b8SHans de Goede void usb_packet_complete_one(USBDevice *dev, USBPacket *p) 4510132b4b6SHans de Goede { 4520132b4b6SHans de Goede USBEndpoint *ep = p->ep; 4530132b4b6SHans de Goede 454c96c41edSGerd Hoffmann assert(p->stream || QTAILQ_FIRST(&ep->queue) == p); 4559a77a0f5SHans de Goede assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK); 4560132b4b6SHans de Goede 4579a77a0f5SHans de Goede if (p->status != USB_RET_SUCCESS || 4589a77a0f5SHans de Goede (p->short_not_ok && (p->actual_length < p->iov.size))) { 4590132b4b6SHans de Goede ep->halted = true; 4600132b4b6SHans de Goede } 4610132b4b6SHans de Goede usb_packet_set_state(p, USB_PACKET_COMPLETE); 4620132b4b6SHans de Goede QTAILQ_REMOVE(&ep->queue, p, queue); 4630132b4b6SHans de Goede dev->port->ops->complete(dev->port, p); 4640132b4b6SHans de Goede } 4650132b4b6SHans de Goede 466f1ae32a1SGerd Hoffmann /* Notify the controller that an async packet is complete. This should only 467f1ae32a1SGerd Hoffmann be called for packets previously deferred by returning USB_RET_ASYNC from 468f1ae32a1SGerd Hoffmann handle_packet. */ 469f1ae32a1SGerd Hoffmann void usb_packet_complete(USBDevice *dev, USBPacket *p) 470f1ae32a1SGerd Hoffmann { 471f1ae32a1SGerd Hoffmann USBEndpoint *ep = p->ep; 472f1ae32a1SGerd Hoffmann 4735ac2731cSGerd Hoffmann usb_packet_check_state(p, USB_PACKET_ASYNC); 474d0ff81b8SHans de Goede usb_packet_complete_one(dev, p); 475f1ae32a1SGerd Hoffmann 4760cae7b1aSHans de Goede while (!QTAILQ_EMPTY(&ep->queue)) { 477f1ae32a1SGerd Hoffmann p = QTAILQ_FIRST(&ep->queue); 4780cae7b1aSHans de Goede if (ep->halted) { 4790cae7b1aSHans de Goede /* Empty the queue on a halt */ 4809a77a0f5SHans de Goede p->status = USB_RET_REMOVE_FROM_QUEUE; 4810cae7b1aSHans de Goede dev->port->ops->complete(dev->port, p); 4820cae7b1aSHans de Goede continue; 4830cae7b1aSHans de Goede } 484f1ae32a1SGerd Hoffmann if (p->state == USB_PACKET_ASYNC) { 485f1ae32a1SGerd Hoffmann break; 486f1ae32a1SGerd Hoffmann } 4875ac2731cSGerd Hoffmann usb_packet_check_state(p, USB_PACKET_QUEUED); 4889a77a0f5SHans de Goede usb_process_one(p); 4899a77a0f5SHans de Goede if (p->status == USB_RET_ASYNC) { 490f1ae32a1SGerd Hoffmann usb_packet_set_state(p, USB_PACKET_ASYNC); 491f1ae32a1SGerd Hoffmann break; 492f1ae32a1SGerd Hoffmann } 493d0ff81b8SHans de Goede usb_packet_complete_one(ep->dev, p); 494f1ae32a1SGerd Hoffmann } 495f1ae32a1SGerd Hoffmann } 496f1ae32a1SGerd Hoffmann 497f1ae32a1SGerd Hoffmann /* Cancel an active packet. The packed must have been deferred by 498f1ae32a1SGerd Hoffmann returning USB_RET_ASYNC from handle_packet, and not yet 499f1ae32a1SGerd Hoffmann completed. */ 500f1ae32a1SGerd Hoffmann void usb_cancel_packet(USBPacket * p) 501f1ae32a1SGerd Hoffmann { 502f1ae32a1SGerd Hoffmann bool callback = (p->state == USB_PACKET_ASYNC); 503f1ae32a1SGerd Hoffmann assert(usb_packet_is_inflight(p)); 504f1ae32a1SGerd Hoffmann usb_packet_set_state(p, USB_PACKET_CANCELED); 505f1ae32a1SGerd Hoffmann QTAILQ_REMOVE(&p->ep->queue, p, queue); 506f1ae32a1SGerd Hoffmann if (callback) { 507f1ae32a1SGerd Hoffmann usb_device_cancel_packet(p->ep->dev, p); 508f1ae32a1SGerd Hoffmann } 509f1ae32a1SGerd Hoffmann } 510f1ae32a1SGerd Hoffmann 511f1ae32a1SGerd Hoffmann 512f1ae32a1SGerd Hoffmann void usb_packet_init(USBPacket *p) 513f1ae32a1SGerd Hoffmann { 514f1ae32a1SGerd Hoffmann qemu_iovec_init(&p->iov, 1); 515f1ae32a1SGerd Hoffmann } 516f1ae32a1SGerd Hoffmann 5175ac2731cSGerd Hoffmann static const char *usb_packet_state_name(USBPacketState state) 518f1ae32a1SGerd Hoffmann { 519f1ae32a1SGerd Hoffmann static const char *name[] = { 520f1ae32a1SGerd Hoffmann [USB_PACKET_UNDEFINED] = "undef", 521f1ae32a1SGerd Hoffmann [USB_PACKET_SETUP] = "setup", 522f1ae32a1SGerd Hoffmann [USB_PACKET_QUEUED] = "queued", 523f1ae32a1SGerd Hoffmann [USB_PACKET_ASYNC] = "async", 524f1ae32a1SGerd Hoffmann [USB_PACKET_COMPLETE] = "complete", 525f1ae32a1SGerd Hoffmann [USB_PACKET_CANCELED] = "canceled", 526f1ae32a1SGerd Hoffmann }; 5275ac2731cSGerd Hoffmann if (state < ARRAY_SIZE(name)) { 5285ac2731cSGerd Hoffmann return name[state]; 5295ac2731cSGerd Hoffmann } 5305ac2731cSGerd Hoffmann return "INVALID"; 5315ac2731cSGerd Hoffmann } 5325ac2731cSGerd Hoffmann 5335ac2731cSGerd Hoffmann void usb_packet_check_state(USBPacket *p, USBPacketState expected) 5345ac2731cSGerd Hoffmann { 5355ac2731cSGerd Hoffmann USBDevice *dev; 5365ac2731cSGerd Hoffmann USBBus *bus; 5375ac2731cSGerd Hoffmann 5385ac2731cSGerd Hoffmann if (p->state == expected) { 5395ac2731cSGerd Hoffmann return; 5405ac2731cSGerd Hoffmann } 5415ac2731cSGerd Hoffmann dev = p->ep->dev; 5425ac2731cSGerd Hoffmann bus = usb_bus_from_device(dev); 5435ac2731cSGerd Hoffmann trace_usb_packet_state_fault(bus->busnr, dev->port->path, p->ep->nr, p, 5445ac2731cSGerd Hoffmann usb_packet_state_name(p->state), 5455ac2731cSGerd Hoffmann usb_packet_state_name(expected)); 5465ac2731cSGerd Hoffmann assert(!"usb packet state check failed"); 5475ac2731cSGerd Hoffmann } 5485ac2731cSGerd Hoffmann 5495ac2731cSGerd Hoffmann void usb_packet_set_state(USBPacket *p, USBPacketState state) 5505ac2731cSGerd Hoffmann { 551f5bf14bfSGerd Hoffmann if (p->ep) { 552f1ae32a1SGerd Hoffmann USBDevice *dev = p->ep->dev; 553f1ae32a1SGerd Hoffmann USBBus *bus = usb_bus_from_device(dev); 5545ac2731cSGerd Hoffmann trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p, 5555ac2731cSGerd Hoffmann usb_packet_state_name(p->state), 5565ac2731cSGerd Hoffmann usb_packet_state_name(state)); 557f5bf14bfSGerd Hoffmann } else { 558f5bf14bfSGerd Hoffmann trace_usb_packet_state_change(-1, "", -1, p, 559f5bf14bfSGerd Hoffmann usb_packet_state_name(p->state), 560f5bf14bfSGerd Hoffmann usb_packet_state_name(state)); 561f5bf14bfSGerd Hoffmann } 562f1ae32a1SGerd Hoffmann p->state = state; 563f1ae32a1SGerd Hoffmann } 564f1ae32a1SGerd Hoffmann 5658550a02dSGerd Hoffmann void usb_packet_setup(USBPacket *p, int pid, 5668550a02dSGerd Hoffmann USBEndpoint *ep, unsigned int stream, 5678550a02dSGerd Hoffmann uint64_t id, bool short_not_ok, bool int_req) 568f1ae32a1SGerd Hoffmann { 569f1ae32a1SGerd Hoffmann assert(!usb_packet_is_inflight(p)); 5700cc6a0f1SGerd Hoffmann assert(p->iov.iov != NULL); 571e983395dSGerd Hoffmann p->id = id; 572f1ae32a1SGerd Hoffmann p->pid = pid; 573f1ae32a1SGerd Hoffmann p->ep = ep; 5748550a02dSGerd Hoffmann p->stream = stream; 5759a77a0f5SHans de Goede p->status = USB_RET_SUCCESS; 5769a77a0f5SHans de Goede p->actual_length = 0; 577f1ae32a1SGerd Hoffmann p->parameter = 0; 5786ba43f1fSHans de Goede p->short_not_ok = short_not_ok; 579a6fb2ddbSHans de Goede p->int_req = int_req; 580a552a966SHans de Goede p->combined = NULL; 581f1ae32a1SGerd Hoffmann qemu_iovec_reset(&p->iov); 582f1ae32a1SGerd Hoffmann usb_packet_set_state(p, USB_PACKET_SETUP); 583f1ae32a1SGerd Hoffmann } 584f1ae32a1SGerd Hoffmann 585f1ae32a1SGerd Hoffmann void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len) 586f1ae32a1SGerd Hoffmann { 587f1ae32a1SGerd Hoffmann qemu_iovec_add(&p->iov, ptr, len); 588f1ae32a1SGerd Hoffmann } 589f1ae32a1SGerd Hoffmann 590f1ae32a1SGerd Hoffmann void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes) 591f1ae32a1SGerd Hoffmann { 5926a98d1c0SGerd Hoffmann QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov; 5936a98d1c0SGerd Hoffmann 5949a77a0f5SHans de Goede assert(p->actual_length >= 0); 5956a98d1c0SGerd Hoffmann assert(p->actual_length + bytes <= iov->size); 596f1ae32a1SGerd Hoffmann switch (p->pid) { 597f1ae32a1SGerd Hoffmann case USB_TOKEN_SETUP: 598f1ae32a1SGerd Hoffmann case USB_TOKEN_OUT: 5996a98d1c0SGerd Hoffmann iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes); 600f1ae32a1SGerd Hoffmann break; 601f1ae32a1SGerd Hoffmann case USB_TOKEN_IN: 6026a98d1c0SGerd Hoffmann iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes); 603f1ae32a1SGerd Hoffmann break; 604f1ae32a1SGerd Hoffmann default: 605f1ae32a1SGerd Hoffmann fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid); 606f1ae32a1SGerd Hoffmann abort(); 607f1ae32a1SGerd Hoffmann } 6089a77a0f5SHans de Goede p->actual_length += bytes; 609f1ae32a1SGerd Hoffmann } 610f1ae32a1SGerd Hoffmann 611f1ae32a1SGerd Hoffmann void usb_packet_skip(USBPacket *p, size_t bytes) 612f1ae32a1SGerd Hoffmann { 6136a98d1c0SGerd Hoffmann QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov; 6146a98d1c0SGerd Hoffmann 6159a77a0f5SHans de Goede assert(p->actual_length >= 0); 6166a98d1c0SGerd Hoffmann assert(p->actual_length + bytes <= iov->size); 617f1ae32a1SGerd Hoffmann if (p->pid == USB_TOKEN_IN) { 6186a98d1c0SGerd Hoffmann iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes); 619f1ae32a1SGerd Hoffmann } 6209a77a0f5SHans de Goede p->actual_length += bytes; 621f1ae32a1SGerd Hoffmann } 622f1ae32a1SGerd Hoffmann 6236a98d1c0SGerd Hoffmann size_t usb_packet_size(USBPacket *p) 6246a98d1c0SGerd Hoffmann { 6256a98d1c0SGerd Hoffmann return p->combined ? p->combined->iov.size : p->iov.size; 6266a98d1c0SGerd Hoffmann } 6276a98d1c0SGerd Hoffmann 628f1ae32a1SGerd Hoffmann void usb_packet_cleanup(USBPacket *p) 629f1ae32a1SGerd Hoffmann { 630f1ae32a1SGerd Hoffmann assert(!usb_packet_is_inflight(p)); 631f1ae32a1SGerd Hoffmann qemu_iovec_destroy(&p->iov); 632f1ae32a1SGerd Hoffmann } 633f1ae32a1SGerd Hoffmann 63419deaa08SGerd Hoffmann void usb_ep_reset(USBDevice *dev) 635f1ae32a1SGerd Hoffmann { 636f1ae32a1SGerd Hoffmann int ep; 637f1ae32a1SGerd Hoffmann 638f1ae32a1SGerd Hoffmann dev->ep_ctl.nr = 0; 639f1ae32a1SGerd Hoffmann dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL; 640f1ae32a1SGerd Hoffmann dev->ep_ctl.ifnum = 0; 6419adbaad3SHans de Goede dev->ep_ctl.max_packet_size = 64; 64204b300f8SHans de Goede dev->ep_ctl.max_streams = 0; 643f1ae32a1SGerd Hoffmann dev->ep_ctl.dev = dev; 644f1ae32a1SGerd Hoffmann dev->ep_ctl.pipeline = false; 645f1ae32a1SGerd Hoffmann for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { 646f1ae32a1SGerd Hoffmann dev->ep_in[ep].nr = ep + 1; 647f1ae32a1SGerd Hoffmann dev->ep_out[ep].nr = ep + 1; 648f1ae32a1SGerd Hoffmann dev->ep_in[ep].pid = USB_TOKEN_IN; 649f1ae32a1SGerd Hoffmann dev->ep_out[ep].pid = USB_TOKEN_OUT; 650f1ae32a1SGerd Hoffmann dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID; 651f1ae32a1SGerd Hoffmann dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID; 6527c37e6a4SGerd Hoffmann dev->ep_in[ep].ifnum = USB_INTERFACE_INVALID; 6537c37e6a4SGerd Hoffmann dev->ep_out[ep].ifnum = USB_INTERFACE_INVALID; 6549adbaad3SHans de Goede dev->ep_in[ep].max_packet_size = 0; 6559adbaad3SHans de Goede dev->ep_out[ep].max_packet_size = 0; 65604b300f8SHans de Goede dev->ep_in[ep].max_streams = 0; 65704b300f8SHans de Goede dev->ep_out[ep].max_streams = 0; 658f1ae32a1SGerd Hoffmann dev->ep_in[ep].dev = dev; 659f1ae32a1SGerd Hoffmann dev->ep_out[ep].dev = dev; 660f1ae32a1SGerd Hoffmann dev->ep_in[ep].pipeline = false; 661f1ae32a1SGerd Hoffmann dev->ep_out[ep].pipeline = false; 66219deaa08SGerd Hoffmann } 66319deaa08SGerd Hoffmann } 66419deaa08SGerd Hoffmann 66519deaa08SGerd Hoffmann void usb_ep_init(USBDevice *dev) 66619deaa08SGerd Hoffmann { 66719deaa08SGerd Hoffmann int ep; 66819deaa08SGerd Hoffmann 66919deaa08SGerd Hoffmann usb_ep_reset(dev); 67019deaa08SGerd Hoffmann QTAILQ_INIT(&dev->ep_ctl.queue); 67119deaa08SGerd Hoffmann for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { 672f1ae32a1SGerd Hoffmann QTAILQ_INIT(&dev->ep_in[ep].queue); 673f1ae32a1SGerd Hoffmann QTAILQ_INIT(&dev->ep_out[ep].queue); 674f1ae32a1SGerd Hoffmann } 675f1ae32a1SGerd Hoffmann } 676f1ae32a1SGerd Hoffmann 677f1ae32a1SGerd Hoffmann void usb_ep_dump(USBDevice *dev) 678f1ae32a1SGerd Hoffmann { 679f1ae32a1SGerd Hoffmann static const char *tname[] = { 680f1ae32a1SGerd Hoffmann [USB_ENDPOINT_XFER_CONTROL] = "control", 681f1ae32a1SGerd Hoffmann [USB_ENDPOINT_XFER_ISOC] = "isoc", 682f1ae32a1SGerd Hoffmann [USB_ENDPOINT_XFER_BULK] = "bulk", 683f1ae32a1SGerd Hoffmann [USB_ENDPOINT_XFER_INT] = "int", 684f1ae32a1SGerd Hoffmann }; 685f1ae32a1SGerd Hoffmann int ifnum, ep, first; 686f1ae32a1SGerd Hoffmann 687f1ae32a1SGerd Hoffmann fprintf(stderr, "Device \"%s\", config %d\n", 688f1ae32a1SGerd Hoffmann dev->product_desc, dev->configuration); 689f1ae32a1SGerd Hoffmann for (ifnum = 0; ifnum < 16; ifnum++) { 690f1ae32a1SGerd Hoffmann first = 1; 691f1ae32a1SGerd Hoffmann for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { 692f1ae32a1SGerd Hoffmann if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID && 693f1ae32a1SGerd Hoffmann dev->ep_in[ep].ifnum == ifnum) { 694f1ae32a1SGerd Hoffmann if (first) { 695f1ae32a1SGerd Hoffmann first = 0; 696f1ae32a1SGerd Hoffmann fprintf(stderr, " Interface %d, alternative %d\n", 697f1ae32a1SGerd Hoffmann ifnum, dev->altsetting[ifnum]); 698f1ae32a1SGerd Hoffmann } 699f1ae32a1SGerd Hoffmann fprintf(stderr, " Endpoint %d, IN, %s, %d max\n", ep, 700f1ae32a1SGerd Hoffmann tname[dev->ep_in[ep].type], 701f1ae32a1SGerd Hoffmann dev->ep_in[ep].max_packet_size); 702f1ae32a1SGerd Hoffmann } 703f1ae32a1SGerd Hoffmann if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID && 704f1ae32a1SGerd Hoffmann dev->ep_out[ep].ifnum == ifnum) { 705f1ae32a1SGerd Hoffmann if (first) { 706f1ae32a1SGerd Hoffmann first = 0; 707f1ae32a1SGerd Hoffmann fprintf(stderr, " Interface %d, alternative %d\n", 708f1ae32a1SGerd Hoffmann ifnum, dev->altsetting[ifnum]); 709f1ae32a1SGerd Hoffmann } 710f1ae32a1SGerd Hoffmann fprintf(stderr, " Endpoint %d, OUT, %s, %d max\n", ep, 711f1ae32a1SGerd Hoffmann tname[dev->ep_out[ep].type], 712f1ae32a1SGerd Hoffmann dev->ep_out[ep].max_packet_size); 713f1ae32a1SGerd Hoffmann } 714f1ae32a1SGerd Hoffmann } 715f1ae32a1SGerd Hoffmann } 716f1ae32a1SGerd Hoffmann fprintf(stderr, "--\n"); 717f1ae32a1SGerd Hoffmann } 718f1ae32a1SGerd Hoffmann 719f1ae32a1SGerd Hoffmann struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep) 720f1ae32a1SGerd Hoffmann { 721f1ae32a1SGerd Hoffmann struct USBEndpoint *eps; 722f1ae32a1SGerd Hoffmann 7237011baecSLiam Merwick assert(dev != NULL); 724f1ae32a1SGerd Hoffmann if (ep == 0) { 725f1ae32a1SGerd Hoffmann return &dev->ep_ctl; 726f1ae32a1SGerd Hoffmann } 727f1ae32a1SGerd Hoffmann assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT); 728f1ae32a1SGerd Hoffmann assert(ep > 0 && ep <= USB_MAX_ENDPOINTS); 72956090d78SLiam Merwick eps = (pid == USB_TOKEN_IN) ? dev->ep_in : dev->ep_out; 730f1ae32a1SGerd Hoffmann return eps + ep - 1; 731f1ae32a1SGerd Hoffmann } 732f1ae32a1SGerd Hoffmann 733f1ae32a1SGerd Hoffmann uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep) 734f1ae32a1SGerd Hoffmann { 735f1ae32a1SGerd Hoffmann struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); 736f1ae32a1SGerd Hoffmann return uep->type; 737f1ae32a1SGerd Hoffmann } 738f1ae32a1SGerd Hoffmann 739f1ae32a1SGerd Hoffmann void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type) 740f1ae32a1SGerd Hoffmann { 741f1ae32a1SGerd Hoffmann struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); 742f1ae32a1SGerd Hoffmann uep->type = type; 743f1ae32a1SGerd Hoffmann } 744f1ae32a1SGerd Hoffmann 745f1ae32a1SGerd Hoffmann void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum) 746f1ae32a1SGerd Hoffmann { 747f1ae32a1SGerd Hoffmann struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); 748f1ae32a1SGerd Hoffmann uep->ifnum = ifnum; 749f1ae32a1SGerd Hoffmann } 750f1ae32a1SGerd Hoffmann 751f1ae32a1SGerd Hoffmann void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep, 752f1ae32a1SGerd Hoffmann uint16_t raw) 753f1ae32a1SGerd Hoffmann { 754f1ae32a1SGerd Hoffmann struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); 755f1ae32a1SGerd Hoffmann int size, microframes; 756f1ae32a1SGerd Hoffmann 757f1ae32a1SGerd Hoffmann size = raw & 0x7ff; 758f1ae32a1SGerd Hoffmann switch ((raw >> 11) & 3) { 759f1ae32a1SGerd Hoffmann case 1: 760f1ae32a1SGerd Hoffmann microframes = 2; 761f1ae32a1SGerd Hoffmann break; 762f1ae32a1SGerd Hoffmann case 2: 763f1ae32a1SGerd Hoffmann microframes = 3; 764f1ae32a1SGerd Hoffmann break; 765f1ae32a1SGerd Hoffmann default: 766f1ae32a1SGerd Hoffmann microframes = 1; 767f1ae32a1SGerd Hoffmann break; 768f1ae32a1SGerd Hoffmann } 769f1ae32a1SGerd Hoffmann uep->max_packet_size = size * microframes; 770f1ae32a1SGerd Hoffmann } 771f1ae32a1SGerd Hoffmann 77204b300f8SHans de Goede void usb_ep_set_max_streams(USBDevice *dev, int pid, int ep, uint8_t raw) 77304b300f8SHans de Goede { 77404b300f8SHans de Goede struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); 77504b300f8SHans de Goede int MaxStreams; 77604b300f8SHans de Goede 77704b300f8SHans de Goede MaxStreams = raw & 0x1f; 77804b300f8SHans de Goede if (MaxStreams) { 77904b300f8SHans de Goede uep->max_streams = 1 << MaxStreams; 78004b300f8SHans de Goede } else { 78104b300f8SHans de Goede uep->max_streams = 0; 78204b300f8SHans de Goede } 78304b300f8SHans de Goede } 78404b300f8SHans de Goede 785e382d966SGerd Hoffmann void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted) 786e382d966SGerd Hoffmann { 787e382d966SGerd Hoffmann struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); 788e382d966SGerd Hoffmann uep->halted = halted; 789e382d966SGerd Hoffmann } 790e382d966SGerd Hoffmann 791c13a9e61SHans de Goede USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, 792c13a9e61SHans de Goede uint64_t id) 793c13a9e61SHans de Goede { 794c13a9e61SHans de Goede struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); 795c13a9e61SHans de Goede USBPacket *p; 796c13a9e61SHans de Goede 7976735d433SHans de Goede QTAILQ_FOREACH(p, &uep->queue, queue) { 798c13a9e61SHans de Goede if (p->id == id) { 799c13a9e61SHans de Goede return p; 800c13a9e61SHans de Goede } 801c13a9e61SHans de Goede } 802c13a9e61SHans de Goede 803c13a9e61SHans de Goede return NULL; 804c13a9e61SHans de Goede } 805