| Channagoud Kadabi | c14b2a5 | 2015-01-06 15:05:12 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 2 | * | 
|  | 3 | * Redistribution and use in source and binary forms, with or without | 
|  | 4 | * modification, are permitted provided that the following conditions are | 
|  | 5 | * met: | 
|  | 6 | *     * Redistributions of source code must retain the above copyright | 
|  | 7 | *       notice, this list of conditions and the following disclaimer. | 
|  | 8 | *     * Redistributions in binary form must reproduce the above | 
|  | 9 | *       copyright notice, this list of conditions and the following | 
|  | 10 | *       disclaimer in the documentation and/or other materials provided | 
|  | 11 | *       with the distribution. | 
|  | 12 | *     * Neither the name of The Linux Foundation nor the names of its | 
|  | 13 | *       contributors may be used to endorse or promote products derived | 
|  | 14 | *       from this software without specific prior written permission. | 
|  | 15 | * | 
|  | 16 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED | 
|  | 17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 
|  | 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT | 
|  | 19 | * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS | 
|  | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
|  | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
|  | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | 
|  | 23 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 
|  | 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | 
|  | 25 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | 
|  | 26 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | 27 | */ | 
|  | 28 |  | 
|  | 29 | /* This file implements the UDC (usb device controller) layer to be used with | 
|  | 30 | * the new dwc controller. | 
|  | 31 | * It exposes APIs to initialize UDC (and thus usb) and perform data transfer | 
|  | 32 | * over usb. | 
|  | 33 | */ | 
|  | 34 |  | 
|  | 35 | #include <reg.h> | 
|  | 36 | #include <debug.h> | 
|  | 37 | #include <string.h> | 
|  | 38 | #include <malloc.h> | 
|  | 39 | #include <stdlib.h> | 
|  | 40 | #include <arch/defines.h> | 
|  | 41 | #include <dev/udc.h> | 
|  | 42 | #include <platform/iomap.h> | 
|  | 43 | #include <usb30_dwc.h> | 
|  | 44 | #include <usb30_wrapper.h> | 
|  | 45 | #include <usb30_udc.h> | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 46 | #include <smem.h> | 
|  | 47 | #include <board.h> | 
|  | 48 | #include <platform/timer.h> | 
| Channagoud Kadabi | 1f24f8a | 2015-02-11 15:43:10 -0800 | [diff] [blame] | 49 | #include <qmp_phy.h> | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 50 |  | 
|  | 51 | //#define DEBUG_USB | 
|  | 52 |  | 
|  | 53 | #ifdef DEBUG_USB | 
|  | 54 | #define DBG(...) dprintf(ALWAYS, __VA_ARGS__) | 
|  | 55 | #else | 
|  | 56 | #define DBG(...) | 
|  | 57 | #endif | 
|  | 58 |  | 
|  | 59 | #define ERR(...) dprintf(ALWAYS, __VA_ARGS__) | 
|  | 60 |  | 
|  | 61 | /* control data transfer is max 512 bytes */ | 
|  | 62 | #define UDC_CONTROL_RX_BUF_SIZE     512 | 
|  | 63 | #define UDC_CONTROL_TX_BUF_SIZE     512 | 
|  | 64 |  | 
|  | 65 | /* Buffer used by dwc driver to process events. | 
|  | 66 | * Must be multiple of 4: snps 6.2.7.2. | 
|  | 67 | */ | 
|  | 68 | #define UDC_DWC_EVENT_BUF_SIZE     4096 | 
|  | 69 |  | 
|  | 70 | /* macro to parse setup request */ | 
|  | 71 | #define SETUP(type,request) (((type) << 8) | (request)) | 
|  | 72 |  | 
|  | 73 | /* macro to generate bit representation of an EP */ | 
|  | 74 | #define EPT_TX(n) (1 << ((n) + 16)) | 
|  | 75 | #define EPT_RX(n) (1 << (n)) | 
|  | 76 |  | 
| Channagoud Kadabi | 4ec4421 | 2014-11-03 14:54:12 -0800 | [diff] [blame] | 77 | /* Macro for bulk SS EP descriptors */ | 
|  | 78 | #define EP_BULK_IN_INDEX          21 | 
|  | 79 | #define EP_BULK_OUT_INDEX         34 | 
|  | 80 |  | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 81 | /* Local functions */ | 
|  | 82 | static struct udc_descriptor *udc_descriptor_alloc(uint32_t type, | 
|  | 83 | uint32_t num, | 
|  | 84 | uint32_t len, | 
|  | 85 | udc_desc_spec_t spec); | 
|  | 86 | static uint8_t udc_string_desc_alloc(udc_t *udc, const char *str); | 
|  | 87 |  | 
|  | 88 | static void udc_descriptor_register(udc_t *udc, struct udc_descriptor *desc); | 
|  | 89 | static void udc_register_language_desc(udc_t *udc); | 
|  | 90 | static void udc_register_bos_desc(udc_t *udc); | 
|  | 91 | static void udc_register_device_desc_usb_20(udc_t *udc, struct udc_device *dev_info); | 
|  | 92 | static void udc_register_device_desc_usb_30(udc_t *udc, struct udc_device *dev_info); | 
|  | 93 | static void udc_register_config_desc_usb20(udc_t *udc, struct udc_gadget *gadget); | 
|  | 94 | static void udc_register_config_desc_usb30(udc_t *udc, struct udc_gadget *gadget); | 
|  | 95 |  | 
|  | 96 | static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data); | 
|  | 97 | static void udc_ept_comp_desc_fill(struct udc_endpoint *ept, uint8_t *data); | 
|  | 98 |  | 
|  | 99 | static void udc_dwc_notify(void *context, dwc_notify_event_t event); | 
|  | 100 | static int udc_handle_setup(void *context, uint8_t *data); | 
|  | 101 |  | 
|  | 102 | /* TODO: This must be the only global var in this file, for now. | 
|  | 103 | * Ideally, all APIs should be sending | 
|  | 104 | * this to us and this ptr should be kept outside of this code. | 
|  | 105 | * This needs change in the common udc APIs and thus keeping it here until that | 
|  | 106 | * is done. | 
|  | 107 | */ | 
|  | 108 | static udc_t *udc_dev = NULL; | 
|  | 109 |  | 
|  | 110 |  | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 111 | __WEAK int platform_is_8974() | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 112 | { | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 113 | return 0; | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 114 | } | 
|  | 115 |  | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 116 | __WEAK int platform_is_8974Pro() | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 117 | { | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 118 | return 0; | 
|  | 119 | } | 
|  | 120 |  | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 121 | static void phy_reset(usb_wrapper_dev_t *wrapper, struct udc_device *dev_info) | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 122 | { | 
|  | 123 | /* phy reset is different for some platforms. */ | 
| Channagoud Kadabi | 7bb866c | 2014-02-18 11:53:06 -0800 | [diff] [blame] | 124 | if (platform_is_8974() || platform_is_8974Pro()) | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 125 | { | 
|  | 126 | /* SS PHY */ | 
|  | 127 | usb_wrapper_ss_phy_reset(wrapper); | 
|  | 128 |  | 
|  | 129 | /* For 8974: hs phy is reset as part of soft reset. | 
|  | 130 | * No need for explicit reset. | 
|  | 131 | */ | 
|  | 132 | } | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 133 | else | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 134 | { | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 135 | if (dev_info->t_usb_if->phy_reset) | 
|  | 136 | dev_info->t_usb_if->phy_reset(); | 
| Channagoud Kadabi | 685337e | 2013-11-13 13:53:24 -0800 | [diff] [blame] | 137 |  | 
|  | 138 | /* On some CDPs PHY_COMMON reset does not set | 
|  | 139 | * reset values in the phy_ctrl_common register. | 
|  | 140 | * Due to this USB does not get enumerated in fastboot | 
|  | 141 | * Force write the reset value | 
|  | 142 | */ | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 143 | if (board_platform_id() == APQ8084) | 
|  | 144 | usb_wrapper_hs_phy_ctrl_force_write(wrapper); | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 145 | } | 
|  | 146 | } | 
|  | 147 |  | 
|  | 148 | /* Initialize HS phy */ | 
|  | 149 | void hs_phy_init(udc_t *dev) | 
|  | 150 | { | 
|  | 151 | /* only for 8974 */ | 
| Channagoud Kadabi | 7bb866c | 2014-02-18 11:53:06 -0800 | [diff] [blame] | 152 | if (platform_is_8974() || platform_is_8974Pro()) | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 153 | { | 
|  | 154 | /* 5.a, 5.b */ | 
|  | 155 | usb_wrapper_hs_phy_init(dev->wrapper_dev); | 
|  | 156 |  | 
|  | 157 | /* 5.d */ | 
|  | 158 | dwc_usb2_phy_soft_reset(dev->dwc); | 
|  | 159 | } | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | /* vbus override */ | 
|  | 163 | void vbus_override(udc_t *dev) | 
|  | 164 | { | 
|  | 165 | /* when vbus signal is not available directly to the controller, | 
|  | 166 | * simulate vbus presense. | 
|  | 167 | */ | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 168 | usb_wrapper_vbus_override(dev->wrapper_dev); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 169 | } | 
|  | 170 |  | 
|  | 171 |  | 
|  | 172 | /* Initialize usb wrapper and dwc h/w blocks. */ | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 173 | static void usb30_init(struct udc_device *dev_info) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 174 | { | 
|  | 175 | usb_wrapper_dev_t* wrapper; | 
|  | 176 | usb_wrapper_config_t wrapper_config; | 
|  | 177 |  | 
|  | 178 | dwc_dev_t *dwc; | 
|  | 179 | dwc_config_t dwc_config; | 
|  | 180 |  | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 181 | /* initialize usb clocks */ | 
|  | 182 | if (dev_info->t_usb_if->clock_init) | 
|  | 183 | dev_info->t_usb_if->clock_init(); | 
|  | 184 |  | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 185 | /* initialize the usb wrapper h/w block */ | 
|  | 186 | wrapper_config.qscratch_base = (void*) MSM_USB30_QSCRATCH_BASE; | 
|  | 187 |  | 
|  | 188 | wrapper = usb_wrapper_init(&wrapper_config); | 
|  | 189 | ASSERT(wrapper); | 
|  | 190 |  | 
|  | 191 | /* save the wrapper ptr */ | 
|  | 192 | udc_dev->wrapper_dev = wrapper; | 
|  | 193 |  | 
|  | 194 | /* initialize the dwc device block */ | 
|  | 195 | dwc_config.base           = (void*) MSM_USB30_BASE; | 
|  | 196 |  | 
|  | 197 | /* buffer must be aligned to buf size. snps 8.2.2 */ | 
|  | 198 | dwc_config.event_buf      = memalign(lcm(CACHE_LINE, UDC_DWC_EVENT_BUF_SIZE), | 
|  | 199 | ROUNDUP(UDC_DWC_EVENT_BUF_SIZE, CACHE_LINE)); | 
|  | 200 | ASSERT(dwc_config.event_buf); | 
|  | 201 |  | 
|  | 202 | dwc_config.event_buf_size = UDC_DWC_EVENT_BUF_SIZE; | 
|  | 203 |  | 
|  | 204 | /* notify handler */ | 
|  | 205 | dwc_config.notify_context = udc_dev; | 
|  | 206 | dwc_config.notify         = udc_dwc_notify; | 
|  | 207 |  | 
|  | 208 | /* setup handler */ | 
|  | 209 | dwc_config.setup_context = udc_dev; | 
|  | 210 | dwc_config.setup_handler = udc_handle_setup; | 
|  | 211 |  | 
|  | 212 | dwc = dwc_init(&dwc_config); | 
|  | 213 | ASSERT(dwc); | 
|  | 214 |  | 
|  | 215 | /* save the dwc dev ptr */ | 
|  | 216 | udc_dev->dwc = dwc; | 
|  | 217 |  | 
|  | 218 |  | 
|  | 219 | /* USB3.0 core and phy initialization as described in HPG */ | 
|  | 220 |  | 
|  | 221 | /* section 4.4.1 Control sequence */ | 
|  | 222 | usb_wrapper_dbm_mode(wrapper, DBM_MODE_BYPASS); | 
|  | 223 |  | 
|  | 224 | /* section 4.4.1: use config 0 - all of RAM1 */ | 
|  | 225 | usb_wrapper_ram_configure(wrapper); | 
|  | 226 |  | 
|  | 227 | /* section 4.4.2: Initialization and configuration sequences */ | 
|  | 228 |  | 
|  | 229 | /* 1. UTMI Mux configuration */ | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 230 | if (dev_info->t_usb_if->mux_config) | 
|  | 231 | dev_info->t_usb_if->mux_config(); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 232 |  | 
|  | 233 | /* 2. Put controller in reset */ | 
|  | 234 | dwc_reset(dwc, 1); | 
|  | 235 |  | 
| Channagoud Kadabi | c14b2a5 | 2015-01-06 15:05:12 -0800 | [diff] [blame] | 236 |  | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 237 | /* Steps 3 - 7 must be done while dwc is in reset condition */ | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 238 |  | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 239 | /* 3. Reset PHY */ | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 240 | phy_reset(wrapper, dev_info); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 241 |  | 
|  | 242 | /* 4. SS phy config */ | 
| Channagoud Kadabi | 1f24f8a | 2015-02-11 15:43:10 -0800 | [diff] [blame] | 243 | if (!use_hsonly_mode()) | 
|  | 244 | usb_wrapper_ss_phy_configure(wrapper); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 245 |  | 
|  | 246 | /* 5. HS phy init */ | 
|  | 247 | usb_wrapper_hs_phy_init(wrapper); | 
|  | 248 |  | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 249 | /* 6. hs phy config */ | 
|  | 250 | usb_wrapper_hs_phy_configure(wrapper); | 
|  | 251 |  | 
|  | 252 | /* 7. Reset PHY digital interface */ | 
|  | 253 | dwc_phy_digital_reset(dwc); | 
|  | 254 |  | 
|  | 255 | /* 8. Bring dwc controller out of reset */ | 
|  | 256 | dwc_reset(dwc, 0); | 
|  | 257 |  | 
|  | 258 | /* 9. */ | 
|  | 259 | usb_wrapper_ss_phy_electrical_config(wrapper); | 
|  | 260 |  | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 261 | /* Perform phy init */ | 
|  | 262 | if (dev_info->t_usb_if->phy_init) | 
|  | 263 | dev_info->t_usb_if->phy_init(); | 
|  | 264 |  | 
| Channagoud Kadabi | 1f24f8a | 2015-02-11 15:43:10 -0800 | [diff] [blame] | 265 | /* HS only mode support */ | 
|  | 266 | if (use_hsonly_mode()) | 
|  | 267 | usb_wrapper_hsonly_mode(wrapper); | 
|  | 268 |  | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 269 | /* 10. */ | 
|  | 270 | usb_wrapper_workaround_10(wrapper); | 
|  | 271 |  | 
|  | 272 | /* 11. */ | 
|  | 273 | usb_wrapper_workaround_11(wrapper); | 
|  | 274 |  | 
|  | 275 | /* 12. */ | 
|  | 276 | dwc_ss_phy_workaround_12(dwc); | 
|  | 277 |  | 
|  | 278 | /* 13. */ | 
|  | 279 | usb_wrapper_workaround_13(wrapper); | 
|  | 280 |  | 
|  | 281 | /* 14. needed only for host mode. ignored. */ | 
|  | 282 |  | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 283 | /* If the target does not support vbus detection in controller, | 
|  | 284 | * simulate vbus presence. | 
|  | 285 | */ | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 286 | if (dev_info->t_usb_if->vbus_override) | 
|  | 287 | vbus_override(udc_dev); | 
| Amol Jadi | 5418da3 | 2013-10-11 14:14:47 -0700 | [diff] [blame] | 288 |  | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 289 | /* 15 - 20 */ | 
|  | 290 | dwc_device_init(dwc); | 
|  | 291 | } | 
|  | 292 |  | 
|  | 293 | /* udc_init: creates and registers various usb descriptor */ | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 294 | int usb30_udc_init(struct udc_device *dev_info) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 295 | { | 
|  | 296 | /* create and initialize udc instance */ | 
|  | 297 | udc_dev = (udc_t*) malloc(sizeof(udc_t)); | 
|  | 298 | ASSERT(udc_dev); | 
|  | 299 |  | 
|  | 300 | /* initialize everything to 0 */ | 
|  | 301 | memset(udc_dev, 0 , sizeof(udc_t)); | 
|  | 302 |  | 
|  | 303 | /* malloc control data buffers */ | 
|  | 304 | udc_dev->ctrl_rx_buf = memalign(CACHE_LINE, ROUNDUP(UDC_CONTROL_RX_BUF_SIZE, CACHE_LINE)); | 
|  | 305 | ASSERT(udc_dev->ctrl_rx_buf); | 
|  | 306 |  | 
|  | 307 | udc_dev->ctrl_tx_buf = memalign(CACHE_LINE, ROUNDUP(UDC_CONTROL_TX_BUF_SIZE, CACHE_LINE)); | 
|  | 308 | ASSERT(udc_dev->ctrl_tx_buf); | 
|  | 309 |  | 
|  | 310 | /* initialize string id */ | 
|  | 311 | udc_dev->next_string_id  = 1; | 
|  | 312 |  | 
|  | 313 | /* Initialize ept data */ | 
|  | 314 | /* alloc table to assume EP0 In/OUT are already allocated.*/ | 
|  | 315 | udc_dev->ept_alloc_table = EPT_TX(0) | EPT_RX(0); | 
|  | 316 | udc_dev->ept_list        = NULL; | 
|  | 317 |  | 
| Channagoud Kadabi | 9a8062e | 2014-02-04 17:09:10 -0800 | [diff] [blame] | 318 | usb30_init(dev_info); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 319 |  | 
|  | 320 | /* register descriptors */ | 
|  | 321 | udc_register_language_desc(udc_dev); | 
|  | 322 | udc_register_device_desc_usb_20(udc_dev, dev_info); | 
|  | 323 | udc_register_device_desc_usb_30(udc_dev, dev_info); | 
|  | 324 | udc_register_bos_desc(udc_dev); | 
|  | 325 |  | 
|  | 326 | return 0; | 
|  | 327 | } | 
|  | 328 |  | 
|  | 329 | /* application registers its gadget by calling this func. | 
|  | 330 | * gadget == interface descriptor | 
|  | 331 | */ | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 332 | int usb30_udc_register_gadget(struct udc_gadget *gadget) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 333 | { | 
|  | 334 | ASSERT(gadget); | 
|  | 335 |  | 
|  | 336 | /* check if already registered */ | 
|  | 337 | if (udc_dev->gadget) | 
|  | 338 | { | 
|  | 339 | ERR("\nonly one gadget supported\n"); | 
|  | 340 | return -1; | 
|  | 341 | } | 
|  | 342 |  | 
|  | 343 | /* create our configuration descriptors based on this gadget data */ | 
|  | 344 | udc_register_config_desc_usb20(udc_dev, gadget); | 
|  | 345 | udc_register_config_desc_usb30(udc_dev, gadget); | 
|  | 346 |  | 
|  | 347 | /* save the gadget */ | 
|  | 348 | udc_dev->gadget = gadget; | 
|  | 349 |  | 
|  | 350 | return 0; | 
|  | 351 | } | 
|  | 352 |  | 
|  | 353 | /* udc_start: */ | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 354 | int usb30_udc_start(void) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 355 | { | 
|  | 356 | /* 19. run | 
|  | 357 | * enable device to receive SOF packets and | 
|  | 358 | * respond to control transfers on EP0 and generate events. | 
|  | 359 | */ | 
|  | 360 | dwc_device_run(udc_dev->dwc, 1); | 
|  | 361 |  | 
|  | 362 | return 0; | 
|  | 363 | } | 
|  | 364 |  | 
|  | 365 | /* Control data rx callback. Called by DWC layer when it receives control | 
|  | 366 | * data from host. | 
|  | 367 | */ | 
|  | 368 | void udc_control_rx_callback(void *context, unsigned actual, int status) | 
|  | 369 | { | 
|  | 370 | udc_t *udc = (udc_t *) context; | 
|  | 371 |  | 
|  | 372 | /* Force reload of buffer update by controller from memory */ | 
|  | 373 | arch_invalidate_cache_range((addr_t) udc->ctrl_rx_buf, actual); | 
|  | 374 |  | 
|  | 375 | /* TODO: for now, there is only one 3-stage write during 3.0 enumeration | 
|  | 376 | * (SET_SEL), which causes this callback. Ideally, set_periodic() must | 
|  | 377 | * be based on which control rx just happened. | 
|  | 378 | * Also, the value of 0x65 should depend on the data received for SET_SEL. | 
|  | 379 | * For now, this value works just fine. | 
|  | 380 | */ | 
|  | 381 | dwc_device_set_periodic_param(udc->dwc, 0x65); | 
|  | 382 | } | 
|  | 383 |  | 
|  | 384 | /* lookup request name for debug purposes */ | 
|  | 385 | static const char *reqname(uint32_t r) | 
|  | 386 | { | 
|  | 387 | switch (r) { | 
|  | 388 | case GET_STATUS: | 
|  | 389 | return "GET_STATUS"; | 
|  | 390 | case CLEAR_FEATURE: | 
|  | 391 | return "CLEAR_FEATURE"; | 
|  | 392 | case SET_FEATURE: | 
|  | 393 | return "SET_FEATURE"; | 
|  | 394 | case SET_ADDRESS: | 
|  | 395 | return "SET_ADDRESS"; | 
|  | 396 | case GET_DESCRIPTOR: | 
|  | 397 | return "GET_DESCRIPTOR"; | 
|  | 398 | case SET_DESCRIPTOR: | 
|  | 399 | return "SET_DESCRIPTOR"; | 
|  | 400 | case GET_CONFIGURATION: | 
|  | 401 | return "GET_CONFIGURATION"; | 
|  | 402 | case SET_CONFIGURATION: | 
|  | 403 | return "SET_CONFIGURATION"; | 
|  | 404 | case GET_INTERFACE: | 
|  | 405 | return "GET_INTERFACE"; | 
|  | 406 | case SET_INTERFACE: | 
|  | 407 | return "SET_INTERFACE"; | 
|  | 408 | case SET_SEL: | 
|  | 409 | return "SET_SEL"; | 
|  | 410 | default: | 
|  | 411 | return "*UNKNOWN*"; | 
|  | 412 | } | 
|  | 413 | } | 
|  | 414 |  | 
|  | 415 | /* callback function called by DWC layer when a setup packed is received. | 
|  | 416 | * the return value tells dwc layer whether this setup pkt results in | 
|  | 417 | * a 2-stage or a 3-stage control transfer or stall. | 
|  | 418 | */ | 
|  | 419 | static int udc_handle_setup(void *context, uint8_t *data) | 
|  | 420 | { | 
|  | 421 | udc_t *udc = (udc_t *) context; | 
|  | 422 | uint32_t len; | 
|  | 423 |  | 
|  | 424 | ASSERT(udc); | 
|  | 425 |  | 
|  | 426 | dwc_dev_t *dwc = udc->dwc; | 
|  | 427 | ASSERT(dwc); | 
|  | 428 |  | 
|  | 429 | struct setup_packet s = *((struct setup_packet*) data); | 
|  | 430 |  | 
|  | 431 | DBG("\n SETUP request: \n type    = 0x%x \n request = 0x%x \n value  = 0x%x" | 
|  | 432 | " \n index   = 0x%x \n length  = 0x%x\n", | 
|  | 433 | s.type, s.request, s.value, s.index, s.length); | 
|  | 434 |  | 
|  | 435 | switch (SETUP(s.type, s.request)) | 
|  | 436 | { | 
|  | 437 | case SETUP(DEVICE_READ, GET_STATUS): | 
|  | 438 | { | 
|  | 439 | DBG("\n DEVICE_READ : GET_STATUS: value = %d index = %d" | 
|  | 440 | " length = %d", s.value, s.index, s.length); | 
|  | 441 |  | 
|  | 442 | if (s.length == 2) { | 
|  | 443 |  | 
|  | 444 | uint16_t zero = 0; | 
|  | 445 | len = 2; | 
|  | 446 |  | 
|  | 447 | /* copy to tx buffer */ | 
|  | 448 | memcpy(udc->ctrl_tx_buf, &zero, len); | 
|  | 449 |  | 
|  | 450 | /* flush buffer to main memory before queueing the request */ | 
|  | 451 | arch_clean_invalidate_cache_range((addr_t) udc->ctrl_tx_buf, len); | 
|  | 452 |  | 
|  | 453 | dwc_transfer_request(udc->dwc, | 
|  | 454 | 0, | 
|  | 455 | DWC_EP_DIRECTION_IN, | 
|  | 456 | udc->ctrl_tx_buf, | 
|  | 457 | len, | 
|  | 458 | NULL, | 
|  | 459 | NULL); | 
|  | 460 |  | 
|  | 461 | return DWC_SETUP_3_STAGE; | 
|  | 462 | } | 
|  | 463 | } | 
|  | 464 | break; | 
|  | 465 | case SETUP(DEVICE_READ, GET_DESCRIPTOR): | 
|  | 466 | { | 
|  | 467 | DBG("\n DEVICE_READ : GET_DESCRIPTOR: value = %d", s.value); | 
|  | 468 |  | 
|  | 469 | /* setup usb ep0-IN to send our device descriptor */ | 
|  | 470 | struct udc_descriptor *desc; | 
|  | 471 |  | 
|  | 472 | for (desc = udc->desc_list; desc; desc = desc->next) | 
|  | 473 | { | 
|  | 474 | /* tag must match the value AND | 
|  | 475 | * if speed is SS, desc must comply with 30 spec OR | 
|  | 476 | * if speed is not SS, desc must comply with 20 spec. | 
|  | 477 | */ | 
|  | 478 | if ((desc->tag == s.value) && | 
|  | 479 | (((udc->speed == UDC_SPEED_SS) && (desc->spec & UDC_DESC_SPEC_30)) || | 
|  | 480 | ((udc->speed != UDC_SPEED_SS) && (desc->spec & UDC_DESC_SPEC_20))) | 
|  | 481 | ) | 
|  | 482 | { | 
|  | 483 | if (desc->len > s.length) | 
|  | 484 | len = s.length; | 
|  | 485 | else | 
|  | 486 | len = desc->len; | 
|  | 487 |  | 
|  | 488 | /* copy to tx buffer */ | 
|  | 489 | memcpy(udc->ctrl_tx_buf, desc->data, len); | 
|  | 490 |  | 
|  | 491 | /* flush buffer to main memory before queueing the request */ | 
|  | 492 | arch_clean_invalidate_cache_range((addr_t) udc->ctrl_tx_buf, len); | 
|  | 493 |  | 
|  | 494 | dwc_transfer_request(udc->dwc, | 
|  | 495 | 0, | 
|  | 496 | DWC_EP_DIRECTION_IN, | 
|  | 497 | udc->ctrl_tx_buf, | 
|  | 498 | len, | 
|  | 499 | NULL, | 
|  | 500 | NULL); | 
|  | 501 |  | 
|  | 502 | return DWC_SETUP_3_STAGE; | 
|  | 503 | } | 
|  | 504 | } | 
|  | 505 | DBG("\n Did not find matching descriptor: = 0x%x", s.value); | 
|  | 506 | } | 
|  | 507 | break; | 
|  | 508 | case SETUP(DEVICE_READ, GET_CONFIGURATION): | 
|  | 509 | { | 
|  | 510 | DBG("\n DEVICE_READ : GET_CONFIGURATION"); | 
|  | 511 |  | 
|  | 512 | if ((s.value == 0) && (s.index == 0) && (s.length == 1)) { | 
|  | 513 |  | 
|  | 514 | len = 1; | 
|  | 515 |  | 
|  | 516 | /* copy to tx buffer */ | 
|  | 517 | memcpy(udc->ctrl_tx_buf, &udc->config_selected, len); | 
|  | 518 |  | 
|  | 519 | /* flush buffer to main memory before queueing the request */ | 
|  | 520 | arch_clean_invalidate_cache_range((addr_t) udc->ctrl_tx_buf, len); | 
|  | 521 |  | 
|  | 522 | dwc_transfer_request(udc->dwc, | 
|  | 523 | 0, | 
|  | 524 | DWC_EP_DIRECTION_IN, | 
|  | 525 | udc->ctrl_tx_buf, | 
|  | 526 | len, | 
|  | 527 | NULL, | 
|  | 528 | NULL); | 
|  | 529 |  | 
|  | 530 | return DWC_SETUP_3_STAGE; | 
|  | 531 | } | 
|  | 532 | else | 
|  | 533 | { | 
|  | 534 | ASSERT(0); | 
|  | 535 | } | 
|  | 536 | } | 
|  | 537 | break; | 
|  | 538 | case SETUP(DEVICE_WRITE, SET_CONFIGURATION): | 
|  | 539 | { | 
|  | 540 | DBG("\n DEVICE_WRITE : SET_CONFIGURATION"); | 
|  | 541 |  | 
|  | 542 | /* select configuration 1 */ | 
|  | 543 | if (s.value == 1) { | 
|  | 544 | struct udc_endpoint *ept; | 
|  | 545 | /* enable endpoints */ | 
|  | 546 | for (ept = udc->ept_list; ept; ept = ept->next) { | 
|  | 547 | if (ept->num == 0) | 
|  | 548 | continue; | 
|  | 549 | else | 
|  | 550 | { | 
|  | 551 | /* add this ep to dwc ep list */ | 
| Sundarajan Srinivasan | 1c42191 | 2014-03-31 17:55:31 -0700 | [diff] [blame] | 552 | dwc_ep_t *ep = (dwc_ep_t *) malloc(sizeof(dwc_ep_t)); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 553 |  | 
| Sundarajan Srinivasan | 1c42191 | 2014-03-31 17:55:31 -0700 | [diff] [blame] | 554 | if(!ep) | 
|  | 555 | { | 
|  | 556 | dprintf(CRITICAL, "udc_handle_setup: DEVICE_WRITE : SET_CONFIGURATION malloc failed for ep\n"); | 
|  | 557 | ASSERT(0); | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 | ep->number        = ept->num; | 
|  | 561 | ep->dir           = ept->in; | 
| Channagoud Kadabi | 5f8f1c4 | 2015-03-25 14:35:05 -0700 | [diff] [blame] | 562 | ep->type          = ept->type; | 
| Sundarajan Srinivasan | 1c42191 | 2014-03-31 17:55:31 -0700 | [diff] [blame] | 563 | ep->max_pkt_size  = ept->maxpkt; | 
|  | 564 | ep->burst_size    = ept->maxburst; | 
|  | 565 | ep->zlp           = 0;             /* TODO: zlp could be made part of ept */ | 
|  | 566 | ep->trb_count     = ept->trb_count; | 
|  | 567 | ep->trb           = ept->trb; | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 568 |  | 
|  | 569 | dwc_device_add_ep(dwc, ep); | 
| Sundarajan Srinivasan | 1c42191 | 2014-03-31 17:55:31 -0700 | [diff] [blame] | 570 |  | 
|  | 571 | if(ep) | 
|  | 572 | free(ep); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 573 | } | 
|  | 574 | } | 
|  | 575 |  | 
|  | 576 | /* now that we have saved the non-control EP details, set config */ | 
|  | 577 | dwc_device_set_configuration(dwc); | 
|  | 578 |  | 
|  | 579 | /* inform client that we are configured. */ | 
|  | 580 | udc->gadget->notify(udc_dev->gadget, UDC_EVENT_ONLINE); | 
|  | 581 |  | 
|  | 582 | udc->config_selected = 1; | 
|  | 583 |  | 
|  | 584 | return DWC_SETUP_2_STAGE; | 
|  | 585 | } | 
|  | 586 | else if (s.value == 0) | 
|  | 587 | { | 
|  | 588 | /* 0 == de-configure. */ | 
|  | 589 | udc->config_selected = 0; | 
|  | 590 | DBG("\n\n CONFIG = 0 !!!!!!!!!\n\n"); | 
|  | 591 | return DWC_SETUP_2_STAGE; | 
|  | 592 | /* TODO: do proper handling for de-config */ | 
|  | 593 | } | 
|  | 594 | else | 
|  | 595 | { | 
|  | 596 | ERR("\n CONFIG = %d not supported\n", s.value); | 
|  | 597 | ASSERT(0); | 
|  | 598 | } | 
|  | 599 | } | 
|  | 600 | break; | 
|  | 601 | case SETUP(DEVICE_WRITE, SET_ADDRESS): | 
|  | 602 | { | 
|  | 603 | DBG("\n DEVICE_WRITE : SET_ADDRESS"); | 
|  | 604 |  | 
|  | 605 | dwc_device_set_addr(dwc, s.value); | 
|  | 606 | return DWC_SETUP_2_STAGE; | 
|  | 607 | } | 
|  | 608 | break; | 
|  | 609 | case SETUP(INTERFACE_WRITE, SET_INTERFACE): | 
|  | 610 | { | 
|  | 611 | DBG("\n DEVICE_WRITE : SET_INTERFACE"); | 
|  | 612 | /* if we ack this everything hangs */ | 
|  | 613 | /* per spec, STALL is valid if there is not alt func */ | 
|  | 614 | goto stall; | 
|  | 615 | } | 
|  | 616 | break; | 
|  | 617 | case SETUP(DEVICE_WRITE, SET_FEATURE): | 
|  | 618 | { | 
|  | 619 | DBG("\n DEVICE_WRITE : SET_FEATURE"); | 
|  | 620 | goto stall; | 
|  | 621 | } | 
|  | 622 | break; | 
|  | 623 | case SETUP(DEVICE_WRITE, CLEAR_FEATURE): | 
|  | 624 | { | 
|  | 625 | DBG("\n DEVICE_WRITE : CLEAR_FEATURE"); | 
|  | 626 | goto stall; | 
|  | 627 | } | 
|  | 628 | break; | 
|  | 629 | case SETUP(ENDPOINT_WRITE, CLEAR_FEATURE): | 
|  | 630 | { | 
| Channagoud Kadabi | de1c162 | 2014-01-13 11:39:06 -0800 | [diff] [blame] | 631 | uint8_t usb_epnum; | 
|  | 632 | uint8_t dir; | 
|  | 633 |  | 
|  | 634 | DBG("\n ENDPOINT_WRITE : CLEAR_FEATURE"); | 
|  | 635 |  | 
|  | 636 | /* | 
|  | 637 | * setup packet received from the host has | 
|  | 638 | * index field containing information about the USB | 
|  | 639 | * endpoint as below: | 
|  | 640 | *  __________________________________ | 
|  | 641 | * | (7)  |   (6 - 4)   |  (3 - 0)    | | 
|  | 642 | * |DIR   |  Reserved   |  EP number  | | 
|  | 643 | * |______|_____________|_____________| | 
|  | 644 | */ | 
|  | 645 | usb_epnum = (s.index & USB_EP_NUM_MASK); | 
| Channagoud Kadabi | ca641d4 | 2014-11-21 16:58:51 -0800 | [diff] [blame] | 646 | dir = ((s.index & USB_EP_DIR_MASK) == USB_EP_DIR_IN) ? 0x1 : 0x0; | 
| Channagoud Kadabi | de1c162 | 2014-01-13 11:39:06 -0800 | [diff] [blame] | 647 |  | 
|  | 648 | /* | 
|  | 649 | * Convert the logical ep number to physical before | 
|  | 650 | * sending the clear stall command. | 
|  | 651 | * As per the data book we use fixed mapping as | 
|  | 652 | * below: | 
|  | 653 | * physical ep 0 --> logical ep0 OUT | 
|  | 654 | * physical ep 1 --> logical ep0 IN | 
|  | 655 | * physical ep 2 --> logical ep 1 OUT | 
|  | 656 | * physical ep 3 --> logical ep 1 IN | 
|  | 657 | * : | 
|  | 658 | * : | 
|  | 659 | * physical ep 30 --> logical ep 15 OUT | 
|  | 660 | * physical ep 31 --> logical ep 15 IN | 
|  | 661 | */ | 
|  | 662 | dwc_ep_cmd_clear_stall(dwc, DWC_EP_PHY_NUM(usb_epnum, dir)); | 
|  | 663 |  | 
|  | 664 | return DWC_SETUP_2_STAGE; | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 665 | } | 
|  | 666 | break; | 
|  | 667 | case SETUP(DEVICE_WRITE, SET_SEL): | 
|  | 668 | { | 
|  | 669 | DBG("\n DEVICE_WRITE : SET_SEL"); | 
|  | 670 |  | 
|  | 671 | /* this is 3-stage write. need to receive data of s.length size. */ | 
|  | 672 | if (s.length > 0) { | 
|  | 673 | dwc_transfer_request(udc->dwc, | 
|  | 674 | 0, | 
|  | 675 | DWC_EP_DIRECTION_OUT, | 
|  | 676 | udc->ctrl_rx_buf, | 
|  | 677 | UDC_CONTROL_RX_BUF_SIZE, | 
|  | 678 | udc_control_rx_callback, | 
|  | 679 | (void *) udc); | 
|  | 680 | return DWC_SETUP_3_STAGE; | 
|  | 681 | } | 
|  | 682 | else | 
|  | 683 | { | 
|  | 684 | /* length must be non-zero */ | 
|  | 685 | ASSERT(0); | 
|  | 686 | } | 
|  | 687 | } | 
|  | 688 | break; | 
|  | 689 |  | 
|  | 690 | default: | 
| Channagoud Kadabi | 4ec4421 | 2014-11-03 14:54:12 -0800 | [diff] [blame] | 691 | /* some of the requests from host are not handled, add a debug | 
|  | 692 | * for the command not being handled, this is not fatal | 
|  | 693 | */ | 
|  | 694 | DBG("\n Unknown setup req.\n type = 0x%x value = %d index = %d" | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 695 | " length = %d\n", s.type, s.value, s.index, s.length); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 696 | } | 
|  | 697 |  | 
|  | 698 | stall: | 
|  | 699 | ERR("\nSTALL. Unsupported setup req: %s %d %d %d %d %d\n", | 
|  | 700 | reqname(s.request), s.type, s.request, s.value, s.index, s.length); | 
|  | 701 |  | 
|  | 702 | return DWC_SETUP_ERROR; | 
|  | 703 | } | 
|  | 704 |  | 
|  | 705 | /* Callback function called by DWC layer when a request to transfer data | 
|  | 706 | * on non-control EP is completed. | 
|  | 707 | */ | 
|  | 708 | void udc_request_complete(void *context, uint32_t actual, int status) | 
|  | 709 | { | 
|  | 710 | struct udc_request *req = ((udc_t *) context)->queued_req; | 
|  | 711 |  | 
|  | 712 | DBG("\n UDC: udc_request_callback: xferred %d bytes status = %d\n", | 
|  | 713 | actual, status); | 
|  | 714 |  | 
|  | 715 | /* clear the queued request. */ | 
|  | 716 | ((udc_t *) context)->queued_req = NULL; | 
|  | 717 |  | 
|  | 718 | if (req->complete) | 
|  | 719 | { | 
|  | 720 | req->complete(req, actual, status); | 
|  | 721 | } | 
|  | 722 |  | 
|  | 723 | DBG("\n UDC: udc_request_callback: done fastboot callback\n"); | 
|  | 724 | } | 
|  | 725 |  | 
|  | 726 | /* App interface to queue in data transfer requests for control and data ep */ | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 727 | int usb30_udc_request_queue(struct udc_endpoint *ept, struct udc_request *req) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 728 | { | 
|  | 729 | int ret; | 
|  | 730 | dwc_dev_t *dwc_dev = udc_dev->dwc; | 
|  | 731 |  | 
|  | 732 | /* ensure device is initialized before queuing request */ | 
|  | 733 | ASSERT(dwc_dev); | 
|  | 734 |  | 
|  | 735 | /* if device is not configured, return error */ | 
|  | 736 | if(udc_dev->config_selected == 0) | 
|  | 737 | { | 
|  | 738 | return -1; | 
|  | 739 | } | 
|  | 740 |  | 
|  | 741 | /* only one request at a time is supported. | 
|  | 742 | * check if a request is already queued. | 
|  | 743 | */ | 
|  | 744 | if(udc_dev->queued_req) | 
|  | 745 | { | 
|  | 746 | return -1; | 
|  | 747 | } | 
|  | 748 |  | 
|  | 749 | DBG("\n udc_request_queue: entry: ep_usb_num = %d", ept->num); | 
|  | 750 |  | 
|  | 751 | /* save the queued request. */ | 
|  | 752 | udc_dev->queued_req = req; | 
|  | 753 |  | 
|  | 754 | ret = dwc_transfer_request(dwc_dev, | 
|  | 755 | ept->num, | 
|  | 756 | ept->in ? DWC_EP_DIRECTION_IN : DWC_EP_DIRECTION_OUT, | 
|  | 757 | req->buf, | 
|  | 758 | req->length, | 
|  | 759 | udc_request_complete, | 
|  | 760 | (void *) udc_dev); | 
|  | 761 |  | 
|  | 762 | DBG("\n udc_request_queue: exit: ep_usb_num = %d", ept->num); | 
|  | 763 |  | 
|  | 764 | return ret; | 
|  | 765 | } | 
|  | 766 |  | 
| Channagoud Kadabi | 4ec4421 | 2014-11-03 14:54:12 -0800 | [diff] [blame] | 767 | static void udc_update_ep_desc(udc_t *udc, uint16_t max_pkt_sz_bulk) | 
|  | 768 | { | 
|  | 769 | struct udc_descriptor *desc= NULL; | 
|  | 770 | struct udc_endpoint *ept = NULL; | 
|  | 771 |  | 
|  | 772 | /* | 
|  | 773 | * By default the bulk EP are registered with 512 Bytes | 
|  | 774 | * as the max packet size. As per SS spec the max packet | 
|  | 775 | * size for bulk is 1024. Some hosts treat the descriptor | 
|  | 776 | * as invalid if the packet size is < 1024. Update the | 
|  | 777 | * descriptors once we are notifed with SS connect event | 
|  | 778 | */ | 
|  | 779 | for (desc = udc->desc_list; desc; desc = desc->next) | 
|  | 780 | { | 
|  | 781 | if (desc->data[EP_BULK_IN_INDEX] == EP_TYPE_BULK) | 
|  | 782 | { | 
|  | 783 | desc->data[EP_BULK_IN_INDEX + 1] = max_pkt_sz_bulk; | 
|  | 784 | desc->data[EP_BULK_IN_INDEX + 2]  = max_pkt_sz_bulk >> 8; | 
|  | 785 | } | 
|  | 786 |  | 
|  | 787 | if (desc->data[EP_BULK_OUT_INDEX] == EP_TYPE_BULK) | 
|  | 788 | { | 
|  | 789 | desc->data[EP_BULK_OUT_INDEX + 1] = max_pkt_sz_bulk; | 
|  | 790 | desc->data[EP_BULK_OUT_INDEX + 2]  = max_pkt_sz_bulk >> 8; | 
|  | 791 | } | 
|  | 792 | } | 
|  | 793 |  | 
|  | 794 | for (ept = udc->ept_list; ept; ept = ept->next) | 
|  | 795 | { | 
|  | 796 | ept->maxpkt = max_pkt_sz_bulk; | 
|  | 797 | } | 
|  | 798 | } | 
|  | 799 |  | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 800 | /* callback function called by dwc layer if any dwc event occurs */ | 
|  | 801 | void udc_dwc_notify(void *context, dwc_notify_event_t event) | 
|  | 802 | { | 
|  | 803 | udc_t *udc = (udc_t *) context; | 
| Channagoud Kadabi | 4ec4421 | 2014-11-03 14:54:12 -0800 | [diff] [blame] | 804 | uint32_t max_pkt_size = 0; | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 805 |  | 
|  | 806 | switch (event) | 
|  | 807 | { | 
|  | 808 | case DWC_NOTIFY_EVENT_CONNECTED_LS: | 
|  | 809 | udc->speed = UDC_SPEED_LS; | 
|  | 810 | break; | 
|  | 811 | case DWC_NOTIFY_EVENT_CONNECTED_FS: | 
|  | 812 | udc->speed = UDC_SPEED_FS; | 
| Channagoud Kadabi | 4ec4421 | 2014-11-03 14:54:12 -0800 | [diff] [blame] | 813 | /* For FS connection update the ep descriptor | 
|  | 814 | * with FS max packet size | 
|  | 815 | */ | 
|  | 816 | max_pkt_size = 64; | 
|  | 817 | udc_update_ep_desc(udc, max_pkt_size); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 818 | break; | 
|  | 819 | case DWC_NOTIFY_EVENT_CONNECTED_HS: | 
|  | 820 | udc->speed = UDC_SPEED_HS; | 
| Channagoud Kadabi | 4ec4421 | 2014-11-03 14:54:12 -0800 | [diff] [blame] | 821 | /* For HS connection update the ep descriptor | 
|  | 822 | * with HS max packet size | 
|  | 823 | */ | 
|  | 824 | max_pkt_size = 512; | 
|  | 825 | udc_update_ep_desc(udc, max_pkt_size); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 826 | break; | 
|  | 827 | case DWC_NOTIFY_EVENT_CONNECTED_SS: | 
|  | 828 | udc->speed = UDC_SPEED_SS; | 
| Channagoud Kadabi | 4ec4421 | 2014-11-03 14:54:12 -0800 | [diff] [blame] | 829 | /* For SS connection update the ep descriptor | 
|  | 830 | * with SS max packet size | 
|  | 831 | */ | 
|  | 832 | max_pkt_size = 1024; | 
|  | 833 | udc_update_ep_desc(udc, max_pkt_size); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 834 | break; | 
|  | 835 | case DWC_NOTIFY_EVENT_DISCONNECTED: | 
|  | 836 | case DWC_NOTIFY_EVENT_OFFLINE: | 
|  | 837 | udc->config_selected = 0; | 
|  | 838 | if (udc->gadget && udc->gadget->notify) | 
|  | 839 | udc->gadget->notify(udc->gadget, UDC_EVENT_OFFLINE); | 
|  | 840 | break; | 
|  | 841 | default: | 
|  | 842 | ASSERT(0); | 
|  | 843 | } | 
|  | 844 | } | 
|  | 845 |  | 
|  | 846 |  | 
|  | 847 | /******************* Function related to descriptor allocation etc.************/ | 
|  | 848 |  | 
|  | 849 | static struct udc_endpoint *_udc_endpoint_alloc(uint8_t num, | 
|  | 850 | uint8_t in, | 
| Channagoud Kadabi | 5f8f1c4 | 2015-03-25 14:35:05 -0700 | [diff] [blame] | 851 | uint8_t type, | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 852 | uint16_t max_pkt) | 
|  | 853 | { | 
|  | 854 | struct udc_endpoint *ept; | 
|  | 855 | udc_t *udc = udc_dev; | 
|  | 856 |  | 
|  | 857 | ept = malloc(sizeof(*ept)); | 
|  | 858 | ASSERT(ept); | 
|  | 859 |  | 
|  | 860 | ept->maxpkt     = max_pkt; | 
|  | 861 | ept->num        = num; | 
| Channagoud Kadabi | 5f8f1c4 | 2015-03-25 14:35:05 -0700 | [diff] [blame] | 862 | ept->type       = type; | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 863 | ept->in         = !!in; | 
|  | 864 | ept->maxburst   = 4;      /* no performance improvement is seen beyond burst size of 4 */ | 
|  | 865 | ept->trb_count  = 66;     /* each trb can transfer (16MB - 1). 65 for 1GB transfer + 1 for roundup/zero length pkt. */ | 
|  | 866 | ept->trb        = memalign(lcm(CACHE_LINE, 16), ROUNDUP(ept->trb_count*sizeof(dwc_trb_t), CACHE_LINE)); /* TRB must be aligned to 16 */ | 
|  | 867 | ASSERT(ept->trb); | 
|  | 868 |  | 
|  | 869 | /* push it on top of ept_list */ | 
|  | 870 | ept->next      = udc->ept_list; | 
|  | 871 | udc->ept_list  = ept; | 
|  | 872 |  | 
|  | 873 | return ept; | 
|  | 874 | } | 
|  | 875 |  | 
|  | 876 | /* Called to create non-control in/out End Point structures by the APP */ | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 877 | struct udc_endpoint *usb30_udc_endpoint_alloc(unsigned type, unsigned maxpkt) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 878 | { | 
|  | 879 | struct udc_endpoint *ept; | 
|  | 880 | uint8_t in; | 
|  | 881 | uint8_t n; | 
|  | 882 | udc_t *udc = udc_dev; | 
|  | 883 |  | 
|  | 884 | if (type == UDC_TYPE_BULK_IN) { | 
|  | 885 | in = 1; | 
| Channagoud Kadabi | 5f8f1c4 | 2015-03-25 14:35:05 -0700 | [diff] [blame] | 886 | type = EP_TYPE_BULK; | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 887 | } else if (type == UDC_TYPE_BULK_OUT) { | 
|  | 888 | in = 0; | 
| Channagoud Kadabi | 5f8f1c4 | 2015-03-25 14:35:05 -0700 | [diff] [blame] | 889 | type = EP_TYPE_BULK; | 
|  | 890 | } else if (type == UDC_TYPE_INTR_IN) { | 
|  | 891 | in = 1; | 
|  | 892 | type = EP_TYPE_INTERRUPT; | 
|  | 893 | } else if (type == UDC_TYPE_INTR_OUT){ | 
|  | 894 | in = 0; | 
|  | 895 | type = EP_TYPE_INTERRUPT; | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 896 | } else { | 
|  | 897 | return 0; | 
|  | 898 | } | 
|  | 899 |  | 
|  | 900 | for (n = 1; n < 16; n++) { | 
|  | 901 | uint32_t bit = in ? EPT_TX(n) : EPT_RX(n); | 
|  | 902 | if (udc->ept_alloc_table & bit) | 
|  | 903 | continue; | 
| Channagoud Kadabi | 5f8f1c4 | 2015-03-25 14:35:05 -0700 | [diff] [blame] | 904 | ept = _udc_endpoint_alloc(n, in, type, maxpkt); | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 905 | if (ept) | 
|  | 906 | udc->ept_alloc_table |= bit; | 
|  | 907 | return ept; | 
|  | 908 | } | 
|  | 909 | return 0; | 
|  | 910 | } | 
|  | 911 |  | 
|  | 912 |  | 
|  | 913 | /* create config + interface + ep desc for 2.0 */ | 
|  | 914 | static void udc_register_config_desc_usb20(udc_t *udc, | 
|  | 915 | struct udc_gadget *gadget) | 
|  | 916 | { | 
|  | 917 | uint8_t  *data; | 
|  | 918 | uint16_t  size; | 
|  | 919 | struct udc_descriptor *desc; | 
|  | 920 |  | 
|  | 921 | ASSERT(udc); | 
|  | 922 | ASSERT(gadget); | 
|  | 923 |  | 
|  | 924 | /* create our configuration descriptor */ | 
|  | 925 |  | 
|  | 926 | /* size is the total size of (config + interface + all EPs) descriptor */ | 
|  | 927 | size = UDC_DESC_SIZE_CONFIGURATION + | 
|  | 928 | UDC_DESC_SIZE_INTERFACE + | 
|  | 929 | (gadget->ifc_endpoints*UDC_DESC_SIZE_ENDPOINT); | 
|  | 930 |  | 
|  | 931 | desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size, UDC_DESC_SPEC_20); | 
|  | 932 |  | 
|  | 933 | data = desc->data; | 
|  | 934 |  | 
|  | 935 | /* Config desc */ | 
|  | 936 | data[0] = 0x09; | 
|  | 937 | data[1] = TYPE_CONFIGURATION; | 
|  | 938 | data[2] = size; | 
|  | 939 | data[3] = size >> 8; | 
|  | 940 | data[4] = 0x01;     /* number of interfaces */ | 
|  | 941 | data[5] = 0x01;     /* configuration value */ | 
|  | 942 | data[6] = 0x00;     /* configuration string */ | 
|  | 943 | data[7] = 0xC0;     /* attributes: reserved and self-powered set */ | 
|  | 944 | data[8] = 0x00;     /* max power: 0ma since we are self powered */ | 
|  | 945 | data += 9; | 
|  | 946 |  | 
|  | 947 | /* Interface desc */ | 
|  | 948 | data[0] = 0x09; | 
|  | 949 | data[1] = TYPE_INTERFACE; | 
|  | 950 | data[2] = 0x00;     /* ifc number */ | 
|  | 951 | data[3] = 0x00;     /* alt number */ | 
|  | 952 | data[4] = gadget->ifc_endpoints; | 
|  | 953 | data[5] = gadget->ifc_class; | 
|  | 954 | data[6] = gadget->ifc_subclass; | 
|  | 955 | data[7] = gadget->ifc_protocol; | 
|  | 956 | data[8] = udc_string_desc_alloc(udc, gadget->ifc_string); | 
|  | 957 | data += 9; | 
|  | 958 |  | 
|  | 959 | for (uint8_t n = 0; n < gadget->ifc_endpoints; n++) { | 
|  | 960 | udc_ept_desc_fill(gadget->ept[n], data); | 
|  | 961 | data += UDC_DESC_SIZE_ENDPOINT; | 
|  | 962 | } | 
|  | 963 |  | 
|  | 964 | udc_descriptor_register(udc, desc); | 
|  | 965 | } | 
|  | 966 |  | 
|  | 967 | /* create config + interface + ep desc for 3.0 */ | 
|  | 968 | static void udc_register_config_desc_usb30(udc_t *udc, | 
|  | 969 | struct udc_gadget *gadget) | 
|  | 970 | { | 
|  | 971 | uint8_t *data; | 
|  | 972 | uint16_t size; | 
|  | 973 | struct udc_descriptor *desc; | 
|  | 974 |  | 
|  | 975 | ASSERT(udc); | 
|  | 976 | ASSERT(gadget); | 
|  | 977 |  | 
|  | 978 | /* create our configuration descriptor */ | 
|  | 979 |  | 
|  | 980 | /* size is the total size of (config + interface + all EPs) descriptor */ | 
|  | 981 | size = UDC_DESC_SIZE_CONFIGURATION + | 
|  | 982 | UDC_DESC_SIZE_INTERFACE + | 
|  | 983 | (gadget->ifc_endpoints*(UDC_DESC_SIZE_ENDPOINT + UDC_DESC_SIZE_ENDPOINT_COMP)); | 
|  | 984 |  | 
|  | 985 | desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size, UDC_DESC_SPEC_30); | 
|  | 986 |  | 
|  | 987 | data = desc->data; | 
|  | 988 |  | 
|  | 989 | /* Config desc */ | 
|  | 990 | data[0] = 0x09; | 
|  | 991 | data[1] = TYPE_CONFIGURATION; | 
|  | 992 | data[2] = size; | 
|  | 993 | data[3] = size >> 8; | 
|  | 994 | data[4] = 0x01;     /* number of interfaces */ | 
|  | 995 | data[5] = 0x01;     /* configuration value */ | 
|  | 996 | data[6] = 0x00;     /* configuration string */ | 
|  | 997 | data[7] = 0xC0;     /* attributes: reserved and self-powered set */ | 
|  | 998 | data[8] = 0x00;     /* max power: 0ma since we are self powered */ | 
|  | 999 | data += 9; | 
|  | 1000 |  | 
|  | 1001 | /* Interface desc */ | 
|  | 1002 | data[0] = 0x09; | 
|  | 1003 | data[1] = TYPE_INTERFACE; | 
|  | 1004 | data[2] = 0x00;     /* ifc number */ | 
|  | 1005 | data[3] = 0x00;     /* alt number */ | 
|  | 1006 | data[4] = gadget->ifc_endpoints; | 
|  | 1007 | data[5] = gadget->ifc_class; | 
|  | 1008 | data[6] = gadget->ifc_subclass; | 
|  | 1009 | data[7] = gadget->ifc_protocol; | 
|  | 1010 | data[8] = udc_string_desc_alloc(udc, gadget->ifc_string); | 
|  | 1011 | data += 9; | 
|  | 1012 |  | 
|  | 1013 | for (uint8_t n = 0; n < gadget->ifc_endpoints; n++) | 
|  | 1014 | { | 
|  | 1015 | /* fill EP desc */ | 
|  | 1016 | udc_ept_desc_fill(gadget->ept[n], data); | 
|  | 1017 | data += UDC_DESC_SIZE_ENDPOINT; | 
|  | 1018 |  | 
|  | 1019 | /* fill EP companion desc */ | 
|  | 1020 | udc_ept_comp_desc_fill(gadget->ept[n], data); | 
|  | 1021 | data += UDC_DESC_SIZE_ENDPOINT_COMP; | 
|  | 1022 | } | 
|  | 1023 |  | 
|  | 1024 | udc_descriptor_register(udc, desc); | 
|  | 1025 | } | 
|  | 1026 |  | 
|  | 1027 |  | 
|  | 1028 | static void udc_register_device_desc_usb_20(udc_t *udc, | 
|  | 1029 | struct udc_device *dev_info) | 
|  | 1030 | { | 
|  | 1031 | uint8_t *data; | 
|  | 1032 | struct udc_descriptor *desc; | 
|  | 1033 |  | 
|  | 1034 | /* create our device descriptor */ | 
|  | 1035 | desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18, UDC_DESC_SPEC_20); | 
|  | 1036 | data = desc->data; | 
|  | 1037 |  | 
|  | 1038 | /* data 0 and 1 is filled by descriptor alloc routine. | 
|  | 1039 | * fill in the remaining entries. | 
|  | 1040 | */ | 
|  | 1041 | data[2] = 0x00; /* usb spec minor rev */ | 
|  | 1042 | data[3] = 0x02; /* usb spec major rev */ | 
|  | 1043 | data[4] = 0x00; /* class */ | 
|  | 1044 | data[5] = 0x00; /* subclass */ | 
|  | 1045 | data[6] = 0x00; /* protocol */ | 
|  | 1046 | data[7] = 0x40; /* max packet size on ept 0 */ | 
|  | 1047 |  | 
|  | 1048 | memcpy(data + 8,  &dev_info->vendor_id,  sizeof(short)); | 
|  | 1049 | memcpy(data + 10, &dev_info->product_id, sizeof(short)); | 
|  | 1050 | memcpy(data + 12, &dev_info->version_id, sizeof(short)); | 
|  | 1051 |  | 
|  | 1052 | data[14] = udc_string_desc_alloc(udc, dev_info->manufacturer); | 
|  | 1053 | data[15] = udc_string_desc_alloc(udc, dev_info->product); | 
|  | 1054 | data[16] = udc_string_desc_alloc(udc, dev_info->serialno); | 
|  | 1055 | data[17] = 1; /* number of configurations */ | 
|  | 1056 |  | 
|  | 1057 | udc_descriptor_register(udc, desc); | 
|  | 1058 | } | 
|  | 1059 |  | 
|  | 1060 | static void udc_register_device_desc_usb_30(udc_t *udc, struct udc_device *dev_info) | 
|  | 1061 | { | 
|  | 1062 | uint8_t *data; | 
|  | 1063 | struct udc_descriptor *desc; | 
|  | 1064 |  | 
|  | 1065 | /* create our device descriptor */ | 
|  | 1066 | desc = udc_descriptor_alloc(TYPE_DEVICE, 0, 18, UDC_DESC_SPEC_30); | 
|  | 1067 | data = desc->data; | 
|  | 1068 |  | 
|  | 1069 | /* data 0 and 1 is filled by descriptor alloc routine. | 
|  | 1070 | * fill in the remaining entries. | 
|  | 1071 | */ | 
|  | 1072 | data[2] = 0x00; /* usb spec minor rev */ | 
|  | 1073 | data[3] = 0x03; /* usb spec major rev */ | 
|  | 1074 | data[4] = 0x00; /* class */ | 
|  | 1075 | data[5] = 0x00; /* subclass */ | 
|  | 1076 | data[6] = 0x00; /* protocol */ | 
|  | 1077 | data[7] = 0x09; /* max packet size on ept 0 */ | 
|  | 1078 | memcpy(data +  8, &dev_info->vendor_id,  sizeof(short)); | 
|  | 1079 | memcpy(data + 10, &dev_info->product_id, sizeof(short)); | 
|  | 1080 | memcpy(data + 12, &dev_info->version_id, sizeof(short)); | 
|  | 1081 | data[14] = udc_string_desc_alloc(udc, dev_info->manufacturer); | 
|  | 1082 | data[15] = udc_string_desc_alloc(udc, dev_info->product); | 
|  | 1083 | data[16] = udc_string_desc_alloc(udc, dev_info->serialno); | 
|  | 1084 | data[17] = 1; /* number of configurations */ | 
|  | 1085 |  | 
|  | 1086 | udc_descriptor_register(udc, desc); | 
|  | 1087 | } | 
|  | 1088 |  | 
|  | 1089 | static void udc_register_bos_desc(udc_t *udc) | 
|  | 1090 | { | 
|  | 1091 | uint8_t *data; | 
|  | 1092 | struct udc_descriptor *desc; | 
|  | 1093 |  | 
|  | 1094 | /* create our device descriptor */ | 
|  | 1095 | desc = udc_descriptor_alloc(TYPE_BOS, 0, 15, UDC_DESC_SPEC_30); /* 15 is total length of bos + other descriptors inside it */ | 
|  | 1096 | data = desc->data; | 
|  | 1097 |  | 
|  | 1098 | /* data 0 and 1 is filled by descriptor alloc routine. | 
|  | 1099 | * fill in the remaining entries. | 
|  | 1100 | */ | 
|  | 1101 | data[0] = 0x05;     /* BOS desc len */ | 
|  | 1102 | data[1] = TYPE_BOS; /* BOS desc type */ | 
|  | 1103 | data[2] = 0x0F;     /* total len of bos desc and its sub desc */ | 
|  | 1104 | data[3] = 0x00;     /* total len of bos desc and its sub desc */ | 
|  | 1105 | data[4] = 0x01;     /* num of sub desc inside bos */ | 
|  | 1106 |  | 
|  | 1107 | data[5]  = 0x0A;    /* desc len */ | 
|  | 1108 | data[6]  = 0x10;    /* Device Capability desc */ | 
|  | 1109 | data[7]  = 0x03;    /* 3 == SuperSpeed capable */ | 
|  | 1110 | data[8]  = 0x00;    /* Attribute: latency tolerance msg: No */ | 
|  | 1111 | data[9]  = 0x0F;    /* Supported Speeds (bit mask): LS, FS, HS, SS */ | 
|  | 1112 | data[10] = 0x00;    /* Reserved part of supported wSupportedSpeeds */ | 
|  | 1113 | data[11] = 0x01;    /* lowest supported speed with full functionality: FS */ | 
|  | 1114 | data[12] = 0x00;    /* U1 device exit latency */ | 
|  | 1115 | data[13] = 0x00;    /* U2 device exit latency (lsb) */ | 
|  | 1116 | data[14] = 0x00;    /* U2 device exit latency (msb) */ | 
|  | 1117 |  | 
|  | 1118 | udc_descriptor_register(udc, desc); | 
|  | 1119 | } | 
|  | 1120 |  | 
|  | 1121 | static void udc_register_language_desc(udc_t *udc) | 
|  | 1122 | { | 
|  | 1123 | /* create and register a language table descriptor */ | 
|  | 1124 | /* language 0x0409 is US English */ | 
|  | 1125 | struct udc_descriptor *desc = udc_descriptor_alloc(TYPE_STRING, | 
|  | 1126 | 0, | 
|  | 1127 | 4, | 
|  | 1128 | UDC_DESC_SPEC_20 | UDC_DESC_SPEC_30); | 
|  | 1129 | desc->data[2] = 0x09; | 
|  | 1130 | desc->data[3] = 0x04; | 
|  | 1131 | udc_descriptor_register(udc, desc); | 
|  | 1132 | } | 
|  | 1133 |  | 
|  | 1134 | static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data) | 
|  | 1135 | { | 
|  | 1136 | data[0] = 7; | 
|  | 1137 | data[1] = TYPE_ENDPOINT; | 
|  | 1138 | data[2] = ept->num | (ept->in ? 0x80 : 0x00); | 
|  | 1139 | data[3] = 0x02; /* bulk -- the only kind we support */ | 
|  | 1140 | data[4] = ept->maxpkt; | 
|  | 1141 | data[5] = ept->maxpkt >> 8; | 
|  | 1142 | data[6] = 0; /* bInterval: must be 0 for bulk. */ | 
|  | 1143 | } | 
|  | 1144 |  | 
|  | 1145 | static void udc_ept_comp_desc_fill(struct udc_endpoint *ept, uint8_t *data) | 
|  | 1146 | { | 
|  | 1147 | data[0] = 6;               /* bLength */ | 
|  | 1148 | data[1] = TYPE_SS_EP_COMP; /* ep type */ | 
|  | 1149 | data[2] = ept->maxburst;   /* maxBurst */ | 
|  | 1150 | data[3] = 0x0;             /* maxStreams */ | 
|  | 1151 | data[4] = 0x0;             /* wBytesPerInterval */ | 
|  | 1152 | data[5] = 0x0;             /* wBytesPerInterval */ | 
|  | 1153 | } | 
|  | 1154 |  | 
|  | 1155 | static uint8_t udc_string_desc_alloc(udc_t *udc, const char *str) | 
|  | 1156 | { | 
|  | 1157 | uint32_t len; | 
|  | 1158 | struct udc_descriptor *desc; | 
|  | 1159 | uint8_t *data; | 
|  | 1160 |  | 
|  | 1161 | if (udc->next_string_id > 255) | 
|  | 1162 | return 0; | 
|  | 1163 |  | 
|  | 1164 | if (!str) | 
|  | 1165 | return 0; | 
|  | 1166 |  | 
|  | 1167 | len = strlen(str); | 
|  | 1168 | desc = udc_descriptor_alloc(TYPE_STRING, | 
|  | 1169 | udc->next_string_id, | 
|  | 1170 | len * 2 + 2, | 
|  | 1171 | UDC_DESC_SPEC_20 | UDC_DESC_SPEC_30); | 
|  | 1172 | if (!desc) | 
|  | 1173 | return 0; | 
|  | 1174 | udc->next_string_id++; | 
|  | 1175 |  | 
|  | 1176 | /* expand ascii string to utf16 */ | 
|  | 1177 | data = desc->data + 2; | 
|  | 1178 | while (len-- > 0) { | 
|  | 1179 | *data++ = *str++; | 
|  | 1180 | *data++ = 0; | 
|  | 1181 | } | 
|  | 1182 |  | 
|  | 1183 | udc_descriptor_register(udc, desc); | 
|  | 1184 | return desc->tag & 0xff; | 
|  | 1185 | } | 
|  | 1186 |  | 
|  | 1187 |  | 
|  | 1188 | static struct udc_descriptor *udc_descriptor_alloc(uint32_t type, | 
|  | 1189 | uint32_t num, | 
|  | 1190 | uint32_t len, | 
|  | 1191 | udc_desc_spec_t spec) | 
|  | 1192 | { | 
|  | 1193 | struct udc_descriptor *desc; | 
|  | 1194 | if ((len > 255) || (len < 2) || (num > 255) || (type > 255)) | 
|  | 1195 | return 0; | 
|  | 1196 |  | 
|  | 1197 | if (!(desc = malloc(sizeof(struct udc_descriptor) + len))) | 
|  | 1198 | return 0; | 
|  | 1199 |  | 
|  | 1200 | desc->next    = 0; | 
|  | 1201 | desc->tag     = (type << 8) | num; | 
|  | 1202 | desc->len     = len; | 
|  | 1203 | desc->spec    = spec; | 
|  | 1204 |  | 
|  | 1205 | /* descriptor data */ | 
|  | 1206 | desc->data[0] = len; | 
|  | 1207 | desc->data[1] = type; | 
|  | 1208 |  | 
|  | 1209 | return desc; | 
|  | 1210 | } | 
|  | 1211 |  | 
|  | 1212 | static void udc_descriptor_register(udc_t *udc, struct udc_descriptor *desc) | 
|  | 1213 | { | 
|  | 1214 | desc->next     = udc->desc_list; | 
|  | 1215 | udc->desc_list = desc; | 
|  | 1216 | } | 
|  | 1217 |  | 
|  | 1218 |  | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 1219 | struct udc_request *usb30_udc_request_alloc(void) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 1220 | { | 
|  | 1221 | struct udc_request *req; | 
|  | 1222 |  | 
|  | 1223 | req = malloc(sizeof(*req)); | 
|  | 1224 | ASSERT(req); | 
|  | 1225 |  | 
|  | 1226 | req->buf      = 0; | 
|  | 1227 | req->length   = 0; | 
|  | 1228 | req->complete = NULL; | 
|  | 1229 | req->context  = 0; | 
|  | 1230 |  | 
|  | 1231 | return req; | 
|  | 1232 | } | 
|  | 1233 |  | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 1234 | void usb30_udc_request_free(struct udc_request *req) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 1235 | { | 
|  | 1236 | free(req); | 
|  | 1237 | } | 
|  | 1238 |  | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 1239 | void usb30_udc_endpoint_free(struct udc_endpoint *ept) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 1240 | { | 
|  | 1241 | /* TODO */ | 
|  | 1242 | } | 
|  | 1243 |  | 
| Amol Jadi | 151f2a5 | 2013-10-07 12:39:11 -0700 | [diff] [blame] | 1244 | int usb30_udc_stop(void) | 
| Amol Jadi | f3d5a89 | 2013-07-23 16:09:44 -0700 | [diff] [blame] | 1245 | { | 
|  | 1246 | dwc_device_run(udc_dev->dwc, 0); | 
|  | 1247 |  | 
|  | 1248 | return 0; | 
|  | 1249 | } |