mbed-os5 only for TYBLE16
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
Diff: drivers/internal/USBDevice.h
- Revision:
- 1:9db0e321a9f4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/internal/USBDevice.h Tue Dec 31 06:02:27 2019 +0000 @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * 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 USBDEVICE_H +#define USBDEVICE_H + +#include <stddef.h> +#include "USBDevice_Types.h" +#include "USBPhy.h" +#include "mbed_critical.h" +#include "Callback.h" + +/** + * \defgroup drivers_USBDevice USBDevice class + * \ingroup drivers-internal-api-usb + * @{ + */ + +/** + * Core USB Device driver + * + * USB driver which wraps and provides synchronization for a USBPhy object. + */ +class USBDevice: public USBPhyEvents { +public: + typedef void (USBDevice::*ep_cb_t)(); + + 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 + * + * @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); + + /** + * Cleanup this USBDevice + * + * This USBDevice must be uninitialized when the destructor is + * called or the behavior is undefined. + */ + virtual ~USBDevice(); + + /** + * 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. + * This method can be used for temporary power-saving; This call can allow + * USB to be temporarily disabled to permit power saving. + * However, it is up to the user to make sure all the + * transfers have concluded (for example when USB power is lost). + * USBDevice::connect can be used to resume USB operation. + */ + void deinit(); + + /** + * Check if the device is configured + * + * @returns true if configured, false otherwise + */ + bool configured(); + + /** + * Connect a device + * This method can also be used to resume USB operation when USB power is + * detected after it was suspended via USBDevice::deinit. + */ + void connect(); + + /** + * Disconnect a device + */ + 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 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 endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, mbed::Callback<void()> callback = NULL); + + /** + * Add an 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 + */ + template<typename T> + bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, void (T::*callback)()) + { + return endpoint_add(endpoint, max_packet, type, mbed::callback(this, static_cast<ep_cb_t>(callback))); + } + + /** + * Remove an endpoint + * + * @param endpoint Endpoint to disable + * @note This endpoint must already have been setup with endpoint_add + */ + void endpoint_remove(usb_ep_t endpoint); + + /** + * Remove all non-zero endpoints + */ + void endpoint_remove_all(); + + /** + * Stall an endpoint + * + * If there is an ongoing transfer on this endpoint then it will + * be aborted. + * + * @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 + */ + void endpoint_stall(usb_ep_t endpoint); + + /** + * Un-stall an endpoint + * + * Un-stalling an endpoint resets data toggle back to DATA0. + * Additionally, if there is an ongoing transfer on this endpoint + * it will be aborted. + * + * @param endpoint Endpoint to un-stall + * @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 + * + * Return the currently configured maximum packet size, wMaxPacketSize, + * for this endpoint. + * @note This endpoint must already have been setup with endpoint_add + */ + uint32_t endpoint_max_packet_size(usb_ep_t endpoint); + + /** + * Abort the current transfer on this endpoint + * + * @param endpoint endpoint with transfer to abort + * @note This endpoint must already have been setup with endpoint_add + */ + void endpoint_abort(usb_ep_t endpoint); + + /** + * start a read on the given endpoint + * + * Start a read on the given endpoint. The data buffer must remain + * unchanged until the transfer either completes or is aborted. + * + * @param endpoint endpoint to read data from + * @param buffer buffer to fill with read data + * @param size The size of data to read. This must be greater than or equal + * to the max packet size for this endpoint + * @return true if the read was completed, otherwise false + * @note This endpoint must already have been setup with endpoint_add + */ + bool read_start(usb_ep_t endpoint, uint8_t *buffer, uint32_t size); + + /** + * Get the status of a read + * + * @param endpoint endpoint to get the status of + * @return number of bytes read by this endpoint + */ + uint32_t read_finish(usb_ep_t endpoint); + + /** + * Write a data to the given endpoint + * + * Write data to an endpoint. The data sent must remain unchanged until + * the transfer either completes or is aborted. + * + * @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_start(usb_ep_t endpoint, uint8_t *buffer, uint32_t size); + + /** + * Get the status of a write + * + * @param endpoint endpoint to get the status of + * @return number of bytes sent by this endpoint + */ + uint32_t write_finish(usb_ep_t endpoint); + + /* + * Get device descriptor. + * + * @returns pointer to the device descriptor + */ + virtual const uint8_t *device_desc(); + + /* + * Get configuration descriptor + * + * @param index descriptor index + * @returns pointer to the configuration descriptor + */ + virtual const uint8_t *configuration_desc(uint8_t index) = 0; + + /* + * Get string lang id descriptor + * + * @return pointer to the string lang id descriptor + */ + virtual const uint8_t *string_langid_desc(); + + /* + * Get string manufacturer descriptor + * + * @returns pointer to the string manufacturer descriptor + */ + virtual const uint8_t *string_imanufacturer_desc(); + + /* + * Get string product descriptor + * + * @returns pointer to the string product descriptor + */ + virtual const uint8_t *string_iproduct_desc(); + + /* + * Get string serial descriptor + * + * @returns pointer to the string serial descriptor + */ + virtual const uint8_t *string_iserial_desc(); + + /* + * Get string configuration descriptor + * + * @returns pointer to the string configuration descriptor + */ + virtual const uint8_t *string_iconfiguration_desc(); + + /* + * Get string interface descriptor + * + * @returns pointer to the string interface descriptor + */ + virtual const uint8_t *string_iinterface_desc(); + + /* + * Get the length of the report descriptor + * + * @returns length of the report descriptor + */ + virtual uint16_t report_desc_dength() + { + return 0; + }; + +protected: + + /** + * 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 + * @param index Configuration descriptor index ( 0 if only one configuration present ) + * @return A descriptor of the given type or NULL if none were found + */ + uint8_t *find_descriptor(uint8_t descriptor_type, uint8_t index = 0); + + /** + * 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: + // 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); + + 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); + void _run_later(void (USBDevice::*function)()); + + void _complete_request(); + void _complete_request_xfer_done(); + void _complete_set_configuration(); + void _complete_set_interface(); + + struct endpoint_info_t { + mbed::Callback<void()> callback; + uint16_t max_packet_size; + uint16_t transfer_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 + }; + + enum UserCallback { + None, + Request, + RequestXferDone, + SetConfiguration, + SetInterface + }; + + struct complete_request_t { + RequestResult result; + uint8_t *data; + uint32_t size; + }; + + union complete_args_t { + complete_request_t request; + bool status; + }; + + struct control_transfer_t { + setup_packet_t setup; + uint8_t *ptr; + uint32_t remaining; + uint8_t direction; + bool zlp; + bool notify; + ControlState stage; + UserCallback user_callback; + complete_args_t args; + }; + + endpoint_info_t _endpoint_info[32 - 2]; + + USBPhy *_phy; + bool _initialized; + bool _connected; + bool _endpoint_add_remove_allowed; + control_transfer_t _transfer; + usb_device_t _device; + uint32_t _max_packet_size_ep0; + void (USBDevice::*_post_process)(); + + bool _setup_ready; + bool _abort_control; + + uint16_t _current_interface; + uint8_t _current_alternate; + uint32_t _locked; +}; + +/** @}*/ + +#endif