yuezonghe | 824eb0c | 2024-06-27 02:32:26 -0700 | [diff] [blame] | 1 | /* ========================================================================== |
| 2 | * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $ |
| 3 | * $Revision: #101 $ |
| 4 | * $Date: 2012/08/10 $ |
| 5 | * $Change: 2047372 $ |
| 6 | * |
| 7 | * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, |
| 8 | * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless |
| 9 | * otherwise expressly agreed to in writing between Synopsys and you. |
| 10 | * |
| 11 | * The Software IS NOT an item of Licensed Software or Licensed Product under |
| 12 | * any End User Software License Agreement or Agreement for Licensed Product |
| 13 | * with Synopsys or any supplement thereto. You are permitted to use and |
| 14 | * redistribute this Software in source and binary forms, with or without |
| 15 | * modification, provided that redistributions of source code must retain this |
| 16 | * notice. You may not view, use, disclose, copy or distribute this file or |
| 17 | * any information contained herein except pursuant to this license grant from |
| 18 | * Synopsys. If you do not agree with this notice, including the disclaimer |
| 19 | * below, then you are not authorized to use the Software. |
| 20 | * |
| 21 | * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS |
| 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 24 | * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, |
| 25 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 28 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| 31 | * DAMAGE. |
| 32 | * ========================================================================== */ |
| 33 | #ifndef DWC_HOST_ONLY |
| 34 | |
| 35 | /** @file |
| 36 | * This file implements PCD Core. All code in this file is portable and doesn't |
| 37 | * use any OS specific functions. |
| 38 | * PCD Core provides Interface, defined in <code><dwc_otg_pcd_if.h></code> |
| 39 | * header file, which can be used to implement OS specific PCD interface. |
| 40 | * |
| 41 | * An important function of the PCD is managing interrupts generated |
| 42 | * by the DWC_otg controller. The implementation of the DWC_otg device |
| 43 | * mode interrupt service routines is in dwc_otg_pcd_intr.c. |
| 44 | * |
| 45 | * @todo Add Device Mode test modes (Test J mode, Test K mode, etc). |
| 46 | * @todo Does it work when the request size is greater than DEPTSIZ |
| 47 | * transfer size |
| 48 | * |
| 49 | */ |
| 50 | #include "global.h" |
| 51 | #include "dwc_otg_pcd.h" |
| 52 | |
| 53 | __align(4) const dwc_device_descriptor_t device_desc = |
| 54 | { |
| 55 | sizeof(dwc_device_descriptor_t), |
| 56 | DEVICE_DESCRIPTOR, |
| 57 | 0x0200, // usb 2.0 //usb 1.1 |
| 58 | 0x00, |
| 59 | 0x00, |
| 60 | 0x00, |
| 61 | CONTROL_64, // ×î´ó°ü8×Ö½Ú |
| 62 | USB_VENDOR_ID, |
| 63 | USB_PRODUCT_ID, |
| 64 | PRODUCT_RELEASE_NUMBER, |
| 65 | 0x01, // manufacturer descriptionË÷ÒýºÅ |
| 66 | 0x02, // product descriptionË÷ÒýºÅ |
| 67 | 0x03, // serial number descriptionË÷ÒýºÅ |
| 68 | 0x01 // ÅäÖÃÊý |
| 69 | }; |
| 70 | |
| 71 | __align(4) const dwc_dev_qual_descriptor_t dev_qual_desc = |
| 72 | { |
| 73 | sizeof(dwc_dev_qual_descriptor_t), |
| 74 | 0x06, |
| 75 | 0x0200, // usb 2.0 |
| 76 | VERDOR_SPECIFIC, |
| 77 | 0x00, |
| 78 | 0x00, |
| 79 | 64, |
| 80 | 0x01, // ÅäÖÃÊý |
| 81 | 0x0 |
| 82 | }; |
| 83 | |
| 84 | |
| 85 | |
| 86 | __align(4) const dwc_langid_descriptor_t tLanguage= |
| 87 | { |
| 88 | STRING_DESCRIPTOR_SIZE(1), |
| 89 | STRING_DESCRIPTOR, |
| 90 | LANGID_US_ENGLISH |
| 91 | }; |
| 92 | |
| 93 | __align(4) const dwc_string_descriptor_t tManufacture= |
| 94 | { |
| 95 | STRING_DESCRIPTOR_SIZE(11), |
| 96 | STRING_DESCRIPTOR, |
| 97 | UNICODE('Z'), UNICODE('T'), UNICODE('E'), UNICODE(' '), UNICODE('C'), |
| 98 | UNICODE('o'), UNICODE(','), UNICODE('L'), UNICODE('t'), UNICODE('d'), |
| 99 | UNICODE('.'), |
| 100 | }; |
| 101 | |
| 102 | __align(4) const dwc_string_descriptor_t tProduct= |
| 103 | { |
| 104 | STRING_DESCRIPTOR_SIZE(14), |
| 105 | STRING_DESCRIPTOR, |
| 106 | UNICODE('Z'), UNICODE('T'), UNICODE('E'), UNICODE(' '), UNICODE('B'), |
| 107 | UNICODE('o'), UNICODE('o'), UNICODE('t'), UNICODE('L'), UNICODE('o'), |
| 108 | UNICODE('a'), UNICODE('d'), UNICODE('e'), UNICODE('r') |
| 109 | }; |
| 110 | |
| 111 | __align(4) const dwc_string_descriptor_t tSN= |
| 112 | { |
| 113 | STRING_DESCRIPTOR_SIZE(16), |
| 114 | STRING_DESCRIPTOR, |
| 115 | UNICODE('z'), UNICODE('t'), UNICODE('e'), UNICODE('&'), UNICODE('u'), |
| 116 | UNICODE('s'), UNICODE('b'), UNICODE('B'), UNICODE('o'), UNICODE('o'), |
| 117 | UNICODE('t'), UNICODE('l'), UNICODE('o'), UNICODE('d'), UNICODE('e'), |
| 118 | UNICODE('r') |
| 119 | }; |
| 120 | |
| 121 | __align(4) const dwc_string_descriptor_t tIfc0Name= |
| 122 | { |
| 123 | STRING_DESCRIPTOR_SIZE(9), |
| 124 | STRING_DESCRIPTOR, |
| 125 | UNICODE('B'), UNICODE('o'), UNICODE('o'), UNICODE('t'), UNICODE('l'), |
| 126 | UNICODE('o'), UNICODE('d'), UNICODE('e'), UNICODE('r') |
| 127 | }; |
| 128 | |
| 129 | __align(4) const dwc_string_descriptor_t tIfc1Name= |
| 130 | { |
| 131 | STRING_DESCRIPTOR_SIZE(6), |
| 132 | STRING_DESCRIPTOR, |
| 133 | UNICODE('S'), UNICODE('e'), UNICODE('r'), UNICODE('i'), UNICODE('a'), |
| 134 | UNICODE('l') |
| 135 | }; |
| 136 | |
| 137 | __align(4) const dwc_string_descriptor_t * const pStrDescIdx[]= |
| 138 | { |
| 139 | (dwc_string_descriptor_t *)(&tLanguage), |
| 140 | (dwc_string_descriptor_t *)&tManufacture, |
| 141 | (dwc_string_descriptor_t *)&tProduct, |
| 142 | (dwc_string_descriptor_t *)&tSN, |
| 143 | (dwc_string_descriptor_t *)&tIfc0Name, |
| 144 | (dwc_string_descriptor_t *)&tIfc1Name, |
| 145 | }; |
| 146 | |
| 147 | |
| 148 | static void do_get_descriptor(dwc_otg_pcd_t * pcd,uint32_t *buff,uint32_t len) |
| 149 | { |
| 150 | |
| 151 | dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; |
| 152 | pcd->ep0_pending = 1; |
| 153 | ep0->dwc_ep.start_xfer_buff =(uint8_t*) buff; |
| 154 | ep0->dwc_ep.xfer_buff =(uint8_t*)buff; |
| 155 | ep0->dwc_ep.xfer_len = len; |
| 156 | ep0->dwc_ep.xfer_count = 0; |
| 157 | ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len; |
| 158 | dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep); |
| 159 | |
| 160 | } |
| 161 | |
| 162 | extern void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val); |
| 163 | |
| 164 | int dwc_setup(dwc_otg_pcd_t * pcd, usb_device_request_t * ctrl) |
| 165 | { |
| 166 | uint8_t byIdx; |
| 167 | uint32_t len = 0; |
| 168 | uint16_t value; |
| 169 | byIdx = (uint8_t)(ctrl->wValue &0xff); |
| 170 | value = ctrl->wValue>>8; |
| 171 | |
| 172 | if( USB_DT_DEVICE ==value ) |
| 173 | { |
| 174 | len = MIN( sizeof(dwc_device_descriptor_t), ctrl->wLength); |
| 175 | do_get_descriptor(pcd,(uint32_t*)&device_desc,len); |
| 176 | } |
| 177 | else if( USB_DT_CONFIG==value ) |
| 178 | { |
| 179 | len = MIN( sizeof(dwc_config_all_t), ctrl->wLength); |
| 180 | do_get_descriptor(pcd,(uint32_t*)&g_config_desc,len); |
| 181 | } |
| 182 | |
| 183 | else if( USB_DT_STRING ==value) |
| 184 | { |
| 185 | len = MIN(((dwc_string_descriptor_t*)(pStrDescIdx[byIdx]))->bLength, ctrl->wLength); |
| 186 | do_get_descriptor(pcd,(uint32_t*)pStrDescIdx[byIdx],len); |
| 187 | } |
| 188 | |
| 189 | else if( USB_DT_INTERFACE == value) |
| 190 | { |
| 191 | len = MIN(((dwc_string_descriptor_t*)(pStrDescIdx[byIdx]))->bLength, ctrl->wLength); |
| 192 | do_get_descriptor(pcd,(uint32_t*)pStrDescIdx[byIdx],len); |
| 193 | } |
| 194 | else if( ENDPOINT_DESCRIPTOR == value) |
| 195 | { |
| 196 | len = MIN(((dwc_string_descriptor_t*)(pStrDescIdx[byIdx]))->bLength, ctrl->wLength); |
| 197 | do_get_descriptor(pcd,(uint32_t*)pStrDescIdx[byIdx],len); |
| 198 | } |
| 199 | else if( USB_DT_DEVICE_QUALIFIER ==value) |
| 200 | { |
| 201 | len = MIN(sizeof(dwc_dev_qual_descriptor_t),ctrl->wLength); |
| 202 | do_get_descriptor(pcd,(uint32_t*)&dev_qual_desc,len); |
| 203 | } |
| 204 | else |
| 205 | { |
| 206 | ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); |
| 207 | } |
| 208 | |
| 209 | return 0; |
| 210 | } |
| 211 | |
| 212 | |
| 213 | static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep, |
| 214 | uint32_t is_in, uint32_t ep_num) |
| 215 | { |
| 216 | /* Init EP structure */ |
| 217 | pcd_ep->desc = 0; |
| 218 | pcd_ep->pcd = pcd; |
| 219 | pcd_ep->stopped = 1; |
| 220 | pcd_ep->queue_sof = 0; |
| 221 | |
| 222 | /* Init DWC ep structure */ |
| 223 | pcd_ep->dwc_ep.is_in = is_in; |
| 224 | pcd_ep->dwc_ep.num = ep_num; |
| 225 | pcd_ep->dwc_ep.active = 0; |
| 226 | pcd_ep->dwc_ep.tx_fifo_num = 0; |
| 227 | /* Control until ep is actvated */ |
| 228 | pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_BULK; |
| 229 | pcd_ep->dwc_ep.maxpacket = 512; |
| 230 | pcd_ep->dwc_ep.maxxfer = 65536; |
| 231 | |
| 232 | pcd_ep->dwc_ep.start_xfer_buff = 0; |
| 233 | pcd_ep->dwc_ep.xfer_buff = 0; |
| 234 | pcd_ep->dwc_ep.xfer_len = 0; |
| 235 | pcd_ep->dwc_ep.xfer_count = 0; |
| 236 | pcd_ep->dwc_ep.sent_zlp = 0; |
| 237 | pcd_ep->dwc_ep.total_len = 0; |
| 238 | } |
| 239 | |
| 240 | /** |
| 241 | * Initialize ep's |
| 242 | */ |
| 243 | static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd) |
| 244 | { |
| 245 | int i; |
| 246 | uint32_t hwcfg1; |
| 247 | dwc_otg_pcd_ep_t *ep; |
| 248 | int in_ep_cntr, out_ep_cntr; |
| 249 | uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps; |
| 250 | uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps; |
| 251 | |
| 252 | /** |
| 253 | * Initialize the EP0 structure. |
| 254 | */ |
| 255 | pcd->ep0.dwc_ep.pPara = (void*)(&global.g_in_pPara[1]); |
| 256 | |
| 257 | ep = &pcd->ep0; |
| 258 | dwc_otg_pcd_init_ep(pcd, ep, 0, 0); |
| 259 | |
| 260 | in_ep_cntr = 0; |
| 261 | hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3; |
| 262 | for (i = 1; in_ep_cntr < num_in_eps; i++) |
| 263 | { |
| 264 | if ((hwcfg1 & 0x1) == 0) |
| 265 | { |
| 266 | pcd->in_ep[in_ep_cntr].dwc_ep.pPara = (void*)(&global.g_in_pPara[in_ep_cntr]); |
| 267 | ep = &pcd->in_ep[in_ep_cntr]; |
| 268 | in_ep_cntr++; |
| 269 | /** |
| 270 | * @todo NGS: Add direction to EP, based on contents |
| 271 | * of HWCFG1. Need a copy of HWCFG1 in pcd structure? |
| 272 | * sprintf(";r |
| 273 | */ |
| 274 | dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i); |
| 275 | } |
| 276 | hwcfg1 >>= 2; |
| 277 | } |
| 278 | |
| 279 | out_ep_cntr = 0; |
| 280 | hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2; |
| 281 | for (i = 1; out_ep_cntr < num_out_eps; i++) |
| 282 | { |
| 283 | if ((hwcfg1 & 0x1) == 0) |
| 284 | { |
| 285 | pcd->out_ep[out_ep_cntr].dwc_ep.pPara = (void*)(&global.g_out_pPara[out_ep_cntr]); |
| 286 | ep = &pcd->out_ep[out_ep_cntr]; |
| 287 | out_ep_cntr++; |
| 288 | /** |
| 289 | * @todo NGS: Add direction to EP, based on contents |
| 290 | * of HWCFG1. Need a copy of HWCFG1 in pcd structure? |
| 291 | * sprintf(";r |
| 292 | */ |
| 293 | dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i); |
| 294 | } |
| 295 | hwcfg1 >>= 2; |
| 296 | } |
| 297 | if(NEED_ENUM == global.g_enum) |
| 298 | { |
| 299 | pcd->ep0state = EP0_DISCONNECT; |
| 300 | } |
| 301 | else |
| 302 | { |
| 303 | pcd->ep0state = EP0_IDLE; |
| 304 | |
| 305 | } |
| 306 | pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE; |
| 307 | pcd->ep0.dwc_ep.type = 0; |
| 308 | } |
| 309 | |
| 310 | /** |
| 311 | * This function initialized the PCD portion of the driver. |
| 312 | * |
| 313 | */ |
| 314 | dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if) |
| 315 | { |
| 316 | dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)&global.g_dwc_otg_pcd_tp; |
| 317 | int i; |
| 318 | uint8_t* pt_dwc_otg_pcd_t = (uint8_t*)&global.g_dwc_otg_pcd_tp; |
| 319 | for(i = 0;i<sizeof(dwc_otg_pcd_t);i++) |
| 320 | { |
| 321 | pt_dwc_otg_pcd_t[i] = 0; |
| 322 | } |
| 323 | |
| 324 | pcd->core_if = core_if; |
| 325 | |
| 326 | pcd->setup_pkt = global.g_u_setup_pkt; |
| 327 | pcd->status_buf = &global.g_status_buf; |
| 328 | dwc_otg_pcd_reinit(pcd); |
| 329 | |
| 330 | return pcd; |
| 331 | |
| 332 | |
| 333 | } |
| 334 | |
| 335 | |
| 336 | /******************************************************************************/ |
| 337 | |
| 338 | #endif /* DWC_HOST_ONLY */ |