These are the examples provided for [[/users/frank26080115/libraries/LPC1700CMSIS_Lib/]] Note, the entire "program" is not compilable!
USBDEV/USBHID/usbcore.c@0:bf7b9fba3924, 2011-03-20 (annotated)
- Committer:
- frank26080115
- Date:
- Sun Mar 20 05:38:56 2011 +0000
- Revision:
- 0:bf7b9fba3924
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
frank26080115 | 0:bf7b9fba3924 | 1 | /*---------------------------------------------------------------------------- |
frank26080115 | 0:bf7b9fba3924 | 2 | * U S B - K e r n e l |
frank26080115 | 0:bf7b9fba3924 | 3 | *---------------------------------------------------------------------------- |
frank26080115 | 0:bf7b9fba3924 | 4 | * Name: USBCORE.C |
frank26080115 | 0:bf7b9fba3924 | 5 | * Purpose: USB Core Module |
frank26080115 | 0:bf7b9fba3924 | 6 | * Version: V1.10 |
frank26080115 | 0:bf7b9fba3924 | 7 | *---------------------------------------------------------------------------- |
frank26080115 | 0:bf7b9fba3924 | 8 | * This software is supplied "AS IS" without any warranties, express, |
frank26080115 | 0:bf7b9fba3924 | 9 | * implied or statutory, including but not limited to the implied |
frank26080115 | 0:bf7b9fba3924 | 10 | * warranties of fitness for purpose, satisfactory quality and |
frank26080115 | 0:bf7b9fba3924 | 11 | * noninfringement. Keil extends you a royalty-free right to reproduce |
frank26080115 | 0:bf7b9fba3924 | 12 | * and distribute executable files created using this software for use |
frank26080115 | 0:bf7b9fba3924 | 13 | * on NXP Semiconductors LPC family microcontroller devices only. Nothing |
frank26080115 | 0:bf7b9fba3924 | 14 | * else gives you the right to use this software. |
frank26080115 | 0:bf7b9fba3924 | 15 | * |
frank26080115 | 0:bf7b9fba3924 | 16 | * Copyright (c) 2005-2009 Keil Software. |
frank26080115 | 0:bf7b9fba3924 | 17 | *---------------------------------------------------------------------------*/ |
frank26080115 | 0:bf7b9fba3924 | 18 | |
frank26080115 | 0:bf7b9fba3924 | 19 | |
frank26080115 | 0:bf7b9fba3924 | 20 | #include "lpc_types.h" |
frank26080115 | 0:bf7b9fba3924 | 21 | |
frank26080115 | 0:bf7b9fba3924 | 22 | #include "usb.h" |
frank26080115 | 0:bf7b9fba3924 | 23 | #include "usbcfg.h" |
frank26080115 | 0:bf7b9fba3924 | 24 | #include "usbhw.h" |
frank26080115 | 0:bf7b9fba3924 | 25 | #include "usbcore.h" |
frank26080115 | 0:bf7b9fba3924 | 26 | #include "usbdesc.h" |
frank26080115 | 0:bf7b9fba3924 | 27 | #include "usbuser.h" |
frank26080115 | 0:bf7b9fba3924 | 28 | |
frank26080115 | 0:bf7b9fba3924 | 29 | #if (USB_CLASS) |
frank26080115 | 0:bf7b9fba3924 | 30 | |
frank26080115 | 0:bf7b9fba3924 | 31 | #if (USB_AUDIO) |
frank26080115 | 0:bf7b9fba3924 | 32 | #include "audio.h" |
frank26080115 | 0:bf7b9fba3924 | 33 | #include "adcuser.h" |
frank26080115 | 0:bf7b9fba3924 | 34 | #endif |
frank26080115 | 0:bf7b9fba3924 | 35 | |
frank26080115 | 0:bf7b9fba3924 | 36 | #if (USB_HID) |
frank26080115 | 0:bf7b9fba3924 | 37 | #include "hid.h" |
frank26080115 | 0:bf7b9fba3924 | 38 | #include "hiduser.h" |
frank26080115 | 0:bf7b9fba3924 | 39 | #endif |
frank26080115 | 0:bf7b9fba3924 | 40 | |
frank26080115 | 0:bf7b9fba3924 | 41 | #if (USB_MSC) |
frank26080115 | 0:bf7b9fba3924 | 42 | #include "msc.h" |
frank26080115 | 0:bf7b9fba3924 | 43 | #include "mscuser.h" |
frank26080115 | 0:bf7b9fba3924 | 44 | extern MSC_CSW CSW; |
frank26080115 | 0:bf7b9fba3924 | 45 | #endif |
frank26080115 | 0:bf7b9fba3924 | 46 | |
frank26080115 | 0:bf7b9fba3924 | 47 | #if (USB_CDC) |
frank26080115 | 0:bf7b9fba3924 | 48 | #include "cdc.h" |
frank26080115 | 0:bf7b9fba3924 | 49 | #include "cdcuser.h" |
frank26080115 | 0:bf7b9fba3924 | 50 | #endif |
frank26080115 | 0:bf7b9fba3924 | 51 | |
frank26080115 | 0:bf7b9fba3924 | 52 | #endif |
frank26080115 | 0:bf7b9fba3924 | 53 | |
frank26080115 | 0:bf7b9fba3924 | 54 | #if (USB_VENDOR) |
frank26080115 | 0:bf7b9fba3924 | 55 | #include "vendor.h" |
frank26080115 | 0:bf7b9fba3924 | 56 | #endif |
frank26080115 | 0:bf7b9fba3924 | 57 | |
frank26080115 | 0:bf7b9fba3924 | 58 | #ifndef __IAR_SYSTEMS_ICC__ |
frank26080115 | 0:bf7b9fba3924 | 59 | #pragma diag_suppress 111,1441 |
frank26080115 | 0:bf7b9fba3924 | 60 | #endif |
frank26080115 | 0:bf7b9fba3924 | 61 | |
frank26080115 | 0:bf7b9fba3924 | 62 | uint16_t USB_DeviceStatus; |
frank26080115 | 0:bf7b9fba3924 | 63 | uint8_t USB_DeviceAddress; |
frank26080115 | 0:bf7b9fba3924 | 64 | uint8_t USB_Configuration; |
frank26080115 | 0:bf7b9fba3924 | 65 | uint32_t USB_EndPointMask; |
frank26080115 | 0:bf7b9fba3924 | 66 | uint32_t USB_EndPointHalt; |
frank26080115 | 0:bf7b9fba3924 | 67 | uint8_t USB_NumInterfaces; |
frank26080115 | 0:bf7b9fba3924 | 68 | uint8_t USB_AltSetting[USB_IF_NUM]; |
frank26080115 | 0:bf7b9fba3924 | 69 | |
frank26080115 | 0:bf7b9fba3924 | 70 | uint8_t EP0Buf[USB_MAX_PACKET0]; |
frank26080115 | 0:bf7b9fba3924 | 71 | |
frank26080115 | 0:bf7b9fba3924 | 72 | |
frank26080115 | 0:bf7b9fba3924 | 73 | USB_EP_DATA EP0Data; |
frank26080115 | 0:bf7b9fba3924 | 74 | |
frank26080115 | 0:bf7b9fba3924 | 75 | USB_SETUP_PACKET SetupPacket; |
frank26080115 | 0:bf7b9fba3924 | 76 | |
frank26080115 | 0:bf7b9fba3924 | 77 | |
frank26080115 | 0:bf7b9fba3924 | 78 | /* |
frank26080115 | 0:bf7b9fba3924 | 79 | * Reset USB Core |
frank26080115 | 0:bf7b9fba3924 | 80 | * Parameters: None |
frank26080115 | 0:bf7b9fba3924 | 81 | * Return Value: None |
frank26080115 | 0:bf7b9fba3924 | 82 | */ |
frank26080115 | 0:bf7b9fba3924 | 83 | |
frank26080115 | 0:bf7b9fba3924 | 84 | void USB_ResetCore (void) { |
frank26080115 | 0:bf7b9fba3924 | 85 | |
frank26080115 | 0:bf7b9fba3924 | 86 | USB_DeviceStatus = USB_POWER; |
frank26080115 | 0:bf7b9fba3924 | 87 | USB_DeviceAddress = 0; |
frank26080115 | 0:bf7b9fba3924 | 88 | USB_Configuration = 0; |
frank26080115 | 0:bf7b9fba3924 | 89 | USB_EndPointMask = 0x00010001; |
frank26080115 | 0:bf7b9fba3924 | 90 | USB_EndPointHalt = 0x00000000; |
frank26080115 | 0:bf7b9fba3924 | 91 | } |
frank26080115 | 0:bf7b9fba3924 | 92 | |
frank26080115 | 0:bf7b9fba3924 | 93 | |
frank26080115 | 0:bf7b9fba3924 | 94 | /* |
frank26080115 | 0:bf7b9fba3924 | 95 | * USB Request - Setup Stage |
frank26080115 | 0:bf7b9fba3924 | 96 | * Parameters: None (global SetupPacket) |
frank26080115 | 0:bf7b9fba3924 | 97 | * Return Value: None |
frank26080115 | 0:bf7b9fba3924 | 98 | */ |
frank26080115 | 0:bf7b9fba3924 | 99 | |
frank26080115 | 0:bf7b9fba3924 | 100 | void USB_SetupStage (void) { |
frank26080115 | 0:bf7b9fba3924 | 101 | USB_ReadEP(0x00, (uint8_t *)&SetupPacket); |
frank26080115 | 0:bf7b9fba3924 | 102 | } |
frank26080115 | 0:bf7b9fba3924 | 103 | |
frank26080115 | 0:bf7b9fba3924 | 104 | |
frank26080115 | 0:bf7b9fba3924 | 105 | /* |
frank26080115 | 0:bf7b9fba3924 | 106 | * USB Request - Data In Stage |
frank26080115 | 0:bf7b9fba3924 | 107 | * Parameters: None (global EP0Data) |
frank26080115 | 0:bf7b9fba3924 | 108 | * Return Value: None |
frank26080115 | 0:bf7b9fba3924 | 109 | */ |
frank26080115 | 0:bf7b9fba3924 | 110 | |
frank26080115 | 0:bf7b9fba3924 | 111 | void USB_DataInStage (void) { |
frank26080115 | 0:bf7b9fba3924 | 112 | uint32_t cnt; |
frank26080115 | 0:bf7b9fba3924 | 113 | |
frank26080115 | 0:bf7b9fba3924 | 114 | if (EP0Data.Count > USB_MAX_PACKET0) { |
frank26080115 | 0:bf7b9fba3924 | 115 | cnt = USB_MAX_PACKET0; |
frank26080115 | 0:bf7b9fba3924 | 116 | } else { |
frank26080115 | 0:bf7b9fba3924 | 117 | cnt = EP0Data.Count; |
frank26080115 | 0:bf7b9fba3924 | 118 | } |
frank26080115 | 0:bf7b9fba3924 | 119 | cnt = USB_WriteEP(0x80, EP0Data.pData, cnt); |
frank26080115 | 0:bf7b9fba3924 | 120 | EP0Data.pData += cnt; |
frank26080115 | 0:bf7b9fba3924 | 121 | EP0Data.Count -= cnt; |
frank26080115 | 0:bf7b9fba3924 | 122 | } |
frank26080115 | 0:bf7b9fba3924 | 123 | |
frank26080115 | 0:bf7b9fba3924 | 124 | |
frank26080115 | 0:bf7b9fba3924 | 125 | /* |
frank26080115 | 0:bf7b9fba3924 | 126 | * USB Request - Data Out Stage |
frank26080115 | 0:bf7b9fba3924 | 127 | * Parameters: None (global EP0Data) |
frank26080115 | 0:bf7b9fba3924 | 128 | * Return Value: None |
frank26080115 | 0:bf7b9fba3924 | 129 | */ |
frank26080115 | 0:bf7b9fba3924 | 130 | |
frank26080115 | 0:bf7b9fba3924 | 131 | void USB_DataOutStage (void) { |
frank26080115 | 0:bf7b9fba3924 | 132 | uint32_t cnt; |
frank26080115 | 0:bf7b9fba3924 | 133 | |
frank26080115 | 0:bf7b9fba3924 | 134 | cnt = USB_ReadEP(0x00, EP0Data.pData); |
frank26080115 | 0:bf7b9fba3924 | 135 | EP0Data.pData += cnt; |
frank26080115 | 0:bf7b9fba3924 | 136 | EP0Data.Count -= cnt; |
frank26080115 | 0:bf7b9fba3924 | 137 | } |
frank26080115 | 0:bf7b9fba3924 | 138 | |
frank26080115 | 0:bf7b9fba3924 | 139 | |
frank26080115 | 0:bf7b9fba3924 | 140 | /* |
frank26080115 | 0:bf7b9fba3924 | 141 | * USB Request - Status In Stage |
frank26080115 | 0:bf7b9fba3924 | 142 | * Parameters: None |
frank26080115 | 0:bf7b9fba3924 | 143 | * Return Value: None |
frank26080115 | 0:bf7b9fba3924 | 144 | */ |
frank26080115 | 0:bf7b9fba3924 | 145 | |
frank26080115 | 0:bf7b9fba3924 | 146 | void USB_StatusInStage (void) { |
frank26080115 | 0:bf7b9fba3924 | 147 | USB_WriteEP(0x80, NULL, 0); |
frank26080115 | 0:bf7b9fba3924 | 148 | } |
frank26080115 | 0:bf7b9fba3924 | 149 | |
frank26080115 | 0:bf7b9fba3924 | 150 | |
frank26080115 | 0:bf7b9fba3924 | 151 | /* |
frank26080115 | 0:bf7b9fba3924 | 152 | * USB Request - Status Out Stage |
frank26080115 | 0:bf7b9fba3924 | 153 | * Parameters: None |
frank26080115 | 0:bf7b9fba3924 | 154 | * Return Value: None |
frank26080115 | 0:bf7b9fba3924 | 155 | */ |
frank26080115 | 0:bf7b9fba3924 | 156 | |
frank26080115 | 0:bf7b9fba3924 | 157 | void USB_StatusOutStage (void) { |
frank26080115 | 0:bf7b9fba3924 | 158 | USB_ReadEP(0x00, EP0Buf); |
frank26080115 | 0:bf7b9fba3924 | 159 | } |
frank26080115 | 0:bf7b9fba3924 | 160 | |
frank26080115 | 0:bf7b9fba3924 | 161 | |
frank26080115 | 0:bf7b9fba3924 | 162 | /* |
frank26080115 | 0:bf7b9fba3924 | 163 | * Get Descriptor USB Request |
frank26080115 | 0:bf7b9fba3924 | 164 | * Parameters: None (global SetupPacket) |
frank26080115 | 0:bf7b9fba3924 | 165 | * Return Value: TRUE - Success, FALSE - Error |
frank26080115 | 0:bf7b9fba3924 | 166 | */ |
frank26080115 | 0:bf7b9fba3924 | 167 | |
frank26080115 | 0:bf7b9fba3924 | 168 | #ifdef __IAR_SYSTEMS_ICC__ |
frank26080115 | 0:bf7b9fba3924 | 169 | inline uint32_t USB_GetDescriptor (void) { |
frank26080115 | 0:bf7b9fba3924 | 170 | #else |
frank26080115 | 0:bf7b9fba3924 | 171 | __inline uint32_t USB_GetDescriptor (void) { |
frank26080115 | 0:bf7b9fba3924 | 172 | #endif |
frank26080115 | 0:bf7b9fba3924 | 173 | uint8_t *pD; |
frank26080115 | 0:bf7b9fba3924 | 174 | uint32_t len, n; |
frank26080115 | 0:bf7b9fba3924 | 175 | |
frank26080115 | 0:bf7b9fba3924 | 176 | switch (SetupPacket.bmRequestType.BM.Recipient) |
frank26080115 | 0:bf7b9fba3924 | 177 | { |
frank26080115 | 0:bf7b9fba3924 | 178 | case REQUEST_TO_DEVICE: |
frank26080115 | 0:bf7b9fba3924 | 179 | switch (SetupPacket.wValue.WB.H) |
frank26080115 | 0:bf7b9fba3924 | 180 | { |
frank26080115 | 0:bf7b9fba3924 | 181 | case USB_DEVICE_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 182 | EP0Data.pData = (uint8_t *)USB_DeviceDescriptor; |
frank26080115 | 0:bf7b9fba3924 | 183 | len = USB_DEVICE_DESC_SIZE; |
frank26080115 | 0:bf7b9fba3924 | 184 | break; |
frank26080115 | 0:bf7b9fba3924 | 185 | case USB_CONFIGURATION_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 186 | pD = (uint8_t *)USB_ConfigDescriptor; |
frank26080115 | 0:bf7b9fba3924 | 187 | for (n = 0; n != SetupPacket.wValue.WB.L; n++) |
frank26080115 | 0:bf7b9fba3924 | 188 | { |
frank26080115 | 0:bf7b9fba3924 | 189 | if (((USB_CONFIGURATION_DESCRIPTOR *)pD)->bLength != 0) |
frank26080115 | 0:bf7b9fba3924 | 190 | { |
frank26080115 | 0:bf7b9fba3924 | 191 | pD += ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength; |
frank26080115 | 0:bf7b9fba3924 | 192 | } |
frank26080115 | 0:bf7b9fba3924 | 193 | } |
frank26080115 | 0:bf7b9fba3924 | 194 | if (((USB_CONFIGURATION_DESCRIPTOR *)pD)->bLength == 0) |
frank26080115 | 0:bf7b9fba3924 | 195 | { |
frank26080115 | 0:bf7b9fba3924 | 196 | return (FALSE); |
frank26080115 | 0:bf7b9fba3924 | 197 | } |
frank26080115 | 0:bf7b9fba3924 | 198 | EP0Data.pData = pD; |
frank26080115 | 0:bf7b9fba3924 | 199 | len = ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength; |
frank26080115 | 0:bf7b9fba3924 | 200 | break; |
frank26080115 | 0:bf7b9fba3924 | 201 | case USB_STRING_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 202 | EP0Data.pData = (uint8_t *)USB_StringDescriptor + SetupPacket.wValue.WB.L; |
frank26080115 | 0:bf7b9fba3924 | 203 | len = ((USB_STRING_DESCRIPTOR *)EP0Data.pData)->bLength; |
frank26080115 | 0:bf7b9fba3924 | 204 | break; |
frank26080115 | 0:bf7b9fba3924 | 205 | default: |
frank26080115 | 0:bf7b9fba3924 | 206 | return (FALSE); |
frank26080115 | 0:bf7b9fba3924 | 207 | } |
frank26080115 | 0:bf7b9fba3924 | 208 | break; |
frank26080115 | 0:bf7b9fba3924 | 209 | case REQUEST_TO_INTERFACE: |
frank26080115 | 0:bf7b9fba3924 | 210 | switch (SetupPacket.wValue.WB.H) |
frank26080115 | 0:bf7b9fba3924 | 211 | { |
frank26080115 | 0:bf7b9fba3924 | 212 | #if USB_HID |
frank26080115 | 0:bf7b9fba3924 | 213 | case HID_HID_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 214 | if (SetupPacket.wIndex.WB.L != USB_HID_IF_NUM) |
frank26080115 | 0:bf7b9fba3924 | 215 | { |
frank26080115 | 0:bf7b9fba3924 | 216 | return (FALSE); /* Only Single HID Interface is supported */ |
frank26080115 | 0:bf7b9fba3924 | 217 | } |
frank26080115 | 0:bf7b9fba3924 | 218 | EP0Data.pData = (uint8_t *)USB_ConfigDescriptor + HID_DESC_OFFSET; |
frank26080115 | 0:bf7b9fba3924 | 219 | len = HID_DESC_SIZE; |
frank26080115 | 0:bf7b9fba3924 | 220 | break; |
frank26080115 | 0:bf7b9fba3924 | 221 | case HID_REPORT_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 222 | if (SetupPacket.wIndex.WB.L != USB_HID_IF_NUM) |
frank26080115 | 0:bf7b9fba3924 | 223 | { |
frank26080115 | 0:bf7b9fba3924 | 224 | return (FALSE); /* Only Single HID Interface is supported */ |
frank26080115 | 0:bf7b9fba3924 | 225 | } |
frank26080115 | 0:bf7b9fba3924 | 226 | EP0Data.pData = (uint8_t *)HID_ReportDescriptor; |
frank26080115 | 0:bf7b9fba3924 | 227 | len = HID_ReportDescSize; |
frank26080115 | 0:bf7b9fba3924 | 228 | break; |
frank26080115 | 0:bf7b9fba3924 | 229 | case HID_PHYSICAL_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 230 | return (FALSE); /* HID Physical Descriptor is not supported */ |
frank26080115 | 0:bf7b9fba3924 | 231 | #endif |
frank26080115 | 0:bf7b9fba3924 | 232 | default: |
frank26080115 | 0:bf7b9fba3924 | 233 | return (FALSE); |
frank26080115 | 0:bf7b9fba3924 | 234 | } |
frank26080115 | 0:bf7b9fba3924 | 235 | break; |
frank26080115 | 0:bf7b9fba3924 | 236 | default: |
frank26080115 | 0:bf7b9fba3924 | 237 | return (FALSE); |
frank26080115 | 0:bf7b9fba3924 | 238 | } |
frank26080115 | 0:bf7b9fba3924 | 239 | |
frank26080115 | 0:bf7b9fba3924 | 240 | if (EP0Data.Count > len) |
frank26080115 | 0:bf7b9fba3924 | 241 | { |
frank26080115 | 0:bf7b9fba3924 | 242 | EP0Data.Count = len; |
frank26080115 | 0:bf7b9fba3924 | 243 | } |
frank26080115 | 0:bf7b9fba3924 | 244 | USB_DataInStage(); |
frank26080115 | 0:bf7b9fba3924 | 245 | |
frank26080115 | 0:bf7b9fba3924 | 246 | return (TRUE); |
frank26080115 | 0:bf7b9fba3924 | 247 | } |
frank26080115 | 0:bf7b9fba3924 | 248 | |
frank26080115 | 0:bf7b9fba3924 | 249 | |
frank26080115 | 0:bf7b9fba3924 | 250 | /* |
frank26080115 | 0:bf7b9fba3924 | 251 | * Set Configuration USB Request |
frank26080115 | 0:bf7b9fba3924 | 252 | * Parameters: None (global SetupPacket) |
frank26080115 | 0:bf7b9fba3924 | 253 | * Return Value: TRUE - Success, FALSE - Error |
frank26080115 | 0:bf7b9fba3924 | 254 | */ |
frank26080115 | 0:bf7b9fba3924 | 255 | |
frank26080115 | 0:bf7b9fba3924 | 256 | #ifdef __IAR_SYSTEMS_ICC__ |
frank26080115 | 0:bf7b9fba3924 | 257 | inline uint32_t USB_SetConfiguration (void) { |
frank26080115 | 0:bf7b9fba3924 | 258 | #else |
frank26080115 | 0:bf7b9fba3924 | 259 | __inline uint32_t USB_SetConfiguration (void) { |
frank26080115 | 0:bf7b9fba3924 | 260 | #endif |
frank26080115 | 0:bf7b9fba3924 | 261 | USB_COMMON_DESCRIPTOR *pD; |
frank26080115 | 0:bf7b9fba3924 | 262 | uint32_t alt, n; |
frank26080115 | 0:bf7b9fba3924 | 263 | uint32_t tmp; |
frank26080115 | 0:bf7b9fba3924 | 264 | |
frank26080115 | 0:bf7b9fba3924 | 265 | if (SetupPacket.wValue.WB.L) |
frank26080115 | 0:bf7b9fba3924 | 266 | { |
frank26080115 | 0:bf7b9fba3924 | 267 | pD = (USB_COMMON_DESCRIPTOR *)USB_ConfigDescriptor; |
frank26080115 | 0:bf7b9fba3924 | 268 | while (pD->bLength) |
frank26080115 | 0:bf7b9fba3924 | 269 | { |
frank26080115 | 0:bf7b9fba3924 | 270 | switch (pD->bDescriptorType) |
frank26080115 | 0:bf7b9fba3924 | 271 | { |
frank26080115 | 0:bf7b9fba3924 | 272 | case USB_CONFIGURATION_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 273 | if (((USB_CONFIGURATION_DESCRIPTOR *)pD)->bConfigurationValue == SetupPacket.wValue.WB.L) |
frank26080115 | 0:bf7b9fba3924 | 274 | { |
frank26080115 | 0:bf7b9fba3924 | 275 | USB_Configuration = SetupPacket.wValue.WB.L; |
frank26080115 | 0:bf7b9fba3924 | 276 | USB_Configure(TRUE); |
frank26080115 | 0:bf7b9fba3924 | 277 | /* if (((USB_CONFIGURATION_DESCRIPTOR *)pD)->bmAttributes & USB_CONFIG_SELF_POWERED) |
frank26080115 | 0:bf7b9fba3924 | 278 | { |
frank26080115 | 0:bf7b9fba3924 | 279 | USB_DeviceStatus |= USB_GETSTATUS_SELF_POWERED; |
frank26080115 | 0:bf7b9fba3924 | 280 | } |
frank26080115 | 0:bf7b9fba3924 | 281 | else |
frank26080115 | 0:bf7b9fba3924 | 282 | { |
frank26080115 | 0:bf7b9fba3924 | 283 | USB_DeviceStatus &= ~USB_GETSTATUS_SELF_POWERED; |
frank26080115 | 0:bf7b9fba3924 | 284 | } */ |
frank26080115 | 0:bf7b9fba3924 | 285 | } |
frank26080115 | 0:bf7b9fba3924 | 286 | else |
frank26080115 | 0:bf7b9fba3924 | 287 | { |
frank26080115 | 0:bf7b9fba3924 | 288 | // (uint8_t *)pD += ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength; |
frank26080115 | 0:bf7b9fba3924 | 289 | tmp = (uint32_t)pD; |
frank26080115 | 0:bf7b9fba3924 | 290 | tmp += ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength; |
frank26080115 | 0:bf7b9fba3924 | 291 | pD = (USB_COMMON_DESCRIPTOR *)tmp; |
frank26080115 | 0:bf7b9fba3924 | 292 | continue; |
frank26080115 | 0:bf7b9fba3924 | 293 | } |
frank26080115 | 0:bf7b9fba3924 | 294 | break; |
frank26080115 | 0:bf7b9fba3924 | 295 | case USB_INTERFACE_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 296 | alt = ((USB_INTERFACE_DESCRIPTOR *)pD)->bAlternateSetting; |
frank26080115 | 0:bf7b9fba3924 | 297 | break; |
frank26080115 | 0:bf7b9fba3924 | 298 | case USB_ENDPOINT_DESCRIPTOR_TYPE: |
frank26080115 | 0:bf7b9fba3924 | 299 | if (alt == 0) |
frank26080115 | 0:bf7b9fba3924 | 300 | { |
frank26080115 | 0:bf7b9fba3924 | 301 | n = ((USB_ENDPOINT_DESCRIPTOR *)pD)->bEndpointAddress & 0x8F; |
frank26080115 | 0:bf7b9fba3924 | 302 | USB_ConfigEP((USB_ENDPOINT_DESCRIPTOR *)pD); |
frank26080115 | 0:bf7b9fba3924 | 303 | USB_EnableEP(n); |
frank26080115 | 0:bf7b9fba3924 | 304 | USB_ResetEP(n); |
frank26080115 | 0:bf7b9fba3924 | 305 | } |
frank26080115 | 0:bf7b9fba3924 | 306 | break; |
frank26080115 | 0:bf7b9fba3924 | 307 | } |
frank26080115 | 0:bf7b9fba3924 | 308 | // (uint8_t *)pD += pD->bLength; |
frank26080115 | 0:bf7b9fba3924 | 309 | tmp = (uint32_t)pD; |
frank26080115 | 0:bf7b9fba3924 | 310 | tmp += pD->bLength; |
frank26080115 | 0:bf7b9fba3924 | 311 | pD = (USB_COMMON_DESCRIPTOR *)tmp; |
frank26080115 | 0:bf7b9fba3924 | 312 | } |
frank26080115 | 0:bf7b9fba3924 | 313 | } |
frank26080115 | 0:bf7b9fba3924 | 314 | else |
frank26080115 | 0:bf7b9fba3924 | 315 | { |
frank26080115 | 0:bf7b9fba3924 | 316 | USB_Configuration = 0; |
frank26080115 | 0:bf7b9fba3924 | 317 | USB_Configure(FALSE); |
frank26080115 | 0:bf7b9fba3924 | 318 | } |
frank26080115 | 0:bf7b9fba3924 | 319 | |
frank26080115 | 0:bf7b9fba3924 | 320 | if (USB_Configuration == SetupPacket.wValue.WB.L) |
frank26080115 | 0:bf7b9fba3924 | 321 | { |
frank26080115 | 0:bf7b9fba3924 | 322 | return (TRUE); |
frank26080115 | 0:bf7b9fba3924 | 323 | } |
frank26080115 | 0:bf7b9fba3924 | 324 | else |
frank26080115 | 0:bf7b9fba3924 | 325 | { |
frank26080115 | 0:bf7b9fba3924 | 326 | return (FALSE); |
frank26080115 | 0:bf7b9fba3924 | 327 | } |
frank26080115 | 0:bf7b9fba3924 | 328 | } |
frank26080115 | 0:bf7b9fba3924 | 329 | |
frank26080115 | 0:bf7b9fba3924 | 330 | /* |
frank26080115 | 0:bf7b9fba3924 | 331 | * USB Endpoint 0 Event Callback |
frank26080115 | 0:bf7b9fba3924 | 332 | * Parameter: event |
frank26080115 | 0:bf7b9fba3924 | 333 | */ |
frank26080115 | 0:bf7b9fba3924 | 334 | |
frank26080115 | 0:bf7b9fba3924 | 335 | void USB_EndPoint0 (uint32_t event) |
frank26080115 | 0:bf7b9fba3924 | 336 | { |
frank26080115 | 0:bf7b9fba3924 | 337 | switch (event) |
frank26080115 | 0:bf7b9fba3924 | 338 | { |
frank26080115 | 0:bf7b9fba3924 | 339 | case USB_EVT_SETUP: |
frank26080115 | 0:bf7b9fba3924 | 340 | USB_SetupStage(); |
frank26080115 | 0:bf7b9fba3924 | 341 | EP0Data.Count = SetupPacket.wLength; |
frank26080115 | 0:bf7b9fba3924 | 342 | switch (SetupPacket.bmRequestType.BM.Type) |
frank26080115 | 0:bf7b9fba3924 | 343 | { |
frank26080115 | 0:bf7b9fba3924 | 344 | case REQUEST_STANDARD: |
frank26080115 | 0:bf7b9fba3924 | 345 | switch (SetupPacket.bRequest) |
frank26080115 | 0:bf7b9fba3924 | 346 | { |
frank26080115 | 0:bf7b9fba3924 | 347 | case USB_REQUEST_SET_ADDRESS: |
frank26080115 | 0:bf7b9fba3924 | 348 | switch (SetupPacket.bmRequestType.BM.Recipient) |
frank26080115 | 0:bf7b9fba3924 | 349 | { |
frank26080115 | 0:bf7b9fba3924 | 350 | case REQUEST_TO_DEVICE: |
frank26080115 | 0:bf7b9fba3924 | 351 | USB_DeviceAddress = SetupPacket.wValue.WB.L;//0x80 | SetupPacket.wValue.WB.L; |
frank26080115 | 0:bf7b9fba3924 | 352 | USB_StatusInStage(); |
frank26080115 | 0:bf7b9fba3924 | 353 | USB_SetAddress(USB_DeviceAddress); |
frank26080115 | 0:bf7b9fba3924 | 354 | break; |
frank26080115 | 0:bf7b9fba3924 | 355 | default: |
frank26080115 | 0:bf7b9fba3924 | 356 | break; |
frank26080115 | 0:bf7b9fba3924 | 357 | } |
frank26080115 | 0:bf7b9fba3924 | 358 | break; |
frank26080115 | 0:bf7b9fba3924 | 359 | |
frank26080115 | 0:bf7b9fba3924 | 360 | case USB_REQUEST_GET_DESCRIPTOR: |
frank26080115 | 0:bf7b9fba3924 | 361 | USB_GetDescriptor(); |
frank26080115 | 0:bf7b9fba3924 | 362 | break; |
frank26080115 | 0:bf7b9fba3924 | 363 | |
frank26080115 | 0:bf7b9fba3924 | 364 | /* case USB_REQUEST_GET_CONFIGURATION: |
frank26080115 | 0:bf7b9fba3924 | 365 | switch (SetupPacket.bmRequestType.BM.Recipient) |
frank26080115 | 0:bf7b9fba3924 | 366 | { |
frank26080115 | 0:bf7b9fba3924 | 367 | case REQUEST_TO_DEVICE: |
frank26080115 | 0:bf7b9fba3924 | 368 | EP0Data.pData = &USB_Configuration; |
frank26080115 | 0:bf7b9fba3924 | 369 | USB_DataInStage(); |
frank26080115 | 0:bf7b9fba3924 | 370 | break; |
frank26080115 | 0:bf7b9fba3924 | 371 | default: |
frank26080115 | 0:bf7b9fba3924 | 372 | break; |
frank26080115 | 0:bf7b9fba3924 | 373 | } |
frank26080115 | 0:bf7b9fba3924 | 374 | break; */ |
frank26080115 | 0:bf7b9fba3924 | 375 | |
frank26080115 | 0:bf7b9fba3924 | 376 | case USB_REQUEST_SET_CONFIGURATION: |
frank26080115 | 0:bf7b9fba3924 | 377 | switch (SetupPacket.bmRequestType.BM.Recipient) |
frank26080115 | 0:bf7b9fba3924 | 378 | { |
frank26080115 | 0:bf7b9fba3924 | 379 | case REQUEST_TO_DEVICE: |
frank26080115 | 0:bf7b9fba3924 | 380 | if (!USB_SetConfiguration()) |
frank26080115 | 0:bf7b9fba3924 | 381 | { |
frank26080115 | 0:bf7b9fba3924 | 382 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 383 | EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 384 | break; |
frank26080115 | 0:bf7b9fba3924 | 385 | } |
frank26080115 | 0:bf7b9fba3924 | 386 | USB_StatusInStage(); |
frank26080115 | 0:bf7b9fba3924 | 387 | #if USB_CONFIGURE_EVENT |
frank26080115 | 0:bf7b9fba3924 | 388 | USB_Configure_Event(); |
frank26080115 | 0:bf7b9fba3924 | 389 | #endif |
frank26080115 | 0:bf7b9fba3924 | 390 | break; |
frank26080115 | 0:bf7b9fba3924 | 391 | default: |
frank26080115 | 0:bf7b9fba3924 | 392 | break; |
frank26080115 | 0:bf7b9fba3924 | 393 | } |
frank26080115 | 0:bf7b9fba3924 | 394 | break; |
frank26080115 | 0:bf7b9fba3924 | 395 | |
frank26080115 | 0:bf7b9fba3924 | 396 | default: |
frank26080115 | 0:bf7b9fba3924 | 397 | break; |
frank26080115 | 0:bf7b9fba3924 | 398 | |
frank26080115 | 0:bf7b9fba3924 | 399 | } |
frank26080115 | 0:bf7b9fba3924 | 400 | break; |
frank26080115 | 0:bf7b9fba3924 | 401 | |
frank26080115 | 0:bf7b9fba3924 | 402 | case REQUEST_CLASS: |
frank26080115 | 0:bf7b9fba3924 | 403 | #if USB_CLASS |
frank26080115 | 0:bf7b9fba3924 | 404 | switch (SetupPacket.bmRequestType.BM.Recipient) |
frank26080115 | 0:bf7b9fba3924 | 405 | { |
frank26080115 | 0:bf7b9fba3924 | 406 | case REQUEST_TO_INTERFACE: |
frank26080115 | 0:bf7b9fba3924 | 407 | #if USB_HID |
frank26080115 | 0:bf7b9fba3924 | 408 | if (SetupPacket.wIndex.WB.L == USB_HID_IF_NUM) |
frank26080115 | 0:bf7b9fba3924 | 409 | { |
frank26080115 | 0:bf7b9fba3924 | 410 | switch (SetupPacket.bRequest) |
frank26080115 | 0:bf7b9fba3924 | 411 | { |
frank26080115 | 0:bf7b9fba3924 | 412 | case HID_REQUEST_GET_REPORT: |
frank26080115 | 0:bf7b9fba3924 | 413 | if (HID_GetReport()) |
frank26080115 | 0:bf7b9fba3924 | 414 | { |
frank26080115 | 0:bf7b9fba3924 | 415 | EP0Data.pData = EP0Buf; |
frank26080115 | 0:bf7b9fba3924 | 416 | USB_DataInStage(); |
frank26080115 | 0:bf7b9fba3924 | 417 | } |
frank26080115 | 0:bf7b9fba3924 | 418 | break; |
frank26080115 | 0:bf7b9fba3924 | 419 | case HID_REQUEST_SET_REPORT: |
frank26080115 | 0:bf7b9fba3924 | 420 | EP0Data.pData = EP0Buf; |
frank26080115 | 0:bf7b9fba3924 | 421 | break; |
frank26080115 | 0:bf7b9fba3924 | 422 | case HID_REQUEST_GET_IDLE: |
frank26080115 | 0:bf7b9fba3924 | 423 | if (HID_GetIdle()) |
frank26080115 | 0:bf7b9fba3924 | 424 | { |
frank26080115 | 0:bf7b9fba3924 | 425 | EP0Data.pData = EP0Buf; |
frank26080115 | 0:bf7b9fba3924 | 426 | USB_DataInStage(); |
frank26080115 | 0:bf7b9fba3924 | 427 | } |
frank26080115 | 0:bf7b9fba3924 | 428 | break; |
frank26080115 | 0:bf7b9fba3924 | 429 | case HID_REQUEST_SET_IDLE: |
frank26080115 | 0:bf7b9fba3924 | 430 | if (HID_SetIdle()) |
frank26080115 | 0:bf7b9fba3924 | 431 | { |
frank26080115 | 0:bf7b9fba3924 | 432 | USB_StatusInStage(); |
frank26080115 | 0:bf7b9fba3924 | 433 | } |
frank26080115 | 0:bf7b9fba3924 | 434 | break; |
frank26080115 | 0:bf7b9fba3924 | 435 | case HID_REQUEST_GET_PROTOCOL: |
frank26080115 | 0:bf7b9fba3924 | 436 | if (HID_GetProtocol()) |
frank26080115 | 0:bf7b9fba3924 | 437 | { |
frank26080115 | 0:bf7b9fba3924 | 438 | EP0Data.pData = EP0Buf; |
frank26080115 | 0:bf7b9fba3924 | 439 | USB_DataInStage(); |
frank26080115 | 0:bf7b9fba3924 | 440 | } |
frank26080115 | 0:bf7b9fba3924 | 441 | break; |
frank26080115 | 0:bf7b9fba3924 | 442 | case HID_REQUEST_SET_PROTOCOL: |
frank26080115 | 0:bf7b9fba3924 | 443 | if (HID_SetProtocol()) |
frank26080115 | 0:bf7b9fba3924 | 444 | { |
frank26080115 | 0:bf7b9fba3924 | 445 | USB_StatusInStage(); |
frank26080115 | 0:bf7b9fba3924 | 446 | } |
frank26080115 | 0:bf7b9fba3924 | 447 | break; |
frank26080115 | 0:bf7b9fba3924 | 448 | default: |
frank26080115 | 0:bf7b9fba3924 | 449 | break; |
frank26080115 | 0:bf7b9fba3924 | 450 | } |
frank26080115 | 0:bf7b9fba3924 | 451 | } |
frank26080115 | 0:bf7b9fba3924 | 452 | #endif /* USB_HID */ |
frank26080115 | 0:bf7b9fba3924 | 453 | default: |
frank26080115 | 0:bf7b9fba3924 | 454 | break; |
frank26080115 | 0:bf7b9fba3924 | 455 | } |
frank26080115 | 0:bf7b9fba3924 | 456 | break; |
frank26080115 | 0:bf7b9fba3924 | 457 | #else |
frank26080115 | 0:bf7b9fba3924 | 458 | #endif /* USB_CLASS */ |
frank26080115 | 0:bf7b9fba3924 | 459 | |
frank26080115 | 0:bf7b9fba3924 | 460 | case REQUEST_VENDOR: |
frank26080115 | 0:bf7b9fba3924 | 461 | break; |
frank26080115 | 0:bf7b9fba3924 | 462 | |
frank26080115 | 0:bf7b9fba3924 | 463 | default: |
frank26080115 | 0:bf7b9fba3924 | 464 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 465 | EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 466 | break; |
frank26080115 | 0:bf7b9fba3924 | 467 | } |
frank26080115 | 0:bf7b9fba3924 | 468 | break; |
frank26080115 | 0:bf7b9fba3924 | 469 | |
frank26080115 | 0:bf7b9fba3924 | 470 | case USB_EVT_OUT: |
frank26080115 | 0:bf7b9fba3924 | 471 | if (SetupPacket.bmRequestType.BM.Dir == 0) |
frank26080115 | 0:bf7b9fba3924 | 472 | { |
frank26080115 | 0:bf7b9fba3924 | 473 | if (EP0Data.Count) |
frank26080115 | 0:bf7b9fba3924 | 474 | { |
frank26080115 | 0:bf7b9fba3924 | 475 | USB_DataOutStage(); |
frank26080115 | 0:bf7b9fba3924 | 476 | if (EP0Data.Count == 0) |
frank26080115 | 0:bf7b9fba3924 | 477 | { |
frank26080115 | 0:bf7b9fba3924 | 478 | switch (SetupPacket.bmRequestType.BM.Type) |
frank26080115 | 0:bf7b9fba3924 | 479 | { |
frank26080115 | 0:bf7b9fba3924 | 480 | case REQUEST_STANDARD: |
frank26080115 | 0:bf7b9fba3924 | 481 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 482 | //EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 483 | break; |
frank26080115 | 0:bf7b9fba3924 | 484 | #if (USB_CLASS) |
frank26080115 | 0:bf7b9fba3924 | 485 | case REQUEST_CLASS: |
frank26080115 | 0:bf7b9fba3924 | 486 | switch (SetupPacket.bmRequestType.BM.Recipient) |
frank26080115 | 0:bf7b9fba3924 | 487 | { |
frank26080115 | 0:bf7b9fba3924 | 488 | case REQUEST_TO_INTERFACE: |
frank26080115 | 0:bf7b9fba3924 | 489 | #if USB_HID |
frank26080115 | 0:bf7b9fba3924 | 490 | if (SetupPacket.wIndex.WB.L == USB_HID_IF_NUM) |
frank26080115 | 0:bf7b9fba3924 | 491 | { |
frank26080115 | 0:bf7b9fba3924 | 492 | if (!HID_SetReport()) |
frank26080115 | 0:bf7b9fba3924 | 493 | { |
frank26080115 | 0:bf7b9fba3924 | 494 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 495 | //EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 496 | //break; |
frank26080115 | 0:bf7b9fba3924 | 497 | } |
frank26080115 | 0:bf7b9fba3924 | 498 | break; |
frank26080115 | 0:bf7b9fba3924 | 499 | //HID_SetReport(); |
frank26080115 | 0:bf7b9fba3924 | 500 | } |
frank26080115 | 0:bf7b9fba3924 | 501 | #endif |
frank26080115 | 0:bf7b9fba3924 | 502 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 503 | //EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 504 | break; |
frank26080115 | 0:bf7b9fba3924 | 505 | case REQUEST_TO_ENDPOINT: |
frank26080115 | 0:bf7b9fba3924 | 506 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 507 | //EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 508 | break; |
frank26080115 | 0:bf7b9fba3924 | 509 | default: |
frank26080115 | 0:bf7b9fba3924 | 510 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 511 | //EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 512 | break; |
frank26080115 | 0:bf7b9fba3924 | 513 | } |
frank26080115 | 0:bf7b9fba3924 | 514 | break; |
frank26080115 | 0:bf7b9fba3924 | 515 | #endif |
frank26080115 | 0:bf7b9fba3924 | 516 | default: |
frank26080115 | 0:bf7b9fba3924 | 517 | USB_SetStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 518 | //EP0Data.Count = 0; |
frank26080115 | 0:bf7b9fba3924 | 519 | break; |
frank26080115 | 0:bf7b9fba3924 | 520 | } |
frank26080115 | 0:bf7b9fba3924 | 521 | USB_StatusInStage(); |
frank26080115 | 0:bf7b9fba3924 | 522 | } |
frank26080115 | 0:bf7b9fba3924 | 523 | } |
frank26080115 | 0:bf7b9fba3924 | 524 | } |
frank26080115 | 0:bf7b9fba3924 | 525 | else |
frank26080115 | 0:bf7b9fba3924 | 526 | { |
frank26080115 | 0:bf7b9fba3924 | 527 | ;//USB_StatusOutStage(); |
frank26080115 | 0:bf7b9fba3924 | 528 | } |
frank26080115 | 0:bf7b9fba3924 | 529 | |
frank26080115 | 0:bf7b9fba3924 | 530 | |
frank26080115 | 0:bf7b9fba3924 | 531 | break; |
frank26080115 | 0:bf7b9fba3924 | 532 | |
frank26080115 | 0:bf7b9fba3924 | 533 | case USB_EVT_IN: |
frank26080115 | 0:bf7b9fba3924 | 534 | if (SetupPacket.bmRequestType.BM.Dir == 1) |
frank26080115 | 0:bf7b9fba3924 | 535 | { |
frank26080115 | 0:bf7b9fba3924 | 536 | if(EP0Data.Count > 0) // ysq add |
frank26080115 | 0:bf7b9fba3924 | 537 | USB_DataInStage(); |
frank26080115 | 0:bf7b9fba3924 | 538 | } |
frank26080115 | 0:bf7b9fba3924 | 539 | //else |
frank26080115 | 0:bf7b9fba3924 | 540 | //{ |
frank26080115 | 0:bf7b9fba3924 | 541 | // if (USB_DeviceAddress & 0x80) |
frank26080115 | 0:bf7b9fba3924 | 542 | // { |
frank26080115 | 0:bf7b9fba3924 | 543 | // USB_DeviceAddress &= 0x7F; |
frank26080115 | 0:bf7b9fba3924 | 544 | // USB_SetAddress(USB_DeviceAddress); |
frank26080115 | 0:bf7b9fba3924 | 545 | // } |
frank26080115 | 0:bf7b9fba3924 | 546 | //} |
frank26080115 | 0:bf7b9fba3924 | 547 | break; |
frank26080115 | 0:bf7b9fba3924 | 548 | |
frank26080115 | 0:bf7b9fba3924 | 549 | case USB_EVT_IN_STALL: |
frank26080115 | 0:bf7b9fba3924 | 550 | USB_ClrStallEP(0x80); |
frank26080115 | 0:bf7b9fba3924 | 551 | break; |
frank26080115 | 0:bf7b9fba3924 | 552 | |
frank26080115 | 0:bf7b9fba3924 | 553 | case USB_EVT_OUT_STALL: |
frank26080115 | 0:bf7b9fba3924 | 554 | USB_ClrStallEP(0x00); |
frank26080115 | 0:bf7b9fba3924 | 555 | break; |
frank26080115 | 0:bf7b9fba3924 | 556 | } |
frank26080115 | 0:bf7b9fba3924 | 557 | } |