xref: /illumos-gate/usr/src/cmd/bhyve/common/usb_emul.h (revision 5c4a5fe16715fb423db76577a6883b5bbecdbe45)
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