From e5e15c04bc58c34906e6d7cfcbad68d1a5617563 Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Fri, 27 Sep 2024 17:25:36 -0600 Subject: wip --- .gitignore | 6 +- 3rd-party/.gitignore | 1 - 3rd-party/MS-LCID.txt | 4073 ++++++++++++++++++++++++++++++ CMakeLists.txt | 32 +- HACKING.md | 10 + PLAN.md | 2 + cmd/harness/main.c | 48 - cmd/harness/usb_keyboard.c | 113 - cmd/harness/usb_keyboard.h | 17 - cmd/sbc_harness/CMakeLists.txt | 23 + cmd/sbc_harness/config/config.h | 54 + cmd/sbc_harness/config/tusb_config.h | 107 + cmd/sbc_harness/main.c | 48 + cmd/sbc_harness/usb_keyboard.c | 113 + cmd/sbc_harness/usb_keyboard.h | 17 + cmd/srv9p/CMakeLists.txt | 15 + cmd/srv9p/config/config.h | 1 + config.h | 58 - lib9p/.editorconfig | 2 +- lib9p/.gitignore | 2 - lib9p/9P2000.e.txt | 4 +- lib9p/9P2000.u.txt | 25 + lib9p/9p.c | 94 + lib9p/9p.h | 15 - lib9p/CMakeLists.txt | 34 + lib9p/defs.c | 89 - lib9p/defs.gen | 456 ---- lib9p/defs.h | 74 - lib9p/include/lib9p/9p.h | 72 + lib9p/include/lib9p/_types.h | 285 +++ lib9p/include/lib9p/linux-errno.h.gen | 34 + lib9p/include/lib9p/srv.h | 16 + lib9p/internal.h | 79 +- lib9p/linux-errno.h.gen | 34 - lib9p/misc.txt | 24 - lib9p/srv.h | 16 - lib9p/types.c | 1331 ++++++++++ lib9p/types.gen | 611 +++++ libcr/CMakeLists.txt | 10 + libcr/coroutine.c | 2 +- libcr/coroutine.h | 130 - libcr/include/libcr/coroutine.h | 130 + libcr_ipc/CMakeLists.txt | 10 + libcr_ipc/coroutine_chan.h | 115 - libcr_ipc/coroutine_rpc.h | 108 - libcr_ipc/coroutine_sema.c | 95 - libcr_ipc/coroutine_sema.h | 35 - libcr_ipc/include/libcr_ipc/chan.h | 115 + libcr_ipc/include/libcr_ipc/rpc.h | 108 + libcr_ipc/include/libcr_ipc/sema.h | 35 + libcr_ipc/sema.c | 95 + libnetio/CMakeLists.txt | 10 + libusb/CMakeLists.txt | 23 + libusb/include/libusb/tusb_helpers.h | 971 +++++++ libusb/include/libusb/tusb_helpers.h.gen | 82 + libusb/include/libusb/usb_common.h | 59 + libusb/tusb_config.h | 107 - libusb/tusb_helpers.h | 971 ------- libusb/tusb_helpers.h.gen | 82 - libusb/usb_common.h | 59 - 60 files changed, 8683 insertions(+), 2704 deletions(-) delete mode 100644 3rd-party/.gitignore create mode 100644 3rd-party/MS-LCID.txt create mode 100644 HACKING.md delete mode 100644 cmd/harness/main.c delete mode 100644 cmd/harness/usb_keyboard.c delete mode 100644 cmd/harness/usb_keyboard.h create mode 100644 cmd/sbc_harness/CMakeLists.txt create mode 100644 cmd/sbc_harness/config/config.h create mode 100644 cmd/sbc_harness/config/tusb_config.h create mode 100644 cmd/sbc_harness/main.c create mode 100644 cmd/sbc_harness/usb_keyboard.c create mode 100644 cmd/sbc_harness/usb_keyboard.h create mode 100644 cmd/srv9p/CMakeLists.txt create mode 120000 cmd/srv9p/config/config.h delete mode 100644 config.h delete mode 100644 lib9p/.gitignore create mode 100644 lib9p/9p.c delete mode 100644 lib9p/9p.h create mode 100644 lib9p/CMakeLists.txt delete mode 100644 lib9p/defs.c delete mode 100755 lib9p/defs.gen delete mode 100644 lib9p/defs.h create mode 100644 lib9p/include/lib9p/9p.h create mode 100644 lib9p/include/lib9p/_types.h create mode 100755 lib9p/include/lib9p/linux-errno.h.gen create mode 100644 lib9p/include/lib9p/srv.h delete mode 100755 lib9p/linux-errno.h.gen delete mode 100644 lib9p/misc.txt delete mode 100644 lib9p/srv.h create mode 100644 lib9p/types.c create mode 100755 lib9p/types.gen create mode 100644 libcr/CMakeLists.txt delete mode 100644 libcr/coroutine.h create mode 100644 libcr/include/libcr/coroutine.h create mode 100644 libcr_ipc/CMakeLists.txt delete mode 100644 libcr_ipc/coroutine_chan.h delete mode 100644 libcr_ipc/coroutine_rpc.h delete mode 100644 libcr_ipc/coroutine_sema.c delete mode 100644 libcr_ipc/coroutine_sema.h create mode 100644 libcr_ipc/include/libcr_ipc/chan.h create mode 100644 libcr_ipc/include/libcr_ipc/rpc.h create mode 100644 libcr_ipc/include/libcr_ipc/sema.h create mode 100644 libcr_ipc/sema.c create mode 100644 libnetio/CMakeLists.txt create mode 100644 libusb/CMakeLists.txt create mode 100644 libusb/include/libusb/tusb_helpers.h create mode 100755 libusb/include/libusb/tusb_helpers.h.gen create mode 100644 libusb/include/libusb/usb_common.h delete mode 100644 libusb/tusb_config.h delete mode 100644 libusb/tusb_helpers.h delete mode 100755 libusb/tusb_helpers.h.gen delete mode 100644 libusb/usb_common.h diff --git a/.gitignore b/.gitignore index fa00101..9e280fc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,4 @@ *.log .mypy_cache/ -/build/ - -/tusb_helpers.h - -/srv9p +build/ diff --git a/3rd-party/.gitignore b/3rd-party/.gitignore deleted file mode 100644 index 4305236..0000000 --- a/3rd-party/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MS-LCID.txt diff --git a/3rd-party/MS-LCID.txt b/3rd-party/MS-LCID.txt new file mode 100644 index 0000000..6bc95b1 --- /dev/null +++ b/3rd-party/MS-LCID.txt @@ -0,0 +1,4073 @@ +[MS-LCID]: +Windows Language Code Identifier (LCID) Reference + + +Intellectual Property Rights Notice for Open Specifications Documentation + Technical Documentation. Microsoft publishes Open Specifications documentation (“this + documentation”) for protocols, file formats, data portability, computer languages, and standards + support. Additionally, overview documents cover inter-protocol relationships and interactions. + Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other + terms that are contained in the terms of use for the Microsoft website that hosts this + documentation, you can make copies of it in order to develop implementations of the technologies + that are described in this documentation and can distribute portions of it in your implementations + that use these technologies or in your documentation as necessary to properly document the + implementation. You can also distribute in your implementation, with or without modification, any + schemas, IDLs, or code samples that are included in the documentation. This permission also + applies to any documents that are referenced in the Open Specifications documentation. + No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation. + Patents. Microsoft has patents that might cover your implementations of the technologies + described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of + this documentation grants any licenses under those patents or any other Microsoft patents. + However, a given Open Specifications document might be covered by the Microsoft Open + Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, + or if the technologies described in this documentation are not covered by the Open Specifications + Promise or Community Promise, as applicable, patent licenses are available by contacting + iplg@microsoft.com. + License Programs. To see all of the protocols in scope under a specific license program and the + associated patents, visit the Patent Map. + Trademarks. The names of companies and products contained in this documentation might be + covered by trademarks or similar intellectual property rights. This notice does not grant any + licenses under those rights. For a list of Microsoft trademarks, visit + www.microsoft.com/trademarks. + Fictitious Names. The example companies, organizations, products, domain names, email + addresses, logos, people, places, and events that are depicted in this documentation are fictitious. + No association with any real company, organization, product, domain name, email address, logo, + person, place, or event is intended or should be inferred. +Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other +than as specifically described above, whether by implication, estoppel, or otherwise. + +Tools. The Open Specifications documentation does not require the use of Microsoft programming +tools or programming environments in order for you to develop an implementation. If you have access +to Microsoft programming tools and environments, you are free to take advantage of them. Certain +Open Specifications documents are intended for use in conjunction with publicly available standards +specifications and network programming art and, as such, assume that the reader either is familiar +with the aforementioned material or has immediate access to it. + +Support. For questions and support, please contact dochelp@microsoft.com. + + + + + 1 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Revision Summary + + Revision Revision + Date History Class Comments + + 2/14/2008 2.1.3 Editorial Changed language and formatting in the technical content. + + 3/14/2008 2.1.4 Editorial Changed language and formatting in the technical content. + + 6/20/2008 2.1.5 Editorial Changed language and formatting in the technical content. + + 7/25/2008 2.1.6 Editorial Changed language and formatting in the technical content. + + 8/29/2008 2.2 Minor Clarified the meaning of the technical content. + + 10/24/2008 2.2.1 Editorial Changed language and formatting in the technical content. + + 12/5/2008 2.3 Minor Clarified the meaning of the technical content. + + 1/16/2009 2.3.1 Editorial Changed language and formatting in the technical content. + + 2/27/2009 2.3.2 Editorial Changed language and formatting in the technical content. + + 4/10/2009 2.4 Minor Clarified the meaning of the technical content. + + 5/22/2009 2.4.1 Editorial Changed language and formatting in the technical content. + + 7/2/2009 2.4.2 Editorial Changed language and formatting in the technical content. + + 8/14/2009 2.4.3 Editorial Changed language and formatting in the technical content. + + 9/25/2009 3.0 Major Updated and revised the technical content. + + 11/6/2009 3.0.1 Editorial Changed language and formatting in the technical content. + + 12/18/2009 3.0.2 Editorial Changed language and formatting in the technical content. + + 1/29/2010 3.1 Minor Clarified the meaning of the technical content. + + 3/12/2010 3.1.1 Editorial Changed language and formatting in the technical content. + + 4/23/2010 3.1.2 Editorial Changed language and formatting in the technical content. + + 6/4/2010 3.1.3 Editorial Changed language and formatting in the technical content. + + No changes to the meaning, language, or formatting of the + 7/16/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 8/27/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 10/8/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 11/19/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 1/7/2011 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 2/11/2011 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 3/25/2011 3.1.3 None + technical content. + + + 2 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Revision Revision + Date History Class Comments + + No changes to the meaning, language, or formatting of the + 5/6/2011 3.1.3 None + technical content. + + 6/17/2011 3.2 Minor Clarified the meaning of the technical content. + + No changes to the meaning, language, or formatting of the + 9/23/2011 3.2 None + technical content. + + 12/16/2011 4.0 Major Updated and revised the technical content. + + No changes to the meaning, language, or formatting of the + 3/30/2012 4.0 None + technical content. + + 7/12/2012 5.0 Major Updated and revised the technical content. + + No changes to the meaning, language, or formatting of the + 10/25/2012 5.0 None + technical content. + + No changes to the meaning, language, or formatting of the + 1/31/2013 5.0 None + technical content. + + 8/8/2013 6.0 Major Updated and revised the technical content. + + 11/14/2013 6.1 Minor Clarified the meaning of the technical content. + + No changes to the meaning, language, or formatting of the + 2/13/2014 6.1 None + technical content. + + No changes to the meaning, language, or formatting of the + 5/15/2014 6.1 None + technical content. + + 6/30/2015 7.0 Major Significantly changed the technical content. + + No changes to the meaning, language, or formatting of the + 10/16/2015 7.0 None + technical content. + + 7/14/2016 8.0 Major Significantly changed the technical content. + + 3/16/2017 9.0 Major Significantly changed the technical content. + + No changes to the meaning, language, or formatting of the + 6/1/2017 9.0 None + technical content. + + 9/15/2017 10.0 Major Significantly changed the technical content. + + 12/1/2017 11.0 Major Significantly changed the technical content. + + 9/12/2018 12.0 Major Significantly changed the technical content. + + 3/13/2019 13.0 Major Significantly changed the technical content. + + 3/4/2020 14.0 Major Significantly changed the technical content. + + 4/7/2021 14.1 Minor Clarified the meaning of the technical content. + + 6/25/2021 15.0 Major Significantly changed the technical content. + + 4/23/2024 16.0 Major Significantly changed the technical content. + + + + + 3 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Table of Contents + 1 Introduction ............................................................................................................ 5 + 1.1 Glossary ........................................................................................................... 5 + 1.2 References ........................................................................................................ 6 + 1.2.1 Normative References ................................................................................... 6 + 1.2.2 Informative References ................................................................................. 6 + 1.3 Overview .......................................................................................................... 6 + 1.4 Relationship to Protocols and Other Structures ...................................................... 7 + 1.5 Applicability Statement ....................................................................................... 7 + 1.6 Versioning and Localization ................................................................................. 7 + 1.7 Vendor-Extensible Fields ..................................................................................... 7 + 2 Structures ............................................................................................................... 8 + 2.1 Language Code Identifiers ................................................................................... 8 + 2.2 LCID Structure ................................................................................................... 8 + 2.2.1 Locale Names without LCIDs ........................................................................ 25 + 3 Structure Examples ............................................................................................... 27 + 4 Security Considerations ......................................................................................... 28 + 5 Appendix A: Product Behavior ............................................................................... 29 + 6 Change Tracking .................................................................................................... 60 + 7 Index ..................................................................................................................... 61 + + + + + 4 / 61 + [MS-LCID] - v20240423 + Windows Language Code Identifier (LCID) Reference + Copyright © 2024 Microsoft Corporation + Release: April 23, 2024 + 1 Introduction +This document provides an overview of language code identifiers (LCIDs), also known as culture +identifiers, which are being deprecated, and the preferred alternate system of locale codes, which +specify a set of locale identifiers that designate culture-specific information such as how text is sorted, +how a date is formatted, and the display format for numbers and currency. + +Sections 1.7 and 2 of this specification are normative. All other sections and examples in this +specification are informative. + + +1.1 Glossary + +This document uses the following terms: + + alternate sort: Specifies an alternate collation for a language that has multiple methods for + sorting data. For example, German has both "Dictionary" and "Phone Book" sorts. "Dictionary" + sorting (de-DE) is the default for German, but developers can specify the alternate "Phone + Book" sort (de-DE_phoneb) explicitly. + + Chinese BIG5 order: Ideographs are ordered according to the code point values of the Taiwanese + BIG5 industrial standard. + + Chinese radical/stroke order: Ideographs are ordered according to radical stroke count. + + Chinese Unicode order: Deprecated. Identical to the default sort information used for English. + + Georgian modern order: An order for the Georgian language that places archaic characters that + are no longer used at the end of the alphabet. + + Georgian traditional order: An order for the Georgian language that intersperses archaic + characters that are no longer used among the rest of the alphabet in their traditional places. + + German phone book order: An order that equates Ä, Ö, and Ü with AE, OE, and UE, respectively + (commonly used in German phone books). + + Hungarian default order: The typical expected alphabetical order for the Hungarian language. + + Hungarian technical order: A sort order that places capital letters before lowercase ones, unlike + most sorts, which sort lowercase first. + + Japanese radical/stroke sort order: Ideographs are ordered by their radical and stroke + components, much like an ideographic dictionary might do. + + Japanese Unicode order: Deprecated. Identical to the default sort information used for English, + except that the backslash (\) is equal to the currency symbol, 0x00A5, the yen sign. + + Japanese XJIS order: Ideographs are ordered according to the code point values of the [JIS X + 208] and [JIS X 212] government standards. + + Korean KSC order: Ideographs are ordered according to the Korean Hangul pronunciation, as + specified in the Korean [KSC5601] government standard. + + Korean Unicode order: Deprecated. Identical to the default sort information used for English, + except that the backslash (\) is equal to the currency symbol, 0x20A9, the won sign. + + neutral locale: A locale describing a language without any region-specific information. + + PRC Chinese phonetic order: Ideographs are ordered according to their A to Z pronunciation + order. + + + 5 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + PRC Chinese stroke count order: Ideographs are ordered according to their stroke count. + + specific locale: A locale describing a language that has a qualifying regional variant. For example, + variants for English can be en-US or en-GB. + + Traditional Chinese Bopomofo order: Ideographs are ordered by their most common Mandarin + pronunciation, using the Chinese Bopomofo order of the pronunciations. + + MAY, SHOULD, MUST, SHOULD NOT, MUST NOT: These terms (in all caps) are used as defined + in [RFC2119]. All statements of optional behavior use either MAY, SHOULD, or SHOULD NOT. + + +1.2 References + +Links to a document in the Microsoft Open Specifications library point to the correct section in the +most recently published version of the referenced document. However, because individual documents +in the library are not updated at the same time, the section numbers in the documents may not +match. You can confirm the correct section numbering by checking the Errata. + + +1.2.1 Normative References + +We conduct frequent surveys of the normative references to assure their continued availability. If you +have any issue with finding a normative reference, please contact dochelp@microsoft.com. We will +assist you in finding the relevant information. + +[ISO-15924] International Organization for Standardization, "ISO 15924 Registration Authority", +http://www.unicode.org/iso15924/ + +[ISO-3166] International Organization for Standardization, "Codes for the representation of names of +countries and their subdivisions -- Part1: Country codes", ISO 3166-1:2013, November 2013, +http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=63545 + +Note There is a charge to download the specification. + +[ISO-639] International Organization for Standardization, "Codes for the representation of names of +languages -- Part 2: Alpha-3 code", ISO 639-2:1998, +http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=4767 + +Note There is a charge to download this specification. + +[MS-DTYP] Microsoft Corporation, "Windows Data Types". + +[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC +2119, March 1997, https://www.rfc-editor.org/info/rfc2119 + +[RFC5646] Phillips, A, and Davis, M., "Tags for Identifying Languages", BCP 47, RFC 4646, September +2006, https://www.rfc-editor.org/info/rfc5646 + + +1.2.2 Informative References + +[KSC5601] Korea Industrial Standards Association, "Code for Information Interchange (Hangul and +Hanja)", Korean Industrial Standard, 1987, Ref. No. KS C 5601-1987. + + +1.3 Overview + +The LCID structure is used to identify specific languages for the purpose of customizing software for +particular languages and cultures. For example, it can specify the way dates, times, and numbers are +formatted as strings. It can also specify paper sizes and preferred sort order based on language +elements. + + 6 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + LCIDs are being deprecated, and implementers are strongly encouraged to use locale names instead. +LCIDs can be used for backward compatibility, but as noted in section 2.2.1, there is no guarantee of +LCID uniqueness when used with valid locale names not otherwise associated with an LCID. + + +1.4 Relationship to Protocols and Other Structures + +This structure is related to protocols and structures that need to make special cases for specific +languages and cultures. + + +1.5 Applicability Statement + +This structure applies in scenarios where special cases need to be made for specific languages and +cultures. + + +1.6 Versioning and Localization + +This structure serves to identify particular languages, locales, and cultures. + + +1.7 Vendor-Extensible Fields + +None. + + + + + 7 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + 2 Structures + +2.1 Language Code Identifiers + +LCIDs are identifiers used to specify localizable information. They are also known as culture identifiers +in the Microsoft .NET Framework environment. + +The name of a culture consists of its [ISO-639] language code, its [ISO-3166] country/region code, +and an optional [ISO-15924] script tag for the written language. For example, the name of the culture +in which the language is Bosnian (as written in Latin script and used in the Bosnia and Herzegovina +region) is bs-Latn-BA.<1><2><3> + + +2.2 LCID Structure + +This protocol references commonly used data types as defined in [MS-DTYP]. + +An LCID is a 4-byte value. The value supplied in an LCID is a standard numeric substitution for the +international [RFC5646] string. + +The following diagram is shown in host byte order. + + 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + + Reserved Sort ID Language ID + + +Reserved (12 bits): This field is reserved for future use. It MUST be 0. + +Sort ID (4 bits): The sort order. In most cases, this value can be 0x0, which indicates a default sort + (SORT_DEFAULT). However, other values can be used when an alternate sort is required. These + alternate values are listed in the following table. For example, 0x0407 (German - Germany) + becomes 0x10407 when SORT_GERMAN_PHONE_BOOK is used. + + Value Meaning + + SORT_CHINESE_BIG5 Chinese BIG5 order + 0x0 Default sort for Simplified Chinese locales + Use with zh-TW, zh-HK, or zh-MO + + SORT_CHINESE_PRCP PRC Chinese phonetic order + 0x0 Default sort for Traditional Chinese locales. + Use with zn-CN or zh-SG + + SORT_DEFAULT Default sort order + 0x0 + + SORT_GEORGIAN_TRADITIONAL Georgian traditional order + 0x0 Default sort for Georgian, use with ka-GE + + SORT_HUNGARIAN_DEFAULT Hungarian default order + 0x0 Default sort for Hungarian, use with hu-HU + + SORT_JAPANESE_XJIS Japanese XJIS order + 0x0 Use with ja-JP + + SORT_KOREAN_KSC Korean KSC order + + + 8 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Value Meaning + + 0x0 Default sort for Korean, use with ko-KR + + SORT_CHINESE_UNICODE Chinese Unicode order<4> + 0x1 Do not use, deprecated + + SORT_GEORGIAN_MODERN Georgian modern order + 0x1 Use with ka-GE, resolves to ka-GE_modern + + SORT_GERMAN_PHONE_BOOK German phone book order + 0x1 Use with de-DE, resolves to de-DE_phoneb + + SORT_HUNGARIAN_TECHNICAL Hungarian technical order + 0x1 Use with hu-HU, resolves to hu-HU_technl + + SORT_JAPANESE_UNICODE Japanese Unicode order<5> + 0x1 Do not use, deprecated + + SORT_KOREAN_UNICODE Korean Unicode order<6> + 0x1 Do not use, deprecated + + SORT_CHINESE_PRC PRC Chinese stroke count order + 0x2 Use with zh-CN, resolves to zh-CN_stroke + Use with zh-SG, resolves to zh-SG_stroke + + SORT_CHINESE_BOPOMOFO Traditional Chinese Bopomofo order + 0x3 Use with zh-TW, resolves to zh-TW_pronun + + SORT_CHINESE_RADICALSTROKE Chinese radical/stroke order<7> + 0x4 Use with zh-HK, resolves to zh-HK_radstr + Use with zh-MO, resolves to zh-MO_radstr + Use with zh-TW, resolves to zh-TW_radstr + + SORT_JAPANESE_RADICALSTROKE Japanese radical/stroke sort order + 0x4 Use with ja-JP, resolves to ja-JP_radstr + + +Language ID (2 bytes): The language component of the LCID.<8> + + Language ID Language tag + + 0x0001 ar + + 0x0002 bg + + 0x0003 ca + + 0x0004 zh-Hans + + 0x0005 cs + + 0x0006 da + + 0x0007 de + + 0x0008 el + + 0x0009 en + + 0x000A es + + + 9 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x000B fi + + 0x000C fr + + 0x000D he + + 0x000E hu + + 0x000F is + + 0x0010 it + + 0x0011 ja + + 0x0012 ko + + 0x0013 nl + + 0x0014 no + + 0x0015 pl + + 0x0016 pt + + 0x0017 rm + + 0x0018 ro + + 0x0019 ru + + 0x001A hr + + 0x001B sk + + 0x001C sq + + 0x001D sv + + 0x001E th + + 0x001F tr + + 0x0020 ur + + 0x0021 id + + 0x0022 uk + + 0x0023 be + + 0x0024 sl + + 0x0025 et + + 0x0026 lv + + 0x0027 lt + + 0x0028 tg + + 0x0029 fa + + 0x002A vi + + + 10 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x002B hy + + 0x002C az + + 0x002D eu + + 0x002E hsb + + 0x002F mk + + 0x0030 st + + 0x0031 ts + + 0x0032 tn + + 0x0033 ve + + 0x0034 xh + + 0x0035 zu + + 0x0036 af + + 0x0037 ka + + 0x0038 fo + + 0x0039 hi + + 0x003A mt + + 0x003B se + + 0x003C ga + + 0x003D yi, reserved + + 0x003E ms + + 0x003F kk + + 0x0040 ky + + 0x0041 sw + + 0x0042 tk + + 0x0043 uz + + 0x0044 tt + + 0x0045 bn + + 0x0046 pa + + 0x0047 gu + + 0x0048 or + + 0x0049 ta + + 0x004A te + + + 11 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x004B kn + + 0x004C ml + + 0x004D as + + 0x004E mr + + 0x004F sa + + 0x0050 mn + + 0x0051 bo + + 0x0052 cy + + 0x0053 km + + 0x0054 lo + + 0x0055 my + + 0x0056 gl + + 0x0057 kok + + 0x0058 mni, reserved + + 0x0059 sd + + 0x005A syr + + 0x005B si + + 0x005C chr + + 0x005D iu + + 0x005E am + + 0x005F tzm + + 0x0060 ks + + 0x0061 ne + + 0x0062 fy + + 0x0063 ps + + 0x0064 fil + + 0x0065 dv + + 0x0066 bin, reserved + + 0x0067 ff + + 0x0068 ha + + 0x0069 ibb, reserved + + 0x006A yo + + + 12 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x006B quz + + 0x006C nso + + 0x006D ba + + 0x006E lb + + 0x006F kl + + 0x0070 ig + + 0x0071 kr, reserved + + 0x0072 om + + 0x0073 ti + + 0x0074 gn + + 0x0075 haw + + 0x0076 la, reserved + + 0x0077 so, reserved + + 0x0078 ii + + 0x0079 pap, reserved + + 0x007A arn + + 0x007B Neither defined nor reserved + + 0x007C moh + + 0x007D Neither defined nor reserved + + 0x007E br + + 0x007F Reserved for invariant locale behavior + + 0x0080 ug + + 0x0081 mi + + 0x0082 oc + + 0x0083 co + + 0x0084 gsw + + 0x0085 sah + + 0x0086 qut + + 0x0087 rw + + 0x0088 wo + + 0x0089 Neither defined nor reserved + + 0x008A Neither defined nor reserved + + + 13 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x008B Neither defined nor reserved + + 0x008C prs + + 0x008D Neither defined nor reserved + + 0x008E Neither defined nor reserved + + 0x008F Neither defined nor reserved + + 0x0090 Neither defined nor reserved + + 0x0091 gd + + 0x0092 ku + + 0x0093 quc, reserved + + 0x0401 ar-SA + + 0x0402 bg-BG + + 0x0403 ca-ES + + 0x0404 zh-TW + + 0x0405 cs-CZ + + 0x0406 da-DK + + 0x0407 de-DE + + 0x0408 el-GR + + 0x0409 en-US + + 0x040A es-ES_tradnl + + 0x040B fi-FI + + 0x040C fr-FR + + 0x040D he-IL + + 0x040E hu-HU + + 0x040F is-IS + + 0x0410 it-IT + + 0x0411 ja-JP + + 0x0412 ko-KR + + 0x0413 nl-NL + + 0x0414 nb-NO + + 0x0415 pl-PL + + 0x0416 pt-BR + + 0x0417 rm-CH + + + 14 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0418 ro-RO + + 0x0419 ru-RU + + 0x041A hr-HR + + 0x041B sk-SK + + 0x041C sq-AL + + 0x041D sv-SE + + 0x041E th-TH + + 0x041F tr-TR + + 0x0420 ur-PK + + 0x0421 id-ID + + 0x0422 uk-UA + + 0x0423 be-BY + + 0x0424 sl-SI + + 0x0425 et-EE + + 0x0426 lv-LV + + 0x0427 lt-LT + + 0x0428 tg-Cyrl-TJ + + 0x0429 fa-IR + + 0x042A vi-VN + + 0x042B hy-AM + + 0x042C az-Latn-AZ + + 0x042D eu-ES + + 0x042E hsb-DE + + 0x042F mk-MK + + 0x0430 st-ZA + + 0x0431 ts-ZA + + 0x0432 tn-ZA + + 0x0433 ve-ZA + + 0x0434 xh-ZA + + 0x0435 zu-ZA + + 0x0436 af-ZA + + 0x0437 ka-GE + + + 15 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0438 fo-FO + + 0x0439 hi-IN + + 0x043A mt-MT + + 0x043B se-NO + + 0x043D yi-001 + + 0x043E ms-MY + + 0x043F kk-KZ + + 0x0440 ky-KG + + 0x0441 sw-KE + + 0x0442 tk-TM + + 0x0443 uz-Latn-UZ + + 0x0444 tt-RU + + 0x0445 bn-IN + + 0x0446 pa-IN + + 0x0447 gu-IN + + 0x0448 or-IN + + 0x0449 ta-IN + + 0x044A te-IN + + 0x044B kn-IN + + 0x044C ml-IN + + 0x044D as-IN + + 0x044E mr-IN + + 0x044F sa-IN + + 0x0450 mn-MN + + 0x0451 bo-CN + + 0x0452 cy-GB + + 0x0453 km-KH + + 0x0454 lo-LA + + 0x0455 my-MM + + 0x0456 gl-ES + + 0x0457 kok-IN + + 0x0458 mni-IN, reserved + + + 16 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0459 sd-Deva-IN, reserved + + 0x045A syr-SY + + 0x045B si-LK + + 0x045C chr-Cher-US + + 0x045D iu-Cans-CA + + 0x045E am-ET + + 0x045F tzm-Arab-MA + + 0x0460 ks-Arab + + 0x0461 ne-NP + + 0x0462 fy-NL + + 0x0463 ps-AF + + 0x0464 fil-PH + + 0x0465 dv-MV + + 0x0466 bin-NG, reserved + + 0x0467 ff-NG, ff-Latn-NG + + 0x0468 ha-Latn-NG + + 0x0469 ibb-NG, reserved + + 0x046A yo-NG + + 0x046B quz-BO + + 0x046C nso-ZA + + 0x046D ba-RU + + 0x046E lb-LU + + 0x046F kl-GL + + 0x0470 ig-NG + + 0x0471 kr-Latn-NG + + 0x0472 om-ET + + 0x0473 ti-ET + + 0x0474 gn-PY + + 0x0475 haw-US + + 0x0476 la-VA + + 0x0477 so-SO + + 0x0478 ii-CN + + + 17 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0479 pap-029, reserved + + 0x047A arn-CL + + 0x047C moh-CA + + 0x047E br-FR + + 0x0480 ug-CN + + 0x0481 mi-NZ + + 0x0482 oc-FR + + 0x0483 co-FR + + 0x0484 gsw-FR + + 0x0485 sah-RU + + 0x0486 qut-GT, reserved + + 0x0487 rw-RW + + 0x0488 wo-SN + + 0x048C prs-AF + + 0x048D plt-MG, reserved + + 0x048E zh-yue-HK, reserved + + 0x048F tdd-Tale-CN, reserved + + 0x0490 khb-Talu-CN, reserved + + 0x0491 gd-GB + + 0x0492 ku-Arab-IQ + + 0x0493 quc-CO, reserved + + 0x0501 qps-ploc + + 0x05FE qps-ploca + + 0x0801 ar-IQ + + 0x0803 ca-ES-valencia + + 0x0804 zh-CN + + 0x0807 de-CH + + 0x0809 en-GB + + 0x080A es-MX + + 0x080C fr-BE + + 0x0810 it-CH + + 0x0811 ja-Ploc-JP, reserved + + + 18 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0813 nl-BE + + 0x0814 nn-NO + + 0x0816 pt-PT + + 0x0818 ro-MD + + 0x0819 ru-MD + + 0x081A sr-Latn-CS + + 0x081D sv-FI + + 0x0820 ur-IN + + 0x0827 Neither defined nor reserved + + 0x082C az-Cyrl-AZ, reserved + + 0x082E dsb-DE + + 0x0832 tn-BW + + 0x083B se-SE + + 0x083C ga-IE + + 0x083E ms-BN + + 0x083F kk-Latn-KZ, reserved + + 0x0843 uz-Cyrl-UZ, reserved + + 0x0845 bn-BD + + 0x0846 pa-Arab-PK + + 0x0849 ta-LK + + 0x0850 mn-Mong-CN, reserved + + 0x0851 bo-BT, reserved + + 0x0859 sd-Arab-PK + + 0x085D iu-Latn-CA + + 0x085F tzm-Latn-DZ + + 0x0860 ks-Deva-IN + + 0x0861 ne-IN + + 0x0867 ff-Latn-SN + + 0x086B quz-EC + + 0x0873 ti-ER + + 0x09FF qps-plocm + + 0x0C00 Locale without assigned LCID if the current user default locale. See section 2.2.1. + + + 19 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0C01 ar-EG + + 0x0C04 zh-HK + + 0x0C07 de-AT + + 0x0C09 en-AU + + 0x0C0A es-ES + + 0x0C0C fr-CA + + 0x0C1A sr-Cyrl-CS + + 0x0C3B se-FI + + 0x0C50 mn-Mong-MN + + 0x0C51 dz-BT + + 0x0C5F tmz-MA, reserved + + 0x0C6b quz-PE + + 0x1000 Locale without assigned LCID if the current user default locale. See section 2.2.1. + + 0x1001 ar-LY + + 0x1004 zh-SG + + 0x1007 de-LU + + 0x1009 en-CA + + 0x100A es-GT + + 0x100C fr-CH + + 0x101A hr-BA + + 0x103B smj-NO + + 0x105F tzm-Tfng-MA + + 0x1401 ar-DZ + + 0x1404 zh-MO + + 0x1407 de-LI + + 0x1409 en-NZ + + 0x140A es-CR + + 0x140C fr-LU + + 0x141A bs-Latn-BA + + 0x143B smj-SE + + 0x1801 ar-MA + + 0x1809 en-IE + + + 20 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x180A es-PA + + 0x180C fr-MC + + 0x181A sr-Latn-BA + + 0x183B sma-NO + + 0x1C01 ar-TN + + 0x1C09 en-ZA + + 0x1C0A es-DO + + 0x1C0C fr-029 + + 0x1C1A sr-Cyrl-BA + + 0x1C3B sma-SE + + 0x2000 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x2001 ar-OM + + 0x2008 Neither defined nor reserved + + 0x2009 en-JM + + 0x200A es-VE + + 0x200C fr-RE + + 0x201A bs-Cyrl-BA + + 0x203B sms-FI + + 0x2400 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x2401 ar-YE + + 0x2409 en-029, reserved + + 0x240A es-CO + + 0x240C fr-CD + + 0x241A sr-Latn-RS + + 0x243B smn-FI + + 0x2800 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x2801 ar-SY + + 0x2809 en-BZ + + 0x280A es-PE + + 0x280C fr-SN + + 0x281A sr-Cyrl-RS + + 0x2C00 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + + 21 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x2C01 ar-JO + + 0x2C09 en-TT + + 0x2C0A es-AR + + 0x2C0C fr-CM + + 0x2C1A sr-Latn-ME + + 0x3000 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x3001 ar-LB + + 0x3009 en-ZW + + 0x300A es-EC + + 0x300C fr-CI + + 0x301A sr-Cyrl-ME + + 0x3400 Unassigned LCID locale temporarily assigned to LCID 0x3400. See section 2.2.1. + + 0x3401 ar-KW + + 0x3409 en-PH + + 0x340A es-CL + + 0x340C fr-ML + + 0x3800 Unassigned LCID locale temporarily assigned to LCID 0x3800. See section 2.2.1. + + 0x3801 ar-AE + + 0x3809 en-ID, reserved + + 0x380A es-UY + + 0x380C fr-MA + + 0x3C00 Unassigned LCID locale temporarily assigned to LCID 0x3C00. See section 2.2.1. + + 0x3C01 ar-BH + + 0x3C09 en-HK + + 0x3C0A es-PY + + 0x3C0C fr-HT + + 0x4000 Unassigned LCID locale temporarily assigned to LCID 0x4000. See section 2.2.1. + + 0x4001 ar-QA + + 0x4009 en-IN + + 0x400A es-BO + + 0x4400 Unassigned LCID locale temporarily assigned to LCID 0x4400. See section 2.2.1. + + 0x4401 ar-Ploc-SA, reserved + + + 22 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x4409 en-MY + + 0x440A es-SV + + 0x4800 Unassigned LCID locale temporarily assigned to LCID 0x4800. See section 2.2.1. + + 0x4801 ar-145, reserved + + 0x4809 en-SG + + 0x480A es-HN + + 0x4C00 Unassigned LCID locale temporarily assigned to LCID 0x4C00. See section 2.2.1. + + 0x4C09 en-AE + + 0x4C0A es-NI + + 0x5009 en-BH, reserved + + 0x500A es-PR + + 0x5409 en-EG, reserved + + 0x540A es-US + + 0x5809 en-JO, reserved + + 0x580A es-419, reserved + + 0x5C09 en-KW, reserved + + 0x5C0A es-CU + + 0x6009 en-TR, reserved + + 0x6409 en-YE, reserved + + 0x641A bs-Cyrl + + 0x681A bs-Latn + + 0x6C1A sr-Cyrl + + 0x701A sr-Latn + + 0x703B smn + + 0x742C az-Cyrl + + 0x743B sms + + 0x7804 zh + + 0x7814 nn + + 0x781A bs + + 0x782C az-Latn + + 0x783B sma + + 0x783F kk-Cyrl, reserved + + + 23 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x7843 uz-Cyrl + + 0x7850 mn-Cyrl + + 0x785D iu-Cans + + 0x785F tzm-Tfng + + 0x7C04 zh-Hant + + 0x7C14 nb + + 0x7C1A sr + + 0x7C28 tg-Cyrl + + 0x7C2E dsb + + 0x7C3B smj + + 0x7C3F kk-Latn, reserved + + 0x7C43 uz-Latn + + 0x7C46 pa-Arab + + 0x7C50 mn-Mong + + 0x7C59 sd-Arab + + 0x7C5C chr-Cher + + 0x7C5D iu-Latn + + 0x7C5F tzm-Latn + + 0x7C67 ff-Latn + + 0x7C68 ha-Latn + + 0x7C92 ku-Arab + + 0xF2EE reserved + + 0xE40C fr-015, reserved + + 0xEEEE reserved + + +Some locales have more than one method of sorting, such as by pronunciation or stroke count. The +primary sort for each locale is provided by the identifiers in the preceding Language ID table. +Alternate sorts can be selected by using one of the identifiers from the following table. + + LCID Language tag (string name) + + 0x0001007F x-IV-mathan (math alphanumeric sorting) + + 0x00010407 de-DE_phoneb + + 0x0001040E hu-HU_tchncl + + 0x00010437 ka-GE_modern + + + + 24 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + LCID Language tag (string name) + + 0x00020804 zh-CN_stroke + + 0x00021004 zh-SG_stroke + + 0x00021404 zh-MO_stroke + + 0x00030404 zh-TW_pronun + + 0x00040404<9> zh-TW_radstr + + 0x00040411 ja-JP_radstr + + 0x00040C04<10> zh-HK_radstr + + 0x00041404<11> zh-MO_radstr + + 0x00050804<12> zh-CN_phoneb + + 0x00051004<13> zh-SG_phoneb + + + + +2.2.1 Locale Names without LCIDs + +Every locale name without an assigned LCID MAY be temporarily given one of the LCIDs in the +following table, if the application requests an LCID.<14> These locale names include any valid +[RFC5646] language tag. + + Note: LCID assignments for Locale Names without LCIDs are temporary and are not suitable + for use across a protocol, or for interchange between processes or machines. These temporary + LCID assignments are also unsuitable for tagging persisted data as the meaning of the LCID + assignment will change over time. + + + Name Value Conditions + + LOCALE_CUSTOM_USER_DEFAULT<15> 0x0C00 When an LCID without a permanent LCID + assignment is also the current user locale, the + protocol will respond with + LOCALE_CUSTOM_USER_DEFAULT for that locale. + This assignment persists until the user changes the + locale. Because the meaning changes over time, + applications are discouraged from persisting this + data. Though this value will likely refer to the same + locale for the lifetime of the current process, that is + not guaranteed. This assignment is a 1-to-1 + relationship between this LCID and the user’s + current default locale name. + + + + + 25 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Name Value Conditions + + Transient LCIDs<16> 0x2000, Some user configurations temporarily associate a + 0x2400, locale without a permanent LCID assignment with + 0x2800, one of these 12 transient LCIDs. This assignment is + 0x2C00, transient and it is not guaranteed; it will likely refer + 0x3000, to the same locale for the lifetime of the process. + 0x3400, However, this assignment will differ for other users + 0x3800, on the machine, or other machines, and, as such, + 0x3C00, is unsuitable for use in protocols or persisted data. + 0x4000, This assignment is a temporary 1-to-1 relationship + 0x4400, between an LCID and a particular locale name and + 0x4800, 0x4C00 will round trip until that relationship changes. + + LOCALE_CUSTOM_UNSPECIFIED<17> 0x1000 When an LCID is requested for a locale without a + permanent LCID assignment, nor a temporary + assignment as above, the protocol will respond + with LOCALE_CUSTOM_UNSPECIFIED for all such + locales. Because this single value is used for + numerous possible locale names, it is impossible to + round trip this locale, even temporarily. + Applications should discard this value as soon as + possible and never persist it. If the system is + forced to respond to a request for + LCID_CUSTOM_UNSPECIFIED, it will fall back to + the current user locale. This is often incorrect but + may prevent an application or component from + failing. As the meaning of this temporary LCID is + unstable, it should never be used for interchange + or persisted data. This is a 1-to-many relationship + that is very unstable. + + + + + 26 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + 3 Structure Examples +The following are examples of LCID values. + + LCID Language tag (string name) Type + + 0x00000075 haw neutral locale + + 0x00000409 en-US specific locale + + 0x00010407 de-DE_phoneb alternate sort for locale + + + + + 27 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + 4 Security Considerations +None. + + + + + 28 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + 5 Appendix A: Product Behavior +The information in this specification is applicable to the following Microsoft products or supplemental +software. References to product versions include updates to those products. + +The terms "earlier" and "later", when used with a product version, refer to either all preceding +versions or all subsequent versions, respectively. The term "through" refers to the inclusive range of +versions. Applicable Microsoft products are listed chronologically in this section. + +Windows Client + + Windows NT operating system + + Windows 2000 operating system + + Windows XP operating system + + Windows Vista operating system + + Windows 7 operating system + + Windows 8 operating system + + Windows 8.1 operating system + + Windows 10 operating system + + Windows 11 operating system + +Windows Server + + Windows NT + + Windows 2000 + + Windows Server 2003 operating system + + Windows Server 2008 R2 operating system + + Windows Server 2012 operating system + + Windows Server 2012 R2 operating system + + Windows Server 2016 operating system + + Windows Server operating system + + Windows Server 2019 operating system + + Windows Server 2022 operating system + + Windows Server 2025 operating system + +Exceptions, if any, are noted in this section. If an update version, service pack or Knowledge Base +(KB) number appears with a product name, the behavior changed in that update. The new behavior +also applies to subsequent updates unless otherwise specified. If a product edition appears with the +product version, behavior is different in that product edition. + +Unless otherwise specified, any statement of optional behavior in this specification that is prescribed +using the terms "SHOULD" or "SHOULD NOT" implies product behavior in accordance with the + + + + 29 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + SHOULD or SHOULD NOT prescription. Unless otherwise specified, the term "MAY" implies that the +product does not follow the prescription. + +<1> Section 2.1: Enabled Languages Kit (ELK) refers to a set of locales that is available through a +web download. Everything that is related to a locale is available from an ELK package (including +information on data formatting, such as date and time, font, keyboard layout, sorting, and currency +information). Additional LCID support is available through a separate ELK package for Windows XP and +Windows Vista clients and for Windows Server 2003 and Windows Server 2008 operating system +servers. + +<2> Section 2.1: In Windows, locales are primarily identified with numeric LCIDs. + +<3> Section 2.1: Windows Server 2003 supports all languages defined for Windows 95 operating +system, Windows 98 operating system, Windows Millennium Edition operating system, Windows NT +3.51 operating system, Windows NT 4.0 operating system, Windows 2000, Windows XP, and Windows +Server 2003 through the ELK. + +<4> Section 2.2: Supported only on Windows NT client and server releases. + +<5> Section 2.2: Supported only on Windows NT client and server releases. + +<6> Section 2.2: Supported only on Windows NT client and server releases. + +<7> Section 2.2: Supported only on Windows 7. + +<8> Section 2.2: The following table shows Language IDs and the versions of Windows in which they +were first made available. Language IDs are not assigned for all Language tags, please see section 1.3 +for further details. + +Supported Versions Key + + Release key Supported versions + + Release A First available in Windows NT 3.51. Supported in all later versions. + + Release B First available in Windows NT Server 4.0 operating system. Supported in all later versions. + + Release C First available in Windows 2000. Supported in all later versions. + + Release D First available in Windows XP and Windows Server 2003. Supported in all later versions. + + Release E1 First available in Windows XP ELK v1 for Windows XP SP2, Windows Server 2003, Windows + Vista, and Windows Server 2008. Supported in all later client and server versions of Windows. + + Release E2 First available in Windows XP ELK v2 for Windows XP SP2, Windows Server 2003, Windows + Vista, and Windows Server 2008. Supported in all later client and server versions of Windows. + + Release V First available in Windows Server 2008 and Windows Vista. Supported in all later versions. + + Release 7 First available in Windows 7 and Windows Server 2008 R2. Supported in all later versions. + + Release 8 First available in Windows 8 and Windows Server 2012. Supported in all later versions + + Release 8.1 First available in Windows 8.1 and Windows Server 2012 R2. Supported in all later versions. + + Release 10 First available in Windows 10 and Windows Server 2016. Supported in all later versions. + + Release 10.1 First available in Windows 10 v1607 operating system and Windows Server 2016. Supported + in all later versions. + + Release 10.2 First available in Windows 10 v1703 operating system. Supported in all later versions. + + Release 10.3 First available in Windows 10 v1709 operating system and Windows Server operating system. + + + 30 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Release key Supported versions + + Supported in all later versions. + + Release 10.4 First available in Windows 10 v1903 operating system and Windows Server v1903 operating + system. Supported in all later versions. + + Release 10.5 First available in Windows 10 v2004 operating system and Windows Server v2004 operating + system. Supported in all later versions. + + + + + Language Language Supported + Language Location (or type) ID tag version + + Afar 0x1000 aa Release 10 + + Afar Djibouti 0x1000 aa-DJ Release 10 + + Afar Eritrea 0x1000 aa-ER Release 10 + + Afar Ethiopia 0x1000 aa-ET Release 10 + + Afrikaans 0x0036 af Release 7 + + Afrikaans Namibia 0x1000 af-NA Release 10 + + Afrikaans South Africa 0x0436 af-ZA Release B + + Aghem 0x1000 agq Release 10 + + Aghem Cameroon 0x1000 agq-CM Release 10 + + Akan 0x1000 ak Release 10 + + Akan Ghana 0x1000 ak-GH Release 10 + + Albanian 0x001C sq Release 7 + + Albanian Albania 0x041C sq-AL Release B + + Albanian North Macedonia 0x1000 sq-MK Release 10 + + Alsatian 0x0084 gsw Release 7 + + Alsatian France 0x0484 gsw-FR Release V + + Alsatian Liechtenstein 0x1000 gsw-LI Release 10 + + Alsatian Switzerland 0x1000 gsw-CH Release 10 + + Amharic 0x005E am Release 7 + + Amharic Ethiopia 0x045E am-ET Release V + + Arabic 0x0001 ar Release 7 + + Arabic Algeria 0x1401 ar-DZ Release B + + Arabic Bahrain 0x3C01 ar-BH Release B + + Arabic Chad 0x1000 ar-TD Release 10 + + Arabic Comoros 0x1000 ar-KM Release 10 + + + 31 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Arabic Djibouti 0x1000 ar-DJ Release 10 + + Arabic Egypt 0x0c01 ar-EG Release B + + Arabic Eritrea 0x1000 ar-ER Release 10 + + Arabic Iraq 0x0801 ar-IQ Release B + + Arabic Israel 0x1000 ar-IL Release 10 + + Arabic Jordan 0x2C01 ar-JO Release B + + Arabic Kuwait 0x3401 ar-KW Release B + + Arabic Lebanon 0x3001 ar-LB Release B + + Arabic Libya 0x1001 ar-LY Release B + + Arabic Mauritania 0x1000 ar-MR Release 10 + + Arabic Morocco 0x1801 ar-MA Release B + + Arabic Oman 0x2001 ar-OM Release B + + Arabic Palestinian Authority 0x1000 ar-PS Release 10 + + Arabic Qatar 0x4001 ar-QA Release B + + Arabic Saudi Arabia 0x0401 ar-SA Release B + + Arabic Somalia 0x1000 ar-SO Release 10 + + Arabic South Sudan 0x1000 ar-SS Release 10 + + Arabic Sudan 0x1000 ar-SD Release 10 + + Arabic Syria 0x2801 ar-SY Release B + + Arabic Tunisia 0x1C01 ar-TN Release B + + Arabic U.A.E. 0x3801 ar-AE Release B + + Arabic World 0x1000 ar-001 Release 10 + + Arabic Yemen 0x2401 ar-YE Release B + + Armenian 0x002B hy Release 7 + + Armenian Armenia 0x042B hy-AM Release C + + Assamese 0x004D as Release 7 + + Assamese India 0x044D as-IN Release V + + Asturian 0x1000 ast Release 10 + + Asturian Spain 0x1000 ast-ES Release 10 + + Asu 0x1000 asa Release 10 + + Asu Tanzania 0x1000 asa-TZ Release 10 + + + + 32 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Azerbaijani (Cyrillic) 0x742C az-Cyrl Windows 7 + + Azerbaijani (Cyrillic) Azerbaijan 0x082C az-Cyrl-AZ Release C + + Azerbaijani (Latin) 0x002C az Release 7 + + Azerbaijani (Latin) 0x782C az-Latn Windows 7 + + Azerbaijani (Latin) Azerbaijan 0x042C az-Latn-AZ Release C + + Bafia 0x1000 ksf Release 10 + + Bafia Cameroon 0x1000 ksf-CM Release 10 + + Bamanankan 0x1000 bm Release 10 + + Bamanankan (Latin) Mali 0x1000 bm-Latn-ML Release 10 + + Bangla 0x0045 bn Release 7 + + Bangla Bangladesh 0x0845 bn-BD Release V + + Bangla India 0x0445 bn-IN Release E1 + + Basaa 0x1000 bas Release 10 + + Basaa Cameroon 0x1000 bas-CM Release 10 + + Bashkir 0x006D ba Release 7 + + Bashkir Russia 0x046D ba-RU Release V + + Basque 0x002D eu Release 7 + + Basque Spain 0x042D eu-ES Release B + + Belarusian 0x0023 be Release 7 + + Belarusian Belarus 0x0423 be-BY Release B + + Bemba 0x1000 bem Release 10 + + Bemba Zambia 0x1000 bem-ZM Release 10 + + Bena 0x1000 bez Release 10 + + Bena Tanzania 0x1000 bez-TZ Release 10 + + Bhojpuri 0x1000 bho Release 11 + + Bhojpuri (Devanagari) 0x1000 bho-Deva Release 11 + + Bhojpuri (Devanagari) India 0x1000 bho-Deva-IN Release 11 + + Blin 0x1000 byn Release 10 + + Blin Eritrea 0x1000 byn-ER Release 10 + + Bodo 0x1000 brx Release 10 + + Bodo India 0x1000 brx-IN Release 10 + + + + 33 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Bosnian (Cyrillic) 0x641A bs-Cyrl Windows 7 + + Bosnian (Cyrillic) Bosnia and Herzegovina 0x201A bs-Cyrl-BA Release E1 + + Bosnian (Latin) 0x681A bs-Latn Windows 7 + + Bosnian (Latin) 0x781A bs Release 7 + + Bosnian (Latin) Bosnia and Herzegovina 0x141A bs-Latn-BA Release E1 + + Breton 0x007E br Release 7 + + Breton France 0x047E br-FR Release V + + Bulgarian 0x0002 bg Release 7 + + Bulgarian Bulgaria 0x0402 bg-BG Release B + + Burmese 0x0055 my Release 8.1 + + Burmese Myanmar 0x0455 my-MM Release 8.1 + + Catalan 0x0003 ca Release 7 + + Catalan Andorra 0x1000 ca-AD Release 10 + + Catalan France 0x1000 ca-FR Release 10 + + Catalan Italy 0x1000 ca-IT Release 10 + + Catalan Spain 0x0403 ca-ES Release B + + Cebuano 0x1000 ceb Release 10.5 + + Cebuan (Latin) 0x1000 ceb-Latn Release 10.5 + + Cebuan (Latin) Philippines 0x1000 ceb-Latn-PH Release 10.5 + + Central Atlas Tamazight Morocco 0x045F tzm-Arab- Release 10 + (Arabic) MA + + Central Atlas Tamazight Morocco 0x1000 tzm-Latn- Release 10 + (Latin) MA + + Central Kurdish 0x0092 ku Release 8 + + Central Kurdish 0x7c92 ku-Arab Release 8 + + Central Kurdish Iraq 0x0492 ku-Arab-IQ Release 8 + + Chakma 0x1000 ccp Release 10.5 + + Chakma Chakma 0x1000 ccp-Cakm Release 10.5 + + Chakma Bangladesh 0x1000 ccp-Cakm- Release 10.5 + BD + + Chakma India 0x1000 ccp-Cakm- Release 10.5 + IN + + Chechen Russia 0x1000 ce-RU Release 10.1 + + + + 34 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Cherokee 0x005C chr Release 8 + + Cherokee 0x7c5C chr-Cher Release 8 + + Cherokee United States 0x045C chr-Cher-US Release 8 + + Chiga 0x1000 cgg Release 10 + + Chiga Uganda 0x1000 cgg-UG Release 10 + + Chinese (Simplified) 0x0004 zh-Hans Release A + + Chinese (Simplified) 0x7804 zh Windows 7 + + Chinese (Simplified) People's Republic of China 0x0804 zh-CN Release A + + Chinese (Simplified) Singapore 0x1004 zh-SG Release A + + Chinese (Traditional) 0x7C04 zh-Hant Release A + + Chinese (Traditional) Hong Kong S.A.R. 0x0C04 zh-HK Release A + + Chinese (Traditional) Macao S.A.R. 0x1404 zh-MO Release D + + Chinese (Traditional) Taiwan 0x0404 zh-TW Release A + + Church Slavic Russia 0x1000 cu-RU Release 10.1 + + Chuvash 0x1000 cv Release 11 + + Chuvash (Cyrillic) 0x1000 cv-Cyrl Release 11 + + Chuvash (Cyrillic) Russia 0x1000 cv-Cyrl-RU Release 11 + + Congo Swahili 0x1000 swc Release 10 + + Congo Swahili Congo DRC 0x1000 swc-CD Release 10 + + Cornish 0x1000 kw Release 10 + + Cornish United Kingdom 0x1000 kw-GB Release 10 + + Corsican 0x0083 co Release 7 + + Corsican France 0x0483 co-FR Release V + + Croatian 0x001A hr Release 7 + + Croatian Croatia 0x041A hr-HR Release A + + Croatian (Latin) Bosnia and Herzegovina 0x101A hr-BA Release E1 + + Czech 0x0005 cs Release 7 + + Czech Czech Republic 0x0405 cs-CZ Release A + + Danish 0x0006 da Release 7 + + Danish Denmark 0x0406 da-DK Release A + + Danish Greenland 0x1000 da-GL Release 10 + + + + 35 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Dari 0x008C prs Release 7 + + Dari Afghanistan 0x048C prs-AF Release V + + Divehi 0x0065 dv Release 7 + + Divehi Maldives 0x0465 dv-MV Release D + + Duala 0x1000 dua Release 10 + + Duala Cameroon 0x1000 dua-CM Release 10 + + Dutch 0x0013 nl Release 7 + + Dutch Aruba 0x1000 nl-AW Release 10 + + Dutch Belgium 0x0813 nl-BE Release A + + Dutch Bonaire, Sint Eustatius and Saba 0x1000 nl-BQ Release 10 + + Dutch Curaçao 0x1000 nl-CW Release 10 + + Dutch Netherlands 0x0413 nl-NL Release A + + Dutch Sint Maarten 0x1000 nl-SX Release 10 + + Dutch Suriname 0x1000 nl-SR Release 10 + + Dzongkha 0x1000 dz Release 10 + + Dzongkha Bhutan 0x0C51 dz-BT Release 10 + + Embu 0x1000 ebu Release 10 + + Embu Kenya 0x1000 ebu-KE Release 10 + + English 0x0009 en Release 7 + + English American Samoa 0x1000 en-AS Release 10 + + English Anguilla 0x1000 en-AI Release 10 + + English Antigua and Barbuda 0x1000 en-AG Release 10 + + English Australia 0x0C09 en-AU Release A + + English Austria 0x1000 en-AT Release 10.1 + + English Bahamas 0x1000 en-BS Release 10 + + English Barbados 0x1000 en-BB Release 10 + + English Belgium 0x1000 en-BE Release 10 + + English Belize 0x2809 en-BZ Release B + + English Bermuda 0x1000 en-BM Release 10 + + English Botswana 0x1000 en-BW Release 10 + + English British Indian Ocean Territory 0x1000 en-IO Release 10 + + + + 36 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English British Virgin Islands 0x1000 en-VG Release 10 + + English Burundi 0x1000 en-BI Release 10.1 + + English Cameroon 0x1000 en-CM Release 10 + + English Canada 0x1009 en-CA Release A + + English Caribbean 0x2409 en-029 Release B + + English Cayman Islands 0x1000 en-KY Release 10 + + English Christmas Island 0x1000 en-CX Release 10 + + English Cocos [Keeling] Islands 0x1000 en-CC Release 10 + + English Cook Islands 0x1000 en-CK Release 10 + + English Cyprus 0x1000 en-CY Release 10.1 + + English Denmark 0x1000 en-DK Release 10.1 + + English Dominica 0x1000 en-DM Release 10 + + English Eritrea 0x1000 en-ER Release 10 + + English Europe 0x1000 en-150 Release 10 + + English Falkland Islands 0x1000 en-FK Release 10 + + English Finland 0x1000 en-FI Release 10.1 + + English Fiji 0x1000 en-FJ Release 10 + + English Gambia 0x1000 en-GM Release 10 + + English Germany 0x1000 en-DE Release 10.1 + + English Ghana 0x1000 en-GH Release 10 + + English Gibraltar 0x1000 en-GI Release 10 + + English Grenada 0x1000 en-GD Release 10 + + English Guam 0x1000 en-GU Release 10 + + English Guernsey 0x1000 en-GG Release 10 + + English Guyana 0x1000 en-GY Release 10 + + English Hong Kong 0x3C09 en-HK Release 8.1 + + English India 0x4009 en-IN Release V + + English Ireland 0x1809 en-IE Release A + + English Isle of Man 0x1000 en-IM Release 10 + + English Israel 0x1000 en-IL Release 10.1 + + English Jamaica 0x2009 en-JM Release B + + + + 37 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English Jersey 0x1000 en-JE Release 10 + + English Kenya 0x1000 en-KE Release 10 + + English Kiribati 0x1000 en-KI Release 10 + + English Lesotho 0x1000 en-LS Release 10 + + English Liberia 0x1000 en-LR Release 10 + + English Macao SAR 0x1000 en-MO Release 10 + + English Madagascar 0x1000 en-MG Release 10 + + English Malawi 0x1000 en-MW Release 10 + + English Malaysia 0x4409 en-MY Release V + + English Maldives 0x1000 en-MV Release 11 + + English Malta 0x1000 en-MT Release 10 + + English Marshall Islands 0x1000 en-MH Release 10 + + English Mauritius 0x1000 en-MU Release 10 + + English Micronesia 0x1000 en-FM Release 10 + + English Montserrat 0x1000 en-MS Release 10 + + English Namibia 0x1000 en-NA Release 10 + + English Nauru 0x1000 en-NR Release 10 + + English Netherlands 0x1000 en-NL Release 10.1 + + English New Zealand 0x1409 en-NZ Release A + + English Nigeria 0x1000 en-NG Release 10 + + English Niue 0x1000 en-NU Release 10 + + English Norfolk Island 0x1000 en-NF Release 10 + + English Northern Mariana Islands 0x1000 en-MP Release 10 + + English Pakistan 0x1000 en-PK Release 10 + + English Palau 0x1000 en-PW Release 10 + + English Papua New Guinea 0x1000 en-PG Release 10 + + English Pitcairn Islands 0x1000 en-PN Release 10 + + English Puerto Rico 0x1000 en-PR Release 10 + + English Republic of the Philippines 0x3409 en-PH Release C + + English Rwanda 0x1000 en-RW Release 10 + + English Saint Kitts and Nevis 0x1000 en-KN Release 10 + + + + 38 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English Saint Lucia 0x1000 en-LC Release 10 + + English Saint Vincent and the Grenadines 0x1000 en-VC Release 10 + + English Samoa 0x1000 en-WS Release 10 + + English Seychelles 0x1000 en-SC Release 10 + + English Sierra Leone 0x1000 en-SL Release 10 + + English Singapore 0x4809 en-SG Release V + + English Sint Maarten 0x1000 en-SX Release 10 + + English Slovenia 0x1000 en-SI Release 10.1 + + English Solomon Islands 0x1000 en-SB Release 10 + + English South Africa 0x1C09 en-ZA Release B + + English South Sudan 0x1000 en-SS Release 10 + + English St Helena, Ascension, Tristan da 0x1000 en-SH Release 10 + Cunha + + English Sudan 0x1000 en-SD Release 10 + + English Swaziland 0x1000 en-SZ Release 10 + + English Sweden 0x1000 en-SE Release 10.1 + + English Switzerland 0x1000 en-CH Release 10.1 + + English Tanzania 0x1000 en-TZ Release 10 + + English Tokelau 0x1000 en-TK Release 10 + + English Tonga 0x1000 en-TO Release 10 + + English Trinidad and Tobago 0x2c09 en-TT Release B + + English Turks and Caicos Islands 0x1000 en-TC Release 10 + + English Tuvalu 0x1000 en-TV Release 10 + + English Uganda 0x1000 en-UG Release 10 + + English United Arab Emirates 0x4C09 en-AE Release 10.5 + + English United Kingdom 0x0809 en-GB Release A + + English United States 0x0409 en-US Release A + + English US Minor Outlying Islands 0x1000 en-UM Release 10 + + English US Virgin Islands 0x1000 en-VI Release 10 + + English Vanuatu 0x1000 en-VU Release 10 + + English World 0x1000 en-001 Release 10 + + English Zambia 0x1000 en-ZM Release 10 + + + 39 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English Zimbabwe 0x3009 en-ZW Release C + + Esperanto 0x1000 eo Release 10 + + Esperanto World 0x1000 eo-001 Release 10 + + Estonian 0x0025 et Release 7 + + Estonian Estonia 0x0425 et-EE Release B + + Ewe 0x1000 ee Release 10 + + Ewe Ghana 0x1000 ee-GH Release 10 + + Ewe Togo 0x1000 ee-TG Release 10 + + Ewondo 0x1000 ewo Release 10 + + Ewondo Cameroon 0x1000 ewo-CM Release 10 + + Faroese 0x0038 fo Release 7 + + Faroese Denmark 0x1000 fo-DK Release 10.1 + + Faroese Faroe Islands 0x0438 fo-FO Release B + + Filipino 0x0064 fil Release 7 + + Filipino Philippines 0x0464 fil-PH Release E2 + + Finnish 0x000B fi Release 7 + + Finnish Finland 0x040B fi-FI Release A + + French 0x000C fr Release 7 + + French Algeria 0x1000 fr-DZ Release 10 + + French Belgium 0x080C fr-BE Release A + + French Benin 0x1000 fr-BJ Release 10 + + French Burkina Faso 0x1000 fr-BF Release 10 + + French Burundi 0x1000 fr-BI Release 10 + + French Cameroon 0x2c0C fr-CM Release 8.1 + + French Canada 0x0c0C fr-CA Release A + + French Caribbean 0x1C0C fr-029 Release 10 + + French Central African Republic 0x1000 fr-CF Release 10 + + French Chad 0x1000 fr-TD Release 10 + + French Comoros 0x1000 fr-KM Release 10 + + French Congo 0x1000 fr-CG Release 10 + + French Congo, DRC 0x240C fr-CD Release 8.1 + + + + 40 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + French Côte d'Ivoire 0x300C fr-CI Release 8.1 + + French Djibouti 0x1000 fr-DJ Release 10 + + French Equatorial Guinea 0x1000 fr-GQ Release 10 + + French France 0x040C fr-FR Release A + + French French Guiana 0x1000 fr-GF Release 10 + + French French Polynesia 0x1000 fr-PF Release 10 + + French Gabon 0x1000 fr-GA Release 10 + + French Guadeloupe 0x1000 fr-GP Release 10 + + French Guinea 0x1000 fr-GN Release 10 + + French Haiti 0x3c0C fr-HT Release 8.1 + + French Luxembourg 0x140C fr-LU Release A + + French Madagascar 0x1000 fr-MG Release 10 + + French Mali 0x340C fr-ML Release 8.1 + + French Martinique 0x1000 fr-MQ Release 10 + + French Mauritania 0x1000 fr-MR Release 10 + + French Mauritius 0x1000 fr-MU Release 10 + + French Mayotte 0x1000 fr-YT Release 10 + + French Morocco 0x380C fr-MA Release 8.1 + + French New Caledonia 0x1000 fr-NC Release 10 + + French Niger 0x1000 fr-NE Release 10 + + French Principality of Monaco 0x180C fr-MC Release A + + French Reunion 0x200C fr-RE Release 8.1 + + French Rwanda 0x1000 fr-RW Release 10 + + French Saint Barthélemy 0x1000 fr-BL Release 10 + + French Saint Martin 0x1000 fr-MF Release 10 + + French Saint Pierre and Miquelon 0x1000 fr-PM Release 10 + + French Senegal 0x280C fr-SN Release 8.1 + + French Seychelles 0x1000 fr-SC Release 10 + + French Switzerland 0x100C fr-CH Release A + + French Syria 0x1000 fr-SY Release 10 + + French Togo 0x1000 fr-TG Release 10 + + + + 41 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + French Tunisia 0x1000 fr-TN Release 10 + + French Vanuatu 0x1000 fr-VU Release 10 + + French Wallis and Futuna 0x1000 fr-WF Release 10 + + Frisian 0x0062 fy Release 7 + + Frisian Netherlands 0x0462 fy-NL Release E2 + + Friulian 0x1000 fur Release 10 + + Friulian Italy 0x1000 fur-IT Release 10 + + Fulah 0x0067 ff Release 8 + + Fulah (Latin) 0x7C67 ff-Latn Release 8 + + Fulah (Latin) Burkina Faso 0x1000 ff-Latn-BF Release 10.4 + + Fulah Cameroon 0x1000 ff-CM Release 10 + + Fulah (Latin) Cameroon 0x1000 ff-Latn-CM Release 10.4 + + Fulah (Latin) Gambia 0x1000 ff-Latn-GM Release 10.4 + + Fulah (Latin) Ghana 0x1000 ff-Latn-GH Release 10.4 + + Fulah Guinea 0x1000 ff-GN Release 10 + + Fulah (Latin) Guinea 0x1000 ff-Latn-GN Release 10.4 + + Fulah (Latin) Guinea-Bissau 0x1000 ff-Latn-GW Release 10.4 + + Fulah (Latin) Liberia 0x1000 ff-Latn-LR Release 10.4 + + Fulah Mauritania 0x1000 ff-MR Release 10 + + Fulah (Latin) Mauritania 0x1000 ff-Latn-MR Release 10.4 + + Fulah (Latin) Niger 0x1000 ff-Latn-NE Release 10.4 + + Fulah Nigeria 0x0467 ff-NG Release 10 + + Fulah (Latin) Nigeria 0x0467 ff-Latn-NG Release 10.4 + + Fulah Senegal 0x0867 ff-Latn-SN Release 8 + + Fulah (Latin) Sierra Leone 0x1000 ff-Latn-SL Release 10.4 + + Galician 0x0056 gl Release 7 + + Galician Spain 0x0456 gl-ES Release D + + Ganda 0x1000 lg Release 10 + + Ganda Uganda 0x1000 lg-UG Release 10 + + Georgian 0x0037 ka Release 7 + + Georgian Georgia 0x0437 ka-GE Release C + + + + 42 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + German 0x0007 de Release 7 + + German Austria 0x0C07 de-AT Release A + + German Belgium 0x1000 de-BE Release 10 + + German Germany 0x0407 de-DE Release A + + German Italy 0x1000 de-IT Release 10.2 + + German Liechtenstein 0x1407 de-LI Release B + + German Luxembourg 0x1007 de-LU Release B + + German Switzerland 0x0807 de-CH Release A + + Greek 0x0008 el Release 7 + + Greek Cyprus 0x1000 el-CY Release 10 + + Greek Greece 0x0408 el-GR Release A + + Greenlandic 0x006F kl Release 7 + + Greenlandic Greenland 0x046F kl-GL Release V + + Guarani 0x0074 gn Release 8.1 + + Guarani Paraguay 0x0474 gn-PY Release 8.1 + + Gujarati 0x0047 gu Release 7 + + Gujarati India 0x0447 gu-IN Release D + + Gusii 0x1000 guz Release 10 + + Gusii Kenya 0x1000 guz-KE Release 10 + + Haryanvi 0x1000 bgc Release 11 + + Haryanvi (Devanagari) 0x1000 bgc-Deva Release 11 + + Haryanvi (Devanagari) India 0x1000 bgc-Deva-IN Release 11 + + Hausa (Latin) 0x0068 ha Release 7 + + Hausa (Latin) 0x7C68 ha-Latn Windows 7 + + Hausa (Latin) Ghana 0x1000 ha-Latn-GH Release 10 + + Hausa (Latin) Niger 0x1000 ha-Latn-NE Release 10 + + Hausa (Latin) Nigeria 0x0468 ha-Latn-NG Release V + + Hawaiian 0x0075 haw Release 8 + + Hawaiian United States 0x0475 haw-US Release 8 + + Hebrew 0x000D he Release 7 + + Hebrew Israel 0x040D he-IL Release B + + + + 43 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Hindi 0x0039 hi Release 7 + + Hindi India 0x0439 hi-IN Release C + + Hindi (Latin) 0x1000 hi-Latn Release 11 + + Hindi (Latin) India 0x1000 hi-Latn-IN Release 11 + + Hungarian 0x000E hu Release 7 + + Hungarian Hungary 0x040E hu-HU Release A + + Icelandic 0x000F is Release 7 + + Icelandic Iceland 0x040F is-IS Release A + + Igbo 0x0070 ig Release 7 + + Igbo Nigeria 0x0470 ig-NG Release V + + Indonesian 0x0021 id Release 7 + + Indonesian Indonesia 0x0421 id-ID Release B + + Interlingua 0x1000 ia Release 10 + + Interlingua France 0x1000 ia-FR Release 10 + + Interlingua World 0x1000 ia-001 Release 10 + + Inuktitut (Latin) 0x005D iu Release 7 + + Inuktitut (Latin) 0x7C5D iu-Latn Windows 7 + + Inuktitut (Latin) Canada 0x085D iu-Latn-CA Release E2 + + Inuktitut (Syllabics) 0x785D iu-Cans Windows 7 + + Inuktitut (Syllabics) Canada 0x045d iu-Cans-CA Release V + + Irish 0x003C ga Windows 7 + + Irish Ireland 0x083C ga-IE Release E2 + + Italian 0x0010 it Release 7 + + Italian Italy 0x0410 it-IT Release A + + Italian San Marino 0x1000 it-SM Release 10 + + Italian Switzerland 0x0810 it-CH Release A + + Italian Vatican City 0x1000 it-VA Release 10.3 + + Japanese 0x0011 ja Release 7 + + Japanese Japan 0x0411 ja-JP Release A + + Javanese 0x1000 jv Release 8.1 + + Javanese Latin 0x1000 jv-Latn Release 8.1 + + + + 44 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Javanese Latin, Indonesia 0x1000 jv-Latn-ID Release 8.1 + + Jola-Fonyi 0x1000 dyo Release 10 + + Jola-Fonyi Senegal 0x1000 dyo-SN Release 10 + + Kabuverdianu 0x1000 kea Release 10 + + Kabuverdianu Cabo Verde 0x1000 kea-CV Release 10 + + Kabyle 0x1000 kab Release 10 + + Kabyle Algeria 0x1000 kab-DZ Release 10 + + Kaingang 0x1000 kgp Release 11 + + Kaingang (Latin) 0x1000 kgp-Latn Release 11 + + Kaingang (Latin) Brazil 0x1000 kgp-Latn-BR Release 11 + + Kako 0x1000 kkj Release 10 + + Kako Cameroon 0x1000 kkj-CM Release 10 + + Kalenjin 0x1000 kln Release 10 + + Kalenjin Kenya 0x1000 kln-KE Release 10 + + Kamba 0x1000 kam Release 10 + + Kamba Kenya 0x1000 kam-KE Release 10 + + Kannada 0x004B kn Release 7 + + Kannada India 0x044B kn-IN Release D + + Kanuri (Latin) Nigeria 0x0471 kr-Latn-NG Release 10 + + Kashmiri 0x0060 ks Release 10 + + Kashmiri Perso-Arabic 0x0460 ks-Arab Release 10 + + Kashmiri Perso-Arabic 0x1000 ks-Arab-IN Release 10 + + Kashmiri (Devanagari) India 0x0860 ks-Deva-IN Release 10 + + Kazakh 0x003F kk Release 7 + + Kazakh Kazakhstan 0x043F kk-KZ Release C + + Khmer 0x0053 km Release 7 + + Khmer Cambodia 0x0453 km-KH Release V + + K'iche 0x0086 quc Release 10 + + K'iche Guatemala 0x0486 quc-Latn-GT Release 10 + + Kikuyu 0x1000 ki Release 10 + + Kikuyu Kenya 0x1000 ki-KE Release 10 + + + + 45 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Kinyarwanda 0x0087 rw Release 7 + + Kinyarwanda Rwanda 0x0487 rw-RW Release V + + Kiswahili 0x0041 sw Release 7 + + Kiswahili Kenya 0x0441 sw-KE Release C + + Kiswahili Tanzania 0x1000 sw-TZ Release 10 + + Kiswahili Uganda 0x1000 sw-UG Release 10 + + Konkani 0x0057 kok Release 7 + + Konkani India 0x0457 kok-IN Release C + + Korean 0x0012 ko Release 7 + + Korean Korea 0x0412 ko-KR Release A + + Korean North Korea 0x1000 ko-KP Release 10.1 + + Koyra Chiini 0x1000 khq Release 10 + + Koyra Chiini Mali 0x1000 khq-ML Release 10 + + Koyraboro Senni 0x1000 ses Release 10 + + Koyraboro Senni Mali 0x1000 ses-ML Release 10 + + Kwasio 0x1000 nmg Release 10 + + Kwasio Cameroon 0x1000 nmg-CM Release 10 + + Kyrgyz 0x0040 ky Release 7 + + Kyrgyz Kyrgyzstan 0x0440 ky-KG Release D + + Kurdish Perso-Arabic, Iran 0x1000 ku-Arab-IR Release 10.1 + + Lakota 0x1000 lkt Release 10 + + Lakota United States 0x1000 lkt-US Release 10 + + Langi 0x1000 lag Release 10 + + Langi Tanzania 0x1000 lag-TZ Release 10 + + Lao 0x0054 lo Release 7 + + Lao Lao P.D.R. 0x0454 lo-LA Release V + + Latin Vatican City 0x0476 la-VA Release 10.5 + + Latvian 0x0026 lv Release 7 + + Latvian Latvia 0x0426 lv-LV Release B + + Lingala 0x1000 ln Release 10 + + Lingala Angola 0x1000 ln-AO Release 10 + + + + 46 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Lingala Central African Republic 0x1000 ln-CF Release 10 + + Lingala Congo 0x1000 ln-CG Release 10 + + Lingala Congo DRC 0x1000 ln-CD Release 10 + + Lithuanian 0x0027 lt Release 7 + + Lithuanian Lithuania 0x0427 lt-LT Release B + + Low German 0x1000 nds Release 10.2 + + Low German Germany 0x1000 nds-DE Release 10.2 + + Low German Netherlands 0x1000 nds-NL Release 10.2 + + Lower Sorbian 0x7C2E dsb Windows 7 + + Lower Sorbian Germany 0x082E dsb-DE Release V + + Luba-Katanga 0x1000 lu Release 10 + + Luba-Katanga Congo DRC 0x1000 lu-CD Release 10 + + Luo 0x1000 luo Release 10 + + Luo Kenya 0x1000 luo-KE Release 10 + + Luxembourgish 0x006E lb Release 7 + + Luxembourgish Luxembourg 0x046E lb-LU Release E2 + + Luyia 0x1000 luy Release 10 + + Luyia Kenya 0x1000 luy-KE Release 10 + + Macedonian 0x002F mk Release 7 + + Macedonian North Macedonia 0x042F mk-MK Release C + + Machame 0x1000 jmc Release 10 + + Machame Tanzania 0x1000 jmc-TZ Release 10 + + Makhuwa-Meetto 0x1000 mgh Release 10 + + Makhuwa-Meetto Mozambique 0x1000 mgh-MZ Release 10 + + Makonde 0x1000 kde Release 10 + + Makonde Tanzania 0x1000 kde-TZ Release 10 + + Malagasy 0x1000 mg Release 8.1 + + Malagasy Madagascar 0x1000 mg-MG Release 8.1 + + Malay 0x003E ms Release 7 + + Malay Brunei Darussalam 0x083E ms-BN Release C + + Malay Malaysia 0x043E ms-MY Release C + + + + 47 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Malayalam 0x004C ml Release 7 + + Malayalam India 0x044C ml-IN Release E1 + + Maltese 0x003A mt Release 7 + + Maltese Malta 0x043A mt-MT Release E1 + + Manx 0x1000 gv Release 10 + + Manx Isle of Man 0x1000 gv-IM Release 10 + + Maori 0x0081 mi Release 7 + + Maori New Zealand 0x0481 mi-NZ Release E1 + + Mapudungun 0x007A arn Release 7 + + Mapudungun Chile 0x047A arn-CL Release E2 + + Marathi 0x004E mr Release 7 + + Marathi India 0x044E mr-IN Release C + + Masai 0x1000 mas Release 10 + + Masai Kenya 0x1000 mas-KE Release 10 + + Masai Tanzania 0x1000 mas-TZ Release 10 + + Mazanderani Iran 0x1000 mzn-IR Release 10.1 + + Meru 0x1000 mer Release 10 + + Meru Kenya 0x1000 mer-KE Release 10 + + Meta' 0x1000 mgo Release 10 + + Meta' Cameroon 0x1000 mgo-CM Release 10 + + Mohawk 0x007C moh Release 7 + + Mohawk Canada 0x047C moh-CA Release E2 + + Mongolian (Cyrillic) 0x0050 mn Release 7 + + Mongolian (Cyrillic) 0x7850 mn-Cyrl Windows 7 + + Mongolian (Cyrillic) Mongolia 0x0450 mn-MN Release D + + Mongolian (Traditional 0x7C50 mn-Mong Windows 7 + Mongolian) + + Mongolian (Traditional People's Republic of China 0x0850 mn-Mong- Release V + Mongolian) CN + + Mongolian (Traditional Mongolia 0x0C50 mn-Mong- Windows 7 + Mongolian) MN + + Morisyen 0x1000 mfe Release 10 + + Morisyen Mauritius 0x1000 mfe-MU Release 10 + + + 48 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Mundang 0x1000 mua Release 10 + + Mundang Cameroon 0x1000 mua-CM Release 10 + + N'ko 0x1000 nqo Release 8.1 + + N'ko Guinea 0x1000 nqo-GN Release 8.1 + + Nama 0x1000 naq Release 10 + + Nama Namibia 0x1000 naq-NA Release 10 + + Nepali 0x0061 ne Release 7 + + Nepali India 0x0861 ne-IN Release 8.1 + + Nepali Nepal 0x0461 ne-NP Release E2 + + Ngiemboon 0x1000 nnh Release 10 + + Ngiemboon Cameroon 0x1000 nnh-CM Release 10 + + Ngomba 0x1000 jgo Release 10 + + Ngomba Cameroon 0x1000 jgo-CM Release 10 + + Nheengatu 0x1000 yrl Release 11 + + Nheengatu (Latin) 0x1000 yrl-Latn Release 11 + + Nheengatu (Latin) Brazil 0x1000 yrl-Latn-BR Release 11 + + Nheengatu (Latin) Colombia 0x1000 yrl-Latn-CO Release 11 + + Nheengatu (Latin) Venezuela 0x1000 yrl-Latn-VE Release 11 + + Northern Luri Iraq 0x1000 lrc-IQ Release 10.1 + + Northern Luri Iran 0x1000 lrc-IR Release 10.1 + + North Ndebele 0x1000 nd Release 10 + + North Ndebele Zimbabwe 0x1000 nd-ZW Release 10 + + Norwegian (Bokmal) 0x0014 no Release 7 + + Norwegian (Bokmal) 0x7C14 nb Release 7 + + Norwegian (Bokmal) Norway 0x0414 nb-NO Release A + + Norwegian (Nynorsk) 0x7814 nn Release 7 + + Norwegian (Nynorsk) Norway 0x0814 nn-NO Release A + + Norwegian Bokmål Svalbard and Jan Mayen 0x1000 nb-SJ Release 10 + + Nuer 0x1000 nus Release 10 + + Nuer Sudan 0x1000 nus-SD Release 10 + + Nuer South Sudan 0x1000 nus-SS Release 10.1 + + + + 49 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Nyankole 0x1000 nyn Release 10 + + Nyankole Uganda 0x1000 nyn-UG Release 10 + + Occitan 0x0082 oc Release 7 + + Occitan France 0x0482 oc-FR Release V + + Occitan Spain 0x1000 oc-ES Release 11 + + Odia 0x0048 or Release 7 + + Odia India 0x0448 or-IN Release V + + Oromo 0x0072 om Release 8.1 + + Oromo Ethiopia 0x0472 om-ET Release 8.1 + + Oromo Kenya 0x1000 om-KE Release 10 + + Ossetian 0x1000 os Release 10 + + Ossetian Cyrillic, Georgia 0x1000 os-GE Release 10 + + Ossetian Cyrillic, Russia 0x1000 os-RU Release 10 + + Pashto 0x0063 ps Release 7 + + Pashto Afghanistan 0x0463 ps-AF Release E2 + + Pashto Pakistan 0x1000 ps-PK Release 10.5 + + Persian 0x0029 fa Release 7 + + Persian Afghanistan 0x1000 fa-AF Release 10 + + Persian Iran 0x0429 fa-IR Release B + + Polish 0x0015 pl Release 7 + + Polish Poland 0x0415 pl-PL Release A + + Portuguese 0x0016 pt Release 7 + + Portuguese Angola 0x1000 pt-AO Release 8.1 + + Portuguese Brazil 0x0416 pt-BR Release A + + Portuguese Cabo Verde 0x1000 pt-CV Release 10 + + Portuguese Equatorial Guinea 0x1000 pt-GQ Release 10.2 + + Portuguese Guinea-Bissau 0x1000 pt-GW Release 10 + + Portuguese Luxembourg 0x1000 pt-LU Release 10.2 + + Portuguese Macao SAR 0x1000 pt-MO Release 10 + + Portuguese Mozambique 0x1000 pt-MZ Release 10 + + Portuguese Portugal 0x0816 pt-PT Release A + + + + 50 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Portuguese São Tomé and Príncipe 0x1000 pt-ST Release 10 + + Portuguese Switzerland 0x1000 pt-CH Release 10.2 + + Portuguese Timor-Leste 0x1000 pt-TL Release 10 + + Prussian 0x1000 prg-001 Release 10.1 + + Pseudo Language Pseudo locale for east Asian/complex 0x05FE qps-ploca Release 7 + script localization testing + + Pseudo Language Pseudo locale used for localization 0x0501 qps-ploc Release 7 + testing + + Pseudo Language Pseudo locale used for localization 0x09FF qps-plocm Release 7 + testing of mirrored locales + + Punjabi 0x0046 pa Release 7 + + Punjabi 0x7C46 pa-Arab Release 8 + + Punjabi India 0x0446 pa-IN Release D + + Punjabi Islamic Republic of Pakistan 0x0846 pa-Arab-PK Release 8 + + Quechua 0x006B quz Release 7 + + Quechua Bolivia 0x046B quz-BO Release E1 + + Quechua Ecuador 0x086B quz-EC Release E1 + + Quechua Peru 0x0C6B quz-PE Release E1 + + Rajasthani 0x1000 raj Release 11 + + Rajasthani 0x1000 raj-Deva Release 11 + (Devanagari) + + Rajasthani India 0x1000 raj-Deva-IN Release 11 + (Devanagari) + + Ripuarian 0x1000 ksh Release 10 + + Ripuarian Germany 0x1000 ksh-DE Release 10 + + Romanian 0x0018 ro Release 7 + + Romanian Moldova 0x0818 ro-MD Release 8.1 + + Romanian Romania 0x0418 ro-RO Release A + + Romansh 0x0017 rm Release 7 + + Romansh Switzerland 0x0417 rm-CH Release E2 + + Rombo 0x1000 rof Release 10 + + Rombo Tanzania 0x1000 rof-TZ Release 10 + + Rundi 0x1000 rn Release 10 + + Rundi Burundi 0x1000 rn-BI Release 10 + + + 51 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Russian 0x0019 ru Release 7 + + Russian Belarus 0x1000 ru-BY Release 10 + + Russian Kazakhstan 0x1000 ru-KZ Release 10 + + Russian Kyrgyzstan 0x1000 ru-KG Release 10 + + Russian Moldova 0x0819 ru-MD Release 10 + + Russian Russia 0x0419 ru-RU Release A + + Russian Ukraine 0x1000 ru-UA Release 10 + + Rwa 0x1000 rwk Release 10 + + Rwa Tanzania 0x1000 rwk-TZ Release 10 + + Saho 0x1000 ssy Release 10 + + Saho Eritrea 0x1000 ssy-ER Release 10 + + Sakha 0x0085 sah Release 7 + + Sakha Russia 0x0485 sah-RU Release V + + Samburu 0x1000 saq Release 10 + + Samburu Kenya 0x1000 saq-KE Release 10 + + Sami (Inari) 0x703B smn Windows 7 + + Sami (Inari) Finland 0x243B smn-FI Release E1 + + Sami (Lule) 0x7C3B smj Windows 7 + + Sami (Lule) Norway 0x103B smj-NO Release E1 + + Sami (Lule) Sweden 0x143B smj-SE Release E1 + + Sami (Northern) 0x003B se Release 7 + + Sami (Northern) Finland 0x0C3B se-FI Release E1 + + Sami (Northern) Norway 0x043B se-NO Release E1 + + Sami (Northern) Sweden 0x083B se-SE Release E1 + + Sami (Skolt) 0x743B sms Windows 7 + + Sami (Skolt) Finland 0x203B sms-FI Release E1 + + Sami (Southern) 0x783B sma Windows 7 + + Sami (Southern) Norway 0x183B sma-NO Release E1 + + Sami (Southern) Sweden 0x1C3B sma-SE Release E1 + + Sango 0x1000 sg Release 10 + + Sango Central African Republic 0x1000 sg-CF Release 10 + + + + 52 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Sangu 0x1000 sbp Release 10 + + Sangu Tanzania 0x1000 sbp-TZ Release 10 + + Sanskrit 0x004F sa Release 7 + + Sanskrit India 0x044F sa-IN Release C + + Sardinian 0x1000 sc Release 11 + + Sardinian (Latin) 0x1000 sc-Latn Release 11 + + Sardinian (Latin) Italy 0x1000 sc-Latn-IT Release 11 + + Scottish Gaelic 0x0091 gd Windows 7 + + Scottish Gaelic United Kingdom 0x0491 gd-GB Release 7 + + Sena 0x1000 seh Release 10 + + Sena Mozambique 0x1000 seh-MZ Release 10 + + Serbian (Cyrillic) 0x6C1A sr-Cyrl Windows 7 + + Serbian (Cyrillic) Bosnia and Herzegovina 0x1C1A sr-Cyrl-BA Release E1 + + Serbian (Cyrillic) Montenegro 0x301A sr-Cyrl-ME Release 7 + + Serbian (Cyrillic) Serbia 0x281A sr-Cyrl-RS Release 7 + + Serbian (Cyrillic) Serbia and Montenegro (Former) 0x0C1A sr-Cyrl-CS Release B + + Serbian (Latin) 0x701A sr-Latn Windows 7 + + Serbian (Latin) 0x7C1A sr Release 7 + + Serbian (Latin) Bosnia and Herzegovina 0x181A sr-Latn-BA Release E1 + + Serbian (Latin) Montenegro 0x2c1A sr-Latn-ME Release 7 + + Serbian (Latin) Serbia 0x241A sr-Latn-RS Release 7 + + Serbian (Latin) Serbia and Montenegro (Former) 0x081A sr-Latn-CS Release B + + Sesotho sa Leboa 0x006C nso Release 7 + + Sesotho sa Leboa South Africa 0x046C nso-ZA Release E1 + + Setswana 0x0032 tn Release 7 + + Setswana Botswana 0x0832 tn-BW Release 8 + + Setswana South Africa 0x0432 tn-ZA Release E1 + + Shambala 0x1000 ksb Release 10 + + Shambala Tanzania 0x1000 ksb-TZ Release 10 + + Shona 0x1000 sn Release 8.1 + + Shona Latin 0x1000 sn-Latn Release 8.1 + + + + 53 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Shona Zimbabwe 0x1000 sn-Latn-ZW Release 8.1 + + Sindhi 0x0059 sd Release 8 + + Sindhi 0x7C59 sd-Arab Release 8 + + Sindhi Islamic Republic of Pakistan 0x0859 sd-Arab-PK Release 8 + + Sinhala 0x005B si Release 7 + + Sinhala Sri Lanka 0x045B si-LK Release V + + Slovak 0x001B sk Release 7 + + Slovak Slovakia 0x041B sk-SK Release A + + Slovenian 0x0024 sl Release 7 + + Slovenian Slovenia 0x0424 sl-SI Release A + + Soga 0x1000 xog Release 10 + + Soga Uganda 0x1000 xog-UG Release 10 + + Somali 0x0077 so Release 8.1 + + Somali Djibouti 0x1000 so-DJ Release 10 + + Somali Ethiopia 0x1000 so-ET Release 10 + + Somali Kenya 0x1000 so-KE Release 10 + + Somali Somalia 0x0477 so-SO Release 8.1 + + Sotho 0x0030 st Release 8.1 + + Sotho South Africa 0x0430 st-ZA Release 8.1 + + South Ndebele 0x1000 nr Release 10 + + South Ndebele South Africa 0x1000 nr-ZA Release 10 + + Southern Sotho Lesotho 0x1000 st-LS Release 10 + + Spanish 0x000A es Release 7 + + Spanish Argentina 0x2C0A es-AR Release B + + Spanish Belize 0x1000 es-BZ Release 10.3 + + Spanish Bolivarian Republic of Venezuela 0x200A es-VE Release B + + Spanish Bolivia 0x400A es-BO Release B + + Spanish Brazil 0x1000 es-BR Release 10.2 + + Spanish Chile 0x340A es-CL Release B + + Spanish Colombia 0x240A es-CO Release B + + Spanish Costa Rica 0x140A es-CR Release B + + + + 54 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Spanish Cuba 0x5c0A es-CU Release 10 + + Spanish Dominican Republic 0x1c0A es-DO Release B + + Spanish Ecuador 0x300A es-EC Release B + + Spanish El Salvador 0x440A es-SV Release B + + Spanish Equatorial Guinea 0x1000 es-GQ Release 10 + + Spanish Guatemala 0x100A es-GT Release B + + Spanish Honduras 0x480A es-HN Release B + + Spanish Latin America 0x580A es-419 Release 8.1 + + Spanish Mexico 0x080A es-MX Release A + + Spanish Nicaragua 0x4C0A es-NI Release B + + Spanish Panama 0x180A es-PA Release B + + Spanish Paraguay 0x3C0A es-PY Release B + + Spanish Peru 0x280A es-PE Release B + + Spanish Philippines 0x1000 es-PH Release 10 + + Spanish Puerto Rico 0x500A es-PR Release B + + Spanish Spain 0x040A es-ES_tradnl Release A + + Spanish Spain 0x0c0A es-ES Release A + + Spanish United States 0x540A es-US Release V + + Spanish Uruguay 0x380A es-UY Release B + + Standard Moroccan 0x1000 zgh Release 8.1 + Tamazight + + Standard Moroccan Morocco 0x1000 zgh-Tfng-MA Release 8.1 + Tamazight + + Standard Moroccan Tifinagh 0x1000 zgh-Tfng Release 8.1 + Tamazight + + Swati 0x1000 ss Release 10 + + Swati South Africa 0x1000 ss-ZA Release 10 + + Swati Swaziland 0x1000 ss-SZ Release 10 + + Swedish 0x001D sv Release 7 + + Swedish Åland Islands 0x1000 sv-AX Release 10 + + Swedish Finland 0x081D sv-FI Release B + + Swedish Sweden 0x041D sv-SE Release A + + Syriac 0x005A syr Release 7 + + + 55 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Syriac Syria 0x045A syr-SY Release D + + Tachelhit 0x1000 shi Release 10 + + Tachelhit Tifinagh 0x1000 shi-Tfng Release 10 + + Tachelhit Tifinagh, Morocco 0x1000 shi-Tfng-MA Release 10 + + Tachelhit (Latin) 0x1000 shi-Latn Release 10 + + Tachelhit (Latin) Morocco 0x1000 shi-Latn-MA Release 10 + + Taita 0x1000 dav Release 10 + + Taita Kenya 0x1000 dav-KE Release 10 + + Tajik (Cyrillic) 0x0028 tg Release 7 + + Tajik (Cyrillic) 0x7C28 tg-Cyrl Windows 7 + + Tajik (Cyrillic) Tajikistan 0x0428 tg-Cyrl-TJ Release V + + Tamazight (Latin) 0x005F tzm Release 7 + + Tamazight (Latin) 0x7C5F tzm-Latn Windows 7 + + Tamazight (Latin) Algeria 0x085F tzm-Latn-DZ Release V + + Tamil 0x0049 ta Release 7 + + Tamil India 0x0449 ta-IN Release C + + Tamil Malaysia 0x1000 ta-MY Release 10 + + Tamil Singapore 0x1000 ta-SG Release 10 + + Tamil Sri Lanka 0x0849 ta-LK Release 8 + + Tasawaq 0x1000 twq Release 10 + + Tasawaq Niger 0x1000 twq-NE Release 10 + + Tatar 0x0044 tt Release 7 + + Tatar Russia 0x0444 tt-RU Release D + + Telugu 0x004A te Release 7 + + Telugu India 0x044A te-IN Release D + + Teso 0x1000 teo Release 10 + + Teso Kenya 0x1000 teo-KE Release 10 + + Teso Uganda 0x1000 teo-UG Release 10 + + Thai 0x001E th Release 7 + + Thai Thailand 0x041E th-TH Release B + + Tibetan 0x0051 bo Release 7 + + + + 56 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Tibetan India 0x1000 bo-IN Release 10 + + Tibetan People's Republic of China 0x0451 bo-CN Release V + + Tigre 0x1000 tig Release 10 + + Tigre Eritrea 0x1000 tig-ER Release 10 + + Tigrinya 0x0073 ti Release 8 + + Tigrinya Eritrea 0x0873 ti-ER Release 8 + + Tigrinya Ethiopia 0x0473 ti-ET Release 8 + + Tongan 0x1000 to Release 10 + + Tongan Tonga 0x1000 to-TO Release 10 + + Tsonga 0x0031 ts Release 8.1 + + Tsonga South Africa 0x0431 ts-ZA Release 8.1 + + Turkish 0x001F tr Release 7 + + Turkish Cyprus 0x1000 tr-CY Release 10 + + Turkish Turkey 0x041F tr-TR Release A + + Turkmen 0x0042 tk Release 7 + + Turkmen Turkmenistan 0x0442 tk-TM Release V + + Ukrainian 0x0022 uk Release 7 + + Ukrainian Ukraine 0x0422 uk-UA Release B + + Upper Sorbian 0x002E hsb Release 7 + + Upper Sorbian Germany 0x042E hsb-DE Release V + + Urdu 0x0020 ur Release 7 + + Urdu India 0x0820 ur-IN Release 8.1 + + Urdu Islamic Republic of Pakistan 0x0420 ur-PK Release C + + Uyghur 0x0080 ug Release 7 + + Uyghur People's Republic of China 0x0480 ug-CN Release V + + Uzbek Perso-Arabic 0x1000 uz-Arab Release 10 + + Uzbek Perso-Arabic, Afghanistan 0x1000 uz-Arab-AF Release 10 + + Uzbek (Cyrillic) 0x7843 uz-Cyrl Windows 7 + + Uzbek (Cyrillic) Uzbekistan 0x0843 uz-Cyrl-UZ Release C + + Uzbek (Latin) 0x0043 uz Release 7 + + Uzbek (Latin) 0x7C43 uz-Latn Windows 7 + + + + 57 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Uzbek (Latin) Uzbekistan 0x0443 uz-Latn-UZ Release C + + Vai 0x1000 vai Release 10 + + Vai 0x1000 vai-Vaii Release 10 + + Vai Liberia 0x1000 vai-Vaii-LR Release 10 + + Vai (Latin) Liberia 0x1000 vai-Latn-LR Release 10 + + Vai (Latin) 0x1000 vai-Latn Release 10 + + Valencian Spain 0x0803 ca-ES- Release 8 + valencia + + Venda 0x0033 ve Release 10 + + Venda South Africa 0x0433 ve-ZA Release 10 + + Vietnamese 0x002A vi Release 7 + + Vietnamese Vietnam 0x042A vi-VN Release B + + Volapük 0x1000 vo Release 10 + + Volapük World 0x1000 vo-001 Release 10 + + Vunjo 0x1000 vun Release 10 + + Vunjo Tanzania 0x1000 vun-TZ Release 10 + + Walser 0x1000 wae Release 10 + + Walser Switzerland 0x1000 wae-CH Release 10 + + Welsh 0x0052 cy Release 7 + + Welsh United Kingdom 0x0452 cy-GB Release E1 + + Wolaytta 0x1000 wal Release 10 + + Wolaytta Ethiopia 0x1000 wal-ET Release 10 + + Wolof 0x0088 wo Release 7 + + Wolof Senegal 0x0488 wo-SN Release V + + Xhosa 0x0034 xh Release 7 + + Xhosa South Africa 0x0434 xh-ZA Release E1 + + Yangben 0x1000 yav Release 10 + + Yangben Cameroon 0x1000 yav-CM Release 10 + + Yi 0x0078 ii Release 7 + + Yi People's Republic of China 0x0478 ii-CN Release V + + Yiddish World 0x043D yi-001 Release 10 + + Yoruba 0x006A yo Release 7 + + + 58 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Yoruba Benin 0x1000 yo-BJ Release 10 + + Yoruba Nigeria 0x046A yo-NG Release V + + Zarma 0x1000 dje Release 10 + + Zarma Niger 0x1000 dje-NE Release 10 + + Zulu 0x0035 zu Release 7 + + Zulu South Africa 0x0435 zu-ZA Release E1 + + + + +<9> Section 2.2: Supported only on Windows 7. + +<10> Section 2.2: Supported only on Windows 7. + +<11> Section 2.2: Supported only on Windows 7. + +<12> Section 2.2: Not supported in client releases earlier than Windows 10 or server releases earlier +than Windows Server 2016. + +<13> Section 2.2: Not supported in client releases earlier than Windows 10 or server releases earlier +than Windows Server 2016. + +<14> Section 2.2.1: The temporary Locale Names without LCID assignments are not supported in +versions before Windows Vista and Windows Server 2008 operating system with Service Pack 2 (SP2). + +<15> Section 2.2.1: Not supported in versions before Windows Vista and Windows Server 2008. + +<16> Section 2.2.1: The Transient LCIDs (0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, +0x3800, 0x3C00, 0x4000, 0x4400, 0x4800, and 0x4C00) were introduced in Windows 8 operating +system and Windows Server 2012 operating system and fail in all prior versions. + +<17> Section 2.2.1: Not supported in versions before Windows Vista and Windows Server 2008. + + + + + 59 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + 6 Change Tracking +This section identifies changes that were made to this document since the last release. Changes are +classified as Major, Minor, or None. + +The revision class Major means that the technical content in the document was significantly revised. +Major changes affect protocol interoperability or implementation. Examples of major changes are: + + A document revision that incorporates changes to interoperability requirements. + A document revision that captures changes to protocol functionality. + +The revision class Minor means that the meaning of the technical content was clarified. Minor changes +do not affect protocol interoperability or implementation. Examples of minor changes are updates to +clarify ambiguity at the sentence, paragraph, or table level. + +The revision class None means that no new technical changes were introduced. Minor editorial and +formatting changes may have been made, but the relevant technical content is identical to the last +released version. + +The changes made to this document are listed in the following table. For more information, please +contact dochelp@microsoft.com. + + Revision + Section Description + class + + 11352 : Added four unassigned locales temporarily assigned to + 2.2 LCID Structure Major + 0x3000. + + Updated for Windows 11 24H2 and Windows Server 2025. + 2.2 LCID Structure Major + Updated the list of neutrals and locales. + + 2.2.1 Locale Names 11352 : Added four unassigned locales temporarily assigned to + Major + without LCIDs 0x3000. + + 5 Appendix A: Product + Added Windows Server 2025 to the product applicability list. Major + Behavior + + + + + 60 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + 7 Index +. + T +.NET - LCIDs as culture identifiers 8 + Tracking changes 60 +A + V +Applicability 7 + Vendor-extensible fields 7 +C Versioning 7 + +Change tracking 60 +Culture identifiers 8 + +E + +Examples 27 +Examples - LCID values 27 + +F + +Fields - vendor-extensible 7 + +G + +Glossary 5 + +I + +Implementer - security considerations 28 +Informative references 6 +Introduction 5 + +L + +LCID packet 8 +Localization 7 + +N + +Normative references 6 + +O + +Overview (synopsis) 6 + +P + +Product behavior 29 + +R + +References 6 + informative 6 + normative 6 +Relationship to protocols and other structures 7 + +S + +Security 28 +Security - implementer considerations 28 + + + 61 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 35a63ad..73c6b8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# CMAkeLists.txt - Main build script for sbc-harness +# CMakeLists.txt - Main build script for sbc-harness project # # Copyright (C) 2024 Luke T. Shumaker # SPDX-Licence-Identifier: AGPL-3.0-or-later @@ -12,23 +12,15 @@ project(sbc_harness) pico_sdk_init() -add_executable(sbc_harness) -target_sources(sbc_harness PUBLIC - main.c - coroutine.c - usb_common.c - usb_keyboard.c +add_custom_target(generate + COMMENT Create generated files that are included in the source distribution ) -target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_LIST_DIR}) # So TinyUSB can find tusb_config.h -target_link_libraries(sbc_harness - pico_stdlib - pico_unique_id - tinyusb_device - tinyusb_board -) -pico_enable_stdio_usb(sbc_harness 0) -pico_enable_stdio_uart(sbc_harness 1) -pico_enable_stdio_semihosting(sbc_harness 0) -pico_enable_stdio_rtt(sbc_harness 0) -pico_add_extra_outputs(sbc_harness) # create map/bin/hex/uf2 file in addition to ELF. -pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness") + +add_subdirectory(libcr) +add_subdirectory(libcr_ipc) +add_subdirectory(libusb) +add_subdirectory(libnetio) +add_subdirectory(lib9p) + +add_subdirectory(cmd/sbc_harness) +add_subdirectory(cmd/srv9p) diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 0000000..1492820 --- /dev/null +++ b/HACKING.md @@ -0,0 +1,10 @@ +Source layout + + - cmd/sbc_harness + - cmd/srv9p + - libcr - A simple coroutine (cooperative multitasking) library + - libcr_ipc - IPC primatives for coroutines built on top of libcr + - libnetio - TODO + - lib9p - A simple 9P protocol server library + - libusb - TODO + diff --git a/PLAN.md b/PLAN.md index da65817..a469acb 100644 --- a/PLAN.md +++ b/PLAN.md @@ -12,3 +12,5 @@ 1. [ ] PicoDVI hello-world 2. [ ] "PiciDVI" to network 3. [ ] reverse the flow of PicoDVI + +https://hackaday.com/2022/08/26/bit-banged-ethernet-on-the-raspberry-pi-pico/ diff --git a/cmd/harness/main.c b/cmd/harness/main.c deleted file mode 100644 index 1fd9f8c..0000000 --- a/cmd/harness/main.c +++ /dev/null @@ -1,48 +0,0 @@ -/* main.c - Main entry point and event loop for sbc-harness - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -/* newlib */ -#include /* for strlen() */ - -/* pico-sdk */ -#include "pico/stdlib.h" - -/* local */ -#include "coroutine.h" -#include "usb_common.h" -#include "usb_keyboard.h" - -COROUTINE hello_world_cr(void *_chan) { - const char *msg = "Hello world!\n"; - usb_keyboard_rpc_t *chan = _chan; - cr_begin(); - - for (size_t i = 0;; i = (i+1) % strlen(msg)) { - cr_rpc_req(chan, NULL, msg[i]); - } - - cr_end(); -} - -int main() { - /* initialization */ - stdio_uart_init(); - //gpio_init(PICO_DEFAULT_LED_PIN); - //gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - - usb_common_earlyinit(); - usb_keyboard_init(); - usb_common_lateinit(); - - /* set up coroutines */ - coroutine_add(usb_common_cr, NULL); - usb_keyboard_rpc_t keyboard_chan = {0}; - coroutine_add(usb_keyboard_cr, &keyboard_chan); - coroutine_add(hello_world_cr, &keyboard_chan); - - /* Event loop. */ - coroutine_main(); -} diff --git a/cmd/harness/usb_keyboard.c b/cmd/harness/usb_keyboard.c deleted file mode 100644 index 1989b35..0000000 --- a/cmd/harness/usb_keyboard.c +++ /dev/null @@ -1,113 +0,0 @@ -/* usb_keyboard.c - Implementation of a USB keyboard device - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#include "tusb.h" - -#include "tusb_helpers.h" /* for TUD_ENDPOINT_IN */ -#include "usb_common.h" -#include "usb_keyboard.h" - -/** - * A USB-HID "Report Descriptor" (see USB-HID 1.11 §6.2.2 "Report - * Descriptor") describing a keyboard. - */ -static uint8_t const hid_report_descriptor_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; - -static uint8_t kbd_ifc = 0; - -void usb_keyboard_init() { - if (kbd_ifc) - return; - usb_common_earlyinit(); - - kbd_ifc = usb_add_interface(cfgnum_std, TUD_HID_DESC_LEN, (uint8_t[]){ - /* USB-HID input-only descriptor for inclusion in the config descriptor; consisting of 3 parts: - * 1. an interface descriptor (USB 2.0 §9.6.5 "Interface"), - * 2. a class-specific (class=HID) descriptor of type HID (USB-HID 1.11 §6.2.1 "HID Descriptor"), - * 3. an endpoint descriptor for inputs (USB 2.0 §9.6.6 "Endpoint"). - * The TUD_HID_DESCRIPTOR() macro takes care of this for us. */ - TUD_HID_DESCRIPTOR( - 0, /* interface : bInterfaceNumber ; Number of this interface (0-indexed) */ - STRID_KBD_IFC, /* interface : iInterface ; Index of string descriptor describing this interface */ - HID_ITF_PROTOCOL_KEYBOARD, /* interface : bInterfaceProtocol ; see USB-HID 1.11 §4.3 "Protocols" */ - sizeof(hid_report_descriptor_keyboard), /* hid : wDescriptorLength ; Total size of report descriptor */ - TUD_ENDPOINT_IN | 1, /* endpoint : bEndpointAddress ; Direction | endpoint number (arbitrary?) */ - CFG_TUD_HID_EP_BUFSIZE, /* endpoint : wMaxPacketSize ; Maximum packet size this endpoint is capable of sending or receiving */ - 10), /* endpoint : bInterval ; poll interval (in milliseconds?) */ - }); -} - -static uint8_t ascii2keycode[128][2] = { HID_ASCII_TO_KEYCODE }; - -COROUTINE usb_keyboard_cr(void *_chan) { - usb_keyboard_rpc_t *chan = _chan; - cr_begin(); - - uint8_t report_id = 0; - uint8_t modifier = 0; - uint8_t keycodes[6] = {0}; - for (;;) { - while (!tud_hid_n_ready(kbd_ifc)) - cr_yield(); - - if (cr_rpc_have_req(chan)) { - uint32_t rune; - cr_rpc_recv_req(chan, &rune); - - modifier = ascii2keycode[rune][0] ? KEYBOARD_MODIFIER_LEFTSHIFT : 0; - keycodes[0] = ascii2keycode[rune][1]; - tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); - - while (!tud_hid_n_ready(kbd_ifc)) - cr_yield(); - - modifier = 0; - keycodes[0] = 0; - tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); - - cr_rpc_send_resp(chan, 1); - } else { - modifier = 0; - keycodes[0] = 0; - tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); - } - } - - cr_end(); -} - -/** - * Return a pointer to the HID "Report Descriptor" (see USB-HID 1.11 - * §6.2.2 "Report Descriptor") for the given index. - */ -uint8_t const *tud_hid_descriptor_report_cb(uint8_t index) { - static uint8_t const *reports[] = { - hid_report_descriptor_keyboard, - }; - if (index >= TU_ARRAY_SIZE(reports)) - return NULL; - return reports[index]; -} - -uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) -{ - // TODO not Implemented - (void) instance; - (void) report_id; - (void) report_type; - (void) buffer; - (void) reqlen; - - return 0; -} - -// Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) -{ - // TODO not implemented - (void) report_id; -} diff --git a/cmd/harness/usb_keyboard.h b/cmd/harness/usb_keyboard.h deleted file mode 100644 index 6b65360..0000000 --- a/cmd/harness/usb_keyboard.h +++ /dev/null @@ -1,17 +0,0 @@ -/* usb_keyboard.h - Implementation of a USB keyboard device - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#ifndef _USB_KEYBOARD_H_ -#define _USB_KEYBOARD_H_ - -#include "coroutine_rpc.h" - -typedef cr_rpc_t(uint32_t, int) usb_keyboard_rpc_t; - -void usb_keyboard_init(void); -COROUTINE usb_keyboard_cr(void *arg); - -#endif /* _USB_KEYBOARD_H_ */ diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt new file mode 100644 index 0000000..34f6360 --- /dev/null +++ b/cmd/sbc_harness/CMakeLists.txt @@ -0,0 +1,23 @@ +# cmd/sbc_harness/CMakeLists.txt - Build script for main sbc_harness.uf2 firmware file +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_executable(sbc_harness + main.c + usb_keyboard.c +) +target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config) +target_link_libraries(sbc_harness + pico_stdlib + pico_unique_id + tinyusb_device + tinyusb_board + libusb +) +pico_enable_stdio_usb(sbc_harness 0) +pico_enable_stdio_uart(sbc_harness 1) +pico_enable_stdio_semihosting(sbc_harness 0) +pico_enable_stdio_rtt(sbc_harness 0) +pico_add_extra_outputs(sbc_harness) # create .map/.bin/.hex/.uf2 files in addition to .elf +pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness") diff --git a/cmd/sbc_harness/config/config.h b/cmd/sbc_harness/config/config.h new file mode 100644 index 0000000..0f0385b --- /dev/null +++ b/cmd/sbc_harness/config/config.h @@ -0,0 +1,54 @@ +/* config.h - Compile-time configuration for sbc_harness + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +/*#include */ + +#if defined(USE_CONFIG_NETIO_POSIX) || defined(USE_CONFIG_COROUTINE) +# define CONFIG_NETIO_NUM_CONNS 8 +#endif +#ifdef USE_CONFIG_NETIO_POSIX +# define CONFIG_NETIO_ISLINUX 1 /* can we use Linux-kernel-specific fcntls? */ +# define CONFIG_NETIO_NUM_PORTS 1 +#endif + +#ifdef USE_CONFIG_COROUTINE +# define CONFIG_COROUTINE_DEFAULT_STACK_SIZE (8*1024) +# define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */ +# define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */ +# define CONFIG_COROUTINE_DEBUG 0 /* bool */ +# define CONFIG_COROUTINE_NUM (1 /* usb_common */ +\ + 1 /* usb_keyboard */ +\ + CONFIG_NETIO_NUM_CONNS /* accept+read */ +\ + (2*CONFIG_NETIO_NUM_CONNS) /* work+write */ ) + /*static_assert((CONFIG_COROUTINE_NUM * CONFIG_COROUTINE_DEFAULT_STACK_SIZE) < (264 * 1024)); */ +#endif + +#ifdef USE_CONFIG_9P +# define CONFIG_9P_PORT 564 + /** + * This max-msg-size is sized so that a Twrite message can return + * 8KiB of data. + * + * This is the same as the default in Plan 9 4e's lib9p; it has the + * comment that "24" is "ample room for Twrite/Rread header + * (iounit)". In fact, the Twrite header is only 23 bytes + * ("size[4] Twrite[1] tag[2] fid[4] offset[8] count[4]") and the + * Rread header is even shorter at 11 bytes ("size[4] Rread[1] + * tag[2] count[4]"), so "24" appears to be the size of the Twrite + * header rounded up to a nice round number. + * + * In older versions of 9P ("9P1"), the max message size was + * defined as part of the protocol specification rather than + * negotiated. In Plan 9 1e it was (8*1024)+128, and was bumped to + * (8*1024)+160 in 2e and 3e. + */ +# define CONFIG_9P_MAX_MSG_SIZE ((8*1024)+24) +# define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */ +#endif + +#endif /* _CONFIG_H */ diff --git a/cmd/sbc_harness/config/tusb_config.h b/cmd/sbc_harness/config/tusb_config.h new file mode 100644 index 0000000..cb1ca3b --- /dev/null +++ b/cmd/sbc_harness/config/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 + * + * 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/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c new file mode 100644 index 0000000..1fd9f8c --- /dev/null +++ b/cmd/sbc_harness/main.c @@ -0,0 +1,48 @@ +/* main.c - Main entry point and event loop for sbc-harness + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +/* newlib */ +#include /* for strlen() */ + +/* pico-sdk */ +#include "pico/stdlib.h" + +/* local */ +#include "coroutine.h" +#include "usb_common.h" +#include "usb_keyboard.h" + +COROUTINE hello_world_cr(void *_chan) { + const char *msg = "Hello world!\n"; + usb_keyboard_rpc_t *chan = _chan; + cr_begin(); + + for (size_t i = 0;; i = (i+1) % strlen(msg)) { + cr_rpc_req(chan, NULL, msg[i]); + } + + cr_end(); +} + +int main() { + /* initialization */ + stdio_uart_init(); + //gpio_init(PICO_DEFAULT_LED_PIN); + //gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + usb_common_earlyinit(); + usb_keyboard_init(); + usb_common_lateinit(); + + /* set up coroutines */ + coroutine_add(usb_common_cr, NULL); + usb_keyboard_rpc_t keyboard_chan = {0}; + coroutine_add(usb_keyboard_cr, &keyboard_chan); + coroutine_add(hello_world_cr, &keyboard_chan); + + /* Event loop. */ + coroutine_main(); +} diff --git a/cmd/sbc_harness/usb_keyboard.c b/cmd/sbc_harness/usb_keyboard.c new file mode 100644 index 0000000..1989b35 --- /dev/null +++ b/cmd/sbc_harness/usb_keyboard.c @@ -0,0 +1,113 @@ +/* usb_keyboard.c - Implementation of a USB keyboard device + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#include "tusb.h" + +#include "tusb_helpers.h" /* for TUD_ENDPOINT_IN */ +#include "usb_common.h" +#include "usb_keyboard.h" + +/** + * A USB-HID "Report Descriptor" (see USB-HID 1.11 §6.2.2 "Report + * Descriptor") describing a keyboard. + */ +static uint8_t const hid_report_descriptor_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; + +static uint8_t kbd_ifc = 0; + +void usb_keyboard_init() { + if (kbd_ifc) + return; + usb_common_earlyinit(); + + kbd_ifc = usb_add_interface(cfgnum_std, TUD_HID_DESC_LEN, (uint8_t[]){ + /* USB-HID input-only descriptor for inclusion in the config descriptor; consisting of 3 parts: + * 1. an interface descriptor (USB 2.0 §9.6.5 "Interface"), + * 2. a class-specific (class=HID) descriptor of type HID (USB-HID 1.11 §6.2.1 "HID Descriptor"), + * 3. an endpoint descriptor for inputs (USB 2.0 §9.6.6 "Endpoint"). + * The TUD_HID_DESCRIPTOR() macro takes care of this for us. */ + TUD_HID_DESCRIPTOR( + 0, /* interface : bInterfaceNumber ; Number of this interface (0-indexed) */ + STRID_KBD_IFC, /* interface : iInterface ; Index of string descriptor describing this interface */ + HID_ITF_PROTOCOL_KEYBOARD, /* interface : bInterfaceProtocol ; see USB-HID 1.11 §4.3 "Protocols" */ + sizeof(hid_report_descriptor_keyboard), /* hid : wDescriptorLength ; Total size of report descriptor */ + TUD_ENDPOINT_IN | 1, /* endpoint : bEndpointAddress ; Direction | endpoint number (arbitrary?) */ + CFG_TUD_HID_EP_BUFSIZE, /* endpoint : wMaxPacketSize ; Maximum packet size this endpoint is capable of sending or receiving */ + 10), /* endpoint : bInterval ; poll interval (in milliseconds?) */ + }); +} + +static uint8_t ascii2keycode[128][2] = { HID_ASCII_TO_KEYCODE }; + +COROUTINE usb_keyboard_cr(void *_chan) { + usb_keyboard_rpc_t *chan = _chan; + cr_begin(); + + uint8_t report_id = 0; + uint8_t modifier = 0; + uint8_t keycodes[6] = {0}; + for (;;) { + while (!tud_hid_n_ready(kbd_ifc)) + cr_yield(); + + if (cr_rpc_have_req(chan)) { + uint32_t rune; + cr_rpc_recv_req(chan, &rune); + + modifier = ascii2keycode[rune][0] ? KEYBOARD_MODIFIER_LEFTSHIFT : 0; + keycodes[0] = ascii2keycode[rune][1]; + tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); + + while (!tud_hid_n_ready(kbd_ifc)) + cr_yield(); + + modifier = 0; + keycodes[0] = 0; + tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); + + cr_rpc_send_resp(chan, 1); + } else { + modifier = 0; + keycodes[0] = 0; + tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); + } + } + + cr_end(); +} + +/** + * Return a pointer to the HID "Report Descriptor" (see USB-HID 1.11 + * §6.2.2 "Report Descriptor") for the given index. + */ +uint8_t const *tud_hid_descriptor_report_cb(uint8_t index) { + static uint8_t const *reports[] = { + hid_report_descriptor_keyboard, + }; + if (index >= TU_ARRAY_SIZE(reports)) + return NULL; + return reports[index]; +} + +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) instance; + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + // TODO not implemented + (void) report_id; +} diff --git a/cmd/sbc_harness/usb_keyboard.h b/cmd/sbc_harness/usb_keyboard.h new file mode 100644 index 0000000..6b65360 --- /dev/null +++ b/cmd/sbc_harness/usb_keyboard.h @@ -0,0 +1,17 @@ +/* usb_keyboard.h - Implementation of a USB keyboard device + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#ifndef _USB_KEYBOARD_H_ +#define _USB_KEYBOARD_H_ + +#include "coroutine_rpc.h" + +typedef cr_rpc_t(uint32_t, int) usb_keyboard_rpc_t; + +void usb_keyboard_init(void); +COROUTINE usb_keyboard_cr(void *arg); + +#endif /* _USB_KEYBOARD_H_ */ diff --git a/cmd/srv9p/CMakeLists.txt b/cmd/srv9p/CMakeLists.txt new file mode 100644 index 0000000..3db8795 --- /dev/null +++ b/cmd/srv9p/CMakeLists.txt @@ -0,0 +1,15 @@ +# cmd/srv9p/CMakeLists.txt - Build script for srv9p test/dev executable +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_executable(srv9p + main.c +) +target_include_directories(srv9p PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config) +target_link_libraries(srv9p + libcr + libcr_ipc + libnetio + lib9p +) diff --git a/cmd/srv9p/config/config.h b/cmd/srv9p/config/config.h new file mode 120000 index 0000000..2edbd7b --- /dev/null +++ b/cmd/srv9p/config/config.h @@ -0,0 +1 @@ +../../sbc_harness/config/config.h \ No newline at end of file diff --git a/config.h b/config.h deleted file mode 100644 index 37bfcbe..0000000 --- a/config.h +++ /dev/null @@ -1,58 +0,0 @@ -/* config.h - Compile-time configuration for sbc-harness - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ -#ifndef _CONFIG_H_ -#define _CONFIG_H_ - -/*#include */ - -#if defined(USE_CONFIG_NETIO_POSIX) || defined(USE_CONFIG_COROUTINE) -# define CONFIG_NETIO_NUM_CONNS 8 -#endif -#ifdef USE_CONFIG_NETIO_POSIX -# define CONFIG_NETIO_ISLINUX 1 /* can we use Linux-kernel-specific fcntls? */ -# define CONFIG_NETIO_NUM_PORTS 1 -#endif - -#ifdef USE_CONFIG_COROUTINE -# define CONFIG_COROUTINE_DEFAULT_STACK_SIZE (8*1024) -# define CONFIG_COROUTINE_MEASURE_STACK 1 /* bool */ -# define CONFIG_COROUTINE_PROTECT_STACK 1 /* bool */ -# define CONFIG_COROUTINE_DEBUG 0 /* bool */ -# define CONFIG_COROUTINE_NUM (1 /* usb_common */ +\ - 1 /* usb_keyboard */ +\ - CONFIG_NETIO_NUM_CONNS /* accept+read */ +\ - (2*CONFIG_NETIO_NUM_CONNS) /* work+write */ ) - /*static_assert((CONFIG_COROUTINE_NUM * CONFIG_COROUTINE_DEFAULT_STACK_SIZE) < (264 * 1024)); */ -#endif - -#ifdef USE_CONFIG_TUSB -# include "tusb_config.h" -#endif - -#ifdef USE_CONFIG_9P -# define CONFIG_9P_PORT 564 - /** - * This max-msg-size is sized so that a Twrite message can return - * 8KiB of data. - * - * This is the same as the default in Plan 9 4e's lib9p; it has the - * comment that "24" is "ample room for Twrite/Rread header - * (iounit)". In fact, the Twrite header is only 23 bytes - * ("size[4] Twrite[1] tag[2] fid[4] offset[8] count[4]") and the - * Rread header is even shorter at 11 bytes ("size[4] Rread[1] - * tag[2] count[4]"), so "24" appears to be the size of the Twrite - * header rounded up to a nice round number. - * - * In older versions of 9P ("9P1"), the max message size was - * defined as part of the protocol specification rather than - * negotiated. In Plan 9 1e it was (8*1024)+128, and was bumped to - * (8*1024)+160 in 2e and 3e. - */ -# define CONFIG_9P_MAX_MSG_SIZE ((8*1024)+24) -# define CONFIG_9P_MAX_ERR_SIZE 128 /* 128 is what Plan 9 4e uses */ -#endif - -#endif /* _CONFIG_H */ diff --git a/lib9p/.editorconfig b/lib9p/.editorconfig index 3f04564..5c79099 100644 --- a/lib9p/.editorconfig +++ b/lib9p/.editorconfig @@ -1,3 +1,3 @@ -[{defs.gen,linux-errno.h.gen}] +[{types.gen,linux-errno.h.gen}] indent_style = space indent_size = 4 diff --git a/lib9p/.gitignore b/lib9p/.gitignore deleted file mode 100644 index 667e81c..0000000 --- a/lib9p/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/defs-* -/linux-errno.h diff --git a/lib9p/9P2000.e.txt b/lib9p/9P2000.e.txt index 22f056e..e60bce0 100644 --- a/lib9p/9P2000.e.txt +++ b/lib9p/9P2000.e.txt @@ -8,9 +8,11 @@ # https://github.com/cloudozer/ling/blob/master/doc/9p2000e.md version "9P2000.e" +from 9P2000.txt import * + 150/Tsession = "key[8]" 151/Rsession = "" 152/Tsread = "fid[4] nwname[2] nwname*(wname[s])" 153/Rsread = "data[d]" -154/Tswrite = "Tswrite tag[2] fid[4] nwname[2] nwname*(wname[s]) data[d]" +154/Tswrite = "fid[4] nwname[2] nwname*(wname[s]) data[d]" 155/Rswrite = "count[4]" diff --git a/lib9p/9P2000.u.txt b/lib9p/9P2000.u.txt index 60d2b11..1fa71fb 100644 --- a/lib9p/9P2000.u.txt +++ b/lib9p/9P2000.u.txt @@ -18,3 +18,28 @@ stat += "file_extension[s]" Tauth += "n_uname[4]" Rerror += "errno[4]" + +# # qid.types +# QTDIR = 1<<7 +# QTAPPEND = 1<<6 +# QTEXCL = 1<<5 +# QTMOUNT = 1<<4 # been around forever, but undocumented? +# QTAUTH = 1<<3 +# QTTMP = 1<<2 # added to Plan 9 2003-12 +# QTSYMLINK = 1<<1 # .u +# QTFILE = 1<<0 +# +# DMDIR = 1<<31 +# DMAPPEND = 1<<30 +# DMEXCL = 1<<29 +# DMMOUNT = 1<<28 +# DMAUTH = 1<<27 +# DMTMP = 1<<26 +# # = 1<<25 +# # = 1<<24 +# DMDEVICE = 1<<23 # .u +# # = 1<<22 +# DMNAMEDPIPE = 1<<21 # .u +# DMSOCKET = 1<<20 # .u +# DMSETUID = 1<<19 # .u +# DMSETGID = 1<<18 # .u diff --git a/lib9p/9p.c b/lib9p/9p.c new file mode 100644 index 0000000..64b09a6 --- /dev/null +++ b/lib9p/9p.c @@ -0,0 +1,94 @@ +/* lib9p/9p.c - Base 9P protocol utilities for both clients and servers + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#include /* for PRIu{n} */ +#include /* for va_* */ +#include /* for vsnprintf() */ +#include /* for strncpy() */ + +#include + +#include "internal.h" + +enum lib9p_version lib9p_ctx_version(lib9p_ctx *ctx) { + assert(ctx); + return ctx->version; +} + +uint32_t lib9p_ctx_max_msg_size(lib9p_ctx *ctx) { + assert(ctx); + return ctx->max_msg_size; +} + +int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) { + strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg)); + ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0'; + ctx->err_num = linux_errno; + return -1; +} + +int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) { + int n; + va_list args; + + va_start(args, fmt); + n = vsnprintf(ctx->err_msg, sizeof(ctx->err_msg), fmt, args); + va_end(args); + if ((size_t)(n+1) < sizeof(ctx->err_msg)) + memset(&ctx->err_msg[n+1], 0, sizeof(ctx->err_msg)-(n+1)); + + ctx->err_num = linux_errno; + + return -1; +} + +size_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes) { + /* Header */ + uint32_t net_len = decode_u32le(net_bytes); + if (net_len < 7) + return lib9p_error(ctx, LINUX_EBADMSG, "message is too short"); + uint8_t typ = net_bytes[4]; + uint32_t net_offset = 7; + + /* Body */ + if (!versions[ctx->version]->msgs[typ].unmarshal_extrasize) + return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %"PRIu8, typ); + size_t host_size = versions[ctx->version]->msgs[typ].unmarshal_basesize; + if (versions[ctx->version]->msgs[typ].unmarshal_extrasize(net_len, net_bytes, &net_offset, &host_size)) + return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content"); + + return host_size; +} + +uint8_t lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body) { + /* Header */ + uint8_t typ = net_bytes[4]; + *out_tag = decode_u16le(&net_bytes[5]); + uint32_t net_offset = 7; + + /* Body */ + void *host_extra = out_body + versions[ctx->version]->msgs[typ].unmarshal_basesize; + if (versions[ctx->version]->msgs[typ].unmarshal(net_bytes, &net_offset, &host_extra, out_body)) + return lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); + + return typ; +} + +uint32_t lib9p_marshal(struct lib9p_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes) { + /* Header */ + out_bytes[4] = typ; + encode_u16le(msgid, &out_bytes[5]); + uint32_t net_offset = 7; + + /* Body */ + if (versions[ctx->version]->msgs[typ].marshal(ctx, body, out_bytes, &net_offset)) + return 0; + + /* Header, again */ + encode_u32le(net_offset, out_bytes); + + return net_offset; +} diff --git a/lib9p/9p.h b/lib9p/9p.h deleted file mode 100644 index 63fbd04..0000000 --- a/lib9p/9p.h +++ /dev/null @@ -1,15 +0,0 @@ -/* 9p/9p.h - TODO - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#include "9p/linux-errno.h" -#include "9p/defs.h" -#include "9p/defs-9P2000.h" -/*#include "9p/defs-9P2000.u.h"*/ - -#define P9_TYPECODE_FOR_CTYPE(msg) _Generic((in_msg) \ - _P9_TYPECODE_FOR_CTYPE_9P2000(msg) \ - /* _P9_TYPECODE_FOR_CTYPE_9P2000u(msg) */ \ - ) diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt new file mode 100644 index 0000000..0faa109 --- /dev/null +++ b/lib9p/CMakeLists.txt @@ -0,0 +1,34 @@ +# libcr/CMakeLists.txt - TODO +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(lib9p INTERFACE) +target_sources(lib9p INTERFACE + types.c + 9p.c + srv.c +) +target_include_directories(lib9p SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt + DEPENDS ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt.gen + COMMAND ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt.gen +) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h + DEPENDS include/lib9p/linux-errno.h.gen ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h.gen ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt >${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h +) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/types.c ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/_types.h + DEPENDS types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt +) +add_dependencies(generate + ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt + ${CMAKE_CURRENT_SOURCE_DIR}/linux-errno.h + ${CMAKE_CURRENT_SOURCE_DIR}/types.c + ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/_types.h +) diff --git a/lib9p/defs.c b/lib9p/defs.c deleted file mode 100644 index 886a0c1..0000000 --- a/lib9p/defs.c +++ /dev/null @@ -1,89 +0,0 @@ -/* 9p/defs.c - TODO - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#include /* for PRIu{n} */ -#include /* for va_* */ -#include /* for vsnprintf() */ -#include /* for strncpy() */ - -#include "9p/defs.h" -#include "9p/linux-errno.h" -#include "9p/internal.h" - -static struct version *versions[_P9_VER_CNT] = { - [P9_VER_9P2000] = &version_9P2000, - /* [P9_VER_9P2000u] = &version_9P2000u, */ -}; - -int p9_error(struct p9_ctx *ctx, uint32_t linux_errno, char const *msg) { - strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg)); - ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0'; - ctx->err_num = linux_errno; - return -1; -} - -int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) { - int n; - va_list args; - - va_start(args, fmt); - n = vsnprintf(ctx->err_msg, sizeof(ctx->err_msg), fmt, args); - va_end(args); - if ((size_t)(n+1) < sizeof(ctx->err_msg)) - memset(&ctx->err_msg[n+1], 0, sizeof(ctx->err_msg)-(n+1)); - - ctx->err_num = linux_errno; - - return -1; -} - -size_t p9_unmarshal_size(struct p9_ctx *ctx, uint8_t *net_bytes) { - /* Header */ - uint32_t net_len = decode_u32le(net_bytes); - if (net_len < 7) - return p9_error(ctx, LINUX_EBADMSG, "message is too short"); - uint8_t typ = net_bytes[4]; - uint32_t net_offset = 7; - - /* Body */ - if (!versions[ctx->version]->msgs[typ].unmarshal_extrasize) - return p9_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %"PRIu8, typ); - size_t host_size = versions[ctx->version]->msgs[typ].unmarshal_basesize; - if (versions[ctx->version]->msgs[typ].unmarshal_extrasize(net_len, net_bytes, &net_offset, &host_size)) - return p9_error(ctx, LINUX_EBADMSG, "message is too short for content"); - - return host_size; -} - -uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body) { - /* Header */ - uint8_t typ = net_bytes[4]; - *out_tag = decode_u16le(&net_bytes[5]); - uint32_t net_offset = 7; - - /* Body */ - void *host_extra = out_body + versions[ctx->version]->msgs[typ].unmarshal_basesize; - if (versions[ctx->version]->msgs[typ].unmarshal(net_bytes, &net_offset, &host_extra, out_body)) - return p9_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); - - return typ; -} - -uint32_t _p9_marshal(struct p9_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes) { - /* Header */ - out_bytes[4] = typ; - encode_u16le(msgid, &out_bytes[5]); - uint32_t net_offset = 7; - - /* Body */ - if (versions[ctx->version]->msgs[typ].marshal(ctx, body, out_bytes, &net_offset)) - return 0; - - /* Header, again */ - encode_u32le(net_offset, out_bytes); - - return net_offset; -} diff --git a/lib9p/defs.gen b/lib9p/defs.gen deleted file mode 100755 index 1a8dc69..0000000 --- a/lib9p/defs.gen +++ /dev/null @@ -1,456 +0,0 @@ -#!/usr/bin/env python -# 9p/defs.gen - Generate C marshalers/unmarshalers for a .txt file -# defining a 9P protocol variant. -# -# Copyright (C) 2024 Luke T. Shumaker -# SPDX-Licence-Identifier: AGPL-3.0-or-later - -import enum -import os.path -import re - -PROGRAM = "./9p/defs.gen" - -# Parse the *.txt ############################################################## - - -class Atom(enum.Enum): - u8 = 1 - u16 = 2 - u32 = 4 - u64 = 8 - - @property - def name(self) -> str: - return str(self.value) - - @property - def static_size(self) -> int: - return self.value - - -# `msgid/structname = "member1 member2..."` -# `structname = "member1 member2..."` -# `structname += "member1 member2..."` -class Struct: - msgid: int | None = None - name: str - members: list["Member"] - - @property - def static_size(self) -> int | None: - size = 0 - for member in self.members: - msize = member.static_size - if msize is None: - return None - size += msize - return size - - -# `cnt*(name[typ])` -# the `cnt*(...)` wrapper is optional -class Member: - cnt: str | None = None - name: str - typ: Atom | Struct - - @property - def static_size(self) -> int | None: - if self.cnt: - return None - return self.typ.static_size - - -re_membername = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" -re_memberspec = ( - f"(?:(?P{re_membername})\\*\\()?(?P{re_membername})\\[(?P.*)\\]\\)?" -) - - -def parse_members( - env: dict[str, Atom | Struct], existing: list[Member], specs: str -) -> list[Member]: - ret = existing - for spec in specs.split(): - m = re.fullmatch(re_memberspec, spec) - if not m: - raise SyntaxError(f"invalid member spec {repr(spec)}") - - member = Member() - - member.name = m.group("name") - if any(x.name == member.name for x in ret): - raise ValueError(f"duplicate member name {repr(member.name)}") - - if m.group("typ") not in env: - raise NameError(f"Unknown type {repr(m.group(2))}") - member.typ = env[m.group("typ")] - - if cnt := m.group("cnt"): - if len(ret) == 0 or ret[-1].name != cnt: - raise ValueError(f"list count must be previous item: {repr(cnt)}") - if not isinstance(ret[-1].typ, Atom): - raise ValueError(f"list count must be an integer type: {repr(cnt)}") - member.cnt = cnt - - ret += [member] - return ret - - -re_version = r'version\s+"(?P[^"]+)"' -re_structspec = ( - r'(?:(?P[0-9]+)/)?(?P\S+)\s*(?P\+?=)\s*"(?P[^"]*)"' -) -re_structspec_cont = r'"(?P[^"]*)"' - - -def parse_file(filename: str) -> tuple[str, list[Struct]]: - version: str | None = None - env: dict[str, Atom | Struct] = { - "1": Atom.u8, - "2": Atom.u16, - "4": Atom.u32, - "8": Atom.u64, - } - with open(filename, "r") as fh: - prev: Struct | None = None - for line in fh: - line = line.split("#", 1)[0].strip() - if not line: - continue - if m := re.fullmatch(re_version, line): - if version: - raise SyntaxError("must have exactly 1 version line") - version = m.group("version") - elif m := re.fullmatch(re_structspec, line): - if m.group("op") == "+=" and m.group("msgid"): - raise SyntaxError("cannot += to a message that is not yet defined") - match m.group("op"): - case "=": - struct = Struct() - if m.group("msgid"): - struct.msgid = int(m.group("msgid")) - struct.name = m.group("name") - struct.members = parse_members(env, [], m.group("members")) - env[struct.name] = struct - prev = struct - case "+=": - if m.group("name") not in env: - raise NameError(f"Unknown type {repr(m.group('name'))}") - _struct = env[m.group("name")] - if not isinstance(_struct, Struct): - raise NameError( - f"Type {repr(m.group('name'))} is not a struct" - ) - struct = _struct - struct.members = parse_members( - env, struct.members, m.group("members") - ) - prev = struct - elif m := re.fullmatch(re_structspec_cont, line): - if not prev: - raise SyntaxError("continuation line must come after a struct line") - prev.members = parse_members(env, prev.members, m.group("members")) - else: - raise SyntaxError(f"invalid line {repr(line)}") - if not version: - raise SyntaxError("must have exactly 1 version line") - structs = [x for x in env.values() if isinstance(x, Struct)] - return version, structs - - -# Generate C ################################################################### - - -def c_typename(idprefix: str, typ: Atom | Struct) -> str: - match typ: - case Atom(): - return f"uint{typ.value*8}_t" - case Struct(): - if typ.msgid is not None: - return f"struct {idprefix}msg_{typ.name}" - return f"struct {idprefix}{typ.name}" - case _: - raise ValueError(f"not a type: {typ.__class__.__name__}") - - -def gen_h(txtname: str, idprefix: str, structs: list[Struct]) -> str: - guard = ( - f"_{txtname.replace('.txt', '.h').upper().replace('/', '_').replace('.', '_')}_" - ) - ret = f"""/* Generated by `{PROGRAM} {txtname}`. DO NOT EDIT! */ - -#ifndef {guard} -#define {guard} - -#define {idprefix.upper()}MIN_MSGLEN 7 -""" - ret += """ -/* non-message structs ********************************************************/ - -""" - for struct in structs: - if struct.msgid is not None: - continue - ret += c_typename(idprefix, struct) + " {\n" - typewidth = max( - len(c_typename(idprefix, member.typ)) for member in struct.members - ) - for member in struct.members: - ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n" - ret += "};\n" - - ret += """ -/* message types **************************************************************/ - -""" - ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n" - namewidth = max(len(msg.name) for msg in structs if msg.msgid is not None) - for msg in structs: - if msg.msgid is None: - continue - ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid},\n" - ret += "};\n" - - ret += """ -/* message structs ************************************************************/ - -""" - for msg in structs: - if msg.msgid is None: - continue - if not msg.members: - ret += c_typename(idprefix, msg) + " {};\n" - continue - ret += c_typename(idprefix, msg) + " {\n" - typewidth = max(len(c_typename(idprefix, member.typ)) for member in msg.members) - for member in msg.members: - ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n" - ret += "};\n" - - ret += f""" -/* tables *********************************************************************/ - -#define _P9_TYPECODE_FOR_CTYPE(msg) """ - for msg in structs: - if msg.msgid is None: - continue - ret += f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}" - ret += "\n" - - ret += "\n" - ret += f"#endif /* {guard} */\n" - return ret - - -def gen_c(txtname: str, idprefix: str, structs: list[Struct]) -> str: - txtdir, txtbase = os.path.split(txtname) - header = os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".h")) - ret = f"""/* Generated by `{PROGRAM} {txtname}`. DO NOT EDIT! */ - -#include -#include -#include /* for malloc() */ - -#include "{header}" -#include "9p/internal.h" -""" - - def used(arg: str) -> str: - return arg - - def unused(arg: str) -> str: - return f"UNUSED({arg})" - - # checksize_* ############################################################## - ret += """ -/* checksize_* ****************************************************************/ - -static inline bool _checksize_list(size_t cnt, _checksize_fn_t fn, size_t host_size, - uint32_t net_len, uint8_t *net_bytes, uint32_t *mut_net_offset, size_t *mut_host_extra) { - for (size_t i = 0; i < cnt; i++) - if (__builtin_add_overflow(*mut_host_extra, host_size, mut_host_extra) - || fn(net_len, net_bytes, mut_net_offset, mut_host_extra)) - return true; - return false; -} - -static inline bool checksize_1(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 1, mut_net_offset) || net_len < *mut_net_offset; -} -static inline bool checksize_2(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 2, mut_net_offset) || net_len < *mut_net_offset; -} -static inline bool checksize_4(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 4, mut_net_offset) || net_len < *mut_net_offset; -} -static inline bool checksize_8(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 8, mut_net_offset) || net_len < *mut_net_offset; -} - -""" - for struct in structs: - inline = ' inline' if struct.msgid is None else '' - argfn = used if struct.members else unused - ret += f"static{inline} bool checksize_{struct.name}(uint32_t {argfn('net_len')}, uint8_t *{argfn('net_bytes')}, uint32_t *{argfn('mut_net_offset')}, size_t *{argfn('mut_host_extra')}) {{" - if len(struct.members) == 0: - ret += "\n\treturn false;\n" - ret += "}\n" - continue - prefix0 = "\treturn " - prefix1 = "\t || " - prefix2 = "\t " - prefix = prefix0 - prev_size: int | None = None - for member in struct.members: - if member.cnt is not None: - assert prev_size - ret += f"\n{prefix }_checksize_list(decode_u{prev_size*8}le(&net_bytes[(*mut_net_offset)-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)})," - ret += f"\n{prefix2} net_len, net_bytes, mut_net_offset, mut_host_extra)" - else: - ret += f"\n{prefix}checksize_{member.typ.name}(net_len, net_bytes, mut_net_offset, mut_host_extra)" - prefix = prefix1 - prev_size = member.static_size - if struct.name == "s": - ret += ( - f"\n{prefix}__builtin_add_overflow(*mut_host_extra, 1, mut_host_extra)" - ) - ret += ";\n}\n" - - # unmarshal_* ############################################################## - ret += """ -/* unmarshal_* ****************************************************************/ -/* checksize_XXX() should be called before unmarshal_XXX(). */ - -static inline bool unmarshal_1(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint8_t *out) { - *out = decode_u8le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 1; - return false; -} -static inline bool unmarshal_2(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint16_t *out) { - *out = decode_u16le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 2; - return false; -} -static inline bool unmarshal_4(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint32_t *out) { - *out = decode_u32le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 4; - return false; -} -static inline bool unmarshal_8(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint64_t *out) { - *out = decode_u64le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 8; - return false; -} - -""" - for struct in structs: - argfn = used if struct.members else unused - ret += f"static inline bool unmarshal_{struct.name}(uint8_t *{argfn('net_bytes')}, uint32_t *{argfn('mut_net_offset')}, void **{argfn('mut_host_extra')}, {c_typename(idprefix, struct)} *{argfn('out')}) {{\n" - for member in struct.members: - if member.cnt: - ret += f"\tout->{member.name} = *mut_host_extra;\n" - ret += f"\t*mut_host_extra += sizeof(*out->{member.name}) * out->{member.cnt};\n" - ret += f"\tfor (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n" - ret += f"\t\tif (unmarshal_{member.typ.name}(net_bytes, mut_net_offset, mut_host_extra, &(out->{member.name}[i])))\n" - ret += f"\t\t\treturn true;\n" - if struct.name == "s": - ret += f"\tif (!is_valid_utf8_without_nul(out->{member.name}, out->{member.cnt}))\n" - ret += f"\t\treturn true;\n" - ret += f"\tout->{member.name}[out->{member.cnt}] = '\\0';\n" - else: - ret += f"\tif (unmarshal_{member.typ.name}(net_bytes, mut_net_offset, mut_host_extra, &(out->{member.name})))\n" - ret += f"\t\treturn true;\n" - ret += "\treturn false;\n" - ret += "}\n" - - # marshal_* ################################################################ - ret += """ -/* marshal_* ******************************************************************/ - -static inline bool marshal_1(struct p9_ctx *ctx, uint8_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 1 > ctx->max_msg_size) - return true; - out_net_bytes[*mut_net_offset] = val; - *mut_net_offset += 1; - return false; -} -static inline bool marshal_2(struct p9_ctx *ctx, uint16_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 2 > ctx->max_msg_size) - return true; - encode_u16le(val, &out_net_bytes[*mut_net_offset]); - *mut_net_offset += 2; - return false; -} -static inline bool marshal_4(struct p9_ctx *ctx, uint32_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 4 > ctx->max_msg_size) - return true; - encode_u32le(val, &out_net_bytes[*mut_net_offset]); - *mut_net_offset += 4; - return false; -} -static inline bool marshal_8(struct p9_ctx *ctx, uint64_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 8 > ctx->max_msg_size) - return true; - encode_u64le(val, &out_net_bytes[*mut_net_offset]); - *mut_net_offset += 8; - return false; -} -""" - for struct in structs: - argfn = used if struct.members else unused - ret += f"static inline bool marshal_{struct.name}(struct p9_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} {argfn('val')}, uint8_t *{argfn('out_net_bytes')}, uint32_t *{argfn('mut_net_offset')}) {{\n" - for member in struct.members: - if member.cnt: - ret += f"\tfor (typeof(val.{member.cnt}) i = 0; i < val.{member.cnt}; i++)\n" - ret += f"\t\tif (marshal_{member.typ.name}(ctx, val.{member.name}[i], out_net_bytes, mut_net_offset))\n" - ret += f"\t\t\treturn true;\n" - else: - ret += f"\tif (marshal_{member.typ.name}(ctx, val.{member.name}, out_net_bytes, mut_net_offset))\n" - ret += f"\t\treturn true;\n" - ret += "\treturn false;\n" - ret += "}\n" - - # tables ################################################################### - ret += """ -/* tables *********************************************************************/ - -""" - for msg in structs: - if msg.msgid is None: - continue - ret += f"static bool _unmarshal_{msg.name}(uint8_t *net_bytes, uint32_t *mut_net_offset, void **mut_host_extra, void *out) {{ return unmarshal_{msg.name}(net_bytes, mut_net_offset, mut_host_extra, ({c_typename(idprefix, msg)} *)out); }}\n" - for msg in structs: - if msg.msgid is None: - continue - ret += f"static bool _marshal_{msg.name}(struct p9_ctx *ctx, void *val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) {{ return marshal_{msg.name}(ctx, *(({c_typename(idprefix, msg)} *)val), out_net_bytes, mut_net_offset); }}\n" - ret += "struct version version_9P2000 = {\n" - ret += "\t.msgs = {\n" - for msg in structs: - if msg.msgid is None: - continue - ret += f"\t\t[{idprefix.upper()}TYP_{msg.name}] = {{ .unmarshal_basesize=sizeof({c_typename(idprefix, msg)}), .unmarshal_extrasize=checksize_{msg.name}, .unmarshal=_unmarshal_{msg.name}, .marshal=_marshal_{msg.name} }},\n" - ret += "\t},\n" - ret += "};\n" - - ############################################################################ - return ret - - -################################################################################ - -if __name__ == "__main__": - import sys - - for txtname in sys.argv[1:]: - txtdir, txtbase = os.path.split(txtname) - version, structs = parse_file(txtname) - with open( - os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".h")), "w" - ) as fh: - fh.write(gen_h(txtname, "p9_", structs)) - with open( - os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".c")), "w" - ) as fh: - fh.write(gen_c(txtname, "p9_", structs)) diff --git a/lib9p/defs.h b/lib9p/defs.h deleted file mode 100644 index 907cdde..0000000 --- a/lib9p/defs.h +++ /dev/null @@ -1,74 +0,0 @@ -/* 9p/defs.h - TODO - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#ifndef _9P_DEFS_H_ -#define _9P_DEFS_H_ - -#include - -#define P9_NOTAG ((uint16_t)~0U) -#define P9_NOFID ((uint32_t)~0U) - -enum p9_version { - P9_VER_UNINITIALIZED, - /* P9_VER_9P1, */ - P9_VER_9P2000, - /*P9_VER_9P2000_u,*/ - /*P9_VER_9P2000_L,*/ - /*P9_VER_9P2000_e,*/ - _P9_VER_CNT, -}; - -struct p9_ctx; - -enum p9_version p9_ctx_version(p9_ctx *); - -/** Write an static error into ctx, return -1. */ -int p9_error(struct p9_ctx *ctx, uint32_t linux_errno, char const *msg); -/** Write a printf-style error into ctx, return -1. */ -int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...); - -/** - * Return how much space the message at net_bytes will take when - * unmarshaled. This number may be larger than net_bytes due to (1) - * struct padding, (2) nul-terminator byes for strings. - * - * Emits an error (return -1, set ctx->err_num and ctx->err_msg) if - * either the message type is unknown or if net_bytes is too short for - * that message type. - * - * @param net_bytes : the complete request, starting with the "size[4]" - * @return required size, or -1 on error - */ -size_t p9_unmarshal_size(struct p9_ctx *ctx, uint8_t *net_bytes); - -/** - * Unmarshal the 9P message `net_bytes` into the C struct `out_body`. - * - * Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a - * string contains invalid UTF-8 or a nul-byte. - * - * @param net_bytes : the complete message, starting with the "size[4]" - * @param out_tag : the message-ID tag - * @param out_body : the message body, must be at least p9_unmarshal_size() bytes - * @return the message type, or -1 on error - */ -uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body); - -/** - * Marshal a `struct p9_msg_{type}` structure into a byte-array. - * - * @param struct p9_ctx *ctx : a request context - * @param uint16_t msgid : the message-ID tag - * @param struct p9_msg_{type} msg : the message to encode - * - * @param uint8_t *out_bytes : the buffer to encode to, must be at be at least ctx->max_msg_size bytes - * @return uint32_t : the encoded length, or -1 on error - */ -#define p9_marshal(ctx, msgid, msg, out_bytes) _p9_marshal(ctx, P9_TYPECODE_FOR_CTYPE(msg), msgid, &(msg), out_bytes) -uint32_t _p9_marshal(struct p9_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes); - -#endif /* _9P_DEFS_H_ */ diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h new file mode 100644 index 0000000..a55f08f --- /dev/null +++ b/lib9p/include/lib9p/9p.h @@ -0,0 +1,72 @@ +/* lib9p/9p.h - Base 9P protocol definitions for both clients and servers + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_9P_H_ +#define _LIB9P_9P_H_ + +#include +#include + +#define LIB9P_NOTAG ((uint16_t)~0U) +#define LIB9P_NOFID ((uint32_t)~0U) + +struct lib9p_ctx; +enum lib9p_version lib9p_ctx_version(lib9p_ctx *); +uint32_t lib9p_ctx_max_msg_size(lib9p_ctx *); + +/** Write an static error into ctx, return -1. */ +int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg); +/** Write a printf-style error into ctx, return -1. */ +int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...); + +/** + * Return how much space the message at net_bytes will take when + * unmarshaled. This number may be larger than net_bytes due to (1) + * struct padding, (2) nul-terminator byes for strings. + * + * Emits an error (return -1, set ctx->err_num and ctx->err_msg) if + * either the message type is unknown, or if net_bytes is too short + * for that message type, or if an invalid string (invalid UTF-8, + * contains a nul-byte) is encountered. + * + * @param net_bytes : the complete request, starting with the "size[4]" + * + * @return required size, or -1 on error + */ +ssize_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes); + +/** + * Unmarshal the 9P message `net_bytes` into the C struct `ret_body`. + * + * Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a + * string contains invalid UTF-8 or a nul-byte. + * + * @param ctx : negotiated protocol parameters, where to record errors + * @param net_bytes : the complete message, starting with the "size[4]" + * + * @return ret_typ : the mesage type + * @return ret_tag : the message-ID tag + * @return ret_body : the message body, must be at least lib9p_unmarshal_size() bytes + * @return the message type, or -1 on error + */ +bool lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, + enum lib9p_msg_typ *ret_typ, uint16_t *ret_tag, void *ret_body); + +/** + * Marshal a `struct lib9p_msg_{typ}` structure into a byte-array. + * + * @param ctx : negotiated protocol parameters, where to record errors + * @param typ : the message type + * @param tag : the message-ID tag + * @param msg : the message to encode + * + * @return ret_bytes : the buffer to encode to, must be at be at least lib9p_ctx_max_msg_size(ctx) bytes + * @return whether there was an error (false=success, true=error) + */ +bool lib9p_marshal(struct lib9p_ctx *ctx, uint8_t typ, uint16_t tag, void *body, + uint8_t *ret_bytes); + +#endif _LIB9P_9P_H_ diff --git a/lib9p/include/lib9p/_types.h b/lib9p/include/lib9p/_types.h new file mode 100644 index 0000000..348945d --- /dev/null +++ b/lib9p/include/lib9p/_types.h @@ -0,0 +1,285 @@ +/* Generated by `./types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt`. DO NOT EDIT! */ + +#ifndef _LIB9P__TYPES_H_ +#define _LIB9P__TYPES_H_ + +#include + +/* versions *******************************************************************/ + +enum lib9p_version { + LIB9P_VER_UNINITIALIZED = 0, + LIB9P_VER_9P2000, /* "9P2000" */ + LIB9P_VER_9P2000_e, /* "9P2000.e" */ + LIB9P_VER_9P2000_u, /* "9P2000.u" */ + LIB9P_VER_NUM, +}; + +/* non-message structs ********************************************************/ + +struct lib9p_d { + uint32_t len; + uint8_t *dat; +}; + +struct lib9p_s { + uint16_t len; + uint8_t *utf8; +}; + +struct lib9p_qid { + uint8_t type; + uint32_t vers; + uint64_t path; +}; + +struct lib9p_stat { + uint16_t stat_size; + uint16_t kern_type; + uint32_t kern_dev; + struct lib9p_qid file_qid; + uint32_t file_mode; + uint32_t file_atime; + uint32_t file_mtime; + uint64_t file_size; + struct lib9p_s file_name; + struct lib9p_s file_owner_uid; + struct lib9p_s file_owner_gid; + struct lib9p_s file_last_modified_uid; + struct lib9p_s file_extension; /* 9P2000.u */ + uint32_t file_owner_n_uid; /* 9P2000.u */ + uint32_t file_owner_n_gid; /* 9P2000.u */ + uint32_t file_last_modified_n_uid; /* 9P2000.u */ +}; + +/* messages *******************************************************************/ + +enum lib9p_msg_type { /* uint8_t */ + LIB9P_TYP_Tversion = 100, + LIB9P_TYP_Rversion = 101, + LIB9P_TYP_Tauth = 102, + LIB9P_TYP_Rauth = 103, + LIB9P_TYP_Tattach = 104, + LIB9P_TYP_Rattach = 105, + LIB9P_TYP_Rerror = 107, + LIB9P_TYP_Tflush = 108, + LIB9P_TYP_Rflush = 109, + LIB9P_TYP_Twalk = 110, + LIB9P_TYP_Rwalk = 111, + LIB9P_TYP_Topen = 112, + LIB9P_TYP_Ropen = 113, + LIB9P_TYP_Tcreate = 114, + LIB9P_TYP_Rcreate = 115, + LIB9P_TYP_Tread = 116, + LIB9P_TYP_Rread = 117, + LIB9P_TYP_Twrite = 118, + LIB9P_TYP_Rwrite = 119, + LIB9P_TYP_Tclunk = 120, + LIB9P_TYP_Rclunk = 121, + LIB9P_TYP_Tremove = 122, + LIB9P_TYP_Rremove = 123, + LIB9P_TYP_Tstat = 124, + LIB9P_TYP_Rstat = 125, + LIB9P_TYP_Twstat = 126, + LIB9P_TYP_Rwstat = 127, + LIB9P_TYP_Tsession = 150, /* 9P2000.e */ + LIB9P_TYP_Rsession = 151, /* 9P2000.e */ + LIB9P_TYP_Tsread = 152, /* 9P2000.e */ + LIB9P_TYP_Rsread = 153, /* 9P2000.e */ + LIB9P_TYP_Tswrite = 154, /* 9P2000.e */ + LIB9P_TYP_Rswrite = 155, /* 9P2000.e */ +}; + +#define LIB9P_TYPECODE_FOR_CTYPE(msg) _Generic((msg), \ + struct lib9p_msg_Tversion: LIB9P_TYP_Tversion, \ + struct lib9p_msg_Rversion: LIB9P_TYP_Rversion, \ + struct lib9p_msg_Tauth: LIB9P_TYP_Tauth, \ + struct lib9p_msg_Rauth: LIB9P_TYP_Rauth, \ + struct lib9p_msg_Tattach: LIB9P_TYP_Tattach, \ + struct lib9p_msg_Rattach: LIB9P_TYP_Rattach, \ + struct lib9p_msg_Rerror: LIB9P_TYP_Rerror, \ + struct lib9p_msg_Tflush: LIB9P_TYP_Tflush, \ + struct lib9p_msg_Rflush: LIB9P_TYP_Rflush, \ + struct lib9p_msg_Twalk: LIB9P_TYP_Twalk, \ + struct lib9p_msg_Rwalk: LIB9P_TYP_Rwalk, \ + struct lib9p_msg_Topen: LIB9P_TYP_Topen, \ + struct lib9p_msg_Ropen: LIB9P_TYP_Ropen, \ + struct lib9p_msg_Tcreate: LIB9P_TYP_Tcreate, \ + struct lib9p_msg_Rcreate: LIB9P_TYP_Rcreate, \ + struct lib9p_msg_Tread: LIB9P_TYP_Tread, \ + struct lib9p_msg_Rread: LIB9P_TYP_Rread, \ + struct lib9p_msg_Twrite: LIB9P_TYP_Twrite, \ + struct lib9p_msg_Rwrite: LIB9P_TYP_Rwrite, \ + struct lib9p_msg_Tclunk: LIB9P_TYP_Tclunk, \ + struct lib9p_msg_Rclunk: LIB9P_TYP_Rclunk, \ + struct lib9p_msg_Tremove: LIB9P_TYP_Tremove, \ + struct lib9p_msg_Rremove: LIB9P_TYP_Rremove, \ + struct lib9p_msg_Tstat: LIB9P_TYP_Tstat, \ + struct lib9p_msg_Rstat: LIB9P_TYP_Rstat, \ + struct lib9p_msg_Twstat: LIB9P_TYP_Twstat, \ + struct lib9p_msg_Rwstat: LIB9P_TYP_Rwstat, \ + struct lib9p_msg_Tsession: LIB9P_TYP_Tsession, \ + struct lib9p_msg_Rsession: LIB9P_TYP_Rsession, \ + struct lib9p_msg_Tsread: LIB9P_TYP_Tsread, \ + struct lib9p_msg_Rsread: LIB9P_TYP_Rsread, \ + struct lib9p_msg_Tswrite: LIB9P_TYP_Tswrite, \ + struct lib9p_msg_Rswrite: LIB9P_TYP_Rswrite) + +struct lib9p_msg_Tversion { + uint32_t max_msg_size; + struct lib9p_s version; +}; + +struct lib9p_msg_Rversion { + uint32_t max_msg_size; + struct lib9p_s version; +}; + +struct lib9p_msg_Tauth { + uint32_t afid; + struct lib9p_s uname; + struct lib9p_s aname; + uint32_t n_uname; /* 9P2000.u */ +}; + +struct lib9p_msg_Rauth { + struct lib9p_qid aqid; +}; + +struct lib9p_msg_Tattach { + uint32_t fid; + uint32_t afid; + struct lib9p_s uname; + struct lib9p_s aname; +}; + +struct lib9p_msg_Rattach { + struct lib9p_qid qid; +}; + +struct lib9p_msg_Rerror { + struct lib9p_s ename; + uint32_t errno; /* 9P2000.u */ +}; + +struct lib9p_msg_Tflush { + uint16_t oldtag; +}; + +struct lib9p_msg_Rflush {}; + +struct lib9p_msg_Twalk { + uint32_t fid; + uint32_t newfid; + uint16_t nwname; + struct lib9p_s *wname; +}; + +struct lib9p_msg_Rwalk { + uint16_t nwqid; + struct lib9p_qid *wqid; +}; + +struct lib9p_msg_Topen { + uint32_t fid; + uint8_t mode; +}; + +struct lib9p_msg_Ropen { + struct lib9p_qid qid; + uint32_t iounit; +}; + +struct lib9p_msg_Tcreate { + uint32_t fid; + struct lib9p_s name; + uint32_t perm; + uint8_t mode; +}; + +struct lib9p_msg_Rcreate { + struct lib9p_qid qid; + uint32_t iounit; +}; + +struct lib9p_msg_Tread { + uint32_t fid; + uint64_t offset; + uint32_t count; +}; + +struct lib9p_msg_Rread { + struct lib9p_d data; +}; + +struct lib9p_msg_Twrite { + uint32_t fid; + uint64_t offset; + struct lib9p_d data; +}; + +struct lib9p_msg_Rwrite { + uint32_t count; +}; + +struct lib9p_msg_Tclunk { + uint32_t fid; +}; + +struct lib9p_msg_Rclunk {}; + +struct lib9p_msg_Tremove { + uint32_t fid; +}; + +struct lib9p_msg_Rremove {}; + +struct lib9p_msg_Tstat { + uint32_t fid; +}; + +struct lib9p_msg_Rstat { + struct lib9p_stat stat; +}; + +struct lib9p_msg_Twstat { + uint32_t fid; + struct lib9p_stat stat; +}; + +struct lib9p_msg_Rwstat {}; + +/* 9P2000.e */ +struct lib9p_msg_Tsession { + uint64_t key; +}; + +/* 9P2000.e */ +struct lib9p_msg_Rsession {}; + +/* 9P2000.e */ +struct lib9p_msg_Tsread { + uint32_t fid; + uint16_t nwname; + struct lib9p_s *wname; +}; + +/* 9P2000.e */ +struct lib9p_msg_Rsread { + struct lib9p_d data; +}; + +/* 9P2000.e */ +struct lib9p_msg_Tswrite { + uint32_t fid; + uint16_t nwname; + struct lib9p_s *wname; + struct lib9p_d data; +}; + +/* 9P2000.e */ +struct lib9p_msg_Rswrite { + uint32_t count; +}; + +#endif /* _LIB9P__TYPES_H_ */ diff --git a/lib9p/include/lib9p/linux-errno.h.gen b/lib9p/include/lib9p/linux-errno.h.gen new file mode 100755 index 0000000..b896384 --- /dev/null +++ b/lib9p/include/lib9p/linux-errno.h.gen @@ -0,0 +1,34 @@ +#!/usr/bin/env python + + +def print_errnos(txtlists: list[str]) -> None: + print( + f"/* 9p/linux-errno.h - Generated by `./9p/linux-errno.h.gen {' '.join(txtlists)}`. DO NOT EDIT! */" + ) + errnos: dict[str, tuple[int, str]] = {} + for txtlist in sys.argv[1:]: + with open(txtlist, "r") as fh: + for line in fh: + if line.startswith("#"): + print(f"/* {line[1:].strip()} */") + continue + _num, name, desc = line.split(maxsplit=2) + num = int(_num) + desc = desc.strip() + errnos[name] = (num, desc) + print() + print("#ifndef _9P_LINUX_ERRNO_H_") + print("#define _9P_LINUX_ERRNO_H_") + print() + namelen = max(len(name) for name in errnos.keys()) + numlen = max(len(str(num)) for (num, desc) in errnos.values()) + for name in errnos: + print(f"#define LINUX_{name.ljust(namelen)} {str(errnos[name][0]).rjust(numlen)} /* {errnos[name][1]} */") + print() + print("#endif /* _9P_LINUX_ERRNO_H_ */") + + +if __name__ == "__main__": + import sys + + print_errnos(sys.argv[1:]) diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h new file mode 100644 index 0000000..3b8b21e --- /dev/null +++ b/lib9p/include/lib9p/srv.h @@ -0,0 +1,16 @@ +#ifndef _LIB9P_SRV_H_ +#define _LIB9P_SRV_H_ + +#include + +struct lib9p_srvreq; + +struct lib9p_srv { + int sockfd; + cr_chan_t(lib9p_srvreq *) reqch; +}; + +COROUTINE lib9p_srv_read_cr(void *_srv); +COROUTINE lib9p_srv_write_cr(void *_srv); + +#endif /* _LIB9P_SRV_H_ */ diff --git a/lib9p/internal.h b/lib9p/internal.h index 61977d4..ebdc3f3 100644 --- a/lib9p/internal.h +++ b/lib9p/internal.h @@ -1,21 +1,20 @@ -/* 9p/internal.h - TODO +/* lib9p/internal.h - TODO * * Copyright (C) 2024 Luke T. Shumaker * SPDX-Licence-Identifier: AGPL-3.0-or-later */ -#ifndef _9P_INTERNAL_H_ -#define _9P_INTERNAL_H_ +#ifndef _LIB9P_INTERNAL_H_ +#define _LIB9P_INTERNAL_H_ #include -#include #include -#include "9p/defs.h" +#include -#define USE_CONFIG_9P +#define USE_CONFIG_LIB9P #include "config.h" -static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX); +static_assert(CONFIG_LIB9P_MAX_ERR_SIZE <= UINT16_MAX); /* C language *****************************************************************/ @@ -23,39 +22,65 @@ static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX); /* types **********************************************************************/ -struct p9_ctx { - enum p9_version version; - uint32_t max_msg_size; - uint32_t Rerror_overhead; +/* NB: We declare this here instead of in the public + * because we don't want to include "config.h" from public headers, + * and I want the MAX_ERR_SIZE to be configurable. */ +struct lib9p_ctx { + /* negotiated */ + enum lib9p_version version; + uint32_t max_msg_size; + /* negotiated (server) */ + uint32_t Rerror_overhead; + + /* state */ + uint32_t err_num; + char err_msg[CONFIG_LIB9P_MAX_ERR_SIZE]; +}; + +/* vtables ********************************************************************/ - uint32_t err_num; - char err_msg[CONFIG_9P_MAX_ERR_SIZE]; +struct _checksize_ctx { + struct lib9p_ctx *ctx; + uint32_t net_size; + uint8_t net_bytes; + + uint32_t net_offset; + /* Increment `host_extra` to pre-allocate space that is + * "extra" beyond sizeof(). */ + size_t host_extra; }; -static inline enum p9_version p9_ctx_version(p9_ctx *ctx) { - assert(ctx); - return ctx->version; -} +struct _unmarshal_ctx { + struct lib9p_ctx *ctx; -/* vtables ********************************************************************/ + uint32_t net_offset; + /* `extra` points to the beginning of unallocated space. */ + void *extra; +}; + +struct _marshal_ctx { + struct lib9p_ctx *ctx; + + uint8_t *net_bytes; + uint32_t net_offset; +}; -typedef bool (*_checksize_fn_t)(uint32_t net_len, uint8_t *net_bytes, uint32_t *mut_net_offset, size_t *mut_host_extra); -typedef bool (*_unmarshal_fn_t)(uint8_t *net_bytes, uint32_t *mut_net_offset, void **mut_host_extra, void *out); -typedef bool (*_marshal_fn_t)(struct p9_ctx *ctx, void *val, uint8_t *out_net_bytes, uint32_t *mut_net_offset); +typedef bool (*_checksize_fn_t)(struct _checksize_ctx *ctx); +typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out); +typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val); -struct msg_vtable { +struct _vtable_msg { size_t unmarshal_basesize; _checksize_fn_t unmarshal_extrasize; _unmarshal_fn_t unmarshal; _marshal_fn_t marshal; }; -struct version { - struct msg_vtable msgs[0xFF]; +struct _vtable_version { + struct _vtable_msg msgs[0xFF]; }; -extern struct version version_9P2000; -/*extern struct version version_9P2000u; */ +extern struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM]; /* unmarshal utilities ********************************************************/ @@ -136,4 +161,4 @@ static inline void encode_u64le(uint64_t in, uint8_t *out) { out[7] = (uint8_t)((in >> 56) & 0xFF); } -#endif /* _9P_INTERNAL_H_ */ +#endif /* _LIB9P_INTERNAL_H_ */ diff --git a/lib9p/linux-errno.h.gen b/lib9p/linux-errno.h.gen deleted file mode 100755 index b896384..0000000 --- a/lib9p/linux-errno.h.gen +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python - - -def print_errnos(txtlists: list[str]) -> None: - print( - f"/* 9p/linux-errno.h - Generated by `./9p/linux-errno.h.gen {' '.join(txtlists)}`. DO NOT EDIT! */" - ) - errnos: dict[str, tuple[int, str]] = {} - for txtlist in sys.argv[1:]: - with open(txtlist, "r") as fh: - for line in fh: - if line.startswith("#"): - print(f"/* {line[1:].strip()} */") - continue - _num, name, desc = line.split(maxsplit=2) - num = int(_num) - desc = desc.strip() - errnos[name] = (num, desc) - print() - print("#ifndef _9P_LINUX_ERRNO_H_") - print("#define _9P_LINUX_ERRNO_H_") - print() - namelen = max(len(name) for name in errnos.keys()) - numlen = max(len(str(num)) for (num, desc) in errnos.values()) - for name in errnos: - print(f"#define LINUX_{name.ljust(namelen)} {str(errnos[name][0]).rjust(numlen)} /* {errnos[name][1]} */") - print() - print("#endif /* _9P_LINUX_ERRNO_H_ */") - - -if __name__ == "__main__": - import sys - - print_errnos(sys.argv[1:]) diff --git a/lib9p/misc.txt b/lib9p/misc.txt deleted file mode 100644 index 93aa304..0000000 --- a/lib9p/misc.txt +++ /dev/null @@ -1,24 +0,0 @@ -# qid.types -QTDIR = 1<<7 -QTAPPEND = 1<<6 -QTEXCL = 1<<5 -QTMOUNT = 1<<4 # been around forever, but undocumented? -QTAUTH = 1<<3 -QTTMP = 1<<2 # added to Plan 9 2003-12 -QTSYMLINK = 1<<1 # .u -QTFILE = 1<<0 - -DMDIR = 1<<31 -DMAPPEND = 1<<30 -DMEXCL = 1<<29 -DMMOUNT = 1<<28 -DMAUTH = 1<<27 -DMTMP = 1<<26 -# = 1<<25 -# = 1<<24 -DMDEVICE = 1<<23 # .u -# = 1<<22 -DMNAMEDPIPE = 1<<21 # .u -DMSOCKET = 1<<20 # .u -DMSETUID = 1<<19 # .u -DMSETGID = 1<<18 # .u diff --git a/lib9p/srv.h b/lib9p/srv.h deleted file mode 100644 index e3623ed..0000000 --- a/lib9p/srv.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _NET9P_H_ -#define _NET9P_H_ - -#include "coroutine.h" - -struct p9_srvreq; - -struct p9_srv { - int sockfd; - cr_chan_t(p9_srvreq *) reqch; -}; - -COROUTINE p9_srv_read_cr(void *_srv); -COROUTINE p9_srv_write_cr(void *_srv); - -#endif /* _NET9P_H_ */ diff --git a/lib9p/types.c b/lib9p/types.c new file mode 100644 index 0000000..73ac28e --- /dev/null +++ b/lib9p/types.c @@ -0,0 +1,1331 @@ +/* Generated by `./types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt`. DO NOT EDIT! */ + +#include + +#include + +#include "internal.h" + +/* checksize_* (internals of unmarshal_size()) ********************************/ + +static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) { + if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset)) + /* If needed-net-size overflowed uint32_t, then + * there's no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + if (ctx->net_offset > ctx->net_size) + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_host(struct _checksize_ctx *ctx, size_t n) { + if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra)) + /* If needed-host-size overflowed size_t, then there's + * no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_list(struct _checksize_ctx *ctx, + size_t cnt, _checksize_fn_t item_fn, size_t item_host_size) { + for (size_t i = 0; i < cnt; i++) + if (_checksize_host(ctx, item_host_size) || item_fn(ctx)) + return true; + return false; +} + +#define checksize_1(ctx) _checksize_net(ctx, 1) +#define checksize_2(ctx) _checksize_net(ctx, 2) +#define checksize_4(ctx) _checksize_net(ctx, 4) +#define checksize_8(ctx) _checksize_net(ctx, 8) + +static inline bool checksize_d(struct _checksize_ctx *ctx) { + uint32_t base_offset = ctx->net_offset; + if (_checksize_4(ctx)) + return true; + uint32_t len = decode_u32le(&ctx->net_bytes[base_offset]); + return checksize_net(ctx, len) || checksize_host(ctx, len); +} + +static inline bool checksize_s(struct _checksize_ctx *ctx) { + uint32_t base_offset = ctx->net_offset; + if (_checksize_2(ctx)) + return true; + uint16_t len = decode_u16le(&ctx->net_bytes[base_offset]); + if (checksize_net(ctx, len) || checksize_host(ctx, ((size_t)len)+1)) + return true; + if (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len)) + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); + return false; +} + +static inline bool checksize_qid(struct _checksize_ctx *ctx) { + return checksize_1(ctx) + || checksize_4(ctx) + || checksize_8(ctx); +} + +static inline bool checksize_stat(struct _checksize_ctx *ctx) { + return checksize_2(ctx) + || checksize_2(ctx) + || checksize_4(ctx) + || checksize_qid(ctx) + || checksize_4(ctx) + || checksize_4(ctx) + || checksize_4(ctx) + || checksize_8(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_s(ctx) ) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ); +} + +static bool checksize_Tversion(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx); +} + +static bool checksize_Rversion(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx); +} + +static bool checksize_Tauth(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ); +} + +static bool checksize_Rauth(struct _checksize_ctx *ctx) { + return checksize_qid(ctx); +} + +static bool checksize_Tattach(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_4(ctx) + || checksize_s(ctx) + || checksize_s(ctx); +} + +static bool checksize_Rattach(struct _checksize_ctx *ctx) { + return checksize_qid(ctx); +} + +static bool checksize_Rerror(struct _checksize_ctx *ctx) { + return checksize_s(ctx) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ); +} + +static bool checksize_Tflush(struct _checksize_ctx *ctx) { + return checksize_2(ctx); +} + +static bool checksize_Rflush(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Twalk(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_4(ctx) + || checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s)); +} + +static bool checksize_Rwalk(struct _checksize_ctx *ctx) { + return checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_qid, sizeof(struct lib9p_qid)); +} + +static bool checksize_Topen(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_1(ctx); +} + +static bool checksize_Ropen(struct _checksize_ctx *ctx) { + return checksize_qid(ctx) + || checksize_4(ctx); +} + +static bool checksize_Tcreate(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx) + || checksize_4(ctx) + || checksize_1(ctx); +} + +static bool checksize_Rcreate(struct _checksize_ctx *ctx) { + return checksize_qid(ctx) + || checksize_4(ctx); +} + +static bool checksize_Tread(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_8(ctx) + || checksize_4(ctx); +} + +static bool checksize_Rread(struct _checksize_ctx *ctx) { + return checksize_d(ctx); +} + +static bool checksize_Twrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_8(ctx) + || checksize_d(ctx); +} + +static bool checksize_Rwrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Tclunk(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Rclunk(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tremove(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Rremove(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tstat(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Rstat(struct _checksize_ctx *ctx) { + return checksize_stat(ctx); +} + +static bool checksize_Twstat(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_stat(ctx); +} + +static bool checksize_Rwstat(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tsession(struct _checksize_ctx *ctx) { + return checksize_8(ctx); +} + +static bool checksize_Rsession(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tsread(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s)); +} + +static bool checksize_Rsread(struct _checksize_ctx *ctx) { + return checksize_d(ctx); +} + +static bool checksize_Tswrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s)) + || checksize_d(ctx); +} + +static bool checksize_Rswrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +/* unmarshal_* ****************************************************************/ + +static inline vold unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) { + *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 1; +} + +static inline vold unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) { + *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 2; +} + +static inline vold unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) { + *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 4; +} + +static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { + *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 8; +} + +static inline void unmarshal_d(struct _unmarshal_ctx *ctx, struct lib9p_d *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->len); + out->dat = ctx->host_extra; + ctx->host_extra += sizeof(out->dat[0]) * out->len; + for (typeof(out->len) i = 0; i < out->len; i++) + unmarshal_1(ctx, &out->dat[i]); +} + +static inline void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9p_s *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->len); + out->utf8 = ctx->host_extra; + ctx->host_extra += sizeof(out->utf8[0]) * out->len; + for (typeof(out->len) i = 0; i < out->len; i++) + unmarshal_1(ctx, &out->utf8[i]); +} + +static inline void unmarshal_qid(struct _unmarshal_ctx *ctx, struct lib9p_qid *out) { + memset(out, 0, sizeof(*out)); + unmarshal_1(ctx, &out->type); + unmarshal_4(ctx, &out->vers); + unmarshal_8(ctx, &out->path); +} + +static inline void unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->stat_size); + unmarshal_2(ctx, &out->kern_type); + unmarshal_4(ctx, &out->kern_dev); + unmarshal_qid(ctx, &out->file_qid); + unmarshal_4(ctx, &out->file_mode); + unmarshal_4(ctx, &out->file_atime); + unmarshal_4(ctx, &out->file_mtime); + unmarshal_8(ctx, &out->file_size); + unmarshal_s(ctx, &out->file_name); + unmarshal_s(ctx, &out->file_owner_uid); + unmarshal_s(ctx, &out->file_owner_gid); + unmarshal_s(ctx, &out->file_last_modified_uid); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_s(ctx, &out->file_extension); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_uid); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_gid); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_last_modified_n_uid); +} + +static void unmarshal_Tversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tversion *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->max_msg_size); + unmarshal_s(ctx, &out->version); +} + +static void unmarshal_Rversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rversion *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->max_msg_size); + unmarshal_s(ctx, &out->version); +} + +static void unmarshal_Tauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tauth *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->afid); + unmarshal_s(ctx, &out->uname); + unmarshal_s(ctx, &out->aname); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->n_uname); +} + +static void unmarshal_Rauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rauth *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->aqid); +} + +static void unmarshal_Tattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tattach *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_4(ctx, &out->afid); + unmarshal_s(ctx, &out->uname); + unmarshal_s(ctx, &out->aname); +} + +static void unmarshal_Rattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rattach *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->qid); +} + +static void unmarshal_Rerror(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rerror *out) { + memset(out, 0, sizeof(*out)); + unmarshal_s(ctx, &out->ename); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->errno); +} + +static void unmarshal_Tflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tflush *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->oldtag); +} + +static void unmarshal_Rflush(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Twalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twalk *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_4(ctx, &out->newfid); + unmarshal_2(ctx, &out->nwname); + out->wname = ctx->host_extra; + ctx->host_extra += sizeof(out->wname[0]) * out->nwname; + for (typeof(out->nwname) i = 0; i < out->nwname; i++) + unmarshal_s(ctx, &out->wname[i]); +} + +static void unmarshal_Rwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwalk *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->nwqid); + out->wqid = ctx->host_extra; + ctx->host_extra += sizeof(out->wqid[0]) * out->nwqid; + for (typeof(out->nwqid) i = 0; i < out->nwqid; i++) + unmarshal_qid(ctx, &out->wqid[i]); +} + +static void unmarshal_Topen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Topen *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_1(ctx, &out->mode); +} + +static void unmarshal_Ropen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Ropen *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->qid); + unmarshal_4(ctx, &out->iounit); +} + +static void unmarshal_Tcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tcreate *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_s(ctx, &out->name); + unmarshal_4(ctx, &out->perm); + unmarshal_1(ctx, &out->mode); +} + +static void unmarshal_Rcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rcreate *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->qid); + unmarshal_4(ctx, &out->iounit); +} + +static void unmarshal_Tread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_8(ctx, &out->offset); + unmarshal_4(ctx, &out->count); +} + +static void unmarshal_Rread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Twrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_8(ctx, &out->offset); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Rwrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->count); +} + +static void unmarshal_Tclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tclunk *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); +} + +static void unmarshal_Rclunk(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tremove *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); +} + +static void unmarshal_Rremove(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tstat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); +} + +static void unmarshal_Rstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rstat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_stat(ctx, &out->stat); +} + +static void unmarshal_Twstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twstat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_stat(ctx, &out->stat); +} + +static void unmarshal_Rwstat(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsession *out) { + memset(out, 0, sizeof(*out)); + unmarshal_8(ctx, &out->key); +} + +static void unmarshal_Rsession(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_2(ctx, &out->nwname); + out->wname = ctx->host_extra; + ctx->host_extra += sizeof(out->wname[0]) * out->nwname; + for (typeof(out->nwname) i = 0; i < out->nwname; i++) + unmarshal_s(ctx, &out->wname[i]); +} + +static void unmarshal_Rsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Tswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tswrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_2(ctx, &out->nwname); + out->wname = ctx->host_extra; + ctx->host_extra += sizeof(out->wname[0]) * out->nwname; + for (typeof(out->nwname) i = 0; i < out->nwname; i++) + unmarshal_s(ctx, &out->wname[i]); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Rswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rswrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->count); +} + +/* marshal_* ******************************************************************/ + +static inline bool _marshal_too_large(struct _marshal_ctx *ctx) { + lib9p_errorf(ctx->ctx, "%s too large to marshal into %s limit (limit=%"PRIu32")", + (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message", + ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"), + ctx->ctx->max_msg_size)); + return true; +} + +static inline bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) { + if (ctx->net_offset + 1 > ctx->max_msg_size) + return _marshal_too_large(ctx); + out_net_bytes[ctx->net_offset] = *val; + ctx->net_offset += 1; + return false; +} + +static inline bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) { + if (ctx->net_offset + 2 > ctx->max_msg_size) + return _marshal_too_large(ctx); + encode_u16le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 2; + return false; +} + +static inline bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) { + if (ctx->net_offset + 4 > ctx->max_msg_size) + return true; + encode_u32le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 4; + return false; +} + +static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { + if (ctx->net_offset + 8 > ctx->max_msg_size) + return true; + encode_u64le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 8; + return false; +} + +static inline bool marshal_d(struct _marshal_ctx *ctx, struct lib9p_d *val) { + return marshal_4(ctx, &val->len) + || ({ + bool err = false; + for (typeof(val->len) i = 0; i < val->len && !err; i++) + err = marshal_1(ctx, &val->dat[i])); + err; + }); +} + +static inline bool marshal_s(struct _marshal_ctx *ctx, struct lib9p_s *val) { + return marshal_2(ctx, &val->len) + || ({ + bool err = false; + for (typeof(val->len) i = 0; i < val->len && !err; i++) + err = marshal_1(ctx, &val->utf8[i])); + err; + }); +} + +static inline bool marshal_qid(struct _marshal_ctx *ctx, struct lib9p_qid *val) { + return marshal_1(ctx, &val->type) + || marshal_4(ctx, &val->vers) + || marshal_8(ctx, &val->path); +} + +static inline bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { + return marshal_2(ctx, &val->stat_size) + || marshal_2(ctx, &val->kern_type) + || marshal_4(ctx, &val->kern_dev) + || marshal_qid(ctx, &val->file_qid) + || marshal_4(ctx, &val->file_mode) + || marshal_4(ctx, &val->file_atime) + || marshal_4(ctx, &val->file_mtime) + || marshal_8(ctx, &val->file_size) + || marshal_s(ctx, &val->file_name) + || marshal_s(ctx, &val->file_owner_uid) + || marshal_s(ctx, &val->file_owner_gid) + || marshal_s(ctx, &val->file_last_modified_uid) + || marshal_s(ctx, &val->file_extension) + || marshal_4(ctx, &val->file_owner_n_uid) + || marshal_4(ctx, &val->file_owner_n_gid) + || marshal_4(ctx, &val->file_last_modified_n_uid); +} + +static bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) { + return marshal_4(ctx, &val->max_msg_size) + || marshal_s(ctx, &val->version); +} + +static bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) { + return marshal_4(ctx, &val->max_msg_size) + || marshal_s(ctx, &val->version); +} + +static bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) { + return marshal_4(ctx, &val->afid) + || marshal_s(ctx, &val->uname) + || marshal_s(ctx, &val->aname) + || marshal_4(ctx, &val->n_uname); +} + +static bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) { + return marshal_qid(ctx, &val->aqid); +} + +static bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) { + return marshal_4(ctx, &val->fid) + || marshal_4(ctx, &val->afid) + || marshal_s(ctx, &val->uname) + || marshal_s(ctx, &val->aname); +} + +static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) { + return marshal_qid(ctx, &val->qid); +} + +static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) { + return marshal_s(ctx, &val->ename) + || marshal_4(ctx, &val->errno); +} + +static bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) { + return marshal_2(ctx, &val->oldtag); +} + +static bool marshal_Rflush(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *UNUSED(val)) { + return false; +} + +static bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) { + return marshal_4(ctx, &val->fid) + || marshal_4(ctx, &val->newfid) + || marshal_2(ctx, &val->nwname) + || ({ + bool err = false; + for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) + err = marshal_s(ctx, &val->wname[i])); + err; + }); +} + +static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) { + return marshal_2(ctx, &val->nwqid) + || ({ + bool err = false; + for (typeof(val->nwqid) i = 0; i < val->nwqid && !err; i++) + err = marshal_qid(ctx, &val->wqid[i])); + err; + }); +} + +static bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) { + return marshal_4(ctx, &val->fid) + || marshal_1(ctx, &val->mode); +} + +static bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) { + return marshal_qid(ctx, &val->qid) + || marshal_4(ctx, &val->iounit); +} + +static bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) { + return marshal_4(ctx, &val->fid) + || marshal_s(ctx, &val->name) + || marshal_4(ctx, &val->perm) + || marshal_1(ctx, &val->mode); +} + +static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) { + return marshal_qid(ctx, &val->qid) + || marshal_4(ctx, &val->iounit); +} + +static bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) { + return marshal_4(ctx, &val->fid) + || marshal_8(ctx, &val->offset) + || marshal_4(ctx, &val->count); +} + +static bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) { + return marshal_d(ctx, &val->data); +} + +static bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) { + return marshal_4(ctx, &val->fid) + || marshal_8(ctx, &val->offset) + || marshal_d(ctx, &val->data); +} + +static bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) { + return marshal_4(ctx, &val->count); +} + +static bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) { + return marshal_4(ctx, &val->fid); +} + +static bool marshal_Rclunk(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *UNUSED(val)) { + return false; +} + +static bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) { + return marshal_4(ctx, &val->fid); +} + +static bool marshal_Rremove(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *UNUSED(val)) { + return false; +} + +static bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) { + return marshal_4(ctx, &val->fid); +} + +static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) { + return marshal_stat(ctx, &val->stat); +} + +static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) { + return marshal_4(ctx, &val->fid) + || marshal_stat(ctx, &val->stat); +} + +static bool marshal_Rwstat(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *UNUSED(val)) { + return false; +} + +static bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) { + return marshal_8(ctx, &val->key); +} + +static bool marshal_Rsession(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *UNUSED(val)) { + return false; +} + +static bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) { + return marshal_4(ctx, &val->fid) + || marshal_2(ctx, &val->nwname) + || ({ + bool err = false; + for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) + err = marshal_s(ctx, &val->wname[i])); + err; + }); +} + +static bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) { + return marshal_d(ctx, &val->data); +} + +static bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) { + return marshal_4(ctx, &val->fid) + || marshal_2(ctx, &val->nwname) + || ({ + bool err = false; + for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) + err = marshal_s(ctx, &val->wname[i])); + err; + }) + || marshal_d(ctx, &val->data); +} + +static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) { + return marshal_4(ctx, &val->count); +} + +/* vtables ********************************************************************/ + +struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM] = { + [LIB9P_VER_UNINITIALIZED] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + }, + [LIB9P_VER_9P2000] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + [LIB9P_TYP_Tauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth), + r.unmarshal_extrasize = checksize_Tauth, + r.unmarshal = unmarshal_Tauth, + r.marshal = (_marshal_fn_t)marshal_Tauth, + }, + [LIB9P_TYP_Rauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth), + r.unmarshal_extrasize = checksize_Rauth, + r.unmarshal = unmarshal_Rauth, + r.marshal = (_marshal_fn_t)marshal_Rauth, + }, + [LIB9P_TYP_Tattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach), + r.unmarshal_extrasize = checksize_Tattach, + r.unmarshal = unmarshal_Tattach, + r.marshal = (_marshal_fn_t)marshal_Tattach, + }, + [LIB9P_TYP_Rattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach), + r.unmarshal_extrasize = checksize_Rattach, + r.unmarshal = unmarshal_Rattach, + r.marshal = (_marshal_fn_t)marshal_Rattach, + }, + [LIB9P_TYP_Rerror] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror), + r.unmarshal_extrasize = checksize_Rerror, + r.unmarshal = unmarshal_Rerror, + r.marshal = (_marshal_fn_t)marshal_Rerror, + }, + [LIB9P_TYP_Tflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush), + r.unmarshal_extrasize = checksize_Tflush, + r.unmarshal = unmarshal_Tflush, + r.marshal = (_marshal_fn_t)marshal_Tflush, + }, + [LIB9P_TYP_Rflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush), + r.unmarshal_extrasize = checksize_Rflush, + r.unmarshal = unmarshal_Rflush, + r.marshal = (_marshal_fn_t)marshal_Rflush, + }, + [LIB9P_TYP_Twalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk), + r.unmarshal_extrasize = checksize_Twalk, + r.unmarshal = unmarshal_Twalk, + r.marshal = (_marshal_fn_t)marshal_Twalk, + }, + [LIB9P_TYP_Rwalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk), + r.unmarshal_extrasize = checksize_Rwalk, + r.unmarshal = unmarshal_Rwalk, + r.marshal = (_marshal_fn_t)marshal_Rwalk, + }, + [LIB9P_TYP_Topen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen), + r.unmarshal_extrasize = checksize_Topen, + r.unmarshal = unmarshal_Topen, + r.marshal = (_marshal_fn_t)marshal_Topen, + }, + [LIB9P_TYP_Ropen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen), + r.unmarshal_extrasize = checksize_Ropen, + r.unmarshal = unmarshal_Ropen, + r.marshal = (_marshal_fn_t)marshal_Ropen, + }, + [LIB9P_TYP_Tcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate), + r.unmarshal_extrasize = checksize_Tcreate, + r.unmarshal = unmarshal_Tcreate, + r.marshal = (_marshal_fn_t)marshal_Tcreate, + }, + [LIB9P_TYP_Rcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate), + r.unmarshal_extrasize = checksize_Rcreate, + r.unmarshal = unmarshal_Rcreate, + r.marshal = (_marshal_fn_t)marshal_Rcreate, + }, + [LIB9P_TYP_Tread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread), + r.unmarshal_extrasize = checksize_Tread, + r.unmarshal = unmarshal_Tread, + r.marshal = (_marshal_fn_t)marshal_Tread, + }, + [LIB9P_TYP_Rread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread), + r.unmarshal_extrasize = checksize_Rread, + r.unmarshal = unmarshal_Rread, + r.marshal = (_marshal_fn_t)marshal_Rread, + }, + [LIB9P_TYP_Twrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite), + r.unmarshal_extrasize = checksize_Twrite, + r.unmarshal = unmarshal_Twrite, + r.marshal = (_marshal_fn_t)marshal_Twrite, + }, + [LIB9P_TYP_Rwrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite), + r.unmarshal_extrasize = checksize_Rwrite, + r.unmarshal = unmarshal_Rwrite, + r.marshal = (_marshal_fn_t)marshal_Rwrite, + }, + [LIB9P_TYP_Tclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk), + r.unmarshal_extrasize = checksize_Tclunk, + r.unmarshal = unmarshal_Tclunk, + r.marshal = (_marshal_fn_t)marshal_Tclunk, + }, + [LIB9P_TYP_Rclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk), + r.unmarshal_extrasize = checksize_Rclunk, + r.unmarshal = unmarshal_Rclunk, + r.marshal = (_marshal_fn_t)marshal_Rclunk, + }, + [LIB9P_TYP_Tremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove), + r.unmarshal_extrasize = checksize_Tremove, + r.unmarshal = unmarshal_Tremove, + r.marshal = (_marshal_fn_t)marshal_Tremove, + }, + [LIB9P_TYP_Rremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove), + r.unmarshal_extrasize = checksize_Rremove, + r.unmarshal = unmarshal_Rremove, + r.marshal = (_marshal_fn_t)marshal_Rremove, + }, + [LIB9P_TYP_Tstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat), + r.unmarshal_extrasize = checksize_Tstat, + r.unmarshal = unmarshal_Tstat, + r.marshal = (_marshal_fn_t)marshal_Tstat, + }, + [LIB9P_TYP_Rstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat), + r.unmarshal_extrasize = checksize_Rstat, + r.unmarshal = unmarshal_Rstat, + r.marshal = (_marshal_fn_t)marshal_Rstat, + }, + [LIB9P_TYP_Twstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat), + r.unmarshal_extrasize = checksize_Twstat, + r.unmarshal = unmarshal_Twstat, + r.marshal = (_marshal_fn_t)marshal_Twstat, + }, + [LIB9P_TYP_Rwstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat), + r.unmarshal_extrasize = checksize_Rwstat, + r.unmarshal = unmarshal_Rwstat, + r.marshal = (_marshal_fn_t)marshal_Rwstat, + }, + }, + [LIB9P_VER_9P2000_e] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + [LIB9P_TYP_Tauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth), + r.unmarshal_extrasize = checksize_Tauth, + r.unmarshal = unmarshal_Tauth, + r.marshal = (_marshal_fn_t)marshal_Tauth, + }, + [LIB9P_TYP_Rauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth), + r.unmarshal_extrasize = checksize_Rauth, + r.unmarshal = unmarshal_Rauth, + r.marshal = (_marshal_fn_t)marshal_Rauth, + }, + [LIB9P_TYP_Tattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach), + r.unmarshal_extrasize = checksize_Tattach, + r.unmarshal = unmarshal_Tattach, + r.marshal = (_marshal_fn_t)marshal_Tattach, + }, + [LIB9P_TYP_Rattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach), + r.unmarshal_extrasize = checksize_Rattach, + r.unmarshal = unmarshal_Rattach, + r.marshal = (_marshal_fn_t)marshal_Rattach, + }, + [LIB9P_TYP_Rerror] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror), + r.unmarshal_extrasize = checksize_Rerror, + r.unmarshal = unmarshal_Rerror, + r.marshal = (_marshal_fn_t)marshal_Rerror, + }, + [LIB9P_TYP_Tflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush), + r.unmarshal_extrasize = checksize_Tflush, + r.unmarshal = unmarshal_Tflush, + r.marshal = (_marshal_fn_t)marshal_Tflush, + }, + [LIB9P_TYP_Rflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush), + r.unmarshal_extrasize = checksize_Rflush, + r.unmarshal = unmarshal_Rflush, + r.marshal = (_marshal_fn_t)marshal_Rflush, + }, + [LIB9P_TYP_Twalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk), + r.unmarshal_extrasize = checksize_Twalk, + r.unmarshal = unmarshal_Twalk, + r.marshal = (_marshal_fn_t)marshal_Twalk, + }, + [LIB9P_TYP_Rwalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk), + r.unmarshal_extrasize = checksize_Rwalk, + r.unmarshal = unmarshal_Rwalk, + r.marshal = (_marshal_fn_t)marshal_Rwalk, + }, + [LIB9P_TYP_Topen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen), + r.unmarshal_extrasize = checksize_Topen, + r.unmarshal = unmarshal_Topen, + r.marshal = (_marshal_fn_t)marshal_Topen, + }, + [LIB9P_TYP_Ropen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen), + r.unmarshal_extrasize = checksize_Ropen, + r.unmarshal = unmarshal_Ropen, + r.marshal = (_marshal_fn_t)marshal_Ropen, + }, + [LIB9P_TYP_Tcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate), + r.unmarshal_extrasize = checksize_Tcreate, + r.unmarshal = unmarshal_Tcreate, + r.marshal = (_marshal_fn_t)marshal_Tcreate, + }, + [LIB9P_TYP_Rcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate), + r.unmarshal_extrasize = checksize_Rcreate, + r.unmarshal = unmarshal_Rcreate, + r.marshal = (_marshal_fn_t)marshal_Rcreate, + }, + [LIB9P_TYP_Tread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread), + r.unmarshal_extrasize = checksize_Tread, + r.unmarshal = unmarshal_Tread, + r.marshal = (_marshal_fn_t)marshal_Tread, + }, + [LIB9P_TYP_Rread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread), + r.unmarshal_extrasize = checksize_Rread, + r.unmarshal = unmarshal_Rread, + r.marshal = (_marshal_fn_t)marshal_Rread, + }, + [LIB9P_TYP_Twrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite), + r.unmarshal_extrasize = checksize_Twrite, + r.unmarshal = unmarshal_Twrite, + r.marshal = (_marshal_fn_t)marshal_Twrite, + }, + [LIB9P_TYP_Rwrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite), + r.unmarshal_extrasize = checksize_Rwrite, + r.unmarshal = unmarshal_Rwrite, + r.marshal = (_marshal_fn_t)marshal_Rwrite, + }, + [LIB9P_TYP_Tclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk), + r.unmarshal_extrasize = checksize_Tclunk, + r.unmarshal = unmarshal_Tclunk, + r.marshal = (_marshal_fn_t)marshal_Tclunk, + }, + [LIB9P_TYP_Rclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk), + r.unmarshal_extrasize = checksize_Rclunk, + r.unmarshal = unmarshal_Rclunk, + r.marshal = (_marshal_fn_t)marshal_Rclunk, + }, + [LIB9P_TYP_Tremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove), + r.unmarshal_extrasize = checksize_Tremove, + r.unmarshal = unmarshal_Tremove, + r.marshal = (_marshal_fn_t)marshal_Tremove, + }, + [LIB9P_TYP_Rremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove), + r.unmarshal_extrasize = checksize_Rremove, + r.unmarshal = unmarshal_Rremove, + r.marshal = (_marshal_fn_t)marshal_Rremove, + }, + [LIB9P_TYP_Tstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat), + r.unmarshal_extrasize = checksize_Tstat, + r.unmarshal = unmarshal_Tstat, + r.marshal = (_marshal_fn_t)marshal_Tstat, + }, + [LIB9P_TYP_Rstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat), + r.unmarshal_extrasize = checksize_Rstat, + r.unmarshal = unmarshal_Rstat, + r.marshal = (_marshal_fn_t)marshal_Rstat, + }, + [LIB9P_TYP_Twstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat), + r.unmarshal_extrasize = checksize_Twstat, + r.unmarshal = unmarshal_Twstat, + r.marshal = (_marshal_fn_t)marshal_Twstat, + }, + [LIB9P_TYP_Rwstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat), + r.unmarshal_extrasize = checksize_Rwstat, + r.unmarshal = unmarshal_Rwstat, + r.marshal = (_marshal_fn_t)marshal_Rwstat, + }, + [LIB9P_TYP_Tsession] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tsession), + r.unmarshal_extrasize = checksize_Tsession, + r.unmarshal = unmarshal_Tsession, + r.marshal = (_marshal_fn_t)marshal_Tsession, + }, + [LIB9P_TYP_Rsession] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rsession), + r.unmarshal_extrasize = checksize_Rsession, + r.unmarshal = unmarshal_Rsession, + r.marshal = (_marshal_fn_t)marshal_Rsession, + }, + [LIB9P_TYP_Tsread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tsread), + r.unmarshal_extrasize = checksize_Tsread, + r.unmarshal = unmarshal_Tsread, + r.marshal = (_marshal_fn_t)marshal_Tsread, + }, + [LIB9P_TYP_Rsread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rsread), + r.unmarshal_extrasize = checksize_Rsread, + r.unmarshal = unmarshal_Rsread, + r.marshal = (_marshal_fn_t)marshal_Rsread, + }, + [LIB9P_TYP_Tswrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tswrite), + r.unmarshal_extrasize = checksize_Tswrite, + r.unmarshal = unmarshal_Tswrite, + r.marshal = (_marshal_fn_t)marshal_Tswrite, + }, + [LIB9P_TYP_Rswrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rswrite), + r.unmarshal_extrasize = checksize_Rswrite, + r.unmarshal = unmarshal_Rswrite, + r.marshal = (_marshal_fn_t)marshal_Rswrite, + }, + }, + [LIB9P_VER_9P2000_u] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + [LIB9P_TYP_Tauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth), + r.unmarshal_extrasize = checksize_Tauth, + r.unmarshal = unmarshal_Tauth, + r.marshal = (_marshal_fn_t)marshal_Tauth, + }, + [LIB9P_TYP_Rauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth), + r.unmarshal_extrasize = checksize_Rauth, + r.unmarshal = unmarshal_Rauth, + r.marshal = (_marshal_fn_t)marshal_Rauth, + }, + [LIB9P_TYP_Tattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach), + r.unmarshal_extrasize = checksize_Tattach, + r.unmarshal = unmarshal_Tattach, + r.marshal = (_marshal_fn_t)marshal_Tattach, + }, + [LIB9P_TYP_Rattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach), + r.unmarshal_extrasize = checksize_Rattach, + r.unmarshal = unmarshal_Rattach, + r.marshal = (_marshal_fn_t)marshal_Rattach, + }, + [LIB9P_TYP_Rerror] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror), + r.unmarshal_extrasize = checksize_Rerror, + r.unmarshal = unmarshal_Rerror, + r.marshal = (_marshal_fn_t)marshal_Rerror, + }, + [LIB9P_TYP_Tflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush), + r.unmarshal_extrasize = checksize_Tflush, + r.unmarshal = unmarshal_Tflush, + r.marshal = (_marshal_fn_t)marshal_Tflush, + }, + [LIB9P_TYP_Rflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush), + r.unmarshal_extrasize = checksize_Rflush, + r.unmarshal = unmarshal_Rflush, + r.marshal = (_marshal_fn_t)marshal_Rflush, + }, + [LIB9P_TYP_Twalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk), + r.unmarshal_extrasize = checksize_Twalk, + r.unmarshal = unmarshal_Twalk, + r.marshal = (_marshal_fn_t)marshal_Twalk, + }, + [LIB9P_TYP_Rwalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk), + r.unmarshal_extrasize = checksize_Rwalk, + r.unmarshal = unmarshal_Rwalk, + r.marshal = (_marshal_fn_t)marshal_Rwalk, + }, + [LIB9P_TYP_Topen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen), + r.unmarshal_extrasize = checksize_Topen, + r.unmarshal = unmarshal_Topen, + r.marshal = (_marshal_fn_t)marshal_Topen, + }, + [LIB9P_TYP_Ropen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen), + r.unmarshal_extrasize = checksize_Ropen, + r.unmarshal = unmarshal_Ropen, + r.marshal = (_marshal_fn_t)marshal_Ropen, + }, + [LIB9P_TYP_Tcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate), + r.unmarshal_extrasize = checksize_Tcreate, + r.unmarshal = unmarshal_Tcreate, + r.marshal = (_marshal_fn_t)marshal_Tcreate, + }, + [LIB9P_TYP_Rcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate), + r.unmarshal_extrasize = checksize_Rcreate, + r.unmarshal = unmarshal_Rcreate, + r.marshal = (_marshal_fn_t)marshal_Rcreate, + }, + [LIB9P_TYP_Tread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread), + r.unmarshal_extrasize = checksize_Tread, + r.unmarshal = unmarshal_Tread, + r.marshal = (_marshal_fn_t)marshal_Tread, + }, + [LIB9P_TYP_Rread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread), + r.unmarshal_extrasize = checksize_Rread, + r.unmarshal = unmarshal_Rread, + r.marshal = (_marshal_fn_t)marshal_Rread, + }, + [LIB9P_TYP_Twrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite), + r.unmarshal_extrasize = checksize_Twrite, + r.unmarshal = unmarshal_Twrite, + r.marshal = (_marshal_fn_t)marshal_Twrite, + }, + [LIB9P_TYP_Rwrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite), + r.unmarshal_extrasize = checksize_Rwrite, + r.unmarshal = unmarshal_Rwrite, + r.marshal = (_marshal_fn_t)marshal_Rwrite, + }, + [LIB9P_TYP_Tclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk), + r.unmarshal_extrasize = checksize_Tclunk, + r.unmarshal = unmarshal_Tclunk, + r.marshal = (_marshal_fn_t)marshal_Tclunk, + }, + [LIB9P_TYP_Rclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk), + r.unmarshal_extrasize = checksize_Rclunk, + r.unmarshal = unmarshal_Rclunk, + r.marshal = (_marshal_fn_t)marshal_Rclunk, + }, + [LIB9P_TYP_Tremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove), + r.unmarshal_extrasize = checksize_Tremove, + r.unmarshal = unmarshal_Tremove, + r.marshal = (_marshal_fn_t)marshal_Tremove, + }, + [LIB9P_TYP_Rremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove), + r.unmarshal_extrasize = checksize_Rremove, + r.unmarshal = unmarshal_Rremove, + r.marshal = (_marshal_fn_t)marshal_Rremove, + }, + [LIB9P_TYP_Tstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat), + r.unmarshal_extrasize = checksize_Tstat, + r.unmarshal = unmarshal_Tstat, + r.marshal = (_marshal_fn_t)marshal_Tstat, + }, + [LIB9P_TYP_Rstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat), + r.unmarshal_extrasize = checksize_Rstat, + r.unmarshal = unmarshal_Rstat, + r.marshal = (_marshal_fn_t)marshal_Rstat, + }, + [LIB9P_TYP_Twstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat), + r.unmarshal_extrasize = checksize_Twstat, + r.unmarshal = unmarshal_Twstat, + r.marshal = (_marshal_fn_t)marshal_Twstat, + }, + [LIB9P_TYP_Rwstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat), + r.unmarshal_extrasize = checksize_Rwstat, + r.unmarshal = unmarshal_Rwstat, + r.marshal = (_marshal_fn_t)marshal_Rwstat, + }, + }, +}; diff --git a/lib9p/types.gen b/lib9p/types.gen new file mode 100755 index 0000000..141b591 --- /dev/null +++ b/lib9p/types.gen @@ -0,0 +1,611 @@ +#!/usr/bin/env python +# lib9p/types.gen - Generate C marshalers/unmarshalers for .txt files +# defining 9P protocol variants. +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +import enum +import os.path +import re +from typing import Callable + +# Parse *.txt ################################################################## + + +class Atom(enum.Enum): + u8 = 1 + u16 = 2 + u32 = 4 + u64 = 8 + + @property + def name(self) -> str: + return str(self.value) + + @property + def static_size(self) -> int: + return self.value + + +# `msgid/structname = "member1 member2..."` +# `structname = "member1 member2..."` +# `structname += "member1 member2..."` +class Struct: + msgid: int | None = None + msgver: set[str] + name: str + members: list["Member"] + + def __init__(self) -> None: + self.msgver = set() + + @property + def static_size(self) -> int | None: + size = 0 + for member in self.members: + msize = member.static_size + if msize is None: + return None + size += msize + return size + + +# `cnt*(name[typ])` +# the `cnt*(...)` wrapper is optional +class Member: + cnt: str | None = None + name: str + typ: Atom | Struct + ver: set[str] + + @property + def static_size(self) -> int | None: + if self.cnt: + return None + return self.typ.static_size + + +re_membername = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" +re_memberspec = ( + f"(?:(?P{re_membername})\\*\\()?(?P{re_membername})\\[(?P.*)\\]\\)?" +) + + +def parse_members( + ver: str, + env: dict[str, Atom | Struct], existing: list[Member], specs: str +) -> list[Member]: + ret = existing + for spec in specs.split(): + m = re.fullmatch(re_memberspec, spec) + if not m: + raise SyntaxError(f"invalid member spec {repr(spec)}") + + member = Member() + member.ver = {ver} + + member.name = m.group("name") + if any(x.name == member.name for x in ret): + raise ValueError(f"duplicate member name {repr(member.name)}") + + if m.group("typ") not in env: + raise NameError(f"Unknown type {repr(m.group(2))}") + member.typ = env[m.group("typ")] + + if cnt := m.group("cnt"): + if len(ret) == 0 or ret[-1].name != cnt: + raise ValueError(f"list count must be previous item: {repr(cnt)}") + if not isinstance(ret[-1].typ, Atom): + raise ValueError(f"list count must be an integer type: {repr(cnt)}") + member.cnt = cnt + + ret += [member] + return ret + + +re_version = r'version\s+"(?P[^"]+)"' +re_import = r'from\s+(?P\S+)\s+import\s+(?P\S+(?:\s*,\s*\S+)*)\s*' +re_structspec = ( + r'(?:(?P[0-9]+)/)?(?P\S+)\s*(?P\+?=)\s*"(?P[^"]*)"' +) +re_structspec_cont = r'"(?P[^"]*)"' + + +def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struct]]]) -> tuple[str, list[Struct]]: + version: str | None = None + env: dict[str, Atom | Struct] = { + "1": Atom.u8, + "2": Atom.u16, + "4": Atom.u32, + "8": Atom.u64, + } + with open(filename, "r") as fh: + prev: Struct | None = None + for line in fh: + line = line.split("#", 1)[0].strip() + if not line: + continue + if m := re.fullmatch(re_version, line): + if version: + raise SyntaxError("must have exactly 1 version line") + version = m.group("version") + elif m := re.fullmatch(re_import, line): + if not version: + raise SyntaxError("must have exactly 1 version line") + other_version, other_structs = get_include(m.group("file")) + for symname in m.group("syms").split(sep=","): + symname = symname.strip() + for struct in other_structs: + if struct.name == symname or symname == '*': + if struct.msgid: + struct.msgver.add(version) + for member in struct.members: + if other_version in member.ver: + member.ver.add(version) + env[struct.name] = struct + elif m := re.fullmatch(re_structspec, line): + if not version: + raise SyntaxError("must have exactly 1 version line") + if m.group("op") == "+=" and m.group("msgid"): + raise SyntaxError("cannot += to a message that is not yet defined") + match m.group("op"): + case "=": + struct = Struct() + if m.group("msgid"): + struct.msgid = int(m.group("msgid")) + struct.msgver.add(version) + struct.name = m.group("name") + struct.members = parse_members(version, env, [], m.group("members")) + env[struct.name] = struct + prev = struct + case "+=": + if m.group("name") not in env: + raise NameError(f"Unknown type {repr(m.group('name'))}") + _struct = env[m.group("name")] + if not isinstance(_struct, Struct): + raise NameError( + f"Type {repr(m.group('name'))} is not a struct" + ) + struct = _struct + struct.members = parse_members(version, + env, struct.members, m.group("members") + ) + prev = struct + elif m := re.fullmatch(re_structspec_cont, line): + if not prev: + raise SyntaxError("continuation line must come after a struct line") + assert(version) + prev.members = parse_members(version, env, prev.members, m.group("members")) + else: + raise SyntaxError(f"invalid line {repr(line)}") + if not version: + raise SyntaxError("must have exactly 1 version line") + structs = [x for x in env.values() if isinstance(x, Struct)] + return version, structs + +# Generate C ################################################################### + + +def c_typename(idprefix: str, typ: Atom | Struct) -> str: + match typ: + case Atom(): + return f"uint{typ.value*8}_t" + case Struct(): + if typ.msgid is not None: + return f"struct {idprefix}msg_{typ.name}" + return f"struct {idprefix}{typ.name}" + case _: + raise ValueError(f"not a type: {typ.__class__.__name__}") + +def c_vercomment(versions: set[str]) -> str|None: + if "9P2000" in versions: + return None + return "/* "+(", ".join(sorted(versions)))+" */" + +def c_ver(idprefix: str, ver: str) -> str: + return f"{idprefix.upper()}VER_{ver.replace('.', '_')}" + +def gen_h(idprefix: str, versions: set[str], structs: list[Struct]) -> str: + guard = "_LIB9P__TYPES_H_" + ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ + +#ifndef {guard} +#define {guard} + +#include +""" + + ret += f""" +/* versions *******************************************************************/ + +enum {idprefix}version {{ + {idprefix.upper()}VER_UNINITIALIZED = 0, +""" + verwidth = max(len(v) for v in versions) + for ver in sorted(versions): + ret += f"\t{c_ver(idprefix, ver)}," + ret += (" "*(verwidth-len(ver))) + ' /* "' + ver + '" */\n' + ret += f"\t{idprefix.upper()}VER_NUM,\n" + ret += "};\n" + + ret += """ +/* non-message structs ********************************************************/ +""" + for struct in structs: + if struct.msgid is not None: + continue + + all_the_same = len(struct.members) == 0 or all(m.ver == struct.members[0].ver for m in struct.members) + typewidth = max(len(c_typename(idprefix, m.typ)) for m in struct.members) + if not all_the_same: + namewidth = max(len(m.name) for m in struct.members) + + ret += "\n" + ret += c_typename(idprefix, struct) + " {\n" + for member in struct.members: + ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};" + if (not all_the_same) and (comment := c_vercomment(member.ver)): + ret += (" "*(namewidth-len(member.name))) + " " + comment + ret += "\n" + ret += "};\n" + + ret += """ +/* messages *******************************************************************/ + +""" + ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n" + namewidth = max(len(msg.name) for msg in structs if msg.msgid is not None) + for msg in structs: + if msg.msgid is None: + continue + ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid}," + if (comment := c_vercomment(msg.msgver)): + ret += " " + comment + ret += "\n" + ret += "};\n" + + ret += "\n" + ret += f"#define {idprefix.upper()}TYPECODE_FOR_CTYPE(msg) _Generic((msg)" + for msg in structs: + if msg.msgid is None: + continue + ret += f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}" + ret += ")\n" + + for msg in structs: + if msg.msgid is None: + continue + + ret += "\n" + if comment := c_vercomment(msg.msgver): + ret += comment + "\n" + ret += c_typename(idprefix, msg) + " {" + if not msg.members: + ret += "};\n" + continue + ret += "\n" + + all_the_same = len(msg.members) == 0 or all(m.ver == msg.members[0].ver for m in msg.members) + typewidth = max(len(c_typename(idprefix, m.typ)) for m in msg.members) + if not all_the_same: + namewidth = max(len(m.name) for m in msg.members) + + for member in msg.members: + ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};" + if (not all_the_same) and (comment := c_vercomment(member.ver)): + ret += (" "*(namewidth-len(member.name))) + " " + comment + ret += "\n" + ret += "};\n" + + + ret += "\n" + ret += f"#endif /* {guard} */\n" + return ret + + +def gen_c(idprefix: str, versions: set[str], structs: list[Struct]) -> str: + ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ + +#include + +#include + +#include "internal.h" +""" + + def used(arg: str) -> str: + return arg + + def unused(arg: str) -> str: + return f"UNUSED({arg})" + + # checksize_* ############################################################## + ret += """ +/* checksize_* (internals of unmarshal_size()) ********************************/ + +static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) { + if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset)) + /* If needed-net-size overflowed uint32_t, then + * there's no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + if (ctx->net_offset > ctx->net_size) + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_host(struct _checksize_ctx *ctx, size_t n) { + if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra)) + /* If needed-host-size overflowed size_t, then there's + * no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_list(struct _checksize_ctx *ctx, + size_t cnt, _checksize_fn_t item_fn, size_t item_host_size) { + for (size_t i = 0; i < cnt; i++) + if (_checksize_host(ctx, item_host_size) || item_fn(ctx)) + return true; + return false; +} + +#define checksize_1(ctx) _checksize_net(ctx, 1) +#define checksize_2(ctx) _checksize_net(ctx, 2) +#define checksize_4(ctx) _checksize_net(ctx, 4) +#define checksize_8(ctx) _checksize_net(ctx, 8) +""" + for struct in structs: + inline = ' inline' if struct.msgid is None else '' + argfn = used if struct.members else unused + ret += "\n" + ret += f"static{inline} bool checksize_{struct.name}(struct _checksize_ctx *{argfn('ctx')}) {{" + if len(struct.members) == 0: + ret += "\n\treturn false;\n" + ret += "}\n" + continue + + prefix0 = "\treturn " + prefix1 = "\t || " + + match struct.name: + case "d": + # Optimize... maybe the compiler could figure out to do + # this, but let's make it obvious. + ret += "\n" + ret += "\tuint32_t base_offset = ctx->net_offset;\n" + ret += "\tif (_checksize_4(ctx))\n" + ret += "\t\treturn true;\n" + ret += "\tuint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);\n" + ret += "\treturn checksize_net(ctx, len) || checksize_host(ctx, len);\n" + ret += "}\n" + case "s": + # Add an extra nul-byte on the host, and validate + # UTF-8 (also, similar optimization to "d"). + ret += "\n" + ret += "\tuint32_t base_offset = ctx->net_offset;\n" + ret += "\tif (_checksize_2(ctx))\n" + ret += "\t\treturn true;\n" + ret += "\tuint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);\n" + ret += "\tif (checksize_net(ctx, len) || checksize_host(ctx, ((size_t)len)+1))\n" + ret += "\t\treturn true;\n" + ret += "\tif (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len))\n" + ret += '\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8");\n' + ret += "\treturn false;\n" + ret += "}\n" + case _: + struct_versions = struct.members[0].ver + + prefix = prefix0 + prev_size: int | None = None + for member in struct.members: + ret += f"\n{prefix}" + if member.ver != struct_versions: + ret += "( ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) && " + if member.cnt is not None: + assert prev_size + ret += f"_checksize_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" + else: + ret += f"checksize_{member.typ.name}(ctx)" + if member.ver != struct_versions: + ret += " )" + prefix = prefix1 + prev_size = member.static_size + ret += ";\n}\n" + + # unmarshal_* ############################################################## + ret += """ +/* unmarshal_* ****************************************************************/ + +static inline vold unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) { + *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 1; +} + +static inline vold unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) { + *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 2; +} + +static inline vold unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) { + *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 4; +} + +static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { + *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 8; +} +""" + for struct in structs: + inline = ' inline' if struct.msgid is None else '' + argfn = used if struct.members else unused + ret += "\n" + ret += f"static{inline} void unmarshal_{struct.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('out')}) {{\n" + ret += "\tmemset(out, 0, sizeof(*out));\n" + + if struct.members: + struct_versions = struct.members[0].ver + for member in struct.members: + ret += "\t" + prefix = "\t" + if member.ver != struct_versions: + ret += "if ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) " + prefix = "\t\t" + if member.cnt: + if member.ver != struct_versions: + ret += "{\n" + ret += f"{prefix}out->{member.name} = ctx->host_extra;\n" + ret += f"{prefix}ctx->host_extra += sizeof(out->{member.name}[0]) * out->{member.cnt};\n" + ret += f"{prefix}for (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n" + ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n" + if member.ver != struct_versions: + ret += "\t}\n" + else: + ret += f"unmarshal_{member.typ.name}(ctx, &out->{member.name});\n" + ret += "}\n" + + # marshal_* ################################################################ + ret += """ +/* marshal_* ******************************************************************/ + +static inline bool _marshal_too_large(struct _marshal_ctx *ctx) { + lib9p_errorf(ctx->ctx, "%s too large to marshal into %s limit (limit=%"PRIu32")", + (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message", + ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"), + ctx->ctx->max_msg_size)); + return true; +} + +static inline bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) { + if (ctx->net_offset + 1 > ctx->max_msg_size) + return _marshal_too_large(ctx); + out_net_bytes[ctx->net_offset] = *val; + ctx->net_offset += 1; + return false; +} + +static inline bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) { + if (ctx->net_offset + 2 > ctx->max_msg_size) + return _marshal_too_large(ctx); + encode_u16le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 2; + return false; +} + +static inline bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) { + if (ctx->net_offset + 4 > ctx->max_msg_size) + return true; + encode_u32le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 4; + return false; +} + +static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { + if (ctx->net_offset + 8 > ctx->max_msg_size) + return true; + encode_u64le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 8; + return false; +} +""" + for struct in structs: + inline = ' inline' if struct.msgid is None else '' + argfn = used if struct.members else unused + ret += "\n" + ret += f"static{inline} bool marshal_{struct.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('val')}) {{" + if len(struct.members) == 0: + ret += "\n\treturn false;\n" + ret += "}\n" + continue + + prefix0 = "\treturn " + prefix1 = "\t || " + prefix2 = "\t " + + prefix = prefix0 + for member in struct.members: + if member.cnt: + ret += f"\n{prefix }({{" + ret += f"\n{prefix2}\tbool err = false;" + ret += f"\n{prefix2}\tfor (typeof(val->{member.cnt}) i = 0; i < val->{member.cnt} && !err; i++)" + ret += f"\n{prefix2}\t\terr = marshal_{member.typ.name}(ctx, &val->{member.name}[i]));" + ret += f"\n{prefix2}\terr;" + ret += f"\n{prefix2}}})" + else: + ret += f"\n{prefix}marshal_{member.typ.name}(ctx, &val->{member.name})" + prefix = prefix1 + ret += ";\n}\n" + + # vtables ################################################################## + def msg_entry(msg: Struct) -> str: + ret = "" + ret += f"\t\t[{idprefix.upper()}TYP_{msg.name}] = {{\n" + ret += f"\t\t\tr.unmarshal_basesize = sizeof({c_typename(idprefix, msg)}),\n" + ret += f"\t\t\tr.unmarshal_extrasize = checksize_{msg.name},\n" + ret += f"\t\t\tr.unmarshal = unmarshal_{msg.name},\n" + ret += f"\t\t\tr.marshal = (_marshal_fn_t)marshal_{msg.name},\n" + ret += "\t\t}" + return ret + ret += f""" +/* vtables ********************************************************************/ + +struct _vtable_version _{idprefix}vtables[LIB9P_VER_NUM] = {{ + [{idprefix.upper()}VER_UNINITIALIZED] = {{ +{msg_entry(next(msg for msg in structs if msg.name == 'Tversion'))}, +{msg_entry(next(msg for msg in structs if msg.name == 'Rversion'))}, + }}, +""" + for ver in sorted(versions): + ret += f"\t[{c_ver(idprefix, ver)}] = {{\n" + for msg in structs: + if ver not in msg.msgver: + continue + ret += msg_entry(msg) + ",\n" + ret += "\t},\n" + ret += "};\n" + + ############################################################################ + return ret + + +################################################################################ + +class Parser: + cache: dict[str, tuple[str, list[Struct]]] = {} + + def parse_file(self, filename: str) -> tuple[str, list[Struct]]: + if filename not in self.cache: + self.cache[filename] = parse_file(filename, self.parse_file) + return self.cache[filename] + + def all(self) -> tuple[set[str], list[Struct]]: + ret_versions: set[str] = set() + ret_structs: dict[str, Struct] = {} + for (version, structs) in self.cache.values(): + if version in ret_versions: + raise ValueError(f"duplicate protocol version {repr(version)}") + ret_versions.add(version) + for struct in structs: + if struct.name in ret_structs: + if struct != ret_structs[struct.name]: + raise ValueError(f"duplicate struct name {repr(struct.name)}") + else: + ret_structs[struct.name] = struct + return ret_versions, list(ret_structs.values()) + +if __name__ == "__main__": + import sys + + if len(sys.argv) < 2: + raise ValueError("requires at least 1 .txt filename") + parser = Parser() + for txtname in sys.argv[1:]: + parser.parse_file(txtname) + versions, structs = parser.all() + with open("include/lib9p/_types.h", "w") as fh: + fh.write(gen_h("lib9p_", versions, structs)) + with open("types.c", "w") as fh: + fh.write(gen_c("lib9p_", versions, structs)) diff --git a/libcr/CMakeLists.txt b/libcr/CMakeLists.txt new file mode 100644 index 0000000..ad7997f --- /dev/null +++ b/libcr/CMakeLists.txt @@ -0,0 +1,10 @@ +# libcr/CMakeLists.txt - TODO +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libcr INTERFACE) +target_sources(libcr INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/coroutine.c +) +target_include_directories(libcr SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 12d4a25..34a96b6 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -10,7 +10,7 @@ #include #include -#include "coroutine.h" +#include "libcr/coroutine.h" /* Configuration **************************************************************/ diff --git a/libcr/coroutine.h b/libcr/coroutine.h deleted file mode 100644 index 4d83181..0000000 --- a/libcr/coroutine.h +++ /dev/null @@ -1,130 +0,0 @@ -/* coroutine.h - Simple embeddable coroutine implementation - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -/** - * A coroutine is a cooperatively-multitasked form of threading. - * - * This coroutine.{h,c} form a lightweight coroutine implementation - * for non-multithreaded environments (only one coroutine may be - * running at a time (so no m:n scheduling), coroutine_{add,main} may - * not be called concurrently with eachother). - * - * Unlike many other lightweight or embeddable coroutine - * implementations, coroutine.{h,c} allow coroutines to use the stack - * as normal C functions and do not forbid switch() blocks in - * coroutines. - * - * See also: coroutine_rpc.h is a request/response system built on top - * of coroutine.{h,c}. - * - * See also: coroutine_chan.h is a 1-way channel system built on top - * of coroutine.{h,c}. - */ -#ifndef _COROUTINE_H_ -#define _COROUTINE_H_ - -#include /* for size_t */ -#include /* for bool */ - -/* typedefs *******************************************************************/ - -/** - * A cid_t is a "coroutine ID", used to refer to a coroutine. - * - * May be reused if a coroutine exits. - * - * Valid IDs are `1 <= cid <= COROUTINE_NUM`; `0` is used for - * "none/invalid". - */ -typedef size_t cid_t; - -/** - * The root function for a coroutine; a coroutine function should be - * declared as - * - * COROUTINE myfunc(void *_args) { - * myargtype *args = args; - * cr_begin(); - * - * ... - * - * cr_end(); - * } - * - * The function MUST NOT ever return (GCC enforces this); call - * cr_exit() or cr_end() instead of returning. - * - * When creating a coroutine with coroutine_add(), the bit before - * cr_begin() runs before coroutine_add() returns; if `_args` points - * to a place on another coroutine's stack that may go away, then this - * is an opportunity to copy it to this coroutine's stack. Otherwise - * you shouldn't do anything else before calling cr_begin(). - * Specifically, coroutine_add() and - * cr_{yield,pause_and_yield,exit,end}() are explicitly forbidden to - * call from within a coroutine before cr_begin() (note that the - * cr_rpc_*() and cr_chan_*() macros call these functions). - */ -typedef void (*cr_fn_t)(void *args); -#define COROUTINE __attribute__ ((noreturn)) void - -/* managing coroutines ********************************************************/ - -/** - * Call `fn(args)` in a new coroutine with stack size `stack_size`. - * - * See the doc comment on c_fn_t for the requirements imposed on fn. - * - * May be called from outside any coroutine (before calling - * coroutine_main()) or from inside of a coroutine (after it cas - * called cr_begin()). - * - * Returns the cid of the newly-created coroutine. May return 0 if - * there are already COROUTINE_NUM active coroutines. - */ -cid_t coroutine_add_with_stack_size(size_t stack_size, cr_fn_t fn, void *args); - -/** - * Like coroutine_add_with_stack_size(), but uses a default stack size so - * you don't need to think about it. - */ -#define coroutine_add(fn, args) coroutine_add_with_stack_size(0, fn, args) - -/** - * The main scheduler loop. - * - * "Should" never return, but will print a message to stderr and - * return if the program has deadlocked and there are no runnable - * coroutines. So be sure to call coroutine_add() at least once - * before calling this. - */ -void coroutine_main(void); - -/* inside of coroutines *******************************************************/ - -/** cr_begin() goes at the beginning of a coroutine, after it has initialized its stack. */ -void cr_begin( void); -/** cr_exit() terminates the currently-running coroutine. */ -__attribute__ ((noreturn)) void cr_exit(void); -/** cr_yield() switches to another coroutine (if there is another runnable coroutine to switch to). */ -void cr_yield(void); -/** cr_pause_and_yield() marks the current coroutine as not-runnable and switches to another coroutine. */ -void cr_pause_and_yield(void); -/** cr_unpause() marks a coroutine as runnable that has previously marked itself as non-runnable with cr_pause_and_yield(). */ -void cr_unpause(cid_t); -/** cr_unpause_from_sighandler() is like cr_unpause(), but safe to call from a signal handler that might race with the coroutine actually pausing itself. */ -void cr_unpause_from_sighandler(cid_t); -/** cr_end() is a counterpart to cr_begin(), but is really just cr_exit(). */ -#define cr_end cr_exit - -/** cr_getcid() returns the cid of the currently-running coroutine. */ -cid_t cr_getcid(void); - -/** - * It is not possible for one coroutine to kill another or to mark - * another as paused; a coroutine may only do those things to itself. - */ - -#endif /* _COROUTINE_H_ */ diff --git a/libcr/include/libcr/coroutine.h b/libcr/include/libcr/coroutine.h new file mode 100644 index 0000000..5c2d608 --- /dev/null +++ b/libcr/include/libcr/coroutine.h @@ -0,0 +1,130 @@ +/* libcr/coroutine.h - Simple embeddable coroutine implementation + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +/** + * A coroutine is a cooperatively-multitasked form of threading. + * + * This coroutine.{h,c} form a lightweight coroutine implementation + * for non-multithreaded environments (only one coroutine may be + * running at a time (so no m:n scheduling), coroutine_{add,main} may + * not be called concurrently with eachother). + * + * Unlike many other lightweight or embeddable coroutine + * implementations, coroutine.{h,c} allow coroutines to use the stack + * as normal C functions and do not forbid switch() blocks in + * coroutines. + * + * See also: coroutine_rpc.h is a request/response system built on top + * of coroutine.{h,c}. + * + * See also: coroutine_chan.h is a 1-way channel system built on top + * of coroutine.{h,c}. + */ +#ifndef _COROUTINE_H_ +#define _COROUTINE_H_ + +#include /* for size_t */ +#include /* for bool */ + +/* typedefs *******************************************************************/ + +/** + * A cid_t is a "coroutine ID", used to refer to a coroutine. + * + * May be reused if a coroutine exits. + * + * Valid IDs are `1 <= cid <= COROUTINE_NUM`; `0` is used for + * "none/invalid". + */ +typedef size_t cid_t; + +/** + * The root function for a coroutine; a coroutine function should be + * declared as + * + * COROUTINE myfunc(void *_args) { + * myargtype *args = args; + * cr_begin(); + * + * ... + * + * cr_end(); + * } + * + * The function MUST NOT ever return (GCC enforces this); call + * cr_exit() or cr_end() instead of returning. + * + * When creating a coroutine with coroutine_add(), the bit before + * cr_begin() runs before coroutine_add() returns; if `_args` points + * to a place on another coroutine's stack that may go away, then this + * is an opportunity to copy it to this coroutine's stack. Otherwise + * you shouldn't do anything else before calling cr_begin(). + * Specifically, coroutine_add() and + * cr_{yield,pause_and_yield,exit,end}() are explicitly forbidden to + * call from within a coroutine before cr_begin() (note that the + * cr_rpc_*() and cr_chan_*() macros call these functions). + */ +typedef void (*cr_fn_t)(void *args); +#define COROUTINE __attribute__ ((noreturn)) void + +/* managing coroutines ********************************************************/ + +/** + * Call `fn(args)` in a new coroutine with stack size `stack_size`. + * + * See the doc comment on c_fn_t for the requirements imposed on fn. + * + * May be called from outside any coroutine (before calling + * coroutine_main()) or from inside of a coroutine (after it cas + * called cr_begin()). + * + * Returns the cid of the newly-created coroutine. May return 0 if + * there are already COROUTINE_NUM active coroutines. + */ +cid_t coroutine_add_with_stack_size(size_t stack_size, cr_fn_t fn, void *args); + +/** + * Like coroutine_add_with_stack_size(), but uses a default stack size so + * you don't need to think about it. + */ +#define coroutine_add(fn, args) coroutine_add_with_stack_size(0, fn, args) + +/** + * The main scheduler loop. + * + * "Should" never return, but will print a message to stderr and + * return if the program has deadlocked and there are no runnable + * coroutines. So be sure to call coroutine_add() at least once + * before calling this. + */ +void coroutine_main(void); + +/* inside of coroutines *******************************************************/ + +/** cr_begin() goes at the beginning of a coroutine, after it has initialized its stack. */ +void cr_begin( void); +/** cr_exit() terminates the currently-running coroutine. */ +__attribute__ ((noreturn)) void cr_exit(void); +/** cr_yield() switches to another coroutine (if there is another runnable coroutine to switch to). */ +void cr_yield(void); +/** cr_pause_and_yield() marks the current coroutine as not-runnable and switches to another coroutine. */ +void cr_pause_and_yield(void); +/** cr_unpause() marks a coroutine as runnable that has previously marked itself as non-runnable with cr_pause_and_yield(). */ +void cr_unpause(cid_t); +/** cr_unpause_from_sighandler() is like cr_unpause(), but safe to call from a signal handler that might race with the coroutine actually pausing itself. */ +void cr_unpause_from_sighandler(cid_t); +/** cr_end() is a counterpart to cr_begin(), but is really just cr_exit(). */ +#define cr_end cr_exit + +/** cr_getcid() returns the cid of the currently-running coroutine. */ +cid_t cr_getcid(void); + +/** + * It is not possible for one coroutine to kill another or to mark + * another as paused; a coroutine may only do those things to itself. + */ + +#endif /* _COROUTINE_H_ */ diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt new file mode 100644 index 0000000..3efb6d9 --- /dev/null +++ b/libcr_ipc/CMakeLists.txt @@ -0,0 +1,10 @@ +# libcr_ipc/CMakeLists.txt - TODO +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libcr_ipc INTERFACE) +target_sources(libcr_ipc INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/sema.c +) +target_include_directories(libcr_ipc SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) diff --git a/libcr_ipc/coroutine_chan.h b/libcr_ipc/coroutine_chan.h deleted file mode 100644 index a3621a6..0000000 --- a/libcr_ipc/coroutine_chan.h +++ /dev/null @@ -1,115 +0,0 @@ -/* coroutine_chan.h - Simple channel system for coroutine.{h,c} - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -/** - * The cr_chan_* macros form a simple Go-like unbuffered channel - * mechanism built on top of the cr_pause_and_yeild() and cr_unpause() - * primitives. - */ -#ifndef _COROUTINE_CHAN_H_ -#define _COROUTINE_CHAN_H_ - -#include - -#include "coroutine.h" - -/** - * cr_chan_t(val_t) returns the type definition for a channel on - * that transports values of type `val_t`. - */ -#define cr_chan_t(val_t) struct { \ - bool ok_to_write; \ - cid_t reader, *tail_reader; \ - val_t *reader_val; \ - \ - bool ok_to_read; \ - cid_t writer, *tail_writer; \ - val_t *writer_val; \ - } - -/* These "functions" are preprocessor macros instead of real C - * functions so that the compiler can do type-checking instead of - * having these functions take `void*`. */ - -/** - * ch_chan_send(*ch, val) sends `val` over `ch`. - */ -#define cr_chan_send(ch, _val) do { \ - if ((ch)->ok_to_write) { /* non-blocking */ \ - *((ch)->reader_val) = (_val); \ - (ch)->ok_to_write = false; \ - cr_unpause((ch)->reader); \ - } else { /* blocking */ \ - cid_t next = 0; \ - if ((ch)->writer) { \ - *((ch)->tail_writer) = cr_getcid(); \ - (ch)->tail_writer = &next; \ - cr_pause_and_yield(); \ - } else { \ - (ch)->writer = cr_getcid(); \ - (ch)->tail_writer = &next; \ - } \ - assert((ch)->writer == cr_getcid()); \ - (ch)->writer_val = &(_val); \ - (ch)->ok_to_read = true; \ - cr_pause_and_yield(); \ - assert((ch)->ok_to_read == false); \ - if (next) { \ - (ch)->writer = next; \ - cr_unpause(next); \ - } else { \ - (ch)->writer = 0; \ - (ch)->tail_writer = NULL; \ - } \ - } \ - } while (0) - -/** - * cr_chan_recv(ch, val_p) reads a value from ch into `*val_p`. - */ -#define cr_chan_recv(ch, _val_p) do { \ - if ((ch)->ok_to_read) { /* non-blocking */ \ - *(_val_p) = *((ch)->writer_val); \ - (ch)->ok_to_read = false; \ - cr_unpause((ch)->writer; \ - } else { /* blocking */ \ - cid_t next = 0; \ - if ((ch)->reader) { \ - *((ch)->tail_reader) = cr_getcid(); \ - (ch)->tail_reader = &next; \ - cr_pause_and_yield(); \ - } else { \ - (ch)->reader = cr_getcid(); \ - (ch)->tail_reader = &next; \ - } \ - assert((ch)->reader == cr_getcid()); \ - (ch)->reader_val = (_val_p); \ - (ch)->ok_to_write = true; \ - cr_pause_and_yield(); \ - assert((ch)->ok_to_write == false); \ - if (next) { \ - (ch)->reader = next; \ - cr_unpause(next); \ - } else { \ - (ch)->reader = 0; \ - (ch)->tail_reader = NULL; \ - } \ - } \ - } while (0) - -/** - * cr_chan_can_send(ch) returns whether cr_chan_send(ch, val) would - * run without blocking. - */ -#define cr_chan_can_send(ch) ((ch)->ok_to_write) - -/** - * cr_chan_can_recv(ch) returns whether cr_chan_recv(ch, &val) would - * run without blocking. - */ -#define cr_chan_can_recv(ch) ((ch)->ok_to_read) - -#endif /* _COROUTINE_CHAN_H_ */ diff --git a/libcr_ipc/coroutine_rpc.h b/libcr_ipc/coroutine_rpc.h deleted file mode 100644 index 11d40d7..0000000 --- a/libcr_ipc/coroutine_rpc.h +++ /dev/null @@ -1,108 +0,0 @@ -/* coroutine_rpc.h - Simple request/response system for coroutine.{h,c} - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -/** - * The cr_rpc_* macros form a simple request/response mechanism built - * on top of the cr_pause_and_yeild() and cr_unpause() primitives. - */ -#ifndef _COROUTINE_RPC_H_ -#define _COROUTINE_RPC_H_ - -#include - -#include "coroutine.h" - -/** - * cr_rpc_t(req_t, resp_t) returns the type definition for a - * rcp-channel on which the requester submits a value of type `req_t` - * and the responder responds with a value of type `resp_t`. - * - * There may be multiple concurrent requesters, but only one - * concurrent responder. If you need multiple concurrent responders, - * set up a system of coroutine_chan.h channels. - */ -#define cr_rpc_t(req_t, resp_t) struct { \ - cid_t requester, *tail_requester; \ - cid_t responder; \ - req_t *req_p; \ - resp_t *resp_p; \ - } - -/* These "functions" are preprocessor macros instead of real C - * functions so that the compiler can do type-checking instead of - * having these functions take `void*`. */ - -/** - * ch_rpc_req(cr_rpc_t(req_t, resp_t) *ch, resp_t *resp, req_t req) - * submits the `req` request to `ch` puts the response in `*resp_p`. - * - * Blocking: Always; until the responder has called both - * cr_rpc_recv_req() and cr_rpc_send_resp(). - */ -#define cr_rpc_req(ch, _resp_p, _req) do { \ - cid_t next = 0; \ - if ((ch)->requester) { \ - *((ch)->tail_requester = cr_getcid(); \ - (ch)->tail_requester = &next; \ - cr_pause_and_yield(); \ - } else { \ - (ch)->requester = cr_getcid(); \ - (ch)->tail_requester = &next; \ - } \ - assert((ch)->requester == cr_getcid()); \ - (ch)->req_p = &(_req); \ - (ch)->resp_p = (_resp_p; \ - if ((ch)->responder != 0) \ - cr_unpause((ch)->responder); \ - cr_pause_and_yield(); \ - if (next) { \ - (ch)->requester = next; \ - cr_unpause(next); \ - } else { \ - (ch)->requester = 0; \ - (ch)->tail_requester = NULL; \ - } - } while (0) - -/** - * cr_rpc_have_req(cr_rpc_t(req_t, resp_t) *ch) allows a responder - * to check whether or not there is a request waiting to be received - * (with cr_rpc_recv_req()) without blocking if there is not. - * - * Blocking: Never. - */ -#define cr_rpc_have_req(ch) ((ch)->req_p != NULL) - -/** - * cr_rpc_recv_req(cr_rpc_t(req_t, resp_t) *ch, req_t *req_p) reads - * a request from ch into `*req_p`. - * - * If there is not a pending request on `ch`, blocks until there is. - * - * Blocking: Maybe. - */ -#define cr_rpc_recv_req(ch, _req_p) do { \ - (ch)->responder = cr_getcid(); \ - if ((ch)->requester == 0) \ - cr_pause_and_yield(); \ - *(_req_p) = *((ch)->req_p); \ - (ch)->req_p = NULL; \ - } while (0) - -/** - * cr_rpc_send_resp(cr_rpc_t(req_t, resp_t) *ch, resp_t resp) sends - * the reply to the most-recently-read request. - * - * Blocking: Never. - */ -#define cr_rpc_send_resp(ch, _resp) do { \ - (ch)->responder = 0; \ - *((ch)->resp_p) = (_resp); \ - (ch)->resp_p = NULL; \ - cr_unpause((ch)->requester); \ - } while (0) - -#endif /* _COROUTINE_RPC_H_ */ diff --git a/libcr_ipc/coroutine_sema.c b/libcr_ipc/coroutine_sema.c deleted file mode 100644 index a8b5ec4..0000000 --- a/libcr_ipc/coroutine_sema.c +++ /dev/null @@ -1,95 +0,0 @@ -/* coroutine_sema.h - Simple semaphores for coroutine.{h,c} - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#include - -#include "coroutine_sema.h" - -struct cid_list { - cid_t val; - struct cid_list *next; -}; - -/* head->next->next->tail */ - -struct _cr_sema { - int cnt; - - struct cid_list *head, **tail; - /* locked indicates that a call from within a coroutine is is - * messing with ->{head,tail}, so a signal handler can't read - * it. */ - bool locked; -}; - -/** Drain the sema->{head,tail} list. Returns true if cr_getcid() was drained. */ -static inline bool drain(volatile cr_sema_t *sema) { - assert(!sema->locked); - cid_t self = cr_getcid(); - - enum drain_result { - DRAINING, - DRAINED_SELF, /* stopped because drained `self` */ - DRAINED_ALL, /* stopped because sema->head == NULL */ - DRAINED_SOME, /* stopped because sema->cnt == 0 */ - } state = DRAINING; - do { - sema->locked = true; - while (state == DRAINING) { - if (!sema->head) { - state = DRAINED_ALL; - } else if (!sema->cnt) { - state = DRAINED_SOME; - } else { - sema->cnt--; - cid_t cid = sema->head->val; - if (cid == self) - state = DRAINED_SELF; - else - cr_unpause(sema->head->val); - sema->head = sema->head->next; - if (!sema->head) - sema->tail = &sema->head; - } - } - sema->locked = false; - /* If there are still coroutines in sema->head, check - * that sema->cnt wasn't incremented between `if - * (!sema->cnt)` and `sema->locked = false`. */ - } while (state == DRAINED_SOME && cnt); - /* If state == DRAINED_SELF, then we better have been the last - * item in the list! */ - assert(state != DRAINED_SELF || !sema->head); - return state == DRAINED_SELF; -} - -void cr_sema_signal(volatile cr_sema_t *sema) { - sema->cnt++; - if (!sema->locked) - drain(); -} - -void cr_sema_wait(volatile cr_sema_t *sema) { - struct cid_list self = { - .val = cr_getcid(), - .next = NULL, - }; - - sema->locked = true; - if (!sema->tail) - sema->head = &self; - else - *(sema->tail) = &self; - sema->tail = &(self.next); - sema->locked = false; - - if (drain()) - /* DRAINED_SELF: (1) No need to pause+yield, (2) we - * better have been the last item in the list! */ - assert(!self.next); - else - cr_pause_and_yield(); -} diff --git a/libcr_ipc/coroutine_sema.h b/libcr_ipc/coroutine_sema.h deleted file mode 100644 index 57d5855..0000000 --- a/libcr_ipc/coroutine_sema.h +++ /dev/null @@ -1,35 +0,0 @@ -/* coroutine_sema.h - Simple semaphores for coroutine.{h,c} - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#ifndef _COROUTINE_SEMA_H_ -#define _COROUTINE_SEMA_H_ - -/** - * A cr_sema_t is a fair unbounded[1] counting semaphore. - * - * [1]: Well, INT_MAX - */ -typedef struct sema_t cr_sema_t; - -/** - * Increment the semaphore, - * - * @blocks never - * @yields never - * @run_in anywhere (coroutine, sighandler) - */ -void cr_sema_signal(cr_sema_t *sema); - -/** - * Wait until the semaphore is >0, then decrement it. - * - * @blocks maybe - * @yields maybe - * @may_run_in coroutine - */ -void cr_sema_wait(cr_sema_t *sema); - -#endif /* _COROUTINE_SEMA_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h new file mode 100644 index 0000000..a3621a6 --- /dev/null +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -0,0 +1,115 @@ +/* coroutine_chan.h - Simple channel system for coroutine.{h,c} + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +/** + * The cr_chan_* macros form a simple Go-like unbuffered channel + * mechanism built on top of the cr_pause_and_yeild() and cr_unpause() + * primitives. + */ +#ifndef _COROUTINE_CHAN_H_ +#define _COROUTINE_CHAN_H_ + +#include + +#include "coroutine.h" + +/** + * cr_chan_t(val_t) returns the type definition for a channel on + * that transports values of type `val_t`. + */ +#define cr_chan_t(val_t) struct { \ + bool ok_to_write; \ + cid_t reader, *tail_reader; \ + val_t *reader_val; \ + \ + bool ok_to_read; \ + cid_t writer, *tail_writer; \ + val_t *writer_val; \ + } + +/* These "functions" are preprocessor macros instead of real C + * functions so that the compiler can do type-checking instead of + * having these functions take `void*`. */ + +/** + * ch_chan_send(*ch, val) sends `val` over `ch`. + */ +#define cr_chan_send(ch, _val) do { \ + if ((ch)->ok_to_write) { /* non-blocking */ \ + *((ch)->reader_val) = (_val); \ + (ch)->ok_to_write = false; \ + cr_unpause((ch)->reader); \ + } else { /* blocking */ \ + cid_t next = 0; \ + if ((ch)->writer) { \ + *((ch)->tail_writer) = cr_getcid(); \ + (ch)->tail_writer = &next; \ + cr_pause_and_yield(); \ + } else { \ + (ch)->writer = cr_getcid(); \ + (ch)->tail_writer = &next; \ + } \ + assert((ch)->writer == cr_getcid()); \ + (ch)->writer_val = &(_val); \ + (ch)->ok_to_read = true; \ + cr_pause_and_yield(); \ + assert((ch)->ok_to_read == false); \ + if (next) { \ + (ch)->writer = next; \ + cr_unpause(next); \ + } else { \ + (ch)->writer = 0; \ + (ch)->tail_writer = NULL; \ + } \ + } \ + } while (0) + +/** + * cr_chan_recv(ch, val_p) reads a value from ch into `*val_p`. + */ +#define cr_chan_recv(ch, _val_p) do { \ + if ((ch)->ok_to_read) { /* non-blocking */ \ + *(_val_p) = *((ch)->writer_val); \ + (ch)->ok_to_read = false; \ + cr_unpause((ch)->writer; \ + } else { /* blocking */ \ + cid_t next = 0; \ + if ((ch)->reader) { \ + *((ch)->tail_reader) = cr_getcid(); \ + (ch)->tail_reader = &next; \ + cr_pause_and_yield(); \ + } else { \ + (ch)->reader = cr_getcid(); \ + (ch)->tail_reader = &next; \ + } \ + assert((ch)->reader == cr_getcid()); \ + (ch)->reader_val = (_val_p); \ + (ch)->ok_to_write = true; \ + cr_pause_and_yield(); \ + assert((ch)->ok_to_write == false); \ + if (next) { \ + (ch)->reader = next; \ + cr_unpause(next); \ + } else { \ + (ch)->reader = 0; \ + (ch)->tail_reader = NULL; \ + } \ + } \ + } while (0) + +/** + * cr_chan_can_send(ch) returns whether cr_chan_send(ch, val) would + * run without blocking. + */ +#define cr_chan_can_send(ch) ((ch)->ok_to_write) + +/** + * cr_chan_can_recv(ch) returns whether cr_chan_recv(ch, &val) would + * run without blocking. + */ +#define cr_chan_can_recv(ch) ((ch)->ok_to_read) + +#endif /* _COROUTINE_CHAN_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h new file mode 100644 index 0000000..11d40d7 --- /dev/null +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -0,0 +1,108 @@ +/* coroutine_rpc.h - Simple request/response system for coroutine.{h,c} + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +/** + * The cr_rpc_* macros form a simple request/response mechanism built + * on top of the cr_pause_and_yeild() and cr_unpause() primitives. + */ +#ifndef _COROUTINE_RPC_H_ +#define _COROUTINE_RPC_H_ + +#include + +#include "coroutine.h" + +/** + * cr_rpc_t(req_t, resp_t) returns the type definition for a + * rcp-channel on which the requester submits a value of type `req_t` + * and the responder responds with a value of type `resp_t`. + * + * There may be multiple concurrent requesters, but only one + * concurrent responder. If you need multiple concurrent responders, + * set up a system of coroutine_chan.h channels. + */ +#define cr_rpc_t(req_t, resp_t) struct { \ + cid_t requester, *tail_requester; \ + cid_t responder; \ + req_t *req_p; \ + resp_t *resp_p; \ + } + +/* These "functions" are preprocessor macros instead of real C + * functions so that the compiler can do type-checking instead of + * having these functions take `void*`. */ + +/** + * ch_rpc_req(cr_rpc_t(req_t, resp_t) *ch, resp_t *resp, req_t req) + * submits the `req` request to `ch` puts the response in `*resp_p`. + * + * Blocking: Always; until the responder has called both + * cr_rpc_recv_req() and cr_rpc_send_resp(). + */ +#define cr_rpc_req(ch, _resp_p, _req) do { \ + cid_t next = 0; \ + if ((ch)->requester) { \ + *((ch)->tail_requester = cr_getcid(); \ + (ch)->tail_requester = &next; \ + cr_pause_and_yield(); \ + } else { \ + (ch)->requester = cr_getcid(); \ + (ch)->tail_requester = &next; \ + } \ + assert((ch)->requester == cr_getcid()); \ + (ch)->req_p = &(_req); \ + (ch)->resp_p = (_resp_p; \ + if ((ch)->responder != 0) \ + cr_unpause((ch)->responder); \ + cr_pause_and_yield(); \ + if (next) { \ + (ch)->requester = next; \ + cr_unpause(next); \ + } else { \ + (ch)->requester = 0; \ + (ch)->tail_requester = NULL; \ + } + } while (0) + +/** + * cr_rpc_have_req(cr_rpc_t(req_t, resp_t) *ch) allows a responder + * to check whether or not there is a request waiting to be received + * (with cr_rpc_recv_req()) without blocking if there is not. + * + * Blocking: Never. + */ +#define cr_rpc_have_req(ch) ((ch)->req_p != NULL) + +/** + * cr_rpc_recv_req(cr_rpc_t(req_t, resp_t) *ch, req_t *req_p) reads + * a request from ch into `*req_p`. + * + * If there is not a pending request on `ch`, blocks until there is. + * + * Blocking: Maybe. + */ +#define cr_rpc_recv_req(ch, _req_p) do { \ + (ch)->responder = cr_getcid(); \ + if ((ch)->requester == 0) \ + cr_pause_and_yield(); \ + *(_req_p) = *((ch)->req_p); \ + (ch)->req_p = NULL; \ + } while (0) + +/** + * cr_rpc_send_resp(cr_rpc_t(req_t, resp_t) *ch, resp_t resp) sends + * the reply to the most-recently-read request. + * + * Blocking: Never. + */ +#define cr_rpc_send_resp(ch, _resp) do { \ + (ch)->responder = 0; \ + *((ch)->resp_p) = (_resp); \ + (ch)->resp_p = NULL; \ + cr_unpause((ch)->requester); \ + } while (0) + +#endif /* _COROUTINE_RPC_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h new file mode 100644 index 0000000..57d5855 --- /dev/null +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -0,0 +1,35 @@ +/* coroutine_sema.h - Simple semaphores for coroutine.{h,c} + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#ifndef _COROUTINE_SEMA_H_ +#define _COROUTINE_SEMA_H_ + +/** + * A cr_sema_t is a fair unbounded[1] counting semaphore. + * + * [1]: Well, INT_MAX + */ +typedef struct sema_t cr_sema_t; + +/** + * Increment the semaphore, + * + * @blocks never + * @yields never + * @run_in anywhere (coroutine, sighandler) + */ +void cr_sema_signal(cr_sema_t *sema); + +/** + * Wait until the semaphore is >0, then decrement it. + * + * @blocks maybe + * @yields maybe + * @may_run_in coroutine + */ +void cr_sema_wait(cr_sema_t *sema); + +#endif /* _COROUTINE_SEMA_H_ */ diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c new file mode 100644 index 0000000..a8b5ec4 --- /dev/null +++ b/libcr_ipc/sema.c @@ -0,0 +1,95 @@ +/* coroutine_sema.h - Simple semaphores for coroutine.{h,c} + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#include + +#include "coroutine_sema.h" + +struct cid_list { + cid_t val; + struct cid_list *next; +}; + +/* head->next->next->tail */ + +struct _cr_sema { + int cnt; + + struct cid_list *head, **tail; + /* locked indicates that a call from within a coroutine is is + * messing with ->{head,tail}, so a signal handler can't read + * it. */ + bool locked; +}; + +/** Drain the sema->{head,tail} list. Returns true if cr_getcid() was drained. */ +static inline bool drain(volatile cr_sema_t *sema) { + assert(!sema->locked); + cid_t self = cr_getcid(); + + enum drain_result { + DRAINING, + DRAINED_SELF, /* stopped because drained `self` */ + DRAINED_ALL, /* stopped because sema->head == NULL */ + DRAINED_SOME, /* stopped because sema->cnt == 0 */ + } state = DRAINING; + do { + sema->locked = true; + while (state == DRAINING) { + if (!sema->head) { + state = DRAINED_ALL; + } else if (!sema->cnt) { + state = DRAINED_SOME; + } else { + sema->cnt--; + cid_t cid = sema->head->val; + if (cid == self) + state = DRAINED_SELF; + else + cr_unpause(sema->head->val); + sema->head = sema->head->next; + if (!sema->head) + sema->tail = &sema->head; + } + } + sema->locked = false; + /* If there are still coroutines in sema->head, check + * that sema->cnt wasn't incremented between `if + * (!sema->cnt)` and `sema->locked = false`. */ + } while (state == DRAINED_SOME && cnt); + /* If state == DRAINED_SELF, then we better have been the last + * item in the list! */ + assert(state != DRAINED_SELF || !sema->head); + return state == DRAINED_SELF; +} + +void cr_sema_signal(volatile cr_sema_t *sema) { + sema->cnt++; + if (!sema->locked) + drain(); +} + +void cr_sema_wait(volatile cr_sema_t *sema) { + struct cid_list self = { + .val = cr_getcid(), + .next = NULL, + }; + + sema->locked = true; + if (!sema->tail) + sema->head = &self; + else + *(sema->tail) = &self; + sema->tail = &(self.next); + sema->locked = false; + + if (drain()) + /* DRAINED_SELF: (1) No need to pause+yield, (2) we + * better have been the last item in the list! */ + assert(!self.next); + else + cr_pause_and_yield(); +} diff --git a/libnetio/CMakeLists.txt b/libnetio/CMakeLists.txt new file mode 100644 index 0000000..226a2e5 --- /dev/null +++ b/libnetio/CMakeLists.txt @@ -0,0 +1,10 @@ +# libnetio/CMakeLists.txt - Build script for libnetio support library +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libnetio INTERFACE) +target_sources(libnetio INTERFACE + netio_posix.c +) +target_include_directories(libnetio SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt new file mode 100644 index 0000000..8f015a1 --- /dev/null +++ b/libusb/CMakeLists.txt @@ -0,0 +1,23 @@ +# libusb/CMakeLists.txt - Build script for libusb support library +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libusb INTERFACE) +target_sources(libusb INTERFACE + usb_common.c +) +target_include_directories(libusb SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.pdf + ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.txt + ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.h + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.gen + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.gen +) +add_dependencies(generate + ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.pdf + ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.txt + ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.h +) diff --git a/libusb/include/libusb/tusb_helpers.h b/libusb/include/libusb/tusb_helpers.h new file mode 100644 index 0000000..cd96357 --- /dev/null +++ b/libusb/include/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 + * + * 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/include/libusb/tusb_helpers.h.gen b/libusb/include/libusb/tusb_helpers.h.gen new file mode 100755 index 0000000..213eda0 --- /dev/null +++ b/libusb/include/libusb/tusb_helpers.h.gen @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# -*- Mode: C -*- +set -e +exec >"${0%.gen}" +cat <<'EOT' +/* libusb/tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB + * + * Copyright (c) 2024 Luke T. Shumaker + * + * 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 _LIBUSB_TUSB_HELPERS_H_ +#define _LIBUSB_TUSB_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 +[ -f ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf ] || wget -O ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf 'https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf' +[ -f ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.txt ] || pdftotext -layout ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf +<${CMAKE_SOURCE_DIR?}/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 /* _LIBUSB_TUSB_HELPERS_H_ */ +EOT diff --git a/libusb/include/libusb/usb_common.h b/libusb/include/libusb/usb_common.h new file mode 100644 index 0000000..3b45246 --- /dev/null +++ b/libusb/include/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 + * 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_ */ diff --git a/libusb/tusb_config.h b/libusb/tusb_config.h deleted file mode 100644 index cb1ca3b..0000000 --- a/libusb/tusb_config.h +++ /dev/null @@ -1,107 +0,0 @@ -/* 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 - * - * 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 deleted file mode 100644 index cd96357..0000000 --- a/libusb/tusb_helpers.h +++ /dev/null @@ -1,971 +0,0 @@ -/* tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB - * - * Copyright (c) 2024 Luke T. Shumaker - * - * 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 deleted file mode 100755 index a348b16..0000000 --- a/libusb/tusb_helpers.h.gen +++ /dev/null @@ -1,82 +0,0 @@ -#!/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 - * - * 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.h b/libusb/usb_common.h deleted file mode 100644 index 3b45246..0000000 --- a/libusb/usb_common.h +++ /dev/null @@ -1,59 +0,0 @@ -/* usb_common.h - Common framework for implementing multiple USB devices at once - * - * Copyright (C) 2024 Luke T. Shumaker - * 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_ */ -- cgit v1.2.3-2-g168b