From 7acc6fe474766788687a5257be21ac549bed77f3 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 1 Apr 2015 16:22:05 +0200 Subject: libusbhost: Open source USB host stack for embedded devices First public version, date: 1.4.2015 Signed-off-by: Amir Hammad --- .gitignore | 9 + .gitmodules | 3 + COPYING.GPL3 | 674 ++++++++++++++++++++++ COPYING.LGPL3 | 165 ++++++ DEVICE_DRIVER_HOWTO | 3 + Makefile | 256 +++++++++ README.md | 78 +++ build/.gitignore | 0 compileDemo.sh | 2 + config.mk | 10 + include/driver/usbh_device_driver.h | 131 +++++ include/usbh_config.h | 56 ++ include/usbh_driver_gp_xbox.h | 73 +++ include/usbh_driver_hid_mouse.h | 43 ++ include/usbh_driver_hub.h | 36 ++ include/usbh_hubbed.h | 76 +++ include/usbh_lld_stm32f4.h | 43 ++ initRepo.sh | 4 + libopencm3 | 1 + libopencm3_stm32f4.ld | 32 ++ src/demo.c | 186 +++++++ src/usart_helpers.c | 287 ++++++++++ src/usart_helpers.h | 56 ++ src/usbh_driver_gp_xbox.c | 420 ++++++++++++++ src/usbh_driver_hid_mouse.c | 294 ++++++++++ src/usbh_driver_hub.c | 865 +++++++++++++++++++++++++++++ src/usbh_driver_hub_private.h | 108 ++++ src/usbh_hubbed.c | 634 +++++++++++++++++++++ src/usbh_lld_stm32f4.c | 1048 +++++++++++++++++++++++++++++++++++ 29 files changed, 5593 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 COPYING.GPL3 create mode 100644 COPYING.LGPL3 create mode 100644 DEVICE_DRIVER_HOWTO create mode 100644 Makefile create mode 100644 README.md create mode 100644 build/.gitignore create mode 100755 compileDemo.sh create mode 100644 config.mk create mode 100644 include/driver/usbh_device_driver.h create mode 100644 include/usbh_config.h create mode 100644 include/usbh_driver_gp_xbox.h create mode 100644 include/usbh_driver_hid_mouse.h create mode 100644 include/usbh_driver_hub.h create mode 100644 include/usbh_hubbed.h create mode 100644 include/usbh_lld_stm32f4.h create mode 100755 initRepo.sh create mode 160000 libopencm3 create mode 100644 libopencm3_stm32f4.ld create mode 100644 src/demo.c create mode 100644 src/usart_helpers.c create mode 100644 src/usart_helpers.h create mode 100644 src/usbh_driver_gp_xbox.c create mode 100644 src/usbh_driver_hid_mouse.c create mode 100644 src/usbh_driver_hub.c create mode 100644 src/usbh_driver_hub_private.h create mode 100644 src/usbh_hubbed.c create mode 100644 src/usbh_lld_stm32f4.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fdf34d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.o +*.d +*.elf +*.map +*.bin +*.hex +*.cproject +*.project +*.a diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2822909 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libopencm3"] + path = libopencm3 + url = https://amirhammad@github.com/amirhammad/libopencm3 diff --git a/COPYING.GPL3 b/COPYING.GPL3 new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING.GPL3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/COPYING.LGPL3 b/COPYING.LGPL3 new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/COPYING.LGPL3 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/DEVICE_DRIVER_HOWTO b/DEVICE_DRIVER_HOWTO new file mode 100644 index 0000000..e26c9f1 --- /dev/null +++ b/DEVICE_DRIVER_HOWTO @@ -0,0 +1,3 @@ +TODO + +See usbh_driver*.c in src directory for example of device drivers. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9fe1c80 --- /dev/null +++ b/Makefile @@ -0,0 +1,256 @@ +## +## This file is part of the libusbhost project. +## Imported and adopted from libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2010 Piotr Esden-Tempski +## Copyright (C) 2013 Frantisek Burian +## Copyright (C) 2014 Amir Hammad +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +BINARY = demo +BINARY := $(addprefix build/, demo) +LIBUSBHOSTNAME = usbhost + +LIBUSBHOST := $(addprefix build/lib, $(LIBUSBHOSTNAME)) +LIBNAME = opencm3_stm32f4 +DEFS = -DSTM32F4 + +# load user config +include config.mk +DEFS += $(USER_CONFIG) + +ifdef USART_DEBUG +DEFS += -DUSART_DEBUG +endif + +DEFS += -Iinclude +LDSCRIPT = lib$(LIBNAME).ld + +SRCDIR = src +OPENCM3_DIR ?= ./libopencm3 +FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mfp16-format=alternative +ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS) + +################################################################################ +# OpenOCD specific variables + +OOCD ?= openocd +OOCD_INTERFACE ?= stlink-v2 +OOCD_BOARD ?= stm32f4discovery + +################################################################################ +# Black Magic Probe specific variables +# Set the BMP_PORT to a serial port and then BMP is used for flashing +BMP_PORT ?= + +################################################################################ +# texane/stlink specific variables +#STLINK_PORT ?= :4242 + +# Be silent per default, but 'make V=1' will show all compiler calls. +ifneq ($(V),1) +Q := @ +NULL := 2>/dev/null +endif + +############################################################################### +# Executables + +PREFIX ?= arm-none-eabi + +CC := $(PREFIX)-gcc +CXX := $(PREFIX)-g++ +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH = $(shell which st-flash) +STYLECHECK := /checkpatch.pl +STYLECHECKFLAGS := --no-tree -f --terse --mailback +STYLECHECKFILES := $(shell find . -name '*.[ch]') + + +############################################################################### +# Source files + +LDSCRIPT ?= $(BINARY).ld + + +SRCS = $(sort $(notdir $(wildcard $(SRCDIR)/*.c))) +OBJSDEMO = $(patsubst %.c, build/%.o ,$(SRCS)) +OBJS = $(filter-out $(BINARY).o, $(OBJSDEMO)) + + +INCLUDE_DIR = $(OPENCM3_DIR)/include +LIB_DIR = $(OPENCM3_DIR)/lib +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + +############################################################################### +# C flags + +CFLAGS += -Ofast -g +CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration +CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C++ flags + +CXXFLAGS += -Ofast -g +CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++ +CXXFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C & C++ preprocessor common flags + +CPPFLAGS += -MD +CPPFLAGS += -Wall -Wundef +CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS) + +############################################################################### +# Linker flags + +LDFLAGS += --static -nostartfiles +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=build/$*.map +LDFLAGS += -Wl,--gc-sections +ifeq ($(V),99) +LDFLAGS += -Wl,--print-gc-sections +endif + +############################################################################### +# Used libraries + +LDLIBS += -l$(LIBNAME) +LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group + +############################################################################### +############################################################################### +############################################################################### + +.SUFFIXES: .elf .bin .hex .srec .list .map .images +.SECONDEXPANSION: +.SECONDARY: + + +all: elf bin lib + +elf: $(BINARY).elf +bin: $(BINARY).bin +hex: $(BINARY).hex +srec: $(BINARY).srec +list: $(BINARY).list +lib: $(LIBUSBHOST).a +images: $(BINARY).images +flash: $(BINARY).flash + +%.images: %.bin %.hex %.srec %.list %.map + @#printf "*** $* images generated ***\n" + +%.bin: %.elf + @printf " OBJCOPY $(*).bin\n" + $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin + +%.hex: %.elf + @#printf " OBJCOPY $(*).hex\n" + $(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex + +%.srec: %.elf + @#printf " OBJCOPY $(*).srec\n" + $(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec + +%.list: %.elf + @#printf " OBJDUMP $(*).list\n" + $(Q)$(OBJDUMP) -S $(*).elf > $(*).list + +-include $(OBJSDEMO:.o=.d) +build/%.elf build/%.map: $(OBJSDEMO) $(LDSCRIPT) + @printf " LD $(*).elf\n" + $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJSDEMO) $(LDLIBS) -o build/$*.elf + +build/%.o:$(SRCDIR)/%.c + @printf " CC $(*).c\n" + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $(SRCDIR)/$*.c + +build/%.o: $(SRCDIR)/%.cxx + @printf " CXX $(*).cxx\n" + $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $(SRCDIR)/$(*).cxx + +build/%.o: $(SRCDIR)/%.cpp + @printf " CXX $(*).cpp\n" + $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $(SRCDIR)/$(*).cpp +$(LIB_DIR)/lib$(LIBNAME).a: + +clean: + @#printf " CLEAN\n" + @rm -f build/* + + +%.stlink-flash: %.bin + @printf " FLASH $<\n" + $(Q)$(STFLASH) write $(*).bin 0x8000000 + +ifeq ($(STLINK_PORT),) +ifeq ($(BMP_PORT),) +ifeq ($(OOCD_SERIAL),) +%.flash: %.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \ + -f board/$(OOCD_BOARD).cfg \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +else +%.flash: %.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \ + -f board/$(OOCD_BOARD).cfg \ + -c "ft2232_serial $(OOCD_SERIAL)" \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(BMP_PORT)' \ + -x $(SCRIPT_DIR)/black_magic_probe_flash.scr \ + $(*).elf +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(STLINK_PORT)' \ + -x $(SCRIPT_DIR)/stlink_flash.scr \ + $(*).elf +endif + +.PHONY: images clean stylecheck styleclean elf bin hex srec list testing + +-include $(OBJS:.o=.d) +build/lib$(LIBUSBHOSTNAME).a: $(OBJS) + @printf " LIB $@\n" + $(Q)$(AR) rcs $@ $(OBJS) diff --git a/README.md b/README.md new file mode 100644 index 0000000..ff631ad --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +###General Information + + +**This library is in an active development.** +**WARNING**: None of its features are considered stable ! + +This library implement usb host driver allowing users use +or write device drivers, which functionality +is abstracted of low level implementation. + +Main objectives are: +- provide open-source(Lesser GPL3) usb host library for embedded devices +- execution speed: This library doesn't use blocking sleep, +making low overhead on runtime performance +- uses static allocation for all its buffers, +so no allocation and reallocation is affecting performance +(possibility of memory fragmentation. execution time indeterminism), +so no malloc(), realloc(), free(). +- written in C, with the support to use it with C++. +- does not depend on any Operating System. Library libopencm3 is used for testing purposes and to get proper defines. +So no runtime dependency is on this library. + + + +Currently supported devices (yet tested) are: +* stm32f407 (stm32f4 Discovery) + +Native device drivers (mostly for demonstration purposes): +- HUB +- Gamepad - XBox compatible Controller +- mouse (draft: only displays raw data) + +###Practical info + +!!! Do not forget to invoke "make clean" before new build when defines change + +**How to initialize repository** + +> ./initRepo.sh + +fetch libopencm3 submodule and compile needed libraries + + +**How to compile demo** + +Edit config.mk for library configuration (By default Full speed OTG periphery on stm32f4 is supported) + + +> ./compileDemo.sh + +compiles demo, that can be flashed into stm32f4 Discovery platform and debug by USART + + +**How to upload firmware (FLASH) to stm32f4 Discovery** + +> sudo make flash + + +**How to view debug data** + +connect uart to USART6 pins on gpios: GPIOC6(TX - data), GPIOC7(RX - not used) +configure uart baud on PC side to 921600 with 1 stop bit, no parity, 8bit data, no handshake + + +**How to compile library only** + +> make lib + +**libusbhost.a** is built without usart debug support +(check compileDemo.sh for hint on how to compile with debug) + + +###Contact +Amir Hammad - *amir.hammad@hotmail.com* + +**Library is maintained there** +> http://github.com/libusbhost/libusbhost + diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/compileDemo.sh b/compileDemo.sh new file mode 100755 index 0000000..7731473 --- /dev/null +++ b/compileDemo.sh @@ -0,0 +1,2 @@ +#!/bin/sh +USART_DEBUG=1 OPENCM3_DIR=libopencm3 make all diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..03fae74 --- /dev/null +++ b/config.mk @@ -0,0 +1,10 @@ + + +USER_CONFIG = + + +# Uncomment to enable OTG_HS support - low level driver +#USER_CONFIG += -DUSE_STM32F4_USBH_DRIVER_HS + +# Uncomment to enable OTG_FS support - low level driver +USER_CONFIG += -DUSE_STM32F4_USBH_DRIVER_FS diff --git a/include/driver/usbh_device_driver.h b/include/driver/usbh_device_driver.h new file mode 100644 index 0000000..f8837e0 --- /dev/null +++ b/include/driver/usbh_device_driver.h @@ -0,0 +1,131 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_DEVICE_DRIVER_ +#define USBH_DEVICE_DRIVER_ + +#include "usbh_config.h" +#include "usbh_hubbed.h" + +#include + +BEGIN_DECLS + +#define USBH_EPTYP_CONTROL (0) +#define USBH_EPTYP_ISOCHRONOUS (1) +#define USBH_EPTYP_BULK (2) +#define USBH_EPTYP_INTERRUPT (3) + +#define USBH_SPEED_FULL (0) +#define USBH_SPEED_LOW (1) +#define USBH_SPEED_HIGH (2) + + +enum USBH_PACKET_CALLBACK_STATUS { + USBH_PACKET_CALLBACK_STATUS_OK = 0, + USBH_PACKET_CALLBACK_STATUS_ERRSIZ = 1, + USBH_PACKET_CALLBACK_STATUS_EAGAIN = 2, // -- TODO: automatic handling of transmit errors 3xTXERR->FATAL + USBH_PACKET_CALLBACK_STATUS_EFATAL = 3 +}; + +enum USBH_POLL_STATUS { + USBH_POLL_STATUS_NONE, + USBH_POLL_STATUS_DEVICE_CONNECTED, + USBH_POLL_STATUS_DEVICE_DISCONNECTED +}; + +struct _usbh_device { + uint16_t packet_size_max0; + int8_t address; + uint8_t speed; // (USBH_SPEED_*) + uint8_t state; // for enumeration purposes + uint8_t toggle0; + const usbh_dev_driver_t *drv; + void *drvdata; + const void *lld; +}; +typedef struct _usbh_device usbh_device_t; + +struct _usbh_packet_callback_data { + enum USBH_PACKET_CALLBACK_STATUS status; + uint32_t transferred_length; +}; +typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t; + +typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status); + +struct _usbh_packet { + void *data; // Pointer to data + uint16_t datalen; // Data length 0..1023 + int8_t address; // Device address + uint8_t endpoint_type; // Endpoint type (see USBH_EPTYP_*) + uint8_t endpoint_address; // Endpoint number 0..15 + uint16_t endpoint_size_max; // Max packet size for an endpoint + uint8_t speed; // (USBH_SPEED_*) + uint8_t *toggle; + usbh_packet_callback_t callback; + void *callback_arg; +}; +typedef struct _usbh_packet usbh_packet_t; + +struct _usbh_driver { + void (*init)(void *drvdata); + void (*write)(void *drvdata, const usbh_packet_t *packet); + void (*read)(void *drvdata, usbh_packet_t *packet); + enum USBH_POLL_STATUS (*poll)(void *drvdata, uint32_t t_us); + uint8_t (*root_speed)(void *drvdata); + + // Pointer to Low-level driver data + void *driver_data; +}; +typedef struct _usbh_driver usbh_driver_t; + +struct _usbh_generic_data { + usbh_device_t usbh_device[USBH_MAX_DEVICES]; + uint8_t usbh_buffer[BUFFER_ONE_BYTES]; +}; +typedef struct _usbh_generic_data usbh_generic_data_t; + + +#define ERROR(arg) LOG_PRINTF("UNHANDLED_ERROR %d: file: %s, line: %d",\ + arg, __FILE__, __LINE__) + + +/// Hub related functions + +usbh_device_t *usbh_get_free_device(const usbh_device_t *dev); +bool usbh_enum_available(void); +void device_enumeration_start(usbh_device_t *dev); + +/// All devices functions + +/// +void usbh_read(usbh_device_t *dev, usbh_packet_t *packet); +void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet); +/// Helper functions +void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev); +void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev); + + +END_DECLS + +#endif diff --git a/include/usbh_config.h b/include/usbh_config.h new file mode 100644 index 0000000..1b60954 --- /dev/null +++ b/include/usbh_config.h @@ -0,0 +1,56 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_CONFIG_ +#define USBH_CONFIG_ + + + +// Max devices per hub +#define USBH_HUB_MAX_DEVICES (8) + +// Max number of hub instancies +#define USBH_MAX_HUBS (2) + +// Max devices +#define USBH_MAX_DEVICES (15) + +// Min: 128 +// Set this wisely +#define BUFFER_ONE_BYTES (2048) + +// MOUSE +#define USBH_HID_MOUSE_MAX_DEVICES (2) + +#define USBH_HID_MOUSE_BUFFER (32) + +// Gamepad XBOX +#define USBH_GP_XBOX_MAX_DEVICES (2) + +#define USBH_GP_XBOX_BUFFER (32) + +/* Sanity checks */ +#if (USBH_MAX_DEVICES > 127) +#error USBH_MAX_DEVICES > 127 +#endif + +#endif diff --git a/include/usbh_driver_gp_xbox.h b/include/usbh_driver_gp_xbox.h new file mode 100644 index 0000000..8080f30 --- /dev/null +++ b/include/usbh_driver_gp_xbox.h @@ -0,0 +1,73 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_DRIVER_GP_XBOX_ +#define USBH_DRIVER_GP_XBOX_ + +#include "usbh_hubbed.h" + +#include + +BEGIN_DECLS + +#define GP_XBOX_DPAD_TOP (1 << 0) +#define GP_XBOX_DPAD_LEFT (1 << 1) +#define GP_XBOX_DPAD_BOTTOM (1 << 2) +#define GP_XBOX_DPAD_RIGHT (1 << 3) +#define GP_XBOX_BUTTON_X (1 << 4) +#define GP_XBOX_BUTTON_Y (1 << 5) +#define GP_XBOX_BUTTON_A (1 << 6) +#define GP_XBOX_BUTTON_B (1 << 7) +#define GP_XBOX_BUTTON_SELECT (1 << 8) +#define GP_XBOX_BUTTON_START (1 << 9) +#define GP_XBOX_BUTTON_LT (1 << 10) +#define GP_XBOX_BUTTON_RT (1 << 11) +#define GP_XBOX_BUTTON_XBOX (1 << 12) +#define GP_XBOX_BUTTON_AXIS_LEFT (1 << 13) +#define GP_XBOX_BUTTON_AXIS_RIGHT (1 << 14) + +struct _gp_xbox_packet { + uint32_t buttons; + int16_t axis_left_x; + int16_t axis_left_y; + int16_t axis_right_x; + int16_t axis_right_y; + uint8_t axis_rear_left; + uint8_t axis_rear_right; +}; +typedef struct _gp_xbox_packet gp_xbox_packet_t; + + +struct _gp_xbox_config { + void (*update)(uint8_t device_id, gp_xbox_packet_t data); + void (*notify_connected)(uint8_t device_id); + void (*notify_disconnected)(uint8_t device_id); +}; +typedef struct _gp_xbox_config gp_xbox_config_t; + +void gp_xbox_driver_init(const gp_xbox_config_t *config); + +extern const usbh_dev_driver_t usbh_gp_xbox_driver; + +END_DECLS + +#endif diff --git a/include/usbh_driver_hid_mouse.h b/include/usbh_driver_hid_mouse.h new file mode 100644 index 0000000..c12fed4 --- /dev/null +++ b/include/usbh_driver_hid_mouse.h @@ -0,0 +1,43 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_DRIVER_HID_MOUSE_ +#define USBH_DRIVER_HID_MOUSE_ + +#include "usbh_hubbed.h" + +#include + +BEGIN_DECLS + +struct _hid_mouse_config { + void (*mouse_in_message_handler)(uint8_t device_id, const uint8_t *data); +}; +typedef struct _hid_mouse_config hid_mouse_config_t; + +void hid_mouse_driver_init(const hid_mouse_config_t *config); + +extern const usbh_dev_driver_t usbh_hid_mouse_driver; + +END_DECLS + +#endif diff --git a/include/usbh_driver_hub.h b/include/usbh_driver_hub.h new file mode 100644 index 0000000..cda1463 --- /dev/null +++ b/include/usbh_driver_hub.h @@ -0,0 +1,36 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_DRIVER_HUB_ +#define USBH_DRIVER_HUB_ + +#include "usbh_hubbed.h" + +BEGIN_DECLS + +void hub_driver_init(void); + +extern const usbh_dev_driver_t usbh_hub_driver; + +END_DECLS + +#endif diff --git a/include/usbh_hubbed.h b/include/usbh_hubbed.h new file mode 100644 index 0000000..00d3b99 --- /dev/null +++ b/include/usbh_hubbed.h @@ -0,0 +1,76 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_HUBBED_ +#define USBH_HUBBED_ + +#include "usbh_config.h" + +#include + +/* This must be placed around external function declaration for C++ + * support. */ +#ifdef __cplusplus +# define BEGIN_DECLS extern "C" { +# define END_DECLS } +#else +# define BEGIN_DECLS +# define END_DECLS +#endif + +BEGIN_DECLS + +#ifndef bool +#define bool _Bool +#define false 0 +#define true 1 +#endif + + +// set to -1 to unused items +struct _usbh_dev_driver_info { + int32_t deviceClass; + int32_t deviceSubClass; + int32_t deviceProtocol; + int32_t idVendor; + int32_t idProduct; + int32_t ifaceClass; + int32_t ifaceSubClass; + int32_t ifaceProtocol; +}; +typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t; + +struct _usbh_dev_driver { + bool (*analyze_descriptor)(void *drv, void *descriptor); + void *(*init)(void *usbh_dev); + void (*poll)(void *drvdata, uint32_t t_us); + void (*remove)(void *drvdata); + const usbh_dev_driver_info_t * const info; +}; +typedef struct _usbh_dev_driver usbh_dev_driver_t; + +void usbh_init(const void *drivers[], const usbh_dev_driver_t * const device_drivers[]); +void usbh_poll(uint32_t t_us); + +END_DECLS + +#endif diff --git a/include/usbh_lld_stm32f4.h b/include/usbh_lld_stm32f4.h new file mode 100644 index 0000000..c55c615 --- /dev/null +++ b/include/usbh_lld_stm32f4.h @@ -0,0 +1,43 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_LLD_STM32F4_H_ +#define USBH_LLD_STM32F4_H_ + +#include "usbh_hubbed.h" + +#include + +BEGIN_DECLS + +// pass this to usbh init +extern const void *usbh_lld_stm32f4_drivers[]; + +#ifdef USART_DEBUG +void print_channels(const void *drvdata); +#else +#define print_channels(arg) ((void)arg) +#endif + +END_DECLS + +#endif diff --git a/initRepo.sh b/initRepo.sh new file mode 100755 index 0000000..10ff5cb --- /dev/null +++ b/initRepo.sh @@ -0,0 +1,4 @@ +#!/bin/sh +git submodule init +git submodule update +make -C libopencm3 -j3 lib/stm32/f4 diff --git a/libopencm3 b/libopencm3 new file mode 160000 index 0000000..798c1ed --- /dev/null +++ b/libopencm3 @@ -0,0 +1 @@ +Subproject commit 798c1edf4d11e8a40a7263dc465fa225a63fa7e9 diff --git a/libopencm3_stm32f4.ld b/libopencm3_stm32f4.ld new file mode 100644 index 0000000..46a80f2 --- /dev/null +++ b/libopencm3_stm32f4.ld @@ -0,0 +1,32 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for ST STM32F4DISCOVERY (STM32F407VG, 1024K flash, 128K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +/* Include the common ld script. */ +INCLUDE ./libopencm3/lib/libopencm3_stm32f4.ld + diff --git a/src/demo.c b/src/demo.c new file mode 100644 index 0000000..f4ef456 --- /dev/null +++ b/src/demo.c @@ -0,0 +1,186 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "usart_helpers.h" /// provides LOG_PRINTF macros used for debugging +#include "usbh_hubbed.h" /// provides usbh_init() and usbh_poll() +#include "usbh_lld_stm32f4.h" /// provides low level usb host driver for stm32f4 platform +#include "usbh_driver_hid_mouse.h" /// provides usb device driver Human Interface Device - type mouse +#include "usbh_driver_hub.h" /// provides usb full speed hub driver (Low speed devices on hub are not supported) +#include "usbh_driver_gp_xbox.h" /// provides usb device driver for Gamepad: Microsoft XBOX compatible Controller + + // STM32f407 compatible +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static inline void delay_ms_busy_loop(uint32_t ms) +{ + volatile uint32_t i; + for (i = 0; i < 14903*ms; i++); +} + + +/* Set STM32 to 168 MHz. */ +static void clock_setup(void) +{ + rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]); + + // GPIO + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); // OTG_FS + button + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN); // OTG_HS + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPCEN); // USART + OTG_FS charge pump + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN); // LEDS + + // periphery + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_USART6EN);// USART + rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_OTGHSEN); +} + +static void gpio_setup(void) +{ + /* Set GPIO12-15 (in GPIO port D) to 'output push-pull'. */ + gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, + GPIO_PUPD_NONE, GPIO12 | GPIO13 | GPIO14 | GPIO15); + + /* Set */ + gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0); + gpio_clear(GPIOC, GPIO0); + + // OTG_FS + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12); + + // OTG_HS + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO15 | GPIO14); + gpio_set_af(GPIOB, GPIO_AF12, GPIO14 | GPIO15); + + // USART TX + gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO7); + gpio_set_af(GPIOC, GPIO_AF8, GPIO6 | GPIO7); + + // button + gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO0); +} + +static const usbh_dev_driver_t *device_drivers[] = { + &usbh_hub_driver, + &usbh_hid_mouse_driver, + &usbh_gp_xbox_driver, + 0 +}; + +static void gp_xbox_update(uint8_t device_id, gp_xbox_packet_t packet) +{ + (void)device_id; + (void)packet; + LOG_PRINTF("update %d: %d %d \r\n", device_id, packet.axis_left_x, packet.buttons & GP_XBOX_BUTTON_A); +} + + +static void gp_xbox_connected(uint8_t device_id) +{ + (void)device_id; + LOG_PRINTF("connected %d", device_id); +} + +static void gp_xbox_disconnected(uint8_t device_id) +{ + (void)device_id; + LOG_PRINTF("disconnected %d", device_id); +} + +static const gp_xbox_config_t gp_xbox_config = { + .update = &gp_xbox_update, + .notify_connected = &gp_xbox_connected, + .notify_disconnected = &gp_xbox_disconnected +}; + +static void mouse_in_message_handler(uint8_t device_id, const uint8_t *data) +{ + (void)device_id; + (void)data; + // print only first 4 bytes, since every mouse should have at least these four set. + // Report descriptors are not read by driver for now, so we do not know what each byte means + LOG_PRINTF("MOUSE EVENT %02X %02X %02X %02X \r\n", data[0], data[1], data[2], data[3]); +} + +static const hid_mouse_config_t mouse_config = { + .mouse_in_message_handler = &mouse_in_message_handler +}; + +int main(void) +{ + clock_setup(); + gpio_setup(); + +#ifdef USART_DEBUG + usart_init(USART6, 921600); +#endif + LOG_PRINTF("\r\n\r\n\r\n\r\n\r\n###################\r\nInit\r\n"); + + /** + * device driver initialization + * + * Pass configuration struct where the callbacks are defined + */ + hid_mouse_driver_init(&mouse_config); + hub_driver_init(); + gp_xbox_driver_init(&gp_xbox_config); + + gpio_set(GPIOD, GPIO13); + + /** + * Pass array of supported low level drivers + * In case of stm32f407, there are up to two supported OTG hosts on one chip. + * Each one can be enabled or disabled in config.mk - optimization for speed + * + * Pass array of supported device drivers + */ + usbh_init(usbh_lld_stm32f4_drivers, device_drivers); + gpio_clear(GPIOD, GPIO13); + + LOG_PRINTF("USB init complete\r\n"); + + uint32_t i = 0; + + while (1) { + LOG_FLUSH(); + + // Toggle some led + gpio_set(GPIOD, GPIO14); + usbh_poll(i); + gpio_clear(GPIOD, GPIO14); + + delay_ms_busy_loop(1); + i += 1000; + } + + return 0; +} diff --git a/src/usart_helpers.c b/src/usart_helpers.c new file mode 100644 index 0000000..31a7556 --- /dev/null +++ b/src/usart_helpers.c @@ -0,0 +1,287 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + + +#include "usart_helpers.h" + +#include +#include +#include +#include +#include +#include + + +#ifndef USART_DEBUG + +void usart_init(uint32_t usart, uint32_t baudrate) +{ + (void)usart; + (void)baudrate; +} +void usart_printf(const char *str, ...) +{ + (void)str; +} +void usart_vprintf(const char *str, va_list va) +{ + (void)va; + (void)str; +} +void usart_fifo_send(void){} + +void usart_call_cmd(struct usart_commands * commands) +{ + (void)commands; +} +void usart_interrupt(void){} + +#else +#warning compiling with debug functions + +#define USART_FIFO_OUT_SIZE (4096) +uint8_t usart_fifo_out_data[USART_FIFO_OUT_SIZE]; +uint32_t usart_fifo_out_len = 0; +uint32_t usart_fifo_out_index = 0; + +#define USART_FIFO_IN_SIZE (1024) +uint8_t usart_fifo_in_data[USART_FIFO_IN_SIZE]; +uint32_t usart_fifo_in_len = 0; +uint32_t usart_fifo_in_index = 0; + +static uint32_t usart = 0; + +static uint8_t usart_fifo_pop(void) +{ + uint8_t ret; + usart_fifo_out_len--; + ret = usart_fifo_out_data[usart_fifo_out_index]; + usart_fifo_out_index++; + if (usart_fifo_out_index == USART_FIFO_OUT_SIZE ) { + usart_fifo_out_index = 0; + } + return ret; +} + +static void usart_fifo_push(uint8_t aData) +{ + uint32_t i; + if( (usart_fifo_out_len + 1) == USART_FIFO_OUT_SIZE)//overflow + { + usart_fifo_out_len = 0; + LOG_PRINTF("OVERFLOW!"); + return; + } + + i = usart_fifo_out_index + usart_fifo_out_len; + if (i >= USART_FIFO_OUT_SIZE) { + i -= USART_FIFO_OUT_SIZE; + } + usart_fifo_out_data[i] = aData; + usart_fifo_out_len++; +} + + +static uint8_t usart_fifo_in_pop(void) +{ + uint8_t ret; + usart_fifo_in_len--; + ret = usart_fifo_in_data[usart_fifo_in_index]; + usart_fifo_in_index++; + if (usart_fifo_in_index == USART_FIFO_IN_SIZE ) { + usart_fifo_in_index = 0; + } + return ret; +} + +static void usart_fifo_in_push(uint8_t aData) +{ + uint32_t i; + if( (usart_fifo_in_len + 1) == USART_FIFO_IN_SIZE)//overflow + { + usart_fifo_in_len = 0; + return; + } + + i = usart_fifo_in_index + usart_fifo_in_len; + if (i >= USART_FIFO_IN_SIZE) { + i -= USART_FIFO_IN_SIZE; + } + usart_fifo_in_data[i] = aData; + usart_fifo_in_len++; +} + + +static void usart_write(const char * data, uint32_t len) +{ + uint32_t i; + for(i = 0; i < len; i++) + { + usart_fifo_push(data[i]); + } +} +void usart_printf(const char *str, ...) +{ + va_list va; + va_start(va, str); + usart_vprintf(str, va); + va_end(va); + +} + +void usart_vprintf(const char *str, va_list va) +{ + char databuffer[128]; + int i = vsnprintf(databuffer, 128, str, va); + if (i > 0) { + usart_write(databuffer, i); + } +} + + + +void usart_init(uint32_t arg_usart, uint32_t baudrate) +{ + usart_set_baudrate(arg_usart, baudrate); + usart_set_databits(arg_usart, 8); + usart_set_flow_control(arg_usart, USART_FLOWCONTROL_NONE); + usart_set_mode(arg_usart, USART_MODE_TX | USART_MODE_RX); + usart_set_parity(arg_usart, USART_PARITY_NONE); + usart_set_stopbits(arg_usart, USART_STOPBITS_1); + + usart_enable_rx_interrupt(arg_usart); + usart_enable(arg_usart); + usart = arg_usart; +} +void usart_interrupt(void) +{ + if (usart_get_interrupt_source(usart, USART_SR_RXNE)) { + uint8_t data = usart_recv(usart); + usart_fifo_in_push(data); + if ( data != 3 && data != '\r' && data != '\n') { + usart_fifo_push(data); + } else { + LOG_PRINTF("\r\n>>"); + } + } +} + +void usart_fifo_send(void) +{ + while(usart_fifo_out_len) { + uint8_t data = usart_fifo_pop(); + usart_wait_send_ready(usart); + usart_send(usart, data); + } +} +static char command[128]; +static uint8_t command_len = 0; +static uint8_t command_argindex = 0; + +static uint8_t usart_read_command(void) +{ + uint32_t fifo_len = usart_fifo_in_len; + while (fifo_len) { + uint8_t data = usart_fifo_in_pop(); + + if ((data >= 'A') && (data <= 'Z')) { + data += 'a'-'A'; + } + + if (((data >= 'a') && (data <= 'z')) || ((data >='0') && (data<='9'))) { + command[command_len++] = data; + } else if (data == ' ') { + if (command_len) { + if (command_argindex == 0) { + command[command_len++] = 0; + command_argindex = command_len; + } else { + command[command_len++] = ' '; + } + } + } else if (data == '\r' || data == '\n') { + if (command_len) { + command[command_len++] = 0; + if (!command_argindex) { + command_argindex = command_len; + } + return 1; + } + } else if (data == 127) { + if (command_len) { + if (command_argindex) { + if (command_len == command_argindex) { + command_argindex = 0; + } + } + command[command_len] = '\0'; + command_len--; + } + } else if (data == 3) { + command_len = 0; + command_argindex = 0; + } else { + LOG_PRINTF("%d ",data); + } + + fifo_len--; + } + return 0; +} +void usart_call_cmd(struct usart_commands * commands) +{ + uint32_t i = 0; + if(!usart_read_command()) { + return; + } + if (!command_len) { + LOG_PRINTF("#2"); + return; + } + //~ for (i = 0; i < command_len; i++) { + //~ LOG_PRINTF("%c", command[i]); + //~ } + i=0; + while(commands[i].cmd != NULL) { + if (!strcmp((char*)command, (char*)commands[i].cmd)) { + if (commands[i].callback) { + if(command_argindex == command_len) { + commands[i].callback(NULL); + } else { + commands[i].callback(&command[command_argindex]); + } + } + usart_write("\r\n>>",4); + command_len = 0; + command_argindex = 0; + return; + } else { + + } + i++; + } + command_len = 0; + command_argindex = 0; + LOG_PRINTF("INVALID COMMAND\r\n>>"); +} + +#endif diff --git a/src/usart_helpers.h b/src/usart_helpers.h new file mode 100644 index 0000000..2a2f561 --- /dev/null +++ b/src/usart_helpers.h @@ -0,0 +1,56 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_USART_HELPERS_H +#define USBH_USART_HELPERS_H + +#include "usbh_hubbed.h" +#include +#include + +BEGIN_DECLS + +struct usart_commands{ + const char * cmd; + void (*callback)(const char * arg); +}; + + +void usart_init(uint32_t usart, uint32_t baudrate); +void usart_printf(const char *str, ...); +void usart_vprintf(const char *str, va_list va); +void usart_fifo_send(void); + +void usart_call_cmd(struct usart_commands * commands); +void usart_interrupt(void); + +#ifdef USART_DEBUG +#define LOG_PRINTF(format, ...) usart_printf(format, ##__VA_ARGS__); +#define LOG_FLUSH() usart_fifo_send() +#else +#define LOG_PRINTF(dummy, ...) ((void)dummy) +#define LOG_FLUSH() +#endif + +END_DECLS + +#endif diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c new file mode 100644 index 0000000..52955d9 --- /dev/null +++ b/src/usbh_driver_gp_xbox.c @@ -0,0 +1,420 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + + +#include "usart_helpers.h" +#include "usbh_driver_gp_xbox.h" +#include "driver/usbh_device_driver.h" + +#include +#include + +static void *gp_xbox_init(void *usbh_dev); +static bool gp_xbox_analyze_descriptor(void *drvdata, void *descriptor); +static void gp_xbox_poll(void *drvdata, uint32_t tflp); +static void gp_xbox_remove(void *drvdata); + +static const usbh_dev_driver_info_t usbh_gp_xbox_driver_info = { + .deviceClass = 0xff, + .deviceSubClass = 0xff, + .deviceProtocol = 0xff, + .idVendor = 0x045e, + .idProduct = 0x028e, + .ifaceClass = 0xff, + .ifaceSubClass = 93, + .ifaceProtocol = 0x01 +}; + +const usbh_dev_driver_t usbh_gp_xbox_driver = { + .init = gp_xbox_init, + .analyze_descriptor = gp_xbox_analyze_descriptor, + .poll = gp_xbox_poll, + .remove = gp_xbox_remove, + .info = &usbh_gp_xbox_driver_info +}; + +enum STATES { + STATE_INACTIVE, + STATE_READING_COMPLETE, + STATE_READING_REQUEST, + STATE_SET_CONFIGURATION_REQUEST, + STATE_SET_CONFIGURATION_EMPTY_READ, + STATE_SET_CONFIGURATION_COMPLETE +}; + +#define GP_XBOX_CORRECT_TRANSFERRED_LENGTH 20 + +struct _gp_xbox_device { + usbh_device_t *usbh_device; + uint8_t buffer[USBH_GP_XBOX_BUFFER]; + uint16_t endpoint_in_maxpacketsize; + uint8_t endpoint_in_address; + enum STATES state_next; + uint8_t endpoint_in_toggle; + uint8_t device_id; + uint8_t configuration_value; +}; +typedef struct _gp_xbox_device gp_xbox_device_t; + +static gp_xbox_device_t gp_xbox_device[USBH_GP_XBOX_MAX_DEVICES]; +static const gp_xbox_config_t *gp_xbox_config; + +static bool initialized = false; +static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox); + +void gp_xbox_driver_init(const gp_xbox_config_t *config) +{ + if (!config) { + return; + } + initialized = true; + uint32_t i; + gp_xbox_config = config; + for (i = 0; i < USBH_GP_XBOX_MAX_DEVICES; i++) { + gp_xbox_device[i].state_next = STATE_INACTIVE; + } +} + +/** + * + * + */ +static void *gp_xbox_init(void *usbh_dev) +{ + if (!initialized) { + LOG_PRINTF("driver not initialized"); + return false; + } + + uint32_t i; + gp_xbox_device_t *drvdata = 0; + + // find free data space for gp_xbox device + for (i = 0; i < USBH_GP_XBOX_MAX_DEVICES; i++) { + if (gp_xbox_device[i].state_next == STATE_INACTIVE) { + drvdata = &gp_xbox_device[i]; + drvdata->device_id = i; + drvdata->endpoint_in_address = 0; + drvdata->endpoint_in_toggle = 0; + drvdata->usbh_device = usbh_dev; + break; + } + } + + return drvdata; +} + +/** + * Returns true if all needed data are parsed + */ +static bool gp_xbox_analyze_descriptor(void *drvdata, void *descriptor) +{ + gp_xbox_device_t *gp_xbox = drvdata; + uint8_t desc_type = ((uint8_t *)descriptor)[1]; + switch (desc_type) { + case USB_DT_CONFIGURATION: + { + struct usb_config_descriptor *cfg = (struct usb_config_descriptor*)descriptor; + gp_xbox->configuration_value = cfg->bConfigurationValue; + } + break; + case USB_DT_DEVICE: + break; + case USB_DT_INTERFACE: + break; + case USB_DT_ENDPOINT: + { + struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor*)descriptor; + if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) { + uint8_t epaddr = ep->bEndpointAddress; + if (epaddr & (1<<7)) { + gp_xbox->endpoint_in_address = epaddr&0x7f; + if (ep->wMaxPacketSize < USBH_GP_XBOX_BUFFER) { + gp_xbox->endpoint_in_maxpacketsize = ep->wMaxPacketSize; + } else { + gp_xbox->endpoint_in_maxpacketsize = USBH_GP_XBOX_BUFFER; + } + } + + if (gp_xbox->endpoint_in_address) { + gp_xbox->state_next = STATE_SET_CONFIGURATION_REQUEST; + return true; + } + } + } + break; + // TODO Class Specific descriptors + default: + break; + } + return false; +} + +static void parse_data(usbh_device_t *dev) +{ + gp_xbox_device_t *gp_xbox = dev->drvdata; + + uint8_t *packet = gp_xbox->buffer; + + gp_xbox_packet_t gp_xbox_packet; + gp_xbox_packet.buttons = 0; + + // DPAD + const uint8_t data1 = packet[2]; + const uint8_t data2 = packet[3]; + if (data1 & (1 << 0)) { + gp_xbox_packet.buttons |= GP_XBOX_DPAD_TOP; + } + + if (data1 & (1 << 1)) { + gp_xbox_packet.buttons |= GP_XBOX_DPAD_BOTTOM; + } + + if (data1 & (1 << 2)) { + gp_xbox_packet.buttons |= GP_XBOX_DPAD_LEFT; + } + + if (data1 & (1 << 3)) { + gp_xbox_packet.buttons |= GP_XBOX_DPAD_RIGHT; + } + + // Start + select + + if (data1 & (1 << 4)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_START; + } + + if (data1 & (1 << 5)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_SELECT; + } + + // axis buttons + + if (data1 & (1 << 6)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_AXIS_LEFT; + } + + if (data1 & (1 << 7)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_AXIS_RIGHT; + } + + // buttons ABXY + + if (data2 & (1 << 4)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_A; + } + + if (data2 & (1 << 5)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_B; + } + + if (data2 & (1 << 6)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_X; + } + + if (data2 & (1 << 7)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_Y; + } + + // buttons rear + + if (data2 & (1 << 0)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_LT; + } + + if (data2 & (1 << 1)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_RT; + } + + if (data2 & (1 << 2)) { + gp_xbox_packet.buttons |= GP_XBOX_BUTTON_XBOX; + } + + // rear levers + + gp_xbox_packet.axis_rear_left = packet[4]; + gp_xbox_packet.axis_rear_right = packet[5]; + gp_xbox_packet.axis_left_x = packet[7]*256 + packet[6]; + gp_xbox_packet.axis_left_y = packet[9]*256 + packet[8]; + gp_xbox_packet.axis_right_x = packet[11]*256 + packet[10]; + gp_xbox_packet.axis_right_y = packet[13]*256 + packet[12]; + + // call update callback + if (gp_xbox_config->update) { + gp_xbox_config->update(gp_xbox->device_id, gp_xbox_packet); + } +} + +static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) +{ + gp_xbox_device_t *gp_xbox = dev->drvdata; + switch (gp_xbox->state_next) { + case STATE_READING_COMPLETE: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + parse_data(dev); + gp_xbox->state_next = STATE_READING_REQUEST; + break; + + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + if (cb_data.transferred_length == GP_XBOX_CORRECT_TRANSFERRED_LENGTH) { + parse_data(dev); + } + gp_xbox->state_next = STATE_READING_REQUEST; + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + ERROR(cb_data.status); + gp_xbox->state_next = STATE_INACTIVE; + break; + } + } + break; + + case STATE_SET_CONFIGURATION_EMPTY_READ: + { + LOG_PRINTF("|empty packet read|"); + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + gp_xbox->state_next = STATE_SET_CONFIGURATION_COMPLETE; + device_xfer_control_read(0, 0, event, dev); + break; + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + gp_xbox->state_next = STATE_INACTIVE; + break; + } + } + break; + case STATE_SET_CONFIGURATION_COMPLETE: // Configured + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + gp_xbox->state_next = STATE_READING_REQUEST; + gp_xbox->endpoint_in_toggle = 0; + LOG_PRINTF("\r\ngp_xbox CONFIGURED\r\n"); + if (gp_xbox_config->notify_connected) { + gp_xbox_config->notify_connected(gp_xbox->device_id); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + gp_xbox->state_next = STATE_INACTIVE; + break; + } + } + break; + + case STATE_INACTIVE: + { + LOG_PRINTF("XBOX inactive"); + } + break; + default: + { + LOG_PRINTF("Unknown state\r\n"); + } + break; + } +} + + +static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox) +{ + usbh_packet_t packet; + + packet.address = gp_xbox->usbh_device->address; + packet.data = &gp_xbox->buffer[0]; + packet.datalen = gp_xbox->endpoint_in_maxpacketsize; + packet.endpoint_address = gp_xbox->endpoint_in_address; + packet.endpoint_size_max = gp_xbox->endpoint_in_maxpacketsize; + packet.endpoint_type = USBH_EPTYP_BULK; + packet.speed = gp_xbox->usbh_device->speed; + packet.callback = event; + packet.callback_arg = gp_xbox->usbh_device; + packet.toggle = &gp_xbox->endpoint_in_toggle; + + gp_xbox->state_next = STATE_READING_COMPLETE; + usbh_read(gp_xbox->usbh_device, &packet); + + // LOG_PRINTF("@gp_xbox EP1 | \r\n"); +} + +/** + * + * tflp time from last poll [us] + */ +static void gp_xbox_poll(void *drvdata, uint32_t tflp) +{ + (void)tflp; + gp_xbox_device_t *gp_xbox = drvdata; + usbh_device_t *dev = gp_xbox->usbh_device; + + switch (gp_xbox->state_next) { + case STATE_READING_REQUEST: + { + read_gp_xbox_in(gp_xbox); + } + break; + + case STATE_SET_CONFIGURATION_REQUEST: + { + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00000000; + setup_data.bRequest = USB_REQ_SET_CONFIGURATION; + setup_data.wValue = gp_xbox->configuration_value; + setup_data.wIndex = 0; + setup_data.wLength = 0; + + gp_xbox->state_next = STATE_SET_CONFIGURATION_EMPTY_READ; + + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } + break; + + default: + { + // do nothing - probably transfer is in progress + } + break; + } +} + +static void gp_xbox_remove(void *drvdata) +{ + LOG_PRINTF("Removing xbox\r\n"); + + gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)drvdata; + if (gp_xbox_config->notify_disconnected) { + gp_xbox_config->notify_disconnected(gp_xbox->device_id); + } + gp_xbox->state_next = STATE_INACTIVE; + gp_xbox->endpoint_in_address = 0; +} diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c new file mode 100644 index 0000000..5c01451 --- /dev/null +++ b/src/usbh_driver_hid_mouse.c @@ -0,0 +1,294 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "usbh_hubbed.h" +#include "driver/usbh_device_driver.h" +#include "usbh_driver_hid_mouse.h" +#include "usart_helpers.h" + +#include + +static void *mouse_init(void *usbh_dev); +static bool mouse_analyze_descriptor(void *drvdata, void *descriptor); +static void mouse_poll(void *drvdata, uint32_t tflp); +static void mouse_remove(void *drvdata); + +static const usbh_dev_driver_info_t usbh_hid_mouse_driver_info = { + .deviceClass = -1, + .deviceSubClass = -1, + .deviceProtocol = -1, + .idVendor = -1, + .idProduct = -1, + .ifaceClass = 0x03, + .ifaceSubClass = -1, + .ifaceProtocol = 0x02 +}; + +const usbh_dev_driver_t usbh_hid_mouse_driver = { + .init = mouse_init, + .analyze_descriptor = mouse_analyze_descriptor, + .poll = mouse_poll, + .remove = mouse_remove, + .info = &usbh_hid_mouse_driver_info +}; + +enum STATES { + STATE_INACTIVE, + STATE_READING_COMPLETE, + STATE_READING_REQUEST, + STATE_SET_CONFIGURATION_REQUEST, + STATE_SET_CONFIGURATION_EMPTY_READ, + STATE_SET_CONFIGURATION_COMPLETE +}; + +struct _hid_mouse_device { + usbh_device_t *usbh_device; + uint8_t buffer[USBH_HID_MOUSE_BUFFER]; + uint16_t endpoint_in_maxpacketsize; + uint8_t endpoint_in_address; + enum STATES state_next; + uint8_t endpoint_in_toggle; + uint8_t device_id; + uint8_t configuration_value; +}; +typedef struct _hid_mouse_device hid_mouse_device_t; + +static hid_mouse_device_t mouse_device[USBH_HID_MOUSE_MAX_DEVICES]; +static const hid_mouse_config_t *mouse_config; + + + + +#include + + + +void hid_mouse_driver_init(const hid_mouse_config_t *config) +{ + uint32_t i; + mouse_config = config; + for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) { + mouse_device[i].state_next = STATE_INACTIVE; + } +} + +/** + * + * + */ +static void *mouse_init(void *usbh_dev) +{ + uint32_t i; + hid_mouse_device_t *drvdata = 0; + + // find free data space for mouse device + for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) { + if (mouse_device[i].state_next == STATE_INACTIVE) { + drvdata = &mouse_device[i]; + drvdata->device_id = i; + drvdata->endpoint_in_address = 0; + drvdata->endpoint_in_toggle = 0; + drvdata->usbh_device = usbh_dev; + break; + } + } + + return drvdata; +} + +/** + * Returns true if all needed data are parsed + */ +static bool mouse_analyze_descriptor(void *drvdata, void *descriptor) +{ + hid_mouse_device_t *mouse = drvdata; + uint8_t desc_type = ((uint8_t *)descriptor)[1]; + switch (desc_type) { + case USB_DT_CONFIGURATION: + { + struct usb_config_descriptor *cfg = (struct usb_config_descriptor*)descriptor; + mouse->configuration_value = cfg->bConfigurationValue; + } + break; + case USB_DT_DEVICE: + break; + case USB_DT_INTERFACE: + break; + case USB_DT_ENDPOINT: + { + struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor*)descriptor; + if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) { + uint8_t epaddr = ep->bEndpointAddress; + if (epaddr & (1<<7)) { + mouse->endpoint_in_address = epaddr&0x7f; + if (ep->wMaxPacketSize < USBH_HID_MOUSE_BUFFER) { + mouse->endpoint_in_maxpacketsize = ep->wMaxPacketSize; + } else { + mouse->endpoint_in_maxpacketsize = USBH_HID_MOUSE_BUFFER; + } + } + + if (mouse->endpoint_in_address) { + mouse->state_next = STATE_SET_CONFIGURATION_REQUEST; + return true; + } + } + } + break; + // TODO Class Specific descriptors + default: + break; + } + return false; +} + +static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) +{ + hid_mouse_device_t *mouse = dev->drvdata; + switch (mouse->state_next) { + case STATE_READING_COMPLETE: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + mouse->state_next = STATE_READING_REQUEST; + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + ERROR(cb_data.status); + mouse->state_next = STATE_INACTIVE; + break; + } + } + break; + + case STATE_SET_CONFIGURATION_EMPTY_READ: + { + LOG_PRINTF("|empty packet read|"); + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + mouse->state_next++; + device_xfer_control_read(0, 0, event, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + ERROR(cb_data.status); + mouse->state_next = STATE_INACTIVE; + break; + } + } + break; + case STATE_SET_CONFIGURATION_COMPLETE: // Configured + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + mouse->state_next = STATE_READING_REQUEST; + mouse->endpoint_in_toggle = 0; + LOG_PRINTF("\r\nMOUSE CONFIGURED\r\n"); + break; + + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + ERROR(cb_data.status); + mouse->state_next = STATE_INACTIVE; + break; + } + } + break; + default: + break; + } +} + + +static void read_mouse_in(void *drvdata) +{ + hid_mouse_device_t *mouse = drvdata; + usbh_packet_t packet; + + packet.address = mouse->usbh_device->address; + packet.data = &mouse->buffer[0]; + packet.datalen = mouse->endpoint_in_maxpacketsize; + packet.endpoint_address = mouse->endpoint_in_address; + packet.endpoint_size_max = mouse->endpoint_in_maxpacketsize; + packet.endpoint_type = USBH_EPTYP_BULK; + packet.speed = mouse->usbh_device->speed; + packet.callback = event; + packet.callback_arg = mouse->usbh_device; + packet.toggle = &mouse->endpoint_in_toggle; + + mouse->state_next = STATE_READING_COMPLETE; + usbh_read(mouse->usbh_device, &packet); + + // LOG_PRINTF("@MOUSE EP1 | \r\n"); + +} + +/** + * + * tflp time from last poll [us] + */ +static void mouse_poll(void *drvdata, uint32_t tflp) +{ + (void)drvdata; + (void)tflp; + hid_mouse_device_t *mouse = drvdata; + usbh_device_t *dev = mouse->usbh_device; + switch (mouse->state_next) { + case STATE_READING_REQUEST: + { + read_mouse_in(drvdata); + } + break; + + case STATE_SET_CONFIGURATION_REQUEST: + { + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00000000; + setup_data.bRequest = USB_REQ_SET_CONFIGURATION; + setup_data.wValue = mouse->configuration_value; + setup_data.wIndex = 0; + setup_data.wLength = 0; + + mouse->state_next++; + + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } + break; + + default: + // do nothing - probably transfer is in progress + break; + } +} + +static void mouse_remove(void *drvdata) +{ + hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata; + mouse->state_next = STATE_INACTIVE; + mouse->endpoint_in_address = 0; +} diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c new file mode 100644 index 0000000..c82eacd --- /dev/null +++ b/src/usbh_driver_hub.c @@ -0,0 +1,865 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "usbh_driver_hub_private.h" +#include "driver/usbh_device_driver.h" +#include "usart_helpers.h" +#include "usbh_config.h" + +#include + + +static hub_device_t hub_device[USBH_MAX_HUBS]; + +static void *hub_init(void *usbh_dev); +static bool hub_analyze_descriptor(void *drvdata, void *descriptor); +static void hub_poll(void *drvdata, uint32_t tflp); +static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data); +static void hub_remove(void *drvdata); + +static const usbh_dev_driver_info_t usbh_hub_driver_info = { + .deviceClass = 0x09, + .deviceSubClass = -1, + .deviceProtocol = -1, + .idVendor = -1, + .idProduct = -1, + .ifaceClass = 0x09, + .ifaceSubClass = -1, + .ifaceProtocol = -1 +}; + +const usbh_dev_driver_t usbh_hub_driver = { + .init = hub_init, + .analyze_descriptor = hub_analyze_descriptor, + .poll = hub_poll, + .remove = hub_remove, + .info = &usbh_hub_driver_info +}; + + + +void hub_driver_init(void) +{ + uint32_t i; + + for (i = 0; i < USBH_MAX_HUBS; i++) { + hub_device[i].device[0] = 0; + hub_device[i].ports_num = 0; + hub_device[i].current_port = -1; + } +} + + +/** + * + * + */ +static void *hub_init(void *usbh_dev) +{ + uint32_t i; + hub_device_t *drvdata = 0; + // find free data space for hub device + for (i = 0; i < USBH_MAX_HUBS; i++) { + if (hub_device[i].device[0] == 0) { + break; + } + } + LOG_PRINTF("%{%d}",i); + LOG_FLUSH(); + if (i == USBH_MAX_HUBS) { + LOG_PRINTF("ERRRRRRR"); + return 0; + } + + drvdata = &hub_device[i]; + drvdata->state = 0; + drvdata->ports_num = 0; + drvdata->device[0] = usbh_dev; + drvdata->busy = 0; + drvdata->endpoint_in_address = 0; + drvdata->endpoint_in_maxpacketsize = 0; + +// for (i = 1; i < USBH_MAX_HUBS + 1; i++) { +// drvdata->device[i]->address = 0; +// drvdata->device[i]->state = 0; +// } + return drvdata; +} + +/** + * Returns true if all needed data are parsed + */ +static bool hub_analyze_descriptor(void *drvdata, void *descriptor) +{ + hub_device_t *hub = drvdata; + uint8_t desc_type = ((uint8_t *)descriptor)[1]; + switch (desc_type) { + case USB_DT_CONFIGURATION: + { + struct usb_config_descriptor *cfg = (struct usb_config_descriptor*)descriptor; + hub->buffer[0] = cfg->bConfigurationValue; + } + break; + + case USB_DT_ENDPOINT: + { + struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor *)descriptor; + if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) { + uint8_t epaddr = ep->bEndpointAddress; + if (epaddr & (1<<7)) { + hub->endpoint_in_address = epaddr&0x7f; + hub->endpoint_in_maxpacketsize = ep->wMaxPacketSize; + } + } + LOG_PRINTF("ENDPOINT DESCRIPTOR FOUND\r\n"); + } + break; + + case USB_DT_HUB: + { + struct usb_hub_descriptor *desc = (struct usb_hub_descriptor *)descriptor; + //~ hub->ports_num = desc->head.bNbrPorts; + if ( desc->head.bNbrPorts <= USBH_HUB_MAX_DEVICES) { + hub->ports_num = desc->head.bNbrPorts; + } else { + LOG_PRINTF("INCREASE NUMBER OF ENABLED PORTS\r\n"); + hub->ports_num = USBH_HUB_MAX_DEVICES; + } + LOG_PRINTF("HUB DESCRIPTOR FOUND \r\n"); + } + break; + + default: + LOG_PRINTF("TYPE: %02X \r\n",desc_type); + break; + } + + if (hub->endpoint_in_address) { + hub->state = 1; + LOG_PRINTF("end enum"); + return true; + } + return false; +} + +// Enumerate +static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) +{ + //~ usbh_device_t *dev = arg; + hub_device_t *hub = dev->drvdata; + + LOG_PRINTF("\r\nHUB->STATE = %d\r\n", hub->state); + switch (hub->state) { + case 26: + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + uint8_t i; + uint8_t *buf = hub->buffer; + uint32_t psc = 0; // Limit: up to 4 bytes... + for (i = 0; i < cb_data.transferred_length; i++) { + psc += buf[i] << (i*8); + } + int8_t port = 0; + + LOG_PRINTF("psc:%d\r\n",psc); + // Driver error... port not found + if (!psc) { + // Continue reading status change endpoint + hub->state = 25; + break; + } + + for (i = 0; i <= hub->ports_num; i++) { + if (psc & (1<current_port >= 1) { + if (hub->current_port != port) { + LOG_PRINTF("X"); + hub->state = 25; + break; + } + } + struct usb_setup_data setup_data; + // If regular port event, else hub event + if (port) { + setup_data.bmRequestType = 0b10100011; + } else { + setup_data.bmRequestType = 0b10100000; + } + + + //~ LOG_PRINTF("port:%d", port); + setup_data.bRequest = USB_REQ_GET_STATUS; + setup_data.wValue = 0; + setup_data.wIndex = port; + setup_data.wLength = 4; + hub->state = 31; + + hub->current_port = port; + LOG_PRINTF("\r\n\r\nPORT FOUND: %d\r\n", port); + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + hub->state = 0; + break; + + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + + // In case of EAGAIN error, retry read on status endpoint + hub->state = 25; + LOG_PRINTF("HUB: Retrying...\r\n"); + break; + } + break; + + case 2: + { + LOG_PRINTF("|empty packet read|"); + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + device_xfer_control_read(0, 0, event, dev); + hub->state++; + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + + case 3: // Get HUB Descriptor write + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + if (hub->ports_num) { + hub->index = 0; + hub->state = 6; + LOG_PRINTF("No need to get HUB DESC\r\n"); + event(dev, cb_data); + } else { + hub->endpoint_in_toggle = 0; + + struct usb_setup_data setup_data; + hub->desc_len = hub->device[0]->packet_size_max0; + + setup_data.bmRequestType = 0b10100000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = 0x29<<8; + setup_data.wIndex = 0; + setup_data.wLength = hub->desc_len; + + hub->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + LOG_PRINTF("DO Need to get HUB DESC\r\n"); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + + case 4: // Get HUB Descriptor read + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + hub->state++; + device_xfer_control_read(hub->buffer, hub->desc_len, event, dev); // "error dynamic size" - bad comment, investigate + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + + case 5:// Hub descriptor found + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_hub_descriptor *hub_descriptor = + (struct usb_hub_descriptor *)hub->buffer; + + // Check size + if (hub_descriptor->head.bDescLength > hub->desc_len) { + struct usb_setup_data setup_data; + hub->desc_len = hub_descriptor->head.bDescLength; + + setup_data.bmRequestType = 0b10100000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = 0x29<<8; + setup_data.wIndex = 0; + setup_data.wLength = hub->desc_len; + + hub->state = 4; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + break; + } else if (hub_descriptor->head.bDescLength == hub->desc_len) { + hub->ports_num = hub_descriptor->head.bNbrPorts; + + hub->state++; + hub->index = 0; + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + event(dev, cb_data); + } else { + //try again + } + } + break; + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + { + LOG_PRINTF("->\t\t\t\t\t ERRSIZ: deschub\r\n"); + struct usb_hub_descriptor*hub_descriptor = + (struct usb_hub_descriptor *)hub->buffer; + + if (cb_data.transferred_length >= sizeof(struct usb_hub_descriptor_head)) { + if (cb_data.transferred_length == hub_descriptor->head.bDescLength) { + // Process HUB descriptor + if ( hub_descriptor->head.bNbrPorts <= USBH_HUB_MAX_DEVICES) { + hub->ports_num = hub_descriptor->head.bNbrPorts; + } else { + LOG_PRINTF("INCREASE NUMBER OF ENABLED PORTS\r\n"); + hub->ports_num = USBH_HUB_MAX_DEVICES; + } + hub->state++; + hub->index = 0; + + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + event(dev, cb_data); + } + } + } + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + ERROR(cb_data.status); + break; + } + } + break; + + case 6:// enable ports + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + if (hub->index < hub->ports_num) { + hub->index++; + struct usb_setup_data setup_data; + + LOG_PRINTF("[!%d!]",hub->index); + setup_data.bmRequestType = 0b00100011; + setup_data.bRequest = HUB_REQ_SET_FEATURE; + setup_data.wValue = HUB_FEATURE_PORT_POWER; + setup_data.wIndex = hub->index; + setup_data.wLength = 0; + + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } else { + hub->state++; + // TODO: + // Delay Based on hub descriptor field bPwr2PwrGood + // delay_ms_busy_loop(200); + + LOG_PRINTF("\r\nHUB CONFIGURED & PORTS POWERED\r\n"); + + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + event(dev, cb_data); + } + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + + case 7: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b10100000; + setup_data.bRequest = USB_REQ_GET_STATUS; + setup_data.wValue = 0; + setup_data.wIndex = 0; + setup_data.wLength = 4; + + hub->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + + } + break; + case 8: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + device_xfer_control_read(hub->buffer, 4, event, dev); + hub->index = 0; + hub->state++; + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + case 9: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b10100011; + setup_data.bRequest = USB_REQ_GET_STATUS; + setup_data.wValue = 0; + setup_data.wIndex = ++hub->index; + setup_data.wLength = 4; + + hub->state++; + + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + case 10: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + device_xfer_control_read(hub->buffer, 4, event, dev); + hub->state++; + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + case 11: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + if (hub->index < hub->ports_num) { + hub->state = 9; + // process data contained in hub->buffer + // TODO: + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + event(dev, cb_data); + } else { + hub->busy = 0; + hub->state = 25; + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + break; + } + } + break; + + case 31: // Read port status + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + int8_t port = hub->current_port; + hub->state++; + + // TODO: rework to endianess aware, + // (maybe whole library is affected by this) + // Detail: + // Isn't universal. Here is endianess ok, + // but on another architecture must not be + device_xfer_control_read(&hub->hub_and_port_status[port], 4, event, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + // continue + hub->state = 25; + break; + } + + } + break; + case 32: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + int8_t port = hub->current_port; + LOG_PRINTF("|%d",port); + + + // Get Port status, else Get Hub status + if (port) { + uint16_t stc = hub->hub_and_port_status[port].stc; + + // Connection status changed + if (stc & (1<device[port]) { + if (!usbh_enum_available() || hub->busy) { + LOG_PRINTF("\r\n\t\t\tCannot enumerate %d %d\r\n", !usbh_enum_available(), hub->busy); + hub->state = 25; + break; + } + } + + // clear feature C_PORT_CONNECTION + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00100011; + setup_data.bRequest = HUB_REQ_CLEAR_FEATURE; + setup_data.wValue = HUB_FEATURE_C_PORT_CONNECTION; + setup_data.wIndex = port; + setup_data.wLength = 0; + + hub->state = 33; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + + } else if(stc & (1<state = 35; + + LOG_PRINTF("RESET"); + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } else { + LOG_PRINTF("another STC %d\r\n", stc); + } + } else { + hub->state = 25; + LOG_PRINTF("HUB status change\r\n"); + } + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + // continue + hub->state = 25; + break; + } + } + break; + case 33: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + int8_t port = hub->current_port; + uint16_t stc = hub->hub_and_port_status[port].stc; + if (!hub->device[port]) { + if ((stc) & (1<state = 11; + LOG_PRINTF("CONN"); + + hub->busy = 1; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } + } else { + LOG_PRINTF("\t\t\t\tDISCONNECT EVENT\r\n"); + if (hub->device[port]->drv && hub->device[port]->drvdata) { + hub->device[port]->drv->remove(hub->device[port]->drvdata); + } + hub->device[port]->address = -1; + + hub->device[port]->drv = 0; + hub->device[port]->drvdata = 0; + hub->device[port] = 0; + hub->current_port = CURRENT_PORT_NONE; + hub->state = 25; + hub->busy = 0; + } + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + // continue + hub->state = 25; + break; + } + } + break; + case 35: // RESET COMPLETE, start enumeration + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + LOG_PRINTF("\r\nPOLL\r\n"); + int8_t port = hub->current_port; + uint16_t sts = hub->hub_and_port_status[port].sts; + + + if (sts & (1<device[port] = usbh_get_free_device(dev); + + if (!hub->device[port]) { + LOG_PRINTF("\r\nFATAL ERROR\r\n"); + return;// DEAD END + } + if ((sts & (1<<(HUB_FEATURE_PORT_LOWSPEED))) && + !(sts & (1<<(HUB_FEATURE_PORT_HIGHSPEED)))) { + LOG_PRINTF("Low speed device"); + + // Disable Low speed device immediately + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00100011; + setup_data.bRequest = HUB_REQ_CLEAR_FEATURE; + setup_data.wValue = HUB_FEATURE_PORT_ENABLE; + setup_data.wIndex = port; + setup_data.wLength = 0; + + // After write process another devices, poll for events + hub->state = 11;//Expecting all ports are powered (constant/non-changeable after init) + hub->current_port = CURRENT_PORT_NONE; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } else if (!(sts & (1<<(HUB_FEATURE_PORT_LOWSPEED))) && + !(sts & (1<<(HUB_FEATURE_PORT_HIGHSPEED)))) { + hub->device[port]->speed = USBH_SPEED_FULL; + LOG_PRINTF("Full speed device"); + hub->timestamp_us = hub->time_curr_us; + hub->state = 100; // schedule wait for 500ms + } + + + } else { + LOG_PRINTF("%s:%d Do not know what to do, when device is disabled after reset\r\n", __FILE__, __LINE__); + hub->state = 25; + return; + } + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + ERROR(cb_data.status); + // continue + hub->state = 25; + break; + } + } + break; + default: + LOG_PRINTF("UNHANDLED EVENT %d\r\n",hub->state); + break; + } +} + +static void read_ep1(void *drvdata) +{ + hub_device_t *hub = drvdata; + usbh_packet_t packet; + + packet.address = hub->device[0]->address; + packet.data = hub->buffer; + packet.datalen = hub->endpoint_in_maxpacketsize; + packet.endpoint_address = hub->endpoint_in_address; + packet.endpoint_size_max = hub->endpoint_in_maxpacketsize; + packet.endpoint_type = USBH_EPTYP_INTERRUPT; + packet.speed = hub->device[0]->speed; + packet.callback = event; + packet.callback_arg = hub->device[0]; + packet.toggle = &hub->endpoint_in_toggle; + + hub->state = 26; + usbh_read(hub->device[0], &packet); + LOG_PRINTF("@hub %d/EP1 | \r\n", hub->device[0]->address); + +} + +/** + * + * tflp time from last poll [ms] + */ +static void hub_poll(void *drvdata, uint32_t time_curr_us) +{ + hub_device_t *hub = drvdata; + usbh_device_t *dev = hub->device[0]; + + hub->time_curr_us = time_curr_us; + + switch (hub->state) { + case 25: + { + if (usbh_enum_available()) { + read_ep1(hub); + } else { + LOG_PRINTF("enum not available\r\n"); + } + } + break; + + case 1: + { + LOG_PRINTF("CFGVAL: %d\r\n", hub->buffer[0]); + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00000000; + setup_data.bRequest = USB_REQ_SET_CONFIGURATION; + setup_data.wValue = hub->buffer[0]; + setup_data.wIndex = 0; + setup_data.wLength = 0; + + hub->state += 2; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + + } + break; + case 100: + if (hub->time_curr_us - hub->timestamp_us > 500000) { + int8_t port = hub->current_port; + LOG_PRINTF("PORT: %d", port); + LOG_PRINTF("\r\nNEW device at address: %d\r\n", hub->device[port]->address); + hub->device[port]->lld = hub->device[0]->lld; + + device_enumeration_start(hub->device[port]); + hub->current_port = CURRENT_PORT_NONE; + + // Maybe error, when assigning address is taking too long + // + // Detail: + // USB hub cannot enable another port while the device + // the current one is also in address state (has address==0) + // Only one device on bus can have address==0 + hub->busy = 0; + + hub->state = 25; + } + break; + default: + break; + } + + if (usbh_enum_available()) { + uint32_t i; + for (i = 1; i < USBH_HUB_MAX_DEVICES + 1; i++) { + if (hub->device[i]) { + if (hub->device[i]->drv && hub->device[i]->drvdata) { + hub->device[i]->drv->poll(hub->device[i]->drvdata, time_curr_us); + } + } + } + } +} +static void hub_remove(void *drvdata) +{ + hub_device_t *hub = drvdata; + uint8_t i; + + // Call fast... to avoid polling + hub->state = 0; + hub->endpoint_in_address = 0; + hub->busy = 0; + for (i = 1; i < USBH_HUB_MAX_DEVICES + 1; i++) { + if (hub->device[i]) { + if (hub->device[i]->drv && hub->device[i]->drvdata) { + if (hub->device[i]->drv->remove != hub_remove) { + LOG_PRINTF("\t\t\t\tHUB REMOVE %d\r\n",hub->device[i]->address); + hub->device[i]->drv->remove(hub->device[i]->drvdata); + } + } + hub->device[i] = 0; + } + hub->device[0]->drv = 0; + hub->device[0]->drvdata = 0; + hub->device[0] = 0; + + } +} diff --git a/src/usbh_driver_hub_private.h b/src/usbh_driver_hub_private.h new file mode 100644 index 0000000..4b98880 --- /dev/null +++ b/src/usbh_driver_hub_private.h @@ -0,0 +1,108 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_DRIVER_HUB_PRIVATE_ +#define USBH_DRIVER_HUB_PRIVATE_ + +#include "usbh_config.h" +#include "driver/usbh_device_driver.h" +#include "usbh_driver_hub.h" + +#include +#include +#include + + +// # HUB DEFINITIONS +#define HUB_FEATURE_PORT_CONNECTION 0 +#define HUB_FEATURE_PORT_ENABLE 1 +#define HUB_FEATURE_PORT_SUSPEND 2 +#define HUB_FEATURE_PORT_OVERCURRENT 3 +#define HUB_FEATURE_PORT_RESET 4 +#define HUB_FEATURE_PORT_POWER 8 +#define HUB_FEATURE_PORT_LOWSPEED 9 +#define HUB_FEATURE_PORT_HIGHSPEED 10 + +#define HUB_FEATURE_C_PORT_CONNECTION 16 +#define HUB_FEATURE_C_PORT_ENABLE 17 +#define HUB_FEATURE_C_PORT_SUSPEND 18 +#define HUB_FEATURE_C_PORT_OVERCURRENT 19 +#define HUB_FEATURE_C_PORT_RESET 20 + +#define HUB_REQ_GET_STATUS 0 +#define HUB_REQ_CLEAR_FEATURE 1 +#define HUB_REQ_SET_FEATURE 3 +#define HUB_REQ_GET_DESCRIPTOR 6 + +#define USB_DT_HUB (41) +#define USB_DT_HUB_SIZE (9) +// Hub buffer: must be larger than hub descriptor +#define USBH_HUB_BUFFER_SIZE (USB_DT_HUB_SIZE) + + +#define CURRENT_PORT_NONE -1 + +struct _hub_device { + usbh_device_t *device[USBH_HUB_MAX_DEVICES + 1]; + uint8_t buffer[USBH_HUB_BUFFER_SIZE]; + uint16_t endpoint_in_maxpacketsize; + uint8_t endpoint_in_address; + uint8_t endpoint_in_toggle; + uint8_t state; + uint8_t desc_len; + uint16_t ports_num; + int8_t index; + int8_t current_port; + + struct { + uint16_t sts; + uint16_t stc; + } hub_and_port_status[USBH_HUB_MAX_DEVICES + 1]; + + bool busy; + + uint32_t time_curr_us; + uint32_t timestamp_us; +}; + +typedef struct _hub_device hub_device_t; + +struct usb_hub_descriptor_head { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; +} __attribute__((packed)); +struct usb_hub_descriptor_body { + uint8_t bDeviceRemovable; + uint8_t PortPwrCtrlMask; +} __attribute__((packed)); + +// for hubs with up to 7 ports on hub +struct usb_hub_descriptor { + struct usb_hub_descriptor_head head; + struct usb_hub_descriptor_body body[1]; +} __attribute__((packed)); + +#endif diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c new file mode 100644 index 0000000..e935f99 --- /dev/null +++ b/src/usbh_hubbed.c @@ -0,0 +1,634 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "usbh_config.h" +#include "usbh_lld_stm32f4.h" +#include "driver/usbh_device_driver.h" +#include "usart_helpers.h" + +#include +#include + +static struct { + bool enumeration_run; + const usbh_driver_t * const *lld_drivers; + const usbh_dev_driver_t * const *dev_drivers; + int8_t address_temporary; +} usbh_data = {0}; + +static void set_enumeration(void) +{ + usbh_data.enumeration_run = true; +} + +static void reset_enumeration(void) +{ + usbh_data.enumeration_run = false; +} + +static bool enumeration(void) +{ + return usbh_data.enumeration_run; +} + +/** + * + */ +static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * device_info) +{ + +#define CHECK_PARTIAL_COMPATIBILITY(what) \ + if (usbh_data.dev_drivers[i]->info->what != -1\ + && device_info->what != usbh_data.dev_drivers[i]->info->what) {\ + i++;\ + continue;\ + } + + + int i = 0; + + while (usbh_data.dev_drivers[i]) { + + CHECK_PARTIAL_COMPATIBILITY(ifaceClass); + CHECK_PARTIAL_COMPATIBILITY(ifaceSubClass); + CHECK_PARTIAL_COMPATIBILITY(ifaceProtocol); + CHECK_PARTIAL_COMPATIBILITY(deviceClass); + CHECK_PARTIAL_COMPATIBILITY(deviceSubClass); + CHECK_PARTIAL_COMPATIBILITY(deviceProtocol); + CHECK_PARTIAL_COMPATIBILITY(idVendor); + CHECK_PARTIAL_COMPATIBILITY(idProduct); + + return usbh_data.dev_drivers[i]; + } + return 0; +#undef CHECK_PARTIAL_COMPATIBILITY +} + + +static void device_register(void *descriptors, uint16_t descriptors_len, usbh_device_t *dev) +{ + uint32_t i = 0; + dev->drv = 0; + uint8_t *buf = (uint8_t *)descriptors; + + dev->drv = 0; + dev->drvdata = 0; + + uint8_t desc_len = buf[i]; + uint8_t desc_type = buf[i + 1]; + + usbh_dev_driver_info_t device_info; + if (desc_type == USB_DT_DEVICE) { + struct usb_device_descriptor *device_desc = (void*)&buf[i]; + LOG_PRINTF("DEVICE DESCRIPTOR"); + device_info.deviceClass = device_desc->bDeviceClass; + device_info.deviceSubClass = device_desc->bDeviceSubClass; + device_info.deviceProtocol = device_desc->bDeviceProtocol; + device_info.idVendor = device_desc->idVendor; + device_info.idProduct = device_desc->idProduct; + } else { + LOG_PRINTF("INVALID descriptors pointer - fatal error"); + return; + } + + + while (i < descriptors_len) { + desc_len = buf[i]; + desc_type = buf[i + 1]; + switch (desc_type) { + case USB_DT_DEVICE: + { + struct usb_device_descriptor *device_desc = (void*)&buf[i]; + LOG_PRINTF("DEVICE DESCRIPTOR"); + device_info.deviceClass = device_desc->bDeviceClass; + device_info.deviceSubClass = device_desc->bDeviceSubClass; + } + break; + + case USB_DT_INTERFACE: + { + LOG_PRINTF("INTERFACE_DESCRIPTOR\r\n"); + struct usb_interface_descriptor *iface = (void*)&buf[i]; + device_info.ifaceClass = iface->bInterfaceClass; + device_info.ifaceSubClass = iface->bInterfaceSubClass; + device_info.ifaceProtocol = iface->bInterfaceProtocol; + const usbh_dev_driver_t *driver = find_driver(&device_info); + if (driver) { + dev->drv = driver; + dev->drvdata = dev->drv->init(dev); + if (!dev->drvdata) { + LOG_PRINTF("CANT TOUCH THIS"); + } + break; + } + } + break; + default: + break; + } + + if (desc_len == 0) { + LOG_PRINTF("PROBLEM WITH PARSE %d\r\n",i); + return; + } + i += desc_len; + + } + + if (dev->drv && dev->drvdata) { + // analyze descriptors + LOG_PRINTF("ANALYZE"); + i = 0; + while (i < descriptors_len) { + desc_len = buf[i]; + void *drvdata = dev->drvdata; + LOG_PRINTF("[%d]",buf[i+1]); + if (dev->drv->analyze_descriptor(drvdata, &buf[i])) { + LOG_PRINTF("Device Initialized\r\n"); + return; + } + i += desc_len; + } + } + LOG_PRINTF("Device NOT Initialized\r\n"); +} + +void usbh_init(const void *drivers_lld[], const usbh_dev_driver_t * const device_drivers[]) +{ + if (!drivers_lld) { + return; + } + + usbh_data.lld_drivers = (const usbh_driver_t **)drivers_lld; + usbh_data.dev_drivers = device_drivers; + + // TODO: init structures + uint32_t k = 0; + while (usbh_data.lld_drivers[k]) { + LOG_PRINTF("DRIVER %d\r\n", k); + + usbh_device_t * usbh_device = + ((usbh_generic_data_t *)(usbh_data.lld_drivers[k])->driver_data)->usbh_device; + uint32_t i; + for (i = 0; i < USBH_MAX_DEVICES; i++) { + //~ LOG_PRINTF("%p ", &usbh_device[i]); + usbh_device[i].address = -1; + usbh_device[i].drv = 0; + usbh_device[i].drvdata = 0; + } + LOG_PRINTF("DRIVER %d", k); + usbh_data.lld_drivers[k]->init(usbh_data.lld_drivers[k]->driver_data); + + k++; + } + +} + +/* + * NEW ENUMERATE + * + */ +void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev) +{ + usbh_packet_t packet; + + packet.data = data; + packet.datalen = datalen; + packet.address = dev->address; + packet.endpoint_address = 0; + packet.endpoint_size_max = dev->packet_size_max0; + packet.endpoint_type = USBH_EPTYP_CONTROL; + packet.speed = dev->speed; + packet.callback = callback; + packet.callback_arg = dev; + packet.toggle = &dev->toggle0; + + usbh_write(dev, &packet); + LOG_PRINTF("WR@device...%d | \r\n", dev->address); +} + +void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev) +{ + usbh_packet_t packet; + + packet.data = data; + packet.datalen = datalen; + packet.address = dev->address; + packet.endpoint_address = 0; + packet.endpoint_size_max = dev->packet_size_max0; + packet.endpoint_type = USBH_EPTYP_CONTROL; + packet.speed = dev->speed; + packet.callback = callback; + packet.callback_arg = dev; + packet.toggle = &dev->toggle0; + + usbh_read(dev, &packet); + LOG_PRINTF("RD@device...%d | \r\n", dev->address); +} + + + +bool usbh_enum_available(void) +{ + return !enumeration(); +} + +/** + * Returns 0 on error + * device otherwise + */ +usbh_device_t *usbh_get_free_device(const usbh_device_t *dev) +{ + const usbh_driver_t *lld = dev->lld; + usbh_generic_data_t *lld_data = lld->driver_data; + usbh_device_t *usbh_device = lld_data->usbh_device; + + uint8_t i; + LOG_PRINTF("DEV ADDRESS%d\r\n", dev->address); + for (i = 0; i < USBH_MAX_DEVICES; i++) { + if (usbh_device[i].address < 0) { + LOG_PRINTF("\t\t\t\t\tFOUND: %d", i); + usbh_device[i].address = i+1; + return &usbh_device[i]; + } else { + LOG_PRINTF("address: %d\r\n\r\n\r\n", usbh_device[i].address); + } + } + + return 0; +} + +static void device_enumeration_terminate(usbh_device_t *dev) +{ + reset_enumeration(); + dev->state = 0; + dev->address = -1; +} + +/* Do not call this function directly, + * only via callback passing into low-level function + * If you must, call it carefully ;) + */ +static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) +{ + const usbh_driver_t *lld = dev->lld; + usbh_generic_data_t *lld_data = lld->driver_data; + uint8_t *usbh_buffer = lld_data->usbh_buffer; + uint8_t state_start = dev->state; // Detection of hang +// LOG_PRINTF("\r\nSTATE: %d\r\n", state); + switch (dev->state) { + case 1: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + dev->state++; + LOG_PRINTF("::%d::", dev->address); + device_xfer_control_read(0, 0, device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + case 2: + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + if (dev->address == 0) { + dev->address = usbh_data.address_temporary; + LOG_PRINTF("ADDR: %d\r\n", dev->address); + } + + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b10000000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = USB_DT_DEVICE << 8; + setup_data.wIndex = 0; + setup_data.wLength = USB_DT_DEVICE_SIZE; + + dev->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + break; + + case 3: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + dev->state++; + device_xfer_control_read(&usbh_buffer[0], USB_DT_DEVICE_SIZE, + device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + dev->state = 2; + + // WARNING: Recursion + // .. but should work + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + device_enumerate(dev, cb_data); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 4: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_device_descriptor *ddt = + (struct usb_device_descriptor *)&usbh_buffer[0]; + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b10000000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = USB_DT_CONFIGURATION << 8; + setup_data.wIndex = 0; + setup_data.wLength = ddt->bMaxPacketSize0;//USB_DT_CONFIGURATION_SIZE; + + dev->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + if (cb_data.transferred_length >= 8) { + struct usb_device_descriptor *ddt = + (struct usb_device_descriptor *)&usbh_buffer[0]; + dev->packet_size_max0 = ddt->bMaxPacketSize0; + dev->state = 2; + + // WARNING: Recursion + // .. but should work + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + device_enumerate(dev, cb_data); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + case 5: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + dev->state++; + device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE], + dev->packet_size_max0, device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 6: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + struct usb_setup_data setup_data; + LOG_PRINTF("WRITE: LEN: %d", cdt->wTotalLength); + setup_data.bmRequestType = 0b10000000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = USB_DT_CONFIGURATION << 8; + setup_data.wIndex = 0; + setup_data.wLength = cdt->wTotalLength; + + dev->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + if (cb_data.transferred_length >= USB_DT_CONFIGURATION_SIZE) { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + if (cb_data.transferred_length <= cdt->wTotalLength) { + dev->state = 8; + + // WARNING: Recursion + // .. but should work + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + device_enumerate(dev, cb_data); + } + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 7: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + dev->state++; + device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE], + cdt->wTotalLength, device_enumerate, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 8: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + LOG_PRINTF("TOTAL_LENGTH: %d\r\n", cdt->wTotalLength); + device_register(usbh_buffer, cdt->wTotalLength + USB_DT_DEVICE_SIZE, dev); + dev->state++; + + reset_enumeration(); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + + } + break; + } + + if (state_start == dev->state) { + LOG_PRINTF("\r\n !HANG %d\r\n", state_start); + } +} + +void device_enumeration_start(usbh_device_t *dev) +{ + set_enumeration(); + dev->state = 1; + + // save address + uint8_t address = dev->address; + dev->address = 0; + + if (dev->speed == USBH_SPEED_LOW) { + dev->packet_size_max0 = 8; + } else { + dev->packet_size_max0 = 64; + } + + usbh_data.address_temporary = address; + + LOG_PRINTF("\r\n\r\n\r\n ENUMERATION OF DEVICE@%d STARTED \r\n\r\n", address); + + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00000000; + setup_data.bRequest = USB_REQ_SET_ADDRESS; + setup_data.wValue = address; + setup_data.wIndex = 0; + setup_data.wLength = 0; + + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); +} + +/** + * Should be called with at least 1kHz frequency + * + */ +void usbh_poll(uint32_t t_us) +{ + uint32_t k = 0; + while (usbh_data.lld_drivers[k]) { + usbh_device_t * usbh_device = + ((usbh_generic_data_t *)(usbh_data.lld_drivers[k]->driver_data))->usbh_device; + usbh_generic_data_t *lld_data = usbh_data.lld_drivers[k]->driver_data; + + enum USBH_POLL_STATUS poll_status = + usbh_data.lld_drivers[k]->poll(lld_data, t_us); + + switch (poll_status) { + case USBH_POLL_STATUS_DEVICE_CONNECTED: + // New device found + LOG_PRINTF("\r\nDEVICE FOUND\r\n"); + usbh_device[0].lld = usbh_data.lld_drivers[k]; + usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data); + usbh_device[0].address = 1; + + device_enumeration_start(&usbh_device[0]); + break; + + case USBH_POLL_STATUS_DEVICE_DISCONNECTED: + { + // Device disconnected + if (usbh_device[0].drv && usbh_device[0].drvdata) { + usbh_device[0].drv->remove(usbh_device[0].drvdata); + } + usbh_device[0].drv = 0; + usbh_device[0].drvdata = 0; + + uint32_t i; + for (i = 1; i < USBH_MAX_DEVICES; i++) { + usbh_device[i].address = -1; + usbh_device[i].drv = 0; + usbh_device[i].drvdata = 0; + } + } + break; + + default: + break; + } + + if (lld_data->usbh_device[0].drv && usbh_device[0].drvdata) { + usbh_device[0].drv->poll(usbh_device[0].drvdata, t_us); + } + + k++; + } +} + +void usbh_read(usbh_device_t *dev, usbh_packet_t *packet) +{ + const usbh_driver_t *lld = dev->lld; + lld->read(lld->driver_data, packet); +} + +void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet) +{ + const usbh_driver_t *lld = dev->lld; + lld->write(lld->driver_data, packet); +} + diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c new file mode 100644 index 0000000..6cf6015 --- /dev/null +++ b/src/usbh_lld_stm32f4.c @@ -0,0 +1,1048 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "usbh_lld_stm32f4.h" +#include "usart_helpers.h" +#include "driver/usbh_device_driver.h" + +#include +#include +#include +#include + + + +/* Receive FIFO size in 32-bit words. */ +#define RX_FIFO_SIZE (64) +/* Transmit NON-periodic FIFO size in 32-bit words. */ +#define TX_NP_FIFO_SIZE (64) +/* Transmit periodic FIFO size in 32-bit words. */ +#define TX_P_FIFO_SIZE (64) + + + + +enum CHANNEL_STATE { + CHANNEL_STATE_FREE = 0, + CHANNEL_STATE_WORK = 1 +}; + +struct _channel { + enum CHANNEL_STATE state; + usbh_packet_t packet; + uint32_t data_index; //used in receive function + uint8_t error_count; +}; +typedef struct _channel channel_t; + +enum DEVICE_STATE { + DEVICE_STATE_INIT = 0, + DEVICE_STATE_RUN = 1, + DEVICE_STATE_RESET = 2 +}; + +enum DEVICE_POLL_STATE { + DEVICE_POLL_STATE_DISCONN = 0, + DEVICE_POLL_STATE_DEVCONN = 1, + DEVICE_POLL_STATE_DEVRST = 2, + DEVICE_POLL_STATE_RUN = 3 +}; + +struct _usbh_lld_stm32f4_driver_data { + usbh_generic_data_t generic; + const uint32_t base; + channel_t *channels; + const uint8_t num_channels; + + uint32_t poll_sequence; + enum DEVICE_POLL_STATE dpstate; + enum DEVICE_STATE state; + uint32_t state_prev;//for reset only + uint32_t time_curr_us; + uint32_t timestamp_us; +}; +typedef struct _usbh_lld_stm32f4_driver_data usbh_lld_stm32f4_driver_data_t; + + + +/* + * Define correct REBASE. If only one driver is enabled use directly OTG base + * + */ +#if defined(USE_STM32F4_USBH_DRIVER_FS) || \ + defined(USE_STM32F4_USBH_DRIVER_HS) + +#if defined(USE_STM32F4_USBH_DRIVER_FS) && \ + defined(USE_STM32F4_USBH_DRIVER_HS) +#define REBASE(reg) MMIO32(dev->base + reg) +#define REBASE_CH(reg, x) MMIO32(dev->base + reg(x)) +#elif defined(USE_STM32F4_USBH_DRIVER_FS) +#define REBASE(reg) MMIO32(USB_OTG_FS_BASE + reg) +#define REBASE_CH(reg, x) MMIO32(USB_OTG_FS_BASE + reg(x)) +#elif defined(USE_STM32F4_USBH_DRIVER_HS) +#define REBASE(reg) MMIO32(USB_OTG_HS_BASE + reg) +#define REBASE_CH(reg, x) MMIO32(USB_OTG_HS_BASE + reg(x)) +#endif + + +static void stm32f4_usbh_init(void *drvdata); +static enum USBH_POLL_STATUS stm32f4_usbh_poll(void *drvdata, uint32_t time_curr_us); +static void stm32f4_usbh_read(void *drvdata, usbh_packet_t *packet); +static void stm32f4_usbh_write(void *drvdata, const usbh_packet_t *packet); +uint8_t stm32f4_root_speed(void *drvdata); + +static int8_t get_free_channel(void *drvdata); +static void channels_init(void *drvdata); +static void rxflvl_handle(void *drvdata); +static void free_channel(void *drvdata, uint8_t channel); + +// USB Full Speed - OTG_FS +#if defined(USE_STM32F4_USBH_DRIVER_FS) +#define NUM_CHANNELS_FS (8) +static channel_t channels_fs[NUM_CHANNELS_FS]; +static usbh_lld_stm32f4_driver_data_t driver_data_fs = { + .base = USB_OTG_FS_BASE, + .channels = channels_fs, + .num_channels = NUM_CHANNELS_FS +}; +const usbh_driver_t stm32f4_usbh_driver_fs = { + .init = stm32f4_usbh_init, + .poll = stm32f4_usbh_poll, + .read = stm32f4_usbh_read, + .write = stm32f4_usbh_write, + .root_speed = stm32f4_root_speed, + .driver_data = &driver_data_fs +}; +#endif + +// USB High Speed - OTG_HS +#if defined(USE_STM32F4_USBH_DRIVER_HS) +#define NUM_CHANNELS_HS (12) +static channel_t channels_hs[NUM_CHANNELS_HS]; +static usbh_lld_stm32f4_driver_data_t driver_data_hs = { + .base = USB_OTG_HS_BASE, + .channels = channels_hs, + .num_channels = NUM_CHANNELS_HS +}; +const usbh_driver_t stm32f4_usbh_driver_hs = { + .init = stm32f4_usbh_init, + .poll = stm32f4_usbh_poll, + .read = stm32f4_usbh_read, + .write = stm32f4_usbh_write, + .root_speed = stm32f4_root_speed, + .driver_data = &driver_data_hs +}; +#endif + + + +static inline void reset_start(usbh_lld_stm32f4_driver_data_t *dev) +{ + + // apply reset condition on port + REBASE(OTG_HPRT) |= OTG_HPRT_PRST; + + // push current state to stack + dev->state_prev = dev->state; + + // move to new state + dev->state = DEVICE_STATE_RESET; + + // schedule disable reset condition after ~10ms + dev->timestamp_us = dev->time_curr_us; +} + +/** + * Should be nonblocking + * + */ +static void stm32f4_usbh_init(void *drvdata) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + dev->state = DEVICE_STATE_INIT; + dev->poll_sequence = 0; + dev->timestamp_us = dev->time_curr_us; + + //Disable interrupts first + REBASE(OTG_GAHBCFG) &= ~OTG_GAHBCFG_GINT; + + // Select full speed phy + REBASE(OTG_GUSBCFG) |= OTG_GUSBCFG_PHYSEL; +} + +static void stm32f4_usbh_port_channel_setup( + void *drvdata, uint32_t channel, uint32_t address, + uint32_t eptyp, uint32_t epnum, uint32_t epdir, + uint32_t max_packet_size) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + channel_t *channels = dev->channels; + + // TODO: maybe to function + switch (eptyp) { + case USBH_EPTYP_CONTROL: + eptyp = OTG_HCCHAR_EPTYP_CONTROL; + break; + case USBH_EPTYP_BULK: + eptyp = OTG_HCCHAR_EPTYP_BULK; + break; + case USBH_EPTYP_INTERRUPT: + eptyp = OTG_HCCHAR_EPTYP_INTERRUPT; + break; + case USBH_EPTYP_ISOCHRONOUS: + eptyp = OTG_HCCHAR_EPTYP_ISOCHRONOUS; + break; + } + + uint32_t speed = 0; + if (channels[channel].packet.speed == USBH_SPEED_LOW) { + speed = OTG_HCCHAR_LSDEV; + } + + REBASE_CH(OTG_HCCHAR, channel) = OTG_HCCHAR_CHENA | + (OTG_HCCHAR_DAD_MASK & (address << 22)) | + OTG_HCCHAR_MCNT_1 | + (OTG_HCCHAR_EPTYP_MASK & (eptyp << 18)) | + (speed) | + (epdir) | + (OTG_HCCHAR_EPNUM_MASK & (epnum << 11) )| + (OTG_HCCHAR_MPSIZ_MASK & max_packet_size); + +} + + +/** + * TODO: Check for maximum datalength + */ +static void stm32f4_usbh_read(void *drvdata, usbh_packet_t *packet) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + channel_t *channels = dev->channels; + + int8_t channel = get_free_channel(dev); + if (channel == -1) { + // BIG PROBLEM + LOG_PRINTF("FATAL ERROR IN, NO CHANNEL LEFT \r\n"); + usbh_packet_callback_data_t cb_data; + cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL; + cb_data.transferred_length = 0; + packet->callback(packet->callback_arg, cb_data); + return; + } + + channels[channel].data_index = 0; + channels[channel].packet = *packet; + + uint32_t dpid; + if (packet->toggle[0]) { + dpid = OTG_HCTSIZ_DPID_DATA1; + } else { + dpid = OTG_HCTSIZ_DPID_DATA0; + } + + uint32_t num_packets; + if (packet->datalen) { + num_packets = ((packet->datalen - 1) / packet->endpoint_size_max) + 1; + } else { + num_packets = 0; + } + + REBASE_CH(OTG_HCTSIZ, channel) = dpid | (num_packets << 19) | packet->datalen; + + stm32f4_usbh_port_channel_setup(dev, channel, + packet->address, + packet->endpoint_type, + packet->endpoint_address, + OTG_HCCHAR_EPDIR_IN, + packet->endpoint_size_max); +} + +/** + * + * Bug: datalen > max_packet_size ... + */ +static void stm32f4_usbh_write(void *drvdata, const usbh_packet_t *packet) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + channel_t *channels = dev->channels; + + int8_t channel = get_free_channel(dev); + + if (channel == -1) { + // BIG PROBLEM + LOG_PRINTF("FATAL ERROR OUT, NO CHANNEL LEFT \r\n"); + usbh_packet_callback_data_t cb_data; + cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL; + cb_data.transferred_length = 0; + packet->callback(packet->callback_arg, cb_data); + return; + } + + channels[channel].data_index = 0; + channels[channel].packet = *packet; + + uint32_t dpid; + if (packet->endpoint_type == USBH_EPTYP_CONTROL) { + dpid = OTG_HCTSIZ_DPID_MDATA; + packet->toggle[0] = 0; + } else if(packet->endpoint_type == USBH_EPTYP_INTERRUPT) { + if (packet->toggle[0]) { + dpid = OTG_HCTSIZ_DPID_DATA1; + } else { + dpid = OTG_HCTSIZ_DPID_DATA0; + } + } else if (packet->endpoint_type == USBH_EPTYP_BULK) { + if (packet->toggle[0]) { + dpid = OTG_HCTSIZ_DPID_DATA1; + } else { + dpid = OTG_HCTSIZ_DPID_DATA0; + } + } else { + dpid = OTG_HCTSIZ_DPID_DATA0; // ! TODO: BUG + LOG_PRINTF("BUG, %d",__LINE__); + } + + uint32_t num_packets; + if (packet->datalen) { + num_packets = ((packet->datalen - 1) / packet->endpoint_size_max) + 1; + } else { + num_packets = 1; + } + REBASE_CH(OTG_HCTSIZ, channel) = dpid | (num_packets << 19) | packet->datalen; + + stm32f4_usbh_port_channel_setup(dev, channel, + packet->address, + packet->endpoint_type, + packet->endpoint_address, + OTG_HCCHAR_EPDIR_OUT, + packet->endpoint_size_max); + + if (packet->endpoint_type == USBH_EPTYP_CONTROL || + packet->endpoint_type == USBH_EPTYP_BULK) { + + volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + RX_FIFO_SIZE; + const uint32_t * buf32 = packet->data; + uint32_t i; + for(i = packet->datalen; i > 0; i-=4) { + *fifo++ = *buf32++; + } + } else { + volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + + RX_FIFO_SIZE + TX_NP_FIFO_SIZE; + const uint32_t * buf32 = packet->data; + uint32_t i; + for(i = packet->datalen; i > 0; i-=4) { + *fifo++ = *buf32++; + } + } + LOG_PRINTF("->WRITE %08X\r\n", REBASE_CH(OTG_HCCHAR, channel)); +} + +static void rxflvl_handle(void *drvdata) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + channel_t *channels = dev->channels; + uint32_t rxstsp = REBASE(OTG_GRXSTSP); + uint8_t channel = rxstsp&0xf; + uint32_t len = (rxstsp>>4) & 0x1ff; + if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_IN) { + uint8_t *data = channels[channel].packet.data; + uint32_t *buf32 = (uint32_t *)&data[channels[channel].data_index]; + + int32_t i; + uint32_t extra; + if (!len) { + return; + } + // Receive data from fifo + volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel); + for (i = len; i > 4; i -= 4) { + *buf32++ = *fifo++; + } + extra = *fifo; + + memcpy(buf32, &extra, i); + channels[channel].data_index += len; + + // If transfer not complete, Enable channel to continue + if ( channels[channel].data_index < channels[channel].packet.datalen) { + if (len == channels[channel].packet.endpoint_size_max) { + REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHENA; + LOG_PRINTF("CHENA[%d/%d] ", channels[channel].data_index, channels[channel].packet.datalen); + } + + } + + } else if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_IN_COMP) { +#ifdef USART_DEBUG + uint32_t i; + LOG_PRINTF("\r\nDATA: "); + for (i = 0; i < channels[channel].data_index; i++) { + uint8_t *data = channels[channel].packet.data; + LOG_PRINTF("%02X ", data[i]); + } +#endif + } else if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_CHH) { + + } else { + + } +} + + +static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev) +{ + channel_t *channels = dev->channels; + + if (dev->dpstate == DEVICE_POLL_STATE_DISCONN) { + REBASE(OTG_GINTSTS) = REBASE(OTG_GINTSTS); + // Check for connection of device + if ((REBASE(OTG_HPRT) & OTG_HPRT_PCDET) && + (REBASE(OTG_HPRT) & OTG_HPRT_PCSTS) ) { + + dev->dpstate = DEVICE_POLL_STATE_DEVCONN; + dev->timestamp_us = dev->time_curr_us; + return USBH_POLL_STATUS_NONE; + } + } + + if (dev->dpstate == DEVICE_POLL_STATE_DEVCONN) { + // May be other condition, e.g. Debounce done, + // using 0.5s wait by default + if (dev->time_curr_us - dev->timestamp_us < 500000) { + return USBH_POLL_STATUS_NONE; + } + + if ((REBASE(OTG_HPRT) & OTG_HPRT_PCDET) && + (REBASE(OTG_HPRT) & OTG_HPRT_PCSTS) ) { + if ((REBASE(OTG_HPRT) & OTG_HPRT_PSPD_MASK) == OTG_HPRT_PSPD_FULL) { + REBASE(OTG_HFIR) = (REBASE(OTG_HFIR) & ~OTG_HFIR_FRIVL_MASK) | 48000; + if ((REBASE(OTG_HCFG) & OTG_HCFG_FSLSPCS_MASK) != OTG_HCFG_FSLSPCS_48MHz) { + REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) | OTG_HCFG_FSLSPCS_48MHz; + LOG_PRINTF("\r\n Reset Full-Speed \r\n"); + } + channels_init(dev); + dev->dpstate = DEVICE_POLL_STATE_DEVRST; + reset_start(dev); + + } else if ((REBASE(OTG_HPRT) & OTG_HPRT_PSPD_MASK) == OTG_HPRT_PSPD_LOW) { + REBASE(OTG_HFIR) = (REBASE(OTG_HFIR) & ~OTG_HFIR_FRIVL_MASK) | 6000; + if ((REBASE(OTG_HCFG) & OTG_HCFG_FSLSPCS_MASK) != OTG_HCFG_FSLSPCS_6MHz) { + REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) | OTG_HCFG_FSLSPCS_6MHz; + LOG_PRINTF("\r\n Reset Low-Speed \r\n"); + } + + channels_init(dev); + dev->dpstate = DEVICE_POLL_STATE_DEVRST; + reset_start(dev); + } + return USBH_POLL_STATUS_NONE; + } + } + + if (dev->dpstate == DEVICE_POLL_STATE_DEVRST) { + if (dev->time_curr_us - dev->timestamp_us < 210000) { + return USBH_POLL_STATUS_NONE; + } else { + dev->dpstate = DEVICE_POLL_STATE_RUN; + } + } + + // ELSE RUN + + if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_SOF) { + REBASE(OTG_GINTSTS) = OTG_GINTSTS_SOF; + } + + while (REBASE(OTG_GINTSTS) & OTG_GINTSTS_RXFLVL) { + //receive data + rxflvl_handle(dev); + } + + if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_HPRTINT) { + if (REBASE(OTG_HPRT) & OTG_HPRT_PENCHNG) { + uint32_t hprt = REBASE(OTG_HPRT); + // Clear Interrupt + // HARDWARE BUG - not mentioned in errata + // To clear interrupt write 0 to PENA + // To disable port write 1 to PENCHNG + REBASE(OTG_HPRT) &= ~OTG_HPRT_PENA; + LOG_PRINTF("PENCHNG"); + if ((hprt & OTG_HPRT_PENA)) { + return USBH_POLL_STATUS_DEVICE_CONNECTED; + } + + } + + if (REBASE(OTG_HPRT) & OTG_HPRT_POCCHNG) { + // TODO: Check for functionality + REBASE(OTG_HPRT) |= OTG_HPRT_POCCHNG; + LOG_PRINTF("POCCHNG"); + } + } + + if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_DISCINT) { + REBASE(OTG_GINTSTS) = OTG_GINTSTS_DISCINT; + LOG_PRINTF("DISCINT"); + + /* + * When the voltage drops, DISCINT interrupt is generated although + * Device is connected, so there is no need to reinitialize channels. + * Often, DISCINT is bad interpreted upon insertion of device + */ + if (!(REBASE(OTG_HPRT) & OTG_HPRT_PCSTS)) { + LOG_PRINTF("discint processsing..."); + channels_init(dev); + } + REBASE(OTG_GINTSTS) = REBASE(OTG_GINTSTS); + dev->dpstate = DEVICE_POLL_STATE_DISCONN; + return USBH_POLL_STATUS_DEVICE_DISCONNECTED; + } + + if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_HCINT) { + uint32_t channel; + + for(channel = 0; channel < dev->num_channels; channel++) + { + if (channels[channel].state != CHANNEL_STATE_WORK || + !(REBASE(OTG_HAINT)&(1<poll_sequence) { + case 0:// wait until AHBIDL is set + if (REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_AHBIDL) { + done = 1; + } + break; + + case 1:// wait 1ms and issue core soft reset + + // needs delay to not hang?? Do not know why. + // Maybe after AHBIDL is set, it needs to set up some things + if (dev->time_curr_us - dev->timestamp_us > 1000) { + REBASE(OTG_GRSTCTL) |= OTG_GRSTCTL_CSRST; + done = 1; + } + break; + + case 2:// wait until core soft reset processing is done + if (!(REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_CSRST)) { + done = 1; + } + break; + + case 3:// wait for 50ms + if (dev->time_curr_us - dev->timestamp_us > 50000) { + done = 1; + } + break; + + case 4:// wait until AHBIDL is set and power up the USB + if (REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_AHBIDL) { + REBASE(OTG_GCCFG) = OTG_GCCFG_VBUSASEN | OTG_GCCFG_VBUSBSEN | + OTG_GCCFG_NOVBUSSENS | OTG_GCCFG_PWRDWN; + done = 1; + } + break; + + case 5:// wait for 50ms and force host only mode + if (dev->time_curr_us - dev->timestamp_us > 50000) { + + // Core initialized + // Force host only mode. + REBASE(OTG_GUSBCFG) |= OTG_GUSBCFG_FHMOD; + done = 1; + } + break; + + case 6:// wait for 200ms and reset PHY clock start reset processing + if (dev->time_curr_us - dev->timestamp_us > 200000) { + /* Restart the PHY clock. */ + REBASE(OTG_PCGCCTL) = 0; + + REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) | + OTG_HCFG_FSLSPCS_48MHz; + + // Start reset processing + REBASE(OTG_HPRT) |= OTG_HPRT_PRST; + + done = 1; + + } + break; + + case 7:// wait for reset processing to be done(12ms), disable PRST + if (dev->time_curr_us - dev->timestamp_us > 12000) { + + REBASE(OTG_HPRT) &= ~OTG_HPRT_PRST; + done = 1; + } + break; + + case 8:// wait 12ms after PRST was disabled, configure fifo + if (dev->time_curr_us - dev->timestamp_us > 12000) { + + REBASE(OTG_HCFG) &= ~OTG_HCFG_FSLSS; + + REBASE(OTG_GRXFSIZ) = RX_FIFO_SIZE; + REBASE(OTG_GNPTXFSIZ) = (TX_NP_FIFO_SIZE << 16) | + RX_FIFO_SIZE; + REBASE(OTG_HPTXFSIZ) = (TX_P_FIFO_SIZE << 16) | + (RX_FIFO_SIZE + TX_NP_FIFO_SIZE); + + // FLUSH RX FIFO + REBASE(OTG_GRSTCTL) |= OTG_GRSTCTL_RXFFLSH; + + done = 1; + } + break; + + case 9: // wait to RX FIFO become flushed, flush TX + if (!(REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_RXFFLSH)) { + REBASE(OTG_GRSTCTL) |= OTG_GRSTCTL_TXFFLSH | (0x10 << 6); + + done = 1; + } + break; + + case 10: // wait to TX FIFO become flushed + if (!(REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_TXFFLSH)) { + + channels_init(dev); + + REBASE(OTG_GOTGINT) |= 1 << 19; + REBASE(OTG_GINTMSK) = 0; + REBASE(OTG_GINTSTS) = ~0; + REBASE(OTG_HPRT) |= OTG_HPRT_PPWR; + + done = 1; + } + break; + + case 11: // wait 200ms + if (dev->time_curr_us - dev->timestamp_us > 200000) { + + // Uncomment to enable Interrupt generation + REBASE(OTG_GAHBCFG) |= OTG_GAHBCFG_GINT; + + LOG_PRINTF("INIT COMPLETE\r\n"); + + // Finish + dev->state = DEVICE_STATE_RUN; + dev->dpstate = DEVICE_POLL_STATE_DISCONN; + + done = 1; + } + } + + if (done) { + dev->poll_sequence++; + dev->timestamp_us = dev->time_curr_us; + LOG_PRINTF("\t\t POLL SEQUENCE %d\r\n", dev->poll_sequence); + } + +} + +static void poll_reset(usbh_lld_stm32f4_driver_data_t *dev) +{ + if (dev->time_curr_us - dev->timestamp_us > 10000) { + REBASE(OTG_HPRT) &= ~OTG_HPRT_PRST; + dev->state = dev->state_prev; + dev->state_prev = DEVICE_STATE_RESET; + + LOG_PRINTF("RESET"); + } else { + LOG_PRINTF("waiting %d < %d\r\n",dev->time_curr_us, dev->timestamp_us); + } +} + +static enum USBH_POLL_STATUS stm32f4_usbh_poll(void *drvdata, uint32_t time_curr_us) +{ + + (void)time_curr_us; + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + uint32_t ret = ret = USBH_POLL_STATUS_NONE; + + // TODO: Check overflow case + dev->time_curr_us = time_curr_us; + + switch (dev->state) { + case DEVICE_STATE_RUN: + ret = poll_run(dev); + break; + + case DEVICE_STATE_INIT: + poll_init(dev); + break; + + case DEVICE_STATE_RESET: + poll_reset(dev); + break; + default: + break; + } + + return ret; + +} + + +/** + * + * Returns positive free channel id + * otherwise -1 for error + */ +static int8_t get_free_channel(void *drvdata) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + channel_t *channels = dev->channels; + uint32_t i = 0; + for (i = 0; i < dev->num_channels; i++) { + if (dev->channels[i].state == CHANNEL_STATE_FREE && + !(REBASE_CH(OTG_HCCHAR, i) & OTG_HCCHAR_CHENA)) { + channels[i].state = CHANNEL_STATE_WORK; + REBASE_CH(OTG_HCINT, i) = ~0; + REBASE_CH(OTG_HCINTMSK, i) |= OTG_HCINTMSK_ACKM | OTG_HCINTMSK_NAKM | + OTG_HCINTMSK_TXERRM | OTG_HCINTMSK_XFRCM | + OTG_HCINTMSK_DTERRM | OTG_HCINTMSK_BBERRM | + OTG_HCINTMSK_CHHM | OTG_HCINTMSK_STALLM | + OTG_HCINTMSK_FRMORM; + REBASE(OTG_HAINTMSK) |= (1 << i); + dev->channels[i].error_count = 0; + return i; + } + } + return -1; +} + +/* + * Do not clear callback and callback data, so channel can be freed even before callback is called + * This saves number of active channels: When one transfer ends, in callback driver can write/read to this channel again (indirectly) + */ +static void free_channel(void *drvdata, uint8_t channel) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + channel_t *channels = dev->channels; + + if (REBASE_CH(OTG_HCCHAR, channel) & OTG_HCCHAR_CHENA) { + REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHDIS; + REBASE_CH(OTG_HCINT, channel) = ~0; + LOG_PRINTF("\r\nDisabling channel %d\r\n", channel); + } else { + channels[channel].state = CHANNEL_STATE_FREE; + } +} +/** + * Init channels + */ +static void channels_init(void *drvdata) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + + uint32_t i = 0; + for (i = 0; i < dev->num_channels; i++) { + REBASE_CH(OTG_HCINT, i) = ~0; + REBASE_CH(OTG_HCINTMSK, i) = 0x7ff; + free_channel(dev, i); + } + + // Enable interrupt mask bits for all channels + REBASE(OTG_HAINTMSK) = (1 << dev->num_channels) - 1; +} + +/** + * Get speed of connected device + * + */ +uint8_t stm32f4_root_speed(void *drvdata) +{ + usbh_lld_stm32f4_driver_data_t *dev = drvdata; + (void)dev; + uint32_t hprt_speed = REBASE(OTG_HPRT) & OTG_HPRT_PSPD_MASK; + if (hprt_speed == OTG_HPRT_PSPD_LOW) { + return USBH_SPEED_LOW; + } else if(hprt_speed == OTG_HPRT_PSPD_FULL) { + return USBH_SPEED_FULL; + } else if(hprt_speed == OTG_HPRT_PSPD_HIGH) { + return USBH_SPEED_HIGH; + } else { + // Should not happen(let the compiler be happy) + return USBH_SPEED_FULL; + } +} +#endif // if defined otg_hs or otg_fs + + +#ifdef USART_DEBUG + +/** + * Just for debug + */ +void print_channels(const void *lld) +{ + usbh_lld_stm32f4_driver_data_t *dev = ((usbh_driver_t *)lld)->driver_data; + channel_t *channels = dev->channels; + int32_t i; + LOG_PRINTF("\r\nCHANNELS: \r\n"); + for (i = 0;i < dev->num_channels;i++) { + LOG_PRINTF("%4d %4d %4d %08X\r\n", channels[i].state, channels[i].packet.address, channels[i].packet.datalen, MMIO32(dev->base + OTG_HCINT(i))); + } +} +#endif + + +const void *usbh_lld_stm32f4_drivers[] = { +#if defined(USE_STM32F4_USBH_DRIVER_FS) + &stm32f4_usbh_driver_fs, +#endif + +#if defined(USE_STM32F4_USBH_DRIVER_HS) + &stm32f4_usbh_driver_hs, +#endif + 0 +}; -- cgit From c6aa4d99c23c605b116ffa6492852f953e717705 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 1 Apr 2015 18:05:00 +0200 Subject: demo: rcc_peripheral_enable_clock->rcc_periph_clock_enable Instead of 2 argument call, use function with one argument. It is more clear, and safer for inexperienced users with libopencm3. Signed-off-by: Amir Hammad --- src/demo.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/demo.c b/src/demo.c index f4ef456..34c2f5b 100644 --- a/src/demo.c +++ b/src/demo.c @@ -52,15 +52,15 @@ static void clock_setup(void) rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]); // GPIO - rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); // OTG_FS + button - rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN); // OTG_HS - rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPCEN); // USART + OTG_FS charge pump - rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN); // LEDS + rcc_periph_clock_enable(RCC_GPIOA); // OTG_FS + button + rcc_periph_clock_enable(RCC_GPIOB); // OTG_HS + rcc_periph_clock_enable(RCC_GPIOC); // USART + OTG_FS charge pump + rcc_periph_clock_enable(RCC_GPIOD); // LEDS // periphery - rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_USART6EN);// USART - rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); - rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_OTGHSEN); + rcc_periph_clock_enable(RCC_USART6); // USART + rcc_periph_clock_enable(RCC_OTGFS); // OTG_FS + rcc_periph_clock_enable(RCC_OTGHS); // OTG_HS } static void gpio_setup(void) -- cgit From e9c2632a199e26e9dac54984bf5e2b25bf13738c Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 1 Apr 2015 18:23:59 +0200 Subject: lld: stm32f4: poll(): fix return value Signed-off-by: Amir Hammad --- src/usbh_lld_stm32f4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 6cf6015..ad14d2e 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -903,12 +903,11 @@ static void poll_reset(usbh_lld_stm32f4_driver_data_t *dev) static enum USBH_POLL_STATUS stm32f4_usbh_poll(void *drvdata, uint32_t time_curr_us) { - (void)time_curr_us; + usbh_lld_stm32f4_driver_data_t *dev = drvdata; - uint32_t ret = ret = USBH_POLL_STATUS_NONE; + enum USBH_POLL_STATUS ret = USBH_POLL_STATUS_NONE; - // TODO: Check overflow case dev->time_curr_us = time_curr_us; switch (dev->state) { @@ -923,6 +922,7 @@ static enum USBH_POLL_STATUS stm32f4_usbh_poll(void *drvdata, uint32_t time_curr case DEVICE_STATE_RESET: poll_reset(dev); break; + default: break; } -- cgit From e35c1e9fc68dbbf870cbfd1213f0194869bcb14d Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 1 Apr 2015 18:29:32 +0200 Subject: poll(): refactor every poll argument t_us and tflp -> time_curr_us added comment to usbh_hubbed.h Signed-off-by: Amir Hammad --- include/driver/usbh_device_driver.h | 2 +- include/usbh_hubbed.h | 13 +++++++++++-- src/usbh_driver_gp_xbox.c | 11 ++++++----- src/usbh_driver_hid_mouse.c | 12 ++++++------ src/usbh_driver_hub.c | 6 +++--- src/usbh_hubbed.c | 6 +++--- 6 files changed, 30 insertions(+), 20 deletions(-) diff --git a/include/driver/usbh_device_driver.h b/include/driver/usbh_device_driver.h index f8837e0..137b39b 100644 --- a/include/driver/usbh_device_driver.h +++ b/include/driver/usbh_device_driver.h @@ -91,7 +91,7 @@ struct _usbh_driver { void (*init)(void *drvdata); void (*write)(void *drvdata, const usbh_packet_t *packet); void (*read)(void *drvdata, usbh_packet_t *packet); - enum USBH_POLL_STATUS (*poll)(void *drvdata, uint32_t t_us); + enum USBH_POLL_STATUS (*poll)(void *drvdata, uint32_t time_curr_us); uint8_t (*root_speed)(void *drvdata); // Pointer to Low-level driver data diff --git a/include/usbh_hubbed.h b/include/usbh_hubbed.h index 00d3b99..1b6b49a 100644 --- a/include/usbh_hubbed.h +++ b/include/usbh_hubbed.h @@ -62,14 +62,23 @@ typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t; struct _usbh_dev_driver { bool (*analyze_descriptor)(void *drv, void *descriptor); void *(*init)(void *usbh_dev); - void (*poll)(void *drvdata, uint32_t t_us); + void (*poll)(void *drvdata, uint32_t time_curr_us); void (*remove)(void *drvdata); const usbh_dev_driver_info_t * const info; }; typedef struct _usbh_dev_driver usbh_dev_driver_t; void usbh_init(const void *drivers[], const usbh_dev_driver_t * const device_drivers[]); -void usbh_poll(uint32_t t_us); + +/** + * \brief usbh_poll + * \param time_curr_us - use monotically rising time + * + * time_curr_us: + * * can overflow, in time of this writing, after 1s) + * * unit is microseconds + */ +void usbh_poll(uint32_t time_curr_us); END_DECLS diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index 52955d9..07eab38 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -30,7 +30,7 @@ static void *gp_xbox_init(void *usbh_dev); static bool gp_xbox_analyze_descriptor(void *drvdata, void *descriptor); -static void gp_xbox_poll(void *drvdata, uint32_t tflp); +static void gp_xbox_poll(void *drvdata, uint32_t time_curr_us); static void gp_xbox_remove(void *drvdata); static const usbh_dev_driver_info_t usbh_gp_xbox_driver_info = { @@ -367,12 +367,13 @@ static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox) } /** - * - * tflp time from last poll [us] + * \param time_curr_us - monotically rising time (see usbh_hubbed.h) + * unit is microseconds */ -static void gp_xbox_poll(void *drvdata, uint32_t tflp) +static void gp_xbox_poll(void *drvdata, uint32_t time_curr_us) { - (void)tflp; + (void)time_curr_us; + gp_xbox_device_t *gp_xbox = drvdata; usbh_device_t *dev = gp_xbox->usbh_device; diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 5c01451..6391ed7 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -29,7 +29,7 @@ static void *mouse_init(void *usbh_dev); static bool mouse_analyze_descriptor(void *drvdata, void *descriptor); -static void mouse_poll(void *drvdata, uint32_t tflp); +static void mouse_poll(void *drvdata, uint32_t time_curr_us); static void mouse_remove(void *drvdata); static const usbh_dev_driver_info_t usbh_hid_mouse_driver_info = { @@ -248,13 +248,13 @@ static void read_mouse_in(void *drvdata) } /** - * - * tflp time from last poll [us] + * \param time_curr_us - monotically rising time (see usbh_hubbed.h) + * unit is microseconds */ -static void mouse_poll(void *drvdata, uint32_t tflp) +static void mouse_poll(void *drvdata, uint32_t time_curr_us) { - (void)drvdata; - (void)tflp; + (void)time_curr_us; + hid_mouse_device_t *mouse = drvdata; usbh_device_t *dev = mouse->usbh_device; switch (mouse->state_next) { diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index c82eacd..a70e0c0 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -32,7 +32,7 @@ static hub_device_t hub_device[USBH_MAX_HUBS]; static void *hub_init(void *usbh_dev); static bool hub_analyze_descriptor(void *drvdata, void *descriptor); -static void hub_poll(void *drvdata, uint32_t tflp); +static void hub_poll(void *drvdata, uint32_t time_curr_us); static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data); static void hub_remove(void *drvdata); @@ -765,8 +765,8 @@ static void read_ep1(void *drvdata) } /** - * - * tflp time from last poll [ms] + * \param time_curr_us - monotically rising time (see usbh_hubbed.h) + * unit is microseconds */ static void hub_poll(void *drvdata, uint32_t time_curr_us) { diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index e935f99..b8fb97c 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -568,7 +568,7 @@ void device_enumeration_start(usbh_device_t *dev) * Should be called with at least 1kHz frequency * */ -void usbh_poll(uint32_t t_us) +void usbh_poll(uint32_t time_curr_us) { uint32_t k = 0; while (usbh_data.lld_drivers[k]) { @@ -577,7 +577,7 @@ void usbh_poll(uint32_t t_us) usbh_generic_data_t *lld_data = usbh_data.lld_drivers[k]->driver_data; enum USBH_POLL_STATUS poll_status = - usbh_data.lld_drivers[k]->poll(lld_data, t_us); + usbh_data.lld_drivers[k]->poll(lld_data, time_curr_us); switch (poll_status) { case USBH_POLL_STATUS_DEVICE_CONNECTED: @@ -613,7 +613,7 @@ void usbh_poll(uint32_t t_us) } if (lld_data->usbh_device[0].drv && usbh_device[0].drvdata) { - usbh_device[0].drv->poll(usbh_device[0].drvdata, t_us); + usbh_device[0].drv->poll(usbh_device[0].drvdata, time_curr_us); } k++; -- cgit From ae3449a302ba199f24810f1f8e9352cf121d2183 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 1 Apr 2015 19:08:53 +0200 Subject: demo: More precise timing, using TIM6 Overflows in 6.5536 seconds Signed-off-by: Amir Hammad --- src/demo.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/demo.c b/src/demo.c index 34c2f5b..d1f2d84 100644 --- a/src/demo.c +++ b/src/demo.c @@ -39,6 +39,7 @@ #include #include + static inline void delay_ms_busy_loop(uint32_t ms) { volatile uint32_t i; @@ -61,6 +62,29 @@ static void clock_setup(void) rcc_periph_clock_enable(RCC_USART6); // USART rcc_periph_clock_enable(RCC_OTGFS); // OTG_FS rcc_periph_clock_enable(RCC_OTGHS); // OTG_HS + rcc_periph_clock_enable(RCC_TIM6); // TIM6 +} + + +/* + * setup 10kHz timer + */ +static void tim6_setup(void) +{ + timer_reset(TIM6); + timer_set_prescaler(TIM6, 16800 - 1); // 168Mhz/10000hz - 1 + timer_set_period(TIM6, 65535); // Overflow in ~6.5 seconds + timer_enable_counter(TIM6); +} + +static uint32_t tim6_get_time_us(void) +{ + uint32_t cnt = timer_get_counter(TIM6); + + // convert to 1MHz less precise timer value -> units: microseconds + uint32_t time_us = cnt * 100; + + return time_us; } static void gpio_setup(void) @@ -140,6 +164,9 @@ int main(void) clock_setup(); gpio_setup(); + // provides time_curr_us to usbh_poll function + tim6_setup(); + #ifdef USART_DEBUG usart_init(USART6, 921600); #endif @@ -168,18 +195,23 @@ int main(void) LOG_PRINTF("USB init complete\r\n"); - uint32_t i = 0; + LOG_FLUSH(); while (1) { - LOG_FLUSH(); - - // Toggle some led + // set busy led gpio_set(GPIOD, GPIO14); - usbh_poll(i); + + uint32_t time_curr_us = tim6_get_time_us(); + + usbh_poll(time_curr_us); + + // clear busy led gpio_clear(GPIOD, GPIO14); + LOG_FLUSH(); + + // approx 1ms interval between usbh_poll() delay_ms_busy_loop(1); - i += 1000; } return 0; -- cgit From 0da537ec692ae3fa79a9ca61a8b3f3e9fe059021 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Sun, 5 Apr 2015 11:52:38 +0200 Subject: Device driver/hid_mouse: Bugfix enum STATES fixing after enum STATES refactor. Signed-off-by: Amir Hammad --- src/usbh_driver_hid_mouse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 6391ed7..1797cd7 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -187,7 +187,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) LOG_PRINTF("|empty packet read|"); switch (cb_data.status) { case USBH_PACKET_CALLBACK_STATUS_OK: - mouse->state_next++; + mouse->state_next = STATE_SET_CONFIGURATION_COMPLETE; device_xfer_control_read(0, 0, event, dev); break; @@ -274,7 +274,7 @@ static void mouse_poll(void *drvdata, uint32_t time_curr_us) setup_data.wIndex = 0; setup_data.wLength = 0; - mouse->state_next++; + mouse->state_next = STATE_SET_CONFIGURATION_EMPTY_READ; device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } -- cgit From efa0baa458ba609e9e2fc116d4fe57f39d72eba9 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Sun, 5 Apr 2015 12:14:47 +0200 Subject: use stdbool.h to define bool type Signed-off-by: Amir Hammad --- include/usbh_hubbed.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/include/usbh_hubbed.h b/include/usbh_hubbed.h index 1b6b49a..3125165 100644 --- a/include/usbh_hubbed.h +++ b/include/usbh_hubbed.h @@ -26,6 +26,7 @@ #include "usbh_config.h" #include +#include /* This must be placed around external function declaration for C++ * support. */ @@ -39,13 +40,6 @@ BEGIN_DECLS -#ifndef bool -#define bool _Bool -#define false 0 -#define true 1 -#endif - - // set to -1 to unused items struct _usbh_dev_driver_info { int32_t deviceClass; -- cgit From e31939e22fd87182ef496565eea4c241fb1387f9 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Sun, 5 Apr 2015 13:27:44 +0200 Subject: usbh_hubbed: reorder items in _usbh_dev_driver struct Signed-off-by: Amir Hammad --- include/usbh_hubbed.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/usbh_hubbed.h b/include/usbh_hubbed.h index 3125165..f99108d 100644 --- a/include/usbh_hubbed.h +++ b/include/usbh_hubbed.h @@ -54,8 +54,8 @@ struct _usbh_dev_driver_info { typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t; struct _usbh_dev_driver { - bool (*analyze_descriptor)(void *drv, void *descriptor); void *(*init)(void *usbh_dev); + bool (*analyze_descriptor)(void *drv, void *descriptor); void (*poll)(void *drvdata, uint32_t time_curr_us); void (*remove)(void *drvdata); const usbh_dev_driver_info_t * const info; -- cgit From f86aacc59c2e1ba483c848f794fce877490ba460 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Sun, 5 Apr 2015 18:54:10 +0200 Subject: Refactor device drivers: don't use automatic casts Signed-off-by: Amir Hammad --- src/usbh_driver_gp_xbox.c | 10 +++++----- src/usbh_driver_hid_mouse.c | 10 +++++----- src/usbh_driver_hub.c | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index 07eab38..9115f0b 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -115,7 +115,7 @@ static void *gp_xbox_init(void *usbh_dev) drvdata->device_id = i; drvdata->endpoint_in_address = 0; drvdata->endpoint_in_toggle = 0; - drvdata->usbh_device = usbh_dev; + drvdata->usbh_device = (usbh_device_t *)usbh_dev; break; } } @@ -128,7 +128,7 @@ static void *gp_xbox_init(void *usbh_dev) */ static bool gp_xbox_analyze_descriptor(void *drvdata, void *descriptor) { - gp_xbox_device_t *gp_xbox = drvdata; + gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)drvdata; uint8_t desc_type = ((uint8_t *)descriptor)[1]; switch (desc_type) { case USB_DT_CONFIGURATION: @@ -171,7 +171,7 @@ static bool gp_xbox_analyze_descriptor(void *drvdata, void *descriptor) static void parse_data(usbh_device_t *dev) { - gp_xbox_device_t *gp_xbox = dev->drvdata; + gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)dev->drvdata; uint8_t *packet = gp_xbox->buffer; @@ -266,7 +266,7 @@ static void parse_data(usbh_device_t *dev) static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) { - gp_xbox_device_t *gp_xbox = dev->drvdata; + gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)dev->drvdata; switch (gp_xbox->state_next) { case STATE_READING_COMPLETE: { @@ -374,7 +374,7 @@ static void gp_xbox_poll(void *drvdata, uint32_t time_curr_us) { (void)time_curr_us; - gp_xbox_device_t *gp_xbox = drvdata; + gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)drvdata; usbh_device_t *dev = gp_xbox->usbh_device; switch (gp_xbox->state_next) { diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 1797cd7..782cac5 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -107,7 +107,7 @@ static void *mouse_init(void *usbh_dev) drvdata->device_id = i; drvdata->endpoint_in_address = 0; drvdata->endpoint_in_toggle = 0; - drvdata->usbh_device = usbh_dev; + drvdata->usbh_device = (usbh_device_t *)usbh_dev; break; } } @@ -120,7 +120,7 @@ static void *mouse_init(void *usbh_dev) */ static bool mouse_analyze_descriptor(void *drvdata, void *descriptor) { - hid_mouse_device_t *mouse = drvdata; + hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata; uint8_t desc_type = ((uint8_t *)descriptor)[1]; switch (desc_type) { case USB_DT_CONFIGURATION: @@ -163,7 +163,7 @@ static bool mouse_analyze_descriptor(void *drvdata, void *descriptor) static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) { - hid_mouse_device_t *mouse = dev->drvdata; + hid_mouse_device_t *mouse = (hid_mouse_device_t *)dev->drvdata; switch (mouse->state_next) { case STATE_READING_COMPLETE: { @@ -226,7 +226,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) static void read_mouse_in(void *drvdata) { - hid_mouse_device_t *mouse = drvdata; + hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata; usbh_packet_t packet; packet.address = mouse->usbh_device->address; @@ -255,7 +255,7 @@ static void mouse_poll(void *drvdata, uint32_t time_curr_us) { (void)time_curr_us; - hid_mouse_device_t *mouse = drvdata; + hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata; usbh_device_t *dev = mouse->usbh_device; switch (mouse->state_next) { case STATE_READING_REQUEST: diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index a70e0c0..c8c7ee9 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -93,7 +93,7 @@ static void *hub_init(void *usbh_dev) drvdata = &hub_device[i]; drvdata->state = 0; drvdata->ports_num = 0; - drvdata->device[0] = usbh_dev; + drvdata->device[0] = (usbh_device_t *)usbh_dev; drvdata->busy = 0; drvdata->endpoint_in_address = 0; drvdata->endpoint_in_maxpacketsize = 0; @@ -110,7 +110,7 @@ static void *hub_init(void *usbh_dev) */ static bool hub_analyze_descriptor(void *drvdata, void *descriptor) { - hub_device_t *hub = drvdata; + hub_device_t *hub = (hub_device_t *)drvdata; uint8_t desc_type = ((uint8_t *)descriptor)[1]; switch (desc_type) { case USB_DT_CONFIGURATION: @@ -165,7 +165,7 @@ static bool hub_analyze_descriptor(void *drvdata, void *descriptor) static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) { //~ usbh_device_t *dev = arg; - hub_device_t *hub = dev->drvdata; + hub_device_t *hub = (hub_device_t *)dev->drvdata; LOG_PRINTF("\r\nHUB->STATE = %d\r\n", hub->state); switch (hub->state) { @@ -744,7 +744,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) static void read_ep1(void *drvdata) { - hub_device_t *hub = drvdata; + hub_device_t *hub = (hub_device_t *)drvdata; usbh_packet_t packet; packet.address = hub->device[0]->address; @@ -770,7 +770,7 @@ static void read_ep1(void *drvdata) */ static void hub_poll(void *drvdata, uint32_t time_curr_us) { - hub_device_t *hub = drvdata; + hub_device_t *hub = (hub_device_t *)drvdata; usbh_device_t *dev = hub->device[0]; hub->time_curr_us = time_curr_us; @@ -840,7 +840,7 @@ static void hub_poll(void *drvdata, uint32_t time_curr_us) } static void hub_remove(void *drvdata) { - hub_device_t *hub = drvdata; + hub_device_t *hub = (hub_device_t *)drvdata; uint8_t i; // Call fast... to avoid polling -- cgit From 0827b6982bb67136c7a3c1bd1d4b0ba1924efbb7 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 6 Apr 2015 16:01:20 +0200 Subject: LLD: stm32f4: change type of i to signed integer this was causing infinite loop, when size of the data was not multiple of 4. Signed-off-by: Amir Hammad --- src/usbh_lld_stm32f4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index ad14d2e..4ee9d77 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -341,15 +341,16 @@ static void stm32f4_usbh_write(void *drvdata, const usbh_packet_t *packet) volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + RX_FIFO_SIZE; const uint32_t * buf32 = packet->data; - uint32_t i; + int i; for(i = packet->datalen; i > 0; i-=4) { *fifo++ = *buf32++; } + } else { volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + RX_FIFO_SIZE + TX_NP_FIFO_SIZE; const uint32_t * buf32 = packet->data; - uint32_t i; + int i; for(i = packet->datalen; i > 0; i-=4) { *fifo++ = *buf32++; } -- cgit From 5622fb0fdae5d1039108848ab98d5060fe3244d4 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Tue, 7 Apr 2015 19:17:54 +0200 Subject: usbh_hubbed: device_register: Don't check for USB_DT_DEVICE twice Signed-off-by: Amir Hammad --- src/usbh_hubbed.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index b8fb97c..85051a8 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -115,15 +115,6 @@ static void device_register(void *descriptors, uint16_t descriptors_len, usbh_de desc_len = buf[i]; desc_type = buf[i + 1]; switch (desc_type) { - case USB_DT_DEVICE: - { - struct usb_device_descriptor *device_desc = (void*)&buf[i]; - LOG_PRINTF("DEVICE DESCRIPTOR"); - device_info.deviceClass = device_desc->bDeviceClass; - device_info.deviceSubClass = device_desc->bDeviceSubClass; - } - break; - case USB_DT_INTERFACE: { LOG_PRINTF("INTERFACE_DESCRIPTOR\r\n"); -- cgit From 7503fd901abe55078209d9bc822ff9e7a6c56215 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 8 Apr 2015 07:50:31 +0200 Subject: lld: stm32f4: Move driver definitions to the end of file This way, we don't need forward declarations Signed-off-by: Amir Hammad --- src/usbh_lld_stm32f4.c | 85 ++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 4ee9d77..fc59dd1 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -38,9 +38,6 @@ /* Transmit periodic FIFO size in 32-bit words. */ #define TX_P_FIFO_SIZE (64) - - - enum CHANNEL_STATE { CHANNEL_STATE_FREE = 0, CHANNEL_STATE_WORK = 1 @@ -103,55 +100,12 @@ typedef struct _usbh_lld_stm32f4_driver_data usbh_lld_stm32f4_driver_data_t; #define REBASE_CH(reg, x) MMIO32(USB_OTG_HS_BASE + reg(x)) #endif - -static void stm32f4_usbh_init(void *drvdata); -static enum USBH_POLL_STATUS stm32f4_usbh_poll(void *drvdata, uint32_t time_curr_us); -static void stm32f4_usbh_read(void *drvdata, usbh_packet_t *packet); -static void stm32f4_usbh_write(void *drvdata, const usbh_packet_t *packet); -uint8_t stm32f4_root_speed(void *drvdata); - static int8_t get_free_channel(void *drvdata); static void channels_init(void *drvdata); static void rxflvl_handle(void *drvdata); static void free_channel(void *drvdata, uint8_t channel); -// USB Full Speed - OTG_FS -#if defined(USE_STM32F4_USBH_DRIVER_FS) -#define NUM_CHANNELS_FS (8) -static channel_t channels_fs[NUM_CHANNELS_FS]; -static usbh_lld_stm32f4_driver_data_t driver_data_fs = { - .base = USB_OTG_FS_BASE, - .channels = channels_fs, - .num_channels = NUM_CHANNELS_FS -}; -const usbh_driver_t stm32f4_usbh_driver_fs = { - .init = stm32f4_usbh_init, - .poll = stm32f4_usbh_poll, - .read = stm32f4_usbh_read, - .write = stm32f4_usbh_write, - .root_speed = stm32f4_root_speed, - .driver_data = &driver_data_fs -}; -#endif -// USB High Speed - OTG_HS -#if defined(USE_STM32F4_USBH_DRIVER_HS) -#define NUM_CHANNELS_HS (12) -static channel_t channels_hs[NUM_CHANNELS_HS]; -static usbh_lld_stm32f4_driver_data_t driver_data_hs = { - .base = USB_OTG_HS_BASE, - .channels = channels_hs, - .num_channels = NUM_CHANNELS_HS -}; -const usbh_driver_t stm32f4_usbh_driver_hs = { - .init = stm32f4_usbh_init, - .poll = stm32f4_usbh_poll, - .read = stm32f4_usbh_read, - .write = stm32f4_usbh_write, - .root_speed = stm32f4_root_speed, - .driver_data = &driver_data_hs -}; -#endif @@ -1000,7 +954,7 @@ static void channels_init(void *drvdata) * Get speed of connected device * */ -uint8_t stm32f4_root_speed(void *drvdata) +static uint8_t stm32f4_root_speed(void *drvdata) { usbh_lld_stm32f4_driver_data_t *dev = drvdata; (void)dev; @@ -1036,6 +990,43 @@ void print_channels(const void *lld) } #endif +// USB Full Speed - OTG_FS +#if defined(USE_STM32F4_USBH_DRIVER_FS) +#define NUM_CHANNELS_FS (8) +static channel_t channels_fs[NUM_CHANNELS_FS]; +static usbh_lld_stm32f4_driver_data_t driver_data_fs = { + .base = USB_OTG_FS_BASE, + .channels = channels_fs, + .num_channels = NUM_CHANNELS_FS +}; +const usbh_driver_t stm32f4_usbh_driver_fs = { + .init = stm32f4_usbh_init, + .poll = stm32f4_usbh_poll, + .read = stm32f4_usbh_read, + .write = stm32f4_usbh_write, + .root_speed = stm32f4_root_speed, + .driver_data = &driver_data_fs +}; +#endif + +// USB High Speed - OTG_HS +#if defined(USE_STM32F4_USBH_DRIVER_HS) +#define NUM_CHANNELS_HS (12) +static channel_t channels_hs[NUM_CHANNELS_HS]; +static usbh_lld_stm32f4_driver_data_t driver_data_hs = { + .base = USB_OTG_HS_BASE, + .channels = channels_hs, + .num_channels = NUM_CHANNELS_HS +}; +const usbh_driver_t stm32f4_usbh_driver_hs = { + .init = stm32f4_usbh_init, + .poll = stm32f4_usbh_poll, + .read = stm32f4_usbh_read, + .write = stm32f4_usbh_write, + .root_speed = stm32f4_root_speed, + .driver_data = &driver_data_hs +}; +#endif const void *usbh_lld_stm32f4_drivers[] = { #if defined(USE_STM32F4_USBH_DRIVER_FS) -- cgit From ba197f8007901be20620935b614f68798dd23f26 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 8 Apr 2015 08:08:34 +0200 Subject: lld: stm32f4: refactor: Remove prefixes of static functions and variables Signed-off-by: Amir Hammad --- src/usbh_lld_stm32f4.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index fc59dd1..429e57e 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -129,7 +129,7 @@ static inline void reset_start(usbh_lld_stm32f4_driver_data_t *dev) * Should be nonblocking * */ -static void stm32f4_usbh_init(void *drvdata) +static void init(void *drvdata) { usbh_lld_stm32f4_driver_data_t *dev = drvdata; dev->state = DEVICE_STATE_INIT; @@ -187,7 +187,7 @@ static void stm32f4_usbh_port_channel_setup( /** * TODO: Check for maximum datalength */ -static void stm32f4_usbh_read(void *drvdata, usbh_packet_t *packet) +static void read(void *drvdata, usbh_packet_t *packet) { usbh_lld_stm32f4_driver_data_t *dev = drvdata; channel_t *channels = dev->channels; @@ -234,7 +234,7 @@ static void stm32f4_usbh_read(void *drvdata, usbh_packet_t *packet) * * Bug: datalen > max_packet_size ... */ -static void stm32f4_usbh_write(void *drvdata, const usbh_packet_t *packet) +static void write(void *drvdata, const usbh_packet_t *packet) { usbh_lld_stm32f4_driver_data_t *dev = drvdata; channel_t *channels = dev->channels; @@ -856,7 +856,7 @@ static void poll_reset(usbh_lld_stm32f4_driver_data_t *dev) } } -static enum USBH_POLL_STATUS stm32f4_usbh_poll(void *drvdata, uint32_t time_curr_us) +static enum USBH_POLL_STATUS poll(void *drvdata, uint32_t time_curr_us) { (void)time_curr_us; @@ -954,7 +954,7 @@ static void channels_init(void *drvdata) * Get speed of connected device * */ -static uint8_t stm32f4_root_speed(void *drvdata) +static uint8_t root_speed(void *drvdata) { usbh_lld_stm32f4_driver_data_t *dev = drvdata; (void)dev; @@ -999,12 +999,12 @@ static usbh_lld_stm32f4_driver_data_t driver_data_fs = { .channels = channels_fs, .num_channels = NUM_CHANNELS_FS }; -const usbh_driver_t stm32f4_usbh_driver_fs = { - .init = stm32f4_usbh_init, - .poll = stm32f4_usbh_poll, - .read = stm32f4_usbh_read, - .write = stm32f4_usbh_write, - .root_speed = stm32f4_root_speed, +static const usbh_driver_t driver_fs = { + .init = init, + .poll = poll, + .read = read, + .write = write, + .root_speed = root_speed, .driver_data = &driver_data_fs }; #endif @@ -1018,23 +1018,23 @@ static usbh_lld_stm32f4_driver_data_t driver_data_hs = { .channels = channels_hs, .num_channels = NUM_CHANNELS_HS }; -const usbh_driver_t stm32f4_usbh_driver_hs = { - .init = stm32f4_usbh_init, - .poll = stm32f4_usbh_poll, - .read = stm32f4_usbh_read, - .write = stm32f4_usbh_write, - .root_speed = stm32f4_root_speed, +static const usbh_driver_t driver_hs = { + .init = init, + .poll = poll, + .read = read, + .write = write, + .root_speed = root_speed, .driver_data = &driver_data_hs }; #endif const void *usbh_lld_stm32f4_drivers[] = { #if defined(USE_STM32F4_USBH_DRIVER_FS) - &stm32f4_usbh_driver_fs, + &driver_fs, #endif #if defined(USE_STM32F4_USBH_DRIVER_HS) - &stm32f4_usbh_driver_hs, + &driver_hs, #endif 0 }; -- cgit From 6625cda9f3eea899c41d1ee5b14913e691075e8a Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 8 Apr 2015 08:04:27 +0200 Subject: Device drivers: Refactor: Move driver declaration to the end of file forward declarations are not needed Signed-off-by: Amir Hammad --- src/usbh_driver_gp_xbox.c | 43 +++++++++++++++++++------------------------ src/usbh_driver_hid_mouse.c | 43 +++++++++++++++++++------------------------ src/usbh_driver_hub.c | 43 +++++++++++++++++++------------------------ 3 files changed, 57 insertions(+), 72 deletions(-) diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index 9115f0b..f742246 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -28,30 +28,6 @@ #include #include -static void *gp_xbox_init(void *usbh_dev); -static bool gp_xbox_analyze_descriptor(void *drvdata, void *descriptor); -static void gp_xbox_poll(void *drvdata, uint32_t time_curr_us); -static void gp_xbox_remove(void *drvdata); - -static const usbh_dev_driver_info_t usbh_gp_xbox_driver_info = { - .deviceClass = 0xff, - .deviceSubClass = 0xff, - .deviceProtocol = 0xff, - .idVendor = 0x045e, - .idProduct = 0x028e, - .ifaceClass = 0xff, - .ifaceSubClass = 93, - .ifaceProtocol = 0x01 -}; - -const usbh_dev_driver_t usbh_gp_xbox_driver = { - .init = gp_xbox_init, - .analyze_descriptor = gp_xbox_analyze_descriptor, - .poll = gp_xbox_poll, - .remove = gp_xbox_remove, - .info = &usbh_gp_xbox_driver_info -}; - enum STATES { STATE_INACTIVE, STATE_READING_COMPLETE, @@ -419,3 +395,22 @@ static void gp_xbox_remove(void *drvdata) gp_xbox->state_next = STATE_INACTIVE; gp_xbox->endpoint_in_address = 0; } + +static const usbh_dev_driver_info_t usbh_gp_xbox_driver_info = { + .deviceClass = 0xff, + .deviceSubClass = 0xff, + .deviceProtocol = 0xff, + .idVendor = 0x045e, + .idProduct = 0x028e, + .ifaceClass = 0xff, + .ifaceSubClass = 93, + .ifaceProtocol = 0x01 +}; + +const usbh_dev_driver_t usbh_gp_xbox_driver = { + .init = gp_xbox_init, + .analyze_descriptor = gp_xbox_analyze_descriptor, + .poll = gp_xbox_poll, + .remove = gp_xbox_remove, + .info = &usbh_gp_xbox_driver_info +}; diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 782cac5..0435138 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -27,30 +27,6 @@ #include -static void *mouse_init(void *usbh_dev); -static bool mouse_analyze_descriptor(void *drvdata, void *descriptor); -static void mouse_poll(void *drvdata, uint32_t time_curr_us); -static void mouse_remove(void *drvdata); - -static const usbh_dev_driver_info_t usbh_hid_mouse_driver_info = { - .deviceClass = -1, - .deviceSubClass = -1, - .deviceProtocol = -1, - .idVendor = -1, - .idProduct = -1, - .ifaceClass = 0x03, - .ifaceSubClass = -1, - .ifaceProtocol = 0x02 -}; - -const usbh_dev_driver_t usbh_hid_mouse_driver = { - .init = mouse_init, - .analyze_descriptor = mouse_analyze_descriptor, - .poll = mouse_poll, - .remove = mouse_remove, - .info = &usbh_hid_mouse_driver_info -}; - enum STATES { STATE_INACTIVE, STATE_READING_COMPLETE, @@ -292,3 +268,22 @@ static void mouse_remove(void *drvdata) mouse->state_next = STATE_INACTIVE; mouse->endpoint_in_address = 0; } + +static const usbh_dev_driver_info_t usbh_hid_mouse_driver_info = { + .deviceClass = -1, + .deviceSubClass = -1, + .deviceProtocol = -1, + .idVendor = -1, + .idProduct = -1, + .ifaceClass = 0x03, + .ifaceSubClass = -1, + .ifaceProtocol = 0x02 +}; + +const usbh_dev_driver_t usbh_hid_mouse_driver = { + .init = mouse_init, + .analyze_descriptor = mouse_analyze_descriptor, + .poll = mouse_poll, + .remove = mouse_remove, + .info = &usbh_hid_mouse_driver_info +}; diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index c8c7ee9..fab946d 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -29,31 +29,7 @@ static hub_device_t hub_device[USBH_MAX_HUBS]; - -static void *hub_init(void *usbh_dev); -static bool hub_analyze_descriptor(void *drvdata, void *descriptor); -static void hub_poll(void *drvdata, uint32_t time_curr_us); static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data); -static void hub_remove(void *drvdata); - -static const usbh_dev_driver_info_t usbh_hub_driver_info = { - .deviceClass = 0x09, - .deviceSubClass = -1, - .deviceProtocol = -1, - .idVendor = -1, - .idProduct = -1, - .ifaceClass = 0x09, - .ifaceSubClass = -1, - .ifaceProtocol = -1 -}; - -const usbh_dev_driver_t usbh_hub_driver = { - .init = hub_init, - .analyze_descriptor = hub_analyze_descriptor, - .poll = hub_poll, - .remove = hub_remove, - .info = &usbh_hub_driver_info -}; @@ -863,3 +839,22 @@ static void hub_remove(void *drvdata) } } + +static const usbh_dev_driver_info_t usbh_hub_driver_info = { + .deviceClass = 0x09, + .deviceSubClass = -1, + .deviceProtocol = -1, + .idVendor = -1, + .idProduct = -1, + .ifaceClass = 0x09, + .ifaceSubClass = -1, + .ifaceProtocol = -1 +}; + +const usbh_dev_driver_t usbh_hub_driver = { + .init = hub_init, + .analyze_descriptor = hub_analyze_descriptor, + .poll = hub_poll, + .remove = hub_remove, + .info = &usbh_hub_driver_info +}; -- cgit From 187d01e3b299465d94de2ad44437cb8e1b5afcbb Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 8 Apr 2015 08:07:43 +0200 Subject: Device drivers: Refactor: Remove prefixes of static functions and variables Signed-off-by: Amir Hammad --- src/usbh_driver_gp_xbox.c | 20 ++++++++++---------- src/usbh_driver_hid_mouse.c | 20 ++++++++++---------- src/usbh_driver_hub.c | 22 +++++++++++----------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index f742246..a2390bd 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -74,7 +74,7 @@ void gp_xbox_driver_init(const gp_xbox_config_t *config) * * */ -static void *gp_xbox_init(void *usbh_dev) +static void *init(void *usbh_dev) { if (!initialized) { LOG_PRINTF("driver not initialized"); @@ -102,7 +102,7 @@ static void *gp_xbox_init(void *usbh_dev) /** * Returns true if all needed data are parsed */ -static bool gp_xbox_analyze_descriptor(void *drvdata, void *descriptor) +static bool analyze_descriptor(void *drvdata, void *descriptor) { gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)drvdata; uint8_t desc_type = ((uint8_t *)descriptor)[1]; @@ -346,7 +346,7 @@ static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox) * \param time_curr_us - monotically rising time (see usbh_hubbed.h) * unit is microseconds */ -static void gp_xbox_poll(void *drvdata, uint32_t time_curr_us) +static void poll(void *drvdata, uint32_t time_curr_us) { (void)time_curr_us; @@ -384,7 +384,7 @@ static void gp_xbox_poll(void *drvdata, uint32_t time_curr_us) } } -static void gp_xbox_remove(void *drvdata) +static void remove(void *drvdata) { LOG_PRINTF("Removing xbox\r\n"); @@ -396,7 +396,7 @@ static void gp_xbox_remove(void *drvdata) gp_xbox->endpoint_in_address = 0; } -static const usbh_dev_driver_info_t usbh_gp_xbox_driver_info = { +static const usbh_dev_driver_info_t driver_info = { .deviceClass = 0xff, .deviceSubClass = 0xff, .deviceProtocol = 0xff, @@ -408,9 +408,9 @@ static const usbh_dev_driver_info_t usbh_gp_xbox_driver_info = { }; const usbh_dev_driver_t usbh_gp_xbox_driver = { - .init = gp_xbox_init, - .analyze_descriptor = gp_xbox_analyze_descriptor, - .poll = gp_xbox_poll, - .remove = gp_xbox_remove, - .info = &usbh_gp_xbox_driver_info + .init = init, + .analyze_descriptor = analyze_descriptor, + .poll = poll, + .remove = remove, + .info = &driver_info }; diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 0435138..2afa084 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -71,7 +71,7 @@ void hid_mouse_driver_init(const hid_mouse_config_t *config) * * */ -static void *mouse_init(void *usbh_dev) +static void *init(void *usbh_dev) { uint32_t i; hid_mouse_device_t *drvdata = 0; @@ -94,7 +94,7 @@ static void *mouse_init(void *usbh_dev) /** * Returns true if all needed data are parsed */ -static bool mouse_analyze_descriptor(void *drvdata, void *descriptor) +static bool analyze_descriptor(void *drvdata, void *descriptor) { hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata; uint8_t desc_type = ((uint8_t *)descriptor)[1]; @@ -227,7 +227,7 @@ static void read_mouse_in(void *drvdata) * \param time_curr_us - monotically rising time (see usbh_hubbed.h) * unit is microseconds */ -static void mouse_poll(void *drvdata, uint32_t time_curr_us) +static void poll(void *drvdata, uint32_t time_curr_us) { (void)time_curr_us; @@ -262,14 +262,14 @@ static void mouse_poll(void *drvdata, uint32_t time_curr_us) } } -static void mouse_remove(void *drvdata) +static void remove(void *drvdata) { hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata; mouse->state_next = STATE_INACTIVE; mouse->endpoint_in_address = 0; } -static const usbh_dev_driver_info_t usbh_hid_mouse_driver_info = { +static const usbh_dev_driver_info_t driver_info = { .deviceClass = -1, .deviceSubClass = -1, .deviceProtocol = -1, @@ -281,9 +281,9 @@ static const usbh_dev_driver_info_t usbh_hid_mouse_driver_info = { }; const usbh_dev_driver_t usbh_hid_mouse_driver = { - .init = mouse_init, - .analyze_descriptor = mouse_analyze_descriptor, - .poll = mouse_poll, - .remove = mouse_remove, - .info = &usbh_hid_mouse_driver_info + .init = init, + .analyze_descriptor = analyze_descriptor, + .poll = poll, + .remove = remove, + .info = &driver_info }; diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index fab946d..9aa55be 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -49,7 +49,7 @@ void hub_driver_init(void) * * */ -static void *hub_init(void *usbh_dev) +static void *init(void *usbh_dev) { uint32_t i; hub_device_t *drvdata = 0; @@ -84,7 +84,7 @@ static void *hub_init(void *usbh_dev) /** * Returns true if all needed data are parsed */ -static bool hub_analyze_descriptor(void *drvdata, void *descriptor) +static bool analyze_descriptor(void *drvdata, void *descriptor) { hub_device_t *hub = (hub_device_t *)drvdata; uint8_t desc_type = ((uint8_t *)descriptor)[1]; @@ -744,7 +744,7 @@ static void read_ep1(void *drvdata) * \param time_curr_us - monotically rising time (see usbh_hubbed.h) * unit is microseconds */ -static void hub_poll(void *drvdata, uint32_t time_curr_us) +static void poll(void *drvdata, uint32_t time_curr_us) { hub_device_t *hub = (hub_device_t *)drvdata; usbh_device_t *dev = hub->device[0]; @@ -814,7 +814,7 @@ static void hub_poll(void *drvdata, uint32_t time_curr_us) } } } -static void hub_remove(void *drvdata) +static void remove(void *drvdata) { hub_device_t *hub = (hub_device_t *)drvdata; uint8_t i; @@ -826,7 +826,7 @@ static void hub_remove(void *drvdata) for (i = 1; i < USBH_HUB_MAX_DEVICES + 1; i++) { if (hub->device[i]) { if (hub->device[i]->drv && hub->device[i]->drvdata) { - if (hub->device[i]->drv->remove != hub_remove) { + if (hub->device[i]->drv->remove != remove) { LOG_PRINTF("\t\t\t\tHUB REMOVE %d\r\n",hub->device[i]->address); hub->device[i]->drv->remove(hub->device[i]->drvdata); } @@ -840,7 +840,7 @@ static void hub_remove(void *drvdata) } } -static const usbh_dev_driver_info_t usbh_hub_driver_info = { +static const usbh_dev_driver_info_t driver_info = { .deviceClass = 0x09, .deviceSubClass = -1, .deviceProtocol = -1, @@ -852,9 +852,9 @@ static const usbh_dev_driver_info_t usbh_hub_driver_info = { }; const usbh_dev_driver_t usbh_hub_driver = { - .init = hub_init, - .analyze_descriptor = hub_analyze_descriptor, - .poll = hub_poll, - .remove = hub_remove, - .info = &usbh_hub_driver_info + .init = init, + .analyze_descriptor = analyze_descriptor, + .poll = poll, + .remove = remove, + .info = &driver_info }; -- cgit From 4b23cb4850aa8f7b8a2823d053dd9369f90c8a9e Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 15 Apr 2015 20:26:09 +0200 Subject: demo: timer: BUGFIX: TIM6 prescaler TIM6 has clock running at 84MHz instead of 168MHz, so set the prescaler accordingly. Signed-off-by: Amir Hammad --- src/demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/demo.c b/src/demo.c index d1f2d84..d4368c9 100644 --- a/src/demo.c +++ b/src/demo.c @@ -72,7 +72,7 @@ static void clock_setup(void) static void tim6_setup(void) { timer_reset(TIM6); - timer_set_prescaler(TIM6, 16800 - 1); // 168Mhz/10000hz - 1 + timer_set_prescaler(TIM6, 8400 - 1); // 84Mhz/10kHz - 1 timer_set_period(TIM6, 65535); // Overflow in ~6.5 seconds timer_enable_counter(TIM6); } -- cgit From 99f24e93899b0b0ccf74af4497dfba5839c162c8 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 13 Jul 2015 14:53:56 +0200 Subject: hub: Fix forgotten break Signed-off-by: Amir Hammad --- src/usbh_driver_hub.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index 9aa55be..ffc3dda 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -322,6 +322,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) } } break; + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: { LOG_PRINTF("->\t\t\t\t\t ERRSIZ: deschub\r\n"); @@ -345,6 +346,8 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) } } } + break; + case USBH_PACKET_CALLBACK_STATUS_EFATAL: case USBH_PACKET_CALLBACK_STATUS_EAGAIN: ERROR(cb_data.status); @@ -380,6 +383,8 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; event(dev, cb_data); } + break; + case USBH_PACKET_CALLBACK_STATUS_EFATAL: case USBH_PACKET_CALLBACK_STATUS_EAGAIN: case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: -- cgit From 0c04dcd6ef62e7e77fbac02d77832857bff7dbed Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 13 Jul 2015 14:48:37 +0200 Subject: usbh_hubbed: cleaning newlines after break; in switch Signed-off-by: Amir Hammad --- src/usbh_hubbed.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index 85051a8..039ccd5 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -305,6 +305,7 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ } } break; + case 2: switch (cb_data.status) { case USBH_PACKET_CALLBACK_STATUS_OK: @@ -405,6 +406,7 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ } } break; + case 5: { switch (cb_data.status) { -- cgit From 54f3b37a7176a905866085fb43276d8f1840f196 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 13 Jul 2015 14:50:44 +0200 Subject: usbh_hubbed: When in unknown state, print Error Signed-off-by: Amir Hammad --- src/usbh_hubbed.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index 039ccd5..0ebaf1c 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -519,6 +519,10 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ } break; + + default: + LOG_PRINTF("Error: Unknown state "__FILE__"/%d\n", __LINE__); + break; } if (state_start == dev->state) { -- cgit From 33856ce17ccc2a4c1041d456f6d9c86eed4b1105 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 13 Jul 2015 14:52:21 +0200 Subject: Global logging: use \n for a new line instead \r\n in LOG_PRINTF Signed-off-by: Amir Hammad --- src/demo.c | 8 +++---- src/usart_helpers.c | 6 +++--- src/usbh_driver_gp_xbox.c | 8 +++---- src/usbh_driver_hid_mouse.c | 4 ++-- src/usbh_driver_hub.c | 52 ++++++++++++++++++++++----------------------- src/usbh_hubbed.c | 30 +++++++++++++------------- src/usbh_lld_stm32f4.c | 24 ++++++++++----------- 7 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/demo.c b/src/demo.c index d4368c9..ec37781 100644 --- a/src/demo.c +++ b/src/demo.c @@ -124,7 +124,7 @@ static void gp_xbox_update(uint8_t device_id, gp_xbox_packet_t packet) { (void)device_id; (void)packet; - LOG_PRINTF("update %d: %d %d \r\n", device_id, packet.axis_left_x, packet.buttons & GP_XBOX_BUTTON_A); + LOG_PRINTF("update %d: %d %d \n", device_id, packet.axis_left_x, packet.buttons & GP_XBOX_BUTTON_A); } @@ -152,7 +152,7 @@ static void mouse_in_message_handler(uint8_t device_id, const uint8_t *data) (void)data; // print only first 4 bytes, since every mouse should have at least these four set. // Report descriptors are not read by driver for now, so we do not know what each byte means - LOG_PRINTF("MOUSE EVENT %02X %02X %02X %02X \r\n", data[0], data[1], data[2], data[3]); + LOG_PRINTF("MOUSE EVENT %02X %02X %02X %02X \n", data[0], data[1], data[2], data[3]); } static const hid_mouse_config_t mouse_config = { @@ -170,7 +170,7 @@ int main(void) #ifdef USART_DEBUG usart_init(USART6, 921600); #endif - LOG_PRINTF("\r\n\r\n\r\n\r\n\r\n###################\r\nInit\r\n"); + LOG_PRINTF("\n\n\n\n\n###################\nInit\n"); /** * device driver initialization @@ -193,7 +193,7 @@ int main(void) usbh_init(usbh_lld_stm32f4_drivers, device_drivers); gpio_clear(GPIOD, GPIO13); - LOG_PRINTF("USB init complete\r\n"); + LOG_PRINTF("USB init complete\n"); LOG_FLUSH(); diff --git a/src/usart_helpers.c b/src/usart_helpers.c index 31a7556..4469b44 100644 --- a/src/usart_helpers.c +++ b/src/usart_helpers.c @@ -180,7 +180,7 @@ void usart_interrupt(void) if ( data != 3 && data != '\r' && data != '\n') { usart_fifo_push(data); } else { - LOG_PRINTF("\r\n>>"); + LOG_PRINTF("\n>>"); } } } @@ -270,7 +270,7 @@ void usart_call_cmd(struct usart_commands * commands) commands[i].callback(&command[command_argindex]); } } - usart_write("\r\n>>",4); + usart_write("\n>>",4); command_len = 0; command_argindex = 0; return; @@ -281,7 +281,7 @@ void usart_call_cmd(struct usart_commands * commands) } command_len = 0; command_argindex = 0; - LOG_PRINTF("INVALID COMMAND\r\n>>"); + LOG_PRINTF("INVALID COMMAND\n>>"); } #endif diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index a2390bd..f1525c4 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -291,7 +291,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) case USBH_PACKET_CALLBACK_STATUS_OK: gp_xbox->state_next = STATE_READING_REQUEST; gp_xbox->endpoint_in_toggle = 0; - LOG_PRINTF("\r\ngp_xbox CONFIGURED\r\n"); + LOG_PRINTF("\ngp_xbox CONFIGURED\n"); if (gp_xbox_config->notify_connected) { gp_xbox_config->notify_connected(gp_xbox->device_id); } @@ -314,7 +314,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) break; default: { - LOG_PRINTF("Unknown state\r\n"); + LOG_PRINTF("Unknown state\n"); } break; } @@ -339,7 +339,7 @@ static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox) gp_xbox->state_next = STATE_READING_COMPLETE; usbh_read(gp_xbox->usbh_device, &packet); - // LOG_PRINTF("@gp_xbox EP1 | \r\n"); + // LOG_PRINTF("@gp_xbox EP1 | \n"); } /** @@ -386,7 +386,7 @@ static void poll(void *drvdata, uint32_t time_curr_us) static void remove(void *drvdata) { - LOG_PRINTF("Removing xbox\r\n"); + LOG_PRINTF("Removing xbox\n"); gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)drvdata; if (gp_xbox_config->notify_disconnected) { diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 2afa084..dc6ab84 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -182,7 +182,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) case USBH_PACKET_CALLBACK_STATUS_OK: mouse->state_next = STATE_READING_REQUEST; mouse->endpoint_in_toggle = 0; - LOG_PRINTF("\r\nMOUSE CONFIGURED\r\n"); + LOG_PRINTF("\nMOUSE CONFIGURED\n"); break; case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: @@ -219,7 +219,7 @@ static void read_mouse_in(void *drvdata) mouse->state_next = STATE_READING_COMPLETE; usbh_read(mouse->usbh_device, &packet); - // LOG_PRINTF("@MOUSE EP1 | \r\n"); + // LOG_PRINTF("@MOUSE EP1 | \n"); } diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index ffc3dda..266cd71 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -106,7 +106,7 @@ static bool analyze_descriptor(void *drvdata, void *descriptor) hub->endpoint_in_maxpacketsize = ep->wMaxPacketSize; } } - LOG_PRINTF("ENDPOINT DESCRIPTOR FOUND\r\n"); + LOG_PRINTF("ENDPOINT DESCRIPTOR FOUND\n"); } break; @@ -117,15 +117,15 @@ static bool analyze_descriptor(void *drvdata, void *descriptor) if ( desc->head.bNbrPorts <= USBH_HUB_MAX_DEVICES) { hub->ports_num = desc->head.bNbrPorts; } else { - LOG_PRINTF("INCREASE NUMBER OF ENABLED PORTS\r\n"); + LOG_PRINTF("INCREASE NUMBER OF ENABLED PORTS\n"); hub->ports_num = USBH_HUB_MAX_DEVICES; } - LOG_PRINTF("HUB DESCRIPTOR FOUND \r\n"); + LOG_PRINTF("HUB DESCRIPTOR FOUND \n"); } break; default: - LOG_PRINTF("TYPE: %02X \r\n",desc_type); + LOG_PRINTF("TYPE: %02X \n",desc_type); break; } @@ -143,7 +143,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) //~ usbh_device_t *dev = arg; hub_device_t *hub = (hub_device_t *)dev->drvdata; - LOG_PRINTF("\r\nHUB->STATE = %d\r\n", hub->state); + LOG_PRINTF("\nHUB->STATE = %d\n", hub->state); switch (hub->state) { case 26: switch (cb_data.status) { @@ -157,7 +157,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) } int8_t port = 0; - LOG_PRINTF("psc:%d\r\n",psc); + LOG_PRINTF("psc:%d\n",psc); // Driver error... port not found if (!psc) { // Continue reading status change endpoint @@ -197,7 +197,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) hub->state = 31; hub->current_port = port; - LOG_PRINTF("\r\n\r\nPORT FOUND: %d\r\n", port); + LOG_PRINTF("\n\nPORT FOUND: %d\n", port); device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } break; @@ -212,7 +212,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) // In case of EAGAIN error, retry read on status endpoint hub->state = 25; - LOG_PRINTF("HUB: Retrying...\r\n"); + LOG_PRINTF("HUB: Retrying...\n"); break; } break; @@ -242,7 +242,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) if (hub->ports_num) { hub->index = 0; hub->state = 6; - LOG_PRINTF("No need to get HUB DESC\r\n"); + LOG_PRINTF("No need to get HUB DESC\n"); event(dev, cb_data); } else { hub->endpoint_in_toggle = 0; @@ -258,7 +258,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) hub->state++; device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); - LOG_PRINTF("DO Need to get HUB DESC\r\n"); + LOG_PRINTF("DO Need to get HUB DESC\n"); } break; @@ -325,7 +325,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: { - LOG_PRINTF("->\t\t\t\t\t ERRSIZ: deschub\r\n"); + LOG_PRINTF("->\t\t\t\t\t ERRSIZ: deschub\n"); struct usb_hub_descriptor*hub_descriptor = (struct usb_hub_descriptor *)hub->buffer; @@ -335,7 +335,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) if ( hub_descriptor->head.bNbrPorts <= USBH_HUB_MAX_DEVICES) { hub->ports_num = hub_descriptor->head.bNbrPorts; } else { - LOG_PRINTF("INCREASE NUMBER OF ENABLED PORTS\r\n"); + LOG_PRINTF("INCREASE NUMBER OF ENABLED PORTS\n"); hub->ports_num = USBH_HUB_MAX_DEVICES; } hub->state++; @@ -378,7 +378,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) // Delay Based on hub descriptor field bPwr2PwrGood // delay_ms_busy_loop(200); - LOG_PRINTF("\r\nHUB CONFIGURED & PORTS POWERED\r\n"); + LOG_PRINTF("\nHUB CONFIGURED & PORTS POWERED\n"); cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; event(dev, cb_data); @@ -553,7 +553,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) // Check, whether device is in connected state if (!hub->device[port]) { if (!usbh_enum_available() || hub->busy) { - LOG_PRINTF("\r\n\t\t\tCannot enumerate %d %d\r\n", !usbh_enum_available(), hub->busy); + LOG_PRINTF("\n\t\t\tCannot enumerate %d %d\n", !usbh_enum_available(), hub->busy); hub->state = 25; break; } @@ -587,11 +587,11 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) LOG_PRINTF("RESET"); device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } else { - LOG_PRINTF("another STC %d\r\n", stc); + LOG_PRINTF("another STC %d\n", stc); } } else { hub->state = 25; - LOG_PRINTF("HUB status change\r\n"); + LOG_PRINTF("HUB status change\n"); } } break; @@ -630,7 +630,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } } else { - LOG_PRINTF("\t\t\t\tDISCONNECT EVENT\r\n"); + LOG_PRINTF("\t\t\t\tDISCONNECT EVENT\n"); if (hub->device[port]->drv && hub->device[port]->drvdata) { hub->device[port]->drv->remove(hub->device[port]->drvdata); } @@ -661,7 +661,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) switch (cb_data.status) { case USBH_PACKET_CALLBACK_STATUS_OK: { - LOG_PRINTF("\r\nPOLL\r\n"); + LOG_PRINTF("\nPOLL\n"); int8_t port = hub->current_port; uint16_t sts = hub->hub_and_port_status[port].sts; @@ -670,7 +670,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) hub->device[port] = usbh_get_free_device(dev); if (!hub->device[port]) { - LOG_PRINTF("\r\nFATAL ERROR\r\n"); + LOG_PRINTF("\nFATAL ERROR\n"); return;// DEAD END } if ((sts & (1<<(HUB_FEATURE_PORT_LOWSPEED))) && @@ -700,7 +700,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) } else { - LOG_PRINTF("%s:%d Do not know what to do, when device is disabled after reset\r\n", __FILE__, __LINE__); + LOG_PRINTF("%s:%d Do not know what to do, when device is disabled after reset\n", __FILE__, __LINE__); hub->state = 25; return; } @@ -718,7 +718,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) } break; default: - LOG_PRINTF("UNHANDLED EVENT %d\r\n",hub->state); + LOG_PRINTF("UNHANDLED EVENT %d\n",hub->state); break; } } @@ -741,7 +741,7 @@ static void read_ep1(void *drvdata) hub->state = 26; usbh_read(hub->device[0], &packet); - LOG_PRINTF("@hub %d/EP1 | \r\n", hub->device[0]->address); + LOG_PRINTF("@hub %d/EP1 | \n", hub->device[0]->address); } @@ -762,14 +762,14 @@ static void poll(void *drvdata, uint32_t time_curr_us) if (usbh_enum_available()) { read_ep1(hub); } else { - LOG_PRINTF("enum not available\r\n"); + LOG_PRINTF("enum not available\n"); } } break; case 1: { - LOG_PRINTF("CFGVAL: %d\r\n", hub->buffer[0]); + LOG_PRINTF("CFGVAL: %d\n", hub->buffer[0]); struct usb_setup_data setup_data; setup_data.bmRequestType = 0b00000000; @@ -787,7 +787,7 @@ static void poll(void *drvdata, uint32_t time_curr_us) if (hub->time_curr_us - hub->timestamp_us > 500000) { int8_t port = hub->current_port; LOG_PRINTF("PORT: %d", port); - LOG_PRINTF("\r\nNEW device at address: %d\r\n", hub->device[port]->address); + LOG_PRINTF("\nNEW device at address: %d\n", hub->device[port]->address); hub->device[port]->lld = hub->device[0]->lld; device_enumeration_start(hub->device[port]); @@ -832,7 +832,7 @@ static void remove(void *drvdata) if (hub->device[i]) { if (hub->device[i]->drv && hub->device[i]->drvdata) { if (hub->device[i]->drv->remove != remove) { - LOG_PRINTF("\t\t\t\tHUB REMOVE %d\r\n",hub->device[i]->address); + LOG_PRINTF("\t\t\t\tHUB REMOVE %d\n",hub->device[i]->address); hub->device[i]->drv->remove(hub->device[i]->drvdata); } } diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index 0ebaf1c..833e5a3 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -117,7 +117,7 @@ static void device_register(void *descriptors, uint16_t descriptors_len, usbh_de switch (desc_type) { case USB_DT_INTERFACE: { - LOG_PRINTF("INTERFACE_DESCRIPTOR\r\n"); + LOG_PRINTF("INTERFACE_DESCRIPTOR\n"); struct usb_interface_descriptor *iface = (void*)&buf[i]; device_info.ifaceClass = iface->bInterfaceClass; device_info.ifaceSubClass = iface->bInterfaceSubClass; @@ -138,7 +138,7 @@ static void device_register(void *descriptors, uint16_t descriptors_len, usbh_de } if (desc_len == 0) { - LOG_PRINTF("PROBLEM WITH PARSE %d\r\n",i); + LOG_PRINTF("PROBLEM WITH PARSE %d\n",i); return; } i += desc_len; @@ -154,13 +154,13 @@ static void device_register(void *descriptors, uint16_t descriptors_len, usbh_de void *drvdata = dev->drvdata; LOG_PRINTF("[%d]",buf[i+1]); if (dev->drv->analyze_descriptor(drvdata, &buf[i])) { - LOG_PRINTF("Device Initialized\r\n"); + LOG_PRINTF("Device Initialized\n"); return; } i += desc_len; } } - LOG_PRINTF("Device NOT Initialized\r\n"); + LOG_PRINTF("Device NOT Initialized\n"); } void usbh_init(const void *drivers_lld[], const usbh_dev_driver_t * const device_drivers[]) @@ -175,7 +175,7 @@ void usbh_init(const void *drivers_lld[], const usbh_dev_driver_t * const device // TODO: init structures uint32_t k = 0; while (usbh_data.lld_drivers[k]) { - LOG_PRINTF("DRIVER %d\r\n", k); + LOG_PRINTF("DRIVER %d\n", k); usbh_device_t * usbh_device = ((usbh_generic_data_t *)(usbh_data.lld_drivers[k])->driver_data)->usbh_device; @@ -214,7 +214,7 @@ void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callbac packet.toggle = &dev->toggle0; usbh_write(dev, &packet); - LOG_PRINTF("WR@device...%d | \r\n", dev->address); + LOG_PRINTF("WR@device...%d | \n", dev->address); } void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev) @@ -233,7 +233,7 @@ void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback packet.toggle = &dev->toggle0; usbh_read(dev, &packet); - LOG_PRINTF("RD@device...%d | \r\n", dev->address); + LOG_PRINTF("RD@device...%d | \n", dev->address); } @@ -254,14 +254,14 @@ usbh_device_t *usbh_get_free_device(const usbh_device_t *dev) usbh_device_t *usbh_device = lld_data->usbh_device; uint8_t i; - LOG_PRINTF("DEV ADDRESS%d\r\n", dev->address); + LOG_PRINTF("DEV ADDRESS%d\n", dev->address); for (i = 0; i < USBH_MAX_DEVICES; i++) { if (usbh_device[i].address < 0) { LOG_PRINTF("\t\t\t\t\tFOUND: %d", i); usbh_device[i].address = i+1; return &usbh_device[i]; } else { - LOG_PRINTF("address: %d\r\n\r\n\r\n", usbh_device[i].address); + LOG_PRINTF("address: %d\n\n\n", usbh_device[i].address); } } @@ -285,7 +285,7 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ usbh_generic_data_t *lld_data = lld->driver_data; uint8_t *usbh_buffer = lld_data->usbh_buffer; uint8_t state_start = dev->state; // Detection of hang -// LOG_PRINTF("\r\nSTATE: %d\r\n", state); +// LOG_PRINTF("\nSTATE: %d\n", state); switch (dev->state) { case 1: { @@ -311,7 +311,7 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ case USBH_PACKET_CALLBACK_STATUS_OK: if (dev->address == 0) { dev->address = usbh_data.address_temporary; - LOG_PRINTF("ADDR: %d\r\n", dev->address); + LOG_PRINTF("ADDR: %d\n", dev->address); } struct usb_setup_data setup_data; @@ -501,7 +501,7 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ { struct usb_config_descriptor *cdt = (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; - LOG_PRINTF("TOTAL_LENGTH: %d\r\n", cdt->wTotalLength); + LOG_PRINTF("TOTAL_LENGTH: %d\n", cdt->wTotalLength); device_register(usbh_buffer, cdt->wTotalLength + USB_DT_DEVICE_SIZE, dev); dev->state++; @@ -526,7 +526,7 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ } if (state_start == dev->state) { - LOG_PRINTF("\r\n !HANG %d\r\n", state_start); + LOG_PRINTF("\n !HANG %d\n", state_start); } } @@ -547,7 +547,7 @@ void device_enumeration_start(usbh_device_t *dev) usbh_data.address_temporary = address; - LOG_PRINTF("\r\n\r\n\r\n ENUMERATION OF DEVICE@%d STARTED \r\n\r\n", address); + LOG_PRINTF("\n\n\n ENUMERATION OF DEVICE@%d STARTED \n\n", address); struct usb_setup_data setup_data; @@ -579,7 +579,7 @@ void usbh_poll(uint32_t time_curr_us) switch (poll_status) { case USBH_POLL_STATUS_DEVICE_CONNECTED: // New device found - LOG_PRINTF("\r\nDEVICE FOUND\r\n"); + LOG_PRINTF("\nDEVICE FOUND\n"); usbh_device[0].lld = usbh_data.lld_drivers[k]; usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data); usbh_device[0].address = 1; diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 429e57e..817df2e 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -195,7 +195,7 @@ static void read(void *drvdata, usbh_packet_t *packet) int8_t channel = get_free_channel(dev); if (channel == -1) { // BIG PROBLEM - LOG_PRINTF("FATAL ERROR IN, NO CHANNEL LEFT \r\n"); + LOG_PRINTF("FATAL ERROR IN, NO CHANNEL LEFT \n"); usbh_packet_callback_data_t cb_data; cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL; cb_data.transferred_length = 0; @@ -243,7 +243,7 @@ static void write(void *drvdata, const usbh_packet_t *packet) if (channel == -1) { // BIG PROBLEM - LOG_PRINTF("FATAL ERROR OUT, NO CHANNEL LEFT \r\n"); + LOG_PRINTF("FATAL ERROR OUT, NO CHANNEL LEFT \n"); usbh_packet_callback_data_t cb_data; cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL; cb_data.transferred_length = 0; @@ -309,7 +309,7 @@ static void write(void *drvdata, const usbh_packet_t *packet) *fifo++ = *buf32++; } } - LOG_PRINTF("->WRITE %08X\r\n", REBASE_CH(OTG_HCCHAR, channel)); + LOG_PRINTF("->WRITE %08X\n", REBASE_CH(OTG_HCCHAR, channel)); } static void rxflvl_handle(void *drvdata) @@ -350,7 +350,7 @@ static void rxflvl_handle(void *drvdata) } else if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_IN_COMP) { #ifdef USART_DEBUG uint32_t i; - LOG_PRINTF("\r\nDATA: "); + LOG_PRINTF("\nDATA: "); for (i = 0; i < channels[channel].data_index; i++) { uint8_t *data = channels[channel].packet.data; LOG_PRINTF("%02X ", data[i]); @@ -393,7 +393,7 @@ static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev) REBASE(OTG_HFIR) = (REBASE(OTG_HFIR) & ~OTG_HFIR_FRIVL_MASK) | 48000; if ((REBASE(OTG_HCFG) & OTG_HCFG_FSLSPCS_MASK) != OTG_HCFG_FSLSPCS_48MHz) { REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) | OTG_HCFG_FSLSPCS_48MHz; - LOG_PRINTF("\r\n Reset Full-Speed \r\n"); + LOG_PRINTF("\n Reset Full-Speed \n"); } channels_init(dev); dev->dpstate = DEVICE_POLL_STATE_DEVRST; @@ -403,7 +403,7 @@ static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev) REBASE(OTG_HFIR) = (REBASE(OTG_HFIR) & ~OTG_HFIR_FRIVL_MASK) | 6000; if ((REBASE(OTG_HCFG) & OTG_HCFG_FSLSPCS_MASK) != OTG_HCFG_FSLSPCS_6MHz) { REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) | OTG_HCFG_FSLSPCS_6MHz; - LOG_PRINTF("\r\n Reset Low-Speed \r\n"); + LOG_PRINTF("\n Reset Low-Speed \n"); } channels_init(dev); @@ -825,7 +825,7 @@ static void poll_init(usbh_lld_stm32f4_driver_data_t *dev) // Uncomment to enable Interrupt generation REBASE(OTG_GAHBCFG) |= OTG_GAHBCFG_GINT; - LOG_PRINTF("INIT COMPLETE\r\n"); + LOG_PRINTF("INIT COMPLETE\n"); // Finish dev->state = DEVICE_STATE_RUN; @@ -838,7 +838,7 @@ static void poll_init(usbh_lld_stm32f4_driver_data_t *dev) if (done) { dev->poll_sequence++; dev->timestamp_us = dev->time_curr_us; - LOG_PRINTF("\t\t POLL SEQUENCE %d\r\n", dev->poll_sequence); + LOG_PRINTF("\t\t POLL SEQUENCE %d\n", dev->poll_sequence); } } @@ -852,7 +852,7 @@ static void poll_reset(usbh_lld_stm32f4_driver_data_t *dev) LOG_PRINTF("RESET"); } else { - LOG_PRINTF("waiting %d < %d\r\n",dev->time_curr_us, dev->timestamp_us); + LOG_PRINTF("waiting %d < %d\n",dev->time_curr_us, dev->timestamp_us); } } @@ -927,7 +927,7 @@ static void free_channel(void *drvdata, uint8_t channel) if (REBASE_CH(OTG_HCCHAR, channel) & OTG_HCCHAR_CHENA) { REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHDIS; REBASE_CH(OTG_HCINT, channel) = ~0; - LOG_PRINTF("\r\nDisabling channel %d\r\n", channel); + LOG_PRINTF("\nDisabling channel %d\n", channel); } else { channels[channel].state = CHANNEL_STATE_FREE; } @@ -983,9 +983,9 @@ void print_channels(const void *lld) usbh_lld_stm32f4_driver_data_t *dev = ((usbh_driver_t *)lld)->driver_data; channel_t *channels = dev->channels; int32_t i; - LOG_PRINTF("\r\nCHANNELS: \r\n"); + LOG_PRINTF("\nCHANNELS: \n"); for (i = 0;i < dev->num_channels;i++) { - LOG_PRINTF("%4d %4d %4d %08X\r\n", channels[i].state, channels[i].packet.address, channels[i].packet.datalen, MMIO32(dev->base + OTG_HCINT(i))); + LOG_PRINTF("%4d %4d %4d %08X\n", channels[i].state, channels[i].packet.address, channels[i].packet.datalen, MMIO32(dev->base + OTG_HCINT(i))); } } #endif -- cgit From 3003006216579428ee255073743321390400a8dc Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 13 Jul 2015 16:16:39 +0200 Subject: hub: Do not allow unitialized driver to be loaded Signed-off-by: Amir Hammad --- src/usbh_driver_hub.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index 266cd71..7678dd7 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -31,12 +31,14 @@ static hub_device_t hub_device[USBH_MAX_HUBS]; static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data); - +static bool initialized = false; void hub_driver_init(void) { uint32_t i; + initialized = true; + for (i = 0; i < USBH_MAX_HUBS; i++) { hub_device[i].device[0] = 0; hub_device[i].ports_num = 0; @@ -51,6 +53,11 @@ void hub_driver_init(void) */ static void *init(void *usbh_dev) { + if (!initialized) { + LOG_PRINTF("\n%s/%d : driver not initialized\r\n", __FILE__, __LINE__); + return 0; + } + uint32_t i; hub_device_t *drvdata = 0; // find free data space for hub device -- cgit From f8658f941129ab929baacf0e6c1b2092a387d132 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 13 Jul 2015 16:17:28 +0200 Subject: mouse: Do not allow unitialized driver to be loaded Signed-off-by: Amir Hammad --- src/usbh_driver_hid_mouse.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index dc6ab84..0a575f2 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -56,11 +56,14 @@ static const hid_mouse_config_t *mouse_config; #include - +static bool initialized = false; void hid_mouse_driver_init(const hid_mouse_config_t *config) { uint32_t i; + + initialized = true; + mouse_config = config; for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) { mouse_device[i].state_next = STATE_INACTIVE; @@ -73,6 +76,11 @@ void hid_mouse_driver_init(const hid_mouse_config_t *config) */ static void *init(void *usbh_dev) { + if (!initialized) { + LOG_PRINTF("\n%s/%d : driver not initialized\r\n", __FILE__, __LINE__); + return 0; + } + uint32_t i; hid_mouse_device_t *drvdata = 0; -- cgit From 09c861c97572de2302e294ae908225e89237c7ad Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 13 Jul 2015 16:18:03 +0200 Subject: gp_xbox: Do not allow unitialized driver to be loaded Signed-off-by: Amir Hammad --- src/usbh_driver_gp_xbox.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index f1525c4..1b1d895 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -77,8 +77,8 @@ void gp_xbox_driver_init(const gp_xbox_config_t *config) static void *init(void *usbh_dev) { if (!initialized) { - LOG_PRINTF("driver not initialized"); - return false; + LOG_PRINTF("\n%s/%d : driver not initialized\r\n", __FILE__, __LINE__); + return 0; } uint32_t i; -- cgit From 1566e7012f6b9b69b2a36808caca001d34bd536e Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 29 Jul 2015 18:18:44 +0200 Subject: hub: Empty packet readings after SET_ and CLEAR_ commands * fixed typo/bug: "hub->state += 2" must have been "hub->state = 2" to issue empty read Now, after each SET_ or CLEAR_ command, empty read is issued. + removed forward declaration of event() - cleaning Signed-off-by: Amir Hammad --- src/usbh_driver_hub.c | 30 +++++++++++++++++++++--------- src/usbh_driver_hub_private.h | 4 ++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index 7678dd7..305a8f3 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -29,7 +29,6 @@ static hub_device_t hub_device[USBH_MAX_HUBS]; -static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data); static bool initialized = false; @@ -224,19 +223,21 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) } break; - case 2: + case EMPTY_PACKET_READ_STATE: { LOG_PRINTF("|empty packet read|"); switch (cb_data.status) { case USBH_PACKET_CALLBACK_STATUS_OK: device_xfer_control_read(0, 0, event, dev); - hub->state++; + hub->state = hub->state_after_empty_read; + hub->state_after_empty_read = 0; break; case USBH_PACKET_CALLBACK_STATUS_EFATAL: case USBH_PACKET_CALLBACK_STATUS_EAGAIN: case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - ERROR(cb_data.status); + hub->state = hub->state_after_empty_read; + event(dev, cb_data); break; } } @@ -378,6 +379,9 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) setup_data.wIndex = hub->index; setup_data.wLength = 0; + hub->state_after_empty_read = hub->state; + hub->state = EMPTY_PACKET_READ_STATE; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } else { hub->state++; @@ -575,7 +579,9 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) setup_data.wIndex = port; setup_data.wLength = 0; - hub->state = 33; + hub->state_after_empty_read = 33; + hub->state = EMPTY_PACKET_READ_STATE; + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } else if(stc & (1<state = 35; + hub->state_after_empty_read = 35; + hub->state = EMPTY_PACKET_READ_STATE; LOG_PRINTF("RESET"); device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); @@ -630,7 +637,9 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) setup_data.wIndex = port; setup_data.wLength = 0; - hub->state = 11; + hub->state_after_empty_read = 11; + hub->state = EMPTY_PACKET_READ_STATE; + LOG_PRINTF("CONN"); hub->busy = 1; @@ -694,7 +703,9 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) setup_data.wLength = 0; // After write process another devices, poll for events - hub->state = 11;//Expecting all ports are powered (constant/non-changeable after init) + hub->state_after_empty_read = 11;//Expecting all ports are powered (constant/non-changeable after init) + hub->state = EMPTY_PACKET_READ_STATE; + hub->current_port = CURRENT_PORT_NONE; device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } else if (!(sts & (1<<(HUB_FEATURE_PORT_LOWSPEED))) && @@ -785,7 +796,8 @@ static void poll(void *drvdata, uint32_t time_curr_us) setup_data.wIndex = 0; setup_data.wLength = 0; - hub->state += 2; + hub->state = EMPTY_PACKET_READ_STATE; + hub->state_after_empty_read = 3; device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); } diff --git a/src/usbh_driver_hub_private.h b/src/usbh_driver_hub_private.h index 4b98880..df38243 100644 --- a/src/usbh_driver_hub_private.h +++ b/src/usbh_driver_hub_private.h @@ -61,6 +61,8 @@ #define CURRENT_PORT_NONE -1 +#define EMPTY_PACKET_READ_STATE 255 + struct _hub_device { usbh_device_t *device[USBH_HUB_MAX_DEVICES + 1]; uint8_t buffer[USBH_HUB_BUFFER_SIZE]; @@ -68,6 +70,8 @@ struct _hub_device { uint8_t endpoint_in_address; uint8_t endpoint_in_toggle; uint8_t state; + uint8_t state_after_empty_read; + uint8_t desc_len; uint16_t ports_num; int8_t index; -- cgit From eb80e438189961ba61b0250490ec73a7e439dcc6 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 26 Aug 2015 07:44:10 +0200 Subject: Device driver/mouse: use correct endpoint type: INTERRUPT Signed-off-by: Amir Hammad --- src/usbh_driver_hid_mouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 0a575f2..56278ef 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -218,7 +218,7 @@ static void read_mouse_in(void *drvdata) packet.datalen = mouse->endpoint_in_maxpacketsize; packet.endpoint_address = mouse->endpoint_in_address; packet.endpoint_size_max = mouse->endpoint_in_maxpacketsize; - packet.endpoint_type = USBH_EPTYP_BULK; + packet.endpoint_type = USBH_EPTYP_INTERRUPT; packet.speed = mouse->usbh_device->speed; packet.callback = event; packet.callback_arg = mouse->usbh_device; -- cgit From b45e10a391cd4079d50c184db95ce061c1405eda Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 26 Aug 2015 07:26:17 +0200 Subject: usbh_hubbed: set packet_size_max0 field also when DT_DEVICE returns OK packet_size_max0 was set only if it was 8. It was not working for 16 or 32. Signed-off-by: Amir Hammad --- src/usbh_hubbed.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index 833e5a3..7391232 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -370,6 +370,7 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_ { struct usb_device_descriptor *ddt = (struct usb_device_descriptor *)&usbh_buffer[0]; + dev->packet_size_max0 = ddt->bMaxPacketSize0; struct usb_setup_data setup_data; setup_data.bmRequestType = 0b10000000; -- cgit From 9f0651caf96babe314cd73ccbbe6aee2aa0bfe36 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Sun, 23 Aug 2015 15:24:27 +0200 Subject: Make: Compile also *.cpp files Signed-off-by: Amir Hammad --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9fe1c80..1052d3a 100644 --- a/Makefile +++ b/Makefile @@ -92,8 +92,10 @@ STYLECHECKFILES := $(shell find . -name '*.[ch]') LDSCRIPT ?= $(BINARY).ld -SRCS = $(sort $(notdir $(wildcard $(SRCDIR)/*.c))) -OBJSDEMO = $(patsubst %.c, build/%.o ,$(SRCS)) +SRCS := $(sort $(notdir $(wildcard $(SRCDIR)/*.c))) +OBJSDEMO := $(patsubst %.c, build/%.o ,$(SRCS)) +SRCS := $(sort $(notdir $(wildcard $(SRCDIR)/*.cpp))) +OBJSDEMO += $(patsubst %.cpp, build/%.o ,$(SRCS)) OBJS = $(filter-out $(BINARY).o, $(OBJSDEMO)) -- cgit From 4abcb07a755af940909bf615fedeb175ba7f6223 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 26 Aug 2015 07:33:35 +0200 Subject: lld/stm32f4: fix bug, setting wrong eptyp field it was always 0 - control transfer... Signed-off-by: Amir Hammad --- src/usbh_lld_stm32f4.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 817df2e..2ad8190 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -160,11 +160,16 @@ static void stm32f4_usbh_port_channel_setup( eptyp = OTG_HCCHAR_EPTYP_BULK; break; case USBH_EPTYP_INTERRUPT: - eptyp = OTG_HCCHAR_EPTYP_INTERRUPT; + // Use bulk transfer also for interrupt, since no difference is on protocol layer + // Except different behaviour of the core + eptyp = OTG_HCCHAR_EPTYP_BULK; break; case USBH_EPTYP_ISOCHRONOUS: eptyp = OTG_HCCHAR_EPTYP_ISOCHRONOUS; break; + default: + LOG_PRINTF("\n\n\n\nWRONG EP TYPE\n\n\n\n\n"); + return; } uint32_t speed = 0; @@ -175,10 +180,10 @@ static void stm32f4_usbh_port_channel_setup( REBASE_CH(OTG_HCCHAR, channel) = OTG_HCCHAR_CHENA | (OTG_HCCHAR_DAD_MASK & (address << 22)) | OTG_HCCHAR_MCNT_1 | - (OTG_HCCHAR_EPTYP_MASK & (eptyp << 18)) | + (OTG_HCCHAR_EPTYP_MASK & (eptyp)) | (speed) | (epdir) | - (OTG_HCCHAR_EPNUM_MASK & (epnum << 11) )| + (OTG_HCCHAR_EPNUM_MASK & (epnum << 11)) | (OTG_HCCHAR_MPSIZ_MASK & max_packet_size); } -- cgit From 631a614c81820455a3dbf8f4bb689887ba768823 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 26 Aug 2015 07:53:00 +0200 Subject: Device driver/gp_xbox:Use correct endpoint type:INTERRUPT Signed-off-by: Amir Hammad --- src/usbh_driver_gp_xbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index 1b1d895..ae478ad 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -330,7 +330,7 @@ static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox) packet.datalen = gp_xbox->endpoint_in_maxpacketsize; packet.endpoint_address = gp_xbox->endpoint_in_address; packet.endpoint_size_max = gp_xbox->endpoint_in_maxpacketsize; - packet.endpoint_type = USBH_EPTYP_BULK; + packet.endpoint_type = USBH_EPTYP_INTERRUPT; packet.speed = gp_xbox->usbh_device->speed; packet.callback = event; packet.callback_arg = gp_xbox->usbh_device; -- cgit From 4cbbb39624f2b1778fd3a3ade226957769234b29 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Wed, 26 Aug 2015 08:00:40 +0200 Subject: lld/stm32f4: Send correct amount of data + added logging output of data that is going to be sent. Signed-off-by: Amir Hammad --- src/usbh_lld_stm32f4.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 2ad8190..8b98321 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -20,9 +20,9 @@ * */ +#include "driver/usbh_device_driver.h" #include "usbh_lld_stm32f4.h" #include "usart_helpers.h" -#include "driver/usbh_device_driver.h" #include #include @@ -301,9 +301,22 @@ static void write(void *drvdata, const usbh_packet_t *packet) volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + RX_FIFO_SIZE; const uint32_t * buf32 = packet->data; int i; - for(i = packet->datalen; i > 0; i-=4) { + LOG_PRINTF("\nSending[%d]: ", packet->datalen); + for(i = packet->datalen; i >= 4; i-=4) { + const uint8_t *buf8 = (const uint8_t *)buf32; + LOG_PRINTF("%02X %02X %02X %02X, ", buf8[0], buf8[1], buf8[2], buf8[3]); *fifo++ = *buf32++; + + } + + if (i > 0) { + *fifo = *buf32&((1 << (8*i)) - 1); + uint8_t *buf8 = (uint8_t *)buf32; + while (i--) { + LOG_PRINTF("%02X ", *buf8++); + } } + LOG_PRINTF("\n"); } else { volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + -- cgit From 2963113e8ee24e3c002cc4856af8508e05ee6e72 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 20 Jun 2016 22:34:32 +0200 Subject: Merged usb midi code into current libusbmaster + merge fixes Signed-off-by: Amir Hammad --- README.md | 1 + include/usbh_config.h | 6 + include/usbh_driver_ac_midi.h | 48 +++++ src/demo.c | 24 +++ src/usbh_driver_ac_midi.c | 391 ++++++++++++++++++++++++++++++++++++++ src/usbh_driver_ac_midi_private.h | 52 +++++ 6 files changed, 522 insertions(+) create mode 100644 include/usbh_driver_ac_midi.h create mode 100644 src/usbh_driver_ac_midi.c create mode 100644 src/usbh_driver_ac_midi_private.h diff --git a/README.md b/README.md index ff631ad..f18ce09 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Native device drivers (mostly for demonstration purposes): - HUB - Gamepad - XBox compatible Controller - mouse (draft: only displays raw data) +- USB MIDI devices (raw data + note on/off) ###Practical info diff --git a/include/usbh_config.h b/include/usbh_config.h index 1b60954..4fa38cb 100644 --- a/include/usbh_config.h +++ b/include/usbh_config.h @@ -43,6 +43,12 @@ #define USBH_HID_MOUSE_BUFFER (32) +// MIDI +// Maximal number of midi devices connected to whatever hub +#define USBH_AC_MIDI_MAX_DEVICES (4) + +#define USBH_AC_MIDI_BUFFER (64) + // Gamepad XBOX #define USBH_GP_XBOX_MAX_DEVICES (2) diff --git a/include/usbh_driver_ac_midi.h b/include/usbh_driver_ac_midi.h new file mode 100644 index 0000000..7b006a9 --- /dev/null +++ b/include/usbh_driver_ac_midi.h @@ -0,0 +1,48 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2016 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_DRIVER_AC_MIDI_ +#define USBH_DRIVER_AC_MIDI_ + +#include "usbh_hubbed.h" + +#include + +BEGIN_DECLS + +struct _midi_config { + void (*read_callback)(int device_id, uint8_t *data); + void (*notify_connected)(int device_id); + void (*notify_disconnected)(int device_id); +}; +typedef struct _midi_config midi_config_t; + +typedef void (*midi_write_callback_t)(uint8_t); + +void midi_driver_init(const midi_config_t *config); +void usbh_midi_write(uint8_t device_id, const void *data, uint32_t length, midi_write_callback_t callback); + +extern const usbh_dev_driver_t usbh_midi_driver; + +END_DECLS + +#endif diff --git a/src/demo.c b/src/demo.c index ec37781..ae8da53 100644 --- a/src/demo.c +++ b/src/demo.c @@ -26,6 +26,7 @@ #include "usbh_driver_hid_mouse.h" /// provides usb device driver Human Interface Device - type mouse #include "usbh_driver_hub.h" /// provides usb full speed hub driver (Low speed devices on hub are not supported) #include "usbh_driver_gp_xbox.h" /// provides usb device driver for Gamepad: Microsoft XBOX compatible Controller +#include "usbh_driver_ac_midi.h" /// provides usb device driver for midi class devices // STM32f407 compatible #include @@ -117,6 +118,7 @@ static const usbh_dev_driver_t *device_drivers[] = { &usbh_hub_driver, &usbh_hid_mouse_driver, &usbh_gp_xbox_driver, + &usbh_midi_driver, 0 }; @@ -159,6 +161,27 @@ static const hid_mouse_config_t mouse_config = { .mouse_in_message_handler = &mouse_in_message_handler }; +static void midi_in_message_handler(int device_id, uint8_t *data) +{ + (void)device_id; + switch (data[1]>>4) { + case 8: + LOG_PRINTF("\r\nNote Off"); + break; + + case 9: + LOG_PRINTF("\r\nNote On"); + break; + + default: + break; + } +} + +const midi_config_t midi_config = { + .read_callback = &midi_in_message_handler +}; + int main(void) { clock_setup(); @@ -180,6 +203,7 @@ int main(void) hid_mouse_driver_init(&mouse_config); hub_driver_init(); gp_xbox_driver_init(&gp_xbox_config); + midi_driver_init(&midi_config); gpio_set(GPIOD, GPIO13); diff --git a/src/usbh_driver_ac_midi.c b/src/usbh_driver_ac_midi.c new file mode 100644 index 0000000..65c7617 --- /dev/null +++ b/src/usbh_driver_ac_midi.c @@ -0,0 +1,391 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2016 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "driver/usbh_device_driver.h" +#include "usbh_driver_ac_midi_private.h" +#include "usart_helpers.h" + +#include +#include +#include + + +static void *midi_init(void *usbh_dev); +static bool midi_analyze_descriptor(void *drvdata, void *descriptor); +static void midi_poll(void *drvdata, uint32_t tflp); +static void midi_remove(void *drvdata); + +static midi_device_t midi_device[USBH_AC_MIDI_MAX_DEVICES]; +static const midi_config_t *midi_config = 0; +static bool initialized = false; + +static const usbh_dev_driver_info_t usbh_midi_driver_info = { + .deviceClass = -1, + .deviceSubClass = -1, + .deviceProtocol = -1, + .idVendor = -1, + .idProduct = -1, + .ifaceClass = 0x01, + .ifaceSubClass = 0x03, + .ifaceProtocol = -1, +}; + +const usbh_dev_driver_t usbh_midi_driver = { + .init = midi_init, + .analyze_descriptor = midi_analyze_descriptor, + .poll = midi_poll, + .remove = midi_remove, + .info = &usbh_midi_driver_info +}; + +void midi_driver_init(const midi_config_t *config) +{ + uint32_t i; + midi_config = config; + for (i = 0; i < USBH_AC_MIDI_MAX_DEVICES; i++) { + midi_device[i].state = 0; + } + initialized = true; +} +/** + * + * + */ +static void *midi_init(void *usbh_dev) +{ + if (!midi_config || !initialized) { + LOG_PRINTF("\n%s/%d : driver not initialized\n", __FILE__, __LINE__); + return 0; + } + uint32_t i; + midi_device_t *drvdata = 0; + + // find free data space for midi device + for (i = 0; i < USBH_AC_MIDI_MAX_DEVICES; i++) { + if (midi_device[i].state == 0) { + drvdata = &midi_device[i]; + drvdata->device_id = i; + drvdata->endpoint_in_address = 0; + drvdata->endpoint_out_address = 0; + drvdata->endpoint_in_toggle = 0; + drvdata->endpoint_out_toggle = 0; + drvdata->usbh_device = usbh_dev; + drvdata->write_callback_user = 0; + drvdata->sending = false; + break; + } + } + + return drvdata; +} + +/** + * Returns true if all needed data are parsed + */ +static bool midi_analyze_descriptor(void *drvdata, void *descriptor) +{ + midi_device_t *midi = drvdata; + uint8_t desc_type = ((uint8_t *)descriptor)[1]; + switch (desc_type) { + case USB_DT_CONFIGURATION: + { + struct usb_config_descriptor *cfg = + (struct usb_config_descriptor*)descriptor; + midi->buffer[0] = cfg->bConfigurationValue; + } + break; + case USB_DT_DEVICE: + break; + case USB_DT_INTERFACE: + break; + case USB_DT_ENDPOINT: + { + struct usb_endpoint_descriptor *ep = + (struct usb_endpoint_descriptor*)descriptor; + if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_BULK) { + uint8_t epaddr = ep->bEndpointAddress; + if (epaddr & (1<<7)) { + midi->endpoint_in_address = epaddr&0x7f; + if (ep->wMaxPacketSize < USBH_AC_MIDI_BUFFER) { + midi->endpoint_in_maxpacketsize = ep->wMaxPacketSize; + } else { + midi->endpoint_in_maxpacketsize = USBH_AC_MIDI_BUFFER; + } + } else { + midi->endpoint_out_address = epaddr; + midi->endpoint_out_maxpacketsize = ep->wMaxPacketSize; + } + + if (midi->endpoint_in_address && midi->endpoint_out_address) { + midi->state = 1; + return true; + } + } + } + break; + + case USB_AUDIO_DT_CS_ENDPOINT: + { + struct usb_midi_in_jack_descriptor *midi_in_jack_desc = + (struct usb_midi_in_jack_descriptor *) descriptor; + (void)midi_in_jack_desc; + } + break; + // TODO Class Specific descriptors + default: + break; + } + return false; +} + +static void midi_in_message(midi_device_t *midi, const uint8_t datalen) +{ + uint8_t i = 0; + if (midi_config->read_callback) { + for (i = 0; i < datalen; i += 4) { + +// uint8_t cable_number = (midi->buffer[i] & 0xf0) >> 4; + uint8_t code_id = midi->buffer[i]&0xf; + + uint8_t *ptrdata = &midi->buffer[i]; + if (code_id < 2) { + continue; + } + midi_config->read_callback(midi->device_id, ptrdata); + } + } +} + +static void event(usbh_device_t *dev, usbh_packet_callback_data_t status) +{ + midi_device_t *midi = (midi_device_t *)dev->drvdata; + switch (midi->state) { + case 26: + { + switch (status.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + midi_in_message(midi, midi->endpoint_in_maxpacketsize); + midi->state = 25; + break; + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + midi_in_message(midi, status.transferred_length); + midi->state = 25; + break; + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + LOG_PRINTF("FATAL ERROR, MIDI DRIVER DEAD \n"); + //~ dev->drv->remove(); + midi->state = 0; + break; + } + } + break; + + case 102: + { + midi->state = 101; + LOG_PRINTF("\n CAN'T TOUCH THIS... ignoring data\n"); + } + break; + case 2: + { + LOG_PRINTF("|empty packet read|"); + if (status.status == USBH_PACKET_CALLBACK_STATUS_OK) { + midi->state++; + device_xfer_control_read(0, 0, event, dev); + } + } + break; + case 3: // Configured + { + if (status.status == USBH_PACKET_CALLBACK_STATUS_OK) { + midi->state = 100; + + midi->endpoint_in_toggle = 0; + LOG_PRINTF("\nMIDI CONFIGURED\n"); + + // Notify user + if (midi_config->notify_connected) { + midi_config->notify_connected(midi->device_id); + } + } + } + break; + default: + break; + } +} + + +static void read_midi_in(void *drvdata, const uint8_t nextstate) +{ + midi_device_t *midi = drvdata; + usbh_packet_t packet; + + packet.address = midi->usbh_device->address; + packet.data = &midi->buffer[0]; + packet.datalen = midi->endpoint_in_maxpacketsize; + packet.endpoint_address = midi->endpoint_in_address; + packet.endpoint_size_max = midi->endpoint_in_maxpacketsize; + packet.endpoint_type = USBH_EPTYP_BULK; + packet.speed = midi->usbh_device->speed; + packet.callback = event; + packet.callback_arg = midi->usbh_device; + packet.toggle = &midi->endpoint_in_toggle; + + midi->state = nextstate; + usbh_read(midi->usbh_device,&packet); +} + +/** + * + * @param t_us global time us + */ +static void midi_poll(void *drvdata, uint32_t t_us) +{ + (void)drvdata; + + midi_device_t *midi = drvdata; + usbh_device_t *dev = midi->usbh_device; + switch (midi->state) { + + /// Upon configuration, some controllers send additional error data + /// case 100, 101, 102 cares for ignoring those data + case 100: + { + midi->time_us_config = t_us; + midi->state = 101; + } + break; + case 101: + { + read_midi_in(drvdata, 102); + } + break; + case 102: + { + // if elapsed MIDI initial delay microseconds + if (t_us - midi->time_us_config > MIDI_INITIAL_DELAY) { + midi->state = 26; + } + } + break; + case 25: + { + read_midi_in(drvdata, 26); + } + break; + + case 1: + { + //~ LOG_PRINTF("CFGVAL: %d\n", dev->config_val); + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00000000; + setup_data.bRequest = USB_REQ_SET_CONFIGURATION; + setup_data.wValue = midi->buffer[0]; + setup_data.wIndex = 0; + setup_data.wLength = 0; + + midi->state++; + + device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev); + } + break; + } +} + +// don't call directly +static void write_callback(usbh_device_t *dev, usbh_packet_callback_data_t status) +{ + (void)status; + midi_device_t *midi = (midi_device_t *)dev->drvdata; + + if (midi->sending) { + midi->sending = false; + const midi_write_callback_t callback = midi->write_callback_user; + if (!callback) { + return; + } + + if (status.status & USBH_PACKET_CALLBACK_STATUS_OK) { + callback(midi->write_packet.datalen); + } else { + if (status.status & USBH_PACKET_CALLBACK_STATUS_ERRSIZ) { + const uint32_t length = status.transferred_length; + callback(length); + } else { + callback(0); + } + } + } +} + +void usbh_midi_write(uint8_t device_id, const void *data, uint32_t length, midi_write_callback_t callback) +{ + // bad device_id handling + if (device_id >= USBH_AC_MIDI_MAX_DEVICES) { + return; + } + + midi_device_t *midi = &midi_device[device_id]; + + // device with provided device_id is not alive + if (midi->state == 0) { + return; + } + + usbh_device_t *dev = midi->usbh_device; + if (midi->endpoint_out_address == 0) { + return; + } + + midi->sending = true; + midi->write_callback_user = callback; + + midi->write_packet.data = (void*)data; // it is safe cast since we are writing and function usbh_write cannot modify data + midi->write_packet.datalen = length; + midi->write_packet.address = dev->address; + midi->write_packet.endpoint_address = midi->endpoint_out_address; + midi->write_packet.endpoint_size_max = midi->endpoint_out_maxpacketsize; + midi->write_packet.endpoint_type = USBH_EPTYP_BULK; + midi->write_packet.speed = dev->speed; + midi->write_packet.callback = write_callback; + midi->write_packet.callback_arg = midi->usbh_device; + midi->write_packet.toggle = &midi->endpoint_out_toggle; + + + usbh_write(dev, &midi->write_packet); +} + +static void midi_remove(void *drvdata) +{ + midi_device_t *midi = drvdata; + + if (midi_config->notify_disconnected) { + midi_config->notify_disconnected(midi->device_id); + } + + midi->state = 0; + midi->endpoint_in_address = 0; + midi->endpoint_out_address = 0; +} diff --git a/src/usbh_driver_ac_midi_private.h b/src/usbh_driver_ac_midi_private.h new file mode 100644 index 0000000..b92ee97 --- /dev/null +++ b/src/usbh_driver_ac_midi_private.h @@ -0,0 +1,52 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2016 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_DRIVER_AC_MIDI_PRIVATE_ +#define USBH_DRIVER_AC_MIDI_PRIVATE_ + +#include "driver/usbh_device_driver.h" +#include "usbh_driver_ac_midi.h" + +#include + + +#define MIDI_INITIAL_DELAY (100000) + +struct _midi_device { + usbh_device_t *usbh_device; + uint8_t buffer[USBH_AC_MIDI_BUFFER]; + uint16_t endpoint_in_maxpacketsize; + uint16_t endpoint_out_maxpacketsize; + uint8_t endpoint_in_address; + uint8_t endpoint_out_address; + uint8_t state; + uint8_t endpoint_in_toggle; + uint8_t endpoint_out_toggle; + uint8_t device_id; + bool sending; + midi_write_callback_t write_callback_user; + usbh_packet_t write_packet; + // Timestamp at sending config command + uint32_t time_us_config; +}; +typedef struct _midi_device midi_device_t; +#endif -- cgit From 4bf0db8f7bac51cda88d5033a1657dc3b85b7c66 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Mon, 20 Jun 2016 22:42:15 +0200 Subject: add todo: clean-up makefiles * organize files properly into directories * avoid the need for make clean Signed-off-by: Amir Hammad --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f18ce09..5dbbc9e 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ Native device drivers (mostly for demonstration purposes): ###Practical info -!!! Do not forget to invoke "make clean" before new build when defines change +!!! Do not forget to invoke "make clean" before new build when defines change(_TODO: remove this warning and fix the Makefile_) + **How to initialize repository** -- cgit From 0432429aa6bcecfeeeccf4ba9b4cca28206b4863 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 24 Jun 2016 00:46:40 +0200 Subject: move USE_STM32f4_USBH_DRIVER_HS/FS from config.mk to usbh_config.h Leave the behaviour as before: Default: FullSpeed Signed-off-by: Amir Hammad --- README.md | 2 +- config.mk | 6 ------ include/usbh_config.h | 6 ++++++ src/demo.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5dbbc9e..31e32ab 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ fetch libopencm3 submodule and compile needed libraries **How to compile demo** -Edit config.mk for library configuration (By default Full speed OTG periphery on stm32f4 is supported) +Edit usbh_config.h to configure the library (By default Full speed OTG periphery on stm32f4 is supported) > ./compileDemo.sh diff --git a/config.mk b/config.mk index 03fae74..3ba462b 100644 --- a/config.mk +++ b/config.mk @@ -2,9 +2,3 @@ USER_CONFIG = - -# Uncomment to enable OTG_HS support - low level driver -#USER_CONFIG += -DUSE_STM32F4_USBH_DRIVER_HS - -# Uncomment to enable OTG_FS support - low level driver -USER_CONFIG += -DUSE_STM32F4_USBH_DRIVER_FS diff --git a/include/usbh_config.h b/include/usbh_config.h index 4fa38cb..7bf800b 100644 --- a/include/usbh_config.h +++ b/include/usbh_config.h @@ -59,4 +59,10 @@ #error USBH_MAX_DEVICES > 127 #endif +// Uncomment to enable OTG_HS support - low level driver +// #define USE_STM32F4_USBH_DRIVER_HS + +// Uncomment to enable OTG_FS support - low level driver +#define USE_STM32F4_USBH_DRIVER_FS + #endif diff --git a/src/demo.c b/src/demo.c index ae8da53..76c33fd 100644 --- a/src/demo.c +++ b/src/demo.c @@ -210,7 +210,7 @@ int main(void) /** * Pass array of supported low level drivers * In case of stm32f407, there are up to two supported OTG hosts on one chip. - * Each one can be enabled or disabled in config.mk - optimization for speed + * Each one can be enabled or disabled in usbh_config.h - optimization for speed * * Pass array of supported device drivers */ -- cgit From 40192caee01bd5fe6c8ed2c61798c95782ccfdd2 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 24 Jun 2016 00:47:47 +0200 Subject: let the user build an array of lld drivers Signed-off-by: Amir Hammad --- include/usbh_lld_stm32f4.h | 3 ++- src/demo.c | 7 ++++++- src/usbh_lld_stm32f4.c | 13 ++----------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/include/usbh_lld_stm32f4.h b/include/usbh_lld_stm32f4.h index c55c615..a8f7b0a 100644 --- a/include/usbh_lld_stm32f4.h +++ b/include/usbh_lld_stm32f4.h @@ -30,7 +30,8 @@ BEGIN_DECLS // pass this to usbh init -extern const void *usbh_lld_stm32f4_drivers[]; +extern const void *usbh_lld_stm32f4_driver_fs; +extern const void *usbh_lld_stm32f4_driver_hs; #ifdef USART_DEBUG void print_channels(const void *drvdata); diff --git a/src/demo.c b/src/demo.c index 76c33fd..f6cccf5 100644 --- a/src/demo.c +++ b/src/demo.c @@ -214,7 +214,12 @@ int main(void) * * Pass array of supported device drivers */ - usbh_init(usbh_lld_stm32f4_drivers, device_drivers); + const void *lld_drivers[] = { + &usbh_lld_stm32f4_driver_fs, // Make sure USE_STM32F4_USBH_DRIVER_FS is defined in usbh_config.h +// &usbh_lld_stm32f4_driver_hs, // Make sure USE_STM32F4_USBH_DRIVER_HS is defined in usbh_config.h + 0 + }; + usbh_init(lld_drivers, device_drivers); gpio_clear(GPIOD, GPIO13); LOG_PRINTF("USB init complete\n"); diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 8b98321..49f6cc2 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -1025,6 +1025,7 @@ static const usbh_driver_t driver_fs = { .root_speed = root_speed, .driver_data = &driver_data_fs }; +const void *usbh_lld_stm32f4_driver_fs = &driver_fs; #endif // USB High Speed - OTG_HS @@ -1044,15 +1045,5 @@ static const usbh_driver_t driver_hs = { .root_speed = root_speed, .driver_data = &driver_data_hs }; +const void *usbh_lld_stm32f4_driver_hs = &driver_hs; #endif - -const void *usbh_lld_stm32f4_drivers[] = { -#if defined(USE_STM32F4_USBH_DRIVER_FS) - &driver_fs, -#endif - -#if defined(USE_STM32F4_USBH_DRIVER_HS) - &driver_hs, -#endif - 0 -}; -- cgit From e59f23ad5c60dc08f281ccc7a794f4482e55ad00 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 24 Jun 2016 01:16:57 +0200 Subject: Don't compile usart_helpers.o when USART_DEBUG is not defined Signed-off-by: Amir Hammad --- Makefile | 5 +++++ src/usart_helpers.h | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1052d3a..9f42be3 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,11 @@ SRCS := $(sort $(notdir $(wildcard $(SRCDIR)/*.cpp))) OBJSDEMO += $(patsubst %.cpp, build/%.o ,$(SRCS)) OBJS = $(filter-out $(BINARY).o, $(OBJSDEMO)) +ifndef USART_DEBUG +OBJS := $(filter-out build/usart_helpers.o, $(OBJS)) +OBJSDEMO := $(filter-out build/usart_helpers.o, $(OBJSDEMO)) +endif + INCLUDE_DIR = $(OPENCM3_DIR)/include LIB_DIR = $(OPENCM3_DIR)/lib diff --git a/src/usart_helpers.h b/src/usart_helpers.h index 2a2f561..eef43fa 100644 --- a/src/usart_helpers.h +++ b/src/usart_helpers.h @@ -35,6 +35,7 @@ struct usart_commands{ }; +#ifdef USART_DEBUG void usart_init(uint32_t usart, uint32_t baudrate); void usart_printf(const char *str, ...); void usart_vprintf(const char *str, va_list va); @@ -42,8 +43,6 @@ void usart_fifo_send(void); void usart_call_cmd(struct usart_commands * commands); void usart_interrupt(void); - -#ifdef USART_DEBUG #define LOG_PRINTF(format, ...) usart_printf(format, ##__VA_ARGS__); #define LOG_FLUSH() usart_fifo_send() #else -- cgit From 27fe98f2d60d28153dfc10452b40664fc1e2ac66 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 24 Jun 2016 01:23:26 +0200 Subject: Embed information about compilation with the debug functions into make output Signed-off-by: Amir Hammad --- Makefile | 2 ++ src/usart_helpers.c | 29 ----------------------------- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 9f42be3..d1eeedf 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,8 @@ OBJS = $(filter-out $(BINARY).o, $(OBJSDEMO)) ifndef USART_DEBUG OBJS := $(filter-out build/usart_helpers.o, $(OBJS)) OBJSDEMO := $(filter-out build/usart_helpers.o, $(OBJSDEMO)) +else +$(info compiling with DEBUG functions) endif diff --git a/src/usart_helpers.c b/src/usart_helpers.c index 4469b44..5a9aa03 100644 --- a/src/usart_helpers.c +++ b/src/usart_helpers.c @@ -31,33 +31,6 @@ #include -#ifndef USART_DEBUG - -void usart_init(uint32_t usart, uint32_t baudrate) -{ - (void)usart; - (void)baudrate; -} -void usart_printf(const char *str, ...) -{ - (void)str; -} -void usart_vprintf(const char *str, va_list va) -{ - (void)va; - (void)str; -} -void usart_fifo_send(void){} - -void usart_call_cmd(struct usart_commands * commands) -{ - (void)commands; -} -void usart_interrupt(void){} - -#else -#warning compiling with debug functions - #define USART_FIFO_OUT_SIZE (4096) uint8_t usart_fifo_out_data[USART_FIFO_OUT_SIZE]; uint32_t usart_fifo_out_len = 0; @@ -283,5 +256,3 @@ void usart_call_cmd(struct usart_commands * commands) command_argindex = 0; LOG_PRINTF("INVALID COMMAND\n>>"); } - -#endif -- cgit From e61ed66174df0bf889586c757aa6a9d23d9401c0 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 8 Jul 2016 23:20:16 +0200 Subject: refactor: use enum instead of #define: USBH_ENDPOINT_TYPE and USBH_SPEED Signed-off-by: Amir Hammad --- include/driver/usbh_device_driver.h | 25 ++++++++++++++----------- src/usbh_driver_ac_midi.c | 4 ++-- src/usbh_driver_gp_xbox.c | 2 +- src/usbh_driver_hid_mouse.c | 2 +- src/usbh_driver_hub.c | 2 +- src/usbh_hubbed.c | 4 ++-- src/usbh_lld_stm32f4.c | 24 ++++++++++++------------ 7 files changed, 33 insertions(+), 30 deletions(-) diff --git a/include/driver/usbh_device_driver.h b/include/driver/usbh_device_driver.h index 137b39b..3a4fbe3 100644 --- a/include/driver/usbh_device_driver.h +++ b/include/driver/usbh_device_driver.h @@ -30,15 +30,18 @@ BEGIN_DECLS -#define USBH_EPTYP_CONTROL (0) -#define USBH_EPTYP_ISOCHRONOUS (1) -#define USBH_EPTYP_BULK (2) -#define USBH_EPTYP_INTERRUPT (3) - -#define USBH_SPEED_FULL (0) -#define USBH_SPEED_LOW (1) -#define USBH_SPEED_HIGH (2) +enum USBH_ENDPOINT_TYPE { + USBH_ENDPOINT_TYPE_CONTROL = 0, + USBH_ENDPOINT_TYPE_ISOCHRONOUS = 1, + USBH_ENDPOINT_TYPE_BULK = 2, + USBH_ENDPOINT_TYPE_INTERRUPT = 3, +}; +enum USBH_SPEED { + USBH_SPEED_FULL = 0, + USBH_SPEED_LOW = 1, + USBH_SPEED_HIGH = 2, +}; enum USBH_PACKET_CALLBACK_STATUS { USBH_PACKET_CALLBACK_STATUS_OK = 0, @@ -56,7 +59,7 @@ enum USBH_POLL_STATUS { struct _usbh_device { uint16_t packet_size_max0; int8_t address; - uint8_t speed; // (USBH_SPEED_*) + enum USBH_SPEED speed; // (USBH_SPEED_*) uint8_t state; // for enumeration purposes uint8_t toggle0; const usbh_dev_driver_t *drv; @@ -80,7 +83,7 @@ struct _usbh_packet { uint8_t endpoint_type; // Endpoint type (see USBH_EPTYP_*) uint8_t endpoint_address; // Endpoint number 0..15 uint16_t endpoint_size_max; // Max packet size for an endpoint - uint8_t speed; // (USBH_SPEED_*) + enum USBH_SPEED speed; // (USBH_SPEED_*) uint8_t *toggle; usbh_packet_callback_t callback; void *callback_arg; @@ -92,9 +95,9 @@ struct _usbh_driver { void (*write)(void *drvdata, const usbh_packet_t *packet); void (*read)(void *drvdata, usbh_packet_t *packet); enum USBH_POLL_STATUS (*poll)(void *drvdata, uint32_t time_curr_us); - uint8_t (*root_speed)(void *drvdata); // Pointer to Low-level driver data + enum USBH_SPEED (*root_speed)(void *drvdata); void *driver_data; }; typedef struct _usbh_driver usbh_driver_t; diff --git a/src/usbh_driver_ac_midi.c b/src/usbh_driver_ac_midi.c index 65c7617..c5403d2 100644 --- a/src/usbh_driver_ac_midi.c +++ b/src/usbh_driver_ac_midi.c @@ -246,7 +246,7 @@ static void read_midi_in(void *drvdata, const uint8_t nextstate) packet.datalen = midi->endpoint_in_maxpacketsize; packet.endpoint_address = midi->endpoint_in_address; packet.endpoint_size_max = midi->endpoint_in_maxpacketsize; - packet.endpoint_type = USBH_EPTYP_BULK; + packet.endpoint_type = USBH_ENDPOINT_TYPE_BULK; packet.speed = midi->usbh_device->speed; packet.callback = event; packet.callback_arg = midi->usbh_device; @@ -367,7 +367,7 @@ void usbh_midi_write(uint8_t device_id, const void *data, uint32_t length, midi_ midi->write_packet.address = dev->address; midi->write_packet.endpoint_address = midi->endpoint_out_address; midi->write_packet.endpoint_size_max = midi->endpoint_out_maxpacketsize; - midi->write_packet.endpoint_type = USBH_EPTYP_BULK; + midi->write_packet.endpoint_type = USBH_ENDPOINT_TYPE_BULK; midi->write_packet.speed = dev->speed; midi->write_packet.callback = write_callback; midi->write_packet.callback_arg = midi->usbh_device; diff --git a/src/usbh_driver_gp_xbox.c b/src/usbh_driver_gp_xbox.c index ae478ad..d8bb1b2 100644 --- a/src/usbh_driver_gp_xbox.c +++ b/src/usbh_driver_gp_xbox.c @@ -330,7 +330,7 @@ static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox) packet.datalen = gp_xbox->endpoint_in_maxpacketsize; packet.endpoint_address = gp_xbox->endpoint_in_address; packet.endpoint_size_max = gp_xbox->endpoint_in_maxpacketsize; - packet.endpoint_type = USBH_EPTYP_INTERRUPT; + packet.endpoint_type = USBH_ENDPOINT_TYPE_INTERRUPT; packet.speed = gp_xbox->usbh_device->speed; packet.callback = event; packet.callback_arg = gp_xbox->usbh_device; diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 56278ef..8324999 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -218,7 +218,7 @@ static void read_mouse_in(void *drvdata) packet.datalen = mouse->endpoint_in_maxpacketsize; packet.endpoint_address = mouse->endpoint_in_address; packet.endpoint_size_max = mouse->endpoint_in_maxpacketsize; - packet.endpoint_type = USBH_EPTYP_INTERRUPT; + packet.endpoint_type = USBH_ENDPOINT_TYPE_INTERRUPT; packet.speed = mouse->usbh_device->speed; packet.callback = event; packet.callback_arg = mouse->usbh_device; diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index 305a8f3..eaaf896 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -751,7 +751,7 @@ static void read_ep1(void *drvdata) packet.datalen = hub->endpoint_in_maxpacketsize; packet.endpoint_address = hub->endpoint_in_address; packet.endpoint_size_max = hub->endpoint_in_maxpacketsize; - packet.endpoint_type = USBH_EPTYP_INTERRUPT; + packet.endpoint_type = USBH_ENDPOINT_TYPE_INTERRUPT; packet.speed = hub->device[0]->speed; packet.callback = event; packet.callback_arg = hub->device[0]; diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index 7391232..b631263 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -207,7 +207,7 @@ void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callbac packet.address = dev->address; packet.endpoint_address = 0; packet.endpoint_size_max = dev->packet_size_max0; - packet.endpoint_type = USBH_EPTYP_CONTROL; + packet.endpoint_type = USBH_ENDPOINT_TYPE_CONTROL; packet.speed = dev->speed; packet.callback = callback; packet.callback_arg = dev; @@ -226,7 +226,7 @@ void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback packet.address = dev->address; packet.endpoint_address = 0; packet.endpoint_size_max = dev->packet_size_max0; - packet.endpoint_type = USBH_EPTYP_CONTROL; + packet.endpoint_type = USBH_ENDPOINT_TYPE_CONTROL; packet.speed = dev->speed; packet.callback = callback; packet.callback_arg = dev; diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 49f6cc2..271943a 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -153,18 +153,18 @@ static void stm32f4_usbh_port_channel_setup( // TODO: maybe to function switch (eptyp) { - case USBH_EPTYP_CONTROL: + case USBH_ENDPOINT_TYPE_CONTROL: eptyp = OTG_HCCHAR_EPTYP_CONTROL; break; - case USBH_EPTYP_BULK: + case USBH_ENDPOINT_TYPE_BULK: eptyp = OTG_HCCHAR_EPTYP_BULK; break; - case USBH_EPTYP_INTERRUPT: + case USBH_ENDPOINT_TYPE_INTERRUPT: // Use bulk transfer also for interrupt, since no difference is on protocol layer // Except different behaviour of the core eptyp = OTG_HCCHAR_EPTYP_BULK; break; - case USBH_EPTYP_ISOCHRONOUS: + case USBH_ENDPOINT_TYPE_ISOCHRONOUS: eptyp = OTG_HCCHAR_EPTYP_ISOCHRONOUS; break; default: @@ -260,16 +260,16 @@ static void write(void *drvdata, const usbh_packet_t *packet) channels[channel].packet = *packet; uint32_t dpid; - if (packet->endpoint_type == USBH_EPTYP_CONTROL) { + if (packet->endpoint_type == USBH_ENDPOINT_TYPE_CONTROL) { dpid = OTG_HCTSIZ_DPID_MDATA; packet->toggle[0] = 0; - } else if(packet->endpoint_type == USBH_EPTYP_INTERRUPT) { + } else if(packet->endpoint_type == USBH_ENDPOINT_TYPE_INTERRUPT) { if (packet->toggle[0]) { dpid = OTG_HCTSIZ_DPID_DATA1; } else { dpid = OTG_HCTSIZ_DPID_DATA0; } - } else if (packet->endpoint_type == USBH_EPTYP_BULK) { + } else if (packet->endpoint_type == USBH_ENDPOINT_TYPE_BULK) { if (packet->toggle[0]) { dpid = OTG_HCTSIZ_DPID_DATA1; } else { @@ -295,8 +295,8 @@ static void write(void *drvdata, const usbh_packet_t *packet) OTG_HCCHAR_EPDIR_OUT, packet->endpoint_size_max); - if (packet->endpoint_type == USBH_EPTYP_CONTROL || - packet->endpoint_type == USBH_EPTYP_BULK) { + if (packet->endpoint_type == USBH_ENDPOINT_TYPE_CONTROL || + packet->endpoint_type == USBH_ENDPOINT_TYPE_BULK) { volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + RX_FIFO_SIZE; const uint32_t * buf32 = packet->data; @@ -517,7 +517,7 @@ static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev) if (hcint & OTG_HCINT_ACK) { REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_ACK; LOG_PRINTF("ACK"); - if (eptyp == USBH_EPTYP_CONTROL) { + if (eptyp == USBH_ENDPOINT_TYPE_CONTROL) { channels[channel].packet.toggle[0] = 1; } else { channels[channel].packet.toggle[0] ^= 1; @@ -597,7 +597,7 @@ static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev) if (hcint & OTG_HCINT_NAK) { REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_NAK; - if (eptyp == USBH_EPTYP_CONTROL) { + if (eptyp == USBH_ENDPOINT_TYPE_CONTROL) { LOG_PRINTF("NAK"); } @@ -972,7 +972,7 @@ static void channels_init(void *drvdata) * Get speed of connected device * */ -static uint8_t root_speed(void *drvdata) +static enum USBH_SPEED root_speed(void *drvdata) { usbh_lld_stm32f4_driver_data_t *dev = drvdata; (void)dev; -- cgit From 2c0f82a4f07fe35bc043f68b9f58b954a16ea689 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 8 Jul 2016 23:21:37 +0200 Subject: documentation: add some basic documentation accross the headers Signed-off-by: Amir Hammad --- include/driver/usbh_device_driver.h | 98 +++++++++++++++++++++++++++++++++---- include/usbh_driver_ac_midi.h | 17 ++++++- include/usbh_driver_gp_xbox.h | 5 ++ include/usbh_driver_hid_mouse.h | 9 ++++ include/usbh_driver_hub.h | 3 ++ include/usbh_hubbed.h | 53 +++++++++++++++++--- src/usbh_hubbed.c | 6 +-- 7 files changed, 171 insertions(+), 20 deletions(-) diff --git a/include/driver/usbh_device_driver.h b/include/driver/usbh_device_driver.h index 3a4fbe3..2839a17 100644 --- a/include/driver/usbh_device_driver.h +++ b/include/driver/usbh_device_driver.h @@ -56,20 +56,49 @@ enum USBH_POLL_STATUS { USBH_POLL_STATUS_DEVICE_DISCONNECTED }; +/** + * @brief The _usbh_device struct + * + * This represents exactly one connected device. + */ struct _usbh_device { + /// max packet size for control endpoint(0) uint16_t packet_size_max0; + + /// Device's address int8_t address; - enum USBH_SPEED speed; // (USBH_SPEED_*) - uint8_t state; // for enumeration purposes + + /// @see USBH_SPEED + enum USBH_SPEED speed; + + /// state used for enumeration purposes + uint8_t state; + + /// toggle bit uint8_t toggle0; + + /** + * @brief drv - device driver used for this connected device + */ + const usbh_dev_driver_t *drv; + /** + * @brief drvdata - device driver's private data + */ void *drvdata; + + /** + * @brief lld - pointer to a low-level driver's instance + */ const void *lld; }; typedef struct _usbh_device usbh_device_t; struct _usbh_packet_callback_data { + /// status - it is used for reporting of the errors enum USBH_PACKET_CALLBACK_STATUS status; + + /// count of bytes that has been actually transferred uint32_t transferred_length; }; typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t; @@ -77,27 +106,76 @@ typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t; typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status); struct _usbh_packet { - void *data; // Pointer to data - uint16_t datalen; // Data length 0..1023 - int8_t address; // Device address - uint8_t endpoint_type; // Endpoint type (see USBH_EPTYP_*) - uint8_t endpoint_address; // Endpoint number 0..15 - uint16_t endpoint_size_max; // Max packet size for an endpoint - enum USBH_SPEED speed; // (USBH_SPEED_*) + /// pointer to data + void *data; + + /// length of the data (up to 1023) + uint16_t datalen; + + /// Device's address + int8_t address; + + /// Endpoint type (see USBH_ENDPOINT_TYPE_*) + uint8_t endpoint_type; + + /// Endpoint number 0..15 + uint8_t endpoint_address; + + /// Max packet size for an endpoint + uint16_t endpoint_size_max; + + /// @see USBH_SPEED + enum USBH_SPEED speed; uint8_t *toggle; + + /** + * @brief callback this will be called when the packet is finished - either successfuly or not. + */ usbh_packet_callback_t callback; + + /** + * @brief callback_arg argument passed into callback + * + * Low level driver is not allowed to alter the data pointed by callback_arg + */ void *callback_arg; }; typedef struct _usbh_packet usbh_packet_t; struct _usbh_driver { + /** + * @brief init initialization routine of the low-level driver + * + * + * This function is called during the initialization of the library(@see usbh_init()) + */ void (*init)(void *drvdata); + + /** + * write - perform a write to a device (@see usbh_packet_t) + */ void (*write)(void *drvdata, const usbh_packet_t *packet); + + /** + * @brief read - perform a read from a device (@see usbh_packet_t) + */ void (*read)(void *drvdata, usbh_packet_t *packet); + + /** + * @brief this is called as a part of @ref usbh_poll() routine + */ enum USBH_POLL_STATUS (*poll)(void *drvdata, uint32_t time_curr_us); - // Pointer to Low-level driver data + /** + * @brief speed of the low-level bus + */ enum USBH_SPEED (*root_speed)(void *drvdata); + + /** + * @brief Pointer to Low-level driver data + * + * Data pointed by this pointer should not be altered by the logic other from low-level driver's logic + */ void *driver_data; }; typedef struct _usbh_driver usbh_driver_t; diff --git a/include/usbh_driver_ac_midi.h b/include/usbh_driver_ac_midi.h index 7b006a9..0993589 100644 --- a/include/usbh_driver_ac_midi.h +++ b/include/usbh_driver_ac_midi.h @@ -36,9 +36,24 @@ struct _midi_config { }; typedef struct _midi_config midi_config_t; -typedef void (*midi_write_callback_t)(uint8_t); +/** + * @param bytes_written count of bytes that were actually written + */ +typedef void (*midi_write_callback_t)(uint8_t bytes_written); +/** + * @brief midi_driver_init initialization routine - this will initialize internal structures of this device driver + * @param config + */ void midi_driver_init(const midi_config_t *config); + +/** + * @brief usbh_midi_write + * @param device_id + * @param data + * @param length + * @param callback this is called when the write call finishes + */ void usbh_midi_write(uint8_t device_id, const void *data, uint32_t length, midi_write_callback_t callback); extern const usbh_dev_driver_t usbh_midi_driver; diff --git a/include/usbh_driver_gp_xbox.h b/include/usbh_driver_gp_xbox.h index 8080f30..90d0ca1 100644 --- a/include/usbh_driver_gp_xbox.h +++ b/include/usbh_driver_gp_xbox.h @@ -64,6 +64,11 @@ struct _gp_xbox_config { }; typedef struct _gp_xbox_config gp_xbox_config_t; + +/** + * @brief gp_xbox_driver_init initialization routine - this will initialize internal structures of this device driver + * @param config + */ void gp_xbox_driver_init(const gp_xbox_config_t *config); extern const usbh_dev_driver_t usbh_gp_xbox_driver; diff --git a/include/usbh_driver_hid_mouse.h b/include/usbh_driver_hid_mouse.h index c12fed4..de7707c 100644 --- a/include/usbh_driver_hid_mouse.h +++ b/include/usbh_driver_hid_mouse.h @@ -30,10 +30,19 @@ BEGIN_DECLS struct _hid_mouse_config { + /** + * @brief this is called when some data is read when polling the device + * @param device_id + * @param data pointer to the data (only 4 bytes are valid!) + */ void (*mouse_in_message_handler)(uint8_t device_id, const uint8_t *data); }; typedef struct _hid_mouse_config hid_mouse_config_t; +/** + * @brief hid_mouse_driver_init initialization routine - this will initialize internal structures of this device driver + * @param config + */ void hid_mouse_driver_init(const hid_mouse_config_t *config); extern const usbh_dev_driver_t usbh_hid_mouse_driver; diff --git a/include/usbh_driver_hub.h b/include/usbh_driver_hub.h index cda1463..8555f79 100644 --- a/include/usbh_driver_hub.h +++ b/include/usbh_driver_hub.h @@ -27,6 +27,9 @@ BEGIN_DECLS +/** + * @brief hub_driver_init initialization routine - this will initialize internal structures of this device driver + */ void hub_driver_init(void); extern const usbh_dev_driver_t usbh_hub_driver; diff --git a/include/usbh_hubbed.h b/include/usbh_hubbed.h index f99108d..ca4a489 100644 --- a/include/usbh_hubbed.h +++ b/include/usbh_hubbed.h @@ -40,7 +40,7 @@ BEGIN_DECLS -// set to -1 to unused items +/// set to -1 for unused items ("don't care" functionality) @see find_driver() struct _usbh_dev_driver_info { int32_t deviceClass; int32_t deviceSubClass; @@ -54,22 +54,63 @@ struct _usbh_dev_driver_info { typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t; struct _usbh_dev_driver { + /** + * @brief init is initialization routine of the device driver + * + * This function is called during the initialization of the device driver + */ void *(*init)(void *usbh_dev); - bool (*analyze_descriptor)(void *drv, void *descriptor); + + /** + * @brief analyze descriptor + * @param[in/out] drvdata is the device driver's private data + * @param[in] descriptor is the pointer to the descriptor that should + * be parsed in order to prepare driver to be loaded + * + * @retval true when the enumeration is complete and the driver is ready to be used + * @retval false when the device driver is not ready to be used + * + * This should be used for getting correct endpoint numbers, getting maximum sizes of endpoints. + * Should return true, when no more data is needed. + * + */ + bool (*analyze_descriptor)(void *drvdata, void *descriptor); + + /** + * @brief poll method is called periodically by the library core (@see usbh_poll()) + * @param[in/out] drvdata is the device driver's private data + * @param[in] time_curr_us current timestamp in microseconds + */ void (*poll)(void *drvdata, uint32_t time_curr_us); + + /** + * @brief unloads the device driver + * @param[in/out] drvdata is the device driver's private data + * + * This should free any data associated with this device + */ void (*remove)(void *drvdata); + + /** + * @brief info - compatibility information about the driver. It is used by the core during device enumeration (@see find_driver()) + */ const usbh_dev_driver_info_t * const info; }; typedef struct _usbh_dev_driver usbh_dev_driver_t; -void usbh_init(const void *drivers[], const usbh_dev_driver_t * const device_drivers[]); +/** + * @brief usbh_init + * @param low_level_drivers list of the low level drivers to be used by this library + * @param device_drivers list of the device drivers that could be used with attached devices + */ +void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]); /** - * \brief usbh_poll - * \param time_curr_us - use monotically rising time + * @brief usbh_poll + * @param time_curr_us - use monotically rising time * * time_curr_us: - * * can overflow, in time of this writing, after 1s) + * * can overflow, in time of this writing, after 1s * * unit is microseconds */ void usbh_poll(uint32_t time_curr_us); diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index b631263..7ffc83d 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -163,13 +163,13 @@ static void device_register(void *descriptors, uint16_t descriptors_len, usbh_de LOG_PRINTF("Device NOT Initialized\n"); } -void usbh_init(const void *drivers_lld[], const usbh_dev_driver_t * const device_drivers[]) +void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]) { - if (!drivers_lld) { + if (!low_level_drivers) { return; } - usbh_data.lld_drivers = (const usbh_driver_t **)drivers_lld; + usbh_data.lld_drivers = (const usbh_driver_t **)low_level_drivers; usbh_data.dev_drivers = device_drivers; // TODO: init structures -- cgit From 1c8aa9d315ff09194df53d9b1af755e03168cd64 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 8 Jul 2016 23:27:18 +0200 Subject: rename usbh_driver to usbh_low_level_driver Signed-off-by: Amir Hammad --- include/driver/usbh_device_driver.h | 4 ++-- src/usbh_hubbed.c | 12 ++++++------ src/usbh_lld_stm32f4.c | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/driver/usbh_device_driver.h b/include/driver/usbh_device_driver.h index 2839a17..4f0ecea 100644 --- a/include/driver/usbh_device_driver.h +++ b/include/driver/usbh_device_driver.h @@ -142,7 +142,7 @@ struct _usbh_packet { }; typedef struct _usbh_packet usbh_packet_t; -struct _usbh_driver { +struct _usbh_low_level_driver { /** * @brief init initialization routine of the low-level driver * @@ -178,7 +178,7 @@ struct _usbh_driver { */ void *driver_data; }; -typedef struct _usbh_driver usbh_driver_t; +typedef struct _usbh_low_level_driver usbh_low_level_driver_t; struct _usbh_generic_data { usbh_device_t usbh_device[USBH_MAX_DEVICES]; diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c index 7ffc83d..82f080f 100644 --- a/src/usbh_hubbed.c +++ b/src/usbh_hubbed.c @@ -30,7 +30,7 @@ static struct { bool enumeration_run; - const usbh_driver_t * const *lld_drivers; + const usbh_low_level_driver_t * const *lld_drivers; const usbh_dev_driver_t * const *dev_drivers; int8_t address_temporary; } usbh_data = {0}; @@ -169,7 +169,7 @@ void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const return; } - usbh_data.lld_drivers = (const usbh_driver_t **)low_level_drivers; + usbh_data.lld_drivers = (const usbh_low_level_driver_t **)low_level_drivers; usbh_data.dev_drivers = device_drivers; // TODO: init structures @@ -249,7 +249,7 @@ bool usbh_enum_available(void) */ usbh_device_t *usbh_get_free_device(const usbh_device_t *dev) { - const usbh_driver_t *lld = dev->lld; + const usbh_low_level_driver_t *lld = dev->lld; usbh_generic_data_t *lld_data = lld->driver_data; usbh_device_t *usbh_device = lld_data->usbh_device; @@ -281,7 +281,7 @@ static void device_enumeration_terminate(usbh_device_t *dev) */ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) { - const usbh_driver_t *lld = dev->lld; + const usbh_low_level_driver_t *lld = dev->lld; usbh_generic_data_t *lld_data = lld->driver_data; uint8_t *usbh_buffer = lld_data->usbh_buffer; uint8_t state_start = dev->state; // Detection of hang @@ -620,13 +620,13 @@ void usbh_poll(uint32_t time_curr_us) void usbh_read(usbh_device_t *dev, usbh_packet_t *packet) { - const usbh_driver_t *lld = dev->lld; + const usbh_low_level_driver_t *lld = dev->lld; lld->read(lld->driver_data, packet); } void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet) { - const usbh_driver_t *lld = dev->lld; + const usbh_low_level_driver_t *lld = dev->lld; lld->write(lld->driver_data, packet); } diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 271943a..83526a9 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -998,7 +998,7 @@ static enum USBH_SPEED root_speed(void *drvdata) */ void print_channels(const void *lld) { - usbh_lld_stm32f4_driver_data_t *dev = ((usbh_driver_t *)lld)->driver_data; + usbh_lld_stm32f4_driver_data_t *dev = ((usbh_low_level_driver_t *)lld)->driver_data; channel_t *channels = dev->channels; int32_t i; LOG_PRINTF("\nCHANNELS: \n"); @@ -1017,7 +1017,7 @@ static usbh_lld_stm32f4_driver_data_t driver_data_fs = { .channels = channels_fs, .num_channels = NUM_CHANNELS_FS }; -static const usbh_driver_t driver_fs = { +static const usbh_low_level_driver_t driver_fs = { .init = init, .poll = poll, .read = read, @@ -1037,7 +1037,7 @@ static usbh_lld_stm32f4_driver_data_t driver_data_hs = { .channels = channels_hs, .num_channels = NUM_CHANNELS_HS }; -static const usbh_driver_t driver_hs = { +static const usbh_low_level_driver_t driver_hs = { .init = init, .poll = poll, .read = read, -- cgit From dd950136aa5c438855eb6a3e87f352a11f60747c Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 8 Jul 2016 23:41:55 +0200 Subject: lld: stm32f4: adjust reporting of the unahandled block of code Signed-off-by: Amir Hammad --- src/usbh_lld_stm32f4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usbh_lld_stm32f4.c b/src/usbh_lld_stm32f4.c index 83526a9..0b12888 100644 --- a/src/usbh_lld_stm32f4.c +++ b/src/usbh_lld_stm32f4.c @@ -277,7 +277,7 @@ static void write(void *drvdata, const usbh_packet_t *packet) } } else { dpid = OTG_HCTSIZ_DPID_DATA0; // ! TODO: BUG - LOG_PRINTF("BUG, %d",__LINE__); + ERROR(""); } uint32_t num_packets; -- cgit From 4f3a3905c9c75c483fd72e173bd904f566dd4472 Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Fri, 8 Jul 2016 23:53:42 +0200 Subject: rename usbh_hubbed.* to usbh_core.* Signed-off-by: Amir Hammad --- include/driver/usbh_device_driver.h | 2 +- include/usbh_core.h | 120 +++++++ include/usbh_driver_ac_midi.h | 2 +- include/usbh_driver_gp_xbox.h | 2 +- include/usbh_driver_hid_mouse.h | 2 +- include/usbh_driver_hub.h | 2 +- include/usbh_hubbed.h | 120 ------- include/usbh_lld_stm32f4.h | 2 +- src/demo.c | 2 +- src/usart_helpers.h | 2 +- src/usbh_core.c | 632 ++++++++++++++++++++++++++++++++++++ src/usbh_driver_hid_mouse.c | 4 +- src/usbh_driver_hub.c | 2 +- src/usbh_hubbed.c | 632 ------------------------------------ 14 files changed, 763 insertions(+), 763 deletions(-) create mode 100644 include/usbh_core.h delete mode 100644 include/usbh_hubbed.h create mode 100644 src/usbh_core.c delete mode 100644 src/usbh_hubbed.c diff --git a/include/driver/usbh_device_driver.h b/include/driver/usbh_device_driver.h index 4f0ecea..2c67129 100644 --- a/include/driver/usbh_device_driver.h +++ b/include/driver/usbh_device_driver.h @@ -24,7 +24,7 @@ #define USBH_DEVICE_DRIVER_ #include "usbh_config.h" -#include "usbh_hubbed.h" +#include "usbh_core.h" #include diff --git a/include/usbh_core.h b/include/usbh_core.h new file mode 100644 index 0000000..2315778 --- /dev/null +++ b/include/usbh_core.h @@ -0,0 +1,120 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#ifndef USBH_CORE_ +#define USBH_CORE_ + +#include "usbh_config.h" + +#include +#include + +/* This must be placed around external function declaration for C++ + * support. */ +#ifdef __cplusplus +# define BEGIN_DECLS extern "C" { +# define END_DECLS } +#else +# define BEGIN_DECLS +# define END_DECLS +#endif + +BEGIN_DECLS + +/// set to -1 for unused items ("don't care" functionality) @see find_driver() +struct _usbh_dev_driver_info { + int32_t deviceClass; + int32_t deviceSubClass; + int32_t deviceProtocol; + int32_t idVendor; + int32_t idProduct; + int32_t ifaceClass; + int32_t ifaceSubClass; + int32_t ifaceProtocol; +}; +typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t; + +struct _usbh_dev_driver { + /** + * @brief init is initialization routine of the device driver + * + * This function is called during the initialization of the device driver + */ + void *(*init)(void *usbh_dev); + + /** + * @brief analyze descriptor + * @param[in/out] drvdata is the device driver's private data + * @param[in] descriptor is the pointer to the descriptor that should + * be parsed in order to prepare driver to be loaded + * + * @retval true when the enumeration is complete and the driver is ready to be used + * @retval false when the device driver is not ready to be used + * + * This should be used for getting correct endpoint numbers, getting maximum sizes of endpoints. + * Should return true, when no more data is needed. + * + */ + bool (*analyze_descriptor)(void *drvdata, void *descriptor); + + /** + * @brief poll method is called periodically by the library core (@see usbh_poll()) + * @param[in/out] drvdata is the device driver's private data + * @param[in] time_curr_us current timestamp in microseconds + */ + void (*poll)(void *drvdata, uint32_t time_curr_us); + + /** + * @brief unloads the device driver + * @param[in/out] drvdata is the device driver's private data + * + * This should free any data associated with this device + */ + void (*remove)(void *drvdata); + + /** + * @brief info - compatibility information about the driver. It is used by the core during device enumeration (@see find_driver()) + */ + const usbh_dev_driver_info_t * const info; +}; +typedef struct _usbh_dev_driver usbh_dev_driver_t; + +/** + * @brief usbh_init + * @param low_level_drivers list of the low level drivers to be used by this library + * @param device_drivers list of the device drivers that could be used with attached devices + */ +void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]); + +/** + * @brief usbh_poll + * @param time_curr_us - use monotically rising time + * + * time_curr_us: + * * can overflow, in time of this writing, after 1s + * * unit is microseconds + */ +void usbh_poll(uint32_t time_curr_us); + +END_DECLS + +#endif // USBH_CORE_ diff --git a/include/usbh_driver_ac_midi.h b/include/usbh_driver_ac_midi.h index 0993589..c692a64 100644 --- a/include/usbh_driver_ac_midi.h +++ b/include/usbh_driver_ac_midi.h @@ -23,7 +23,7 @@ #ifndef USBH_DRIVER_AC_MIDI_ #define USBH_DRIVER_AC_MIDI_ -#include "usbh_hubbed.h" +#include "usbh_core.h" #include diff --git a/include/usbh_driver_gp_xbox.h b/include/usbh_driver_gp_xbox.h index 90d0ca1..32aed8a 100644 --- a/include/usbh_driver_gp_xbox.h +++ b/include/usbh_driver_gp_xbox.h @@ -23,7 +23,7 @@ #ifndef USBH_DRIVER_GP_XBOX_ #define USBH_DRIVER_GP_XBOX_ -#include "usbh_hubbed.h" +#include "usbh_core.h" #include diff --git a/include/usbh_driver_hid_mouse.h b/include/usbh_driver_hid_mouse.h index de7707c..b60046a 100644 --- a/include/usbh_driver_hid_mouse.h +++ b/include/usbh_driver_hid_mouse.h @@ -23,7 +23,7 @@ #ifndef USBH_DRIVER_HID_MOUSE_ #define USBH_DRIVER_HID_MOUSE_ -#include "usbh_hubbed.h" +#include "usbh_core.h" #include diff --git a/include/usbh_driver_hub.h b/include/usbh_driver_hub.h index 8555f79..1066074 100644 --- a/include/usbh_driver_hub.h +++ b/include/usbh_driver_hub.h @@ -23,7 +23,7 @@ #ifndef USBH_DRIVER_HUB_ #define USBH_DRIVER_HUB_ -#include "usbh_hubbed.h" +#include "usbh_core.h" BEGIN_DECLS diff --git a/include/usbh_hubbed.h b/include/usbh_hubbed.h deleted file mode 100644 index ca4a489..0000000 --- a/include/usbh_hubbed.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of the libusbhost library - * hosted at http://github.com/libusbhost/libusbhost - * - * Copyright (C) 2015 Amir Hammad - * - * - * libusbhost is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - * - */ - -#ifndef USBH_HUBBED_ -#define USBH_HUBBED_ - -#include "usbh_config.h" - -#include -#include - -/* This must be placed around external function declaration for C++ - * support. */ -#ifdef __cplusplus -# define BEGIN_DECLS extern "C" { -# define END_DECLS } -#else -# define BEGIN_DECLS -# define END_DECLS -#endif - -BEGIN_DECLS - -/// set to -1 for unused items ("don't care" functionality) @see find_driver() -struct _usbh_dev_driver_info { - int32_t deviceClass; - int32_t deviceSubClass; - int32_t deviceProtocol; - int32_t idVendor; - int32_t idProduct; - int32_t ifaceClass; - int32_t ifaceSubClass; - int32_t ifaceProtocol; -}; -typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t; - -struct _usbh_dev_driver { - /** - * @brief init is initialization routine of the device driver - * - * This function is called during the initialization of the device driver - */ - void *(*init)(void *usbh_dev); - - /** - * @brief analyze descriptor - * @param[in/out] drvdata is the device driver's private data - * @param[in] descriptor is the pointer to the descriptor that should - * be parsed in order to prepare driver to be loaded - * - * @retval true when the enumeration is complete and the driver is ready to be used - * @retval false when the device driver is not ready to be used - * - * This should be used for getting correct endpoint numbers, getting maximum sizes of endpoints. - * Should return true, when no more data is needed. - * - */ - bool (*analyze_descriptor)(void *drvdata, void *descriptor); - - /** - * @brief poll method is called periodically by the library core (@see usbh_poll()) - * @param[in/out] drvdata is the device driver's private data - * @param[in] time_curr_us current timestamp in microseconds - */ - void (*poll)(void *drvdata, uint32_t time_curr_us); - - /** - * @brief unloads the device driver - * @param[in/out] drvdata is the device driver's private data - * - * This should free any data associated with this device - */ - void (*remove)(void *drvdata); - - /** - * @brief info - compatibility information about the driver. It is used by the core during device enumeration (@see find_driver()) - */ - const usbh_dev_driver_info_t * const info; -}; -typedef struct _usbh_dev_driver usbh_dev_driver_t; - -/** - * @brief usbh_init - * @param low_level_drivers list of the low level drivers to be used by this library - * @param device_drivers list of the device drivers that could be used with attached devices - */ -void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]); - -/** - * @brief usbh_poll - * @param time_curr_us - use monotically rising time - * - * time_curr_us: - * * can overflow, in time of this writing, after 1s - * * unit is microseconds - */ -void usbh_poll(uint32_t time_curr_us); - -END_DECLS - -#endif diff --git a/include/usbh_lld_stm32f4.h b/include/usbh_lld_stm32f4.h index a8f7b0a..ead40cd 100644 --- a/include/usbh_lld_stm32f4.h +++ b/include/usbh_lld_stm32f4.h @@ -23,7 +23,7 @@ #ifndef USBH_LLD_STM32F4_H_ #define USBH_LLD_STM32F4_H_ -#include "usbh_hubbed.h" +#include "usbh_core.h" #include diff --git a/src/demo.c b/src/demo.c index f6cccf5..295013a 100644 --- a/src/demo.c +++ b/src/demo.c @@ -21,7 +21,7 @@ */ #include "usart_helpers.h" /// provides LOG_PRINTF macros used for debugging -#include "usbh_hubbed.h" /// provides usbh_init() and usbh_poll() +#include "usbh_core.h" /// provides usbh_init() and usbh_poll() #include "usbh_lld_stm32f4.h" /// provides low level usb host driver for stm32f4 platform #include "usbh_driver_hid_mouse.h" /// provides usb device driver Human Interface Device - type mouse #include "usbh_driver_hub.h" /// provides usb full speed hub driver (Low speed devices on hub are not supported) diff --git a/src/usart_helpers.h b/src/usart_helpers.h index eef43fa..d36f689 100644 --- a/src/usart_helpers.h +++ b/src/usart_helpers.h @@ -23,7 +23,7 @@ #ifndef USBH_USART_HELPERS_H #define USBH_USART_HELPERS_H -#include "usbh_hubbed.h" +#include "usbh_core.h" #include #include diff --git a/src/usbh_core.c b/src/usbh_core.c new file mode 100644 index 0000000..82f080f --- /dev/null +++ b/src/usbh_core.c @@ -0,0 +1,632 @@ +/* + * This file is part of the libusbhost library + * hosted at http://github.com/libusbhost/libusbhost + * + * Copyright (C) 2015 Amir Hammad + * + * + * libusbhost is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + +#include "usbh_config.h" +#include "usbh_lld_stm32f4.h" +#include "driver/usbh_device_driver.h" +#include "usart_helpers.h" + +#include +#include + +static struct { + bool enumeration_run; + const usbh_low_level_driver_t * const *lld_drivers; + const usbh_dev_driver_t * const *dev_drivers; + int8_t address_temporary; +} usbh_data = {0}; + +static void set_enumeration(void) +{ + usbh_data.enumeration_run = true; +} + +static void reset_enumeration(void) +{ + usbh_data.enumeration_run = false; +} + +static bool enumeration(void) +{ + return usbh_data.enumeration_run; +} + +/** + * + */ +static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * device_info) +{ + +#define CHECK_PARTIAL_COMPATIBILITY(what) \ + if (usbh_data.dev_drivers[i]->info->what != -1\ + && device_info->what != usbh_data.dev_drivers[i]->info->what) {\ + i++;\ + continue;\ + } + + + int i = 0; + + while (usbh_data.dev_drivers[i]) { + + CHECK_PARTIAL_COMPATIBILITY(ifaceClass); + CHECK_PARTIAL_COMPATIBILITY(ifaceSubClass); + CHECK_PARTIAL_COMPATIBILITY(ifaceProtocol); + CHECK_PARTIAL_COMPATIBILITY(deviceClass); + CHECK_PARTIAL_COMPATIBILITY(deviceSubClass); + CHECK_PARTIAL_COMPATIBILITY(deviceProtocol); + CHECK_PARTIAL_COMPATIBILITY(idVendor); + CHECK_PARTIAL_COMPATIBILITY(idProduct); + + return usbh_data.dev_drivers[i]; + } + return 0; +#undef CHECK_PARTIAL_COMPATIBILITY +} + + +static void device_register(void *descriptors, uint16_t descriptors_len, usbh_device_t *dev) +{ + uint32_t i = 0; + dev->drv = 0; + uint8_t *buf = (uint8_t *)descriptors; + + dev->drv = 0; + dev->drvdata = 0; + + uint8_t desc_len = buf[i]; + uint8_t desc_type = buf[i + 1]; + + usbh_dev_driver_info_t device_info; + if (desc_type == USB_DT_DEVICE) { + struct usb_device_descriptor *device_desc = (void*)&buf[i]; + LOG_PRINTF("DEVICE DESCRIPTOR"); + device_info.deviceClass = device_desc->bDeviceClass; + device_info.deviceSubClass = device_desc->bDeviceSubClass; + device_info.deviceProtocol = device_desc->bDeviceProtocol; + device_info.idVendor = device_desc->idVendor; + device_info.idProduct = device_desc->idProduct; + } else { + LOG_PRINTF("INVALID descriptors pointer - fatal error"); + return; + } + + + while (i < descriptors_len) { + desc_len = buf[i]; + desc_type = buf[i + 1]; + switch (desc_type) { + case USB_DT_INTERFACE: + { + LOG_PRINTF("INTERFACE_DESCRIPTOR\n"); + struct usb_interface_descriptor *iface = (void*)&buf[i]; + device_info.ifaceClass = iface->bInterfaceClass; + device_info.ifaceSubClass = iface->bInterfaceSubClass; + device_info.ifaceProtocol = iface->bInterfaceProtocol; + const usbh_dev_driver_t *driver = find_driver(&device_info); + if (driver) { + dev->drv = driver; + dev->drvdata = dev->drv->init(dev); + if (!dev->drvdata) { + LOG_PRINTF("CANT TOUCH THIS"); + } + break; + } + } + break; + default: + break; + } + + if (desc_len == 0) { + LOG_PRINTF("PROBLEM WITH PARSE %d\n",i); + return; + } + i += desc_len; + + } + + if (dev->drv && dev->drvdata) { + // analyze descriptors + LOG_PRINTF("ANALYZE"); + i = 0; + while (i < descriptors_len) { + desc_len = buf[i]; + void *drvdata = dev->drvdata; + LOG_PRINTF("[%d]",buf[i+1]); + if (dev->drv->analyze_descriptor(drvdata, &buf[i])) { + LOG_PRINTF("Device Initialized\n"); + return; + } + i += desc_len; + } + } + LOG_PRINTF("Device NOT Initialized\n"); +} + +void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]) +{ + if (!low_level_drivers) { + return; + } + + usbh_data.lld_drivers = (const usbh_low_level_driver_t **)low_level_drivers; + usbh_data.dev_drivers = device_drivers; + + // TODO: init structures + uint32_t k = 0; + while (usbh_data.lld_drivers[k]) { + LOG_PRINTF("DRIVER %d\n", k); + + usbh_device_t * usbh_device = + ((usbh_generic_data_t *)(usbh_data.lld_drivers[k])->driver_data)->usbh_device; + uint32_t i; + for (i = 0; i < USBH_MAX_DEVICES; i++) { + //~ LOG_PRINTF("%p ", &usbh_device[i]); + usbh_device[i].address = -1; + usbh_device[i].drv = 0; + usbh_device[i].drvdata = 0; + } + LOG_PRINTF("DRIVER %d", k); + usbh_data.lld_drivers[k]->init(usbh_data.lld_drivers[k]->driver_data); + + k++; + } + +} + +/* + * NEW ENUMERATE + * + */ +void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev) +{ + usbh_packet_t packet; + + packet.data = data; + packet.datalen = datalen; + packet.address = dev->address; + packet.endpoint_address = 0; + packet.endpoint_size_max = dev->packet_size_max0; + packet.endpoint_type = USBH_ENDPOINT_TYPE_CONTROL; + packet.speed = dev->speed; + packet.callback = callback; + packet.callback_arg = dev; + packet.toggle = &dev->toggle0; + + usbh_write(dev, &packet); + LOG_PRINTF("WR@device...%d | \n", dev->address); +} + +void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev) +{ + usbh_packet_t packet; + + packet.data = data; + packet.datalen = datalen; + packet.address = dev->address; + packet.endpoint_address = 0; + packet.endpoint_size_max = dev->packet_size_max0; + packet.endpoint_type = USBH_ENDPOINT_TYPE_CONTROL; + packet.speed = dev->speed; + packet.callback = callback; + packet.callback_arg = dev; + packet.toggle = &dev->toggle0; + + usbh_read(dev, &packet); + LOG_PRINTF("RD@device...%d | \n", dev->address); +} + + + +bool usbh_enum_available(void) +{ + return !enumeration(); +} + +/** + * Returns 0 on error + * device otherwise + */ +usbh_device_t *usbh_get_free_device(const usbh_device_t *dev) +{ + const usbh_low_level_driver_t *lld = dev->lld; + usbh_generic_data_t *lld_data = lld->driver_data; + usbh_device_t *usbh_device = lld_data->usbh_device; + + uint8_t i; + LOG_PRINTF("DEV ADDRESS%d\n", dev->address); + for (i = 0; i < USBH_MAX_DEVICES; i++) { + if (usbh_device[i].address < 0) { + LOG_PRINTF("\t\t\t\t\tFOUND: %d", i); + usbh_device[i].address = i+1; + return &usbh_device[i]; + } else { + LOG_PRINTF("address: %d\n\n\n", usbh_device[i].address); + } + } + + return 0; +} + +static void device_enumeration_terminate(usbh_device_t *dev) +{ + reset_enumeration(); + dev->state = 0; + dev->address = -1; +} + +/* Do not call this function directly, + * only via callback passing into low-level function + * If you must, call it carefully ;) + */ +static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) +{ + const usbh_low_level_driver_t *lld = dev->lld; + usbh_generic_data_t *lld_data = lld->driver_data; + uint8_t *usbh_buffer = lld_data->usbh_buffer; + uint8_t state_start = dev->state; // Detection of hang +// LOG_PRINTF("\nSTATE: %d\n", state); + switch (dev->state) { + case 1: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + dev->state++; + LOG_PRINTF("::%d::", dev->address); + device_xfer_control_read(0, 0, device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 2: + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + if (dev->address == 0) { + dev->address = usbh_data.address_temporary; + LOG_PRINTF("ADDR: %d\n", dev->address); + } + + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b10000000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = USB_DT_DEVICE << 8; + setup_data.wIndex = 0; + setup_data.wLength = USB_DT_DEVICE_SIZE; + + dev->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + break; + + case 3: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + dev->state++; + device_xfer_control_read(&usbh_buffer[0], USB_DT_DEVICE_SIZE, + device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + dev->state = 2; + + // WARNING: Recursion + // .. but should work + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + device_enumerate(dev, cb_data); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 4: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_device_descriptor *ddt = + (struct usb_device_descriptor *)&usbh_buffer[0]; + dev->packet_size_max0 = ddt->bMaxPacketSize0; + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b10000000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = USB_DT_CONFIGURATION << 8; + setup_data.wIndex = 0; + setup_data.wLength = ddt->bMaxPacketSize0;//USB_DT_CONFIGURATION_SIZE; + + dev->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + if (cb_data.transferred_length >= 8) { + struct usb_device_descriptor *ddt = + (struct usb_device_descriptor *)&usbh_buffer[0]; + dev->packet_size_max0 = ddt->bMaxPacketSize0; + dev->state = 2; + + // WARNING: Recursion + // .. but should work + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + device_enumerate(dev, cb_data); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 5: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + dev->state++; + device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE], + dev->packet_size_max0, device_enumerate, dev); + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 6: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + struct usb_setup_data setup_data; + LOG_PRINTF("WRITE: LEN: %d", cdt->wTotalLength); + setup_data.bmRequestType = 0b10000000; + setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; + setup_data.wValue = USB_DT_CONFIGURATION << 8; + setup_data.wIndex = 0; + setup_data.wLength = cdt->wTotalLength; + + dev->state++; + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + if (cb_data.transferred_length >= USB_DT_CONFIGURATION_SIZE) { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + if (cb_data.transferred_length <= cdt->wTotalLength) { + dev->state = 8; + + // WARNING: Recursion + // .. but should work + cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; + device_enumerate(dev, cb_data); + } + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 7: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + dev->state++; + device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE], + cdt->wTotalLength, device_enumerate, dev); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + } + break; + + case 8: + { + switch (cb_data.status) { + case USBH_PACKET_CALLBACK_STATUS_OK: + { + struct usb_config_descriptor *cdt = + (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; + LOG_PRINTF("TOTAL_LENGTH: %d\n", cdt->wTotalLength); + device_register(usbh_buffer, cdt->wTotalLength + USB_DT_DEVICE_SIZE, dev); + dev->state++; + + reset_enumeration(); + } + break; + + case USBH_PACKET_CALLBACK_STATUS_EFATAL: + case USBH_PACKET_CALLBACK_STATUS_EAGAIN: + case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: + device_enumeration_terminate(dev); + ERROR(cb_data.status); + break; + } + + } + break; + + default: + LOG_PRINTF("Error: Unknown state "__FILE__"/%d\n", __LINE__); + break; + } + + if (state_start == dev->state) { + LOG_PRINTF("\n !HANG %d\n", state_start); + } +} + +void device_enumeration_start(usbh_device_t *dev) +{ + set_enumeration(); + dev->state = 1; + + // save address + uint8_t address = dev->address; + dev->address = 0; + + if (dev->speed == USBH_SPEED_LOW) { + dev->packet_size_max0 = 8; + } else { + dev->packet_size_max0 = 64; + } + + usbh_data.address_temporary = address; + + LOG_PRINTF("\n\n\n ENUMERATION OF DEVICE@%d STARTED \n\n", address); + + struct usb_setup_data setup_data; + + setup_data.bmRequestType = 0b00000000; + setup_data.bRequest = USB_REQ_SET_ADDRESS; + setup_data.wValue = address; + setup_data.wIndex = 0; + setup_data.wLength = 0; + + device_xfer_control_write(&setup_data, sizeof(setup_data), + device_enumerate, dev); +} + +/** + * Should be called with at least 1kHz frequency + * + */ +void usbh_poll(uint32_t time_curr_us) +{ + uint32_t k = 0; + while (usbh_data.lld_drivers[k]) { + usbh_device_t * usbh_device = + ((usbh_generic_data_t *)(usbh_data.lld_drivers[k]->driver_data))->usbh_device; + usbh_generic_data_t *lld_data = usbh_data.lld_drivers[k]->driver_data; + + enum USBH_POLL_STATUS poll_status = + usbh_data.lld_drivers[k]->poll(lld_data, time_curr_us); + + switch (poll_status) { + case USBH_POLL_STATUS_DEVICE_CONNECTED: + // New device found + LOG_PRINTF("\nDEVICE FOUND\n"); + usbh_device[0].lld = usbh_data.lld_drivers[k]; + usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data); + usbh_device[0].address = 1; + + device_enumeration_start(&usbh_device[0]); + break; + + case USBH_POLL_STATUS_DEVICE_DISCONNECTED: + { + // Device disconnected + if (usbh_device[0].drv && usbh_device[0].drvdata) { + usbh_device[0].drv->remove(usbh_device[0].drvdata); + } + usbh_device[0].drv = 0; + usbh_device[0].drvdata = 0; + + uint32_t i; + for (i = 1; i < USBH_MAX_DEVICES; i++) { + usbh_device[i].address = -1; + usbh_device[i].drv = 0; + usbh_device[i].drvdata = 0; + } + } + break; + + default: + break; + } + + if (lld_data->usbh_device[0].drv && usbh_device[0].drvdata) { + usbh_device[0].drv->poll(usbh_device[0].drvdata, time_curr_us); + } + + k++; + } +} + +void usbh_read(usbh_device_t *dev, usbh_packet_t *packet) +{ + const usbh_low_level_driver_t *lld = dev->lld; + lld->read(lld->driver_data, packet); +} + +void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet) +{ + const usbh_low_level_driver_t *lld = dev->lld; + lld->write(lld->driver_data, packet); +} + diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c index 8324999..5265329 100644 --- a/src/usbh_driver_hid_mouse.c +++ b/src/usbh_driver_hid_mouse.c @@ -20,7 +20,7 @@ * */ -#include "usbh_hubbed.h" +#include "usbh_core.h" #include "driver/usbh_device_driver.h" #include "usbh_driver_hid_mouse.h" #include "usart_helpers.h" @@ -232,7 +232,7 @@ static void read_mouse_in(void *drvdata) } /** - * \param time_curr_us - monotically rising time (see usbh_hubbed.h) + * @param time_curr_us - monotically rising time (@see usbh_poll()) * unit is microseconds */ static void poll(void *drvdata, uint32_t time_curr_us) diff --git a/src/usbh_driver_hub.c b/src/usbh_driver_hub.c index eaaf896..7bd58cc 100644 --- a/src/usbh_driver_hub.c +++ b/src/usbh_driver_hub.c @@ -764,7 +764,7 @@ static void read_ep1(void *drvdata) } /** - * \param time_curr_us - monotically rising time (see usbh_hubbed.h) + * @param time_curr_us - monotically rising time (@see usbh_poll()) * unit is microseconds */ static void poll(void *drvdata, uint32_t time_curr_us) diff --git a/src/usbh_hubbed.c b/src/usbh_hubbed.c deleted file mode 100644 index 82f080f..0000000 --- a/src/usbh_hubbed.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * This file is part of the libusbhost library - * hosted at http://github.com/libusbhost/libusbhost - * - * Copyright (C) 2015 Amir Hammad - * - * - * libusbhost is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - * - */ - -#include "usbh_config.h" -#include "usbh_lld_stm32f4.h" -#include "driver/usbh_device_driver.h" -#include "usart_helpers.h" - -#include -#include - -static struct { - bool enumeration_run; - const usbh_low_level_driver_t * const *lld_drivers; - const usbh_dev_driver_t * const *dev_drivers; - int8_t address_temporary; -} usbh_data = {0}; - -static void set_enumeration(void) -{ - usbh_data.enumeration_run = true; -} - -static void reset_enumeration(void) -{ - usbh_data.enumeration_run = false; -} - -static bool enumeration(void) -{ - return usbh_data.enumeration_run; -} - -/** - * - */ -static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * device_info) -{ - -#define CHECK_PARTIAL_COMPATIBILITY(what) \ - if (usbh_data.dev_drivers[i]->info->what != -1\ - && device_info->what != usbh_data.dev_drivers[i]->info->what) {\ - i++;\ - continue;\ - } - - - int i = 0; - - while (usbh_data.dev_drivers[i]) { - - CHECK_PARTIAL_COMPATIBILITY(ifaceClass); - CHECK_PARTIAL_COMPATIBILITY(ifaceSubClass); - CHECK_PARTIAL_COMPATIBILITY(ifaceProtocol); - CHECK_PARTIAL_COMPATIBILITY(deviceClass); - CHECK_PARTIAL_COMPATIBILITY(deviceSubClass); - CHECK_PARTIAL_COMPATIBILITY(deviceProtocol); - CHECK_PARTIAL_COMPATIBILITY(idVendor); - CHECK_PARTIAL_COMPATIBILITY(idProduct); - - return usbh_data.dev_drivers[i]; - } - return 0; -#undef CHECK_PARTIAL_COMPATIBILITY -} - - -static void device_register(void *descriptors, uint16_t descriptors_len, usbh_device_t *dev) -{ - uint32_t i = 0; - dev->drv = 0; - uint8_t *buf = (uint8_t *)descriptors; - - dev->drv = 0; - dev->drvdata = 0; - - uint8_t desc_len = buf[i]; - uint8_t desc_type = buf[i + 1]; - - usbh_dev_driver_info_t device_info; - if (desc_type == USB_DT_DEVICE) { - struct usb_device_descriptor *device_desc = (void*)&buf[i]; - LOG_PRINTF("DEVICE DESCRIPTOR"); - device_info.deviceClass = device_desc->bDeviceClass; - device_info.deviceSubClass = device_desc->bDeviceSubClass; - device_info.deviceProtocol = device_desc->bDeviceProtocol; - device_info.idVendor = device_desc->idVendor; - device_info.idProduct = device_desc->idProduct; - } else { - LOG_PRINTF("INVALID descriptors pointer - fatal error"); - return; - } - - - while (i < descriptors_len) { - desc_len = buf[i]; - desc_type = buf[i + 1]; - switch (desc_type) { - case USB_DT_INTERFACE: - { - LOG_PRINTF("INTERFACE_DESCRIPTOR\n"); - struct usb_interface_descriptor *iface = (void*)&buf[i]; - device_info.ifaceClass = iface->bInterfaceClass; - device_info.ifaceSubClass = iface->bInterfaceSubClass; - device_info.ifaceProtocol = iface->bInterfaceProtocol; - const usbh_dev_driver_t *driver = find_driver(&device_info); - if (driver) { - dev->drv = driver; - dev->drvdata = dev->drv->init(dev); - if (!dev->drvdata) { - LOG_PRINTF("CANT TOUCH THIS"); - } - break; - } - } - break; - default: - break; - } - - if (desc_len == 0) { - LOG_PRINTF("PROBLEM WITH PARSE %d\n",i); - return; - } - i += desc_len; - - } - - if (dev->drv && dev->drvdata) { - // analyze descriptors - LOG_PRINTF("ANALYZE"); - i = 0; - while (i < descriptors_len) { - desc_len = buf[i]; - void *drvdata = dev->drvdata; - LOG_PRINTF("[%d]",buf[i+1]); - if (dev->drv->analyze_descriptor(drvdata, &buf[i])) { - LOG_PRINTF("Device Initialized\n"); - return; - } - i += desc_len; - } - } - LOG_PRINTF("Device NOT Initialized\n"); -} - -void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]) -{ - if (!low_level_drivers) { - return; - } - - usbh_data.lld_drivers = (const usbh_low_level_driver_t **)low_level_drivers; - usbh_data.dev_drivers = device_drivers; - - // TODO: init structures - uint32_t k = 0; - while (usbh_data.lld_drivers[k]) { - LOG_PRINTF("DRIVER %d\n", k); - - usbh_device_t * usbh_device = - ((usbh_generic_data_t *)(usbh_data.lld_drivers[k])->driver_data)->usbh_device; - uint32_t i; - for (i = 0; i < USBH_MAX_DEVICES; i++) { - //~ LOG_PRINTF("%p ", &usbh_device[i]); - usbh_device[i].address = -1; - usbh_device[i].drv = 0; - usbh_device[i].drvdata = 0; - } - LOG_PRINTF("DRIVER %d", k); - usbh_data.lld_drivers[k]->init(usbh_data.lld_drivers[k]->driver_data); - - k++; - } - -} - -/* - * NEW ENUMERATE - * - */ -void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev) -{ - usbh_packet_t packet; - - packet.data = data; - packet.datalen = datalen; - packet.address = dev->address; - packet.endpoint_address = 0; - packet.endpoint_size_max = dev->packet_size_max0; - packet.endpoint_type = USBH_ENDPOINT_TYPE_CONTROL; - packet.speed = dev->speed; - packet.callback = callback; - packet.callback_arg = dev; - packet.toggle = &dev->toggle0; - - usbh_write(dev, &packet); - LOG_PRINTF("WR@device...%d | \n", dev->address); -} - -void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev) -{ - usbh_packet_t packet; - - packet.data = data; - packet.datalen = datalen; - packet.address = dev->address; - packet.endpoint_address = 0; - packet.endpoint_size_max = dev->packet_size_max0; - packet.endpoint_type = USBH_ENDPOINT_TYPE_CONTROL; - packet.speed = dev->speed; - packet.callback = callback; - packet.callback_arg = dev; - packet.toggle = &dev->toggle0; - - usbh_read(dev, &packet); - LOG_PRINTF("RD@device...%d | \n", dev->address); -} - - - -bool usbh_enum_available(void) -{ - return !enumeration(); -} - -/** - * Returns 0 on error - * device otherwise - */ -usbh_device_t *usbh_get_free_device(const usbh_device_t *dev) -{ - const usbh_low_level_driver_t *lld = dev->lld; - usbh_generic_data_t *lld_data = lld->driver_data; - usbh_device_t *usbh_device = lld_data->usbh_device; - - uint8_t i; - LOG_PRINTF("DEV ADDRESS%d\n", dev->address); - for (i = 0; i < USBH_MAX_DEVICES; i++) { - if (usbh_device[i].address < 0) { - LOG_PRINTF("\t\t\t\t\tFOUND: %d", i); - usbh_device[i].address = i+1; - return &usbh_device[i]; - } else { - LOG_PRINTF("address: %d\n\n\n", usbh_device[i].address); - } - } - - return 0; -} - -static void device_enumeration_terminate(usbh_device_t *dev) -{ - reset_enumeration(); - dev->state = 0; - dev->address = -1; -} - -/* Do not call this function directly, - * only via callback passing into low-level function - * If you must, call it carefully ;) - */ -static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) -{ - const usbh_low_level_driver_t *lld = dev->lld; - usbh_generic_data_t *lld_data = lld->driver_data; - uint8_t *usbh_buffer = lld_data->usbh_buffer; - uint8_t state_start = dev->state; // Detection of hang -// LOG_PRINTF("\nSTATE: %d\n", state); - switch (dev->state) { - case 1: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - dev->state++; - LOG_PRINTF("::%d::", dev->address); - device_xfer_control_read(0, 0, device_enumerate, dev); - break; - - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - } - break; - - case 2: - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - if (dev->address == 0) { - dev->address = usbh_data.address_temporary; - LOG_PRINTF("ADDR: %d\n", dev->address); - } - - struct usb_setup_data setup_data; - - setup_data.bmRequestType = 0b10000000; - setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; - setup_data.wValue = USB_DT_DEVICE << 8; - setup_data.wIndex = 0; - setup_data.wLength = USB_DT_DEVICE_SIZE; - - dev->state++; - device_xfer_control_write(&setup_data, sizeof(setup_data), - device_enumerate, dev); - break; - - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - break; - - case 3: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - dev->state++; - device_xfer_control_read(&usbh_buffer[0], USB_DT_DEVICE_SIZE, - device_enumerate, dev); - break; - - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - dev->state = 2; - - // WARNING: Recursion - // .. but should work - cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; - device_enumerate(dev, cb_data); - break; - - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - } - break; - - case 4: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - { - struct usb_device_descriptor *ddt = - (struct usb_device_descriptor *)&usbh_buffer[0]; - dev->packet_size_max0 = ddt->bMaxPacketSize0; - struct usb_setup_data setup_data; - - setup_data.bmRequestType = 0b10000000; - setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; - setup_data.wValue = USB_DT_CONFIGURATION << 8; - setup_data.wIndex = 0; - setup_data.wLength = ddt->bMaxPacketSize0;//USB_DT_CONFIGURATION_SIZE; - - dev->state++; - device_xfer_control_write(&setup_data, sizeof(setup_data), - device_enumerate, dev); - } - break; - - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - if (cb_data.transferred_length >= 8) { - struct usb_device_descriptor *ddt = - (struct usb_device_descriptor *)&usbh_buffer[0]; - dev->packet_size_max0 = ddt->bMaxPacketSize0; - dev->state = 2; - - // WARNING: Recursion - // .. but should work - cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; - device_enumerate(dev, cb_data); - } - break; - - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - } - break; - - case 5: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - dev->state++; - device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE], - dev->packet_size_max0, device_enumerate, dev); - break; - - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - } - break; - - case 6: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - { - struct usb_config_descriptor *cdt = - (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; - struct usb_setup_data setup_data; - LOG_PRINTF("WRITE: LEN: %d", cdt->wTotalLength); - setup_data.bmRequestType = 0b10000000; - setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; - setup_data.wValue = USB_DT_CONFIGURATION << 8; - setup_data.wIndex = 0; - setup_data.wLength = cdt->wTotalLength; - - dev->state++; - device_xfer_control_write(&setup_data, sizeof(setup_data), - device_enumerate, dev); - } - break; - - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - if (cb_data.transferred_length >= USB_DT_CONFIGURATION_SIZE) { - struct usb_config_descriptor *cdt = - (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; - if (cb_data.transferred_length <= cdt->wTotalLength) { - dev->state = 8; - - // WARNING: Recursion - // .. but should work - cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK; - device_enumerate(dev, cb_data); - } - } - break; - - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - } - break; - - case 7: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - { - struct usb_config_descriptor *cdt = - (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; - dev->state++; - device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE], - cdt->wTotalLength, device_enumerate, dev); - } - break; - - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - } - break; - - case 8: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - { - struct usb_config_descriptor *cdt = - (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE]; - LOG_PRINTF("TOTAL_LENGTH: %d\n", cdt->wTotalLength); - device_register(usbh_buffer, cdt->wTotalLength + USB_DT_DEVICE_SIZE, dev); - dev->state++; - - reset_enumeration(); - } - break; - - case USBH_PACKET_CALLBACK_STATUS_EFATAL: - case USBH_PACKET_CALLBACK_STATUS_EAGAIN: - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - device_enumeration_terminate(dev); - ERROR(cb_data.status); - break; - } - - } - break; - - default: - LOG_PRINTF("Error: Unknown state "__FILE__"/%d\n", __LINE__); - break; - } - - if (state_start == dev->state) { - LOG_PRINTF("\n !HANG %d\n", state_start); - } -} - -void device_enumeration_start(usbh_device_t *dev) -{ - set_enumeration(); - dev->state = 1; - - // save address - uint8_t address = dev->address; - dev->address = 0; - - if (dev->speed == USBH_SPEED_LOW) { - dev->packet_size_max0 = 8; - } else { - dev->packet_size_max0 = 64; - } - - usbh_data.address_temporary = address; - - LOG_PRINTF("\n\n\n ENUMERATION OF DEVICE@%d STARTED \n\n", address); - - struct usb_setup_data setup_data; - - setup_data.bmRequestType = 0b00000000; - setup_data.bRequest = USB_REQ_SET_ADDRESS; - setup_data.wValue = address; - setup_data.wIndex = 0; - setup_data.wLength = 0; - - device_xfer_control_write(&setup_data, sizeof(setup_data), - device_enumerate, dev); -} - -/** - * Should be called with at least 1kHz frequency - * - */ -void usbh_poll(uint32_t time_curr_us) -{ - uint32_t k = 0; - while (usbh_data.lld_drivers[k]) { - usbh_device_t * usbh_device = - ((usbh_generic_data_t *)(usbh_data.lld_drivers[k]->driver_data))->usbh_device; - usbh_generic_data_t *lld_data = usbh_data.lld_drivers[k]->driver_data; - - enum USBH_POLL_STATUS poll_status = - usbh_data.lld_drivers[k]->poll(lld_data, time_curr_us); - - switch (poll_status) { - case USBH_POLL_STATUS_DEVICE_CONNECTED: - // New device found - LOG_PRINTF("\nDEVICE FOUND\n"); - usbh_device[0].lld = usbh_data.lld_drivers[k]; - usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data); - usbh_device[0].address = 1; - - device_enumeration_start(&usbh_device[0]); - break; - - case USBH_POLL_STATUS_DEVICE_DISCONNECTED: - { - // Device disconnected - if (usbh_device[0].drv && usbh_device[0].drvdata) { - usbh_device[0].drv->remove(usbh_device[0].drvdata); - } - usbh_device[0].drv = 0; - usbh_device[0].drvdata = 0; - - uint32_t i; - for (i = 1; i < USBH_MAX_DEVICES; i++) { - usbh_device[i].address = -1; - usbh_device[i].drv = 0; - usbh_device[i].drvdata = 0; - } - } - break; - - default: - break; - } - - if (lld_data->usbh_device[0].drv && usbh_device[0].drvdata) { - usbh_device[0].drv->poll(usbh_device[0].drvdata, time_curr_us); - } - - k++; - } -} - -void usbh_read(usbh_device_t *dev, usbh_packet_t *packet) -{ - const usbh_low_level_driver_t *lld = dev->lld; - lld->read(lld->driver_data, packet); -} - -void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet) -{ - const usbh_low_level_driver_t *lld = dev->lld; - lld->write(lld->driver_data, packet); -} - -- cgit From 90d7268876ba52fa786f53683b04f08a6ef459ab Mon Sep 17 00:00:00 2001 From: Amir Hammad Date: Sat, 9 Jul 2016 00:19:22 +0200 Subject: Add doxyfile Signed-off-by: Amir Hammad --- .gitignore | 1 + Doxyfile | 2406 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 4 +- README.md | 3 + 4 files changed, 2413 insertions(+), 1 deletion(-) create mode 100644 Doxyfile diff --git a/.gitignore b/.gitignore index fdf34d4..3e83207 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ *.cproject *.project *.a +doc diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..4efb27b --- /dev/null +++ b/Doxyfile @@ -0,0 +1,2406 @@ +# Doxyfile 1.8.11 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "libusbhost" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = include include/driver + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, +# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c *.h + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /