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