2018.07.26

Dependencies:   FATFileSystem2 mbed-rtos

Fork of USBHost by mbed official

Committer:
sayzyas
Date:
Thu Jul 26 00:29:30 2018 +0000
Revision:
44:e437b1c7c61e
Parent:
43:78f328f311dc
2018.07.26

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sayzyas 43:78f328f311dc 1 /* mbed USBHost Library
sayzyas 43:78f328f311dc 2 * Copyright (c) 2006-2013 ARM Limited
sayzyas 43:78f328f311dc 3 *
sayzyas 43:78f328f311dc 4 * Licensed under the Apache License, Version 2.0 (the "License");
sayzyas 43:78f328f311dc 5 * you may not use this file except in compliance with the License.
sayzyas 43:78f328f311dc 6 * You may obtain a copy of the License at
sayzyas 43:78f328f311dc 7 *
sayzyas 43:78f328f311dc 8 * http://www.apache.org/licenses/LICENSE-2.0
sayzyas 43:78f328f311dc 9 *
sayzyas 43:78f328f311dc 10 * Unless required by applicable law or agreed to in writing, software
sayzyas 43:78f328f311dc 11 * distributed under the License is distributed on an "AS IS" BASIS,
sayzyas 43:78f328f311dc 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
sayzyas 43:78f328f311dc 13 * See the License for the specific language governing permissions and
sayzyas 43:78f328f311dc 14 * limitations under the License.
sayzyas 43:78f328f311dc 15 */
sayzyas 43:78f328f311dc 16
sayzyas 43:78f328f311dc 17 #if defined(TARGET_RZ_A1H)
sayzyas 43:78f328f311dc 18
sayzyas 43:78f328f311dc 19 #include "mbed.h"
sayzyas 43:78f328f311dc 20 #include "USBHALHost.h"
sayzyas 43:78f328f311dc 21 #include "dbg.h"
sayzyas 43:78f328f311dc 22
sayzyas 43:78f328f311dc 23 #include "ohci_wrapp_RZ_A1.h"
sayzyas 43:78f328f311dc 24
sayzyas 43:78f328f311dc 25
sayzyas 43:78f328f311dc 26 #define HCCA_SIZE sizeof(HCCA)
sayzyas 43:78f328f311dc 27 #define ED_SIZE sizeof(HCED)
sayzyas 43:78f328f311dc 28 #define TD_SIZE sizeof(HCTD)
sayzyas 43:78f328f311dc 29
sayzyas 43:78f328f311dc 30 #define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
sayzyas 43:78f328f311dc 31 #define ALIGNE_MSK (0x0000000F)
sayzyas 43:78f328f311dc 32
sayzyas 43:78f328f311dc 33 static volatile uint8_t usb_buf[TOTAL_SIZE + ALIGNE_MSK]; //16 bytes aligned!
sayzyas 43:78f328f311dc 34
sayzyas 43:78f328f311dc 35 USBHALHost * USBHALHost::instHost;
sayzyas 43:78f328f311dc 36
sayzyas 43:78f328f311dc 37 USBHALHost::USBHALHost() {
sayzyas 43:78f328f311dc 38 instHost = this;
sayzyas 43:78f328f311dc 39 memInit();
sayzyas 43:78f328f311dc 40 memset((void*)usb_hcca, 0, HCCA_SIZE);
sayzyas 43:78f328f311dc 41 for (int i = 0; i < MAX_ENDPOINT; i++) {
sayzyas 43:78f328f311dc 42 edBufAlloc[i] = false;
sayzyas 43:78f328f311dc 43 }
sayzyas 43:78f328f311dc 44 for (int i = 0; i < MAX_TD; i++) {
sayzyas 43:78f328f311dc 45 tdBufAlloc[i] = false;
sayzyas 43:78f328f311dc 46 }
sayzyas 43:78f328f311dc 47 }
sayzyas 43:78f328f311dc 48
sayzyas 43:78f328f311dc 49 void USBHALHost::init() {
sayzyas 43:78f328f311dc 50 ohciwrapp_init(&_usbisr);
sayzyas 43:78f328f311dc 51
sayzyas 43:78f328f311dc 52 ohciwrapp_reg_w(OHCI_REG_CONTROL, 1); // HARDWARE RESET
sayzyas 43:78f328f311dc 53 ohciwrapp_reg_w(OHCI_REG_CONTROLHEADED, 0); // Initialize Control list head to Zero
sayzyas 43:78f328f311dc 54 ohciwrapp_reg_w(OHCI_REG_BULKHEADED, 0); // Initialize Bulk list head to Zero
sayzyas 43:78f328f311dc 55
sayzyas 43:78f328f311dc 56 // Wait 100 ms before apply reset
sayzyas 43:78f328f311dc 57 wait_ms(100);
sayzyas 43:78f328f311dc 58
sayzyas 43:78f328f311dc 59 // software reset
sayzyas 43:78f328f311dc 60 ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_HCR);
sayzyas 43:78f328f311dc 61
sayzyas 43:78f328f311dc 62 // Write Fm Interval and Largest Data Packet Counter
sayzyas 43:78f328f311dc 63 ohciwrapp_reg_w(OHCI_REG_FMINTERVAL, DEFAULT_FMINTERVAL);
sayzyas 43:78f328f311dc 64 ohciwrapp_reg_w(OHCI_REG_PERIODICSTART, FI * 90 / 100);
sayzyas 43:78f328f311dc 65
sayzyas 43:78f328f311dc 66 // Put HC in operational state
sayzyas 43:78f328f311dc 67 ohciwrapp_reg_w(OHCI_REG_CONTROL, (ohciwrapp_reg_r(OHCI_REG_CONTROL) & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER);
sayzyas 43:78f328f311dc 68 // Set Global Power
sayzyas 43:78f328f311dc 69 ohciwrapp_reg_w(OHCI_REG_RHSTATUS, OR_RH_STATUS_LPSC);
sayzyas 43:78f328f311dc 70
sayzyas 43:78f328f311dc 71 ohciwrapp_reg_w(OHCI_REG_HCCA, (uint32_t)(usb_hcca));
sayzyas 43:78f328f311dc 72
sayzyas 43:78f328f311dc 73 // Clear Interrrupt Status
sayzyas 43:78f328f311dc 74 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS));
sayzyas 43:78f328f311dc 75
sayzyas 43:78f328f311dc 76 ohciwrapp_reg_w(OHCI_REG_INTERRUPTENABLE, OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC);
sayzyas 43:78f328f311dc 77
sayzyas 43:78f328f311dc 78 // Enable the USB Interrupt
sayzyas 43:78f328f311dc 79 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_CSC);
sayzyas 43:78f328f311dc 80 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
sayzyas 43:78f328f311dc 81
sayzyas 43:78f328f311dc 82 // Check for any connected devices
sayzyas 43:78f328f311dc 83 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
sayzyas 43:78f328f311dc 84 //Device connected
sayzyas 43:78f328f311dc 85 wait_ms(150);
sayzyas 43:78f328f311dc 86 USB_DBG("Device connected (%08x)\n\r", ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1));
sayzyas 43:78f328f311dc 87 deviceConnected(0, 1, ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_LSDA);
sayzyas 43:78f328f311dc 88 }
sayzyas 43:78f328f311dc 89 }
sayzyas 43:78f328f311dc 90
sayzyas 43:78f328f311dc 91 uint32_t USBHALHost::controlHeadED() {
sayzyas 43:78f328f311dc 92 return ohciwrapp_reg_r(OHCI_REG_CONTROLHEADED);
sayzyas 43:78f328f311dc 93 }
sayzyas 43:78f328f311dc 94
sayzyas 43:78f328f311dc 95 uint32_t USBHALHost::bulkHeadED() {
sayzyas 43:78f328f311dc 96 return ohciwrapp_reg_r(OHCI_REG_BULKHEADED);
sayzyas 43:78f328f311dc 97 }
sayzyas 43:78f328f311dc 98
sayzyas 43:78f328f311dc 99 uint32_t USBHALHost::interruptHeadED() {
sayzyas 43:78f328f311dc 100 return usb_hcca->IntTable[0];
sayzyas 43:78f328f311dc 101 }
sayzyas 43:78f328f311dc 102
sayzyas 43:78f328f311dc 103 void USBHALHost::updateBulkHeadED(uint32_t addr) {
sayzyas 43:78f328f311dc 104 ohciwrapp_reg_w(OHCI_REG_BULKHEADED, addr);
sayzyas 43:78f328f311dc 105 }
sayzyas 43:78f328f311dc 106
sayzyas 43:78f328f311dc 107
sayzyas 43:78f328f311dc 108 void USBHALHost::updateControlHeadED(uint32_t addr) {
sayzyas 43:78f328f311dc 109 ohciwrapp_reg_w(OHCI_REG_CONTROLHEADED, addr);
sayzyas 43:78f328f311dc 110 }
sayzyas 43:78f328f311dc 111
sayzyas 43:78f328f311dc 112 void USBHALHost::updateInterruptHeadED(uint32_t addr) {
sayzyas 43:78f328f311dc 113 usb_hcca->IntTable[0] = addr;
sayzyas 43:78f328f311dc 114 }
sayzyas 43:78f328f311dc 115
sayzyas 43:78f328f311dc 116
sayzyas 43:78f328f311dc 117 void USBHALHost::enableList(ENDPOINT_TYPE type) {
sayzyas 43:78f328f311dc 118 uint32_t wk_data;
sayzyas 43:78f328f311dc 119
sayzyas 43:78f328f311dc 120 switch(type) {
sayzyas 43:78f328f311dc 121 case CONTROL_ENDPOINT:
sayzyas 43:78f328f311dc 122 ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_CLF);
sayzyas 43:78f328f311dc 123 wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_CLE);
sayzyas 43:78f328f311dc 124 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
sayzyas 43:78f328f311dc 125 break;
sayzyas 43:78f328f311dc 126 case ISOCHRONOUS_ENDPOINT:
sayzyas 43:78f328f311dc 127 break;
sayzyas 43:78f328f311dc 128 case BULK_ENDPOINT:
sayzyas 43:78f328f311dc 129 ohciwrapp_reg_w(OHCI_REG_COMMANDSTATUS, OR_CMD_STATUS_BLF);
sayzyas 43:78f328f311dc 130 wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_BLE);
sayzyas 43:78f328f311dc 131 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
sayzyas 43:78f328f311dc 132 break;
sayzyas 43:78f328f311dc 133 case INTERRUPT_ENDPOINT:
sayzyas 43:78f328f311dc 134 wk_data = (ohciwrapp_reg_r(OHCI_REG_CONTROL) | OR_CONTROL_PLE);
sayzyas 43:78f328f311dc 135 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
sayzyas 43:78f328f311dc 136 break;
sayzyas 43:78f328f311dc 137 }
sayzyas 43:78f328f311dc 138 }
sayzyas 43:78f328f311dc 139
sayzyas 43:78f328f311dc 140
sayzyas 43:78f328f311dc 141 bool USBHALHost::disableList(ENDPOINT_TYPE type) {
sayzyas 43:78f328f311dc 142 uint32_t wk_data;
sayzyas 43:78f328f311dc 143
sayzyas 43:78f328f311dc 144 switch(type) {
sayzyas 43:78f328f311dc 145 case CONTROL_ENDPOINT:
sayzyas 43:78f328f311dc 146 wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
sayzyas 43:78f328f311dc 147 if(wk_data & OR_CONTROL_CLE) {
sayzyas 43:78f328f311dc 148 wk_data &= ~OR_CONTROL_CLE;
sayzyas 43:78f328f311dc 149 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
sayzyas 43:78f328f311dc 150 return true;
sayzyas 43:78f328f311dc 151 }
sayzyas 43:78f328f311dc 152 return false;
sayzyas 43:78f328f311dc 153 case ISOCHRONOUS_ENDPOINT:
sayzyas 43:78f328f311dc 154 return false;
sayzyas 43:78f328f311dc 155 case BULK_ENDPOINT:
sayzyas 43:78f328f311dc 156 wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
sayzyas 43:78f328f311dc 157 if(wk_data & OR_CONTROL_BLE) {
sayzyas 43:78f328f311dc 158 wk_data &= ~OR_CONTROL_BLE;
sayzyas 43:78f328f311dc 159 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
sayzyas 43:78f328f311dc 160 return true;
sayzyas 43:78f328f311dc 161 }
sayzyas 43:78f328f311dc 162 return false;
sayzyas 43:78f328f311dc 163 case INTERRUPT_ENDPOINT:
sayzyas 43:78f328f311dc 164 wk_data = ohciwrapp_reg_r(OHCI_REG_CONTROL);
sayzyas 43:78f328f311dc 165 if(wk_data & OR_CONTROL_PLE) {
sayzyas 43:78f328f311dc 166 wk_data &= ~OR_CONTROL_PLE;
sayzyas 43:78f328f311dc 167 ohciwrapp_reg_w(OHCI_REG_CONTROL, wk_data);
sayzyas 43:78f328f311dc 168 return true;
sayzyas 43:78f328f311dc 169 }
sayzyas 43:78f328f311dc 170 return false;
sayzyas 43:78f328f311dc 171 }
sayzyas 43:78f328f311dc 172 return false;
sayzyas 43:78f328f311dc 173 }
sayzyas 43:78f328f311dc 174
sayzyas 43:78f328f311dc 175
sayzyas 43:78f328f311dc 176 void USBHALHost::memInit() {
sayzyas 43:78f328f311dc 177 volatile uint8_t *p_wk_buf = (uint8_t *)(((uint32_t)usb_buf + ALIGNE_MSK) & ~ALIGNE_MSK);
sayzyas 43:78f328f311dc 178
sayzyas 43:78f328f311dc 179 usb_hcca = (volatile HCCA *)p_wk_buf;
sayzyas 43:78f328f311dc 180 usb_edBuf = (volatile uint8_t *)(p_wk_buf + HCCA_SIZE);
sayzyas 43:78f328f311dc 181 usb_tdBuf = (volatile uint8_t *)(p_wk_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE));
sayzyas 43:78f328f311dc 182 }
sayzyas 43:78f328f311dc 183
sayzyas 43:78f328f311dc 184 volatile uint8_t * USBHALHost::getED() {
sayzyas 43:78f328f311dc 185 for (int i = 0; i < MAX_ENDPOINT; i++) {
sayzyas 43:78f328f311dc 186 if ( !edBufAlloc[i] ) {
sayzyas 43:78f328f311dc 187 edBufAlloc[i] = true;
sayzyas 43:78f328f311dc 188 return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
sayzyas 43:78f328f311dc 189 }
sayzyas 43:78f328f311dc 190 }
sayzyas 43:78f328f311dc 191 perror("Could not allocate ED\r\n");
sayzyas 43:78f328f311dc 192 return NULL; //Could not alloc ED
sayzyas 43:78f328f311dc 193 }
sayzyas 43:78f328f311dc 194
sayzyas 43:78f328f311dc 195 volatile uint8_t * USBHALHost::getTD() {
sayzyas 43:78f328f311dc 196 int i;
sayzyas 43:78f328f311dc 197 for (i = 0; i < MAX_TD; i++) {
sayzyas 43:78f328f311dc 198 if ( !tdBufAlloc[i] ) {
sayzyas 43:78f328f311dc 199 tdBufAlloc[i] = true;
sayzyas 43:78f328f311dc 200 return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
sayzyas 43:78f328f311dc 201 }
sayzyas 43:78f328f311dc 202 }
sayzyas 43:78f328f311dc 203 perror("Could not allocate TD\r\n");
sayzyas 43:78f328f311dc 204 return NULL; //Could not alloc TD
sayzyas 43:78f328f311dc 205 }
sayzyas 43:78f328f311dc 206
sayzyas 43:78f328f311dc 207
sayzyas 43:78f328f311dc 208 void USBHALHost::freeED(volatile uint8_t * ed) {
sayzyas 43:78f328f311dc 209 int i;
sayzyas 43:78f328f311dc 210 i = (ed - usb_edBuf) / ED_SIZE;
sayzyas 43:78f328f311dc 211 edBufAlloc[i] = false;
sayzyas 43:78f328f311dc 212 }
sayzyas 43:78f328f311dc 213
sayzyas 43:78f328f311dc 214 void USBHALHost::freeTD(volatile uint8_t * td) {
sayzyas 43:78f328f311dc 215 int i;
sayzyas 43:78f328f311dc 216 i = (td - usb_tdBuf) / TD_SIZE;
sayzyas 43:78f328f311dc 217 tdBufAlloc[i] = false;
sayzyas 43:78f328f311dc 218 }
sayzyas 43:78f328f311dc 219
sayzyas 43:78f328f311dc 220
sayzyas 43:78f328f311dc 221 void USBHALHost::resetRootHub() {
sayzyas 43:78f328f311dc 222 // Initiate port reset
sayzyas 43:78f328f311dc 223 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRS);
sayzyas 43:78f328f311dc 224
sayzyas 43:78f328f311dc 225 while (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRS);
sayzyas 43:78f328f311dc 226
sayzyas 43:78f328f311dc 227 // ...and clear port reset signal
sayzyas 43:78f328f311dc 228 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
sayzyas 43:78f328f311dc 229 }
sayzyas 43:78f328f311dc 230
sayzyas 43:78f328f311dc 231
sayzyas 43:78f328f311dc 232 void USBHALHost::_usbisr(void) {
sayzyas 43:78f328f311dc 233 if (instHost) {
sayzyas 43:78f328f311dc 234 instHost->UsbIrqhandler();
sayzyas 43:78f328f311dc 235 }
sayzyas 43:78f328f311dc 236 }
sayzyas 43:78f328f311dc 237
sayzyas 43:78f328f311dc 238 void USBHALHost::UsbIrqhandler() {
sayzyas 43:78f328f311dc 239 uint32_t int_status = ohciwrapp_reg_r(OHCI_REG_INTERRUPTSTATUS) & ohciwrapp_reg_r(OHCI_REG_INTERRUPTENABLE);
sayzyas 43:78f328f311dc 240 uint32_t data;
sayzyas 43:78f328f311dc 241
sayzyas 43:78f328f311dc 242 if (int_status != 0) { //Is there something to actually process?
sayzyas 43:78f328f311dc 243 // Root hub status change interrupt
sayzyas 43:78f328f311dc 244 if (int_status & OR_INTR_STATUS_RHSC) {
sayzyas 43:78f328f311dc 245 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CSC) {
sayzyas 43:78f328f311dc 246 if (ohciwrapp_reg_r(OHCI_REG_RHSTATUS) & OR_RH_STATUS_DRWE) {
sayzyas 43:78f328f311dc 247 // When DRWE is on, Connect Status Change
sayzyas 43:78f328f311dc 248 // means a remote wakeup event.
sayzyas 43:78f328f311dc 249 } else {
sayzyas 43:78f328f311dc 250
sayzyas 43:78f328f311dc 251 //Root device connected
sayzyas 43:78f328f311dc 252 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_CCS) {
sayzyas 43:78f328f311dc 253
sayzyas 43:78f328f311dc 254 // wait 150ms to avoid bounce
sayzyas 43:78f328f311dc 255 wait_ms(150);
sayzyas 43:78f328f311dc 256
sayzyas 43:78f328f311dc 257 //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
sayzyas 43:78f328f311dc 258 data = ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_LSDA;
sayzyas 43:78f328f311dc 259 deviceConnected(0, 1, data);
sayzyas 43:78f328f311dc 260 }
sayzyas 43:78f328f311dc 261
sayzyas 43:78f328f311dc 262 //Root device disconnected
sayzyas 43:78f328f311dc 263 else {
sayzyas 43:78f328f311dc 264
sayzyas 43:78f328f311dc 265 if (!(int_status & OR_INTR_STATUS_WDH)) {
sayzyas 43:78f328f311dc 266 usb_hcca->DoneHead = 0;
sayzyas 43:78f328f311dc 267 }
sayzyas 43:78f328f311dc 268
sayzyas 43:78f328f311dc 269 deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
sayzyas 43:78f328f311dc 270
sayzyas 43:78f328f311dc 271 if (int_status & OR_INTR_STATUS_WDH) {
sayzyas 43:78f328f311dc 272 usb_hcca->DoneHead = 0;
sayzyas 43:78f328f311dc 273 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_WDH);
sayzyas 43:78f328f311dc 274 }
sayzyas 43:78f328f311dc 275 }
sayzyas 43:78f328f311dc 276 }
sayzyas 43:78f328f311dc 277 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_CSC);
sayzyas 43:78f328f311dc 278 }
sayzyas 43:78f328f311dc 279 if (ohciwrapp_reg_r(OHCI_REG_RHPORTSTATUS1) & OR_RH_PORT_PRSC) {
sayzyas 43:78f328f311dc 280 ohciwrapp_reg_w(OHCI_REG_RHPORTSTATUS1, OR_RH_PORT_PRSC);
sayzyas 43:78f328f311dc 281 }
sayzyas 43:78f328f311dc 282 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_RHSC);
sayzyas 43:78f328f311dc 283 }
sayzyas 43:78f328f311dc 284
sayzyas 43:78f328f311dc 285 // Writeback Done Head interrupt
sayzyas 43:78f328f311dc 286 if (int_status & OR_INTR_STATUS_WDH) {
sayzyas 43:78f328f311dc 287 transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
sayzyas 43:78f328f311dc 288 ohciwrapp_reg_w(OHCI_REG_INTERRUPTSTATUS, OR_INTR_STATUS_WDH);
sayzyas 43:78f328f311dc 289 }
sayzyas 43:78f328f311dc 290 }
sayzyas 43:78f328f311dc 291 }
sayzyas 43:78f328f311dc 292 #endif