1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 2006-2023 Hans Petter Selasky 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 * usb_dev.c - An abstraction layer for creating devices under /dev/... 29f9f848faSopenharmony_ci */ 30f9f848faSopenharmony_ci 31f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 32f9f848faSopenharmony_ci#include "fs/driver.h" 33f9f848faSopenharmony_ci#include "fs/file.h" 34f9f848faSopenharmony_ci#include <unistd.h> 35f9f848faSopenharmony_ci 36f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 37f9f848faSopenharmony_ci#define USB_DEBUG_VAR usb_fifo_debug 38f9f848faSopenharmony_ci 39f9f848faSopenharmony_ci#if USB_HAVE_UGEN 40f9f848faSopenharmony_ci 41f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 42f9f848faSopenharmony_cistatic int usb_fifo_debug = 0; 43f9f848faSopenharmony_ci#endif 44f9f848faSopenharmony_ci 45f9f848faSopenharmony_ci/* prototypes */ 46f9f848faSopenharmony_ci 47f9f848faSopenharmony_cistatic int usb_fifo_open(struct usb_cdev_privdata *, 48f9f848faSopenharmony_ci struct usb_fifo *, int); 49f9f848faSopenharmony_cistatic void usb_fifo_close(struct usb_fifo *, int); 50f9f848faSopenharmony_cistatic void usb_fifo_check_methods(struct usb_fifo_methods *); 51f9f848faSopenharmony_cistatic struct usb_fifo *usb_fifo_alloc(struct mtx *); 52f9f848faSopenharmony_cistatic struct usb_endpoint *usb_dev_get_ep(struct usb_device *, uint8_t, 53f9f848faSopenharmony_ci uint8_t); 54f9f848faSopenharmony_cistatic void usb_loc_fill(struct usb_fs_privdata *, 55f9f848faSopenharmony_ci struct usb_cdev_privdata *); 56f9f848faSopenharmony_cistatic usb_error_t usb_ref_device(struct usb_cdev_privdata *, struct usb_cdev_refdata *, int); 57f9f848faSopenharmony_cistatic usb_error_t usb_usb_ref_device(struct usb_cdev_privdata *, struct usb_cdev_refdata *); 58f9f848faSopenharmony_cistatic void usb_unref_device(struct usb_cdev_privdata *, struct usb_cdev_refdata *); 59f9f848faSopenharmony_ci 60f9f848faSopenharmony_cistatic int usb_open(struct file *filep); 61f9f848faSopenharmony_cistatic int usb_close(struct file *filep); 62f9f848faSopenharmony_cistatic int usb_ioctl(struct file *filep, int cmd, unsigned long arg); 63f9f848faSopenharmony_cistatic ssize_t usb_read(struct file *filep, char *buffer, size_t buflen); 64f9f848faSopenharmony_cistatic ssize_t usb_write(struct file *filep, const char *buffer, size_t buflen); 65f9f848faSopenharmony_cistatic int usb_poll(struct file *filep, poll_table *fds); 66f9f848faSopenharmony_ci 67f9f848faSopenharmony_cistatic usb_fifo_open_t usb_fifo_dummy_open; 68f9f848faSopenharmony_cistatic usb_fifo_close_t usb_fifo_dummy_close; 69f9f848faSopenharmony_cistatic usb_fifo_ioctl_t usb_fifo_dummy_ioctl; 70f9f848faSopenharmony_cistatic usb_fifo_cmd_t usb_fifo_dummy_cmd; 71f9f848faSopenharmony_ci 72f9f848faSopenharmony_ci/* character device structure used for devices (/dev/ugenX.Y and /dev/uXXX) */ 73f9f848faSopenharmony_cistruct file_operations_vfs usb_devsw = { 74f9f848faSopenharmony_ci .open = usb_open, 75f9f848faSopenharmony_ci .close = usb_close, 76f9f848faSopenharmony_ci .ioctl = usb_ioctl, 77f9f848faSopenharmony_ci .read = usb_read, 78f9f848faSopenharmony_ci .write = usb_write, 79f9f848faSopenharmony_ci .poll = usb_poll, 80f9f848faSopenharmony_ci .mmap = NULL, 81f9f848faSopenharmony_ci}; 82f9f848faSopenharmony_ci 83f9f848faSopenharmony_cistatic TAILQ_HEAD(, usb_symlink) usb_sym_head; 84f9f848faSopenharmony_cistatic struct sx usb_sym_lock; 85f9f848faSopenharmony_ci 86f9f848faSopenharmony_cistruct mtx usb_ref_lock; 87f9f848faSopenharmony_ci 88f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 89f9f848faSopenharmony_ci * usb_loc_fill 90f9f848faSopenharmony_ci * 91f9f848faSopenharmony_ci * This is used to fill out a usb_cdev_privdata structure based on the 92f9f848faSopenharmony_ci * device's address as contained in usb_fs_privdata. 93f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 94f9f848faSopenharmony_cistatic void 95f9f848faSopenharmony_ciusb_loc_fill(struct usb_fs_privdata* pd, struct usb_cdev_privdata *cpd) 96f9f848faSopenharmony_ci{ 97f9f848faSopenharmony_ci cpd->bus_index = pd->bus_index; 98f9f848faSopenharmony_ci cpd->dev_index = pd->dev_index; 99f9f848faSopenharmony_ci cpd->ep_addr = pd->ep_addr; 100f9f848faSopenharmony_ci cpd->fifo_index = pd->fifo_index; 101f9f848faSopenharmony_ci} 102f9f848faSopenharmony_ci 103f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 104f9f848faSopenharmony_ci * usb_ref_device 105f9f848faSopenharmony_ci * 106f9f848faSopenharmony_ci * This function is used to atomically refer an USB device by its 107f9f848faSopenharmony_ci * device location. If this function returns success the USB device 108f9f848faSopenharmony_ci * will not disappear until the USB device is unreferenced. 109f9f848faSopenharmony_ci * 110f9f848faSopenharmony_ci * Return values: 111f9f848faSopenharmony_ci * 0: Success, refcount incremented on the given USB device. 112f9f848faSopenharmony_ci * Else: Failure. 113f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 114f9f848faSopenharmony_cistatic usb_error_t 115f9f848faSopenharmony_ciusb_ref_device(struct usb_cdev_privdata *cpd, 116f9f848faSopenharmony_ci struct usb_cdev_refdata *crd, int need_uref) 117f9f848faSopenharmony_ci{ 118f9f848faSopenharmony_ci struct usb_fifo **ppf = NULL; 119f9f848faSopenharmony_ci struct usb_fifo *f = NULL; 120f9f848faSopenharmony_ci 121f9f848faSopenharmony_ci DPRINTFN(2, "cpd=%p need uref=%d\n", cpd, need_uref); 122f9f848faSopenharmony_ci 123f9f848faSopenharmony_ci /* clear all refs */ 124f9f848faSopenharmony_ci (void)memset_s(crd, sizeof(*crd), 0, sizeof(*crd)); 125f9f848faSopenharmony_ci 126f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 127f9f848faSopenharmony_ci cpd->bus = devclass_get_softc(usb_devclass_ptr, cpd->bus_index); 128f9f848faSopenharmony_ci if (cpd->bus == NULL) { 129f9f848faSopenharmony_ci DPRINTFN(2, "no bus at %u\n", cpd->bus_index); 130f9f848faSopenharmony_ci goto error; 131f9f848faSopenharmony_ci } 132f9f848faSopenharmony_ci cpd->udev = cpd->bus->devices[cpd->dev_index]; 133f9f848faSopenharmony_ci if (cpd->udev == NULL) { 134f9f848faSopenharmony_ci DPRINTFN(2, "no device at %u\n", cpd->dev_index); 135f9f848faSopenharmony_ci goto error; 136f9f848faSopenharmony_ci } 137f9f848faSopenharmony_ci 138f9f848faSopenharmony_ci if (cpd->udev->state == USB_STATE_DETACHED && 139f9f848faSopenharmony_ci (need_uref != 2)) { 140f9f848faSopenharmony_ci DPRINTFN(2, "device is detached\n"); 141f9f848faSopenharmony_ci goto error; 142f9f848faSopenharmony_ci } 143f9f848faSopenharmony_ci if (need_uref) { 144f9f848faSopenharmony_ci DPRINTFN(2, "ref udev - needed\n"); 145f9f848faSopenharmony_ci 146f9f848faSopenharmony_ci if (cpd->udev->refcount == USB_DEV_REF_MAX) { 147f9f848faSopenharmony_ci DPRINTFN(2, "no dev ref\n"); 148f9f848faSopenharmony_ci goto error; 149f9f848faSopenharmony_ci } 150f9f848faSopenharmony_ci cpd->udev->refcount++; 151f9f848faSopenharmony_ci 152f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 153f9f848faSopenharmony_ci 154f9f848faSopenharmony_ci /* 155f9f848faSopenharmony_ci * We need to grab the enumeration SX-lock before 156f9f848faSopenharmony_ci * grabbing the FIFO refs to avoid deadlock at detach! 157f9f848faSopenharmony_ci */ 158f9f848faSopenharmony_ci crd->do_unlock = usbd_enum_lock(cpd->udev); 159f9f848faSopenharmony_ci 160f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 161f9f848faSopenharmony_ci 162f9f848faSopenharmony_ci /* 163f9f848faSopenharmony_ci * Set "is_uref" after grabbing the default SX lock 164f9f848faSopenharmony_ci */ 165f9f848faSopenharmony_ci crd->is_uref = 1; 166f9f848faSopenharmony_ci 167f9f848faSopenharmony_ci /* check for signal */ 168f9f848faSopenharmony_ci if (crd->do_unlock > 1) { 169f9f848faSopenharmony_ci crd->do_unlock = 0; 170f9f848faSopenharmony_ci goto error; 171f9f848faSopenharmony_ci } 172f9f848faSopenharmony_ci } 173f9f848faSopenharmony_ci 174f9f848faSopenharmony_ci /* check if we are doing an open */ 175f9f848faSopenharmony_ci if (cpd->fflags == 0) { 176f9f848faSopenharmony_ci /* use zero defaults */ 177f9f848faSopenharmony_ci } else { 178f9f848faSopenharmony_ci /* check for write */ 179f9f848faSopenharmony_ci if ((unsigned int)cpd->fflags & FWRITE) { 180f9f848faSopenharmony_ci ppf = cpd->udev->fifo; 181f9f848faSopenharmony_ci f = ppf[cpd->fifo_index + USB_FIFO_TX]; 182f9f848faSopenharmony_ci crd->txfifo = f; 183f9f848faSopenharmony_ci crd->is_write = 1; /* ref */ 184f9f848faSopenharmony_ci if (f == NULL || f->refcount == USB_FIFO_REF_MAX) 185f9f848faSopenharmony_ci goto error; 186f9f848faSopenharmony_ci if (f->curr_cpd != cpd) 187f9f848faSopenharmony_ci goto error; 188f9f848faSopenharmony_ci 189f9f848faSopenharmony_ci /* check if USB-FS is active */ 190f9f848faSopenharmony_ci if (f->fs_ep_max != 0) { 191f9f848faSopenharmony_ci crd->is_usbfs = 1; 192f9f848faSopenharmony_ci } 193f9f848faSopenharmony_ci } 194f9f848faSopenharmony_ci 195f9f848faSopenharmony_ci /* check for read */ 196f9f848faSopenharmony_ci if ((unsigned int)cpd->fflags & FREAD) { 197f9f848faSopenharmony_ci ppf = cpd->udev->fifo; 198f9f848faSopenharmony_ci f = ppf[cpd->fifo_index + USB_FIFO_RX]; 199f9f848faSopenharmony_ci crd->rxfifo = f; 200f9f848faSopenharmony_ci crd->is_read = 1; /* ref */ 201f9f848faSopenharmony_ci if (f == NULL || f->refcount == USB_FIFO_REF_MAX) 202f9f848faSopenharmony_ci goto error; 203f9f848faSopenharmony_ci if (f->curr_cpd != cpd) 204f9f848faSopenharmony_ci goto error; 205f9f848faSopenharmony_ci 206f9f848faSopenharmony_ci /* check if USB-FS is active */ 207f9f848faSopenharmony_ci if (f->fs_ep_max != 0) { 208f9f848faSopenharmony_ci crd->is_usbfs = 1; 209f9f848faSopenharmony_ci } 210f9f848faSopenharmony_ci } 211f9f848faSopenharmony_ci } 212f9f848faSopenharmony_ci 213f9f848faSopenharmony_ci /* when everything is OK we increment the refcounts */ 214f9f848faSopenharmony_ci if (crd->is_write) { 215f9f848faSopenharmony_ci DPRINTFN(2, "ref write\n"); 216f9f848faSopenharmony_ci crd->txfifo->refcount++; 217f9f848faSopenharmony_ci } 218f9f848faSopenharmony_ci if (crd->is_read) { 219f9f848faSopenharmony_ci DPRINTFN(2, "ref read\n"); 220f9f848faSopenharmony_ci crd->rxfifo->refcount++; 221f9f848faSopenharmony_ci } 222f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 223f9f848faSopenharmony_ci 224f9f848faSopenharmony_ci return (0); 225f9f848faSopenharmony_ci 226f9f848faSopenharmony_cierror: 227f9f848faSopenharmony_ci if (crd->do_unlock) 228f9f848faSopenharmony_ci usbd_enum_unlock(cpd->udev); 229f9f848faSopenharmony_ci 230f9f848faSopenharmony_ci if (crd->is_uref) { 231f9f848faSopenharmony_ci if (cpd->udev && --(cpd->udev->refcount) == 0) 232f9f848faSopenharmony_ci cv_broadcast(&cpd->udev->ref_cv); 233f9f848faSopenharmony_ci } 234f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 235f9f848faSopenharmony_ci DPRINTFN(2, "fail\n"); 236f9f848faSopenharmony_ci 237f9f848faSopenharmony_ci /* clear all refs */ 238f9f848faSopenharmony_ci memset(crd, 0, sizeof(*crd)); 239f9f848faSopenharmony_ci 240f9f848faSopenharmony_ci return (USB_ERR_INVAL); 241f9f848faSopenharmony_ci} 242f9f848faSopenharmony_ci 243f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 244f9f848faSopenharmony_ci * usb_usb_ref_device 245f9f848faSopenharmony_ci * 246f9f848faSopenharmony_ci * This function is used to upgrade an USB reference to include the 247f9f848faSopenharmony_ci * USB device reference on a USB location. 248f9f848faSopenharmony_ci * 249f9f848faSopenharmony_ci * Return values: 250f9f848faSopenharmony_ci * 0: Success, refcount incremented on the given USB device. 251f9f848faSopenharmony_ci * Else: Failure. 252f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 253f9f848faSopenharmony_cistatic usb_error_t 254f9f848faSopenharmony_ciusb_usb_ref_device(struct usb_cdev_privdata *cpd, 255f9f848faSopenharmony_ci struct usb_cdev_refdata *crd) 256f9f848faSopenharmony_ci{ 257f9f848faSopenharmony_ci /* 258f9f848faSopenharmony_ci * Check if we already got an USB reference on this location: 259f9f848faSopenharmony_ci */ 260f9f848faSopenharmony_ci if (crd->is_uref) 261f9f848faSopenharmony_ci return (0); /* success */ 262f9f848faSopenharmony_ci 263f9f848faSopenharmony_ci /* 264f9f848faSopenharmony_ci * To avoid deadlock at detach we need to drop the FIFO ref 265f9f848faSopenharmony_ci * and re-acquire a new ref! 266f9f848faSopenharmony_ci */ 267f9f848faSopenharmony_ci usb_unref_device(cpd, crd); 268f9f848faSopenharmony_ci 269f9f848faSopenharmony_ci return (usb_ref_device(cpd, crd, 1 /* need uref */)); 270f9f848faSopenharmony_ci} 271f9f848faSopenharmony_ci 272f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 273f9f848faSopenharmony_ci * usb_unref_device 274f9f848faSopenharmony_ci * 275f9f848faSopenharmony_ci * This function will release the reference count by one unit for the 276f9f848faSopenharmony_ci * given USB device. 277f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 278f9f848faSopenharmony_cistatic void 279f9f848faSopenharmony_ciusb_unref_device(struct usb_cdev_privdata *cpd, 280f9f848faSopenharmony_ci struct usb_cdev_refdata *crd) 281f9f848faSopenharmony_ci{ 282f9f848faSopenharmony_ci 283f9f848faSopenharmony_ci DPRINTFN(2, "cpd=%p is_uref=%d\n", cpd, crd->is_uref); 284f9f848faSopenharmony_ci 285f9f848faSopenharmony_ci if (crd->do_unlock) 286f9f848faSopenharmony_ci usbd_enum_unlock(cpd->udev); 287f9f848faSopenharmony_ci 288f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 289f9f848faSopenharmony_ci if (crd->is_read) { 290f9f848faSopenharmony_ci if (--(crd->rxfifo->refcount) == 0) { 291f9f848faSopenharmony_ci cv_signal(&crd->rxfifo->cv_drain); 292f9f848faSopenharmony_ci } 293f9f848faSopenharmony_ci crd->is_read = 0; 294f9f848faSopenharmony_ci } 295f9f848faSopenharmony_ci if (crd->is_write) { 296f9f848faSopenharmony_ci if (--(crd->txfifo->refcount) == 0) { 297f9f848faSopenharmony_ci cv_signal(&crd->txfifo->cv_drain); 298f9f848faSopenharmony_ci } 299f9f848faSopenharmony_ci crd->is_write = 0; 300f9f848faSopenharmony_ci } 301f9f848faSopenharmony_ci if (crd->is_uref) { 302f9f848faSopenharmony_ci crd->is_uref = 0; 303f9f848faSopenharmony_ci if (--(cpd->udev->refcount) == 0) 304f9f848faSopenharmony_ci cv_broadcast(&cpd->udev->ref_cv); 305f9f848faSopenharmony_ci } 306f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 307f9f848faSopenharmony_ci} 308f9f848faSopenharmony_ci 309f9f848faSopenharmony_cistatic struct usb_fifo * 310f9f848faSopenharmony_ciusb_fifo_alloc(struct mtx *mtx) 311f9f848faSopenharmony_ci{ 312f9f848faSopenharmony_ci struct usb_fifo *f; 313f9f848faSopenharmony_ci 314f9f848faSopenharmony_ci f = bsd_malloc(sizeof(*f), M_USBDEV, M_WAITOK | M_ZERO); 315f9f848faSopenharmony_ci if (f != NULL) { 316f9f848faSopenharmony_ci cv_init(&f->cv_io, "FIFO-IO"); 317f9f848faSopenharmony_ci cv_init(&f->cv_drain, "FIFO-DRAIN"); 318f9f848faSopenharmony_ci f->priv_mtx = mtx; 319f9f848faSopenharmony_ci f->refcount = 1; 320f9f848faSopenharmony_ci mtx_init(mtx, 0, 0, MTX_RECURSE); 321f9f848faSopenharmony_ci } 322f9f848faSopenharmony_ci return (f); 323f9f848faSopenharmony_ci} 324f9f848faSopenharmony_ci 325f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 326f9f848faSopenharmony_ci * usb_fifo_create 327f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 328f9f848faSopenharmony_cistatic int 329f9f848faSopenharmony_ciusb_fifo_create(struct usb_cdev_privdata *cpd, 330f9f848faSopenharmony_ci struct usb_cdev_refdata *crd) 331f9f848faSopenharmony_ci{ 332f9f848faSopenharmony_ci struct usb_device *udev = cpd->udev; 333f9f848faSopenharmony_ci struct usb_fifo *f = NULL; 334f9f848faSopenharmony_ci struct usb_endpoint *ep = NULL; 335f9f848faSopenharmony_ci uint8_t n; 336f9f848faSopenharmony_ci uint8_t is_tx; 337f9f848faSopenharmony_ci uint8_t is_rx; 338f9f848faSopenharmony_ci uint8_t no_null; 339f9f848faSopenharmony_ci uint8_t is_busy; 340f9f848faSopenharmony_ci int e = cpd->ep_addr; 341f9f848faSopenharmony_ci 342f9f848faSopenharmony_ci is_tx = ((unsigned int)cpd->fflags & FWRITE) ? 1 : 0; 343f9f848faSopenharmony_ci is_rx = ((unsigned int)cpd->fflags & FREAD) ? 1 : 0; 344f9f848faSopenharmony_ci no_null = 1; 345f9f848faSopenharmony_ci is_busy = 0; 346f9f848faSopenharmony_ci 347f9f848faSopenharmony_ci /* Preallocated FIFO */ 348f9f848faSopenharmony_ci if (e < 0) { 349f9f848faSopenharmony_ci DPRINTFN(5, "Preallocated FIFO\n"); 350f9f848faSopenharmony_ci if (is_tx) { 351f9f848faSopenharmony_ci f = udev->fifo[cpd->fifo_index + USB_FIFO_TX]; 352f9f848faSopenharmony_ci if (f == NULL) 353f9f848faSopenharmony_ci return (EINVAL); 354f9f848faSopenharmony_ci crd->txfifo = f; 355f9f848faSopenharmony_ci } 356f9f848faSopenharmony_ci if (is_rx) { 357f9f848faSopenharmony_ci f = udev->fifo[cpd->fifo_index + USB_FIFO_RX]; 358f9f848faSopenharmony_ci if (f == NULL) 359f9f848faSopenharmony_ci return (EINVAL); 360f9f848faSopenharmony_ci crd->rxfifo = f; 361f9f848faSopenharmony_ci } 362f9f848faSopenharmony_ci return (0); 363f9f848faSopenharmony_ci } 364f9f848faSopenharmony_ci 365f9f848faSopenharmony_ci KASSERT(e >= 0 && e <= 15, ("endpoint %d out of range", e)); 366f9f848faSopenharmony_ci 367f9f848faSopenharmony_ci /* search for a free FIFO slot */ 368f9f848faSopenharmony_ci DPRINTFN(5, "Endpoint device, searching for 0x%02x\n", e); 369f9f848faSopenharmony_ci for (n = 0;; n += 2) { 370f9f848faSopenharmony_ci if (n == USB_FIFO_MAX) { 371f9f848faSopenharmony_ci if (no_null) { 372f9f848faSopenharmony_ci no_null = 0; 373f9f848faSopenharmony_ci n = 0; 374f9f848faSopenharmony_ci } else { 375f9f848faSopenharmony_ci /* end of FIFOs reached */ 376f9f848faSopenharmony_ci DPRINTFN(5, "out of FIFOs\n"); 377f9f848faSopenharmony_ci return (ENOMEM); 378f9f848faSopenharmony_ci } 379f9f848faSopenharmony_ci } 380f9f848faSopenharmony_ci /* Check for TX FIFO */ 381f9f848faSopenharmony_ci if (is_tx) { 382f9f848faSopenharmony_ci f = udev->fifo[n + USB_FIFO_TX]; 383f9f848faSopenharmony_ci if (f != NULL) { 384f9f848faSopenharmony_ci if (f->dev_ep_index != e) { 385f9f848faSopenharmony_ci /* wrong endpoint index */ 386f9f848faSopenharmony_ci continue; 387f9f848faSopenharmony_ci } 388f9f848faSopenharmony_ci if (f->curr_cpd != NULL) { 389f9f848faSopenharmony_ci /* FIFO is opened */ 390f9f848faSopenharmony_ci is_busy = 1; 391f9f848faSopenharmony_ci continue; 392f9f848faSopenharmony_ci } 393f9f848faSopenharmony_ci } else if (no_null) { 394f9f848faSopenharmony_ci continue; 395f9f848faSopenharmony_ci } 396f9f848faSopenharmony_ci } 397f9f848faSopenharmony_ci /* Check for RX FIFO */ 398f9f848faSopenharmony_ci if (is_rx) { 399f9f848faSopenharmony_ci f = udev->fifo[n + USB_FIFO_RX]; 400f9f848faSopenharmony_ci if (f != NULL) { 401f9f848faSopenharmony_ci if (f->dev_ep_index != e) { 402f9f848faSopenharmony_ci /* wrong endpoint index */ 403f9f848faSopenharmony_ci continue; 404f9f848faSopenharmony_ci } 405f9f848faSopenharmony_ci if (f->curr_cpd != NULL) { 406f9f848faSopenharmony_ci /* FIFO is opened */ 407f9f848faSopenharmony_ci is_busy = 1; 408f9f848faSopenharmony_ci continue; 409f9f848faSopenharmony_ci } 410f9f848faSopenharmony_ci } else if (no_null) { 411f9f848faSopenharmony_ci continue; 412f9f848faSopenharmony_ci } 413f9f848faSopenharmony_ci } 414f9f848faSopenharmony_ci break; 415f9f848faSopenharmony_ci } 416f9f848faSopenharmony_ci 417f9f848faSopenharmony_ci if (no_null == 0) { 418f9f848faSopenharmony_ci if (e >= (USB_EP_MAX / 2)) { 419f9f848faSopenharmony_ci /* we don't create any endpoints in this range */ 420f9f848faSopenharmony_ci DPRINTFN(5, "ep out of range\n"); 421f9f848faSopenharmony_ci return (is_busy ? EBUSY : EINVAL); 422f9f848faSopenharmony_ci } 423f9f848faSopenharmony_ci } 424f9f848faSopenharmony_ci 425f9f848faSopenharmony_ci if ((e != 0) && is_busy) { 426f9f848faSopenharmony_ci /* 427f9f848faSopenharmony_ci * Only the default control endpoint is allowed to be 428f9f848faSopenharmony_ci * opened multiple times! 429f9f848faSopenharmony_ci */ 430f9f848faSopenharmony_ci DPRINTFN(5, "busy\n"); 431f9f848faSopenharmony_ci return (EBUSY); 432f9f848faSopenharmony_ci } 433f9f848faSopenharmony_ci 434f9f848faSopenharmony_ci /* Check TX FIFO */ 435f9f848faSopenharmony_ci if (is_tx && 436f9f848faSopenharmony_ci (udev->fifo[n + USB_FIFO_TX] == NULL)) { 437f9f848faSopenharmony_ci ep = usb_dev_get_ep(udev, e, USB_FIFO_TX); 438f9f848faSopenharmony_ci DPRINTFN(5, "dev_get_endpoint(%d, 0x%x)\n", e, USB_FIFO_TX); 439f9f848faSopenharmony_ci if (ep == NULL) { 440f9f848faSopenharmony_ci DPRINTFN(5, "dev_get_endpoint returned NULL\n"); 441f9f848faSopenharmony_ci return (EINVAL); 442f9f848faSopenharmony_ci } 443f9f848faSopenharmony_ci f = usb_fifo_alloc(&udev->device_mtx); 444f9f848faSopenharmony_ci if (f == NULL) { 445f9f848faSopenharmony_ci DPRINTFN(5, "could not alloc tx fifo\n"); 446f9f848faSopenharmony_ci return (ENOMEM); 447f9f848faSopenharmony_ci } 448f9f848faSopenharmony_ci /* update some fields */ 449f9f848faSopenharmony_ci f->fifo_index = n + USB_FIFO_TX; 450f9f848faSopenharmony_ci f->dev_ep_index = e; 451f9f848faSopenharmony_ci f->priv_sc0 = ep; 452f9f848faSopenharmony_ci f->methods = &usb_ugen_methods; 453f9f848faSopenharmony_ci f->iface_index = ep->iface_index; 454f9f848faSopenharmony_ci f->udev = udev; 455f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 456f9f848faSopenharmony_ci udev->fifo[n + USB_FIFO_TX] = f; 457f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 458f9f848faSopenharmony_ci } 459f9f848faSopenharmony_ci /* Check RX FIFO */ 460f9f848faSopenharmony_ci if (is_rx && 461f9f848faSopenharmony_ci (udev->fifo[n + USB_FIFO_RX] == NULL)) { 462f9f848faSopenharmony_ci ep = usb_dev_get_ep(udev, e, USB_FIFO_RX); 463f9f848faSopenharmony_ci DPRINTFN(5, "dev_get_endpoint(%d, 0x%x)\n", e, USB_FIFO_RX); 464f9f848faSopenharmony_ci if (ep == NULL) { 465f9f848faSopenharmony_ci DPRINTFN(5, "dev_get_endpoint returned NULL\n"); 466f9f848faSopenharmony_ci return (EINVAL); 467f9f848faSopenharmony_ci } 468f9f848faSopenharmony_ci f = usb_fifo_alloc(&udev->device_mtx); 469f9f848faSopenharmony_ci if (f == NULL) { 470f9f848faSopenharmony_ci DPRINTFN(5, "could not alloc rx fifo\n"); 471f9f848faSopenharmony_ci return (ENOMEM); 472f9f848faSopenharmony_ci } 473f9f848faSopenharmony_ci /* update some fields */ 474f9f848faSopenharmony_ci f->fifo_index = n + USB_FIFO_RX; 475f9f848faSopenharmony_ci f->dev_ep_index = e; 476f9f848faSopenharmony_ci f->priv_sc0 = ep; 477f9f848faSopenharmony_ci f->methods = &usb_ugen_methods; 478f9f848faSopenharmony_ci f->iface_index = ep->iface_index; 479f9f848faSopenharmony_ci f->udev = udev; 480f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 481f9f848faSopenharmony_ci udev->fifo[n + USB_FIFO_RX] = f; 482f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 483f9f848faSopenharmony_ci } 484f9f848faSopenharmony_ci if (is_tx) { 485f9f848faSopenharmony_ci crd->txfifo = udev->fifo[n + USB_FIFO_TX]; 486f9f848faSopenharmony_ci } 487f9f848faSopenharmony_ci if (is_rx) { 488f9f848faSopenharmony_ci crd->rxfifo = udev->fifo[n + USB_FIFO_RX]; 489f9f848faSopenharmony_ci } 490f9f848faSopenharmony_ci /* fill out fifo index */ 491f9f848faSopenharmony_ci DPRINTFN(5, "fifo index = %d\n", n); 492f9f848faSopenharmony_ci cpd->fifo_index = n; 493f9f848faSopenharmony_ci 494f9f848faSopenharmony_ci /* complete */ 495f9f848faSopenharmony_ci 496f9f848faSopenharmony_ci return (0); 497f9f848faSopenharmony_ci} 498f9f848faSopenharmony_ci 499f9f848faSopenharmony_civoid 500f9f848faSopenharmony_ciusb_fifo_free(struct usb_fifo *f) 501f9f848faSopenharmony_ci{ 502f9f848faSopenharmony_ci uint8_t n; 503f9f848faSopenharmony_ci 504f9f848faSopenharmony_ci if (f == NULL) { 505f9f848faSopenharmony_ci /* be NULL safe */ 506f9f848faSopenharmony_ci return; 507f9f848faSopenharmony_ci } 508f9f848faSopenharmony_ci /* destroy symlink devices, if any */ 509f9f848faSopenharmony_ci for (n = 0; n != 2; n++) { 510f9f848faSopenharmony_ci if (f->symlink[n]) { 511f9f848faSopenharmony_ci usb_free_symlink(f->symlink[n]); 512f9f848faSopenharmony_ci f->symlink[n] = NULL; 513f9f848faSopenharmony_ci } 514f9f848faSopenharmony_ci } 515f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 516f9f848faSopenharmony_ci 517f9f848faSopenharmony_ci /* delink ourselves to stop calls from userland */ 518f9f848faSopenharmony_ci if ((f->fifo_index < USB_FIFO_MAX) && 519f9f848faSopenharmony_ci (f->udev != NULL) && 520f9f848faSopenharmony_ci (f->udev->fifo[f->fifo_index] == f)) { 521f9f848faSopenharmony_ci f->udev->fifo[f->fifo_index] = NULL; 522f9f848faSopenharmony_ci } else { 523f9f848faSopenharmony_ci DPRINTFN(0, "USB FIFO %p has not been linked\n", f); 524f9f848faSopenharmony_ci } 525f9f848faSopenharmony_ci 526f9f848faSopenharmony_ci /* decrease refcount */ 527f9f848faSopenharmony_ci f->refcount--; 528f9f848faSopenharmony_ci /* need to wait until all callers have exited */ 529f9f848faSopenharmony_ci while (f->refcount != 0) { 530f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); /* avoid LOR */ 531f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 532f9f848faSopenharmony_ci /* prevent write flush, if any */ 533f9f848faSopenharmony_ci f->flag_iserror = 1; 534f9f848faSopenharmony_ci /* get I/O thread out of any sleep state */ 535f9f848faSopenharmony_ci if (f->flag_sleeping) { 536f9f848faSopenharmony_ci f->flag_sleeping = 0; 537f9f848faSopenharmony_ci cv_broadcast(&f->cv_io); 538f9f848faSopenharmony_ci } 539f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 540f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 541f9f848faSopenharmony_ci 542f9f848faSopenharmony_ci /* 543f9f848faSopenharmony_ci * Check if the "f->refcount" variable reached zero 544f9f848faSopenharmony_ci * during the unlocked time before entering wait: 545f9f848faSopenharmony_ci */ 546f9f848faSopenharmony_ci if (f->refcount == 0) 547f9f848faSopenharmony_ci break; 548f9f848faSopenharmony_ci 549f9f848faSopenharmony_ci /* wait for sync */ 550f9f848faSopenharmony_ci cv_wait(&f->cv_drain, &usb_ref_lock); 551f9f848faSopenharmony_ci } 552f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 553f9f848faSopenharmony_ci 554f9f848faSopenharmony_ci /* take care of closing the device here, if any */ 555f9f848faSopenharmony_ci usb_fifo_close(f, 0); 556f9f848faSopenharmony_ci 557f9f848faSopenharmony_ci cv_destroy(&f->cv_io); 558f9f848faSopenharmony_ci cv_destroy(&f->cv_drain); 559f9f848faSopenharmony_ci 560f9f848faSopenharmony_ci bsd_free(f, M_USBDEV); 561f9f848faSopenharmony_ci} 562f9f848faSopenharmony_ci 563f9f848faSopenharmony_cistatic struct usb_endpoint * 564f9f848faSopenharmony_ciusb_dev_get_ep(struct usb_device *udev, uint8_t ep_index, uint8_t dir) 565f9f848faSopenharmony_ci{ 566f9f848faSopenharmony_ci struct usb_endpoint *ep = NULL; 567f9f848faSopenharmony_ci uint8_t ep_dir; 568f9f848faSopenharmony_ci 569f9f848faSopenharmony_ci if (ep_index == 0) { 570f9f848faSopenharmony_ci ep = &udev->ctrl_ep; 571f9f848faSopenharmony_ci } else { 572f9f848faSopenharmony_ci if (dir == USB_FIFO_RX) { 573f9f848faSopenharmony_ci if (udev->flags.usb_mode == USB_MODE_HOST) { 574f9f848faSopenharmony_ci ep_dir = UE_DIR_IN; 575f9f848faSopenharmony_ci } else { 576f9f848faSopenharmony_ci ep_dir = UE_DIR_OUT; 577f9f848faSopenharmony_ci } 578f9f848faSopenharmony_ci } else { 579f9f848faSopenharmony_ci if (udev->flags.usb_mode == USB_MODE_HOST) { 580f9f848faSopenharmony_ci ep_dir = UE_DIR_OUT; 581f9f848faSopenharmony_ci } else { 582f9f848faSopenharmony_ci ep_dir = UE_DIR_IN; 583f9f848faSopenharmony_ci } 584f9f848faSopenharmony_ci } 585f9f848faSopenharmony_ci ep = usbd_get_ep_by_addr(udev, ep_index | ep_dir); 586f9f848faSopenharmony_ci } 587f9f848faSopenharmony_ci 588f9f848faSopenharmony_ci if (ep == NULL) { 589f9f848faSopenharmony_ci /* if the endpoint does not exist then return */ 590f9f848faSopenharmony_ci return (NULL); 591f9f848faSopenharmony_ci } 592f9f848faSopenharmony_ci if (ep->edesc == NULL) { 593f9f848faSopenharmony_ci /* invalid endpoint */ 594f9f848faSopenharmony_ci return (NULL); 595f9f848faSopenharmony_ci } 596f9f848faSopenharmony_ci return (ep); /* success */ 597f9f848faSopenharmony_ci} 598f9f848faSopenharmony_ci 599f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 600f9f848faSopenharmony_ci * usb_fifo_open 601f9f848faSopenharmony_ci * 602f9f848faSopenharmony_ci * Returns: 603f9f848faSopenharmony_ci * 0: Success 604f9f848faSopenharmony_ci * Else: Failure 605f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 606f9f848faSopenharmony_cistatic int 607f9f848faSopenharmony_ciusb_fifo_open(struct usb_cdev_privdata *cpd, 608f9f848faSopenharmony_ci struct usb_fifo *f, int fflags) 609f9f848faSopenharmony_ci{ 610f9f848faSopenharmony_ci int err; 611f9f848faSopenharmony_ci 612f9f848faSopenharmony_ci if (f == NULL) { 613f9f848faSopenharmony_ci /* no FIFO there */ 614f9f848faSopenharmony_ci DPRINTFN(2, "no FIFO\n"); 615f9f848faSopenharmony_ci return (ENXIO); 616f9f848faSopenharmony_ci } 617f9f848faSopenharmony_ci /* remove FWRITE and FREAD flags */ 618f9f848faSopenharmony_ci fflags = (unsigned int)fflags & (~(FWRITE | FREAD)); 619f9f848faSopenharmony_ci 620f9f848faSopenharmony_ci /* set correct file flags */ 621f9f848faSopenharmony_ci if ((f->fifo_index & 1) == USB_FIFO_TX) { 622f9f848faSopenharmony_ci fflags = (unsigned int)fflags | FWRITE; 623f9f848faSopenharmony_ci } else { 624f9f848faSopenharmony_ci fflags = (unsigned int)fflags | FREAD; 625f9f848faSopenharmony_ci } 626f9f848faSopenharmony_ci 627f9f848faSopenharmony_ci /* check if we are already opened */ 628f9f848faSopenharmony_ci /* we don't need any locks when checking this variable */ 629f9f848faSopenharmony_ci if (f->curr_cpd != NULL) { 630f9f848faSopenharmony_ci err = EBUSY; 631f9f848faSopenharmony_ci goto done; 632f9f848faSopenharmony_ci } 633f9f848faSopenharmony_ci 634f9f848faSopenharmony_ci /* reset short flag before open */ 635f9f848faSopenharmony_ci f->flag_short = 0; 636f9f848faSopenharmony_ci 637f9f848faSopenharmony_ci /* call open method */ 638f9f848faSopenharmony_ci err = (f->methods->f_open) (f, fflags); 639f9f848faSopenharmony_ci if (err) { 640f9f848faSopenharmony_ci goto done; 641f9f848faSopenharmony_ci } 642f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 643f9f848faSopenharmony_ci 644f9f848faSopenharmony_ci /* reset sleep flag */ 645f9f848faSopenharmony_ci f->flag_sleeping = 0; 646f9f848faSopenharmony_ci 647f9f848faSopenharmony_ci /* reset error flag */ 648f9f848faSopenharmony_ci f->flag_iserror = 0; 649f9f848faSopenharmony_ci 650f9f848faSopenharmony_ci /* reset complete flag */ 651f9f848faSopenharmony_ci f->flag_iscomplete = 0; 652f9f848faSopenharmony_ci 653f9f848faSopenharmony_ci /* reset select flag */ 654f9f848faSopenharmony_ci f->flag_isselect = 0; 655f9f848faSopenharmony_ci 656f9f848faSopenharmony_ci /* reset flushing flag */ 657f9f848faSopenharmony_ci f->flag_flushing = 0; 658f9f848faSopenharmony_ci 659f9f848faSopenharmony_ci /* reset ASYNC proc flag */ 660f9f848faSopenharmony_ci f->async_p = NULL; 661f9f848faSopenharmony_ci 662f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 663f9f848faSopenharmony_ci /* flag the fifo as opened to prevent others */ 664f9f848faSopenharmony_ci f->curr_cpd = cpd; 665f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 666f9f848faSopenharmony_ci 667f9f848faSopenharmony_ci /* reset queue */ 668f9f848faSopenharmony_ci usb_fifo_reset(f); 669f9f848faSopenharmony_ci 670f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 671f9f848faSopenharmony_cidone: 672f9f848faSopenharmony_ci return (err); 673f9f848faSopenharmony_ci} 674f9f848faSopenharmony_ci 675f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 676f9f848faSopenharmony_ci * usb_fifo_reset 677f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 678f9f848faSopenharmony_civoid 679f9f848faSopenharmony_ciusb_fifo_reset(struct usb_fifo *f) 680f9f848faSopenharmony_ci{ 681f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 682f9f848faSopenharmony_ci 683f9f848faSopenharmony_ci if (f == NULL) { 684f9f848faSopenharmony_ci return; 685f9f848faSopenharmony_ci } 686f9f848faSopenharmony_ci while (1) { 687f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->used_q, m); 688f9f848faSopenharmony_ci if (m) { 689f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->free_q, m); 690f9f848faSopenharmony_ci } else { 691f9f848faSopenharmony_ci break; 692f9f848faSopenharmony_ci } 693f9f848faSopenharmony_ci } 694f9f848faSopenharmony_ci /* reset have fragment flag */ 695f9f848faSopenharmony_ci f->flag_have_fragment = 0; 696f9f848faSopenharmony_ci} 697f9f848faSopenharmony_ci 698f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 699f9f848faSopenharmony_ci * usb_fifo_close 700f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 701f9f848faSopenharmony_cistatic void 702f9f848faSopenharmony_ciusb_fifo_close(struct usb_fifo *f, int fflags) 703f9f848faSopenharmony_ci{ 704f9f848faSopenharmony_ci int err; 705f9f848faSopenharmony_ci 706f9f848faSopenharmony_ci /* check if we are not opened */ 707f9f848faSopenharmony_ci if (f->curr_cpd == NULL) { 708f9f848faSopenharmony_ci /* nothing to do - already closed */ 709f9f848faSopenharmony_ci return; 710f9f848faSopenharmony_ci } 711f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 712f9f848faSopenharmony_ci 713f9f848faSopenharmony_ci /* clear current cdev private data pointer */ 714f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 715f9f848faSopenharmony_ci f->curr_cpd = NULL; 716f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 717f9f848faSopenharmony_ci 718f9f848faSopenharmony_ci /* remove FWRITE and FREAD flags */ 719f9f848faSopenharmony_ci fflags = (unsigned int)fflags & (~(FWRITE | FREAD)); 720f9f848faSopenharmony_ci 721f9f848faSopenharmony_ci /* flush written data, if any */ 722f9f848faSopenharmony_ci if ((f->fifo_index & 1) == USB_FIFO_TX) { 723f9f848faSopenharmony_ci if (!f->flag_iserror) { 724f9f848faSopenharmony_ci /* set flushing flag */ 725f9f848faSopenharmony_ci f->flag_flushing = 1; 726f9f848faSopenharmony_ci 727f9f848faSopenharmony_ci /* get the last packet in */ 728f9f848faSopenharmony_ci if (f->flag_have_fragment) { 729f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 730f9f848faSopenharmony_ci f->flag_have_fragment = 0; 731f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->free_q, m); 732f9f848faSopenharmony_ci if (m) { 733f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->used_q, m); 734f9f848faSopenharmony_ci } 735f9f848faSopenharmony_ci } 736f9f848faSopenharmony_ci 737f9f848faSopenharmony_ci /* start write transfer, if not already started */ 738f9f848faSopenharmony_ci (f->methods->f_start_write) (f); 739f9f848faSopenharmony_ci 740f9f848faSopenharmony_ci /* check if flushed already */ 741f9f848faSopenharmony_ci while (f->flag_flushing && 742f9f848faSopenharmony_ci (!f->flag_iserror)) { 743f9f848faSopenharmony_ci /* wait until all data has been written */ 744f9f848faSopenharmony_ci f->flag_sleeping = 1; 745f9f848faSopenharmony_ci err = cv_timedwait(&f->cv_io, f->priv_mtx, 746f9f848faSopenharmony_ci USB_MS_TO_TICKS(USB_DEFAULT_TIMEOUT)); 747f9f848faSopenharmony_ci if (err) { 748f9f848faSopenharmony_ci DPRINTF("signal received\n"); 749f9f848faSopenharmony_ci break; 750f9f848faSopenharmony_ci } 751f9f848faSopenharmony_ci } 752f9f848faSopenharmony_ci } 753f9f848faSopenharmony_ci fflags = (unsigned int)fflags | FWRITE; 754f9f848faSopenharmony_ci 755f9f848faSopenharmony_ci /* stop write transfer, if not already stopped */ 756f9f848faSopenharmony_ci (f->methods->f_stop_write) (f); 757f9f848faSopenharmony_ci } else { 758f9f848faSopenharmony_ci fflags = (unsigned int)fflags | FREAD; 759f9f848faSopenharmony_ci 760f9f848faSopenharmony_ci /* stop write transfer, if not already stopped */ 761f9f848faSopenharmony_ci (f->methods->f_stop_read) (f); 762f9f848faSopenharmony_ci } 763f9f848faSopenharmony_ci 764f9f848faSopenharmony_ci /* check if we are sleeping */ 765f9f848faSopenharmony_ci if (f->flag_sleeping) { 766f9f848faSopenharmony_ci DPRINTFN(2, "Sleeping at close!\n"); 767f9f848faSopenharmony_ci } 768f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 769f9f848faSopenharmony_ci 770f9f848faSopenharmony_ci /* call close method */ 771f9f848faSopenharmony_ci (f->methods->f_close) (f, fflags); 772f9f848faSopenharmony_ci 773f9f848faSopenharmony_ci DPRINTF("closed\n"); 774f9f848faSopenharmony_ci} 775f9f848faSopenharmony_ci 776f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 777f9f848faSopenharmony_ci * usb_open - cdev callback 778f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 779f9f848faSopenharmony_cistatic int 780f9f848faSopenharmony_ciusb_open(struct file *filep) 781f9f848faSopenharmony_ci{ 782f9f848faSopenharmony_ci struct drv_data* drvData = (struct drv_data* )filep->f_vnode->data; 783f9f848faSopenharmony_ci struct usb_fs_privdata* pd = (struct usb_fs_privdata* )drvData->priv; 784f9f848faSopenharmony_ci struct usb_cdev_refdata refs; 785f9f848faSopenharmony_ci struct usb_cdev_privdata *cpd = NULL; 786f9f848faSopenharmony_ci int err; 787f9f848faSopenharmony_ci int fflags; 788f9f848faSopenharmony_ci 789f9f848faSopenharmony_ci DPRINTFN(2, "%s fflags=0x%08x\n", filep->f_path, fflags); 790f9f848faSopenharmony_ci 791f9f848faSopenharmony_ci if (((unsigned int)filep->f_oflags & O_ACCMODE) == O_RDWR) { 792f9f848faSopenharmony_ci fflags = FREAD | FWRITE; 793f9f848faSopenharmony_ci } else if (((unsigned int)filep->f_oflags & O_ACCMODE) == O_WRONLY) { 794f9f848faSopenharmony_ci fflags = FWRITE; 795f9f848faSopenharmony_ci } else { 796f9f848faSopenharmony_ci fflags = FREAD; 797f9f848faSopenharmony_ci } 798f9f848faSopenharmony_ci 799f9f848faSopenharmony_ci cpd = bsd_malloc(sizeof(*cpd), M_USBDEV, M_WAITOK | M_ZERO); 800f9f848faSopenharmony_ci if (cpd == NULL) { 801f9f848faSopenharmony_ci return (-ENOMEM); 802f9f848faSopenharmony_ci } 803f9f848faSopenharmony_ci 804f9f848faSopenharmony_ci usb_loc_fill(pd, cpd); 805f9f848faSopenharmony_ci err = usb_ref_device(cpd, &refs, 1); 806f9f848faSopenharmony_ci if (err) { 807f9f848faSopenharmony_ci DPRINTFN(2, "cannot ref device\n"); 808f9f848faSopenharmony_ci bsd_free(cpd, M_USBDEV); 809f9f848faSopenharmony_ci return (-ENXIO); 810f9f848faSopenharmony_ci } 811f9f848faSopenharmony_ci cpd->fflags = fflags; /* access mode for open lifetime */ 812f9f848faSopenharmony_ci 813f9f848faSopenharmony_ci /* create FIFOs, if any */ 814f9f848faSopenharmony_ci err = usb_fifo_create(cpd, &refs); 815f9f848faSopenharmony_ci /* check for error */ 816f9f848faSopenharmony_ci if (err) { 817f9f848faSopenharmony_ci DPRINTFN(2, "cannot create fifo\n"); 818f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 819f9f848faSopenharmony_ci bsd_free(cpd, M_USBDEV); 820f9f848faSopenharmony_ci return (-err); 821f9f848faSopenharmony_ci } 822f9f848faSopenharmony_ci if ((unsigned int)fflags & FREAD) { 823f9f848faSopenharmony_ci err = usb_fifo_open(cpd, refs.rxfifo, fflags); 824f9f848faSopenharmony_ci if (err) { 825f9f848faSopenharmony_ci DPRINTFN(2, "read open failed\n"); 826f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 827f9f848faSopenharmony_ci bsd_free(cpd, M_USBDEV); 828f9f848faSopenharmony_ci return (-err); 829f9f848faSopenharmony_ci } 830f9f848faSopenharmony_ci } 831f9f848faSopenharmony_ci if ((unsigned int)fflags & FWRITE) { 832f9f848faSopenharmony_ci err = usb_fifo_open(cpd, refs.txfifo, fflags); 833f9f848faSopenharmony_ci if (err) { 834f9f848faSopenharmony_ci DPRINTFN(2, "write open failed\n"); 835f9f848faSopenharmony_ci if ((unsigned int)fflags & FREAD) { 836f9f848faSopenharmony_ci usb_fifo_close(refs.rxfifo, fflags); 837f9f848faSopenharmony_ci } 838f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 839f9f848faSopenharmony_ci bsd_free(cpd, M_USBDEV); 840f9f848faSopenharmony_ci return (-err); 841f9f848faSopenharmony_ci 842f9f848faSopenharmony_ci } 843f9f848faSopenharmony_ci } 844f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 845f9f848faSopenharmony_ci filep->f_priv = cpd; 846f9f848faSopenharmony_ci 847f9f848faSopenharmony_ci return (0); 848f9f848faSopenharmony_ci} 849f9f848faSopenharmony_ci 850f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 851f9f848faSopenharmony_ci * usb_close - cdev callback 852f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 853f9f848faSopenharmony_cistatic int 854f9f848faSopenharmony_ciusb_close(struct file *filep) 855f9f848faSopenharmony_ci{ 856f9f848faSopenharmony_ci struct usb_cdev_refdata refs; 857f9f848faSopenharmony_ci struct usb_cdev_privdata *cpd = (struct usb_cdev_privdata *)filep->f_priv; 858f9f848faSopenharmony_ci int err; 859f9f848faSopenharmony_ci 860f9f848faSopenharmony_ci DPRINTFN(2, "cpd=%p\n", cpd); 861f9f848faSopenharmony_ci 862f9f848faSopenharmony_ci err = usb_ref_device(cpd, &refs, 863f9f848faSopenharmony_ci 2 /* uref and allow detached state */); 864f9f848faSopenharmony_ci if (err) { 865f9f848faSopenharmony_ci DPRINTFN(2, "Cannot grab USB reference when " 866f9f848faSopenharmony_ci "closing USB file handle\n"); 867f9f848faSopenharmony_ci return (-ENXIO); 868f9f848faSopenharmony_ci } 869f9f848faSopenharmony_ci if ((unsigned int)cpd->fflags & FREAD) { 870f9f848faSopenharmony_ci usb_fifo_close(refs.rxfifo, cpd->fflags); 871f9f848faSopenharmony_ci } 872f9f848faSopenharmony_ci if ((unsigned int)cpd->fflags & FWRITE) { 873f9f848faSopenharmony_ci usb_fifo_close(refs.txfifo, cpd->fflags); 874f9f848faSopenharmony_ci } 875f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 876f9f848faSopenharmony_ci 877f9f848faSopenharmony_ci bsd_free(cpd, M_USBDEV); 878f9f848faSopenharmony_ci return (0); 879f9f848faSopenharmony_ci} 880f9f848faSopenharmony_ci 881f9f848faSopenharmony_civoid 882f9f848faSopenharmony_ciusb_dev_init(void *arg) 883f9f848faSopenharmony_ci{ 884f9f848faSopenharmony_ci int ret; 885f9f848faSopenharmony_ci mtx_init(&usb_ref_lock, "USB ref mutex", NULL, MTX_DEF); 886f9f848faSopenharmony_ci ret = mkdir(USB_DEVICE_DIR, DEFAULT_DIR_MODE); 887f9f848faSopenharmony_ci if (ret < 0) { 888f9f848faSopenharmony_ci usb_err("usb mkdir error! ret = %d, errono = %d\n", ret, get_errno()); 889f9f848faSopenharmony_ci } 890f9f848faSopenharmony_ci 891f9f848faSopenharmony_ci sx_init(&usb_sym_lock, "USB sym mutex"); 892f9f848faSopenharmony_ci TAILQ_INIT(&usb_sym_head); 893f9f848faSopenharmony_ci 894f9f848faSopenharmony_ci /* check the UGEN methods */ 895f9f848faSopenharmony_ci usb_fifo_check_methods(&usb_ugen_methods); 896f9f848faSopenharmony_ci} 897f9f848faSopenharmony_ci 898f9f848faSopenharmony_civoid 899f9f848faSopenharmony_ciusb_dev_uninit(void *arg) 900f9f848faSopenharmony_ci{ 901f9f848faSopenharmony_ci int ret; 902f9f848faSopenharmony_ci mtx_destroy(&usb_ref_lock); 903f9f848faSopenharmony_ci sx_destroy(&usb_sym_lock); 904f9f848faSopenharmony_ci ret = rmdir(USB_DEVICE_DIR); 905f9f848faSopenharmony_ci if (ret < 0) { 906f9f848faSopenharmony_ci usb_err("usb rmdir error! ret = %d, errono = %d\n", ret, get_errno()); 907f9f848faSopenharmony_ci } 908f9f848faSopenharmony_ci 909f9f848faSopenharmony_ci} 910f9f848faSopenharmony_ci 911f9f848faSopenharmony_cistatic int 912f9f848faSopenharmony_ciusb_ioctl_f_sub(struct usb_fifo *f, u_long cmd, const void *addr, 913f9f848faSopenharmony_ci struct thread *td) 914f9f848faSopenharmony_ci{ 915f9f848faSopenharmony_ci int error = 0; 916f9f848faSopenharmony_ci int data; 917f9f848faSopenharmony_ci 918f9f848faSopenharmony_ci switch (cmd) { 919f9f848faSopenharmony_ci case FIONBIO: 920f9f848faSopenharmony_ci /* handled by upper FS layer */ 921f9f848faSopenharmony_ci break; 922f9f848faSopenharmony_ci 923f9f848faSopenharmony_ci case FIOASYNC: 924f9f848faSopenharmony_ci error = copyin((const void *)addr, &data, sizeof(data)); 925f9f848faSopenharmony_ci if (data) { 926f9f848faSopenharmony_ci if (f->async_p != NULL) { 927f9f848faSopenharmony_ci error = EBUSY; 928f9f848faSopenharmony_ci break; 929f9f848faSopenharmony_ci } 930f9f848faSopenharmony_ci f->async_p = USB_TD_GET_PROC(td); 931f9f848faSopenharmony_ci } else { 932f9f848faSopenharmony_ci f->async_p = NULL; 933f9f848faSopenharmony_ci } 934f9f848faSopenharmony_ci break; 935f9f848faSopenharmony_ci 936f9f848faSopenharmony_ci /* XXX this is not the most general solution */ 937f9f848faSopenharmony_ci case TIOCSPGRP: 938f9f848faSopenharmony_ci if (f->async_p == NULL) { 939f9f848faSopenharmony_ci error = EINVAL; 940f9f848faSopenharmony_ci break; 941f9f848faSopenharmony_ci } 942f9f848faSopenharmony_ci error = copyin((const void *)addr, &data, sizeof(data)); 943f9f848faSopenharmony_ci if (data != USB_PROC_GET_GID(f->async_p)) { 944f9f848faSopenharmony_ci error = EPERM; 945f9f848faSopenharmony_ci break; 946f9f848faSopenharmony_ci } 947f9f848faSopenharmony_ci break; 948f9f848faSopenharmony_ci default: 949f9f848faSopenharmony_ci return (ENOIOCTL); 950f9f848faSopenharmony_ci } 951f9f848faSopenharmony_ci DPRINTFN(3, "cmd 0x%lx = %d\n", cmd, error); 952f9f848faSopenharmony_ci return (error); 953f9f848faSopenharmony_ci} 954f9f848faSopenharmony_ci 955f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 956f9f848faSopenharmony_ci * usb_ioctl - cdev callback 957f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 958f9f848faSopenharmony_cistatic int 959f9f848faSopenharmony_ciusb_ioctl(struct file *filep, int cmd, unsigned long arg) 960f9f848faSopenharmony_ci{ 961f9f848faSopenharmony_ci struct usb_cdev_refdata refs; 962f9f848faSopenharmony_ci struct usb_cdev_privdata *cpd = (struct usb_cdev_privdata *)filep->f_priv; 963f9f848faSopenharmony_ci struct usb_fifo *f = NULL; 964f9f848faSopenharmony_ci int fflags; 965f9f848faSopenharmony_ci int err; 966f9f848faSopenharmony_ci caddr_t addr = (caddr_t)(UINTPTR)arg; 967f9f848faSopenharmony_ci 968f9f848faSopenharmony_ci DPRINTFN(2, "cmd=0x%lx\n", cmd); 969f9f848faSopenharmony_ci 970f9f848faSopenharmony_ci /* 971f9f848faSopenharmony_ci * Performance optimisation: We try to check for IOCTL's that 972f9f848faSopenharmony_ci * don't need the USB reference first. Then we grab the USB 973f9f848faSopenharmony_ci * reference if we need it! 974f9f848faSopenharmony_ci */ 975f9f848faSopenharmony_ci err = usb_ref_device(cpd, &refs, 0 /* no uref */ ); 976f9f848faSopenharmony_ci if (err) 977f9f848faSopenharmony_ci return (-ENXIO); 978f9f848faSopenharmony_ci 979f9f848faSopenharmony_ci fflags = cpd->fflags; 980f9f848faSopenharmony_ci 981f9f848faSopenharmony_ci f = NULL; /* set default value */ 982f9f848faSopenharmony_ci err = ENOIOCTL; /* set default value */ 983f9f848faSopenharmony_ci 984f9f848faSopenharmony_ci if ((unsigned int)fflags & FWRITE) { 985f9f848faSopenharmony_ci f = refs.txfifo; 986f9f848faSopenharmony_ci err = usb_ioctl_f_sub(f, cmd, addr, NULL); 987f9f848faSopenharmony_ci } 988f9f848faSopenharmony_ci if ((unsigned int)fflags & FREAD) { 989f9f848faSopenharmony_ci f = refs.rxfifo; 990f9f848faSopenharmony_ci err = usb_ioctl_f_sub(f, cmd, addr, NULL); 991f9f848faSopenharmony_ci } 992f9f848faSopenharmony_ci KASSERT(f != NULL, ("fifo not found")); 993f9f848faSopenharmony_ci if (err != ENOIOCTL) 994f9f848faSopenharmony_ci goto done; 995f9f848faSopenharmony_ci 996f9f848faSopenharmony_ci err = (f->methods->f_ioctl) (f, cmd, addr, fflags); 997f9f848faSopenharmony_ci 998f9f848faSopenharmony_ci DPRINTFN(2, "f_ioctl cmd 0x%lx = %d\n", cmd, err); 999f9f848faSopenharmony_ci 1000f9f848faSopenharmony_ci if (err != ENOIOCTL) 1001f9f848faSopenharmony_ci goto done; 1002f9f848faSopenharmony_ci 1003f9f848faSopenharmony_ci if (usb_usb_ref_device(cpd, &refs)) { 1004f9f848faSopenharmony_ci /* we lost the reference */ 1005f9f848faSopenharmony_ci return (-ENXIO); 1006f9f848faSopenharmony_ci } 1007f9f848faSopenharmony_ci 1008f9f848faSopenharmony_ci err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags); 1009f9f848faSopenharmony_ci 1010f9f848faSopenharmony_ci DPRINTFN(2, "f_ioctl_post cmd 0x%lx = %d\n", cmd, err); 1011f9f848faSopenharmony_ci 1012f9f848faSopenharmony_ci if (err == ENOIOCTL) 1013f9f848faSopenharmony_ci err = ENOTTY; 1014f9f848faSopenharmony_ci 1015f9f848faSopenharmony_ci if (err) 1016f9f848faSopenharmony_ci goto done; 1017f9f848faSopenharmony_ci 1018f9f848faSopenharmony_ci /* Wait for re-enumeration, if any */ 1019f9f848faSopenharmony_ci 1020f9f848faSopenharmony_ci while (f->udev->re_enumerate_wait != USB_RE_ENUM_DONE) { 1021f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1022f9f848faSopenharmony_ci 1023f9f848faSopenharmony_ci usb_pause_mtx(NULL, hz / 128); 1024f9f848faSopenharmony_ci 1025f9f848faSopenharmony_ci while (usb_ref_device(cpd, &refs, 1 /* need uref */)) { 1026f9f848faSopenharmony_ci if (usb_ref_device(cpd, &refs, 0)) { 1027f9f848faSopenharmony_ci /* device no longer exists */ 1028f9f848faSopenharmony_ci return (-ENXIO); 1029f9f848faSopenharmony_ci } 1030f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1031f9f848faSopenharmony_ci usb_pause_mtx(NULL, hz / 128); 1032f9f848faSopenharmony_ci } 1033f9f848faSopenharmony_ci } 1034f9f848faSopenharmony_ci 1035f9f848faSopenharmony_cidone: 1036f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1037f9f848faSopenharmony_ci return (-err); 1038f9f848faSopenharmony_ci} 1039f9f848faSopenharmony_ci 1040f9f848faSopenharmony_ci/* ARGSUSED */ 1041f9f848faSopenharmony_cistatic int 1042f9f848faSopenharmony_ciusb_poll(struct file *filep, poll_table *fds) 1043f9f848faSopenharmony_ci{ 1044f9f848faSopenharmony_ci struct usb_cdev_refdata refs; 1045f9f848faSopenharmony_ci struct usb_cdev_privdata *cpd = (struct usb_cdev_privdata *)filep->f_priv; 1046f9f848faSopenharmony_ci struct usb_fifo *f = NULL; 1047f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1048f9f848faSopenharmony_ci int fflags, revents; 1049f9f848faSopenharmony_ci pollevent_t events = fds->key; 1050f9f848faSopenharmony_ci 1051f9f848faSopenharmony_ci if (usb_ref_device(cpd, &refs, 0) != 0) 1052f9f848faSopenharmony_ci return (events & 1053f9f848faSopenharmony_ci (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); 1054f9f848faSopenharmony_ci 1055f9f848faSopenharmony_ci fflags = cpd->fflags; 1056f9f848faSopenharmony_ci 1057f9f848faSopenharmony_ci /* Figure out who needs service */ 1058f9f848faSopenharmony_ci revents = 0; 1059f9f848faSopenharmony_ci if ((events & (POLLOUT | POLLWRNORM)) && 1060f9f848faSopenharmony_ci ((unsigned int)fflags & FWRITE)) { 1061f9f848faSopenharmony_ci f = refs.txfifo; 1062f9f848faSopenharmony_ci 1063f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 1064f9f848faSopenharmony_ci 1065f9f848faSopenharmony_ci if (!refs.is_usbfs) { 1066f9f848faSopenharmony_ci if (f->flag_iserror) { 1067f9f848faSopenharmony_ci /* we got an error */ 1068f9f848faSopenharmony_ci m = (void *)1; 1069f9f848faSopenharmony_ci } else { 1070f9f848faSopenharmony_ci if (f->queue_data == NULL) { 1071f9f848faSopenharmony_ci /* 1072f9f848faSopenharmony_ci * start write transfer, if not 1073f9f848faSopenharmony_ci * already started 1074f9f848faSopenharmony_ci */ 1075f9f848faSopenharmony_ci (f->methods->f_start_write) (f); 1076f9f848faSopenharmony_ci } 1077f9f848faSopenharmony_ci /* check if any packets are available */ 1078f9f848faSopenharmony_ci USB_IF_POLL(&f->free_q, m); 1079f9f848faSopenharmony_ci } 1080f9f848faSopenharmony_ci } else { 1081f9f848faSopenharmony_ci if (f->flag_iscomplete) { 1082f9f848faSopenharmony_ci m = (void *)1; 1083f9f848faSopenharmony_ci } else { 1084f9f848faSopenharmony_ci m = NULL; 1085f9f848faSopenharmony_ci } 1086f9f848faSopenharmony_ci } 1087f9f848faSopenharmony_ci 1088f9f848faSopenharmony_ci if (m) { 1089f9f848faSopenharmony_ci revents = (unsigned int)revents | (events & (POLLOUT | POLLWRNORM)); 1090f9f848faSopenharmony_ci } else { 1091f9f848faSopenharmony_ci f->flag_isselect = 1; 1092f9f848faSopenharmony_ci } 1093f9f848faSopenharmony_ci 1094f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 1095f9f848faSopenharmony_ci } 1096f9f848faSopenharmony_ci if ((events & (POLLIN | POLLRDNORM)) && 1097f9f848faSopenharmony_ci ((unsigned int)fflags & FREAD)) { 1098f9f848faSopenharmony_ci f = refs.rxfifo; 1099f9f848faSopenharmony_ci 1100f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 1101f9f848faSopenharmony_ci 1102f9f848faSopenharmony_ci if (!refs.is_usbfs) { 1103f9f848faSopenharmony_ci if (f->flag_iserror) { 1104f9f848faSopenharmony_ci /* we have an error */ 1105f9f848faSopenharmony_ci m = (void *)1; 1106f9f848faSopenharmony_ci } else { 1107f9f848faSopenharmony_ci if (f->queue_data == NULL) { 1108f9f848faSopenharmony_ci /* 1109f9f848faSopenharmony_ci * start read transfer, if not 1110f9f848faSopenharmony_ci * already started 1111f9f848faSopenharmony_ci */ 1112f9f848faSopenharmony_ci 1113f9f848faSopenharmony_ci (f->methods->f_start_read) (f); 1114f9f848faSopenharmony_ci } 1115f9f848faSopenharmony_ci 1116f9f848faSopenharmony_ci /* check if any packets are available */ 1117f9f848faSopenharmony_ci USB_IF_POLL(&f->used_q, m); 1118f9f848faSopenharmony_ci } 1119f9f848faSopenharmony_ci } else { 1120f9f848faSopenharmony_ci if (f->flag_iscomplete) { 1121f9f848faSopenharmony_ci m = (void *)1; 1122f9f848faSopenharmony_ci } else { 1123f9f848faSopenharmony_ci m = NULL; 1124f9f848faSopenharmony_ci } 1125f9f848faSopenharmony_ci } 1126f9f848faSopenharmony_ci 1127f9f848faSopenharmony_ci if (m) { 1128f9f848faSopenharmony_ci revents = (unsigned int)revents | (events & (POLLIN | POLLRDNORM)); 1129f9f848faSopenharmony_ci } else { 1130f9f848faSopenharmony_ci f->flag_isselect = 1; 1131f9f848faSopenharmony_ci 1132f9f848faSopenharmony_ci if (!refs.is_usbfs) { 1133f9f848faSopenharmony_ci 1134f9f848faSopenharmony_ci /* start reading data */ 1135f9f848faSopenharmony_ci (f->methods->f_start_read) (f); 1136f9f848faSopenharmony_ci } 1137f9f848faSopenharmony_ci } 1138f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 1139f9f848faSopenharmony_ci } 1140f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1141f9f848faSopenharmony_ci 1142f9f848faSopenharmony_ci return (revents); 1143f9f848faSopenharmony_ci} 1144f9f848faSopenharmony_ci 1145f9f848faSopenharmony_cistatic int 1146f9f848faSopenharmony_ciusb_read(struct file *filep, char *buffer, size_t buflen) 1147f9f848faSopenharmony_ci{ 1148f9f848faSopenharmony_ci struct usb_cdev_refdata refs; 1149f9f848faSopenharmony_ci struct usb_cdev_privdata *cpd = (struct usb_cdev_privdata *)filep->f_priv; 1150f9f848faSopenharmony_ci struct usb_fifo *f = NULL; 1151f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1152f9f848faSopenharmony_ci int resid; 1153f9f848faSopenharmony_ci int io_len; 1154f9f848faSopenharmony_ci int err; 1155f9f848faSopenharmony_ci 1156f9f848faSopenharmony_ci err = usb_ref_device(cpd, &refs, 0 /* no uref */ ); 1157f9f848faSopenharmony_ci if (err) 1158f9f848faSopenharmony_ci return (-ENXIO); 1159f9f848faSopenharmony_ci 1160f9f848faSopenharmony_ci f = refs.rxfifo; 1161f9f848faSopenharmony_ci if (f == NULL) { 1162f9f848faSopenharmony_ci /* should not happen */ 1163f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1164f9f848faSopenharmony_ci return (-EPERM); 1165f9f848faSopenharmony_ci } 1166f9f848faSopenharmony_ci 1167f9f848faSopenharmony_ci resid = buflen; 1168f9f848faSopenharmony_ci 1169f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 1170f9f848faSopenharmony_ci 1171f9f848faSopenharmony_ci /* check for permanent read error */ 1172f9f848faSopenharmony_ci if (f->flag_iserror) { 1173f9f848faSopenharmony_ci err = EIO; 1174f9f848faSopenharmony_ci goto done; 1175f9f848faSopenharmony_ci } 1176f9f848faSopenharmony_ci /* check if USB-FS interface is active */ 1177f9f848faSopenharmony_ci if (refs.is_usbfs) { 1178f9f848faSopenharmony_ci /* 1179f9f848faSopenharmony_ci * The queue is used for events that should be 1180f9f848faSopenharmony_ci * retrieved using the "USB_FS_COMPLETE" ioctl. 1181f9f848faSopenharmony_ci */ 1182f9f848faSopenharmony_ci err = EINVAL; 1183f9f848faSopenharmony_ci goto done; 1184f9f848faSopenharmony_ci } 1185f9f848faSopenharmony_ci 1186f9f848faSopenharmony_ci while (resid > 0) { 1187f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->used_q, m); 1188f9f848faSopenharmony_ci 1189f9f848faSopenharmony_ci if (m == NULL) { 1190f9f848faSopenharmony_ci /* start read transfer, if not already started */ 1191f9f848faSopenharmony_ci 1192f9f848faSopenharmony_ci (f->methods->f_start_read) (f); 1193f9f848faSopenharmony_ci 1194f9f848faSopenharmony_ci DPRINTF("sleeping\n"); 1195f9f848faSopenharmony_ci 1196f9f848faSopenharmony_ci err = usb_fifo_wait(f); 1197f9f848faSopenharmony_ci if (err) { 1198f9f848faSopenharmony_ci break; 1199f9f848faSopenharmony_ci } 1200f9f848faSopenharmony_ci continue; 1201f9f848faSopenharmony_ci } 1202f9f848faSopenharmony_ci if (f->methods->f_filter_read) { 1203f9f848faSopenharmony_ci /* 1204f9f848faSopenharmony_ci * Sometimes it is convenient to process data at the 1205f9f848faSopenharmony_ci * expense of a userland process instead of a kernel 1206f9f848faSopenharmony_ci * process. 1207f9f848faSopenharmony_ci */ 1208f9f848faSopenharmony_ci (f->methods->f_filter_read) (f, m); 1209f9f848faSopenharmony_ci } 1210f9f848faSopenharmony_ci 1211f9f848faSopenharmony_ci io_len = MIN(m->cur_data_len, resid); 1212f9f848faSopenharmony_ci 1213f9f848faSopenharmony_ci DPRINTFN(2, "transfer %d bytes from %p\n", 1214f9f848faSopenharmony_ci io_len, m->cur_data_ptr); 1215f9f848faSopenharmony_ci 1216f9f848faSopenharmony_ci err = copyout((const void *)m->cur_data_ptr, buffer, io_len); 1217f9f848faSopenharmony_ci if (err) { 1218f9f848faSopenharmony_ci break; 1219f9f848faSopenharmony_ci } 1220f9f848faSopenharmony_ci 1221f9f848faSopenharmony_ci m->cur_data_len -= io_len; 1222f9f848faSopenharmony_ci m->cur_data_ptr += io_len; 1223f9f848faSopenharmony_ci 1224f9f848faSopenharmony_ci if (m->cur_data_len == 0) { 1225f9f848faSopenharmony_ci uint8_t last_packet; 1226f9f848faSopenharmony_ci 1227f9f848faSopenharmony_ci last_packet = m->last_packet; 1228f9f848faSopenharmony_ci 1229f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->free_q, m); 1230f9f848faSopenharmony_ci 1231f9f848faSopenharmony_ci if (last_packet) { 1232f9f848faSopenharmony_ci /* keep framing */ 1233f9f848faSopenharmony_ci break; 1234f9f848faSopenharmony_ci } 1235f9f848faSopenharmony_ci } else { 1236f9f848faSopenharmony_ci USB_IF_PREPEND(&f->used_q, m); 1237f9f848faSopenharmony_ci } 1238f9f848faSopenharmony_ci 1239f9f848faSopenharmony_ci if (err) { 1240f9f848faSopenharmony_ci break; 1241f9f848faSopenharmony_ci } 1242f9f848faSopenharmony_ci resid -= io_len; 1243f9f848faSopenharmony_ci } 1244f9f848faSopenharmony_cidone: 1245f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 1246f9f848faSopenharmony_ci 1247f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1248f9f848faSopenharmony_ci 1249f9f848faSopenharmony_ci return (-err); 1250f9f848faSopenharmony_ci} 1251f9f848faSopenharmony_ci 1252f9f848faSopenharmony_cistatic int 1253f9f848faSopenharmony_ciusb_write(struct file *filep, const char *buffer, size_t buflen) 1254f9f848faSopenharmony_ci{ 1255f9f848faSopenharmony_ci struct usb_cdev_refdata refs; 1256f9f848faSopenharmony_ci struct usb_cdev_privdata *cpd = (struct usb_cdev_privdata *)filep->f_priv; 1257f9f848faSopenharmony_ci struct usb_fifo *f = NULL; 1258f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1259f9f848faSopenharmony_ci uint8_t *pdata = NULL; 1260f9f848faSopenharmony_ci int resid; 1261f9f848faSopenharmony_ci int io_len; 1262f9f848faSopenharmony_ci int err; 1263f9f848faSopenharmony_ci 1264f9f848faSopenharmony_ci DPRINTFN(2, "\n"); 1265f9f848faSopenharmony_ci 1266f9f848faSopenharmony_ci err = usb_ref_device(cpd, &refs, 0 /* no uref */ ); 1267f9f848faSopenharmony_ci if (err) 1268f9f848faSopenharmony_ci return (-ENXIO); 1269f9f848faSopenharmony_ci 1270f9f848faSopenharmony_ci f = refs.txfifo; 1271f9f848faSopenharmony_ci if (f == NULL) { 1272f9f848faSopenharmony_ci /* should not happen */ 1273f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1274f9f848faSopenharmony_ci return (-EPERM); 1275f9f848faSopenharmony_ci } 1276f9f848faSopenharmony_ci 1277f9f848faSopenharmony_ci resid = buflen; 1278f9f848faSopenharmony_ci 1279f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 1280f9f848faSopenharmony_ci 1281f9f848faSopenharmony_ci /* check for permanent write error */ 1282f9f848faSopenharmony_ci if (f->flag_iserror) { 1283f9f848faSopenharmony_ci err = EIO; 1284f9f848faSopenharmony_ci goto done; 1285f9f848faSopenharmony_ci } 1286f9f848faSopenharmony_ci /* check if USB-FS interface is active */ 1287f9f848faSopenharmony_ci if (refs.is_usbfs) { 1288f9f848faSopenharmony_ci /* 1289f9f848faSopenharmony_ci * The queue is used for events that should be 1290f9f848faSopenharmony_ci * retrieved using the "USB_FS_COMPLETE" ioctl. 1291f9f848faSopenharmony_ci */ 1292f9f848faSopenharmony_ci err = EINVAL; 1293f9f848faSopenharmony_ci goto done; 1294f9f848faSopenharmony_ci } 1295f9f848faSopenharmony_ci if (f->queue_data == NULL) { 1296f9f848faSopenharmony_ci /* start write transfer, if not already started */ 1297f9f848faSopenharmony_ci (f->methods->f_start_write) (f); 1298f9f848faSopenharmony_ci } 1299f9f848faSopenharmony_ci /* we allow writing zero length data */ 1300f9f848faSopenharmony_ci do { 1301f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->free_q, m); 1302f9f848faSopenharmony_ci 1303f9f848faSopenharmony_ci if (m == NULL) { 1304f9f848faSopenharmony_ci DPRINTF("sleeping\n"); 1305f9f848faSopenharmony_ci 1306f9f848faSopenharmony_ci err = usb_fifo_wait(f); 1307f9f848faSopenharmony_ci if (err) { 1308f9f848faSopenharmony_ci break; 1309f9f848faSopenharmony_ci } 1310f9f848faSopenharmony_ci continue; 1311f9f848faSopenharmony_ci } 1312f9f848faSopenharmony_ci 1313f9f848faSopenharmony_ci if (f->flag_have_fragment == 0) { 1314f9f848faSopenharmony_ci USB_MBUF_RESET(m); 1315f9f848faSopenharmony_ci io_len = m->cur_data_len; 1316f9f848faSopenharmony_ci pdata = m->cur_data_ptr; 1317f9f848faSopenharmony_ci if (io_len > resid) 1318f9f848faSopenharmony_ci io_len = resid; 1319f9f848faSopenharmony_ci m->cur_data_len = io_len; 1320f9f848faSopenharmony_ci } else { 1321f9f848faSopenharmony_ci io_len = m->max_data_len - m->cur_data_len; 1322f9f848faSopenharmony_ci pdata = m->cur_data_ptr + m->cur_data_len; 1323f9f848faSopenharmony_ci if (io_len > resid) 1324f9f848faSopenharmony_ci io_len = resid; 1325f9f848faSopenharmony_ci m->cur_data_len += io_len; 1326f9f848faSopenharmony_ci } 1327f9f848faSopenharmony_ci 1328f9f848faSopenharmony_ci DPRINTFN(2, "transfer %d bytes to %p\n", 1329f9f848faSopenharmony_ci io_len, pdata); 1330f9f848faSopenharmony_ci 1331f9f848faSopenharmony_ci err = copyin(buffer, pdata, io_len); 1332f9f848faSopenharmony_ci if (err) { 1333f9f848faSopenharmony_ci f->flag_have_fragment = 0; 1334f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->free_q, m); 1335f9f848faSopenharmony_ci break; 1336f9f848faSopenharmony_ci } 1337f9f848faSopenharmony_ci 1338f9f848faSopenharmony_ci /* check if the buffer is ready to be transmitted */ 1339f9f848faSopenharmony_ci 1340f9f848faSopenharmony_ci if ((f->flag_write_defrag == 0) || 1341f9f848faSopenharmony_ci (m->cur_data_len == m->max_data_len)) { 1342f9f848faSopenharmony_ci f->flag_have_fragment = 0; 1343f9f848faSopenharmony_ci 1344f9f848faSopenharmony_ci /* 1345f9f848faSopenharmony_ci * Check for write filter: 1346f9f848faSopenharmony_ci * 1347f9f848faSopenharmony_ci * Sometimes it is convenient to process data 1348f9f848faSopenharmony_ci * at the expense of a userland process 1349f9f848faSopenharmony_ci * instead of a kernel process. 1350f9f848faSopenharmony_ci */ 1351f9f848faSopenharmony_ci if (f->methods->f_filter_write) { 1352f9f848faSopenharmony_ci (f->methods->f_filter_write) (f, m); 1353f9f848faSopenharmony_ci } 1354f9f848faSopenharmony_ci 1355f9f848faSopenharmony_ci /* Put USB mbuf in the used queue */ 1356f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->used_q, m); 1357f9f848faSopenharmony_ci 1358f9f848faSopenharmony_ci /* Start writing data, if not already started */ 1359f9f848faSopenharmony_ci (f->methods->f_start_write) (f); 1360f9f848faSopenharmony_ci } else { 1361f9f848faSopenharmony_ci /* Wait for more data or close */ 1362f9f848faSopenharmony_ci f->flag_have_fragment = 1; 1363f9f848faSopenharmony_ci USB_IF_PREPEND(&f->free_q, m); 1364f9f848faSopenharmony_ci } 1365f9f848faSopenharmony_ci resid -= io_len; 1366f9f848faSopenharmony_ci } while (resid > 0); 1367f9f848faSopenharmony_cidone: 1368f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 1369f9f848faSopenharmony_ci 1370f9f848faSopenharmony_ci usb_unref_device(cpd, &refs); 1371f9f848faSopenharmony_ci 1372f9f848faSopenharmony_ci return (-err); 1373f9f848faSopenharmony_ci} 1374f9f848faSopenharmony_ci 1375f9f848faSopenharmony_ciint 1376f9f848faSopenharmony_ciusb_fifo_wait(struct usb_fifo *f) 1377f9f848faSopenharmony_ci{ 1378f9f848faSopenharmony_ci int err; 1379f9f848faSopenharmony_ci 1380f9f848faSopenharmony_ci mtx_assert(f->priv_mtx, MA_OWNED); 1381f9f848faSopenharmony_ci 1382f9f848faSopenharmony_ci if (f->flag_iserror) { 1383f9f848faSopenharmony_ci /* we are gone */ 1384f9f848faSopenharmony_ci return (EIO); 1385f9f848faSopenharmony_ci } 1386f9f848faSopenharmony_ci f->flag_sleeping = 1; 1387f9f848faSopenharmony_ci 1388f9f848faSopenharmony_ci err = cv_wait(&f->cv_io, f->priv_mtx); 1389f9f848faSopenharmony_ci 1390f9f848faSopenharmony_ci if (f->flag_iserror) { 1391f9f848faSopenharmony_ci /* we are gone */ 1392f9f848faSopenharmony_ci err = EIO; 1393f9f848faSopenharmony_ci } 1394f9f848faSopenharmony_ci return (err); 1395f9f848faSopenharmony_ci} 1396f9f848faSopenharmony_ci 1397f9f848faSopenharmony_civoid 1398f9f848faSopenharmony_ciusb_fifo_signal(struct usb_fifo *f) 1399f9f848faSopenharmony_ci{ 1400f9f848faSopenharmony_ci if (f->flag_sleeping) { 1401f9f848faSopenharmony_ci f->flag_sleeping = 0; 1402f9f848faSopenharmony_ci cv_broadcast(&f->cv_io); 1403f9f848faSopenharmony_ci } 1404f9f848faSopenharmony_ci} 1405f9f848faSopenharmony_ci 1406f9f848faSopenharmony_civoid 1407f9f848faSopenharmony_ciusb_fifo_wakeup(struct usb_fifo *f) 1408f9f848faSopenharmony_ci{ 1409f9f848faSopenharmony_ci usb_fifo_signal(f); 1410f9f848faSopenharmony_ci} 1411f9f848faSopenharmony_ci 1412f9f848faSopenharmony_cistatic int 1413f9f848faSopenharmony_ciusb_fifo_dummy_open(struct usb_fifo *fifo, int fflags) 1414f9f848faSopenharmony_ci{ 1415f9f848faSopenharmony_ci return (0); 1416f9f848faSopenharmony_ci} 1417f9f848faSopenharmony_ci 1418f9f848faSopenharmony_cistatic void 1419f9f848faSopenharmony_ciusb_fifo_dummy_close(struct usb_fifo *fifo, int fflags) 1420f9f848faSopenharmony_ci{ 1421f9f848faSopenharmony_ci return; 1422f9f848faSopenharmony_ci} 1423f9f848faSopenharmony_ci 1424f9f848faSopenharmony_cistatic int 1425f9f848faSopenharmony_ciusb_fifo_dummy_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) 1426f9f848faSopenharmony_ci{ 1427f9f848faSopenharmony_ci return (ENOIOCTL); 1428f9f848faSopenharmony_ci} 1429f9f848faSopenharmony_ci 1430f9f848faSopenharmony_cistatic void 1431f9f848faSopenharmony_ciusb_fifo_dummy_cmd(struct usb_fifo *fifo) 1432f9f848faSopenharmony_ci{ 1433f9f848faSopenharmony_ci fifo->flag_flushing = 0; /* not flushing */ 1434f9f848faSopenharmony_ci} 1435f9f848faSopenharmony_ci 1436f9f848faSopenharmony_cistatic void 1437f9f848faSopenharmony_ciusb_fifo_check_methods(struct usb_fifo_methods *pm) 1438f9f848faSopenharmony_ci{ 1439f9f848faSopenharmony_ci /* check that all callback functions are OK */ 1440f9f848faSopenharmony_ci 1441f9f848faSopenharmony_ci if (pm->f_open == NULL) 1442f9f848faSopenharmony_ci pm->f_open = &usb_fifo_dummy_open; 1443f9f848faSopenharmony_ci 1444f9f848faSopenharmony_ci if (pm->f_close == NULL) 1445f9f848faSopenharmony_ci pm->f_close = &usb_fifo_dummy_close; 1446f9f848faSopenharmony_ci 1447f9f848faSopenharmony_ci if (pm->f_ioctl == NULL) 1448f9f848faSopenharmony_ci pm->f_ioctl = &usb_fifo_dummy_ioctl; 1449f9f848faSopenharmony_ci 1450f9f848faSopenharmony_ci if (pm->f_ioctl_post == NULL) 1451f9f848faSopenharmony_ci pm->f_ioctl_post = &usb_fifo_dummy_ioctl; 1452f9f848faSopenharmony_ci 1453f9f848faSopenharmony_ci if (pm->f_start_read == NULL) 1454f9f848faSopenharmony_ci pm->f_start_read = &usb_fifo_dummy_cmd; 1455f9f848faSopenharmony_ci 1456f9f848faSopenharmony_ci if (pm->f_stop_read == NULL) 1457f9f848faSopenharmony_ci pm->f_stop_read = &usb_fifo_dummy_cmd; 1458f9f848faSopenharmony_ci 1459f9f848faSopenharmony_ci if (pm->f_start_write == NULL) 1460f9f848faSopenharmony_ci pm->f_start_write = &usb_fifo_dummy_cmd; 1461f9f848faSopenharmony_ci 1462f9f848faSopenharmony_ci if (pm->f_stop_write == NULL) 1463f9f848faSopenharmony_ci pm->f_stop_write = &usb_fifo_dummy_cmd; 1464f9f848faSopenharmony_ci} 1465f9f848faSopenharmony_ci 1466f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1467f9f848faSopenharmony_ci * usb_fifo_attach 1468f9f848faSopenharmony_ci * 1469f9f848faSopenharmony_ci * The following function will create a duplex FIFO. 1470f9f848faSopenharmony_ci * 1471f9f848faSopenharmony_ci * Return values: 1472f9f848faSopenharmony_ci * 0: Success. 1473f9f848faSopenharmony_ci * Else: Failure. 1474f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1475f9f848faSopenharmony_ciint 1476f9f848faSopenharmony_ciusb_fifo_attach(struct usb_device *udev, void *priv_sc, 1477f9f848faSopenharmony_ci struct mtx *priv_mtx, struct usb_fifo_methods *pm, 1478f9f848faSopenharmony_ci struct usb_fifo_sc *f_sc, uint16_t unit, int16_t subunit, 1479f9f848faSopenharmony_ci uint8_t iface_index, uid_t uid, gid_t gid, int mode) 1480f9f848faSopenharmony_ci{ 1481f9f848faSopenharmony_ci struct usb_fifo *f_tx = NULL; 1482f9f848faSopenharmony_ci struct usb_fifo *f_rx = NULL; 1483f9f848faSopenharmony_ci char devname[32]; 1484f9f848faSopenharmony_ci uint8_t n; 1485f9f848faSopenharmony_ci 1486f9f848faSopenharmony_ci f_sc->fp[USB_FIFO_TX] = NULL; 1487f9f848faSopenharmony_ci f_sc->fp[USB_FIFO_RX] = NULL; 1488f9f848faSopenharmony_ci 1489f9f848faSopenharmony_ci if (pm == NULL) 1490f9f848faSopenharmony_ci return (EINVAL); 1491f9f848faSopenharmony_ci 1492f9f848faSopenharmony_ci /* check the methods */ 1493f9f848faSopenharmony_ci usb_fifo_check_methods(pm); 1494f9f848faSopenharmony_ci 1495f9f848faSopenharmony_ci if (priv_mtx == NULL) 1496f9f848faSopenharmony_ci priv_mtx = &Giant; 1497f9f848faSopenharmony_ci 1498f9f848faSopenharmony_ci /* search for a free FIFO slot */ 1499f9f848faSopenharmony_ci for (n = 0;; n += 2) { 1500f9f848faSopenharmony_ci if (n == USB_FIFO_MAX) { 1501f9f848faSopenharmony_ci /* end of FIFOs reached */ 1502f9f848faSopenharmony_ci return (ENOMEM); 1503f9f848faSopenharmony_ci } 1504f9f848faSopenharmony_ci /* Check for TX FIFO */ 1505f9f848faSopenharmony_ci if (udev->fifo[n + USB_FIFO_TX] != NULL) { 1506f9f848faSopenharmony_ci continue; 1507f9f848faSopenharmony_ci } 1508f9f848faSopenharmony_ci /* Check for RX FIFO */ 1509f9f848faSopenharmony_ci if (udev->fifo[n + USB_FIFO_RX] != NULL) { 1510f9f848faSopenharmony_ci continue; 1511f9f848faSopenharmony_ci } 1512f9f848faSopenharmony_ci break; 1513f9f848faSopenharmony_ci } 1514f9f848faSopenharmony_ci 1515f9f848faSopenharmony_ci f_tx = usb_fifo_alloc(priv_mtx); 1516f9f848faSopenharmony_ci f_rx = usb_fifo_alloc(priv_mtx); 1517f9f848faSopenharmony_ci 1518f9f848faSopenharmony_ci if ((f_tx == NULL) || (f_rx == NULL)) { 1519f9f848faSopenharmony_ci usb_fifo_free(f_tx); 1520f9f848faSopenharmony_ci usb_fifo_free(f_rx); 1521f9f848faSopenharmony_ci return (ENOMEM); 1522f9f848faSopenharmony_ci } 1523f9f848faSopenharmony_ci /* initialise FIFO structures */ 1524f9f848faSopenharmony_ci 1525f9f848faSopenharmony_ci f_tx->fifo_index = n + USB_FIFO_TX; 1526f9f848faSopenharmony_ci f_tx->dev_ep_index = -1; 1527f9f848faSopenharmony_ci f_tx->priv_sc0 = priv_sc; 1528f9f848faSopenharmony_ci f_tx->methods = pm; 1529f9f848faSopenharmony_ci f_tx->iface_index = iface_index; 1530f9f848faSopenharmony_ci f_tx->udev = udev; 1531f9f848faSopenharmony_ci 1532f9f848faSopenharmony_ci f_rx->fifo_index = n + USB_FIFO_RX; 1533f9f848faSopenharmony_ci f_rx->dev_ep_index = -1; 1534f9f848faSopenharmony_ci f_rx->priv_sc0 = priv_sc; 1535f9f848faSopenharmony_ci f_rx->methods = pm; 1536f9f848faSopenharmony_ci f_rx->iface_index = iface_index; 1537f9f848faSopenharmony_ci f_rx->udev = udev; 1538f9f848faSopenharmony_ci 1539f9f848faSopenharmony_ci f_sc->fp[USB_FIFO_TX] = f_tx; 1540f9f848faSopenharmony_ci f_sc->fp[USB_FIFO_RX] = f_rx; 1541f9f848faSopenharmony_ci 1542f9f848faSopenharmony_ci mtx_lock(&usb_ref_lock); 1543f9f848faSopenharmony_ci udev->fifo[f_tx->fifo_index] = f_tx; 1544f9f848faSopenharmony_ci udev->fifo[f_rx->fifo_index] = f_rx; 1545f9f848faSopenharmony_ci mtx_unlock(&usb_ref_lock); 1546f9f848faSopenharmony_ci 1547f9f848faSopenharmony_ci for (n = 0; n != 4; n++) { 1548f9f848faSopenharmony_ci if (pm->basename[n] == NULL) { 1549f9f848faSopenharmony_ci continue; 1550f9f848faSopenharmony_ci } 1551f9f848faSopenharmony_ci if (subunit < 0) { 1552f9f848faSopenharmony_ci if (snprintf_s(devname, sizeof(devname), sizeof(devname) - 1, 1553f9f848faSopenharmony_ci "%s%u%s", pm->basename[n], 1554f9f848faSopenharmony_ci unit, pm->postfix[n] ? 1555f9f848faSopenharmony_ci pm->postfix[n] : "")) { 1556f9f848faSopenharmony_ci /* ignore */ 1557f9f848faSopenharmony_ci } 1558f9f848faSopenharmony_ci } else { 1559f9f848faSopenharmony_ci if (snprintf_s(devname, sizeof(devname), sizeof(devname) - 1, 1560f9f848faSopenharmony_ci "%s%u.%d%s", pm->basename[n], 1561f9f848faSopenharmony_ci unit, subunit, pm->postfix[n] ? 1562f9f848faSopenharmony_ci pm->postfix[n] : "")) { 1563f9f848faSopenharmony_ci /* ignore */ 1564f9f848faSopenharmony_ci } 1565f9f848faSopenharmony_ci } 1566f9f848faSopenharmony_ci 1567f9f848faSopenharmony_ci /* 1568f9f848faSopenharmony_ci * Distribute the symbolic links into two FIFO structures: 1569f9f848faSopenharmony_ci */ 1570f9f848faSopenharmony_ci if (n & 1) { 1571f9f848faSopenharmony_ci f_rx->symlink[n / 2] = 1572f9f848faSopenharmony_ci usb_alloc_symlink(devname); 1573f9f848faSopenharmony_ci } else { 1574f9f848faSopenharmony_ci f_tx->symlink[n / 2] = 1575f9f848faSopenharmony_ci usb_alloc_symlink(devname); 1576f9f848faSopenharmony_ci } 1577f9f848faSopenharmony_ci 1578f9f848faSopenharmony_ci /* Create the device */ 1579f9f848faSopenharmony_ci f_sc->dev = usb_make_dev(udev, devname, -1, 1580f9f848faSopenharmony_ci f_tx->fifo_index & f_rx->fifo_index, 1581f9f848faSopenharmony_ci FREAD|FWRITE, uid, gid, mode); 1582f9f848faSopenharmony_ci } 1583f9f848faSopenharmony_ci 1584f9f848faSopenharmony_ci DPRINTFN(2, "attached %p/%p\n", f_tx, f_rx); 1585f9f848faSopenharmony_ci return (0); 1586f9f848faSopenharmony_ci} 1587f9f848faSopenharmony_ci 1588f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1589f9f848faSopenharmony_ci * usb_fifo_alloc_buffer 1590f9f848faSopenharmony_ci * 1591f9f848faSopenharmony_ci * Return values: 1592f9f848faSopenharmony_ci * 0: Success 1593f9f848faSopenharmony_ci * Else failure 1594f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1595f9f848faSopenharmony_ciint 1596f9f848faSopenharmony_ciusb_fifo_alloc_buffer(struct usb_fifo *f, usb_size_t bufsize, 1597f9f848faSopenharmony_ci uint16_t nbuf) 1598f9f848faSopenharmony_ci{ 1599f9f848faSopenharmony_ci struct usb_ifqueue temp_q = {}; 1600f9f848faSopenharmony_ci void *queue_data; 1601f9f848faSopenharmony_ci 1602f9f848faSopenharmony_ci usb_fifo_free_buffer(f); 1603f9f848faSopenharmony_ci 1604f9f848faSopenharmony_ci temp_q.ifq_maxlen = nbuf; 1605f9f848faSopenharmony_ci 1606f9f848faSopenharmony_ci queue_data = usb_alloc_mbufs( 1607f9f848faSopenharmony_ci M_USBDEV, &temp_q, bufsize, nbuf); 1608f9f848faSopenharmony_ci 1609f9f848faSopenharmony_ci if (queue_data == NULL && bufsize != 0 && nbuf != 0) 1610f9f848faSopenharmony_ci return (ENOMEM); 1611f9f848faSopenharmony_ci 1612f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 1613f9f848faSopenharmony_ci 1614f9f848faSopenharmony_ci /* 1615f9f848faSopenharmony_ci * Setup queues and sizes under lock to avoid early use by 1616f9f848faSopenharmony_ci * concurrent FIFO access: 1617f9f848faSopenharmony_ci */ 1618f9f848faSopenharmony_ci f->free_q = temp_q; 1619f9f848faSopenharmony_ci f->used_q.ifq_maxlen = nbuf; 1620f9f848faSopenharmony_ci f->queue_data = queue_data; 1621f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 1622f9f848faSopenharmony_ci 1623f9f848faSopenharmony_ci return (0); /* success */ 1624f9f848faSopenharmony_ci} 1625f9f848faSopenharmony_ci 1626f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1627f9f848faSopenharmony_ci * usb_fifo_free_buffer 1628f9f848faSopenharmony_ci * 1629f9f848faSopenharmony_ci * This function will free the buffers associated with a FIFO. This 1630f9f848faSopenharmony_ci * function can be called multiple times in a row. 1631f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1632f9f848faSopenharmony_civoid 1633f9f848faSopenharmony_ciusb_fifo_free_buffer(struct usb_fifo *f) 1634f9f848faSopenharmony_ci{ 1635f9f848faSopenharmony_ci void *queue_data; 1636f9f848faSopenharmony_ci 1637f9f848faSopenharmony_ci mtx_lock(f->priv_mtx); 1638f9f848faSopenharmony_ci 1639f9f848faSopenharmony_ci /* Get and clear pointer to free, if any. */ 1640f9f848faSopenharmony_ci queue_data = f->queue_data; 1641f9f848faSopenharmony_ci f->queue_data = NULL; 1642f9f848faSopenharmony_ci 1643f9f848faSopenharmony_ci /* 1644f9f848faSopenharmony_ci * Reset queues under lock to avoid use of freed buffers by 1645f9f848faSopenharmony_ci * concurrent FIFO activity: 1646f9f848faSopenharmony_ci */ 1647f9f848faSopenharmony_ci memset(&f->free_q, 0, sizeof(f->free_q)); 1648f9f848faSopenharmony_ci memset(&f->used_q, 0, sizeof(f->used_q)); 1649f9f848faSopenharmony_ci mtx_unlock(f->priv_mtx); 1650f9f848faSopenharmony_ci 1651f9f848faSopenharmony_ci /* Free old buffer, if any. */ 1652f9f848faSopenharmony_ci bsd_free(queue_data, M_USBDEV); 1653f9f848faSopenharmony_ci} 1654f9f848faSopenharmony_ci 1655f9f848faSopenharmony_civoid 1656f9f848faSopenharmony_ciusb_fifo_detach(struct usb_fifo_sc *f_sc) 1657f9f848faSopenharmony_ci{ 1658f9f848faSopenharmony_ci if (f_sc == NULL) { 1659f9f848faSopenharmony_ci return; 1660f9f848faSopenharmony_ci } 1661f9f848faSopenharmony_ci usb_fifo_free(f_sc->fp[USB_FIFO_TX]); 1662f9f848faSopenharmony_ci usb_fifo_free(f_sc->fp[USB_FIFO_RX]); 1663f9f848faSopenharmony_ci 1664f9f848faSopenharmony_ci f_sc->fp[USB_FIFO_TX] = NULL; 1665f9f848faSopenharmony_ci f_sc->fp[USB_FIFO_RX] = NULL; 1666f9f848faSopenharmony_ci 1667f9f848faSopenharmony_ci usb_destroy_dev(f_sc->dev); 1668f9f848faSopenharmony_ci 1669f9f848faSopenharmony_ci f_sc->dev = NULL; 1670f9f848faSopenharmony_ci 1671f9f848faSopenharmony_ci DPRINTFN(2, "detached %p\n", f_sc); 1672f9f848faSopenharmony_ci} 1673f9f848faSopenharmony_ci 1674f9f848faSopenharmony_ciusb_size_t 1675f9f848faSopenharmony_ciusb_fifo_put_bytes_max(struct usb_fifo *f) 1676f9f848faSopenharmony_ci{ 1677f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1678f9f848faSopenharmony_ci usb_size_t len; 1679f9f848faSopenharmony_ci 1680f9f848faSopenharmony_ci USB_IF_POLL(&f->free_q, m); 1681f9f848faSopenharmony_ci 1682f9f848faSopenharmony_ci if (m) { 1683f9f848faSopenharmony_ci len = m->max_data_len; 1684f9f848faSopenharmony_ci } else { 1685f9f848faSopenharmony_ci len = 0; 1686f9f848faSopenharmony_ci } 1687f9f848faSopenharmony_ci return (len); 1688f9f848faSopenharmony_ci} 1689f9f848faSopenharmony_ci 1690f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1691f9f848faSopenharmony_ci * usb_fifo_put_data 1692f9f848faSopenharmony_ci * 1693f9f848faSopenharmony_ci * what: 1694f9f848faSopenharmony_ci * 0 - normal operation 1695f9f848faSopenharmony_ci * 1 - set last packet flag to enforce framing 1696f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1697f9f848faSopenharmony_civoid 1698f9f848faSopenharmony_ciusb_fifo_put_data(struct usb_fifo *f, struct usb_page_cache *pc, 1699f9f848faSopenharmony_ci usb_frlength_t offset, usb_frlength_t len, uint8_t what) 1700f9f848faSopenharmony_ci{ 1701f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1702f9f848faSopenharmony_ci usb_frlength_t io_len; 1703f9f848faSopenharmony_ci 1704f9f848faSopenharmony_ci while (len || (what == 1)) { 1705f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->free_q, m); 1706f9f848faSopenharmony_ci 1707f9f848faSopenharmony_ci if (m) { 1708f9f848faSopenharmony_ci USB_MBUF_RESET(m); 1709f9f848faSopenharmony_ci 1710f9f848faSopenharmony_ci io_len = MIN(len, m->cur_data_len); 1711f9f848faSopenharmony_ci 1712f9f848faSopenharmony_ci usbd_copy_out(pc, offset, m->cur_data_ptr, io_len); 1713f9f848faSopenharmony_ci 1714f9f848faSopenharmony_ci m->cur_data_len = io_len; 1715f9f848faSopenharmony_ci offset += io_len; 1716f9f848faSopenharmony_ci len -= io_len; 1717f9f848faSopenharmony_ci 1718f9f848faSopenharmony_ci if ((len == 0) && (what == 1)) { 1719f9f848faSopenharmony_ci m->last_packet = 1; 1720f9f848faSopenharmony_ci } 1721f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->used_q, m); 1722f9f848faSopenharmony_ci 1723f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1724f9f848faSopenharmony_ci 1725f9f848faSopenharmony_ci if ((len == 0) || (what == 1)) { 1726f9f848faSopenharmony_ci break; 1727f9f848faSopenharmony_ci } 1728f9f848faSopenharmony_ci } else { 1729f9f848faSopenharmony_ci break; 1730f9f848faSopenharmony_ci } 1731f9f848faSopenharmony_ci } 1732f9f848faSopenharmony_ci} 1733f9f848faSopenharmony_ci 1734f9f848faSopenharmony_civoid 1735f9f848faSopenharmony_ciusb_fifo_put_data_linear(struct usb_fifo *f, void *ptr, 1736f9f848faSopenharmony_ci usb_size_t len, uint8_t what) 1737f9f848faSopenharmony_ci{ 1738f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1739f9f848faSopenharmony_ci usb_size_t io_len; 1740f9f848faSopenharmony_ci int error; 1741f9f848faSopenharmony_ci 1742f9f848faSopenharmony_ci while (len || (what == 1)) { 1743f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->free_q, m); 1744f9f848faSopenharmony_ci 1745f9f848faSopenharmony_ci if (m) { 1746f9f848faSopenharmony_ci USB_MBUF_RESET(m); 1747f9f848faSopenharmony_ci 1748f9f848faSopenharmony_ci io_len = MIN(len, m->cur_data_len); 1749f9f848faSopenharmony_ci 1750f9f848faSopenharmony_ci error = memcpy_s(m->cur_data_ptr, io_len, ptr, io_len); 1751f9f848faSopenharmony_ci if (error != EOK) { 1752f9f848faSopenharmony_ci break; 1753f9f848faSopenharmony_ci } 1754f9f848faSopenharmony_ci 1755f9f848faSopenharmony_ci m->cur_data_len = io_len; 1756f9f848faSopenharmony_ci ptr = USB_ADD_BYTES(ptr, io_len); 1757f9f848faSopenharmony_ci len -= io_len; 1758f9f848faSopenharmony_ci 1759f9f848faSopenharmony_ci if ((len == 0) && (what == 1)) { 1760f9f848faSopenharmony_ci m->last_packet = 1; 1761f9f848faSopenharmony_ci } 1762f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->used_q, m); 1763f9f848faSopenharmony_ci 1764f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1765f9f848faSopenharmony_ci 1766f9f848faSopenharmony_ci if ((len == 0) || (what == 1)) { 1767f9f848faSopenharmony_ci break; 1768f9f848faSopenharmony_ci } 1769f9f848faSopenharmony_ci } else { 1770f9f848faSopenharmony_ci break; 1771f9f848faSopenharmony_ci } 1772f9f848faSopenharmony_ci } 1773f9f848faSopenharmony_ci} 1774f9f848faSopenharmony_ci 1775f9f848faSopenharmony_ciuint8_t 1776f9f848faSopenharmony_ciusb_fifo_put_data_buffer(struct usb_fifo *f, void *ptr, usb_size_t len) 1777f9f848faSopenharmony_ci{ 1778f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1779f9f848faSopenharmony_ci 1780f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->free_q, m); 1781f9f848faSopenharmony_ci 1782f9f848faSopenharmony_ci if (m) { 1783f9f848faSopenharmony_ci m->cur_data_len = len; 1784f9f848faSopenharmony_ci m->cur_data_ptr = ptr; 1785f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->used_q, m); 1786f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1787f9f848faSopenharmony_ci return (1); 1788f9f848faSopenharmony_ci } 1789f9f848faSopenharmony_ci return (0); 1790f9f848faSopenharmony_ci} 1791f9f848faSopenharmony_ci 1792f9f848faSopenharmony_civoid 1793f9f848faSopenharmony_ciusb_fifo_put_data_error(struct usb_fifo *f) 1794f9f848faSopenharmony_ci{ 1795f9f848faSopenharmony_ci f->flag_iserror = 1; 1796f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1797f9f848faSopenharmony_ci} 1798f9f848faSopenharmony_ci 1799f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1800f9f848faSopenharmony_ci * usb_fifo_get_data 1801f9f848faSopenharmony_ci * 1802f9f848faSopenharmony_ci * what: 1803f9f848faSopenharmony_ci * 0 - normal operation 1804f9f848faSopenharmony_ci * 1 - only get one "usb_mbuf" 1805f9f848faSopenharmony_ci * 1806f9f848faSopenharmony_ci * returns: 1807f9f848faSopenharmony_ci * 0 - no more data 1808f9f848faSopenharmony_ci * 1 - data in buffer 1809f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1810f9f848faSopenharmony_ciuint8_t 1811f9f848faSopenharmony_ciusb_fifo_get_data(struct usb_fifo *f, struct usb_page_cache *pc, 1812f9f848faSopenharmony_ci usb_frlength_t offset, usb_frlength_t len, usb_frlength_t *actlen, 1813f9f848faSopenharmony_ci uint8_t what) 1814f9f848faSopenharmony_ci{ 1815f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1816f9f848faSopenharmony_ci usb_frlength_t io_len; 1817f9f848faSopenharmony_ci uint8_t tr_data = 0; 1818f9f848faSopenharmony_ci 1819f9f848faSopenharmony_ci actlen[0] = 0; 1820f9f848faSopenharmony_ci 1821f9f848faSopenharmony_ci while (1) { 1822f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->used_q, m); 1823f9f848faSopenharmony_ci 1824f9f848faSopenharmony_ci if (m) { 1825f9f848faSopenharmony_ci tr_data = 1; 1826f9f848faSopenharmony_ci 1827f9f848faSopenharmony_ci io_len = MIN(len, m->cur_data_len); 1828f9f848faSopenharmony_ci 1829f9f848faSopenharmony_ci usbd_copy_in(pc, offset, m->cur_data_ptr, io_len); 1830f9f848faSopenharmony_ci 1831f9f848faSopenharmony_ci len -= io_len; 1832f9f848faSopenharmony_ci offset += io_len; 1833f9f848faSopenharmony_ci actlen[0] += io_len; 1834f9f848faSopenharmony_ci m->cur_data_ptr += io_len; 1835f9f848faSopenharmony_ci m->cur_data_len -= io_len; 1836f9f848faSopenharmony_ci 1837f9f848faSopenharmony_ci if ((m->cur_data_len == 0) || (what == 1)) { 1838f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->free_q, m); 1839f9f848faSopenharmony_ci 1840f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1841f9f848faSopenharmony_ci 1842f9f848faSopenharmony_ci if (what == 1) { 1843f9f848faSopenharmony_ci break; 1844f9f848faSopenharmony_ci } 1845f9f848faSopenharmony_ci } else { 1846f9f848faSopenharmony_ci USB_IF_PREPEND(&f->used_q, m); 1847f9f848faSopenharmony_ci } 1848f9f848faSopenharmony_ci } else { 1849f9f848faSopenharmony_ci if (tr_data) { 1850f9f848faSopenharmony_ci /* wait for data to be written out */ 1851f9f848faSopenharmony_ci break; 1852f9f848faSopenharmony_ci } 1853f9f848faSopenharmony_ci if (f->flag_flushing) { 1854f9f848faSopenharmony_ci /* check if we should send a short packet */ 1855f9f848faSopenharmony_ci if (f->flag_short != 0) { 1856f9f848faSopenharmony_ci f->flag_short = 0; 1857f9f848faSopenharmony_ci tr_data = 1; 1858f9f848faSopenharmony_ci break; 1859f9f848faSopenharmony_ci } 1860f9f848faSopenharmony_ci /* flushing complete */ 1861f9f848faSopenharmony_ci f->flag_flushing = 0; 1862f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1863f9f848faSopenharmony_ci } 1864f9f848faSopenharmony_ci break; 1865f9f848faSopenharmony_ci } 1866f9f848faSopenharmony_ci if (len == 0) { 1867f9f848faSopenharmony_ci break; 1868f9f848faSopenharmony_ci } 1869f9f848faSopenharmony_ci } 1870f9f848faSopenharmony_ci return (tr_data); 1871f9f848faSopenharmony_ci} 1872f9f848faSopenharmony_ci 1873f9f848faSopenharmony_ciuint8_t 1874f9f848faSopenharmony_ciusb_fifo_get_data_linear(struct usb_fifo *f, void *ptr, 1875f9f848faSopenharmony_ci usb_size_t len, usb_size_t *actlen, uint8_t what) 1876f9f848faSopenharmony_ci{ 1877f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1878f9f848faSopenharmony_ci usb_size_t io_len; 1879f9f848faSopenharmony_ci uint8_t tr_data = 0; 1880f9f848faSopenharmony_ci int error; 1881f9f848faSopenharmony_ci 1882f9f848faSopenharmony_ci actlen[0] = 0; 1883f9f848faSopenharmony_ci 1884f9f848faSopenharmony_ci while (1) { 1885f9f848faSopenharmony_ci USB_IF_DEQUEUE(&f->used_q, m); 1886f9f848faSopenharmony_ci 1887f9f848faSopenharmony_ci if (m) { 1888f9f848faSopenharmony_ci tr_data = 1; 1889f9f848faSopenharmony_ci 1890f9f848faSopenharmony_ci io_len = MIN(len, m->cur_data_len); 1891f9f848faSopenharmony_ci 1892f9f848faSopenharmony_ci error = memcpy_s(ptr, io_len, m->cur_data_ptr, io_len); 1893f9f848faSopenharmony_ci if (error != EOK) { 1894f9f848faSopenharmony_ci break; 1895f9f848faSopenharmony_ci } 1896f9f848faSopenharmony_ci 1897f9f848faSopenharmony_ci len -= io_len; 1898f9f848faSopenharmony_ci ptr = USB_ADD_BYTES(ptr, io_len); 1899f9f848faSopenharmony_ci actlen[0] += io_len; 1900f9f848faSopenharmony_ci m->cur_data_ptr += io_len; 1901f9f848faSopenharmony_ci m->cur_data_len -= io_len; 1902f9f848faSopenharmony_ci 1903f9f848faSopenharmony_ci if ((m->cur_data_len == 0) || (what == 1)) { 1904f9f848faSopenharmony_ci USB_IF_ENQUEUE(&f->free_q, m); 1905f9f848faSopenharmony_ci 1906f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1907f9f848faSopenharmony_ci 1908f9f848faSopenharmony_ci if (what == 1) { 1909f9f848faSopenharmony_ci break; 1910f9f848faSopenharmony_ci } 1911f9f848faSopenharmony_ci } else { 1912f9f848faSopenharmony_ci USB_IF_PREPEND(&f->used_q, m); 1913f9f848faSopenharmony_ci } 1914f9f848faSopenharmony_ci } else { 1915f9f848faSopenharmony_ci if (tr_data) { 1916f9f848faSopenharmony_ci /* wait for data to be written out */ 1917f9f848faSopenharmony_ci break; 1918f9f848faSopenharmony_ci } 1919f9f848faSopenharmony_ci if (f->flag_flushing) { 1920f9f848faSopenharmony_ci /* check if we should send a short packet */ 1921f9f848faSopenharmony_ci if (f->flag_short != 0) { 1922f9f848faSopenharmony_ci f->flag_short = 0; 1923f9f848faSopenharmony_ci tr_data = 1; 1924f9f848faSopenharmony_ci break; 1925f9f848faSopenharmony_ci } 1926f9f848faSopenharmony_ci /* flushing complete */ 1927f9f848faSopenharmony_ci f->flag_flushing = 0; 1928f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1929f9f848faSopenharmony_ci } 1930f9f848faSopenharmony_ci break; 1931f9f848faSopenharmony_ci } 1932f9f848faSopenharmony_ci if (len == 0) { 1933f9f848faSopenharmony_ci break; 1934f9f848faSopenharmony_ci } 1935f9f848faSopenharmony_ci } 1936f9f848faSopenharmony_ci return (tr_data); 1937f9f848faSopenharmony_ci} 1938f9f848faSopenharmony_ci 1939f9f848faSopenharmony_ciuint8_t 1940f9f848faSopenharmony_ciusb_fifo_get_data_buffer(struct usb_fifo *f, void **pptr, usb_size_t *plen) 1941f9f848faSopenharmony_ci{ 1942f9f848faSopenharmony_ci struct usb_mbuf *m = NULL; 1943f9f848faSopenharmony_ci 1944f9f848faSopenharmony_ci USB_IF_POLL(&f->used_q, m); 1945f9f848faSopenharmony_ci 1946f9f848faSopenharmony_ci if (m) { 1947f9f848faSopenharmony_ci *plen = m->cur_data_len; 1948f9f848faSopenharmony_ci *pptr = m->cur_data_ptr; 1949f9f848faSopenharmony_ci 1950f9f848faSopenharmony_ci return (1); 1951f9f848faSopenharmony_ci } 1952f9f848faSopenharmony_ci return (0); 1953f9f848faSopenharmony_ci} 1954f9f848faSopenharmony_ci 1955f9f848faSopenharmony_civoid 1956f9f848faSopenharmony_ciusb_fifo_get_data_error(struct usb_fifo *f) 1957f9f848faSopenharmony_ci{ 1958f9f848faSopenharmony_ci f->flag_iserror = 1; 1959f9f848faSopenharmony_ci usb_fifo_wakeup(f); 1960f9f848faSopenharmony_ci} 1961f9f848faSopenharmony_ci 1962f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1963f9f848faSopenharmony_ci * usb_alloc_symlink 1964f9f848faSopenharmony_ci * 1965f9f848faSopenharmony_ci * Return values: 1966f9f848faSopenharmony_ci * NULL: Failure 1967f9f848faSopenharmony_ci * Else: Pointer to symlink entry 1968f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1969f9f848faSopenharmony_cistruct usb_symlink * 1970f9f848faSopenharmony_ciusb_alloc_symlink(const char *target) 1971f9f848faSopenharmony_ci{ 1972f9f848faSopenharmony_ci struct usb_symlink *ps = NULL; 1973f9f848faSopenharmony_ci 1974f9f848faSopenharmony_ci ps = bsd_malloc(sizeof(*ps), M_USBDEV, M_WAITOK); 1975f9f848faSopenharmony_ci if (ps == NULL) { 1976f9f848faSopenharmony_ci return (ps); 1977f9f848faSopenharmony_ci } 1978f9f848faSopenharmony_ci /* XXX no longer needed */ 1979f9f848faSopenharmony_ci strlcpy(ps->src_path, target, sizeof(ps->src_path)); 1980f9f848faSopenharmony_ci ps->src_len = strlen(ps->src_path); 1981f9f848faSopenharmony_ci strlcpy(ps->dst_path, target, sizeof(ps->dst_path)); 1982f9f848faSopenharmony_ci ps->dst_len = strlen(ps->dst_path); 1983f9f848faSopenharmony_ci 1984f9f848faSopenharmony_ci sx_xlock(&usb_sym_lock); 1985f9f848faSopenharmony_ci TAILQ_INSERT_TAIL(&usb_sym_head, ps, sym_entry); 1986f9f848faSopenharmony_ci sx_xunlock(&usb_sym_lock); 1987f9f848faSopenharmony_ci return (ps); 1988f9f848faSopenharmony_ci} 1989f9f848faSopenharmony_ci 1990f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 1991f9f848faSopenharmony_ci * usb_free_symlink 1992f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 1993f9f848faSopenharmony_civoid 1994f9f848faSopenharmony_ciusb_free_symlink(struct usb_symlink *ps) 1995f9f848faSopenharmony_ci{ 1996f9f848faSopenharmony_ci if (ps == NULL) { 1997f9f848faSopenharmony_ci return; 1998f9f848faSopenharmony_ci } 1999f9f848faSopenharmony_ci sx_xlock(&usb_sym_lock); 2000f9f848faSopenharmony_ci TAILQ_REMOVE(&usb_sym_head, ps, sym_entry); 2001f9f848faSopenharmony_ci sx_xunlock(&usb_sym_lock); 2002f9f848faSopenharmony_ci 2003f9f848faSopenharmony_ci bsd_free(ps, M_USBDEV); 2004f9f848faSopenharmony_ci} 2005f9f848faSopenharmony_ci 2006f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 2007f9f848faSopenharmony_ci * usb_read_symlink 2008f9f848faSopenharmony_ci * 2009f9f848faSopenharmony_ci * Return value: 2010f9f848faSopenharmony_ci * 0: Success 2011f9f848faSopenharmony_ci * Else: Failure 2012f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 2013f9f848faSopenharmony_ciint 2014f9f848faSopenharmony_ciusb_read_symlink(uint8_t *user_ptr, uint32_t startentry, uint32_t user_len) 2015f9f848faSopenharmony_ci{ 2016f9f848faSopenharmony_ci struct usb_symlink *ps; 2017f9f848faSopenharmony_ci uint32_t temp; 2018f9f848faSopenharmony_ci uint32_t delta = 0; 2019f9f848faSopenharmony_ci uint8_t len; 2020f9f848faSopenharmony_ci int error = 0; 2021f9f848faSopenharmony_ci 2022f9f848faSopenharmony_ci sx_xlock(&usb_sym_lock); 2023f9f848faSopenharmony_ci 2024f9f848faSopenharmony_ci TAILQ_FOREACH(ps, &usb_sym_head, sym_entry) { 2025f9f848faSopenharmony_ci /* 2026f9f848faSopenharmony_ci * Compute total length of source and destination symlink 2027f9f848faSopenharmony_ci * strings pluss one length byte and two NUL bytes: 2028f9f848faSopenharmony_ci */ 2029f9f848faSopenharmony_ci temp = ps->src_len + ps->dst_len + 3; 2030f9f848faSopenharmony_ci 2031f9f848faSopenharmony_ci if (temp > 255) { 2032f9f848faSopenharmony_ci /* 2033f9f848faSopenharmony_ci * Skip entry because this length cannot fit 2034f9f848faSopenharmony_ci * into one byte: 2035f9f848faSopenharmony_ci */ 2036f9f848faSopenharmony_ci continue; 2037f9f848faSopenharmony_ci } 2038f9f848faSopenharmony_ci if (startentry != 0) { 2039f9f848faSopenharmony_ci /* decrement read offset */ 2040f9f848faSopenharmony_ci startentry--; 2041f9f848faSopenharmony_ci continue; 2042f9f848faSopenharmony_ci } 2043f9f848faSopenharmony_ci if (temp > user_len) { 2044f9f848faSopenharmony_ci /* out of buffer space */ 2045f9f848faSopenharmony_ci break; 2046f9f848faSopenharmony_ci } 2047f9f848faSopenharmony_ci len = temp; 2048f9f848faSopenharmony_ci 2049f9f848faSopenharmony_ci /* copy out total length */ 2050f9f848faSopenharmony_ci 2051f9f848faSopenharmony_ci error = copyout(&len, 2052f9f848faSopenharmony_ci USB_ADD_BYTES(user_ptr, delta), 1); 2053f9f848faSopenharmony_ci if (error) { 2054f9f848faSopenharmony_ci break; 2055f9f848faSopenharmony_ci } 2056f9f848faSopenharmony_ci delta += 1; 2057f9f848faSopenharmony_ci 2058f9f848faSopenharmony_ci /* copy out source string */ 2059f9f848faSopenharmony_ci 2060f9f848faSopenharmony_ci error = copyout(ps->src_path, 2061f9f848faSopenharmony_ci USB_ADD_BYTES(user_ptr, delta), ps->src_len); 2062f9f848faSopenharmony_ci if (error) { 2063f9f848faSopenharmony_ci break; 2064f9f848faSopenharmony_ci } 2065f9f848faSopenharmony_ci len = 0; 2066f9f848faSopenharmony_ci delta += ps->src_len; 2067f9f848faSopenharmony_ci error = copyout(&len, 2068f9f848faSopenharmony_ci USB_ADD_BYTES(user_ptr, delta), 1); 2069f9f848faSopenharmony_ci if (error) { 2070f9f848faSopenharmony_ci break; 2071f9f848faSopenharmony_ci } 2072f9f848faSopenharmony_ci delta += 1; 2073f9f848faSopenharmony_ci 2074f9f848faSopenharmony_ci /* copy out destination string */ 2075f9f848faSopenharmony_ci 2076f9f848faSopenharmony_ci error = copyout(ps->dst_path, 2077f9f848faSopenharmony_ci USB_ADD_BYTES(user_ptr, delta), ps->dst_len); 2078f9f848faSopenharmony_ci if (error) { 2079f9f848faSopenharmony_ci break; 2080f9f848faSopenharmony_ci } 2081f9f848faSopenharmony_ci len = 0; 2082f9f848faSopenharmony_ci delta += ps->dst_len; 2083f9f848faSopenharmony_ci error = copyout(&len, 2084f9f848faSopenharmony_ci USB_ADD_BYTES(user_ptr, delta), 1); 2085f9f848faSopenharmony_ci if (error) { 2086f9f848faSopenharmony_ci break; 2087f9f848faSopenharmony_ci } 2088f9f848faSopenharmony_ci delta += 1; 2089f9f848faSopenharmony_ci 2090f9f848faSopenharmony_ci user_len -= temp; 2091f9f848faSopenharmony_ci } 2092f9f848faSopenharmony_ci 2093f9f848faSopenharmony_ci /* a zero length entry indicates the end */ 2094f9f848faSopenharmony_ci 2095f9f848faSopenharmony_ci if ((user_len != 0) && (error == 0)) { 2096f9f848faSopenharmony_ci len = 0; 2097f9f848faSopenharmony_ci 2098f9f848faSopenharmony_ci error = copyout(&len, 2099f9f848faSopenharmony_ci USB_ADD_BYTES(user_ptr, delta), 1); 2100f9f848faSopenharmony_ci } 2101f9f848faSopenharmony_ci sx_xunlock(&usb_sym_lock); 2102f9f848faSopenharmony_ci return (error); 2103f9f848faSopenharmony_ci} 2104f9f848faSopenharmony_ci 2105f9f848faSopenharmony_civoid 2106f9f848faSopenharmony_ciusb_fifo_set_close_zlp(struct usb_fifo *f, uint8_t onoff) 2107f9f848faSopenharmony_ci{ 2108f9f848faSopenharmony_ci if (f == NULL) 2109f9f848faSopenharmony_ci return; 2110f9f848faSopenharmony_ci 2111f9f848faSopenharmony_ci /* send a Zero Length Packet, ZLP, before close */ 2112f9f848faSopenharmony_ci f->flag_short = onoff; 2113f9f848faSopenharmony_ci} 2114f9f848faSopenharmony_ci 2115f9f848faSopenharmony_civoid 2116f9f848faSopenharmony_ciusb_fifo_set_write_defrag(struct usb_fifo *f, uint8_t onoff) 2117f9f848faSopenharmony_ci{ 2118f9f848faSopenharmony_ci if (f == NULL) 2119f9f848faSopenharmony_ci return; 2120f9f848faSopenharmony_ci 2121f9f848faSopenharmony_ci /* defrag written data */ 2122f9f848faSopenharmony_ci f->flag_write_defrag = onoff; 2123f9f848faSopenharmony_ci /* reset defrag state */ 2124f9f848faSopenharmony_ci f->flag_have_fragment = 0; 2125f9f848faSopenharmony_ci} 2126f9f848faSopenharmony_ci 2127f9f848faSopenharmony_civoid * 2128f9f848faSopenharmony_ciusb_fifo_softc(struct usb_fifo *f) 2129f9f848faSopenharmony_ci{ 2130f9f848faSopenharmony_ci return (f->priv_sc0); 2131f9f848faSopenharmony_ci} 2132f9f848faSopenharmony_ci#endif /* USB_HAVE_UGEN */ 2133