/** * Main function, containing the main loop that manages timer- and * USB-functionality. * /return the obligatory integer that nobody cares about... */ void usb_main(void) { // USB Reset by device only required on Watchdog Reset P2U_PS2_PORT &= ~((1 << P2U_PS2_CLOCK_PIN)|(1 << P2U_PS2_DATA_PIN)); // input:tri-state output:low P2U_USB_CFG_DDR &= ~((1 << P2U_USB_CFG_DPLUS_BIT)|(1 << P2U_USB_CFG_DMINUS_BIT));// input, remove USB reset condition usbInit(); int interfaceCount = 0; if( eeprom_read_byte((uint8_t *)EEPROM_USB_COMPATIBILITY) == 0x00 ) { usbDeviceDisconnect(); /* do this while interrupts are disabled */ uchar i = 0; do{ /* fake USB disconnect for > 250 ms */ wdt_reset(); _delay_ms(1); }while(--i); } usbDeviceConnect(); // init setKeyScanDriver(&driverKeyScanUsb); setUpdateDriver(&updateUsb); clearReportBuffer(); sei(); #if USB_COUNT_SOF bool _isSuspended = false; int suspendCount = 0; #endif for(;;){ /* * USB3.0 + win10의 경우 usbDeviceConnect() 딜레이가 있으면 일부 장치에서 인식이 되지않아 이를 제거 * 하지만, 구식 부트로더 (ps2avrGB_bootloader_140623)의 경우 빠져나올 때 usbDeviceDisconnect()를 처리하지 않아서 * 이를 여기서 처리해줌. */ if(interfaceReady == false && interfaceCount++ > 1000) { cli(); usbDeviceDisconnect(); wdt_enable(WDTO_15MS); for(;;); } #if USB_COUNT_SOF if (usbSofCount != 0) { _isSuspended = false; usbSofCount = 0; suspendCount = 0; _usbReset = false; wakeUp(); } else if(_usbReset == true){ _isSuspended = false; usbSofCount = 1; wakeUp(); }else{ // Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1) if (_isSuspended == false && suspendCount++ > 1000 && isReleaseAll()) { _isSuspended = true; sleep(); } } #endif // main event loop usbPoll(); // if an update is needed, send the report if (usbInterruptIsReady()) { scanKeyUsbWithMacro(); // changes? if(updateNeeded){ if(interfaceReady==false) continue; #if USB_COUNT_SOF if(_isSuspended == true) { wake_up_signal(); updateNeeded = 0; continue; } #endif memset(reportKeyboard, 0, REPORT_SIZE_KEYBOARD); reportKeyboard[0] = _modifiers; reportKeyboard[1] = 0; memcpy ( reportKeyboard+2, reportBuffer, _countOfBuffer ); //strlen((char *)reportBuffer) ); // DBG1(0x06, (uchar *)&reportKeyboard, 8); usbSetInterrupt((void *)&reportKeyboard, sizeof(reportKeyboard)); updateNeeded = 0; #if !USB_COUNT_SOF wakeUpUsb(); #endif }else if(_initState == INIT_INDEX_SET_IDLE){ // DBG1(0x99, (uchar *)&_initState, 1); _initState = INIT_INDEX_INITED; // 재부팅시 첫키 입력 오류를 방지하기 위해서 HID init 후 all release 전송; memset(reportKeyboard, 0, REPORT_SIZE_KEYBOARD); usbSetInterrupt((void *)&reportKeyboard, sizeof(reportKeyboard)); clearMatrix(); #if !USB_COUNT_SOF wakeUpUsb(); #endif // 플러깅 후 출력되는 메세지는 넘락등 LED가 반응한 후에 보여진다. // usbInterruptIsReady() 일지라도 LED 반응 전에는 출력이 되지 않는다. // LED 반응 후에 처리하려고 하면 MAC OS에서 실행되지 않는다. // (MAC OS에서는 플러깅 시 LED가 반응하지 않는다. 대신 바로 출력이 된다.) // for os x // DBG1(0xAA, (uchar *)&idleRate, 1); }else if(_ledInitState == INIT_LED_INDEX_INITED){ _ledInitState = INIT_LED_INDEX_COMPLETE; // for windows } // ps2avrU loop, must be after scan matrix; enterFrame(); } #if !defined( USING_SIMPLE_MODE ) if(usbInterruptIsReady3()){ if(_extraHasChanged){ report_extra_t gReportExtra = { .report_id = REPORT_ID_CONSUMER, .usage = extraData }; usbSetInterrupt3((void *)&gReportExtra, sizeof(gReportExtra)); _extraHasChanged = false; #if !USB_COUNT_SOF wakeUpUsb(); #endif } if(_systemHasChanged){ report_extra_t gReportExtra = { .report_id = REPORT_ID_SYSTEM, .usage = systemData }; usbSetInterrupt3((void *)&gReportExtra, sizeof(gReportExtra)); _systemHasChanged = false; #if !USB_COUNT_SOF wakeUpUsb(); #endif } } #endif if(_initState == INIT_INDEX_INITED){ if(initCount++ == 200){ // delay for OS X USB multi device // all platform init led initAfterInterfaceMount(); // DBG1(0xAB, (uchar *)&initCount, 2); }else if(initCount > 200){ initCount = 201; _initState = INIT_INDEX_COMPLETE; } } #if !USB_COUNT_SOF // 입력이 한동안 없으면 슬립모드로; countSleepUsb(); #endif } /* #if !defined(INTERFACE_ONLY_USB) // data line reset; USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT); #endif */ }
static void processTxPs2(void){ if (isReadyForTx() && !isWaitingRx()) { // pokud flag odesilani ok -> if the flag sent ok switch(m_state) { case STA_NORMAL: // if error during send if(isEmpty()){ scanKeyPs2WithMacro(); } // ps2avrU loop, must be scan matrix; enterFrame(); keyval = pop(); if(keyval == WAIT_RX) { setWaitingRx(true); return; } if(keyval==SPLIT) return; if(keyval) { tx_state(keyval, STA_NORMAL); loopCnt=0; }else if(lastMAKE_SIZE>0) { // means key is still pressed loopCnt++; // if key is pressed until typmatic_delay, goes to repeat the last key if(loopCnt >= TYPEMATIC_DELAY*150+230) { loopCnt=0; lastMAKE_IDX=0; m_state = STA_REPEAT; } } break; // typematic : repeat last key case STA_REPEAT: if(lastMAKE_IDX==0) { // key state can be escaped only if whole key scancode is transmitted scanKeyPs2WithMacro(); } // ps2avrU loop, must be scan matrix; enterFrame(); if(lastMAKE_SIZE==0 || !isEmpty()) { // key is released. go to normal m_state=STA_NORMAL; loopCnt=0; break; } // if release key is pushed, send them. if(loopCnt==1 || lastMAKE_IDX!=0) { tx_state(lastMAKE[lastMAKE_IDX++], STA_REPEAT); lastMAKE_IDX %= lastMAKE_SIZE; } loopCnt++; loopCnt %= (3+TYPEMATIC_REPEAT*10) * ps2_repeat_speed; break; case STA_WAIT_SCAN_REPLY: tx_state(0x02, STA_NORMAL); break; case STA_WAIT_ID: tx_state(0xAB, STA_WAIT_ID1); break; case STA_WAIT_ID1: tx_state(0x83, STA_NORMAL); break; case STA_WAIT_RESET: clear(); tx_state(0xAA, STA_NORMAL); break; } } }
/** * Main function, containing the main loop that manages timer- and * USB-functionality. * /return the obligatory integer that nobody cares about... */ void usb_main(void) { // USB Reset by device only required on Watchdog Reset P2U_PS2_PORT &= ~((1 << P2U_PS2_CLOCK_PIN)|(1 << P2U_PS2_DATA_PIN)); // input:tri-state output:low P2U_USB_CFG_DDR &= ~((1 << P2U_USB_CFG_DPLUS_BIT)|(1 << P2U_USB_CFG_DMINUS_BIT));// input, remove USB reset condition // configure timer 0 for a rate of 12M/(1024 * 256) = 45.78Hz (~22ms) //TCCR0 |= (1<<CS02)|(1<<CS00); // timer 0 prescaler: 1024 // TCCR0 &= ~((1<<CS02)|(1<<CS01)|(1<<CS00)); // timer stop usbInit(); uint8_t idleCounter = 0; uchar i = 0; usbDeviceDisconnect(); /* do this while interrupts are disabled */ do{ /* fake USB disconnect for > 250 ms */ // wdt_reset(); _delay_ms(1); }while(--i); usbDeviceConnect(); // init setKeyScanDriver(&driverKeyScanUsb); setUpdateDriver(&updateUsb); clearReportBuffer(); sei(); #if USB_COUNT_SOF bool _isSuspended = false; int suspendCount = 0; #endif for(;;){ #ifndef INTERFACE_ONLY_USB // 카운트 이내에 신호가 잡히지 않으면 이동; // 특별한 경우에만 발생하는 현상이다. if(INTERFACE == INTERFACE_USB && interfaceReady == false && interfaceCount++ > 3000){ // move to ps/2 INTERFACE = INTERFACE_PS2; DBG1(0x88, 0, 0); break; } #endif #if USB_COUNT_SOF if (usbSofCount != 0) { // DBG1(0x55, (uchar *)&usbSofCount, 1); _isSuspended = false; usbSofCount = 0; suspendCount = 0; _usbReset = false; wakeUp(); } else if(_usbReset == true){ // DBG1(0x56, (uchar *)&usbSofCount, 1); _isSuspended = false; usbSofCount = 1; wakeUp(); }else{ // Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1) if (_isSuspended == false && suspendCount++ > 10000 && getModifierDownBuffer() == 0 && getDownBufferAt(0) == 0) { // DBG1(0x5a, (uchar *)&usbSofCount, 2); _isSuspended = true; sleep(); } } #endif // main event loop usbPoll(); #if USB_COUNT_SOF /*if(_isSuspended == true) { continue; }*/ #endif // check timer if we need periodic reports if (TIFR & (1 << TOV0)) { TIFR = (1 << TOV0); // reset flag if (idleRate != 0) { // do we need periodic reports? if(idleCounter > 4){ // yes, but not yet idleCounter -= 5; // 22ms in units of 4ms } else { // yes, it is time now updateNeeded = 1; idleCounter = idleRate; } } } // if an update is needed, send the report if (usbInterruptIsReady()) { scanKeyUsbWithMacro(); // changes? // ps2avrU loop, must be after scan matrix; enterFrame(); if(updateNeeded){ if(interfaceReady==false) continue; memset(reportKeyboard, 0, REPORT_SIZE_KEYBOARD); reportKeyboard[0] = _modifiers; reportKeyboard[1] = 0; memcpy ( reportKeyboard+2, reportBuffer, strlen((char *)reportBuffer) ); // DBG1(0x06, (uchar *)&reportKeyboard[0], 1); usbSetInterrupt((void *)&reportKeyboard, sizeof(reportKeyboard)); updateNeeded = 0; #if !USB_COUNT_SOF wakeUpUsb(); #endif }else if(_initState == INIT_INDEX_SET_IDLE){ DBG1(0x99, (uchar *)&_initState, 1); _initState = INIT_INDEX_INITED; // 재부팅시 첫키 입력 오류를 방지하기 위해서 HID init 후 all release 전송; memset(reportKeyboard, 0, REPORT_SIZE_KEYBOARD); usbSetInterrupt((void *)&reportKeyboard, sizeof(reportKeyboard)); clearMatrix(); #if !USB_COUNT_SOF wakeUpUsb(); #endif // 플러깅 후 출력되는 메세지는 넘락등 LED가 반응한 후에 보여진다. // usbInterruptIsReady() 일지라도 LED 반응 전에는 출력이 되지 않는다. // LED 반응 후에 처리하려고 하면 MAC OS에서 실행되지 않는다. // (MAC OS에서는 플러깅 시 LED가 반응하지 않는다. 대신 바로 출력이 된다.) // for os x if(idleRate > 0) { startKeyMappingOnBoot(); } // DBG1(0xAA, (uchar *)&idleRate, 1); }else if(_ledInitState == INIT_INDEX_INITED){ _ledInitState = INIT_INDEX_COMPLETE; // for windows if(idleRate == 0) { startKeyMappingOnBoot(); } } } if(usbInterruptIsReady3()){ if(_extraHasChanged){ report_extra_t gReportExtra = { .report_id = REPORT_ID_CONSUMER, .usage = extraData }; usbSetInterrupt3((void *)&gReportExtra, sizeof(gReportExtra)); _extraHasChanged = false; #if !USB_COUNT_SOF wakeUpUsb(); #endif } if(_systemHasChanged){ report_extra_t gReportExtra = { .report_id = REPORT_ID_SYSTEM, .usage = systemData }; usbSetInterrupt3((void *)&gReportExtra, sizeof(gReportExtra)); _systemHasChanged = false; #if !USB_COUNT_SOF wakeUpUsb(); #endif } } if(_initState == INIT_INDEX_INITED){ if(initCount++ == 200){ // delay for OS X USB multi device // all platform init led initAfterInterfaceMount(); }else if(initCount > 200){ initCount = 201; _initState = INIT_INDEX_COMPLETE; } } #if !USB_COUNT_SOF // 입력이 한동안 없으면 슬립모드로; countSleepUsb(); #endif } #ifndef INTERFACE_ONLY_USB // data line reset; USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT); #endif }