1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 5f9f848faSopenharmony_ci * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 6f9f848faSopenharmony_ci * Copyright (c) 2008-2020 Hans Petter Selasky. All rights reserved. 7f9f848faSopenharmony_ci * 8f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 9f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 10f9f848faSopenharmony_ci * are met: 11f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 12f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 13f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 14f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 15f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 16f9f848faSopenharmony_ci * 17f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27f9f848faSopenharmony_ci * SUCH DAMAGE. 28f9f848faSopenharmony_ci */ 29f9f848faSopenharmony_ci 30f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 31f9f848faSopenharmony_ci 32f9f848faSopenharmony_cistatic int usb_no_cs_fail; 33f9f848faSopenharmony_cistatic int usb_full_ddesc; 34f9f848faSopenharmony_ci 35f9f848faSopenharmony_ci#define usb_port_reset_recovery_max 2000 /* ms */ 36f9f848faSopenharmony_cistatic uint32_t usb_reset_port_flag[8]; /* 256 bits for reset port flag refer to USB_MAX_PORTS */ 37f9f848faSopenharmony_ci#define PORTNO_TO_NBIT(portno, i) (1U << (portno - (i << 5))) 38f9f848faSopenharmony_ci 39f9f848faSopenharmony_cistatic void 40f9f848faSopenharmony_ciusb_reset_port_flag_set(uint8_t portno) 41f9f848faSopenharmony_ci{ 42f9f848faSopenharmony_ci uint32_t i = portno >> 5; 43f9f848faSopenharmony_ci 44f9f848faSopenharmony_ci usb_reset_port_flag[i] |= PORTNO_TO_NBIT(portno, i); 45f9f848faSopenharmony_ci} 46f9f848faSopenharmony_ci 47f9f848faSopenharmony_cistatic void 48f9f848faSopenharmony_ciusb_reset_port_flag_clear(uint8_t portno) 49f9f848faSopenharmony_ci{ 50f9f848faSopenharmony_ci uint32_t i = portno >> 5; 51f9f848faSopenharmony_ci 52f9f848faSopenharmony_ci usb_reset_port_flag[i] &= ~PORTNO_TO_NBIT(portno, i); 53f9f848faSopenharmony_ci} 54f9f848faSopenharmony_ci 55f9f848faSopenharmony_cistatic bool 56f9f848faSopenharmony_ciusb_reset_port_flag_is_set(uint8_t portno) 57f9f848faSopenharmony_ci{ 58f9f848faSopenharmony_ci uint32_t i = portno >> 5; 59f9f848faSopenharmony_ci 60f9f848faSopenharmony_ci if (usb_reset_port_flag[i] & PORTNO_TO_NBIT(portno, i)) { 61f9f848faSopenharmony_ci return true; 62f9f848faSopenharmony_ci } else { 63f9f848faSopenharmony_ci return false; 64f9f848faSopenharmony_ci } 65f9f848faSopenharmony_ci} 66f9f848faSopenharmony_ci 67f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 68f9f848faSopenharmony_ci#define USB_DEBUG_VAR usb_debug 69f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 70f9f848faSopenharmony_ci#ifdef USB_REQ_DEBUG 71f9f848faSopenharmony_ci/* The following structures are used in connection to fault injection. */ 72f9f848faSopenharmony_cistruct usb_ctrl_debug { 73f9f848faSopenharmony_ci int bus_index; /* target bus */ 74f9f848faSopenharmony_ci int dev_index; /* target address */ 75f9f848faSopenharmony_ci int ds_fail; /* fail data stage */ 76f9f848faSopenharmony_ci int ss_fail; /* fail status stage */ 77f9f848faSopenharmony_ci int ds_delay; /* data stage delay in ms */ 78f9f848faSopenharmony_ci int ss_delay; /* status stage delay in ms */ 79f9f848faSopenharmony_ci int bmRequestType_value; 80f9f848faSopenharmony_ci int bRequest_value; 81f9f848faSopenharmony_ci}; 82f9f848faSopenharmony_ci 83f9f848faSopenharmony_cistruct usb_ctrl_debug_bits { 84f9f848faSopenharmony_ci uint16_t ds_delay; 85f9f848faSopenharmony_ci uint16_t ss_delay; 86f9f848faSopenharmony_ci uint8_t ds_fail:1; 87f9f848faSopenharmony_ci uint8_t ss_fail:1; 88f9f848faSopenharmony_ci uint8_t enabled:1; 89f9f848faSopenharmony_ci}; 90f9f848faSopenharmony_ci 91f9f848faSopenharmony_ci/* The default is to disable fault injection. */ 92f9f848faSopenharmony_ci 93f9f848faSopenharmony_cistatic struct usb_ctrl_debug usb_ctrl_debug = { 94f9f848faSopenharmony_ci .bus_index = -1, 95f9f848faSopenharmony_ci .dev_index = -1, 96f9f848faSopenharmony_ci .bmRequestType_value = -1, 97f9f848faSopenharmony_ci .bRequest_value = -1, 98f9f848faSopenharmony_ci}; 99f9f848faSopenharmony_ci 100f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 101f9f848faSopenharmony_ci * usbd_get_debug_bits 102f9f848faSopenharmony_ci * 103f9f848faSopenharmony_ci * This function is only useful in USB host mode. 104f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 105f9f848faSopenharmony_cistatic void 106f9f848faSopenharmony_ciusbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req, 107f9f848faSopenharmony_ci struct usb_ctrl_debug_bits *dbg) 108f9f848faSopenharmony_ci{ 109f9f848faSopenharmony_ci int temp; 110f9f848faSopenharmony_ci 111f9f848faSopenharmony_ci (void)memset_s(dbg, sizeof(*dbg), 0, sizeof(*dbg)); 112f9f848faSopenharmony_ci 113f9f848faSopenharmony_ci /* Compute data stage delay */ 114f9f848faSopenharmony_ci 115f9f848faSopenharmony_ci temp = usb_ctrl_debug.ds_delay; 116f9f848faSopenharmony_ci if (temp < 0) 117f9f848faSopenharmony_ci temp = 0; 118f9f848faSopenharmony_ci else if (temp > (16*1024)) 119f9f848faSopenharmony_ci temp = (16*1024); 120f9f848faSopenharmony_ci 121f9f848faSopenharmony_ci dbg->ds_delay = temp; 122f9f848faSopenharmony_ci 123f9f848faSopenharmony_ci /* Compute status stage delay */ 124f9f848faSopenharmony_ci 125f9f848faSopenharmony_ci temp = usb_ctrl_debug.ss_delay; 126f9f848faSopenharmony_ci if (temp < 0) 127f9f848faSopenharmony_ci temp = 0; 128f9f848faSopenharmony_ci else if (temp > (16*1024)) 129f9f848faSopenharmony_ci temp = (16*1024); 130f9f848faSopenharmony_ci 131f9f848faSopenharmony_ci dbg->ss_delay = temp; 132f9f848faSopenharmony_ci 133f9f848faSopenharmony_ci /* Check if this control request should be failed */ 134f9f848faSopenharmony_ci 135f9f848faSopenharmony_ci if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index) 136f9f848faSopenharmony_ci return; 137f9f848faSopenharmony_ci 138f9f848faSopenharmony_ci if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index) 139f9f848faSopenharmony_ci return; 140f9f848faSopenharmony_ci 141f9f848faSopenharmony_ci temp = usb_ctrl_debug.bmRequestType_value; 142f9f848faSopenharmony_ci 143f9f848faSopenharmony_ci if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255)) 144f9f848faSopenharmony_ci return; 145f9f848faSopenharmony_ci 146f9f848faSopenharmony_ci temp = usb_ctrl_debug.bRequest_value; 147f9f848faSopenharmony_ci 148f9f848faSopenharmony_ci if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255)) 149f9f848faSopenharmony_ci return; 150f9f848faSopenharmony_ci 151f9f848faSopenharmony_ci temp = usb_ctrl_debug.ds_fail; 152f9f848faSopenharmony_ci if (temp) 153f9f848faSopenharmony_ci dbg->ds_fail = 1; 154f9f848faSopenharmony_ci 155f9f848faSopenharmony_ci temp = usb_ctrl_debug.ss_fail; 156f9f848faSopenharmony_ci if (temp) 157f9f848faSopenharmony_ci dbg->ss_fail = 1; 158f9f848faSopenharmony_ci 159f9f848faSopenharmony_ci dbg->enabled = 1; 160f9f848faSopenharmony_ci} 161f9f848faSopenharmony_ci#endif /* USB_REQ_DEBUG */ 162f9f848faSopenharmony_ci#endif /* LOSCFG_USB_DEBUG */ 163f9f848faSopenharmony_ci 164f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 165f9f848faSopenharmony_ci * usbd_do_request_callback 166f9f848faSopenharmony_ci * 167f9f848faSopenharmony_ci * This function is the USB callback for generic USB Host control 168f9f848faSopenharmony_ci * transfers. 169f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 170f9f848faSopenharmony_civoid 171f9f848faSopenharmony_ciusbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error) 172f9f848faSopenharmony_ci{ 173f9f848faSopenharmony_ci ; /* workaround for a bug in "indent" */ 174f9f848faSopenharmony_ci 175f9f848faSopenharmony_ci DPRINTF("st=%u\n", USB_GET_STATE(xfer)); 176f9f848faSopenharmony_ci 177f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 178f9f848faSopenharmony_ci case USB_ST_SETUP: 179f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 180f9f848faSopenharmony_ci break; 181f9f848faSopenharmony_ci default: 182f9f848faSopenharmony_ci (void)cv_signal(&xfer->xroot->udev->ctrlreq_cv); 183f9f848faSopenharmony_ci break; 184f9f848faSopenharmony_ci } 185f9f848faSopenharmony_ci} 186f9f848faSopenharmony_ci 187f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 188f9f848faSopenharmony_ci * usb_do_clear_stall_callback 189f9f848faSopenharmony_ci * 190f9f848faSopenharmony_ci * This function is the USB callback for generic clear stall requests. 191f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 192f9f848faSopenharmony_civoid 193f9f848faSopenharmony_ciusb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 194f9f848faSopenharmony_ci{ 195f9f848faSopenharmony_ci struct usb_device_request req; 196f9f848faSopenharmony_ci struct usb_device *udev; 197f9f848faSopenharmony_ci struct usb_endpoint *ep; 198f9f848faSopenharmony_ci struct usb_endpoint *ep_end; 199f9f848faSopenharmony_ci struct usb_endpoint *ep_first; 200f9f848faSopenharmony_ci usb_stream_t x; 201f9f848faSopenharmony_ci uint8_t to; 202f9f848faSopenharmony_ci 203f9f848faSopenharmony_ci udev = xfer->xroot->udev; 204f9f848faSopenharmony_ci 205f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 206f9f848faSopenharmony_ci 207f9f848faSopenharmony_ci /* round robin endpoint clear stall */ 208f9f848faSopenharmony_ci 209f9f848faSopenharmony_ci ep = udev->ep_curr; 210f9f848faSopenharmony_ci ep_end = udev->endpoints + udev->endpoints_max; 211f9f848faSopenharmony_ci ep_first = udev->endpoints; 212f9f848faSopenharmony_ci to = udev->endpoints_max; 213f9f848faSopenharmony_ci 214f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 215f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 216f9f848faSopenharmony_citr_transferred: 217f9f848faSopenharmony_ci /* reset error counter */ 218f9f848faSopenharmony_ci udev->clear_stall_errors = 0; 219f9f848faSopenharmony_ci 220f9f848faSopenharmony_ci if (ep == NULL) 221f9f848faSopenharmony_ci goto tr_setup; /* device was unconfigured */ 222f9f848faSopenharmony_ci if (ep->edesc && 223f9f848faSopenharmony_ci ep->is_stalled) { 224f9f848faSopenharmony_ci ep->toggle_next = 0; 225f9f848faSopenharmony_ci ep->is_stalled = 0; 226f9f848faSopenharmony_ci /* some hardware needs a callback to clear the data toggle */ 227f9f848faSopenharmony_ci usbd_clear_stall_locked(udev, ep); 228f9f848faSopenharmony_ci for (x = 0; x != USB_MAX_EP_STREAMS; x++) { 229f9f848faSopenharmony_ci /* start the current or next transfer, if any */ 230f9f848faSopenharmony_ci usb_command_wrapper(&ep->endpoint_q[x], 231f9f848faSopenharmony_ci ep->endpoint_q[x].curr); 232f9f848faSopenharmony_ci } 233f9f848faSopenharmony_ci } 234f9f848faSopenharmony_ci ep++; 235f9f848faSopenharmony_ci 236f9f848faSopenharmony_ci case USB_ST_SETUP: 237f9f848faSopenharmony_citr_setup: 238f9f848faSopenharmony_ci if (to == 0) 239f9f848faSopenharmony_ci break; /* no endpoints - nothing to do */ 240f9f848faSopenharmony_ci if ((ep < ep_first) || (ep >= ep_end)) 241f9f848faSopenharmony_ci ep = ep_first; /* endpoint wrapped around */ 242f9f848faSopenharmony_ci if (ep->edesc && 243f9f848faSopenharmony_ci ep->is_stalled) { 244f9f848faSopenharmony_ci /* setup a clear-stall packet */ 245f9f848faSopenharmony_ci 246f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_ENDPOINT; 247f9f848faSopenharmony_ci req.bRequest = UR_CLEAR_FEATURE; 248f9f848faSopenharmony_ci USETW(req.wValue, UF_ENDPOINT_HALT); 249f9f848faSopenharmony_ci req.wIndex[0] = ep->edesc->bEndpointAddress; 250f9f848faSopenharmony_ci req.wIndex[1] = 0; 251f9f848faSopenharmony_ci USETW(req.wLength, 0); 252f9f848faSopenharmony_ci 253f9f848faSopenharmony_ci /* copy in the transfer */ 254f9f848faSopenharmony_ci 255f9f848faSopenharmony_ci usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 256f9f848faSopenharmony_ci 257f9f848faSopenharmony_ci /* set length */ 258f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 259f9f848faSopenharmony_ci xfer->nframes = 1; 260f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 261f9f848faSopenharmony_ci 262f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 263f9f848faSopenharmony_ci 264f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 265f9f848faSopenharmony_ci break; 266f9f848faSopenharmony_ci } 267f9f848faSopenharmony_ci ep++; 268f9f848faSopenharmony_ci to--; 269f9f848faSopenharmony_ci goto tr_setup; 270f9f848faSopenharmony_ci 271f9f848faSopenharmony_ci default: 272f9f848faSopenharmony_ci if (error == USB_ERR_CANCELLED) 273f9f848faSopenharmony_ci break; 274f9f848faSopenharmony_ci 275f9f848faSopenharmony_ci DPRINTF("Clear stall failed.\n"); 276f9f848faSopenharmony_ci 277f9f848faSopenharmony_ci /* 278f9f848faSopenharmony_ci * Some VMs like VirtualBox always return failure on 279f9f848faSopenharmony_ci * clear-stall which we sometimes should just ignore. 280f9f848faSopenharmony_ci */ 281f9f848faSopenharmony_ci if (usb_no_cs_fail) 282f9f848faSopenharmony_ci goto tr_transferred; 283f9f848faSopenharmony_ci 284f9f848faSopenharmony_ci /* 285f9f848faSopenharmony_ci * Some non-compliant USB devices do not implement the 286f9f848faSopenharmony_ci * clear endpoint halt feature. Silently ignore such 287f9f848faSopenharmony_ci * devices, when they at least respond correctly 288f9f848faSopenharmony_ci * passing up a valid STALL PID packet. 289f9f848faSopenharmony_ci */ 290f9f848faSopenharmony_ci if (error == USB_ERR_STALLED) 291f9f848faSopenharmony_ci goto tr_transferred; 292f9f848faSopenharmony_ci 293f9f848faSopenharmony_ci if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) 294f9f848faSopenharmony_ci goto tr_setup; 295f9f848faSopenharmony_ci 296f9f848faSopenharmony_ci if (error == USB_ERR_TIMEOUT) { 297f9f848faSopenharmony_ci udev->clear_stall_errors = USB_CS_RESET_LIMIT; 298f9f848faSopenharmony_ci DPRINTF("Trying to re-enumerate.\n"); 299f9f848faSopenharmony_ci usbd_start_re_enumerate(udev); 300f9f848faSopenharmony_ci } else { 301f9f848faSopenharmony_ci udev->clear_stall_errors++; 302f9f848faSopenharmony_ci if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) { 303f9f848faSopenharmony_ci DPRINTF("Trying to re-enumerate.\n"); 304f9f848faSopenharmony_ci usbd_start_re_enumerate(udev); 305f9f848faSopenharmony_ci } 306f9f848faSopenharmony_ci } 307f9f848faSopenharmony_ci goto tr_setup; 308f9f848faSopenharmony_ci } 309f9f848faSopenharmony_ci 310f9f848faSopenharmony_ci /* store current endpoint */ 311f9f848faSopenharmony_ci udev->ep_curr = ep; 312f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 313f9f848faSopenharmony_ci} 314f9f848faSopenharmony_ci 315f9f848faSopenharmony_cistatic usb_handle_req_t * 316f9f848faSopenharmony_ciusbd_get_hr_func(struct usb_device *udev) 317f9f848faSopenharmony_ci{ 318f9f848faSopenharmony_ci /* figure out if there is a Handle Request function */ 319f9f848faSopenharmony_ci if (udev->flags.usb_mode == USB_MODE_DEVICE) 320f9f848faSopenharmony_ci return (usb_temp_get_desc_p); 321f9f848faSopenharmony_ci else if (udev->parent_hub == NULL) 322f9f848faSopenharmony_ci return (udev->bus->methods->roothub_exec); 323f9f848faSopenharmony_ci else 324f9f848faSopenharmony_ci return (NULL); 325f9f848faSopenharmony_ci} 326f9f848faSopenharmony_ci 327f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 328f9f848faSopenharmony_ci * usbd_do_request_flags and usbd_do_request 329f9f848faSopenharmony_ci * 330f9f848faSopenharmony_ci * Description of arguments passed to these functions: 331f9f848faSopenharmony_ci * 332f9f848faSopenharmony_ci * "udev" - this is the "usb_device" structure pointer on which the 333f9f848faSopenharmony_ci * request should be performed. It is possible to call this function 334f9f848faSopenharmony_ci * in both Host Side mode and Device Side mode. 335f9f848faSopenharmony_ci * 336f9f848faSopenharmony_ci * "mtx" - if this argument is non-NULL the mutex pointed to by it 337f9f848faSopenharmony_ci * will get dropped and picked up during the execution of this 338f9f848faSopenharmony_ci * function, hence this function sometimes needs to sleep. If this 339f9f848faSopenharmony_ci * argument is NULL it has no effect. 340f9f848faSopenharmony_ci * 341f9f848faSopenharmony_ci * "req" - this argument must always be non-NULL and points to an 342f9f848faSopenharmony_ci * 8-byte structure holding the USB request to be done. The USB 343f9f848faSopenharmony_ci * request structure has a bit telling the direction of the USB 344f9f848faSopenharmony_ci * request, if it is a read or a write. 345f9f848faSopenharmony_ci * 346f9f848faSopenharmony_ci * "data" - if the "wLength" part of the structure pointed to by "req" 347f9f848faSopenharmony_ci * is non-zero this argument must point to a valid kernel buffer which 348f9f848faSopenharmony_ci * can hold at least "wLength" bytes. If "wLength" is zero "data" can 349f9f848faSopenharmony_ci * be NULL. 350f9f848faSopenharmony_ci * 351f9f848faSopenharmony_ci * "flags" - here is a list of valid flags: 352f9f848faSopenharmony_ci * 353f9f848faSopenharmony_ci * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 354f9f848faSopenharmony_ci * specified 355f9f848faSopenharmony_ci * 356f9f848faSopenharmony_ci * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 357f9f848faSopenharmony_ci * at a later point in time. This is tunable by the "hw.usb.ss_delay" 358f9f848faSopenharmony_ci * sysctl. This flag is mostly useful for debugging. 359f9f848faSopenharmony_ci * 360f9f848faSopenharmony_ci * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 361f9f848faSopenharmony_ci * pointer. 362f9f848faSopenharmony_ci * 363f9f848faSopenharmony_ci * "actlen" - if non-NULL the actual transfer length will be stored in 364f9f848faSopenharmony_ci * the 16-bit unsigned integer pointed to by "actlen". This 365f9f848faSopenharmony_ci * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 366f9f848faSopenharmony_ci * used. 367f9f848faSopenharmony_ci * 368f9f848faSopenharmony_ci * "timeout" - gives the timeout for the control transfer in 369f9f848faSopenharmony_ci * milliseconds. A "timeout" value less than 50 milliseconds is 370f9f848faSopenharmony_ci * treated like a 50 millisecond timeout. A "timeout" value greater 371f9f848faSopenharmony_ci * than 30 seconds is treated like a 30 second timeout. This USB stack 372f9f848faSopenharmony_ci * does not allow control requests without a timeout. 373f9f848faSopenharmony_ci * 374f9f848faSopenharmony_ci * NOTE: This function is thread safe. All calls to "usbd_do_request_flags" 375f9f848faSopenharmony_ci * will be serialized by the use of the USB device enumeration lock. 376f9f848faSopenharmony_ci * 377f9f848faSopenharmony_ci * Returns: 378f9f848faSopenharmony_ci * 0: Success 379f9f848faSopenharmony_ci * Else: Failure 380f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 381f9f848faSopenharmony_ciusb_error_t 382f9f848faSopenharmony_ciusbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 383f9f848faSopenharmony_ci struct usb_device_request *req, void *data, uint16_t flags, 384f9f848faSopenharmony_ci uint16_t *actlen, usb_timeout_t timeout) 385f9f848faSopenharmony_ci{ 386f9f848faSopenharmony_ci#ifdef USB_REQ_DEBUG 387f9f848faSopenharmony_ci struct usb_ctrl_debug_bits dbg; 388f9f848faSopenharmony_ci#endif 389f9f848faSopenharmony_ci usb_handle_req_t *hr_func; 390f9f848faSopenharmony_ci struct usb_xfer *xfer; 391f9f848faSopenharmony_ci const void *desc; 392f9f848faSopenharmony_ci int err = 0; 393f9f848faSopenharmony_ci usb_ticks_t start_ticks; 394f9f848faSopenharmony_ci usb_ticks_t delta_ticks; 395f9f848faSopenharmony_ci usb_ticks_t max_ticks; 396f9f848faSopenharmony_ci uint16_t length; 397f9f848faSopenharmony_ci uint16_t temp; 398f9f848faSopenharmony_ci uint16_t acttemp; 399f9f848faSopenharmony_ci uint8_t do_unlock; 400f9f848faSopenharmony_ci 401f9f848faSopenharmony_ci if (timeout < 50) { 402f9f848faSopenharmony_ci /* timeout is too small */ 403f9f848faSopenharmony_ci timeout = 50; 404f9f848faSopenharmony_ci } 405f9f848faSopenharmony_ci if (timeout > 30000) { 406f9f848faSopenharmony_ci /* timeout is too big */ 407f9f848faSopenharmony_ci timeout = 30000; 408f9f848faSopenharmony_ci } 409f9f848faSopenharmony_ci length = UGETW(req->wLength); 410f9f848faSopenharmony_ci 411f9f848faSopenharmony_ci DPRINTFN(6, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 412f9f848faSopenharmony_ci "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 413f9f848faSopenharmony_ci udev, req->bmRequestType, req->bRequest, 414f9f848faSopenharmony_ci req->wValue[1], req->wValue[0], 415f9f848faSopenharmony_ci req->wIndex[1], req->wIndex[0], 416f9f848faSopenharmony_ci req->wLength[1], req->wLength[0]); 417f9f848faSopenharmony_ci 418f9f848faSopenharmony_ci /* Check if the device is still alive */ 419f9f848faSopenharmony_ci if (udev->state < USB_STATE_POWERED) { 420f9f848faSopenharmony_ci DPRINTF("usb device has gone\n"); 421f9f848faSopenharmony_ci return (USB_ERR_NOT_CONFIGURED); 422f9f848faSopenharmony_ci } 423f9f848faSopenharmony_ci 424f9f848faSopenharmony_ci /* 425f9f848faSopenharmony_ci * Set "actlen" to a known value in case the caller does not 426f9f848faSopenharmony_ci * check the return value: 427f9f848faSopenharmony_ci */ 428f9f848faSopenharmony_ci if (actlen) 429f9f848faSopenharmony_ci *actlen = 0; 430f9f848faSopenharmony_ci 431f9f848faSopenharmony_ci#if (USB_HAVE_USER_IO == 0) 432f9f848faSopenharmony_ci if (flags & USB_USER_DATA_PTR) 433f9f848faSopenharmony_ci return (USB_ERR_INVAL); 434f9f848faSopenharmony_ci#endif 435f9f848faSopenharmony_ci if ((mtx != NULL) && (mtx != &Giant)) { 436f9f848faSopenharmony_ci USB_MTX_UNLOCK(mtx); 437f9f848faSopenharmony_ci USB_MTX_ASSERT(mtx, MA_NOTOWNED); 438f9f848faSopenharmony_ci } 439f9f848faSopenharmony_ci 440f9f848faSopenharmony_ci /* 441f9f848faSopenharmony_ci * Serialize access to this function: 442f9f848faSopenharmony_ci */ 443f9f848faSopenharmony_ci do_unlock = usbd_ctrl_lock(udev); 444f9f848faSopenharmony_ci 445f9f848faSopenharmony_ci hr_func = usbd_get_hr_func(udev); 446f9f848faSopenharmony_ci if (hr_func != NULL) { 447f9f848faSopenharmony_ci DPRINTF("Handle Request function is set\n"); 448f9f848faSopenharmony_ci 449f9f848faSopenharmony_ci desc = NULL; 450f9f848faSopenharmony_ci temp = 0; 451f9f848faSopenharmony_ci 452f9f848faSopenharmony_ci if (!(req->bmRequestType & UT_READ)) { 453f9f848faSopenharmony_ci if (length != 0) { 454f9f848faSopenharmony_ci DPRINTFN(1, "The handle request function " 455f9f848faSopenharmony_ci "does not support writing data!\n"); 456f9f848faSopenharmony_ci err = USB_ERR_INVAL; 457f9f848faSopenharmony_ci goto done; 458f9f848faSopenharmony_ci } 459f9f848faSopenharmony_ci } 460f9f848faSopenharmony_ci 461f9f848faSopenharmony_ci /* The root HUB code needs the BUS lock locked */ 462f9f848faSopenharmony_ci 463f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 464f9f848faSopenharmony_ci err = (hr_func) (udev, req, &desc, &temp); 465f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 466f9f848faSopenharmony_ci 467f9f848faSopenharmony_ci if (err) 468f9f848faSopenharmony_ci goto done; 469f9f848faSopenharmony_ci 470f9f848faSopenharmony_ci if (length > temp) { 471f9f848faSopenharmony_ci if (!(flags & USB_SHORT_XFER_OK)) { 472f9f848faSopenharmony_ci err = USB_ERR_SHORT_XFER; 473f9f848faSopenharmony_ci goto done; 474f9f848faSopenharmony_ci } 475f9f848faSopenharmony_ci length = temp; 476f9f848faSopenharmony_ci } 477f9f848faSopenharmony_ci if (actlen) 478f9f848faSopenharmony_ci *actlen = length; 479f9f848faSopenharmony_ci 480f9f848faSopenharmony_ci if (length > 0) { 481f9f848faSopenharmony_ci#if USB_HAVE_USER_IO 482f9f848faSopenharmony_ci if (flags & USB_USER_DATA_PTR) { 483f9f848faSopenharmony_ci if (copyout(desc, data, length)) { 484f9f848faSopenharmony_ci err = USB_ERR_INVAL; 485f9f848faSopenharmony_ci goto done; 486f9f848faSopenharmony_ci } 487f9f848faSopenharmony_ci } else 488f9f848faSopenharmony_ci#endif 489f9f848faSopenharmony_ci (void)memcpy_s(data, length, desc, length); 490f9f848faSopenharmony_ci } 491f9f848faSopenharmony_ci goto done; /* success */ 492f9f848faSopenharmony_ci } 493f9f848faSopenharmony_ci 494f9f848faSopenharmony_ci /* 495f9f848faSopenharmony_ci * Setup a new USB transfer or use the existing one, if any: 496f9f848faSopenharmony_ci */ 497f9f848faSopenharmony_ci usbd_ctrl_transfer_setup(udev); 498f9f848faSopenharmony_ci 499f9f848faSopenharmony_ci xfer = udev->ctrl_xfer[0]; 500f9f848faSopenharmony_ci if (xfer == NULL) { 501f9f848faSopenharmony_ci /* most likely out of memory */ 502f9f848faSopenharmony_ci err = USB_ERR_NOMEM; 503f9f848faSopenharmony_ci goto done; 504f9f848faSopenharmony_ci } 505f9f848faSopenharmony_ci 506f9f848faSopenharmony_ci#ifdef USB_REQ_DEBUG 507f9f848faSopenharmony_ci /* Get debug bits */ 508f9f848faSopenharmony_ci usbd_get_debug_bits(udev, req, &dbg); 509f9f848faSopenharmony_ci 510f9f848faSopenharmony_ci /* Check for fault injection */ 511f9f848faSopenharmony_ci if (dbg.enabled) 512f9f848faSopenharmony_ci flags |= USB_DELAY_STATUS_STAGE; 513f9f848faSopenharmony_ci#endif 514f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 515f9f848faSopenharmony_ci 516f9f848faSopenharmony_ci if (flags & USB_DELAY_STATUS_STAGE) 517f9f848faSopenharmony_ci xfer->flags.manual_status = 1; 518f9f848faSopenharmony_ci else 519f9f848faSopenharmony_ci xfer->flags.manual_status = 0; 520f9f848faSopenharmony_ci 521f9f848faSopenharmony_ci if (flags & USB_SHORT_XFER_OK) 522f9f848faSopenharmony_ci xfer->flags.short_xfer_ok = 1; 523f9f848faSopenharmony_ci else 524f9f848faSopenharmony_ci xfer->flags.short_xfer_ok = 0; 525f9f848faSopenharmony_ci 526f9f848faSopenharmony_ci xfer->timeout = timeout; 527f9f848faSopenharmony_ci 528f9f848faSopenharmony_ci start_ticks = CUR_TICKS; 529f9f848faSopenharmony_ci 530f9f848faSopenharmony_ci max_ticks = USB_MS_TO_TICKS(timeout); 531f9f848faSopenharmony_ci 532f9f848faSopenharmony_ci usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); 533f9f848faSopenharmony_ci 534f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(*req)); 535f9f848faSopenharmony_ci 536f9f848faSopenharmony_ci while (1) { 537f9f848faSopenharmony_ci temp = length; 538f9f848faSopenharmony_ci if (temp > usbd_xfer_max_len(xfer)) { 539f9f848faSopenharmony_ci temp = usbd_xfer_max_len(xfer); 540f9f848faSopenharmony_ci } 541f9f848faSopenharmony_ci#ifdef USB_REQ_DEBUG 542f9f848faSopenharmony_ci if (xfer->flags.manual_status) { 543f9f848faSopenharmony_ci if (usbd_xfer_frame_len(xfer, 0) != 0) { 544f9f848faSopenharmony_ci /* Execute data stage separately */ 545f9f848faSopenharmony_ci temp = 0; 546f9f848faSopenharmony_ci } else if (temp > 0) { 547f9f848faSopenharmony_ci if (dbg.ds_fail) { 548f9f848faSopenharmony_ci err = USB_ERR_INVAL; 549f9f848faSopenharmony_ci break; 550f9f848faSopenharmony_ci } 551f9f848faSopenharmony_ci if (dbg.ds_delay > 0) { 552f9f848faSopenharmony_ci usb_pause_mtx( 553f9f848faSopenharmony_ci xfer->xroot->xfer_mtx, 554f9f848faSopenharmony_ci USB_MS_TO_TICKS(dbg.ds_delay)); 555f9f848faSopenharmony_ci /* make sure we don't time out */ 556f9f848faSopenharmony_ci start_ticks = CUR_TICKS; 557f9f848faSopenharmony_ci } 558f9f848faSopenharmony_ci } 559f9f848faSopenharmony_ci } 560f9f848faSopenharmony_ci#endif 561f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 1, temp); 562f9f848faSopenharmony_ci 563f9f848faSopenharmony_ci if (temp > 0) { 564f9f848faSopenharmony_ci if (!(req->bmRequestType & UT_READ)) { 565f9f848faSopenharmony_ci#if USB_HAVE_USER_IO 566f9f848faSopenharmony_ci if (flags & USB_USER_DATA_PTR) { 567f9f848faSopenharmony_ci USB_XFER_UNLOCK(xfer); 568f9f848faSopenharmony_ci err = usbd_copy_in_user(xfer->frbuffers + 1, 569f9f848faSopenharmony_ci 0, data, temp); 570f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 571f9f848faSopenharmony_ci if (err) { 572f9f848faSopenharmony_ci err = USB_ERR_INVAL; 573f9f848faSopenharmony_ci break; 574f9f848faSopenharmony_ci } 575f9f848faSopenharmony_ci } else 576f9f848faSopenharmony_ci#endif 577f9f848faSopenharmony_ci usbd_copy_in(xfer->frbuffers + 1, 578f9f848faSopenharmony_ci 0, data, temp); 579f9f848faSopenharmony_ci } 580f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 2); 581f9f848faSopenharmony_ci } else { 582f9f848faSopenharmony_ci if (usbd_xfer_frame_len(xfer, 0) == 0) { 583f9f848faSopenharmony_ci if (xfer->flags.manual_status) { 584f9f848faSopenharmony_ci#ifdef USB_REQ_DEBUG 585f9f848faSopenharmony_ci if (dbg.ss_fail) { 586f9f848faSopenharmony_ci err = USB_ERR_INVAL; 587f9f848faSopenharmony_ci break; 588f9f848faSopenharmony_ci } 589f9f848faSopenharmony_ci if (dbg.ss_delay > 0) { 590f9f848faSopenharmony_ci usb_pause_mtx( 591f9f848faSopenharmony_ci xfer->xroot->xfer_mtx, 592f9f848faSopenharmony_ci USB_MS_TO_TICKS(dbg.ss_delay)); 593f9f848faSopenharmony_ci /* make sure we don't time out */ 594f9f848faSopenharmony_ci start_ticks = CUR_TICKS; 595f9f848faSopenharmony_ci } 596f9f848faSopenharmony_ci#endif 597f9f848faSopenharmony_ci xfer->flags.manual_status = 0; 598f9f848faSopenharmony_ci } else { 599f9f848faSopenharmony_ci break; 600f9f848faSopenharmony_ci } 601f9f848faSopenharmony_ci } 602f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 1); 603f9f848faSopenharmony_ci } 604f9f848faSopenharmony_ci 605f9f848faSopenharmony_ci usbd_transfer_start(xfer); 606f9f848faSopenharmony_ci 607f9f848faSopenharmony_ci while (usbd_transfer_pending(xfer)) { 608f9f848faSopenharmony_ci (void)cv_wait(&udev->ctrlreq_cv, 609f9f848faSopenharmony_ci xfer->xroot->xfer_mtx); 610f9f848faSopenharmony_ci } 611f9f848faSopenharmony_ci 612f9f848faSopenharmony_ci err = xfer->error; 613f9f848faSopenharmony_ci 614f9f848faSopenharmony_ci if (err) { 615f9f848faSopenharmony_ci break; 616f9f848faSopenharmony_ci } 617f9f848faSopenharmony_ci 618f9f848faSopenharmony_ci /* get actual length of DATA stage */ 619f9f848faSopenharmony_ci 620f9f848faSopenharmony_ci if (xfer->aframes < 2) { 621f9f848faSopenharmony_ci acttemp = 0; 622f9f848faSopenharmony_ci } else { 623f9f848faSopenharmony_ci acttemp = usbd_xfer_frame_len(xfer, 1); 624f9f848faSopenharmony_ci } 625f9f848faSopenharmony_ci 626f9f848faSopenharmony_ci /* check for short packet */ 627f9f848faSopenharmony_ci 628f9f848faSopenharmony_ci if (temp > acttemp) { 629f9f848faSopenharmony_ci temp = acttemp; 630f9f848faSopenharmony_ci length = temp; 631f9f848faSopenharmony_ci } 632f9f848faSopenharmony_ci if (temp > 0) { 633f9f848faSopenharmony_ci if (req->bmRequestType & UT_READ) { 634f9f848faSopenharmony_ci#if USB_HAVE_USER_IO 635f9f848faSopenharmony_ci if (flags & USB_USER_DATA_PTR) { 636f9f848faSopenharmony_ci USB_XFER_UNLOCK(xfer); 637f9f848faSopenharmony_ci err = usbd_copy_out_user(xfer->frbuffers + 1, 638f9f848faSopenharmony_ci 0, data, temp); 639f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 640f9f848faSopenharmony_ci if (err) { 641f9f848faSopenharmony_ci err = USB_ERR_INVAL; 642f9f848faSopenharmony_ci break; 643f9f848faSopenharmony_ci } 644f9f848faSopenharmony_ci } else 645f9f848faSopenharmony_ci#endif 646f9f848faSopenharmony_ci usbd_copy_out(xfer->frbuffers + 1, 647f9f848faSopenharmony_ci 0, data, temp); 648f9f848faSopenharmony_ci } 649f9f848faSopenharmony_ci } 650f9f848faSopenharmony_ci /* 651f9f848faSopenharmony_ci * Clear "frlengths[0]" so that we don't send the setup 652f9f848faSopenharmony_ci * packet again: 653f9f848faSopenharmony_ci */ 654f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, 0); 655f9f848faSopenharmony_ci 656f9f848faSopenharmony_ci /* update length and data pointer */ 657f9f848faSopenharmony_ci length -= temp; 658f9f848faSopenharmony_ci data = USB_ADD_BYTES(data, temp); 659f9f848faSopenharmony_ci 660f9f848faSopenharmony_ci if (actlen) { 661f9f848faSopenharmony_ci (*actlen) += temp; 662f9f848faSopenharmony_ci } 663f9f848faSopenharmony_ci /* check for timeout */ 664f9f848faSopenharmony_ci 665f9f848faSopenharmony_ci delta_ticks = CUR_TICKS - start_ticks; 666f9f848faSopenharmony_ci if (delta_ticks > max_ticks) { 667f9f848faSopenharmony_ci if (!err) { 668f9f848faSopenharmony_ci err = USB_ERR_TIMEOUT; 669f9f848faSopenharmony_ci } 670f9f848faSopenharmony_ci } 671f9f848faSopenharmony_ci if (err) { 672f9f848faSopenharmony_ci break; 673f9f848faSopenharmony_ci } 674f9f848faSopenharmony_ci } 675f9f848faSopenharmony_ci 676f9f848faSopenharmony_ci if (err) { 677f9f848faSopenharmony_ci /* 678f9f848faSopenharmony_ci * Make sure that the control endpoint is no longer 679f9f848faSopenharmony_ci * blocked in case of a non-transfer related error: 680f9f848faSopenharmony_ci */ 681f9f848faSopenharmony_ci usbd_transfer_stop(xfer); 682f9f848faSopenharmony_ci } 683f9f848faSopenharmony_ci USB_XFER_UNLOCK(xfer); 684f9f848faSopenharmony_ci 685f9f848faSopenharmony_cidone: 686f9f848faSopenharmony_ci if (do_unlock) 687f9f848faSopenharmony_ci usbd_ctrl_unlock(udev); 688f9f848faSopenharmony_ci 689f9f848faSopenharmony_ci if ((mtx != NULL) && (mtx != &Giant)) 690f9f848faSopenharmony_ci USB_MTX_LOCK(mtx); 691f9f848faSopenharmony_ci 692f9f848faSopenharmony_ci switch (err) { 693f9f848faSopenharmony_ci case USB_ERR_NORMAL_COMPLETION: 694f9f848faSopenharmony_ci case USB_ERR_SHORT_XFER: 695f9f848faSopenharmony_ci case USB_ERR_STALLED: 696f9f848faSopenharmony_ci case USB_ERR_CANCELLED: 697f9f848faSopenharmony_ci break; 698f9f848faSopenharmony_ci default: 699f9f848faSopenharmony_ci DPRINTF("I/O error - waiting a bit for TT cleanup\n"); 700f9f848faSopenharmony_ci usb_pause_mtx(mtx, hz / 16); 701f9f848faSopenharmony_ci break; 702f9f848faSopenharmony_ci } 703f9f848faSopenharmony_ci return ((usb_error_t)err); 704f9f848faSopenharmony_ci} 705f9f848faSopenharmony_ci 706f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 707f9f848faSopenharmony_ci * usbd_do_request_proc - factored out code 708f9f848faSopenharmony_ci * 709f9f848faSopenharmony_ci * This function is factored out code. It does basically the same like 710f9f848faSopenharmony_ci * usbd_do_request_flags, except it will check the status of the 711f9f848faSopenharmony_ci * passed process argument before doing the USB request. If the 712f9f848faSopenharmony_ci * process is draining the USB_ERR_IOERROR code will be returned. It 713f9f848faSopenharmony_ci * is assumed that the mutex associated with the process is locked 714f9f848faSopenharmony_ci * when calling this function. 715f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 716f9f848faSopenharmony_ciusb_error_t 717f9f848faSopenharmony_ciusbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, 718f9f848faSopenharmony_ci struct usb_device_request *req, void *data, uint16_t flags, 719f9f848faSopenharmony_ci uint16_t *actlen, usb_timeout_t timeout) 720f9f848faSopenharmony_ci{ 721f9f848faSopenharmony_ci usb_error_t err; 722f9f848faSopenharmony_ci uint16_t len; 723f9f848faSopenharmony_ci 724f9f848faSopenharmony_ci /* get request data length */ 725f9f848faSopenharmony_ci len = UGETW(req->wLength); 726f9f848faSopenharmony_ci 727f9f848faSopenharmony_ci /* check if the device is being detached */ 728f9f848faSopenharmony_ci if (usb_proc_is_gone(pproc)) { 729f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 730f9f848faSopenharmony_ci goto done; 731f9f848faSopenharmony_ci } 732f9f848faSopenharmony_ci 733f9f848faSopenharmony_ci /* forward the USB request */ 734f9f848faSopenharmony_ci err = usbd_do_request_flags(udev, pproc->up_mtx, 735f9f848faSopenharmony_ci req, data, flags, actlen, timeout); 736f9f848faSopenharmony_ci 737f9f848faSopenharmony_cidone: 738f9f848faSopenharmony_ci /* on failure we zero the data */ 739f9f848faSopenharmony_ci /* on short packet we zero the unused data */ 740f9f848faSopenharmony_ci if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { 741f9f848faSopenharmony_ci if (err) 742f9f848faSopenharmony_ci (void)memset_s(data, len, 0, len); 743f9f848faSopenharmony_ci else if (actlen && *actlen != len) 744f9f848faSopenharmony_ci (void)memset_s(((uint8_t *)data) + *actlen, len - *actlen, 0, len - *actlen); 745f9f848faSopenharmony_ci } 746f9f848faSopenharmony_ci return (err); 747f9f848faSopenharmony_ci} 748f9f848faSopenharmony_ci 749f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 750f9f848faSopenharmony_ci * usbd_req_reset_port 751f9f848faSopenharmony_ci * 752f9f848faSopenharmony_ci * This function will instruct a USB HUB to perform a reset sequence 753f9f848faSopenharmony_ci * on the specified port number. 754f9f848faSopenharmony_ci * 755f9f848faSopenharmony_ci * Returns: 756f9f848faSopenharmony_ci * 0: Success. The USB device should now be at address zero. 757f9f848faSopenharmony_ci * Else: Failure. No USB device is present and the USB port should be 758f9f848faSopenharmony_ci * disabled. 759f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 760f9f848faSopenharmony_ciusb_error_t 761f9f848faSopenharmony_ciusbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 762f9f848faSopenharmony_ci{ 763f9f848faSopenharmony_ci struct usb_port_status ps; 764f9f848faSopenharmony_ci usb_error_t err; 765f9f848faSopenharmony_ci uint16_t n; 766f9f848faSopenharmony_ci uint16_t status; 767f9f848faSopenharmony_ci uint16_t change; 768f9f848faSopenharmony_ci 769f9f848faSopenharmony_ci DPRINTF("\n"); 770f9f848faSopenharmony_ci 771f9f848faSopenharmony_ci /* clear any leftover port reset changes first */ 772f9f848faSopenharmony_ci (void)usbd_req_clear_port_feature( 773f9f848faSopenharmony_ci udev, mtx, port, UHF_C_PORT_RESET); 774f9f848faSopenharmony_ci 775f9f848faSopenharmony_ci /* assert port reset on the given port */ 776f9f848faSopenharmony_ci err = usbd_req_set_port_feature( 777f9f848faSopenharmony_ci udev, mtx, port, UHF_PORT_RESET); 778f9f848faSopenharmony_ci 779f9f848faSopenharmony_ci /* check for errors */ 780f9f848faSopenharmony_ci if (err) 781f9f848faSopenharmony_ci goto done; 782f9f848faSopenharmony_ci n = 0; 783f9f848faSopenharmony_ci while (1) { 784f9f848faSopenharmony_ci /* wait for the device to recover from reset */ 785f9f848faSopenharmony_ci usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay)); 786f9f848faSopenharmony_ci n += usb_port_reset_delay; 787f9f848faSopenharmony_ci err = usbd_req_get_port_status(udev, mtx, &ps, port); 788f9f848faSopenharmony_ci if (err) 789f9f848faSopenharmony_ci goto done; 790f9f848faSopenharmony_ci 791f9f848faSopenharmony_ci status = UGETW(ps.wPortStatus); 792f9f848faSopenharmony_ci change = UGETW(ps.wPortChange); 793f9f848faSopenharmony_ci 794f9f848faSopenharmony_ci /* The port state is unknown until the reset completes. 795f9f848faSopenharmony_ci * On top of that, some chips may require additional time to re-establish a connection after the reset is complete, 796f9f848faSopenharmony_ci * so also wait for the connection to be re-established. 797f9f848faSopenharmony_ci */ 798f9f848faSopenharmony_ci if (!(status & UPS_RESET) && (status & UPS_CURRENT_CONNECT_STATUS)) 799f9f848faSopenharmony_ci break; 800f9f848faSopenharmony_ci 801f9f848faSopenharmony_ci /* check for timeout */ 802f9f848faSopenharmony_ci if (n > 1000) { 803f9f848faSopenharmony_ci n = 0; 804f9f848faSopenharmony_ci break; 805f9f848faSopenharmony_ci } 806f9f848faSopenharmony_ci } 807f9f848faSopenharmony_ci 808f9f848faSopenharmony_ci /* clear port reset first */ 809f9f848faSopenharmony_ci err = usbd_req_clear_port_feature( 810f9f848faSopenharmony_ci udev, mtx, port, UHF_C_PORT_RESET); 811f9f848faSopenharmony_ci if (err) 812f9f848faSopenharmony_ci goto done; 813f9f848faSopenharmony_ci 814f9f848faSopenharmony_ci if (change & UPS_CURRENT_CONNECT_STATUS) { 815f9f848faSopenharmony_ci usb_reset_port_flag_set(port); 816f9f848faSopenharmony_ci return (USB_ERR_IOERROR); 817f9f848faSopenharmony_ci } 818f9f848faSopenharmony_ci 819f9f848faSopenharmony_ci if ((udev->speed == USB_SPEED_SUPER) && 820f9f848faSopenharmony_ci (change & UHF_C_BH_PORT_RESET)) { 821f9f848faSopenharmony_ci /* try to clear port warm reset */ 822f9f848faSopenharmony_ci err = usbd_req_clear_port_feature( 823f9f848faSopenharmony_ci udev, mtx, port, UHF_C_BH_PORT_RESET); 824f9f848faSopenharmony_ci if (err) 825f9f848faSopenharmony_ci goto done; 826f9f848faSopenharmony_ci } 827f9f848faSopenharmony_ci 828f9f848faSopenharmony_ci /* check for timeout */ 829f9f848faSopenharmony_ci if (n == 0) { 830f9f848faSopenharmony_ci err = USB_ERR_TIMEOUT; 831f9f848faSopenharmony_ci goto done; 832f9f848faSopenharmony_ci } 833f9f848faSopenharmony_ci 834f9f848faSopenharmony_ci /* wait for the device to recover from reset */ 835f9f848faSopenharmony_ci if (usb_reset_port_flag_is_set(port) == true) { 836f9f848faSopenharmony_ci usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery_max)); 837f9f848faSopenharmony_ci usb_reset_port_flag_clear(port); 838f9f848faSopenharmony_ci } else { 839f9f848faSopenharmony_ci usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery)); 840f9f848faSopenharmony_ci } 841f9f848faSopenharmony_ci 842f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 843f9f848faSopenharmony_ci 844f9f848faSopenharmony_cidone: 845f9f848faSopenharmony_ci DPRINTFN(0, "port %d reset returning error=%s\n", 846f9f848faSopenharmony_ci port, usbd_errstr(err)); 847f9f848faSopenharmony_ci return (err); 848f9f848faSopenharmony_ci} 849f9f848faSopenharmony_ci 850f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 851f9f848faSopenharmony_ci * usbd_req_warm_reset_port 852f9f848faSopenharmony_ci * 853f9f848faSopenharmony_ci * This function will instruct an USB HUB to perform a warm reset 854f9f848faSopenharmony_ci * sequence on the specified port number. This kind of reset is not 855f9f848faSopenharmony_ci * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted 856f9f848faSopenharmony_ci * for SUPER-speed USB HUBs. 857f9f848faSopenharmony_ci * 858f9f848faSopenharmony_ci * Returns: 859f9f848faSopenharmony_ci * 0: Success. The USB device should now be available again. 860f9f848faSopenharmony_ci * Else: Failure. No USB device is present and the USB port should be 861f9f848faSopenharmony_ci * disabled. 862f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 863f9f848faSopenharmony_ciusb_error_t 864f9f848faSopenharmony_ciusbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, 865f9f848faSopenharmony_ci uint8_t port) 866f9f848faSopenharmony_ci{ 867f9f848faSopenharmony_ci struct usb_port_status ps; 868f9f848faSopenharmony_ci usb_error_t err; 869f9f848faSopenharmony_ci uint16_t n; 870f9f848faSopenharmony_ci uint16_t status; 871f9f848faSopenharmony_ci uint16_t change; 872f9f848faSopenharmony_ci 873f9f848faSopenharmony_ci DPRINTF("\n"); 874f9f848faSopenharmony_ci 875f9f848faSopenharmony_ci err = usbd_req_get_port_status(udev, mtx, &ps, port); 876f9f848faSopenharmony_ci if (err) 877f9f848faSopenharmony_ci goto done; 878f9f848faSopenharmony_ci 879f9f848faSopenharmony_ci status = UGETW(ps.wPortStatus); 880f9f848faSopenharmony_ci 881f9f848faSopenharmony_ci switch (UPS_PORT_LINK_STATE_GET(status)) { 882f9f848faSopenharmony_ci case UPS_PORT_LS_U3: 883f9f848faSopenharmony_ci case UPS_PORT_LS_COMP_MODE: 884f9f848faSopenharmony_ci case UPS_PORT_LS_LOOPBACK: 885f9f848faSopenharmony_ci case UPS_PORT_LS_SS_INA: 886f9f848faSopenharmony_ci break; 887f9f848faSopenharmony_ci default: 888f9f848faSopenharmony_ci DPRINTF("Wrong state for warm reset\n"); 889f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 890f9f848faSopenharmony_ci } 891f9f848faSopenharmony_ci 892f9f848faSopenharmony_ci /* clear any leftover warm port reset changes first */ 893f9f848faSopenharmony_ci (void)usbd_req_clear_port_feature(udev, mtx, 894f9f848faSopenharmony_ci port, UHF_C_BH_PORT_RESET); 895f9f848faSopenharmony_ci 896f9f848faSopenharmony_ci /* set warm port reset */ 897f9f848faSopenharmony_ci err = usbd_req_set_port_feature(udev, mtx, 898f9f848faSopenharmony_ci port, UHF_BH_PORT_RESET); 899f9f848faSopenharmony_ci if (err) 900f9f848faSopenharmony_ci goto done; 901f9f848faSopenharmony_ci 902f9f848faSopenharmony_ci n = 0; 903f9f848faSopenharmony_ci while (1) { 904f9f848faSopenharmony_ci /* wait for the device to recover from reset */ 905f9f848faSopenharmony_ci usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay)); 906f9f848faSopenharmony_ci n += usb_port_reset_delay; 907f9f848faSopenharmony_ci err = usbd_req_get_port_status(udev, mtx, &ps, port); 908f9f848faSopenharmony_ci if (err) 909f9f848faSopenharmony_ci goto done; 910f9f848faSopenharmony_ci 911f9f848faSopenharmony_ci status = UGETW(ps.wPortStatus); 912f9f848faSopenharmony_ci change = UGETW(ps.wPortChange); 913f9f848faSopenharmony_ci 914f9f848faSopenharmony_ci /* if the device disappeared, just give up */ 915f9f848faSopenharmony_ci if (!(status & UPS_CURRENT_CONNECT_STATUS)) 916f9f848faSopenharmony_ci goto done; 917f9f848faSopenharmony_ci 918f9f848faSopenharmony_ci /* check if reset is complete */ 919f9f848faSopenharmony_ci if (change & UPS_C_BH_PORT_RESET) 920f9f848faSopenharmony_ci break; 921f9f848faSopenharmony_ci 922f9f848faSopenharmony_ci /* check for timeout */ 923f9f848faSopenharmony_ci if (n > 1000) { 924f9f848faSopenharmony_ci n = 0; 925f9f848faSopenharmony_ci break; 926f9f848faSopenharmony_ci } 927f9f848faSopenharmony_ci } 928f9f848faSopenharmony_ci 929f9f848faSopenharmony_ci /* clear port reset first */ 930f9f848faSopenharmony_ci err = usbd_req_clear_port_feature( 931f9f848faSopenharmony_ci udev, mtx, port, UHF_C_BH_PORT_RESET); 932f9f848faSopenharmony_ci if (err) 933f9f848faSopenharmony_ci goto done; 934f9f848faSopenharmony_ci 935f9f848faSopenharmony_ci /* check for timeout */ 936f9f848faSopenharmony_ci if (n == 0) { 937f9f848faSopenharmony_ci err = USB_ERR_TIMEOUT; 938f9f848faSopenharmony_ci goto done; 939f9f848faSopenharmony_ci } 940f9f848faSopenharmony_ci /* wait for the device to recover from reset */ 941f9f848faSopenharmony_ci usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery)); 942f9f848faSopenharmony_ci 943f9f848faSopenharmony_cidone: 944f9f848faSopenharmony_ci DPRINTFN(2, "port %d warm reset returning error=%s\n", 945f9f848faSopenharmony_ci port, usbd_errstr(err)); 946f9f848faSopenharmony_ci return (err); 947f9f848faSopenharmony_ci} 948f9f848faSopenharmony_ci 949f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 950f9f848faSopenharmony_ci * usbd_req_get_desc 951f9f848faSopenharmony_ci * 952f9f848faSopenharmony_ci * This function can be used to retrieve USB descriptors. It contains 953f9f848faSopenharmony_ci * some additional logic like zeroing of missing descriptor bytes and 954f9f848faSopenharmony_ci * retrying an USB descriptor in case of failure. The "min_len" 955f9f848faSopenharmony_ci * argument specifies the minimum descriptor length. The "max_len" 956f9f848faSopenharmony_ci * argument specifies the maximum descriptor length. If the real 957f9f848faSopenharmony_ci * descriptor length is less than the minimum length the missing 958f9f848faSopenharmony_ci * byte(s) will be zeroed. The type field, the second byte of the USB 959f9f848faSopenharmony_ci * descriptor, will get forced to the correct type. If the "actlen" 960f9f848faSopenharmony_ci * pointer is non-NULL, the actual length of the transfer will get 961f9f848faSopenharmony_ci * stored in the 16-bit unsigned integer which it is pointing to. The 962f9f848faSopenharmony_ci * first byte of the descriptor will not get updated. If the "actlen" 963f9f848faSopenharmony_ci * pointer is NULL the first byte of the descriptor will get updated 964f9f848faSopenharmony_ci * to reflect the actual length instead. If "min_len" is not equal to 965f9f848faSopenharmony_ci * "max_len" then this function will try to retrive the beginning of 966f9f848faSopenharmony_ci * the descriptor and base the maximum length on the first byte of the 967f9f848faSopenharmony_ci * descriptor. 968f9f848faSopenharmony_ci * 969f9f848faSopenharmony_ci * Returns: 970f9f848faSopenharmony_ci * 0: Success 971f9f848faSopenharmony_ci * Else: Failure 972f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 973f9f848faSopenharmony_ciusb_error_t 974f9f848faSopenharmony_ciusbd_req_get_desc(struct usb_device *udev, 975f9f848faSopenharmony_ci struct mtx *mtx, uint16_t *actlen, void *desc, 976f9f848faSopenharmony_ci uint16_t min_len, uint16_t max_len, 977f9f848faSopenharmony_ci uint16_t id, uint8_t type, uint8_t index, 978f9f848faSopenharmony_ci uint8_t retries) 979f9f848faSopenharmony_ci{ 980f9f848faSopenharmony_ci struct usb_device_request req; 981f9f848faSopenharmony_ci uint8_t *buf; 982f9f848faSopenharmony_ci usb_error_t err; 983f9f848faSopenharmony_ci 984f9f848faSopenharmony_ci DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 985f9f848faSopenharmony_ci id, type, index, max_len); 986f9f848faSopenharmony_ci 987f9f848faSopenharmony_ci req.bmRequestType = UT_READ_DEVICE; 988f9f848faSopenharmony_ci req.bRequest = UR_GET_DESCRIPTOR; 989f9f848faSopenharmony_ci USETW2(req.wValue, type, index); 990f9f848faSopenharmony_ci USETW(req.wIndex, id); 991f9f848faSopenharmony_ci 992f9f848faSopenharmony_ci while (1) { 993f9f848faSopenharmony_ci if ((min_len < 2) || (max_len < 2)) { 994f9f848faSopenharmony_ci err = USB_ERR_INVAL; 995f9f848faSopenharmony_ci goto done; 996f9f848faSopenharmony_ci } 997f9f848faSopenharmony_ci USETW(req.wLength, min_len); 998f9f848faSopenharmony_ci 999f9f848faSopenharmony_ci err = usbd_do_request_flags(udev, mtx, &req, 1000f9f848faSopenharmony_ci desc, 0, NULL, 500 /* ms */); 1001f9f848faSopenharmony_ci 1002f9f848faSopenharmony_ci if (err) { 1003f9f848faSopenharmony_ci if (!retries) { 1004f9f848faSopenharmony_ci goto done; 1005f9f848faSopenharmony_ci } 1006f9f848faSopenharmony_ci retries--; 1007f9f848faSopenharmony_ci 1008f9f848faSopenharmony_ci usb_pause_mtx(mtx, hz / 5); 1009f9f848faSopenharmony_ci 1010f9f848faSopenharmony_ci continue; 1011f9f848faSopenharmony_ci } 1012f9f848faSopenharmony_ci buf = desc; 1013f9f848faSopenharmony_ci 1014f9f848faSopenharmony_ci if (min_len == max_len) { 1015f9f848faSopenharmony_ci /* enforce correct length */ 1016f9f848faSopenharmony_ci if ((buf[0] > min_len) && (actlen == NULL)) 1017f9f848faSopenharmony_ci buf[0] = min_len; 1018f9f848faSopenharmony_ci 1019f9f848faSopenharmony_ci /* enforce correct type */ 1020f9f848faSopenharmony_ci buf[1] = type; 1021f9f848faSopenharmony_ci 1022f9f848faSopenharmony_ci goto done; 1023f9f848faSopenharmony_ci } 1024f9f848faSopenharmony_ci /* range check */ 1025f9f848faSopenharmony_ci 1026f9f848faSopenharmony_ci if (max_len > buf[0]) { 1027f9f848faSopenharmony_ci max_len = buf[0]; 1028f9f848faSopenharmony_ci } 1029f9f848faSopenharmony_ci /* zero minimum data */ 1030f9f848faSopenharmony_ci 1031f9f848faSopenharmony_ci while (min_len > max_len) { 1032f9f848faSopenharmony_ci min_len--; 1033f9f848faSopenharmony_ci buf[min_len] = 0; 1034f9f848faSopenharmony_ci } 1035f9f848faSopenharmony_ci 1036f9f848faSopenharmony_ci /* set new minimum length */ 1037f9f848faSopenharmony_ci 1038f9f848faSopenharmony_ci min_len = max_len; 1039f9f848faSopenharmony_ci } 1040f9f848faSopenharmony_cidone: 1041f9f848faSopenharmony_ci if (actlen != NULL) { 1042f9f848faSopenharmony_ci if (err) 1043f9f848faSopenharmony_ci *actlen = 0; 1044f9f848faSopenharmony_ci else 1045f9f848faSopenharmony_ci *actlen = min_len; 1046f9f848faSopenharmony_ci } 1047f9f848faSopenharmony_ci return (err); 1048f9f848faSopenharmony_ci} 1049f9f848faSopenharmony_ci 1050f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1051f9f848faSopenharmony_ci * usbd_req_get_string_any 1052f9f848faSopenharmony_ci * 1053f9f848faSopenharmony_ci * This function will return the string given by "string_index" 1054f9f848faSopenharmony_ci * using the first language ID. The maximum length "len" includes 1055f9f848faSopenharmony_ci * the terminating zero. The "len" argument should be twice as 1056f9f848faSopenharmony_ci * big pluss 2 bytes, compared with the actual maximum string length ! 1057f9f848faSopenharmony_ci * 1058f9f848faSopenharmony_ci * Returns: 1059f9f848faSopenharmony_ci * 0: Success 1060f9f848faSopenharmony_ci * Else: Failure 1061f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1062f9f848faSopenharmony_ciusb_error_t 1063f9f848faSopenharmony_ciusbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 1064f9f848faSopenharmony_ci uint16_t len, uint8_t string_index) 1065f9f848faSopenharmony_ci{ 1066f9f848faSopenharmony_ci char *s; 1067f9f848faSopenharmony_ci uint8_t *temp; 1068f9f848faSopenharmony_ci uint16_t i; 1069f9f848faSopenharmony_ci uint16_t n; 1070f9f848faSopenharmony_ci uint16_t c; 1071f9f848faSopenharmony_ci uint8_t swap; 1072f9f848faSopenharmony_ci usb_error_t err; 1073f9f848faSopenharmony_ci 1074f9f848faSopenharmony_ci if (len == 0) { 1075f9f848faSopenharmony_ci /* should not happen */ 1076f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 1077f9f848faSopenharmony_ci } 1078f9f848faSopenharmony_ci if (string_index == 0) { 1079f9f848faSopenharmony_ci /* this is the language table */ 1080f9f848faSopenharmony_ci buf[0] = 0; 1081f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1082f9f848faSopenharmony_ci } 1083f9f848faSopenharmony_ci if (udev->flags.no_strings) { 1084f9f848faSopenharmony_ci buf[0] = 0; 1085f9f848faSopenharmony_ci return (USB_ERR_STALLED); 1086f9f848faSopenharmony_ci } 1087f9f848faSopenharmony_ci err = usbd_req_get_string_desc 1088f9f848faSopenharmony_ci (udev, mtx, buf, len, udev->langid, string_index); 1089f9f848faSopenharmony_ci if (err) { 1090f9f848faSopenharmony_ci buf[0] = 0; 1091f9f848faSopenharmony_ci return (err); 1092f9f848faSopenharmony_ci } 1093f9f848faSopenharmony_ci temp = (uint8_t *)buf; 1094f9f848faSopenharmony_ci 1095f9f848faSopenharmony_ci if (temp[0] < 2) { 1096f9f848faSopenharmony_ci /* string length is too short */ 1097f9f848faSopenharmony_ci buf[0] = 0; 1098f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1099f9f848faSopenharmony_ci } 1100f9f848faSopenharmony_ci /* reserve one byte for terminating zero */ 1101f9f848faSopenharmony_ci len--; 1102f9f848faSopenharmony_ci 1103f9f848faSopenharmony_ci /* find maximum length */ 1104f9f848faSopenharmony_ci s = buf; 1105f9f848faSopenharmony_ci n = (temp[0] / 2) - 1; 1106f9f848faSopenharmony_ci if (n > len) { 1107f9f848faSopenharmony_ci n = len; 1108f9f848faSopenharmony_ci } 1109f9f848faSopenharmony_ci /* skip descriptor header */ 1110f9f848faSopenharmony_ci temp += 2; 1111f9f848faSopenharmony_ci 1112f9f848faSopenharmony_ci /* reset swap state */ 1113f9f848faSopenharmony_ci swap = 3; 1114f9f848faSopenharmony_ci 1115f9f848faSopenharmony_ci /* convert and filter */ 1116f9f848faSopenharmony_ci for (i = 0; (i != n); i++) { 1117f9f848faSopenharmony_ci c = UGETW(temp + (2 * i)); 1118f9f848faSopenharmony_ci 1119f9f848faSopenharmony_ci /* convert from Unicode, handle buggy strings */ 1120f9f848faSopenharmony_ci if (((c & 0xff00) == 0) && (swap & 1)) { 1121f9f848faSopenharmony_ci /* Little Endian, default */ 1122f9f848faSopenharmony_ci *s = c; 1123f9f848faSopenharmony_ci swap = 1; 1124f9f848faSopenharmony_ci } else if (((c & 0x00ff) == 0) && (swap & 2)) { 1125f9f848faSopenharmony_ci /* Big Endian */ 1126f9f848faSopenharmony_ci *s = c >> 8; 1127f9f848faSopenharmony_ci swap = 2; 1128f9f848faSopenharmony_ci } else { 1129f9f848faSopenharmony_ci /* silently skip bad character */ 1130f9f848faSopenharmony_ci continue; 1131f9f848faSopenharmony_ci } 1132f9f848faSopenharmony_ci 1133f9f848faSopenharmony_ci /* 1134f9f848faSopenharmony_ci * Filter by default - We only allow alphanumerical 1135f9f848faSopenharmony_ci * and a few more to avoid any problems with scripts 1136f9f848faSopenharmony_ci * and daemons. 1137f9f848faSopenharmony_ci */ 1138f9f848faSopenharmony_ci if (isalpha(*s) || 1139f9f848faSopenharmony_ci isdigit(*s) || 1140f9f848faSopenharmony_ci *s == '-' || 1141f9f848faSopenharmony_ci *s == '+' || 1142f9f848faSopenharmony_ci *s == ' ' || 1143f9f848faSopenharmony_ci *s == '.' || 1144f9f848faSopenharmony_ci *s == ',') { 1145f9f848faSopenharmony_ci /* allowed */ 1146f9f848faSopenharmony_ci s++; 1147f9f848faSopenharmony_ci } 1148f9f848faSopenharmony_ci /* silently skip bad character */ 1149f9f848faSopenharmony_ci } 1150f9f848faSopenharmony_ci *s = 0; /* zero terminate resulting string */ 1151f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 1152f9f848faSopenharmony_ci} 1153f9f848faSopenharmony_ci 1154f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1155f9f848faSopenharmony_ci * usbd_req_get_string_desc 1156f9f848faSopenharmony_ci * 1157f9f848faSopenharmony_ci * If you don't know the language ID, consider using 1158f9f848faSopenharmony_ci * "usbd_req_get_string_any()". 1159f9f848faSopenharmony_ci * 1160f9f848faSopenharmony_ci * Returns: 1161f9f848faSopenharmony_ci * 0: Success 1162f9f848faSopenharmony_ci * Else: Failure 1163f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1164f9f848faSopenharmony_ciusb_error_t 1165f9f848faSopenharmony_ciusbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 1166f9f848faSopenharmony_ci uint16_t max_len, uint16_t lang_id, 1167f9f848faSopenharmony_ci uint8_t string_index) 1168f9f848faSopenharmony_ci{ 1169f9f848faSopenharmony_ci return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 1170f9f848faSopenharmony_ci UDESC_STRING, string_index, 0)); 1171f9f848faSopenharmony_ci} 1172f9f848faSopenharmony_ci 1173f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1174f9f848faSopenharmony_ci * usbd_req_get_config_desc_ptr 1175f9f848faSopenharmony_ci * 1176f9f848faSopenharmony_ci * This function is used in device side mode to retrieve the pointer 1177f9f848faSopenharmony_ci * to the generated config descriptor. This saves allocating space for 1178f9f848faSopenharmony_ci * an additional config descriptor when setting the configuration. 1179f9f848faSopenharmony_ci * 1180f9f848faSopenharmony_ci * Returns: 1181f9f848faSopenharmony_ci * 0: Success 1182f9f848faSopenharmony_ci * Else: Failure 1183f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1184f9f848faSopenharmony_ciusb_error_t 1185f9f848faSopenharmony_ciusbd_req_get_descriptor_ptr(struct usb_device *udev, 1186f9f848faSopenharmony_ci struct usb_config_descriptor **ppcd, uint16_t wValue) 1187f9f848faSopenharmony_ci{ 1188f9f848faSopenharmony_ci struct usb_device_request req; 1189f9f848faSopenharmony_ci usb_handle_req_t *hr_func; 1190f9f848faSopenharmony_ci const void *ptr; 1191f9f848faSopenharmony_ci uint16_t len; 1192f9f848faSopenharmony_ci usb_error_t err; 1193f9f848faSopenharmony_ci 1194f9f848faSopenharmony_ci req.bmRequestType = UT_READ_DEVICE; 1195f9f848faSopenharmony_ci req.bRequest = UR_GET_DESCRIPTOR; 1196f9f848faSopenharmony_ci USETW(req.wValue, wValue); 1197f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1198f9f848faSopenharmony_ci USETW(req.wLength, 0); 1199f9f848faSopenharmony_ci 1200f9f848faSopenharmony_ci ptr = NULL; 1201f9f848faSopenharmony_ci len = 0; 1202f9f848faSopenharmony_ci 1203f9f848faSopenharmony_ci hr_func = usbd_get_hr_func(udev); 1204f9f848faSopenharmony_ci 1205f9f848faSopenharmony_ci if (hr_func == NULL) 1206f9f848faSopenharmony_ci err = USB_ERR_INVAL; 1207f9f848faSopenharmony_ci else { 1208f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 1209f9f848faSopenharmony_ci err = (hr_func) (udev, &req, &ptr, &len); 1210f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 1211f9f848faSopenharmony_ci } 1212f9f848faSopenharmony_ci 1213f9f848faSopenharmony_ci if (err) 1214f9f848faSopenharmony_ci ptr = NULL; 1215f9f848faSopenharmony_ci else if (ptr == NULL) 1216f9f848faSopenharmony_ci err = USB_ERR_INVAL; 1217f9f848faSopenharmony_ci 1218f9f848faSopenharmony_ci *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 1219f9f848faSopenharmony_ci 1220f9f848faSopenharmony_ci return (err); 1221f9f848faSopenharmony_ci} 1222f9f848faSopenharmony_ci 1223f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1224f9f848faSopenharmony_ci * usbd_req_get_config_desc 1225f9f848faSopenharmony_ci * 1226f9f848faSopenharmony_ci * Returns: 1227f9f848faSopenharmony_ci * 0: Success 1228f9f848faSopenharmony_ci * Else: Failure 1229f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1230f9f848faSopenharmony_ciusb_error_t 1231f9f848faSopenharmony_ciusbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 1232f9f848faSopenharmony_ci struct usb_config_descriptor *d, uint8_t conf_index) 1233f9f848faSopenharmony_ci{ 1234f9f848faSopenharmony_ci usb_error_t err; 1235f9f848faSopenharmony_ci 1236f9f848faSopenharmony_ci DPRINTFN(4, "confidx=%d\n", conf_index); 1237f9f848faSopenharmony_ci 1238f9f848faSopenharmony_ci err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1239f9f848faSopenharmony_ci sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 1240f9f848faSopenharmony_ci if (err) { 1241f9f848faSopenharmony_ci goto done; 1242f9f848faSopenharmony_ci } 1243f9f848faSopenharmony_ci /* Extra sanity checking */ 1244f9f848faSopenharmony_ci if (UGETW(d->wTotalLength) < (uint16_t)sizeof(*d)) { 1245f9f848faSopenharmony_ci err = USB_ERR_INVAL; 1246f9f848faSopenharmony_ci } 1247f9f848faSopenharmony_cidone: 1248f9f848faSopenharmony_ci return (err); 1249f9f848faSopenharmony_ci} 1250f9f848faSopenharmony_ci 1251f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1252f9f848faSopenharmony_ci * usbd_alloc_config_desc 1253f9f848faSopenharmony_ci * 1254f9f848faSopenharmony_ci * This function is used to allocate a zeroed configuration 1255f9f848faSopenharmony_ci * descriptor. 1256f9f848faSopenharmony_ci * 1257f9f848faSopenharmony_ci * Returns: 1258f9f848faSopenharmony_ci * NULL: Failure 1259f9f848faSopenharmony_ci * Else: Success 1260f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1261f9f848faSopenharmony_civoid * 1262f9f848faSopenharmony_ciusbd_alloc_config_desc(struct usb_device *udev, uint32_t size) 1263f9f848faSopenharmony_ci{ 1264f9f848faSopenharmony_ci if (size > USB_CONFIG_MAX) { 1265f9f848faSopenharmony_ci DPRINTF("Configuration descriptor too big\n"); 1266f9f848faSopenharmony_ci return (NULL); 1267f9f848faSopenharmony_ci } 1268f9f848faSopenharmony_ci#if (USB_HAVE_FIXED_CONFIG == 0) 1269f9f848faSopenharmony_ci return (bsd_malloc(size, M_USBDEV, M_ZERO | M_WAITOK)); 1270f9f848faSopenharmony_ci#else 1271f9f848faSopenharmony_ci (void)memset_s(udev->config_data, sizeof(udev->config_data), 0, sizeof(udev->config_data)); 1272f9f848faSopenharmony_ci return (udev->config_data); 1273f9f848faSopenharmony_ci#endif 1274f9f848faSopenharmony_ci} 1275f9f848faSopenharmony_ci 1276f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1277f9f848faSopenharmony_ci * usbd_alloc_config_desc 1278f9f848faSopenharmony_ci * 1279f9f848faSopenharmony_ci * This function is used to free a configuration descriptor. 1280f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1281f9f848faSopenharmony_civoid 1282f9f848faSopenharmony_ciusbd_free_config_desc(struct usb_device *udev, void *ptr) 1283f9f848faSopenharmony_ci{ 1284f9f848faSopenharmony_ci#if (USB_HAVE_FIXED_CONFIG == 0) 1285f9f848faSopenharmony_ci bsd_free(ptr, M_USBDEV); 1286f9f848faSopenharmony_ci#endif 1287f9f848faSopenharmony_ci} 1288f9f848faSopenharmony_ci 1289f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1290f9f848faSopenharmony_ci * usbd_req_get_config_desc_full 1291f9f848faSopenharmony_ci * 1292f9f848faSopenharmony_ci * This function gets the complete USB configuration descriptor and 1293f9f848faSopenharmony_ci * ensures that "wTotalLength" is correct. The returned configuration 1294f9f848faSopenharmony_ci * descriptor is freed by calling "usbd_free_config_desc()". 1295f9f848faSopenharmony_ci * 1296f9f848faSopenharmony_ci * Returns: 1297f9f848faSopenharmony_ci * 0: Success 1298f9f848faSopenharmony_ci * Else: Failure 1299f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1300f9f848faSopenharmony_ciusb_error_t 1301f9f848faSopenharmony_ciusbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 1302f9f848faSopenharmony_ci struct usb_config_descriptor **ppcd, uint8_t index) 1303f9f848faSopenharmony_ci{ 1304f9f848faSopenharmony_ci struct usb_config_descriptor cd; 1305f9f848faSopenharmony_ci struct usb_config_descriptor *cdesc; 1306f9f848faSopenharmony_ci uint32_t len; 1307f9f848faSopenharmony_ci usb_error_t err; 1308f9f848faSopenharmony_ci 1309f9f848faSopenharmony_ci DPRINTFN(4, "index=%d\n", index); 1310f9f848faSopenharmony_ci 1311f9f848faSopenharmony_ci *ppcd = NULL; 1312f9f848faSopenharmony_ci 1313f9f848faSopenharmony_ci err = usbd_req_get_config_desc(udev, mtx, &cd, index); 1314f9f848faSopenharmony_ci if (err) 1315f9f848faSopenharmony_ci return (err); 1316f9f848faSopenharmony_ci 1317f9f848faSopenharmony_ci /* get full descriptor */ 1318f9f848faSopenharmony_ci len = UGETW(cd.wTotalLength); 1319f9f848faSopenharmony_ci if (len < (uint32_t)sizeof(*cdesc)) { 1320f9f848faSopenharmony_ci /* corrupt descriptor */ 1321f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1322f9f848faSopenharmony_ci } else if (len > USB_CONFIG_MAX) { 1323f9f848faSopenharmony_ci DPRINTF("Configuration descriptor was truncated\n"); 1324f9f848faSopenharmony_ci len = USB_CONFIG_MAX; 1325f9f848faSopenharmony_ci } 1326f9f848faSopenharmony_ci cdesc = usbd_alloc_config_desc(udev, len); 1327f9f848faSopenharmony_ci if (cdesc == NULL) 1328f9f848faSopenharmony_ci return (USB_ERR_NOMEM); 1329f9f848faSopenharmony_ci err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 1330f9f848faSopenharmony_ci UDESC_CONFIG, index, 3); 1331f9f848faSopenharmony_ci if (err) { 1332f9f848faSopenharmony_ci usbd_free_config_desc(udev, cdesc); 1333f9f848faSopenharmony_ci return (err); 1334f9f848faSopenharmony_ci } 1335f9f848faSopenharmony_ci /* make sure that the device is not fooling us: */ 1336f9f848faSopenharmony_ci USETW(cdesc->wTotalLength, len); 1337f9f848faSopenharmony_ci 1338f9f848faSopenharmony_ci *ppcd = cdesc; 1339f9f848faSopenharmony_ci 1340f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); /* success */ 1341f9f848faSopenharmony_ci} 1342f9f848faSopenharmony_ci 1343f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1344f9f848faSopenharmony_ci * usbd_req_get_device_desc 1345f9f848faSopenharmony_ci * 1346f9f848faSopenharmony_ci * Returns: 1347f9f848faSopenharmony_ci * 0: Success 1348f9f848faSopenharmony_ci * Else: Failure 1349f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1350f9f848faSopenharmony_ciusb_error_t 1351f9f848faSopenharmony_ciusbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1352f9f848faSopenharmony_ci struct usb_device_descriptor *d) 1353f9f848faSopenharmony_ci{ 1354f9f848faSopenharmony_ci DPRINTFN(4, "\n"); 1355f9f848faSopenharmony_ci return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1356f9f848faSopenharmony_ci sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1357f9f848faSopenharmony_ci} 1358f9f848faSopenharmony_ci 1359f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1360f9f848faSopenharmony_ci * usbd_req_get_alt_interface_no 1361f9f848faSopenharmony_ci * 1362f9f848faSopenharmony_ci * Returns: 1363f9f848faSopenharmony_ci * 0: Success 1364f9f848faSopenharmony_ci * Else: Failure 1365f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1366f9f848faSopenharmony_ciusb_error_t 1367f9f848faSopenharmony_ciusbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1368f9f848faSopenharmony_ci uint8_t *alt_iface_no, uint8_t iface_index) 1369f9f848faSopenharmony_ci{ 1370f9f848faSopenharmony_ci struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1371f9f848faSopenharmony_ci struct usb_device_request req; 1372f9f848faSopenharmony_ci 1373f9f848faSopenharmony_ci if ((iface == NULL) || (iface->idesc == NULL)) 1374f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1375f9f848faSopenharmony_ci 1376f9f848faSopenharmony_ci req.bmRequestType = UT_READ_INTERFACE; 1377f9f848faSopenharmony_ci req.bRequest = UR_GET_INTERFACE; 1378f9f848faSopenharmony_ci USETW(req.wValue, 0); 1379f9f848faSopenharmony_ci req.wIndex[0] = iface->idesc->bInterfaceNumber; 1380f9f848faSopenharmony_ci req.wIndex[1] = 0; 1381f9f848faSopenharmony_ci USETW(req.wLength, 1); 1382f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1383f9f848faSopenharmony_ci} 1384f9f848faSopenharmony_ci 1385f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1386f9f848faSopenharmony_ci * usbd_req_set_alt_interface_no 1387f9f848faSopenharmony_ci * 1388f9f848faSopenharmony_ci * Returns: 1389f9f848faSopenharmony_ci * 0: Success 1390f9f848faSopenharmony_ci * Else: Failure 1391f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1392f9f848faSopenharmony_ciusb_error_t 1393f9f848faSopenharmony_ciusbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1394f9f848faSopenharmony_ci uint8_t iface_index, uint8_t alt_no) 1395f9f848faSopenharmony_ci{ 1396f9f848faSopenharmony_ci struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1397f9f848faSopenharmony_ci struct usb_device_request req; 1398f9f848faSopenharmony_ci usb_error_t err; 1399f9f848faSopenharmony_ci 1400f9f848faSopenharmony_ci if ((iface == NULL) || (iface->idesc == NULL)) 1401f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1402f9f848faSopenharmony_ci 1403f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_INTERFACE; 1404f9f848faSopenharmony_ci req.bRequest = UR_SET_INTERFACE; 1405f9f848faSopenharmony_ci req.wValue[0] = alt_no; 1406f9f848faSopenharmony_ci req.wValue[1] = 0; 1407f9f848faSopenharmony_ci req.wIndex[0] = iface->idesc->bInterfaceNumber; 1408f9f848faSopenharmony_ci req.wIndex[1] = 0; 1409f9f848faSopenharmony_ci USETW(req.wLength, 0); 1410f9f848faSopenharmony_ci err = usbd_do_request(udev, mtx, &req, 0); 1411f9f848faSopenharmony_ci if (err == USB_ERR_STALLED && iface->num_altsetting == 1) { 1412f9f848faSopenharmony_ci /* 1413f9f848faSopenharmony_ci * The USB specification chapter 9.4.10 says that USB 1414f9f848faSopenharmony_ci * devices having only one alternate setting are 1415f9f848faSopenharmony_ci * allowed to STALL this request. Ignore this failure. 1416f9f848faSopenharmony_ci */ 1417f9f848faSopenharmony_ci err = 0; 1418f9f848faSopenharmony_ci DPRINTF("Setting default alternate number failed. (ignored)\n"); 1419f9f848faSopenharmony_ci } 1420f9f848faSopenharmony_ci return (err); 1421f9f848faSopenharmony_ci} 1422f9f848faSopenharmony_ci 1423f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1424f9f848faSopenharmony_ci * usbd_req_get_device_status 1425f9f848faSopenharmony_ci * 1426f9f848faSopenharmony_ci * Returns: 1427f9f848faSopenharmony_ci * 0: Success 1428f9f848faSopenharmony_ci * Else: Failure 1429f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1430f9f848faSopenharmony_ciusb_error_t 1431f9f848faSopenharmony_ciusbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1432f9f848faSopenharmony_ci struct usb_status *st) 1433f9f848faSopenharmony_ci{ 1434f9f848faSopenharmony_ci struct usb_device_request req; 1435f9f848faSopenharmony_ci 1436f9f848faSopenharmony_ci req.bmRequestType = UT_READ_DEVICE; 1437f9f848faSopenharmony_ci req.bRequest = UR_GET_STATUS; 1438f9f848faSopenharmony_ci USETW(req.wValue, 0); 1439f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1440f9f848faSopenharmony_ci USETW(req.wLength, sizeof(*st)); 1441f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, st)); 1442f9f848faSopenharmony_ci} 1443f9f848faSopenharmony_ci 1444f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1445f9f848faSopenharmony_ci * usbd_req_get_hub_descriptor 1446f9f848faSopenharmony_ci * 1447f9f848faSopenharmony_ci * Returns: 1448f9f848faSopenharmony_ci * 0: Success 1449f9f848faSopenharmony_ci * Else: Failure 1450f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1451f9f848faSopenharmony_ciusb_error_t 1452f9f848faSopenharmony_ciusbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1453f9f848faSopenharmony_ci struct usb_hub_descriptor *hd, uint8_t nports) 1454f9f848faSopenharmony_ci{ 1455f9f848faSopenharmony_ci struct usb_device_request req; 1456f9f848faSopenharmony_ci uint16_t len = (nports + 7 + (8 * 8)) / 8; 1457f9f848faSopenharmony_ci 1458f9f848faSopenharmony_ci req.bmRequestType = UT_READ_CLASS_DEVICE; 1459f9f848faSopenharmony_ci req.bRequest = UR_GET_DESCRIPTOR; 1460f9f848faSopenharmony_ci USETW2(req.wValue, UDESC_HUB, 0); 1461f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1462f9f848faSopenharmony_ci USETW(req.wLength, len); 1463f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, hd)); 1464f9f848faSopenharmony_ci} 1465f9f848faSopenharmony_ci 1466f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1467f9f848faSopenharmony_ci * usbd_req_get_ss_hub_descriptor 1468f9f848faSopenharmony_ci * 1469f9f848faSopenharmony_ci * Returns: 1470f9f848faSopenharmony_ci * 0: Success 1471f9f848faSopenharmony_ci * Else: Failure 1472f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1473f9f848faSopenharmony_ciusb_error_t 1474f9f848faSopenharmony_ciusbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1475f9f848faSopenharmony_ci struct usb_hub_ss_descriptor *hd, uint8_t nports) 1476f9f848faSopenharmony_ci{ 1477f9f848faSopenharmony_ci struct usb_device_request req; 1478f9f848faSopenharmony_ci uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8); 1479f9f848faSopenharmony_ci 1480f9f848faSopenharmony_ci req.bmRequestType = UT_READ_CLASS_DEVICE; 1481f9f848faSopenharmony_ci req.bRequest = UR_GET_DESCRIPTOR; 1482f9f848faSopenharmony_ci USETW2(req.wValue, UDESC_SS_HUB, 0); 1483f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1484f9f848faSopenharmony_ci USETW(req.wLength, len); 1485f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, hd)); 1486f9f848faSopenharmony_ci} 1487f9f848faSopenharmony_ci 1488f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1489f9f848faSopenharmony_ci * usbd_req_get_hub_status 1490f9f848faSopenharmony_ci * 1491f9f848faSopenharmony_ci * Returns: 1492f9f848faSopenharmony_ci * 0: Success 1493f9f848faSopenharmony_ci * Else: Failure 1494f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1495f9f848faSopenharmony_ciusb_error_t 1496f9f848faSopenharmony_ciusbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1497f9f848faSopenharmony_ci struct usb_hub_status *st) 1498f9f848faSopenharmony_ci{ 1499f9f848faSopenharmony_ci struct usb_device_request req; 1500f9f848faSopenharmony_ci 1501f9f848faSopenharmony_ci req.bmRequestType = UT_READ_CLASS_DEVICE; 1502f9f848faSopenharmony_ci req.bRequest = UR_GET_STATUS; 1503f9f848faSopenharmony_ci USETW(req.wValue, 0); 1504f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1505f9f848faSopenharmony_ci USETW(req.wLength, sizeof(struct usb_hub_status)); 1506f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, st)); 1507f9f848faSopenharmony_ci} 1508f9f848faSopenharmony_ci 1509f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1510f9f848faSopenharmony_ci * usbd_req_set_address 1511f9f848faSopenharmony_ci * 1512f9f848faSopenharmony_ci * This function is used to set the address for an USB device. After 1513f9f848faSopenharmony_ci * port reset the USB device will respond at address zero. 1514f9f848faSopenharmony_ci * 1515f9f848faSopenharmony_ci * Returns: 1516f9f848faSopenharmony_ci * 0: Success 1517f9f848faSopenharmony_ci * Else: Failure 1518f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1519f9f848faSopenharmony_ciusb_error_t 1520f9f848faSopenharmony_ciusbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1521f9f848faSopenharmony_ci{ 1522f9f848faSopenharmony_ci struct usb_device_request req; 1523f9f848faSopenharmony_ci usb_error_t err; 1524f9f848faSopenharmony_ci 1525f9f848faSopenharmony_ci DPRINTF("setting device address=%d\n", addr); 1526f9f848faSopenharmony_ci 1527f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_DEVICE; 1528f9f848faSopenharmony_ci req.bRequest = UR_SET_ADDRESS; 1529f9f848faSopenharmony_ci USETW(req.wValue, addr); 1530f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1531f9f848faSopenharmony_ci USETW(req.wLength, 0); 1532f9f848faSopenharmony_ci 1533f9f848faSopenharmony_ci err = USB_ERR_INVAL; 1534f9f848faSopenharmony_ci 1535f9f848faSopenharmony_ci /* check if USB controller handles set address */ 1536f9f848faSopenharmony_ci if (udev->bus->methods->set_address != NULL) 1537f9f848faSopenharmony_ci err = (udev->bus->methods->set_address) (udev, mtx, addr); 1538f9f848faSopenharmony_ci 1539f9f848faSopenharmony_ci if (err != USB_ERR_INVAL) 1540f9f848faSopenharmony_ci goto done; 1541f9f848faSopenharmony_ci 1542f9f848faSopenharmony_ci /* Setting the address should not take more than 1 second ! */ 1543f9f848faSopenharmony_ci err = usbd_do_request_flags(udev, mtx, &req, NULL, 1544f9f848faSopenharmony_ci USB_DELAY_STATUS_STAGE, NULL, 1000); 1545f9f848faSopenharmony_ci 1546f9f848faSopenharmony_cidone: 1547f9f848faSopenharmony_ci /* allow device time to set new address */ 1548f9f848faSopenharmony_ci usb_pause_mtx(mtx, 1549f9f848faSopenharmony_ci USB_MS_TO_TICKS(usb_set_address_settle)); 1550f9f848faSopenharmony_ci 1551f9f848faSopenharmony_ci return (err); 1552f9f848faSopenharmony_ci} 1553f9f848faSopenharmony_ci 1554f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1555f9f848faSopenharmony_ci * usbd_req_get_port_status 1556f9f848faSopenharmony_ci * 1557f9f848faSopenharmony_ci * Returns: 1558f9f848faSopenharmony_ci * 0: Success 1559f9f848faSopenharmony_ci * Else: Failure 1560f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1561f9f848faSopenharmony_ciusb_error_t 1562f9f848faSopenharmony_ciusbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1563f9f848faSopenharmony_ci struct usb_port_status *ps, uint8_t port) 1564f9f848faSopenharmony_ci{ 1565f9f848faSopenharmony_ci struct usb_device_request req; 1566f9f848faSopenharmony_ci 1567f9f848faSopenharmony_ci req.bmRequestType = UT_READ_CLASS_OTHER; 1568f9f848faSopenharmony_ci req.bRequest = UR_GET_STATUS; 1569f9f848faSopenharmony_ci USETW(req.wValue, 0); 1570f9f848faSopenharmony_ci req.wIndex[0] = port; 1571f9f848faSopenharmony_ci req.wIndex[1] = 0; 1572f9f848faSopenharmony_ci USETW(req.wLength, sizeof *ps); 1573f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, ps)); 1574f9f848faSopenharmony_ci} 1575f9f848faSopenharmony_ci 1576f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1577f9f848faSopenharmony_ci * usbd_req_clear_hub_feature 1578f9f848faSopenharmony_ci * 1579f9f848faSopenharmony_ci * Returns: 1580f9f848faSopenharmony_ci * 0: Success 1581f9f848faSopenharmony_ci * Else: Failure 1582f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1583f9f848faSopenharmony_ciusb_error_t 1584f9f848faSopenharmony_ciusbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1585f9f848faSopenharmony_ci uint16_t sel) 1586f9f848faSopenharmony_ci{ 1587f9f848faSopenharmony_ci struct usb_device_request req; 1588f9f848faSopenharmony_ci 1589f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1590f9f848faSopenharmony_ci req.bRequest = UR_CLEAR_FEATURE; 1591f9f848faSopenharmony_ci USETW(req.wValue, sel); 1592f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1593f9f848faSopenharmony_ci USETW(req.wLength, 0); 1594f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1595f9f848faSopenharmony_ci} 1596f9f848faSopenharmony_ci 1597f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1598f9f848faSopenharmony_ci * usbd_req_set_hub_feature 1599f9f848faSopenharmony_ci * 1600f9f848faSopenharmony_ci * Returns: 1601f9f848faSopenharmony_ci * 0: Success 1602f9f848faSopenharmony_ci * Else: Failure 1603f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1604f9f848faSopenharmony_ciusb_error_t 1605f9f848faSopenharmony_ciusbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1606f9f848faSopenharmony_ci uint16_t sel) 1607f9f848faSopenharmony_ci{ 1608f9f848faSopenharmony_ci struct usb_device_request req; 1609f9f848faSopenharmony_ci 1610f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1611f9f848faSopenharmony_ci req.bRequest = UR_SET_FEATURE; 1612f9f848faSopenharmony_ci USETW(req.wValue, sel); 1613f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1614f9f848faSopenharmony_ci USETW(req.wLength, 0); 1615f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1616f9f848faSopenharmony_ci} 1617f9f848faSopenharmony_ci 1618f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1619f9f848faSopenharmony_ci * usbd_req_set_hub_u1_timeout 1620f9f848faSopenharmony_ci * 1621f9f848faSopenharmony_ci * Returns: 1622f9f848faSopenharmony_ci * 0: Success 1623f9f848faSopenharmony_ci * Else: Failure 1624f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1625f9f848faSopenharmony_ciusb_error_t 1626f9f848faSopenharmony_ciusbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx, 1627f9f848faSopenharmony_ci uint8_t port, uint8_t timeout) 1628f9f848faSopenharmony_ci{ 1629f9f848faSopenharmony_ci struct usb_device_request req; 1630f9f848faSopenharmony_ci 1631f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 1632f9f848faSopenharmony_ci req.bRequest = UR_SET_FEATURE; 1633f9f848faSopenharmony_ci USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 1634f9f848faSopenharmony_ci req.wIndex[0] = port; 1635f9f848faSopenharmony_ci req.wIndex[1] = timeout; 1636f9f848faSopenharmony_ci USETW(req.wLength, 0); 1637f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1638f9f848faSopenharmony_ci} 1639f9f848faSopenharmony_ci 1640f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1641f9f848faSopenharmony_ci * usbd_req_set_hub_u2_timeout 1642f9f848faSopenharmony_ci * 1643f9f848faSopenharmony_ci * Returns: 1644f9f848faSopenharmony_ci * 0: Success 1645f9f848faSopenharmony_ci * Else: Failure 1646f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1647f9f848faSopenharmony_ciusb_error_t 1648f9f848faSopenharmony_ciusbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx, 1649f9f848faSopenharmony_ci uint8_t port, uint8_t timeout) 1650f9f848faSopenharmony_ci{ 1651f9f848faSopenharmony_ci struct usb_device_request req; 1652f9f848faSopenharmony_ci 1653f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 1654f9f848faSopenharmony_ci req.bRequest = UR_SET_FEATURE; 1655f9f848faSopenharmony_ci USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 1656f9f848faSopenharmony_ci req.wIndex[0] = port; 1657f9f848faSopenharmony_ci req.wIndex[1] = timeout; 1658f9f848faSopenharmony_ci USETW(req.wLength, 0); 1659f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1660f9f848faSopenharmony_ci} 1661f9f848faSopenharmony_ci 1662f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1663f9f848faSopenharmony_ci * usbd_req_set_hub_depth 1664f9f848faSopenharmony_ci * 1665f9f848faSopenharmony_ci * Returns: 1666f9f848faSopenharmony_ci * 0: Success 1667f9f848faSopenharmony_ci * Else: Failure 1668f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1669f9f848faSopenharmony_ciusb_error_t 1670f9f848faSopenharmony_ciusbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx, 1671f9f848faSopenharmony_ci uint16_t depth) 1672f9f848faSopenharmony_ci{ 1673f9f848faSopenharmony_ci struct usb_device_request req; 1674f9f848faSopenharmony_ci 1675f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1676f9f848faSopenharmony_ci req.bRequest = UR_SET_HUB_DEPTH; 1677f9f848faSopenharmony_ci USETW(req.wValue, depth); 1678f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1679f9f848faSopenharmony_ci USETW(req.wLength, 0); 1680f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1681f9f848faSopenharmony_ci} 1682f9f848faSopenharmony_ci 1683f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1684f9f848faSopenharmony_ci * usbd_req_clear_port_feature 1685f9f848faSopenharmony_ci * 1686f9f848faSopenharmony_ci * Returns: 1687f9f848faSopenharmony_ci * 0: Success 1688f9f848faSopenharmony_ci * Else: Failure 1689f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1690f9f848faSopenharmony_ciusb_error_t 1691f9f848faSopenharmony_ciusbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1692f9f848faSopenharmony_ci uint8_t port, uint16_t sel) 1693f9f848faSopenharmony_ci{ 1694f9f848faSopenharmony_ci struct usb_device_request req; 1695f9f848faSopenharmony_ci 1696f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 1697f9f848faSopenharmony_ci req.bRequest = UR_CLEAR_FEATURE; 1698f9f848faSopenharmony_ci USETW(req.wValue, sel); 1699f9f848faSopenharmony_ci req.wIndex[0] = port; 1700f9f848faSopenharmony_ci req.wIndex[1] = 0; 1701f9f848faSopenharmony_ci USETW(req.wLength, 0); 1702f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1703f9f848faSopenharmony_ci} 1704f9f848faSopenharmony_ci 1705f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1706f9f848faSopenharmony_ci * usbd_req_set_port_feature 1707f9f848faSopenharmony_ci * 1708f9f848faSopenharmony_ci * Returns: 1709f9f848faSopenharmony_ci * 0: Success 1710f9f848faSopenharmony_ci * Else: Failure 1711f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1712f9f848faSopenharmony_ciusb_error_t 1713f9f848faSopenharmony_ciusbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1714f9f848faSopenharmony_ci uint8_t port, uint16_t sel) 1715f9f848faSopenharmony_ci{ 1716f9f848faSopenharmony_ci struct usb_device_request req; 1717f9f848faSopenharmony_ci 1718f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 1719f9f848faSopenharmony_ci req.bRequest = UR_SET_FEATURE; 1720f9f848faSopenharmony_ci USETW(req.wValue, sel); 1721f9f848faSopenharmony_ci req.wIndex[0] = port; 1722f9f848faSopenharmony_ci req.wIndex[1] = 0; 1723f9f848faSopenharmony_ci USETW(req.wLength, 0); 1724f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1725f9f848faSopenharmony_ci} 1726f9f848faSopenharmony_ci 1727f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1728f9f848faSopenharmony_ci * usbd_req_set_protocol 1729f9f848faSopenharmony_ci * 1730f9f848faSopenharmony_ci * Returns: 1731f9f848faSopenharmony_ci * 0: Success 1732f9f848faSopenharmony_ci * Else: Failure 1733f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1734f9f848faSopenharmony_ciusb_error_t 1735f9f848faSopenharmony_ciusbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1736f9f848faSopenharmony_ci uint8_t iface_index, uint16_t report) 1737f9f848faSopenharmony_ci{ 1738f9f848faSopenharmony_ci struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1739f9f848faSopenharmony_ci struct usb_device_request req; 1740f9f848faSopenharmony_ci 1741f9f848faSopenharmony_ci if ((iface == NULL) || (iface->idesc == NULL)) { 1742f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1743f9f848faSopenharmony_ci } 1744f9f848faSopenharmony_ci DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1745f9f848faSopenharmony_ci iface, report, iface->idesc->bInterfaceNumber); 1746f9f848faSopenharmony_ci 1747f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1748f9f848faSopenharmony_ci req.bRequest = UR_SET_PROTOCOL; 1749f9f848faSopenharmony_ci USETW(req.wValue, report); 1750f9f848faSopenharmony_ci req.wIndex[0] = iface->idesc->bInterfaceNumber; 1751f9f848faSopenharmony_ci req.wIndex[1] = 0; 1752f9f848faSopenharmony_ci USETW(req.wLength, 0); 1753f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1754f9f848faSopenharmony_ci} 1755f9f848faSopenharmony_ci 1756f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1757f9f848faSopenharmony_ci * usbd_req_set_report 1758f9f848faSopenharmony_ci * 1759f9f848faSopenharmony_ci * Returns: 1760f9f848faSopenharmony_ci * 0: Success 1761f9f848faSopenharmony_ci * Else: Failure 1762f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1763f9f848faSopenharmony_ciusb_error_t 1764f9f848faSopenharmony_ciusbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1765f9f848faSopenharmony_ci uint8_t iface_index, uint8_t type, uint8_t id) 1766f9f848faSopenharmony_ci{ 1767f9f848faSopenharmony_ci struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1768f9f848faSopenharmony_ci struct usb_device_request req; 1769f9f848faSopenharmony_ci 1770f9f848faSopenharmony_ci if ((iface == NULL) || (iface->idesc == NULL)) { 1771f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1772f9f848faSopenharmony_ci } 1773f9f848faSopenharmony_ci DPRINTFN(5, "len=%d\n", len); 1774f9f848faSopenharmony_ci 1775f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1776f9f848faSopenharmony_ci req.bRequest = UR_SET_REPORT; 1777f9f848faSopenharmony_ci USETW2(req.wValue, type, id); 1778f9f848faSopenharmony_ci req.wIndex[0] = iface->idesc->bInterfaceNumber; 1779f9f848faSopenharmony_ci req.wIndex[1] = 0; 1780f9f848faSopenharmony_ci USETW(req.wLength, len); 1781f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, data)); 1782f9f848faSopenharmony_ci} 1783f9f848faSopenharmony_ci 1784f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1785f9f848faSopenharmony_ci * usbd_req_get_report 1786f9f848faSopenharmony_ci * 1787f9f848faSopenharmony_ci * Returns: 1788f9f848faSopenharmony_ci * 0: Success 1789f9f848faSopenharmony_ci * Else: Failure 1790f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1791f9f848faSopenharmony_ciusb_error_t 1792f9f848faSopenharmony_ciusbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1793f9f848faSopenharmony_ci uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1794f9f848faSopenharmony_ci{ 1795f9f848faSopenharmony_ci struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1796f9f848faSopenharmony_ci struct usb_device_request req; 1797f9f848faSopenharmony_ci 1798f9f848faSopenharmony_ci if ((iface == NULL) || (iface->idesc == NULL)) { 1799f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1800f9f848faSopenharmony_ci } 1801f9f848faSopenharmony_ci DPRINTFN(5, "len=%d\n", len); 1802f9f848faSopenharmony_ci 1803f9f848faSopenharmony_ci req.bmRequestType = UT_READ_CLASS_INTERFACE; 1804f9f848faSopenharmony_ci req.bRequest = UR_GET_REPORT; 1805f9f848faSopenharmony_ci USETW2(req.wValue, type, id); 1806f9f848faSopenharmony_ci req.wIndex[0] = iface->idesc->bInterfaceNumber; 1807f9f848faSopenharmony_ci req.wIndex[1] = 0; 1808f9f848faSopenharmony_ci USETW(req.wLength, len); 1809f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, data)); 1810f9f848faSopenharmony_ci} 1811f9f848faSopenharmony_ci 1812f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1813f9f848faSopenharmony_ci * usbd_req_set_idle 1814f9f848faSopenharmony_ci * 1815f9f848faSopenharmony_ci * Returns: 1816f9f848faSopenharmony_ci * 0: Success 1817f9f848faSopenharmony_ci * Else: Failure 1818f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1819f9f848faSopenharmony_ciusb_error_t 1820f9f848faSopenharmony_ciusbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1821f9f848faSopenharmony_ci uint8_t iface_index, uint8_t duration, uint8_t id) 1822f9f848faSopenharmony_ci{ 1823f9f848faSopenharmony_ci struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1824f9f848faSopenharmony_ci struct usb_device_request req; 1825f9f848faSopenharmony_ci 1826f9f848faSopenharmony_ci if ((iface == NULL) || (iface->idesc == NULL)) { 1827f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1828f9f848faSopenharmony_ci } 1829f9f848faSopenharmony_ci DPRINTFN(5, "%d %d\n", duration, id); 1830f9f848faSopenharmony_ci 1831f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1832f9f848faSopenharmony_ci req.bRequest = UR_SET_IDLE; 1833f9f848faSopenharmony_ci USETW2(req.wValue, duration, id); 1834f9f848faSopenharmony_ci req.wIndex[0] = iface->idesc->bInterfaceNumber; 1835f9f848faSopenharmony_ci req.wIndex[1] = 0; 1836f9f848faSopenharmony_ci USETW(req.wLength, 0); 1837f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1838f9f848faSopenharmony_ci} 1839f9f848faSopenharmony_ci 1840f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1841f9f848faSopenharmony_ci * usbd_req_get_report_descriptor 1842f9f848faSopenharmony_ci * 1843f9f848faSopenharmony_ci * Returns: 1844f9f848faSopenharmony_ci * 0: Success 1845f9f848faSopenharmony_ci * Else: Failure 1846f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1847f9f848faSopenharmony_ciusb_error_t 1848f9f848faSopenharmony_ciusbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1849f9f848faSopenharmony_ci void *d, uint16_t size, uint8_t iface_index) 1850f9f848faSopenharmony_ci{ 1851f9f848faSopenharmony_ci struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1852f9f848faSopenharmony_ci struct usb_device_request req; 1853f9f848faSopenharmony_ci 1854f9f848faSopenharmony_ci if ((iface == NULL) || (iface->idesc == NULL)) { 1855f9f848faSopenharmony_ci return (USB_ERR_INVAL); 1856f9f848faSopenharmony_ci } 1857f9f848faSopenharmony_ci req.bmRequestType = UT_READ_INTERFACE; 1858f9f848faSopenharmony_ci req.bRequest = UR_GET_DESCRIPTOR; 1859f9f848faSopenharmony_ci USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1860f9f848faSopenharmony_ci req.wIndex[0] = iface->idesc->bInterfaceNumber; 1861f9f848faSopenharmony_ci req.wIndex[1] = 0; 1862f9f848faSopenharmony_ci USETW(req.wLength, size); 1863f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, d)); 1864f9f848faSopenharmony_ci} 1865f9f848faSopenharmony_ci 1866f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1867f9f848faSopenharmony_ci * usbd_req_set_config 1868f9f848faSopenharmony_ci * 1869f9f848faSopenharmony_ci * This function is used to select the current configuration number in 1870f9f848faSopenharmony_ci * both USB device side mode and USB host side mode. When setting the 1871f9f848faSopenharmony_ci * configuration the function of the interfaces can change. 1872f9f848faSopenharmony_ci * 1873f9f848faSopenharmony_ci * Returns: 1874f9f848faSopenharmony_ci * 0: Success 1875f9f848faSopenharmony_ci * Else: Failure 1876f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1877f9f848faSopenharmony_ciusb_error_t 1878f9f848faSopenharmony_ciusbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1879f9f848faSopenharmony_ci{ 1880f9f848faSopenharmony_ci struct usb_device_request req; 1881f9f848faSopenharmony_ci 1882f9f848faSopenharmony_ci DPRINTF("setting config %d\n", conf); 1883f9f848faSopenharmony_ci 1884f9f848faSopenharmony_ci /* do "set configuration" request */ 1885f9f848faSopenharmony_ci 1886f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_DEVICE; 1887f9f848faSopenharmony_ci req.bRequest = UR_SET_CONFIG; 1888f9f848faSopenharmony_ci req.wValue[0] = conf; 1889f9f848faSopenharmony_ci req.wValue[1] = 0; 1890f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1891f9f848faSopenharmony_ci USETW(req.wLength, 0); 1892f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 1893f9f848faSopenharmony_ci} 1894f9f848faSopenharmony_ci 1895f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1896f9f848faSopenharmony_ci * usbd_req_get_config 1897f9f848faSopenharmony_ci * 1898f9f848faSopenharmony_ci * Returns: 1899f9f848faSopenharmony_ci * 0: Success 1900f9f848faSopenharmony_ci * Else: Failure 1901f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1902f9f848faSopenharmony_ciusb_error_t 1903f9f848faSopenharmony_ciusbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1904f9f848faSopenharmony_ci{ 1905f9f848faSopenharmony_ci struct usb_device_request req; 1906f9f848faSopenharmony_ci 1907f9f848faSopenharmony_ci req.bmRequestType = UT_READ_DEVICE; 1908f9f848faSopenharmony_ci req.bRequest = UR_GET_CONFIG; 1909f9f848faSopenharmony_ci USETW(req.wValue, 0); 1910f9f848faSopenharmony_ci USETW(req.wIndex, 0); 1911f9f848faSopenharmony_ci USETW(req.wLength, 1); 1912f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, pconf)); 1913f9f848faSopenharmony_ci} 1914f9f848faSopenharmony_ci 1915f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1916f9f848faSopenharmony_ci * usbd_setup_device_desc 1917f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1918f9f848faSopenharmony_ciusb_error_t 1919f9f848faSopenharmony_ciusbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) 1920f9f848faSopenharmony_ci{ 1921f9f848faSopenharmony_ci usb_error_t err; 1922f9f848faSopenharmony_ci 1923f9f848faSopenharmony_ci /* 1924f9f848faSopenharmony_ci * Get the first 8 bytes of the device descriptor ! 1925f9f848faSopenharmony_ci * 1926f9f848faSopenharmony_ci * NOTE: "usbd_do_request()" will check the device descriptor 1927f9f848faSopenharmony_ci * next time we do a request to see if the maximum packet size 1928f9f848faSopenharmony_ci * changed! The 8 first bytes of the device descriptor 1929f9f848faSopenharmony_ci * contains the maximum packet size to use on control endpoint 1930f9f848faSopenharmony_ci * 0. If this value is different from "USB_MAX_IPACKET" a new 1931f9f848faSopenharmony_ci * USB control request will be setup! 1932f9f848faSopenharmony_ci */ 1933f9f848faSopenharmony_ci switch (udev->speed) { 1934f9f848faSopenharmony_ci case USB_SPEED_FULL: 1935f9f848faSopenharmony_ci if (usb_full_ddesc != 0) { 1936f9f848faSopenharmony_ci /* get full device descriptor */ 1937f9f848faSopenharmony_ci err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1938f9f848faSopenharmony_ci if (err == 0) 1939f9f848faSopenharmony_ci break; 1940f9f848faSopenharmony_ci } 1941f9f848faSopenharmony_ci 1942f9f848faSopenharmony_ci /* get partial device descriptor, some devices crash on this */ 1943f9f848faSopenharmony_ci err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1944f9f848faSopenharmony_ci USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1945f9f848faSopenharmony_ci if (err != 0) { 1946f9f848faSopenharmony_ci DPRINTF("Trying fallback for getting the USB device descriptor\n"); 1947f9f848faSopenharmony_ci /* try 8 bytes bMaxPacketSize */ 1948f9f848faSopenharmony_ci udev->ddesc.bMaxPacketSize = 8; 1949f9f848faSopenharmony_ci /* get full device descriptor */ 1950f9f848faSopenharmony_ci err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1951f9f848faSopenharmony_ci if (err == 0) 1952f9f848faSopenharmony_ci break; 1953f9f848faSopenharmony_ci /* try 16 bytes bMaxPacketSize */ 1954f9f848faSopenharmony_ci udev->ddesc.bMaxPacketSize = 16; 1955f9f848faSopenharmony_ci /* get full device descriptor */ 1956f9f848faSopenharmony_ci err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1957f9f848faSopenharmony_ci if (err == 0) 1958f9f848faSopenharmony_ci break; 1959f9f848faSopenharmony_ci /* try 32/64 bytes bMaxPacketSize */ 1960f9f848faSopenharmony_ci udev->ddesc.bMaxPacketSize = 32; 1961f9f848faSopenharmony_ci } 1962f9f848faSopenharmony_ci 1963f9f848faSopenharmony_ci /* get the full device descriptor */ 1964f9f848faSopenharmony_ci err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1965f9f848faSopenharmony_ci break; 1966f9f848faSopenharmony_ci 1967f9f848faSopenharmony_ci default: 1968f9f848faSopenharmony_ci DPRINTF("Minimum bMaxPacketSize is large enough " 1969f9f848faSopenharmony_ci "to hold the complete device descriptor or " 1970f9f848faSopenharmony_ci "only one bMaxPacketSize choice\n"); 1971f9f848faSopenharmony_ci 1972f9f848faSopenharmony_ci /* get the full device descriptor */ 1973f9f848faSopenharmony_ci err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1974f9f848faSopenharmony_ci 1975f9f848faSopenharmony_ci /* try one more time, if error */ 1976f9f848faSopenharmony_ci if (err != 0) 1977f9f848faSopenharmony_ci err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1978f9f848faSopenharmony_ci break; 1979f9f848faSopenharmony_ci } 1980f9f848faSopenharmony_ci 1981f9f848faSopenharmony_ci if (err != 0) { 1982f9f848faSopenharmony_ci DPRINTFN(0, "getting device descriptor " 1983f9f848faSopenharmony_ci "at addr %d failed, %s\n", udev->address, 1984f9f848faSopenharmony_ci usbd_errstr(err)); 1985f9f848faSopenharmony_ci return (err); 1986f9f848faSopenharmony_ci } 1987f9f848faSopenharmony_ci 1988f9f848faSopenharmony_ci DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " 1989f9f848faSopenharmony_ci "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", 1990f9f848faSopenharmony_ci udev->address, UGETW(udev->ddesc.bcdUSB), 1991f9f848faSopenharmony_ci udev->ddesc.bDeviceClass, 1992f9f848faSopenharmony_ci udev->ddesc.bDeviceSubClass, 1993f9f848faSopenharmony_ci udev->ddesc.bDeviceProtocol, 1994f9f848faSopenharmony_ci udev->ddesc.bMaxPacketSize, 1995f9f848faSopenharmony_ci udev->ddesc.bLength, 1996f9f848faSopenharmony_ci udev->speed); 1997f9f848faSopenharmony_ci 1998f9f848faSopenharmony_ci return (err); 1999f9f848faSopenharmony_ci} 2000f9f848faSopenharmony_ci 2001f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2002f9f848faSopenharmony_ci * usbd_req_re_enumerate 2003f9f848faSopenharmony_ci * 2004f9f848faSopenharmony_ci * NOTE: After this function returns the hardware is in the 2005f9f848faSopenharmony_ci * unconfigured state! The application is responsible for setting a 2006f9f848faSopenharmony_ci * new configuration. 2007f9f848faSopenharmony_ci * 2008f9f848faSopenharmony_ci * Returns: 2009f9f848faSopenharmony_ci * 0: Success 2010f9f848faSopenharmony_ci * Else: Failure 2011f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2012f9f848faSopenharmony_ciusb_error_t 2013f9f848faSopenharmony_ciusbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 2014f9f848faSopenharmony_ci{ 2015f9f848faSopenharmony_ci struct usb_device *parent_hub; 2016f9f848faSopenharmony_ci usb_error_t err; 2017f9f848faSopenharmony_ci uint8_t old_addr; 2018f9f848faSopenharmony_ci uint8_t do_retry = 1; 2019f9f848faSopenharmony_ci 2020f9f848faSopenharmony_ci if (udev->flags.usb_mode != USB_MODE_HOST) { 2021f9f848faSopenharmony_ci return (USB_ERR_INVAL); 2022f9f848faSopenharmony_ci } 2023f9f848faSopenharmony_ci DPRINTFN(5, "try to enumerate device\n"); 2024f9f848faSopenharmony_ci old_addr = udev->address; 2025f9f848faSopenharmony_ci parent_hub = udev->parent_hub; 2026f9f848faSopenharmony_ci if (parent_hub == NULL) { 2027f9f848faSopenharmony_ci return (USB_ERR_INVAL); 2028f9f848faSopenharmony_ci } 2029f9f848faSopenharmony_ciretry: 2030f9f848faSopenharmony_ci#if USB_HAVE_TT_SUPPORT 2031f9f848faSopenharmony_ci /* 2032f9f848faSopenharmony_ci * Try to reset the High Speed parent HUB of a LOW- or FULL- 2033f9f848faSopenharmony_ci * speed device, if any. 2034f9f848faSopenharmony_ci */ 2035f9f848faSopenharmony_ci if ((udev->parent_hs_hub != NULL) && 2036f9f848faSopenharmony_ci (udev->speed != USB_SPEED_HIGH)) { 2037f9f848faSopenharmony_ci DPRINTF("Trying to reset parent High Speed TT.\n"); 2038f9f848faSopenharmony_ci if ((udev->parent_hs_hub == parent_hub) && 2039f9f848faSopenharmony_ci ((uhub_count_active_host_ports(parent_hub, USB_SPEED_LOW) + 2040f9f848faSopenharmony_ci uhub_count_active_host_ports(parent_hub, USB_SPEED_FULL)) == 1)) { 2041f9f848faSopenharmony_ci /* we can reset the whole TT */ 2042f9f848faSopenharmony_ci err = usbd_req_reset_tt(parent_hub, NULL, 2043f9f848faSopenharmony_ci udev->hs_port_no); 2044f9f848faSopenharmony_ci } else { 2045f9f848faSopenharmony_ci /* only reset a particular device and endpoint */ 2046f9f848faSopenharmony_ci err = usbd_req_clear_tt_buffer(udev->parent_hs_hub, NULL, 2047f9f848faSopenharmony_ci udev->hs_port_no, old_addr, UE_CONTROL, 0); 2048f9f848faSopenharmony_ci } 2049f9f848faSopenharmony_ci if (err) { 2050f9f848faSopenharmony_ci DPRINTF("Resetting parent High " 2051f9f848faSopenharmony_ci "Speed TT failed (%s).\n", 2052f9f848faSopenharmony_ci usbd_errstr(err)); 2053f9f848faSopenharmony_ci } 2054f9f848faSopenharmony_ci } 2055f9f848faSopenharmony_ci#endif 2056f9f848faSopenharmony_ci /* Try to warm reset first */ 2057f9f848faSopenharmony_ci if (parent_hub->speed == USB_SPEED_SUPER) 2058f9f848faSopenharmony_ci (void)usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no); 2059f9f848faSopenharmony_ci 2060f9f848faSopenharmony_ci /* Try to reset the parent HUB port. */ 2061f9f848faSopenharmony_ci err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 2062f9f848faSopenharmony_ci if (err) { 2063f9f848faSopenharmony_ci DPRINTFN(0, "addr=%d, port reset failed, %s\n", 2064f9f848faSopenharmony_ci old_addr, usbd_errstr(err)); 2065f9f848faSopenharmony_ci goto done; 2066f9f848faSopenharmony_ci } 2067f9f848faSopenharmony_ci 2068f9f848faSopenharmony_ci /* 2069f9f848faSopenharmony_ci * After that the port has been reset our device should be at 2070f9f848faSopenharmony_ci * address zero: 2071f9f848faSopenharmony_ci */ 2072f9f848faSopenharmony_ci udev->address = USB_START_ADDR; 2073f9f848faSopenharmony_ci 2074f9f848faSopenharmony_ci /* reset "bMaxPacketSize" */ 2075f9f848faSopenharmony_ci udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 2076f9f848faSopenharmony_ci 2077f9f848faSopenharmony_ci /* reset USB state */ 2078f9f848faSopenharmony_ci usb_set_device_state(udev, USB_STATE_POWERED); 2079f9f848faSopenharmony_ci 2080f9f848faSopenharmony_ci /* 2081f9f848faSopenharmony_ci * Restore device address: 2082f9f848faSopenharmony_ci */ 2083f9f848faSopenharmony_ci err = usbd_req_set_address(udev, mtx, old_addr); 2084f9f848faSopenharmony_ci if (err) { 2085f9f848faSopenharmony_ci /* XXX ignore any errors! */ 2086f9f848faSopenharmony_ci DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 2087f9f848faSopenharmony_ci old_addr, usbd_errstr(err)); 2088f9f848faSopenharmony_ci } 2089f9f848faSopenharmony_ci /* 2090f9f848faSopenharmony_ci * Restore device address, if the controller driver did not 2091f9f848faSopenharmony_ci * set a new one: 2092f9f848faSopenharmony_ci */ 2093f9f848faSopenharmony_ci if (udev->address == USB_START_ADDR) 2094f9f848faSopenharmony_ci udev->address = old_addr; 2095f9f848faSopenharmony_ci 2096f9f848faSopenharmony_ci /* setup the device descriptor and the initial "wMaxPacketSize" */ 2097f9f848faSopenharmony_ci err = usbd_setup_device_desc(udev, mtx); 2098f9f848faSopenharmony_ci 2099f9f848faSopenharmony_cidone: 2100f9f848faSopenharmony_ci if (err && do_retry) { 2101f9f848faSopenharmony_ci /* give the USB firmware some time to load */ 2102f9f848faSopenharmony_ci usb_pause_mtx(mtx, hz / 2); 2103f9f848faSopenharmony_ci /* no more retries after this retry */ 2104f9f848faSopenharmony_ci do_retry = 0; 2105f9f848faSopenharmony_ci /* try again */ 2106f9f848faSopenharmony_ci goto retry; 2107f9f848faSopenharmony_ci } 2108f9f848faSopenharmony_ci /* restore address */ 2109f9f848faSopenharmony_ci if (udev->address == USB_START_ADDR) 2110f9f848faSopenharmony_ci udev->address = old_addr; 2111f9f848faSopenharmony_ci /* update state, if successful */ 2112f9f848faSopenharmony_ci if (err == 0) 2113f9f848faSopenharmony_ci usb_set_device_state(udev, USB_STATE_ADDRESSED); 2114f9f848faSopenharmony_ci return (err); 2115f9f848faSopenharmony_ci} 2116f9f848faSopenharmony_ci 2117f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2118f9f848faSopenharmony_ci * usbd_req_clear_device_feature 2119f9f848faSopenharmony_ci * 2120f9f848faSopenharmony_ci * Returns: 2121f9f848faSopenharmony_ci * 0: Success 2122f9f848faSopenharmony_ci * Else: Failure 2123f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2124f9f848faSopenharmony_ciusb_error_t 2125f9f848faSopenharmony_ciusbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 2126f9f848faSopenharmony_ci uint16_t sel) 2127f9f848faSopenharmony_ci{ 2128f9f848faSopenharmony_ci struct usb_device_request req; 2129f9f848faSopenharmony_ci 2130f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_DEVICE; 2131f9f848faSopenharmony_ci req.bRequest = UR_CLEAR_FEATURE; 2132f9f848faSopenharmony_ci USETW(req.wValue, sel); 2133f9f848faSopenharmony_ci USETW(req.wIndex, 0); 2134f9f848faSopenharmony_ci USETW(req.wLength, 0); 2135f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 2136f9f848faSopenharmony_ci} 2137f9f848faSopenharmony_ci 2138f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2139f9f848faSopenharmony_ci * usbd_req_set_device_feature 2140f9f848faSopenharmony_ci * 2141f9f848faSopenharmony_ci * Returns: 2142f9f848faSopenharmony_ci * 0: Success 2143f9f848faSopenharmony_ci * Else: Failure 2144f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2145f9f848faSopenharmony_ciusb_error_t 2146f9f848faSopenharmony_ciusbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 2147f9f848faSopenharmony_ci uint16_t sel) 2148f9f848faSopenharmony_ci{ 2149f9f848faSopenharmony_ci struct usb_device_request req; 2150f9f848faSopenharmony_ci 2151f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_DEVICE; 2152f9f848faSopenharmony_ci req.bRequest = UR_SET_FEATURE; 2153f9f848faSopenharmony_ci USETW(req.wValue, sel); 2154f9f848faSopenharmony_ci USETW(req.wIndex, 0); 2155f9f848faSopenharmony_ci USETW(req.wLength, 0); 2156f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 2157f9f848faSopenharmony_ci} 2158f9f848faSopenharmony_ci 2159f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2160f9f848faSopenharmony_ci * usbd_req_reset_tt 2161f9f848faSopenharmony_ci * 2162f9f848faSopenharmony_ci * Returns: 2163f9f848faSopenharmony_ci * 0: Success 2164f9f848faSopenharmony_ci * Else: Failure 2165f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2166f9f848faSopenharmony_ciusb_error_t 2167f9f848faSopenharmony_ciusbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx, 2168f9f848faSopenharmony_ci uint8_t port) 2169f9f848faSopenharmony_ci{ 2170f9f848faSopenharmony_ci struct usb_device_request req; 2171f9f848faSopenharmony_ci 2172f9f848faSopenharmony_ci /* For single TT HUBs the port should be 1 */ 2173f9f848faSopenharmony_ci 2174f9f848faSopenharmony_ci if ((udev->ddesc.bDeviceClass == UDCLASS_HUB) && 2175f9f848faSopenharmony_ci (udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)) 2176f9f848faSopenharmony_ci port = 1; 2177f9f848faSopenharmony_ci 2178f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 2179f9f848faSopenharmony_ci req.bRequest = UR_RESET_TT; 2180f9f848faSopenharmony_ci USETW(req.wValue, 0); 2181f9f848faSopenharmony_ci req.wIndex[0] = port; 2182f9f848faSopenharmony_ci req.wIndex[1] = 0; 2183f9f848faSopenharmony_ci USETW(req.wLength, 0); 2184f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 2185f9f848faSopenharmony_ci} 2186f9f848faSopenharmony_ci 2187f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2188f9f848faSopenharmony_ci * usbd_req_clear_tt_buffer 2189f9f848faSopenharmony_ci * 2190f9f848faSopenharmony_ci * For single TT HUBs the port should be 1. 2191f9f848faSopenharmony_ci * 2192f9f848faSopenharmony_ci * Returns: 2193f9f848faSopenharmony_ci * 0: Success 2194f9f848faSopenharmony_ci * Else: Failure 2195f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2196f9f848faSopenharmony_ciusb_error_t 2197f9f848faSopenharmony_ciusbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx, 2198f9f848faSopenharmony_ci uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint) 2199f9f848faSopenharmony_ci{ 2200f9f848faSopenharmony_ci struct usb_device_request req; 2201f9f848faSopenharmony_ci uint16_t wValue; 2202f9f848faSopenharmony_ci 2203f9f848faSopenharmony_ci /* For single TT HUBs the port should be 1 */ 2204f9f848faSopenharmony_ci 2205f9f848faSopenharmony_ci if ((udev->ddesc.bDeviceClass == UDCLASS_HUB) && 2206f9f848faSopenharmony_ci (udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)) 2207f9f848faSopenharmony_ci port = 1; 2208f9f848faSopenharmony_ci 2209f9f848faSopenharmony_ci wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) | 2210f9f848faSopenharmony_ci ((endpoint & 0x80) << 8) | ((type & 3) << 12); 2211f9f848faSopenharmony_ci 2212f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 2213f9f848faSopenharmony_ci req.bRequest = UR_CLEAR_TT_BUFFER; 2214f9f848faSopenharmony_ci USETW(req.wValue, wValue); 2215f9f848faSopenharmony_ci req.wIndex[0] = port; 2216f9f848faSopenharmony_ci req.wIndex[1] = 0; 2217f9f848faSopenharmony_ci USETW(req.wLength, 0); 2218f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 2219f9f848faSopenharmony_ci} 2220f9f848faSopenharmony_ci 2221f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2222f9f848faSopenharmony_ci * usbd_req_set_port_link_state 2223f9f848faSopenharmony_ci * 2224f9f848faSopenharmony_ci * USB 3.0 specific request 2225f9f848faSopenharmony_ci * 2226f9f848faSopenharmony_ci * Returns: 2227f9f848faSopenharmony_ci * 0: Success 2228f9f848faSopenharmony_ci * Else: Failure 2229f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2230f9f848faSopenharmony_ciusb_error_t 2231f9f848faSopenharmony_ciusbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx, 2232f9f848faSopenharmony_ci uint8_t port, uint8_t link_state) 2233f9f848faSopenharmony_ci{ 2234f9f848faSopenharmony_ci struct usb_device_request req; 2235f9f848faSopenharmony_ci 2236f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 2237f9f848faSopenharmony_ci req.bRequest = UR_SET_FEATURE; 2238f9f848faSopenharmony_ci USETW(req.wValue, UHF_PORT_LINK_STATE); 2239f9f848faSopenharmony_ci req.wIndex[0] = port; 2240f9f848faSopenharmony_ci req.wIndex[1] = link_state; 2241f9f848faSopenharmony_ci USETW(req.wLength, 0); 2242f9f848faSopenharmony_ci return (usbd_do_request(udev, mtx, &req, 0)); 2243f9f848faSopenharmony_ci} 2244f9f848faSopenharmony_ci 2245f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2246f9f848faSopenharmony_ci * usbd_req_set_lpm_info 2247f9f848faSopenharmony_ci * 2248f9f848faSopenharmony_ci * USB 2.0 specific request for Link Power Management. 2249f9f848faSopenharmony_ci * 2250f9f848faSopenharmony_ci * Returns: 2251f9f848faSopenharmony_ci * 0: Success 2252f9f848faSopenharmony_ci * USB_ERR_PENDING_REQUESTS: NYET 2253f9f848faSopenharmony_ci * USB_ERR_TIMEOUT: TIMEOUT 2254f9f848faSopenharmony_ci * USB_ERR_STALL: STALL 2255f9f848faSopenharmony_ci * Else: Failure 2256f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2257f9f848faSopenharmony_ciusb_error_t 2258f9f848faSopenharmony_ciusbd_req_set_lpm_info(struct usb_device *udev, struct mtx *mtx, 2259f9f848faSopenharmony_ci uint8_t port, uint8_t besl, uint8_t addr, uint8_t rwe) 2260f9f848faSopenharmony_ci{ 2261f9f848faSopenharmony_ci struct usb_device_request req; 2262f9f848faSopenharmony_ci usb_error_t err; 2263f9f848faSopenharmony_ci uint8_t buf[1]; 2264f9f848faSopenharmony_ci 2265f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_OTHER; 2266f9f848faSopenharmony_ci req.bRequest = UR_SET_AND_TEST; 2267f9f848faSopenharmony_ci USETW(req.wValue, UHF_PORT_L1); 2268f9f848faSopenharmony_ci req.wIndex[0] = (port & 0xF) | ((besl & 0xF) << 4); 2269f9f848faSopenharmony_ci req.wIndex[1] = (addr & 0x7F) | (rwe ? 0x80 : 0x00); 2270f9f848faSopenharmony_ci USETW(req.wLength, sizeof(buf)); 2271f9f848faSopenharmony_ci 2272f9f848faSopenharmony_ci /* set default value in case of short transfer */ 2273f9f848faSopenharmony_ci buf[0] = 0x00; 2274f9f848faSopenharmony_ci 2275f9f848faSopenharmony_ci err = usbd_do_request(udev, mtx, &req, buf); 2276f9f848faSopenharmony_ci if (err) 2277f9f848faSopenharmony_ci return (err); 2278f9f848faSopenharmony_ci 2279f9f848faSopenharmony_ci switch (buf[0]) { 2280f9f848faSopenharmony_ci case 0x00: /* SUCCESS */ 2281f9f848faSopenharmony_ci break; 2282f9f848faSopenharmony_ci case 0x10: /* NYET */ 2283f9f848faSopenharmony_ci err = USB_ERR_PENDING_REQUESTS; 2284f9f848faSopenharmony_ci break; 2285f9f848faSopenharmony_ci case 0x11: /* TIMEOUT */ 2286f9f848faSopenharmony_ci err = USB_ERR_TIMEOUT; 2287f9f848faSopenharmony_ci break; 2288f9f848faSopenharmony_ci case 0x30: /* STALL */ 2289f9f848faSopenharmony_ci err = USB_ERR_STALLED; 2290f9f848faSopenharmony_ci break; 2291f9f848faSopenharmony_ci default: /* reserved */ 2292f9f848faSopenharmony_ci err = USB_ERR_IOERROR; 2293f9f848faSopenharmony_ci break; 2294f9f848faSopenharmony_ci } 2295f9f848faSopenharmony_ci return (err); 2296f9f848faSopenharmony_ci} 2297f9f848faSopenharmony_ci 2298f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 2299