1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 5f9f848faSopenharmony_ci * 6f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 7f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 8f9f848faSopenharmony_ci * are met: 9f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 10f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 11f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 12f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 13f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 14f9f848faSopenharmony_ci * 15f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25f9f848faSopenharmony_ci * SUCH DAMAGE. 26f9f848faSopenharmony_ci */ 27f9f848faSopenharmony_ci 28f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 29f9f848faSopenharmony_ci 30f9f848faSopenharmony_ci/* function prototypes */ 31f9f848faSopenharmony_ci 32f9f848faSopenharmony_cistatic uint8_t usb_handle_get_stall(struct usb_device *, uint8_t); 33f9f848faSopenharmony_cistatic usb_error_t usb_handle_remote_wakeup(struct usb_xfer *, uint8_t); 34f9f848faSopenharmony_cistatic usb_error_t usb_handle_request(struct usb_xfer *); 35f9f848faSopenharmony_cistatic usb_error_t usb_handle_set_config(struct usb_xfer *, uint8_t); 36f9f848faSopenharmony_cistatic usb_error_t usb_handle_set_stall(struct usb_xfer *, uint8_t, 37f9f848faSopenharmony_ci uint8_t); 38f9f848faSopenharmony_cistatic usb_error_t usb_handle_iface_request(struct usb_xfer *, void **, 39f9f848faSopenharmony_ci uint16_t *, struct usb_device_request, uint16_t, 40f9f848faSopenharmony_ci uint8_t); 41f9f848faSopenharmony_ci 42f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 43f9f848faSopenharmony_ci * usb_handle_request_callback 44f9f848faSopenharmony_ci * 45f9f848faSopenharmony_ci * This function is the USB callback for generic USB Device control 46f9f848faSopenharmony_ci * transfers. 47f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 48f9f848faSopenharmony_civoid 49f9f848faSopenharmony_ciusb_handle_request_callback(struct usb_xfer *xfer, usb_error_t error) 50f9f848faSopenharmony_ci{ 51f9f848faSopenharmony_ci usb_error_t err; 52f9f848faSopenharmony_ci 53f9f848faSopenharmony_ci /* check the current transfer state */ 54f9f848faSopenharmony_ci 55f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 56f9f848faSopenharmony_ci case USB_ST_SETUP: 57f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 58f9f848faSopenharmony_ci 59f9f848faSopenharmony_ci /* handle the request */ 60f9f848faSopenharmony_ci err = usb_handle_request(xfer); 61f9f848faSopenharmony_ci 62f9f848faSopenharmony_ci if (err) { 63f9f848faSopenharmony_ci if (err == USB_ERR_BAD_CONTEXT) { 64f9f848faSopenharmony_ci /* we need to re-setup the control transfer */ 65f9f848faSopenharmony_ci usb_needs_explore(xfer->xroot->bus, 0); 66f9f848faSopenharmony_ci break; 67f9f848faSopenharmony_ci } 68f9f848faSopenharmony_ci goto tr_restart; 69f9f848faSopenharmony_ci } 70f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 71f9f848faSopenharmony_ci break; 72f9f848faSopenharmony_ci 73f9f848faSopenharmony_ci default: 74f9f848faSopenharmony_ci /* check if a control transfer is active */ 75f9f848faSopenharmony_ci if (xfer->flags_int.control_rem != 0xFFFF) { 76f9f848faSopenharmony_ci /* handle the request */ 77f9f848faSopenharmony_ci (void)usb_handle_request(xfer); 78f9f848faSopenharmony_ci } 79f9f848faSopenharmony_ci if (xfer->error != USB_ERR_CANCELLED) { 80f9f848faSopenharmony_ci /* should not happen - try stalling */ 81f9f848faSopenharmony_ci goto tr_restart; 82f9f848faSopenharmony_ci } 83f9f848faSopenharmony_ci break; 84f9f848faSopenharmony_ci } 85f9f848faSopenharmony_ci return; 86f9f848faSopenharmony_ci 87f9f848faSopenharmony_citr_restart: 88f9f848faSopenharmony_ci /* 89f9f848faSopenharmony_ci * If a control transfer is active, stall it, and wait for the 90f9f848faSopenharmony_ci * next control transfer. 91f9f848faSopenharmony_ci */ 92f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(struct usb_device_request)); 93f9f848faSopenharmony_ci xfer->nframes = 1; 94f9f848faSopenharmony_ci xfer->flags.manual_status = 1; 95f9f848faSopenharmony_ci xfer->flags.force_short_xfer = 0; 96f9f848faSopenharmony_ci usbd_xfer_set_stall(xfer); /* cancel previous transfer, if any */ 97f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 98f9f848faSopenharmony_ci} 99f9f848faSopenharmony_ci 100f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 101f9f848faSopenharmony_ci * usb_handle_set_config 102f9f848faSopenharmony_ci * 103f9f848faSopenharmony_ci * Returns: 104f9f848faSopenharmony_ci * 0: Success 105f9f848faSopenharmony_ci * Else: Failure 106f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 107f9f848faSopenharmony_cistatic usb_error_t 108f9f848faSopenharmony_ciusb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no) 109f9f848faSopenharmony_ci{ 110f9f848faSopenharmony_ci struct usb_device *udev = xfer->xroot->udev; 111f9f848faSopenharmony_ci usb_error_t err = USB_ERR_NORMAL_COMPLETION; 112f9f848faSopenharmony_ci uint8_t do_unlock; 113f9f848faSopenharmony_ci 114f9f848faSopenharmony_ci /* 115f9f848faSopenharmony_ci * We need to protect against other threads doing probe and 116f9f848faSopenharmony_ci * attach: 117f9f848faSopenharmony_ci */ 118f9f848faSopenharmony_ci USB_XFER_UNLOCK(xfer); 119f9f848faSopenharmony_ci 120f9f848faSopenharmony_ci /* Prevent re-enumeration */ 121f9f848faSopenharmony_ci do_unlock = usbd_enum_lock(udev); 122f9f848faSopenharmony_ci 123f9f848faSopenharmony_ci if (conf_no == USB_UNCONFIG_NO) { 124f9f848faSopenharmony_ci conf_no = USB_UNCONFIG_INDEX; 125f9f848faSopenharmony_ci } else { 126f9f848faSopenharmony_ci /* 127f9f848faSopenharmony_ci * The relationship between config number and config index 128f9f848faSopenharmony_ci * is very simple in our case: 129f9f848faSopenharmony_ci */ 130f9f848faSopenharmony_ci conf_no--; 131f9f848faSopenharmony_ci } 132f9f848faSopenharmony_ci 133f9f848faSopenharmony_ci if (usbd_set_config_index(udev, conf_no)) { 134f9f848faSopenharmony_ci DPRINTF("set config %d failed\n", conf_no); 135f9f848faSopenharmony_ci err = USB_ERR_STALLED; 136f9f848faSopenharmony_ci goto done; 137f9f848faSopenharmony_ci } 138f9f848faSopenharmony_ci if (usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY)) { 139f9f848faSopenharmony_ci DPRINTF("probe and attach failed\n"); 140f9f848faSopenharmony_ci err = USB_ERR_STALLED; 141f9f848faSopenharmony_ci goto done; 142f9f848faSopenharmony_ci } 143f9f848faSopenharmony_cidone: 144f9f848faSopenharmony_ci if (do_unlock) 145f9f848faSopenharmony_ci usbd_enum_unlock(udev); 146f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 147f9f848faSopenharmony_ci return (err); 148f9f848faSopenharmony_ci} 149f9f848faSopenharmony_ci 150f9f848faSopenharmony_cistatic usb_error_t 151f9f848faSopenharmony_ciusb_check_alt_setting(struct usb_device *udev, 152f9f848faSopenharmony_ci struct usb_interface *iface, uint8_t alt_index) 153f9f848faSopenharmony_ci{ 154f9f848faSopenharmony_ci uint8_t do_unlock; 155f9f848faSopenharmony_ci usb_error_t err = USB_ERR_NORMAL_COMPLETION; 156f9f848faSopenharmony_ci 157f9f848faSopenharmony_ci /* Prevent re-enumeration */ 158f9f848faSopenharmony_ci do_unlock = usbd_enum_lock(udev); 159f9f848faSopenharmony_ci 160f9f848faSopenharmony_ci if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc)) 161f9f848faSopenharmony_ci err = USB_ERR_INVAL; 162f9f848faSopenharmony_ci 163f9f848faSopenharmony_ci if (do_unlock) 164f9f848faSopenharmony_ci usbd_enum_unlock(udev); 165f9f848faSopenharmony_ci 166f9f848faSopenharmony_ci return (err); 167f9f848faSopenharmony_ci} 168f9f848faSopenharmony_ci 169f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 170f9f848faSopenharmony_ci * usb_handle_iface_request 171f9f848faSopenharmony_ci * 172f9f848faSopenharmony_ci * Returns: 173f9f848faSopenharmony_ci * 0: Success 174f9f848faSopenharmony_ci * Else: Failure 175f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 176f9f848faSopenharmony_cistatic usb_error_t 177f9f848faSopenharmony_ciusb_handle_iface_request(struct usb_xfer *xfer, 178f9f848faSopenharmony_ci void **ppdata, uint16_t *plen, 179f9f848faSopenharmony_ci struct usb_device_request req, uint16_t off, uint8_t state) 180f9f848faSopenharmony_ci{ 181f9f848faSopenharmony_ci struct usb_interface *iface; 182f9f848faSopenharmony_ci struct usb_interface *iface_parent; /* parent interface */ 183f9f848faSopenharmony_ci struct usb_device *udev = xfer->xroot->udev; 184f9f848faSopenharmony_ci int error; 185f9f848faSopenharmony_ci uint8_t iface_index; 186f9f848faSopenharmony_ci uint8_t temp_state; 187f9f848faSopenharmony_ci uint8_t do_unlock; 188f9f848faSopenharmony_ci 189f9f848faSopenharmony_ci if ((req.bmRequestType & 0x1F) == UT_INTERFACE) { 190f9f848faSopenharmony_ci iface_index = req.wIndex[0]; /* unicast */ 191f9f848faSopenharmony_ci } else { 192f9f848faSopenharmony_ci iface_index = 0; /* broadcast */ 193f9f848faSopenharmony_ci } 194f9f848faSopenharmony_ci 195f9f848faSopenharmony_ci /* 196f9f848faSopenharmony_ci * We need to protect against other threads doing probe and 197f9f848faSopenharmony_ci * attach: 198f9f848faSopenharmony_ci */ 199f9f848faSopenharmony_ci USB_XFER_UNLOCK(xfer); 200f9f848faSopenharmony_ci 201f9f848faSopenharmony_ci /* Prevent re-enumeration */ 202f9f848faSopenharmony_ci do_unlock = usbd_enum_lock(udev); 203f9f848faSopenharmony_ci 204f9f848faSopenharmony_ci error = ENXIO; 205f9f848faSopenharmony_ci 206f9f848faSopenharmony_citr_repeat: 207f9f848faSopenharmony_ci iface = usbd_get_iface(udev, iface_index); 208f9f848faSopenharmony_ci if ((iface == NULL) || 209f9f848faSopenharmony_ci (iface->idesc == NULL)) { 210f9f848faSopenharmony_ci /* end of interfaces non-existing interface */ 211f9f848faSopenharmony_ci goto tr_stalled; 212f9f848faSopenharmony_ci } 213f9f848faSopenharmony_ci /* set initial state */ 214f9f848faSopenharmony_ci 215f9f848faSopenharmony_ci temp_state = state; 216f9f848faSopenharmony_ci 217f9f848faSopenharmony_ci /* forward request to interface, if any */ 218f9f848faSopenharmony_ci 219f9f848faSopenharmony_ci if ((error != 0) && 220f9f848faSopenharmony_ci (error != ENOTTY) && 221f9f848faSopenharmony_ci (iface->subdev != NULL) && 222f9f848faSopenharmony_ci device_is_attached(iface->subdev)) { 223f9f848faSopenharmony_ci error = USB_HANDLE_REQUEST(iface->subdev, 224f9f848faSopenharmony_ci &req, ppdata, plen, 225f9f848faSopenharmony_ci off, &temp_state); 226f9f848faSopenharmony_ci } 227f9f848faSopenharmony_ci iface_parent = usbd_get_iface(udev, iface->parent_iface_index); 228f9f848faSopenharmony_ci 229f9f848faSopenharmony_ci if ((iface_parent == NULL) || 230f9f848faSopenharmony_ci (iface_parent->idesc == NULL)) { 231f9f848faSopenharmony_ci /* non-existing interface */ 232f9f848faSopenharmony_ci iface_parent = NULL; 233f9f848faSopenharmony_ci } 234f9f848faSopenharmony_ci /* forward request to parent interface, if any */ 235f9f848faSopenharmony_ci 236f9f848faSopenharmony_ci if ((error != 0) && 237f9f848faSopenharmony_ci (error != ENOTTY) && 238f9f848faSopenharmony_ci (iface_parent != NULL) && 239f9f848faSopenharmony_ci (iface_parent->subdev != NULL) && 240f9f848faSopenharmony_ci ((req.bmRequestType & 0x1F) == UT_INTERFACE) && 241f9f848faSopenharmony_ci (iface_parent->subdev != iface->subdev) && 242f9f848faSopenharmony_ci device_is_attached(iface_parent->subdev)) { 243f9f848faSopenharmony_ci error = USB_HANDLE_REQUEST(iface_parent->subdev, 244f9f848faSopenharmony_ci &req, ppdata, plen, off, &temp_state); 245f9f848faSopenharmony_ci } 246f9f848faSopenharmony_ci if (error == 0) { 247f9f848faSopenharmony_ci /* negativly adjust pointer and length */ 248f9f848faSopenharmony_ci *ppdata = ((uint8_t *)(*ppdata)) - off; 249f9f848faSopenharmony_ci *plen += off; 250f9f848faSopenharmony_ci 251f9f848faSopenharmony_ci if ((state == USB_HR_NOT_COMPLETE) && 252f9f848faSopenharmony_ci (temp_state == USB_HR_COMPLETE_OK)) 253f9f848faSopenharmony_ci goto tr_short; 254f9f848faSopenharmony_ci else 255f9f848faSopenharmony_ci goto tr_valid; 256f9f848faSopenharmony_ci } else if (error == ENOTTY) { 257f9f848faSopenharmony_ci goto tr_stalled; 258f9f848faSopenharmony_ci } 259f9f848faSopenharmony_ci if ((req.bmRequestType & 0x1F) != UT_INTERFACE) { 260f9f848faSopenharmony_ci iface_index++; /* iterate */ 261f9f848faSopenharmony_ci goto tr_repeat; 262f9f848faSopenharmony_ci } 263f9f848faSopenharmony_ci if (state != USB_HR_NOT_COMPLETE) { 264f9f848faSopenharmony_ci /* we are complete */ 265f9f848faSopenharmony_ci goto tr_valid; 266f9f848faSopenharmony_ci } 267f9f848faSopenharmony_ci switch (req.bmRequestType) { 268f9f848faSopenharmony_ci case UT_WRITE_INTERFACE: 269f9f848faSopenharmony_ci switch (req.bRequest) { 270f9f848faSopenharmony_ci case UR_SET_INTERFACE: 271f9f848faSopenharmony_ci /* 272f9f848faSopenharmony_ci * We assume that the endpoints are the same 273f9f848faSopenharmony_ci * across the alternate settings. 274f9f848faSopenharmony_ci * 275f9f848faSopenharmony_ci * Reset the endpoints, because re-attaching 276f9f848faSopenharmony_ci * only a part of the device is not possible. 277f9f848faSopenharmony_ci */ 278f9f848faSopenharmony_ci error = usb_check_alt_setting(udev, 279f9f848faSopenharmony_ci iface, req.wValue[0]); 280f9f848faSopenharmony_ci if (error) { 281f9f848faSopenharmony_ci DPRINTF("alt setting does not exist %s\n", 282f9f848faSopenharmony_ci usbd_errstr(error)); 283f9f848faSopenharmony_ci goto tr_stalled; 284f9f848faSopenharmony_ci } 285f9f848faSopenharmony_ci error = usb_reset_iface_endpoints(udev, iface_index); 286f9f848faSopenharmony_ci if (error) { 287f9f848faSopenharmony_ci DPRINTF("alt setting failed %s\n", 288f9f848faSopenharmony_ci usbd_errstr(error)); 289f9f848faSopenharmony_ci goto tr_stalled; 290f9f848faSopenharmony_ci } 291f9f848faSopenharmony_ci /* update the current alternate setting */ 292f9f848faSopenharmony_ci iface->alt_index = req.wValue[0]; 293f9f848faSopenharmony_ci break; 294f9f848faSopenharmony_ci 295f9f848faSopenharmony_ci default: 296f9f848faSopenharmony_ci goto tr_stalled; 297f9f848faSopenharmony_ci } 298f9f848faSopenharmony_ci break; 299f9f848faSopenharmony_ci 300f9f848faSopenharmony_ci case UT_READ_INTERFACE: 301f9f848faSopenharmony_ci switch (req.bRequest) { 302f9f848faSopenharmony_ci case UR_GET_INTERFACE: 303f9f848faSopenharmony_ci *ppdata = &iface->alt_index; 304f9f848faSopenharmony_ci *plen = 1; 305f9f848faSopenharmony_ci break; 306f9f848faSopenharmony_ci 307f9f848faSopenharmony_ci default: 308f9f848faSopenharmony_ci goto tr_stalled; 309f9f848faSopenharmony_ci } 310f9f848faSopenharmony_ci break; 311f9f848faSopenharmony_ci default: 312f9f848faSopenharmony_ci goto tr_stalled; 313f9f848faSopenharmony_ci } 314f9f848faSopenharmony_citr_valid: 315f9f848faSopenharmony_ci if (do_unlock) 316f9f848faSopenharmony_ci usbd_enum_unlock(udev); 317f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 318f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); 319f9f848faSopenharmony_ci 320f9f848faSopenharmony_citr_short: 321f9f848faSopenharmony_ci if (do_unlock) 322f9f848faSopenharmony_ci usbd_enum_unlock(udev); 323f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 324f9f848faSopenharmony_ci return (USB_ERR_SHORT_XFER); 325f9f848faSopenharmony_ci 326f9f848faSopenharmony_citr_stalled: 327f9f848faSopenharmony_ci if (do_unlock) 328f9f848faSopenharmony_ci usbd_enum_unlock(udev); 329f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 330f9f848faSopenharmony_ci return (USB_ERR_STALLED); 331f9f848faSopenharmony_ci} 332f9f848faSopenharmony_ci 333f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 334f9f848faSopenharmony_ci * usb_handle_stall 335f9f848faSopenharmony_ci * 336f9f848faSopenharmony_ci * Returns: 337f9f848faSopenharmony_ci * 0: Success 338f9f848faSopenharmony_ci * Else: Failure 339f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 340f9f848faSopenharmony_cistatic usb_error_t 341f9f848faSopenharmony_ciusb_handle_set_stall(struct usb_xfer *xfer, uint8_t ep, uint8_t do_stall) 342f9f848faSopenharmony_ci{ 343f9f848faSopenharmony_ci struct usb_device *udev = xfer->xroot->udev; 344f9f848faSopenharmony_ci usb_error_t err; 345f9f848faSopenharmony_ci 346f9f848faSopenharmony_ci USB_XFER_UNLOCK(xfer); 347f9f848faSopenharmony_ci err = usbd_set_endpoint_stall(udev, 348f9f848faSopenharmony_ci usbd_get_ep_by_addr(udev, ep), do_stall); 349f9f848faSopenharmony_ci USB_XFER_LOCK(xfer); 350f9f848faSopenharmony_ci return (err); 351f9f848faSopenharmony_ci} 352f9f848faSopenharmony_ci 353f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 354f9f848faSopenharmony_ci * usb_handle_get_stall 355f9f848faSopenharmony_ci * 356f9f848faSopenharmony_ci * Returns: 357f9f848faSopenharmony_ci * 0: Success 358f9f848faSopenharmony_ci * Else: Failure 359f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 360f9f848faSopenharmony_cistatic uint8_t 361f9f848faSopenharmony_ciusb_handle_get_stall(struct usb_device *udev, uint8_t ea_val) 362f9f848faSopenharmony_ci{ 363f9f848faSopenharmony_ci struct usb_endpoint *ep; 364f9f848faSopenharmony_ci uint8_t halted; 365f9f848faSopenharmony_ci 366f9f848faSopenharmony_ci ep = usbd_get_ep_by_addr(udev, ea_val); 367f9f848faSopenharmony_ci if (ep == NULL) { 368f9f848faSopenharmony_ci /* nothing to do */ 369f9f848faSopenharmony_ci return (0); 370f9f848faSopenharmony_ci } 371f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 372f9f848faSopenharmony_ci halted = ep->is_stalled; 373f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 374f9f848faSopenharmony_ci 375f9f848faSopenharmony_ci return (halted); 376f9f848faSopenharmony_ci} 377f9f848faSopenharmony_ci 378f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 379f9f848faSopenharmony_ci * usb_handle_remote_wakeup 380f9f848faSopenharmony_ci * 381f9f848faSopenharmony_ci * Returns: 382f9f848faSopenharmony_ci * 0: Success 383f9f848faSopenharmony_ci * Else: Failure 384f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 385f9f848faSopenharmony_cistatic usb_error_t 386f9f848faSopenharmony_ciusb_handle_remote_wakeup(struct usb_xfer *xfer, uint8_t is_on) 387f9f848faSopenharmony_ci{ 388f9f848faSopenharmony_ci struct usb_device *udev; 389f9f848faSopenharmony_ci struct usb_bus *bus; 390f9f848faSopenharmony_ci 391f9f848faSopenharmony_ci udev = xfer->xroot->udev; 392f9f848faSopenharmony_ci bus = udev->bus; 393f9f848faSopenharmony_ci 394f9f848faSopenharmony_ci USB_BUS_LOCK(bus); 395f9f848faSopenharmony_ci 396f9f848faSopenharmony_ci if (is_on) { 397f9f848faSopenharmony_ci udev->flags.remote_wakeup = 1; 398f9f848faSopenharmony_ci } else { 399f9f848faSopenharmony_ci udev->flags.remote_wakeup = 0; 400f9f848faSopenharmony_ci } 401f9f848faSopenharmony_ci 402f9f848faSopenharmony_ci USB_BUS_UNLOCK(bus); 403f9f848faSopenharmony_ci 404f9f848faSopenharmony_ci#if USB_HAVE_POWERD 405f9f848faSopenharmony_ci /* In case we are out of sync, update the power state. */ 406f9f848faSopenharmony_ci usb_bus_power_update(udev->bus); 407f9f848faSopenharmony_ci#endif 408f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); /* success */ 409f9f848faSopenharmony_ci} 410f9f848faSopenharmony_ci 411f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 412f9f848faSopenharmony_ci * usb_handle_request 413f9f848faSopenharmony_ci * 414f9f848faSopenharmony_ci * Internal state sequence: 415f9f848faSopenharmony_ci * 416f9f848faSopenharmony_ci * USB_HR_NOT_COMPLETE -> USB_HR_COMPLETE_OK v USB_HR_COMPLETE_ERR 417f9f848faSopenharmony_ci * 418f9f848faSopenharmony_ci * Returns: 419f9f848faSopenharmony_ci * 0: Ready to start hardware 420f9f848faSopenharmony_ci * Else: Stall current transfer, if any 421f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 422f9f848faSopenharmony_cistatic usb_error_t 423f9f848faSopenharmony_ciusb_handle_request(struct usb_xfer *xfer) 424f9f848faSopenharmony_ci{ 425f9f848faSopenharmony_ci struct usb_device_request req; 426f9f848faSopenharmony_ci struct usb_device *udev; 427f9f848faSopenharmony_ci const void *src_zcopy; /* zero-copy source pointer */ 428f9f848faSopenharmony_ci const void *src_mcopy; /* non zero-copy source pointer */ 429f9f848faSopenharmony_ci uint16_t off; /* data offset */ 430f9f848faSopenharmony_ci uint16_t rem; /* data remainder */ 431f9f848faSopenharmony_ci uint16_t max_len; /* max fragment length */ 432f9f848faSopenharmony_ci uint16_t wValue; 433f9f848faSopenharmony_ci uint8_t state; 434f9f848faSopenharmony_ci uint8_t is_complete = 1; 435f9f848faSopenharmony_ci usb_error_t err; 436f9f848faSopenharmony_ci union { 437f9f848faSopenharmony_ci uWord wStatus; 438f9f848faSopenharmony_ci uint8_t buf[2]; 439f9f848faSopenharmony_ci } temp; 440f9f848faSopenharmony_ci 441f9f848faSopenharmony_ci /* 442f9f848faSopenharmony_ci * Filter the USB transfer state into 443f9f848faSopenharmony_ci * something which we understand: 444f9f848faSopenharmony_ci */ 445f9f848faSopenharmony_ci 446f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 447f9f848faSopenharmony_ci case USB_ST_SETUP: 448f9f848faSopenharmony_ci state = USB_HR_NOT_COMPLETE; 449f9f848faSopenharmony_ci 450f9f848faSopenharmony_ci if (!xfer->flags_int.control_act) { 451f9f848faSopenharmony_ci /* nothing to do */ 452f9f848faSopenharmony_ci goto tr_stalled; 453f9f848faSopenharmony_ci } 454f9f848faSopenharmony_ci break; 455f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 456f9f848faSopenharmony_ci if (!xfer->flags_int.control_act) { 457f9f848faSopenharmony_ci state = USB_HR_COMPLETE_OK; 458f9f848faSopenharmony_ci } else { 459f9f848faSopenharmony_ci state = USB_HR_NOT_COMPLETE; 460f9f848faSopenharmony_ci } 461f9f848faSopenharmony_ci break; 462f9f848faSopenharmony_ci default: 463f9f848faSopenharmony_ci state = USB_HR_COMPLETE_ERR; 464f9f848faSopenharmony_ci break; 465f9f848faSopenharmony_ci } 466f9f848faSopenharmony_ci 467f9f848faSopenharmony_ci /* reset frame stuff */ 468f9f848faSopenharmony_ci 469f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, 0); 470f9f848faSopenharmony_ci 471f9f848faSopenharmony_ci usbd_xfer_set_frame_offset(xfer, 0, 0); 472f9f848faSopenharmony_ci usbd_xfer_set_frame_offset(xfer, sizeof(req), 1); 473f9f848faSopenharmony_ci 474f9f848faSopenharmony_ci /* get the current request, if any */ 475f9f848faSopenharmony_ci 476f9f848faSopenharmony_ci usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req)); 477f9f848faSopenharmony_ci 478f9f848faSopenharmony_ci if (xfer->flags_int.control_rem == 0xFFFF) { 479f9f848faSopenharmony_ci /* first time - not initialised */ 480f9f848faSopenharmony_ci rem = UGETW(req.wLength); 481f9f848faSopenharmony_ci off = 0; 482f9f848faSopenharmony_ci } else { 483f9f848faSopenharmony_ci /* not first time - initialised */ 484f9f848faSopenharmony_ci rem = xfer->flags_int.control_rem; 485f9f848faSopenharmony_ci off = UGETW(req.wLength) - rem; 486f9f848faSopenharmony_ci } 487f9f848faSopenharmony_ci 488f9f848faSopenharmony_ci /* set some defaults */ 489f9f848faSopenharmony_ci 490f9f848faSopenharmony_ci max_len = 0; 491f9f848faSopenharmony_ci src_zcopy = NULL; 492f9f848faSopenharmony_ci src_mcopy = NULL; 493f9f848faSopenharmony_ci udev = xfer->xroot->udev; 494f9f848faSopenharmony_ci 495f9f848faSopenharmony_ci /* get some request fields decoded */ 496f9f848faSopenharmony_ci 497f9f848faSopenharmony_ci wValue = UGETW(req.wValue); 498f9f848faSopenharmony_ci 499f9f848faSopenharmony_ci DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x " 500f9f848faSopenharmony_ci "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType, 501f9f848faSopenharmony_ci req.bRequest, wValue, UGETW(req.wIndex), off, rem, state); 502f9f848faSopenharmony_ci 503f9f848faSopenharmony_ci /* demultiplex the control request */ 504f9f848faSopenharmony_ci 505f9f848faSopenharmony_ci switch (req.bmRequestType) { 506f9f848faSopenharmony_ci case UT_READ_DEVICE: 507f9f848faSopenharmony_ci if (state != USB_HR_NOT_COMPLETE) { 508f9f848faSopenharmony_ci break; 509f9f848faSopenharmony_ci } 510f9f848faSopenharmony_ci switch (req.bRequest) { 511f9f848faSopenharmony_ci case UR_GET_DESCRIPTOR: 512f9f848faSopenharmony_ci goto tr_handle_get_descriptor; 513f9f848faSopenharmony_ci case UR_GET_CONFIG: 514f9f848faSopenharmony_ci goto tr_handle_get_config; 515f9f848faSopenharmony_ci case UR_GET_STATUS: 516f9f848faSopenharmony_ci goto tr_handle_get_status; 517f9f848faSopenharmony_ci default: 518f9f848faSopenharmony_ci goto tr_stalled; 519f9f848faSopenharmony_ci } 520f9f848faSopenharmony_ci break; 521f9f848faSopenharmony_ci 522f9f848faSopenharmony_ci case UT_WRITE_DEVICE: 523f9f848faSopenharmony_ci switch (req.bRequest) { 524f9f848faSopenharmony_ci case UR_SET_ADDRESS: 525f9f848faSopenharmony_ci goto tr_handle_set_address; 526f9f848faSopenharmony_ci case UR_SET_CONFIG: 527f9f848faSopenharmony_ci goto tr_handle_set_config; 528f9f848faSopenharmony_ci case UR_CLEAR_FEATURE: 529f9f848faSopenharmony_ci switch (wValue) { 530f9f848faSopenharmony_ci case UF_DEVICE_REMOTE_WAKEUP: 531f9f848faSopenharmony_ci goto tr_handle_clear_wakeup; 532f9f848faSopenharmony_ci default: 533f9f848faSopenharmony_ci goto tr_stalled; 534f9f848faSopenharmony_ci } 535f9f848faSopenharmony_ci break; 536f9f848faSopenharmony_ci case UR_SET_FEATURE: 537f9f848faSopenharmony_ci switch (wValue) { 538f9f848faSopenharmony_ci case UF_DEVICE_REMOTE_WAKEUP: 539f9f848faSopenharmony_ci goto tr_handle_set_wakeup; 540f9f848faSopenharmony_ci default: 541f9f848faSopenharmony_ci goto tr_stalled; 542f9f848faSopenharmony_ci } 543f9f848faSopenharmony_ci break; 544f9f848faSopenharmony_ci default: 545f9f848faSopenharmony_ci goto tr_stalled; 546f9f848faSopenharmony_ci } 547f9f848faSopenharmony_ci break; 548f9f848faSopenharmony_ci 549f9f848faSopenharmony_ci case UT_WRITE_ENDPOINT: 550f9f848faSopenharmony_ci switch (req.bRequest) { 551f9f848faSopenharmony_ci case UR_CLEAR_FEATURE: 552f9f848faSopenharmony_ci switch (wValue) { 553f9f848faSopenharmony_ci case UF_ENDPOINT_HALT: 554f9f848faSopenharmony_ci goto tr_handle_clear_halt; 555f9f848faSopenharmony_ci default: 556f9f848faSopenharmony_ci goto tr_stalled; 557f9f848faSopenharmony_ci } 558f9f848faSopenharmony_ci break; 559f9f848faSopenharmony_ci case UR_SET_FEATURE: 560f9f848faSopenharmony_ci switch (wValue) { 561f9f848faSopenharmony_ci case UF_ENDPOINT_HALT: 562f9f848faSopenharmony_ci goto tr_handle_set_halt; 563f9f848faSopenharmony_ci default: 564f9f848faSopenharmony_ci goto tr_stalled; 565f9f848faSopenharmony_ci } 566f9f848faSopenharmony_ci break; 567f9f848faSopenharmony_ci default: 568f9f848faSopenharmony_ci goto tr_stalled; 569f9f848faSopenharmony_ci } 570f9f848faSopenharmony_ci break; 571f9f848faSopenharmony_ci 572f9f848faSopenharmony_ci case UT_READ_ENDPOINT: 573f9f848faSopenharmony_ci switch (req.bRequest) { 574f9f848faSopenharmony_ci case UR_GET_STATUS: 575f9f848faSopenharmony_ci goto tr_handle_get_ep_status; 576f9f848faSopenharmony_ci default: 577f9f848faSopenharmony_ci goto tr_stalled; 578f9f848faSopenharmony_ci } 579f9f848faSopenharmony_ci break; 580f9f848faSopenharmony_ci default: 581f9f848faSopenharmony_ci /* we use "USB_ADD_BYTES" to de-const the src_zcopy */ 582f9f848faSopenharmony_ci err = usb_handle_iface_request(xfer, 583f9f848faSopenharmony_ci USB_ADD_BYTES(&src_zcopy, 0), 584f9f848faSopenharmony_ci &max_len, req, off, state); 585f9f848faSopenharmony_ci if (err == 0) { 586f9f848faSopenharmony_ci is_complete = 0; 587f9f848faSopenharmony_ci goto tr_valid; 588f9f848faSopenharmony_ci } else if (err == USB_ERR_SHORT_XFER) { 589f9f848faSopenharmony_ci goto tr_valid; 590f9f848faSopenharmony_ci } 591f9f848faSopenharmony_ci /* 592f9f848faSopenharmony_ci * Reset zero-copy pointer and max length 593f9f848faSopenharmony_ci * variable in case they were unintentionally 594f9f848faSopenharmony_ci * set: 595f9f848faSopenharmony_ci */ 596f9f848faSopenharmony_ci src_zcopy = NULL; 597f9f848faSopenharmony_ci max_len = 0; 598f9f848faSopenharmony_ci 599f9f848faSopenharmony_ci /* 600f9f848faSopenharmony_ci * Check if we have a vendor specific 601f9f848faSopenharmony_ci * descriptor: 602f9f848faSopenharmony_ci */ 603f9f848faSopenharmony_ci goto tr_handle_get_descriptor; 604f9f848faSopenharmony_ci } 605f9f848faSopenharmony_ci goto tr_valid; 606f9f848faSopenharmony_ci 607f9f848faSopenharmony_citr_handle_get_descriptor: 608f9f848faSopenharmony_ci err = (usb_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len); 609f9f848faSopenharmony_ci if (err) 610f9f848faSopenharmony_ci goto tr_stalled; 611f9f848faSopenharmony_ci if (src_zcopy == NULL) 612f9f848faSopenharmony_ci goto tr_stalled; 613f9f848faSopenharmony_ci goto tr_valid; 614f9f848faSopenharmony_ci 615f9f848faSopenharmony_citr_handle_get_config: 616f9f848faSopenharmony_ci temp.buf[0] = udev->curr_config_no; 617f9f848faSopenharmony_ci src_mcopy = temp.buf; 618f9f848faSopenharmony_ci max_len = 1; 619f9f848faSopenharmony_ci goto tr_valid; 620f9f848faSopenharmony_ci 621f9f848faSopenharmony_citr_handle_get_status: 622f9f848faSopenharmony_ci 623f9f848faSopenharmony_ci wValue = 0; 624f9f848faSopenharmony_ci 625f9f848faSopenharmony_ci USB_BUS_LOCK(udev->bus); 626f9f848faSopenharmony_ci if (udev->flags.remote_wakeup) { 627f9f848faSopenharmony_ci wValue |= UDS_REMOTE_WAKEUP; 628f9f848faSopenharmony_ci } 629f9f848faSopenharmony_ci if (udev->flags.self_powered) { 630f9f848faSopenharmony_ci wValue |= UDS_SELF_POWERED; 631f9f848faSopenharmony_ci } 632f9f848faSopenharmony_ci USB_BUS_UNLOCK(udev->bus); 633f9f848faSopenharmony_ci 634f9f848faSopenharmony_ci USETW(temp.wStatus, wValue); 635f9f848faSopenharmony_ci src_mcopy = temp.wStatus; 636f9f848faSopenharmony_ci max_len = sizeof(temp.wStatus); 637f9f848faSopenharmony_ci goto tr_valid; 638f9f848faSopenharmony_ci 639f9f848faSopenharmony_citr_handle_set_address: 640f9f848faSopenharmony_ci if (state == USB_HR_NOT_COMPLETE) { 641f9f848faSopenharmony_ci if (wValue >= 0x80) { 642f9f848faSopenharmony_ci /* invalid value */ 643f9f848faSopenharmony_ci goto tr_stalled; 644f9f848faSopenharmony_ci } else if (udev->curr_config_no != 0) { 645f9f848faSopenharmony_ci /* we are configured ! */ 646f9f848faSopenharmony_ci goto tr_stalled; 647f9f848faSopenharmony_ci } 648f9f848faSopenharmony_ci } else if (state != USB_HR_NOT_COMPLETE) { 649f9f848faSopenharmony_ci udev->address = (wValue & 0x7F); 650f9f848faSopenharmony_ci goto tr_bad_context; 651f9f848faSopenharmony_ci } 652f9f848faSopenharmony_ci goto tr_valid; 653f9f848faSopenharmony_ci 654f9f848faSopenharmony_citr_handle_set_config: 655f9f848faSopenharmony_ci if (state == USB_HR_NOT_COMPLETE) { 656f9f848faSopenharmony_ci if (usb_handle_set_config(xfer, req.wValue[0])) { 657f9f848faSopenharmony_ci goto tr_stalled; 658f9f848faSopenharmony_ci } 659f9f848faSopenharmony_ci } 660f9f848faSopenharmony_ci goto tr_valid; 661f9f848faSopenharmony_ci 662f9f848faSopenharmony_citr_handle_clear_halt: 663f9f848faSopenharmony_ci if (state == USB_HR_NOT_COMPLETE) { 664f9f848faSopenharmony_ci if (usb_handle_set_stall(xfer, req.wIndex[0], 0)) { 665f9f848faSopenharmony_ci goto tr_stalled; 666f9f848faSopenharmony_ci } 667f9f848faSopenharmony_ci } 668f9f848faSopenharmony_ci goto tr_valid; 669f9f848faSopenharmony_ci 670f9f848faSopenharmony_citr_handle_clear_wakeup: 671f9f848faSopenharmony_ci if (state == USB_HR_NOT_COMPLETE) { 672f9f848faSopenharmony_ci if (usb_handle_remote_wakeup(xfer, 0)) { 673f9f848faSopenharmony_ci goto tr_stalled; 674f9f848faSopenharmony_ci } 675f9f848faSopenharmony_ci } 676f9f848faSopenharmony_ci goto tr_valid; 677f9f848faSopenharmony_ci 678f9f848faSopenharmony_citr_handle_set_halt: 679f9f848faSopenharmony_ci if (state == USB_HR_NOT_COMPLETE) { 680f9f848faSopenharmony_ci if (usb_handle_set_stall(xfer, req.wIndex[0], 1)) { 681f9f848faSopenharmony_ci goto tr_stalled; 682f9f848faSopenharmony_ci } 683f9f848faSopenharmony_ci } 684f9f848faSopenharmony_ci goto tr_valid; 685f9f848faSopenharmony_ci 686f9f848faSopenharmony_citr_handle_set_wakeup: 687f9f848faSopenharmony_ci if (state == USB_HR_NOT_COMPLETE) { 688f9f848faSopenharmony_ci if (usb_handle_remote_wakeup(xfer, 1)) { 689f9f848faSopenharmony_ci goto tr_stalled; 690f9f848faSopenharmony_ci } 691f9f848faSopenharmony_ci } 692f9f848faSopenharmony_ci goto tr_valid; 693f9f848faSopenharmony_ci 694f9f848faSopenharmony_citr_handle_get_ep_status: 695f9f848faSopenharmony_ci if (state == USB_HR_NOT_COMPLETE) { 696f9f848faSopenharmony_ci temp.wStatus[0] = 697f9f848faSopenharmony_ci usb_handle_get_stall(udev, req.wIndex[0]); 698f9f848faSopenharmony_ci temp.wStatus[1] = 0; 699f9f848faSopenharmony_ci src_mcopy = temp.wStatus; 700f9f848faSopenharmony_ci max_len = sizeof(temp.wStatus); 701f9f848faSopenharmony_ci } 702f9f848faSopenharmony_ci goto tr_valid; 703f9f848faSopenharmony_ci 704f9f848faSopenharmony_citr_valid: 705f9f848faSopenharmony_ci if (state != USB_HR_NOT_COMPLETE) { 706f9f848faSopenharmony_ci goto tr_stalled; 707f9f848faSopenharmony_ci } 708f9f848faSopenharmony_ci /* subtract offset from length */ 709f9f848faSopenharmony_ci 710f9f848faSopenharmony_ci max_len -= off; 711f9f848faSopenharmony_ci 712f9f848faSopenharmony_ci /* Compute the real maximum data length */ 713f9f848faSopenharmony_ci 714f9f848faSopenharmony_ci if (max_len > xfer->max_data_length) { 715f9f848faSopenharmony_ci max_len = usbd_xfer_max_len(xfer); 716f9f848faSopenharmony_ci } 717f9f848faSopenharmony_ci if (max_len > rem) { 718f9f848faSopenharmony_ci max_len = rem; 719f9f848faSopenharmony_ci } 720f9f848faSopenharmony_ci /* 721f9f848faSopenharmony_ci * If the remainder is greater than the maximum data length, 722f9f848faSopenharmony_ci * we need to truncate the value for the sake of the 723f9f848faSopenharmony_ci * comparison below: 724f9f848faSopenharmony_ci */ 725f9f848faSopenharmony_ci if (rem > xfer->max_data_length) { 726f9f848faSopenharmony_ci rem = usbd_xfer_max_len(xfer); 727f9f848faSopenharmony_ci } 728f9f848faSopenharmony_ci if ((rem != max_len) && (is_complete != 0)) { 729f9f848faSopenharmony_ci /* 730f9f848faSopenharmony_ci * If we don't transfer the data we can transfer, then 731f9f848faSopenharmony_ci * the transfer is short ! 732f9f848faSopenharmony_ci */ 733f9f848faSopenharmony_ci xfer->flags.force_short_xfer = 1; 734f9f848faSopenharmony_ci xfer->nframes = 2; 735f9f848faSopenharmony_ci } else { 736f9f848faSopenharmony_ci /* 737f9f848faSopenharmony_ci * Default case 738f9f848faSopenharmony_ci */ 739f9f848faSopenharmony_ci xfer->flags.force_short_xfer = 0; 740f9f848faSopenharmony_ci xfer->nframes = max_len ? 2 : 1; 741f9f848faSopenharmony_ci } 742f9f848faSopenharmony_ci if (max_len > 0) { 743f9f848faSopenharmony_ci if (src_mcopy) { 744f9f848faSopenharmony_ci src_mcopy = USB_ADD_BYTES(src_mcopy, off); 745f9f848faSopenharmony_ci usbd_copy_in(xfer->frbuffers + 1, 0, 746f9f848faSopenharmony_ci src_mcopy, max_len); 747f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 1, max_len); 748f9f848faSopenharmony_ci } else { 749f9f848faSopenharmony_ci usbd_xfer_set_frame_data(xfer, 1, 750f9f848faSopenharmony_ci USB_ADD_BYTES(src_zcopy, off), max_len); 751f9f848faSopenharmony_ci } 752f9f848faSopenharmony_ci } else { 753f9f848faSopenharmony_ci /* the end is reached, send status */ 754f9f848faSopenharmony_ci xfer->flags.manual_status = 0; 755f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 1, 0); 756f9f848faSopenharmony_ci } 757f9f848faSopenharmony_ci DPRINTF("success\n"); 758f9f848faSopenharmony_ci return (USB_ERR_NORMAL_COMPLETION); /* success */ 759f9f848faSopenharmony_ci 760f9f848faSopenharmony_citr_stalled: 761f9f848faSopenharmony_ci DPRINTF("%s\n", (state != USB_HR_NOT_COMPLETE) ? 762f9f848faSopenharmony_ci "complete" : "stalled"); 763f9f848faSopenharmony_ci return (USB_ERR_STALLED); 764f9f848faSopenharmony_ci 765f9f848faSopenharmony_citr_bad_context: 766f9f848faSopenharmony_ci DPRINTF("bad context\n"); 767f9f848faSopenharmony_ci return (USB_ERR_BAD_CONTEXT); 768f9f848faSopenharmony_ci} 769