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