freebsd_network: Introduce USB-handling code.
It is not yet wired in to the rest of the compatibilit layer; that will happen in the next commits. The bulk of the implementation is in usb.cpp; most of the rest of the new files are copied from FreeBSD to varying degrees.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2018-2019, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Augustin Cavalier <waddlesplash>
|
||||
*/
|
||||
#ifndef _FBSD_COMPAT_USB_STANDARD_H_
|
||||
#define _FBSD_COMPAT_USB_STANDARD_H_
|
||||
|
||||
#include <sys/malloc.h>
|
||||
|
||||
MALLOC_DECLARE(M_USB);
|
||||
MALLOC_DECLARE(M_USBDEV);
|
||||
|
||||
#include <dev/usb/usb_endian.h>
|
||||
#include <dev/usb/usb_haiku.h>
|
||||
|
||||
#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_
|
||||
@@ -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_ */
|
||||
@@ -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_
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2020, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Augustin Cavalier <waddlesplash>
|
||||
*/
|
||||
#ifndef _USB_ENDIAN_H_
|
||||
#define _USB_ENDIAN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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_ */
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2018, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Augustin Cavalier <waddlesplash>
|
||||
*/
|
||||
#ifndef _FBSD_COMPAT_USB_HAIKU_H_
|
||||
#define _FBSD_COMPAT_USB_HAIKU_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
/* 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_
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/callout.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/priv.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#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");
|
||||
}
|
||||
@@ -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 <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/callout.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#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
|
||||
@@ -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 <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/callout.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/priv.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
|
||||
#include <dev/usb/usb_device.h>
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* 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 */
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Copyright 2022, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include <sys/condvar.h>
|
||||
|
||||
extern "C" {
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/taskqueue.h>
|
||||
#include <sys/priority.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usb_device.h>
|
||||
|
||||
#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 <USB3.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2022, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/callout.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
|
||||
|
||||
/** 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 */
|
||||
}
|
||||
Reference in New Issue
Block a user