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