diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usb.h b/src/libs/compat/freebsd_network/compat/dev/usb/usb.h new file mode 100644 index 0000000000..26488ad27a --- /dev/null +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usb.h @@ -0,0 +1,77 @@ +/* + * Copyright 2018-2019, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * Augustin Cavalier + */ +#ifndef _FBSD_COMPAT_USB_STANDARD_H_ +#define _FBSD_COMPAT_USB_STANDARD_H_ + +#include + +MALLOC_DECLARE(M_USB); +MALLOC_DECLARE(M_USBDEV); + +#include +#include + +#define USB_STACK_VERSION 2000 /* 2.0 */ + +struct usb_device_request { + uByte bmRequestType; + uByte bRequest; + uWord wValue; + uWord wIndex; + uWord wLength; +} __packed; +typedef struct usb_device_request usb_device_request_t; + +/* abbreviated Haiku request types */ +#define HAIKU_USB_REQTYPE_DEVICE_IN 0x80 +#define HAIKU_USB_REQTYPE_DEVICE_OUT 0x00 +#define HAIKU_USB_REQTYPE_VENDOR 0x40 + +/* FreeBSD request types */ +#define UT_READ_VENDOR_DEVICE (HAIKU_USB_REQTYPE_DEVICE_IN | HAIKU_USB_REQTYPE_VENDOR) +#define UT_WRITE_VENDOR_DEVICE (HAIKU_USB_REQTYPE_DEVICE_OUT | HAIKU_USB_REQTYPE_VENDOR) + +/* make sure this matches Haiku's usb_speed! */ +enum usb_dev_speed { + USB_SPEED_LOW, + USB_SPEED_FULL, + USB_SPEED_HIGH, + USB_SPEED_SUPER, +}; + +enum usb_hc_mode { + USB_MODE_HOST, /* initiates transfers */ + USB_MODE_DEVICE, /* bus transfer target */ + USB_MODE_DUAL /* can be host or device */ +}; +#define USB_MODE_MAX (USB_MODE_DUAL+1) + +#define usb_endpoint_descriptor freebsd_usb_endpoint_descriptor +struct usb_endpoint_descriptor { + uByte bLength; + uByte bDescriptorType; + uByte bEndpointAddress; +#define UE_GET_DIR(a) ((a) & 0x80) +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7)) +#define UE_DIR_IN 0x80 /* IN-token endpoint, fixed */ +#define UE_DIR_OUT 0x00 /* OUT-token endpoint, fixed */ +#define UE_ADDR 0x0f +#define UE_ADDR_ANY 0xff +#define UE_GET_ADDR(a) ((a) & UE_ADDR) + uByte bmAttributes; +#define UE_XFERTYPE 0x03 +#define UE_CONTROL 0x00 +#define UE_BULK 0x02 +#define UE_INTERRUPT 0x03 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE) + uWord wMaxPacketSize; + uByte bInterval; +} __packed; +typedef struct usb_endpoint_descriptor usb_endpoint_descriptor_t; + +#endif // _FBSD_COMPAT_USB_STANDARD_H_ diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usb_debug.h b/src/libs/compat/freebsd_network/compat/dev/usb/usb_debug.h new file mode 100644 index 0000000000..0f2940310e --- /dev/null +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usb_debug.h @@ -0,0 +1,86 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* This file contains various factored out debug macros. */ + +#ifndef _USB_DEBUG_H_ +#define _USB_DEBUG_H_ + +/* Declare global USB debug variable. */ +extern int usb_debug; + +/* Check if USB debugging is enabled. */ +#ifdef USB_DEBUG_VAR +#ifdef USB_DEBUG +#define DPRINTFN(n,fmt,...) do { \ + if ((USB_DEBUG_VAR) >= (n)) { \ + printf("%s: " fmt, \ + __FUNCTION__ ,##__VA_ARGS__); \ + } \ +} while (0) +#define DPRINTF(...) DPRINTFN(1, __VA_ARGS__) +#else +#define DPRINTF(...) do { } while (0) +#define DPRINTFN(...) do { } while (0) +#endif +#endif + +struct usb_interface; +struct usb_device; +struct usb_endpoint; +struct usb_xfer; + +void usb_dump_iface(struct usb_interface *iface); +void usb_dump_device(struct usb_device *udev); +void usb_dump_queue(struct usb_endpoint *ep); +void usb_dump_endpoint(struct usb_endpoint *ep); +void usb_dump_xfer(struct usb_xfer *xfer); + +#ifdef USB_DEBUG +extern unsigned int usb_port_reset_delay; +extern unsigned int usb_port_root_reset_delay; +extern unsigned int usb_port_reset_recovery; +extern unsigned int usb_port_powerup_delay; +extern unsigned int usb_port_resume_delay; +extern unsigned int usb_set_address_settle; +extern unsigned int usb_resume_delay; +extern unsigned int usb_resume_wait; +extern unsigned int usb_resume_recovery; +extern unsigned int usb_extra_power_up_time; +#else +#define usb_port_reset_delay USB_PORT_RESET_DELAY +#define usb_port_root_reset_delay USB_PORT_ROOT_RESET_DELAY +#define usb_port_reset_recovery USB_PORT_RESET_RECOVERY +#define usb_port_powerup_delay USB_PORT_POWERUP_DELAY +#define usb_port_resume_delay USB_PORT_RESUME_DELAY +#define usb_set_address_settle USB_SET_ADDRESS_SETTLE +#define usb_resume_delay USB_RESUME_DELAY +#define usb_resume_wait USB_RESUME_WAIT +#define usb_resume_recovery USB_RESUME_RECOVERY +#define usb_extra_power_up_time USB_EXTRA_POWER_UP_TIME +#endif + +#endif /* _USB_DEBUG_H_ */ diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usb_device.h b/src/libs/compat/freebsd_network/compat/dev/usb/usb_device.h new file mode 100644 index 0000000000..8cd8931100 --- /dev/null +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usb_device.h @@ -0,0 +1,17 @@ +/* + * Copyright 2022, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + */ +#ifndef _FBSD_COMPAT_USB_DEVICE_H_ +#define _FBSD_COMPAT_USB_DEVICE_H_ + +struct usb_device { + struct usb_endpoint endpoints[USB_MAX_EP_UNITS]; + uint8_t endpoints_max; /* number of endpoints present */ + + uint32 haiku_usb_device; +}; + +void usb_cleanup_device(struct usb_device* udev); + +#endif // _FBSD_COMPAT_USB_DEVICE_H_ diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usb_endian.h b/src/libs/compat/freebsd_network/compat/dev/usb/usb_endian.h new file mode 100644 index 0000000000..48f599e06d --- /dev/null +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usb_endian.h @@ -0,0 +1,28 @@ +/* + * Copyright 2020, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * Augustin Cavalier + */ +#ifndef _USB_ENDIAN_H_ +#define _USB_ENDIAN_H_ + +#include + +typedef uint8_t uByte; +typedef uint16_t uWord; +typedef uint32_t uDWord; +typedef uint64_t uQWord; + +#define UGETB(w) (uint8_t)(w) +#define UGETW(w) (uint16_t)(w) +#define UGETDW(w) (uint32_t)(w) +#define UGETQW(w) (uint64_t)(w) + +#define USETB(w,v) { (w) = (uint8_t)(v); } +#define USETW(w,v) { (w) = (uint16_t)(v); } +#define USETDW(w,v) { (w) = (uint32_t)(v); } +#define USETQW(w,v) { (w) = (uint64_t)(v); } + +#endif /* _USB_ENDIAN_H_ */ diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usb_haiku.h b/src/libs/compat/freebsd_network/compat/dev/usb/usb_haiku.h new file mode 100644 index 0000000000..b19c62f3da --- /dev/null +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usb_haiku.h @@ -0,0 +1,80 @@ +/* + * Copyright 2018, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * Augustin Cavalier + */ +#ifndef _FBSD_COMPAT_USB_HAIKU_H_ +#define _FBSD_COMPAT_USB_HAIKU_H_ + +#include + +/* Default USB configuration */ +#define USB_HAVE_UGEN 1 +#define USB_HAVE_DEVCTL 1 +#define USB_HAVE_BUSDMA 1 +#define USB_HAVE_COMPAT_LINUX 0 +#define USB_HAVE_USER_IO 1 +#define USB_HAVE_MBUF 1 +#define USB_HAVE_TT_SUPPORT 1 +#define USB_HAVE_POWERD 1 +#define USB_HAVE_MSCTEST 1 +#define USB_HAVE_MSCTEST_DETACH 1 +#define USB_HAVE_PF 1 +#define USB_HAVE_ROOT_MOUNT_HOLD 1 +#define USB_HAVE_ID_SECTION 0 +#define USB_HAVE_PER_BUS_PROCESS 1 +#define USB_HAVE_FIXED_ENDPOINT 0 +#define USB_HAVE_FIXED_IFACE 0 +#define USB_HAVE_FIXED_CONFIG 0 +#define USB_HAVE_FIXED_PORT 0 +#define USB_HAVE_DISABLE_ENUM 1 + +/* define zero ticks callout value */ +#define USB_CALLOUT_ZERO_TICKS 1 + +#define USB_TD_GET_PROC(td) (td)->td_proc +#define USB_PROC_GET_GID(td) (td)->p_pgid + +#if (!defined(USB_HOST_ALIGN)) || (USB_HOST_ALIGN <= 0) +/* Use default value. */ +#undef USB_HOST_ALIGN +#if defined(__arm__) || defined(__mips__) || defined(__powerpc__) +#define USB_HOST_ALIGN 32 /* Arm and MIPS need at least this much, if not more */ +#else +#define USB_HOST_ALIGN 8 /* bytes, must be power of two */ +#endif +#endif +/* Sanity check for USB_HOST_ALIGN: Verify power of two. */ +#if ((-USB_HOST_ALIGN) & USB_HOST_ALIGN) != USB_HOST_ALIGN +#error "USB_HOST_ALIGN is not power of two." +#endif +#define USB_FS_ISOC_UFRAME_MAX 4 /* exclusive unit */ +#define USB_BUS_MAX 256 /* units */ +#define USB_MAX_DEVICES 128 /* units */ +#define USB_CONFIG_MAX 65535 /* bytes */ +#define USB_IFACE_MAX 32 /* units */ +#define USB_FIFO_MAX 128 /* units */ +#define USB_MAX_EP_STREAMS 8 /* units */ +#define USB_MAX_EP_UNITS 32 /* units */ +#define USB_MAX_PORTS 255 /* units */ + +#define USB_MAX_FS_ISOC_FRAMES_PER_XFER (120) /* units */ +#define USB_MAX_HS_ISOC_FRAMES_PER_XFER (8*120) /* units */ + +#define USB_HUB_MAX_DEPTH 5 +#define USB_EP0_BUFSIZE 1024 /* bytes */ +#define USB_CS_RESET_LIMIT 20 /* failures = 20 * 50 ms = 1sec */ + +#define USB_MAX_AUTO_QUIRK 8 /* maximum number of dynamic quirks */ + +typedef uint32_t usb_timeout_t; /* milliseconds */ +typedef uint32_t usb_frlength_t; /* bytes */ +typedef uint32_t usb_frcount_t; /* units */ +typedef uint32_t usb_size_t; /* bytes */ +typedef uint32_t usb_ticks_t; /* system defined */ +typedef uint16_t usb_power_mask_t; /* see "USB_HW_POWER_XXX" */ +typedef uint16_t usb_stream_t; /* stream ID */ + +#endif // _FBSD_COMPAT_USB_HAIKU_H_ diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usbdi.h b/src/libs/compat/freebsd_network/compat/dev/usb/usbdi.h new file mode 100644 index 0000000000..4e38104c0f --- /dev/null +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usbdi.h @@ -0,0 +1,375 @@ +/* + * Copyright 2022, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + */ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2009 Andrew Thompson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _FBSD_COMPAT_USB_USBDI_H_ +#define _FBSD_COMPAT_USB_USBDI_H_ + +#define usb_device freebsd_usb_device +#define usb_interface freebsd_usb_interface + +struct usb_device; +struct usb_interface; +struct usb_xfer; +struct usb_attach_arg; +struct usb_endpoint; +struct usb_page_cache; +struct usb_page_search; +struct usb_process; +struct usb_mbuf; +struct usb_fs_privdata; +struct mbuf; + +typedef enum { /* keep in sync with usb_errstr_table */ + USB_ERR_NORMAL_COMPLETION = 0, + USB_ERR_PENDING_REQUESTS, /* 1 */ + USB_ERR_NOT_STARTED, /* 2 */ + USB_ERR_INVAL, /* 3 */ + USB_ERR_NOMEM, /* 4 */ + USB_ERR_CANCELLED, /* 5 */ + USB_ERR_BAD_ADDRESS, /* 6 */ + USB_ERR_BAD_BUFSIZE, /* 7 */ + USB_ERR_BAD_FLAG, /* 8 */ + USB_ERR_NO_CALLBACK, /* 9 */ + USB_ERR_IN_USE, /* 10 */ + USB_ERR_NO_ADDR, /* 11 */ + USB_ERR_NO_PIPE, /* 12 */ + USB_ERR_ZERO_NFRAMES, /* 13 */ + USB_ERR_ZERO_MAXP, /* 14 */ + USB_ERR_SET_ADDR_FAILED, /* 15 */ + USB_ERR_NO_POWER, /* 16 */ + USB_ERR_TOO_DEEP, /* 17 */ + USB_ERR_IOERROR, /* 18 */ + USB_ERR_NOT_CONFIGURED, /* 19 */ + USB_ERR_TIMEOUT, /* 20 */ + USB_ERR_SHORT_XFER, /* 21 */ + USB_ERR_STALLED, /* 22 */ + USB_ERR_INTERRUPTED, /* 23 */ + USB_ERR_DMA_LOAD_FAILED, /* 24 */ + USB_ERR_BAD_CONTEXT, /* 25 */ + USB_ERR_NO_ROOT_HUB, /* 26 */ + USB_ERR_NO_INTR_THREAD, /* 27 */ + USB_ERR_NOT_LOCKED, /* 28 */ + USB_ERR_MAX +} usb_error_t; + +/* + * Flags for transfers + */ +#define USB_FORCE_SHORT_XFER 0x0001 /* force a short transmit last */ +#define USB_SHORT_XFER_OK 0x0004 /* allow short reads */ +#define USB_DELAY_STATUS_STAGE 0x0010 /* insert delay before STATUS stage */ +#define USB_USER_DATA_PTR 0x0020 /* internal flag */ +#define USB_MULTI_SHORT_OK 0x0040 /* allow multiple short frames */ +#define USB_MANUAL_STATUS 0x0080 /* manual ctrl status */ + +#define USB_NO_TIMEOUT 0 +#define USB_DEFAULT_TIMEOUT 5000 /* 5000 ms = 5 seconds */ + +#if defined(_KERNEL) +/* typedefs */ + +typedef void (usb_callback_t)(struct usb_xfer *, usb_error_t); + +/* + * The following macros are used used to convert milliseconds into + * HZ. We use 1024 instead of 1000 milliseconds per second to save a + * full division. + */ +#define USB_MS_HZ 1024 + +#define USB_MS_TO_TICKS(ms) \ + (((uint32_t)((((uint32_t)(ms)) * ((uint32_t)(hz))) + USB_MS_HZ - 1)) / USB_MS_HZ) + +/* + * The following structure defines a USB endpoint. + */ +struct usb_endpoint { + struct usb_endpoint_descriptor* edesc; + uint8_t iface_index; /* not used by "default endpoint" */ +}; + +/* + * The following structure defines a set of USB transfer flags. + */ +struct usb_xfer_flags { + uint8_t force_short_xfer:1; + /* force a short transmit transfer last */ + uint8_t short_xfer_ok:1; /* allow short receive transfers */ + uint8_t short_frames_ok:1; /* allow short frames */ + uint8_t pipe_bof:1; /* block pipe on failure */ + uint8_t proxy_buffer:1; + /* makes buffer size a factor of "max_frame_size" */ + uint8_t ext_buffer:1; /* uses external DMA buffer */ + uint8_t manual_status:1; + /* non automatic status stage on control transfers */ + uint8_t no_pipe_ok:1; + /* set if "USB_ERR_NO_PIPE" error can be ignored */ + uint8_t stall_pipe:1; + /* set if the endpoint belonging to this USB transfer + * should be stalled before starting this transfer! */ +}; + +struct usb_config { + usb_callback_t *callback; /* USB transfer callback */ + usb_frlength_t bufsize; /* total pipe buffer size in bytes */ + usb_frcount_t frames; /* maximum number of USB frames */ + usb_timeout_t interval; /* interval in milliseconds */ +#define USB_DEFAULT_INTERVAL 0 + usb_timeout_t timeout; /* transfer timeout in milliseconds */ + struct usb_xfer_flags flags; /* transfer flags */ + usb_stream_t stream_id; /* USB3.0 specific */ + enum usb_hc_mode usb_mode; /* host or device mode */ + uint8_t type; /* pipe type */ + uint8_t endpoint; /* pipe number */ + uint8_t direction; /* pipe direction */ + uint8_t ep_index; /* pipe index match to use */ + uint8_t if_index; /* "ifaces" index to use */ +}; + +#if USB_HAVE_ID_SECTION +#define STRUCT_USB_HOST_ID \ + struct usb_device_id __section("usb_host_id") +#define STRUCT_USB_DEVICE_ID \ + struct usb_device_id __section("usb_device_id") +#define STRUCT_USB_DUAL_ID \ + struct usb_device_id __section("usb_dual_id") +#else +#define STRUCT_USB_HOST_ID \ + struct usb_device_id +#define STRUCT_USB_DEVICE_ID \ + struct usb_device_id +#define STRUCT_USB_DUAL_ID \ + struct usb_device_id +#endif /* USB_HAVE_ID_SECTION */ + +struct usb_device_id { + /* Select which fields to match against */ +#if BYTE_ORDER == LITTLE_ENDIAN + uint16_t + match_flag_vendor:1, + match_flag_product:1, + match_flag_dev_lo:1, + match_flag_dev_hi:1, + + match_flag_dev_class:1, + match_flag_dev_subclass:1, + match_flag_dev_protocol:1, + match_flag_int_class:1, + + match_flag_int_subclass:1, + match_flag_int_protocol:1, + match_flag_unused:6; +#else + uint16_t + match_flag_unused:6, + match_flag_int_protocol:1, + match_flag_int_subclass:1, + + match_flag_int_class:1, + match_flag_dev_protocol:1, + match_flag_dev_subclass:1, + match_flag_dev_class:1, + + match_flag_dev_hi:1, + match_flag_dev_lo:1, + match_flag_product:1, + match_flag_vendor:1; +#endif + + /* Used for product specific matches; the BCD range is inclusive */ + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice_lo; + uint16_t bcdDevice_hi; + + /* Used for device class matches */ + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + + /* Used for interface class matches */ + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + + /* Hook for driver specific information */ + unsigned long driver_info; +} __aligned(32); + +#define USB_PNP_HOST_INFO(table) +#define USB_PNP_DEVICE_INFO(table) +#define USB_PNP_DUAL_INFO(table) + +/* check that the size of the structure above is correct */ +extern char usb_device_id_assert[(sizeof(struct usb_device_id) == 32) ? 1 : -1]; + +#define USB_VENDOR(vend) \ + .match_flag_vendor = 1, .idVendor = (vend) + +#define USB_PRODUCT(prod) \ + .match_flag_product = 1, .idProduct = (prod) + +#define USB_VP(vend,prod) \ + USB_VENDOR(vend), USB_PRODUCT(prod) + +#define USB_VPI(vend,prod,info) \ + USB_VENDOR(vend), USB_PRODUCT(prod), USB_DRIVER_INFO(info) + +#define USB_DEV_BCD_GTEQ(lo) /* greater than or equal */ \ + .match_flag_dev_lo = 1, .bcdDevice_lo = (lo) + +#define USB_DEV_BCD_LTEQ(hi) /* less than or equal */ \ + .match_flag_dev_hi = 1, .bcdDevice_hi = (hi) + +#define USB_DEV_CLASS(dc) \ + .match_flag_dev_class = 1, .bDeviceClass = (dc) + +#define USB_DEV_SUBCLASS(dsc) \ + .match_flag_dev_subclass = 1, .bDeviceSubClass = (dsc) + +#define USB_DEV_PROTOCOL(dp) \ + .match_flag_dev_protocol = 1, .bDeviceProtocol = (dp) + +#define USB_IFACE_CLASS(ic) \ + .match_flag_int_class = 1, .bInterfaceClass = (ic) + +#define USB_IFACE_SUBCLASS(isc) \ + .match_flag_int_subclass = 1, .bInterfaceSubClass = (isc) + +#define USB_IFACE_PROTOCOL(ip) \ + .match_flag_int_protocol = 1, .bInterfaceProtocol = (ip) + +#define USB_IF_CSI(class,subclass,info) \ + USB_IFACE_CLASS(class), USB_IFACE_SUBCLASS(subclass), USB_DRIVER_INFO(info) + +#define USB_DRIVER_INFO(n) \ + .driver_info = (n) + +#define USB_GET_DRIVER_INFO(did) \ + (did)->driver_info + +/* + * The following structure keeps information that is used to match + * against an array of "usb_device_id" elements. + */ +struct usbd_lookup_info { + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t bIfaceIndex; + uint8_t bIfaceNum; + uint8_t bConfigIndex; + uint8_t bConfigNum; +}; + +/* Structure used by probe and attach */ +struct usb_attach_arg { + struct usbd_lookup_info info; + device_t temp_dev; /* for internal use */ + unsigned long driver_info; /* for internal use */ + void *driver_ivar; + struct usb_device *device; /* current device */ + struct usb_interface *iface; /* current interface */ + enum usb_hc_mode usb_mode; /* host or device mode */ + uint8_t port; + uint8_t dev_state; +#define UAA_DEV_READY 0 +#define UAA_DEV_DISABLED 1 +#define UAA_DEV_EJECTING 2 +}; + +/* + * The following is a wrapper for the callout structure to ease + * porting the code to other platforms. + */ +struct usb_callout { + struct callout co; +}; +#define usb_callout_init_mtx(c,m,f) callout_init_mtx(&(c)->co,m,f) +#define usb_callout_reset(c,t,f,d) callout_reset(&(c)->co,t,f,d) +#define usb_callout_stop(c) callout_stop(&(c)->co) +#define usb_callout_drain(c) callout_drain(&(c)->co) +#define usb_callout_pending(c) callout_pending(&(c)->co) + +/* USB transfer states */ +#define USB_ST_SETUP 0 +#define USB_ST_TRANSFERRED 1 +#define USB_ST_ERROR 2 + +/* + * The following macro will return the current state of an USB + * transfer like defined by the "USB_ST_XXX" enums. + */ +#define USB_GET_STATE(xfer) (usbd_xfer_state(xfer)) + +int usbd_lookup_id_by_uaa(const struct usb_device_id *id, + usb_size_t sizeof_id, struct usb_attach_arg *uaa); + +void device_set_usb_desc(device_t dev); + +const char *usbd_errstr(usb_error_t error); +void usb_pause_mtx(struct mtx *mtx, int _ticks); + +usb_error_t usbd_do_request_flags(struct usb_device* udev, struct mtx *mtx, + struct usb_device_request* req, void* data, uint16_t flags, + uint16_t *actlen, usb_timeout_t timeout); +#define usbd_do_request(u,m,r,d) \ + usbd_do_request_flags(u,m,r,d,0,NULL,USB_DEFAULT_TIMEOUT) + +void usb_pause_mtx(struct mtx *mtx, int _ticks); + +enum usb_dev_speed usbd_get_speed(struct usb_device* udev); + +void* usbd_xfer_softc(struct usb_xfer *xfer); +uint8_t usbd_xfer_state(struct usb_xfer *xfer); +usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer); +void usbd_xfer_set_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex, + void *ptr, usb_frlength_t len); +void usbd_xfer_set_stall(struct usb_xfer *xfer); +void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, + int *aframes, int *nframes); + +void usbd_transfer_submit(struct usb_xfer *xfer); +void usbd_transfer_start(struct usb_xfer *xfer); +void usbd_transfer_stop(struct usb_xfer *xfer); +void usbd_transfer_drain(struct usb_xfer* xfer); +usb_error_t usbd_transfer_setup(struct usb_device *udev, + const uint8_t *ifaces, struct usb_xfer **pxfer, + const struct usb_config *setup_start, uint16_t n_setup, + void *priv_sc, struct mtx *priv_mtx); +void usbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup); + +#endif /* _KERNEL */ +#endif /* _FBSD_COMPAT_USB_USBDI_H_ */ diff --git a/src/libs/compat/freebsd_network/device.h b/src/libs/compat/freebsd_network/device.h index e8a721997c..0b9d22b609 100644 --- a/src/libs/compat/freebsd_network/device.h +++ b/src/libs/compat/freebsd_network/device.h @@ -77,6 +77,12 @@ void uninit_callout(void); status_t init_pci(); void uninit_pci(); +status_t init_usb(); +void uninit_usb(); + +status_t get_next_usb_device(uint32* cookie, struct freebsd_usb_device* result); +status_t get_usb_device_attach_arg(struct freebsd_usb_device* device, struct usb_attach_arg* uaa); + device_t find_root_device(int); pci_info* get_device_pci_info(device_t dev); diff --git a/src/libs/compat/freebsd_network/fbsd_usb_error.c b/src/libs/compat/freebsd_network/fbsd_usb_error.c new file mode 100644 index 0000000000..8db07b343b --- /dev/null +++ b/src/libs/compat/freebsd_network/fbsd_usb_error.c @@ -0,0 +1,90 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef USB_GLOBAL_INCLUDE_FILE +#include USB_GLOBAL_INCLUDE_FILE +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#endif /* USB_GLOBAL_INCLUDE_FILE */ + +static const char* usb_errstr_table[USB_ERR_MAX] = { + [USB_ERR_NORMAL_COMPLETION] = "USB_ERR_NORMAL_COMPLETION", + [USB_ERR_PENDING_REQUESTS] = "USB_ERR_PENDING_REQUESTS", + [USB_ERR_NOT_STARTED] = "USB_ERR_NOT_STARTED", + [USB_ERR_INVAL] = "USB_ERR_INVAL", + [USB_ERR_NOMEM] = "USB_ERR_NOMEM", + [USB_ERR_CANCELLED] = "USB_ERR_CANCELLED", + [USB_ERR_BAD_ADDRESS] = "USB_ERR_BAD_ADDRESS", + [USB_ERR_BAD_BUFSIZE] = "USB_ERR_BAD_BUFSIZE", + [USB_ERR_BAD_FLAG] = "USB_ERR_BAD_FLAG", + [USB_ERR_NO_CALLBACK] = "USB_ERR_NO_CALLBACK", + [USB_ERR_IN_USE] = "USB_ERR_IN_USE", + [USB_ERR_NO_ADDR] = "USB_ERR_NO_ADDR", + [USB_ERR_NO_PIPE] = "USB_ERR_NO_PIPE", + [USB_ERR_ZERO_NFRAMES] = "USB_ERR_ZERO_NFRAMES", + [USB_ERR_ZERO_MAXP] = "USB_ERR_ZERO_MAXP", + [USB_ERR_SET_ADDR_FAILED] = "USB_ERR_SET_ADDR_FAILED", + [USB_ERR_NO_POWER] = "USB_ERR_NO_POWER", + [USB_ERR_TOO_DEEP] = "USB_ERR_TOO_DEEP", + [USB_ERR_IOERROR] = "USB_ERR_IOERROR", + [USB_ERR_NOT_CONFIGURED] = "USB_ERR_NOT_CONFIGURED", + [USB_ERR_TIMEOUT] = "USB_ERR_TIMEOUT", + [USB_ERR_SHORT_XFER] = "USB_ERR_SHORT_XFER", + [USB_ERR_STALLED] = "USB_ERR_STALLED", + [USB_ERR_INTERRUPTED] = "USB_ERR_INTERRUPTED", + [USB_ERR_DMA_LOAD_FAILED] = "USB_ERR_DMA_LOAD_FAILED", + [USB_ERR_BAD_CONTEXT] = "USB_ERR_BAD_CONTEXT", + [USB_ERR_NO_ROOT_HUB] = "USB_ERR_NO_ROOT_HUB", + [USB_ERR_NO_INTR_THREAD] = "USB_ERR_NO_INTR_THREAD", + [USB_ERR_NOT_LOCKED] = "USB_ERR_NOT_LOCKED", +}; + +/*------------------------------------------------------------------------* + * usbd_errstr + * + * This function converts an USB error code into a string. + *------------------------------------------------------------------------*/ +const char * +usbd_errstr(usb_error_t err) +{ + return (err < USB_ERR_MAX ? usb_errstr_table[err] : "USB_ERR_UNKNOWN"); +} diff --git a/src/libs/compat/freebsd_network/fbsd_usb_lookup.c b/src/libs/compat/freebsd_network/fbsd_usb_lookup.c new file mode 100644 index 0000000000..85245af2ba --- /dev/null +++ b/src/libs/compat/freebsd_network/fbsd_usb_lookup.c @@ -0,0 +1,216 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef USB_GLOBAL_INCLUDE_FILE +#include USB_GLOBAL_INCLUDE_FILE +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#endif /* USB_GLOBAL_INCLUDE_FILE */ + +/*------------------------------------------------------------------------* + * usbd_lookup_id_by_info + * + * This functions takes an array of "struct usb_device_id" and tries + * to match the entries with the information in "struct usbd_lookup_info". + * + * NOTE: The "sizeof_id" parameter must be a multiple of the + * usb_device_id structure size. Else the behaviour of this function + * is undefined. + * + * Return values: + * NULL: No match found. + * Else: Pointer to matching entry. + *------------------------------------------------------------------------*/ +const struct usb_device_id * +usbd_lookup_id_by_info(const struct usb_device_id *id, usb_size_t sizeof_id, + const struct usbd_lookup_info *info) +{ + const struct usb_device_id *id_end; + + if (id == NULL) { + goto done; + } + id_end = (const void *)(((const uint8_t *)id) + sizeof_id); + + /* + * Keep on matching array entries until we find a match or + * until we reach the end of the matching array: + */ + for (; id != id_end; id++) { + + if ((id->match_flag_vendor) && + (id->idVendor != info->idVendor)) { + continue; + } + if ((id->match_flag_product) && + (id->idProduct != info->idProduct)) { + continue; + } + if ((id->match_flag_dev_lo) && + (id->bcdDevice_lo > info->bcdDevice)) { + continue; + } + if ((id->match_flag_dev_hi) && + (id->bcdDevice_hi < info->bcdDevice)) { + continue; + } + if ((id->match_flag_dev_class) && + (id->bDeviceClass != info->bDeviceClass)) { + continue; + } + if ((id->match_flag_dev_subclass) && + (id->bDeviceSubClass != info->bDeviceSubClass)) { + continue; + } + if ((id->match_flag_dev_protocol) && + (id->bDeviceProtocol != info->bDeviceProtocol)) { + continue; + } + if ((id->match_flag_int_class) && + (id->bInterfaceClass != info->bInterfaceClass)) { + continue; + } + if ((id->match_flag_int_subclass) && + (id->bInterfaceSubClass != info->bInterfaceSubClass)) { + continue; + } + if ((id->match_flag_int_protocol) && + (id->bInterfaceProtocol != info->bInterfaceProtocol)) { + continue; + } + /* We found a match! */ + return (id); + } + +done: + return (NULL); +} + +/*------------------------------------------------------------------------* + * usbd_lookup_id_by_uaa - factored out code + * + * Return values: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +int +usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id, + struct usb_attach_arg *uaa) +{ + id = usbd_lookup_id_by_info(id, sizeof_id, &uaa->info); + if (id) { + /* copy driver info */ + uaa->driver_info = id->driver_info; + return (0); + } + return (ENXIO); +} + +/*------------------------------------------------------------------------* + * Export the USB device ID format we use to userspace tools. + *------------------------------------------------------------------------*/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define U16_XOR "0" +#else +#define U16_XOR "8" +#endif + +#if defined(KLD_MODULE) && (USB_HAVE_ID_SECTION != 0) +static const char __section("bus_autoconf_format") __used usb_id_format[] = { + + /* Declare that three different sections use the same format */ + + "usb_host_id{256,:}" + "usb_device_id{256,:}" + "usb_dual_id{256,:}" + + /* List size of fields in the usb_device_id structure */ + + "mf_vendor{" U16_XOR ",1}" + "mf_product{" U16_XOR ",1}" + "mf_dev_lo{" U16_XOR ",1}" + "mf_dev_hi{" U16_XOR ",1}" + + "mf_dev_class{" U16_XOR ",1}" + "mf_dev_subclass{" U16_XOR ",1}" + "mf_dev_protocol{" U16_XOR ",1}" + "mf_int_class{" U16_XOR ",1}" + + "mf_int_subclass{" U16_XOR ",1}" + "mf_int_protocol{" U16_XOR ",1}" + "unused{" U16_XOR ",6}" + + "idVendor[0]{" U16_XOR ",8}" + "idVendor[1]{" U16_XOR ",8}" + "idProduct[0]{" U16_XOR ",8}" + "idProduct[1]{" U16_XOR ",8}" + "bcdDevice_lo[0]{" U16_XOR ",8}" + "bcdDevice_lo[1]{" U16_XOR ",8}" + "bcdDevice_hi[0]{" U16_XOR ",8}" + "bcdDevice_hi[1]{" U16_XOR ",8}" + + "bDeviceClass{0,8}" + "bDeviceSubClass{0,8}" + "bDeviceProtocol{0,8}" + "bInterfaceClass{0,8}" + "bInterfaceSubClass{0,8}" + "bInterfaceProtocol{0,8}" + +#if USB_HAVE_COMPAT_LINUX + "mfl_vendor{" U16_XOR ",1}" + "mfl_product{" U16_XOR ",1}" + "mfl_dev_lo{" U16_XOR ",1}" + "mfl_dev_hi{" U16_XOR ",1}" + + "mfl_dev_class{" U16_XOR ",1}" + "mfl_dev_subclass{" U16_XOR ",1}" + "mfl_dev_protocol{" U16_XOR ",1}" + "mfl_int_class{" U16_XOR ",1}" + + "mfl_int_subclass{" U16_XOR ",1}" + "mfl_int_protocol{" U16_XOR ",1}" + "unused{" U16_XOR ",6}" +#endif +}; +#endif diff --git a/src/libs/compat/freebsd_network/fbsd_usb_util.c b/src/libs/compat/freebsd_network/fbsd_usb_util.c new file mode 100644 index 0000000000..e15c6b57aa --- /dev/null +++ b/src/libs/compat/freebsd_network/fbsd_usb_util.c @@ -0,0 +1,107 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/*------------------------------------------------------------------------* + * usb_pause_mtx - factored out code + * + * This function will delay the code by the passed number of system + * ticks. The passed mutex "mtx" will be dropped while waiting, if + * "mtx" is different from NULL. + *------------------------------------------------------------------------*/ +void +usb_pause_mtx(struct mtx *mtx, int timo) +{ + if (mtx != NULL) + mtx_unlock(mtx); + + /* + * Add one tick to the timeout so that we don't return too + * early! Note that pause() will assert that the passed + * timeout is positive and non-zero! + */ + pause("USBWAIT", timo + 1); + + if (mtx != NULL) + mtx_lock(mtx); +} + +/*------------------------------------------------------------------------* + * usb_printbcd + * + * This function will print the version number "bcd" to the string + * pointed to by "p" having a maximum length of "p_len" bytes + * including the terminating zero. + *------------------------------------------------------------------------*/ +void +usb_printbcd(char *p, uint16_t p_len, uint16_t bcd) +{ + if (snprintf(p, p_len, "%x.%02x", bcd >> 8, bcd & 0xff)) { + /* ignore any errors */ + } +} + +/*------------------------------------------------------------------------* + * usb_trim_spaces + * + * This function removes spaces at the beginning and the end of the string + * pointed to by the "p" argument. + *------------------------------------------------------------------------*/ +void +usb_trim_spaces(char *p) +{ + char *q; + char *e; + + if (p == NULL) + return; + q = e = p; + while (*q == ' ') /* skip leading spaces */ + q++; + while ((*p = *q++)) /* copy string */ + if (*p++ != ' ') /* remember last non-space */ + e = p; + *e = 0; /* kill trailing spaces */ +} diff --git a/src/libs/compat/freebsd_network/usb.cpp b/src/libs/compat/freebsd_network/usb.cpp new file mode 100644 index 0000000000..4086ee5e68 --- /dev/null +++ b/src/libs/compat/freebsd_network/usb.cpp @@ -0,0 +1,485 @@ +/* + * Copyright 2022, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + */ + +#include + +extern "C" { +#include +#include +#include +#include + +#include +#include +#include + +#include "device.h" +} + +// undo name remappings, so we can use both FreeBSD and Haiku ones in this file +#undef usb_device +#undef usb_interface +#undef usb_endpoint_descriptor + +#include + + +usb_module_info* sUSB = NULL; +struct taskqueue* sUSBTaskqueue = NULL; + + +status_t +init_usb() +{ + if (sUSB != NULL) + return B_OK; + + if (get_module(B_USB_MODULE_NAME, (module_info**)&sUSB) != B_OK) { + dprintf("cannot get module \"%s\"\n", B_USB_MODULE_NAME); + return B_ERROR; + } + return B_OK; +} + + +void +uninit_usb() +{ + if (sUSB != NULL) + put_module(B_USB_MODULE_NAME); + if (sUSBTaskqueue != NULL) + taskqueue_free(sUSBTaskqueue); + + sUSB = NULL; + sUSBTaskqueue = NULL; +} + + +status_t +get_next_usb_device(uint32* cookie, freebsd_usb_device* result) +{ + // We cheat here: since USB IDs are sequential, instead of doing a + // complicated parent/child iteration dance, we simply request device + // descriptors and let the USB stack figure out the rest. + // + // It would be better if we used USB->register_driver, but that is not + // an option at present for a variety of reasons... + const usb_configuration_info* config; + usb_device current; + while (*cookie < 1024) { + current = *cookie; + *cookie = *cookie + 1; + + config = sUSB->get_configuration(current); + if (config != NULL) + break; + } + if (config == NULL) + return ENODEV; + + result->haiku_usb_device = current; + result->endpoints_max = 0; + for (size_t i = 0; i < config->interface_count; i++) { + usb_interface_info* iface = config->interface[i].active; + for (size_t j = 0; j < iface->endpoint_count; j++) { + const int rep = result->endpoints_max++; + result->endpoints[rep].iface_index = i; + + static_assert(sizeof(freebsd_usb_endpoint_descriptor) + == sizeof(usb_endpoint_descriptor), "size mismatch"); + + if (result->endpoints[rep].edesc == NULL) + result->endpoints[rep].edesc = new freebsd_usb_endpoint_descriptor; + + memcpy(result->endpoints[rep].edesc, iface->endpoint[j].descr, + sizeof(usb_endpoint_descriptor)); + } + } + + return B_OK; +} + + +status_t +get_usb_device_attach_arg(struct freebsd_usb_device* device, struct usb_attach_arg* uaa) +{ + memset(uaa, 0, sizeof(struct usb_attach_arg)); + + const usb_device_descriptor* device_desc = + sUSB->get_device_descriptor(device->haiku_usb_device); + if (!device_desc) + return B_BAD_VALUE; + + uaa->info.idVendor = device_desc->vendor_id; + uaa->info.idProduct = device_desc->product_id; + uaa->info.bcdDevice = device_desc->device_version; + uaa->info.bDeviceClass = device_desc->device_class; + uaa->info.bDeviceSubClass = device_desc->device_subclass; + uaa->info.bDeviceProtocol = device_desc->device_protocol; + + const usb_configuration_info* config = sUSB->get_configuration(device->haiku_usb_device); + if (!device_desc) + return B_BAD_VALUE; + + // TODO: represent more than just interface[0], but how? + usb_interface_info* iface = config->interface[0].active; + + uaa->info.bInterfaceClass = iface->descr->interface_class; + uaa->info.bInterfaceSubClass = iface->descr->interface_subclass; + uaa->info.bInterfaceProtocol = iface->descr->interface_protocol; + + // TODO: bIface{Index,Num}, bConfig{Index,Num} + + uaa->device = device; + uaa->iface = NULL; + + // TODO: fetch values for these? + uaa->usb_mode = USB_MODE_HOST; + uaa->port = 1; + uaa->dev_state = UAA_DEV_READY; + + return B_OK; +} + + +void +usb_cleanup_device(freebsd_usb_device* udev) +{ + for (int i = 0; i < USB_MAX_EP_UNITS; i++) { + delete udev->endpoints[i].edesc; + udev->endpoints[i].edesc = NULL; + } +} + + +static usb_error_t +map_usb_error(status_t err) +{ + switch (err) { + case B_OK: return USB_ERR_NORMAL_COMPLETION; + case B_DEV_STALLED: return USB_ERR_STALLED; + case B_CANCELED: return USB_ERR_CANCELLED; + } + return USB_ERR_INVAL; +} + + +extern "C" usb_error_t +usbd_do_request_flags(struct freebsd_usb_device* udev, struct mtx* mtx, + struct usb_device_request* req, void* data, uint16_t flags, + uint16_t* actlen, usb_timeout_t timeout) +{ + if (mtx != NULL) + mtx_unlock(mtx); + + // FIXME: timeouts + // TODO: flags + + size_t actualLen = 0; + status_t ret = sUSB->send_request((usb_device)udev->haiku_usb_device, + req->bmRequestType, req->bRequest, + UGETW(req->wValue), UGETW(req->wIndex), UGETW(req->wLength), + data, &actualLen); + if (actlen) + *actlen = actualLen; + + if (mtx != NULL) + mtx_lock(mtx); + + return map_usb_error(ret); +} + + +enum usb_dev_speed +usbd_get_speed(struct freebsd_usb_device* udev) +{ + const usb_device_descriptor* descriptor = sUSB->get_device_descriptor( + (usb_device)udev->haiku_usb_device); + KASSERT(descriptor != NULL, ("no device")); + + if (descriptor->usb_version >= 0x0300) + return USB_SPEED_SUPER; + else if (descriptor->usb_version >= 0x200) + return USB_SPEED_HIGH; + else if (descriptor->usb_version >= 0x110) + return USB_SPEED_FULL; + else if (descriptor->usb_version >= 0x100) + return USB_SPEED_LOW; + + panic("unknown USB version!"); + return (usb_dev_speed)-1; +} + + +struct usb_xfer { + struct mtx* mutex; + void* priv_sc; + usb_callback_t* callback; + usb_xfer_flags flags; + usb_frlength_t max_data_length; + + usb_device device; + uint8 type; + usb_pipe pipe; + iovec* frames; + int nframes; + + uint8 usb_state; + bool in_progress; + status_t result; + int transferred_length; + + struct task invoker; + struct cv condition; +}; + + +extern "C" usb_error_t +usbd_transfer_setup(struct freebsd_usb_device* udev, + const uint8_t* ifaces, struct usb_xfer** ppxfer, + const struct usb_config* setup_start, uint16_t n_setup, + void* priv_sc, struct mtx* xfer_mtx) +{ + if (xfer_mtx == NULL) + xfer_mtx = &Giant; + + // Make sure the taskqueue exists. + if (sUSBTaskqueue == NULL) { + mtx_lock(&Giant); + if (sUSBTaskqueue == NULL) { + sUSBTaskqueue = taskqueue_create("usb taskq", 0, + taskqueue_thread_enqueue, &sUSBTaskqueue); + taskqueue_start_threads(&sUSBTaskqueue, 1, PZERO, "usb taskq"); + } + mtx_unlock(&Giant); + } + + const usb_configuration_info* device_config = sUSB->get_configuration( + (usb_device)udev->haiku_usb_device); + + for (const struct usb_config* setup = setup_start; + setup < (setup_start + n_setup); setup++) { + /* skip transfers w/o callbacks */ + if (setup->callback == NULL) + continue; + + struct usb_xfer* xfer = new usb_xfer; + xfer->mutex = xfer_mtx; + xfer->priv_sc = priv_sc; + xfer->callback = setup->callback; + xfer->flags = setup->flags; + xfer->max_data_length = setup->bufsize; + + xfer->device = (usb_device)udev->haiku_usb_device; + xfer->type = setup->type; + + xfer->pipe = -1; + uint8_t endpoint = setup->endpoint; + uint8_t iface_index = ifaces[setup->if_index]; + if (endpoint == UE_ADDR_ANY) { + for (int i = 0; i < udev->endpoints_max; i++) { + if (UE_GET_XFERTYPE(udev->endpoints[i].edesc->bmAttributes) != xfer->type) + continue; + + endpoint = udev->endpoints[i].edesc->bEndpointAddress; + break; + } + } + usb_interface_info* iface = device_config->interface[iface_index].active; + for (int i = 0; i < iface->endpoint_count; i++) { + if (iface->endpoint[i].descr->endpoint_address != endpoint) + continue; + + xfer->pipe = iface->endpoint[i].handle; + break; + } + if (xfer->pipe == -1) + panic("failed to locate endpoint!"); + + xfer->nframes = setup->frames; + if (xfer->nframes == 0) + xfer->nframes = 1; + xfer->frames = (iovec*)calloc(xfer->nframes, sizeof(iovec)); + + xfer->usb_state = USB_ST_SETUP; + xfer->in_progress = false; + xfer->transferred_length = 0; + cv_init(&xfer->condition, "FreeBSD USB transfer"); + + if (xfer->flags.proxy_buffer) + panic("not yet supported"); + + ppxfer[setup - setup_start] = xfer; + } + + return USB_ERR_NORMAL_COMPLETION; +} + + +extern "C" void +usbd_transfer_unsetup(struct usb_xfer** pxfer, uint16_t n_setup) +{ + for (int i = 0; i < n_setup; i++) { + struct usb_xfer* xfer = pxfer[i]; + usbd_transfer_drain(xfer); + cv_destroy(&xfer->condition); + free(xfer->frames); + delete xfer; + } +} + + +extern "C" usb_frlength_t +usbd_xfer_max_len(struct usb_xfer* xfer) +{ + return xfer->max_data_length; +} + + +extern "C" void* +usbd_xfer_softc(struct usb_xfer* xfer) +{ + return xfer->priv_sc; +} + + +extern "C" uint8_t +usbd_xfer_state(struct usb_xfer* xfer) +{ + return xfer->usb_state; +} + + +extern "C" void +usbd_xfer_set_frame_data(struct usb_xfer* xfer, + usb_frcount_t frindex, void* ptr, usb_frlength_t len) +{ + KASSERT(frindex < uint32_t(xfer->nframes), ("frame index overflow")); + + xfer->frames[frindex].iov_base = ptr; + xfer->frames[frindex].iov_len = len; +} + + +extern "C" void +usbd_xfer_set_stall(struct usb_xfer *xfer) +{ + // Not needed? +} + + +static void +usbd_invoker(void* arg, int pending) +{ + struct usb_xfer* xfer = (struct usb_xfer*)arg; + mtx_lock(xfer->mutex); + xfer->in_progress = false; + xfer->usb_state = (xfer->result == B_OK) ? USB_ST_TRANSFERRED : USB_ST_ERROR; + xfer->callback(xfer, map_usb_error(xfer->result)); + mtx_unlock(xfer->mutex); + cv_signal(&xfer->condition); +} + + +static void +usbd_callback(void* arg, status_t status, void* data, size_t actualLength) +{ + struct usb_xfer* xfer = (struct usb_xfer*)arg; + xfer->result = status; + xfer->transferred_length = actualLength; + + TASK_INIT(&xfer->invoker, 0, usbd_invoker, xfer); + taskqueue_enqueue(sUSBTaskqueue, &xfer->invoker); +} + + +extern "C" void +usbd_transfer_start(struct usb_xfer* xfer) +{ + if (xfer->in_progress) + return; + + xfer->usb_state = USB_ST_SETUP; + xfer->callback(xfer, USB_ERR_NOT_STARTED); +} + + +extern "C" void +usbd_transfer_submit(struct usb_xfer* xfer) +{ + KASSERT(!xfer->in_progress, ("cannot submit in-progress transfer!")); + + xfer->transferred_length = 0; + xfer->in_progress = true; + switch (xfer->type) { + case UE_BULK: + sUSB->queue_bulk_v(xfer->pipe, xfer->frames, xfer->nframes, usbd_callback, xfer); + break; + + case UE_INTERRUPT: + KASSERT(xfer->nframes == 1, ("invalid frame count for interrupt transfer")); + sUSB->queue_interrupt(xfer->pipe, xfer->frames[0].iov_base, xfer->frames[0].iov_len, + usbd_callback, xfer); + break; + + default: + panic("unhandled pipe type %d", xfer->type); + } +} + + +extern "C" void +usbd_transfer_stop(struct usb_xfer* xfer) +{ + if (xfer == NULL) + return; + mtx_assert(xfer->mutex, MA_OWNED); + + if (!xfer->in_progress) + return; + + // Unfortunately we have no way of cancelling just one transfer. + sUSB->cancel_queued_transfers(xfer->pipe); +} + + +extern "C" void +usbd_transfer_drain(struct usb_xfer* xfer) +{ + if (xfer == NULL) + return; + + mtx_lock(xfer->mutex); + usbd_transfer_stop(xfer); + while (xfer->in_progress) + cv_wait(&xfer->condition, xfer->mutex); + mtx_unlock(xfer->mutex); +} + + +extern "C" void +usbd_xfer_status(struct usb_xfer* xfer, int* actlen, int* sumlen, int* aframes, int* nframes) +{ + if (actlen) + *actlen = xfer->transferred_length; + if (sumlen) { + int sum = 0; + for (int i = 0; i < xfer->nframes; i++) + sum += xfer->frames[i].iov_len; + *sumlen = sum; + } + if (aframes) { + int length = xfer->transferred_length; + int frames = 0; + for (int i = 0; i < xfer->nframes && length > 0; i++) { + length -= xfer->frames[i].iov_len; + if (length >= 0) + frames++; + } + *aframes = frames; + } + if (nframes) + *nframes = xfer->nframes; +} diff --git a/src/libs/compat/freebsd_network/usb_util.c b/src/libs/compat/freebsd_network/usb_util.c new file mode 100644 index 0000000000..c5ecbd9a74 --- /dev/null +++ b/src/libs/compat/freebsd_network/usb_util.c @@ -0,0 +1,44 @@ +/* + * Copyright 2022, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + */ + +#include +#include +#include + +#include +#include + + +/** device_set_usb_desc + * This function can be called at probe or attach to set the USB + * device supplied textual description for the given device. */ +void +device_set_usb_desc(device_t dev) +{ + struct usb_attach_arg *uaa; + struct usb_device *udev; + struct usb_interface *iface; + usb_error_t err; + + if (dev == NULL) { + /* should not happen */ + return; + } + uaa = device_get_ivars(dev); + if (uaa == NULL) { + /* can happen if called at the wrong time */ + return; + } + udev = uaa->device; + iface = uaa->iface; + + if ((iface == NULL)) { + err = USB_ERR_INVAL; + } else { + err = 0; + } + + /* TODO */ +}