Bring in USB4BSD, Hans Petter Selasky rework of the USB stack

that includes significant features and SMP safety.

This commit includes a more or less complete rewrite of the *BSD USB
stack, including Host Controller and Device Controller drivers and
updating all existing USB drivers to use the new USB API:

1) A brief feature list:

  - A new and mutex enabled USB API.

  - Many USB drivers are now running Giant free.

  - Linux USB kernel compatibility layer.

  - New UGEN backend and libusb library, finally solves the "driver
    unloading" problem. The new BSD licensed libusb20 library is fully
    compatible with libusb-0.1.12 from sourceforge.

  - New "usbconfig" utility, for easy configuration of USB.

  - Full support for Split transactions, which means you can use your
    full speed USB audio device on a high speed USB HUB.

  - Full support for HS ISOC transactions, which makes writing drivers
    for various HS webcams possible, for example.

  - Full support for USB on embedded platforms, mostly cache flushing
    and buffer invalidating stuff.

  - Safer parsing of USB descriptors.

  - Autodetect of annoying USB install disks.

  - Support for USB device side mode, also called USB gadget mode,
    using the same API like the USB host side. In other words the new
    USB stack is symmetric with regard to host and device side.

  - Support for USB transfers like I/O vectors, means more throughput
    and less interrupts.

  - ... see the FreeBSD quarterly status reports under "USB project"

2) To enable the driver in the default kernel build:

2.a) Remove all existing USB device options from your kernel config
file.

2.b) Add the following USB device options to your kernel configuration
file:

# USB core support
device          usb2_core

# USB controller support
device		usb2_controller
device		usb2_controller_ehci
device		usb2_controller_ohci
device		usb2_controller_uhci

# USB mass storage support
device		usb2_storage
device		usb2_storage_mass

# USB ethernet support, requires miibus
device		usb2_ethernet
device		usb2_ethernet_aue
device		usb2_ethernet_axe
device		usb2_ethernet_cdce
device		usb2_ethernet_cue
device		usb2_ethernet_kue
device		usb2_ethernet_rue
device		usb2_ethernet_dav

# USB wireless LAN support
device		usb2_wlan
device		usb2_wlan_rum
device		usb2_wlan_ral
device		usb2_wlan_zyd

# USB serial device support
device		usb2_serial
device		usb2_serial_ark
device		usb2_serial_bsa
device		usb2_serial_bser
device		usb2_serial_chcom
device		usb2_serial_cycom
device		usb2_serial_foma
device		usb2_serial_ftdi
device		usb2_serial_gensa
device		usb2_serial_ipaq
device		usb2_serial_lpt
device		usb2_serial_mct
device		usb2_serial_modem
device		usb2_serial_moscom
device		usb2_serial_plcom
device		usb2_serial_visor
device		usb2_serial_vscom

# USB bluetooth support
device		usb2_bluetooth
device		usb2_bluetooth_ng

# USB input device support
device		usb2_input
device		usb2_input_hid
device		usb2_input_kbd
device		usb2_input_ms

# USB sound and MIDI device support
device		usb2_sound

2) To enable the driver at runtime:

2.a) Unload all existing USB modules. If USB is compiled into the
kernel then you might have to build a new kernel.

2.b) Load the "usb2_xxx.ko" modules under /boot/kernel having the same
base name like the kernel device option.

Submitted by: Hans Petter Selasky hselasky at c2i dot net
Reviewed by: imp, alfred
This commit is contained in:
Alfred Perlstein 2008-11-04 02:31:03 +00:00
parent 68b2399298
commit eabe30fc9c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=184610
270 changed files with 136537 additions and 3 deletions

24
lib/libusb20/Makefile Normal file
View File

@ -0,0 +1,24 @@
#
# $FreeBSD$
#
# Makefile for the FreeBSD specific LibUSB 2.0
#
LIB= usb20
SHLIB_MAJOR= 1
SHLIB_MINOR= 0
SRCS= libusb20.c
SRCS+= libusb20_desc.c
SRCS+= libusb20_ugen20.c
SRCS+= libusb20_compat01.c
SRCS+= libusb20_compat10.c
INCS+= libusb20.h
INCS+= libusb20_desc.h
INCS+= libusb20_compat01.h
INCS+= libusb20_compat10.h
MAN= libusb20.3
MKLINT= no
NOGCCERROR=
.include <bsd.lib.mk>

893
lib/libusb20/libusb20.3 Normal file
View File

@ -0,0 +1,893 @@
.\"
.\" 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.
.\"
.\" $FreeBSD$
.\"
.Dd Oct 23, 2008
.Dt LIBUSB20 3
.Os
.Sh NAME
.Nm libusb20
.
.Nd "USB access library"
.
.
.Sh LIBRARY
.
.
USB access library (libusb20 -lusb20)
.
.
.
.Sh SYNOPSIS
.
.
.In libusb20.h
.
.
.Sh DESCRIPTION
.
The
.Nm
library implements functions to be able to easily access and control
USB through the USB file system interface.
.
.
.Sh USB TRANSFER OPERATIONS
.
.Pp
.
.Fn libusb20_tr_close
This function will release all kernel resources associated with an USB
.Fa xfer .
.
This function returns zero upon success.
.
Non-zero return values indicate a LIBUSB20_ERROR value.
.
.Pp
.
.Fn libusb20_tr_open
This function will allocate kernel resources like
.Fa MaxBufSize
and
.Fa MaxFrameCount
associated with an USB
.Fa xfer
and bind the transfer to the specified
.Fa ep_no .
.
This function returns zero upon success.
.
Non-zero return values indicate a LIBUSB20_ERROR value.
.
.Pp
.
.Fn libusb20_tr_get_pointer
This function will return a pointer to the allocated USB transfer according to the
.Fa pdev
and
.Fa tr_index
arguments.
.
This function returns NULL in case of failure.
.
.Pp
.
.Fn libusb20_tr_get_time_complete
This function will return the completion time of an USB transfer in
millisecond units. This function is most useful for isochronous USB
transfers when doing echo cancelling.
.
.Pp
.
.Fn libusb20_tr_get_actual_frames
This function will return the actual number of USB frames after an USB
transfer completed. A value of zero means that no data was transferred.
.
.Pp
.
.Fn libusb20_tr_get_actual_length
This function will return the sum of the actual length for all
transferred USB frames for the given USB transfer.
.
.Pp
.
.Fn libusb20_tr_get_max_frames
This function will return the maximum number of USB frames that were
allocated when an USB transfer was setup for the given USB transfer.
.
.Pp
.
.Fn libusb20_tr_get_max_packet_length
This function will return the maximum packet length in bytes
associated with the given USB transfer.
.
The packet length can be used round up buffer sizes so that short USB
packets are avoided for proxy buffers.
.
.
.Pp
.
.Fn libusb20_tr_get_max_total_length
This function will return the maximum value for the length sum of all
USB frames associated with an USB transfer.
.
.Pp
.
.Fn libusb20_tr_get_status
This function will return the status of an USB transfer.
.
Status values are defined by a set of LIBUSB20_TRANSFER_XXX enums.
.
.Pp
.
.Fn libusb20_tr_pending
This function will return non-zero if the given USB transfer is
pending for completion.
.
Else this function returns zero.
.
.Pp
.
.Fn libusb20_tr_callback_wrapper
This is an internal function used to wrap asynchronous USB callbacks.
.
.Pp
.
.Fn libusb20_tr_clear_stall_sync
This is an internal function used to synchronously clear the stall on
the given USB transfer.
.
Please see the USB specification for more information on stall
clearing.
.
If the given USB transfer is pending when this function is called, the
USB transfer will complete with an error after that this function has
been called.
.
.Pp
.
.Fn libusb20_tr_drain
This function will stop the given USB transfer and will not return
until the USB transfer has been stopped in hardware.
.
.Pp
.
.Fn libusb20_tr_set_buffer
This function is used to set the
.Fa buffer
pointer for the given USB transfer and
.Fa fr_index .
.
Typically the frame index is zero.
.
.
.Pp
.
.Fn libusb20_tr_set_callback
This function is used to set the USB callback for asynchronous USB
transfers.
.
The callback type is defined by libusb20_tr_callback_t.
.
.Pp
.
.Fn libusb20_tr_set_flags
This function is used to set various USB flags for the given USB transfer.
.Bl -tag
.It LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK
Report a short frame as error.
.It LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK
Multiple short frames are not allowed.
.It LIBUSB20_TRANSFER_FORCE_SHORT
All transmitted frames are short terminated.
.It LIBUSB20_TRANSFER_DO_CLEAR_STALL
Will do a clear-stall before starting the transfer.
.El
.
.Pp
.
.Fn libusb20_tr_set_length
This function sets the length of a given USB transfer and frame index.
.
.Pp
.
.Fn libusb20_tr_set_priv_sc0
This function sets private driver pointer number zero.
.
.Pp
.
.Fn libusb20_tr_set_priv_sc1
This function sets private driver pointer number one.
.
.Pp
.
.Fn libusb20_tr_set_timeout
This function sets the timeout for the given USB transfer.
.
A timeout value of zero means no timeout.
.
The timeout is given in milliseconds.
.
.Pp
.
.Fn libusb20_tr_set_total_frames
This function sets the total number of frames that should be executed when the USB transfer is submitted.
.
The total number of USB frames must be less than the maximum number of USB frames associated with the given USB transfer.
.
.Pp
.
.Fn libusb20_tr_setup_bulk
This function is a helper function for setting up a single frame USB BULK transfer.
.
.Pp
.
.Fn libusb20_tr_setup_control
This function is a helper function for setting up a single or dual
frame USB CONTROL transfer depending on the control transfer length.
.
.Pp
.
.Fn libusb20_tr_setup_intr
This function is a helper function for setting up a single frame USB INTERRUPT transfer.
.
.Pp
.
.Fn libusb20_tr_setup_isoc
This function is a helper function for setting up a multi frame USB ISOCHRONOUS transfer.
.
.Pp
.
.Fn libusb20_tr_start
This function will get the USB transfer started, if not already
started.
.
This function will not get the transfer queued in hardware.
.
This function is non-blocking.
.
.Pp
.
.Fn libusb20_tr_stop
This function will get the USB transfer stopped, if not already stopped.
.
This function is non-blocking, which means that the actual stop can
happen after the return of this function.
.
.Pp
.
.Fn libusb20_tr_submit
This function will get the USB transfer queued in hardware.
.
.
.Pp
.
.Fn libusb20_tr_get_priv_sc0
This function returns private driver pointer number zero associated
with an USB transfer.
.
.
.Pp
.
.Fn libusb20_tr_get_priv_sc1
This function returns private driver pointer number one associated
with an USB transfer.
.
.
.Sh USB DEVICE OPERATIONS
.
.Pp
.
.Fn libusb20_dev_get_backend_name
This function returns a zero terminated string describing the backend used.
.
.Pp
.
.Fn libusb20_dev_get_desc
This function returns a zero terminated string describing the given USB device.
.
.Pp
.
.Fn libusb20_dev_claim_interface
This function will try to claim the given USB interface given by
.Fa iface_index .
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_close
This function will close the given USB device.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_detach_kernel_driver
This function will try to detach the kernel driver for the USB interface given by
.Fa iface_index .
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_set_config_index
This function will try to set the configuration index on an USB
device.
.
The first configuration index is zero.
.
The un-configure index is 255.
.
This function returns zero on success else a LIBUSB20_ERROR value is returned.
.
.Pp
.
.Fn libusb20_dev_get_debug
This function returns the debug level of an USB device.
.
.Pp
.
.Fn libusb20_dev_get_fd
This function returns the file descriptor of the given USB device.
.
A negative value is returned when no file descriptor is present.
.
The file descriptor can be used for polling purposes.
.
.Pp
.
.Fn libusb20_dev_kernel_driver_active
This function returns a non-zero value if a kernel driver is active on
the given USB interface.
.
Else zero is returned.
.
.Pp
.
.Fn libusb20_dev_open
This function opens an USB device so that setting up USB transfers
becomes possible.
.
The number of USB transfers can be zero which means only control
transfers are allowed.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
A return value of LIBUSB20_ERROR_BUSY means that the device is already
opened.
.
.Pp
.
.Fn libusb20_dev_process
This function is called to sync kernel USB transfers with userland USB
transfers.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned typically indicating that the given USB device has been
detached.
.
.Pp
.
.Fn libusb20_dev_release_interface
This function will try to release a claimed USB interface for the specified USB device.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_request_sync
This function will perform a synchronous control request on the given
USB device.
.
Before this call will succeed the USB device must be opened.
.
.Fa setup
is a pointer to a decoded and host endian SETUP packet.
.Fa data
is a pointer to a data transfer buffer associated with the control transaction. This argument can be NULL.
.Fa pactlen
is a pointer to a variable that will hold the actual transfer length after the control transaction is complete.
.Fa timeout
is the transaction timeout given in milliseconds.
A timeout of zero means no timeout.
.Fa flags
is used to specify transaction flags, for example LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_req_string_sync
This function will synchronously request an USB string by language ID
and string index into the given buffer limited by a maximum length.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_req_string_simple_sync
This function will synchronously request an USB string using the
default language ID and convert the string into ASCII before storing
the string into the given buffer limited by a maximum length which
includes the terminating zero.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.
.Pp
.
.Fn libusb20_dev_reset
This function will try to BUS reset the given USB device and restore
the last set USB configuration.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_set_power_mode
This function sets the power mode of the USB device.
.
Valid power modes:
.Bl -tag
.It LIBUSB20_POWER_OFF
.It LIBUSB20_POWER_ON
.It LIBUSB20_POWER_SAVE
.It LIBUSB20_POWER_SUSPEND
.It LIBUSB20_POWER_RESUME
.El
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_get_power_mode
This function returns the currently selected power mode for the given
USB device.
.
.Pp
.
.Fn libusb20_dev_set_alt_index
This function will try to set the given alternate index for the given
USB interface index.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_set_owner
This function will set the ownership of the given USB device.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_set_perm
This function will set the permissions of the given USB device.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_set_iface_owner
This function will set the ownership of the given USB interface.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_set_iface_perm
This function will set the permissions of the given USB interface.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_get_owner
This function will retrieve the current USB device ownership.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_get_perm
This function will retrieve the current USB device permissions.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_get_iface_owner
This function will retrieve the current USB interface ownership for
the given USB interface.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_get_iface_perm
This function will retrieve the current USB interface permissions for
the given USB interface.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_dev_get_device_desc
This function returns a pointer to the decoded and host endian version
of the device descriptor.
.
The USB device need not be opened when calling this function.
.
.Pp
.
.Fn libusb20_dev_alloc_config
This function will read out and decode the USB config descriptor for
the given USB device and config index. This function returns a pointer
to the decoded configuration which must eventually be passed to
free(). NULL is returned in case of failure.
.
.Pp
.
.Fn libusb20_dev_alloc(void)
This is an internal function to allocate a new USB device.
.
.Pp
.
.Fn libusb20_dev_get_address
This function returns the internal and not necessarily the real
hardware address of the given USB device.
.
.Pp
.
.Fn libusb20_dev_get_bus_number
This function return the internal bus number which the given USB
device belongs to.
.
.Pp
.
.Fn libusb20_dev_get_mode
This function returns the current operation mode of the USB entity.
.
Valid return values are:
.Bl -tag
.It LIBUSB20_MODE_HOST
.It LIBUSB20_MODE_DEVICE
.El
.
.Pp
.
.Fn libusb20_dev_get_speed
This function returns the current speed of the given USB device.
.
.Bl -tag
.It LIBUSB20_SPEED_UNKNOWN
.It LIBUSB20_SPEED_LOW
.It LIBUSB20_SPEED_FULL
.It LIBUSB20_SPEED_HIGH
.It LIBUSB20_SPEED_VARIABLE
.It LIBUSB20_SPEED_SUPER
.El
.
.Pp
.
.Fn libusb20_dev_get_config_index
This function returns the currently select config index for the given
USB device.
.
.Pp
.
.Fn libusb20_dev_free
This function will free the given USB device and all associated USB
transfers.
.
.Pp
.
.Fn libusb20_dev_set_debug
This function will set the debug level for the given USB device.
.
.Pp
.
.Fn libusb20_dev_wait_process
This function will wait until a pending USB transfer has completed on
the given USB device.
.
A timeout value can be specified which is passed on to the
.Xr 2 poll
function.
.
.Sh USB BUS OPERATIONS
.
.Fn libusb20_bus_set_owner
This function will set the ownership for the given USB bus.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_bus_set_perm
This function will set the permissions for the given USB bus.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_bus_get_owner
This function will retrieve the ownership for the given USB bus.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_bus_get_perm
This function will retrieve the permissions for the given USB bus.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.
.Sh USB BACKEND OPERATIONS
.
.Fn libusb20_be_get_dev_quirk
This function will return the device quirk according to
.Fa index
into the libusb20_quirk structure pointed to by
.Fa pq .
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
If the given quirk does not exist LIBUSB20_ERROR_NOT_FOUND is
returned.
.
.Pp
.
.Fn libusb20_be_get_quirk_name
This function will return the quirk name according to
.Fa index
into the libusb20_quirk structure pointed to by
.Fa pq .
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
If the given quirk does not exist LIBUSB20_ERROR_NOT_FOUND is
returned.
.
.Pp
.
.Fn libusb20_be_add_dev_quirk
This function will add the libusb20_quirk structure pointed to by the
.Fa pq
argument into the device quirk list.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
If the given quirk cannot be added LIBUSB20_ERROR_NO_MEM is
returned.
.
.Pp
.
.Fn libusb20_be_remove_dev_quirk
This function will remove the quirk matching the libusb20_quirk structure pointed to by the
.Fa pq
argument from the device quirk list.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
If the given quirk does not exist LIBUSB20_ERROR_NOT_FOUND is
returned.
.
.Pp
.
.Fn libusb20_be_set_owner
This function will set the ownership for the given backend.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_be_set_perm
This function will set the permissions for the given backend.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_be_get_owner
This function will retrieve the ownership of the given backend.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_be_get_perm
This function will retrieve the permissions of the given backend.
.
.
This function returns zero on success else a LIBUSB20_ERROR value is
returned.
.
.Pp
.
.Fn libusb20_be_alloc
This is an internal function to allocate a USB backend.
.
.Pp
.Fn libusb20_be_alloc_default
.Fn libusb20_be_alloc_freebsd
.Fn libusb20_be_alloc_linux
These functions are used to allocate a specific USB backend or the
operating system default USB backend. Allocating a backend is a way to
scan for currently present USB devices.
.
.Pp
.
.Fn libusb20_be_device_foreach
This function is used to iterate USB devices present in a USB backend.
.
The starting value of
.Fa pdev
is NULL.
.
This function returns the next USB device in the list.
.
If NULL is returned the end of the USB device list has been reached.
.
.Pp
.
.Fn libusb20_be_dequeue_device
This function will dequeue the given USB device pointer from the
backend USB device list.
.
Dequeued USB devices will not be freed when the backend is freed.
.
.Pp
.
.Fn libusb20_be_enqueue_device
This function will enqueue the given USB device pointer in the backend USB device list.
.
Enqueued USB devices will get freed when the backend is freed.
.
.Pp
.
.Fn libusb20_be_free
This function will free the given backend and all USB devices in its device list.
.
.
.Sh USB DESCRIPTOR PARSING
.
.Fn libusb20_me_get_1
This function will return a byte at the given byte offset of a message
entity.
.
This function is safe against invalid offsets.
.
.Pp
.
.Fn libusb20_me_get_2
This function will return a little endian 16-bit value at the given byte offset of a message
entity.
.
This function is safe against invalid offsets.
.
.Pp
.
.Fn libusb20_me_encode
This function will encode a so-called *DECODED structure into binary
format.
.
The total encoded length that will fit in the given buffer is
returned.
.
If the buffer pointer is NULL no data will be written to the buffer
location.
.
.Pp
.
.Fn libusb20_me_decode
This function will decode a binary structure into a so-called *DECODED
structure.
.
The total decoded length is returned.
.
The buffer pointer cannot be NULL.
.
.
.Sh LIBUSB VERSION 0.1 COMPATIBILITY
.
.Fn usb_open
.Fn usb_close
.Fn usb_get_string
.Fn usb_get_string_simple
.Fn usb_get_descriptor_by_endpoint
.Fn usb_get_descriptor
.Fn usb_parse_descriptor
.Fn usb_parse_configuration
.Fn usb_destroy_configuration
.Fn usb_fetch_and_parse_descriptors
.Fn usb_bulk_write
.Fn usb_bulk_read
.Fn usb_interrupt_write
.Fn usb_interrupt_read
.Fn usb_control_msg
.Fn usb_set_configuration
.Fn usb_claim_interface
.Fn usb_release_interface
.Fn usb_set_altinterface
.Fn usb_resetep
.Fn usb_clear_halt
.Fn usb_reset
.Fn usb_strerror
.Fn usb_init
.Fn usb_set_debug
.Fn usb_find_busses
.Fn usb_find_devices
.Fn usb_device
.Fn usb_get_busses
These functions are compliant with LibUSB version 0.1.12.
.
.Sh FILES
.
.
/dev/usb
.Sh SEE ALSO
.Xr usb2_core 4 ,
.Xr usbconfig 8
.
.
.Sh HISTORY
.
.
Some parts of the
.Nm
API derives from the libusb project at sourceforge.

1245
lib/libusb20/libusb20.c Normal file

File diff suppressed because it is too large Load Diff

313
lib/libusb20/libusb20.h Normal file
View File

@ -0,0 +1,313 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
* Copyright (c) 2007-2008 Daniel Drake. All rights reserved.
* Copyright (c) 2001 Johannes Erdfelt. 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.
*/
#ifndef _LIBUSB20_H_
#define _LIBUSB20_H_
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/endian.h>
#ifdef __cplusplus
extern "C" {
#endif
#if 0
}; /* style */
#endif
/** \ingroup misc
* Error codes. Most libusb20 functions return 0 on success or one of
* these codes on failure.
*/
enum libusb20_error {
/** Success (no error) */
LIBUSB20_SUCCESS = 0,
/** Input/output error */
LIBUSB20_ERROR_IO = -1,
/** Invalid parameter */
LIBUSB20_ERROR_INVALID_PARAM = -2,
/** Access denied (insufficient permissions) */
LIBUSB20_ERROR_ACCESS = -3,
/** No such device (it may have been disconnected) */
LIBUSB20_ERROR_NO_DEVICE = -4,
/** Entity not found */
LIBUSB20_ERROR_NOT_FOUND = -5,
/** Resource busy */
LIBUSB20_ERROR_BUSY = -6,
/** Operation timed out */
LIBUSB20_ERROR_TIMEOUT = -7,
/** Overflow */
LIBUSB20_ERROR_OVERFLOW = -8,
/** Pipe error */
LIBUSB20_ERROR_PIPE = -9,
/** System call interrupted (perhaps due to signal) */
LIBUSB20_ERROR_INTERRUPTED = -10,
/** Insufficient memory */
LIBUSB20_ERROR_NO_MEM = -11,
/** Operation not supported or unimplemented on this platform */
LIBUSB20_ERROR_NOT_SUPPORTED = -12,
/** Other error */
LIBUSB20_ERROR_OTHER = -99,
};
/** \ingroup asyncio
* libusb20_tr_get_status() values */
enum libusb20_transfer_status {
/** Transfer completed without error. Note that this does not
* indicate that the entire amount of requested data was
* transferred. */
LIBUSB20_TRANSFER_COMPLETED,
/** Callback code to start transfer */
LIBUSB20_TRANSFER_START,
/** Drain complete callback code */
LIBUSB20_TRANSFER_DRAINED,
/** Transfer failed */
LIBUSB20_TRANSFER_ERROR,
/** Transfer timed out */
LIBUSB20_TRANSFER_TIMED_OUT,
/** Transfer was cancelled */
LIBUSB20_TRANSFER_CANCELLED,
/** For bulk/interrupt endpoints: halt condition detected
* (endpoint stalled). For control endpoints: control request
* not supported. */
LIBUSB20_TRANSFER_STALL,
/** Device was disconnected */
LIBUSB20_TRANSFER_NO_DEVICE,
/** Device sent more data than requested */
LIBUSB20_TRANSFER_OVERFLOW,
};
/** \ingroup asyncio
* libusb20_tr_set_flags() values */
enum libusb20_transfer_flags {
/** Report a short frame as error */
LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK = 0x0001,
/** Multiple short frames are not allowed */
LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK = 0x0002,
/** All transmitted frames are short terminated */
LIBUSB20_TRANSFER_FORCE_SHORT = 0x0004,
/** Will do a clear-stall before xfer */
LIBUSB20_TRANSFER_DO_CLEAR_STALL = 0x0008,
};
/** \ingroup misc
* libusb20_dev_get_mode() values
*/
enum libusb20_device_mode {
LIBUSB20_MODE_HOST, /* default */
LIBUSB20_MODE_DEVICE,
};
/** \ingroup misc
* libusb20_dev_get_speed() values
*/
enum {
LIBUSB20_SPEED_UNKNOWN, /* default */
LIBUSB20_SPEED_LOW,
LIBUSB20_SPEED_FULL,
LIBUSB20_SPEED_HIGH,
LIBUSB20_SPEED_VARIABLE,
LIBUSB20_SPEED_SUPER,
};
/** \ingroup misc
* libusb20_dev_set_power() values
*/
enum {
LIBUSB20_POWER_OFF,
LIBUSB20_POWER_ON,
LIBUSB20_POWER_SAVE,
LIBUSB20_POWER_SUSPEND,
LIBUSB20_POWER_RESUME,
};
struct libusb20_transfer;
struct libusb20_backend;
struct libusb20_backend_methods;
struct libusb20_device;
struct libusb20_device_methods;
struct libusb20_config;
struct LIBUSB20_CONTROL_SETUP_DECODED;
struct LIBUSB20_DEVICE_DESC_DECODED;
typedef void (libusb20_tr_callback_t)(struct libusb20_transfer *xfer);
struct libusb20_quirk {
uint16_t vid; /* vendor ID */
uint16_t pid; /* product ID */
uint16_t bcdDeviceLow; /* low revision value, inclusive */
uint16_t bcdDeviceHigh; /* high revision value, inclusive */
uint16_t reserved[2]; /* for the future */
/* quirk name, UQ_XXX, including terminating zero */
char quirkname[64 - 12];
};
/* USB transfer operations */
int libusb20_tr_close(struct libusb20_transfer *xfer);
int libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t pMaxBufSize, uint32_t MaxFrameCount, uint8_t ep_no);
struct libusb20_transfer *libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t tr_index);
uint16_t libusb20_tr_get_time_complete(struct libusb20_transfer *xfer);
uint32_t libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer);
uint32_t libusb20_tr_get_actual_length(struct libusb20_transfer *xfer);
uint32_t libusb20_tr_get_max_frames(struct libusb20_transfer *xfer);
uint32_t libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer);
uint32_t libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer);
uint8_t libusb20_tr_get_status(struct libusb20_transfer *xfer);
uint8_t libusb20_tr_pending(struct libusb20_transfer *xfer);
void libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer);
void libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer);
void libusb20_tr_drain(struct libusb20_transfer *xfer);
void libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t fr_index);
void libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb);
void libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags);
void libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t fr_index);
void libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0);
void libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1);
void libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout);
void libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames);
void libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint32_t timeout);
void libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pbuf, uint32_t timeout);
void libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint32_t timeout);
void libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint16_t fr_index);
void libusb20_tr_start(struct libusb20_transfer *xfer);
void libusb20_tr_stop(struct libusb20_transfer *xfer);
void libusb20_tr_submit(struct libusb20_transfer *xfer);
void *libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer);
void *libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer);
/* USB device operations */
const char *libusb20_dev_get_backend_name(struct libusb20_device *pdev);
const char *libusb20_dev_get_desc(struct libusb20_device *pdev);
int libusb20_dev_claim_interface(struct libusb20_device *pdev, uint8_t iface_index);
int libusb20_dev_close(struct libusb20_device *pdev);
int libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t iface_index);
int libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex);
int libusb20_dev_get_debug(struct libusb20_device *pdev);
int libusb20_dev_get_fd(struct libusb20_device *pdev);
int libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t iface_index);
int libusb20_dev_open(struct libusb20_device *pdev, uint16_t transfer_max);
int libusb20_dev_process(struct libusb20_device *pdev);
int libusb20_dev_release_interface(struct libusb20_device *pdev, uint8_t iface_index);
int libusb20_dev_request_sync(struct libusb20_device *pdev, struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags);
int libusb20_dev_req_string_sync(struct libusb20_device *pdev, uint8_t index, uint16_t langid, void *ptr, uint16_t len);
int libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, uint8_t index, void *ptr, uint16_t len);
int libusb20_dev_reset(struct libusb20_device *pdev);
int libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode);
uint8_t libusb20_dev_get_power_mode(struct libusb20_device *pdev);
int libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t iface_index, uint8_t alt_index);
int libusb20_dev_set_owner(struct libusb20_device *pdev, uid_t user, gid_t group);
int libusb20_dev_set_perm(struct libusb20_device *pdev, mode_t mode);
int libusb20_dev_set_iface_owner(struct libusb20_device *pdev, uint8_t iface_index, uid_t user, gid_t group);
int libusb20_dev_set_iface_perm(struct libusb20_device *pdev, uint8_t iface_index, mode_t mode);
int libusb20_dev_get_owner(struct libusb20_device *pdev, uid_t *user, gid_t *group);
int libusb20_dev_get_perm(struct libusb20_device *pdev, mode_t *mode);
int libusb20_dev_get_iface_owner(struct libusb20_device *pdev, uint8_t iface_index, uid_t *user, gid_t *group);
int libusb20_dev_get_iface_perm(struct libusb20_device *pdev, uint8_t iface_index, mode_t *mode);
struct LIBUSB20_DEVICE_DESC_DECODED *libusb20_dev_get_device_desc(struct libusb20_device *pdev);
struct libusb20_config *libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t config_index);
struct libusb20_device *libusb20_dev_alloc(void);
uint8_t libusb20_dev_get_address(struct libusb20_device *pdev);
uint8_t libusb20_dev_get_bus_number(struct libusb20_device *pdev);
uint8_t libusb20_dev_get_mode(struct libusb20_device *pdev);
uint8_t libusb20_dev_get_speed(struct libusb20_device *pdev);
uint8_t libusb20_dev_get_config_index(struct libusb20_device *pdev);
void libusb20_dev_free(struct libusb20_device *pdev);
void libusb20_dev_set_debug(struct libusb20_device *pdev, int debug);
void libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout);
/* USB bus operations */
int libusb20_bus_set_owner(struct libusb20_backend *pbe, uint8_t bus, uid_t user, gid_t group);
int libusb20_bus_set_perm(struct libusb20_backend *pbe, uint8_t bus, mode_t mode);
int libusb20_bus_get_owner(struct libusb20_backend *pbe, uint8_t bus, uid_t *user, gid_t *group);
int libusb20_bus_get_perm(struct libusb20_backend *pbe, uint8_t bus, mode_t *mode);
/* USB global operations */
int libusb20_be_get_dev_quirk(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
int libusb20_be_get_quirk_name(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
int libusb20_be_add_dev_quirk(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
int libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
int libusb20_be_set_owner(struct libusb20_backend *be, uid_t user, gid_t group);
int libusb20_be_set_perm(struct libusb20_backend *be, mode_t mode);
int libusb20_be_get_owner(struct libusb20_backend *be, uid_t *user, gid_t *group);
int libusb20_be_get_perm(struct libusb20_backend *be, mode_t *mode);
/* USB backend operations */
struct libusb20_backend *libusb20_be_alloc(const struct libusb20_backend_methods *methods);
struct libusb20_backend *libusb20_be_alloc_default(void);
struct libusb20_backend *libusb20_be_alloc_freebsd(void);
struct libusb20_backend *libusb20_be_alloc_linux(void);
struct libusb20_device *libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev);
void libusb20_be_dequeue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev);
void libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev);
void libusb20_be_free(struct libusb20_backend *pbe);
#if 0
{ /* style */
#endif
#ifdef __cplusplus
}
#endif
#endif /* _LIBUSB20_H_ */

View File

@ -0,0 +1,902 @@
/* $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 the emulation layer for LibUSB v0.1 from sourceforge.
*/
#include <sys/queue.h>
#include <stdlib.h>
#include <stdio.h>
#include "libusb20.h"
#include "libusb20_desc.h"
#include "libusb20_int.h"
#include "libusb20_compat01.h"
/*
* The two following macros were taken from the original LibUSB v0.1
* for sake of compatibility:
*/
#define LIST_ADD(begin, ent) \
do { \
if (begin) { \
ent->next = begin; \
ent->next->prev = ent; \
} else { \
ent->next = NULL; \
} \
ent->prev = NULL; \
begin = ent; \
} while(0)
#define LIST_DEL(begin, ent) \
do { \
if (ent->prev) { \
ent->prev->next = ent->next; \
} else { \
begin = ent->next; \
} \
if (ent->next) { \
ent->next->prev = ent->prev; \
} \
ent->prev = NULL; \
ent->next = NULL; \
} while (0)
struct usb_bus *usb_busses = NULL;
static struct usb_bus usb_global_bus = {
.dirname = {"/dev/usb"},
.root_dev = NULL,
.devices = NULL,
};
static struct libusb20_backend *usb_backend = NULL;
struct usb_parse_state {
struct {
struct libusb20_endpoint *currep;
struct libusb20_interface *currifc;
struct libusb20_config *currcfg;
struct libusb20_me_struct *currextra;
} a;
struct {
struct usb_config_descriptor *currcfg;
struct usb_interface_descriptor *currifc;
struct usb_endpoint_descriptor *currep;
struct usb_interface *currifcw;
uint8_t *currextra;
} b;
uint8_t preparse;
};
static uint8_t
usb_get_first_claimed_interface(usb_dev_handle * dev)
{
struct libusb20_device *pdev = (void *)dev;
uint32_t x;
uint8_t y;
x = pdev->claimed_interfaces;
for (y = 0; y != 32; y++) {
if (x & (1 << y))
break;
}
if (y == 32)
y = 0xFF; /* dummy */
return (y);
}
static struct libusb20_transfer *
usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no)
{
struct libusb20_device *pdev = (void *)dev;
struct libusb20_transfer *xfer;
int err;
uint32_t bufsize;
uint8_t x;
uint8_t speed;
x = (ep_no & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 2;
if (ep_no & LIBUSB20_ENDPOINT_DIR_MASK) {
/* this is a IN endpoint */
x |= 1;
}
speed = libusb20_dev_get_speed(pdev);
/* select a sensible buffer size */
if (speed == LIBUSB20_SPEED_LOW) {
bufsize = 256;
} else if (speed == LIBUSB20_SPEED_FULL) {
bufsize = 4096;
} else {
bufsize = 16384;
}
xfer = libusb20_tr_get_pointer(pdev, x);
if (xfer == NULL)
return (xfer);
err = libusb20_tr_open(xfer, bufsize, 1, ep_no);
if (err == LIBUSB20_ERROR_BUSY) {
/* already opened */
return (xfer);
} else if (err) {
return (NULL);
}
/* success */
return (xfer);
}
usb_dev_handle *
usb_open(struct usb_device *dev)
{
int err;
err = libusb20_dev_open(dev->dev, 16 * 2);
if (err == LIBUSB20_ERROR_BUSY) {
/*
* Workaround buggy USB applications which open the USB
* device multiple times:
*/
return (dev->dev);
}
if (err)
return (NULL);
return (dev->dev);
}
int
usb_close(usb_dev_handle * dev)
{
int err;
err = libusb20_dev_close((void *)dev);
if (err)
return (-1);
return (0);
}
int
usb_get_string(usb_dev_handle * dev, int index,
int langid, char *buf, size_t buflen)
{
int err;
err = libusb20_dev_req_string_sync((void *)dev,
index, langid, buf, buflen);
if (err)
return (-1);
return (0);
}
int
usb_get_string_simple(usb_dev_handle * dev, int index,
char *buf, size_t buflen)
{
int err;
err = libusb20_dev_req_string_simple_sync((void *)dev,
index, buf, buflen);
if (err)
return (-1);
return (strlen(buf));
}
int
usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type,
uint8_t index, void *buf, int size)
{
memset(buf, 0, size);
return (usb_control_msg(udev, ep | USB_ENDPOINT_IN,
USB_REQ_GET_DESCRIPTOR, (type << 8) + index, 0,
buf, size, 1000));
}
int
usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t index,
void *buf, int size)
{
memset(buf, 0, size);
return (usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
(type << 8) + index, 0, buf, size, 1000));
}
int
usb_parse_descriptor(uint8_t *source, char *description, void *dest)
{
uint8_t *sp = source;
uint8_t *dp = dest;
uint16_t w;
uint32_t d;
char *cp;
for (cp = description; *cp; cp++) {
switch (*cp) {
case 'b': /* 8-bit byte */
*dp++ = *sp++;
break;
/*
* 16-bit word, convert from little endian to CPU
*/
case 'w':
w = (sp[1] << 8) | sp[0];
sp += 2;
/* Align to word boundary */
dp += ((dp - (uint8_t *)0) & 1);
*((uint16_t *)dp) = w;
dp += 2;
break;
/*
* 32-bit dword, convert from little endian to CPU
*/
case 'd':
d = (sp[3] << 24) | (sp[2] << 16) |
(sp[1] << 8) | sp[0];
sp += 4;
/* Align to word boundary */
dp += ((dp - (uint8_t *)0) & 1);
/* Align to double word boundary */
dp += ((dp - (uint8_t *)0) & 2);
*((uint32_t *)dp) = d;
dp += 4;
break;
}
}
return (sp - source);
}
static void
usb_parse_extra(struct usb_parse_state *ps, uint8_t **pptr, int *plen)
{
void *ptr;
uint16_t len;
ptr = ps->a.currextra->ptr;
len = ps->a.currextra->len;
if (ps->preparse == 0) {
memcpy(ps->b.currextra, ptr, len);
*pptr = ps->b.currextra;
*plen = len;
}
ps->b.currextra += len;
return;
}
static void
usb_parse_endpoint(struct usb_parse_state *ps)
{
struct usb_endpoint_descriptor *bep;
struct libusb20_endpoint *aep;
aep = ps->a.currep;
bep = ps->b.currep++;
if (ps->preparse == 0) {
/* copy descriptor fields */
bep->bLength = aep->desc.bLength;
bep->bDescriptorType = aep->desc.bDescriptorType;
bep->bEndpointAddress = aep->desc.bEndpointAddress;
bep->bmAttributes = aep->desc.bmAttributes;
bep->wMaxPacketSize = aep->desc.wMaxPacketSize;
bep->bInterval = aep->desc.bInterval;
bep->bRefresh = aep->desc.bRefresh;
bep->bSynchAddress = aep->desc.bSynchAddress;
}
ps->a.currextra = &aep->extra;
usb_parse_extra(ps, &bep->extra, &bep->extralen);
return;
}
static void
usb_parse_iface_sub(struct usb_parse_state *ps)
{
struct libusb20_interface *aifc;
struct usb_interface_descriptor *bifc;
uint8_t x;
aifc = ps->a.currifc;
bifc = ps->b.currifc++;
if (ps->preparse == 0) {
/* copy descriptor fields */
bifc->bLength = aifc->desc.bLength;
bifc->bDescriptorType = aifc->desc.bDescriptorType;
bifc->bInterfaceNumber = aifc->desc.bInterfaceNumber;
bifc->bAlternateSetting = aifc->desc.bAlternateSetting;
bifc->bNumEndpoints = aifc->num_endpoints;
bifc->bInterfaceClass = aifc->desc.bInterfaceClass;
bifc->bInterfaceSubClass = aifc->desc.bInterfaceSubClass;
bifc->bInterfaceProtocol = aifc->desc.bInterfaceProtocol;
bifc->iInterface = aifc->desc.iInterface;
bifc->endpoint = ps->b.currep;
}
for (x = 0; x != aifc->num_endpoints; x++) {
ps->a.currep = aifc->endpoints + x;
usb_parse_endpoint(ps);
}
ps->a.currextra = &aifc->extra;
usb_parse_extra(ps, &bifc->extra, &bifc->extralen);
return;
}
static void
usb_parse_iface(struct usb_parse_state *ps)
{
struct libusb20_interface *aifc;
struct usb_interface *bifc;
uint8_t x;
aifc = ps->a.currifc;
bifc = ps->b.currifcw++;
if (ps->preparse == 0) {
/* initialise interface wrapper */
bifc->altsetting = ps->b.currifc;
bifc->num_altsetting = aifc->num_altsetting + 1;
}
usb_parse_iface_sub(ps);
for (x = 0; x != aifc->num_altsetting; x++) {
ps->a.currifc = aifc->altsetting + x;
usb_parse_iface_sub(ps);
}
return;
}
static void
usb_parse_config(struct usb_parse_state *ps)
{
struct libusb20_config *acfg;
struct usb_config_descriptor *bcfg;
uint8_t x;
acfg = ps->a.currcfg;
bcfg = ps->b.currcfg;
if (ps->preparse == 0) {
/* initialise config wrapper */
bcfg->bLength = acfg->desc.bLength;
bcfg->bDescriptorType = acfg->desc.bDescriptorType;
bcfg->wTotalLength = acfg->desc.wTotalLength;
bcfg->bNumInterfaces = acfg->num_interface;
bcfg->bConfigurationValue = acfg->desc.bConfigurationValue;
bcfg->iConfiguration = acfg->desc.iConfiguration;
bcfg->bmAttributes = acfg->desc.bmAttributes;
bcfg->MaxPower = acfg->desc.bMaxPower;
bcfg->interface = ps->b.currifcw;
}
for (x = 0; x != acfg->num_interface; x++) {
ps->a.currifc = acfg->interface + x;
usb_parse_iface(ps);
}
ps->a.currextra = &acfg->extra;
usb_parse_extra(ps, &bcfg->extra, &bcfg->extralen);
return;
}
int
usb_parse_configuration(struct usb_config_descriptor *config,
uint8_t *buffer)
{
struct usb_parse_state ps;
uint8_t *ptr;
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
if ((buffer == NULL) || (config == NULL)) {
return (-1);
}
memset(&ps, 0, sizeof(ps));
ps.a.currcfg = libusb20_parse_config_desc(buffer);
ps.b.currcfg = config;
if (ps.a.currcfg == NULL) {
/* could not parse config or out of memory */
return (-1);
}
/* do the pre-parse */
ps.preparse = 1;
usb_parse_config(&ps);
a = ((uint8_t *)(ps.b.currifcw) - ((uint8_t *)0));
b = ((uint8_t *)(ps.b.currifc) - ((uint8_t *)0));
c = ((uint8_t *)(ps.b.currep) - ((uint8_t *)0));
d = ((uint8_t *)(ps.b.currextra) - ((uint8_t *)0));
/* allocate memory for our configuration */
ptr = malloc(a + b + c + d);
/* "currifcw" must be first, hence this pointer is freed */
ps.b.currifcw = (void *)(ptr);
ps.b.currifc = (void *)(ptr + a);
ps.b.currep = (void *)(ptr + a + b);
ps.b.currextra = (void *)(ptr + a + b + c);
/* generate a libusb v0.1 compatible structure */
ps.preparse = 0;
usb_parse_config(&ps);
/* free config structure */
free(ps.a.currcfg);
return (0); /* success */
}
void
usb_destroy_configuration(struct usb_device *dev)
{
uint8_t c;
if (dev->config == NULL) {
return;
}
for (c = 0; c != dev->descriptor.bNumConfigurations; c++) {
struct usb_config_descriptor *cf = &dev->config[c];
if (cf->interface != NULL) {
free(cf->interface);
cf->interface = NULL;
}
}
free(dev->config);
dev->config = NULL;
return;
}
void
usb_fetch_and_parse_descriptors(usb_dev_handle * udev)
{
struct usb_device *dev;
struct libusb20_device *pdev;
uint8_t *ptr;
int error;
uint32_t size;
uint16_t len;
uint8_t x;
if (udev == NULL) {
/* be NULL safe */
return;
}
dev = usb_device(udev);
pdev = (void *)udev;
if (dev->descriptor.bNumConfigurations == 0) {
/* invalid device */
return;
}
size = dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor);
dev->config = malloc(size);
if (dev->config == NULL) {
/* out of memory */
return;
}
memset(dev->config, 0, size);
for (x = 0; x != dev->descriptor.bNumConfigurations; x++) {
error = (pdev->methods->get_config_desc_full) (
pdev, &ptr, &len, x);
if (error) {
usb_destroy_configuration(dev);
return;
}
usb_parse_configuration(dev->config + x, ptr);
/* free config buffer */
free(ptr);
}
return;
}
static int
usb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size,
int timeout, int is_intr)
{
struct libusb20_transfer *xfer;
uint32_t temp;
uint32_t maxsize;
uint32_t actlen;
char *oldbytes;
xfer = usb_get_transfer_by_ep_no(dev, ep);
if (xfer == NULL)
return (-1);
if (libusb20_tr_pending(xfer)) {
/* there is already a transfer ongoing */
return (-1);
}
maxsize = libusb20_tr_get_max_total_length(xfer);
oldbytes = bytes;
/*
* We allow transferring zero bytes which is the same
* equivalent to a zero length USB packet.
*/
do {
temp = size;
if (temp > maxsize) {
/* find maximum possible length */
temp = maxsize;
}
if (is_intr)
libusb20_tr_setup_intr(xfer, bytes, temp, timeout);
else
libusb20_tr_setup_bulk(xfer, bytes, temp, timeout);
libusb20_tr_start(xfer);
while (1) {
if (libusb20_dev_process((void *)dev) != 0) {
/* device detached */
return (-1);
}
if (libusb20_tr_pending(xfer) == 0) {
/* transfer complete */
break;
}
/* wait for USB event from kernel */
libusb20_dev_wait_process((void *)dev, -1);
}
if (libusb20_tr_get_status(xfer)) {
/* transfer error */
return (-1);
}
actlen = libusb20_tr_get_actual_length(xfer);
bytes += actlen;
size -= actlen;
if (actlen != temp) {
/* short transfer */
break;
}
} while (size > 0);
return (bytes - oldbytes);
}
int
usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes,
int size, int timeout)
{
return (usb_std_io(dev, ep, bytes, size, timeout, 0));
}
int
usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes,
int size, int timeout)
{
return (usb_std_io(dev, ep, bytes, size, timeout, 0));
}
int
usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes,
int size, int timeout)
{
return (usb_std_io(dev, ep, bytes, size, timeout, 1));
}
int
usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes,
int size, int timeout)
{
return (usb_std_io(dev, ep, bytes, size, timeout, 1));
}
int
usb_control_msg(usb_dev_handle * dev, int requesttype, int request,
int value, int index, char *bytes, int size, int timeout)
{
struct LIBUSB20_CONTROL_SETUP_DECODED req;
int err;
uint16_t actlen;
LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
req.bmRequestType = requesttype;
req.bRequest = request;
req.wValue = value;
req.wIndex = index;
req.wLength = size;
err = libusb20_dev_request_sync((void *)dev, &req, bytes,
&actlen, timeout, 0);
if (err)
return (-1);
return (actlen);
}
int
usb_set_configuration(usb_dev_handle * dev, int configuration)
{
int err;
err = libusb20_dev_set_config_index((void *)dev, configuration);
if (err)
return (-1);
return (0);
}
int
usb_claim_interface(usb_dev_handle * dev, int interface)
{
int err;
err = libusb20_dev_claim_interface((void *)dev, interface);
if (err)
return (-1);
return (0);
}
int
usb_release_interface(usb_dev_handle * dev, int interface)
{
int err;
err = libusb20_dev_release_interface((void *)dev, interface);
if (err)
return (-1);
return (0);
}
int
usb_set_altinterface(usb_dev_handle * dev, int alternate)
{
int err;
uint8_t iface;
iface = usb_get_first_claimed_interface(dev);
err = libusb20_dev_set_alt_index((void *)dev, iface, alternate);
if (err)
return (-1);
return (0);
}
int
usb_resetep(usb_dev_handle * dev, unsigned int ep)
{
/* emulate an endpoint reset through clear-STALL */
return (usb_clear_halt(dev, ep));
}
int
usb_clear_halt(usb_dev_handle * dev, unsigned int ep)
{
struct libusb20_transfer *xfer;
xfer = usb_get_transfer_by_ep_no(dev, ep);
if (xfer == NULL)
return (-1);
libusb20_tr_clear_stall_sync(xfer);
return (0);
}
int
usb_reset(usb_dev_handle * dev)
{
int err;
err = libusb20_dev_reset((void *)dev);
if (err)
return (-1);
return (0);
}
char *
usb_strerror(void)
{
/* TODO */
return ("Unknown error");
}
void
usb_init(void)
{
/* nothing to do */
return;
}
void
usb_set_debug(int level)
{
/* use kernel UGEN debugging if you need to see what is going on */
return;
}
int
usb_find_busses(void)
{
usb_busses = &usb_global_bus;
return (0);
}
int
usb_find_devices(void)
{
struct libusb20_device *pdev;
struct usb_device *udev;
struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
struct libusb20_backend *pold;
int err;
/* cleanup after last device search */
pold = usb_backend;
pdev = NULL;
while ((pdev = libusb20_be_device_foreach(pold, pdev))) {
if (!pdev->is_opened) {
/*
* if the device has not been opened we free the
* device data
*/
udev = pdev->priv01Data;
libusb20_be_dequeue_device(pold, pdev);
libusb20_dev_free(pdev);
if (udev != NULL) {
LIST_DEL(usb_global_bus.devices, udev);
free(udev);
}
pdev = NULL; /* restart search */
}
}
/* do a new backend device search */
usb_backend = libusb20_be_alloc_default();
if (usb_backend == NULL) {
usb_backend = pold; /* restore */
return (-1);
}
/* iterate all devices */
pdev = NULL;
while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) {
udev = malloc(sizeof(*udev));
if (udev == NULL)
break;
memset(udev, 0, sizeof(*udev));
udev->bus = &usb_global_bus;
snprintf(udev->filename, sizeof(udev->filename),
"/dev/ugen%u.%u",
libusb20_dev_get_bus_number(pdev),
libusb20_dev_get_address(pdev));
ddesc = libusb20_dev_get_device_desc(pdev);
udev->descriptor.bLength = sizeof(udev->descriptor);
udev->descriptor.bDescriptorType = ddesc->bDescriptorType;
udev->descriptor.bcdUSB = ddesc->bcdUSB;
udev->descriptor.bDeviceClass = ddesc->bDeviceClass;
udev->descriptor.bDeviceSubClass = ddesc->bDeviceSubClass;
udev->descriptor.bDeviceProtocol = ddesc->bDeviceProtocol;
udev->descriptor.bMaxPacketSize0 = ddesc->bMaxPacketSize0;
udev->descriptor.idVendor = ddesc->idVendor;
udev->descriptor.idProduct = ddesc->idProduct;
udev->descriptor.bcdDevice = ddesc->bcdDevice;
udev->descriptor.iManufacturer = ddesc->iManufacturer;
udev->descriptor.iProduct = ddesc->iProduct;
udev->descriptor.iSerialNumber = ddesc->iSerialNumber;
udev->descriptor.bNumConfigurations =
ddesc->bNumConfigurations;
if (udev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
/* truncate number of configurations */
udev->descriptor.bNumConfigurations = USB_MAXCONFIG;
}
/* link together the two structures */
udev->dev = pdev;
pdev->priv01Data = udev;
err = libusb20_dev_open(pdev, 0);
if (err == 0) {
/* XXX get all config descriptors by default */
usb_fetch_and_parse_descriptors((void *)pdev);
libusb20_dev_close(pdev);
}
LIST_ADD(usb_global_bus.devices, udev);
}
/* move old devices over to the new USB backend */
while ((pdev = libusb20_be_device_foreach(pold, pdev))) {
libusb20_be_dequeue_device(pold, pdev);
libusb20_be_enqueue_device(usb_backend, pdev);
}
/* free old backend, if any */
libusb20_be_free(pold);
return (0); /* success */
}
struct usb_device *
usb_device(usb_dev_handle * dev)
{
struct libusb20_device *pdev;
pdev = (void *)dev;
return (pdev->priv01Data);
}
struct usb_bus *
usb_get_busses(void)
{
return (usb_busses);
}

View File

@ -0,0 +1,310 @@
/* $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.
*/
#ifndef _LIBUSB20_COMPAT_01_H_
#define _LIBUSB20_COMPAT_01_H_
#include <sys/stdint.h>
#include <sys/endian.h>
#include <sys/types.h>
#include <sys/param.h>
/* USB interface class codes */
#define USB_CLASS_PER_INTERFACE 0
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PRINTER 7
#define USB_CLASS_PTP 6
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_DATA 10
#define USB_CLASS_VENDOR_SPEC 0xff
/* USB descriptor types */
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_HID 0x21
#define USB_DT_REPORT 0x22
#define USB_DT_PHYSICAL 0x23
#define USB_DT_HUB 0x29
/* USB descriptor type sizes */
#define USB_DT_DEVICE_SIZE 18
#define USB_DT_CONFIG_SIZE 9
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9
#define USB_DT_HUB_NONVAR_SIZE 7
/* USB descriptor header */
struct usb_descriptor_header {
uint8_t bLength;
uint8_t bDescriptorType;
};
/* USB string descriptor */
struct usb_string_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wData[1];
};
/* USB HID descriptor */
struct usb_hid_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID;
uint8_t bCountryCode;
uint8_t bNumDescriptors;
/* uint8_t bReportDescriptorType; */
/* uint16_t wDescriptorLength; */
/* ... */
};
/* USB endpoint descriptor */
#define USB_MAXENDPOINTS 32
struct usb_endpoint_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
#define USB_ENDPOINT_ADDRESS_MASK 0x0f
#define USB_ENDPOINT_DIR_MASK 0x80
uint8_t bmAttributes;
#define USB_ENDPOINT_TYPE_MASK 0x03
#define USB_ENDPOINT_TYPE_CONTROL 0
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
#define USB_ENDPOINT_TYPE_BULK 2
#define USB_ENDPOINT_TYPE_INTERRUPT 3
uint16_t wMaxPacketSize;
uint8_t bInterval;
uint8_t bRefresh;
uint8_t bSynchAddress;
uint8_t *extra; /* Extra descriptors */
int extralen;
};
/* USB interface descriptor */
#define USB_MAXINTERFACES 32
struct usb_interface_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
struct usb_endpoint_descriptor *endpoint;
uint8_t *extra; /* Extra descriptors */
int extralen;
};
#define USB_MAXALTSETTING 128 /* Hard limit */
struct usb_interface {
struct usb_interface_descriptor *altsetting;
int num_altsetting;
};
/* USB configuration descriptor */
#define USB_MAXCONFIG 8
struct usb_config_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t MaxPower;
struct usb_interface *interface;
uint8_t *extra; /* Extra descriptors */
int extralen;
};
/* USB device descriptor */
struct usb_device_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
};
/* USB setup packet */
struct usb_ctrl_setup {
uint8_t bRequestType;
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define USB_ENDPOINT_IN 0x80
#define USB_ENDPOINT_OUT 0x00
uint8_t bRequest;
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
/* Error codes */
#define USB_ERROR_BEGIN 500000
/* Byte swapping */
#define USB_LE16_TO_CPU(x) le16toh(x)
/* Data types */
struct usb_device;
struct usb_bus;
/*
* To maintain compatibility with applications already built with libusb,
* we must only add entries to the end of this structure. NEVER delete or
* move members and only change types if you really know what you're doing.
*/
struct usb_device {
struct usb_device *next;
struct usb_device *prev;
char filename[PATH_MAX + 1];
struct usb_bus *bus;
struct usb_device_descriptor descriptor;
struct usb_config_descriptor *config;
void *dev;
uint8_t devnum;
uint8_t num_children;
struct usb_device **children;
};
struct usb_bus {
struct usb_bus *next;
struct usb_bus *prev;
char dirname[PATH_MAX + 1];
struct usb_device *devices;
uint32_t location;
struct usb_device *root_dev;
};
struct usb_dev_handle;
typedef struct usb_dev_handle usb_dev_handle;
/* Variables */
extern struct usb_bus *usb_busses;
#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* style */
#endif
/* Function prototypes from "libusb20_compat01.c" */
usb_dev_handle *usb_open(struct usb_device *dev);
int usb_close(usb_dev_handle * dev);
int usb_get_string(usb_dev_handle * dev, int index, int langid, char *buf, size_t buflen);
int usb_get_string_simple(usb_dev_handle * dev, int index, char *buf, size_t buflen);
int usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type, uint8_t index, void *buf, int size);
int usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t index, void *buf, int size);
int usb_parse_descriptor(uint8_t *source, char *description, void *dest);
int usb_parse_configuration(struct usb_config_descriptor *config, uint8_t *buffer);
void usb_destroy_configuration(struct usb_device *dev);
void usb_fetch_and_parse_descriptors(usb_dev_handle * udev);
int usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
int usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
int usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
int usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout);
int usb_control_msg(usb_dev_handle * dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
int usb_set_configuration(usb_dev_handle * dev, int configuration);
int usb_claim_interface(usb_dev_handle * dev, int interface);
int usb_release_interface(usb_dev_handle * dev, int interface);
int usb_set_altinterface(usb_dev_handle * dev, int alternate);
int usb_resetep(usb_dev_handle * dev, unsigned int ep);
int usb_clear_halt(usb_dev_handle * dev, unsigned int ep);
int usb_reset(usb_dev_handle * dev);
char *usb_strerror(void);
void usb_init(void);
void usb_set_debug(int level);
int usb_find_busses(void);
int usb_find_devices(void);
struct usb_device *usb_device(usb_dev_handle * dev);
struct usb_bus *usb_get_busses(void);
#if 0
{ /* style */
#endif
#ifdef __cplusplus
}
#endif
#endif /* _LIBUSB20_COMPAT01_H_ */

View File

@ -0,0 +1,29 @@
/* $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 the emulation layer for LibUSB v1.0 from sourceforge.
*/

View File

@ -0,0 +1,25 @@
/* $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.
*/

View File

@ -0,0 +1,771 @@
/* $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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/queue.h>
#include "libusb20.h"
#include "libusb20_desc.h"
#include "libusb20_int.h"
static const uint32_t libusb20_me_encode_empty[2]; /* dummy */
LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC);
LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC);
LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP);
/*------------------------------------------------------------------------*
* libusb20_parse_config_desc
*
* Return values:
* NULL: Out of memory.
* Else: A valid config structure pointer which must be passed to "free()"
*------------------------------------------------------------------------*/
struct libusb20_config *
libusb20_parse_config_desc(const void *config_desc)
{
struct libusb20_config *lub_config;
struct libusb20_interface *lub_interface;
struct libusb20_interface *lub_alt_interface;
struct libusb20_interface *last_if;
struct libusb20_endpoint *lub_endpoint;
struct libusb20_endpoint *last_ep;
struct libusb20_me_struct pcdesc;
const uint8_t *ptr;
uint32_t size;
uint16_t niface_no_alt;
uint16_t niface;
uint16_t nendpoint;
uint8_t iface_no;
ptr = config_desc;
if (ptr[1] != LIBUSB20_DT_CONFIG) {
return (NULL); /* not config descriptor */
}
/*
* The first "bInterfaceNumber" should never have the value 0xff.
* Then it is corrupt.
*/
niface_no_alt = 0;
nendpoint = 0;
niface = 0;
iface_no = 0 - 1;
ptr = NULL;
/* get "wTotalLength" and setup "pcdesc" */
pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0);
pcdesc.len =
((uint8_t *)config_desc)[2] |
(((uint8_t *)config_desc)[3] << 8);
pcdesc.type = LIBUSB20_ME_IS_RAW;
/* descriptor pre-scan */
while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
nendpoint++;
} else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
niface++;
/* check "bInterfaceNumber" */
if (ptr[2] != iface_no) {
iface_no = ptr[2];
niface_no_alt++;
}
}
}
/* sanity checking */
if (niface >= 256) {
return (NULL); /* corrupt */
}
if (nendpoint >= 256) {
return (NULL); /* corrupt */
}
size = sizeof(*lub_config) +
(niface * sizeof(*lub_interface)) +
(nendpoint * sizeof(*lub_endpoint)) +
pcdesc.len;
lub_config = malloc(size);
if (lub_config == NULL) {
return (NULL); /* out of memory */
}
lub_interface = (void *)(lub_config + 1);
lub_alt_interface = (void *)(lub_interface + niface_no_alt);
lub_endpoint = (void *)(lub_interface + niface);
/*
* Make a copy of the config descriptor, so that the caller can free
* the inital config descriptor pointer!
*/
ptr = (void *)(lub_endpoint + nendpoint);
memcpy(LIBUSB20_ADD_BYTES(ptr, 0), config_desc, pcdesc.len);
pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0);
config_desc = LIBUSB20_ADD_BYTES(ptr, 0);
/* init config structure */
ptr = config_desc;
LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc);
if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) {
/* ignore */
}
lub_config->num_interface = 0;
lub_config->interface = lub_interface;
lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
lub_config->extra.len = -ptr[0];
lub_config->extra.type = LIBUSB20_ME_IS_RAW;
/* reset states */
niface = 0;
iface_no = 0 - 1;
ptr = NULL;
lub_interface--;
lub_endpoint--;
last_if = NULL;
last_ep = NULL;
/* descriptor pre-scan */
while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
if (last_if) {
lub_endpoint++;
last_ep = lub_endpoint;
last_if->num_endpoints++;
LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc);
if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) {
/* ignore */
}
last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
last_ep->extra.len = 0;
last_ep->extra.type = LIBUSB20_ME_IS_RAW;
} else {
lub_config->extra.len += ptr[0];
}
} else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
if (ptr[2] != iface_no) {
/* new interface */
iface_no = ptr[2];
lub_interface++;
lub_config->num_interface++;
last_if = lub_interface;
niface++;
} else {
/* one more alternate setting */
lub_interface->num_altsetting++;
last_if = lub_alt_interface;
lub_alt_interface++;
}
LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc);
if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) {
/* ignore */
}
/*
* Sometimes USB devices have corrupt interface
* descriptors and we need to overwrite the provided
* interface number!
*/
last_if->desc.bInterfaceNumber = niface - 1;
last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
last_if->extra.len = 0;
last_if->extra.type = LIBUSB20_ME_IS_RAW;
last_if->endpoints = lub_endpoint + 1;
last_if->altsetting = lub_alt_interface;
last_if->num_altsetting = 0;
last_if->num_endpoints = 0;
last_ep = NULL;
} else {
/* unknown descriptor */
if (last_if) {
if (last_ep) {
last_ep->extra.len += ptr[0];
} else {
last_if->extra.len += ptr[0];
}
} else {
lub_config->extra.len += ptr[0];
}
}
}
return (lub_config);
}
/*------------------------------------------------------------------------*
* libusb20_desc_foreach
*
* Safe traversal of USB descriptors.
*
* Return values:
* NULL: End of descriptors
* Else: Pointer to next descriptor
*------------------------------------------------------------------------*/
const uint8_t *
libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
const uint8_t *psubdesc)
{
void *end;
if (pdesc == NULL) {
return (NULL);
}
end = LIBUSB20_ADD_BYTES(pdesc->ptr, pdesc->len);
if (psubdesc == NULL) {
psubdesc = LIBUSB20_ADD_BYTES(pdesc->ptr, 0);
} else {
psubdesc = LIBUSB20_ADD_BYTES(psubdesc, psubdesc[0]);
}
return (((((void *)psubdesc) >= ((void *)(pdesc->ptr))) &&
(((void *)psubdesc) < end) &&
(LIBUSB20_ADD_BYTES(psubdesc, psubdesc[0]) >= ((void *)(pdesc->ptr))) &&
(LIBUSB20_ADD_BYTES(psubdesc, psubdesc[0]) <= end) &&
(psubdesc[0] >= 3)) ? psubdesc : NULL);
}
/*------------------------------------------------------------------------*
* libusb20_me_get_1 - safety wrapper to read out one byte
*------------------------------------------------------------------------*/
uint8_t
libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
{
if (offset < ie->len) {
return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
}
return (0);
}
/*------------------------------------------------------------------------*
* libusb20_me_get_2 - safety wrapper to read out one word
*------------------------------------------------------------------------*/
uint16_t
libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
{
return (libusb20_me_get_1(ie, offset) |
(libusb20_me_get_1(ie, offset + 1) << 8));
}
/*------------------------------------------------------------------------*
* libusb20_me_encode - encode a message structure
*
* Description of parameters:
* "len" - maximum length of output buffer
* "ptr" - pointer to output buffer. If NULL, no data will be written
* "pd" - source structure
*
* Return values:
* 0..65535 - Number of bytes used, limited by the "len" input parameter.
*------------------------------------------------------------------------*/
uint16_t
libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
{
const uint8_t *pf; /* pointer to format data */
uint8_t *buf; /* pointer to output buffer */
uint32_t pd_offset; /* decoded structure offset */
uint16_t len_old; /* old length */
uint16_t pd_count; /* decoded element count */
uint8_t me; /* message element */
/* initialise */
len_old = len;
buf = ptr;
pd_offset = sizeof(void *);
pf = (*((struct libusb20_me_format **)pd))->format;
/* scan */
while (1) {
/* get information element */
me = (pf[0]) & LIBUSB20_ME_MASK;
pd_count = pf[1] | (pf[2] << 8);
pf += 3;
/* encode the message element */
switch (me) {
case LIBUSB20_ME_INT8:
while (pd_count--) {
uint8_t temp;
if (len < 1) /* overflow */
goto done;
if (buf) {
temp = *((const uint8_t *)
LIBUSB20_ADD_BYTES(pd, pd_offset));
buf[0] = temp;
buf += 1;
}
pd_offset += 1;
len -= 1;
}
break;
case LIBUSB20_ME_INT16:
pd_offset = -((-pd_offset) & ~1); /* align */
while (pd_count--) {
uint16_t temp;
if (len < 2) /* overflow */
goto done;
if (buf) {
temp = *((const uint16_t *)
LIBUSB20_ADD_BYTES(pd, pd_offset));
buf[1] = (temp >> 8) & 0xFF;
buf[0] = temp & 0xFF;
buf += 2;
}
pd_offset += 2;
len -= 2;
}
break;
case LIBUSB20_ME_INT32:
pd_offset = -((-pd_offset) & ~3); /* align */
while (pd_count--) {
uint32_t temp;
if (len < 4) /* overflow */
goto done;
if (buf) {
temp = *((const uint32_t *)
LIBUSB20_ADD_BYTES(pd, pd_offset));
buf[3] = (temp >> 24) & 0xFF;
buf[2] = (temp >> 16) & 0xFF;
buf[1] = (temp >> 8) & 0xFF;
buf[0] = temp & 0xFF;
buf += 4;
}
pd_offset += 4;
len -= 4;
}
break;
case LIBUSB20_ME_INT64:
pd_offset = -((-pd_offset) & ~7); /* align */
while (pd_count--) {
uint64_t temp;
if (len < 8) /* overflow */
goto done;
if (buf) {
temp = *((const uint64_t *)
LIBUSB20_ADD_BYTES(pd, pd_offset));
buf[7] = (temp >> 56) & 0xFF;
buf[6] = (temp >> 48) & 0xFF;
buf[5] = (temp >> 40) & 0xFF;
buf[4] = (temp >> 32) & 0xFF;
buf[3] = (temp >> 24) & 0xFF;
buf[2] = (temp >> 16) & 0xFF;
buf[1] = (temp >> 8) & 0xFF;
buf[0] = temp & 0xFF;
buf += 8;
}
pd_offset += 8;
len -= 8;
}
break;
case LIBUSB20_ME_STRUCT:
pd_offset = -((-pd_offset) &
~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
while (pd_count--) {
void *src_ptr;
uint16_t src_len;
struct libusb20_me_struct *ps;
ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
switch (ps->type) {
case LIBUSB20_ME_IS_RAW:
src_len = ps->len;
src_ptr = ps->ptr;
break;
case LIBUSB20_ME_IS_ENCODED:
if (ps->len == 0) {
/*
* Length is encoded
* in the data itself
* and should be
* correct:
*/
ps->len = 0 - 1;
}
src_len = libusb20_me_get_1(pd, 0);
src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
if (src_len == 0xFF) {
/* length is escaped */
src_len = libusb20_me_get_2(pd, 1);
src_ptr =
LIBUSB20_ADD_BYTES(ps->ptr, 3);
}
break;
case LIBUSB20_ME_IS_DECODED:
/* reserve 3 length bytes */
src_len = libusb20_me_encode(NULL,
0 - 1 - 3, ps->ptr);
src_ptr = NULL;
break;
default: /* empty structure */
src_len = 0;
src_ptr = NULL;
break;
}
if (src_len > 0xFE) {
if (src_len > (uint16_t)(0 - 1 - 3))
/* overflow */
goto done;
if (len < (src_len + 3))
/* overflow */
goto done;
if (buf) {
buf[0] = 0xFF;
buf[1] = (src_len & 0xFF);
buf[2] = (src_len >> 8) & 0xFF;
buf += 3;
}
len -= (src_len + 3);
} else {
if (len < (src_len + 1))
/* overflow */
goto done;
if (buf) {
buf[0] = (src_len & 0xFF);
buf += 1;
}
len -= (src_len + 1);
}
/* check for buffer and non-zero length */
if (buf && src_len) {
if (ps->type == LIBUSB20_ME_IS_DECODED) {
/*
* Repeat encode
* procedure - we have
* room for the
* complete structure:
*/
uint16_t dummy;
dummy = libusb20_me_encode(buf,
0 - 1 - 3, ps->ptr);
} else {
bcopy(src_ptr, buf, src_len);
}
buf += src_len;
}
pd_offset += sizeof(struct libusb20_me_struct);
}
break;
default:
goto done;
}
}
done:
return (len_old - len);
}
/*------------------------------------------------------------------------*
* libusb20_me_decode - decode a message into a decoded structure
*
* Description of parameters:
* "ptr" - message pointer
* "len" - message length
* "pd" - pointer to decoded structure
*
* Returns:
* "0..65535" - number of bytes decoded, limited by "len"
*------------------------------------------------------------------------*/
uint16_t
libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
{
const uint8_t *pf; /* pointer to format data */
const uint8_t *buf; /* pointer to input buffer */
uint32_t pd_offset; /* decoded structure offset */
uint16_t len_old; /* old length */
uint16_t pd_count; /* decoded element count */
uint8_t me; /* message element */
/* initialise */
len_old = len;
buf = ptr;
pd_offset = sizeof(void *);
pf = (*((struct libusb20_me_format **)pd))->format;
/* scan */
while (1) {
/* get information element */
me = (pf[0]) & LIBUSB20_ME_MASK;
pd_count = pf[1] | (pf[2] << 8);
pf += 3;
/* decode the message element by type */
switch (me) {
case LIBUSB20_ME_INT8:
while (pd_count--) {
uint8_t temp;
if (len < 1) {
len = 0;
temp = 0;
} else {
len -= 1;
temp = buf[0];
buf++;
}
*((uint8_t *)LIBUSB20_ADD_BYTES(pd,
pd_offset)) = temp;
pd_offset += 1;
}
break;
case LIBUSB20_ME_INT16:
pd_offset = -((-pd_offset) & ~1); /* align */
while (pd_count--) {
uint16_t temp;
if (len < 2) {
len = 0;
temp = 0;
} else {
len -= 2;
temp = buf[1] << 8;
temp |= buf[0];
buf += 2;
}
*((uint16_t *)LIBUSB20_ADD_BYTES(pd,
pd_offset)) = temp;
pd_offset += 2;
}
break;
case LIBUSB20_ME_INT32:
pd_offset = -((-pd_offset) & ~3); /* align */
while (pd_count--) {
uint32_t temp;
if (len < 4) {
len = 0;
temp = 0;
} else {
len -= 4;
temp = buf[3] << 24;
temp |= buf[2] << 16;
temp |= buf[1] << 8;
temp |= buf[0];
buf += 4;
}
*((uint32_t *)LIBUSB20_ADD_BYTES(pd,
pd_offset)) = temp;
pd_offset += 4;
}
break;
case LIBUSB20_ME_INT64:
pd_offset = -((-pd_offset) & ~7); /* align */
while (pd_count--) {
uint64_t temp;
if (len < 8) {
len = 0;
temp = 0;
} else {
len -= 8;
temp = ((uint64_t)buf[7]) << 56;
temp |= ((uint64_t)buf[6]) << 48;
temp |= ((uint64_t)buf[5]) << 40;
temp |= ((uint64_t)buf[4]) << 32;
temp |= buf[3] << 24;
temp |= buf[2] << 16;
temp |= buf[1] << 8;
temp |= buf[0];
buf += 8;
}
*((uint64_t *)LIBUSB20_ADD_BYTES(pd,
pd_offset)) = temp;
pd_offset += 8;
}
break;
case LIBUSB20_ME_STRUCT:
pd_offset = -((-pd_offset) &
~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
while (pd_count--) {
uint16_t temp;
uint16_t dummy;
struct libusb20_me_struct *ps;
ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
if (ps->type == LIBUSB20_ME_IS_ENCODED) {
/*
* Pre-store a de-constified
* pointer to the raw
* structure:
*/
ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
/*
* Get the correct number of
* length bytes:
*/
if (len != 0) {
if (buf[0] == 0xFF) {
ps->len = 3;
} else {
ps->len = 1;
}
} else {
ps->len = 0;
}
}
/* get the structure length */
if (len != 0) {
if (buf[0] == 0xFF) {
if (len < 3) {
len = 0;
temp = 0;
} else {
len -= 3;
temp = buf[1] |
(buf[2] << 8);
buf += 3;
}
} else {
len -= 1;
temp = buf[0];
buf += 1;
}
} else {
len = 0;
temp = 0;
}
/* check for invalid length */
if (temp > len) {
len = 0;
temp = 0;
}
/* check wanted structure type */
switch (ps->type) {
case LIBUSB20_ME_IS_ENCODED:
/* check for zero length */
if (temp == 0) {
/*
* The pointer must
* be valid:
*/
ps->ptr = LIBUSB20_ADD_BYTES(
libusb20_me_encode_empty, 0);
ps->len = 1;
} else {
ps->len += temp;
}
break;
case LIBUSB20_ME_IS_RAW:
/* update length and pointer */
ps->len = temp;
ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
break;
case LIBUSB20_ME_IS_EMPTY:
case LIBUSB20_ME_IS_DECODED:
/* check for non-zero length */
if (temp != 0) {
/* update type */
ps->type = LIBUSB20_ME_IS_DECODED;
ps->len = 0;
/*
* Recursivly decode
* the next structure
*/
dummy = libusb20_me_decode(buf,
temp, ps->ptr);
} else {
/* update type */
ps->type = LIBUSB20_ME_IS_EMPTY;
ps->len = 0;
}
break;
default:
/*
* nothing to do - should
* not happen
*/
ps->ptr = NULL;
ps->len = 0;
break;
}
buf += temp;
len -= temp;
pd_offset += sizeof(struct libusb20_me_struct);
}
break;
default:
goto done;
}
}
done:
return (len_old - len);
}

View File

@ -0,0 +1,534 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
* Copyright (c) 2007-2008 Daniel Drake. All rights reserved.
* Copyright (c) 2001 Johannes Erdfelt. 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.
*/
/*
* NOTE: This file contains the definition of some standard USB
* structures. All structures which name ends by *DECODED use host byte
* order.
*/
/*
* NOTE: This file uses a lot of macros. If you want to see what the
* macros become when they are expanded then run the following
* commands from your shell:
*
* cpp libusb20_desc.h > temp.h
* indent temp.h
* less temp.h
*/
#ifndef _LIBUSB20_DESC_H_
#define _LIBUSB20_DESC_H_
#ifdef __cplusplus
extern "C" {
#endif
#if 0
}; /* style */
#endif
/* basic macros */
#define LIBUSB20__NOT(...) __VA_ARGS__
#define LIBUSB20_NOT(arg) LIBUSB20__NOT(LIBUSB20_YES arg(() LIBUSB20_NO))
#define LIBUSB20_YES(...) __VA_ARGS__
#define LIBUSB20_NO(...)
#define LIBUSB20_END(...) __VA_ARGS__
#define LIBUSB20_MAX(a,b) (((a) > (b)) ? (a) : (b))
#define LIBUSB20_MIN(a,b) (((a) < (b)) ? (a) : (b))
#define LIBUSB20_ADD_BYTES(ptr,off) \
((void *)(((const uint8_t *)(ptr)) + (off)))
/* basic message elements */
enum {
LIBUSB20_ME_INT8,
LIBUSB20_ME_INT16,
LIBUSB20_ME_INT32,
LIBUSB20_ME_INT64,
LIBUSB20_ME_STRUCT,
LIBUSB20_ME_MAX, /* used to indicate end */
};
/* basic message element modifiers */
enum {
LIBUSB20_ME_IS_UNSIGNED = 0x00,
LIBUSB20_ME_IS_SIGNED = 0x80,
LIBUSB20_ME_MASK = 0x7F,
};
enum {
LIBUSB20_ME_IS_RAW, /* structure excludes length field
* (hardcoded value) */
LIBUSB20_ME_IS_ENCODED, /* structure includes length field */
LIBUSB20_ME_IS_EMPTY, /* no structure */
LIBUSB20_ME_IS_DECODED, /* structure is recursive */
};
/* basic helper structures and macros */
#define LIBUSB20_ME_STRUCT_ALIGN sizeof(void *)
struct libusb20_me_struct {
void *ptr; /* data pointer */
uint16_t len; /* defaults to zero */
uint16_t type; /* defaults to LIBUSB20_ME_IS_EMPTY */
} __aligned(LIBUSB20_ME_STRUCT_ALIGN);
struct libusb20_me_format {
const uint8_t *format; /* always set */
const char *desc; /* optionally set */
const char *fields; /* optionally set */
};
#define LIBUSB20_ME_STRUCT(n, field, arg, ismeta) \
ismeta ( LIBUSB20_ME_STRUCT, 1, 0, ) \
LIBUSB20_NOT(ismeta) ( struct libusb20_me_struct field; )
#define LIBUSB20_ME_STRUCT_ARRAY(n, field, arg, ismeta) \
ismeta ( LIBUSB20_ME_STRUCT , (arg) & 0xFF, \
((arg) / 0x100) & 0xFF, ) \
LIBUSB20_NOT(ismeta) ( struct libusb20_me_struct field [arg]; )
#define LIBUSB20_ME_INTEGER(n, field, ismeta, un, u, bits, a, size) \
ismeta ( LIBUSB20_ME_INT##bits | \
LIBUSB20_ME_IS_##un##SIGNED , \
(size) & 0xFF, ((size) / 0x100) & 0xFF, ) \
LIBUSB20_NOT(ismeta) ( u##int##bits##_t \
__aligned((bits) / 8) field a; )
#define LIBUSB20_ME_UINT8_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 8, , 1)
#define LIBUSB20_ME_UINT8_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 8, [arg], arg)
#define LIBUSB20_ME_SINT8_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 8, , 1)
#define LIBUSB20_ME_SINT8_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 8, [arg], arg)
#define LIBUSB20_ME_UINT16_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 16, , 1)
#define LIBUSB20_ME_UINT16_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 16, [arg], arg)
#define LIBUSB20_ME_SINT16_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 16, , 1)
#define LIBUSB20_ME_SINT16_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 16, [arg], arg)
#define LIBUSB20_ME_UINT32_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 32, , 1)
#define LIBUSB20_ME_UINT32_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 32, [arg], arg)
#define LIBUSB20_ME_SINT32_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 32, , 1)
#define LIBUSB20_ME_SINT32_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 32, [arg], arg)
#define LIBUSB20_ME_UINT64_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 64, , 1)
#define LIBUSB20_ME_UINT64_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta, UN, u, 64, [arg], arg)
#define LIBUSB20_ME_SINT64_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 64, , 1)
#define LIBUSB20_ME_SINT64_ARRAY_T(n, field, arg, ismeta) \
LIBUSB20_ME_INTEGER(n, field, ismeta,,, 64, [arg], arg)
#define LIBUSB20_MAKE_DECODED_FIELD(n, type, field, arg) \
LIBUSB20_ME_##type (n, field, arg, LIBUSB20_NO)
#define LIBUSB20_MAKE_STRUCT(name) \
extern const struct libusb20_me_format \
name##_FORMAT[1]; \
struct name##_DECODED { \
const struct libusb20_me_format *name##_FORMAT; \
name (LIBUSB20_MAKE_DECODED_FIELD,) \
}
#define LIBUSB20_MAKE_STRUCT_FORMAT(name) \
const struct libusb20_me_format \
name##_FORMAT[1] = {{ \
.format = LIBUSB20_MAKE_FORMAT(name), \
.desc = #name, \
.fields = NULL, \
}}
#define LIBUSB20_MAKE_FORMAT_SUB(n, type, field, arg) \
LIBUSB20_ME_##type (n, field, arg, LIBUSB20_YES)
#define LIBUSB20_MAKE_FORMAT(what) (const uint8_t []) \
{ what (LIBUSB20_MAKE_FORMAT_SUB, ) LIBUSB20_ME_MAX, 0, 0 }
#define LIBUSB20_INIT(what, ptr) do { \
memset(ptr, 0, sizeof(*(ptr))); \
(ptr)->what##_FORMAT = what##_FORMAT; \
} while (0)
#define LIBUSB20_DEVICE_DESC(m,n) \
m(n, UINT8_T, bLength, ) \
m(n, UINT8_T, bDescriptorType, ) \
m(n, UINT16_T, bcdUSB, ) \
m(n, UINT8_T, bDeviceClass, ) \
m(n, UINT8_T, bDeviceSubClass, ) \
m(n, UINT8_T, bDeviceProtocol, ) \
m(n, UINT8_T, bMaxPacketSize0, ) \
m(n, UINT16_T, idVendor, ) \
m(n, UINT16_T, idProduct, ) \
m(n, UINT16_T, bcdDevice, ) \
m(n, UINT8_T, iManufacturer, ) \
m(n, UINT8_T, iProduct, ) \
m(n, UINT8_T, iSerialNumber, ) \
m(n, UINT8_T, bNumConfigurations, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_DEVICE_DESC);
#define LIBUSB20_ENDPOINT_DESC(m,n) \
m(n, UINT8_T, bLength, ) \
m(n, UINT8_T, bDescriptorType, ) \
m(n, UINT8_T, bEndpointAddress, ) \
m(n, UINT8_T, bmAttributes, ) \
m(n, UINT16_T, wMaxPacketSize, ) \
m(n, UINT8_T, bInterval, ) \
m(n, UINT8_T, bRefresh, ) \
m(n, UINT8_T, bSynchAddress, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_ENDPOINT_DESC);
#define LIBUSB20_INTERFACE_DESC(m,n) \
m(n, UINT8_T, bLength, ) \
m(n, UINT8_T, bDescriptorType, ) \
m(n, UINT8_T, bInterfaceNumber, ) \
m(n, UINT8_T, bAlternateSetting, ) \
m(n, UINT8_T, bNumEndpoints, ) \
m(n, UINT8_T, bInterfaceClass, ) \
m(n, UINT8_T, bInterfaceSubClass, ) \
m(n, UINT8_T, bInterfaceProtocol, ) \
m(n, UINT8_T, iInterface, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_INTERFACE_DESC);
#define LIBUSB20_CONFIG_DESC(m,n) \
m(n, UINT8_T, bLength, ) \
m(n, UINT8_T, bDescriptorType, ) \
m(n, UINT16_T, wTotalLength, ) \
m(n, UINT8_T, bNumInterfaces, ) \
m(n, UINT8_T, bConfigurationValue, ) \
m(n, UINT8_T, iConfiguration, ) \
m(n, UINT8_T, bmAttributes, ) \
m(n, UINT8_T, bMaxPower, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_CONFIG_DESC);
#define LIBUSB20_CONTROL_SETUP(m,n) \
m(n, UINT8_T, bmRequestType, ) \
m(n, UINT8_T, bRequest, ) \
m(n, UINT16_T, wValue, ) \
m(n, UINT16_T, wIndex, ) \
m(n, UINT16_T, wLength, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_CONTROL_SETUP);
/* standard USB stuff */
/** \ingroup desc
* Device and/or Interface Class codes */
enum libusb20_class_code {
/** In the context of a \ref LIBUSB20_DEVICE_DESC "device
* descriptor", this bDeviceClass value indicates that each
* interface specifies its own class information and all
* interfaces operate independently.
*/
LIBUSB20_CLASS_PER_INTERFACE = 0,
/** Audio class */
LIBUSB20_CLASS_AUDIO = 1,
/** Communications class */
LIBUSB20_CLASS_COMM = 2,
/** Human Interface Device class */
LIBUSB20_CLASS_HID = 3,
/** Printer dclass */
LIBUSB20_CLASS_PRINTER = 7,
/** Picture transfer protocol class */
LIBUSB20_CLASS_PTP = 6,
/** Mass storage class */
LIBUSB20_CLASS_MASS_STORAGE = 8,
/** Hub class */
LIBUSB20_CLASS_HUB = 9,
/** Data class */
LIBUSB20_CLASS_DATA = 10,
/** Class is vendor-specific */
LIBUSB20_CLASS_VENDOR_SPEC = 0xff,
};
/** \ingroup desc
* Descriptor types as defined by the USB specification. */
enum libusb20_descriptor_type {
/** Device descriptor. See LIBUSB20_DEVICE_DESC. */
LIBUSB20_DT_DEVICE = 0x01,
/** Configuration descriptor. See LIBUSB20_CONFIG_DESC. */
LIBUSB20_DT_CONFIG = 0x02,
/** String descriptor */
LIBUSB20_DT_STRING = 0x03,
/** Interface descriptor. See LIBUSB20_INTERFACE_DESC. */
LIBUSB20_DT_INTERFACE = 0x04,
/** Endpoint descriptor. See LIBUSB20_ENDPOINT_DESC. */
LIBUSB20_DT_ENDPOINT = 0x05,
/** HID descriptor */
LIBUSB20_DT_HID = 0x21,
/** HID report descriptor */
LIBUSB20_DT_REPORT = 0x22,
/** Physical descriptor */
LIBUSB20_DT_PHYSICAL = 0x23,
/** Hub descriptor */
LIBUSB20_DT_HUB = 0x29,
};
/* Descriptor sizes per descriptor type */
#define LIBUSB20_DT_DEVICE_SIZE 18
#define LIBUSB20_DT_CONFIG_SIZE 9
#define LIBUSB20_DT_INTERFACE_SIZE 9
#define LIBUSB20_DT_ENDPOINT_SIZE 7
#define LIBUSB20_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
#define LIBUSB20_DT_HUB_NONVAR_SIZE 7
#define LIBUSB20_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
#define LIBUSB20_ENDPOINT_DIR_MASK 0x80
/** \ingroup desc
* Endpoint direction. Values for bit 7 of the
* \ref LIBUSB20_ENDPOINT_DESC::bEndpointAddress "endpoint address" scheme.
*/
enum libusb20_endpoint_direction {
/** In: device-to-host */
LIBUSB20_ENDPOINT_IN = 0x80,
/** Out: host-to-device */
LIBUSB20_ENDPOINT_OUT = 0x00,
};
#define LIBUSB20_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */
/** \ingroup desc
* Endpoint transfer type. Values for bits 0:1 of the
* \ref LIBUSB20_ENDPOINT_DESC::bmAttributes "endpoint attributes" field.
*/
enum libusb20_transfer_type {
/** Control endpoint */
LIBUSB20_TRANSFER_TYPE_CONTROL = 0,
/** Isochronous endpoint */
LIBUSB20_TRANSFER_TYPE_ISOCHRONOUS = 1,
/** Bulk endpoint */
LIBUSB20_TRANSFER_TYPE_BULK = 2,
/** Interrupt endpoint */
LIBUSB20_TRANSFER_TYPE_INTERRUPT = 3,
};
/** \ingroup misc
* Standard requests, as defined in table 9-3 of the USB2 specifications */
enum libusb20_standard_request {
/** Request status of the specific recipient */
LIBUSB20_REQUEST_GET_STATUS = 0x00,
/** Clear or disable a specific feature */
LIBUSB20_REQUEST_CLEAR_FEATURE = 0x01,
/* 0x02 is reserved */
/** Set or enable a specific feature */
LIBUSB20_REQUEST_SET_FEATURE = 0x03,
/* 0x04 is reserved */
/** Set device address for all future accesses */
LIBUSB20_REQUEST_SET_ADDRESS = 0x05,
/** Get the specified descriptor */
LIBUSB20_REQUEST_GET_DESCRIPTOR = 0x06,
/** Used to update existing descriptors or add new descriptors */
LIBUSB20_REQUEST_SET_DESCRIPTOR = 0x07,
/** Get the current device configuration value */
LIBUSB20_REQUEST_GET_CONFIGURATION = 0x08,
/** Set device configuration */
LIBUSB20_REQUEST_SET_CONFIGURATION = 0x09,
/** Return the selected alternate setting for the specified
* interface */
LIBUSB20_REQUEST_GET_INTERFACE = 0x0A,
/** Select an alternate interface for the specified interface */
LIBUSB20_REQUEST_SET_INTERFACE = 0x0B,
/** Set then report an endpoint's synchronization frame */
LIBUSB20_REQUEST_SYNCH_FRAME = 0x0C,
};
/** \ingroup misc
* Request type bits of the
* \ref libusb20_control_setup::bmRequestType "bmRequestType" field in
* control transfers. */
enum libusb20_request_type {
/** Standard */
LIBUSB20_REQUEST_TYPE_STANDARD = (0x00 << 5),
/** Class */
LIBUSB20_REQUEST_TYPE_CLASS = (0x01 << 5),
/** Vendor */
LIBUSB20_REQUEST_TYPE_VENDOR = (0x02 << 5),
/** Reserved */
LIBUSB20_REQUEST_TYPE_RESERVED = (0x03 << 5),
};
/** \ingroup misc
* Recipient bits of the
* \ref libusb20_control_setup::bmRequestType "bmRequestType" field in
* control transfers. Values 4 through 31 are reserved. */
enum libusb20_request_recipient {
/** Device */
LIBUSB20_RECIPIENT_DEVICE = 0x00,
/** Interface */
LIBUSB20_RECIPIENT_INTERFACE = 0x01,
/** Endpoint */
LIBUSB20_RECIPIENT_ENDPOINT = 0x02,
/** Other */
LIBUSB20_RECIPIENT_OTHER = 0x03,
};
#define LIBUSB20_ISO_SYNC_TYPE_MASK 0x0C
/** \ingroup desc
* Synchronization type for isochronous endpoints. Values for bits 2:3
* of the \ref LIBUSB20_ENDPOINT_DESC::bmAttributes "bmAttributes"
* field in LIBUSB20_ENDPOINT_DESC.
*/
enum libusb20_iso_sync_type {
/** No synchronization */
LIBUSB20_ISO_SYNC_TYPE_NONE = 0,
/** Asynchronous */
LIBUSB20_ISO_SYNC_TYPE_ASYNC = 1,
/** Adaptive */
LIBUSB20_ISO_SYNC_TYPE_ADAPTIVE = 2,
/** Synchronous */
LIBUSB20_ISO_SYNC_TYPE_SYNC = 3,
};
#define LIBUSB20_ISO_USAGE_TYPE_MASK 0x30
/** \ingroup desc
* Usage type for isochronous endpoints. Values for bits 4:5 of the
* \ref LIBUSB20_ENDPOINT_DESC::bmAttributes "bmAttributes" field in
* LIBUSB20_ENDPOINT_DESC.
*/
enum libusb20_iso_usage_type {
/** Data endpoint */
LIBUSB20_ISO_USAGE_TYPE_DATA = 0,
/** Feedback endpoint */
LIBUSB20_ISO_USAGE_TYPE_FEEDBACK = 1,
/** Implicit feedback Data endpoint */
LIBUSB20_ISO_USAGE_TYPE_IMPLICIT = 2,
};
struct libusb20_endpoint {
struct LIBUSB20_ENDPOINT_DESC_DECODED desc;
struct libusb20_me_struct extra;
} __aligned(sizeof(void *));
struct libusb20_interface {
struct LIBUSB20_INTERFACE_DESC_DECODED desc;
struct libusb20_me_struct extra;
struct libusb20_interface *altsetting;
struct libusb20_endpoint *endpoints;
uint8_t num_altsetting;
uint8_t num_endpoints;
} __aligned(sizeof(void *));
struct libusb20_config {
struct LIBUSB20_CONFIG_DESC_DECODED desc;
struct libusb20_me_struct extra;
struct libusb20_interface *interface;
uint8_t num_interface;
} __aligned(sizeof(void *));
uint8_t libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset);
uint16_t libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset);
uint16_t libusb20_me_encode(void *ptr, uint16_t len, const void *pd);
uint16_t libusb20_me_decode(const void *ptr, uint16_t len, void *pd);
const uint8_t *libusb20_desc_foreach(const struct libusb20_me_struct *pdesc, const uint8_t *psubdesc);
struct libusb20_config *libusb20_parse_config_desc(const void *config_desc);
#if 0
{ /* style */
#endif
#ifdef __cplusplus
}
#endif
#endif /* _LIBUSB20_DESC_H_ */

252
lib/libusb20/libusb20_int.h Normal file
View File

@ -0,0 +1,252 @@
/* $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 describes internal structures.
*/
#ifndef _LIBUSB20_INT_H_
#define _LIBUSB20_INT_H_
struct libusb20_device;
struct libusb20_backend;
struct libusb20_transfer;
struct libusb20_quirk;
union libusb20_session_data {
unsigned long session_data;
struct timespec tv;
uint32_t plugtime;
};
/* USB backend specific */
typedef const char *(libusb20_get_backend_name_t)(void);
typedef int (libusb20_root_get_dev_quirk_t)(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
typedef int (libusb20_root_get_quirk_name_t)(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
typedef int (libusb20_root_add_dev_quirk_t)(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
typedef int (libusb20_root_remove_dev_quirk_t)(struct libusb20_backend *pbe, struct libusb20_quirk *pq);
typedef int (libusb20_bus_get_owner_t)(struct libusb20_backend *pbe, uint8_t bus, uid_t *user, gid_t *group);
typedef int (libusb20_bus_get_perm_t)(struct libusb20_backend *pbe, uint8_t bus, mode_t *mode);
typedef int (libusb20_bus_set_owner_t)(struct libusb20_backend *pbe, uint8_t bus, uid_t user, gid_t group);
typedef int (libusb20_bus_set_perm_t)(struct libusb20_backend *pbe, uint8_t bus, mode_t mode);
typedef int (libusb20_close_device_t)(struct libusb20_device *pdev);
typedef int (libusb20_dev_get_iface_owner_t)(struct libusb20_device *pdev, uint8_t iface_index, uid_t *user, gid_t *group);
typedef int (libusb20_dev_get_iface_perm_t)(struct libusb20_device *pdev, uint8_t iface_index, mode_t *mode);
typedef int (libusb20_dev_get_owner_t)(struct libusb20_device *pdev, uid_t *user, gid_t *group);
typedef int (libusb20_dev_get_perm_t)(struct libusb20_device *pdev, mode_t *mode);
typedef int (libusb20_dev_set_iface_owner_t)(struct libusb20_device *pdev, uint8_t iface_index, uid_t user, gid_t group);
typedef int (libusb20_dev_set_iface_perm_t)(struct libusb20_device *pdev, uint8_t iface_index, mode_t mode);
typedef int (libusb20_dev_set_owner_t)(struct libusb20_device *pdev, uid_t user, gid_t group);
typedef int (libusb20_dev_set_perm_t)(struct libusb20_device *pdev, mode_t mode);
typedef int (libusb20_init_backend_t)(struct libusb20_backend *pbe);
typedef int (libusb20_open_device_t)(struct libusb20_device *pdev, uint16_t transfer_count_max);
typedef int (libusb20_root_get_owner_t)(struct libusb20_backend *pbe, uid_t *user, gid_t *group);
typedef int (libusb20_root_get_perm_t)(struct libusb20_backend *pbe, mode_t *mode);
typedef int (libusb20_root_set_owner_t)(struct libusb20_backend *pbe, uid_t user, gid_t group);
typedef int (libusb20_root_set_perm_t)(struct libusb20_backend *pbe, mode_t mode);
typedef void (libusb20_exit_backend_t)(struct libusb20_backend *pbe);
#define LIBUSB20_DEFINE(n,field) \
libusb20_##field##_t *field;
#define LIBUSB20_DECLARE(n,field) \
/* .field = */ n##_##field,
#define LIBUSB20_BACKEND(m,n) \
/* description of this backend */ \
m(n, get_backend_name) \
/* optional backend methods */ \
m(n, init_backend) \
m(n, exit_backend) \
m(n, bus_set_owner) \
m(n, bus_get_owner) \
m(n, bus_set_perm) \
m(n, bus_get_perm) \
m(n, dev_get_iface_owner) \
m(n, dev_get_iface_perm) \
m(n, dev_get_owner) \
m(n, dev_get_perm) \
m(n, dev_set_iface_owner) \
m(n, dev_set_iface_perm) \
m(n, dev_set_owner) \
m(n, dev_set_perm) \
m(n, root_get_dev_quirk) \
m(n, root_get_quirk_name) \
m(n, root_add_dev_quirk) \
m(n, root_remove_dev_quirk) \
m(n, root_set_owner) \
m(n, root_get_owner) \
m(n, root_set_perm) \
m(n, root_get_perm) \
/* mandatory device methods */ \
m(n, open_device) \
m(n, close_device) \
struct libusb20_backend_methods {
LIBUSB20_BACKEND(LIBUSB20_DEFINE,)
};
/* USB dummy methods */
typedef int (libusb20_dummy_int_t)(void);
typedef void (libusb20_dummy_void_t)(void);
/* USB device specific */
typedef int (libusb20_claim_interface_t)(struct libusb20_device *pdev, uint8_t iface_index);
typedef int (libusb20_detach_kernel_driver_t)(struct libusb20_device *pdev, uint8_t iface_index);
typedef int (libusb20_do_request_sync_t)(struct libusb20_device *pdev, struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags);
typedef int (libusb20_get_config_desc_full_t)(struct libusb20_device *pdev, uint8_t **ppbuf, uint16_t *plen, uint8_t index);
typedef int (libusb20_get_config_index_t)(struct libusb20_device *pdev, uint8_t *pindex);
typedef int (libusb20_kernel_driver_active_t)(struct libusb20_device *pdev, uint8_t iface_index);
typedef int (libusb20_process_t)(struct libusb20_device *pdev);
typedef int (libusb20_release_interface_t)(struct libusb20_device *pdev, uint8_t iface_index);
typedef int (libusb20_reset_device_t)(struct libusb20_device *pdev);
typedef int (libusb20_set_power_mode_t)(struct libusb20_device *pdev, uint8_t power_mode);
typedef int (libusb20_get_power_mode_t)(struct libusb20_device *pdev, uint8_t *power_mode);
typedef int (libusb20_set_alt_index_t)(struct libusb20_device *pdev, uint8_t iface_index, uint8_t alt_index);
typedef int (libusb20_set_config_index_t)(struct libusb20_device *pdev, uint8_t index);
/* USB transfer specific */
typedef int (libusb20_tr_open_t)(struct libusb20_transfer *xfer, uint32_t MaxBufSize, uint32_t MaxFrameCount, uint8_t ep_no);
typedef int (libusb20_tr_close_t)(struct libusb20_transfer *xfer);
typedef int (libusb20_tr_clear_stall_sync_t)(struct libusb20_transfer *xfer);
typedef void (libusb20_tr_submit_t)(struct libusb20_transfer *xfer);
typedef void (libusb20_tr_cancel_async_t)(struct libusb20_transfer *xfer);
#define LIBUSB20_DEVICE(m,n) \
m(n, claim_interface) \
m(n, detach_kernel_driver) \
m(n, do_request_sync) \
m(n, get_config_desc_full) \
m(n, get_config_index) \
m(n, kernel_driver_active) \
m(n, process) \
m(n, release_interface) \
m(n, reset_device) \
m(n, set_power_mode) \
m(n, get_power_mode) \
m(n, set_alt_index) \
m(n, set_config_index) \
m(n, tr_cancel_async) \
m(n, tr_clear_stall_sync) \
m(n, tr_close) \
m(n, tr_open) \
m(n, tr_submit) \
struct libusb20_device_methods {
LIBUSB20_DEVICE(LIBUSB20_DEFINE,)
};
struct libusb20_backend {
TAILQ_HEAD(, libusb20_device) usb_devs;
const struct libusb20_backend_methods *methods;
};
struct libusb20_transfer {
struct libusb20_device *pdev; /* the USB device we belong to */
libusb20_tr_callback_t *callback;
void *priv_sc0; /* private client data */
void *priv_sc1; /* private client data */
/*
* Pointer to a list of buffer pointers:
*/
void **ppBuffer;
/*
* Pointer to frame lengths, which are updated to actual length
* after the USB transfer completes:
*/
uint32_t *pLength;
uint32_t maxTotalLength;
uint32_t maxFrames; /* total number of frames */
uint32_t nFrames; /* total number of frames */
uint32_t aFrames; /* actual number of frames */
uint32_t timeout;
/* isochronous completion time in milliseconds */
uint16_t timeComplete;
uint16_t trIndex;
uint16_t maxPacketLen;
uint8_t flags; /* see LIBUSB20_TRANSFER_XXX */
uint8_t status; /* see LIBUSB20_TRANSFER_XXX */
uint8_t is_opened;
uint8_t is_pending;
uint8_t is_cancel;
uint8_t is_draining;
uint8_t is_restart;
};
struct libusb20_device {
/* device descriptor */
struct LIBUSB20_DEVICE_DESC_DECODED ddesc;
/* device timestamp */
union libusb20_session_data session_data;
/* our device entry */
TAILQ_ENTRY(libusb20_device) dev_entry;
/* device methods */
const struct libusb20_device_methods *methods;
/* backend methods */
const struct libusb20_backend_methods *beMethods;
/* list of USB transfers */
struct libusb20_transfer *pTransfer;
/* private backend data */
void *privBeData;
/* libUSB v0.1 compat data */
void *priv01Data;
/* claimed interfaces */
uint32_t claimed_interfaces;
/* device file handle */
int file;
/* device file handle (control transfers only) */
int file_ctrl;
/* debugging level */
int debug;
/* number of USB transfers */
uint16_t nTransfer;
uint8_t bus_number;
uint8_t device_address;
uint8_t usb_mode;
uint8_t usb_speed;
uint8_t is_opened;
char usb_desc[96];
};
extern const struct libusb20_backend_methods libusb20_ugen20_backend;
extern const struct libusb20_backend_methods libusb20_linux_backend;
#endif /* _LIBUSB20_INT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_BLUETOOTH 4
.Os
.
.Sh NAME
.
.
.Nm usb2_bluetooth
.
.Nd "USB bluetooth container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_bluetooth"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_bluetooth_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB bluetooth drivers.
.
When you plug an USB bluetooth device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,65 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_CONTROLLER 4
.Os
.
.Sh NAME
.
.
.Nm usb2_controller
.
.Nd "USB controller container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_controller"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_controller_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB Host and Device side
controller drivers.
.
When you plug an USB controller the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_core 4

630
share/man/man4/usb2_core.4 Normal file
View File

@ -0,0 +1,630 @@
.\" $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.
.\"
.Dd September 20, 2008
.Dt USB2_CORE 4
.Os
.
.Sh NAME
.
.
.Nm usb2_core
.
.Nd "USB core functions"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_core"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_core_load="YES"
.Ed
.
.Pp
Here is a list of commonly used functions:
.Pp
.
.Ft "usb2_error_t"
.Fo "usb2_transfer_setup"
.Fa "udev"
.Fa "ifaces"
.Fa "pxfer"
.Fa "setup_start"
.Fa "n_setup"
.Fa "priv_sc"
.Fa "priv_mtx"
.Fc
.
.Ft "void"
.Fo "usb2_transfer_unsetup"
.Fa "pxfer"
.Fa "n_setup"
.Fc
.
.Ft "void"
.Fo "usb2_transfer_start"
.Fa "xfer"
.Fc
.
.Ft "void"
.Fo "usb2_transfer_stop"
.Fa "xfer"
.Fc
.
.Ft "void"
.Fo "usb2_transfer_drain"
.Fa "xfer"
.Fc
.
.
.Sh DESCRIPTION
The
.Nm
module implements the core functionality of the USB standard and many
helper functions to make USB device driver programming easier and more
safe.
.
The
.Nm
module supports both USB Host and USB Device side mode!
.
.Sh USB TRANSFER MANAGEMENT FUNCTIONS
The USB standard defines four types of USB transfers.
.
Control transfers, Bulk transfers, Interrupt transfers and Isochronous
transfers.
.
All the transfer types are managed using the following five functions:
.
.Pp
.
.Fn usb2_transfer_setup
This function will allocate memory for and initialise an array of USB
transfers and all required DMA memory.
.
This function can sleep or block waiting for resources to become
available.
.Fa udev
is a pointer to "struct usb2_device".
.Fa ifaces
is an array of interface index numbers to use. See "if_index".
.Fa pxfer
is a pointer to an array of USB transfer pointers that are initialized
to NULL, and then pointed to allocated USB transfers.
.Fa setup_start
is a pointer to an array of USB config structures.
.Fa n_setup
is a number telling the USB system how many USB transfers should be
setup.
.Fa priv_sc
is the private softc pointer, which will be used to initialize
"xfer->priv_sc".
.Fa priv_mtx
is the private mutex protecting the transfer structure and the
softc. This pointer is used to initialize "xfer->priv_mtx".
This function returns
zero upon success. A non-zero return value indicates failure.
.
.Pp
.
.Fn usb2_transfer_unsetup
This function will release the given USB transfers and all allocated
resources associated with these USB transfers.
.Fa pxfer
is a pointer to an array of USB transfer pointers, that may be NULL,
that should be freed by the USB system.
.Fa n_setup
is a number telling the USB system how many USB transfers should be
unsetup.
.
This function can sleep waiting for USB transfers to complete.
.
This function is NULL safe with regard to the USB transfer structure
pointer.
.
It is not allowed to call this function from the USB transfer
callback.
.
.Pp
.
.Fn usb2_transfer_start
This function will start the USB transfer pointed to by
.Fa xfer,
if not already started.
.
This function is always non-blocking and must be called with the
so-called private USB mutex locked.
.
This function is NULL safe with regard to the USB transfer structure
pointer.
.
.Pp
.
.Fn usb2_transfer_stop
This function will stop the USB transfer pointed to by
.Fa xfer,
if not already stopped.
.
This function is always non-blocking and must be called with the
so-called private USB mutex locked.
.
This function can return before the USB callback has been called.
.
This function is NULL safe with regard to the USB transfer structure
pointer.
.
If the transfer was in progress, the callback will called with
"USB_ST_ERROR" and "xfer->error = USB_ERR_CANCELLED".
.
.Pp
.
.Fn usb2_transfer_drain
This function will stop an USB transfer, if not already stopped and
wait for any additional USB hardware operations to complete.
.
Buffers that are loaded into DMA using "usb2_set_frame_data()" can
safely be freed after that this function has returned.
.
This function can block the caller and will not return before the USB
callback has been called.
.
This function is NULL safe with regard to the USB transfer structure
pointer.
.
.Sh USB TRANSFER CALLBACK
.
The USB callback has three states.
.
USB_ST_SETUP, USB_ST_TRANSFERRED and USB_ST_ERROR. USB_ST_SETUP is the
initial state.
.
After the callback has been called with this state it will always be
called back at a later stage in one of the other two states.
.
In the USB_ST_ERROR state the "error" field of the USB transfer
structure is set to the error cause.
.
The USB callback should not restart the USB transfer in case the error
cause is USB_ERR_CANCELLED.
.
The USB callback is protected from recursion.
.
That means one can start and stop whatever transfer from the callback
of another transfer one desires.
.
Also the transfer that is currently called back.
.
Recursion is handled like this that when the callback that wants to
recurse returns it is called one more time.
.
.
.Pp
.
.Fn usb2_start_hardware
This function should only be called from within the USB callback and
is used to start the USB hardware.
.
Typical parameters that should be set in the USB transfer structure
before this function is called are "frlengths[]", "nframes" and
"frbuffers[]".
.
An USB transfer can have multiple frames consisting of one or more USB
packets making up an I/O vector for all USB transfer types.
.
After the USB transfer is complete "frlengths[]" is updated to the
actual USB transfer length for the given frame.
.Bd -literal -offset indent
void
usb2_default_callback(struct usb2_xfer *xfer)
{
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
/*
* Setup xfer->frlengths[], xfer->nframes
* and write data to xfer->frbuffers[], if any
*/
usb2_start_hardware(xfer);
break;
case USB_ST_TRANSFERRED:
/*
* Read data from xfer->frbuffers[], if any.
* "xfer->frlengths[]" should now have been
* updated to the actual length.
*/
break;
default: /* Error */
/*
* Print error message and clear stall
* for example.
*/
break;
}
/*
* Here it is safe to do something without the private
* USB mutex locked.
*/
return;
}
.Ed
.
.Sh USB CONTROL TRANSFERS
An USB control transfer has three parts.
.
First the SETUP packet, then DATA packet(s) and then a STATUS
packet.
.
The SETUP packet is always pointed to by "xfer->frbuffers[0]" and the
length is stored in "xfer->frlengths[0]" also if there should not be
sent any SETUP packet! If an USB control transfer has no DATA stage,
then "xfer->nframes" should be set to 1.
.
Else the default value is "xfer->nframes" equal to 2.
.
.Bd -literal -offset indent
Example1: SETUP + STATUS
xfer->nframes = 1;
xfer->frlenghts[0] = 8;
usb2_start_hardware(xfer);
Example2: SETUP + DATA + STATUS
xfer->nframes = 2;
xfer->frlenghts[0] = 8;
xfer->frlenghts[1] = 1;
usb2_start_hardware(xfer);
Example3: SETUP + DATA + STATUS - split
1st callback:
xfer->nframes = 1;
xfer->frlenghts[0] = 8;
usb2_start_hardware(xfer);
2nd callback:
/* IMPORTANT: frbuffers[0] must still point at the setup packet! */
xfer->nframes = 2;
xfer->frlenghts[0] = 0;
xfer->frlenghts[1] = 1;
usb2_start_hardware(xfer);
Example4: SETUP + STATUS - split
1st callback:
xfer->nframes = 1;
xfer->frlenghts[0] = 8;
xfer->flags.manual_status = 1;
usb2_start_hardware(xfer);
2nd callback:
xfer->nframes = 1;
xfer->frlenghts[0] = 0;
xfer->flags.manual_status = 0;
usb2_start_hardware(xfer);
.Ed
.Sh USB TRANSFER CONFIG
To simply the search for endpoints the
.Nm
module defines a USB config structure where it is possible to specify
the characteristics of the wanted endpoint.
.Bd -literal -offset indent
struct usb2_config {
bufsize,
callback
direction,
endpoint,
frames,
index flags,
interval,
timeout,
type,
};
.Ed
.
.Pp
.Fa type
field selects the USB pipe type.
.
Valid values are: UE_INTERRUPT, UE_CONTROL, UE_BULK,
UE_ISOCHRONOUS.
.
The special value UE_BULK_INTR will select BULK and INTERRUPT pipes.
.
This field is mandatory.
.
.Pp
.Fa endpoint
field selects the USB endpoint number.
.
A value of 0xFF, "-1" or "UE_ADDR_ANY" will select the first matching
endpoint.
.
This field is mandatory.
.
.Pp
.Fa direction
field selects the USB endpoint direction.
.
A value of "UE_DIR_ANY" will select the first matching endpoint.
.
Else valid values are: "UE_DIR_IN" and "UE_DIR_OUT".
.
"UE_DIR_IN" and "UE_DIR_OUT" can be binary OR'ed by "UE_DIR_SID" which
means that the direction will be swapped in case of
USB_MODE_DEVICE.
.
Note that "UE_DIR_IN" refers to the data transfer direction of the
"IN" tokens and "UE_DIR_OUT" refers to the data transfer direction of
the "OUT" tokens.
.
This field is mandatory.
.
.Pp
.Fa interval
field selects the interrupt interval.
.
The value of this field is given in milliseconds and is independent of
device speed.
.
Depending on the endpoint type, this field has different meaning:
.Bl -tag
.It UE_INTERRUPT
"0" use the default interrupt interval based on endpoint descriptor.
"Else" use the given value for polling rate.
.It UE_ISOCHRONOUS
"0" use default. "Else" the value is ignored.
.It UE_BULK
.It UE_CONTROL
"0" no transfer pre-delay. "Else" a delay as given by this field in
milliseconds is inserted before the hardware is started when
"usb2_start_hardware()" is called.
.Pp
NOTE: The transfer timeout, if any, is started after that the
pre-delay has elapsed!
.El
.
.Pp
.Fa timeout
field, if non-zero, will set the transfer timeout in milliseconds. If
the "timeout" field is zero and the transfer type is ISOCHRONOUS a
timeout of 250ms will be used.
.
.Pp
.Fa frames
field sets the maximum number of frames. If zero is specified it will
yield the following results:
.Bl -tag
.It UE_BULK
xfer->nframes = 1;
.It UE_INTERRUPT
xfer->nframes = 1;
.It UE_CONTROL
xfer->nframes = 2;
.It UE_ISOCHRONOUS
Not allowed. Will cause an error.
.El
.
.Pp
.Fa ep_index
field allows you to give a number, in case more endpoints match the
description, that selects which matching "ep_index" should be used.
.
.Pp
.Fa if_index
field allows you to select which of the interface numbers in the
"ifaces" array parameter passed to "usb2_transfer_setup" that should
be used when setting up the given USB transfer.
.
.Pp
.Fa flags
field has type "struct usb2_xfer_flags" and allows one to set initial
flags an USB transfer. Valid flags are:
.Bl -tag
.It force_short_xfer
This flag forces the last transmitted USB packet to be short. A short
packet has a length of less than "xfer->max_packet_size", which
derives from "wMaxPacketSize". This flag can be changed during
operation.
.It short_xfer_ok
This flag allows the received transfer length, "xfer->actlen" to be
less than "xfer->sumlen" upon completion of a transfer. This flag can
be changed during operation.
.It pipe_bof
This flag causes a failing USB transfer to remain first in the PIPE
queue except in the case of "xfer->error" equal to
"USB_ERR_CANCELLED". No other USB transfers in the affected PIPE queue
will be started until either:
.Bl -tag
.It 1
The failing USB transfer is stopped using "usb2_transfer_stop()".
.It 2
The failing USB transfer performs a successful transfer.
.El
The purpose of this flag is to avoid races when multiple transfers are
queued for execution on an USB endpoint, and the first executing
transfer fails leading to the need for clearing of stall for
example.
.
In this case this flag is used to prevent the following USB transfers
from being executed at the same time the clear-stall command is
executed on the USB control endpoint.
.
This flag can be changed during operation.
.Pp
"BOF" is short for "Block On Failure"
.Pp
NOTE: This flag should be set on all BULK and INTERRUPT USB transfers
which use an endpoint that can be shared between userland and kernel.
.
.
.It proxy_buffer
Setting this flag will cause that the total buffer size will be
rounded up to the nearest atomic hardware transfer size.
.
The maximum data length of any USB transfer is always stored in the
"xfer->max_data_length".
.
For control transfers the USB kernel will allocate additional space
for the 8-bytes of SETUP header.
.
These 8-bytes are not counted by the "xfer->max_data_length"
variable.
.
This flag can not be changed during operation.
.
.
.It ext_buffer
Setting this flag will cause that no data buffer will be
allocated.
.
Instead the USB client must supply a data buffer.
.
This flag can not be changed during operation.
.
.
.It manual_status
Setting this flag prevents an USB STATUS stage to be appended to the
end of the USB control transfer.
.
If no control data is transferred this flag must be cleared.
.
Else an error will be returned to the USB callback.
.
This flag is mostly useful for the USB device side.
.
This flag can be changed during operation.
.
.
.It no_pipe_ok
Setting this flag causes the USB_ERR_NO_PIPE error to be ignored. This
flag can not be changed during operation.
.
.
.It stall_pipe
.Bl -tag
.It Device Side Mode
Setting this flag will cause STALL pids to be sent to the endpoint
belonging to this transfer before the transfer is started.
.
The transfer is started at the moment the host issues a clear-stall
command on the STALL'ed endpoint.
.
This flag can be changed during operation.
.It Host Side Mode
Setting this flag will cause a clear-stall control request to be
executed on the endpoint before the USB transfer is started.
.El
.Pp
If this flag is changed outside the USB callback function you have to
use the "usb2_transfer_set_stall()" and "usb2_transfer_clear_stall()"
functions !
.
.El
.Pp
.Fa bufsize
field sets the total buffer size in bytes.
.
If this field is zero, "wMaxPacketSize" will be used, multiplied by
the "frames" field if the transfer type is ISOCHRONOUS.
.
This is useful for setting up interrupt pipes.
.
This field is mandatory.
.Pp
NOTE: For control transfers "bufsize" includes the length of the
request structure.
.
.Pp
.Fa callback
pointer sets the USB callback. This field is mandatory.
.
.
.Sh USB LINUX COMPAT LAYER
The
.Nm
module supports the Linux USB API.
.
.
.
.
.Sh USB SECURITY MODEL
.
.
The
.Nm
module implements fine grained read and write access based on username
and group.
.
Access is granted at four levels:
.
.Bl -tag
.It Level 4 - USB interface
USB interfaces can be given individual access rights.
.It Level 3 - USB device
USB devices can be given individual access rights.
.It Level 2 - USB BUS
USB busses can be given individual access rights.
.It Level 1 - USB
USB as a whole can be given individual access rights.
.El
.Pp
The
.Nm
module will search for access rights starting at level 4 continuing
downwards to USB at level 1.
.
For critical applications you should be aware that the outgoing serial
BUS traffic will be broadcasted to all USB devices.
.
For absolute security USB devices that require different access rights
should not be placed on the same USB BUS or controller.
.
If connected to the same USB bus, it is possible that a USB device can
sniff and intercept the communication of another USB device.
.
Using USB HUBs will not solve this problem.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usbconfig 8
.Sh STANDARDS
The
.Nm
module complies with the USB 2.0 standard.
.Sh HISTORY
The
.Nm
module has been inspired by the NetBSD USB stack initially written by
Lennart Augustsson. The
.Nm
module was written by
.An Hans Petter Selasky Aq hselasky@freebsd.org .

View File

@ -0,0 +1,65 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_ETHERNET 4
.Os
.
.Sh NAME
.
.
.Nm usb2_ethernet
.
.Nd "USB ethernet container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_ethernet"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_ethernet_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB ethernet drivers.
.
When you plug an USB ethernet device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,65 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_IMAGE 4
.Os
.
.Sh NAME
.
.
.Nm usb2_image
.
.Nd "USB image container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_image"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_image_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB image scanner drivers.
.
When you plug an USB image scanner device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,66 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_INPUT 4
.Os
.
.Sh NAME
.
.
.Nm usb2_input
.
.Nd "USB input container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_input"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_input_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB input drivers.
.
When you plug an USB input device, like USB mouse, USB keyboard and USB
HID device, the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,66 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_MISC 4
.Os
.
.Sh NAME
.
.
.Nm usb2_misc
.
.Nd "USB miscellaneous container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_misc"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_misc_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for various USB drivers that does not fit
into into any other USB container module.
.
When you plug an USB miscellaneous device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,66 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_NDIS 4
.Os
.
.Sh NAME
.
.
.Nm usb2_ndis
.
.Nd "USB NDIS container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_ndis"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_ndis_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for various USB drivers that does not fit
into into any other USB container module.
.
When you plug an USB NDIS device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,64 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_QUIRK 4
.Os
.
.Sh NAME
.
.
.Nm usb2_quirk
.
.Nd "USB quirk container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_quirk"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_quirk_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB quirks.
.
USB quirks are workarounds for specific USB device problems. The
.Nm
module can be dynamically loaded and unloaded at any time.
.
.
.
.Sh SEE ALSO
.Xr usb2_core 4
.Xr usb2_controller 4

View File

@ -0,0 +1,66 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_SERIAL 4
.Os
.
.Sh NAME
.
.
.Nm usb2_serial
.
.Nd "USB serial container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_serial"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_serial_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB serial and USB parallel port
drivers.
.
When you plug an USB serial or USB parallel port device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,65 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_SOUND 4
.Os
.
.Sh NAME
.
.
.Nm usb2_sound
.
.Nd "USB sound container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_sound"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_sound_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB sound and USB MIDI drivers.
.
When you plug an USB sound or USB MIDI device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,65 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_STORAGE 4
.Os
.
.Sh NAME
.
.
.Nm usb2_storage
.
.Nd "USB storage container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_storage"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_storage_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB storage drivers.
.
When you plug an USB storage device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -0,0 +1,84 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_TEMPLATE 4
.Os
.
.Sh NAME
.
.
.Nm usb2_template
.
.Nd "USB templates"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_template"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_template_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module implements various USB templates that are needed when
programming an USB device side driver.
.
A USB template consists of an USB device descriptor, one or more USB
configuration descriptors, one or more USB interface descriptors, one
or more USB endpoint descriptors, USB strings and additional USB
descriptors.
.
The USB template module currently has templates for USB Mass Storage,
USB CDC Ethernet and Message Transfer Protocol.
.
USB templates are currently selected using the "hw.usb2.template"
sysctl.
.
The "hw.usb2.template" value can be changed at any time, but will not
have any effect until the USB device has been re-enumerated.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4
.Sh STANDARDS
The
.Nm
module complies with the USB 2.0 standard.
.Sh HISTORY
The
.Nm
module was written by
.An Hans Petter Selasky Aq hselasky@freebsd.org .

View File

@ -0,0 +1,65 @@
.\" $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.
.\"
.Dd September 21, 2008
.Dt USB2_WLAN 4
.Os
.
.Sh NAME
.
.
.Nm usb2_wlan
.
.Nd "USB WLAN container module"
.
.
.Sh SYNOPSIS
To compile this module into the kernel, place the following line in
your kernel configuration file:
.Bd -ragged -offset indent
.Cd "device usb2_wlan"
.Ed
.Pp
To load the module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
usb2_wlan_load="YES"
.Ed
.
.Sh DESCRIPTION
The
.Nm
module is a container module for all USB WLAN drivers.
.
When you plug an USB WLAN device the
.Nm
module will try to load the required driver for your device
automatically.
.
.
.
.Sh SEE ALSO
.Xr usb2_controller 4
.Xr usb2_core 4

View File

@ -1366,6 +1366,145 @@ dev/usb/uscanner.c optional uscanner
dev/usb/uslcom.c optional uslcom
dev/usb/uvisor.c optional uvisor
dev/usb/uvscom.c optional uvscom
#
# USB2 controller drivers
#
dev/usb2/controller/at91dci.c optional usb2_core usb2_controller usb2_controller_at91dci
dev/usb2/controller/at91dci_atmelarm.c optional usb2_core usb2_controller usb2_controller_at91dci at91rm9200
dev/usb2/controller/musb2_otg.c optional usb2_core usb2_controller usb2_controller_musb
dev/usb2/controller/musb2_otg_atmelarm.c optional usb2_core usb2_controller usb2_controller_musb at91rm9200
dev/usb2/controller/ehci2.c optional usb2_core usb2_controller usb2_controller_ehci
dev/usb2/controller/ehci2_pci.c optional usb2_core usb2_controller usb2_controller_ehci pci
dev/usb2/controller/ohci2.c optional usb2_core usb2_controller usb2_controller_ohci
dev/usb2/controller/ohci2_atmelarm.c optional usb2_core usb2_controller usb2_controller_ohci at91rm9200
dev/usb2/controller/ohci2_pci.c optional usb2_core usb2_controller usb2_controller_ohci pci
dev/usb2/controller/uhci2.c optional usb2_core usb2_controller usb2_controller_uhci
dev/usb2/controller/uhci2_pci.c optional usb2_core usb2_controller usb2_controller_uhci pci
dev/usb2/controller/uss820dci.c optional usb2_core usb2_controller usb2_controller_uss820dci
dev/usb2/controller/uss820dci_atmelarm.c optional usb2_core usb2_controller usb2_controller_uss820dci at91rm9200
dev/usb2/controller/usb2_controller.c optional usb2_core usb2_controller
#
# USB2 storage drivers
#
dev/usb2/storage/ata-usb2.c optional usb2_core usb2_storage usb2_storage_ata
dev/usb2/storage/umass2.c optional usb2_core usb2_storage usb2_storage_mass
dev/usb2/storage/urio2.c optional usb2_core usb2_storage usb2_storage_rio
dev/usb2/storage/usb2_storage.c optional usb2_core usb2_storage
dev/usb2/storage/ustorage2_fs.c optional usb2_core usb2_storage usb2_storage_fs
#
# USB2 NDIS driver
#
dev/usb2/ndis/if_ndis_usb2.c optional usb2_core usb2_ndis
dev/usb2/ndis/usb2_ndis.c optional usb2_core usb2_ndis
#
# USB2 core
#
dev/usb2/core/usb2_busdma.c optional usb2_core
dev/usb2/core/usb2_compat_linux.c optional usb2_core
dev/usb2/core/usb2_config_td.c optional usb2_core
dev/usb2/core/usb2_core.c optional usb2_core
dev/usb2/core/usb2_debug.c optional usb2_core
dev/usb2/core/usb2_dev.c optional usb2_core
dev/usb2/core/usb2_device.c optional usb2_core
dev/usb2/core/usb2_dynamic.c optional usb2_core
dev/usb2/core/usb2_error.c optional usb2_core
dev/usb2/core/usb2_generic.c optional usb2_core
dev/usb2/core/usb2_handle_request.c optional usb2_core
dev/usb2/core/usb2_hid.c optional usb2_core
dev/usb2/core/usb2_hub.c optional usb2_core
dev/usb2/core/usb2_if.m optional usb2_core
dev/usb2/core/usb2_lookup.c optional usb2_core
dev/usb2/core/usb2_mbuf.c optional usb2_core
dev/usb2/core/usb2_msctest.c optional usb2_core
dev/usb2/core/usb2_parse.c optional usb2_core
dev/usb2/core/usb2_process.c optional usb2_core
dev/usb2/core/usb2_request.c optional usb2_core
dev/usb2/core/usb2_sw_transfer.c optional usb2_core
dev/usb2/core/usb2_transfer.c optional usb2_core
dev/usb2/core/usb2_util.c optional usb2_core
#
# USB2 ethernet drivers
#
dev/usb2/ethernet/if_aue2.c optional usb2_core usb2_ethernet usb2_ethernet_aue
dev/usb2/ethernet/if_axe2.c optional usb2_core usb2_ethernet usb2_ethernet_axe
dev/usb2/ethernet/if_cdce2.c optional usb2_core usb2_ethernet usb2_ethernet_cdce
dev/usb2/ethernet/if_cue2.c optional usb2_core usb2_ethernet usb2_ethernet_cue
dev/usb2/ethernet/if_kue2.c optional usb2_core usb2_ethernet usb2_ethernet_kue
dev/usb2/ethernet/if_rue2.c optional usb2_core usb2_ethernet usb2_ethernet_rue
dev/usb2/ethernet/if_udav2.c optional usb2_core usb2_ethernet usb2_ethernet_udav
dev/usb2/ethernet/usb2_ethernet.c optional usb2_core usb2_ethernet
#
# USB2 WLAN drivers
#
dev/usb2/wlan/if_rum2.c optional usb2_core usb2_wlan usb2_wlan_rum
dev/usb2/wlan/if_ural2.c optional usb2_core usb2_wlan usb2_wlan_ral
dev/usb2/wlan/if_zyd2.c optional usb2_core usb2_wlan usb2_wlan_zyd
dev/usb2/wlan/usb2_wlan.c optional usb2_core usb2_wlan
#
# USB2 serial and parallel port drivers
#
dev/usb2/serial/uark2.c optional usb2_core usb2_serial usb2_serial_ark
dev/usb2/serial/ubsa2.c optional usb2_core usb2_serial usb2_serial_bsa
dev/usb2/serial/ubser2.c optional usb2_core usb2_serial usb2_serial_bser
dev/usb2/serial/uchcom2.c optional usb2_core usb2_serial usb2_serial_chcom
dev/usb2/serial/ucycom2.c optional usb2_core usb2_serial usb2_serial_cycom
dev/usb2/serial/ufoma2.c optional usb2_core usb2_serial usb2_serial_foma
dev/usb2/serial/uftdi2.c optional usb2_core usb2_serial usb2_serial_ftdi
dev/usb2/serial/ugensa2.c optional usb2_core usb2_serial usb2_serial_gensa
dev/usb2/serial/uipaq2.c optional usb2_core usb2_serial usb2_serial_ipaq
dev/usb2/serial/ulpt2.c optional usb2_core usb2_serial usb2_serial_lpt
dev/usb2/serial/umct2.c optional usb2_core usb2_serial usb2_serial_mct
dev/usb2/serial/umodem2.c optional usb2_core usb2_serial usb2_serial_modem
dev/usb2/serial/umoscom2.c optional usb2_core usb2_serial usb2_serial_moscom
dev/usb2/serial/uplcom2.c optional usb2_core usb2_serial usb2_serial_plcom
dev/usb2/serial/usb2_serial.c optional usb2_core usb2_serial
dev/usb2/serial/uvisor2.c optional usb2_core usb2_serial usb2_serial_visor
dev/usb2/serial/uvscom2.c optional usb2_core usb2_serial usb2_serial_vscom
#
# USB2 bluetooth drivers
#
dev/usb2/bluetooth/usb2_bluetooth.c optional usb2_core usb2_bluetooth
dev/usb2/bluetooth/ng_ubt2.c optional usb2_core usb2_bluetooth usb2_bluetooth_ng
dev/usb2/bluetooth/ubtbcmfw2.c optional usb2_core usb2_bluetooth usb2_bluetooth_fw
#
# USB2 misc drivers
#
dev/usb2/misc/usb2_misc.c optional usb2_core usb2_misc
dev/usb2/misc/ufm2.c optional usb2_core usb2_misc usb2_misc_fm
dev/usb2/misc/udbp2.c optional usb2_core usb2_misc usb2_misc_dbp
#
# USB2 input drivers
#
dev/usb2/input/uhid2.c optional usb2_core usb2_input usb2_input_hid
dev/usb2/input/ukbd2.c optional usb2_core usb2_input usb2_input_kbd
dev/usb2/input/ums2.c optional usb2_core usb2_input usb2_input_ms
dev/usb2/input/usb2_input.c optional usb2_core usb2_input
#
# USB2 quirks
#
dev/usb2/quirk/usb2_quirk.c optional usb2_core usb2_quirk
#
# USB2 templates
#
dev/usb2/template/usb2_template.c optional usb2_core usb2_template
dev/usb2/template/usb2_template_cdce.c optional usb2_core usb2_template
dev/usb2/template/usb2_template_msc.c optional usb2_core usb2_template
dev/usb2/template/usb2_template_mtp.c optional usb2_core usb2_template
#
# USB2 image drivers
#
dev/usb2/image/usb2_image.c optional usb2_core usb2_image
dev/usb2/image/uscanner2.c optional usb2_core usb2_image usb2_scanner
#
# USB2 sound and MIDI drivers
#
dev/usb2/sound/usb2_sound.c optional usb2_core usb2_sound
dev/usb2/sound/uaudio2.c optional usb2_core usb2_sound
dev/usb2/sound/uaudio2_pcm.c optional usb2_core usb2_sound
#
# USB2 END
#
dev/utopia/idtphy.c optional utopia
dev/utopia/suni.c optional utopia
dev/utopia/utopia.c optional utopia

View File

@ -570,13 +570,26 @@ chn_read(struct pcm_channel *c, struct uio *buf)
void
chn_intr(struct pcm_channel *c)
{
CHN_LOCK(c);
uint8_t do_unlock;
if (CHN_LOCK_OWNED(c)) {
/*
* Allow sound drivers to call this function with
* "CHN_LOCK()" locked:
*/
do_unlock = 0;
} else {
do_unlock = 1;
CHN_LOCK(c);
}
c->interrupts++;
if (c->direction == PCMDIR_PLAY)
chn_wrintr(c);
else
chn_rdintr(c);
CHN_UNLOCK(c);
if (do_unlock) {
CHN_UNLOCK(c);
}
return;
}
u_int32_t

View File

@ -258,11 +258,13 @@ int chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak);
#endif
#ifdef USING_MUTEX
#define CHN_LOCK_OWNED(c) mtx_owned((struct mtx *)((c)->lock))
#define CHN_LOCK(c) mtx_lock((struct mtx *)((c)->lock))
#define CHN_UNLOCK(c) mtx_unlock((struct mtx *)((c)->lock))
#define CHN_TRYLOCK(c) mtx_trylock((struct mtx *)((c)->lock))
#define CHN_LOCKASSERT(c) mtx_assert((struct mtx *)((c)->lock), MA_OWNED)
#else
#define CHN_LOCK_OWNED(c) 0
#define CHN_LOCK(c)
#define CHN_UNLOCK(c)
#define CHN_TRYLOCK(c)

View File

@ -589,7 +589,7 @@ mixer_delete(struct snd_mixer *m)
KASSERT(m->type == MIXER_TYPE_SECONDARY,
("%s(): illegal mixer type=%d", __func__, m->type));
snd_mtxlock(m->lock);
/* mixer uninit can sleep --hps */
MIXER_UNINIT(m);
@ -704,14 +704,24 @@ mixer_uninit(device_t dev)
return EBUSY;
}
/* destroy dev can sleep --hps */
snd_mtxunlock(m->lock);
pdev->si_drv1 = NULL;
destroy_dev(pdev);
snd_mtxlock(m->lock);
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
mixer_set(m, i, 0);
mixer_setrecsrc(m, SOUND_MASK_MIC);
snd_mtxunlock(m->lock);
/* mixer uninit can sleep --hps */
MIXER_UNINIT(m);
snd_mtxfree(m->lock);
@ -1280,3 +1290,16 @@ mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
return (EINVAL);
}
/*
* Allow the sound driver to use the mixer lock to protect its mixer
* data:
*/
struct mtx *
mixer_get_lock(struct snd_mixer *m)
{
if (m->lock == NULL) {
return (&Giant);
}
return (m->lock);
}

View File

@ -56,6 +56,7 @@ void mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev);
u_int32_t mix_getparent(struct snd_mixer *m, u_int32_t dev);
u_int32_t mix_getchild(struct snd_mixer *m, u_int32_t dev);
void *mix_getdevinfo(struct snd_mixer *m);
struct mtx *mixer_get_lock(struct snd_mixer *m);
extern int mixer_count;

View File

@ -0,0 +1,18 @@
$Id: TODO,v 1.1 2002/11/24 19:46:56 max Exp $
$FreeBSD$
1) SMP/Locking
The code makes use of ng_send_fn() whenever possible. Just
need to verify and make sure i did it right
2) Firmware upgrade
According to Bluetooth spec device may present third interface
to perform firmware upgrade. 3Com USB Bluetooth dongle has
such interface. Need to implement set of Netgraph messages.
3) Isochronous USB transfers (SCO data)
Tried to fix isochrounous transfers, which are still disabled
by default.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
/*
* ng_ubt_var.h
*/
/*-
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ng_ubt_var.h,v 1.2 2003/03/22 23:44:36 max Exp $
* $FreeBSD$
*/
#ifndef _NG_UBT_VAR_H_
#define _NG_UBT_VAR_H_
/* pullup wrapper */
#define NG_UBT_M_PULLUP(m, s) \
do { \
if ((m)->m_len < (s)) \
(m) = m_pullup((m), (s)); \
if ((m) == NULL) { \
NG_UBT_ALERT("%s: %s - m_pullup(%d) failed\n", \
__func__, sc->sc_name, (s)); \
} \
} while (0)
/* Debug printf's */
#define NG_UBT_DEBUG(level, sc, fmt, ...) do { \
if ((sc)->sc_debug >= (level)) { \
printf("%s:%s:%d: " fmt, (sc)->sc_name, \
__FUNCTION__, __LINE__,## __VA_ARGS__); \
} \
} while (0)
#define NG_UBT_ALERT(...) NG_UBT_DEBUG(NG_UBT_ALERT_LEVEL, __VA_ARGS__)
#define NG_UBT_ERR(...) NG_UBT_DEBUG(NG_UBT_ERR_LEVEL, __VA_ARGS__)
#define NG_UBT_WARN(...) NG_UBT_DEBUG(NG_UBT_WARN_LEVEL, __VA_ARGS__)
#define NG_UBT_INFO(...) NG_UBT_DEBUG(NG_UBT_INFO_LEVEL, __VA_ARGS__)
/* Bluetooth USB control request type */
#define UBT_HCI_REQUEST 0x20
#define UBT_DEFAULT_QLEN 12
/* Bluetooth USB defines */
#define UBT_IF_0_N_TRANSFER 7 /* units */
#define UBT_IF_1_N_TRANSFER 4 /* units */
#define UBT_ISOC_NFRAMES 25 /* units */
/* USB device softc structure */
struct ubt_softc {
/* State */
ng_ubt_node_debug_ep sc_debug; /* debug level */
uint32_t sc_flags; /* device flags */
#define UBT_NEED_FRAME_TYPE (1 << 0)/* device required frame type */
#define UBT_HAVE_FRAME_TYPE UBT_NEED_FRAME_TYPE
#define UBT_FLAG_READ_STALL (1 << 1)/* read transfer has stalled */
#define UBT_FLAG_WRITE_STALL (1 << 2)/* write transfer has stalled */
#define UBT_FLAG_INTR_STALL (1 << 3)/* interrupt transfer has stalled */
ng_ubt_node_stat_ep sc_stat; /* statistic */
#define NG_UBT_STAT_PCKTS_SENT(s) (s).pckts_sent ++
#define NG_UBT_STAT_BYTES_SENT(s, n) (s).bytes_sent += (n)
#define NG_UBT_STAT_PCKTS_RECV(s) (s).pckts_recv ++
#define NG_UBT_STAT_BYTES_RECV(s, n) (s).bytes_recv += (n)
#define NG_UBT_STAT_OERROR(s) (s).oerrors ++
#define NG_UBT_STAT_IERROR(s) (s).ierrors ++
#define NG_UBT_STAT_RESET(s) bzero(&(s), sizeof((s)))
uint8_t sc_name[16];
struct mtx sc_mtx;
/* USB device specific */
struct usb2_xfer *sc_xfer_if_0[UBT_IF_0_N_TRANSFER];
struct usb2_xfer *sc_xfer_if_1[UBT_IF_1_N_TRANSFER];
/* Interrupt pipe (HCI events) */
struct mbuf *sc_intr_buffer; /* interrupt buffer */
/* Control pipe (HCI commands) */
struct ng_bt_mbufq sc_cmdq; /* HCI command queue */
#define UBT_CTRL_BUFFER_SIZE (sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE)
/* Bulk in pipe (ACL data) */
struct mbuf *sc_bulk_in_buffer; /* bulk-in buffer */
/* Bulk out pipe (ACL data) */
struct ng_bt_mbufq sc_aclq; /* ACL data queue */
#define UBT_BULK_READ_BUFFER_SIZE (MCLBYTES-1) /* reserve one byte for ID-tag */
#define UBT_BULK_WRITE_BUFFER_SIZE (MCLBYTES)
/* Isoc. out pipe (ACL data) */
struct ng_bt_mbufq sc_scoq; /* SCO data queue */
/* Isoc. in pipe (ACL data) */
struct ng_bt_mbufq sc_sciq; /* SCO data queue */
/* Netgraph specific */
node_p sc_node; /* pointer back to node */
hook_p sc_hook; /* upstream hook */
};
typedef struct ubt_softc ubt_softc_t;
typedef struct ubt_softc *ubt_softc_p;
#endif /* ndef _NG_UBT_VAR_H_ */

View File

@ -0,0 +1,448 @@
/*
* ubtbcmfw.c
*/
/*-
* Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* 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.
*
* $Id: ubtbcmfw.c,v 1.3 2003/10/10 19:15:08 max Exp $
* $FreeBSD$
*/
#include <dev/usb2/include/usb2_devid.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_ioctl.h>
#define USB_DEBUG_VAR usb2_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_parse.h>
#include <dev/usb2/core/usb2_lookup.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_mbuf.h>
#include <dev/usb2/core/usb2_dev.h>
/*
* Download firmware to BCM2033.
*/
#define UBTBCMFW_CONFIG_NO 1 /* Config number */
#define UBTBCMFW_IFACE_IDX 0 /* Control interface */
#define UBTBCMFW_T_MAX 4 /* units */
struct ubtbcmfw_softc {
struct usb2_fifo_sc sc_fifo;
struct mtx sc_mtx;
device_t sc_dev;
struct usb2_device *sc_udev;
struct usb2_xfer *sc_xfer[UBTBCMFW_T_MAX];
uint8_t sc_flags;
#define UBTBCMFW_FLAG_WRITE_STALL 0x01
#define UBTBCMFW_FLAG_READ_STALL 0x02
};
#define UBTBCMFW_BSIZE 1024
#define UBTBCMFW_IFQ_MAXLEN 2
/* prototypes */
static device_probe_t ubtbcmfw_probe;
static device_attach_t ubtbcmfw_attach;
static device_detach_t ubtbcmfw_detach;
static usb2_callback_t ubtbcmfw_write_callback;
static usb2_callback_t ubtbcmfw_write_clear_stall_callback;
static usb2_callback_t ubtbcmfw_read_callback;
static usb2_callback_t ubtbcmfw_read_clear_stall_callback;
static usb2_fifo_close_t ubtbcmfw_close;
static usb2_fifo_cmd_t ubtbcmfw_start_read;
static usb2_fifo_cmd_t ubtbcmfw_start_write;
static usb2_fifo_cmd_t ubtbcmfw_stop_read;
static usb2_fifo_cmd_t ubtbcmfw_stop_write;
static usb2_fifo_ioctl_t ubtbcmfw_ioctl;
static usb2_fifo_open_t ubtbcmfw_open;
static struct usb2_fifo_methods ubtbcmfw_fifo_methods = {
.f_close = &ubtbcmfw_close,
.f_ioctl = &ubtbcmfw_ioctl,
.f_open = &ubtbcmfw_open,
.f_start_read = &ubtbcmfw_start_read,
.f_start_write = &ubtbcmfw_start_write,
.f_stop_read = &ubtbcmfw_stop_read,
.f_stop_write = &ubtbcmfw_stop_write,
.basename[0] = "ubtbcmfw",
.basename[1] = "ubtbcmfw",
.basename[2] = "ubtbcmfw",
.postfix[0] = "",
.postfix[1] = ".1",
.postfix[2] = ".2",
};
static const struct usb2_config ubtbcmfw_config[UBTBCMFW_T_MAX] = {
[0] = {
.type = UE_BULK,
.endpoint = 0x02, /* fixed */
.direction = UE_DIR_OUT,
.mh.bufsize = UBTBCMFW_BSIZE,
.mh.flags = {.pipe_bof = 1,.proxy_buffer = 1,},
.mh.callback = &ubtbcmfw_write_callback,
},
[1] = {
.type = UE_INTERRUPT,
.endpoint = 0x01, /* fixed */
.direction = UE_DIR_IN,
.mh.bufsize = UBTBCMFW_BSIZE,
.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,},
.mh.callback = &ubtbcmfw_read_callback,
},
[2] = {
.type = UE_CONTROL,
.endpoint = 0x00, /* Control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
.mh.flags = {},
.mh.callback = &ubtbcmfw_write_clear_stall_callback,
.mh.timeout = 1000, /* 1 second */
.mh.interval = 50, /* 50ms */
},
[3] = {
.type = UE_CONTROL,
.endpoint = 0x00, /* Control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
.mh.flags = {},
.mh.callback = &ubtbcmfw_read_clear_stall_callback,
.mh.timeout = 1000, /* 1 second */
.mh.interval = 50, /* 50ms */
},
};
/*
* Module
*/
static devclass_t ubtbcmfw_devclass;
static device_method_t ubtbcmfw_methods[] = {
DEVMETHOD(device_probe, ubtbcmfw_probe),
DEVMETHOD(device_attach, ubtbcmfw_attach),
DEVMETHOD(device_detach, ubtbcmfw_detach),
{0, 0}
};
static driver_t ubtbcmfw_driver = {
.name = "ubtbcmfw",
.methods = ubtbcmfw_methods,
.size = sizeof(struct ubtbcmfw_softc),
};
DRIVER_MODULE(ubtbcmfw, ushub, ubtbcmfw_driver, ubtbcmfw_devclass, NULL, 0);
MODULE_DEPEND(ubtbcmfw, usb2_bluetooth, 1, 1, 1);
MODULE_DEPEND(ubtbcmfw, usb2_core, 1, 1, 1);
/*
* Probe for a USB Bluetooth device
*/
static int
ubtbcmfw_probe(device_t dev)
{
struct usb2_attach_arg *uaa = device_get_ivars(dev);
if (uaa->usb2_mode != USB_MODE_HOST) {
return (ENXIO);
}
if (uaa->info.bIfaceIndex != 0)
return (ENXIO);
/* Match the boot device. */
if (uaa->info.idVendor == USB_VENDOR_BROADCOM &&
uaa->info.idProduct == USB_PRODUCT_BROADCOM_BCM2033)
return (0);
return (ENXIO);
}
/*
* Attach the device
*/
static int
ubtbcmfw_attach(device_t dev)
{
struct usb2_attach_arg *uaa = device_get_ivars(dev);
struct ubtbcmfw_softc *sc = device_get_softc(dev);
int32_t err;
uint8_t iface_index;
if (sc == NULL) {
return (ENOMEM);
}
sc->sc_dev = dev;
sc->sc_udev = uaa->device;
device_set_usb2_desc(dev);
mtx_init(&sc->sc_mtx, "ubtbcmfw lock", NULL, MTX_DEF | MTX_RECURSE);
iface_index = UBTBCMFW_IFACE_IDX;
err = usb2_transfer_setup(uaa->device,
&iface_index, sc->sc_xfer, ubtbcmfw_config,
UBTBCMFW_T_MAX, sc, &sc->sc_mtx);
if (err) {
device_printf(dev, "allocating USB transfers "
"failed, err=%s\n", usb2_errstr(err));
goto detach;
}
/* set interface permissions */
usb2_set_iface_perm(uaa->device, uaa->info.bIfaceIndex,
UID_ROOT, GID_OPERATOR, 0644);
err = usb2_fifo_attach(uaa->device, sc, &sc->sc_mtx,
&ubtbcmfw_fifo_methods, &sc->sc_fifo,
device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex);
if (err) {
goto detach;
}
return (0); /* success */
detach:
ubtbcmfw_detach(dev);
return (ENOMEM); /* failure */
}
/*
* Detach the device
*/
static int
ubtbcmfw_detach(device_t dev)
{
struct ubtbcmfw_softc *sc = device_get_softc(dev);
usb2_fifo_detach(&sc->sc_fifo);
usb2_transfer_unsetup(sc->sc_xfer, UBTBCMFW_T_MAX);
mtx_destroy(&sc->sc_mtx);
return (0);
}
static void
ubtbcmfw_write_callback(struct usb2_xfer *xfer)
{
struct ubtbcmfw_softc *sc = xfer->priv_sc;
struct usb2_fifo *f = sc->sc_fifo.fp[USB_FIFO_RX];
uint32_t actlen;
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
case USB_ST_SETUP:
if (sc->sc_flags & UBTBCMFW_FLAG_WRITE_STALL) {
usb2_transfer_start(sc->sc_xfer[2]);
return;
}
if (usb2_fifo_get_data(f, xfer->frbuffers, 0,
UBTBCMFW_BSIZE, &actlen, 0)) {
xfer->frlengths[0] = actlen;
usb2_start_hardware(xfer);
}
return;
default: /* Error */
if (xfer->error != USB_ERR_CANCELLED) {
/* try to clear stall first */
sc->sc_flags |= UBTBCMFW_FLAG_WRITE_STALL;
usb2_transfer_start(sc->sc_xfer[2]);
}
return;
}
}
static void
ubtbcmfw_write_clear_stall_callback(struct usb2_xfer *xfer)
{
struct ubtbcmfw_softc *sc = xfer->priv_sc;
struct usb2_xfer *xfer_other = sc->sc_xfer[0];
if (usb2_clear_stall_callback(xfer, xfer_other)) {
DPRINTF("stall cleared\n");
sc->sc_flags &= ~UBTBCMFW_FLAG_WRITE_STALL;
usb2_transfer_start(xfer_other);
}
return;
}
static void
ubtbcmfw_read_callback(struct usb2_xfer *xfer)
{
struct ubtbcmfw_softc *sc = xfer->priv_sc;
struct usb2_fifo *f = sc->sc_fifo.fp[USB_FIFO_RX];
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
usb2_fifo_put_data(f, xfer->frbuffers,
0, xfer->actlen, 1);
case USB_ST_SETUP:
if (sc->sc_flags & UBTBCMFW_FLAG_READ_STALL) {
usb2_transfer_start(sc->sc_xfer[3]);
return;
}
if (usb2_fifo_put_bytes_max(f) != 0) {
xfer->frlengths[0] = xfer->max_data_length;
usb2_start_hardware(xfer);
}
return;
default: /* Error */
if (xfer->error != USB_ERR_CANCELLED) {
/* try to clear stall first */
sc->sc_flags |= UBTBCMFW_FLAG_READ_STALL;
usb2_transfer_start(sc->sc_xfer[3]);
}
return;
}
}
static void
ubtbcmfw_read_clear_stall_callback(struct usb2_xfer *xfer)
{
struct ubtbcmfw_softc *sc = xfer->priv_sc;
struct usb2_xfer *xfer_other = sc->sc_xfer[1];
if (usb2_clear_stall_callback(xfer, xfer_other)) {
DPRINTF("stall cleared\n");
sc->sc_flags &= ~UBTBCMFW_FLAG_READ_STALL;
usb2_transfer_start(xfer_other);
}
return;
}
static void
ubtbcmfw_start_read(struct usb2_fifo *fifo)
{
struct ubtbcmfw_softc *sc = fifo->priv_sc0;
usb2_transfer_start(sc->sc_xfer[1]);
return;
}
static void
ubtbcmfw_stop_read(struct usb2_fifo *fifo)
{
struct ubtbcmfw_softc *sc = fifo->priv_sc0;
usb2_transfer_stop(sc->sc_xfer[3]);
usb2_transfer_stop(sc->sc_xfer[1]);
return;
}
static void
ubtbcmfw_start_write(struct usb2_fifo *fifo)
{
struct ubtbcmfw_softc *sc = fifo->priv_sc0;
usb2_transfer_start(sc->sc_xfer[0]);
return;
}
static void
ubtbcmfw_stop_write(struct usb2_fifo *fifo)
{
struct ubtbcmfw_softc *sc = fifo->priv_sc0;
usb2_transfer_stop(sc->sc_xfer[2]);
usb2_transfer_stop(sc->sc_xfer[0]);
return;
}
static int
ubtbcmfw_open(struct usb2_fifo *fifo, int fflags, struct thread *td)
{
struct ubtbcmfw_softc *sc = fifo->priv_sc0;
if (fflags & FREAD) {
if (usb2_fifo_alloc_buffer(fifo,
sc->sc_xfer[1]->max_data_length,
UBTBCMFW_IFQ_MAXLEN)) {
return (ENOMEM);
}
}
if (fflags & FWRITE) {
/* clear stall first */
mtx_lock(&sc->sc_mtx);
sc->sc_flags |= UBTBCMFW_FLAG_WRITE_STALL;
mtx_unlock(&sc->sc_mtx);
if (usb2_fifo_alloc_buffer(fifo,
sc->sc_xfer[0]->max_data_length,
UBTBCMFW_IFQ_MAXLEN)) {
return (ENOMEM);
}
}
return (0);
}
static void
ubtbcmfw_close(struct usb2_fifo *fifo, int fflags, struct thread *td)
{
if (fflags & (FREAD | FWRITE)) {
usb2_fifo_free_buffer(fifo);
}
return;
}
static int
ubtbcmfw_ioctl(struct usb2_fifo *fifo, u_long cmd, void *data,
int fflags, struct thread *td)
{
struct ubtbcmfw_softc *sc = fifo->priv_sc0;
int error = 0;
switch (cmd) {
case USB_GET_DEVICE_DESC:
*(struct usb2_device_descriptor *)data =
*usb2_get_device_descriptor(sc->sc_udev);
break;
default:
error = EINVAL;
break;
}
return (error);
}

View File

@ -0,0 +1,31 @@
/* $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 <dev/usb2/core/usb2_core.h>
#include <dev/usb2/bluetooth/usb2_bluetooth.h>
MODULE_VERSION(usb2_bluetooth, 1);
MODULE_DEPEND(usb2_bluetooth, usb2_core, 1, 1, 1);

View File

@ -0,0 +1,30 @@
/* $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.
*/
#ifndef _USB2_BLUETOOTH_H_
#define _USB2_BLUETOOTH_H_
#endif /* _USB2_BLUETOOTH_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,242 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2006 ATMEL
* Copyright (c) 2007 Hans Petter Selasky <hselasky@freebsd.org>
* 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.
*/
/*
* USB Device Port (UDP) register definition, based on
* "AT91RM9200.h" provided by ATMEL.
*/
#ifndef _AT9100_DCI_H_
#define _AT9100_DCI_H_
#define AT91_UDP_FRM 0x00 /* Frame number register */
#define AT91_UDP_FRM_MASK (0x7FF << 0) /* Frame Number as Defined in
* the Packet Field Formats */
#define AT91_UDP_FRM_ERR (0x1 << 16) /* Frame Error */
#define AT91_UDP_FRM_OK (0x1 << 17) /* Frame OK */
#define AT91_UDP_GSTATE 0x04 /* Global state register */
#define AT91_UDP_GSTATE_ADDR (0x1 << 0) /* Addressed state */
#define AT91_UDP_GSTATE_CONFG (0x1 << 1) /* Configured */
#define AT91_UDP_GSTATE_ESR (0x1 << 2) /* Enable Send Resume */
#define AT91_UDP_GSTATE_RSM (0x1 << 3) /* A Resume Has Been Sent to
* the Host */
#define AT91_UDP_GSTATE_RMW (0x1 << 4) /* Remote Wake Up Enable */
#define AT91_UDP_FADDR 0x08 /* Function Address Register */
#define AT91_UDP_FADDR_MASK (0x7F << 0)/* Function Address Mask */
#define AT91_UDP_FADDR_EN (0x1 << 8)/* Function Enable */
#define AT91_UDP_RES0 0x0C /* Reserved 0 */
#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */
#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */
#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */
#define AT91_UDP_ISR 0x1C /* Interrupt Status Register */
#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */
#define AT91_UDP_INT_EP(n) (0x1 <<(n))/* Endpoint "n" Interrupt */
#define AT91_UDP_INT_RXSUSP (0x1 << 8)/* USB Suspend Interrupt */
#define AT91_UDP_INT_RXRSM (0x1 << 9)/* USB Resume Interrupt */
#define AT91_UDP_INT_EXTRSM (0x1 << 10)/* USB External Resume Interrupt */
#define AT91_UDP_INT_SOFINT (0x1 << 11)/* USB Start Of frame Interrupt */
#define AT91_UDP_INT_END_BR (0x1 << 12)/* USB End Of Bus Reset Interrupt */
#define AT91_UDP_INT_WAKEUP (0x1 << 13)/* USB Resume Interrupt */
#define AT91_UDP_INT_BUS \
(AT91_UDP_INT_RXSUSP|AT91_UDP_INT_RXRSM| \
AT91_UDP_INT_END_BR)
#define AT91_UDP_INT_EPS \
(AT91_UDP_INT_EP(0)|AT91_UDP_INT_EP(1)| \
AT91_UDP_INT_EP(2)|AT91_UDP_INT_EP(3)| \
AT91_UDP_INT_EP(4)|AT91_UDP_INT_EP(5))
#define AT91_UDP_INT_DEFAULT \
(AT91_UDP_INT_EPS|AT91_UDP_INT_BUS)
#define AT91_UDP_RES1 0x24 /* Reserved 1 */
#define AT91_UDP_RST 0x28 /* Reset Endpoint Register */
#define AT91_UDP_RST_EP(n) (0x1 << (n))/* Reset Endpoint "n" */
#define AT91_UDP_RES2 0x2C /* Reserved 2 */
#define AT91_UDP_CSR(n) (0x30 + (4*(n)))/* Endpoint Control and Status
* Register */
#define AT91_UDP_CSR_TXCOMP (0x1 << 0) /* Generates an IN packet with data
* previously written in the DPR */
#define AT91_UDP_CSR_RX_DATA_BK0 (0x1 << 1) /* Receive Data Bank 0 */
#define AT91_UDP_CSR_RXSETUP (0x1 << 2) /* Sends STALL to the Host
* (Control endpoints) */
#define AT91_UDP_CSR_ISOERROR (0x1 << 3) /* Isochronous error
* (Isochronous endpoints) */
#define AT91_UDP_CSR_STALLSENT (0x1 << 3) /* Stall sent (Control, bulk,
* interrupt endpoints) */
#define AT91_UDP_CSR_TXPKTRDY (0x1 << 4) /* Transmit Packet Ready */
#define AT91_UDP_CSR_FORCESTALL (0x1 << 5) /* Force Stall (used by
* Control, Bulk and
* Isochronous endpoints). */
#define AT91_UDP_CSR_RX_DATA_BK1 (0x1 << 6) /* Receive Data Bank 1 (only
* used by endpoints with
* ping-pong attributes). */
#define AT91_UDP_CSR_DIR (0x1 << 7) /* Transfer Direction */
#define AT91_UDP_CSR_ET_MASK (0x7 << 8) /* Endpoint transfer type mask */
#define AT91_UDP_CSR_ET_CTRL (0x0 << 8) /* Control IN+OUT */
#define AT91_UDP_CSR_ET_ISO (0x1 << 8) /* Isochronous */
#define AT91_UDP_CSR_ET_BULK (0x2 << 8) /* Bulk */
#define AT91_UDP_CSR_ET_INT (0x3 << 8) /* Interrupt */
#define AT91_UDP_CSR_ET_DIR_OUT (0x0 << 8) /* OUT tokens */
#define AT91_UDP_CSR_ET_DIR_IN (0x4 << 8) /* IN tokens */
#define AT91_UDP_CSR_DTGLE (0x1 << 11) /* Data Toggle */
#define AT91_UDP_CSR_EPEDS (0x1 << 15) /* Endpoint Enable Disable */
#define AT91_UDP_CSR_RXBYTECNT (0x7FF << 16) /* Number Of Bytes Available
* in the FIFO */
#define AT91_UDP_FDR(n) (0x50 + (4*(n)))/* Endpoint FIFO Data Register */
#define AT91_UDP_RES3 0x70 /* Reserved 3 */
#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */
#define AT91_UDP_TXVC_DIS (0x1 << 8)
#define AT91_UDP_EP_MAX 6 /* maximum number of endpoints
* supported */
#define AT91_UDP_READ_4(sc, reg) \
bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
#define AT91_UDP_WRITE_4(sc, reg, data) \
bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data)
struct at91dci_td;
typedef uint8_t (at91dci_cmd_t)(struct at91dci_td *td);
struct at91dci_td {
bus_space_tag_t io_tag;
bus_space_handle_t io_hdl;
struct at91dci_td *obj_next;
at91dci_cmd_t *func;
struct usb2_page_cache *pc;
uint32_t offset;
uint32_t remainder;
uint16_t max_packet_size;
uint8_t status_reg;
uint8_t fifo_reg;
uint8_t fifo_bank:1;
uint8_t error:1;
uint8_t alt_next:1;
uint8_t short_pkt:1;
uint8_t support_multi_buffer:1;
uint8_t did_stall:1;
};
struct at91dci_std_temp {
at91dci_cmd_t *func;
struct usb2_page_cache *pc;
struct at91dci_td *td;
struct at91dci_td *td_next;
uint32_t len;
uint32_t offset;
uint16_t max_frame_size;
uint8_t short_pkt;
/*
* short_pkt = 0: transfer should be short terminated
* short_pkt = 1: transfer should not be short terminated
*/
uint8_t setup_alt_next;
};
struct at91dci_config_desc {
struct usb2_config_descriptor confd;
struct usb2_interface_descriptor ifcd;
struct usb2_endpoint_descriptor endpd;
} __packed;
union at91dci_hub_temp {
uWord wValue;
struct usb2_port_status ps;
};
struct at91dci_ep_flags {
uint8_t fifo_bank:1; /* hardware specific */
};
struct at91dci_flags {
uint8_t change_connect:1;
uint8_t change_suspend:1;
uint8_t status_suspend:1; /* set if suspended */
uint8_t status_vbus:1; /* set if present */
uint8_t status_bus_reset:1; /* set if reset complete */
uint8_t remote_wakeup:1;
uint8_t self_powered:1;
uint8_t clocks_off:1;
uint8_t port_powered:1;
uint8_t port_enabled:1;
uint8_t d_pulled_up:1;
};
struct at91dci_softc {
struct usb2_bus sc_bus;
union at91dci_hub_temp sc_hub_temp;
LIST_HEAD(, usb2_xfer) sc_interrupt_list_head;
struct usb2_sw_transfer sc_root_ctrl;
struct usb2_sw_transfer sc_root_intr;
struct usb2_config_td sc_config_td;
struct resource *sc_io_res;
struct resource *sc_irq_res;
void *sc_intr_hdl;
bus_size_t sc_io_size;
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
void (*sc_clocks_on) (void *arg);
void (*sc_clocks_off) (void *arg);
void *sc_clocks_arg;
void (*sc_pull_up) (void *arg);
void (*sc_pull_down) (void *arg);
void *sc_pull_arg;
uint8_t sc_rt_addr; /* root HUB address */
uint8_t sc_dv_addr; /* device address */
uint8_t sc_conf; /* root HUB config */
uint8_t sc_hub_idata[1];
struct at91dci_flags sc_flags;
struct at91dci_ep_flags sc_ep_flags[AT91_UDP_EP_MAX];
};
/* prototypes */
usb2_error_t at91dci_init(struct at91dci_softc *sc);
void at91dci_uninit(struct at91dci_softc *sc);
void at91dci_suspend(struct at91dci_softc *sc);
void at91dci_resume(struct at91dci_softc *sc);
void at91dci_interrupt(struct at91dci_softc *sc);
#endif /* _AT9100_DCI_H_ */

View File

@ -0,0 +1,361 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*-
* Copyright (c) 2007-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 <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/at91dci.h>
#include <sys/rman.h>
#include <arm/at91/at91_pmcvar.h>
#include <arm/at91/at91rm92reg.h>
#include <arm/at91/at91_pio_rm9200.h>
#include <arm/at91/at91_piovar.h>
#define MEM_RID 0
/* Pin Definitions - do they belong here or somewhere else ? */
#define VBUS_MASK AT91C_PIO_PB24
#define VBUS_BASE AT91RM92_PIOB_BASE
#define PULLUP_MASK AT91C_PIO_PB22
#define PULLUP_BASE AT91RM92_PIOB_BASE
static device_probe_t at91_udp_probe;
static device_attach_t at91_udp_attach;
static device_detach_t at91_udp_detach;
static device_shutdown_t at91_udp_shutdown;
struct at91_udp_softc {
struct at91dci_softc sc_dci; /* must be first */
struct at91_pmc_clock *sc_iclk;
struct at91_pmc_clock *sc_fclk;
struct resource *sc_vbus_irq_res;
void *sc_vbus_intr_hdl;
};
static void
at91_vbus_interrupt(struct at91_udp_softc *sc)
{
uint32_t temp;
uint8_t vbus_val;
/* XXX temporary clear interrupts here */
temp = at91_pio_gpio_clear_interrupt(VBUS_BASE);
/* just forward it */
vbus_val = at91_pio_gpio_get(VBUS_BASE, VBUS_MASK);
(sc->sc_dci.sc_bus.methods->vbus_interrupt)
(&sc->sc_dci.sc_bus, vbus_val);
return;
}
static void
at91_udp_clocks_on(void *arg)
{
struct at91_udp_softc *sc = arg;
at91_pmc_clock_enable(sc->sc_iclk);
at91_pmc_clock_enable(sc->sc_fclk);
return;
}
static void
at91_udp_clocks_off(void *arg)
{
struct at91_udp_softc *sc = arg;
at91_pmc_clock_disable(sc->sc_fclk);
at91_pmc_clock_disable(sc->sc_iclk);
return;
}
static void
at91_udp_pull_up(void *arg)
{
at91_pio_gpio_set(PULLUP_BASE, PULLUP_MASK);
return;
}
static void
at91_udp_pull_down(void *arg)
{
at91_pio_gpio_clear(PULLUP_BASE, PULLUP_MASK);
return;
}
static int
at91_udp_probe(device_t dev)
{
device_set_desc(dev, "AT91 integrated AT91_UDP controller");
return (0);
}
static int
at91_udp_attach(device_t dev)
{
struct at91_udp_softc *sc = device_get_softc(dev);
int err;
int rid;
if (sc == NULL) {
return (ENXIO);
}
/* setup AT9100 USB device controller interface softc */
sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on;
sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off;
sc->sc_dci.sc_clocks_arg = sc;
sc->sc_dci.sc_pull_up = &at91_udp_pull_up;
sc->sc_dci.sc_pull_down = &at91_udp_pull_down;
sc->sc_dci.sc_pull_arg = sc;
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_dci.sc_bus,
USB_GET_DMA_TAG(dev), NULL)) {
return (ENOMEM);
}
/*
* configure VBUS input pin, enable deglitch and enable
* interrupt :
*/
at91_pio_use_gpio(VBUS_BASE, VBUS_MASK);
at91_pio_gpio_input(VBUS_BASE, VBUS_MASK);
at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1);
at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 1);
/*
* configure PULLUP output pin :
*/
at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK);
at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0);
at91_udp_pull_down(sc);
/* wait 10ms for pulldown to stabilise */
usb2_pause_mtx(NULL, 10);
sc->sc_iclk = at91_pmc_clock_ref("udc_clk");
sc->sc_fclk = at91_pmc_clock_ref("udpck");
rid = MEM_RID;
sc->sc_dci.sc_io_res =
bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (!(sc->sc_dci.sc_io_res)) {
err = ENOMEM;
goto error;
}
sc->sc_dci.sc_io_tag = rman_get_bustag(sc->sc_dci.sc_io_res);
sc->sc_dci.sc_io_hdl = rman_get_bushandle(sc->sc_dci.sc_io_res);
sc->sc_dci.sc_io_size = rman_get_size(sc->sc_dci.sc_io_res);
rid = 0;
sc->sc_dci.sc_irq_res =
bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
if (!(sc->sc_dci.sc_irq_res)) {
goto error;
}
rid = 1;
sc->sc_vbus_irq_res =
bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
if (!(sc->sc_vbus_irq_res)) {
goto error;
}
sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1);
if (!(sc->sc_dci.sc_bus.bdev)) {
goto error;
}
device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus);
err = usb2_config_td_setup(&sc->sc_dci.sc_config_td, sc,
&sc->sc_dci.sc_bus.mtx, NULL, 0, 4);
if (err) {
device_printf(dev, "could not setup config thread!\n");
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
#else
err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
#endif
if (err) {
sc->sc_dci.sc_intr_hdl = NULL;
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)at91_vbus_interrupt, sc, &sc->sc_vbus_intr_hdl);
#else
err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)at91_vbus_interrupt, sc, &sc->sc_vbus_intr_hdl);
#endif
if (err) {
sc->sc_vbus_intr_hdl = NULL;
goto error;
}
err = at91dci_init(&sc->sc_dci);
if (!err) {
err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev);
}
if (err) {
goto error;
} else {
/* poll VBUS one time */
at91_vbus_interrupt(sc);
}
return (0);
error:
at91_udp_detach(dev);
return (ENXIO);
}
static int
at91_udp_detach(device_t dev)
{
struct at91_udp_softc *sc = device_get_softc(dev);
device_t bdev;
int err;
if (sc->sc_dci.sc_bus.bdev) {
bdev = sc->sc_dci.sc_bus.bdev;
device_detach(bdev);
device_delete_child(dev, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(dev);
/* disable Transceiver */
AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS);
/* disable and clear all interrupts */
AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF);
AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF);
/* disable VBUS interrupt */
at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0);
if (sc->sc_vbus_irq_res && sc->sc_vbus_intr_hdl) {
err = bus_teardown_intr(dev, sc->sc_vbus_irq_res,
sc->sc_vbus_intr_hdl);
sc->sc_vbus_intr_hdl = NULL;
}
if (sc->sc_vbus_irq_res) {
bus_release_resource(dev, SYS_RES_IRQ, 1,
sc->sc_vbus_irq_res);
sc->sc_vbus_irq_res = NULL;
}
if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) {
/*
* only call at91_udp_uninit() after at91_udp_init()
*/
at91dci_uninit(&sc->sc_dci);
err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res,
sc->sc_dci.sc_intr_hdl);
sc->sc_dci.sc_intr_hdl = NULL;
}
if (sc->sc_dci.sc_irq_res) {
bus_release_resource(dev, SYS_RES_IRQ, 0,
sc->sc_dci.sc_irq_res);
sc->sc_dci.sc_irq_res = NULL;
}
if (sc->sc_dci.sc_io_res) {
bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID,
sc->sc_dci.sc_io_res);
sc->sc_dci.sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_dci.sc_config_td);
usb2_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL);
/* disable clocks */
at91_pmc_clock_disable(sc->sc_iclk);
at91_pmc_clock_disable(sc->sc_fclk);
at91_pmc_clock_deref(sc->sc_fclk);
at91_pmc_clock_deref(sc->sc_iclk);
return (0);
}
static int
at91_udp_shutdown(device_t dev)
{
struct at91_udp_softc *sc = device_get_softc(dev);
int err;
err = bus_generic_shutdown(dev);
if (err)
return (err);
at91dci_uninit(&sc->sc_dci);
return (0);
}
static device_method_t at91_udp_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, at91_udp_probe),
DEVMETHOD(device_attach, at91_udp_attach),
DEVMETHOD(device_detach, at91_udp_detach),
DEVMETHOD(device_shutdown, at91_udp_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
};
static driver_t at91_udp_driver = {
"at91_udp",
at91_udp_methods,
sizeof(struct at91_udp_softc),
};
static devclass_t at91_udp_devclass;
DRIVER_MODULE(at91_udp, atmelarm, at91_udp_driver, at91_udp_devclass, 0, 0);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,515 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net).
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef _EHCI_H_
#define _EHCI_H_
/* PCI config registers */
#define PCI_CBMEM 0x10 /* configuration base MEM */
#define PCI_INTERFACE_EHCI 0x20
#define PCI_USBREV 0x60 /* RO USB protocol revision */
#define PCI_USB_REV_MASK 0xff
#define PCI_USB_REV_PRE_1_0 0x00
#define PCI_USB_REV_1_0 0x10
#define PCI_USB_REV_1_1 0x11
#define PCI_USB_REV_2_0 0x20
#define PCI_EHCI_FLADJ 0x61 /* RW Frame len adj, SOF=59488+6*fladj */
#define PCI_EHCI_PORTWAKECAP 0x62 /* RW Port wake caps (opt) */
/* EHCI Extended Capabilities */
#define EHCI_EC_LEGSUP 0x01
#define EHCI_EECP_NEXT(x) (((x) >> 8) & 0xff)
#define EHCI_EECP_ID(x) ((x) & 0xff)
/* Legacy support extended capability */
#define EHCI_LEGSUP_BIOS_SEM 0x02
#define EHCI_LEGSUP_OS_SEM 0x03
#define EHCI_LEGSUP_USBLEGCTLSTS 0x04
/* EHCI capability registers */
#define EHCI_CAPLENGTH 0x00 /* RO Capability register length field */
/* reserved 0x01 */
#define EHCI_HCIVERSION 0x02 /* RO Interface version number */
#define EHCI_HCSPARAMS 0x04 /* RO Structural parameters */
#define EHCI_HCS_DEBUGPORT(x) (((x) >> 20) & 0xf)
#define EHCI_HCS_P_INDICATOR(x) ((x) & 0x10000)
#define EHCI_HCS_N_CC(x) (((x) >> 12) & 0xf) /* # of companion ctlrs */
#define EHCI_HCS_N_PCC(x) (((x) >> 8) & 0xf) /* # of ports per comp. */
#define EHCI_HCS_PPC(x) ((x) & 0x10) /* port power control */
#define EHCI_HCS_N_PORTS(x) ((x) & 0xf) /* # of ports */
#define EHCI_HCCPARAMS 0x08 /* RO Capability parameters */
#define EHCI_HCC_EECP(x) (((x) >> 8) & 0xff) /* extended ports caps */
#define EHCI_HCC_IST(x) (((x) >> 4) & 0xf) /* isoc sched threshold */
#define EHCI_HCC_ASPC(x) ((x) & 0x4) /* async sched park cap */
#define EHCI_HCC_PFLF(x) ((x) & 0x2) /* prog frame list flag */
#define EHCI_HCC_64BIT(x) ((x) & 0x1) /* 64 bit address cap */
#define EHCI_HCSP_PORTROUTE 0x0c /* RO Companion port route description */
/* EHCI operational registers. Offset given by EHCI_CAPLENGTH register */
#define EHCI_USBCMD 0x00 /* RO, RW, WO Command register */
#define EHCI_CMD_ITC_M 0x00ff0000 /* RW interrupt threshold ctrl */
#define EHCI_CMD_ITC_1 0x00010000
#define EHCI_CMD_ITC_2 0x00020000
#define EHCI_CMD_ITC_4 0x00040000
#define EHCI_CMD_ITC_8 0x00080000
#define EHCI_CMD_ITC_16 0x00100000
#define EHCI_CMD_ITC_32 0x00200000
#define EHCI_CMD_ITC_64 0x00400000
#define EHCI_CMD_ASPME 0x00000800 /* RW/RO async park enable */
#define EHCI_CMD_ASPMC 0x00000300 /* RW/RO async park count */
#define EHCI_CMD_LHCR 0x00000080 /* RW light host ctrl reset */
#define EHCI_CMD_IAAD 0x00000040 /* RW intr on async adv door
* bell */
#define EHCI_CMD_ASE 0x00000020 /* RW async sched enable */
#define EHCI_CMD_PSE 0x00000010 /* RW periodic sched enable */
#define EHCI_CMD_FLS_M 0x0000000c /* RW/RO frame list size */
#define EHCI_CMD_FLS(x) (((x) >> 2) & 3) /* RW/RO frame list size */
#define EHCI_CMD_HCRESET 0x00000002 /* RW reset */
#define EHCI_CMD_RS 0x00000001 /* RW run/stop */
#define EHCI_USBSTS 0x04 /* RO, RW, RWC Status register */
#define EHCI_STS_ASS 0x00008000 /* RO async sched status */
#define EHCI_STS_PSS 0x00004000 /* RO periodic sched status */
#define EHCI_STS_REC 0x00002000 /* RO reclamation */
#define EHCI_STS_HCH 0x00001000 /* RO host controller halted */
#define EHCI_STS_IAA 0x00000020 /* RWC interrupt on async adv */
#define EHCI_STS_HSE 0x00000010 /* RWC host system error */
#define EHCI_STS_FLR 0x00000008 /* RWC frame list rollover */
#define EHCI_STS_PCD 0x00000004 /* RWC port change detect */
#define EHCI_STS_ERRINT 0x00000002 /* RWC error interrupt */
#define EHCI_STS_INT 0x00000001 /* RWC interrupt */
#define EHCI_STS_INTRS(x) ((x) & 0x3f)
/*
* NOTE: the doorbell interrupt is enabled, but the doorbell is never
* used! SiS chipsets require this.
*/
#define EHCI_NORMAL_INTRS (EHCI_STS_IAA | EHCI_STS_HSE | \
EHCI_STS_PCD | EHCI_STS_ERRINT | EHCI_STS_INT)
#define EHCI_USBINTR 0x08 /* RW Interrupt register */
#define EHCI_INTR_IAAE 0x00000020 /* interrupt on async advance
* ena */
#define EHCI_INTR_HSEE 0x00000010 /* host system error ena */
#define EHCI_INTR_FLRE 0x00000008 /* frame list rollover ena */
#define EHCI_INTR_PCIE 0x00000004 /* port change ena */
#define EHCI_INTR_UEIE 0x00000002 /* USB error intr ena */
#define EHCI_INTR_UIE 0x00000001 /* USB intr ena */
#define EHCI_FRINDEX 0x0c /* RW Frame Index register */
#define EHCI_CTRLDSSEGMENT 0x10 /* RW Control Data Structure Segment */
#define EHCI_PERIODICLISTBASE 0x14 /* RW Periodic List Base */
#define EHCI_ASYNCLISTADDR 0x18 /* RW Async List Base */
#define EHCI_CONFIGFLAG 0x40 /* RW Configure Flag register */
#define EHCI_CONF_CF 0x00000001 /* RW configure flag */
#define EHCI_PORTSC(n) (0x40+(4*(n))) /* RO, RW, RWC Port Status reg */
#define EHCI_PS_WKOC_E 0x00400000 /* RW wake on over current ena */
#define EHCI_PS_WKDSCNNT_E 0x00200000 /* RW wake on disconnect ena */
#define EHCI_PS_WKCNNT_E 0x00100000 /* RW wake on connect ena */
#define EHCI_PS_PTC 0x000f0000 /* RW port test control */
#define EHCI_PS_PIC 0x0000c000 /* RW port indicator control */
#define EHCI_PS_PO 0x00002000 /* RW port owner */
#define EHCI_PS_PP 0x00001000 /* RW,RO port power */
#define EHCI_PS_LS 0x00000c00 /* RO line status */
#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == 0x00000400)
#define EHCI_PS_PR 0x00000100 /* RW port reset */
#define EHCI_PS_SUSP 0x00000080 /* RW suspend */
#define EHCI_PS_FPR 0x00000040 /* RW force port resume */
#define EHCI_PS_OCC 0x00000020 /* RWC over current change */
#define EHCI_PS_OCA 0x00000010 /* RO over current active */
#define EHCI_PS_PEC 0x00000008 /* RWC port enable change */
#define EHCI_PS_PE 0x00000004 /* RW port enable */
#define EHCI_PS_CSC 0x00000002 /* RWC connect status change */
#define EHCI_PS_CS 0x00000001 /* RO connect status */
#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
#define EHCI_PORT_RESET_COMPLETE 2 /* ms */
/*
* Alignment NOTE: structures must be aligned so that the hardware can index
* without performing addition.
*/
#define EHCI_FRAMELIST_ALIGN 0x1000 /* bytes */
#define EHCI_FRAMELIST_COUNT 1024 /* units */
#define EHCI_VIRTUAL_FRAMELIST_COUNT 128 /* units */
#if ((8*EHCI_VIRTUAL_FRAMELIST_COUNT) < USB_MAX_HS_ISOC_FRAMES_PER_XFER)
#error "maximum number of high-speed isochronous frames is higher than supported!"
#endif
#if (EHCI_VIRTUAL_FRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER)
#error "maximum number of full-speed isochronous frames is higher than supported!"
#endif
/* Link types */
#define EHCI_LINK_TERMINATE 0x00000001
#define EHCI_LINK_TYPE(x) ((x) & 0x00000006)
#define EHCI_LINK_ITD 0x0
#define EHCI_LINK_QH 0x2
#define EHCI_LINK_SITD 0x4
#define EHCI_LINK_FSTN 0x6
#define EHCI_LINK_ADDR(x) ((x) &~ 0x1f)
/* Structures alignment (bytes) */
#define EHCI_ITD_ALIGN 128
#define EHCI_SITD_ALIGN 64
#define EHCI_QTD_ALIGN 64
#define EHCI_QH_ALIGN 128
#define EHCI_FSTN_ALIGN 32
/* Data buffers are divided into one or more pages */
#define EHCI_PAGE_SIZE 0x1000
#if ((USB_PAGE_SIZE < EHCI_PAGE_SIZE) || (EHCI_PAGE_SIZE == 0) || \
(USB_PAGE_SIZE < EHCI_ITD_ALIGN) || (EHCI_ITD_ALIGN == 0) || \
(USB_PAGE_SIZE < EHCI_SITD_ALIGN) || (EHCI_SITD_ALIGN == 0) || \
(USB_PAGE_SIZE < EHCI_QTD_ALIGN) || (EHCI_QTD_ALIGN == 0) || \
(USB_PAGE_SIZE < EHCI_QH_ALIGN) || (EHCI_QH_ALIGN == 0) || \
(USB_PAGE_SIZE < EHCI_FSTN_ALIGN) || (EHCI_FSTN_ALIGN == 0))
#error "Invalid USB page size!"
#endif
/*
* Isochronous Transfer Descriptor. This descriptor is used for high speed
* transfers only.
*/
struct ehci_itd {
volatile uint32_t itd_next;
volatile uint32_t itd_status[8];
#define EHCI_ITD_SET_LEN(x) ((x) << 16)
#define EHCI_ITD_GET_LEN(x) (((x) >> 16) & 0xFFF)
#define EHCI_ITD_IOC (1 << 15)
#define EHCI_ITD_SET_PG(x) ((x) << 12)
#define EHCI_ITD_GET_PG(x) (((x) >> 12) & 0x7)
#define EHCI_ITD_SET_OFFS(x) (x)
#define EHCI_ITD_GET_OFFS(x) (((x) >> 0) & 0xFFF)
#define EHCI_ITD_ACTIVE (1 << 31)
#define EHCI_ITD_DATABUFERR (1 << 30)
#define EHCI_ITD_BABBLE (1 << 29)
#define EHCI_ITD_XACTERR (1 << 28)
volatile uint32_t itd_bp[7];
/* itd_bp[0] */
#define EHCI_ITD_SET_ADDR(x) (x)
#define EHCI_ITD_GET_ADDR(x) (((x) >> 0) & 0x7F)
#define EHCI_ITD_SET_ENDPT(x) ((x) << 8)
#define EHCI_ITD_GET_ENDPT(x) (((x) >> 8) & 0xF)
/* itd_bp[1] */
#define EHCI_ITD_SET_DIR_IN (1 << 11)
#define EHCI_ITD_SET_DIR_OUT (0 << 11)
#define EHCI_ITD_SET_MPL(x) (x)
#define EHCI_ITD_GET_MPL(x) (((x) >> 0) & 0x7FF)
volatile uint32_t itd_bp_hi[7];
/*
* Extra information needed:
*/
uint32_t itd_self;
struct ehci_itd *next;
struct ehci_itd *prev;
struct ehci_itd *obj_next;
struct usb2_page_cache *page_cache;
} __aligned(EHCI_ITD_ALIGN);
typedef struct ehci_itd ehci_itd_t;
/*
* Split Transaction Isochronous Transfer Descriptor. This descriptor is used
* for full speed transfers only.
*/
struct ehci_sitd {
volatile uint32_t sitd_next;
volatile uint32_t sitd_portaddr;
#define EHCI_SITD_SET_DIR_OUT (0 << 31)
#define EHCI_SITD_SET_DIR_IN (1 << 31)
#define EHCI_SITD_SET_ADDR(x) (x)
#define EHCI_SITD_GET_ADDR(x) ((x) & 0x7F)
#define EHCI_SITD_SET_ENDPT(x) ((x) << 8)
#define EHCI_SITD_GET_ENDPT(x) (((x) >> 8) & 0xF)
#define EHCI_SITD_GET_DIR(x) ((x) >> 31)
#define EHCI_SITD_SET_PORT(x) ((x) << 24)
#define EHCI_SITD_GET_PORT(x) (((x) >> 24) & 0x7F)
#define EHCI_SITD_SET_HUBA(x) ((x) << 16)
#define EHCI_SITD_GET_HUBA(x) (((x) >> 16) & 0x7F)
volatile uint32_t sitd_mask;
#define EHCI_SITD_SET_SMASK(x) (x)
#define EHCI_SITD_SET_CMASK(x) ((x) << 8)
volatile uint32_t sitd_status;
#define EHCI_SITD_COMPLETE_SPLIT (1<<1)
#define EHCI_SITD_START_SPLIT (0<<1)
#define EHCI_SITD_MISSED_MICRO_FRAME (1<<2)
#define EHCI_SITD_XACTERR (1<<3)
#define EHCI_SITD_BABBLE (1<<4)
#define EHCI_SITD_DATABUFERR (1<<5)
#define EHCI_SITD_ERROR (1<<6)
#define EHCI_SITD_ACTIVE (1<<7)
#define EHCI_SITD_IOC (1<<31)
#define EHCI_SITD_SET_LEN(len) ((len)<<16)
#define EHCI_SITD_GET_LEN(x) (((x)>>16) & 0x3FF)
volatile uint32_t sitd_bp[2];
volatile uint32_t sitd_back;
volatile uint32_t sitd_bp_hi[2];
/*
* Extra information needed:
*/
uint32_t sitd_self;
struct ehci_sitd *next;
struct ehci_sitd *prev;
struct ehci_sitd *obj_next;
struct usb2_page_cache *page_cache;
} __aligned(EHCI_SITD_ALIGN);
typedef struct ehci_sitd ehci_sitd_t;
/* Queue Element Transfer Descriptor */
struct ehci_qtd {
volatile uint32_t qtd_next;
volatile uint32_t qtd_altnext;
volatile uint32_t qtd_status;
#define EHCI_QTD_GET_STATUS(x) (((x) >> 0) & 0xff)
#define EHCI_QTD_SET_STATUS(x) ((x) << 0)
#define EHCI_QTD_ACTIVE 0x80
#define EHCI_QTD_HALTED 0x40
#define EHCI_QTD_BUFERR 0x20
#define EHCI_QTD_BABBLE 0x10
#define EHCI_QTD_XACTERR 0x08
#define EHCI_QTD_MISSEDMICRO 0x04
#define EHCI_QTD_SPLITXSTATE 0x02
#define EHCI_QTD_PINGSTATE 0x01
#define EHCI_QTD_STATERRS 0x74
#define EHCI_QTD_GET_PID(x) (((x) >> 8) & 0x3)
#define EHCI_QTD_SET_PID(x) ((x) << 8)
#define EHCI_QTD_PID_OUT 0x0
#define EHCI_QTD_PID_IN 0x1
#define EHCI_QTD_PID_SETUP 0x2
#define EHCI_QTD_GET_CERR(x) (((x) >> 10) & 0x3)
#define EHCI_QTD_SET_CERR(x) ((x) << 10)
#define EHCI_QTD_GET_C_PAGE(x) (((x) >> 12) & 0x7)
#define EHCI_QTD_SET_C_PAGE(x) ((x) << 12)
#define EHCI_QTD_GET_IOC(x) (((x) >> 15) & 0x1)
#define EHCI_QTD_IOC 0x00008000
#define EHCI_QTD_GET_BYTES(x) (((x) >> 16) & 0x7fff)
#define EHCI_QTD_SET_BYTES(x) ((x) << 16)
#define EHCI_QTD_GET_TOGGLE(x) (((x) >> 31) & 0x1)
#define EHCI_QTD_SET_TOGGLE(x) ((x) << 31)
#define EHCI_QTD_TOGGLE_MASK 0x80000000
#define EHCI_QTD_NBUFFERS 5
#define EHCI_QTD_PAYLOAD_MAX ((EHCI_QTD_NBUFFERS-1)*EHCI_PAGE_SIZE)
volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS];
volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS];
/*
* Extra information needed:
*/
struct ehci_qtd *alt_next;
struct ehci_qtd *obj_next;
struct usb2_page_cache *page_cache;
uint32_t qtd_self;
uint16_t len;
} __aligned(EHCI_QTD_ALIGN);
typedef struct ehci_qtd ehci_qtd_t;
/* Queue Head Sub Structure */
struct ehci_qh_sub {
volatile uint32_t qtd_next;
volatile uint32_t qtd_altnext;
volatile uint32_t qtd_status;
volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS];
volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS];
} __aligned(4);
/* Queue Head */
struct ehci_qh {
volatile uint32_t qh_link;
volatile uint32_t qh_endp;
#define EHCI_QH_GET_ADDR(x) (((x) >> 0) & 0x7f) /* endpoint addr */
#define EHCI_QH_SET_ADDR(x) (x)
#define EHCI_QH_ADDRMASK 0x0000007f
#define EHCI_QH_GET_INACT(x) (((x) >> 7) & 0x01) /* inactivate on next */
#define EHCI_QH_INACT 0x00000080
#define EHCI_QH_GET_ENDPT(x) (((x) >> 8) & 0x0f) /* endpoint no */
#define EHCI_QH_SET_ENDPT(x) ((x) << 8)
#define EHCI_QH_GET_EPS(x) (((x) >> 12) & 0x03) /* endpoint speed */
#define EHCI_QH_SET_EPS(x) ((x) << 12)
#define EHCI_QH_SPEED_FULL 0x0
#define EHCI_QH_SPEED_LOW 0x1
#define EHCI_QH_SPEED_HIGH 0x2
#define EHCI_QH_GET_DTC(x) (((x) >> 14) & 0x01) /* data toggle control */
#define EHCI_QH_DTC 0x00004000
#define EHCI_QH_GET_HRECL(x) (((x) >> 15) & 0x01) /* head of reclamation */
#define EHCI_QH_HRECL 0x00008000
#define EHCI_QH_GET_MPL(x) (((x) >> 16) & 0x7ff) /* max packet len */
#define EHCI_QH_SET_MPL(x) ((x) << 16)
#define EHCI_QH_MPLMASK 0x07ff0000
#define EHCI_QH_GET_CTL(x) (((x) >> 27) & 0x01) /* control endpoint */
#define EHCI_QH_CTL 0x08000000
#define EHCI_QH_GET_NRL(x) (((x) >> 28) & 0x0f) /* NAK reload */
#define EHCI_QH_SET_NRL(x) ((x) << 28)
volatile uint32_t qh_endphub;
#define EHCI_QH_GET_SMASK(x) (((x) >> 0) & 0xff) /* intr sched mask */
#define EHCI_QH_SET_SMASK(x) ((x) << 0)
#define EHCI_QH_GET_CMASK(x) (((x) >> 8) & 0xff) /* split completion mask */
#define EHCI_QH_SET_CMASK(x) ((x) << 8)
#define EHCI_QH_GET_HUBA(x) (((x) >> 16) & 0x7f) /* hub address */
#define EHCI_QH_SET_HUBA(x) ((x) << 16)
#define EHCI_QH_GET_PORT(x) (((x) >> 23) & 0x7f) /* hub port */
#define EHCI_QH_SET_PORT(x) ((x) << 23)
#define EHCI_QH_GET_MULT(x) (((x) >> 30) & 0x03) /* pipe multiplier */
#define EHCI_QH_SET_MULT(x) ((x) << 30)
volatile uint32_t qh_curqtd;
struct ehci_qh_sub qh_qtd;
/*
* Extra information needed:
*/
struct ehci_qh *next;
struct ehci_qh *prev;
struct ehci_qh *obj_next;
struct usb2_page_cache *page_cache;
uint32_t qh_self;
} __aligned(EHCI_QH_ALIGN);
typedef struct ehci_qh ehci_qh_t;
/* Periodic Frame Span Traversal Node */
struct ehci_fstn {
volatile uint32_t fstn_link;
volatile uint32_t fstn_back;
} __aligned(EHCI_FSTN_ALIGN);
typedef struct ehci_fstn ehci_fstn_t;
struct ehci_hw_softc {
struct usb2_page_cache pframes_pc;
struct usb2_page_cache async_start_pc;
struct usb2_page_cache intr_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT];
struct usb2_page_cache isoc_hs_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT];
struct usb2_page_cache isoc_fs_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT];
struct usb2_page pframes_pg;
struct usb2_page async_start_pg;
struct usb2_page intr_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT];
struct usb2_page isoc_hs_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT];
struct usb2_page isoc_fs_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT];
};
struct ehci_config_desc {
struct usb2_config_descriptor confd;
struct usb2_interface_descriptor ifcd;
struct usb2_endpoint_descriptor endpd;
} __packed;
union ehci_hub_desc {
struct usb2_status stat;
struct usb2_port_status ps;
struct usb2_device_descriptor devd;
struct usb2_device_qualifier odevd;
struct usb2_hub_descriptor hubd;
uint8_t temp[128];
};
typedef struct ehci_softc {
struct ehci_hw_softc sc_hw;
struct usb2_bus sc_bus; /* base device */
struct usb2_config_td sc_config_td;
struct usb2_callout sc_tmo_pcd;
union ehci_hub_desc sc_hub_desc;
struct usb2_sw_transfer sc_root_ctrl;
struct usb2_sw_transfer sc_root_intr;
struct resource *sc_io_res;
struct resource *sc_irq_res;
struct ehci_qh *sc_async_p_last;
struct ehci_qh *sc_intr_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT];
struct ehci_sitd *sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT];
struct ehci_itd *sc_isoc_hs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT];
void *sc_intr_hdl;
device_t sc_dev;
bus_size_t sc_io_size;
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
uint32_t sc_eintrs;
uint32_t sc_cmd; /* shadow of cmd register during
* suspend */
uint16_t sc_intr_stat[EHCI_VIRTUAL_FRAMELIST_COUNT];
uint16_t sc_id_vendor; /* vendor ID for root hub */
uint8_t sc_offs; /* offset to operational registers */
uint8_t sc_doorbell_disable; /* set on doorbell failure */
uint8_t sc_noport;
uint8_t sc_addr; /* device address */
uint8_t sc_conf; /* device configuration */
uint8_t sc_isreset;
uint8_t sc_hub_idata[8];
char sc_vendor[16]; /* vendor string for root hub */
} ehci_softc_t;
#define EREAD1(sc, a) bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (a))
#define EREAD2(sc, a) bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (a))
#define EREAD4(sc, a) bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (a))
#define EWRITE1(sc, a, x) \
bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (a), (x))
#define EWRITE2(sc, a, x) \
bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (a), (x))
#define EWRITE4(sc, a, x) \
bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (a), (x))
#define EOREAD1(sc, a) \
bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a))
#define EOREAD2(sc, a) \
bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a))
#define EOREAD4(sc, a) \
bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a))
#define EOWRITE1(sc, a, x) \
bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a), (x))
#define EOWRITE2(sc, a, x) \
bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a), (x))
#define EOWRITE4(sc, a, x) \
bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (sc)->sc_offs+(a), (x))
usb2_bus_mem_cb_t ehci_iterate_hw_softc;
usb2_error_t ehci_init(ehci_softc_t *sc);
void ehci_detach(struct ehci_softc *sc);
void ehci_suspend(struct ehci_softc *sc);
void ehci_resume(struct ehci_softc *sc);
void ehci_shutdown(ehci_softc_t *sc);
void ehci_interrupt(ehci_softc_t *sc);
#endif /* _EHCI_H_ */

View File

@ -0,0 +1,498 @@
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (augustss@carlstedt.se) at
* Carlstedt Research & Technology.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller.
*
* The EHCI 1.0 spec can be found at
* http://developer.intel.com/technology/usb/download/ehci-r10.pdf
* and the USB 2.0 spec at
* http://www.usb.org/developers/docs/usb_20.zip
*/
/* The low level controller code for EHCI has been split into
* PCI probes and EHCI specific code. This was done to facilitate the
* sharing of code between *BSD's
*/
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/usb2_pci.h>
#include <dev/usb2/controller/ehci2.h>
#define PCI_EHCI_VENDORID_ACERLABS 0x10b9
#define PCI_EHCI_VENDORID_AMD 0x1022
#define PCI_EHCI_VENDORID_APPLE 0x106b
#define PCI_EHCI_VENDORID_ATI 0x1002
#define PCI_EHCI_VENDORID_CMDTECH 0x1095
#define PCI_EHCI_VENDORID_INTEL 0x8086
#define PCI_EHCI_VENDORID_NEC 0x1033
#define PCI_EHCI_VENDORID_OPTI 0x1045
#define PCI_EHCI_VENDORID_PHILIPS 0x1131
#define PCI_EHCI_VENDORID_SIS 0x1039
#define PCI_EHCI_VENDORID_NVIDIA 0x12D2
#define PCI_EHCI_VENDORID_NVIDIA2 0x10DE
#define PCI_EHCI_VENDORID_VIA 0x1106
#define PCI_EHCI_BASE_REG 0x10
static void ehci_pci_takecontroller(device_t self);
static device_probe_t ehci_pci_probe;
static device_attach_t ehci_pci_attach;
static device_detach_t ehci_pci_detach;
static device_suspend_t ehci_pci_suspend;
static device_resume_t ehci_pci_resume;
static device_shutdown_t ehci_pci_shutdown;
static int
ehci_pci_suspend(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
int err;
err = bus_generic_suspend(self);
if (err)
return (err);
ehci_suspend(sc);
return (0);
}
static int
ehci_pci_resume(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
ehci_pci_takecontroller(self);
ehci_resume(sc);
bus_generic_resume(self);
return (0);
}
static int
ehci_pci_shutdown(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
int err;
err = bus_generic_shutdown(self);
if (err)
return (err);
ehci_shutdown(sc);
return (0);
}
static const char *
ehci_pci_match(device_t self)
{
uint32_t device_id = pci_get_devid(self);
switch (device_id) {
case 0x268c8086:
return ("Intel 63XXESB USB 2.0 controller");
case 0x523910b9:
return "ALi M5239 USB 2.0 controller";
case 0x10227463:
return "AMD 8111 USB 2.0 controller";
case 0x20951022:
return ("AMD CS5536 (Geode) USB 2.0 controller");
case 0x43451002:
return "ATI SB200 USB 2.0 controller";
case 0x43731002:
return "ATI SB400 USB 2.0 controller";
case 0x25ad8086:
return "Intel 6300ESB USB 2.0 controller";
case 0x24cd8086:
return "Intel 82801DB/L/M (ICH4) USB 2.0 controller";
case 0x24dd8086:
return "Intel 82801EB/R (ICH5) USB 2.0 controller";
case 0x265c8086:
return "Intel 82801FB (ICH6) USB 2.0 controller";
case 0x27cc8086:
return "Intel 82801GB/R (ICH7) USB 2.0 controller";
case 0x28368086:
return "Intel 82801H (ICH8) USB 2.0 controller USB2-A";
case 0x283a8086:
return "Intel 82801H (ICH8) USB 2.0 controller USB2-B";
case 0x293a8086:
return "Intel 82801I (ICH9) USB 2.0 controller";
case 0x293c8086:
return "Intel 82801I (ICH9) USB 2.0 controller";
case 0x00e01033:
return ("NEC uPD 720100 USB 2.0 controller");
case 0x006810de:
return "NVIDIA nForce2 USB 2.0 controller";
case 0x008810de:
return "NVIDIA nForce2 Ultra 400 USB 2.0 controller";
case 0x00d810de:
return "NVIDIA nForce3 USB 2.0 controller";
case 0x00e810de:
return "NVIDIA nForce3 250 USB 2.0 controller";
case 0x005b10de:
return "NVIDIA nForce4 USB 2.0 controller";
case 0x15621131:
return "Philips ISP156x USB 2.0 controller";
case 0x31041106:
return ("VIA VT6202 USB 2.0 controller");
default:
break;
}
if ((pci_get_class(self) == PCIC_SERIALBUS)
&& (pci_get_subclass(self) == PCIS_SERIALBUS_USB)
&& (pci_get_progif(self) == PCI_INTERFACE_EHCI)) {
return ("EHCI (generic) USB 2.0 controller");
}
return (NULL); /* dunno */
}
static int
ehci_pci_probe(device_t self)
{
const char *desc = ehci_pci_match(self);
if (desc) {
device_set_desc(self, desc);
return (0);
} else {
return (ENXIO);
}
}
static int
ehci_pci_attach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
int err;
int rid;
if (sc == NULL) {
device_printf(self, "Could not allocate sc\n");
return (ENXIO);
}
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_bus,
USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
return ENOMEM;
}
sc->sc_dev = self;
pci_enable_busmaster(self);
switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) {
case PCI_USB_REV_PRE_1_0:
case PCI_USB_REV_1_0:
case PCI_USB_REV_1_1:
/*
* NOTE: some EHCI USB controllers have the wrong USB
* revision number. It appears those controllers are
* fully compliant so we just ignore this value in
* some common cases.
*/
device_printf(self, "pre-2.0 USB revision (ignored)\n");
/* fallthrough */
case PCI_USB_REV_2_0:
sc->sc_bus.usbrev = USB_REV_2_0;
break;
default:
sc->sc_bus.usbrev = USB_REV_UNKNOWN;
break;
}
rid = PCI_CBMEM;
sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (!sc->sc_io_res) {
device_printf(self, "Could not map memory\n");
goto error;
}
sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
sc->sc_io_size = rman_get_size(sc->sc_io_res);
rid = 0;
sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
RF_SHAREABLE | RF_ACTIVE);
if (sc->sc_irq_res == NULL) {
device_printf(self, "Could not allocate irq\n");
goto error;
}
sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
if (!sc->sc_bus.bdev) {
device_printf(self, "Could not add USB device\n");
goto error;
}
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
/*
* ehci_pci_match will never return NULL if ehci_pci_probe
* succeeded
*/
device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self));
switch (pci_get_vendor(self)) {
case PCI_EHCI_VENDORID_ACERLABS:
sprintf(sc->sc_vendor, "AcerLabs");
break;
case PCI_EHCI_VENDORID_AMD:
sprintf(sc->sc_vendor, "AMD");
break;
case PCI_EHCI_VENDORID_APPLE:
sprintf(sc->sc_vendor, "Apple");
break;
case PCI_EHCI_VENDORID_ATI:
sprintf(sc->sc_vendor, "ATI");
break;
case PCI_EHCI_VENDORID_CMDTECH:
sprintf(sc->sc_vendor, "CMDTECH");
break;
case PCI_EHCI_VENDORID_INTEL:
sprintf(sc->sc_vendor, "Intel");
break;
case PCI_EHCI_VENDORID_NEC:
sprintf(sc->sc_vendor, "NEC");
break;
case PCI_EHCI_VENDORID_OPTI:
sprintf(sc->sc_vendor, "OPTi");
break;
case PCI_EHCI_VENDORID_PHILIPS:
sprintf(sc->sc_vendor, "Philips");
break;
case PCI_EHCI_VENDORID_SIS:
sprintf(sc->sc_vendor, "SiS");
break;
case PCI_EHCI_VENDORID_NVIDIA:
case PCI_EHCI_VENDORID_NVIDIA2:
sprintf(sc->sc_vendor, "nVidia");
break;
case PCI_EHCI_VENDORID_VIA:
sprintf(sc->sc_vendor, "VIA");
break;
default:
if (bootverbose)
device_printf(self, "(New EHCI DeviceId=0x%08x)\n",
pci_get_devid(self));
sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self));
}
err = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_bus.mtx,
NULL, 0, 4);
if (err) {
device_printf(self, "could not setup config thread!\n");
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl);
#else
err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl);
#endif
if (err) {
device_printf(self, "Could not setup irq, %d\n", err);
sc->sc_intr_hdl = NULL;
goto error;
}
ehci_pci_takecontroller(self);
err = ehci_init(sc);
if (!err) {
err = device_probe_and_attach(sc->sc_bus.bdev);
}
if (err) {
device_printf(self, "USB init failed err=%d\n", err);
goto error;
}
return (0);
error:
ehci_pci_detach(self);
return (ENXIO);
}
static int
ehci_pci_detach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
device_t bdev;
usb2_config_td_drain(&sc->sc_config_td);
if (sc->sc_bus.bdev) {
bdev = sc->sc_bus.bdev;
device_detach(bdev);
device_delete_child(self, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(self);
pci_disable_busmaster(self);
/*
* disable interrupts that might have been switched on in ehci_init
*/
if (sc->sc_io_res) {
EWRITE4(sc, EHCI_USBINTR, 0);
}
if (sc->sc_irq_res && sc->sc_intr_hdl) {
/*
* only call ehci_detach() after ehci_init()
*/
ehci_detach(sc);
int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
if (err)
/* XXX or should we panic? */
device_printf(self, "Could not tear down irq, %d\n",
err);
sc->sc_intr_hdl = NULL;
}
if (sc->sc_irq_res) {
bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
sc->sc_irq_res = NULL;
}
if (sc->sc_io_res) {
bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM,
sc->sc_io_res);
sc->sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_config_td);
usb2_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
return (0);
}
static void
ehci_pci_takecontroller(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
uint32_t cparams;
uint32_t eec;
uint16_t to;
uint8_t eecp;
uint8_t bios_sem;
cparams = EREAD4(sc, EHCI_HCCPARAMS);
/* Synchronise with the BIOS if it owns the controller. */
for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
eecp = EHCI_EECP_NEXT(eec)) {
eec = pci_read_config(self, eecp, 4);
if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) {
continue;
}
bios_sem = pci_read_config(self, eecp +
EHCI_LEGSUP_BIOS_SEM, 1);
if (bios_sem == 0) {
continue;
}
device_printf(sc->sc_bus.bdev, "waiting for BIOS "
"to give up control\n");
pci_write_config(self, eecp +
EHCI_LEGSUP_OS_SEM, 1, 1);
to = 500;
while (1) {
bios_sem = pci_read_config(self, eecp +
EHCI_LEGSUP_BIOS_SEM, 1);
if (bios_sem == 0)
break;
if (--to == 0) {
device_printf(sc->sc_bus.bdev,
"timed out waiting for BIOS\n");
break;
}
usb2_pause_mtx(NULL, 10); /* wait 10ms */
}
}
return;
}
static driver_t ehci_driver =
{
.name = "ehci",
.methods = (device_method_t[]){
/* device interface */
DEVMETHOD(device_probe, ehci_pci_probe),
DEVMETHOD(device_attach, ehci_pci_attach),
DEVMETHOD(device_detach, ehci_pci_detach),
DEVMETHOD(device_suspend, ehci_pci_suspend),
DEVMETHOD(device_resume, ehci_pci_resume),
DEVMETHOD(device_shutdown, ehci_pci_shutdown),
/* bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
},
.size = sizeof(struct ehci_softc),
};
static devclass_t ehci_devclass;
DRIVER_MODULE(ehci, pci, ehci_driver, ehci_devclass, 0, 0);
DRIVER_MODULE(ehci, cardbus, ehci_driver, ehci_devclass, 0, 0);
MODULE_DEPEND(ehci, usb2_controller, 1, 1, 1);
MODULE_DEPEND(ehci, usb2_core, 1, 1, 1);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,403 @@
/* $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 header file defines the registers of the Mentor Graphics
* USB OnTheGo Inventra chip.
*/
#ifndef _MUSB2_OTG_H_
#define _MUSB2_OTG_H_
/* Common registers */
#define MUSB2_REG_FADDR 0x0000 /* function address register */
#define MUSB2_MASK_FADDR 0x7F
#define MUSB2_REG_POWER 0x0001 /* power register */
#define MUSB2_MASK_SUSPM_ENA 0x01
#define MUSB2_MASK_SUSPMODE 0x02
#define MUSB2_MASK_RESUME 0x04
#define MUSB2_MASK_RESET 0x08
#define MUSB2_MASK_HSMODE 0x10
#define MUSB2_MASK_HSENAB 0x20
#define MUSB2_MASK_SOFTC 0x40
#define MUSB2_MASK_ISOUPD 0x80
/* Endpoint interrupt handling */
#define MUSB2_REG_INTTX 0x0002 /* transmit interrupt register */
#define MUSB2_REG_INTRX 0x0004 /* receive interrupt register */
#define MUSB2_REG_INTTXE 0x0006 /* transmit interrupt enable register */
#define MUSB2_REG_INTRXE 0x0008 /* receive interrupt enable register */
#define MUSB2_MASK_EPINT(epn) (1 << (epn)) /* epn = [0..15] */
/* Common interrupt handling */
#define MUSB2_REG_INTUSB 0x000A /* USB interrupt register */
#define MUSB2_MASK_ISUSP 0x01
#define MUSB2_MASK_IRESUME 0x02
#define MUSB2_MASK_IRESET 0x04
#define MUSB2_MASK_IBABBLE 0x04
#define MUSB2_MASK_ISOF 0x08
#define MUSB2_MASK_ICONN 0x10
#define MUSB2_MASK_IDISC 0x20
#define MUSB2_MASK_ISESSRQ 0x40
#define MUSB2_MASK_IVBUSERR 0x80
#define MUSB2_REG_INTUSBE 0x000B /* USB interrupt enable register */
#define MUSB2_REG_FRAME 0x000C /* USB frame register */
#define MUSB2_MASK_FRAME 0x3FF /* 0..1023 */
#define MUSB2_REG_EPINDEX 0x000E /* endpoint index register */
#define MUSB2_MASK_EPINDEX 0x0F
#define MUSB2_REG_TESTMODE 0x000F /* test mode register */
#define MUSB2_MASK_TSE0_NAK 0x01
#define MUSB2_MASK_TJ 0x02
#define MUSB2_MASK_TK 0x04
#define MUSB2_MASK_TPACKET 0x08
#define MUSB2_MASK_TFORCE_HS 0x10
#define MUSB2_MASK_TFORCE_LS 0x20
#define MUSB2_MASK_TFIFO_ACC 0x40
#define MUSB2_MASK_TFORCE_HC 0x80
#define MUSB2_REG_INDEXED_CSR 0x0010 /* EP control status register offset */
#define MUSB2_REG_TXMAXP (0x0000 + MUSB2_REG_INDEXED_CSR)
#define MUSB2_REG_RXMAXP (0x0004 + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_PKTSIZE 0x03FF /* in bytes, should be even */
#define MUSB2_MASK_PKTMULT 0xFC00 /* HS packet multiplier: 0..2 */
#define MUSB2_REG_TXCSRL (0x0002 + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_CSRL_TXPKTRDY 0x01
#define MUSB2_MASK_CSRL_TXFIFONEMPTY 0x02
#define MUSB2_MASK_CSRL_TXUNDERRUN 0x04 /* Device Mode */
#define MUSB2_MASK_CSRL_TXERROR 0x04 /* Host Mode */
#define MUSB2_MASK_CSRL_TXFFLUSH 0x08
#define MUSB2_MASK_CSRL_TXSENDSTALL 0x10/* Device Mode */
#define MUSB2_MASK_CSRL_TXSETUPPKT 0x10 /* Host Mode */
#define MUSB2_MASK_CSRL_TXSENTSTALL 0x20/* Device Mode */
#define MUSB2_MASK_CSRL_TXSTALLED 0x20 /* Host Mode */
#define MUSB2_MASK_CSRL_TXDT_CLR 0x40
#define MUSB2_MASK_CSRL_TXINCOMP 0x80
/* Device Side Mode */
#define MUSB2_MASK_CSR0L_RXPKTRDY 0x01
#define MUSB2_MASK_CSR0L_TXPKTRDY 0x02
#define MUSB2_MASK_CSR0L_SENTSTALL 0x04
#define MUSB2_MASK_CSR0L_DATAEND 0x08
#define MUSB2_MASK_CSR0L_SETUPEND 0x10
#define MUSB2_MASK_CSR0L_SENDSTALL 0x20
#define MUSB2_MASK_CSR0L_RXPKTRDY_CLR 0x40
#define MUSB2_MASK_CSR0L_SETUPEND_CLR 0x80
/* Host Side Mode */
#define MUSB2_MASK_CSR0L_RXSTALL 0x04
#define MUSB2_MASK_CSR0L_SETUPPKT 0x08
#define MUSB2_MASK_CSR0L_ERROR 0x10
#define MUSB2_MASK_CSR0L_REQPKT 0x20
#define MUSB2_MASK_CSR0L_STATUSPKT 0x40
#define MUSB2_MASK_CSR0L_NAKTIMO 0x80
#define MUSB2_REG_TXCSRH (0x0003 + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_CSRH_TXDT_VAL 0x01 /* Host Mode */
#define MUSB2_MASK_CSRH_TXDT_WR 0x02 /* Host Mode */
#define MUSB2_MASK_CSRH_TXDMAREQMODE 0x04
#define MUSB2_MASK_CSRH_TXDT_SWITCH 0x08
#define MUSB2_MASK_CSRH_TXDMAREQENA 0x10
#define MUSB2_MASK_CSRH_RXMODE 0x00
#define MUSB2_MASK_CSRH_TXMODE 0x20
#define MUSB2_MASK_CSRH_TXISO 0x40 /* Device Mode */
#define MUSB2_MASK_CSRH_TXAUTOSET 0x80
#define MUSB2_MASK_CSR0H_FFLUSH 0x01 /* Device Side flush FIFO */
#define MUSB2_MASK_CSR0H_DT 0x02 /* Host Side data toggle */
#define MUSB2_MASK_CSR0H_DT_SET 0x04 /* Host Side */
#define MUSB2_MASK_CSR0H_PING_DIS 0x08 /* Host Side */
#define MUSB2_REG_RXCSRL (0x0006 + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_CSRL_RXPKTRDY 0x01
#define MUSB2_MASK_CSRL_RXFIFOFULL 0x02
#define MUSB2_MASK_CSRL_RXOVERRUN 0x04
#define MUSB2_MASK_CSRL_RXDATAERR 0x08
#define MUSB2_MASK_CSRL_RXFFLUSH 0x10
#define MUSB2_MASK_CSRL_RXSENDSTALL 0x20/* Device Mode */
#define MUSB2_MASK_CSRL_RXREQPKT 0x20 /* Host Mode */
#define MUSB2_MASK_CSRL_RXSENTSTALL 0x40/* Device Mode */
#define MUSB2_MASK_CSRL_RXSTALL 0x40 /* Host Mode */
#define MUSB2_MASK_CSRL_RXDT_CLR 0x80
#define MUSB2_REG_RXCSRH (0x0007 + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_CSRH_RXINCOMP 0x01
#define MUSB2_MASK_CSRH_RXDT_VAL 0x02 /* Host Mode */
#define MUSB2_MASK_CSRH_RXDT_SET 0x04 /* Host Mode */
#define MUSB2_MASK_CSRH_RXDMAREQMODE 0x08
#define MUSB2_MASK_CSRH_RXNYET 0x10
#define MUSB2_MASK_CSRH_RXDMAREQENA 0x20
#define MUSB2_MASK_CSRH_RXISO 0x40 /* Device Mode */
#define MUSB2_MASK_CSRH_RXAUTOREQ 0x40 /* Host Mode */
#define MUSB2_MASK_CSRH_RXAUTOCLEAR 0x80
#define MUSB2_REG_RXCOUNT (0x0008 + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_RXCOUNT 0xFFFF
#define MUSB2_REG_TXTI (0x000A + MUSB2_REG_INDEXED_CSR)
#define MUSB2_REG_RXTI (0x000C + MUSB2_REG_INDEXED_CSR)
/* Host Mode */
#define MUSB2_MASK_TI_SPEED 0xC0
#define MUSB2_MASK_TI_SPEED_LO 0xC0
#define MUSB2_MASK_TI_SPEED_FS 0x80
#define MUSB2_MASK_TI_SPEED_HS 0x40
#define MUSB2_MASK_TI_PROTO_CTRL 0x00
#define MUSB2_MASK_TI_PROTO_ISOC 0x10
#define MUSB2_MASK_TI_PROTO_BULK 0x20
#define MUSB2_MASK_TI_PROTO_INTR 0x30
#define MUSB2_MASK_TI_EP_NUM 0x0F
#define MUSB2_REG_TXNAKLIMIT (0x000B /* EPN=0 */ + MUSB2_REG_INDEXED_CSR)
#define MUSB2_REG_RXNAKLIMIT (0x000D /* EPN=0 */ + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_NAKLIMIT 0xFF
#define MUSB2_REG_FSIZE (0x000F + MUSB2_REG_INDEXED_CSR)
#define MUSB2_MASK_RX_FSIZE 0xF0 /* 3..13, 2**n bytes */
#define MUSB2_MASK_TX_FSIZE 0x0F /* 3..13, 2**n bytes */
#define MUSB2_REG_EPFIFO(n) (0x0020 + (4*(n)))
#define MUSB2_REG_CONFDATA 0x000F /* EPN=0 */
#define MUSB2_MASK_CD_UTMI_DW 0x01
#define MUSB2_MASK_CD_SOFTCONE 0x02
#define MUSB2_MASK_CD_DYNFIFOSZ 0x04
#define MUSB2_MASK_CD_HBTXE 0x08
#define MUSB2_MASK_CD_HBRXE 0x10
#define MUSB2_MASK_CD_BIGEND 0x20
#define MUSB2_MASK_CD_MPTXE 0x40
#define MUSB2_MASK_CD_MPRXE 0x80
/* Various registers */
#define MUSB2_REG_DEVCTL 0x0060
#define MUSB2_MASK_SESS 0x01
#define MUSB2_MASK_HOSTREQ 0x02
#define MUSB2_MASK_HOSTMD 0x04
#define MUSB2_MASK_VBUS0 0x08
#define MUSB2_MASK_VBUS1 0x10
#define MUSB2_MASK_LSDEV 0x20
#define MUSB2_MASK_FSDEV 0x40
#define MUSB2_MASK_BDEV 0x80
#define MUSB2_REG_MISC 0x0061
#define MUSB2_MASK_RXEDMA 0x01
#define MUSB2_MASK_TXEDMA 0x02
#define MUSB2_REG_TXFIFOSZ 0x0062
#define MUSB2_REG_RXFIFOSZ 0x0063
#define MUSB2_MASK_FIFODB 0x10 /* set if double buffering, r/w */
#define MUSB2_MASK_FIFOSZ 0x0F
#define MUSB2_VAL_FIFOSZ_8 0
#define MUSB2_VAL_FIFOSZ_16 1
#define MUSB2_VAL_FIFOSZ_32 2
#define MUSB2_VAL_FIFOSZ_64 3
#define MUSB2_VAL_FIFOSZ_128 4
#define MUSB2_VAL_FIFOSZ_256 5
#define MUSB2_VAL_FIFOSZ_512 6
#define MUSB2_VAL_FIFOSZ_1024 7
#define MUSB2_VAL_FIFOSZ_2048 8
#define MUSB2_VAL_FIFOSZ_4096 9
#define MUSB2_REG_TXFIFOADD 0x0064
#define MUSB2_REG_RXFIFOADD 0x0066
#define MUSB2_MASK_FIFOADD 0xFFF /* unit is 8-bytes */
#define MUSB2_REG_VSTATUS 0x0068
#define MUSB2_REG_VCONTROL 0x0068
#define MUSB2_REG_HWVERS 0x006C
#define MUSB2_REG_ULPI_BASE 0x0070
#define MUSB2_REG_EPINFO 0x0078
#define MUSB2_MASK_NRXEP 0xF0
#define MUSB2_MASK_NTXEP 0x0F
#define MUSB2_REG_RAMINFO 0x0079
#define MUSB2_REG_LINKINFO 0x007A
#define MUSB2_REG_VPLEN 0x007B
#define MUSB2_MASK_VPLEN 0xFF
#define MUSB2_REG_HS_EOF1 0x007C
#define MUSB2_REG_FS_EOF1 0x007D
#define MUSB2_REG_LS_EOF1 0x007E
#define MUSB2_REG_SOFT_RST 0x007F
#define MUSB2_MASK_SRST 0x01
#define MUSB2_MASK_SRSTX 0x02
#define MUSB2_REG_RQPKTCOUNT(n) (0x0300 + (4*(n))
#define MUSB2_REG_RXDBDIS 0x0340
#define MUSB2_REG_TXDBDIS 0x0342
#define MUSB2_MASK_DB(n) (1 << (n)) /* disable double buffer, n = [0..15] */
#define MUSB2_REG_CHIRPTO 0x0344
#define MUSB2_REG_HSRESUM 0x0346
/* Host Mode only registers */
#define MUSB2_REG_TXFADDR(n) (0x0080 + (8*(n)))
#define MUSB2_REG_TXHADDR(n) (0x0082 + (8*(n)))
#define MUSB2_REG_TXHUBPORT(n) (0x0083 + (8*(n)))
#define MUSB2_REG_RXFADDR(n) (0x0084 + (8*(n)))
#define MUSB2_REG_RXHADDR(n) (0x0086 + (8*(n)))
#define MUSB2_REG_RXHPORT(n) (0x0087 + (8*(n)))
#define MUSB2_EP_MAX 16 /* maximum number of endpoints */
#define MUSB2_READ_2(sc, reg) \
bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
#define MUSB2_WRITE_2(sc, reg, data) \
bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data)
#define MUSB2_READ_1(sc, reg) \
bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
#define MUSB2_WRITE_1(sc, reg, data) \
bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data)
struct musbotg_td;
struct musbotg_softc;
typedef uint8_t (musbotg_cmd_t)(struct musbotg_td *td);
struct musbotg_dma {
struct musbotg_softc *sc;
uint32_t dma_chan;
uint8_t busy:1;
uint8_t complete:1;
uint8_t error:1;
};
struct musbotg_td {
struct musbotg_td *obj_next;
musbotg_cmd_t *func;
struct usb2_page_cache *pc;
uint32_t offset;
uint32_t remainder;
uint16_t max_frame_size; /* packet_size * mult */
uint8_t ep_no;
uint8_t error:1;
uint8_t alt_next:1;
uint8_t short_pkt:1;
uint8_t support_multi_buffer:1;
uint8_t did_stall:1;
uint8_t dma_enabled:1;
};
struct musbotg_std_temp {
musbotg_cmd_t *func;
struct usb2_page_cache *pc;
struct musbotg_td *td;
struct musbotg_td *td_next;
uint32_t len;
uint32_t offset;
uint16_t max_frame_size;
uint8_t short_pkt;
/*
* short_pkt = 0: transfer should be short terminated
* short_pkt = 1: transfer should not be short terminated
*/
uint8_t setup_alt_next;
};
struct musbotg_config_desc {
struct usb2_config_descriptor confd;
struct usb2_interface_descriptor ifcd;
struct usb2_endpoint_descriptor endpd;
} __packed;
union musbotg_hub_temp {
uWord wValue;
struct usb2_port_status ps;
};
struct musbotg_flags {
uint8_t change_connect:1;
uint8_t change_suspend:1;
uint8_t status_suspend:1; /* set if suspended */
uint8_t status_vbus:1; /* set if present */
uint8_t status_bus_reset:1; /* set if reset complete */
uint8_t status_high_speed:1; /* set if High Speed is selected */
uint8_t remote_wakeup:1;
uint8_t self_powered:1;
uint8_t clocks_off:1;
uint8_t port_powered:1;
uint8_t port_enabled:1;
uint8_t d_pulled_up:1;
};
struct musbotg_softc {
struct usb2_bus sc_bus;
union musbotg_hub_temp sc_hub_temp;
struct usb2_sw_transfer sc_root_ctrl;
struct usb2_sw_transfer sc_root_intr;
struct usb2_config_td sc_config_td;
struct usb2_hw_ep_profile sc_hw_ep_profile[16];
struct resource *sc_io_res;
struct resource *sc_irq_res;
void *sc_intr_hdl;
bus_size_t sc_io_size;
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
void (*sc_clocks_on) (void *arg);
void (*sc_clocks_off) (void *arg);
void *sc_clocks_arg;
uint32_t sc_bounce_buf[(1024 * 3) / 4]; /* bounce buffer */
uint8_t sc_ep_max; /* maximum number of RX and TX
* endpoints supported */
uint8_t sc_rt_addr; /* root HUB address */
uint8_t sc_dv_addr; /* device address */
uint8_t sc_conf; /* root HUB config */
uint8_t sc_ep0_busy; /* set if ep0 is busy */
uint8_t sc_ep0_cmd; /* pending commands */
uint8_t sc_conf_data; /* copy of hardware register */
uint8_t sc_hub_idata[1];
struct musbotg_flags sc_flags;
};
/* prototypes */
usb2_error_t musbotg_init(struct musbotg_softc *sc);
void musbotg_uninit(struct musbotg_softc *sc);
void musbotg_suspend(struct musbotg_softc *sc);
void musbotg_resume(struct musbotg_softc *sc);
void musbotg_interrupt(struct musbotg_softc *sc);
#endif /* _MUSB2_OTG_H_ */

View File

@ -0,0 +1,256 @@
/* $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 <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/musb2_otg.h>
#include <sys/rman.h>
static device_probe_t musbotg_probe;
static device_attach_t musbotg_attach;
static device_detach_t musbotg_detach;
static device_shutdown_t musbotg_shutdown;
struct musbotg_super_softc {
struct musbotg_softc sc_otg; /* must be first */
};
static void
musbotg_vbus_interrupt(struct musbotg_super_softc *sc)
{
uint8_t vbus_val = 1; /* fake VBUS on - TODO */
/* just forward it */
(sc->sc_otg.sc_bus.methods->vbus_interrupt)
(&sc->sc_otg.sc_bus, vbus_val);
return;
}
static void
musbotg_clocks_on(void *arg)
{
#if 0
struct musbotg_super_softc *sc = arg;
#endif
return;
}
static void
musbotg_clocks_off(void *arg)
{
#if 0
struct musbotg_super_softc *sc = arg;
#endif
return;
}
static int
musbotg_probe(device_t dev)
{
device_set_desc(dev, "MUSB OTG integrated USB controller");
return (0);
}
static int
musbotg_attach(device_t dev)
{
struct musbotg_super_softc *sc = device_get_softc(dev);
int err;
int rid;
if (sc == NULL) {
return (ENXIO);
}
/* setup MUSB OTG USB controller interface softc */
sc->sc_otg.sc_clocks_on = &musbotg_clocks_on;
sc->sc_otg.sc_clocks_off = &musbotg_clocks_off;
sc->sc_otg.sc_clocks_arg = sc;
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
USB_GET_DMA_TAG(dev), NULL)) {
return (ENOMEM);
}
rid = 0;
sc->sc_otg.sc_io_res =
bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (!(sc->sc_otg.sc_io_res)) {
err = ENOMEM;
goto error;
}
sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);
sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);
sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res);
rid = 0;
sc->sc_otg.sc_irq_res =
bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
if (!(sc->sc_otg.sc_irq_res)) {
goto error;
}
sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
if (!(sc->sc_otg.sc_bus.bdev)) {
goto error;
}
device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
err = usb2_config_td_setup(&sc->sc_otg.sc_config_td, sc,
&sc->sc_otg.sc_bus.mtx, NULL, 0, 4);
if (err) {
device_printf(dev, "could not setup config thread!\n");
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
#else
err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
#endif
if (err) {
sc->sc_otg.sc_intr_hdl = NULL;
goto error;
}
err = musbotg_init(&sc->sc_otg);
if (!err) {
err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
}
if (err) {
goto error;
} else {
/* poll VBUS one time */
musbotg_vbus_interrupt(sc);
}
return (0);
error:
musbotg_detach(dev);
return (ENXIO);
}
static int
musbotg_detach(device_t dev)
{
struct musbotg_super_softc *sc = device_get_softc(dev);
device_t bdev;
int err;
if (sc->sc_otg.sc_bus.bdev) {
bdev = sc->sc_otg.sc_bus.bdev;
device_detach(bdev);
device_delete_child(dev, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(dev);
if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
/*
* only call musbotg_uninit() after musbotg_init()
*/
musbotg_uninit(&sc->sc_otg);
err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
sc->sc_otg.sc_intr_hdl);
sc->sc_otg.sc_intr_hdl = NULL;
}
/* free IRQ channel, if any */
if (sc->sc_otg.sc_irq_res) {
bus_release_resource(dev, SYS_RES_IRQ, 0,
sc->sc_otg.sc_irq_res);
sc->sc_otg.sc_irq_res = NULL;
}
/* free memory resource, if any */
if (sc->sc_otg.sc_io_res) {
bus_release_resource(dev, SYS_RES_MEMORY, 0,
sc->sc_otg.sc_io_res);
sc->sc_otg.sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_otg.sc_config_td);
usb2_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
return (0);
}
static int
musbotg_shutdown(device_t dev)
{
struct musbotg_super_softc *sc = device_get_softc(dev);
int err;
err = bus_generic_shutdown(dev);
if (err)
return (err);
musbotg_uninit(&sc->sc_otg);
return (0);
}
static device_method_t musbotg_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, musbotg_probe),
DEVMETHOD(device_attach, musbotg_attach),
DEVMETHOD(device_detach, musbotg_detach),
DEVMETHOD(device_shutdown, musbotg_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
};
static driver_t musbotg_driver = {
"musbotg",
musbotg_methods,
sizeof(struct musbotg_super_softc),
};
static devclass_t musbotg_devclass;
DRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0);
MODULE_DEPEND(musbotg, usb2_controller, 1, 1, 1);
MODULE_DEPEND(musbotg, usb2_core, 1, 1, 1);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,364 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef _OHCI_H_
#define _OHCI_H_
/* PCI config registers */
#define PCI_CBMEM 0x10 /* configuration base memory */
#define PCI_INTERFACE_OHCI 0x10
/* OHCI registers */
#define OHCI_REVISION 0x00 /* OHCI revision */
#define OHCI_REV_LO(rev) ((rev) & 0xf)
#define OHCI_REV_HI(rev) (((rev)>>4) & 0xf)
#define OHCI_REV_LEGACY(rev) ((rev) & 0x100)
#define OHCI_CONTROL 0x04
#define OHCI_CBSR_MASK 0x00000003 /* Control/Bulk Service Ratio */
#define OHCI_RATIO_1_1 0x00000000
#define OHCI_RATIO_1_2 0x00000001
#define OHCI_RATIO_1_3 0x00000002
#define OHCI_RATIO_1_4 0x00000003
#define OHCI_PLE 0x00000004 /* Periodic List Enable */
#define OHCI_IE 0x00000008 /* Isochronous Enable */
#define OHCI_CLE 0x00000010 /* Control List Enable */
#define OHCI_BLE 0x00000020 /* Bulk List Enable */
#define OHCI_HCFS_MASK 0x000000c0 /* HostControllerFunctionalStat
* e */
#define OHCI_HCFS_RESET 0x00000000
#define OHCI_HCFS_RESUME 0x00000040
#define OHCI_HCFS_OPERATIONAL 0x00000080
#define OHCI_HCFS_SUSPEND 0x000000c0
#define OHCI_IR 0x00000100 /* Interrupt Routing */
#define OHCI_RWC 0x00000200 /* Remote Wakeup Connected */
#define OHCI_RWE 0x00000400 /* Remote Wakeup Enabled */
#define OHCI_COMMAND_STATUS 0x08
#define OHCI_HCR 0x00000001 /* Host Controller Reset */
#define OHCI_CLF 0x00000002 /* Control List Filled */
#define OHCI_BLF 0x00000004 /* Bulk List Filled */
#define OHCI_OCR 0x00000008 /* Ownership Change Request */
#define OHCI_SOC_MASK 0x00030000 /* Scheduling Overrun Count */
#define OHCI_INTERRUPT_STATUS 0x0c
#define OHCI_SO 0x00000001 /* Scheduling Overrun */
#define OHCI_WDH 0x00000002 /* Writeback Done Head */
#define OHCI_SF 0x00000004 /* Start of Frame */
#define OHCI_RD 0x00000008 /* Resume Detected */
#define OHCI_UE 0x00000010 /* Unrecoverable Error */
#define OHCI_FNO 0x00000020 /* Frame Number Overflow */
#define OHCI_RHSC 0x00000040 /* Root Hub Status Change */
#define OHCI_OC 0x40000000 /* Ownership Change */
#define OHCI_MIE 0x80000000 /* Master Interrupt Enable */
#define OHCI_INTERRUPT_ENABLE 0x10
#define OHCI_INTERRUPT_DISABLE 0x14
#define OHCI_HCCA 0x18
#define OHCI_PERIOD_CURRENT_ED 0x1c
#define OHCI_CONTROL_HEAD_ED 0x20
#define OHCI_CONTROL_CURRENT_ED 0x24
#define OHCI_BULK_HEAD_ED 0x28
#define OHCI_BULK_CURRENT_ED 0x2c
#define OHCI_DONE_HEAD 0x30
#define OHCI_FM_INTERVAL 0x34
#define OHCI_GET_IVAL(s) ((s) & 0x3fff)
#define OHCI_GET_FSMPS(s) (((s) >> 16) & 0x7fff)
#define OHCI_FIT 0x80000000
#define OHCI_FM_REMAINING 0x38
#define OHCI_FM_NUMBER 0x3c
#define OHCI_PERIODIC_START 0x40
#define OHCI_LS_THRESHOLD 0x44
#define OHCI_RH_DESCRIPTOR_A 0x48
#define OHCI_GET_NDP(s) ((s) & 0xff)
#define OHCI_PSM 0x0100 /* Power Switching Mode */
#define OHCI_NPS 0x0200 /* No Power Switching */
#define OHCI_DT 0x0400 /* Device Type */
#define OHCI_OCPM 0x0800 /* Overcurrent Protection Mode */
#define OHCI_NOCP 0x1000 /* No Overcurrent Protection */
#define OHCI_GET_POTPGT(s) ((s) >> 24)
#define OHCI_RH_DESCRIPTOR_B 0x4c
#define OHCI_RH_STATUS 0x50
#define OHCI_LPS 0x00000001 /* Local Power Status */
#define OHCI_OCI 0x00000002 /* OverCurrent Indicator */
#define OHCI_DRWE 0x00008000 /* Device Remote Wakeup Enable */
#define OHCI_LPSC 0x00010000 /* Local Power Status Change */
#define OHCI_CCIC 0x00020000 /* OverCurrent Indicator
* Change */
#define OHCI_CRWE 0x80000000 /* Clear Remote Wakeup Enable */
#define OHCI_RH_PORT_STATUS(n) (0x50 + ((n)*4)) /* 1 based indexing */
#define OHCI_LES (OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE)
#define OHCI_ALL_INTRS (OHCI_SO | OHCI_WDH | OHCI_SF | \
OHCI_RD | OHCI_UE | OHCI_FNO | \
OHCI_RHSC | OHCI_OC)
#define OHCI_NORMAL_INTRS (OHCI_WDH | OHCI_RD | OHCI_UE | OHCI_RHSC)
#define OHCI_FSMPS(i) (((i-210)*6/7) << 16)
#define OHCI_PERIODIC(i) ((i)*9/10)
#define OHCI_NO_INTRS 32
#define OHCI_HCCA_SIZE 256
/* Structures alignment (bytes) */
#define OHCI_HCCA_ALIGN 256
#define OHCI_ED_ALIGN 16
#define OHCI_TD_ALIGN 16
#define OHCI_ITD_ALIGN 32
#define OHCI_PAGE_SIZE 0x1000
#define OHCI_PAGE(x) ((x) &~ 0xfff)
#define OHCI_PAGE_OFFSET(x) ((x) & 0xfff)
#define OHCI_PAGE_MASK(x) ((x) & 0xfff)
#if ((USB_PAGE_SIZE < OHCI_ED_ALIGN) || (OHCI_ED_ALIGN == 0) || \
(USB_PAGE_SIZE < OHCI_TD_ALIGN) || (OHCI_TD_ALIGN == 0) || \
(USB_PAGE_SIZE < OHCI_ITD_ALIGN) || (OHCI_ITD_ALIGN == 0) || \
(USB_PAGE_SIZE < OHCI_PAGE_SIZE) || (OHCI_PAGE_SIZE == 0))
#error "Invalid USB page size!"
#endif
#define OHCI_VIRTUAL_FRAMELIST_COUNT 128/* dummy */
#if (OHCI_VIRTUAL_FRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER)
#error "maximum number of full-speed isochronous frames is higher than supported!"
#endif
struct ohci_hcca {
volatile uint32_t hcca_interrupt_table[OHCI_NO_INTRS];
volatile uint32_t hcca_frame_number;
volatile uint32_t hcca_done_head;
#define OHCI_DONE_INTRS 1
} __aligned(OHCI_HCCA_ALIGN);
typedef struct ohci_hcca ohci_hcca_t;
struct ohci_ed {
volatile uint32_t ed_flags;
#define OHCI_ED_GET_FA(s) ((s) & 0x7f)
#define OHCI_ED_ADDRMASK 0x0000007f
#define OHCI_ED_SET_FA(s) (s)
#define OHCI_ED_GET_EN(s) (((s) >> 7) & 0xf)
#define OHCI_ED_SET_EN(s) ((s) << 7)
#define OHCI_ED_DIR_MASK 0x00001800
#define OHCI_ED_DIR_TD 0x00000000
#define OHCI_ED_DIR_OUT 0x00000800
#define OHCI_ED_DIR_IN 0x00001000
#define OHCI_ED_SPEED 0x00002000
#define OHCI_ED_SKIP 0x00004000
#define OHCI_ED_FORMAT_GEN 0x00000000
#define OHCI_ED_FORMAT_ISO 0x00008000
#define OHCI_ED_GET_MAXP(s) (((s) >> 16) & 0x07ff)
#define OHCI_ED_SET_MAXP(s) ((s) << 16)
#define OHCI_ED_MAXPMASK (0x7ff << 16)
volatile uint32_t ed_tailp;
volatile uint32_t ed_headp;
#define OHCI_HALTED 0x00000001
#define OHCI_TOGGLECARRY 0x00000002
#define OHCI_HEADMASK 0xfffffffc
volatile uint32_t ed_next;
/*
* Extra information needed:
*/
struct ohci_ed *next;
struct ohci_ed *prev;
struct ohci_ed *obj_next;
struct usb2_page_cache *page_cache;
uint32_t ed_self;
} __aligned(OHCI_ED_ALIGN);
typedef struct ohci_ed ohci_ed_t;
struct ohci_td {
volatile uint32_t td_flags;
#define OHCI_TD_R 0x00040000 /* Buffer Rounding */
#define OHCI_TD_DP_MASK 0x00180000 /* Direction / PID */
#define OHCI_TD_SETUP 0x00000000
#define OHCI_TD_OUT 0x00080000
#define OHCI_TD_IN 0x00100000
#define OHCI_TD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */
#define OHCI_TD_SET_DI(x) ((x) << 21)
#define OHCI_TD_NOINTR 0x00e00000
#define OHCI_TD_INTR_MASK 0x00e00000
#define OHCI_TD_TOGGLE_CARRY 0x00000000
#define OHCI_TD_TOGGLE_0 0x02000000
#define OHCI_TD_TOGGLE_1 0x03000000
#define OHCI_TD_TOGGLE_MASK 0x03000000
#define OHCI_TD_GET_EC(x) (((x) >> 26) & 3) /* Error Count */
#define OHCI_TD_GET_CC(x) ((x) >> 28) /* Condition Code */
#define OHCI_TD_SET_CC(x) ((x) << 28)
#define OHCI_TD_NOCC 0xf0000000
volatile uint32_t td_cbp; /* Current Buffer Pointer */
volatile uint32_t td_next; /* Next TD */
#define OHCI_TD_NEXT_END 0
volatile uint32_t td_be; /* Buffer End */
/*
* Extra information needed:
*/
struct ohci_td *obj_next;
struct ohci_td *alt_next;
struct usb2_page_cache *page_cache;
uint32_t td_self;
uint16_t len;
} __aligned(OHCI_TD_ALIGN);
typedef struct ohci_td ohci_td_t;
struct ohci_itd {
volatile uint32_t itd_flags;
#define OHCI_ITD_GET_SF(x) ((x) & 0x0000ffff)
#define OHCI_ITD_SET_SF(x) ((x) & 0xffff)
#define OHCI_ITD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */
#define OHCI_ITD_SET_DI(x) ((x) << 21)
#define OHCI_ITD_NOINTR 0x00e00000
#define OHCI_ITD_GET_FC(x) ((((x) >> 24) & 7)+1) /* Frame Count */
#define OHCI_ITD_SET_FC(x) (((x)-1) << 24)
#define OHCI_ITD_GET_CC(x) ((x) >> 28) /* Condition Code */
#define OHCI_ITD_NOCC 0xf0000000
#define OHCI_ITD_NOFFSET 8
volatile uint32_t itd_bp0; /* Buffer Page 0 */
volatile uint32_t itd_next; /* Next ITD */
volatile uint32_t itd_be; /* Buffer End */
volatile uint16_t itd_offset[OHCI_ITD_NOFFSET]; /* Buffer offsets and
* Status */
#define OHCI_ITD_PAGE_SELECT 0x00001000
#define OHCI_ITD_MK_OFFS(len) (0xe000 | ((len) & 0x1fff))
#define OHCI_ITD_PSW_LENGTH(x) ((x) & 0xfff) /* Transfer length */
#define OHCI_ITD_PSW_GET_CC(x) ((x) >> 12) /* Condition Code */
/*
* Extra information needed:
*/
struct ohci_itd *obj_next;
struct usb2_page_cache *page_cache;
uint32_t itd_self;
uint8_t frames;
} __aligned(OHCI_ITD_ALIGN);
typedef struct ohci_itd ohci_itd_t;
#define OHCI_CC_NO_ERROR 0
#define OHCI_CC_CRC 1
#define OHCI_CC_BIT_STUFFING 2
#define OHCI_CC_DATA_TOGGLE_MISMATCH 3
#define OHCI_CC_STALL 4
#define OHCI_CC_DEVICE_NOT_RESPONDING 5
#define OHCI_CC_PID_CHECK_FAILURE 6
#define OHCI_CC_UNEXPECTED_PID 7
#define OHCI_CC_DATA_OVERRUN 8
#define OHCI_CC_DATA_UNDERRUN 9
#define OHCI_CC_BUFFER_OVERRUN 12
#define OHCI_CC_BUFFER_UNDERRUN 13
#define OHCI_CC_NOT_ACCESSED 15
/* Some delay needed when changing certain registers. */
#define OHCI_ENABLE_POWER_DELAY 5
#define OHCI_READ_DESC_DELAY 5
#define OHCI_NO_EDS (2*OHCI_NO_INTRS)
struct ohci_hw_softc {
struct usb2_page_cache hcca_pc;
struct usb2_page_cache ctrl_start_pc;
struct usb2_page_cache bulk_start_pc;
struct usb2_page_cache isoc_start_pc;
struct usb2_page_cache intr_start_pc[OHCI_NO_EDS];
struct usb2_page hcca_pg;
struct usb2_page ctrl_start_pg;
struct usb2_page bulk_start_pg;
struct usb2_page isoc_start_pg;
struct usb2_page intr_start_pg[OHCI_NO_EDS];
};
struct ohci_config_desc {
struct usb2_config_descriptor confd;
struct usb2_interface_descriptor ifcd;
struct usb2_endpoint_descriptor endpd;
} __packed;
union ohci_hub_desc {
struct usb2_status stat;
struct usb2_port_status ps;
struct usb2_device_descriptor devd;
struct usb2_hub_descriptor hubd;
uint8_t temp[128];
};
typedef struct ohci_softc {
struct ohci_hw_softc sc_hw;
struct usb2_bus sc_bus; /* base device */
struct usb2_config_td sc_config_td;
struct usb2_callout sc_tmo_rhsc;
union ohci_hub_desc sc_hub_desc;
struct usb2_sw_transfer sc_root_ctrl;
struct usb2_sw_transfer sc_root_intr;
struct resource *sc_io_res;
struct resource *sc_irq_res;
struct ohci_hcca *sc_hcca_p;
struct ohci_ed *sc_ctrl_p_last;
struct ohci_ed *sc_bulk_p_last;
struct ohci_ed *sc_isoc_p_last;
struct ohci_ed *sc_intr_p_last[OHCI_NO_EDS];
void *sc_intr_hdl;
device_t sc_dev;
bus_size_t sc_io_size;
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
uint32_t sc_eintrs; /* enabled interrupts */
uint32_t sc_control; /* Preserved during suspend/standby */
uint32_t sc_intre;
uint16_t sc_intr_stat[OHCI_NO_EDS];
uint16_t sc_id_vendor;
uint8_t sc_noport;
uint8_t sc_addr; /* device address */
uint8_t sc_conf; /* device configuration */
uint8_t sc_hub_idata[32];
char sc_vendor[16];
} ohci_softc_t;
usb2_bus_mem_cb_t ohci_iterate_hw_softc;
usb2_error_t ohci_init(ohci_softc_t *sc);
void ohci_detach(struct ohci_softc *sc);
void ohci_suspend(ohci_softc_t *sc);
void ohci_resume(ohci_softc_t *sc);
void ohci_interrupt(ohci_softc_t *sc);
#endif /* _OHCI_H_ */

View File

@ -0,0 +1,232 @@
/*-
* Copyright (c) 2006 M. Warner Losh. 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 ``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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/ohci2.h>
#include <sys/rman.h>
#include <arm/at91/at91_pmcvar.h>
#define MEM_RID 0
static device_probe_t ohci_atmelarm_probe;
static device_attach_t ohci_atmelarm_attach;
static device_detach_t ohci_atmelarm_detach;
struct at91_ohci_softc {
struct ohci_softc sc_ohci; /* must be first */
struct at91_pmc_clock *iclk;
struct at91_pmc_clock *fclk;
};
static int
ohci_atmelarm_probe(device_t dev)
{
device_set_desc(dev, "AT91 integrated OHCI controller");
return (BUS_PROBE_DEFAULT);
}
static int
ohci_atmelarm_attach(device_t dev)
{
struct at91_ohci_softc *sc = device_get_softc(dev);
int err;
int rid;
if (sc == NULL) {
return (ENXIO);
}
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_ohci.sc_bus,
USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) {
return ENOMEM;
}
sc->iclk = at91_pmc_clock_ref("ohci_clk");
sc->fclk = at91_pmc_clock_ref("uhpck");
sc->sc_ohci.sc_dev = dev;
rid = MEM_RID;
sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&rid, RF_ACTIVE);
if (!(sc->sc_ohci.sc_io_res)) {
err = ENOMEM;
goto error;
}
sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res);
sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res);
sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res);
rid = 0;
sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_ACTIVE);
if (!(sc->sc_ohci.sc_irq_res)) {
goto error;
}
sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1);
if (!(sc->sc_ohci.sc_bus.bdev)) {
goto error;
}
device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus);
strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor));
err = usb2_config_td_setup(&sc->sc_ohci.sc_config_td, sc,
&sc->sc_ohci.sc_bus.mtx, NULL, 0, 4);
if (err) {
device_printf(dev, "could not setup config thread!\n");
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
#else
err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl);
#endif
if (err) {
sc->sc_ohci.sc_intr_hdl = NULL;
goto error;
}
/*
* turn on the clocks from the AT91's point of view. Keep the unit in reset.
*/
at91_pmc_clock_enable(sc->iclk);
at91_pmc_clock_enable(sc->fclk);
bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl,
OHCI_CONTROL, 0);
err = ohci_init(&sc->sc_ohci);
if (!err) {
err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev);
}
if (err) {
goto error;
}
return (0);
error:
ohci_atmelarm_detach(dev);
return (ENXIO);
}
static int
ohci_atmelarm_detach(device_t dev)
{
struct at91_ohci_softc *sc = device_get_softc(dev);
device_t bdev;
int err;
if (sc->sc_ohci.sc_bus.bdev) {
bdev = sc->sc_ohci.sc_bus.bdev;
device_detach(bdev);
device_delete_child(dev, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(dev);
/*
* Put the controller into reset, then disable clocks and do
* the MI tear down. We have to disable the clocks/hardware
* after we do the rest of the teardown. We also disable the
* clocks in the opposite order we acquire them, but that
* doesn't seem to be absolutely necessary. We free up the
* clocks after we disable them, so the system could, in
* theory, reuse them.
*/
bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl,
OHCI_CONTROL, 0);
at91_pmc_clock_disable(sc->fclk);
at91_pmc_clock_disable(sc->iclk);
at91_pmc_clock_deref(sc->fclk);
at91_pmc_clock_deref(sc->iclk);
if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) {
/*
* only call ohci_detach() after ohci_init()
*/
ohci_detach(&sc->sc_ohci);
err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl);
sc->sc_ohci.sc_intr_hdl = NULL;
}
if (sc->sc_ohci.sc_irq_res) {
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res);
sc->sc_ohci.sc_irq_res = NULL;
}
if (sc->sc_ohci.sc_io_res) {
bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID,
sc->sc_ohci.sc_io_res);
sc->sc_ohci.sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_ohci.sc_config_td);
usb2_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc);
return (0);
}
static device_method_t ohci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ohci_atmelarm_probe),
DEVMETHOD(device_attach, ohci_atmelarm_attach),
DEVMETHOD(device_detach, ohci_atmelarm_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
};
static driver_t ohci_driver = {
"ohci",
ohci_methods,
sizeof(struct at91_ohci_softc),
};
static devclass_t ohci_devclass;
DRIVER_MODULE(ohci, atmelarm, ohci_driver, ohci_devclass, 0, 0);
MODULE_DEPEND(ohci, usb2_controller, 1, 1, 1);
MODULE_DEPEND(ohci, usb2_core, 1, 1, 1);

View File

@ -0,0 +1,392 @@
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (augustss@carlstedt.se) at
* Carlstedt Research & Technology.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* USB Open Host Controller driver.
*
* OHCI spec: http://www.intel.com/design/usb/ohci11d.pdf
*/
/* The low level controller code for OHCI has been split into
* PCI probes and OHCI specific code. This was done to facilitate the
* sharing of code between *BSD's
*/
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/usb2_pci.h>
#include <dev/usb2/controller/ohci2.h>
#define PCI_OHCI_VENDORID_ACERLABS 0x10b9
#define PCI_OHCI_VENDORID_AMD 0x1022
#define PCI_OHCI_VENDORID_APPLE 0x106b
#define PCI_OHCI_VENDORID_ATI 0x1002
#define PCI_OHCI_VENDORID_CMDTECH 0x1095
#define PCI_OHCI_VENDORID_NEC 0x1033
#define PCI_OHCI_VENDORID_NVIDIA 0x12D2
#define PCI_OHCI_VENDORID_NVIDIA2 0x10DE
#define PCI_OHCI_VENDORID_OPTI 0x1045
#define PCI_OHCI_VENDORID_SIS 0x1039
#define PCI_OHCI_VENDORID_SUN 0x108e
#define PCI_OHCI_BASE_REG 0x10
static device_probe_t ohci_pci_probe;
static device_attach_t ohci_pci_attach;
static device_detach_t ohci_pci_detach;
static device_suspend_t ohci_pci_suspend;
static device_resume_t ohci_pci_resume;
static int
ohci_pci_suspend(device_t self)
{
ohci_softc_t *sc = device_get_softc(self);
int err;
err = bus_generic_suspend(self);
if (err) {
return (err);
}
ohci_suspend(sc);
return (0);
}
static int
ohci_pci_resume(device_t self)
{
ohci_softc_t *sc = device_get_softc(self);
uint32_t reg, int_line;
if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) {
device_printf(self, "chip is in D%d mode "
"-- setting to D0\n", pci_get_powerstate(self));
reg = pci_read_config(self, PCI_CBMEM, 4);
int_line = pci_read_config(self, PCIR_INTLINE, 4);
pci_set_powerstate(self, PCI_POWERSTATE_D0);
pci_write_config(self, PCI_CBMEM, reg, 4);
pci_write_config(self, PCIR_INTLINE, int_line, 4);
}
ohci_resume(sc);
bus_generic_resume(self);
return (0);
}
static const char *
ohci_pci_match(device_t self)
{
uint32_t device_id = pci_get_devid(self);
switch (device_id) {
case 0x523710b9:
return ("AcerLabs M5237 (Aladdin-V) USB controller");
case 0x740c1022:
return ("AMD-756 USB Controller");
case 0x74141022:
return ("AMD-766 USB Controller");
case 0x43741002:
return "ATI SB400 USB Controller";
case 0x43751002:
return "ATI SB400 USB Controller";
case 0x06701095:
return ("CMD Tech 670 (USB0670) USB controller");
case 0x06731095:
return ("CMD Tech 673 (USB0673) USB controller");
case 0xc8611045:
return ("OPTi 82C861 (FireLink) USB controller");
case 0x00351033:
return ("NEC uPD 9210 USB controller");
case 0x00d710de:
return ("nVidia nForce3 USB Controller");
case 0x70011039:
return ("SiS 5571 USB controller");
case 0x1103108e:
return "Sun PCIO-2 USB controller";
case 0x0019106b:
return ("Apple KeyLargo USB controller");
default:
break;
}
if ((pci_get_class(self) == PCIC_SERIALBUS) &&
(pci_get_subclass(self) == PCIS_SERIALBUS_USB) &&
(pci_get_progif(self) == PCI_INTERFACE_OHCI)) {
return ("OHCI (generic) USB controller");
}
return (NULL);
}
static int
ohci_pci_probe(device_t self)
{
const char *desc = ohci_pci_match(self);
if (desc) {
device_set_desc(self, desc);
return (0);
} else {
return (ENXIO);
}
}
static int
ohci_pci_attach(device_t self)
{
ohci_softc_t *sc = device_get_softc(self);
int rid;
int err;
if (sc == NULL) {
device_printf(self, "Could not allocate sc\n");
return (ENXIO);
}
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self),
&ohci_iterate_hw_softc)) {
return ENOMEM;
}
sc->sc_dev = self;
pci_enable_busmaster(self);
rid = PCI_CBMEM;
sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (!sc->sc_io_res) {
device_printf(self, "Could not map memory\n");
goto error;
}
sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
sc->sc_io_size = rman_get_size(sc->sc_io_res);
rid = 0;
sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
RF_SHAREABLE | RF_ACTIVE);
if (sc->sc_irq_res == NULL) {
device_printf(self, "Could not allocate irq\n");
goto error;
}
sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
if (!sc->sc_bus.bdev) {
device_printf(self, "Could not add USB device\n");
goto error;
}
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
/*
* ohci_pci_match will never return NULL if ohci_pci_probe
* succeeded
*/
device_set_desc(sc->sc_bus.bdev, ohci_pci_match(self));
switch (pci_get_vendor(self)) {
case PCI_OHCI_VENDORID_ACERLABS:
sprintf(sc->sc_vendor, "AcerLabs");
break;
case PCI_OHCI_VENDORID_AMD:
sprintf(sc->sc_vendor, "AMD");
break;
case PCI_OHCI_VENDORID_APPLE:
sprintf(sc->sc_vendor, "Apple");
break;
case PCI_OHCI_VENDORID_ATI:
sprintf(sc->sc_vendor, "ATI");
break;
case PCI_OHCI_VENDORID_CMDTECH:
sprintf(sc->sc_vendor, "CMDTECH");
break;
case PCI_OHCI_VENDORID_NEC:
sprintf(sc->sc_vendor, "NEC");
break;
case PCI_OHCI_VENDORID_NVIDIA:
case PCI_OHCI_VENDORID_NVIDIA2:
sprintf(sc->sc_vendor, "nVidia");
break;
case PCI_OHCI_VENDORID_OPTI:
sprintf(sc->sc_vendor, "OPTi");
break;
case PCI_OHCI_VENDORID_SIS:
sprintf(sc->sc_vendor, "SiS");
break;
case PCI_OHCI_VENDORID_SUN:
sprintf(sc->sc_vendor, "SUN");
break;
default:
if (bootverbose) {
device_printf(self, "(New OHCI DeviceId=0x%08x)\n",
pci_get_devid(self));
}
sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self));
}
err = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_bus.mtx,
NULL, 0, 4);
if (err) {
device_printf(self, "could not setup config thread!\n");
goto error;
}
/* sc->sc_bus.usbrev; set by ohci_init() */
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl);
#else
err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl);
#endif
if (err) {
device_printf(self, "Could not setup irq, %d\n", err);
sc->sc_intr_hdl = NULL;
goto error;
}
err = ohci_init(sc);
if (!err) {
err = device_probe_and_attach(sc->sc_bus.bdev);
}
if (err) {
device_printf(self, "USB init failed\n");
goto error;
}
return (0);
error:
ohci_pci_detach(self);
return (ENXIO);
}
static int
ohci_pci_detach(device_t self)
{
ohci_softc_t *sc = device_get_softc(self);
device_t bdev;
usb2_config_td_drain(&sc->sc_config_td);
if (sc->sc_bus.bdev) {
bdev = sc->sc_bus.bdev;
device_detach(bdev);
device_delete_child(self, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(self);
pci_disable_busmaster(self);
if (sc->sc_irq_res && sc->sc_intr_hdl) {
/*
* only call ohci_detach() after ohci_init()
*/
ohci_detach(sc);
int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
if (err) {
/* XXX or should we panic? */
device_printf(self, "Could not tear down irq, %d\n",
err);
}
sc->sc_intr_hdl = NULL;
}
if (sc->sc_irq_res) {
bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
sc->sc_irq_res = NULL;
}
if (sc->sc_io_res) {
bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM,
sc->sc_io_res);
sc->sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_config_td);
usb2_bus_mem_free_all(&sc->sc_bus, &ohci_iterate_hw_softc);
return (0);
}
static driver_t ohci_driver =
{
.name = "ohci",
.methods = (device_method_t[]){
/* device interface */
DEVMETHOD(device_probe, ohci_pci_probe),
DEVMETHOD(device_attach, ohci_pci_attach),
DEVMETHOD(device_detach, ohci_pci_detach),
DEVMETHOD(device_suspend, ohci_pci_suspend),
DEVMETHOD(device_resume, ohci_pci_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
/* bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
},
.size = sizeof(struct ohci_softc),
};
static devclass_t ohci_devclass;
DRIVER_MODULE(ohci, pci, ohci_driver, ohci_devclass, 0, 0);
DRIVER_MODULE(ohci, cardbus, ohci_driver, ohci_devclass, 0, 0);
MODULE_DEPEND(ohci, usb2_controller, 1, 1, 1);
MODULE_DEPEND(ohci, usb2_core, 1, 1, 1);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,318 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef _UHCI_H_
#define _UHCI_H_
/* PCI config registers */
#define PCI_USBREV 0x60 /* USB protocol revision */
#define PCI_USB_REV_MASK 0xff
#define PCI_USB_REV_PRE_1_0 0x00
#define PCI_USB_REV_1_0 0x10
#define PCI_USB_REV_1_1 0x11
#define PCI_LEGSUP 0xc0 /* Legacy Support register */
#define PCI_LEGSUP_USBPIRQDEN 0x2000 /* USB PIRQ D Enable */
#define PCI_CBIO 0x20 /* configuration base IO */
#define PCI_INTERFACE_UHCI 0x00
/* UHCI registers */
#define UHCI_CMD 0x00
#define UHCI_CMD_RS 0x0001
#define UHCI_CMD_HCRESET 0x0002
#define UHCI_CMD_GRESET 0x0004
#define UHCI_CMD_EGSM 0x0008
#define UHCI_CMD_FGR 0x0010
#define UHCI_CMD_SWDBG 0x0020
#define UHCI_CMD_CF 0x0040
#define UHCI_CMD_MAXP 0x0080
#define UHCI_STS 0x02
#define UHCI_STS_USBINT 0x0001
#define UHCI_STS_USBEI 0x0002
#define UHCI_STS_RD 0x0004
#define UHCI_STS_HSE 0x0008
#define UHCI_STS_HCPE 0x0010
#define UHCI_STS_HCH 0x0020
#define UHCI_STS_ALLINTRS 0x003f
#define UHCI_INTR 0x04
#define UHCI_INTR_TOCRCIE 0x0001
#define UHCI_INTR_RIE 0x0002
#define UHCI_INTR_IOCE 0x0004
#define UHCI_INTR_SPIE 0x0008
#define UHCI_FRNUM 0x06
#define UHCI_FRNUM_MASK 0x03ff
#define UHCI_FLBASEADDR 0x08
#define UHCI_SOF 0x0c
#define UHCI_SOF_MASK 0x7f
#define UHCI_PORTSC1 0x010
#define UHCI_PORTSC2 0x012
#define UHCI_PORTSC_CCS 0x0001
#define UHCI_PORTSC_CSC 0x0002
#define UHCI_PORTSC_PE 0x0004
#define UHCI_PORTSC_POEDC 0x0008
#define UHCI_PORTSC_LS 0x0030
#define UHCI_PORTSC_LS_SHIFT 4
#define UHCI_PORTSC_RD 0x0040
#define UHCI_PORTSC_LSDA 0x0100
#define UHCI_PORTSC_PR 0x0200
#define UHCI_PORTSC_OCI 0x0400
#define UHCI_PORTSC_OCIC 0x0800
#define UHCI_PORTSC_SUSP 0x1000
#define URWMASK(x) ((x) & (UHCI_PORTSC_SUSP | \
UHCI_PORTSC_PR | UHCI_PORTSC_RD | \
UHCI_PORTSC_PE))
#define UHCI_FRAMELIST_COUNT 1024 /* units */
#define UHCI_FRAMELIST_ALIGN 4096 /* bytes */
/* Structures alignment (bytes) */
#define UHCI_TD_ALIGN 16
#define UHCI_QH_ALIGN 16
#if ((USB_PAGE_SIZE < UHCI_TD_ALIGN) || (UHCI_TD_ALIGN == 0) || \
(USB_PAGE_SIZE < UHCI_QH_ALIGN) || (UHCI_QH_ALIGN == 0))
#error "Invalid USB page size!"
#endif
typedef uint32_t uhci_physaddr_t;
#define UHCI_PTR_T 0x00000001
#define UHCI_PTR_TD 0x00000000
#define UHCI_PTR_QH 0x00000002
#define UHCI_PTR_VF 0x00000004
#define UHCI_QH_REMOVE_DELAY 5 /* us - QH remove delay */
/*
* The Queue Heads (QH) and Transfer Descriptors (TD) are accessed by
* both the CPU and the USB-controller which run concurrently. Great
* care must be taken. When the data-structures are linked into the
* USB controller's frame list, the USB-controller "owns" the
* td_status and qh_elink fields, which will not be written by the
* CPU.
*
*/
struct uhci_td {
/*
* Data used by the UHCI controller.
* volatile is used in order to mantain struct members ordering.
*/
volatile uint32_t td_next;
volatile uint32_t td_status;
#define UHCI_TD_GET_ACTLEN(s) (((s) + 1) & 0x3ff)
#define UHCI_TD_ZERO_ACTLEN(t) ((t) | 0x3ff)
#define UHCI_TD_BITSTUFF 0x00020000
#define UHCI_TD_CRCTO 0x00040000
#define UHCI_TD_NAK 0x00080000
#define UHCI_TD_BABBLE 0x00100000
#define UHCI_TD_DBUFFER 0x00200000
#define UHCI_TD_STALLED 0x00400000
#define UHCI_TD_ACTIVE 0x00800000
#define UHCI_TD_IOC 0x01000000
#define UHCI_TD_IOS 0x02000000
#define UHCI_TD_LS 0x04000000
#define UHCI_TD_GET_ERRCNT(s) (((s) >> 27) & 3)
#define UHCI_TD_SET_ERRCNT(n) ((n) << 27)
#define UHCI_TD_SPD 0x20000000
volatile uint32_t td_token;
#define UHCI_TD_PID 0x000000ff
#define UHCI_TD_PID_IN 0x00000069
#define UHCI_TD_PID_OUT 0x000000e1
#define UHCI_TD_PID_SETUP 0x0000002d
#define UHCI_TD_GET_PID(s) ((s) & 0xff)
#define UHCI_TD_SET_DEVADDR(a) ((a) << 8)
#define UHCI_TD_GET_DEVADDR(s) (((s) >> 8) & 0x7f)
#define UHCI_TD_SET_ENDPT(e) (((e) & 0xf) << 15)
#define UHCI_TD_GET_ENDPT(s) (((s) >> 15) & 0xf)
#define UHCI_TD_SET_DT(t) ((t) << 19)
#define UHCI_TD_GET_DT(s) (((s) >> 19) & 1)
#define UHCI_TD_SET_MAXLEN(l) (((l)-1) << 21)
#define UHCI_TD_GET_MAXLEN(s) ((((s) >> 21) + 1) & 0x7ff)
#define UHCI_TD_MAXLEN_MASK 0xffe00000
volatile uint32_t td_buffer;
/*
* Extra information needed:
*/
struct uhci_td *next;
struct uhci_td *prev;
struct uhci_td *obj_next;
struct usb2_page_cache *page_cache;
struct usb2_page_cache *fix_pc;
uint32_t td_self;
uint16_t len;
} __aligned(UHCI_TD_ALIGN);
typedef struct uhci_td uhci_td_t;
#define UHCI_TD_ERROR (UHCI_TD_BITSTUFF | UHCI_TD_CRCTO | \
UHCI_TD_BABBLE | UHCI_TD_DBUFFER | UHCI_TD_STALLED)
#define UHCI_TD_SETUP(len, endp, dev) (UHCI_TD_SET_MAXLEN(len) | \
UHCI_TD_SET_ENDPT(endp) | \
UHCI_TD_SET_DEVADDR(dev) | \
UHCI_TD_PID_SETUP)
#define UHCI_TD_OUT(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | \
UHCI_TD_SET_ENDPT(endp) | \
UHCI_TD_SET_DEVADDR(dev) | \
UHCI_TD_PID_OUT | UHCI_TD_SET_DT(dt))
#define UHCI_TD_IN(len, endp, dev, dt) (UHCI_TD_SET_MAXLEN(len) | \
UHCI_TD_SET_ENDPT(endp) | \
UHCI_TD_SET_DEVADDR(dev) | \
UHCI_TD_PID_IN | UHCI_TD_SET_DT(dt))
struct uhci_qh {
/*
* Data used by the UHCI controller.
*/
volatile uint32_t qh_h_next;
volatile uint32_t qh_e_next;
/*
* Extra information needed:
*/
struct uhci_qh *h_next;
struct uhci_qh *h_prev;
struct uhci_qh *obj_next;
struct uhci_td *e_next;
struct usb2_page_cache *page_cache;
uint32_t qh_self;
uint16_t intr_pos;
} __aligned(UHCI_QH_ALIGN);
typedef struct uhci_qh uhci_qh_t;
/* Maximum number of isochronous TD's and QH's interrupt */
#define UHCI_VFRAMELIST_COUNT 128
#define UHCI_IFRAMELIST_COUNT (2 * UHCI_VFRAMELIST_COUNT)
#if (((UHCI_VFRAMELIST_COUNT & (UHCI_VFRAMELIST_COUNT-1)) != 0) || \
(UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT))
#error "UHCI_VFRAMELIST_COUNT is not power of two"
#error "or UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT"
#endif
#if (UHCI_VFRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER)
#error "maximum number of full-speed isochronous frames is higher than supported!"
#endif
struct uhci_config_desc {
struct usb2_config_descriptor confd;
struct usb2_interface_descriptor ifcd;
struct usb2_endpoint_descriptor endpd;
} __packed;
union uhci_hub_desc {
struct usb2_status stat;
struct usb2_port_status ps;
struct usb2_device_descriptor devd;
uint8_t temp[128];
};
struct uhci_hw_softc {
struct usb2_page_cache pframes_pc;
struct usb2_page_cache isoc_start_pc[UHCI_VFRAMELIST_COUNT];
struct usb2_page_cache intr_start_pc[UHCI_IFRAMELIST_COUNT];
struct usb2_page_cache ls_ctl_start_pc;
struct usb2_page_cache fs_ctl_start_pc;
struct usb2_page_cache bulk_start_pc;
struct usb2_page_cache last_qh_pc;
struct usb2_page_cache last_td_pc;
struct usb2_page pframes_pg;
struct usb2_page isoc_start_pg[UHCI_VFRAMELIST_COUNT];
struct usb2_page intr_start_pg[UHCI_IFRAMELIST_COUNT];
struct usb2_page ls_ctl_start_pg;
struct usb2_page fs_ctl_start_pg;
struct usb2_page bulk_start_pg;
struct usb2_page last_qh_pg;
struct usb2_page last_td_pg;
};
typedef struct uhci_softc {
struct uhci_hw_softc sc_hw;
struct usb2_bus sc_bus; /* base device */
struct usb2_config_td sc_config_td;
union uhci_hub_desc sc_hub_desc;
struct usb2_sw_transfer sc_root_ctrl;
struct usb2_sw_transfer sc_root_intr;
struct uhci_td *sc_isoc_p_last[UHCI_VFRAMELIST_COUNT]; /* pointer to last TD
* for isochronous */
struct uhci_qh *sc_intr_p_last[UHCI_IFRAMELIST_COUNT]; /* pointer to last QH
* for interrupt */
struct uhci_qh *sc_ls_ctl_p_last; /* pointer to last QH for low
* speed control */
struct uhci_qh *sc_fs_ctl_p_last; /* pointer to last QH for full
* speed control */
struct uhci_qh *sc_bulk_p_last; /* pointer to last QH for bulk */
struct uhci_qh *sc_reclaim_qh_p;
struct uhci_qh *sc_last_qh_p;
struct uhci_td *sc_last_td_p;
struct resource *sc_io_res;
struct resource *sc_irq_res;
void *sc_intr_hdl;
device_t sc_dev;
bus_size_t sc_io_size;
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
uint32_t sc_loops; /* number of QHs that wants looping */
uint16_t sc_intr_stat[UHCI_IFRAMELIST_COUNT];
uint16_t sc_saved_frnum;
uint8_t sc_addr; /* device address */
uint8_t sc_conf; /* device configuration */
uint8_t sc_isreset;
uint8_t sc_saved_sof;
uint8_t sc_hub_idata[1];
char sc_vendor[16]; /* vendor string for root hub */
} uhci_softc_t;
usb2_bus_mem_cb_t uhci_iterate_hw_softc;
usb2_error_t uhci_init(uhci_softc_t *sc);
void uhci_suspend(uhci_softc_t *sc);
void uhci_resume(uhci_softc_t *sc);
void uhci_reset(uhci_softc_t *sc);
void uhci_interrupt(uhci_softc_t *sc);
#endif /* _UHCI_H_ */

View File

@ -0,0 +1,453 @@
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (augustss@carlstedt.se) at
* Carlstedt Research & Technology.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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/cdefs.h>
__FBSDID("$FreeBSD$");
/* Universal Host Controller Interface
*
* UHCI spec: http://www.intel.com/
*/
/* The low level controller code for UHCI has been split into
* PCI probes and UHCI specific code. This was done to facilitate the
* sharing of code between *BSD's
*/
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/usb2_pci.h>
#include <dev/usb2/controller/uhci2.h>
#define PCI_UHCI_VENDORID_INTEL 0x8086
#define PCI_UHCI_VENDORID_VIA 0x1106
/* PIIX4E has no separate stepping */
#define PCI_UHCI_BASE_REG 0x20
static device_probe_t uhci_pci_probe;
static device_attach_t uhci_pci_attach;
static device_detach_t uhci_pci_detach;
static device_suspend_t uhci_pci_suspend;
static device_resume_t uhci_pci_resume;
static int
uhci_pci_suspend(device_t self)
{
uhci_softc_t *sc = device_get_softc(self);
int err;
err = bus_generic_suspend(self);
if (err) {
return (err);
}
uhci_suspend(sc);
return (0);
}
static int
uhci_pci_resume(device_t self)
{
uhci_softc_t *sc = device_get_softc(self);
pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2);
uhci_resume(sc);
bus_generic_resume(self);
return (0);
}
static const char *
uhci_pci_match(device_t self)
{
uint32_t device_id = pci_get_devid(self);
switch (device_id) {
case 0x26888086:
return ("Intel 631XESB/632XESB/3100 USB controller USB-1");
case 0x26898086:
return ("Intel 631XESB/632XESB/3100 USB controller USB-2");
case 0x268a8086:
return ("Intel 631XESB/632XESB/3100 USB controller USB-3");
case 0x268b8086:
return ("Intel 631XESB/632XESB/3100 USB controller USB-4");
case 0x70208086:
return ("Intel 82371SB (PIIX3) USB controller");
case 0x71128086:
return ("Intel 82371AB/EB (PIIX4) USB controller");
case 0x24128086:
return ("Intel 82801AA (ICH) USB controller");
case 0x24228086:
return ("Intel 82801AB (ICH0) USB controller");
case 0x24428086:
return ("Intel 82801BA/BAM (ICH2) USB controller USB-A");
case 0x24448086:
return ("Intel 82801BA/BAM (ICH2) USB controller USB-B");
case 0x24828086:
return ("Intel 82801CA/CAM (ICH3) USB controller USB-A");
case 0x24848086:
return ("Intel 82801CA/CAM (ICH3) USB controller USB-B");
case 0x24878086:
return ("Intel 82801CA/CAM (ICH3) USB controller USB-C");
case 0x24c28086:
return ("Intel 82801DB (ICH4) USB controller USB-A");
case 0x24c48086:
return ("Intel 82801DB (ICH4) USB controller USB-B");
case 0x24c78086:
return ("Intel 82801DB (ICH4) USB controller USB-C");
case 0x24d28086:
return ("Intel 82801EB (ICH5) USB controller USB-A");
case 0x24d48086:
return ("Intel 82801EB (ICH5) USB controller USB-B");
case 0x24d78086:
return ("Intel 82801EB (ICH5) USB controller USB-C");
case 0x24de8086:
return ("Intel 82801EB (ICH5) USB controller USB-D");
case 0x26588086:
return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-A");
case 0x26598086:
return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-B");
case 0x265a8086:
return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-C");
case 0x265b8086:
return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-D");
case 0x28308086:
return ("Intel 82801H (ICH8) USB controller USB-A");
case 0x28318086:
return ("Intel 82801H (ICH8) USB controller USB-B");
case 0x28328086:
return ("Intel 82801H (ICH8) USB controller USB-C");
case 0x28348086:
return ("Intel 82801H (ICH8) USB controller USB-D");
case 0x28358086:
return ("Intel 82801H (ICH8) USB controller USB-E");
case 0x29348086:
return ("Intel 82801I (ICH9) USB controller");
case 0x29358086:
return ("Intel 82801I (ICH9) USB controller");
case 0x29368086:
return ("Intel 82801I (ICH9) USB controller");
case 0x29378086:
return ("Intel 82801I (ICH9) USB controller");
case 0x29388086:
return ("Intel 82801I (ICH9) USB controller");
case 0x29398086:
return ("Intel 82801I (ICH9) USB controller");
case 0x719a8086:
return ("Intel 82443MX USB controller");
case 0x76028086:
return ("Intel 82372FB/82468GX USB controller");
case 0x30381106:
return ("VIA 83C572 USB controller");
default:
break;
}
if ((pci_get_class(self) == PCIC_SERIALBUS) &&
(pci_get_subclass(self) == PCIS_SERIALBUS_USB) &&
(pci_get_progif(self) == PCI_INTERFACE_UHCI)) {
return ("UHCI (generic) USB controller");
}
return (NULL);
}
static int
uhci_pci_probe(device_t self)
{
const char *desc = uhci_pci_match(self);
if (desc) {
device_set_desc(self, desc);
return (0);
} else {
return (ENXIO);
}
}
static int
uhci_pci_attach(device_t self)
{
uhci_softc_t *sc = device_get_softc(self);
int rid;
int err;
if (sc == NULL) {
device_printf(self, "Could not allocate sc\n");
return (ENXIO);
}
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self),
&uhci_iterate_hw_softc)) {
return ENOMEM;
}
sc->sc_dev = self;
pci_enable_busmaster(self);
rid = PCI_UHCI_BASE_REG;
sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (!sc->sc_io_res) {
device_printf(self, "Could not map ports\n");
goto error;
}
sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
sc->sc_io_size = rman_get_size(sc->sc_io_res);
/* disable interrupts */
bus_space_write_2(sc->sc_io_tag, sc->sc_io_hdl, UHCI_INTR, 0);
rid = 0;
sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
RF_SHAREABLE | RF_ACTIVE);
if (sc->sc_irq_res == NULL) {
device_printf(self, "Could not allocate irq\n");
goto error;
}
sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
if (!sc->sc_bus.bdev) {
device_printf(self, "Could not add USB device\n");
goto error;
}
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
/*
* uhci_pci_match must never return NULL if uhci_pci_probe
* succeeded
*/
device_set_desc(sc->sc_bus.bdev, uhci_pci_match(self));
switch (pci_get_vendor(self)) {
case PCI_UHCI_VENDORID_INTEL:
sprintf(sc->sc_vendor, "Intel");
break;
case PCI_UHCI_VENDORID_VIA:
sprintf(sc->sc_vendor, "VIA");
break;
default:
if (bootverbose) {
device_printf(self, "(New UHCI DeviceId=0x%08x)\n",
pci_get_devid(self));
}
sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self));
}
switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) {
case PCI_USB_REV_PRE_1_0:
sc->sc_bus.usbrev = USB_REV_PRE_1_0;
break;
case PCI_USB_REV_1_0:
sc->sc_bus.usbrev = USB_REV_1_0;
break;
default:
sc->sc_bus.usbrev = USB_REV_UNKNOWN;
break;
}
err = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_bus.mtx,
NULL, 0, 4);
if (err) {
device_printf(self, "could not setup config thread!\n");
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl);
#else
err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl);
#endif
if (err) {
device_printf(self, "Could not setup irq, %d\n", err);
sc->sc_intr_hdl = NULL;
goto error;
}
/*
* Set the PIRQD enable bit and switch off all the others. We don't
* want legacy support to interfere with us XXX Does this also mean
* that the BIOS won't touch the keyboard anymore if it is connected
* to the ports of the root hub?
*/
#if USB_DEBUG
if (pci_read_config(self, PCI_LEGSUP, 2) != PCI_LEGSUP_USBPIRQDEN) {
device_printf(self, "LegSup = 0x%04x\n",
pci_read_config(self, PCI_LEGSUP, 2));
}
#endif
pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2);
err = uhci_init(sc);
if (!err) {
err = device_probe_and_attach(sc->sc_bus.bdev);
}
if (err) {
device_printf(self, "USB init failed\n");
goto error;
}
return (0);
error:
uhci_pci_detach(self);
return (ENXIO);
}
int
uhci_pci_detach(device_t self)
{
uhci_softc_t *sc = device_get_softc(self);
device_t bdev;
usb2_config_td_drain(&sc->sc_config_td);
if (sc->sc_bus.bdev) {
bdev = sc->sc_bus.bdev;
device_detach(bdev);
device_delete_child(self, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(self);
/*
* disable interrupts that might have been switched on in
* uhci_init.
*/
if (sc->sc_io_res) {
mtx_lock(&sc->sc_bus.mtx);
/* stop the controller */
uhci_reset(sc);
mtx_unlock(&sc->sc_bus.mtx);
}
pci_disable_busmaster(self);
if (sc->sc_irq_res && sc->sc_intr_hdl) {
int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
if (err) {
/* XXX or should we panic? */
device_printf(self, "Could not tear down irq, %d\n",
err);
}
sc->sc_intr_hdl = NULL;
}
if (sc->sc_irq_res) {
bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
sc->sc_irq_res = NULL;
}
if (sc->sc_io_res) {
bus_release_resource(self, SYS_RES_IOPORT, PCI_UHCI_BASE_REG,
sc->sc_io_res);
sc->sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_config_td);
usb2_bus_mem_free_all(&sc->sc_bus, &uhci_iterate_hw_softc);
return (0);
}
static driver_t uhci_driver =
{
.name = "uhci",
.methods = (device_method_t[]){
/* device interface */
DEVMETHOD(device_probe, uhci_pci_probe),
DEVMETHOD(device_attach, uhci_pci_attach),
DEVMETHOD(device_detach, uhci_pci_detach),
DEVMETHOD(device_suspend, uhci_pci_suspend),
DEVMETHOD(device_resume, uhci_pci_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
},
.size = sizeof(struct uhci_softc),
};
static devclass_t uhci_devclass;
DRIVER_MODULE(uhci, pci, uhci_driver, uhci_devclass, 0, 0);
DRIVER_MODULE(uhci, cardbus, uhci_driver, uhci_devclass, 0, 0);
MODULE_DEPEND(uhci, usb2_controller, 1, 1, 1);
MODULE_DEPEND(uhci, usb2_core, 1, 1, 1);

View File

@ -0,0 +1,88 @@
/* $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.
*/
#ifndef _USB2_BUS_H_
#define _USB2_BUS_H_
/*
* The following structure defines the USB explore message sent to the
* USB explore process.
*/
struct usb2_bus_msg {
struct usb2_proc_msg hdr;
struct usb2_bus *bus;
};
/*
* The following structure defines the USB statistics structure.
*/
struct usb2_bus_stat {
uint32_t uds_requests[4];
};
/*
* The following structure defines an USB BUS. There is one USB BUS
* for every Host or Device controller.
*/
struct usb2_bus {
struct usb2_bus_stat stats_err;
struct usb2_bus_stat stats_ok;
struct usb2_process explore_proc;
struct usb2_bus_msg explore_msg[2];
struct usb2_bus_msg detach_msg[2];
struct mtx mtx; /* This mutex protects the USB
* hardware */
struct usb2_perm perm;
struct usb2_xfer_queue intr_q;
device_t bdev; /* filled by HC driver */
struct usb2_dma_parent_tag dma_parent_tag[1];
struct usb2_dma_tag dma_tags[USB_BUS_DMA_TAG_MAX];
struct usb2_bus_methods *methods; /* filled by HC driver */
struct usb2_device *devices[USB_MAX_DEVICES];
uint32_t uframe_usage[USB_HS_MICRO_FRAMES_MAX];
uint32_t transfer_count[4];
uint16_t isoc_time_last; /* in milliseconds */
uint8_t alloc_failed; /* Set if memory allocation failed. */
uint8_t driver_added_refcount; /* Current driver generation count */
uint8_t usbrev; /* USB revision. See "USB_REV_XXX". */
uint8_t devices_max; /* maximum number of USB devices */
uint8_t do_probe; /* set if USB BUS should be re-probed */
union {
struct usb2_hw_ep_scratch hw_ep_scratch[1];
struct usb2_temp_setup temp_setup[1];
uint8_t data[128];
} scratch[1];
};
#endif /* _USB2_BUS_H_ */

View File

@ -0,0 +1,477 @@
/* $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 <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_standard.h>
#define USB_DEBUG_VAR usb2_ctrl_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_dynamic.h>
#include <dev/usb2/core/usb2_device.h>
#include <dev/usb2/core/usb2_hub.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
/* function prototypes */
static device_probe_t usb2_probe;
static device_attach_t usb2_attach;
static device_detach_t usb2_detach;
static void usb2_attach_sub(device_t dev, struct usb2_bus *bus);
static void usb2_post_init(void *arg);
static void usb2_bus_mem_flush_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc, struct usb2_page *pg, uint32_t size, uint32_t align);
static void usb2_bus_mem_alloc_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc, struct usb2_page *pg, uint32_t size, uint32_t align);
static void usb2_bus_mem_free_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc, struct usb2_page *pg, uint32_t size, uint32_t align);
/* static variables */
#if USB_DEBUG
static int usb2_ctrl_debug = 0;
SYSCTL_NODE(_hw_usb2, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller");
SYSCTL_INT(_hw_usb2_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb2_ctrl_debug, 0,
"Debug level");
#endif
static uint8_t usb2_post_init_called = 0;
static devclass_t usb2_devclass;
static device_method_t usb2_methods[] = {
DEVMETHOD(device_probe, usb2_probe),
DEVMETHOD(device_attach, usb2_attach),
DEVMETHOD(device_detach, usb2_detach),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
{0, 0}
};
static driver_t usb2_driver = {
.name = "usbus",
.methods = usb2_methods,
.size = 0,
};
DRIVER_MODULE(usbus, ohci, usb2_driver, usb2_devclass, 0, 0);
DRIVER_MODULE(usbus, uhci, usb2_driver, usb2_devclass, 0, 0);
DRIVER_MODULE(usbus, ehci, usb2_driver, usb2_devclass, 0, 0);
DRIVER_MODULE(usbus, at91_udp, usb2_driver, usb2_devclass, 0, 0);
DRIVER_MODULE(usbus, uss820, usb2_driver, usb2_devclass, 0, 0);
MODULE_DEPEND(usb2_controller, usb2_core, 1, 1, 1);
MODULE_VERSION(usb2_controller, 1);
/*------------------------------------------------------------------------*
* usb2_probe
*
* This function is called from "{ehci,ohci,uhci}_pci_attach()".
*------------------------------------------------------------------------*/
static int
usb2_probe(device_t dev)
{
DPRINTF("\n");
return (0);
}
/*------------------------------------------------------------------------*
* usb2_attach
*------------------------------------------------------------------------*/
static int
usb2_attach(device_t dev)
{
struct usb2_bus *bus = device_get_ivars(dev);
DPRINTF("\n");
if (bus == NULL) {
DPRINTFN(0, "USB device has no ivars\n");
return (ENXIO);
}
if (usb2_post_init_called) {
mtx_lock(&Giant);
usb2_attach_sub(dev, bus);
mtx_unlock(&Giant);
usb2_needs_explore(bus, 1);
}
return (0); /* return success */
}
/*------------------------------------------------------------------------*
* usb2_detach
*------------------------------------------------------------------------*/
static int
usb2_detach(device_t dev)
{
struct usb2_bus *bus = device_get_softc(dev);
DPRINTF("\n");
if (bus == NULL) {
/* was never setup properly */
return (0);
}
/* Let the USB explore process detach all devices. */
mtx_lock(&bus->mtx);
if (usb2_proc_msignal(&bus->explore_proc,
&bus->detach_msg[0], &bus->detach_msg[1])) {
/* ignore */
}
/* Wait for detach to complete */
usb2_proc_mwait(&bus->explore_proc,
&bus->detach_msg[0], &bus->detach_msg[1]);
mtx_unlock(&bus->mtx);
/* Get rid of USB explore process */
usb2_proc_unsetup(&bus->explore_proc);
return (0);
}
/*------------------------------------------------------------------------*
* usb2_bus_explore
*
* This function is used to explore the device tree from the root.
*------------------------------------------------------------------------*/
static void
usb2_bus_explore(struct usb2_proc_msg *pm)
{
struct usb2_bus *bus;
struct usb2_device *udev;
bus = ((struct usb2_bus_msg *)pm)->bus;
udev = bus->devices[USB_ROOT_HUB_ADDR];
if (udev && udev->hub) {
if (bus->do_probe) {
bus->do_probe = 0;
bus->driver_added_refcount++;
}
if (bus->driver_added_refcount == 0) {
/* avoid zero, hence that is memory default */
bus->driver_added_refcount = 1;
}
mtx_unlock(&bus->mtx);
mtx_lock(&Giant);
/*
* Explore the Root USB HUB. This call can sleep,
* exiting Giant, which is actually Giant.
*/
(udev->hub->explore) (udev);
mtx_unlock(&Giant);
mtx_lock(&bus->mtx);
}
return;
}
/*------------------------------------------------------------------------*
* usb2_bus_detach
*
* This function is used to detach the device tree from the root.
*------------------------------------------------------------------------*/
static void
usb2_bus_detach(struct usb2_proc_msg *pm)
{
struct usb2_bus *bus;
struct usb2_device *udev;
device_t dev;
bus = ((struct usb2_bus_msg *)pm)->bus;
udev = bus->devices[USB_ROOT_HUB_ADDR];
dev = bus->bdev;
/* clear the softc */
device_set_softc(dev, NULL);
mtx_unlock(&bus->mtx);
mtx_lock(&Giant);
/* detach children first */
bus_generic_detach(dev);
/*
* Free USB Root device, but not any sub-devices, hence they
* are freed by the caller of this function:
*/
usb2_detach_device(udev, USB_IFACE_INDEX_ANY, 0);
usb2_free_device(udev);
mtx_unlock(&Giant);
mtx_lock(&bus->mtx);
/* clear bdev variable last */
bus->bdev = NULL;
return;
}
/*------------------------------------------------------------------------*
* usb2_attach_sub
*
* This function is the real USB bus attach code. It is factored out,
* hence it can be called at two different places in time. During
* bootup this function is called from "usb2_post_init". During
* hot-plug it is called directly from the "usb2_attach()" method.
*------------------------------------------------------------------------*/
static void
usb2_attach_sub(device_t dev, struct usb2_bus *bus)
{
struct usb2_device *child;
usb2_error_t err;
uint8_t speed;
DPRINTF("\n");
mtx_assert(&Giant, MA_OWNED);
switch (bus->usbrev) {
case USB_REV_1_0:
speed = USB_SPEED_FULL;
device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n");
break;
case USB_REV_1_1:
speed = USB_SPEED_FULL;
device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n");
break;
case USB_REV_2_0:
speed = USB_SPEED_HIGH;
device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n");
break;
case USB_REV_2_5:
speed = USB_SPEED_VARIABLE;
device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n");
break;
default:
device_printf(bus->bdev, "Unsupported USB revision!\n");
return;
}
/* Allocate the Root USB device */
child = usb2_alloc_device(bus->bdev, bus, NULL, 0, 0, 1,
speed, USB_MODE_HOST);
if (child) {
err = usb2_probe_and_attach(child,
USB_IFACE_INDEX_ANY);
if (!err) {
if (!bus->devices[USB_ROOT_HUB_ADDR]->hub) {
err = USB_ERR_NO_ROOT_HUB;
}
}
} else {
err = USB_ERR_NOMEM;
}
if (err) {
device_printf(bus->bdev, "Root HUB problem, error=%s\n",
usb2_errstr(err));
}
/* Initialise USB process messages */
bus->explore_msg[0].hdr.pm_callback = &usb2_bus_explore;
bus->explore_msg[0].bus = bus;
bus->explore_msg[1].hdr.pm_callback = &usb2_bus_explore;
bus->explore_msg[1].bus = bus;
bus->detach_msg[0].hdr.pm_callback = &usb2_bus_detach;
bus->detach_msg[0].bus = bus;
bus->detach_msg[1].hdr.pm_callback = &usb2_bus_detach;
bus->detach_msg[1].bus = bus;
/* Create a new USB process */
if (usb2_proc_setup(&bus->explore_proc,
&bus->mtx, USB_PRI_MED)) {
printf("WARNING: Creation of USB explore process failed.\n");
}
/* set softc - we are ready */
device_set_softc(dev, bus);
return;
}
/*------------------------------------------------------------------------*
* usb2_post_init
*
* This function is called to attach all USB busses that were found
* during bootup.
*------------------------------------------------------------------------*/
static void
usb2_post_init(void *arg)
{
struct usb2_bus *bus;
devclass_t dc;
device_t dev;
int max;
int n;
mtx_lock(&Giant);
usb2_devclass_ptr = devclass_find("usbus");
dc = usb2_devclass_ptr;
if (dc) {
max = devclass_get_maxunit(dc) + 1;
for (n = 0; n != max; n++) {
dev = devclass_get_device(dc, n);
if (dev && device_is_attached(dev)) {
bus = device_get_ivars(dev);
if (bus) {
mtx_lock(&Giant);
usb2_attach_sub(dev, bus);
mtx_unlock(&Giant);
}
}
}
} else {
DPRINTFN(0, "no devclass\n");
}
usb2_post_init_called = 1;
/* explore all USB busses in parallell */
usb2_needs_explore_all();
mtx_unlock(&Giant);
return;
}
SYSINIT(usb2_post_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, usb2_post_init, NULL);
SYSUNINIT(usb2_bus_unload, SI_SUB_KLD, SI_ORDER_ANY, usb2_bus_unload, NULL);
/*------------------------------------------------------------------------*
* usb2_bus_mem_flush_all_cb
*------------------------------------------------------------------------*/
static void
usb2_bus_mem_flush_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc,
struct usb2_page *pg, uint32_t size, uint32_t align)
{
usb2_pc_cpu_flush(pc);
return;
}
/*------------------------------------------------------------------------*
* usb2_bus_mem_flush_all - factored out code
*------------------------------------------------------------------------*/
void
usb2_bus_mem_flush_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb)
{
if (cb) {
cb(bus, &usb2_bus_mem_flush_all_cb);
}
return;
}
/*------------------------------------------------------------------------*
* usb2_bus_mem_alloc_all_cb
*------------------------------------------------------------------------*/
static void
usb2_bus_mem_alloc_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc,
struct usb2_page *pg, uint32_t size, uint32_t align)
{
/* need to initialize the page cache */
pc->tag_parent = bus->dma_parent_tag;
if (usb2_pc_alloc_mem(pc, pg, size, align)) {
bus->alloc_failed = 1;
}
return;
}
/*------------------------------------------------------------------------*
* usb2_bus_mem_alloc_all - factored out code
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
uint8_t
usb2_bus_mem_alloc_all(struct usb2_bus *bus, bus_dma_tag_t dmat,
usb2_bus_mem_cb_t *cb)
{
bus->alloc_failed = 0;
bus->devices_max = USB_MAX_DEVICES;
mtx_init(&bus->mtx, "USB lock",
NULL, MTX_DEF | MTX_RECURSE);
TAILQ_INIT(&bus->intr_q.head);
usb2_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags,
dmat, &bus->mtx, NULL, NULL, 32, USB_BUS_DMA_TAG_MAX);
if (cb) {
cb(bus, &usb2_bus_mem_alloc_all_cb);
}
if (bus->alloc_failed) {
usb2_bus_mem_free_all(bus, cb);
}
return (bus->alloc_failed);
}
/*------------------------------------------------------------------------*
* usb2_bus_mem_free_all_cb
*------------------------------------------------------------------------*/
static void
usb2_bus_mem_free_all_cb(struct usb2_bus *bus, struct usb2_page_cache *pc,
struct usb2_page *pg, uint32_t size, uint32_t align)
{
usb2_pc_free_mem(pc);
return;
}
/*------------------------------------------------------------------------*
* usb2_bus_mem_free_all - factored out code
*------------------------------------------------------------------------*/
void
usb2_bus_mem_free_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb)
{
if (cb) {
cb(bus, &usb2_bus_mem_free_all_cb);
}
usb2_dma_tag_unsetup(bus->dma_parent_tag);
mtx_destroy(&bus->mtx);
return;
}

View File

@ -0,0 +1,172 @@
/* $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.
*/
#ifndef _USB2_CONTROLLER_H_
#define _USB2_CONTROLLER_H_
/* defines */
#define USB_BUS_DMA_TAG_MAX 8
/* structure prototypes */
struct usb2_bus;
struct usb2_page;
struct usb2_pipe;
struct usb2_page_cache;
struct usb2_setup_params;
struct usb2_hw_ep_profile;
struct usb2_fs_isoc_schedule;
struct usb2_config_descriptor;
struct usb2_endpoint_descriptor;
/* typedefs */
typedef void (usb2_bus_mem_sub_cb_t)(struct usb2_bus *bus, struct usb2_page_cache *pc, struct usb2_page *pg, uint32_t size, uint32_t align);
typedef void (usb2_bus_mem_cb_t)(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *scb);
/*
* The following structure is used to define all the USB BUS
* callbacks.
*/
struct usb2_bus_methods {
/* USB Device and Host mode - Mandatory */
void (*pipe_init) (struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, struct usb2_pipe *pipe);
void (*do_poll) (struct usb2_bus *);
void (*xfer_setup) (struct usb2_setup_params *parm);
void (*xfer_unsetup) (struct usb2_xfer *xfer);
void (*get_dma_delay) (struct usb2_bus *, uint32_t *pdelay);
/* USB Device mode only - Mandatory */
void (*get_hw_ep_profile) (struct usb2_device *udev, const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr);
void (*set_stall) (struct usb2_device *udev, struct usb2_xfer *xfer, struct usb2_pipe *pipe);
void (*clear_stall) (struct usb2_device *udev, struct usb2_pipe *pipe);
void (*rem_wakeup_set) (struct usb2_device *udev, uint8_t is_on);
/* USB Device mode only - Optional */
void (*vbus_interrupt) (struct usb2_bus *, uint8_t is_on);
};
/*
* The following structure is used to define all the USB pipe
* callbacks.
*/
struct usb2_pipe_methods {
/* Mandatory USB Device and Host mode callbacks: */
void (*open) (struct usb2_xfer *xfer);
void (*close) (struct usb2_xfer *xfer);
void (*enter) (struct usb2_xfer *xfer);
void (*start) (struct usb2_xfer *xfer);
/* Optional */
uint8_t (*isdone) (struct usb2_xfer *xfer);
void *info;
/* Flags */
uint8_t enter_is_cancelable:1;
uint8_t start_is_cancelable:1;
};
/*
* The following structure keeps information about what a hardware USB
* endpoint supports.
*/
struct usb2_hw_ep_profile {
uint16_t max_in_frame_size; /* IN-token direction */
uint16_t max_out_frame_size; /* OUT-token direction */
uint8_t is_simplex:1;
uint8_t support_multi_buffer:1;
uint8_t support_bulk:1;
uint8_t support_control:1;
uint8_t support_interrupt:1;
uint8_t support_isochronous:1;
uint8_t support_in:1; /* IN-token is supported */
uint8_t support_out:1; /* OUT-token is supported */
};
/*
* The following structure is used when trying to allocate hardware
* endpoints for an USB configuration in USB device side mode.
*/
struct usb2_hw_ep_scratch_sub {
const struct usb2_hw_ep_profile *pf;
uint16_t max_frame_size;
uint8_t hw_endpoint_out;
uint8_t hw_endpoint_in;
uint8_t needs_ep_type;
uint8_t needs_in:1;
uint8_t needs_out:1;
};
/*
* The following structure is used when trying to allocate hardware
* endpoints for an USB configuration in USB device side mode.
*/
struct usb2_hw_ep_scratch {
struct usb2_hw_ep_scratch_sub ep[USB_EP_MAX];
struct usb2_hw_ep_scratch_sub *ep_max;
struct usb2_config_descriptor *cd;
struct usb2_device *udev;
struct usb2_bus_methods *methods;
uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16];
uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16];
};
/*
* The following structure is used when generating USB descriptors
* from USB templates.
*/
struct usb2_temp_setup {
void *buf;
uint32_t size;
uint8_t usb2_speed;
uint8_t self_powered;
uint8_t bNumEndpoints;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bConfigurationValue;
usb2_error_t err;
};
/* prototypes */
void usb2_bus_mem_flush_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb);
uint8_t usb2_bus_mem_alloc_all(struct usb2_bus *bus, bus_dma_tag_t dmat, usb2_bus_mem_cb_t *cb);
void usb2_bus_mem_free_all(struct usb2_bus *bus, usb2_bus_mem_cb_t *cb);
uint16_t usb2_isoc_time_expand(struct usb2_bus *bus, uint16_t isoc_time_curr);
uint16_t usb2_fs_isoc_schedule_isoc_time_expand(struct usb2_device *udev, struct usb2_fs_isoc_schedule **pp_start, struct usb2_fs_isoc_schedule **pp_end, uint16_t isoc_time);
uint8_t usb2_fs_isoc_schedule_alloc(struct usb2_fs_isoc_schedule *fss, uint8_t *pstart, uint16_t len);
#endif /* _USB2_CONTROLLER_H_ */

View File

@ -0,0 +1,39 @@
/* $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.
*/
#ifndef _USB2_PCI_H_
#define _USB2_PCI_H_
/*
* We don't want the following files included everywhere, that's why
* they are in a separate file.
*/
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <sys/rman.h>
#endif /* _USB2_PCI_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,375 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2007 Hans Petter Selasky <hselasky@freebsd.org>
* 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.
*/
#ifndef _USS820_DCI_H_
#define _USS820_DCI_H_
#define USS820_EP_MAX 8 /* maximum number of endpoints */
#define USS820_TXDAT 0x00 /* Transmit FIFO data */
#define USS820_TXCNTL 0x01 /* Transmit FIFO byte count low */
#define USS820_TXCNTL_MASK 0xFF
#define USS820_TXCNTH 0x02 /* Transmit FIFO byte count high */
#define USS820_TXCNTH_MASK 0x03
#define USS820_TXCNTH_UNUSED 0xFC
#define USS820_TXCON 0x03 /* USB transmit FIFO control */
#define USS820_TXCON_REVRP 0x01
#define USS820_TXCON_ADVRM 0x02
#define USS820_TXCON_ATM 0x04 /* Automatic Transmit Management */
#define USS820_TXCON_TXISO 0x08 /* Transmit Isochronous Data */
#define USS820_TXCON_UNUSED 0x10
#define USS820_TXCON_FFSZ_16_64 0x00
#define USS820_TXCON_FFSZ_64_256 0x20
#define USS820_TXCON_FFSZ_8_512 0x40
#define USS820_TXCON_FFSZ_32_1024 0x60
#define USS820_TXCON_FFSZ_MASK 0x60
#define USS820_TXCON_TXCLR 0x80 /* Transmit FIFO clear */
#define USS820_TXFLG 0x04 /* Transmit FIFO flag (Read Only) */
#define USS820_TXFLG_TXOVF 0x01 /* TX overrun */
#define USS820_TXFLG_TXURF 0x02 /* TX underrun */
#define USS820_TXFLG_TXFULL 0x04 /* TX full */
#define USS820_TXFLG_TXEMP 0x08 /* TX empty */
#define USS820_TXFLG_UNUSED 0x30
#define USS820_TXFLG_TXFIF0 0x40
#define USS820_TXFLG_TXFIF1 0x80
#define USS820_RXDAT 0x05 /* Receive FIFO data */
#define USS820_RXCNTL 0x06 /* Receive FIFO byte count low */
#define USS820_RXCNTL_MASK 0xFF
#define USS820_RXCNTH 0x07 /* Receive FIFO byte count high */
#define USS820_RXCNTH_MASK 0x03
#define USS820_RXCNTH_UNUSED 0xFC
#define USS820_RXCON 0x08 /* Receive FIFO control */
#define USS820_RXCON_REVWP 0x01
#define USS820_RXCON_ADVWM 0x02
#define USS820_RXCON_ARM 0x04 /* Auto Receive Management */
#define USS820_RXCON_RXISO 0x08 /* Receive Isochronous Data */
#define USS820_RXCON_RXFFRC 0x10 /* FIFO Read Complete */
#define USS820_RXCON_FFSZ_16_64 0x00
#define USS820_RXCON_FFSZ_64_256 0x20
#define USS820_RXCON_FFSZ_8_512 0x40
#define USS820_RXCON_FFSZ_32_1024 0x60
#define USS820_RXCON_RXCLR 0x80 /* Receive FIFO clear */
#define USS820_RXFLG 0x09 /* Receive FIFO flag (Read Only) */
#define USS820_RXFLG_RXOVF 0x01 /* RX overflow */
#define USS820_RXFLG_RXURF 0x02 /* RX underflow */
#define USS820_RXFLG_RXFULL 0x04 /* RX full */
#define USS820_RXFLG_RXEMP 0x08 /* RX empty */
#define USS820_RXFLG_RXFLUSH 0x10 /* RX flush */
#define USS820_RXFLG_UNUSED 0x20
#define USS820_RXFLG_RXFIF0 0x40
#define USS820_RXFLG_RXFIF1 0x80
#define USS820_EPINDEX 0x0a /* Endpoint index selection */
#define USS820_EPINDEX_MASK 0x07
#define USS820_EPINDEX_UNUSED 0xF8
#define USS820_EPCON 0x0b /* Endpoint control */
#define USS820_EPCON_TXEPEN 0x01 /* Transmit Endpoint Enable */
#define USS820_EPCON_TXOE 0x02 /* Transmit Output Enable */
#define USS820_EPCON_RXEPEN 0x04 /* Receive Endpoint Enable */
#define USS820_EPCON_RXIE 0x08 /* Receive Input Enable */
#define USS820_EPCON_RXSPM 0x10 /* Receive Single-Packet Mode */
#define USS820_EPCON_CTLEP 0x20 /* Control Endpoint */
#define USS820_EPCON_TXSTL 0x40 /* Stall Transmit Endpoint */
#define USS820_EPCON_RXSTL 0x80 /* Stall Receive Endpoint */
#define USS820_TXSTAT 0x0c /* Transmit status */
#define USS820_TXSTAT_TXACK 0x01 /* Transmit Acknowledge */
#define USS820_TXSTAT_TXERR 0x02 /* Transmit Error */
#define USS820_TXSTAT_TXVOID 0x04 /* Transmit Void */
#define USS820_TXSTAT_TXSOVW 0x08 /* Transmit Data Sequence Overwrite
* Bit */
#define USS820_TXSTAT_TXFLUSH 0x10 /* Transmit FIFO Packet Flushed */
#define USS820_TXSTAT_TXNAKE 0x20 /* Transmit NAK Mode Enable */
#define USS820_TXSTAT_TXDSAM 0x40 /* Transmit Data-Set-Available Mode */
#define USS820_TXSTAT_TXSEQ 0x80 /* Transmitter Current Sequence Bit */
#define USS820_RXSTAT 0x0d /* Receive status */
#define USS820_RXSTAT_RXACK 0x01 /* Receive Acknowledge */
#define USS820_RXSTAT_RXERR 0x02 /* Receive Error */
#define USS820_RXSTAT_RXVOID 0x04 /* Receive Void */
#define USS820_RXSTAT_RXSOVW 0x08 /* Receive Data Sequence Overwrite Bit */
#define USS820_RXSTAT_EDOVW 0x10 /* End Overwrite Flag */
#define USS820_RXSTAT_STOVW 0x20 /* Start Overwrite Flag */
#define USS820_RXSTAT_RXSETUP 0x40 /* Received SETUP token */
#define USS820_RXSTAT_RXSEQ 0x80 /* Receiver Endpoint Sequence Bit */
#define USS820_SOFL 0x0e /* Start Of Frame counter low */
#define USS820_SOFL_MASK 0xFF
#define USS820_SOFH 0x0f /* Start Of Frame counter high */
#define USS820_SOFH_MASK 0x07
#define USS820_SOFH_SOFDIS 0x08 /* SOF Pin Output Disable */
#define USS820_SOFH_FTLOCK 0x10 /* Frame Timer Lock */
#define USS820_SOFH_SOFIE 0x20 /* SOF Interrupt Enable */
#define USS820_SOFH_ASOF 0x40 /* Any Start of Frame */
#define USS820_SOFH_SOFACK 0x80 /* SOF Token Received Without Error */
#define USS820_FADDR 0x10 /* Function Address */
#define USS820_FADDR_MASK 0x7F
#define USS820_FADDR_UNUSED 0x80
#define USS820_SCR 0x11 /* System Control */
#define USS820_SCR_UNUSED 0x01
#define USS820_SCR_T_IRQ 0x02 /* Global Interrupt Enable */
#define USS820_SCR_IRQLVL 0x04 /* Interrupt Mode */
#define USS820_SCR_SRESET 0x08 /* Software reset */
#define USS820_SCR_IE_RESET 0x10 /* Enable Reset Interrupt */
#define USS820_SCR_IE_SUSP 0x20 /* Enable Suspend Interrupt */
#define USS820_SCR_RWUPE 0x40 /* Enable Remote Wake-Up Feature */
#define USS820_SCR_IRQPOL 0x80 /* IRQ polarity */
#define USS820_SSR 0x12 /* System Status */
#define USS820_SSR_RESET 0x01 /* Reset Condition Detected on USB
* cable */
#define USS820_SSR_SUSPEND 0x02 /* Suspend Detected */
#define USS820_SSR_RESUME 0x04 /* Resume Detected */
#define USS820_SSR_SUSPDIS 0x08 /* Suspend Disable */
#define USS820_SSR_SUSPPO 0x10 /* Suspend Power Off */
#define USS820_SSR_UNUSED 0xE0
#define USS820_UNK0 0x13 /* Unknown */
#define USS820_UNK0_UNUSED 0xFF
#define USS820_SBI 0x14 /* Serial bus interrupt low */
#define USS820_SBI_FTXD0 0x01 /* Function Transmit Done, EP 0 */
#define USS820_SBI_FRXD0 0x02 /* Function Receive Done, EP 0 */
#define USS820_SBI_FTXD1 0x04
#define USS820_SBI_FRXD1 0x08
#define USS820_SBI_FTXD2 0x10
#define USS820_SBI_FRXD2 0x20
#define USS820_SBI_FTXD3 0x40
#define USS820_SBI_FRXD3 0x80
#define USS820_SBI1 0x15 /* Serial bus interrupt high */
#define USS820_SBI1_FTXD4 0x01
#define USS820_SBI1_FRXD4 0x02
#define USS820_SBI1_FTXD5 0x04
#define USS820_SBI1_FRXD5 0x08
#define USS820_SBI1_FTXD6 0x10
#define USS820_SBI1_FRXD6 0x20
#define USS820_SBI1_FTXD7 0x40
#define USS820_SBI1_FRXD7 0x80
#define USS820_SBIE 0x16 /* Serial bus interrupt enable low */
#define USS820_SBIE_FTXIE0 0x01
#define USS820_SBIE_FRXIE0 0x02
#define USS820_SBIE_FTXIE1 0x04
#define USS820_SBIE_FRXIE1 0x08
#define USS820_SBIE_FTXIE2 0x10
#define USS820_SBIE_FRXIE2 0x20
#define USS820_SBIE_FTXIE3 0x40
#define USS820_SBIE_FRXIE3 0x80
#define USS820_SBIE1 0x17 /* Serial bus interrupt enable high */
#define USS820_SBIE1_FTXIE4 0x01
#define USS820_SBIE1_FRXIE4 0x02
#define USS820_SBIE1_FTXIE5 0x04
#define USS820_SBIE1_FRXIE5 0x08
#define USS820_SBIE1_FTXIE6 0x10
#define USS820_SBIE1_FRXIE6 0x20
#define USS820_SBIE1_FTXIE7 0x40
#define USS820_SBIE1_FRXIE7 0x80
#define USS820_REV 0x18 /* Hardware revision */
#define USS820_REV_MIN 0x0F
#define USS820_REV_MAJ 0xF0
#define USS820_LOCK 0x19 /* Suspend power-off locking */
#define USS820_LOCK_UNLOCKED 0x01
#define USS820_LOCK_UNUSED 0xFE
#define USS820_PEND 0x1a /* Pend hardware status update */
#define USS820_PEND_PEND 0x01
#define USS820_PEND_UNUSED 0xFE
#define USS820_SCRATCH 0x1b /* Scratch firmware information */
#define USS820_SCRATCH_MASK 0x7F
#define USS820_SCRATCH_IE_RESUME 0x80 /* Enable Resume Interrupt */
#define USS820_MCSR 0x1c /* Miscellaneous control and status */
#define USS820_MCSR_DPEN 0x01 /* DPLS Pull-Up Enable */
#define USS820_MCSR_SUSPLOE 0x02 /* Suspend Lock Out Enable */
#define USS820_MCSR_BDFEAT 0x04 /* Board Feature Enable */
#define USS820_MCSR_FEAT 0x08 /* Feature Enable */
#define USS820_MCSR_PKGID 0x10 /* Package Identification */
#define USS820_MCSR_SUSPS 0x20 /* Suspend Status */
#define USS820_MCSR_INIT 0x40 /* Device Initialized */
#define USS820_MCSR_RWUPR 0x80 /* Remote Wakeup-Up Remember */
#define USS820_DSAV 0x1d /* Data set available low (Read Only) */
#define USS820_DSAV_TXAV0 0x01
#define USS820_DSAV_RXAV0 0x02
#define USS820_DSAV_TXAV1 0x04
#define USS820_DSAV_RXAV1 0x08
#define USS820_DSAV_TXAV2 0x10
#define USS820_DSAV_RXAV2 0x20
#define USS820_DSAV_TXAV3 0x40
#define USS820_DSAV_RXAV3 0x80
#define USS820_DSAV1 0x1e /* Data set available high */
#define USS820_DSAV1_TXAV4 0x01
#define USS820_DSAV1_RXAV4 0x02
#define USS820_DSAV1_TXAV5 0x04
#define USS820_DSAV1_RXAV5 0x08
#define USS820_DSAV1_TXAV6 0x10
#define USS820_DSAV1_RXAV6 0x20
#define USS820_DSAV1_TXAV7 0x40
#define USS820_DSAV1_RXAV7 0x80
#define USS820_UNK1 0x1f /* Unknown */
#define USS820_UNK1_UNKNOWN 0xFF
#define USS820_GET_REG(sc,reg) \
((reg) << (sc)->sc_reg_shift)
#define USS820_READ_1(sc, reg) \
bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \
USS820_GET_REG(sc,reg))
#define USS820_WRITE_1(sc, reg, data) \
bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \
USS820_GET_REG(sc,reg), data)
struct uss820dci_td;
typedef uint8_t (uss820dci_cmd_t)(struct uss820dci_td *td);
struct uss820dci_td {
bus_space_tag_t io_tag;
bus_space_handle_t io_hdl;
struct uss820dci_td *obj_next;
uss820dci_cmd_t *func;
struct usb2_page_cache *pc;
uint32_t offset;
uint32_t remainder;
uint16_t max_packet_size;
uint8_t rx_stat_reg;
uint8_t tx_stat_reg;
uint8_t rx_flag_reg;
uint8_t tx_flag_reg;
uint8_t rx_fifo_reg;
uint8_t tx_fifo_reg;
uint8_t rx_count_low_reg;
uint8_t rx_count_high_reg;
uint8_t tx_count_low_reg;
uint8_t tx_count_high_reg;
uint8_t rx_cntl_reg;
uint8_t tx_cntl_reg;
uint8_t ep_reg;
uint8_t pend_reg;
uint8_t ep_index;
uint8_t error:1;
uint8_t alt_next:1;
uint8_t short_pkt:1;
uint8_t support_multi_buffer:1;
uint8_t did_stall:1;
};
struct uss820_std_temp {
uss820dci_cmd_t *func;
struct usb2_page_cache *pc;
struct uss820dci_td *td;
struct uss820dci_td *td_next;
uint32_t len;
uint32_t offset;
uint16_t max_frame_size;
uint8_t short_pkt;
/*
* short_pkt = 0: transfer should be short terminated
* short_pkt = 1: transfer should not be short terminated
*/
uint8_t setup_alt_next;
};
struct uss820dci_config_desc {
struct usb2_config_descriptor confd;
struct usb2_interface_descriptor ifcd;
struct usb2_endpoint_descriptor endpd;
} __packed;
union uss820_hub_temp {
uWord wValue;
struct usb2_port_status ps;
};
struct uss820_flags {
uint8_t change_connect:1;
uint8_t change_suspend:1;
uint8_t status_suspend:1; /* set if suspended */
uint8_t status_vbus:1; /* set if present */
uint8_t status_bus_reset:1; /* set if reset complete */
uint8_t clocks_off:1;
uint8_t port_powered:1;
uint8_t port_enabled:1;
uint8_t d_pulled_up:1;
uint8_t mcsr_feat:1;
};
struct uss820dci_softc {
struct usb2_bus sc_bus;
union uss820_hub_temp sc_hub_temp;
LIST_HEAD(, usb2_xfer) sc_interrupt_list_head;
struct usb2_sw_transfer sc_root_ctrl;
struct usb2_sw_transfer sc_root_intr;
struct usb2_config_td sc_config_td;
struct resource *sc_io_res;
struct resource *sc_irq_res;
void *sc_intr_hdl;
bus_size_t sc_io_size;
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
uint8_t sc_rt_addr; /* root HUB address */
uint8_t sc_dv_addr; /* device address */
uint8_t sc_conf; /* root HUB config */
uint8_t sc_reg_shift;
uint8_t sc_hub_idata[1];
struct uss820_flags sc_flags;
};
/* prototypes */
usb2_error_t uss820dci_init(struct uss820dci_softc *sc);
void uss820dci_uninit(struct uss820dci_softc *sc);
void uss820dci_suspend(struct uss820dci_softc *sc);
void uss820dci_resume(struct uss820dci_softc *sc);
void uss820dci_interrupt(struct uss820dci_softc *sc);
#endif /* _USS820_DCI_H_ */

View File

@ -0,0 +1,247 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*-
* Copyright (c) 2008 Hans Petter Selasky <hselasky@freebsd.org>
* 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 <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/uss820dci.h>
#include <sys/rman.h>
static device_probe_t uss820_atmelarm_probe;
static device_attach_t uss820_atmelarm_attach;
static device_detach_t uss820_atmelarm_detach;
static device_suspend_t uss820_atmelarm_suspend;
static device_resume_t uss820_atmelarm_resume;
static device_shutdown_t uss820_atmelarm_shutdown;
static device_method_t uss820dci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, uss820_atmelarm_probe),
DEVMETHOD(device_attach, uss820_atmelarm_attach),
DEVMETHOD(device_detach, uss820_atmelarm_detach),
DEVMETHOD(device_suspend, uss820_atmelarm_suspend),
DEVMETHOD(device_resume, uss820_atmelarm_resume),
DEVMETHOD(device_shutdown, uss820_atmelarm_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
};
static driver_t uss820dci_driver = {
.name = "uss820",
.methods = uss820dci_methods,
.size = sizeof(struct uss820dci_softc),
};
static devclass_t uss820dci_devclass;
DRIVER_MODULE(uss820, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0);
MODULE_DEPEND(uss820, usb2_controller, 1, 1, 1);
MODULE_DEPEND(uss820, usb2_core, 1, 1, 1);
static const char *const uss820_desc = "USS820 USB Device Controller";
static int
uss820_atmelarm_suspend(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
err = bus_generic_suspend(dev);
if (err == 0) {
uss820dci_suspend(sc);
}
return (err);
}
static int
uss820_atmelarm_resume(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
uss820dci_resume(sc);
err = bus_generic_resume(dev);
return (err);
}
static int
uss820_atmelarm_shutdown(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
err = bus_generic_shutdown(dev);
if (err)
return (err);
uss820dci_uninit(sc);
return (0);
}
static int
uss820_atmelarm_probe(device_t dev)
{
device_set_desc(dev, uss820_desc);
return (0); /* success */
}
static int
uss820_atmelarm_attach(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
int rid;
if (sc == NULL) {
return (ENXIO);
}
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_bus,
USB_GET_DMA_TAG(dev), NULL)) {
return (ENOMEM);
}
rid = 0;
sc->sc_io_res =
bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
if (!sc->sc_io_res) {
goto error;
}
sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
sc->sc_io_size = rman_get_size(sc->sc_io_res);
/* multiply all addresses by 4 */
sc->sc_reg_shift = 2;
rid = 0;
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_SHAREABLE | RF_ACTIVE);
if (sc->sc_irq_res == NULL) {
goto error;
}
sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
if (!(sc->sc_bus.bdev)) {
goto error;
}
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
err = usb2_config_td_setup(&sc->sc_config_td, sc,
&sc->sc_bus.mtx, NULL, 0, 4);
if (err) {
device_printf(dev, "could not setup config thread!\n");
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
#else
err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
#endif
if (err) {
sc->sc_intr_hdl = NULL;
goto error;
}
err = uss820dci_init(sc);
if (err) {
device_printf(dev, "Init failed\n");
goto error;
}
err = device_probe_and_attach(sc->sc_bus.bdev);
if (err) {
device_printf(dev, "USB probe and attach failed\n");
goto error;
}
return (0);
error:
uss820_atmelarm_detach(dev);
return (ENXIO);
}
static int
uss820_atmelarm_detach(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
device_t bdev;
int err;
if (sc->sc_bus.bdev) {
bdev = sc->sc_bus.bdev;
device_detach(bdev);
device_delete_child(dev, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(dev);
if (sc->sc_irq_res && sc->sc_intr_hdl) {
/*
* only call at91_udp_uninit() after at91_udp_init()
*/
uss820dci_uninit(sc);
err = bus_teardown_intr(dev, sc->sc_irq_res,
sc->sc_intr_hdl);
sc->sc_intr_hdl = NULL;
}
if (sc->sc_irq_res) {
bus_release_resource(dev, SYS_RES_IRQ, 0,
sc->sc_irq_res);
sc->sc_irq_res = NULL;
}
if (sc->sc_io_res) {
bus_release_resource(dev, SYS_RES_IOPORT, 0,
sc->sc_io_res);
sc->sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_config_td);
usb2_bus_mem_free_all(&sc->sc_bus, NULL);
return (0);
}

View File

@ -0,0 +1,266 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*-
* Copyright (c) 2008 Hans Petter Selasky <hselasky@freebsd.org>
* 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 <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_sw_transfer.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
#include <dev/usb2/controller/uss820dci.h>
#include <dev/pccard/pccardreg.h>
#include <dev/pccard/pccardvar.h>
#include <sys/rman.h>
static device_probe_t uss820_pccard_probe;
static device_attach_t uss820_pccard_attach;
static device_detach_t uss820_pccard_detach;
static device_suspend_t uss820_pccard_suspend;
static device_resume_t uss820_pccard_resume;
static device_shutdown_t uss820_pccard_shutdown;
static uint8_t uss820_pccard_lookup(device_t dev);
static device_method_t uss820dci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, uss820_pccard_probe),
DEVMETHOD(device_attach, uss820_pccard_attach),
DEVMETHOD(device_detach, uss820_pccard_detach),
DEVMETHOD(device_suspend, uss820_pccard_suspend),
DEVMETHOD(device_resume, uss820_pccard_resume),
DEVMETHOD(device_shutdown, uss820_pccard_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
{0, 0}
};
static driver_t uss820dci_driver = {
.name = "uss820",
.methods = uss820dci_methods,
.size = sizeof(struct uss820dci_softc),
};
static devclass_t uss820dci_devclass;
DRIVER_MODULE(uss820, pccard, uss820dci_driver, uss820dci_devclass, 0, 0);
MODULE_DEPEND(uss820, usb2_core, 1, 1, 1);
static const char *const uss820_desc = "USS820 USB Device Controller";
static int
uss820_pccard_suspend(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
err = bus_generic_suspend(dev);
if (err == 0) {
uss820dci_suspend(sc);
}
return (err);
}
static int
uss820_pccard_resume(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
uss820dci_resume(sc);
err = bus_generic_resume(dev);
return (err);
}
static int
uss820_pccard_shutdown(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
err = bus_generic_shutdown(dev);
if (err)
return (err);
uss820dci_uninit(sc);
return (0);
}
static uint8_t
uss820_pccard_lookup(device_t dev)
{
uint32_t prod;
uint32_t vend;
pccard_get_vendor(dev, &vend);
pccard_get_product(dev, &prod);
/* ID's will be added later */
return (0);
}
static int
uss820_pccard_probe(device_t dev)
{
if (uss820_pccard_lookup(dev)) {
device_set_desc(dev, uss820_desc);
return (0);
}
return (ENXIO);
}
static int
uss820_pccard_attach(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
int err;
int rid;
if (sc == NULL) {
return (ENXIO);
}
/* get all DMA memory */
if (usb2_bus_mem_alloc_all(&sc->sc_bus,
USB_GET_DMA_TAG(dev), NULL)) {
return (ENOMEM);
}
rid = 0;
sc->sc_io_res =
bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
if (!sc->sc_io_res) {
goto error;
}
sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
sc->sc_io_size = rman_get_size(sc->sc_io_res);
/* multiply all addresses by 4 */
sc->sc_reg_shift = 2;
rid = 0;
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_SHAREABLE | RF_ACTIVE);
if (sc->sc_irq_res == NULL) {
goto error;
}
sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
if (!(sc->sc_bus.bdev)) {
goto error;
}
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
err = usb2_config_td_setup(&sc->sc_config_td, sc,
&sc->sc_bus.mtx, NULL, 0, 4);
if (err) {
device_printf(dev, "could not setup config thread!\n");
goto error;
}
#if (__FreeBSD_version >= 700031)
err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
#else
err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
(void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
#endif
if (err) {
sc->sc_intr_hdl = NULL;
goto error;
}
err = uss820dci_init(sc);
if (err) {
device_printf(dev, "Init failed\n");
goto error;
}
err = device_probe_and_attach(sc->sc_bus.bdev);
if (err) {
device_printf(dev, "USB probe and attach failed\n");
goto error;
}
return (0);
error:
uss820_pccard_detach(dev);
return (ENXIO);
}
static int
uss820_pccard_detach(device_t dev)
{
struct uss820dci_softc *sc = device_get_softc(dev);
device_t bdev;
int err;
if (sc->sc_bus.bdev) {
bdev = sc->sc_bus.bdev;
device_detach(bdev);
device_delete_child(dev, bdev);
}
/* during module unload there are lots of children leftover */
device_delete_all_children(dev);
if (sc->sc_irq_res && sc->sc_intr_hdl) {
/*
* only call at91_udp_uninit() after at91_udp_init()
*/
uss820dci_uninit(sc);
err = bus_teardown_intr(dev, sc->sc_irq_res,
sc->sc_intr_hdl);
sc->sc_intr_hdl = NULL;
}
if (sc->sc_irq_res) {
bus_release_resource(dev, SYS_RES_IRQ, 0,
sc->sc_irq_res);
sc->sc_irq_res = NULL;
}
if (sc->sc_io_res) {
bus_release_resource(dev, SYS_RES_IOPORT, 0,
sc->sc_io_res);
sc->sc_io_res = NULL;
}
usb2_config_td_unsetup(&sc->sc_config_td);
usb2_bus_mem_free_all(&sc->sc_bus, NULL);
return (0);
}

View File

@ -0,0 +1,411 @@
$FreeBSD$
DESCRIPTION OF THE NEW USB API
The new USB 2.0 API consists of 5 functions. All transfer types are
managed using these functions. There is no longer need for separate
functions to setup INTERRUPT- and ISOCHRONOUS- transfers.
+--------------------------------------------------------------+
| |
| "usb2_transfer_setup" - This function will allocate all |
| necessary DMA memory and might |
| sleep! |
| |
| "usb2_transfer_unsetup" - This function will stop the USB |
| transfer, if it is currently |
| active, release all DMA |
| memory and might sleep! |
| |
| "usb2_transfer_start" - This function will start an USB |
| transfer, if not already started.|
| This function is always |
| non-blocking. ** |
| |
| "usb2_transfer_stop" - This function will stop an USB |
| transfer, if not already stopped.|
| The callback function will be |
| called before this function |
| returns. This function is always |
| non-blocking. ** |
| |
| "usb2_transfer_drain" - This function will stop an USB |
| transfer, if not already stopped |
| and wait for any additional |
| DMA load operations to complete. |
| Buffers that are loaded into DMA |
| using "usb2_set_frame_data" can |
| safely be freed after that |
| this function has returned. This |
| function can block the caller. |
| |
| ** These functions must be called with the private driver's |
| lock locked. |
| |
| NOTE: These USB API functions are NULL safe, with regard |
| to the USB transfer structure pointer. |
+--------------------------------------------------------------+
Reference: /sys/dev/usb2/core/usb2_transfer.c
/*
* A simple USB callback state-machine:
*
* +->-----------------------+
* | |
* +-<-+-------[tr_setup]--------+-<-+-<-[start/restart]
* | |
* | |
* | |
* +------>-[tr_transferred]---------+
* | |
* +--------->-[tr_error]------------+
*/
void
usb2_default_callback(struct usb2_xfer *xfer)
{
/*
* NOTE: it is not allowed to return
* before "USB_CHECK_STATUS()",
* even if the system is tearing down!
*/
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
/*
* Setup xfer->frlengths[], xfer->nframes
* and write data to xfer->frbuffers[], if any
*/
/**/
usb2_start_hardware(xfer);
return;
case USB_ST_TRANSFERRED:
/*
* Read data from xfer->frbuffers[], if any.
* "xfer->frlengths[]" should now have been
* updated to the actual length.
*/
return;
default: /* Error */
/* print error message and clear stall for example */
return;
}
}
=== Notes for USB control transfers ===
An USB control transfer has three parts. First the SETUP packet, then
DATA packet(s) and then a STATUS packet. The SETUP packet is always
pointed to by "xfer->frbuffers[0]" and the length is stored in
"xfer->frlengths[0]" also if there should not be sent any SETUP
packet! If an USB control transfer has no DATA stage, then
"xfer->nframes" should be set to 1. Else the default value is
"xfer->nframes" equal to 2.
Example1: SETUP + STATUS
xfer->nframes = 1;
xfer->frlenghts[0] = 8;
usb2_start_hardware(xfer);
Example2: SETUP + DATA + STATUS
xfer->nframes = 2;
xfer->frlenghts[0] = 8;
xfer->frlenghts[1] = 1;
usb2_start_hardware(xfer);
Example3: SETUP + DATA + STATUS - split
1st callback:
xfer->nframes = 1;
xfer->frlenghts[0] = 8;
usb2_start_hardware(xfer);
2nd callback:
/* IMPORTANT: frbuffer[0] must still point at the setup packet! */
xfer->nframes = 2;
xfer->frlenghts[0] = 0;
xfer->frlenghts[1] = 1;
usb2_start_hardware(xfer);
Example4: SETUP + STATUS - split
1st callback:
xfer->nframes = 1;
xfer->frlenghts[0] = 8;
xfer->flags.manual_status = 1;
usb2_start_hardware(xfer);
2nd callback:
xfer->nframes = 1;
xfer->frlenghts[0] = 0;
xfer->flags.manual_status = 0;
usb2_start_hardware(xfer);
=== General USB transfer notes ===
1) Something that one should be aware of is that all USB callbacks support
recursation. That means one can start/stop whatever transfer from the callback
of another transfer one desires. Also the transfer that is currently called
back. Recursion is handled like this that when the callback that wants to
recurse returns it is called one more time.
2) After that the "usb2_start_hardware()" function has been called in
the callback one can always depend on that "tr_error" or "tr_transferred"
will get jumped afterwards. Always!
3) Sleeping functions can only be called from the attach routine of the
driver. Else one should not use sleeping functions unless one has to. It is
very difficult with sleep, because one has to think that the device might have
detached when the thread returns from sleep.
4) Polling.
use_polling
This flag can be used with any callback and will cause the
"usb2_transfer_start()" function to wait using "DELAY()",
without exiting any mutexes, until the transfer is finished or
has timed out. This flag can be changed during operation.
NOTE: If polling is used the "timeout" field should be non-zero!
NOTE: USB_ERR_CANCELLED is returned in case of timeout
instead of USB_ERR_TIMEOUT!
USB device driver examples:
/sys/dev/usb2/ethernet/if_axe.c
/sys/dev/usb2/ethernet/if_aue.c
QUICK REFERENCE
===============
/*------------------------------------------------------------------------*
* usb2_error_t
* usb2_transfer_setup(udev, ifaces, pxfer, setup_start,
* n_setup, priv_sc, priv_mtx)
*------------------------------------------------------------------------*/
- "udev" is a pointer to "struct usb2_device".
- "ifaces" array of interface index numbers to use. See "if_index".
- "pxfer" is a pointer to an array of USB transfer pointers that are
initialized to NULL, and then pointed to allocated USB transfers.
- "setup_start" is a pointer to an array of USB config structures.
- "n_setup" is a number telling the USB system how many USB transfers
should be setup.
- "priv_sc" is the private softc pointer, which will be used to
initialize "xfer->priv_sc".
- "priv_mtx" is the private mutex protecting the transfer structure and
the softc. This pointer is used to initialize "xfer->priv_mtx".
/*------------------------------------------------------------------------*
* void
* usb2_transfer_unsetup(pxfer, n_setup)
*------------------------------------------------------------------------*/
- "pxfer" is a pointer to an array of USB transfer pointers, that may
be NULL, that should be freed by the USB system.
- "n_setup" is a number telling the USB system how many USB transfers
should be unsetup
NOTE: This function can sleep, waiting for active mutexes to become unlocked!
NOTE: It is not allowed to call "usb2_transfer_unsetup" from the callback
of a USB transfer.
/*------------------------------------------------------------------------*
* void
* usb2_transfer_start(xfer)
*------------------------------------------------------------------------*/
- "xfer" is pointer to a USB transfer that should be started
NOTE: this function must be called with "priv_mtx" locked
/*------------------------------------------------------------------------*
* void
* usb2_transfer_stop(xfer)
*------------------------------------------------------------------------*/
- "xfer" is a pointer to a USB transfer that should be stopped
NOTE: this function must be called with "priv_mtx" locked
NOTE: if the transfer was in progress, the callback will called with
"xfer->error=USB_ERR_CANCELLED", before this function returns
/*------------------------------------------------------------------------*
* struct usb2_config {
* type, endpoint, direction, interval, timeout, frames, index
* flags, bufsize, callback
* };
*------------------------------------------------------------------------*/
- The "type" field selects the USB pipe type. Valid values are:
UE_INTERRUPT, UE_CONTROL, UE_BULK, UE_ISOCHRONOUS. The special
value UE_BULK_INTR will select BULK and INTERRUPT pipes.
This field is mandatory.
- The "endpoint" field selects the USB endpoint number. A value of
0xFF, "-1" or "UE_ADDR_ANY" will select the first matching endpoint.
This field is mandatory.
- The "direction" field selects the USB endpoint direction. A value of
"UE_DIR_ANY" will select the first matching endpoint. Else valid
values are: "UE_DIR_IN" and "UE_DIR_OUT". "UE_DIR_IN" and
"UE_DIR_OUT" can be binary ORed by "UE_DIR_SID" which means that the
direction will be swapped in case of USB_MODE_DEVICE. Note that
"UE_DIR_IN" refers to the data transfer direction of the "IN" tokens
and "UE_DIR_OUT" refers to the data transfer direction of the "OUT"
tokens. This field is mandatory.
- The "interval" field selects the interrupt interval. The value of this
field is given in milliseconds and is independent of device speed. Depending
on the endpoint type, this field has different meaning:
UE_INTERRUPT)
"0" use the default interrupt interval based on endpoint descriptor.
"Else" use the given value for polling rate.
UE_ISOCHRONOUS)
"0" use default.
"Else" the value is ignored.
UE_BULK)
UE_CONTROL)
"0" no transfer pre-delay.
"Else" a delay as given by this field in milliseconds is
inserted before the hardware is started when
"usb2_start_hardware()" is called.
NOTE: The transfer timeout, if any, is started after that
the pre-delay has elapsed!
- The "timeout" field, if non-zero, will set the transfer timeout in
milliseconds. If the "timeout" field is zero and the transfer type
is ISOCHRONOUS a timeout of 250ms will be used.
- The "frames" field sets the maximum number of frames. If zero is
specified it will yield the following results:
UE_BULK)
UE_INTERRUPT)
xfer->nframes = 1;
UE_CONTROL)
xfer->nframes = 2;
UE_ISOCHRONOUS)
Not allowed. Will cause an error.
- The "ep_index" field allows you to give a number, in case more
endpoints match the description, that selects which matching
"ep_index" should be used.
- The "if_index" field allows you to select which of the interface
numbers in the "ifaces" array parameter passed to "usb2_transfer_setup"
that should be used when setting up the given USB transfer.
- The "flags" field has type "struct usb2_xfer_flags" and allows one
to set initial flags an USB transfer. Valid flags are:
force_short_xfer
This flag forces the last transmitted USB packet to be short.
A short packet has a length of less than "xfer->max_packet_size",
which derives from "wMaxPacketSize". This flag can be changed
during operation.
short_xfer_ok
This flag allows the received transfer length, "xfer->actlen"
to be less than "xfer->sumlen" upon completion of a transfer.
This flag can be changed during operation.
pipe_bof
This flag causes a failing USB transfer to remain first
in the PIPE queue except in the case of "xfer->error" equal
to "USB_ERR_CANCELLED". No other USB transfers in the affected
PIPE queue will be started until either:
1) The failing USB transfer is stopped using "usb2_transfer_stop()".
2) The failing USB transfer performs a successful transfer.
The purpose of this flag is to avoid races when multiple
transfers are queued for execution on an USB endpoint, and the
first executing transfer fails leading to the need for
clearing of stall for example. In this case this flag is used
to prevent the following USB transfers from being executed at
the same time the clear-stall command is executed on the USB
control endpoint. This flag can be changed during operation.
"BOF" is short for "Block On Failure"
NOTE: This flag should be set on all BULK and INTERRUPT
USB transfers which use an endpoint that can be shared
between userland and kernel.
proxy_buffer
Setting this flag will cause that the total buffer size will
be rounded up to the nearest atomic hardware transfer
size. The maximum data length of any USB transfer is always
stored in the "xfer->max_data_length". For control transfers
the USB kernel will allocate additional space for the 8-bytes
of SETUP header. These 8-bytes are not counted by the
"xfer->max_data_length" variable. This flag can not be changed
during operation.
ext_buffer
Setting this flag will cause that no data buffer will be
allocated. Instead the USB client must supply a data buffer.
This flag can not be changed during operation.
manual_status
Setting this flag prevents an USB STATUS stage to be appended
to the end of the USB control transfer. If no control data is
transferred this flag must be cleared. Else an error will be
returned to the USB callback. This flag is mostly useful for
the USB device side. This flag can be changed during
operation.
no_pipe_ok
Setting this flag causes the USB_ERR_NO_PIPE error to be
ignored. This flag can not be changed during operation.
stall_pipe
Setting this flag will cause STALL pids to be sent to the
endpoint belonging to this transfer before the transfer is
started. The transfer is started at the moment the host issues
a clear-stall command on the STALL'ed endpoint. This flag can
be changed during operation. This flag does only have effect
in USB device side mode except for control endpoints. This
flag is cleared when the stall command has been executed. This
flag can only be changed outside the callback function by
using the functions "usb2_transfer_set_stall()" and
"usb2_transfer_clear_stall()" !
- The "bufsize" field sets the total buffer size in bytes. If
this field is zero, "wMaxPacketSize" will be used, multiplied by the
"frames" field if the transfer type is ISOCHRONOUS. This is useful for
setting up interrupt pipes. This field is mandatory.
NOTE: For control transfers "bufsize" includes
the length of the request structure.
- The "callback" pointer sets the USB callback. This field is mandatory.
MUTEX NOTE:
===========
When you create a mutex using "mtx_init()", don't forget to call
"mtx_destroy()" at detach, else you can get "freed memory accessed"
panics.
--HPS

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,169 @@
/* $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.
*/
#ifndef _USB2_BUSDMA_H_
#define _USB2_BUSDMA_H_
#include <sys/uio.h>
#include <sys/mbuf.h>
#include <machine/bus.h>
/* defines */
#define USB_PAGE_SIZE PAGE_SIZE /* use system PAGE_SIZE */
#ifdef __FreeBSD__
#if (__FreeBSD_version >= 700020)
#define USB_GET_DMA_TAG(dev) bus_get_dma_tag(dev)
#else
#define USB_GET_DMA_TAG(dev) NULL /* XXX */
#endif
#endif
/* structure prototypes */
struct usb2_xfer_root;
struct usb2_dma_parent_tag;
/*
* The following typedef defines the USB DMA load done callback.
*/
typedef void (usb2_dma_callback_t)(struct usb2_dma_parent_tag *udpt);
/*
* The following structure defines physical and non kernel virtual
* address of a memory page having size USB_PAGE_SIZE.
*/
struct usb2_page {
bus_size_t physaddr;
void *buffer; /* non Kernel Virtual Address */
};
/*
* The following structure is used when needing the kernel virtual
* pointer and the physical address belonging to an offset in an USB
* page cache.
*/
struct usb2_page_search {
void *buffer;
bus_size_t physaddr;
uint32_t length;
};
/*
* The following structure is used to keep information about a DMA
* memory allocation.
*/
struct usb2_page_cache {
#ifdef __FreeBSD__
bus_dma_tag_t tag;
bus_dmamap_t map;
#endif
#ifdef __NetBSD__
bus_dma_tag_t tag;
bus_dmamap_t map;
bus_dma_segment_t *p_seg;
#endif
struct usb2_page *page_start;
struct usb2_dma_parent_tag *tag_parent; /* always set */
void *buffer; /* virtual buffer pointer */
#ifdef __NetBSD__
int n_seg;
#endif
uint32_t page_offset_buf;
uint32_t page_offset_end;
uint8_t isread:1; /* set if we are currently reading
* from the memory. Else write. */
uint8_t ismultiseg:1; /* set if we can have multiple
* segments */
};
/*
* The following structure describes the parent USB DMA tag.
*/
struct usb2_dma_parent_tag {
#ifdef __FreeBSD__
struct cv cv[1]; /* internal condition variable */
#endif
bus_dma_tag_t tag; /* always set */
struct mtx *mtx; /* private mutex, always set */
struct usb2_xfer_root *info; /* used by the callback function */
usb2_dma_callback_t *func; /* load complete callback function */
struct usb2_dma_tag *utag_first;/* pointer to first USB DMA tag */
uint8_t dma_error; /* set if DMA load operation failed */
uint8_t dma_bits; /* number of DMA address lines */
uint8_t utag_max; /* number of USB DMA tags */
};
/*
* The following structure describes an USB DMA tag.
*/
struct usb2_dma_tag {
#ifdef __NetBSD__
bus_dma_segment_t *p_seg;
#endif
struct usb2_dma_parent_tag *tag_parent;
bus_dma_tag_t tag;
uint32_t align;
uint32_t size;
#ifdef __NetBSD__
uint32_t n_seg;
#endif
};
/* function prototypes */
int usb2_uiomove(struct usb2_page_cache *pc, struct uio *uio, uint32_t pc_offset, uint32_t len);
struct usb2_dma_tag *usb2_dma_tag_find(struct usb2_dma_parent_tag *udpt, uint32_t size, uint32_t align);
uint8_t usb2_pc_alloc_mem(struct usb2_page_cache *pc, struct usb2_page *pg, uint32_t size, uint32_t align);
uint8_t usb2_pc_dmamap_create(struct usb2_page_cache *pc, uint32_t size);
uint8_t usb2_pc_load_mem(struct usb2_page_cache *pc, uint32_t size, uint8_t sync);
void usb2_bdma_done_event(struct usb2_dma_parent_tag *udpt);
void usb2_bdma_post_sync(struct usb2_xfer *xfer);
void usb2_bdma_pre_sync(struct usb2_xfer *xfer);
void usb2_bdma_work_loop(struct usb2_xfer_queue *pq);
void usb2_bzero(struct usb2_page_cache *cache, uint32_t offset, uint32_t len);
void usb2_copy_in(struct usb2_page_cache *cache, uint32_t offset, const void *ptr, uint32_t len);
int usb2_copy_in_user(struct usb2_page_cache *cache, uint32_t offset, const void *ptr, uint32_t len);
void usb2_copy_out(struct usb2_page_cache *cache, uint32_t offset, void *ptr, uint32_t len);
int usb2_copy_out_user(struct usb2_page_cache *cache, uint32_t offset, void *ptr, uint32_t len);
void usb2_dma_tag_setup(struct usb2_dma_parent_tag *udpt, struct usb2_dma_tag *udt, bus_dma_tag_t dmat, struct mtx *mtx, usb2_dma_callback_t *func, struct usb2_xfer_root *info, uint8_t ndmabits, uint8_t nudt);
void usb2_dma_tag_unsetup(struct usb2_dma_parent_tag *udpt);
void usb2_get_page(struct usb2_page_cache *pc, uint32_t offset, struct usb2_page_search *res);
void usb2_m_copy_in(struct usb2_page_cache *cache, uint32_t dst_offset, struct mbuf *m, uint32_t src_offset, uint32_t src_len);
void usb2_pc_cpu_flush(struct usb2_page_cache *pc);
void usb2_pc_cpu_invalidate(struct usb2_page_cache *pc);
void usb2_pc_dmamap_destroy(struct usb2_page_cache *pc);
void usb2_pc_free_mem(struct usb2_page_cache *pc);
#endif /* _USB2_BUSDMA_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,465 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2007 Luigi Rizzo - Universita` di Pisa. All rights reserved.
* Copyright (c) 2007 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.
*/
#ifndef _USB_COMPAT_LINUX_H
#define _USB_COMPAT_LINUX_H
struct usb_device;
struct usb_interface;
struct usb_driver;
struct urb;
typedef void *pm_message_t;
typedef void (usb_complete_t)(struct urb *);
#define USB_MAX_FULL_SPEED_ISOC_FRAMES (60 * 1)
#define USB_MAX_HIGH_SPEED_ISOC_FRAMES (60 * 8)
/*
* Linux compatible USB device drivers put their device information
* into the "usb_device_id" structure using the "USB_DEVICE()" macro.
* The "MODULE_DEVICE_TABLE()" macro can be used to export this
* information to userland.
*/
struct usb_device_id {
/* which fields to match against */
uint16_t match_flags;
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
/* 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;
};
#define USB_DEVICE_ID_MATCH_DEVICE \
(USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
#define USB_DEVICE(vend,prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
.idProduct = (prod)
/* The "usb_driver" structure holds the Linux USB device driver
* callbacks, and a pointer to device ID's which this entry should
* match against. Usually this entry is exposed to the USB emulation
* layer using the "USB_DRIVER_EXPORT()" macro, which is defined
* below.
*/
struct usb_driver {
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
int (*ioctl) (struct usb_interface *intf, unsigned int code,
void *buf);
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
const struct usb_device_id *id_table;
void (*shutdown) (struct usb_interface *intf);
LIST_ENTRY(usb_driver) linux_driver_list;
};
#define USB_DRIVER_EXPORT(id,p_usb_drv) \
SYSINIT(id,SI_SUB_KLD,SI_ORDER_FIRST,usb_linux_register,p_usb_drv); \
SYSUNINIT(id,SI_SUB_KLD,SI_ORDER_ANY,usb_linux_deregister,p_usb_drv)
/*
* The following structure is the same as "usb_device_descriptor_t"
* except that 16-bit values are "uint16_t" and not an array of "uint8_t".
* It is used by Linux USB device drivers.
*/
struct usb_device_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} __packed;
/*
* The following structure is the same as
* "usb_interface_descriptor_t". It is used by
* Linux USB device drivers.
*/
struct usb_interface_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} __packed;
/*
* The following structure is the same as "usb_endpoint_descriptor_t"
* except that 16-bit values are "uint16_t" and not an array of "uint8_t".
* It is used by Linux USB device drivers.
*/
struct usb_endpoint_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
/* extension for audio endpoints only: */
uint8_t bRefresh;
uint8_t bSynchAddress;
} __packed;
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9
/*
* Endpoints
*/
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
/* CONTROL REQUEST SUPPORT */
/*
* Definition of direction mask for
* "bEndpointAddress" and "bmRequestType":
*/
#define USB_DIR_MASK 0x80
#define USB_DIR_OUT 0x00 /* write to USB device */
#define USB_DIR_IN 0x80 /* read from USB device */
/*
* Definition of type mask for
* "bmRequestType":
*/
#define USB_TYPE_MASK (0x03 << 5)
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
/*
* Definition of receiver mask for
* "bmRequestType":
*/
#define USB_RECIP_MASK 0x1f
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
/*
* Definition of standard request values for
* "bRequest":
*/
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
/*
* USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
* are read as a bit array returned by USB_REQ_GET_STATUS. (So there
* are at most sixteen features of each type.)
*/
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
#define USB_DEVICE_BATTERY 2 /* (wireless) */
#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless) */
#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
#define PIPE_ISOCHRONOUS 0x01 /* UE_ISOCHRONOUS */
#define PIPE_INTERRUPT 0x03 /* UE_INTERRUPT */
#define PIPE_CONTROL 0x00 /* UE_CONTROL */
#define PIPE_BULK 0x02 /* UE_BULK */
/* Whenever Linux references an USB endpoint:
* a) to initialize "urb->pipe"
* b) second argument passed to "usb_control_msg()"
*
* Then it uses one of the following macros. The "endpoint" argument
* is the physical endpoint value masked by 0xF. The "dev" argument
* is a pointer to "struct usb_device".
*/
#define usb_sndctrlpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_CONTROL, (endpoint) | USB_DIR_OUT)
#define usb_rcvctrlpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_CONTROL, (endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_ISOCHRONOUS, (endpoint) | USB_DIR_OUT)
#define usb_rcvisocpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_ISOCHRONOUS, (endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_BULK, (endpoint) | USB_DIR_OUT)
#define usb_rcvbulkpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_BULK, (endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_INTERRUPT, (endpoint) | USB_DIR_OUT)
#define usb_rcvintpipe(dev,endpoint) \
usb_find_host_endpoint(dev, PIPE_INTERRUPT, (endpoint) | USB_DIR_IN)
/* The following four structures makes up a tree, where we have the
* leaf structure, "usb_host_endpoint", first, and the root structure,
* "usb_device", last. The four structures below mirror the structure
* of the USB descriptors belonging to an USB configuration. Please
* refer to the USB specification for a definition of "endpoints" and
* "interfaces".
*/
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
TAILQ_HEAD(, urb) bsd_urb_list;
struct usb2_xfer *bsd_xfer[2];
uint8_t *extra; /* Extra descriptors */
uint32_t fbsd_buf_size;
uint16_t extralen;
uint8_t bsd_iface_index;
} __aligned(USB_HOST_ALIGN);
struct usb_host_interface {
struct usb_interface_descriptor desc;
/* the following array has size "desc.bNumEndpoint" */
struct usb_host_endpoint *endpoint;
const char *string; /* iInterface string, if present */
uint8_t *extra; /* Extra descriptors */
uint16_t extralen;
uint8_t bsd_iface_index;
} __aligned(USB_HOST_ALIGN);
struct usb_interface {
/* array of alternate settings for this interface */
struct usb_host_interface *altsetting;
struct usb_host_interface *cur_altsetting;
struct usb_device *linux_udev;
void *bsd_priv_sc; /* device specific information */
uint8_t num_altsetting; /* number of alternate settings */
uint8_t bsd_iface_index;
} __aligned(USB_HOST_ALIGN);
struct usb_device {
struct usb_device_descriptor descriptor;
struct usb_host_endpoint ep0;
struct usb2_device *bsd_udev;
struct usb_interface *bsd_iface_start;
struct usb_interface *bsd_iface_end;
struct usb_host_endpoint *bsd_endpoint_start;
struct usb_host_endpoint *bsd_endpoint_end;
/* static strings from the device */
const char *product; /* iProduct string, if present */
const char *manufacturer; /* iManufacturer string, if present */
const char *serial; /* iSerialNumber string, if present */
uint16_t devnum;
uint8_t speed; /* USB_SPEED_XXX */
} __aligned(USB_HOST_ALIGN);
/*
* The following structure is used to extend "struct urb" when we are
* dealing with an isochronous endpoint. It contains information about
* the data offset and data length of an isochronous packet.
* The "actual_length" field is updated before the "complete"
* callback in the "urb" structure is called.
*/
struct usb_iso_packet_descriptor {
uint32_t offset; /* depreciated buffer offset (the
* packets are usually back to back) */
uint16_t length; /* expected length */
uint16_t actual_length;
uint16_t status;
};
/*
* The following structure holds various information about an USB
* transfer. This structure is used for all kinds of USB transfers.
*
* URB is short for USB Request Block.
*/
struct urb {
TAILQ_ENTRY(urb) bsd_urb_list;
struct cv cv_wait;
struct usb_device *dev; /* (in) pointer to associated device */
struct usb_host_endpoint *pipe; /* (in) pipe pointer */
uint8_t *setup_packet; /* (in) setup packet (control only) */
uint8_t *bsd_data_ptr;
void *transfer_buffer; /* (in) associated data buffer */
void *context; /* (in) context for completion */
usb_complete_t *complete; /* (in) completion routine */
uint32_t transfer_buffer_length;/* (in) data buffer length */
uint32_t actual_length; /* (return) actual transfer length */
uint32_t bsd_length_rem;
uint32_t timeout; /* FreeBSD specific */
uint16_t transfer_flags; /* (in) */
#define URB_SHORT_NOT_OK 0x0001 /* report short transfers like errors */
#define URB_ISO_ASAP 0x0002 /* ignore "start_frame" field */
#define URB_ZERO_PACKET 0x0004 /* the USB transfer ends with a short
* packet */
#define URB_NO_TRANSFER_DMA_MAP 0x0008 /* "transfer_dma" is valid on submit */
#define URB_WAIT_WAKEUP 0x0010 /* custom flags */
#define URB_IS_SLEEPING 0x0020 /* custom flags */
uint16_t start_frame; /* (modify) start frame (ISO) */
uint16_t number_of_packets; /* (in) number of ISO packets */
uint16_t interval; /* (modify) transfer interval
* (INT/ISO) */
uint16_t error_count; /* (return) number of ISO errors */
int16_t status; /* (return) status */
uint8_t setup_dma; /* (in) not used on FreeBSD */
uint8_t transfer_dma; /* (in) not used on FreeBSD */
uint8_t bsd_isread;
struct usb_iso_packet_descriptor iso_frame_desc[]; /* (in) ISO ONLY */
};
/* various prototypes */
int usb_submit_urb(struct urb *urb, uint16_t mem_flags);
int usb_unlink_urb(struct urb *urb);
int usb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe);
int usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *pipe, uint8_t request, uint8_t requesttype, uint16_t value, uint16_t index, void *data, uint16_t size, uint32_t timeout);
int usb_set_interface(struct usb_device *dev, uint8_t ifnum, uint8_t alternate);
int usb_setup_endpoint(struct usb_device *dev, struct usb_host_endpoint *uhe, uint32_t bufsize);
struct usb_host_endpoint *usb_find_host_endpoint(struct usb_device *dev, uint8_t type, uint8_t ep);
struct urb *usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags);
struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf, uint8_t alt_index);
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no);
void *usb_buffer_alloc(struct usb_device *dev, uint32_t size, uint16_t mem_flags, uint8_t *dma_addr);
void *usb_get_intfdata(struct usb_interface *intf);
void usb_buffer_free(struct usb_device *dev, uint32_t size, void *addr, uint8_t dma_addr);
void usb_free_urb(struct urb *urb);
void usb_init_urb(struct urb *urb);
void usb_kill_urb(struct urb *urb);
void usb_set_intfdata(struct usb_interface *intf, void *data);
void usb_linux_register(void *arg);
void usb_linux_deregister(void *arg);
#define interface_to_usbdev(intf) (intf)->linux_udev
#define interface_to_bsddev(intf) (intf)->linux_udev->bsd_udev
#endif /* _USB_COMPAT_LINUX_H */

View File

@ -0,0 +1,320 @@
/* $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 <dev/usb2/include/usb2_mfunc.h>
#define USB_DEBUG_VAR usb2_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_config_td.h>
#include <dev/usb2/core/usb2_debug.h>
static void usb2_config_td_sync_cb(struct usb2_config_td_softc *sc, struct usb2_config_td_cc *cc, uint16_t ref);
static void
usb2_config_td_dispatch(struct usb2_proc_msg *pm)
{
struct usb2_config_td_item *pi = (void *)pm;
struct usb2_config_td *ctd = pi->p_ctd;
DPRINTF("\n");
(pi->command_func) (ctd->p_softc, (void *)(pi + 1), pi->command_ref);
if (TAILQ_NEXT(pm, pm_qentry) == NULL) {
/* last command */
if (ctd->p_end_of_commands) {
(ctd->p_end_of_commands) (ctd->p_softc);
}
}
return;
}
/*------------------------------------------------------------------------*
* usb2_config_td_setup
*
* NOTE: the structure pointed to by "ctd" must be zeroed before calling
* this function!
*
* Return values:
* 0: success
* Else: failure
*------------------------------------------------------------------------*/
uint8_t
usb2_config_td_setup(struct usb2_config_td *ctd, void *priv_sc,
struct mtx *priv_mtx,
usb2_config_td_end_of_commands_t *p_func_eoc,
uint16_t item_size, uint16_t item_count)
{
struct usb2_config_td_item *pi;
uint16_t n;
DPRINTF(" size=%u, count=%u \n", item_size, item_count);
if (item_count >= 256) {
DPRINTFN(0, "too many items!\n");
return (1);
}
ctd->p_softc = priv_sc;
ctd->p_end_of_commands = p_func_eoc;
ctd->msg_count = (2 * item_count);
ctd->msg_size =
(sizeof(struct usb2_config_td_item) + item_size);
ctd->p_msgs =
malloc(ctd->msg_size * ctd->msg_count, M_USBDEV, M_WAITOK | M_ZERO);
if (ctd->p_msgs == NULL) {
return (1);
}
if (usb2_proc_setup(&ctd->usb2_proc, priv_mtx, USB_PRI_MED)) {
free(ctd->p_msgs, M_USBDEV);
ctd->p_msgs = NULL;
return (1);
}
/* initialise messages */
pi = USB_ADD_BYTES(ctd->p_msgs, 0);
for (n = 0; n != ctd->msg_count; n++) {
pi->hdr.pm_callback = &usb2_config_td_dispatch;
pi->p_ctd = ctd;
pi = USB_ADD_BYTES(pi, ctd->msg_size);
}
return (0);
}
/*------------------------------------------------------------------------*
* usb2_config_td_drain
*
* This function will tear down an USB config thread, waiting for the
* currently executing command to return.
*
* NOTE: If the structure pointed to by "ctd" is all zero,
* this function does nothing.
*------------------------------------------------------------------------*/
void
usb2_config_td_drain(struct usb2_config_td *ctd)
{
DPRINTF("\n");
if (ctd->p_msgs) {
usb2_proc_drain(&ctd->usb2_proc);
}
return;
}
/*------------------------------------------------------------------------*
* usb2_config_td_unsetup
*
* NOTE: If the structure pointed to by "ctd" is all zero,
* this function does nothing.
*------------------------------------------------------------------------*/
void
usb2_config_td_unsetup(struct usb2_config_td *ctd)
{
DPRINTF("\n");
usb2_config_td_drain(ctd);
if (ctd->p_msgs) {
usb2_proc_unsetup(&ctd->usb2_proc);
free(ctd->p_msgs, M_USBDEV);
ctd->p_msgs = NULL;
}
return;
}
/*------------------------------------------------------------------------*
* usb2_config_td_queue_command
*
* This function will enter a command into the config thread queue for
* execution. The "command_sync" field was previously used to indicate
* the queue count which is now fixed at two elements. If the
* "command_sync" field is equal to "USB2_CONFIG_TD_SYNC" the command
* will be executed synchronously from the config thread. The
* "command_ref" argument is the reference count for the current
* command which is passed on to the "command_post_func"
* function. This parameter can be used to make a command
* unique. "command_pre_func" is called from this function when we
* have the final queue element. "command_post_func" is called from
* the USB config thread when the command reaches the beginning of the
* USB config thread queue. This function must be called locked.
*------------------------------------------------------------------------*/
void
usb2_config_td_queue_command(struct usb2_config_td *ctd,
usb2_config_td_command_t *command_pre_func,
usb2_config_td_command_t *command_post_func,
uint16_t command_sync,
uint16_t command_ref)
{
struct usb2_config_td_item *pi;
struct usb2_config_td_item *pi_0;
struct usb2_config_td_item *pi_1;
uint16_t n;
if (usb2_config_td_is_gone(ctd)) {
DPRINTF("gone\n");
/* nothing more to do */
return;
}
DPRINTF("\n");
pi = USB_ADD_BYTES(ctd->p_msgs, 0);
for (n = 0;; n += 2) {
if (n == ctd->msg_count) {
/* should not happen */
panic("%s:%d: out of memory!\n",
__FUNCTION__, __LINE__);
return;
}
if (pi->command_func == NULL) {
/* reserve our entry */
pi->command_func = command_post_func;
pi->command_ref = command_ref;
pi_0 = pi;
pi = USB_ADD_BYTES(pi, ctd->msg_size);
pi->command_func = command_post_func;
pi->command_ref = command_ref;
pi_1 = pi;
break;
}
if ((pi->command_func == command_post_func) &&
(pi->command_ref == command_ref)) {
/* found an entry */
pi_0 = pi;
pi = USB_ADD_BYTES(pi, ctd->msg_size);
pi_1 = pi;
break;
}
pi = USB_ADD_BYTES(pi, (2 * ctd->msg_size));
}
/*
* We have two message structures. One of them will get
* queued:
*/
pi = usb2_proc_msignal(&ctd->usb2_proc, pi_0, pi_1);
/*
* The job of the post-command function is to finish the command in
* a separate context to allow calls to sleeping functions
* basically. Queue the post command before calling the pre command.
* That way commands queued by the pre command will be queued after
* the current command.
*/
/*
* The job of the pre-command function is to copy the needed
* configuration to the provided structure and to execute other
* commands that must happen immediately
*/
if (command_pre_func) {
(command_pre_func) (ctd->p_softc, (void *)(pi + 1), command_ref);
}
if (command_sync == USB2_CONFIG_TD_SYNC) {
usb2_proc_mwait(&ctd->usb2_proc, pi_0, pi_1);
}
return;
}
/*------------------------------------------------------------------------*
* usb2_config_td_is_gone
*
* Return values:
* 0: config thread is running
* Else: config thread is gone
*------------------------------------------------------------------------*/
uint8_t
usb2_config_td_is_gone(struct usb2_config_td *ctd)
{
return (usb2_proc_is_gone(&ctd->usb2_proc));
}
/*------------------------------------------------------------------------*
* usb2_config_td_sleep
*
* NOTE: this function can only be called from the config thread
*
* Return values:
* 0: normal delay
* Else: config thread is gone
*------------------------------------------------------------------------*/
uint8_t
usb2_config_td_sleep(struct usb2_config_td *ctd, uint32_t timeout)
{
uint8_t is_gone = usb2_config_td_is_gone(ctd);
if (is_gone) {
goto done;
}
if (timeout == 0) {
/*
* Zero means no timeout, so avoid that by setting
* timeout to one:
*/
timeout = 1;
}
mtx_unlock(ctd->usb2_proc.up_mtx);
if (pause("USBWAIT", timeout)) {
/* ignore */
}
mtx_lock(ctd->usb2_proc.up_mtx);
is_gone = usb2_config_td_is_gone(ctd);
done:
return (is_gone);
}
/*------------------------------------------------------------------------*
* usb2_config_td_sync
*
* This function will wait until all commands have been executed on
* the config thread. This function must be called locked and can
* sleep.
*
* Return values:
* 0: success
* Else: config thread is gone
*------------------------------------------------------------------------*/
uint8_t
usb2_config_td_sync(struct usb2_config_td *ctd)
{
if (usb2_config_td_is_gone(ctd)) {
return (1);
}
usb2_config_td_queue_command(ctd, NULL,
&usb2_config_td_sync_cb, USB2_CONFIG_TD_SYNC, 0);
if (usb2_config_td_is_gone(ctd)) {
return (1);
}
return (0);
}
static void
usb2_config_td_sync_cb(struct usb2_config_td_softc *sc,
struct usb2_config_td_cc *cc, uint16_t ref)
{
return;
}

View File

@ -0,0 +1,71 @@
/* $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.
*/
#ifndef _USB2_CONFIG_TD_H_
#define _USB2_CONFIG_TD_H_
struct usb2_config_td_softc;
struct usb2_config_td_cc;
#define USB2_CONFIG_TD_SYNC 0xFFFF /* magic value */
typedef void (usb2_config_td_command_t)(struct usb2_config_td_softc *sc, struct usb2_config_td_cc *cc, uint16_t reference);
typedef void (usb2_config_td_end_of_commands_t)(struct usb2_config_td_softc *sc);
/*
* The following structure defines a command that should be executed
* using the USB config thread system.
*/
struct usb2_config_td_item {
struct usb2_proc_msg hdr;
struct usb2_config_td *p_ctd;
usb2_config_td_command_t *command_func;
uint16_t command_ref;
} __aligned(USB_HOST_ALIGN);
/*
* The following structure defines an USB config thread.
*/
struct usb2_config_td {
struct usb2_process usb2_proc;
struct usb2_config_td_softc *p_softc;
usb2_config_td_end_of_commands_t *p_end_of_commands;
void *p_msgs;
uint16_t msg_size;
uint16_t msg_count;
};
/* prototypes */
uint8_t usb2_config_td_setup(struct usb2_config_td *ctd, void *priv_sc, struct mtx *priv_mtx, usb2_config_td_end_of_commands_t *p_func_eoc, uint16_t item_size, uint16_t item_count);
void usb2_config_td_drain(struct usb2_config_td *ctd);
void usb2_config_td_unsetup(struct usb2_config_td *ctd);
void usb2_config_td_queue_command(struct usb2_config_td *ctd, usb2_config_td_command_t *pre_func, usb2_config_td_command_t *post_func, uint16_t command_sync, uint16_t command_ref);
uint8_t usb2_config_td_is_gone(struct usb2_config_td *ctd);
uint8_t usb2_config_td_sleep(struct usb2_config_td *ctd, uint32_t timeout);
uint8_t usb2_config_td_sync(struct usb2_config_td *ctd);
#endif /* _USB2_CONFIG_TD_H_ */

View File

@ -0,0 +1,40 @@
/* $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.
*/
/*
* USB specifications and other documentation can be found at
* http://www.usb.org/developers/docs/ and
* http://www.usb.org/developers/devclass_docs/
*/
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_mbuf.h>
MALLOC_DEFINE(M_USB, "USB", "USB");
MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");
MODULE_VERSION(usb2_core, 1);

View File

@ -0,0 +1,448 @@
/* $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.
*/
/*
* Including this file is mandatory for all USB related c-files in the
* kernel.
*/
#ifndef _USB2_CORE_H_
#define _USB2_CORE_H_
/* Default USB configuration */
#ifndef USB_NO_POLL
#define USB_NO_POLL 0
#endif
#ifndef USB_USE_CONDVAR
#define USB_USE_CONDVAR 0
#endif
#ifndef USB_TD_GET_PROC
#define USB_TD_GET_PROC(td) (td)->td_proc
#endif
#ifndef USB_PROC_GET_GID
#define USB_PROC_GET_GID(td) (td)->p_pgid
#endif
#ifndef USB_VNOPS_FO_CLOSE
#define USB_VNOPS_FO_CLOSE(fp, td, perr) do { \
(td)->td_fpop = (fp); \
*(perr) = vnops.fo_close(fp, td); \
(td)->td_fpop = NULL; \
} while (0)
#endif
#ifndef USB_VNOPS_FO_STAT
#define USB_VNOPS_FO_STAT(fp, sb, cred, td) \
vnops.fo_stat(fp, sb, cred, td)
#endif
#ifndef USB_VNOPS_FO_TRUNCATE
#define USB_VNOPS_FO_TRUNCATE(fp, length, cred, td) \
vnops.fo_truncate(fp, length, cred, td)
#endif
/* Include files */
#include <sys/stdint.h>
#include <sys/stddef.h>
#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/linker_set.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/unistd.h>
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_revision.h>
#include "usb2_if.h"
#include "opt_usb.h"
#include "opt_bus.h"
#define USB_STACK_VERSION 2000 /* 2.0 */
#define USB_HOST_ALIGN 8 /* bytes, must be power of two */
#define USB_ROOT_HUB_ADDR 1 /* value */
#define USB_ISOC_TIME_MAX 128 /* ms */
#define USB_FS_ISOC_UFRAME_MAX 4 /* exclusive unit */
#if (USB_FS_ISOC_UFRAME_MAX > 6)
#error "USB_FS_ISOC_UFRAME_MAX cannot be set higher than 6"
#endif
#define USB_MAX_FS_ISOC_FRAMES_PER_XFER (120) /* units */
#define USB_MAX_HS_ISOC_FRAMES_PER_XFER (8*120) /* units */
#define USB_MAX_IPACKET 8 /* maximum size of the initial USB
* data packet */
#ifndef USB_VERBOSE
#define USB_VERBOSE 1
#endif
#define USB_HUB_MAX_DEPTH 5
/* 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) ((xfer)->usb2_state)
/*
* The following macro will tell if an USB transfer is currently
* receiving or transferring data.
*/
#define USB_GET_DATA_ISREAD(xfer) (((xfer)->flags_int.usb2_mode == \
USB_MODE_DEVICE) ? ((xfer->endpoint & UE_DIR_IN) ? 0 : 1) : \
((xfer->endpoint & UE_DIR_IN) ? 1 : 0))
/*
* 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)
/* macros */
#define usb2_callout_init_mtx(c,m,f) callout_init_mtx(&(c)->co,m,f)
#define usb2_callout_reset(c,t,f,d) callout_reset(&(c)->co,t,f,d)
#define usb2_callout_stop(c) callout_stop(&(c)->co)
#define usb2_callout_drain(c) callout_drain(&(c)->co)
#define usb2_callout_pending(c) callout_pending(&(c)->co)
/* structure prototypes */
struct file;
struct usb2_bus;
struct usb2_device;
struct usb2_page;
struct usb2_page_cache;
struct usb2_xfer;
struct usb2_xfer_root;
/* typedefs */
typedef uint8_t usb2_error_t;
typedef void (usb2_callback_t)(struct usb2_xfer *);
/* structures */
/*
* This structure contains permissions.
*/
struct usb2_perm {
uint32_t uid;
uint32_t gid;
uint16_t mode;
};
/*
* Common queue structure for USB transfers.
*/
struct usb2_xfer_queue {
TAILQ_HEAD(, usb2_xfer) head;
struct usb2_xfer *curr; /* current USB transfer processed */
void (*command) (struct usb2_xfer_queue *pq);
uint8_t recurse_1:1;
uint8_t recurse_2:1;
};
/*
* The following is a wrapper for the callout structure to ease
* porting the code to other platforms.
*/
struct usb2_callout {
struct callout co;
};
/*
* The following structure defines a set of USB transfer flags.
*/
struct usb2_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! */
};
/*
* The following structure defines a set of internal USB transfer
* flags.
*/
struct usb2_xfer_flags_int {
uint16_t control_rem; /* remainder in bytes */
uint8_t open:1; /* set if USB pipe has been opened */
uint8_t transferring:1; /* set if an USB transfer is in
* progress */
uint8_t did_dma_delay:1; /* set if we waited for HW DMA */
uint8_t did_close:1; /* set if we closed the USB transfer */
uint8_t draining:1; /* set if we are draining an USB
* transfer */
uint8_t started:1; /* keeps track of started or stopped */
uint8_t bandwidth_reclaimed:1;
uint8_t control_xfr:1; /* set if control transfer */
uint8_t control_hdr:1; /* set if control header should be
* sent */
uint8_t control_act:1; /* set if control transfer is active */
uint8_t short_frames_ok:1; /* filtered version */
uint8_t short_xfer_ok:1; /* filtered version */
uint8_t bdma_enable:1; /* filtered version (only set if
* hardware supports DMA) */
uint8_t bdma_no_post_sync:1; /* set if the USB callback wrapper
* should not do the BUS-DMA post sync
* operation */
uint8_t bdma_setup:1; /* set if BUS-DMA has been setup */
uint8_t isochronous_xfr:1; /* set if isochronous transfer */
uint8_t usb2_mode:1; /* shadow copy of "udev->usb2_mode" */
uint8_t curr_dma_set:1; /* used by USB HC/DC driver */
uint8_t can_cancel_immed:1; /* set if USB transfer can be
* cancelled immediately */
};
/*
* The following structure defines the symmetric part of an USB config
* structure.
*/
struct usb2_config_sub {
usb2_callback_t *callback; /* USB transfer callback */
uint32_t bufsize; /* total pipe buffer size in bytes */
uint32_t frames; /* maximum number of USB frames */
uint16_t interval; /* interval in milliseconds */
#define USB_DEFAULT_INTERVAL 0
uint16_t timeout; /* transfer timeout in milliseconds */
struct usb2_xfer_flags flags; /* transfer flags */
};
/*
* The following structure define an USB configuration, that basically
* is used when setting up an USB transfer.
*/
struct usb2_config {
struct usb2_config_sub mh; /* parameters for USB_MODE_HOST */
struct usb2_config_sub md; /* parameters for USB_MODE_DEVICE */
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 */
};
/*
* The following structure defines an USB transfer.
*/
struct usb2_xfer {
struct usb2_callout timeout_handle;
TAILQ_ENTRY(usb2_xfer) wait_entry; /* used at various places */
struct usb2_page_cache *buf_fixup; /* fixup buffer(s) */
struct usb2_xfer_queue *wait_queue; /* pointer to queue that we
* are waiting on */
struct usb2_page *dma_page_ptr;
struct usb2_pipe *pipe; /* our USB pipe */
struct usb2_device *udev;
struct mtx *priv_mtx; /* cannot be changed during operation */
struct mtx *usb2_mtx; /* used by HC driver */
struct usb2_xfer_root *usb2_root; /* used by HC driver */
void *usb2_sc; /* used by HC driver */
void *qh_start[2]; /* used by HC driver */
void *td_start[2]; /* used by HC driver */
void *td_transfer_first; /* used by HC driver */
void *td_transfer_last; /* used by HC driver */
void *td_transfer_cache; /* used by HC driver */
void *priv_sc; /* device driver data pointer 1 */
void *priv_fifo; /* device driver data pointer 2 */
void *local_buffer;
uint32_t *frlengths;
struct usb2_page_cache *frbuffers;
usb2_callback_t *callback;
uint32_t max_usb2_frame_size;
uint32_t max_data_length;
uint32_t sumlen; /* sum of all lengths in bytes */
uint32_t actlen; /* actual length in bytes */
uint32_t timeout; /* milliseconds */
#define USB_NO_TIMEOUT 0
#define USB_DEFAULT_TIMEOUT 5000 /* 5000 ms = 5 seconds */
uint32_t max_frame_count; /* initial value of "nframes" after
* setup */
uint32_t nframes; /* number of USB frames to transfer */
uint32_t aframes; /* actual number of USB frames
* transferred */
uint16_t max_packet_size;
uint16_t max_frame_size;
uint16_t qh_pos;
uint16_t isoc_time_complete; /* in ms */
uint16_t interval; /* milliseconds */
uint8_t address; /* physical USB address */
uint8_t endpoint; /* physical USB endpoint */
uint8_t max_packet_count;
uint8_t usb2_smask;
uint8_t usb2_cmask;
uint8_t usb2_uframe;
uint8_t usb2_state;
usb2_error_t error;
struct usb2_xfer_flags flags;
struct usb2_xfer_flags_int flags_int;
};
/*
* The following structure keeps information that is used to match
* against an array of "usb2_device_id" elements.
*/
struct usb2_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 usb2_attach_arg {
struct usb2_lookup_info info;
device_t temp_dev; /* for internal use */
const void *driver_info; /* for internal use */
struct usb2_device *device; /* current device */
struct usb2_interface *iface; /* current interface */
uint8_t usb2_mode; /* see USB_MODE_XXX */
uint8_t port;
uint8_t use_generic; /* hint for generic drivers */
};
/* Structure used when referring an USB device */
struct usb2_location {
struct usb2_bus *bus;
struct usb2_device *udev;
struct usb2_interface *iface;
struct usb2_fifo *rxfifo;
struct usb2_fifo *txfifo;
uint32_t devloc; /* original devloc */
uint16_t bus_index;
uint8_t dev_index;
uint8_t iface_index;
uint8_t ep_index;
uint8_t is_read;
uint8_t is_write;
uint8_t is_uref;
};
/* external variables */
MALLOC_DECLARE(M_USB);
MALLOC_DECLARE(M_USBDEV);
MALLOC_DECLARE(M_USBHC);
extern struct mtx usb2_ref_lock;
/* typedefs */
typedef struct malloc_type *usb2_malloc_type;
/* prototypes */
const char *usb2_errstr(usb2_error_t error);
struct usb2_config_descriptor *usb2_get_config_descriptor(struct usb2_device *udev);
struct usb2_device_descriptor *usb2_get_device_descriptor(struct usb2_device *udev);
struct usb2_interface *usb2_get_iface(struct usb2_device *udev, uint8_t iface_index);
struct usb2_interface_descriptor *usb2_get_interface_descriptor(struct usb2_interface *iface);
uint8_t usb2_clear_stall_callback(struct usb2_xfer *xfer1, struct usb2_xfer *xfer2);
uint8_t usb2_get_interface_altindex(struct usb2_interface *iface);
usb2_error_t usb2_set_alt_interface_index(struct usb2_device *udev, uint8_t iface_index, uint8_t alt_index);
uint8_t usb2_get_speed(struct usb2_device *udev);
usb2_error_t usb2_transfer_setup(struct usb2_device *udev, const uint8_t *ifaces, struct usb2_xfer **pxfer, const struct usb2_config *setup_start, uint16_t n_setup, void *priv_sc, struct mtx *priv_mtx);
void usb2_set_frame_data(struct usb2_xfer *xfer, void *ptr, uint32_t frindex);
void usb2_set_frame_offset(struct usb2_xfer *xfer, uint32_t offset, uint32_t frindex);
void usb2_start_hardware(struct usb2_xfer *xfer);
void usb2_transfer_clear_stall(struct usb2_xfer *xfer);
void usb2_transfer_drain(struct usb2_xfer *xfer);
void usb2_transfer_set_stall(struct usb2_xfer *xfer);
void usb2_transfer_start(struct usb2_xfer *xfer);
void usb2_transfer_stop(struct usb2_xfer *xfer);
void usb2_transfer_unsetup(struct usb2_xfer **pxfer, uint16_t n_setup);
usb2_error_t usb2_ref_device(struct file *fp, struct usb2_location *ploc, uint32_t devloc);
void usb2_unref_device(struct usb2_location *ploc);
void usb2_set_parent_iface(struct usb2_device *udev, uint8_t iface_index, uint8_t parent_index);
void usb2_set_iface_perm(struct usb2_device *udev, uint8_t iface_index, uint32_t uid, uint32_t gid, uint16_t mode);
uint8_t usb2_get_bus_index(struct usb2_device *udev);
uint8_t usb2_get_device_index(struct usb2_device *udev);
#endif /* _USB2_CORE_H_ */

View File

@ -0,0 +1,153 @@
/* $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 <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_device.h>
/*
* Define this unconditionally in case a kernel module is loaded that
* has been compiled with debugging options.
*/
int usb2_debug = 0;
SYSCTL_NODE(_hw, OID_AUTO, usb2, CTLFLAG_RW, 0, "USB debugging");
SYSCTL_INT(_hw_usb2, OID_AUTO, debug, CTLFLAG_RW,
&usb2_debug, 0, "Debug level");
/*------------------------------------------------------------------------*
* usb2_dump_iface
*
* This function dumps information about an USB interface.
*------------------------------------------------------------------------*/
void
usb2_dump_iface(struct usb2_interface *iface)
{
printf("usb2_dump_iface: iface=%p\n", iface);
if (iface == NULL) {
return;
}
printf(" iface=%p idesc=%p altindex=%d\n",
iface, iface->idesc, iface->alt_index);
return;
}
/*------------------------------------------------------------------------*
* usb2_dump_device
*
* This function dumps information about an USB device.
*------------------------------------------------------------------------*/
void
usb2_dump_device(struct usb2_device *udev)
{
printf("usb2_dump_device: dev=%p\n", udev);
if (udev == NULL) {
return;
}
printf(" bus=%p \n"
" address=%d config=%d depth=%d speed=%d self_powered=%d\n"
" power=%d langid=%d\n",
udev->bus,
udev->address, udev->curr_config_no, udev->depth, udev->speed,
udev->flags.self_powered, udev->power, udev->langid);
return;
}
/*------------------------------------------------------------------------*
* usb2_dump_queue
*
* This function dumps the USB transfer that are queued up on an USB pipe.
*------------------------------------------------------------------------*/
void
usb2_dump_queue(struct usb2_pipe *pipe)
{
struct usb2_xfer *xfer;
printf("usb2_dump_queue: pipe=%p xfer: ", pipe);
TAILQ_FOREACH(xfer, &pipe->pipe_q.head, wait_entry) {
printf(" %p", xfer);
}
printf("\n");
return;
}
/*------------------------------------------------------------------------*
* usb2_dump_pipe
*
* This function dumps information about an USB pipe.
*------------------------------------------------------------------------*/
void
usb2_dump_pipe(struct usb2_pipe *pipe)
{
if (pipe) {
printf("usb2_dump_pipe: pipe=%p", pipe);
printf(" edesc=%p isoc_next=%d toggle_next=%d",
pipe->edesc, pipe->isoc_next, pipe->toggle_next);
if (pipe->edesc) {
printf(" bEndpointAddress=0x%02x",
pipe->edesc->bEndpointAddress);
}
printf("\n");
usb2_dump_queue(pipe);
} else {
printf("usb2_dump_pipe: pipe=NULL\n");
}
return;
}
/*------------------------------------------------------------------------*
* usb2_dump_xfer
*
* This function dumps information about an USB transfer.
*------------------------------------------------------------------------*/
void
usb2_dump_xfer(struct usb2_xfer *xfer)
{
printf("usb2_dump_xfer: xfer=%p\n", xfer);
if (xfer == NULL) {
return;
}
if (xfer->pipe == NULL) {
printf("xfer %p: pipe=NULL\n",
xfer);
return;
}
printf("xfer %p: udev=%p vid=0x%04x pid=0x%04x addr=%d "
"pipe=%p ep=0x%02x attr=0x%02x\n",
xfer, xfer->udev,
UGETW(xfer->udev->ddesc.idVendor),
UGETW(xfer->udev->ddesc.idProduct),
xfer->udev->address, xfer->pipe,
xfer->pipe->edesc->bEndpointAddress,
xfer->pipe->edesc->bmAttributes);
return;
}

View File

@ -0,0 +1,70 @@
/* $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 _USB2_DEBUG_H_
#define _USB2_DEBUG_H_
/* Declare parent SYSCTL USB node. */
SYSCTL_DECL(_hw_usb2);
/* Declare global USB debug variable. */
extern int usb2_debug;
/* Force debugging until further */
#ifndef USB_DEBUG
#define USB_DEBUG 1
#endif
/* Check if USB debugging is enabled. */
#ifdef USB_DEBUG_VAR
#if (USB_DEBUG != 0)
#define DPRINTFN(n,fmt,...) do { \
if ((USB_DEBUG_VAR) >= (n)) { \
printf("%s:%u: " fmt, \
__FUNCTION__, __LINE__,## __VA_ARGS__); \
} \
} while (0)
#define DPRINTF(...) DPRINTFN(1, __VA_ARGS__)
#else
#define DPRINTF(...) do { } while (0)
#define DPRINTFN(...) do { } while (0)
#endif
#endif
struct usb2_interface;
struct usb2_device;
struct usb2_pipe;
struct usb2_xfer;
void usb2_dump_iface(struct usb2_interface *iface);
void usb2_dump_device(struct usb2_device *udev);
void usb2_dump_queue(struct usb2_pipe *pipe);
void usb2_dump_pipe(struct usb2_pipe *pipe);
void usb2_dump_xfer(struct usb2_xfer *xfer);
#endif /* _USB2_DEBUG_H_ */

2786
sys/dev/usb2/core/usb2_dev.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,149 @@
/* $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.
*/
#ifndef _USB2_DEV_H_
#define _USB2_DEV_H_
#include <sys/file.h>
#include <sys/vnode.h>
#include <sys/poll.h>
#include <sys/signalvar.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#define USB_FIFO_TX 0
#define USB_FIFO_RX 1
struct usb2_fifo;
typedef int (usb2_fifo_open_t)(struct usb2_fifo *fifo, int fflags, struct thread *td);
typedef void (usb2_fifo_close_t)(struct usb2_fifo *fifo, int fflags, struct thread *td);
typedef int (usb2_fifo_ioctl_t)(struct usb2_fifo *fifo, u_long cmd, void *addr, int fflags, struct thread *td);
typedef void (usb2_fifo_cmd_t)(struct usb2_fifo *fifo);
struct usb2_symlink {
TAILQ_ENTRY(usb2_symlink) sym_entry;
char src_path[32]; /* Source path - including terminating
* zero */
char dst_path[32]; /* Destination path - including
* terminating zero */
uint8_t src_len; /* String length */
uint8_t dst_len; /* String length */
};
/*
* Locking note for the following functions. All the
* "usb2_fifo_cmd_t" functions are called locked. The others are
* called unlocked.
*/
struct usb2_fifo_methods {
usb2_fifo_open_t *f_open;
usb2_fifo_close_t *f_close;
usb2_fifo_ioctl_t *f_ioctl;
usb2_fifo_cmd_t *f_start_read;
usb2_fifo_cmd_t *f_stop_read;
usb2_fifo_cmd_t *f_start_write;
usb2_fifo_cmd_t *f_stop_write;
const char *basename[4];
const char *postfix[4];
};
/*
* Most of the fields in the "usb2_fifo" structure are used by the
* generic USB access layer.
*/
struct usb2_fifo {
struct usb2_ifqueue free_q;
struct usb2_ifqueue used_q;
struct selinfo selinfo;
struct cv cv_io;
struct cv cv_drain;
struct usb2_fifo_methods *methods;
struct usb2_symlink *symlink[2];/* our symlinks */
struct proc *async_p; /* process that wants SIGIO */
struct usb2_fs_endpoint *fs_ep_ptr;
struct usb2_device *udev;
struct usb2_xfer *xfer[2];
struct usb2_xfer **fs_xfer;
struct mtx *priv_mtx; /* client data */
struct file *curr_file; /* set if FIFO is opened by a FILE */
void *priv_sc0; /* client data */
void *priv_sc1; /* client data */
void *queue_data;
uint32_t timeout; /* timeout in milliseconds */
uint32_t bufsize; /* BULK and INTERRUPT buffer size */
uint16_t nframes; /* for isochronous mode */
uint16_t dev_ep_index; /* our device endpoint index */
uint8_t flag_no_uref; /* set if FIFO is not control endpoint */
uint8_t flag_sleeping; /* set if FIFO is sleeping */
uint8_t flag_iscomplete; /* set if a USB transfer is complete */
uint8_t flag_iserror; /* set if FIFO error happened */
uint8_t flag_isselect; /* set if FIFO is selected */
uint8_t flag_flushing; /* set if FIFO is flushing data */
uint8_t flag_short; /* set if short_ok or force_short
* transfer flags should be set */
uint8_t flag_stall; /* set if clear stall should be run */
uint8_t iface_index; /* set to the interface we belong to */
uint8_t fifo_index; /* set to the FIFO index in "struct
* usb2_device" */
uint8_t fs_ep_max;
uint8_t fifo_zlp; /* zero length packet count */
uint8_t refcount;
#define USB_FIFO_REF_MAX 0xFF
};
struct usb2_fifo_sc {
struct usb2_fifo *fp[2];
};
int usb2_fifo_wait(struct usb2_fifo *fifo);
void usb2_fifo_signal(struct usb2_fifo *fifo);
int usb2_fifo_alloc_buffer(struct usb2_fifo *f, uint32_t bufsize, uint16_t nbuf);
void usb2_fifo_free_buffer(struct usb2_fifo *f);
int usb2_fifo_attach(struct usb2_device *udev, void *priv_sc, struct mtx *priv_mtx, struct usb2_fifo_methods *pm, struct usb2_fifo_sc *f_sc, uint16_t unit, uint16_t subunit, uint8_t iface_index);
void usb2_fifo_detach(struct usb2_fifo_sc *f_sc);
uint32_t usb2_fifo_put_bytes_max(struct usb2_fifo *fifo);
void usb2_fifo_put_data(struct usb2_fifo *fifo, struct usb2_page_cache *pc, uint32_t offset, uint32_t len, uint8_t what);
void usb2_fifo_put_data_linear(struct usb2_fifo *fifo, void *ptr, uint32_t len, uint8_t what);
uint8_t usb2_fifo_put_data_buffer(struct usb2_fifo *f, void *ptr, uint32_t len);
void usb2_fifo_put_data_error(struct usb2_fifo *fifo);
uint8_t usb2_fifo_get_data(struct usb2_fifo *fifo, struct usb2_page_cache *pc, uint32_t offset, uint32_t len, uint32_t *actlen, uint8_t what);
uint8_t usb2_fifo_get_data_linear(struct usb2_fifo *fifo, void *ptr, uint32_t len, uint32_t *actlen, uint8_t what);
uint8_t usb2_fifo_get_data_buffer(struct usb2_fifo *f, void **pptr, uint32_t *plen);
void usb2_fifo_get_data_next(struct usb2_fifo *f);
void usb2_fifo_get_data_error(struct usb2_fifo *fifo);
uint8_t usb2_fifo_opened(struct usb2_fifo *fifo);
void usb2_fifo_free(struct usb2_fifo *f);
void usb2_fifo_reset(struct usb2_fifo *f);
int usb2_check_thread_perm(struct usb2_device *udev, struct thread *td, int fflags, uint8_t iface_index, uint8_t ep_index);
void usb2_fifo_wakeup(struct usb2_fifo *f);
struct usb2_symlink *usb2_alloc_symlink(const char *target, const char *fmt,...);
void usb2_free_symlink(struct usb2_symlink *ps);
uint32_t usb2_lookup_symlink(const char *src_ptr, uint8_t src_len);
int usb2_read_symlink(uint8_t *user_ptr, uint32_t startentry, uint32_t user_len);
#endif /* _USB2_DEV_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,162 @@
/* $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.
*/
#ifndef _USB2_DEVICE_H_
#define _USB2_DEVICE_H_
struct usb2_symlink;
#define USB_DEFAULT_XFER_MAX 2
struct usb2_clear_stall_msg {
struct usb2_proc_msg hdr;
struct usb2_device *udev;
};
/*
* The following structure defines an USB pipe which is equal to an
* USB endpoint.
*/
struct usb2_pipe {
struct usb2_xfer_queue pipe_q; /* queue of USB transfers */
struct usb2_xfer *xfer_block; /* blocking USB transfer */
struct usb2_endpoint_descriptor *edesc;
struct usb2_pipe_methods *methods; /* set by HC driver */
uint16_t isoc_next;
uint16_t refcount;
uint8_t toggle_next:1; /* next data toggle value */
uint8_t is_stalled:1; /* set if pipe is stalled */
uint8_t is_synced:1; /* set if we a synchronised */
uint8_t unused:5;
uint8_t iface_index; /* not used by "default pipe" */
};
/*
* The following structure defines an USB interface.
*/
struct usb2_interface {
struct usb2_perm perm; /* interface permissions */
struct usb2_interface_descriptor *idesc;
device_t subdev;
uint8_t alt_index;
uint8_t parent_iface_index;
};
/*
* The following structure defines the USB device flags.
*/
struct usb2_device_flags {
uint8_t usb2_mode:1; /* USB mode (see USB_MODE_XXX) */
uint8_t self_powered:1; /* set if USB device is self powered */
uint8_t suspended:1; /* set if USB device is suspended */
uint8_t no_strings:1; /* set if USB device does not support
* strings */
uint8_t remote_wakeup:1; /* set if remote wakeup is enabled */
uint8_t uq_bus_powered:1; /* set if BUS powered quirk is present */
uint8_t uq_power_claim:1; /* set if power claim quirk is present */
};
/*
* The following structure defines an USB device. There exists one of
* these structures for every USB device.
*/
struct usb2_device {
struct usb2_clear_stall_msg cs_msg[2]; /* generic clear stall
* messages */
struct usb2_perm perm;
struct sx default_sx[2];
struct mtx default_mtx[1];
struct cv default_cv[2];
struct usb2_interface ifaces[USB_IFACE_MAX];
struct usb2_pipe default_pipe; /* Control Endpoint 0 */
struct usb2_pipe pipes[USB_EP_MAX];
struct usb2_bus *bus; /* our USB BUS */
device_t parent_dev; /* parent device */
struct usb2_device *parent_hub;
struct usb2_config_descriptor *cdesc; /* full config descr */
struct usb2_hub *hub; /* only if this is a hub */
struct usb_device *linux_dev;
struct usb2_xfer *default_xfer[USB_DEFAULT_XFER_MAX];
struct usb2_temp_data *usb2_template_ptr;
struct usb2_pipe *pipe_curr; /* current clear stall pipe */
struct usb2_fifo *fifo[USB_FIFO_MAX];
struct usb2_symlink *ugen_symlink; /* our generic symlink */
uint32_t plugtime; /* copy of "ticks" */
uint16_t refcount;
#define USB_DEV_REF_MAX 0xffff
uint16_t power; /* mA the device uses */
uint16_t langid; /* language for strings */
uint8_t address; /* device addess */
uint8_t device_index; /* device index in "bus->devices" */
uint8_t curr_config_index; /* current configuration index */
uint8_t curr_config_no; /* current configuration number */
uint8_t depth; /* distance from root HUB */
uint8_t speed; /* low/full/high speed */
uint8_t port_index; /* parent HUB port index */
uint8_t port_no; /* parent HUB port number */
uint8_t hs_hub_addr; /* high-speed HUB address */
uint8_t hs_port_no; /* high-speed HUB port number */
uint8_t driver_added_refcount; /* our driver added generation count */
uint8_t power_mode; /* see USB_POWER_XXX */
/* the "flags" field is write-protected by "bus->mtx" */
struct usb2_device_flags flags;
struct usb2_endpoint_descriptor default_ep_desc; /* for pipe 0 */
struct usb2_device_descriptor ddesc; /* device descriptor */
char serial[64]; /* serial number */
char manufacturer[64]; /* manufacturer string */
char product[64]; /* product string */
};
/* function prototypes */
struct usb2_device *usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, struct usb2_device *parent_hub, uint8_t depth, uint8_t port_index, uint8_t port_no, uint8_t speed, uint8_t usb2_mode);
struct usb2_pipe *usb2_get_pipe(struct usb2_device *udev, uint8_t iface_index, const struct usb2_config *setup);
struct usb2_pipe *usb2_get_pipe_by_addr(struct usb2_device *udev, uint8_t ea_val);
usb2_error_t usb2_interface_count(struct usb2_device *udev, uint8_t *count);
usb2_error_t usb2_probe_and_attach(struct usb2_device *udev, uint8_t iface_index);
usb2_error_t usb2_reset_iface_endpoints(struct usb2_device *udev, uint8_t iface_index);
usb2_error_t usb2_set_config_index(struct usb2_device *udev, uint8_t index);
usb2_error_t usb2_set_endpoint_stall(struct usb2_device *udev, struct usb2_pipe *pipe, uint8_t do_stall);
usb2_error_t usb2_suspend_resume(struct usb2_device *udev, uint8_t do_suspend);
void usb2_detach_device(struct usb2_device *udev, uint8_t iface_index, uint8_t free_subdev);
void usb2_devinfo(struct usb2_device *udev, char *dst_ptr, uint16_t dst_len);
void usb2_free_device(struct usb2_device *udev);
void *usb2_find_descriptor(struct usb2_device *udev, void *id, uint8_t iface_index, uint8_t type, uint8_t type_mask, uint8_t subtype, uint8_t subtype_mask);
void usb_linux_free_device(struct usb_device *dev);
#endif /* _USB2_DEVICE_H_ */

View File

@ -0,0 +1,140 @@
/* $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 <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_device.h>
#include <dev/usb2/core/usb2_dynamic.h>
/* function prototypes */
static usb2_temp_get_desc_t usb2_temp_get_desc_w;
static usb2_temp_setup_by_index_t usb2_temp_setup_by_index_w;
static usb2_temp_unsetup_t usb2_temp_unsetup_w;
static usb2_test_quirk_t usb2_test_quirk_w;
static usb2_quirk_ioctl_t usb2_quirk_ioctl_w;
/* global variables */
usb2_temp_get_desc_t *usb2_temp_get_desc_p = &usb2_temp_get_desc_w;
usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index_w;
usb2_temp_unsetup_t *usb2_temp_unsetup_p = &usb2_temp_unsetup_w;
usb2_test_quirk_t *usb2_test_quirk_p = &usb2_test_quirk_w;
usb2_quirk_ioctl_t *usb2_quirk_ioctl_p = &usb2_quirk_ioctl_w;
devclass_t usb2_devclass_ptr = NULL;
static usb2_error_t
usb2_temp_setup_by_index_w(struct usb2_device *udev, uint16_t index)
{
return (USB_ERR_INVAL);
}
static uint8_t
usb2_test_quirk_w(const struct usb2_lookup_info *info, uint16_t quirk)
{
return (0); /* no match */
}
static int
usb2_quirk_ioctl_w(unsigned long cmd, caddr_t data, int fflag, struct thread *td)
{
return (ENOIOCTL);
}
static void
usb2_temp_get_desc_w(struct usb2_device *udev, struct usb2_device_request *req, const void **pPtr, uint16_t *pLength)
{
/* stall */
*pPtr = NULL;
*pLength = 0;
return;
}
static void
usb2_temp_unsetup_w(struct usb2_device *udev)
{
if (udev->usb2_template_ptr) {
free(udev->usb2_template_ptr, M_USB);
udev->usb2_template_ptr = NULL;
}
return;
}
void
usb2_quirk_unload(void *arg)
{
/* reset function pointers */
usb2_test_quirk_p = &usb2_test_quirk_w;
usb2_quirk_ioctl_p = &usb2_quirk_ioctl_w;
/* wait for CPU to exit the loaded functions, if any */
/* XXX this is a tradeoff */
pause("WAIT", hz);
return;
}
void
usb2_temp_unload(void *arg)
{
/* reset function pointers */
usb2_temp_get_desc_p = &usb2_temp_get_desc_w;
usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index_w;
usb2_temp_unsetup_p = &usb2_temp_unsetup_w;
/* wait for CPU to exit the loaded functions, if any */
/* XXX this is a tradeoff */
pause("WAIT", hz);
return;
}
void
usb2_bus_unload(void *arg)
{
/* reset function pointers */
usb2_devclass_ptr = NULL;
/* wait for CPU to exit the loaded functions, if any */
/* XXX this is a tradeoff */
pause("WAIT", hz);
return;
}

View File

@ -0,0 +1,61 @@
/* $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.
*/
#ifndef _USB2_DYNAMIC_H_
#define _USB2_DYNAMIC_H_
/* prototypes */
struct usb2_device;
struct usb2_lookup_info;
struct usb2_device_request;
/* typedefs */
typedef usb2_error_t (usb2_temp_setup_by_index_t)(struct usb2_device *udev, uint16_t index);
typedef uint8_t (usb2_test_quirk_t)(const struct usb2_lookup_info *info, uint16_t quirk);
typedef int (usb2_quirk_ioctl_t)(unsigned long cmd, caddr_t data, int fflag, struct thread *td);
typedef void (usb2_temp_get_desc_t)(struct usb2_device *udev, struct usb2_device_request *req, const void **pPtr, uint16_t *pLength);
typedef void (usb2_temp_unsetup_t)(struct usb2_device *udev);
/* global function pointers */
extern usb2_temp_get_desc_t *usb2_temp_get_desc_p;
extern usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p;
extern usb2_temp_unsetup_t *usb2_temp_unsetup_p;
extern usb2_test_quirk_t *usb2_test_quirk_p;
extern usb2_quirk_ioctl_t *usb2_quirk_ioctl_p;
extern devclass_t usb2_devclass_ptr;
/* function prototypes */
void usb2_temp_unload(void *);
void usb2_quirk_unload(void *);
void usb2_bus_unload(void *);
uint8_t usb2_test_quirk(const struct usb2_attach_arg *uaa, uint16_t quirk);
#endif /* _USB2_DYNAMIC_H_ */

View File

@ -0,0 +1,44 @@
/* $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 <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/core/usb2_core.h>
USB_MAKE_DEBUG_TABLE(USB_ERR);
/*------------------------------------------------------------------------*
* usb2_errstr
*
* This function converts an USB error code into a string.
*------------------------------------------------------------------------*/
const char *
usb2_errstr(usb2_error_t err)
{
return ((err < USB_ERR_MAX) ?
USB_ERR[err] : "USB_ERR_UNKNOWN");
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/* $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.
*/
#ifndef _USB2_GENERIC_H_
#define _USB2_GENERIC_H_
extern struct usb2_fifo_methods usb2_ugen_methods;
int ugen_do_request(struct usb2_fifo *f, struct usb2_ctl_request *ur);
#endif /* _USB2_GENERIC_H_ */

View File

@ -0,0 +1,750 @@
/* $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 <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_standard.h>
#define USB_DEBUG_VAR usb2_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_transfer.h>
#include <dev/usb2/core/usb2_device.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_dynamic.h>
#include <dev/usb2/core/usb2_hub.h>
#include <dev/usb2/controller/usb2_controller.h>
#include <dev/usb2/controller/usb2_bus.h>
/* enum */
enum {
ST_DATA,
ST_POST_STATUS,
};
/* function prototypes */
static uint8_t usb2_handle_get_stall(struct usb2_device *udev, uint8_t ea_val);
static usb2_error_t usb2_handle_remote_wakeup(struct usb2_xfer *xfer, uint8_t is_on);
static usb2_error_t usb2_handle_request(struct usb2_xfer *xfer);
static usb2_error_t usb2_handle_set_config(struct usb2_xfer *xfer, uint8_t conf_no);
static usb2_error_t usb2_handle_set_stall(struct usb2_xfer *xfer, uint8_t ep, uint8_t do_stall);
static usb2_error_t usb2_handle_iface_request(struct usb2_xfer *xfer, void **ppdata, uint16_t *plen, struct usb2_device_request req, uint16_t off, uint8_t state);
/*------------------------------------------------------------------------*
* usb2_handle_request_callback
*
* This function is the USB callback for generic USB Device control
* transfers.
*------------------------------------------------------------------------*/
void
usb2_handle_request_callback(struct usb2_xfer *xfer)
{
usb2_error_t err;
/* check the current transfer state */
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
case USB_ST_TRANSFERRED:
/* handle the request */
err = usb2_handle_request(xfer);
if (err) {
if (err == USB_ERR_BAD_CONTEXT) {
/* we need to re-setup the control transfer */
usb2_needs_explore(xfer->udev->bus, 0);
break;
}
/*
* If no control transfer is active,
* receive the next SETUP message:
*/
goto tr_restart;
}
usb2_start_hardware(xfer);
break;
default:
if (xfer->error != USB_ERR_CANCELLED) {
/* should not happen - try stalling */
goto tr_restart;
}
break;
}
return;
tr_restart:
xfer->frlengths[0] = sizeof(struct usb2_device_request);
xfer->nframes = 1;
xfer->flags.manual_status = 1;
xfer->flags.force_short_xfer = 0;
xfer->flags.stall_pipe = 1; /* cancel previous transfer, if any */
usb2_start_hardware(xfer);
return;
}
/*------------------------------------------------------------------------*
* usb2_handle_set_config
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
static usb2_error_t
usb2_handle_set_config(struct usb2_xfer *xfer, uint8_t conf_no)
{
usb2_error_t err = 0;
/*
* We need to protect against other threads doing probe and
* attach:
*/
mtx_unlock(xfer->priv_mtx);
mtx_lock(&Giant); /* XXX */
sx_xlock(xfer->udev->default_sx + 1);
if (conf_no == USB_UNCONFIG_NO) {
conf_no = USB_UNCONFIG_INDEX;
} else {
/*
* The relationship between config number and config index
* is very simple in our case:
*/
conf_no--;
}
if (usb2_set_config_index(xfer->udev, conf_no)) {
DPRINTF("set config %d failed\n", conf_no);
err = USB_ERR_STALLED;
goto done;
}
if (usb2_probe_and_attach(xfer->udev, USB_IFACE_INDEX_ANY)) {
DPRINTF("probe and attach failed\n");
err = USB_ERR_STALLED;
goto done;
}
done:
mtx_unlock(&Giant); /* XXX */
sx_unlock(xfer->udev->default_sx + 1);
mtx_lock(xfer->priv_mtx);
return (err);
}
/*------------------------------------------------------------------------*
* usb2_handle_iface_request
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
static usb2_error_t
usb2_handle_iface_request(struct usb2_xfer *xfer,
void **ppdata, uint16_t *plen,
struct usb2_device_request req, uint16_t off, uint8_t state)
{
struct usb2_interface *iface;
struct usb2_interface *iface_parent; /* parent interface */
struct usb2_device *udev = xfer->udev;
int error;
uint8_t iface_index;
if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
iface_index = req.wIndex[0]; /* unicast */
} else {
iface_index = 0; /* broadcast */
}
/*
* We need to protect against other threads doing probe and
* attach:
*/
mtx_unlock(xfer->priv_mtx);
mtx_lock(&Giant); /* XXX */
sx_xlock(udev->default_sx + 1);
error = ENXIO;
tr_repeat:
iface = usb2_get_iface(udev, iface_index);
if ((iface == NULL) ||
(iface->idesc == NULL)) {
/* end of interfaces non-existing interface */
goto tr_stalled;
}
/* forward request to interface, if any */
if ((error != 0) &&
(error != ENOTTY) &&
(iface->subdev != NULL) &&
device_is_attached(iface->subdev)) {
#if 0
DEVMETHOD(usb2_handle_request, NULL); /* dummy */
#endif
error = USB2_HANDLE_REQUEST(iface->subdev,
&req, ppdata, plen,
off, (state == ST_POST_STATUS));
}
iface_parent = usb2_get_iface(udev, iface->parent_iface_index);
if ((iface_parent == NULL) ||
(iface_parent->idesc == NULL)) {
/* non-existing interface */
iface_parent = NULL;
}
/* forward request to parent interface, if any */
if ((error != 0) &&
(error != ENOTTY) &&
(iface_parent != NULL) &&
(iface_parent->subdev != NULL) &&
((req.bmRequestType & 0x1F) == UT_INTERFACE) &&
(iface_parent->subdev != iface->subdev) &&
device_is_attached(iface_parent->subdev)) {
error = USB2_HANDLE_REQUEST(iface_parent->subdev,
&req, ppdata, plen, off,
(state == ST_POST_STATUS));
}
if (error == 0) {
/* negativly adjust pointer and length */
*ppdata = ((uint8_t *)(*ppdata)) - off;
*plen += off;
goto tr_valid;
} else if (error == ENOTTY) {
goto tr_stalled;
}
if ((req.bmRequestType & 0x1F) != UT_INTERFACE) {
iface_index++; /* iterate */
goto tr_repeat;
}
if (state == ST_POST_STATUS) {
/* we are complete */
goto tr_valid;
}
switch (req.bmRequestType) {
case UT_WRITE_INTERFACE:
switch (req.bRequest) {
case UR_SET_INTERFACE:
/*
* Handle special case. If we have parent interface
* we just reset the endpoints, because this is a
* multi interface device and re-attaching only a
* part of the device is not possible. Also if the
* alternate setting is the same like before we just
* reset the interface endoints.
*/
if ((iface_parent != NULL) ||
(iface->alt_index == req.wValue[0])) {
error = usb2_reset_iface_endpoints(udev,
iface_index);
if (error) {
DPRINTF("alt setting failed %s\n",
usb2_errstr(error));
goto tr_stalled;
}
break;
}
error = usb2_set_alt_interface_index(udev,
iface_index, req.wValue[0]);
if (error) {
DPRINTF("alt setting failed %s\n",
usb2_errstr(error));
goto tr_stalled;
}
error = usb2_probe_and_attach(udev,
iface_index);
if (error) {
DPRINTF("alt setting probe failed\n");
goto tr_stalled;
}
break;
default:
goto tr_stalled;
}
break;
case UT_READ_INTERFACE:
switch (req.bRequest) {
case UR_GET_INTERFACE:
*ppdata = &iface->alt_index;
*plen = 1;
break;
default:
goto tr_stalled;
}
break;
default:
goto tr_stalled;
}
tr_valid:
mtx_unlock(&Giant);
sx_unlock(udev->default_sx + 1);
mtx_lock(xfer->priv_mtx);
return (0);
tr_stalled:
mtx_unlock(&Giant);
sx_unlock(udev->default_sx + 1);
mtx_lock(xfer->priv_mtx);
return (USB_ERR_STALLED);
}
/*------------------------------------------------------------------------*
* usb2_handle_stall
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
static usb2_error_t
usb2_handle_set_stall(struct usb2_xfer *xfer, uint8_t ep, uint8_t do_stall)
{
usb2_error_t err;
mtx_unlock(xfer->priv_mtx);
err = usb2_set_endpoint_stall(xfer->udev,
usb2_get_pipe_by_addr(xfer->udev, ep), do_stall);
mtx_lock(xfer->priv_mtx);
return (err);
}
/*------------------------------------------------------------------------*
* usb2_handle_get_stall
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
static uint8_t
usb2_handle_get_stall(struct usb2_device *udev, uint8_t ea_val)
{
struct usb2_pipe *pipe;
uint8_t halted;
pipe = usb2_get_pipe_by_addr(udev, ea_val);
if (pipe == NULL) {
/* nothing to do */
return (0);
}
mtx_lock(&udev->bus->mtx);
halted = pipe->is_stalled;
mtx_unlock(&udev->bus->mtx);
return (halted);
}
/*------------------------------------------------------------------------*
* usb2_handle_remote_wakeup
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
static usb2_error_t
usb2_handle_remote_wakeup(struct usb2_xfer *xfer, uint8_t is_on)
{
struct usb2_device *udev;
struct usb2_bus *bus;
udev = xfer->udev;
bus = udev->bus;
mtx_lock(&bus->mtx);
if (is_on) {
udev->flags.remote_wakeup = 1;
} else {
udev->flags.remote_wakeup = 0;
}
(bus->methods->rem_wakeup_set) (xfer->udev, is_on);
mtx_unlock(&bus->mtx);
return (0); /* success */
}
/*------------------------------------------------------------------------*
* usb2_handle_request
*
* Internal state sequence:
*
* ST_DATA -> ST_POST_STATUS
*
* Returns:
* 0: Ready to start hardware
* Else: Stall current transfer, if any
*------------------------------------------------------------------------*/
static usb2_error_t
usb2_handle_request(struct usb2_xfer *xfer)
{
struct usb2_device_request req;
struct usb2_device *udev;
const void *src_zcopy; /* zero-copy source pointer */
const void *src_mcopy; /* non zero-copy source pointer */
uint16_t off; /* data offset */
uint16_t rem; /* data remainder */
uint16_t max_len; /* max fragment length */
uint16_t wValue;
uint16_t wIndex;
uint8_t state;
usb2_error_t err;
union {
uWord wStatus;
uint8_t buf[2];
} temp;
/*
* Filter the USB transfer state into
* something which we understand:
*/
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
state = ST_DATA;
if (!xfer->flags_int.control_act) {
/* nothing to do */
goto tr_stalled;
}
break;
default: /* USB_ST_TRANSFERRED */
if (!xfer->flags_int.control_act) {
state = ST_POST_STATUS;
} else {
state = ST_DATA;
}
break;
}
/* reset frame stuff */
xfer->frlengths[0] = 0;
usb2_set_frame_offset(xfer, 0, 0);
usb2_set_frame_offset(xfer, sizeof(req), 1);
/* get the current request, if any */
usb2_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
if (xfer->flags_int.control_rem == 0xFFFF) {
/* first time - not initialised */
rem = UGETW(req.wLength);
off = 0;
} else {
/* not first time - initialised */
rem = xfer->flags_int.control_rem;
off = UGETW(req.wLength) - rem;
}
/* set some defaults */
max_len = 0;
src_zcopy = NULL;
src_mcopy = NULL;
udev = xfer->udev;
/* get some request fields decoded */
wValue = UGETW(req.wValue);
wIndex = UGETW(req.wIndex);
DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x "
"off=0x%x rem=0x%x, state=%d\n", req.bmRequestType,
req.bRequest, wValue, wIndex, off, rem, state);
/* demultiplex the control request */
switch (req.bmRequestType) {
case UT_READ_DEVICE:
if (state != ST_DATA) {
break;
}
switch (req.bRequest) {
case UR_GET_DESCRIPTOR:
goto tr_handle_get_descriptor;
case UR_GET_CONFIG:
goto tr_handle_get_config;
case UR_GET_STATUS:
goto tr_handle_get_status;
default:
goto tr_stalled;
}
break;
case UT_WRITE_DEVICE:
switch (req.bRequest) {
case UR_SET_ADDRESS:
goto tr_handle_set_address;
case UR_SET_CONFIG:
goto tr_handle_set_config;
case UR_CLEAR_FEATURE:
switch (wValue) {
case UF_DEVICE_REMOTE_WAKEUP:
goto tr_handle_clear_wakeup;
default:
goto tr_stalled;
}
break;
case UR_SET_FEATURE:
switch (wValue) {
case UF_DEVICE_REMOTE_WAKEUP:
goto tr_handle_set_wakeup;
default:
goto tr_stalled;
}
break;
default:
goto tr_stalled;
}
break;
case UT_WRITE_ENDPOINT:
switch (req.bRequest) {
case UR_CLEAR_FEATURE:
switch (wValue) {
case UF_ENDPOINT_HALT:
goto tr_handle_clear_halt;
default:
goto tr_stalled;
}
break;
case UR_SET_FEATURE:
switch (wValue) {
case UF_ENDPOINT_HALT:
goto tr_handle_set_halt;
default:
goto tr_stalled;
}
break;
default:
goto tr_stalled;
}
break;
case UT_READ_ENDPOINT:
switch (req.bRequest) {
case UR_GET_STATUS:
goto tr_handle_get_ep_status;
default:
goto tr_stalled;
}
break;
default:
/* we use "USB_ADD_BYTES" to de-const the src_zcopy */
err = usb2_handle_iface_request(xfer,
USB_ADD_BYTES(&src_zcopy, 0),
&max_len, req, off, state);
if (err == 0) {
goto tr_valid;
}
/*
* Reset zero-copy pointer and max length
* variable in case they were unintentionally
* set:
*/
src_zcopy = NULL;
max_len = 0;
/*
* Check if we have a vendor specific
* descriptor:
*/
goto tr_handle_get_descriptor;
}
goto tr_valid;
tr_handle_get_descriptor:
(usb2_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len);
if (src_zcopy == NULL) {
goto tr_stalled;
}
goto tr_valid;
tr_handle_get_config:
temp.buf[0] = udev->curr_config_no;
src_mcopy = temp.buf;
max_len = 1;
goto tr_valid;
tr_handle_get_status:
wValue = 0;
mtx_lock(&udev->bus->mtx);
if (udev->flags.remote_wakeup) {
wValue |= UDS_REMOTE_WAKEUP;
}
if (udev->flags.self_powered) {
wValue |= UDS_SELF_POWERED;
}
mtx_unlock(&udev->bus->mtx);
USETW(temp.wStatus, wValue);
src_mcopy = temp.wStatus;
max_len = sizeof(temp.wStatus);
goto tr_valid;
tr_handle_set_address:
if (state == ST_DATA) {
if (wValue >= 0x80) {
/* invalid value */
goto tr_stalled;
} else if (udev->curr_config_no != 0) {
/* we are configured ! */
goto tr_stalled;
}
} else if (state == ST_POST_STATUS) {
udev->address = (wValue & 0x7F);
goto tr_bad_context;
}
goto tr_valid;
tr_handle_set_config:
if (state == ST_DATA) {
if (usb2_handle_set_config(xfer, req.wValue[0])) {
goto tr_stalled;
}
}
goto tr_valid;
tr_handle_clear_halt:
if (state == ST_DATA) {
if (usb2_handle_set_stall(xfer, req.wIndex[0], 0)) {
goto tr_stalled;
}
}
goto tr_valid;
tr_handle_clear_wakeup:
if (state == ST_DATA) {
if (usb2_handle_remote_wakeup(xfer, 0)) {
goto tr_stalled;
}
}
goto tr_valid;
tr_handle_set_halt:
if (state == ST_DATA) {
if (usb2_handle_set_stall(xfer, req.wIndex[0], 1)) {
goto tr_stalled;
}
}
goto tr_valid;
tr_handle_set_wakeup:
if (state == ST_DATA) {
if (usb2_handle_remote_wakeup(xfer, 1)) {
goto tr_stalled;
}
}
goto tr_valid;
tr_handle_get_ep_status:
if (state == ST_DATA) {
temp.wStatus[0] =
usb2_handle_get_stall(udev, req.wIndex[0]);
temp.wStatus[1] = 0;
src_mcopy = temp.wStatus;
max_len = sizeof(temp.wStatus);
}
goto tr_valid;
tr_valid:
if (state == ST_POST_STATUS) {
goto tr_stalled;
}
/* subtract offset from length */
max_len -= off;
/* Compute the real maximum data length */
if (max_len > xfer->max_data_length) {
max_len = xfer->max_data_length;
}
if (max_len > rem) {
max_len = rem;
}
/*
* If the remainder is greater than the maximum data length,
* we need to truncate the value for the sake of the
* comparison below:
*/
if (rem > xfer->max_data_length) {
rem = xfer->max_data_length;
}
if (rem != max_len) {
/*
* If we don't transfer the data we can transfer, then
* the transfer is short !
*/
xfer->flags.force_short_xfer = 1;
xfer->nframes = 2;
} else {
/*
* Default case
*/
xfer->flags.force_short_xfer = 0;
xfer->nframes = max_len ? 2 : 1;
}
if (max_len > 0) {
if (src_mcopy) {
src_mcopy = USB_ADD_BYTES(src_mcopy, off);
usb2_copy_in(xfer->frbuffers + 1, 0,
src_mcopy, max_len);
} else {
usb2_set_frame_data(xfer,
USB_ADD_BYTES(src_zcopy, off), 1);
}
xfer->frlengths[1] = max_len;
} else {
/* the end is reached, send status */
xfer->flags.manual_status = 0;
xfer->frlengths[1] = 0;
}
DPRINTF("success\n");
return (0); /* success */
tr_stalled:
DPRINTF("%s\n", (state == ST_POST_STATUS) ?
"complete" : "stalled");
return (USB_ERR_STALLED);
tr_bad_context:
DPRINTF("bad context\n");
return (USB_ERR_BAD_CONTEXT);
}

View File

@ -0,0 +1,30 @@
/* $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.
*/
#ifndef _USB2_HANDLE_REQUEST_H_
#define _USB2_HANDLE_REQUEST_H_
#endif /* _USB2_HANDLE_REQUEST_H_ */

View File

@ -0,0 +1,582 @@
/* $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_hid.h>
#define USB_DEBUG_VAR usb2_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_parse.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_device.h>
#include <dev/usb2/core/usb2_request.h>
#include <dev/usb2/core/usb2_hid.h>
static void hid_clear_local(struct hid_item *);
#define MAXUSAGE 100
struct hid_data {
const uint8_t *start;
const uint8_t *end;
const uint8_t *p;
struct hid_item cur;
int32_t usages[MAXUSAGE];
int nu;
int minset;
int multi;
int multimax;
int kindset;
};
/*------------------------------------------------------------------------*
* hid_clear_local
*------------------------------------------------------------------------*/
static void
hid_clear_local(struct hid_item *c)
{
c->usage = 0;
c->usage_minimum = 0;
c->usage_maximum = 0;
c->designator_index = 0;
c->designator_minimum = 0;
c->designator_maximum = 0;
c->string_index = 0;
c->string_minimum = 0;
c->string_maximum = 0;
c->set_delimiter = 0;
}
/*------------------------------------------------------------------------*
* hid_start_parse
*------------------------------------------------------------------------*/
struct hid_data *
hid_start_parse(const void *d, int len, int kindset)
{
struct hid_data *s;
s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
s->start = s->p = d;
s->end = ((const uint8_t *)d) + len;
s->kindset = kindset;
return (s);
}
/*------------------------------------------------------------------------*
* hid_end_parse
*------------------------------------------------------------------------*/
void
hid_end_parse(struct hid_data *s)
{
while (s->cur.next != NULL) {
struct hid_item *hi = s->cur.next->next;
free(s->cur.next, M_TEMP);
s->cur.next = hi;
}
free(s, M_TEMP);
}
/*------------------------------------------------------------------------*
* hid_get_item
*------------------------------------------------------------------------*/
int
hid_get_item(struct hid_data *s, struct hid_item *h)
{
struct hid_item *c = &s->cur;
unsigned int bTag, bType, bSize;
uint32_t oldpos;
const uint8_t *data;
int32_t dval;
const uint8_t *p;
struct hid_item *hi;
int i;
top:
if (s->multimax != 0) {
if (s->multi < s->multimax) {
c->usage = s->usages[MIN(s->multi, s->nu - 1)];
s->multi++;
*h = *c;
c->loc.pos += c->loc.size;
h->next = 0;
return (1);
} else {
c->loc.count = s->multimax;
s->multimax = 0;
s->nu = 0;
hid_clear_local(c);
}
}
for (;;) {
p = s->p;
if (p >= s->end)
return (0);
bSize = *p++;
if (bSize == 0xfe) {
/* long item */
bSize = *p++;
bSize |= *p++ << 8;
bTag = *p++;
data = p;
p += bSize;
bType = 0xff; /* XXX what should it be */
} else {
/* short item */
bTag = bSize >> 4;
bType = (bSize >> 2) & 3;
bSize &= 3;
if (bSize == 3)
bSize = 4;
data = p;
p += bSize;
}
s->p = p;
switch (bSize) {
case 0:
dval = 0;
break;
case 1:
dval = (int8_t)*data++;
break;
case 2:
dval = *data++;
dval |= *data++ << 8;
dval = (int16_t)dval;
break;
case 4:
dval = *data++;
dval |= *data++ << 8;
dval |= *data++ << 16;
dval |= *data++ << 24;
break;
default:
printf("BAD LENGTH %d\n", bSize);
continue;
}
switch (bType) {
case 0: /* Main */
switch (bTag) {
case 8: /* Input */
if (!(s->kindset & (1 << hid_input))) {
if (s->nu > 0)
s->nu--;
continue;
}
c->kind = hid_input;
c->flags = dval;
ret:
if (c->flags & HIO_VARIABLE) {
s->multimax = c->loc.count;
s->multi = 0;
c->loc.count = 1;
if (s->minset) {
for (i = c->usage_minimum;
i <= c->usage_maximum;
i++) {
s->usages[s->nu] = i;
if (s->nu < MAXUSAGE - 1)
s->nu++;
}
s->minset = 0;
}
goto top;
} else {
*h = *c;
h->next = 0;
c->loc.pos +=
c->loc.size * c->loc.count;
hid_clear_local(c);
s->minset = 0;
return (1);
}
case 9: /* Output */
if (!(s->kindset & (1 << hid_output))) {
if (s->nu > 0)
s->nu--;
continue;
}
c->kind = hid_output;
c->flags = dval;
goto ret;
case 10: /* Collection */
c->kind = hid_collection;
c->collection = dval;
c->collevel++;
*h = *c;
hid_clear_local(c);
s->nu = 0;
return (1);
case 11: /* Feature */
if (!(s->kindset & (1 << hid_feature))) {
if (s->nu > 0)
s->nu--;
continue;
}
c->kind = hid_feature;
c->flags = dval;
goto ret;
case 12: /* End collection */
c->kind = hid_endcollection;
c->collevel--;
*h = *c;
hid_clear_local(c);
s->nu = 0;
return (1);
default:
printf("Main bTag=%d\n", bTag);
break;
}
break;
case 1: /* Global */
switch (bTag) {
case 0:
c->_usage_page = dval << 16;
break;
case 1:
c->logical_minimum = dval;
break;
case 2:
c->logical_maximum = dval;
break;
case 3:
c->physical_minimum = dval;
break;
case 4:
c->physical_maximum = dval;
break;
case 5:
c->unit_exponent = dval;
break;
case 6:
c->unit = dval;
break;
case 7:
c->loc.size = dval;
break;
case 8:
c->report_ID = dval;
break;
case 9:
c->loc.count = dval;
break;
case 10: /* Push */
hi = malloc(sizeof *hi, M_TEMP, M_WAITOK);
*hi = s->cur;
c->next = hi;
break;
case 11: /* Pop */
hi = c->next;
oldpos = c->loc.pos;
s->cur = *hi;
c->loc.pos = oldpos;
free(hi, M_TEMP);
break;
default:
printf("Global bTag=%d\n", bTag);
break;
}
break;
case 2: /* Local */
switch (bTag) {
case 0:
if (bSize == 1)
dval = c->_usage_page | (dval & 0xff);
else if (bSize == 2)
dval = c->_usage_page | (dval & 0xffff);
c->usage = dval;
if (s->nu < MAXUSAGE)
s->usages[s->nu++] = dval;
/* else XXX */
break;
case 1:
s->minset = 1;
if (bSize == 1)
dval = c->_usage_page | (dval & 0xff);
else if (bSize == 2)
dval = c->_usage_page | (dval & 0xffff);
c->usage_minimum = dval;
break;
case 2:
if (bSize == 1)
dval = c->_usage_page | (dval & 0xff);
else if (bSize == 2)
dval = c->_usage_page | (dval & 0xffff);
c->usage_maximum = dval;
break;
case 3:
c->designator_index = dval;
break;
case 4:
c->designator_minimum = dval;
break;
case 5:
c->designator_maximum = dval;
break;
case 7:
c->string_index = dval;
break;
case 8:
c->string_minimum = dval;
break;
case 9:
c->string_maximum = dval;
break;
case 10:
c->set_delimiter = dval;
break;
default:
printf("Local bTag=%d\n", bTag);
break;
}
break;
default:
printf("default bType=%d\n", bType);
break;
}
}
}
/*------------------------------------------------------------------------*
* hid_report_size
*------------------------------------------------------------------------*/
int
hid_report_size(const void *buf, int len, enum hid_kind k, uint8_t *idp)
{
struct hid_data *d;
struct hid_item h;
int hi, lo, size, id;
id = 0;
hi = lo = -1;
for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);)
if (h.kind == k) {
if (h.report_ID != 0 && !id)
id = h.report_ID;
if (h.report_ID == id) {
if (lo < 0)
lo = h.loc.pos;
hi = h.loc.pos + h.loc.size * h.loc.count;
}
}
hid_end_parse(d);
size = hi - lo;
if (id != 0) {
size += 8;
*idp = id; /* XXX wrong */
} else
*idp = 0;
return ((size + 7) / 8);
}
/*------------------------------------------------------------------------*
* hid_locate
*------------------------------------------------------------------------*/
int
hid_locate(const void *desc, int size, uint32_t u, enum hid_kind k,
struct hid_location *loc, uint32_t *flags)
{
struct hid_data *d;
struct hid_item h;
for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
if (loc != NULL)
*loc = h.loc;
if (flags != NULL)
*flags = h.flags;
hid_end_parse(d);
return (1);
}
}
hid_end_parse(d);
loc->size = 0;
return (0);
}
/*------------------------------------------------------------------------*
* hid_get_data
*------------------------------------------------------------------------*/
uint32_t
hid_get_data(const uint8_t *buf, uint32_t len, struct hid_location *loc)
{
uint32_t hpos = loc->pos;
uint32_t hsize = loc->size;
uint32_t data;
int i, s, t;
DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
if (hsize == 0)
return (0);
data = 0;
s = hpos / 8;
for (i = hpos; i < (hpos + hsize); i += 8) {
t = (i / 8);
if (t < len) {
data |= buf[t] << ((t - s) * 8);
}
}
data >>= hpos % 8;
data &= (1 << hsize) - 1;
hsize = 32 - hsize;
/* Sign extend */
data = ((int32_t)data << hsize) >> hsize;
DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
loc->pos, loc->size, (long)data);
return (data);
}
/*------------------------------------------------------------------------*
* hid_is_collection
*------------------------------------------------------------------------*/
int
hid_is_collection(const void *desc, int size, uint32_t usage)
{
struct hid_data *hd;
struct hid_item hi;
int err;
hd = hid_start_parse(desc, size, hid_input);
if (hd == NULL)
return (0);
err = hid_get_item(hd, &hi) &&
hi.kind == hid_collection &&
hi.usage == usage;
hid_end_parse(hd);
return (err);
}
/*------------------------------------------------------------------------*
* hid_get_descriptor_from_usb
*
* This function will search for a HID descriptor between two USB
* interface descriptors.
*
* Return values:
* NULL: No more HID descriptors.
* Else: Pointer to HID descriptor.
*------------------------------------------------------------------------*/
struct usb2_hid_descriptor *
hid_get_descriptor_from_usb(struct usb2_config_descriptor *cd,
struct usb2_interface_descriptor *id)
{
struct usb2_descriptor *desc = (void *)id;
if (desc == NULL) {
return (NULL);
}
while ((desc = usb2_desc_foreach(cd, desc))) {
if ((desc->bDescriptorType == UDESC_HID) &&
(desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
return (void *)desc;
}
if (desc->bDescriptorType == UDESC_INTERFACE) {
break;
}
}
return (NULL);
}
/*------------------------------------------------------------------------*
* usb2_req_get_hid_desc
*
* This function will read out an USB report descriptor from the USB
* device.
*
* Return values:
* NULL: Failure.
* Else: Success. The pointer should eventually be passed to free().
*------------------------------------------------------------------------*/
usb2_error_t
usb2_req_get_hid_desc(struct usb2_device *udev, struct mtx *mtx,
void **descp, uint16_t *sizep,
usb2_malloc_type mem, uint8_t iface_index)
{
struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
struct usb2_hid_descriptor *hid;
usb2_error_t err;
if ((iface == NULL) || (iface->idesc == NULL)) {
return (USB_ERR_INVAL);
}
hid = hid_get_descriptor_from_usb
(usb2_get_config_descriptor(udev), iface->idesc);
if (hid == NULL) {
return (USB_ERR_IOERROR);
}
*sizep = UGETW(hid->descrs[0].wDescriptorLength);
if (*sizep == 0) {
return (USB_ERR_IOERROR);
}
if (mtx)
mtx_unlock(mtx);
*descp = malloc(*sizep, mem, M_ZERO | M_WAITOK);
if (mtx)
mtx_lock(mtx);
if (*descp == NULL) {
return (USB_ERR_NOMEM);
}
err = usb2_req_get_report_descriptor
(udev, mtx, *descp, *sizep, iface_index);
if (err) {
free(*descp, mem);
*descp = NULL;
return (err);
}
return (USB_ERR_NORMAL_COMPLETION);
}

View File

@ -0,0 +1,89 @@
/* $FreeBSD$ */
/*-
* Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
* Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.
* Copyright (c) 1998 Lennart Augustsson. 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.
*/
#ifndef _USB2_CORE_HID_H_
#define _USB2_CORE_HID_H_
struct usb2_hid_descriptor;
struct usb2_config_descriptor;
enum hid_kind {
hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
};
struct hid_location {
uint32_t size;
uint32_t count;
uint32_t pos;
};
struct hid_item {
/* Global */
int32_t _usage_page;
int32_t logical_minimum;
int32_t logical_maximum;
int32_t physical_minimum;
int32_t physical_maximum;
int32_t unit_exponent;
int32_t unit;
int32_t report_ID;
/* Local */
int32_t usage;
int32_t usage_minimum;
int32_t usage_maximum;
int32_t designator_index;
int32_t designator_minimum;
int32_t designator_maximum;
int32_t string_index;
int32_t string_minimum;
int32_t string_maximum;
int32_t set_delimiter;
/* Misc */
int32_t collection;
int collevel;
enum hid_kind kind;
uint32_t flags;
/* Location */
struct hid_location loc;
/* */
struct hid_item *next;
};
/* prototypes from "usb2_hid.c" */
struct hid_data *hid_start_parse(const void *d, int len, int kindset);
void hid_end_parse(struct hid_data *s);
int hid_get_item(struct hid_data *s, struct hid_item *h);
int hid_report_size(const void *buf, int len, enum hid_kind k, uint8_t *id);
int hid_locate(const void *desc, int size, uint32_t usage, enum hid_kind kind, struct hid_location *loc, uint32_t *flags);
uint32_t hid_get_data(const uint8_t *buf, uint32_t len, struct hid_location *loc);
int hid_is_collection(const void *desc, int size, uint32_t usage);
struct usb2_hid_descriptor *hid_get_descriptor_from_usb(struct usb2_config_descriptor *cd, struct usb2_interface_descriptor *id);
usb2_error_t usb2_req_get_hid_desc(struct usb2_device *udev, struct mtx *mtx, void **descp, uint16_t *sizep, usb2_malloc_type mem, uint8_t iface_index);
#endif /* _USB2_CORE_HID_H_ */

1330
sys/dev/usb2/core/usb2_hub.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,75 @@
/* $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.
*/
#ifndef _USB2_HUB_H_
#define _USB2_HUB_H_
/*
* The following structure defines an USB port.
*/
struct usb2_port {
uint8_t restartcnt;
#define USB_RESTART_MAX 5
uint8_t device_index; /* zero means not valid */
uint8_t usb2_mode:1; /* current USB mode */
uint8_t unused:7;
};
/*
* The following structure defines how many bytes are
* left in an 1ms USB time slot.
*/
struct usb2_fs_isoc_schedule {
uint16_t total_bytes;
uint8_t frame_bytes;
uint8_t frame_slot;
};
/*
* The following structure defines an USB HUB.
*/
struct usb2_hub {
struct usb2_fs_isoc_schedule fs_isoc_schedule[USB_ISOC_TIME_MAX];
struct usb2_device *hubudev; /* the HUB device */
usb2_error_t (*explore) (struct usb2_device *hub);
void *hubsoftc;
uint32_t uframe_usage[USB_HS_MICRO_FRAMES_MAX];
uint16_t portpower; /* mA per USB port */
uint8_t isoc_last_time;
uint8_t nports;
struct usb2_port ports[0];
};
/* function prototypes */
uint8_t usb2_intr_schedule_adjust(struct usb2_device *udev, int16_t len, uint8_t slot);
void usb2_fs_isoc_schedule_init_all(struct usb2_fs_isoc_schedule *fss);
void usb2_bus_port_set_device(struct usb2_bus *bus, struct usb2_port *up, struct usb2_device *udev, uint8_t device_index);
struct usb2_device *usb2_bus_port_get_device(struct usb2_bus *bus, struct usb2_port *up);
void usb2_needs_explore(struct usb2_bus *bus, uint8_t do_probe);
void usb2_needs_explore_all(void);
#endif /* _USB2_HUB_H_ */

View File

@ -0,0 +1,52 @@
#-
# 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,
# without modification, immediately at the beginning of the file.
# 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.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# 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.
#
# $FreeBSD$
#
# USB interface description
#
#include <sys/bus.h>
INTERFACE usb2;
# The device received a control request
#
# Return values:
# 0: Success
# ENOTTY: Transaction stalled
# Else: Use builtin request handler
#
METHOD int handle_request {
device_t dev;
const void *req; /* pointer to the device request */
void **pptr; /* data pointer */
uint16_t *plen; /* maximum transfer length */
uint16_t offset; /* data offset */
uint8_t is_complete; /* set if transfer is complete */
};

View File

@ -0,0 +1,134 @@
/* $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 <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_lookup.h>
/*------------------------------------------------------------------------*
* usb2_lookup_id_by_info
*
* This functions takes an array of "struct usb2_device_id" and tries
* to match the entries with the information in "struct usb2_lookup_info".
*
* NOTE: The "sizeof_id" parameter must be a multiple of the
* usb2_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 usb2_device_id *
usb2_lookup_id_by_info(const struct usb2_device_id *id, uint32_t sizeof_id,
const struct usb2_lookup_info *info)
{
const struct usb2_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 ((info->bDeviceClass == 0xFF) &&
(!(id->match_flag_vendor)) &&
((id->match_flag_int_class) ||
(id->match_flag_int_subclass) ||
(id->match_flag_int_protocol))) {
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);
}
/*------------------------------------------------------------------------*
* usb2_lookup_id_by_uaa - factored out code
*
* Return values:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
int
usb2_lookup_id_by_uaa(const struct usb2_device_id *id, uint32_t sizeof_id,
struct usb2_attach_arg *uaa)
{
id = usb2_lookup_id_by_info(id, sizeof_id, &uaa->info);
if (id) {
/* copy driver info */
uaa->driver_info = id->driver_info;
return (0);
}
return (ENXIO);
}

View File

@ -0,0 +1,119 @@
/* $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.
*/
#ifndef _USB2_LOOKUP_H_
#define _USB2_LOOKUP_H_
struct usb2_attach_arg;
/*
* The following structure is used when looking up an USB driver for
* an USB device. It is inspired by the Linux structure called
* "usb2_device_id".
*/
struct usb2_device_id {
/* Hook for driver specific information */
const void *driver_info;
/* 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;
/* Select which fields to match against */
uint8_t match_flag_vendor:1;
uint8_t match_flag_product:1;
uint8_t match_flag_dev_lo:1;
uint8_t match_flag_dev_hi:1;
uint8_t match_flag_dev_class:1;
uint8_t match_flag_dev_subclass:1;
uint8_t match_flag_dev_protocol:1;
uint8_t match_flag_int_class:1;
uint8_t match_flag_int_subclass:1;
uint8_t match_flag_int_protocol: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(ptr) \
.driver_info = ((const void *)(ptr))
#define USB_GET_DRIVER_INFO(did) \
(((const uint8_t *)((did)->driver_info)) - ((const uint8_t *)0))
const struct usb2_device_id *usb2_lookup_id_by_info(const struct usb2_device_id *id, uint32_t sizeof_id, const struct usb2_lookup_info *info);
int usb2_lookup_id_by_uaa(const struct usb2_device_id *id, uint32_t sizeof_id, struct usb2_attach_arg *uaa);
#endif /* _USB2_LOOKUP_H_ */

View File

@ -0,0 +1,77 @@
/* $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 <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_mbuf.h>
/*------------------------------------------------------------------------*
* usb2_alloc_mbufs - allocate mbufs to an usbd interface queue
*
* Returns:
* A pointer that should be passed to "free()" when the buffer(s)
* should be released.
*------------------------------------------------------------------------*/
void *
usb2_alloc_mbufs(struct malloc_type *type, struct usb2_ifqueue *ifq,
uint32_t block_size, uint16_t nblocks)
{
struct usb2_mbuf *m_ptr;
uint8_t *data_ptr;
void *free_ptr = NULL;
uint32_t alloc_size;
/* align data */
block_size += ((-block_size) & (USB_HOST_ALIGN - 1));
if (nblocks && block_size) {
alloc_size = (block_size + sizeof(struct usb2_mbuf)) * nblocks;
free_ptr = malloc(alloc_size, type, M_WAITOK | M_ZERO);
if (free_ptr == NULL) {
goto done;
}
m_ptr = free_ptr;
data_ptr = (void *)(m_ptr + nblocks);
while (nblocks--) {
m_ptr->cur_data_ptr =
m_ptr->min_data_ptr = data_ptr;
m_ptr->cur_data_len =
m_ptr->max_data_len = block_size;
USB_IF_ENQUEUE(ifq, m_ptr);
m_ptr++;
data_ptr += block_size;
}
}
done:
return (free_ptr);
}

View File

@ -0,0 +1,100 @@
/* $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.
*/
#ifndef _USB2_MBUF_H_
#define _USB2_MBUF_H_
/*
* The following structure defines a minimum re-implementation of the
* mbuf system in the kernel.
*/
struct usb2_mbuf {
uint8_t *cur_data_ptr;
uint8_t *min_data_ptr;
struct usb2_mbuf *usb2_nextpkt;
struct usb2_mbuf *usb2_next;
uint32_t cur_data_len;
uint32_t max_data_len:31;
uint32_t last_packet:1;
};
/*
* The following structure defines a minimum re-implementation of the
* ifqueue structure in the kernel.
*/
struct usb2_ifqueue {
struct usb2_mbuf *ifq_head;
struct usb2_mbuf *ifq_tail;
uint32_t ifq_len;
uint32_t ifq_maxlen;
};
#define USB_IF_ENQUEUE(ifq, m) do { \
(m)->usb2_nextpkt = NULL; \
if ((ifq)->ifq_tail == NULL) \
(ifq)->ifq_head = (m); \
else \
(ifq)->ifq_tail->usb2_nextpkt = (m); \
(ifq)->ifq_tail = (m); \
(ifq)->ifq_len++; \
} while (0)
#define USB_IF_DEQUEUE(ifq, m) do { \
(m) = (ifq)->ifq_head; \
if (m) { \
if (((ifq)->ifq_head = (m)->usb2_nextpkt) == NULL) { \
(ifq)->ifq_tail = NULL; \
} \
(m)->usb2_nextpkt = NULL; \
(ifq)->ifq_len--; \
} \
} while (0)
#define USB_IF_PREPEND(ifq, m) do { \
(m)->usb2_nextpkt = (ifq)->ifq_head; \
if ((ifq)->ifq_tail == NULL) { \
(ifq)->ifq_tail = (m); \
} \
(ifq)->ifq_head = (m); \
(ifq)->ifq_len++; \
} while (0)
#define USB_IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen)
#define USB_IF_QLEN(ifq) ((ifq)->ifq_len)
#define USB_IF_POLL(ifq, m) ((m) = (ifq)->ifq_head)
#define USB_MBUF_RESET(m) do { \
(m)->cur_data_ptr = (m)->min_data_ptr; \
(m)->cur_data_len = (m)->max_data_len; \
(m)->last_packet = 0; \
} while (0)
/* prototypes */
void *usb2_alloc_mbufs(struct malloc_type *type, struct usb2_ifqueue *ifq, uint32_t block_size, uint16_t nblocks);
#endif /* _USB2_MBUF_H_ */

View File

@ -0,0 +1,612 @@
/* $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.
*/
/*
* The following file contains code that will detect USB autoinstall
* disks.
*
* TODO: Potentially we could add code to automatically detect USB
* mass storage quirks for not supported SCSI commands!
*/
#include <dev/usb2/include/usb2_defs.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_standard.h>
#define USB_DEBUG_VAR usb2_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_transfer.h>
#include <dev/usb2/core/usb2_msctest.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_busdma.h>
#include <dev/usb2/core/usb2_device.h>
#include <dev/usb2/core/usb2_request.h>
#include <dev/usb2/core/usb2_util.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/include/usb2_error.h>
#include <dev/usb2/include/usb2_standard.h>
enum {
ST_COMMAND,
ST_DATA_RD,
ST_DATA_RD_CS,
ST_DATA_WR,
ST_DATA_WR_CS,
ST_STATUS,
ST_MAX,
};
enum {
DIR_IN,
DIR_OUT,
DIR_NONE,
};
#define BULK_SIZE 64 /* dummy */
/* Command Block Wrapper */
struct bbb_cbw {
uDWord dCBWSignature;
#define CBWSIGNATURE 0x43425355
uDWord dCBWTag;
uDWord dCBWDataTransferLength;
uByte bCBWFlags;
#define CBWFLAGS_OUT 0x00
#define CBWFLAGS_IN 0x80
uByte bCBWLUN;
uByte bCDBLength;
#define CBWCDBLENGTH 16
uByte CBWCDB[CBWCDBLENGTH];
} __packed;
/* Command Status Wrapper */
struct bbb_csw {
uDWord dCSWSignature;
#define CSWSIGNATURE 0x53425355
uDWord dCSWTag;
uDWord dCSWDataResidue;
uByte bCSWStatus;
#define CSWSTATUS_GOOD 0x0
#define CSWSTATUS_FAILED 0x1
#define CSWSTATUS_PHASE 0x2
} __packed;
struct bbb_transfer {
struct mtx mtx;
struct cv cv;
struct bbb_cbw cbw;
struct bbb_csw csw;
struct usb2_xfer *xfer[ST_MAX];
uint8_t *data_ptr;
uint32_t data_len; /* bytes */
uint32_t data_rem; /* bytes */
uint32_t data_timeout; /* ms */
uint32_t actlen; /* bytes */
uint8_t cmd_len; /* bytes */
uint8_t dir;
uint8_t lun;
uint8_t state;
uint8_t error;
uint8_t status_try;
uint8_t buffer[256];
};
static usb2_callback_t bbb_command_callback;
static usb2_callback_t bbb_data_read_callback;
static usb2_callback_t bbb_data_rd_cs_callback;
static usb2_callback_t bbb_data_write_callback;
static usb2_callback_t bbb_data_wr_cs_callback;
static usb2_callback_t bbb_status_callback;
static const struct usb2_config bbb_config[ST_MAX] = {
[ST_COMMAND] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.mh.bufsize = sizeof(struct bbb_cbw),
.mh.flags = {},
.mh.callback = &bbb_command_callback,
.mh.timeout = 4 * USB_MS_HZ, /* 4 seconds */
},
[ST_DATA_RD] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.mh.bufsize = BULK_SIZE,
.mh.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
.mh.callback = &bbb_data_read_callback,
.mh.timeout = 4 * USB_MS_HZ, /* 4 seconds */
},
[ST_DATA_RD_CS] = {
.type = UE_CONTROL,
.endpoint = 0x00, /* Control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
.mh.flags = {},
.mh.callback = &bbb_data_rd_cs_callback,
.mh.timeout = 1 * USB_MS_HZ, /* 1 second */
},
[ST_DATA_WR] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.mh.bufsize = BULK_SIZE,
.mh.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
.mh.callback = &bbb_data_write_callback,
.mh.timeout = 4 * USB_MS_HZ, /* 4 seconds */
},
[ST_DATA_WR_CS] = {
.type = UE_CONTROL,
.endpoint = 0x00, /* Control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
.mh.flags = {},
.mh.callback = &bbb_data_wr_cs_callback,
.mh.timeout = 1 * USB_MS_HZ, /* 1 second */
},
[ST_STATUS] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.mh.bufsize = sizeof(struct bbb_csw),
.mh.flags = {.short_xfer_ok = 1,},
.mh.callback = &bbb_status_callback,
.mh.timeout = 1 * USB_MS_HZ, /* 1 second */
},
};
static void
bbb_done(struct bbb_transfer *sc, uint8_t error)
{
struct usb2_xfer *xfer;
xfer = sc->xfer[sc->state];
/* verify the error code */
if (error) {
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
case USB_ST_TRANSFERRED:
error = 1;
break;
default:
error = 2;
break;
}
}
sc->error = error;
sc->state = ST_COMMAND;
sc->status_try = 1;
usb2_cv_signal(&sc->cv);
return;
}
static void
bbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index)
{
sc->state = xfer_index;
usb2_transfer_start(sc->xfer[xfer_index]);
return;
}
static void
bbb_data_clear_stall_callback(struct usb2_xfer *xfer,
uint8_t next_xfer, uint8_t stall_xfer)
{
struct bbb_transfer *sc = xfer->priv_sc;
if (usb2_clear_stall_callback(xfer, sc->xfer[stall_xfer])) {
switch (USB_GET_STATE(xfer)) {
case USB_ST_SETUP:
case USB_ST_TRANSFERRED:
bbb_transfer_start(sc, next_xfer);
break;
default:
bbb_done(sc, 1);
break;
}
}
return;
}
static void
bbb_command_callback(struct usb2_xfer *xfer)
{
struct bbb_transfer *sc = xfer->priv_sc;
uint32_t tag;
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
bbb_transfer_start
(sc, ((sc->dir == DIR_IN) ? ST_DATA_RD :
(sc->dir == DIR_OUT) ? ST_DATA_WR :
ST_STATUS));
break;
case USB_ST_SETUP:
sc->status_try = 0;
tag = UGETDW(sc->cbw.dCBWTag) + 1;
USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
USETDW(sc->cbw.dCBWTag, tag);
USETDW(sc->cbw.dCBWDataTransferLength, sc->data_len);
sc->cbw.bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT);
sc->cbw.bCBWLUN = sc->lun;
if (sc->cbw.bCDBLength > sizeof(sc->cbw.CBWCDB)) {
sc->cbw.bCDBLength = sizeof(sc->cbw.CBWCDB);
DPRINTFN(0, "Truncating long command!\n");
}
xfer->frlengths[0] = sizeof(sc->cbw);
usb2_set_frame_data(xfer, &sc->cbw, 0);
usb2_start_hardware(xfer);
break;
default: /* Error */
bbb_done(sc, 1);
break;
}
return;
}
static void
bbb_data_read_callback(struct usb2_xfer *xfer)
{
struct bbb_transfer *sc = xfer->priv_sc;
uint32_t max_bulk = xfer->max_data_length;
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
sc->data_rem -= xfer->actlen;
sc->data_ptr += xfer->actlen;
sc->actlen += xfer->actlen;
if (xfer->actlen < xfer->sumlen) {
/* short transfer */
sc->data_rem = 0;
}
case USB_ST_SETUP:
DPRINTF("max_bulk=%d, data_rem=%d\n",
max_bulk, sc->data_rem);
if (sc->data_rem == 0) {
bbb_transfer_start(sc, ST_STATUS);
break;
}
if (max_bulk > sc->data_rem) {
max_bulk = sc->data_rem;
}
xfer->timeout = sc->data_timeout;
xfer->frlengths[0] = max_bulk;
usb2_set_frame_data(xfer, sc->data_ptr, 0);
usb2_start_hardware(xfer);
break;
default: /* Error */
if (xfer->error == USB_ERR_CANCELLED) {
bbb_done(sc, 1);
} else {
bbb_transfer_start(sc, ST_DATA_RD_CS);
}
break;
}
return;
}
static void
bbb_data_rd_cs_callback(struct usb2_xfer *xfer)
{
bbb_data_clear_stall_callback(xfer, ST_STATUS,
ST_DATA_RD);
return;
}
static void
bbb_data_write_callback(struct usb2_xfer *xfer)
{
struct bbb_transfer *sc = xfer->priv_sc;
uint32_t max_bulk = xfer->max_data_length;
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
sc->data_rem -= xfer->actlen;
sc->data_ptr += xfer->actlen;
sc->actlen += xfer->actlen;
if (xfer->actlen < xfer->sumlen) {
/* short transfer */
sc->data_rem = 0;
}
case USB_ST_SETUP:
DPRINTF("max_bulk=%d, data_rem=%d\n",
max_bulk, sc->data_rem);
if (sc->data_rem == 0) {
bbb_transfer_start(sc, ST_STATUS);
return;
}
if (max_bulk > sc->data_rem) {
max_bulk = sc->data_rem;
}
xfer->timeout = sc->data_timeout;
xfer->frlengths[0] = max_bulk;
usb2_set_frame_data(xfer, sc->data_ptr, 0);
usb2_start_hardware(xfer);
return;
default: /* Error */
if (xfer->error == USB_ERR_CANCELLED) {
bbb_done(sc, 1);
} else {
bbb_transfer_start(sc, ST_DATA_WR_CS);
}
return;
}
}
static void
bbb_data_wr_cs_callback(struct usb2_xfer *xfer)
{
bbb_data_clear_stall_callback(xfer, ST_STATUS,
ST_DATA_WR);
return;
}
static void
bbb_status_callback(struct usb2_xfer *xfer)
{
struct bbb_transfer *sc = xfer->priv_sc;
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
/* very simple status check */
if (xfer->actlen < sizeof(sc->csw)) {
bbb_done(sc, 1);/* error */
} else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) {
bbb_done(sc, 0);/* success */
} else {
bbb_done(sc, 1);/* error */
}
break;
case USB_ST_SETUP:
xfer->frlengths[0] = sizeof(sc->csw);
usb2_set_frame_data(xfer, &sc->csw, 0);
usb2_start_hardware(xfer);
break;
default:
DPRINTFN(0, "Failed to read CSW: %s, try %d\n",
usb2_errstr(xfer->error), sc->status_try);
if ((xfer->error == USB_ERR_CANCELLED) ||
(sc->status_try)) {
bbb_done(sc, 1);
} else {
sc->status_try = 1;
bbb_transfer_start(sc, ST_DATA_RD_CS);
}
break;
}
return;
}
/*------------------------------------------------------------------------*
* bbb_command_start - execute a SCSI command synchronously
*
* Return values
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
static uint8_t
bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
void *data_ptr, uint32_t data_len, uint8_t cmd_len,
uint32_t data_timeout)
{
sc->lun = lun;
sc->dir = data_len ? dir : DIR_NONE;
sc->data_ptr = data_ptr;
sc->data_len = data_len;
sc->data_rem = data_len;
sc->data_timeout = (data_timeout + USB_MS_HZ);
sc->actlen = 0;
sc->cmd_len = cmd_len;
usb2_transfer_start(sc->xfer[sc->state]);
while (usb2_transfer_pending(sc->xfer[sc->state])) {
usb2_cv_wait(&sc->cv, &sc->mtx);
}
return (sc->error);
}
/*------------------------------------------------------------------------*
* usb2_test_autoinstall
*
* Return values:
* 0: This interface is an auto install disk (CD-ROM)
* Else: Not an auto install disk.
*------------------------------------------------------------------------*/
usb2_error_t
usb2_test_autoinstall(struct usb2_device *udev, uint8_t iface_index)
{
struct usb2_interface *iface;
struct usb2_interface_descriptor *id;
usb2_error_t err;
uint8_t timeout;
uint8_t sid_type;
struct bbb_transfer *sc;
if (udev == NULL) {
return (USB_ERR_INVAL);
}
iface = usb2_get_iface(udev, iface_index);
if (iface == NULL) {
return (USB_ERR_INVAL);
}
id = iface->idesc;
if (id == NULL) {
return (USB_ERR_INVAL);
}
if (id->bInterfaceClass != UICLASS_MASS) {
return (USB_ERR_INVAL);
}
switch (id->bInterfaceSubClass) {
case UISUBCLASS_SCSI:
case UISUBCLASS_UFI:
break;
default:
return (USB_ERR_INVAL);
}
switch (id->bInterfaceProtocol) {
case UIPROTO_MASS_BBB_OLD:
case UIPROTO_MASS_BBB:
break;
default:
return (USB_ERR_INVAL);
}
sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO);
if (sc == NULL) {
return (USB_ERR_NOMEM);
}
mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF);
usb2_cv_init(&sc->cv, "WBBB");
err = usb2_transfer_setup(udev,
&iface_index, sc->xfer, bbb_config,
ST_MAX, sc, &sc->mtx);
if (err) {
goto done;
}
mtx_lock(&sc->mtx);
timeout = 4; /* tries */
repeat_inquiry:
sc->cbw.CBWCDB[0] = 0x12; /* INQUIRY */
err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 256, 6, USB_MS_HZ);
if (err) {
err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 256, 12, USB_MS_HZ);
if (err) {
err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 256, 16, USB_MS_HZ);
}
}
if ((sc->actlen != 0) && (err == 0)) {
sid_type = sc->buffer[0] & 0x1F;
if (sid_type == 0x05) {
/* CD-ROM */
/* XXX could investigate more */
return (0);
}
} else if (--timeout) {
usb2_pause_mtx(&sc->mtx, USB_MS_HZ);
goto repeat_inquiry;
}
err = USB_ERR_INVAL;
goto done;
done:
mtx_unlock(&sc->mtx);
usb2_transfer_unsetup(sc->xfer, ST_MAX);
mtx_destroy(&sc->mtx);
usb2_cv_destroy(&sc->cv);
free(sc, M_USB);
return (err);
}
/*
* Huawei Exxx radio devices have a built in flash disk which is their
* default power up configuration. This allows the device to carry its
* own installation software.
*
* Instead of following the USB spec, and create multiple
* configuration descriptors for this, the devices expects the driver
* to send UF_DEVICE_REMOTE_WAKEUP to endpoint 2 to reset the device,
* so it reprobes, now with the radio exposed.
*/
usb2_error_t
usb2_test_huawei(struct usb2_device *udev, uint8_t iface_index)
{
struct usb2_device_request req;
struct usb2_interface *iface;
struct usb2_interface_descriptor *id;
usb2_error_t err;
if (udev == NULL) {
return (USB_ERR_INVAL);
}
iface = usb2_get_iface(udev, iface_index);
if (iface == NULL) {
return (USB_ERR_INVAL);
}
id = iface->idesc;
if (id == NULL) {
return (USB_ERR_INVAL);
}
if (id->bInterfaceClass != UICLASS_MASS) {
return (USB_ERR_INVAL);
}
/* Bend it like Beckham */
req.bmRequestType = UT_WRITE_DEVICE;
req.bRequest = UR_SET_FEATURE;
USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
USETW(req.wIndex, 2);
USETW(req.wLength, 0);
/* We get error at return, but it works */
err = usb2_do_request_flags(udev, NULL, &req, NULL, 0, NULL, 1 * USB_MS_HZ);
return (0); /* success */
}

View File

@ -0,0 +1,33 @@
/* $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.
*/
#ifndef _USB2_MSCTEST_H_
#define _USB2_MSCTEST_H_
usb2_error_t usb2_test_autoinstall(struct usb2_device *udev, uint8_t iface_index);
usb2_error_t usb2_test_huawei(struct usb2_device *udev, uint8_t iface_index);
#endif /* _USB2_MSCTEST_H_ */

View File

@ -0,0 +1,208 @@
/* $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 <dev/usb2/include/usb2_standard.h>
#include <dev/usb2/include/usb2_mfunc.h>
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_parse.h>
/*------------------------------------------------------------------------*
* usb2_desc_foreach
*
* This function is the safe way to iterate across the USB config
* descriptor. It contains several checks against invalid
* descriptors. If the "desc" argument passed to this function is
* "NULL" the first descriptor, if any, will be returned.
*
* Return values:
* NULL: End of descriptors
* Else: Next descriptor after "desc"
*------------------------------------------------------------------------*/
struct usb2_descriptor *
usb2_desc_foreach(struct usb2_config_descriptor *cd, struct usb2_descriptor *desc)
{
void *end;
if (cd == NULL) {
return (NULL);
}
end = USB_ADD_BYTES(cd, UGETW(cd->wTotalLength));
if (desc == NULL) {
desc = USB_ADD_BYTES(cd, 0);
} else {
desc = USB_ADD_BYTES(desc, desc->bLength);
}
return (((((void *)desc) >= ((void *)cd)) &&
(((void *)desc) < end) &&
(USB_ADD_BYTES(desc, desc->bLength) >= ((void *)cd)) &&
(USB_ADD_BYTES(desc, desc->bLength) <= end) &&
(desc->bLength >= sizeof(*desc))) ? desc : NULL);
}
/*------------------------------------------------------------------------*
* usb2_find_idesc
*
* This function will return the interface descriptor, if any, that
* has index "iface_index" and alternate index "alt_index".
*
* Return values:
* NULL: End of descriptors
* Else: A valid interface descriptor
*------------------------------------------------------------------------*/
struct usb2_interface_descriptor *
usb2_find_idesc(struct usb2_config_descriptor *cd,
uint8_t iface_index, uint8_t alt_index)
{
struct usb2_descriptor *desc = NULL;
struct usb2_interface_descriptor *id;
uint8_t curidx = 0;
uint8_t lastidx = 0;
uint8_t curaidx = 0;
uint8_t first = 1;
while ((desc = usb2_desc_foreach(cd, desc))) {
if ((desc->bDescriptorType == UDESC_INTERFACE) &&
(desc->bLength >= sizeof(*id))) {
id = (void *)desc;
if (first) {
first = 0;
lastidx = id->bInterfaceNumber;
} else if (id->bInterfaceNumber != lastidx) {
lastidx = id->bInterfaceNumber;
curidx++;
curaidx = 0;
} else {
curaidx++;
}
if ((iface_index == curidx) && (alt_index == curaidx)) {
return (id);
}
}
}
return (NULL);
}
/*------------------------------------------------------------------------*
* usb2_find_edesc
*
* This function will return the endpoint descriptor for the passed
* interface index, alternate index and endpoint index.
*
* Return values:
* NULL: End of descriptors
* Else: A valid endpoint descriptor
*------------------------------------------------------------------------*/
struct usb2_endpoint_descriptor *
usb2_find_edesc(struct usb2_config_descriptor *cd,
uint8_t iface_index, uint8_t alt_index, uint8_t ep_index)
{
struct usb2_descriptor *desc = NULL;
struct usb2_interface_descriptor *d;
uint8_t curidx = 0;
d = usb2_find_idesc(cd, iface_index, alt_index);
if (d == NULL)
return (NULL);
if (ep_index >= d->bNumEndpoints) /* quick exit */
return (NULL);
desc = ((void *)d);
while ((desc = usb2_desc_foreach(cd, desc))) {
if (desc->bDescriptorType == UDESC_INTERFACE) {
break;
}
if (desc->bDescriptorType == UDESC_ENDPOINT) {
if (curidx == ep_index) {
if (desc->bLength <
sizeof(struct usb2_endpoint_descriptor)) {
/* endpoint index is invalid */
break;
}
return ((void *)desc);
}
curidx++;
}
}
return (NULL);
}
/*------------------------------------------------------------------------*
* usb2_get_no_endpoints
*
* This function will count the total number of endpoints available.
*------------------------------------------------------------------------*/
uint16_t
usb2_get_no_endpoints(struct usb2_config_descriptor *cd)
{
struct usb2_descriptor *desc = NULL;
uint16_t count = 0;
while ((desc = usb2_desc_foreach(cd, desc))) {
if (desc->bDescriptorType == UDESC_ENDPOINT) {
count++;
}
}
return (count);
}
/*------------------------------------------------------------------------*
* usb2_get_no_alts
*
* Return value:
* Number of alternate settings for the given "ifaceno".
*
* NOTE: The returned can be larger than the actual number of
* alternate settings.
*------------------------------------------------------------------------*/
uint16_t
usb2_get_no_alts(struct usb2_config_descriptor *cd, uint8_t ifaceno)
{
struct usb2_descriptor *desc = NULL;
struct usb2_interface_descriptor *id;
uint16_t n = 0;
while ((desc = usb2_desc_foreach(cd, desc))) {
if ((desc->bDescriptorType == UDESC_INTERFACE) &&
(desc->bLength >= sizeof(*id))) {
id = (void *)desc;
if (id->bInterfaceNumber == ifaceno) {
n++;
}
}
}
return (n);
}

View File

@ -0,0 +1,36 @@
/* $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.
*/
#ifndef _USB2_PARSE_H_
#define _USB2_PARSE_H_
struct usb2_descriptor *usb2_desc_foreach(struct usb2_config_descriptor *cd, struct usb2_descriptor *desc);
struct usb2_interface_descriptor *usb2_find_idesc(struct usb2_config_descriptor *cd, uint8_t iface_index, uint8_t alt_index);
struct usb2_endpoint_descriptor *usb2_find_edesc(struct usb2_config_descriptor *cd, uint8_t iface_index, uint8_t alt_index, uint8_t ep_index);
uint16_t usb2_get_no_endpoints(struct usb2_config_descriptor *cd);
uint16_t usb2_get_no_alts(struct usb2_config_descriptor *cd, uint8_t ifaceno);
#endif /* _USB2_PARSE_H_ */

View File

@ -0,0 +1,480 @@
/* $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.
*/
#define USB_DEBUG_VAR usb2_proc_debug
#include <dev/usb2/core/usb2_core.h>
#include <dev/usb2/core/usb2_process.h>
#include <dev/usb2/core/usb2_debug.h>
#include <dev/usb2/core/usb2_util.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/sched.h>
#if (__FreeBSD_version < 700000)
#define thread_lock(td) mtx_lock_spin(&sched_lock)
#define thread_unlock(td) mtx_unlock_spin(&sched_lock)
#endif
#if (__FreeBSD_version >= 800000)
#define USB_THREAD_CREATE(f, s, p, ...) \
kproc_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__)
#define USB_THREAD_SUSPEND(p) kproc_suspend(p,0)
#define USB_THREAD_EXIT(err) kproc_exit(err)
#else
#define USB_THREAD_CREATE(f, s, p, ...) \
kthread_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__)
#define USB_THREAD_SUSPEND(p) kthread_suspend(p,0)
#define USB_THREAD_EXIT(err) kthread_exit(err)
#endif
#if USB_DEBUG
static int usb2_proc_debug;
SYSCTL_NODE(_hw_usb2, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process");
SYSCTL_INT(_hw_usb2_proc, OID_AUTO, debug, CTLFLAG_RW, &usb2_proc_debug, 0,
"Debug level");
#endif
/*------------------------------------------------------------------------*
* usb2_process
*
* This function is the USB process dispatcher.
*------------------------------------------------------------------------*/
static void
usb2_process(void *arg)
{
struct usb2_process *up = arg;
struct usb2_proc_msg *pm;
struct thread *td;
/* adjust priority */
td = curthread;
thread_lock(td);
sched_prio(td, up->up_prio);
thread_unlock(td);
mtx_lock(up->up_mtx);
up->up_curtd = td;
while (1) {
if (up->up_gone) {
break;
}
/*
* NOTE to reimplementors: dequeueing a command from the
* "used" queue and executing it must be atomic, with regard
* to the "up_mtx" mutex. That means any attempt to queue a
* command by another thread must be blocked until either:
*
* 1) the command sleeps
*
* 2) the command returns
*
* Here is a practical example that shows how this helps
* solving a problem:
*
* Assume that you want to set the baud rate on a USB serial
* device. During the programming of the device you don't
* want to receive nor transmit any data, because it will be
* garbage most likely anyway. The programming of our USB
* device takes 20 milliseconds and it needs to call
* functions that sleep.
*
* Non-working solution: Before we queue the programming
* command, we stop transmission and reception of data. Then
* we queue a programming command. At the end of the
* programming command we enable transmission and reception
* of data.
*
* Problem: If a second programming command is queued while the
* first one is sleeping, we end up enabling transmission
* and reception of data too early.
*
* Working solution: Before we queue the programming command,
* we stop transmission and reception of data. Then we queue
* a programming command. Then we queue a second command
* that only enables transmission and reception of data.
*
* Why it works: If a second programming command is queued
* while the first one is sleeping, then the queueing of a
* second command to enable the data transfers, will cause
* the previous one, which is still on the queue, to be
* removed from the queue, and re-inserted after the last
* baud rate programming command, which then gives the
* desired result.
*/
pm = TAILQ_FIRST(&up->up_qhead);
if (pm) {
DPRINTF("Message pm=%p, cb=%p (enter)\n",
pm, pm->pm_callback);
(pm->pm_callback) (pm);
if (pm == TAILQ_FIRST(&up->up_qhead)) {
/* nothing changed */
TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
pm->pm_qentry.tqe_prev = NULL;
}
DPRINTF("Message pm=%p (leave)\n", pm);
continue;
}
/* end if messages - check if anyone is waiting for sync */
if (up->up_dsleep) {
up->up_dsleep = 0;
usb2_cv_broadcast(&up->up_drain);
}
up->up_msleep = 1;
usb2_cv_wait(&up->up_cv, up->up_mtx);
}
up->up_ptr = NULL;
usb2_cv_signal(&up->up_cv);
mtx_unlock(up->up_mtx);
USB_THREAD_EXIT(0);
return;
}
/*------------------------------------------------------------------------*
* usb2_proc_setup
*
* This function will create a process using the given "prio" that can
* execute callbacks. The mutex pointed to by "p_mtx" will be applied
* before calling the callbacks and released after that the callback
* has returned. The structure pointed to by "up" is assumed to be
* zeroed before this function is called.
*
* Return values:
* 0: success
* Else: failure
*------------------------------------------------------------------------*/
uint8_t
usb2_proc_setup(struct usb2_process *up, struct mtx *p_mtx, uint8_t prio)
{
up->up_mtx = p_mtx;
up->up_prio = prio;
TAILQ_INIT(&up->up_qhead);
usb2_cv_init(&up->up_cv, "WMSG");
usb2_cv_init(&up->up_drain, "DMSG");
if (USB_THREAD_CREATE(&usb2_process, up,
&up->up_ptr, "USBPROC")) {
DPRINTFN(0, "Unable to create USB process.");
up->up_ptr = NULL;
goto error;
}
return (0);
error:
usb2_proc_unsetup(up);
return (1);
}
/*------------------------------------------------------------------------*
* usb2_proc_unsetup
*
* NOTE: If the structure pointed to by "up" is all zero, this
* function does nothing.
*
* NOTE: Messages that are pending on the process queue will not be
* removed nor called.
*------------------------------------------------------------------------*/
void
usb2_proc_unsetup(struct usb2_process *up)
{
if (!(up->up_mtx)) {
/* not initialised */
return;
}
usb2_proc_drain(up);
usb2_cv_destroy(&up->up_cv);
usb2_cv_destroy(&up->up_drain);
/* make sure that we do not enter here again */
up->up_mtx = NULL;
return;
}
/*------------------------------------------------------------------------*
* usb2_proc_msignal
*
* This function will queue one of the passed USB process messages on
* the USB process queue. The first message that is not already queued
* will get queued. If both messages are already queued the one queued
* last will be removed from the queue and queued in the end. The USB
* process mutex must be locked when calling this function. This
* function exploits the fact that a process can only do one callback
* at a time. The message that was queued is returned.
*------------------------------------------------------------------------*/
void *
usb2_proc_msignal(struct usb2_process *up, void *_pm0, void *_pm1)
{
struct usb2_proc_msg *pm0 = _pm0;
struct usb2_proc_msg *pm1 = _pm1;
struct usb2_proc_msg *pm2;
uint32_t d;
uint8_t t;
mtx_assert(up->up_mtx, MA_OWNED);
t = 0;
if (pm0->pm_qentry.tqe_prev) {
t |= 1;
}
if (pm1->pm_qentry.tqe_prev) {
t |= 2;
}
if (t == 0) {
/*
* No entries are queued. Queue "pm0" and use the existing
* message number.
*/
pm2 = pm0;
} else if (t == 1) {
/* Check if we need to increment the message number. */
if (pm0->pm_num == up->up_msg_num) {
up->up_msg_num++;
}
pm2 = pm1;
} else if (t == 2) {
/* Check if we need to increment the message number. */
if (pm1->pm_num == up->up_msg_num) {
up->up_msg_num++;
}
pm2 = pm0;
} else if (t == 3) {
/*
* Both entries are queued. Re-queue the entry closest to
* the end.
*/
d = (pm1->pm_num - pm0->pm_num);
/* Check sign after subtraction */
if (d & 0x80000000) {
pm2 = pm0;
} else {
pm2 = pm1;
}
TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry);
} else {
pm2 = NULL; /* panic - should not happen */
}
DPRINTF(" t=%u, num=%u\n", t, up->up_msg_num);
/* Put message last on queue */
pm2->pm_num = up->up_msg_num;
TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry);
/* Check if we need to wakeup the USB process. */
if (up->up_msleep) {
up->up_msleep = 0; /* save "cv_signal()" calls */
usb2_cv_signal(&up->up_cv);
}
return (pm2);
}
/*------------------------------------------------------------------------*
* usb2_proc_is_gone
*
* Return values:
* 0: USB process is running
* Else: USB process is tearing down
*------------------------------------------------------------------------*/
uint8_t
usb2_proc_is_gone(struct usb2_process *up)
{
mtx_assert(up->up_mtx, MA_OWNED);
return (up->up_gone ? 1 : 0);
}
/*------------------------------------------------------------------------*
* usb2_proc_mwait
*
* This function will return when the USB process message pointed to
* by "pm" is no longer on a queue. This function must be called
* having "up->up_mtx" locked.
*------------------------------------------------------------------------*/
void
usb2_proc_mwait(struct usb2_process *up, void *_pm0, void *_pm1)
{
struct usb2_proc_msg *pm0 = _pm0;
struct usb2_proc_msg *pm1 = _pm1;
mtx_assert(up->up_mtx, MA_OWNED);
if (up->up_curtd == curthread) {
/* Just remove the messages from the queue. */
if (pm0->pm_qentry.tqe_prev) {
TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry);
pm0->pm_qentry.tqe_prev = NULL;
}
if (pm1->pm_qentry.tqe_prev) {
TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry);
pm1->pm_qentry.tqe_prev = NULL;
}
} else
while (pm0->pm_qentry.tqe_prev ||
pm1->pm_qentry.tqe_prev) {
/* check if config thread is gone */
if (up->up_gone)
break;
up->up_dsleep = 1;
usb2_cv_wait(&up->up_drain, up->up_mtx);
}
return;
}
/*------------------------------------------------------------------------*
* usb2_proc_drain
*
* This function will tear down an USB process, waiting for the
* currently executing command to return.
*
* NOTE: If the structure pointed to by "up" is all zero,
* this function does nothing.
*------------------------------------------------------------------------*/
void
usb2_proc_drain(struct usb2_process *up)
{
if (!(up->up_mtx)) {
/* not initialised */
return;
}
if (up->up_mtx != &Giant) {
mtx_assert(up->up_mtx, MA_NOTOWNED);
}
mtx_lock(up->up_mtx);
/* Set the gone flag */
up->up_gone = 1;
while (up->up_ptr) {
/* Check if we need to wakeup the USB process */
if (up->up_msleep || up->up_csleep) {
up->up_msleep = 0;
up->up_csleep = 0;
usb2_cv_signal(&up->up_cv);
}
/* Check if we are still cold booted */
if (cold) {
USB_THREAD_SUSPEND(up->up_ptr);
printf("WARNING: A USB process has been left suspended!\n");
break;
}
usb2_cv_wait(&up->up_cv, up->up_mtx);
}
/* Check if someone is waiting - should not happen */
if (up->up_dsleep) {
up->up_dsleep = 0;
usb2_cv_broadcast(&up->up_drain);
DPRINTF("WARNING: Someone is waiting "
"for USB process drain!\n");
}
mtx_unlock(up->up_mtx);
return;
}
/*------------------------------------------------------------------------*
* usb2_proc_cwait
*
* This function will suspend the current process until
* "usb2_proc_signal()" or "usb2_proc_drain()" is called. The
* "timeout" parameter defines the maximum wait time in system
* ticks. If "timeout" is zero that means no timeout.
*
* NOTE: This function can only be called from within an USB process.
*
* Return values:
* USB_PROC_WAIT_TIMEOUT: Timeout
* USB_PROC_WAIT_NORMAL: Success
* Else: USB process is tearing down
*------------------------------------------------------------------------*/
uint8_t
usb2_proc_cwait(struct usb2_process *up, int timeout)
{
int error;
mtx_assert(up->up_mtx, MA_OWNED);
if (up->up_gone) {
return (USB_PROC_WAIT_DRAIN);
}
up->up_csleep = 1;
if (timeout == 0) {
usb2_cv_wait(&up->up_cv, up->up_mtx);
error = 0;
} else {
error = usb2_cv_timedwait(&up->up_cv, up->up_mtx, timeout);
}
up->up_csleep = 0;
if (up->up_gone) {
return (USB_PROC_WAIT_DRAIN);
}
if (error == EWOULDBLOCK) {
return (USB_PROC_WAIT_TIMEOUT);
}
return (0);
}
/*------------------------------------------------------------------------*
* usb2_proc_csignal
*
* This function will wakeup the given USB process.
*------------------------------------------------------------------------*/
void
usb2_proc_csignal(struct usb2_process *up)
{
mtx_assert(up->up_mtx, MA_OWNED);
if (up->up_csleep) {
up->up_csleep = 0;
usb2_cv_signal(&up->up_cv);
}
return;
}

View File

@ -0,0 +1,89 @@
/* $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.
*/
#ifndef _USB2_PROCESS_H_
#define _USB2_PROCESS_H_
#include <sys/priority.h>
/* defines */
#define USB_PRI_HIGH PI_NET
#define USB_PRI_MED PI_DISK
#define USB_PROC_WAIT_TIMEOUT 2
#define USB_PROC_WAIT_DRAIN 1
#define USB_PROC_WAIT_NORMAL 0
/* structure prototypes */
struct usb2_proc_msg;
/* typedefs */
typedef void (usb2_proc_callback_t)(struct usb2_proc_msg *hdr);
/*
* The following structure defines the USB process message header.
*/
struct usb2_proc_msg {
TAILQ_ENTRY(usb2_proc_msg) pm_qentry;
usb2_proc_callback_t *pm_callback;
uint32_t pm_num;
};
/*
* The following structure defines the USB process.
*/
struct usb2_process {
TAILQ_HEAD(, usb2_proc_msg) up_qhead;
struct cv up_cv;
struct cv up_drain;
struct proc *up_ptr;
struct thread *up_curtd;
struct mtx *up_mtx;
uint32_t up_msg_num;
uint8_t up_prio;
uint8_t up_gone;
uint8_t up_msleep;
uint8_t up_csleep;
uint8_t up_dsleep;
};
/* prototypes */
uint8_t usb2_proc_cwait(struct usb2_process *up, int timeout);
uint8_t usb2_proc_is_gone(struct usb2_process *up);
uint8_t usb2_proc_setup(struct usb2_process *up, struct mtx *p_mtx, uint8_t prio);
void usb2_proc_csignal(struct usb2_process *up);
void usb2_proc_drain(struct usb2_process *up);
void usb2_proc_mwait(struct usb2_process *up, void *pm0, void *pm1);
void usb2_proc_unsetup(struct usb2_process *up);
void *usb2_proc_msignal(struct usb2_process *up, void *pm0, void *pm1);
#endif /* _USB2_PROCESS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
/* $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.
*/
#ifndef _USB2_REQUEST_H_
#define _USB2_REQUEST_H_
usb2_error_t usb2_do_request_flags(struct usb2_device *udev, struct mtx *mtx, struct usb2_device_request *req, void *data, uint32_t flags, uint16_t *actlen, uint32_t timeout);
usb2_error_t usb2_req_clear_hub_feature(struct usb2_device *udev, struct mtx *mtx, uint16_t sel);
usb2_error_t usb2_req_clear_port_feature(struct usb2_device *udev, struct mtx *mtx, uint8_t port, uint16_t sel);
usb2_error_t usb2_req_get_alt_interface_no(struct usb2_device *udev, struct mtx *mtx, uint8_t *alt_iface_no, uint8_t iface_index);
usb2_error_t usb2_req_get_config(struct usb2_device *udev, struct mtx *mtx, uint8_t *pconf);
usb2_error_t usb2_req_get_config_desc(struct usb2_device *udev, struct mtx *mtx, struct usb2_config_descriptor *d, uint8_t conf_index);
usb2_error_t usb2_req_get_config_desc_full(struct usb2_device *udev, struct mtx *mtx, struct usb2_config_descriptor **ppcd, struct malloc_type *mtype, uint8_t conf_index);
usb2_error_t usb2_req_get_desc(struct usb2_device *udev, struct mtx *mtx, void *desc, uint16_t min_len, uint16_t max_len, uint16_t id, uint8_t type, uint8_t index, uint8_t retries);
usb2_error_t usb2_req_get_device_desc(struct usb2_device *udev, struct mtx *mtx, struct usb2_device_descriptor *d);
usb2_error_t usb2_req_get_device_status(struct usb2_device *udev, struct mtx *mtx, struct usb2_status *st);
usb2_error_t usb2_req_get_hub_descriptor(struct usb2_device *udev, struct mtx *mtx, struct usb2_hub_descriptor *hd, uint8_t nports);
usb2_error_t usb2_req_get_hub_status(struct usb2_device *udev, struct mtx *mtx, struct usb2_hub_status *st);
usb2_error_t usb2_req_get_port_status(struct usb2_device *udev, struct mtx *mtx, struct usb2_port_status *ps, uint8_t port);
usb2_error_t usb2_req_get_report(struct usb2_device *udev, struct mtx *mtx, void *data, uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id);
usb2_error_t usb2_req_get_report_descriptor(struct usb2_device *udev, struct mtx *mtx, void *d, uint16_t size, uint8_t iface_index);
usb2_error_t usb2_req_get_string_any(struct usb2_device *udev, struct mtx *mtx, char *buf, uint16_t len, uint8_t string_index);
usb2_error_t usb2_req_get_string_desc(struct usb2_device *udev, struct mtx *mtx, void *sdesc, uint16_t max_len, uint16_t lang_id, uint8_t string_index);
usb2_error_t usb2_req_reset_port(struct usb2_device *udev, struct mtx *mtx, uint8_t port);
usb2_error_t usb2_req_set_address(struct usb2_device *udev, struct mtx *mtx, uint16_t addr);
usb2_error_t usb2_req_set_alt_interface_no(struct usb2_device *udev, struct mtx *mtx, uint8_t iface_index, uint8_t alt_no);
usb2_error_t usb2_req_set_config(struct usb2_device *udev, struct mtx *mtx, uint8_t conf);
usb2_error_t usb2_req_set_hub_feature(struct usb2_device *udev, struct mtx *mtx, uint16_t sel);
usb2_error_t usb2_req_set_idle(struct usb2_device *udev, struct mtx *mtx, uint8_t iface_index, uint8_t duration, uint8_t id);
usb2_error_t usb2_req_set_port_feature(struct usb2_device *udev, struct mtx *mtx, uint8_t port, uint16_t sel);
usb2_error_t usb2_req_set_protocol(struct usb2_device *udev, struct mtx *mtx, uint8_t iface_index, uint16_t report);
usb2_error_t usb2_req_set_report(struct usb2_device *udev, struct mtx *mtx, void *data, uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id);
usb2_error_t usb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx);
#define usb2_do_request(u,m,r,d) \
usb2_do_request_flags(u,m,r,d,0,NULL,USB_DEFAULT_TIMEOUT)
#endif /* _USB2_REQUEST_H_ */

Some files were not shown because too many files have changed in this diff Show More