Update USBDevice and configure to use a USBPhy

Update the USBDevice class API so it matches mbed-os's naming
conventions, has a more robust API and uses USBPhy as its backend.
pull/9768/head
Russ Butler 2018-02-27 10:23:14 -06:00
parent f7cb2cd280
commit caace4ac61
4 changed files with 1332 additions and 550 deletions

View File

@ -14,6 +14,9 @@
* limitations under the License.
*/
#ifndef USBDESCRIPTOR_H
#define USBDESCRIPTOR_H
/* Standard descriptor types */
#define DEVICE_DESCRIPTOR (1)
#define CONFIGURATION_DESCRIPTOR (2)
@ -44,9 +47,6 @@
#define LSB(n) ((n)&0xff)
#define MSB(n) (((n)&0xff00)>>8)
/* Convert physical endpoint number to descriptor endpoint number */
#define PHY_TO_DESC(endpoint) (((endpoint)>>1) | (((endpoint) & 1) ? 0x80:0))
/* bmAttributes in configuration descriptor */
/* C_RESERVED must always be set */
#define C_RESERVED (1U<<7)
@ -70,3 +70,5 @@
#define E_DATA (0x00)
#define E_FEEDBACK (0x10)
#define E_IMPLICIT_FEEDBACK (0x20)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -19,170 +19,241 @@
#include "mbed.h"
#include "USBDevice_Types.h"
#include "USBHAL.h"
#include "USBPhy.h"
#include "mbed_critical.h"
class USBDevice: public USBHAL {
/**
* \defgroup usb_device USB Device
*
*/
/**
* \defgroup usb_device_core Core
*
* @ingroup usb_device
*/
/**
* Core USB Device driver
*
* USB driver which wraps and provides synchronization for a USBPhy object.
*
* @ingroup usb_device_core
*/
class USBDevice: public USBPhyEvents {
public:
typedef void (USBDevice::*ep_cb_t)(usb_ep_t endpoint);
enum RequestResult {
Receive = 0,
Send = 1,
Success = 2,
Failure = 3,
PassThrough = 4,
};
enum DeviceState {
Attached,
Powered,
Default,
Address,
Configured
};
struct setup_packet_t {
struct {
uint8_t dataTransferDirection;
uint8_t Type;
uint8_t Recipient;
} bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
/**
* Instantiate a new USBDevice with the given parameters
*
* This function uses a target's built in USBPhy.
*
* @param vendor_id The USB vendor ID
* @param product_id The USB product ID
* @param product_release The device release number
*/
USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
/*
/**
* Instantiate a new USBDevice with the given parameters
*
* @param phy The USBPhy providing physical USB access
* @param vendor_id The USB vendor ID
* @param product_id The USB product ID
* @param product_release The device release number
*/
USBDevice(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
/**
* Initialize this instance
*
* This function must be called before calling
* any other functions of this class, unless specifically
*/
void init();
/**
* Power down this instance
*
* Disable interrupts and stop sending events.
*/
void deinit();
/**
* Check if the device is configured
*
* @returns true if configured, false otherwise
*/
bool configured(void);
bool configured();
/*
/**
* Connect a device
*
* @param blocking: block if not configured
*/
void connect(bool blocking = true);
/*
/**
* Disconnect a device
*/
void disconnect(void);
void disconnect();
/*
/**
* Enable the start of frame interrupt
*
* Call USBDevice::callback_sof on every frame.
*/
void sof_enable();
/**
* Disable the start of frame interrupt
*
* Stop calling USBDevice::callback_sof.
*/
void sof_disable();
/**
* Add an endpoint
*
* @param endpoint endpoint which will be added
* @param maxPacket Maximum size of a packet which can be sent for this endpoint
* @param endpoint Endpoint to enable
* @param max_packet Maximum size of a packet which can be sent or received on this endpoint
* @param type Endpoint type - USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO
* @param callback Method pointer to be called when a packet is transferred
* @returns true if successful, false otherwise
*/
bool addEndpoint(uint8_t endpoint, uint32_t maxPacket);
bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, ep_cb_t callback = NULL);
/*
* Start a reading on a certain endpoint.
* You can access the result of the reading by USBDevice_read
/**
* Add an endpoint
*
* @param endpoint endpoint which will be read
* @param maxSize the maximum length that can be read
* @return true if successful
* @param endpoint Endpoint to enable
* @param max_packet Maximum size of a packet which can be sent or received on this endpoint
* @param type Endpoint type - USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO
* @param callback Method pointer to be called when a packet is transferred
* @returns true if successful, false otherwise
*/
bool readStart(uint8_t endpoint, uint32_t maxSize);
/*
* Read a certain endpoint. Before calling this function, USBUSBDevice_readStart
* must be called.
*
* Warning: blocking
*
* @param endpoint endpoint which will be read
* @param buffer buffer will be filled with the data received
* @param size the number of bytes read will be stored in *size
* @param maxSize the maximum length that can be read
* @returns true if successful
*/
bool readEP(uint8_t endpoint, uint8_t *buffer, uint32_t *size, uint32_t maxSize);
/*
* Read a certain endpoint.
*
* Warning: non blocking
*
* @param endpoint endpoint which will be read
* @param buffer buffer will be filled with the data received (if data are available)
* @param size the number of bytes read will be stored in *size
* @param maxSize the maximum length that can be read
* @returns true if successful
*/
bool readEP_NB(uint8_t endpoint, uint8_t *buffer, uint32_t *size, uint32_t maxSize);
/*
* Write a certain endpoint.
*
* Warning: blocking
*
* @param endpoint endpoint to write
* @param buffer data contained in buffer will be write
* @param size the number of bytes to write
* @param maxSize the maximum length that can be written on this endpoint
*/
bool write(uint8_t endpoint, uint8_t *buffer, uint32_t size, uint32_t maxSize);
/*
* Write a certain endpoint.
*
* Warning: non blocking
*
* @param endpoint endpoint to write
* @param buffer data contained in buffer will be write
* @param size the number of bytes to write
* @param maxSize the maximum length that can be written on this endpoint
*/
bool writeNB(uint8_t endpoint, uint8_t *buffer, uint32_t size, uint32_t maxSize);
/*
* Called by USBDevice layer on bus reset. Warning: Called in ISR context
*
* May be used to reset state
*/
virtual void USBCallback_busReset(void) {};
/*
* Called by USBDevice on Endpoint0 request. Warning: Called in ISR context
* This is used to handle extensions to standard requests
* and class specific requests
*
* @returns true if class handles this request
*/
virtual bool USBCallback_request()
template<typename T>
bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, void (T::*callback)(usb_ep_t endpoint))
{
return false;
};
return endpoint_add(endpoint, max_packet, type, static_cast<ep_cb_t>(callback));
}
/*
* Called by USBDevice on Endpoint0 request completion
* if the 'notify' flag has been set to true. Warning: Called in ISR context
/**
* Remove an endpoint
*
* In this case it is used to indicate that a HID report has
* been received from the host on endpoint 0
*
* @param buf buffer received on endpoint 0
* @param length length of this buffer
* @param endpoint Endpoint to disable
* @note This endpoint must already have been setup with endpoint_add
*/
virtual void USBCallback_requestCompleted(uint8_t *buf, uint32_t length) {};
void endpoint_remove(usb_ep_t endpoint);
/*
* Called by USBDevice layer. Set configuration of the device.
* For instance, you can add all endpoints that you need on this function.
/**
* Stall an endpoint
*
* @param configuration Number of the configuration
* @param endpoint Endpoint to stall
* @note You cannot stall endpoint 0 with this function
* @note This endpoint must already have been setup with endpoint_add
*/
virtual bool USBCallback_setConfiguration(uint8_t configuration)
{
return false;
};
void endpoint_stall(usb_ep_t endpoint);
/*
* Called by USBDevice layer. Set interface/alternate of the device.
/**
* Unstall an endpoint
*
* @param endpoint Endpoint to unstall
* @note This endpoint must already have been setup with endpoint_add
*/
void endpoint_unstall(usb_ep_t endpoint);
/**
* Get the current maximum size for this endpoint
*
* @param interface Number of the interface to be configured
* @param alternate Number of the alternate to be configured
* @returns true if class handles this request
* Return the currently configured maximum packet size, wMaxPacketSize,
* for this endpoint.
* @note This endpoint must already have been setup with endpoint_add
*/
virtual bool USBCallback_setInterface(uint16_t interface, uint8_t alternate)
{
return false;
};
uint32_t endpoint_max_packet_size(usb_ep_t endpoint);
/** Start a read on the given endpoint
*
* After the read is finished call read_start to get the result.
*
* @param endpoint endpoint to perform the read on
* @return true if the read was started, false if no more reads can be started
* @note This endpoint must already have been setup with endpoint_add
*/
bool read_start(usb_ep_t endpoint);
/**
* Finish a read on the given endpoint
*
* Get the contents of a read started with read_start. To ensure all
* the data from this endpoint is read make sure the buffer and size
* passed is at least as big as the maximum packet for this endpoint.
*
* @param endpoint endpoint to read data from
* @param buffer buffer to fill with read data
* @param max_size the total size of the data buffer. This must be at least
* the max packet size of this endpoint
* @param size The size of data that was read
* @return true if the read was completed, otherwise false
* @note This endpoint must already have been setup with endpoint_add
*/
bool read_finish(usb_ep_t endpoint, uint8_t *buffer, uint32_t max_size, uint32_t *size);
/**
* Write a data to the given endpoint
*
* Write data to an endpoint.
*
* @param endpoint endpoint to write data to
* @param buffer data to write
* @param size the size of data to send. This must be less than or equal to the
* max packet size of this endpoint
* @note This endpoint must already have been setup with endpoint_add
*/
bool write(usb_ep_t endpoint, uint8_t *buffer, uint32_t size);
/*
* Get device descriptor.
*
* @returns pointer to the device descriptor
*/
virtual const uint8_t *deviceDesc();
virtual const uint8_t *device_desc();
/*
* Get configuration descriptor
*
* @returns pointer to the configuration descriptor
*/
virtual const uint8_t *configurationDesc()
virtual const uint8_t *configuration_desc()
{
return NULL;
};
@ -192,93 +263,308 @@ public:
*
* @return pointer to the string lang id descriptor
*/
virtual const uint8_t *stringLangidDesc();
virtual const uint8_t *string_langid_desc();
/*
* Get string manufacturer descriptor
*
* @returns pointer to the string manufacturer descriptor
*/
virtual const uint8_t *stringImanufacturerDesc();
virtual const uint8_t *string_imanufacturer_desc();
/*
* Get string product descriptor
*
* @returns pointer to the string product descriptor
*/
virtual const uint8_t *stringIproductDesc();
virtual const uint8_t *string_iproduct_desc();
/*
* Get string serial descriptor
*
* @returns pointer to the string serial descriptor
*/
virtual const uint8_t *stringIserialDesc();
virtual const uint8_t *string_iserial_desc();
/*
* Get string configuration descriptor
*
* @returns pointer to the string configuration descriptor
*/
virtual const uint8_t *stringIConfigurationDesc();
virtual const uint8_t *string_iconfiguration_desc();
/*
* Get string interface descriptor
*
* @returns pointer to the string interface descriptor
*/
virtual const uint8_t *stringIinterfaceDesc();
virtual const uint8_t *string_iinterface_desc();
/*
* Get the length of the report descriptor
*
* @returns length of the report descriptor
*/
virtual uint16_t reportDescLength()
virtual uint16_t report_desc_dength()
{
return 0;
};
protected:
virtual void busReset(void);
virtual void EP0setupCallback(void);
virtual void EP0out(void);
virtual void EP0in(void);
virtual void connectStateChanged(unsigned int connected);
virtual void suspendStateChanged(unsigned int suspended);
uint8_t *findDescriptor(uint8_t descriptorType);
CONTROL_TRANSFER *getTransferPtr(void);
uint16_t VENDOR_ID;
uint16_t PRODUCT_ID;
uint16_t PRODUCT_RELEASE;
uint8_t deviceDescriptor[18];
/**
* Called by USBDevice layer on power state change.
*
* @param powered true if device is powered, false otherwise
*
* Warning: Called in ISR context
*/
virtual void callback_power(bool powered)
{
}
/**
* Called by USBDevice layer on each new USB frame.
*
* Callbacks are enabled and disabled by calling sof_enable
* and sof_disable.
*
* @param frame_number The current frame number
*
* Warning: Called in ISR context
*/
virtual void callback_sof(int frame_number)
{
}
/**
* Called by USBDevice layer on bus reset.
*
* complete_reset must be called after
* the device is fully reset.
*
* Warning: Called in ISR context
*/
virtual void callback_reset()
{
}
/**
* Called when USB changes state
*
* @param new_state The new state of the USBDevice
*
* Warning: Called in ISR context
*/
virtual void callback_state_change(DeviceState new_state) = 0;
/**
* Called by USBDevice on Endpoint0 request.
*
* This is used to handle extensions to standard requests
* and class specific requests. The function complete_request
* must be always be called in response to this callback.
*
* Warning: Called in ISR context
*/
virtual void callback_request(const setup_packet_t *setup) = 0;
/**
* Called to complete the setup stage of a callback request
*
* Possible options that can be passed as a result are:
* - Receive - Start the data OUT phase of this control transfer
* - Send - Start the data IN phase of this control transfer
* - Success - Operation was a success so start the status phase
* - Failure - Operation failed or is unsupported so send a stall
* - PassThrough - Pass on the request for standard processing
*
* @param result The result of the setup phase.
* @param data Buffer to send or receive if the result is Send or Receive
* @param size Size to transfer if the result is Send or Receive
*/
void complete_request(RequestResult result, uint8_t *data=NULL, uint32_t size=0);
/**
* Called by USBDevice on data stage completion
*
* The function complete_request_xfer_done must be always be called
* in response to this callback.
*
* @param setup Setup packet of the current request
* @param aborted false if the operation was aborted, true otherwise
*
* Warning: Called in ISR context
*/
virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted) = 0;
/**
* Called to complete the data stage of a callback request
*
* @param success true if the operation was successful, false otherwise
*/
void complete_request_xfer_done(bool success);
/*
* Called by USBDevice layer in response to set_configuration.
*
* Upon reception of this command endpoints of the previous configuration
* if any must be removed with endpoint_remove and new endpoint added with
* endpoint_add.
*
* @param configuration Number of the configuration
*
* Warning: Called in ISR context
*/
virtual void callback_set_configuration(uint8_t configuration) = 0;
/**
* Called to complete a set configuration command
*
* @param success true if the configuration was set, false otherwise
*/
void complete_set_configuration(bool success);
/*
* Called by USBDevice layer in response to set_interface.
*
* Upon reception of this command endpoints of any previous interface
* if any must be removed with endpoint_remove and new endpoint added with
* endpoint_add.
*
* @param configuration Number of the configuration
*
* Warning: Called in ISR context
*/
virtual void callback_set_interface(uint16_t interface, uint8_t alternate) = 0;
/**
* Called to complete a set interface command
*
* @param success true if the interface was set, false otherwise
*/
void complete_set_interface(bool success);
/**
* Find a descriptor type inside the configuration descriptor
*
* @param descriptor_type Type of descriptor to find
* @return A descriptor of the given type or NULL if none were found
*/
uint8_t *find_descriptor(uint8_t descriptor_type);
/**
* Get the endpoint table of this device
*
* @return Endpoint table of the USBPhy attached to this USBDevice
*/
const usb_ep_table_t *endpoint_table();
/**
* Callback called to indicate the USB processing needs to be done
*/
virtual void start_process();
/**
* Acquire exclusive access to this instance USBDevice
*/
virtual void lock();
/**
* Release exclusive access to this instance USBDevice
*/
virtual void unlock();
/**
* Assert that the current thread of execution holds the lock
*
*/
virtual void assert_locked();
uint16_t vendor_id;
uint16_t product_id;
uint16_t product_release;
uint8_t device_descriptor[18];
private:
bool addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket);
bool requestGetDescriptor(void);
bool controlOut(void);
bool controlIn(void);
bool requestSetAddress(void);
bool requestSetConfiguration(void);
bool requestSetFeature(void);
bool requestClearFeature(void);
bool requestGetStatus(void);
bool requestSetup(void);
bool controlSetup(void);
void decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet);
bool requestGetConfiguration(void);
bool requestGetInterface(void);
bool requestSetInterface(void);
// USBPhyEvents
virtual void power(bool powered);
virtual void suspend(bool suspended);
virtual void sof(int frame_number);
virtual void reset();
virtual void ep0_setup();
virtual void ep0_out();
virtual void ep0_in();
virtual void out(usb_ep_t endpoint);
virtual void in(usb_ep_t endpoint);
CONTROL_TRANSFER transfer;
USB_DEVICE device;
bool _request_get_descriptor();
bool _control_out();
bool _control_in();
bool _request_set_address();
bool _request_set_configuration();
bool _request_set_feature();
bool _request_clear_feature();
bool _request_get_status();
bool _request_setup();
void _control_setup();
void _control_abort();
void _control_abort_start();
void _control_setup_continue();
void _decode_setup_packet(uint8_t *data, setup_packet_t *packet);
bool _request_get_configuration();
bool _request_get_interface();
bool _request_set_interface();
void _change_state(DeviceState state);
uint16_t currentInterface;
uint8_t currentAlternate;
struct endpoint_info_t {
void (USBDevice::*callback)(usb_ep_t endpoint);
uint16_t max_packet_size;
uint8_t flags;
uint8_t pending;
};
struct usb_device_t {
volatile DeviceState state;
uint8_t configuration;
bool suspended;
};
enum ControlState {
Setup,
DataOut,
DataIn,
Status
};
struct control_transfer_t {
setup_packet_t setup;
uint8_t *ptr;
uint32_t remaining;
uint8_t direction;
bool zlp;
bool notify;
ControlState stage;
bool user_callback;
};
endpoint_info_t _endpoint_info[32 - 2];
USBPhy *_phy;
bool _initialized;
control_transfer_t _transfer;
usb_device_t _device;
uint32_t _max_packet_size_ep0;
bool _setup_ready;
bool _abort_control;
uint16_t _current_interface;
uint8_t _current_alternate;
uint32_t _locked;
};
#endif

View File

@ -49,33 +49,4 @@
#define DESCRIPTOR_TYPE(wValue) (wValue >> 8)
#define DESCRIPTOR_INDEX(wValue) (wValue & 0xff)
typedef struct {
struct {
uint8_t dataTransferDirection;
uint8_t Type;
uint8_t Recipient;
} bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} SETUP_PACKET;
typedef struct {
SETUP_PACKET setup;
uint8_t *ptr;
uint32_t remaining;
uint8_t direction;
bool zlp;
bool notify;
} CONTROL_TRANSFER;
typedef enum {ATTACHED, POWERED, DEFAULT, ADDRESS, CONFIGURED} DEVICE_STATE;
typedef struct {
volatile DEVICE_STATE state;
uint8_t configuration;
bool suspended;
} USB_DEVICE;
#endif