1*5c4a5fe1SAndy Fiddaman /*- 2*5c4a5fe1SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause 3*5c4a5fe1SAndy Fiddaman * 4*5c4a5fe1SAndy Fiddaman * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com> 5*5c4a5fe1SAndy Fiddaman * Copyright 2018 Joyent, Inc. 6*5c4a5fe1SAndy Fiddaman * All rights reserved. 7*5c4a5fe1SAndy Fiddaman * 8*5c4a5fe1SAndy Fiddaman * Redistribution and use in source and binary forms, with or without 9*5c4a5fe1SAndy Fiddaman * modification, are permitted provided that the following conditions 10*5c4a5fe1SAndy Fiddaman * are met: 11*5c4a5fe1SAndy Fiddaman * 1. Redistributions of source code must retain the above copyright 12*5c4a5fe1SAndy Fiddaman * notice, this list of conditions and the following disclaimer. 13*5c4a5fe1SAndy Fiddaman * 2. Redistributions in binary form must reproduce the above copyright 14*5c4a5fe1SAndy Fiddaman * notice, this list of conditions and the following disclaimer in the 15*5c4a5fe1SAndy Fiddaman * documentation and/or other materials provided with the distribution. 16*5c4a5fe1SAndy Fiddaman * 17*5c4a5fe1SAndy Fiddaman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*5c4a5fe1SAndy Fiddaman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*5c4a5fe1SAndy Fiddaman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*5c4a5fe1SAndy Fiddaman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*5c4a5fe1SAndy Fiddaman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*5c4a5fe1SAndy Fiddaman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*5c4a5fe1SAndy Fiddaman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*5c4a5fe1SAndy Fiddaman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*5c4a5fe1SAndy Fiddaman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*5c4a5fe1SAndy Fiddaman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*5c4a5fe1SAndy Fiddaman * SUCH DAMAGE. 28*5c4a5fe1SAndy Fiddaman */ 29*5c4a5fe1SAndy Fiddaman 30*5c4a5fe1SAndy Fiddaman #ifndef _USB_EMUL_H_ 31*5c4a5fe1SAndy Fiddaman #define _USB_EMUL_H_ 32*5c4a5fe1SAndy Fiddaman 33*5c4a5fe1SAndy Fiddaman #include <sys/nv.h> 34*5c4a5fe1SAndy Fiddaman #include <stdlib.h> 35*5c4a5fe1SAndy Fiddaman #include <sys/linker_set.h> 36*5c4a5fe1SAndy Fiddaman #include <pthread.h> 37*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__ 38*5c4a5fe1SAndy Fiddaman #include <synch.h> 39*5c4a5fe1SAndy Fiddaman #endif 40*5c4a5fe1SAndy Fiddaman 41*5c4a5fe1SAndy Fiddaman #define USB_MAX_XFER_BLOCKS 8 42*5c4a5fe1SAndy Fiddaman 43*5c4a5fe1SAndy Fiddaman #define USB_XFER_OUT 0 44*5c4a5fe1SAndy Fiddaman #define USB_XFER_IN 1 45*5c4a5fe1SAndy Fiddaman 46*5c4a5fe1SAndy Fiddaman 47*5c4a5fe1SAndy Fiddaman 48*5c4a5fe1SAndy Fiddaman struct usb_hci; 49*5c4a5fe1SAndy Fiddaman struct usb_device_request; 50*5c4a5fe1SAndy Fiddaman struct usb_data_xfer; 51*5c4a5fe1SAndy Fiddaman 52*5c4a5fe1SAndy Fiddaman /* Device emulation handlers */ 53*5c4a5fe1SAndy Fiddaman struct usb_devemu { 54*5c4a5fe1SAndy Fiddaman const char *ue_emu; /* name of device emulation */ 55*5c4a5fe1SAndy Fiddaman int ue_usbver; /* usb version: 2 or 3 */ 56*5c4a5fe1SAndy Fiddaman int ue_usbspeed; /* usb device speed */ 57*5c4a5fe1SAndy Fiddaman 58*5c4a5fe1SAndy Fiddaman /* instance creation */ 59*5c4a5fe1SAndy Fiddaman void *(*ue_init)(struct usb_hci *hci, nvlist_t *nvl); 60*5c4a5fe1SAndy Fiddaman 61*5c4a5fe1SAndy Fiddaman /* handlers */ 62*5c4a5fe1SAndy Fiddaman int (*ue_request)(void *sc, struct usb_data_xfer *xfer); 63*5c4a5fe1SAndy Fiddaman int (*ue_data)(void *sc, struct usb_data_xfer *xfer, int dir, 64*5c4a5fe1SAndy Fiddaman int epctx); 65*5c4a5fe1SAndy Fiddaman int (*ue_reset)(void *sc); 66*5c4a5fe1SAndy Fiddaman int (*ue_remove)(void *sc); 67*5c4a5fe1SAndy Fiddaman int (*ue_stop)(void *sc); 68*5c4a5fe1SAndy Fiddaman }; 69*5c4a5fe1SAndy Fiddaman #define USB_EMUL_SET(x) DATA_SET(usb_emu_set, x) 70*5c4a5fe1SAndy Fiddaman 71*5c4a5fe1SAndy Fiddaman /* 72*5c4a5fe1SAndy Fiddaman * USB device events to notify HCI when state changes 73*5c4a5fe1SAndy Fiddaman */ 74*5c4a5fe1SAndy Fiddaman enum hci_usbev { 75*5c4a5fe1SAndy Fiddaman USBDEV_ATTACH, 76*5c4a5fe1SAndy Fiddaman USBDEV_RESET, 77*5c4a5fe1SAndy Fiddaman USBDEV_STOP, 78*5c4a5fe1SAndy Fiddaman USBDEV_REMOVE, 79*5c4a5fe1SAndy Fiddaman }; 80*5c4a5fe1SAndy Fiddaman 81*5c4a5fe1SAndy Fiddaman /* usb controller, ie xhci, ehci */ 82*5c4a5fe1SAndy Fiddaman struct usb_hci { 83*5c4a5fe1SAndy Fiddaman int (*hci_intr)(struct usb_hci *hci, int epctx); 84*5c4a5fe1SAndy Fiddaman int (*hci_event)(struct usb_hci *hci, enum hci_usbev evid, 85*5c4a5fe1SAndy Fiddaman void *param); 86*5c4a5fe1SAndy Fiddaman void *hci_sc; /* private softc for hci */ 87*5c4a5fe1SAndy Fiddaman 88*5c4a5fe1SAndy Fiddaman /* controller managed fields */ 89*5c4a5fe1SAndy Fiddaman int hci_address; 90*5c4a5fe1SAndy Fiddaman int hci_port; 91*5c4a5fe1SAndy Fiddaman }; 92*5c4a5fe1SAndy Fiddaman 93*5c4a5fe1SAndy Fiddaman /* 94*5c4a5fe1SAndy Fiddaman * Each xfer block is mapped to the hci transfer block. 95*5c4a5fe1SAndy Fiddaman * On input into the device handler, blen is set to the length of buf. 96*5c4a5fe1SAndy Fiddaman * The device handler is to update blen to reflect on the residual size 97*5c4a5fe1SAndy Fiddaman * of the buffer, i.e. len(buf) - len(consumed). 98*5c4a5fe1SAndy Fiddaman */ 99*5c4a5fe1SAndy Fiddaman struct usb_data_xfer_block { 100*5c4a5fe1SAndy Fiddaman void *buf; /* IN or OUT pointer */ 101*5c4a5fe1SAndy Fiddaman int blen; /* in:len(buf), out:len(remaining) */ 102*5c4a5fe1SAndy Fiddaman int bdone; /* bytes transferred */ 103*5c4a5fe1SAndy Fiddaman uint32_t processed; /* device processed this + errcode */ 104*5c4a5fe1SAndy Fiddaman void *hci_data; /* HCI private reference */ 105*5c4a5fe1SAndy Fiddaman int ccs; 106*5c4a5fe1SAndy Fiddaman uint32_t streamid; 107*5c4a5fe1SAndy Fiddaman uint64_t trbnext; /* next TRB guest address */ 108*5c4a5fe1SAndy Fiddaman }; 109*5c4a5fe1SAndy Fiddaman 110*5c4a5fe1SAndy Fiddaman struct usb_data_xfer { 111*5c4a5fe1SAndy Fiddaman struct usb_data_xfer_block data[USB_MAX_XFER_BLOCKS]; 112*5c4a5fe1SAndy Fiddaman struct usb_device_request *ureq; /* setup ctl request */ 113*5c4a5fe1SAndy Fiddaman int ndata; /* # of data items */ 114*5c4a5fe1SAndy Fiddaman int head; 115*5c4a5fe1SAndy Fiddaman int tail; 116*5c4a5fe1SAndy Fiddaman pthread_mutex_t mtx; 117*5c4a5fe1SAndy Fiddaman }; 118*5c4a5fe1SAndy Fiddaman 119*5c4a5fe1SAndy Fiddaman enum USB_ERRCODE { 120*5c4a5fe1SAndy Fiddaman USB_ACK, 121*5c4a5fe1SAndy Fiddaman USB_NAK, 122*5c4a5fe1SAndy Fiddaman USB_STALL, 123*5c4a5fe1SAndy Fiddaman USB_NYET, 124*5c4a5fe1SAndy Fiddaman USB_ERR, 125*5c4a5fe1SAndy Fiddaman USB_SHORT 126*5c4a5fe1SAndy Fiddaman }; 127*5c4a5fe1SAndy Fiddaman 128*5c4a5fe1SAndy Fiddaman #define USB_DATA_GET_ERRCODE(x) (x)->processed >> 8 129*5c4a5fe1SAndy Fiddaman #define USB_DATA_SET_ERRCODE(x,e) do { \ 130*5c4a5fe1SAndy Fiddaman (x)->processed = ((x)->processed & 0xFF) | (e << 8); \ 131*5c4a5fe1SAndy Fiddaman } while (0) 132*5c4a5fe1SAndy Fiddaman 133*5c4a5fe1SAndy Fiddaman #define USB_DATA_OK(x,i) ((x)->data[(i)].buf != NULL) 134*5c4a5fe1SAndy Fiddaman 135*5c4a5fe1SAndy Fiddaman #define USB_DATA_XFER_INIT(x) do { \ 136*5c4a5fe1SAndy Fiddaman memset((x), 0, sizeof(*(x))); \ 137*5c4a5fe1SAndy Fiddaman pthread_mutex_init(&((x)->mtx), NULL); \ 138*5c4a5fe1SAndy Fiddaman } while (0) 139*5c4a5fe1SAndy Fiddaman 140*5c4a5fe1SAndy Fiddaman #define USB_DATA_XFER_RESET(x) do { \ 141*5c4a5fe1SAndy Fiddaman memset((x)->data, 0, sizeof((x)->data)); \ 142*5c4a5fe1SAndy Fiddaman (x)->ndata = 0; \ 143*5c4a5fe1SAndy Fiddaman (x)->head = (x)->tail = 0; \ 144*5c4a5fe1SAndy Fiddaman } while (0) 145*5c4a5fe1SAndy Fiddaman 146*5c4a5fe1SAndy Fiddaman #define USB_DATA_XFER_LOCK(x) do { \ 147*5c4a5fe1SAndy Fiddaman pthread_mutex_lock(&((x)->mtx)); \ 148*5c4a5fe1SAndy Fiddaman } while (0) 149*5c4a5fe1SAndy Fiddaman 150*5c4a5fe1SAndy Fiddaman #define USB_DATA_XFER_UNLOCK(x) do { \ 151*5c4a5fe1SAndy Fiddaman pthread_mutex_unlock(&((x)->mtx)); \ 152*5c4a5fe1SAndy Fiddaman } while (0) 153*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__ 154*5c4a5fe1SAndy Fiddaman #define USB_DATA_XFER_LOCK_HELD(x) MUTEX_HELD(&((x)->mtx)) 155*5c4a5fe1SAndy Fiddaman #endif 156*5c4a5fe1SAndy Fiddaman 157*5c4a5fe1SAndy Fiddaman struct usb_devemu *usb_emu_finddev(const char *name); 158*5c4a5fe1SAndy Fiddaman 159*5c4a5fe1SAndy Fiddaman struct usb_data_xfer_block *usb_data_xfer_append(struct usb_data_xfer *xfer, 160*5c4a5fe1SAndy Fiddaman void *buf, int blen, void *hci_data, int ccs); 161*5c4a5fe1SAndy Fiddaman 162*5c4a5fe1SAndy Fiddaman 163*5c4a5fe1SAndy Fiddaman #endif /* _USB_EMUL_H_ */ 164