mirror of https://github.com/ARMmbed/mbed-os.git
Add USBPhy, USB HAL and Utility class
Add the USBPhy and USBPhyEvents abstract classes, the HAL header using this class and the EndpointResolver utility class.pull/9768/head
parent
e03b3b68c1
commit
8ae123f2d4
|
@ -0,0 +1,29 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "usb_phy_api.h"
|
||||
#include "mbed_error.h"
|
||||
|
||||
#if !defined(DEVICE_USBDEVICE) || !DEVICE_USBDEVICE
|
||||
|
||||
USBPhy *get_usb_phy()
|
||||
{
|
||||
error("This board does not have a hardware USB driver");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
/** \addtogroup hal */
|
||||
/** @{*/
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef MBED_USB_PHY_API_H
|
||||
#define MBED_USB_PHY_API_H
|
||||
|
||||
#include "USBPhy.h"
|
||||
|
||||
/** Return a the USBPhy instance for this hardware
|
||||
*
|
||||
* For details on adding support for a USBPhy see the specification in USBPhy.h.
|
||||
*
|
||||
* @return A pointer to a USBPhy instance
|
||||
* @note Calling this function on platforms without a USBPhy will result in an
|
||||
* error
|
||||
*/
|
||||
USBPhy *get_usb_phy();
|
||||
|
||||
#endif
|
||||
|
||||
/** @}*/
|
|
@ -0,0 +1,302 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef USBPHY_H
|
||||
#define USBPHY_H
|
||||
|
||||
#include "USBPhyTypes.h"
|
||||
#include "USBPhyEvents.h"
|
||||
|
||||
/** Abstract interface to physical USB hardware
|
||||
*
|
||||
* # Defined behavior
|
||||
* * Any endpoint configurations which fit in the parameters of the table returned
|
||||
* by USBPhy::endpoint_table can be used.
|
||||
* * All endpoints in any valid endpoint configuration can be used concurrently
|
||||
* * Device supports use of at least one control, bulk, interrupt and
|
||||
* isochronous in each direction at the same time - at least 8 endpoints.
|
||||
* * Device supports all standard endpoint sizes (wMaxPacketSize)
|
||||
* * Device can handle an interrupt latency of at least 100ms if reset is not being performed and address is not being set
|
||||
* * USBPhyEvents events are only sent when USBPhy is in the initialized state
|
||||
* * When unpowered only the USBPhyEvents::power event can be sent
|
||||
* * On USB reset all endpoints are removed except for endpoint 0
|
||||
* * USBPhyEvents::out and USBPhyEvents::in events only occur for endpoints which have been added
|
||||
* * A call to USBPhy::ep0_write results in USBPhyEvents::in getting called if not
|
||||
* interrupted by a power loss or reset
|
||||
* * A call to endpoint_read followed by endpoint_read_result results in USBPhyEvents::out getting called if not
|
||||
* interrupted by a power loss or reset
|
||||
* * Endpoint 0 naks all transactions aside from setup packets until one
|
||||
* of ep0_read, ep0_write or ep0_stall has been called
|
||||
* * Endpoint 0 stall is automatically cleared on reception of a setup packet
|
||||
*
|
||||
* # Undefined behavior
|
||||
* * Calling USBPhy::endpoint_add or USBPhy::endpoint_remove outside of the control requests SetInterface or SetConfiguration
|
||||
* * Devices behavior is undefined if latency is greater than 2ms when address is being set - see USB spec 9.2.6.3
|
||||
* * Devices behavior is undefined if latency is greater than 10ms when a reset occurs - see USB spec 7.1.7.5
|
||||
* * Calling any of the USBPhy::endpoint_* functions on endpoint 0
|
||||
*
|
||||
* # Notes
|
||||
* * Make sure USB packets are processed in the correct order when multiple packets are present.
|
||||
* Typically IN endpoints should be handled before OUT endpoints if both are pending.
|
||||
* * Setup packets may be resent if there is noise on the USB line. The USBPhy should be able
|
||||
* to gracefully handle this scenario and respond to the setup packet with an ACK.
|
||||
* * Bi-directional protocols making use of alternating IN and OUT phases should not rely
|
||||
* on the last ACK an IN transfer to indicate that the OUT phase should start. Instead,
|
||||
* the OUT phase should be started at the same time the last IN transfer is started. This
|
||||
* is because the ACK to the last in transfer may be dropped if there is noise on the USB
|
||||
* line. If dropped it will only get re-sent on the next IN phase. More info on this can be
|
||||
* found in section 8.5.3.3 of the USB spec.
|
||||
*
|
||||
* @ingroup usb_device_core
|
||||
*/
|
||||
class USBPhy {
|
||||
public:
|
||||
USBPhy() {};
|
||||
virtual ~USBPhy() {};
|
||||
|
||||
/**
|
||||
* Initialize this USBPhy instance
|
||||
*
|
||||
* This function must be called before calling
|
||||
* any other functions of this class, unless specifically
|
||||
* noted.
|
||||
*
|
||||
* @param events Callback class to handle USB events
|
||||
*/
|
||||
virtual void init(USBPhyEvents *events) = 0;
|
||||
|
||||
/**
|
||||
* Power down this USBPhy instance
|
||||
*
|
||||
* Disable interrupts and stop sending events.
|
||||
*/
|
||||
virtual void deinit() = 0;
|
||||
|
||||
/**
|
||||
* Check if USB power is present
|
||||
*
|
||||
* Devices which don't support checking the USB power state
|
||||
* must always return true.
|
||||
*
|
||||
* @return true if USB power is present, false otherwise
|
||||
*/
|
||||
virtual bool powered() = 0;
|
||||
|
||||
/**
|
||||
* Make the USB phy visible to the USB host
|
||||
*
|
||||
* Enable either the D+ or D- pullup so the host can detect
|
||||
* the presence of this device.
|
||||
*/
|
||||
virtual void connect() = 0;
|
||||
|
||||
/**
|
||||
* Detach the USB phy
|
||||
*
|
||||
* Disable the D+ and D- pullup and stop responding to
|
||||
* USB traffic.
|
||||
*/
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
/**
|
||||
* Set this device to the configured state
|
||||
*
|
||||
* Enable added endpoints if they are not enabled
|
||||
* already.
|
||||
*/
|
||||
virtual void configure() = 0;
|
||||
|
||||
/**
|
||||
* Leave the configured state
|
||||
*
|
||||
* This is a notification to the USBPhy indicating that the device
|
||||
* is leaving the configured state. The USBPhy can disable all
|
||||
* endpoints other than endpoint 0.
|
||||
*
|
||||
*/
|
||||
virtual void unconfigure() = 0;
|
||||
|
||||
/**
|
||||
* Enable the start of frame interrupt
|
||||
*
|
||||
* Call USBPhyEvents::sof on every frame.
|
||||
*/
|
||||
virtual void sof_enable() = 0;
|
||||
|
||||
/**
|
||||
* Disable the start of frame interrupt
|
||||
*
|
||||
* Stop calling USBPhyEvents::sof.
|
||||
*/
|
||||
virtual void sof_disable() = 0;
|
||||
|
||||
/**
|
||||
* Set the USBPhy's address
|
||||
*
|
||||
* @param address This device's USB address
|
||||
*/
|
||||
virtual void set_address(uint8_t address) = 0;
|
||||
|
||||
/**
|
||||
* Wake upstream devices
|
||||
*/
|
||||
virtual void remote_wakeup() = 0;
|
||||
|
||||
/**
|
||||
* Get the endpoint table
|
||||
*
|
||||
* This function returns a table which describes the endpoints
|
||||
* can be used, the functionality of those endpoints and the
|
||||
* resource cost.
|
||||
*/
|
||||
virtual const usb_ep_table_t* endpoint_table() = 0;
|
||||
|
||||
/**
|
||||
* Set wMaxPacketSize of endpoint 0
|
||||
*
|
||||
* @param max_packet The wMaxPacketSize value for endpoint 0
|
||||
* @return The actual size of endpoint 0
|
||||
*/
|
||||
virtual uint32_t ep0_set_max_packet(uint32_t max_packet) = 0;
|
||||
|
||||
/**
|
||||
* Read the contents of the SETUP packet
|
||||
*
|
||||
* @param buffer Buffer to fill with data
|
||||
* @param size Size of buffer passed in
|
||||
*/
|
||||
virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size) = 0;
|
||||
|
||||
/**
|
||||
* Start receiving a packet of up to wMaxPacketSize on endpoint 0
|
||||
*/
|
||||
virtual void ep0_read() = 0;
|
||||
|
||||
/**
|
||||
* Read the contents of a received packet
|
||||
*
|
||||
* @param buffer Buffer to fill with the data read
|
||||
* @param size Size of buffer
|
||||
*/
|
||||
virtual uint32_t ep0_read_result(uint8_t *buffer, uint32_t size) = 0;
|
||||
|
||||
/**
|
||||
* Write a packet on endpoint 0
|
||||
*
|
||||
* @param buffer Buffer fill with data to send
|
||||
* @param size Size of data to send
|
||||
*/
|
||||
virtual void ep0_write(uint8_t *buffer, uint32_t size) = 0;
|
||||
|
||||
/**
|
||||
* Protocol stall on endpoint 0
|
||||
*
|
||||
* Stall all IN and OUT packets on endpoint 0 until a setup packet
|
||||
* is received.
|
||||
* @note The stall is cleared automatically when a setup packet is received
|
||||
*/
|
||||
virtual void ep0_stall() = 0;
|
||||
|
||||
/**
|
||||
* Configure and enable an endpoint
|
||||
*
|
||||
* @param endpoint Endpoint to configure and enable
|
||||
* @param max_packet The maximum packet size that can be sent or received
|
||||
* @param type The type of endpoint this should be configured as -
|
||||
* USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO
|
||||
* @note This function cannot be used to configure endpoint 0. That must be done
|
||||
* with ep0_set_max_packet
|
||||
*/
|
||||
virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) = 0;
|
||||
|
||||
/**
|
||||
* Disable an endpoint
|
||||
*
|
||||
* @param endpoint Endpoint to disable
|
||||
*/
|
||||
virtual void endpoint_remove(usb_ep_t endpoint) = 0;
|
||||
|
||||
/**
|
||||
* Perform a functional stall on the given endpoint
|
||||
*
|
||||
* Set the HALT feature for this endpoint so that all further
|
||||
* communication is aborted.
|
||||
*
|
||||
* @param endpoint Endpoint to stall
|
||||
*/
|
||||
virtual void endpoint_stall(usb_ep_t endpoint) = 0;
|
||||
|
||||
/**
|
||||
* Unstall the endpoint
|
||||
*
|
||||
* Clear the HALT feature on this endpoint so communication can
|
||||
* resume.
|
||||
*
|
||||
* @param endpoint Endpoint to stall
|
||||
*/
|
||||
virtual void endpoint_unstall(usb_ep_t endpoint) = 0;
|
||||
|
||||
/**
|
||||
* Start a read on the given endpoint
|
||||
*
|
||||
* @param endpoint Endpoint to start the read on
|
||||
* @param max_packet A hint as to the wMaxPacketSize of this endpoint.
|
||||
* This must match the size in endpoint_add.
|
||||
* @return true if the read was successfully started, false otherwise
|
||||
*/
|
||||
virtual bool endpoint_read(usb_ep_t endpoint, uint32_t max_packet) = 0;
|
||||
|
||||
/**
|
||||
* Finish a read on the given endpoint
|
||||
*
|
||||
* @param endpoint Endpoint to read data from
|
||||
* @param data Buffer to fill with data
|
||||
* @param size Size of buffer
|
||||
* @param bytes_read The number of bytes in the current packet. This can be larger than
|
||||
* the size parameter if the buffer passed in was too small.
|
||||
* @return true if data was read false otherwise
|
||||
*/
|
||||
virtual bool endpoint_read_result(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytes_read) = 0;
|
||||
|
||||
/**
|
||||
* Start a write on the given endpoint
|
||||
*
|
||||
* @param endpoint Endpoint to write to
|
||||
* @param data Buffer to write
|
||||
* @param size Size of data to write
|
||||
* @return true if the data was prepared for transmit, false otherwise
|
||||
*/
|
||||
virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) = 0;
|
||||
|
||||
/**
|
||||
* Abort the current transfer if it has not yet been sent
|
||||
*
|
||||
* @param endpoint Endpoint to abort the transfer on. It is implementation defined
|
||||
* if this function has an effect on receive endpoints.
|
||||
*/
|
||||
virtual void endpoint_abort(usb_ep_t endpoint) = 0;
|
||||
|
||||
/**
|
||||
* Callback used for performing USB processing
|
||||
*
|
||||
* USBPhy processing should be triggered by calling USBPhyEvents::start_process
|
||||
* and done inside process. All USBPhyEvents callbacks aside from
|
||||
* USBPhyEvents::start_process must be called in the context of process
|
||||
*/
|
||||
virtual void process() = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,107 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef USBPHY_EVENTS_H
|
||||
#define USBPHY_EVENTS_H
|
||||
|
||||
#include "USBPhyTypes.h"
|
||||
|
||||
/** Event handler for USBPhy
|
||||
*
|
||||
* This class is the event handler for the USBPhy class. Any events generated
|
||||
* by USBPhy are passed to this class via the virtual functions.
|
||||
*
|
||||
* @ingroup usb_device_core
|
||||
*
|
||||
*/
|
||||
class USBPhyEvents {
|
||||
public:
|
||||
USBPhyEvents() {};
|
||||
virtual ~USBPhyEvents() {};
|
||||
|
||||
/**
|
||||
* Callback called when a bus reset occurs
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void reset() = 0;
|
||||
|
||||
/**
|
||||
* Callback called when an endpoint 0 setup packet is received
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void ep0_setup() = 0;
|
||||
|
||||
/**
|
||||
* Callback called when an endpoint 0 out packet is received
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void ep0_out() = 0;
|
||||
|
||||
/**
|
||||
* Callback called when an endpoint 0 in packet is received
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void ep0_in() = 0;
|
||||
|
||||
/**
|
||||
* Callback called USB power is applied or removed
|
||||
*
|
||||
* @param powered true if USB power is present, false otherwise
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void power(bool powered) = 0;
|
||||
|
||||
/**
|
||||
* Callback called when entering or leaving suspend mode
|
||||
*
|
||||
* @param suspended true if entering suspend mode false otherwise
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void suspend(bool suspended) = 0;
|
||||
|
||||
/**
|
||||
* Callback called on start of frame
|
||||
*
|
||||
* @param frame_number The current frame number
|
||||
* @note This callback is enabled/disabled by
|
||||
* calling USBPhy::sof_enable / USBPhy::sof_disable
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void sof(int frame_number) = 0;
|
||||
|
||||
/**
|
||||
* Callback called on the reception of an OUT packet
|
||||
*
|
||||
* @param endpoint Endpoint which received the OUT packet
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void out(usb_ep_t endpoint) = 0;
|
||||
|
||||
/**
|
||||
* Callback called on the transmission of an IN packet
|
||||
*
|
||||
* @param endpoint Endpoint which sent the IN packet
|
||||
* @note called in the contex of USBPhy::process
|
||||
*/
|
||||
virtual void in(usb_ep_t endpoint) = 0;
|
||||
|
||||
/**
|
||||
* Callback called to indicate the USB processing needs to be done
|
||||
*/
|
||||
virtual void start_process() = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef USBPHY_TYPES_H
|
||||
#define USBPHY_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t usb_ep_t;
|
||||
|
||||
typedef enum {
|
||||
USB_EP_TYPE_CTRL = 0,
|
||||
USB_EP_TYPE_ISO = 1,
|
||||
USB_EP_TYPE_BULK = 2,
|
||||
USB_EP_TYPE_INT = 3
|
||||
} usb_ep_type_t;
|
||||
|
||||
enum {
|
||||
USB_EP_ATTR_ALLOW_CTRL = 1 << USB_EP_TYPE_CTRL,
|
||||
USB_EP_ATTR_ALLOW_BULK = 1 << USB_EP_TYPE_BULK,
|
||||
USB_EP_ATTR_ALLOW_INT = 1 << USB_EP_TYPE_INT,
|
||||
USB_EP_ATTR_ALLOW_ISO = 1 << USB_EP_TYPE_ISO,
|
||||
USB_EP_ATTR_ALLOW_ALL = USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_ALLOW_BULK |
|
||||
USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_ALLOW_ISO,
|
||||
|
||||
USB_EP_ATTR_DIR_IN = 0 << 4,
|
||||
USB_EP_ATTR_DIR_OUT = 1 << 4,
|
||||
USB_EP_ATTR_DIR_IN_OR_OUT = 2 << 4,
|
||||
USB_EP_ATTR_DIR_IN_AND_OUT = 3 << 4,
|
||||
USB_EP_ATTR_DIR_MASK = 3 << 4
|
||||
};
|
||||
typedef uint8_t usb_ep_attr_t;
|
||||
|
||||
struct usb_ep_entry_t {
|
||||
usb_ep_attr_t attributes;
|
||||
uint8_t byte_cost;
|
||||
uint16_t base_cost;
|
||||
};
|
||||
|
||||
struct usb_ep_table_t {
|
||||
uint32_t resources;
|
||||
usb_ep_entry_t table[16];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,136 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mbed.h"
|
||||
#include "EndpointResolver.h"
|
||||
|
||||
static uint32_t logical_to_index(uint32_t logical, bool in_not_out)
|
||||
{
|
||||
return (logical << 1) | (in_not_out ? 1 : 0);
|
||||
}
|
||||
|
||||
static uint32_t index_to_logical(uint32_t index)
|
||||
{
|
||||
return index >> 1;
|
||||
}
|
||||
|
||||
|
||||
EndpointResolver::EndpointResolver(const usb_ep_table_t *table) : _table(table), _cost(0), _used(0), _valid(true)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
EndpointResolver::~EndpointResolver()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void EndpointResolver::endpoint_ctrl(uint32_t size)
|
||||
{
|
||||
endpoint_in(USB_EP_TYPE_CTRL, size);
|
||||
endpoint_out(USB_EP_TYPE_CTRL, size);
|
||||
}
|
||||
|
||||
usb_ep_t EndpointResolver::endpoint_in(usb_ep_type_t type, uint32_t size)
|
||||
{
|
||||
int index = next_index(type, true);
|
||||
if (index < 0) {
|
||||
_valid = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const usb_ep_entry_t &entry = _table->table[index_to_logical(index)];
|
||||
_cost += entry.base_cost + entry.byte_cost * size;
|
||||
_used |= 1 << index;
|
||||
|
||||
return index_to_endpoint(index);
|
||||
}
|
||||
|
||||
usb_ep_t EndpointResolver::endpoint_out(usb_ep_type_t type, uint32_t size)
|
||||
{
|
||||
int index = next_index(type, false);
|
||||
if (index < 0) {
|
||||
_valid = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const usb_ep_entry_t &entry = _table->table[index_to_logical(index)];
|
||||
_cost += entry.base_cost + entry.byte_cost * size;
|
||||
_used |= 1 << index;
|
||||
|
||||
return index_to_endpoint(index);
|
||||
}
|
||||
|
||||
bool EndpointResolver::valid()
|
||||
{
|
||||
return _valid && (_cost <= _table->resources);
|
||||
}
|
||||
|
||||
void EndpointResolver::reset() {
|
||||
_cost = 0;
|
||||
_used = 0;
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
usb_ep_t EndpointResolver::index_to_endpoint(int index)
|
||||
{
|
||||
return index_to_logical(index) | ((index & 1) ? 0x80 : 0);
|
||||
}
|
||||
|
||||
int EndpointResolver::next_index(usb_ep_type_t type, bool in_not_out)
|
||||
{
|
||||
for (int logical = 0; logical < (int)(sizeof(_table->table) / sizeof(_table->table[0])); logical++) {
|
||||
uint32_t index = logical_to_index(logical, in_not_out);
|
||||
uint32_t other = logical_to_index(logical, !in_not_out);
|
||||
const usb_ep_entry_t &entry = _table->table[logical];
|
||||
|
||||
usb_ep_attr_t dir = entry.attributes & USB_EP_ATTR_DIR_MASK;
|
||||
bool in_allowed = dir != USB_EP_ATTR_DIR_OUT;
|
||||
bool out_allowed = dir != USB_EP_ATTR_DIR_IN;
|
||||
bool shared = dir == USB_EP_ATTR_DIR_IN_OR_OUT;
|
||||
|
||||
if (!(entry.attributes & (1 << type))) {
|
||||
// This type is not supported
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_not_out && !in_allowed) {
|
||||
// In endpoint not supported
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_not_out && !out_allowed) {
|
||||
// Out endpoint not supported
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_used & (1 << index)) {
|
||||
// This endpoint is in use
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shared && (1 << other)) {
|
||||
// This endpoint can only be one direction at a time and is in
|
||||
// use by the other direction
|
||||
continue;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Not found
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ENDPOINT_RESOLVER_H
|
||||
#define ENDPOINT_RESOLVER_H
|
||||
|
||||
#include "mbed.h"
|
||||
|
||||
#include "USBPhy.h"
|
||||
|
||||
/**
|
||||
* Utility class for resolving endpoints
|
||||
*
|
||||
* This class is intended to make the process of
|
||||
* selecting the correct endpoint from a device endpoint
|
||||
* table easier. It also provides a verification function
|
||||
* to check if the device has enough resources for the
|
||||
* given configuration.
|
||||
*
|
||||
* @ingroup usb_device_core
|
||||
*/
|
||||
class EndpointResolver {
|
||||
public:
|
||||
EndpointResolver(const usb_ep_table_t *table);
|
||||
~EndpointResolver();
|
||||
|
||||
/**
|
||||
* Add control endpoint size
|
||||
*
|
||||
* @param size Space reserved for control in and control out
|
||||
*/
|
||||
void endpoint_ctrl(uint32_t size);
|
||||
|
||||
/**
|
||||
* Return a free IN endpoint of the given size
|
||||
*
|
||||
* @param type Desired endpoint type
|
||||
* @param size Space to reserve for this endpoint
|
||||
* @return Endpoint index or 0 if there are not enough resources
|
||||
*/
|
||||
usb_ep_t endpoint_in(usb_ep_type_t type, uint32_t size);
|
||||
|
||||
/**
|
||||
* Return a free OUT endpoint of the given size
|
||||
*
|
||||
* @param type Desired endpoint type
|
||||
* @param size Space to reserve for this endpoint
|
||||
* @return Endpoint index or 0 if there are not enough resources
|
||||
*/
|
||||
usb_ep_t endpoint_out(usb_ep_type_t type, uint32_t size);
|
||||
|
||||
/**
|
||||
* Check if the endpoint configuration created so far is valid
|
||||
*
|
||||
* @return true if all endpoint sizes are available and fit, false otherwise
|
||||
*/
|
||||
bool valid();
|
||||
|
||||
/**
|
||||
* Reset this class's state to when it was constructed
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
usb_ep_t index_to_endpoint(int index);
|
||||
int next_index(usb_ep_type_t type, bool in_not_out);
|
||||
|
||||
const usb_ep_table_t *_table;
|
||||
uint32_t _cost;
|
||||
uint32_t _used;
|
||||
bool _valid;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue