summaryrefslogtreecommitdiff
path: root/tmk_core/protocol/vusb/main.c
blob: 3f93ef6d24f2a204c451eb56db6943b76b8b6fe1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* Name: main.c
 * Project: hid-mouse, a very simple HID example
 * Author: Christian Starkjohann
 * Creation Date: 2008-04-07
 * Tabsize: 4
 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
 * This Revision: $Id: main.c 790 2010-05-30 21:00:26Z cs $
 */

#include <stdint.h>

#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/wdt.h>
#include <avr/sleep.h>

#include <usbdrv/usbdrv.h>

#include "vusb.h"

#include "keyboard.h"
#include "host.h"
#include "timer.h"
#include "print.h"
#include "suspend.h"
#include "wait.h"
#include "sendchar.h"

#ifdef SLEEP_LED_ENABLE
#    include "sleep_led.h"
#endif

#ifdef CONSOLE_ENABLE
void console_task(void);
#endif

#ifdef RAW_ENABLE
void raw_hid_task(void);
#endif

/* This is from main.c of USBaspLoader */
static void initForUsbConnectivity(void) {
    uint8_t i = 0;

    usbInit();
    /* enforce USB re-enumerate: */
    usbDeviceDisconnect(); /* do this while interrupts are disabled */
    while (--i) {          /* fake USB disconnect for > 250 ms */
        wdt_reset();
        wait_ms(1);
    }
    usbDeviceConnect();
}

static void usb_remote_wakeup(void) {
    cli();

    int8_t ddr_orig = USBDDR;
    USBOUT |= (1 << USBMINUS);
    USBDDR = ddr_orig | USBMASK;
    USBOUT ^= USBMASK;

    wait_ms(25);

    USBOUT ^= USBMASK;
    USBDDR = ddr_orig;
    USBOUT &= ~(1 << USBMINUS);

    sei();
}

/** \brief Setup USB
 *
 * FIXME: Needs doc
 */
static void setup_usb(void) { initForUsbConnectivity(); }

/** \brief Main
 *
 * FIXME: Needs doc
 */
int main(void) __attribute__((weak));
int main(void) {
    bool suspended = false;
#if USB_COUNT_SOF
    uint16_t last_timer = timer_read();
#endif

#ifdef CLKPR
    // avoid unintentional changes of clock frequency in devices that have a
    // clock prescaler
    clock_prescale_set(clock_div_1);
#endif
    keyboard_setup();
    setup_usb();
    sei();
    keyboard_init();
    host_set_driver(vusb_driver());

    wait_ms(50);

#ifdef SLEEP_LED_ENABLE
    sleep_led_init();
#endif

    while (1) {
#if USB_COUNT_SOF
        if (usbSofCount != 0) {
            suspended   = false;
            usbSofCount = 0;
            last_timer  = timer_read();
#    ifdef SLEEP_LED_ENABLE
            sleep_led_disable();
#    endif
        } else {
            // Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1)
            if (timer_elapsed(last_timer) > 5) {
                suspended = true;
#    ifdef SLEEP_LED_ENABLE
                sleep_led_enable();
#    endif
            }
        }
#endif
        if (!suspended) {
            usbPoll();

            // TODO: configuration process is inconsistent. it sometime fails.
            // To prevent failing to configure NOT scan keyboard during configuration
            if (usbConfiguration && usbInterruptIsReady()) {
                keyboard_task();
            }
            vusb_transfer_keyboard();

#ifdef RAW_ENABLE
            usbPoll();

            if (usbConfiguration && usbInterruptIsReady3()) {
                raw_hid_task();
            }
#endif
#ifdef CONSOLE_ENABLE
            usbPoll();

            if (usbConfiguration && usbInterruptIsReady3()) {
                console_task();
            }
#endif

            // Run housekeeping
            housekeeping_task_kb();
            housekeeping_task_user();
        } else if (suspend_wakeup_condition()) {
            usb_remote_wakeup();
        }
    }
}