diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-09-26 19:36:54 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-09-26 19:36:54 -0600 |
commit | 71e1a86a033c380f85dd300d788af63bfef25bab (patch) | |
tree | 07aa53d5a933ba51535a78972edbfe0cd95a31c5 /libusb | |
parent | f5da707e77ee954b12f3c961012e4f40fa4e1bd3 (diff) |
wip reorg
Diffstat (limited to 'libusb')
-rw-r--r-- | libusb/tusb_config.h | 107 | ||||
-rw-r--r-- | libusb/tusb_helpers.h | 971 | ||||
-rwxr-xr-x | libusb/tusb_helpers.h.gen | 82 | ||||
-rw-r--r-- | libusb/usb_common.c | 189 | ||||
-rw-r--r-- | libusb/usb_common.h | 59 |
5 files changed, 1408 insertions, 0 deletions
diff --git a/libusb/tusb_config.h b/libusb/tusb_config.h new file mode 100644 index 0000000..cb1ca3b --- /dev/null +++ b/libusb/tusb_config.h @@ -0,0 +1,107 @@ +/* tusb_config.h - Compile-time configuration for the TinyUSB library + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//-------------------------------------------------------------------- +// TinyUSB Device (TUD) initialization for rp2040-based boards +//-------------------------------------------------------------------- + +// Which USB port to use for the RootHub. +// The rp2040 only has 1 port, so it's gotta be port #0. +#define BOARD_TUD_RHPORT 0 + +// RHPort max operational speed. +// Use OPT_MODE_DEFAULT_SPEED for max speed supported by MCU. +#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED + +//-------------------------------------------------------------------- +// Configuration: common +//-------------------------------------------------------------------- + +// defined by compiler flags +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +// Conditional because it might be defined with `-D` on the command +// line if `cmake -DCMAKE_BUILD_TYPE=Debug`. +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 0 +#endif + +// USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. +// Tinyusb use follows macros to declare transferring memory so that they can be put +// into those specific section. +// e.g +// - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) +// - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) +#define CFG_TUSB_MEM_SECTION /* blank */ +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) + +#define CFG_TUD_ENABLED 1 +#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED + +//-------------------------------------------------------------------- +// Configuration: TinyUSB Device (TUD) +//-------------------------------------------------------------------- + +// control endpoint max packet size (only 8, 16, 32, or 64 are valid) +#define CFG_TUD_ENDPOINT0_SIZE 64 + +// Which of TinyUSB's built-in class drivers to enable. +// +// If a class takes an int, that's the maximum number of interfaces of +// that type that may be listed in the same configuration descriptor. +#define CFG_TUD_CDC 0 // int : Communications Device Class (e.g. ttyUSB) https://www.usb.org/sites/default/files/CDC1.2_WMC1.1_012011.zip +#define CFG_TUD_MSC 0 // bool: Mass Storage Class https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf +#define CFG_TUD_HID 1 // int : Human Interface Device https://www.usb.org/sites/default/files/hid1_11.pdf +#define CFG_TUD_AUDIO 0 // int : Audio https://www.usb.org/sites/default/files/audio10.pdf +#define CFG_TUD_VIDEO 0 // int : Video https://www.usb.org/sites/default/files/USB_Video_Class_1_5.zip +#define CFG_TUD_MIDI 0 // int : Musical Instrument Digital Interface https://www.usb.org/sites/default/files/USB%20MIDI%20v2_0.pdf +#define CFG_TUD_VENDOR 0 // int : ??? +#define CFG_TUD_USBTMC 0 // bool: Test & Measurement Class https://www.usb.org/sites/default/files/USBTMC_1_006a.zip +#define CFG_TUD_DFU_RUNTIME 0 // bool: Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf +#define CFG_TUD_DFU 0 // bool: Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf +#define CFG_TUD_ECM_RNDIS 0 // bool: net +#define CFG_TUD_NCM 0 // bool: net +#define CFG_TUD_BTH 0 // bool: Bluetooth + +// HID buffer size Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_EP_BUFSIZE 8 + +//-------------------------------------------------------------------- +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/libusb/tusb_helpers.h b/libusb/tusb_helpers.h new file mode 100644 index 0000000..cd96357 --- /dev/null +++ b/libusb/tusb_helpers.h @@ -0,0 +1,971 @@ +/* tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB + * + * Copyright (c) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _USB_HELPERS_H_ +#define _USB_HELPERS_H_ + +/* USB 2.0 §9.6.7 "String" says "The list of currently defined USB LANGIDs can be found at + * http://www.usb.org/developers/docs.html.", but that page 404s. + * + * Once upon a time the USB-IF (usb.org) published a "Language Identifiers (LANGIDs)" version 1.0, + * dated 2000-03-29. There is no longer any mention of this on usb.org, but I found a copy at + * http://www.baiheee.com/Documents/090518/090518112619/USB_LANGIDs.pdf + * + * So how does the USB-IF defined LANGIDs these days? + * + * https://www.usb.org/deprecated-links-and-tools says "To get the latest LANGID definitions go to + * https://docs.microsoft.com/en-us/windows/desktop/intl/language-identifier-constants-and-strings. This + * page will change as new LANGIDs are added." That page has no list of LANGIDs, but says "For the + * predefined primary language identifiers with their valid sublanguage identifiers, see + * [\[MS-LCID\]: Windows Language Code Identifier (LCID) + * Reference](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-565326e84c37f)." + * That page at the time of this writing as a PDF marked as version 16.0, dated 2024-04-24: + * https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf + * [MS-LCID] defines an LCID as a 32-bit value consisting of a 16-bit a "Language ID", a 4-bit "Sort + * ID", and 12 reserved bits. + * + * That is to say: The USB-IF has said in essence "USB LANGIDs are defined to be the 'Language ID' + * portion of Microsoft Windows LCIDs (Language Code Identifiers); refer to Microsoft's published + * list of LCID Language IDs for a list of USB LANGIDs." + * + * The scheme for Language IDs is that the least-significant-byte is "primary" ID and the + * most-significant-byte is a "sublanguage" ID within that. With this in mind, Microsoft's choice + * to sort their list of by most-significant-byte was a poor editorial choice. + */ +#define LANGID_AR 0x0001 +#define LANGID_AR 0x0001 +#define LANGID_AR_SA 0x0401 +#define LANGID_AR_SA 0x0401 +#define LANGID_QPS_PLOC 0x0501 +#define LANGID_QPS_PLOC 0x0501 +#define LANGID_AR_IQ 0x0801 +#define LANGID_AR_IQ 0x0801 +#define LANGID_AR_EG 0x0C01 +#define LANGID_AR_EG 0x0C01 +#define LANGID_AR_LY 0x1001 +#define LANGID_AR_LY 0x1001 +#define LANGID_AR_DZ 0x1401 +#define LANGID_AR_DZ 0x1401 +#define LANGID_AR_MA 0x1801 +#define LANGID_AR_MA 0x1801 +#define LANGID_AR_TN 0x1C01 +#define LANGID_AR_TN 0x1C01 +#define LANGID_AR_OM 0x2001 +#define LANGID_AR_OM 0x2001 +#define LANGID_AR_YE 0x2401 +#define LANGID_AR_YE 0x2401 +#define LANGID_AR_SY 0x2801 +#define LANGID_AR_SY 0x2801 +#define LANGID_AR_JO 0x2C01 +#define LANGID_AR_JO 0x2C01 +#define LANGID_AR_LB 0x3001 +#define LANGID_AR_LB 0x3001 +#define LANGID_AR_KW 0x3401 +#define LANGID_AR_KW 0x3401 +#define LANGID_AR_AE 0x3801 +#define LANGID_AR_AE 0x3801 +#define LANGID_AR_BH 0x3C01 +#define LANGID_AR_BH 0x3C01 +#define LANGID_AR_QA 0x4001 +#define LANGID_AR_QA 0x4001 +#define LANGID_AR_PLOC_SA 0x4401 +#define LANGID_AR_PLOC_SA 0x4401 +#define LANGID_AR_145 0x4801 +#define LANGID_AR_145 0x4801 +#define LANGID_BG 0x0002 +#define LANGID_BG 0x0002 +#define LANGID_BG_BG 0x0402 +#define LANGID_BG_BG 0x0402 +#define LANGID_CA 0x0003 +#define LANGID_CA 0x0003 +#define LANGID_CA_ES 0x0403 +#define LANGID_CA_ES 0x0403 +#define LANGID_CA_ES_VALENCIA 0x0803 +#define LANGID_CA_ES_VALENCIA 0x0803 +#define LANGID_ZH_HANS 0x0004 +#define LANGID_ZH_HANS 0x0004 +#define LANGID_ZH_TW 0x0404 +#define LANGID_ZH_TW 0x0404 +#define LANGID_ZH_CN 0x0804 +#define LANGID_ZH_CN 0x0804 +#define LANGID_ZH_HK 0x0C04 +#define LANGID_ZH_HK 0x0C04 +#define LANGID_ZH_SG 0x1004 +#define LANGID_ZH_SG 0x1004 +#define LANGID_ZH_MO 0x1404 +#define LANGID_ZH_MO 0x1404 +#define LANGID_ZH 0x7804 +#define LANGID_ZH 0x7804 +#define LANGID_ZH_HANT 0x7C04 +#define LANGID_ZH_HANT 0x7C04 +#define LANGID_CS 0x0005 +#define LANGID_CS 0x0005 +#define LANGID_CS_CZ 0x0405 +#define LANGID_CS_CZ 0x0405 +#define LANGID_DA 0x0006 +#define LANGID_DA 0x0006 +#define LANGID_DA_DK 0x0406 +#define LANGID_DA_DK 0x0406 +#define LANGID_DE 0x0007 +#define LANGID_DE 0x0007 +#define LANGID_DE_DE 0x0407 +#define LANGID_DE_DE 0x0407 +#define LANGID_DE_CH 0x0807 +#define LANGID_DE_CH 0x0807 +#define LANGID_DE_AT 0x0C07 +#define LANGID_DE_AT 0x0C07 +#define LANGID_DE_LU 0x1007 +#define LANGID_DE_LU 0x1007 +#define LANGID_DE_LI 0x1407 +#define LANGID_DE_LI 0x1407 +#define LANGID_EL 0x0008 +#define LANGID_EL 0x0008 +#define LANGID_EL_GR 0x0408 +#define LANGID_EL_GR 0x0408 +#define LANGID_EN 0x0009 +#define LANGID_EN 0x0009 +#define LANGID_EN_US 0x0409 +#define LANGID_EN_US 0x0409 +#define LANGID_EN_GB 0x0809 +#define LANGID_EN_GB 0x0809 +#define LANGID_EN_AU 0x0C09 +#define LANGID_EN_AU 0x0C09 +#define LANGID_EN_CA 0x1009 +#define LANGID_EN_CA 0x1009 +#define LANGID_EN_NZ 0x1409 +#define LANGID_EN_NZ 0x1409 +#define LANGID_EN_IE 0x1809 +#define LANGID_EN_IE 0x1809 +#define LANGID_EN_ZA 0x1C09 +#define LANGID_EN_ZA 0x1C09 +#define LANGID_EN_JM 0x2009 +#define LANGID_EN_JM 0x2009 +#define LANGID_EN_029 0x2409 +#define LANGID_EN_029 0x2409 +#define LANGID_EN_BZ 0x2809 +#define LANGID_EN_BZ 0x2809 +#define LANGID_EN_TT 0x2C09 +#define LANGID_EN_TT 0x2C09 +#define LANGID_EN_ZW 0x3009 +#define LANGID_EN_ZW 0x3009 +#define LANGID_EN_PH 0x3409 +#define LANGID_EN_PH 0x3409 +#define LANGID_EN_ID 0x3809 +#define LANGID_EN_ID 0x3809 +#define LANGID_EN_HK 0x3C09 +#define LANGID_EN_HK 0x3C09 +#define LANGID_EN_IN 0x4009 +#define LANGID_EN_IN 0x4009 +#define LANGID_EN_MY 0x4409 +#define LANGID_EN_MY 0x4409 +#define LANGID_EN_SG 0x4809 +#define LANGID_EN_SG 0x4809 +#define LANGID_EN_AE 0x4C09 +#define LANGID_EN_AE 0x4C09 +#define LANGID_EN_BH 0x5009 +#define LANGID_EN_BH 0x5009 +#define LANGID_EN_EG 0x5409 +#define LANGID_EN_EG 0x5409 +#define LANGID_EN_JO 0x5809 +#define LANGID_EN_JO 0x5809 +#define LANGID_EN_KW 0x5C09 +#define LANGID_EN_KW 0x5C09 +#define LANGID_EN_TR 0x6009 +#define LANGID_EN_TR 0x6009 +#define LANGID_EN_YE 0x6409 +#define LANGID_EN_YE 0x6409 +#define LANGID_ES 0x000A +#define LANGID_ES 0x000A +#define LANGID_ES_ES_TRADNL 0x040A +#define LANGID_ES_ES_TRADNL 0x040A +#define LANGID_ES_MX 0x080A +#define LANGID_ES_MX 0x080A +#define LANGID_ES_ES 0x0C0A +#define LANGID_ES_ES 0x0C0A +#define LANGID_ES_GT 0x100A +#define LANGID_ES_GT 0x100A +#define LANGID_ES_CR 0x140A +#define LANGID_ES_CR 0x140A +#define LANGID_ES_PA 0x180A +#define LANGID_ES_PA 0x180A +#define LANGID_ES_DO 0x1C0A +#define LANGID_ES_DO 0x1C0A +#define LANGID_ES_VE 0x200A +#define LANGID_ES_VE 0x200A +#define LANGID_ES_CO 0x240A +#define LANGID_ES_CO 0x240A +#define LANGID_ES_PE 0x280A +#define LANGID_ES_PE 0x280A +#define LANGID_ES_AR 0x2C0A +#define LANGID_ES_AR 0x2C0A +#define LANGID_ES_EC 0x300A +#define LANGID_ES_EC 0x300A +#define LANGID_ES_CL 0x340A +#define LANGID_ES_CL 0x340A +#define LANGID_ES_UY 0x380A +#define LANGID_ES_UY 0x380A +#define LANGID_ES_PY 0x3C0A +#define LANGID_ES_PY 0x3C0A +#define LANGID_ES_BO 0x400A +#define LANGID_ES_BO 0x400A +#define LANGID_ES_SV 0x440A +#define LANGID_ES_SV 0x440A +#define LANGID_ES_HN 0x480A +#define LANGID_ES_HN 0x480A +#define LANGID_ES_NI 0x4C0A +#define LANGID_ES_NI 0x4C0A +#define LANGID_ES_PR 0x500A +#define LANGID_ES_PR 0x500A +#define LANGID_ES_US 0x540A +#define LANGID_ES_US 0x540A +#define LANGID_ES_419 0x580A +#define LANGID_ES_419 0x580A +#define LANGID_ES_CU 0x5C0A +#define LANGID_ES_CU 0x5C0A +#define LANGID_FI 0x000B +#define LANGID_FI 0x000B +#define LANGID_FI_FI 0x040B +#define LANGID_FI_FI 0x040B +#define LANGID_FR 0x000C +#define LANGID_FR 0x000C +#define LANGID_FR_FR 0x040C +#define LANGID_FR_FR 0x040C +#define LANGID_FR_BE 0x080C +#define LANGID_FR_BE 0x080C +#define LANGID_FR_CA 0x0C0C +#define LANGID_FR_CA 0x0C0C +#define LANGID_FR_CH 0x100C +#define LANGID_FR_CH 0x100C +#define LANGID_FR_LU 0x140C +#define LANGID_FR_LU 0x140C +#define LANGID_FR_MC 0x180C +#define LANGID_FR_MC 0x180C +#define LANGID_FR_029 0x1C0C +#define LANGID_FR_029 0x1C0C +#define LANGID_FR_RE 0x200C +#define LANGID_FR_RE 0x200C +#define LANGID_FR_CD 0x240C +#define LANGID_FR_CD 0x240C +#define LANGID_FR_SN 0x280C +#define LANGID_FR_SN 0x280C +#define LANGID_FR_CM 0x2C0C +#define LANGID_FR_CM 0x2C0C +#define LANGID_FR_CI 0x300C +#define LANGID_FR_CI 0x300C +#define LANGID_FR_ML 0x340C +#define LANGID_FR_ML 0x340C +#define LANGID_FR_MA 0x380C +#define LANGID_FR_MA 0x380C +#define LANGID_FR_HT 0x3C0C +#define LANGID_FR_HT 0x3C0C +#define LANGID_FR_015 0xE40C +#define LANGID_FR_015 0xE40C +#define LANGID_HE 0x000D +#define LANGID_HE 0x000D +#define LANGID_HE_IL 0x040D +#define LANGID_HE_IL 0x040D +#define LANGID_HU 0x000E +#define LANGID_HU 0x000E +#define LANGID_HU_HU 0x040E +#define LANGID_HU_HU 0x040E +#define LANGID_IS 0x000F +#define LANGID_IS 0x000F +#define LANGID_IS_IS 0x040F +#define LANGID_IS_IS 0x040F +#define LANGID_IT 0x0010 +#define LANGID_IT 0x0010 +#define LANGID_IT_IT 0x0410 +#define LANGID_IT_IT 0x0410 +#define LANGID_IT_CH 0x0810 +#define LANGID_IT_CH 0x0810 +#define LANGID_JA 0x0011 +#define LANGID_JA 0x0011 +#define LANGID_JA_JP 0x0411 +#define LANGID_JA_JP 0x0411 +#define LANGID_JA_PLOC_JP 0x0811 +#define LANGID_JA_PLOC_JP 0x0811 +#define LANGID_KO 0x0012 +#define LANGID_KO 0x0012 +#define LANGID_KO_KR 0x0412 +#define LANGID_KO_KR 0x0412 +#define LANGID_NL 0x0013 +#define LANGID_NL 0x0013 +#define LANGID_NL_NL 0x0413 +#define LANGID_NL_NL 0x0413 +#define LANGID_NL_BE 0x0813 +#define LANGID_NL_BE 0x0813 +#define LANGID_NO 0x0014 +#define LANGID_NO 0x0014 +#define LANGID_NB_NO 0x0414 +#define LANGID_NB_NO 0x0414 +#define LANGID_NN_NO 0x0814 +#define LANGID_NN_NO 0x0814 +#define LANGID_NN 0x7814 +#define LANGID_NN 0x7814 +#define LANGID_NB 0x7C14 +#define LANGID_NB 0x7C14 +#define LANGID_PL 0x0015 +#define LANGID_PL 0x0015 +#define LANGID_PL_PL 0x0415 +#define LANGID_PL_PL 0x0415 +#define LANGID_PT 0x0016 +#define LANGID_PT 0x0016 +#define LANGID_PT_BR 0x0416 +#define LANGID_PT_BR 0x0416 +#define LANGID_PT_PT 0x0816 +#define LANGID_PT_PT 0x0816 +#define LANGID_RM 0x0017 +#define LANGID_RM 0x0017 +#define LANGID_RM_CH 0x0417 +#define LANGID_RM_CH 0x0417 +#define LANGID_RO 0x0018 +#define LANGID_RO 0x0018 +#define LANGID_RO_RO 0x0418 +#define LANGID_RO_RO 0x0418 +#define LANGID_RO_MD 0x0818 +#define LANGID_RO_MD 0x0818 +#define LANGID_RU 0x0019 +#define LANGID_RU 0x0019 +#define LANGID_RU_RU 0x0419 +#define LANGID_RU_RU 0x0419 +#define LANGID_RU_MD 0x0819 +#define LANGID_RU_MD 0x0819 +#define LANGID_HR 0x001A +#define LANGID_HR 0x001A +#define LANGID_HR_HR 0x041A +#define LANGID_HR_HR 0x041A +#define LANGID_SR_LATN_CS 0x081A +#define LANGID_SR_LATN_CS 0x081A +#define LANGID_SR_CYRL_CS 0x0C1A +#define LANGID_SR_CYRL_CS 0x0C1A +#define LANGID_HR_BA 0x101A +#define LANGID_HR_BA 0x101A +#define LANGID_BS_LATN_BA 0x141A +#define LANGID_BS_LATN_BA 0x141A +#define LANGID_SR_LATN_BA 0x181A +#define LANGID_SR_LATN_BA 0x181A +#define LANGID_SR_CYRL_BA 0x1C1A +#define LANGID_SR_CYRL_BA 0x1C1A +#define LANGID_BS_CYRL_BA 0x201A +#define LANGID_BS_CYRL_BA 0x201A +#define LANGID_SR_LATN_RS 0x241A +#define LANGID_SR_LATN_RS 0x241A +#define LANGID_SR_CYRL_RS 0x281A +#define LANGID_SR_CYRL_RS 0x281A +#define LANGID_SR_LATN_ME 0x2C1A +#define LANGID_SR_LATN_ME 0x2C1A +#define LANGID_SR_CYRL_ME 0x301A +#define LANGID_SR_CYRL_ME 0x301A +#define LANGID_BS_CYRL 0x641A +#define LANGID_BS_CYRL 0x641A +#define LANGID_BS_LATN 0x681A +#define LANGID_BS_LATN 0x681A +#define LANGID_SR_CYRL 0x6C1A +#define LANGID_SR_CYRL 0x6C1A +#define LANGID_SR_LATN 0x701A +#define LANGID_SR_LATN 0x701A +#define LANGID_BS 0x781A +#define LANGID_BS 0x781A +#define LANGID_SR 0x7C1A +#define LANGID_SR 0x7C1A +#define LANGID_SK 0x001B +#define LANGID_SK 0x001B +#define LANGID_SK_SK 0x041B +#define LANGID_SK_SK 0x041B +#define LANGID_SQ 0x001C +#define LANGID_SQ 0x001C +#define LANGID_SQ_AL 0x041C +#define LANGID_SQ_AL 0x041C +#define LANGID_SV 0x001D +#define LANGID_SV 0x001D +#define LANGID_SV_SE 0x041D +#define LANGID_SV_SE 0x041D +#define LANGID_SV_FI 0x081D +#define LANGID_SV_FI 0x081D +#define LANGID_TH 0x001E +#define LANGID_TH 0x001E +#define LANGID_TH_TH 0x041E +#define LANGID_TH_TH 0x041E +#define LANGID_TR 0x001F +#define LANGID_TR 0x001F +#define LANGID_TR_TR 0x041F +#define LANGID_TR_TR 0x041F +#define LANGID_UR 0x0020 +#define LANGID_UR 0x0020 +#define LANGID_UR_PK 0x0420 +#define LANGID_UR_PK 0x0420 +#define LANGID_UR_IN 0x0820 +#define LANGID_UR_IN 0x0820 +#define LANGID_ID 0x0021 +#define LANGID_ID 0x0021 +#define LANGID_ID_ID 0x0421 +#define LANGID_ID_ID 0x0421 +#define LANGID_UK 0x0022 +#define LANGID_UK 0x0022 +#define LANGID_UK_UA 0x0422 +#define LANGID_UK_UA 0x0422 +#define LANGID_BE 0x0023 +#define LANGID_BE 0x0023 +#define LANGID_BE_BY 0x0423 +#define LANGID_BE_BY 0x0423 +#define LANGID_SL 0x0024 +#define LANGID_SL 0x0024 +#define LANGID_SL_SI 0x0424 +#define LANGID_SL_SI 0x0424 +#define LANGID_ET 0x0025 +#define LANGID_ET 0x0025 +#define LANGID_ET_EE 0x0425 +#define LANGID_ET_EE 0x0425 +#define LANGID_LV 0x0026 +#define LANGID_LV 0x0026 +#define LANGID_LV_LV 0x0426 +#define LANGID_LV_LV 0x0426 +#define LANGID_LT 0x0027 +#define LANGID_LT 0x0027 +#define LANGID_LT_LT 0x0427 +#define LANGID_LT_LT 0x0427 +#define LANGID_TG 0x0028 +#define LANGID_TG 0x0028 +#define LANGID_TG_CYRL_TJ 0x0428 +#define LANGID_TG_CYRL_TJ 0x0428 +#define LANGID_TG_CYRL 0x7C28 +#define LANGID_TG_CYRL 0x7C28 +#define LANGID_FA 0x0029 +#define LANGID_FA 0x0029 +#define LANGID_FA_IR 0x0429 +#define LANGID_FA_IR 0x0429 +#define LANGID_VI 0x002A +#define LANGID_VI 0x002A +#define LANGID_VI_VN 0x042A +#define LANGID_VI_VN 0x042A +#define LANGID_HY 0x002B +#define LANGID_HY 0x002B +#define LANGID_HY_AM 0x042B +#define LANGID_HY_AM 0x042B +#define LANGID_AZ 0x002C +#define LANGID_AZ 0x002C +#define LANGID_AZ_LATN_AZ 0x042C +#define LANGID_AZ_LATN_AZ 0x042C +#define LANGID_AZ_CYRL_AZ 0x082C +#define LANGID_AZ_CYRL_AZ 0x082C +#define LANGID_AZ_CYRL 0x742C +#define LANGID_AZ_CYRL 0x742C +#define LANGID_AZ_LATN 0x782C +#define LANGID_AZ_LATN 0x782C +#define LANGID_EU 0x002D +#define LANGID_EU 0x002D +#define LANGID_EU_ES 0x042D +#define LANGID_EU_ES 0x042D +#define LANGID_HSB 0x002E +#define LANGID_HSB 0x002E +#define LANGID_HSB_DE 0x042E +#define LANGID_HSB_DE 0x042E +#define LANGID_DSB_DE 0x082E +#define LANGID_DSB_DE 0x082E +#define LANGID_DSB 0x7C2E +#define LANGID_DSB 0x7C2E +#define LANGID_MK 0x002F +#define LANGID_MK 0x002F +#define LANGID_MK_MK 0x042F +#define LANGID_MK_MK 0x042F +#define LANGID_ST 0x0030 +#define LANGID_ST 0x0030 +#define LANGID_ST_ZA 0x0430 +#define LANGID_ST_ZA 0x0430 +#define LANGID_TS 0x0031 +#define LANGID_TS 0x0031 +#define LANGID_TS_ZA 0x0431 +#define LANGID_TS_ZA 0x0431 +#define LANGID_TN 0x0032 +#define LANGID_TN 0x0032 +#define LANGID_TN_ZA 0x0432 +#define LANGID_TN_ZA 0x0432 +#define LANGID_TN_BW 0x0832 +#define LANGID_TN_BW 0x0832 +#define LANGID_VE 0x0033 +#define LANGID_VE 0x0033 +#define LANGID_VE_ZA 0x0433 +#define LANGID_VE_ZA 0x0433 +#define LANGID_XH 0x0034 +#define LANGID_XH 0x0034 +#define LANGID_XH_ZA 0x0434 +#define LANGID_XH_ZA 0x0434 +#define LANGID_ZU 0x0035 +#define LANGID_ZU 0x0035 +#define LANGID_ZU_ZA 0x0435 +#define LANGID_ZU_ZA 0x0435 +#define LANGID_AF 0x0036 +#define LANGID_AF 0x0036 +#define LANGID_AF_ZA 0x0436 +#define LANGID_AF_ZA 0x0436 +#define LANGID_KA 0x0037 +#define LANGID_KA 0x0037 +#define LANGID_KA_GE 0x0437 +#define LANGID_KA_GE 0x0437 +#define LANGID_FO 0x0038 +#define LANGID_FO 0x0038 +#define LANGID_FO_FO 0x0438 +#define LANGID_FO_FO 0x0438 +#define LANGID_HI 0x0039 +#define LANGID_HI 0x0039 +#define LANGID_HI_IN 0x0439 +#define LANGID_HI_IN 0x0439 +#define LANGID_MT 0x003A +#define LANGID_MT 0x003A +#define LANGID_MT_MT 0x043A +#define LANGID_MT_MT 0x043A +#define LANGID_SE 0x003B +#define LANGID_SE 0x003B +#define LANGID_SE_NO 0x043B +#define LANGID_SE_NO 0x043B +#define LANGID_SE_SE 0x083B +#define LANGID_SE_SE 0x083B +#define LANGID_SE_FI 0x0C3B +#define LANGID_SE_FI 0x0C3B +#define LANGID_SMJ_NO 0x103B +#define LANGID_SMJ_NO 0x103B +#define LANGID_SMJ_SE 0x143B +#define LANGID_SMJ_SE 0x143B +#define LANGID_SMA_NO 0x183B +#define LANGID_SMA_NO 0x183B +#define LANGID_SMA_SE 0x1C3B +#define LANGID_SMA_SE 0x1C3B +#define LANGID_SMS_FI 0x203B +#define LANGID_SMS_FI 0x203B +#define LANGID_SMN_FI 0x243B +#define LANGID_SMN_FI 0x243B +#define LANGID_SMN 0x703B +#define LANGID_SMN 0x703B +#define LANGID_SMS 0x743B +#define LANGID_SMS 0x743B +#define LANGID_SMA 0x783B +#define LANGID_SMA 0x783B +#define LANGID_SMJ 0x7C3B +#define LANGID_SMJ 0x7C3B +#define LANGID_GA 0x003C +#define LANGID_GA 0x003C +#define LANGID_GA_IE 0x083C +#define LANGID_GA_IE 0x083C +#define LANGID_YI 0x003D +#define LANGID_YI 0x003D +#define LANGID_YI_001 0x043D +#define LANGID_YI_001 0x043D +#define LANGID_MS 0x003E +#define LANGID_MS 0x003E +#define LANGID_MS_MY 0x043E +#define LANGID_MS_MY 0x043E +#define LANGID_MS_BN 0x083E +#define LANGID_MS_BN 0x083E +#define LANGID_KK 0x003F +#define LANGID_KK 0x003F +#define LANGID_KK_KZ 0x043F +#define LANGID_KK_KZ 0x043F +#define LANGID_KK_LATN_KZ 0x083F +#define LANGID_KK_LATN_KZ 0x083F +#define LANGID_KK_CYRL 0x783F +#define LANGID_KK_CYRL 0x783F +#define LANGID_KK_LATN 0x7C3F +#define LANGID_KK_LATN 0x7C3F +#define LANGID_KY 0x0040 +#define LANGID_KY 0x0040 +#define LANGID_KY_KG 0x0440 +#define LANGID_KY_KG 0x0440 +#define LANGID_SW 0x0041 +#define LANGID_SW 0x0041 +#define LANGID_SW_KE 0x0441 +#define LANGID_SW_KE 0x0441 +#define LANGID_TK 0x0042 +#define LANGID_TK 0x0042 +#define LANGID_TK_TM 0x0442 +#define LANGID_TK_TM 0x0442 +#define LANGID_UZ 0x0043 +#define LANGID_UZ 0x0043 +#define LANGID_UZ_LATN_UZ 0x0443 +#define LANGID_UZ_LATN_UZ 0x0443 +#define LANGID_UZ_CYRL_UZ 0x0843 +#define LANGID_UZ_CYRL_UZ 0x0843 +#define LANGID_UZ_CYRL 0x7843 +#define LANGID_UZ_CYRL 0x7843 +#define LANGID_UZ_LATN 0x7C43 +#define LANGID_UZ_LATN 0x7C43 +#define LANGID_TT 0x0044 +#define LANGID_TT 0x0044 +#define LANGID_TT_RU 0x0444 +#define LANGID_TT_RU 0x0444 +#define LANGID_BN 0x0045 +#define LANGID_BN 0x0045 +#define LANGID_BN_IN 0x0445 +#define LANGID_BN_IN 0x0445 +#define LANGID_BN_BD 0x0845 +#define LANGID_BN_BD 0x0845 +#define LANGID_PA 0x0046 +#define LANGID_PA 0x0046 +#define LANGID_PA_IN 0x0446 +#define LANGID_PA_IN 0x0446 +#define LANGID_PA_ARAB_PK 0x0846 +#define LANGID_PA_ARAB_PK 0x0846 +#define LANGID_PA_ARAB 0x7C46 +#define LANGID_PA_ARAB 0x7C46 +#define LANGID_GU 0x0047 +#define LANGID_GU 0x0047 +#define LANGID_GU_IN 0x0447 +#define LANGID_GU_IN 0x0447 +#define LANGID_OR 0x0048 +#define LANGID_OR 0x0048 +#define LANGID_OR_IN 0x0448 +#define LANGID_OR_IN 0x0448 +#define LANGID_TA 0x0049 +#define LANGID_TA 0x0049 +#define LANGID_TA_IN 0x0449 +#define LANGID_TA_IN 0x0449 +#define LANGID_TA_LK 0x0849 +#define LANGID_TA_LK 0x0849 +#define LANGID_TE 0x004A +#define LANGID_TE 0x004A +#define LANGID_TE_IN 0x044A +#define LANGID_TE_IN 0x044A +#define LANGID_KN 0x004B +#define LANGID_KN 0x004B +#define LANGID_KN_IN 0x044B +#define LANGID_KN_IN 0x044B +#define LANGID_ML 0x004C +#define LANGID_ML 0x004C +#define LANGID_ML_IN 0x044C +#define LANGID_ML_IN 0x044C +#define LANGID_AS 0x004D +#define LANGID_AS 0x004D +#define LANGID_AS_IN 0x044D +#define LANGID_AS_IN 0x044D +#define LANGID_MR 0x004E +#define LANGID_MR 0x004E +#define LANGID_MR_IN 0x044E +#define LANGID_MR_IN 0x044E +#define LANGID_SA 0x004F +#define LANGID_SA 0x004F +#define LANGID_SA_IN 0x044F +#define LANGID_SA_IN 0x044F +#define LANGID_MN 0x0050 +#define LANGID_MN 0x0050 +#define LANGID_MN_MN 0x0450 +#define LANGID_MN_MN 0x0450 +#define LANGID_MN_MONG_CN 0x0850 +#define LANGID_MN_MONG_CN 0x0850 +#define LANGID_MN_MONG_MN 0x0C50 +#define LANGID_MN_MONG_MN 0x0C50 +#define LANGID_MN_CYRL 0x7850 +#define LANGID_MN_CYRL 0x7850 +#define LANGID_MN_MONG 0x7C50 +#define LANGID_MN_MONG 0x7C50 +#define LANGID_BO 0x0051 +#define LANGID_BO 0x0051 +#define LANGID_BO_CN 0x0451 +#define LANGID_BO_CN 0x0451 +#define LANGID_BO_BT 0x0851 +#define LANGID_BO_BT 0x0851 +#define LANGID_DZ_BT 0x0C51 +#define LANGID_DZ_BT 0x0C51 +#define LANGID_CY 0x0052 +#define LANGID_CY 0x0052 +#define LANGID_CY_GB 0x0452 +#define LANGID_CY_GB 0x0452 +#define LANGID_KM 0x0053 +#define LANGID_KM 0x0053 +#define LANGID_KM_KH 0x0453 +#define LANGID_KM_KH 0x0453 +#define LANGID_LO 0x0054 +#define LANGID_LO 0x0054 +#define LANGID_LO_LA 0x0454 +#define LANGID_LO_LA 0x0454 +#define LANGID_MY 0x0055 +#define LANGID_MY 0x0055 +#define LANGID_MY_MM 0x0455 +#define LANGID_MY_MM 0x0455 +#define LANGID_GL 0x0056 +#define LANGID_GL 0x0056 +#define LANGID_GL_ES 0x0456 +#define LANGID_GL_ES 0x0456 +#define LANGID_KOK 0x0057 +#define LANGID_KOK 0x0057 +#define LANGID_KOK_IN 0x0457 +#define LANGID_KOK_IN 0x0457 +#define LANGID_MNI 0x0058 +#define LANGID_MNI 0x0058 +#define LANGID_MNI_IN 0x0458 +#define LANGID_MNI_IN 0x0458 +#define LANGID_SD 0x0059 +#define LANGID_SD 0x0059 +#define LANGID_SD_DEVA_IN 0x0459 +#define LANGID_SD_DEVA_IN 0x0459 +#define LANGID_SD_ARAB_PK 0x0859 +#define LANGID_SD_ARAB_PK 0x0859 +#define LANGID_SD_ARAB 0x7C59 +#define LANGID_SD_ARAB 0x7C59 +#define LANGID_SYR 0x005A +#define LANGID_SYR 0x005A +#define LANGID_SYR_SY 0x045A +#define LANGID_SYR_SY 0x045A +#define LANGID_SI 0x005B +#define LANGID_SI 0x005B +#define LANGID_SI_LK 0x045B +#define LANGID_SI_LK 0x045B +#define LANGID_CHR 0x005C +#define LANGID_CHR 0x005C +#define LANGID_CHR_CHER_US 0x045C +#define LANGID_CHR_CHER_US 0x045C +#define LANGID_CHR_CHER 0x7C5C +#define LANGID_CHR_CHER 0x7C5C +#define LANGID_IU 0x005D +#define LANGID_IU 0x005D +#define LANGID_IU_CANS_CA 0x045D +#define LANGID_IU_CANS_CA 0x045D +#define LANGID_IU_LATN_CA 0x085D +#define LANGID_IU_LATN_CA 0x085D +#define LANGID_IU_CANS 0x785D +#define LANGID_IU_CANS 0x785D +#define LANGID_IU_LATN 0x7C5D +#define LANGID_IU_LATN 0x7C5D +#define LANGID_AM 0x005E +#define LANGID_AM 0x005E +#define LANGID_AM_ET 0x045E +#define LANGID_AM_ET 0x045E +#define LANGID_TZM 0x005F +#define LANGID_TZM 0x005F +#define LANGID_TZM_ARAB_MA 0x045F +#define LANGID_TZM_ARAB_MA 0x045F +#define LANGID_TZM_LATN_DZ 0x085F +#define LANGID_TZM_LATN_DZ 0x085F +#define LANGID_TMZ_MA 0x0C5F +#define LANGID_TMZ_MA 0x0C5F +#define LANGID_TZM_TFNG_MA 0x105F +#define LANGID_TZM_TFNG_MA 0x105F +#define LANGID_TZM_TFNG 0x785F +#define LANGID_TZM_TFNG 0x785F +#define LANGID_TZM_LATN 0x7C5F +#define LANGID_TZM_LATN 0x7C5F +#define LANGID_KS 0x0060 +#define LANGID_KS 0x0060 +#define LANGID_KS_ARAB 0x0460 +#define LANGID_KS_ARAB 0x0460 +#define LANGID_KS_DEVA_IN 0x0860 +#define LANGID_KS_DEVA_IN 0x0860 +#define LANGID_NE 0x0061 +#define LANGID_NE 0x0061 +#define LANGID_NE_NP 0x0461 +#define LANGID_NE_NP 0x0461 +#define LANGID_NE_IN 0x0861 +#define LANGID_NE_IN 0x0861 +#define LANGID_FY 0x0062 +#define LANGID_FY 0x0062 +#define LANGID_FY_NL 0x0462 +#define LANGID_FY_NL 0x0462 +#define LANGID_PS 0x0063 +#define LANGID_PS 0x0063 +#define LANGID_PS_AF 0x0463 +#define LANGID_PS_AF 0x0463 +#define LANGID_FIL 0x0064 +#define LANGID_FIL 0x0064 +#define LANGID_FIL_PH 0x0464 +#define LANGID_FIL_PH 0x0464 +#define LANGID_DV 0x0065 +#define LANGID_DV 0x0065 +#define LANGID_DV_MV 0x0465 +#define LANGID_DV_MV 0x0465 +#define LANGID_BIN 0x0066 +#define LANGID_BIN 0x0066 +#define LANGID_BIN_NG 0x0466 +#define LANGID_BIN_NG 0x0466 +#define LANGID_FF 0x0067 +#define LANGID_FF 0x0067 +#define LANGID_FF_NG 0x0467 +#define LANGID_FF_NG 0x0467 +#define LANGID_FF_LATN_SN 0x0867 +#define LANGID_FF_LATN_SN 0x0867 +#define LANGID_FF_LATN 0x7C67 +#define LANGID_FF_LATN 0x7C67 +#define LANGID_HA 0x0068 +#define LANGID_HA 0x0068 +#define LANGID_HA_LATN_NG 0x0468 +#define LANGID_HA_LATN_NG 0x0468 +#define LANGID_HA_LATN 0x7C68 +#define LANGID_HA_LATN 0x7C68 +#define LANGID_IBB 0x0069 +#define LANGID_IBB 0x0069 +#define LANGID_IBB_NG 0x0469 +#define LANGID_IBB_NG 0x0469 +#define LANGID_YO 0x006A +#define LANGID_YO 0x006A +#define LANGID_YO_NG 0x046A +#define LANGID_YO_NG 0x046A +#define LANGID_QUZ 0x006B +#define LANGID_QUZ 0x006B +#define LANGID_QUZ_BO 0x046B +#define LANGID_QUZ_BO 0x046B +#define LANGID_QUZ_EC 0x086B +#define LANGID_QUZ_EC 0x086B +#define LANGID_NSO 0x006C +#define LANGID_NSO 0x006C +#define LANGID_NSO_ZA 0x046C +#define LANGID_NSO_ZA 0x046C +#define LANGID_BA 0x006D +#define LANGID_BA 0x006D +#define LANGID_BA_RU 0x046D +#define LANGID_BA_RU 0x046D +#define LANGID_LB 0x006E +#define LANGID_LB 0x006E +#define LANGID_LB_LU 0x046E +#define LANGID_LB_LU 0x046E +#define LANGID_KL 0x006F +#define LANGID_KL 0x006F +#define LANGID_KL_GL 0x046F +#define LANGID_KL_GL 0x046F +#define LANGID_IG 0x0070 +#define LANGID_IG 0x0070 +#define LANGID_IG_NG 0x0470 +#define LANGID_IG_NG 0x0470 +#define LANGID_KR 0x0071 +#define LANGID_KR 0x0071 +#define LANGID_KR_LATN_NG 0x0471 +#define LANGID_KR_LATN_NG 0x0471 +#define LANGID_OM 0x0072 +#define LANGID_OM 0x0072 +#define LANGID_OM_ET 0x0472 +#define LANGID_OM_ET 0x0472 +#define LANGID_TI 0x0073 +#define LANGID_TI 0x0073 +#define LANGID_TI_ET 0x0473 +#define LANGID_TI_ET 0x0473 +#define LANGID_TI_ER 0x0873 +#define LANGID_TI_ER 0x0873 +#define LANGID_GN 0x0074 +#define LANGID_GN 0x0074 +#define LANGID_GN_PY 0x0474 +#define LANGID_GN_PY 0x0474 +#define LANGID_HAW 0x0075 +#define LANGID_HAW 0x0075 +#define LANGID_HAW_US 0x0475 +#define LANGID_HAW_US 0x0475 +#define LANGID_LA 0x0076 +#define LANGID_LA 0x0076 +#define LANGID_LA_VA 0x0476 +#define LANGID_LA_VA 0x0476 +#define LANGID_SO 0x0077 +#define LANGID_SO 0x0077 +#define LANGID_SO_SO 0x0477 +#define LANGID_SO_SO 0x0477 +#define LANGID_II 0x0078 +#define LANGID_II 0x0078 +#define LANGID_II_CN 0x0478 +#define LANGID_II_CN 0x0478 +#define LANGID_PAP 0x0079 +#define LANGID_PAP 0x0079 +#define LANGID_PAP_029 0x0479 +#define LANGID_PAP_029 0x0479 +#define LANGID_ARN 0x007A +#define LANGID_ARN 0x007A +#define LANGID_ARN_CL 0x047A +#define LANGID_ARN_CL 0x047A +#define LANGID_MOH 0x007C +#define LANGID_MOH 0x007C +#define LANGID_MOH_CA 0x047C +#define LANGID_MOH_CA 0x047C +#define LANGID_BR 0x007E +#define LANGID_BR 0x007E +#define LANGID_BR_FR 0x047E +#define LANGID_BR_FR 0x047E +#define LANGID_UG 0x0080 +#define LANGID_UG 0x0080 +#define LANGID_UG_CN 0x0480 +#define LANGID_UG_CN 0x0480 +#define LANGID_MI 0x0081 +#define LANGID_MI 0x0081 +#define LANGID_MI_NZ 0x0481 +#define LANGID_MI_NZ 0x0481 +#define LANGID_OC 0x0082 +#define LANGID_OC 0x0082 +#define LANGID_OC_FR 0x0482 +#define LANGID_OC_FR 0x0482 +#define LANGID_CO 0x0083 +#define LANGID_CO 0x0083 +#define LANGID_CO_FR 0x0483 +#define LANGID_CO_FR 0x0483 +#define LANGID_GSW 0x0084 +#define LANGID_GSW 0x0084 +#define LANGID_GSW_FR 0x0484 +#define LANGID_GSW_FR 0x0484 +#define LANGID_SAH 0x0085 +#define LANGID_SAH 0x0085 +#define LANGID_SAH_RU 0x0485 +#define LANGID_SAH_RU 0x0485 +#define LANGID_QUT 0x0086 +#define LANGID_QUT 0x0086 +#define LANGID_QUT_GT 0x0486 +#define LANGID_QUT_GT 0x0486 +#define LANGID_RW 0x0087 +#define LANGID_RW 0x0087 +#define LANGID_RW_RW 0x0487 +#define LANGID_RW_RW 0x0487 +#define LANGID_WO 0x0088 +#define LANGID_WO 0x0088 +#define LANGID_WO_SN 0x0488 +#define LANGID_WO_SN 0x0488 +#define LANGID_PRS 0x008C +#define LANGID_PRS 0x008C +#define LANGID_PRS_AF 0x048C +#define LANGID_PRS_AF 0x048C +#define LANGID_PLT_MG 0x048D +#define LANGID_PLT_MG 0x048D +#define LANGID_ZH_YUE_HK 0x048E +#define LANGID_ZH_YUE_HK 0x048E +#define LANGID_TDD_TALE_CN 0x048F +#define LANGID_TDD_TALE_CN 0x048F +#define LANGID_KHB_TALU_CN 0x0490 +#define LANGID_KHB_TALU_CN 0x0490 +#define LANGID_GD 0x0091 +#define LANGID_GD 0x0091 +#define LANGID_GD_GB 0x0491 +#define LANGID_GD_GB 0x0491 +#define LANGID_KU 0x0092 +#define LANGID_KU 0x0092 +#define LANGID_KU_ARAB_IQ 0x0492 +#define LANGID_KU_ARAB_IQ 0x0492 +#define LANGID_KU_ARAB 0x7C92 +#define LANGID_KU_ARAB 0x7C92 +#define LANGID_QUC 0x0093 +#define LANGID_QUC 0x0093 +#define LANGID_QUC_CO 0x0493 +#define LANGID_QUC_CO 0x0493 +#define LANGID_QPS_PLOCA 0x05FE +#define LANGID_QPS_PLOCA 0x05FE +#define LANGID_QPS_PLOCM 0x09FF +#define LANGID_QPS_PLOCM 0x09FF + +/* USB 2.0 §9.6.6 "Endpoint", field bEndpointAddress, bit 7 */ +#define TUD_ENDPOINT_OUT 0x00 +#define TUD_ENDPOINT_IN 0x80 + +#define TU_UTF16(str) u ## str + +#endif /* _USB_HELPERS_H_ */ diff --git a/libusb/tusb_helpers.h.gen b/libusb/tusb_helpers.h.gen new file mode 100755 index 0000000..a348b16 --- /dev/null +++ b/libusb/tusb_helpers.h.gen @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# -*- Mode: C -*- +set -e +exec >"${0%.gen}" +cat <<'EOT' +/* tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB + * + * Copyright (c) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _USB_HELPERS_H_ +#define _USB_HELPERS_H_ + +/* USB 2.0 §9.6.7 "String" says "The list of currently defined USB LANGIDs can be found at + * http://www.usb.org/developers/docs.html.", but that page 404s. + * + * Once upon a time the USB-IF (usb.org) published a "Language Identifiers (LANGIDs)" version 1.0, + * dated 2000-03-29. There is no longer any mention of this on usb.org, but I found a copy at + * http://www.baiheee.com/Documents/090518/090518112619/USB_LANGIDs.pdf + * + * So how does the USB-IF defined LANGIDs these days? + * + * https://www.usb.org/deprecated-links-and-tools says "To get the latest LANGID definitions go to + * https://docs.microsoft.com/en-us/windows/desktop/intl/language-identifier-constants-and-strings. This + * page will change as new LANGIDs are added." That page has no list of LANGIDs, but says "For the + * predefined primary language identifiers with their valid sublanguage identifiers, see + * [\[MS-LCID\]: Windows Language Code Identifier (LCID) + * Reference](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-565326e84c37f)." + * That page at the time of this writing as a PDF marked as version 16.0, dated 2024-04-24: + * https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf + * [MS-LCID] defines an LCID as a 32-bit value consisting of a 16-bit a "Language ID", a 4-bit "Sort + * ID", and 12 reserved bits. + * + * That is to say: The USB-IF has said in essence "USB LANGIDs are defined to be the 'Language ID' + * portion of Microsoft Windows LCIDs (Language Code Identifiers); refer to Microsoft's published + * list of LCID Language IDs for a list of USB LANGIDs." + * + * The scheme for Language IDs is that the least-significant-byte is "primary" ID and the + * most-significant-byte is a "sublanguage" ID within that. With this in mind, Microsoft's choice + * to sort their list of by most-significant-byte was a poor editorial choice. + */ +EOT +[ -d 3rd-party ] || mkdir 3rd-party +[ -f 3rd-party/MS-LCID.pdf ] || wget -O 3rd-party/MS-LCID.pdf 'https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf' +[ -f 3rd-party/MS-LCID.txt ] || pdftotext -layout 3rd-party/MS-LCID.pdf +<3rd-party/MS-LCID.txt \ + grep -E '^\s*0x[0-9A-F]{4}\s+[a-z]' | sed 's/,.*//' | grep -v reserved | # find the lines we're interested in + sed -E 's/^\s*0x(..)(..)\s+(\S.*)/\2 \1 \3/p' | tr '[:lower:]-' '[:upper:]_' | # format them as 'PRIhex SUBhex UPPER_STR' + sort | + sed -E 's/(..) (..) (.*)/#define LANGID_\3 0x\2\1/' | # format them as '#define LANGID_UPPER_STR 0xSUBPRI' + column --table --output-separator=' ' +cat <<'EOT' + +/* USB 2.0 §9.6.6 "Endpoint", field bEndpointAddress, bit 7 */ +#define TUD_ENDPOINT_OUT 0x00 +#define TUD_ENDPOINT_IN 0x80 + +#define TU_UTF16(str) u ## str + +#endif /* _USB_HELPERS_H_ */ +EOT diff --git a/libusb/usb_common.c b/libusb/usb_common.c new file mode 100644 index 0000000..f10ace8 --- /dev/null +++ b/libusb/usb_common.c @@ -0,0 +1,189 @@ +/* usb_common.c - Common framework for implementing multiple USB devices at once + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#include <stdint.h> /* for uint{n}_t types */ +#include <string.h> /* memcpy(newlib) */ +#include <assert.h> /* for assert(newlib) */ +#include <stdlib.h> /* for malloc(pico_malloc), realloc(pico_malloc), reallocarray(pico_malloc) */ +#include "bsp/board_api.h" /* for board_init(), board_init_after_usb(), board_usb_get_serial(TinyUSB) */ +#include "tusb.h" /* for various tusb_*_t types */ + +#include "tusb_helpers.h" /* for LANGID_*, TU_UTF16() */ +#include "usb_common.h" + +/* Strings ********************************************************************/ + +/** + * Return a pointer to the USB "String Descriptor" (see USB 2.0 §9.6.7 + * "String"). + */ +uint16_t const *tud_descriptor_string_cb(uint8_t strid, uint16_t langid) { + static struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bString[(0xFF-2)/2]; + } desc; + TU_VERIFY_STATIC(sizeof desc == (0xFF/2)*2, "incorrect size"); + + static uint16_t const langids[] = { + LANGID_EN_US, + }; + + size_t bytelen = 0; + if (strid == 0) { + memcpy(desc.bString, langids, sizeof langids); + bytelen = sizeof langids; + } else { +#define CONST_STR(str) bytelen = ((sizeof (str))-1); memcpy(desc.bString, (str), ((sizeof (str))-1)); + switch (langid) { + case LANGID_EN_US: + switch (strid) { + case STRID_MANUF: CONST_STR(TU_UTF16("Umorpha Systems")); break; + case STRID_PRODUCT: CONST_STR(TU_UTF16("SBC-Harness Keyboard")); break; + case STRID_CFG: CONST_STR(TU_UTF16("Standard Configuration")); break; + case STRID_KBD_IFC: CONST_STR(TU_UTF16("Keyboard Interface")); break; + case STRID_SERIAL: +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Waddress-of-packed-member" + bytelen = 2 * board_usb_get_serial(desc.bString, TU_ARRAY_SIZE(desc.bString)); +#pragma GCC diagnostic pop + break; + default: + printf("GET STRING: unknown string id=%"PRIu8, strid); + return NULL; + } + break; + default: + printf("GET STRING: unknown LANGID=%"PRIx16, langid); + return NULL; + } + } + assert(bytelen <= sizeof desc.bString); + desc.bLength = bytelen + 2; + desc.bDescriptorType = TUSB_DESC_STRING; + return (uint16_t *)&desc; +} + +/* Globals ********************************************************************/ + +uint8_t cfgnum_std = 0; + +void usb_common_earlyinit(void) { + if (cfgnum_std) + return; + cfgnum_std = usb_add_config( + STRID_CFG, /* iConfiguration ; Index of string descriptor describing this configuration */ + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, /* bmAttributes ; Bitmap of flags (self-powered and remote-wakeup are the only flags defined in USB 2.0) */ + 100); /* bMaxPower (in mA) ; Maximum power consumption of the device when in this configuration */ +} + +void usb_common_lateinit(void) { + board_init(); + tud_init(BOARD_TUD_RHPORT); + if (board_init_after_tusb) + board_init_after_tusb(); +} + +COROUTINE usb_common_cr(void *_arg) { + (void) _arg; + cr_begin(); + + for (;;) { + tud_task(); + cr_yield(); + } + + cr_end(); +} + +/* Main utilities *************************************************************/ + +static uint8_t configc = 0; +static uint8_t **configv = NULL; + +uint8_t usb_add_config(uint8_t iConfiguration, uint8_t bmAttributes, uint8_t bMaxPower_mA) { + uint8_t *desc; + + configv = reallocarray(configv, ++configc, sizeof configv[0]); + desc = configv[configc-1] = malloc(TUD_CONFIG_DESC_LEN); + + memcpy(desc, (uint8_t[]){ + /* USB configuration descriptor header (USB 2.0 §9.6.4 "Configuration") */ + TUD_CONFIG_DESCRIPTOR( + configc, /* bConfigurationValue */ + 0, /* bNumInterfaces (will be incremented by usb_add_interface() */ + iConfiguration, /* iConfiguration */ + TUD_CONFIG_DESC_LEN, /* wTotalLength (will be incremented by usb_add_interface() */ + bmAttributes, /* bmAttributes */ + bMaxPower_mA+1), /* bMaxPower (+1 because tusb just does n/2 instead of (n+1)/2) */ + }, TUD_CONFIG_DESC_LEN); + + return configc; +} + +uint8_t usb_add_interface(uint8_t cfg_num, uint16_t ifc_len, uint8_t *ifc_dat) { + assert(cfg_num > 0 && cfg_num <= configc); + assert(ifc_len >= 3); + assert(ifc_dat); + + uint8_t *desc = configv[cfg_num-1]; + // wTotalLength + uint16_t total_len = TU_U16(desc[3], desc[2]) + ifc_len; + desc[3] = TU_U16_HIGH(total_len); + desc[2] = TU_U16_LOW(total_len); + // bNumInterfaces + ifc_dat[3] = desc[4]++; + + desc = configv[cfg_num-1] = realloc(desc, total_len); + memcpy(&desc[total_len-ifc_len], ifc_dat, ifc_len); + + return ifc_dat[3]; +} + +/** + * Return a pointer to the USB "Device Descriptor" (see USB 2.0 §9.6.1 + * "Device") as a byte-array. + */ +uint8_t const *tud_descriptor_device_cb(void) { + /* Our device descriptor is static, so just declare it as a + * static const. */ + static tusb_desc_device_t desc = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x200, /* USB 2.0 */ + + /* Use the "base device class", which means to use information + * from interface descriptors instead of a global device + * descriptor. */ + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCAFE, /* Vendor ID (assigned by the USB-IF) */ + .idProduct = 0x4001, /* Product ID (assigned by the manufacturer) */ + .bcdDevice = 0x0100, /* Device release number */ + + .iManufacturer = STRID_MANUF, /* Index of string descriptor describing manufacturer */ + .iProduct = STRID_PRODUCT, /* Index of string descriptor describing product */ + .iSerialNumber = STRID_SERIAL, /* Index of string descriptor describing the device's serial number */ + + .bNumConfigurations = 0, /* Number of possible configurations */ + }; + desc.bNumConfigurations = configc; + return (uint8_t const *) &desc; +} + +/** + * Return a pointer to the USB config "Configuration Descriptor" (see + * USB 2.0 §9.6.4 "Configuration") for the given index. + */ +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { + if (index >= configc) + return NULL; + return configv[index]; +} diff --git a/libusb/usb_common.h b/libusb/usb_common.h new file mode 100644 index 0000000..3b45246 --- /dev/null +++ b/libusb/usb_common.h @@ -0,0 +1,59 @@ +/* usb_common.h - Common framework for implementing multiple USB devices at once + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#ifndef _USB_COMMON_H_ +#define _USB_COMMON_H_ + +#include "coroutine.h" + +/* Strings ********************************************************************/ + +enum { + /* Be sure to keep this list in-sync with + * usb_common.c:tud_descriptor_string_cb() */ + STRID_LANGID = 0, + STRID_MANUF, + STRID_PRODUCT, + STRID_SERIAL, + STRID_CFG, + STRID_KBD_IFC, + + STRID_NONE = 0, +}; + +/* Globals ********************************************************************/ + +extern uint8_t cfgnum_std; +void usb_common_earlyinit(void); +void usb_common_lateinit(void); +COROUTINE usb_common_cr(void *arg); + +/* Main utilities *************************************************************/ + +/** + * Declare a new TUD configuration. + * + * @param iConfiguration : ID of the string descriptor describing this configuration + * @param bmAttributes : bitmap of flags; TUSB_DESC_CONFIG_ATT_{REMOTE_WAKUP,SELF_POWERED} + * @param bMaxPower_mA : maximum power consumption of the device when in this configuration, in mA + * @return the configuration number for the created config + */ +uint8_t usb_add_config(uint8_t iConfiguration, uint8_t bmAttributes, uint8_t bMaxPower_mA); + +/** + * Add an interface to a configuration that has been created with usb_add_config(). + * + * @param cfg_num : the value returned from usb_add_config() + * @param ifc_len : the length of ifc_Dat + * @param ifc_dat : the raw descriptor data for the interface (probably created by + * TUD_{CLASS}_DESCRIPTOR(); grep TinyUSB/src/device/usbd.h for '#define + * TUD_\S*_DESCRIPTOR(_itfnum'). The interface number in this data is overwritten with the + * appropriate number for this config. + * @return the interface number for the added interface + */ +uint8_t usb_add_interface(uint8_t cfg_num, uint16_t ifc_len, uint8_t *ifc_dat); + +#endif /* _USB_COMMON_H_ */ |