diff options
Diffstat (limited to 'tmk_core')
65 files changed, 17114 insertions, 1 deletions
diff --git a/tmk_core/arm_atsam.mk b/tmk_core/arm_atsam.mk new file mode 100644 index 000000000..ef412d59d --- /dev/null +++ b/tmk_core/arm_atsam.mk | |||
@@ -0,0 +1,56 @@ | |||
1 | # Hey Emacs, this is a -*- makefile -*- | ||
2 | ############################################################################## | ||
3 | # Compiler settings | ||
4 | # | ||
5 | CC = arm-none-eabi-gcc | ||
6 | OBJCOPY = arm-none-eabi-objcopy | ||
7 | OBJDUMP = arm-none-eabi-objdump | ||
8 | SIZE = arm-none-eabi-size | ||
9 | AR = arm-none-eabi-ar rcs | ||
10 | NM = arm-none-eabi-nm | ||
11 | HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature | ||
12 | EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) | ||
13 | BIN = | ||
14 | |||
15 | COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/include | ||
16 | COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/arm/cmsis/5.0.1/CMSIS/Include | ||
17 | |||
18 | COMPILEFLAGS += -funsigned-char | ||
19 | COMPILEFLAGS += -funsigned-bitfields | ||
20 | COMPILEFLAGS += -ffunction-sections | ||
21 | COMPILEFLAGS += -fshort-enums | ||
22 | COMPILEFLAGS += -fno-inline-small-functions | ||
23 | COMPILEFLAGS += -fno-strict-aliasing | ||
24 | COMPILEFLAGS += -mfloat-abi=hard | ||
25 | COMPILEFLAGS += -mfpu=fpv4-sp-d16 | ||
26 | COMPILEFLAGS += -mthumb | ||
27 | |||
28 | #ALLOW_WARNINGS = yes | ||
29 | |||
30 | CFLAGS += $(COMPILEFLAGS) | ||
31 | |||
32 | CPPFLAGS += $(COMPILEFLAGS) | ||
33 | CPPFLAGS += -fno-exceptions -std=c++11 | ||
34 | |||
35 | LDFLAGS +=-Wl,--gc-sections | ||
36 | LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map" | ||
37 | LDFLAGS += -Wl,--start-group | ||
38 | LDFLAGS += -Wl,--end-group | ||
39 | LDFLAGS += -Wl,--gc-sections | ||
40 | LDFLAGS += -T$(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/gcc/gcc/samd51j18a_flash.ld | ||
41 | |||
42 | OPT_DEFS += -DPROTOCOL_ARM_ATSAM | ||
43 | |||
44 | MCUFLAGS = -mcpu=$(MCU) | ||
45 | MCUFLAGS += -D__$(ARM_ATSAM)__ | ||
46 | |||
47 | # List any extra directories to look for libraries here. | ||
48 | # Each directory must be seperated by a space. | ||
49 | # Use forward slashes for directory separators. | ||
50 | # For a directory that has spaces, enclose it in quotes. | ||
51 | EXTRALIBDIRS = | ||
52 | |||
53 | # Convert hex to bin. | ||
54 | bin: $(BUILD_DIR)/$(TARGET).hex | ||
55 | $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin | ||
56 | $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin; | ||
diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 3e407f157..fd91d29dc 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk | |||
@@ -3,6 +3,8 @@ ifeq ($(PLATFORM),AVR) | |||
3 | PLATFORM_COMMON_DIR = $(COMMON_DIR)/avr | 3 | PLATFORM_COMMON_DIR = $(COMMON_DIR)/avr |
4 | else ifeq ($(PLATFORM),CHIBIOS) | 4 | else ifeq ($(PLATFORM),CHIBIOS) |
5 | PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios | 5 | PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios |
6 | else ifeq ($(PLATFORM),ARM_ATSAM) | ||
7 | PLATFORM_COMMON_DIR = $(COMMON_DIR)/arm_atsam | ||
6 | else | 8 | else |
7 | PLATFORM_COMMON_DIR = $(COMMON_DIR)/test | 9 | PLATFORM_COMMON_DIR = $(COMMON_DIR)/test |
8 | endif | 10 | endif |
@@ -35,6 +37,10 @@ ifeq ($(PLATFORM),CHIBIOS) | |||
35 | endif | 37 | endif |
36 | endif | 38 | endif |
37 | 39 | ||
40 | ifeq ($(PLATFORM),ARM_ATSAM) | ||
41 | TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c | ||
42 | endif | ||
43 | |||
38 | ifeq ($(PLATFORM),TEST) | 44 | ifeq ($(PLATFORM),TEST) |
39 | TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c | 45 | TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c |
40 | endif | 46 | endif |
diff --git a/tmk_core/common/arm_atsam/bootloader.c b/tmk_core/common/arm_atsam/bootloader.c new file mode 100644 index 000000000..5155d9ff0 --- /dev/null +++ b/tmk_core/common/arm_atsam/bootloader.c | |||
@@ -0,0 +1,19 @@ | |||
1 | /* Copyright 2017 Fred Sundvik | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include "bootloader.h" | ||
18 | |||
19 | void bootloader_jump(void) {} | ||
diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c new file mode 100644 index 000000000..61cc039ef --- /dev/null +++ b/tmk_core/common/arm_atsam/eeprom.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* Copyright 2017 Fred Sundvik | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include "eeprom.h" | ||
18 | |||
19 | #define EEPROM_SIZE 32 | ||
20 | |||
21 | static uint8_t buffer[EEPROM_SIZE]; | ||
22 | |||
23 | uint8_t eeprom_read_byte(const uint8_t *addr) { | ||
24 | uintptr_t offset = (uintptr_t)addr; | ||
25 | return buffer[offset]; | ||
26 | } | ||
27 | |||
28 | void eeprom_write_byte(uint8_t *addr, uint8_t value) { | ||
29 | uintptr_t offset = (uintptr_t)addr; | ||
30 | buffer[offset] = value; | ||
31 | } | ||
32 | |||
33 | uint16_t eeprom_read_word(const uint16_t *addr) { | ||
34 | const uint8_t *p = (const uint8_t *)addr; | ||
35 | return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8); | ||
36 | } | ||
37 | |||
38 | uint32_t eeprom_read_dword(const uint32_t *addr) { | ||
39 | const uint8_t *p = (const uint8_t *)addr; | ||
40 | return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8) | ||
41 | | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24); | ||
42 | } | ||
43 | |||
44 | void eeprom_read_block(void *buf, const void *addr, uint32_t len) { | ||
45 | const uint8_t *p = (const uint8_t *)addr; | ||
46 | uint8_t *dest = (uint8_t *)buf; | ||
47 | while (len--) { | ||
48 | *dest++ = eeprom_read_byte(p++); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | void eeprom_write_word(uint16_t *addr, uint16_t value) { | ||
53 | uint8_t *p = (uint8_t *)addr; | ||
54 | eeprom_write_byte(p++, value); | ||
55 | eeprom_write_byte(p, value >> 8); | ||
56 | } | ||
57 | |||
58 | void eeprom_write_dword(uint32_t *addr, uint32_t value) { | ||
59 | uint8_t *p = (uint8_t *)addr; | ||
60 | eeprom_write_byte(p++, value); | ||
61 | eeprom_write_byte(p++, value >> 8); | ||
62 | eeprom_write_byte(p++, value >> 16); | ||
63 | eeprom_write_byte(p, value >> 24); | ||
64 | } | ||
65 | |||
66 | void eeprom_write_block(const void *buf, void *addr, uint32_t len) { | ||
67 | uint8_t *p = (uint8_t *)addr; | ||
68 | const uint8_t *src = (const uint8_t *)buf; | ||
69 | while (len--) { | ||
70 | eeprom_write_byte(p++, *src++); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | void eeprom_update_byte(uint8_t *addr, uint8_t value) { | ||
75 | eeprom_write_byte(addr, value); | ||
76 | } | ||
77 | |||
78 | void eeprom_update_word(uint16_t *addr, uint16_t value) { | ||
79 | uint8_t *p = (uint8_t *)addr; | ||
80 | eeprom_write_byte(p++, value); | ||
81 | eeprom_write_byte(p, value >> 8); | ||
82 | } | ||
83 | |||
84 | void eeprom_update_dword(uint32_t *addr, uint32_t value) { | ||
85 | uint8_t *p = (uint8_t *)addr; | ||
86 | eeprom_write_byte(p++, value); | ||
87 | eeprom_write_byte(p++, value >> 8); | ||
88 | eeprom_write_byte(p++, value >> 16); | ||
89 | eeprom_write_byte(p, value >> 24); | ||
90 | } | ||
91 | |||
92 | void eeprom_update_block(const void *buf, void *addr, uint32_t len) { | ||
93 | uint8_t *p = (uint8_t *)addr; | ||
94 | const uint8_t *src = (const uint8_t *)buf; | ||
95 | while (len--) { | ||
96 | eeprom_write_byte(p++, *src++); | ||
97 | } | ||
98 | } | ||
diff --git a/tmk_core/common/arm_atsam/printf.h b/tmk_core/common/arm_atsam/printf.h new file mode 100644 index 000000000..582c83bf5 --- /dev/null +++ b/tmk_core/common/arm_atsam/printf.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _PRINTF_H_ | ||
2 | #define _PRINTF_H_ | ||
3 | |||
4 | #define __xprintf dpf | ||
5 | int dpf(const char *_Format, ...); | ||
6 | |||
7 | #endif //_PRINTF_H_ | ||
8 | |||
diff --git a/tmk_core/common/arm_atsam/suspend.c b/tmk_core/common/arm_atsam/suspend.c new file mode 100644 index 000000000..01d1930ea --- /dev/null +++ b/tmk_core/common/arm_atsam/suspend.c | |||
@@ -0,0 +1,17 @@ | |||
1 | /* Copyright 2017 Fred Sundvik | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | |||
diff --git a/tmk_core/common/arm_atsam/timer.c b/tmk_core/common/arm_atsam/timer.c new file mode 100644 index 000000000..bcfe5002c --- /dev/null +++ b/tmk_core/common/arm_atsam/timer.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include "samd51j18a.h" | ||
2 | #include "timer.h" | ||
3 | #include "tmk_core/protocol/arm_atsam/clks.h" | ||
4 | |||
5 | void set_time(uint64_t tset) | ||
6 | { | ||
7 | ms_clk = tset; | ||
8 | } | ||
9 | |||
10 | void timer_init(void) | ||
11 | { | ||
12 | ms_clk = 0; | ||
13 | } | ||
14 | |||
15 | uint16_t timer_read(void) | ||
16 | { | ||
17 | return (uint16_t)ms_clk; | ||
18 | } | ||
19 | |||
20 | uint32_t timer_read32(void) | ||
21 | { | ||
22 | return (uint32_t)ms_clk; | ||
23 | } | ||
24 | |||
25 | uint64_t timer_read64(void) | ||
26 | { | ||
27 | return ms_clk; | ||
28 | } | ||
29 | |||
30 | uint16_t timer_elapsed(uint16_t tlast) | ||
31 | { | ||
32 | return TIMER_DIFF_16(timer_read(), tlast); | ||
33 | } | ||
34 | |||
35 | uint32_t timer_elapsed32(uint32_t tlast) | ||
36 | { | ||
37 | return TIMER_DIFF_32(timer_read32(), tlast); | ||
38 | } | ||
39 | |||
40 | uint32_t timer_elapsed64(uint32_t tlast) | ||
41 | { | ||
42 | uint64_t tnow = timer_read64(); | ||
43 | return (tnow >= tlast ? tnow - tlast : UINT64_MAX - tlast + tnow); | ||
44 | } | ||
45 | |||
46 | void timer_clear(void) | ||
47 | { | ||
48 | ms_clk = 0; | ||
49 | } | ||
50 | |||
51 | void wait_ms(uint64_t msec) | ||
52 | { | ||
53 | CLK_delay_ms(msec); | ||
54 | } | ||
55 | |||
56 | void wait_us(uint16_t usec) | ||
57 | { | ||
58 | CLK_delay_us(usec); | ||
59 | } | ||
diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h index 8836c0fc7..9cbe67bad 100644 --- a/tmk_core/common/print.h +++ b/tmk_core/common/print.h | |||
@@ -99,6 +99,34 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); | |||
99 | 99 | ||
100 | # endif /* USER_PRINT / NORMAL PRINT */ | 100 | # endif /* USER_PRINT / NORMAL PRINT */ |
101 | 101 | ||
102 | #elif defined(PROTOCOL_ARM_ATSAM) /* PROTOCOL_ARM_ATSAM */ | ||
103 | |||
104 | # include "arm_atsam/printf.h" | ||
105 | |||
106 | # ifdef USER_PRINT /* USER_PRINT */ | ||
107 | |||
108 | // Remove normal print defines | ||
109 | # define print(s) | ||
110 | # define println(s) | ||
111 | # define xprintf(fmt, ...) | ||
112 | |||
113 | // Create user print defines | ||
114 | # define uprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__) | ||
115 | # define uprint(s) xprintf(s) | ||
116 | # define uprintln(s) xprintf(s "\r\n") | ||
117 | |||
118 | # else /* NORMAL PRINT */ | ||
119 | |||
120 | // Create user & normal print defines | ||
121 | # define xprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__) | ||
122 | # define print(s) xprintf(s) | ||
123 | # define println(s) xprintf(s "\r\n") | ||
124 | # define uprint(s) print(s) | ||
125 | # define uprintln(s) println(s) | ||
126 | # define uprintf(fmt, ...) xprintf(fmt, ...) | ||
127 | |||
128 | # endif /* USER_PRINT / NORMAL PRINT */ | ||
129 | |||
102 | #elif defined(__arm__) /* __arm__ */ | 130 | #elif defined(__arm__) /* __arm__ */ |
103 | 131 | ||
104 | # include "mbed/xprintf.h" | 132 | # include "mbed/xprintf.h" |
@@ -130,7 +158,7 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); | |||
130 | /* TODO: to select output destinations: UART/USBSerial */ | 158 | /* TODO: to select output destinations: UART/USBSerial */ |
131 | # define print_set_sendchar(func) | 159 | # define print_set_sendchar(func) |
132 | 160 | ||
133 | #endif /* __AVR__ / PROTOCOL_CHIBIOS / __arm__ */ | 161 | #endif /* __AVR__ / PROTOCOL_CHIBIOS / PROTOCOL_ARM_ATSAM / __arm__ */ |
134 | 162 | ||
135 | // User print disables the normal print messages in the body of QMK/TMK code and | 163 | // User print disables the normal print messages in the body of QMK/TMK code and |
136 | // is meant as a lightweight alternative to NOPRINT. Use it when you only want to do | 164 | // is meant as a lightweight alternative to NOPRINT. Use it when you only want to do |
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h index 6c27eb9dc..167f38275 100644 --- a/tmk_core/common/report.h +++ b/tmk_core/common/report.h | |||
@@ -84,6 +84,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
84 | #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE | 84 | #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE |
85 | #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2) | 85 | #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2) |
86 | #define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1) | 86 | #define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1) |
87 | #elif defined(PROTOCOL_ARM_ATSAM) | ||
88 | #include "protocol/arm_atsam/usb/udi_device_epsize.h" | ||
89 | #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE | ||
90 | #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2) | ||
91 | #define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1) | ||
87 | #else | 92 | #else |
88 | #error "NKRO not supported with this protocol" | 93 | #error "NKRO not supported with this protocol" |
89 | #endif | 94 | #endif |
diff --git a/tmk_core/protocol/arm_atsam.mk b/tmk_core/protocol/arm_atsam.mk new file mode 100644 index 000000000..d535b64cd --- /dev/null +++ b/tmk_core/protocol/arm_atsam.mk | |||
@@ -0,0 +1,26 @@ | |||
1 | ARM_ATSAM_DIR = protocol/arm_atsam | ||
2 | |||
3 | SRC += $(ARM_ATSAM_DIR)/adc.c | ||
4 | SRC += $(ARM_ATSAM_DIR)/clks.c | ||
5 | SRC += $(ARM_ATSAM_DIR)/d51_util.c | ||
6 | SRC += $(ARM_ATSAM_DIR)/i2c_master.c | ||
7 | SRC += $(ARM_ATSAM_DIR)/led_matrix.c | ||
8 | SRC += $(ARM_ATSAM_DIR)/main_arm_atsam.c | ||
9 | SRC += $(ARM_ATSAM_DIR)/spi.c | ||
10 | SRC += $(ARM_ATSAM_DIR)/startup.c | ||
11 | |||
12 | SRC += $(ARM_ATSAM_DIR)/usb/main_usb.c | ||
13 | SRC += $(ARM_ATSAM_DIR)/usb/spfssf.c | ||
14 | SRC += $(ARM_ATSAM_DIR)/usb/udc.c | ||
15 | SRC += $(ARM_ATSAM_DIR)/usb/udi_cdc.c | ||
16 | SRC += $(ARM_ATSAM_DIR)/usb/udi_hid.c | ||
17 | SRC += $(ARM_ATSAM_DIR)/usb/udi_hid_kbd.c | ||
18 | SRC += $(ARM_ATSAM_DIR)/usb/udi_hid_kbd_desc.c | ||
19 | SRC += $(ARM_ATSAM_DIR)/usb/ui.c | ||
20 | SRC += $(ARM_ATSAM_DIR)/usb/usb2422.c | ||
21 | SRC += $(ARM_ATSAM_DIR)/usb/usb.c | ||
22 | SRC += $(ARM_ATSAM_DIR)/usb/usb_device_udd.c | ||
23 | SRC += $(ARM_ATSAM_DIR)/usb/usb_util.c | ||
24 | |||
25 | # Search Path | ||
26 | VPATH += $(TMK_DIR)/$(ARM_ATSAM_DIR) | ||
diff --git a/tmk_core/protocol/arm_atsam/adc.c b/tmk_core/protocol/arm_atsam/adc.c new file mode 100644 index 000000000..ab77f9240 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/adc.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "arm_atsam_protocol.h" | ||
19 | |||
20 | uint16_t v_5v; | ||
21 | uint16_t v_5v_avg; | ||
22 | uint16_t v_con_1; | ||
23 | uint16_t v_con_2; | ||
24 | uint16_t v_con_1_boot; | ||
25 | uint16_t v_con_2_boot; | ||
26 | |||
27 | void ADC0_clock_init(void) | ||
28 | { | ||
29 | DBGC(DC_ADC0_CLOCK_INIT_BEGIN); | ||
30 | |||
31 | MCLK->APBDMASK.bit.ADC0_ = 1; //ADC0 Clock Enable | ||
32 | |||
33 | GCLK->PCHCTRL[ADC0_GCLK_ID].bit.GEN = GEN_OSC0; //Select generator clock | ||
34 | GCLK->PCHCTRL[ADC0_GCLK_ID].bit.CHEN = 1; //Enable peripheral clock | ||
35 | |||
36 | DBGC(DC_ADC0_CLOCK_INIT_COMPLETE); | ||
37 | } | ||
38 | |||
39 | void ADC0_init(void) | ||
40 | { | ||
41 | DBGC(DC_ADC0_INIT_BEGIN); | ||
42 | |||
43 | //MCU | ||
44 | PORT->Group[1].DIRCLR.reg = 1 << 0; //PB00 as input 5V | ||
45 | PORT->Group[1].DIRCLR.reg = 1 << 1; //PB01 as input CON2 | ||
46 | PORT->Group[1].DIRCLR.reg = 1 << 2; //PB02 as input CON1 | ||
47 | PORT->Group[1].PMUX[0].bit.PMUXE = 1; //PB00 mux select B ADC 5V | ||
48 | PORT->Group[1].PMUX[0].bit.PMUXO = 1; //PB01 mux select B ADC CON2 | ||
49 | PORT->Group[1].PMUX[1].bit.PMUXE = 1; //PB02 mux select B ADC CON1 | ||
50 | PORT->Group[1].PINCFG[0].bit.PMUXEN = 1; //PB01 mux ADC Enable 5V | ||
51 | PORT->Group[1].PINCFG[1].bit.PMUXEN = 1; //PB01 mux ADC Enable CON2 | ||
52 | PORT->Group[1].PINCFG[2].bit.PMUXEN = 1; //PB02 mux ADC Enable CON1 | ||
53 | |||
54 | //ADC | ||
55 | ADC0->CTRLA.bit.SWRST = 1; | ||
56 | while (ADC0->SYNCBUSY.bit.SWRST) { DBGC(DC_ADC0_SWRST_SYNCING_1); } | ||
57 | while (ADC0->CTRLA.bit.SWRST) { DBGC(DC_ADC0_SWRST_SYNCING_2); } | ||
58 | |||
59 | //Clock divide | ||
60 | ADC0->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV2_Val; | ||
61 | |||
62 | //Averaging | ||
63 | ADC0->AVGCTRL.bit.SAMPLENUM = ADC_AVGCTRL_SAMPLENUM_4_Val; | ||
64 | while (ADC0->SYNCBUSY.bit.AVGCTRL) { DBGC(DC_ADC0_AVGCTRL_SYNCING_1); } | ||
65 | if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_1_Val) ADC0->AVGCTRL.bit.ADJRES = 0; | ||
66 | else if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_2_Val) ADC0->AVGCTRL.bit.ADJRES = 1; | ||
67 | else if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_4_Val) ADC0->AVGCTRL.bit.ADJRES = 2; | ||
68 | else if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_8_Val) ADC0->AVGCTRL.bit.ADJRES = 3; | ||
69 | else ADC0->AVGCTRL.bit.ADJRES = 4; | ||
70 | while (ADC0->SYNCBUSY.bit.AVGCTRL) { DBGC(DC_ADC0_AVGCTRL_SYNCING_2); } | ||
71 | |||
72 | //Settling | ||
73 | ADC0->SAMPCTRL.bit.SAMPLEN = 45; //Sampling Time Length: 1-63, 1 ADC CLK per | ||
74 | while (ADC0->SYNCBUSY.bit.SAMPCTRL) { DBGC(DC_ADC0_SAMPCTRL_SYNCING_1); } | ||
75 | |||
76 | //Load factory calibration data | ||
77 | ADC0->CALIB.bit.BIASCOMP = (ADC0_FUSES_BIASCOMP_ADDR >> ADC0_FUSES_BIASCOMP_Pos) & ADC0_FUSES_BIASCOMP_Msk; | ||
78 | ADC0->CALIB.bit.BIASR2R = (ADC0_FUSES_BIASR2R_ADDR >> ADC0_FUSES_BIASR2R_Pos) & ADC0_FUSES_BIASR2R_Msk; | ||
79 | ADC0->CALIB.bit.BIASREFBUF = (ADC0_FUSES_BIASREFBUF_ADDR >> ADC0_FUSES_BIASREFBUF_Pos) & ADC0_FUSES_BIASREFBUF_Msk; | ||
80 | |||
81 | //Enable | ||
82 | ADC0->CTRLA.bit.ENABLE = 1; | ||
83 | while (ADC0->SYNCBUSY.bit.ENABLE) { DBGC(DC_ADC0_ENABLE_SYNCING_1); } | ||
84 | |||
85 | DBGC(DC_ADC0_INIT_COMPLETE); | ||
86 | } | ||
87 | |||
88 | uint16_t adc_get(uint8_t muxpos) | ||
89 | { | ||
90 | ADC0->INPUTCTRL.bit.MUXPOS = muxpos; | ||
91 | while (ADC0->SYNCBUSY.bit.INPUTCTRL) {} | ||
92 | |||
93 | ADC0->SWTRIG.bit.START = 1; | ||
94 | while (ADC0->SYNCBUSY.bit.SWTRIG) {} | ||
95 | while (!ADC0->INTFLAG.bit.RESRDY) {} | ||
96 | |||
97 | return ADC0->RESULT.reg; | ||
98 | } | ||
99 | |||
diff --git a/tmk_core/protocol/arm_atsam/adc.h b/tmk_core/protocol/arm_atsam/adc.h new file mode 100644 index 000000000..5a90ece3f --- /dev/null +++ b/tmk_core/protocol/arm_atsam/adc.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _ADC_H_ | ||
19 | #define _ADC_H_ | ||
20 | |||
21 | #define ADC_5V_START_LEVEL 2365 | ||
22 | |||
23 | #define ADC_5V ADC_INPUTCTRL_MUXPOS_AIN12_Val | ||
24 | #define ADC_CON1 ADC_INPUTCTRL_MUXPOS_AIN14_Val | ||
25 | #define ADC_CON2 ADC_INPUTCTRL_MUXPOS_AIN13_Val | ||
26 | |||
27 | extern uint16_t v_5v; | ||
28 | extern uint16_t v_5v_avg; | ||
29 | extern uint16_t v_con_1; | ||
30 | extern uint16_t v_con_2; | ||
31 | extern uint16_t v_con_1_boot; | ||
32 | extern uint16_t v_con_2_boot; | ||
33 | |||
34 | void ADC0_clock_init(void); | ||
35 | void ADC0_init(void); | ||
36 | |||
37 | #endif //_ADC_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h b/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h new file mode 100644 index 000000000..be73beccd --- /dev/null +++ b/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _ARM_ATSAM_PROTOCOL_H_ | ||
19 | #define _ARM_ATSAM_PROTOCOL_H_ | ||
20 | |||
21 | #include "samd51j18a.h" | ||
22 | #include "md_bootloader.h" | ||
23 | |||
24 | #include "d51_util.h" | ||
25 | #include "clks.h" | ||
26 | #include "adc.h" | ||
27 | #include "i2c_master.h" | ||
28 | #include "spi.h" | ||
29 | |||
30 | #include "./usb/usb2422.h" | ||
31 | |||
32 | #ifndef MD_BOOTLOADER | ||
33 | |||
34 | #include "main_arm_atsam.h" | ||
35 | #include "led_matrix.h" | ||
36 | #include "issi3733_driver.h" | ||
37 | #include "./usb/compiler.h" | ||
38 | #include "./usb/udc.h" | ||
39 | #include "./usb/spfssf.h" | ||
40 | #include "./usb/udi_cdc.h" | ||
41 | |||
42 | #endif //MD_BOOTLOADER | ||
43 | |||
44 | #endif //_ARM_ATSAM_PROTOCOL_H_ | ||
45 | |||
diff --git a/tmk_core/protocol/arm_atsam/clks.c b/tmk_core/protocol/arm_atsam/clks.c new file mode 100644 index 000000000..8768d0a99 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/clks.c | |||
@@ -0,0 +1,439 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "arm_atsam_protocol.h" | ||
19 | |||
20 | #include <string.h> | ||
21 | |||
22 | volatile clk_t system_clks; | ||
23 | volatile uint64_t ms_clk; | ||
24 | |||
25 | volatile uint8_t us_delay_done; | ||
26 | |||
27 | const uint32_t sercom_apbbase[] = {(uint32_t)SERCOM0,(uint32_t)SERCOM1,(uint32_t)SERCOM2,(uint32_t)SERCOM3,(uint32_t)SERCOM4,(uint32_t)SERCOM5}; | ||
28 | const uint8_t sercom_pchan[] = {7, 8, 23, 24, 34, 35}; | ||
29 | |||
30 | #define USE_DPLL_IND 0 | ||
31 | #define USE_DPLL_DEF GCLK_SOURCE_DPLL0 | ||
32 | |||
33 | void CLK_oscctrl_init(void) | ||
34 | { | ||
35 | Oscctrl *posctrl = OSCCTRL; | ||
36 | Gclk *pgclk = GCLK; | ||
37 | |||
38 | DBGC(DC_CLK_OSC_INIT_BEGIN); | ||
39 | |||
40 | //default setup on por | ||
41 | system_clks.freq_dfll = FREQ_DFLL_DEFAULT; | ||
42 | system_clks.freq_gclk[0] = system_clks.freq_dfll; | ||
43 | |||
44 | //configure and startup 16MHz xosc0 | ||
45 | posctrl->XOSCCTRL[0].bit.ENABLE = 0; | ||
46 | posctrl->XOSCCTRL[0].bit.STARTUP = 0xD; | ||
47 | posctrl->XOSCCTRL[0].bit.ENALC = 1; | ||
48 | posctrl->XOSCCTRL[0].bit.IMULT = 5; | ||
49 | posctrl->XOSCCTRL[0].bit.IPTAT = 3; | ||
50 | posctrl->XOSCCTRL[0].bit.ONDEMAND = 0; | ||
51 | posctrl->XOSCCTRL[0].bit.XTALEN = 1; | ||
52 | posctrl->XOSCCTRL[0].bit.ENABLE = 1; | ||
53 | while (posctrl->STATUS.bit.XOSCRDY0 == 0) { DBGC(DC_CLK_OSC_INIT_XOSC0_SYNC); } | ||
54 | system_clks.freq_xosc0 = FREQ_XOSC0; | ||
55 | |||
56 | //configure and startup DPLL | ||
57 | posctrl->Dpll[USE_DPLL_IND].DPLLCTRLA.bit.ENABLE = 0; | ||
58 | while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_DISABLE); } | ||
59 | posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.REFCLK = 2; //select XOSC0 (16MHz) | ||
60 | posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.DIV = 7; //16 MHz / (2 * (7 + 1)) = 1 MHz | ||
61 | posctrl->Dpll[USE_DPLL_IND].DPLLRATIO.bit.LDR = PLL_RATIO; //1 MHz * (PLL_RATIO(47) + 1) = 48MHz | ||
62 | while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.DPLLRATIO) { DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_RATIO); } | ||
63 | posctrl->Dpll[USE_DPLL_IND].DPLLCTRLA.bit.ONDEMAND = 0; | ||
64 | posctrl->Dpll[USE_DPLL_IND].DPLLCTRLA.bit.ENABLE = 1; | ||
65 | while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_ENABLE); } | ||
66 | while (posctrl->Dpll[USE_DPLL_IND].DPLLSTATUS.bit.LOCK == 0) { DBGC(DC_CLK_OSC_INIT_DPLL_WAIT_LOCK); } | ||
67 | while (posctrl->Dpll[USE_DPLL_IND].DPLLSTATUS.bit.CLKRDY == 0) { DBGC(DC_CLK_OSC_INIT_DPLL_WAIT_CLKRDY); } | ||
68 | system_clks.freq_dpll[0] = (system_clks.freq_xosc0 / 2 / (posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.DIV + 1)) * (posctrl->Dpll[USE_DPLL_IND].DPLLRATIO.bit.LDR + 1); | ||
69 | |||
70 | //change gclk0 to DPLL | ||
71 | pgclk->GENCTRL[GEN_DPLL0].bit.SRC = USE_DPLL_DEF; | ||
72 | while (pgclk->SYNCBUSY.bit.GENCTRL0) { DBGC(DC_CLK_OSC_INIT_GCLK_SYNC_GENCTRL0); } | ||
73 | |||
74 | system_clks.freq_gclk[0] = system_clks.freq_dpll[0]; | ||
75 | |||
76 | DBGC(DC_CLK_OSC_INIT_COMPLETE); | ||
77 | } | ||
78 | |||
79 | //configure for 1MHz (1 usec timebase) | ||
80 | //call CLK_set_gclk_freq(GEN_TC45, FREQ_TC45_DEFAULT); | ||
81 | uint32_t CLK_set_gclk_freq(uint8_t gclkn, uint32_t freq) | ||
82 | { | ||
83 | Gclk *pgclk = GCLK; | ||
84 | |||
85 | DBGC(DC_CLK_SET_GCLK_FREQ_BEGIN); | ||
86 | |||
87 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_1); } | ||
88 | pgclk->GENCTRL[gclkn].bit.SRC = USE_DPLL_DEF; | ||
89 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_2); } | ||
90 | pgclk->GENCTRL[gclkn].bit.DIV = (uint8_t)(system_clks.freq_dpll[0] / freq); | ||
91 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_3); } | ||
92 | pgclk->GENCTRL[gclkn].bit.DIVSEL = 0; | ||
93 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_4); } | ||
94 | pgclk->GENCTRL[gclkn].bit.GENEN = 1; | ||
95 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_5); } | ||
96 | system_clks.freq_gclk[gclkn] = system_clks.freq_dpll[0] / pgclk->GENCTRL[gclkn].bit.DIV; | ||
97 | |||
98 | DBGC(DC_CLK_SET_GCLK_FREQ_COMPLETE); | ||
99 | |||
100 | return system_clks.freq_gclk[gclkn]; | ||
101 | } | ||
102 | |||
103 | void CLK_init_osc(void) | ||
104 | { | ||
105 | uint8_t gclkn = GEN_OSC0; | ||
106 | Gclk *pgclk = GCLK; | ||
107 | |||
108 | DBGC(DC_CLK_INIT_OSC_BEGIN); | ||
109 | |||
110 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_1); } | ||
111 | pgclk->GENCTRL[gclkn].bit.SRC = GCLK_SOURCE_XOSC0; | ||
112 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_2); } | ||
113 | pgclk->GENCTRL[gclkn].bit.DIV = 1; | ||
114 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_3); } | ||
115 | pgclk->GENCTRL[gclkn].bit.DIVSEL = 0; | ||
116 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_4); } | ||
117 | pgclk->GENCTRL[gclkn].bit.GENEN = 1; | ||
118 | while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_5); } | ||
119 | system_clks.freq_gclk[gclkn] = system_clks.freq_xosc0; | ||
120 | |||
121 | DBGC(DC_CLK_INIT_OSC_COMPLETE); | ||
122 | } | ||
123 | |||
124 | void CLK_reset_time(void) | ||
125 | { | ||
126 | Tc *ptc4 = TC4; | ||
127 | Tc *ptc0 = TC0; | ||
128 | |||
129 | ms_clk = 0; | ||
130 | |||
131 | DBGC(DC_CLK_RESET_TIME_BEGIN); | ||
132 | |||
133 | //stop counters | ||
134 | ptc4->COUNT16.CTRLA.bit.ENABLE = 0; | ||
135 | while (ptc4->COUNT16.SYNCBUSY.bit.ENABLE) {} | ||
136 | ptc0->COUNT32.CTRLA.bit.ENABLE = 0; | ||
137 | while (ptc0->COUNT32.SYNCBUSY.bit.ENABLE) {} | ||
138 | //zero counters | ||
139 | ptc4->COUNT16.COUNT.reg = 0; | ||
140 | while (ptc4->COUNT16.SYNCBUSY.bit.COUNT) {} | ||
141 | ptc0->COUNT32.COUNT.reg = 0; | ||
142 | while (ptc0->COUNT32.SYNCBUSY.bit.COUNT) {} | ||
143 | //start counters | ||
144 | ptc0->COUNT32.CTRLA.bit.ENABLE = 1; | ||
145 | while (ptc0->COUNT32.SYNCBUSY.bit.ENABLE) {} | ||
146 | ptc4->COUNT16.CTRLA.bit.ENABLE = 1; | ||
147 | while (ptc4->COUNT16.SYNCBUSY.bit.ENABLE) {} | ||
148 | |||
149 | DBGC(DC_CLK_RESET_TIME_COMPLETE); | ||
150 | } | ||
151 | |||
152 | void TC4_Handler() | ||
153 | { | ||
154 | if (TC4->COUNT16.INTFLAG.bit.MC0) | ||
155 | { | ||
156 | TC4->COUNT16.INTFLAG.reg = TC_INTENCLR_MC0; | ||
157 | ms_clk++; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | void TC5_Handler() | ||
162 | { | ||
163 | if (TC5->COUNT16.INTFLAG.bit.MC0) | ||
164 | { | ||
165 | TC5->COUNT16.INTFLAG.reg = TC_INTENCLR_MC0; | ||
166 | us_delay_done = 1; | ||
167 | TC5->COUNT16.CTRLA.bit.ENABLE = 0; | ||
168 | while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {} | ||
169 | } | ||
170 | } | ||
171 | |||
172 | uint32_t CLK_enable_timebase(void) | ||
173 | { | ||
174 | Gclk *pgclk = GCLK; | ||
175 | Mclk *pmclk = MCLK; | ||
176 | Tc *ptc4 = TC4; | ||
177 | Tc *ptc5 = TC5; | ||
178 | Tc *ptc0 = TC0; | ||
179 | Evsys *pevsys = EVSYS; | ||
180 | |||
181 | DBGC(DC_CLK_ENABLE_TIMEBASE_BEGIN); | ||
182 | |||
183 | //gclk2 highspeed time base | ||
184 | CLK_set_gclk_freq(GEN_TC45, FREQ_TC45_DEFAULT); | ||
185 | CLK_init_osc(); | ||
186 | |||
187 | //unmask TC4, sourcegclk2 to TC4 | ||
188 | pmclk->APBCMASK.bit.TC4_ = 1; | ||
189 | pgclk->PCHCTRL[TC4_GCLK_ID].bit.GEN = GEN_TC45; | ||
190 | pgclk->PCHCTRL[TC4_GCLK_ID].bit.CHEN = 1; | ||
191 | |||
192 | //unmask TC5 sourcegclk2 to TC5 | ||
193 | pmclk->APBCMASK.bit.TC5_ = 1; | ||
194 | pgclk->PCHCTRL[TC5_GCLK_ID].bit.GEN = GEN_TC45; | ||
195 | pgclk->PCHCTRL[TC5_GCLK_ID].bit.CHEN = 1; | ||
196 | |||
197 | //configure TC4 | ||
198 | DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_BEGIN); | ||
199 | ptc4->COUNT16.CTRLA.bit.ENABLE = 0; | ||
200 | while (ptc4->COUNT16.SYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_DISABLE); } | ||
201 | ptc4->COUNT16.CTRLA.bit.SWRST = 1; | ||
202 | while (ptc4->COUNT16.SYNCBUSY.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_1); } | ||
203 | while (ptc4->COUNT16.CTRLA.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_2); } | ||
204 | |||
205 | //CTRLA defaults | ||
206 | //CTRLB as default, counting up | ||
207 | ptc4->COUNT16.CTRLBCLR.reg = 5; | ||
208 | while (ptc4->COUNT16.SYNCBUSY.bit.CTRLB) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CLTRB); } | ||
209 | ptc4->COUNT16.CC[0].reg = 999; | ||
210 | while (ptc4->COUNT16.SYNCBUSY.bit.CC0) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CC0); } | ||
211 | //ptc4->COUNT16.DBGCTRL.bit.DBGRUN = 1; | ||
212 | |||
213 | //wave mode | ||
214 | ptc4->COUNT16.WAVE.bit.WAVEGEN = 1; //MFRQ match frequency mode, toggle each CC match | ||
215 | //generate event for next stage | ||
216 | ptc4->COUNT16.EVCTRL.bit.MCEO0 = 1; | ||
217 | |||
218 | NVIC_EnableIRQ(TC4_IRQn); | ||
219 | ptc4->COUNT16.INTENSET.bit.MC0 = 1; | ||
220 | |||
221 | DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_COMPLETE); | ||
222 | |||
223 | //configure TC5 | ||
224 | DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_BEGIN); | ||
225 | ptc5->COUNT16.CTRLA.bit.ENABLE = 0; | ||
226 | while (ptc5->COUNT16.SYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_DISABLE); } | ||
227 | ptc5->COUNT16.CTRLA.bit.SWRST = 1; | ||
228 | while (ptc5->COUNT16.SYNCBUSY.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_1); } | ||
229 | while (ptc5->COUNT16.CTRLA.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_2); } | ||
230 | |||
231 | //CTRLA defaults | ||
232 | //CTRLB as default, counting up | ||
233 | ptc5->COUNT16.CTRLBCLR.reg = 5; | ||
234 | while (ptc5->COUNT16.SYNCBUSY.bit.CTRLB) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_CLTRB); } | ||
235 | //ptc5->COUNT16.DBGCTRL.bit.DBGRUN = 1; | ||
236 | |||
237 | //wave mode | ||
238 | ptc5->COUNT16.WAVE.bit.WAVEGEN = 1; //MFRQ match frequency mode, toggle each CC match | ||
239 | //generate event for next stage | ||
240 | ptc5->COUNT16.EVCTRL.bit.MCEO0 = 1; | ||
241 | |||
242 | NVIC_EnableIRQ(TC5_IRQn); | ||
243 | ptc5->COUNT16.INTENSET.bit.MC0 = 1; | ||
244 | |||
245 | DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_COMPLETE); | ||
246 | |||
247 | //unmask TC0,1, sourcegclk2 to TC0,1 | ||
248 | pmclk->APBAMASK.bit.TC0_ = 1; | ||
249 | pgclk->PCHCTRL[TC0_GCLK_ID].bit.GEN = GEN_TC45; | ||
250 | pgclk->PCHCTRL[TC0_GCLK_ID].bit.CHEN = 1; | ||
251 | |||
252 | pmclk->APBAMASK.bit.TC1_ = 1; | ||
253 | pgclk->PCHCTRL[TC1_GCLK_ID].bit.GEN = GEN_TC45; | ||
254 | pgclk->PCHCTRL[TC1_GCLK_ID].bit.CHEN = 1; | ||
255 | |||
256 | //configure TC0 | ||
257 | DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_BEGIN); | ||
258 | ptc0->COUNT32.CTRLA.bit.ENABLE = 0; | ||
259 | while (ptc0->COUNT32.SYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_DISABLE); } | ||
260 | ptc0->COUNT32.CTRLA.bit.SWRST = 1; | ||
261 | while (ptc0->COUNT32.SYNCBUSY.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_1); } | ||
262 | while (ptc0->COUNT32.CTRLA.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_2); } | ||
263 | //CTRLA as default | ||
264 | ptc0->COUNT32.CTRLA.bit.MODE = 2; //32 bit mode | ||
265 | ptc0->COUNT32.EVCTRL.bit.TCEI = 1; //enable incoming events | ||
266 | ptc0->COUNT32.EVCTRL.bit.EVACT = 2 ; //count events | ||
267 | |||
268 | DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_COMPLETE); | ||
269 | |||
270 | DBGC(DC_CLK_ENABLE_TIMEBASE_EVSYS_BEGIN); | ||
271 | |||
272 | //configure event system | ||
273 | pmclk->APBBMASK.bit.EVSYS_ = 1; | ||
274 | pgclk->PCHCTRL[EVSYS_GCLK_ID_0].bit.GEN = GEN_TC45; | ||
275 | pgclk->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 1; | ||
276 | pevsys->USER[44].reg = EVSYS_ID_USER_PORT_EV_0; //TC0 will get event channel 0 | ||
277 | pevsys->Channel[0].CHANNEL.bit.EDGSEL = EVSYS_CHANNEL_EDGSEL_RISING_EDGE_Val; //Rising edge | ||
278 | pevsys->Channel[0].CHANNEL.bit.PATH = EVSYS_CHANNEL_PATH_SYNCHRONOUS_Val; //Synchronous | ||
279 | pevsys->Channel[0].CHANNEL.bit.EVGEN = EVSYS_ID_GEN_TC4_MCX_0; //TC4 MC0 | ||
280 | |||
281 | DBGC(DC_CLK_ENABLE_TIMEBASE_EVSYS_COMPLETE); | ||
282 | |||
283 | CLK_reset_time(); | ||
284 | |||
285 | ADC0_clock_init(); | ||
286 | |||
287 | DBGC(DC_CLK_ENABLE_TIMEBASE_COMPLETE); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | uint32_t CLK_get_ms(void) | ||
293 | { | ||
294 | return ms_clk; | ||
295 | } | ||
296 | |||
297 | void CLK_delay_us(uint16_t usec) | ||
298 | { | ||
299 | us_delay_done = 0; | ||
300 | |||
301 | if (TC5->COUNT16.CTRLA.bit.ENABLE) | ||
302 | { | ||
303 | TC5->COUNT16.CTRLA.bit.ENABLE = 0; | ||
304 | while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {} | ||
305 | } | ||
306 | |||
307 | if (usec < 10) usec = 0; | ||
308 | else usec -= 10; | ||
309 | |||
310 | TC5->COUNT16.CC[0].reg = usec; | ||
311 | while (TC5->COUNT16.SYNCBUSY.bit.CC0) {} | ||
312 | |||
313 | TC5->COUNT16.CTRLA.bit.ENABLE = 1; | ||
314 | while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {} | ||
315 | |||
316 | while (!us_delay_done) {} | ||
317 | } | ||
318 | |||
319 | void CLK_delay_ms(uint64_t msec) | ||
320 | { | ||
321 | msec += CLK_get_ms(); | ||
322 | while (msec > CLK_get_ms()) {} | ||
323 | } | ||
324 | |||
325 | void clk_enable_sercom_apbmask(int sercomn) | ||
326 | { | ||
327 | Mclk *pmclk = MCLK; | ||
328 | switch (sercomn) | ||
329 | { | ||
330 | case 0: | ||
331 | pmclk->APBAMASK.bit.SERCOM0_ = 1; | ||
332 | break; | ||
333 | case 1: | ||
334 | pmclk->APBAMASK.bit.SERCOM1_ = 1; | ||
335 | break; | ||
336 | case 2: | ||
337 | pmclk->APBBMASK.bit.SERCOM2_ = 1; | ||
338 | break; | ||
339 | case 3: | ||
340 | pmclk->APBBMASK.bit.SERCOM3_ = 1; | ||
341 | break; | ||
342 | default: | ||
343 | break; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | //call CLK_oscctrl_init first | ||
348 | //call CLK_set_spi_freq(CHAN_SERCOM_SPI, FREQ_SPI_DEFAULT); | ||
349 | uint32_t CLK_set_spi_freq(uint8_t sercomn, uint32_t freq) | ||
350 | { | ||
351 | DBGC(DC_CLK_SET_SPI_FREQ_BEGIN); | ||
352 | |||
353 | Gclk *pgclk = GCLK; | ||
354 | Sercom *psercom = (Sercom *)sercom_apbbase[sercomn]; | ||
355 | clk_enable_sercom_apbmask(sercomn); | ||
356 | |||
357 | //all gclk0 for now | ||
358 | pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.GEN = 0; | ||
359 | pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.CHEN = 1; | ||
360 | |||
361 | psercom->I2CM.CTRLA.bit.SWRST = 1; | ||
362 | while (psercom->I2CM.SYNCBUSY.bit.SWRST) {} | ||
363 | while (psercom->I2CM.CTRLA.bit.SWRST) {} | ||
364 | |||
365 | psercom->SPI.BAUD.reg = (uint8_t) (system_clks.freq_gclk[0]/2/freq-1); | ||
366 | system_clks.freq_spi = system_clks.freq_gclk[0]/2/(psercom->SPI.BAUD.reg+1); | ||
367 | system_clks.freq_sercom[sercomn] = system_clks.freq_spi; | ||
368 | |||
369 | DBGC(DC_CLK_SET_SPI_FREQ_COMPLETE); | ||
370 | |||
371 | return system_clks.freq_spi; | ||
372 | } | ||
373 | |||
374 | //call CLK_oscctrl_init first | ||
375 | //call CLK_set_i2c0_freq(CHAN_SERCOM_I2C0, FREQ_I2C0_DEFAULT); | ||
376 | uint32_t CLK_set_i2c0_freq(uint8_t sercomn, uint32_t freq) | ||
377 | { | ||
378 | DBGC(DC_CLK_SET_I2C0_FREQ_BEGIN); | ||
379 | |||
380 | Gclk *pgclk = GCLK; | ||
381 | Sercom *psercom = (Sercom *)sercom_apbbase[sercomn]; | ||
382 | clk_enable_sercom_apbmask(sercomn); | ||
383 | |||
384 | //all gclk0 for now | ||
385 | pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.GEN = 0; | ||
386 | pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.CHEN = 1; | ||
387 | |||
388 | psercom->I2CM.CTRLA.bit.SWRST = 1; | ||
389 | while (psercom->I2CM.SYNCBUSY.bit.SWRST) {} | ||
390 | while (psercom->I2CM.CTRLA.bit.SWRST) {} | ||
391 | |||
392 | psercom->I2CM.BAUD.bit.BAUD = (uint8_t) (system_clks.freq_gclk[0]/2/freq-1); | ||
393 | system_clks.freq_i2c0 = system_clks.freq_gclk[0]/2/(psercom->I2CM.BAUD.bit.BAUD+1); | ||
394 | system_clks.freq_sercom[sercomn] = system_clks.freq_i2c0; | ||
395 | |||
396 | DBGC(DC_CLK_SET_I2C0_FREQ_COMPLETE); | ||
397 | |||
398 | return system_clks.freq_i2c0; | ||
399 | } | ||
400 | |||
401 | //call CLK_oscctrl_init first | ||
402 | //call CLK_set_i2c1_freq(CHAN_SERCOM_I2C1, FREQ_I2C1_DEFAULT); | ||
403 | uint32_t CLK_set_i2c1_freq(uint8_t sercomn, uint32_t freq) | ||
404 | { | ||
405 | DBGC(DC_CLK_SET_I2C1_FREQ_BEGIN); | ||
406 | |||
407 | Gclk *pgclk = GCLK; | ||
408 | Sercom *psercom = (Sercom *)sercom_apbbase[sercomn]; | ||
409 | clk_enable_sercom_apbmask(sercomn); | ||
410 | |||
411 | //all gclk0 for now | ||
412 | pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.GEN = 0; | ||
413 | pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.CHEN = 1; | ||
414 | |||
415 | psercom->I2CM.CTRLA.bit.SWRST = 1; | ||
416 | while (psercom->I2CM.SYNCBUSY.bit.SWRST) {} | ||
417 | while (psercom->I2CM.CTRLA.bit.SWRST) {} | ||
418 | |||
419 | psercom->I2CM.BAUD.bit.BAUD = (uint8_t) (system_clks.freq_gclk[0]/2/freq-10); | ||
420 | system_clks.freq_i2c1 = system_clks.freq_gclk[0]/2/(psercom->I2CM.BAUD.bit.BAUD+10); | ||
421 | system_clks.freq_sercom[sercomn] = system_clks.freq_i2c1; | ||
422 | |||
423 | DBGC(DC_CLK_SET_I2C1_FREQ_COMPLETE); | ||
424 | |||
425 | return system_clks.freq_i2c1; | ||
426 | } | ||
427 | |||
428 | void CLK_init(void) | ||
429 | { | ||
430 | DBGC(DC_CLK_INIT_BEGIN); | ||
431 | |||
432 | memset((void *)&system_clks,0,sizeof(system_clks)); | ||
433 | |||
434 | CLK_oscctrl_init(); | ||
435 | CLK_enable_timebase(); | ||
436 | |||
437 | DBGC(DC_CLK_INIT_COMPLETE); | ||
438 | } | ||
439 | |||
diff --git a/tmk_core/protocol/arm_atsam/clks.h b/tmk_core/protocol/arm_atsam/clks.h new file mode 100644 index 000000000..96819bfdd --- /dev/null +++ b/tmk_core/protocol/arm_atsam/clks.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _CLKS_H_ | ||
19 | #define _CLKS_H_ | ||
20 | |||
21 | #ifndef MD_BOOTLOADER | ||
22 | |||
23 | //From keyboard | ||
24 | #include "config_led.h" | ||
25 | #include "config.h" | ||
26 | |||
27 | #endif //MD_BOOTLOADER | ||
28 | |||
29 | #define PLL_RATIO 47 //mcu frequency ((X+1)MHz) | ||
30 | #define FREQ_DFLL_DEFAULT 48000000 //DFLL frequency / usb clock | ||
31 | #define FREQ_SPI_DEFAULT 1000000 //spi to 595 shift regs | ||
32 | #define FREQ_I2C0_DEFAULT 100000 //i2c to hub | ||
33 | #define FREQ_I2C1_DEFAULT I2C_HZ //i2c to LED drivers | ||
34 | #define FREQ_TC45_DEFAULT 1000000 //1 usec resolution | ||
35 | |||
36 | //I2C1 Set ~Result PWM Time (2x Drivers) | ||
37 | // 1000000 1090000 | ||
38 | // 900000 1000000 3.82ms | ||
39 | // 800000 860000 | ||
40 | // 700000 750000 | ||
41 | // 600000 630000 | ||
42 | // 580000 615000 6.08ms | ||
43 | // 500000 522000 | ||
44 | |||
45 | #define FREQ_XOSC0 16000000 | ||
46 | |||
47 | #define CHAN_SERCOM_SPI 2 //shift regs | ||
48 | #define CHAN_SERCOM_I2C0 0 //hub | ||
49 | #define CHAN_SERCOM_I2C1 1 //led drivers | ||
50 | #define CHAN_SERCOM_UART 3 //debug util | ||
51 | |||
52 | //Generator clock channels | ||
53 | #define GEN_DPLL0 0 | ||
54 | #define GEN_OSC0 1 | ||
55 | #define GEN_TC45 2 | ||
56 | |||
57 | #define SERCOM_COUNT 5 | ||
58 | #define GCLK_COUNT 12 | ||
59 | |||
60 | typedef struct clk_s { | ||
61 | uint32_t freq_dfll; | ||
62 | uint32_t freq_dpll[2]; | ||
63 | uint32_t freq_sercom[SERCOM_COUNT]; | ||
64 | uint32_t freq_gclk[GCLK_COUNT]; | ||
65 | uint32_t freq_xosc0; | ||
66 | uint32_t freq_spi; | ||
67 | uint32_t freq_i2c0; | ||
68 | uint32_t freq_i2c1; | ||
69 | uint32_t freq_uart; | ||
70 | uint32_t freq_adc0; | ||
71 | } clk_t; | ||
72 | |||
73 | extern volatile clk_t system_clks; | ||
74 | extern volatile uint64_t ms_clk; | ||
75 | |||
76 | void CLK_oscctrl_init(void); | ||
77 | void CLK_reset_time(void); | ||
78 | uint32_t CLK_set_gclk_freq(uint8_t gclkn, uint32_t freq); | ||
79 | uint32_t CLK_enable_timebase(void); | ||
80 | uint32_t CLK_get_ms(void); | ||
81 | uint64_t CLK_get_us(void); | ||
82 | void CLK_delay_us(uint16_t usec); | ||
83 | void CLK_delay_ms(uint64_t msec); | ||
84 | |||
85 | uint32_t CLK_set_spi_freq(uint8_t sercomn, uint32_t freq); | ||
86 | uint32_t CLK_set_i2c0_freq(uint8_t sercomn, uint32_t freq); | ||
87 | uint32_t CLK_set_i2c1_freq(uint8_t sercomn, uint32_t freq); | ||
88 | void CLK_init(void); | ||
89 | |||
90 | #endif // _CLKS_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/d51_util.c b/tmk_core/protocol/arm_atsam/d51_util.c new file mode 100644 index 000000000..91b58757c --- /dev/null +++ b/tmk_core/protocol/arm_atsam/d51_util.c | |||
@@ -0,0 +1,165 @@ | |||
1 | #include "d51_util.h" | ||
2 | |||
3 | //Display unsigned 32-bit number through m15 | ||
4 | //Read as follows: 1230 = || ||| |||| | (note always ending toggle) | ||
5 | void m15_print(uint32_t x) | ||
6 | { | ||
7 | int8_t t; | ||
8 | uint32_t n; | ||
9 | uint32_t p, p2; | ||
10 | |||
11 | if (x < 10) t = 0; | ||
12 | else if (x < 100) t = 1; | ||
13 | else if (x < 1000) t = 2; | ||
14 | else if (x < 10000) t = 3; | ||
15 | else if (x < 100000) t = 4; | ||
16 | else if (x < 1000000) t = 5; | ||
17 | else if (x < 10000000) t = 6; | ||
18 | else if (x < 100000000) t = 7; | ||
19 | else if (x < 1000000000) t = 8; | ||
20 | else t = 9; | ||
21 | |||
22 | while (t >= 0) | ||
23 | { | ||
24 | p2 = t; | ||
25 | p = 1; | ||
26 | while (p2--) p *= 10; | ||
27 | n = x / p; | ||
28 | x -= n * p; | ||
29 | while (n > 0) | ||
30 | { | ||
31 | m15_on; | ||
32 | n--; | ||
33 | m15_off; | ||
34 | } | ||
35 | //Will always end with an extra toggle | ||
36 | m15_on; | ||
37 | t--; | ||
38 | m15_off; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | //Display unsigned 32-bit number through debug led | ||
43 | //Read as follows: 1230 = [*] [* *] [* * *] [**] (note zero is fast double flash) | ||
44 | #define DLED_ONTIME 600000 | ||
45 | #define DLED_PAUSE 1000000 | ||
46 | volatile uint32_t w; | ||
47 | void dled_print(uint32_t x, uint8_t long_pause) | ||
48 | { | ||
49 | int8_t t; | ||
50 | uint32_t n; | ||
51 | uint32_t p, p2; | ||
52 | |||
53 | if (x < 10) t = 0; | ||
54 | else if (x < 100) t = 1; | ||
55 | else if (x < 1000) t = 2; | ||
56 | else if (x < 10000) t = 3; | ||
57 | else if (x < 100000) t = 4; | ||
58 | else if (x < 1000000) t = 5; | ||
59 | else if (x < 10000000) t = 6; | ||
60 | else if (x < 100000000) t = 7; | ||
61 | else if (x < 1000000000) t = 8; | ||
62 | else t = 9; | ||
63 | |||
64 | while (t >= 0) | ||
65 | { | ||
66 | p2 = t; | ||
67 | p = 1; | ||
68 | while (p2--) p *= 10; | ||
69 | n = x / p; | ||
70 | x -= n * p; | ||
71 | if (!n) | ||
72 | { | ||
73 | led_on; | ||
74 | for (w = DLED_ONTIME / 4; w; w--); | ||
75 | led_off; | ||
76 | for (w = DLED_ONTIME / 4; w; w--); | ||
77 | led_on; | ||
78 | for (w = DLED_ONTIME / 4; w; w--); | ||
79 | led_off; | ||
80 | for (w = DLED_ONTIME / 4; w; w--); | ||
81 | n--; | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | while (n > 0) | ||
86 | { | ||
87 | led_on; | ||
88 | for (w = DLED_ONTIME; w; w--); | ||
89 | led_off; | ||
90 | for (w = DLED_ONTIME / 2; w; w--); | ||
91 | n--; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | for (w = DLED_PAUSE; w; w--); | ||
96 | t--; | ||
97 | } | ||
98 | |||
99 | if (long_pause) | ||
100 | { | ||
101 | for (w = DLED_PAUSE * 4; w; w--); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | #ifdef DEBUG_BOOT_TRACING | ||
106 | |||
107 | volatile uint32_t debug_code; | ||
108 | |||
109 | void EIC_15_Handler() | ||
110 | { | ||
111 | //This is only for non-functional keyboard troubleshooting and should be disabled after boot | ||
112 | //Intention is to lock up the keyboard here with repeating debug led code | ||
113 | while (1) | ||
114 | { | ||
115 | dled_print(debug_code, 1); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | void debug_code_init(void) | ||
120 | { | ||
121 | DBGC(DC_UNSET); | ||
122 | |||
123 | //Configure Ports for EIC on PB31 | ||
124 | PORT->Group[1].DIRCLR.reg = 1 << 31; //Input | ||
125 | PORT->Group[1].OUTSET.reg = 1 << 31; //High | ||
126 | PORT->Group[1].PINCFG[31].bit.INEN = 1; //Input Enable | ||
127 | PORT->Group[1].PINCFG[31].bit.PULLEN = 1; //Pull Enable | ||
128 | PORT->Group[1].PINCFG[31].bit.PMUXEN = 1; //Mux Enable | ||
129 | PORT->Group[1].PMUX[15].bit.PMUXO = 0; //Mux A | ||
130 | |||
131 | //Enable CLK_EIC_APB | ||
132 | MCLK->APBAMASK.bit.EIC_ = 1; | ||
133 | |||
134 | //Configure EIC | ||
135 | EIC->CTRLA.bit.SWRST = 1; | ||
136 | while (EIC->SYNCBUSY.bit.SWRST) {} | ||
137 | EIC->ASYNCH.reg = 1 << 15; | ||
138 | EIC->INTENSET.reg = 1 << 15; | ||
139 | EIC->CONFIG[1].bit.SENSE7 = 2; | ||
140 | EIC->CTRLA.bit.ENABLE = 1; | ||
141 | while (EIC->SYNCBUSY.bit.ENABLE) {} | ||
142 | |||
143 | //Enable EIC IRQ | ||
144 | NVIC_EnableIRQ(EIC_15_IRQn); | ||
145 | } | ||
146 | |||
147 | void debug_code_disable(void) | ||
148 | { | ||
149 | //Disable EIC IRQ | ||
150 | NVIC_DisableIRQ(EIC_15_IRQn); | ||
151 | |||
152 | //Disable EIC | ||
153 | EIC->CTRLA.bit.ENABLE = 0; | ||
154 | while (EIC->SYNCBUSY.bit.ENABLE) {} | ||
155 | |||
156 | //Disable CLK_EIC_APB | ||
157 | MCLK->APBAMASK.bit.EIC_ = 0; | ||
158 | } | ||
159 | |||
160 | #else | ||
161 | |||
162 | void debug_code_init(void) {} | ||
163 | void debug_code_disable(void) {} | ||
164 | |||
165 | #endif //DEBUG_BOOT_TRACING | ||
diff --git a/tmk_core/protocol/arm_atsam/d51_util.h b/tmk_core/protocol/arm_atsam/d51_util.h new file mode 100644 index 000000000..465889c7c --- /dev/null +++ b/tmk_core/protocol/arm_atsam/d51_util.h | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _D51_UTIL_H_ | ||
19 | #define _D51_UTIL_H_ | ||
20 | |||
21 | #include "samd51j18a.h" | ||
22 | |||
23 | //TODO: PS: Should bring these ports out to keyboard level configuration | ||
24 | |||
25 | //Debug LED PA27 | ||
26 | #define led_ena REG_PORT_DIRSET0 = 0x08000000 //PA27 Output | ||
27 | #define led_on REG_PORT_OUTSET0 = 0x08000000 //PA27 High | ||
28 | #define led_off REG_PORT_OUTCLR0 = 0x08000000 //PA27 Low | ||
29 | |||
30 | //Debug Port PB30 | ||
31 | #define m15_ena REG_PORT_DIRSET1 = 0x40000000 //PB30 Output | ||
32 | #define m15_on REG_PORT_OUTSET1 = 0x40000000 //PB30 High | ||
33 | #define m15_off REG_PORT_OUTCLR1 = 0x40000000 //PB30 Low | ||
34 | |||
35 | #define m15_loop(M15X) {uint8_t M15L=M15X; while(M15L--){m15_on;CLK_delay_us(1);m15_off;}} | ||
36 | |||
37 | void m15_print(uint32_t x); | ||
38 | void dled_print(uint32_t x, uint8_t long_pause); | ||
39 | |||
40 | void debug_code_init(void); | ||
41 | void debug_code_disable(void); | ||
42 | |||
43 | #ifdef DEBUG_BOOT_TRACING | ||
44 | |||
45 | #define DBGC(n) debug_code = n | ||
46 | |||
47 | extern volatile uint32_t debug_code; | ||
48 | |||
49 | enum debug_code_list { | ||
50 | DC_UNSET = 0, | ||
51 | DC_CLK_INIT_BEGIN, | ||
52 | DC_CLK_INIT_COMPLETE, | ||
53 | DC_CLK_SET_I2C1_FREQ_BEGIN, | ||
54 | DC_CLK_SET_I2C1_FREQ_COMPLETE, | ||
55 | DC_CLK_SET_I2C0_FREQ_BEGIN, | ||
56 | DC_CLK_SET_I2C0_FREQ_COMPLETE, | ||
57 | DC_CLK_SET_SPI_FREQ_BEGIN, | ||
58 | DC_CLK_SET_SPI_FREQ_COMPLETE, | ||
59 | DC_CLK_ENABLE_TIMEBASE_BEGIN, | ||
60 | DC_CLK_ENABLE_TIMEBASE_SYNC_ENABLE, | ||
61 | DC_CLK_ENABLE_TIMEBASE_SYNC_SWRST_1, | ||
62 | DC_CLK_ENABLE_TIMEBASE_SYNC_SWRST_2, | ||
63 | DC_CLK_ENABLE_TIMEBASE_TC4_BEGIN, | ||
64 | DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_DISABLE, | ||
65 | DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_1, | ||
66 | DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_2, | ||
67 | DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CLTRB, | ||
68 | DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CC0, | ||
69 | DC_CLK_ENABLE_TIMEBASE_TC4_COMPLETE, | ||
70 | DC_CLK_ENABLE_TIMEBASE_TC5_BEGIN, | ||
71 | DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_DISABLE, | ||
72 | DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_1, | ||
73 | DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_2, | ||
74 | DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_CLTRB, | ||
75 | DC_CLK_ENABLE_TIMEBASE_TC5_COMPLETE, | ||
76 | DC_CLK_ENABLE_TIMEBASE_TC0_BEGIN, | ||
77 | DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_DISABLE, | ||
78 | DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_1, | ||
79 | DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_2, | ||
80 | DC_CLK_ENABLE_TIMEBASE_TC0_COMPLETE, | ||
81 | DC_CLK_ENABLE_TIMEBASE_EVSYS_BEGIN, | ||
82 | DC_CLK_ENABLE_TIMEBASE_EVSYS_COMPLETE, | ||
83 | DC_CLK_ENABLE_TIMEBASE_COMPLETE, | ||
84 | DC_CLK_SET_GCLK_FREQ_BEGIN, | ||
85 | DC_CLK_SET_GCLK_FREQ_SYNC_1, | ||
86 | DC_CLK_SET_GCLK_FREQ_SYNC_2, | ||
87 | DC_CLK_SET_GCLK_FREQ_SYNC_3, | ||
88 | DC_CLK_SET_GCLK_FREQ_SYNC_4, | ||
89 | DC_CLK_SET_GCLK_FREQ_SYNC_5, | ||
90 | DC_CLK_SET_GCLK_FREQ_COMPLETE, | ||
91 | DC_CLK_INIT_OSC_BEGIN, | ||
92 | DC_CLK_INIT_OSC_SYNC_1, | ||
93 | DC_CLK_INIT_OSC_SYNC_2, | ||
94 | DC_CLK_INIT_OSC_SYNC_3, | ||
95 | DC_CLK_INIT_OSC_SYNC_4, | ||
96 | DC_CLK_INIT_OSC_SYNC_5, | ||
97 | DC_CLK_INIT_OSC_COMPLETE, | ||
98 | DC_CLK_RESET_TIME_BEGIN, | ||
99 | DC_CLK_RESET_TIME_COMPLETE, | ||
100 | DC_CLK_OSC_INIT_BEGIN, | ||
101 | DC_CLK_OSC_INIT_XOSC0_SYNC, | ||
102 | DC_CLK_OSC_INIT_DPLL_SYNC_DISABLE, | ||
103 | DC_CLK_OSC_INIT_DPLL_SYNC_RATIO, | ||
104 | DC_CLK_OSC_INIT_DPLL_SYNC_ENABLE, | ||
105 | DC_CLK_OSC_INIT_DPLL_WAIT_LOCK, | ||
106 | DC_CLK_OSC_INIT_DPLL_WAIT_CLKRDY, | ||
107 | DC_CLK_OSC_INIT_GCLK_SYNC_GENCTRL0, | ||
108 | DC_CLK_OSC_INIT_COMPLETE, | ||
109 | DC_SPI_INIT_BEGIN, | ||
110 | DC_SPI_WRITE_DRE, | ||
111 | DC_SPI_WRITE_TXC_1, | ||
112 | DC_SPI_WRITE_TXC_2, | ||
113 | DC_SPI_SYNC_ENABLING, | ||
114 | DC_SPI_INIT_COMPLETE, | ||
115 | DC_PORT_DETECT_INIT_BEGIN, | ||
116 | DC_PORT_DETECT_INIT_FAILED, | ||
117 | DC_PORT_DETECT_INIT_COMPLETE, | ||
118 | DC_USB_RESET_BEGIN, | ||
119 | DC_USB_RESET_COMPLETE, | ||
120 | DC_USB_SET_HOST_BY_VOLTAGE_BEGIN, | ||
121 | DC_USB_SET_HOST_5V_LOW_WAITING, | ||
122 | DC_USB_SET_HOST_BY_VOLTAGE_COMPLETE, | ||
123 | DC_USB_CONFIGURE_BEGIN, | ||
124 | DC_USB_CONFIGURE_GET_SERIAL, | ||
125 | DC_USB_CONFIGURE_COMPLETE, | ||
126 | DC_USB_WRITE2422_BLOCK_BEGIN, | ||
127 | DC_USB_WRITE2422_BLOCK_SYNC_SYSOP, | ||
128 | DC_USB_WRITE2422_BLOCK_COMPLETE, | ||
129 | DC_ADC0_CLOCK_INIT_BEGIN, | ||
130 | DC_ADC0_CLOCK_INIT_COMPLETE, | ||
131 | DC_ADC0_INIT_BEGIN, | ||
132 | DC_ADC0_SWRST_SYNCING_1, | ||
133 | DC_ADC0_SWRST_SYNCING_2, | ||
134 | DC_ADC0_AVGCTRL_SYNCING_1, | ||
135 | DC_ADC0_AVGCTRL_SYNCING_2, | ||
136 | DC_ADC0_SAMPCTRL_SYNCING_1, | ||
137 | DC_ADC0_ENABLE_SYNCING_1, | ||
138 | DC_ADC0_INIT_COMPLETE, | ||
139 | DC_I2C0_INIT_BEGIN, | ||
140 | DC_I2C0_INIT_SYNC_ENABLING, | ||
141 | DC_I2C0_INIT_SYNC_SYSOP, | ||
142 | DC_I2C0_INIT_WAIT_IDLE, | ||
143 | DC_I2C0_INIT_COMPLETE, | ||
144 | DC_I2C1_INIT_BEGIN, | ||
145 | DC_I2C1_INIT_SYNC_ENABLING, | ||
146 | DC_I2C1_INIT_SYNC_SYSOP, | ||
147 | DC_I2C1_INIT_WAIT_IDLE, | ||
148 | DC_I2C1_INIT_COMPLETE, | ||
149 | DC_I2C3733_INIT_CONTROL_BEGIN, | ||
150 | DC_I2C3733_INIT_CONTROL_COMPLETE, | ||
151 | DC_I2C3733_INIT_DRIVERS_BEGIN, | ||
152 | DC_I2C3733_INIT_DRIVERS_COMPLETE, | ||
153 | DC_I2C_DMAC_LED_INIT_BEGIN, | ||
154 | DC_I2C_DMAC_LED_INIT_COMPLETE, | ||
155 | DC_I2C3733_CONTROL_SET_BEGIN, | ||
156 | DC_I2C3733_CONTROL_SET_COMPLETE, | ||
157 | DC_LED_MATRIX_INIT_BEGIN, | ||
158 | DC_LED_MATRIX_INIT_COMPLETE, | ||
159 | DC_USB2422_INIT_BEGIN, | ||
160 | DC_USB2422_INIT_WAIT_5V_LOW, | ||
161 | DC_USB2422_INIT_OSC_SYNC_DISABLING, | ||
162 | DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_1, | ||
163 | DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_2, | ||
164 | DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_3, | ||
165 | DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_4, | ||
166 | DC_USB2422_INIT_OSC_SYNC_DFLLMUL, | ||
167 | DC_USB2422_INIT_OSC_SYNC_ENABLING, | ||
168 | DC_USB2422_INIT_USB_SYNC_SWRST, | ||
169 | DC_USB2422_INIT_USB_WAIT_SWRST, | ||
170 | DC_USB2422_INIT_USB_SYNC_ENABLING, | ||
171 | DC_USB2422_INIT_COMPLETE, | ||
172 | DC_MAIN_UDC_START_BEGIN, | ||
173 | DC_MAIN_UDC_START_COMPLETE, | ||
174 | DC_MAIN_CDC_INIT_BEGIN, | ||
175 | DC_MAIN_CDC_INIT_COMPLETE, | ||
176 | /* Never change the order of error codes! Only add codes to end! */ | ||
177 | }; | ||
178 | |||
179 | #else | ||
180 | |||
181 | #define DBGC(n) {} | ||
182 | |||
183 | #endif //DEBUG_BOOT_TRACING | ||
184 | |||
185 | #endif //_D51_UTIL_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/i2c_master.c b/tmk_core/protocol/arm_atsam/i2c_master.c new file mode 100644 index 000000000..bbe909e9b --- /dev/null +++ b/tmk_core/protocol/arm_atsam/i2c_master.c | |||
@@ -0,0 +1,585 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "arm_atsam_protocol.h" | ||
19 | |||
20 | #ifndef MD_BOOTLOADER | ||
21 | |||
22 | #include <string.h> | ||
23 | |||
24 | //From keyboard | ||
25 | #include "config.h" | ||
26 | #include "config_led.h" | ||
27 | #include "matrix.h" | ||
28 | |||
29 | #define I2C_LED_USE_DMA 1 //Set 1 to use background DMA transfers for leds, Set 0 to use inline software transfers | ||
30 | |||
31 | static uint8_t i2c_led_q[I2C_Q_SIZE]; //I2C queue circular buffer | ||
32 | static uint8_t i2c_led_q_s; //Start of circular buffer | ||
33 | static uint8_t i2c_led_q_e; //End of circular buffer | ||
34 | static uint8_t i2c_led_q_full; //Queue full counter for reset | ||
35 | |||
36 | static uint8_t dma_sendbuf[I2C_DMA_MAX_SEND]; //Data being written to I2C | ||
37 | |||
38 | volatile uint8_t i2c_led_q_running; | ||
39 | |||
40 | #endif //MD_BOOTLOADER | ||
41 | |||
42 | void i2c0_init(void) | ||
43 | { | ||
44 | DBGC(DC_I2C0_INIT_BEGIN); | ||
45 | |||
46 | CLK_set_i2c0_freq(CHAN_SERCOM_I2C0, FREQ_I2C0_DEFAULT); | ||
47 | |||
48 | //MCU | ||
49 | PORT->Group[0].PMUX[4].bit.PMUXE = 2; | ||
50 | PORT->Group[0].PMUX[4].bit.PMUXO = 2; | ||
51 | PORT->Group[0].PINCFG[8].bit.PMUXEN = 1; | ||
52 | PORT->Group[0].PINCFG[9].bit.PMUXEN = 1; | ||
53 | |||
54 | //I2C | ||
55 | //Note: SW Reset handled in CLK_set_i2c0_freq clks.c | ||
56 | |||
57 | SERCOM0->I2CM.CTRLA.bit.MODE = 5; //Set master mode | ||
58 | |||
59 | SERCOM0->I2CM.CTRLA.bit.SPEED = 0; //Set to 1 for Fast-mode Plus (FM+) up to 1 MHz | ||
60 | SERCOM0->I2CM.CTRLA.bit.RUNSTDBY = 1; //Enabled | ||
61 | |||
62 | SERCOM0->I2CM.CTRLA.bit.ENABLE = 1; //Enable the device | ||
63 | while (SERCOM0->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C0_INIT_SYNC_ENABLING); } //Wait for SYNCBUSY.ENABLE to clear | ||
64 | |||
65 | SERCOM0->I2CM.STATUS.bit.BUSSTATE = 1; //Force into IDLE state | ||
66 | while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C0_INIT_SYNC_SYSOP); } | ||
67 | while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C0_INIT_WAIT_IDLE); } //Wait while not idle | ||
68 | |||
69 | DBGC(DC_I2C0_INIT_COMPLETE); | ||
70 | } | ||
71 | |||
72 | uint8_t i2c0_start(uint8_t address) | ||
73 | { | ||
74 | SERCOM0->I2CM.ADDR.bit.ADDR = address; | ||
75 | while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) {} | ||
76 | while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {} | ||
77 | while (SERCOM0->I2CM.STATUS.bit.RXNACK) {} | ||
78 | |||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | uint8_t i2c0_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout) | ||
83 | { | ||
84 | if (!length) return 0; | ||
85 | |||
86 | i2c0_start(address); | ||
87 | |||
88 | while (length) | ||
89 | { | ||
90 | SERCOM0->I2CM.DATA.bit.DATA = *data; | ||
91 | while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {} | ||
92 | while (SERCOM0->I2CM.STATUS.bit.RXNACK) {} | ||
93 | |||
94 | data++; | ||
95 | length--; | ||
96 | } | ||
97 | |||
98 | i2c0_stop(); | ||
99 | |||
100 | return 1; | ||
101 | } | ||
102 | |||
103 | void i2c0_stop(void) | ||
104 | { | ||
105 | if (SERCOM0->I2CM.STATUS.bit.CLKHOLD || SERCOM0->I2CM.INTFLAG.bit.MB == 1 || SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1) | ||
106 | { | ||
107 | SERCOM0->I2CM.CTRLB.bit.CMD = 3; | ||
108 | while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP); | ||
109 | while (SERCOM0->I2CM.STATUS.bit.CLKHOLD); | ||
110 | while (SERCOM0->I2CM.INTFLAG.bit.MB); | ||
111 | while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | #ifndef MD_BOOTLOADER | ||
116 | void i2c1_init(void) | ||
117 | { | ||
118 | DBGC(DC_I2C1_INIT_BEGIN); | ||
119 | |||
120 | CLK_set_i2c1_freq(CHAN_SERCOM_I2C1, FREQ_I2C1_DEFAULT); | ||
121 | |||
122 | /* MCU */ | ||
123 | PORT->Group[0].PMUX[8].bit.PMUXE = 2; | ||
124 | PORT->Group[0].PMUX[8].bit.PMUXO = 2; | ||
125 | PORT->Group[0].PINCFG[16].bit.PMUXEN = 1; | ||
126 | PORT->Group[0].PINCFG[17].bit.PMUXEN = 1; | ||
127 | |||
128 | /* I2C */ | ||
129 | //Note: SW Reset handled in CLK_set_i2c1_freq clks.c | ||
130 | |||
131 | SERCOM1->I2CM.CTRLA.bit.MODE = 5; //MODE: Set master mode (No sync) | ||
132 | SERCOM1->I2CM.CTRLA.bit.SPEED = 1; //SPEED: Fm+ up to 1MHz (No sync) | ||
133 | SERCOM1->I2CM.CTRLA.bit.RUNSTDBY = 1; //RUNSTBY: Enabled (No sync) | ||
134 | |||
135 | SERCOM1->I2CM.CTRLB.bit.SMEN = 1; //SMEN: Smart mode enabled (For DMA)(No sync) | ||
136 | |||
137 | NVIC_EnableIRQ(SERCOM1_0_IRQn); | ||
138 | SERCOM1->I2CM.INTENSET.bit.ERROR = 1; | ||
139 | |||
140 | SERCOM1->I2CM.CTRLA.bit.ENABLE = 1; //ENABLE: Enable the device (sync SYNCBUSY.ENABLE) | ||
141 | while (SERCOM1->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C1_INIT_SYNC_ENABLING); } //Wait for SYNCBUSY.ENABLE to clear | ||
142 | |||
143 | SERCOM1->I2CM.STATUS.bit.BUSSTATE = 1; //BUSSTATE: Force into IDLE state (sync SYNCBUSY.SYSOP) | ||
144 | while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C1_INIT_SYNC_SYSOP); } | ||
145 | while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C1_INIT_WAIT_IDLE); } //Wait while not idle | ||
146 | |||
147 | DBGC(DC_I2C1_INIT_COMPLETE); | ||
148 | } | ||
149 | |||
150 | uint8_t i2c1_start(uint8_t address) | ||
151 | { | ||
152 | SERCOM1->I2CM.ADDR.bit.ADDR = address; | ||
153 | while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) {} | ||
154 | while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {} | ||
155 | while (SERCOM1->I2CM.STATUS.bit.RXNACK) {} | ||
156 | |||
157 | return 1; | ||
158 | } | ||
159 | |||
160 | uint8_t i2c1_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout) | ||
161 | { | ||
162 | if (!length) return 0; | ||
163 | |||
164 | i2c1_start(address); | ||
165 | |||
166 | while (length) | ||
167 | { | ||
168 | SERCOM1->I2CM.DATA.bit.DATA = *data; | ||
169 | while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {} | ||
170 | while (SERCOM1->I2CM.STATUS.bit.RXNACK) {} | ||
171 | |||
172 | data++; | ||
173 | length--; | ||
174 | } | ||
175 | |||
176 | i2c1_stop(); | ||
177 | |||
178 | return 1; | ||
179 | } | ||
180 | |||
181 | void i2c1_stop(void) | ||
182 | { | ||
183 | if (SERCOM1->I2CM.STATUS.bit.CLKHOLD || SERCOM1->I2CM.INTFLAG.bit.MB == 1 || SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1) | ||
184 | { | ||
185 | SERCOM1->I2CM.CTRLB.bit.CMD = 3; | ||
186 | while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP); | ||
187 | while (SERCOM1->I2CM.STATUS.bit.CLKHOLD); | ||
188 | while (SERCOM1->I2CM.INTFLAG.bit.MB); | ||
189 | while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | void i2c_led_send_CRWL(uint8_t drvid) | ||
194 | { | ||
195 | uint8_t i2cdata[] = { ISSI3733_CMDRWL, ISSI3733_CMDRWL_WRITE_ENABLE_ONCE }; | ||
196 | i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0); | ||
197 | } | ||
198 | |||
199 | void i2c_led_select_page(uint8_t drvid, uint8_t pageno) | ||
200 | { | ||
201 | uint8_t i2cdata[] = { ISSI3733_CMDR, pageno }; | ||
202 | i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0); | ||
203 | } | ||
204 | |||
205 | void i2c_led_send_GCR(uint8_t drvid) | ||
206 | { | ||
207 | uint8_t i2cdata[] = { ISSI3733_GCCR, 0x00 }; | ||
208 | |||
209 | if (gcr_actual > LED_GCR_MAX) gcr_actual = LED_GCR_MAX; | ||
210 | i2cdata[1] = gcr_actual; | ||
211 | |||
212 | i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0); | ||
213 | } | ||
214 | |||
215 | void i2c_led_send_onoff(uint8_t drvid) | ||
216 | { | ||
217 | #if I2C_LED_USE_DMA != 1 | ||
218 | if (!i2c_led_q_running) | ||
219 | { | ||
220 | #endif | ||
221 | i2c_led_send_CRWL(drvid); | ||
222 | i2c_led_select_page(drvid, 0); | ||
223 | #if I2C_LED_USE_DMA != 1 | ||
224 | } | ||
225 | #endif | ||
226 | |||
227 | *issidrv[drvid].onoff = 0; //Force start location offset to zero | ||
228 | i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].onoff, ISSI3733_PG0_BYTES, 0); | ||
229 | } | ||
230 | |||
231 | void i2c_led_send_mode_op_gcr(uint8_t drvid, uint8_t mode, uint8_t operation) | ||
232 | { | ||
233 | uint8_t i2cdata[] = { ISSI3733_CR, mode | operation, gcr_actual}; | ||
234 | i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0); | ||
235 | } | ||
236 | |||
237 | void i2c_led_send_pur_pdr(uint8_t drvid, uint8_t pur, uint8_t pdr) | ||
238 | { | ||
239 | uint8_t i2cdata[] = { ISSI3733_SWYR_PUR, pur, pdr }; | ||
240 | |||
241 | i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0); | ||
242 | } | ||
243 | |||
244 | void i2c_led_send_pwm(uint8_t drvid) | ||
245 | { | ||
246 | #if I2C_LED_USE_DMA != 1 | ||
247 | if (!i2c_led_q_running) | ||
248 | { | ||
249 | #endif | ||
250 | i2c_led_send_CRWL(drvid); | ||
251 | i2c_led_select_page(drvid, 0); | ||
252 | #if I2C_LED_USE_DMA != 1 | ||
253 | } | ||
254 | #endif | ||
255 | |||
256 | *issidrv[drvid].pwm = 0; //Force start location offset to zero | ||
257 | i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].pwm, ISSI3733_PG1_BYTES, 0); | ||
258 | } | ||
259 | |||
260 | uint8_t I2C3733_Init_Control(void) | ||
261 | { | ||
262 | DBGC(DC_I2C3733_INIT_CONTROL_BEGIN); | ||
263 | |||
264 | srdata.bit.SDB_N = 1; | ||
265 | SPI_WriteSRData(); | ||
266 | |||
267 | CLK_delay_ms(1); | ||
268 | |||
269 | srdata.bit.IRST = 0; | ||
270 | SPI_WriteSRData(); | ||
271 | |||
272 | CLK_delay_ms(1); | ||
273 | |||
274 | DBGC(DC_I2C3733_INIT_CONTROL_COMPLETE); | ||
275 | |||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | uint8_t I2C3733_Init_Drivers(void) | ||
280 | { | ||
281 | DBGC(DC_I2C3733_INIT_DRIVERS_BEGIN); | ||
282 | |||
283 | gcr_actual = ISSI3733_GCR_DEFAULT; | ||
284 | gcr_actual_last = gcr_actual; | ||
285 | |||
286 | if (gcr_actual > LED_GCR_MAX) gcr_actual = LED_GCR_MAX; | ||
287 | gcr_desired = gcr_actual; | ||
288 | |||
289 | //Set up master device | ||
290 | i2c_led_send_CRWL(0); | ||
291 | i2c_led_select_page(0, 3); | ||
292 | i2c_led_send_mode_op_gcr(0, ISSI3733_CR_SYNC_MASTER, ISSI3733_CR_SSD_NORMAL); | ||
293 | |||
294 | //Set up slave device | ||
295 | i2c_led_send_CRWL(1); | ||
296 | i2c_led_select_page(1, 3); | ||
297 | i2c_led_send_mode_op_gcr(1, ISSI3733_CR_SYNC_SLAVE, ISSI3733_CR_SSD_NORMAL); | ||
298 | |||
299 | i2c_led_send_CRWL(0); | ||
300 | i2c_led_select_page(0, 3); | ||
301 | i2c_led_send_pur_pdr(0, ISSI3733_SWYR_PUR_8000, ISSI3733_CSXR_PDR_8000); | ||
302 | |||
303 | i2c_led_send_CRWL(1); | ||
304 | i2c_led_select_page(1, 3); | ||
305 | i2c_led_send_pur_pdr(1, ISSI3733_SWYR_PUR_8000, ISSI3733_CSXR_PDR_8000); | ||
306 | |||
307 | DBGC(DC_I2C3733_INIT_DRIVERS_COMPLETE); | ||
308 | |||
309 | return 1; | ||
310 | } | ||
311 | |||
312 | void I2C_DMAC_LED_Init(void) | ||
313 | { | ||
314 | Dmac *dmac = DMAC; | ||
315 | |||
316 | DBGC(DC_I2C_DMAC_LED_INIT_BEGIN); | ||
317 | |||
318 | //Disable device | ||
319 | dmac->CTRL.bit.DMAENABLE = 0; //Disable DMAC | ||
320 | while (dmac->CTRL.bit.DMAENABLE) {} //Wait for disabled state in case of ongoing transfers | ||
321 | dmac->CTRL.bit.SWRST = 1; //Software Reset DMAC | ||
322 | while (dmac->CTRL.bit.SWRST) {} //Wait for software reset to complete | ||
323 | |||
324 | //Configure device | ||
325 | dmac->BASEADDR.reg = (uint32_t)&dmac_desc; //Set descriptor base address | ||
326 | dmac->WRBADDR.reg = (uint32_t)&dmac_desc_wb; //Set descriptor write back address | ||
327 | dmac->CTRL.reg |= 0x0f00; //Handle all priorities (LVL0-3) | ||
328 | |||
329 | //Disable channel | ||
330 | dmac->Channel[0].CHCTRLA.bit.ENABLE = 0; //Disable the channel | ||
331 | while (dmac->Channel[0].CHCTRLA.bit.ENABLE) {} //Wait for disabled state in case of ongoing transfers | ||
332 | dmac->Channel[0].CHCTRLA.bit.SWRST = 1; //Software Reset the channel | ||
333 | while (dmac->Channel[0].CHCTRLA.bit.SWRST) {} //Wait for software reset to complete | ||
334 | |||
335 | //Configure channel | ||
336 | dmac->Channel[0].CHCTRLA.bit.THRESHOLD = 0; //1BEAT | ||
337 | dmac->Channel[0].CHCTRLA.bit.BURSTLEN = 0; //SINGLE | ||
338 | dmac->Channel[0].CHCTRLA.bit.TRIGACT = 2; //BURST | ||
339 | dmac->Channel[0].CHCTRLA.bit.TRIGSRC = SERCOM1_DMAC_ID_TX; //Trigger source | ||
340 | dmac->Channel[0].CHCTRLA.bit.RUNSTDBY = 1; //Run in standby | ||
341 | |||
342 | NVIC_EnableIRQ(DMAC_0_IRQn); | ||
343 | dmac->Channel[0].CHINTENSET.bit.TCMPL = 1; | ||
344 | dmac->Channel[0].CHINTENSET.bit.TERR = 1; | ||
345 | |||
346 | //Enable device | ||
347 | dmac->CTRL.bit.DMAENABLE = 1; //Enable DMAC | ||
348 | while (dmac->CTRL.bit.DMAENABLE == 0) {} //Wait for enable state | ||
349 | |||
350 | DBGC(DC_I2C_DMAC_LED_INIT_COMPLETE); | ||
351 | } | ||
352 | |||
353 | //state = 1 enable | ||
354 | //state = 0 disable | ||
355 | void I2C3733_Control_Set(uint8_t state) | ||
356 | { | ||
357 | DBGC(DC_I2C3733_CONTROL_SET_BEGIN); | ||
358 | |||
359 | srdata.bit.SDB_N = (state == 1 ? 1 : 0); | ||
360 | SPI_WriteSRData(); | ||
361 | |||
362 | DBGC(DC_I2C3733_CONTROL_SET_COMPLETE); | ||
363 | } | ||
364 | |||
365 | void i2c_led_desc_defaults(void) | ||
366 | { | ||
367 | dmac_desc.BTCTRL.bit.STEPSIZE = 0; //SRCINC used in favor for auto 1 inc | ||
368 | dmac_desc.BTCTRL.bit.STEPSEL = 0; //SRCINC used in favor for auto 1 inc | ||
369 | dmac_desc.BTCTRL.bit.DSTINC = 0; //The Destination Address Increment is disabled | ||
370 | dmac_desc.BTCTRL.bit.SRCINC = 1; //The Source Address Increment is enabled (Inc by 1) | ||
371 | dmac_desc.BTCTRL.bit.BEATSIZE = 0; //8-bit bus transfer | ||
372 | dmac_desc.BTCTRL.bit.BLOCKACT = 0; //Channel will be disabled if it is the last block transfer in the transaction | ||
373 | dmac_desc.BTCTRL.bit.EVOSEL = 0; //Event generation disabled | ||
374 | dmac_desc.BTCTRL.bit.VALID = 1; //Set dmac valid | ||
375 | } | ||
376 | |||
377 | void i2c_led_prepare_send_dma(uint8_t *data, uint8_t len) | ||
378 | { | ||
379 | i2c_led_desc_defaults(); | ||
380 | |||
381 | dmac_desc.BTCNT.reg = len; | ||
382 | dmac_desc.SRCADDR.reg = (uint32_t)data + len; | ||
383 | dmac_desc.DSTADDR.reg = (uint32_t)&SERCOM1->I2CM.DATA.reg; | ||
384 | dmac_desc.DESCADDR.reg = 0; | ||
385 | } | ||
386 | |||
387 | void i2c_led_begin_dma(uint8_t drvid) | ||
388 | { | ||
389 | DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1; //Enable the channel | ||
390 | |||
391 | SERCOM1->I2CM.ADDR.reg = (dmac_desc.BTCNT.reg << 16) | 0x2000 | issidrv[drvid].addr; //Begin transfer | ||
392 | } | ||
393 | |||
394 | void i2c_led_send_CRWL_dma(uint8_t drvid) | ||
395 | { | ||
396 | *(dma_sendbuf+0) = ISSI3733_CMDRWL; | ||
397 | *(dma_sendbuf+1) = ISSI3733_CMDRWL_WRITE_ENABLE_ONCE; | ||
398 | i2c_led_prepare_send_dma(dma_sendbuf, 2); | ||
399 | |||
400 | i2c_led_begin_dma(drvid); | ||
401 | } | ||
402 | |||
403 | void i2c_led_select_page_dma(uint8_t drvid, uint8_t pageno) | ||
404 | { | ||
405 | *(dma_sendbuf+0) = ISSI3733_CMDR; | ||
406 | *(dma_sendbuf+1) = pageno; | ||
407 | i2c_led_prepare_send_dma(dma_sendbuf, 2); | ||
408 | |||
409 | i2c_led_begin_dma(drvid); | ||
410 | } | ||
411 | |||
412 | void i2c_led_send_GCR_dma(uint8_t drvid) | ||
413 | { | ||
414 | *(dma_sendbuf+0) = ISSI3733_GCCR; | ||
415 | *(dma_sendbuf+1) = gcr_actual; | ||
416 | i2c_led_prepare_send_dma(dma_sendbuf, 2); | ||
417 | |||
418 | i2c_led_begin_dma(drvid); | ||
419 | } | ||
420 | |||
421 | void i2c_led_send_pwm_dma(uint8_t drvid) | ||
422 | { | ||
423 | //Note: This copies the CURRENT pwm buffer, which may be getting modified | ||
424 | memcpy(dma_sendbuf, issidrv[drvid].pwm, ISSI3733_PG1_BYTES); | ||
425 | *dma_sendbuf = 0; //Force start location offset to zero | ||
426 | i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG1_BYTES); | ||
427 | |||
428 | i2c_led_begin_dma(drvid); | ||
429 | } | ||
430 | |||
431 | void i2c_led_send_onoff_dma(uint8_t drvid) | ||
432 | { | ||
433 | //Note: This copies the CURRENT onoff buffer, which may be getting modified | ||
434 | memcpy(dma_sendbuf, issidrv[drvid].onoff, ISSI3733_PG0_BYTES); | ||
435 | *dma_sendbuf = 0; //Force start location offset to zero | ||
436 | i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG0_BYTES); | ||
437 | |||
438 | i2c_led_begin_dma(drvid); | ||
439 | } | ||
440 | |||
441 | void i2c_led_q_init(void) | ||
442 | { | ||
443 | memset(i2c_led_q, 0, I2C_Q_SIZE); | ||
444 | i2c_led_q_s = 0; | ||
445 | i2c_led_q_e = 0; | ||
446 | i2c_led_q_running = 0; | ||
447 | i2c_led_q_full = 0; | ||
448 | } | ||
449 | |||
450 | uint8_t i2c_led_q_isempty(void) | ||
451 | { | ||
452 | return i2c_led_q_s == i2c_led_q_e; | ||
453 | } | ||
454 | |||
455 | uint8_t i2c_led_q_size(void) | ||
456 | { | ||
457 | return (i2c_led_q_e - i2c_led_q_s) % I2C_Q_SIZE; | ||
458 | } | ||
459 | |||
460 | uint8_t i2c_led_q_available(void) | ||
461 | { | ||
462 | return I2C_Q_SIZE - i2c_led_q_size() - 1; //Never allow end to meet start | ||
463 | } | ||
464 | |||
465 | void i2c_led_q_add(uint8_t cmd) | ||
466 | { | ||
467 | //WARNING: Always request room before adding commands! | ||
468 | |||
469 | //Assign command | ||
470 | i2c_led_q[i2c_led_q_e] = cmd; | ||
471 | |||
472 | i2c_led_q_e = (i2c_led_q_e + 1) % I2C_Q_SIZE; //Move end up one or wrap | ||
473 | } | ||
474 | |||
475 | void i2c_led_q_s_advance(void) | ||
476 | { | ||
477 | i2c_led_q_s = (i2c_led_q_s + 1) % I2C_Q_SIZE; //Move start up one or wrap | ||
478 | } | ||
479 | |||
480 | //Always request room before adding commands | ||
481 | //PS: In case the queue somehow gets filled, it will reset if it can not clear up | ||
482 | //PS: Could only get this to happen through unrealistic timings to overload the I2C bus | ||
483 | uint8_t i2c_led_q_request_room(uint8_t request_size) | ||
484 | { | ||
485 | if (request_size > i2c_led_q_available()) | ||
486 | { | ||
487 | i2c_led_q_full++; | ||
488 | |||
489 | if (i2c_led_q_full >= 100) //Give the queue a chance to clear up | ||
490 | { | ||
491 | led_on; | ||
492 | I2C_DMAC_LED_Init(); | ||
493 | i2c_led_q_init(); | ||
494 | return 1; | ||
495 | } | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | i2c_led_q_full = 0; | ||
501 | |||
502 | return 1; | ||
503 | } | ||
504 | |||
505 | uint8_t i2c_led_q_run(void) | ||
506 | { | ||
507 | if (i2c_led_q_isempty()) | ||
508 | { | ||
509 | i2c_led_q_running = 0; | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | if (i2c_led_q_running) return 1; | ||
514 | |||
515 | i2c_led_q_running = 1; | ||
516 | |||
517 | #if I2C_LED_USE_DMA != 1 | ||
518 | while (!i2c_led_q_isempty()) | ||
519 | { | ||
520 | #endif | ||
521 | //run command | ||
522 | if (i2c_led_q[i2c_led_q_s] == I2C_Q_CRWL) | ||
523 | { | ||
524 | i2c_led_q_s_advance(); | ||
525 | uint8_t drvid = i2c_led_q[i2c_led_q_s]; | ||
526 | #if I2C_LED_USE_DMA == 1 | ||
527 | i2c_led_send_CRWL_dma(drvid); | ||
528 | #else | ||
529 | i2c_led_send_CRWL(drvid); | ||
530 | #endif | ||
531 | } | ||
532 | else if (i2c_led_q[i2c_led_q_s] == I2C_Q_PAGE_SELECT) | ||
533 | { | ||
534 | i2c_led_q_s_advance(); | ||
535 | uint8_t drvid = i2c_led_q[i2c_led_q_s]; | ||
536 | i2c_led_q_s_advance(); | ||
537 | uint8_t page = i2c_led_q[i2c_led_q_s]; | ||
538 | #if I2C_LED_USE_DMA == 1 | ||
539 | i2c_led_select_page_dma(drvid, page); | ||
540 | #else | ||
541 | i2c_led_select_page(drvid, page); | ||
542 | #endif | ||
543 | } | ||
544 | else if (i2c_led_q[i2c_led_q_s] == I2C_Q_PWM) | ||
545 | { | ||
546 | i2c_led_q_s_advance(); | ||
547 | uint8_t drvid = i2c_led_q[i2c_led_q_s]; | ||
548 | #if I2C_LED_USE_DMA == 1 | ||
549 | i2c_led_send_pwm_dma(drvid); | ||
550 | #else | ||
551 | i2c_led_send_pwm(drvid); | ||
552 | #endif | ||
553 | } | ||
554 | else if (i2c_led_q[i2c_led_q_s] == I2C_Q_GCR) | ||
555 | { | ||
556 | i2c_led_q_s_advance(); | ||
557 | uint8_t drvid = i2c_led_q[i2c_led_q_s]; | ||
558 | #if I2C_LED_USE_DMA == 1 | ||
559 | i2c_led_send_GCR_dma(drvid); | ||
560 | #else | ||
561 | i2c_led_send_GCR(drvid); | ||
562 | #endif | ||
563 | } | ||
564 | else if (i2c_led_q[i2c_led_q_s] == I2C_Q_ONOFF) | ||
565 | { | ||
566 | i2c_led_q_s_advance(); | ||
567 | uint8_t drvid = i2c_led_q[i2c_led_q_s]; | ||
568 | #if I2C_LED_USE_DMA == 1 | ||
569 | i2c_led_send_onoff_dma(drvid); | ||
570 | #else | ||
571 | i2c_led_send_onoff(drvid); | ||
572 | #endif | ||
573 | } | ||
574 | |||
575 | i2c_led_q_s_advance(); //Advance last run command or if the command byte was not serviced | ||
576 | |||
577 | #if I2C_LED_USE_DMA != 1 | ||
578 | } | ||
579 | |||
580 | i2c_led_q_running = 0; | ||
581 | #endif | ||
582 | |||
583 | return 1; | ||
584 | } | ||
585 | #endif //MD_BOOTLOADER | ||
diff --git a/tmk_core/protocol/arm_atsam/i2c_master.h b/tmk_core/protocol/arm_atsam/i2c_master.h new file mode 100644 index 000000000..99481366a --- /dev/null +++ b/tmk_core/protocol/arm_atsam/i2c_master.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _I2C_MASTER_H_ | ||
19 | #define _I2C_MASTER_H_ | ||
20 | |||
21 | #ifndef MD_BOOTLOADER | ||
22 | |||
23 | #include "samd51j18a.h" | ||
24 | #include "issi3733_driver.h" | ||
25 | #include "config.h" | ||
26 | |||
27 | __attribute__((__aligned__(16))) | ||
28 | DmacDescriptor dmac_desc; | ||
29 | __attribute__((__aligned__(16))) | ||
30 | DmacDescriptor dmac_desc_wb; | ||
31 | |||
32 | uint8_t I2C3733_Init_Control(void); | ||
33 | uint8_t I2C3733_Init_Drivers(void); | ||
34 | void I2C3733_Control_Set(uint8_t state); | ||
35 | void I2C_DMAC_LED_Init(void); | ||
36 | |||
37 | #define I2C_Q_SIZE 100 | ||
38 | |||
39 | #define I2C_Q_NA 100 | ||
40 | #define I2C_Q_CRWL 101 | ||
41 | #define I2C_Q_PAGE_SELECT 102 | ||
42 | #define I2C_Q_PWM 103 | ||
43 | #define I2C_Q_GCR 104 | ||
44 | #define I2C_Q_ONOFF 105 | ||
45 | |||
46 | #define I2C_DMA_MAX_SEND 255 | ||
47 | |||
48 | extern volatile uint8_t i2c_led_q_running; | ||
49 | |||
50 | #define I2C_LED_Q_PWM(a) { \ | ||
51 | if (i2c_led_q_request_room(7)) \ | ||
52 | { \ | ||
53 | i2c_led_q_add(I2C_Q_CRWL); \ | ||
54 | i2c_led_q_add(a); \ | ||
55 | i2c_led_q_add(I2C_Q_PAGE_SELECT); \ | ||
56 | i2c_led_q_add(a); \ | ||
57 | i2c_led_q_add(ISSI3733_PG_PWM); \ | ||
58 | i2c_led_q_add(I2C_Q_PWM); \ | ||
59 | i2c_led_q_add(a); \ | ||
60 | } \ | ||
61 | } | ||
62 | |||
63 | #define I2C_LED_Q_GCR(a) { \ | ||
64 | if (i2c_led_q_request_room(7)) \ | ||
65 | { \ | ||
66 | i2c_led_q_add(I2C_Q_CRWL); \ | ||
67 | i2c_led_q_add(a); \ | ||
68 | i2c_led_q_add(I2C_Q_PAGE_SELECT); \ | ||
69 | i2c_led_q_add(a); \ | ||
70 | i2c_led_q_add(ISSI3733_PG_FN); \ | ||
71 | i2c_led_q_add(I2C_Q_GCR); \ | ||
72 | i2c_led_q_add(a); \ | ||
73 | } \ | ||
74 | } | ||
75 | |||
76 | #define I2C_LED_Q_ONOFF(a) { \ | ||
77 | if (i2c_led_q_request_room(7)) \ | ||
78 | { \ | ||
79 | i2c_led_q_add(I2C_Q_CRWL); \ | ||
80 | i2c_led_q_add(a); \ | ||
81 | i2c_led_q_add(I2C_Q_PAGE_SELECT); \ | ||
82 | i2c_led_q_add(a); \ | ||
83 | i2c_led_q_add(ISSI3733_PG_ONOFF); \ | ||
84 | i2c_led_q_add(I2C_Q_ONOFF); \ | ||
85 | i2c_led_q_add(a); \ | ||
86 | } \ | ||
87 | } | ||
88 | |||
89 | |||
90 | void i2c_led_q_init(void); | ||
91 | void i2c_led_q_add(uint8_t cmd); | ||
92 | void i2c_led_q_s_advance(void); | ||
93 | uint8_t i2c_led_q_size(void); | ||
94 | uint8_t i2c_led_q_request_room(uint8_t request_size); | ||
95 | uint8_t i2c_led_q_run(void); | ||
96 | |||
97 | void i2c1_init(void); | ||
98 | uint8_t i2c1_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout); | ||
99 | void i2c1_stop(void); | ||
100 | |||
101 | #endif //MD_BOOTLOADER | ||
102 | |||
103 | void i2c0_init(void); | ||
104 | uint8_t i2c0_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout); | ||
105 | void i2c0_stop(void); | ||
106 | |||
107 | #endif // _I2C_MASTER_H_ | ||
108 | |||
diff --git a/tmk_core/protocol/arm_atsam/issi3733_driver.h b/tmk_core/protocol/arm_atsam/issi3733_driver.h new file mode 100644 index 000000000..a537029f0 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/issi3733_driver.h | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _ISSI3733_DRIVER_H_ | ||
19 | #define _ISSI3733_DRIVER_H_ | ||
20 | |||
21 | //ISII3733 Registers | ||
22 | |||
23 | #define ISSI3733_CMDR 0xFD //Command Register (Write Only) | ||
24 | |||
25 | #define ISSI3733_CMDRWL 0xFE //Command Register Write Lock (Read/Write) | ||
26 | #define ISSI3733_CMDRWL_WRITE_DISABLE 0x00 //Lock register | ||
27 | #define ISSI3733_CMDRWL_WRITE_ENABLE_ONCE 0xC5 //Enable one write to register then reset to locked | ||
28 | |||
29 | #define ISSI3733_IMR 0xF0 //Interrupt Mask Register (Write Only) | ||
30 | #define ISSI3733_IMR_IAC_ON 0x08 //Auto Clear Interrupt Bit - Interrupt auto clear when INTB stay low exceeds 8ms | ||
31 | #define ISSI3733_IMR_IAB_ON 0x04 //Auto Breath Interrupt Bit - Enable auto breath loop finish interrupt | ||
32 | #define ISSI3733_IMR_IS_ON 0x02 //Dot Short Interrupt Bit - Enable dot short interrupt | ||
33 | #define ISSI3733_IMR_IO_ON 0x01 //Dot Open Interrupt Bit - Enable dot open interrupt | ||
34 | |||
35 | #define ISSI3733_ISR 0xF1 //Interrupt Status Register (Read Only) | ||
36 | #define ISSI3733_ISR_ABM3_FINISH 0x10 //Auto Breath Mode 3 Finish Bit - ABM3 finished | ||
37 | #define ISSI3733_ISR_ABM2_FINISH 0x08 //Auto Breath Mode 2 Finish Bit - ABM2 finished | ||
38 | #define ISSI3733_ISR_ABM1_FINISH 0x04 //Auto Breath Mode 1 Finish Bit - ABM1 finished | ||
39 | #define ISSI3733_ISR_SB 0x02 //Short Bit - Shorted | ||
40 | #define ISSI3733_ISR_OB 0x01 //Open Bit - Opened | ||
41 | |||
42 | #define ISSI3733_PG0 0x00 //LED Control Register | ||
43 | #define ISSI3733_PG1 0x01 //PWM Register | ||
44 | #define ISSI3733_PG2 0x02 //Auto Breath Mode Register | ||
45 | #define ISSI3733_PG3 0x03 //Function Register | ||
46 | |||
47 | #define ISSI3733_PG_ONOFF ISSI3733_PG0 | ||
48 | #define ISSI3733_PG_OR ISSI3733_PG0 | ||
49 | #define ISSI3733_PG_SR ISSI3733_PG0 | ||
50 | #define ISSI3733_PG_PWM ISSI3733_PG1 | ||
51 | #define ISSI3733_PG_ABM ISSI3733_PG2 | ||
52 | #define ISSI3733_PG_FN ISSI3733_PG3 | ||
53 | |||
54 | #define ISSI3733_CR 0x00 //Configuration Register | ||
55 | |||
56 | //PG3: Configuration Register: Synchronize Configuration | ||
57 | #define ISSI3733_CR_SYNC_MASTER 0x40 //Master | ||
58 | #define ISSI3733_CR_SYNC_SLAVE 0x80 //Slave | ||
59 | #define ISSI3733_CR_SYNC_HIGH_IMP 0xC0 //High Impedance | ||
60 | |||
61 | //PG3: Configuration Register: Open/Short Detection Enable Bit | ||
62 | //#define ISSI3733_CR_OSD_DISABLE 0x00 //Disable open/short detection | ||
63 | #define ISSI3733_CR_OSD_ENABLE 0x04 //Enable open/short detection | ||
64 | |||
65 | //PG3: Configuration Register: Auto Breath Enable | ||
66 | //#define ISSI3733_CR_B_EN_PWM 0x00 //PWM Mode Enable | ||
67 | #define ISSI3733_CR_B_EN_AUTO 0x02 //Auto Breath Mode Enable | ||
68 | |||
69 | //PG3: Configuration Register: Software Shutdown Control | ||
70 | //#define ISSI3733_CR_SSD_SHUTDOWN 0x00 //Software shutdown | ||
71 | #define ISSI3733_CR_SSD_NORMAL 0x01 //Normal operation | ||
72 | |||
73 | #define ISSI3733_GCCR 0x01 //Global Current Control Register | ||
74 | |||
75 | //1 Byte, Iout = (GCC / 256) * (840 / Rext) | ||
76 | //TODO: Give user define for Rext | ||
77 | |||
78 | //PG3: Auto Breath Control Register 1 | ||
79 | #define ISSI3733_ABCR1_ABM1 0x02 //Auto Breath Control Register 1 of ABM-1 | ||
80 | #define ISSI3733_ABCR1_ABM2 0x06 //Auto Breath Control Register 1 of ABM-2 | ||
81 | #define ISSI3733_ABCR1_ABM3 0x0A //Auto Breath Control Register 1 of ABM-3 | ||
82 | |||
83 | //Rise time | ||
84 | #define ISSI3733_ABCR1_T1_0021 0x00 //0.21s | ||
85 | #define ISSI3733_ABCR1_T1_0042 0x20 //0.42s | ||
86 | #define ISSI3733_ABCR1_T1_0084 0x40 //0.84s | ||
87 | #define ISSI3733_ABCR1_T1_0168 0x60 //1.68s | ||
88 | #define ISSI3733_ABCR1_T1_0336 0x80 //3.36s | ||
89 | #define ISSI3733_ABCR1_T1_0672 0xA0 //6.72s | ||
90 | #define ISSI3733_ABCR1_T1_1344 0xC0 //13.44s | ||
91 | #define ISSI3733_ABCR1_T1_2688 0xE0 //26.88s | ||
92 | |||
93 | //Max value time | ||
94 | #define ISSI3733_ABCR1_T2_0000 0x00 //0s | ||
95 | #define ISSI3733_ABCR1_T2_0021 0x02 //0.21s | ||
96 | #define ISSI3733_ABCR1_T2_0042 0x04 //0.42s | ||
97 | #define ISSI3733_ABCR1_T2_0084 0x06 //0.84s | ||
98 | #define ISSI3733_ABCR1_T2_0168 0x08 //1.68s | ||
99 | #define ISSI3733_ABCR1_T2_0336 0x0A //3.36s | ||
100 | #define ISSI3733_ABCR1_T2_0672 0x0C //6.72s | ||
101 | #define ISSI3733_ABCR1_T2_1344 0x0E //13.44s | ||
102 | #define ISSI3733_ABCR1_T2_2688 0x10 //26.88s | ||
103 | |||
104 | //PG3: Auto Breath Control Register 2 | ||
105 | #define ISSI3733_ABCR2_ABM1 0x03 //Auto Breath Control Register 2 of ABM-1 | ||
106 | #define ISSI3733_ABCR2_ABM2 0x07 //Auto Breath Control Register 2 of ABM-2 | ||
107 | #define ISSI3733_ABCR2_ABM3 0x0B //Auto Breath Control Register 2 of ABM-3 | ||
108 | |||
109 | //Fall time | ||
110 | #define ISSI3733_ABCR2_T3_0021 0x00 //0.21s | ||
111 | #define ISSI3733_ABCR2_T3_0042 0x20 //0.42s | ||
112 | #define ISSI3733_ABCR2_T3_0084 0x40 //0.84s | ||
113 | #define ISSI3733_ABCR2_T3_0168 0x60 //1.68s | ||
114 | #define ISSI3733_ABCR2_T3_0336 0x80 //3.36s | ||
115 | #define ISSI3733_ABCR2_T3_0672 0xA0 //6.72s | ||
116 | #define ISSI3733_ABCR2_T3_1344 0xC0 //13.44s | ||
117 | #define ISSI3733_ABCR2_T3_2688 0xE0 //26.88s | ||
118 | |||
119 | //Min value time | ||
120 | #define ISSI3733_ABCR2_T4_0000 0x00 //0s | ||
121 | #define ISSI3733_ABCR2_T4_0021 0x02 //0.21s | ||
122 | #define ISSI3733_ABCR2_T4_0042 0x04 //0.42s | ||
123 | #define ISSI3733_ABCR2_T4_0084 0x06 //0.84s | ||
124 | #define ISSI3733_ABCR2_T4_0168 0x08 //1.68s | ||
125 | #define ISSI3733_ABCR2_T4_0336 0x0A //3.36s | ||
126 | #define ISSI3733_ABCR2_T4_0672 0x0C //6.72s | ||
127 | #define ISSI3733_ABCR2_T4_1344 0x0E //13.44s | ||
128 | #define ISSI3733_ABCR2_T4_2688 0x10 //26.88s | ||
129 | #define ISSI3733_ABCR2_T4_5376 0x12 //53.76s | ||
130 | #define ISSI3733_ABCR2_T4_10752 0x14 //107.52s | ||
131 | |||
132 | //PG3: Auto Breath Control Register 3 | ||
133 | #define ISSI3733_ABCR3_ABM1 0x04 //Auto Breath Control Register 3 of ABM-1 | ||
134 | #define ISSI3733_ABCR3_ABM2 0x08 //Auto Breath Control Register 3 of ABM-2 | ||
135 | #define ISSI3733_ABCR3_ABM3 0x0C //Auto Breath Control Register 3 of ABM-3 | ||
136 | |||
137 | #define ISSI3733_ABCR3_LTA_LOOP_ENDLESS 0x00 | ||
138 | #define ISSI3733_ABCR3_LTA_LOOP_1 0x01 | ||
139 | #define ISSI3733_ABCR3_LTA_LOOP_2 0x02 | ||
140 | #define ISSI3733_ABCR3_LTA_LOOP_3 0x03 | ||
141 | #define ISSI3733_ABCR3_LTA_LOOP_4 0x04 | ||
142 | #define ISSI3733_ABCR3_LTA_LOOP_5 0x05 | ||
143 | #define ISSI3733_ABCR3_LTA_LOOP_6 0x06 | ||
144 | #define ISSI3733_ABCR3_LTA_LOOP_7 0x07 | ||
145 | #define ISSI3733_ABCR3_LTA_LOOP_8 0x08 | ||
146 | #define ISSI3733_ABCR3_LTA_LOOP_9 0x09 | ||
147 | #define ISSI3733_ABCR3_LTA_LOOP_10 0x0A | ||
148 | #define ISSI3733_ABCR3_LTA_LOOP_11 0x0B | ||
149 | #define ISSI3733_ABCR3_LTA_LOOP_12 0x0C | ||
150 | #define ISSI3733_ABCR3_LTA_LOOP_13 0x0D | ||
151 | #define ISSI3733_ABCR3_LTA_LOOP_14 0x0E | ||
152 | #define ISSI3733_ABCR3_LTA_LOOP_15 0x0F | ||
153 | |||
154 | //Loop Begin | ||
155 | #define ISSI3733_ABCR3_LB_T1 0x00 | ||
156 | #define ISSI3733_ABCR3_LB_T2 0x10 | ||
157 | #define ISSI3733_ABCR3_LB_T3 0x20 | ||
158 | #define ISSI3733_ABCR3_LB_T4 0x30 | ||
159 | |||
160 | //Loop End | ||
161 | #define ISSI3733_ABCR3_LE_T3 0x00 //End at Off state | ||
162 | #define ISSI3733_ABCR3_LE_T1 0x40 //End at On State | ||
163 | |||
164 | //PG3: Auto Breath Control Register 4 | ||
165 | #define ISSI3733_ABCR4_ABM1 0x05 //Auto Breath Control Register 4 of ABM-1 | ||
166 | #define ISSI3733_ABCR4_ABM2 0x09 //Auto Breath Control Register 4 of ABM-2 | ||
167 | #define ISSI3733_ABCR4_ABM3 0x0D //Auto Breath Control Register 4 of ABM-3 | ||
168 | |||
169 | #define ISSI3733_ABCR4_LTB_LOOP_ENDLESS 0x00 | ||
170 | //Or 8bit loop times | ||
171 | |||
172 | //PG3: Time Update Register | ||
173 | #define ISSI3733_TUR 0x0E | ||
174 | #define ISSI3733_TUR_UPDATE 0x00 //Write to update 02h~0Dh time registers after configuring | ||
175 | |||
176 | //PG3: SWy Pull-Up Resistor Selection Register | ||
177 | #define ISSI3733_SWYR_PUR 0x0F | ||
178 | #define ISSI3733_SWYR_PUR_NONE 0x00 //No pull-up resistor | ||
179 | #define ISSI3733_SWYR_PUR_500 0x01 //0.5k Ohm | ||
180 | #define ISSI3733_SWYR_PUR_1000 0x02 //1.0k Ohm | ||
181 | #define ISSI3733_SWYR_PUR_2000 0x03 //2.0k Ohm | ||
182 | #define ISSI3733_SWYR_PUR_4000 0x04 //4.0k Ohm | ||
183 | #define ISSI3733_SWYR_PUR_8000 0x05 //8.0k Ohm | ||
184 | #define ISSI3733_SWYR_PUR_16000 0x06 //16k Ohm | ||
185 | #define ISSI3733_SWYR_PUR_32000 0x07 //32k Ohm | ||
186 | |||
187 | //PG3: CSx Pull-Down Resistor Selection Register | ||
188 | #define ISSI3733_CSXR_PDR 0x10 | ||
189 | #define ISSI3733_CSXR_PDR_NONE 0x00 //No pull-down resistor | ||
190 | #define ISSI3733_CSXR_PDR_500 0x01 //0.5k Ohm | ||
191 | #define ISSI3733_CSXR_PDR_1000 0x02 //1.0k Ohm | ||
192 | #define ISSI3733_CSXR_PDR_2000 0x03 //2.0k Ohm | ||
193 | #define ISSI3733_CSXR_PDR_4000 0x04 //4.0k Ohm | ||
194 | #define ISSI3733_CSXR_PDR_8000 0x05 //8.0k Ohm | ||
195 | #define ISSI3733_CSXR_PDR_16000 0x06 //16k Ohm | ||
196 | #define ISSI3733_CSXR_PDR_32000 0x07 //32k Ohm | ||
197 | |||
198 | //PG3: Reset Register | ||
199 | #define ISSI3733_RR 0x11 //Read to reset all registers to default values | ||
200 | |||
201 | #endif //_ISSI3733_DRIVER_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/led_matrix.c b/tmk_core/protocol/arm_atsam/led_matrix.c new file mode 100644 index 000000000..7ee1dad22 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/led_matrix.c | |||
@@ -0,0 +1,509 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "arm_atsam_protocol.h" | ||
19 | #include "tmk_core/common/led.h" | ||
20 | #include <string.h> | ||
21 | |||
22 | void SERCOM1_0_Handler( void ) | ||
23 | { | ||
24 | if (SERCOM1->I2CM.INTFLAG.bit.ERROR) | ||
25 | { | ||
26 | SERCOM1->I2CM.INTFLAG.reg = SERCOM_I2CM_INTENCLR_ERROR; | ||
27 | } | ||
28 | } | ||
29 | |||
30 | void DMAC_0_Handler( void ) | ||
31 | { | ||
32 | if (DMAC->Channel[0].CHINTFLAG.bit.TCMPL) | ||
33 | { | ||
34 | DMAC->Channel[0].CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; | ||
35 | |||
36 | i2c1_stop(); | ||
37 | |||
38 | i2c_led_q_running = 0; | ||
39 | |||
40 | i2c_led_q_run(); | ||
41 | |||
42 | return; | ||
43 | } | ||
44 | |||
45 | if (DMAC->Channel[0].CHINTFLAG.bit.TERR) | ||
46 | { | ||
47 | DMAC->Channel[0].CHINTFLAG.reg = DMAC_CHINTENCLR_TERR; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT]; | ||
52 | |||
53 | issi3733_led_t led_map[ISSI3733_LED_COUNT+1] = ISSI3733_LED_MAP; | ||
54 | issi3733_led_t *lede = led_map + ISSI3733_LED_COUNT; //End pointer of mapping | ||
55 | |||
56 | uint8_t gcr_desired; | ||
57 | uint8_t gcr_breathe; | ||
58 | uint8_t gcr_use; | ||
59 | uint8_t gcr_actual; | ||
60 | uint8_t gcr_actual_last; | ||
61 | |||
62 | #define ACT_GCR_NONE 0 | ||
63 | #define ACT_GCR_INC 1 | ||
64 | #define ACT_GCR_DEC 2 | ||
65 | |||
66 | #define LED_GCR_STEP_AUTO 2 | ||
67 | |||
68 | static uint8_t gcr_min_counter; | ||
69 | static uint8_t v_5v_cat_hit; | ||
70 | |||
71 | //WARNING: Automatic GCR is in place to prevent USB shutdown and LED driver overloading | ||
72 | void gcr_compute(void) | ||
73 | { | ||
74 | uint8_t action = ACT_GCR_NONE; | ||
75 | |||
76 | if (led_animation_breathing) | ||
77 | gcr_use = gcr_breathe; | ||
78 | else | ||
79 | gcr_use = gcr_desired; | ||
80 | |||
81 | //If the 5v takes a catastrophic hit, disable the LED drivers briefly, assert auto gcr mode, min gcr and let the auto take over | ||
82 | if (v_5v < V5_CAT) | ||
83 | { | ||
84 | I2C3733_Control_Set(0); | ||
85 | //CDC_print("USB: WARNING: 5V catastrophic level reached! Disabling LED drivers!\r\n"); //Blocking print is bad here! | ||
86 | v_5v_cat_hit = 20; //~100ms recover | ||
87 | gcr_actual = 0; //Minimize GCR | ||
88 | usb_gcr_auto = 1; //Force auto mode enabled | ||
89 | return; | ||
90 | } | ||
91 | else if (v_5v_cat_hit > 1) | ||
92 | { | ||
93 | v_5v_cat_hit--; | ||
94 | return; | ||
95 | } | ||
96 | else if (v_5v_cat_hit == 1) | ||
97 | { | ||
98 | I2C3733_Control_Set(1); | ||
99 | CDC_print("USB: WARNING: Re-enabling LED drivers\r\n"); | ||
100 | v_5v_cat_hit = 0; | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | if (usb_gcr_auto) | ||
105 | { | ||
106 | if (v_5v_avg < V5_LOW) action = ACT_GCR_DEC; | ||
107 | else if (v_5v_avg > V5_HIGH && gcr_actual < gcr_use) action = ACT_GCR_INC; | ||
108 | else if (gcr_actual > gcr_use) action = ACT_GCR_DEC; | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | if (gcr_actual < gcr_use) action = ACT_GCR_INC; | ||
113 | else if (gcr_actual > gcr_use) action = ACT_GCR_DEC; | ||
114 | } | ||
115 | |||
116 | if (action == ACT_GCR_NONE) | ||
117 | { | ||
118 | gcr_min_counter = 0; | ||
119 | } | ||
120 | else if (action == ACT_GCR_INC) | ||
121 | { | ||
122 | if (LED_GCR_STEP_AUTO > LED_GCR_MAX - gcr_actual) gcr_actual = LED_GCR_MAX; //Obey max and prevent wrapping | ||
123 | else gcr_actual += LED_GCR_STEP_AUTO; | ||
124 | gcr_min_counter = 0; | ||
125 | } | ||
126 | else if (action == ACT_GCR_DEC) | ||
127 | { | ||
128 | if (LED_GCR_STEP_AUTO > gcr_actual) //Prevent wrapping | ||
129 | { | ||
130 | gcr_actual = 0; | ||
131 | //At this point, power can no longer be cut from the LED drivers, so focus on cutting out extra port if active | ||
132 | if (usb_extra_state != USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) //If not in a wait for replug state | ||
133 | { | ||
134 | if (usb_extra_state == USB_EXTRA_STATE_ENABLED) //If extra usb is enabled | ||
135 | { | ||
136 | gcr_min_counter++; | ||
137 | if (gcr_min_counter > 200) //5ms per check = 1s delay | ||
138 | { | ||
139 | USB_ExtraSetState(USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG); | ||
140 | usb_extra_manual = 0; //Force disable manual mode of extra port | ||
141 | if (usb_extra_manual) CDC_print("USB: Disabling extra port until replug and manual mode toggle!\r\n"); | ||
142 | else CDC_print("USB: Disabling extra port until replug!\r\n"); | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | else | ||
148 | { | ||
149 | //Power successfully cut back from LED drivers | ||
150 | gcr_actual -= LED_GCR_STEP_AUTO; | ||
151 | gcr_min_counter = 0; | ||
152 | |||
153 | //If breathe mode is active, the top end can fluctuate if the host can not supply enough current | ||
154 | //So set the breathe GCR to where it becomes stable | ||
155 | if (led_animation_breathing == 1) | ||
156 | { | ||
157 | gcr_breathe = gcr_actual; | ||
158 | //PS: At this point, setting breathing to exhale makes a noticebly shorter cycle | ||
159 | // and the same would happen maybe one or two more times. Therefore I'm favoring | ||
160 | // powering through one full breathe and letting gcr settle completely | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | led_disp_t disp; | ||
167 | |||
168 | void issi3733_prepare_arrays(void) | ||
169 | { | ||
170 | memset(issidrv,0,sizeof(issi3733_driver_t) * ISSI3733_DRIVER_COUNT); | ||
171 | |||
172 | int i; | ||
173 | uint8_t addrs[ISSI3733_DRIVER_COUNT] = ISSI3773_DRIVER_ADDRESSES; | ||
174 | |||
175 | for (i=0;i<ISSI3733_DRIVER_COUNT;i++) | ||
176 | { | ||
177 | issidrv[i].addr = addrs[i]; | ||
178 | } | ||
179 | |||
180 | issi3733_led_t *cur = led_map; | ||
181 | |||
182 | while (cur < lede) | ||
183 | { | ||
184 | //BYTE: 1 + (SW-1)*16 + (CS-1) | ||
185 | cur->rgb.g = issidrv[cur->adr.drv-1].pwm + 1 + ((cur->adr.swg-1)*16 + (cur->adr.cs-1)); | ||
186 | cur->rgb.r = issidrv[cur->adr.drv-1].pwm + 1 + ((cur->adr.swr-1)*16 + (cur->adr.cs-1)); | ||
187 | cur->rgb.b = issidrv[cur->adr.drv-1].pwm + 1 + ((cur->adr.swb-1)*16 + (cur->adr.cs-1)); | ||
188 | |||
189 | //BYTE: 1 + (SW-1)*2 + (CS-1)/8 | ||
190 | //BIT: (CS-1)%8 | ||
191 | *(issidrv[cur->adr.drv-1].onoff + 1 + (cur->adr.swg-1)*2+(cur->adr.cs-1)/8) |= (1<<((cur->adr.cs-1)%8)); | ||
192 | *(issidrv[cur->adr.drv-1].onoff + 1 + (cur->adr.swr-1)*2+(cur->adr.cs-1)/8) |= (1<<((cur->adr.cs-1)%8)); | ||
193 | *(issidrv[cur->adr.drv-1].onoff + 1 + (cur->adr.swb-1)*2+(cur->adr.cs-1)/8) |= (1<<((cur->adr.cs-1)%8)); | ||
194 | |||
195 | cur++; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | void disp_calc_extents(void) | ||
200 | { | ||
201 | issi3733_led_t *cur = led_map; | ||
202 | |||
203 | disp.left = 1e10; | ||
204 | disp.right = -1e10; | ||
205 | disp.top = -1e10; | ||
206 | disp.bottom = 1e10; | ||
207 | |||
208 | while (cur < lede) | ||
209 | { | ||
210 | if (cur->x < disp.left) disp.left = cur->x; | ||
211 | if (cur->x > disp.right) disp.right = cur->x; | ||
212 | if (cur->y < disp.bottom) disp.bottom = cur->y; | ||
213 | if (cur->y > disp.top) disp.top = cur->y; | ||
214 | |||
215 | cur++; | ||
216 | } | ||
217 | |||
218 | disp.width = disp.right - disp.left; | ||
219 | disp.height = disp.top - disp.bottom; | ||
220 | } | ||
221 | |||
222 | void disp_pixel_setup(void) | ||
223 | { | ||
224 | issi3733_led_t *cur = led_map; | ||
225 | |||
226 | while (cur < lede) | ||
227 | { | ||
228 | cur->px = (cur->x - disp.left) / disp.width * 100; | ||
229 | cur->py = (cur->y - disp.top) / disp.height * 100; | ||
230 | *cur->rgb.r = 0; | ||
231 | *cur->rgb.g = 0; | ||
232 | *cur->rgb.b = 0; | ||
233 | |||
234 | cur++; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | void led_matrix_prepare(void) | ||
239 | { | ||
240 | disp_calc_extents(); | ||
241 | disp_pixel_setup(); | ||
242 | } | ||
243 | |||
244 | uint8_t led_enabled; | ||
245 | float led_animation_speed; | ||
246 | uint8_t led_animation_direction; | ||
247 | uint8_t led_animation_breathing; | ||
248 | uint8_t led_animation_breathe_cur; | ||
249 | uint8_t breathe_step; | ||
250 | uint8_t breathe_dir; | ||
251 | uint64_t led_next_run; | ||
252 | |||
253 | uint8_t led_animation_id; | ||
254 | uint8_t led_lighting_mode; | ||
255 | |||
256 | issi3733_led_t *led_cur; | ||
257 | uint8_t led_per_run = 15; | ||
258 | float breathe_mult; | ||
259 | |||
260 | void led_matrix_run(led_setup_t *f) | ||
261 | { | ||
262 | float ro; | ||
263 | float go; | ||
264 | float bo; | ||
265 | float px; | ||
266 | uint8_t led_this_run = 0; | ||
267 | |||
268 | if (led_cur == 0) //Denotes start of new processing cycle in the case of chunked processing | ||
269 | { | ||
270 | led_cur = led_map; | ||
271 | |||
272 | disp.frame += 1; | ||
273 | |||
274 | breathe_mult = 1; | ||
275 | |||
276 | if (led_animation_breathing) | ||
277 | { | ||
278 | led_animation_breathe_cur += breathe_step * breathe_dir; | ||
279 | |||
280 | if (led_animation_breathe_cur >= BREATHE_MAX_STEP) | ||
281 | breathe_dir = -1; | ||
282 | else if (led_animation_breathe_cur <= BREATHE_MIN_STEP) | ||
283 | breathe_dir = 1; | ||
284 | |||
285 | //Brightness curve created for 256 steps, 0 - ~98% | ||
286 | breathe_mult = 0.000015 * led_animation_breathe_cur * led_animation_breathe_cur; | ||
287 | if (breathe_mult > 1) breathe_mult = 1; | ||
288 | else if (breathe_mult < 0) breathe_mult = 0; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | uint8_t fcur = 0; | ||
293 | uint8_t fmax = 0; | ||
294 | |||
295 | //Frames setup | ||
296 | while (f[fcur].end != 1) | ||
297 | { | ||
298 | fcur++; //Count frames | ||
299 | } | ||
300 | |||
301 | fmax = fcur; //Store total frames count | ||
302 | |||
303 | while (led_cur < lede && led_this_run < led_per_run) | ||
304 | { | ||
305 | ro = 0; | ||
306 | go = 0; | ||
307 | bo = 0; | ||
308 | |||
309 | if (led_lighting_mode == LED_MODE_KEYS_ONLY && led_cur->scan == 255) | ||
310 | { | ||
311 | //Do not act on this LED | ||
312 | } | ||
313 | else if (led_lighting_mode == LED_MODE_NON_KEYS_ONLY && led_cur->scan != 255) | ||
314 | { | ||
315 | //Do not act on this LED | ||
316 | } | ||
317 | else if (led_lighting_mode == LED_MODE_INDICATORS_ONLY) | ||
318 | { | ||
319 | //Do not act on this LED (Only show indicators) | ||
320 | } | ||
321 | else | ||
322 | { | ||
323 | //Act on LED | ||
324 | for (fcur = 0; fcur < fmax; fcur++) | ||
325 | { | ||
326 | px = led_cur->px; | ||
327 | float pxmod; | ||
328 | pxmod = (float)(disp.frame % (uint32_t)(1000.0f / led_animation_speed)) / 10.0f * led_animation_speed; | ||
329 | |||
330 | //Add in any moving effects | ||
331 | if ((!led_animation_direction && f[fcur].ef & EF_SCR_R) || (led_animation_direction && (f[fcur].ef & EF_SCR_L))) | ||
332 | { | ||
333 | pxmod *= 100.0f; | ||
334 | pxmod = (uint32_t)pxmod % 10000; | ||
335 | pxmod /= 100.0f; | ||
336 | |||
337 | px -= pxmod; | ||
338 | |||
339 | if (px > 100) px -= 100; | ||
340 | else if (px < 0) px += 100; | ||
341 | } | ||
342 | else if ((!led_animation_direction && f[fcur].ef & EF_SCR_L) || (led_animation_direction && (f[fcur].ef & EF_SCR_R))) | ||
343 | { | ||
344 | pxmod *= 100.0f; | ||
345 | pxmod = (uint32_t)pxmod % 10000; | ||
346 | pxmod /= 100.0f; | ||
347 | px += pxmod; | ||
348 | |||
349 | if (px > 100) px -= 100; | ||
350 | else if (px < 0) px += 100; | ||
351 | } | ||
352 | |||
353 | //Check if LED's px is in current frame | ||
354 | if (px < f[fcur].hs) continue; | ||
355 | if (px > f[fcur].he) continue; | ||
356 | //note: < 0 or > 100 continue | ||
357 | |||
358 | //Calculate the px within the start-stop percentage for color blending | ||
359 | px = (px - f[fcur].hs) / (f[fcur].he - f[fcur].hs); | ||
360 | |||
361 | //Add in any color effects | ||
362 | if (f[fcur].ef & EF_OVER) | ||
363 | { | ||
364 | ro = (px * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5; | ||
365 | go = (px * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5; | ||
366 | bo = (px * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5; | ||
367 | } | ||
368 | else if (f[fcur].ef & EF_SUBTRACT) | ||
369 | { | ||
370 | ro -= (px * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5; | ||
371 | go -= (px * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5; | ||
372 | bo -= (px * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5; | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | ro += (px * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5; | ||
377 | go += (px * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5; | ||
378 | bo += (px * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5; | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | |||
383 | //Clamp values 0-255 | ||
384 | if (ro > 255) ro = 255; else if (ro < 0) ro = 0; | ||
385 | if (go > 255) go = 255; else if (go < 0) go = 0; | ||
386 | if (bo > 255) bo = 255; else if (bo < 0) bo = 0; | ||
387 | |||
388 | if (led_animation_breathing) | ||
389 | { | ||
390 | ro *= breathe_mult; | ||
391 | go *= breathe_mult; | ||
392 | bo *= breathe_mult; | ||
393 | } | ||
394 | |||
395 | *led_cur->rgb.r = (uint8_t)ro; | ||
396 | *led_cur->rgb.g = (uint8_t)go; | ||
397 | *led_cur->rgb.b = (uint8_t)bo; | ||
398 | |||
399 | #ifdef USB_LED_INDICATOR_ENABLE | ||
400 | if (keyboard_leds()) | ||
401 | { | ||
402 | uint8_t kbled = keyboard_leds(); | ||
403 | if ( | ||
404 | #if USB_LED_NUM_LOCK_SCANCODE != 255 | ||
405 | (led_cur->scan == USB_LED_NUM_LOCK_SCANCODE && kbled & (1<<USB_LED_NUM_LOCK)) || | ||
406 | #endif //NUM LOCK | ||
407 | #if USB_LED_CAPS_LOCK_SCANCODE != 255 | ||
408 | (led_cur->scan == USB_LED_CAPS_LOCK_SCANCODE && kbled & (1<<USB_LED_CAPS_LOCK)) || | ||
409 | #endif //CAPS LOCK | ||
410 | #if USB_LED_SCROLL_LOCK_SCANCODE != 255 | ||
411 | (led_cur->scan == USB_LED_SCROLL_LOCK_SCANCODE && kbled & (1<<USB_LED_SCROLL_LOCK)) || | ||
412 | #endif //SCROLL LOCK | ||
413 | #if USB_LED_COMPOSE_SCANCODE != 255 | ||
414 | (led_cur->scan == USB_LED_COMPOSE_SCANCODE && kbled & (1<<USB_LED_COMPOSE)) || | ||
415 | #endif //COMPOSE | ||
416 | #if USB_LED_KANA_SCANCODE != 255 | ||
417 | (led_cur->scan == USB_LED_KANA_SCANCODE && kbled & (1<<USB_LED_KANA)) || | ||
418 | #endif //KANA | ||
419 | (0)) | ||
420 | { | ||
421 | if (*led_cur->rgb.r > 127) *led_cur->rgb.r = 0; | ||
422 | else *led_cur->rgb.r = 255; | ||
423 | if (*led_cur->rgb.g > 127) *led_cur->rgb.g = 0; | ||
424 | else *led_cur->rgb.g = 255; | ||
425 | if (*led_cur->rgb.b > 127) *led_cur->rgb.b = 0; | ||
426 | else *led_cur->rgb.b = 255; | ||
427 | } | ||
428 | } | ||
429 | #endif //USB_LED_INDICATOR_ENABLE | ||
430 | |||
431 | led_cur++; | ||
432 | led_this_run++; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | uint8_t led_matrix_init(void) | ||
437 | { | ||
438 | DBGC(DC_LED_MATRIX_INIT_BEGIN); | ||
439 | |||
440 | issi3733_prepare_arrays(); | ||
441 | |||
442 | led_matrix_prepare(); | ||
443 | |||
444 | disp.frame = 0; | ||
445 | led_next_run = 0; | ||
446 | |||
447 | led_enabled = 1; | ||
448 | led_animation_id = 0; | ||
449 | led_lighting_mode = LED_MODE_NORMAL; | ||
450 | led_animation_speed = 4.0f; | ||
451 | led_animation_direction = 0; | ||
452 | led_animation_breathing = 0; | ||
453 | led_animation_breathe_cur = BREATHE_MIN_STEP; | ||
454 | breathe_step = 1; | ||
455 | breathe_dir = 1; | ||
456 | |||
457 | gcr_min_counter = 0; | ||
458 | v_5v_cat_hit = 0; | ||
459 | |||
460 | //Run led matrix code once for initial LED coloring | ||
461 | led_cur = 0; | ||
462 | led_matrix_run((led_setup_t*)led_setups[led_animation_id]); | ||
463 | |||
464 | DBGC(DC_LED_MATRIX_INIT_COMPLETE); | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | #define LED_UPDATE_RATE 10 //ms | ||
470 | |||
471 | //led data processing can take time, so process data in chunks to free up the processor | ||
472 | //this is done through led_cur and lede | ||
473 | void led_matrix_task(void) | ||
474 | { | ||
475 | if (led_enabled) | ||
476 | { | ||
477 | //If an update may run and frame processing has completed | ||
478 | if (CLK_get_ms() >= led_next_run && led_cur == lede) | ||
479 | { | ||
480 | uint8_t drvid; | ||
481 | |||
482 | led_next_run = CLK_get_ms() + LED_UPDATE_RATE; //Set next frame update time | ||
483 | |||
484 | //NOTE: GCR does not need to be timed with LED processing, but there is really no harm | ||
485 | if (gcr_actual != gcr_actual_last) | ||
486 | { | ||
487 | for (drvid=0;drvid<ISSI3733_DRIVER_COUNT;drvid++) | ||
488 | I2C_LED_Q_GCR(drvid); //Queue data | ||
489 | gcr_actual_last = gcr_actual; | ||
490 | } | ||
491 | |||
492 | for (drvid=0;drvid<ISSI3733_DRIVER_COUNT;drvid++) | ||
493 | I2C_LED_Q_PWM(drvid); //Queue data | ||
494 | |||
495 | i2c_led_q_run(); | ||
496 | |||
497 | led_cur = 0; //Signal next frame calculations may begin | ||
498 | } | ||
499 | } | ||
500 | |||
501 | //Process more data if not finished | ||
502 | if (led_cur != lede) | ||
503 | { | ||
504 | //m15_off; //debug profiling | ||
505 | led_matrix_run((led_setup_t*)led_setups[led_animation_id]); | ||
506 | //m15_on; //debug profiling | ||
507 | } | ||
508 | } | ||
509 | |||
diff --git a/tmk_core/protocol/arm_atsam/led_matrix.h b/tmk_core/protocol/arm_atsam/led_matrix.h new file mode 100644 index 000000000..01b078b71 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/led_matrix.h | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _LED_MATRIX_H_ | ||
19 | #define _LED_MATRIX_H_ | ||
20 | |||
21 | //From keyboard | ||
22 | #include "config_led.h" | ||
23 | |||
24 | //CS1-CS16 Current Source "Col" | ||
25 | #define ISSI3733_CS_COUNT 16 | ||
26 | |||
27 | //SW1-SW12 Switch "Row" | ||
28 | #define ISSI3733_SW_COUNT 12 | ||
29 | |||
30 | #define ISSI3733_LED_RGB_COUNT ISSI3733_CS_COUNT * ISSI3733_SW_COUNT | ||
31 | #define ISSI3733_PG0_BYTES ISSI3733_LED_RGB_COUNT / 8 + 1 //+1 for first byte being memory start offset for I2C transfer | ||
32 | #define ISSI3733_PG1_BYTES ISSI3733_LED_RGB_COUNT + 1 //+1 for first byte being memory start offset for I2C transfer | ||
33 | #define ISSI3733_PG2_BYTES ISSI3733_LED_RGB_COUNT + 1 //+1 for first byte being memory start offset for I2C transfer | ||
34 | #define ISSI3733_PG3_BYTES 18 + 1 //+1 for first byte being memory start offset for I2C transfer | ||
35 | |||
36 | #define ISSI3733_PG_ONOFF_BYTES ISSI3733_PG0_BYTES | ||
37 | #define ISSI3733_PG_OR_BYTES ISSI3733_PG0_BYTES | ||
38 | #define ISSI3733_PG_SR_BYTES ISSI3733_PG0_BYTES | ||
39 | #define ISSI3733_PG_PWM_BYTES ISSI3733_PG1_BYTES | ||
40 | #define ISSI3733_PG_ABM_BYTES ISSI3733_PG2_BYTES | ||
41 | #define ISSI3733_PG_FN_BYTES ISSI3733_PG3_BYTES | ||
42 | |||
43 | typedef struct issi3733_driver_s { | ||
44 | uint8_t addr; //Address of the driver according to wiring "ISSI3733: Table 1 Slave Address" | ||
45 | uint8_t onoff[ISSI3733_PG_ONOFF_BYTES]; //PG0 - LED Control Register - LED On/Off Register | ||
46 | uint8_t open[ISSI3733_PG_OR_BYTES]; //PG0 - LED Control Register - LED Open Register | ||
47 | uint8_t shrt[ISSI3733_PG_SR_BYTES]; //PG0 - LED Control Register - LED Short Register | ||
48 | uint8_t pwm[ISSI3733_PG_PWM_BYTES]; //PG1 - PWM Register | ||
49 | uint8_t abm[ISSI3733_PG_ABM_BYTES]; //PG2 - Auto Breath Mode Register | ||
50 | uint8_t conf[ISSI3733_PG_FN_BYTES]; //PG3 - Function Register | ||
51 | } issi3733_driver_t; | ||
52 | |||
53 | typedef struct issi3733_rgb_s { | ||
54 | uint8_t *r; //Direct access into PWM data | ||
55 | uint8_t *g; //Direct access into PWM data | ||
56 | uint8_t *b; //Direct access into PWM data | ||
57 | } issi3733_rgb_t; | ||
58 | |||
59 | typedef struct issi3733_rgb_adr_s { | ||
60 | uint8_t drv; //Driver from given list | ||
61 | uint8_t cs; //CS | ||
62 | uint8_t swr; //SW Red | ||
63 | uint8_t swg; //SW Green | ||
64 | uint8_t swb; //SW Blue | ||
65 | } issi3733_rgb_adr_t; | ||
66 | |||
67 | typedef struct issi3733_led_s { | ||
68 | uint8_t id; //According to PCB ref | ||
69 | issi3733_rgb_t rgb; //PWM settings of R G B | ||
70 | issi3733_rgb_adr_t adr; //Hardware addresses | ||
71 | float x; //Physical position X | ||
72 | float y; //Physical position Y | ||
73 | float px; //Physical position X in percent | ||
74 | float py; //Physical position Y in percent | ||
75 | uint8_t scan; //Key scan code from wiring (set 0xFF if no key) | ||
76 | } issi3733_led_t; | ||
77 | |||
78 | typedef struct led_disp_s { | ||
79 | uint64_t frame; | ||
80 | float left; | ||
81 | float right; | ||
82 | float top; | ||
83 | float bottom; | ||
84 | float width; | ||
85 | float height; | ||
86 | } led_disp_t; | ||
87 | |||
88 | uint8_t led_matrix_init(void); | ||
89 | |||
90 | #define LED_MODE_NORMAL 0 //Must be 0 | ||
91 | #define LED_MODE_KEYS_ONLY 1 | ||
92 | #define LED_MODE_NON_KEYS_ONLY 2 | ||
93 | #define LED_MODE_INDICATORS_ONLY 3 | ||
94 | #define LED_MODE_MAX_INDEX LED_MODE_INDICATORS_ONLY //Must be highest value | ||
95 | |||
96 | #define EF_NONE 0x00000000 //No effect | ||
97 | #define EF_OVER 0x00000001 //Overwrite any previous color information with new | ||
98 | #define EF_SCR_L 0x00000002 //Scroll left | ||
99 | #define EF_SCR_R 0x00000004 //Scroll right | ||
100 | #define EF_SUBTRACT 0x00000008 //Subtract color values | ||
101 | |||
102 | typedef struct led_setup_s { | ||
103 | float hs; //Band begin at percent | ||
104 | float he; //Band end at percent | ||
105 | uint8_t rs; //Red start value | ||
106 | uint8_t re; //Red end value | ||
107 | uint8_t gs; //Green start value | ||
108 | uint8_t ge; //Green end value | ||
109 | uint8_t bs; //Blue start value | ||
110 | uint8_t be; //Blue end value | ||
111 | uint32_t ef; //Animation and color effects | ||
112 | uint8_t end; //Set to signal end of the setup | ||
113 | } led_setup_t; | ||
114 | |||
115 | extern issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT]; | ||
116 | |||
117 | extern uint8_t gcr_desired; | ||
118 | extern uint8_t gcr_breathe; | ||
119 | extern uint8_t gcr_actual; | ||
120 | extern uint8_t gcr_actual_last; | ||
121 | |||
122 | extern uint8_t led_animation_id; | ||
123 | extern uint8_t led_enabled; | ||
124 | extern float led_animation_speed; | ||
125 | extern uint8_t led_lighting_mode; | ||
126 | extern uint8_t led_animation_direction; | ||
127 | extern uint8_t led_animation_breathing; | ||
128 | extern uint8_t led_animation_breathe_cur; | ||
129 | extern uint8_t breathe_dir; | ||
130 | extern const uint8_t led_setups_count; | ||
131 | |||
132 | extern void *led_setups[]; | ||
133 | |||
134 | extern issi3733_led_t *led_cur; | ||
135 | extern issi3733_led_t *lede; | ||
136 | |||
137 | void led_matrix_run(led_setup_t *f); | ||
138 | void led_matrix_task(void); | ||
139 | |||
140 | void gcr_compute(void); | ||
141 | |||
142 | #endif //_LED_MATRIX_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/main_arm_atsam.c b/tmk_core/protocol/arm_atsam/main_arm_atsam.c new file mode 100644 index 000000000..e9514730e --- /dev/null +++ b/tmk_core/protocol/arm_atsam/main_arm_atsam.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "samd51j18a.h" | ||
19 | #include "tmk_core/common/keyboard.h" | ||
20 | |||
21 | #include "report.h" | ||
22 | #include "host.h" | ||
23 | #include "host_driver.h" | ||
24 | #include "keycode_config.h" | ||
25 | #include <string.h> | ||
26 | #include "quantum.h" | ||
27 | |||
28 | //From protocol directory | ||
29 | #include "arm_atsam_protocol.h" | ||
30 | |||
31 | //From keyboard's directory | ||
32 | #include "config_led.h" | ||
33 | |||
34 | uint8_t keyboard_leds(void); | ||
35 | void send_keyboard(report_keyboard_t *report); | ||
36 | void send_mouse(report_mouse_t *report); | ||
37 | void send_system(uint16_t data); | ||
38 | void send_consumer(uint16_t data); | ||
39 | |||
40 | host_driver_t arm_atsam_driver = { | ||
41 | keyboard_leds, | ||
42 | send_keyboard, | ||
43 | send_mouse, | ||
44 | send_system, | ||
45 | send_consumer | ||
46 | }; | ||
47 | |||
48 | uint8_t led_states; | ||
49 | |||
50 | uint8_t keyboard_leds(void) | ||
51 | { | ||
52 | #ifdef NKRO_ENABLE | ||
53 | if (keymap_config.nkro) | ||
54 | return udi_hid_nkro_report_set; | ||
55 | else | ||
56 | #endif //NKRO_ENABLE | ||
57 | return udi_hid_kbd_report_set; | ||
58 | } | ||
59 | |||
60 | void send_keyboard(report_keyboard_t *report) | ||
61 | { | ||
62 | uint32_t irqflags; | ||
63 | |||
64 | #ifdef NKRO_ENABLE | ||
65 | if (!keymap_config.nkro) | ||
66 | { | ||
67 | #endif //NKRO_ENABLE | ||
68 | dprint("s-kbd\r\n"); | ||
69 | |||
70 | irqflags = __get_PRIMASK(); | ||
71 | __disable_irq(); | ||
72 | __DMB(); | ||
73 | |||
74 | memcpy(udi_hid_kbd_report, report->raw, UDI_HID_KBD_REPORT_SIZE); | ||
75 | udi_hid_kbd_b_report_valid = 1; | ||
76 | udi_hid_kbd_send_report(); | ||
77 | |||
78 | __DMB(); | ||
79 | __set_PRIMASK(irqflags); | ||
80 | #ifdef NKRO_ENABLE | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | dprint("s-nkro\r\n"); | ||
85 | |||
86 | irqflags = __get_PRIMASK(); | ||
87 | __disable_irq(); | ||
88 | __DMB(); | ||
89 | |||
90 | memcpy(udi_hid_nkro_report, report->raw, UDI_HID_NKRO_REPORT_SIZE); | ||
91 | udi_hid_nkro_b_report_valid = 1; | ||
92 | udi_hid_nkro_send_report(); | ||
93 | |||
94 | __DMB(); | ||
95 | __set_PRIMASK(irqflags); | ||
96 | } | ||
97 | #endif //NKRO_ENABLE | ||
98 | } | ||
99 | |||
100 | void send_mouse(report_mouse_t *report) | ||
101 | { | ||
102 | #ifdef MOUSEKEY_ENABLE | ||
103 | uint32_t irqflags; | ||
104 | |||
105 | dprint("s-mou\r\n"); | ||
106 | |||
107 | irqflags = __get_PRIMASK(); | ||
108 | __disable_irq(); | ||
109 | __DMB(); | ||
110 | |||
111 | memcpy(udi_hid_mou_report, report, UDI_HID_MOU_REPORT_SIZE); | ||
112 | udi_hid_mou_b_report_valid = 1; | ||
113 | udi_hid_mou_send_report(); | ||
114 | |||
115 | __DMB(); | ||
116 | __set_PRIMASK(irqflags); | ||
117 | #endif //MOUSEKEY_ENABLE | ||
118 | } | ||
119 | |||
120 | void send_system(uint16_t data) | ||
121 | { | ||
122 | #ifdef EXTRAKEY_ENABLE | ||
123 | dprintf("s-exks %i\r\n", data); | ||
124 | |||
125 | uint32_t irqflags; | ||
126 | |||
127 | irqflags = __get_PRIMASK(); | ||
128 | __disable_irq(); | ||
129 | __DMB(); | ||
130 | |||
131 | udi_hid_exk_report.desc.report_id = REPORT_ID_SYSTEM; | ||
132 | if (data != 0) data = data - SYSTEM_POWER_DOWN + 1; | ||
133 | udi_hid_exk_report.desc.report_data = data; | ||
134 | udi_hid_exk_b_report_valid = 1; | ||
135 | udi_hid_exk_send_report(); | ||
136 | |||
137 | __DMB(); | ||
138 | __set_PRIMASK(irqflags); | ||
139 | #endif //EXTRAKEY_ENABLE | ||
140 | } | ||
141 | |||
142 | void send_consumer(uint16_t data) | ||
143 | { | ||
144 | #ifdef EXTRAKEY_ENABLE | ||
145 | dprintf("s-exkc %i\r\n",data); | ||
146 | |||
147 | uint32_t irqflags; | ||
148 | |||
149 | irqflags = __get_PRIMASK(); | ||
150 | __disable_irq(); | ||
151 | __DMB(); | ||
152 | |||
153 | udi_hid_exk_report.desc.report_id = REPORT_ID_CONSUMER; | ||
154 | udi_hid_exk_report.desc.report_data = data; | ||
155 | udi_hid_exk_b_report_valid = 1; | ||
156 | udi_hid_exk_send_report(); | ||
157 | |||
158 | __DMB(); | ||
159 | __set_PRIMASK(irqflags); | ||
160 | #endif //EXTRAKEY_ENABLE | ||
161 | } | ||
162 | |||
163 | int main(void) | ||
164 | { | ||
165 | led_ena; | ||
166 | m15_ena; | ||
167 | |||
168 | debug_code_init(); | ||
169 | |||
170 | CLK_init(); | ||
171 | |||
172 | ADC0_init(); | ||
173 | |||
174 | SPI_Init(); | ||
175 | |||
176 | i2c1_init(); | ||
177 | |||
178 | matrix_init(); | ||
179 | |||
180 | USB2422_init(); | ||
181 | |||
182 | DBGC(DC_MAIN_UDC_START_BEGIN); | ||
183 | udc_start(); | ||
184 | DBGC(DC_MAIN_UDC_START_COMPLETE); | ||
185 | |||
186 | DBGC(DC_MAIN_CDC_INIT_BEGIN); | ||
187 | CDC_init(); | ||
188 | DBGC(DC_MAIN_CDC_INIT_COMPLETE); | ||
189 | |||
190 | while (USB2422_Port_Detect_Init() == 0) {} | ||
191 | |||
192 | led_off; | ||
193 | m15_off; | ||
194 | |||
195 | led_matrix_init(); | ||
196 | |||
197 | while (I2C3733_Init_Control() != 1) {} | ||
198 | while (I2C3733_Init_Drivers() != 1) {} | ||
199 | |||
200 | I2C_DMAC_LED_Init(); | ||
201 | |||
202 | i2c_led_q_init(); | ||
203 | |||
204 | uint8_t drvid; | ||
205 | for (drvid=0;drvid<ISSI3733_DRIVER_COUNT;drvid++) | ||
206 | I2C_LED_Q_ONOFF(drvid); //Queue data | ||
207 | |||
208 | keyboard_setup(); | ||
209 | |||
210 | keyboard_init(); | ||
211 | |||
212 | host_set_driver(&arm_atsam_driver); | ||
213 | |||
214 | #ifdef VIRTSER_ENABLE | ||
215 | uint64_t next_print = 0; | ||
216 | #endif //VIRTSER_ENABLE | ||
217 | uint64_t next_usb_checkup = 0; | ||
218 | uint64_t next_5v_checkup = 0; | ||
219 | |||
220 | v_5v_avg = adc_get(ADC_5V); | ||
221 | |||
222 | debug_code_disable(); | ||
223 | |||
224 | while (1) | ||
225 | { | ||
226 | if (usb_state == USB_STATE_POWERDOWN) | ||
227 | { | ||
228 | led_on; | ||
229 | if (led_enabled) | ||
230 | { | ||
231 | for (drvid=0;drvid<ISSI3733_DRIVER_COUNT;drvid++) | ||
232 | { | ||
233 | I2C3733_Control_Set(0); | ||
234 | } | ||
235 | } | ||
236 | while (usb_state == USB_STATE_POWERDOWN) {} | ||
237 | if (led_enabled) | ||
238 | { | ||
239 | for (drvid=0;drvid<ISSI3733_DRIVER_COUNT;drvid++) | ||
240 | { | ||
241 | I2C3733_Control_Set(1); | ||
242 | } | ||
243 | } | ||
244 | led_off; | ||
245 | } | ||
246 | |||
247 | keyboard_task(); | ||
248 | |||
249 | led_matrix_task(); | ||
250 | |||
251 | if (CLK_get_ms() > next_5v_checkup) | ||
252 | { | ||
253 | next_5v_checkup = CLK_get_ms() + 5; | ||
254 | |||
255 | v_5v = adc_get(ADC_5V); | ||
256 | v_5v_avg = 0.9 * v_5v_avg + 0.1 * v_5v; | ||
257 | |||
258 | gcr_compute(); | ||
259 | } | ||
260 | |||
261 | if (CLK_get_ms() > next_usb_checkup) | ||
262 | { | ||
263 | next_usb_checkup = CLK_get_ms() + 10; | ||
264 | |||
265 | USB_HandleExtraDevice(); | ||
266 | } | ||
267 | |||
268 | #ifdef VIRTSER_ENABLE | ||
269 | if (CLK_get_ms() > next_print) | ||
270 | { | ||
271 | next_print = CLK_get_ms() + 250; | ||
272 | //dpf("5v=%i 5vu=%i dlow=%i dhi=%i gca=%i gcd=%i\r\n",v_5v,v_5v_avg,v_5v_avg-V5_LOW,v_5v_avg-V5_HIGH,gcr_actual,gcr_desired); | ||
273 | } | ||
274 | #endif //VIRTSER_ENABLE | ||
275 | } | ||
276 | |||
277 | return 1; | ||
278 | } | ||
279 | |||
diff --git a/tmk_core/protocol/arm_atsam/main_arm_atsam.h b/tmk_core/protocol/arm_atsam/main_arm_atsam.h new file mode 100644 index 000000000..78205e2e1 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/main_arm_atsam.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _MAIN_ARM_ATSAM_H_ | ||
19 | #define _MAIN_ARM_ATSAM_H_ | ||
20 | |||
21 | uint8_t keyboard_leds(void); | ||
22 | |||
23 | #endif //_MAIN_ARM_ATSAM_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/md_bootloader.h b/tmk_core/protocol/arm_atsam/md_bootloader.h new file mode 100644 index 000000000..1316876c8 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/md_bootloader.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #ifndef _MD_BOOTLOADER_H_ | ||
2 | #define _MD_BOOTLOADER_H_ | ||
3 | |||
4 | extern uint32_t _srom; | ||
5 | extern uint32_t _lrom; | ||
6 | extern uint32_t _erom; | ||
7 | |||
8 | #define BOOTLOADER_SERIAL_MAX_SIZE 20 //DO NOT MODIFY! | ||
9 | |||
10 | #ifdef MD_BOOTLOADER | ||
11 | |||
12 | #define MCU_HZ 48000000 | ||
13 | #define I2C_HZ 0 //Not used | ||
14 | |||
15 | #endif //MD_BOOTLOADER | ||
16 | |||
17 | #endif //_MD_BOOTLOADER_H_ | ||
18 | |||
diff --git a/tmk_core/protocol/arm_atsam/spi.c b/tmk_core/protocol/arm_atsam/spi.c new file mode 100644 index 000000000..6036a9220 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/spi.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "arm_atsam_protocol.h" | ||
19 | |||
20 | Srdata_t srdata; | ||
21 | |||
22 | void SPI_WriteSRData(void) | ||
23 | { | ||
24 | uint16_t timeout; | ||
25 | |||
26 | SC2_RCLCK_LO; | ||
27 | |||
28 | timeout = 50000; | ||
29 | while (!(SCSPI->SPI.INTFLAG.bit.DRE) && --timeout) { DBGC(DC_SPI_WRITE_DRE); } | ||
30 | |||
31 | SCSPI->SPI.DATA.bit.DATA = srdata.reg & 0xFF; //Shift in bits 7-0 | ||
32 | timeout = 50000; | ||
33 | while (!(SCSPI->SPI.INTFLAG.bit.TXC) && --timeout) { DBGC(DC_SPI_WRITE_TXC_1); } | ||
34 | |||
35 | SCSPI->SPI.DATA.bit.DATA = (srdata.reg >> 8) & 0xFF; //Shift in bits 15-8 | ||
36 | timeout = 50000; | ||
37 | while (!(SCSPI->SPI.INTFLAG.bit.TXC) && --timeout) { DBGC(DC_SPI_WRITE_TXC_2); } | ||
38 | |||
39 | SC2_RCLCK_HI; | ||
40 | } | ||
41 | |||
42 | void SPI_Init(void) | ||
43 | { | ||
44 | uint32_t timeout; | ||
45 | |||
46 | DBGC(DC_SPI_INIT_BEGIN); | ||
47 | |||
48 | CLK_set_spi_freq(CHAN_SERCOM_SPI, FREQ_SPI_DEFAULT); | ||
49 | |||
50 | PORT->Group[0].PMUX[6].bit.PMUXE = 2; | ||
51 | PORT->Group[0].PMUX[6].bit.PMUXO = 2; | ||
52 | PORT->Group[0].PINCFG[12].bit.PMUXEN = 1; | ||
53 | PORT->Group[0].PINCFG[13].bit.PMUXEN = 1; | ||
54 | |||
55 | //Configure Shift Registers | ||
56 | SC2_DIRSET; | ||
57 | SC2_RCLCK_HI; | ||
58 | SC2_OE_DIS; | ||
59 | |||
60 | SCSPI->SPI.CTRLA.bit.DORD = 1; | ||
61 | SCSPI->SPI.CTRLA.bit.CPOL = 1; | ||
62 | SCSPI->SPI.CTRLA.bit.CPHA = 1; | ||
63 | SCSPI->SPI.CTRLA.bit.DIPO = 3; | ||
64 | SCSPI->SPI.CTRLA.bit.MODE = 3; //master | ||
65 | |||
66 | SCSPI->SPI.CTRLA.bit.ENABLE = 1; | ||
67 | timeout = 50000; | ||
68 | while (SCSPI->SPI.SYNCBUSY.bit.ENABLE && timeout--) { DBGC(DC_SPI_SYNC_ENABLING); } | ||
69 | |||
70 | srdata.reg = 0; | ||
71 | srdata.bit.HUB_CONNECT = 0; | ||
72 | srdata.bit.HUB_RESET_N = 0; | ||
73 | srdata.bit.S_UP = 0; | ||
74 | srdata.bit.E_UP_N = 1; | ||
75 | srdata.bit.S_DN1 = 1; | ||
76 | srdata.bit.E_DN1_N = 1; | ||
77 | srdata.bit.E_VBUS_1 = 0; | ||
78 | srdata.bit.E_VBUS_2 = 0; | ||
79 | srdata.bit.SRC_1 = 1; | ||
80 | srdata.bit.SRC_2 = 1; | ||
81 | srdata.bit.IRST = 1; | ||
82 | srdata.bit.SDB_N = 0; | ||
83 | SPI_WriteSRData(); | ||
84 | |||
85 | //Enable register output | ||
86 | SC2_OE_ENA; | ||
87 | |||
88 | DBGC(DC_SPI_INIT_COMPLETE); | ||
89 | } | ||
90 | |||
diff --git a/tmk_core/protocol/arm_atsam/spi.h b/tmk_core/protocol/arm_atsam/spi.h new file mode 100644 index 000000000..3412dfc36 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/spi.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _SPI_H_ | ||
19 | #define _SPI_H_ | ||
20 | |||
21 | //TODO: PS: Should bring ports to keyboard configuration | ||
22 | |||
23 | #define SCSPI SERCOM2 | ||
24 | |||
25 | #define P14_DIR 0x00004000 /* PIN14 DIR Bit */ | ||
26 | #define P14_OUT 0x00004000 /* PIN14 OUT Bit */ | ||
27 | #define P15_DIR 0x00008000 /* PIN15 DIR Bit */ | ||
28 | #define P15_OUT 0x00008000 /* PIN15 OUT Bit */ | ||
29 | |||
30 | #define SC2_RCLCK_LO REG_PORT_OUTCLR1 = P14_OUT /* PB14 Low, SC2_RCLCK Low */ | ||
31 | #define SC2_RCLCK_HI REG_PORT_OUTSET1 = P14_OUT /* PB14 High, SC2_RCLCK High */ | ||
32 | #define SC2_OE_ENA REG_PORT_OUTCLR1 = P15_OUT /* PB15 Low, SC2_OE_N Low (Shift register enabled) */ | ||
33 | #define SC2_OE_DIS REG_PORT_OUTSET1 = P15_OUT /* PB15 High, SC2_OE_N High (Shift register disabled) */ | ||
34 | #define SC2_DIRSET REG_PORT_DIRSET1 = P14_DIR | P15_DIR; /* PB14 PB15 OUT */ | ||
35 | |||
36 | typedef union { | ||
37 | struct { | ||
38 | uint16_t RSVD4:1; /*!< bit: 0 */ | ||
39 | uint16_t RSVD3:1; /*!< bit: 1 */ | ||
40 | uint16_t RSVD2:1; /*!< bit: 2 */ | ||
41 | uint16_t RSVD1:1; /*!< bit: 3 */ | ||
42 | uint16_t SDB_N:1; /*!< bit: 4 SHUTDOWN THE CHIP WHEN 0, RUN WHEN 1 */ | ||
43 | uint16_t IRST:1; /*!< bit: 5 RESET THE IS3733 I2C WHEN 1, RUN WHEN 0 */ | ||
44 | uint16_t SRC_2:1; /*!< bit: 6 ADVERTISE A SOURCE TO USBC-2 CC */ | ||
45 | uint16_t SRC_1:1; /*!< bit: 7 ADVERTISE A SOURCE TO USBC-1 CC */ | ||
46 | uint16_t E_VBUS_2:1; /*!< bit: 8 ENABLE 5V OUT TO USBC-2 WHEN 1 */ | ||
47 | uint16_t E_VBUS_1:1; /*!< bit: 9 ENABLE 5V OUT TO USBC-1 WHEN 1 */ | ||
48 | uint16_t E_DN1_N:1; /*!< bit: 10 ENABLE DN1 1:2 MUX WHEN 0 */ | ||
49 | uint16_t S_DN1:1; /*!< bit: 11 SELECT DN1 PATH 0:USBC-1, 1:USBC-2 */ | ||
50 | uint16_t E_UP_N:1; /*!< bit: 12 ENABLE SUP 1:2 MUX WHEN 0 */ | ||
51 | uint16_t S_UP:1; /*!< bit: 13 SELECT UP PATH 0:USBC-1, 1:USBC-2 */ | ||
52 | uint16_t HUB_RESET_N:1; /*!< bit: 14 RESET USB HUB WHEN 0, RUN WHEN 1 */ | ||
53 | uint16_t HUB_CONNECT:1; /*!< bit: 15 SIGNAL VBUS CONNECT TO USB HUB WHEN 1 */ | ||
54 | } bit; /*!< Structure used for bit access */ | ||
55 | uint16_t reg; /*!< Type used for register access */ | ||
56 | } Srdata_t; | ||
57 | |||
58 | extern Srdata_t srdata; | ||
59 | |||
60 | void SPI_WriteSRData(void); | ||
61 | void SPI_Init(void); | ||
62 | |||
63 | #endif //_SPI_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/startup.c b/tmk_core/protocol/arm_atsam/startup.c new file mode 100644 index 000000000..a62d02f1c --- /dev/null +++ b/tmk_core/protocol/arm_atsam/startup.c | |||
@@ -0,0 +1,548 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief gcc starttup file for SAMD51 | ||
5 | * | ||
6 | * Copyright (c) 2017 Microchip Technology Inc. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * SPDX-License-Identifier: Apache-2.0 | ||
13 | * | ||
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
15 | * not use this file except in compliance with the License. | ||
16 | * You may obtain a copy of the Licence at | ||
17 | * | ||
18 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
19 | * | ||
20 | * Unless required by applicable law or agreed to in writing, software | ||
21 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT | ||
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
23 | * See the License for the specific language governing permissions and | ||
24 | * limitations under the License. | ||
25 | * | ||
26 | * \asf_license_stop | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include "samd51.h" | ||
31 | |||
32 | /* Initialize segments */ | ||
33 | extern uint32_t _sfixed; | ||
34 | extern uint32_t _efixed; | ||
35 | extern uint32_t _etext; | ||
36 | extern uint32_t _srelocate; | ||
37 | extern uint32_t _erelocate; | ||
38 | extern uint32_t _szero; | ||
39 | extern uint32_t _ezero; | ||
40 | extern uint32_t _sstack; | ||
41 | extern uint32_t _estack; | ||
42 | |||
43 | /** \cond DOXYGEN_SHOULD_SKIP_THIS */ | ||
44 | int main(void); | ||
45 | /** \endcond */ | ||
46 | |||
47 | void __libc_init_array(void); | ||
48 | |||
49 | /* Default empty handler */ | ||
50 | void Dummy_Handler(void); | ||
51 | |||
52 | /* Cortex-M4 core handlers */ | ||
53 | void NMI_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
54 | void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
55 | void MemManage_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
56 | void BusFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
57 | void UsageFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
58 | void SVC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
59 | void DebugMon_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
60 | void PendSV_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
61 | void SysTick_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
62 | |||
63 | /* Peripherals handlers */ | ||
64 | void PM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
65 | void MCLK_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
66 | void OSCCTRL_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* OSCCTRL_XOSCFAIL_0, OSCCTRL_XOSCRDY_0 */ | ||
67 | void OSCCTRL_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* OSCCTRL_XOSCFAIL_1, OSCCTRL_XOSCRDY_1 */ | ||
68 | void OSCCTRL_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* OSCCTRL_DFLLLOCKC, OSCCTRL_DFLLLOCKF, OSCCTRL_DFLLOOB, OSCCTRL_DFLLRCS, OSCCTRL_DFLLRDY */ | ||
69 | void OSCCTRL_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* OSCCTRL_DPLLLCKF_0, OSCCTRL_DPLLLCKR_0, OSCCTRL_DPLLLDRTO_0, OSCCTRL_DPLLLTO_0 */ | ||
70 | void OSCCTRL_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* OSCCTRL_DPLLLCKF_1, OSCCTRL_DPLLLCKR_1, OSCCTRL_DPLLLDRTO_1, OSCCTRL_DPLLLTO_1 */ | ||
71 | void OSC32KCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
72 | void SUPC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SUPC_B12SRDY, SUPC_B33SRDY, SUPC_BOD12RDY, SUPC_BOD33RDY, SUPC_VCORERDY, SUPC_VREGRDY */ | ||
73 | void SUPC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SUPC_BOD12DET, SUPC_BOD33DET */ | ||
74 | void WDT_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
75 | void RTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
76 | void EIC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_0 */ | ||
77 | void EIC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_1 */ | ||
78 | void EIC_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_2 */ | ||
79 | void EIC_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_3 */ | ||
80 | void EIC_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_4 */ | ||
81 | void EIC_5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_5 */ | ||
82 | void EIC_6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_6 */ | ||
83 | void EIC_7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_7 */ | ||
84 | void EIC_8_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_8 */ | ||
85 | void EIC_9_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_9 */ | ||
86 | void EIC_10_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_10 */ | ||
87 | void EIC_11_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_11 */ | ||
88 | void EIC_12_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_12 */ | ||
89 | void EIC_13_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_13 */ | ||
90 | void EIC_14_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_14 */ | ||
91 | void EIC_15_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EIC_EXTINT_15 */ | ||
92 | void FREQM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
93 | void NVMCTRL_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* NVMCTRL_0, NVMCTRL_1, NVMCTRL_2, NVMCTRL_3, NVMCTRL_4, NVMCTRL_5, NVMCTRL_6, NVMCTRL_7 */ | ||
94 | void NVMCTRL_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* NVMCTRL_10, NVMCTRL_8, NVMCTRL_9 */ | ||
95 | void DMAC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DMAC_SUSP_0, DMAC_TCMPL_0, DMAC_TERR_0 */ | ||
96 | void DMAC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DMAC_SUSP_1, DMAC_TCMPL_1, DMAC_TERR_1 */ | ||
97 | void DMAC_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DMAC_SUSP_2, DMAC_TCMPL_2, DMAC_TERR_2 */ | ||
98 | void DMAC_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DMAC_SUSP_3, DMAC_TCMPL_3, DMAC_TERR_3 */ | ||
99 | void DMAC_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DMAC_SUSP_10, DMAC_SUSP_11, DMAC_SUSP_12, DMAC_SUSP_13, DMAC_SUSP_14, DMAC_SUSP_15, DMAC_SUSP_16, DMAC_SUSP_17, DMAC_SUSP_18, DMAC_SUSP_19, DMAC_SUSP_20, DMAC_SUSP_21, DMAC_SUSP_22, DMAC_SUSP_23, DMAC_SUSP_24, DMAC_SUSP_25, DMAC_SUSP_26, DMAC_SUSP_27, DMAC_SUSP_28, DMAC_SUSP_29, DMAC_SUSP_30, DMAC_SUSP_31, DMAC_SUSP_4, DMAC_SUSP_5, DMAC_SUSP_6, DMAC_SUSP_7, DMAC_SUSP_8, DMAC_SUSP_9, DMAC_TCMPL_10, DMAC_TCMPL_11, DMAC_TCMPL_12, DMAC_TCMPL_13, DMAC_TCMPL_14, DMAC_TCMPL_15, DMAC_TCMPL_16, DMAC_TCMPL_17, DMAC_TCMPL_18, DMAC_TCMPL_19, DMAC_TCMPL_20, DMAC_TCMPL_21, DMAC_TCMPL_22, DMAC_TCMPL_23, DMAC_TCMPL_24, DMAC_TCMPL_25, DMAC_TCMPL_26, DMAC_TCMPL_27, DMAC_TCMPL_28, DMAC_TCMPL_29, DMAC_TCMPL_30, DMAC_TCMPL_31, DMAC_TCMPL_4, DMAC_TCMPL_5, DMAC_TCMPL_6, DMAC_TCMPL_7, DMAC_TCMPL_8, DMAC_TCMPL_9, DMAC_TERR_10, DMAC_TERR_11, DMAC_TERR_12, DMAC_TERR_13, DMAC_TERR_14, DMAC_TERR_15, DMAC_TERR_16, DMAC_TERR_17, DMAC_TERR_18, DMAC_TERR_19, DMAC_TERR_20, DMAC_TERR_21, DMAC_TERR_22, DMAC_TERR_23, DMAC_TERR_24, DMAC_TERR_25, DMAC_TERR_26, DMAC_TERR_27, DMAC_TERR_28, DMAC_TERR_29, DMAC_TERR_30, DMAC_TERR_31, DMAC_TERR_4, DMAC_TERR_5, DMAC_TERR_6, DMAC_TERR_7, DMAC_TERR_8, DMAC_TERR_9 */ | ||
100 | void EVSYS_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EVSYS_EVD_0, EVSYS_OVR_0 */ | ||
101 | void EVSYS_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EVSYS_EVD_1, EVSYS_OVR_1 */ | ||
102 | void EVSYS_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EVSYS_EVD_2, EVSYS_OVR_2 */ | ||
103 | void EVSYS_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EVSYS_EVD_3, EVSYS_OVR_3 */ | ||
104 | void EVSYS_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* EVSYS_EVD_10, EVSYS_EVD_11, EVSYS_EVD_4, EVSYS_EVD_5, EVSYS_EVD_6, EVSYS_EVD_7, EVSYS_EVD_8, EVSYS_EVD_9, EVSYS_OVR_10, EVSYS_OVR_11, EVSYS_OVR_4, EVSYS_OVR_5, EVSYS_OVR_6, EVSYS_OVR_7, EVSYS_OVR_8, EVSYS_OVR_9 */ | ||
105 | void PAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
106 | void TAL_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TAL_BRK */ | ||
107 | void TAL_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TAL_IPS_0, TAL_IPS_1 */ | ||
108 | void RAMECC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
109 | void SERCOM0_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM0_0 */ | ||
110 | void SERCOM0_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM0_1 */ | ||
111 | void SERCOM0_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM0_2 */ | ||
112 | void SERCOM0_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM0_3, SERCOM0_4, SERCOM0_5, SERCOM0_6 */ | ||
113 | void SERCOM1_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM1_0 */ | ||
114 | void SERCOM1_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM1_1 */ | ||
115 | void SERCOM1_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM1_2 */ | ||
116 | void SERCOM1_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM1_3, SERCOM1_4, SERCOM1_5, SERCOM1_6 */ | ||
117 | void SERCOM2_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM2_0 */ | ||
118 | void SERCOM2_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM2_1 */ | ||
119 | void SERCOM2_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM2_2 */ | ||
120 | void SERCOM2_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM2_3, SERCOM2_4, SERCOM2_5, SERCOM2_6 */ | ||
121 | void SERCOM3_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM3_0 */ | ||
122 | void SERCOM3_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM3_1 */ | ||
123 | void SERCOM3_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM3_2 */ | ||
124 | void SERCOM3_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM3_3, SERCOM3_4, SERCOM3_5, SERCOM3_6 */ | ||
125 | #ifdef ID_SERCOM4 | ||
126 | void SERCOM4_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM4_0 */ | ||
127 | void SERCOM4_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM4_1 */ | ||
128 | void SERCOM4_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM4_2 */ | ||
129 | void SERCOM4_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM4_3, SERCOM4_4, SERCOM4_5, SERCOM4_6 */ | ||
130 | #endif | ||
131 | #ifdef ID_SERCOM5 | ||
132 | void SERCOM5_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM5_0 */ | ||
133 | void SERCOM5_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM5_1 */ | ||
134 | void SERCOM5_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM5_2 */ | ||
135 | void SERCOM5_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM5_3, SERCOM5_4, SERCOM5_5, SERCOM5_6 */ | ||
136 | #endif | ||
137 | #ifdef ID_SERCOM6 | ||
138 | void SERCOM6_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM6_0 */ | ||
139 | void SERCOM6_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM6_1 */ | ||
140 | void SERCOM6_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM6_2 */ | ||
141 | void SERCOM6_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM6_3, SERCOM6_4, SERCOM6_5, SERCOM6_6 */ | ||
142 | #endif | ||
143 | #ifdef ID_SERCOM7 | ||
144 | void SERCOM7_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM7_0 */ | ||
145 | void SERCOM7_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM7_1 */ | ||
146 | void SERCOM7_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM7_2 */ | ||
147 | void SERCOM7_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* SERCOM7_3, SERCOM7_4, SERCOM7_5, SERCOM7_6 */ | ||
148 | #endif | ||
149 | #ifdef ID_CAN0 | ||
150 | void CAN0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
151 | #endif | ||
152 | #ifdef ID_CAN1 | ||
153 | void CAN1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
154 | #endif | ||
155 | #ifdef ID_USB | ||
156 | void USB_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* USB_EORSM_DNRSM, USB_EORST_RST, USB_LPMSUSP_DDISC, USB_LPM_DCONN, USB_MSOF, USB_RAMACER, USB_RXSTP_TXSTP_0, USB_RXSTP_TXSTP_1, USB_RXSTP_TXSTP_2, USB_RXSTP_TXSTP_3, USB_RXSTP_TXSTP_4, USB_RXSTP_TXSTP_5, USB_RXSTP_TXSTP_6, USB_RXSTP_TXSTP_7, USB_STALL0_STALL_0, USB_STALL0_STALL_1, USB_STALL0_STALL_2, USB_STALL0_STALL_3, USB_STALL0_STALL_4, USB_STALL0_STALL_5, USB_STALL0_STALL_6, USB_STALL0_STALL_7, USB_STALL1_0, USB_STALL1_1, USB_STALL1_2, USB_STALL1_3, USB_STALL1_4, USB_STALL1_5, USB_STALL1_6, USB_STALL1_7, USB_SUSPEND, USB_TRFAIL0_TRFAIL_0, USB_TRFAIL0_TRFAIL_1, USB_TRFAIL0_TRFAIL_2, USB_TRFAIL0_TRFAIL_3, USB_TRFAIL0_TRFAIL_4, USB_TRFAIL0_TRFAIL_5, USB_TRFAIL0_TRFAIL_6, USB_TRFAIL0_TRFAIL_7, USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2, USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5, USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */ | ||
157 | void USB_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* USB_SOF_HSOF */ | ||
158 | void USB_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* USB_TRCPT0_0, USB_TRCPT0_1, USB_TRCPT0_2, USB_TRCPT0_3, USB_TRCPT0_4, USB_TRCPT0_5, USB_TRCPT0_6, USB_TRCPT0_7 */ | ||
159 | void USB_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* USB_TRCPT1_0, USB_TRCPT1_1, USB_TRCPT1_2, USB_TRCPT1_3, USB_TRCPT1_4, USB_TRCPT1_5, USB_TRCPT1_6, USB_TRCPT1_7 */ | ||
160 | #endif | ||
161 | #ifdef ID_GMAC | ||
162 | void GMAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
163 | #endif | ||
164 | void TCC0_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC0_CNT_A, TCC0_DFS_A, TCC0_ERR_A, TCC0_FAULT0_A, TCC0_FAULT1_A, TCC0_FAULTA_A, TCC0_FAULTB_A, TCC0_OVF, TCC0_TRG, TCC0_UFS_A */ | ||
165 | void TCC0_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC0_MC_0 */ | ||
166 | void TCC0_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC0_MC_1 */ | ||
167 | void TCC0_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC0_MC_2 */ | ||
168 | void TCC0_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC0_MC_3 */ | ||
169 | void TCC0_5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC0_MC_4 */ | ||
170 | void TCC0_6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC0_MC_5 */ | ||
171 | void TCC1_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC1_CNT_A, TCC1_DFS_A, TCC1_ERR_A, TCC1_FAULT0_A, TCC1_FAULT1_A, TCC1_FAULTA_A, TCC1_FAULTB_A, TCC1_OVF, TCC1_TRG, TCC1_UFS_A */ | ||
172 | void TCC1_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC1_MC_0 */ | ||
173 | void TCC1_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC1_MC_1 */ | ||
174 | void TCC1_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC1_MC_2 */ | ||
175 | void TCC1_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC1_MC_3 */ | ||
176 | void TCC2_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC2_CNT_A, TCC2_DFS_A, TCC2_ERR_A, TCC2_FAULT0_A, TCC2_FAULT1_A, TCC2_FAULTA_A, TCC2_FAULTB_A, TCC2_OVF, TCC2_TRG, TCC2_UFS_A */ | ||
177 | void TCC2_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC2_MC_0 */ | ||
178 | void TCC2_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC2_MC_1 */ | ||
179 | void TCC2_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC2_MC_2 */ | ||
180 | #ifdef ID_TCC3 | ||
181 | void TCC3_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC3_CNT_A, TCC3_DFS_A, TCC3_ERR_A, TCC3_FAULT0_A, TCC3_FAULT1_A, TCC3_FAULTA_A, TCC3_FAULTB_A, TCC3_OVF, TCC3_TRG, TCC3_UFS_A */ | ||
182 | void TCC3_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC3_MC_0 */ | ||
183 | void TCC3_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC3_MC_1 */ | ||
184 | #endif | ||
185 | #ifdef ID_TCC4 | ||
186 | void TCC4_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC4_CNT_A, TCC4_DFS_A, TCC4_ERR_A, TCC4_FAULT0_A, TCC4_FAULT1_A, TCC4_FAULTA_A, TCC4_FAULTB_A, TCC4_OVF, TCC4_TRG, TCC4_UFS_A */ | ||
187 | void TCC4_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC4_MC_0 */ | ||
188 | void TCC4_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* TCC4_MC_1 */ | ||
189 | #endif | ||
190 | void TC0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
191 | void TC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
192 | void TC2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
193 | void TC3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
194 | #ifdef ID_TC4 | ||
195 | void TC4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
196 | #endif | ||
197 | #ifdef ID_TC5 | ||
198 | void TC5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
199 | #endif | ||
200 | #ifdef ID_TC6 | ||
201 | void TC6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
202 | #endif | ||
203 | #ifdef ID_TC7 | ||
204 | void TC7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
205 | #endif | ||
206 | void PDEC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* PDEC_DIR_A, PDEC_ERR_A, PDEC_OVF, PDEC_VLC_A */ | ||
207 | void PDEC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* PDEC_MC_0 */ | ||
208 | void PDEC_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* PDEC_MC_1 */ | ||
209 | void ADC0_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* ADC0_OVERRUN, ADC0_WINMON */ | ||
210 | void ADC0_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* ADC0_RESRDY */ | ||
211 | void ADC1_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* ADC1_OVERRUN, ADC1_WINMON */ | ||
212 | void ADC1_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* ADC1_RESRDY */ | ||
213 | void AC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
214 | void DAC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DAC_OVERRUN_A_0, DAC_OVERRUN_A_1, DAC_UNDERRUN_A_0, DAC_UNDERRUN_A_1 */ | ||
215 | void DAC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DAC_EMPTY_0 */ | ||
216 | void DAC_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DAC_EMPTY_1 */ | ||
217 | void DAC_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DAC_RESRDY_0 */ | ||
218 | void DAC_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* DAC_RESRDY_1 */ | ||
219 | #ifdef ID_I2S | ||
220 | void I2S_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
221 | #endif | ||
222 | void PCC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
223 | void AES_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
224 | void TRNG_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
225 | #ifdef ID_ICM | ||
226 | void ICM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
227 | #endif | ||
228 | #ifdef ID_PUKCC | ||
229 | void PUKCC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
230 | #endif | ||
231 | void QSPI_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
232 | #ifdef ID_SDHC0 | ||
233 | void SDHC0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
234 | #endif | ||
235 | #ifdef ID_SDHC1 | ||
236 | void SDHC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); | ||
237 | #endif | ||
238 | |||
239 | /* Exception Table */ | ||
240 | __attribute__ ((section(".vectors"))) | ||
241 | const DeviceVectors exception_table = { | ||
242 | |||
243 | /* Configure Initial Stack Pointer, using linker-generated symbols */ | ||
244 | .pvStack = (void*) (&_estack), | ||
245 | |||
246 | .pfnReset_Handler = (void*) Reset_Handler, | ||
247 | .pfnNMI_Handler = (void*) NMI_Handler, | ||
248 | .pfnHardFault_Handler = (void*) HardFault_Handler, | ||
249 | .pfnMemManage_Handler = (void*) MemManage_Handler, | ||
250 | .pfnBusFault_Handler = (void*) BusFault_Handler, | ||
251 | .pfnUsageFault_Handler = (void*) UsageFault_Handler, | ||
252 | .pvReservedM9 = (void*) (0UL), /* Reserved */ | ||
253 | .pvReservedM8 = (void*) (0UL), /* Reserved */ | ||
254 | .pvReservedM7 = (void*) (0UL), /* Reserved */ | ||
255 | .pvReservedM6 = (void*) (0UL), /* Reserved */ | ||
256 | .pfnSVC_Handler = (void*) SVC_Handler, | ||
257 | .pfnDebugMon_Handler = (void*) DebugMon_Handler, | ||
258 | .pvReservedM3 = (void*) (0UL), /* Reserved */ | ||
259 | .pfnPendSV_Handler = (void*) PendSV_Handler, | ||
260 | .pfnSysTick_Handler = (void*) SysTick_Handler, | ||
261 | |||
262 | /* Configurable interrupts */ | ||
263 | .pfnPM_Handler = (void*) PM_Handler, /* 0 Power Manager */ | ||
264 | .pfnMCLK_Handler = (void*) MCLK_Handler, /* 1 Main Clock */ | ||
265 | .pfnOSCCTRL_0_Handler = (void*) OSCCTRL_0_Handler, /* 2 OSCCTRL_XOSCFAIL_0, OSCCTRL_XOSCRDY_0 */ | ||
266 | .pfnOSCCTRL_1_Handler = (void*) OSCCTRL_1_Handler, /* 3 OSCCTRL_XOSCFAIL_1, OSCCTRL_XOSCRDY_1 */ | ||
267 | .pfnOSCCTRL_2_Handler = (void*) OSCCTRL_2_Handler, /* 4 OSCCTRL_DFLLLOCKC, OSCCTRL_DFLLLOCKF, OSCCTRL_DFLLOOB, OSCCTRL_DFLLRCS, OSCCTRL_DFLLRDY */ | ||
268 | .pfnOSCCTRL_3_Handler = (void*) OSCCTRL_3_Handler, /* 5 OSCCTRL_DPLLLCKF_0, OSCCTRL_DPLLLCKR_0, OSCCTRL_DPLLLDRTO_0, OSCCTRL_DPLLLTO_0 */ | ||
269 | .pfnOSCCTRL_4_Handler = (void*) OSCCTRL_4_Handler, /* 6 OSCCTRL_DPLLLCKF_1, OSCCTRL_DPLLLCKR_1, OSCCTRL_DPLLLDRTO_1, OSCCTRL_DPLLLTO_1 */ | ||
270 | .pfnOSC32KCTRL_Handler = (void*) OSC32KCTRL_Handler, /* 7 32kHz Oscillators Control */ | ||
271 | .pfnSUPC_0_Handler = (void*) SUPC_0_Handler, /* 8 SUPC_B12SRDY, SUPC_B33SRDY, SUPC_BOD12RDY, SUPC_BOD33RDY, SUPC_VCORERDY, SUPC_VREGRDY */ | ||
272 | .pfnSUPC_1_Handler = (void*) SUPC_1_Handler, /* 9 SUPC_BOD12DET, SUPC_BOD33DET */ | ||
273 | .pfnWDT_Handler = (void*) WDT_Handler, /* 10 Watchdog Timer */ | ||
274 | .pfnRTC_Handler = (void*) RTC_Handler, /* 11 Real-Time Counter */ | ||
275 | .pfnEIC_0_Handler = (void*) EIC_0_Handler, /* 12 EIC_EXTINT_0 */ | ||
276 | .pfnEIC_1_Handler = (void*) EIC_1_Handler, /* 13 EIC_EXTINT_1 */ | ||
277 | .pfnEIC_2_Handler = (void*) EIC_2_Handler, /* 14 EIC_EXTINT_2 */ | ||
278 | .pfnEIC_3_Handler = (void*) EIC_3_Handler, /* 15 EIC_EXTINT_3 */ | ||
279 | .pfnEIC_4_Handler = (void*) EIC_4_Handler, /* 16 EIC_EXTINT_4 */ | ||
280 | .pfnEIC_5_Handler = (void*) EIC_5_Handler, /* 17 EIC_EXTINT_5 */ | ||
281 | .pfnEIC_6_Handler = (void*) EIC_6_Handler, /* 18 EIC_EXTINT_6 */ | ||
282 | .pfnEIC_7_Handler = (void*) EIC_7_Handler, /* 19 EIC_EXTINT_7 */ | ||
283 | .pfnEIC_8_Handler = (void*) EIC_8_Handler, /* 20 EIC_EXTINT_8 */ | ||
284 | .pfnEIC_9_Handler = (void*) EIC_9_Handler, /* 21 EIC_EXTINT_9 */ | ||
285 | .pfnEIC_10_Handler = (void*) EIC_10_Handler, /* 22 EIC_EXTINT_10 */ | ||
286 | .pfnEIC_11_Handler = (void*) EIC_11_Handler, /* 23 EIC_EXTINT_11 */ | ||
287 | .pfnEIC_12_Handler = (void*) EIC_12_Handler, /* 24 EIC_EXTINT_12 */ | ||
288 | .pfnEIC_13_Handler = (void*) EIC_13_Handler, /* 25 EIC_EXTINT_13 */ | ||
289 | .pfnEIC_14_Handler = (void*) EIC_14_Handler, /* 26 EIC_EXTINT_14 */ | ||
290 | .pfnEIC_15_Handler = (void*) EIC_15_Handler, /* 27 EIC_EXTINT_15 */ | ||
291 | .pfnFREQM_Handler = (void*) FREQM_Handler, /* 28 Frequency Meter */ | ||
292 | .pfnNVMCTRL_0_Handler = (void*) NVMCTRL_0_Handler, /* 29 NVMCTRL_0, NVMCTRL_1, NVMCTRL_2, NVMCTRL_3, NVMCTRL_4, NVMCTRL_5, NVMCTRL_6, NVMCTRL_7 */ | ||
293 | .pfnNVMCTRL_1_Handler = (void*) NVMCTRL_1_Handler, /* 30 NVMCTRL_10, NVMCTRL_8, NVMCTRL_9 */ | ||
294 | .pfnDMAC_0_Handler = (void*) DMAC_0_Handler, /* 31 DMAC_SUSP_0, DMAC_TCMPL_0, DMAC_TERR_0 */ | ||
295 | .pfnDMAC_1_Handler = (void*) DMAC_1_Handler, /* 32 DMAC_SUSP_1, DMAC_TCMPL_1, DMAC_TERR_1 */ | ||
296 | .pfnDMAC_2_Handler = (void*) DMAC_2_Handler, /* 33 DMAC_SUSP_2, DMAC_TCMPL_2, DMAC_TERR_2 */ | ||
297 | .pfnDMAC_3_Handler = (void*) DMAC_3_Handler, /* 34 DMAC_SUSP_3, DMAC_TCMPL_3, DMAC_TERR_3 */ | ||
298 | .pfnDMAC_4_Handler = (void*) DMAC_4_Handler, /* 35 DMAC_SUSP_10, DMAC_SUSP_11, DMAC_SUSP_12, DMAC_SUSP_13, DMAC_SUSP_14, DMAC_SUSP_15, DMAC_SUSP_16, DMAC_SUSP_17, DMAC_SUSP_18, DMAC_SUSP_19, DMAC_SUSP_20, DMAC_SUSP_21, DMAC_SUSP_22, DMAC_SUSP_23, DMAC_SUSP_24, DMAC_SUSP_25, DMAC_SUSP_26, DMAC_SUSP_27, DMAC_SUSP_28, DMAC_SUSP_29, DMAC_SUSP_30, DMAC_SUSP_31, DMAC_SUSP_4, DMAC_SUSP_5, DMAC_SUSP_6, DMAC_SUSP_7, DMAC_SUSP_8, DMAC_SUSP_9, DMAC_TCMPL_10, DMAC_TCMPL_11, DMAC_TCMPL_12, DMAC_TCMPL_13, DMAC_TCMPL_14, DMAC_TCMPL_15, DMAC_TCMPL_16, DMAC_TCMPL_17, DMAC_TCMPL_18, DMAC_TCMPL_19, DMAC_TCMPL_20, DMAC_TCMPL_21, DMAC_TCMPL_22, DMAC_TCMPL_23, DMAC_TCMPL_24, DMAC_TCMPL_25, DMAC_TCMPL_26, DMAC_TCMPL_27, DMAC_TCMPL_28, DMAC_TCMPL_29, DMAC_TCMPL_30, DMAC_TCMPL_31, DMAC_TCMPL_4, DMAC_TCMPL_5, DMAC_TCMPL_6, DMAC_TCMPL_7, DMAC_TCMPL_8, DMAC_TCMPL_9, DMAC_TERR_10, DMAC_TERR_11, DMAC_TERR_12, DMAC_TERR_13, DMAC_TERR_14, DMAC_TERR_15, DMAC_TERR_16, DMAC_TERR_17, DMAC_TERR_18, DMAC_TERR_19, DMAC_TERR_20, DMAC_TERR_21, DMAC_TERR_22, DMAC_TERR_23, DMAC_TERR_24, DMAC_TERR_25, DMAC_TERR_26, DMAC_TERR_27, DMAC_TERR_28, DMAC_TERR_29, DMAC_TERR_30, DMAC_TERR_31, DMAC_TERR_4, DMAC_TERR_5, DMAC_TERR_6, DMAC_TERR_7, DMAC_TERR_8, DMAC_TERR_9 */ | ||
299 | .pfnEVSYS_0_Handler = (void*) EVSYS_0_Handler, /* 36 EVSYS_EVD_0, EVSYS_OVR_0 */ | ||
300 | .pfnEVSYS_1_Handler = (void*) EVSYS_1_Handler, /* 37 EVSYS_EVD_1, EVSYS_OVR_1 */ | ||
301 | .pfnEVSYS_2_Handler = (void*) EVSYS_2_Handler, /* 38 EVSYS_EVD_2, EVSYS_OVR_2 */ | ||
302 | .pfnEVSYS_3_Handler = (void*) EVSYS_3_Handler, /* 39 EVSYS_EVD_3, EVSYS_OVR_3 */ | ||
303 | .pfnEVSYS_4_Handler = (void*) EVSYS_4_Handler, /* 40 EVSYS_EVD_10, EVSYS_EVD_11, EVSYS_EVD_4, EVSYS_EVD_5, EVSYS_EVD_6, EVSYS_EVD_7, EVSYS_EVD_8, EVSYS_EVD_9, EVSYS_OVR_10, EVSYS_OVR_11, EVSYS_OVR_4, EVSYS_OVR_5, EVSYS_OVR_6, EVSYS_OVR_7, EVSYS_OVR_8, EVSYS_OVR_9 */ | ||
304 | .pfnPAC_Handler = (void*) PAC_Handler, /* 41 Peripheral Access Controller */ | ||
305 | .pfnTAL_0_Handler = (void*) TAL_0_Handler, /* 42 TAL_BRK */ | ||
306 | .pfnTAL_1_Handler = (void*) TAL_1_Handler, /* 43 TAL_IPS_0, TAL_IPS_1 */ | ||
307 | .pvReserved44 = (void*) (0UL), /* 44 Reserved */ | ||
308 | .pfnRAMECC_Handler = (void*) RAMECC_Handler, /* 45 RAM ECC */ | ||
309 | .pfnSERCOM0_0_Handler = (void*) SERCOM0_0_Handler, /* 46 SERCOM0_0 */ | ||
310 | .pfnSERCOM0_1_Handler = (void*) SERCOM0_1_Handler, /* 47 SERCOM0_1 */ | ||
311 | .pfnSERCOM0_2_Handler = (void*) SERCOM0_2_Handler, /* 48 SERCOM0_2 */ | ||
312 | .pfnSERCOM0_3_Handler = (void*) SERCOM0_3_Handler, /* 49 SERCOM0_3, SERCOM0_4, SERCOM0_5, SERCOM0_6 */ | ||
313 | .pfnSERCOM1_0_Handler = (void*) SERCOM1_0_Handler, /* 50 SERCOM1_0 */ | ||
314 | .pfnSERCOM1_1_Handler = (void*) SERCOM1_1_Handler, /* 51 SERCOM1_1 */ | ||
315 | .pfnSERCOM1_2_Handler = (void*) SERCOM1_2_Handler, /* 52 SERCOM1_2 */ | ||
316 | .pfnSERCOM1_3_Handler = (void*) SERCOM1_3_Handler, /* 53 SERCOM1_3, SERCOM1_4, SERCOM1_5, SERCOM1_6 */ | ||
317 | .pfnSERCOM2_0_Handler = (void*) SERCOM2_0_Handler, /* 54 SERCOM2_0 */ | ||
318 | .pfnSERCOM2_1_Handler = (void*) SERCOM2_1_Handler, /* 55 SERCOM2_1 */ | ||
319 | .pfnSERCOM2_2_Handler = (void*) SERCOM2_2_Handler, /* 56 SERCOM2_2 */ | ||
320 | .pfnSERCOM2_3_Handler = (void*) SERCOM2_3_Handler, /* 57 SERCOM2_3, SERCOM2_4, SERCOM2_5, SERCOM2_6 */ | ||
321 | .pfnSERCOM3_0_Handler = (void*) SERCOM3_0_Handler, /* 58 SERCOM3_0 */ | ||
322 | .pfnSERCOM3_1_Handler = (void*) SERCOM3_1_Handler, /* 59 SERCOM3_1 */ | ||
323 | .pfnSERCOM3_2_Handler = (void*) SERCOM3_2_Handler, /* 60 SERCOM3_2 */ | ||
324 | .pfnSERCOM3_3_Handler = (void*) SERCOM3_3_Handler, /* 61 SERCOM3_3, SERCOM3_4, SERCOM3_5, SERCOM3_6 */ | ||
325 | #ifdef ID_SERCOM4 | ||
326 | .pfnSERCOM4_0_Handler = (void*) SERCOM4_0_Handler, /* 62 SERCOM4_0 */ | ||
327 | .pfnSERCOM4_1_Handler = (void*) SERCOM4_1_Handler, /* 63 SERCOM4_1 */ | ||
328 | .pfnSERCOM4_2_Handler = (void*) SERCOM4_2_Handler, /* 64 SERCOM4_2 */ | ||
329 | .pfnSERCOM4_3_Handler = (void*) SERCOM4_3_Handler, /* 65 SERCOM4_3, SERCOM4_4, SERCOM4_5, SERCOM4_6 */ | ||
330 | #else | ||
331 | .pvReserved62 = (void*) (0UL), /* 62 Reserved */ | ||
332 | .pvReserved63 = (void*) (0UL), /* 63 Reserved */ | ||
333 | .pvReserved64 = (void*) (0UL), /* 64 Reserved */ | ||
334 | .pvReserved65 = (void*) (0UL), /* 65 Reserved */ | ||
335 | #endif | ||
336 | #ifdef ID_SERCOM5 | ||
337 | .pfnSERCOM5_0_Handler = (void*) SERCOM5_0_Handler, /* 66 SERCOM5_0 */ | ||
338 | .pfnSERCOM5_1_Handler = (void*) SERCOM5_1_Handler, /* 67 SERCOM5_1 */ | ||
339 | .pfnSERCOM5_2_Handler = (void*) SERCOM5_2_Handler, /* 68 SERCOM5_2 */ | ||
340 | .pfnSERCOM5_3_Handler = (void*) SERCOM5_3_Handler, /* 69 SERCOM5_3, SERCOM5_4, SERCOM5_5, SERCOM5_6 */ | ||
341 | #else | ||
342 | .pvReserved66 = (void*) (0UL), /* 66 Reserved */ | ||
343 | .pvReserved67 = (void*) (0UL), /* 67 Reserved */ | ||
344 | .pvReserved68 = (void*) (0UL), /* 68 Reserved */ | ||
345 | .pvReserved69 = (void*) (0UL), /* 69 Reserved */ | ||
346 | #endif | ||
347 | #ifdef ID_SERCOM6 | ||
348 | .pfnSERCOM6_0_Handler = (void*) SERCOM6_0_Handler, /* 70 SERCOM6_0 */ | ||
349 | .pfnSERCOM6_1_Handler = (void*) SERCOM6_1_Handler, /* 71 SERCOM6_1 */ | ||
350 | .pfnSERCOM6_2_Handler = (void*) SERCOM6_2_Handler, /* 72 SERCOM6_2 */ | ||
351 | .pfnSERCOM6_3_Handler = (void*) SERCOM6_3_Handler, /* 73 SERCOM6_3, SERCOM6_4, SERCOM6_5, SERCOM6_6 */ | ||
352 | #else | ||
353 | .pvReserved70 = (void*) (0UL), /* 70 Reserved */ | ||
354 | .pvReserved71 = (void*) (0UL), /* 71 Reserved */ | ||
355 | .pvReserved72 = (void*) (0UL), /* 72 Reserved */ | ||
356 | .pvReserved73 = (void*) (0UL), /* 73 Reserved */ | ||
357 | #endif | ||
358 | #ifdef ID_SERCOM7 | ||
359 | .pfnSERCOM7_0_Handler = (void*) SERCOM7_0_Handler, /* 74 SERCOM7_0 */ | ||
360 | .pfnSERCOM7_1_Handler = (void*) SERCOM7_1_Handler, /* 75 SERCOM7_1 */ | ||
361 | .pfnSERCOM7_2_Handler = (void*) SERCOM7_2_Handler, /* 76 SERCOM7_2 */ | ||
362 | .pfnSERCOM7_3_Handler = (void*) SERCOM7_3_Handler, /* 77 SERCOM7_3, SERCOM7_4, SERCOM7_5, SERCOM7_6 */ | ||
363 | #else | ||
364 | .pvReserved74 = (void*) (0UL), /* 74 Reserved */ | ||
365 | .pvReserved75 = (void*) (0UL), /* 75 Reserved */ | ||
366 | .pvReserved76 = (void*) (0UL), /* 76 Reserved */ | ||
367 | .pvReserved77 = (void*) (0UL), /* 77 Reserved */ | ||
368 | #endif | ||
369 | #ifdef ID_CAN0 | ||
370 | .pfnCAN0_Handler = (void*) CAN0_Handler, /* 78 Control Area Network 0 */ | ||
371 | #else | ||
372 | .pvReserved78 = (void*) (0UL), /* 78 Reserved */ | ||
373 | #endif | ||
374 | #ifdef ID_CAN1 | ||
375 | .pfnCAN1_Handler = (void*) CAN1_Handler, /* 79 Control Area Network 1 */ | ||
376 | #else | ||
377 | .pvReserved79 = (void*) (0UL), /* 79 Reserved */ | ||
378 | #endif | ||
379 | #ifdef ID_USB | ||
380 | .pfnUSB_0_Handler = (void*) USB_0_Handler, /* 80 USB_EORSM_DNRSM, USB_EORST_RST, USB_LPMSUSP_DDISC, USB_LPM_DCONN, USB_MSOF, USB_RAMACER, USB_RXSTP_TXSTP_0, USB_RXSTP_TXSTP_1, USB_RXSTP_TXSTP_2, USB_RXSTP_TXSTP_3, USB_RXSTP_TXSTP_4, USB_RXSTP_TXSTP_5, USB_RXSTP_TXSTP_6, USB_RXSTP_TXSTP_7, USB_STALL0_STALL_0, USB_STALL0_STALL_1, USB_STALL0_STALL_2, USB_STALL0_STALL_3, USB_STALL0_STALL_4, USB_STALL0_STALL_5, USB_STALL0_STALL_6, USB_STALL0_STALL_7, USB_STALL1_0, USB_STALL1_1, USB_STALL1_2, USB_STALL1_3, USB_STALL1_4, USB_STALL1_5, USB_STALL1_6, USB_STALL1_7, USB_SUSPEND, USB_TRFAIL0_TRFAIL_0, USB_TRFAIL0_TRFAIL_1, USB_TRFAIL0_TRFAIL_2, USB_TRFAIL0_TRFAIL_3, USB_TRFAIL0_TRFAIL_4, USB_TRFAIL0_TRFAIL_5, USB_TRFAIL0_TRFAIL_6, USB_TRFAIL0_TRFAIL_7, USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2, USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5, USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */ | ||
381 | .pfnUSB_1_Handler = (void*) USB_1_Handler, /* 81 USB_SOF_HSOF */ | ||
382 | .pfnUSB_2_Handler = (void*) USB_2_Handler, /* 82 USB_TRCPT0_0, USB_TRCPT0_1, USB_TRCPT0_2, USB_TRCPT0_3, USB_TRCPT0_4, USB_TRCPT0_5, USB_TRCPT0_6, USB_TRCPT0_7 */ | ||
383 | .pfnUSB_3_Handler = (void*) USB_3_Handler, /* 83 USB_TRCPT1_0, USB_TRCPT1_1, USB_TRCPT1_2, USB_TRCPT1_3, USB_TRCPT1_4, USB_TRCPT1_5, USB_TRCPT1_6, USB_TRCPT1_7 */ | ||
384 | #else | ||
385 | .pvReserved80 = (void*) (0UL), /* 80 Reserved */ | ||
386 | .pvReserved81 = (void*) (0UL), /* 81 Reserved */ | ||
387 | .pvReserved82 = (void*) (0UL), /* 82 Reserved */ | ||
388 | .pvReserved83 = (void*) (0UL), /* 83 Reserved */ | ||
389 | #endif | ||
390 | #ifdef ID_GMAC | ||
391 | .pfnGMAC_Handler = (void*) GMAC_Handler, /* 84 Ethernet MAC */ | ||
392 | #else | ||
393 | .pvReserved84 = (void*) (0UL), /* 84 Reserved */ | ||
394 | #endif | ||
395 | .pfnTCC0_0_Handler = (void*) TCC0_0_Handler, /* 85 TCC0_CNT_A, TCC0_DFS_A, TCC0_ERR_A, TCC0_FAULT0_A, TCC0_FAULT1_A, TCC0_FAULTA_A, TCC0_FAULTB_A, TCC0_OVF, TCC0_TRG, TCC0_UFS_A */ | ||
396 | .pfnTCC0_1_Handler = (void*) TCC0_1_Handler, /* 86 TCC0_MC_0 */ | ||
397 | .pfnTCC0_2_Handler = (void*) TCC0_2_Handler, /* 87 TCC0_MC_1 */ | ||
398 | .pfnTCC0_3_Handler = (void*) TCC0_3_Handler, /* 88 TCC0_MC_2 */ | ||
399 | .pfnTCC0_4_Handler = (void*) TCC0_4_Handler, /* 89 TCC0_MC_3 */ | ||
400 | .pfnTCC0_5_Handler = (void*) TCC0_5_Handler, /* 90 TCC0_MC_4 */ | ||
401 | .pfnTCC0_6_Handler = (void*) TCC0_6_Handler, /* 91 TCC0_MC_5 */ | ||
402 | .pfnTCC1_0_Handler = (void*) TCC1_0_Handler, /* 92 TCC1_CNT_A, TCC1_DFS_A, TCC1_ERR_A, TCC1_FAULT0_A, TCC1_FAULT1_A, TCC1_FAULTA_A, TCC1_FAULTB_A, TCC1_OVF, TCC1_TRG, TCC1_UFS_A */ | ||
403 | .pfnTCC1_1_Handler = (void*) TCC1_1_Handler, /* 93 TCC1_MC_0 */ | ||
404 | .pfnTCC1_2_Handler = (void*) TCC1_2_Handler, /* 94 TCC1_MC_1 */ | ||
405 | .pfnTCC1_3_Handler = (void*) TCC1_3_Handler, /* 95 TCC1_MC_2 */ | ||
406 | .pfnTCC1_4_Handler = (void*) TCC1_4_Handler, /* 96 TCC1_MC_3 */ | ||
407 | .pfnTCC2_0_Handler = (void*) TCC2_0_Handler, /* 97 TCC2_CNT_A, TCC2_DFS_A, TCC2_ERR_A, TCC2_FAULT0_A, TCC2_FAULT1_A, TCC2_FAULTA_A, TCC2_FAULTB_A, TCC2_OVF, TCC2_TRG, TCC2_UFS_A */ | ||
408 | .pfnTCC2_1_Handler = (void*) TCC2_1_Handler, /* 98 TCC2_MC_0 */ | ||
409 | .pfnTCC2_2_Handler = (void*) TCC2_2_Handler, /* 99 TCC2_MC_1 */ | ||
410 | .pfnTCC2_3_Handler = (void*) TCC2_3_Handler, /* 100 TCC2_MC_2 */ | ||
411 | #ifdef ID_TCC3 | ||
412 | .pfnTCC3_0_Handler = (void*) TCC3_0_Handler, /* 101 TCC3_CNT_A, TCC3_DFS_A, TCC3_ERR_A, TCC3_FAULT0_A, TCC3_FAULT1_A, TCC3_FAULTA_A, TCC3_FAULTB_A, TCC3_OVF, TCC3_TRG, TCC3_UFS_A */ | ||
413 | .pfnTCC3_1_Handler = (void*) TCC3_1_Handler, /* 102 TCC3_MC_0 */ | ||
414 | .pfnTCC3_2_Handler = (void*) TCC3_2_Handler, /* 103 TCC3_MC_1 */ | ||
415 | #else | ||
416 | .pvReserved101 = (void*) (0UL), /* 101 Reserved */ | ||
417 | .pvReserved102 = (void*) (0UL), /* 102 Reserved */ | ||
418 | .pvReserved103 = (void*) (0UL), /* 103 Reserved */ | ||
419 | #endif | ||
420 | #ifdef ID_TCC4 | ||
421 | .pfnTCC4_0_Handler = (void*) TCC4_0_Handler, /* 104 TCC4_CNT_A, TCC4_DFS_A, TCC4_ERR_A, TCC4_FAULT0_A, TCC4_FAULT1_A, TCC4_FAULTA_A, TCC4_FAULTB_A, TCC4_OVF, TCC4_TRG, TCC4_UFS_A */ | ||
422 | .pfnTCC4_1_Handler = (void*) TCC4_1_Handler, /* 105 TCC4_MC_0 */ | ||
423 | .pfnTCC4_2_Handler = (void*) TCC4_2_Handler, /* 106 TCC4_MC_1 */ | ||
424 | #else | ||
425 | .pvReserved104 = (void*) (0UL), /* 104 Reserved */ | ||
426 | .pvReserved105 = (void*) (0UL), /* 105 Reserved */ | ||
427 | .pvReserved106 = (void*) (0UL), /* 106 Reserved */ | ||
428 | #endif | ||
429 | .pfnTC0_Handler = (void*) TC0_Handler, /* 107 Basic Timer Counter 0 */ | ||
430 | .pfnTC1_Handler = (void*) TC1_Handler, /* 108 Basic Timer Counter 1 */ | ||
431 | .pfnTC2_Handler = (void*) TC2_Handler, /* 109 Basic Timer Counter 2 */ | ||
432 | .pfnTC3_Handler = (void*) TC3_Handler, /* 110 Basic Timer Counter 3 */ | ||
433 | #ifdef ID_TC4 | ||
434 | .pfnTC4_Handler = (void*) TC4_Handler, /* 111 Basic Timer Counter 4 */ | ||
435 | #else | ||
436 | .pvReserved111 = (void*) (0UL), /* 111 Reserved */ | ||
437 | #endif | ||
438 | #ifdef ID_TC5 | ||
439 | .pfnTC5_Handler = (void*) TC5_Handler, /* 112 Basic Timer Counter 5 */ | ||
440 | #else | ||
441 | .pvReserved112 = (void*) (0UL), /* 112 Reserved */ | ||
442 | #endif | ||
443 | #ifdef ID_TC6 | ||
444 | .pfnTC6_Handler = (void*) TC6_Handler, /* 113 Basic Timer Counter 6 */ | ||
445 | #else | ||
446 | .pvReserved113 = (void*) (0UL), /* 113 Reserved */ | ||
447 | #endif | ||
448 | #ifdef ID_TC7 | ||
449 | .pfnTC7_Handler = (void*) TC7_Handler, /* 114 Basic Timer Counter 7 */ | ||
450 | #else | ||
451 | .pvReserved114 = (void*) (0UL), /* 114 Reserved */ | ||
452 | #endif | ||
453 | .pfnPDEC_0_Handler = (void*) PDEC_0_Handler, /* 115 PDEC_DIR_A, PDEC_ERR_A, PDEC_OVF, PDEC_VLC_A */ | ||
454 | .pfnPDEC_1_Handler = (void*) PDEC_1_Handler, /* 116 PDEC_MC_0 */ | ||
455 | .pfnPDEC_2_Handler = (void*) PDEC_2_Handler, /* 117 PDEC_MC_1 */ | ||
456 | .pfnADC0_0_Handler = (void*) ADC0_0_Handler, /* 118 ADC0_OVERRUN, ADC0_WINMON */ | ||
457 | .pfnADC0_1_Handler = (void*) ADC0_1_Handler, /* 119 ADC0_RESRDY */ | ||
458 | .pfnADC1_0_Handler = (void*) ADC1_0_Handler, /* 120 ADC1_OVERRUN, ADC1_WINMON */ | ||
459 | .pfnADC1_1_Handler = (void*) ADC1_1_Handler, /* 121 ADC1_RESRDY */ | ||
460 | .pfnAC_Handler = (void*) AC_Handler, /* 122 Analog Comparators */ | ||
461 | .pfnDAC_0_Handler = (void*) DAC_0_Handler, /* 123 DAC_OVERRUN_A_0, DAC_OVERRUN_A_1, DAC_UNDERRUN_A_0, DAC_UNDERRUN_A_1 */ | ||
462 | .pfnDAC_1_Handler = (void*) DAC_1_Handler, /* 124 DAC_EMPTY_0 */ | ||
463 | .pfnDAC_2_Handler = (void*) DAC_2_Handler, /* 125 DAC_EMPTY_1 */ | ||
464 | .pfnDAC_3_Handler = (void*) DAC_3_Handler, /* 126 DAC_RESRDY_0 */ | ||
465 | .pfnDAC_4_Handler = (void*) DAC_4_Handler, /* 127 DAC_RESRDY_1 */ | ||
466 | #ifdef ID_I2S | ||
467 | .pfnI2S_Handler = (void*) I2S_Handler, /* 128 Inter-IC Sound Interface */ | ||
468 | #else | ||
469 | .pvReserved128 = (void*) (0UL), /* 128 Reserved */ | ||
470 | #endif | ||
471 | .pfnPCC_Handler = (void*) PCC_Handler, /* 129 Parallel Capture Controller */ | ||
472 | .pfnAES_Handler = (void*) AES_Handler, /* 130 Advanced Encryption Standard */ | ||
473 | .pfnTRNG_Handler = (void*) TRNG_Handler, /* 131 True Random Generator */ | ||
474 | #ifdef ID_ICM | ||
475 | .pfnICM_Handler = (void*) ICM_Handler, /* 132 Integrity Check Monitor */ | ||
476 | #else | ||
477 | .pvReserved132 = (void*) (0UL), /* 132 Reserved */ | ||
478 | #endif | ||
479 | #ifdef ID_PUKCC | ||
480 | .pfnPUKCC_Handler = (void*) PUKCC_Handler, /* 133 PUblic-Key Cryptography Controller */ | ||
481 | #else | ||
482 | .pvReserved133 = (void*) (0UL), /* 133 Reserved */ | ||
483 | #endif | ||
484 | .pfnQSPI_Handler = (void*) QSPI_Handler, /* 134 Quad SPI interface */ | ||
485 | #ifdef ID_SDHC0 | ||
486 | .pfnSDHC0_Handler = (void*) SDHC0_Handler, /* 135 SD/MMC Host Controller 0 */ | ||
487 | #else | ||
488 | .pvReserved135 = (void*) (0UL), /* 135 Reserved */ | ||
489 | #endif | ||
490 | #ifdef ID_SDHC1 | ||
491 | .pfnSDHC1_Handler = (void*) SDHC1_Handler /* 136 SD/MMC Host Controller 1 */ | ||
492 | #else | ||
493 | .pvReserved136 = (void*) (0UL) /* 136 Reserved */ | ||
494 | #endif | ||
495 | }; | ||
496 | |||
497 | /** | ||
498 | * \brief This is the code that gets called on processor reset. | ||
499 | * To initialize the device, and call the main() routine. | ||
500 | */ | ||
501 | void Reset_Handler(void) | ||
502 | { | ||
503 | uint32_t *pSrc, *pDest; | ||
504 | |||
505 | /* Initialize the relocate segment */ | ||
506 | pSrc = &_etext; | ||
507 | pDest = &_srelocate; | ||
508 | |||
509 | if (pSrc != pDest) { | ||
510 | for (; pDest < &_erelocate;) { | ||
511 | *pDest++ = *pSrc++; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* Clear the zero segment */ | ||
516 | for (pDest = &_szero; pDest < &_ezero;) { | ||
517 | *pDest++ = 0; | ||
518 | } | ||
519 | |||
520 | /* Set the vector table base address */ | ||
521 | pSrc = (uint32_t *) & _sfixed; | ||
522 | SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk); | ||
523 | |||
524 | #if __FPU_USED | ||
525 | /* Enable FPU */ | ||
526 | SCB->CPACR |= (0xFu << 20); | ||
527 | __DSB(); | ||
528 | __ISB(); | ||
529 | #endif | ||
530 | |||
531 | /* Initialize the C library */ | ||
532 | __libc_init_array(); | ||
533 | |||
534 | /* Branch to main function */ | ||
535 | main(); | ||
536 | |||
537 | /* Infinite loop */ | ||
538 | while (1); | ||
539 | } | ||
540 | |||
541 | /** | ||
542 | * \brief Default interrupt handler for unused IRQs. | ||
543 | */ | ||
544 | void Dummy_Handler(void) | ||
545 | { | ||
546 | while (1) { | ||
547 | } | ||
548 | } | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/compiler.h b/tmk_core/protocol/arm_atsam/usb/compiler.h new file mode 100644 index 000000000..d33843986 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/compiler.h | |||
@@ -0,0 +1,1177 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Commonly used includes, types and macros. | ||
5 | * | ||
6 | * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted provided that the following conditions are met: | ||
12 | * | ||
13 | * 1. Redistributions of source code must retain the above copyright notice, | ||
14 | * this list of conditions and the following disclaimer. | ||
15 | * | ||
16 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
17 | * this list of conditions and the following disclaimer in the documentation | ||
18 | * and/or other materials provided with the distribution. | ||
19 | * | ||
20 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
21 | * from this software without specific prior written permission. | ||
22 | * | ||
23 | * 4. This software may only be redistributed and used in connection with an | ||
24 | * Atmel microcontroller product. | ||
25 | * | ||
26 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
27 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
29 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
30 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
34 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
35 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
36 | * POSSIBILITY OF SUCH DAMAGE. | ||
37 | * | ||
38 | * \asf_license_stop | ||
39 | * | ||
40 | */ | ||
41 | /* | ||
42 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
43 | */ | ||
44 | |||
45 | #ifndef UTILS_COMPILER_H_INCLUDED | ||
46 | #define UTILS_COMPILER_H_INCLUDED | ||
47 | |||
48 | /** | ||
49 | * \defgroup group_sam0_utils Compiler abstraction layer and code utilities | ||
50 | * | ||
51 | * Compiler abstraction layer and code utilities for Cortex-M0+ based Atmel SAM devices. | ||
52 | * This module provides various abstraction layers and utilities to make code compatible between different compilers. | ||
53 | * | ||
54 | * @{ | ||
55 | */ | ||
56 | |||
57 | #if (defined __ICCARM__) | ||
58 | # include <intrinsics.h> | ||
59 | #endif | ||
60 | |||
61 | #include <stddef.h> | ||
62 | //#include <parts.h> | ||
63 | //#include <status_codes.h> | ||
64 | //#include <preprocessor.h> | ||
65 | //#include <io.h> | ||
66 | |||
67 | #ifndef __ASSEMBLY__ | ||
68 | |||
69 | #include <stdio.h> | ||
70 | #include <stdbool.h> | ||
71 | #include <stdint.h> | ||
72 | #include <stdlib.h> | ||
73 | |||
74 | /** | ||
75 | * \def UNUSED | ||
76 | * \brief Marking \a v as a unused parameter or value. | ||
77 | */ | ||
78 | #define UNUSED(v) (void)(v) | ||
79 | |||
80 | /** | ||
81 | * \def barrier | ||
82 | * \brief Memory barrier | ||
83 | */ | ||
84 | #ifdef __GNUC__ | ||
85 | # define barrier() asm volatile("" ::: "memory") | ||
86 | #else | ||
87 | # define barrier() asm ("") | ||
88 | #endif | ||
89 | |||
90 | /** | ||
91 | * \brief Emit the compiler pragma \a arg. | ||
92 | * | ||
93 | * \param[in] arg The pragma directive as it would appear after \e \#pragma | ||
94 | * (i.e. not stringified). | ||
95 | */ | ||
96 | #define COMPILER_PRAGMA(arg) _Pragma(#arg) | ||
97 | |||
98 | /** | ||
99 | * \def COMPILER_PACK_SET(alignment) | ||
100 | * \brief Set maximum alignment for subsequent struct and union definitions to \a alignment. | ||
101 | */ | ||
102 | #define COMPILER_PACK_SET(alignment) COMPILER_PRAGMA(pack(alignment)) | ||
103 | |||
104 | /** | ||
105 | * \def COMPILER_PACK_RESET() | ||
106 | * \brief Set default alignment for subsequent struct and union definitions. | ||
107 | */ | ||
108 | #define COMPILER_PACK_RESET() COMPILER_PRAGMA(pack()) | ||
109 | |||
110 | |||
111 | /** | ||
112 | * \brief Set aligned boundary. | ||
113 | */ | ||
114 | #if (defined __GNUC__) || (defined __CC_ARM) | ||
115 | # define COMPILER_ALIGNED(a) __attribute__((__aligned__(a))) | ||
116 | #elif (defined __ICCARM__) | ||
117 | # define COMPILER_ALIGNED(a) COMPILER_PRAGMA(data_alignment = a) | ||
118 | #endif | ||
119 | |||
120 | /** | ||
121 | * \brief Set word-aligned boundary. | ||
122 | */ | ||
123 | #if (defined __GNUC__) || defined(__CC_ARM) | ||
124 | #define COMPILER_WORD_ALIGNED __attribute__((__aligned__(4))) | ||
125 | #elif (defined __ICCARM__) | ||
126 | #define COMPILER_WORD_ALIGNED COMPILER_PRAGMA(data_alignment = 4) | ||
127 | #endif | ||
128 | |||
129 | /** | ||
130 | * \def __always_inline | ||
131 | * \brief The function should always be inlined. | ||
132 | * | ||
133 | * This annotation instructs the compiler to ignore its inlining | ||
134 | * heuristics and inline the function no matter how big it thinks it | ||
135 | * becomes. | ||
136 | */ | ||
137 | #if defined(__CC_ARM) | ||
138 | # define __always_inline __forceinline | ||
139 | #elif (defined __GNUC__) | ||
140 | # define __always_inline __attribute__((__always_inline__)) | ||
141 | #elif (defined __ICCARM__) | ||
142 | # define __always_inline _Pragma("inline=forced") | ||
143 | #endif | ||
144 | |||
145 | /** | ||
146 | * \def __no_inline | ||
147 | * \brief The function should never be inlined | ||
148 | * | ||
149 | * This annotation instructs the compiler to ignore its inlining | ||
150 | * heuristics and not inline the function no matter how small it thinks it | ||
151 | * becomes. | ||
152 | */ | ||
153 | #if defined(__CC_ARM) | ||
154 | # define __no_inline __attribute__((noinline)) | ||
155 | #elif (defined __GNUC__) | ||
156 | # define __no_inline __attribute__((noinline)) | ||
157 | #elif (defined __ICCARM__) | ||
158 | # define __no_inline _Pragma("inline=never") | ||
159 | #endif | ||
160 | |||
161 | |||
162 | /** \brief This macro is used to test fatal errors. | ||
163 | * | ||
164 | * The macro tests if the expression is false. If it is, a fatal error is | ||
165 | * detected and the application hangs up. If \c TEST_SUITE_DEFINE_ASSERT_MACRO | ||
166 | * is defined, a unit test version of the macro is used, to allow execution | ||
167 | * of further tests after a false expression. | ||
168 | * | ||
169 | * \param[in] expr Expression to evaluate and supposed to be nonzero. | ||
170 | */ | ||
171 | #if defined(_ASSERT_ENABLE_) | ||
172 | # if defined(TEST_SUITE_DEFINE_ASSERT_MACRO) | ||
173 | # include "unit_test/suite.h" | ||
174 | # else | ||
175 | # undef TEST_SUITE_DEFINE_ASSERT_MACRO | ||
176 | # define Assert(expr) \ | ||
177 | {\ | ||
178 | if (!(expr)) asm("BKPT #0");\ | ||
179 | } | ||
180 | # endif | ||
181 | #else | ||
182 | # define Assert(expr) ((void) 0) | ||
183 | #endif | ||
184 | |||
185 | /* Define WEAK attribute */ | ||
186 | #if defined ( __CC_ARM ) | ||
187 | # define WEAK __attribute__ ((weak)) | ||
188 | #elif defined ( __ICCARM__ ) | ||
189 | # define WEAK __weak | ||
190 | #elif defined ( __GNUC__ ) | ||
191 | # define WEAK __attribute__ ((weak)) | ||
192 | #endif | ||
193 | |||
194 | /* Define NO_INIT attribute */ | ||
195 | #if defined ( __CC_ARM ) | ||
196 | # define NO_INIT __attribute__((zero_init)) | ||
197 | #elif defined ( __ICCARM__ ) | ||
198 | # define NO_INIT __no_init | ||
199 | #elif defined ( __GNUC__ ) | ||
200 | # define NO_INIT __attribute__((section(".no_init"))) | ||
201 | #endif | ||
202 | |||
203 | //#include "interrupt.h" | ||
204 | |||
205 | /** \name Usual Types | ||
206 | * @{ */ | ||
207 | #ifndef __cplusplus | ||
208 | # if !defined(__bool_true_false_are_defined) | ||
209 | typedef unsigned char bool; | ||
210 | # endif | ||
211 | #endif | ||
212 | typedef uint16_t le16_t; | ||
213 | typedef uint16_t be16_t; | ||
214 | typedef uint32_t le32_t; | ||
215 | typedef uint32_t be32_t; | ||
216 | typedef uint32_t iram_size_t; | ||
217 | /** @} */ | ||
218 | |||
219 | /** \name Aliasing Aggregate Types | ||
220 | * @{ */ | ||
221 | |||
222 | /** 16-bit union. */ | ||
223 | typedef union | ||
224 | { | ||
225 | int16_t s16; | ||
226 | uint16_t u16; | ||
227 | int8_t s8[2]; | ||
228 | uint8_t u8[2]; | ||
229 | } Union16; | ||
230 | |||
231 | /** 32-bit union. */ | ||
232 | typedef union | ||
233 | { | ||
234 | int32_t s32; | ||
235 | uint32_t u32; | ||
236 | int16_t s16[2]; | ||
237 | uint16_t u16[2]; | ||
238 | int8_t s8[4]; | ||
239 | uint8_t u8[4]; | ||
240 | } Union32; | ||
241 | |||
242 | /** 64-bit union. */ | ||
243 | typedef union | ||
244 | { | ||
245 | int64_t s64; | ||
246 | uint64_t u64; | ||
247 | int32_t s32[2]; | ||
248 | uint32_t u32[2]; | ||
249 | int16_t s16[4]; | ||
250 | uint16_t u16[4]; | ||
251 | int8_t s8[8]; | ||
252 | uint8_t u8[8]; | ||
253 | } Union64; | ||
254 | |||
255 | /** Union of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
256 | typedef union | ||
257 | { | ||
258 | int64_t *s64ptr; | ||
259 | uint64_t *u64ptr; | ||
260 | int32_t *s32ptr; | ||
261 | uint32_t *u32ptr; | ||
262 | int16_t *s16ptr; | ||
263 | uint16_t *u16ptr; | ||
264 | int8_t *s8ptr; | ||
265 | uint8_t *u8ptr; | ||
266 | } UnionPtr; | ||
267 | |||
268 | /** Union of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
269 | typedef union | ||
270 | { | ||
271 | volatile int64_t *s64ptr; | ||
272 | volatile uint64_t *u64ptr; | ||
273 | volatile int32_t *s32ptr; | ||
274 | volatile uint32_t *u32ptr; | ||
275 | volatile int16_t *s16ptr; | ||
276 | volatile uint16_t *u16ptr; | ||
277 | volatile int8_t *s8ptr; | ||
278 | volatile uint8_t *u8ptr; | ||
279 | } UnionVPtr; | ||
280 | |||
281 | /** Union of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
282 | typedef union | ||
283 | { | ||
284 | const int64_t *s64ptr; | ||
285 | const uint64_t *u64ptr; | ||
286 | const int32_t *s32ptr; | ||
287 | const uint32_t *u32ptr; | ||
288 | const int16_t *s16ptr; | ||
289 | const uint16_t *u16ptr; | ||
290 | const int8_t *s8ptr; | ||
291 | const uint8_t *u8ptr; | ||
292 | } UnionCPtr; | ||
293 | |||
294 | /** Union of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
295 | typedef union | ||
296 | { | ||
297 | const volatile int64_t *s64ptr; | ||
298 | const volatile uint64_t *u64ptr; | ||
299 | const volatile int32_t *s32ptr; | ||
300 | const volatile uint32_t *u32ptr; | ||
301 | const volatile int16_t *s16ptr; | ||
302 | const volatile uint16_t *u16ptr; | ||
303 | const volatile int8_t *s8ptr; | ||
304 | const volatile uint8_t *u8ptr; | ||
305 | } UnionCVPtr; | ||
306 | |||
307 | /** Structure of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
308 | typedef struct | ||
309 | { | ||
310 | int64_t *s64ptr; | ||
311 | uint64_t *u64ptr; | ||
312 | int32_t *s32ptr; | ||
313 | uint32_t *u32ptr; | ||
314 | int16_t *s16ptr; | ||
315 | uint16_t *u16ptr; | ||
316 | int8_t *s8ptr; | ||
317 | uint8_t *u8ptr; | ||
318 | } StructPtr; | ||
319 | |||
320 | /** Structure of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
321 | typedef struct | ||
322 | { | ||
323 | volatile int64_t *s64ptr; | ||
324 | volatile uint64_t *u64ptr; | ||
325 | volatile int32_t *s32ptr; | ||
326 | volatile uint32_t *u32ptr; | ||
327 | volatile int16_t *s16ptr; | ||
328 | volatile uint16_t *u16ptr; | ||
329 | volatile int8_t *s8ptr; | ||
330 | volatile uint8_t *u8ptr; | ||
331 | } StructVPtr; | ||
332 | |||
333 | /** Structure of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
334 | typedef struct | ||
335 | { | ||
336 | const int64_t *s64ptr; | ||
337 | const uint64_t *u64ptr; | ||
338 | const int32_t *s32ptr; | ||
339 | const uint32_t *u32ptr; | ||
340 | const int16_t *s16ptr; | ||
341 | const uint16_t *u16ptr; | ||
342 | const int8_t *s8ptr; | ||
343 | const uint8_t *u8ptr; | ||
344 | } StructCPtr; | ||
345 | |||
346 | /** Structure of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ | ||
347 | typedef struct | ||
348 | { | ||
349 | const volatile int64_t *s64ptr; | ||
350 | const volatile uint64_t *u64ptr; | ||
351 | const volatile int32_t *s32ptr; | ||
352 | const volatile uint32_t *u32ptr; | ||
353 | const volatile int16_t *s16ptr; | ||
354 | const volatile uint16_t *u16ptr; | ||
355 | const volatile int8_t *s8ptr; | ||
356 | const volatile uint8_t *u8ptr; | ||
357 | } StructCVPtr; | ||
358 | |||
359 | /** @} */ | ||
360 | |||
361 | #endif /* #ifndef __ASSEMBLY__ */ | ||
362 | |||
363 | /** \name Usual Constants | ||
364 | * @{ */ | ||
365 | //kmod #define DISABLE 0 | ||
366 | //kmod #define ENABLE 1 | ||
367 | |||
368 | #ifndef __cplusplus | ||
369 | # if !defined(__bool_true_false_are_defined) | ||
370 | # define false 0 | ||
371 | # define true 1 | ||
372 | # endif | ||
373 | #endif | ||
374 | /** @} */ | ||
375 | |||
376 | #ifndef __ASSEMBLY__ | ||
377 | |||
378 | /** \name Optimization Control | ||
379 | * @{ */ | ||
380 | |||
381 | /** | ||
382 | * \def likely(exp) | ||
383 | * \brief The expression \a exp is likely to be true | ||
384 | */ | ||
385 | #if !defined(likely) || defined(__DOXYGEN__) | ||
386 | # define likely(exp) (exp) | ||
387 | #endif | ||
388 | |||
389 | /** | ||
390 | * \def unlikely(exp) | ||
391 | * \brief The expression \a exp is unlikely to be true | ||
392 | */ | ||
393 | #if !defined(unlikely) || defined(__DOXYGEN__) | ||
394 | # define unlikely(exp) (exp) | ||
395 | #endif | ||
396 | |||
397 | /** | ||
398 | * \def is_constant(exp) | ||
399 | * \brief Determine if an expression evaluates to a constant value. | ||
400 | * | ||
401 | * \param[in] exp Any expression | ||
402 | * | ||
403 | * \return true if \a exp is constant, false otherwise. | ||
404 | */ | ||
405 | #if (defined __GNUC__) || (defined __CC_ARM) | ||
406 | # define is_constant(exp) __builtin_constant_p(exp) | ||
407 | #else | ||
408 | # define is_constant(exp) (0) | ||
409 | #endif | ||
410 | |||
411 | /** @} */ | ||
412 | |||
413 | /** \name Bit-Field Handling | ||
414 | * @{ */ | ||
415 | |||
416 | /** \brief Reads the bits of a value specified by a given bit-mask. | ||
417 | * | ||
418 | * \param[in] value Value to read bits from. | ||
419 | * \param[in] mask Bit-mask indicating bits to read. | ||
420 | * | ||
421 | * \return Read bits. | ||
422 | */ | ||
423 | #define Rd_bits( value, mask) ((value) & (mask)) | ||
424 | |||
425 | /** \brief Writes the bits of a C lvalue specified by a given bit-mask. | ||
426 | * | ||
427 | * \param[in] lvalue C lvalue to write bits to. | ||
428 | * \param[in] mask Bit-mask indicating bits to write. | ||
429 | * \param[in] bits Bits to write. | ||
430 | * | ||
431 | * \return Resulting value with written bits. | ||
432 | */ | ||
433 | #define Wr_bits(lvalue, mask, bits) ((lvalue) = ((lvalue) & ~(mask)) |\ | ||
434 | ((bits ) & (mask))) | ||
435 | |||
436 | /** \brief Tests the bits of a value specified by a given bit-mask. | ||
437 | * | ||
438 | * \param[in] value Value of which to test bits. | ||
439 | * \param[in] mask Bit-mask indicating bits to test. | ||
440 | * | ||
441 | * \return \c 1 if at least one of the tested bits is set, else \c 0. | ||
442 | */ | ||
443 | #define Tst_bits( value, mask) (Rd_bits(value, mask) != 0) | ||
444 | |||
445 | /** \brief Clears the bits of a C lvalue specified by a given bit-mask. | ||
446 | * | ||
447 | * \param[in] lvalue C lvalue of which to clear bits. | ||
448 | * \param[in] mask Bit-mask indicating bits to clear. | ||
449 | * | ||
450 | * \return Resulting value with cleared bits. | ||
451 | */ | ||
452 | #define Clr_bits(lvalue, mask) ((lvalue) &= ~(mask)) | ||
453 | |||
454 | /** \brief Sets the bits of a C lvalue specified by a given bit-mask. | ||
455 | * | ||
456 | * \param[in] lvalue C lvalue of which to set bits. | ||
457 | * \param[in] mask Bit-mask indicating bits to set. | ||
458 | * | ||
459 | * \return Resulting value with set bits. | ||
460 | */ | ||
461 | #define Set_bits(lvalue, mask) ((lvalue) |= (mask)) | ||
462 | |||
463 | /** \brief Toggles the bits of a C lvalue specified by a given bit-mask. | ||
464 | * | ||
465 | * \param[in] lvalue C lvalue of which to toggle bits. | ||
466 | * \param[in] mask Bit-mask indicating bits to toggle. | ||
467 | * | ||
468 | * \return Resulting value with toggled bits. | ||
469 | */ | ||
470 | #define Tgl_bits(lvalue, mask) ((lvalue) ^= (mask)) | ||
471 | |||
472 | /** \brief Reads the bit-field of a value specified by a given bit-mask. | ||
473 | * | ||
474 | * \param[in] value Value to read a bit-field from. | ||
475 | * \param[in] mask Bit-mask indicating the bit-field to read. | ||
476 | * | ||
477 | * \return Read bit-field. | ||
478 | */ | ||
479 | #define Rd_bitfield( value, mask) (Rd_bits( value, mask) >> ctz(mask)) | ||
480 | |||
481 | /** \brief Writes the bit-field of a C lvalue specified by a given bit-mask. | ||
482 | * | ||
483 | * \param[in] lvalue C lvalue to write a bit-field to. | ||
484 | * \param[in] mask Bit-mask indicating the bit-field to write. | ||
485 | * \param[in] bitfield Bit-field to write. | ||
486 | * | ||
487 | * \return Resulting value with written bit-field. | ||
488 | */ | ||
489 | #define Wr_bitfield(lvalue, mask, bitfield) (Wr_bits(lvalue, mask, (uint32_t)(bitfield) << ctz(mask))) | ||
490 | |||
491 | /** @} */ | ||
492 | |||
493 | |||
494 | /** \name Zero-Bit Counting | ||
495 | * | ||
496 | * Under GCC, __builtin_clz and __builtin_ctz behave like macros when | ||
497 | * applied to constant expressions (values known at compile time), so they are | ||
498 | * more optimized than the use of the corresponding assembly instructions and | ||
499 | * they can be used as constant expressions e.g. to initialize objects having | ||
500 | * static storage duration, and like the corresponding assembly instructions | ||
501 | * when applied to non-constant expressions (values unknown at compile time), so | ||
502 | * they are more optimized than an assembly periphrasis. Hence, clz and ctz | ||
503 | * ensure a possible and optimized behavior for both constant and non-constant | ||
504 | * expressions. | ||
505 | * | ||
506 | * @{ */ | ||
507 | |||
508 | /** \brief Counts the leading zero bits of the given value considered as a 32-bit integer. | ||
509 | * | ||
510 | * \param[in] u Value of which to count the leading zero bits. | ||
511 | * | ||
512 | * \return The count of leading zero bits in \a u. | ||
513 | */ | ||
514 | #if (defined __GNUC__) || (defined __CC_ARM) | ||
515 | # define clz(u) ((u) ? __builtin_clz(u) : 32) | ||
516 | #else | ||
517 | # define clz(u) (((u) == 0) ? 32 : \ | ||
518 | ((u) & (1ul << 31)) ? 0 : \ | ||
519 | ((u) & (1ul << 30)) ? 1 : \ | ||
520 | ((u) & (1ul << 29)) ? 2 : \ | ||
521 | ((u) & (1ul << 28)) ? 3 : \ | ||
522 | ((u) & (1ul << 27)) ? 4 : \ | ||
523 | ((u) & (1ul << 26)) ? 5 : \ | ||
524 | ((u) & (1ul << 25)) ? 6 : \ | ||
525 | ((u) & (1ul << 24)) ? 7 : \ | ||
526 | ((u) & (1ul << 23)) ? 8 : \ | ||
527 | ((u) & (1ul << 22)) ? 9 : \ | ||
528 | ((u) & (1ul << 21)) ? 10 : \ | ||
529 | ((u) & (1ul << 20)) ? 11 : \ | ||
530 | ((u) & (1ul << 19)) ? 12 : \ | ||
531 | ((u) & (1ul << 18)) ? 13 : \ | ||
532 | ((u) & (1ul << 17)) ? 14 : \ | ||
533 | ((u) & (1ul << 16)) ? 15 : \ | ||
534 | ((u) & (1ul << 15)) ? 16 : \ | ||
535 | ((u) & (1ul << 14)) ? 17 : \ | ||
536 | ((u) & (1ul << 13)) ? 18 : \ | ||
537 | ((u) & (1ul << 12)) ? 19 : \ | ||
538 | ((u) & (1ul << 11)) ? 20 : \ | ||
539 | ((u) & (1ul << 10)) ? 21 : \ | ||
540 | ((u) & (1ul << 9)) ? 22 : \ | ||
541 | ((u) & (1ul << 8)) ? 23 : \ | ||
542 | ((u) & (1ul << 7)) ? 24 : \ | ||
543 | ((u) & (1ul << 6)) ? 25 : \ | ||
544 | ((u) & (1ul << 5)) ? 26 : \ | ||
545 | ((u) & (1ul << 4)) ? 27 : \ | ||
546 | ((u) & (1ul << 3)) ? 28 : \ | ||
547 | ((u) & (1ul << 2)) ? 29 : \ | ||
548 | ((u) & (1ul << 1)) ? 30 : \ | ||
549 | 31) | ||
550 | #endif | ||
551 | |||
552 | /** \brief Counts the trailing zero bits of the given value considered as a 32-bit integer. | ||
553 | * | ||
554 | * \param[in] u Value of which to count the trailing zero bits. | ||
555 | * | ||
556 | * \return The count of trailing zero bits in \a u. | ||
557 | */ | ||
558 | #if (defined __GNUC__) || (defined __CC_ARM) | ||
559 | # define ctz(u) ((u) ? __builtin_ctz(u) : 32) | ||
560 | #else | ||
561 | # define ctz(u) ((u) & (1ul << 0) ? 0 : \ | ||
562 | (u) & (1ul << 1) ? 1 : \ | ||
563 | (u) & (1ul << 2) ? 2 : \ | ||
564 | (u) & (1ul << 3) ? 3 : \ | ||
565 | (u) & (1ul << 4) ? 4 : \ | ||
566 | (u) & (1ul << 5) ? 5 : \ | ||
567 | (u) & (1ul << 6) ? 6 : \ | ||
568 | (u) & (1ul << 7) ? 7 : \ | ||
569 | (u) & (1ul << 8) ? 8 : \ | ||
570 | (u) & (1ul << 9) ? 9 : \ | ||
571 | (u) & (1ul << 10) ? 10 : \ | ||
572 | (u) & (1ul << 11) ? 11 : \ | ||
573 | (u) & (1ul << 12) ? 12 : \ | ||
574 | (u) & (1ul << 13) ? 13 : \ | ||
575 | (u) & (1ul << 14) ? 14 : \ | ||
576 | (u) & (1ul << 15) ? 15 : \ | ||
577 | (u) & (1ul << 16) ? 16 : \ | ||
578 | (u) & (1ul << 17) ? 17 : \ | ||
579 | (u) & (1ul << 18) ? 18 : \ | ||
580 | (u) & (1ul << 19) ? 19 : \ | ||
581 | (u) & (1ul << 20) ? 20 : \ | ||
582 | (u) & (1ul << 21) ? 21 : \ | ||
583 | (u) & (1ul << 22) ? 22 : \ | ||
584 | (u) & (1ul << 23) ? 23 : \ | ||
585 | (u) & (1ul << 24) ? 24 : \ | ||
586 | (u) & (1ul << 25) ? 25 : \ | ||
587 | (u) & (1ul << 26) ? 26 : \ | ||
588 | (u) & (1ul << 27) ? 27 : \ | ||
589 | (u) & (1ul << 28) ? 28 : \ | ||
590 | (u) & (1ul << 29) ? 29 : \ | ||
591 | (u) & (1ul << 30) ? 30 : \ | ||
592 | (u) & (1ul << 31) ? 31 : \ | ||
593 | 32) | ||
594 | #endif | ||
595 | |||
596 | /** @} */ | ||
597 | |||
598 | |||
599 | /** \name Bit Reversing | ||
600 | * @{ */ | ||
601 | |||
602 | /** \brief Reverses the bits of \a u8. | ||
603 | * | ||
604 | * \param[in] u8 U8 of which to reverse the bits. | ||
605 | * | ||
606 | * \return Value resulting from \a u8 with reversed bits. | ||
607 | */ | ||
608 | #define bit_reverse8(u8) ((U8)(bit_reverse32((U8)(u8)) >> 24)) | ||
609 | |||
610 | /** \brief Reverses the bits of \a u16. | ||
611 | * | ||
612 | * \param[in] u16 U16 of which to reverse the bits. | ||
613 | * | ||
614 | * \return Value resulting from \a u16 with reversed bits. | ||
615 | */ | ||
616 | #define bit_reverse16(u16) ((uint16_t)(bit_reverse32((uint16_t)(u16)) >> 16)) | ||
617 | |||
618 | /** \brief Reverses the bits of \a u32. | ||
619 | * | ||
620 | * \param[in] u32 U32 of which to reverse the bits. | ||
621 | * | ||
622 | * \return Value resulting from \a u32 with reversed bits. | ||
623 | */ | ||
624 | #define bit_reverse32(u32) __RBIT(u32) | ||
625 | |||
626 | /** \brief Reverses the bits of \a u64. | ||
627 | * | ||
628 | * \param[in] u64 U64 of which to reverse the bits. | ||
629 | * | ||
630 | * \return Value resulting from \a u64 with reversed bits. | ||
631 | */ | ||
632 | #define bit_reverse64(u64) ((uint64_t)(((uint64_t)bit_reverse32((uint64_t)(u64) >> 32)) |\ | ||
633 | ((uint64_t)bit_reverse32((uint64_t)(u64)) << 32))) | ||
634 | |||
635 | /** @} */ | ||
636 | |||
637 | |||
638 | /** \name Alignment | ||
639 | * @{ */ | ||
640 | |||
641 | /** \brief Tests alignment of the number \a val with the \a n boundary. | ||
642 | * | ||
643 | * \param[in] val Input value. | ||
644 | * \param[in] n Boundary. | ||
645 | * | ||
646 | * \return \c 1 if the number \a val is aligned with the \a n boundary, else \c 0. | ||
647 | */ | ||
648 | #define Test_align(val, n) (!Tst_bits( val, (n) - 1 ) ) | ||
649 | |||
650 | /** \brief Gets alignment of the number \a val with respect to the \a n boundary. | ||
651 | * | ||
652 | * \param[in] val Input value. | ||
653 | * \param[in] n Boundary. | ||
654 | * | ||
655 | * \return Alignment of the number \a val with respect to the \a n boundary. | ||
656 | */ | ||
657 | #define Get_align(val, n) ( Rd_bits( val, (n) - 1 ) ) | ||
658 | |||
659 | /** \brief Sets alignment of the lvalue number \a lval to \a alg with respect to the \a n boundary. | ||
660 | * | ||
661 | * \param[in] lval Input/output lvalue. | ||
662 | * \param[in] n Boundary. | ||
663 | * \param[in] alg Alignment. | ||
664 | * | ||
665 | * \return New value of \a lval resulting from its alignment set to \a alg with respect to the \a n boundary. | ||
666 | */ | ||
667 | #define Set_align(lval, n, alg) ( Wr_bits(lval, (n) - 1, alg) ) | ||
668 | |||
669 | /** \brief Aligns the number \a val with the upper \a n boundary. | ||
670 | * | ||
671 | * \param[in] val Input value. | ||
672 | * \param[in] n Boundary. | ||
673 | * | ||
674 | * \return Value resulting from the number \a val aligned with the upper \a n boundary. | ||
675 | */ | ||
676 | #define Align_up( val, n) (((val) + ((n) - 1)) & ~((n) - 1)) | ||
677 | |||
678 | /** \brief Aligns the number \a val with the lower \a n boundary. | ||
679 | * | ||
680 | * \param[in] val Input value. | ||
681 | * \param[in] n Boundary. | ||
682 | * | ||
683 | * \return Value resulting from the number \a val aligned with the lower \a n boundary. | ||
684 | */ | ||
685 | #define Align_down(val, n) ( (val) & ~((n) - 1)) | ||
686 | |||
687 | /** @} */ | ||
688 | |||
689 | |||
690 | /** \name Mathematics | ||
691 | * | ||
692 | * The same considerations as for clz and ctz apply here but GCC does not | ||
693 | * provide built-in functions to access the assembly instructions abs, min and | ||
694 | * max and it does not produce them by itself in most cases, so two sets of | ||
695 | * macros are defined here: | ||
696 | * - Abs, Min and Max to apply to constant expressions (values known at | ||
697 | * compile time); | ||
698 | * - abs, min and max to apply to non-constant expressions (values unknown at | ||
699 | * compile time), abs is found in stdlib.h. | ||
700 | * | ||
701 | * @{ */ | ||
702 | |||
703 | /** \brief Takes the absolute value of \a a. | ||
704 | * | ||
705 | * \param[in] a Input value. | ||
706 | * | ||
707 | * \return Absolute value of \a a. | ||
708 | * | ||
709 | * \note More optimized if only used with values known at compile time. | ||
710 | */ | ||
711 | #define Abs(a) (((a) < 0 ) ? -(a) : (a)) | ||
712 | |||
713 | #ifndef __cplusplus | ||
714 | /** \brief Takes the minimal value of \a a and \a b. | ||
715 | * | ||
716 | * \param[in] a Input value. | ||
717 | * \param[in] b Input value. | ||
718 | * | ||
719 | * \return Minimal value of \a a and \a b. | ||
720 | * | ||
721 | * \note More optimized if only used with values known at compile time. | ||
722 | */ | ||
723 | #define Min(a, b) (((a) < (b)) ? (a) : (b)) | ||
724 | |||
725 | /** \brief Takes the maximal value of \a a and \a b. | ||
726 | * | ||
727 | * \param[in] a Input value. | ||
728 | * \param[in] b Input value. | ||
729 | * | ||
730 | * \return Maximal value of \a a and \a b. | ||
731 | * | ||
732 | * \note More optimized if only used with values known at compile time. | ||
733 | */ | ||
734 | #define Max(a, b) (((a) > (b)) ? (a) : (b)) | ||
735 | |||
736 | /** \brief Takes the minimal value of \a a and \a b. | ||
737 | * | ||
738 | * \param[in] a Input value. | ||
739 | * \param[in] b Input value. | ||
740 | * | ||
741 | * \return Minimal value of \a a and \a b. | ||
742 | * | ||
743 | * \note More optimized if only used with values unknown at compile time. | ||
744 | */ | ||
745 | #define min(a, b) Min(a, b) | ||
746 | |||
747 | /** \brief Takes the maximal value of \a a and \a b. | ||
748 | * | ||
749 | * \param[in] a Input value. | ||
750 | * \param[in] b Input value. | ||
751 | * | ||
752 | * \return Maximal value of \a a and \a b. | ||
753 | * | ||
754 | * \note More optimized if only used with values unknown at compile time. | ||
755 | */ | ||
756 | #define max(a, b) Max(a, b) | ||
757 | #endif | ||
758 | |||
759 | /** @} */ | ||
760 | |||
761 | |||
762 | /** \brief Calls the routine at address \a addr. | ||
763 | * | ||
764 | * It generates a long call opcode. | ||
765 | * | ||
766 | * For example, `Long_call(0x80000000)' generates a software reset on a UC3 if | ||
767 | * it is invoked from the CPU supervisor mode. | ||
768 | * | ||
769 | * \param[in] addr Address of the routine to call. | ||
770 | * | ||
771 | * \note It may be used as a long jump opcode in some special cases. | ||
772 | */ | ||
773 | #define Long_call(addr) ((*(void (*)(void))(addr))()) | ||
774 | |||
775 | |||
776 | /** \name MCU Endianism Handling | ||
777 | * ARM is MCU little endian. | ||
778 | * | ||
779 | * @{ */ | ||
780 | #define BE16(x) swap16(x) | ||
781 | #define LE16(x) (x) | ||
782 | |||
783 | #define le16_to_cpu(x) (x) | ||
784 | #define cpu_to_le16(x) (x) | ||
785 | #define LE16_TO_CPU(x) (x) | ||
786 | #define CPU_TO_LE16(x) (x) | ||
787 | |||
788 | #define be16_to_cpu(x) swap16(x) | ||
789 | #define cpu_to_be16(x) swap16(x) | ||
790 | #define BE16_TO_CPU(x) swap16(x) | ||
791 | #define CPU_TO_BE16(x) swap16(x) | ||
792 | |||
793 | #define le32_to_cpu(x) (x) | ||
794 | #define cpu_to_le32(x) (x) | ||
795 | #define LE32_TO_CPU(x) (x) | ||
796 | #define CPU_TO_LE32(x) (x) | ||
797 | |||
798 | #define be32_to_cpu(x) swap32(x) | ||
799 | #define cpu_to_be32(x) swap32(x) | ||
800 | #define BE32_TO_CPU(x) swap32(x) | ||
801 | #define CPU_TO_BE32(x) swap32(x) | ||
802 | /** @} */ | ||
803 | |||
804 | |||
805 | /** \name Endianism Conversion | ||
806 | * | ||
807 | * The same considerations as for clz and ctz apply here but GCC's | ||
808 | * __builtin_bswap_32 and __builtin_bswap_64 do not behave like macros when | ||
809 | * applied to constant expressions, so two sets of macros are defined here: | ||
810 | * - Swap16, Swap32 and Swap64 to apply to constant expressions (values known | ||
811 | * at compile time); | ||
812 | * - swap16, swap32 and swap64 to apply to non-constant expressions (values | ||
813 | * unknown at compile time). | ||
814 | * | ||
815 | * @{ */ | ||
816 | |||
817 | /** \brief Toggles the endianism of \a u16 (by swapping its bytes). | ||
818 | * | ||
819 | * \param[in] u16 U16 of which to toggle the endianism. | ||
820 | * | ||
821 | * \return Value resulting from \a u16 with toggled endianism. | ||
822 | * | ||
823 | * \note More optimized if only used with values known at compile time. | ||
824 | */ | ||
825 | #define Swap16(u16) ((uint16_t)(((uint16_t)(u16) >> 8) |\ | ||
826 | ((uint16_t)(u16) << 8))) | ||
827 | |||
828 | /** \brief Toggles the endianism of \a u32 (by swapping its bytes). | ||
829 | * | ||
830 | * \param[in] u32 U32 of which to toggle the endianism. | ||
831 | * | ||
832 | * \return Value resulting from \a u32 with toggled endianism. | ||
833 | * | ||
834 | * \note More optimized if only used with values known at compile time. | ||
835 | */ | ||
836 | #define Swap32(u32) ((uint32_t)(((uint32_t)Swap16((uint32_t)(u32) >> 16)) |\ | ||
837 | ((uint32_t)Swap16((uint32_t)(u32)) << 16))) | ||
838 | |||
839 | /** \brief Toggles the endianism of \a u64 (by swapping its bytes). | ||
840 | * | ||
841 | * \param[in] u64 U64 of which to toggle the endianism. | ||
842 | * | ||
843 | * \return Value resulting from \a u64 with toggled endianism. | ||
844 | * | ||
845 | * \note More optimized if only used with values known at compile time. | ||
846 | */ | ||
847 | #define Swap64(u64) ((uint64_t)(((uint64_t)Swap32((uint64_t)(u64) >> 32)) |\ | ||
848 | ((uint64_t)Swap32((uint64_t)(u64)) << 32))) | ||
849 | |||
850 | /** \brief Toggles the endianism of \a u16 (by swapping its bytes). | ||
851 | * | ||
852 | * \param[in] u16 U16 of which to toggle the endianism. | ||
853 | * | ||
854 | * \return Value resulting from \a u16 with toggled endianism. | ||
855 | * | ||
856 | * \note More optimized if only used with values unknown at compile time. | ||
857 | */ | ||
858 | #define swap16(u16) Swap16(u16) | ||
859 | |||
860 | /** \brief Toggles the endianism of \a u32 (by swapping its bytes). | ||
861 | * | ||
862 | * \param[in] u32 U32 of which to toggle the endianism. | ||
863 | * | ||
864 | * \return Value resulting from \a u32 with toggled endianism. | ||
865 | * | ||
866 | * \note More optimized if only used with values unknown at compile time. | ||
867 | */ | ||
868 | #if (defined __GNUC__) | ||
869 | # define swap32(u32) ((uint32_t)__builtin_bswap32((uint32_t)(u32))) | ||
870 | #else | ||
871 | # define swap32(u32) Swap32(u32) | ||
872 | #endif | ||
873 | |||
874 | /** \brief Toggles the endianism of \a u64 (by swapping its bytes). | ||
875 | * | ||
876 | * \param[in] u64 U64 of which to toggle the endianism. | ||
877 | * | ||
878 | * \return Value resulting from \a u64 with toggled endianism. | ||
879 | * | ||
880 | * \note More optimized if only used with values unknown at compile time. | ||
881 | */ | ||
882 | #if (defined __GNUC__) | ||
883 | # define swap64(u64) ((uint64_t)__builtin_bswap64((uint64_t)(u64))) | ||
884 | #else | ||
885 | # define swap64(u64) ((uint64_t)(((uint64_t)swap32((uint64_t)(u64) >> 32)) |\ | ||
886 | ((uint64_t)swap32((uint64_t)(u64)) << 32))) | ||
887 | #endif | ||
888 | |||
889 | /** @} */ | ||
890 | |||
891 | |||
892 | /** \name Target Abstraction | ||
893 | * | ||
894 | * @{ */ | ||
895 | |||
896 | #define _GLOBEXT_ extern /**< extern storage-class specifier. */ | ||
897 | #define _CONST_TYPE_ const /**< const type qualifier. */ | ||
898 | #define _MEM_TYPE_SLOW_ /**< Slow memory type. */ | ||
899 | #define _MEM_TYPE_MEDFAST_ /**< Fairly fast memory type. */ | ||
900 | #define _MEM_TYPE_FAST_ /**< Fast memory type. */ | ||
901 | |||
902 | #define memcmp_ram2ram memcmp /**< Target-specific memcmp of RAM to RAM. */ | ||
903 | #define memcmp_code2ram memcmp /**< Target-specific memcmp of RAM to NVRAM. */ | ||
904 | #define memcpy_ram2ram memcpy /**< Target-specific memcpy from RAM to RAM. */ | ||
905 | #define memcpy_code2ram memcpy /**< Target-specific memcpy from NVRAM to RAM. */ | ||
906 | |||
907 | /** @} */ | ||
908 | |||
909 | /** | ||
910 | * \brief Calculate \f$ \left\lceil \frac{a}{b} \right\rceil \f$ using | ||
911 | * integer arithmetic. | ||
912 | * | ||
913 | * \param[in] a An integer | ||
914 | * \param[in] b Another integer | ||
915 | * | ||
916 | * \return (\a a / \a b) rounded up to the nearest integer. | ||
917 | */ | ||
918 | #define div_ceil(a, b) (((a) + (b) - 1) / (b)) | ||
919 | |||
920 | #endif /* #ifndef __ASSEMBLY__ */ | ||
921 | #ifdef __ICCARM__ | ||
922 | /** \name Compiler Keywords | ||
923 | * | ||
924 | * Port of some keywords from GCC to IAR Embedded Workbench. | ||
925 | * | ||
926 | * @{ */ | ||
927 | |||
928 | #define __asm__ asm | ||
929 | #define __inline__ inline | ||
930 | #define __volatile__ | ||
931 | |||
932 | /** @} */ | ||
933 | |||
934 | #endif | ||
935 | |||
936 | #define FUNC_PTR void * | ||
937 | /** | ||
938 | * \def unused | ||
939 | * \brief Marking \a v as a unused parameter or value. | ||
940 | */ | ||
941 | #define unused(v) do { (void)(v); } while(0) | ||
942 | |||
943 | /* Define RAMFUNC attribute */ | ||
944 | #if defined ( __CC_ARM ) /* Keil uVision 4 */ | ||
945 | # define RAMFUNC __attribute__ ((section(".ramfunc"))) | ||
946 | #elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ | ||
947 | # define RAMFUNC __ramfunc | ||
948 | #elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ | ||
949 | # define RAMFUNC __attribute__ ((section(".ramfunc"))) | ||
950 | #endif | ||
951 | |||
952 | /* Define OPTIMIZE_HIGH attribute */ | ||
953 | #if defined ( __CC_ARM ) /* Keil uVision 4 */ | ||
954 | # define OPTIMIZE_HIGH _Pragma("O3") | ||
955 | #elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ | ||
956 | # define OPTIMIZE_HIGH _Pragma("optimize=high") | ||
957 | #elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ | ||
958 | # define OPTIMIZE_HIGH __attribute__((optimize("s"))) | ||
959 | #endif | ||
960 | //kmod #define PASS 0 | ||
961 | //kmod #define FAIL 1 | ||
962 | //kmod #define LOW 0 | ||
963 | //kmod #define HIGH 1 | ||
964 | |||
965 | typedef int8_t S8 ; //!< 8-bit signed integer. | ||
966 | typedef uint8_t U8 ; //!< 8-bit unsigned integer. | ||
967 | typedef int16_t S16; //!< 16-bit signed integer. | ||
968 | typedef uint16_t U16; //!< 16-bit unsigned integer. | ||
969 | typedef int32_t S32; //!< 32-bit signed integer. | ||
970 | typedef uint32_t U32; //!< 32-bit unsigned integer. | ||
971 | typedef int64_t S64; //!< 64-bit signed integer. | ||
972 | typedef uint64_t U64; //!< 64-bit unsigned integer. | ||
973 | typedef float F32; //!< 32-bit floating-point number. | ||
974 | typedef double F64; //!< 64-bit floating-point number. | ||
975 | |||
976 | #define MSB(u16) (((U8 *)&(u16))[1]) //!< Most significant byte of \a u16. | ||
977 | #define LSB(u16) (((U8 *)&(u16))[0]) //!< Least significant byte of \a u16. | ||
978 | |||
979 | #define MSH(u32) (((U16 *)&(u32))[1]) //!< Most significant half-word of \a u32. | ||
980 | #define LSH(u32) (((U16 *)&(u32))[0]) //!< Least significant half-word of \a u32. | ||
981 | #define MSB0W(u32) (((U8 *)&(u32))[3]) //!< Most significant byte of 1st rank of \a u32. | ||
982 | #define MSB1W(u32) (((U8 *)&(u32))[2]) //!< Most significant byte of 2nd rank of \a u32. | ||
983 | #define MSB2W(u32) (((U8 *)&(u32))[1]) //!< Most significant byte of 3rd rank of \a u32. | ||
984 | #define MSB3W(u32) (((U8 *)&(u32))[0]) //!< Most significant byte of 4th rank of \a u32. | ||
985 | #define LSB3W(u32) MSB0W(u32) //!< Least significant byte of 4th rank of \a u32. | ||
986 | #define LSB2W(u32) MSB1W(u32) //!< Least significant byte of 3rd rank of \a u32. | ||
987 | #define LSB1W(u32) MSB2W(u32) //!< Least significant byte of 2nd rank of \a u32. | ||
988 | #define LSB0W(u32) MSB3W(u32) //!< Least significant byte of 1st rank of \a u32. | ||
989 | |||
990 | #define MSW(u64) (((U32 *)&(u64))[1]) //!< Most significant word of \a u64. | ||
991 | #define LSW(u64) (((U32 *)&(u64))[0]) //!< Least significant word of \a u64. | ||
992 | #define MSH0(u64) (((U16 *)&(u64))[3]) //!< Most significant half-word of 1st rank of \a u64. | ||
993 | #define MSH1(u64) (((U16 *)&(u64))[2]) //!< Most significant half-word of 2nd rank of \a u64. | ||
994 | #define MSH2(u64) (((U16 *)&(u64))[1]) //!< Most significant half-word of 3rd rank of \a u64. | ||
995 | #define MSH3(u64) (((U16 *)&(u64))[0]) //!< Most significant half-word of 4th rank of \a u64. | ||
996 | #define LSH3(u64) MSH0(u64) //!< Least significant half-word of 4th rank of \a u64. | ||
997 | #define LSH2(u64) MSH1(u64) //!< Least significant half-word of 3rd rank of \a u64. | ||
998 | #define LSH1(u64) MSH2(u64) //!< Least significant half-word of 2nd rank of \a u64. | ||
999 | #define LSH0(u64) MSH3(u64) //!< Least significant half-word of 1st rank of \a u64. | ||
1000 | #define MSB0D(u64) (((U8 *)&(u64))[7]) //!< Most significant byte of 1st rank of \a u64. | ||
1001 | #define MSB1D(u64) (((U8 *)&(u64))[6]) //!< Most significant byte of 2nd rank of \a u64. | ||
1002 | #define MSB2D(u64) (((U8 *)&(u64))[5]) //!< Most significant byte of 3rd rank of \a u64. | ||
1003 | #define MSB3D(u64) (((U8 *)&(u64))[4]) //!< Most significant byte of 4th rank of \a u64. | ||
1004 | #define MSB4D(u64) (((U8 *)&(u64))[3]) //!< Most significant byte of 5th rank of \a u64. | ||
1005 | #define MSB5D(u64) (((U8 *)&(u64))[2]) //!< Most significant byte of 6th rank of \a u64. | ||
1006 | #define MSB6D(u64) (((U8 *)&(u64))[1]) //!< Most significant byte of 7th rank of \a u64. | ||
1007 | #define MSB7D(u64) (((U8 *)&(u64))[0]) //!< Most significant byte of 8th rank of \a u64. | ||
1008 | #define LSB7D(u64) MSB0D(u64) //!< Least significant byte of 8th rank of \a u64. | ||
1009 | #define LSB6D(u64) MSB1D(u64) //!< Least significant byte of 7th rank of \a u64. | ||
1010 | #define LSB5D(u64) MSB2D(u64) //!< Least significant byte of 6th rank of \a u64. | ||
1011 | #define LSB4D(u64) MSB3D(u64) //!< Least significant byte of 5th rank of \a u64. | ||
1012 | #define LSB3D(u64) MSB4D(u64) //!< Least significant byte of 4th rank of \a u64. | ||
1013 | #define LSB2D(u64) MSB5D(u64) //!< Least significant byte of 3rd rank of \a u64. | ||
1014 | #define LSB1D(u64) MSB6D(u64) //!< Least significant byte of 2nd rank of \a u64. | ||
1015 | #define LSB0D(u64) MSB7D(u64) //!< Least significant byte of 1st rank of \a u64. | ||
1016 | |||
1017 | #define LSB0(u32) LSB0W(u32) //!< Least significant byte of 1st rank of \a u32. | ||
1018 | #define LSB1(u32) LSB1W(u32) //!< Least significant byte of 2nd rank of \a u32. | ||
1019 | #define LSB2(u32) LSB2W(u32) //!< Least significant byte of 3rd rank of \a u32. | ||
1020 | #define LSB3(u32) LSB3W(u32) //!< Least significant byte of 4th rank of \a u32. | ||
1021 | #define MSB3(u32) MSB3W(u32) //!< Most significant byte of 4th rank of \a u32. | ||
1022 | #define MSB2(u32) MSB2W(u32) //!< Most significant byte of 3rd rank of \a u32. | ||
1023 | #define MSB1(u32) MSB1W(u32) //!< Most significant byte of 2nd rank of \a u32. | ||
1024 | #define MSB0(u32) MSB0W(u32) //!< Most significant byte of 1st rank of \a u32. | ||
1025 | |||
1026 | #if defined(__ICCARM__) | ||
1027 | #define SHORTENUM __packed | ||
1028 | #elif defined(__GNUC__) | ||
1029 | #define SHORTENUM __attribute__((packed)) | ||
1030 | #endif | ||
1031 | |||
1032 | /* No operation */ | ||
1033 | #if defined(__ICCARM__) | ||
1034 | #define nop() __no_operation() | ||
1035 | #elif defined(__GNUC__) | ||
1036 | #define nop() (__NOP()) | ||
1037 | #endif | ||
1038 | |||
1039 | #define FLASH_DECLARE(x) const x | ||
1040 | #define FLASH_EXTERN(x) extern const x | ||
1041 | #define PGM_READ_BYTE(x) *(x) | ||
1042 | #define PGM_READ_WORD(x) *(x) | ||
1043 | #define MEMCPY_ENDIAN memcpy | ||
1044 | #define PGM_READ_BLOCK(dst, src, len) memcpy((dst), (src), (len)) | ||
1045 | |||
1046 | /*Defines the Flash Storage for the request and response of MAC*/ | ||
1047 | #define CMD_ID_OCTET (0) | ||
1048 | |||
1049 | /* Converting of values from CPU endian to little endian. */ | ||
1050 | #define CPU_ENDIAN_TO_LE16(x) (x) | ||
1051 | #define CPU_ENDIAN_TO_LE32(x) (x) | ||
1052 | #define CPU_ENDIAN_TO_LE64(x) (x) | ||
1053 | |||
1054 | /* Converting of values from little endian to CPU endian. */ | ||
1055 | #define LE16_TO_CPU_ENDIAN(x) (x) | ||
1056 | #define LE32_TO_CPU_ENDIAN(x) (x) | ||
1057 | #define LE64_TO_CPU_ENDIAN(x) (x) | ||
1058 | |||
1059 | /* Converting of constants from little endian to CPU endian. */ | ||
1060 | #define CLE16_TO_CPU_ENDIAN(x) (x) | ||
1061 | #define CLE32_TO_CPU_ENDIAN(x) (x) | ||
1062 | #define CLE64_TO_CPU_ENDIAN(x) (x) | ||
1063 | |||
1064 | /* Converting of constants from CPU endian to little endian. */ | ||
1065 | #define CCPU_ENDIAN_TO_LE16(x) (x) | ||
1066 | #define CCPU_ENDIAN_TO_LE32(x) (x) | ||
1067 | #define CCPU_ENDIAN_TO_LE64(x) (x) | ||
1068 | |||
1069 | #define ADDR_COPY_DST_SRC_16(dst, src) ((dst) = (src)) | ||
1070 | #define ADDR_COPY_DST_SRC_64(dst, src) ((dst) = (src)) | ||
1071 | |||
1072 | /** | ||
1073 | * @brief Converts a 64-Bit value into a 8 Byte array | ||
1074 | * | ||
1075 | * @param[in] value 64-Bit value | ||
1076 | * @param[out] data Pointer to the 8 Byte array to be updated with 64-Bit value | ||
1077 | * @ingroup apiPalApi | ||
1078 | */ | ||
1079 | static inline void convert_64_bit_to_byte_array(uint64_t value, uint8_t *data) | ||
1080 | { | ||
1081 | uint8_t index = 0; | ||
1082 | |||
1083 | while (index < 8) | ||
1084 | { | ||
1085 | data[index++] = value & 0xFF; | ||
1086 | value = value >> 8; | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | /** | ||
1091 | * @brief Converts a 16-Bit value into a 2 Byte array | ||
1092 | * | ||
1093 | * @param[in] value 16-Bit value | ||
1094 | * @param[out] data Pointer to the 2 Byte array to be updated with 16-Bit value | ||
1095 | * @ingroup apiPalApi | ||
1096 | */ | ||
1097 | static inline void convert_16_bit_to_byte_array(uint16_t value, uint8_t *data) | ||
1098 | { | ||
1099 | data[0] = value & 0xFF; | ||
1100 | data[1] = (value >> 8) & 0xFF; | ||
1101 | } | ||
1102 | |||
1103 | /* Converts a 16-Bit value into a 2 Byte array */ | ||
1104 | static inline void convert_spec_16_bit_to_byte_array(uint16_t value, uint8_t *data) | ||
1105 | { | ||
1106 | data[0] = value & 0xFF; | ||
1107 | data[1] = (value >> 8) & 0xFF; | ||
1108 | } | ||
1109 | |||
1110 | /* Converts a 16-Bit value into a 2 Byte array */ | ||
1111 | static inline void convert_16_bit_to_byte_address(uint16_t value, uint8_t *data) | ||
1112 | { | ||
1113 | data[0] = value & 0xFF; | ||
1114 | data[1] = (value >> 8) & 0xFF; | ||
1115 | } | ||
1116 | |||
1117 | /* | ||
1118 | * @brief Converts a 2 Byte array into a 16-Bit value | ||
1119 | * | ||
1120 | * @param data Specifies the pointer to the 2 Byte array | ||
1121 | * | ||
1122 | * @return 16-Bit value | ||
1123 | * @ingroup apiPalApi | ||
1124 | */ | ||
1125 | static inline uint16_t convert_byte_array_to_16_bit(uint8_t *data) | ||
1126 | { | ||
1127 | return (data[0] | ((uint16_t)data[1] << 8)); | ||
1128 | } | ||
1129 | |||
1130 | /* Converts a 4 Byte array into a 32-Bit value */ | ||
1131 | static inline uint32_t convert_byte_array_to_32_bit(uint8_t *data) | ||
1132 | { | ||
1133 | union | ||
1134 | { | ||
1135 | uint32_t u32; | ||
1136 | uint8_t u8[4]; | ||
1137 | } long_addr; | ||
1138 | |||
1139 | uint8_t index; | ||
1140 | |||
1141 | for (index = 0; index < 4; index++) | ||
1142 | { | ||
1143 | long_addr.u8[index] = *data++; | ||
1144 | } | ||
1145 | |||
1146 | return long_addr.u32; | ||
1147 | } | ||
1148 | |||
1149 | /** | ||
1150 | * @brief Converts a 8 Byte array into a 64-Bit value | ||
1151 | * | ||
1152 | * @param data Specifies the pointer to the 8 Byte array | ||
1153 | * | ||
1154 | * @return 64-Bit value | ||
1155 | * @ingroup apiPalApi | ||
1156 | */ | ||
1157 | static inline uint64_t convert_byte_array_to_64_bit(uint8_t *data) | ||
1158 | { | ||
1159 | union | ||
1160 | { | ||
1161 | uint64_t u64; | ||
1162 | uint8_t u8[8]; | ||
1163 | } long_addr; | ||
1164 | |||
1165 | uint8_t index; | ||
1166 | |||
1167 | for (index = 0; index < 8; index++) | ||
1168 | { | ||
1169 | long_addr.u8[index] = *data++; | ||
1170 | } | ||
1171 | |||
1172 | return long_addr.u64; | ||
1173 | } | ||
1174 | |||
1175 | /** @} */ | ||
1176 | |||
1177 | #endif /* UTILS_COMPILER_H_INCLUDED */ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/conf_usb.h b/tmk_core/protocol/arm_atsam/usb/conf_usb.h new file mode 100644 index 000000000..8f0f47268 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/conf_usb.h | |||
@@ -0,0 +1,163 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB configuration file | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _CONF_USB_H_ | ||
48 | #define _CONF_USB_H_ | ||
49 | |||
50 | #include "compiler.h" | ||
51 | #include "udi_device_conf.h" | ||
52 | |||
53 | #define UDI_CDC_DEFAULT_RATE 115200 | ||
54 | #define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1 | ||
55 | #define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE | ||
56 | #define UDI_CDC_DEFAULT_DATABITS 8 | ||
57 | |||
58 | //! Device definition (mandatory) | ||
59 | #define USB_DEVICE_VENDOR_ID VENDOR_ID | ||
60 | #define USB_DEVICE_PRODUCT_ID PRODUCT_ID | ||
61 | #define USB_DEVICE_VERSION DEVICE_VER | ||
62 | #define USB_DEVICE_POWER 500 // Consumption on Vbus line (mA) | ||
63 | #define USB_DEVICE_ATTR (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED) | ||
64 | // (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED) | ||
65 | // (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED) | ||
66 | // (USB_CONFIG_ATTR_SELF_POWERED) | ||
67 | // (USB_CONFIG_ATTR_BUS_POWERED) | ||
68 | |||
69 | //! USB Device string definitions (Optional) | ||
70 | #define USB_DEVICE_MANUFACTURE_NAME MANUFACTURER | ||
71 | #define USB_DEVICE_PRODUCT_NAME PRODUCT | ||
72 | #define USB_DEVICE_SERIAL_NAME SERIAL_NUM | ||
73 | |||
74 | //Comment out USB_DEVICE_SERIAL_USE_BOOTLOADER_SERIAL to prevent ROM lookup of factory programmed serial number | ||
75 | #define USB_DEVICE_SERIAL_USE_BOOTLOADER_SERIAL | ||
76 | |||
77 | /** | ||
78 | * Device speeds support | ||
79 | * @{ | ||
80 | */ | ||
81 | //! To define a Low speed device | ||
82 | //#define USB_DEVICE_LOW_SPEED | ||
83 | |||
84 | //! To authorize the High speed | ||
85 | #if (UC3A3||UC3A4) | ||
86 | //#define USB_DEVICE_HS_SUPPORT | ||
87 | #elif (SAM3XA||SAM3U) | ||
88 | //#define USB_DEVICE_HS_SUPPORT | ||
89 | #endif | ||
90 | //@} | ||
91 | |||
92 | /** | ||
93 | * USB Device Callbacks definitions (Optional) | ||
94 | * @{ | ||
95 | */ | ||
96 | #define UDC_VBUS_EVENT(b_vbus_high) | ||
97 | #define UDC_SOF_EVENT() main_sof_action() | ||
98 | #define UDC_SUSPEND_EVENT() main_suspend_action() | ||
99 | #define UDC_RESUME_EVENT() main_resume_action() | ||
100 | //! Mandatory when USB_DEVICE_ATTR authorizes remote wakeup feature | ||
101 | #define UDC_REMOTEWAKEUP_ENABLE() main_remotewakeup_enable() | ||
102 | #define UDC_REMOTEWAKEUP_DISABLE() main_remotewakeup_disable() | ||
103 | //! When a extra string descriptor must be supported | ||
104 | //! other than manufacturer, product and serial string | ||
105 | // #define UDC_GET_EXTRA_STRING() | ||
106 | //@} | ||
107 | |||
108 | //@} | ||
109 | |||
110 | |||
111 | /** | ||
112 | * USB Interface Configuration | ||
113 | * @{ | ||
114 | */ | ||
115 | /** | ||
116 | * Configuration of HID Keyboard interface | ||
117 | * @{ | ||
118 | */ | ||
119 | //! Interface callback definition | ||
120 | #ifdef KBD | ||
121 | #define UDI_HID_KBD_ENABLE_EXT() main_kbd_enable() | ||
122 | #define UDI_HID_KBD_DISABLE_EXT() main_kbd_disable() | ||
123 | //#define UDI_HID_KBD_CHANGE_LED(value) ui_kbd_led(value) | ||
124 | #endif | ||
125 | |||
126 | #ifdef NKRO | ||
127 | #define UDI_HID_NKRO_ENABLE_EXT() main_nkro_enable() | ||
128 | #define UDI_HID_NKRO_DISABLE_EXT() main_nkro_disable() | ||
129 | //#define UDI_HID_NKRO_CHANGE_LED(value) ui_kbd_led(value) | ||
130 | #endif | ||
131 | |||
132 | #ifdef EXK | ||
133 | #define UDI_HID_EXK_ENABLE_EXT() main_exk_enable() | ||
134 | #define UDI_HID_EXK_DISABLE_EXT() main_exk_disable() | ||
135 | #endif | ||
136 | |||
137 | #ifdef MOU | ||
138 | #define UDI_HID_MOU_ENABLE_EXT() main_mou_enable() | ||
139 | #define UDI_HID_MOU_DISABLE_EXT() main_mou_disable() | ||
140 | #endif | ||
141 | |||
142 | #ifdef RAW | ||
143 | #define UDI_HID_RAW_ENABLE_EXT() main_raw_enable() | ||
144 | #define UDI_HID_RAW_DISABLE_EXT() main_raw_disable() | ||
145 | #endif | ||
146 | |||
147 | |||
148 | //@} | ||
149 | //@} | ||
150 | |||
151 | |||
152 | /** | ||
153 | * USB Device Driver Configuration | ||
154 | * @{ | ||
155 | */ | ||
156 | //@} | ||
157 | |||
158 | //! The includes of classes and other headers must be done at the end of this file to avoid compile error | ||
159 | #include "udi_hid_kbd_conf.h" | ||
160 | #include "usb_main.h" | ||
161 | #include "ui.h" | ||
162 | |||
163 | #endif // _CONF_USB_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/main_usb.c b/tmk_core/protocol/arm_atsam/usb/main_usb.c new file mode 100644 index 000000000..e943cbcdc --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/main_usb.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "samd51j18a.h" | ||
19 | #include "conf_usb.h" | ||
20 | #include "udd.h" | ||
21 | |||
22 | uint8_t keyboard_protocol = 1; | ||
23 | |||
24 | void main_suspend_action(void) | ||
25 | { | ||
26 | ui_powerdown(); | ||
27 | } | ||
28 | |||
29 | void main_resume_action(void) | ||
30 | { | ||
31 | ui_wakeup(); | ||
32 | } | ||
33 | |||
34 | void main_sof_action(void) | ||
35 | { | ||
36 | ui_process(udd_get_frame_number()); | ||
37 | } | ||
38 | |||
39 | void main_remotewakeup_enable(void) | ||
40 | { | ||
41 | ui_wakeup_enable(); | ||
42 | } | ||
43 | |||
44 | void main_remotewakeup_disable(void) | ||
45 | { | ||
46 | ui_wakeup_disable(); | ||
47 | } | ||
48 | |||
49 | #ifdef KBD | ||
50 | volatile bool main_b_kbd_enable = false; | ||
51 | bool main_kbd_enable(void) | ||
52 | { | ||
53 | main_b_kbd_enable = true; | ||
54 | return true; | ||
55 | } | ||
56 | |||
57 | void main_kbd_disable(void) | ||
58 | { | ||
59 | main_b_kbd_enable = false; | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | #ifdef NKRO | ||
64 | volatile bool main_b_nkro_enable = false; | ||
65 | bool main_nkro_enable(void) | ||
66 | { | ||
67 | main_b_nkro_enable = true; | ||
68 | return true; | ||
69 | } | ||
70 | |||
71 | void main_nkro_disable(void) | ||
72 | { | ||
73 | main_b_nkro_enable = false; | ||
74 | } | ||
75 | #endif | ||
76 | |||
77 | #ifdef EXK | ||
78 | volatile bool main_b_exk_enable = false; | ||
79 | bool main_exk_enable(void) | ||
80 | { | ||
81 | main_b_exk_enable = true; | ||
82 | return true; | ||
83 | } | ||
84 | |||
85 | void main_exk_disable(void) | ||
86 | { | ||
87 | main_b_exk_enable = false; | ||
88 | } | ||
89 | #endif | ||
90 | |||
91 | #ifdef MOU | ||
92 | volatile bool main_b_mou_enable = false; | ||
93 | bool main_mou_enable(void) | ||
94 | { | ||
95 | main_b_mou_enable = true; | ||
96 | return true; | ||
97 | } | ||
98 | |||
99 | void main_mou_disable(void) | ||
100 | { | ||
101 | main_b_mou_enable = false; | ||
102 | } | ||
103 | #endif | ||
104 | |||
105 | #ifdef RAW | ||
106 | volatile bool main_b_raw_enable = false; | ||
107 | bool main_raw_enable(void) | ||
108 | { | ||
109 | main_b_raw_enable = true; | ||
110 | return true; | ||
111 | } | ||
112 | |||
113 | void main_raw_disable(void) | ||
114 | { | ||
115 | main_b_raw_enable = false; | ||
116 | } | ||
117 | #endif | ||
118 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/spfssf.c b/tmk_core/protocol/arm_atsam/usb/spfssf.c new file mode 100644 index 000000000..449a8bb7d --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/spfssf.c | |||
@@ -0,0 +1,268 @@ | |||
1 | #include "samd51j18a.h" | ||
2 | #include "stdarg.h" | ||
3 | #include "spfssf.h" | ||
4 | #include "usb_util.h" | ||
5 | |||
6 | int vspf(char *_Dest, const char *_Format, va_list va) | ||
7 | { | ||
8 | //va_list va; //Variable argument list variable | ||
9 | char *d = _Dest; //Pointer to dest | ||
10 | |||
11 | //va_start(va,_Format); //Initialize the variable argument list | ||
12 | while (*_Format) //While not end of format string | ||
13 | { | ||
14 | if (*_Format == SPF_SPEC_START) //If current format string character is the specifier start character | ||
15 | { | ||
16 | _Format++; //Skip over the character | ||
17 | while (*_Format && *_Format <= 64) _Format++; //Forward past any options | ||
18 | if (*_Format == SPF_SPEC_START) *d++ = *_Format; //If the character is the specifier start character, output the character and advance dest | ||
19 | else if (*_Format == SPF_SPEC_LONG) //If the character is the long type | ||
20 | { | ||
21 | _Format++; //Skip over the character | ||
22 | if (*_Format == SPF_SPEC_DECIMAL) //If the character is the decimal type | ||
23 | { | ||
24 | int64_t buf = va_arg(va,int64_t); //Get the next value from the va list | ||
25 | //if (buf < 0) { *d++ = '-'; buf = -buf; } //If the given number is negative, add a negative sign to the dest and invert number | ||
26 | //spf_uint2str_32_3t(&d,buf,32); //Perform the conversion | ||
27 | d += UTIL_ltoa_radix(buf, d, 10); | ||
28 | } | ||
29 | else if (*_Format == SPF_SPEC_UNSIGNED) //If the character is the unsigned type | ||
30 | { | ||
31 | uint64_t num = va_arg(va,uint64_t); //Get the next value from the va list | ||
32 | //spf_uint2str_32_3t(&d,num,32); //Perform the conversion | ||
33 | d += UTIL_ltoa_radix(num, d, 10); | ||
34 | } | ||
35 | else if (*_Format == SPF_SPEC_UHINT || *_Format == SPF_SPEC_UHINT_UP) //If the character is the unsigned type | ||
36 | { | ||
37 | uint64_t buf = va_arg(va,uint64_t); //Get the next value from the va list | ||
38 | //spf_uint2hex_32(&d,(unsigned long) buf); | ||
39 | d += UTIL_ltoa_radix(buf, d, 16); | ||
40 | } | ||
41 | else //If the character was not a known type | ||
42 | { | ||
43 | *d++ = SPF_SPEC_START; //Output the start specifier | ||
44 | *d++ = SPF_SPEC_LONG; //Output the long type | ||
45 | *d++ = *_Format; //Output the unknown type | ||
46 | } | ||
47 | } | ||
48 | else if (*_Format == SPF_SPEC_DECIMAL) //If the character is the decimal type | ||
49 | { | ||
50 | int buf = va_arg(va,int); //Get the next value from the va list | ||
51 | //if (buf < 0) { *d++ = '-'; buf = -buf; } //If the given number is negative, add a negative sign to the dest and invert number | ||
52 | //spf_uint2str_32_3t(&d,buf,16); //Perform the conversion | ||
53 | d += UTIL_itoa(buf, d); | ||
54 | } | ||
55 | else if (*_Format == SPF_SPEC_INT) //If the character is the integer type | ||
56 | { | ||
57 | int buf = va_arg(va,int); //Get the next value from the va list | ||
58 | //if (buf < 0) { *d++ = '-'; buf = -buf; } //If the given number is negative, add a negative sign to the dest and inverted number | ||
59 | //spf_uint2str_32_3t(&d,buf,16); //Perform the conversion | ||
60 | d += UTIL_itoa(buf, d); | ||
61 | } | ||
62 | else if (*_Format == SPF_SPEC_UINT) //If the character is the unsigned integer type | ||
63 | { | ||
64 | int buf = va_arg(va,int); //Get the next value from the va list | ||
65 | //spf_uint2str_32_3t(&d,buf,16); //Perform the conversion | ||
66 | d += UTIL_utoa(buf, d); | ||
67 | } | ||
68 | else if (*_Format == SPF_SPEC_STRING) //If the character is the string type | ||
69 | { | ||
70 | char *buf = va_arg(va,char*); //Get the next value from the va list | ||
71 | while (*buf) *d++ = *buf++; //Perform the conversion (simply output characters and adcance pointers) | ||
72 | } | ||
73 | else if (*_Format == SPF_SPEC_UHINT || *_Format == SPF_SPEC_UHINT_UP) //If the character is the short type | ||
74 | { | ||
75 | int buf = va_arg(va,unsigned int); //Get the next value from the va list | ||
76 | //spf_uint2hex_32(&d,(unsigned long) buf); //Perform the conversion | ||
77 | d += UTIL_utoa(buf, d); | ||
78 | } | ||
79 | else //If the character type is unknown | ||
80 | { | ||
81 | *d++ = SPF_SPEC_START; //Output the start specifier | ||
82 | *d++ = *_Format; //Output the unknown type | ||
83 | } | ||
84 | } | ||
85 | else *d++ = *_Format; //If the character is unknown, output it to dest and advance dest | ||
86 | _Format++; //Advance the format buffer pointer to next character | ||
87 | } | ||
88 | //va_end(va); //End the variable argument list | ||
89 | |||
90 | *d = '\0'; //Cap off the destination string with a zero | ||
91 | |||
92 | return d - _Dest; //Return the length of the destintion buffer | ||
93 | } | ||
94 | |||
95 | int spf(char *_Dest, const char *_Format, ...) | ||
96 | { | ||
97 | va_list va; //Variable argument list variable | ||
98 | int result; | ||
99 | |||
100 | va_start(va,_Format); //Initialize the variable argument list | ||
101 | result = vspf(_Dest, _Format, va); | ||
102 | va_end(va); | ||
103 | return result; | ||
104 | } | ||
105 | |||
106 | //sscanf string to number (integer types) | ||
107 | int64_t ssf_ston(const char **_Src, uint32_t count, uint32_t *conv_count) | ||
108 | { | ||
109 | int64_t value = 0; //Return value accumulator | ||
110 | uint32_t counter=count; //Counter to keep track of numbers converted | ||
111 | const char* p; //Pointer to first non space character | ||
112 | |||
113 | while (*(*_Src) == SSF_SKIP_SPACE) (*_Src)++; //Forward through the whitespace to next non whitespace | ||
114 | |||
115 | p = (*_Src); //Set pointer to first non space character | ||
116 | if (*p == '+' || *p == '-') (*_Src)++; //Skip over sign if any | ||
117 | while (*(*_Src) >= ASCII_NUM_START && | ||
118 | *(*_Src) <= ASCII_NUM_END && | ||
119 | counter) //While the source character is a digit and counter is not zero | ||
120 | { | ||
121 | value *= 10; //Multiply result by 10 to make room for next 1's place number | ||
122 | value += *(*_Src)++ - ASCII_NUM_START; //Add source number to value | ||
123 | counter--; //Decrement counter | ||
124 | } | ||
125 | if (counter - count == 0) return 0; //If no number conversion were performed, return 0 | ||
126 | if (*p == '-') value = -value; //If the number given was negative, make the result negative | ||
127 | |||
128 | if (conv_count) (*conv_count)++; //Increment the converted count | ||
129 | return value; //Return the value | ||
130 | } | ||
131 | |||
132 | uint64_t ssf_hton(const char **_Src, uint32_t count,uint32_t *conv_count) | ||
133 | { | ||
134 | int64_t value=0; //Return value accumulator | ||
135 | uint32_t counter=count; //Counter to keep track of numbers converted | ||
136 | //const char* p; //Pointer to first non space character | ||
137 | char c; | ||
138 | |||
139 | while (*(*_Src) == SSF_SKIP_SPACE) (*_Src)++; //Forward through the whitespace to next non whitespace | ||
140 | |||
141 | //p = (*_Src); //Set pointer to first non space character | ||
142 | |||
143 | while (counter) | ||
144 | { | ||
145 | c = *(*_Src)++; | ||
146 | if (c >= 'a' && c <= 'f') c -= ('a'-'A'); //toupper | ||
147 | if (c < '0' || (c > '9' && c < 'A') || c > 'F') break; | ||
148 | value *= 16; //Multiply result by 10 to make room for next 1's place number | ||
149 | c = c - '0'; | ||
150 | if (c > 9) c -= 7; | ||
151 | value += c; //Add source number to value | ||
152 | counter--; //Decrement counter | ||
153 | } | ||
154 | |||
155 | if (counter - count == 0) return 0; //If no number conversion were performed, return 0 | ||
156 | //if (*p == '-') value = -value; //If the number given was negative, make the result negative | ||
157 | |||
158 | if (conv_count) (*conv_count)++; //Increment the converted count | ||
159 | return value; | ||
160 | } | ||
161 | |||
162 | //sscanf | ||
163 | int ssf(const char *_Src, const char *_Format, ...) | ||
164 | { | ||
165 | va_list va; //Variable argument list variable | ||
166 | unsigned char looking_for=0; //Static char specified in format to be found in source | ||
167 | uint32_t conv_count=0; //Count of conversions made | ||
168 | |||
169 | va_start(va,_Format); //Initialize the variable argument list | ||
170 | while (*_Format) //While the format string has not been fully read | ||
171 | { | ||
172 | if (looking_for != 0) //If we are looking for a matching character in the source string | ||
173 | { | ||
174 | while (*_Src != looking_for && *_Src) _Src++; //While the character is not found in the source string and not the end of the source | ||
175 | // string, increment the pointer position | ||
176 | if (*_Src == looking_for) _Src++; //If the character was found, step over it | ||
177 | else break; //Else the end was reached and the scan is now invalid (Could not find static character) | ||
178 | looking_for = 0; //Clear the looking for character | ||
179 | } | ||
180 | if (*_Format == SSF_SPEC_START) //If the current format character is the specifier start character | ||
181 | { | ||
182 | _Format++; //Step over the specifier start character | ||
183 | if (*_Format == SSF_SPEC_DECIMAL) //If the decimal specifier type is found | ||
184 | { | ||
185 | int *value=va_arg(va,int*); //User given destination address | ||
186 | //*value = (int)ssf_ston(&_Src,5,&conv_count); //Run conversion | ||
187 | *value = (int)ssf_ston(&_Src,10,&conv_count); //Run conversion | ||
188 | } | ||
189 | else if (*_Format == SSF_SPEC_LONG) //If the long specifier type is found | ||
190 | { | ||
191 | _Format++; //Skip over the specifier type | ||
192 | if (*_Format == SSF_SPEC_DECIMAL) //If the decimal specifier type is found | ||
193 | { | ||
194 | int64_t *value=va_arg(va,int64_t*); //User given destination address | ||
195 | //*value = (int64_t)ssf_ston(&_Src,10,&conv_count); //Run conversion | ||
196 | *value = (int64_t)ssf_ston(&_Src,19,&conv_count); //Run conversion | ||
197 | } | ||
198 | else if (*_Format == SSF_SPEC_UHINT) //If the decimal specifier type is found | ||
199 | { | ||
200 | uint64_t *value=va_arg(va,uint64_t *); //User given destination address | ||
201 | //*value = (uint64_t int)ssf_hton(&_Src,12,&conv_count); //Run conversion | ||
202 | *value = (uint64_t)ssf_hton(&_Src,16,&conv_count); //Run conversion | ||
203 | } | ||
204 | } | ||
205 | else if (*_Format == SSF_SPEC_SHORTINT) //If the short int specifier type is found | ||
206 | { | ||
207 | _Format++; //Skip over the specifier type | ||
208 | if (*_Format == SSF_SPEC_SHORTINT) //If the short int specifier type is found | ||
209 | { | ||
210 | _Format++; //Skip over the specifier type | ||
211 | if (*_Format == SSF_SPEC_DECIMAL) //If the decimal specifier type is found | ||
212 | { | ||
213 | unsigned char *value=va_arg(va,unsigned char*); //User given destination address | ||
214 | //*value = (unsigned char)ssf_ston(&_Src,3,&conv_count); //Run conversion | ||
215 | *value = (unsigned char)ssf_ston(&_Src,5,&conv_count); //Run conversion | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | else if (*_Format == SSF_SPEC_STRING) //If the specifier type is string | ||
220 | { | ||
221 | char *value=va_arg(va,char*); //User given destination address, max chars read pointer | ||
222 | while (*_Src == SSF_SKIP_SPACE) _Src++; //Forward through the whitespace to next non whitespace | ||
223 | while (*_Src != SSF_SKIP_SPACE && *_Src) *value++ = *_Src++; //While any character but space and not end of string and not end location, copy char to dest | ||
224 | *value = 0; //Cap off the string pointer with zero | ||
225 | conv_count++; //Increment the converted count | ||
226 | } | ||
227 | else if (*_Format == SSF_SPEC_VERSION) //If the specifier type is string | ||
228 | { | ||
229 | char *value=va_arg(va,char*); //User given destination address, max chars read pointer | ||
230 | while (*_Src == SSF_SKIP_SPACE) _Src++; //Forward through the whitespace to next non whitespace | ||
231 | while (*_Src != SSF_DELIM_COMMA && *_Src) *value++ = *_Src++; //While any character but space and not end of string and not end location, copy char to dest | ||
232 | *value = 0; //Cap off the string pointer with zero | ||
233 | conv_count++; //Increment the converted count | ||
234 | } | ||
235 | else if (*_Format >= ASCII_NUM_START && *_Format <= ASCII_NUM_END) | ||
236 | { | ||
237 | uint32_t len = (uint32_t)ssf_ston(&_Format,3,NULL); //Convert the given length | ||
238 | if (*_Format == SSF_SPEC_STRING) //If the specifier type is string | ||
239 | { | ||
240 | char *value=va_arg(va,char*),*e; //User given destination address, max chars read pointer | ||
241 | while (*_Src == SSF_SKIP_SPACE) _Src++; //Forward through the whitespace to next non whitespace | ||
242 | e = (char*)_Src+len; //Set a maximum length pointer location | ||
243 | while (*_Src != SSF_SKIP_SPACE && *_Src && _Src != e) *value++ = *_Src++; //While any character but space and not end of string and not end location, copy char to dest | ||
244 | *value = 0; //Cap off the string pointer with zero | ||
245 | conv_count++; //Increment the converted count | ||
246 | } | ||
247 | else if (*_Format == SSF_SPEC_VERSION) //If the specifier type is string | ||
248 | { | ||
249 | char *value=va_arg(va,char*),*e; //User given destination address, max chars read pointer | ||
250 | while (*_Src == SSF_SKIP_SPACE) _Src++; //Forward through the whitespace to next non whitespace | ||
251 | e = (char*)_Src+len; //Set a maximum length pointer location | ||
252 | while (*_Src != SSF_DELIM_COMMA && *_Src && _Src != e) *value++ = *_Src++; //While any character but space and not end of string and not end location, copy char to dest | ||
253 | *value = 0; //Cap off the string pointer with zero | ||
254 | conv_count++; //Increment the converted count | ||
255 | } | ||
256 | } | ||
257 | else if (*_Format == SSF_SPEC_START) looking_for = *_Format; //If another start specifier character is found, output a specifier character | ||
258 | else break; //Scan is now invalid (Uknown type specified) | ||
259 | } | ||
260 | else if (*_Format == SSF_SKIP_SPACE) { } //If a space is found, ignore it | ||
261 | else looking_for = *_Format; //If any other character is found, it is static and should be found in src as well | ||
262 | _Format++; //Skip over current format character | ||
263 | } | ||
264 | |||
265 | va_end(va); //End the variable argument list | ||
266 | return conv_count; //Return the number of conversions made | ||
267 | } | ||
268 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/spfssf.h b/tmk_core/protocol/arm_atsam/usb/spfssf.h new file mode 100644 index 000000000..337a904df --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/spfssf.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #ifndef ____spfssf_h | ||
2 | #define ____spfssf_h | ||
3 | |||
4 | #include <stdarg.h> | ||
5 | |||
6 | #define sprintf spf | ||
7 | #define sscanf ssf | ||
8 | |||
9 | #define SIZEOF_OFFSET 1 | ||
10 | |||
11 | #ifndef NULL | ||
12 | #define NULL 0 | ||
13 | #endif | ||
14 | |||
15 | #define SPF_NONE 0 | ||
16 | |||
17 | #define SPF_SPEC_START 37 //% | ||
18 | #define SPF_SPEC_DECIMAL 100 //d 16bit dec signed (-32767 to 32767) DONE same as i | ||
19 | #define SPF_SPEC_INT 105 //i 16bit dec signed (-32767 to 32767) DONE same as d | ||
20 | #define SPF_SPEC_UINT 117 //u 16bit dec unsigned (0 to 65535) DONE | ||
21 | #define SPF_SPEC_STRING 115 //s variable length (abcd...) DONE | ||
22 | #define SPF_SPEC_UHINT 120 //x 16bit hex lwrc (7fa) DONE | ||
23 | #define SPF_SPEC_UHINT_UP 88 //x 16bit hex lwrc (7fa) DONE | ||
24 | #define SPF_SPEC_LONG 108 //l start of either ld or lu DONE | ||
25 | #define SPF_SPEC_DECIMAL 100 //ld 32bit dec signed (-2147483647 to 2147483647) DONE | ||
26 | #define SPF_SPEC_UNSIGNED 117 //lu 32bit dec unsigned (0 to 4294967295) DONE | ||
27 | #define SPF_SPEC_UHINT 120 //lx 32bit hex unsigned (0 to ffffffff) DONE | ||
28 | |||
29 | #define SSF_SPEC_START 37 //% | ||
30 | #define SSF_SPEC_SHORTINT 104 //h 8bit dec signed (-127 to 127) DONE | ||
31 | #define SSF_LEN_SHORTINT 3 //hhd | ||
32 | #define SSF_SPEC_DECIMAL 100 //d 16bit dec signed (-32767 to 32767) DONE | ||
33 | #define SSF_LEN_DECIMAL 5 //32767 | ||
34 | #define SSF_SPEC_INT 105 //i 16bit dec signed (-32767 to 32767) DONE | ||
35 | #define SSF_LEN_INT 5 //32767 | ||
36 | #define SSF_SPEC_LONG 108 //l start of either ld or lu DONE | ||
37 | #define SSF_SPEC_DECIMAL 100 //ld 32bit dec signed (-2147483647 to 2147483647) DONE | ||
38 | #define SSF_SPEC_UHINT 120 //lx 32bit hex unsigned DONE | ||
39 | #define SSF_LEN_LDECIMAL 10 //2147483647 | ||
40 | #define SSF_SPEC_STRING 115 //s variable length (abcd...) DONE | ||
41 | #define SSF_SKIP_SPACE 32 //space | ||
42 | |||
43 | #define SSF_SPEC_VERSION 118 //v collect to comma delimiter - special | ||
44 | #define SSF_DELIM_COMMA 44 //, | ||
45 | |||
46 | #define ASCII_NUM_START 48 //0 | ||
47 | #define ASCII_NUM_END 58 //9 | ||
48 | |||
49 | #define T_UINT32_0_LIMIT 14 | ||
50 | #define T_UINT32_1_LIMIT 27 | ||
51 | |||
52 | int vspf(char *_Dest, const char *_Format, va_list va); | ||
53 | int spf(char *_Dest, const char *_Format, ...); | ||
54 | int ssf(const char *_Src, const char *_Format, ...); | ||
55 | |||
56 | #endif //____spfssf_h | ||
57 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/status_codes.h b/tmk_core/protocol/arm_atsam/usb/status_codes.h new file mode 100644 index 000000000..f56d2faed --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/status_codes.h | |||
@@ -0,0 +1,158 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Status code definitions. | ||
5 | * | ||
6 | * This file defines various status codes returned by functions, | ||
7 | * indicating success or failure as well as what kind of failure. | ||
8 | * | ||
9 | * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved. | ||
10 | * | ||
11 | * \asf_license_start | ||
12 | * | ||
13 | * \page License | ||
14 | * | ||
15 | * Redistribution and use in source and binary forms, with or without | ||
16 | * modification, are permitted provided that the following conditions are met: | ||
17 | * | ||
18 | * 1. Redistributions of source code must retain the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer. | ||
20 | * | ||
21 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
22 | * this list of conditions and the following disclaimer in the documentation | ||
23 | * and/or other materials provided with the distribution. | ||
24 | * | ||
25 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
26 | * from this software without specific prior written permission. | ||
27 | * | ||
28 | * 4. This software may only be redistributed and used in connection with an | ||
29 | * Atmel microcontroller product. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
32 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
33 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
34 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
35 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
40 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | * | ||
43 | * \asf_license_stop | ||
44 | * | ||
45 | */ | ||
46 | /* | ||
47 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
48 | */ | ||
49 | |||
50 | #ifndef STATUS_CODES_H_INCLUDED | ||
51 | #define STATUS_CODES_H_INCLUDED | ||
52 | |||
53 | #include <stdint.h> | ||
54 | |||
55 | /** | ||
56 | * \defgroup group_sam0_utils_status_codes Status Codes | ||
57 | * | ||
58 | * \ingroup group_sam0_utils | ||
59 | * | ||
60 | * @{ | ||
61 | */ | ||
62 | |||
63 | /** Mask to retrieve the error category of a status code. */ | ||
64 | #define STATUS_CATEGORY_MASK 0xF0 | ||
65 | |||
66 | /** Mask to retrieve the error code within the category of a status code. */ | ||
67 | #define STATUS_ERROR_MASK 0x0F | ||
68 | |||
69 | /** Status code error categories. */ | ||
70 | enum status_categories { | ||
71 | STATUS_CATEGORY_OK = 0x00, | ||
72 | STATUS_CATEGORY_COMMON = 0x10, | ||
73 | STATUS_CATEGORY_ANALOG = 0x30, | ||
74 | STATUS_CATEGORY_COM = 0x40, | ||
75 | STATUS_CATEGORY_IO = 0x50, | ||
76 | }; | ||
77 | |||
78 | /** | ||
79 | * Status code that may be returned by shell commands and protocol | ||
80 | * implementations. | ||
81 | * | ||
82 | * \note Any change to these status codes and the corresponding | ||
83 | * message strings is strictly forbidden. New codes can be added, | ||
84 | * however, but make sure that any message string tables are updated | ||
85 | * at the same time. | ||
86 | */ | ||
87 | enum status_code { | ||
88 | STATUS_OK = STATUS_CATEGORY_OK | 0x00, | ||
89 | STATUS_VALID_DATA = STATUS_CATEGORY_OK | 0x01, | ||
90 | STATUS_NO_CHANGE = STATUS_CATEGORY_OK | 0x02, | ||
91 | STATUS_ABORTED = STATUS_CATEGORY_OK | 0x04, | ||
92 | STATUS_BUSY = STATUS_CATEGORY_OK | 0x05, | ||
93 | STATUS_SUSPEND = STATUS_CATEGORY_OK | 0x06, | ||
94 | |||
95 | STATUS_ERR_IO = STATUS_CATEGORY_COMMON | 0x00, | ||
96 | STATUS_ERR_REQ_FLUSHED = STATUS_CATEGORY_COMMON | 0x01, | ||
97 | STATUS_ERR_TIMEOUT = STATUS_CATEGORY_COMMON | 0x02, | ||
98 | STATUS_ERR_BAD_DATA = STATUS_CATEGORY_COMMON | 0x03, | ||
99 | STATUS_ERR_NOT_FOUND = STATUS_CATEGORY_COMMON | 0x04, | ||
100 | STATUS_ERR_UNSUPPORTED_DEV = STATUS_CATEGORY_COMMON | 0x05, | ||
101 | STATUS_ERR_NO_MEMORY = STATUS_CATEGORY_COMMON | 0x06, | ||
102 | STATUS_ERR_INVALID_ARG = STATUS_CATEGORY_COMMON | 0x07, | ||
103 | STATUS_ERR_BAD_ADDRESS = STATUS_CATEGORY_COMMON | 0x08, | ||
104 | STATUS_ERR_BAD_FORMAT = STATUS_CATEGORY_COMMON | 0x0A, | ||
105 | STATUS_ERR_BAD_FRQ = STATUS_CATEGORY_COMMON | 0x0B, | ||
106 | STATUS_ERR_DENIED = STATUS_CATEGORY_COMMON | 0x0c, | ||
107 | STATUS_ERR_ALREADY_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0d, | ||
108 | STATUS_ERR_OVERFLOW = STATUS_CATEGORY_COMMON | 0x0e, | ||
109 | STATUS_ERR_NOT_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0f, | ||
110 | |||
111 | STATUS_ERR_SAMPLERATE_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x00, | ||
112 | STATUS_ERR_RESOLUTION_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x01, | ||
113 | |||
114 | STATUS_ERR_BAUDRATE_UNAVAILABLE = STATUS_CATEGORY_COM | 0x00, | ||
115 | STATUS_ERR_PACKET_COLLISION = STATUS_CATEGORY_COM | 0x01, | ||
116 | STATUS_ERR_PROTOCOL = STATUS_CATEGORY_COM | 0x02, | ||
117 | |||
118 | STATUS_ERR_PIN_MUX_INVALID = STATUS_CATEGORY_IO | 0x00, | ||
119 | }; | ||
120 | typedef enum status_code status_code_genare_t; | ||
121 | |||
122 | /** | ||
123 | Status codes used by MAC stack. | ||
124 | */ | ||
125 | enum status_code_wireless { | ||
126 | //STATUS_OK = 0, //!< Success | ||
127 | ERR_IO_ERROR = -1, //!< I/O error | ||
128 | ERR_FLUSHED = -2, //!< Request flushed from queue | ||
129 | ERR_TIMEOUT = -3, //!< Operation timed out | ||
130 | ERR_BAD_DATA = -4, //!< Data integrity check failed | ||
131 | ERR_PROTOCOL = -5, //!< Protocol error | ||
132 | ERR_UNSUPPORTED_DEV = -6, //!< Unsupported device | ||
133 | ERR_NO_MEMORY = -7, //!< Insufficient memory | ||
134 | ERR_INVALID_ARG = -8, //!< Invalid argument | ||
135 | ERR_BAD_ADDRESS = -9, //!< Bad address | ||
136 | ERR_BUSY = -10, //!< Resource is busy | ||
137 | ERR_BAD_FORMAT = -11, //!< Data format not recognized | ||
138 | ERR_NO_TIMER = -12, //!< No timer available | ||
139 | ERR_TIMER_ALREADY_RUNNING = -13, //!< Timer already running | ||
140 | ERR_TIMER_NOT_RUNNING = -14, //!< Timer not running | ||
141 | |||
142 | /** | ||
143 | * \brief Operation in progress | ||
144 | * | ||
145 | * This status code is for driver-internal use when an operation | ||
146 | * is currently being performed. | ||
147 | * | ||
148 | * \note Drivers should never return this status code to any | ||
149 | * callers. It is strictly for internal use. | ||
150 | */ | ||
151 | OPERATION_IN_PROGRESS = -128, | ||
152 | }; | ||
153 | |||
154 | typedef enum status_code_wireless status_code_t; | ||
155 | |||
156 | /** @} */ | ||
157 | |||
158 | #endif /* STATUS_CODES_H_INCLUDED */ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udc.c b/tmk_core/protocol/arm_atsam/usb/udc.c new file mode 100644 index 000000000..12444d305 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udc.c | |||
@@ -0,0 +1,1164 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device Controller (UDC) | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #include "conf_usb.h" | ||
48 | #include "usb_protocol.h" | ||
49 | #include "udd.h" | ||
50 | #include "udc_desc.h" | ||
51 | #include "udi_device_conf.h" | ||
52 | #include "udi.h" | ||
53 | #include "udc.h" | ||
54 | #include "md_bootloader.h" | ||
55 | |||
56 | /** | ||
57 | * \ingroup udc_group | ||
58 | * \defgroup udc_group_interne Implementation of UDC | ||
59 | * | ||
60 | * Internal implementation | ||
61 | * @{ | ||
62 | */ | ||
63 | |||
64 | //! \name Internal variables to manage the USB device | ||
65 | //! @{ | ||
66 | |||
67 | //! Device status state (see enum usb_device_status in usb_protocol.h) | ||
68 | static le16_t udc_device_status; | ||
69 | |||
70 | COMPILER_WORD_ALIGNED | ||
71 | //! Device interface setting value | ||
72 | static uint8_t udc_iface_setting = 0; | ||
73 | |||
74 | //! Device Configuration number selected by the USB host | ||
75 | COMPILER_WORD_ALIGNED | ||
76 | static uint8_t udc_num_configuration = 0; | ||
77 | |||
78 | //! Pointer on the selected speed device configuration | ||
79 | static udc_config_speed_t UDC_DESC_STORAGE *udc_ptr_conf; | ||
80 | |||
81 | //! Pointer on interface descriptor used by SETUP request. | ||
82 | static usb_iface_desc_t UDC_DESC_STORAGE *udc_ptr_iface; | ||
83 | |||
84 | //! @} | ||
85 | |||
86 | |||
87 | //! \name Internal structure to store the USB device main strings | ||
88 | //! @{ | ||
89 | |||
90 | /** | ||
91 | * \brief Language ID of USB device (US ID by default) | ||
92 | */ | ||
93 | COMPILER_WORD_ALIGNED | ||
94 | static UDC_DESC_STORAGE usb_str_lgid_desc_t udc_string_desc_languageid = { | ||
95 | .desc.bLength = sizeof(usb_str_lgid_desc_t), | ||
96 | .desc.bDescriptorType = USB_DT_STRING, | ||
97 | .string = {LE16(USB_LANGID_EN_US)} | ||
98 | }; | ||
99 | |||
100 | /** | ||
101 | * \brief USB device manufacture name storage | ||
102 | * String is allocated only if USB_DEVICE_MANUFACTURE_NAME is declared | ||
103 | * by usb application configuration | ||
104 | */ | ||
105 | #ifdef USB_DEVICE_MANUFACTURE_NAME | ||
106 | static uint8_t udc_string_manufacturer_name[] = USB_DEVICE_MANUFACTURE_NAME; | ||
107 | #define USB_DEVICE_MANUFACTURE_NAME_SIZE (sizeof(udc_string_manufacturer_name)-1) | ||
108 | #else | ||
109 | #define USB_DEVICE_MANUFACTURE_NAME_SIZE 0 | ||
110 | #endif | ||
111 | |||
112 | /** | ||
113 | * \brief USB device product name storage | ||
114 | * String is allocated only if USB_DEVICE_PRODUCT_NAME is declared | ||
115 | * by usb application configuration | ||
116 | */ | ||
117 | #ifdef USB_DEVICE_PRODUCT_NAME | ||
118 | static uint8_t udc_string_product_name[] = USB_DEVICE_PRODUCT_NAME; | ||
119 | #define USB_DEVICE_PRODUCT_NAME_SIZE (sizeof(udc_string_product_name)-1) | ||
120 | #else | ||
121 | #define USB_DEVICE_PRODUCT_NAME_SIZE 0 | ||
122 | #endif | ||
123 | |||
124 | #if defined USB_DEVICE_SERIAL_NAME | ||
125 | #define USB_DEVICE_SERIAL_NAME_SIZE (sizeof(USB_DEVICE_SERIAL_NAME)-1) | ||
126 | #else | ||
127 | #define USB_DEVICE_SERIAL_NAME_SIZE 0 | ||
128 | #endif | ||
129 | |||
130 | uint8_t usb_device_serial_name_size = 0; | ||
131 | #if defined USB_DEVICE_SERIAL_USE_BOOTLOADER_SERIAL | ||
132 | uint8_t bootloader_serial_number[BOOTLOADER_SERIAL_MAX_SIZE+1]=""; | ||
133 | #endif | ||
134 | static const uint8_t *udc_get_string_serial_name(void) | ||
135 | { | ||
136 | #if defined USB_DEVICE_SERIAL_USE_BOOTLOADER_SERIAL | ||
137 | uint32_t serial_ptrloc = (uint32_t)&_srom - 4; | ||
138 | uint32_t serial_address = *(uint32_t *)serial_ptrloc; //Address of bootloader's serial number if available | ||
139 | |||
140 | if (serial_address != 0xFFFFFFFF && serial_address < serial_ptrloc) //Check for factory programmed serial address | ||
141 | { | ||
142 | if ((serial_address & 0xFF) % 4 == 0) //Check alignment | ||
143 | { | ||
144 | uint16_t *serial_use = (uint16_t *)(serial_address); //Point to address of string in rom | ||
145 | uint8_t serial_length = 0; | ||
146 | |||
147 | while ((*(serial_use + serial_length) > 32 && *(serial_use + serial_length) < 127) && | ||
148 | serial_length < BOOTLOADER_SERIAL_MAX_SIZE) | ||
149 | { | ||
150 | bootloader_serial_number[serial_length] = *(serial_use + serial_length) & 0xFF; | ||
151 | serial_length++; | ||
152 | } | ||
153 | bootloader_serial_number[serial_length] = 0; | ||
154 | |||
155 | usb_device_serial_name_size = serial_length; | ||
156 | |||
157 | return bootloader_serial_number; //Use serial programmed into bootloader rom | ||
158 | } | ||
159 | } | ||
160 | #endif | ||
161 | |||
162 | usb_device_serial_name_size = USB_DEVICE_SERIAL_NAME_SIZE; | ||
163 | |||
164 | #if defined USB_DEVICE_SERIAL_NAME | ||
165 | return (const uint8_t *)USB_DEVICE_SERIAL_NAME; //Use serial supplied by keyboard's config.h | ||
166 | #else | ||
167 | return 0; //No serial supplied | ||
168 | #endif | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * \brief USB device string descriptor | ||
173 | * Structure used to transfer ASCII strings to USB String descriptor structure. | ||
174 | */ | ||
175 | #ifndef BOOTLOADER_SERIAL_MAX_SIZE | ||
176 | #define BOOTLOADER_SERIAL_MAX_SIZE 0 | ||
177 | #endif //BOOTLOADER_SERIAL_MAX_SIZE | ||
178 | struct udc_string_desc_t { | ||
179 | usb_str_desc_t header; | ||
180 | le16_t string[Max(Max(Max(USB_DEVICE_MANUFACTURE_NAME_SIZE, \ | ||
181 | USB_DEVICE_PRODUCT_NAME_SIZE), USB_DEVICE_SERIAL_NAME_SIZE), \ | ||
182 | BOOTLOADER_SERIAL_MAX_SIZE)]; | ||
183 | }; | ||
184 | COMPILER_WORD_ALIGNED | ||
185 | static UDC_DESC_STORAGE struct udc_string_desc_t udc_string_desc = { | ||
186 | .header.bDescriptorType = USB_DT_STRING | ||
187 | }; | ||
188 | //! @} | ||
189 | |||
190 | usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void) | ||
191 | { | ||
192 | return udc_ptr_iface; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * \brief Returns a value to check the end of USB Configuration descriptor | ||
197 | * | ||
198 | * \return address after the last byte of USB Configuration descriptor | ||
199 | */ | ||
200 | static usb_conf_desc_t UDC_DESC_STORAGE *udc_get_eof_conf(void) | ||
201 | { | ||
202 | return (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) | ||
203 | udc_ptr_conf->desc + | ||
204 | le16_to_cpu(udc_ptr_conf->desc->wTotalLength)); | ||
205 | } | ||
206 | |||
207 | #if (0!=USB_DEVICE_MAX_EP) | ||
208 | /** | ||
209 | * \brief Search specific descriptor in global interface descriptor | ||
210 | * | ||
211 | * \param desc Address of interface descriptor | ||
212 | * or previous specific descriptor found | ||
213 | * \param desc_id Descriptor ID to search | ||
214 | * | ||
215 | * \return address of specific descriptor found | ||
216 | * \return NULL if it is the end of global interface descriptor | ||
217 | */ | ||
218 | static usb_conf_desc_t UDC_DESC_STORAGE *udc_next_desc_in_iface(usb_conf_desc_t | ||
219 | UDC_DESC_STORAGE * desc, uint8_t desc_id) | ||
220 | { | ||
221 | usb_conf_desc_t UDC_DESC_STORAGE *ptr_eof_desc; | ||
222 | |||
223 | ptr_eof_desc = udc_get_eof_conf(); | ||
224 | // Go to next descriptor | ||
225 | desc = (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) desc + | ||
226 | desc->bLength); | ||
227 | // Check the end of configuration descriptor | ||
228 | while (ptr_eof_desc > desc) { | ||
229 | // If new interface descriptor is found, | ||
230 | // then it is the end of the current global interface descriptor | ||
231 | if (USB_DT_INTERFACE == desc->bDescriptorType) { | ||
232 | break; // End of global interface descriptor | ||
233 | } | ||
234 | if (desc_id == desc->bDescriptorType) { | ||
235 | return desc; // Specific descriptor found | ||
236 | } | ||
237 | // Go to next descriptor | ||
238 | desc = (UDC_DESC_STORAGE usb_conf_desc_t *) ((uint8_t *) desc + | ||
239 | desc->bLength); | ||
240 | } | ||
241 | return NULL; // No specific descriptor found | ||
242 | } | ||
243 | #endif | ||
244 | |||
245 | /** | ||
246 | * \brief Search an interface descriptor | ||
247 | * This routine updates the internal pointer udc_ptr_iface. | ||
248 | * | ||
249 | * \param iface_num Interface number to find in Configuration Descriptor | ||
250 | * \param setting_num Setting number of interface to find | ||
251 | * | ||
252 | * \return 1 if found or 0 if not found | ||
253 | */ | ||
254 | static bool udc_update_iface_desc(uint8_t iface_num, uint8_t setting_num) | ||
255 | { | ||
256 | usb_conf_desc_t UDC_DESC_STORAGE *ptr_end_desc; | ||
257 | |||
258 | if (0 == udc_num_configuration) { | ||
259 | return false; | ||
260 | } | ||
261 | |||
262 | if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) { | ||
263 | return false; | ||
264 | } | ||
265 | |||
266 | // Start at the beginning of configuration descriptor | ||
267 | udc_ptr_iface = (UDC_DESC_STORAGE usb_iface_desc_t *) | ||
268 | udc_ptr_conf->desc; | ||
269 | |||
270 | // Check the end of configuration descriptor | ||
271 | ptr_end_desc = udc_get_eof_conf(); | ||
272 | while (ptr_end_desc > | ||
273 | (UDC_DESC_STORAGE usb_conf_desc_t *) udc_ptr_iface) { | ||
274 | if (USB_DT_INTERFACE == udc_ptr_iface->bDescriptorType) { | ||
275 | // A interface descriptor is found | ||
276 | // Check interface and alternate setting number | ||
277 | if ((iface_num == udc_ptr_iface->bInterfaceNumber) && | ||
278 | (setting_num == | ||
279 | udc_ptr_iface->bAlternateSetting)) { | ||
280 | return true; // Interface found | ||
281 | } | ||
282 | } | ||
283 | // Go to next descriptor | ||
284 | udc_ptr_iface = (UDC_DESC_STORAGE usb_iface_desc_t *) ( | ||
285 | (uint8_t *) udc_ptr_iface + | ||
286 | udc_ptr_iface->bLength); | ||
287 | } | ||
288 | return false; // Interface not found | ||
289 | } | ||
290 | |||
291 | /** | ||
292 | * \brief Disables an usb device interface (UDI) | ||
293 | * This routine call the UDI corresponding to interface number | ||
294 | * | ||
295 | * \param iface_num Interface number to disable | ||
296 | * | ||
297 | * \return 1 if it is done or 0 if interface is not found | ||
298 | */ | ||
299 | static bool udc_iface_disable(uint8_t iface_num) | ||
300 | { | ||
301 | udi_api_t UDC_DESC_STORAGE *udi_api; | ||
302 | |||
303 | // Select first alternate setting of the interface | ||
304 | // to update udc_ptr_iface before call iface->getsetting() | ||
305 | if (!udc_update_iface_desc(iface_num, 0)) { | ||
306 | return false; | ||
307 | } | ||
308 | |||
309 | // Select the interface with the current alternate setting | ||
310 | udi_api = udc_ptr_conf->udi_apis[iface_num]; | ||
311 | |||
312 | #if (0!=USB_DEVICE_MAX_EP) | ||
313 | if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) { | ||
314 | return false; | ||
315 | } | ||
316 | |||
317 | // Start at the beginning of interface descriptor | ||
318 | { | ||
319 | usb_ep_desc_t UDC_DESC_STORAGE *ep_desc; | ||
320 | ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) udc_ptr_iface; | ||
321 | while (1) { | ||
322 | // Search Endpoint descriptor included in global interface descriptor | ||
323 | ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) | ||
324 | udc_next_desc_in_iface((UDC_DESC_STORAGE | ||
325 | usb_conf_desc_t *) | ||
326 | ep_desc, USB_DT_ENDPOINT); | ||
327 | if (NULL == ep_desc) { | ||
328 | break; | ||
329 | } | ||
330 | // Free the endpoint used by the interface | ||
331 | udd_ep_free(ep_desc->bEndpointAddress); | ||
332 | } | ||
333 | } | ||
334 | #endif | ||
335 | |||
336 | // Disable interface | ||
337 | udi_api->disable(); | ||
338 | return true; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * \brief Enables an usb device interface (UDI) | ||
343 | * This routine calls the UDI corresponding | ||
344 | * to the interface and setting number. | ||
345 | * | ||
346 | * \param iface_num Interface number to enable | ||
347 | * \param setting_num Setting number to enable | ||
348 | * | ||
349 | * \return 1 if it is done or 0 if interface is not found | ||
350 | */ | ||
351 | static bool udc_iface_enable(uint8_t iface_num, uint8_t setting_num) | ||
352 | { | ||
353 | // Select the interface descriptor | ||
354 | if (!udc_update_iface_desc(iface_num, setting_num)) { | ||
355 | return false; | ||
356 | } | ||
357 | |||
358 | #if (0!=USB_DEVICE_MAX_EP) | ||
359 | usb_ep_desc_t UDC_DESC_STORAGE *ep_desc; | ||
360 | |||
361 | // Start at the beginning of the global interface descriptor | ||
362 | ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) udc_ptr_iface; | ||
363 | while (1) { | ||
364 | // Search Endpoint descriptor included in the global interface descriptor | ||
365 | ep_desc = (UDC_DESC_STORAGE usb_ep_desc_t *) | ||
366 | udc_next_desc_in_iface((UDC_DESC_STORAGE | ||
367 | usb_conf_desc_t *) ep_desc, | ||
368 | USB_DT_ENDPOINT); | ||
369 | if (NULL == ep_desc) | ||
370 | break; | ||
371 | // Alloc the endpoint used by the interface | ||
372 | if (!udd_ep_alloc(ep_desc->bEndpointAddress, | ||
373 | ep_desc->bmAttributes, | ||
374 | le16_to_cpu | ||
375 | (ep_desc->wMaxPacketSize))) { | ||
376 | return false; | ||
377 | } | ||
378 | } | ||
379 | #endif | ||
380 | // Enable the interface | ||
381 | return udc_ptr_conf->udi_apis[iface_num]->enable(); | ||
382 | } | ||
383 | |||
384 | /*! \brief Start the USB Device stack | ||
385 | */ | ||
386 | void udc_start(void) | ||
387 | { | ||
388 | udd_enable(); | ||
389 | } | ||
390 | |||
391 | /*! \brief Stop the USB Device stack | ||
392 | */ | ||
393 | void udc_stop(void) | ||
394 | { | ||
395 | udd_disable(); | ||
396 | udc_reset(); | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * \brief Reset the current configuration of the USB device, | ||
401 | * This routines can be called by UDD when a RESET on the USB line occurs. | ||
402 | */ | ||
403 | void udc_reset(void) | ||
404 | { | ||
405 | uint8_t iface_num; | ||
406 | |||
407 | if (udc_num_configuration) { | ||
408 | for (iface_num = 0; | ||
409 | iface_num < udc_ptr_conf->desc->bNumInterfaces; | ||
410 | iface_num++) { | ||
411 | udc_iface_disable(iface_num); | ||
412 | } | ||
413 | } | ||
414 | udc_num_configuration = 0; | ||
415 | #if (USB_CONFIG_ATTR_REMOTE_WAKEUP \ | ||
416 | == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP)) | ||
417 | if (CPU_TO_LE16(USB_DEV_STATUS_REMOTEWAKEUP) & udc_device_status) { | ||
418 | // Remote wakeup is enabled then disable it | ||
419 | UDC_REMOTEWAKEUP_DISABLE(); | ||
420 | } | ||
421 | #endif | ||
422 | udc_device_status = | ||
423 | #if (USB_DEVICE_ATTR & USB_CONFIG_ATTR_SELF_POWERED) | ||
424 | CPU_TO_LE16(USB_DEV_STATUS_SELF_POWERED); | ||
425 | #else | ||
426 | CPU_TO_LE16(USB_DEV_STATUS_BUS_POWERED); | ||
427 | #endif | ||
428 | } | ||
429 | |||
430 | void udc_sof_notify(void) | ||
431 | { | ||
432 | uint8_t iface_num; | ||
433 | |||
434 | if (udc_num_configuration) { | ||
435 | for (iface_num = 0; | ||
436 | iface_num < udc_ptr_conf->desc->bNumInterfaces; | ||
437 | iface_num++) { | ||
438 | if (udc_ptr_conf->udi_apis[iface_num]->sof_notify != NULL) { | ||
439 | udc_ptr_conf->udi_apis[iface_num]->sof_notify(); | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * \brief Standard device request to get device status | ||
447 | * | ||
448 | * \return true if success | ||
449 | */ | ||
450 | static bool udc_req_std_dev_get_status(void) | ||
451 | { | ||
452 | if (udd_g_ctrlreq.req.wLength != sizeof(udc_device_status)) { | ||
453 | return false; | ||
454 | } | ||
455 | |||
456 | udd_set_setup_payload( (uint8_t *) & udc_device_status, | ||
457 | sizeof(udc_device_status)); | ||
458 | return true; | ||
459 | } | ||
460 | |||
461 | #if (0!=USB_DEVICE_MAX_EP) | ||
462 | /** | ||
463 | * \brief Standard endpoint request to get endpoint status | ||
464 | * | ||
465 | * \return true if success | ||
466 | */ | ||
467 | static bool udc_req_std_ep_get_status(void) | ||
468 | { | ||
469 | static le16_t udc_ep_status; | ||
470 | |||
471 | if (udd_g_ctrlreq.req.wLength != sizeof(udc_ep_status)) { | ||
472 | return false; | ||
473 | } | ||
474 | |||
475 | udc_ep_status = udd_ep_is_halted(udd_g_ctrlreq.req. | ||
476 | wIndex & 0xFF) ? CPU_TO_LE16(USB_EP_STATUS_HALTED) : 0; | ||
477 | |||
478 | udd_set_setup_payload( (uint8_t *) & udc_ep_status, | ||
479 | sizeof(udc_ep_status)); | ||
480 | return true; | ||
481 | } | ||
482 | #endif | ||
483 | |||
484 | /** | ||
485 | * \brief Standard device request to change device status | ||
486 | * | ||
487 | * \return true if success | ||
488 | */ | ||
489 | static bool udc_req_std_dev_clear_feature(void) | ||
490 | { | ||
491 | if (udd_g_ctrlreq.req.wLength) { | ||
492 | return false; | ||
493 | } | ||
494 | |||
495 | if (udd_g_ctrlreq.req.wValue == USB_DEV_FEATURE_REMOTE_WAKEUP) { | ||
496 | udc_device_status &= CPU_TO_LE16(~(uint32_t)USB_DEV_STATUS_REMOTEWAKEUP); | ||
497 | #if (USB_CONFIG_ATTR_REMOTE_WAKEUP \ | ||
498 | == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP)) | ||
499 | UDC_REMOTEWAKEUP_DISABLE(); | ||
500 | #endif | ||
501 | return true; | ||
502 | } | ||
503 | return false; | ||
504 | } | ||
505 | |||
506 | #if (0!=USB_DEVICE_MAX_EP) | ||
507 | /** | ||
508 | * \brief Standard endpoint request to clear endpoint feature | ||
509 | * | ||
510 | * \return true if success | ||
511 | */ | ||
512 | static bool udc_req_std_ep_clear_feature(void) | ||
513 | { | ||
514 | if (udd_g_ctrlreq.req.wLength) { | ||
515 | return false; | ||
516 | } | ||
517 | |||
518 | if (udd_g_ctrlreq.req.wValue == USB_EP_FEATURE_HALT) { | ||
519 | return udd_ep_clear_halt(udd_g_ctrlreq.req.wIndex & 0xFF); | ||
520 | } | ||
521 | return false; | ||
522 | } | ||
523 | #endif | ||
524 | |||
525 | /** | ||
526 | * \brief Standard device request to set a feature | ||
527 | * | ||
528 | * \return true if success | ||
529 | */ | ||
530 | static bool udc_req_std_dev_set_feature(void) | ||
531 | { | ||
532 | if (udd_g_ctrlreq.req.wLength) { | ||
533 | return false; | ||
534 | } | ||
535 | |||
536 | switch (udd_g_ctrlreq.req.wValue) { | ||
537 | |||
538 | case USB_DEV_FEATURE_REMOTE_WAKEUP: | ||
539 | #if (USB_CONFIG_ATTR_REMOTE_WAKEUP \ | ||
540 | == (USB_DEVICE_ATTR & USB_CONFIG_ATTR_REMOTE_WAKEUP)) | ||
541 | udc_device_status |= CPU_TO_LE16(USB_DEV_STATUS_REMOTEWAKEUP); | ||
542 | UDC_REMOTEWAKEUP_ENABLE(); | ||
543 | return true; | ||
544 | #else | ||
545 | return false; | ||
546 | #endif | ||
547 | |||
548 | #ifdef USB_DEVICE_HS_SUPPORT | ||
549 | case USB_DEV_FEATURE_TEST_MODE: | ||
550 | if (!udd_is_high_speed()) { | ||
551 | break; | ||
552 | } | ||
553 | if (udd_g_ctrlreq.req.wIndex & 0xff) { | ||
554 | break; | ||
555 | } | ||
556 | // Unconfigure the device, terminating all ongoing requests | ||
557 | udc_reset(); | ||
558 | switch ((udd_g_ctrlreq.req.wIndex >> 8) & 0xFF) { | ||
559 | case USB_DEV_TEST_MODE_J: | ||
560 | udd_g_ctrlreq.callback = udd_test_mode_j; | ||
561 | return true; | ||
562 | |||
563 | case USB_DEV_TEST_MODE_K: | ||
564 | udd_g_ctrlreq.callback = udd_test_mode_k; | ||
565 | return true; | ||
566 | |||
567 | case USB_DEV_TEST_MODE_SE0_NAK: | ||
568 | udd_g_ctrlreq.callback = udd_test_mode_se0_nak; | ||
569 | return true; | ||
570 | |||
571 | case USB_DEV_TEST_MODE_PACKET: | ||
572 | udd_g_ctrlreq.callback = udd_test_mode_packet; | ||
573 | return true; | ||
574 | |||
575 | case USB_DEV_TEST_MODE_FORCE_ENABLE: // Only for downstream facing hub ports | ||
576 | default: | ||
577 | break; | ||
578 | } | ||
579 | break; | ||
580 | #endif | ||
581 | default: | ||
582 | break; | ||
583 | } | ||
584 | return false; | ||
585 | } | ||
586 | |||
587 | /** | ||
588 | * \brief Standard endpoint request to halt an endpoint | ||
589 | * | ||
590 | * \return true if success | ||
591 | */ | ||
592 | #if (0!=USB_DEVICE_MAX_EP) | ||
593 | static bool udc_req_std_ep_set_feature(void) | ||
594 | { | ||
595 | if (udd_g_ctrlreq.req.wLength) { | ||
596 | return false; | ||
597 | } | ||
598 | if (udd_g_ctrlreq.req.wValue == USB_EP_FEATURE_HALT) { | ||
599 | udd_ep_abort(udd_g_ctrlreq.req.wIndex & 0xFF); | ||
600 | return udd_ep_set_halt(udd_g_ctrlreq.req.wIndex & 0xFF); | ||
601 | } | ||
602 | return false; | ||
603 | } | ||
604 | #endif | ||
605 | |||
606 | /** | ||
607 | * \brief Change the address of device | ||
608 | * Callback called at the end of request set address | ||
609 | */ | ||
610 | static void udc_valid_address(void) | ||
611 | { | ||
612 | udd_set_address(udd_g_ctrlreq.req.wValue & 0x7F); | ||
613 | } | ||
614 | |||
615 | /** | ||
616 | * \brief Standard device request to set device address | ||
617 | * | ||
618 | * \return true if success | ||
619 | */ | ||
620 | static bool udc_req_std_dev_set_address(void) | ||
621 | { | ||
622 | if (udd_g_ctrlreq.req.wLength) { | ||
623 | return false; | ||
624 | } | ||
625 | |||
626 | // The address must be changed at the end of setup request after the handshake | ||
627 | // then we use a callback to change address | ||
628 | udd_g_ctrlreq.callback = udc_valid_address; | ||
629 | return true; | ||
630 | } | ||
631 | |||
632 | /** | ||
633 | * \brief Standard device request to get device string descriptor | ||
634 | * | ||
635 | * \return true if success | ||
636 | */ | ||
637 | static bool udc_req_std_dev_get_str_desc(void) | ||
638 | { | ||
639 | uint8_t i; | ||
640 | const uint8_t *str; | ||
641 | uint8_t str_length = 0; | ||
642 | |||
643 | // Link payload pointer to the string corresponding at request | ||
644 | switch (udd_g_ctrlreq.req.wValue & 0xff) { | ||
645 | case 0: | ||
646 | udd_set_setup_payload((uint8_t *) &udc_string_desc_languageid, | ||
647 | sizeof(udc_string_desc_languageid)); | ||
648 | break; | ||
649 | |||
650 | #ifdef USB_DEVICE_MANUFACTURE_NAME | ||
651 | case 1: | ||
652 | str_length = USB_DEVICE_MANUFACTURE_NAME_SIZE; | ||
653 | str = udc_string_manufacturer_name; | ||
654 | break; | ||
655 | #endif | ||
656 | #ifdef USB_DEVICE_PRODUCT_NAME | ||
657 | case 2: | ||
658 | str_length = USB_DEVICE_PRODUCT_NAME_SIZE; | ||
659 | str = udc_string_product_name; | ||
660 | break; | ||
661 | #endif | ||
662 | case 3: | ||
663 | str = udc_get_string_serial_name(); | ||
664 | str_length = usb_device_serial_name_size; | ||
665 | break; | ||
666 | default: | ||
667 | #ifdef UDC_GET_EXTRA_STRING | ||
668 | if (UDC_GET_EXTRA_STRING()) { | ||
669 | break; | ||
670 | } | ||
671 | #endif | ||
672 | return false; | ||
673 | } | ||
674 | |||
675 | if (str_length) { | ||
676 | for(i = 0; i < str_length; i++) { | ||
677 | udc_string_desc.string[i] = cpu_to_le16((le16_t)str[i]); | ||
678 | } | ||
679 | |||
680 | udc_string_desc.header.bLength = 2 + (str_length) * 2; | ||
681 | udd_set_setup_payload( | ||
682 | (uint8_t *) &udc_string_desc, | ||
683 | udc_string_desc.header.bLength); | ||
684 | } | ||
685 | |||
686 | return true; | ||
687 | } | ||
688 | |||
689 | /** | ||
690 | * \brief Standard device request to get descriptors about USB device | ||
691 | * | ||
692 | * \return true if success | ||
693 | */ | ||
694 | static bool udc_req_std_dev_get_descriptor(void) | ||
695 | { | ||
696 | uint8_t conf_num; | ||
697 | |||
698 | conf_num = udd_g_ctrlreq.req.wValue & 0xff; | ||
699 | |||
700 | // Check descriptor ID | ||
701 | switch ((uint8_t) (udd_g_ctrlreq.req.wValue >> 8)) { | ||
702 | case USB_DT_DEVICE: | ||
703 | // Device descriptor requested | ||
704 | #ifdef USB_DEVICE_HS_SUPPORT | ||
705 | if (!udd_is_high_speed()) { | ||
706 | udd_set_setup_payload( | ||
707 | (uint8_t *) udc_config.confdev_hs, | ||
708 | udc_config.confdev_hs->bLength); | ||
709 | } else | ||
710 | #endif | ||
711 | { | ||
712 | udd_set_setup_payload( | ||
713 | (uint8_t *) udc_config.confdev_lsfs, | ||
714 | udc_config.confdev_lsfs->bLength); | ||
715 | } | ||
716 | break; | ||
717 | |||
718 | case USB_DT_CONFIGURATION: | ||
719 | // Configuration descriptor requested | ||
720 | #ifdef USB_DEVICE_HS_SUPPORT | ||
721 | if (udd_is_high_speed()) { | ||
722 | // HS descriptor | ||
723 | if (conf_num >= udc_config.confdev_hs->bNumConfigurations) { | ||
724 | return false; | ||
725 | } | ||
726 | udd_set_setup_payload( | ||
727 | (uint8_t *)udc_config.conf_hs[conf_num].desc, | ||
728 | le16_to_cpu(udc_config.conf_hs[conf_num].desc->wTotalLength)); | ||
729 | } else | ||
730 | #endif | ||
731 | { | ||
732 | // FS descriptor | ||
733 | if (conf_num >= udc_config.confdev_lsfs->bNumConfigurations) { | ||
734 | return false; | ||
735 | } | ||
736 | udd_set_setup_payload( | ||
737 | (uint8_t *)udc_config.conf_lsfs[conf_num].desc, | ||
738 | le16_to_cpu(udc_config.conf_lsfs[conf_num].desc->wTotalLength)); | ||
739 | } | ||
740 | ((usb_conf_desc_t *) udd_g_ctrlreq.payload)->bDescriptorType = | ||
741 | USB_DT_CONFIGURATION; | ||
742 | break; | ||
743 | |||
744 | #ifdef USB_DEVICE_HS_SUPPORT | ||
745 | case USB_DT_DEVICE_QUALIFIER: | ||
746 | // Device qualifier descriptor requested | ||
747 | udd_set_setup_payload( (uint8_t *) udc_config.qualifier, | ||
748 | udc_config.qualifier->bLength); | ||
749 | break; | ||
750 | |||
751 | case USB_DT_OTHER_SPEED_CONFIGURATION: | ||
752 | // Other configuration descriptor requested | ||
753 | if (!udd_is_high_speed()) { | ||
754 | // HS descriptor | ||
755 | if (conf_num >= udc_config.confdev_hs->bNumConfigurations) { | ||
756 | return false; | ||
757 | } | ||
758 | udd_set_setup_payload( | ||
759 | (uint8_t *)udc_config.conf_hs[conf_num].desc, | ||
760 | le16_to_cpu(udc_config.conf_hs[conf_num].desc->wTotalLength)); | ||
761 | } else { | ||
762 | // FS descriptor | ||
763 | if (conf_num >= udc_config.confdev_lsfs->bNumConfigurations) { | ||
764 | return false; | ||
765 | } | ||
766 | udd_set_setup_payload( | ||
767 | (uint8_t *)udc_config.conf_lsfs[conf_num].desc, | ||
768 | le16_to_cpu(udc_config.conf_lsfs[conf_num].desc->wTotalLength)); | ||
769 | } | ||
770 | ((usb_conf_desc_t *) udd_g_ctrlreq.payload)->bDescriptorType = | ||
771 | USB_DT_OTHER_SPEED_CONFIGURATION; | ||
772 | break; | ||
773 | #endif | ||
774 | |||
775 | case USB_DT_BOS: | ||
776 | // Device BOS descriptor requested | ||
777 | if (udc_config.conf_bos == NULL) { | ||
778 | return false; | ||
779 | } | ||
780 | udd_set_setup_payload( (uint8_t *) udc_config.conf_bos, | ||
781 | udc_config.conf_bos->wTotalLength); | ||
782 | break; | ||
783 | |||
784 | case USB_DT_STRING: | ||
785 | // String descriptor requested | ||
786 | if (!udc_req_std_dev_get_str_desc()) { | ||
787 | return false; | ||
788 | } | ||
789 | break; | ||
790 | |||
791 | default: | ||
792 | // Unknown descriptor requested | ||
793 | return false; | ||
794 | } | ||
795 | // if the descriptor is larger than length requested, then reduce it | ||
796 | if (udd_g_ctrlreq.req.wLength < udd_g_ctrlreq.payload_size) { | ||
797 | udd_g_ctrlreq.payload_size = udd_g_ctrlreq.req.wLength; | ||
798 | } | ||
799 | return true; | ||
800 | } | ||
801 | |||
802 | /** | ||
803 | * \brief Standard device request to get configuration number | ||
804 | * | ||
805 | * \return true if success | ||
806 | */ | ||
807 | static bool udc_req_std_dev_get_configuration(void) | ||
808 | { | ||
809 | if (udd_g_ctrlreq.req.wLength != 1) { | ||
810 | return false; | ||
811 | } | ||
812 | |||
813 | udd_set_setup_payload(&udc_num_configuration,1); | ||
814 | return true; | ||
815 | } | ||
816 | |||
817 | /** | ||
818 | * \brief Standard device request to enable a configuration | ||
819 | * | ||
820 | * \return true if success | ||
821 | */ | ||
822 | static bool udc_req_std_dev_set_configuration(void) | ||
823 | { | ||
824 | uint8_t iface_num; | ||
825 | |||
826 | // Check request length | ||
827 | if (udd_g_ctrlreq.req.wLength) { | ||
828 | return false; | ||
829 | } | ||
830 | // Authorize configuration only if the address is valid | ||
831 | if (!udd_getaddress()) { | ||
832 | return false; | ||
833 | } | ||
834 | // Check the configuration number requested | ||
835 | #ifdef USB_DEVICE_HS_SUPPORT | ||
836 | if (udd_is_high_speed()) { | ||
837 | // HS descriptor | ||
838 | if ((udd_g_ctrlreq.req.wValue & 0xFF) > | ||
839 | udc_config.confdev_hs->bNumConfigurations) { | ||
840 | return false; | ||
841 | } | ||
842 | } else | ||
843 | #endif | ||
844 | { | ||
845 | // FS descriptor | ||
846 | if ((udd_g_ctrlreq.req.wValue & 0xFF) > | ||
847 | udc_config.confdev_lsfs->bNumConfigurations) { | ||
848 | return false; | ||
849 | } | ||
850 | } | ||
851 | |||
852 | // Reset current configuration | ||
853 | udc_reset(); | ||
854 | |||
855 | // Enable new configuration | ||
856 | udc_num_configuration = udd_g_ctrlreq.req.wValue & 0xFF; | ||
857 | if (udc_num_configuration == 0) { | ||
858 | return true; // Default empty configuration requested | ||
859 | } | ||
860 | // Update pointer of the configuration descriptor | ||
861 | #ifdef USB_DEVICE_HS_SUPPORT | ||
862 | if (udd_is_high_speed()) { | ||
863 | // HS descriptor | ||
864 | udc_ptr_conf = &udc_config.conf_hs[udc_num_configuration - 1]; | ||
865 | } else | ||
866 | #endif | ||
867 | { | ||
868 | // FS descriptor | ||
869 | udc_ptr_conf = &udc_config.conf_lsfs[udc_num_configuration - 1]; | ||
870 | } | ||
871 | // Enable all interfaces of the selected configuration | ||
872 | for (iface_num = 0; iface_num < udc_ptr_conf->desc->bNumInterfaces; | ||
873 | iface_num++) { | ||
874 | if (!udc_iface_enable(iface_num, 0)) { | ||
875 | return false; | ||
876 | } | ||
877 | } | ||
878 | return true; | ||
879 | } | ||
880 | |||
881 | /** | ||
882 | * \brief Standard interface request | ||
883 | * to get the alternate setting number of an interface | ||
884 | * | ||
885 | * \return true if success | ||
886 | */ | ||
887 | static bool udc_req_std_iface_get_setting(void) | ||
888 | { | ||
889 | uint8_t iface_num; | ||
890 | udi_api_t UDC_DESC_STORAGE *udi_api; | ||
891 | |||
892 | if (udd_g_ctrlreq.req.wLength != 1) { | ||
893 | return false; // Error in request | ||
894 | } | ||
895 | if (!udc_num_configuration) { | ||
896 | return false; // The device is not is configured state yet | ||
897 | } | ||
898 | |||
899 | // Check the interface number included in the request | ||
900 | iface_num = udd_g_ctrlreq.req.wIndex & 0xFF; | ||
901 | if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) { | ||
902 | return false; | ||
903 | } | ||
904 | |||
905 | // Select first alternate setting of the interface to update udc_ptr_iface | ||
906 | // before call iface->getsetting() | ||
907 | if (!udc_update_iface_desc(iface_num, 0)) { | ||
908 | return false; | ||
909 | } | ||
910 | // Get alternate setting from UDI | ||
911 | udi_api = udc_ptr_conf->udi_apis[iface_num]; | ||
912 | udc_iface_setting = udi_api->getsetting(); | ||
913 | |||
914 | // Link value to payload pointer of request | ||
915 | udd_set_setup_payload(&udc_iface_setting,1); | ||
916 | return true; | ||
917 | } | ||
918 | |||
919 | /** | ||
920 | * \brief Standard interface request | ||
921 | * to set an alternate setting of an interface | ||
922 | * | ||
923 | * \return true if success | ||
924 | */ | ||
925 | static bool udc_req_std_iface_set_setting(void) | ||
926 | { | ||
927 | uint8_t iface_num, setting_num; | ||
928 | |||
929 | if (udd_g_ctrlreq.req.wLength) { | ||
930 | return false; // Error in request | ||
931 | } | ||
932 | if (!udc_num_configuration) { | ||
933 | return false; // The device is not is configured state yet | ||
934 | } | ||
935 | |||
936 | iface_num = udd_g_ctrlreq.req.wIndex & 0xFF; | ||
937 | setting_num = udd_g_ctrlreq.req.wValue & 0xFF; | ||
938 | |||
939 | // Disable current setting | ||
940 | if (!udc_iface_disable(iface_num)) { | ||
941 | return false; | ||
942 | } | ||
943 | |||
944 | // Enable new setting | ||
945 | return udc_iface_enable(iface_num, setting_num); | ||
946 | } | ||
947 | |||
948 | /** | ||
949 | * \brief Main routine to manage the standard USB SETUP request | ||
950 | * | ||
951 | * \return true if the request is supported | ||
952 | */ | ||
953 | static bool udc_reqstd(void) | ||
954 | { | ||
955 | if (Udd_setup_is_in()) { | ||
956 | // GET Standard Requests | ||
957 | if (udd_g_ctrlreq.req.wLength == 0) { | ||
958 | return false; // Error for USB host | ||
959 | } | ||
960 | |||
961 | if (USB_REQ_RECIP_DEVICE == Udd_setup_recipient()) { | ||
962 | // Standard Get Device request | ||
963 | switch (udd_g_ctrlreq.req.bRequest) { | ||
964 | case USB_REQ_GET_STATUS: | ||
965 | return udc_req_std_dev_get_status(); | ||
966 | case USB_REQ_GET_DESCRIPTOR: | ||
967 | return udc_req_std_dev_get_descriptor(); | ||
968 | case USB_REQ_GET_CONFIGURATION: | ||
969 | return udc_req_std_dev_get_configuration(); | ||
970 | default: | ||
971 | break; | ||
972 | } | ||
973 | } | ||
974 | |||
975 | if (USB_REQ_RECIP_INTERFACE == Udd_setup_recipient()) { | ||
976 | // Standard Get Interface request | ||
977 | switch (udd_g_ctrlreq.req.bRequest) { | ||
978 | case USB_REQ_GET_INTERFACE: | ||
979 | return udc_req_std_iface_get_setting(); | ||
980 | default: | ||
981 | break; | ||
982 | } | ||
983 | } | ||
984 | #if (0!=USB_DEVICE_MAX_EP) | ||
985 | if (USB_REQ_RECIP_ENDPOINT == Udd_setup_recipient()) { | ||
986 | // Standard Get Endpoint request | ||
987 | switch (udd_g_ctrlreq.req.bRequest) { | ||
988 | case USB_REQ_GET_STATUS: | ||
989 | return udc_req_std_ep_get_status(); | ||
990 | default: | ||
991 | break; | ||
992 | } | ||
993 | } | ||
994 | #endif | ||
995 | } else { | ||
996 | // SET Standard Requests | ||
997 | if (USB_REQ_RECIP_DEVICE == Udd_setup_recipient()) { | ||
998 | // Standard Set Device request | ||
999 | switch (udd_g_ctrlreq.req.bRequest) { | ||
1000 | case USB_REQ_SET_ADDRESS: | ||
1001 | return udc_req_std_dev_set_address(); | ||
1002 | case USB_REQ_CLEAR_FEATURE: | ||
1003 | return udc_req_std_dev_clear_feature(); | ||
1004 | case USB_REQ_SET_FEATURE: | ||
1005 | return udc_req_std_dev_set_feature(); | ||
1006 | case USB_REQ_SET_CONFIGURATION: | ||
1007 | return udc_req_std_dev_set_configuration(); | ||
1008 | case USB_REQ_SET_DESCRIPTOR: | ||
1009 | /* Not supported (defined as optional by the USB 2.0 spec) */ | ||
1010 | break; | ||
1011 | default: | ||
1012 | break; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | if (USB_REQ_RECIP_INTERFACE == Udd_setup_recipient()) { | ||
1017 | // Standard Set Interface request | ||
1018 | switch (udd_g_ctrlreq.req.bRequest) { | ||
1019 | case USB_REQ_SET_INTERFACE: | ||
1020 | return udc_req_std_iface_set_setting(); | ||
1021 | default: | ||
1022 | break; | ||
1023 | } | ||
1024 | } | ||
1025 | #if (0!=USB_DEVICE_MAX_EP) | ||
1026 | if (USB_REQ_RECIP_ENDPOINT == Udd_setup_recipient()) { | ||
1027 | // Standard Set Endpoint request | ||
1028 | switch (udd_g_ctrlreq.req.bRequest) { | ||
1029 | case USB_REQ_CLEAR_FEATURE: | ||
1030 | return udc_req_std_ep_clear_feature(); | ||
1031 | case USB_REQ_SET_FEATURE: | ||
1032 | return udc_req_std_ep_set_feature(); | ||
1033 | default: | ||
1034 | break; | ||
1035 | } | ||
1036 | } | ||
1037 | #endif | ||
1038 | } | ||
1039 | return false; | ||
1040 | } | ||
1041 | |||
1042 | /** | ||
1043 | * \brief Send the SETUP interface request to UDI | ||
1044 | * | ||
1045 | * \return true if the request is supported | ||
1046 | */ | ||
1047 | static bool udc_req_iface(void) | ||
1048 | { | ||
1049 | uint8_t iface_num; | ||
1050 | udi_api_t UDC_DESC_STORAGE *udi_api; | ||
1051 | |||
1052 | if (0 == udc_num_configuration) { | ||
1053 | return false; // The device is not is configured state yet | ||
1054 | } | ||
1055 | // Check interface number | ||
1056 | iface_num = udd_g_ctrlreq.req.wIndex & 0xFF; | ||
1057 | if (iface_num >= udc_ptr_conf->desc->bNumInterfaces) { | ||
1058 | return false; | ||
1059 | } | ||
1060 | |||
1061 | //* To update udc_ptr_iface with the selected interface in request | ||
1062 | // Select first alternate setting of interface to update udc_ptr_iface | ||
1063 | // before calling udi_api->getsetting() | ||
1064 | if (!udc_update_iface_desc(iface_num, 0)) { | ||
1065 | return false; | ||
1066 | } | ||
1067 | // Select the interface with the current alternate setting | ||
1068 | udi_api = udc_ptr_conf->udi_apis[iface_num]; | ||
1069 | if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) { | ||
1070 | return false; | ||
1071 | } | ||
1072 | |||
1073 | // Send the SETUP request to the UDI corresponding to the interface number | ||
1074 | return udi_api->setup(); | ||
1075 | } | ||
1076 | |||
1077 | /** | ||
1078 | * \brief Send the SETUP interface request to UDI | ||
1079 | * | ||
1080 | * \return true if the request is supported | ||
1081 | */ | ||
1082 | static bool udc_req_ep(void) | ||
1083 | { | ||
1084 | uint8_t iface_num; | ||
1085 | udi_api_t UDC_DESC_STORAGE *udi_api; | ||
1086 | |||
1087 | if (0 == udc_num_configuration) { | ||
1088 | return false; // The device is not is configured state yet | ||
1089 | } | ||
1090 | // Send this request on all enabled interfaces | ||
1091 | iface_num = udd_g_ctrlreq.req.wIndex & 0xFF; | ||
1092 | for (iface_num = 0; iface_num < udc_ptr_conf->desc->bNumInterfaces; | ||
1093 | iface_num++) { | ||
1094 | // Select the interface with the current alternate setting | ||
1095 | udi_api = udc_ptr_conf->udi_apis[iface_num]; | ||
1096 | if (!udc_update_iface_desc(iface_num, udi_api->getsetting())) { | ||
1097 | return false; | ||
1098 | } | ||
1099 | |||
1100 | // Send the SETUP request to the UDI | ||
1101 | if (udi_api->setup()) { | ||
1102 | return true; | ||
1103 | } | ||
1104 | } | ||
1105 | return false; | ||
1106 | } | ||
1107 | |||
1108 | /** | ||
1109 | * \brief Main routine to manage the USB SETUP request. | ||
1110 | * | ||
1111 | * This function parses a USB SETUP request and submits an appropriate | ||
1112 | * response back to the host or, in the case of SETUP OUT requests | ||
1113 | * with data, sets up a buffer for receiving the data payload. | ||
1114 | * | ||
1115 | * The main standard requests defined by the USB 2.0 standard are handled | ||
1116 | * internally. The interface requests are sent to UDI, and the specific request | ||
1117 | * sent to a specific application callback. | ||
1118 | * | ||
1119 | * \return true if the request is supported, else the request is stalled by UDD | ||
1120 | */ | ||
1121 | bool udc_process_setup(void) | ||
1122 | { | ||
1123 | // By default no data (receive/send) and no callbacks registered | ||
1124 | udd_g_ctrlreq.payload_size = 0; | ||
1125 | udd_g_ctrlreq.callback = NULL; | ||
1126 | udd_g_ctrlreq.over_under_run = NULL; | ||
1127 | |||
1128 | if (Udd_setup_is_in()) { | ||
1129 | if (udd_g_ctrlreq.req.wLength == 0) { | ||
1130 | return false; // Error from USB host | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | // If standard request then try to decode it in UDC | ||
1135 | if (Udd_setup_type() == USB_REQ_TYPE_STANDARD) { | ||
1136 | if (udc_reqstd()) { | ||
1137 | return true; | ||
1138 | } | ||
1139 | } | ||
1140 | |||
1141 | // If interface request then try to decode it in UDI | ||
1142 | if (Udd_setup_recipient() == USB_REQ_RECIP_INTERFACE) { | ||
1143 | if (udc_req_iface()) { | ||
1144 | return true; | ||
1145 | } | ||
1146 | } | ||
1147 | |||
1148 | // If endpoint request then try to decode it in UDI | ||
1149 | if (Udd_setup_recipient() == USB_REQ_RECIP_ENDPOINT) { | ||
1150 | if (udc_req_ep()) { | ||
1151 | return true; | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | // Here SETUP request unknown by UDC and UDIs | ||
1156 | #ifdef USB_DEVICE_SPECIFIC_REQUEST | ||
1157 | // Try to decode it in specific callback | ||
1158 | return USB_DEVICE_SPECIFIC_REQUEST(); // Ex: Vendor request,... | ||
1159 | #else | ||
1160 | return false; | ||
1161 | #endif | ||
1162 | } | ||
1163 | |||
1164 | //! @} | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udc.h b/tmk_core/protocol/arm_atsam/usb/udc.h new file mode 100644 index 000000000..c88a442cb --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udc.h | |||
@@ -0,0 +1,260 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Interface of the USB Device Controller (UDC) | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDC_H_ | ||
48 | #define _UDC_H_ | ||
49 | |||
50 | #include "conf_usb.h" | ||
51 | #include "usb_protocol.h" | ||
52 | #include "udc_desc.h" | ||
53 | #include "udd.h" | ||
54 | |||
55 | #if USB_DEVICE_VENDOR_ID == 0 | ||
56 | # error USB_DEVICE_VENDOR_ID cannot be equal to 0 | ||
57 | #endif | ||
58 | |||
59 | #if USB_DEVICE_PRODUCT_ID == 0 | ||
60 | # error USB_DEVICE_PRODUCT_ID cannot be equal to 0 | ||
61 | #endif | ||
62 | |||
63 | #ifdef __cplusplus | ||
64 | extern "C" { | ||
65 | #endif | ||
66 | |||
67 | /** | ||
68 | * \ingroup usb_device_group | ||
69 | * \defgroup udc_group USB Device Controller (UDC) | ||
70 | * | ||
71 | * The UDC provides a high-level abstraction of the usb device. | ||
72 | * You can use these functions to control the main device state | ||
73 | * (start/attach/wakeup). | ||
74 | * | ||
75 | * \section USB_DEVICE_CONF USB Device Custom configuration | ||
76 | * The following USB Device configuration must be included in the conf_usb.h | ||
77 | * file of the application. | ||
78 | * | ||
79 | * USB_DEVICE_VENDOR_ID (Word)<br> | ||
80 | * Vendor ID provided by USB org (ATMEL 0x03EB). | ||
81 | * | ||
82 | * USB_DEVICE_PRODUCT_ID (Word)<br> | ||
83 | * Product ID (Referenced in usb_atmel.h). | ||
84 | * | ||
85 | * USB_DEVICE_MAJOR_VERSION (Byte)<br> | ||
86 | * Major version of the device | ||
87 | * | ||
88 | * USB_DEVICE_MINOR_VERSION (Byte)<br> | ||
89 | * Minor version of the device | ||
90 | * | ||
91 | * USB_DEVICE_MANUFACTURE_NAME (string)<br> | ||
92 | * ASCII name for the manufacture | ||
93 | * | ||
94 | * USB_DEVICE_PRODUCT_NAME (string)<br> | ||
95 | * ASCII name for the product | ||
96 | * | ||
97 | * USB_DEVICE_SERIAL_NAME (string)<br> | ||
98 | * ASCII name to enable and set a serial number | ||
99 | * | ||
100 | * USB_DEVICE_POWER (Numeric)<br> | ||
101 | * (unit mA) Maximum device power | ||
102 | * | ||
103 | * USB_DEVICE_ATTR (Byte)<br> | ||
104 | * USB attributes available: | ||
105 | * - USB_CONFIG_ATTR_SELF_POWERED | ||
106 | * - USB_CONFIG_ATTR_REMOTE_WAKEUP | ||
107 | * Note: if remote wake enabled then defines remotewakeup callbacks, | ||
108 | * see Table 5-2. External API from UDC - Callback | ||
109 | * | ||
110 | * USB_DEVICE_LOW_SPEED (Only defined)<br> | ||
111 | * Force the USB Device to run in low speed | ||
112 | * | ||
113 | * USB_DEVICE_HS_SUPPORT (Only defined)<br> | ||
114 | * Authorize the USB Device to run in high speed | ||
115 | * | ||
116 | * USB_DEVICE_MAX_EP (Byte)<br> | ||
117 | * Define the maximum endpoint number used by the USB Device.<br> | ||
118 | * This one is already defined in UDI default configuration. | ||
119 | * Ex: | ||
120 | * - When endpoint control 0x00, endpoint 0x01 and | ||
121 | * endpoint 0x82 is used then USB_DEVICE_MAX_EP=2 | ||
122 | * - When only endpoint control 0x00 is used then USB_DEVICE_MAX_EP=0 | ||
123 | * - When endpoint 0x01 and endpoint 0x81 is used then USB_DEVICE_MAX_EP=1<br> | ||
124 | * (configuration not possible on USBB interface) | ||
125 | * @{ | ||
126 | */ | ||
127 | |||
128 | /** | ||
129 | * \brief Authorizes the VBUS event | ||
130 | * | ||
131 | * \return true, if the VBUS monitoring is possible. | ||
132 | * | ||
133 | * \section udc_vbus_monitoring VBus monitoring used cases | ||
134 | * | ||
135 | * The VBus monitoring is used only for USB SELF Power application. | ||
136 | * | ||
137 | * - By default the USB device is automatically attached when Vbus is high | ||
138 | * or when USB is start for devices without internal Vbus monitoring. | ||
139 | * conf_usb.h file does not contains define USB_DEVICE_ATTACH_AUTO_DISABLE. | ||
140 | * \code //#define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode | ||
141 | * | ||
142 | * - Add custom VBUS monitoring. conf_usb.h file contains define | ||
143 | * USB_DEVICE_ATTACH_AUTO_DISABLE: | ||
144 | * \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode | ||
145 | * User C file contains: | ||
146 | * \code | ||
147 | // Authorize VBUS monitoring | ||
148 | if (!udc_include_vbus_monitoring()) { | ||
149 | // Implement custom VBUS monitoring via GPIO or other | ||
150 | } | ||
151 | Event_VBUS_present() // VBUS interrupt or GPIO interrupt or other | ||
152 | { | ||
153 | // Attach USB Device | ||
154 | udc_attach(); | ||
155 | } | ||
156 | \endcode | ||
157 | * | ||
158 | * - Case of battery charging. conf_usb.h file contains define | ||
159 | * USB_DEVICE_ATTACH_AUTO_DISABLE: | ||
160 | * \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode | ||
161 | * User C file contains: | ||
162 | * \code | ||
163 | Event VBUS present() // VBUS interrupt or GPIO interrupt or .. | ||
164 | { | ||
165 | // Authorize battery charging, but wait key press to start USB. | ||
166 | } | ||
167 | Event Key press() | ||
168 | { | ||
169 | // Stop batteries charging | ||
170 | // Start USB | ||
171 | udc_attach(); | ||
172 | } | ||
173 | \endcode | ||
174 | */ | ||
175 | static inline bool udc_include_vbus_monitoring(void) | ||
176 | { | ||
177 | return udd_include_vbus_monitoring(); | ||
178 | } | ||
179 | |||
180 | /*! \brief Start the USB Device stack | ||
181 | */ | ||
182 | void udc_start(void); | ||
183 | |||
184 | /*! \brief Stop the USB Device stack | ||
185 | */ | ||
186 | void udc_stop(void); | ||
187 | |||
188 | /** | ||
189 | * \brief Attach device to the bus when possible | ||
190 | * | ||
191 | * \warning If a VBus control is included in driver, | ||
192 | * then it will attach device when an acceptable Vbus | ||
193 | * level from the host is detected. | ||
194 | */ | ||
195 | static inline void udc_attach(void) | ||
196 | { | ||
197 | udd_attach(); | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * \brief Detaches the device from the bus | ||
202 | * | ||
203 | * The driver must remove pull-up on USB line D- or D+. | ||
204 | */ | ||
205 | static inline void udc_detach(void) | ||
206 | { | ||
207 | udd_detach(); | ||
208 | } | ||
209 | |||
210 | /*! \brief The USB driver sends a resume signal called \e "Upstream Resume" | ||
211 | * This is authorized only when the remote wakeup feature is enabled by host. | ||
212 | */ | ||
213 | static inline void udc_remotewakeup(void) | ||
214 | { | ||
215 | udd_send_remotewakeup(); | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * \brief Returns a pointer on the current interface descriptor | ||
220 | * | ||
221 | * \return pointer on the current interface descriptor. | ||
222 | */ | ||
223 | usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void); | ||
224 | |||
225 | //@} | ||
226 | |||
227 | /** | ||
228 | * \ingroup usb_group | ||
229 | * \defgroup usb_device_group USB Stack Device | ||
230 | * | ||
231 | * This module includes USB Stack Device implementation. | ||
232 | * The stack is divided in three parts: | ||
233 | * - USB Device Controller (UDC) provides USB chapter 9 compliance | ||
234 | * - USB Device Interface (UDI) provides USB Class compliance | ||
235 | * - USB Device Driver (UDD) provides USB Driver for each Atmel MCU | ||
236 | |||
237 | * Many USB Device applications can be implemented on Atmel MCU. | ||
238 | * Atmel provides many application notes for different applications: | ||
239 | * - AVR4900, provides general information about Device Stack | ||
240 | * - AVR4901, explains how to create a new class | ||
241 | * - AVR4902, explains how to create a composite device | ||
242 | * - AVR49xx, all device classes provided in ASF have an application note | ||
243 | * | ||
244 | * A basic USB knowledge is required to understand the USB Device | ||
245 | * Class application notes (HID,MS,CDC,PHDC,...). | ||
246 | * Then, to create an USB device with | ||
247 | * only one class provided by ASF, refer directly to the application note | ||
248 | * corresponding to this USB class. The USB Device application note for | ||
249 | * New Class and Composite is dedicated to advanced USB users. | ||
250 | * | ||
251 | * @{ | ||
252 | */ | ||
253 | |||
254 | //! @} | ||
255 | |||
256 | #ifdef __cplusplus | ||
257 | } | ||
258 | #endif | ||
259 | |||
260 | #endif // _UDC_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udc_desc.h b/tmk_core/protocol/arm_atsam/usb/udc_desc.h new file mode 100644 index 000000000..9cab03dcb --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udc_desc.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Common API for USB Device Interface | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDC_DESC_H_ | ||
48 | #define _UDC_DESC_H_ | ||
49 | |||
50 | #include "conf_usb.h" | ||
51 | #include "usb_protocol.h" | ||
52 | #include "udi.h" | ||
53 | |||
54 | #ifdef __cplusplus | ||
55 | extern "C" { | ||
56 | #endif | ||
57 | |||
58 | /** | ||
59 | * \ingroup udc_group | ||
60 | * \defgroup udc_desc_group USB Device Descriptor | ||
61 | * | ||
62 | * @{ | ||
63 | */ | ||
64 | |||
65 | /** | ||
66 | * \brief Defines the memory's location of USB descriptors | ||
67 | * | ||
68 | * By default the Descriptor is stored in RAM | ||
69 | * (UDC_DESC_STORAGE is defined empty). | ||
70 | * | ||
71 | * If you have need to free RAM space, | ||
72 | * it is possible to put descriptor in flash in following case: | ||
73 | * - USB driver authorize flash transfer (USBB on UC3 and USB on Mega) | ||
74 | * - USB Device is not high speed (UDC no need to change USB descriptors) | ||
75 | * | ||
76 | * For UC3 application used "const". | ||
77 | * | ||
78 | * For Mega application used "code". | ||
79 | */ | ||
80 | #define UDC_DESC_STORAGE | ||
81 | // Descriptor storage in internal RAM | ||
82 | #if (defined UDC_DATA_USE_HRAM_SUPPORT) | ||
83 | #if defined(__GNUC__) | ||
84 | #define UDC_DATA(x) COMPILER_WORD_ALIGNED __attribute__((__section__(".data_hram0"))) | ||
85 | #define UDC_BSS(x) COMPILER_ALIGNED(x) __attribute__((__section__(".bss_hram0"))) | ||
86 | #elif defined(__ICCAVR32__) | ||
87 | #define UDC_DATA(x) COMPILER_ALIGNED(x) __data32 | ||
88 | #define UDC_BSS(x) COMPILER_ALIGNED(x) __data32 | ||
89 | #endif | ||
90 | #else | ||
91 | #define UDC_DATA(x) COMPILER_ALIGNED(x) | ||
92 | #define UDC_BSS(x) COMPILER_ALIGNED(x) | ||
93 | #endif | ||
94 | |||
95 | |||
96 | |||
97 | /** | ||
98 | * \brief Configuration descriptor and UDI link for one USB speed | ||
99 | */ | ||
100 | typedef struct { | ||
101 | //! USB configuration descriptor | ||
102 | usb_conf_desc_t UDC_DESC_STORAGE *desc; | ||
103 | //! Array of UDI API pointer | ||
104 | udi_api_t UDC_DESC_STORAGE *UDC_DESC_STORAGE * udi_apis; | ||
105 | } udc_config_speed_t; | ||
106 | |||
107 | |||
108 | /** | ||
109 | * \brief All information about the USB Device | ||
110 | */ | ||
111 | typedef struct { | ||
112 | //! USB device descriptor for low or full speed | ||
113 | usb_dev_desc_t UDC_DESC_STORAGE *confdev_lsfs; | ||
114 | //! USB configuration descriptor and UDI API pointers for low or full speed | ||
115 | udc_config_speed_t UDC_DESC_STORAGE *conf_lsfs; | ||
116 | #ifdef USB_DEVICE_HS_SUPPORT | ||
117 | //! USB device descriptor for high speed | ||
118 | usb_dev_desc_t UDC_DESC_STORAGE *confdev_hs; | ||
119 | //! USB device qualifier, only use in high speed mode | ||
120 | usb_dev_qual_desc_t UDC_DESC_STORAGE *qualifier; | ||
121 | //! USB configuration descriptor and UDI API pointers for high speed | ||
122 | udc_config_speed_t UDC_DESC_STORAGE *conf_hs; | ||
123 | #endif | ||
124 | usb_dev_bos_desc_t UDC_DESC_STORAGE *conf_bos; | ||
125 | } udc_config_t; | ||
126 | |||
127 | //! Global variables of USB Device Descriptor and UDI links | ||
128 | extern UDC_DESC_STORAGE udc_config_t udc_config; | ||
129 | |||
130 | //@} | ||
131 | |||
132 | #ifdef __cplusplus | ||
133 | } | ||
134 | #endif | ||
135 | #endif // _UDC_DESC_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udd.h b/tmk_core/protocol/arm_atsam/usb/udd.h new file mode 100644 index 000000000..b580e5847 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udd.h | |||
@@ -0,0 +1,396 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Common API for USB Device Drivers (UDD) | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDD_H_ | ||
48 | #define _UDD_H_ | ||
49 | |||
50 | #include "usb_protocol.h" | ||
51 | #include "udc_desc.h" | ||
52 | |||
53 | #ifdef __cplusplus | ||
54 | extern "C" { | ||
55 | #endif | ||
56 | |||
57 | /** | ||
58 | * \ingroup usb_device_group | ||
59 | * \defgroup udd_group USB Device Driver (UDD) | ||
60 | * | ||
61 | * The UDD driver provides a low-level abstraction of the device | ||
62 | * controller hardware. Most events coming from the hardware such as | ||
63 | * interrupts, which may cause the UDD to call into the UDC and UDI. | ||
64 | * | ||
65 | * @{ | ||
66 | */ | ||
67 | |||
68 | //! \brief Endpoint identifier | ||
69 | typedef uint8_t udd_ep_id_t; | ||
70 | |||
71 | //! \brief Endpoint transfer status | ||
72 | //! Returned in parameters of callback register via udd_ep_run routine. | ||
73 | typedef enum { | ||
74 | UDD_EP_TRANSFER_OK = 0, | ||
75 | UDD_EP_TRANSFER_ABORT = 1, | ||
76 | } udd_ep_status_t; | ||
77 | |||
78 | /** | ||
79 | * \brief Global variable to give and record information of the setup request management | ||
80 | * | ||
81 | * This global variable allows to decode and response a setup request. | ||
82 | * It can be updated by udc_process_setup() from UDC or *setup() from UDIs. | ||
83 | */ | ||
84 | typedef struct { | ||
85 | //! Data received in USB SETUP packet | ||
86 | //! Note: The swap of "req.wValues" from uin16_t to le16_t is done by UDD. | ||
87 | usb_setup_req_t req; | ||
88 | |||
89 | //! Point to buffer to send or fill with data following SETUP packet | ||
90 | //! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer) | ||
91 | uint8_t *payload; | ||
92 | |||
93 | //! Size of buffer to send or fill, and content the number of byte transfered | ||
94 | uint16_t payload_size; | ||
95 | |||
96 | //! Callback called after reception of ZLP from setup request | ||
97 | void (*callback) (void); | ||
98 | |||
99 | //! Callback called when the buffer given (.payload) is full or empty. | ||
100 | //! This one return false to abort data transfer, or true with a new buffer in .payload. | ||
101 | bool(*over_under_run) (void); | ||
102 | } udd_ctrl_request_t; | ||
103 | extern udd_ctrl_request_t udd_g_ctrlreq; | ||
104 | |||
105 | //! Return true if the setup request \a udd_g_ctrlreq indicates IN data transfer | ||
106 | #define Udd_setup_is_in() \ | ||
107 | (USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) | ||
108 | |||
109 | //! Return true if the setup request \a udd_g_ctrlreq indicates OUT data transfer | ||
110 | #define Udd_setup_is_out() \ | ||
111 | (USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK)) | ||
112 | |||
113 | //! Return the type of the SETUP request \a udd_g_ctrlreq. \see usb_reqtype. | ||
114 | #define Udd_setup_type() \ | ||
115 | (udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK) | ||
116 | |||
117 | //! Return the recipient of the SETUP request \a udd_g_ctrlreq. \see usb_recipient | ||
118 | #define Udd_setup_recipient() \ | ||
119 | (udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK) | ||
120 | |||
121 | /** | ||
122 | * \brief End of halt callback function type. | ||
123 | * Registered by routine udd_ep_wait_stall_clear() | ||
124 | * Callback called when endpoint stall is cleared. | ||
125 | */ | ||
126 | typedef void (*udd_callback_halt_cleared_t) (void); | ||
127 | |||
128 | /** | ||
129 | * \brief End of transfer callback function type. | ||
130 | * Registered by routine udd_ep_run() | ||
131 | * Callback called by USB interrupt after data transfer or abort (reset,...). | ||
132 | * | ||
133 | * \param status UDD_EP_TRANSFER_OK, if transfer is complete | ||
134 | * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted | ||
135 | * \param n number of data transfered | ||
136 | */ | ||
137 | typedef void (*udd_callback_trans_t) (udd_ep_status_t status, | ||
138 | iram_size_t nb_transfered, udd_ep_id_t ep); | ||
139 | |||
140 | /** | ||
141 | * \brief Authorizes the VBUS event | ||
142 | * | ||
143 | * \return true, if the VBUS monitoring is possible. | ||
144 | */ | ||
145 | bool udd_include_vbus_monitoring(void); | ||
146 | |||
147 | /** | ||
148 | * \brief Enables the USB Device mode | ||
149 | */ | ||
150 | void udd_enable(void); | ||
151 | |||
152 | /** | ||
153 | * \brief Disables the USB Device mode | ||
154 | */ | ||
155 | void udd_disable(void); | ||
156 | |||
157 | /** | ||
158 | * \brief Attach device to the bus when possible | ||
159 | * | ||
160 | * \warning If a VBus control is included in driver, | ||
161 | * then it will attach device when an acceptable Vbus | ||
162 | * level from the host is detected. | ||
163 | */ | ||
164 | void udd_attach(void); | ||
165 | |||
166 | /** | ||
167 | * \brief Detaches the device from the bus | ||
168 | * | ||
169 | * The driver must remove pull-up on USB line D- or D+. | ||
170 | */ | ||
171 | void udd_detach(void); | ||
172 | |||
173 | /** | ||
174 | * \brief Test whether the USB Device Controller is running at high | ||
175 | * speed or not. | ||
176 | * | ||
177 | * \return \c true if the Device is running at high speed mode, otherwise \c false. | ||
178 | */ | ||
179 | bool udd_is_high_speed(void); | ||
180 | |||
181 | /** | ||
182 | * \brief Changes the USB address of device | ||
183 | * | ||
184 | * \param address New USB address | ||
185 | */ | ||
186 | void udd_set_address(uint8_t address); | ||
187 | |||
188 | /** | ||
189 | * \brief Returns the USB address of device | ||
190 | * | ||
191 | * \return USB address | ||
192 | */ | ||
193 | uint8_t udd_getaddress(void); | ||
194 | |||
195 | /** | ||
196 | * \brief Returns the current start of frame number | ||
197 | * | ||
198 | * \return current start of frame number. | ||
199 | */ | ||
200 | uint16_t udd_get_frame_number(void); | ||
201 | |||
202 | /** | ||
203 | * \brief Returns the current micro start of frame number | ||
204 | * | ||
205 | * \return current micro start of frame number required in high speed mode. | ||
206 | */ | ||
207 | uint16_t udd_get_micro_frame_number(void); | ||
208 | |||
209 | /*! \brief The USB driver sends a resume signal called Upstream Resume | ||
210 | */ | ||
211 | void udd_send_remotewakeup(void); | ||
212 | |||
213 | /** | ||
214 | * \brief Load setup payload | ||
215 | * | ||
216 | * \param payload Pointer on payload | ||
217 | * \param payload_size Size of payload | ||
218 | */ | ||
219 | void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size ); | ||
220 | |||
221 | |||
222 | /** | ||
223 | * \name Endpoint Management | ||
224 | * | ||
225 | * The following functions allow drivers to create and remove | ||
226 | * endpoints, as well as set, clear and query their "halted" and | ||
227 | * "wedged" states. | ||
228 | */ | ||
229 | //@{ | ||
230 | |||
231 | #if (USB_DEVICE_MAX_EP != 0) | ||
232 | |||
233 | /** | ||
234 | * \brief Configures and enables an endpoint | ||
235 | * | ||
236 | * \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT). | ||
237 | * \param bmAttributes Attributes of endpoint declared in the descriptor. | ||
238 | * \param MaxEndpointSize Endpoint maximum size | ||
239 | * | ||
240 | * \return \c 1 if the endpoint is enabled, otherwise \c 0. | ||
241 | */ | ||
242 | bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, | ||
243 | uint16_t MaxEndpointSize); | ||
244 | |||
245 | /** | ||
246 | * \brief Disables an endpoint | ||
247 | * | ||
248 | * \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT). | ||
249 | */ | ||
250 | void udd_ep_free(udd_ep_id_t ep); | ||
251 | |||
252 | /** | ||
253 | * \brief Check if the endpoint \a ep is halted. | ||
254 | * | ||
255 | * \param ep The ID of the endpoint to check. | ||
256 | * | ||
257 | * \return \c 1 if \a ep is halted, otherwise \c 0. | ||
258 | */ | ||
259 | bool udd_ep_is_halted(udd_ep_id_t ep); | ||
260 | |||
261 | /** | ||
262 | * \brief Set the halted state of the endpoint \a ep | ||
263 | * | ||
264 | * After calling this function, any transaction on \a ep will result | ||
265 | * in a STALL handshake being sent. Any pending transactions will be | ||
266 | * performed first, however. | ||
267 | * | ||
268 | * \param ep The ID of the endpoint to be halted | ||
269 | * | ||
270 | * \return \c 1 if \a ep is halted, otherwise \c 0. | ||
271 | */ | ||
272 | bool udd_ep_set_halt(udd_ep_id_t ep); | ||
273 | |||
274 | /** | ||
275 | * \brief Clear the halted state of the endpoint \a ep | ||
276 | * | ||
277 | * After calling this function, any transaction on \a ep will | ||
278 | * be handled normally, i.e. a STALL handshake will not be sent, and | ||
279 | * the data toggle sequence will start at DATA0. | ||
280 | * | ||
281 | * \param ep The ID of the endpoint to be un-halted | ||
282 | * | ||
283 | * \return \c 1 if function was successfully done, otherwise \c 0. | ||
284 | */ | ||
285 | bool udd_ep_clear_halt(udd_ep_id_t ep); | ||
286 | |||
287 | /** | ||
288 | * \brief Registers a callback to call when endpoint halt is cleared | ||
289 | * | ||
290 | * \param ep The ID of the endpoint to use | ||
291 | * \param callback NULL or function to call when endpoint halt is cleared | ||
292 | * | ||
293 | * \warning if the endpoint is not halted then the \a callback is called immediately. | ||
294 | * | ||
295 | * \return \c 1 if the register is accepted, otherwise \c 0. | ||
296 | */ | ||
297 | bool udd_ep_wait_stall_clear(udd_ep_id_t ep, | ||
298 | udd_callback_halt_cleared_t callback); | ||
299 | |||
300 | /** | ||
301 | * \brief Allows to receive or send data on an endpoint | ||
302 | * | ||
303 | * The driver uses a specific DMA USB to transfer data | ||
304 | * from internal RAM to endpoint, if this one is available. | ||
305 | * When the transfer is finished or aborted (stall, reset, ...), the \a callback is called. | ||
306 | * The \a callback returns the transfer status and eventually the number of byte transfered. | ||
307 | * Note: The control endpoint is not authorized. | ||
308 | * | ||
309 | * \param ep The ID of the endpoint to use | ||
310 | * \param b_shortpacket Enabled automatic short packet | ||
311 | * \param buf Buffer on Internal RAM to send or fill. | ||
312 | * It must be align, then use COMPILER_WORD_ALIGNED. | ||
313 | * \param buf_size Buffer size to send or fill | ||
314 | * \param callback NULL or function to call at the end of transfer | ||
315 | * | ||
316 | * \warning About \a b_shortpacket, for IN endpoint it means that a short packet | ||
317 | * (or a Zero Length Packet) will be sent to the USB line to properly close the usb | ||
318 | * transfer at the end of the data transfer. | ||
319 | * For Bulk and Interrupt OUT endpoint, it will automatically stop the transfer | ||
320 | * at the end of the data transfer (received short packet). | ||
321 | * | ||
322 | * \return \c 1 if function was successfully done, otherwise \c 0. | ||
323 | */ | ||
324 | bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, | ||
325 | uint8_t *buf, iram_size_t buf_size, | ||
326 | udd_callback_trans_t callback); | ||
327 | /** | ||
328 | * \brief Aborts transfer on going on endpoint | ||
329 | * | ||
330 | * If a transfer is on going, then it is stopped and | ||
331 | * the callback registered is called to signal the end of transfer. | ||
332 | * Note: The control endpoint is not authorized. | ||
333 | * | ||
334 | * \param ep Endpoint to abort | ||
335 | */ | ||
336 | void udd_ep_abort(udd_ep_id_t ep); | ||
337 | |||
338 | #endif | ||
339 | |||
340 | //@} | ||
341 | |||
342 | |||
343 | /** | ||
344 | * \name High speed test mode management | ||
345 | * | ||
346 | * The following functions allow the device to jump to a specific test mode required in high speed mode. | ||
347 | */ | ||
348 | //@{ | ||
349 | void udd_test_mode_j(void); | ||
350 | void udd_test_mode_k(void); | ||
351 | void udd_test_mode_se0_nak(void); | ||
352 | void udd_test_mode_packet(void); | ||
353 | //@} | ||
354 | |||
355 | |||
356 | /** | ||
357 | * \name UDC callbacks to provide for UDD | ||
358 | * | ||
359 | * The following callbacks are used by UDD. | ||
360 | */ | ||
361 | //@{ | ||
362 | |||
363 | /** | ||
364 | * \brief Decodes and manages a setup request | ||
365 | * | ||
366 | * The driver call it when a SETUP packet is received. | ||
367 | * The \c udd_g_ctrlreq contains the data of SETUP packet. | ||
368 | * If this callback accepts the setup request then it must | ||
369 | * return \c 1 and eventually update \c udd_g_ctrlreq to send or receive data. | ||
370 | * | ||
371 | * \return \c 1 if the request is accepted, otherwise \c 0. | ||
372 | */ | ||
373 | extern bool udc_process_setup(void); | ||
374 | |||
375 | /** | ||
376 | * \brief Reset the UDC | ||
377 | * | ||
378 | * The UDC must reset all configuration. | ||
379 | */ | ||
380 | extern void udc_reset(void); | ||
381 | |||
382 | /** | ||
383 | * \brief To signal that a SOF is occurred | ||
384 | * | ||
385 | * The UDC must send the signal to all UDIs enabled | ||
386 | */ | ||
387 | extern void udc_sof_notify(void); | ||
388 | |||
389 | //@} | ||
390 | |||
391 | //@} | ||
392 | |||
393 | #ifdef __cplusplus | ||
394 | } | ||
395 | #endif | ||
396 | #endif // _UDD_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi.h b/tmk_core/protocol/arm_atsam/usb/udi.h new file mode 100644 index 000000000..9e4d4baf7 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi.h | |||
@@ -0,0 +1,133 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Common API for USB Device Interface | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDI_H_ | ||
48 | #define _UDI_H_ | ||
49 | |||
50 | #include "conf_usb.h" | ||
51 | #include "usb_protocol.h" | ||
52 | |||
53 | #ifdef __cplusplus | ||
54 | extern "C" { | ||
55 | #endif | ||
56 | |||
57 | /** | ||
58 | * \ingroup usb_device_group | ||
59 | * \defgroup udi_group USB Device Interface (UDI) | ||
60 | * The UDI provides a common API for all classes, | ||
61 | * and this is used by UDC for the main control of USB Device interface. | ||
62 | * @{ | ||
63 | */ | ||
64 | |||
65 | /** | ||
66 | * \brief UDI API. | ||
67 | * | ||
68 | * The callbacks within this structure are called only by | ||
69 | * USB Device Controller (UDC) | ||
70 | * | ||
71 | * The udc_get_interface_desc() can be use by UDI to know the interface descriptor | ||
72 | * selected by UDC. | ||
73 | */ | ||
74 | typedef struct { | ||
75 | /** | ||
76 | * \brief Enable the interface. | ||
77 | * | ||
78 | * This function is called when the host selects a configuration | ||
79 | * to which this interface belongs through a Set Configuration | ||
80 | * request, and when the host selects an alternate setting of | ||
81 | * this interface through a Set Interface request. | ||
82 | * | ||
83 | * \return \c 1 if function was successfully done, otherwise \c 0. | ||
84 | */ | ||
85 | bool(*enable) (void); | ||
86 | |||
87 | /** | ||
88 | * \brief Disable the interface. | ||
89 | * | ||
90 | * This function is called when this interface is currently | ||
91 | * active, and | ||
92 | * - the host selects any configuration through a Set | ||
93 | * Configuration request, or | ||
94 | * - the host issues a USB reset, or | ||
95 | * - the device is detached from the host (i.e. Vbus is no | ||
96 | * longer present) | ||
97 | */ | ||
98 | void (*disable) (void); | ||
99 | |||
100 | /** | ||
101 | * \brief Handle a control request directed at an interface. | ||
102 | * | ||
103 | * This function is called when this interface is currently | ||
104 | * active and the host sends a SETUP request | ||
105 | * with this interface as the recipient. | ||
106 | * | ||
107 | * Use udd_g_ctrlreq to decode and response to SETUP request. | ||
108 | * | ||
109 | * \return \c 1 if this interface supports the SETUP request, otherwise \c 0. | ||
110 | */ | ||
111 | bool(*setup) (void); | ||
112 | |||
113 | /** | ||
114 | * \brief Returns the current setting of the selected interface. | ||
115 | * | ||
116 | * This function is called when UDC when know alternate setting of selected interface. | ||
117 | * | ||
118 | * \return alternate setting of selected interface | ||
119 | */ | ||
120 | uint8_t(*getsetting) (void); | ||
121 | |||
122 | /** | ||
123 | * \brief To signal that a SOF is occurred | ||
124 | */ | ||
125 | void(*sof_notify) (void); | ||
126 | } udi_api_t; | ||
127 | |||
128 | //@} | ||
129 | |||
130 | #ifdef __cplusplus | ||
131 | } | ||
132 | #endif | ||
133 | #endif // _UDI_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_cdc.c b/tmk_core/protocol/arm_atsam/usb/udi_cdc.c new file mode 100644 index 000000000..b4159d325 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_cdc.c | |||
@@ -0,0 +1,1384 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device Communication Device Class (CDC) interface. | ||
5 | * | ||
6 | * Copyright (c) 2009-2016 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #include "samd51j18a.h" | ||
48 | #include "conf_usb.h" | ||
49 | #include "usb_protocol.h" | ||
50 | #include "usb_protocol_cdc.h" | ||
51 | #include "udd.h" | ||
52 | #include "udc.h" | ||
53 | #include "udi_cdc.h" | ||
54 | #include <string.h> | ||
55 | #include "udi_cdc_conf.h" | ||
56 | #include "udi_device_conf.h" | ||
57 | #include "spfssf.h" | ||
58 | #include "stdarg.h" | ||
59 | #include "tmk_core/protocol/arm_atsam/clks.h" | ||
60 | |||
61 | #ifdef CDC | ||
62 | |||
63 | #ifdef UDI_CDC_LOW_RATE | ||
64 | # ifdef USB_DEVICE_HS_SUPPORT | ||
65 | # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE) | ||
66 | # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE) | ||
67 | # else | ||
68 | # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE) | ||
69 | # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE) | ||
70 | # endif | ||
71 | #else | ||
72 | # ifdef USB_DEVICE_HS_SUPPORT | ||
73 | # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE) | ||
74 | # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE) | ||
75 | # else | ||
76 | # define UDI_CDC_TX_BUFFERS (5*UDI_CDC_DATA_EPS_FS_SIZE) | ||
77 | # define UDI_CDC_RX_BUFFERS (5*UDI_CDC_DATA_EPS_FS_SIZE) | ||
78 | # endif | ||
79 | #endif | ||
80 | |||
81 | #ifndef UDI_CDC_TX_EMPTY_NOTIFY | ||
82 | # define UDI_CDC_TX_EMPTY_NOTIFY(port) | ||
83 | #endif | ||
84 | |||
85 | /** | ||
86 | * \ingroup udi_cdc_group | ||
87 | * \defgroup udi_cdc_group_udc Interface with USB Device Core (UDC) | ||
88 | * | ||
89 | * Structures and functions required by UDC. | ||
90 | * | ||
91 | * @{ | ||
92 | */ | ||
93 | bool udi_cdc_comm_enable(void); | ||
94 | void udi_cdc_comm_disable(void); | ||
95 | bool udi_cdc_comm_setup(void); | ||
96 | bool udi_cdc_data_enable(void); | ||
97 | void udi_cdc_data_disable(void); | ||
98 | bool udi_cdc_data_setup(void); | ||
99 | uint8_t udi_cdc_getsetting(void); | ||
100 | void udi_cdc_data_sof_notify(void); | ||
101 | UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm = { | ||
102 | .enable = udi_cdc_comm_enable, | ||
103 | .disable = udi_cdc_comm_disable, | ||
104 | .setup = udi_cdc_comm_setup, | ||
105 | .getsetting = udi_cdc_getsetting, | ||
106 | .sof_notify = NULL | ||
107 | }; | ||
108 | UDC_DESC_STORAGE udi_api_t udi_api_cdc_data = { | ||
109 | .enable = udi_cdc_data_enable, | ||
110 | .disable = udi_cdc_data_disable, | ||
111 | .setup = udi_cdc_data_setup, | ||
112 | .getsetting = udi_cdc_getsetting, | ||
113 | .sof_notify = udi_cdc_data_sof_notify, | ||
114 | }; | ||
115 | //@} | ||
116 | |||
117 | /** | ||
118 | * \ingroup udi_cdc_group | ||
119 | * \defgroup udi_cdc_group_internal Implementation of UDI CDC | ||
120 | * | ||
121 | * Class internal implementation | ||
122 | * @{ | ||
123 | */ | ||
124 | |||
125 | /** | ||
126 | * \name Internal routines | ||
127 | */ | ||
128 | //@{ | ||
129 | |||
130 | /** | ||
131 | * \name Routines to control serial line | ||
132 | */ | ||
133 | //@{ | ||
134 | |||
135 | /** | ||
136 | * \brief Returns the port number corresponding at current setup request | ||
137 | * | ||
138 | * \return port number | ||
139 | */ | ||
140 | static uint8_t udi_cdc_setup_to_port(void); | ||
141 | |||
142 | /** | ||
143 | * \brief Sends line coding to application | ||
144 | * | ||
145 | * Called after SETUP request when line coding data is received. | ||
146 | */ | ||
147 | static void udi_cdc_line_coding_received(void); | ||
148 | |||
149 | /** | ||
150 | * \brief Records new state | ||
151 | * | ||
152 | * \param port Communication port number to manage | ||
153 | * \param b_set State is enabled if true, else disabled | ||
154 | * \param bit_mask Field to process (see CDC_SERIAL_STATE_ defines) | ||
155 | */ | ||
156 | static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask); | ||
157 | |||
158 | /** | ||
159 | * \brief Check and eventually notify the USB host of new state | ||
160 | * | ||
161 | * \param port Communication port number to manage | ||
162 | * \param ep Port communication endpoint | ||
163 | */ | ||
164 | static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep); | ||
165 | |||
166 | /** | ||
167 | * \brief Ack sent of serial state message | ||
168 | * Callback called after serial state message sent | ||
169 | * | ||
170 | * \param status UDD_EP_TRANSFER_OK, if transfer finished | ||
171 | * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted | ||
172 | * \param n number of data transfered | ||
173 | */ | ||
174 | static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep); | ||
175 | |||
176 | //@} | ||
177 | |||
178 | /** | ||
179 | * \name Routines to process data transfer | ||
180 | */ | ||
181 | //@{ | ||
182 | |||
183 | /** | ||
184 | * \brief Enable the reception of data from the USB host | ||
185 | * | ||
186 | * The value udi_cdc_rx_trans_sel indicate the RX buffer to fill. | ||
187 | * | ||
188 | * \param port Communication port number to manage | ||
189 | * | ||
190 | * \return \c 1 if function was successfully done, otherwise \c 0. | ||
191 | */ | ||
192 | static bool udi_cdc_rx_start(uint8_t port); | ||
193 | |||
194 | /** | ||
195 | * \brief Update rx buffer management with a new data | ||
196 | * Callback called after data reception on USB line | ||
197 | * | ||
198 | * \param status UDD_EP_TRANSFER_OK, if transfer finish | ||
199 | * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted | ||
200 | * \param n number of data received | ||
201 | */ | ||
202 | static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep); | ||
203 | |||
204 | /** | ||
205 | * \brief Ack sent of tx buffer | ||
206 | * Callback called after data transfer on USB line | ||
207 | * | ||
208 | * \param status UDD_EP_TRANSFER_OK, if transfer finished | ||
209 | * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted | ||
210 | * \param n number of data transfered | ||
211 | */ | ||
212 | static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep); | ||
213 | |||
214 | /** | ||
215 | * \brief Send buffer on line or wait a SOF event | ||
216 | * | ||
217 | * \param port Communication port number to manage | ||
218 | */ | ||
219 | static void udi_cdc_tx_send(uint8_t port); | ||
220 | |||
221 | //@} | ||
222 | |||
223 | //@} | ||
224 | |||
225 | /** | ||
226 | * \name Information about configuration of communication line | ||
227 | */ | ||
228 | //@{ | ||
229 | COMPILER_WORD_ALIGNED | ||
230 | static usb_cdc_line_coding_t udi_cdc_line_coding[UDI_CDC_PORT_NB]; | ||
231 | static bool udi_cdc_serial_state_msg_ongoing[UDI_CDC_PORT_NB]; | ||
232 | static volatile le16_t udi_cdc_state[UDI_CDC_PORT_NB]; | ||
233 | COMPILER_WORD_ALIGNED static usb_cdc_notify_serial_state_t uid_cdc_state_msg[UDI_CDC_PORT_NB]; | ||
234 | |||
235 | //! Status of CDC COMM interfaces | ||
236 | static volatile uint8_t udi_cdc_nb_comm_enabled = 0; | ||
237 | //@} | ||
238 | |||
239 | /** | ||
240 | * \name Variables to manage RX/TX transfer requests | ||
241 | * Two buffers for each sense are used to optimize the speed. | ||
242 | */ | ||
243 | //@{ | ||
244 | |||
245 | //! Status of CDC DATA interfaces | ||
246 | static volatile uint8_t udi_cdc_nb_data_enabled = 0; | ||
247 | static volatile bool udi_cdc_data_running = false; | ||
248 | //! Buffer to receive data | ||
249 | COMPILER_WORD_ALIGNED static uint8_t udi_cdc_rx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_RX_BUFFERS]; | ||
250 | //! Data available in RX buffers | ||
251 | static volatile uint16_t udi_cdc_rx_buf_nb[UDI_CDC_PORT_NB][2]; | ||
252 | //! Give the current RX buffer used (rx0 if 0, rx1 if 1) | ||
253 | static volatile uint8_t udi_cdc_rx_buf_sel[UDI_CDC_PORT_NB]; | ||
254 | //! Read position in current RX buffer | ||
255 | static volatile uint16_t udi_cdc_rx_pos[UDI_CDC_PORT_NB]; | ||
256 | //! Signal a transfer on-going | ||
257 | static volatile bool udi_cdc_rx_trans_ongoing[UDI_CDC_PORT_NB]; | ||
258 | |||
259 | //! Define a transfer halted | ||
260 | #define UDI_CDC_TRANS_HALTED 2 | ||
261 | |||
262 | //! Buffer to send data | ||
263 | COMPILER_WORD_ALIGNED static uint8_t udi_cdc_tx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_TX_BUFFERS]; | ||
264 | //! Data available in TX buffers | ||
265 | static uint16_t udi_cdc_tx_buf_nb[UDI_CDC_PORT_NB][2]; | ||
266 | //! Give current TX buffer used (tx0 if 0, tx1 if 1) | ||
267 | static volatile uint8_t udi_cdc_tx_buf_sel[UDI_CDC_PORT_NB]; | ||
268 | //! Value of SOF during last TX transfer | ||
269 | static uint16_t udi_cdc_tx_sof_num[UDI_CDC_PORT_NB]; | ||
270 | //! Signal a transfer on-going | ||
271 | static volatile bool udi_cdc_tx_trans_ongoing[UDI_CDC_PORT_NB]; | ||
272 | //! Signal that both buffer content data to send | ||
273 | static volatile bool udi_cdc_tx_both_buf_to_send[UDI_CDC_PORT_NB]; | ||
274 | |||
275 | //@} | ||
276 | |||
277 | bool udi_cdc_comm_enable(void) | ||
278 | { | ||
279 | uint8_t port; | ||
280 | uint8_t iface_comm_num; | ||
281 | |||
282 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
283 | port = 0; | ||
284 | udi_cdc_nb_comm_enabled = 0; | ||
285 | //#else | ||
286 | // if (udi_cdc_nb_comm_enabled > UDI_CDC_PORT_NB) { | ||
287 | // udi_cdc_nb_comm_enabled = 0; | ||
288 | // } | ||
289 | // port = udi_cdc_nb_comm_enabled; | ||
290 | //#endif | ||
291 | |||
292 | // Initialize control signal management | ||
293 | udi_cdc_state[port] = CPU_TO_LE16(0); | ||
294 | |||
295 | uid_cdc_state_msg[port].header.bmRequestType = | ||
296 | USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS | | ||
297 | USB_REQ_RECIP_INTERFACE; | ||
298 | uid_cdc_state_msg[port].header.bNotification = USB_REQ_CDC_NOTIFY_SERIAL_STATE; | ||
299 | uid_cdc_state_msg[port].header.wValue = LE16(0); | ||
300 | |||
301 | /* | ||
302 | switch (port) { | ||
303 | #define UDI_CDC_PORT_TO_IFACE_COMM(index, unused) \ | ||
304 | case index: \ | ||
305 | iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_##index; \ | ||
306 | break; | ||
307 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_IFACE_COMM, ~) | ||
308 | #undef UDI_CDC_PORT_TO_IFACE_COMM | ||
309 | default: | ||
310 | iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0; | ||
311 | break; | ||
312 | } | ||
313 | */ | ||
314 | iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0; | ||
315 | |||
316 | uid_cdc_state_msg[port].header.wIndex = LE16(iface_comm_num); | ||
317 | uid_cdc_state_msg[port].header.wLength = LE16(2); | ||
318 | uid_cdc_state_msg[port].value = CPU_TO_LE16(0); | ||
319 | |||
320 | udi_cdc_line_coding[port].dwDTERate = CPU_TO_LE32(UDI_CDC_DEFAULT_RATE); | ||
321 | udi_cdc_line_coding[port].bCharFormat = UDI_CDC_DEFAULT_STOPBITS; | ||
322 | udi_cdc_line_coding[port].bParityType = UDI_CDC_DEFAULT_PARITY; | ||
323 | udi_cdc_line_coding[port].bDataBits = UDI_CDC_DEFAULT_DATABITS; | ||
324 | // Call application callback | ||
325 | // to initialize memories or indicate that interface is enabled | ||
326 | #if 0 | ||
327 | UDI_CDC_SET_CODING_EXT(port,(&udi_cdc_line_coding[port])); | ||
328 | if (!UDI_CDC_ENABLE_EXT(port)) { | ||
329 | return false; | ||
330 | } | ||
331 | #endif | ||
332 | udi_cdc_nb_comm_enabled++; | ||
333 | return true; | ||
334 | } | ||
335 | |||
336 | bool udi_cdc_data_enable(void) | ||
337 | { | ||
338 | uint8_t port; | ||
339 | |||
340 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
341 | port = 0; | ||
342 | udi_cdc_nb_data_enabled = 0; | ||
343 | //#else | ||
344 | // if (udi_cdc_nb_data_enabled > UDI_CDC_PORT_NB) { | ||
345 | // udi_cdc_nb_data_enabled = 0; | ||
346 | // } | ||
347 | // port = udi_cdc_nb_data_enabled; | ||
348 | //#endif | ||
349 | |||
350 | // Initialize TX management | ||
351 | udi_cdc_tx_trans_ongoing[port] = false; | ||
352 | udi_cdc_tx_both_buf_to_send[port] = false; | ||
353 | udi_cdc_tx_buf_sel[port] = 0; | ||
354 | udi_cdc_tx_buf_nb[port][0] = 0; | ||
355 | udi_cdc_tx_buf_nb[port][1] = 0; | ||
356 | udi_cdc_tx_sof_num[port] = 0; | ||
357 | udi_cdc_tx_send(port); | ||
358 | |||
359 | // Initialize RX management | ||
360 | udi_cdc_rx_trans_ongoing[port] = false; | ||
361 | udi_cdc_rx_buf_sel[port] = 0; | ||
362 | udi_cdc_rx_buf_nb[port][0] = 0; | ||
363 | udi_cdc_rx_buf_nb[port][1] = 0; | ||
364 | udi_cdc_rx_pos[port] = 0; | ||
365 | if (!udi_cdc_rx_start(port)) { | ||
366 | return false; | ||
367 | } | ||
368 | udi_cdc_nb_data_enabled++; | ||
369 | if (udi_cdc_nb_data_enabled == UDI_CDC_PORT_NB) { | ||
370 | udi_cdc_data_running = true; | ||
371 | } | ||
372 | return true; | ||
373 | } | ||
374 | |||
375 | void udi_cdc_comm_disable(void) | ||
376 | { | ||
377 | Assert(udi_cdc_nb_comm_enabled != 0); | ||
378 | udi_cdc_nb_comm_enabled--; | ||
379 | } | ||
380 | |||
381 | void udi_cdc_data_disable(void) | ||
382 | { | ||
383 | // uint8_t port; | ||
384 | |||
385 | Assert(udi_cdc_nb_data_enabled != 0); | ||
386 | udi_cdc_nb_data_enabled--; | ||
387 | // port = udi_cdc_nb_data_enabled; | ||
388 | // UDI_CDC_DISABLE_EXT(port); | ||
389 | udi_cdc_data_running = false; | ||
390 | } | ||
391 | |||
392 | bool udi_cdc_comm_setup(void) | ||
393 | { | ||
394 | uint8_t port = udi_cdc_setup_to_port(); | ||
395 | |||
396 | if (Udd_setup_is_in()) { | ||
397 | // GET Interface Requests | ||
398 | if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { | ||
399 | // Requests Class Interface Get | ||
400 | switch (udd_g_ctrlreq.req.bRequest) { | ||
401 | case USB_REQ_CDC_GET_LINE_CODING: | ||
402 | // Get configuration of CDC line | ||
403 | if (sizeof(usb_cdc_line_coding_t) != | ||
404 | udd_g_ctrlreq.req.wLength) | ||
405 | return false; // Error for USB host | ||
406 | udd_g_ctrlreq.payload = | ||
407 | (uint8_t *) & | ||
408 | udi_cdc_line_coding[port]; | ||
409 | udd_g_ctrlreq.payload_size = | ||
410 | sizeof(usb_cdc_line_coding_t); | ||
411 | return true; | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | if (Udd_setup_is_out()) { | ||
416 | // SET Interface Requests | ||
417 | if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { | ||
418 | // Requests Class Interface Set | ||
419 | switch (udd_g_ctrlreq.req.bRequest) { | ||
420 | case USB_REQ_CDC_SET_LINE_CODING: | ||
421 | // Change configuration of CDC line | ||
422 | if (sizeof(usb_cdc_line_coding_t) != | ||
423 | udd_g_ctrlreq.req.wLength) | ||
424 | return false; // Error for USB host | ||
425 | udd_g_ctrlreq.callback = | ||
426 | udi_cdc_line_coding_received; | ||
427 | udd_g_ctrlreq.payload = | ||
428 | (uint8_t *) & | ||
429 | udi_cdc_line_coding[port]; | ||
430 | udd_g_ctrlreq.payload_size = | ||
431 | sizeof(usb_cdc_line_coding_t); | ||
432 | return true; | ||
433 | case USB_REQ_CDC_SET_CONTROL_LINE_STATE: | ||
434 | // According cdc spec 1.1 chapter 6.2.14 | ||
435 | // UDI_CDC_SET_DTR_EXT(port, (0 != | ||
436 | // (udd_g_ctrlreq.req.wValue | ||
437 | // & CDC_CTRL_SIGNAL_DTE_PRESENT))); | ||
438 | // UDI_CDC_SET_RTS_EXT(port, (0 != | ||
439 | // (udd_g_ctrlreq.req.wValue | ||
440 | // & CDC_CTRL_SIGNAL_ACTIVATE_CARRIER))); | ||
441 | return true; | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | return false; // request Not supported | ||
446 | } | ||
447 | |||
448 | bool udi_cdc_data_setup(void) | ||
449 | { | ||
450 | return false; // request Not supported | ||
451 | } | ||
452 | |||
453 | uint8_t udi_cdc_getsetting(void) | ||
454 | { | ||
455 | return 0; // CDC don't have multiple alternate setting | ||
456 | } | ||
457 | |||
458 | void udi_cdc_data_sof_notify(void) | ||
459 | { | ||
460 | static uint8_t port_notify = 0; | ||
461 | |||
462 | // A call of udi_cdc_data_sof_notify() is done for each port | ||
463 | udi_cdc_tx_send(port_notify); | ||
464 | /* | ||
465 | #if UDI_CDC_PORT_NB != 1 // To optimize code | ||
466 | port_notify++; | ||
467 | if (port_notify >= UDI_CDC_PORT_NB) { | ||
468 | port_notify = 0; | ||
469 | } | ||
470 | #endif | ||
471 | */ | ||
472 | } | ||
473 | |||
474 | |||
475 | //------------------------------------------------- | ||
476 | //------- Internal routines to control serial line | ||
477 | |||
478 | static uint8_t udi_cdc_setup_to_port(void) | ||
479 | { | ||
480 | uint8_t port; | ||
481 | |||
482 | /* | ||
483 | switch (udd_g_ctrlreq.req.wIndex & 0xFF) { | ||
484 | #define UDI_CDC_IFACE_COMM_TO_PORT(iface, unused) \ | ||
485 | case UDI_CDC_COMM_IFACE_NUMBER_##iface: \ | ||
486 | port = iface; \ | ||
487 | break; | ||
488 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_IFACE_COMM_TO_PORT, ~) | ||
489 | #undef UDI_CDC_IFACE_COMM_TO_PORT | ||
490 | default: | ||
491 | port = 0; | ||
492 | break; | ||
493 | } | ||
494 | */ | ||
495 | port = 0; | ||
496 | |||
497 | return port; | ||
498 | } | ||
499 | |||
500 | static void udi_cdc_line_coding_received(void) | ||
501 | { | ||
502 | uint8_t port = udi_cdc_setup_to_port(); | ||
503 | UNUSED(port); | ||
504 | |||
505 | // UDI_CDC_SET_CODING_EXT(port, (&udi_cdc_line_coding[port])); | ||
506 | } | ||
507 | |||
508 | static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask) | ||
509 | { | ||
510 | udd_ep_id_t ep_comm; | ||
511 | uint32_t irqflags; //irqflags_t | ||
512 | |||
513 | |||
514 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
515 | port = 0; | ||
516 | //#endif | ||
517 | |||
518 | // Update state | ||
519 | irqflags = __get_PRIMASK(); | ||
520 | __disable_irq(); | ||
521 | __DMB(); | ||
522 | if (b_set) { | ||
523 | udi_cdc_state[port] |= bit_mask; | ||
524 | } else { | ||
525 | udi_cdc_state[port] &= ~(unsigned)bit_mask; | ||
526 | } | ||
527 | __DMB(); | ||
528 | __set_PRIMASK(irqflags); | ||
529 | |||
530 | /* | ||
531 | // Send it if possible and state changed | ||
532 | switch (port) { | ||
533 | #define UDI_CDC_PORT_TO_COMM_EP(index, unused) \ | ||
534 | case index: \ | ||
535 | ep_comm = UDI_CDC_COMM_EP_##index; \ | ||
536 | break; | ||
537 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_COMM_EP, ~) | ||
538 | #undef UDI_CDC_PORT_TO_COMM_EP | ||
539 | default: | ||
540 | ep_comm = UDI_CDC_COMM_EP_0; | ||
541 | break; | ||
542 | } | ||
543 | */ | ||
544 | ep_comm = UDI_CDC_COMM_EP_0; | ||
545 | |||
546 | udi_cdc_ctrl_state_notify(port, ep_comm); | ||
547 | } | ||
548 | |||
549 | |||
550 | static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep) | ||
551 | { | ||
552 | #if UDI_CDC_PORT_NB == 1 // To optimize code | ||
553 | port = 0; | ||
554 | #endif | ||
555 | |||
556 | // Send it if possible and state changed | ||
557 | if ((!udi_cdc_serial_state_msg_ongoing[port]) | ||
558 | && (udi_cdc_state[port] != uid_cdc_state_msg[port].value)) { | ||
559 | // Fill notification message | ||
560 | uid_cdc_state_msg[port].value = udi_cdc_state[port]; | ||
561 | // Send notification message | ||
562 | udi_cdc_serial_state_msg_ongoing[port] = | ||
563 | udd_ep_run(ep, | ||
564 | false, | ||
565 | (uint8_t *) & uid_cdc_state_msg[port], | ||
566 | sizeof(uid_cdc_state_msg[0]), | ||
567 | udi_cdc_serial_state_msg_sent); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | |||
572 | static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep) | ||
573 | { | ||
574 | uint8_t port; | ||
575 | UNUSED(n); | ||
576 | UNUSED(status); | ||
577 | |||
578 | /* | ||
579 | switch (ep) { | ||
580 | #define UDI_CDC_GET_PORT_FROM_COMM_EP(iface, unused) \ | ||
581 | case UDI_CDC_COMM_EP_##iface: \ | ||
582 | port = iface; \ | ||
583 | break; | ||
584 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_GET_PORT_FROM_COMM_EP, ~) | ||
585 | #undef UDI_CDC_GET_PORT_FROM_COMM_EP | ||
586 | default: | ||
587 | port = 0; | ||
588 | break; | ||
589 | } | ||
590 | */ | ||
591 | port = 0; | ||
592 | |||
593 | udi_cdc_serial_state_msg_ongoing[port] = false; | ||
594 | |||
595 | // For the irregular signals like break, the incoming ring signal, | ||
596 | // or the overrun error state, this will reset their values to zero | ||
597 | // and again will not send another notification until their state changes. | ||
598 | udi_cdc_state[port] &= ~(CDC_SERIAL_STATE_BREAK | | ||
599 | CDC_SERIAL_STATE_RING | | ||
600 | CDC_SERIAL_STATE_FRAMING | | ||
601 | CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN); | ||
602 | uid_cdc_state_msg[port].value &= ~(CDC_SERIAL_STATE_BREAK | | ||
603 | CDC_SERIAL_STATE_RING | | ||
604 | CDC_SERIAL_STATE_FRAMING | | ||
605 | CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN); | ||
606 | // Send it if possible and state changed | ||
607 | udi_cdc_ctrl_state_notify(port, ep); | ||
608 | } | ||
609 | |||
610 | //------------------------------------------------- | ||
611 | //------- Internal routines to process data transfer | ||
612 | |||
613 | static bool udi_cdc_rx_start(uint8_t port) | ||
614 | { | ||
615 | uint32_t irqflags; //irqflags_t | ||
616 | uint8_t buf_sel_trans; | ||
617 | udd_ep_id_t ep; | ||
618 | |||
619 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
620 | port = 0; | ||
621 | //#endif | ||
622 | |||
623 | irqflags = __get_PRIMASK(); | ||
624 | __disable_irq(); | ||
625 | __DMB(); | ||
626 | buf_sel_trans = udi_cdc_rx_buf_sel[port]; | ||
627 | if (udi_cdc_rx_trans_ongoing[port] || | ||
628 | (udi_cdc_rx_pos[port] < udi_cdc_rx_buf_nb[port][buf_sel_trans])) { | ||
629 | // Transfer already on-going or current buffer no empty | ||
630 | __DMB(); | ||
631 | __set_PRIMASK(irqflags); | ||
632 | return false; | ||
633 | } | ||
634 | |||
635 | // Change current buffer | ||
636 | udi_cdc_rx_pos[port] = 0; | ||
637 | udi_cdc_rx_buf_sel[port] = (buf_sel_trans==0)?1:0; | ||
638 | |||
639 | // Start transfer on RX | ||
640 | udi_cdc_rx_trans_ongoing[port] = true; | ||
641 | __DMB(); | ||
642 | __set_PRIMASK(irqflags); | ||
643 | |||
644 | if (udi_cdc_multi_is_rx_ready(port)) { | ||
645 | // UDI_CDC_RX_NOTIFY(port); | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | // Send the buffer with enable of short packet | ||
650 | switch (port) { | ||
651 | #define UDI_CDC_PORT_TO_DATA_EP_OUT(index, unused) \ | ||
652 | case index: \ | ||
653 | ep = UDI_CDC_DATA_EP_OUT_##index; \ | ||
654 | break; | ||
655 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_OUT, ~) | ||
656 | #undef UDI_CDC_PORT_TO_DATA_EP_OUT | ||
657 | default: | ||
658 | ep = UDI_CDC_DATA_EP_OUT_0; | ||
659 | break; | ||
660 | } | ||
661 | */ | ||
662 | ep = UDI_CDC_DATA_EP_OUT_0; | ||
663 | |||
664 | return udd_ep_run(ep, | ||
665 | true, | ||
666 | udi_cdc_rx_buf[port][buf_sel_trans], | ||
667 | UDI_CDC_RX_BUFFERS, | ||
668 | udi_cdc_data_received); | ||
669 | } | ||
670 | |||
671 | static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep) | ||
672 | { | ||
673 | uint8_t buf_sel_trans; | ||
674 | uint8_t port; | ||
675 | |||
676 | /* | ||
677 | switch (ep) { | ||
678 | #define UDI_CDC_DATA_EP_OUT_TO_PORT(index, unused) \ | ||
679 | case UDI_CDC_DATA_EP_OUT_##index: \ | ||
680 | port = index; \ | ||
681 | break; | ||
682 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_OUT_TO_PORT, ~) | ||
683 | #undef UDI_CDC_DATA_EP_OUT_TO_PORT | ||
684 | default: | ||
685 | port = 0; | ||
686 | break; | ||
687 | } | ||
688 | */ | ||
689 | port = 0; | ||
690 | |||
691 | if (UDD_EP_TRANSFER_OK != status) { | ||
692 | // Abort reception | ||
693 | return; | ||
694 | } | ||
695 | |||
696 | buf_sel_trans = (udi_cdc_rx_buf_sel[port]==0)?1:0; | ||
697 | |||
698 | if (!n) { | ||
699 | udd_ep_run( ep, | ||
700 | true, | ||
701 | udi_cdc_rx_buf[port][buf_sel_trans], | ||
702 | UDI_CDC_RX_BUFFERS, | ||
703 | udi_cdc_data_received); | ||
704 | return; | ||
705 | } | ||
706 | |||
707 | udi_cdc_rx_buf_nb[port][buf_sel_trans] = n; | ||
708 | udi_cdc_rx_trans_ongoing[port] = false; | ||
709 | udi_cdc_rx_start(port); | ||
710 | } | ||
711 | |||
712 | static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep) | ||
713 | { | ||
714 | uint8_t port; | ||
715 | UNUSED(n); | ||
716 | |||
717 | /* | ||
718 | switch (ep) { | ||
719 | #define UDI_CDC_DATA_EP_IN_TO_PORT(index, unused) \ | ||
720 | case UDI_CDC_DATA_EP_IN_##index: \ | ||
721 | port = index; \ | ||
722 | break; | ||
723 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_IN_TO_PORT, ~) | ||
724 | #undef UDI_CDC_DATA_EP_IN_TO_PORT | ||
725 | default: | ||
726 | port = 0; | ||
727 | break; | ||
728 | } | ||
729 | */ | ||
730 | port = 0; | ||
731 | |||
732 | if (UDD_EP_TRANSFER_OK != status) { | ||
733 | // Abort transfer | ||
734 | return; | ||
735 | } | ||
736 | |||
737 | udi_cdc_tx_buf_nb[port][(udi_cdc_tx_buf_sel[port]==0)?1:0] = 0; | ||
738 | udi_cdc_tx_both_buf_to_send[port] = false; | ||
739 | udi_cdc_tx_trans_ongoing[port] = false; | ||
740 | |||
741 | if (n != 0) { | ||
742 | UDI_CDC_TX_EMPTY_NOTIFY(port); | ||
743 | } | ||
744 | |||
745 | udi_cdc_tx_send(port); | ||
746 | } | ||
747 | |||
748 | static void udi_cdc_tx_send(uint8_t port) | ||
749 | { | ||
750 | uint32_t irqflags; //irqflags_t | ||
751 | uint8_t buf_sel_trans; | ||
752 | bool b_short_packet; | ||
753 | udd_ep_id_t ep; | ||
754 | static uint16_t sof_zlp_counter = 0; | ||
755 | |||
756 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
757 | port = 0; | ||
758 | //#endif | ||
759 | |||
760 | if (udi_cdc_tx_trans_ongoing[port]) { | ||
761 | return; // Already on going or wait next SOF to send next data | ||
762 | } | ||
763 | if (udd_is_high_speed()) { | ||
764 | if (udi_cdc_tx_sof_num[port] == udd_get_micro_frame_number()) { | ||
765 | return; // Wait next SOF to send next data | ||
766 | } | ||
767 | }else{ | ||
768 | if (udi_cdc_tx_sof_num[port] == udd_get_frame_number()) { | ||
769 | return; // Wait next SOF to send next data | ||
770 | } | ||
771 | } | ||
772 | |||
773 | irqflags = __get_PRIMASK(); | ||
774 | __disable_irq(); | ||
775 | __DMB(); | ||
776 | buf_sel_trans = udi_cdc_tx_buf_sel[port]; | ||
777 | if (udi_cdc_tx_buf_nb[port][buf_sel_trans] == 0) { | ||
778 | sof_zlp_counter++; | ||
779 | if (((!udd_is_high_speed()) && (sof_zlp_counter < 100)) | ||
780 | || (udd_is_high_speed() && (sof_zlp_counter < 800))) { | ||
781 | __DMB(); | ||
782 | __set_PRIMASK(irqflags); | ||
783 | return; | ||
784 | } | ||
785 | } | ||
786 | sof_zlp_counter = 0; | ||
787 | |||
788 | if (!udi_cdc_tx_both_buf_to_send[port]) { | ||
789 | // Send current Buffer | ||
790 | // and switch the current buffer | ||
791 | udi_cdc_tx_buf_sel[port] = (buf_sel_trans==0)?1:0; | ||
792 | }else{ | ||
793 | // Send the other Buffer | ||
794 | // and no switch the current buffer | ||
795 | buf_sel_trans = (buf_sel_trans==0)?1:0; | ||
796 | } | ||
797 | udi_cdc_tx_trans_ongoing[port] = true; | ||
798 | __DMB(); | ||
799 | __set_PRIMASK(irqflags); | ||
800 | |||
801 | b_short_packet = (udi_cdc_tx_buf_nb[port][buf_sel_trans] != UDI_CDC_TX_BUFFERS); | ||
802 | if (b_short_packet) { | ||
803 | if (udd_is_high_speed()) { | ||
804 | udi_cdc_tx_sof_num[port] = udd_get_micro_frame_number(); | ||
805 | }else{ | ||
806 | udi_cdc_tx_sof_num[port] = udd_get_frame_number(); | ||
807 | } | ||
808 | }else{ | ||
809 | udi_cdc_tx_sof_num[port] = 0; // Force next transfer without wait SOF | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | // Send the buffer with enable of short packet | ||
814 | switch (port) { | ||
815 | #define UDI_CDC_PORT_TO_DATA_EP_IN(index, unused) \ | ||
816 | case index: \ | ||
817 | ep = UDI_CDC_DATA_EP_IN_##index; \ | ||
818 | break; | ||
819 | MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_IN, ~) | ||
820 | #undef UDI_CDC_PORT_TO_DATA_EP_IN | ||
821 | default: | ||
822 | ep = UDI_CDC_DATA_EP_IN_0; | ||
823 | break; | ||
824 | } | ||
825 | */ | ||
826 | ep = UDI_CDC_DATA_EP_IN_0; | ||
827 | |||
828 | udd_ep_run( ep, | ||
829 | b_short_packet, | ||
830 | udi_cdc_tx_buf[port][buf_sel_trans], | ||
831 | udi_cdc_tx_buf_nb[port][buf_sel_trans], | ||
832 | udi_cdc_data_sent); | ||
833 | } | ||
834 | |||
835 | //--------------------------------------------- | ||
836 | //------- Application interface | ||
837 | |||
838 | void udi_cdc_ctrl_signal_dcd(bool b_set) | ||
839 | { | ||
840 | udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD); | ||
841 | } | ||
842 | |||
843 | void udi_cdc_ctrl_signal_dsr(bool b_set) | ||
844 | { | ||
845 | udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR); | ||
846 | } | ||
847 | |||
848 | void udi_cdc_signal_framing_error(void) | ||
849 | { | ||
850 | udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING); | ||
851 | } | ||
852 | |||
853 | void udi_cdc_signal_parity_error(void) | ||
854 | { | ||
855 | udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY); | ||
856 | } | ||
857 | |||
858 | void udi_cdc_signal_overrun(void) | ||
859 | { | ||
860 | udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN); | ||
861 | } | ||
862 | |||
863 | void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set) | ||
864 | { | ||
865 | udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD); | ||
866 | } | ||
867 | |||
868 | void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set) | ||
869 | { | ||
870 | udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR); | ||
871 | } | ||
872 | |||
873 | void udi_cdc_multi_signal_framing_error(uint8_t port) | ||
874 | { | ||
875 | udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING); | ||
876 | } | ||
877 | |||
878 | void udi_cdc_multi_signal_parity_error(uint8_t port) | ||
879 | { | ||
880 | udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY); | ||
881 | } | ||
882 | |||
883 | void udi_cdc_multi_signal_overrun(uint8_t port) | ||
884 | { | ||
885 | udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN); | ||
886 | } | ||
887 | |||
888 | iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port) | ||
889 | { | ||
890 | uint32_t irqflags; //irqflags_t | ||
891 | uint16_t pos; | ||
892 | iram_size_t nb_received; | ||
893 | |||
894 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
895 | port = 0; | ||
896 | //#endif | ||
897 | |||
898 | irqflags = __get_PRIMASK(); | ||
899 | __disable_irq(); | ||
900 | __DMB(); | ||
901 | pos = udi_cdc_rx_pos[port]; | ||
902 | nb_received = udi_cdc_rx_buf_nb[port][udi_cdc_rx_buf_sel[port]] - pos; | ||
903 | __DMB(); | ||
904 | __set_PRIMASK(irqflags); | ||
905 | return nb_received; | ||
906 | } | ||
907 | |||
908 | iram_size_t udi_cdc_get_nb_received_data(void) | ||
909 | { | ||
910 | return udi_cdc_multi_get_nb_received_data(0); | ||
911 | } | ||
912 | |||
913 | bool udi_cdc_multi_is_rx_ready(uint8_t port) | ||
914 | { | ||
915 | return (udi_cdc_multi_get_nb_received_data(port) > 0); | ||
916 | } | ||
917 | |||
918 | bool udi_cdc_is_rx_ready(void) | ||
919 | { | ||
920 | return udi_cdc_multi_is_rx_ready(0); | ||
921 | } | ||
922 | |||
923 | int udi_cdc_multi_getc(uint8_t port) | ||
924 | { | ||
925 | uint32_t irqflags; //irqflags_t | ||
926 | int rx_data = 0; | ||
927 | bool b_databit_9; | ||
928 | uint16_t pos; | ||
929 | uint8_t buf_sel; | ||
930 | bool again; | ||
931 | |||
932 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
933 | port = 0; | ||
934 | //#endif | ||
935 | |||
936 | b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits); | ||
937 | |||
938 | udi_cdc_getc_process_one_byte: | ||
939 | // Check available data | ||
940 | irqflags = __get_PRIMASK(); | ||
941 | __disable_irq(); | ||
942 | __DMB(); | ||
943 | pos = udi_cdc_rx_pos[port]; | ||
944 | buf_sel = udi_cdc_rx_buf_sel[port]; | ||
945 | again = pos >= udi_cdc_rx_buf_nb[port][buf_sel]; | ||
946 | __DMB(); | ||
947 | __set_PRIMASK(irqflags); | ||
948 | while (again) { | ||
949 | if (!udi_cdc_data_running) { | ||
950 | return 0; | ||
951 | } | ||
952 | goto udi_cdc_getc_process_one_byte; | ||
953 | } | ||
954 | |||
955 | // Read data | ||
956 | rx_data |= udi_cdc_rx_buf[port][buf_sel][pos]; | ||
957 | udi_cdc_rx_pos[port] = pos+1; | ||
958 | |||
959 | udi_cdc_rx_start(port); | ||
960 | |||
961 | if (b_databit_9) { | ||
962 | // Receive MSB | ||
963 | b_databit_9 = false; | ||
964 | rx_data = rx_data << 8; | ||
965 | goto udi_cdc_getc_process_one_byte; | ||
966 | } | ||
967 | return rx_data; | ||
968 | } | ||
969 | |||
970 | int udi_cdc_getc(void) | ||
971 | { | ||
972 | return udi_cdc_multi_getc(0); | ||
973 | } | ||
974 | |||
975 | iram_size_t udi_cdc_multi_read_buf(uint8_t port, void* buf, iram_size_t size) | ||
976 | { | ||
977 | uint32_t irqflags; //irqflags_t | ||
978 | uint8_t *ptr_buf = (uint8_t *)buf; | ||
979 | iram_size_t copy_nb; | ||
980 | uint16_t pos; | ||
981 | uint8_t buf_sel; | ||
982 | bool again; | ||
983 | |||
984 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
985 | port = 0; | ||
986 | //#endif | ||
987 | |||
988 | udi_cdc_read_buf_loop_wait: | ||
989 | // Check available data | ||
990 | irqflags = __get_PRIMASK(); | ||
991 | __disable_irq(); | ||
992 | __DMB(); pos = udi_cdc_rx_pos[port]; | ||
993 | buf_sel = udi_cdc_rx_buf_sel[port]; | ||
994 | again = pos >= udi_cdc_rx_buf_nb[port][buf_sel]; | ||
995 | __DMB(); | ||
996 | __set_PRIMASK(irqflags); | ||
997 | while (again) { | ||
998 | if (!udi_cdc_data_running) { | ||
999 | return size; | ||
1000 | } | ||
1001 | goto udi_cdc_read_buf_loop_wait; | ||
1002 | } | ||
1003 | |||
1004 | // Read data | ||
1005 | copy_nb = udi_cdc_rx_buf_nb[port][buf_sel] - pos; | ||
1006 | if (copy_nb>size) { | ||
1007 | copy_nb = size; | ||
1008 | } | ||
1009 | memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], copy_nb); | ||
1010 | udi_cdc_rx_pos[port] += copy_nb; | ||
1011 | ptr_buf += copy_nb; | ||
1012 | size -= copy_nb; | ||
1013 | udi_cdc_rx_start(port); | ||
1014 | |||
1015 | if (size) { | ||
1016 | goto udi_cdc_read_buf_loop_wait; | ||
1017 | } | ||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static iram_size_t udi_cdc_multi_read_no_polling(uint8_t port, void* buf, iram_size_t size) | ||
1022 | { | ||
1023 | uint8_t *ptr_buf = (uint8_t *)buf; | ||
1024 | iram_size_t nb_avail_data; | ||
1025 | uint16_t pos; | ||
1026 | uint8_t buf_sel; | ||
1027 | uint32_t irqflags; //irqflags_t | ||
1028 | |||
1029 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
1030 | port = 0; | ||
1031 | //#endif | ||
1032 | |||
1033 | //Data interface not started... exit | ||
1034 | if (!udi_cdc_data_running) { | ||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | //Get number of available data | ||
1039 | // Check available data | ||
1040 | irqflags = __get_PRIMASK(); | ||
1041 | __disable_irq(); | ||
1042 | __DMB(); | ||
1043 | pos = udi_cdc_rx_pos[port]; | ||
1044 | buf_sel = udi_cdc_rx_buf_sel[port]; | ||
1045 | nb_avail_data = udi_cdc_rx_buf_nb[port][buf_sel] - pos; | ||
1046 | __DMB(); | ||
1047 | __set_PRIMASK(irqflags); | ||
1048 | //If the buffer contains less than the requested number of data, | ||
1049 | //adjust read size | ||
1050 | if(nb_avail_data<size) { | ||
1051 | size = nb_avail_data; | ||
1052 | } | ||
1053 | if(size>0) { | ||
1054 | memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], size); | ||
1055 | irqflags = __get_PRIMASK(); | ||
1056 | __disable_irq(); | ||
1057 | __DMB(); | ||
1058 | udi_cdc_rx_pos[port] += size; | ||
1059 | __DMB(); | ||
1060 | __set_PRIMASK(irqflags); | ||
1061 | ptr_buf += size; | ||
1062 | udi_cdc_rx_start(port); | ||
1063 | } | ||
1064 | return(nb_avail_data); | ||
1065 | } | ||
1066 | |||
1067 | iram_size_t udi_cdc_read_no_polling(void* buf, iram_size_t size) | ||
1068 | { | ||
1069 | return udi_cdc_multi_read_no_polling(0, buf, size); | ||
1070 | } | ||
1071 | |||
1072 | iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size) | ||
1073 | { | ||
1074 | return udi_cdc_multi_read_buf(0, buf, size); | ||
1075 | } | ||
1076 | |||
1077 | iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port) | ||
1078 | { | ||
1079 | uint32_t irqflags; //irqflags_t | ||
1080 | iram_size_t buf_sel_nb, retval; | ||
1081 | uint8_t buf_sel; | ||
1082 | |||
1083 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
1084 | port = 0; | ||
1085 | //#endif | ||
1086 | |||
1087 | irqflags = __get_PRIMASK(); | ||
1088 | __disable_irq(); | ||
1089 | __DMB(); | ||
1090 | buf_sel = udi_cdc_tx_buf_sel[port]; | ||
1091 | buf_sel_nb = udi_cdc_tx_buf_nb[port][buf_sel]; | ||
1092 | if (buf_sel_nb == UDI_CDC_TX_BUFFERS) { | ||
1093 | if ((!udi_cdc_tx_trans_ongoing[port]) | ||
1094 | && (!udi_cdc_tx_both_buf_to_send[port])) { | ||
1095 | /* One buffer is full, but the other buffer is not used. | ||
1096 | * (not used = transfer on-going) | ||
1097 | * then move to the other buffer to store data */ | ||
1098 | udi_cdc_tx_both_buf_to_send[port] = true; | ||
1099 | udi_cdc_tx_buf_sel[port] = (buf_sel == 0)? 1 : 0; | ||
1100 | buf_sel_nb = 0; | ||
1101 | } | ||
1102 | } | ||
1103 | retval = UDI_CDC_TX_BUFFERS - buf_sel_nb; | ||
1104 | __DMB(); | ||
1105 | __set_PRIMASK(irqflags); | ||
1106 | return retval; | ||
1107 | } | ||
1108 | |||
1109 | iram_size_t udi_cdc_get_free_tx_buffer(void) | ||
1110 | { | ||
1111 | return udi_cdc_multi_get_free_tx_buffer(0); | ||
1112 | } | ||
1113 | |||
1114 | bool udi_cdc_multi_is_tx_ready(uint8_t port) | ||
1115 | { | ||
1116 | return (udi_cdc_multi_get_free_tx_buffer(port) != 0); | ||
1117 | } | ||
1118 | |||
1119 | bool udi_cdc_is_tx_ready(void) | ||
1120 | { | ||
1121 | return udi_cdc_multi_is_tx_ready(0); | ||
1122 | } | ||
1123 | |||
1124 | int udi_cdc_multi_putc(uint8_t port, int value) | ||
1125 | { | ||
1126 | uint32_t irqflags; //irqflags_t | ||
1127 | bool b_databit_9; | ||
1128 | uint8_t buf_sel; | ||
1129 | |||
1130 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
1131 | port = 0; | ||
1132 | //#endif | ||
1133 | |||
1134 | b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits); | ||
1135 | |||
1136 | udi_cdc_putc_process_one_byte: | ||
1137 | // Check available space | ||
1138 | if (!udi_cdc_multi_is_tx_ready(port)) { | ||
1139 | if (!udi_cdc_data_running) { | ||
1140 | return false; | ||
1141 | } | ||
1142 | goto udi_cdc_putc_process_one_byte; | ||
1143 | } | ||
1144 | |||
1145 | // Write value | ||
1146 | irqflags = __get_PRIMASK(); | ||
1147 | __disable_irq(); | ||
1148 | __DMB(); | ||
1149 | buf_sel = udi_cdc_tx_buf_sel[port]; | ||
1150 | udi_cdc_tx_buf[port][buf_sel][udi_cdc_tx_buf_nb[port][buf_sel]++] = value; | ||
1151 | __DMB(); | ||
1152 | __set_PRIMASK(irqflags); | ||
1153 | |||
1154 | if (b_databit_9) { | ||
1155 | // Send MSB | ||
1156 | b_databit_9 = false; | ||
1157 | value = value >> 8; | ||
1158 | goto udi_cdc_putc_process_one_byte; | ||
1159 | } | ||
1160 | return true; | ||
1161 | } | ||
1162 | |||
1163 | int udi_cdc_putc(int value) | ||
1164 | { | ||
1165 | return udi_cdc_multi_putc(0, value); | ||
1166 | } | ||
1167 | |||
1168 | iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size) | ||
1169 | { | ||
1170 | uint32_t irqflags; //irqflags_t | ||
1171 | uint8_t buf_sel; | ||
1172 | uint16_t buf_nb; | ||
1173 | iram_size_t copy_nb; | ||
1174 | uint8_t *ptr_buf = (uint8_t *)buf; | ||
1175 | |||
1176 | //#if UDI_CDC_PORT_NB == 1 // To optimize code | ||
1177 | port = 0; | ||
1178 | //#endif | ||
1179 | |||
1180 | if (9 == udi_cdc_line_coding[port].bDataBits) { | ||
1181 | size *=2; | ||
1182 | } | ||
1183 | |||
1184 | udi_cdc_write_buf_loop_wait: | ||
1185 | |||
1186 | // Check available space | ||
1187 | if (!udi_cdc_multi_is_tx_ready(port)) { | ||
1188 | if (!udi_cdc_data_running) { | ||
1189 | return size; | ||
1190 | } | ||
1191 | goto udi_cdc_write_buf_loop_wait; | ||
1192 | } | ||
1193 | |||
1194 | // Write values | ||
1195 | irqflags = __get_PRIMASK(); | ||
1196 | __disable_irq(); | ||
1197 | __DMB(); | ||
1198 | buf_sel = udi_cdc_tx_buf_sel[port]; | ||
1199 | buf_nb = udi_cdc_tx_buf_nb[port][buf_sel]; | ||
1200 | copy_nb = UDI_CDC_TX_BUFFERS - buf_nb; | ||
1201 | if (copy_nb > size) { | ||
1202 | copy_nb = size; | ||
1203 | } | ||
1204 | memcpy(&udi_cdc_tx_buf[port][buf_sel][buf_nb], ptr_buf, copy_nb); | ||
1205 | udi_cdc_tx_buf_nb[port][buf_sel] = buf_nb + copy_nb; | ||
1206 | __DMB(); | ||
1207 | __set_PRIMASK(irqflags); | ||
1208 | |||
1209 | // Update buffer pointer | ||
1210 | ptr_buf = ptr_buf + copy_nb; | ||
1211 | size -= copy_nb; | ||
1212 | |||
1213 | if (size) { | ||
1214 | goto udi_cdc_write_buf_loop_wait; | ||
1215 | } | ||
1216 | |||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | iram_size_t udi_cdc_write_buf(const void* buf, iram_size_t size) | ||
1221 | { | ||
1222 | return udi_cdc_multi_write_buf(0, buf, size); | ||
1223 | } | ||
1224 | |||
1225 | #define MAX_PRINT 256 | ||
1226 | #define CDC_SEND_INTERVAL 2 | ||
1227 | uint32_t cdc_tx_send_time_next; | ||
1228 | |||
1229 | void CDC_send(void) | ||
1230 | { | ||
1231 | while (CLK_get_ms() < cdc_tx_send_time_next); | ||
1232 | udi_cdc_tx_send(0); | ||
1233 | cdc_tx_send_time_next = CLK_get_ms() + CDC_SEND_INTERVAL; | ||
1234 | } | ||
1235 | |||
1236 | uint32_t CDC_print(char *printbuf) | ||
1237 | { | ||
1238 | uint32_t count=0; | ||
1239 | char *buf = printbuf; | ||
1240 | char c; | ||
1241 | |||
1242 | if (CLK_get_ms() < 5000) return 0; | ||
1243 | |||
1244 | while ((c = *buf++) != 0 && !(count >= MAX_PRINT)) | ||
1245 | { | ||
1246 | count++; | ||
1247 | if (!udi_cdc_is_tx_ready()) return 0; | ||
1248 | udi_cdc_putc(c); | ||
1249 | if (count >= UDI_CDC_TX_BUFFERS) | ||
1250 | { | ||
1251 | count = 0; | ||
1252 | CDC_send(); | ||
1253 | } | ||
1254 | } | ||
1255 | if (count) | ||
1256 | { | ||
1257 | CDC_send(); | ||
1258 | } | ||
1259 | return 1; | ||
1260 | } | ||
1261 | |||
1262 | |||
1263 | char printbuf[CDC_PRINTBUF_SIZE]; | ||
1264 | |||
1265 | int dpf(const char *_Format, ...) | ||
1266 | { | ||
1267 | va_list va; //Variable argument list variable | ||
1268 | int result; | ||
1269 | |||
1270 | va_start(va,_Format); //Initialize the variable argument list | ||
1271 | result = vspf(printbuf, _Format, va); | ||
1272 | va_end(va); | ||
1273 | |||
1274 | CDC_print(printbuf); | ||
1275 | |||
1276 | return result; | ||
1277 | } | ||
1278 | |||
1279 | //global "inbuf" if desired | ||
1280 | inbuf_t inbuf; | ||
1281 | |||
1282 | uint32_t CDC_input_buf(inbuf_t inbuf, uint32_t inbuf_size) | ||
1283 | { | ||
1284 | int RXChar; | ||
1285 | int entered = 0; | ||
1286 | |||
1287 | if (!udi_cdc_is_rx_ready()) return 0; | ||
1288 | udi_cdc_get_nb_received_data(); | ||
1289 | RXChar = udi_cdc_getc(); | ||
1290 | |||
1291 | if (RXChar) | ||
1292 | { | ||
1293 | switch (RXChar) | ||
1294 | { | ||
1295 | case '\t': //tab - repeat last | ||
1296 | inbuf.count=inbuf.lastcount; | ||
1297 | inbuf.buf[inbuf.count+1] = 0; | ||
1298 | CDC_print(inbuf.buf); | ||
1299 | break; | ||
1300 | case '\r': //enter | ||
1301 | inbuf.buf[inbuf.count]=0; | ||
1302 | inbuf.lastcount = inbuf.count; | ||
1303 | inbuf.count = 0; | ||
1304 | entered = 1; | ||
1305 | break; | ||
1306 | case '\b': //backspace | ||
1307 | if (inbuf.count > 0) { | ||
1308 | inbuf.count -= 1; | ||
1309 | CDC_print("\b \b\0"); | ||
1310 | } | ||
1311 | else | ||
1312 | CDC_print("\a\0"); | ||
1313 | break; | ||
1314 | default: | ||
1315 | if ((RXChar >= 32) && (RXChar <= 126)) | ||
1316 | { | ||
1317 | if (inbuf.count < inbuf_size-1) | ||
1318 | { | ||
1319 | inbuf.buf[inbuf.count] = RXChar; | ||
1320 | inbuf.buf[inbuf.count+1] = 0; | ||
1321 | CDC_print(&inbuf.buf[inbuf.count]); | ||
1322 | inbuf.count += 1; | ||
1323 | } | ||
1324 | else | ||
1325 | CDC_print("\a\0"); | ||
1326 | } | ||
1327 | break; | ||
1328 | } | ||
1329 | RXChar = 0; | ||
1330 | } | ||
1331 | return entered; | ||
1332 | } | ||
1333 | |||
1334 | uint32_t CDC_input() | ||
1335 | { | ||
1336 | return CDC_input_buf(inbuf, CDC_INBUF_SIZE); | ||
1337 | } | ||
1338 | |||
1339 | void CDC_init(void) | ||
1340 | { | ||
1341 | inbuf.count = 0; | ||
1342 | inbuf.lastcount = 0; | ||
1343 | printbuf[0] = 0; | ||
1344 | cdc_tx_send_time_next = CLK_get_ms() + CDC_SEND_INTERVAL; | ||
1345 | } | ||
1346 | |||
1347 | #else //CDC line 62 | ||
1348 | |||
1349 | char printbuf[CDC_PRINTBUF_SIZE]; | ||
1350 | |||
1351 | void CDC_send(void) | ||
1352 | { | ||
1353 | return; | ||
1354 | } | ||
1355 | |||
1356 | uint32_t CDC_print(char *printbuf) | ||
1357 | { | ||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | int dpf(const char *_Format, ...) | ||
1362 | { | ||
1363 | return 0; | ||
1364 | } | ||
1365 | |||
1366 | inbuf_t inbuf; | ||
1367 | |||
1368 | uint32_t CDC_input(void) | ||
1369 | { | ||
1370 | return 0; | ||
1371 | } | ||
1372 | |||
1373 | void CDC_init(void) | ||
1374 | { | ||
1375 | inbuf.count = 0; | ||
1376 | inbuf.lastcount = 0; | ||
1377 | printbuf[0]=0; | ||
1378 | } | ||
1379 | |||
1380 | char printbuf[CDC_PRINTBUF_SIZE]; | ||
1381 | |||
1382 | #endif //CDC line 62 | ||
1383 | |||
1384 | //@} | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_cdc.h b/tmk_core/protocol/arm_atsam/usb/udi_cdc.h new file mode 100644 index 000000000..6b70e96d0 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_cdc.h | |||
@@ -0,0 +1,381 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device Communication Device Class (CDC) interface definitions. | ||
5 | * | ||
6 | * Copyright (c) 2009-2016 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDI_CDC_H_ | ||
48 | #define _UDI_CDC_H_ | ||
49 | |||
50 | #ifdef CDC | ||
51 | |||
52 | #include "conf_usb.h" | ||
53 | #include "usb_protocol.h" | ||
54 | #include "usb_protocol_cdc.h" | ||
55 | #include "udd.h" | ||
56 | #include "udc_desc.h" | ||
57 | #include "udi.h" | ||
58 | |||
59 | // Check the number of port | ||
60 | #ifndef UDI_CDC_PORT_NB | ||
61 | # define UDI_CDC_PORT_NB 1 | ||
62 | #endif | ||
63 | #if (UDI_CDC_PORT_NB > 1) | ||
64 | # error UDI_CDC_PORT_NB must be at most 1 | ||
65 | #endif | ||
66 | |||
67 | #ifdef __cplusplus | ||
68 | extern "C" { | ||
69 | #endif | ||
70 | |||
71 | /** | ||
72 | * \addtogroup udi_cdc_group_udc | ||
73 | * @{ | ||
74 | */ | ||
75 | |||
76 | //! Global structure which contains standard UDI API for UDC | ||
77 | extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm; | ||
78 | extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_data; | ||
79 | //@} | ||
80 | |||
81 | //#define CDC_ACM_SIZE 64 see usb_protocol_cdc.h | ||
82 | //#define CDC_RX_SIZE 64 | ||
83 | |||
84 | //! CDC communication endpoints size for all speeds | ||
85 | #define UDI_CDC_COMM_EP_SIZE CDC_ACM_SIZE | ||
86 | //! CDC data endpoints size for FS speed (8B, 16B, 32B, 64B) | ||
87 | #define UDI_CDC_DATA_EPS_FS_SIZE CDC_RX_SIZE | ||
88 | |||
89 | #define CDC_PRINT_BUF_SIZE 256 | ||
90 | extern char printbuf[CDC_PRINT_BUF_SIZE]; | ||
91 | |||
92 | //@} | ||
93 | |||
94 | /** | ||
95 | * \ingroup udi_group | ||
96 | * \defgroup udi_cdc_group USB Device Interface (UDI) for Communication Class Device (CDC) | ||
97 | * | ||
98 | * Common APIs used by high level application to use this USB class. | ||
99 | * | ||
100 | * These routines are used to transfer and control data | ||
101 | * to/from USB CDC endpoint. | ||
102 | * | ||
103 | * See \ref udi_cdc_quickstart. | ||
104 | * @{ | ||
105 | */ | ||
106 | |||
107 | /** | ||
108 | * \name Interface for application with single CDC interface support | ||
109 | */ | ||
110 | //@{ | ||
111 | |||
112 | /** | ||
113 | * \brief Notify a state change of DCD signal | ||
114 | * | ||
115 | * \param b_set DCD is enabled if true, else disabled | ||
116 | */ | ||
117 | void udi_cdc_ctrl_signal_dcd(bool b_set); | ||
118 | |||
119 | /** | ||
120 | * \brief Notify a state change of DSR signal | ||
121 | * | ||
122 | * \param b_set DSR is enabled if true, else disabled | ||
123 | */ | ||
124 | void udi_cdc_ctrl_signal_dsr(bool b_set); | ||
125 | |||
126 | /** | ||
127 | * \brief Notify a framing error | ||
128 | */ | ||
129 | void udi_cdc_signal_framing_error(void); | ||
130 | |||
131 | /** | ||
132 | * \brief Notify a parity error | ||
133 | */ | ||
134 | void udi_cdc_signal_parity_error(void); | ||
135 | |||
136 | /** | ||
137 | * \brief Notify a overrun | ||
138 | */ | ||
139 | void udi_cdc_signal_overrun(void); | ||
140 | |||
141 | /** | ||
142 | * \brief Gets the number of byte received | ||
143 | * | ||
144 | * \return the number of data available | ||
145 | */ | ||
146 | iram_size_t udi_cdc_get_nb_received_data(void); | ||
147 | |||
148 | /** | ||
149 | * \brief This function checks if a character has been received on the CDC line | ||
150 | * | ||
151 | * \return \c 1 if a byte is ready to be read. | ||
152 | */ | ||
153 | bool udi_cdc_is_rx_ready(void); | ||
154 | |||
155 | /** | ||
156 | * \brief Waits and gets a value on CDC line | ||
157 | * | ||
158 | * \return value read on CDC line | ||
159 | */ | ||
160 | int udi_cdc_getc(void); | ||
161 | |||
162 | /** | ||
163 | * \brief Reads a RAM buffer on CDC line | ||
164 | * | ||
165 | * \param buf Values read | ||
166 | * \param size Number of value read | ||
167 | * | ||
168 | * \return the number of data remaining | ||
169 | */ | ||
170 | iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size); | ||
171 | |||
172 | /** | ||
173 | * \brief Non polling reads of a up to 'size' data from CDC line | ||
174 | * | ||
175 | * \param port Communication port number to manage | ||
176 | * \param buf Buffer where to store read data | ||
177 | * \param size Maximum number of data to read (size of buffer) | ||
178 | * | ||
179 | * \return the number of data effectively read | ||
180 | */ | ||
181 | iram_size_t udi_cdc_read_no_polling(void* buf, iram_size_t size); | ||
182 | |||
183 | /** | ||
184 | * \brief Gets the number of free byte in TX buffer | ||
185 | * | ||
186 | * \return the number of free byte in TX buffer | ||
187 | */ | ||
188 | iram_size_t udi_cdc_get_free_tx_buffer(void); | ||
189 | |||
190 | /** | ||
191 | * \brief This function checks if a new character sent is possible | ||
192 | * The type int is used to support scanf redirection from compiler LIB. | ||
193 | * | ||
194 | * \return \c 1 if a new character can be sent | ||
195 | */ | ||
196 | bool udi_cdc_is_tx_ready(void); | ||
197 | |||
198 | /** | ||
199 | * \brief Puts a byte on CDC line | ||
200 | * The type int is used to support printf redirection from compiler LIB. | ||
201 | * | ||
202 | * \param value Value to put | ||
203 | * | ||
204 | * \return \c 1 if function was successfully done, otherwise \c 0. | ||
205 | */ | ||
206 | int udi_cdc_putc(int value); | ||
207 | |||
208 | /** | ||
209 | * \brief Writes a RAM buffer on CDC line | ||
210 | * | ||
211 | * \param buf Values to write | ||
212 | * \param size Number of value to write | ||
213 | * | ||
214 | * \return the number of data remaining | ||
215 | */ | ||
216 | iram_size_t udi_cdc_write_buf(const void* buf, iram_size_t size); | ||
217 | //@} | ||
218 | |||
219 | /** | ||
220 | * \name Interface for application with multi CDC interfaces support | ||
221 | */ | ||
222 | //@{ | ||
223 | |||
224 | /** | ||
225 | * \brief Notify a state change of DCD signal | ||
226 | * | ||
227 | * \param port Communication port number to manage | ||
228 | * \param b_set DCD is enabled if true, else disabled | ||
229 | */ | ||
230 | void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set); | ||
231 | |||
232 | /** | ||
233 | * \brief Notify a state change of DSR signal | ||
234 | * | ||
235 | * \param port Communication port number to manage | ||
236 | * \param b_set DSR is enabled if true, else disabled | ||
237 | */ | ||
238 | void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set); | ||
239 | |||
240 | /** | ||
241 | * \brief Notify a framing error | ||
242 | * | ||
243 | * \param port Communication port number to manage | ||
244 | */ | ||
245 | void udi_cdc_multi_signal_framing_error(uint8_t port); | ||
246 | |||
247 | /** | ||
248 | * \brief Notify a parity error | ||
249 | * | ||
250 | * \param port Communication port number to manage | ||
251 | */ | ||
252 | void udi_cdc_multi_signal_parity_error(uint8_t port); | ||
253 | |||
254 | /** | ||
255 | * \brief Notify a overrun | ||
256 | * | ||
257 | * \param port Communication port number to manage | ||
258 | */ | ||
259 | void udi_cdc_multi_signal_overrun(uint8_t port); | ||
260 | |||
261 | /** | ||
262 | * \brief Gets the number of byte received | ||
263 | * | ||
264 | * \param port Communication port number to manage | ||
265 | * | ||
266 | * \return the number of data available | ||
267 | */ | ||
268 | iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port); | ||
269 | |||
270 | /** | ||
271 | * \brief This function checks if a character has been received on the CDC line | ||
272 | * | ||
273 | * \param port Communication port number to manage | ||
274 | * | ||
275 | * \return \c 1 if a byte is ready to be read. | ||
276 | */ | ||
277 | bool udi_cdc_multi_is_rx_ready(uint8_t port); | ||
278 | |||
279 | /** | ||
280 | * \brief Waits and gets a value on CDC line | ||
281 | * | ||
282 | * \param port Communication port number to manage | ||
283 | * | ||
284 | * \return value read on CDC line | ||
285 | */ | ||
286 | int udi_cdc_multi_getc(uint8_t port); | ||
287 | |||
288 | /** | ||
289 | * \brief Reads a RAM buffer on CDC line | ||
290 | * | ||
291 | * \param port Communication port number to manage | ||
292 | * \param buf Values read | ||
293 | * \param size Number of values read | ||
294 | * | ||
295 | * \return the number of data remaining | ||
296 | */ | ||
297 | iram_size_t udi_cdc_multi_read_buf(uint8_t port, void* buf, iram_size_t size); | ||
298 | |||
299 | /** | ||
300 | * \brief Gets the number of free byte in TX buffer | ||
301 | * | ||
302 | * \param port Communication port number to manage | ||
303 | * | ||
304 | * \return the number of free byte in TX buffer | ||
305 | */ | ||
306 | iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port); | ||
307 | |||
308 | /** | ||
309 | * \brief This function checks if a new character sent is possible | ||
310 | * The type int is used to support scanf redirection from compiler LIB. | ||
311 | * | ||
312 | * \param port Communication port number to manage | ||
313 | * | ||
314 | * \return \c 1 if a new character can be sent | ||
315 | */ | ||
316 | bool udi_cdc_multi_is_tx_ready(uint8_t port); | ||
317 | |||
318 | /** | ||
319 | * \brief Puts a byte on CDC line | ||
320 | * The type int is used to support printf redirection from compiler LIB. | ||
321 | * | ||
322 | * \param port Communication port number to manage | ||
323 | * \param value Value to put | ||
324 | * | ||
325 | * \return \c 1 if function was successfully done, otherwise \c 0. | ||
326 | */ | ||
327 | int udi_cdc_multi_putc(uint8_t port, int value); | ||
328 | |||
329 | /** | ||
330 | * \brief Writes a RAM buffer on CDC line | ||
331 | * | ||
332 | * \param port Communication port number to manage | ||
333 | * \param buf Values to write | ||
334 | * \param size Number of value to write | ||
335 | * | ||
336 | * \return the number of data remaining | ||
337 | */ | ||
338 | iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size); | ||
339 | //@} | ||
340 | |||
341 | #define CDC_PRINTBUF_SIZE 256 | ||
342 | extern char printbuf[CDC_PRINTBUF_SIZE]; | ||
343 | |||
344 | #define CDC_INBUF_SIZE 256 | ||
345 | |||
346 | typedef struct { | ||
347 | uint32_t count; | ||
348 | uint32_t lastcount; | ||
349 | char buf[CDC_INBUF_SIZE]; | ||
350 | } inbuf_t; | ||
351 | |||
352 | #else //CDC | ||
353 | |||
354 | // keep these to accommodate calls if remaining | ||
355 | #define CDC_PRINTBUF_SIZE 1 | ||
356 | extern char printbuf[CDC_PRINTBUF_SIZE]; | ||
357 | |||
358 | #define CDC_INBUF_SIZE 1 | ||
359 | |||
360 | typedef struct { | ||
361 | uint32_t count; | ||
362 | uint32_t lastcount; | ||
363 | char buf[CDC_INBUF_SIZE]; | ||
364 | } inbuf_t; | ||
365 | |||
366 | extern inbuf_t inbuf; | ||
367 | |||
368 | #endif //CDC | ||
369 | |||
370 | uint32_t CDC_print(char *printbuf); | ||
371 | uint32_t CDC_input(void); | ||
372 | void CDC_init(void); | ||
373 | |||
374 | #define __xprintf dpf | ||
375 | int dpf(const char *_Format, ...); | ||
376 | |||
377 | #ifdef __cplusplus | ||
378 | } | ||
379 | #endif | ||
380 | |||
381 | #endif // _UDI_CDC_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h b/tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h new file mode 100644 index 000000000..2db61fab5 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Default CDC configuration for a USB Device with a single interface | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDI_CDC_CONF_H_ | ||
48 | #define _UDI_CDC_CONF_H_ | ||
49 | |||
50 | #include "usb_protocol_cdc.h" | ||
51 | #include "conf_usb.h" | ||
52 | #include "udi_device_conf.h" | ||
53 | |||
54 | #ifndef UDI_CDC_PORT_NB | ||
55 | #define UDI_CDC_PORT_NB 1 | ||
56 | #endif | ||
57 | |||
58 | #ifdef __cplusplus | ||
59 | extern "C" { | ||
60 | #endif | ||
61 | |||
62 | #define UDI_CDC_DATA_EP_IN_0 ((CDC_TX_ENDPOINT) | (USB_EP_DIR_IN)) //TX | ||
63 | #define UDI_CDC_DATA_EP_OUT_0 ((CDC_RX_ENDPOINT) | (USB_EP_DIR_OUT)) // RX | ||
64 | #define UDI_CDC_COMM_EP_0 ((CDC_ACM_ENDPOINT) | (USB_EP_DIR_IN)) // Notify endpoint | ||
65 | |||
66 | #define UDI_CDC_COMM_IFACE_NUMBER_0 (CDC_STATUS_INTERFACE) | ||
67 | #define UDI_CDC_DATA_IFACE_NUMBER_0 (CDC_DATA_INTERFACE) | ||
68 | |||
69 | #ifdef __cplusplus | ||
70 | } | ||
71 | #endif | ||
72 | #endif // _UDI_CDC_CONF_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h b/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h new file mode 100644 index 000000000..c78726234 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h | |||
@@ -0,0 +1,715 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _UDI_DEVICE_CONF_H_ | ||
19 | #define _UDI_DEVICE_CONF_H_ | ||
20 | |||
21 | #include "udi_device_epsize.h" | ||
22 | #include "usb_protocol.h" | ||
23 | #include "compiler.h" | ||
24 | #include "usb_protocol_hid.h" | ||
25 | |||
26 | #define DEVICE_CLASS 0 | ||
27 | #define DEVICE_SUBCLASS 0 | ||
28 | #define DEVICE_PROTOCOL 0 | ||
29 | |||
30 | #define KBD | ||
31 | |||
32 | //#define MOUSE_ENABLE //rules.mk | ||
33 | #ifdef MOUSE_ENABLE | ||
34 | #define MOU | ||
35 | #endif | ||
36 | |||
37 | //#define EXTRAKEY_ENABLE //rules.mk | ||
38 | #ifdef EXTRAKEY_ENABLE | ||
39 | #define EXK | ||
40 | #endif | ||
41 | |||
42 | //#define RAW_ENABLE //rules.mk | ||
43 | #ifdef RAW_ENABLE | ||
44 | #define RAW | ||
45 | #endif | ||
46 | |||
47 | //#define CONSOLE_ENABLE //deferred implementation | ||
48 | //#ifdef CONSOLE_ENABLE | ||
49 | //#define CON | ||
50 | //#endif | ||
51 | |||
52 | //#define NKRO_ENABLE //rules.mk | ||
53 | #ifdef NKRO_ENABLE | ||
54 | #define NKRO | ||
55 | #endif | ||
56 | |||
57 | //#define MIDI_ENABLE //deferred implementation | ||
58 | //#ifdef MIDI_ENABLE | ||
59 | //#define MIDI | ||
60 | //#endif | ||
61 | |||
62 | //#define VIRTSER_ENABLE //rules.mk | ||
63 | #ifdef VIRTSER_ENABLE | ||
64 | #define CDC | ||
65 | //because CDC uses IAD (interface association descriptor | ||
66 | //per USB Interface Association Descriptor Device Class Code and Use Model 7/23/2003 Rev 1.0) | ||
67 | #undef DEVICE_CLASS | ||
68 | #define DEVICE_CLASS 0xEF | ||
69 | #undef DEVICE_SUBCLASS | ||
70 | #define DEVICE_SUBCLASS 0x02 | ||
71 | #undef DEVICE_PROTOCOL | ||
72 | #define DEVICE_PROTOCOL 0x01 | ||
73 | #endif | ||
74 | |||
75 | /* number of interfaces */ | ||
76 | #define NEXT_INTERFACE_0 0 | ||
77 | |||
78 | #ifdef KBD | ||
79 | #define KEYBOARD_INTERFACE NEXT_INTERFACE_0 | ||
80 | #define NEXT_INTERFACE_1 (KEYBOARD_INTERFACE + 1) | ||
81 | #define UDI_HID_KBD_IFACE_NUMBER KEYBOARD_INTERFACE | ||
82 | #else | ||
83 | #define NEXT_INTERFACE_1 NEXT_INTERFACE_0 | ||
84 | #endif | ||
85 | |||
86 | // It is important that the Raw HID interface is at a constant | ||
87 | // interface number, to support Linux/OSX platforms and chrome.hid | ||
88 | // If Raw HID is enabled, let it be always 1. | ||
89 | #ifdef RAW | ||
90 | #define RAW_INTERFACE NEXT_INTERFACE_1 | ||
91 | #define NEXT_INTERFACE_2 (RAW_INTERFACE + 1) | ||
92 | #else | ||
93 | #define NEXT_INTERFACE_2 NEXT_INTERFACE_1 | ||
94 | #endif | ||
95 | |||
96 | #ifdef MOU | ||
97 | #define MOUSE_INTERFACE NEXT_INTERFACE_2 | ||
98 | #define UDI_HID_MOU_IFACE_NUMBER MOUSE_INTERFACE | ||
99 | #define NEXT_INTERFACE_3 (MOUSE_INTERFACE + 1) | ||
100 | #else | ||
101 | #define NEXT_INTERFACE_3 NEXT_INTERFACE_2 | ||
102 | #endif | ||
103 | |||
104 | #ifdef EXK | ||
105 | #define EXTRAKEY_INTERFACE NEXT_INTERFACE_3 | ||
106 | #define NEXT_INTERFACE_4 (EXTRAKEY_INTERFACE + 1) | ||
107 | #define UDI_HID_EXK_IFACE_NUMBER EXTRAKEY_INTERFACE | ||
108 | #else | ||
109 | #define NEXT_INTERFACE_4 NEXT_INTERFACE_3 | ||
110 | #endif | ||
111 | |||
112 | #ifdef CON | ||
113 | #define CONSOLE_INTERFACE NEXT_INTERFACE_4 | ||
114 | #define NEXT_INTERFACE_5 (CONSOLE_INTERFACE + 1) | ||
115 | #else | ||
116 | #define NEXT_INTERFACE_5 NEXT_INTERFACE_4 | ||
117 | #endif | ||
118 | |||
119 | #ifdef NKRO | ||
120 | #define NKRO_INTERFACE NEXT_INTERFACE_5 | ||
121 | #define NEXT_INTERFACE_6 (NKRO_INTERFACE + 1) | ||
122 | #define UDI_HID_NKRO_IFACE_NUMBER NKRO_INTERFACE | ||
123 | #else | ||
124 | #define NEXT_INTERFACE_6 NEXT_INTERFACE_5 | ||
125 | #endif | ||
126 | |||
127 | #ifdef MIDI | ||
128 | #define AC_INTERFACE NEXT_INTERFACE_6 | ||
129 | #define AS_INTERFACE (AC_INTERFACE + 1) | ||
130 | #define NEXT_INTERFACE_7 (AS_INTERFACE + 1) | ||
131 | #else | ||
132 | #define NEXT_INTERFACE_7 NEXT_INTERFACE_6 | ||
133 | #endif | ||
134 | |||
135 | #ifdef CDC | ||
136 | #define CCI_INTERFACE NEXT_INTERFACE_7 | ||
137 | #define CDI_INTERFACE (CCI_INTERFACE + 1) | ||
138 | #define NEXT_INTERFACE_8 (CDI_INTERFACE + 1) | ||
139 | #define CDC_STATUS_INTERFACE CCI_INTERFACE | ||
140 | #define CDC_DATA_INTERFACE CDI_INTERFACE | ||
141 | #else | ||
142 | #define NEXT_INTERFACE_8 NEXT_INTERFACE_7 | ||
143 | #endif | ||
144 | |||
145 | /* nubmer of interfaces */ | ||
146 | #define TOTAL_INTERFACES NEXT_INTERFACE_8 | ||
147 | #define USB_DEVICE_NB_INTERFACE TOTAL_INTERFACES | ||
148 | |||
149 | |||
150 | // ********************************************************************** | ||
151 | // Endopoint number and size | ||
152 | // ********************************************************************** | ||
153 | #define USB_DEVICE_EP_CTRL_SIZE 8 | ||
154 | |||
155 | #define NEXT_IN_EPNUM_0 1 | ||
156 | #define NEXT_OUT_EPNUM_0 1 | ||
157 | |||
158 | #ifdef KBD | ||
159 | #define KEYBOARD_IN_EPNUM NEXT_IN_EPNUM_0 | ||
160 | #define UDI_HID_KBD_EP_IN KEYBOARD_IN_EPNUM | ||
161 | #define NEXT_IN_EPNUM_1 (KEYBOARD_IN_EPNUM + 1) | ||
162 | #define UDI_HID_KBD_EP_SIZE KEYBOARD_EPSIZE | ||
163 | #define KBD_POLLING_INTERVAL 10 | ||
164 | #ifndef UDI_HID_KBD_STRING_ID | ||
165 | #define UDI_HID_KBD_STRING_ID 0 | ||
166 | #endif | ||
167 | #else | ||
168 | #define NEXT_IN_EPNUM_1 NEXT_IN_EPNUM_0 | ||
169 | #endif | ||
170 | |||
171 | #ifdef MOU | ||
172 | #define MOUSE_IN_EPNUM NEXT_IN_EPNUM_1 | ||
173 | #define NEXT_IN_EPNUM_2 (MOUSE_IN_EPNUM + 1) | ||
174 | #define UDI_HID_MOU_EP_IN MOUSE_IN_EPNUM | ||
175 | #define UDI_HID_MOU_EP_SIZE MOUSE_EPSIZE | ||
176 | #define MOU_POLLING_INTERVAL 10 | ||
177 | #ifndef UDI_HID_MOU_STRING_ID | ||
178 | #define UDI_HID_MOU_STRING_ID 0 | ||
179 | #endif | ||
180 | #else | ||
181 | #define NEXT_IN_EPNUM_2 NEXT_IN_EPNUM_1 | ||
182 | #endif | ||
183 | |||
184 | #ifdef EXK | ||
185 | #define EXTRAKEY_IN_EPNUM NEXT_IN_EPNUM_2 | ||
186 | #define UDI_HID_EXK_EP_IN EXTRAKEY_IN_EPNUM | ||
187 | #define NEXT_IN_EPNUM_3 (EXTRAKEY_IN_EPNUM + 1) | ||
188 | #define UDI_HID_EXK_EP_SIZE EXTRAKEY_EPSIZE | ||
189 | #define EXTRAKEY_POLLING_INTERVAL 10 | ||
190 | #ifndef UDI_HID_EXK_STRING_ID | ||
191 | #define UDI_HID_EXK_STRING_ID 0 | ||
192 | #endif | ||
193 | #else | ||
194 | #define NEXT_IN_EPNUM_3 NEXT_IN_EPNUM_2 | ||
195 | #endif | ||
196 | |||
197 | #ifdef RAW | ||
198 | #define RAW_IN_EPNUM NEXT_IN_EPNUM_3 | ||
199 | #define UDI_HID_RAW_EP_IN RAW_IN_EPNUM | ||
200 | #define NEXT_IN_EPNUM_4 (RAW_IN_EPNUM + 1) | ||
201 | #define RAW_OUT_EPNUM NEXT_OUT_EPNUM_0 | ||
202 | #define UDI_HID_RAW_EP_OUT RAW_OUT_EPNUM | ||
203 | #define NEXT_OUT_EPNUM_1 (RAW_OUT_EPNUM + 1) | ||
204 | #define RAW_POLLING_INTERVAL 1 | ||
205 | #ifndef UDI_HID_RAW_STRING_ID | ||
206 | #define UDI_HID_RAW_STRING_ID 0 | ||
207 | #endif | ||
208 | #else | ||
209 | #define NEXT_IN_EPNUM_4 NEXT_IN_EPNUM_3 | ||
210 | #define NEXT_OUT_EPNUM_1 NEXT_OUT_EPNUM_0 | ||
211 | #endif | ||
212 | |||
213 | #ifdef CON | ||
214 | #define CONSOLE_IN_EPNUM NEXT_IN_EPNUM_4 | ||
215 | #define NEXT_IN_EPNUM_5 (CONSOLE_IN_EPNUM + 1) | ||
216 | #define CONSOLE_OUT_EPNUM NEXT_OUT_EPNUM_1 | ||
217 | #define NEXT_OUT_EPNUM_2 (CONSOLE_OUT_EPNUM + 1) | ||
218 | #define CONSOLE_POLLING_INTERVAL 1 | ||
219 | #else | ||
220 | #define NEXT_IN_EPNUM_5 NEXT_IN_EPNUM_4 | ||
221 | #define NEXT_OUT_EPNUM_2 NEXT_OUT_EPNUM_1 | ||
222 | #endif | ||
223 | |||
224 | #ifdef NKRO | ||
225 | #define NKRO_IN_EPNUM NEXT_IN_EPNUM_5 | ||
226 | #define UDI_HID_NKRO_EP_IN NKRO_IN_EPNUM | ||
227 | #define NEXT_IN_EPNUM_6 (NKRO_IN_EPNUM + 1) | ||
228 | #define UDI_HID_NKRO_EP_SIZE NKRO_EPSIZE | ||
229 | #define NKRO_POLLING_INTERVAL 1 | ||
230 | #ifndef UDI_HID_NKRO_STRING_ID | ||
231 | #define UDI_HID_NKRO_STRING_ID 0 | ||
232 | #endif | ||
233 | #else | ||
234 | #define NEXT_IN_EPNUM_6 NEXT_IN_EPNUM_5 | ||
235 | #endif | ||
236 | |||
237 | #ifdef MIDI | ||
238 | #define MIDI_STREAM_IN_EPNUM NEXT_IN_EPNUM_6 | ||
239 | #define NEXT_IN_EPNUM_7 (MIDI_STREAM_IN_EPNUM + 1) | ||
240 | #define MIDI_STREAM_OUT_EPNUM NEXT_OUT_EPNUM_2 | ||
241 | #define NEXT_OUT_EPNUM_3 (MIDI_STREAM_OUT_EPNUM + 1) | ||
242 | #define MIDI_POLLING_INTERVAL 5 | ||
243 | #else | ||
244 | #define NEXT_IN_EPNUM_7 NEXT_IN_EPNUM_6 | ||
245 | #define NEXT_OUT_EPNUM_3 NEXT_OUT_EPNUM_2 | ||
246 | #endif | ||
247 | |||
248 | #ifdef CDC | ||
249 | #define CDC_NOTIFICATION_EPNUM NEXT_IN_EPNUM_7 | ||
250 | #define CDC_ACM_ENDPOINT CDC_NOTIFICATION_EPNUM | ||
251 | #define CDC_TX_ENDPOINT (CDC_NOTIFICATION_EPNUM + 1) | ||
252 | #define NEXT_IN_EPNUM_8 (CDC_TX_ENDPOINT + 1) | ||
253 | |||
254 | #define CDC_OUT_EPNUM NEXT_OUT_EPNUM_3 | ||
255 | #define CDC_RX_ENDPOINT CDC_OUT_EPNUM | ||
256 | #define NEXT_OUT_EPNUM_4 (CDC_OUT_EPNUM + 1) | ||
257 | |||
258 | #define CDC_ACM_SIZE CDC_NOTIFICATION_EPSIZE | ||
259 | #define CDC_RX_SIZE CDC_EPSIZE //KFSMOD was 64 | ||
260 | #define CDC_TX_SIZE CDC_RX_SIZE | ||
261 | #define CDC_ACM_POLLING_INTERVAL 255 | ||
262 | #define CDC_EP_INTERVAL_STATUS CDC_ACM_POLLING_INTERVAL | ||
263 | #define CDC_DATA_POLLING_INTERVAL 5 | ||
264 | #define CDC_EP_INTERVAL_DATA CDC_DATA_POLLING_INTERVAL | ||
265 | #define CDC_STATUS_NAME L"Virtual Serial Port - Status" | ||
266 | #define CDC_DATA_NAME L"Virtual Serial Port - Data" | ||
267 | #else | ||
268 | #define NEXT_IN_EPNUM_8 NEXT_IN_EPNUM_7 | ||
269 | #define NEXT_OUT_EPNUM_4 NEXT_OUT_EPNUM_3 | ||
270 | #endif | ||
271 | |||
272 | #define TOTAL_OUT_EP NEXT_OUT_EPNUM_4 | ||
273 | #define TOTAL_IN_EP NEXT_IN_EPNUM_8 | ||
274 | #define USB_DEVICE_MAX_EP (max(NEXT_OUT_EPNUM_4, NEXT_IN_EPNUM_8)) | ||
275 | |||
276 | #if USB_DEVICE_MAX_EP > 8 | ||
277 | #error "There are not enough available endpoints to support all functions. Remove some in the rules.mk file.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI, VIRTSER)" | ||
278 | #endif | ||
279 | |||
280 | |||
281 | // ********************************************************************** | ||
282 | // KBD Descriptor structure and content | ||
283 | // ********************************************************************** | ||
284 | #ifdef KBD | ||
285 | |||
286 | COMPILER_PACK_SET(1) | ||
287 | |||
288 | typedef struct { | ||
289 | usb_iface_desc_t iface; | ||
290 | usb_hid_descriptor_t hid; | ||
291 | usb_ep_desc_t ep; | ||
292 | } udi_hid_kbd_desc_t; | ||
293 | |||
294 | typedef struct { | ||
295 | uint8_t array[59]; | ||
296 | } udi_hid_kbd_report_desc_t; | ||
297 | |||
298 | #define UDI_HID_KBD_DESC {\ | ||
299 | .iface.bLength = sizeof(usb_iface_desc_t),\ | ||
300 | .iface.bDescriptorType = USB_DT_INTERFACE,\ | ||
301 | .iface.bInterfaceNumber = UDI_HID_KBD_IFACE_NUMBER,\ | ||
302 | .iface.bAlternateSetting = 0,\ | ||
303 | .iface.bNumEndpoints = 1,\ | ||
304 | .iface.bInterfaceClass = HID_CLASS,\ | ||
305 | .iface.bInterfaceSubClass = HID_SUB_CLASS_BOOT,\ | ||
306 | .iface.bInterfaceProtocol = HID_PROTOCOL_KEYBOARD,\ | ||
307 | .iface.iInterface = UDI_HID_KBD_STRING_ID,\ | ||
308 | .hid.bLength = sizeof(usb_hid_descriptor_t),\ | ||
309 | .hid.bDescriptorType = USB_DT_HID,\ | ||
310 | .hid.bcdHID = LE16(USB_HID_BDC_V1_11),\ | ||
311 | .hid.bCountryCode = USB_HID_NO_COUNTRY_CODE,\ | ||
312 | .hid.bNumDescriptors = USB_HID_NUM_DESC,\ | ||
313 | .hid.bRDescriptorType = USB_DT_HID_REPORT,\ | ||
314 | .hid.wDescriptorLength = LE16(sizeof(udi_hid_kbd_report_desc_t)),\ | ||
315 | .ep.bLength = sizeof(usb_ep_desc_t),\ | ||
316 | .ep.bDescriptorType = USB_DT_ENDPOINT,\ | ||
317 | .ep.bEndpointAddress = UDI_HID_KBD_EP_IN | USB_EP_DIR_IN,\ | ||
318 | .ep.bmAttributes = USB_EP_TYPE_INTERRUPT,\ | ||
319 | .ep.wMaxPacketSize = LE16(UDI_HID_KBD_EP_SIZE),\ | ||
320 | .ep.bInterval = KBD_POLLING_INTERVAL,\ | ||
321 | } | ||
322 | |||
323 | //set report buffer (from host) | ||
324 | extern uint8_t udi_hid_kbd_report_set; | ||
325 | |||
326 | //report buffer (to host) | ||
327 | #define UDI_HID_KBD_REPORT_SIZE 8 | ||
328 | extern uint8_t udi_hid_kbd_report[UDI_HID_KBD_REPORT_SIZE]; | ||
329 | |||
330 | COMPILER_PACK_RESET() | ||
331 | |||
332 | #endif //KBD | ||
333 | |||
334 | // ********************************************************************** | ||
335 | // EXK Descriptor structure and content | ||
336 | // ********************************************************************** | ||
337 | #ifdef EXK | ||
338 | |||
339 | COMPILER_PACK_SET(1) | ||
340 | |||
341 | typedef struct { | ||
342 | usb_iface_desc_t iface; | ||
343 | usb_hid_descriptor_t hid; | ||
344 | usb_ep_desc_t ep; | ||
345 | } udi_hid_exk_desc_t; | ||
346 | |||
347 | typedef struct { | ||
348 | uint8_t array[54]; | ||
349 | } udi_hid_exk_report_desc_t; | ||
350 | |||
351 | #define UDI_HID_EXK_DESC {\ | ||
352 | .iface.bLength = sizeof(usb_iface_desc_t),\ | ||
353 | .iface.bDescriptorType = USB_DT_INTERFACE,\ | ||
354 | .iface.bInterfaceNumber = UDI_HID_EXK_IFACE_NUMBER,\ | ||
355 | .iface.bAlternateSetting = 0,\ | ||
356 | .iface.bNumEndpoints = 1,\ | ||
357 | .iface.bInterfaceClass = HID_CLASS,\ | ||
358 | .iface.bInterfaceSubClass = HID_SUB_CLASS_BOOT,\ | ||
359 | .iface.bInterfaceProtocol = HID_PROTOCOL_GENERIC,\ | ||
360 | .iface.iInterface = UDI_HID_EXK_STRING_ID,\ | ||
361 | .hid.bLength = sizeof(usb_hid_descriptor_t),\ | ||
362 | .hid.bDescriptorType = USB_DT_HID,\ | ||
363 | .hid.bcdHID = LE16(USB_HID_BDC_V1_11),\ | ||
364 | .hid.bCountryCode = USB_HID_NO_COUNTRY_CODE,\ | ||
365 | .hid.bNumDescriptors = USB_HID_NUM_DESC,\ | ||
366 | .hid.bRDescriptorType = USB_DT_HID_REPORT,\ | ||
367 | .hid.wDescriptorLength = LE16(sizeof(udi_hid_exk_report_desc_t)),\ | ||
368 | .ep.bLength = sizeof(usb_ep_desc_t),\ | ||
369 | .ep.bDescriptorType = USB_DT_ENDPOINT,\ | ||
370 | .ep.bEndpointAddress = UDI_HID_EXK_EP_IN | USB_EP_DIR_IN,\ | ||
371 | .ep.bmAttributes = USB_EP_TYPE_INTERRUPT,\ | ||
372 | .ep.wMaxPacketSize = LE16(UDI_HID_EXK_EP_SIZE),\ | ||
373 | .ep.bInterval = EXTRAKEY_POLLING_INTERVAL,\ | ||
374 | } | ||
375 | |||
376 | //set report buffer (from host) | ||
377 | extern uint8_t udi_hid_exk_report_set; | ||
378 | |||
379 | //report buffer | ||
380 | #define UDI_HID_EXK_REPORT_SIZE 3 | ||
381 | |||
382 | typedef union { | ||
383 | struct { | ||
384 | uint8_t report_id; | ||
385 | uint16_t report_data; | ||
386 | } desc; | ||
387 | uint8_t raw[UDI_HID_EXK_REPORT_SIZE]; | ||
388 | } udi_hid_exk_report_t; | ||
389 | |||
390 | extern udi_hid_exk_report_t udi_hid_exk_report; | ||
391 | |||
392 | COMPILER_PACK_RESET() | ||
393 | |||
394 | #endif //EXK | ||
395 | |||
396 | // ********************************************************************** | ||
397 | // NKRO Descriptor structure and content | ||
398 | // ********************************************************************** | ||
399 | #ifdef NKRO | ||
400 | |||
401 | COMPILER_PACK_SET(1) | ||
402 | |||
403 | typedef struct { | ||
404 | usb_iface_desc_t iface; | ||
405 | usb_hid_descriptor_t hid; | ||
406 | usb_ep_desc_t ep; | ||
407 | } udi_hid_nkro_desc_t; | ||
408 | |||
409 | typedef struct { | ||
410 | uint8_t array[57]; | ||
411 | } udi_hid_nkro_report_desc_t; | ||
412 | |||
413 | #define UDI_HID_NKRO_DESC {\ | ||
414 | .iface.bLength = sizeof(usb_iface_desc_t),\ | ||
415 | .iface.bDescriptorType = USB_DT_INTERFACE,\ | ||
416 | .iface.bInterfaceNumber = UDI_HID_NKRO_IFACE_NUMBER,\ | ||
417 | .iface.bAlternateSetting = 0,\ | ||
418 | .iface.bNumEndpoints = 1,\ | ||
419 | .iface.bInterfaceClass = HID_CLASS,\ | ||
420 | .iface.bInterfaceSubClass = HID_SUB_CLASS_NOBOOT,\ | ||
421 | .iface.bInterfaceProtocol = HID_PROTOCOL_KEYBOARD,\ | ||
422 | .iface.iInterface = UDI_HID_NKRO_STRING_ID,\ | ||
423 | .hid.bLength = sizeof(usb_hid_descriptor_t),\ | ||
424 | .hid.bDescriptorType = USB_DT_HID,\ | ||
425 | .hid.bcdHID = LE16(USB_HID_BDC_V1_11),\ | ||
426 | .hid.bCountryCode = USB_HID_NO_COUNTRY_CODE,\ | ||
427 | .hid.bNumDescriptors = USB_HID_NUM_DESC,\ | ||
428 | .hid.bRDescriptorType = USB_DT_HID_REPORT,\ | ||
429 | .hid.wDescriptorLength = LE16(sizeof(udi_hid_nkro_report_desc_t)),\ | ||
430 | .ep.bLength = sizeof(usb_ep_desc_t),\ | ||
431 | .ep.bDescriptorType = USB_DT_ENDPOINT,\ | ||
432 | .ep.bEndpointAddress = UDI_HID_NKRO_EP_IN | USB_EP_DIR_IN,\ | ||
433 | .ep.bmAttributes = USB_EP_TYPE_INTERRUPT,\ | ||
434 | .ep.wMaxPacketSize = LE16(UDI_HID_NKRO_EP_SIZE),\ | ||
435 | .ep.bInterval = NKRO_POLLING_INTERVAL,\ | ||
436 | } | ||
437 | |||
438 | //set report buffer | ||
439 | extern uint8_t udi_hid_nkro_report_set; | ||
440 | |||
441 | //report buffer | ||
442 | #define UDI_HID_NKRO_REPORT_SIZE 32 | ||
443 | extern uint8_t udi_hid_nkro_report[UDI_HID_NKRO_REPORT_SIZE]; | ||
444 | |||
445 | COMPILER_PACK_RESET() | ||
446 | |||
447 | #endif //NKRO | ||
448 | |||
449 | // ********************************************************************** | ||
450 | // MOU Descriptor structure and content | ||
451 | // ********************************************************************** | ||
452 | #ifdef MOU | ||
453 | |||
454 | COMPILER_PACK_SET(1) | ||
455 | |||
456 | typedef struct { | ||
457 | usb_iface_desc_t iface; | ||
458 | usb_hid_descriptor_t hid; | ||
459 | usb_ep_desc_t ep; | ||
460 | } udi_hid_mou_desc_t; | ||
461 | |||
462 | typedef struct { | ||
463 | uint8_t array[77];//MOU PDS | ||
464 | } udi_hid_mou_report_desc_t; | ||
465 | |||
466 | #define UDI_HID_MOU_DESC {\ | ||
467 | .iface.bLength = sizeof(usb_iface_desc_t),\ | ||
468 | .iface.bDescriptorType = USB_DT_INTERFACE,\ | ||
469 | .iface.bInterfaceNumber = MOUSE_INTERFACE,\ | ||
470 | .iface.bAlternateSetting = 0,\ | ||
471 | .iface.bNumEndpoints = 1,\ | ||
472 | .iface.bInterfaceClass = HID_CLASS,\ | ||
473 | .iface.bInterfaceSubClass = HID_SUB_CLASS_BOOT,\ | ||
474 | .iface.bInterfaceProtocol = HID_PROTOCOL_MOUSE,\ | ||
475 | .iface.iInterface = UDI_HID_MOU_STRING_ID,\ | ||
476 | .hid.bLength = sizeof(usb_hid_descriptor_t),\ | ||
477 | .hid.bDescriptorType = USB_DT_HID,\ | ||
478 | .hid.bcdHID = LE16(USB_HID_BDC_V1_11),\ | ||
479 | .hid.bCountryCode = USB_HID_NO_COUNTRY_CODE,\ | ||
480 | .hid.bNumDescriptors = USB_HID_NUM_DESC,\ | ||
481 | .hid.bRDescriptorType = USB_DT_HID_REPORT,\ | ||
482 | .hid.wDescriptorLength = LE16(sizeof(udi_hid_mou_report_desc_t)),\ | ||
483 | .ep.bLength = sizeof(usb_ep_desc_t),\ | ||
484 | .ep.bDescriptorType = USB_DT_ENDPOINT,\ | ||
485 | .ep.bEndpointAddress = UDI_HID_MOU_EP_IN | USB_EP_DIR_IN,\ | ||
486 | .ep.bmAttributes = USB_EP_TYPE_INTERRUPT,\ | ||
487 | .ep.wMaxPacketSize = LE16(UDI_HID_MOU_EP_SIZE),\ | ||
488 | .ep.bInterval = MOU_POLLING_INTERVAL,\ | ||
489 | } | ||
490 | |||
491 | //no set report buffer | ||
492 | |||
493 | //report buffer | ||
494 | #define UDI_HID_MOU_REPORT_SIZE 5 //MOU PDS | ||
495 | extern uint8_t udi_hid_mou_report[UDI_HID_MOU_REPORT_SIZE]; | ||
496 | |||
497 | COMPILER_PACK_RESET() | ||
498 | |||
499 | #endif //MOU | ||
500 | |||
501 | // ********************************************************************** | ||
502 | // RAW Descriptor structure and content | ||
503 | // ********************************************************************** | ||
504 | #ifdef RAW | ||
505 | |||
506 | COMPILER_PACK_SET(1) | ||
507 | |||
508 | typedef struct { | ||
509 | usb_iface_desc_t iface; | ||
510 | usb_hid_descriptor_t hid; | ||
511 | usb_ep_desc_t ep_out; | ||
512 | usb_ep_desc_t ep_in; | ||
513 | } udi_hid_raw_desc_t; | ||
514 | |||
515 | typedef struct { | ||
516 | uint8_t array[27]; | ||
517 | } udi_hid_raw_report_desc_t; | ||
518 | |||
519 | #define UDI_HID_RAW_DESC {\ | ||
520 | .iface.bLength = sizeof(usb_iface_desc_t),\ | ||
521 | .iface.bDescriptorType = USB_DT_INTERFACE,\ | ||
522 | .iface.bInterfaceNumber = RAW_INTERFACE,\ | ||
523 | .iface.bAlternateSetting = 0,\ | ||
524 | .iface.bNumEndpoints = 2,\ | ||
525 | .iface.bInterfaceClass = HID_CLASS,\ | ||
526 | .iface.bInterfaceSubClass = HID_SUB_CLASS_NOBOOT,\ | ||
527 | .iface.bInterfaceProtocol = HID_SUB_CLASS_NOBOOT,\ | ||
528 | .iface.iInterface = UDI_HID_RAW_STRING_ID,\ | ||
529 | .hid.bLength = sizeof(usb_hid_descriptor_t),\ | ||
530 | .hid.bDescriptorType = USB_DT_HID,\ | ||
531 | .hid.bcdHID = LE16(USB_HID_BDC_V1_11),\ | ||
532 | .hid.bCountryCode = USB_HID_NO_COUNTRY_CODE,\ | ||
533 | .hid.bNumDescriptors = USB_HID_NUM_DESC,\ | ||
534 | .hid.bRDescriptorType = USB_DT_HID_REPORT,\ | ||
535 | .hid.wDescriptorLength = LE16(sizeof(udi_hid_raw_report_desc_t)),\ | ||
536 | .ep_out.bLength = sizeof(usb_ep_desc_t),\ | ||
537 | .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ | ||
538 | .ep_out.bEndpointAddress = UDI_HID_RAW_EP_OUT | USB_EP_DIR_OUT,\ | ||
539 | .ep_out.bmAttributes = USB_EP_TYPE_INTERRUPT,\ | ||
540 | .ep_out.wMaxPacketSize = LE16(RAW_EPSIZE),\ | ||
541 | .ep_out.bInterval = RAW_POLLING_INTERVAL,\ | ||
542 | .ep_in.bLength = sizeof(usb_ep_desc_t),\ | ||
543 | .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ | ||
544 | .ep_in.bEndpointAddress = UDI_HID_RAW_EP_IN | USB_EP_DIR_IN,\ | ||
545 | .ep_in.bmAttributes = USB_EP_TYPE_INTERRUPT,\ | ||
546 | .ep_in.wMaxPacketSize = LE16(RAW_EPSIZE),\ | ||
547 | .ep_in.bInterval = RAW_POLLING_INTERVAL,\ | ||
548 | } | ||
549 | |||
550 | #define UDI_HID_RAW_REPORT_SIZE RAW_EPSIZE | ||
551 | |||
552 | extern uint8_t udi_hid_raw_report_set[UDI_HID_RAW_REPORT_SIZE]; | ||
553 | |||
554 | //report buffer | ||
555 | extern uint8_t udi_hid_raw_report[UDI_HID_RAW_REPORT_SIZE]; | ||
556 | |||
557 | COMPILER_PACK_RESET() | ||
558 | |||
559 | #endif //RAW | ||
560 | |||
561 | // ********************************************************************** | ||
562 | // CDC Descriptor structure and content | ||
563 | // ********************************************************************** | ||
564 | #ifdef CDC | ||
565 | |||
566 | COMPILER_PACK_SET(1) | ||
567 | |||
568 | typedef struct { | ||
569 | uint8_t bFunctionLength; | ||
570 | uint8_t bDescriptorType; | ||
571 | uint8_t bDescriptorSubtype; | ||
572 | le16_t bcdCDC; | ||
573 | } usb_cdc_hdr_desc_t; | ||
574 | |||
575 | typedef struct { | ||
576 | uint8_t bFunctionLength; | ||
577 | uint8_t bDescriptorType; | ||
578 | uint8_t bDescriptorSubtype; | ||
579 | uint8_t bmCapabilities; | ||
580 | uint8_t bDataInterface; | ||
581 | } usb_cdc_call_mgmt_desc_t; | ||
582 | |||
583 | typedef struct { | ||
584 | uint8_t bFunctionLength; | ||
585 | uint8_t bDescriptorType; | ||
586 | uint8_t bDescriptorSubtype; | ||
587 | uint8_t bmCapabilities; | ||
588 | } usb_cdc_acm_desc_t; | ||
589 | |||
590 | typedef struct { | ||
591 | uint8_t bFunctionLength; | ||
592 | uint8_t bDescriptorType; | ||
593 | uint8_t bDescriptorSubtype; | ||
594 | uint8_t bMasterInterface; | ||
595 | uint8_t bSlaveInterface0; | ||
596 | } usb_cdc_union_desc_t; | ||
597 | |||
598 | typedef struct { | ||
599 | usb_association_desc_t iaface; | ||
600 | usb_iface_desc_t iface_c; | ||
601 | usb_cdc_hdr_desc_t fd; | ||
602 | usb_cdc_call_mgmt_desc_t mfd; | ||
603 | usb_cdc_acm_desc_t acmd; | ||
604 | usb_cdc_union_desc_t ufd; | ||
605 | usb_ep_desc_t ep_c; | ||
606 | usb_iface_desc_t iface_d; | ||
607 | usb_ep_desc_t ep_tx; | ||
608 | usb_ep_desc_t ep_rx; | ||
609 | } udi_cdc_desc_t; | ||
610 | |||
611 | #define CDC_DESCRIPTOR {\ | ||
612 | .iaface.bLength = sizeof(usb_association_desc_t),\ | ||
613 | .iaface.bDescriptorType = USB_DT_IAD,\ | ||
614 | .iaface.bFirstInterface = CDC_STATUS_INTERFACE,\ | ||
615 | .iaface.bInterfaceCount = 2,\ | ||
616 | .iaface.bFunctionClass = CDC_CLASS_DEVICE,\ | ||
617 | .iaface.bFunctionSubClass = CDC_SUBCLASS_ACM,\ | ||
618 | .iaface.bFunctionProtocol = CDC_PROTOCOL_V25TER,\ | ||
619 | .iaface.iFunction = 0,\ | ||
620 | .iface_c.bLength = sizeof(usb_iface_desc_t),\ | ||
621 | .iface_c.bDescriptorType = USB_DT_INTERFACE,\ | ||
622 | .iface_c.bInterfaceNumber = CDC_STATUS_INTERFACE,\ | ||
623 | .iface_c.bAlternateSetting = 0,\ | ||
624 | .iface_c.bNumEndpoints = 1,\ | ||
625 | .iface_c.bInterfaceClass = 0x02,\ | ||
626 | .iface_c.bInterfaceSubClass = 0x02,\ | ||
627 | .iface_c.bInterfaceProtocol = CDC_PROTOCOL_V25TER,\ | ||
628 | .iface_c.iInterface = 0,\ | ||
629 | .fd.bFunctionLength = sizeof(usb_cdc_hdr_desc_t),\ | ||
630 | .fd.bDescriptorType = CDC_CS_INTERFACE,\ | ||
631 | .fd.bDescriptorSubtype = CDC_SCS_HEADER,\ | ||
632 | .fd.bcdCDC = 0x0110,\ | ||
633 | .mfd.bFunctionLength = sizeof(usb_cdc_call_mgmt_desc_t),\ | ||
634 | .mfd.bDescriptorType = CDC_CS_INTERFACE,\ | ||
635 | .mfd.bDescriptorSubtype = CDC_SCS_CALL_MGMT,\ | ||
636 | .mfd.bmCapabilities = CDC_CALL_MGMT_SUPPORTED,\ | ||
637 | .mfd.bDataInterface = CDC_DATA_INTERFACE,\ | ||
638 | .acmd.bFunctionLength = sizeof(usb_cdc_acm_desc_t),\ | ||
639 | .acmd.bDescriptorType = CDC_CS_INTERFACE,\ | ||
640 | .acmd.bDescriptorSubtype = CDC_SCS_ACM,\ | ||
641 | .acmd.bmCapabilities = CDC_ACM_SUPPORT_LINE_REQUESTS,\ | ||
642 | .ufd.bFunctionLength = sizeof(usb_cdc_union_desc_t),\ | ||
643 | .ufd.bDescriptorType = CDC_CS_INTERFACE,\ | ||
644 | .ufd.bDescriptorSubtype = CDC_SCS_UNION,\ | ||
645 | .ufd.bMasterInterface = CDC_STATUS_INTERFACE,\ | ||
646 | .ufd.bSlaveInterface0 = CDC_DATA_INTERFACE,\ | ||
647 | .ep_c.bLength = sizeof(usb_ep_desc_t),\ | ||
648 | .ep_c.bDescriptorType = USB_DT_ENDPOINT,\ | ||
649 | .ep_c.bEndpointAddress = CDC_ACM_ENDPOINT | USB_EP_DIR_IN,\ | ||
650 | .ep_c.bmAttributes = USB_EP_TYPE_INTERRUPT,\ | ||
651 | .ep_c.wMaxPacketSize = LE16(CDC_ACM_SIZE),\ | ||
652 | .ep_c.bInterval = CDC_EP_INTERVAL_STATUS,\ | ||
653 | .iface_d.bLength = sizeof(usb_iface_desc_t),\ | ||
654 | .iface_d.bDescriptorType = USB_DT_INTERFACE,\ | ||
655 | .iface_d.bInterfaceNumber = CDC_DATA_INTERFACE,\ | ||
656 | .iface_d.bAlternateSetting = 0,\ | ||
657 | .iface_d.bNumEndpoints = 2,\ | ||
658 | .iface_d.bInterfaceClass = CDC_CLASS_DATA,\ | ||
659 | .iface_d.bInterfaceSubClass = 0,\ | ||
660 | .iface_d.bInterfaceProtocol = 0,\ | ||
661 | .iface_d.iInterface = 0,\ | ||
662 | .ep_rx.bLength = sizeof(usb_ep_desc_t),\ | ||
663 | .ep_rx.bDescriptorType = USB_DT_ENDPOINT,\ | ||
664 | .ep_rx.bEndpointAddress = CDC_RX_ENDPOINT | USB_EP_DIR_OUT,\ | ||
665 | .ep_rx.bmAttributes = USB_EP_TYPE_BULK,\ | ||
666 | .ep_rx.wMaxPacketSize = LE16(CDC_RX_SIZE),\ | ||
667 | .ep_rx.bInterval = CDC_EP_INTERVAL_DATA,\ | ||
668 | .ep_tx.bLength = sizeof(usb_ep_desc_t),\ | ||
669 | .ep_tx.bDescriptorType = USB_DT_ENDPOINT,\ | ||
670 | .ep_tx.bEndpointAddress = CDC_TX_ENDPOINT | USB_EP_DIR_IN,\ | ||
671 | .ep_tx.bmAttributes = USB_EP_TYPE_BULK,\ | ||
672 | .ep_tx.wMaxPacketSize = LE16(CDC_TX_SIZE),\ | ||
673 | .ep_tx.bInterval = CDC_EP_INTERVAL_DATA,\ | ||
674 | } | ||
675 | |||
676 | COMPILER_PACK_RESET() | ||
677 | |||
678 | #endif //CDC | ||
679 | |||
680 | // ********************************************************************** | ||
681 | // CONFIGURATION Descriptor structure and content | ||
682 | // ********************************************************************** | ||
683 | COMPILER_PACK_SET(1) | ||
684 | |||
685 | typedef struct { | ||
686 | usb_conf_desc_t conf; | ||
687 | #ifdef KBD | ||
688 | udi_hid_kbd_desc_t hid_kbd; | ||
689 | #endif | ||
690 | #ifdef MOU | ||
691 | udi_hid_mou_desc_t hid_mou; | ||
692 | #endif | ||
693 | #ifdef EXK | ||
694 | udi_hid_exk_desc_t hid_exk; | ||
695 | #endif | ||
696 | #ifdef RAW | ||
697 | udi_hid_raw_desc_t hid_raw; | ||
698 | #endif | ||
699 | #ifdef CON | ||
700 | udi_hid_con_desc_t hid_con; | ||
701 | #endif | ||
702 | #ifdef NKRO | ||
703 | udi_hid_nkro_desc_t hid_nkro; | ||
704 | #endif | ||
705 | #ifdef MIDI | ||
706 | udi_hid_midi_desc_t hid_midi; | ||
707 | #endif | ||
708 | #ifdef CDC | ||
709 | udi_cdc_desc_t cdc_serial; | ||
710 | #endif | ||
711 | } udc_desc_t; | ||
712 | |||
713 | COMPILER_PACK_RESET() | ||
714 | |||
715 | #endif //_UDI_DEVICE_CONF_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_device_epsize.h b/tmk_core/protocol/arm_atsam/usb/udi_device_epsize.h new file mode 100644 index 000000000..96d03c286 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_device_epsize.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _UDI_DEVICE_EPSIZE_H_ | ||
19 | #define _UDI_DEVICE_EPSIZE_H_ | ||
20 | |||
21 | #define KEYBOARD_EPSIZE 8 | ||
22 | #define MOUSE_EPSIZE 8 | ||
23 | #define EXTRAKEY_EPSIZE 8 | ||
24 | #define RAW_EPSIZE 64 | ||
25 | #define CONSOLE_EPSIZE 32 | ||
26 | #define NKRO_EPSIZE 32 | ||
27 | #define MIDI_STREAM_EPSIZE 64 | ||
28 | #define CDC_NOTIFICATION_EPSIZE 8 | ||
29 | #define CDC_EPSIZE 16 | ||
30 | |||
31 | #endif //_UDI_DEVICE_EPSIZE_H_ | ||
32 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid.c b/tmk_core/protocol/arm_atsam/usb/udi_hid.c new file mode 100644 index 000000000..131b7a0ec --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device Human Interface Device (HID) interface. | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #include "conf_usb.h" | ||
48 | #include "usb_protocol.h" | ||
49 | #include "udd.h" | ||
50 | #include "udc.h" | ||
51 | #include "udi_hid.h" | ||
52 | |||
53 | |||
54 | /** | ||
55 | * \ingroup udi_hid_group | ||
56 | * \defgroup udi_hid_group_internal Implementation of HID common library | ||
57 | * @{ | ||
58 | */ | ||
59 | |||
60 | /** | ||
61 | * \brief Send the specific descriptors requested by SETUP request | ||
62 | * | ||
63 | * \retval true if the descriptor is supported | ||
64 | */ | ||
65 | static bool udi_hid_reqstdifaceget_descriptor(uint8_t *report_desc); | ||
66 | |||
67 | bool udi_hid_setup( uint8_t *rate, uint8_t *protocol, uint8_t *report_desc, bool (*setup_report)(void) ) | ||
68 | { | ||
69 | if (Udd_setup_is_in()) { | ||
70 | // Requests Interface GET | ||
71 | if (Udd_setup_type() == USB_REQ_TYPE_STANDARD) { | ||
72 | // Requests Standard Interface Get | ||
73 | switch (udd_g_ctrlreq.req.bRequest) { | ||
74 | |||
75 | case USB_REQ_GET_DESCRIPTOR: | ||
76 | return udi_hid_reqstdifaceget_descriptor(report_desc); | ||
77 | } | ||
78 | } | ||
79 | if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { | ||
80 | // Requests Class Interface Get | ||
81 | switch (udd_g_ctrlreq.req.bRequest) { | ||
82 | |||
83 | case USB_REQ_HID_GET_REPORT: | ||
84 | return setup_report(); | ||
85 | |||
86 | case USB_REQ_HID_GET_IDLE: | ||
87 | udd_g_ctrlreq.payload = rate; | ||
88 | udd_g_ctrlreq.payload_size = 1; | ||
89 | return true; | ||
90 | |||
91 | case USB_REQ_HID_GET_PROTOCOL: | ||
92 | udd_g_ctrlreq.payload = protocol; | ||
93 | udd_g_ctrlreq.payload_size = 1; | ||
94 | return true; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | if (Udd_setup_is_out()) { | ||
99 | // Requests Interface SET | ||
100 | if (Udd_setup_type() == USB_REQ_TYPE_CLASS) { | ||
101 | // Requests Class Interface Set | ||
102 | switch (udd_g_ctrlreq.req.bRequest) { | ||
103 | |||
104 | case USB_REQ_HID_SET_REPORT: | ||
105 | return setup_report(); | ||
106 | |||
107 | case USB_REQ_HID_SET_IDLE: | ||
108 | *rate = udd_g_ctrlreq.req.wValue >> 8; | ||
109 | return true; | ||
110 | |||
111 | case USB_REQ_HID_SET_PROTOCOL: | ||
112 | if (0 != udd_g_ctrlreq.req.wLength) | ||
113 | return false; | ||
114 | *protocol = udd_g_ctrlreq.req.wValue; | ||
115 | return true; | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | return false; // Request not supported | ||
120 | } | ||
121 | |||
122 | //--------------------------------------------- | ||
123 | //------- Internal routines | ||
124 | |||
125 | static bool udi_hid_reqstdifaceget_descriptor(uint8_t *report_desc) | ||
126 | { | ||
127 | usb_hid_descriptor_t UDC_DESC_STORAGE *ptr_hid_desc; | ||
128 | |||
129 | // Get the USB descriptor which is located after the interface descriptor | ||
130 | // This descriptor must be the HID descriptor | ||
131 | ptr_hid_desc = (usb_hid_descriptor_t UDC_DESC_STORAGE *) ((uint8_t *) | ||
132 | udc_get_interface_desc() + sizeof(usb_iface_desc_t)); | ||
133 | if (USB_DT_HID != ptr_hid_desc->bDescriptorType) | ||
134 | return false; | ||
135 | |||
136 | // The SETUP request can ask for: | ||
137 | // - an USB_DT_HID descriptor | ||
138 | // - or USB_DT_HID_REPORT descriptor | ||
139 | // - or USB_DT_HID_PHYSICAL descriptor | ||
140 | if (USB_DT_HID == (uint8_t) (udd_g_ctrlreq.req.wValue >> 8)) { | ||
141 | // USB_DT_HID descriptor requested then send it | ||
142 | udd_g_ctrlreq.payload = (uint8_t *) ptr_hid_desc; | ||
143 | udd_g_ctrlreq.payload_size = | ||
144 | min(udd_g_ctrlreq.req.wLength, | ||
145 | ptr_hid_desc->bLength); | ||
146 | return true; | ||
147 | } | ||
148 | // The HID_X descriptor requested must correspond to report type | ||
149 | // included in the HID descriptor | ||
150 | if (ptr_hid_desc->bRDescriptorType == | ||
151 | (uint8_t) (udd_g_ctrlreq.req.wValue >> 8)) { | ||
152 | // Send HID Report descriptor given by high level | ||
153 | udd_g_ctrlreq.payload = report_desc; | ||
154 | udd_g_ctrlreq.payload_size = | ||
155 | min(udd_g_ctrlreq.req.wLength, | ||
156 | le16_to_cpu(ptr_hid_desc->wDescriptorLength)); | ||
157 | return true; | ||
158 | } | ||
159 | return false; | ||
160 | } | ||
161 | |||
162 | //@} | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid.h b/tmk_core/protocol/arm_atsam/usb/udi_hid.h new file mode 100644 index 000000000..0edb09c1c --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device Human Interface Device (HID) interface definitions. | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDI_HID_H_ | ||
48 | #define _UDI_HID_H_ | ||
49 | |||
50 | #include "conf_usb.h" | ||
51 | #include "usb_protocol.h" | ||
52 | #include "usb_protocol_hid.h" | ||
53 | #include "udd.h" | ||
54 | |||
55 | #ifdef __cplusplus | ||
56 | extern "C" { | ||
57 | #endif | ||
58 | |||
59 | /** | ||
60 | * \ingroup udi_group | ||
61 | * \defgroup udi_hid_group USB Device Interface (UDI) for Human Interface Device (HID) | ||
62 | * | ||
63 | * Common library for all Human Interface Device (HID) implementation. | ||
64 | * | ||
65 | * @{ | ||
66 | */ | ||
67 | |||
68 | /** | ||
69 | * \brief Decode HID setup request | ||
70 | * | ||
71 | * \param rate Pointer on rate of current HID interface | ||
72 | * \param protocol Pointer on protocol of current HID interface | ||
73 | * \param report_desc Pointer on report descriptor of current HID interface | ||
74 | * \param set_report Pointer on set_report callback of current HID interface | ||
75 | * | ||
76 | * \return \c 1 if function was successfully done, otherwise \c 0. | ||
77 | */ | ||
78 | bool udi_hid_setup( uint8_t *rate, uint8_t *protocol, uint8_t *report_desc, bool (*setup_report)(void) ); | ||
79 | |||
80 | //@} | ||
81 | |||
82 | #ifdef __cplusplus | ||
83 | } | ||
84 | #endif | ||
85 | #endif // _UDI_HID_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c new file mode 100644 index 000000000..18f69350c --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c | |||
@@ -0,0 +1,845 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device Human Interface Device (HID) keyboard interface. | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #include "samd51j18a.h" | ||
48 | #include "conf_usb.h" | ||
49 | #include "usb_protocol.h" | ||
50 | #include "udd.h" | ||
51 | #include "udc.h" | ||
52 | #include "udi_device_conf.h" | ||
53 | #include "udi_hid.h" | ||
54 | #include "udi_hid_kbd.h" | ||
55 | #include <string.h> | ||
56 | |||
57 | //*************************************************************************** | ||
58 | // KBD | ||
59 | //*************************************************************************** | ||
60 | #ifdef KBD | ||
61 | |||
62 | bool udi_hid_kbd_enable(void); | ||
63 | void udi_hid_kbd_disable(void); | ||
64 | bool udi_hid_kbd_setup(void); | ||
65 | uint8_t udi_hid_kbd_getsetting(void); | ||
66 | |||
67 | UDC_DESC_STORAGE udi_api_t udi_api_hid_kbd = { | ||
68 | .enable = (bool(*)(void))udi_hid_kbd_enable, | ||
69 | .disable = (void (*)(void))udi_hid_kbd_disable, | ||
70 | .setup = (bool(*)(void))udi_hid_kbd_setup, | ||
71 | .getsetting = (uint8_t(*)(void))udi_hid_kbd_getsetting, | ||
72 | .sof_notify = NULL, | ||
73 | }; | ||
74 | |||
75 | COMPILER_WORD_ALIGNED | ||
76 | static uint8_t udi_hid_kbd_rate; | ||
77 | |||
78 | COMPILER_WORD_ALIGNED | ||
79 | static uint8_t udi_hid_kbd_protocol; | ||
80 | |||
81 | COMPILER_WORD_ALIGNED | ||
82 | uint8_t udi_hid_kbd_report_set; | ||
83 | |||
84 | bool udi_hid_kbd_b_report_valid; | ||
85 | |||
86 | COMPILER_WORD_ALIGNED | ||
87 | uint8_t udi_hid_kbd_report[UDI_HID_KBD_REPORT_SIZE]; | ||
88 | |||
89 | static bool udi_hid_kbd_b_report_trans_ongoing; | ||
90 | |||
91 | COMPILER_WORD_ALIGNED | ||
92 | static uint8_t udi_hid_kbd_report_trans[UDI_HID_KBD_REPORT_SIZE]; | ||
93 | |||
94 | COMPILER_WORD_ALIGNED | ||
95 | UDC_DESC_STORAGE udi_hid_kbd_report_desc_t udi_hid_kbd_report_desc = { | ||
96 | { | ||
97 | 0x05, 0x01, // Usage Page (Generic Desktop) | ||
98 | 0x09, 0x06, // Usage (Keyboard) | ||
99 | 0xA1, 0x01, // Collection (Application) | ||
100 | 0x05, 0x07, // Usage Page (Keyboard) | ||
101 | 0x19, 0xE0, // Usage Minimum (224) | ||
102 | 0x29, 0xE7, // Usage Maximum (231) | ||
103 | 0x15, 0x00, // Logical Minimum (0) | ||
104 | 0x25, 0x01, // Logical Maximum (1) | ||
105 | 0x75, 0x01, // Report Size (1) | ||
106 | 0x95, 0x08, // Report Count (8) | ||
107 | 0x81, 0x02, // Input (Data, Variable, Absolute) | ||
108 | 0x81, 0x01, // Input (Constant) | ||
109 | 0x19, 0x00, // Usage Minimum (0) | ||
110 | 0x29, 0x65, // Usage Maximum (101) | ||
111 | 0x15, 0x00, // Logical Minimum (0) | ||
112 | 0x25, 0x65, // Logical Maximum (101) | ||
113 | 0x75, 0x08, // Report Size (8) | ||
114 | 0x95, 0x06, // Report Count (6) | ||
115 | 0x81, 0x00, // Input (Data, Array) | ||
116 | 0x05, 0x08, // Usage Page (LED) | ||
117 | 0x19, 0x01, // Usage Minimum (1) | ||
118 | 0x29, 0x05, // Usage Maximum (5) | ||
119 | 0x15, 0x00, // Logical Minimum (0) | ||
120 | 0x25, 0x01, // Logical Maximum (1) | ||
121 | 0x75, 0x01, // Report Size (1) | ||
122 | 0x95, 0x05, // Report Count (5) | ||
123 | 0x91, 0x02, // Output (Data, Variable, Absolute) | ||
124 | 0x95, 0x03, // Report Count (3) | ||
125 | 0x91, 0x01, // Output (Constant) | ||
126 | 0xC0 // End Collection | ||
127 | } | ||
128 | }; | ||
129 | |||
130 | static bool udi_hid_kbd_setreport(void); | ||
131 | |||
132 | static void udi_hid_kbd_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); | ||
133 | |||
134 | static void udi_hid_kbd_setreport_valid(void); | ||
135 | |||
136 | bool udi_hid_kbd_enable(void) | ||
137 | { | ||
138 | // Initialize internal values | ||
139 | udi_hid_kbd_rate = 0; | ||
140 | udi_hid_kbd_protocol = 0; | ||
141 | udi_hid_kbd_b_report_trans_ongoing = false; | ||
142 | memset(udi_hid_kbd_report, 0, UDI_HID_KBD_REPORT_SIZE); | ||
143 | udi_hid_kbd_b_report_valid = false; | ||
144 | return UDI_HID_KBD_ENABLE_EXT(); | ||
145 | } | ||
146 | |||
147 | void udi_hid_kbd_disable(void) | ||
148 | { | ||
149 | UDI_HID_KBD_DISABLE_EXT(); | ||
150 | } | ||
151 | |||
152 | bool udi_hid_kbd_setup(void) | ||
153 | { | ||
154 | return udi_hid_setup(&udi_hid_kbd_rate, | ||
155 | &udi_hid_kbd_protocol, | ||
156 | (uint8_t *) &udi_hid_kbd_report_desc, | ||
157 | udi_hid_kbd_setreport); | ||
158 | } | ||
159 | |||
160 | uint8_t udi_hid_kbd_getsetting(void) | ||
161 | { | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static bool udi_hid_kbd_setreport(void) | ||
166 | { | ||
167 | if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8)) | ||
168 | && (0 == (0xFF & udd_g_ctrlreq.req.wValue)) | ||
169 | && (1 == udd_g_ctrlreq.req.wLength)) { | ||
170 | // Report OUT type on report ID 0 from USB Host | ||
171 | udd_g_ctrlreq.payload = &udi_hid_kbd_report_set; | ||
172 | udd_g_ctrlreq.callback = udi_hid_kbd_setreport_valid; | ||
173 | udd_g_ctrlreq.payload_size = 1; | ||
174 | return true; | ||
175 | } | ||
176 | return false; | ||
177 | } | ||
178 | |||
179 | bool udi_hid_kbd_send_report(void) | ||
180 | { | ||
181 | if (!main_b_kbd_enable) { | ||
182 | return false; | ||
183 | } | ||
184 | |||
185 | if (udi_hid_kbd_b_report_trans_ongoing) { | ||
186 | return false; | ||
187 | } | ||
188 | |||
189 | memcpy(udi_hid_kbd_report_trans, udi_hid_kbd_report, | ||
190 | UDI_HID_KBD_REPORT_SIZE); | ||
191 | udi_hid_kbd_b_report_valid = false; | ||
192 | udi_hid_kbd_b_report_trans_ongoing = | ||
193 | udd_ep_run(UDI_HID_KBD_EP_IN | USB_EP_DIR_IN, | ||
194 | false, | ||
195 | udi_hid_kbd_report_trans, | ||
196 | UDI_HID_KBD_REPORT_SIZE, | ||
197 | udi_hid_kbd_report_sent); | ||
198 | |||
199 | return udi_hid_kbd_b_report_trans_ongoing; | ||
200 | } | ||
201 | |||
202 | static void udi_hid_kbd_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep) | ||
203 | { | ||
204 | UNUSED(status); | ||
205 | UNUSED(nb_sent); | ||
206 | UNUSED(ep); | ||
207 | udi_hid_kbd_b_report_trans_ongoing = false; | ||
208 | if (udi_hid_kbd_b_report_valid) { | ||
209 | udi_hid_kbd_send_report(); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | static void udi_hid_kbd_setreport_valid(void) | ||
214 | { | ||
215 | //UDI_HID_KBD_CHANGE_LED(udi_hid_kbd_report_set); | ||
216 | } | ||
217 | |||
218 | #endif //KBD | ||
219 | |||
220 | //******************************************************************************************** | ||
221 | // NKRO Keyboard | ||
222 | //******************************************************************************************** | ||
223 | #ifdef NKRO | ||
224 | |||
225 | bool udi_hid_nkro_enable(void); | ||
226 | void udi_hid_nkro_disable(void); | ||
227 | bool udi_hid_nkro_setup(void); | ||
228 | uint8_t udi_hid_nkro_getsetting(void); | ||
229 | |||
230 | UDC_DESC_STORAGE udi_api_t udi_api_hid_nkro = { | ||
231 | .enable = (bool(*)(void))udi_hid_nkro_enable, | ||
232 | .disable = (void (*)(void))udi_hid_nkro_disable, | ||
233 | .setup = (bool(*)(void))udi_hid_nkro_setup, | ||
234 | .getsetting = (uint8_t(*)(void))udi_hid_nkro_getsetting, | ||
235 | .sof_notify = NULL, | ||
236 | }; | ||
237 | |||
238 | COMPILER_WORD_ALIGNED | ||
239 | static uint8_t udi_hid_nkro_rate; | ||
240 | |||
241 | COMPILER_WORD_ALIGNED | ||
242 | static uint8_t udi_hid_nkro_protocol; | ||
243 | |||
244 | COMPILER_WORD_ALIGNED | ||
245 | uint8_t udi_hid_nkro_report_set; | ||
246 | |||
247 | bool udi_hid_nkro_b_report_valid; | ||
248 | |||
249 | COMPILER_WORD_ALIGNED | ||
250 | uint8_t udi_hid_nkro_report[UDI_HID_NKRO_REPORT_SIZE]; | ||
251 | |||
252 | static bool udi_hid_nkro_b_report_trans_ongoing; | ||
253 | |||
254 | COMPILER_WORD_ALIGNED | ||
255 | static uint8_t udi_hid_nkro_report_trans[UDI_HID_NKRO_REPORT_SIZE]; | ||
256 | |||
257 | COMPILER_WORD_ALIGNED | ||
258 | UDC_DESC_STORAGE udi_hid_nkro_report_desc_t udi_hid_nkro_report_desc = { | ||
259 | { | ||
260 | 0x05, 0x01, // Usage Page (Generic Desktop), | ||
261 | 0x09, 0x06, // Usage (Keyboard), | ||
262 | 0xA1, 0x01, // Collection (Application) - Keyboard, | ||
263 | |||
264 | //Mods | ||
265 | 0x75, 0x01, // Report Size (1), | ||
266 | 0x95, 0x08, // Report Count (8), | ||
267 | 0x15, 0x00, // Logical Minimum (0), | ||
268 | 0x25, 0x01, // Logical Maximum (1), | ||
269 | 0x05, 0x07, // Usage Page (Key Codes), | ||
270 | 0x19, 0xE0, // Usage Minimum (224), | ||
271 | 0x29, 0xE7, // Usage Maximum (231), | ||
272 | 0x81, 0x02, // Input (Data, Variable, Absolute), | ||
273 | |||
274 | //LED Report | ||
275 | 0x75, 0x01, // Report Size (1), | ||
276 | 0x95, 0x05, // Report Count (5), | ||
277 | 0x05, 0x08, // Usage Page (LEDs), | ||
278 | 0x19, 0x01, // Usage Minimum (1), | ||
279 | 0x29, 0x05, // Usage Maximum (5), | ||
280 | 0x91, 0x02, // Output (Data, Variable, Absolute), | ||
281 | |||
282 | //LED Report Padding | ||
283 | 0x75, 0x03, // Report Size (3), | ||
284 | 0x95, 0x01, // Report Count (1), | ||
285 | 0x91, 0x03, // Output (Constant), | ||
286 | |||
287 | //Main keys | ||
288 | 0x75, 0x01, // Report Size (1), | ||
289 | 0x95, 0xF8, // Report Count (248), | ||
290 | 0x15, 0x00, // Logical Minimum (0), | ||
291 | 0x25, 0x01, // Logical Maximum (1), | ||
292 | 0x05, 0x07, // Usage Page (Key Codes), | ||
293 | 0x19, 0x00, // Usage Minimum (0), | ||
294 | 0x29, 0xF7, // Usage Maximum (247), | ||
295 | 0x81, 0x02, // Input (Data, Variable, Absolute, Bitfield), | ||
296 | 0xc0, // End Collection - Keyboard | ||
297 | } | ||
298 | }; | ||
299 | |||
300 | static bool udi_hid_nkro_setreport(void); | ||
301 | static void udi_hid_nkro_setreport_valid(void); | ||
302 | static void udi_hid_nkro_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); | ||
303 | |||
304 | bool udi_hid_nkro_enable(void) | ||
305 | { | ||
306 | // Initialize internal values | ||
307 | udi_hid_nkro_rate = 0; | ||
308 | udi_hid_nkro_protocol = 0; | ||
309 | udi_hid_nkro_b_report_trans_ongoing = false; | ||
310 | memset(udi_hid_nkro_report, 0, UDI_HID_NKRO_REPORT_SIZE); | ||
311 | udi_hid_nkro_b_report_valid = false; | ||
312 | return UDI_HID_NKRO_ENABLE_EXT(); | ||
313 | } | ||
314 | |||
315 | void udi_hid_nkro_disable(void) | ||
316 | { | ||
317 | UDI_HID_NKRO_DISABLE_EXT(); | ||
318 | } | ||
319 | |||
320 | bool udi_hid_nkro_setup(void) | ||
321 | { | ||
322 | return udi_hid_setup(&udi_hid_nkro_rate, | ||
323 | &udi_hid_nkro_protocol, | ||
324 | (uint8_t *) &udi_hid_nkro_report_desc, | ||
325 | udi_hid_nkro_setreport); | ||
326 | } | ||
327 | |||
328 | uint8_t udi_hid_nkro_getsetting(void) | ||
329 | { | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | //keyboard receives LED report here | ||
334 | static bool udi_hid_nkro_setreport(void) | ||
335 | { | ||
336 | if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8)) | ||
337 | && (0 == (0xFF & udd_g_ctrlreq.req.wValue)) | ||
338 | && (1 == udd_g_ctrlreq.req.wLength)) { | ||
339 | // Report OUT type on report ID 0 from USB Host | ||
340 | udd_g_ctrlreq.payload = &udi_hid_nkro_report_set; | ||
341 | udd_g_ctrlreq.callback = udi_hid_nkro_setreport_valid; //must call routine to transform setreport to LED state | ||
342 | udd_g_ctrlreq.payload_size = 1; | ||
343 | return true; | ||
344 | } | ||
345 | return false; | ||
346 | } | ||
347 | |||
348 | bool udi_hid_nkro_send_report(void) | ||
349 | { | ||
350 | if (!main_b_nkro_enable) { | ||
351 | return false; | ||
352 | } | ||
353 | |||
354 | if (udi_hid_nkro_b_report_trans_ongoing) { | ||
355 | return false; | ||
356 | } | ||
357 | |||
358 | memcpy(udi_hid_nkro_report_trans, udi_hid_nkro_report,UDI_HID_NKRO_REPORT_SIZE); | ||
359 | udi_hid_nkro_b_report_valid = false; | ||
360 | udi_hid_nkro_b_report_trans_ongoing = | ||
361 | udd_ep_run(UDI_HID_NKRO_EP_IN | USB_EP_DIR_IN, | ||
362 | false, | ||
363 | udi_hid_nkro_report_trans, | ||
364 | UDI_HID_NKRO_REPORT_SIZE, | ||
365 | udi_hid_nkro_report_sent); | ||
366 | |||
367 | return udi_hid_nkro_b_report_trans_ongoing; | ||
368 | } | ||
369 | |||
370 | static void udi_hid_nkro_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep) | ||
371 | { | ||
372 | UNUSED(status); | ||
373 | UNUSED(nb_sent); | ||
374 | UNUSED(ep); | ||
375 | udi_hid_nkro_b_report_trans_ongoing = false; | ||
376 | if (udi_hid_nkro_b_report_valid) { | ||
377 | udi_hid_nkro_send_report(); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static void udi_hid_nkro_setreport_valid(void) | ||
382 | { | ||
383 | //UDI_HID_NKRO_CHANGE_LED(udi_hid_nkro_report_set); | ||
384 | } | ||
385 | |||
386 | #endif //NKRO | ||
387 | |||
388 | //******************************************************************************************** | ||
389 | // EXK (extra-keys) SYS-CTRL Keyboard | ||
390 | //******************************************************************************************** | ||
391 | #ifdef EXK | ||
392 | |||
393 | bool udi_hid_exk_enable(void); | ||
394 | void udi_hid_exk_disable(void); | ||
395 | bool udi_hid_exk_setup(void); | ||
396 | uint8_t udi_hid_exk_getsetting(void); | ||
397 | |||
398 | UDC_DESC_STORAGE udi_api_t udi_api_hid_exk = { | ||
399 | .enable = (bool(*)(void))udi_hid_exk_enable, | ||
400 | .disable = (void (*)(void))udi_hid_exk_disable, | ||
401 | .setup = (bool(*)(void))udi_hid_exk_setup, | ||
402 | .getsetting = (uint8_t(*)(void))udi_hid_exk_getsetting, | ||
403 | .sof_notify = NULL, | ||
404 | }; | ||
405 | |||
406 | COMPILER_WORD_ALIGNED | ||
407 | static uint8_t udi_hid_exk_rate; | ||
408 | |||
409 | COMPILER_WORD_ALIGNED | ||
410 | static uint8_t udi_hid_exk_protocol; | ||
411 | |||
412 | COMPILER_WORD_ALIGNED | ||
413 | uint8_t udi_hid_exk_report_set; | ||
414 | |||
415 | bool udi_hid_exk_b_report_valid; | ||
416 | |||
417 | COMPILER_WORD_ALIGNED | ||
418 | udi_hid_exk_report_t udi_hid_exk_report; | ||
419 | |||
420 | static bool udi_hid_exk_b_report_trans_ongoing; | ||
421 | |||
422 | COMPILER_WORD_ALIGNED | ||
423 | static uint8_t udi_hid_exk_report_trans[UDI_HID_EXK_REPORT_SIZE]; | ||
424 | |||
425 | COMPILER_WORD_ALIGNED | ||
426 | UDC_DESC_STORAGE udi_hid_exk_report_desc_t udi_hid_exk_report_desc = { | ||
427 | { | ||
428 | // System Control Collection (8 bits) | ||
429 | |||
430 | 0x05, 0x01, // Usage Page (Generic Desktop), | ||
431 | 0x09, 0x80, // Usage (System Control), | ||
432 | 0xA1, 0x01, // Collection (Application), | ||
433 | 0x85, 0x02, // Report ID (2) (System), | ||
434 | 0x16, 0x01, 0x00, // Logical Minimum (1), | ||
435 | 0x26, 0x03, 0x00, // Logical Maximum (3), | ||
436 | 0x1A, 0x81, 0x00, // Usage Minimum (81) (System Power Down), | ||
437 | 0x2A, 0x83, 0x00, // Usage Maximum (83) (System Wake Up), | ||
438 | 0x75, 0x10, // Report Size (16), | ||
439 | 0x95, 0x01, // Report Count (1), | ||
440 | 0x81, 0x00, // Input (Data, Array), | ||
441 | 0xC0, // End Collection - System Control | ||
442 | |||
443 | // Consumer Control Collection - Media Keys (16 bits) | ||
444 | |||
445 | 0x05, 0x0C, // Usage Page (Consumer), | ||
446 | 0x09, 0x01, // Usage (Consumer Control), | ||
447 | 0xA1, 0x01, // Collection (Application), | ||
448 | 0x85, 0x03, // Report ID (3) (Consumer), | ||
449 | 0x16, 0x01, 0x00, // Logical Minimum (1), | ||
450 | 0x26, 0x9C, 0x02, // Logical Maximum (668), | ||
451 | 0x1A, 0x01, 0x00, // Usage Minimum (1), | ||
452 | 0x2A, 0x9C, 0x02, // Usage Maximum (668), | ||
453 | 0x75, 0x10, // Report Size (16), | ||
454 | 0x95, 0x01, // Report Count (1), | ||
455 | 0x81, 0x00, // Input (Data, Array), | ||
456 | 0xC0, // End Collection - Consumer Control | ||
457 | } | ||
458 | }; | ||
459 | |||
460 | static bool udi_hid_exk_setreport(void); | ||
461 | |||
462 | static void udi_hid_exk_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); | ||
463 | |||
464 | static void udi_hid_exk_setreport_valid(void); | ||
465 | |||
466 | bool udi_hid_exk_enable(void) | ||
467 | { | ||
468 | // Initialize internal values | ||
469 | udi_hid_exk_rate = 0; | ||
470 | udi_hid_exk_protocol = 0; | ||
471 | udi_hid_exk_b_report_trans_ongoing = false; | ||
472 | memset(udi_hid_exk_report.raw, 0, UDI_HID_EXK_REPORT_SIZE); | ||
473 | udi_hid_exk_b_report_valid = false; | ||
474 | return UDI_HID_EXK_ENABLE_EXT(); | ||
475 | } | ||
476 | |||
477 | void udi_hid_exk_disable(void) | ||
478 | { | ||
479 | UDI_HID_EXK_DISABLE_EXT(); | ||
480 | } | ||
481 | |||
482 | bool udi_hid_exk_setup(void) | ||
483 | { | ||
484 | return udi_hid_setup(&udi_hid_exk_rate, | ||
485 | &udi_hid_exk_protocol, | ||
486 | (uint8_t *) &udi_hid_exk_report_desc, | ||
487 | udi_hid_exk_setreport); | ||
488 | } | ||
489 | |||
490 | uint8_t udi_hid_exk_getsetting(void) | ||
491 | { | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static bool udi_hid_exk_setreport(void) | ||
496 | { | ||
497 | if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8)) | ||
498 | && (0 == (0xFF & udd_g_ctrlreq.req.wValue)) | ||
499 | && (1 == udd_g_ctrlreq.req.wLength)) { | ||
500 | // Report OUT type on report ID 0 from USB Host | ||
501 | udd_g_ctrlreq.payload = &udi_hid_exk_report_set; | ||
502 | udd_g_ctrlreq.callback = udi_hid_exk_setreport_valid; | ||
503 | udd_g_ctrlreq.payload_size = 1; | ||
504 | return true; | ||
505 | } | ||
506 | return false; | ||
507 | } | ||
508 | |||
509 | bool udi_hid_exk_send_report(void) | ||
510 | { | ||
511 | if (!main_b_exk_enable) { | ||
512 | return false; | ||
513 | } | ||
514 | |||
515 | if (udi_hid_exk_b_report_trans_ongoing) { | ||
516 | return false; | ||
517 | } | ||
518 | |||
519 | memcpy(udi_hid_exk_report_trans, udi_hid_exk_report.raw, UDI_HID_EXK_REPORT_SIZE); | ||
520 | udi_hid_exk_b_report_valid = false; | ||
521 | udi_hid_exk_b_report_trans_ongoing = | ||
522 | udd_ep_run(UDI_HID_EXK_EP_IN | USB_EP_DIR_IN, | ||
523 | false, | ||
524 | udi_hid_exk_report_trans, | ||
525 | UDI_HID_EXK_REPORT_SIZE, | ||
526 | udi_hid_exk_report_sent); | ||
527 | |||
528 | return udi_hid_exk_b_report_trans_ongoing; | ||
529 | } | ||
530 | |||
531 | static void udi_hid_exk_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep) | ||
532 | { | ||
533 | UNUSED(status); | ||
534 | UNUSED(nb_sent); | ||
535 | UNUSED(ep); | ||
536 | udi_hid_exk_b_report_trans_ongoing = false; | ||
537 | if (udi_hid_exk_b_report_valid) { | ||
538 | udi_hid_exk_send_report(); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | static void udi_hid_exk_setreport_valid(void) | ||
543 | { | ||
544 | |||
545 | } | ||
546 | |||
547 | #endif //EXK | ||
548 | |||
549 | //******************************************************************************************** | ||
550 | // MOU Mouse | ||
551 | //******************************************************************************************** | ||
552 | #ifdef MOU | ||
553 | |||
554 | bool udi_hid_mou_enable(void); | ||
555 | void udi_hid_mou_disable(void); | ||
556 | bool udi_hid_mou_setup(void); | ||
557 | uint8_t udi_hid_mou_getsetting(void); | ||
558 | |||
559 | UDC_DESC_STORAGE udi_api_t udi_api_hid_mou = { | ||
560 | .enable = (bool(*)(void))udi_hid_mou_enable, | ||
561 | .disable = (void (*)(void))udi_hid_mou_disable, | ||
562 | .setup = (bool(*)(void))udi_hid_mou_setup, | ||
563 | .getsetting = (uint8_t(*)(void))udi_hid_mou_getsetting, | ||
564 | .sof_notify = NULL, | ||
565 | }; | ||
566 | |||
567 | COMPILER_WORD_ALIGNED | ||
568 | static uint8_t udi_hid_mou_rate; | ||
569 | |||
570 | COMPILER_WORD_ALIGNED | ||
571 | static uint8_t udi_hid_mou_protocol; | ||
572 | |||
573 | //COMPILER_WORD_ALIGNED | ||
574 | //uint8_t udi_hid_mou_report_set; //No set report | ||
575 | |||
576 | bool udi_hid_mou_b_report_valid; | ||
577 | |||
578 | COMPILER_WORD_ALIGNED | ||
579 | uint8_t udi_hid_mou_report[UDI_HID_MOU_REPORT_SIZE]; | ||
580 | |||
581 | static bool udi_hid_mou_b_report_trans_ongoing; | ||
582 | |||
583 | COMPILER_WORD_ALIGNED | ||
584 | static uint8_t udi_hid_mou_report_trans[UDI_HID_MOU_REPORT_SIZE]; | ||
585 | |||
586 | COMPILER_WORD_ALIGNED | ||
587 | UDC_DESC_STORAGE udi_hid_mou_report_desc_t udi_hid_mou_report_desc = { | ||
588 | { | ||
589 | 0x05, 0x01, // Usage Page (Generic Desktop), | ||
590 | 0x09, 0x02, // Usage (Mouse), | ||
591 | 0xA1, 0x01, // Collection (Application), | ||
592 | 0x09, 0x01, // Usage (Pointer), | ||
593 | 0xA1, 0x00, // Collection (Physical), | ||
594 | 0x05, 0x09, // Usage Page (Buttons), | ||
595 | 0x19, 0x01, // Usage Minimum (01), | ||
596 | 0x29, 0x05, // Usage Maximun (05), | ||
597 | 0x15, 0x00, // Logical Minimum (0), | ||
598 | 0x25, 0x01, // Logical Maximum (1), | ||
599 | 0x95, 0x05, // Report Count (5), | ||
600 | 0x75, 0x01, // Report Size (1), | ||
601 | 0x81, 0x02, // Input (Data, Variable, Absolute), ;5 button bits | ||
602 | 0x95, 0x01, // Report Count (1), | ||
603 | 0x75, 0x03, // Report Size (3), | ||
604 | 0x81, 0x01, // Input (Constant), ;3 bit padding, | ||
605 | |||
606 | 0x05, 0x01, // Usage Page (Generic Desktop), | ||
607 | 0x09, 0x30, // Usage (X), | ||
608 | 0x09, 0x31, // Usage (Y), | ||
609 | 0x15, 0x81, // Logical Minimum (-127), | ||
610 | 0x25, 0x7F, // Logical Maximum (127), | ||
611 | 0x95, 0x02, // Report Count (2), | ||
612 | 0x75, 0x08, // Report Size (8), | ||
613 | 0x81, 0x06, // Input (Data, Variable, Relative), ;2 position bytes (X & Y), | ||
614 | |||
615 | 0x09, 0x38, // Usage (Wheel), | ||
616 | 0x15, 0x81, // Logical Minimum (-127), | ||
617 | 0x25, 0x7F, // Logical Maximum (127), | ||
618 | 0x95, 0x01, // Report Count (1), | ||
619 | 0x75, 0x08, // Report Size (8), | ||
620 | 0x81, 0x06, // Input (Data, Variable, Relative), | ||
621 | |||
622 | 0x05, 0x0C, // Usage Page (Consumer), | ||
623 | 0x0A, 0x38, 0x02, // Usage (AC Pan (Horizontal wheel)), | ||
624 | 0x15, 0x81, // Logical Minimum (-127), | ||
625 | 0x25, 0x7F, // Logical Maximum (127), | ||
626 | 0x95, 0x01, // Report Count (1), | ||
627 | 0x75, 0x08, // Report Size (8), | ||
628 | 0x81, 0x06, // Input (Data, Variable, Relative), | ||
629 | |||
630 | 0xC0, // End Collection, | ||
631 | 0xC0, // End Collection | ||
632 | } | ||
633 | }; | ||
634 | |||
635 | static void udi_hid_mou_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); | ||
636 | |||
637 | bool udi_hid_mou_enable(void) | ||
638 | { | ||
639 | // Initialize internal values | ||
640 | udi_hid_mou_rate = 0; | ||
641 | udi_hid_mou_protocol = 0; | ||
642 | udi_hid_mou_b_report_trans_ongoing = false; | ||
643 | memset(udi_hid_mou_report, 0, UDI_HID_MOU_REPORT_SIZE); | ||
644 | udi_hid_mou_b_report_valid = false; | ||
645 | return UDI_HID_MOU_ENABLE_EXT(); | ||
646 | } | ||
647 | |||
648 | void udi_hid_mou_disable(void) | ||
649 | { | ||
650 | UDI_HID_MOU_DISABLE_EXT(); | ||
651 | } | ||
652 | |||
653 | bool udi_hid_mou_setup(void) | ||
654 | { | ||
655 | return udi_hid_setup(&udi_hid_mou_rate, | ||
656 | &udi_hid_mou_protocol, | ||
657 | (uint8_t *) &udi_hid_mou_report_desc, | ||
658 | NULL); | ||
659 | } | ||
660 | |||
661 | uint8_t udi_hid_mou_getsetting(void) | ||
662 | { | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | bool udi_hid_mou_send_report(void) | ||
667 | { | ||
668 | if (!main_b_mou_enable) { | ||
669 | return false; | ||
670 | } | ||
671 | |||
672 | if (udi_hid_mou_b_report_trans_ongoing) { | ||
673 | return false; | ||
674 | } | ||
675 | |||
676 | memcpy(udi_hid_mou_report_trans, udi_hid_mou_report, UDI_HID_MOU_REPORT_SIZE); | ||
677 | udi_hid_mou_b_report_valid = false; | ||
678 | udi_hid_mou_b_report_trans_ongoing = | ||
679 | udd_ep_run(UDI_HID_MOU_EP_IN | USB_EP_DIR_IN, | ||
680 | false, | ||
681 | udi_hid_mou_report_trans, | ||
682 | UDI_HID_MOU_REPORT_SIZE, | ||
683 | udi_hid_mou_report_sent); | ||
684 | |||
685 | return udi_hid_mou_b_report_trans_ongoing; | ||
686 | } | ||
687 | |||
688 | static void udi_hid_mou_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep) | ||
689 | { | ||
690 | UNUSED(status); | ||
691 | UNUSED(nb_sent); | ||
692 | UNUSED(ep); | ||
693 | udi_hid_mou_b_report_trans_ongoing = false; | ||
694 | if (udi_hid_mou_b_report_valid) { | ||
695 | udi_hid_mou_send_report(); | ||
696 | } | ||
697 | } | ||
698 | |||
699 | #endif //MOU | ||
700 | |||
701 | //******************************************************************************************** | ||
702 | // RAW | ||
703 | //******************************************************************************************** | ||
704 | #ifdef RAW | ||
705 | |||
706 | bool udi_hid_raw_enable(void); | ||
707 | void udi_hid_raw_disable(void); | ||
708 | bool udi_hid_raw_setup(void); | ||
709 | uint8_t udi_hid_raw_getsetting(void); | ||
710 | |||
711 | UDC_DESC_STORAGE udi_api_t udi_api_hid_raw = { | ||
712 | .enable = (bool(*)(void))udi_hid_raw_enable, | ||
713 | .disable = (void (*)(void))udi_hid_raw_disable, | ||
714 | .setup = (bool(*)(void))udi_hid_raw_setup, | ||
715 | .getsetting = (uint8_t(*)(void))udi_hid_raw_getsetting, | ||
716 | .sof_notify = NULL, | ||
717 | }; | ||
718 | |||
719 | COMPILER_WORD_ALIGNED | ||
720 | static uint8_t udi_hid_raw_rate; | ||
721 | |||
722 | COMPILER_WORD_ALIGNED | ||
723 | static uint8_t udi_hid_raw_protocol; | ||
724 | |||
725 | COMPILER_WORD_ALIGNED | ||
726 | uint8_t udi_hid_raw_report_set[UDI_HID_RAW_REPORT_SIZE]; | ||
727 | |||
728 | static bool udi_hid_raw_b_report_valid; | ||
729 | |||
730 | COMPILER_WORD_ALIGNED | ||
731 | uint8_t udi_hid_raw_report[UDI_HID_RAW_REPORT_SIZE]; | ||
732 | |||
733 | static bool udi_hid_raw_b_report_trans_ongoing; | ||
734 | |||
735 | COMPILER_WORD_ALIGNED | ||
736 | static uint8_t udi_hid_raw_report_trans[UDI_HID_RAW_REPORT_SIZE]; | ||
737 | |||
738 | COMPILER_WORD_ALIGNED | ||
739 | UDC_DESC_STORAGE udi_hid_raw_report_desc_t udi_hid_raw_report_desc = { | ||
740 | { | ||
741 | 0x06, // Usage Page (Vendor Defined) | ||
742 | 0xFF, 0xFF, | ||
743 | 0x0A, // Usage (Mouse) | ||
744 | 0xFF, 0xFF, | ||
745 | 0xA1, 0x01, // Collection (Application) | ||
746 | 0x75, 0x08, // Report Size (8) | ||
747 | 0x15, 0x00, // Logical Minimum (0) | ||
748 | 0x25, 0xFF, // Logical Maximum (255) | ||
749 | 0x95, 0x40, // Report Count | ||
750 | 0x09, 0x01, // Usage (Input) | ||
751 | 0x81, 0x02, // Input (Data | ||
752 | 0x95, 0x40, // Report Count | ||
753 | 0x09, 0x02, // Usage (Output) | ||
754 | 0x91, 0x02, // Output (Data | ||
755 | 0xC0, // End Collection - Consumer Control | ||
756 | } | ||
757 | }; | ||
758 | |||
759 | static bool udi_hid_raw_setreport(void); | ||
760 | static void udi_hid_raw_setreport_valid(void); | ||
761 | |||
762 | static void udi_hid_raw_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); | ||
763 | |||
764 | bool udi_hid_raw_enable(void) | ||
765 | { | ||
766 | // Initialize internal values | ||
767 | udi_hid_raw_rate = 0; | ||
768 | udi_hid_raw_protocol = 0; | ||
769 | udi_hid_raw_b_report_trans_ongoing = false; | ||
770 | memset(udi_hid_raw_report, 0, UDI_HID_RAW_REPORT_SIZE); | ||
771 | udi_hid_raw_b_report_valid = false; | ||
772 | return UDI_HID_RAW_ENABLE_EXT(); | ||
773 | } | ||
774 | |||
775 | void udi_hid_raw_disable(void) | ||
776 | { | ||
777 | UDI_HID_RAW_DISABLE_EXT(); | ||
778 | } | ||
779 | |||
780 | bool udi_hid_raw_setup(void) | ||
781 | { | ||
782 | return udi_hid_setup(&udi_hid_raw_rate, | ||
783 | &udi_hid_raw_protocol, | ||
784 | (uint8_t *) &udi_hid_raw_report_desc, | ||
785 | udi_hid_raw_setreport); | ||
786 | } | ||
787 | |||
788 | uint8_t udi_hid_raw_getsetting(void) | ||
789 | { | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static bool udi_hid_raw_setreport(void) | ||
794 | { | ||
795 | if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8)) | ||
796 | && (0 == (0xFF & udd_g_ctrlreq.req.wValue)) | ||
797 | && (UDI_HID_RAW_REPORT_SIZE == udd_g_ctrlreq.req.wLength)) { | ||
798 | // Report OUT type on report ID 0 from USB Host | ||
799 | udd_g_ctrlreq.payload = udi_hid_raw_report_set; | ||
800 | udd_g_ctrlreq.callback = udi_hid_raw_setreport_valid; //must call routine to transform setreport to LED state | ||
801 | udd_g_ctrlreq.payload_size = UDI_HID_RAW_REPORT_SIZE; | ||
802 | return true; | ||
803 | } | ||
804 | return false; | ||
805 | } | ||
806 | |||
807 | bool udi_hid_raw_send_report(void) | ||
808 | { | ||
809 | if (!main_b_raw_enable) { | ||
810 | return false; | ||
811 | } | ||
812 | |||
813 | if (udi_hid_raw_b_report_trans_ongoing) { | ||
814 | return false; | ||
815 | } | ||
816 | |||
817 | memcpy(udi_hid_raw_report_trans, udi_hid_raw_report,UDI_HID_RAW_REPORT_SIZE); | ||
818 | udi_hid_raw_b_report_valid = false; | ||
819 | udi_hid_raw_b_report_trans_ongoing = | ||
820 | udd_ep_run(UDI_HID_RAW_EP_IN | USB_EP_DIR_IN, | ||
821 | false, | ||
822 | udi_hid_raw_report_trans, | ||
823 | UDI_HID_RAW_REPORT_SIZE, | ||
824 | udi_hid_raw_report_sent); | ||
825 | |||
826 | return udi_hid_raw_b_report_trans_ongoing; | ||
827 | } | ||
828 | |||
829 | static void udi_hid_raw_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep) | ||
830 | { | ||
831 | UNUSED(status); | ||
832 | UNUSED(nb_sent); | ||
833 | UNUSED(ep); | ||
834 | udi_hid_raw_b_report_trans_ongoing = false; | ||
835 | if (udi_hid_raw_b_report_valid) { | ||
836 | udi_hid_raw_send_report(); | ||
837 | } | ||
838 | } | ||
839 | |||
840 | static void udi_hid_raw_setreport_valid(void) | ||
841 | { | ||
842 | |||
843 | } | ||
844 | |||
845 | #endif //RAW | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h new file mode 100644 index 000000000..9a2741534 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device Human Interface Device (HID) keyboard interface. | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UDC_HID_KBD_H_ | ||
48 | #define _UDC_HID_KBD_H_ | ||
49 | |||
50 | #include "udc_desc.h" | ||
51 | #include "udi.h" | ||
52 | |||
53 | #ifdef __cplusplus | ||
54 | extern "C" { | ||
55 | #endif | ||
56 | |||
57 | //****************************************************************************** | ||
58 | // Keyboard interface definitions | ||
59 | //****************************************************************************** | ||
60 | #ifdef KBD | ||
61 | extern UDC_DESC_STORAGE udi_api_t udi_api_hid_kbd; | ||
62 | extern bool udi_hid_kbd_b_report_valid; | ||
63 | extern uint8_t udi_hid_kbd_report_set; | ||
64 | bool udi_hid_kbd_send_report(void); | ||
65 | #endif //KBD | ||
66 | |||
67 | //******************************************************************************************** | ||
68 | // NKRO Keyboard | ||
69 | //******************************************************************************************** | ||
70 | #ifdef NKRO | ||
71 | extern UDC_DESC_STORAGE udi_api_t udi_api_hid_nkro; | ||
72 | extern bool udi_hid_nkro_b_report_valid; | ||
73 | bool udi_hid_nkro_send_report(void); | ||
74 | #endif //NKRO | ||
75 | |||
76 | //******************************************************************************************** | ||
77 | // SYS-CTRL interface | ||
78 | //******************************************************************************************** | ||
79 | #ifdef EXK | ||
80 | extern UDC_DESC_STORAGE udi_api_t udi_api_hid_exk; | ||
81 | extern bool udi_hid_exk_b_report_valid; | ||
82 | extern uint8_t udi_hid_exk_report_set; | ||
83 | bool udi_hid_exk_send_report(void); | ||
84 | #endif //EXK | ||
85 | |||
86 | //******************************************************************************************** | ||
87 | // MOU Mouse | ||
88 | //******************************************************************************************** | ||
89 | #ifdef MOU | ||
90 | extern UDC_DESC_STORAGE udi_api_t udi_api_hid_mou; | ||
91 | extern bool udi_hid_mou_b_report_valid; | ||
92 | bool udi_hid_mou_send_report(void); | ||
93 | #endif //MOU | ||
94 | |||
95 | //******************************************************************************************** | ||
96 | // RAW Raw | ||
97 | //******************************************************************************************** | ||
98 | #ifdef RAW | ||
99 | extern UDC_DESC_STORAGE udi_api_t udi_api_hid_raw; | ||
100 | bool udi_hid_raw_send_report(void); | ||
101 | #endif //RAW | ||
102 | |||
103 | //@} | ||
104 | |||
105 | #ifdef __cplusplus | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | #endif // _UDC_HID_KBD_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h new file mode 100644 index 000000000..db5db17ed --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Default HID keyboard configuration for a USB Device | ||
5 | * with a single interface HID keyboard | ||
6 | * | ||
7 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
8 | * | ||
9 | * \asf_license_start | ||
10 | * | ||
11 | * \page License | ||
12 | * | ||
13 | * Redistribution and use in source and binary forms, with or without | ||
14 | * modification, are permitted provided that the following conditions are met: | ||
15 | * | ||
16 | * 1. Redistributions of source code must retain the above copyright notice, | ||
17 | * this list of conditions and the following disclaimer. | ||
18 | * | ||
19 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
20 | * this list of conditions and the following disclaimer in the documentation | ||
21 | * and/or other materials provided with the distribution. | ||
22 | * | ||
23 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
24 | * from this software without specific prior written permission. | ||
25 | * | ||
26 | * 4. This software may only be redistributed and used in connection with an | ||
27 | * Atmel microcontroller product. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
30 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
31 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
32 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
33 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
37 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
38 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | * | ||
41 | * \asf_license_stop | ||
42 | * | ||
43 | */ | ||
44 | /* | ||
45 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
46 | */ | ||
47 | |||
48 | #ifndef _UDI_HID_KBD_CONF_H_ | ||
49 | #define _UDI_HID_KBD_CONF_H_ | ||
50 | |||
51 | /** | ||
52 | * \addtogroup udi_hid_keyboard_group_single_desc | ||
53 | * @{ | ||
54 | */ | ||
55 | |||
56 | #include "udi_device_conf.h" | ||
57 | |||
58 | #include "udi_hid_kbd.h" | ||
59 | |||
60 | #endif // _UDI_HID_KBD_CONF_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c new file mode 100644 index 000000000..16bd4e514 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Default descriptors for a USB Device | ||
5 | * with a single interface HID keyboard | ||
6 | * | ||
7 | * Copyright (c) 2009-2016 Atmel Corporation. All rights reserved. | ||
8 | * | ||
9 | * \asf_license_start | ||
10 | * | ||
11 | * \page License | ||
12 | * | ||
13 | * Redistribution and use in source and binary forms, with or without | ||
14 | * modification, are permitted provided that the following conditions are met: | ||
15 | * | ||
16 | * 1. Redistributions of source code must retain the above copyright notice, | ||
17 | * this list of conditions and the following disclaimer. | ||
18 | * | ||
19 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
20 | * this list of conditions and the following disclaimer in the documentation | ||
21 | * and/or other materials provided with the distribution. | ||
22 | * | ||
23 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
24 | * from this software without specific prior written permission. | ||
25 | * | ||
26 | * 4. This software may only be redistributed and used in connection with an | ||
27 | * Atmel microcontroller product. | ||
28 | * | ||
29 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
30 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
31 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
32 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
33 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
37 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
38 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGE. | ||
40 | * | ||
41 | * \asf_license_stop | ||
42 | * | ||
43 | */ | ||
44 | /* | ||
45 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
46 | */ | ||
47 | |||
48 | #include "conf_usb.h" | ||
49 | #include "usb_protocol.h" | ||
50 | #include "udc_desc.h" | ||
51 | #include "udi_device_conf.h" | ||
52 | #include "udi_hid_kbd.h" | ||
53 | #include "udi_cdc.h" | ||
54 | |||
55 | /** | ||
56 | * \ingroup udi_hid_keyboard_group | ||
57 | * \defgroup udi_hid_keyboard_group_single_desc USB device descriptors for a single interface | ||
58 | * | ||
59 | * The following structures provide the USB device descriptors required | ||
60 | * for USB Device with a single interface HID keyboard. | ||
61 | * | ||
62 | * It is ready to use and do not require more definition. | ||
63 | * @{ | ||
64 | */ | ||
65 | |||
66 | //! USB Device Descriptor | ||
67 | COMPILER_WORD_ALIGNED | ||
68 | UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = { | ||
69 | .bLength = sizeof(usb_dev_desc_t), | ||
70 | .bDescriptorType = USB_DT_DEVICE, | ||
71 | .bcdUSB = LE16(USB_V2_0), | ||
72 | .bDeviceClass = DEVICE_CLASS, | ||
73 | .bDeviceSubClass = DEVICE_SUBCLASS, | ||
74 | .bDeviceProtocol = DEVICE_PROTOCOL, | ||
75 | .bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE, | ||
76 | .idVendor = LE16(USB_DEVICE_VENDOR_ID), | ||
77 | .idProduct = LE16(USB_DEVICE_PRODUCT_ID), | ||
78 | .bcdDevice = LE16(USB_DEVICE_VERSION), | ||
79 | #ifdef USB_DEVICE_MANUFACTURE_NAME | ||
80 | .iManufacturer = 1, | ||
81 | #else | ||
82 | .iManufacturer = 0, // No manufacture string | ||
83 | #endif | ||
84 | #ifdef USB_DEVICE_PRODUCT_NAME | ||
85 | .iProduct = 2, | ||
86 | #else | ||
87 | .iProduct = 0, // No product string | ||
88 | #endif | ||
89 | #if (defined USB_DEVICE_SERIAL_NAME || defined USB_DEVICE_GET_SERIAL_NAME_POINTER) | ||
90 | .iSerialNumber = 3, | ||
91 | #else | ||
92 | .iSerialNumber = 0, // No serial string | ||
93 | #endif | ||
94 | .bNumConfigurations = 1 | ||
95 | }; | ||
96 | |||
97 | #if 0 | ||
98 | #ifdef USB_DEVICE_HS_SUPPORT | ||
99 | //! USB Device Qualifier Descriptor for HS | ||
100 | COMPILER_WORD_ALIGNED | ||
101 | UDC_DESC_STORAGE usb_dev_qual_desc_t udc_device_qual = { | ||
102 | .bLength = sizeof(usb_dev_qual_desc_t), | ||
103 | .bDescriptorType = USB_DT_DEVICE_QUALIFIER, | ||
104 | .bcdUSB = LE16(USB_V2_0), | ||
105 | .bDeviceClass = 0, | ||
106 | .bDeviceSubClass = 0, | ||
107 | .bDeviceProtocol = 0, | ||
108 | .bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE, | ||
109 | .bNumConfigurations = 1 | ||
110 | }; | ||
111 | #endif | ||
112 | #endif | ||
113 | |||
114 | //! USB Device Configuration Descriptor filled for FS and HS | ||
115 | COMPILER_WORD_ALIGNED | ||
116 | UDC_DESC_STORAGE udc_desc_t udc_desc = { | ||
117 | .conf.bLength = sizeof(usb_conf_desc_t), | ||
118 | .conf.bDescriptorType = USB_DT_CONFIGURATION, | ||
119 | .conf.wTotalLength = LE16(sizeof(udc_desc_t)), | ||
120 | .conf.bNumInterfaces = USB_DEVICE_NB_INTERFACE, | ||
121 | .conf.bConfigurationValue = 1, | ||
122 | .conf.iConfiguration = 0, | ||
123 | .conf.bmAttributes = /* USB_CONFIG_ATTR_MUST_SET | */ USB_DEVICE_ATTR, | ||
124 | .conf.bMaxPower = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER), | ||
125 | #ifdef KBD | ||
126 | .hid_kbd = UDI_HID_KBD_DESC, | ||
127 | #endif | ||
128 | #ifdef RAW | ||
129 | .hid_raw = UDI_HID_RAW_DESC, | ||
130 | #endif | ||
131 | #ifdef MOU | ||
132 | .hid_mou = UDI_HID_MOU_DESC, | ||
133 | #endif | ||
134 | #ifdef EXK | ||
135 | .hid_exk = UDI_HID_EXK_DESC, | ||
136 | #endif | ||
137 | #ifdef NKRO | ||
138 | .hid_nkro = UDI_HID_NKRO_DESC, | ||
139 | #endif | ||
140 | #ifdef CDC | ||
141 | .cdc_serial = CDC_DESCRIPTOR, | ||
142 | #endif | ||
143 | }; | ||
144 | |||
145 | UDC_DESC_STORAGE udi_api_t *udi_apis[USB_DEVICE_NB_INTERFACE] = { | ||
146 | #ifdef KBD | ||
147 | &udi_api_hid_kbd, | ||
148 | #endif | ||
149 | #ifdef RAW | ||
150 | &udi_api_hid_raw, | ||
151 | #endif | ||
152 | #ifdef MOU | ||
153 | &udi_api_hid_mou, | ||
154 | #endif | ||
155 | #ifdef EXK | ||
156 | &udi_api_hid_exk, | ||
157 | #endif | ||
158 | #ifdef NKRO | ||
159 | &udi_api_hid_nkro, | ||
160 | #endif | ||
161 | #ifdef CDC | ||
162 | &udi_api_cdc_comm, &udi_api_cdc_data, | ||
163 | #endif | ||
164 | }; | ||
165 | |||
166 | //! Add UDI with USB Descriptors FS & HS | ||
167 | UDC_DESC_STORAGE udc_config_speed_t udc_config_fshs[1] = {{ | ||
168 | .desc = (usb_conf_desc_t UDC_DESC_STORAGE*)&udc_desc, | ||
169 | .udi_apis = udi_apis, | ||
170 | }}; | ||
171 | |||
172 | //! Add all information about USB Device in global structure for UDC | ||
173 | UDC_DESC_STORAGE udc_config_t udc_config = { | ||
174 | .confdev_lsfs = &udc_device_desc, | ||
175 | .conf_lsfs = udc_config_fshs, | ||
176 | }; | ||
177 | |||
178 | //@} | ||
179 | //@} | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/ui.c b/tmk_core/protocol/arm_atsam/usb/ui.c new file mode 100644 index 000000000..031678b64 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/ui.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief User Interface | ||
5 | * | ||
6 | * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef ARM_MATH_CM4 | ||
48 | #define ARM_MATH_CM4 | ||
49 | #endif | ||
50 | |||
51 | #undef LITTLE_ENDIAN //redefined in samd51j18a.h | ||
52 | #include "samd51j18a.h" | ||
53 | #include "ui.h" | ||
54 | |||
55 | volatile uint8_t usb_state; | ||
56 | |||
57 | //! Sequence process running each \c SEQUENCE_PERIOD ms | ||
58 | #define SEQUENCE_PERIOD 150 | ||
59 | |||
60 | #if 0 | ||
61 | /* Interrupt on "pin change" from push button to do wakeup on USB | ||
62 | * Note: | ||
63 | * This interrupt is enable when the USB host enable remote wakeup feature | ||
64 | * This interrupt wakeup the CPU if this one is in idle mode | ||
65 | */ | ||
66 | static void ui_wakeup_handler(void) | ||
67 | { | ||
68 | /* It is a wakeup then send wakeup USB */ | ||
69 | udc_remotewakeup(); | ||
70 | } | ||
71 | #endif | ||
72 | |||
73 | void ui_init(void) | ||
74 | { | ||
75 | usb_state = USB_STATE_POWERUP; | ||
76 | } | ||
77 | |||
78 | void ui_powerdown(void) | ||
79 | { | ||
80 | usb_state = USB_STATE_POWERDOWN; | ||
81 | } | ||
82 | |||
83 | void ui_wakeup_enable(void) | ||
84 | { | ||
85 | |||
86 | } | ||
87 | |||
88 | void ui_wakeup_disable(void) | ||
89 | { | ||
90 | |||
91 | } | ||
92 | |||
93 | void ui_wakeup(void) | ||
94 | { | ||
95 | usb_state = USB_STATE_POWERUP; | ||
96 | } | ||
97 | |||
98 | void ui_process(uint16_t framenumber) | ||
99 | { | ||
100 | |||
101 | } | ||
102 | |||
103 | void ui_kbd_led(uint8_t value) | ||
104 | { | ||
105 | |||
106 | } | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/ui.h b/tmk_core/protocol/arm_atsam/usb/ui.h new file mode 100644 index 000000000..3d899e669 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/ui.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Common User Interface for HID Keyboard application | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _UI_H_ | ||
48 | #define _UI_H_ | ||
49 | |||
50 | extern volatile uint8_t usb_state; | ||
51 | |||
52 | #define USB_STATE_UNKNOWN 0 | ||
53 | #define USB_STATE_POWERDOWN 1 | ||
54 | #define USB_STATE_POWERUP 2 | ||
55 | |||
56 | //! \brief Initializes the user interface | ||
57 | void ui_init(void); | ||
58 | |||
59 | //! \brief Enters the user interface in power down mode | ||
60 | void ui_powerdown(void); | ||
61 | |||
62 | //! \brief Enables the asynchronous interrupts of the user interface | ||
63 | void ui_wakeup_enable(void); | ||
64 | |||
65 | //! \brief Disables the asynchronous interrupts of the user interface | ||
66 | void ui_wakeup_disable(void); | ||
67 | |||
68 | //! \brief Exits the user interface of power down mode | ||
69 | void ui_wakeup(void); | ||
70 | |||
71 | /*! \brief This process is called each 1ms | ||
72 | * It is called only if the USB interface is enabled. | ||
73 | * | ||
74 | * \param framenumber Current frame number | ||
75 | */ | ||
76 | void ui_process(uint16_t framenumber); | ||
77 | |||
78 | /*! \brief Turn on or off the keyboard LEDs | ||
79 | */ | ||
80 | void ui_kbd_led(uint8_t value); | ||
81 | |||
82 | #endif // _UI_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb.c b/tmk_core/protocol/arm_atsam/usb/usb.c new file mode 100644 index 000000000..d30d76dd1 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb.c | |||
@@ -0,0 +1,1144 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief SAM USB Driver. | ||
5 | * | ||
6 | * Copyright (C) 2014-2016 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #define DEVICE_MODE_ONLY true | ||
48 | #define SAMD11 DEVICE_MODE_ONLY | ||
49 | |||
50 | #ifndef ARM_MATH_CM4 | ||
51 | #define ARM_MATH_CM4 | ||
52 | #endif | ||
53 | |||
54 | #include "compiler.h" | ||
55 | #undef LITTLE_ENDIAN //redefined in samd51j18a.h | ||
56 | #include "samd51j18a.h" | ||
57 | #include <stdbool.h> | ||
58 | #include <string.h> | ||
59 | #include "arm_math.h" | ||
60 | #include "status_codes.h" | ||
61 | #include "usb.h" | ||
62 | |||
63 | /** Fields definition from a LPM TOKEN */ | ||
64 | #define USB_LPM_ATTRIBUT_BLINKSTATE_MASK (0xF << 0) | ||
65 | #define USB_LPM_ATTRIBUT_HIRD_MASK (0xF << 4) | ||
66 | #define USB_LPM_ATTRIBUT_REMOTEWAKE_MASK (1 << 8) | ||
67 | #define USB_LPM_ATTRIBUT_BLINKSTATE(value) ((value & 0xF) << 0) | ||
68 | #define USB_LPM_ATTRIBUT_HIRD(value) ((value & 0xF) << 4) | ||
69 | #define USB_LPM_ATTRIBUT_REMOTEWAKE(value) ((value & 1) << 8) | ||
70 | #define USB_LPM_ATTRIBUT_BLINKSTATE_L1 USB_LPM_ATTRIBUT_BLINKSTATE(1) | ||
71 | |||
72 | /** | ||
73 | * \brief Mask selecting the index part of an endpoint address | ||
74 | */ | ||
75 | #define USB_EP_ADDR_MASK 0x0f | ||
76 | |||
77 | /** | ||
78 | * \brief Endpoint transfer direction is IN | ||
79 | */ | ||
80 | #define USB_EP_DIR_IN 0x80 | ||
81 | |||
82 | /** | ||
83 | * \brief Endpoint transfer direction is OUT | ||
84 | */ | ||
85 | #define USB_EP_DIR_OUT 0x00 | ||
86 | |||
87 | /** | ||
88 | * \name USB SRAM data containing pipe descriptor table | ||
89 | * The content of the USB SRAM can be : | ||
90 | * - modified by USB hardware interface to update pipe status. | ||
91 | * Thereby, it is read by software. | ||
92 | * - modified by USB software to control pipe. | ||
93 | * Thereby, it is read by hardware. | ||
94 | * This data section is volatile. | ||
95 | * | ||
96 | * @{ | ||
97 | */ | ||
98 | COMPILER_PACK_SET(1) | ||
99 | COMPILER_WORD_ALIGNED | ||
100 | union { | ||
101 | UsbDeviceDescriptor usb_endpoint_table[USB_EPT_NUM]; | ||
102 | } usb_descriptor_table; | ||
103 | COMPILER_PACK_RESET() | ||
104 | /** @} */ | ||
105 | |||
106 | /** | ||
107 | * \brief Local USB module instance | ||
108 | */ | ||
109 | static struct usb_module *_usb_instances; | ||
110 | |||
111 | /* Device LPM callback variable */ | ||
112 | static uint32_t device_callback_lpm_wakeup_enable; | ||
113 | |||
114 | /** | ||
115 | * \brief Device endpoint callback parameter variable, used to transfer info to UDD wrapper layer | ||
116 | */ | ||
117 | static struct usb_endpoint_callback_parameter ep_callback_para; | ||
118 | |||
119 | /** | ||
120 | * \internal USB Device IRQ Mask Bits Map | ||
121 | */ | ||
122 | static const uint16_t _usb_device_irq_bits[USB_DEVICE_CALLBACK_N] = { | ||
123 | USB_DEVICE_INTFLAG_SOF, | ||
124 | USB_DEVICE_INTFLAG_EORST, | ||
125 | USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_EORSM | USB_DEVICE_INTFLAG_UPRSM, | ||
126 | USB_DEVICE_INTFLAG_RAMACER, | ||
127 | USB_DEVICE_INTFLAG_SUSPEND, | ||
128 | USB_DEVICE_INTFLAG_LPMNYET, | ||
129 | USB_DEVICE_INTFLAG_LPMSUSP, | ||
130 | }; | ||
131 | |||
132 | /** | ||
133 | * \internal USB Device IRQ Mask Bits Map | ||
134 | */ | ||
135 | static const uint8_t _usb_endpoint_irq_bits[USB_DEVICE_EP_CALLBACK_N] = { | ||
136 | USB_DEVICE_EPINTFLAG_TRCPT_Msk, | ||
137 | USB_DEVICE_EPINTFLAG_TRFAIL_Msk, | ||
138 | USB_DEVICE_EPINTFLAG_RXSTP, | ||
139 | USB_DEVICE_EPINTFLAG_STALL_Msk | ||
140 | }; | ||
141 | |||
142 | /** | ||
143 | * \brief Registers a USB device callback | ||
144 | * | ||
145 | * Registers a callback function which is implemented by the user. | ||
146 | * | ||
147 | * \note The callback must be enabled by \ref usb_device_enable_callback, | ||
148 | * in order for the interrupt handler to call it when the conditions for the | ||
149 | * callback type is met. | ||
150 | * | ||
151 | * \param[in] module_inst Pointer to USB software instance struct | ||
152 | * \param[in] callback_type Callback type given by an enum | ||
153 | * \param[in] callback_func Pointer to callback function | ||
154 | * | ||
155 | * \return Status of the registration operation. | ||
156 | * \retval STATUS_OK The callback was registered successfully. | ||
157 | */ | ||
158 | enum status_code usb_device_register_callback(struct usb_module *module_inst, | ||
159 | enum usb_device_callback callback_type, | ||
160 | usb_device_callback_t callback_func) | ||
161 | { | ||
162 | /* Sanity check arguments */ | ||
163 | Assert(module_inst); | ||
164 | Assert(callback_func); | ||
165 | |||
166 | /* Register callback function */ | ||
167 | module_inst->device_callback[callback_type] = callback_func; | ||
168 | |||
169 | /* Set the bit corresponding to the callback_type */ | ||
170 | module_inst->device_registered_callback_mask |= _usb_device_irq_bits[callback_type]; | ||
171 | |||
172 | return STATUS_OK; | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * \brief Unregisters a USB device callback | ||
177 | * | ||
178 | * Unregisters an asynchronous callback implemented by the user. Removing it | ||
179 | * from the internal callback registration table. | ||
180 | * | ||
181 | * \param[in] module_inst Pointer to USB software instance struct | ||
182 | * \param[in] callback_type Callback type given by an enum | ||
183 | * | ||
184 | * \return Status of the de-registration operation. | ||
185 | * \retval STATUS_OK The callback was unregistered successfully. | ||
186 | */ | ||
187 | enum status_code usb_device_unregister_callback(struct usb_module *module_inst, | ||
188 | enum usb_device_callback callback_type) | ||
189 | { | ||
190 | /* Sanity check arguments */ | ||
191 | Assert(module_inst); | ||
192 | |||
193 | /* Unregister callback function */ | ||
194 | module_inst->device_callback[callback_type] = NULL; | ||
195 | |||
196 | /* Clear the bit corresponding to the callback_type */ | ||
197 | module_inst->device_registered_callback_mask &= ~_usb_device_irq_bits[callback_type]; | ||
198 | |||
199 | return STATUS_OK; | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * \brief Enables USB device callback generation for a given type. | ||
204 | * | ||
205 | * Enables asynchronous callbacks for a given logical type. | ||
206 | * This must be called before USB device generate callback events. | ||
207 | * | ||
208 | * \param[in] module_inst Pointer to USB software instance struct | ||
209 | * \param[in] callback_type Callback type given by an enum | ||
210 | * | ||
211 | * \return Status of the callback enable operation. | ||
212 | * \retval STATUS_OK The callback was enabled successfully. | ||
213 | */ | ||
214 | enum status_code usb_device_enable_callback(struct usb_module *module_inst, | ||
215 | enum usb_device_callback callback_type) | ||
216 | { | ||
217 | /* Sanity check arguments */ | ||
218 | Assert(module_inst); | ||
219 | Assert(module_inst->hw); | ||
220 | |||
221 | /* clear related flag */ | ||
222 | module_inst->hw->DEVICE.INTFLAG.reg = _usb_device_irq_bits[callback_type]; | ||
223 | |||
224 | /* Enable callback */ | ||
225 | module_inst->device_enabled_callback_mask |= _usb_device_irq_bits[callback_type]; | ||
226 | |||
227 | module_inst->hw->DEVICE.INTENSET.reg = _usb_device_irq_bits[callback_type]; | ||
228 | |||
229 | return STATUS_OK; | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * \brief Disables USB device callback generation for a given type. | ||
234 | * | ||
235 | * Disables asynchronous callbacks for a given logical type. | ||
236 | * | ||
237 | * \param[in] module_inst Pointer to USB software instance struct | ||
238 | * \param[in] callback_type Callback type given by an enum | ||
239 | * | ||
240 | * \return Status of the callback disable operation. | ||
241 | * \retval STATUS_OK The callback was disabled successfully. | ||
242 | */ | ||
243 | enum status_code usb_device_disable_callback(struct usb_module *module_inst, | ||
244 | enum usb_device_callback callback_type) | ||
245 | { | ||
246 | /* Sanity check arguments */ | ||
247 | Assert(module_inst); | ||
248 | Assert(module_inst->hw); | ||
249 | |||
250 | /* Disable callback */ | ||
251 | module_inst->device_enabled_callback_mask &= ~_usb_device_irq_bits[callback_type]; | ||
252 | |||
253 | module_inst->hw->DEVICE.INTENCLR.reg = _usb_device_irq_bits[callback_type]; | ||
254 | |||
255 | return STATUS_OK; | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * \brief Registers a USB device endpoint callback | ||
260 | * | ||
261 | * Registers a callback function which is implemented by the user. | ||
262 | * | ||
263 | * \note The callback must be enabled by \ref usb_device_endpoint_enable_callback, | ||
264 | * in order for the interrupt handler to call it when the conditions for the | ||
265 | * callback type is met. | ||
266 | * | ||
267 | * \param[in] module_inst Pointer to USB software instance struct | ||
268 | * \param[in] ep_num Endpoint to configure | ||
269 | * \param[in] callback_type Callback type given by an enum | ||
270 | * \param[in] callback_func Pointer to callback function | ||
271 | * | ||
272 | * \return Status of the registration operation. | ||
273 | * \retval STATUS_OK The callback was registered successfully. | ||
274 | */ | ||
275 | enum status_code usb_device_endpoint_register_callback( | ||
276 | struct usb_module *module_inst, uint8_t ep_num, | ||
277 | enum usb_device_endpoint_callback callback_type, | ||
278 | usb_device_endpoint_callback_t callback_func) | ||
279 | { | ||
280 | /* Sanity check arguments */ | ||
281 | Assert(module_inst); | ||
282 | Assert(ep_num < USB_EPT_NUM); | ||
283 | Assert(callback_func); | ||
284 | |||
285 | /* Register callback function */ | ||
286 | module_inst->device_endpoint_callback[ep_num][callback_type] = callback_func; | ||
287 | |||
288 | /* Set the bit corresponding to the callback_type */ | ||
289 | module_inst->device_endpoint_registered_callback_mask[ep_num] |= _usb_endpoint_irq_bits[callback_type]; | ||
290 | |||
291 | return STATUS_OK; | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * \brief Unregisters a USB device endpoint callback | ||
296 | * | ||
297 | * Unregisters an callback implemented by the user. Removing it | ||
298 | * from the internal callback registration table. | ||
299 | * | ||
300 | * \param[in] module_inst Pointer to USB software instance struct | ||
301 | * \param[in] ep_num Endpoint to configure | ||
302 | * \param[in] callback_type Callback type given by an enum | ||
303 | * | ||
304 | * \return Status of the de-registration operation. | ||
305 | * \retval STATUS_OK The callback was unregistered successfully. | ||
306 | */ | ||
307 | enum status_code usb_device_endpoint_unregister_callback( | ||
308 | struct usb_module *module_inst, uint8_t ep_num, | ||
309 | enum usb_device_endpoint_callback callback_type) | ||
310 | { | ||
311 | /* Sanity check arguments */ | ||
312 | Assert(module_inst); | ||
313 | Assert(ep_num < USB_EPT_NUM); | ||
314 | |||
315 | /* Unregister callback function */ | ||
316 | module_inst->device_endpoint_callback[ep_num][callback_type] = NULL; | ||
317 | |||
318 | /* Clear the bit corresponding to the callback_type */ | ||
319 | module_inst->device_endpoint_registered_callback_mask[ep_num] &= ~_usb_endpoint_irq_bits[callback_type]; | ||
320 | |||
321 | return STATUS_OK; | ||
322 | } | ||
323 | |||
324 | /** | ||
325 | * \brief Enables USB device endpoint callback generation for a given type. | ||
326 | * | ||
327 | * Enables callbacks for a given logical type. | ||
328 | * This must be called before USB device pipe generate callback events. | ||
329 | * | ||
330 | * \param[in] module_inst Pointer to USB software instance struct | ||
331 | * \param[in] ep Endpoint to configure | ||
332 | * \param[in] callback_type Callback type given by an enum | ||
333 | * | ||
334 | * \return Status of the callback enable operation. | ||
335 | * \retval STATUS_OK The callback was enabled successfully. | ||
336 | */ | ||
337 | enum status_code usb_device_endpoint_enable_callback( | ||
338 | struct usb_module *module_inst, uint8_t ep, | ||
339 | enum usb_device_endpoint_callback callback_type) | ||
340 | { | ||
341 | /* Sanity check arguments */ | ||
342 | Assert(module_inst); | ||
343 | Assert(module_inst->hw); | ||
344 | |||
345 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
346 | Assert(ep_num < USB_EPT_NUM); | ||
347 | |||
348 | /* Enable callback */ | ||
349 | module_inst->device_endpoint_enabled_callback_mask[ep_num] |= _usb_endpoint_irq_bits[callback_type]; | ||
350 | |||
351 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRCPT) { | ||
352 | if (ep_num == 0) { // control endpoint | ||
353 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1; | ||
354 | } else if (ep & USB_EP_DIR_IN) { | ||
355 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT1; | ||
356 | } else { | ||
357 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0; | ||
358 | } | ||
359 | } | ||
360 | |||
361 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL) { | ||
362 | if (ep_num == 0) { // control endpoint | ||
363 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRFAIL0 | USB_DEVICE_EPINTENSET_TRFAIL1; | ||
364 | } else if (ep & USB_EP_DIR_IN) { | ||
365 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRFAIL1; | ||
366 | } else { | ||
367 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRFAIL0; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_RXSTP) { | ||
372 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_RXSTP; | ||
373 | } | ||
374 | |||
375 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_STALL) { | ||
376 | if (ep & USB_EP_DIR_IN) { | ||
377 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_STALL1; | ||
378 | } else { | ||
379 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENSET.reg = USB_DEVICE_EPINTENSET_STALL0; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | return STATUS_OK; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * \brief Disables USB device endpoint callback generation for a given type. | ||
388 | * | ||
389 | * Disables callbacks for a given logical type. | ||
390 | * | ||
391 | * \param[in] module_inst Pointer to USB software instance struct | ||
392 | * \param[in] ep Endpoint to configure | ||
393 | * \param[in] callback_type Callback type given by an enum | ||
394 | * | ||
395 | * \return Status of the callback disable operation. | ||
396 | * \retval STATUS_OK The callback was disabled successfully. | ||
397 | */ | ||
398 | enum status_code usb_device_endpoint_disable_callback( | ||
399 | struct usb_module *module_inst, uint8_t ep, | ||
400 | enum usb_device_endpoint_callback callback_type) | ||
401 | { | ||
402 | /* Sanity check arguments */ | ||
403 | Assert(module_inst); | ||
404 | Assert(module_inst->hw); | ||
405 | |||
406 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
407 | Assert(ep_num < USB_EPT_NUM); | ||
408 | |||
409 | /* Enable callback */ | ||
410 | module_inst->device_endpoint_enabled_callback_mask[ep_num] &= ~_usb_endpoint_irq_bits[callback_type]; | ||
411 | |||
412 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRCPT) { | ||
413 | if (ep_num == 0) { // control endpoint | ||
414 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRCPT0 | USB_DEVICE_EPINTENCLR_TRCPT1; | ||
415 | } else if (ep & USB_EP_DIR_IN) { | ||
416 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRCPT1; | ||
417 | } else { | ||
418 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRCPT0; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL) { | ||
423 | if (ep_num == 0) { // control endpoint | ||
424 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRFAIL0 | USB_DEVICE_EPINTENCLR_TRFAIL1; | ||
425 | } else if (ep & USB_EP_DIR_IN) { | ||
426 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRFAIL1; | ||
427 | } else { | ||
428 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRFAIL0; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_RXSTP) { | ||
433 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_RXSTP; | ||
434 | } | ||
435 | |||
436 | if (callback_type == USB_DEVICE_ENDPOINT_CALLBACK_STALL) { | ||
437 | if (ep & USB_EP_DIR_IN) { | ||
438 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_STALL1; | ||
439 | } else { | ||
440 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_STALL0; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | return STATUS_OK; | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * \brief Initializes an USB device endpoint configuration structure to defaults. | ||
449 | * | ||
450 | * Initializes a given USB device endpoint configuration structure to a | ||
451 | * set of known default values. This function should be called on all new | ||
452 | * instances of these configuration structures before being modified by the | ||
453 | * user application. | ||
454 | * | ||
455 | * The default configuration is as follows: | ||
456 | * \li endpoint address is 0 | ||
457 | * \li endpoint size is 8 bytes | ||
458 | * \li auto_zlp is false | ||
459 | * \li endpoint type is control | ||
460 | * | ||
461 | * \param[out] ep_config Configuration structure to initialize to default values | ||
462 | */ | ||
463 | void usb_device_endpoint_get_config_defaults(struct usb_device_endpoint_config *ep_config) | ||
464 | { | ||
465 | /* Sanity check arguments */ | ||
466 | Assert(ep_config); | ||
467 | |||
468 | /* Write default config to config struct */ | ||
469 | ep_config->ep_address = 0; | ||
470 | ep_config->ep_size = USB_ENDPOINT_8_BYTE; | ||
471 | ep_config->auto_zlp = false; | ||
472 | ep_config->ep_type = USB_DEVICE_ENDPOINT_TYPE_CONTROL; | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * \brief Writes an USB device endpoint configuration to the hardware module. | ||
477 | * | ||
478 | * Writes out a given configuration of an USB device endpoint | ||
479 | * configuration to the hardware module. If the pipe is already configured, | ||
480 | * the new configuration will replace the existing one. | ||
481 | * | ||
482 | * \param[in] module_inst Pointer to USB software instance struct | ||
483 | * \param[in] ep_config Configuration settings for the endpoint | ||
484 | * | ||
485 | * \return Status of the device endpoint configuration operation | ||
486 | * \retval STATUS_OK The device endpoint was configured successfully | ||
487 | * \retval STATUS_ERR_DENIED The endpoint address is already configured | ||
488 | */ | ||
489 | enum status_code usb_device_endpoint_set_config(struct usb_module *module_inst, | ||
490 | struct usb_device_endpoint_config *ep_config) | ||
491 | { | ||
492 | /* Sanity check arguments */ | ||
493 | Assert(module_inst); | ||
494 | Assert(ep_config); | ||
495 | |||
496 | uint8_t ep_num = ep_config->ep_address & USB_EP_ADDR_MASK; | ||
497 | uint8_t ep_bank = (ep_config->ep_address & USB_EP_DIR_IN) ? 1 : 0; | ||
498 | |||
499 | switch (ep_config->ep_type) { | ||
500 | case USB_DEVICE_ENDPOINT_TYPE_DISABLE: | ||
501 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0) | USB_DEVICE_EPCFG_EPTYPE1(0); | ||
502 | return STATUS_OK; | ||
503 | |||
504 | case USB_DEVICE_ENDPOINT_TYPE_CONTROL: | ||
505 | if ((module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE0_Msk) == 0 && \ | ||
506 | (module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE1_Msk) == 0) { | ||
507 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); | ||
508 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; | ||
509 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; | ||
510 | } else { | ||
511 | return STATUS_ERR_DENIED; | ||
512 | } | ||
513 | if (true == ep_config->auto_zlp) { | ||
514 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[0].PCKSIZE.reg |= USB_DEVICE_PCKSIZE_AUTO_ZLP; | ||
515 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.reg |= USB_DEVICE_PCKSIZE_AUTO_ZLP; | ||
516 | } else { | ||
517 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[0].PCKSIZE.reg &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP; | ||
518 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.reg &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP; | ||
519 | } | ||
520 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[0].PCKSIZE.bit.SIZE = ep_config->ep_size; | ||
521 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.SIZE = ep_config->ep_size; | ||
522 | return STATUS_OK; | ||
523 | |||
524 | case USB_DEVICE_ENDPOINT_TYPE_ISOCHRONOUS: | ||
525 | if (ep_bank) { | ||
526 | if ((module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE1_Msk) == 0){ | ||
527 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg |= USB_DEVICE_EPCFG_EPTYPE1(2); | ||
528 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; | ||
529 | } else { | ||
530 | return STATUS_ERR_DENIED; | ||
531 | } | ||
532 | } else { | ||
533 | if ((module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE0_Msk) == 0){ | ||
534 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg |= USB_DEVICE_EPCFG_EPTYPE0(2); | ||
535 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; | ||
536 | } else { | ||
537 | return STATUS_ERR_DENIED; | ||
538 | } | ||
539 | } | ||
540 | break; | ||
541 | |||
542 | case USB_DEVICE_ENDPOINT_TYPE_BULK: | ||
543 | if (ep_bank) { | ||
544 | if ((module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE1_Msk) == 0){ | ||
545 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg |= USB_DEVICE_EPCFG_EPTYPE1(3); | ||
546 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; | ||
547 | } else { | ||
548 | return STATUS_ERR_DENIED; | ||
549 | } | ||
550 | } else { | ||
551 | if ((module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE0_Msk) == 0){ | ||
552 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg |= USB_DEVICE_EPCFG_EPTYPE0(3); | ||
553 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; | ||
554 | } else { | ||
555 | return STATUS_ERR_DENIED; | ||
556 | } | ||
557 | } | ||
558 | break; | ||
559 | |||
560 | case USB_DEVICE_ENDPOINT_TYPE_INTERRUPT: | ||
561 | if (ep_bank) { | ||
562 | if ((module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE1_Msk) == 0){ | ||
563 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg |= USB_DEVICE_EPCFG_EPTYPE1(4); | ||
564 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; | ||
565 | } else { | ||
566 | return STATUS_ERR_DENIED; | ||
567 | } | ||
568 | } else { | ||
569 | if ((module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg & USB_DEVICE_EPCFG_EPTYPE0_Msk) == 0){ | ||
570 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.reg |= USB_DEVICE_EPCFG_EPTYPE0(4); | ||
571 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; | ||
572 | } else { | ||
573 | return STATUS_ERR_DENIED; | ||
574 | } | ||
575 | } | ||
576 | break; | ||
577 | |||
578 | default: | ||
579 | break; | ||
580 | } | ||
581 | |||
582 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[ep_bank].PCKSIZE.bit.SIZE = ep_config->ep_size; | ||
583 | |||
584 | if (true == ep_config->auto_zlp) { | ||
585 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[ep_bank].PCKSIZE.reg |= USB_DEVICE_PCKSIZE_AUTO_ZLP; | ||
586 | } else { | ||
587 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[ep_bank].PCKSIZE.reg &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP; | ||
588 | } | ||
589 | |||
590 | return STATUS_OK; | ||
591 | } | ||
592 | |||
593 | /** | ||
594 | * \brief Check if current endpoint is configured | ||
595 | * | ||
596 | * \param module_inst Pointer to USB software instance struct | ||
597 | * \param ep Endpoint address (direction & number) | ||
598 | * | ||
599 | * \return \c true if endpoint is configured and ready to use | ||
600 | */ | ||
601 | bool usb_device_endpoint_is_configured(struct usb_module *module_inst, uint8_t ep) | ||
602 | { | ||
603 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
604 | uint8_t flag; | ||
605 | |||
606 | if (ep & USB_EP_DIR_IN) { | ||
607 | flag = (uint8_t)(module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.bit.EPTYPE1); | ||
608 | } else { | ||
609 | flag = (uint8_t)(module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.bit.EPTYPE0); | ||
610 | } | ||
611 | return ((enum usb_device_endpoint_type)(flag) != USB_DEVICE_ENDPOINT_TYPE_DISABLE); | ||
612 | } | ||
613 | |||
614 | |||
615 | /** | ||
616 | * \brief Abort ongoing job on the endpoint | ||
617 | * | ||
618 | * \param module_inst Pointer to USB software instance struct | ||
619 | * \param ep Endpoint address | ||
620 | */ | ||
621 | void usb_device_endpoint_abort_job(struct usb_module *module_inst, uint8_t ep) | ||
622 | { | ||
623 | uint8_t ep_num; | ||
624 | ep_num = ep & USB_EP_ADDR_MASK; | ||
625 | |||
626 | // Stop transfer | ||
627 | if (ep & USB_EP_DIR_IN) { | ||
628 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; | ||
629 | // Eventually ack a transfer occur during abort | ||
630 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1; | ||
631 | } else { | ||
632 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; | ||
633 | // Eventually ack a transfer occur during abort | ||
634 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0; | ||
635 | } | ||
636 | } | ||
637 | |||
638 | /** | ||
639 | * \brief Check if endpoint is halted | ||
640 | * | ||
641 | * \param module_inst Pointer to USB software instance struct | ||
642 | * \param ep Endpoint address | ||
643 | * | ||
644 | * \return \c true if the endpoint is halted | ||
645 | */ | ||
646 | bool usb_device_endpoint_is_halted(struct usb_module *module_inst, uint8_t ep) | ||
647 | { | ||
648 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
649 | |||
650 | if (ep & USB_EP_DIR_IN) { | ||
651 | return (module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ1); | ||
652 | } else { | ||
653 | return (module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ0); | ||
654 | } | ||
655 | } | ||
656 | |||
657 | /** | ||
658 | * \brief Halt the endpoint (send STALL) | ||
659 | * | ||
660 | * \param module_inst Pointer to USB software instance struct | ||
661 | * \param ep Endpoint address | ||
662 | */ | ||
663 | void usb_device_endpoint_set_halt(struct usb_module *module_inst, uint8_t ep) | ||
664 | { | ||
665 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
666 | |||
667 | // Stall endpoint | ||
668 | if (ep & USB_EP_DIR_IN) { | ||
669 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; | ||
670 | } else { | ||
671 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; | ||
672 | } | ||
673 | } | ||
674 | |||
675 | /** | ||
676 | * \brief Clear endpoint halt state | ||
677 | * | ||
678 | * \param module_inst Pointer to USB software instance struct | ||
679 | * \param ep Endpoint address | ||
680 | */ | ||
681 | void usb_device_endpoint_clear_halt(struct usb_module *module_inst, uint8_t ep) | ||
682 | { | ||
683 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
684 | |||
685 | if (ep & USB_EP_DIR_IN) { | ||
686 | if (module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ1) { | ||
687 | // Remove stall request | ||
688 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1; | ||
689 | if (module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_STALL1) { | ||
690 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL1; | ||
691 | // The Stall has occurred, then reset data toggle | ||
692 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLIN; | ||
693 | } | ||
694 | } | ||
695 | } else { | ||
696 | if (module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ0) { | ||
697 | // Remove stall request | ||
698 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0; | ||
699 | if (module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_STALL0) { | ||
700 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL0; | ||
701 | // The Stall has occurred, then reset data toggle | ||
702 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLOUT; | ||
703 | } | ||
704 | } | ||
705 | } | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * \brief Start write buffer job on a endpoint | ||
710 | * | ||
711 | * \param module_inst Pointer to USB module instance | ||
712 | * \param ep_num Endpoint number | ||
713 | * \param pbuf Pointer to buffer | ||
714 | * \param buf_size Size of buffer | ||
715 | * | ||
716 | * \return Status of procedure | ||
717 | * \retval STATUS_OK Job started successfully | ||
718 | * \retval STATUS_ERR_DENIED Endpoint is not ready | ||
719 | */ | ||
720 | enum status_code usb_device_endpoint_write_buffer_job(struct usb_module *module_inst,uint8_t ep_num, | ||
721 | uint8_t* pbuf, uint32_t buf_size) | ||
722 | { | ||
723 | /* Sanity check arguments */ | ||
724 | Assert(module_inst); | ||
725 | Assert(module_inst->hw); | ||
726 | Assert(ep_num < USB_EPT_NUM); | ||
727 | |||
728 | uint8_t flag; | ||
729 | flag = (uint8_t)(module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.bit.EPTYPE1); | ||
730 | if ((enum usb_device_endpoint_type)(flag) == USB_DEVICE_ENDPOINT_TYPE_DISABLE) { | ||
731 | return STATUS_ERR_DENIED; | ||
732 | }; | ||
733 | |||
734 | /* get endpoint configuration from setting register */ | ||
735 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[1].ADDR.reg = (uint32_t)pbuf; | ||
736 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; | ||
737 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = buf_size; | ||
738 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY; | ||
739 | |||
740 | return STATUS_OK; | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * \brief Start read buffer job on a endpoint | ||
745 | * | ||
746 | * \param module_inst Pointer to USB module instance | ||
747 | * \param ep_num Endpoint number | ||
748 | * \param pbuf Pointer to buffer | ||
749 | * \param buf_size Size of buffer | ||
750 | * | ||
751 | * \return Status of procedure | ||
752 | * \retval STATUS_OK Job started successfully | ||
753 | * \retval STATUS_ERR_DENIED Endpoint is not ready | ||
754 | */ | ||
755 | enum status_code usb_device_endpoint_read_buffer_job(struct usb_module *module_inst,uint8_t ep_num, | ||
756 | uint8_t* pbuf, uint32_t buf_size) | ||
757 | { | ||
758 | /* Sanity check arguments */ | ||
759 | Assert(module_inst); | ||
760 | Assert(module_inst->hw); | ||
761 | Assert(ep_num < USB_EPT_NUM); | ||
762 | |||
763 | uint8_t flag; | ||
764 | flag = (uint8_t)(module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPCFG.bit.EPTYPE0); | ||
765 | if ((enum usb_device_endpoint_type)(flag) == USB_DEVICE_ENDPOINT_TYPE_DISABLE) { | ||
766 | return STATUS_ERR_DENIED; | ||
767 | }; | ||
768 | |||
769 | /* get endpoint configuration from setting register */ | ||
770 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[0].ADDR.reg = (uint32_t)pbuf; | ||
771 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = buf_size; | ||
772 | usb_descriptor_table.usb_endpoint_table[ep_num].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; | ||
773 | module_inst->hw->DEVICE.DeviceEndpoint[ep_num].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; | ||
774 | |||
775 | return STATUS_OK; | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * \brief Start setup packet read job on a endpoint | ||
780 | * | ||
781 | * \param module_inst Pointer to USB device module instance | ||
782 | * \param pbuf Pointer to buffer | ||
783 | * | ||
784 | * \return Status of procedure | ||
785 | * \retval STATUS_OK Job started successfully | ||
786 | * \retval STATUS_ERR_DENIED Endpoint is not ready | ||
787 | */ | ||
788 | enum status_code usb_device_endpoint_setup_buffer_job(struct usb_module *module_inst, | ||
789 | uint8_t* pbuf) | ||
790 | { | ||
791 | /* Sanity check arguments */ | ||
792 | Assert(module_inst); | ||
793 | Assert(module_inst->hw); | ||
794 | |||
795 | /* get endpoint configuration from setting register */ | ||
796 | usb_descriptor_table.usb_endpoint_table[0].DeviceDescBank[0].ADDR.reg = (uint32_t)pbuf; | ||
797 | usb_descriptor_table.usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8; | ||
798 | usb_descriptor_table.usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; | ||
799 | module_inst->hw->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; | ||
800 | |||
801 | return STATUS_OK; | ||
802 | } | ||
803 | |||
804 | static void _usb_device_interrupt_handler(void) | ||
805 | { | ||
806 | uint16_t ep_inst; | ||
807 | uint16_t flags, flags_run; | ||
808 | ep_inst = _usb_instances->hw->DEVICE.EPINTSMRY.reg; | ||
809 | |||
810 | /* device interrupt */ | ||
811 | if (0 == ep_inst) { | ||
812 | int i; | ||
813 | |||
814 | /* get interrupt flags */ | ||
815 | flags = _usb_instances->hw->DEVICE.INTFLAG.reg; | ||
816 | flags_run = flags & | ||
817 | _usb_instances->device_enabled_callback_mask & | ||
818 | _usb_instances->device_registered_callback_mask; | ||
819 | |||
820 | for (i = 0; i < USB_DEVICE_CALLBACK_N; i ++) { | ||
821 | if (flags & _usb_device_irq_bits[i]) { | ||
822 | _usb_instances->hw->DEVICE.INTFLAG.reg = | ||
823 | _usb_device_irq_bits[i]; | ||
824 | } | ||
825 | if (flags_run & _usb_device_irq_bits[i]) { | ||
826 | if (i == USB_DEVICE_CALLBACK_LPMSUSP) { | ||
827 | device_callback_lpm_wakeup_enable = | ||
828 | usb_descriptor_table.usb_endpoint_table[0].DeviceDescBank[0].EXTREG.bit.VARIABLE | ||
829 | & USB_LPM_ATTRIBUT_REMOTEWAKE_MASK; | ||
830 | } | ||
831 | (_usb_instances->device_callback[i])(_usb_instances, &device_callback_lpm_wakeup_enable); | ||
832 | } | ||
833 | } | ||
834 | |||
835 | } else { | ||
836 | /* endpoint interrupt */ | ||
837 | |||
838 | for (uint8_t i = 0; i < USB_EPT_NUM; i++) { | ||
839 | |||
840 | if (ep_inst & (1 << i)) { | ||
841 | flags = _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg; | ||
842 | flags_run = flags & | ||
843 | _usb_instances->device_endpoint_enabled_callback_mask[i] & | ||
844 | _usb_instances->device_endpoint_registered_callback_mask[i]; | ||
845 | |||
846 | // endpoint transfer stall interrupt | ||
847 | if (flags & USB_DEVICE_EPINTFLAG_STALL_Msk) { | ||
848 | if (_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_STALL1) { | ||
849 | _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL1; | ||
850 | ep_callback_para.endpoint_address = USB_EP_DIR_IN | i; | ||
851 | } else if (_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_STALL0) { | ||
852 | _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL0; | ||
853 | ep_callback_para.endpoint_address = USB_EP_DIR_OUT | i; | ||
854 | } | ||
855 | |||
856 | if (flags_run & USB_DEVICE_EPINTFLAG_STALL_Msk) { | ||
857 | (_usb_instances->device_endpoint_callback[i][USB_DEVICE_ENDPOINT_CALLBACK_STALL])(_usb_instances,&ep_callback_para); | ||
858 | } | ||
859 | return; | ||
860 | } | ||
861 | |||
862 | // endpoint received setup interrupt | ||
863 | if (flags & USB_DEVICE_EPINTFLAG_RXSTP) { | ||
864 | _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP; | ||
865 | if(_usb_instances->device_endpoint_enabled_callback_mask[i] & _usb_endpoint_irq_bits[USB_DEVICE_ENDPOINT_CALLBACK_RXSTP]) { | ||
866 | ep_callback_para.received_bytes = (uint16_t)(usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT); | ||
867 | (_usb_instances->device_endpoint_callback[i][USB_DEVICE_ENDPOINT_CALLBACK_RXSTP])(_usb_instances,&ep_callback_para); | ||
868 | } | ||
869 | return; | ||
870 | } | ||
871 | |||
872 | // endpoint transfer complete interrupt | ||
873 | if (flags & USB_DEVICE_EPINTFLAG_TRCPT_Msk) { | ||
874 | if (_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT1) { | ||
875 | _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1; | ||
876 | ep_callback_para.endpoint_address = USB_EP_DIR_IN | i; | ||
877 | ep_callback_para.sent_bytes = (uint16_t)(usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT); | ||
878 | |||
879 | } else if (_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT0) { | ||
880 | _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0; | ||
881 | ep_callback_para.endpoint_address = USB_EP_DIR_OUT | i; | ||
882 | ep_callback_para.received_bytes = (uint16_t)(usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT); | ||
883 | ep_callback_para.out_buffer_size = (uint16_t)(usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE); | ||
884 | } | ||
885 | if(flags_run & USB_DEVICE_EPINTFLAG_TRCPT_Msk) { | ||
886 | (_usb_instances->device_endpoint_callback[i][USB_DEVICE_ENDPOINT_CALLBACK_TRCPT])(_usb_instances,&ep_callback_para); | ||
887 | } | ||
888 | return; | ||
889 | } | ||
890 | |||
891 | // endpoint transfer fail interrupt | ||
892 | if (flags & USB_DEVICE_EPINTFLAG_TRFAIL_Msk) { | ||
893 | if (_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRFAIL1) { | ||
894 | _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL1; | ||
895 | if (usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[1].STATUS_BK.reg & USB_DEVICE_STATUS_BK_ERRORFLOW) { | ||
896 | usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[1].STATUS_BK.reg &= ~USB_DEVICE_STATUS_BK_ERRORFLOW; | ||
897 | } | ||
898 | ep_callback_para.endpoint_address = USB_EP_DIR_IN | i; | ||
899 | if (_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT1) { | ||
900 | return; | ||
901 | } | ||
902 | } else if(_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRFAIL0) { | ||
903 | _usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL0; | ||
904 | if (usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[0].STATUS_BK.reg & USB_DEVICE_STATUS_BK_ERRORFLOW) { | ||
905 | usb_descriptor_table.usb_endpoint_table[i].DeviceDescBank[0].STATUS_BK.reg &= ~USB_DEVICE_STATUS_BK_ERRORFLOW; | ||
906 | } | ||
907 | ep_callback_para.endpoint_address = USB_EP_DIR_OUT | i; | ||
908 | if (_usb_instances->hw->DEVICE.DeviceEndpoint[i].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT0) { | ||
909 | return; | ||
910 | } | ||
911 | } | ||
912 | |||
913 | if(flags_run & USB_DEVICE_EPINTFLAG_TRFAIL_Msk) { | ||
914 | (_usb_instances->device_endpoint_callback[i][USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL])(_usb_instances,&ep_callback_para); | ||
915 | } | ||
916 | return; | ||
917 | } | ||
918 | } | ||
919 | } | ||
920 | } | ||
921 | } | ||
922 | |||
923 | /** | ||
924 | * \brief Enable the USB module peripheral | ||
925 | * | ||
926 | * \param module_inst pointer to USB module instance | ||
927 | */ | ||
928 | void usb_enable(struct usb_module *module_inst) | ||
929 | { | ||
930 | Assert(module_inst); | ||
931 | Assert(module_inst->hw); | ||
932 | |||
933 | module_inst->hw->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE; | ||
934 | while (module_inst->hw->DEVICE.SYNCBUSY.reg == USB_SYNCBUSY_ENABLE); | ||
935 | } | ||
936 | |||
937 | /** | ||
938 | * \brief Disable the USB module peripheral | ||
939 | * | ||
940 | * \param module_inst pointer to USB module instance | ||
941 | */ | ||
942 | void usb_disable(struct usb_module *module_inst) | ||
943 | { | ||
944 | Assert(module_inst); | ||
945 | Assert(module_inst->hw); | ||
946 | |||
947 | module_inst->hw->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_MASK; | ||
948 | module_inst->hw->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_MASK; | ||
949 | module_inst->hw->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE; | ||
950 | while (module_inst->hw->DEVICE.SYNCBUSY.reg == USB_SYNCBUSY_ENABLE); | ||
951 | } | ||
952 | |||
953 | /** | ||
954 | * \brief Interrupt handler for the USB module. | ||
955 | */ | ||
956 | void USB_0_Handler(void) | ||
957 | { | ||
958 | if (_usb_instances->hw->DEVICE.CTRLA.bit.MODE) { | ||
959 | |||
960 | } else { | ||
961 | /*device mode ISR */ | ||
962 | _usb_device_interrupt_handler(); | ||
963 | } | ||
964 | } | ||
965 | |||
966 | void USB_1_Handler(void) | ||
967 | { | ||
968 | _usb_device_interrupt_handler(); | ||
969 | } | ||
970 | |||
971 | void USB_2_Handler(void) | ||
972 | { | ||
973 | _usb_device_interrupt_handler(); | ||
974 | } | ||
975 | |||
976 | void USB_3_Handler(void) | ||
977 | { | ||
978 | _usb_device_interrupt_handler(); | ||
979 | } | ||
980 | |||
981 | /** | ||
982 | * \brief Get the default USB module settings | ||
983 | * | ||
984 | * \param[out] module_config Configuration structure to initialize to default values | ||
985 | */ | ||
986 | void usb_get_config_defaults(struct usb_config *module_config) | ||
987 | { | ||
988 | Assert(module_config); | ||
989 | |||
990 | /* Sanity check arguments */ | ||
991 | Assert(module_config); | ||
992 | /* Write default configuration to config struct */ | ||
993 | module_config->select_host_mode = 0; | ||
994 | module_config->run_in_standby = 1; | ||
995 | module_config->source_generator = 0; | ||
996 | module_config->speed_mode = USB_SPEED_FULL; | ||
997 | } | ||
998 | |||
999 | #define NVM_USB_PAD_TRANSN_POS 45 | ||
1000 | #define NVM_USB_PAD_TRANSN_SIZE 5 | ||
1001 | #define NVM_USB_PAD_TRANSP_POS 50 | ||
1002 | #define NVM_USB_PAD_TRANSP_SIZE 5 | ||
1003 | #define NVM_USB_PAD_TRIM_POS 55 | ||
1004 | #define NVM_USB_PAD_TRIM_SIZE 3 | ||
1005 | |||
1006 | /** | ||
1007 | * \brief Initializes USB module instance | ||
1008 | * | ||
1009 | * Enables the clock and initializes the USB module, based on the given | ||
1010 | * configuration values. | ||
1011 | * | ||
1012 | * \param[in,out] module_inst Pointer to the software module instance struct | ||
1013 | * \param[in] hw Pointer to the USB hardware module | ||
1014 | * \param[in] module_config Pointer to the USB configuration options struct | ||
1015 | * | ||
1016 | * \return Status of the initialization procedure. | ||
1017 | * | ||
1018 | * \retval STATUS_OK The module was initialized successfully | ||
1019 | */ | ||
1020 | |||
1021 | #define GCLK_USB 10 | ||
1022 | |||
1023 | enum status_code usb_init(struct usb_module *module_inst, Usb *const hw, | ||
1024 | struct usb_config *module_config) | ||
1025 | { | ||
1026 | /* Sanity check arguments */ | ||
1027 | Assert(hw); | ||
1028 | Assert(module_inst); | ||
1029 | Assert(module_config); | ||
1030 | |||
1031 | uint32_t i,j; | ||
1032 | uint32_t pad_transn, pad_transp, pad_trim; | ||
1033 | |||
1034 | Gclk *pgclk = GCLK; | ||
1035 | Mclk *pmclk = MCLK; | ||
1036 | Port *pport = PORT; | ||
1037 | Oscctrl *posc = OSCCTRL; | ||
1038 | |||
1039 | _usb_instances = module_inst; | ||
1040 | |||
1041 | /* Associate the software module instance with the hardware module */ | ||
1042 | module_inst->hw = hw; | ||
1043 | |||
1044 | //setup peripheral and synchronous bus clocks to USB | ||
1045 | pmclk->AHBMASK.bit.USB_ = 1; | ||
1046 | pmclk->APBBMASK.bit.USB_ = 1; | ||
1047 | |||
1048 | /* Set up the USB DP/DN pins */ | ||
1049 | pport->Group[0].PMUX[12].reg = 0x77; //PA24, PA25, function column H for USB D-, D+ | ||
1050 | pport->Group[0].PINCFG[24].bit.PMUXEN = 1; | ||
1051 | pport->Group[0].PINCFG[25].bit.PMUXEN = 1; | ||
1052 | pport->Group[1].PMUX[11].bit.PMUXE = 7; //PB22, function column H for USB SOF_1KHz output | ||
1053 | pport->Group[1].PINCFG[22].bit.PMUXEN = 1; | ||
1054 | |||
1055 | //configure and enable DFLL for USB clock recovery mode at 48MHz | ||
1056 | posc->DFLLCTRLA.bit.ENABLE = 0; | ||
1057 | while (posc->DFLLSYNC.bit.ENABLE); | ||
1058 | while (posc->DFLLSYNC.bit.DFLLCTRLB); | ||
1059 | posc->DFLLCTRLB.bit.USBCRM = 1; | ||
1060 | while (posc->DFLLSYNC.bit.DFLLCTRLB); | ||
1061 | posc->DFLLCTRLB.bit.MODE = 1; | ||
1062 | while (posc->DFLLSYNC.bit.DFLLCTRLB); | ||
1063 | posc->DFLLCTRLB.bit.QLDIS = 0; | ||
1064 | while (posc->DFLLSYNC.bit.DFLLCTRLB); | ||
1065 | posc->DFLLCTRLB.bit.CCDIS = 1; | ||
1066 | posc->DFLLMUL.bit.MUL = 0xbb80; //4800 x 1KHz | ||
1067 | while (posc->DFLLSYNC.bit.DFLLMUL); | ||
1068 | posc->DFLLCTRLA.bit.ENABLE = 1; | ||
1069 | while (posc->DFLLSYNC.bit.ENABLE); | ||
1070 | |||
1071 | /* Setup clock for module */ | ||
1072 | pgclk->PCHCTRL[GCLK_USB].bit.GEN = 0; | ||
1073 | pgclk->PCHCTRL[GCLK_USB].bit.CHEN = 1; | ||
1074 | |||
1075 | /* Reset */ | ||
1076 | hw->DEVICE.CTRLA.bit.SWRST = 1; | ||
1077 | while (hw->DEVICE.SYNCBUSY.bit.SWRST) { | ||
1078 | /* Sync wait */ | ||
1079 | } | ||
1080 | |||
1081 | /* Change QOS values to have the best performance and correct USB behaviour */ | ||
1082 | USB->DEVICE.QOSCTRL.bit.CQOS = 2; | ||
1083 | USB->DEVICE.QOSCTRL.bit.DQOS = 2; | ||
1084 | |||
1085 | /* Load Pad Calibration */ | ||
1086 | |||
1087 | pad_transn = (USB_FUSES_TRANSN_ADDR >> USB_FUSES_TRANSN_Pos) & USB_FUSES_TRANSN_Msk; | ||
1088 | if (pad_transn == 0x1F) { | ||
1089 | pad_transn = 5; | ||
1090 | } | ||
1091 | |||
1092 | hw->DEVICE.PADCAL.bit.TRANSN = pad_transn; | ||
1093 | |||
1094 | pad_transp = (USB_FUSES_TRANSP_ADDR >> USB_FUSES_TRANSP_Pos) & USB_FUSES_TRANSP_Msk; | ||
1095 | if (pad_transp == 0x1F) { | ||
1096 | pad_transp = 29; | ||
1097 | } | ||
1098 | |||
1099 | hw->DEVICE.PADCAL.bit.TRANSP = pad_transp; | ||
1100 | |||
1101 | pad_trim = (USB_FUSES_TRIM_ADDR >> USB_FUSES_TRIM_Pos) & USB_FUSES_TRIM_Msk; | ||
1102 | if (pad_trim == 0x07) { | ||
1103 | pad_trim = 3; | ||
1104 | } | ||
1105 | |||
1106 | hw->DEVICE.PADCAL.bit.TRIM = pad_trim; | ||
1107 | |||
1108 | /* Set the configuration */ | ||
1109 | hw->DEVICE.CTRLA.bit.MODE = module_config->select_host_mode; | ||
1110 | hw->DEVICE.CTRLA.bit.RUNSTDBY = module_config->run_in_standby; | ||
1111 | hw->DEVICE.DESCADD.reg = (uint32_t)(&usb_descriptor_table.usb_endpoint_table[0]); | ||
1112 | if (USB_SPEED_FULL == module_config->speed_mode) { | ||
1113 | module_inst->hw->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; | ||
1114 | } else if(USB_SPEED_LOW == module_config->speed_mode) { | ||
1115 | module_inst->hw->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_LS_Val; | ||
1116 | } | ||
1117 | |||
1118 | memset((uint8_t *)(&usb_descriptor_table.usb_endpoint_table[0]), 0, | ||
1119 | sizeof(usb_descriptor_table.usb_endpoint_table)); | ||
1120 | |||
1121 | /* device callback related */ | ||
1122 | for (i = 0; i < USB_DEVICE_CALLBACK_N; i++) { | ||
1123 | module_inst->device_callback[i] = NULL; | ||
1124 | } | ||
1125 | for (i = 0; i < USB_EPT_NUM; i++) { | ||
1126 | for(j = 0; j < USB_DEVICE_EP_CALLBACK_N; j++) { | ||
1127 | module_inst->device_endpoint_callback[i][j] = NULL; | ||
1128 | } | ||
1129 | } | ||
1130 | module_inst->device_registered_callback_mask = 0; | ||
1131 | module_inst->device_enabled_callback_mask = 0; | ||
1132 | for (j = 0; j < USB_EPT_NUM; j++) { | ||
1133 | module_inst->device_endpoint_registered_callback_mask[j] = 0; | ||
1134 | module_inst->device_endpoint_enabled_callback_mask[j] = 0; | ||
1135 | } | ||
1136 | |||
1137 | /* Enable interrupts for this USB module */ | ||
1138 | NVIC_EnableIRQ(USB_0_IRQn); | ||
1139 | NVIC_EnableIRQ(USB_2_IRQn); | ||
1140 | NVIC_EnableIRQ(USB_3_IRQn); | ||
1141 | |||
1142 | return STATUS_OK; | ||
1143 | } | ||
1144 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb.h b/tmk_core/protocol/arm_atsam/usb/usb.h new file mode 100644 index 000000000..9a452881a --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb.h | |||
@@ -0,0 +1,492 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief SAM USB Driver | ||
5 | * | ||
6 | * Copyright (C) 2014-2016 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | #ifndef USB_H_INCLUDED | ||
47 | #define USB_H_INCLUDED | ||
48 | |||
49 | #ifdef __cplusplus | ||
50 | extern "C" { | ||
51 | #endif | ||
52 | |||
53 | /** | ||
54 | * \defgroup asfdoc_sam0_usb_group SAM Universal Serial Bus (USB) | ||
55 | * | ||
56 | * The Universal Serial Bus (USB) module complies with the USB 2.1 specification. | ||
57 | * | ||
58 | * The following peripherals are used by this module: | ||
59 | * - USB (Universal Serial Bus) | ||
60 | * | ||
61 | * The following devices can use this module: | ||
62 | * - Atmel | SMART SAM D51 | ||
63 | * | ||
64 | * The USB module covers following mode: | ||
65 | * \if USB_DEVICE_MODE | ||
66 | * - USB Device Mode | ||
67 | * \endif | ||
68 | * \if USB_HOST_MODE | ||
69 | * - USB Host Mode | ||
70 | * \endif | ||
71 | * | ||
72 | * The USB module covers following speed: | ||
73 | * \if USB_HS_MODE | ||
74 | * - USB High Speed (480Mbit/s) | ||
75 | * \endif | ||
76 | * - USB Full Speed (12Mbit/s) | ||
77 | * \if USB_LS_MODE | ||
78 | * - USB Low Speed (1.5Mbit/s) | ||
79 | * \endif | ||
80 | * | ||
81 | * \if USB_LPM_MODE | ||
82 | * The USB module supports Link Power Management (LPM-L1) protocol. | ||
83 | * \endif | ||
84 | * | ||
85 | * USB support needs whole set of enumeration process, to make the device | ||
86 | * recognizable and usable. The USB driver is designed to interface to the | ||
87 | * USB Stack in Atmel Software Framework (ASF). | ||
88 | * | ||
89 | * \if USB_DEVICE_MODE | ||
90 | * \section asfdoc_sam0_usb_device USB Device Mode | ||
91 | * The ASF USB Device Stack has defined the USB Device Driver (UDD) interface, | ||
92 | * to support USB device operations. The USB module device driver complies with | ||
93 | * this interface, so that the USB Device Stack can work based on the | ||
94 | * USB module. | ||
95 | * | ||
96 | * Refer to <a href="http://www.atmel.com/images/doc8360.pdf"> | ||
97 | * "ASF - USB Device Stack"</a> for more details. | ||
98 | * \endif | ||
99 | * | ||
100 | * \if USB_HOST_MODE | ||
101 | * \section adfdoc_sam0_usb_host USB Host Mode | ||
102 | * The ASF USB Host Stack has defined the USB Host Driver (UHD) interface, | ||
103 | * to support USB host operations. The USB module host driver complies with | ||
104 | * this interface, so that the USB Host Stack can work based on the USB module. | ||
105 | * | ||
106 | * Refer to <a href="http://www.atmel.com/images/doc8486.pdf"> | ||
107 | * "ASF - USB Host Stack"</a> for more details. | ||
108 | * \endif | ||
109 | */ | ||
110 | |||
111 | /** Enum for the speed status for the USB module */ | ||
112 | enum usb_speed { | ||
113 | USB_SPEED_LOW, | ||
114 | USB_SPEED_FULL, | ||
115 | }; | ||
116 | |||
117 | /** Enum for the possible callback types for the USB in host module */ | ||
118 | enum usb_host_callback { | ||
119 | USB_HOST_CALLBACK_SOF, | ||
120 | USB_HOST_CALLBACK_RESET, | ||
121 | USB_HOST_CALLBACK_WAKEUP, | ||
122 | USB_HOST_CALLBACK_DNRSM, | ||
123 | USB_HOST_CALLBACK_UPRSM, | ||
124 | USB_HOST_CALLBACK_RAMACER, | ||
125 | USB_HOST_CALLBACK_CONNECT, | ||
126 | USB_HOST_CALLBACK_DISCONNECT, | ||
127 | USB_HOST_CALLBACK_N, | ||
128 | }; | ||
129 | |||
130 | /** Enum for the possible callback types for the USB pipe in host module */ | ||
131 | enum usb_host_pipe_callback { | ||
132 | USB_HOST_PIPE_CALLBACK_TRANSFER_COMPLETE, | ||
133 | USB_HOST_PIPE_CALLBACK_ERROR, | ||
134 | USB_HOST_PIPE_CALLBACK_SETUP, | ||
135 | USB_HOST_PIPE_CALLBACK_STALL, | ||
136 | USB_HOST_PIPE_CALLBACK_N, | ||
137 | }; | ||
138 | |||
139 | /** | ||
140 | * \brief Host pipe types. | ||
141 | */ | ||
142 | enum usb_host_pipe_type { | ||
143 | USB_HOST_PIPE_TYPE_DISABLE, | ||
144 | USB_HOST_PIPE_TYPE_CONTROL, | ||
145 | USB_HOST_PIPE_TYPE_ISO, | ||
146 | USB_HOST_PIPE_TYPE_BULK, | ||
147 | USB_HOST_PIPE_TYPE_INTERRUPT, | ||
148 | USB_HOST_PIPE_TYPE_EXTENDED, | ||
149 | }; | ||
150 | |||
151 | /** | ||
152 | * \brief Host pipe token types. | ||
153 | */ | ||
154 | enum usb_host_pipe_token { | ||
155 | USB_HOST_PIPE_TOKEN_SETUP, | ||
156 | USB_HOST_PIPE_TOKEN_IN, | ||
157 | USB_HOST_PIPE_TOKEN_OUT, | ||
158 | }; | ||
159 | |||
160 | /** | ||
161 | * \brief Enumeration for the possible callback types for the USB in device module | ||
162 | */ | ||
163 | enum usb_device_callback { | ||
164 | USB_DEVICE_CALLBACK_SOF, | ||
165 | USB_DEVICE_CALLBACK_RESET, | ||
166 | USB_DEVICE_CALLBACK_WAKEUP, | ||
167 | USB_DEVICE_CALLBACK_RAMACER, | ||
168 | USB_DEVICE_CALLBACK_SUSPEND, | ||
169 | USB_DEVICE_CALLBACK_LPMNYET, | ||
170 | USB_DEVICE_CALLBACK_LPMSUSP, | ||
171 | USB_DEVICE_CALLBACK_N, | ||
172 | }; | ||
173 | |||
174 | /** | ||
175 | * \brief Enumeration for the possible callback types for the USB endpoint in device module | ||
176 | */ | ||
177 | enum usb_device_endpoint_callback { | ||
178 | USB_DEVICE_ENDPOINT_CALLBACK_TRCPT, | ||
179 | USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL, | ||
180 | USB_DEVICE_ENDPOINT_CALLBACK_RXSTP, | ||
181 | USB_DEVICE_ENDPOINT_CALLBACK_STALL, | ||
182 | USB_DEVICE_EP_CALLBACK_N, | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * \brief Device Endpoint types. | ||
187 | */ | ||
188 | enum usb_device_endpoint_type { | ||
189 | USB_DEVICE_ENDPOINT_TYPE_DISABLE, | ||
190 | USB_DEVICE_ENDPOINT_TYPE_CONTROL, | ||
191 | USB_DEVICE_ENDPOINT_TYPE_ISOCHRONOUS, | ||
192 | USB_DEVICE_ENDPOINT_TYPE_BULK, | ||
193 | USB_DEVICE_ENDPOINT_TYPE_INTERRUPT, | ||
194 | }; | ||
195 | |||
196 | /** | ||
197 | * \brief Endpoint Size | ||
198 | */ | ||
199 | enum usb_endpoint_size { | ||
200 | USB_ENDPOINT_8_BYTE, | ||
201 | USB_ENDPOINT_16_BYTE, | ||
202 | USB_ENDPOINT_32_BYTE, | ||
203 | USB_ENDPOINT_64_BYTE, | ||
204 | USB_ENDPOINT_128_BYTE, | ||
205 | USB_ENDPOINT_256_BYTE, | ||
206 | USB_ENDPOINT_512_BYTE, | ||
207 | USB_ENDPOINT_1023_BYTE, | ||
208 | }; | ||
209 | |||
210 | /** | ||
211 | * \brief Link Power Management Handshake. | ||
212 | */ | ||
213 | enum usb_device_lpm_mode { | ||
214 | USB_DEVICE_LPM_NOT_SUPPORT, | ||
215 | USB_DEVICE_LPM_ACK, | ||
216 | USB_DEVICE_LPM_NYET, | ||
217 | }; | ||
218 | |||
219 | /** | ||
220 | * \brief Module structure | ||
221 | */ | ||
222 | struct usb_module; | ||
223 | |||
224 | /** | ||
225 | * \name Host Callback Functions Types | ||
226 | * @{ | ||
227 | */ | ||
228 | typedef void (*usb_host_callback_t)(struct usb_module *module_inst); | ||
229 | typedef void (*usb_host_pipe_callback_t)(struct usb_module *module_inst, void *); | ||
230 | /** @} */ | ||
231 | |||
232 | /** | ||
233 | * \name Device Callback Functions Types | ||
234 | * @{ | ||
235 | */ | ||
236 | typedef void (*usb_device_callback_t)(struct usb_module *module_inst, void* pointer); | ||
237 | typedef void (*usb_device_endpoint_callback_t)(struct usb_module *module_inst, void* pointer); | ||
238 | /** @} */ | ||
239 | |||
240 | /** USB configurations */ | ||
241 | struct usb_config { | ||
242 | /** \c true for host, \c false for device. */ | ||
243 | bool select_host_mode; | ||
244 | /** When \c true the module is enabled during standby. */ | ||
245 | bool run_in_standby; | ||
246 | /** Generic Clock Generator source channel. */ | ||
247 | // enum gclk_generator source_generator; | ||
248 | uint8_t source_generator; | ||
249 | /** Speed mode */ | ||
250 | //enum usb_speed speed_mode; | ||
251 | uint8_t speed_mode; | ||
252 | }; | ||
253 | |||
254 | /** | ||
255 | * \brief USB software module instance structure. | ||
256 | * | ||
257 | * USB software module instance structure, used to retain software state | ||
258 | * information of an associated hardware module instance. | ||
259 | * | ||
260 | */ | ||
261 | struct usb_module { | ||
262 | /** Hardware module pointer of the associated USB peripheral. */ | ||
263 | Usb *hw; | ||
264 | |||
265 | /** Array to store device related callback functions */ | ||
266 | usb_device_callback_t device_callback[USB_DEVICE_CALLBACK_N]; | ||
267 | usb_device_endpoint_callback_t device_endpoint_callback[USB_EPT_NUM][USB_DEVICE_EP_CALLBACK_N]; | ||
268 | /** Bit mask for device callbacks registered */ | ||
269 | uint16_t device_registered_callback_mask; | ||
270 | /** Bit mask for device callbacks enabled */ | ||
271 | uint16_t device_enabled_callback_mask; | ||
272 | /** Bit mask for device endpoint callbacks registered */ | ||
273 | uint8_t device_endpoint_registered_callback_mask[USB_EPT_NUM]; | ||
274 | /** Bit mask for device endpoint callbacks enabled */ | ||
275 | uint8_t device_endpoint_enabled_callback_mask[USB_EPT_NUM]; | ||
276 | }; | ||
277 | |||
278 | /** USB device endpoint configurations */ | ||
279 | struct usb_device_endpoint_config { | ||
280 | /** device address */ | ||
281 | uint8_t ep_address; | ||
282 | /** endpoint size */ | ||
283 | enum usb_endpoint_size ep_size; | ||
284 | /** automatic zero length packet mode, \c true to enable */ | ||
285 | bool auto_zlp; | ||
286 | /** type of endpoint with Bank */ | ||
287 | enum usb_device_endpoint_type ep_type; | ||
288 | }; | ||
289 | |||
290 | /** USB device endpoint callback status parameter structure */ | ||
291 | struct usb_endpoint_callback_parameter { | ||
292 | uint16_t received_bytes; | ||
293 | uint16_t sent_bytes; | ||
294 | uint16_t out_buffer_size; | ||
295 | uint8_t endpoint_address; | ||
296 | }; | ||
297 | |||
298 | void usb_enable(struct usb_module *module_inst); | ||
299 | void usb_disable(struct usb_module *module_inst); | ||
300 | |||
301 | /** | ||
302 | * \brief Get the status of USB module's state machine | ||
303 | * | ||
304 | * \param module_inst Pointer to USB module instance | ||
305 | */ | ||
306 | static inline uint8_t usb_get_state_machine_status(struct usb_module *module_inst) | ||
307 | { | ||
308 | /* Sanity check arguments */ | ||
309 | Assert(module_inst); | ||
310 | Assert(module_inst->hw); | ||
311 | |||
312 | return module_inst->hw->DEVICE.FSMSTATUS.reg; | ||
313 | } | ||
314 | |||
315 | void usb_get_config_defaults(struct usb_config *module_config); | ||
316 | enum status_code usb_init(struct usb_module *module_inst, Usb *const hw, | ||
317 | struct usb_config *module_config); | ||
318 | |||
319 | /** | ||
320 | * \brief Attach USB device to the bus | ||
321 | * | ||
322 | * \param module_inst Pointer to USB device module instance | ||
323 | */ | ||
324 | static inline void usb_device_attach(struct usb_module *module_inst) | ||
325 | { | ||
326 | module_inst->hw->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH; | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * \brief Detach USB device from the bus | ||
331 | * | ||
332 | * \param module_inst Pointer to USB device module instance | ||
333 | */ | ||
334 | static inline void usb_device_detach(struct usb_module *module_inst) | ||
335 | { | ||
336 | module_inst->hw->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_DETACH; | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * \brief Get the speed mode of USB device | ||
341 | * | ||
342 | * \param module_inst Pointer to USB device module instance | ||
343 | * \return USB Speed mode (\ref usb_speed). | ||
344 | */ | ||
345 | static inline enum usb_speed usb_device_get_speed(struct usb_module *module_inst) | ||
346 | { | ||
347 | if (!(module_inst->hw->DEVICE.STATUS.reg & USB_DEVICE_STATUS_SPEED_Msk)) { | ||
348 | return USB_SPEED_FULL; | ||
349 | } else { | ||
350 | return USB_SPEED_LOW; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * \brief Get the address of USB device | ||
356 | * | ||
357 | * \param module_inst Pointer to USB device module instance | ||
358 | * \return USB device address value. | ||
359 | */ | ||
360 | static inline uint8_t usb_device_get_address(struct usb_module *module_inst) | ||
361 | { | ||
362 | return ((uint8_t)(module_inst->hw->DEVICE.DADD.bit.DADD)); | ||
363 | } | ||
364 | |||
365 | /** | ||
366 | * \brief Set the speed mode of USB device | ||
367 | * | ||
368 | * \param module_inst Pointer to USB device module instance | ||
369 | * \param address USB device address value | ||
370 | */ | ||
371 | static inline void usb_device_set_address(struct usb_module *module_inst, uint8_t address) | ||
372 | { | ||
373 | module_inst->hw->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | address; | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * \brief Get the frame number of USB device | ||
378 | * | ||
379 | * \param module_inst Pointer to USB device module instance | ||
380 | * \return USB device frame number value. | ||
381 | */ | ||
382 | static inline uint16_t usb_device_get_frame_number(struct usb_module *module_inst) | ||
383 | { | ||
384 | return ((uint16_t)(module_inst->hw->DEVICE.FNUM.bit.FNUM)); | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * \brief Get the micro-frame number of USB device | ||
389 | * | ||
390 | * \param module_inst Pointer to USB device module instance | ||
391 | * \return USB device micro-frame number value. | ||
392 | */ | ||
393 | static inline uint16_t usb_device_get_micro_frame_number(struct usb_module *module_inst) | ||
394 | { | ||
395 | return ((uint16_t)(module_inst->hw->DEVICE.FNUM.reg)); | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | * \brief USB device send the resume wakeup | ||
400 | * | ||
401 | * \param module_inst Pointer to USB device module instance | ||
402 | */ | ||
403 | static inline void usb_device_send_remote_wake_up(struct usb_module *module_inst) | ||
404 | { | ||
405 | module_inst->hw->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_UPRSM; | ||
406 | } | ||
407 | |||
408 | /** | ||
409 | * \brief USB device set the LPM mode | ||
410 | * | ||
411 | * \param module_inst Pointer to USB device module instance | ||
412 | * \param lpm_mode LPM mode | ||
413 | */ | ||
414 | static inline void usb_device_set_lpm_mode(struct usb_module *module_inst, | ||
415 | enum usb_device_lpm_mode lpm_mode) | ||
416 | { | ||
417 | module_inst->hw->DEVICE.CTRLB.bit.LPMHDSK = lpm_mode; | ||
418 | } | ||
419 | |||
420 | /** | ||
421 | * \name USB Device Callback Management | ||
422 | * @{ | ||
423 | */ | ||
424 | enum status_code usb_device_register_callback(struct usb_module *module_inst, | ||
425 | enum usb_device_callback callback_type, | ||
426 | usb_device_callback_t callback_func); | ||
427 | enum status_code usb_device_unregister_callback(struct usb_module *module_inst, | ||
428 | enum usb_device_callback callback_type); | ||
429 | enum status_code usb_device_enable_callback(struct usb_module *module_inst, | ||
430 | enum usb_device_callback callback_type); | ||
431 | enum status_code usb_device_disable_callback(struct usb_module *module_inst, | ||
432 | enum usb_device_callback callback_type); | ||
433 | /** @} */ | ||
434 | |||
435 | /** | ||
436 | * \name USB Device Endpoint Configuration | ||
437 | * @{ | ||
438 | */ | ||
439 | void usb_device_endpoint_get_config_defaults(struct usb_device_endpoint_config *ep_config); | ||
440 | enum status_code usb_device_endpoint_set_config(struct usb_module *module_inst, | ||
441 | struct usb_device_endpoint_config *ep_config); | ||
442 | bool usb_device_endpoint_is_configured(struct usb_module *module_inst, uint8_t ep); | ||
443 | /** @} */ | ||
444 | |||
445 | /** | ||
446 | * \name USB Device Endpoint Callback Management | ||
447 | * @{ | ||
448 | */ | ||
449 | enum status_code usb_device_endpoint_register_callback( | ||
450 | struct usb_module *module_inst, uint8_t ep_num, | ||
451 | enum usb_device_endpoint_callback callback_type, | ||
452 | usb_device_endpoint_callback_t callback_func); | ||
453 | enum status_code usb_device_endpoint_unregister_callback( | ||
454 | struct usb_module *module_inst, uint8_t ep_num, | ||
455 | enum usb_device_endpoint_callback callback_type); | ||
456 | enum status_code usb_device_endpoint_enable_callback( | ||
457 | struct usb_module *module_inst, uint8_t ep, | ||
458 | enum usb_device_endpoint_callback callback_type); | ||
459 | enum status_code usb_device_endpoint_disable_callback( | ||
460 | struct usb_module *module_inst, uint8_t ep, | ||
461 | enum usb_device_endpoint_callback callback_type); | ||
462 | /** @} */ | ||
463 | |||
464 | /** | ||
465 | * \name USB Device Endpoint Job Management | ||
466 | * @{ | ||
467 | */ | ||
468 | enum status_code usb_device_endpoint_write_buffer_job(struct usb_module *module_inst,uint8_t ep_num, | ||
469 | uint8_t* pbuf, uint32_t buf_size); | ||
470 | enum status_code usb_device_endpoint_read_buffer_job(struct usb_module *module_inst,uint8_t ep_num, | ||
471 | uint8_t* pbuf, uint32_t buf_size); | ||
472 | enum status_code usb_device_endpoint_setup_buffer_job(struct usb_module *module_inst, | ||
473 | uint8_t* pbuf); | ||
474 | void usb_device_endpoint_abort_job(struct usb_module *module_inst, uint8_t ep); | ||
475 | /** @} */ | ||
476 | |||
477 | /** | ||
478 | * \name USB Device Endpoint Operations | ||
479 | * @{ | ||
480 | */ | ||
481 | |||
482 | bool usb_device_endpoint_is_halted(struct usb_module *module_inst, uint8_t ep); | ||
483 | void usb_device_endpoint_set_halt(struct usb_module *module_inst, uint8_t ep); | ||
484 | void usb_device_endpoint_clear_halt(struct usb_module *module_inst, uint8_t ep); | ||
485 | |||
486 | /** @} */ | ||
487 | |||
488 | #ifdef __cplusplus | ||
489 | } | ||
490 | #endif | ||
491 | |||
492 | #endif /* USB_H_INCLUDED */ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb2422.c b/tmk_core/protocol/arm_atsam/usb/usb2422.c new file mode 100644 index 000000000..7c78e41d4 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb2422.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "arm_atsam_protocol.h" | ||
19 | #include <string.h> | ||
20 | |||
21 | Usb2422 USB2422_shadow; | ||
22 | unsigned char i2c0_buf[34]; | ||
23 | |||
24 | const uint16_t MFRNAME[] = { 'M','a','s','s','d','r','o','p',' ','I','n','c','.' }; //Massdrop Inc. | ||
25 | const uint16_t PRDNAME[] = { 'M','a','s','s','d','r','o','p',' ','H','u','b' }; //Massdrop Hub | ||
26 | #ifndef MD_BOOTLOADER | ||
27 | //Serial number reported stops before first found space character or at last found character | ||
28 | const uint16_t SERNAME[] = { 'U','n','a','v','a','i','l','a','b','l','e' }; //Unavailable | ||
29 | #else | ||
30 | //In production, this field is found, modified, and offset noted as the last 32-bit word in the bootloader space | ||
31 | //The offset allows the application to use the factory programmed serial (which may differ from the physical serial label) | ||
32 | //Serial number reported stops before first found space character or when max size is reached | ||
33 | __attribute__((__aligned__(4))) | ||
34 | const uint16_t SERNAME[BOOTLOADER_SERIAL_MAX_SIZE] = { 'M','D','H','U','B','B','O','O','T','L','0','0','0','0','0','0','0','0','0','0' }; | ||
35 | //NOTE: Serial replacer will not write a string longer than given here as a precaution, so give enough | ||
36 | // space as needed and adjust BOOTLOADER_SERIAL_MAX_SIZE to match amount given | ||
37 | #endif //MD_BOOTLOADER | ||
38 | |||
39 | uint8_t usb_host_port; | ||
40 | |||
41 | #ifndef MD_BOOTLOADER | ||
42 | |||
43 | uint8_t usb_extra_state; | ||
44 | uint8_t usb_extra_manual; | ||
45 | uint8_t usb_gcr_auto; | ||
46 | |||
47 | #endif //MD_BOOTLOADER | ||
48 | |||
49 | uint16_t adc_extra; | ||
50 | |||
51 | void USB_write2422_block(void) | ||
52 | { | ||
53 | unsigned char *dest = i2c0_buf; | ||
54 | unsigned char *src; | ||
55 | unsigned char *base = (unsigned char *)&USB2422_shadow; | ||
56 | |||
57 | DBGC(DC_USB_WRITE2422_BLOCK_BEGIN); | ||
58 | |||
59 | for (src = base; src < base + 256; src += 32) | ||
60 | { | ||
61 | dest[0] = src - base; | ||
62 | dest[1] = 32; | ||
63 | memcpy(&dest[2], src, 32); | ||
64 | i2c0_transmit(USB2422_ADDR, dest, 34, 50000); | ||
65 | SERCOM0->I2CM.CTRLB.bit.CMD = 0x03; | ||
66 | while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_USB_WRITE2422_BLOCK_SYNC_SYSOP); } | ||
67 | CLK_delay_us(100); | ||
68 | } | ||
69 | |||
70 | DBGC(DC_USB_WRITE2422_BLOCK_COMPLETE); | ||
71 | } | ||
72 | |||
73 | void USB2422_init(void) | ||
74 | { | ||
75 | Gclk *pgclk = GCLK; | ||
76 | Mclk *pmclk = MCLK; | ||
77 | Port *pport = PORT; | ||
78 | Oscctrl *posc = OSCCTRL; | ||
79 | Usb *pusb = USB; | ||
80 | Srdata_t *pspi = &srdata; | ||
81 | |||
82 | DBGC(DC_USB2422_INIT_BEGIN); | ||
83 | |||
84 | while ((v_5v = adc_get(ADC_5V)) < ADC_5V_START_LEVEL) { DBGC(DC_USB2422_INIT_WAIT_5V_LOW); } | ||
85 | |||
86 | //setup peripheral and synchronous bus clocks to USB | ||
87 | pgclk->PCHCTRL[10].bit.GEN = 0; | ||
88 | pgclk->PCHCTRL[10].bit.CHEN = 1; | ||
89 | pmclk->AHBMASK.bit.USB_ = 1; | ||
90 | pmclk->APBBMASK.bit.USB_ = 1; | ||
91 | |||
92 | //setup port pins for D-, D+, and SOF_1KHZ | ||
93 | pport->Group[0].PMUX[12].reg = 0x77; //PA24, PA25, function column H for USB D-, D+ | ||
94 | pport->Group[0].PINCFG[24].bit.PMUXEN = 1; | ||
95 | pport->Group[0].PINCFG[25].bit.PMUXEN = 1; | ||
96 | pport->Group[1].PMUX[11].bit.PMUXE = 7; //PB22, function column H for USB SOF_1KHz output | ||
97 | pport->Group[1].PINCFG[22].bit.PMUXEN = 1; | ||
98 | |||
99 | //configure and enable DFLL for USB clock recovery mode at 48MHz | ||
100 | posc->DFLLCTRLA.bit.ENABLE = 0; | ||
101 | while (posc->DFLLSYNC.bit.ENABLE) { DBGC(DC_USB2422_INIT_OSC_SYNC_DISABLING); } | ||
102 | while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_1); } | ||
103 | posc->DFLLCTRLB.bit.USBCRM = 1; | ||
104 | while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_2); } | ||
105 | posc->DFLLCTRLB.bit.MODE = 1; | ||
106 | while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_3); } | ||
107 | posc->DFLLCTRLB.bit.QLDIS = 0; | ||
108 | while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_4); } | ||
109 | posc->DFLLCTRLB.bit.CCDIS = 1; | ||
110 | posc->DFLLMUL.bit.MUL = 0xBB80; //4800 x 1KHz | ||
111 | while (posc->DFLLSYNC.bit.DFLLMUL) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLMUL); } | ||
112 | posc->DFLLCTRLA.bit.ENABLE = 1; | ||
113 | while (posc->DFLLSYNC.bit.ENABLE) { DBGC(DC_USB2422_INIT_OSC_SYNC_ENABLING); } | ||
114 | |||
115 | pusb->DEVICE.CTRLA.bit.SWRST = 1; | ||
116 | while (pusb->DEVICE.SYNCBUSY.bit.SWRST) { DBGC(DC_USB2422_INIT_USB_SYNC_SWRST); } | ||
117 | while (pusb->DEVICE.CTRLA.bit.SWRST) { DBGC(DC_USB2422_INIT_USB_WAIT_SWRST); } | ||
118 | //calibration from factory presets | ||
119 | pusb->DEVICE.PADCAL.bit.TRANSN = (USB_FUSES_TRANSN_ADDR >> USB_FUSES_TRANSN_Pos) & USB_FUSES_TRANSN_Msk; | ||
120 | pusb->DEVICE.PADCAL.bit.TRANSP = (USB_FUSES_TRANSP_ADDR >> USB_FUSES_TRANSP_Pos) & USB_FUSES_TRANSP_Msk; | ||
121 | pusb->DEVICE.PADCAL.bit.TRIM = (USB_FUSES_TRIM_ADDR >> USB_FUSES_TRIM_Pos) & USB_FUSES_TRIM_Msk; | ||
122 | //device mode, enabled | ||
123 | pusb->DEVICE.CTRLB.bit.SPDCONF = 0; //full speed | ||
124 | pusb->DEVICE.CTRLA.bit.MODE = 0; | ||
125 | pusb->DEVICE.CTRLA.bit.ENABLE = 1; | ||
126 | while (pusb->DEVICE.SYNCBUSY.bit.ENABLE) { DBGC(DC_USB2422_INIT_USB_SYNC_ENABLING); } | ||
127 | |||
128 | pusb->DEVICE.QOSCTRL.bit.DQOS = 2; | ||
129 | pusb->DEVICE.QOSCTRL.bit.CQOS = 2; | ||
130 | |||
131 | pport->Group[USB2422_HUB_ACTIVE_GROUP].PINCFG[USB2422_HUB_ACTIVE_PIN].bit.INEN = 1; | ||
132 | |||
133 | i2c0_init(); //IC2 clk must be high at USB2422 reset release time to signal SMB configuration | ||
134 | |||
135 | pspi->bit.HUB_CONNECT = 1; //connect signal | ||
136 | pspi->bit.HUB_RESET_N = 1; //reset high | ||
137 | SPI_WriteSRData(); | ||
138 | |||
139 | CLK_delay_us(100); | ||
140 | |||
141 | #ifndef MD_BOOTLOADER | ||
142 | |||
143 | usb_extra_manual = 0; | ||
144 | usb_gcr_auto = 1; | ||
145 | |||
146 | #endif //MD_BOOTLOADER | ||
147 | |||
148 | DBGC(DC_USB2422_INIT_COMPLETE); | ||
149 | } | ||
150 | |||
151 | void USB_reset(void) | ||
152 | { | ||
153 | Srdata_t *pspi = &srdata; | ||
154 | |||
155 | DBGC(DC_USB_RESET_BEGIN); | ||
156 | |||
157 | //pulse reset for at least 1 usec | ||
158 | pspi->bit.HUB_RESET_N = 0; //reset low | ||
159 | SPI_WriteSRData(); | ||
160 | CLK_delay_us(1); | ||
161 | pspi->bit.HUB_RESET_N = 1; //reset high to run | ||
162 | SPI_WriteSRData(); | ||
163 | CLK_delay_us(1); | ||
164 | |||
165 | DBGC(DC_USB_RESET_COMPLETE); | ||
166 | } | ||
167 | |||
168 | void USB_configure(void) | ||
169 | { | ||
170 | Usb2422 *pusb2422 = &USB2422_shadow; | ||
171 | memset(pusb2422, 0, sizeof(Usb2422)); | ||
172 | |||
173 | uint16_t *serial_use = (uint16_t *)SERNAME; //Default to use SERNAME from this file | ||
174 | uint8_t serial_length = sizeof(SERNAME) / sizeof(uint16_t); //Default to use SERNAME from this file | ||
175 | #ifndef MD_BOOTLOADER | ||
176 | uint32_t serial_ptrloc = (uint32_t)&_srom - 4; | ||
177 | #else //MD_BOOTLOADER | ||
178 | uint32_t serial_ptrloc = (uint32_t)&_erom - 4; | ||
179 | #endif //MD_BOOTLOADER | ||
180 | uint32_t serial_address = *(uint32_t *)serial_ptrloc; //Address of bootloader's serial number if available | ||
181 | |||
182 | DBGC(DC_USB_CONFIGURE_BEGIN); | ||
183 | |||
184 | if (serial_address != 0xFFFFFFFF && serial_address < serial_ptrloc) //Check for factory programmed serial address | ||
185 | { | ||
186 | if ((serial_address & 0xFF) % 4 == 0) //Check alignment | ||
187 | { | ||
188 | serial_use = (uint16_t *)(serial_address); | ||
189 | serial_length = 0; | ||
190 | while ((*(serial_use + serial_length) > 32 && *(serial_use + serial_length) < 127) && | ||
191 | serial_length < BOOTLOADER_SERIAL_MAX_SIZE) | ||
192 | { | ||
193 | serial_length++; | ||
194 | DBGC(DC_USB_CONFIGURE_GET_SERIAL); | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | //configure Usb2422 registers | ||
200 | pusb2422->VID.reg = 0x04D8; // from Microchip 4/19/2018 | ||
201 | pusb2422->PID.reg = 0xEEC5; // from Microchip 4/19/2018 = Massdrop, Inc. USB Hub | ||
202 | pusb2422->DID.reg = 0x0101; // BCD 01.01 | ||
203 | pusb2422->CFG1.bit.SELF_BUS_PWR = 1; // self powered for now | ||
204 | pusb2422->CFG1.bit.HS_DISABLE = 1; // full or high speed | ||
205 | //pusb2422->CFG2.bit.COMPOUND = 0; // compound device | ||
206 | pusb2422->CFG3.bit.STRING_EN = 1; // strings enabled | ||
207 | //pusb2422->NRD.bit.PORT2_NR = 0; // MCU is non-removable | ||
208 | pusb2422->MAXPB.reg = 20; // 0mA | ||
209 | pusb2422->HCMCB.reg = 20; // 0mA | ||
210 | pusb2422->MFRSL.reg = sizeof(MFRNAME) / sizeof(uint16_t); | ||
211 | pusb2422->PRDSL.reg = sizeof(PRDNAME) / sizeof(uint16_t); | ||
212 | pusb2422->SERSL.reg = serial_length; | ||
213 | memcpy(pusb2422->MFRSTR, MFRNAME, sizeof(MFRNAME)); | ||
214 | memcpy(pusb2422->PRDSTR, PRDNAME, sizeof(PRDNAME)); | ||
215 | memcpy(pusb2422->SERSTR, serial_use, serial_length * sizeof(uint16_t)); | ||
216 | //pusb2422->BOOSTUP.bit.BOOST=3; //upstream port | ||
217 | //pusb2422->BOOSTDOWN.bit.BOOST1=0; // extra port | ||
218 | //pusb2422->BOOSTDOWN.bit.BOOST2=2; //MCU is close | ||
219 | pusb2422->STCD.bit.USB_ATTACH = 1; | ||
220 | USB_write2422_block(); | ||
221 | |||
222 | adc_extra = 0; | ||
223 | |||
224 | DBGC(DC_USB_CONFIGURE_COMPLETE); | ||
225 | } | ||
226 | |||
227 | uint16_t USB_active(void) | ||
228 | { | ||
229 | return (PORT->Group[USB2422_HUB_ACTIVE_GROUP].IN.reg & (1 << USB2422_HUB_ACTIVE_PIN)) != 0; | ||
230 | } | ||
231 | |||
232 | void USB_set_host_by_voltage(void) | ||
233 | { | ||
234 | //UP is upstream device (HOST) | ||
235 | //DN1 is downstream device (EXTRA) | ||
236 | //DN2 is keyboard (KEYB) | ||
237 | |||
238 | DBGC(DC_USB_SET_HOST_BY_VOLTAGE_BEGIN); | ||
239 | |||
240 | usb_host_port = USB_HOST_PORT_UNKNOWN; | ||
241 | #ifndef MD_BOOTLOADER | ||
242 | usb_extra_state = USB_EXTRA_STATE_UNKNOWN; | ||
243 | #endif //MD_BOOTLOADER | ||
244 | srdata.bit.SRC_1 = 1; //USBC-1 available for test | ||
245 | srdata.bit.SRC_2 = 1; //USBC-2 available for test | ||
246 | srdata.bit.E_UP_N = 1; //HOST disable | ||
247 | srdata.bit.E_DN1_N = 1; //EXTRA disable | ||
248 | srdata.bit.E_VBUS_1 = 0; //USBC-1 disable full power I/O | ||
249 | srdata.bit.E_VBUS_2 = 0; //USBC-2 disable full power I/O | ||
250 | |||
251 | SPI_WriteSRData(); | ||
252 | |||
253 | CLK_delay_ms(250); | ||
254 | |||
255 | while ((v_5v = adc_get(ADC_5V)) < ADC_5V_START_LEVEL) { DBGC(DC_USB_SET_HOST_5V_LOW_WAITING); } | ||
256 | |||
257 | v_con_1 = adc_get(ADC_CON1); | ||
258 | v_con_2 = adc_get(ADC_CON2); | ||
259 | |||
260 | v_con_1_boot = v_con_1; | ||
261 | v_con_2_boot = v_con_2; | ||
262 | |||
263 | if (v_con_1 > v_con_2) | ||
264 | { | ||
265 | srdata.bit.S_UP = 0; //HOST to USBC-1 | ||
266 | srdata.bit.S_DN1 = 1; //EXTRA to USBC-2 | ||
267 | srdata.bit.SRC_1 = 1; //HOST on USBC-1 | ||
268 | srdata.bit.SRC_2 = 0; //EXTRA available on USBC-2 | ||
269 | |||
270 | srdata.bit.E_VBUS_1 = 1; //USBC-1 enable full power I/O | ||
271 | srdata.bit.E_VBUS_2 = 0; //USBC-2 disable full power I/O | ||
272 | |||
273 | SPI_WriteSRData(); | ||
274 | |||
275 | srdata.bit.E_UP_N = 0; //HOST enable | ||
276 | |||
277 | SPI_WriteSRData(); | ||
278 | |||
279 | usb_host_port = USB_HOST_PORT_1; | ||
280 | } | ||
281 | else | ||
282 | { | ||
283 | srdata.bit.S_UP = 1; //EXTRA to USBC-1 | ||
284 | srdata.bit.S_DN1 = 0; //HOST to USBC-2 | ||
285 | srdata.bit.SRC_1 = 0; //EXTRA available on USBC-1 | ||
286 | srdata.bit.SRC_2 = 1; //HOST on USBC-2 | ||
287 | |||
288 | srdata.bit.E_VBUS_1 = 0; //USBC-1 disable full power I/O | ||
289 | srdata.bit.E_VBUS_2 = 1; //USBC-2 enable full power I/O | ||
290 | |||
291 | SPI_WriteSRData(); | ||
292 | |||
293 | srdata.bit.E_UP_N = 0; //HOST enable | ||
294 | |||
295 | SPI_WriteSRData(); | ||
296 | |||
297 | usb_host_port = USB_HOST_PORT_2; | ||
298 | } | ||
299 | |||
300 | #ifndef MD_BOOTLOADER | ||
301 | usb_extra_state = USB_EXTRA_STATE_DISABLED; | ||
302 | #endif //MD_BOOTLOADER | ||
303 | |||
304 | USB_reset(); | ||
305 | USB_configure(); | ||
306 | |||
307 | DBGC(DC_USB_SET_HOST_BY_VOLTAGE_COMPLETE); | ||
308 | } | ||
309 | |||
310 | uint8_t USB2422_Port_Detect_Init(void) | ||
311 | { | ||
312 | uint32_t port_detect_retry_ms; | ||
313 | uint32_t tmod; | ||
314 | |||
315 | DBGC(DC_PORT_DETECT_INIT_BEGIN); | ||
316 | |||
317 | USB_set_host_by_voltage(); | ||
318 | |||
319 | port_detect_retry_ms = CLK_get_ms() + PORT_DETECT_RETRY_INTERVAL; | ||
320 | |||
321 | while (!USB_active()) | ||
322 | { | ||
323 | tmod = CLK_get_ms() % PORT_DETECT_RETRY_INTERVAL; | ||
324 | |||
325 | if (v_con_1 > v_con_2) //Values updated from USB_set_host_by_voltage(); | ||
326 | { | ||
327 | //1 flash for port 1 detected | ||
328 | if (tmod > 500 && tmod < 600) { led_on; } | ||
329 | else { led_off; } | ||
330 | } | ||
331 | else if (v_con_2 > v_con_1) //Values updated from USB_set_host_by_voltage(); | ||
332 | { | ||
333 | //2 flash for port 2 detected | ||
334 | if (tmod > 500 && tmod < 600) { led_on; } | ||
335 | else if (tmod > 700 && tmod < 800) { led_on; } | ||
336 | else { led_off; } | ||
337 | } | ||
338 | |||
339 | if (CLK_get_ms() > port_detect_retry_ms) | ||
340 | { | ||
341 | DBGC(DC_PORT_DETECT_INIT_FAILED); | ||
342 | return 0; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | DBGC(DC_PORT_DETECT_INIT_COMPLETE); | ||
347 | |||
348 | return 1; | ||
349 | } | ||
350 | |||
351 | #ifndef MD_BOOTLOADER | ||
352 | |||
353 | void USB_ExtraSetState(uint8_t state) | ||
354 | { | ||
355 | uint8_t state_save = state; | ||
356 | |||
357 | if (state == USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) | ||
358 | state = USB_EXTRA_STATE_DISABLED; | ||
359 | |||
360 | if (usb_host_port == USB_HOST_PORT_1) srdata.bit.E_VBUS_2 = state; | ||
361 | else if (usb_host_port == USB_HOST_PORT_2) srdata.bit.E_VBUS_1 = state; | ||
362 | else return; | ||
363 | |||
364 | srdata.bit.E_DN1_N = !state; | ||
365 | SPI_WriteSRData(); | ||
366 | |||
367 | usb_extra_state = state_save; | ||
368 | |||
369 | if (usb_extra_state == USB_EXTRA_STATE_ENABLED) CDC_print("USB: Extra enabled\r\n"); | ||
370 | else if (usb_extra_state == USB_EXTRA_STATE_DISABLED) | ||
371 | { | ||
372 | CDC_print("USB: Extra disabled\r\n"); | ||
373 | if (led_animation_breathing) gcr_breathe = gcr_desired; | ||
374 | } | ||
375 | else if (usb_extra_state == USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) CDC_print("USB: Extra disabled until replug\r\n"); | ||
376 | else CDC_print("USB: Extra state unknown\r\n"); | ||
377 | } | ||
378 | |||
379 | void USB_HandleExtraDevice(void) | ||
380 | { | ||
381 | uint16_t adcval; | ||
382 | |||
383 | if (usb_host_port == USB_HOST_PORT_1) adcval = adc_get(ADC_CON2); | ||
384 | else if (usb_host_port == USB_HOST_PORT_2) adcval = adc_get(ADC_CON1); | ||
385 | else return; | ||
386 | |||
387 | adc_extra = adc_extra * 0.9 + adcval * 0.1; | ||
388 | |||
389 | //Check for a forced disable state (such as overload prevention) | ||
390 | if (usb_extra_state == USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) | ||
391 | { | ||
392 | //Detect unplug and reset state to disabled | ||
393 | if (adc_extra > USB_EXTRA_ADC_THRESHOLD) usb_extra_state = USB_EXTRA_STATE_DISABLED; | ||
394 | |||
395 | return; //Return even if unplug detected | ||
396 | } | ||
397 | |||
398 | if (usb_extra_manual) | ||
399 | { | ||
400 | if (usb_extra_state == USB_EXTRA_STATE_DISABLED) | ||
401 | USB_ExtraSetState(USB_EXTRA_STATE_ENABLED); | ||
402 | |||
403 | return; | ||
404 | } | ||
405 | |||
406 | //dpf("a %i %i\r\n",adcval, adc_extra); | ||
407 | if (usb_extra_state == USB_EXTRA_STATE_DISABLED && adc_extra < USB_EXTRA_ADC_THRESHOLD) USB_ExtraSetState(USB_EXTRA_STATE_ENABLED); | ||
408 | else if (usb_extra_state == USB_EXTRA_STATE_ENABLED && adc_extra > USB_EXTRA_ADC_THRESHOLD) USB_ExtraSetState(USB_EXTRA_STATE_DISABLED); | ||
409 | } | ||
410 | |||
411 | #endif //MD_BOOTLOADER | ||
412 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb2422.h b/tmk_core/protocol/arm_atsam/usb/usb2422.h new file mode 100644 index 000000000..6c763dd8c --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb2422.h | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | Copyright 2018 Massdrop Inc. | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef _USB2422_H_ | ||
19 | #define _USB2422_H_ | ||
20 | |||
21 | #define USB2422_ALT67_1P0 | ||
22 | #define REV_USB2422 0x100 | ||
23 | |||
24 | #define USB2422_ADDR 0x58 //I2C device address, one instance | ||
25 | |||
26 | #define USB2422_HUB_ACTIVE_GROUP 0 //PA | ||
27 | #define USB2422_HUB_ACTIVE_PIN 18 //18 | ||
28 | |||
29 | /* -------- USB2422_VID : (USB2422L Offset: 0x00) (R/W 16) Vendor ID -------- */ | ||
30 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
31 | typedef union { | ||
32 | struct { | ||
33 | uint16_t VID_LSB : 8; | ||
34 | uint16_t VID_MSB : 8; | ||
35 | } bit; /*!< Structure used for bit access */ | ||
36 | uint16_t reg; /*!< Type used for register access */ | ||
37 | } USB2422_VID_Type; | ||
38 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
39 | |||
40 | /* -------- USB2422_PID : (USB2422L Offset: 0x02) (R/W 16) Product ID -------- */ | ||
41 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
42 | typedef union { | ||
43 | struct { | ||
44 | uint16_t PID_LSB : 8; | ||
45 | uint16_t PID_MSB : 8; | ||
46 | } bit; /*!< Structure used for bit access */ | ||
47 | uint16_t reg; /*!< Type used for register access */ | ||
48 | } USB2422_PID_Type; | ||
49 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
50 | |||
51 | /* -------- USB2422_DID : (USB2422L Offset: 0x04) (R/W 16) Device ID -------- */ | ||
52 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
53 | typedef union { | ||
54 | struct { | ||
55 | uint16_t DID_LSB : 8; | ||
56 | uint16_t DID_MSB : 8; | ||
57 | } bit; /*!< Structure used for bit access */ | ||
58 | uint16_t reg; /*!< Type used for register access */ | ||
59 | } USB2422_DID_Type; | ||
60 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
61 | |||
62 | /* -------- USB2422_CFG1 : (USB2422L Offset: 0x06) (R/W 8) Configuration Data Byte 1-------- */ | ||
63 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
64 | typedef union { | ||
65 | struct { | ||
66 | uint8_t PORT_PWR : 1; | ||
67 | uint8_t CURRENT_SNS : 2; | ||
68 | uint8_t EOP_DISABLE : 1; | ||
69 | uint8_t MTT_ENABLE : 1; | ||
70 | uint8_t HS_DISABLE :1; | ||
71 | uint8_t :1; | ||
72 | uint8_t SELF_BUS_PWR : 1; | ||
73 | } bit; /*!< Structure used for bit access */ | ||
74 | uint8_t reg; /*!< Type used for register access */ | ||
75 | } USB2422_CFG1_Type; | ||
76 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
77 | |||
78 | /* -------- USB2422_CFG2 : (USB2422L Offset: 0x07) (R/W 8) Configuration Data Byte 2-------- */ | ||
79 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
80 | typedef union { | ||
81 | struct { | ||
82 | uint8_t : 3; | ||
83 | uint8_t COMPOUND : 1; | ||
84 | uint8_t OC_TIMER :2; | ||
85 | uint8_t :1; | ||
86 | uint8_t DYNAMIC : 1; | ||
87 | } bit; /*!< Structure used for bit access */ | ||
88 | uint8_t reg; /*!< Type used for register access */ | ||
89 | } USB2422_CFG2_Type; | ||
90 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
91 | |||
92 | /* -------- USB2422_CFG3 : (USB2422L Offset: 0x08) (R/W 16) Configuration Data Byte 3-------- */ | ||
93 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
94 | typedef union { | ||
95 | struct { | ||
96 | uint8_t STRING_EN : 1; | ||
97 | uint8_t :2; | ||
98 | uint8_t PRTMAP_EN :1; | ||
99 | uint8_t : 4; | ||
100 | } bit; /*!< Structure used for bit access */ | ||
101 | uint8_t reg; /*!< Type used for register access */ | ||
102 | } USB2422_CFG3_Type; | ||
103 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
104 | |||
105 | /* -------- USB2422_NRD : (USB2422L Offset: 0x09) (R/W 8) Non Removable Device -------- */ | ||
106 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
107 | typedef union { | ||
108 | struct { | ||
109 | uint8_t : 5; | ||
110 | uint8_t PORT2_NR :1; | ||
111 | uint8_t PORT1_NR :1; | ||
112 | uint8_t : 1; | ||
113 | } bit; /*!< Structure used for bit access */ | ||
114 | uint8_t reg; /*!< Type used for register access */ | ||
115 | } USB2422_NRD_Type; | ||
116 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
117 | |||
118 | /* -------- USB2422_PDS : (USB2422L Offset: 0x0A) (R/W 8) Port Diable for Self-Powered Operation -------- */ | ||
119 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
120 | typedef union { | ||
121 | struct { | ||
122 | uint8_t : 1; | ||
123 | uint8_t PORT1_DIS :1; | ||
124 | uint8_t PORT2_DIS :1; | ||
125 | uint8_t : 5; | ||
126 | } bit; /*!< Structure used for bit access */ | ||
127 | uint8_t reg; /*!< Type used for register access */ | ||
128 | } USB2422_PDS_Type; | ||
129 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
130 | |||
131 | /* -------- USB2422_PDB : (USB2422L Offset: 0x0B) (R/W 8) Port Diable for Bus-Powered Operation -------- */ | ||
132 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
133 | typedef union { | ||
134 | struct { | ||
135 | uint8_t : 1; | ||
136 | uint8_t PORT1_DIS :1; | ||
137 | uint8_t PORT2_DIS :1; | ||
138 | uint8_t : 5; | ||
139 | } bit; /*!< Structure used for bit access */ | ||
140 | uint8_t reg; /*!< Type used for register access */ | ||
141 | } USB2422_PDB_Type; | ||
142 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
143 | |||
144 | /* -------- USB2422_MAXPS : (USB2422L Offset: 0x0C) (R/W 8) Max Power for Self-Powered Operation -------- */ | ||
145 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
146 | typedef union { | ||
147 | struct { | ||
148 | uint8_t MAX_PWR_SP : 8; | ||
149 | } bit; /*!< Structure used for bit access */ | ||
150 | uint8_t reg; /*!< Type used for register access */ | ||
151 | } USB2422_MAXPS_Type; | ||
152 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
153 | |||
154 | /* -------- USB2422_MAXPB : (USB2422L Offset: 0x0D) (R/W 8) Max Power for Bus-Powered Operation -------- */ | ||
155 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
156 | typedef union { | ||
157 | struct { | ||
158 | uint8_t MAX_PWR_BP : 8; | ||
159 | } bit; /*!< Structure used for bit access */ | ||
160 | uint8_t reg; /*!< Type used for register access */ | ||
161 | } USB2422_MAXPB_Type; | ||
162 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
163 | |||
164 | /* -------- USB2422_HCMCS : (USB2422L Offset: 0x0E) (R/W 8) Hub Controller Max Current for Self-Powered Operation -------- */ | ||
165 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
166 | typedef union { | ||
167 | struct { | ||
168 | uint8_t HC_MAX_C_SP : 8; | ||
169 | } bit; /*!< Structure used for bit access */ | ||
170 | uint8_t reg; /*!< Type used for register access */ | ||
171 | } USB2422_HCMCS_Type; | ||
172 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
173 | |||
174 | /* -------- USB2422_HCMCB : (USB2422L Offset: 0x0F) (R/W 8) Hub Controller Max Current for Bus-Powered Operation -------- */ | ||
175 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
176 | typedef union { | ||
177 | struct { | ||
178 | uint8_t HC_MAX_C_BP : 8; | ||
179 | } bit; /*!< Structure used for bit access */ | ||
180 | uint8_t reg; /*!< Type used for register access */ | ||
181 | } USB2422_HCMCB_Type; | ||
182 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
183 | |||
184 | /* -------- USB2422_PWRT : (USB2422L Offset: 0x10) (R/W 8) Power On Time -------- */ | ||
185 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
186 | typedef union { | ||
187 | struct { | ||
188 | uint8_t POWER_ON_TIME : 8; | ||
189 | } bit; /*!< Structure used for bit access */ | ||
190 | uint8_t reg; /*!< Type used for register access */ | ||
191 | } USB2422_PWRT_Type; | ||
192 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
193 | |||
194 | /* -------- USB2422_LANGID LSB : (USB2422L Offset: 0x11) (R/W 16) Language ID -------- */ | ||
195 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
196 | typedef union { | ||
197 | struct { | ||
198 | uint8_t LANGID_LSB : 8; | ||
199 | } bit; /*!< Structure used for bit access */ | ||
200 | uint8_t reg; /*!< Type used for register access */ | ||
201 | } USB2422_LANGID_LSB_Type; | ||
202 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
203 | |||
204 | /* -------- USB2422_LANGID MSB : (USB2422L Offset: 0x12) (R/W 16) Language ID -------- */ | ||
205 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
206 | typedef union { | ||
207 | struct { | ||
208 | uint8_t LANGID_MSB : 8; | ||
209 | } bit; /*!< Structure used for bit access */ | ||
210 | uint8_t reg; /*!< Type used for register access */ | ||
211 | } USB2422_LANGID_MSB_Type; | ||
212 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
213 | |||
214 | |||
215 | /* -------- USB2422_MFRSL : (USB2422L Offset: 0x13) (R/W 8) Manufacturer String Length -------- */ | ||
216 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
217 | typedef union { | ||
218 | struct { | ||
219 | uint8_t MFR_STR_LEN : 8; | ||
220 | } bit; /*!< Structure used for bit access */ | ||
221 | uint8_t reg; /*!< Type used for register access */ | ||
222 | } USB2422_MFRSL_Type; | ||
223 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
224 | |||
225 | /* -------- USB2422_PRDSL : (USB2422L Offset: 0x14) (R/W 8) Product String Length -------- */ | ||
226 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
227 | typedef union { | ||
228 | struct { | ||
229 | uint8_t PRD_STR_LEN : 8; | ||
230 | } bit; /*!< Structure used for bit access */ | ||
231 | uint8_t reg; /*!< Type used for register access */ | ||
232 | } USB2422_PRDSL_Type; | ||
233 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
234 | |||
235 | /* -------- USB2422_SERSL : (USB2422L Offset: 0x15) (R/W 8) Serial String Length -------- */ | ||
236 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
237 | typedef union { | ||
238 | struct { | ||
239 | uint8_t SER_STR_LEN : 8; | ||
240 | } bit; /*!< Structure used for bit access */ | ||
241 | uint8_t reg; /*!< Type used for register access */ | ||
242 | } USB2422_SERSL_Type; | ||
243 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
244 | |||
245 | /* -------- USB2422_MFRSTR : (USB2422L Offset: 0x16-53) (R/W 8) Maufacturer String -------- */ | ||
246 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
247 | typedef uint16_t USB2422_MFRSTR_Type; | ||
248 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
249 | |||
250 | /* -------- USB2422_PRDSTR : (USB2422L Offset: 0x54-91) (R/W 8) Product String -------- */ | ||
251 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
252 | typedef uint16_t USB2422_PRDSTR_Type; | ||
253 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
254 | |||
255 | /* -------- USB2422_SERSTR : (USB2422L Offset: 0x92-CF) (R/W 8) Serial String -------- */ | ||
256 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
257 | typedef uint16_t USB2422_SERSTR_Type; | ||
258 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
259 | |||
260 | /* -------- USB2422_BCEN : (USB2422L Offset: 0xD0) (R/W 8) Battery Charging Enable -------- */ | ||
261 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
262 | typedef union { | ||
263 | struct { | ||
264 | uint8_t : 1; | ||
265 | uint8_t PORT1_BCE :1; | ||
266 | uint8_t PORT2_BCE :1; | ||
267 | uint8_t : 5; | ||
268 | } bit; /*!< Structure used for bit access */ | ||
269 | uint8_t reg; /*!< Type used for register access */ | ||
270 | } USB2422_BCEN_Type; | ||
271 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
272 | |||
273 | /* -------- USB2422_BOOSTUP : (USB2422L Offset: 0xF6) (R/W 8) Boost Upstream -------- */ | ||
274 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
275 | typedef union { | ||
276 | struct { | ||
277 | uint8_t BOOST :2; | ||
278 | uint8_t : 6; | ||
279 | } bit; /*!< Structure used for bit access */ | ||
280 | uint8_t reg; /*!< Type used for register access */ | ||
281 | } USB2422_BOOSTUP_Type; | ||
282 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
283 | |||
284 | /* -------- USB2422_BOOSTDOWN : (USB2422L Offset: 0xF8) (R/W 8) Boost Downstream -------- */ | ||
285 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
286 | typedef union { | ||
287 | struct { | ||
288 | uint8_t BOOST1 :2; | ||
289 | uint8_t BOOST2 :2; | ||
290 | uint8_t : 4; | ||
291 | } bit; /*!< Structure used for bit access */ | ||
292 | uint8_t reg; /*!< Type used for register access */ | ||
293 | } USB2422_BOOSTDOWN_Type; | ||
294 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
295 | |||
296 | /* -------- USB2422_PRTSP : (USB2422L Offset: 0xFA) (R/W 8) Port Swap -------- */ | ||
297 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
298 | typedef union { | ||
299 | struct { | ||
300 | uint8_t : 1; | ||
301 | uint8_t PORT1_SP :1; | ||
302 | uint8_t PORT2_SP :1; | ||
303 | uint8_t : 5; | ||
304 | } bit; /*!< Structure used for bit access */ | ||
305 | uint8_t reg; /*!< Type used for register access */ | ||
306 | } USB2422_PRTSP_Type; | ||
307 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
308 | |||
309 | /* -------- USB2422_PRTR12 : (USB2422L Offset: 0xFB) (R/W 8) Port 1/2 Remap -------- */ | ||
310 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
311 | typedef union { | ||
312 | struct { | ||
313 | uint8_t PORT1_REMAP: 4; | ||
314 | uint8_t PORT2_REMAP: 4; | ||
315 | } bit; /*!< Structure used for bit access */ | ||
316 | uint8_t reg; /*!< Type used for register access */ | ||
317 | } USB2422_PRTR12_Type; | ||
318 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
319 | #define USB2422_PRTR12_DISABLE 0 | ||
320 | #define USB2422_PRT12_P2TOL1 1 | ||
321 | #define USB2422_PRT12_P2XTOL2 2 | ||
322 | #define USB2422_PRT12_P1TOL1 1 | ||
323 | #define USB2422_PRT12_P1XTOL2 2 | ||
324 | |||
325 | /* -------- USB2422_STCD : (USB2422L Offset: 0xFF) (R/W 8) Status Command -------- */ | ||
326 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
327 | typedef union { | ||
328 | struct { | ||
329 | uint8_t USB_ATTACH: 1; | ||
330 | uint8_t RESET: 1; | ||
331 | uint8_t INTF_PWRDN: 1; | ||
332 | uint8_t : 5; | ||
333 | } bit; /*!< Structure used for bit access */ | ||
334 | uint8_t reg; /*!< Type used for register access */ | ||
335 | } USB2422_STCD_Type; | ||
336 | #endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ | ||
337 | |||
338 | /** \brief USB2422 device hardware registers */ | ||
339 | #if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) | ||
340 | typedef struct { | ||
341 | USB2422_VID_Type VID; /**< \brief Offset: 0x00*/ | ||
342 | USB2422_PID_Type PID; /**< \brief Offset: 0x02*/ | ||
343 | USB2422_DID_Type DID; /**< \brief Offset: 0x04*/ | ||
344 | USB2422_CFG1_Type CFG1; /**< \brief Offset: 0x06*/ | ||
345 | USB2422_CFG2_Type CFG2; /**< \brief Offset: 0x07*/ | ||
346 | USB2422_CFG3_Type CFG3; /**< \brief Offset: 0x08*/ | ||
347 | USB2422_NRD_Type NRD; /**< \brief Offset: 0x09*/ | ||
348 | USB2422_PDS_Type PDS; /**< \brief Offset: 0x0A*/ | ||
349 | USB2422_PDB_Type PDB; /**< \brief Offset: 0x0B*/ | ||
350 | USB2422_MAXPS_Type MAXPS; /**< \brief Offset: 0x0C*/ | ||
351 | USB2422_MAXPB_Type MAXPB; /**< \brief Offset: 0x0D*/ | ||
352 | USB2422_HCMCS_Type HCMCS; /**< \brief Offset: 0x0E*/ | ||
353 | USB2422_HCMCB_Type HCMCB; /**< \brief Offset: 0x0F*/ | ||
354 | USB2422_PWRT_Type PWRT; /**< \brief Offset: 0x10*/ | ||
355 | USB2422_LANGID_LSB_Type LANGID_LSB; /**< \brief Offset: 0x11*/ | ||
356 | USB2422_LANGID_MSB_Type LANGID_MSB; /**< \brief Offset: 0x12*/ | ||
357 | USB2422_MFRSL_Type MFRSL; /**< \brief Offset: 0x13*/ | ||
358 | USB2422_PRDSL_Type PRDSL; /**< \brief Offset: 0x14*/ | ||
359 | USB2422_SERSL_Type SERSL; /**< \brief Offset: 0x15*/ | ||
360 | USB2422_MFRSTR_Type MFRSTR[31]; /**< \brief Offset: 0x16*/ | ||
361 | USB2422_PRDSTR_Type PRDSTR[31]; /**< \brief Offset: 0x54*/ | ||
362 | USB2422_SERSTR_Type SERSTR[31]; /**< \brief Offset: 0x92*/ | ||
363 | USB2422_BCEN_Type BCEN; /**< \brief Offset: 0xD0*/ | ||
364 | uint8_t Reserved1[0x25]; | ||
365 | USB2422_BOOSTUP_Type BOOSTUP; /**< \brief Offset: 0xF6*/ | ||
366 | uint8_t Reserved2[0x1]; | ||
367 | USB2422_BOOSTDOWN_Type BOOSTDOWN; /**< \brief Offset: 0xF8*/ | ||
368 | uint8_t Reserved3[0x1]; | ||
369 | USB2422_PRTSP_Type PRTSP; /**< \brief Offset: 0xFA*/ | ||
370 | USB2422_PRTR12_Type PRTR12; /**< \brief Offset: 0xFB*/ | ||
371 | uint8_t Reserved4[0x3]; | ||
372 | USB2422_STCD_Type STCD; /**< \brief Offset: 0xFF*/ | ||
373 | } Usb2422; | ||
374 | #endif | ||
375 | |||
376 | #define PORT_DETECT_RETRY_INTERVAL 2000 | ||
377 | |||
378 | #define USB_EXTRA_ADC_THRESHOLD 900 | ||
379 | |||
380 | #define USB_EXTRA_STATE_DISABLED 0 | ||
381 | #define USB_EXTRA_STATE_ENABLED 1 | ||
382 | #define USB_EXTRA_STATE_UNKNOWN 2 | ||
383 | #define USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG 3 | ||
384 | |||
385 | #define USB_HOST_PORT_1 0 | ||
386 | #define USB_HOST_PORT_2 1 | ||
387 | #define USB_HOST_PORT_UNKNOWN 2 | ||
388 | |||
389 | extern uint8_t usb_host_port; | ||
390 | extern uint8_t usb_extra_state; | ||
391 | extern uint8_t usb_extra_manual; | ||
392 | extern uint8_t usb_gcr_auto; | ||
393 | |||
394 | void USB2422_init(void); | ||
395 | void USB_reset(void); | ||
396 | void USB_configure(void); | ||
397 | uint16_t USB_active(void); | ||
398 | void USB_set_host_by_voltage(void); | ||
399 | uint16_t adc_get(uint8_t muxpos); | ||
400 | uint8_t USB2422_Port_Detect_Init(void); | ||
401 | void USB_HandleExtraDevice(void); | ||
402 | void USB_ExtraSetState(uint8_t state); | ||
403 | |||
404 | #endif //_USB2422_H_ | ||
405 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_atmel.h b/tmk_core/protocol/arm_atsam/usb/usb_atmel.h new file mode 100644 index 000000000..7febdc9ec --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_atmel.h | |||
@@ -0,0 +1,190 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief All USB VIDs and PIDs from Atmel USB applications | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _USB_ATMEL_H_ | ||
48 | #define _USB_ATMEL_H_ | ||
49 | |||
50 | /** | ||
51 | * \defgroup usb_group USB Stack | ||
52 | * | ||
53 | * This stack includes the USB Device Stack, USB Host Stack and common | ||
54 | * definitions. | ||
55 | * @{ | ||
56 | */ | ||
57 | |||
58 | //! @} | ||
59 | |||
60 | /** | ||
61 | * \ingroup usb_group | ||
62 | * \defgroup usb_atmel_ids_group Atmel USB Identifiers | ||
63 | * | ||
64 | * This module defines Atmel PID and VIDs constants. | ||
65 | * | ||
66 | * @{ | ||
67 | */ | ||
68 | |||
69 | //! \name Vendor Identifier assigned by USB org to ATMEL | ||
70 | #define USB_VID_ATMEL 0x03EB | ||
71 | |||
72 | //! \name Product Identifier assigned by ATMEL to AVR applications | ||
73 | //! @{ | ||
74 | |||
75 | //! \name The range from 2000h to 20FFh is reserved to the old PID for C51, MEGA, and others. | ||
76 | //! @{ | ||
77 | #define USB_PID_ATMEL_MEGA_HIDGENERIC 0x2013 | ||
78 | #define USB_PID_ATMEL_MEGA_HIDKEYBOARD 0x2017 | ||
79 | #define USB_PID_ATMEL_MEGA_CDC 0x2018 | ||
80 | #define USB_PID_ATMEL_MEGA_AUDIO_IN 0x2019 | ||
81 | #define USB_PID_ATMEL_MEGA_MS 0x201A | ||
82 | #define USB_PID_ATMEL_MEGA_AUDIO_IN_OUT 0x201B | ||
83 | #define USB_PID_ATMEL_MEGA_HIDMOUSE 0x201C | ||
84 | #define USB_PID_ATMEL_MEGA_HIDMOUSE_CERTIF_U4 0x201D | ||
85 | #define USB_PID_ATMEL_MEGA_CDC_MULTI 0x201E | ||
86 | #define USB_PID_ATMEL_MEGA_MS_HIDMS_HID_USBKEY 0x2022 | ||
87 | #define USB_PID_ATMEL_MEGA_MS_HIDMS_HID_STK525 0x2023 | ||
88 | #define USB_PID_ATMEL_MEGA_MS_2 0x2029 | ||
89 | #define USB_PID_ATMEL_MEGA_MS_HIDMS 0x202A | ||
90 | #define USB_PID_ATMEL_MEGA_MS_3 0x2032 | ||
91 | #define USB_PID_ATMEL_MEGA_LIBUSB 0x2050 | ||
92 | //! @} | ||
93 | |||
94 | //! \name The range 2100h to 21FFh is reserved to PIDs for AVR Tools. | ||
95 | //! @{ | ||
96 | #define USB_PID_ATMEL_XPLAINED 0x2122 | ||
97 | #define USB_PID_ATMEL_XMEGA_USB_ZIGBIT_2_4GHZ 0x214A | ||
98 | #define USB_PID_ATMEL_XMEGA_USB_ZIGBIT_SUBGHZ 0x214B | ||
99 | //! @} | ||
100 | |||
101 | //! \name The range 2300h to 23FFh is reserved to PIDs for demo from ASF1.7=> | ||
102 | //! @{ | ||
103 | #define USB_PID_ATMEL_UC3_ENUM 0x2300 | ||
104 | #define USB_PID_ATMEL_UC3_MS 0x2301 | ||
105 | #define USB_PID_ATMEL_UC3_MS_SDRAM_LOADER 0x2302 | ||
106 | #define USB_PID_ATMEL_UC3_EVK1100_CTRLPANEL 0x2303 | ||
107 | #define USB_PID_ATMEL_UC3_HID 0x2304 | ||
108 | #define USB_PID_ATMEL_UC3_EVK1101_CTRLPANEL_HID 0x2305 | ||
109 | #define USB_PID_ATMEL_UC3_EVK1101_CTRLPANEL_HID_MS 0x2306 | ||
110 | #define USB_PID_ATMEL_UC3_CDC 0x2307 | ||
111 | #define USB_PID_ATMEL_UC3_AUDIO_MICRO 0x2308 | ||
112 | #define USB_PID_ATMEL_UC3_CDC_DEBUG 0x2310 // Virtual Com (debug interface) on EVK11xx | ||
113 | #define USB_PID_ATMEL_UC3_AUDIO_SPEAKER_MICRO 0x2311 | ||
114 | #define USB_PID_ATMEL_UC3_CDC_MSC 0x2312 | ||
115 | //! @} | ||
116 | |||
117 | //! \name The range 2400h to 24FFh is reserved to PIDs for ASF applications | ||
118 | //! @{ | ||
119 | #define USB_PID_ATMEL_ASF_HIDMOUSE 0x2400 | ||
120 | #define USB_PID_ATMEL_ASF_HIDKEYBOARD 0x2401 | ||
121 | #define USB_PID_ATMEL_ASF_HIDGENERIC 0x2402 | ||
122 | #define USB_PID_ATMEL_ASF_MSC 0x2403 | ||
123 | #define USB_PID_ATMEL_ASF_CDC 0x2404 | ||
124 | #define USB_PID_ATMEL_ASF_PHDC 0x2405 | ||
125 | #define USB_PID_ATMEL_ASF_HIDMTOUCH 0x2406 | ||
126 | #define USB_PID_ATMEL_ASF_MSC_HIDMOUSE 0x2420 | ||
127 | #define USB_PID_ATMEL_ASF_MSC_HIDS_CDC 0x2421 | ||
128 | #define USB_PID_ATMEL_ASF_MSC_HIDKEYBOARD 0x2422 | ||
129 | #define USB_PID_ATMEL_ASF_VENDOR_CLASS 0x2423 | ||
130 | #define USB_PID_ATMEL_ASF_MSC_CDC 0x2424 | ||
131 | #define USB_PID_ATMEL_ASF_TWO_CDC 0x2425 | ||
132 | #define USB_PID_ATMEL_ASF_SEVEN_CDC 0x2426 | ||
133 | #define USB_PID_ATMEL_ASF_XPLAIN_BC_POWERONLY 0x2430 | ||
134 | #define USB_PID_ATMEL_ASF_XPLAIN_BC_TERMINAL 0x2431 | ||
135 | #define USB_PID_ATMEL_ASF_XPLAIN_BC_TOUCH 0x2432 | ||
136 | #define USB_PID_ATMEL_ASF_AUDIO_SPEAKER 0x2433 | ||
137 | #define USB_PID_ATMEL_ASF_XMEGA_B1_XPLAINED 0x2434 | ||
138 | //! @} | ||
139 | |||
140 | //! \name The range 2F00h to 2FFFh is reserved to official PIDs for AVR bootloaders | ||
141 | //! Note, !!!! don't use this range for demos or examples !!!! | ||
142 | //! @{ | ||
143 | #define USB_PID_ATMEL_DFU_ATXMEGA64C3 0x2FD6 | ||
144 | #define USB_PID_ATMEL_DFU_ATXMEGA128C3 0x2FD7 | ||
145 | #define USB_PID_ATMEL_DFU_ATXMEGA16C4 0x2FD8 | ||
146 | #define USB_PID_ATMEL_DFU_ATXMEGA32C4 0x2FD9 | ||
147 | #define USB_PID_ATMEL_DFU_ATXMEGA256C3 0x2FDA | ||
148 | #define USB_PID_ATMEL_DFU_ATXMEGA384C3 0x2FDB | ||
149 | #define USB_PID_ATMEL_DFU_ATUCL3_L4 0x2FDC | ||
150 | #define USB_PID_ATMEL_DFU_ATXMEGA64A4U 0x2FDD | ||
151 | #define USB_PID_ATMEL_DFU_ATXMEGA128A4U 0x2FDE | ||
152 | |||
153 | #define USB_PID_ATMEL_DFU_ATXMEGA64B3 0x2FDF | ||
154 | #define USB_PID_ATMEL_DFU_ATXMEGA128B3 0x2FE0 | ||
155 | #define USB_PID_ATMEL_DFU_ATXMEGA64B1 0x2FE1 | ||
156 | #define USB_PID_ATMEL_DFU_ATXMEGA256A3BU 0x2FE2 | ||
157 | #define USB_PID_ATMEL_DFU_ATXMEGA16A4U 0x2FE3 | ||
158 | #define USB_PID_ATMEL_DFU_ATXMEGA32A4U 0x2FE4 | ||
159 | #define USB_PID_ATMEL_DFU_ATXMEGA64A3U 0x2FE5 | ||
160 | #define USB_PID_ATMEL_DFU_ATXMEGA128A3U 0x2FE6 | ||
161 | #define USB_PID_ATMEL_DFU_ATXMEGA192A3U 0x2FE7 | ||
162 | #define USB_PID_ATMEL_DFU_ATXMEGA64A1U 0x2FE8 | ||
163 | #define USB_PID_ATMEL_DFU_ATUC3D 0x2FE9 | ||
164 | #define USB_PID_ATMEL_DFU_ATXMEGA128B1 0x2FEA | ||
165 | #define USB_PID_ATMEL_DFU_AT32UC3C 0x2FEB | ||
166 | #define USB_PID_ATMEL_DFU_ATXMEGA256A3U 0x2FEC | ||
167 | #define USB_PID_ATMEL_DFU_ATXMEGA128A1U 0x2FED | ||
168 | #define USB_PID_ATMEL_DFU_ATMEGA8U2 0x2FEE | ||
169 | #define USB_PID_ATMEL_DFU_ATMEGA16U2 0x2FEF | ||
170 | #define USB_PID_ATMEL_DFU_ATMEGA32U2 0x2FF0 | ||
171 | #define USB_PID_ATMEL_DFU_AT32UC3A3 0x2FF1 | ||
172 | #define USB_PID_ATMEL_DFU_ATMEGA32U6 0x2FF2 | ||
173 | #define USB_PID_ATMEL_DFU_ATMEGA16U4 0x2FF3 | ||
174 | #define USB_PID_ATMEL_DFU_ATMEGA32U4 0x2FF4 | ||
175 | #define USB_PID_ATMEL_DFU_AT32AP7200 0x2FF5 | ||
176 | #define USB_PID_ATMEL_DFU_AT32UC3B 0x2FF6 | ||
177 | #define USB_PID_ATMEL_DFU_AT90USB82 0x2FF7 | ||
178 | #define USB_PID_ATMEL_DFU_AT32UC3A 0x2FF8 | ||
179 | #define USB_PID_ATMEL_DFU_AT90USB64 0x2FF9 | ||
180 | #define USB_PID_ATMEL_DFU_AT90USB162 0x2FFA | ||
181 | #define USB_PID_ATMEL_DFU_AT90USB128 0x2FFB | ||
182 | // 2FFCh to 2FFFh used by C51 family products | ||
183 | //! @} | ||
184 | |||
185 | //! @} | ||
186 | |||
187 | //! @} | ||
188 | |||
189 | |||
190 | #endif // _USB_ATMEL_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_device_udd.c b/tmk_core/protocol/arm_atsam/usb/usb_device_udd.c new file mode 100644 index 000000000..b31256df7 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_device_udd.c | |||
@@ -0,0 +1,1097 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Device wrapper layer for compliance with common driver UDD | ||
5 | * | ||
6 | * Copyright (C) 2014-2016 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | #include "samd51j18a.h" | ||
47 | #include <string.h> | ||
48 | #include <stdlib.h> | ||
49 | |||
50 | // Get USB device configuration | ||
51 | #include "conf_usb.h" | ||
52 | #include "udd.h" | ||
53 | #include "usb.h" | ||
54 | #include "status_codes.h" | ||
55 | |||
56 | /** | ||
57 | * \ingroup usb_device_group | ||
58 | * \defgroup usb_device_udd_group USB Device Driver Implement (UDD) | ||
59 | * USB low-level driver for USB device mode | ||
60 | * @{ | ||
61 | */ | ||
62 | // Check USB device configuration | ||
63 | #ifdef USB_DEVICE_HS_SUPPORT | ||
64 | # error The High speed mode is not supported on this part, please remove USB_DEVICE_HS_SUPPORT in conf_usb.h | ||
65 | #endif | ||
66 | |||
67 | //Note: This driver is adapted for SAMD51 | ||
68 | |||
69 | #ifndef UDC_REMOTEWAKEUP_LPM_ENABLE | ||
70 | #define UDC_REMOTEWAKEUP_LPM_ENABLE() | ||
71 | #endif | ||
72 | #ifndef UDC_REMOTEWAKEUP_LPM_DISABLE | ||
73 | #define UDC_REMOTEWAKEUP_LPM_DISABLE() | ||
74 | #endif | ||
75 | #ifndef UDC_SUSPEND_LPM_EVENT | ||
76 | #define UDC_SUSPEND_LPM_EVENT() | ||
77 | #endif | ||
78 | |||
79 | /* for debug text */ | ||
80 | #ifdef USB_DEBUG | ||
81 | # define dbg_print printf | ||
82 | #else | ||
83 | # define dbg_print(...) | ||
84 | #endif | ||
85 | |||
86 | /** Maximum size of a transfer in multi-packet mode */ | ||
87 | #define UDD_ENDPOINT_MAX_TRANS ((8*1024)-1) | ||
88 | |||
89 | /** USB software device instance structure */ | ||
90 | struct usb_module usb_device; | ||
91 | |||
92 | /** | ||
93 | * \name Clock management | ||
94 | * | ||
95 | * @{ | ||
96 | */ | ||
97 | |||
98 | #define UDD_CLOCK_GEN 0 | ||
99 | |||
100 | static inline void udd_wait_clock_ready(void) | ||
101 | { | ||
102 | |||
103 | } | ||
104 | |||
105 | /** | ||
106 | * \name Power management | ||
107 | * | ||
108 | * @{ | ||
109 | */ | ||
110 | #define udd_sleep_mode(arg) | ||
111 | /** @} */ | ||
112 | |||
113 | /** | ||
114 | * \name Control endpoint low level management routine. | ||
115 | * | ||
116 | * This function performs control endpoint management. | ||
117 | * It handles the SETUP/DATA/HANDSHAKE phases of a control transaction. | ||
118 | * | ||
119 | * @{ | ||
120 | */ | ||
121 | |||
122 | /** | ||
123 | * \brief Buffer to store the data received on control endpoint (SETUP/OUT endpoint 0) | ||
124 | * | ||
125 | * Used to avoid a RAM buffer overflow in case of the payload buffer | ||
126 | * is smaller than control endpoint size | ||
127 | */ | ||
128 | UDC_BSS(4) | ||
129 | uint8_t udd_ctrl_buffer[USB_DEVICE_EP_CTRL_SIZE]; | ||
130 | |||
131 | /** Bit definitions about endpoint control state machine for udd_ep_control_state */ | ||
132 | typedef enum { | ||
133 | UDD_EPCTRL_SETUP = 0, //!< Wait a SETUP packet | ||
134 | UDD_EPCTRL_DATA_OUT = 1, //!< Wait a OUT data packet | ||
135 | UDD_EPCTRL_DATA_IN = 2, //!< Wait a IN data packet | ||
136 | UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP = 3, //!< Wait a IN ZLP packet | ||
137 | UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP = 4, //!< Wait a OUT ZLP packet | ||
138 | UDD_EPCTRL_STALL_REQ = 5, //!< STALL enabled on IN & OUT packet | ||
139 | } udd_ctrl_ep_state_t; | ||
140 | |||
141 | /** Global variable to give and record information of the set up request management */ | ||
142 | udd_ctrl_request_t udd_g_ctrlreq; | ||
143 | |||
144 | /** State of the endpoint control management */ | ||
145 | static udd_ctrl_ep_state_t udd_ep_control_state; | ||
146 | |||
147 | /** Total number of data received/sent during data packet phase with previous payload buffers */ | ||
148 | static uint16_t udd_ctrl_prev_payload_nb_trans; | ||
149 | |||
150 | /** Number of data received/sent to/from udd_g_ctrlreq.payload buffer */ | ||
151 | static uint16_t udd_ctrl_payload_nb_trans; | ||
152 | |||
153 | /** @} */ | ||
154 | |||
155 | /** | ||
156 | * \name Management of bulk/interrupt/isochronous endpoints | ||
157 | * | ||
158 | * The UDD manages the data transfer on endpoints: | ||
159 | * - Start data transfer on endpoint with USB Device DMA | ||
160 | * - Send a ZLP packet if requested | ||
161 | * - Call callback registered to signal end of transfer | ||
162 | * The transfer abort and stall feature are supported. | ||
163 | * | ||
164 | * @{ | ||
165 | */ | ||
166 | |||
167 | /** | ||
168 | * \brief Buffer to store the data received on bulk/interrupt endpoints | ||
169 | * | ||
170 | * Used to avoid a RAM buffer overflow in case of the user buffer | ||
171 | * is smaller than endpoint size | ||
172 | * | ||
173 | * \warning The protected interrupt endpoint size is 512 bytes maximum. | ||
174 | * \warning The isochronous and endpoint is not protected by this system and | ||
175 | * the user must always use a buffer corresponding at endpoint size. | ||
176 | */ | ||
177 | |||
178 | #if (defined USB_DEVICE_LOW_SPEED) | ||
179 | UDC_BSS(4) uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][8]; | ||
180 | #elif (defined USB_DEVICE_HS_SUPPORT) | ||
181 | UDC_BSS(4) uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][512]; | ||
182 | #else | ||
183 | UDC_BSS(4) uint8_t udd_ep_out_cache_buffer[USB_DEVICE_MAX_EP][64]; | ||
184 | #endif | ||
185 | |||
186 | /** Structure definition about job registered on an endpoint */ | ||
187 | typedef struct { | ||
188 | union { | ||
189 | //! Callback to call at the end of transfer | ||
190 | udd_callback_trans_t call_trans; | ||
191 | //! Callback to call when the endpoint halt is cleared | ||
192 | udd_callback_halt_cleared_t call_nohalt; | ||
193 | }; | ||
194 | //! Buffer located in internal RAM to send or fill during job | ||
195 | uint8_t *buf; | ||
196 | //! Size of buffer to send or fill | ||
197 | iram_size_t buf_size; | ||
198 | //! Total number of data transferred on endpoint | ||
199 | iram_size_t nb_trans; | ||
200 | //! Endpoint size | ||
201 | uint16_t ep_size; | ||
202 | //! A job is registered on this endpoint | ||
203 | uint8_t busy:1; | ||
204 | //! A short packet is requested for this job on endpoint IN | ||
205 | uint8_t b_shortpacket:1; | ||
206 | //! The cache buffer is currently used on endpoint OUT | ||
207 | uint8_t b_use_out_cache_buffer:1; | ||
208 | } udd_ep_job_t; | ||
209 | |||
210 | /** Array to register a job on bulk/interrupt/isochronous endpoint */ | ||
211 | static udd_ep_job_t udd_ep_job[2 * USB_DEVICE_MAX_EP]; | ||
212 | |||
213 | /** @} */ | ||
214 | |||
215 | /** | ||
216 | * \brief Get the detailed job by endpoint number | ||
217 | * \param[in] ep Endpoint Address | ||
218 | * \retval pointer to an udd_ep_job_t structure instance | ||
219 | */ | ||
220 | static udd_ep_job_t* udd_ep_get_job(udd_ep_id_t ep) | ||
221 | { | ||
222 | if ((ep == 0) || (ep == 0x80)) { | ||
223 | return NULL; | ||
224 | } else { | ||
225 | return &udd_ep_job[(2 * (ep & USB_EP_ADDR_MASK) + ((ep & USB_EP_DIR_IN) ? 1 : 0)) - 2]; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * \brief Endpoint IN process, continue to send packets or zero length packet | ||
231 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
232 | */ | ||
233 | static void udd_ep_trans_in_next(void* pointer) | ||
234 | { | ||
235 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
236 | udd_ep_id_t ep = ep_callback_para->endpoint_address; | ||
237 | uint16_t ep_size, nb_trans; | ||
238 | uint16_t next_trans; | ||
239 | udd_ep_id_t ep_num; | ||
240 | udd_ep_job_t *ptr_job; | ||
241 | |||
242 | ptr_job = udd_ep_get_job(ep); | ||
243 | ep_num = ep & USB_EP_ADDR_MASK; | ||
244 | |||
245 | ep_size = ptr_job->ep_size; | ||
246 | /* Update number of data transferred */ | ||
247 | nb_trans = ep_callback_para->sent_bytes; | ||
248 | ptr_job->nb_trans += nb_trans; | ||
249 | |||
250 | /* Need to send other data */ | ||
251 | if (ptr_job->nb_trans != ptr_job->buf_size) { | ||
252 | next_trans = ptr_job->buf_size - ptr_job->nb_trans; | ||
253 | if (UDD_ENDPOINT_MAX_TRANS < next_trans) { | ||
254 | /* The USB hardware support a maximum | ||
255 | * transfer size of UDD_ENDPOINT_MAX_TRANS Bytes */ | ||
256 | next_trans = UDD_ENDPOINT_MAX_TRANS -(UDD_ENDPOINT_MAX_TRANS % ep_size); | ||
257 | } | ||
258 | /* Need ZLP, if requested and last packet is not a short packet */ | ||
259 | ptr_job->b_shortpacket = ptr_job->b_shortpacket && (0 == (next_trans % ep_size)); | ||
260 | usb_device_endpoint_write_buffer_job(&usb_device,ep_num,&ptr_job->buf[ptr_job->nb_trans],next_trans); | ||
261 | return; | ||
262 | } | ||
263 | |||
264 | /* Need to send a ZLP after all data transfer */ | ||
265 | if (ptr_job->b_shortpacket) { | ||
266 | ptr_job->b_shortpacket = false; | ||
267 | /* Start new transfer */ | ||
268 | usb_device_endpoint_write_buffer_job(&usb_device,ep_num,&ptr_job->buf[ptr_job->nb_trans],0); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | /* Job complete then call callback */ | ||
273 | ptr_job->busy = false; | ||
274 | if (NULL != ptr_job->call_trans) { | ||
275 | ptr_job->call_trans(UDD_EP_TRANSFER_OK, ptr_job->nb_trans, ep); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * \brief Endpoint OUT process, continue to receive packets or zero length packet | ||
281 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
282 | */ | ||
283 | static void udd_ep_trans_out_next(void* pointer) | ||
284 | { | ||
285 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
286 | udd_ep_id_t ep = ep_callback_para->endpoint_address; | ||
287 | uint16_t ep_size, nb_trans; | ||
288 | uint16_t next_trans; | ||
289 | udd_ep_id_t ep_num; | ||
290 | udd_ep_job_t *ptr_job; | ||
291 | |||
292 | ptr_job = udd_ep_get_job(ep); | ||
293 | ep_num = ep & USB_EP_ADDR_MASK; | ||
294 | |||
295 | ep_size = ptr_job->ep_size; | ||
296 | /* Update number of data transferred */ | ||
297 | nb_trans = ep_callback_para->received_bytes; | ||
298 | |||
299 | /* Can be necessary to copy data receive from cache buffer to user buffer */ | ||
300 | if (ptr_job->b_use_out_cache_buffer) { | ||
301 | memcpy(&ptr_job->buf[ptr_job->nb_trans], udd_ep_out_cache_buffer[ep_num - 1], ptr_job->buf_size % ep_size); | ||
302 | } | ||
303 | |||
304 | /* Update number of data transferred */ | ||
305 | ptr_job->nb_trans += nb_trans; | ||
306 | if (ptr_job->nb_trans > ptr_job->buf_size) { | ||
307 | ptr_job->nb_trans = ptr_job->buf_size; | ||
308 | } | ||
309 | |||
310 | /* If all previous data requested are received and user buffer not full | ||
311 | * then need to receive other data */ | ||
312 | if ((nb_trans == ep_callback_para->out_buffer_size) && (ptr_job->nb_trans != ptr_job->buf_size)) { | ||
313 | next_trans = ptr_job->buf_size - ptr_job->nb_trans; | ||
314 | if (UDD_ENDPOINT_MAX_TRANS < next_trans) { | ||
315 | /* The USB hardware support a maximum transfer size | ||
316 | * of UDD_ENDPOINT_MAX_TRANS Bytes */ | ||
317 | next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ep_size); | ||
318 | } else { | ||
319 | next_trans -= next_trans % ep_size; | ||
320 | } | ||
321 | |||
322 | if (next_trans < ep_size) { | ||
323 | /* Use the cache buffer for Bulk or Interrupt size endpoint */ | ||
324 | ptr_job->b_use_out_cache_buffer = true; | ||
325 | usb_device_endpoint_read_buffer_job(&usb_device,ep_num,udd_ep_out_cache_buffer[ep_num - 1],ep_size); | ||
326 | } else { | ||
327 | usb_device_endpoint_read_buffer_job(&usb_device,ep_num,&ptr_job->buf[ptr_job->nb_trans],next_trans); | ||
328 | } | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | /* Job complete then call callback */ | ||
333 | ptr_job->busy = false; | ||
334 | if (NULL != ptr_job->call_trans) { | ||
335 | ptr_job->call_trans(UDD_EP_TRANSFER_OK, ptr_job->nb_trans, ep); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * \brief Endpoint Transfer Complete callback function, to do the next transfer depends on the direction(IN or OUT) | ||
341 | * \param[in] module_inst Pointer to USB module instance | ||
342 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
343 | */ | ||
344 | static void udd_ep_transfer_process(struct usb_module *module_inst, void* pointer) | ||
345 | { | ||
346 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
347 | udd_ep_id_t ep = ep_callback_para->endpoint_address; | ||
348 | |||
349 | if (ep & USB_EP_DIR_IN) { | ||
350 | udd_ep_trans_in_next(pointer); | ||
351 | } else { | ||
352 | udd_ep_trans_out_next(pointer); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | void udd_ep_abort(udd_ep_id_t ep) | ||
357 | { | ||
358 | udd_ep_job_t *ptr_job; | ||
359 | |||
360 | usb_device_endpoint_abort_job(&usb_device, ep); | ||
361 | |||
362 | /* Job complete then call callback */ | ||
363 | ptr_job = udd_ep_get_job(ep); | ||
364 | if (!ptr_job->busy) { | ||
365 | return; | ||
366 | } | ||
367 | ptr_job->busy = false; | ||
368 | if (NULL != ptr_job->call_trans) { | ||
369 | /* It can be a Transfer or stall callback */ | ||
370 | ptr_job->call_trans(UDD_EP_TRANSFER_ABORT, ptr_job->nb_trans, ep); | ||
371 | } | ||
372 | } | ||
373 | |||
374 | bool udd_is_high_speed(void) | ||
375 | { | ||
376 | return false; | ||
377 | } | ||
378 | |||
379 | uint16_t udd_get_frame_number(void) | ||
380 | { | ||
381 | return usb_device_get_frame_number(&usb_device); | ||
382 | } | ||
383 | |||
384 | uint16_t udd_get_micro_frame_number(void) | ||
385 | { | ||
386 | return usb_device_get_micro_frame_number(&usb_device); | ||
387 | } | ||
388 | |||
389 | void udd_ep_free(udd_ep_id_t ep) | ||
390 | { | ||
391 | struct usb_device_endpoint_config config_ep; | ||
392 | usb_device_endpoint_get_config_defaults(&config_ep); | ||
393 | |||
394 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
395 | udd_ep_abort(ep); | ||
396 | |||
397 | config_ep.ep_address = ep; | ||
398 | config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_DISABLE; | ||
399 | usb_device_endpoint_set_config(&usb_device, &config_ep); | ||
400 | usb_device_endpoint_unregister_callback(&usb_device,ep_num,USB_DEVICE_ENDPOINT_CALLBACK_TRCPT); | ||
401 | usb_device_endpoint_disable_callback(&usb_device,ep,USB_DEVICE_ENDPOINT_CALLBACK_TRCPT); | ||
402 | } | ||
403 | |||
404 | bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) | ||
405 | { | ||
406 | struct usb_device_endpoint_config config_ep; | ||
407 | usb_device_endpoint_get_config_defaults(&config_ep); | ||
408 | |||
409 | config_ep.ep_address = ep; | ||
410 | |||
411 | if(MaxEndpointSize <= 8) { | ||
412 | config_ep.ep_size = USB_ENDPOINT_8_BYTE; | ||
413 | } else if(MaxEndpointSize <= 16) { | ||
414 | config_ep.ep_size = USB_ENDPOINT_16_BYTE; | ||
415 | } else if(MaxEndpointSize <= 32) { | ||
416 | config_ep.ep_size = USB_ENDPOINT_32_BYTE; | ||
417 | } else if(MaxEndpointSize <= 64) { | ||
418 | config_ep.ep_size = USB_ENDPOINT_64_BYTE; | ||
419 | } else if(MaxEndpointSize <= 128) { | ||
420 | config_ep.ep_size = USB_ENDPOINT_128_BYTE; | ||
421 | } else if(MaxEndpointSize <= 256) { | ||
422 | config_ep.ep_size = USB_ENDPOINT_256_BYTE; | ||
423 | } else if(MaxEndpointSize <= 512) { | ||
424 | config_ep.ep_size = USB_ENDPOINT_512_BYTE; | ||
425 | } else if(MaxEndpointSize <= 1023) { | ||
426 | config_ep.ep_size = USB_ENDPOINT_1023_BYTE; | ||
427 | } else { | ||
428 | return false; | ||
429 | } | ||
430 | udd_ep_job_t *ptr_job = udd_ep_get_job(ep); | ||
431 | ptr_job->ep_size = MaxEndpointSize; | ||
432 | |||
433 | bmAttributes = bmAttributes & USB_EP_TYPE_MASK; | ||
434 | |||
435 | /* Check endpoint type */ | ||
436 | if(USB_EP_TYPE_ISOCHRONOUS == bmAttributes) { | ||
437 | config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_ISOCHRONOUS; | ||
438 | } else if (USB_EP_TYPE_BULK == bmAttributes) { | ||
439 | config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_BULK; | ||
440 | } else if (USB_EP_TYPE_INTERRUPT == bmAttributes) { | ||
441 | config_ep.ep_type = USB_DEVICE_ENDPOINT_TYPE_INTERRUPT; | ||
442 | } else { | ||
443 | return false; | ||
444 | } | ||
445 | |||
446 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
447 | |||
448 | if (STATUS_OK != usb_device_endpoint_set_config(&usb_device, &config_ep)) { | ||
449 | return false; | ||
450 | } | ||
451 | usb_device_endpoint_register_callback(&usb_device,ep_num,USB_DEVICE_ENDPOINT_CALLBACK_TRCPT,udd_ep_transfer_process); | ||
452 | usb_device_endpoint_enable_callback(&usb_device,ep,USB_DEVICE_ENDPOINT_CALLBACK_TRCPT); | ||
453 | usb_device_endpoint_enable_callback(&usb_device,ep,USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL); | ||
454 | |||
455 | return true; | ||
456 | } | ||
457 | |||
458 | bool udd_ep_is_halted(udd_ep_id_t ep) | ||
459 | { | ||
460 | return usb_device_endpoint_is_halted(&usb_device, ep); | ||
461 | } | ||
462 | |||
463 | bool udd_ep_set_halt(udd_ep_id_t ep) | ||
464 | { | ||
465 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
466 | |||
467 | if (USB_DEVICE_MAX_EP < ep_num) { | ||
468 | return false; | ||
469 | } | ||
470 | |||
471 | usb_device_endpoint_set_halt(&usb_device, ep); | ||
472 | |||
473 | udd_ep_abort(ep); | ||
474 | return true; | ||
475 | } | ||
476 | |||
477 | bool udd_ep_clear_halt(udd_ep_id_t ep) | ||
478 | { | ||
479 | udd_ep_job_t *ptr_job; | ||
480 | uint8_t ep_num = ep & USB_EP_ADDR_MASK; | ||
481 | |||
482 | if (USB_DEVICE_MAX_EP < ep_num) { | ||
483 | return false; | ||
484 | } | ||
485 | ptr_job = udd_ep_get_job(ep); | ||
486 | |||
487 | usb_device_endpoint_clear_halt(&usb_device, ep); | ||
488 | |||
489 | /* If a job is register on clear halt action then execute callback */ | ||
490 | if (ptr_job->busy == true) { | ||
491 | ptr_job->busy = false; | ||
492 | ptr_job->call_nohalt(); | ||
493 | } | ||
494 | |||
495 | return true; | ||
496 | } | ||
497 | |||
498 | bool udd_ep_wait_stall_clear(udd_ep_id_t ep, udd_callback_halt_cleared_t callback) | ||
499 | { | ||
500 | udd_ep_id_t ep_num; | ||
501 | udd_ep_job_t *ptr_job; | ||
502 | |||
503 | ep_num = ep & USB_EP_ADDR_MASK; | ||
504 | if (USB_DEVICE_MAX_EP < ep_num) { | ||
505 | return false; | ||
506 | } | ||
507 | |||
508 | ptr_job = udd_ep_get_job(ep); | ||
509 | if (ptr_job->busy == true) { | ||
510 | return false; /* Job already on going */ | ||
511 | } | ||
512 | |||
513 | /* Wait clear halt endpoint */ | ||
514 | if (usb_device_endpoint_is_halted(&usb_device, ep)) { | ||
515 | /* Endpoint halted then registers the callback */ | ||
516 | ptr_job->busy = true; | ||
517 | ptr_job->call_nohalt = callback; | ||
518 | return true; | ||
519 | } else if (usb_device_endpoint_is_configured(&usb_device, ep)) { | ||
520 | callback(); /* Endpoint not halted then call directly callback */ | ||
521 | return true; | ||
522 | } else { | ||
523 | return false; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | /** | ||
528 | * \brief Control Endpoint stall sending data | ||
529 | */ | ||
530 | static void udd_ctrl_stall_data(void) | ||
531 | { | ||
532 | udd_ep_control_state = UDD_EPCTRL_STALL_REQ; | ||
533 | |||
534 | usb_device_endpoint_set_halt(&usb_device, USB_EP_DIR_IN); | ||
535 | usb_device_endpoint_clear_halt(&usb_device, USB_EP_DIR_OUT); | ||
536 | } | ||
537 | |||
538 | bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t *buf, iram_size_t buf_size, udd_callback_trans_t callback) | ||
539 | { | ||
540 | udd_ep_id_t ep_num; | ||
541 | udd_ep_job_t *ptr_job; | ||
542 | uint32_t irqflags; | ||
543 | |||
544 | ep_num = ep & USB_EP_ADDR_MASK; | ||
545 | |||
546 | if ((USB_DEVICE_MAX_EP < ep_num) || (udd_ep_is_halted(ep))) { | ||
547 | return false; | ||
548 | } | ||
549 | |||
550 | ptr_job = udd_ep_get_job(ep); | ||
551 | |||
552 | irqflags = __get_PRIMASK(); | ||
553 | __disable_irq(); | ||
554 | __DMB(); | ||
555 | |||
556 | if (ptr_job->busy == true) { | ||
557 | __DMB(); | ||
558 | __set_PRIMASK(irqflags); | ||
559 | return false; /* Job already on going */ | ||
560 | } | ||
561 | |||
562 | ptr_job->busy = true; | ||
563 | __DMB(); | ||
564 | __set_PRIMASK(irqflags); | ||
565 | |||
566 | /* No job running, set up a new one */ | ||
567 | ptr_job->buf = buf; | ||
568 | ptr_job->buf_size = buf_size; | ||
569 | ptr_job->nb_trans = 0; | ||
570 | ptr_job->call_trans = callback; | ||
571 | ptr_job->b_shortpacket = b_shortpacket; | ||
572 | ptr_job->b_use_out_cache_buffer = false; | ||
573 | |||
574 | /* Initialize value to simulate a empty transfer */ | ||
575 | uint16_t next_trans; | ||
576 | |||
577 | if (ep & USB_EP_DIR_IN) { | ||
578 | if (0 != ptr_job->buf_size) { | ||
579 | next_trans = ptr_job->buf_size; | ||
580 | if (UDD_ENDPOINT_MAX_TRANS < next_trans) { | ||
581 | next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ptr_job->ep_size); | ||
582 | } | ||
583 | ptr_job->b_shortpacket = ptr_job->b_shortpacket && (0 == (next_trans % ptr_job->ep_size)); | ||
584 | } else if (true == ptr_job->b_shortpacket) { | ||
585 | ptr_job->b_shortpacket = false; /* avoid to send zero length packet again */ | ||
586 | next_trans = 0; | ||
587 | } else { | ||
588 | ptr_job->busy = false; | ||
589 | if (NULL != ptr_job->call_trans) { | ||
590 | ptr_job->call_trans(UDD_EP_TRANSFER_OK, 0, ep); | ||
591 | } | ||
592 | return true; | ||
593 | } | ||
594 | return (STATUS_OK == | ||
595 | usb_device_endpoint_write_buffer_job(&usb_device, | ||
596 | ep_num,&ptr_job->buf[0],next_trans)); | ||
597 | } else { | ||
598 | if (0 != ptr_job->buf_size) { | ||
599 | next_trans = ptr_job->buf_size; | ||
600 | if (UDD_ENDPOINT_MAX_TRANS < next_trans) { | ||
601 | /* The USB hardware support a maximum transfer size | ||
602 | * of UDD_ENDPOINT_MAX_TRANS Bytes */ | ||
603 | next_trans = UDD_ENDPOINT_MAX_TRANS - | ||
604 | (UDD_ENDPOINT_MAX_TRANS % ptr_job->ep_size); | ||
605 | } else { | ||
606 | next_trans -= next_trans % ptr_job->ep_size; | ||
607 | } | ||
608 | if (next_trans < ptr_job->ep_size) { | ||
609 | ptr_job->b_use_out_cache_buffer = true; | ||
610 | return (STATUS_OK == | ||
611 | usb_device_endpoint_read_buffer_job(&usb_device, ep_num, | ||
612 | udd_ep_out_cache_buffer[ep_num - 1], | ||
613 | ptr_job->ep_size)); | ||
614 | } else { | ||
615 | return (STATUS_OK == | ||
616 | usb_device_endpoint_read_buffer_job(&usb_device, ep_num, | ||
617 | &ptr_job->buf[0],next_trans)); | ||
618 | } | ||
619 | } else { | ||
620 | ptr_job->busy = false; | ||
621 | if (NULL != ptr_job->call_trans) { | ||
622 | ptr_job->call_trans(UDD_EP_TRANSFER_OK, 0, ep); | ||
623 | } | ||
624 | return true; | ||
625 | } | ||
626 | } | ||
627 | } | ||
628 | |||
629 | void udd_set_address(uint8_t address) | ||
630 | { | ||
631 | usb_device_set_address(&usb_device,address); | ||
632 | } | ||
633 | |||
634 | uint8_t udd_getaddress(void) | ||
635 | { | ||
636 | return usb_device_get_address(&usb_device); | ||
637 | } | ||
638 | |||
639 | void udd_send_remotewakeup(void) | ||
640 | { | ||
641 | uint32_t try = 5; | ||
642 | udd_wait_clock_ready(); | ||
643 | udd_sleep_mode(UDD_STATE_IDLE); | ||
644 | while(2 != usb_get_state_machine_status(&usb_device) && try --) { | ||
645 | usb_device_send_remote_wake_up(&usb_device); | ||
646 | } | ||
647 | } | ||
648 | |||
649 | void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size ) | ||
650 | { | ||
651 | udd_g_ctrlreq.payload = payload; | ||
652 | udd_g_ctrlreq.payload_size = payload_size; | ||
653 | } | ||
654 | |||
655 | /** | ||
656 | * \brief Control Endpoint translate the data in buffer into Device Request Struct | ||
657 | */ | ||
658 | static void udd_ctrl_fetch_ram(void) | ||
659 | { | ||
660 | udd_g_ctrlreq.req.bmRequestType = udd_ctrl_buffer[0]; | ||
661 | udd_g_ctrlreq.req.bRequest = udd_ctrl_buffer[1]; | ||
662 | udd_g_ctrlreq.req.wValue = ((uint16_t)(udd_ctrl_buffer[3]) << 8) + udd_ctrl_buffer[2]; | ||
663 | udd_g_ctrlreq.req.wIndex = ((uint16_t)(udd_ctrl_buffer[5]) << 8) + udd_ctrl_buffer[4]; | ||
664 | udd_g_ctrlreq.req.wLength = ((uint16_t)(udd_ctrl_buffer[7]) << 8) + udd_ctrl_buffer[6]; | ||
665 | } | ||
666 | |||
667 | /** | ||
668 | * \brief Control Endpoint send out zero length packet | ||
669 | */ | ||
670 | static void udd_ctrl_send_zlp_in(void) | ||
671 | { | ||
672 | udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP; | ||
673 | usb_device_endpoint_setup_buffer_job(&usb_device,udd_ctrl_buffer); | ||
674 | usb_device_endpoint_write_buffer_job(&usb_device,0,udd_g_ctrlreq.payload,0); | ||
675 | } | ||
676 | |||
677 | /** | ||
678 | * \brief Process control endpoint IN transaction | ||
679 | */ | ||
680 | static void udd_ctrl_in_sent(void) | ||
681 | { | ||
682 | static bool b_shortpacket = false; | ||
683 | uint16_t nb_remain; | ||
684 | |||
685 | nb_remain = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans; | ||
686 | |||
687 | if (0 == nb_remain) { | ||
688 | /* All content of current buffer payload are sent Update number of total data sending by previous payload buffer */ | ||
689 | udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; | ||
690 | if ((udd_g_ctrlreq.req.wLength == udd_ctrl_prev_payload_nb_trans) || b_shortpacket) { | ||
691 | /* All data requested are transferred or a short packet has been sent, then it is the end of data phase. | ||
692 | * Generate an OUT ZLP for handshake phase */ | ||
693 | udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP; | ||
694 | usb_device_endpoint_setup_buffer_job(&usb_device,udd_ctrl_buffer); | ||
695 | return; | ||
696 | } | ||
697 | /* Need of new buffer because the data phase is not complete */ | ||
698 | if ((!udd_g_ctrlreq.over_under_run) || (!udd_g_ctrlreq.over_under_run())) { | ||
699 | /* Under run then send zlp on IN | ||
700 | * Here nb_remain=0, this allows to send a IN ZLP */ | ||
701 | } else { | ||
702 | /* A new payload buffer is given */ | ||
703 | udd_ctrl_payload_nb_trans = 0; | ||
704 | nb_remain = udd_g_ctrlreq.payload_size; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | /* Continue transfer and send next data */ | ||
709 | if (nb_remain >= USB_DEVICE_EP_CTRL_SIZE) { | ||
710 | nb_remain = USB_DEVICE_EP_CTRL_SIZE; | ||
711 | b_shortpacket = false; | ||
712 | } else { | ||
713 | b_shortpacket = true; | ||
714 | } | ||
715 | |||
716 | /* Link payload buffer directly on USB hardware */ | ||
717 | usb_device_endpoint_write_buffer_job(&usb_device,0,udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans,nb_remain); | ||
718 | |||
719 | udd_ctrl_payload_nb_trans += nb_remain; | ||
720 | } | ||
721 | |||
722 | /** | ||
723 | * \brief Process control endpoint OUT transaction | ||
724 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
725 | */ | ||
726 | static void udd_ctrl_out_received(void* pointer) | ||
727 | { | ||
728 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
729 | |||
730 | uint16_t nb_data; | ||
731 | nb_data = ep_callback_para->received_bytes; /* Read data received during OUT phase */ | ||
732 | |||
733 | if (udd_g_ctrlreq.payload_size < (udd_ctrl_payload_nb_trans + nb_data)) { | ||
734 | /* Payload buffer too small */ | ||
735 | nb_data = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans; | ||
736 | } | ||
737 | |||
738 | memcpy((uint8_t *) (udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans), udd_ctrl_buffer, nb_data); | ||
739 | udd_ctrl_payload_nb_trans += nb_data; | ||
740 | |||
741 | if ((USB_DEVICE_EP_CTRL_SIZE != nb_data) || \ | ||
742 | (udd_g_ctrlreq.req.wLength <= (udd_ctrl_prev_payload_nb_trans + udd_ctrl_payload_nb_trans))) { | ||
743 | /* End of reception because it is a short packet | ||
744 | * or all data are transferred */ | ||
745 | |||
746 | /* Before send ZLP, call intermediate callback | ||
747 | * in case of data receive generate a stall */ | ||
748 | udd_g_ctrlreq.payload_size = udd_ctrl_payload_nb_trans; | ||
749 | if (NULL != udd_g_ctrlreq.over_under_run) { | ||
750 | if (!udd_g_ctrlreq.over_under_run()) { | ||
751 | /* Stall ZLP */ | ||
752 | udd_ep_control_state = UDD_EPCTRL_STALL_REQ; | ||
753 | /* Stall all packets on IN & OUT control endpoint */ | ||
754 | udd_ep_set_halt(0); | ||
755 | /* Ack reception of OUT to replace NAK by a STALL */ | ||
756 | return; | ||
757 | } | ||
758 | } | ||
759 | /* Send IN ZLP to ACK setup request */ | ||
760 | udd_ctrl_send_zlp_in(); | ||
761 | return; | ||
762 | } | ||
763 | |||
764 | if (udd_g_ctrlreq.payload_size == udd_ctrl_payload_nb_trans) { | ||
765 | /* Overrun then request a new payload buffer */ | ||
766 | if (!udd_g_ctrlreq.over_under_run) { | ||
767 | /* No callback available to request a new payload buffer | ||
768 | * Stall ZLP */ | ||
769 | udd_ep_control_state = UDD_EPCTRL_STALL_REQ; | ||
770 | /* Stall all packets on IN & OUT control endpoint */ | ||
771 | udd_ep_set_halt(0); | ||
772 | return; | ||
773 | } | ||
774 | if (!udd_g_ctrlreq.over_under_run()) { | ||
775 | /* No new payload buffer delivered | ||
776 | * Stall ZLP */ | ||
777 | udd_ep_control_state = UDD_EPCTRL_STALL_REQ; | ||
778 | /* Stall all packets on IN & OUT control endpoint */ | ||
779 | udd_ep_set_halt(0); | ||
780 | return; | ||
781 | } | ||
782 | /* New payload buffer available | ||
783 | * Update number of total data received */ | ||
784 | udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; | ||
785 | |||
786 | /* Reinitialize reception on payload buffer */ | ||
787 | udd_ctrl_payload_nb_trans = 0; | ||
788 | } | ||
789 | usb_device_endpoint_read_buffer_job(&usb_device,0,udd_ctrl_buffer,USB_DEVICE_EP_CTRL_SIZE); | ||
790 | } | ||
791 | |||
792 | /** | ||
793 | * \internal | ||
794 | * \brief Endpoint 0 (control) SETUP received callback | ||
795 | * \param[in] module_inst pointer to USB module instance | ||
796 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
797 | */ | ||
798 | static void _usb_ep0_on_setup(struct usb_module *module_inst, void* pointer) | ||
799 | { | ||
800 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
801 | |||
802 | if (UDD_EPCTRL_SETUP != udd_ep_control_state) { | ||
803 | if (NULL != udd_g_ctrlreq.callback) { | ||
804 | udd_g_ctrlreq.callback(); | ||
805 | } | ||
806 | udd_ep_control_state = UDD_EPCTRL_SETUP; | ||
807 | } | ||
808 | if ( 8 != ep_callback_para->received_bytes) { | ||
809 | udd_ctrl_stall_data(); | ||
810 | return; | ||
811 | } else { | ||
812 | udd_ctrl_fetch_ram(); | ||
813 | if (false == udc_process_setup()) { | ||
814 | udd_ctrl_stall_data(); | ||
815 | return; | ||
816 | } else if (Udd_setup_is_in()) { | ||
817 | udd_ctrl_prev_payload_nb_trans = 0; | ||
818 | udd_ctrl_payload_nb_trans = 0; | ||
819 | udd_ep_control_state = UDD_EPCTRL_DATA_IN; | ||
820 | usb_device_endpoint_read_buffer_job(&usb_device,0,udd_ctrl_buffer,USB_DEVICE_EP_CTRL_SIZE); | ||
821 | udd_ctrl_in_sent(); | ||
822 | } else { | ||
823 | if(0 == udd_g_ctrlreq.req.wLength) { | ||
824 | udd_ctrl_send_zlp_in(); | ||
825 | return; | ||
826 | } else { | ||
827 | udd_ctrl_prev_payload_nb_trans = 0; | ||
828 | udd_ctrl_payload_nb_trans = 0; | ||
829 | udd_ep_control_state = UDD_EPCTRL_DATA_OUT; | ||
830 | /* Initialize buffer size and enable OUT bank */ | ||
831 | usb_device_endpoint_read_buffer_job(&usb_device,0,udd_ctrl_buffer,USB_DEVICE_EP_CTRL_SIZE); | ||
832 | } | ||
833 | } | ||
834 | } | ||
835 | } | ||
836 | |||
837 | /** | ||
838 | * \brief Control Endpoint Process when underflow condition has occurred | ||
839 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
840 | */ | ||
841 | static void udd_ctrl_underflow(void* pointer) | ||
842 | { | ||
843 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
844 | |||
845 | if (UDD_EPCTRL_DATA_OUT == udd_ep_control_state) { | ||
846 | /* Host want to stop OUT transaction | ||
847 | * then stop to wait OUT data phase and wait IN ZLP handshake */ | ||
848 | udd_ctrl_send_zlp_in(); | ||
849 | } else if (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state) { | ||
850 | /* A OUT handshake is waiting by device, | ||
851 | * but host want extra IN data then stall extra IN data */ | ||
852 | usb_device_endpoint_set_halt(&usb_device, ep_callback_para->endpoint_address); | ||
853 | } | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * \brief Control Endpoint Process when overflow condition has occurred | ||
858 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
859 | */ | ||
860 | static void udd_ctrl_overflow(void* pointer) | ||
861 | { | ||
862 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
863 | |||
864 | if (UDD_EPCTRL_DATA_IN == udd_ep_control_state) { | ||
865 | /* Host want to stop IN transaction | ||
866 | * then stop to wait IN data phase and wait OUT ZLP handshake */ | ||
867 | udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP; | ||
868 | } else if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { | ||
869 | /* A IN handshake is waiting by device, | ||
870 | * but host want extra OUT data then stall extra OUT data and following status stage */ | ||
871 | usb_device_endpoint_set_halt(&usb_device, ep_callback_para->endpoint_address); | ||
872 | } | ||
873 | } | ||
874 | |||
875 | /** | ||
876 | * \internal | ||
877 | * \brief Control endpoint transfer fail callback function | ||
878 | * \param[in] module_inst Pointer to USB module instance | ||
879 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
880 | */ | ||
881 | static void _usb_ep0_on_tansfer_fail(struct usb_module *module_inst, void* pointer) | ||
882 | { | ||
883 | struct usb_endpoint_callback_parameter *ep_callback_para = (struct usb_endpoint_callback_parameter*)pointer; | ||
884 | |||
885 | if(ep_callback_para->endpoint_address & USB_EP_DIR_IN) { | ||
886 | udd_ctrl_underflow(pointer); | ||
887 | } else { | ||
888 | udd_ctrl_overflow(pointer); | ||
889 | } | ||
890 | } | ||
891 | |||
892 | /** | ||
893 | * \internal | ||
894 | * \brief Control endpoint transfer complete callback function | ||
895 | * \param[in] module_inst Pointer to USB module instance | ||
896 | * \param[in] pointer Pointer to the endpoint transfer status parameter struct from driver layer. | ||
897 | */ | ||
898 | static void _usb_ep0_on_tansfer_ok(struct usb_module *module_inst, void *pointer) | ||
899 | { | ||
900 | if (UDD_EPCTRL_DATA_OUT == udd_ep_control_state) { /* handshake Out for status stage */ | ||
901 | udd_ctrl_out_received(pointer); | ||
902 | } else if (UDD_EPCTRL_DATA_IN == udd_ep_control_state) { /* handshake In for status stage */ | ||
903 | udd_ctrl_in_sent(); | ||
904 | } else { | ||
905 | if (NULL != udd_g_ctrlreq.callback) { | ||
906 | udd_g_ctrlreq.callback(); | ||
907 | } | ||
908 | udd_ep_control_state = UDD_EPCTRL_SETUP; | ||
909 | } | ||
910 | } | ||
911 | |||
912 | /** | ||
913 | * \brief Enable Control Endpoint | ||
914 | * \param[in] module_inst Pointer to USB module instance | ||
915 | */ | ||
916 | static void udd_ctrl_ep_enable(struct usb_module *module_inst) | ||
917 | { | ||
918 | /* USB Device Endpoint0 Configuration */ | ||
919 | struct usb_device_endpoint_config config_ep0; | ||
920 | |||
921 | usb_device_endpoint_get_config_defaults(&config_ep0); | ||
922 | config_ep0.ep_size = (enum usb_endpoint_size)(32 - clz(((uint32_t)Min(Max(USB_DEVICE_EP_CTRL_SIZE, 8), 1024) << 1) - 1) - 1 - 3); | ||
923 | usb_device_endpoint_set_config(module_inst,&config_ep0); | ||
924 | |||
925 | usb_device_endpoint_setup_buffer_job(module_inst,udd_ctrl_buffer); | ||
926 | |||
927 | usb_device_endpoint_register_callback(module_inst,0,USB_DEVICE_ENDPOINT_CALLBACK_RXSTP, _usb_ep0_on_setup ); | ||
928 | usb_device_endpoint_register_callback(module_inst,0,USB_DEVICE_ENDPOINT_CALLBACK_TRCPT,_usb_ep0_on_tansfer_ok ); | ||
929 | usb_device_endpoint_register_callback(module_inst,0,USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL,_usb_ep0_on_tansfer_fail ); | ||
930 | usb_device_endpoint_enable_callback(module_inst,0,USB_DEVICE_ENDPOINT_CALLBACK_RXSTP); | ||
931 | usb_device_endpoint_enable_callback(module_inst,0,USB_DEVICE_ENDPOINT_CALLBACK_TRCPT); | ||
932 | usb_device_endpoint_enable_callback(module_inst,0,USB_DEVICE_ENDPOINT_CALLBACK_TRFAIL); | ||
933 | |||
934 | #ifdef USB_DEVICE_LPM_SUPPORT | ||
935 | // Enable LPM feature | ||
936 | usb_device_set_lpm_mode(module_inst, USB_DEVICE_LPM_ACK); | ||
937 | #endif | ||
938 | |||
939 | udd_ep_control_state = UDD_EPCTRL_SETUP; | ||
940 | } | ||
941 | |||
942 | /** | ||
943 | * \internal | ||
944 | * \brief Control endpoint Suspend callback function | ||
945 | * \param[in] module_inst Pointer to USB module instance | ||
946 | * \param[in] pointer Pointer to the callback parameter from driver layer. | ||
947 | */ | ||
948 | static void _usb_on_suspend(struct usb_module *module_inst, void *pointer) | ||
949 | { | ||
950 | usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND); | ||
951 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP); | ||
952 | udd_sleep_mode(UDD_STATE_SUSPEND); | ||
953 | #ifdef UDC_SUSPEND_EVENT | ||
954 | UDC_SUSPEND_EVENT(); | ||
955 | #endif | ||
956 | } | ||
957 | |||
958 | #ifdef USB_DEVICE_LPM_SUPPORT | ||
959 | static void _usb_device_lpm_suspend(struct usb_module *module_inst, void *pointer) | ||
960 | { | ||
961 | dbg_print("LPM_SUSP\n"); | ||
962 | |||
963 | uint32_t *lpm_wakeup_enable; | ||
964 | lpm_wakeup_enable = (uint32_t *)pointer; | ||
965 | |||
966 | usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP); | ||
967 | usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND); | ||
968 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP); | ||
969 | |||
970 | //#warning Here the sleep mode must be choose to have a DFLL startup time < bmAttribut.HIRD | ||
971 | udd_sleep_mode(UDD_STATE_SUSPEND_LPM); // Enter in LPM SUSPEND mode | ||
972 | if ((*lpm_wakeup_enable)) { | ||
973 | UDC_REMOTEWAKEUP_LPM_ENABLE(); | ||
974 | } | ||
975 | if (!(*lpm_wakeup_enable)) { | ||
976 | UDC_REMOTEWAKEUP_LPM_DISABLE(); | ||
977 | } | ||
978 | UDC_SUSPEND_LPM_EVENT(); | ||
979 | } | ||
980 | #endif | ||
981 | |||
982 | /** | ||
983 | * \internal | ||
984 | * \brief Control endpoint SOF callback function | ||
985 | * \param[in] module_inst Pointer to USB module instance | ||
986 | * \param[in] pointer Pointer to the callback parameter from driver layer. | ||
987 | */ | ||
988 | static void _usb_on_sof_notify(struct usb_module *module_inst, void *pointer) | ||
989 | { | ||
990 | udc_sof_notify(); | ||
991 | #ifdef UDC_SOF_EVENT | ||
992 | UDC_SOF_EVENT(); | ||
993 | #endif | ||
994 | } | ||
995 | |||
996 | /** | ||
997 | * \internal | ||
998 | * \brief Control endpoint Reset callback function | ||
999 | * \param[in] module_inst Pointer to USB module instance | ||
1000 | * \param[in] pointer Pointer to the callback parameter from driver layer. | ||
1001 | */ | ||
1002 | static void _usb_on_bus_reset(struct usb_module *module_inst, void *pointer) | ||
1003 | { | ||
1004 | // Reset USB Device Stack Core | ||
1005 | udc_reset(); | ||
1006 | usb_device_set_address(module_inst,0); | ||
1007 | udd_ctrl_ep_enable(module_inst); | ||
1008 | } | ||
1009 | |||
1010 | /** | ||
1011 | * \internal | ||
1012 | * \brief Control endpoint Wakeup callback function | ||
1013 | * \param[in] module_inst Pointer to USB module instance | ||
1014 | * \param[in] pointer Pointer to the callback parameter from driver layer. | ||
1015 | */ | ||
1016 | static void _usb_on_wakeup(struct usb_module *module_inst, void *pointer) | ||
1017 | { | ||
1018 | udd_wait_clock_ready(); | ||
1019 | |||
1020 | usb_device_disable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP); | ||
1021 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND); | ||
1022 | #ifdef USB_DEVICE_LPM_SUPPORT | ||
1023 | usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP, _usb_device_lpm_suspend); | ||
1024 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP); | ||
1025 | #endif | ||
1026 | udd_sleep_mode(UDD_STATE_IDLE); | ||
1027 | #ifdef UDC_RESUME_EVENT | ||
1028 | UDC_RESUME_EVENT(); | ||
1029 | #endif | ||
1030 | } | ||
1031 | |||
1032 | void udd_detach(void) | ||
1033 | { | ||
1034 | usb_device_detach(&usb_device); | ||
1035 | udd_sleep_mode(UDD_STATE_SUSPEND); | ||
1036 | } | ||
1037 | |||
1038 | void udd_attach(void) | ||
1039 | { | ||
1040 | udd_sleep_mode(UDD_STATE_IDLE); | ||
1041 | usb_device_attach(&usb_device); | ||
1042 | |||
1043 | usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND, _usb_on_suspend); | ||
1044 | usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_SOF, _usb_on_sof_notify); | ||
1045 | usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_RESET, _usb_on_bus_reset); | ||
1046 | usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP, _usb_on_wakeup); | ||
1047 | |||
1048 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_SUSPEND); | ||
1049 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_SOF); | ||
1050 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_RESET); | ||
1051 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_WAKEUP); | ||
1052 | #ifdef USB_DEVICE_LPM_SUPPORT | ||
1053 | usb_device_register_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP, _usb_device_lpm_suspend); | ||
1054 | usb_device_enable_callback(&usb_device, USB_DEVICE_CALLBACK_LPMSUSP); | ||
1055 | #endif | ||
1056 | } | ||
1057 | |||
1058 | void udd_enable(void) | ||
1059 | { | ||
1060 | uint32_t irqflags; | ||
1061 | |||
1062 | /* To avoid USB interrupt before end of initialization */ | ||
1063 | irqflags = __get_PRIMASK(); | ||
1064 | __disable_irq(); | ||
1065 | __DMB(); | ||
1066 | |||
1067 | struct usb_config config_usb; | ||
1068 | |||
1069 | /* USB Module configuration */ | ||
1070 | usb_get_config_defaults(&config_usb); | ||
1071 | config_usb.source_generator = UDD_CLOCK_GEN; | ||
1072 | usb_init(&usb_device, USB, &config_usb); | ||
1073 | |||
1074 | /* USB Module Enable */ | ||
1075 | usb_enable(&usb_device); | ||
1076 | |||
1077 | /* Check clock after enable module, request the clock */ | ||
1078 | udd_wait_clock_ready(); | ||
1079 | |||
1080 | udd_sleep_mode(UDD_STATE_SUSPEND); | ||
1081 | |||
1082 | // No VBus detect, assume always high | ||
1083 | #ifndef USB_DEVICE_ATTACH_AUTO_DISABLE | ||
1084 | udd_attach(); | ||
1085 | #endif | ||
1086 | |||
1087 | __DMB(); | ||
1088 | __set_PRIMASK(irqflags); | ||
1089 | } | ||
1090 | |||
1091 | void udd_disable(void) | ||
1092 | { | ||
1093 | udd_detach(); | ||
1094 | |||
1095 | udd_sleep_mode(UDD_STATE_OFF); | ||
1096 | } | ||
1097 | /** @} */ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_main.h b/tmk_core/protocol/arm_atsam/usb/usb_main.h new file mode 100644 index 000000000..b7adaa1a7 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_main.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief Declaration of main function used by HID keyboard example | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _MAIN_H_ | ||
48 | #define _MAIN_H_ | ||
49 | |||
50 | //Enters the application in low power mode | ||
51 | //Callback called when USB host sets USB line in suspend state | ||
52 | void main_suspend_action(void); | ||
53 | |||
54 | //Called by UDD when the USB line exit of suspend state | ||
55 | void main_resume_action(void); | ||
56 | |||
57 | //Called when a start of frame is received on USB line | ||
58 | void main_sof_action(void); | ||
59 | |||
60 | //Called by UDC when USB Host request to enable remote wakeup | ||
61 | void main_remotewakeup_enable(void); | ||
62 | |||
63 | //Called by UDC when USB Host request to disable remote wakeup | ||
64 | void main_remotewakeup_disable(void); | ||
65 | |||
66 | |||
67 | #ifdef KBD | ||
68 | extern volatile bool main_b_kbd_enable; | ||
69 | bool main_kbd_enable(void); | ||
70 | void main_kbd_disable(void); | ||
71 | #endif //KBD | ||
72 | |||
73 | #ifdef NKRO | ||
74 | extern volatile bool main_b_nkro_enable; | ||
75 | bool main_nkro_enable(void); | ||
76 | void main_nkro_disable(void); | ||
77 | #endif //NKRO | ||
78 | |||
79 | #ifdef EXK | ||
80 | extern volatile bool main_b_exk_enable; | ||
81 | bool main_exk_enable(void); | ||
82 | void main_exk_disable(void); | ||
83 | #endif //EXK | ||
84 | |||
85 | #ifdef MOU | ||
86 | extern volatile bool main_b_mou_enable; | ||
87 | bool main_mou_enable(void); | ||
88 | void main_mou_disable(void); | ||
89 | #endif //MOU | ||
90 | |||
91 | #ifdef RAW | ||
92 | extern volatile bool main_b_raw_enable; | ||
93 | bool main_raw_enable(void); | ||
94 | void main_raw_disable(void); | ||
95 | #endif //RAW | ||
96 | |||
97 | #endif // _MAIN_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_protocol.h b/tmk_core/protocol/arm_atsam/usb/usb_protocol.h new file mode 100644 index 000000000..892a7d3a5 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_protocol.h | |||
@@ -0,0 +1,498 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB protocol definitions. | ||
5 | * | ||
6 | * This file contains the USB definitions and data structures provided by the | ||
7 | * USB 2.0 specification. | ||
8 | * | ||
9 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
10 | * | ||
11 | * \asf_license_start | ||
12 | * | ||
13 | * \page License | ||
14 | * | ||
15 | * Redistribution and use in source and binary forms, with or without | ||
16 | * modification, are permitted provided that the following conditions are met: | ||
17 | * | ||
18 | * 1. Redistributions of source code must retain the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer. | ||
20 | * | ||
21 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
22 | * this list of conditions and the following disclaimer in the documentation | ||
23 | * and/or other materials provided with the distribution. | ||
24 | * | ||
25 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
26 | * from this software without specific prior written permission. | ||
27 | * | ||
28 | * 4. This software may only be redistributed and used in connection with an | ||
29 | * Atmel microcontroller product. | ||
30 | * | ||
31 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
32 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
33 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
34 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
35 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
40 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGE. | ||
42 | * | ||
43 | * \asf_license_stop | ||
44 | * | ||
45 | */ | ||
46 | /* | ||
47 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
48 | */ | ||
49 | |||
50 | #ifndef _USB_PROTOCOL_H_ | ||
51 | #define _USB_PROTOCOL_H_ | ||
52 | |||
53 | #include "usb_atmel.h" | ||
54 | |||
55 | /** | ||
56 | * \ingroup usb_group | ||
57 | * \defgroup usb_protocol_group USB Protocol Definitions | ||
58 | * | ||
59 | * This module defines constants and data structures provided by the USB | ||
60 | * 2.0 specification. | ||
61 | * | ||
62 | * @{ | ||
63 | */ | ||
64 | |||
65 | //! Value for field bcdUSB | ||
66 | #define USB_V2_0 0x0200 //!< USB Specification version 2.00 | ||
67 | #define USB_V2_1 0x0201 //!< USB Specification version 2.01 | ||
68 | |||
69 | /*! \name Generic definitions (Class, subclass and protocol) | ||
70 | */ | ||
71 | //! @{ | ||
72 | #define NO_CLASS 0x00 | ||
73 | #define CLASS_VENDOR_SPECIFIC 0xFF | ||
74 | #define NO_SUBCLASS 0x00 | ||
75 | #define NO_PROTOCOL 0x00 | ||
76 | //! @} | ||
77 | |||
78 | //! \name IAD (Interface Association Descriptor) constants | ||
79 | //! @{ | ||
80 | #define CLASS_IAD 0xEF | ||
81 | #define SUB_CLASS_IAD 0x02 | ||
82 | #define PROTOCOL_IAD 0x01 | ||
83 | //! @} | ||
84 | |||
85 | /** | ||
86 | * \brief USB request data transfer direction (bmRequestType) | ||
87 | */ | ||
88 | #define USB_REQ_DIR_OUT (0<<7) //!< Host to device | ||
89 | #define USB_REQ_DIR_IN (1<<7) //!< Device to host | ||
90 | #define USB_REQ_DIR_MASK (1<<7) //!< Mask | ||
91 | |||
92 | /** | ||
93 | * \brief USB request types (bmRequestType) | ||
94 | */ | ||
95 | #define USB_REQ_TYPE_STANDARD (0<<5) //!< Standard request | ||
96 | #define USB_REQ_TYPE_CLASS (1<<5) //!< Class-specific request | ||
97 | #define USB_REQ_TYPE_VENDOR (2<<5) //!< Vendor-specific request | ||
98 | #define USB_REQ_TYPE_MASK (3<<5) //!< Mask | ||
99 | |||
100 | /** | ||
101 | * \brief USB recipient codes (bmRequestType) | ||
102 | */ | ||
103 | #define USB_REQ_RECIP_DEVICE (0<<0) //!< Recipient device | ||
104 | #define USB_REQ_RECIP_INTERFACE (1<<0) //!< Recipient interface | ||
105 | #define USB_REQ_RECIP_ENDPOINT (2<<0) //!< Recipient endpoint | ||
106 | #define USB_REQ_RECIP_OTHER (3<<0) //!< Recipient other | ||
107 | #define USB_REQ_RECIP_MASK (0x1F) //!< Mask | ||
108 | |||
109 | /** | ||
110 | * \brief Standard USB requests (bRequest) | ||
111 | */ | ||
112 | enum usb_reqid { | ||
113 | USB_REQ_GET_STATUS = 0, | ||
114 | USB_REQ_CLEAR_FEATURE = 1, | ||
115 | USB_REQ_SET_FEATURE = 3, | ||
116 | USB_REQ_SET_ADDRESS = 5, | ||
117 | USB_REQ_GET_DESCRIPTOR = 6, | ||
118 | USB_REQ_SET_DESCRIPTOR = 7, | ||
119 | USB_REQ_GET_CONFIGURATION = 8, | ||
120 | USB_REQ_SET_CONFIGURATION = 9, | ||
121 | USB_REQ_GET_INTERFACE = 10, | ||
122 | USB_REQ_SET_INTERFACE = 11, | ||
123 | USB_REQ_SYNCH_FRAME = 12, | ||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * \brief Standard USB device status flags | ||
128 | * | ||
129 | */ | ||
130 | enum usb_device_status { | ||
131 | USB_DEV_STATUS_BUS_POWERED = 0, | ||
132 | USB_DEV_STATUS_SELF_POWERED = 1, | ||
133 | USB_DEV_STATUS_REMOTEWAKEUP = 2 | ||
134 | }; | ||
135 | |||
136 | /** | ||
137 | * \brief Standard USB Interface status flags | ||
138 | * | ||
139 | */ | ||
140 | enum usb_interface_status { | ||
141 | USB_IFACE_STATUS_RESERVED = 0 | ||
142 | }; | ||
143 | |||
144 | /** | ||
145 | * \brief Standard USB endpoint status flags | ||
146 | * | ||
147 | */ | ||
148 | enum usb_endpoint_status { | ||
149 | USB_EP_STATUS_HALTED = 1, | ||
150 | }; | ||
151 | |||
152 | /** | ||
153 | * \brief Standard USB device feature flags | ||
154 | * | ||
155 | * \note valid for SetFeature request. | ||
156 | */ | ||
157 | enum usb_device_feature { | ||
158 | USB_DEV_FEATURE_REMOTE_WAKEUP = 1, //!< Remote wakeup enabled | ||
159 | USB_DEV_FEATURE_TEST_MODE = 2, //!< USB test mode | ||
160 | USB_DEV_FEATURE_OTG_B_HNP_ENABLE = 3, | ||
161 | USB_DEV_FEATURE_OTG_A_HNP_SUPPORT = 4, | ||
162 | USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5 | ||
163 | }; | ||
164 | |||
165 | /** | ||
166 | * \brief Test Mode possible on HS USB device | ||
167 | * | ||
168 | * \note valid for USB_DEV_FEATURE_TEST_MODE request. | ||
169 | */ | ||
170 | enum usb_device_hs_test_mode { | ||
171 | USB_DEV_TEST_MODE_J = 1, | ||
172 | USB_DEV_TEST_MODE_K = 2, | ||
173 | USB_DEV_TEST_MODE_SE0_NAK = 3, | ||
174 | USB_DEV_TEST_MODE_PACKET = 4, | ||
175 | USB_DEV_TEST_MODE_FORCE_ENABLE = 5, | ||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * \brief Standard USB endpoint feature/status flags | ||
180 | */ | ||
181 | enum usb_endpoint_feature { | ||
182 | USB_EP_FEATURE_HALT = 0, | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * \brief Standard USB Test Mode Selectors | ||
187 | */ | ||
188 | enum usb_test_mode_selector { | ||
189 | USB_TEST_J = 0x01, | ||
190 | USB_TEST_K = 0x02, | ||
191 | USB_TEST_SE0_NAK = 0x03, | ||
192 | USB_TEST_PACKET = 0x04, | ||
193 | USB_TEST_FORCE_ENABLE = 0x05, | ||
194 | }; | ||
195 | |||
196 | /** | ||
197 | * \brief Standard USB descriptor types | ||
198 | */ | ||
199 | enum usb_descriptor_type { | ||
200 | USB_DT_DEVICE = 1, | ||
201 | USB_DT_CONFIGURATION = 2, | ||
202 | USB_DT_STRING = 3, | ||
203 | USB_DT_INTERFACE = 4, | ||
204 | USB_DT_ENDPOINT = 5, | ||
205 | USB_DT_DEVICE_QUALIFIER = 6, | ||
206 | USB_DT_OTHER_SPEED_CONFIGURATION = 7, | ||
207 | USB_DT_INTERFACE_POWER = 8, | ||
208 | USB_DT_OTG = 9, | ||
209 | USB_DT_IAD = 0x0B, | ||
210 | USB_DT_BOS = 0x0F, | ||
211 | USB_DT_DEVICE_CAPABILITY = 0x10, | ||
212 | }; | ||
213 | |||
214 | /** | ||
215 | * \brief USB Device Capability types | ||
216 | */ | ||
217 | enum usb_capability_type { | ||
218 | USB_DC_USB20_EXTENSION = 0x02, | ||
219 | }; | ||
220 | |||
221 | /** | ||
222 | * \brief USB Device Capability - USB 2.0 Extension | ||
223 | * To fill bmAttributes field of usb_capa_ext_desc_t structure. | ||
224 | */ | ||
225 | enum usb_capability_extension_attr { | ||
226 | USB_DC_EXT_LPM = 0x00000002, | ||
227 | }; | ||
228 | |||
229 | #define HIRD_50_US 0 | ||
230 | #define HIRD_125_US 1 | ||
231 | #define HIRD_200_US 2 | ||
232 | #define HIRD_275_US 3 | ||
233 | #define HIRD_350_US 4 | ||
234 | #define HIRD_425_US 5 | ||
235 | #define HIRD_500_US 6 | ||
236 | #define HIRD_575_US 7 | ||
237 | #define HIRD_650_US 8 | ||
238 | #define HIRD_725_US 9 | ||
239 | #define HIRD_800_US 10 | ||
240 | #define HIRD_875_US 11 | ||
241 | #define HIRD_950_US 12 | ||
242 | #define HIRD_1025_US 13 | ||
243 | #define HIRD_1100_US 14 | ||
244 | #define HIRD_1175_US 15 | ||
245 | |||
246 | /** Fields definition from a LPM TOKEN */ | ||
247 | #define USB_LPM_ATTRIBUT_BLINKSTATE_MASK (0xF << 0) | ||
248 | #define USB_LPM_ATTRIBUT_FIRD_MASK (0xF << 4) | ||
249 | #define USB_LPM_ATTRIBUT_REMOTEWAKE_MASK (1 << 8) | ||
250 | #define USB_LPM_ATTRIBUT_BLINKSTATE(value) ((value & 0xF) << 0) | ||
251 | #define USB_LPM_ATTRIBUT_FIRD(value) ((value & 0xF) << 4) | ||
252 | #define USB_LPM_ATTRIBUT_REMOTEWAKE(value) ((value & 1) << 8) | ||
253 | #define USB_LPM_ATTRIBUT_BLINKSTATE_L1 USB_LPM_ATTRIBUT_BLINKSTATE(1) | ||
254 | |||
255 | /** | ||
256 | * \brief Standard USB endpoint transfer types | ||
257 | */ | ||
258 | enum usb_ep_type { | ||
259 | USB_EP_TYPE_CONTROL = 0x00, | ||
260 | USB_EP_TYPE_ISOCHRONOUS = 0x01, | ||
261 | USB_EP_TYPE_BULK = 0x02, | ||
262 | USB_EP_TYPE_INTERRUPT = 0x03, | ||
263 | USB_EP_TYPE_MASK = 0x03, | ||
264 | }; | ||
265 | |||
266 | /** | ||
267 | * \brief Standard USB language IDs for string descriptors | ||
268 | */ | ||
269 | enum usb_langid { | ||
270 | USB_LANGID_EN_US = 0x0409, //!< English (United States) | ||
271 | }; | ||
272 | |||
273 | /** | ||
274 | * \brief Mask selecting the index part of an endpoint address | ||
275 | */ | ||
276 | #define USB_EP_ADDR_MASK 0x0f | ||
277 | |||
278 | //! \brief USB address identifier | ||
279 | typedef uint8_t usb_add_t; | ||
280 | |||
281 | /** | ||
282 | * \brief Endpoint transfer direction is IN | ||
283 | */ | ||
284 | #define USB_EP_DIR_IN 0x80 | ||
285 | |||
286 | /** | ||
287 | * \brief Endpoint transfer direction is OUT | ||
288 | */ | ||
289 | #define USB_EP_DIR_OUT 0x00 | ||
290 | |||
291 | //! \brief Endpoint identifier | ||
292 | typedef uint8_t usb_ep_t; | ||
293 | |||
294 | /** | ||
295 | * \brief Maximum length in bytes of a USB descriptor | ||
296 | * | ||
297 | * The maximum length of a USB descriptor is limited by the 8-bit | ||
298 | * bLength field. | ||
299 | */ | ||
300 | #define USB_MAX_DESC_LEN 255 | ||
301 | |||
302 | /* | ||
303 | * 2-byte alignment requested for all USB structures. | ||
304 | */ | ||
305 | COMPILER_PACK_SET(1) | ||
306 | |||
307 | /** | ||
308 | * \brief A USB Device SETUP request | ||
309 | * | ||
310 | * The data payload of SETUP packets always follows this structure. | ||
311 | */ | ||
312 | typedef struct { | ||
313 | uint8_t bmRequestType; | ||
314 | uint8_t bRequest; | ||
315 | le16_t wValue; | ||
316 | le16_t wIndex; | ||
317 | le16_t wLength; | ||
318 | } usb_setup_req_t; | ||
319 | |||
320 | /** | ||
321 | * \brief Standard USB device descriptor structure | ||
322 | */ | ||
323 | typedef struct { | ||
324 | uint8_t bLength; | ||
325 | uint8_t bDescriptorType; | ||
326 | le16_t bcdUSB; | ||
327 | uint8_t bDeviceClass; | ||
328 | uint8_t bDeviceSubClass; | ||
329 | uint8_t bDeviceProtocol; | ||
330 | uint8_t bMaxPacketSize0; | ||
331 | le16_t idVendor; | ||
332 | le16_t idProduct; | ||
333 | le16_t bcdDevice; | ||
334 | uint8_t iManufacturer; | ||
335 | uint8_t iProduct; | ||
336 | uint8_t iSerialNumber; | ||
337 | uint8_t bNumConfigurations; | ||
338 | } usb_dev_desc_t; | ||
339 | |||
340 | /** | ||
341 | * \brief Standard USB device qualifier descriptor structure | ||
342 | * | ||
343 | * This descriptor contains information about the device when running at | ||
344 | * the "other" speed (i.e. if the device is currently operating at high | ||
345 | * speed, this descriptor can be used to determine what would change if | ||
346 | * the device was operating at full speed.) | ||
347 | */ | ||
348 | typedef struct { | ||
349 | uint8_t bLength; | ||
350 | uint8_t bDescriptorType; | ||
351 | le16_t bcdUSB; | ||
352 | uint8_t bDeviceClass; | ||
353 | uint8_t bDeviceSubClass; | ||
354 | uint8_t bDeviceProtocol; | ||
355 | uint8_t bMaxPacketSize0; | ||
356 | uint8_t bNumConfigurations; | ||
357 | uint8_t bReserved; | ||
358 | } usb_dev_qual_desc_t; | ||
359 | |||
360 | /** | ||
361 | * \brief USB Device BOS descriptor structure | ||
362 | * | ||
363 | * The BOS descriptor (Binary device Object Store) defines a root | ||
364 | * descriptor that is similar to the configuration descriptor, and is | ||
365 | * the base descriptor for accessing a family of related descriptors. | ||
366 | * A host can read a BOS descriptor and learn from the wTotalLength field | ||
367 | * the entire size of the device-level descriptor set, or it can read in | ||
368 | * the entire BOS descriptor set of device capabilities. | ||
369 | * The host accesses this descriptor using the GetDescriptor() request. | ||
370 | * The descriptor type in the GetDescriptor() request is set to BOS. | ||
371 | */ | ||
372 | typedef struct { | ||
373 | uint8_t bLength; | ||
374 | uint8_t bDescriptorType; | ||
375 | le16_t wTotalLength; | ||
376 | uint8_t bNumDeviceCaps; | ||
377 | } usb_dev_bos_desc_t; | ||
378 | |||
379 | |||
380 | /** | ||
381 | * \brief USB Device Capabilities - USB 2.0 Extension Descriptor structure | ||
382 | * | ||
383 | * Defines the set of USB 1.1-specific device level capabilities. | ||
384 | */ | ||
385 | typedef struct { | ||
386 | uint8_t bLength; | ||
387 | uint8_t bDescriptorType; | ||
388 | uint8_t bDevCapabilityType; | ||
389 | le32_t bmAttributes; | ||
390 | } usb_dev_capa_ext_desc_t; | ||
391 | |||
392 | /** | ||
393 | * \brief USB Device LPM Descriptor structure | ||
394 | * | ||
395 | * The BOS descriptor and capabilities descriptors for LPM. | ||
396 | */ | ||
397 | typedef struct { | ||
398 | usb_dev_bos_desc_t bos; | ||
399 | usb_dev_capa_ext_desc_t capa_ext; | ||
400 | } usb_dev_lpm_desc_t; | ||
401 | |||
402 | /** | ||
403 | * \brief Standard USB Interface Association Descriptor structure | ||
404 | */ | ||
405 | typedef struct { | ||
406 | uint8_t bLength; //!< size of this descriptor in bytes | ||
407 | uint8_t bDescriptorType; //!< INTERFACE descriptor type | ||
408 | uint8_t bFirstInterface; //!< Number of interface | ||
409 | uint8_t bInterfaceCount; //!< value to select alternate setting | ||
410 | uint8_t bFunctionClass; //!< Class code assigned by the USB | ||
411 | uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB | ||
412 | uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB | ||
413 | uint8_t iFunction; //!< Index of string descriptor | ||
414 | } usb_association_desc_t; | ||
415 | |||
416 | |||
417 | /** | ||
418 | * \brief Standard USB configuration descriptor structure | ||
419 | */ | ||
420 | typedef struct { | ||
421 | uint8_t bLength; | ||
422 | uint8_t bDescriptorType; | ||
423 | le16_t wTotalLength; | ||
424 | uint8_t bNumInterfaces; | ||
425 | uint8_t bConfigurationValue; | ||
426 | uint8_t iConfiguration; | ||
427 | uint8_t bmAttributes; | ||
428 | uint8_t bMaxPower; | ||
429 | } usb_conf_desc_t; | ||
430 | |||
431 | |||
432 | #define USB_CONFIG_ATTR_MUST_SET (1 << 7) //!< Must always be set | ||
433 | #define USB_CONFIG_ATTR_BUS_POWERED (0 << 6) //!< Bus-powered | ||
434 | #define USB_CONFIG_ATTR_SELF_POWERED (1 << 6) //!< Self-powered | ||
435 | #define USB_CONFIG_ATTR_REMOTE_WAKEUP (1 << 5) //!< remote wakeup supported | ||
436 | |||
437 | #define USB_CONFIG_MAX_POWER(ma) (((ma) + 1) / 2) //!< Max power in mA | ||
438 | |||
439 | /** | ||
440 | * \brief Standard USB association descriptor structure | ||
441 | */ | ||
442 | typedef struct { | ||
443 | uint8_t bLength; //!< Size of this descriptor in bytes | ||
444 | uint8_t bDescriptorType; //!< Interface descriptor type | ||
445 | uint8_t bFirstInterface; //!< Number of interface | ||
446 | uint8_t bInterfaceCount; //!< value to select alternate setting | ||
447 | uint8_t bFunctionClass; //!< Class code assigned by the USB | ||
448 | uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB | ||
449 | uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB | ||
450 | uint8_t iFunction; //!< Index of string descriptor | ||
451 | } usb_iad_desc_t; | ||
452 | |||
453 | /** | ||
454 | * \brief Standard USB interface descriptor structure | ||
455 | */ | ||
456 | typedef struct { | ||
457 | uint8_t bLength; | ||
458 | uint8_t bDescriptorType; | ||
459 | uint8_t bInterfaceNumber; | ||
460 | uint8_t bAlternateSetting; | ||
461 | uint8_t bNumEndpoints; | ||
462 | uint8_t bInterfaceClass; | ||
463 | uint8_t bInterfaceSubClass; | ||
464 | uint8_t bInterfaceProtocol; | ||
465 | uint8_t iInterface; | ||
466 | } usb_iface_desc_t; | ||
467 | |||
468 | /** | ||
469 | * \brief Standard USB endpoint descriptor structure | ||
470 | */ | ||
471 | typedef struct { | ||
472 | uint8_t bLength; | ||
473 | uint8_t bDescriptorType; | ||
474 | uint8_t bEndpointAddress; | ||
475 | uint8_t bmAttributes; | ||
476 | le16_t wMaxPacketSize; | ||
477 | uint8_t bInterval; | ||
478 | } usb_ep_desc_t; | ||
479 | |||
480 | |||
481 | /** | ||
482 | * \brief A standard USB string descriptor structure | ||
483 | */ | ||
484 | typedef struct { | ||
485 | uint8_t bLength; | ||
486 | uint8_t bDescriptorType; | ||
487 | } usb_str_desc_t; | ||
488 | |||
489 | typedef struct { | ||
490 | usb_str_desc_t desc; | ||
491 | le16_t string[1]; | ||
492 | } usb_str_lgid_desc_t; | ||
493 | |||
494 | COMPILER_PACK_RESET() | ||
495 | |||
496 | //! @} | ||
497 | |||
498 | #endif /* _USB_PROTOCOL_H_ */ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h b/tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h new file mode 100644 index 000000000..479f25d4e --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h | |||
@@ -0,0 +1,193 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Communication Device Class (CDC) protocol definitions | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | #ifndef _USB_PROTOCOL_CDC_H_ | ||
47 | #define _USB_PROTOCOL_CDC_H_ | ||
48 | |||
49 | #include "compiler.h" | ||
50 | |||
51 | #ifdef CDC | ||
52 | |||
53 | #define CDC_CLASS_DEVICE 0x02 //!< USB Communication Device Class | ||
54 | #define CDC_CLASS_COMM 0x02 //!< CDC Communication Class Interface | ||
55 | #define CDC_CLASS_DATA 0x0A //!< CDC Data Class Interface | ||
56 | |||
57 | #define CDC_SUBCLASS_DLCM 0x01 //!< Direct Line Control Model | ||
58 | #define CDC_SUBCLASS_ACM 0x02 //!< Abstract Control Model | ||
59 | #define CDC_SUBCLASS_TCM 0x03 //!< Telephone Control Model | ||
60 | #define CDC_SUBCLASS_MCCM 0x04 //!< Multi-Channel Control Model | ||
61 | #define CDC_SUBCLASS_CCM 0x05 //!< CAPI Control Model | ||
62 | #define CDC_SUBCLASS_ETH 0x06 //!< Ethernet Networking Control Model | ||
63 | #define CDC_SUBCLASS_ATM 0x07 //!< ATM Networking Control Model | ||
64 | |||
65 | #define CDC_PROTOCOL_V25TER 0x01 //!< Common AT commands | ||
66 | |||
67 | #define CDC_PROTOCOL_I430 0x30 //!< ISDN BRI | ||
68 | #define CDC_PROTOCOL_HDLC 0x31 //!< HDLC | ||
69 | #define CDC_PROTOCOL_TRANS 0x32 //!< Transparent | ||
70 | #define CDC_PROTOCOL_Q921M 0x50 //!< Q.921 management protocol | ||
71 | #define CDC_PROTOCOL_Q921 0x51 //!< Q.931 [sic] Data link protocol | ||
72 | #define CDC_PROTOCOL_Q921TM 0x52 //!< Q.921 TEI-multiplexor | ||
73 | #define CDC_PROTOCOL_V42BIS 0x90 //!< Data compression procedures | ||
74 | #define CDC_PROTOCOL_Q931 0x91 //!< Euro-ISDN protocol control | ||
75 | #define CDC_PROTOCOL_V120 0x92 //!< V.24 rate adaption to ISDN | ||
76 | #define CDC_PROTOCOL_CAPI20 0x93 //!< CAPI Commands | ||
77 | #define CDC_PROTOCOL_HOST 0xFD //!< Host based driver | ||
78 | |||
79 | #define CDC_PROTOCOL_PUFD 0xFE | ||
80 | |||
81 | #define CDC_CS_INTERFACE 0x24 //!< Interface Functional Descriptor | ||
82 | #define CDC_CS_ENDPOINT 0x25 //!< Endpoint Functional Descriptor | ||
83 | |||
84 | #define CDC_SCS_HEADER 0x00 //!< Header Functional Descriptor | ||
85 | #define CDC_SCS_CALL_MGMT 0x01 //!< Call Management | ||
86 | #define CDC_SCS_ACM 0x02 //!< Abstract Control Management | ||
87 | #define CDC_SCS_UNION 0x06 //!< Union Functional Descriptor | ||
88 | |||
89 | #define USB_REQ_CDC_SEND_ENCAPSULATED_COMMAND 0x00 | ||
90 | #define USB_REQ_CDC_GET_ENCAPSULATED_RESPONSE 0x01 | ||
91 | #define USB_REQ_CDC_SET_COMM_FEATURE 0x02 | ||
92 | #define USB_REQ_CDC_GET_COMM_FEATURE 0x03 | ||
93 | #define USB_REQ_CDC_CLEAR_COMM_FEATURE 0x04 | ||
94 | #define USB_REQ_CDC_SET_AUX_LINE_STATE 0x10 | ||
95 | #define USB_REQ_CDC_SET_HOOK_STATE 0x11 | ||
96 | #define USB_REQ_CDC_PULSE_SETUP 0x12 | ||
97 | #define USB_REQ_CDC_SEND_PULSE 0x13 | ||
98 | #define USB_REQ_CDC_SET_PULSE_TIME 0x14 | ||
99 | #define USB_REQ_CDC_RING_AUX_JACK 0x15 | ||
100 | #define USB_REQ_CDC_SET_LINE_CODING 0x20 | ||
101 | #define USB_REQ_CDC_GET_LINE_CODING 0x21 | ||
102 | #define USB_REQ_CDC_SET_CONTROL_LINE_STATE 0x22 | ||
103 | #define USB_REQ_CDC_SEND_BREAK 0x23 | ||
104 | #define USB_REQ_CDC_SET_RINGER_PARMS 0x30 | ||
105 | #define USB_REQ_CDC_GET_RINGER_PARMS 0x31 | ||
106 | #define USB_REQ_CDC_SET_OPERATION_PARMS 0x32 | ||
107 | #define USB_REQ_CDC_GET_OPERATION_PARMS 0x33 | ||
108 | #define USB_REQ_CDC_SET_LINE_PARMS 0x34 | ||
109 | #define USB_REQ_CDC_GET_LINE_PARMS 0x35 | ||
110 | #define USB_REQ_CDC_DIAL_DIGITS 0x36 | ||
111 | #define USB_REQ_CDC_SET_UNIT_PARAMETER 0x37 | ||
112 | #define USB_REQ_CDC_GET_UNIT_PARAMETER 0x38 | ||
113 | #define USB_REQ_CDC_CLEAR_UNIT_PARAMETER 0x39 | ||
114 | #define USB_REQ_CDC_GET_PROFILE 0x3A | ||
115 | #define USB_REQ_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 | ||
116 | #define USB_REQ_CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERNFILTER 0x41 | ||
117 | #define USB_REQ_CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERNFILTER 0x42 | ||
118 | #define USB_REQ_CDC_SET_ETHERNET_PACKET_FILTER 0x43 | ||
119 | #define USB_REQ_CDC_GET_ETHERNET_STATISTIC 0x44 | ||
120 | #define USB_REQ_CDC_SET_ATM_DATA_FORMAT 0x50 | ||
121 | #define USB_REQ_CDC_GET_ATM_DEVICE_STATISTICS 0x51 | ||
122 | #define USB_REQ_CDC_SET_ATM_DEFAULT_VC 0x52 | ||
123 | #define USB_REQ_CDC_GET_ATM_VC_STATISTICS 0x53 | ||
124 | // Added bNotification codes according cdc spec 1.1 chapter 6.3 | ||
125 | #define USB_REQ_CDC_NOTIFY_RING_DETECT 0x09 | ||
126 | #define USB_REQ_CDC_NOTIFY_SERIAL_STATE 0x20 | ||
127 | #define USB_REQ_CDC_NOTIFY_CALL_STATE_CHANGE 0x28 | ||
128 | #define USB_REQ_CDC_NOTIFY_LINE_STATE_CHANGE 0x29 | ||
129 | |||
130 | |||
131 | #define CDC_CALL_MGMT_SUPPORTED (1 << 0) | ||
132 | #define CDC_CALL_MGMT_OVER_DCI (1 << 1) | ||
133 | #define CDC_ACM_SUPPORT_FEATURE_REQUESTS (1 << 0) | ||
134 | #define CDC_ACM_SUPPORT_LINE_REQUESTS (1 << 1) | ||
135 | #define CDC_ACM_SUPPORT_SENDBREAK_REQUESTS (1 << 2) | ||
136 | #define CDC_ACM_SUPPORT_NOTIFY_REQUESTS (1 << 3) | ||
137 | |||
138 | #pragma pack(push,1) | ||
139 | typedef struct { | ||
140 | le32_t dwDTERate; | ||
141 | uint8_t bCharFormat; | ||
142 | uint8_t bParityType; | ||
143 | uint8_t bDataBits; | ||
144 | } usb_cdc_line_coding_t; | ||
145 | #pragma pack(pop) | ||
146 | |||
147 | enum cdc_char_format { | ||
148 | CDC_STOP_BITS_1 = 0, //!< 1 stop bit | ||
149 | CDC_STOP_BITS_1_5 = 1, //!< 1.5 stop bits | ||
150 | CDC_STOP_BITS_2 = 2, //!< 2 stop bits | ||
151 | }; | ||
152 | |||
153 | enum cdc_parity { | ||
154 | CDC_PAR_NONE = 0, //!< No parity | ||
155 | CDC_PAR_ODD = 1, //!< Odd parity | ||
156 | CDC_PAR_EVEN = 2, //!< Even parity | ||
157 | CDC_PAR_MARK = 3, //!< Parity forced to 0 (space) | ||
158 | CDC_PAR_SPACE = 4, //!< Parity forced to 1 (mark) | ||
159 | }; | ||
160 | |||
161 | |||
162 | typedef struct { | ||
163 | uint16_t value; | ||
164 | } usb_cdc_control_signal_t; | ||
165 | |||
166 | #define CDC_CTRL_SIGNAL_ACTIVATE_CARRIER (1 << 1) | ||
167 | #define CDC_CTRL_SIGNAL_DTE_PRESENT (1 << 0) | ||
168 | |||
169 | |||
170 | typedef struct { | ||
171 | uint8_t bmRequestType; | ||
172 | uint8_t bNotification; | ||
173 | le16_t wValue; | ||
174 | le16_t wIndex; | ||
175 | le16_t wLength; | ||
176 | } usb_cdc_notify_msg_t; | ||
177 | |||
178 | typedef struct { | ||
179 | usb_cdc_notify_msg_t header; | ||
180 | le16_t value; | ||
181 | } usb_cdc_notify_serial_state_t; | ||
182 | |||
183 | #define CDC_SERIAL_STATE_DCD CPU_TO_LE16((1<<0)) | ||
184 | #define CDC_SERIAL_STATE_DSR CPU_TO_LE16((1<<1)) | ||
185 | #define CDC_SERIAL_STATE_BREAK CPU_TO_LE16((1<<2)) | ||
186 | #define CDC_SERIAL_STATE_RING CPU_TO_LE16((1<<3)) | ||
187 | #define CDC_SERIAL_STATE_FRAMING CPU_TO_LE16((1<<4)) | ||
188 | #define CDC_SERIAL_STATE_PARITY CPU_TO_LE16((1<<5)) | ||
189 | #define CDC_SERIAL_STATE_OVERRUN CPU_TO_LE16((1<<6)) | ||
190 | |||
191 | #endif | ||
192 | |||
193 | #endif // _USB_PROTOCOL_CDC_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h b/tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h new file mode 100644 index 000000000..c482e9c06 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h | |||
@@ -0,0 +1,319 @@ | |||
1 | /** | ||
2 | * \file | ||
3 | * | ||
4 | * \brief USB Human Interface Device (HID) protocol definitions. | ||
5 | * | ||
6 | * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved. | ||
7 | * | ||
8 | * \asf_license_start | ||
9 | * | ||
10 | * \page License | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright notice, | ||
16 | * this list of conditions and the following disclaimer. | ||
17 | * | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright notice, | ||
19 | * this list of conditions and the following disclaimer in the documentation | ||
20 | * and/or other materials provided with the distribution. | ||
21 | * | ||
22 | * 3. The name of Atmel may not be used to endorse or promote products derived | ||
23 | * from this software without specific prior written permission. | ||
24 | * | ||
25 | * 4. This software may only be redistributed and used in connection with an | ||
26 | * Atmel microcontroller product. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | ||
29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | ||
31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR | ||
32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGE. | ||
39 | * | ||
40 | * \asf_license_stop | ||
41 | * | ||
42 | */ | ||
43 | /* | ||
44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> | ||
45 | */ | ||
46 | |||
47 | #ifndef _USB_PROTOCOL_HID_H_ | ||
48 | #define _USB_PROTOCOL_HID_H_ | ||
49 | |||
50 | /** | ||
51 | * \ingroup usb_protocol_group | ||
52 | * \defgroup usb_hid_protocol USB Human Interface Device (HID) | ||
53 | * protocol definitions | ||
54 | * \brief USB Human Interface Device (HID) protocol definitions | ||
55 | * | ||
56 | * @{ | ||
57 | */ | ||
58 | |||
59 | //! \name Possible Class value | ||
60 | //@{ | ||
61 | #define HID_CLASS 0x03 | ||
62 | //@} | ||
63 | |||
64 | //! \name Possible SubClass value | ||
65 | //@{ | ||
66 | //! Interface subclass NO support BOOT protocol | ||
67 | #define HID_SUB_CLASS_NOBOOT 0x00 | ||
68 | //! Interface subclass support BOOT protocol | ||
69 | #define HID_SUB_CLASS_BOOT 0x01 | ||
70 | //@} | ||
71 | |||
72 | //! \name Possible protocol value | ||
73 | //@{ | ||
74 | //! Protocol generic standard | ||
75 | #define HID_PROTOCOL_GENERIC 0x00 | ||
76 | //! Protocol keyboard standard | ||
77 | #define HID_PROTOCOL_KEYBOARD 0x01 | ||
78 | //! Protocol mouse standard | ||
79 | #define HID_PROTOCOL_MOUSE 0x02 | ||
80 | //@} | ||
81 | |||
82 | |||
83 | //! \brief Hid USB requests (bRequest) | ||
84 | enum usb_reqid_hid { | ||
85 | USB_REQ_HID_GET_REPORT = 0x01, | ||
86 | USB_REQ_HID_GET_IDLE = 0x02, | ||
87 | USB_REQ_HID_GET_PROTOCOL = 0x03, | ||
88 | USB_REQ_HID_SET_REPORT = 0x09, | ||
89 | USB_REQ_HID_SET_IDLE = 0x0A, | ||
90 | USB_REQ_HID_SET_PROTOCOL = 0x0B, | ||
91 | }; | ||
92 | |||
93 | //! \brief HID USB descriptor types | ||
94 | enum usb_descriptor_type_hid { | ||
95 | USB_DT_HID = 0x21, | ||
96 | USB_DT_HID_REPORT = 0x22, | ||
97 | USB_DT_HID_PHYSICAL = 0x23, | ||
98 | }; | ||
99 | |||
100 | //! \brief HID Type for report descriptor | ||
101 | enum usb_hid_item_report_type { | ||
102 | USB_HID_ITEM_REPORT_TYPE_MAIN = 0, | ||
103 | USB_HID_ITEM_REPORT_TYPE_GLOBAL = 1, | ||
104 | USB_HID_ITEM_REPORT_TYPE_LOCAL = 2, | ||
105 | USB_HID_ITEM_REPORT_TYPE_LONG = 3, | ||
106 | }; | ||
107 | |||
108 | //! \brief HID report type | ||
109 | enum usb_hid_report_type { | ||
110 | USB_HID_REPORT_TYPE_INPUT = 1, | ||
111 | USB_HID_REPORT_TYPE_OUTPUT = 2, | ||
112 | USB_HID_REPORT_TYPE_FEATURE = 3, | ||
113 | }; | ||
114 | |||
115 | |||
116 | //! \brief HID protocol | ||
117 | enum usb_hid_protocol { | ||
118 | USB_HID_PROCOTOL_BOOT = 0, | ||
119 | USB_HID_PROCOTOL_REPORT = 1, | ||
120 | }; | ||
121 | |||
122 | COMPILER_PACK_SET(1) | ||
123 | |||
124 | //! \brief HID Descriptor | ||
125 | typedef struct { | ||
126 | uint8_t bLength; //!< Size of this descriptor in bytes | ||
127 | uint8_t bDescriptorType; //!< HID descriptor type | ||
128 | le16_t bcdHID; //!< Binary Coded Decimal Spec. release | ||
129 | uint8_t bCountryCode; //!< Hardware target country | ||
130 | uint8_t bNumDescriptors; //!< Number of HID class descriptors to follow | ||
131 | uint8_t bRDescriptorType; //!< Report descriptor type | ||
132 | le16_t wDescriptorLength; //!< Total length of Report descriptor | ||
133 | } usb_hid_descriptor_t; | ||
134 | |||
135 | COMPILER_PACK_RESET() | ||
136 | |||
137 | //! \name HID Report type | ||
138 | //! Used by SETUP_HID_GET_REPORT & SETUP_HID_SET_REPORT | ||
139 | //! @{ | ||
140 | #define REPORT_TYPE_INPUT 0x01 | ||
141 | #define REPORT_TYPE_OUTPUT 0x02 | ||
142 | #define REPORT_TYPE_FEATURE 0x03 | ||
143 | //! @} | ||
144 | |||
145 | //! \name Constants of field DESCRIPTOR_HID | ||
146 | //! @{ | ||
147 | //! Numeric expression identifying the HID Class | ||
148 | //! Specification release (here V1.11) | ||
149 | #define USB_HID_BDC_V1_11 0x0111 | ||
150 | //! Numeric expression specifying the number of class descriptors | ||
151 | //! Note: Always at least one i.e. Report descriptor. | ||
152 | #define USB_HID_NUM_DESC 0x01 | ||
153 | |||
154 | //! \name Country code | ||
155 | //! @{ | ||
156 | #define USB_HID_NO_COUNTRY_CODE 0 // Not Supported | ||
157 | #define USB_HID_COUNTRY_ARABIC 1 // Arabic | ||
158 | #define USB_HID_COUNTRY_BELGIAN 2 // Belgian | ||
159 | #define USB_HID_COUNTRY_CANADIAN_BILINGUAL 3 // Canadian-Bilingual | ||
160 | #define USB_HID_COUNTRY_CANADIAN_FRENCH 4 // Canadian-French | ||
161 | #define USB_HID_COUNTRY_CZECH_REPUBLIC 5 // Czech Republic | ||
162 | #define USB_HID_COUNTRY_DANISH 6 // Danish | ||
163 | #define USB_HID_COUNTRY_FINNISH 7 // Finnish | ||
164 | #define USB_HID_COUNTRY_FRENCH 8 // French | ||
165 | #define USB_HID_COUNTRY_GERMAN 9 // German | ||
166 | #define USB_HID_COUNTRY_GREEK 10 // Greek | ||
167 | #define USB_HID_COUNTRY_HEBREW 11 // Hebrew | ||
168 | #define USB_HID_COUNTRY_HUNGARY 12 // Hungary | ||
169 | #define USB_HID_COUNTRY_INTERNATIONAL_ISO 13 // International (ISO) | ||
170 | #define USB_HID_COUNTRY_ITALIAN 14 // Italian | ||
171 | #define USB_HID_COUNTRY_JAPAN_KATAKANA 15 // Japan (Katakana) | ||
172 | #define USB_HID_COUNTRY_KOREAN 16 // Korean | ||
173 | #define USB_HID_COUNTRY_LATIN_AMERICAN 17 // Latin American | ||
174 | #define USB_HID_COUNTRY_NETHERLANDS_DUTCH 18 // Netherlands/Dutch | ||
175 | #define USB_HID_COUNTRY_NORWEGIAN 19 // Norwegian | ||
176 | #define USB_HID_COUNTRY_PERSIAN_FARSI 20 // Persian (Farsi) | ||
177 | #define USB_HID_COUNTRY_POLAND 21 // Poland | ||
178 | #define USB_HID_COUNTRY_PORTUGUESE 22 // Portuguese | ||
179 | #define USB_HID_COUNTRY_RUSSIA 23 // Russia | ||
180 | #define USB_HID_COUNTRY_SLOVAKIA 24 // Slovakia | ||
181 | #define USB_HID_COUNTRY_SPANISH 25 // Spanish | ||
182 | #define USB_HID_COUNTRY_SWEDISH 26 // Swedish | ||
183 | #define USB_HID_COUNTRY_SWISS_FRENCH 27 // Swiss/French | ||
184 | #define USB_HID_COUNTRY_SWISS_GERMAN 28 // Swiss/German | ||
185 | #define USB_HID_COUNTRY_SWITZERLAND 29 // Switzerland | ||
186 | #define USB_HID_COUNTRY_TAIWAN 30 // Taiwan | ||
187 | #define USB_HID_COUNTRY_TURKISH_Q 31 // Turkish-Q | ||
188 | #define USB_HID_COUNTRY_UK 32 // UK | ||
189 | #define USB_HID_COUNTRY_US 33 // US | ||
190 | #define USB_HID_COUNTRY_YUGOSLAVIA 34 // Yugoslavia | ||
191 | #define USB_HID_COUNTRY_TURKISH_F 35 // Turkish-F | ||
192 | //! @} | ||
193 | //! @} | ||
194 | //! @} | ||
195 | |||
196 | |||
197 | //! \name HID KEYS values | ||
198 | //! @{ | ||
199 | #define HID_A 0x04 | ||
200 | #define HID_B 0x05 | ||
201 | #define HID_C 0x06 | ||
202 | #define HID_D 0x07 | ||
203 | #define HID_E 0x08 | ||
204 | #define HID_F 0x09 | ||
205 | #define HID_G 0x0A | ||
206 | #define HID_H 0x0B | ||
207 | #define HID_I 0x0C | ||
208 | #define HID_J 0x0D | ||
209 | #define HID_K 0x0E | ||
210 | #define HID_L 0x0F | ||
211 | #define HID_M 0x10 | ||
212 | #define HID_N 0x11 | ||
213 | #define HID_O 0x12 | ||
214 | #define HID_P 0x13 | ||
215 | #define HID_Q 0x14 | ||
216 | #define HID_R 0x15 | ||
217 | #define HID_S 0x16 | ||
218 | #define HID_T 0x17 | ||
219 | #define HID_U 0x18 | ||
220 | #define HID_V 0x19 | ||
221 | #define HID_W 0x1A | ||
222 | #define HID_X 0x1B | ||
223 | #define HID_Y 0x1C | ||
224 | #define HID_Z 0x1D | ||
225 | #define HID_1 30 | ||
226 | #define HID_2 31 | ||
227 | #define HID_3 32 | ||
228 | #define HID_4 33 | ||
229 | #define HID_5 34 | ||
230 | #define HID_6 35 | ||
231 | #define HID_7 36 | ||
232 | #define HID_8 37 | ||
233 | #define HID_9 38 | ||
234 | #define HID_0 39 | ||
235 | #define HID_ENTER 40 | ||
236 | #define HID_ESCAPE 41 | ||
237 | #define HID_BACKSPACE 42 | ||
238 | #define HID_TAB 43 | ||
239 | #define HID_SPACEBAR 44 | ||
240 | #define HID_UNDERSCORE 45 | ||
241 | #define HID_PLUS 46 | ||
242 | #define HID_OPEN_BRACKET 47 // { | ||
243 | #define HID_CLOSE_BRACKET 48 // } | ||
244 | #define HID_BACKSLASH 49 | ||
245 | #define HID_ASH 50 // # ~ | ||
246 | #define HID_COLON 51 // ; : | ||
247 | #define HID_QUOTE 52 // ' " | ||
248 | #define HID_TILDE 53 | ||
249 | #define HID_COMMA 54 | ||
250 | #define HID_DOT 55 | ||
251 | #define HID_SLASH 56 | ||
252 | #define HID_CAPS_LOCK 57 | ||
253 | #define HID_F1 58 | ||
254 | #define HID_F2 59 | ||
255 | #define HID_F3 60 | ||
256 | #define HID_F4 61 | ||
257 | #define HID_F5 62 | ||
258 | #define HID_F6 63 | ||
259 | #define HID_F7 64 | ||
260 | #define HID_F8 65 | ||
261 | #define HID_F9 66 | ||
262 | #define HID_F10 67 | ||
263 | #define HID_F11 68 | ||
264 | #define HID_F12 69 | ||
265 | #define HID_PRINTSCREEN 70 | ||
266 | #define HID_SCROLL_LOCK 71 | ||
267 | #define HID_PAUSE 72 | ||
268 | #define HID_INSERT 73 | ||
269 | #define HID_HOME 74 | ||
270 | #define HID_PAGEUP 75 | ||
271 | #define HID_DELETE 76 | ||
272 | #define HID_END 77 | ||
273 | #define HID_PAGEDOWN 78 | ||
274 | #define HID_RIGHT 79 | ||
275 | #define HID_LEFT 80 | ||
276 | #define HID_DOWN 81 | ||
277 | #define HID_UP 82 | ||
278 | #define HID_KEYPAD_NUM_LOCK 83 | ||
279 | #define HID_KEYPAD_DIVIDE 84 | ||
280 | #define HID_KEYPAD_AT 85 | ||
281 | #define HID_KEYPAD_MULTIPLY 85 | ||
282 | #define HID_KEYPAD_MINUS 86 | ||
283 | #define HID_KEYPAD_PLUS 87 | ||
284 | #define HID_KEYPAD_ENTER 88 | ||
285 | #define HID_KEYPAD_1 89 | ||
286 | #define HID_KEYPAD_2 90 | ||
287 | #define HID_KEYPAD_3 91 | ||
288 | #define HID_KEYPAD_4 92 | ||
289 | #define HID_KEYPAD_5 93 | ||
290 | #define HID_KEYPAD_6 94 | ||
291 | #define HID_KEYPAD_7 95 | ||
292 | #define HID_KEYPAD_8 96 | ||
293 | #define HID_KEYPAD_9 97 | ||
294 | #define HID_KEYPAD_0 98 | ||
295 | |||
296 | //! \name HID modifier values | ||
297 | //! @{ | ||
298 | #define HID_MODIFIER_NONE 0x00 | ||
299 | #define HID_MODIFIER_LEFT_CTRL 0x01 | ||
300 | #define HID_MODIFIER_LEFT_SHIFT 0x02 | ||
301 | #define HID_MODIFIER_LEFT_ALT 0x04 | ||
302 | #define HID_MODIFIER_LEFT_UI 0x08 | ||
303 | #define HID_MODIFIER_RIGHT_CTRL 0x10 | ||
304 | #define HID_MODIFIER_RIGHT_SHIFT 0x20 | ||
305 | #define HID_MODIFIER_RIGHT_ALT 0x40 | ||
306 | #define HID_MODIFIER_RIGHT_UI 0x80 | ||
307 | //! @} | ||
308 | //! @} | ||
309 | |||
310 | //! \name HID KEYS values | ||
311 | //! @{ | ||
312 | #define HID_LED_NUM_LOCK (1<<0) | ||
313 | #define HID_LED_CAPS_LOCK (1<<1) | ||
314 | #define HID_LED_SCROLL_LOCK (1<<2) | ||
315 | #define HID_LED_COMPOSE (1<<3) | ||
316 | #define HID_LED_KANA (1<<4) | ||
317 | //! @} | ||
318 | |||
319 | #endif // _USB_PROTOCOL_HID_H_ | ||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_util.c b/tmk_core/protocol/arm_atsam/usb/usb_util.c new file mode 100644 index 000000000..58b349362 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_util.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include "samd51j18a.h" | ||
2 | #include "string.h" | ||
3 | #include "usb_util.h" | ||
4 | |||
5 | char digit(int d, int radix) | ||
6 | { | ||
7 | if (d < 10) | ||
8 | { | ||
9 | return d + '0'; | ||
10 | } | ||
11 | else | ||
12 | { | ||
13 | return d - 10 + 'A'; | ||
14 | } | ||
15 | } | ||
16 | |||
17 | int UTIL_ltoa_radix(int64_t value, char *dest, int radix) | ||
18 | { | ||
19 | int64_t original = value; //save original value | ||
20 | char buf[25] = ""; | ||
21 | int c = sizeof(buf)-1; | ||
22 | int last = c; | ||
23 | int d; | ||
24 | int size; | ||
25 | |||
26 | if (value < 0) //if it's negative, take the absolute value | ||
27 | value = -value; | ||
28 | |||
29 | do //write least significant digit of value that's left | ||
30 | { | ||
31 | d = (value % radix); | ||
32 | buf[--c] = digit(d, radix); | ||
33 | value /= radix; | ||
34 | } while (value); | ||
35 | |||
36 | if (original < 0) | ||
37 | buf[--c] = '-'; | ||
38 | |||
39 | size = last - c + 1; //includes null at end | ||
40 | memcpy(dest, &buf[c], last - c + 1); | ||
41 | |||
42 | return (size - 1); //without null termination | ||
43 | } | ||
44 | |||
45 | int UTIL_ltoa(int64_t value, char *dest) | ||
46 | { | ||
47 | return UTIL_ltoa_radix(value, dest, 10); | ||
48 | } | ||
49 | |||
50 | int UTIL_itoa(int value, char *dest) | ||
51 | { | ||
52 | return UTIL_ltoa_radix((int64_t)value, dest, 10); | ||
53 | } | ||
54 | |||
55 | int UTIL_utoa(uint32_t value, char *dest) | ||
56 | { | ||
57 | return UTIL_ltoa_radix((int64_t)value, dest, 10); | ||
58 | } | ||
59 | |||
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_util.h b/tmk_core/protocol/arm_atsam/usb/usb_util.h new file mode 100644 index 000000000..2134d5d27 --- /dev/null +++ b/tmk_core/protocol/arm_atsam/usb/usb_util.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef _USB_UTIL_H_ | ||
2 | #define _USB_UTIL_H_ | ||
3 | |||
4 | int UTIL_ltoa_radix(int64_t value, char *dest, int radix); | ||
5 | int UTIL_ltoa(int64_t value, char *dest); | ||
6 | int UTIL_itoa(int value, char *dest); | ||
7 | int UTIL_utoa(uint32_t value, char *dest); | ||
8 | |||
9 | #endif //_USB_UTIL_H_ | ||
10 | |||
diff --git a/tmk_core/protocol/arm_atsam/wait_api.h b/tmk_core/protocol/arm_atsam/wait_api.h new file mode 100644 index 000000000..424fbb53b --- /dev/null +++ b/tmk_core/protocol/arm_atsam/wait_api.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _wait_api_h_ | ||
2 | #define _wait_api_h_ | ||
3 | |||
4 | void wait_ms(uint64_t msec); | ||
5 | void wait_us(uint16_t usec); | ||
6 | |||
7 | #endif | ||
8 | |||