Repository: insane-adding-machines/frosted Branch: master Commit: 5c3aa21f146a Files: 224 Total size: 1.5 MB Directory structure: gitextract_hhcit_l3/ ├── .gitignore ├── .gitmodules ├── .project ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── defconfig/ │ ├── lpc1769.config │ ├── lpc17xx.config │ ├── qemu-orig.config │ ├── qemu.config │ ├── qemunet.config │ ├── stm32f407-discovery.config │ ├── stm32f429i-discovery.config │ ├── stm32f746-discovery.config │ ├── stm32f746-nucleo.config │ └── stm32f769-discovery.config ├── gdbinit.bflt ├── gdbinit.mini ├── include/ │ └── frosted_api.h ├── kconfig/ │ ├── .gitignore │ ├── Kconfig │ ├── Makefile │ ├── Makefile.frosted │ ├── POTFILES.in │ ├── STM32F4x1Discovery.cfg │ ├── check.sh │ ├── conf.c │ ├── confdata.c │ ├── expr.c │ ├── expr.h │ ├── frosted.conf │ ├── gconf.c │ ├── gconf.glade │ ├── images.c │ ├── kxgettext.c │ ├── list.h │ ├── lkc.h │ ├── lkc_proto.h │ ├── lpc17xx.cfg │ ├── mconf.c │ ├── menu.c │ ├── merge_config.sh │ ├── nconf.c │ ├── nconf.gui.c │ ├── nconf.h │ ├── qconf.cc │ ├── qconf.h │ ├── qemu2.cfg │ ├── streamline_config.pl │ ├── symbol.c │ ├── util.c │ ├── zconf.gperf │ ├── zconf.hash.c_shipped │ ├── zconf.l │ ├── zconf.lex.c_shipped │ ├── zconf.tab.c_shipped │ └── zconf.y ├── kernel/ │ ├── Kconfig │ ├── adc.h │ ├── bflt.c │ ├── bflt.h │ ├── cdc_acm.h │ ├── cdc_ecm.h │ ├── cirbuf.c │ ├── cirbuf.h │ ├── crypto/ │ │ ├── aes.c │ │ ├── aes.h │ │ ├── misc.c │ │ ├── misc.h │ │ ├── sha256.c │ │ └── sha256.h │ ├── device.h │ ├── drivers/ │ │ ├── device.c │ │ ├── devusb_cdc_ecm.c │ │ ├── dma.h │ │ ├── dsp.h │ │ ├── eth.h │ │ ├── exti.c │ │ ├── exti.h │ │ ├── fbcon.c │ │ ├── fbcon.h │ │ ├── fonts.h │ │ ├── fortuna.c │ │ ├── framebuffer.h │ │ ├── frand.c │ │ ├── ft5336.c │ │ ├── gpio.c │ │ ├── gpio.h │ │ ├── i2c.h │ │ ├── ili9341.c │ │ ├── l3gd20.c │ │ ├── l3gd20.h │ │ ├── lis3dsh.c │ │ ├── lis3dsh.h │ │ ├── lm3s_eth.c │ │ ├── lsm303dlhc.c │ │ ├── lsm303dlhc.h │ │ ├── ltdc.h │ │ ├── mccog21.c │ │ ├── null.c │ │ ├── pty.c │ │ ├── pty.h │ │ ├── rng.h │ │ ├── sdio.h │ │ ├── sdram.h │ │ ├── socket_in.c │ │ ├── socket_in.h │ │ ├── socket_un.c │ │ ├── spi.h │ │ ├── stm32_dma.c │ │ ├── stm32_eth.c │ │ ├── stm32_i2c.c │ │ ├── stm32_lowpower.c │ │ ├── stm32_rng.c │ │ ├── stm32_sdio.c │ │ ├── stm32_sdio.h │ │ ├── stm32_spi.c │ │ ├── stm32_usb.c │ │ ├── stm32f4_adc.c │ │ ├── stm32f4_dsp.c │ │ ├── stm32f4_sdram.c │ │ ├── stm32f7_ltdc.c │ │ ├── stm32f7_sdram.c │ │ ├── stmpe811.c │ │ ├── stmpe811.h │ │ ├── tty_console.c │ │ ├── tty_console.h │ │ ├── uart.c │ │ ├── uart.h │ │ ├── uart_dev.h │ │ ├── usb/ │ │ │ ├── usb_kbd.c │ │ │ └── usbh_drivers.h │ │ ├── usb.h │ │ └── xadow_LED_5x7.c │ ├── fonts/ │ │ ├── cga_8x8.c │ │ ├── palette_256_xterm.c │ │ └── piccolo_7x6.c │ ├── fortuna.h │ ├── fpb.c │ ├── fpb.h │ ├── framebuffer.c │ ├── frand.h │ ├── frosted.c │ ├── frosted.h │ ├── fs/ │ │ ├── fatfs.c │ │ ├── fatfs.h │ │ ├── memfs.c │ │ ├── sysfs.c │ │ ├── xipfs.c │ │ └── xipfs.h │ ├── getaddrinfo.c │ ├── hardfault_debug.c │ ├── heap.h │ ├── interrupts.h │ ├── kprintf.c │ ├── kprintf.h │ ├── lm3s/ │ │ ├── Kconfig │ │ ├── lm3s.c │ │ ├── lm3s.ld.in │ │ └── lm3s6965evb.c │ ├── locks.c │ ├── locks.h │ ├── lowpower.h │ ├── lpc17xx/ │ │ ├── Kconfig │ │ ├── lpc1768mbed.c │ │ ├── lpc1769xpresso.c │ │ └── lpc17xx.ld.in │ ├── lpc17xx.h │ ├── malloc.c │ ├── malloc.h │ ├── module.c │ ├── mpu.c │ ├── mpu.h │ ├── mutex.S │ ├── net/ │ │ ├── Kconfig │ │ ├── if.h │ │ ├── pico_lock.c │ │ └── route.h │ ├── nrf51/ │ │ ├── Kconfig │ │ ├── blenanov1_5.c │ │ └── nrf51.ld.in │ ├── nrf52/ │ │ ├── Kconfig │ │ ├── blenanov2_0.c │ │ └── nrf52.ld.in │ ├── null.h │ ├── pico_port.h │ ├── pipe.c │ ├── scheduler.c │ ├── scheduler.h │ ├── semaphore.S │ ├── stm32f4/ │ │ ├── Kconfig │ │ ├── stm32f4.ld.in │ │ ├── stm32f407discovery.c │ │ ├── stm32f407diymore.c │ │ ├── stm32f411nucleo.c │ │ ├── stm32f429discovery.c │ │ ├── stm32f446nucleo.c │ │ ├── stm32f4x1discovery.c │ │ └── stm32f4xxpyboard.c │ ├── stm32f7/ │ │ ├── Kconfig │ │ ├── stm32f7.ld.in │ │ ├── stm32f746discovery.c │ │ ├── stm32f746nucleo-144.c │ │ └── stm32f769discovery.c │ ├── string.c │ ├── string.h │ ├── sys.c │ ├── syscall_table_gen.py │ ├── syscall_vector.c │ ├── systick.c │ ├── tasklet.c │ ├── term.c │ ├── vfs.c │ └── vfs.h ├── qemu.gdbinit ├── rules/ │ ├── arch.mk │ ├── config.mk │ ├── picotcp.mk │ └── userspace.mk ├── scripts/ │ ├── frosted-dev-setup │ └── frosted-qemu-setup └── xipfs.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Object files *.o *.ko *.obj *.elf *.bin # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex *.map # Debug files *.dSYM/ *.lst *.d tags #python compiled *.pyc #kconfig kconfig/.config kconfig/.config.old kconfig/.depend #generated files apps/apps.ld .gdbinit build/ kernel/syscall_table.c *.img *.ld ================================================ FILE: .gitmodules ================================================ [submodule "apps/busybox"] path = apps/busybox url = https://github.com/insane-adding-machines/busybox.git [submodule "kernel/net/picotcp"] path = kernel/net/picotcp url = https://github.com/danielinux/picotcp.git [submodule "frosted-userland"] path = frosted-userland url = https://github.com/insane-adding-machines/frosted-userland.git [submodule "kernel/frosted-headers"] path = kernel/frosted-headers url = https://github.com/insane-adding-machines/frosted-headers.git [submodule "kernel/unicore-mx"] path = kernel/unicore-mx url = https://github.com/insane-adding-machines/unicore-mx.git ================================================ FILE: .project ================================================ Frosted org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature ================================================ FILE: CODE_OF_CONDUCT.md ================================================ Code of Conduct Insane-adding-machines is a community organization, whose purpose is to promote the use of Free Software in the Internet of things. We value the involvement of everyone in this community. We are committed to creating a friendly and respectful place for learning, teaching and contributing. All participants in our events and communications are expected to show respect and courtesy to others. To make clear what is expected, everyone participating in activities within Insane-adding-machines is required to conform to the following Code of Conduct. This code of conduct applies to all spaces managed by Insane-adding-machines including, but not limited to, workshops, email lists, online forums, IRC channels and on GitHub. Code of Conduct =============== Insane-adding-machines are dedicated to providing a welcoming and supportive environment for all people, regardless of background or identity. However, we recognise that some groups in our community are subject to historical and ongoing discrimination, and may be vulnerable or disadvantaged. Membership in such a specific group can be on the basis of characteristics such as gender, sexual orientation, disability, physical appearance, body size, race, nationality, sex, colour, ethnic or social origin, pregnancy, citizenship, familial status, veteran status, genetic information, religion or belief, political or any other opinion, membership of a national minority, property, birth, age, or choice of text editor. We do not tolerate harassment of participants on the basis of these categories, or for any other reason. Harassment is any form of behaviour intended to exclude, intimidate, or cause discomfort. Because we are a diverse community, we may have different ways of communicating and of understanding the intent behind actions. Therefore we have chosen to prohibit certain forms of behaviour in our community, regardless of intent. Prohibited harassing behaviour includes but is not limited to: - written or verbal comments which have the effect of excluding people on the basis of membership of a specific group listed above causing someone to fear for their safety, such as through stalking, following, or intimidation - the display of sexual or violent images - unwelcome sexual attention - nonconsensual or unwelcome physical contact - sustained disruption of talks, events or communications - incitement to violence, suicide, or self-harm - continuing to initiate interaction (including photography or recording) with someone after being asked to stop - publication of private communication without consent Behaviour not explicitly mentioned above may still constitute harassment. The list above should not be taken as exhaustive but rather as a guide to make it easier to enrich all of us and the communities in which we participate. All interactions should be professional regardless of location: harassment is prohibited whether it occurs on- or offline, and the same standards apply to both. Enforcement of the Code of Conduct will be respectful and not include any harassing behaviors. Thank you for helping make this a welcoming, friendly community for all. This code of conduct is a modified version of that used by PyCon, which in turn is forked from a template written by the Ada Initiative and hosted on the Geek Feminism Wiki. Contributors to this document: Adam Obeng, Aleksandra Pawlik, Bill Mills, Carol Willing, Erin Becker, Hilmar Lapp, Kara Woo, Karin Lagesen, Pauline Barmby, Sheila Miguez, Simon Waldman, Tracy Teal. ================================================ FILE: CONTRIBUTING.md ================================================ Contributing to Frosted ----------------- Frosted is a community project with no strong copyright enforcement. You are free to contribute to the official repository, hosted at github.com/insane-adding-machines/frosted. By contributing to Frosted, you agree that the code you write will be published and distributed under the term of GNU General Public License, as specified in LICENSE. We don't ask to yield any rights to the code you write, except those required by the LICENSE. In order to contribute, fork the project on github, commit in your local repository, submit a PR. Regular contributors that show interest for the projects are added to the community. Being part of the community means accepting the Code of Conduct. Coding style ----------------- - Indentation is 4 spaces (no tabs) - no spaces inside parenthesis - spaces around binary operators - no trailing spaces - we place a space after every keyword - constants and macros are capitalized - the asterisk in a pointer declaration is adjacent to the symbol name, not its type - function opening brace is on the next line - inner blocks opening brace is on the same line - function/variable case default is `snake_case` and not `CamelCase` - no typedefs (exceptions must be discussed and approved by the community) - write short functions with meaningful names - centralized return point for functions is encouraged. The use of keyword `goto` is allowed to create a centralized return point. More in general, we appreciate if you follow the same style as the existing kernel code. ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice This 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. ================================================ FILE: Makefile ================================================ -include kconfig/.config FROSTED:=$(PWD) FLASH_ORIGIN?=0x0 CFLAGS+=-DFLASH_ORIGIN=$(FLASH_ORIGIN) ifneq ($(V),1) Q:=@ #Do not print "Entering directory ...". MAKEFLAGS += --no-print-directory endif #kernel headers CFLAGS+=-Ikernel/frosted-headers/include -nostdlib #drivers headers CFLAGS+=-Ikernel/drivers #fs headers CFLAGS+=-Ikernel/fs # minimal kernel OBJS-y+= kernel/frosted.o \ kernel/vfs.o \ kernel/systick.o \ kernel/drivers/device.o \ kernel/mpu.o \ kernel/fpb.o \ kernel/string.o \ kernel/sys.o \ kernel/locks.o \ kernel/semaphore.o \ kernel/mutex.o \ kernel/tasklet.o \ kernel/scheduler.o \ kernel/syscall_table.o \ kernel/malloc.o \ kernel/module.o \ kernel/cirbuf.o \ kernel/term.o \ kernel/bflt.o \ kernel/getaddrinfo.o \ kernel/kprintf.o \ kernel/pipe.o -include rules/config.mk include rules/arch.mk include rules/picotcp.mk include rules/userspace.mk # device drivers OBJS-$(ARCH_STM32F4)+=kernel/drivers/gpio.o \ kernel/drivers/exti.o OBJS-$(ARCH_STM32F7)+=kernel/drivers/gpio.o \ kernel/drivers/exti.o OBJS-$(ARCH_LPC17XX)+=kernel/drivers/gpio.o OBJS-$(ARCH_NRF51)+=kernel/drivers/gpio.o OBJS-$(ARCH_NRF52)+=kernel/drivers/gpio.o OBJS-$(MEMFS)+= kernel/fs/memfs.o OBJS-$(XIPFS)+= kernel/fs/xipfs.o CFLAGS-$(MEMFS)+=-DCONFIG_MEMFS OBJS-$(FATFS)+= kernel/fs/fatfs.o CFLAGS-$(FATFS)+=-DCONFIG_FATFS CFLAGS-$(FAT32)+=-DCONFIG_FAT32 OBJS-$(SYSFS)+= kernel/fs/sysfs.o CFLAGS-$(SYSFS)+=-DCONFIG_SYSFS OBJS-$(DEVNULL)+= kernel/drivers/null.o CFLAGS-$(DEVNULL)+=-DCONFIG_DEVNULL OBJS-$(SOCK_UNIX)+= kernel/drivers/socket_un.o CFLAGS-$(SOCK_UNIX)+=-DCONFIG_SOCK_UNIX OBJS-$(PTY_UNIX)+= kernel/drivers/pty.o CFLAGS-$(PTY_UNIX)+=-DCONFIG_PTY_UNIX OBJS-$(PICOTCP)+= kernel/drivers/socket_in.o CFLAGS-$(PICOTCP)+=-DCONFIG_PICOTCP CFLAGS-$(CONFIG_PICOTCP_LOOP)+="-DCONFIG_PICOTCP_LOOP" CFLAGS-$(TCPIP_MEMPOOL_YN)+=-DCONFIG_TCPIP_MEMPOOL=$(TCPIP_MEMPOOL) OBJS-$(DEVL3GD20)+= kernel/drivers/l3gd20.o CFLAGS-$(DEVL3GD20)+=-DCONFIG_DEVL3GD20 OBJS-$(DEVLSM303DLHC)+= kernel/drivers/lsm303dlhc.o CFLAGS-$(DEVLSM303DLHC)+=-DCONFIG_DEVLSM303DLHC OBJS-$(DEVSTMPE811)+= kernel/drivers/stmpe811.o CFLAGS-$(DEVSTMPE811)+=-DCONFIG_DEVSTMPE811 OBJS-$(DEVFT5336)+= kernel/drivers/ft5336.o CFLAGS-$(DEVFT5336)+=-DCONFIG_DEVFT5336 OBJS-$(DEVMCCOG21)+= kernel/drivers/mccog21.o CFLAGS-$(DEVMCCOG21)+=-DCONFIG_DEVMCCOG21 OBJS-$(DEVXALED5X7)+= kernel/drivers/xadow_LED_5x7.o CFLAGS-$(DEVXALED5X7)+=-DCONFIG_DEVXALED5X7 OBJS-$(DEVSPI)+= kernel/drivers/stm32_spi.o CFLAGS-$(DEVSPI)+=-DCONFIG_DEVSTM32F4SPI OBJS-$(DEVLIS3DSH)+= kernel/drivers/lis3dsh.o CFLAGS-$(DEVLIS3DSH)+=-DCONFIG_DEVLIS3DSH OBJS-$(DEVSTM32I2C)+= kernel/drivers/stm32_i2c.o CFLAGS-$(DEVSTM32I2C)+=-DCONFIG_DEVI2C OBJS-$(DEVF4DSP)+=kernel/drivers/stm32f4_dsp.o CFLAGS-$(DEVF4DSP)+=-DCONFIG_DSP OBJS-$(DEVF4ETH)+= kernel/drivers/stm32_eth.o CFLAGS-$(DEVF4ETH)+=-DCONFIG_DEVETH OBJS-$(DEVF7ETH)+= kernel/drivers/stm32_eth.o CFLAGS-$(DEVF7ETH)+=-DCONFIG_DEVETH OBJS-$(DEVLM3SETH)+= kernel/drivers/lm3s_eth.o CFLAGS-$(DEVLM3SETH)+=-DCONFIG_DEVETH OBJS-$(DEVUART)+= kernel/drivers/uart.o CFLAGS-$(DEVUART)+=-DCONFIG_DEVUART OBJS-$(DEVILI9341)+= kernel/drivers/ili9341.o CFLAGS-$(DEVILI9341)+=-DCONFIG_DEVILI9341 -DCONFIG_LTDC OBJS-$(DEVF7DISCOLTDC) += kernel/drivers/stm32f7_ltdc.o CFLAGS-$(DEVF7DISCOLTDC)+=-DCONFIG_DEVF7DISCOLTDC -DCONFIG_LTDC OBJS-$(DEVFRAMEBUFFER)+= kernel/framebuffer.o CFLAGS-$(DEVFRAMEBUFFER)+=-DCONFIG_DEVFRAMEBUFFER OBJS-$(DEVFBCON)+= kernel/drivers/fbcon.o kernel/fonts/palette_256_xterm.o kernel/drivers/tty_console.o CFLAGS-$(DEVFBCON)+=-DCONFIG_DEVTTY_CONSOLE # Font Selection OBJS-$(FONT_CGA_8X8)+=kernel/fonts/cga_8x8.o CFLAGS-$(FONT_CGA_8X8)+=-DCONFIG_FONT_8x8 OBJS-$(FONT_PICCOLO_7X6)+=kernel/fonts/piccolo_7x6.o CFLAGS-$(FONT_PICCOLO_7X6)+=-DCONFIG_FONT_7x6 CFLAGS-$(DEVFBCON)+=-DCONFIG_DEVFBCON OBJS-$(DEVSTM32DMA)+=kernel/drivers/stm32_dma.o CFLAGS-$(DEVSTM32DMA)+=-DCONFIG_DMA CFLAGS-$(DEVSTM32USB)+=-DCONFIG_DEVUSB OBJS-$(DEVSTM32USB)+=kernel/drivers/stm32_usb.o CFLAGS-$(DEVSTM32USBFS)+=-DCONFIG_DEVUSBFS CFLAGS-$(DEVSTM32USBHS)+=-DCONFIG_DEVUSBHS CFLAGS-$(USBFS_HOST)+=-DCONFIG_USBHOST -DCONFIG_USBFSHOST CFLAGS-$(USBHS_HOST)+=-DCONFIG_USBHOST -DCONFIG_USBHSHOST OBJS-$(DEVSTM32SDIO)+=kernel/drivers/stm32_sdio.o CFLAGS-$(DEVSTM32SDIO)+=-DCONFIG_SDIO OBJS-$(LOWPOWER)+=kernel/drivers/stm32_lowpower.o CFLAGS-$(LSE32K)+=-DCONFIG_LSE32K OBJS-$(DEVADC)+=kernel/drivers/stm32f4_adc.o CFLAGS-$(DEVADC)+=-DCONFIG_DEVADC OBJS-$(DEVRNG)+=kernel/drivers/stm32_rng.o CFLAGS-$(DEVRNG)+=-DCONFIG_RNG OBJS-$(DEVFRAND)+=kernel/drivers/stm32_rng.o \ kernel/crypto/misc.o \ kernel/crypto/sha256.o \ kernel/crypto/aes.o \ kernel/drivers/fortuna.o \ kernel/drivers/frand.o CFLAGS-$(DEVFRAND)+=-DCONFIG_FRAND -DCONFIG_RNG OBJS-$(STM32F7_SDRAM)+=kernel/drivers/stm32f7_sdram.o OBJS-$(STM32F4_SDRAM)+=kernel/drivers/stm32f4_sdram.o CFLAGS-$(STM32F7_SDRAM)+=-DCONFIG_SDRAM CFLAGS-$(STM32F4_SDRAM)+=-DCONFIG_SDRAM OBJS-$(DEV_USB_ETH)+=kernel/drivers/devusb_cdc_ecm.o CFLAGS-$(DEV_USB_ETH)+=-DCONFIG_DEV_USBETH CFLAGS-$(DEV_USB_ETH)+=-DCONFIG_USB_DEFAULT_IP=\"$(USB_DEFAULT_IP)\" CFLAGS-$(DEV_USB_ETH)+=-DCONFIG_USB_DEFAULT_NM=\"$(USB_DEFAULT_NM)\" CFLAGS-$(DEV_USB_ETH)+=-DCONFIG_USB_DEFAULT_GW=\"$(USB_DEFAULT_GW)\" OBJS-$(DEV_USBH_KBD)+=kernel/drivers/usb/usb_kbd.o CFLAGS-$(DEV_USBH_KBD)+=-DCONFIG_DEV_USBH_KBD CFLAGS-$(DEVF4ETH)+=-DCONFIG_DEV_ETH CFLAGS-$(DEVF4ETH)+=-DCONFIG_ETH_DEFAULT_IP=\"$(ETH_DEFAULT_IP)\" CFLAGS-$(DEVF4ETH)+=-DCONFIG_ETH_DEFAULT_NM=\"$(ETH_DEFAULT_NM)\" CFLAGS-$(DEVF4ETH)+=-DCONFIG_ETH_DEFAULT_GW=\"$(ETH_DEFAULT_GW)\" CFLAGS-$(DEVF7ETH)+=-DCONFIG_DEV_ETH CFLAGS-$(DEVF7ETH)+=-DCONFIG_ETH_DEFAULT_IP=\"$(ETH_DEFAULT_IP)\" CFLAGS-$(DEVF7ETH)+=-DCONFIG_ETH_DEFAULT_NM=\"$(ETH_DEFAULT_NM)\" CFLAGS-$(DEVF7ETH)+=-DCONFIG_ETH_DEFAULT_GW=\"$(ETH_DEFAULT_GW)\" CFLAGS-$(DEVLM3SETH)+=-DCONFIG_DEV_ETH CFLAGS-$(DEVLM3SETH)+=-DCONFIG_ETH_DEFAULT_IP=\"$(ETH_DEFAULT_IP)\" CFLAGS-$(DEVLM3SETH)+=-DCONFIG_ETH_DEFAULT_NM=\"$(ETH_DEFAULT_NM)\" CFLAGS-$(DEVLM3SETH)+=-DCONFIG_ETH_DEFAULT_GW=\"$(ETH_DEFAULT_GW)\" OBJS-$(MACH_STM32F407Discovery)+=kernel/$(BOARD)/stm32f407discovery.o CFLAGS-$(MACH_STM32F405Pyboard10)+=-DCONFIG_PYBOARD_1_0 CFLAGS-$(MACH_STM32F405Pyboard11)+=-DCONFIG_PYBOARD_1_1 -DCLOCK_12MHZ CFLAGS-$(MACH_STM32F411Pyboard11lite)+=-DCONFIG_PYBOARD_1_1 -DCLOCK_12MHZ OBJS-$(MACH_STM32F405Pyboard10)+=kernel/$(BOARD)/stm32f4xxpyboard.o OBJS-$(MACH_STM32F405Pyboard11)+=kernel/$(BOARD)/stm32f4xxpyboard.o OBJS-$(MACH_STM32F411Pyboard11lite)+=kernel/$(BOARD)/stm32f4xxpyboard.o OBJS-$(MACH_STM32F411Nucleo)+=kernel/$(BOARD)/stm32f411nucleo.o OBJS-$(MACH_STM32F4x1Discovery)+=kernel/$(BOARD)/stm32f4x1discovery.o OBJS-$(MACH_STM32F429Discovery)+=kernel/$(BOARD)/stm32f429discovery.o OBJS-$(MACH_STM32F446Nucleo)+=kernel/$(BOARD)/stm32f446nucleo.o OBJS-$(MACH_STM32F746Discovery)+=kernel/$(BOARD)/stm32f746discovery.o OBJS-$(MACH_STM32F769Discovery)+=kernel/$(BOARD)/stm32f769discovery.o OBJS-$(MACH_STM32F746Nucleo144)+=kernel/$(BOARD)/stm32f746nucleo-144.o OBJS-$(MACH_LPC1768MBED)+=kernel/$(BOARD)/lpc1768mbed.o OBJS-$(MACH_SEEEDPRO)+=kernel/$(BOARD)/lpc1768mbed.o OBJS-$(MACH_LPC1679XPRESSO)+=kernel/$(BOARD)/lpc1769xpresso.o OBJS-$(MACH_LM3S6965EVB)+=kernel/$(BOARD)/lm3s6965evb.o OBJS-$(MACH_LM3SVIRT)+=kernel/$(BOARD)/lm3s6965evb.o OBJS-$(MACH_BLENANOV1_5)+=kernel/$(BOARD)/blenanov1_5.o OBJS-$(MACH_BLENANOV2_0)+=kernel/$(BOARD)/blenanov2_0.o OBJS-$(MACH_STM32F407Diymore)+=kernel/$(BOARD)/stm32f407diymore.o LIB-y:= LIB-$(PICOTCP)+=$(PREFIX)/lib/libpicotcp.a LIB-y+=kernel/unicore-mx/lib/libucmx_$(BOARD).a OBJS-$(PICOTCP)+=kernel/net/pico_lock.o CFLAGS+=$(CFLAGS-y) SHELL=/bin/bash all: image.bin kernel/syscall_table.c: kernel/syscall_table_gen.py @python2 $^ $(PREFIX)/lib/libpicotcp.a: echo $(BUILD_PICO) $(BUILD_PICO) @pwd .PHONY: FORCE st-flash st-flash: image.bin st-flash write image.bin 0x08000000 kernel.img: kernel.elf @export PADTO=`python2 -c "print ( $(KFLASHMEM_SIZE) * 1024) + int('$(FLASH_ORIGIN)', 16)"`; \ $(CROSS_COMPILE)objcopy -O binary --pad-to=$$PADTO kernel.elf $@ apps.img: $(USERSPACE) @make -C $(USERSPACE) FROSTED=$(PWD) FAMILY=$(FAMILY) ARCH=$(MCPU) image.bin: kernel.img apps.img cat kernel.img apps.img > $@ kernel/unicore-mx/lib/libucmx_$(BOARD).a: make -C kernel/unicore-mx FP_FLAGS="-mfloat-abi=soft" PREFIX=arm-frosted-eabi TARGETS=$(UNICOREMX_TARGET) kernel/$(BOARD)/$(BOARD).ld: kernel/$(BOARD)/$(BOARD).ld.in export KRAMMEM_SIZE_B=`python2 -c "print '0x%X' % ( $(KRAMMEM_SIZE) * 1024)"`; \ export KFLASHMEM_SIZE_B=`python2 -c "print '0x%X' % ( $(KFLASHMEM_SIZE) * 1024)"`; \ export RAM1_SIZE_B=`python2 -c "print '0x%X' % ( $(RAM1_SIZE) * 1024)"`; \ export RAM2_SIZE_B=`python2 -c "print '0x%X' % ( $(RAM2_SIZE) * 1024)"`; \ export RAM3_SIZE_B=`python2 -c "print '0x%X' % ( $(RAM3_SIZE) * 1024)"`; \ export SDRAM_SIZE_B=`python2 -c "print '0x%X' % ( $(SDRAM_SIZE))"`; \ cat $^ | sed -e "s/__FLASH_ORIGIN/$(FLASH_ORIGIN)/g" | \ sed -e "s/__KFLASHMEM_SIZE/$$KFLASHMEM_SIZE_B/g" | \ sed -e "s/__KRAMMEM_SIZE/$$KRAMMEM_SIZE_B/g" |\ sed -e "s/__RAM1_BASE/$(RAM1_BASE)/g" |\ sed -e "s/__RAM2_BASE/$(RAM2_BASE)/g" |\ sed -e "s/__RAM3_BASE/$(RAM3_BASE)/g" |\ sed -e "s/__SDRAM_BASE/$(SDRAM_BASE)/g" |\ sed -e "s/__RAM1_SIZE/$$RAM1_SIZE_B/g" |\ sed -e "s/__RAM2_SIZE/$$RAM2_SIZE_B/g" |\ sed -e "s/__RAM3_SIZE/$$RAM3_SIZE_B/g" |\ sed -e "s/__SDRAM_SIZE/$$SDRAM_SIZE_B/g" \ >$@ kernel.elf: $(LIB-y) $(OBJS-y) kernel/$(BOARD)/$(BOARD).ld @$(CC) -o $@ -Tkernel/$(BOARD)/$(BOARD).ld -Wl,--start-group $(OBJS-y) $(LIB-y) -Wl,--end-group \ -Wl,-Map,kernel.map $(LDFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) qemudbg: image.bin qemu-system-arm -M lm3s6965evb --kernel image.bin -nographic -S -gdb tcp::3333 qemu: image.bin qemu-system-arm -M lm3s6965evb --kernel image.bin -nographic qemu2: qemu qemunet: sudo qemu-system-arm -M lm3s6965evb --kernel image.bin -nographic -net nic,vlan=0 -net tap,vlan=0,ifname=frost0 qemunetdbg: sudo qemu-system-arm -M lm3s6965evb --kernel image.bin -nographic -S -gdb tcp::3333 -net nic,vlan=0 -net tap,vlan=0,ifname=frost0 qemubridgedbg: qemu-system-arm -M lm3s6965evb --kernel image.bin -nographic -S -gdb tcp::3333 -net nic,vlan=0 -net tap,helper=$(HOME)/frosted-qemu/qemu-bin/libexec/qemu-bridge-helper qemubridge: qemu-system-arm -M lm3s6965evb --kernel image.bin -nographic -net nic,vlan=0 -net tap,helper=$(HOME)/frosted-qemu/qemu-bin/libexec/qemu-bridge-helper menuconfig: @$(MAKE) -C kconfig/ menuconfig -f Makefile.frosted config: @$(MAKE) -C kconfig/ config -f Makefile.frosted defconfig: FORCE @test $(TARGET) || (echo "ERROR: you must define a target" && false) @cp -i defconfig/$(TARGET).config kconfig/.config malloc_test: @gcc -o malloc.test kernel/malloc.c -DCONFIG_KRAM_SIZE=4 libclean: clean @make -C kernel/unicore-mx clean PREFIX=arm-frosted-eabi clean: @rm -f malloc.test @rm -f kernel/$(BOARD)/$(BOARD).ld @make -C $(USERSPACE) clean @rm -f $(OBJS-y) @rm -f *.map *.bin *.elf *.img @rm -f kernel/$(BOARD)/$(BOARD).ld @rm -rf build @rm -f tags @rm -f kernel/syscall_table.c ================================================ FILE: README.md ================================================ # Frosted :snowman: ## We moved to gitlab! Please visit [Frosted OS](https://gitlab.com/insane-adding-machines/frosted) and [Insane Adding Machines](https://gitlab.com/insane-adding-machines/) new homes! Bye! _the frosted development team_ ================================================ FILE: defconfig/lpc1769.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # # ARCH_LM3S is not set ARCH_LPC17XX=y # ARCH_STM32F4 is not set # ARCH_STM32F7 is not set # ARCH_LPC1763 is not set # ARCH_LPC1764 is not set # ARCH_LPC1765 is not set # ARCH_LPC1766 is not set # ARCH_LPC1767 is not set # ARCH_LPC1768 is not set ARCH_LPC1769=y FLASH_SIZE_512KB=y RAM_SIZE_32KB=y # CLK_100MHZ is not set CLK_120MHZ=y MACH_LPC1679XPRESSO=y # # Kernel Configuration # KFLASHMEM_SIZE=128 KRAMMEM_SIZE=32 # TASK_STACK_SIZE_1K is not set TASK_STACK_SIZE_2K=y # TASK_STACK_SIZE_4K is not set # TASK_STACK_SIZE_8K is not set MPU=y PTHREADS=y SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set STRACE=y # # Filesystems # SYSFS=y MEMFS=y XIPFS=y # FATFS is not set # # Networking # # SOCK_INET is not set # TCPIP_MEMPOOL_YN is not set # # Device Drivers # # DEVNULL is not set DEVUART=y UART_0=y # UART_1 is not set # UART_2 is not set # UART_3 is not set # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/lpc17xx.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # # ARCH_LM3S is not set ARCH_LPC17XX=y # ARCH_STM32F4 is not set # ARCH_STM32F7 is not set # ARCH_LPC1763 is not set # ARCH_LPC1764 is not set # ARCH_LPC1765 is not set # ARCH_LPC1766 is not set # ARCH_LPC1767 is not set ARCH_LPC1768=y # ARCH_LPC1769 is not set FLASH_SIZE_512KB=y RAM_SIZE_32KB=y CLK_100MHZ=y # MACH_LPC1768MBED is not set MACH_SEEEDPRO=y # # Kernel Configuration # KFLASHMEM_SIZE=128 KRAMMEM_SIZE=32 # # IPC features # SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set STRACE=y # TASK_STACK_SIZE_1K is not set TASK_STACK_SIZE_2K=y # TASK_STACK_SIZE_4K is not set # TASK_STACK_SIZE_8K is not set # # Filesystems # SYSFS=y MEMFS=y XIPFS=y # FATFS is not set # # Networking # # SOCK_INET is not set # TCPIP_MEMPOOL_YN is not set # # Device Drivers # # DEVNULL is not set DEVUART=y UART_0=y # UART_1 is not set # UART_2 is not set # UART_3 is not set DEVGPIO=y # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/qemu-orig.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # ARCH_LM3S=y # ARCH_LPC17XX is not set # ARCH_STM32F4 is not set # ARCH_STM32F7 is not set ARCH_LM3S6965=y # ARCH_LM3SVIRT is not set FLASH_SIZE_256KB=y RAM_SIZE_64KB=y MACH_LM3S6965EVB=y # # Kernel Configuration # KFLASHMEM_SIZE=64 KRAMMEM_SIZE=32 # TASK_STACK_SIZE_1K is not set TASK_STACK_SIZE_2K=y # TASK_STACK_SIZE_4K is not set # TASK_STACK_SIZE_8K is not set MPU=y # # IPC features # SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set # STRACE is not set # # Filesystems # SYSFS=y # MEMFS is not set XIPFS=y # FATFS is not set # # Networking # # SOCK_INET is not set # TCPIP_MEMPOOL_YN is not set # # Device Drivers # # DEVNULL is not set DEVUART=y USART_0=y # USART_1 is not set # USART_2 is not set # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/qemu.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # ARCH_LM3S=y # ARCH_LPC17XX is not set # ARCH_STM32F4 is not set # ARCH_STM32F7 is not set # ARCH_LM3S6965 is not set ARCH_LM3SVIRT=y FLASH_SIZE_1MB=y RAM_SIZE_256KB=y MACH_LM3SVIRT=y # # Kernel Configuration # KFLASHMEM_SIZE=128 KRAMMEM_SIZE=128 # TASK_STACK_SIZE_1K is not set # TASK_STACK_SIZE_2K is not set TASK_STACK_SIZE_4K=y # TASK_STACK_SIZE_8K is not set MPU=y PTHREADS=y SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set # STRACE is not set # # Filesystems # SYSFS=y # MEMFS is not set XIPFS=y # FATFS is not set # # Networking # # SOCK_INET is not set # TCPIP_MEMPOOL_YN is not set # # Device Drivers # DEVNULL=y DEVUART=y USART_0=y # USART_1 is not set # USART_2 is not set # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/qemunet.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # ARCH_LM3S=y # ARCH_LPC17XX is not set # ARCH_STM32F4 is not set # ARCH_STM32F7 is not set # ARCH_LM3S6965 is not set ARCH_LM3SVIRT=y FLASH_SIZE_1MB=y RAM_SIZE_256KB=y MACH_LM3SVIRT=y # # Kernel Configuration # KFLASHMEM_SIZE=128 KRAMMEM_SIZE=64 # TASK_STACK_SIZE_1K is not set TASK_STACK_SIZE_2K=y # TASK_STACK_SIZE_4K is not set # TASK_STACK_SIZE_8K is not set MPU=y PTHREADS=y SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set # STRACE is not set # # Filesystems # SYSFS=y # MEMFS is not set XIPFS=y # FATFS is not set # # Networking # SOCK_INET=y # TCPIP_MEMPOOL_YN is not set PICOTCP=y # # picoTCP configuration # CONFIG_PICOTCP_IPV4=y # CONFIG_PICOTCP_IPV6 is not set CONFIG_PICOTCP_TCP=y CONFIG_PICOTCP_UDP=y CONFIG_PICOTCP_DNS=y # CONFIG_PICOTCP_MCAST is not set # CONFIG_PICOTCP_NAT is not set # CONFIG_PICOTCP_IPFILTER is not set CONFIG_PICOTCP_LOOP=y # CONFIG_PICOTCP_DEBUG is not set # # Device Drivers # DEVNULL=y DEVUART=y USART_0=y # USART_1 is not set # USART_2 is not set DEVLM3SETH=y ETH_DEFAULT_IP="192.168.20.150" ETH_DEFAULT_NM="255.255.255.0" ETH_DEFAULT_GW="192.168.20.1" # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/stm32f407-discovery.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # # ARCH_LM3S is not set # ARCH_LPC17XX is not set ARCH_STM32F4=y # ARCH_STM32F7 is not set # ARCH_STM32F401_XB is not set # ARCH_STM32F401_XC is not set # ARCH_STM32F401_XD is not set # ARCH_STM32F401_XE is not set # ARCH_STM32F405_XG is not set # ARCH_STM32F405_XE is not set ARCH_STM32F407_XG=y # ARCH_STM32F407_XE is not set # ARCH_STM32F411_XE is not set # ARCH_STM32F411_XC is not set # ARCH_STM32F429_XE is not set # ARCH_STM32F429_XG is not set # ARCH_STM32F429_XI is not set # ARCH_STM32F446_ZE is not set FLASH_SIZE_1MB=y RAM_SIZE_192KB=y ARCH_STM32F407=y DEVSTM32DMA=y # CLK_120MHZ is not set CLK_168MHZ=y MACH_STM32F407Discovery=y # STM32F4_SDRAM is not set # # Kernel Configuration # KFLASHMEM_SIZE=192 KRAMMEM_SIZE=128 # TASK_STACK_SIZE_1K is not set # TASK_STACK_SIZE_2K is not set TASK_STACK_SIZE_4K=y # TASK_STACK_SIZE_8K is not set MPU=y PTHREADS=y SIGNALS=y PIPE=y SOCK_UNIX=y # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set # STRACE is not set # # Filesystems # SYSFS=y MEMFS=y XIPFS=y # FATFS is not set # # Networking # # SOCK_INET is not set # TCPIP_MEMPOOL_YN is not set # # Device Drivers # DEVNULL=y DEVUART=y # USART_1 is not set USART_2=y # USART_3 is not set # USART_6 is not set DEVF4DSP=y DEVSTM32USB=y DEVSTM32USBFS=y USBFS_HOST=y # USBFS_GUEST is not set # DEVTIM is not set # DEVADC is not set # DEVSTM32SDIO is not set # DEVSTM32I2C is not set # DEVSPI is not set # DEV_RANDOM is not set # DEVFRAMEBUFFER is not set # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/stm32f429i-discovery.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # # ARCH_LM3S is not set # ARCH_LPC17XX is not set ARCH_STM32F4=y # ARCH_STM32F7 is not set # ARCH_STM32F401_XB is not set # ARCH_STM32F401_XC is not set # ARCH_STM32F401_XD is not set # ARCH_STM32F401_XE is not set # ARCH_STM32F405_XG is not set # ARCH_STM32F405_XE is not set # ARCH_STM32F407_XG is not set # ARCH_STM32F407_XE is not set # ARCH_STM32F411_XE is not set # ARCH_STM32F411_XC is not set # ARCH_STM32F429_XE is not set # ARCH_STM32F429_XG is not set ARCH_STM32F429_XI=y # ARCH_STM32F446_ZE is not set FLASH_SIZE_2MB=y RAM_SIZE_256KB=y ARCH_STM32F429=y # CLK_48MHZ is not set # CLK_84MHZ is not set CLK_168MHZ=y MACH_STM32F429Discovery=y # # Kernel Configuration # KFLASHMEM_SIZE=128 KRAMMEM_SIZE=64 # TASK_STACK_SIZE_1K is not set TASK_STACK_SIZE_2K=y # TASK_STACK_SIZE_4K is not set # TASK_STACK_SIZE_8K is not set MPU=y # # IPC features # SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # KLOG=y KLOG_SIZE=256 MEMFAULT_DBG=y # HARDFAULT_DBG is not set # STRACE is not set # # Filesystems # SYSFS=y MEMFS=y XIPFS=y # FATFS is not set # # Networking # # SOCK_INET is not set # TCPIP_MEMPOOL_YN is not set # # Device Drivers # DEVNULL=y DEVUART=y USART_1=y # USART_2 is not set # DEVF4DSP is not set # DEVSTM32USB is not set # DEVTIM is not set # DEVADC is not set # DEVSTM32SDIO is not set # DEVSTM32I2C is not set # DEVSPI is not set # DEV_RANDOM is not set # DEVRNG is not set # DEVFRAND is not set # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/stm32f746-discovery.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # # ARCH_LM3S is not set # ARCH_LPC17XX is not set # ARCH_STM32F4 is not set ARCH_STM32F7=y ARCH_STM32F746_NG=y # ARCH_STM32F769_NI is not set FLASH_SIZE_1MB=y RAM_SIZE_320KB=y ARCH_STM32F746=y CLK_216MHZ=y MACH_STM32F746Discovery=y # MACH_STM32F746Nucleo144 is not set STM32F7_SDRAM=y # # Kernel Configuration # KFLASHMEM_SIZE=256 KRAMMEM_SIZE=256 # TASK_STACK_SIZE_1K is not set # TASK_STACK_SIZE_2K is not set TASK_STACK_SIZE_4K=y # TASK_STACK_SIZE_8K is not set MPU=y PTHREADS=y SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set STRACE=y # # Filesystems # SYSFS=y # MEMFS is not set XIPFS=y FATFS=y FAT32=y FAT16=y # # Networking # SOCK_INET=y # TCPIP_MEMPOOL_YN is not set PICOTCP=y # # picoTCP configuration # CONFIG_PICOTCP_IPV4=y # CONFIG_PICOTCP_IPV6 is not set CONFIG_PICOTCP_TCP=y CONFIG_PICOTCP_UDP=y CONFIG_PICOTCP_DNS=y # CONFIG_PICOTCP_MCAST is not set # CONFIG_PICOTCP_NAT is not set # CONFIG_PICOTCP_IPFILTER is not set CONFIG_PICOTCP_LOOP=y # CONFIG_PICOTCP_DEBUG is not set # # Device Drivers # DEVNULL=y DEVUART=y # USART_1 is not set # USART_2 is not set # USART_3 is not set USART_6=y DEVSTM32USB=y DEVSTM32USBFS=y # USBFS_HOST is not set USBFS_GUEST=y # DEVSTM32USBHS is not set DEV_USB_ETH=y USB_DEFAULT_IP="192.168.6.150" USB_DEFAULT_NM="255.255.255.0" USB_DEFAULT_GW="192.168.6.1" # DEVTIM is not set # DEVF7ETH is not set DEVSTM32SDIO=y # DEVSTM32I2C is not set # DEVSPI is not set # DEV_RANDOM is not set DEVFRAMEBUFFER=y DEVFBCON=y FONT_CGA_8X8=y # FONT_PICCOLO_7X6 is not set DEVF7DISCOLTDC=y # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/stm32f746-nucleo.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # # ARCH_LM3S is not set # ARCH_LPC17XX is not set # ARCH_STM32F4 is not set ARCH_STM32F7=y ARCH_STM32F746_NG=y # ARCH_STM32F769_NI is not set FLASH_SIZE_1MB=y RAM_SIZE_320KB=y ARCH_STM32F746=y CLK_216MHZ=y # MACH_STM32F746Discovery is not set MACH_STM32F746Nucleo144=y # STM32F7_SDRAM is not set # # Kernel Configuration # KFLASHMEM_SIZE=128 KRAMMEM_SIZE=32 # TASK_STACK_SIZE_1K is not set TASK_STACK_SIZE_2K=y # TASK_STACK_SIZE_4K is not set # TASK_STACK_SIZE_8K is not set MPU=y PTHREADS=y SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # # KLOG is not set MEMFAULT_DBG=y # HARDFAULT_DBG is not set STRACE=y # # Filesystems # SYSFS=y # MEMFS is not set XIPFS=y # FATFS is not set # # Networking # # SOCK_INET is not set # TCPIP_MEMPOOL_YN is not set # # Device Drivers # DEVNULL=y DEVUART=y # USART_1 is not set # USART_2 is not set # USART_3 is not set USART_6=y DEVSTM32USB=y DEVSTM32USBFS=y USBFS_HOST=y # USBFS_GUEST is not set # DEVSTM32USBHS is not set # DEVTIM is not set # DEVSTM32SDIO is not set # DEVSTM32I2C is not set # DEVSPI is not set # DEV_RANDOM is not set # DEVFRAMEBUFFER is not set # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: defconfig/stm32f769-discovery.config ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Compiler options # GDB_CFLAG=y OPTIMIZE_NONE=y # OPTIMIZE_SIZE is not set # OPTIMIZE_PERF is not set # # Platform Selection # # ARCH_LM3S is not set # ARCH_LPC17XX is not set # ARCH_STM32F4 is not set ARCH_STM32F7=y # ARCH_NRF51 is not set # ARCH_STM32F746_NG is not set ARCH_STM32F769_NI=y FLASH_SIZE_2MB=y RAM_SIZE_368KB=y ARCH_STM32F769=y CLK_216MHZ=y MACH_STM32F769Discovery=y # STM32F7_SDRAM is not set # # Kernel Configuration # KFLASHMEM_SIZE=128 KRAMMEM_SIZE=64 # TASK_STACK_SIZE_1K is not set # TASK_STACK_SIZE_2K is not set TASK_STACK_SIZE_4K=y # TASK_STACK_SIZE_8K is not set MPU=y PTHREADS=y SIGNALS=y PIPE=y # SOCK_UNIX is not set # # Debugging options # KLOG=y KLOG_SIZE=256 MEMFAULT_DBG=y HARDFAULT_DBG=y # STRACE is not set # # Filesystems # SYSFS=y MEMFS=y XIPFS=y FATFS=y FAT32=y FAT16=y # # Networking # SOCK_INET=y # TCPIP_MEMPOOL_YN is not set PICOTCP=y # # picoTCP configuration # CONFIG_PICOTCP_IPV4=y # CONFIG_PICOTCP_IPV6 is not set CONFIG_PICOTCP_TCP=y CONFIG_PICOTCP_UDP=y CONFIG_PICOTCP_DNS=y # CONFIG_PICOTCP_MCAST is not set # CONFIG_PICOTCP_NAT is not set # CONFIG_PICOTCP_IPFILTER is not set CONFIG_PICOTCP_LOOP=y # CONFIG_PICOTCP_DEBUG is not set # # Device Drivers # DEVNULL=y DEVUART=y # USART_1 is not set # USART_2 is not set # USART_3 is not set USART_6=y # DEVSTM32USBHS is not set DEVF7ETH=y ETH_DEFAULT_IP="192.168.2.151" ETH_DEFAULT_NM="255.255.255.0" ETH_DEFAULT_GW="192.168.2.1" DEVSTM32SDIO=y # DEVSPI is not set # DEV_RANDOM is not set # DEVFRAMEBUFFER is not set # # Power Management # # # Power Management requires CPU Timer support # ================================================ FILE: gdbinit.bflt ================================================ tar ext :3333 monitor reset layout src symbol-file file kernel.elf add-symbol-file ./frosted-mini-userspace-bflt/init.gdb 0x20090 -s .data 0x20008014 -s .bss 0x2000813c add-symbol-file frosted-mini-userspace-bflt/idling.gdb 0x20a84 -s .data 0x2000815c -s .bss 0x200081ac add-symbol-file frosted-mini-userspace-bflt/fresh.gdb 0x21334 -s .data 0x200081f8 -s .bss 0x20008b84 add-symbol-file frosted-mini-userspace-bflt/binutils.gdb 0x18de0 -s .data 0x2000acf0 -s .bss 0x2000c610 mon reset mon halt stepi focus c ================================================ FILE: gdbinit.mini ================================================ tar ext :3333 monitor reset layout src symbol-file file kernel.elf mon reset mon halt stepi focus c ================================================ FILE: include/frosted_api.h ================================================ #ifndef INC_FROSTED_API #define INC_FROSTED_API #include "stdint.h" #define INIT __attribute__((section(".init"))) /* Constants */ /* move to limits.h ? */ #define MAXPATHLEN 256 #define ARG_MAX 32 /* open */ #include /* seek */ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 /* syslog */ #define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but significant condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ /* opendir - readdir */ typedef void DIR; /* semaphore */ struct semaphore; typedef struct semaphore sem_t; typedef struct semaphore mutex_t; #define MAX_FILE 64 struct dirent { uint32_t d_ino; char d_name[MAX_FILE]; }; /* #define S_IFMT 0170000 // bit mask for the file type bit fields #define P_IFMT 0000007 // bit mask for file permissions */ #define P_EXEC 0000001 // exec /* for unix sockets */ #ifndef __frosted__ #define AF_UNIX 0 #define SOCK_STREAM 6 #define SOCK_DGRAM 17 #endif struct __attribute__((packed)) sockaddr { uint16_t sa_family; uint8_t sa_zero[14]; }; struct __attribute__((packed)) sockaddr_un { uint16_t sun_family; uint8_t sun_path[MAX_FILE - 2]; }; struct sockaddr_env { struct sockaddr *se_addr; unsigned int se_len; }; extern int errno; #endif ================================================ FILE: kconfig/.gitignore ================================================ # # Generated files # config* *.lex.c *.tab.c *.tab.h zconf.hash.c *.moc gconf.glade.h *.pot *.mo # # configuration programs # conf mconf nconf qconf gconf kxgettext ================================================ FILE: kconfig/Kconfig ================================================ mainmenu "FROSTED Kernel Configuration" source ../kernel/Kconfig ================================================ FILE: kconfig/Makefile ================================================ # =========================================================================== # Kernel configuration targets # These targets are used from top-level makefile PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \ localmodconfig localyesconfig ifdef KBUILD_KCONFIG Kconfig := $(KBUILD_KCONFIG) else Kconfig := Kconfig endif # We need this, in case the user has it in its environment unexport CONFIG_ xconfig: $(obj)/qconf $< $(Kconfig) gconfig: $(obj)/gconf $< $(Kconfig) menuconfig: $(obj)/mconf echo obj is $(obj) echo Executing $< $< $(Kconfig) config: $(obj)/conf $< --oldaskconfig $(Kconfig) nconfig: $(obj)/nconf $< $(Kconfig) oldconfig: $(obj)/conf $< --$@ $(Kconfig) silentoldconfig: $(obj)/conf $(Q)mkdir -p include/generated $< --$@ $(Kconfig) localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ mv -f .tmp.config .config; \ $(obj)/conf --silentoldconfig $(Kconfig); \ mv -f .config.old.1 .config.old) \ else \ mv -f .tmp.config .config; \ $(obj)/conf --silentoldconfig $(Kconfig); \ fi $(Q)rm -f .tmp.config # Create new linux.pot file # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h $(Q)echo " GEN config.pot" $(Q)xgettext --default-domain=linux \ --add-comments --keyword=_ --keyword=N_ \ --from-code=UTF-8 \ --files-from=$(srctree)/scripts/kconfig/POTFILES.in \ --directory=$(srctree) --directory=$(objtree) \ --output $(obj)/config.pot $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ $(srctree)/arch/*/um/Kconfig`; \ do \ echo " GEN $$i"; \ $(obj)/kxgettext $$i \ >> $(obj)/config.pot; \ done ) $(Q)echo " GEN linux.pot" $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ --output $(obj)/linux.pot $(Q)rm -f $(obj)/config.pot PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf $< --$@ $(Kconfig) PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig listnewconfig olddefconfig: $(obj)/conf $< --$@ $(Kconfig) # oldnoconfig is an alias of olddefconfig, because people already are dependent # on its behavior(sets new symbols to their default value but not 'n') with the # counter-intuitive name. oldnoconfig: $(obj)/conf $< --olddefconfig $(Kconfig) savedefconfig: $(obj)/conf $< --$@=defconfig $(Kconfig) defconfig: $(obj)/conf ifeq ($(KBUILD_DEFCONFIG),) $< --defconfig $(Kconfig) else @echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) endif %_defconfig: $(obj)/conf $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) # Help text used by make help help: @echo ' config - Update current config utilising a line-oriented program' @echo ' nconfig - Update current config utilising a ncurses menu based program' @echo ' menuconfig - Update current config utilising a menu based program' @echo ' xconfig - Update current config utilising a QT based front-end' @echo ' gconfig - Update current config utilising a GTK based front-end' @echo ' oldconfig - Update current config utilising a provided .config as base' @echo ' localmodconfig - Update current config disabling modules not loaded' @echo ' localyesconfig - Update current config converting local mods to core' @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' @echo ' defconfig - New config with default from ARCH supplied defconfig' @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' @echo ' allnoconfig - New config where all options are answered with no' @echo ' allyesconfig - New config where all options are accepted with yes' @echo ' allmodconfig - New config selecting modules when possible' @echo ' alldefconfig - New config with all symbols set to default' @echo ' randconfig - New config with random answer to all options' @echo ' listnewconfig - List new options' @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' # lxdialog stuff check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh # Use recursively expanded variables so we do not call gcc unless # we really need to do so. (Do not call gcc as part of make mrproper) HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ -DLOCALE # =========================================================================== # Shared Makefile for the various kconfig executables: # conf: Used for defconfig, oldconfig and related targets # nconf: Used for the nconfig target. # Utilizes ncurses # mconf: Used for the menuconfig target # Utilizes the lxdialog package # qconf: Used for the xconfig target # Based on QT which needs to be installed to compile it # gconf: Used for the gconfig target # Based on GTK which needs to be installed to compile it # object files used by all kconfig flavours lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o conf-objs := conf.o zconf.tab.o mconf-objs := mconf.o zconf.tab.o $(lxdialog) nconf-objs := nconf.o zconf.tab.o nconf.gui.o kxgettext-objs := kxgettext.o zconf.tab.o qconf-cxxobjs := qconf.o qconf-objs := zconf.tab.o gconf-objs := gconf.o zconf.tab.o hostprogs-y := conf ifeq ($(MAKECMDGOALS),nconfig) hostprogs-y += nconf endif ifeq ($(MAKECMDGOALS),menuconfig) hostprogs-y += mconf endif ifeq ($(MAKECMDGOALS),update-po-config) hostprogs-y += kxgettext endif ifeq ($(MAKECMDGOALS),xconfig) qconf-target := 1 endif ifeq ($(MAKECMDGOALS),gconfig) gconf-target := 1 endif ifeq ($(qconf-target),1) hostprogs-y += qconf endif ifeq ($(gconf-target),1) hostprogs-y += gconf endif clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h clean-files += mconf qconf gconf nconf clean-files += config.pot linux.pot # Check that we have the required ncurses stuff installed for lxdialog (menuconfig) PHONY += $(obj)/dochecklxdialog $(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog $(obj)/dochecklxdialog: $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf) always := dochecklxdialog # Add environment specific flags HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)) # generated files seem to need this to find local include files HOSTCFLAGS_zconf.lex.o := -I$(src) HOSTCFLAGS_zconf.tab.o := -I$(src) LEX_PREFIX_zconf := zconf YACC_PREFIX_zconf := zconf HOSTLOADLIBES_qconf = $(KC_QT_LIBS) HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ -Wno-missing-prototypes HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) HOSTLOADLIBES_nconf = $(shell \ pkg-config --libs menu panel ncurses 2>/dev/null \ || echo "-lmenu -lpanel -lncurses" ) $(obj)/qconf.o: $(obj)/.tmp_qtcheck ifeq ($(qconf-target),1) $(obj)/.tmp_qtcheck: $(src)/Makefile -include $(obj)/.tmp_qtcheck # QT needs some extra effort... $(obj)/.tmp_qtcheck: @set -e; echo " CHECK qt"; dir=""; pkg=""; \ if ! pkg-config --exists QtCore 2> /dev/null; then \ echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \ pkg-config --exists qt 2> /dev/null && pkg=qt; \ pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \ if [ -n "$$pkg" ]; then \ cflags="\$$(shell pkg-config $$pkg --cflags)"; \ libs="\$$(shell pkg-config $$pkg --libs)"; \ moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \ dir="$$(pkg-config $$pkg --variable=prefix)"; \ else \ for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \ if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \ done; \ if [ -z "$$dir" ]; then \ echo >&2 "*"; \ echo >&2 "* Unable to find any QT installation. Please make sure that"; \ echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \ echo >&2 "* either qmake can be found or install pkg-config or set"; \ echo >&2 "* the QTDIR environment variable to the correct location."; \ echo >&2 "*"; \ false; \ fi; \ libpath=$$dir/lib; lib=qt; osdir=""; \ $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \ osdir=x$$($(HOSTCXX) -print-multi-os-directory); \ test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \ test -f $$libpath/libqt-mt.so && lib=qt-mt; \ cflags="-I$$dir/include"; \ libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \ moc="$$dir/bin/moc"; \ fi; \ if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \ echo "*"; \ echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \ echo "*"; \ moc="/usr/bin/moc"; \ fi; \ else \ cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \ libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \ moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \ [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \ fi; \ echo "KC_QT_CFLAGS=$$cflags" > $@; \ echo "KC_QT_LIBS=$$libs" >> $@; \ echo "KC_QT_MOC=$$moc" >> $@ endif $(obj)/gconf.o: $(obj)/.tmp_gtkcheck ifeq ($(gconf-target),1) -include $(obj)/.tmp_gtkcheck # GTK needs some extra effort, too... $(obj)/.tmp_gtkcheck: @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \ if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ touch $@; \ else \ echo >&2 "*"; \ echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \ echo >&2 "*"; \ false; \ fi \ else \ echo >&2 "*"; \ echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \ echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \ echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ echo >&2 "*"; \ false; \ fi endif $(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c $(obj)/qconf.o: $(obj)/qconf.moc quiet_cmd_moc = MOC $@ cmd_moc = $(KC_QT_MOC) -i $< -o $@ $(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck $(call cmd,moc) # Extract gconf menu items for I18N support $(obj)/gconf.glade.h: $(obj)/gconf.glade $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \ $(obj)/gconf.glade ================================================ FILE: kconfig/Makefile.frosted ================================================ src := . top_srcdir=../../ top_builddir=../../ srctree := . obj ?= . include Makefile #HOSTCFLAGS+=-Dinline="" -include foo.h #CFLAGS+=-DCURSES_LOC="" #CFLAGS+=-DLOCALE HOSTCC?=gcc PATH:=$(PATH):. -include $(obj)/.depend $(obj)/.depend: $(wildcard *.h *.c) $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) -MM *.c > $@ 2>/dev/null || : __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m))) host-cmulti := $(foreach m,$(__hostprogs),\ $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) host-cxxmulti := $(foreach m,$(__hostprogs),\ $(if $($(m)-cxxobjs),$(m),$(if $($(m)-objs),))) host-cobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-objs)))) host-cxxobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-cxxobjs)))) HOST_EXTRACFLAGS += -I$(obj) -DCONFIG_=\"\" $(host-csingle): %: %.c $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$@) $< -o $(obj)/$@ $(host-cmulti): %: $(host-cobjs) $(host-cshlib) $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$@) $(addprefix $(obj)/,$($(@F)-objs)) $(HOSTLOADLIBES_$(@F)) -o $(obj)/$@ $(host-cxxmulti): %: $(host-cxxobjs) $(host-cobjs) $(host-cshlib) $(HOSTCXX) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$@) $(addprefix $(obj)/,$($(@F)-objs) $($(@F)-cxxobjs)) $(HOSTLOADLIBES_$(@F)) -o $(obj)/$@ $(obj)/%.o: %.c $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@ $(obj)/%.o: $(obj)/%.c $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@ $(obj)/%.o: %.cc $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$(@F)) -c $< -o $@ $(obj)/%:: $(src)/%_shipped $(Q)cat $< > $@ clean: $(Q)rm -f $(addprefix $(obj)/,$(clean-files)) distclean: clean $(Q)rm -f $(addprefix $(obj)/,$(lxdialog) $(conf-objs) $(mconf-objs) $(kxgettext-objs) \ $(hostprogs-y) $(qconf-cxxobjs) $(qconf-objs) $(gconf-objs) \ mconf .depend) FORCE: .PHONY: FORCE clean distclean ================================================ FILE: kconfig/POTFILES.in ================================================ scripts/kconfig/lxdialog/checklist.c scripts/kconfig/lxdialog/inputbox.c scripts/kconfig/lxdialog/menubox.c scripts/kconfig/lxdialog/textbox.c scripts/kconfig/lxdialog/util.c scripts/kconfig/lxdialog/yesno.c scripts/kconfig/mconf.c scripts/kconfig/conf.c scripts/kconfig/confdata.c scripts/kconfig/gconf.c scripts/kconfig/gconf.glade.h scripts/kconfig/qconf.cc ================================================ FILE: kconfig/STM32F4x1Discovery.cfg ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Platform Selection # # ARCH_LM3S is not set # ARCH_LPC17XX is not set ARCH_STM32F4=y # ARCH_STM32F401_XB is not set # ARCH_STM32F401_XC is not set # ARCH_STM32F401_XD is not set # ARCH_STM32F401_XE is not set # ARCH_STM32F405_XG is not set # ARCH_STM32F405_XE is not set # ARCH_STM32F407_XG is not set # ARCH_STM32F407_XE is not set ARCH_STM32F411_XE=y # ARCH_STM32F411_XC is not set # ARCH_STM32F429_XE is not set # ARCH_STM32F429_XG is not set # ARCH_STM32F429_XI is not set FLASH_SIZE_512KB=y RAM_SIZE_128KB=y ARCH_STM32F411=y CLK_48MHZ=y # CLK_84MHZ is not set MACH_STM32F4x1Discovery=y # # Kernel Configuration # KFLASHMEM_SIZE=48 KRAMMEM_SIZE=16 # # Subsystems # # # Filesystems # SYSFS=y MEMFS=y XIPFS=y # # Sockets # SOCK_UNIX=y # # Devices # DEVNULL=y DEVUART=y # USART_1 is not set USART_2=y # USART_6 is not set DEVSPI=y SPI_1=y DEVL3GD20=y DEVGPIO=y # # Applications # FRESH=y # TASK2 is not set # PRODCONS is not set ================================================ FILE: kconfig/check.sh ================================================ #!/bin/sh # Needed for systems without gettext $* -x c -o /dev/null - > /dev/null 2>&1 << EOF #include int main() { gettext(""); return 0; } EOF if [ ! "$?" -eq "0" ]; then echo -DKBUILD_NO_NLS; fi ================================================ FILE: kconfig/conf.c ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include #include #include #include #include #include #include #include "lkc.h" static void conf(struct menu *menu); static void check_conf(struct menu *menu); static void xfgets(char *str, int size, FILE *in); enum input_mode { oldaskconfig, silentoldconfig, oldconfig, allnoconfig, allyesconfig, allmodconfig, alldefconfig, randconfig, defconfig, savedefconfig, listnewconfig, olddefconfig, } input_mode = oldaskconfig; static int indent = 1; static int tty_stdio; static int valid_stdin = 1; static int sync_kconfig; static int conf_cnt; static char line[128]; static struct menu *rootEntry; static void print_help(struct menu *menu) { struct gstr help = str_new(); menu_get_ext_help(menu, &help); printf("\n%s\n", str_get(&help)); str_free(&help); } static void strip(char *str) { char *p = str; int l; while ((isspace(*p))) p++; l = strlen(p); if (p != str) memmove(str, p, l + 1); if (!l) return; p = str + l - 1; while ((isspace(*p))) *p-- = 0; } static void check_stdin(void) { if (!valid_stdin) { printf(_("aborted!\n\n")); printf(_("Console input/output is redirected. ")); printf(_("Run 'make oldconfig' to update configuration.\n\n")); exit(1); } } static int conf_askvalue(struct symbol *sym, const char *def) { enum symbol_type type = sym_get_type(sym); if (!sym_has_value(sym)) printf(_("(NEW) ")); line[0] = '\n'; line[1] = 0; if (!sym_is_changable(sym)) { printf("%s\n", def); line[0] = '\n'; line[1] = 0; return 0; } switch (input_mode) { case oldconfig: case silentoldconfig: if (sym_has_value(sym)) { printf("%s\n", def); return 0; } check_stdin(); /* fall through */ case oldaskconfig: fflush(stdout); xfgets(line, 128, stdin); if (!tty_stdio) printf("\n"); return 1; default: break; } switch (type) { case S_INT: case S_HEX: case S_STRING: printf("%s\n", def); return 1; default: ; } printf("%s", line); return 1; } static int conf_string(struct menu *menu) { struct symbol *sym = menu->sym; const char *def; while (1) { printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); printf("(%s) ", sym->name); def = sym_get_string_value(sym); if (sym_get_string_value(sym)) printf("[%s] ", def); if (!conf_askvalue(sym, def)) return 0; switch (line[0]) { case '\n': break; case '?': /* print help */ if (line[1] == '\n') { print_help(menu); def = NULL; break; } /* fall through */ default: line[strlen(line)-1] = 0; def = line; } if (def && sym_set_string_value(sym, def)) return 0; } } static int conf_sym(struct menu *menu) { struct symbol *sym = menu->sym; tristate oldval, newval; while (1) { printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); if (sym->name) printf("(%s) ", sym->name); putchar('['); oldval = sym_get_tristate_value(sym); switch (oldval) { case no: putchar('N'); break; case mod: putchar('M'); break; case yes: putchar('Y'); break; } if (oldval != no && sym_tristate_within_range(sym, no)) printf("/n"); if (oldval != mod && sym_tristate_within_range(sym, mod)) printf("/m"); if (oldval != yes && sym_tristate_within_range(sym, yes)) printf("/y"); if (menu_has_help(menu)) printf("/?"); printf("] "); if (!conf_askvalue(sym, sym_get_string_value(sym))) return 0; strip(line); switch (line[0]) { case 'n': case 'N': newval = no; if (!line[1] || !strcmp(&line[1], "o")) break; continue; case 'm': case 'M': newval = mod; if (!line[1]) break; continue; case 'y': case 'Y': newval = yes; if (!line[1] || !strcmp(&line[1], "es")) break; continue; case 0: newval = oldval; break; case '?': goto help; default: continue; } if (sym_set_tristate_value(sym, newval)) return 0; help: print_help(menu); } } static int conf_choice(struct menu *menu) { struct symbol *sym, *def_sym; struct menu *child; bool is_new; sym = menu->sym; is_new = !sym_has_value(sym); if (sym_is_changable(sym)) { conf_sym(menu); sym_calc_value(sym); switch (sym_get_tristate_value(sym)) { case no: return 1; case mod: return 0; case yes: break; } } else { switch (sym_get_tristate_value(sym)) { case no: return 1; case mod: printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); return 0; case yes: break; } } while (1) { int cnt, def; printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); def_sym = sym_get_choice_value(sym); cnt = def = 0; line[0] = 0; for (child = menu->list; child; child = child->next) { if (!menu_is_visible(child)) continue; if (!child->sym) { printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); continue; } cnt++; if (child->sym == def_sym) { def = cnt; printf("%*c", indent, '>'); } else printf("%*c", indent, ' '); printf(" %d. %s", cnt, _(menu_get_prompt(child))); if (child->sym->name) printf(" (%s)", child->sym->name); if (!sym_has_value(child->sym)) printf(_(" (NEW)")); printf("\n"); } printf(_("%*schoice"), indent - 1, ""); if (cnt == 1) { printf("[1]: 1\n"); goto conf_childs; } printf("[1-%d", cnt); if (menu_has_help(menu)) printf("?"); printf("]: "); switch (input_mode) { case oldconfig: case silentoldconfig: if (!is_new) { cnt = def; printf("%d\n", cnt); break; } check_stdin(); /* fall through */ case oldaskconfig: fflush(stdout); xfgets(line, 128, stdin); strip(line); if (line[0] == '?') { print_help(menu); continue; } if (!line[0]) cnt = def; else if (isdigit(line[0])) cnt = atoi(line); else continue; break; default: break; } conf_childs: for (child = menu->list; child; child = child->next) { if (!child->sym || !menu_is_visible(child)) continue; if (!--cnt) break; } if (!child) continue; if (line[0] && line[strlen(line) - 1] == '?') { print_help(child); continue; } sym_set_choice_value(sym, child->sym); for (child = child->list; child; child = child->next) { indent += 2; conf(child); indent -= 2; } return 1; } } static void conf(struct menu *menu) { struct symbol *sym; struct property *prop; struct menu *child; if (!menu_is_visible(menu)) return; sym = menu->sym; prop = menu->prompt; if (prop) { const char *prompt; switch (prop->type) { case P_MENU: if ((input_mode == silentoldconfig || input_mode == listnewconfig || input_mode == olddefconfig) && rootEntry != menu) { check_conf(menu); return; } /* fall through */ case P_COMMENT: prompt = menu_get_prompt(menu); if (prompt) printf("%*c\n%*c %s\n%*c\n", indent, '*', indent, '*', _(prompt), indent, '*'); default: ; } } if (!sym) goto conf_childs; if (sym_is_choice(sym)) { conf_choice(menu); if (sym->curr.tri != mod) return; goto conf_childs; } switch (sym->type) { case S_INT: case S_HEX: case S_STRING: conf_string(menu); break; default: conf_sym(menu); break; } conf_childs: if (sym) indent += 2; for (child = menu->list; child; child = child->next) conf(child); if (sym) indent -= 2; } static void check_conf(struct menu *menu) { struct symbol *sym; struct menu *child; if (!menu_is_visible(menu)) return; sym = menu->sym; if (sym && !sym_has_value(sym)) { if (sym_is_changable(sym) || (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { if (input_mode == listnewconfig) { if (sym->name && !sym_is_choice_value(sym)) { printf("%s%s\n", CONFIG_, sym->name); } } else if (input_mode != olddefconfig) { if (!conf_cnt++) printf(_("*\n* Restart config...\n*\n")); rootEntry = menu_get_parent_menu(menu); conf(rootEntry); } } } for (child = menu->list; child; child = child->next) check_conf(child); } static struct option long_opts[] = { {"oldaskconfig", no_argument, NULL, oldaskconfig}, {"oldconfig", no_argument, NULL, oldconfig}, {"silentoldconfig", no_argument, NULL, silentoldconfig}, {"defconfig", optional_argument, NULL, defconfig}, {"savedefconfig", required_argument, NULL, savedefconfig}, {"allnoconfig", no_argument, NULL, allnoconfig}, {"allyesconfig", no_argument, NULL, allyesconfig}, {"allmodconfig", no_argument, NULL, allmodconfig}, {"alldefconfig", no_argument, NULL, alldefconfig}, {"randconfig", no_argument, NULL, randconfig}, {"listnewconfig", no_argument, NULL, listnewconfig}, {"olddefconfig", no_argument, NULL, olddefconfig}, /* * oldnoconfig is an alias of olddefconfig, because people already * are dependent on its behavior(sets new symbols to their default * value but not 'n') with the counter-intuitive name. */ {"oldnoconfig", no_argument, NULL, olddefconfig}, {NULL, 0, NULL, 0} }; static void conf_usage(const char *progname) { printf("Usage: %s [option] \n", progname); printf("[option] is _one_ of the following:\n"); printf(" --listnewconfig List new options\n"); printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); printf(" --oldconfig Update a configuration using a provided .config as base\n"); printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); printf(" --oldnoconfig An alias of olddefconfig\n"); printf(" --defconfig New config with default defined in \n"); printf(" --savedefconfig Save the minimal current configuration to \n"); printf(" --allnoconfig New config where all options are answered with no\n"); printf(" --allyesconfig New config where all options are answered with yes\n"); printf(" --allmodconfig New config where all options are answered with mod\n"); printf(" --alldefconfig New config with all symbols set to default\n"); printf(" --randconfig New config with random answer to all options\n"); } int main(int ac, char **av) { const char *progname = av[0]; int opt; const char *name, *defconfig_file = NULL /* gcc uninit */; struct stat tmpstat; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); tty_stdio = isatty(0) && isatty(1) && isatty(2); while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) { input_mode = (enum input_mode)opt; switch (opt) { case silentoldconfig: sync_kconfig = 1; break; case defconfig: case savedefconfig: defconfig_file = optarg; break; case randconfig: { struct timeval now; unsigned int seed; char *seed_env; /* * Use microseconds derived seed, * compensate for systems where it may be zero */ gettimeofday(&now, NULL); seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); seed_env = getenv("KCONFIG_SEED"); if( seed_env && *seed_env ) { char *endp; int tmp = (int)strtol(seed_env, &endp, 0); if (*endp == '\0') { seed = tmp; } } fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); srand(seed); break; } case oldaskconfig: case oldconfig: case allnoconfig: case allyesconfig: case allmodconfig: case alldefconfig: case listnewconfig: case olddefconfig: break; case '?': conf_usage(progname); exit(1); break; } } if (ac == optind) { printf(_("%s: Kconfig file missing\n"), av[0]); conf_usage(progname); exit(1); } name = av[optind]; conf_parse(name); //zconfdump(stdout); if (sync_kconfig) { name = conf_get_configname(); if (stat(name, &tmpstat)) { fprintf(stderr, _("***\n" "*** Configuration file \"%s\" not found!\n" "***\n" "*** Please run some configurator (e.g. \"make oldconfig\" or\n" "*** \"make menuconfig\" or \"make xconfig\").\n" "***\n"), name); exit(1); } } switch (input_mode) { case defconfig: if (!defconfig_file) defconfig_file = conf_get_default_confname(); if (conf_read(defconfig_file)) { printf(_("***\n" "*** Can't find default configuration \"%s\"!\n" "***\n"), defconfig_file); exit(1); } break; case savedefconfig: case silentoldconfig: case oldaskconfig: case oldconfig: case listnewconfig: case olddefconfig: conf_read(NULL); break; case allnoconfig: case allyesconfig: case allmodconfig: case alldefconfig: case randconfig: name = getenv("KCONFIG_ALLCONFIG"); if (!name) break; if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { if (conf_read_simple(name, S_DEF_USER)) { fprintf(stderr, _("*** Can't read seed configuration \"%s\"!\n"), name); exit(1); } break; } switch (input_mode) { case allnoconfig: name = "allno.config"; break; case allyesconfig: name = "allyes.config"; break; case allmodconfig: name = "allmod.config"; break; case alldefconfig: name = "alldef.config"; break; case randconfig: name = "allrandom.config"; break; default: break; } if (conf_read_simple(name, S_DEF_USER) && conf_read_simple("all.config", S_DEF_USER)) { fprintf(stderr, _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), name); exit(1); } break; default: break; } if (sync_kconfig) { if (conf_get_changed()) { name = getenv("KCONFIG_NOSILENTUPDATE"); if (name && *name) { fprintf(stderr, _("\n*** The configuration requires explicit update.\n\n")); return 1; } } valid_stdin = tty_stdio; } switch (input_mode) { case allnoconfig: conf_set_all_new_symbols(def_no); break; case allyesconfig: conf_set_all_new_symbols(def_yes); break; case allmodconfig: conf_set_all_new_symbols(def_mod); break; case alldefconfig: conf_set_all_new_symbols(def_default); break; case randconfig: /* Really nothing to do in this loop */ while (conf_set_all_new_symbols(def_random)) ; break; case defconfig: conf_set_all_new_symbols(def_default); break; case savedefconfig: break; case oldaskconfig: rootEntry = &rootmenu; conf(&rootmenu); input_mode = silentoldconfig; /* fall through */ case oldconfig: case listnewconfig: case olddefconfig: case silentoldconfig: /* Update until a loop caused no more changes */ do { conf_cnt = 0; check_conf(&rootmenu); } while (conf_cnt && (input_mode != listnewconfig && input_mode != olddefconfig)); break; } if (sync_kconfig) { /* silentoldconfig is used during the build so we shall update autoconf. * All other commands are only used to generate a config. */ if (conf_get_changed() && conf_write(NULL)) { fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); exit(1); } if (conf_write_autoconf()) { fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); return 1; } } else if (input_mode == savedefconfig) { if (conf_write_defconfig(defconfig_file)) { fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), defconfig_file); return 1; } } else if (input_mode != listnewconfig) { if (conf_write(NULL)) { fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); exit(1); } } return 0; } /* * Helper function to facilitate fgets() by Jean Sacren. */ void xfgets(char *str, int size, FILE *in) { if (fgets(str, size, in) == NULL) fprintf(stderr, "\nError in reading or end of file.\n"); } ================================================ FILE: kconfig/confdata.c ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include #include #include #include #include #include #include "lkc.h" static void conf_warning(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); static void conf_message(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); static const char *conf_filename; static int conf_lineno, conf_warnings, conf_unsaved; const char conf_defname[] = "arch/$ARCH/defconfig"; static void conf_warning(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); conf_warnings++; } static void conf_default_message_callback(const char *fmt, va_list ap) { printf("#\n# "); vprintf(fmt, ap); printf("\n#\n"); } static void (*conf_message_callback) (const char *fmt, va_list ap) = conf_default_message_callback; void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) { conf_message_callback = fn; } static void conf_message(const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (conf_message_callback) conf_message_callback(fmt, ap); } const char *conf_get_configname(void) { char *name = getenv("KCONFIG_CONFIG"); return name ? name : ".config"; } const char *conf_get_autoconfig_name(void) { char *name = getenv("KCONFIG_AUTOCONFIG"); return name ? name : "include/config/auto.conf"; } static char *conf_expand_value(const char *in) { struct symbol *sym; const char *src; static char res_value[SYMBOL_MAXLENGTH]; char *dst, name[SYMBOL_MAXLENGTH]; res_value[0] = 0; dst = name; while ((src = strchr(in, '$'))) { strncat(res_value, in, src - in); src++; dst = name; while (isalnum(*src) || *src == '_') *dst++ = *src++; *dst = 0; sym = sym_lookup(name, 0); sym_calc_value(sym); strcat(res_value, sym_get_string_value(sym)); in = src; } strcat(res_value, in); return res_value; } char *conf_get_default_confname(void) { struct stat buf; static char fullname[PATH_MAX+1]; char *env, *name; name = conf_expand_value(conf_defname); env = getenv(SRCTREE); if (env) { sprintf(fullname, "%s/%s", env, name); if (!stat(fullname, &buf)) return fullname; } return name; } static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) { char *p2; switch (sym->type) { case S_TRISTATE: if (p[0] == 'm') { sym->def[def].tri = mod; sym->flags |= def_flags; break; } /* fall through */ case S_BOOLEAN: if (p[0] == 'y') { sym->def[def].tri = yes; sym->flags |= def_flags; break; } if (p[0] == 'n') { sym->def[def].tri = no; sym->flags |= def_flags; break; } if (def != S_DEF_AUTO) conf_warning("symbol value '%s' invalid for %s", p, sym->name); return 1; case S_OTHER: if (*p != '"') { for (p2 = p; *p2 && !isspace(*p2); p2++) ; sym->type = S_STRING; goto done; } /* fall through */ case S_STRING: if (*p++ != '"') break; for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { if (*p2 == '"') { *p2 = 0; break; } memmove(p2, p2 + 1, strlen(p2)); } if (!p2) { if (def != S_DEF_AUTO) conf_warning("invalid string found"); return 1; } /* fall through */ case S_INT: case S_HEX: done: if (sym_string_valid(sym, p)) { sym->def[def].val = strdup(p); sym->flags |= def_flags; } else { if (def != S_DEF_AUTO) conf_warning("symbol value '%s' invalid for %s", p, sym->name); return 1; } break; default: ; } return 0; } #define LINE_GROWTH 16 static int add_byte(int c, char **lineptr, size_t slen, size_t *n) { char *nline; size_t new_size = slen + 1; if (new_size > *n) { new_size += LINE_GROWTH - 1; new_size *= 2; nline = realloc(*lineptr, new_size); if (!nline) return -1; *lineptr = nline; *n = new_size; } (*lineptr)[slen] = c; return 0; } static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) { char *line = *lineptr; size_t slen = 0; for (;;) { int c = getc(stream); switch (c) { case '\n': if (add_byte(c, &line, slen, n) < 0) goto e_out; slen++; /* fall through */ case EOF: if (add_byte('\0', &line, slen, n) < 0) goto e_out; *lineptr = line; if (slen == 0) return -1; return slen; default: if (add_byte(c, &line, slen, n) < 0) goto e_out; slen++; } } e_out: line[slen-1] = '\0'; *lineptr = line; return -1; } int conf_read_simple(const char *name, int def) { FILE *in = NULL; char *line = NULL; size_t line_asize = 0; char *p, *p2; struct symbol *sym; int i, def_flags; if (name) { in = zconf_fopen(name); } else { struct property *prop; name = conf_get_configname(); in = zconf_fopen(name); if (in) goto load; sym_add_change_count(1); if (!sym_defconfig_list) { if (modules_sym) sym_calc_value(modules_sym); return 1; } for_all_defaults(sym_defconfig_list, prop) { if (expr_calc_value(prop->visible.expr) == no || prop->expr->type != E_SYMBOL) continue; name = conf_expand_value(prop->expr->left.sym->name); in = zconf_fopen(name); if (in) { conf_message(_("using defaults found in %s"), name); goto load; } } } if (!in) return 1; load: conf_filename = name; conf_lineno = 0; conf_warnings = 0; conf_unsaved = 0; def_flags = SYMBOL_DEF << def; for_all_symbols(i, sym) { sym->flags |= SYMBOL_CHANGED; sym->flags &= ~(def_flags|SYMBOL_VALID); if (sym_is_choice(sym)) sym->flags |= def_flags; switch (sym->type) { case S_INT: case S_HEX: case S_STRING: if (sym->def[def].val) free(sym->def[def].val); /* fall through */ default: sym->def[def].val = NULL; sym->def[def].tri = no; } } while (compat_getline(&line, &line_asize, in) != -1) { conf_lineno++; sym = NULL; if (line[0] == '#') { if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) continue; p = strchr(line + 2 + strlen(CONFIG_), ' '); if (!p) continue; *p++ = 0; if (strncmp(p, "is not set", 10)) continue; if (def == S_DEF_USER) { sym = sym_find(line + 2 + strlen(CONFIG_)); if (!sym) { sym_add_change_count(1); goto setsym; } } else { sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); if (sym->type == S_UNKNOWN) sym->type = S_BOOLEAN; } if (sym->flags & def_flags) { conf_warning("override: reassigning to symbol %s", sym->name); } switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: sym->def[def].tri = no; sym->flags |= def_flags; break; default: ; } } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { p = strchr(line + strlen(CONFIG_), '='); if (!p) continue; *p++ = 0; p2 = strchr(p, '\n'); if (p2) { *p2-- = 0; if (*p2 == '\r') *p2 = 0; } if (def == S_DEF_USER) { sym = sym_find(line + strlen(CONFIG_)); if (!sym) { sym_add_change_count(1); goto setsym; } } else { sym = sym_lookup(line + strlen(CONFIG_), 0); if (sym->type == S_UNKNOWN) sym->type = S_OTHER; } if (sym->flags & def_flags) { conf_warning("override: reassigning to symbol %s", sym->name); } if (conf_set_sym_val(sym, def, def_flags, p)) continue; } else { if (line[0] != '\r' && line[0] != '\n') conf_warning("unexpected data"); continue; } setsym: if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); switch (sym->def[def].tri) { case no: break; case mod: if (cs->def[def].tri == yes) { conf_warning("%s creates inconsistent choice state", sym->name); cs->flags &= ~def_flags; } break; case yes: if (cs->def[def].tri != no) conf_warning("override: %s changes choice state", sym->name); cs->def[def].val = sym; break; } cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); } } free(line); fclose(in); if (modules_sym) sym_calc_value(modules_sym); return 0; } int conf_read(const char *name) { struct symbol *sym; int i; sym_set_change_count(0); if (conf_read_simple(name, S_DEF_USER)) return 1; for_all_symbols(i, sym) { sym_calc_value(sym); if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) continue; if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { /* check that calculated value agrees with saved value */ switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) break; if (!sym_is_choice(sym)) continue; /* fall through */ default: if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) continue; break; } } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) /* no previous value and not saved */ continue; conf_unsaved++; /* maybe print value in verbose mode... */ } for_all_symbols(i, sym) { if (sym_has_value(sym) && !sym_is_choice_value(sym)) { /* Reset values of generates values, so they'll appear * as new, if they should become visible, but that * doesn't quite work if the Kconfig and the saved * configuration disagree. */ if (sym->visible == no && !conf_unsaved) sym->flags &= ~SYMBOL_DEF_USER; switch (sym->type) { case S_STRING: case S_INT: case S_HEX: /* Reset a string value if it's out of range */ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) break; sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); conf_unsaved++; break; default: break; } } } sym_add_change_count(conf_warnings || conf_unsaved); return 0; } /* * Kconfig configuration printer * * This printer is used when generating the resulting configuration after * kconfig invocation and `defconfig' files. Unset symbol might be omitted by * passing a non-NULL argument to the printer. * */ static void kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) { switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: if (*value == 'n') { bool skip_unset = (arg != NULL); if (!skip_unset) fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name); return; } break; default: break; } fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); } static void kconfig_print_comment(FILE *fp, const char *value, void *arg) { const char *p = value; size_t l; for (;;) { l = strcspn(p, "\n"); fprintf(fp, "#"); if (l) { fprintf(fp, " "); xfwrite(p, l, 1, fp); p += l; } fprintf(fp, "\n"); if (*p++ == '\0') break; } } static struct conf_printer kconfig_printer_cb = { .print_symbol = kconfig_print_symbol, .print_comment = kconfig_print_comment, }; /* * Header printer * * This printer is used when generating the `include/generated/autoconf.h' file. */ static void header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) { switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: { const char *suffix = ""; switch (*value) { case 'n': break; case 'm': suffix = "_MODULE"; /* fall through */ default: fprintf(fp, "#define %s%s%s 1\n", CONFIG_, sym->name, suffix); } break; } case S_HEX: { const char *prefix = ""; if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) prefix = "0x"; fprintf(fp, "#define %s%s %s%s\n", CONFIG_, sym->name, prefix, value); break; } case S_STRING: case S_INT: fprintf(fp, "#define %s%s %s\n", CONFIG_, sym->name, value); break; default: break; } } static void header_print_comment(FILE *fp, const char *value, void *arg) { const char *p = value; size_t l; fprintf(fp, "/*\n"); for (;;) { l = strcspn(p, "\n"); fprintf(fp, " *"); if (l) { fprintf(fp, " "); xfwrite(p, l, 1, fp); p += l; } fprintf(fp, "\n"); if (*p++ == '\0') break; } fprintf(fp, " */\n"); } static struct conf_printer header_printer_cb = { .print_symbol = header_print_symbol, .print_comment = header_print_comment, }; /* * Tristate printer * * This printer is used when generating the `include/config/tristate.conf' file. */ static void tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) { if (sym->type == S_TRISTATE && *value != 'n') fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); } static struct conf_printer tristate_printer_cb = { .print_symbol = tristate_print_symbol, .print_comment = kconfig_print_comment, }; static void conf_write_symbol(FILE *fp, struct symbol *sym, struct conf_printer *printer, void *printer_arg) { const char *str; switch (sym->type) { case S_OTHER: case S_UNKNOWN: break; case S_STRING: str = sym_get_string_value(sym); str = sym_escape_string_value(str); printer->print_symbol(fp, sym, str, printer_arg); free((void *)str); break; default: str = sym_get_string_value(sym); printer->print_symbol(fp, sym, str, printer_arg); } } static void conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) { char buf[256]; snprintf(buf, sizeof(buf), "\n" "Automatically generated file; DO NOT EDIT.\n" "%s\n", rootmenu.prompt->text); printer->print_comment(fp, buf, printer_arg); } /* * Write out a minimal config. * All values that has default values are skipped as this is redundant. */ int conf_write_defconfig(const char *filename) { struct symbol *sym; struct menu *menu; FILE *out; out = fopen(filename, "w"); if (!out) return 1; sym_clear_all_valid(); /* Traverse all menus to find all relevant symbols */ menu = rootmenu.list; while (menu != NULL) { sym = menu->sym; if (sym == NULL) { if (!menu_is_visible(menu)) goto next_menu; } else if (!sym_is_choice(sym)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) goto next_menu; sym->flags &= ~SYMBOL_WRITE; /* If we cannot change the symbol - skip */ if (!sym_is_changable(sym)) goto next_menu; /* If symbol equals to default value - skip */ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) goto next_menu; /* * If symbol is a choice value and equals to the * default for a choice - skip. * But only if value is bool and equal to "y" and * choice is not "optional". * (If choice is "optional" then all values can be "n") */ if (sym_is_choice_value(sym)) { struct symbol *cs; struct symbol *ds; cs = prop_get_symbol(sym_get_choice_prop(sym)); ds = sym_choice_default(cs); if (!sym_is_optional(cs) && sym == ds) { if ((sym->type == S_BOOLEAN) && sym_get_tristate_value(sym) == yes) goto next_menu; } } conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); } next_menu: if (menu->list != NULL) { menu = menu->list; } else if (menu->next != NULL) { menu = menu->next; } else { while ((menu = menu->parent)) { if (menu->next != NULL) { menu = menu->next; break; } } } } fclose(out); return 0; } int conf_write(const char *name) { FILE *out; struct symbol *sym; struct menu *menu; const char *basename; const char *str; char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; char *env; dirname[0] = 0; if (name && name[0]) { struct stat st; char *slash; if (!stat(name, &st) && S_ISDIR(st.st_mode)) { strcpy(dirname, name); strcat(dirname, "/"); basename = conf_get_configname(); } else if ((slash = strrchr(name, '/'))) { int size = slash - name + 1; memcpy(dirname, name, size); dirname[size] = 0; if (slash[1]) basename = slash + 1; else basename = conf_get_configname(); } else basename = name; } else basename = conf_get_configname(); sprintf(newname, "%s%s", dirname, basename); env = getenv("KCONFIG_OVERWRITECONFIG"); if (!env || !*env) { sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); out = fopen(tmpname, "w"); } else { *tmpname = 0; out = fopen(newname, "w"); } if (!out) return 1; conf_write_heading(out, &kconfig_printer_cb, NULL); if (!conf_get_changed()) sym_clear_all_valid(); menu = rootmenu.list; while (menu) { sym = menu->sym; if (!sym) { if (!menu_is_visible(menu)) goto next; str = menu_get_prompt(menu); fprintf(out, "\n" "#\n" "# %s\n" "#\n", str); } else if (!(sym->flags & SYMBOL_CHOICE)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) goto next; sym->flags &= ~SYMBOL_WRITE; conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); } next: if (menu->list) { menu = menu->list; continue; } if (menu->next) menu = menu->next; else while ((menu = menu->parent)) { if (menu->next) { menu = menu->next; break; } } } fclose(out); if (*tmpname) { strcat(dirname, basename); strcat(dirname, ".old"); rename(newname, dirname); if (rename(tmpname, newname)) return 1; } conf_message(_("configuration written to %s"), newname); sym_set_change_count(0); return 0; } static int conf_split_config(void) { const char *name; char path[PATH_MAX+1]; char *s, *d, c; struct symbol *sym; struct stat sb; int res, i, fd; name = conf_get_autoconfig_name(); conf_read_simple(name, S_DEF_AUTO); if (chdir("include/config")) return 1; res = 0; for_all_symbols(i, sym) { sym_calc_value(sym); if ((sym->flags & SYMBOL_AUTO) || !sym->name) continue; if (sym->flags & SYMBOL_WRITE) { if (sym->flags & SYMBOL_DEF_AUTO) { /* * symbol has old and new value, * so compare them... */ switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: if (sym_get_tristate_value(sym) == sym->def[S_DEF_AUTO].tri) continue; break; case S_STRING: case S_HEX: case S_INT: if (!strcmp(sym_get_string_value(sym), sym->def[S_DEF_AUTO].val)) continue; break; default: break; } } else { /* * If there is no old value, only 'no' (unset) * is allowed as new value. */ switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: if (sym_get_tristate_value(sym) == no) continue; break; default: break; } } } else if (!(sym->flags & SYMBOL_DEF_AUTO)) /* There is neither an old nor a new value. */ continue; /* else * There is an old value, but no new value ('no' (unset) * isn't saved in auto.conf, so the old value is always * different from 'no'). */ /* Replace all '_' and append ".h" */ s = sym->name; d = path; while ((c = *s++)) { c = tolower(c); *d++ = (c == '_') ? '/' : c; } strcpy(d, ".h"); /* Assume directory path already exists. */ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { if (errno != ENOENT) { res = 1; break; } /* * Create directory components, * unless they exist already. */ d = path; while ((d = strchr(d, '/'))) { *d = 0; if (stat(path, &sb) && mkdir(path, 0755)) { res = 1; goto out; } *d++ = '/'; } /* Try it again. */ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { res = 1; break; } } close(fd); } out: if (chdir("../..")) return 1; return res; } int conf_write_autoconf(void) { struct symbol *sym; const char *name; FILE *out, *tristate, *out_h; int i; sym_clear_all_valid(); file_write_dep("include/config/auto.conf.cmd"); if (conf_split_config()) return 1; out = fopen(".tmpconfig", "w"); if (!out) return 1; tristate = fopen(".tmpconfig_tristate", "w"); if (!tristate) { fclose(out); return 1; } out_h = fopen(".tmpconfig.h", "w"); if (!out_h) { fclose(out); fclose(tristate); return 1; } conf_write_heading(out, &kconfig_printer_cb, NULL); conf_write_heading(tristate, &tristate_printer_cb, NULL); conf_write_heading(out_h, &header_printer_cb, NULL); for_all_symbols(i, sym) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE) || !sym->name) continue; /* write symbol to auto.conf, tristate and header files */ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); conf_write_symbol(out_h, sym, &header_printer_cb, NULL); } fclose(out); fclose(tristate); fclose(out_h); name = getenv("KCONFIG_AUTOHEADER"); if (!name) name = "include/generated/autoconf.h"; if (rename(".tmpconfig.h", name)) return 1; name = getenv("KCONFIG_TRISTATE"); if (!name) name = "include/config/tristate.conf"; if (rename(".tmpconfig_tristate", name)) return 1; name = conf_get_autoconfig_name(); /* * This must be the last step, kbuild has a dependency on auto.conf * and this marks the successful completion of the previous steps. */ if (rename(".tmpconfig", name)) return 1; return 0; } static int sym_change_count; static void (*conf_changed_callback)(void); void sym_set_change_count(int count) { int _sym_change_count = sym_change_count; sym_change_count = count; if (conf_changed_callback && (bool)_sym_change_count != (bool)count) conf_changed_callback(); } void sym_add_change_count(int count) { sym_set_change_count(count + sym_change_count); } bool conf_get_changed(void) { return sym_change_count; } void conf_set_changed_callback(void (*fn)(void)) { conf_changed_callback = fn; } static bool randomize_choice_values(struct symbol *csym) { struct property *prop; struct symbol *sym; struct expr *e; int cnt, def; /* * If choice is mod then we may have more items selected * and if no then no-one. * In both cases stop. */ if (csym->curr.tri != yes) return false; prop = sym_get_choice_prop(csym); /* count entries in choice block */ cnt = 0; expr_list_for_each_sym(prop->expr, e, sym) cnt++; /* * find a random value and set it to yes, * set the rest to no so we have only one set */ def = (rand() % cnt); cnt = 0; expr_list_for_each_sym(prop->expr, e, sym) { if (def == cnt++) { sym->def[S_DEF_USER].tri = yes; csym->def[S_DEF_USER].val = sym; } else { sym->def[S_DEF_USER].tri = no; } sym->flags |= SYMBOL_DEF_USER; /* clear VALID to get value calculated */ sym->flags &= ~SYMBOL_VALID; } csym->flags |= SYMBOL_DEF_USER; /* clear VALID to get value calculated */ csym->flags &= ~(SYMBOL_VALID); return true; } void set_all_choice_values(struct symbol *csym) { struct property *prop; struct symbol *sym; struct expr *e; prop = sym_get_choice_prop(csym); /* * Set all non-assinged choice values to no */ expr_list_for_each_sym(prop->expr, e, sym) { if (!sym_has_value(sym)) sym->def[S_DEF_USER].tri = no; } csym->flags |= SYMBOL_DEF_USER; /* clear VALID to get value calculated */ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); } bool conf_set_all_new_symbols(enum conf_def_mode mode) { struct symbol *sym, *csym; int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y * pty: probability of tristate = y * ptm: probability of tristate = m */ pby = 50; pty = ptm = 33; /* can't go as the default in switch-case * below, otherwise gcc whines about * -Wmaybe-uninitialized */ if (mode == def_random) { int n, p[3]; char *env = getenv("KCONFIG_PROBABILITY"); n = 0; while( env && *env ) { char *endp; int tmp = strtol( env, &endp, 10 ); if( tmp >= 0 && tmp <= 100 ) { p[n++] = tmp; } else { errno = ERANGE; perror( "KCONFIG_PROBABILITY" ); exit( 1 ); } env = (*endp == ':') ? endp+1 : endp; if( n >=3 ) { break; } } switch( n ) { case 1: pby = p[0]; ptm = pby/2; pty = pby-ptm; break; case 2: pty = p[0]; ptm = p[1]; pby = pty + ptm; break; case 3: pby = p[0]; pty = p[1]; ptm = p[2]; break; } if( pty+ptm > 100 ) { errno = ERANGE; perror( "KCONFIG_PROBABILITY" ); exit( 1 ); } } bool has_changed = false; for_all_symbols(i, sym) { if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) continue; switch (sym_get_type(sym)) { case S_BOOLEAN: case S_TRISTATE: has_changed = true; switch (mode) { case def_yes: sym->def[S_DEF_USER].tri = yes; break; case def_mod: sym->def[S_DEF_USER].tri = mod; break; case def_no: if (sym->flags & SYMBOL_ALLNOCONFIG_Y) sym->def[S_DEF_USER].tri = yes; else sym->def[S_DEF_USER].tri = no; break; case def_random: sym->def[S_DEF_USER].tri = no; cnt = rand() % 100; if (sym->type == S_TRISTATE) { if (cnt < pty) sym->def[S_DEF_USER].tri = yes; else if (cnt < (pty+ptm)) sym->def[S_DEF_USER].tri = mod; } else if (cnt < pby) sym->def[S_DEF_USER].tri = yes; break; default: continue; } if (!(sym_is_choice(sym) && mode == def_random)) sym->flags |= SYMBOL_DEF_USER; break; default: break; } } sym_clear_all_valid(); /* * We have different type of choice blocks. * If curr.tri equals to mod then we can select several * choice symbols in one block. * In this case we do nothing. * If curr.tri equals yes then only one symbol can be * selected in a choice block and we set it to yes, * and the rest to no. */ if (mode != def_random) { for_all_symbols(i, csym) { if ((sym_is_choice(csym) && !sym_has_value(csym)) || sym_is_choice_value(csym)) csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; } } for_all_symbols(i, csym) { if (sym_has_value(csym) || !sym_is_choice(csym)) continue; sym_calc_value(csym); if (mode == def_random) has_changed = randomize_choice_values(csym); else { set_all_choice_values(csym); has_changed = true; } } return has_changed; } ================================================ FILE: kconfig/expr.c ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include "lkc.h" #define DEBUG_EXPR 0 struct expr *expr_alloc_symbol(struct symbol *sym) { struct expr *e = xcalloc(1, sizeof(*e)); e->type = E_SYMBOL; e->left.sym = sym; return e; } struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) { struct expr *e = xcalloc(1, sizeof(*e)); e->type = type; e->left.expr = ce; return e; } struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) { struct expr *e = xcalloc(1, sizeof(*e)); e->type = type; e->left.expr = e1; e->right.expr = e2; return e; } struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) { struct expr *e = xcalloc(1, sizeof(*e)); e->type = type; e->left.sym = s1; e->right.sym = s2; return e; } struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) { if (!e1) return e2; return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; } struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) { if (!e1) return e2; return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; } struct expr *expr_copy(const struct expr *org) { struct expr *e; if (!org) return NULL; e = xmalloc(sizeof(*org)); memcpy(e, org, sizeof(*org)); switch (org->type) { case E_SYMBOL: e->left = org->left; break; case E_NOT: e->left.expr = expr_copy(org->left.expr); break; case E_EQUAL: case E_UNEQUAL: e->left.sym = org->left.sym; e->right.sym = org->right.sym; break; case E_AND: case E_OR: case E_LIST: e->left.expr = expr_copy(org->left.expr); e->right.expr = expr_copy(org->right.expr); break; default: printf("can't copy type %d\n", e->type); free(e); e = NULL; break; } return e; } void expr_free(struct expr *e) { if (!e) return; switch (e->type) { case E_SYMBOL: break; case E_NOT: expr_free(e->left.expr); return; case E_EQUAL: case E_UNEQUAL: break; case E_OR: case E_AND: expr_free(e->left.expr); expr_free(e->right.expr); break; default: printf("how to free type %d?\n", e->type); break; } free(e); } static int trans_count; #define e1 (*ep1) #define e2 (*ep2) static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) { if (e1->type == type) { __expr_eliminate_eq(type, &e1->left.expr, &e2); __expr_eliminate_eq(type, &e1->right.expr, &e2); return; } if (e2->type == type) { __expr_eliminate_eq(type, &e1, &e2->left.expr); __expr_eliminate_eq(type, &e1, &e2->right.expr); return; } if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && e1->left.sym == e2->left.sym && (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) return; if (!expr_eq(e1, e2)) return; trans_count++; expr_free(e1); expr_free(e2); switch (type) { case E_OR: e1 = expr_alloc_symbol(&symbol_no); e2 = expr_alloc_symbol(&symbol_no); break; case E_AND: e1 = expr_alloc_symbol(&symbol_yes); e2 = expr_alloc_symbol(&symbol_yes); break; default: ; } } void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) { if (!e1 || !e2) return; switch (e1->type) { case E_OR: case E_AND: __expr_eliminate_eq(e1->type, ep1, ep2); default: ; } if (e1->type != e2->type) switch (e2->type) { case E_OR: case E_AND: __expr_eliminate_eq(e2->type, ep1, ep2); default: ; } e1 = expr_eliminate_yn(e1); e2 = expr_eliminate_yn(e2); } #undef e1 #undef e2 int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; if (e1->type != e2->type) return 0; switch (e1->type) { case E_EQUAL: case E_UNEQUAL: return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; case E_SYMBOL: return e1->left.sym == e2->left.sym; case E_NOT: return expr_eq(e1->left.expr, e2->left.expr); case E_AND: case E_OR: e1 = expr_copy(e1); e2 = expr_copy(e2); old_count = trans_count; expr_eliminate_eq(&e1, &e2); res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && e1->left.sym == e2->left.sym); expr_free(e1); expr_free(e2); trans_count = old_count; return res; case E_LIST: case E_RANGE: case E_NONE: /* panic */; } if (DEBUG_EXPR) { expr_fprint(e1, stdout); printf(" = "); expr_fprint(e2, stdout); printf(" ?\n"); } return 0; } struct expr *expr_eliminate_yn(struct expr *e) { struct expr *tmp; if (e) switch (e->type) { case E_AND: e->left.expr = expr_eliminate_yn(e->left.expr); e->right.expr = expr_eliminate_yn(e->right.expr); if (e->left.expr->type == E_SYMBOL) { if (e->left.expr->left.sym == &symbol_no) { expr_free(e->left.expr); expr_free(e->right.expr); e->type = E_SYMBOL; e->left.sym = &symbol_no; e->right.expr = NULL; return e; } else if (e->left.expr->left.sym == &symbol_yes) { free(e->left.expr); tmp = e->right.expr; *e = *(e->right.expr); free(tmp); return e; } } if (e->right.expr->type == E_SYMBOL) { if (e->right.expr->left.sym == &symbol_no) { expr_free(e->left.expr); expr_free(e->right.expr); e->type = E_SYMBOL; e->left.sym = &symbol_no; e->right.expr = NULL; return e; } else if (e->right.expr->left.sym == &symbol_yes) { free(e->right.expr); tmp = e->left.expr; *e = *(e->left.expr); free(tmp); return e; } } break; case E_OR: e->left.expr = expr_eliminate_yn(e->left.expr); e->right.expr = expr_eliminate_yn(e->right.expr); if (e->left.expr->type == E_SYMBOL) { if (e->left.expr->left.sym == &symbol_no) { free(e->left.expr); tmp = e->right.expr; *e = *(e->right.expr); free(tmp); return e; } else if (e->left.expr->left.sym == &symbol_yes) { expr_free(e->left.expr); expr_free(e->right.expr); e->type = E_SYMBOL; e->left.sym = &symbol_yes; e->right.expr = NULL; return e; } } if (e->right.expr->type == E_SYMBOL) { if (e->right.expr->left.sym == &symbol_no) { free(e->right.expr); tmp = e->left.expr; *e = *(e->left.expr); free(tmp); return e; } else if (e->right.expr->left.sym == &symbol_yes) { expr_free(e->left.expr); expr_free(e->right.expr); e->type = E_SYMBOL; e->left.sym = &symbol_yes; e->right.expr = NULL; return e; } } break; default: ; } return e; } /* * bool FOO!=n => FOO */ struct expr *expr_trans_bool(struct expr *e) { if (!e) return NULL; switch (e->type) { case E_AND: case E_OR: case E_NOT: e->left.expr = expr_trans_bool(e->left.expr); e->right.expr = expr_trans_bool(e->right.expr); break; case E_UNEQUAL: // FOO!=n -> FOO if (e->left.sym->type == S_TRISTATE) { if (e->right.sym == &symbol_no) { e->type = E_SYMBOL; e->right.sym = NULL; } } break; default: ; } return e; } /* * e1 || e2 -> ? */ static struct expr *expr_join_or(struct expr *e1, struct expr *e2) { struct expr *tmp; struct symbol *sym1, *sym2; if (expr_eq(e1, e2)) return expr_copy(e1); if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) return NULL; if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) return NULL; if (e1->type == E_NOT) { tmp = e1->left.expr; if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) return NULL; sym1 = tmp->left.sym; } else sym1 = e1->left.sym; if (e2->type == E_NOT) { if (e2->left.expr->type != E_SYMBOL) return NULL; sym2 = e2->left.expr->left.sym; } else sym2 = e2->left.sym; if (sym1 != sym2) return NULL; if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) return NULL; if (sym1->type == S_TRISTATE) { if (e1->type == E_EQUAL && e2->type == E_EQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { // (a='y') || (a='m') -> (a!='n') return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); } if (e1->type == E_EQUAL && e2->type == E_EQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { // (a='y') || (a='n') -> (a!='m') return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); } if (e1->type == E_EQUAL && e2->type == E_EQUAL && ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { // (a='m') || (a='n') -> (a!='y') return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); } } if (sym1->type == S_BOOLEAN && sym1 == sym2) { if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) return expr_alloc_symbol(&symbol_yes); } if (DEBUG_EXPR) { printf("optimize ("); expr_fprint(e1, stdout); printf(") || ("); expr_fprint(e2, stdout); printf(")?\n"); } return NULL; } static struct expr *expr_join_and(struct expr *e1, struct expr *e2) { struct expr *tmp; struct symbol *sym1, *sym2; if (expr_eq(e1, e2)) return expr_copy(e1); if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) return NULL; if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) return NULL; if (e1->type == E_NOT) { tmp = e1->left.expr; if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) return NULL; sym1 = tmp->left.sym; } else sym1 = e1->left.sym; if (e2->type == E_NOT) { if (e2->left.expr->type != E_SYMBOL) return NULL; sym2 = e2->left.expr->left.sym; } else sym2 = e2->left.sym; if (sym1 != sym2) return NULL; if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) return NULL; if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) // (a) && (a='y') -> (a='y') return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) // (a) && (a!='n') -> (a) return expr_alloc_symbol(sym1); if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) // (a) && (a!='m') -> (a='y') return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); if (sym1->type == S_TRISTATE) { if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' sym2 = e1->right.sym; if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) : expr_alloc_symbol(&symbol_no); } if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' sym2 = e2->right.sym; if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) : expr_alloc_symbol(&symbol_no); } if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) // (a!='y') && (a!='n') -> (a='m') return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) // (a!='y') && (a!='m') -> (a='n') return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) // (a!='m') && (a!='n') -> (a='m') return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) return NULL; } if (DEBUG_EXPR) { printf("optimize ("); expr_fprint(e1, stdout); printf(") && ("); expr_fprint(e2, stdout); printf(")?\n"); } return NULL; } static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) { #define e1 (*ep1) #define e2 (*ep2) struct expr *tmp; if (e1->type == type) { expr_eliminate_dups1(type, &e1->left.expr, &e2); expr_eliminate_dups1(type, &e1->right.expr, &e2); return; } if (e2->type == type) { expr_eliminate_dups1(type, &e1, &e2->left.expr); expr_eliminate_dups1(type, &e1, &e2->right.expr); return; } if (e1 == e2) return; switch (e1->type) { case E_OR: case E_AND: expr_eliminate_dups1(e1->type, &e1, &e1); default: ; } switch (type) { case E_OR: tmp = expr_join_or(e1, e2); if (tmp) { expr_free(e1); expr_free(e2); e1 = expr_alloc_symbol(&symbol_no); e2 = tmp; trans_count++; } break; case E_AND: tmp = expr_join_and(e1, e2); if (tmp) { expr_free(e1); expr_free(e2); e1 = expr_alloc_symbol(&symbol_yes); e2 = tmp; trans_count++; } break; default: ; } #undef e1 #undef e2 } static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2) { #define e1 (*ep1) #define e2 (*ep2) struct expr *tmp, *tmp1, *tmp2; if (e1->type == type) { expr_eliminate_dups2(type, &e1->left.expr, &e2); expr_eliminate_dups2(type, &e1->right.expr, &e2); return; } if (e2->type == type) { expr_eliminate_dups2(type, &e1, &e2->left.expr); expr_eliminate_dups2(type, &e1, &e2->right.expr); } if (e1 == e2) return; switch (e1->type) { case E_OR: expr_eliminate_dups2(e1->type, &e1, &e1); // (FOO || BAR) && (!FOO && !BAR) -> n tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); tmp2 = expr_copy(e2); tmp = expr_extract_eq_and(&tmp1, &tmp2); if (expr_is_yes(tmp1)) { expr_free(e1); e1 = expr_alloc_symbol(&symbol_no); trans_count++; } expr_free(tmp2); expr_free(tmp1); expr_free(tmp); break; case E_AND: expr_eliminate_dups2(e1->type, &e1, &e1); // (FOO && BAR) || (!FOO || !BAR) -> y tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); tmp2 = expr_copy(e2); tmp = expr_extract_eq_or(&tmp1, &tmp2); if (expr_is_no(tmp1)) { expr_free(e1); e1 = expr_alloc_symbol(&symbol_yes); trans_count++; } expr_free(tmp2); expr_free(tmp1); expr_free(tmp); break; default: ; } #undef e1 #undef e2 } struct expr *expr_eliminate_dups(struct expr *e) { int oldcount; if (!e) return e; oldcount = trans_count; while (1) { trans_count = 0; switch (e->type) { case E_OR: case E_AND: expr_eliminate_dups1(e->type, &e, &e); expr_eliminate_dups2(e->type, &e, &e); default: ; } if (!trans_count) break; e = expr_eliminate_yn(e); } trans_count = oldcount; return e; } struct expr *expr_transform(struct expr *e) { struct expr *tmp; if (!e) return NULL; switch (e->type) { case E_EQUAL: case E_UNEQUAL: case E_SYMBOL: case E_LIST: break; default: e->left.expr = expr_transform(e->left.expr); e->right.expr = expr_transform(e->right.expr); } switch (e->type) { case E_EQUAL: if (e->left.sym->type != S_BOOLEAN) break; if (e->right.sym == &symbol_no) { e->type = E_NOT; e->left.expr = expr_alloc_symbol(e->left.sym); e->right.sym = NULL; break; } if (e->right.sym == &symbol_mod) { printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); e->type = E_SYMBOL; e->left.sym = &symbol_no; e->right.sym = NULL; break; } if (e->right.sym == &symbol_yes) { e->type = E_SYMBOL; e->right.sym = NULL; break; } break; case E_UNEQUAL: if (e->left.sym->type != S_BOOLEAN) break; if (e->right.sym == &symbol_no) { e->type = E_SYMBOL; e->right.sym = NULL; break; } if (e->right.sym == &symbol_mod) { printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); e->type = E_SYMBOL; e->left.sym = &symbol_yes; e->right.sym = NULL; break; } if (e->right.sym == &symbol_yes) { e->type = E_NOT; e->left.expr = expr_alloc_symbol(e->left.sym); e->right.sym = NULL; break; } break; case E_NOT: switch (e->left.expr->type) { case E_NOT: // !!a -> a tmp = e->left.expr->left.expr; free(e->left.expr); free(e); e = tmp; e = expr_transform(e); break; case E_EQUAL: case E_UNEQUAL: // !a='x' -> a!='x' tmp = e->left.expr; free(e); e = tmp; e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; break; case E_OR: // !(a || b) -> !a && !b tmp = e->left.expr; e->type = E_AND; e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); tmp->type = E_NOT; tmp->right.expr = NULL; e = expr_transform(e); break; case E_AND: // !(a && b) -> !a || !b tmp = e->left.expr; e->type = E_OR; e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); tmp->type = E_NOT; tmp->right.expr = NULL; e = expr_transform(e); break; case E_SYMBOL: if (e->left.expr->left.sym == &symbol_yes) { // !'y' -> 'n' tmp = e->left.expr; free(e); e = tmp; e->type = E_SYMBOL; e->left.sym = &symbol_no; break; } if (e->left.expr->left.sym == &symbol_mod) { // !'m' -> 'm' tmp = e->left.expr; free(e); e = tmp; e->type = E_SYMBOL; e->left.sym = &symbol_mod; break; } if (e->left.expr->left.sym == &symbol_no) { // !'n' -> 'y' tmp = e->left.expr; free(e); e = tmp; e->type = E_SYMBOL; e->left.sym = &symbol_yes; break; } break; default: ; } break; default: ; } return e; } int expr_contains_symbol(struct expr *dep, struct symbol *sym) { if (!dep) return 0; switch (dep->type) { case E_AND: case E_OR: return expr_contains_symbol(dep->left.expr, sym) || expr_contains_symbol(dep->right.expr, sym); case E_SYMBOL: return dep->left.sym == sym; case E_EQUAL: case E_UNEQUAL: return dep->left.sym == sym || dep->right.sym == sym; case E_NOT: return expr_contains_symbol(dep->left.expr, sym); default: ; } return 0; } bool expr_depends_symbol(struct expr *dep, struct symbol *sym) { if (!dep) return false; switch (dep->type) { case E_AND: return expr_depends_symbol(dep->left.expr, sym) || expr_depends_symbol(dep->right.expr, sym); case E_SYMBOL: return dep->left.sym == sym; case E_EQUAL: if (dep->left.sym == sym) { if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) return true; } break; case E_UNEQUAL: if (dep->left.sym == sym) { if (dep->right.sym == &symbol_no) return true; } break; default: ; } return false; } struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) { struct expr *tmp = NULL; expr_extract_eq(E_AND, &tmp, ep1, ep2); if (tmp) { *ep1 = expr_eliminate_yn(*ep1); *ep2 = expr_eliminate_yn(*ep2); } return tmp; } struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) { struct expr *tmp = NULL; expr_extract_eq(E_OR, &tmp, ep1, ep2); if (tmp) { *ep1 = expr_eliminate_yn(*ep1); *ep2 = expr_eliminate_yn(*ep2); } return tmp; } void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) { #define e1 (*ep1) #define e2 (*ep2) if (e1->type == type) { expr_extract_eq(type, ep, &e1->left.expr, &e2); expr_extract_eq(type, ep, &e1->right.expr, &e2); return; } if (e2->type == type) { expr_extract_eq(type, ep, ep1, &e2->left.expr); expr_extract_eq(type, ep, ep1, &e2->right.expr); return; } if (expr_eq(e1, e2)) { *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1; expr_free(e2); if (type == E_AND) { e1 = expr_alloc_symbol(&symbol_yes); e2 = expr_alloc_symbol(&symbol_yes); } else if (type == E_OR) { e1 = expr_alloc_symbol(&symbol_no); e2 = expr_alloc_symbol(&symbol_no); } } #undef e1 #undef e2 } struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) { struct expr *e1, *e2; if (!e) { e = expr_alloc_symbol(sym); if (type == E_UNEQUAL) e = expr_alloc_one(E_NOT, e); return e; } switch (e->type) { case E_AND: e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); if (sym == &symbol_yes) e = expr_alloc_two(E_AND, e1, e2); if (sym == &symbol_no) e = expr_alloc_two(E_OR, e1, e2); if (type == E_UNEQUAL) e = expr_alloc_one(E_NOT, e); return e; case E_OR: e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); if (sym == &symbol_yes) e = expr_alloc_two(E_OR, e1, e2); if (sym == &symbol_no) e = expr_alloc_two(E_AND, e1, e2); if (type == E_UNEQUAL) e = expr_alloc_one(E_NOT, e); return e; case E_NOT: return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); case E_UNEQUAL: case E_EQUAL: if (type == E_EQUAL) { if (sym == &symbol_yes) return expr_copy(e); if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_no); if (sym == &symbol_no) return expr_alloc_one(E_NOT, expr_copy(e)); } else { if (sym == &symbol_yes) return expr_alloc_one(E_NOT, expr_copy(e)); if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_yes); if (sym == &symbol_no) return expr_copy(e); } break; case E_SYMBOL: return expr_alloc_comp(type, e->left.sym, sym); case E_LIST: case E_RANGE: case E_NONE: /* panic */; } return NULL; } tristate expr_calc_value(struct expr *e) { tristate val1, val2; const char *str1, *str2; if (!e) return yes; switch (e->type) { case E_SYMBOL: sym_calc_value(e->left.sym); return e->left.sym->curr.tri; case E_AND: val1 = expr_calc_value(e->left.expr); val2 = expr_calc_value(e->right.expr); return EXPR_AND(val1, val2); case E_OR: val1 = expr_calc_value(e->left.expr); val2 = expr_calc_value(e->right.expr); return EXPR_OR(val1, val2); case E_NOT: val1 = expr_calc_value(e->left.expr); return EXPR_NOT(val1); case E_EQUAL: sym_calc_value(e->left.sym); sym_calc_value(e->right.sym); str1 = sym_get_string_value(e->left.sym); str2 = sym_get_string_value(e->right.sym); return !strcmp(str1, str2) ? yes : no; case E_UNEQUAL: sym_calc_value(e->left.sym); sym_calc_value(e->right.sym); str1 = sym_get_string_value(e->left.sym); str2 = sym_get_string_value(e->right.sym); return !strcmp(str1, str2) ? no : yes; default: printf("expr_calc_value: %d?\n", e->type); return no; } } int expr_compare_type(enum expr_type t1, enum expr_type t2) { #if 0 return 1; #else if (t1 == t2) return 0; switch (t1) { case E_EQUAL: case E_UNEQUAL: if (t2 == E_NOT) return 1; case E_NOT: if (t2 == E_AND) return 1; case E_AND: if (t2 == E_OR) return 1; case E_OR: if (t2 == E_LIST) return 1; case E_LIST: if (t2 == 0) return 1; default: return -1; } printf("[%dgt%d?]", t1, t2); return 0; #endif } static inline struct expr * expr_get_leftmost_symbol(const struct expr *e) { if (e == NULL) return NULL; while (e->type != E_SYMBOL) e = e->left.expr; return expr_copy(e); } /* * Given expression `e1' and `e2', returns the leaf of the longest * sub-expression of `e1' not containing 'e2. */ struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) { struct expr *ret; switch (e1->type) { case E_OR: return expr_alloc_and( expr_simplify_unmet_dep(e1->left.expr, e2), expr_simplify_unmet_dep(e1->right.expr, e2)); case E_AND: { struct expr *e; e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); e = expr_eliminate_dups(e); ret = (!expr_eq(e, e1)) ? e1 : NULL; expr_free(e); break; } default: ret = e1; break; } return expr_get_leftmost_symbol(ret); } void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) { if (!e) { fn(data, NULL, "y"); return; } if (expr_compare_type(prevtoken, e->type) > 0) fn(data, NULL, "("); switch (e->type) { case E_SYMBOL: if (e->left.sym->name) fn(data, e->left.sym, e->left.sym->name); else fn(data, NULL, ""); break; case E_NOT: fn(data, NULL, "!"); expr_print(e->left.expr, fn, data, E_NOT); break; case E_EQUAL: if (e->left.sym->name) fn(data, e->left.sym, e->left.sym->name); else fn(data, NULL, ""); fn(data, NULL, "="); fn(data, e->right.sym, e->right.sym->name); break; case E_UNEQUAL: if (e->left.sym->name) fn(data, e->left.sym, e->left.sym->name); else fn(data, NULL, ""); fn(data, NULL, "!="); fn(data, e->right.sym, e->right.sym->name); break; case E_OR: expr_print(e->left.expr, fn, data, E_OR); fn(data, NULL, " || "); expr_print(e->right.expr, fn, data, E_OR); break; case E_AND: expr_print(e->left.expr, fn, data, E_AND); fn(data, NULL, " && "); expr_print(e->right.expr, fn, data, E_AND); break; case E_LIST: fn(data, e->right.sym, e->right.sym->name); if (e->left.expr) { fn(data, NULL, " ^ "); expr_print(e->left.expr, fn, data, E_LIST); } break; case E_RANGE: fn(data, NULL, "["); fn(data, e->left.sym, e->left.sym->name); fn(data, NULL, " "); fn(data, e->right.sym, e->right.sym->name); fn(data, NULL, "]"); break; default: { char buf[32]; sprintf(buf, "", e->type); fn(data, NULL, buf); break; } } if (expr_compare_type(prevtoken, e->type) > 0) fn(data, NULL, ")"); } static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) { xfwrite(str, strlen(str), 1, data); } void expr_fprint(struct expr *e, FILE *out) { expr_print(e, expr_print_file_helper, out, E_NONE); } static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) { struct gstr *gs = (struct gstr*)data; const char *sym_str = NULL; if (sym) sym_str = sym_get_string_value(sym); if (gs->max_width) { unsigned extra_length = strlen(str); const char *last_cr = strrchr(gs->s, '\n'); unsigned last_line_length; if (sym_str) extra_length += 4 + strlen(sym_str); if (!last_cr) last_cr = gs->s; last_line_length = strlen(gs->s) - (last_cr - gs->s); if ((last_line_length + extra_length) > gs->max_width) str_append(gs, "\\\n"); } str_append(gs, str); if (sym && sym->type != S_UNKNOWN) str_printf(gs, " [=%s]", sym_str); } void expr_gstr_print(struct expr *e, struct gstr *gs) { expr_print(e, expr_print_gstr_helper, gs, E_NONE); } ================================================ FILE: kconfig/expr.h ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #ifndef EXPR_H #define EXPR_H #ifdef __cplusplus extern "C" { #endif #include #include #include "list.h" #ifndef __cplusplus #include #endif struct file { struct file *next; struct file *parent; const char *name; int lineno; }; typedef enum tristate { no, mod, yes } tristate; enum expr_type { E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE }; union expr_data { struct expr *expr; struct symbol *sym; }; struct expr { enum expr_type type; union expr_data left, right; }; #define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) #define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) #define EXPR_NOT(dep) (2-(dep)) #define expr_list_for_each_sym(l, e, s) \ for (e = (l); e && (s = e->right.sym); e = e->left.expr) struct expr_value { struct expr *expr; tristate tri; }; struct symbol_value { void *val; tristate tri; }; enum symbol_type { S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER }; /* enum values are used as index to symbol.def[] */ enum { S_DEF_USER, /* main user value */ S_DEF_AUTO, /* values read from auto.conf */ S_DEF_DEF3, /* Reserved for UI usage */ S_DEF_DEF4, /* Reserved for UI usage */ S_DEF_COUNT }; struct symbol { struct symbol *next; char *name; enum symbol_type type; struct symbol_value curr; struct symbol_value def[S_DEF_COUNT]; tristate visible; int flags; struct property *prop; struct expr_value dir_dep; struct expr_value rev_dep; }; #define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) #define SYMBOL_CONST 0x0001 /* symbol is const */ #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ #define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ #define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ #define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ #define SYMBOL_CHANGED 0x0400 /* ? */ #define SYMBOL_AUTO 0x1000 /* value from environment variable */ #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ #define SYMBOL_WARNED 0x8000 /* warning has been issued */ /* Set when symbol.def[] is used */ #define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ #define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ #define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ /* choice values need to be set before calculating this symbol value */ #define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 /* Set symbol to y if allnoconfig; used for symbols that hide others */ #define SYMBOL_ALLNOCONFIG_Y 0x200000 #define SYMBOL_MAXLENGTH 256 #define SYMBOL_HASHSIZE 9973 /* A property represent the config options that can be associated * with a config "symbol". * Sample: * config FOO * default y * prompt "foo prompt" * select BAR * config BAZ * int "BAZ Value" * range 1..255 */ enum prop_type { P_UNKNOWN, P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ P_COMMENT, /* text associated with a comment */ P_MENU, /* prompt associated with a menuconfig option */ P_DEFAULT, /* default y */ P_CHOICE, /* choice value */ P_SELECT, /* select BAR */ P_RANGE, /* range 7..100 (for a symbol) */ P_ENV, /* value from environment variable */ P_SYMBOL, /* where a symbol is defined */ }; struct property { struct property *next; /* next property - null if last */ struct symbol *sym; /* the symbol for which the property is associated */ enum prop_type type; /* type of property */ const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ struct expr_value visible; struct expr *expr; /* the optional conditional part of the property */ struct menu *menu; /* the menu the property are associated with * valid for: P_SELECT, P_RANGE, P_CHOICE, * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ struct file *file; /* what file was this property defined */ int lineno; /* what lineno was this property defined */ }; #define for_all_properties(sym, st, tok) \ for (st = sym->prop; st; st = st->next) \ if (st->type == (tok)) #define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) #define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) #define for_all_prompts(sym, st) \ for (st = sym->prop; st; st = st->next) \ if (st->text) struct menu { struct menu *next; struct menu *parent; struct menu *list; struct symbol *sym; struct property *prompt; struct expr *visibility; struct expr *dep; unsigned int flags; char *help; struct file *file; int lineno; void *data; }; #define MENU_CHANGED 0x0001 #define MENU_ROOT 0x0002 struct jump_key { struct list_head entries; size_t offset; struct menu *target; int index; }; #define JUMP_NB 9 extern struct file *file_list; extern struct file *current_file; struct file *lookup_file(const char *name); extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; extern struct symbol *sym_defconfig_list; extern int cdebug; struct expr *expr_alloc_symbol(struct symbol *sym); struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); struct expr *expr_copy(const struct expr *org); void expr_free(struct expr *e); int expr_eq(struct expr *e1, struct expr *e2); void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); tristate expr_calc_value(struct expr *e); struct expr *expr_eliminate_yn(struct expr *e); struct expr *expr_trans_bool(struct expr *e); struct expr *expr_eliminate_dups(struct expr *e); struct expr *expr_transform(struct expr *e); int expr_contains_symbol(struct expr *dep, struct symbol *sym); bool expr_depends_symbol(struct expr *dep, struct symbol *sym); struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); void expr_fprint(struct expr *e, FILE *out); struct gstr; /* forward */ void expr_gstr_print(struct expr *e, struct gstr *gs); static inline int expr_is_yes(struct expr *e) { return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); } static inline int expr_is_no(struct expr *e) { return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); } #ifdef __cplusplus } #endif #endif /* EXPR_H */ ================================================ FILE: kconfig/frosted.conf ================================================ ================================================ FILE: kconfig/gconf.c ================================================ /* Hey EMACS -*- linux-c -*- */ /* * * Copyright (C) 2002-2003 Romain Lievin * Released under the terms of the GNU GPL v2.0. * */ #ifdef HAVE_CONFIG_H # include #endif #include #include "lkc.h" #include "images.c" #include #include #include #include #include #include #include #include //#define DEBUG enum { SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW }; enum { OPT_NORMAL, OPT_ALL, OPT_PROMPT }; static gint view_mode = FULL_VIEW; static gboolean show_name = TRUE; static gboolean show_range = TRUE; static gboolean show_value = TRUE; static gboolean resizeable = FALSE; static int opt_mode = OPT_NORMAL; GtkWidget *main_wnd = NULL; GtkWidget *tree1_w = NULL; // left frame GtkWidget *tree2_w = NULL; // right frame GtkWidget *text_w = NULL; GtkWidget *hpaned = NULL; GtkWidget *vpaned = NULL; GtkWidget *back_btn = NULL; GtkWidget *save_btn = NULL; GtkWidget *save_menu_item = NULL; GtkTextTag *tag1, *tag2; GdkColor color; GtkTreeStore *tree1, *tree2, *tree; GtkTreeModel *model1, *model2; static GtkTreeIter *parents[256]; static gint indent; static struct menu *current; // current node for SINGLE view static struct menu *browsed; // browsed node for SPLIT view enum { COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF, COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD, COL_NUMBER }; static void display_list(void); static void display_tree(struct menu *menu); static void display_tree_part(void); static void update_tree(struct menu *src, GtkTreeIter * dst); static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); static gchar **fill_row(struct menu *menu); static void conf_changed(void); /* Helping/Debugging Functions */ const char *dbg_sym_flags(int val) { static char buf[256]; bzero(buf, 256); if (val & SYMBOL_CONST) strcat(buf, "const/"); if (val & SYMBOL_CHECK) strcat(buf, "check/"); if (val & SYMBOL_CHOICE) strcat(buf, "choice/"); if (val & SYMBOL_CHOICEVAL) strcat(buf, "choiceval/"); if (val & SYMBOL_VALID) strcat(buf, "valid/"); if (val & SYMBOL_OPTIONAL) strcat(buf, "optional/"); if (val & SYMBOL_WRITE) strcat(buf, "write/"); if (val & SYMBOL_CHANGED) strcat(buf, "changed/"); if (val & SYMBOL_AUTO) strcat(buf, "auto/"); buf[strlen(buf) - 1] = '\0'; return buf; } void replace_button_icon(GladeXML * xml, GdkDrawable * window, GtkStyle * style, gchar * btn_name, gchar ** xpm) { GdkPixmap *pixmap; GdkBitmap *mask; GtkToolButton *button; GtkWidget *image; pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, &style->bg[GTK_STATE_NORMAL], xpm); button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); image = gtk_image_new_from_pixmap(pixmap, mask); gtk_widget_show(image); gtk_tool_button_set_icon_widget(button, image); } /* Main Window Initialization */ void init_main_window(const gchar * glade_file) { GladeXML *xml; GtkWidget *widget; GtkTextBuffer *txtbuf; GtkStyle *style; xml = glade_xml_new(glade_file, "window1", NULL); if (!xml) g_error(_("GUI loading failed !\n")); glade_xml_signal_autoconnect(xml); main_wnd = glade_xml_get_widget(xml, "window1"); hpaned = glade_xml_get_widget(xml, "hpaned1"); vpaned = glade_xml_get_widget(xml, "vpaned1"); tree1_w = glade_xml_get_widget(xml, "treeview1"); tree2_w = glade_xml_get_widget(xml, "treeview2"); text_w = glade_xml_get_widget(xml, "textview3"); back_btn = glade_xml_get_widget(xml, "button1"); gtk_widget_set_sensitive(back_btn, FALSE); widget = glade_xml_get_widget(xml, "show_name1"); gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, show_name); widget = glade_xml_get_widget(xml, "show_range1"); gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, show_range); widget = glade_xml_get_widget(xml, "show_data1"); gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, show_value); save_btn = glade_xml_get_widget(xml, "button3"); save_menu_item = glade_xml_get_widget(xml, "save1"); conf_set_changed_callback(conf_changed); style = gtk_widget_get_style(main_wnd); widget = glade_xml_get_widget(xml, "toolbar1"); #if 0 /* Use stock Gtk icons instead */ replace_button_icon(xml, main_wnd->window, style, "button1", (gchar **) xpm_back); replace_button_icon(xml, main_wnd->window, style, "button2", (gchar **) xpm_load); replace_button_icon(xml, main_wnd->window, style, "button3", (gchar **) xpm_save); #endif replace_button_icon(xml, main_wnd->window, style, "button4", (gchar **) xpm_single_view); replace_button_icon(xml, main_wnd->window, style, "button5", (gchar **) xpm_split_view); replace_button_icon(xml, main_wnd->window, style, "button6", (gchar **) xpm_tree_view); #if 0 switch (view_mode) { case SINGLE_VIEW: widget = glade_xml_get_widget(xml, "button4"); g_signal_emit_by_name(widget, "clicked"); break; case SPLIT_VIEW: widget = glade_xml_get_widget(xml, "button5"); g_signal_emit_by_name(widget, "clicked"); break; case FULL_VIEW: widget = glade_xml_get_widget(xml, "button6"); g_signal_emit_by_name(widget, "clicked"); break; } #endif txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", "foreground", "red", "weight", PANGO_WEIGHT_BOLD, NULL); tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", /*"style", PANGO_STYLE_OBLIQUE, */ NULL); gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text); gtk_widget_show(main_wnd); } void init_tree_model(void) { gint i; tree = tree2 = gtk_tree_store_new(COL_NUMBER, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_COLOR, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); model2 = GTK_TREE_MODEL(tree2); for (parents[0] = NULL, i = 1; i < 256; i++) parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); tree1 = gtk_tree_store_new(COL_NUMBER, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_COLOR, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); model1 = GTK_TREE_MODEL(tree1); } void init_left_tree(void) { GtkTreeView *view = GTK_TREE_VIEW(tree1_w); GtkCellRenderer *renderer; GtkTreeSelection *sel; GtkTreeViewColumn *column; gtk_tree_view_set_model(view, model1); gtk_tree_view_set_headers_visible(view, TRUE); gtk_tree_view_set_rules_hint(view, TRUE); column = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, column); gtk_tree_view_column_set_title(column, _("Options")); renderer = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE); gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "active", COL_BTNACT, "inconsistent", COL_BTNINC, "visible", COL_BTNVIS, "radio", COL_BTNRAD, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE); gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "text", COL_OPTION, "foreground-gdk", COL_COLOR, NULL); sel = gtk_tree_view_get_selection(view); gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); gtk_widget_realize(tree1_w); } static void renderer_edited(GtkCellRendererText * cell, const gchar * path_string, const gchar * new_text, gpointer user_data); void init_right_tree(void) { GtkTreeView *view = GTK_TREE_VIEW(tree2_w); GtkCellRenderer *renderer; GtkTreeSelection *sel; GtkTreeViewColumn *column; gint i; gtk_tree_view_set_model(view, model2); gtk_tree_view_set_headers_visible(view, TRUE); gtk_tree_view_set_rules_hint(view, TRUE); column = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, column); gtk_tree_view_column_set_title(column, _("Options")); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE); gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "pixbuf", COL_PIXBUF, "visible", COL_PIXVIS, NULL); renderer = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE); gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "active", COL_BTNACT, "inconsistent", COL_BTNINC, "visible", COL_BTNVIS, "radio", COL_BTNRAD, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE); gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "text", COL_OPTION, "foreground-gdk", COL_COLOR, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, _("Name"), renderer, "text", COL_NAME, "foreground-gdk", COL_COLOR, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, "N", renderer, "text", COL_NO, "foreground-gdk", COL_COLOR, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, "M", renderer, "text", COL_MOD, "foreground-gdk", COL_COLOR, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, "Y", renderer, "text", COL_YES, "foreground-gdk", COL_COLOR, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, _("Value"), renderer, "text", COL_VALUE, "editable", COL_EDIT, "foreground-gdk", COL_COLOR, NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(renderer_edited), NULL); column = gtk_tree_view_get_column(view, COL_NAME); gtk_tree_view_column_set_visible(column, show_name); column = gtk_tree_view_get_column(view, COL_NO); gtk_tree_view_column_set_visible(column, show_range); column = gtk_tree_view_get_column(view, COL_MOD); gtk_tree_view_column_set_visible(column, show_range); column = gtk_tree_view_get_column(view, COL_YES); gtk_tree_view_column_set_visible(column, show_range); column = gtk_tree_view_get_column(view, COL_VALUE); gtk_tree_view_column_set_visible(column, show_value); if (resizeable) { for (i = 0; i < COL_VALUE; i++) { column = gtk_tree_view_get_column(view, i); gtk_tree_view_column_set_resizable(column, TRUE); } } sel = gtk_tree_view_get_selection(view); gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); } /* Utility Functions */ static void text_insert_help(struct menu *menu) { GtkTextBuffer *buffer; GtkTextIter start, end; const char *prompt = _(menu_get_prompt(menu)); struct gstr help = str_new(); menu_get_ext_help(menu, &help); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); gtk_text_buffer_get_bounds(buffer, &start, &end); gtk_text_buffer_delete(buffer, &start, &end); gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, NULL); gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2, NULL); str_free(&help); } static void text_insert_msg(const char *title, const char *message) { GtkTextBuffer *buffer; GtkTextIter start, end; const char *msg = message; buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); gtk_text_buffer_get_bounds(buffer, &start, &end); gtk_text_buffer_delete(buffer, &start, &end); gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1, NULL); gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2, NULL); } /* Main Windows Callbacks */ void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, gpointer user_data) { GtkWidget *dialog, *label; gint result; if (!conf_get_changed()) return FALSE; dialog = gtk_dialog_new_with_buttons(_("Warning !"), GTK_WINDOW(main_wnd), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_STOCK_OK, GTK_RESPONSE_YES, GTK_STOCK_NO, GTK_RESPONSE_NO, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL); label = gtk_label_new(_("\nSave configuration ?\n")); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); gtk_widget_show(label); result = gtk_dialog_run(GTK_DIALOG(dialog)); switch (result) { case GTK_RESPONSE_YES: on_save_activate(NULL, NULL); return FALSE; case GTK_RESPONSE_NO: return FALSE; case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: default: gtk_widget_destroy(dialog); return TRUE; } return FALSE; } void on_window1_destroy(GtkObject * object, gpointer user_data) { gtk_main_quit(); } void on_window1_size_request(GtkWidget * widget, GtkRequisition * requisition, gpointer user_data) { static gint old_h; gint w, h; if (widget->window == NULL) gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); else gdk_window_get_size(widget->window, &w, &h); if (h == old_h) return; old_h = h; gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); } /* Menu & Toolbar Callbacks */ static void load_filename(GtkFileSelection * file_selector, gpointer user_data) { const gchar *fn; fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION (user_data)); if (conf_read(fn)) text_insert_msg(_("Error"), _("Unable to load configuration !")); else display_tree(&rootmenu); } void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *fs; fs = gtk_file_selection_new(_("Load file...")); g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(load_filename), (gpointer) fs); g_signal_connect_swapped(GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer) fs); g_signal_connect_swapped(GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer) fs); gtk_widget_show(fs); } void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) { if (conf_write(NULL)) text_insert_msg(_("Error"), _("Unable to save configuration !")); } static void store_filename(GtkFileSelection * file_selector, gpointer user_data) { const gchar *fn; fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION (user_data)); if (conf_write(fn)) text_insert_msg(_("Error"), _("Unable to save configuration !")); gtk_widget_destroy(GTK_WIDGET(user_data)); } void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *fs; fs = gtk_file_selection_new(_("Save file as...")); g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(store_filename), (gpointer) fs); g_signal_connect_swapped(GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer) fs); g_signal_connect_swapped(GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer) fs); gtk_widget_show(fs); } void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) { if (!on_window1_delete_event(NULL, NULL, NULL)) gtk_widget_destroy(GTK_WIDGET(main_wnd)); } void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkTreeViewColumn *col; show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); if (col) gtk_tree_view_column_set_visible(col, show_name); } void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkTreeViewColumn *col; show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); if (col) gtk_tree_view_column_set_visible(col, show_range); col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD); if (col) gtk_tree_view_column_set_visible(col, show_range); col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES); if (col) gtk_tree_view_column_set_visible(col, show_range); } void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkTreeViewColumn *col; show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); if (col) gtk_tree_view_column_set_visible(col, show_value); } void on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) { opt_mode = OPT_NORMAL; gtk_tree_store_clear(tree2); display_tree(&rootmenu); /* instead of update_tree to speed-up */ } void on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) { opt_mode = OPT_ALL; gtk_tree_store_clear(tree2); display_tree(&rootmenu); /* instead of update_tree to speed-up */ } void on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) { opt_mode = OPT_PROMPT; gtk_tree_store_clear(tree2); display_tree(&rootmenu); /* instead of update_tree to speed-up */ } void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; const gchar *intro_text = _( "Welcome to gkc, the GTK+ graphical configuration tool\n" "For each option, a blank box indicates the feature is disabled, a\n" "check indicates it is enabled, and a dot indicates that it is to\n" "be compiled as a module. Clicking on the box will cycle through the three states.\n" "\n" "If you do not see an option (e.g., a device driver) that you\n" "believe should be present, try turning on Show All Options\n" "under the Options menu.\n" "Although there is no cross reference yet to help you figure out\n" "what other options must be enabled to support the option you\n" "are interested in, you can still view the help of a grayed-out\n" "option.\n" "\n" "Toggling Show Debug Info under the Options menu will show \n" "the dependencies, which you can then match by examining other options."); dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", intro_text); g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog)); gtk_widget_show_all(dialog); } void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; const gchar *about_text = _("gkc is copyright (c) 2002 Romain Lievin .\n" "Based on the source code from Roman Zippel.\n"); dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", about_text); g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog)); gtk_widget_show_all(dialog); } void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; const gchar *license_text = _("gkc is released under the terms of the GNU GPL v2.\n" "For more information, please see the source code or\n" "visit http://www.fsf.org/licenses/licenses.html\n"); dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", license_text); g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog)); gtk_widget_show_all(dialog); } void on_back_clicked(GtkButton * button, gpointer user_data) { enum prop_type ptype; current = current->parent; ptype = current->prompt ? current->prompt->type : P_UNKNOWN; if (ptype != P_MENU) current = current->parent; display_tree_part(); if (current == &rootmenu) gtk_widget_set_sensitive(back_btn, FALSE); } void on_load_clicked(GtkButton * button, gpointer user_data) { on_load1_activate(NULL, user_data); } void on_single_clicked(GtkButton * button, gpointer user_data) { view_mode = SINGLE_VIEW; gtk_widget_hide(tree1_w); current = &rootmenu; display_tree_part(); } void on_split_clicked(GtkButton * button, gpointer user_data) { gint w, h; view_mode = SPLIT_VIEW; gtk_widget_show(tree1_w); gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); gtk_paned_set_position(GTK_PANED(hpaned), w / 2); if (tree2) gtk_tree_store_clear(tree2); display_list(); /* Disable back btn, like in full mode. */ gtk_widget_set_sensitive(back_btn, FALSE); } void on_full_clicked(GtkButton * button, gpointer user_data) { view_mode = FULL_VIEW; gtk_widget_hide(tree1_w); if (tree2) gtk_tree_store_clear(tree2); display_tree(&rootmenu); gtk_widget_set_sensitive(back_btn, FALSE); } void on_collapse_clicked(GtkButton * button, gpointer user_data) { gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); } void on_expand_clicked(GtkButton * button, gpointer user_data) { gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); } /* CTree Callbacks */ /* Change hex/int/string value in the cell */ static void renderer_edited(GtkCellRendererText * cell, const gchar * path_string, const gchar * new_text, gpointer user_data) { GtkTreePath *path = gtk_tree_path_new_from_string(path_string); GtkTreeIter iter; const char *old_def, *new_def; struct menu *menu; struct symbol *sym; if (!gtk_tree_model_get_iter(model2, &iter, path)) return; gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); sym = menu->sym; gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); new_def = new_text; sym_set_string_value(sym, new_def); update_tree(&rootmenu, NULL); gtk_tree_path_free(path); } /* Change the value of a symbol and update the tree */ static void change_sym_value(struct menu *menu, gint col) { struct symbol *sym = menu->sym; tristate newval; if (!sym) return; if (col == COL_NO) newval = no; else if (col == COL_MOD) newval = mod; else if (col == COL_YES) newval = yes; else return; switch (sym_get_type(sym)) { case S_BOOLEAN: case S_TRISTATE: if (!sym_tristate_within_range(sym, newval)) newval = yes; sym_set_tristate_value(sym, newval); if (view_mode == FULL_VIEW) update_tree(&rootmenu, NULL); else if (view_mode == SPLIT_VIEW) { update_tree(browsed, NULL); display_list(); } else if (view_mode == SINGLE_VIEW) display_tree_part(); //fixme: keep exp/coll break; case S_INT: case S_HEX: case S_STRING: default: break; } } static void toggle_sym_value(struct menu *menu) { if (!menu->sym) return; sym_toggle_tristate_value(menu->sym); if (view_mode == FULL_VIEW) update_tree(&rootmenu, NULL); else if (view_mode == SPLIT_VIEW) { update_tree(browsed, NULL); display_list(); } else if (view_mode == SINGLE_VIEW) display_tree_part(); //fixme: keep exp/coll } static gint column2index(GtkTreeViewColumn * column) { gint i; for (i = 0; i < COL_NUMBER; i++) { GtkTreeViewColumn *col; col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i); if (col == column) return i; } return -1; } /* User click: update choice (full) or goes down (single) */ gboolean on_treeview2_button_press_event(GtkWidget * widget, GdkEventButton * event, gpointer user_data) { GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreePath *path; GtkTreeViewColumn *column; GtkTreeIter iter; struct menu *menu; gint col; #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK gint tx = (gint) event->x; gint ty = (gint) event->y; gint cx, cy; gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, &cy); #else gtk_tree_view_get_cursor(view, &path, &column); #endif if (path == NULL) return FALSE; if (!gtk_tree_model_get_iter(model2, &iter, path)) return FALSE; gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); col = column2index(column); if (event->type == GDK_2BUTTON_PRESS) { enum prop_type ptype; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { // goes down into menu current = menu; display_tree_part(); gtk_widget_set_sensitive(back_btn, TRUE); } else if ((col == COL_OPTION)) { toggle_sym_value(menu); gtk_tree_view_expand_row(view, path, TRUE); } } else { if (col == COL_VALUE) { toggle_sym_value(menu); gtk_tree_view_expand_row(view, path, TRUE); } else if (col == COL_NO || col == COL_MOD || col == COL_YES) { change_sym_value(menu, col); gtk_tree_view_expand_row(view, path, TRUE); } } return FALSE; } /* Key pressed: update choice */ gboolean on_treeview2_key_press_event(GtkWidget * widget, GdkEventKey * event, gpointer user_data) { GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreePath *path; GtkTreeViewColumn *column; GtkTreeIter iter; struct menu *menu; gint col; gtk_tree_view_get_cursor(view, &path, &column); if (path == NULL) return FALSE; if (event->keyval == GDK_space) { if (gtk_tree_view_row_expanded(view, path)) gtk_tree_view_collapse_row(view, path); else gtk_tree_view_expand_row(view, path, FALSE); return TRUE; } if (event->keyval == GDK_KP_Enter) { } if (widget == tree1_w) return FALSE; gtk_tree_model_get_iter(model2, &iter, path); gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); if (!strcasecmp(event->string, "n")) col = COL_NO; else if (!strcasecmp(event->string, "m")) col = COL_MOD; else if (!strcasecmp(event->string, "y")) col = COL_YES; else col = -1; change_sym_value(menu, col); return FALSE; } /* Row selection changed: update help */ void on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) { GtkTreeSelection *selection; GtkTreeIter iter; struct menu *menu; selection = gtk_tree_view_get_selection(treeview); if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); text_insert_help(menu); } } /* User click: display sub-tree in the right frame. */ gboolean on_treeview1_button_press_event(GtkWidget * widget, GdkEventButton * event, gpointer user_data) { GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreePath *path; GtkTreeViewColumn *column; GtkTreeIter iter; struct menu *menu; gint tx = (gint) event->x; gint ty = (gint) event->y; gint cx, cy; gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, &cy); if (path == NULL) return FALSE; gtk_tree_model_get_iter(model1, &iter, path); gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); if (event->type == GDK_2BUTTON_PRESS) { toggle_sym_value(menu); current = menu; display_tree_part(); } else { browsed = menu; display_tree_part(); } gtk_widget_realize(tree2_w); gtk_tree_view_set_cursor(view, path, NULL, FALSE); gtk_widget_grab_focus(tree2_w); return FALSE; } /* Fill a row of strings */ static gchar **fill_row(struct menu *menu) { static gchar *row[COL_NUMBER]; struct symbol *sym = menu->sym; const char *def; int stype; tristate val; enum prop_type ptype; int i; for (i = COL_OPTION; i <= COL_COLOR; i++) g_free(row[i]); bzero(row, sizeof(row)); row[COL_OPTION] = g_strdup_printf("%s %s", _(menu_get_prompt(menu)), sym && !sym_has_value(sym) ? "(NEW)" : ""); if (opt_mode == OPT_ALL && !menu_is_visible(menu)) row[COL_COLOR] = g_strdup("DarkGray"); else if (opt_mode == OPT_PROMPT && menu_has_prompt(menu) && !menu_is_visible(menu)) row[COL_COLOR] = g_strdup("DarkGray"); else row[COL_COLOR] = g_strdup("Black"); ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; switch (ptype) { case P_MENU: row[COL_PIXBUF] = (gchar *) xpm_menu; if (view_mode == SINGLE_VIEW) row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); break; case P_COMMENT: row[COL_PIXBUF] = (gchar *) xpm_void; row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); break; default: row[COL_PIXBUF] = (gchar *) xpm_void; row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); break; } if (!sym) return row; row[COL_NAME] = g_strdup(sym->name); sym_calc_value(sym); sym->flags &= ~SYMBOL_CHANGED; if (sym_is_choice(sym)) { // parse childs for getting final value struct menu *child; struct symbol *def_sym = sym_get_choice_value(sym); struct menu *def_menu = NULL; row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); for (child = menu->list; child; child = child->next) { if (menu_is_visible(child) && child->sym == def_sym) def_menu = child; } if (def_menu) row[COL_VALUE] = g_strdup(_(menu_get_prompt(def_menu))); } if (sym->flags & SYMBOL_CHOICEVAL) row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); stype = sym_get_type(sym); switch (stype) { case S_BOOLEAN: if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); if (sym_is_choice(sym)) break; /* fall through */ case S_TRISTATE: val = sym_get_tristate_value(sym); switch (val) { case no: row[COL_NO] = g_strdup("N"); row[COL_VALUE] = g_strdup("N"); row[COL_BTNACT] = GINT_TO_POINTER(FALSE); row[COL_BTNINC] = GINT_TO_POINTER(FALSE); break; case mod: row[COL_MOD] = g_strdup("M"); row[COL_VALUE] = g_strdup("M"); row[COL_BTNINC] = GINT_TO_POINTER(TRUE); break; case yes: row[COL_YES] = g_strdup("Y"); row[COL_VALUE] = g_strdup("Y"); row[COL_BTNACT] = GINT_TO_POINTER(TRUE); row[COL_BTNINC] = GINT_TO_POINTER(FALSE); break; } if (val != no && sym_tristate_within_range(sym, no)) row[COL_NO] = g_strdup("_"); if (val != mod && sym_tristate_within_range(sym, mod)) row[COL_MOD] = g_strdup("_"); if (val != yes && sym_tristate_within_range(sym, yes)) row[COL_YES] = g_strdup("_"); break; case S_INT: case S_HEX: case S_STRING: def = sym_get_string_value(sym); row[COL_VALUE] = g_strdup(def); row[COL_EDIT] = GINT_TO_POINTER(TRUE); row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); break; } return row; } /* Set the node content with a row of strings */ static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) { GdkColor color; gboolean success; GdkPixbuf *pix; pix = gdk_pixbuf_new_from_xpm_data((const char **) row[COL_PIXBUF]); gdk_color_parse(row[COL_COLOR], &color); gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, FALSE, FALSE, &success); gtk_tree_store_set(tree, node, COL_OPTION, row[COL_OPTION], COL_NAME, row[COL_NAME], COL_NO, row[COL_NO], COL_MOD, row[COL_MOD], COL_YES, row[COL_YES], COL_VALUE, row[COL_VALUE], COL_MENU, (gpointer) menu, COL_COLOR, &color, COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), COL_PIXBUF, pix, COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), -1); g_object_unref(pix); } /* Add a node to the tree */ static void place_node(struct menu *menu, char **row) { GtkTreeIter *parent = parents[indent - 1]; GtkTreeIter *node = parents[indent]; gtk_tree_store_append(tree, node, parent); set_node(node, menu, row); } /* Find a node in the GTK+ tree */ static GtkTreeIter found; /* * Find a menu in the GtkTree starting at parent. */ GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent, struct menu *tofind) { GtkTreeIter iter; GtkTreeIter *child = &iter; gboolean valid; GtkTreeIter *ret; valid = gtk_tree_model_iter_children(model2, child, parent); while (valid) { struct menu *menu; gtk_tree_model_get(model2, child, 6, &menu, -1); if (menu == tofind) { memcpy(&found, child, sizeof(GtkTreeIter)); return &found; } ret = gtktree_iter_find_node(child, tofind); if (ret) return ret; valid = gtk_tree_model_iter_next(model2, child); } return NULL; } /* * Update the tree by adding/removing entries * Does not change other nodes */ static void update_tree(struct menu *src, GtkTreeIter * dst) { struct menu *child1; GtkTreeIter iter, tmp; GtkTreeIter *child2 = &iter; gboolean valid; GtkTreeIter *sibling; struct symbol *sym; struct menu *menu1, *menu2; if (src == &rootmenu) indent = 1; valid = gtk_tree_model_iter_children(model2, child2, dst); for (child1 = src->list; child1; child1 = child1->next) { sym = child1->sym; reparse: menu1 = child1; if (valid) gtk_tree_model_get(model2, child2, COL_MENU, &menu2, -1); else menu2 = NULL; // force adding of a first child #ifdef DEBUG printf("%*c%s | %s\n", indent, ' ', menu1 ? menu_get_prompt(menu1) : "nil", menu2 ? menu_get_prompt(menu2) : "nil"); #endif if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) || (opt_mode == OPT_ALL && !menu_get_prompt(child1))) { /* remove node */ if (gtktree_iter_find_node(dst, menu1) != NULL) { memcpy(&tmp, child2, sizeof(GtkTreeIter)); valid = gtk_tree_model_iter_next(model2, child2); gtk_tree_store_remove(tree2, &tmp); if (!valid) return; /* next parent */ else goto reparse; /* next child */ } else continue; } if (menu1 != menu2) { if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node if (!valid && !menu2) sibling = NULL; else sibling = child2; gtk_tree_store_insert_before(tree2, child2, dst, sibling); set_node(child2, menu1, fill_row(menu1)); if (menu2 == NULL) valid = TRUE; } else { // remove node memcpy(&tmp, child2, sizeof(GtkTreeIter)); valid = gtk_tree_model_iter_next(model2, child2); gtk_tree_store_remove(tree2, &tmp); if (!valid) return; // next parent else goto reparse; // next child } } else if (sym && (sym->flags & SYMBOL_CHANGED)) { set_node(child2, menu1, fill_row(menu1)); } indent++; update_tree(child1, child2); indent--; valid = gtk_tree_model_iter_next(model2, child2); } } /* Display the whole tree (single/split/full view) */ static void display_tree(struct menu *menu) { struct symbol *sym; struct property *prop; struct menu *child; enum prop_type ptype; if (menu == &rootmenu) { indent = 1; current = &rootmenu; } for (child = menu->list; child; child = child->next) { prop = child->prompt; sym = child->sym; ptype = prop ? prop->type : P_UNKNOWN; if (sym) sym->flags &= ~SYMBOL_CHANGED; if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) && (tree == tree1)) continue; if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) && (tree == tree2)) continue; if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || (opt_mode == OPT_ALL && menu_get_prompt(child))) place_node(child, fill_row(child)); #ifdef DEBUG printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); printf("%s", prop_get_type_name(ptype)); printf(" | "); if (sym) { printf("%s", sym_type_name(sym->type)); printf(" | "); printf("%s", dbg_sym_flags(sym->flags)); printf("\n"); } else printf("\n"); #endif if ((view_mode != FULL_VIEW) && (ptype == P_MENU) && (tree == tree2)) continue; /* if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) || (view_mode == FULL_VIEW) || (view_mode == SPLIT_VIEW))*/ /* Change paned position if the view is not in 'split mode' */ if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) { gtk_paned_set_position(GTK_PANED(hpaned), 0); } if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) || (view_mode == FULL_VIEW) || (view_mode == SPLIT_VIEW)) { indent++; display_tree(child); indent--; } } } /* Display a part of the tree starting at current node (single/split view) */ static void display_tree_part(void) { if (tree2) gtk_tree_store_clear(tree2); if (view_mode == SINGLE_VIEW) display_tree(current); else if (view_mode == SPLIT_VIEW) display_tree(browsed); gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); } /* Display the list in the left frame (split view) */ static void display_list(void) { if (tree1) gtk_tree_store_clear(tree1); tree = tree1; display_tree(&rootmenu); gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); tree = tree2; } void fixup_rootmenu(struct menu *menu) { struct menu *child; static int menu_cnt = 0; menu->flags |= MENU_ROOT; for (child = menu->list; child; child = child->next) { if (child->prompt && child->prompt->type == P_MENU) { menu_cnt++; fixup_rootmenu(child); menu_cnt--; } else if (!menu_cnt) fixup_rootmenu(child); } } /* Main */ int main(int ac, char *av[]) { const char *name; char *env; gchar *glade_file; bindtextdomain(PACKAGE, LOCALEDIR); bind_textdomain_codeset(PACKAGE, "UTF-8"); textdomain(PACKAGE); /* GTK stuffs */ gtk_set_locale(); gtk_init(&ac, &av); glade_init(); //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); /* Determine GUI path */ env = getenv(SRCTREE); if (env) glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL); else if (av[0][0] == '/') glade_file = g_strconcat(av[0], ".glade", NULL); else glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); /* Conf stuffs */ if (ac > 1 && av[1][0] == '-') { switch (av[1][1]) { case 'a': //showAll = 1; break; case 'h': case '?': printf("%s \n", av[0]); exit(0); } name = av[2]; } else name = av[1]; conf_parse(name); fixup_rootmenu(&rootmenu); conf_read(NULL); /* Load the interface and connect signals */ init_main_window(glade_file); init_tree_model(); init_left_tree(); init_right_tree(); switch (view_mode) { case SINGLE_VIEW: display_tree_part(); break; case SPLIT_VIEW: display_list(); break; case FULL_VIEW: display_tree(&rootmenu); break; } gtk_main(); return 0; } static void conf_changed(void) { bool changed = conf_get_changed(); gtk_widget_set_sensitive(save_btn, changed); gtk_widget_set_sensitive(save_menu_item, changed); } ================================================ FILE: kconfig/gconf.glade ================================================ True Gtk Kernel Configurator GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False 640 480 True False True False False GDK_WINDOW_TYPE_HINT_NORMAL GDK_GRAVITY_NORTH_WEST True False 0 True True _File True True Load a config file _Load True True gtk-open 1 0.5 0.5 0 0 True Save the config in .config _Save True True gtk-save 1 0.5 0.5 0 0 True Save the config in a file Save _as True True gtk-save-as 1 0.5 0.5 0 0 True True _Quit True True gtk-quit 1 0.5 0.5 0 0 True _Options True True Show name Show _name True False True Show range (Y/M/N) Show _range True False True Show value of the option Show _data True False True True Show normal options Show normal options True True True Show all options Show all _options True False set_option_mode1 True Show all options with prompts Show all prompt options True False set_option_mode1 True _Help True True _Introduction True True gtk-dialog-question 1 0.5 0.5 0 0 True _About True True gtk-properties 1 0.5 0.5 0 0 True _License True True gtk-justify-fill 1 0.5 0.5 0 0 0 False False True GTK_SHADOW_OUT GTK_POS_LEFT GTK_POS_TOP True GTK_ORIENTATION_HORIZONTAL GTK_TOOLBAR_BOTH True True True Goes up of one level (single view) Back True gtk-undo True True False False True True True True False True False False True Load a config file Load True gtk-open True True False False True True Save a config file Save True gtk-save True True False False True True True True False True False False True Single view Single True gtk-missing-image True True False False True True Split view Split True gtk-missing-image True True False False True True Full view Full True gtk-missing-image True True False False True True True True False True False False True Collapse the whole tree in the right frame Collapse True gtk-remove True True False False True True Expand the whole tree in the right frame Expand True gtk-add True True False False True 0 False False 1 True True 0 True GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC GTK_SHADOW_IN GTK_CORNER_TOP_LEFT True True True False False False True False True True 0 True GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC GTK_SHADOW_IN GTK_CORNER_TOP_LEFT True True True True False False False True False True GTK_POLICY_NEVER GTK_POLICY_AUTOMATIC GTK_SHADOW_IN GTK_CORNER_TOP_LEFT True True False False True GTK_JUSTIFY_LEFT GTK_WRAP_WORD True 0 0 0 0 0 0 Sorry, no help available for this option yet. True True True True 0 True True ================================================ FILE: kconfig/images.c ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ static const char *xpm_load[] = { "22 22 5 1", ". c None", "# c #000000", "c c #838100", "a c #ffff00", "b c #ffffff", "......................", "......................", "......................", "............####....#.", "...........#....##.##.", "..................###.", ".................####.", ".####...........#####.", "#abab##########.......", "#babababababab#.......", "#ababababababa#.......", "#babababababab#.......", "#ababab###############", "#babab##cccccccccccc##", "#abab##cccccccccccc##.", "#bab##cccccccccccc##..", "#ab##cccccccccccc##...", "#b##cccccccccccc##....", "###cccccccccccc##.....", "##cccccccccccc##......", "###############.......", "......................"}; static const char *xpm_save[] = { "22 22 5 1", ". c None", "# c #000000", "a c #838100", "b c #c5c2c5", "c c #cdb6d5", "......................", ".####################.", ".#aa#bbbbbbbbbbbb#bb#.", ".#aa#bbbbbbbbbbbb#bb#.", ".#aa#bbbbbbbbbcbb####.", ".#aa#bbbccbbbbbbb#aa#.", ".#aa#bbbccbbbbbbb#aa#.", ".#aa#bbbbbbbbbbbb#aa#.", ".#aa#bbbbbbbbbbbb#aa#.", ".#aa#bbbbbbbbbbbb#aa#.", ".#aa#bbbbbbbbbbbb#aa#.", ".#aaa############aaa#.", ".#aaaaaaaaaaaaaaaaaa#.", ".#aaaaaaaaaaaaaaaaaa#.", ".#aaa#############aa#.", ".#aaa#########bbb#aa#.", ".#aaa#########bbb#aa#.", ".#aaa#########bbb#aa#.", ".#aaa#########bbb#aa#.", ".#aaa#########bbb#aa#.", "..##################..", "......................"}; static const char *xpm_back[] = { "22 22 3 1", ". c None", "# c #000083", "a c #838183", "......................", "......................", "......................", "......................", "......................", "...........######a....", "..#......##########...", "..##...####......##a..", "..###.###.........##..", "..######..........##..", "..#####...........##..", "..######..........##..", "..#######.........##..", "..########.......##a..", "...............a###...", "...............###....", "......................", "......................", "......................", "......................", "......................", "......................"}; static const char *xpm_tree_view[] = { "22 22 2 1", ". c None", "# c #000000", "......................", "......................", "......#...............", "......#...............", "......#...............", "......#...............", "......#...............", "......########........", "......#...............", "......#...............", "......#...............", "......#...............", "......#...............", "......########........", "......#...............", "......#...............", "......#...............", "......#...............", "......#...............", "......########........", "......................", "......................"}; static const char *xpm_single_view[] = { "22 22 2 1", ". c None", "# c #000000", "......................", "......................", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "..........#...........", "......................", "......................"}; static const char *xpm_split_view[] = { "22 22 2 1", ". c None", "# c #000000", "......................", "......................", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......#......#........", "......................", "......................"}; static const char *xpm_symbol_no[] = { "12 12 2 1", " c white", ". c black", " ", " .......... ", " . . ", " . . ", " . . ", " . . ", " . . ", " . . ", " . . ", " . . ", " .......... ", " "}; static const char *xpm_symbol_mod[] = { "12 12 2 1", " c white", ". c black", " ", " .......... ", " . . ", " . . ", " . .. . ", " . .... . ", " . .... . ", " . .. . ", " . . ", " . . ", " .......... ", " "}; static const char *xpm_symbol_yes[] = { "12 12 2 1", " c white", ". c black", " ", " .......... ", " . . ", " . . ", " . . . ", " . .. . ", " . . .. . ", " . .... . ", " . .. . ", " . . ", " .......... ", " "}; static const char *xpm_choice_no[] = { "12 12 2 1", " c white", ". c black", " ", " .... ", " .. .. ", " . . ", " . . ", " . . ", " . . ", " . . ", " . . ", " .. .. ", " .... ", " "}; static const char *xpm_choice_yes[] = { "12 12 2 1", " c white", ". c black", " ", " .... ", " .. .. ", " . . ", " . .. . ", " . .... . ", " . .... . ", " . .. . ", " . . ", " .. .. ", " .... ", " "}; static const char *xpm_menu[] = { "12 12 2 1", " c white", ". c black", " ", " .......... ", " . . ", " . .. . ", " . .... . ", " . ...... . ", " . ...... . ", " . .... . ", " . .. . ", " . . ", " .......... ", " "}; static const char *xpm_menu_inv[] = { "12 12 2 1", " c white", ". c black", " ", " .......... ", " .......... ", " .. ...... ", " .. .... ", " .. .. ", " .. .. ", " .. .... ", " .. ...... ", " .......... ", " .......... ", " "}; static const char *xpm_menuback[] = { "12 12 2 1", " c white", ". c black", " ", " .......... ", " . . ", " . .. . ", " . .... . ", " . ...... . ", " . ...... . ", " . .... . ", " . .. . ", " . . ", " .......... ", " "}; static const char *xpm_void[] = { "12 12 2 1", " c white", ". c black", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; ================================================ FILE: kconfig/kxgettext.c ================================================ /* * Arnaldo Carvalho de Melo , 2005 * * Released under the terms of the GNU GPL v2.0 */ #include #include #include "lkc.h" static char *escape(const char* text, char *bf, int len) { char *bfp = bf; int multiline = strchr(text, '\n') != NULL; int eol = 0; int textlen = strlen(text); if ((textlen > 0) && (text[textlen-1] == '\n')) eol = 1; *bfp++ = '"'; --len; if (multiline) { *bfp++ = '"'; *bfp++ = '\n'; *bfp++ = '"'; len -= 3; } while (*text != '\0' && len > 1) { if (*text == '"') *bfp++ = '\\'; else if (*text == '\n') { *bfp++ = '\\'; *bfp++ = 'n'; *bfp++ = '"'; *bfp++ = '\n'; *bfp++ = '"'; len -= 5; ++text; goto next; } else if (*text == '\\') { *bfp++ = '\\'; len--; } *bfp++ = *text++; next: --len; } if (multiline && eol) bfp -= 3; *bfp++ = '"'; *bfp = '\0'; return bf; } struct file_line { struct file_line *next; const char *file; int lineno; }; static struct file_line *file_line__new(const char *file, int lineno) { struct file_line *self = malloc(sizeof(*self)); if (self == NULL) goto out; self->file = file; self->lineno = lineno; self->next = NULL; out: return self; } struct message { const char *msg; const char *option; struct message *next; struct file_line *files; }; static struct message *message__list; static struct message *message__new(const char *msg, char *option, const char *file, int lineno) { struct message *self = malloc(sizeof(*self)); if (self == NULL) goto out; self->files = file_line__new(file, lineno); if (self->files == NULL) goto out_fail; self->msg = strdup(msg); if (self->msg == NULL) goto out_fail_msg; self->option = option; self->next = NULL; out: return self; out_fail_msg: free(self->files); out_fail: free(self); self = NULL; goto out; } static struct message *mesage__find(const char *msg) { struct message *m = message__list; while (m != NULL) { if (strcmp(m->msg, msg) == 0) break; m = m->next; } return m; } static int message__add_file_line(struct message *self, const char *file, int lineno) { int rc = -1; struct file_line *fl = file_line__new(file, lineno); if (fl == NULL) goto out; fl->next = self->files; self->files = fl; rc = 0; out: return rc; } static int message__add(const char *msg, char *option, const char *file, int lineno) { int rc = 0; char bf[16384]; char *escaped = escape(msg, bf, sizeof(bf)); struct message *m = mesage__find(escaped); if (m != NULL) rc = message__add_file_line(m, file, lineno); else { m = message__new(escaped, option, file, lineno); if (m != NULL) { m->next = message__list; message__list = m; } else rc = -1; } return rc; } static void menu_build_message_list(struct menu *menu) { struct menu *child; message__add(menu_get_prompt(menu), NULL, menu->file == NULL ? "Root Menu" : menu->file->name, menu->lineno); if (menu->sym != NULL && menu_has_help(menu)) message__add(menu_get_help(menu), menu->sym->name, menu->file == NULL ? "Root Menu" : menu->file->name, menu->lineno); for (child = menu->list; child != NULL; child = child->next) if (child->prompt != NULL) menu_build_message_list(child); } static void message__print_file_lineno(struct message *self) { struct file_line *fl = self->files; putchar('\n'); if (self->option != NULL) printf("# %s:00000\n", self->option); printf("#: %s:%d", fl->file, fl->lineno); fl = fl->next; while (fl != NULL) { printf(", %s:%d", fl->file, fl->lineno); fl = fl->next; } putchar('\n'); } static void message__print_gettext_msgid_msgstr(struct message *self) { message__print_file_lineno(self); printf("msgid %s\n" "msgstr \"\"\n", self->msg); } static void menu__xgettext(void) { struct message *m = message__list; while (m != NULL) { /* skip empty lines ("") */ if (strlen(m->msg) > sizeof("\"\"")) message__print_gettext_msgid_msgstr(m); m = m->next; } } int main(int ac, char **av) { conf_parse(av[1]); menu_build_message_list(menu_get_root_menu(NULL)); menu__xgettext(); return 0; } ================================================ FILE: kconfig/list.h ================================================ #ifndef LIST_H #define LIST_H /* * Copied from include/linux/... */ #undef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *_new, struct list_head *prev, struct list_head *next) { next->prev = _new; _new->next = next; _new->prev = prev; prev->next = _new; } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *_new, struct list_head *head) { __list_add(_new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } #define LIST_POISON1 ((void *) 0x00100100) #define LIST_POISON2 ((void *) 0x00200200) /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = (struct list_head*)LIST_POISON1; entry->prev = (struct list_head*)LIST_POISON2; } #endif ================================================ FILE: kconfig/lkc.h ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #ifndef LKC_H #define LKC_H #include "expr.h" #ifndef KBUILD_NO_NLS # include #else static inline const char *gettext(const char *txt) { return txt; } static inline void textdomain(const char *domainname) {} static inline void bindtextdomain(const char *name, const char *dir) {} static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } #endif #ifdef __cplusplus extern "C" { #endif #define P(name,type,arg) extern type name arg #include "lkc_proto.h" #undef P #define SRCTREE "srctree" #ifndef PACKAGE #define PACKAGE "linux" #endif #define LOCALEDIR "/usr/share/locale" #define _(text) gettext(text) #define N_(text) (text) #ifndef CONFIG_ #define CONFIG_ "CONFIG_" #endif static inline const char *CONFIG_prefix(void) { return getenv( "CONFIG_" ) ?: CONFIG_; } #undef CONFIG_ #define CONFIG_ CONFIG_prefix() #define TF_COMMAND 0x0001 #define TF_PARAM 0x0002 #define TF_OPTION 0x0004 enum conf_def_mode { def_default, def_yes, def_mod, def_no, def_random }; #define T_OPT_MODULES 1 #define T_OPT_DEFCONFIG_LIST 2 #define T_OPT_ENV 3 #define T_OPT_ALLNOCONFIG_Y 4 struct kconf_id { int name; int token; unsigned int flags; enum symbol_type stype; }; extern int zconfdebug; int zconfparse(void); void zconfdump(FILE *out); void zconf_starthelp(void); FILE *zconf_fopen(const char *name); void zconf_initscan(const char *name); void zconf_nextfile(const char *name); int zconf_lineno(void); const char *zconf_curname(void); /* confdata.c */ const char *conf_get_configname(void); const char *conf_get_autoconfig_name(void); char *conf_get_default_confname(void); void sym_set_change_count(int count); void sym_add_change_count(int count); bool conf_set_all_new_symbols(enum conf_def_mode mode); void set_all_choice_values(struct symbol *csym); struct conf_printer { void (*print_symbol)(FILE *, struct symbol *, const char *, void *); void (*print_comment)(FILE *, const char *, void *); }; /* confdata.c and expr.c */ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) { assert(len != 0); if (fwrite(str, len, count, out) != count) fprintf(stderr, "Error in writing or end of file.\n"); } /* menu.c */ void _menu_init(void); void menu_warn(struct menu *menu, const char *fmt, ...); struct menu *menu_add_menu(void); void menu_end_menu(void); void menu_add_entry(struct symbol *sym); void menu_end_entry(void); void menu_add_dep(struct expr *dep); void menu_add_visibility(struct expr *dep); struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); void menu_add_option(int token, char *arg); void menu_finalize(struct menu *parent); void menu_set_type(int type); /* util.c */ struct file *file_lookup(const char *name); int file_write_dep(const char *name); void *xmalloc(size_t size); void *xcalloc(size_t nmemb, size_t size); struct gstr { size_t len; char *s; /* * when max_width is not zero long lines in string s (if any) get * wrapped not to exceed the max_width value */ int max_width; }; struct gstr str_new(void); struct gstr str_assign(const char *s); void str_free(struct gstr *gs); void str_append(struct gstr *gs, const char *s); void str_printf(struct gstr *gs, const char *fmt, ...); const char *str_get(struct gstr *gs); /* symbol.c */ extern struct expr *sym_env_list; void sym_init(void); void sym_clear_all_valid(void); void sym_set_all_changed(void); void sym_set_changed(struct symbol *sym); struct symbol *sym_choice_default(struct symbol *sym); const char *sym_get_string_default(struct symbol *sym); struct symbol *sym_check_deps(struct symbol *sym); struct property *prop_alloc(enum prop_type type, struct symbol *sym); struct symbol *prop_get_symbol(struct property *prop); struct property *sym_get_env_prop(struct symbol *sym); static inline tristate sym_get_tristate_value(struct symbol *sym) { return sym->curr.tri; } static inline struct symbol *sym_get_choice_value(struct symbol *sym) { return (struct symbol *)sym->curr.val; } static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) { return sym_set_tristate_value(chval, yes); } static inline bool sym_is_choice(struct symbol *sym) { return sym->flags & SYMBOL_CHOICE ? true : false; } static inline bool sym_is_choice_value(struct symbol *sym) { return sym->flags & SYMBOL_CHOICEVAL ? true : false; } static inline bool sym_is_optional(struct symbol *sym) { return sym->flags & SYMBOL_OPTIONAL ? true : false; } static inline bool sym_has_value(struct symbol *sym) { return sym->flags & SYMBOL_DEF_USER ? true : false; } #ifdef __cplusplus } #endif #endif /* LKC_H */ ================================================ FILE: kconfig/lkc_proto.h ================================================ #include /* confdata.c */ P(conf_parse,void,(const char *name)); P(conf_read,int,(const char *name)); P(conf_read_simple,int,(const char *name, int)); P(conf_write_defconfig,int,(const char *name)); P(conf_write,int,(const char *name)); P(conf_write_autoconf,int,(void)); P(conf_get_changed,bool,(void)); P(conf_set_changed_callback, void,(void (*fn)(void))); P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap))); /* menu.c */ P(rootmenu,struct menu,); P(menu_is_empty, bool, (struct menu *menu)); P(menu_is_visible, bool, (struct menu *menu)); P(menu_has_prompt, bool, (struct menu *menu)); P(menu_get_prompt,const char *,(struct menu *menu)); P(menu_get_root_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu)); P(menu_has_help,bool,(struct menu *menu)); P(menu_get_help,const char *,(struct menu *menu)); P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head *head)); P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head *head)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); /* symbol.c */ P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); P(sym_lookup,struct symbol *,(const char *name, int flags)); P(sym_find,struct symbol *,(const char *name)); P(sym_expand_string_value,const char *,(const char *in)); P(sym_escape_string_value, const char *,(const char *in)); P(sym_re_search,struct symbol **,(const char *pattern)); P(sym_type_name,const char *,(enum symbol_type type)); P(sym_calc_value,void,(struct symbol *sym)); P(sym_get_type,enum symbol_type,(struct symbol *sym)); P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); P(sym_is_changable,bool,(struct symbol *sym)); P(sym_get_choice_prop,struct property *,(struct symbol *sym)); P(sym_get_default_prop,struct property *,(struct symbol *sym)); P(sym_get_string_value,const char *,(struct symbol *sym)); P(prop_get_type_name,const char *,(enum prop_type type)); /* expr.c */ P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)); ================================================ FILE: kconfig/lpc17xx.cfg ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Platform Selection # # ARCH_LM3S is not set ARCH_LPC17XX=y # ARCH_STM32F4 is not set # ARCH_LPC1763 is not set # ARCH_LPC1764 is not set # ARCH_LPC1765 is not set # ARCH_LPC1766 is not set # ARCH_LPC1767 is not set ARCH_LPC1768=y # ARCH_LPC1769 is not set FLASH_SIZE_512KB=y RAM_SIZE_32KB=y CLK_100MHZ=y MACH_LPC1768MBED=y # MACH_SEEEDPRO is not set # # Kernel Configuration # KFLASHMEM_SIZE=48 KRAMMEM_SIZE=6 # # Subsystems # # # Filesystems # SYSFS=y MEMFS=y XIPFS=y # # Sockets # SOCK_UNIX=y # # Devices # DEVNULL=y # DEVUART is not set DEVGPIO=y # # Applications # FRESH=y # TASK2 is not set # PRODCONS is not set ================================================ FILE: kconfig/mconf.c ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. * * Introduced single menu mode (show all sub-menus in one large tree). * 2002-11-06 Petr Baudis * * i18n, 2005, Arnaldo Carvalho de Melo */ #include #include #include #include #include #include #include #include #include #include #include "lkc.h" #include "lxdialog/dialog.h" static const char mconf_readme[] = N_( "Overview\n" "--------\n" "This interface lets you select features and parameters for the build.\n" "Features can either be built-in, modularized, or ignored. Parameters\n" "must be entered in as decimal or hexadecimal numbers or text.\n" "\n" "Menu items beginning with following braces represent features that\n" " [ ] can be built in or removed\n" " < > can be built in, modularized or removed\n" " { } can be built in or modularized (selected by other feature)\n" " - - are selected by other feature,\n" "while *, M or whitespace inside braces means to build in, build as\n" "a module or to exclude the feature respectively.\n" "\n" "To change any of these features, highlight it with the cursor\n" "keys and press to build it in, to make it a module or\n" " to remove it. You may also press the to cycle\n" "through the available options (i.e. Y->N->M->Y).\n" "\n" "Some additional keyboard hints:\n" "\n" "Menus\n" "----------\n" "o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n" " wish to change or the submenu you wish to select and press .\n" " Submenus are designated by \"--->\", empty ones by \"----\".\n" "\n" " Shortcut: Press the option's highlighted letter (hotkey).\n" " Pressing a hotkey more than once will sequence\n" " through all visible items which use that hotkey.\n" "\n" " You may also use the and keys to scroll\n" " unseen options into view.\n" "\n" "o To exit a menu use the cursor keys to highlight the button\n" " and press .\n" "\n" " Shortcut: Press or or if there is no hotkey\n" " using those letters. You may press a single , but\n" " there is a delayed response which you may find annoying.\n" "\n" " Also, the and cursor keys will cycle between and\n" " \n" "\n" "\n" "Data Entry\n" "-----------\n" "o Enter the requested information and press \n" " If you are entering hexadecimal values, it is not necessary to\n" " add the '0x' prefix to the entry.\n" "\n" "o For help, use the or cursor keys to highlight the help option\n" " and press . You can try as well.\n" "\n" "\n" "Text Box (Help Window)\n" "--------\n" "o Use the cursor keys to scroll up/down/left/right. The VI editor\n" " keys h,j,k,l function here as do , , and for\n" " those who are familiar with less and lynx.\n" "\n" "o Press , , , or to exit.\n" "\n" "\n" "Alternate Configuration Files\n" "-----------------------------\n" "Menuconfig supports the use of alternate configuration files for\n" "those who, for various reasons, find it necessary to switch\n" "between different configurations.\n" "\n" "The button will let you save the current configuration to\n" "a file of your choosing. Use the button to load a previously\n" "saved alternate configuration.\n" "\n" "Even if you don't use alternate configuration files, but you find\n" "during a Menuconfig session that you have completely messed up your\n" "settings, you may use the button to restore your previously\n" "saved settings from \".config\" without restarting Menuconfig.\n" "\n" "Other information\n" "-----------------\n" "If you use Menuconfig in an XTERM window, make sure you have your\n" "$TERM variable set to point to an xterm definition which supports\n" "color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n" "not display correctly in an RXVT window because rxvt displays only one\n" "intensity of color, bright.\n" "\n" "Menuconfig will display larger menus on screens or xterms which are\n" "set to display more than the standard 25 row by 80 column geometry.\n" "In order for this to work, the \"stty size\" command must be able to\n" "display the screen's current row and column geometry. I STRONGLY\n" "RECOMMEND that you make sure you do NOT have the shell variables\n" "LINES and COLUMNS exported into your environment. Some distributions\n" "export those variables via /etc/profile. Some ncurses programs can\n" "become confused when those variables (LINES & COLUMNS) don't reflect\n" "the true screen size.\n" "\n" "Optional personality available\n" "------------------------------\n" "If you prefer to have all of the options listed in a single menu,\n" "rather than the default multimenu hierarchy, run the menuconfig with\n" "MENUCONFIG_MODE environment variable set to single_menu. Example:\n" "\n" "make MENUCONFIG_MODE=single_menu menuconfig\n" "\n" " will then unroll the appropriate category, or enfold it if it\n" "is already unrolled.\n" "\n" "Note that this mode can eventually be a little more CPU expensive\n" "(especially with a larger number of unrolled categories) than the\n" "default mode.\n" "\n" "Different color themes available\n" "--------------------------------\n" "It is possible to select different color themes using the variable\n" "MENUCONFIG_COLOR. To select a theme use:\n" "\n" "make MENUCONFIG_COLOR= menuconfig\n" "\n" "Available themes are\n" " mono => selects colors suitable for monochrome displays\n" " blackbg => selects a color scheme with black background\n" " classic => theme with blue background. The classic look\n" " bluetitle => an LCD friendly version of classic. (default)\n" "\n"), menu_instructions[] = N_( "Arrow keys navigate the menu. " " selects submenus ---> (or empty submenus ----). " "Highlighted letters are hotkeys. " "Pressing includes, excludes, modularizes features. " "Press to exit, for Help, for Search. " "Legend: [*] built-in [ ] excluded module < > module capable"), radiolist_instructions[] = N_( "Use the arrow keys to navigate this window or " "press the hotkey of the item you wish to select " "followed by the . " "Press for additional information about this option."), inputbox_instructions_int[] = N_( "Please enter a decimal value. " "Fractions will not be accepted. " "Use the key to move from the input field to the buttons below it."), inputbox_instructions_hex[] = N_( "Please enter a hexadecimal value. " "Use the key to move from the input field to the buttons below it."), inputbox_instructions_string[] = N_( "Please enter a string value. " "Use the key to move from the input field to the buttons below it."), setmod_text[] = N_( "This feature depends on another which has been configured as a module.\n" "As a result, this feature will be built as a module."), load_config_text[] = N_( "Enter the name of the configuration file you wish to load. " "Accept the name shown to restore the configuration you " "last retrieved. Leave blank to abort."), load_config_help[] = N_( "\n" "For various reasons, one may wish to keep several different\n" "configurations available on a single machine.\n" "\n" "If you have saved a previous configuration in a file other than the\n" "default one, entering its name here will allow you to modify that\n" "configuration.\n" "\n" "If you are uncertain, then you have probably never used alternate\n" "configuration files. You should therefore leave this blank to abort.\n"), save_config_text[] = N_( "Enter a filename to which this configuration should be saved " "as an alternate. Leave blank to abort."), save_config_help[] = N_( "\n" "For various reasons, one may wish to keep different configurations\n" "available on a single machine.\n" "\n" "Entering a file name here will allow you to later retrieve, modify\n" "and use the current configuration as an alternate to whatever\n" "configuration options you have selected at that time.\n" "\n" "If you are uncertain what all this means then you should probably\n" "leave this blank.\n"), search_help[] = N_( "\n" "Search for symbols and display their relations.\n" "Regular expressions are allowed.\n" "Example: search for \"^FOO\"\n" "Result:\n" "-----------------------------------------------------------------\n" "Symbol: FOO [=m]\n" "Type : tristate\n" "Prompt: Foo bus is used to drive the bar HW\n" " Location:\n" " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [=y])\n" "(1) -> PCI access mode ( [=y])\n" " Defined at drivers/pci/Kconfig:47\n" " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" " Selects: LIBCRC32\n" " Selected by: BAR [=n]\n" "-----------------------------------------------------------------\n" "o The line 'Type:' shows the type of the configuration option for\n" " this symbol (boolean, tristate, string, ...)\n" "o The line 'Prompt:' shows the text used in the menu structure for\n" " this symbol\n" "o The 'Defined at' line tells at what file / line number the symbol\n" " is defined\n" "o The 'Depends on:' line tells what symbols need to be defined for\n" " this symbol to be visible in the menu (selectable)\n" "o The 'Location:' lines tells where in the menu structure this symbol\n" " is located\n" " A location followed by a [=y] indicates that this is a\n" " selectable menu item - and the current value is displayed inside\n" " brackets.\n" " Press the key in the (#) prefix to jump directly to that\n" " location. You will be returned to the current search results\n" " after exiting this new menu.\n" "o The 'Selects:' line tells what symbols will be automatically\n" " selected if this symbol is selected (y or m)\n" "o The 'Selected by' line tells what symbol has selected this symbol\n" "\n" "Only relevant lines are shown.\n" "\n\n" "Search examples:\n" "Examples: USB => find all symbols containing USB\n" " ^USB => find all symbols starting with USB\n" " USB$ => find all symbols ending with USB\n" "\n"); static int indent; static struct menu *current_menu; static int child_count; static int single_menu_mode; static int show_all_options; static int save_and_exit; static void conf(struct menu *menu, struct menu *active_menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); static void conf_load(void); static void conf_save(void); static int show_textbox_ext(const char *title, char *text, int r, int c, int *keys, int *vscroll, int *hscroll, update_text_fn update_text, void *data); static void show_textbox(const char *title, const char *text, int r, int c); static void show_helptext(const char *title, const char *text); static void show_help(struct menu *menu); static char filename[PATH_MAX+1]; static void set_config_filename(const char *config_filename) { static char menu_backtitle[PATH_MAX+128]; int size; size = snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s", config_filename, rootmenu.prompt->text); if (size >= sizeof(menu_backtitle)) menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; set_dialog_backtitle(menu_backtitle); size = snprintf(filename, sizeof(filename), "%s", config_filename); if (size >= sizeof(filename)) filename[sizeof(filename)-1] = '\0'; } struct subtitle_part { struct list_head entries; const char *text; }; static LIST_HEAD(trail); static struct subtitle_list *subtitles; static void set_subtitle(void) { struct subtitle_part *sp; struct subtitle_list *pos, *tmp; for (pos = subtitles; pos != NULL; pos = tmp) { tmp = pos->next; free(pos); } subtitles = NULL; list_for_each_entry(sp, &trail, entries) { if (sp->text) { if (pos) { pos->next = xcalloc(sizeof(*pos), 1); pos = pos->next; } else { subtitles = pos = xcalloc(sizeof(*pos), 1); } pos->text = sp->text; } } set_dialog_subtitles(subtitles); } static void reset_subtitle(void) { struct subtitle_list *pos, *tmp; for (pos = subtitles; pos != NULL; pos = tmp) { tmp = pos->next; free(pos); } subtitles = NULL; set_dialog_subtitles(subtitles); } struct search_data { struct list_head *head; struct menu **targets; int *keys; }; static void update_text(char *buf, size_t start, size_t end, void *_data) { struct search_data *data = _data; struct jump_key *pos; int k = 0; list_for_each_entry(pos, data->head, entries) { if (pos->offset >= start && pos->offset < end) { char header[4]; if (k < JUMP_NB) { int key = '0' + (pos->index % JUMP_NB) + 1; sprintf(header, "(%c)", key); data->keys[k] = key; data->targets[k] = pos->target; k++; } else { sprintf(header, " "); } memcpy(buf + pos->offset, header, sizeof(header) - 1); } } data->keys[k] = 0; } static void search_conf(void) { struct symbol **sym_arr; struct gstr res; struct gstr title; char *dialog_input; int dres, vscroll = 0, hscroll = 0; bool again; struct gstr sttext; struct subtitle_part stpart; title = str_new(); str_printf( &title, _("Enter (sub)string or regexp to search for " "(with or without \"%s\")"), CONFIG_); again: dialog_clear(); dres = dialog_inputbox(_("Search Configuration Parameter"), str_get(&title), 10, 75, ""); switch (dres) { case 0: break; case 1: show_helptext(_("Search Configuration"), search_help); goto again; default: str_free(&title); return; } /* strip the prefix if necessary */ dialog_input = dialog_input_result; if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) dialog_input += strlen(CONFIG_); sttext = str_new(); str_printf(&sttext, "Search (%s)", dialog_input_result); stpart.text = str_get(&sttext); list_add_tail(&stpart.entries, &trail); sym_arr = sym_re_search(dialog_input); do { LIST_HEAD(head); struct menu *targets[JUMP_NB]; int keys[JUMP_NB + 1], i; struct search_data data = { .head = &head, .targets = targets, .keys = keys, }; struct jump_key *pos, *tmp; res = get_relations_str(sym_arr, &head); set_subtitle(); dres = show_textbox_ext(_("Search Results"), (char *) str_get(&res), 0, 0, keys, &vscroll, &hscroll, &update_text, (void *) &data); again = false; for (i = 0; i < JUMP_NB && keys[i]; i++) if (dres == keys[i]) { conf(targets[i]->parent, targets[i]); again = true; } str_free(&res); list_for_each_entry_safe(pos, tmp, &head, entries) free(pos); } while (again); free(sym_arr); str_free(&title); list_del(trail.prev); str_free(&sttext); } static void build_conf(struct menu *menu) { struct symbol *sym; struct property *prop; struct menu *child; int type, tmp, doint = 2; tristate val; char ch; bool visible; /* * note: menu_is_visible() has side effect that it will * recalc the value of the symbol. */ visible = menu_is_visible(menu); if (show_all_options && !menu_has_prompt(menu)) return; else if (!show_all_options && !visible) return; sym = menu->sym; prop = menu->prompt; if (!sym) { if (prop && menu != current_menu) { const char *prompt = menu_get_prompt(menu); switch (prop->type) { case P_MENU: child_count++; prompt = _(prompt); if (single_menu_mode) { item_make("%s%*c%s", menu->data ? "-->" : "++>", indent + 1, ' ', prompt); } else item_make(" %*c%s %s", indent + 1, ' ', prompt, menu_is_empty(menu) ? "----" : "--->"); item_set_tag('m'); item_set_data(menu); if (single_menu_mode && menu->data) goto conf_childs; return; case P_COMMENT: if (prompt) { child_count++; item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt)); item_set_tag(':'); item_set_data(menu); } break; default: if (prompt) { child_count++; item_make("---%*c%s", indent + 1, ' ', _(prompt)); item_set_tag(':'); item_set_data(menu); } } } else doint = 0; goto conf_childs; } type = sym_get_type(sym); if (sym_is_choice(sym)) { struct symbol *def_sym = sym_get_choice_value(sym); struct menu *def_menu = NULL; child_count++; for (child = menu->list; child; child = child->next) { if (menu_is_visible(child) && child->sym == def_sym) def_menu = child; } val = sym_get_tristate_value(sym); if (sym_is_changable(sym)) { switch (type) { case S_BOOLEAN: item_make("[%c]", val == no ? ' ' : '*'); break; case S_TRISTATE: switch (val) { case yes: ch = '*'; break; case mod: ch = 'M'; break; default: ch = ' '; break; } item_make("<%c>", ch); break; } item_set_tag('t'); item_set_data(menu); } else { item_make(" "); item_set_tag(def_menu ? 't' : ':'); item_set_data(menu); } item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); if (val == yes) { if (def_menu) { item_add_str(" (%s)", _(menu_get_prompt(def_menu))); item_add_str(" --->"); if (def_menu->list) { indent += 2; build_conf(def_menu); indent -= 2; } } return; } } else { if (menu == current_menu) { item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); item_set_tag(':'); item_set_data(menu); goto conf_childs; } child_count++; val = sym_get_tristate_value(sym); if (sym_is_choice_value(sym) && val == yes) { item_make(" "); item_set_tag(':'); item_set_data(menu); } else { switch (type) { case S_BOOLEAN: if (sym_is_changable(sym)) item_make("[%c]", val == no ? ' ' : '*'); else item_make("-%c-", val == no ? ' ' : '*'); item_set_tag('t'); item_set_data(menu); break; case S_TRISTATE: switch (val) { case yes: ch = '*'; break; case mod: ch = 'M'; break; default: ch = ' '; break; } if (sym_is_changable(sym)) { if (sym->rev_dep.tri == mod) item_make("{%c}", ch); else item_make("<%c>", ch); } else item_make("-%c-", ch); item_set_tag('t'); item_set_data(menu); break; default: tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ item_make("(%s)", sym_get_string_value(sym)); tmp = indent - tmp + 4; if (tmp < 0) tmp = 0; item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), (sym_has_value(sym) || !sym_is_changable(sym)) ? "" : _(" (NEW)")); item_set_tag('s'); item_set_data(menu); goto conf_childs; } } item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), (sym_has_value(sym) || !sym_is_changable(sym)) ? "" : _(" (NEW)")); if (menu->prompt->type == P_MENU) { item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); return; } } conf_childs: indent += doint; for (child = menu->list; child; child = child->next) build_conf(child); indent -= doint; } static void conf(struct menu *menu, struct menu *active_menu) { struct menu *submenu; const char *prompt = menu_get_prompt(menu); struct subtitle_part stpart; struct symbol *sym; int res; int s_scroll = 0; if (menu != &rootmenu) stpart.text = menu_get_prompt(menu); else stpart.text = NULL; list_add_tail(&stpart.entries, &trail); while (1) { item_reset(); current_menu = menu; build_conf(menu); if (!child_count) break; set_subtitle(); dialog_clear(); res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), _(menu_instructions), active_menu, &s_scroll); if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) break; if (item_count() != 0) { if (!item_activate_selected()) continue; if (!item_tag()) continue; } submenu = item_data(); active_menu = item_data(); if (submenu) sym = submenu->sym; else sym = NULL; switch (res) { case 0: switch (item_tag()) { case 'm': if (single_menu_mode) submenu->data = (void *) (long) !submenu->data; else conf(submenu, NULL); break; case 't': if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) conf_choice(submenu); else if (submenu->prompt->type == P_MENU) conf(submenu, NULL); break; case 's': conf_string(submenu); break; } break; case 2: if (sym) show_help(submenu); else { reset_subtitle(); show_helptext(_("README"), _(mconf_readme)); } break; case 3: reset_subtitle(); conf_save(); break; case 4: reset_subtitle(); conf_load(); break; case 5: if (item_is_tag('t')) { if (sym_set_tristate_value(sym, yes)) break; if (sym_set_tristate_value(sym, mod)) show_textbox(NULL, setmod_text, 6, 74); } break; case 6: if (item_is_tag('t')) sym_set_tristate_value(sym, no); break; case 7: if (item_is_tag('t')) sym_set_tristate_value(sym, mod); break; case 8: if (item_is_tag('t')) sym_toggle_tristate_value(sym); else if (item_is_tag('m')) conf(submenu, NULL); break; case 9: search_conf(); break; case 10: show_all_options = !show_all_options; break; } } list_del(trail.prev); } static int show_textbox_ext(const char *title, char *text, int r, int c, int *keys, int *vscroll, int *hscroll, update_text_fn update_text, void *data) { dialog_clear(); return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, update_text, data); } static void show_textbox(const char *title, const char *text, int r, int c) { show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, NULL, NULL); } static void show_helptext(const char *title, const char *text) { show_textbox(title, text, 0, 0); } static void conf_message_callback(const char *fmt, va_list ap) { char buf[PATH_MAX+1]; vsnprintf(buf, sizeof(buf), fmt, ap); if (save_and_exit) printf("%s", buf); else show_textbox(NULL, buf, 6, 60); } static void show_help(struct menu *menu) { struct gstr help = str_new(); help.max_width = getmaxx(stdscr) - 10; menu_get_ext_help(menu, &help); show_helptext(_(menu_get_prompt(menu)), str_get(&help)); str_free(&help); } static void conf_choice(struct menu *menu) { const char *prompt = _(menu_get_prompt(menu)); struct menu *child; struct symbol *active; active = sym_get_choice_value(menu->sym); while (1) { int res; int selected; item_reset(); current_menu = menu; for (child = menu->list; child; child = child->next) { if (!menu_is_visible(child)) continue; if (child->sym) item_make("%s", _(menu_get_prompt(child))); else { item_make("*** %s ***", _(menu_get_prompt(child))); item_set_tag(':'); } item_set_data(child); if (child->sym == active) item_set_selected(1); if (child->sym == sym_get_choice_value(menu->sym)) item_set_tag('X'); } dialog_clear(); res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), _(radiolist_instructions), MENUBOX_HEIGTH_MIN, MENUBOX_WIDTH_MIN, CHECKLIST_HEIGTH_MIN); selected = item_activate_selected(); switch (res) { case 0: if (selected) { child = item_data(); if (!child->sym) break; sym_set_tristate_value(child->sym, yes); } return; case 1: if (selected) { child = item_data(); show_help(child); active = child->sym; } else show_help(menu); break; case KEY_ESC: return; case -ERRDISPLAYTOOSMALL: return; } } } static void conf_string(struct menu *menu) { const char *prompt = menu_get_prompt(menu); while (1) { int res; const char *heading; switch (sym_get_type(menu->sym)) { case S_INT: heading = _(inputbox_instructions_int); break; case S_HEX: heading = _(inputbox_instructions_hex); break; case S_STRING: heading = _(inputbox_instructions_string); break; default: heading = _("Internal mconf error!"); } dialog_clear(); res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"), heading, 10, 75, sym_get_string_value(menu->sym)); switch (res) { case 0: if (sym_set_string_value(menu->sym, dialog_input_result)) return; show_textbox(NULL, _("You have made an invalid entry."), 5, 43); break; case 1: show_help(menu); break; case KEY_ESC: return; } } } static void conf_load(void) { while (1) { int res; dialog_clear(); res = dialog_inputbox(NULL, load_config_text, 11, 55, filename); switch(res) { case 0: if (!dialog_input_result[0]) return; if (!conf_read(dialog_input_result)) { set_config_filename(dialog_input_result); sym_set_change_count(1); return; } show_textbox(NULL, _("File does not exist!"), 5, 38); break; case 1: show_helptext(_("Load Alternate Configuration"), load_config_help); break; case KEY_ESC: return; } } } static void conf_save(void) { while (1) { int res; dialog_clear(); res = dialog_inputbox(NULL, save_config_text, 11, 55, filename); switch(res) { case 0: if (!dialog_input_result[0]) return; if (!conf_write(dialog_input_result)) { set_config_filename(dialog_input_result); return; } show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); break; case 1: show_helptext(_("Save Alternate Configuration"), save_config_help); break; case KEY_ESC: return; } } } static int handle_exit(void) { int res; save_and_exit = 1; reset_subtitle(); dialog_clear(); if (conf_get_changed()) res = dialog_yesno(NULL, _("Do you wish to save your new configuration?\n" "(Press to continue configuration.)"), 6, 60); else res = -1; end_dialog(saved_x, saved_y); switch (res) { case 0: if (conf_write(filename)) { fprintf(stderr, _("\n\n" "Error while writing of the configuration.\n" "Your configuration changes were NOT saved." "\n\n")); return 1; } /* fall through */ case -1: printf(_("\n\n" "*** End of the configuration.\n" "*** Execute 'make' to start the build or try 'make help'." "\n\n")); res = 0; break; default: fprintf(stderr, _("\n\n" "Your configuration changes were NOT saved." "\n\n")); if (res != KEY_ESC) res = 0; } return res; } static void sig_handler(int signo) { exit(handle_exit()); } int main(int ac, char **av) { char *mode; int res; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); signal(SIGINT, sig_handler); conf_parse(av[1]); conf_read(NULL); mode = getenv("MENUCONFIG_MODE"); if (mode) { if (!strcasecmp(mode, "single_menu")) single_menu_mode = 1; } if (init_dialog(NULL)) { fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); return 1; } set_config_filename(conf_get_configname()); conf_set_message_callback(conf_message_callback); do { conf(&rootmenu, NULL); res = handle_exit(); } while (res == KEY_ESC); return res; } ================================================ FILE: kconfig/menu.c ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include "lkc.h" static const char nohelp_text[] = "There is no help available for this option."; struct menu rootmenu; static struct menu **last_entry_ptr; struct file *file_list; struct file *current_file; void menu_warn(struct menu *menu, const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); } static void prop_warn(struct property *prop, const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); } void _menu_init(void) { current_entry = current_menu = &rootmenu; last_entry_ptr = &rootmenu.list; } void menu_add_entry(struct symbol *sym) { struct menu *menu; menu = xmalloc(sizeof(*menu)); memset(menu, 0, sizeof(*menu)); menu->sym = sym; menu->parent = current_menu; menu->file = current_file; menu->lineno = zconf_lineno(); *last_entry_ptr = menu; last_entry_ptr = &menu->next; current_entry = menu; if (sym) menu_add_symbol(P_SYMBOL, sym, NULL); } void menu_end_entry(void) { } struct menu *menu_add_menu(void) { menu_end_entry(); last_entry_ptr = ¤t_entry->list; return current_menu = current_entry; } void menu_end_menu(void) { last_entry_ptr = ¤t_menu->next; current_menu = current_menu->parent; } static struct expr *menu_check_dep(struct expr *e) { if (!e) return e; switch (e->type) { case E_NOT: e->left.expr = menu_check_dep(e->left.expr); break; case E_OR: case E_AND: e->left.expr = menu_check_dep(e->left.expr); e->right.expr = menu_check_dep(e->right.expr); break; case E_SYMBOL: /* change 'm' into 'm' && MODULES */ if (e->left.sym == &symbol_mod) return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); break; default: break; } return e; } void menu_add_dep(struct expr *dep) { current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); } void menu_set_type(int type) { struct symbol *sym = current_entry->sym; if (sym->type == type) return; if (sym->type == S_UNKNOWN) { sym->type = type; return; } menu_warn(current_entry, "ignoring type redefinition of '%s' from '%s' to '%s'", sym->name ? sym->name : "", sym_type_name(sym->type), sym_type_name(type)); } struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) { struct property *prop = prop_alloc(type, current_entry->sym); prop->menu = current_entry; prop->expr = expr; prop->visible.expr = menu_check_dep(dep); if (prompt) { if (isspace(*prompt)) { prop_warn(prop, "leading whitespace ignored"); while (isspace(*prompt)) prompt++; } if (current_entry->prompt && current_entry != &rootmenu) prop_warn(prop, "prompt redefined"); /* Apply all upper menus' visibilities to actual prompts. */ if(type == P_PROMPT) { struct menu *menu = current_entry; while ((menu = menu->parent) != NULL) { struct expr *dup_expr; if (!menu->visibility) continue; /* * Do not add a reference to the * menu's visibility expression but * use a copy of it. Otherwise the * expression reduction functions * will modify expressions that have * multiple references which can * cause unwanted side effects. */ dup_expr = expr_copy(menu->visibility); prop->visible.expr = expr_alloc_and(prop->visible.expr, dup_expr); } } current_entry->prompt = prop; } prop->text = prompt; return prop; } struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) { return menu_add_prop(type, prompt, NULL, dep); } void menu_add_visibility(struct expr *expr) { current_entry->visibility = expr_alloc_and(current_entry->visibility, expr); } void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) { menu_add_prop(type, NULL, expr, dep); } void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) { menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); } void menu_add_option(int token, char *arg) { switch (token) { case T_OPT_MODULES: if (modules_sym) zconf_error("symbol '%s' redefines option 'modules'" " already defined by symbol '%s'", current_entry->sym->name, modules_sym->name ); modules_sym = current_entry->sym; break; case T_OPT_DEFCONFIG_LIST: if (!sym_defconfig_list) sym_defconfig_list = current_entry->sym; else if (sym_defconfig_list != current_entry->sym) zconf_error("trying to redefine defconfig symbol"); break; case T_OPT_ENV: prop_add_env(arg); break; case T_OPT_ALLNOCONFIG_Y: current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; break; } } static int menu_validate_number(struct symbol *sym, struct symbol *sym2) { return sym2->type == S_INT || sym2->type == S_HEX || (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); } static void sym_check_prop(struct symbol *sym) { struct property *prop; struct symbol *sym2; for (prop = sym->prop; prop; prop = prop->next) { switch (prop->type) { case P_DEFAULT: if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && prop->expr->type != E_SYMBOL) prop_warn(prop, "default for config symbol '%s'" " must be a single symbol", sym->name); if (prop->expr->type != E_SYMBOL) break; sym2 = prop_get_symbol(prop); if (sym->type == S_HEX || sym->type == S_INT) { if (!menu_validate_number(sym, sym2)) prop_warn(prop, "'%s': number is invalid", sym->name); } break; case P_SELECT: sym2 = prop_get_symbol(prop); if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) prop_warn(prop, "config symbol '%s' uses select, but is " "not boolean or tristate", sym->name); else if (sym2->type != S_UNKNOWN && sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE) prop_warn(prop, "'%s' has wrong type. 'select' only " "accept arguments of boolean and " "tristate type", sym2->name); break; case P_RANGE: if (sym->type != S_INT && sym->type != S_HEX) prop_warn(prop, "range is only allowed " "for int or hex symbols"); if (!menu_validate_number(sym, prop->expr->left.sym) || !menu_validate_number(sym, prop->expr->right.sym)) prop_warn(prop, "range is invalid"); break; default: ; } } } void menu_finalize(struct menu *parent) { struct menu *menu, *last_menu; struct symbol *sym; struct property *prop; struct expr *parentdep, *basedep, *dep, *dep2, **ep; sym = parent->sym; if (parent->list) { if (sym && sym_is_choice(sym)) { if (sym->type == S_UNKNOWN) { /* find the first choice value to find out choice type */ current_entry = parent; for (menu = parent->list; menu; menu = menu->next) { if (menu->sym && menu->sym->type != S_UNKNOWN) { menu_set_type(menu->sym->type); break; } } } /* set the type of the remaining choice values */ for (menu = parent->list; menu; menu = menu->next) { current_entry = menu; if (menu->sym && menu->sym->type == S_UNKNOWN) menu_set_type(sym->type); } parentdep = expr_alloc_symbol(sym); } else if (parent->prompt) parentdep = parent->prompt->visible.expr; else parentdep = parent->dep; for (menu = parent->list; menu; menu = menu->next) { basedep = expr_transform(menu->dep); basedep = expr_alloc_and(expr_copy(parentdep), basedep); basedep = expr_eliminate_dups(basedep); menu->dep = basedep; if (menu->sym) prop = menu->sym->prop; else prop = menu->prompt; for (; prop; prop = prop->next) { if (prop->menu != menu) continue; dep = expr_transform(prop->visible.expr); dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_eliminate_dups(dep); if (menu->sym && menu->sym->type != S_TRISTATE) dep = expr_trans_bool(dep); prop->visible.expr = dep; if (prop->type == P_SELECT) { struct symbol *es = prop_get_symbol(prop); es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); } } } for (menu = parent->list; menu; menu = menu->next) menu_finalize(menu); } else if (sym) { basedep = parent->prompt ? parent->prompt->visible.expr : NULL; basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_eliminate_dups(expr_transform(basedep)); last_menu = NULL; for (menu = parent->next; menu; menu = menu->next) { dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; if (!expr_contains_symbol(dep, sym)) break; if (expr_depends_symbol(dep, sym)) goto next; dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); dep = expr_eliminate_dups(expr_transform(dep)); dep2 = expr_copy(basedep); expr_eliminate_eq(&dep, &dep2); expr_free(dep); if (!expr_is_yes(dep2)) { expr_free(dep2); break; } expr_free(dep2); next: menu_finalize(menu); menu->parent = parent; last_menu = menu; } if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; last_menu->next = NULL; } sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); } for (menu = parent->list; menu; menu = menu->next) { if (sym && sym_is_choice(sym) && menu->sym && !sym_is_choice_value(menu->sym)) { current_entry = menu; menu->sym->flags |= SYMBOL_CHOICEVAL; if (!menu->prompt) menu_warn(menu, "choice value must have a prompt"); for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->type == P_DEFAULT) prop_warn(prop, "defaults for choice " "values not supported"); if (prop->menu == menu) continue; if (prop->type == P_PROMPT && prop->menu->parent->sym != sym) prop_warn(prop, "choice value used outside its choice group"); } /* Non-tristate choice values of tristate choices must * depend on the choice being set to Y. The choice * values' dependencies were propagated to their * properties above, so the change here must be re- * propagated. */ if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); menu->dep = expr_alloc_and(basedep, menu->dep); for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; prop->visible.expr = expr_alloc_and(expr_copy(basedep), prop->visible.expr); } } menu_add_symbol(P_CHOICE, sym, NULL); prop = sym_get_choice_prop(sym); for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) ; *ep = expr_alloc_one(E_LIST, NULL); (*ep)->right.sym = menu->sym; } if (menu->list && (!menu->prompt || !menu->prompt->text)) { for (last_menu = menu->list; ; last_menu = last_menu->next) { last_menu->parent = parent; if (!last_menu->next) break; } last_menu->next = menu->next; menu->next = menu->list; menu->list = NULL; } } if (sym && !(sym->flags & SYMBOL_WARNED)) { if (sym->type == S_UNKNOWN) menu_warn(parent, "config symbol defined without type"); if (sym_is_choice(sym) && !parent->prompt) menu_warn(parent, "choice must have a prompt"); /* Check properties connected to this symbol */ sym_check_prop(sym); sym->flags |= SYMBOL_WARNED; } if (sym && !sym_is_optional(sym) && parent->prompt) { sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, expr_alloc_and(parent->prompt->visible.expr, expr_alloc_symbol(&symbol_mod))); } } bool menu_has_prompt(struct menu *menu) { if (!menu->prompt) return false; return true; } /* * Determine if a menu is empty. * A menu is considered empty if it contains no or only * invisible entries. */ bool menu_is_empty(struct menu *menu) { struct menu *child; for (child = menu->list; child; child = child->next) { if (menu_is_visible(child)) return(false); } return(true); } bool menu_is_visible(struct menu *menu) { struct menu *child; struct symbol *sym; tristate visible; if (!menu->prompt) return false; if (menu->visibility) { if (expr_calc_value(menu->visibility) == no) return no; } sym = menu->sym; if (sym) { sym_calc_value(sym); visible = menu->prompt->visible.tri; } else visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); if (visible != no) return true; if (!sym || sym_get_tristate_value(menu->sym) == no) return false; for (child = menu->list; child; child = child->next) { if (menu_is_visible(child)) { if (sym) sym->flags |= SYMBOL_DEF_USER; return true; } } return false; } const char *menu_get_prompt(struct menu *menu) { if (menu->prompt) return menu->prompt->text; else if (menu->sym) return menu->sym->name; return NULL; } struct menu *menu_get_root_menu(struct menu *menu) { return &rootmenu; } struct menu *menu_get_parent_menu(struct menu *menu) { enum prop_type type; for (; menu != &rootmenu; menu = menu->parent) { type = menu->prompt ? menu->prompt->type : 0; if (type == P_MENU) break; } return menu; } bool menu_has_help(struct menu *menu) { return menu->help != NULL; } const char *menu_get_help(struct menu *menu) { if (menu->help) return menu->help; else return ""; } static void get_prompt_str(struct gstr *r, struct property *prop, struct list_head *head) { int i, j; struct menu *submenu[8], *menu, *location = NULL; struct jump_key *jump; str_printf(r, _("Prompt: %s\n"), _(prop->text)); menu = prop->menu->parent; for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { bool accessible = menu_is_visible(menu); submenu[i++] = menu; if (location == NULL && accessible) location = menu; } if (head && location) { jump = xmalloc(sizeof(struct jump_key)); if (menu_is_visible(prop->menu)) { /* * There is not enough room to put the hint at the * beginning of the "Prompt" line. Put the hint on the * last "Location" line even when it would belong on * the former. */ jump->target = prop->menu; } else jump->target = location; if (list_empty(head)) jump->index = 0; else jump->index = list_entry(head->prev, struct jump_key, entries)->index + 1; list_add_tail(&jump->entries, head); } if (i > 0) { str_printf(r, _(" Location:\n")); for (j = 4; --i >= 0; j += 2) { menu = submenu[i]; if (head && location && menu == location) jump->offset = strlen(r->s); str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? menu->sym->name : _(""), sym_get_string_value(menu->sym)); } str_append(r, "\n"); } } } /* * get property of type P_SYMBOL */ static struct property *get_symbol_prop(struct symbol *sym) { struct property *prop = NULL; for_all_properties(sym, prop, P_SYMBOL) break; return prop; } /* * head is optional and may be NULL */ void get_symbol_str(struct gstr *r, struct symbol *sym, struct list_head *head) { bool hit; struct property *prop; if (sym && sym->name) { str_printf(r, "Symbol: %s [=%s]\n", sym->name, sym_get_string_value(sym)); str_printf(r, "Type : %s\n", sym_type_name(sym->type)); if (sym->type == S_INT || sym->type == S_HEX) { prop = sym_get_range_prop(sym); if (prop) { str_printf(r, "Range : "); expr_gstr_print(prop->expr, r); str_append(r, "\n"); } } } for_all_prompts(sym, prop) get_prompt_str(r, prop, head); prop = get_symbol_prop(sym); if (prop) { str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, prop->menu->lineno); if (!expr_is_yes(prop->visible.expr)) { str_append(r, _(" Depends on: ")); expr_gstr_print(prop->visible.expr, r); str_append(r, "\n"); } } hit = false; for_all_properties(sym, prop, P_SELECT) { if (!hit) { str_append(r, " Selects: "); hit = true; } else str_printf(r, " && "); expr_gstr_print(prop->expr, r); } if (hit) str_append(r, "\n"); if (sym->rev_dep.expr) { str_append(r, _(" Selected by: ")); expr_gstr_print(sym->rev_dep.expr, r); str_append(r, "\n"); } str_append(r, "\n\n"); } struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) { struct symbol *sym; struct gstr res = str_new(); int i; for (i = 0; sym_arr && (sym = sym_arr[i]); i++) get_symbol_str(&res, sym, head); if (!i) str_append(&res, _("No matches found.\n")); return res; } void menu_get_ext_help(struct menu *menu, struct gstr *help) { struct symbol *sym = menu->sym; const char *help_text = nohelp_text; if (menu_has_help(menu)) { if (sym->name) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); help_text = menu_get_help(menu); } str_printf(help, "%s\n", _(help_text)); if (sym) get_symbol_str(help, sym, NULL); } ================================================ FILE: kconfig/merge_config.sh ================================================ #!/bin/sh # merge_config.sh - Takes a list of config fragment values, and merges # them one by one. Provides warnings on overridden values, and specified # values that did not make it to the resulting .config file (due to missed # dependencies or config symbol removal). # # Portions reused from kconf_check and generate_cfg: # http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check # http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg # # Copyright (c) 2009-2010 Wind River Systems, Inc. # Copyright 2011 Linaro # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # 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. clean_up() { rm -f $TMP_FILE exit } trap clean_up HUP INT TERM usage() { echo "Usage: $0 [OPTIONS] [CONFIG [...]]" echo " -h display this help text" echo " -m only merge the fragments, do not execute the make command" echo " -n use allnoconfig instead of alldefconfig" echo " -r list redundant entries when merging fragments" echo " -O dir to put generated output files" } MAKE=true ALLTARGET=alldefconfig WARNREDUN=false OUTPUT=. while true; do case $1 in "-n") ALLTARGET=allnoconfig shift continue ;; "-m") MAKE=false shift continue ;; "-h") usage exit ;; "-r") WARNREDUN=true shift continue ;; "-O") if [ -d $2 ];then OUTPUT=$(echo $2 | sed 's/\/*$//') else echo "output directory $2 does not exist" 1>&2 exit 1 fi shift 2 continue ;; *) break ;; esac done INITFILE=$1 shift; MERGE_LIST=$* SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) echo "Using $INITFILE as base" cat $INITFILE > $TMP_FILE # Merge files, printing warnings on overrided values for MERGE_FILE in $MERGE_LIST ; do echo "Merging $MERGE_FILE" CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE) for CFG in $CFG_LIST ; do grep -q -w $CFG $TMP_FILE if [ $? -eq 0 ] ; then PREV_VAL=$(grep -w $CFG $TMP_FILE) NEW_VAL=$(grep -w $CFG $MERGE_FILE) if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then echo Value of $CFG is redefined by fragment $MERGE_FILE: echo Previous value: $PREV_VAL echo New value: $NEW_VAL echo elif [ "$WARNREDUN" = "true" ]; then echo Value of $CFG is redundant by fragment $MERGE_FILE: fi sed -i "/$CFG[ =]/d" $TMP_FILE fi done cat $MERGE_FILE >> $TMP_FILE done if [ "$MAKE" = "false" ]; then cp $TMP_FILE $OUTPUT/.config echo "#" echo "# merged configuration written to $OUTPUT/.config (needs make)" echo "#" clean_up exit fi # If we have an output dir, setup the O= argument, otherwise leave # it blank, since O=. will create an unnecessary ./source softlink OUTPUT_ARG="" if [ "$OUTPUT" != "." ] ; then OUTPUT_ARG="O=$OUTPUT" fi # Use the merged file as the starting point for: # alldefconfig: Fills in any missing symbols with Kconfig default # allnoconfig: Fills in any missing symbols with # CONFIG_* is not set make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET # Check all specified config values took (might have missed-dependency issues) for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config) if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then echo "Value requested for $CFG not in final .config" echo "Requested value: $REQUESTED_VAL" echo "Actual value: $ACTUAL_VAL" echo "" fi done clean_up ================================================ FILE: kconfig/nconf.c ================================================ /* * Copyright (C) 2008 Nir Tzachar #include #include "lkc.h" #include "nconf.h" #include static const char nconf_global_help[] = N_( "Help windows\n" "------------\n" "o Global help: Unless in a data entry window, pressing will give \n" " you the global help window, which you are just reading.\n" "\n" "o A short version of the global help is available by pressing .\n" "\n" "o Local help: To get help related to the current menu entry, use any\n" " of , or if in a data entry window then press .\n" "\n" "\n" "Menu entries\n" "------------\n" "This interface lets you select features and parameters for the \n" "build. Features can either be built-in, modularized, or removed.\n" "Parameters must be entered as text or decimal or hexadecimal numbers.\n" "\n" "Menu entries beginning with following braces represent features that\n" " [ ] can be built in or removed\n" " < > can be built in, modularized or removed\n" " { } can be built in or modularized, are selected by another feature\n" " - - are selected by another feature\n" " XXX cannot be selected. Symbol Info tells you why.\n" "*, M or whitespace inside braces means to build in, build as a module\n" "or to exclude the feature respectively.\n" "\n" "To change any of these features, highlight it with the movement keys\n" "listed below and press to build it in, to make it a module or\n" " to remove it. You may press the key to cycle through the\n" "available options.\n" "\n" "A trailing \"--->\" designates a submenu, a trailing \"----\" an\n" "empty submenu.\n" "\n" "Menu navigation keys\n" "----------------------------------------------------------------------\n" "Linewise up \n" "Linewise down \n" "Pagewise up \n" "Pagewise down \n" "First entry \n" "Last entry \n" "Enter a submenu \n" "Go back to parent menu \n" "Close a help window \n" "Close entry window, apply \n" "Close entry window, forget \n" "Start incremental, case-insensitive search for STRING in menu entries,\n" " no regex support, STRING is displayed in upper left corner\n" " STRING\n" " Remove last character \n" " Jump to next hit \n" " Jump to previous hit \n" "Exit menu search mode \n" "Search for configuration variables with or without leading CONFIG_\n" " RegExpr\n" "Verbose search help \n" "----------------------------------------------------------------------\n" "\n" "Unless in a data entry window, key <1> may be used instead of ,\n" "<2> instead of , etc.\n" "\n" "\n" "Radiolist (Choice list)\n" "-----------------------\n" "Use the movement keys listed above to select the option you wish to set\n" "and press .\n" "\n" "\n" "Data entry\n" "----------\n" "Enter the requested information and press . Hexadecimal values\n" "may be entered without the \"0x\" prefix.\n" "\n" "\n" "Text Box (Help Window)\n" "----------------------\n" "Use movement keys as listed in table above.\n" "\n" "Press any of to exit.\n" "\n" "\n" "Alternate configuration files\n" "-----------------------------\n" "nconfig supports switching between different configurations.\n" "Press to save your current configuration. Press and enter\n" "a file name to load a previously saved configuration.\n" "\n" "\n" "Terminal configuration\n" "----------------------\n" "If you use nconfig in a xterm window, make sure your TERM environment\n" "variable specifies a terminal configuration which supports at least\n" "16 colors. Otherwise nconfig will look rather bad.\n" "\n" "If the \"stty size\" command reports the current terminalsize correctly,\n" "nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n" "and display longer menus properly.\n" "\n" "\n" "Single menu mode\n" "----------------\n" "If you prefer to have all of the menu entries listed in a single menu,\n" "rather than the default multimenu hierarchy, run nconfig with\n" "NCONFIG_MODE environment variable set to single_menu. Example:\n" "\n" "make NCONFIG_MODE=single_menu nconfig\n" "\n" " will then unfold the appropriate category, or fold it if it\n" "is already unfolded. Folded menu entries will be designated by a\n" "leading \"++>\" and unfolded entries by a leading \"-->\".\n" "\n" "Note that this mode can eventually be a little more CPU expensive than\n" "the default mode, especially with a larger number of unfolded submenus.\n" "\n"), menu_no_f_instructions[] = N_( "Legend: [*] built-in [ ] excluded module < > module capable.\n" "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" "\n" "Use the following keys to navigate the menus:\n" "Move up or down with and .\n" "Enter a submenu with or .\n" "Exit a submenu to its parent menu with or .\n" "Pressing includes, excludes, modularizes features.\n" "Pressing cycles through the available options.\n" "To search for menu entries press .\n" " always leaves the current window.\n" "\n" "You do not have function keys support.\n" "Press <1> instead of , <2> instead of , etc.\n" "For verbose global help use key <1>.\n" "For help related to the current menu entry press or .\n"), menu_instructions[] = N_( "Legend: [*] built-in [ ] excluded module < > module capable.\n" "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" "\n" "Use the following keys to navigate the menus:\n" "Move up or down with or .\n" "Enter a submenu with or .\n" "Exit a submenu to its parent menu with or .\n" "Pressing includes, excludes, modularizes features.\n" "Pressing cycles through the available options.\n" "To search for menu entries press .\n" " always leaves the current window.\n" "\n" "Pressing <1> may be used instead of , <2> instead of , etc.\n" "For verbose global help press .\n" "For help related to the current menu entry press or .\n"), radiolist_instructions[] = N_( "Press , , or to navigate a radiolist, select\n" "with .\n" "For help related to the current entry press or .\n" "For global help press .\n"), inputbox_instructions_int[] = N_( "Please enter a decimal value.\n" "Fractions will not be accepted.\n" "Press to apply, to cancel."), inputbox_instructions_hex[] = N_( "Please enter a hexadecimal value.\n" "Press to apply, to cancel."), inputbox_instructions_string[] = N_( "Please enter a string value.\n" "Press to apply, to cancel."), setmod_text[] = N_( "This feature depends on another feature which has been configured as a\n" "module. As a result, the current feature will be built as a module too."), load_config_text[] = N_( "Enter the name of the configuration file you wish to load.\n" "Accept the name shown to restore the configuration you last\n" "retrieved. Leave empty to abort."), load_config_help[] = N_( "For various reasons, one may wish to keep several different\n" "configurations available on a single machine.\n" "\n" "If you have saved a previous configuration in a file other than the\n" "default one, entering its name here will allow you to load and modify\n" "that configuration.\n" "\n" "Leave empty to abort.\n"), save_config_text[] = N_( "Enter a filename to which this configuration should be saved\n" "as an alternate. Leave empty to abort."), save_config_help[] = N_( "For various reasons, one may wish to keep several different\n" "configurations available on a single machine.\n" "\n" "Entering a file name here will allow you to later retrieve, modify\n" "and use the current configuration as an alternate to whatever\n" "configuration options you have selected at that time.\n" "\n" "Leave empty to abort.\n"), search_help[] = N_( "Search for symbols (configuration variable names CONFIG_*) and display\n" "their relations. Regular expressions are supported.\n" "Example: Search for \"^FOO\".\n" "Result:\n" "-----------------------------------------------------------------\n" "Symbol: FOO [ = m]\n" "Prompt: Foo bus is used to drive the bar HW\n" "Defined at drivers/pci/Kconfig:47\n" "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" "Location:\n" " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [ = y])\n" " -> PCI access mode ( [ = y])\n" "Selects: LIBCRC32\n" "Selected by: BAR\n" "-----------------------------------------------------------------\n" "o The line 'Prompt:' shows the text displayed for this symbol in\n" " the menu hierarchy.\n" "o The 'Defined at' line tells at what file / line number the symbol is\n" " defined.\n" "o The 'Depends on:' line lists symbols that need to be defined for\n" " this symbol to be visible and selectable in the menu.\n" "o The 'Location:' lines tell, where in the menu structure this symbol\n" " is located. A location followed by a [ = y] indicates that this is\n" " a selectable menu item, and the current value is displayed inside\n" " brackets.\n" "o The 'Selects:' line tells, what symbol will be automatically selected\n" " if this symbol is selected (y or m).\n" "o The 'Selected by' line tells what symbol has selected this symbol.\n" "\n" "Only relevant lines are shown.\n" "\n\n" "Search examples:\n" "USB => find all symbols containing USB\n" "^USB => find all symbols starting with USB\n" "USB$ => find all symbols ending with USB\n" "\n"); struct mitem { char str[256]; char tag; void *usrptr; int is_visible; }; #define MAX_MENU_ITEMS 4096 static int show_all_items; static int indent; static struct menu *current_menu; static int child_count; static int single_menu_mode; /* the window in which all information appears */ static WINDOW *main_window; /* the largest size of the menu window */ static int mwin_max_lines; static int mwin_max_cols; /* the window in which we show option buttons */ static MENU *curses_menu; static ITEM *curses_menu_items[MAX_MENU_ITEMS]; static struct mitem k_menu_items[MAX_MENU_ITEMS]; static int items_num; static int global_exit; /* the currently selected button */ const char *current_instructions = menu_instructions; static char *dialog_input_result; static int dialog_input_result_len; static void conf(struct menu *menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); static void conf_load(void); static void conf_save(void); static void show_help(struct menu *menu); static int do_exit(void); static void setup_windows(void); static void search_conf(void); typedef void (*function_key_handler_t)(int *key, struct menu *menu); static void handle_f1(int *key, struct menu *current_item); static void handle_f2(int *key, struct menu *current_item); static void handle_f3(int *key, struct menu *current_item); static void handle_f4(int *key, struct menu *current_item); static void handle_f5(int *key, struct menu *current_item); static void handle_f6(int *key, struct menu *current_item); static void handle_f7(int *key, struct menu *current_item); static void handle_f8(int *key, struct menu *current_item); static void handle_f9(int *key, struct menu *current_item); struct function_keys { const char *key_str; const char *func; function_key key; function_key_handler_t handler; }; static const int function_keys_num = 9; struct function_keys function_keys[] = { { .key_str = "F1", .func = "Help", .key = F_HELP, .handler = handle_f1, }, { .key_str = "F2", .func = "SymInfo", .key = F_SYMBOL, .handler = handle_f2, }, { .key_str = "F3", .func = "Help 2", .key = F_INSTS, .handler = handle_f3, }, { .key_str = "F4", .func = "ShowAll", .key = F_CONF, .handler = handle_f4, }, { .key_str = "F5", .func = "Back", .key = F_BACK, .handler = handle_f5, }, { .key_str = "F6", .func = "Save", .key = F_SAVE, .handler = handle_f6, }, { .key_str = "F7", .func = "Load", .key = F_LOAD, .handler = handle_f7, }, { .key_str = "F8", .func = "SymSearch", .key = F_SEARCH, .handler = handle_f8, }, { .key_str = "F9", .func = "Exit", .key = F_EXIT, .handler = handle_f9, }, }; static void print_function_line(void) { int i; int offset = 1; const int skip = 1; int lines = getmaxy(stdscr); for (i = 0; i < function_keys_num; i++) { (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); mvwprintw(main_window, lines-3, offset, "%s", function_keys[i].key_str); (void) wattrset(main_window, attributes[FUNCTION_TEXT]); offset += strlen(function_keys[i].key_str); mvwprintw(main_window, lines-3, offset, "%s", function_keys[i].func); offset += strlen(function_keys[i].func) + skip; } (void) wattrset(main_window, attributes[NORMAL]); } /* help */ static void handle_f1(int *key, struct menu *current_item) { show_scroll_win(main_window, _("Global help"), _(nconf_global_help)); return; } /* symbole help */ static void handle_f2(int *key, struct menu *current_item) { show_help(current_item); return; } /* instructions */ static void handle_f3(int *key, struct menu *current_item) { show_scroll_win(main_window, _("Short help"), _(current_instructions)); return; } /* config */ static void handle_f4(int *key, struct menu *current_item) { int res = btn_dialog(main_window, _("Show all symbols?"), 2, " ", ""); if (res == 0) show_all_items = 1; else if (res == 1) show_all_items = 0; return; } /* back */ static void handle_f5(int *key, struct menu *current_item) { *key = KEY_LEFT; return; } /* save */ static void handle_f6(int *key, struct menu *current_item) { conf_save(); return; } /* load */ static void handle_f7(int *key, struct menu *current_item) { conf_load(); return; } /* search */ static void handle_f8(int *key, struct menu *current_item) { search_conf(); return; } /* exit */ static void handle_f9(int *key, struct menu *current_item) { do_exit(); return; } /* return != 0 to indicate the key was handles */ static int process_special_keys(int *key, struct menu *menu) { int i; if (*key == KEY_RESIZE) { setup_windows(); return 1; } for (i = 0; i < function_keys_num; i++) { if (*key == KEY_F(function_keys[i].key) || *key == '0' + function_keys[i].key){ function_keys[i].handler(key, menu); return 1; } } return 0; } static void clean_items(void) { int i; for (i = 0; curses_menu_items[i]; i++) free_item(curses_menu_items[i]); bzero(curses_menu_items, sizeof(curses_menu_items)); bzero(k_menu_items, sizeof(k_menu_items)); items_num = 0; } typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN, FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f; /* return the index of the matched item, or -1 if no such item exists */ static int get_mext_match(const char *match_str, match_f flag) { int match_start = item_index(current_item(curses_menu)); int index; if (flag == FIND_NEXT_MATCH_DOWN) ++match_start; else if (flag == FIND_NEXT_MATCH_UP) --match_start; index = match_start; index = (index + items_num) % items_num; while (true) { char *str = k_menu_items[index].str; if (strcasestr(str, match_str) != 0) return index; if (flag == FIND_NEXT_MATCH_UP || flag == MATCH_TINKER_PATTERN_UP) --index; else ++index; index = (index + items_num) % items_num; if (index == match_start) return -1; } } /* Make a new item. */ static void item_make(struct menu *menu, char tag, const char *fmt, ...) { va_list ap; if (items_num > MAX_MENU_ITEMS-1) return; bzero(&k_menu_items[items_num], sizeof(k_menu_items[0])); k_menu_items[items_num].tag = tag; k_menu_items[items_num].usrptr = menu; if (menu != NULL) k_menu_items[items_num].is_visible = menu_is_visible(menu); else k_menu_items[items_num].is_visible = 1; va_start(ap, fmt); vsnprintf(k_menu_items[items_num].str, sizeof(k_menu_items[items_num].str), fmt, ap); va_end(ap); if (!k_menu_items[items_num].is_visible) memcpy(k_menu_items[items_num].str, "XXX", 3); curses_menu_items[items_num] = new_item( k_menu_items[items_num].str, k_menu_items[items_num].str); set_item_userptr(curses_menu_items[items_num], &k_menu_items[items_num]); /* if (!k_menu_items[items_num].is_visible) item_opts_off(curses_menu_items[items_num], O_SELECTABLE); */ items_num++; curses_menu_items[items_num] = NULL; } /* very hackish. adds a string to the last item added */ static void item_add_str(const char *fmt, ...) { va_list ap; int index = items_num-1; char new_str[256]; char tmp_str[256]; if (index < 0) return; va_start(ap, fmt); vsnprintf(new_str, sizeof(new_str), fmt, ap); va_end(ap); snprintf(tmp_str, sizeof(tmp_str), "%s%s", k_menu_items[index].str, new_str); strncpy(k_menu_items[index].str, tmp_str, sizeof(k_menu_items[index].str)); free_item(curses_menu_items[index]); curses_menu_items[index] = new_item( k_menu_items[index].str, k_menu_items[index].str); set_item_userptr(curses_menu_items[index], &k_menu_items[index]); } /* get the tag of the currently selected item */ static char item_tag(void) { ITEM *cur; struct mitem *mcur; cur = current_item(curses_menu); if (cur == NULL) return 0; mcur = (struct mitem *) item_userptr(cur); return mcur->tag; } static int curses_item_index(void) { return item_index(current_item(curses_menu)); } static void *item_data(void) { ITEM *cur; struct mitem *mcur; cur = current_item(curses_menu); if (!cur) return NULL; mcur = (struct mitem *) item_userptr(cur); return mcur->usrptr; } static int item_is_tag(char tag) { return item_tag() == tag; } static char filename[PATH_MAX+1]; static char menu_backtitle[PATH_MAX+128]; static const char *set_config_filename(const char *config_filename) { int size; size = snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s", config_filename, rootmenu.prompt->text); if (size >= sizeof(menu_backtitle)) menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; size = snprintf(filename, sizeof(filename), "%s", config_filename); if (size >= sizeof(filename)) filename[sizeof(filename)-1] = '\0'; return menu_backtitle; } /* return = 0 means we are successful. * -1 means go on doing what you were doing */ static int do_exit(void) { int res; if (!conf_get_changed()) { global_exit = 1; return 0; } res = btn_dialog(main_window, _("Do you wish to save your new configuration?\n" " to cancel and resume nconfig."), 2, " ", ""); if (res == KEY_EXIT) { global_exit = 0; return -1; } /* if we got here, the user really wants to exit */ switch (res) { case 0: res = conf_write(filename); if (res) btn_dialog( main_window, _("Error during writing of configuration.\n" "Your configuration changes were NOT saved."), 1, ""); break; default: btn_dialog( main_window, _("Your configuration changes were NOT saved."), 1, ""); break; } global_exit = 1; return 0; } static void search_conf(void) { struct symbol **sym_arr; struct gstr res; struct gstr title; char *dialog_input; int dres; title = str_new(); str_printf( &title, _("Enter (sub)string or regexp to search for " "(with or without \"%s\")"), CONFIG_); again: dres = dialog_inputbox(main_window, _("Search Configuration Parameter"), str_get(&title), "", &dialog_input_result, &dialog_input_result_len); switch (dres) { case 0: break; case 1: show_scroll_win(main_window, _("Search Configuration"), search_help); goto again; default: str_free(&title); return; } /* strip the prefix if necessary */ dialog_input = dialog_input_result; if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); res = get_relations_str(sym_arr, NULL); free(sym_arr); show_scroll_win(main_window, _("Search Results"), str_get(&res)); str_free(&res); str_free(&title); } static void build_conf(struct menu *menu) { struct symbol *sym; struct property *prop; struct menu *child; int type, tmp, doint = 2; tristate val; char ch; if (!menu || (!show_all_items && !menu_is_visible(menu))) return; sym = menu->sym; prop = menu->prompt; if (!sym) { if (prop && menu != current_menu) { const char *prompt = menu_get_prompt(menu); enum prop_type ptype; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; switch (ptype) { case P_MENU: child_count++; prompt = _(prompt); if (single_menu_mode) { item_make(menu, 'm', "%s%*c%s", menu->data ? "-->" : "++>", indent + 1, ' ', prompt); } else item_make(menu, 'm', " %*c%s %s", indent + 1, ' ', prompt, menu_is_empty(menu) ? "----" : "--->"); if (single_menu_mode && menu->data) goto conf_childs; return; case P_COMMENT: if (prompt) { child_count++; item_make(menu, ':', " %*c*** %s ***", indent + 1, ' ', _(prompt)); } break; default: if (prompt) { child_count++; item_make(menu, ':', "---%*c%s", indent + 1, ' ', _(prompt)); } } } else doint = 0; goto conf_childs; } type = sym_get_type(sym); if (sym_is_choice(sym)) { struct symbol *def_sym = sym_get_choice_value(sym); struct menu *def_menu = NULL; child_count++; for (child = menu->list; child; child = child->next) { if (menu_is_visible(child) && child->sym == def_sym) def_menu = child; } val = sym_get_tristate_value(sym); if (sym_is_changable(sym)) { switch (type) { case S_BOOLEAN: item_make(menu, 't', "[%c]", val == no ? ' ' : '*'); break; case S_TRISTATE: switch (val) { case yes: ch = '*'; break; case mod: ch = 'M'; break; default: ch = ' '; break; } item_make(menu, 't', "<%c>", ch); break; } } else { item_make(menu, def_menu ? 't' : ':', " "); } item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); if (val == yes) { if (def_menu) { item_add_str(" (%s)", _(menu_get_prompt(def_menu))); item_add_str(" --->"); if (def_menu->list) { indent += 2; build_conf(def_menu); indent -= 2; } } return; } } else { if (menu == current_menu) { item_make(menu, ':', "---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); goto conf_childs; } child_count++; val = sym_get_tristate_value(sym); if (sym_is_choice_value(sym) && val == yes) { item_make(menu, ':', " "); } else { switch (type) { case S_BOOLEAN: if (sym_is_changable(sym)) item_make(menu, 't', "[%c]", val == no ? ' ' : '*'); else item_make(menu, 't', "-%c-", val == no ? ' ' : '*'); break; case S_TRISTATE: switch (val) { case yes: ch = '*'; break; case mod: ch = 'M'; break; default: ch = ' '; break; } if (sym_is_changable(sym)) { if (sym->rev_dep.tri == mod) item_make(menu, 't', "{%c}", ch); else item_make(menu, 't', "<%c>", ch); } else item_make(menu, 't', "-%c-", ch); break; default: tmp = 2 + strlen(sym_get_string_value(sym)); item_make(menu, 's', " (%s)", sym_get_string_value(sym)); tmp = indent - tmp + 4; if (tmp < 0) tmp = 0; item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), (sym_has_value(sym) || !sym_is_changable(sym)) ? "" : _(" (NEW)")); goto conf_childs; } } item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), (sym_has_value(sym) || !sym_is_changable(sym)) ? "" : _(" (NEW)")); if (menu->prompt && menu->prompt->type == P_MENU) { item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); return; } } conf_childs: indent += doint; for (child = menu->list; child; child = child->next) build_conf(child); indent -= doint; } static void reset_menu(void) { unpost_menu(curses_menu); clean_items(); } /* adjust the menu to show this item. * prefer not to scroll the menu if possible*/ static void center_item(int selected_index, int *last_top_row) { int toprow; set_top_row(curses_menu, *last_top_row); toprow = top_row(curses_menu); if (selected_index < toprow || selected_index >= toprow+mwin_max_lines) { toprow = max(selected_index-mwin_max_lines/2, 0); if (toprow >= item_count(curses_menu)-mwin_max_lines) toprow = item_count(curses_menu)-mwin_max_lines; set_top_row(curses_menu, toprow); } set_current_item(curses_menu, curses_menu_items[selected_index]); *last_top_row = toprow; post_menu(curses_menu); refresh_all_windows(main_window); } /* this function assumes reset_menu has been called before */ static void show_menu(const char *prompt, const char *instructions, int selected_index, int *last_top_row) { int maxx, maxy; WINDOW *menu_window; current_instructions = instructions; clear(); (void) wattrset(main_window, attributes[NORMAL]); print_in_middle(stdscr, 1, 0, getmaxx(stdscr), menu_backtitle, attributes[MAIN_HEADING]); (void) wattrset(main_window, attributes[MAIN_MENU_BOX]); box(main_window, 0, 0); (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]); mvwprintw(main_window, 0, 3, " %s ", prompt); (void) wattrset(main_window, attributes[NORMAL]); set_menu_items(curses_menu, curses_menu_items); /* position the menu at the middle of the screen */ scale_menu(curses_menu, &maxy, &maxx); maxx = min(maxx, mwin_max_cols-2); maxy = mwin_max_lines; menu_window = derwin(main_window, maxy, maxx, 2, (mwin_max_cols-maxx)/2); keypad(menu_window, TRUE); set_menu_win(curses_menu, menu_window); set_menu_sub(curses_menu, menu_window); /* must reassert this after changing items, otherwise returns to a * default of 16 */ set_menu_format(curses_menu, maxy, 1); center_item(selected_index, last_top_row); set_menu_format(curses_menu, maxy, 1); print_function_line(); /* Post the menu */ post_menu(curses_menu); refresh_all_windows(main_window); } static void adj_match_dir(match_f *match_direction) { if (*match_direction == FIND_NEXT_MATCH_DOWN) *match_direction = MATCH_TINKER_PATTERN_DOWN; else if (*match_direction == FIND_NEXT_MATCH_UP) *match_direction = MATCH_TINKER_PATTERN_UP; /* else, do no change.. */ } struct match_state { int in_search; match_f match_direction; char pattern[256]; }; /* Return 0 means I have handled the key. In such a case, ans should hold the * item to center, or -1 otherwise. * Else return -1 . */ static int do_match(int key, struct match_state *state, int *ans) { char c = (char) key; int terminate_search = 0; *ans = -1; if (key == '/' || (state->in_search && key == 27)) { move(0, 0); refresh(); clrtoeol(); state->in_search = 1-state->in_search; bzero(state->pattern, sizeof(state->pattern)); state->match_direction = MATCH_TINKER_PATTERN_DOWN; return 0; } else if (!state->in_search) return 1; if (isalnum(c) || isgraph(c) || c == ' ') { state->pattern[strlen(state->pattern)] = c; state->pattern[strlen(state->pattern)] = '\0'; adj_match_dir(&state->match_direction); *ans = get_mext_match(state->pattern, state->match_direction); } else if (key == KEY_DOWN) { state->match_direction = FIND_NEXT_MATCH_DOWN; *ans = get_mext_match(state->pattern, state->match_direction); } else if (key == KEY_UP) { state->match_direction = FIND_NEXT_MATCH_UP; *ans = get_mext_match(state->pattern, state->match_direction); } else if (key == KEY_BACKSPACE || key == 127) { state->pattern[strlen(state->pattern)-1] = '\0'; adj_match_dir(&state->match_direction); } else terminate_search = 1; if (terminate_search) { state->in_search = 0; bzero(state->pattern, sizeof(state->pattern)); move(0, 0); refresh(); clrtoeol(); return -1; } return 0; } static void conf(struct menu *menu) { struct menu *submenu = 0; const char *prompt = menu_get_prompt(menu); struct symbol *sym; int res; int current_index = 0; int last_top_row = 0; struct match_state match_state = { .in_search = 0, .match_direction = MATCH_TINKER_PATTERN_DOWN, .pattern = "", }; while (!global_exit) { reset_menu(); current_menu = menu; build_conf(menu); if (!child_count) break; show_menu(prompt ? _(prompt) : _("Main Menu"), _(menu_instructions), current_index, &last_top_row); keypad((menu_win(curses_menu)), TRUE); while (!global_exit) { if (match_state.in_search) { mvprintw(0, 0, "searching: %s", match_state.pattern); clrtoeol(); } refresh_all_windows(main_window); res = wgetch(menu_win(curses_menu)); if (!res) break; if (do_match(res, &match_state, ¤t_index) == 0) { if (current_index != -1) center_item(current_index, &last_top_row); continue; } if (process_special_keys(&res, (struct menu *) item_data())) break; switch (res) { case KEY_DOWN: menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: menu_driver(curses_menu, REQ_SCR_DPAGE); break; case KEY_PPAGE: menu_driver(curses_menu, REQ_SCR_UPAGE); break; case KEY_HOME: menu_driver(curses_menu, REQ_FIRST_ITEM); break; case KEY_END: menu_driver(curses_menu, REQ_LAST_ITEM); break; case 'h': case '?': show_help((struct menu *) item_data()); break; } if (res == 10 || res == 27 || res == 32 || res == 'n' || res == 'y' || res == KEY_LEFT || res == KEY_RIGHT || res == 'm') break; refresh_all_windows(main_window); } refresh_all_windows(main_window); /* if ESC or left*/ if (res == 27 || (menu != &rootmenu && res == KEY_LEFT)) break; /* remember location in the menu */ last_top_row = top_row(curses_menu); current_index = curses_item_index(); if (!item_tag()) continue; submenu = (struct menu *) item_data(); if (!submenu || !menu_is_visible(submenu)) continue; sym = submenu->sym; switch (res) { case ' ': if (item_is_tag('t')) sym_toggle_tristate_value(sym); else if (item_is_tag('m')) conf(submenu); break; case KEY_RIGHT: case 10: /* ENTER WAS PRESSED */ switch (item_tag()) { case 'm': if (single_menu_mode) submenu->data = (void *) (long) !submenu->data; else conf(submenu); break; case 't': if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) conf_choice(submenu); else if (submenu->prompt && submenu->prompt->type == P_MENU) conf(submenu); else if (res == 10) sym_toggle_tristate_value(sym); break; case 's': conf_string(submenu); break; } break; case 'y': if (item_is_tag('t')) { if (sym_set_tristate_value(sym, yes)) break; if (sym_set_tristate_value(sym, mod)) btn_dialog(main_window, setmod_text, 0); } break; case 'n': if (item_is_tag('t')) sym_set_tristate_value(sym, no); break; case 'm': if (item_is_tag('t')) sym_set_tristate_value(sym, mod); break; } } } static void conf_message_callback(const char *fmt, va_list ap) { char buf[1024]; vsnprintf(buf, sizeof(buf), fmt, ap); btn_dialog(main_window, buf, 1, ""); } static void show_help(struct menu *menu) { struct gstr help; if (!menu) return; help = str_new(); menu_get_ext_help(menu, &help); show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); str_free(&help); } static void conf_choice(struct menu *menu) { const char *prompt = _(menu_get_prompt(menu)); struct menu *child = 0; struct symbol *active; int selected_index = 0; int last_top_row = 0; int res, i = 0; struct match_state match_state = { .in_search = 0, .match_direction = MATCH_TINKER_PATTERN_DOWN, .pattern = "", }; active = sym_get_choice_value(menu->sym); /* this is mostly duplicated from the conf() function. */ while (!global_exit) { reset_menu(); for (i = 0, child = menu->list; child; child = child->next) { if (!show_all_items && !menu_is_visible(child)) continue; if (child->sym == sym_get_choice_value(menu->sym)) item_make(child, ':', " %s", _(menu_get_prompt(child))); else if (child->sym) item_make(child, ':', " %s", _(menu_get_prompt(child))); else item_make(child, ':', "*** %s ***", _(menu_get_prompt(child))); if (child->sym == active){ last_top_row = top_row(curses_menu); selected_index = i; } i++; } show_menu(prompt ? _(prompt) : _("Choice Menu"), _(radiolist_instructions), selected_index, &last_top_row); while (!global_exit) { if (match_state.in_search) { mvprintw(0, 0, "searching: %s", match_state.pattern); clrtoeol(); } refresh_all_windows(main_window); res = wgetch(menu_win(curses_menu)); if (!res) break; if (do_match(res, &match_state, &selected_index) == 0) { if (selected_index != -1) center_item(selected_index, &last_top_row); continue; } if (process_special_keys( &res, (struct menu *) item_data())) break; switch (res) { case KEY_DOWN: menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: menu_driver(curses_menu, REQ_SCR_DPAGE); break; case KEY_PPAGE: menu_driver(curses_menu, REQ_SCR_UPAGE); break; case KEY_HOME: menu_driver(curses_menu, REQ_FIRST_ITEM); break; case KEY_END: menu_driver(curses_menu, REQ_LAST_ITEM); break; case 'h': case '?': show_help((struct menu *) item_data()); break; } if (res == 10 || res == 27 || res == ' ' || res == KEY_LEFT){ break; } refresh_all_windows(main_window); } /* if ESC or left */ if (res == 27 || res == KEY_LEFT) break; child = item_data(); if (!child || !menu_is_visible(child) || !child->sym) continue; switch (res) { case ' ': case 10: case KEY_RIGHT: sym_set_tristate_value(child->sym, yes); return; case 'h': case '?': show_help(child); active = child->sym; break; case KEY_EXIT: return; } } } static void conf_string(struct menu *menu) { const char *prompt = menu_get_prompt(menu); while (1) { int res; const char *heading; switch (sym_get_type(menu->sym)) { case S_INT: heading = _(inputbox_instructions_int); break; case S_HEX: heading = _(inputbox_instructions_hex); break; case S_STRING: heading = _(inputbox_instructions_string); break; default: heading = _("Internal nconf error!"); } res = dialog_inputbox(main_window, prompt ? _(prompt) : _("Main Menu"), heading, sym_get_string_value(menu->sym), &dialog_input_result, &dialog_input_result_len); switch (res) { case 0: if (sym_set_string_value(menu->sym, dialog_input_result)) return; btn_dialog(main_window, _("You have made an invalid entry."), 0); break; case 1: show_help(menu); break; case KEY_EXIT: return; } } } static void conf_load(void) { while (1) { int res; res = dialog_inputbox(main_window, NULL, load_config_text, filename, &dialog_input_result, &dialog_input_result_len); switch (res) { case 0: if (!dialog_input_result[0]) return; if (!conf_read(dialog_input_result)) { set_config_filename(dialog_input_result); sym_set_change_count(1); return; } btn_dialog(main_window, _("File does not exist!"), 0); break; case 1: show_scroll_win(main_window, _("Load Alternate Configuration"), load_config_help); break; case KEY_EXIT: return; } } } static void conf_save(void) { while (1) { int res; res = dialog_inputbox(main_window, NULL, save_config_text, filename, &dialog_input_result, &dialog_input_result_len); switch (res) { case 0: if (!dialog_input_result[0]) return; res = conf_write(dialog_input_result); if (!res) { set_config_filename(dialog_input_result); return; } btn_dialog(main_window, _("Can't create file! " "Probably a nonexistent directory."), 1, ""); break; case 1: show_scroll_win(main_window, _("Save Alternate Configuration"), save_config_help); break; case KEY_EXIT: return; } } } void setup_windows(void) { int lines, columns; getmaxyx(stdscr, lines, columns); if (main_window != NULL) delwin(main_window); /* set up the menu and menu window */ main_window = newwin(lines-2, columns-2, 2, 1); keypad(main_window, TRUE); mwin_max_lines = lines-7; mwin_max_cols = columns-6; /* panels order is from bottom to top */ new_panel(main_window); } int main(int ac, char **av) { int lines, columns; char *mode; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); conf_parse(av[1]); conf_read(NULL); mode = getenv("NCONFIG_MODE"); if (mode) { if (!strcasecmp(mode, "single_menu")) single_menu_mode = 1; } /* Initialize curses */ initscr(); /* set color theme */ set_colors(); cbreak(); noecho(); keypad(stdscr, TRUE); curs_set(0); getmaxyx(stdscr, lines, columns); if (columns < 75 || lines < 20) { endwin(); printf("Your terminal should have at " "least 20 lines and 75 columns\n"); return 1; } notimeout(stdscr, FALSE); #if NCURSES_REENTRANT set_escdelay(1); #else ESCDELAY = 1; #endif /* set btns menu */ curses_menu = new_menu(curses_menu_items); menu_opts_off(curses_menu, O_SHOWDESC); menu_opts_on(curses_menu, O_SHOWMATCH); menu_opts_on(curses_menu, O_ONEVALUE); menu_opts_on(curses_menu, O_NONCYCLIC); menu_opts_on(curses_menu, O_IGNORECASE); set_menu_mark(curses_menu, " "); set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); set_config_filename(conf_get_configname()); setup_windows(); /* check for KEY_FUNC(1) */ if (has_key(KEY_F(1)) == FALSE) { show_scroll_win(main_window, _("Instructions"), _(menu_no_f_instructions)); } conf_set_message_callback(conf_message_callback); /* do the work */ while (!global_exit) { conf(&rootmenu); if (!global_exit && do_exit() == 0) break; } /* ok, we are done */ unpost_menu(curses_menu); free_menu(curses_menu); delwin(main_window); clear(); refresh(); endwin(); return 0; } ================================================ FILE: kconfig/nconf.gui.c ================================================ /* * Copyright (C) 2008 Nir Tzachar 0) win_rows = msg_lines+4; else win_rows = msg_lines+2; win = newwin(win_rows, total_width+4, y, x); keypad(win, TRUE); menu_win = derwin(win, 1, btns_width, win_rows-2, 1+(total_width+2-btns_width)/2); menu = new_menu(btns); msg_win = derwin(win, win_rows-2, msg_width, 1, 1+(total_width+2-msg_width)/2); set_menu_fore(menu, attributes[DIALOG_MENU_FORE]); set_menu_back(menu, attributes[DIALOG_MENU_BACK]); (void) wattrset(win, attributes[DIALOG_BOX]); box(win, 0, 0); /* print message */ (void) wattrset(msg_win, attributes[DIALOG_TEXT]); fill_window(msg_win, msg); set_menu_win(menu, win); set_menu_sub(menu, menu_win); set_menu_format(menu, 1, btn_num); menu_opts_off(menu, O_SHOWDESC); menu_opts_off(menu, O_SHOWMATCH); menu_opts_on(menu, O_ONEVALUE); menu_opts_on(menu, O_NONCYCLIC); set_menu_mark(menu, ""); post_menu(menu); touchwin(win); refresh_all_windows(main_window); while ((res = wgetch(win))) { switch (res) { case KEY_LEFT: menu_driver(menu, REQ_LEFT_ITEM); break; case KEY_RIGHT: menu_driver(menu, REQ_RIGHT_ITEM); break; case 10: /* ENTER */ case 27: /* ESCAPE */ case ' ': case KEY_F(F_BACK): case KEY_F(F_EXIT): break; } touchwin(win); refresh_all_windows(main_window); if (res == 10 || res == ' ') { res = item_index(current_item(menu)); break; } else if (res == 27 || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) { res = KEY_EXIT; break; } } unpost_menu(menu); free_menu(menu); for (i = 0; i < btn_num; i++) free_item(btns[i]); delwin(win); return res; } int dialog_inputbox(WINDOW *main_window, const char *title, const char *prompt, const char *init, char **resultp, int *result_len) { int prompt_lines = 0; int prompt_width = 0; WINDOW *win; WINDOW *prompt_win; WINDOW *form_win; PANEL *panel; int i, x, y; int res = -1; int cursor_position = strlen(init); int cursor_form_win; char *result = *resultp; if (strlen(init)+1 > *result_len) { *result_len = strlen(init)+1; *resultp = result = realloc(result, *result_len); } /* find the widest line of msg: */ prompt_lines = get_line_no(prompt); for (i = 0; i < prompt_lines; i++) { const char *line = get_line(prompt, i); int len = get_line_length(line); prompt_width = max(prompt_width, len); } if (title) prompt_width = max(prompt_width, strlen(title)); /* place dialog in middle of screen */ y = (getmaxy(stdscr)-(prompt_lines+4))/2; x = (getmaxx(stdscr)-(prompt_width+4))/2; strncpy(result, init, *result_len); /* create the windows */ win = newwin(prompt_lines+6, prompt_width+7, y, x); prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2); form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2); keypad(form_win, TRUE); (void) wattrset(form_win, attributes[INPUT_FIELD]); (void) wattrset(win, attributes[INPUT_BOX]); box(win, 0, 0); (void) wattrset(win, attributes[INPUT_HEADING]); if (title) mvwprintw(win, 0, 3, "%s", title); /* print message */ (void) wattrset(prompt_win, attributes[INPUT_TEXT]); fill_window(prompt_win, prompt); mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); cursor_form_win = min(cursor_position, prompt_width-1); mvwprintw(form_win, 0, 0, "%s", result + cursor_position-cursor_form_win); /* create panels */ panel = new_panel(win); /* show the cursor */ curs_set(1); touchwin(win); refresh_all_windows(main_window); while ((res = wgetch(form_win))) { int len = strlen(result); switch (res) { case 10: /* ENTER */ case 27: /* ESCAPE */ case KEY_F(F_HELP): case KEY_F(F_EXIT): case KEY_F(F_BACK): break; case 127: case KEY_BACKSPACE: if (cursor_position > 0) { memmove(&result[cursor_position-1], &result[cursor_position], len-cursor_position+1); cursor_position--; cursor_form_win--; len--; } break; case KEY_DC: if (cursor_position >= 0 && cursor_position < len) { memmove(&result[cursor_position], &result[cursor_position+1], len-cursor_position+1); len--; } break; case KEY_UP: case KEY_RIGHT: if (cursor_position < len) { cursor_position++; cursor_form_win++; } break; case KEY_DOWN: case KEY_LEFT: if (cursor_position > 0) { cursor_position--; cursor_form_win--; } break; case KEY_HOME: cursor_position = 0; cursor_form_win = 0; break; case KEY_END: cursor_position = len; cursor_form_win = min(cursor_position, prompt_width-1); break; default: if ((isgraph(res) || isspace(res))) { /* one for new char, one for '\0' */ if (len+2 > *result_len) { *result_len = len+2; *resultp = result = realloc(result, *result_len); } /* insert the char at the proper position */ memmove(&result[cursor_position+1], &result[cursor_position], len-cursor_position+1); result[cursor_position] = res; cursor_position++; cursor_form_win++; len++; } else { mvprintw(0, 0, "unknown key: %d\n", res); } break; } if (cursor_form_win < 0) cursor_form_win = 0; else if (cursor_form_win > prompt_width-1) cursor_form_win = prompt_width-1; wmove(form_win, 0, 0); wclrtoeol(form_win); mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); mvwprintw(form_win, 0, 0, "%s", result + cursor_position-cursor_form_win); wmove(form_win, 0, cursor_form_win); touchwin(win); refresh_all_windows(main_window); if (res == 10) { res = 0; break; } else if (res == 27 || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) { res = KEY_EXIT; break; } else if (res == KEY_F(F_HELP)) { res = 1; break; } } /* hide the cursor */ curs_set(0); del_panel(panel); delwin(prompt_win); delwin(form_win); delwin(win); return res; } /* refresh all windows in the correct order */ void refresh_all_windows(WINDOW *main_window) { update_panels(); touchwin(main_window); refresh(); } /* layman's scrollable window... */ void show_scroll_win(WINDOW *main_window, const char *title, const char *text) { int res; int total_lines = get_line_no(text); int x, y, lines, columns; int start_x = 0, start_y = 0; int text_lines = 0, text_cols = 0; int total_cols = 0; int win_cols = 0; int win_lines = 0; int i = 0; WINDOW *win; WINDOW *pad; PANEL *panel; getmaxyx(stdscr, lines, columns); /* find the widest line of msg: */ total_lines = get_line_no(text); for (i = 0; i < total_lines; i++) { const char *line = get_line(text, i); int len = get_line_length(line); total_cols = max(total_cols, len+2); } /* create the pad */ pad = newpad(total_lines+10, total_cols+10); (void) wattrset(pad, attributes[SCROLLWIN_TEXT]); fill_window(pad, text); win_lines = min(total_lines+4, lines-2); win_cols = min(total_cols+2, columns-2); text_lines = max(win_lines-4, 0); text_cols = max(win_cols-2, 0); /* place window in middle of screen */ y = (lines-win_lines)/2; x = (columns-win_cols)/2; win = newwin(win_lines, win_cols, y, x); keypad(win, TRUE); /* show the help in the help window, and show the help panel */ (void) wattrset(win, attributes[SCROLLWIN_BOX]); box(win, 0, 0); (void) wattrset(win, attributes[SCROLLWIN_HEADING]); mvwprintw(win, 0, 3, " %s ", title); panel = new_panel(win); /* handle scrolling */ do { copywin(pad, win, start_y, start_x, 2, 2, text_lines, text_cols, 0); print_in_middle(win, text_lines+2, 0, text_cols, "", attributes[DIALOG_MENU_FORE]); wrefresh(win); res = wgetch(win); switch (res) { case KEY_NPAGE: case ' ': case 'd': start_y += text_lines-2; break; case KEY_PPAGE: case 'u': start_y -= text_lines+2; break; case KEY_HOME: start_y = 0; break; case KEY_END: start_y = total_lines-text_lines; break; case KEY_DOWN: case 'j': start_y++; break; case KEY_UP: case 'k': start_y--; break; case KEY_LEFT: case 'h': start_x--; break; case KEY_RIGHT: case 'l': start_x++; break; } if (res == 10 || res == 27 || res == 'q' || res == KEY_F(F_HELP) || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) break; if (start_y < 0) start_y = 0; if (start_y >= total_lines-text_lines) start_y = total_lines-text_lines; if (start_x < 0) start_x = 0; if (start_x >= total_cols-text_cols) start_x = total_cols-text_cols; } while (res); del_panel(panel); delwin(win); refresh_all_windows(main_window); } ================================================ FILE: kconfig/nconf.h ================================================ /* * Copyright (C) 2008 Nir Tzachar #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ncurses.h" #define max(a, b) ({\ typeof(a) _a = a;\ typeof(b) _b = b;\ _a > _b ? _a : _b; }) #define min(a, b) ({\ typeof(a) _a = a;\ typeof(b) _b = b;\ _a < _b ? _a : _b; }) typedef enum { NORMAL = 1, MAIN_HEADING, MAIN_MENU_BOX, MAIN_MENU_FORE, MAIN_MENU_BACK, MAIN_MENU_GREY, MAIN_MENU_HEADING, SCROLLWIN_TEXT, SCROLLWIN_HEADING, SCROLLWIN_BOX, DIALOG_TEXT, DIALOG_MENU_FORE, DIALOG_MENU_BACK, DIALOG_BOX, INPUT_BOX, INPUT_HEADING, INPUT_TEXT, INPUT_FIELD, FUNCTION_TEXT, FUNCTION_HIGHLIGHT, ATTR_MAX } attributes_t; extern attributes_t attributes[]; typedef enum { F_HELP = 1, F_SYMBOL = 2, F_INSTS = 3, F_CONF = 4, F_BACK = 5, F_SAVE = 6, F_LOAD = 7, F_SEARCH = 8, F_EXIT = 9, } function_key; void set_colors(void); /* this changes the windows attributes !!! */ void print_in_middle(WINDOW *win, int starty, int startx, int width, const char *string, chtype color); int get_line_length(const char *line); int get_line_no(const char *text); const char *get_line(const char *text, int line_no); void fill_window(WINDOW *win, const char *text); int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...); int dialog_inputbox(WINDOW *main_window, const char *title, const char *prompt, const char *init, char **resultp, int *result_len); void refresh_all_windows(WINDOW *main_window); void show_scroll_win(WINDOW *main_window, const char *title, const char *text); ================================================ FILE: kconfig/qconf.cc ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #if QT_VERSION < 0x040000 #include #include #include #include #include #include #include #include #include #include #else #include #include #include #include #include #include #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lkc.h" #include "qconf.h" #include "qconf.moc" #include "images.c" #ifdef _ # undef _ # define _ qgettext #endif static QApplication *configApp; static ConfigSettings *configSettings; Q3Action *ConfigMainWindow::saveAction; static inline QString qgettext(const char* str) { return QString::fromLocal8Bit(gettext(str)); } static inline QString qgettext(const QString& str) { return QString::fromLocal8Bit(gettext(str.latin1())); } ConfigSettings::ConfigSettings() : QSettings("kernel.org", "qconf") { } /** * Reads a list of integer values from the application settings. */ Q3ValueList ConfigSettings::readSizes(const QString& key, bool *ok) { Q3ValueList result; QStringList entryList = readListEntry(key, ok); QStringList::Iterator it; for (it = entryList.begin(); it != entryList.end(); ++it) result.push_back((*it).toInt()); return result; } /** * Writes a list of integer values to the application settings. */ bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList& value) { QStringList stringList; Q3ValueList::ConstIterator it; for (it = value.begin(); it != value.end(); ++it) stringList.push_back(QString::number(*it)); return writeEntry(key, stringList); } /* * set the new data * TODO check the value */ void ConfigItem::okRename(int col) { Parent::okRename(col); sym_set_string_value(menu->sym, text(dataColIdx).latin1()); listView()->updateList(this); } /* * update the displayed of a menu entry */ void ConfigItem::updateMenu(void) { ConfigList* list; struct symbol* sym; struct property *prop; QString prompt; int type; tristate expr; list = listView(); if (goParent) { setPixmap(promptColIdx, list->menuBackPix); prompt = ".."; goto set_prompt; } sym = menu->sym; prop = menu->prompt; prompt = _(menu_get_prompt(menu)); if (prop) switch (prop->type) { case P_MENU: if (list->mode == singleMode || list->mode == symbolMode) { /* a menuconfig entry is displayed differently * depending whether it's at the view root or a child. */ if (sym && list->rootEntry == menu) break; setPixmap(promptColIdx, list->menuPix); } else { if (sym) break; setPixmap(promptColIdx, 0); } goto set_prompt; case P_COMMENT: setPixmap(promptColIdx, 0); goto set_prompt; default: ; } if (!sym) goto set_prompt; setText(nameColIdx, QString::fromLocal8Bit(sym->name)); type = sym_get_type(sym); switch (type) { case S_BOOLEAN: case S_TRISTATE: char ch; if (!sym_is_changable(sym) && list->optMode == normalOpt) { setPixmap(promptColIdx, 0); setText(noColIdx, QString::null); setText(modColIdx, QString::null); setText(yesColIdx, QString::null); break; } expr = sym_get_tristate_value(sym); switch (expr) { case yes: if (sym_is_choice_value(sym) && type == S_BOOLEAN) setPixmap(promptColIdx, list->choiceYesPix); else setPixmap(promptColIdx, list->symbolYesPix); setText(yesColIdx, "Y"); ch = 'Y'; break; case mod: setPixmap(promptColIdx, list->symbolModPix); setText(modColIdx, "M"); ch = 'M'; break; default: if (sym_is_choice_value(sym) && type == S_BOOLEAN) setPixmap(promptColIdx, list->choiceNoPix); else setPixmap(promptColIdx, list->symbolNoPix); setText(noColIdx, "N"); ch = 'N'; break; } if (expr != no) setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); if (expr != mod) setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); if (expr != yes) setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); setText(dataColIdx, QChar(ch)); break; case S_INT: case S_HEX: case S_STRING: const char* data; data = sym_get_string_value(sym); int i = list->mapIdx(dataColIdx); if (i >= 0) setRenameEnabled(i, TRUE); setText(dataColIdx, data); if (type == S_STRING) prompt = QString("%1: %2").arg(prompt).arg(data); else prompt = QString("(%2) %1").arg(prompt).arg(data); break; } if (!sym_has_value(sym) && visible) prompt += _(" (NEW)"); set_prompt: setText(promptColIdx, prompt); } void ConfigItem::testUpdateMenu(bool v) { ConfigItem* i; visible = v; if (!menu) return; sym_calc_value(menu->sym); if (menu->flags & MENU_CHANGED) { /* the menu entry changed, so update all list items */ menu->flags &= ~MENU_CHANGED; for (i = (ConfigItem*)menu->data; i; i = i->nextItem) i->updateMenu(); } else if (listView()->updateAll) updateMenu(); } void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) { ConfigList* list = listView(); if (visible) { if (isSelected() && !list->hasFocus() && list->mode == menuMode) Parent::paintCell(p, list->inactivedColorGroup, column, width, align); else Parent::paintCell(p, cg, column, width, align); } else Parent::paintCell(p, list->disabledColorGroup, column, width, align); } /* * construct a menu entry */ void ConfigItem::init(void) { if (menu) { ConfigList* list = listView(); nextItem = (ConfigItem*)menu->data; menu->data = this; if (list->mode != fullMode) setOpen(TRUE); sym_calc_value(menu->sym); } updateMenu(); } /* * destruct a menu entry */ ConfigItem::~ConfigItem(void) { if (menu) { ConfigItem** ip = (ConfigItem**)&menu->data; for (; *ip; ip = &(*ip)->nextItem) { if (*ip == this) { *ip = nextItem; break; } } } } ConfigLineEdit::ConfigLineEdit(ConfigView* parent) : Parent(parent) { connect(this, SIGNAL(lostFocus()), SLOT(hide())); } void ConfigLineEdit::show(ConfigItem* i) { item = i; if (sym_get_string_value(item->menu->sym)) setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); else setText(QString::null); Parent::show(); setFocus(); } void ConfigLineEdit::keyPressEvent(QKeyEvent* e) { switch (e->key()) { case Qt::Key_Escape: break; case Qt::Key_Return: case Qt::Key_Enter: sym_set_string_value(item->menu->sym, text().latin1()); parent()->updateList(item); break; default: Parent::keyPressEvent(e); return; } e->accept(); parent()->list->setFocus(); hide(); } ConfigList::ConfigList(ConfigView* p, const char *name) : Parent(p, name), updateAll(false), symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), showName(false), showRange(false), showData(false), optMode(normalOpt), rootEntry(0), headerPopup(0) { int i; setSorting(-1); setRootIsDecorated(TRUE); disabledColorGroup = palette().active(); disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); inactivedColorGroup = palette().active(); inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); connect(this, SIGNAL(selectionChanged(void)), SLOT(updateSelection(void))); if (name) { configSettings->beginGroup(name); showName = configSettings->readBoolEntry("/showName", false); showRange = configSettings->readBoolEntry("/showRange", false); showData = configSettings->readBoolEntry("/showData", false); optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false); configSettings->endGroup(); connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); } for (i = 0; i < colNr; i++) colMap[i] = colRevMap[i] = -1; addColumn(promptColIdx, _("Option")); reinit(); } bool ConfigList::menuSkip(struct menu *menu) { if (optMode == normalOpt && menu_is_visible(menu)) return false; if (optMode == promptOpt && menu_has_prompt(menu)) return false; if (optMode == allOpt) return false; return true; } void ConfigList::reinit(void) { removeColumn(dataColIdx); removeColumn(yesColIdx); removeColumn(modColIdx); removeColumn(noColIdx); removeColumn(nameColIdx); if (showName) addColumn(nameColIdx, _("Name")); if (showRange) { addColumn(noColIdx, "N"); addColumn(modColIdx, "M"); addColumn(yesColIdx, "Y"); } if (showData) addColumn(dataColIdx, _("Value")); updateListAll(); } void ConfigList::saveSettings(void) { if (name()) { configSettings->beginGroup(name()); configSettings->writeEntry("/showName", showName); configSettings->writeEntry("/showRange", showRange); configSettings->writeEntry("/showData", showData); configSettings->writeEntry("/optionMode", (int)optMode); configSettings->endGroup(); } } ConfigItem* ConfigList::findConfigItem(struct menu *menu) { ConfigItem* item = (ConfigItem*)menu->data; for (; item; item = item->nextItem) { if (this == item->listView()) break; } return item; } void ConfigList::updateSelection(void) { struct menu *menu; enum prop_type type; ConfigItem* item = (ConfigItem*)selectedItem(); if (!item) return; menu = item->menu; emit menuChanged(menu); if (!menu) return; type = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (mode == menuMode && type == P_MENU) emit menuSelected(menu); } void ConfigList::updateList(ConfigItem* item) { ConfigItem* last = 0; if (!rootEntry) { if (mode != listMode) goto update; Q3ListViewItemIterator it(this); ConfigItem* item; for (; it.current(); ++it) { item = (ConfigItem*)it.current(); if (!item->menu) continue; item->testUpdateMenu(menu_is_visible(item->menu)); } return; } if (rootEntry != &rootmenu && (mode == singleMode || (mode == symbolMode && rootEntry->parent != &rootmenu))) { item = firstChild(); if (!item) item = new ConfigItem(this, 0, true); last = item; } if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && rootEntry->sym && rootEntry->prompt) { item = last ? last->nextSibling() : firstChild(); if (!item) item = new ConfigItem(this, last, rootEntry, true); else item->testUpdateMenu(true); updateMenuList(item, rootEntry); triggerUpdate(); return; } update: updateMenuList(this, rootEntry); triggerUpdate(); } void ConfigList::setValue(ConfigItem* item, tristate val) { struct symbol* sym; int type; tristate oldval; sym = item->menu ? item->menu->sym : 0; if (!sym) return; type = sym_get_type(sym); switch (type) { case S_BOOLEAN: case S_TRISTATE: oldval = sym_get_tristate_value(sym); if (!sym_set_tristate_value(sym, val)) return; if (oldval == no && item->menu->list) item->setOpen(TRUE); parent()->updateList(item); break; } } void ConfigList::changeValue(ConfigItem* item) { struct symbol* sym; struct menu* menu; int type, oldexpr, newexpr; menu = item->menu; if (!menu) return; sym = menu->sym; if (!sym) { if (item->menu->list) item->setOpen(!item->isOpen()); return; } type = sym_get_type(sym); switch (type) { case S_BOOLEAN: case S_TRISTATE: oldexpr = sym_get_tristate_value(sym); newexpr = sym_toggle_tristate_value(sym); if (item->menu->list) { if (oldexpr == newexpr) item->setOpen(!item->isOpen()); else if (oldexpr == no) item->setOpen(TRUE); } if (oldexpr != newexpr) parent()->updateList(item); break; case S_INT: case S_HEX: case S_STRING: if (colMap[dataColIdx] >= 0) item->startRename(colMap[dataColIdx]); else parent()->lineEdit->show(item); break; } } void ConfigList::setRootMenu(struct menu *menu) { enum prop_type type; if (rootEntry == menu) return; type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; if (type != P_MENU) return; updateMenuList(this, 0); rootEntry = menu; updateListAll(); setSelected(currentItem(), hasFocus()); ensureItemVisible(currentItem()); } void ConfigList::setParentMenu(void) { ConfigItem* item; struct menu *oldroot; oldroot = rootEntry; if (rootEntry == &rootmenu) return; setRootMenu(menu_get_parent_menu(rootEntry->parent)); Q3ListViewItemIterator it(this); for (; (item = (ConfigItem*)it.current()); it++) { if (item->menu == oldroot) { setCurrentItem(item); ensureItemVisible(item); break; } } } /* * update all the children of a menu entry * removes/adds the entries from the parent widget as necessary * * parent: either the menu list widget or a menu entry widget * menu: entry to be updated */ template void ConfigList::updateMenuList(P* parent, struct menu* menu) { struct menu* child; ConfigItem* item; ConfigItem* last; bool visible; enum prop_type type; if (!menu) { while ((item = parent->firstChild())) delete item; return; } last = parent->firstChild(); if (last && !last->goParent) last = 0; for (child = menu->list; child; child = child->next) { item = last ? last->nextSibling() : parent->firstChild(); type = child->prompt ? child->prompt->type : P_UNKNOWN; switch (mode) { case menuMode: if (!(child->flags & MENU_ROOT)) goto hide; break; case symbolMode: if (child->flags & MENU_ROOT) goto hide; break; default: break; } visible = menu_is_visible(child); if (!menuSkip(child)) { if (!child->sym && !child->list && !child->prompt) continue; if (!item || item->menu != child) item = new ConfigItem(parent, last, child, visible); else item->testUpdateMenu(visible); if (mode == fullMode || mode == menuMode || type != P_MENU) updateMenuList(item, child); else updateMenuList(item, 0); last = item; continue; } hide: if (item && item->menu == child) { last = parent->firstChild(); if (last == item) last = 0; else while (last->nextSibling() != item) last = last->nextSibling(); delete item; } } } void ConfigList::keyPressEvent(QKeyEvent* ev) { Q3ListViewItem* i = currentItem(); ConfigItem* item; struct menu *menu; enum prop_type type; if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { emit parentSelected(); ev->accept(); return; } if (!i) { Parent::keyPressEvent(ev); return; } item = (ConfigItem*)i; switch (ev->key()) { case Qt::Key_Return: case Qt::Key_Enter: if (item->goParent) { emit parentSelected(); break; } menu = item->menu; if (!menu) break; type = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (type == P_MENU && rootEntry != menu && mode != fullMode && mode != menuMode) { emit menuSelected(menu); break; } case Qt::Key_Space: changeValue(item); break; case Qt::Key_N: setValue(item, no); break; case Qt::Key_M: setValue(item, mod); break; case Qt::Key_Y: setValue(item, yes); break; default: Parent::keyPressEvent(ev); return; } ev->accept(); } void ConfigList::contentsMousePressEvent(QMouseEvent* e) { //QPoint p(contentsToViewport(e->pos())); //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); Parent::contentsMousePressEvent(e); } void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) { QPoint p(contentsToViewport(e->pos())); ConfigItem* item = (ConfigItem*)itemAt(p); struct menu *menu; enum prop_type ptype; const QPixmap* pm; int idx, x; if (!item) goto skip; menu = item->menu; x = header()->offset() + p.x(); idx = colRevMap[header()->sectionAt(x)]; switch (idx) { case promptColIdx: pm = item->pixmap(promptColIdx); if (pm) { int off = header()->sectionPos(0) + itemMargin() + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); if (x >= off && x < off + pm->width()) { if (item->goParent) { emit parentSelected(); break; } else if (!menu) break; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (ptype == P_MENU && rootEntry != menu && mode != fullMode && mode != menuMode) emit menuSelected(menu); else changeValue(item); } } break; case noColIdx: setValue(item, no); break; case modColIdx: setValue(item, mod); break; case yesColIdx: setValue(item, yes); break; case dataColIdx: changeValue(item); break; } skip: //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); Parent::contentsMouseReleaseEvent(e); } void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) { //QPoint p(contentsToViewport(e->pos())); //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); Parent::contentsMouseMoveEvent(e); } void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) { QPoint p(contentsToViewport(e->pos())); ConfigItem* item = (ConfigItem*)itemAt(p); struct menu *menu; enum prop_type ptype; if (!item) goto skip; if (item->goParent) { emit parentSelected(); goto skip; } menu = item->menu; if (!menu) goto skip; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) emit menuSelected(menu); else if (menu->sym) changeValue(item); skip: //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); Parent::contentsMouseDoubleClickEvent(e); } void ConfigList::focusInEvent(QFocusEvent *e) { struct menu *menu = NULL; Parent::focusInEvent(e); ConfigItem* item = (ConfigItem *)currentItem(); if (item) { setSelected(item, TRUE); menu = item->menu; } emit gotFocus(menu); } void ConfigList::contextMenuEvent(QContextMenuEvent *e) { if (e->y() <= header()->geometry().bottom()) { if (!headerPopup) { Q3Action *action; headerPopup = new Q3PopupMenu(this); action = new Q3Action(NULL, _("Show Name"), 0, this); action->setToggleAction(TRUE); connect(action, SIGNAL(toggled(bool)), parent(), SLOT(setShowName(bool))); connect(parent(), SIGNAL(showNameChanged(bool)), action, SLOT(setOn(bool))); action->setOn(showName); action->addTo(headerPopup); action = new Q3Action(NULL, _("Show Range"), 0, this); action->setToggleAction(TRUE); connect(action, SIGNAL(toggled(bool)), parent(), SLOT(setShowRange(bool))); connect(parent(), SIGNAL(showRangeChanged(bool)), action, SLOT(setOn(bool))); action->setOn(showRange); action->addTo(headerPopup); action = new Q3Action(NULL, _("Show Data"), 0, this); action->setToggleAction(TRUE); connect(action, SIGNAL(toggled(bool)), parent(), SLOT(setShowData(bool))); connect(parent(), SIGNAL(showDataChanged(bool)), action, SLOT(setOn(bool))); action->setOn(showData); action->addTo(headerPopup); } headerPopup->exec(e->globalPos()); e->accept(); } else e->ignore(); } ConfigView*ConfigView::viewList; QAction *ConfigView::showNormalAction; QAction *ConfigView::showAllAction; QAction *ConfigView::showPromptAction; ConfigView::ConfigView(QWidget* parent, const char *name) : Parent(parent, name) { list = new ConfigList(this, name); lineEdit = new ConfigLineEdit(this); lineEdit->hide(); this->nextView = viewList; viewList = this; } ConfigView::~ConfigView(void) { ConfigView** vp; for (vp = &viewList; *vp; vp = &(*vp)->nextView) { if (*vp == this) { *vp = nextView; break; } } } void ConfigView::setOptionMode(QAction *act) { if (act == showNormalAction) list->optMode = normalOpt; else if (act == showAllAction) list->optMode = allOpt; else list->optMode = promptOpt; list->updateListAll(); } void ConfigView::setShowName(bool b) { if (list->showName != b) { list->showName = b; list->reinit(); emit showNameChanged(b); } } void ConfigView::setShowRange(bool b) { if (list->showRange != b) { list->showRange = b; list->reinit(); emit showRangeChanged(b); } } void ConfigView::setShowData(bool b) { if (list->showData != b) { list->showData = b; list->reinit(); emit showDataChanged(b); } } void ConfigList::setAllOpen(bool open) { Q3ListViewItemIterator it(this); for (; it.current(); it++) it.current()->setOpen(open); } void ConfigView::updateList(ConfigItem* item) { ConfigView* v; for (v = viewList; v; v = v->nextView) v->list->updateList(item); } void ConfigView::updateListAll(void) { ConfigView* v; for (v = viewList; v; v = v->nextView) v->list->updateListAll(); } ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) : Parent(parent, name), sym(0), _menu(0) { if (name) { configSettings->beginGroup(name); _showDebug = configSettings->readBoolEntry("/showDebug", false); configSettings->endGroup(); connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); } } void ConfigInfoView::saveSettings(void) { if (name()) { configSettings->beginGroup(name()); configSettings->writeEntry("/showDebug", showDebug()); configSettings->endGroup(); } } void ConfigInfoView::setShowDebug(bool b) { if (_showDebug != b) { _showDebug = b; if (_menu) menuInfo(); else if (sym) symbolInfo(); emit showDebugChanged(b); } } void ConfigInfoView::setInfo(struct menu *m) { if (_menu == m) return; _menu = m; sym = NULL; if (!_menu) clear(); else menuInfo(); } void ConfigInfoView::symbolInfo(void) { QString str; str += "Symbol: "; str += print_filter(sym->name); str += "

value: "; str += print_filter(sym_get_string_value(sym)); str += "
visibility: "; str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; str += "
"; str += debug_info(sym); setText(str); } void ConfigInfoView::menuInfo(void) { struct symbol* sym; QString head, debug, help; sym = _menu->sym; if (sym) { if (_menu->prompt) { head += ""; head += print_filter(_(_menu->prompt->text)); head += ""; if (sym->name) { head += " ("; if (showDebug()) head += QString().sprintf("", sym); head += print_filter(sym->name); if (showDebug()) head += ""; head += ")"; } } else if (sym->name) { head += ""; if (showDebug()) head += QString().sprintf("", sym); head += print_filter(sym->name); if (showDebug()) head += ""; head += ""; } head += "

"; if (showDebug()) debug = debug_info(sym); struct gstr help_gstr = str_new(); menu_get_ext_help(_menu, &help_gstr); help = print_filter(str_get(&help_gstr)); str_free(&help_gstr); } else if (_menu->prompt) { head += ""; head += print_filter(_(_menu->prompt->text)); head += "

"; if (showDebug()) { if (_menu->prompt->visible.expr) { debug += "  dep: "; expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); debug += "

"; } } } if (showDebug()) debug += QString().sprintf("defined at %s:%d

", _menu->file->name, _menu->lineno); setText(head + debug + help); } QString ConfigInfoView::debug_info(struct symbol *sym) { QString debug; debug += "type: "; debug += print_filter(sym_type_name(sym->type)); if (sym_is_choice(sym)) debug += " (choice)"; debug += "
"; if (sym->rev_dep.expr) { debug += "reverse dep: "; expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); debug += "
"; } for (struct property *prop = sym->prop; prop; prop = prop->next) { switch (prop->type) { case P_PROMPT: case P_MENU: debug += QString().sprintf("prompt: ", prop->menu); debug += print_filter(_(prop->text)); debug += "
"; break; case P_DEFAULT: case P_SELECT: case P_RANGE: case P_ENV: debug += prop_get_type_name(prop->type); debug += ": "; expr_print(prop->expr, expr_print_help, &debug, E_NONE); debug += "
"; break; case P_CHOICE: if (sym_is_choice(sym)) { debug += "choice: "; expr_print(prop->expr, expr_print_help, &debug, E_NONE); debug += "
"; } break; default: debug += "unknown property: "; debug += prop_get_type_name(prop->type); debug += "
"; } if (prop->visible.expr) { debug += "    dep: "; expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); debug += "
"; } } debug += "
"; return debug; } QString ConfigInfoView::print_filter(const QString &str) { QRegExp re("[<>&\"\\n]"); QString res = str; for (int i = 0; (i = res.find(re, i)) >= 0;) { switch (res[i].latin1()) { case '<': res.replace(i, 1, "<"); i += 4; break; case '>': res.replace(i, 1, ">"); i += 4; break; case '&': res.replace(i, 1, "&"); i += 5; break; case '"': res.replace(i, 1, """); i += 6; break; case '\n': res.replace(i, 1, "
"); i += 4; break; } } return res; } void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) { QString* text = reinterpret_cast(data); QString str2 = print_filter(str); if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { *text += QString().sprintf("", sym); *text += str2; *text += ""; } else *text += str2; } Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos) { Q3PopupMenu* popup = Parent::createPopupMenu(pos); Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup); action->setToggleAction(TRUE); connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); action->setOn(showDebug()); popup->insertSeparator(); action->addTo(popup); return popup; } void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e) { Parent::contentsContextMenuEvent(e); } ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) : Parent(parent, name), result(NULL) { setCaption("Search Config"); QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6); QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6); layout2->addWidget(new QLabel(_("Find:"), this)); editField = new QLineEdit(this); connect(editField, SIGNAL(returnPressed()), SLOT(search())); layout2->addWidget(editField); searchButton = new QPushButton(_("Search"), this); searchButton->setAutoDefault(FALSE); connect(searchButton, SIGNAL(clicked()), SLOT(search())); layout2->addWidget(searchButton); layout1->addLayout(layout2); split = new QSplitter(this); split->setOrientation(Qt::Vertical); list = new ConfigView(split, name); list->list->mode = listMode; info = new ConfigInfoView(split, name); connect(list->list, SIGNAL(menuChanged(struct menu *)), info, SLOT(setInfo(struct menu *))); connect(list->list, SIGNAL(menuChanged(struct menu *)), parent, SLOT(setMenuLink(struct menu *))); layout1->addWidget(split); if (name) { int x, y, width, height; bool ok; configSettings->beginGroup(name); width = configSettings->readNumEntry("/window width", parent->width() / 2); height = configSettings->readNumEntry("/window height", parent->height() / 2); resize(width, height); x = configSettings->readNumEntry("/window x", 0, &ok); if (ok) y = configSettings->readNumEntry("/window y", 0, &ok); if (ok) move(x, y); Q3ValueList sizes = configSettings->readSizes("/split", &ok); if (ok) split->setSizes(sizes); configSettings->endGroup(); connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); } } void ConfigSearchWindow::saveSettings(void) { if (name()) { configSettings->beginGroup(name()); configSettings->writeEntry("/window x", pos().x()); configSettings->writeEntry("/window y", pos().y()); configSettings->writeEntry("/window width", size().width()); configSettings->writeEntry("/window height", size().height()); configSettings->writeSizes("/split", split->sizes()); configSettings->endGroup(); } } void ConfigSearchWindow::search(void) { struct symbol **p; struct property *prop; ConfigItem *lastItem = NULL; free(result); list->list->clear(); info->clear(); result = sym_re_search(editField->text().latin1()); if (!result) return; for (p = result; *p; p++) { for_all_prompts((*p), prop) lastItem = new ConfigItem(list->list, lastItem, prop->menu, menu_is_visible(prop->menu)); } } /* * Construct the complete config widget */ ConfigMainWindow::ConfigMainWindow(void) : searchWindow(0) { QMenuBar* menu; bool ok; int x, y, width, height; char title[256]; QDesktopWidget *d = configApp->desktop(); snprintf(title, sizeof(title), "%s%s", rootmenu.prompt->text, #if QT_VERSION < 0x040000 " (Qt3)" #else "" #endif ); setCaption(title); width = configSettings->readNumEntry("/window width", d->width() - 64); height = configSettings->readNumEntry("/window height", d->height() - 64); resize(width, height); x = configSettings->readNumEntry("/window x", 0, &ok); if (ok) y = configSettings->readNumEntry("/window y", 0, &ok); if (ok) move(x, y); split1 = new QSplitter(this); split1->setOrientation(Qt::Horizontal); setCentralWidget(split1); menuView = new ConfigView(split1, "menu"); menuList = menuView->list; split2 = new QSplitter(split1); split2->setOrientation(Qt::Vertical); // create config tree configView = new ConfigView(split2, "config"); configList = configView->list; helpText = new ConfigInfoView(split2, "help"); helpText->setTextFormat(Qt::RichText); setTabOrder(configList, helpText); configList->setFocus(); menu = menuBar(); toolBar = new Q3ToolBar("Tools", this); backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this); connect(backAction, SIGNAL(activated()), SLOT(goBack())); backAction->setEnabled(FALSE); Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); connect(quitAction, SIGNAL(activated()), SLOT(close())); Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); conf_set_changed_callback(conf_changed); // Set saveAction's initial state conf_changed(); Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this); connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this); connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this); connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this); showNameAction->setToggleAction(TRUE); connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool))); showNameAction->setOn(configView->showName()); Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this); showRangeAction->setToggleAction(TRUE); connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool))); showRangeAction->setOn(configList->showRange); Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this); showDataAction->setToggleAction(TRUE); connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool))); showDataAction->setOn(configList->showData); QActionGroup *optGroup = new QActionGroup(this); optGroup->setExclusive(TRUE); connect(optGroup, SIGNAL(selected(QAction *)), configView, SLOT(setOptionMode(QAction *))); connect(optGroup, SIGNAL(selected(QAction *)), menuView, SLOT(setOptionMode(QAction *))); #if QT_VERSION >= 0x040000 configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup); configView->showAllAction = new QAction(_("Show All Options"), optGroup); configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup); #else configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup); configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup); configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup); #endif configView->showNormalAction->setToggleAction(TRUE); configView->showNormalAction->setOn(configList->optMode == normalOpt); configView->showAllAction->setToggleAction(TRUE); configView->showAllAction->setOn(configList->optMode == allOpt); configView->showPromptAction->setToggleAction(TRUE); configView->showPromptAction->setOn(configList->optMode == promptOpt); Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this); showDebugAction->setToggleAction(TRUE); connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool))); showDebugAction->setOn(helpText->showDebug()); Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this); connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this); connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); // init tool bar backAction->addTo(toolBar); toolBar->addSeparator(); loadAction->addTo(toolBar); saveAction->addTo(toolBar); toolBar->addSeparator(); singleViewAction->addTo(toolBar); splitViewAction->addTo(toolBar); fullViewAction->addTo(toolBar); // create config menu Q3PopupMenu* config = new Q3PopupMenu(this); menu->insertItem(_("&File"), config); loadAction->addTo(config); saveAction->addTo(config); saveAsAction->addTo(config); config->insertSeparator(); quitAction->addTo(config); // create edit menu Q3PopupMenu* editMenu = new Q3PopupMenu(this); menu->insertItem(_("&Edit"), editMenu); searchAction->addTo(editMenu); // create options menu Q3PopupMenu* optionMenu = new Q3PopupMenu(this); menu->insertItem(_("&Option"), optionMenu); showNameAction->addTo(optionMenu); showRangeAction->addTo(optionMenu); showDataAction->addTo(optionMenu); optionMenu->insertSeparator(); optGroup->addTo(optionMenu); optionMenu->insertSeparator(); // create help menu Q3PopupMenu* helpMenu = new Q3PopupMenu(this); menu->insertSeparator(); menu->insertItem(_("&Help"), helpMenu); showIntroAction->addTo(helpMenu); showAboutAction->addTo(helpMenu); connect(configList, SIGNAL(menuChanged(struct menu *)), helpText, SLOT(setInfo(struct menu *))); connect(configList, SIGNAL(menuSelected(struct menu *)), SLOT(changeMenu(struct menu *))); connect(configList, SIGNAL(parentSelected()), SLOT(goBack())); connect(menuList, SIGNAL(menuChanged(struct menu *)), helpText, SLOT(setInfo(struct menu *))); connect(menuList, SIGNAL(menuSelected(struct menu *)), SLOT(changeMenu(struct menu *))); connect(configList, SIGNAL(gotFocus(struct menu *)), helpText, SLOT(setInfo(struct menu *))); connect(menuList, SIGNAL(gotFocus(struct menu *)), helpText, SLOT(setInfo(struct menu *))); connect(menuList, SIGNAL(gotFocus(struct menu *)), SLOT(listFocusChanged(void))); connect(helpText, SIGNAL(menuSelected(struct menu *)), SLOT(setMenuLink(struct menu *))); QString listMode = configSettings->readEntry("/listMode", "symbol"); if (listMode == "single") showSingleView(); else if (listMode == "full") showFullView(); else /*if (listMode == "split")*/ showSplitView(); // UI setup done, restore splitter positions Q3ValueList sizes = configSettings->readSizes("/split1", &ok); if (ok) split1->setSizes(sizes); sizes = configSettings->readSizes("/split2", &ok); if (ok) split2->setSizes(sizes); } void ConfigMainWindow::loadConfig(void) { QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this); if (s.isNull()) return; if (conf_read(QFile::encodeName(s))) QMessageBox::information(this, "qconf", _("Unable to load configuration!")); ConfigView::updateListAll(); } bool ConfigMainWindow::saveConfig(void) { if (conf_write(NULL)) { QMessageBox::information(this, "qconf", _("Unable to save configuration!")); return false; } return true; } void ConfigMainWindow::saveConfigAs(void) { QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this); if (s.isNull()) return; saveConfig(); } void ConfigMainWindow::searchConfig(void) { if (!searchWindow) searchWindow = new ConfigSearchWindow(this, "search"); searchWindow->show(); } void ConfigMainWindow::changeMenu(struct menu *menu) { configList->setRootMenu(menu); if (configList->rootEntry->parent == &rootmenu) backAction->setEnabled(FALSE); else backAction->setEnabled(TRUE); } void ConfigMainWindow::setMenuLink(struct menu *menu) { struct menu *parent; ConfigList* list = NULL; ConfigItem* item; if (configList->menuSkip(menu)) return; switch (configList->mode) { case singleMode: list = configList; parent = menu_get_parent_menu(menu); if (!parent) return; list->setRootMenu(parent); break; case symbolMode: if (menu->flags & MENU_ROOT) { configList->setRootMenu(menu); configList->clearSelection(); list = menuList; } else { list = configList; parent = menu_get_parent_menu(menu->parent); if (!parent) return; item = menuList->findConfigItem(parent); if (item) { menuList->setSelected(item, TRUE); menuList->ensureItemVisible(item); } list->setRootMenu(parent); } break; case fullMode: list = configList; break; default: break; } if (list) { item = list->findConfigItem(menu); if (item) { list->setSelected(item, TRUE); list->ensureItemVisible(item); list->setFocus(); } } } void ConfigMainWindow::listFocusChanged(void) { if (menuList->mode == menuMode) configList->clearSelection(); } void ConfigMainWindow::goBack(void) { ConfigItem* item; configList->setParentMenu(); if (configList->rootEntry == &rootmenu) backAction->setEnabled(FALSE); item = (ConfigItem*)menuList->selectedItem(); while (item) { if (item->menu == configList->rootEntry) { menuList->setSelected(item, TRUE); break; } item = (ConfigItem*)item->parent(); } } void ConfigMainWindow::showSingleView(void) { menuView->hide(); menuList->setRootMenu(0); configList->mode = singleMode; if (configList->rootEntry == &rootmenu) configList->updateListAll(); else configList->setRootMenu(&rootmenu); configList->setAllOpen(TRUE); configList->setFocus(); } void ConfigMainWindow::showSplitView(void) { configList->mode = symbolMode; if (configList->rootEntry == &rootmenu) configList->updateListAll(); else configList->setRootMenu(&rootmenu); configList->setAllOpen(TRUE); configApp->processEvents(); menuList->mode = menuMode; menuList->setRootMenu(&rootmenu); menuList->setAllOpen(TRUE); menuView->show(); menuList->setFocus(); } void ConfigMainWindow::showFullView(void) { menuView->hide(); menuList->setRootMenu(0); configList->mode = fullMode; if (configList->rootEntry == &rootmenu) configList->updateListAll(); else configList->setRootMenu(&rootmenu); configList->setAllOpen(FALSE); configList->setFocus(); } /* * ask for saving configuration before quitting * TODO ask only when something changed */ void ConfigMainWindow::closeEvent(QCloseEvent* e) { if (!conf_get_changed()) { e->accept(); return; } QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); mb.setButtonText(QMessageBox::No, _("&Discard Changes")); mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); switch (mb.exec()) { case QMessageBox::Yes: if (saveConfig()) e->accept(); else e->ignore(); break; case QMessageBox::No: e->accept(); break; case QMessageBox::Cancel: e->ignore(); break; } } void ConfigMainWindow::showIntro(void) { static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n" "For each option, a blank box indicates the feature is disabled, a check\n" "indicates it is enabled, and a dot indicates that it is to be compiled\n" "as a module. Clicking on the box will cycle through the three states.\n\n" "If you do not see an option (e.g., a device driver) that you believe\n" "should be present, try turning on Show All Options under the Options menu.\n" "Although there is no cross reference yet to help you figure out what other\n" "options must be enabled to support the option you are interested in, you can\n" "still view the help of a grayed-out option.\n\n" "Toggling Show Debug Info under the Options menu will show the dependencies,\n" "which you can then match by examining other options.\n\n"); QMessageBox::information(this, "qconf", str); } void ConfigMainWindow::showAbout(void) { static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel .\n\n" "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); QMessageBox::information(this, "qconf", str); } void ConfigMainWindow::saveSettings(void) { configSettings->writeEntry("/window x", pos().x()); configSettings->writeEntry("/window y", pos().y()); configSettings->writeEntry("/window width", size().width()); configSettings->writeEntry("/window height", size().height()); QString entry; switch(configList->mode) { case singleMode : entry = "single"; break; case symbolMode : entry = "split"; break; case fullMode : entry = "full"; break; default: break; } configSettings->writeEntry("/listMode", entry); configSettings->writeSizes("/split1", split1->sizes()); configSettings->writeSizes("/split2", split2->sizes()); } void ConfigMainWindow::conf_changed(void) { if (saveAction) saveAction->setEnabled(conf_get_changed()); } void fixup_rootmenu(struct menu *menu) { struct menu *child; static int menu_cnt = 0; menu->flags |= MENU_ROOT; for (child = menu->list; child; child = child->next) { if (child->prompt && child->prompt->type == P_MENU) { menu_cnt++; fixup_rootmenu(child); menu_cnt--; } else if (!menu_cnt) fixup_rootmenu(child); } } static const char *progname; static void usage(void) { printf(_("%s \n"), progname); exit(0); } int main(int ac, char** av) { ConfigMainWindow* v; const char *name; bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); progname = av[0]; configApp = new QApplication(ac, av); if (ac > 1 && av[1][0] == '-') { switch (av[1][1]) { case 'h': case '?': usage(); } name = av[2]; } else name = av[1]; if (!name) usage(); conf_parse(name); fixup_rootmenu(&rootmenu); conf_read(NULL); //zconfdump(stdout); configSettings = new ConfigSettings(); configSettings->beginGroup("/kconfig/qconf"); v = new ConfigMainWindow(); //zconfdump(stdout); configApp->setMainWidget(v); configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); v->show(); configApp->exec(); configSettings->endGroup(); delete configSettings; return 0; } ================================================ FILE: kconfig/qconf.h ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #if QT_VERSION < 0x040000 #include #else #include #endif #include #if QT_VERSION < 0x040000 #define Q3ValueList QValueList #define Q3PopupMenu QPopupMenu #define Q3ListView QListView #define Q3ListViewItem QListViewItem #define Q3VBox QVBox #define Q3TextBrowser QTextBrowser #define Q3MainWindow QMainWindow #define Q3Action QAction #define Q3ToolBar QToolBar #define Q3ListViewItemIterator QListViewItemIterator #define Q3FileDialog QFileDialog #endif class ConfigView; class ConfigList; class ConfigItem; class ConfigLineEdit; class ConfigMainWindow; class ConfigSettings : public QSettings { public: ConfigSettings(); Q3ValueList readSizes(const QString& key, bool *ok); bool writeSizes(const QString& key, const Q3ValueList& value); }; enum colIdx { promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr }; enum listMode { singleMode, menuMode, symbolMode, fullMode, listMode }; enum optionMode { normalOpt = 0, allOpt, promptOpt }; class ConfigList : public Q3ListView { Q_OBJECT typedef class Q3ListView Parent; public: ConfigList(ConfigView* p, const char *name = 0); void reinit(void); ConfigView* parent(void) const { return (ConfigView*)Parent::parent(); } ConfigItem* findConfigItem(struct menu *); protected: void keyPressEvent(QKeyEvent *e); void contentsMousePressEvent(QMouseEvent *e); void contentsMouseReleaseEvent(QMouseEvent *e); void contentsMouseMoveEvent(QMouseEvent *e); void contentsMouseDoubleClickEvent(QMouseEvent *e); void focusInEvent(QFocusEvent *e); void contextMenuEvent(QContextMenuEvent *e); public slots: void setRootMenu(struct menu *menu); void updateList(ConfigItem *item); void setValue(ConfigItem* item, tristate val); void changeValue(ConfigItem* item); void updateSelection(void); void saveSettings(void); signals: void menuChanged(struct menu *menu); void menuSelected(struct menu *menu); void parentSelected(void); void gotFocus(struct menu *); public: void updateListAll(void) { updateAll = true; updateList(NULL); updateAll = false; } ConfigList* listView() { return this; } ConfigItem* firstChild() const { return (ConfigItem *)Parent::firstChild(); } int mapIdx(colIdx idx) { return colMap[idx]; } void addColumn(colIdx idx, const QString& label) { colMap[idx] = Parent::addColumn(label); colRevMap[colMap[idx]] = idx; } void removeColumn(colIdx idx) { int col = colMap[idx]; if (col >= 0) { Parent::removeColumn(col); colRevMap[col] = colMap[idx] = -1; } } void setAllOpen(bool open); void setParentMenu(void); bool menuSkip(struct menu *); template void updateMenuList(P*, struct menu*); bool updateAll; QPixmap symbolYesPix, symbolModPix, symbolNoPix; QPixmap choiceYesPix, choiceNoPix; QPixmap menuPix, menuInvPix, menuBackPix, voidPix; bool showName, showRange, showData; enum listMode mode; enum optionMode optMode; struct menu *rootEntry; QColorGroup disabledColorGroup; QColorGroup inactivedColorGroup; Q3PopupMenu* headerPopup; private: int colMap[colNr]; int colRevMap[colNr]; }; class ConfigItem : public Q3ListViewItem { typedef class Q3ListViewItem Parent; public: ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v) : Parent(parent, after), menu(m), visible(v), goParent(false) { init(); } ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) : Parent(parent, after), menu(m), visible(v), goParent(false) { init(); } ConfigItem(Q3ListView *parent, ConfigItem *after, bool v) : Parent(parent, after), menu(0), visible(v), goParent(true) { init(); } ~ConfigItem(void); void init(void); void okRename(int col); void updateMenu(void); void testUpdateMenu(bool v); ConfigList* listView() const { return (ConfigList*)Parent::listView(); } ConfigItem* firstChild() const { return (ConfigItem *)Parent::firstChild(); } ConfigItem* nextSibling() const { return (ConfigItem *)Parent::nextSibling(); } void setText(colIdx idx, const QString& text) { Parent::setText(listView()->mapIdx(idx), text); } QString text(colIdx idx) const { return Parent::text(listView()->mapIdx(idx)); } void setPixmap(colIdx idx, const QPixmap& pm) { Parent::setPixmap(listView()->mapIdx(idx), pm); } const QPixmap* pixmap(colIdx idx) const { return Parent::pixmap(listView()->mapIdx(idx)); } void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align); ConfigItem* nextItem; struct menu *menu; bool visible; bool goParent; }; class ConfigLineEdit : public QLineEdit { Q_OBJECT typedef class QLineEdit Parent; public: ConfigLineEdit(ConfigView* parent); ConfigView* parent(void) const { return (ConfigView*)Parent::parent(); } void show(ConfigItem *i); void keyPressEvent(QKeyEvent *e); public: ConfigItem *item; }; class ConfigView : public Q3VBox { Q_OBJECT typedef class Q3VBox Parent; public: ConfigView(QWidget* parent, const char *name = 0); ~ConfigView(void); static void updateList(ConfigItem* item); static void updateListAll(void); bool showName(void) const { return list->showName; } bool showRange(void) const { return list->showRange; } bool showData(void) const { return list->showData; } public slots: void setShowName(bool); void setShowRange(bool); void setShowData(bool); void setOptionMode(QAction *); signals: void showNameChanged(bool); void showRangeChanged(bool); void showDataChanged(bool); public: ConfigList* list; ConfigLineEdit* lineEdit; static ConfigView* viewList; ConfigView* nextView; static QAction *showNormalAction; static QAction *showAllAction; static QAction *showPromptAction; }; class ConfigInfoView : public Q3TextBrowser { Q_OBJECT typedef class Q3TextBrowser Parent; public: ConfigInfoView(QWidget* parent, const char *name = 0); bool showDebug(void) const { return _showDebug; } public slots: void setInfo(struct menu *menu); void saveSettings(void); void setShowDebug(bool); signals: void showDebugChanged(bool); void menuSelected(struct menu *); protected: void symbolInfo(void); void menuInfo(void); QString debug_info(struct symbol *sym); static QString print_filter(const QString &str); static void expr_print_help(void *data, struct symbol *sym, const char *str); Q3PopupMenu* createPopupMenu(const QPoint& pos); void contentsContextMenuEvent(QContextMenuEvent *e); struct symbol *sym; struct menu *_menu; bool _showDebug; }; class ConfigSearchWindow : public QDialog { Q_OBJECT typedef class QDialog Parent; public: ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0); public slots: void saveSettings(void); void search(void); protected: QLineEdit* editField; QPushButton* searchButton; QSplitter* split; ConfigView* list; ConfigInfoView* info; struct symbol **result; }; class ConfigMainWindow : public Q3MainWindow { Q_OBJECT static Q3Action *saveAction; static void conf_changed(void); public: ConfigMainWindow(void); public slots: void changeMenu(struct menu *); void setMenuLink(struct menu *); void listFocusChanged(void); void goBack(void); void loadConfig(void); bool saveConfig(void); void saveConfigAs(void); void searchConfig(void); void showSingleView(void); void showSplitView(void); void showFullView(void); void showIntro(void); void showAbout(void); void saveSettings(void); protected: void closeEvent(QCloseEvent *e); ConfigSearchWindow *searchWindow; ConfigView *menuView; ConfigList *menuList; ConfigView *configView; ConfigList *configList; ConfigInfoView *helpText; Q3ToolBar *toolBar; Q3Action *backAction; QSplitter* split1; QSplitter* split2; }; ================================================ FILE: kconfig/qemu2.cfg ================================================ # # Automatically generated file; DO NOT EDIT. # FROSTED Kernel Configuration # # # Platform Selection # ARCH_LM3S=y # ARCH_LPC17XX is not set # ARCH_STM32F4 is not set # ARCH_LPC1763 is not set # ARCH_LPC1764 is not set # ARCH_LPC1765 is not set # ARCH_LPC1766 is not set # ARCH_LPC1767 is not set # ARCH_LPC1768 is not set # ARCH_LPC1769 is not set ARCH_LM3S6965=y FLASH_SIZE_256KB=y RAM_SIZE_64KB=y # CLK_100MHZ is not set # MACH_LPC1768MBED is not set # MACH_SEEEDPRO is not set MACH_LM3S6965EVB=y # # Kernel Configuration # KFLASHMEM_SIZE=48 KRAMMEM_SIZE=6 # # Subsystems # # # Filesystems # SYSFS=y MEMFS=y XIPFS=y # # Sockets # SOCK_UNIX=y # # Devices # DEVNULL=y DEVUART=y USART_0=y # USART_1 is not set # USART_2 is not set # # Applications # FRESH=y # TASK2 is not set # PRODCONS is not set ================================================ FILE: kconfig/streamline_config.pl ================================================ #!/usr/bin/perl -w # # Copyright 2005-2009 - Steven Rostedt # Licensed under the terms of the GNU GPL License version 2 # # It's simple enough to figure out how this works. # If not, then you can ask me at stripconfig@goodmis.org # # What it does? # # If you have installed a Linux kernel from a distribution # that turns on way too many modules than you need, and # you only want the modules you use, then this program # is perfect for you. # # It gives you the ability to turn off all the modules that are # not loaded on your system. # # Howto: # # 1. Boot up the kernel that you want to stream line the config on. # 2. Change directory to the directory holding the source of the # kernel that you just booted. # 3. Copy the configuraton file to this directory as .config # 4. Have all your devices that you need modules for connected and # operational (make sure that their corresponding modules are loaded) # 5. Run this script redirecting the output to some other file # like config_strip. # 6. Back up your old config (if you want too). # 7. copy the config_strip file to .config # 8. Run "make oldconfig" # # Now your kernel is ready to be built with only the modules that # are loaded. # # Here's what I did with my Debian distribution. # # cd /usr/src/linux-2.6.10 # cp /boot/config-2.6.10-1-686-smp .config # ~/bin/streamline_config > config_strip # mv .config config_sav # mv config_strip .config # make oldconfig # use strict; use Getopt::Long; # set the environment variable LOCALMODCONFIG_DEBUG to get # debug output. my $debugprint = 0; $debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG})); sub dprint { return if (!$debugprint); print STDERR @_; } my $config = ".config"; my $uname = `uname -r`; chomp $uname; my @searchconfigs = ( { "file" => ".config", "exec" => "cat", }, { "file" => "/proc/config.gz", "exec" => "zcat", }, { "file" => "/boot/config-$uname", "exec" => "cat", }, { "file" => "/boot/vmlinuz-$uname", "exec" => "scripts/extract-ikconfig", "test" => "scripts/extract-ikconfig", }, { "file" => "vmlinux", "exec" => "scripts/extract-ikconfig", "test" => "scripts/extract-ikconfig", }, { "file" => "/lib/modules/$uname/kernel/kernel/configs.ko", "exec" => "scripts/extract-ikconfig", "test" => "scripts/extract-ikconfig", }, { "file" => "kernel/configs.ko", "exec" => "scripts/extract-ikconfig", "test" => "scripts/extract-ikconfig", }, { "file" => "kernel/configs.o", "exec" => "scripts/extract-ikconfig", "test" => "scripts/extract-ikconfig", }, ); sub read_config { foreach my $conf (@searchconfigs) { my $file = $conf->{"file"}; next if ( ! -f "$file"); if (defined($conf->{"test"})) { `$conf->{"test"} $conf->{"file"} 2>/dev/null`; next if ($?); } my $exec = $conf->{"exec"}; print STDERR "using config: '$file'\n"; open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file"; my @x = <$infile>; close $infile; return @x; } die "No config file found"; } my @config_file = read_config; # Parse options my $localmodconfig = 0; my $localyesconfig = 0; GetOptions("localmodconfig" => \$localmodconfig, "localyesconfig" => \$localyesconfig); # Get the build source and top level Kconfig file (passed in) my $ksource = ($ARGV[0] ? $ARGV[0] : '.'); my $kconfig = $ARGV[1]; my $lsmod_file = $ENV{'LSMOD'}; my @makefiles = `find $ksource -name Makefile 2>/dev/null`; chomp @makefiles; my %depends; my %selects; my %prompts; my %objects; my $var; my $iflevel = 0; my @ifdeps; # prevent recursion my %read_kconfigs; sub read_kconfig { my ($kconfig) = @_; my $state = "NONE"; my $config; my $cont = 0; my $line; my $source = "$ksource/$kconfig"; my $last_source = ""; # Check for any environment variables used while ($source =~ /\$(\w+)/ && $last_source ne $source) { my $env = $1; $last_source = $source; $source =~ s/\$$env/$ENV{$env}/; } open(my $kinfile, '<', $source) || die "Can't open $kconfig"; while (<$kinfile>) { chomp; # Make sure that lines ending with \ continue if ($cont) { $_ = $line . " " . $_; } if (s/\\$//) { $cont = 1; $line = $_; next; } $cont = 0; # collect any Kconfig sources if (/^source\s*"(.*)"/) { my $kconfig = $1; # prevent reading twice. if (!defined($read_kconfigs{$kconfig})) { $read_kconfigs{$kconfig} = 1; read_kconfig($kconfig); } next; } # configs found if (/^\s*(menu)?config\s+(\S+)\s*$/) { $state = "NEW"; $config = $2; # Add depends for 'if' nesting for (my $i = 0; $i < $iflevel; $i++) { if ($i) { $depends{$config} .= " " . $ifdeps[$i]; } else { $depends{$config} = $ifdeps[$i]; } $state = "DEP"; } # collect the depends for the config } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { $state = "DEP"; $depends{$config} = $1; } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) { $depends{$config} .= " " . $1; } elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) { my $dep = $3; if ($dep !~ /^\s*(y|m|n)\s*$/) { $dep =~ s/.*\sif\s+//; $depends{$config} .= " " . $dep; dprint "Added default depends $dep to $config\n"; } # Get the configs that select this config } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) { my $conf = $1; if (defined($selects{$conf})) { $selects{$conf} .= " " . $config; } else { $selects{$conf} = $config; } # configs without prompts must be selected } elsif ($state ne "NONE" && /^\s*tristate\s\S/) { # note if the config has a prompt $prompts{$config} = 1; # Check for if statements } elsif (/^if\s+(.*\S)\s*$/) { my $deps = $1; # remove beginning and ending non text $deps =~ s/^[^a-zA-Z0-9_]*//; $deps =~ s/[^a-zA-Z0-9_]*$//; my @deps = split /[^a-zA-Z0-9_]+/, $deps; $ifdeps[$iflevel++] = join ':', @deps; } elsif (/^endif/) { $iflevel-- if ($iflevel); # stop on "help" } elsif (/^\s*help\s*$/) { $state = "NONE"; } } close($kinfile); } if ($kconfig) { read_kconfig($kconfig); } # Makefiles can use variables to define their dependencies sub convert_vars { my ($line, %vars) = @_; my $process = ""; while ($line =~ s/^(.*?)(\$\((.*?)\))//) { my $start = $1; my $variable = $2; my $var = $3; if (defined($vars{$var})) { $process .= $start . $vars{$var}; } else { $process .= $start . $variable; } } $process .= $line; return $process; } # Read all Makefiles to map the configs to the objects foreach my $makefile (@makefiles) { my $line = ""; my %make_vars; open(my $infile, '<', $makefile) || die "Can't open $makefile"; while (<$infile>) { # if this line ends with a backslash, continue chomp; if (/^(.*)\\$/) { $line .= $1; next; } $line .= $_; $_ = $line; $line = ""; my $objs; # Convert variables in a line (could define configs) $_ = convert_vars($_, %make_vars); # collect objects after obj-$(CONFIG_FOO_BAR) if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) { $var = $1; $objs = $2; # check if variables are set } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) { $make_vars{$1} = $2; } if (defined($objs)) { foreach my $obj (split /\s+/,$objs) { $obj =~ s/-/_/g; if ($obj =~ /(.*)\.o$/) { # Objects may be enabled by more than one config. # Store configs in an array. my @arr; if (defined($objects{$1})) { @arr = @{$objects{$1}}; } $arr[$#arr+1] = $var; # The objects have a hash mapping to a reference # of an array of configs. $objects{$1} = \@arr; } } } } close($infile); } my %modules; my $linfile; if (defined($lsmod_file)) { if ( ! -f $lsmod_file) { if ( -f $ENV{'objtree'}."/".$lsmod_file) { $lsmod_file = $ENV{'objtree'}."/".$lsmod_file; } else { die "$lsmod_file not found"; } } my $otype = ( -x $lsmod_file) ? '-|' : '<'; open($linfile, $otype, $lsmod_file); } else { # see what modules are loaded on this system my $lsmod; foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) { if ( -x "$dir/lsmod" ) { $lsmod = "$dir/lsmod"; last; } } if (!defined($lsmod)) { # try just the path $lsmod = "lsmod"; } open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod"; } while (<$linfile>) { next if (/^Module/); # Skip the first line. if (/^(\S+)/) { $modules{$1} = 1; } } close ($linfile); # add to the configs hash all configs that are needed to enable # a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o # where we know we need bar.o so we add FOO to the list. my %configs; foreach my $module (keys(%modules)) { if (defined($objects{$module})) { my @arr = @{$objects{$module}}; foreach my $conf (@arr) { $configs{$conf} = $module; dprint "$conf added by direct ($module)\n"; if ($debugprint) { my $c=$conf; $c =~ s/^CONFIG_//; if (defined($depends{$c})) { dprint " deps = $depends{$c}\n"; } else { dprint " no deps\n"; } } } } else { # Most likely, someone has a custom (binary?) module loaded. print STDERR "$module config not found!!\n"; } } # Read the current config, and see what is enabled. We want to # ignore configs that we would not enable anyway. my %orig_configs; my $valid = "A-Za-z_0-9"; foreach my $line (@config_file) { $_ = $line; if (/(CONFIG_[$valid]*)=(m|y)/) { $orig_configs{$1} = $2; } } my $repeat = 1; my $depconfig; # # Note, we do not care about operands (like: &&, ||, !) we want to add any # config that is in the depend list of another config. This script does # not enable configs that are not already enabled. If we come across a # config A that depends on !B, we can still add B to the list of depends # to keep on. If A was on in the original config, B would not have been # and B would not be turned on by this script. # sub parse_config_depends { my ($p) = @_; while ($p =~ /[$valid]/) { if ($p =~ /^[^$valid]*([$valid]+)/) { my $conf = "CONFIG_" . $1; $p =~ s/^[^$valid]*[$valid]+//; # We only need to process if the depend config is a module if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") { next; } if (!defined($configs{$conf})) { # We must make sure that this config has its # dependencies met. $repeat = 1; # do again dprint "$conf selected by depend $depconfig\n"; $configs{$conf} = 1; } } else { die "this should never happen"; } } } # Select is treated a bit differently than depends. We call this # when a config has no prompt and requires another config to be # selected. We use to just select all configs that selected this # config, but found that that can balloon into enabling hundreds # of configs that we do not care about. # # The idea is we look at all the configs that select it. If one # is already in our list of configs to enable, then there's nothing # else to do. If there isn't, we pick the first config that was # enabled in the orignal config and use that. sub parse_config_selects { my ($config, $p) = @_; my $next_config; while ($p =~ /[$valid]/) { if ($p =~ /^[^$valid]*([$valid]+)/) { my $conf = "CONFIG_" . $1; $p =~ s/^[^$valid]*[$valid]+//; # Make sure that this config exists in the current .config file if (!defined($orig_configs{$conf})) { dprint "$conf not set for $config select\n"; next; } # Check if something other than a module selects this config if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") { dprint "$conf (non module) selects config, we are good\n"; # we are good with this return; } if (defined($configs{$conf})) { dprint "$conf selects $config so we are good\n"; # A set config selects this config, we are good return; } # Set this config to be selected if (!defined($next_config)) { $next_config = $conf; } } else { die "this should never happen"; } } # If no possible config selected this, then something happened. if (!defined($next_config)) { print STDERR "WARNING: $config is required, but nothing in the\n"; print STDERR " current config selects it.\n"; return; } # If we are here, then we found no config that is set and # selects this config. Repeat. $repeat = 1; # Make this config need to be selected $configs{$next_config} = 1; dprint "$next_config selected by select $config\n"; } my %process_selects; # loop through all configs, select their dependencies. sub loop_depend { $repeat = 1; while ($repeat) { $repeat = 0; forloop: foreach my $config (keys %configs) { # If this config is not a module, we do not need to process it if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") { next forloop; } $config =~ s/^CONFIG_//; $depconfig = $config; if (defined($depends{$config})) { # This config has dependencies. Make sure they are also included parse_config_depends $depends{$config}; } # If the config has no prompt, then we need to check if a config # that is enabled selected it. Or if we need to enable one. if (!defined($prompts{$config}) && defined($selects{$config})) { $process_selects{$config} = 1; } } } } sub loop_select { foreach my $config (keys %process_selects) { $config =~ s/^CONFIG_//; dprint "Process select $config\n"; # config has no prompt and must be selected. parse_config_selects $config, $selects{$config}; } } while ($repeat) { # Get the first set of configs and their dependencies. loop_depend; $repeat = 0; # Now we need to see if we have to check selects; loop_select; } my %setconfigs; # Finally, read the .config file and turn off any module enabled that # we could not find a reason to keep enabled. foreach my $line (@config_file) { $_ = $line; if (/CONFIG_IKCONFIG/) { if (/# CONFIG_IKCONFIG is not set/) { # enable IKCONFIG at least as a module print "CONFIG_IKCONFIG=m\n"; # don't ask about PROC print "# CONFIG_IKCONFIG_PROC is not set\n"; } else { print; } next; } if (/^(CONFIG.*)=(m|y)/) { if (defined($configs{$1})) { if ($localyesconfig) { $setconfigs{$1} = 'y'; print "$1=y\n"; next; } else { $setconfigs{$1} = $2; } } elsif ($2 eq "m") { print "# $1 is not set\n"; next; } } print; } # Integrity check, make sure all modules that we want enabled do # indeed have their configs set. loop: foreach my $module (keys(%modules)) { if (defined($objects{$module})) { my @arr = @{$objects{$module}}; foreach my $conf (@arr) { if (defined($setconfigs{$conf})) { next loop; } } print STDERR "module $module did not have configs"; foreach my $conf (@arr) { print STDERR " " , $conf; } print STDERR "\n"; } } ================================================ FILE: kconfig/symbol.c ================================================ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include #include "lkc.h" struct symbol symbol_yes = { .name = "y", .curr = { "y", yes }, .flags = SYMBOL_CONST|SYMBOL_VALID, }, symbol_mod = { .name = "m", .curr = { "m", mod }, .flags = SYMBOL_CONST|SYMBOL_VALID, }, symbol_no = { .name = "n", .curr = { "n", no }, .flags = SYMBOL_CONST|SYMBOL_VALID, }, symbol_empty = { .name = "", .curr = { "", no }, .flags = SYMBOL_VALID, }; struct symbol *sym_defconfig_list; struct symbol *modules_sym; tristate modules_val; struct expr *sym_env_list; static void sym_add_default(struct symbol *sym, const char *def) { struct property *prop = prop_alloc(P_DEFAULT, sym); prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); } void sym_init(void) { struct symbol *sym; struct utsname uts; static bool inited = false; if (inited) return; inited = true; uname(&uts); sym = sym_lookup("UNAME_RELEASE", 0); sym->type = S_STRING; sym->flags |= SYMBOL_AUTO; sym_add_default(sym, uts.release); } enum symbol_type sym_get_type(struct symbol *sym) { enum symbol_type type = sym->type; if (type == S_TRISTATE) { if (sym_is_choice_value(sym) && sym->visible == yes) type = S_BOOLEAN; else if (modules_val == no) type = S_BOOLEAN; } return type; } const char *sym_type_name(enum symbol_type type) { switch (type) { case S_BOOLEAN: return "boolean"; case S_TRISTATE: return "tristate"; case S_INT: return "integer"; case S_HEX: return "hex"; case S_STRING: return "string"; case S_UNKNOWN: return "unknown"; case S_OTHER: break; } return "???"; } struct property *sym_get_choice_prop(struct symbol *sym) { struct property *prop; for_all_choices(sym, prop) return prop; return NULL; } struct property *sym_get_env_prop(struct symbol *sym) { struct property *prop; for_all_properties(sym, prop, P_ENV) return prop; return NULL; } struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; for_all_defaults(sym, prop) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri != no) return prop; } return NULL; } static struct property *sym_get_range_prop(struct symbol *sym) { struct property *prop; for_all_properties(sym, prop, P_RANGE) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri != no) return prop; } return NULL; } static long long sym_get_range_val(struct symbol *sym, int base) { sym_calc_value(sym); switch (sym->type) { case S_INT: base = 10; break; case S_HEX: base = 16; break; default: break; } return strtoll(sym->curr.val, NULL, base); } static void sym_validate_range(struct symbol *sym) { struct property *prop; int base; long long val, val2; char str[64]; switch (sym->type) { case S_INT: base = 10; break; case S_HEX: base = 16; break; default: return; } prop = sym_get_range_prop(sym); if (!prop) return; val = strtoll(sym->curr.val, NULL, base); val2 = sym_get_range_val(prop->expr->left.sym, base); if (val >= val2) { val2 = sym_get_range_val(prop->expr->right.sym, base); if (val <= val2) return; } if (sym->type == S_INT) sprintf(str, "%lld", val2); else sprintf(str, "0x%llx", val2); sym->curr.val = strdup(str); } static void sym_calc_visibility(struct symbol *sym) { struct property *prop; tristate tri; /* any prompt visible? */ tri = no; for_all_prompts(sym, prop) { prop->visible.tri = expr_calc_value(prop->visible.expr); tri = EXPR_OR(tri, prop->visible.tri); } if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) tri = yes; if (sym->visible != tri) { sym->visible = tri; sym_set_changed(sym); } if (sym_is_choice_value(sym)) return; /* defaulting to "yes" if no explicit "depends on" are given */ tri = yes; if (sym->dir_dep.expr) tri = expr_calc_value(sym->dir_dep.expr); if (tri == mod) tri = yes; if (sym->dir_dep.tri != tri) { sym->dir_dep.tri = tri; sym_set_changed(sym); } tri = no; if (sym->rev_dep.expr) tri = expr_calc_value(sym->rev_dep.expr); if (tri == mod && sym_get_type(sym) == S_BOOLEAN) tri = yes; if (sym->rev_dep.tri != tri) { sym->rev_dep.tri = tri; sym_set_changed(sym); } } /* * Find the default symbol for a choice. * First try the default values for the choice symbol * Next locate the first visible choice value * Return NULL if none was found */ struct symbol *sym_choice_default(struct symbol *sym) { struct symbol *def_sym; struct property *prop; struct expr *e; /* any of the defaults visible? */ for_all_defaults(sym, prop) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri == no) continue; def_sym = prop_get_symbol(prop); if (def_sym->visible != no) return def_sym; } /* just get the first visible value */ prop = sym_get_choice_prop(sym); expr_list_for_each_sym(prop->expr, e, def_sym) if (def_sym->visible != no) return def_sym; /* failed to locate any defaults */ return NULL; } static struct symbol *sym_calc_choice(struct symbol *sym) { struct symbol *def_sym; struct property *prop; struct expr *e; int flags; /* first calculate all choice values' visibilities */ flags = sym->flags; prop = sym_get_choice_prop(sym); expr_list_for_each_sym(prop->expr, e, def_sym) { sym_calc_visibility(def_sym); if (def_sym->visible != no) flags &= def_sym->flags; } sym->flags &= flags | ~SYMBOL_DEF_USER; /* is the user choice visible? */ def_sym = sym->def[S_DEF_USER].val; if (def_sym && def_sym->visible != no) return def_sym; def_sym = sym_choice_default(sym); if (def_sym == NULL) /* no choice? reset tristate value */ sym->curr.tri = no; return def_sym; } void sym_calc_value(struct symbol *sym) { struct symbol_value newval, oldval; struct property *prop; struct expr *e; if (!sym) return; if (sym->flags & SYMBOL_VALID) return; if (sym_is_choice_value(sym) && sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; prop = sym_get_choice_prop(sym); sym_calc_value(prop_get_symbol(prop)); } sym->flags |= SYMBOL_VALID; oldval = sym->curr; switch (sym->type) { case S_INT: case S_HEX: case S_STRING: newval = symbol_empty.curr; break; case S_BOOLEAN: case S_TRISTATE: newval = symbol_no.curr; break; default: sym->curr.val = sym->name; sym->curr.tri = no; return; } if (!sym_is_choice_value(sym)) sym->flags &= ~SYMBOL_WRITE; sym_calc_visibility(sym); /* set default if recursively called */ sym->curr = newval; switch (sym_get_type(sym)) { case S_BOOLEAN: case S_TRISTATE: if (sym_is_choice_value(sym) && sym->visible == yes) { prop = sym_get_choice_prop(sym); newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; } else { if (sym->visible != no) { /* if the symbol is visible use the user value * if available, otherwise try the default value */ sym->flags |= SYMBOL_WRITE; if (sym_has_value(sym)) { newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible); goto calc_newval; } } if (sym->rev_dep.tri != no) sym->flags |= SYMBOL_WRITE; if (!sym_is_choice(sym)) { prop = sym_get_default_prop(sym); if (prop) { sym->flags |= SYMBOL_WRITE; newval.tri = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); } } calc_newval: if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { struct expr *e; e = expr_simplify_unmet_dep(sym->rev_dep.expr, sym->dir_dep.expr); fprintf(stderr, "warning: ("); expr_fprint(e, stderr); fprintf(stderr, ") selects %s which has unmet direct dependencies (", sym->name); expr_fprint(sym->dir_dep.expr, stderr); fprintf(stderr, ")\n"); expr_free(e); } newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); } if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) newval.tri = yes; break; case S_STRING: case S_HEX: case S_INT: if (sym->visible != no) { sym->flags |= SYMBOL_WRITE; if (sym_has_value(sym)) { newval.val = sym->def[S_DEF_USER].val; break; } } prop = sym_get_default_prop(sym); if (prop) { struct symbol *ds = prop_get_symbol(prop); if (ds) { sym->flags |= SYMBOL_WRITE; sym_calc_value(ds); newval.val = ds->curr.val; } } break; default: ; } sym->curr = newval; if (sym_is_choice(sym) && newval.tri == yes) sym->curr.val = sym_calc_choice(sym); sym_validate_range(sym); if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { sym_set_changed(sym); if (modules_sym == sym) { sym_set_all_changed(); modules_val = modules_sym->curr.tri; } } if (sym_is_choice(sym)) { struct symbol *choice_sym; prop = sym_get_choice_prop(sym); expr_list_for_each_sym(prop->expr, e, choice_sym) { if ((sym->flags & SYMBOL_WRITE) && choice_sym->visible != no) choice_sym->flags |= SYMBOL_WRITE; if (sym->flags & SYMBOL_CHANGED) sym_set_changed(choice_sym); } } if (sym->flags & SYMBOL_AUTO) sym->flags &= ~SYMBOL_WRITE; if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) set_all_choice_values(sym); } void sym_clear_all_valid(void) { struct symbol *sym; int i; for_all_symbols(i, sym) sym->flags &= ~SYMBOL_VALID; sym_add_change_count(1); if (modules_sym) sym_calc_value(modules_sym); } void sym_set_changed(struct symbol *sym) { struct property *prop; sym->flags |= SYMBOL_CHANGED; for (prop = sym->prop; prop; prop = prop->next) { if (prop->menu) prop->menu->flags |= MENU_CHANGED; } } void sym_set_all_changed(void) { struct symbol *sym; int i; for_all_symbols(i, sym) sym_set_changed(sym); } bool sym_tristate_within_range(struct symbol *sym, tristate val) { int type = sym_get_type(sym); if (sym->visible == no) return false; if (type != S_BOOLEAN && type != S_TRISTATE) return false; if (type == S_BOOLEAN && val == mod) return false; if (sym->visible <= sym->rev_dep.tri) return false; if (sym_is_choice_value(sym) && sym->visible == yes) return val == yes; return val >= sym->rev_dep.tri && val <= sym->visible; } bool sym_set_tristate_value(struct symbol *sym, tristate val) { tristate oldval = sym_get_tristate_value(sym); if (oldval != val && !sym_tristate_within_range(sym, val)) return false; if (!(sym->flags & SYMBOL_DEF_USER)) { sym->flags |= SYMBOL_DEF_USER; sym_set_changed(sym); } /* * setting a choice value also resets the new flag of the choice * symbol and all other choice values. */ if (sym_is_choice_value(sym) && val == yes) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); struct property *prop; struct expr *e; cs->def[S_DEF_USER].val = sym; cs->flags |= SYMBOL_DEF_USER; prop = sym_get_choice_prop(cs); for (e = prop->expr; e; e = e->left.expr) { if (e->right.sym->visible != no) e->right.sym->flags |= SYMBOL_DEF_USER; } } sym->def[S_DEF_USER].tri = val; if (oldval != val) sym_clear_all_valid(); return true; } tristate sym_toggle_tristate_value(struct symbol *sym) { tristate oldval, newval; oldval = newval = sym_get_tristate_value(sym); do { switch (newval) { case no: newval = mod; break; case mod: newval = yes; break; case yes: newval = no; break; } if (sym_set_tristate_value(sym, newval)) break; } while (oldval != newval); return newval; } bool sym_string_valid(struct symbol *sym, const char *str) { signed char ch; switch (sym->type) { case S_STRING: return true; case S_INT: ch = *str++; if (ch == '-') ch = *str++; if (!isdigit(ch)) return false; if (ch == '0' && *str != 0) return false; while ((ch = *str++)) { if (!isdigit(ch)) return false; } return true; case S_HEX: if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) str += 2; ch = *str++; do { if (!isxdigit(ch)) return false; } while ((ch = *str++)); return true; case S_BOOLEAN: case S_TRISTATE: switch (str[0]) { case 'y': case 'Y': case 'm': case 'M': case 'n': case 'N': return true; } return false; default: return false; } } bool sym_string_within_range(struct symbol *sym, const char *str) { struct property *prop; long long val; switch (sym->type) { case S_STRING: return sym_string_valid(sym, str); case S_INT: if (!sym_string_valid(sym, str)) return false; prop = sym_get_range_prop(sym); if (!prop) return true; val = strtoll(str, NULL, 10); return val >= sym_get_range_val(prop->expr->left.sym, 10) && val <= sym_get_range_val(prop->expr->right.sym, 10); case S_HEX: if (!sym_string_valid(sym, str)) return false; prop = sym_get_range_prop(sym); if (!prop) return true; val = strtoll(str, NULL, 16); return val >= sym_get_range_val(prop->expr->left.sym, 16) && val <= sym_get_range_val(prop->expr->right.sym, 16); case S_BOOLEAN: case S_TRISTATE: switch (str[0]) { case 'y': case 'Y': return sym_tristate_within_range(sym, yes); case 'm': case 'M': return sym_tristate_within_range(sym, mod); case 'n': case 'N': return sym_tristate_within_range(sym, no); } return false; default: return false; } } bool sym_set_string_value(struct symbol *sym, const char *newval) { const char *oldval; char *val; int size; switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: switch (newval[0]) { case 'y': case 'Y': return sym_set_tristate_value(sym, yes); case 'm': case 'M': return sym_set_tristate_value(sym, mod); case 'n': case 'N': return sym_set_tristate_value(sym, no); } return false; default: ; } if (!sym_string_within_range(sym, newval)) return false; if (!(sym->flags & SYMBOL_DEF_USER)) { sym->flags |= SYMBOL_DEF_USER; sym_set_changed(sym); } oldval = sym->def[S_DEF_USER].val; size = strlen(newval) + 1; if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { size += 2; sym->def[S_DEF_USER].val = val = xmalloc(size); *val++ = '0'; *val++ = 'x'; } else if (!oldval || strcmp(oldval, newval)) sym->def[S_DEF_USER].val = val = xmalloc(size); else return true; strcpy(val, newval); free((void *)oldval); sym_clear_all_valid(); return true; } /* * Find the default value associated to a symbol. * For tristate symbol handle the modules=n case * in which case "m" becomes "y". * If the symbol does not have any default then fallback * to the fixed default values. */ const char *sym_get_string_default(struct symbol *sym) { struct property *prop; struct symbol *ds; const char *str; tristate val; sym_calc_visibility(sym); sym_calc_value(modules_sym); val = symbol_no.curr.tri; str = symbol_empty.curr.val; /* If symbol has a default value look it up */ prop = sym_get_default_prop(sym); if (prop != NULL) { switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: /* The visibility may limit the value from yes => mod */ val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); break; default: /* * The following fails to handle the situation * where a default value is further limited by * the valid range. */ ds = prop_get_symbol(prop); if (ds != NULL) { sym_calc_value(ds); str = (const char *)ds->curr.val; } } } /* Handle select statements */ val = EXPR_OR(val, sym->rev_dep.tri); /* transpose mod to yes if modules are not enabled */ if (val == mod) if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) val = yes; /* transpose mod to yes if type is bool */ if (sym->type == S_BOOLEAN && val == mod) val = yes; switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: switch (val) { case no: return "n"; case mod: return "m"; case yes: return "y"; } case S_INT: case S_HEX: return str; case S_STRING: return str; case S_OTHER: case S_UNKNOWN: break; } return ""; } const char *sym_get_string_value(struct symbol *sym) { tristate val; switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: val = sym_get_tristate_value(sym); switch (val) { case no: return "n"; case mod: sym_calc_value(modules_sym); return (modules_sym->curr.tri == no) ? "n" : "m"; case yes: return "y"; } break; default: ; } return (const char *)sym->curr.val; } bool sym_is_changable(struct symbol *sym) { return sym->visible > sym->rev_dep.tri; } static unsigned strhash(const char *s) { /* fnv32 hash */ unsigned hash = 2166136261U; for (; *s; s++) hash = (hash ^ *s) * 0x01000193; return hash; } struct symbol *sym_lookup(const char *name, int flags) { struct symbol *symbol; char *new_name; int hash; if (name) { if (name[0] && !name[1]) { switch (name[0]) { case 'y': return &symbol_yes; case 'm': return &symbol_mod; case 'n': return &symbol_no; } } hash = strhash(name) % SYMBOL_HASHSIZE; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { if (symbol->name && !strcmp(symbol->name, name) && (flags ? symbol->flags & flags : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) return symbol; } new_name = strdup(name); } else { new_name = NULL; hash = 0; } symbol = xmalloc(sizeof(*symbol)); memset(symbol, 0, sizeof(*symbol)); symbol->name = new_name; symbol->type = S_UNKNOWN; symbol->flags |= flags; symbol->next = symbol_hash[hash]; symbol_hash[hash] = symbol; return symbol; } struct symbol *sym_find(const char *name) { struct symbol *symbol = NULL; int hash = 0; if (!name) return NULL; if (name[0] && !name[1]) { switch (name[0]) { case 'y': return &symbol_yes; case 'm': return &symbol_mod; case 'n': return &symbol_no; } } hash = strhash(name) % SYMBOL_HASHSIZE; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { if (symbol->name && !strcmp(symbol->name, name) && !(symbol->flags & SYMBOL_CONST)) break; } return symbol; } /* * Expand symbol's names embedded in the string given in argument. Symbols' * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to * the empty string. */ const char *sym_expand_string_value(const char *in) { const char *src; char *res; size_t reslen; reslen = strlen(in) + 1; res = xmalloc(reslen); res[0] = '\0'; while ((src = strchr(in, '$'))) { char *p, name[SYMBOL_MAXLENGTH]; const char *symval = ""; struct symbol *sym; size_t newlen; strncat(res, in, src - in); src++; p = name; while (isalnum(*src) || *src == '_') *p++ = *src++; *p = '\0'; sym = sym_find(name); if (sym != NULL) { sym_calc_value(sym); symval = sym_get_string_value(sym); } newlen = strlen(res) + strlen(symval) + strlen(src) + 1; if (newlen > reslen) { reslen = newlen; res = realloc(res, reslen); } strcat(res, symval); in = src; } strcat(res, in); return res; } const char *sym_escape_string_value(const char *in) { const char *p; size_t reslen; char *res; size_t l; reslen = strlen(in) + strlen("\"\"") + 1; p = in; for (;;) { l = strcspn(p, "\"\\"); p += l; if (p[0] == '\0') break; reslen++; p++; } res = xmalloc(reslen); res[0] = '\0'; strcat(res, "\""); p = in; for (;;) { l = strcspn(p, "\"\\"); strncat(res, p, l); p += l; if (p[0] == '\0') break; strcat(res, "\\"); strncat(res, p++, 1); } strcat(res, "\""); return res; } struct sym_match { struct symbol *sym; off_t so, eo; }; /* Compare matched symbols as thus: * - first, symbols that match exactly * - then, alphabetical sort */ static int sym_rel_comp(const void *sym1, const void *sym2) { const struct sym_match *s1 = sym1; const struct sym_match *s2 = sym2; int exact1, exact2; /* Exact match: * - if matched length on symbol s1 is the length of that symbol, * then this symbol should come first; * - if matched length on symbol s2 is the length of that symbol, * then this symbol should come first. * Note: since the search can be a regexp, both symbols may match * exactly; if this is the case, we can't decide which comes first, * and we fallback to sorting alphabetically. */ exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); if (exact1 && !exact2) return -1; if (!exact1 && exact2) return 1; /* As a fallback, sort symbols alphabetically */ return strcmp(s1->sym->name, s2->sym->name); } struct symbol **sym_re_search(const char *pattern) { struct symbol *sym, **sym_arr = NULL; struct sym_match *sym_match_arr = NULL; int i, cnt, size; regex_t re; regmatch_t match[1]; cnt = size = 0; /* Skip if empty */ if (strlen(pattern) == 0) return NULL; if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) return NULL; for_all_symbols(i, sym) { if (sym->flags & SYMBOL_CONST || !sym->name) continue; if (regexec(&re, sym->name, 1, match, 0)) continue; if (cnt >= size) { void *tmp; size += 16; tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); if (!tmp) goto sym_re_search_free; sym_match_arr = tmp; } sym_calc_value(sym); /* As regexec returned 0, we know we have a match, so * we can use match[0].rm_[se]o without further checks */ sym_match_arr[cnt].so = match[0].rm_so; sym_match_arr[cnt].eo = match[0].rm_eo; sym_match_arr[cnt++].sym = sym; } if (sym_match_arr) { qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); sym_arr = malloc((cnt+1) * sizeof(struct symbol)); if (!sym_arr) goto sym_re_search_free; for (i = 0; i < cnt; i++) sym_arr[i] = sym_match_arr[i].sym; sym_arr[cnt] = NULL; } sym_re_search_free: /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ free(sym_match_arr); regfree(&re); return sym_arr; } /* * When we check for recursive dependencies we use a stack to save * current state so we can print out relevant info to user. * The entries are located on the call stack so no need to free memory. * Note insert() remove() must always match to properly clear the stack. */ static struct dep_stack { struct dep_stack *prev, *next; struct symbol *sym; struct property *prop; struct expr *expr; } *check_top; static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) { memset(stack, 0, sizeof(*stack)); if (check_top) check_top->next = stack; stack->prev = check_top; stack->sym = sym; check_top = stack; } static void dep_stack_remove(void) { check_top = check_top->prev; if (check_top) check_top->next = NULL; } /* * Called when we have detected a recursive dependency. * check_top point to the top of the stact so we use * the ->prev pointer to locate the bottom of the stack. */ static void sym_check_print_recursive(struct symbol *last_sym) { struct dep_stack *stack; struct symbol *sym, *next_sym; struct menu *menu = NULL; struct property *prop; struct dep_stack cv_stack; if (sym_is_choice_value(last_sym)) { dep_stack_insert(&cv_stack, last_sym); last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); } for (stack = check_top; stack != NULL; stack = stack->prev) if (stack->sym == last_sym) break; if (!stack) { fprintf(stderr, "unexpected recursive dependency error\n"); return; } for (; stack; stack = stack->next) { sym = stack->sym; next_sym = stack->next ? stack->next->sym : last_sym; prop = stack->prop; if (prop == NULL) prop = stack->sym->prop; /* for choice values find the menu entry (used below) */ if (sym_is_choice(sym) || sym_is_choice_value(sym)) { for (prop = sym->prop; prop; prop = prop->next) { menu = prop->menu; if (prop->menu) break; } } if (stack->sym == last_sym) fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", prop->file->name, prop->lineno); if (stack->expr) { fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", prop->file->name, prop->lineno, sym->name ? sym->name : "", prop_get_type_name(prop->type), next_sym->name ? next_sym->name : ""); } else if (stack->prop) { fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", prop->file->name, prop->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else if (sym_is_choice(sym)) { fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", menu->file->name, menu->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else if (sym_is_choice_value(sym)) { fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", menu->file->name, menu->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else { fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", prop->file->name, prop->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } } if (check_top == &cv_stack) dep_stack_remove(); } static struct symbol *sym_check_expr_deps(struct expr *e) { struct symbol *sym; if (!e) return NULL; switch (e->type) { case E_OR: case E_AND: sym = sym_check_expr_deps(e->left.expr); if (sym) return sym; return sym_check_expr_deps(e->right.expr); case E_NOT: return sym_check_expr_deps(e->left.expr); case E_EQUAL: case E_UNEQUAL: sym = sym_check_deps(e->left.sym); if (sym) return sym; return sym_check_deps(e->right.sym); case E_SYMBOL: return sym_check_deps(e->left.sym); default: break; } printf("Oops! How to check %d?\n", e->type); return NULL; } /* return NULL when dependencies are OK */ static struct symbol *sym_check_sym_deps(struct symbol *sym) { struct symbol *sym2; struct property *prop; struct dep_stack stack; dep_stack_insert(&stack, sym); sym2 = sym_check_expr_deps(sym->rev_dep.expr); if (sym2) goto out; for (prop = sym->prop; prop; prop = prop->next) { if (prop->type == P_CHOICE || prop->type == P_SELECT) continue; stack.prop = prop; sym2 = sym_check_expr_deps(prop->visible.expr); if (sym2) break; if (prop->type != P_DEFAULT || sym_is_choice(sym)) continue; stack.expr = prop->expr; sym2 = sym_check_expr_deps(prop->expr); if (sym2) break; stack.expr = NULL; } out: dep_stack_remove(); return sym2; } static struct symbol *sym_check_choice_deps(struct symbol *choice) { struct symbol *sym, *sym2; struct property *prop; struct expr *e; struct dep_stack stack; dep_stack_insert(&stack, choice); prop = sym_get_choice_prop(choice); expr_list_for_each_sym(prop->expr, e, sym) sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); sym2 = sym_check_sym_deps(choice); choice->flags &= ~SYMBOL_CHECK; if (sym2) goto out; expr_list_for_each_sym(prop->expr, e, sym) { sym2 = sym_check_sym_deps(sym); if (sym2) break; } out: expr_list_for_each_sym(prop->expr, e, sym) sym->flags &= ~SYMBOL_CHECK; if (sym2 && sym_is_choice_value(sym2) && prop_get_symbol(sym_get_choice_prop(sym2)) == choice) sym2 = choice; dep_stack_remove(); return sym2; } struct symbol *sym_check_deps(struct symbol *sym) { struct symbol *sym2; struct property *prop; if (sym->flags & SYMBOL_CHECK) { sym_check_print_recursive(sym); return sym; } if (sym->flags & SYMBOL_CHECKED) return NULL; if (sym_is_choice_value(sym)) { struct dep_stack stack; /* for choice groups start the check with main choice symbol */ dep_stack_insert(&stack, sym); prop = sym_get_choice_prop(sym); sym2 = sym_check_deps(prop_get_symbol(prop)); dep_stack_remove(); } else if (sym_is_choice(sym)) { sym2 = sym_check_choice_deps(sym); } else { sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); sym2 = sym_check_sym_deps(sym); sym->flags &= ~SYMBOL_CHECK; } if (sym2 && sym2 == sym) sym2 = NULL; return sym2; } struct property *prop_alloc(enum prop_type type, struct symbol *sym) { struct property *prop; struct property **propp; prop = xmalloc(sizeof(*prop)); memset(prop, 0, sizeof(*prop)); prop->type = type; prop->sym = sym; prop->file = current_file; prop->lineno = zconf_lineno(); /* append property to the prop list of symbol */ if (sym) { for (propp = &sym->prop; *propp; propp = &(*propp)->next) ; *propp = prop; } return prop; } struct symbol *prop_get_symbol(struct property *prop) { if (prop->expr && (prop->expr->type == E_SYMBOL || prop->expr->type == E_LIST)) return prop->expr->left.sym; return NULL; } const char *prop_get_type_name(enum prop_type type) { switch (type) { case P_PROMPT: return "prompt"; case P_ENV: return "env"; case P_COMMENT: return "comment"; case P_MENU: return "menu"; case P_DEFAULT: return "default"; case P_CHOICE: return "choice"; case P_SELECT: return "select"; case P_RANGE: return "range"; case P_SYMBOL: return "symbol"; case P_UNKNOWN: break; } return "unknown"; } static void prop_add_env(const char *env) { struct symbol *sym, *sym2; struct property *prop; char *p; sym = current_entry->sym; sym->flags |= SYMBOL_AUTO; for_all_properties(sym, prop, P_ENV) { sym2 = prop_get_symbol(prop); if (strcmp(sym2->name, env)) menu_warn(current_entry, "redefining environment symbol from %s", sym2->name); return; } prop = prop_alloc(P_ENV, sym); prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); sym_env_list = expr_alloc_one(E_LIST, sym_env_list); sym_env_list->right.sym = sym; p = getenv(env); if (p) sym_add_default(sym, p); else menu_warn(current_entry, "environment variable %s undefined", env); } ================================================ FILE: kconfig/util.c ================================================ /* * Copyright (C) 2002-2005 Roman Zippel * Copyright (C) 2002-2005 Sam Ravnborg * * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include "lkc.h" /* file already present in list? If not add it */ struct file *file_lookup(const char *name) { struct file *file; const char *file_name = sym_expand_string_value(name); for (file = file_list; file; file = file->next) { if (!strcmp(name, file->name)) { free((void *)file_name); return file; } } file = xmalloc(sizeof(*file)); memset(file, 0, sizeof(*file)); file->name = file_name; file->next = file_list; file_list = file; return file; } /* write a dependency file as used by kbuild to track dependencies */ int file_write_dep(const char *name) { struct symbol *sym, *env_sym; struct expr *e; struct file *file; FILE *out; if (!name) name = ".kconfig.d"; out = fopen("..config.tmp", "w"); if (!out) return 1; fprintf(out, "deps_config := \\\n"); for (file = file_list; file; file = file->next) { if (file->next) fprintf(out, "\t%s \\\n", file->name); else fprintf(out, "\t%s\n", file->name); } fprintf(out, "\n%s: \\\n" "\t$(deps_config)\n\n", conf_get_autoconfig_name()); expr_list_for_each_sym(sym_env_list, e, sym) { struct property *prop; const char *value; prop = sym_get_env_prop(sym); env_sym = prop_get_symbol(prop); if (!env_sym) continue; value = getenv(env_sym->name); if (!value) value = ""; fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); fprintf(out, "endif\n"); } fprintf(out, "\n$(deps_config): ;\n"); fclose(out); rename("..config.tmp", name); return 0; } /* Allocate initial growable string */ struct gstr str_new(void) { struct gstr gs; gs.s = xmalloc(sizeof(char) * 64); gs.len = 64; gs.max_width = 0; strcpy(gs.s, "\0"); return gs; } /* Allocate and assign growable string */ struct gstr str_assign(const char *s) { struct gstr gs; gs.s = strdup(s); gs.len = strlen(s) + 1; gs.max_width = 0; return gs; } /* Free storage for growable string */ void str_free(struct gstr *gs) { if (gs->s) free(gs->s); gs->s = NULL; gs->len = 0; } /* Append to growable string */ void str_append(struct gstr *gs, const char *s) { size_t l; if (s) { l = strlen(gs->s) + strlen(s) + 1; if (l > gs->len) { gs->s = realloc(gs->s, l); gs->len = l; } strcat(gs->s, s); } } /* Append printf formatted string to growable string */ void str_printf(struct gstr *gs, const char *fmt, ...) { va_list ap; char s[10000]; /* big enough... */ va_start(ap, fmt); vsnprintf(s, sizeof(s), fmt, ap); str_append(gs, s); va_end(ap); } /* Retrieve value of growable string */ const char *str_get(struct gstr *gs) { return gs->s; } void *xmalloc(size_t size) { void *p = malloc(size); if (p) return p; fprintf(stderr, "Out of memory.\n"); exit(1); } void *xcalloc(size_t nmemb, size_t size) { void *p = calloc(nmemb, size); if (p) return p; fprintf(stderr, "Out of memory.\n"); exit(1); } ================================================ FILE: kconfig/zconf.gperf ================================================ %language=ANSI-C %define hash-function-name kconf_id_hash %define lookup-function-name kconf_id_lookup %define string-pool-name kconf_id_strings %compare-strncmp %enum %pic %struct-type struct kconf_id; static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); %% mainmenu, T_MAINMENU, TF_COMMAND menu, T_MENU, TF_COMMAND endmenu, T_ENDMENU, TF_COMMAND source, T_SOURCE, TF_COMMAND choice, T_CHOICE, TF_COMMAND endchoice, T_ENDCHOICE, TF_COMMAND comment, T_COMMENT, TF_COMMAND config, T_CONFIG, TF_COMMAND menuconfig, T_MENUCONFIG, TF_COMMAND help, T_HELP, TF_COMMAND if, T_IF, TF_COMMAND|TF_PARAM endif, T_ENDIF, TF_COMMAND depends, T_DEPENDS, TF_COMMAND optional, T_OPTIONAL, TF_COMMAND default, T_DEFAULT, TF_COMMAND, S_UNKNOWN prompt, T_PROMPT, TF_COMMAND tristate, T_TYPE, TF_COMMAND, S_TRISTATE def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE bool, T_TYPE, TF_COMMAND, S_BOOLEAN boolean, T_TYPE, TF_COMMAND, S_BOOLEAN def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN int, T_TYPE, TF_COMMAND, S_INT hex, T_TYPE, TF_COMMAND, S_HEX string, T_TYPE, TF_COMMAND, S_STRING select, T_SELECT, TF_COMMAND range, T_RANGE, TF_COMMAND visible, T_VISIBLE, TF_COMMAND option, T_OPTION, TF_COMMAND on, T_ON, TF_PARAM modules, T_OPT_MODULES, TF_OPTION defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION env, T_OPT_ENV, TF_OPTION allnoconfig_y, T_OPT_ALLNOCONFIG_Y,TF_OPTION %% ================================================ FILE: kconfig/zconf.hash.c_shipped ================================================ /* ANSI-C code produced by gperf version 3.0.4 */ /* Command-line: gperf -t --output-file scripts/kconfig/zconf.hash.c_shipped -a -C -E -g -k '1,3,$' -p -t scripts/kconfig/zconf.gperf */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) /* The character set is not based on ISO-646. */ #error "gperf generated tables don't work with this execution character set. Please report a bug to ." #endif #line 10 "scripts/kconfig/zconf.gperf" struct kconf_id; static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); /* maximum key range = 71, duplicates = 0 */ #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static unsigned int kconf_id_hash (register const char *str, register unsigned int len) { static const unsigned char asso_values[] = { 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 5, 25, 25, 0, 0, 0, 5, 0, 0, 73, 73, 5, 0, 10, 5, 45, 73, 20, 20, 0, 15, 15, 73, 20, 5, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73 }; register int hval = len; switch (hval) { default: hval += asso_values[(unsigned char)str[2]]; /*FALLTHROUGH*/ case 2: case 1: hval += asso_values[(unsigned char)str[0]]; break; } return hval + asso_values[(unsigned char)str[len - 1]]; } struct kconf_id_strings_t { char kconf_id_strings_str2[sizeof("if")]; char kconf_id_strings_str3[sizeof("int")]; char kconf_id_strings_str5[sizeof("endif")]; char kconf_id_strings_str7[sizeof("default")]; char kconf_id_strings_str8[sizeof("tristate")]; char kconf_id_strings_str9[sizeof("endchoice")]; char kconf_id_strings_str12[sizeof("def_tristate")]; char kconf_id_strings_str13[sizeof("def_bool")]; char kconf_id_strings_str14[sizeof("defconfig_list")]; char kconf_id_strings_str17[sizeof("on")]; char kconf_id_strings_str18[sizeof("optional")]; char kconf_id_strings_str21[sizeof("option")]; char kconf_id_strings_str22[sizeof("endmenu")]; char kconf_id_strings_str23[sizeof("mainmenu")]; char kconf_id_strings_str25[sizeof("menuconfig")]; char kconf_id_strings_str27[sizeof("modules")]; char kconf_id_strings_str28[sizeof("allnoconfig_y")]; char kconf_id_strings_str29[sizeof("menu")]; char kconf_id_strings_str31[sizeof("select")]; char kconf_id_strings_str32[sizeof("comment")]; char kconf_id_strings_str33[sizeof("env")]; char kconf_id_strings_str35[sizeof("range")]; char kconf_id_strings_str36[sizeof("choice")]; char kconf_id_strings_str39[sizeof("bool")]; char kconf_id_strings_str41[sizeof("source")]; char kconf_id_strings_str42[sizeof("visible")]; char kconf_id_strings_str43[sizeof("hex")]; char kconf_id_strings_str46[sizeof("config")]; char kconf_id_strings_str47[sizeof("boolean")]; char kconf_id_strings_str51[sizeof("string")]; char kconf_id_strings_str54[sizeof("help")]; char kconf_id_strings_str56[sizeof("prompt")]; char kconf_id_strings_str72[sizeof("depends")]; }; static const struct kconf_id_strings_t kconf_id_strings_contents = { "if", "int", "endif", "default", "tristate", "endchoice", "def_tristate", "def_bool", "defconfig_list", "on", "optional", "option", "endmenu", "mainmenu", "menuconfig", "modules", "allnoconfig_y", "menu", "select", "comment", "env", "range", "choice", "bool", "source", "visible", "hex", "config", "boolean", "string", "help", "prompt", "depends" }; #define kconf_id_strings ((const char *) &kconf_id_strings_contents) #ifdef __GNUC__ __inline #if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ __attribute__ ((__gnu_inline__)) #endif #endif const struct kconf_id * kconf_id_lookup (register const char *str, register unsigned int len) { enum { TOTAL_KEYWORDS = 33, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 14, MIN_HASH_VALUE = 2, MAX_HASH_VALUE = 72 }; static const struct kconf_id wordlist[] = { {-1}, {-1}, #line 25 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM}, #line 36 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT}, {-1}, #line 26 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, {-1}, #line 29 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, #line 31 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE}, #line 20 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, {-1}, {-1}, #line 32 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE}, #line 35 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, #line 45 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION}, {-1}, {-1}, #line 43 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM}, #line 28 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND}, {-1}, {-1}, #line 42 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND}, #line 17 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND}, #line 15 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_MAINMENU, TF_COMMAND}, {-1}, #line 23 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND}, {-1}, #line 44 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, #line 47 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPT_ALLNOCONFIG_Y,TF_OPTION}, #line 16 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, {-1}, #line 39 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, #line 21 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, #line 46 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION}, {-1}, #line 40 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND}, #line 19 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND}, {-1}, {-1}, #line 33 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_TYPE, TF_COMMAND, S_BOOLEAN}, {-1}, #line 18 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND}, #line 41 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND}, #line 37 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX}, {-1}, {-1}, #line 22 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND}, #line 34 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN}, {-1}, {-1}, {-1}, #line 38 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING}, {-1}, {-1}, #line 24 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54, T_HELP, TF_COMMAND}, {-1}, #line 30 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56, T_PROMPT, TF_COMMAND}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, #line 27 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72, T_DEPENDS, TF_COMMAND} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { register int key = kconf_id_hash (str, len); if (key <= MAX_HASH_VALUE && key >= 0) { register int o = wordlist[key].name; if (o >= 0) { register const char *s = o + kconf_id_strings; if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') return &wordlist[key]; } } } return 0; } #line 48 "scripts/kconfig/zconf.gperf" ================================================ FILE: kconfig/zconf.l ================================================ %option nostdinit noyywrap never-interactive full ecs %option 8bit nodefault perf-report perf-report %option noinput %x COMMAND HELP STRING PARAM %{ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include #include "lkc.h" #define START_STRSIZE 16 static struct { struct file *file; int lineno; } current_pos; static char *text; static int text_size, text_asize; struct buffer { struct buffer *parent; YY_BUFFER_STATE state; }; struct buffer *current_buf; static int last_ts, first_ts; static void zconf_endhelp(void); static void zconf_endfile(void); static void new_string(void) { text = xmalloc(START_STRSIZE); text_asize = START_STRSIZE; text_size = 0; *text = 0; } static void append_string(const char *str, int size) { int new_size = text_size + size + 1; if (new_size > text_asize) { new_size += START_STRSIZE - 1; new_size &= -START_STRSIZE; text = realloc(text, new_size); text_asize = new_size; } memcpy(text + text_size, str, size); text_size += size; text[text_size] = 0; } static void alloc_string(const char *str, int size) { text = xmalloc(size + 1); memcpy(text, str, size); text[size] = 0; } %} n [A-Za-z0-9_] %% int str = 0; int ts, i; [ \t]*#.*\n | [ \t]*\n { current_file->lineno++; return T_EOL; } [ \t]*#.* [ \t]+ { BEGIN(COMMAND); } . { unput(yytext[0]); BEGIN(COMMAND); } { {n}+ { const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); BEGIN(PARAM); current_pos.file = current_file; current_pos.lineno = current_file->lineno; if (id && id->flags & TF_COMMAND) { zconflval.id = id; return id->token; } alloc_string(yytext, yyleng); zconflval.string = text; return T_WORD; } . \n { BEGIN(INITIAL); current_file->lineno++; return T_EOL; } } { "&&" return T_AND; "||" return T_OR; "(" return T_OPEN_PAREN; ")" return T_CLOSE_PAREN; "!" return T_NOT; "=" return T_EQUAL; "!=" return T_UNEQUAL; \"|\' { str = yytext[0]; new_string(); BEGIN(STRING); } \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; --- /* ignore */ ({n}|[-/.])+ { const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); if (id && id->flags & TF_PARAM) { zconflval.id = id; return id->token; } alloc_string(yytext, yyleng); zconflval.string = text; return T_WORD; } #.* /* comment */ \\\n current_file->lineno++; . <> { BEGIN(INITIAL); } } { [^'"\\\n]+/\n { append_string(yytext, yyleng); zconflval.string = text; return T_WORD_QUOTE; } [^'"\\\n]+ { append_string(yytext, yyleng); } \\.?/\n { append_string(yytext + 1, yyleng - 1); zconflval.string = text; return T_WORD_QUOTE; } \\.? { append_string(yytext + 1, yyleng - 1); } \'|\" { if (str == yytext[0]) { BEGIN(PARAM); zconflval.string = text; return T_WORD_QUOTE; } else append_string(yytext, 1); } \n { printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); current_file->lineno++; BEGIN(INITIAL); return T_EOL; } <> { BEGIN(INITIAL); } } { [ \t]+ { ts = 0; for (i = 0; i < yyleng; i++) { if (yytext[i] == '\t') ts = (ts & ~7) + 8; else ts++; } last_ts = ts; if (first_ts) { if (ts < first_ts) { zconf_endhelp(); return T_HELPTEXT; } ts -= first_ts; while (ts > 8) { append_string(" ", 8); ts -= 8; } append_string(" ", ts); } } [ \t]*\n/[^ \t\n] { current_file->lineno++; zconf_endhelp(); return T_HELPTEXT; } [ \t]*\n { current_file->lineno++; append_string("\n", 1); } [^ \t\n].* { while (yyleng) { if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) break; yyleng--; } append_string(yytext, yyleng); if (!first_ts) first_ts = last_ts; } <> { zconf_endhelp(); return T_HELPTEXT; } } <> { if (current_file) { zconf_endfile(); return T_EOL; } fclose(yyin); yyterminate(); } %% void zconf_starthelp(void) { new_string(); last_ts = first_ts = 0; BEGIN(HELP); } static void zconf_endhelp(void) { zconflval.string = text; BEGIN(INITIAL); } /* * Try to open specified file with following names: * ./name * $(srctree)/name * The latter is used when srctree is separate from objtree * when compiling the kernel. * Return NULL if file is not found. */ FILE *zconf_fopen(const char *name) { char *env, fullname[PATH_MAX+1]; FILE *f; f = fopen(name, "r"); if (!f && name != NULL && name[0] != '/') { env = getenv(SRCTREE); if (env) { sprintf(fullname, "%s/%s", env, name); f = fopen(fullname, "r"); } } return f; } void zconf_initscan(const char *name) { yyin = zconf_fopen(name); if (!yyin) { printf("can't find file %s\n", name); exit(1); } current_buf = xmalloc(sizeof(*current_buf)); memset(current_buf, 0, sizeof(*current_buf)); current_file = file_lookup(name); current_file->lineno = 1; } void zconf_nextfile(const char *name) { struct file *iter; struct file *file = file_lookup(name); struct buffer *buf = xmalloc(sizeof(*buf)); memset(buf, 0, sizeof(*buf)); current_buf->state = YY_CURRENT_BUFFER; yyin = zconf_fopen(file->name); if (!yyin) { printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), file->name); exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); buf->parent = current_buf; current_buf = buf; for (iter = current_file->parent; iter; iter = iter->parent ) { if (!strcmp(current_file->name,iter->name) ) { printf("%s:%d: recursive inclusion detected. " "Inclusion path:\n current file : '%s'\n", zconf_curname(), zconf_lineno(), zconf_curname()); iter = current_file->parent; while (iter && \ strcmp(iter->name,current_file->name)) { printf(" included from: '%s:%d'\n", iter->name, iter->lineno-1); iter = iter->parent; } if (iter) printf(" included from: '%s:%d'\n", iter->name, iter->lineno+1); exit(1); } } file->lineno = 1; file->parent = current_file; current_file = file; } static void zconf_endfile(void) { struct buffer *parent; current_file = current_file->parent; parent = current_buf->parent; if (parent) { fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(parent->state); } free(current_buf); current_buf = parent; } int zconf_lineno(void) { return current_pos.lineno; } const char *zconf_curname(void) { return current_pos.file ? current_pos.file->name : ""; } ================================================ FILE: kconfig/zconf.lex.c_shipped ================================================ #line 3 "scripts/kconfig/zconf.lex.c_shipped" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define yy_create_buffer zconf_create_buffer #define yy_delete_buffer zconf_delete_buffer #define yy_flex_debug zconf_flex_debug #define yy_init_buffer zconf_init_buffer #define yy_flush_buffer zconf_flush_buffer #define yy_load_buffer_state zconf_load_buffer_state #define yy_switch_to_buffer zconf_switch_to_buffer #define yyin zconfin #define yyleng zconfleng #define yylex zconflex #define yylineno zconflineno #define yyout zconfout #define yyrestart zconfrestart #define yytext zconftext #define yywrap zconfwrap #define yyalloc zconfalloc #define yyrealloc zconfrealloc #define yyfree zconffree #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 35 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE zconfrestart(zconfin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif extern int zconfleng; extern FILE *zconfin, *zconfout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up zconftext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via zconfrestart()), so that the user can continue scanning by * just pointing zconfin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when zconftext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int zconfleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow zconfwrap()'s to do buffer switches * instead of setting up a fresh zconfin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void zconfrestart (FILE *input_file ); void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size ); void zconf_delete_buffer (YY_BUFFER_STATE b ); void zconf_flush_buffer (YY_BUFFER_STATE b ); void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ); void zconfpop_buffer_state (void ); static void zconfensure_buffer_stack (void ); static void zconf_load_buffer_state (void ); static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len ); void *zconfalloc (yy_size_t ); void *zconfrealloc (void *,yy_size_t ); void zconffree (void * ); #define yy_new_buffer zconf_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ zconfensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ zconfensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define zconfwrap(n) 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; typedef int yy_state_type; extern int zconflineno; int zconflineno = 1; extern char *zconftext; #define yytext_ptr zconftext static yyconst flex_int16_t yy_nxt[][17] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }, { 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }, { 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 16, 16, 16 }, { 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 16, 16, 16 }, { 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19 }, { 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19 }, { 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, 22, 22, 22, 22, 22, 25, 22 }, { 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, 22, 22, 22, 22, 22, 25, 22 }, { 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, 33, 34, 35, 35, 36, 37, 38 }, { 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, 33, 34, 35, 35, 36, 37, 38 }, { -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11 }, { 11, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12 }, { 11, -13, 39, 40, -13, -13, 41, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13 }, { 11, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14 }, { 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }, { 11, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16 }, { 11, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17 }, { 11, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, 44, -18, -18, -18 }, { 11, 45, 45, -19, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45 }, { 11, -20, 46, 47, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20 }, { 11, 48, -21, -21, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 }, { 11, 49, 49, 50, 49, -22, 49, 49, -22, 49, 49, 49, 49, 49, 49, -22, 49 }, { 11, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23 }, { 11, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24 }, { 11, 51, 51, 52, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51 }, { 11, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26 }, { 11, -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, -27 }, { 11, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, 53, -28, -28 }, { 11, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29 }, { 11, 54, 54, -30, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54 }, { 11, -31, -31, -31, -31, -31, -31, 55, -31, -31, -31, -31, -31, -31, -31, -31, -31 }, { 11, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32 }, { 11, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33 }, { 11, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, 56, 57, 57, -34, -34, -34 }, { 11, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, 57, 57, 57, -35, -35, -35 }, { 11, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36 }, { 11, -37, -37, 58, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37 }, { 11, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, 59 }, { 11, -39, 39, 40, -39, -39, 41, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39 }, { 11, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40 }, { 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }, { 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }, { 11, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43 }, { 11, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, 44, -44, -44, -44 }, { 11, 45, 45, -45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45 }, { 11, -46, 46, 47, -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, -46 }, { 11, 48, -47, -47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 }, { 11, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48 }, { 11, 49, 49, 50, 49, -49, 49, 49, -49, 49, 49, 49, 49, 49, 49, -49, 49 }, { 11, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50 }, { 11, -51, -51, 52, -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, -51 }, { 11, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52 }, { 11, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53 }, { 11, 54, 54, -54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54 }, { 11, -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, -55 }, { 11, -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, 60, 57, 57, -56, -56, -56 }, { 11, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, 57, 57, 57, -57, -57, -57 }, { 11, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58 }, { 11, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59 }, { 11, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, 57, 57, 57, -60, -60, -60 }, } ; static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up zconftext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ zconfleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 33 #define YY_END_OF_BUFFER 34 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[61] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 5, 4, 2, 3, 7, 8, 6, 32, 29, 31, 24, 28, 27, 26, 22, 17, 13, 16, 20, 22, 11, 12, 19, 19, 14, 22, 22, 4, 2, 3, 3, 1, 6, 32, 29, 31, 30, 24, 23, 26, 25, 15, 20, 9, 19, 19, 21, 10, 18 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 5, 6, 1, 1, 7, 8, 9, 10, 1, 1, 1, 11, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 14, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 15, 1, 1, 13, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; extern int zconf_flex_debug; int zconf_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *zconftext; #define YY_NO_INPUT 1 /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include #include "lkc.h" #define START_STRSIZE 16 static struct { struct file *file; int lineno; } current_pos; static char *text; static int text_size, text_asize; struct buffer { struct buffer *parent; YY_BUFFER_STATE state; }; struct buffer *current_buf; static int last_ts, first_ts; static void zconf_endhelp(void); static void zconf_endfile(void); static void new_string(void) { text = xmalloc(START_STRSIZE); text_asize = START_STRSIZE; text_size = 0; *text = 0; } static void append_string(const char *str, int size) { int new_size = text_size + size + 1; if (new_size > text_asize) { new_size += START_STRSIZE - 1; new_size &= -START_STRSIZE; text = realloc(text, new_size); text_asize = new_size; } memcpy(text + text_size, str, size); text_size += size; text[text_size] = 0; } static void alloc_string(const char *str, int size) { text = xmalloc(size + 1); memcpy(text, str, size); text[size] = 0; } #define INITIAL 0 #define COMMAND 1 #define HELP 2 #define STRING 3 #define PARAM 4 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int zconflex_destroy (void ); int zconfget_debug (void ); void zconfset_debug (int debug_flag ); YY_EXTRA_TYPE zconfget_extra (void ); void zconfset_extra (YY_EXTRA_TYPE user_defined ); FILE *zconfget_in (void ); void zconfset_in (FILE * in_str ); FILE *zconfget_out (void ); void zconfset_out (FILE * out_str ); int zconfget_leng (void ); char *zconfget_text (void ); int zconfget_lineno (void ); void zconfset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int zconfwrap (void ); #else extern int zconfwrap (void ); #endif #endif static void yyunput (int c,char *buf_ptr ); #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ errno=0; \ while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(zconfin); \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int zconflex (void); #define YY_DECL int zconflex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after zconftext and zconfleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; int str = 0; int ts, i; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! zconfin ) zconfin = stdin; if ( ! zconfout ) zconfout = stdout; if ( ! YY_CURRENT_BUFFER ) { zconfensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = zconf_create_buffer(zconfin,YY_BUF_SIZE ); } zconf_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of zconftext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) ++yy_cp; yy_current_state = -yy_current_state; yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 1: /* rule 1 can match eol */ case 2: /* rule 2 can match eol */ YY_RULE_SETUP { current_file->lineno++; return T_EOL; } YY_BREAK case 3: YY_RULE_SETUP YY_BREAK case 4: YY_RULE_SETUP { BEGIN(COMMAND); } YY_BREAK case 5: YY_RULE_SETUP { unput(zconftext[0]); BEGIN(COMMAND); } YY_BREAK case 6: YY_RULE_SETUP { const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); BEGIN(PARAM); current_pos.file = current_file; current_pos.lineno = current_file->lineno; if (id && id->flags & TF_COMMAND) { zconflval.id = id; return id->token; } alloc_string(zconftext, zconfleng); zconflval.string = text; return T_WORD; } YY_BREAK case 7: YY_RULE_SETUP YY_BREAK case 8: /* rule 8 can match eol */ YY_RULE_SETUP { BEGIN(INITIAL); current_file->lineno++; return T_EOL; } YY_BREAK case 9: YY_RULE_SETUP return T_AND; YY_BREAK case 10: YY_RULE_SETUP return T_OR; YY_BREAK case 11: YY_RULE_SETUP return T_OPEN_PAREN; YY_BREAK case 12: YY_RULE_SETUP return T_CLOSE_PAREN; YY_BREAK case 13: YY_RULE_SETUP return T_NOT; YY_BREAK case 14: YY_RULE_SETUP return T_EQUAL; YY_BREAK case 15: YY_RULE_SETUP return T_UNEQUAL; YY_BREAK case 16: YY_RULE_SETUP { str = zconftext[0]; new_string(); BEGIN(STRING); } YY_BREAK case 17: /* rule 17 can match eol */ YY_RULE_SETUP BEGIN(INITIAL); current_file->lineno++; return T_EOL; YY_BREAK case 18: YY_RULE_SETUP /* ignore */ YY_BREAK case 19: YY_RULE_SETUP { const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); if (id && id->flags & TF_PARAM) { zconflval.id = id; return id->token; } alloc_string(zconftext, zconfleng); zconflval.string = text; return T_WORD; } YY_BREAK case 20: YY_RULE_SETUP /* comment */ YY_BREAK case 21: /* rule 21 can match eol */ YY_RULE_SETUP current_file->lineno++; YY_BREAK case 22: YY_RULE_SETUP YY_BREAK case YY_STATE_EOF(PARAM): { BEGIN(INITIAL); } YY_BREAK case 23: /* rule 23 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up zconftext again */ YY_RULE_SETUP { append_string(zconftext, zconfleng); zconflval.string = text; return T_WORD_QUOTE; } YY_BREAK case 24: YY_RULE_SETUP { append_string(zconftext, zconfleng); } YY_BREAK case 25: /* rule 25 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up zconftext again */ YY_RULE_SETUP { append_string(zconftext + 1, zconfleng - 1); zconflval.string = text; return T_WORD_QUOTE; } YY_BREAK case 26: YY_RULE_SETUP { append_string(zconftext + 1, zconfleng - 1); } YY_BREAK case 27: YY_RULE_SETUP { if (str == zconftext[0]) { BEGIN(PARAM); zconflval.string = text; return T_WORD_QUOTE; } else append_string(zconftext, 1); } YY_BREAK case 28: /* rule 28 can match eol */ YY_RULE_SETUP { printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); current_file->lineno++; BEGIN(INITIAL); return T_EOL; } YY_BREAK case YY_STATE_EOF(STRING): { BEGIN(INITIAL); } YY_BREAK case 29: YY_RULE_SETUP { ts = 0; for (i = 0; i < zconfleng; i++) { if (zconftext[i] == '\t') ts = (ts & ~7) + 8; else ts++; } last_ts = ts; if (first_ts) { if (ts < first_ts) { zconf_endhelp(); return T_HELPTEXT; } ts -= first_ts; while (ts > 8) { append_string(" ", 8); ts -= 8; } append_string(" ", ts); } } YY_BREAK case 30: /* rule 30 can match eol */ *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ (yy_c_buf_p) = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up zconftext again */ YY_RULE_SETUP { current_file->lineno++; zconf_endhelp(); return T_HELPTEXT; } YY_BREAK case 31: /* rule 31 can match eol */ YY_RULE_SETUP { current_file->lineno++; append_string("\n", 1); } YY_BREAK case 32: YY_RULE_SETUP { while (zconfleng) { if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t')) break; zconfleng--; } append_string(zconftext, zconfleng); if (!first_ts) first_ts = last_ts; } YY_BREAK case YY_STATE_EOF(HELP): { zconf_endhelp(); return T_HELPTEXT; } YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(COMMAND): { if (current_file) { zconf_endfile(); return T_EOL; } fclose(zconfin); yyterminate(); } YY_BREAK case 33: YY_RULE_SETUP YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed zconfin at a new source and called * zconflex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( zconfwrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * zconftext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of zconflex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), (size_t) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; zconfrestart(zconfin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; yy_current_state = yy_nxt[yy_current_state][1]; yy_is_jam = (yy_current_state <= 0); return yy_is_jam ? 0 : yy_current_state; } static void yyunput (int c, register char * yy_bp ) { register char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up zconftext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = (yy_n_chars) + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ zconfrestart(zconfin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( zconfwrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve zconftext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void zconfrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ zconfensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = zconf_create_buffer(zconfin,YY_BUF_SIZE ); } zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); zconf_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * zconfpop_buffer_state(); * zconfpush_buffer_state(new_buffer); */ zconfensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; zconf_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (zconfwrap()) processing, but the only time this flag * is looked at is after zconfwrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void zconf_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); b->yy_is_our_buffer = 1; zconf_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with zconf_create_buffer() * */ void zconf_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) zconffree((void *) b->yy_ch_buf ); zconffree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a zconfrestart() or at EOF. */ static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; zconf_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then zconf_init_buffer was _probably_ * called from zconfrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void zconf_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) zconf_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; zconfensure_buffer_stack(); /* This block is copied from zconf_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from zconf_switch_to_buffer. */ zconf_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void zconfpop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; zconf_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { zconf_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void zconfensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; zconf_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to zconflex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * zconf_scan_bytes() instead. */ YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr ) { return zconf_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to zconflex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) zconfalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = zconf_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up zconftext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ zconftext[zconfleng] = (yy_hold_char); \ (yy_c_buf_p) = zconftext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ zconfleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int zconfget_lineno (void) { return zconflineno; } /** Get the input stream. * */ FILE *zconfget_in (void) { return zconfin; } /** Get the output stream. * */ FILE *zconfget_out (void) { return zconfout; } /** Get the length of the current token. * */ int zconfget_leng (void) { return zconfleng; } /** Get the current token. * */ char *zconfget_text (void) { return zconftext; } /** Set the current line number. * @param line_number * */ void zconfset_lineno (int line_number ) { zconflineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see zconf_switch_to_buffer */ void zconfset_in (FILE * in_str ) { zconfin = in_str ; } void zconfset_out (FILE * out_str ) { zconfout = out_str ; } int zconfget_debug (void) { return zconf_flex_debug; } void zconfset_debug (int bdebug ) { zconf_flex_debug = bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from zconflex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT zconfin = stdin; zconfout = stdout; #else zconfin = (FILE *) 0; zconfout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * zconflex_init() */ return 0; } /* zconflex_destroy is for both reentrant and non-reentrant scanners. */ int zconflex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ zconf_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; zconfpop_buffer_state(); } /* Destroy the stack itself. */ zconffree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * zconflex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *zconfalloc (yy_size_t size ) { return (void *) malloc( size ); } void *zconfrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void zconffree (void * ptr ) { free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" void zconf_starthelp(void) { new_string(); last_ts = first_ts = 0; BEGIN(HELP); } static void zconf_endhelp(void) { zconflval.string = text; BEGIN(INITIAL); } /* * Try to open specified file with following names: * ./name * $(srctree)/name * The latter is used when srctree is separate from objtree * when compiling the kernel. * Return NULL if file is not found. */ FILE *zconf_fopen(const char *name) { char *env, fullname[PATH_MAX+1]; FILE *f; f = fopen(name, "r"); if (!f && name != NULL && name[0] != '/') { env = getenv(SRCTREE); if (env) { sprintf(fullname, "%s/%s", env, name); f = fopen(fullname, "r"); } } return f; } void zconf_initscan(const char *name) { zconfin = zconf_fopen(name); if (!zconfin) { printf("can't find file %s\n", name); exit(1); } current_buf = xmalloc(sizeof(*current_buf)); memset(current_buf, 0, sizeof(*current_buf)); current_file = file_lookup(name); current_file->lineno = 1; } void zconf_nextfile(const char *name) { struct file *iter; struct file *file = file_lookup(name); struct buffer *buf = xmalloc(sizeof(*buf)); memset(buf, 0, sizeof(*buf)); current_buf->state = YY_CURRENT_BUFFER; zconfin = zconf_fopen(file->name); if (!zconfin) { printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), file->name); exit(1); } zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); buf->parent = current_buf; current_buf = buf; for (iter = current_file->parent; iter; iter = iter->parent ) { if (!strcmp(current_file->name,iter->name) ) { printf("%s:%d: recursive inclusion detected. " "Inclusion path:\n current file : '%s'\n", zconf_curname(), zconf_lineno(), zconf_curname()); iter = current_file->parent; while (iter && \ strcmp(iter->name,current_file->name)) { printf(" included from: '%s:%d'\n", iter->name, iter->lineno-1); iter = iter->parent; } if (iter) printf(" included from: '%s:%d'\n", iter->name, iter->lineno+1); exit(1); } } file->lineno = 1; file->parent = current_file; current_file = file; } static void zconf_endfile(void) { struct buffer *parent; current_file = current_file->parent; parent = current_buf->parent; if (parent) { fclose(zconfin); zconf_delete_buffer(YY_CURRENT_BUFFER); zconf_switch_to_buffer(parent->state); } free(current_buf); current_buf = parent; } int zconf_lineno(void) { return current_pos.lineno; } const char *zconf_curname(void) { return current_pos.file ? current_pos.file->name : ""; } ================================================ FILE: kconfig/zconf.tab.c_shipped ================================================ /* A Bison parser, made by GNU Bison 2.5. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.5" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* Substitute the variable and function names. */ #define yyparse zconfparse #define yylex zconflex #define yyerror zconferror #define yylval zconflval #define yychar zconfchar #define yydebug zconfdebug #define yynerrs zconfnerrs /* Copy the first part of user declarations. */ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include #include #include "lkc.h" #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) #define PRINTD 0x0001 #define DEBUG_PARSE 0x0002 int cdebug = PRINTD; extern int zconflex(void); static void zconfprint(const char *err, ...); static void zconf_error(const char *err, ...); static void zconferror(const char *err); static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 1 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { T_MAINMENU = 258, T_MENU = 259, T_ENDMENU = 260, T_SOURCE = 261, T_CHOICE = 262, T_ENDCHOICE = 263, T_COMMENT = 264, T_CONFIG = 265, T_MENUCONFIG = 266, T_HELP = 267, T_HELPTEXT = 268, T_IF = 269, T_ENDIF = 270, T_DEPENDS = 271, T_OPTIONAL = 272, T_PROMPT = 273, T_TYPE = 274, T_DEFAULT = 275, T_SELECT = 276, T_RANGE = 277, T_VISIBLE = 278, T_OPTION = 279, T_ON = 280, T_WORD = 281, T_WORD_QUOTE = 282, T_UNEQUAL = 283, T_CLOSE_PAREN = 284, T_OPEN_PAREN = 285, T_EOL = 286, T_OR = 287, T_AND = 288, T_EQUAL = 289, T_NOT = 290 }; #endif #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { char *string; struct file *file; struct symbol *symbol; struct expr *expr; struct menu *menu; const struct kconf_id *id; } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif /* Copy the second part of user declarations. */ /* Include zconf.hash.c here so it can see the token constants. */ #include "zconf.hash.c" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 11 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 290 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 36 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 50 /* YYNRULES -- Number of rules. */ #define YYNRULES 118 /* YYNRULES -- Number of states. */ #define YYNSTATES 191 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 290 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint16 yyprhs[] = { 0, 0, 3, 6, 8, 11, 13, 14, 17, 20, 23, 26, 31, 36, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 72, 75, 79, 82, 86, 89, 90, 93, 96, 99, 102, 105, 108, 112, 117, 122, 127, 133, 137, 138, 142, 143, 146, 150, 153, 155, 159, 160, 163, 166, 169, 172, 175, 180, 184, 187, 192, 193, 196, 200, 202, 206, 207, 210, 213, 216, 220, 224, 228, 230, 234, 235, 238, 241, 244, 248, 252, 255, 258, 261, 262, 265, 268, 271, 276, 277, 280, 283, 286, 287, 290, 292, 294, 297, 300, 303, 305, 308, 309, 312, 314, 318, 322, 326, 329, 333, 337, 339, 341, 342 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { 37, 0, -1, 81, 38, -1, 38, -1, 63, 39, -1, 39, -1, -1, 39, 41, -1, 39, 55, -1, 39, 67, -1, 39, 80, -1, 39, 26, 1, 31, -1, 39, 40, 1, 31, -1, 39, 1, 31, -1, 16, -1, 18, -1, 19, -1, 21, -1, 17, -1, 22, -1, 20, -1, 23, -1, 31, -1, 61, -1, 71, -1, 44, -1, 46, -1, 69, -1, 26, 1, 31, -1, 1, 31, -1, 10, 26, 31, -1, 43, 47, -1, 11, 26, 31, -1, 45, 47, -1, -1, 47, 48, -1, 47, 49, -1, 47, 75, -1, 47, 73, -1, 47, 42, -1, 47, 31, -1, 19, 78, 31, -1, 18, 79, 82, 31, -1, 20, 83, 82, 31, -1, 21, 26, 82, 31, -1, 22, 84, 84, 82, 31, -1, 24, 50, 31, -1, -1, 50, 26, 51, -1, -1, 34, 79, -1, 7, 85, 31, -1, 52, 56, -1, 80, -1, 53, 58, 54, -1, -1, 56, 57, -1, 56, 75, -1, 56, 73, -1, 56, 31, -1, 56, 42, -1, 18, 79, 82, 31, -1, 19, 78, 31, -1, 17, 31, -1, 20, 26, 82, 31, -1, -1, 58, 41, -1, 14, 83, 81, -1, 80, -1, 59, 62, 60, -1, -1, 62, 41, -1, 62, 67, -1, 62, 55, -1, 3, 79, 81, -1, 4, 79, 31, -1, 64, 76, 74, -1, 80, -1, 65, 68, 66, -1, -1, 68, 41, -1, 68, 67, -1, 68, 55, -1, 6, 79, 31, -1, 9, 79, 31, -1, 70, 74, -1, 12, 31, -1, 72, 13, -1, -1, 74, 75, -1, 74, 31, -1, 74, 42, -1, 16, 25, 83, 31, -1, -1, 76, 77, -1, 76, 31, -1, 23, 82, -1, -1, 79, 82, -1, 26, -1, 27, -1, 5, 31, -1, 8, 31, -1, 15, 31, -1, 31, -1, 81, 31, -1, -1, 14, 83, -1, 84, -1, 84, 34, 84, -1, 84, 28, 84, -1, 30, 83, 29, -1, 35, 83, -1, 83, 32, 83, -1, 83, 33, 83, -1, 26, -1, 27, -1, -1, 26, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 103, 103, 103, 105, 105, 107, 109, 110, 111, 112, 113, 114, 118, 122, 122, 122, 122, 122, 122, 122, 122, 126, 127, 128, 129, 130, 131, 135, 136, 142, 150, 156, 164, 174, 176, 177, 178, 179, 180, 181, 184, 192, 198, 208, 214, 220, 223, 225, 236, 237, 242, 251, 256, 264, 267, 269, 270, 271, 272, 273, 276, 282, 293, 299, 309, 311, 316, 324, 332, 335, 337, 338, 339, 344, 351, 358, 363, 371, 374, 376, 377, 378, 381, 389, 396, 403, 409, 416, 418, 419, 420, 423, 431, 433, 434, 437, 444, 446, 451, 452, 455, 456, 457, 461, 462, 465, 466, 469, 470, 471, 472, 473, 474, 475, 478, 479, 482, 483 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", "common_stmt", "option_error", "config_entry_start", "config_stmt", "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", "config_option", "symbol_option", "symbol_option_list", "symbol_option_arg", "choice", "choice_entry", "choice_end", "choice_stmt", "choice_option_list", "choice_option", "choice_block", "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment", "comment_stmt", "help_start", "help", "depends_list", "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 36, 37, 37, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 42, 42, 43, 44, 45, 46, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 49, 50, 50, 51, 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 59, 60, 61, 62, 62, 62, 62, 63, 64, 65, 66, 67, 68, 68, 68, 68, 69, 70, 71, 72, 73, 74, 74, 74, 74, 75, 76, 76, 76, 77, 78, 78, 79, 79, 80, 80, 80, 81, 81, 82, 82, 83, 83, 83, 83, 83, 83, 83, 84, 84, 85, 85 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 2, 1, 2, 1, 0, 2, 2, 2, 2, 4, 4, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 3, 2, 3, 2, 0, 2, 2, 2, 2, 2, 2, 3, 4, 4, 4, 5, 3, 0, 3, 0, 2, 3, 2, 1, 3, 0, 2, 2, 2, 2, 2, 4, 3, 2, 4, 0, 2, 3, 1, 3, 0, 2, 2, 2, 3, 3, 3, 1, 3, 0, 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, 2, 2, 4, 0, 2, 2, 2, 0, 2, 1, 1, 2, 2, 2, 1, 2, 0, 2, 1, 3, 3, 3, 2, 3, 3, 1, 1, 0, 1 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. Performed when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 6, 0, 104, 0, 3, 0, 6, 6, 99, 100, 0, 1, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 14, 18, 15, 16, 20, 17, 19, 21, 0, 22, 0, 7, 34, 25, 34, 26, 55, 65, 8, 70, 23, 93, 79, 9, 27, 88, 24, 10, 0, 105, 2, 74, 13, 0, 101, 0, 118, 0, 102, 0, 0, 0, 115, 116, 0, 0, 0, 108, 103, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 75, 83, 51, 84, 30, 32, 0, 112, 0, 0, 67, 0, 0, 11, 12, 0, 0, 0, 0, 97, 0, 0, 0, 47, 0, 40, 39, 35, 36, 0, 38, 37, 0, 0, 97, 0, 59, 60, 56, 58, 57, 66, 54, 53, 71, 73, 69, 72, 68, 106, 95, 0, 94, 80, 82, 78, 81, 77, 90, 91, 89, 111, 113, 114, 110, 109, 29, 86, 0, 106, 0, 106, 106, 106, 0, 0, 0, 87, 63, 106, 0, 106, 0, 96, 0, 0, 41, 98, 0, 0, 106, 49, 46, 28, 0, 62, 0, 107, 92, 42, 43, 44, 0, 0, 48, 61, 64, 45, 50 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 3, 4, 5, 33, 34, 108, 35, 36, 37, 38, 74, 109, 110, 157, 186, 39, 40, 124, 41, 76, 120, 77, 42, 128, 43, 78, 6, 44, 45, 137, 46, 80, 47, 48, 49, 111, 112, 81, 113, 79, 134, 152, 153, 50, 7, 165, 69, 70, 60 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -90 static const yytype_int16 yypact[] = { 4, 42, -90, 96, -90, 111, -90, 15, -90, -90, 75, -90, 82, 42, 104, 42, 110, 107, 42, 115, 125, -4, 121, -90, -90, -90, -90, -90, -90, -90, -90, 162, -90, 163, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, 139, -90, -90, 138, -90, 142, -90, 143, -90, 152, -90, 164, 167, 168, -90, -90, -4, -4, 77, -18, -90, 177, 185, 33, 71, 195, 247, 236, -2, 236, 171, -90, -90, -90, -90, -90, -90, 41, -90, -4, -4, 138, 97, 97, -90, -90, 186, 187, 194, 42, 42, -4, 196, 97, -90, 219, -90, -90, -90, -90, 210, -90, -90, 204, 42, 42, 199, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, 222, -90, 223, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, 215, -90, -90, -90, -90, -90, -4, 222, 228, 222, -5, 222, 97, 35, 229, -90, -90, 222, 232, 222, -4, -90, 135, 233, -90, -90, 234, 235, 222, 240, -90, -90, 237, -90, 239, -13, -90, -90, -90, -90, 244, 42, -90, -90, -90, -90, -90 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -90, -90, 269, 271, -90, 23, -70, -90, -90, -90, -90, 243, -90, -90, -90, -90, -90, -90, -90, -48, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, -20, -90, -90, -90, -90, -90, 206, 205, -68, -90, -90, 169, -1, 27, -7, 118, -66, -89, -90 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -86 static const yytype_int16 yytable[] = { 10, 88, 89, 54, 146, 147, 119, 1, 122, 164, 93, 141, 56, 142, 58, 156, 94, 62, 1, 90, 91, 131, 65, 66, 144, 145, 67, 90, 91, 132, 127, 68, 136, -31, 97, 2, 154, -31, -31, -31, -31, -31, -31, -31, -31, 98, 52, -31, -31, 99, -31, 100, 101, 102, 103, 104, -31, 105, 129, 106, 138, 173, 92, 141, 107, 142, 174, 172, 8, 9, 143, -33, 97, 90, 91, -33, -33, -33, -33, -33, -33, -33, -33, 98, 166, -33, -33, 99, -33, 100, 101, 102, 103, 104, -33, 105, 11, 106, 179, 151, 123, 126, 107, 135, 125, 130, 2, 139, 2, 90, 91, -5, 12, 55, 161, 13, 14, 15, 16, 17, 18, 19, 20, 65, 66, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 57, 59, 31, 61, -4, 12, 63, 32, 13, 14, 15, 16, 17, 18, 19, 20, 64, 71, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 72, 73, 31, 180, 90, 91, 52, 32, -85, 97, 82, 83, -85, -85, -85, -85, -85, -85, -85, -85, 84, 190, -85, -85, 99, -85, -85, -85, -85, -85, -85, -85, 85, 97, 106, 86, 87, -52, -52, 140, -52, -52, -52, -52, 98, 95, -52, -52, 99, 114, 115, 116, 117, 96, 148, 149, 150, 158, 106, 155, 159, 97, 163, 118, -76, -76, -76, -76, -76, -76, -76, -76, 160, 164, -76, -76, 99, 13, 14, 15, 16, 17, 18, 19, 20, 91, 106, 21, 22, 14, 15, 140, 17, 18, 19, 20, 168, 175, 21, 22, 177, 181, 182, 183, 32, 187, 167, 188, 169, 170, 171, 185, 189, 53, 51, 32, 176, 75, 178, 121, 0, 133, 162, 0, 0, 0, 0, 184 }; #define yypact_value_is_default(yystate) \ ((yystate) == (-90)) #define yytable_value_is_error(yytable_value) \ YYID (0) static const yytype_int16 yycheck[] = { 1, 67, 68, 10, 93, 94, 76, 3, 76, 14, 28, 81, 13, 81, 15, 104, 34, 18, 3, 32, 33, 23, 26, 27, 90, 91, 30, 32, 33, 31, 78, 35, 80, 0, 1, 31, 102, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 78, 26, 80, 26, 69, 133, 31, 133, 31, 156, 26, 27, 29, 0, 1, 32, 33, 4, 5, 6, 7, 8, 9, 10, 11, 12, 150, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 26, 164, 100, 77, 78, 31, 80, 77, 78, 31, 80, 31, 32, 33, 0, 1, 31, 115, 4, 5, 6, 7, 8, 9, 10, 11, 26, 27, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 31, 26, 26, 31, 0, 1, 26, 31, 4, 5, 6, 7, 8, 9, 10, 11, 26, 31, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 1, 1, 26, 31, 32, 33, 31, 31, 0, 1, 31, 31, 4, 5, 6, 7, 8, 9, 10, 11, 31, 185, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 31, 1, 26, 31, 31, 5, 6, 31, 8, 9, 10, 11, 12, 31, 14, 15, 16, 17, 18, 19, 20, 31, 31, 31, 25, 1, 26, 26, 13, 1, 26, 31, 4, 5, 6, 7, 8, 9, 10, 11, 31, 14, 14, 15, 16, 4, 5, 6, 7, 8, 9, 10, 11, 33, 26, 14, 15, 5, 6, 31, 8, 9, 10, 11, 31, 31, 14, 15, 31, 31, 31, 31, 31, 31, 151, 31, 153, 154, 155, 34, 31, 7, 6, 31, 161, 37, 163, 76, -1, 79, 116, -1, -1, -1, -1, 172 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 3, 31, 37, 38, 39, 63, 81, 26, 27, 79, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 26, 31, 40, 41, 43, 44, 45, 46, 52, 53, 55, 59, 61, 64, 65, 67, 69, 70, 71, 80, 39, 31, 38, 81, 31, 79, 31, 79, 26, 85, 31, 79, 26, 26, 26, 27, 30, 35, 83, 84, 31, 1, 1, 47, 47, 56, 58, 62, 76, 68, 74, 31, 31, 31, 31, 31, 31, 83, 83, 32, 33, 81, 28, 34, 31, 31, 1, 12, 16, 18, 19, 20, 21, 22, 24, 26, 31, 42, 48, 49, 72, 73, 75, 17, 18, 19, 20, 31, 42, 57, 73, 75, 41, 54, 80, 41, 55, 60, 67, 80, 23, 31, 74, 77, 41, 55, 66, 67, 80, 31, 42, 75, 29, 83, 83, 84, 84, 31, 31, 25, 79, 78, 79, 83, 26, 84, 50, 1, 13, 31, 79, 78, 26, 14, 82, 83, 82, 31, 82, 82, 82, 84, 26, 31, 31, 82, 31, 82, 83, 31, 31, 31, 31, 82, 34, 51, 31, 31, 31, 79 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. However, YYFAIL appears to be in use. Nevertheless, it is formally deprecated in Bison 2.4.2's NEWS entry, where a plan to phase it out is discussed. */ #define YYFAIL goto yyerrlab #if defined YYFAIL /* This is here to suppress warnings from the GCC cpp's -Wunused-macros. Normally we don't worry about that warning, but some users do, and we want to make it easy for users to remove YYFAIL uses, which will produce warnings from Bison 2.5. */ #endif #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = 0; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - Assume YYFAIL is not used. It's too flawed to consider. See for details. YYERROR is fine as it does not invoke this function. - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { case 53: /* "choice_entry" */ { fprintf(stderr, "%s:%d: missing end statement for this entry\n", (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); if (current_menu == (yyvaluep->menu)) menu_end_menu(); }; break; case 59: /* "if_entry" */ { fprintf(stderr, "%s:%d: missing end statement for this entry\n", (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); if (current_menu == (yyvaluep->menu)) menu_end_menu(); }; break; case 65: /* "menu_entry" */ { fprintf(stderr, "%s:%d: missing end statement for this entry\n", (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); if (current_menu == (yyvaluep->menu)) menu_end_menu(); }; break; default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yytoken = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 10: { zconf_error("unexpected end statement"); } break; case 11: { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); } break; case 12: { zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); } break; case 13: { zconf_error("invalid statement"); } break; case 28: { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); } break; case 29: { zconf_error("invalid option"); } break; case 30: { struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); } break; case 31: { menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); } break; case 32: { struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); } break; case 33: { if (current_entry->prompt) current_entry->prompt->type = P_MENU; else zconfprint("warning: menuconfig statement without prompt"); menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); } break; case 41: { menu_set_type((yyvsp[(1) - (3)].id)->stype); printd(DEBUG_PARSE, "%s:%d:type(%u)\n", zconf_curname(), zconf_lineno(), (yyvsp[(1) - (3)].id)->stype); } break; case 42: { menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); } break; case 43: { menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN) menu_set_type((yyvsp[(1) - (4)].id)->stype); printd(DEBUG_PARSE, "%s:%d:default(%u)\n", zconf_curname(), zconf_lineno(), (yyvsp[(1) - (4)].id)->stype); } break; case 44: { menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); } break; case 45: { menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); } break; case 48: { const struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); if (id && id->flags & TF_OPTION) menu_add_option(id->token, (yyvsp[(3) - (3)].string)); else zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); free((yyvsp[(2) - (3)].string)); } break; case 49: { (yyval.string) = NULL; } break; case 50: { (yyval.string) = (yyvsp[(2) - (2)].string); } break; case 51: { struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); sym->flags |= SYMBOL_AUTO; menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); } break; case 52: { (yyval.menu) = menu_add_menu(); } break; case 53: { if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); } } break; case 61: { menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); } break; case 62: { if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { menu_set_type((yyvsp[(1) - (3)].id)->stype); printd(DEBUG_PARSE, "%s:%d:type(%u)\n", zconf_curname(), zconf_lineno(), (yyvsp[(1) - (3)].id)->stype); } else YYERROR; } break; case 63: { current_entry->sym->flags |= SYMBOL_OPTIONAL; printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); } break; case 64: { if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); } else YYERROR; } break; case 67: { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); menu_add_entry(NULL); menu_add_dep((yyvsp[(2) - (3)].expr)); (yyval.menu) = menu_add_menu(); } break; case 68: { if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); } } break; case 74: { menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); } break; case 75: { menu_add_entry(NULL); menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); } break; case 76: { (yyval.menu) = menu_add_menu(); } break; case 77: { if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); } } break; case 83: { printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); zconf_nextfile((yyvsp[(2) - (3)].string)); } break; case 84: { menu_add_entry(NULL); menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); } break; case 85: { menu_end_entry(); } break; case 86: { printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); zconf_starthelp(); } break; case 87: { current_entry->help = (yyvsp[(2) - (2)].string); } break; case 92: { menu_add_dep((yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); } break; case 96: { menu_add_visibility((yyvsp[(2) - (2)].expr)); } break; case 98: { menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); } break; case 101: { (yyval.id) = (yyvsp[(1) - (2)].id); } break; case 102: { (yyval.id) = (yyvsp[(1) - (2)].id); } break; case 103: { (yyval.id) = (yyvsp[(1) - (2)].id); } break; case 106: { (yyval.expr) = NULL; } break; case 107: { (yyval.expr) = (yyvsp[(2) - (2)].expr); } break; case 108: { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); } break; case 109: { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } break; case 110: { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } break; case 111: { (yyval.expr) = (yyvsp[(2) - (3)].expr); } break; case 112: { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); } break; case 113: { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 114: { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 115: { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); } break; case 116: { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); } break; case 117: { (yyval.string) = NULL; } break; default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } *++yyvsp = yylval; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } void conf_parse(const char *name) { struct symbol *sym; int i; zconf_initscan(name); sym_init(); _menu_init(); rootmenu.prompt = menu_add_prompt(P_MENU, "FROSTED kernel configuration", NULL); if (getenv("ZCONF_DEBUG")) zconfdebug = 1; zconfparse(); if (zconfnerrs) exit(1); if (!modules_sym) modules_sym = sym_find( "n" ); rootmenu.prompt->text = _(rootmenu.prompt->text); rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); menu_finalize(&rootmenu); for_all_symbols(i, sym) { if (sym_check_deps(sym)) zconfnerrs++; } if (zconfnerrs) exit(1); sym_set_change_count(1); } static const char *zconf_tokenname(int token) { switch (token) { case T_MENU: return "menu"; case T_ENDMENU: return "endmenu"; case T_CHOICE: return "choice"; case T_ENDCHOICE: return "endchoice"; case T_IF: return "if"; case T_ENDIF: return "endif"; case T_DEPENDS: return "depends"; case T_VISIBLE: return "visible"; } return ""; } static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) { if (id->token != endtoken) { zconf_error("unexpected '%s' within %s block", kconf_id_strings + id->name, zconf_tokenname(starttoken)); zconfnerrs++; return false; } if (current_menu->file != current_file) { zconf_error("'%s' in different file than '%s'", kconf_id_strings + id->name, zconf_tokenname(starttoken)); fprintf(stderr, "%s:%d: location of the '%s'\n", current_menu->file->name, current_menu->lineno, zconf_tokenname(starttoken)); zconfnerrs++; return false; } return true; } static void zconfprint(const char *err, ...) { va_list ap; fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); fprintf(stderr, "\n"); } static void zconf_error(const char *err, ...) { va_list ap; zconfnerrs++; fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); fprintf(stderr, "\n"); } static void zconferror(const char *err) { fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); } static void print_quoted_string(FILE *out, const char *str) { const char *p; int len; putc('"', out); while ((p = strchr(str, '"'))) { len = p - str; if (len) fprintf(out, "%.*s", len, str); fputs("\\\"", out); str = p + 1; } fputs(str, out); putc('"', out); } static void print_symbol(FILE *out, struct menu *menu) { struct symbol *sym = menu->sym; struct property *prop; if (sym_is_choice(sym)) fprintf(out, "\nchoice\n"); else fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: fputs(" boolean\n", out); break; case S_TRISTATE: fputs(" tristate\n", out); break; case S_STRING: fputs(" string\n", out); break; case S_INT: fputs(" integer\n", out); break; case S_HEX: fputs(" hex\n", out); break; default: fputs(" ???\n", out); break; } for (prop = sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; switch (prop->type) { case P_PROMPT: fputs(" prompt ", out); print_quoted_string(out, prop->text); if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_DEFAULT: fputs( " default ", out); expr_fprint(prop->expr, out); if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_CHOICE: fputs(" #choice value\n", out); break; case P_SELECT: fputs( " select ", out); expr_fprint(prop->expr, out); fputc('\n', out); break; case P_RANGE: fputs( " range ", out); expr_fprint(prop->expr, out); fputc('\n', out); break; case P_MENU: fputs( " menu ", out); print_quoted_string(out, prop->text); fputc('\n', out); break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; } } if (menu->help) { int len = strlen(menu->help); while (menu->help[--len] == '\n') menu->help[len] = 0; fprintf(out, " help\n%s\n", menu->help); } } void zconfdump(FILE *out) { struct property *prop; struct symbol *sym; struct menu *menu; menu = rootmenu.list; while (menu) { if ((sym = menu->sym)) print_symbol(out, menu); else if ((prop = menu->prompt)) { switch (prop->type) { case P_COMMENT: fputs("\ncomment ", out); print_quoted_string(out, prop->text); fputs("\n", out); break; case P_MENU: fputs("\nmenu ", out); print_quoted_string(out, prop->text); fputs("\n", out); break; default: ; } if (!expr_is_yes(prop->visible.expr)) { fputs(" depends ", out); expr_fprint(prop->visible.expr, out); fputc('\n', out); } } if (menu->list) menu = menu->list; else if (menu->next) menu = menu->next; else while ((menu = menu->parent)) { if (menu->prompt && menu->prompt->type == P_MENU) fputs("\nendmenu\n", out); if (menu->next) { menu = menu->next; break; } } } } #include "zconf.lex.c" #include "util.c" #include "confdata.c" #include "expr.c" #include "symbol.c" #include "menu.c" ================================================ FILE: kconfig/zconf.y ================================================ %{ /* * Copyright (C) 2002 Roman Zippel * Released under the terms of the GNU GPL v2.0. */ #include #include #include #include #include #include #include "lkc.h" #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) #define PRINTD 0x0001 #define DEBUG_PARSE 0x0002 int cdebug = PRINTD; extern int zconflex(void); static void zconfprint(const char *err, ...); static void zconf_error(const char *err, ...); static void zconferror(const char *err); static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; %} %expect 30 %union { char *string; struct file *file; struct symbol *symbol; struct expr *expr; struct menu *menu; const struct kconf_id *id; } %token T_MAINMENU %token T_MENU %token T_ENDMENU %token T_SOURCE %token T_CHOICE %token T_ENDCHOICE %token T_COMMENT %token T_CONFIG %token T_MENUCONFIG %token T_HELP %token T_HELPTEXT %token T_IF %token T_ENDIF %token T_DEPENDS %token T_OPTIONAL %token T_PROMPT %token T_TYPE %token T_DEFAULT %token T_SELECT %token T_RANGE %token T_VISIBLE %token T_OPTION %token T_ON %token T_WORD %token T_WORD_QUOTE %token T_UNEQUAL %token T_CLOSE_PAREN %token T_OPEN_PAREN %token T_EOL %left T_OR %left T_AND %left T_EQUAL T_UNEQUAL %nonassoc T_NOT %type prompt %type symbol %type expr %type if_expr %type end %type option_name %type if_entry menu_entry choice_entry %type symbol_option_arg word_opt %destructor { fprintf(stderr, "%s:%d: missing end statement for this entry\n", $$->file->name, $$->lineno); if (current_menu == $$) menu_end_menu(); } if_entry menu_entry choice_entry %{ /* Include zconf.hash.c here so it can see the token constants. */ #include "zconf.hash.c" %} %% input: nl start | start; start: mainmenu_stmt stmt_list | stmt_list; stmt_list: /* empty */ | stmt_list common_stmt | stmt_list choice_stmt | stmt_list menu_stmt | stmt_list end { zconf_error("unexpected end statement"); } | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } | stmt_list option_name error T_EOL { zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); } | stmt_list error T_EOL { zconf_error("invalid statement"); } ; option_name: T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE ; common_stmt: T_EOL | if_stmt | comment_stmt | config_stmt | menuconfig_stmt | source_stmt ; option_error: T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } | error T_EOL { zconf_error("invalid option"); } ; /* config/menuconfig entry */ config_entry_start: T_CONFIG T_WORD T_EOL { struct symbol *sym = sym_lookup($2, 0); sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); }; config_stmt: config_entry_start config_option_list { menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); }; menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL { struct symbol *sym = sym_lookup($2, 0); sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); }; menuconfig_stmt: menuconfig_entry_start config_option_list { if (current_entry->prompt) current_entry->prompt->type = P_MENU; else zconfprint("warning: menuconfig statement without prompt"); menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); }; config_option_list: /* empty */ | config_option_list config_option | config_option_list symbol_option | config_option_list depends | config_option_list help | config_option_list option_error | config_option_list T_EOL ; config_option: T_TYPE prompt_stmt_opt T_EOL { menu_set_type($1->stype); printd(DEBUG_PARSE, "%s:%d:type(%u)\n", zconf_curname(), zconf_lineno(), $1->stype); }; config_option: T_PROMPT prompt if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; config_option: T_DEFAULT expr if_expr T_EOL { menu_add_expr(P_DEFAULT, $2, $3); if ($1->stype != S_UNKNOWN) menu_set_type($1->stype); printd(DEBUG_PARSE, "%s:%d:default(%u)\n", zconf_curname(), zconf_lineno(), $1->stype); }; config_option: T_SELECT T_WORD if_expr T_EOL { menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); }; config_option: T_RANGE symbol symbol if_expr T_EOL { menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); }; symbol_option: T_OPTION symbol_option_list T_EOL ; symbol_option_list: /* empty */ | symbol_option_list T_WORD symbol_option_arg { const struct kconf_id *id = kconf_id_lookup($2, strlen($2)); if (id && id->flags & TF_OPTION) menu_add_option(id->token, $3); else zconfprint("warning: ignoring unknown option %s", $2); free($2); }; symbol_option_arg: /* empty */ { $$ = NULL; } | T_EQUAL prompt { $$ = $2; } ; /* choice entry */ choice: T_CHOICE word_opt T_EOL { struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); sym->flags |= SYMBOL_AUTO; menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); }; choice_entry: choice choice_option_list { $$ = menu_add_menu(); }; choice_end: end { if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); } }; choice_stmt: choice_entry choice_block choice_end ; choice_option_list: /* empty */ | choice_option_list choice_option | choice_option_list depends | choice_option_list help | choice_option_list T_EOL | choice_option_list option_error ; choice_option: T_PROMPT prompt if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; choice_option: T_TYPE prompt_stmt_opt T_EOL { if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { menu_set_type($1->stype); printd(DEBUG_PARSE, "%s:%d:type(%u)\n", zconf_curname(), zconf_lineno(), $1->stype); } else YYERROR; }; choice_option: T_OPTIONAL T_EOL { current_entry->sym->flags |= SYMBOL_OPTIONAL; printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); }; choice_option: T_DEFAULT T_WORD if_expr T_EOL { if ($1->stype == S_UNKNOWN) { menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); } else YYERROR; }; choice_block: /* empty */ | choice_block common_stmt ; /* if entry */ if_entry: T_IF expr nl { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); menu_add_entry(NULL); menu_add_dep($2); $$ = menu_add_menu(); }; if_end: end { if (zconf_endtoken($1, T_IF, T_ENDIF)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); } }; if_stmt: if_entry if_block if_end ; if_block: /* empty */ | if_block common_stmt | if_block menu_stmt | if_block choice_stmt ; /* mainmenu entry */ mainmenu_stmt: T_MAINMENU prompt nl { menu_add_prompt(P_MENU, $2, NULL); }; /* menu entry */ menu: T_MENU prompt T_EOL { menu_add_entry(NULL); menu_add_prompt(P_MENU, $2, NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); }; menu_entry: menu visibility_list depends_list { $$ = menu_add_menu(); }; menu_end: end { if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); } }; menu_stmt: menu_entry menu_block menu_end ; menu_block: /* empty */ | menu_block common_stmt | menu_block menu_stmt | menu_block choice_stmt ; source_stmt: T_SOURCE prompt T_EOL { printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); zconf_nextfile($2); }; /* comment entry */ comment: T_COMMENT prompt T_EOL { menu_add_entry(NULL); menu_add_prompt(P_COMMENT, $2, NULL); printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); }; comment_stmt: comment depends_list { menu_end_entry(); }; /* help option */ help_start: T_HELP T_EOL { printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); zconf_starthelp(); }; help: help_start T_HELPTEXT { current_entry->help = $2; }; /* depends option */ depends_list: /* empty */ | depends_list depends | depends_list T_EOL | depends_list option_error ; depends: T_DEPENDS T_ON expr T_EOL { menu_add_dep($3); printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); }; /* visibility option */ visibility_list: /* empty */ | visibility_list visible | visibility_list T_EOL ; visible: T_VISIBLE if_expr { menu_add_visibility($2); }; /* prompt statement */ prompt_stmt_opt: /* empty */ | prompt if_expr { menu_add_prompt(P_PROMPT, $1, $2); }; prompt: T_WORD | T_WORD_QUOTE ; end: T_ENDMENU T_EOL { $$ = $1; } | T_ENDCHOICE T_EOL { $$ = $1; } | T_ENDIF T_EOL { $$ = $1; } ; nl: T_EOL | nl T_EOL ; if_expr: /* empty */ { $$ = NULL; } | T_IF expr { $$ = $2; } ; expr: symbol { $$ = expr_alloc_symbol($1); } | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } ; symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } ; word_opt: /* empty */ { $$ = NULL; } | T_WORD %% void conf_parse(const char *name) { struct symbol *sym; int i; zconf_initscan(name); sym_init(); _menu_init(); rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); if (getenv("ZCONF_DEBUG")) zconfdebug = 1; zconfparse(); if (zconfnerrs) exit(1); if (!modules_sym) modules_sym = sym_find( "n" ); rootmenu.prompt->text = _(rootmenu.prompt->text); rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); menu_finalize(&rootmenu); for_all_symbols(i, sym) { if (sym_check_deps(sym)) zconfnerrs++; } if (zconfnerrs) exit(1); sym_set_change_count(1); } static const char *zconf_tokenname(int token) { switch (token) { case T_MENU: return "menu"; case T_ENDMENU: return "endmenu"; case T_CHOICE: return "choice"; case T_ENDCHOICE: return "endchoice"; case T_IF: return "if"; case T_ENDIF: return "endif"; case T_DEPENDS: return "depends"; case T_VISIBLE: return "visible"; } return ""; } static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) { if (id->token != endtoken) { zconf_error("unexpected '%s' within %s block", kconf_id_strings + id->name, zconf_tokenname(starttoken)); zconfnerrs++; return false; } if (current_menu->file != current_file) { zconf_error("'%s' in different file than '%s'", kconf_id_strings + id->name, zconf_tokenname(starttoken)); fprintf(stderr, "%s:%d: location of the '%s'\n", current_menu->file->name, current_menu->lineno, zconf_tokenname(starttoken)); zconfnerrs++; return false; } return true; } static void zconfprint(const char *err, ...) { va_list ap; fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); fprintf(stderr, "\n"); } static void zconf_error(const char *err, ...) { va_list ap; zconfnerrs++; fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); fprintf(stderr, "\n"); } static void zconferror(const char *err) { fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); } static void print_quoted_string(FILE *out, const char *str) { const char *p; int len; putc('"', out); while ((p = strchr(str, '"'))) { len = p - str; if (len) fprintf(out, "%.*s", len, str); fputs("\\\"", out); str = p + 1; } fputs(str, out); putc('"', out); } static void print_symbol(FILE *out, struct menu *menu) { struct symbol *sym = menu->sym; struct property *prop; if (sym_is_choice(sym)) fprintf(out, "\nchoice\n"); else fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: fputs(" boolean\n", out); break; case S_TRISTATE: fputs(" tristate\n", out); break; case S_STRING: fputs(" string\n", out); break; case S_INT: fputs(" integer\n", out); break; case S_HEX: fputs(" hex\n", out); break; default: fputs(" ???\n", out); break; } for (prop = sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; switch (prop->type) { case P_PROMPT: fputs(" prompt ", out); print_quoted_string(out, prop->text); if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_DEFAULT: fputs( " default ", out); expr_fprint(prop->expr, out); if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_CHOICE: fputs(" #choice value\n", out); break; case P_SELECT: fputs( " select ", out); expr_fprint(prop->expr, out); fputc('\n', out); break; case P_RANGE: fputs( " range ", out); expr_fprint(prop->expr, out); fputc('\n', out); break; case P_MENU: fputs( " menu ", out); print_quoted_string(out, prop->text); fputc('\n', out); break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; } } if (menu->help) { int len = strlen(menu->help); while (menu->help[--len] == '\n') menu->help[len] = 0; fprintf(out, " help\n%s\n", menu->help); } } void zconfdump(FILE *out) { struct property *prop; struct symbol *sym; struct menu *menu; menu = rootmenu.list; while (menu) { if ((sym = menu->sym)) print_symbol(out, menu); else if ((prop = menu->prompt)) { switch (prop->type) { case P_COMMENT: fputs("\ncomment ", out); print_quoted_string(out, prop->text); fputs("\n", out); break; case P_MENU: fputs("\nmenu ", out); print_quoted_string(out, prop->text); fputs("\n", out); break; default: ; } if (!expr_is_yes(prop->visible.expr)) { fputs(" depends ", out); expr_fprint(prop->visible.expr, out); fputc('\n', out); } } if (menu->list) menu = menu->list; else if (menu->next) menu = menu->next; else while ((menu = menu->parent)) { if (menu->prompt && menu->prompt->type == P_MENU) fputs("\nendmenu\n", out); if (menu->next) { menu = menu->next; break; } } } } #include "zconf.lex.c" #include "util.c" #include "confdata.c" #include "expr.c" #include "symbol.c" #include "menu.c" ================================================ FILE: kernel/Kconfig ================================================ menu "Compiler options" config GDB_CFLAG bool "Keep debugging symbols" default y choice prompt "Compiler optimization" config OPTIMIZE_NONE bool "No optimization" config OPTIMIZE_SIZE bool "Optimize for size" config OPTIMIZE_PERF bool "Optimize for performance" endchoice endmenu menu "Platform Selection" choice ARCH prompt "Architecture" default ARCH_LM3S config ARCH_LM3S bool "LM3S" help Enable support for Stellaris LM3S systems config ARCH_LPC17XX bool "LPC17XX" help Enable support for NXP LPC17xx systems config ARCH_STM32F4 bool "STM32F4" help Enable support for ST STM32F4 systems config ARCH_STM32F7 bool "STM32F7" help Enable support for ST STM32F7 systems config ARCH_NRF51 bool "NRF51" help Enable support for Nordic NRF51 systems config ARCH_NRF52 bool "NRF52" help Enable support for Nordic NRF52 systems endchoice source "../kernel/stm32f7/Kconfig" source "../kernel/stm32f4/Kconfig" source "../kernel/lpc17xx/Kconfig" source "../kernel/lm3s/Kconfig" source "../kernel/nrf51/Kconfig" source "../kernel/nrf52/Kconfig" config FLASH_SIZE_2MB bool config FLASH_SIZE_1MB bool config FLASH_SIZE_512KB bool config FLASH_SIZE_384KB bool config FLASH_SIZE_256KB bool config FLASH_SIZE_192KB bool config FLASH_SIZE_128KB bool config RAM_SIZE_368KB bool config RAM_SIZE_320KB bool config RAM_SIZE_256KB bool config RAM_SIZE_192KB bool config RAM_SIZE_128KB bool config RAM_SIZE_96KB bool config RAM_SIZE_64KB bool config RAM_SIZE_32KB bool config RAM_SIZE_24KB bool config RAM_SIZE_16KB bool config ARCH_STM32F401 bool config ARCH_STM32F405 bool config ARCH_STM32F407 bool config ARCH_STM32F411 bool config ARCH_STM32F429 bool config ARCH_STM32F446 bool config ARCH_STM32F746 bool config ARCH_STM32F769 bool config DEVSTM32DMA bool #Temp hack to allow '407 & '411 clock setups to coexist choice prompt "Clock Speed" config CLK_16MHZ bool "16MHz" depends on (ARCH_NRF51) config CLK_48MHZ bool "48MHz" depends on (ARCH_STM32F401 || ARCH_STM32F411 || ARCH_STM32F429) || ARCH_STM32F407 || ARCH_STM32F405 config CLK_84MHZ bool "84MHz" depends on (ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F429 || ARCH_NRF52) || ARCH_STM32F407 || ARCH_STM32F405 config CLK_100MHZ bool "100MHz" depends on ARCH_LPC17XX || ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 config CLK_120MHZ bool "120MHz" depends on (ARCH_STM32F407 || ARCH_STM32F405 || ARCH_LPC1769) config CLK_168MHZ bool "168MHz" depends on (ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F429) config CLK_180MHZ bool "180MHz" depends on (ARCH_STM32F446) config CLK_216MHZ bool "216MHZ" depends on (ARCH_STM32F746 || ARCH_STM32F769) endchoice choice prompt "Board" default MACH_STM32F407Discovery config MACH_STM32F746Discovery bool "STM32F746 Discovery" depends on (ARCH_STM32F746) config MACH_STM32F769Discovery bool "STM32F769 Discovery" depends on (ARCH_STM32F769) config MACH_STM32F746Nucleo144 bool "STM32F746 Nucleo-144" depends on (ARCH_STM32F746) config MACH_STM32F407Discovery bool "STM32F407Discovery" depends on (ARCH_STM32F407) config MACH_STM32F405Pyboard10 bool "STM32F405 PyBoard v1.0 (micropython)" depends on (ARCH_STM32F405) config MACH_STM32F405Pyboard11 bool "STM32F405 PyBoard v1.1 (micropython)" depends on (ARCH_STM32F405) config MACH_STM32F411Pyboard11lite bool "STM32F411 PyBoard v1.1 lite (micropython)" depends on (ARCH_STM32F411) config MACH_STM32F4x1Discovery bool "STM32F4x1Discovery" depends on ( ARCH_STM32F401 ||ARCH_STM32F411) config MACH_STM32F429Discovery bool "STM32F429Discovery" depends on (ARCH_STM32F429) config MACH_STM32F446Nucleo bool "STM32F446 Nucleo" depends on (ARCH_STM32F446) config MACH_STM32F411Nucleo bool "STM32F411 Nucleo" depends on (ARCH_STM32F411) config MACH_STM32F407Diymore bool "STM32F407 based Diymore from dyimore.cc" depends on (ARCH_STM32F407) config MACH_LPC1768MBED bool "LPC1768MBED" depends on ARCH_LPC1768 config MACH_SEEEDPRO bool "SEEEDPRO" depends on ARCH_LPC1768 config MACH_LPC1679XPRESSO bool "LPC1679XPRESSO" depends on ARCH_LPC1769 config MACH_LM3S6965EVB bool "lm3s6965evb" depends on ARCH_LM3S6965 config MACH_LM3SVIRT bool "lm3s-qemu" depends on ARCH_LM3SVIRT default y config MACH_BLENANOV1_5 bool "BLENanoV1.5" depends on ARCH_NRF51 default y config MACH_BLENANOV2_0 bool "BLENanoV2.0" depends on ARCH_NRF52 default y endchoice config STM32F7_SDRAM depends on ARCH_STM32F7 bool "Enable external SDRAM" default y config STM32F4_SDRAM depends on ARCH_STM32F4 bool "Enable external SDRAM" default n endmenu menu "Kernel Configuration" config KFLASHMEM_SIZE int "Kernel Flash size (KB)" default 64 config KRAMMEM_SIZE int "Kernel RAM size (KB)" default 64 choice prompt "Tasks Stack Size" default TASK_STACK_SIZE_2K config TASK_STACK_SIZE_1K bool "Tiny stack (1024 Bytes)" config TASK_STACK_SIZE_2K bool "Small stack (2048 Bytes)" config TASK_STACK_SIZE_4K bool "Big stack (4096 Bytes)" config TASK_STACK_SIZE_8K bool "Huge stack (8192 Bytes)" endchoice config MPU bool "Run-time Memory Protection" default y config PTHREADS bool "POSIX Threads (pthreads)" default y config SIGNALS bool "Process Signals" default y config PIPE bool "Pipe" default y config SOCK_UNIX bool "UNIX Sockets for IPC" default n config PTY_UNIX bool "UNIX98 scheme pseudo-tty devices (/dev/pts/X)" default n endmenu menu "Debugging options" config KLOG bool "Enable kernel logging" default y config KLOG_SIZE depends on KLOG int "Kernel log buffer size" default 256 config MEMFAULT_DBG bool "Enable extended segfault debug" default y config HARDFAULT_DBG bool "Enable extended hardfault debug" default n config STRACE bool "Enable syscall tracer" default n endmenu menu "Filesystems" config SYSFS bool "SysFS (/sys)" default y config MEMFS bool "MemFS" default y config XIPFS bool "Xip FS" default y config FATFS bool "Fat FS" default n config FAT32 depends on FATFS bool "Fat32 support" default n endmenu menu "Networking" config SOCK_INET bool "TCP/IP Socket support" default n config TCPIP_MEMPOOL_YN bool "Separate memory pool for TCP/IP stack" default n if TCPIP_MEMPOOL_YN config TCPIP_MEMPOOL string "TCP/IP pool base address" default "0x10000000" endif choice NET_STACK prompt "TCP/IP stack selection" default PICOTCP depends on SOCK_INET config PICOTCP bool "Built-in PicoTCP" endchoice source ../kernel/net/Kconfig endmenu menu "Device Drivers" config DEVNULL bool "Support for /dev/null and /dev/zero" default y menuconfig DEVUART bool "Generic UART driver" default y if DEVUART config USART_0 bool "USART 0" depends on (ARCH_LM3S6965 || ARCH_LM3SVIRT) config USART_1 bool "USART 1" depends on (ARCH_LM3S6965 || ARCH_LM3SVIRT || \ ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F405 || ARCH_STM32F407 || ARCH_STM32F429 || ARCH_STM32F446 || \ ARCH_STM32F746 || ARCH_STM32F769) config USART_2 bool "USART 2" depends on (ARCH_LM3S6965 || ARCH_LM3SVIRT || \ ARCH_STM32F401 || ARCH_STM32F411 || ARCH_STM32F405 || ARCH_STM32F429 || ARCH_STM32F407 || ARCH_STM32F446 || \ ARCH_STM32F746 || ARCH_STM32F769 ) config USART_3 bool "USART 3" depends on (ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F746 || ARCH_STM32F769 ) config USART_4 bool "USART 4" depends on (ARCH_STM32F405) config USART_6 bool "USART 6" depends on (ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F446 || \ ARCH_STM32F746 || ARCH_STM32F769 ) config UART_0 bool "UART 0" depends on (ARCH_LPC17XX || ARCH_NRF51 || ARCH_NRF52) config UART_1 bool "UART 1" depends on ARCH_LPC17XX config UART_2 bool "UART 2" depends on ARCH_LPC17XX config UART_3 bool "UART 3" depends on ARCH_LPC17XX endif config DEVF4DSP bool "STM32F4 Sound driver" depends on (ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F429 || ARCH_STM32F446) select DEVSTM32DMA default n config DEVSTM32USB bool menuconfig DEVSTM32USBFS bool "Support for Full Speed USB OTG" depends on (!DEVSTM32USBHFS) && (ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F429 || ARCH_STM32F446 || \ ARCH_STM32F746) default n select DEVSTM32USB if DEVSTM32USBFS choice prompt "USB FS OTG mode" default USBFS_GUEST config USBFS_HOST bool "Host mode" config USBFS_GUEST bool "Device mode" endchoice endif menuconfig DEVSTM32USBHS bool "Support for High Speed USB OTG" depends on (ARCH_STM32F746 || ARCH_STM32F769) select DEVSTM32USB default n if DEVSTM32USBHS choice prompt "USB HS OTG mode" default USBHS_GUEST config USBHS_HOST bool "Host mode" config USBHS_GUEST bool "Device mode" endchoice endif config DEV_USB_ETH depends on PICOTCP && ( (DEVSTM32USBHS && USBHS_GUEST) || (DEVSTM32USBFS && USBFS_GUEST) ) select DEVSTM32USB bool "Ethernet over USB (CDC-ECM)" default n config DEV_USBH_KBD depends on (USBHS_HOST || USBFS_HOST) bool "USB Keyboard support" default n if DEV_USB_ETH config USB_DEFAULT_IP string "Default (boot-up) address for usb0" default 192.168.6.150 config USB_DEFAULT_NM string "Default (boot-up) netmask for usb0" default 255.255.255.0 config USB_DEFAULT_GW string "Default (boot-up) gateway for usb0" default 192.168.6.1 endif config DEVADC bool "Generic ADC driver" depends on (ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F429 || ARCH_STM32F446) select DEVSTM32DMA default n config DEVF4ETH bool "STM32F4 Ethernet driver" depends on ((ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F429 || ARCH_STM32F446) && PICOTCP) default n config DEVF7ETH bool "STM32F7 Ethernet driver" depends on ((ARCH_STM32F746 || ARCH_STM32F769) && PICOTCP) default n config DEVLM3SETH bool "LM3S Ethernet driver" depends on ((ARCH_LM3S) && PICOTCP) default n if DEVF4ETH || DEVF7ETH || DEVLM3SETH config ETH_DEFAULT_IP string "Default (boot-up) address for eth0" default 192.168.2.150 config ETH_DEFAULT_NM string "Default (boot-up) netmask for eth0" default 255.255.255.0 config ETH_DEFAULT_GW string "Default (boot-up) gateway for eth0" default 192.168.2.1 endif config DEVSTM32SDIO bool "STM32F4/7 SD I/O driver" depends on (ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F429 || ARCH_STM32F7|| ARCH_STM32F446) default n menuconfig DEVSTM32I2C bool "STM32 I2C driver" depends on (ARCH_STM32F401 ||ARCH_STM32F411 || ARCH_STM32F407 || ARCH_STM32F405 || ARCH_STM32F429 || ARCH_STM32F446 || ARCH_STM32F746) select DEVSTM32DMA default n if DEVSTM32I2C config I2C1 bool "I2C 1" default n config I2C2 bool "I2C 2" default n config I2C3 bool "I2C 3" default y endif config DEVCS43L22 tristate "CS43L22 driver (Stereo DAC)" depends on (DEVSTM32I2C) default n config DEVLSM303DLHC tristate "LSM303DLHC driver (Accelerometer & Magnetometer)" depends on (DEVSTM32I2C) default n config DEVMCCOG21 tristate "MCCOG21 driver (2-lines B/W display)" depends on (DEVSTM32I2C) default n config DEVXALED5X7 tristate "Xadow LED Matrix 5X7 driver" depends on (DEVSTM32I2C) default n config DEVFT5336 tristate "FT5336 driver (Touchscreen STM32F746)" depends on (DEVSTM32I2C) default n config DEVSTMPE811 tristate "STMPE811 driver (Touchscreen)" depends on (DEVSTM32I2C) default n menuconfig DEVSPI bool "Generic SPI driver" depends on (ARCH_STM32F4 || ARCH_STM32F7) select DEVSTM32DMA default n if DEVSPI config SPI_1 bool "SPI 1" config SPI_3 bool "SPI 3" config SPI_5 bool "SPI 5" endif config DEVLIS3DSH tristate "LIS3DSH driver (3-Axis Accelerometer)" depends on (DEVSPI) default n config DEVILI9341 tristate "ILI9341 driver (LCD Controller)" depends on (DEVSPI) default n config DEVL3GD20 tristate "L3GD20 driver (Gyro)" depends on (DEVSPI) default n config DEV_RANDOM depends on (ARCH_STM32F4 || ARCH_STM32F7) bool "STM32F2/F4/F7 Random devices" default n if DEV_RANDOM choice prompt "Random device selection" config DEVRNG bool "Hardware TRNG driver" config DEVFRAND bool "Fortuna PRNG device" endchoice endif menuconfig DEVFRAMEBUFFER depends on (ARCH_STM32F7 || ARCH_STM32F4) bool "STM32 Framebuffer driver" default y config DEVFBCON depends on DEVFRAMEBUFFER bool "Console on Framebuffer via /dev/fbcon" default y choice FONT_FACE prompt "Console font face" depends on DEVFBCON default FONT_CGA8X8 config FONT_CGA_8X8 bool "CGA 8x8" config FONT_PICCOLO_7X6 bool "Piccolo 7x6" endchoice config DEVF7DISCOLTDC depends on DEVFRAMEBUFFER bool "F746 Discovery LTDC" default y endmenu menu "Power Management" config LOWPOWER bool "Enable suspend() and standby() syscalls" default n config LSE32K depends on LOWPOWER bool "Use external low-speed oscillator (LSE) at 32kHz to feed the RTC" default n endmenu ================================================ FILE: kernel/adc.h ================================================ #ifndef INC_ADC #define INC_ADC #define NUM_ADC_CHANNELS 16 struct adc_config { uint32_t base; uint32_t irq; uint32_t rcc; const char * name; uint8_t channel_array[NUM_ADC_CHANNELS]; uint8_t num_channels; struct dma_config dma; uint32_t dma_rcc; }; void adc_init(const struct adc_config adc_configs[], int num_adc); #endif ================================================ FILE: kernel/bflt.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "flat.h" #include "kprintf.h" #include "libopencmsis/core_cm3.h" #include "unicore-mx/cm3/systick.h" /************************* * bFLT start *************************/ #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ static inline uint16_t short_be(uint16_t le) { return (uint16_t)(((le & 0xFFu) << 8) | ((le >> 8u) & 0xFFu)); } static inline uint32_t long_be(uint32_t le) { uint8_t *b = (uint8_t *)≤ uint32_t be = 0; uint32_t b0, b1, b2; b0 = b[0]; b1 = b[1]; b2 = b[2]; be = b[3] + (b2 << 8) + (b1 << 16) + (b0 << 24); return be; } static void load_header(struct flat_hdr * to_hdr, struct flat_hdr * from_hdr) { memcpy((uint8_t*)to_hdr, (uint8_t*)from_hdr, sizeof(struct flat_hdr)); } static int check_header(struct flat_hdr * header) { if (memcmp(header->magic, "bFLT", 4) != 0) { kprintf("bFLT: Magic number does not match\r\n"); return -1; } if (long_be(header->rev) != FLAT_VERSION){ kprintf("bFLT: Version number does not match\r\n"); return -1; } /* check for unsupported flags */ if (long_be(header->flags) & (FLAT_FLAG_GZIP | FLAT_FLAG_GZDATA)) { kprintf("bFLT: Unsupported flags detected - GZip'd data is not supported\r\n"); return -1; } return 0; } static unsigned long * calc_reloc(uint8_t * base, uint32_t offset) { /* the library id is in top byte of offset */ int id = (offset >> 24) & 0x000000FFu; if (id) { kprintf("bFLT: No shared library support\r\n"); return (unsigned long *)RELOC_FAILED; } return (unsigned long *)(base + (offset & 0x00FFFFFFu)); } static int process_got_relocs(struct flat_hdr * hdr, uint8_t * base, uint8_t * got_start) { /* * Addresses in header are relative to start of FILE (so including flat_hdr) * Addresses in the relocs are relative to start of .text (so excluding flat_hdr) */ unsigned long * rp = (unsigned long * )got_start; unsigned long data_start = long_be(hdr->data_start) - sizeof(struct flat_hdr); unsigned long bss_end = long_be(hdr->bss_end) - sizeof(struct flat_hdr); uint8_t * text_start_dest = base + sizeof(struct flat_hdr); uint8_t * data_start_dest = got_start; for (rp; *rp != 0xffffffff; rp++) { if (*rp) { unsigned long addr = RELOC_FAILED; if (*rp < data_start) { /* reloc is in .text section: BASE == text_start -- addr == relative to .text */ addr = (unsigned long)calc_reloc(text_start_dest, *rp); } else if (*rp < bss_end) { /* reloc is in .data section: BASE == data_start -- addr == relative to .text - (start of data) */ addr = (unsigned long)calc_reloc(data_start_dest, *rp - data_start); } /* this will remap pointers starting from address 0x0, to wherever they are actually loaded in the memory map (.text reloc) */ if (addr == RELOC_FAILED) { //errno = -ENOEXEC; return -1; } *rp = addr; } } return 0; } /* works only for FLAT v4 */ /* reloc starts just after data_end */ int process_relocs(struct flat_hdr * hdr, unsigned long * base, unsigned long data_start_dest, unsigned long *reloc, int relocs) { int i; /* Relocations in the table point to an address, * at that address(1), there is an adress(2) that needs fixup, * and needs to be written at it's original address(1), after it's been fixed */ /* * Addresses in header are relative to start of FILE (so including flat_hdr) * Addresses in the relocs are relative to start of .text (so excluding flat_hdr) */ unsigned long data_start = long_be(hdr->data_start) - sizeof(struct flat_hdr); unsigned long data_end = long_be(hdr->data_end) - sizeof(struct flat_hdr); /* relocs must be located in .data segment for GOTPIC */ unsigned long bss_end = long_be(hdr->bss_end) - sizeof(struct flat_hdr); unsigned long text_start_dest = ((unsigned long)base) + sizeof(struct flat_hdr); /* original RELOC is relative to text_start (.bss in ROM/Flash/source) */ /* * Now run through the relocation entries. * We've got to be careful here as C++ produces relocatable zero * entries in the constructor and destructor tables which are then * tested for being not zero (which will always occur unless we're * based from address zero). This causes an endless loop as __start * is at zero. The solution used is to not relocate zero addresses. * This has the negative side effect of not allowing a global data * reference to be statically initialised to _stext (I've moved * __start to address 4 so that is okay). */ for (i=0; i < relocs; i++) { unsigned long addr, *fixup_addr; unsigned long *relocd_addr = (unsigned long *)RELOC_FAILED; /* Get the address of the pointer to be relocated (of course, the address has to be relocated first). */ fixup_addr = (unsigned long *)long_be(reloc[i]); /* two cases: reloc_addr < text_end: For now we only support GOTPIC, which cannot have relocations in .text segment! * or reloc_addr > data_start */ /* TODO: Make common between GOT and regular relocs ? */ if ((unsigned long)fixup_addr < data_start) { /* FAIL -- non GOTPIC, cannot write to ROM/.text */ return -1; } else if ((unsigned long)fixup_addr < data_end) { /* Reloc is in .data section (must be for GOTPIC), now make this point to the .data source (in the DEST ram!), and dereference */ fixup_addr = (unsigned long *)calc_reloc((uint8_t *)((unsigned long)data_start_dest - (unsigned long)data_start), (unsigned long)fixup_addr); if (fixup_addr == (unsigned long *)RELOC_FAILED) return -1; /* Again 2 cases: reloc points to .text -- or to .data/.bss */ if (*fixup_addr < data_start) { /* reloc is in .text section: BASE == text_start -- addr == relative to .text */ relocd_addr = (unsigned long *)calc_reloc((uint8_t *)text_start_dest, *fixup_addr); } else if (*fixup_addr < bss_end) { /* reloc is in .data section: BASE == data_start -- addr == relative to .text - (start of data) */ relocd_addr = (unsigned long *)calc_reloc((uint8_t *)data_start_dest, *fixup_addr - data_start); } else { relocd_addr = (unsigned long *)RELOC_FAILED; return -1; } /* write the relocated/offsetted value back were it was read */ *fixup_addr = (unsigned long)relocd_addr; } if (relocd_addr == (unsigned long *)RELOC_FAILED) { kprintf("bFLT: Unable to calculate relocation address\r\n"); return -1; } } return 0; } /* BFLT file structure: * * +------------------------+ 0x0 * | BFLT header | * +------------------------+ * | padding | * +------------------------+ entry * | .text section | * | | * +------------------------+ data_start * | .data section | * | | * +------------------------+ data_end, relocs_start, bss_start * | relocations (and .bss) | * |........................| relocs_end <- BFLT ends here * | (.bss section) | * +------------------------+ bss_end */ int bflt_load(uint8_t* from, void **reloc_text, void **reloc_data, void **reloc_bss, void ** entry_point, size_t *stack_size, uint32_t *got_loc, uint32_t *text_len, uint32_t *data_len) { struct flat_hdr hdr; void * mem = NULL; uint32_t bss_len, stack_len, flags, alloc_len, entry_point_offset; uint8_t *relocs_src, *text_src, *data_dest; uint8_t *address_zero = from; int32_t relocs, rev; //kprintf("bFLT: Loading from 0x%p\r\n", from); if (!address_zero) { goto error; } load_header(&hdr, (struct flat_hdr *)address_zero); if (check_header(&hdr) != 0) { kprintf("bFLT: Bad FLT header\r\n"); goto error; } /* Calculate all the sizes */ *text_len = long_be(hdr.data_start) - sizeof(struct flat_hdr); *data_len = long_be(hdr.data_end) - long_be(hdr.data_start); bss_len = long_be(hdr.bss_end) - long_be(hdr.data_end); stack_len = long_be(hdr.stack_size); relocs = long_be(hdr.reloc_count); flags = long_be(hdr.flags); rev = long_be(hdr.rev); /* Calculate source addresses */ text_src = address_zero + sizeof(struct flat_hdr); relocs_src = address_zero + long_be(hdr.reloc_start); entry_point_offset = (long_be(hdr.entry) & 0xFFFFFFFE) - sizeof(struct flat_hdr); /* offset inside .text + reset THUMB bit */ *stack_size = stack_len; /* * calculate the extra space we need to malloc */ /* relocs are located in the .bss part of the BFLT binary, so we need whichever is biggest */ if ((relocs * sizeof(uint32_t)) > bss_len) alloc_len = relocs * sizeof(uint32_t); else alloc_len = bss_len; alloc_len += *data_len; /* * there are a couple of cases here: * -> the fully copied to RAM case which lumps it all together (RAM flag) * -> the separate code/data case (GOTPIC flag, w/o RAM flag) */ if (flags & FLAT_FLAG_GZIP) { kprintf("bFLT: GZIP compression not supported\r\n"); goto error; } if (flags & FLAT_FLAG_GOTPIC) { uint8_t *mem, *copy_src; uint32_t data_offset = 0; uint32_t copy_len = *data_len; if (flags & FLAT_FLAG_RAM) { alloc_len += *text_len; copy_len += *text_len; data_offset = *text_len; } /* Allocate enough memory for .data, .bss and possibly .text */ mem = u_malloc(alloc_len); if (!mem) { kprintf("bFLT: Could not allocate enough memory for process\r\n"); goto error; } /* .text is only relocated when RAM flag is set */ if (flags & FLAT_FLAG_RAM) { *reloc_text = mem; copy_src = text_src; } else { *reloc_text = text_src; copy_src = text_src + *text_len; } /* .data is always relocated */ data_dest = mem + data_offset; *entry_point = *reloc_text + entry_point_offset; *reloc_data = data_dest; *reloc_bss = data_dest + *data_len; /* copy segments .data segment and possibly .text */ memcpy(mem, copy_src, copy_len); /* zero-init .bss */ memset(data_dest + *data_len, 0, bss_len); } else { /* GZIP or FULL RAM bFLTs not supported for now */ kprintf("bFLT: Only GOTPIC bFLT binaries are supported\r\n"); goto error; } /* * We just load the allocations into some temporary memory to * help simplify all this mumbo jumbo * * We've got two different sections of relocation entries. * The first is the GOT which resides at the beginning of the data segment * and is terminated with a -1. This one can be relocated in place. * The second is the extra relocation entries tacked after the image's * data segment. These require a little more processing as the entry is * really an offset into the image which contains an offset into the * image. */ /* init relocations */ if (flags & FLAT_FLAG_GOTPIC) { //printf("GOT-PIC!\n"); if (process_got_relocs(&hdr, address_zero, data_dest)) // .data section is beginning of GOT goto error; *got_loc = (uint32_t)data_dest; } /* * Now run through the relocation entries. */ process_relocs(&hdr, (uint32_t *)address_zero, (uint32_t)data_dest, (uint32_t *)relocs_src, relocs); return 0; error: if (mem) kfree(mem); *reloc_text = NULL; *reloc_data = NULL; *reloc_bss = NULL; *entry_point = NULL; kprintf("bFLT: Caught error - exiting\r\n"); return -1; } ================================================ FILE: kernel/bflt.h ================================================ /* */ #include #include "flat.h" #ifndef _BFLT_H_ #define _BFLT_H_ int bflt_load(uint8_t* from, void **reloc_text, void **reloc_data, void **reloc_bss, void **entry_point, size_t *stack_size, uint32_t *got_loc, uint32_t *text_len, uint32_t *data_len); #endif ================================================ FILE: kernel/cdc_acm.h ================================================ #ifndef INC_CDC_ACM_H #define INC_CDC_ACM_H struct cdcacm_addr { const char * name; const char * usb_name; }; void cdcacm_init(struct fnode *dev, const struct cdcacm_addr cdcacm_addrs[], int num_cdcacm); #endif ================================================ FILE: kernel/cdc_ecm.h ================================================ #ifndef INC_CDC_ECM_H #define INC_CDC_ECM_H #define USBETH_MAX_FRAME 1514 void cdcecm_init_init(const unsigned char * usb_name); #endif ================================================ FILE: kernel/cirbuf.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "cirbuf.h" #include "errno.h" struct cirbuf { uint8_t *buf; uint8_t *readptr; uint8_t *writeptr; int bufsize; }; struct cirbuf * cirbuf_create(int size) { struct cirbuf* inbuf; if (size <= 0) return NULL; inbuf = kalloc(sizeof(struct cirbuf)); if (!inbuf) return NULL; inbuf->buf = kalloc(size); if (!inbuf->buf) { kfree(inbuf); return NULL; } inbuf->bufsize = size; inbuf->readptr = inbuf->buf; inbuf->writeptr = inbuf->buf; return inbuf; } /* 0 on success, -1 on fail */ int cirbuf_writebyte(struct cirbuf *cb, uint8_t byte) { if (!cb) return -1; /* check if there is space */ if (!cirbuf_bytesfree(cb)) return -1; *cb->writeptr = byte; cb->writeptr++; /* wrap if needed */ if (cb->writeptr > (cb->buf + cb->bufsize - 1u)) cb->writeptr = cb->buf; return 0; } /* 0 on success, -1 on fail */ int cirbuf_readbyte(struct cirbuf *cb, uint8_t *byte) { if (!cb || !byte) return -1; /* check if there is data */ if (!cirbuf_bytesinuse(cb)) return -1; *byte = *cb->readptr++; /* wrap if needed */ if (cb->readptr > (cb->buf + cb->bufsize - 1u)) cb->readptr = cb->buf; return 0; } int cirbuf_readbytes(struct cirbuf *cb, void *bytes, int len) { int buflen; int i; char *dst = bytes; if (!cb || !bytes) return -1; /* check if there is data */ buflen = cirbuf_bytesinuse(cb); if (buflen == 0) return -1; if (len > buflen) len = buflen; for (i = 0; i < len; i++) { dst[i] = *(cb->readptr++); /* wrap if needed */ if (cb->readptr > (cb->buf + cb->bufsize - 1u)) cb->readptr = cb->buf; } return len; } /* written len on success, 0 on fail */ int cirbuf_writebytes(struct cirbuf *cb, const uint8_t * bytes, int len) { uint8_t byte; int freesize; int tot_len = len; if (!cb) return 0; /* check if there is space */ freesize = cirbuf_bytesfree(cb); if (!freesize) return 0; if (freesize < len) { len = freesize; tot_len = freesize; } /* Wrap needed ? */ if ((cb->writeptr + len) > (cb->buf + cb->bufsize) - 1u) { int len_first_part = cb->buf + cb->bufsize - cb->writeptr; /* end - current position */ memcpy(cb->writeptr, bytes, len_first_part); bytes += len_first_part; cb->writeptr = cb->buf; /* set to start of buffer */ len -= len_first_part; } /* write remaining part */ if (len) { memcpy(cb->writeptr, bytes, len); cb->writeptr += len; } return tot_len; } int cirbuf_bytesfree(struct cirbuf *cb) { int bytes; if (!cb) return -1; bytes = (int)(cb->readptr - cb->writeptr - 1); if (cb->writeptr >= cb->readptr) bytes += cb->bufsize; return bytes; } int cirbuf_bytesinuse(struct cirbuf *cb) { int bytes; if (!cb) return -1; bytes = (int)(cb->writeptr - cb->readptr); if (cb->writeptr < cb->readptr) bytes += cb->bufsize; return (bytes); } ================================================ FILE: kernel/cirbuf.h ================================================ #include "frosted.h" #ifndef CIR_BUF_H #define CIR_BUF_H struct cirbuf; struct cirbuf * cirbuf_create(int size); /* 0 on success, -1 on fail */ int cirbuf_writebyte(struct cirbuf *cb, uint8_t byte); /* 0 on success, -1 on fail */ int cirbuf_readbyte(struct cirbuf *cb, uint8_t *byte); /* len on success, -1 on fail */ int cirbuf_writebytes(struct cirbuf *cb, const uint8_t * bytes, int len); /* len on success, -1 on fail */ int cirbuf_readbytes(struct cirbuf *cb, void *bytes, int len); int cirbuf_bytesfree(struct cirbuf *cb); int cirbuf_bytesinuse(struct cirbuf *cb); #endif ================================================ FILE: kernel/crypto/aes.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Copyright (C) 2006-2016 wolfSSL Inc. * */ #include "frosted.h" #include "crypto/misc.h" #include "crypto/aes.h" #define AES_MAX_KEY_SIZE 256 #define GETBYTE(x, y) (word32)((byte)((x) >> (8 * (y)))) static const word32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; static const word32 Te[5][256] = { { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }, { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }, { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }, { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }, { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, } }; static const word32 Td[5][256] = { { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }, { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }, { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }, { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }, { 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, } }; static int wc_AesSetIV(Aes *aes, const byte *iv) { if (aes == NULL) return -1; if (iv) XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE); else XMEMSET(aes->reg, 0, AES_BLOCK_SIZE); return 0; } static int wc_AesSetKeyLocal(Aes *aes, const byte *userKey, word32 keylen, const byte *iv, int dir) { word32 temp, *rk = aes->key; unsigned int i = 0; aes->rounds = keylen/4 + 6; XMEMCPY(rk, userKey, keylen); ByteReverseWords(rk, rk, keylen); switch(keylen) { case 32: while (1) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^ (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^ (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^ (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) break; temp = rk[11]; rk[12] = rk[ 4] ^ (Te[4][GETBYTE(temp, 3)] & 0xff000000) ^ (Te[4][GETBYTE(temp, 2)] & 0x00ff0000) ^ (Te[4][GETBYTE(temp, 1)] & 0x0000ff00) ^ (Te[4][GETBYTE(temp, 0)] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } break; default: return -1; } if (dir == AES_DECRYPTION) { unsigned int j; rk = aes->key; /* invert the order of the round keys: */ for (i = 0, j = 4* aes->rounds; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the * first and the last: */ for (i = 1; i < aes->rounds; i++) { rk += 4; rk[0] = Td[0][Te[4][GETBYTE(rk[0], 3)] & 0xff] ^ Td[1][Te[4][GETBYTE(rk[0], 2)] & 0xff] ^ Td[2][Te[4][GETBYTE(rk[0], 1)] & 0xff] ^ Td[3][Te[4][GETBYTE(rk[0], 0)] & 0xff]; rk[1] = Td[0][Te[4][GETBYTE(rk[1], 3)] & 0xff] ^ Td[1][Te[4][GETBYTE(rk[1], 2)] & 0xff] ^ Td[2][Te[4][GETBYTE(rk[1], 1)] & 0xff] ^ Td[3][Te[4][GETBYTE(rk[1], 0)] & 0xff]; rk[2] = Td[0][Te[4][GETBYTE(rk[2], 3)] & 0xff] ^ Td[1][Te[4][GETBYTE(rk[2], 2)] & 0xff] ^ Td[2][Te[4][GETBYTE(rk[2], 1)] & 0xff] ^ Td[3][Te[4][GETBYTE(rk[2], 0)] & 0xff]; rk[3] = Td[0][Te[4][GETBYTE(rk[3], 3)] & 0xff] ^ Td[1][Te[4][GETBYTE(rk[3], 2)] & 0xff] ^ Td[2][Te[4][GETBYTE(rk[3], 1)] & 0xff] ^ Td[3][Te[4][GETBYTE(rk[3], 0)] & 0xff]; } } return wc_AesSetIV(aes, iv); } int wc_AesSetKey(Aes *aes, const byte *userKey, word32 keylen, const byte *iv, int dir) { const word32 max_key_len = (AES_MAX_KEY_SIZE / 8); if (!(keylen == 32)) return -1; if (keylen > max_key_len) { return -1; } return wc_AesSetKeyLocal(aes, userKey, keylen, iv, dir); } static void wc_AesEncrypt(Aes *aes, const byte *inBlock, byte *outBlock) { word32 s0, s1, s2, s3; word32 t0, t1, t2, t3; word32 r = aes->rounds >> 1; const word32* rk = aes->key; if (r > 7 || r == 0) { //WOLFSSL_MSG("AesEncrypt encountered improper key, set it up"); return; /* stop instead of segfaulting, set up your keys! */ } /* * map byte array block to cipher state * and add initial round key: */ XMEMCPY(&s0, inBlock, sizeof(s0)); XMEMCPY(&s1, inBlock + sizeof(s0), sizeof(s1)); XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2)); XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3)); s0 = ByteReverseWord32(s0); s1 = ByteReverseWord32(s1); s2 = ByteReverseWord32(s2); s3 = ByteReverseWord32(s3); s0 ^= rk[0]; s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; /* * Nr - 1 full rounds: */ for (;;) { t0 = Te[0][GETBYTE(s0, 3)] ^ Te[1][GETBYTE(s1, 2)] ^ Te[2][GETBYTE(s2, 1)] ^ Te[3][GETBYTE(s3, 0)] ^ rk[4]; t1 = Te[0][GETBYTE(s1, 3)] ^ Te[1][GETBYTE(s2, 2)] ^ Te[2][GETBYTE(s3, 1)] ^ Te[3][GETBYTE(s0, 0)] ^ rk[5]; t2 = Te[0][GETBYTE(s2, 3)] ^ Te[1][GETBYTE(s3, 2)] ^ Te[2][GETBYTE(s0, 1)] ^ Te[3][GETBYTE(s1, 0)] ^ rk[6]; t3 = Te[0][GETBYTE(s3, 3)] ^ Te[1][GETBYTE(s0, 2)] ^ Te[2][GETBYTE(s1, 1)] ^ Te[3][GETBYTE(s2, 0)] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te[0][GETBYTE(t0, 3)] ^ Te[1][GETBYTE(t1, 2)] ^ Te[2][GETBYTE(t2, 1)] ^ Te[3][GETBYTE(t3, 0)] ^ rk[0]; s1 = Te[0][GETBYTE(t1, 3)] ^ Te[1][GETBYTE(t2, 2)] ^ Te[2][GETBYTE(t3, 1)] ^ Te[3][GETBYTE(t0, 0)] ^ rk[1]; s2 = Te[0][GETBYTE(t2, 3)] ^ Te[1][GETBYTE(t3, 2)] ^ Te[2][GETBYTE(t0, 1)] ^ Te[3][GETBYTE(t1, 0)] ^ rk[2]; s3 = Te[0][GETBYTE(t3, 3)] ^ Te[1][GETBYTE(t0, 2)] ^ Te[2][GETBYTE(t1, 1)] ^ Te[3][GETBYTE(t2, 0)] ^ rk[3]; } /* * apply last round and * map cipher state to byte array block: */ s0 = (Te[4][GETBYTE(t0, 3)] & 0xff000000) ^ (Te[4][GETBYTE(t1, 2)] & 0x00ff0000) ^ (Te[4][GETBYTE(t2, 1)] & 0x0000ff00) ^ (Te[4][GETBYTE(t3, 0)] & 0x000000ff) ^ rk[0]; s1 = (Te[4][GETBYTE(t1, 3)] & 0xff000000) ^ (Te[4][GETBYTE(t2, 2)] & 0x00ff0000) ^ (Te[4][GETBYTE(t3, 1)] & 0x0000ff00) ^ (Te[4][GETBYTE(t0, 0)] & 0x000000ff) ^ rk[1]; s2 = (Te[4][GETBYTE(t2, 3)] & 0xff000000) ^ (Te[4][GETBYTE(t3, 2)] & 0x00ff0000) ^ (Te[4][GETBYTE(t0, 1)] & 0x0000ff00) ^ (Te[4][GETBYTE(t1, 0)] & 0x000000ff) ^ rk[2]; s3 = (Te[4][GETBYTE(t3, 3)] & 0xff000000) ^ (Te[4][GETBYTE(t0, 2)] & 0x00ff0000) ^ (Te[4][GETBYTE(t1, 1)] & 0x0000ff00) ^ (Te[4][GETBYTE(t2, 0)] & 0x000000ff) ^ rk[3]; /* write out */ s0 = ByteReverseWord32(s0); s1 = ByteReverseWord32(s1); s2 = ByteReverseWord32(s2); s3 = ByteReverseWord32(s3); XMEMCPY(outBlock, &s0, sizeof(s0)); XMEMCPY(outBlock + sizeof(s0), &s1, sizeof(s1)); XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2)); XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3)); } static void wc_AesDecrypt(Aes *aes, const byte *inBlock, byte *outBlock) { word32 s0, s1, s2, s3; word32 t0, t1, t2, t3; word32 r = aes->rounds >> 1; const word32 *rk = aes->key; if (r > 7 || r == 0) { return; /* stop instead of segfaulting, set up your keys! */ } /* * map byte array block to cipher state * and add initial round key: */ XMEMCPY(&s0, inBlock, sizeof(s0)); XMEMCPY(&s1, inBlock + sizeof(s0), sizeof(s1)); XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2)); XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3)); s0 = ByteReverseWord32(s0); s1 = ByteReverseWord32(s1); s2 = ByteReverseWord32(s2); s3 = ByteReverseWord32(s3); s0 ^= rk[0]; s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; /* * Nr - 1 full rounds: */ for (;;) { t0 = Td[0][GETBYTE(s0, 3)] ^ Td[1][GETBYTE(s3, 2)] ^ Td[2][GETBYTE(s2, 1)] ^ Td[3][GETBYTE(s1, 0)] ^ rk[4]; t1 = Td[0][GETBYTE(s1, 3)] ^ Td[1][GETBYTE(s0, 2)] ^ Td[2][GETBYTE(s3, 1)] ^ Td[3][GETBYTE(s2, 0)] ^ rk[5]; t2 = Td[0][GETBYTE(s2, 3)] ^ Td[1][GETBYTE(s1, 2)] ^ Td[2][GETBYTE(s0, 1)] ^ Td[3][GETBYTE(s3, 0)] ^ rk[6]; t3 = Td[0][GETBYTE(s3, 3)] ^ Td[1][GETBYTE(s2, 2)] ^ Td[2][GETBYTE(s1, 1)] ^ Td[3][GETBYTE(s0, 0)] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Td[0][GETBYTE(t0, 3)] ^ Td[1][GETBYTE(t3, 2)] ^ Td[2][GETBYTE(t2, 1)] ^ Td[3][GETBYTE(t1, 0)] ^ rk[0]; s1 = Td[0][GETBYTE(t1, 3)] ^ Td[1][GETBYTE(t0, 2)] ^ Td[2][GETBYTE(t3, 1)] ^ Td[3][GETBYTE(t2, 0)] ^ rk[1]; s2 = Td[0][GETBYTE(t2, 3)] ^ Td[1][GETBYTE(t1, 2)] ^ Td[2][GETBYTE(t0, 1)] ^ Td[3][GETBYTE(t3, 0)] ^ rk[2]; s3 = Td[0][GETBYTE(t3, 3)] ^ Td[1][GETBYTE(t2, 2)] ^ Td[2][GETBYTE(t1, 1)] ^ Td[3][GETBYTE(t0, 0)] ^ rk[3]; } /* * apply last round and * map cipher state to byte array block: */ s0 = (Td[4][GETBYTE(t0, 3)] & 0xff000000) ^ (Td[4][GETBYTE(t3, 2)] & 0x00ff0000) ^ (Td[4][GETBYTE(t2, 1)] & 0x0000ff00) ^ (Td[4][GETBYTE(t1, 0)] & 0x000000ff) ^ rk[0]; s1 = (Td[4][GETBYTE(t1, 3)] & 0xff000000) ^ (Td[4][GETBYTE(t0, 2)] & 0x00ff0000) ^ (Td[4][GETBYTE(t3, 1)] & 0x0000ff00) ^ (Td[4][GETBYTE(t2, 0)] & 0x000000ff) ^ rk[1]; s2 = (Td[4][GETBYTE(t2, 3)] & 0xff000000) ^ (Td[4][GETBYTE(t1, 2)] & 0x00ff0000) ^ (Td[4][GETBYTE(t0, 1)] & 0x0000ff00) ^ (Td[4][GETBYTE(t3, 0)] & 0x000000ff) ^ rk[2]; s3 = (Td[4][GETBYTE(t3, 3)] & 0xff000000) ^ (Td[4][GETBYTE(t2, 2)] & 0x00ff0000) ^ (Td[4][GETBYTE(t1, 1)] & 0x0000ff00) ^ (Td[4][GETBYTE(t0, 0)] & 0x000000ff) ^ rk[3]; /* write out */ s0 = ByteReverseWord32(s0); s1 = ByteReverseWord32(s1); s2 = ByteReverseWord32(s2); s3 = ByteReverseWord32(s3); XMEMCPY(outBlock, &s0, sizeof(s0)); XMEMCPY(outBlock + sizeof(s0), &s1, sizeof(s1)); XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2)); XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3)); } int wc_AesCbcEncrypt(Aes *aes, byte *out, const byte *in, word32 sz) { word32 blocks = sz / AES_BLOCK_SIZE; while (blocks--) { xorbuf((byte *)aes->reg, in, AES_BLOCK_SIZE); wc_AesEncrypt(aes, (byte*)aes->reg, (byte *)aes->reg); XMEMCPY(out, aes->reg, AES_BLOCK_SIZE); out += AES_BLOCK_SIZE; in += AES_BLOCK_SIZE; } return 0; } int wc_AesCbcDecrypt(Aes *aes, byte *out, const byte *in, word32 sz) { word32 blocks = sz / AES_BLOCK_SIZE; while (blocks--) { XMEMCPY(aes->tmp, in, AES_BLOCK_SIZE); wc_AesDecrypt(aes, (byte *)aes->tmp, out); xorbuf(out, (byte *)aes->reg, AES_BLOCK_SIZE); XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE); out += AES_BLOCK_SIZE; in += AES_BLOCK_SIZE; } return 0; } ================================================ FILE: kernel/crypto/aes.h ================================================ #ifndef CRYPTO_AES_H_ #define CRYPTO_AES_H_ #include "crypto/misc.h" enum { AES_ENC_TYPE = 1, /* cipher unique type */ AES_ENCRYPTION = 0, AES_DECRYPTION = 1, AES_BLOCK_SIZE = 16 }; typedef struct Aes { /* AESNI needs key first, rounds 2nd, not sure why yet */ __attribute__ ( (aligned (16))) word32 key[60]; word32 rounds; __attribute__ ( (aligned (16))) word32 reg[AES_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */ __attribute__ ( (aligned (16))) word32 tmp[AES_BLOCK_SIZE / sizeof(word32)]; /* same */ void *heap; /* memory hint to use */ } Aes; int wc_AesSetKey(Aes *aes, const byte *userKey, word32 keylen, const byte *iv, int dir); int wc_AesCbcEncrypt(Aes *aes, byte *out, const byte *in, word32 sz); int wc_AesCbcDecrypt(Aes *aes, byte *out, const byte *in, word32 sz); #endif /* CRYPTO_AES_H_ */ ================================================ FILE: kernel/crypto/misc.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Copyright (C) 2006-2016 wolfSSL Inc. * */ #include "frosted.h" #include "crypto/misc.h" word32 rotlFixed(word32 x, word32 y) { return (x << y) | (x >> (sizeof(y) * 8 - y)); } word32 rotrFixed(word32 x, word32 y) { return (x >> y) | (x << (sizeof(y) * 8 - y)); } word32 ByteReverseWord32(word32 value) { /* 6 instructions with rotate instruction, 8 without */ value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); return rotlFixed(value, 16U); } void ByteReverseWords(word32 *out, const word32 *in, word32 byte_count) { word32 count = byte_count/(word32)sizeof(word32), i; for (i = 0; i < count; i++) out[i] = ByteReverseWord32(in[i]); } static void XorWords(word32 *r, const word32 *a, word32 n) { word32 i; for (i = 0; i < n; i++) r[i] ^= a[i]; } void xorbuf(void *buf, const void *mask, word32 count) { if ((((word32)buf | (word32)mask | count) % sizeof(word32)) == 0) XorWords((word32 *)buf, (const word32 *)mask, (count / sizeof(word32))); else { word32 i; byte *b = (byte *)buf; const byte *m = (const byte *)mask; for (i = 0; i < count; i++) b[i] ^= m[i]; } } ================================================ FILE: kernel/crypto/misc.h ================================================ #ifndef CRYPTO_MISC_H_ #define CRYPTO_MISC_H_ #define XMEMCPY(d,s,l) memcpy((d),(s),(l)) #define XMEMSET(b,c,l) memset((b),(c),(l)) #define XMEMCMP(s1,s2,n) memcmp((s1),(s2),(n)) #define XMEMMOVE(d,s,l) memmove((d),(s),(l)) #ifndef byte typedef unsigned char byte; #endif typedef unsigned short word16; typedef unsigned int word32; word32 rotlFixed(word32 x, word32 y); word32 rotrFixed(word32 x, word32 y); word32 ByteReverseWord32(word32 value); void ByteReverseWords(word32 *out, const word32 *in, word32 byte_count); void xorbuf(void *buf, const void *mask, word32 count); #endif /* CRYPTO_MISC_H_ */ ================================================ FILE: kernel/crypto/sha256.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Copyright (C) 2006-2016 wolfSSL Inc. * Code submitted to wolfSSL by raphael.huck@efixo.com * */ #include "frosted.h" #include "crypto/misc.h" #include "crypto/sha256.h" static inline word32 min(word32 a, word32 b) { return a > b ? b : a; } static const __attribute__ ((aligned (32))) word32 K[64] = { 0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL, 0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L, 0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L, 0xC19BF174L, 0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL, 0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL, 0x983E5152L, 0xA831C66DL, 0xB00327C8L, 0xBF597FC7L, 0xC6E00BF3L, 0xD5A79147L, 0x06CA6351L, 0x14292967L, 0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL, 0x53380D13L, 0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L, 0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L, 0xD192E819L, 0xD6990624L, 0xF40E3585L, 0x106AA070L, 0x19A4C116L, 0x1E376C08L, 0x2748774CL, 0x34B0BCB5L, 0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL, 0x682E6FF3L, 0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L, 0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L }; #define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define Maj(x,y,z) ((((x) | (y)) & (z)) | ((x) & (y))) #define R(x, n) (((x)&0xFFFFFFFFU)>>(n)) #define S(x, n) rotrFixed(x, n) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) #define RND(a,b,c,d,e,f,g,h,i) \ t0 = (h) + Sigma1((e)) + Ch((e), (f), (g)) + K[(i)] + W[(i)]; \ t1 = Sigma0((a)) + Maj((a), (b), (c)); \ (d) += t0; \ (h) = t0 + t1; static int Transform(Sha256 *sha256) { word32 S[8], t0, t1; int i; word32 *W; W = (word32 *)kalloc(sizeof(word32) * 64); if (W == NULL) return -1; /* Copy context->state[] to working vars */ for (i = 0; i < 8; i++) S[i] = sha256->digest[i]; for (i = 0; i < 16; i++) W[i] = sha256->buffer[i]; for (i = 16; i < 64; i++) W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16]; for (i = 0; i < 64; i += 8) { RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); } /* Add the working vars back into digest state[] */ for (i = 0; i < 8; i++) { sha256->digest[i] += S[i]; } kfree(W); return 0; } #define XTRANSFORM(sha256, B) Transform(sha256) static inline void AddLength(Sha256 *sha256, word32 len) { word32 tmp = sha256->loLen; if ( (sha256->loLen += len) < tmp) sha256->hiLen++; /* carry low to high */ } int wc_InitSha256(Sha256 *sha256) { int ret = 0; sha256->digest[0] = 0x6A09E667L; sha256->digest[1] = 0xBB67AE85L; sha256->digest[2] = 0x3C6EF372L; sha256->digest[3] = 0xA54FF53AL; sha256->digest[4] = 0x510E527FL; sha256->digest[5] = 0x9B05688CL; sha256->digest[6] = 0x1F83D9ABL; sha256->digest[7] = 0x5BE0CD19L; sha256->buffLen = 0; sha256->loLen = 0; sha256->hiLen = 0; return ret; } int wc_Sha256Update(Sha256 *sha256, const byte *data, word32 len) { /* do block size increments */ byte *local = (byte *)sha256->buffer; while (len) { word32 add = min(len, SHA256_BLOCK_SIZE - sha256->buffLen); XMEMCPY(&local[sha256->buffLen], data, add); sha256->buffLen += add; data += add; len -= add; if (sha256->buffLen == SHA256_BLOCK_SIZE) { int ret; ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE); ret = XTRANSFORM(sha256, local); if (ret != 0) return ret; AddLength(sha256, SHA256_BLOCK_SIZE); sha256->buffLen = 0; } } return 0; } int wc_Sha256Final(Sha256 *sha256, byte *hash) { byte *local = (byte *)sha256->buffer; int ret; AddLength(sha256, sha256->buffLen); /* before adding pads */ local[sha256->buffLen++] = 0x80; /* add 1 */ /* pad with zeros */ if (sha256->buffLen > SHA256_PAD_SIZE) { XMEMSET(&local[sha256->buffLen], 0, SHA256_BLOCK_SIZE - sha256->buffLen); sha256->buffLen += SHA256_BLOCK_SIZE - sha256->buffLen; ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE); ret = XTRANSFORM(sha256, local); if (ret != 0) return ret; sha256->buffLen = 0; } XMEMSET(&local[sha256->buffLen], 0, SHA256_PAD_SIZE - sha256->buffLen); /* put lengths in bits */ sha256->hiLen = (sha256->loLen >> (8 * sizeof(sha256->loLen) - 3)) + (sha256->hiLen << 3); sha256->loLen = sha256->loLen << 3; /* store lengths */ ByteReverseWords(sha256->buffer, sha256->buffer, SHA256_BLOCK_SIZE); /* ! length ordering dependent on digest endian type ! */ XMEMCPY(&local[SHA256_PAD_SIZE], &sha256->hiLen, sizeof(word32)); XMEMCPY(&local[SHA256_PAD_SIZE + sizeof(word32)], &sha256->loLen, sizeof(word32)); ret = XTRANSFORM(sha256, local); if (ret != 0) return ret; ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE); XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE); return wc_InitSha256(sha256); /* reset state */ } ================================================ FILE: kernel/crypto/sha256.h ================================================ #ifndef CRYPTO_SHA256_H_ #define CRYPTO_SHA256_H_ #include "crypto/misc.h" /* in bytes */ enum { SHA256 = 2, /* hash type unique */ SHA256_BLOCK_SIZE = 64, SHA256_DIGEST_SIZE = 32, SHA256_PAD_SIZE = 56 }; /* Sha256 digest */ typedef struct Sha256 { word32 buffLen; /* in bytes */ word32 loLen; /* length in bytes */ word32 hiLen; /* length in bytes */ word32 digest[SHA256_DIGEST_SIZE / sizeof(word32)]; word32 buffer[SHA256_BLOCK_SIZE / sizeof(word32)]; } Sha256; int wc_InitSha256(Sha256 *sha256); int wc_Sha256Update(Sha256 *sha256, const byte *data, word32 len); int wc_Sha256Final(Sha256 *sha256, byte *hash); #endif /* CRYPTO_SHA256_H_ */ ================================================ FILE: kernel/device.h ================================================ #ifndef INC_DEVICE #define INC_DEVICE #include "frosted.h" struct device { struct fnode *fno; mutex_t * mutex; struct task *task; }; int device_open(const char *path, int flags); struct device * device_fno_init(struct module * mod, const char * name, struct fnode *node, uint32_t flags,void * priv); #endif ================================================ FILE: kernel/drivers/device.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" int device_open(const char *path, int flags) { struct fnode *f = fno_search(path); if (!f) return -1; return task_filedesc_add(f); } struct device * device_fno_init(struct module * mod, const char * name, struct fnode *node, uint32_t flags, void * priv) { struct device * device = kalloc(sizeof(struct device)); device->fno = NULL; /* Only create a device node if there is a name */ if(name) { device->fno = fno_create(mod, name, node); device->fno->priv = priv; device->fno->flags |= flags; } device->task = NULL; device->mutex = mutex_init(); return device; } ================================================ FILE: kernel/drivers/devusb_cdc_ecm.c ================================================ /* * USB Ethernet gadget driver * * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include #include #include #include "usb.h" #define USBETH_MAX_FRAME 1514 struct pico_dev_usbeth { struct pico_device dev; }; struct usbeth_rx_buffer { enum usbeth_rx_buffer_status { RX_STATUS_FREE, /**< Buffer is free */ RX_STATUS_INCOMING, /**< We have unprocessed buffer */ RX_STATUS_TCPIP /** PICO TCP is processing */ } status; uint16_t size; uint8_t buf[USBETH_MAX_FRAME]; }; struct usbeth_tx_buffer { enum usbeth_tx_buffer_status { TX_STATUS_FREE, TX_STATUS_PENDING, TX_STATUS_COMPLETE } status; uint16_t size; uint8_t buf[USBETH_MAX_FRAME]; }; static struct pico_dev_usbeth *pico_usbeth = NULL; static struct usbeth_rx_buffer *rx_buffer = NULL; static struct usbeth_tx_buffer *tx_buffer = NULL; static const struct __attribute__((packed)) { struct usb_config_descriptor config; struct usb_interface_descriptor comm_iface; struct { struct usb_cdc_header_descriptor header; struct usb_cdc_union_descriptor cdc_union; struct usb_cdc_ecm_descriptor ecm; } __attribute__((packed)) functional_descriptors; struct usb_endpoint_descriptor comm_endp; struct usb_interface_descriptor data_iface; struct usb_endpoint_descriptor data_endp[2]; } cdc_ecm_config = { .config = { .bLength = USB_DT_CONFIGURATION_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = sizeof(cdc_ecm_config), .bNumInterfaces = 2, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0xC0, .bMaxPower = 0x32 }, .comm_iface = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_CDC, .bInterfaceSubClass = USB_CDC_SUBCLASS_ECM, .bInterfaceProtocol = USB_CDC_PROTOCOL_NONE, .iInterface = 0 }, .functional_descriptors = { .header = { .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_CDC_TYPE_HEADER, .bcdCDC = 0x0120, }, .cdc_union = { .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_CDC_TYPE_UNION, .bControlInterface = 0, .bSubordinateInterface0 = 1, }, .ecm = { .bFunctionLength = sizeof(struct usb_cdc_ecm_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_CDC_TYPE_ECM, .iMACAddress = 4, .bmEthernetStatistics = { 0, 0, 0, 0 }, .wMaxSegmentSize = USBETH_MAX_FRAME, .wNumberMCFilters = 0, .bNumberPowerFilters = 0, }, }, .comm_endp = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x82, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 16, .bInterval = 0x10, }, .data_iface = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 1, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_DATA, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = 0 }, .data_endp = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x01, .bmAttributes = USB_ENDPOINT_ATTR_BULK, .wMaxPacketSize = 64, .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x81, .bmAttributes = USB_ENDPOINT_ATTR_BULK, .wMaxPacketSize = 64, .bInterval = 1, }} }; static const struct usb_string_descriptor string_lang_list = { .bLength = USB_DT_STRING_SIZE(1), .bDescriptorType = USB_DT_STRING, .wData = { USB_LANGID_ENGLISH_UNITED_STATES } }; const struct usb_string_descriptor usb_string_manuf = { .bLength = USB_DT_STRING_SIZE(22), .bDescriptorType = USB_DT_STRING, /* Insane adding machines */ .wData = { 0x0049, 0x006e, 0x0073, 0x0061, 0x006e, 0x0065, 0x0020, 0x0061, 0x0064, 0x0064, 0x0069, 0x006e, 0x0067, 0x0020, 0x006d, 0x0061, 0x0063, 0x0068, 0x0069, 0x006e, 0x0065, 0x0073 } }; static const struct usb_string_descriptor usb_string_name = { .bLength = USB_DT_STRING_SIZE(18), .bDescriptorType = USB_DT_STRING, /* Frosted Eth gadget */ .wData = { 0x0046, 0x0072, 0x006f, 0x0073, 0x0074, 0x0065, 0x0064, 0x0020, 0x0045, 0x0074, 0x0068, 0x0020, 0x0067, 0x0061, 0x0064, 0x0067, 0x0065, 0x0074 } }; static const struct usb_string_descriptor usb_serialn = { .bLength = USB_DT_STRING_SIZE(2), .bDescriptorType = USB_DT_STRING, /* 01 */ .wData = { 0x0030, 0x0031 } }; static const struct usb_string_descriptor usb_macaddr = { .bLength = USB_DT_STRING_SIZE(12), .bDescriptorType = USB_DT_STRING, /* 005af341b4c9 */ .wData = { 0x0030, 0x0030, 0x0035, 0x0061, 0x0066, 0x0033, 0x0034, 0x0031, 0x0062, 0x0034, 0x0063, 0x0039 } }; static const struct usb_string_descriptor **string_data[1] = { (const struct usb_string_descriptor *[]) { &usb_string_manuf, &usb_string_name, &usb_serialn, &usb_macaddr } }; static const struct usbd_info_string string = { .lang_list = &string_lang_list, .count = 4, .data = string_data }; static const struct usb_device_descriptor cdc_ecm_dev = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = 0x0200, .bDeviceClass = USB_CLASS_CDC, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x0483, .idProduct = 0x5740, .bcdDevice = 0x0200, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1 }; static const struct usbd_info cdc_ecm_info = { .device = { .desc = &cdc_ecm_dev, .string = &string }, .config = {{ .desc = (const struct usb_config_descriptor *) &cdc_ecm_config, .string = &string }} }; static const uint8_t mac_addr[6] = { 0, 0x5a, 0xf3, 0x41, 0xb4, 0xca }; static void cdcecm_setup_request(usbd_device *usbd_dev, uint8_t ep_addr, const struct usb_setup_data *setup_data) { (void) ep_addr; /* Assuming (ep_addr == 0) */ const uint8_t bmReqMask = USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT; const uint8_t bmReqVal = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; if ((setup_data->bmRequestType & bmReqMask) != bmReqVal) { /* Not of our interest, let library handle */ usbd_ep0_setup(usbd_dev, setup_data); return; } switch (setup_data->bRequest) { case USB_CDC_REQ_SET_ETHERNET_MULTICAST_FILTER: case USB_CDC_REQ_SET_ETHERNET_PACKET_FILTER: case USB_CDC_REQ_SET_ETHERNET_PM_PATTERN_FILTER: case USB_CDC_REQ_SET_CONTROL_LINE_STATE: usbd_ep0_transfer(usbd_dev, setup_data, NULL, 0, NULL); return; case USB_CDC_REQ_SET_LINE_CODING: { if (setup_data->wLength < sizeof(struct usb_cdc_line_coding)) { break; } /* Just read whatever the host is sending */ uint8_t buf[sizeof(struct usb_cdc_line_coding)]; usbd_ep0_transfer(usbd_dev, setup_data, buf, setup_data->wLength, NULL); } return; } /* Unsupported request */ usbd_ep0_stall(usbd_dev); } /*************************** * * * USB Device Definition * * * *************************** * * */ static void cdcecm_set_config(usbd_device *usbd_dev, const struct usb_config_descriptor *cfg); static usbd_device *usbd_dev; static void notify_link_up(void) { static const uint8_t buf[8] = {0x51, 0, 1, 0, 0, 0, 0, 0}; const usbd_transfer transfer = { .ep_type = USBD_EP_INTERRUPT, .ep_addr = 0x82, .ep_size = 16, .ep_interval = 0, .buffer = (void *) buf, .length = sizeof(buf), .flags = USBD_FLAG_NONE, .timeout = USBD_TIMEOUT_NEVER, .callback = NULL }; usbd_transfer_submit(usbd_dev, &transfer); } static void bulk_out_callback(usbd_device *dev, const usbd_transfer *transfer, usbd_transfer_status status, usbd_urb_id urb_id) { static int notified_link_up = 0; static int fail_count = 0; (void)urb_id; if (status != USBD_SUCCESS) { return; } if (!notified_link_up) { notified_link_up = 1; notify_link_up(); } if (rx_buffer->status == RX_STATUS_FREE) { rx_buffer->size = transfer->transferred; rx_buffer->status = RX_STATUS_INCOMING; } else { if(++fail_count > 100) { rx_buffer->status = RX_STATUS_FREE; } } frosted_tcpip_wakeup(); } static void bulk_out_submit(void) { rx_buffer->size = 0; rx_buffer->status = RX_STATUS_FREE; const usbd_transfer transfer = { .ep_type = USBD_EP_BULK, .ep_addr = 0x01, .ep_size = 64, .ep_interval = USBD_INTERVAL_NA, .buffer = rx_buffer->buf, .length = USBETH_MAX_FRAME, .flags = USBD_FLAG_SHORT_PACKET, .timeout = USBD_TIMEOUT_NEVER, .callback = bulk_out_callback }; usbd_transfer_submit(usbd_dev, &transfer); } static void cdcecm_set_config(usbd_device *usbd_dev, const struct usb_config_descriptor *cfg) { (void)cfg; usbd_ep_prepare(usbd_dev, 0x01, USBD_EP_BULK, 64, USBD_INTERVAL_NA, USBD_EP_NONE); usbd_ep_prepare(usbd_dev, 0x81, USBD_EP_BULK, 64, USBD_INTERVAL_NA, USBD_EP_NONE); usbd_ep_prepare(usbd_dev, 0x82, USBD_EP_INTERRUPT, 16, 0, USBD_EP_NONE); bulk_out_submit(); } /** * Transfer callback for BULK IN (TX) */ static void bulk_in_callback(usbd_device *dev, const usbd_transfer *transfer, usbd_transfer_status status, usbd_urb_id urb_id) { (void)dev; (void)transfer; (void)urb_id; tx_buffer->status = TX_STATUS_COMPLETE; frosted_tcpip_wakeup(); } static int pico_usbeth_send(struct pico_device *dev, void *buf, int len) { struct pico_dev_usbeth *usbeth = (struct pico_dev_usbeth *) dev; static int fail_count = 0; const usbd_transfer transfer = { .ep_type = USBD_EP_BULK, .ep_addr = 0x81, .ep_size = 64, .ep_interval = USBD_INTERVAL_NA, .buffer = tx_buffer->buf, .length = len, .flags = USBD_FLAG_NONE, .timeout = USBD_TIMEOUT_NEVER, .callback = bulk_in_callback }; if (tx_buffer->status == TX_STATUS_PENDING) { if (++fail_count > 100) tx_buffer->status == TX_STATUS_FREE; return 0; } tx_buffer->status = TX_STATUS_PENDING; if (len > USBETH_MAX_FRAME) len = USBETH_MAX_FRAME; memcpy(tx_buffer->buf, buf, len); tx_buffer->size = len; usbd_transfer_submit(usbd_dev, &transfer); return len; } static int pico_usbeth_poll(struct pico_device *dev, int loop_score) { if (rx_buffer->status == RX_STATUS_INCOMING) { pico_stack_recv(&pico_usbeth->dev, rx_buffer->buf, rx_buffer->size); bulk_out_submit(); loop_score--; } return loop_score; } static void pico_usbeth_destroy(struct pico_device *dev) { struct pico_dev_usbeth *usbeth = (struct pico_dev_usbeth *) dev; kfree(rx_buffer); kfree(tx_buffer); kfree(usbeth); usbeth = NULL; rx_buffer = NULL; tx_buffer = NULL; } int usb_ethernet_init(unsigned int dev) { struct pico_dev_usbeth *usb = kalloc(sizeof(*usb)); uint8_t *usb_buf; struct pico_ip4 default_ip, default_nm, default_gw, zero; const char ipstr[] = CONFIG_USB_DEFAULT_IP; const char nmstr[] = CONFIG_USB_DEFAULT_NM; const char gwstr[] = CONFIG_USB_DEFAULT_GW; zero.addr = 0U; if (!rx_buffer) { rx_buffer = kalloc(sizeof(*rx_buffer)); if (!rx_buffer) return -1; } if (!tx_buffer) { tx_buffer = kalloc(sizeof(*tx_buffer)); if (!tx_buffer) { kfree(rx_buffer); return -1; } } pico_string_to_ipv4(ipstr, &default_ip.addr); pico_string_to_ipv4(nmstr, &default_nm.addr); pico_string_to_ipv4(gwstr, &default_gw.addr); memset(usb, 0, sizeof(struct pico_dev_usbeth)); usb->dev.overhead = 0; usb->dev.send = pico_usbeth_send; usb->dev.poll = pico_usbeth_poll; usb->dev.destroy = pico_usbeth_destroy; if (pico_device_init(&usb->dev,"usb0", mac_addr) < 0) { kfree(usb_buf); kfree(usb); return -1; } pico_usbeth = usb; /* Set address/netmask */ pico_ipv4_link_add(&usb->dev, default_ip, default_nm); /* Set default gateway */ pico_ipv4_route_add(zero, zero, default_gw, 1, NULL); tx_buffer->status = TX_STATUS_FREE; if (usbdev_start(&usbd_dev, dev, &cdc_ecm_info) < 0) { return -EBUSY; } usbd_register_set_config_callback(usbd_dev, cdcecm_set_config); usbd_register_setup_callback(usbd_dev, cdcecm_setup_request); return 0; } ================================================ FILE: kernel/drivers/dma.h ================================================ #ifndef INC_DMA #define INC_DMA struct dma_config { uint32_t base; uint8_t stream; uint32_t channel; uint32_t psize; uint32_t msize; uint32_t dirn; uint32_t prio; uint32_t paddr; uint32_t irq; }; void init_dma(const struct dma_config * dma, uint32_t ptr, uint32_t len); #endif ================================================ FILE: kernel/drivers/dsp.h ================================================ #ifndef INC_DSP #define INC_DSP #ifdef CONFIG_DSP int dsp_init(void); #else # define dsp_init() ((-ENOENT)) #endif #endif ================================================ FILE: kernel/drivers/eth.h ================================================ #ifndef INC_ETH #define INC_ETH #include "frosted.h" #include "gpio.h" struct eth_config { const struct gpio_config *pio_mii; const unsigned int n_pio_mii; const struct gpio_config pio_phy_reset; const int has_phy_reset; }; #ifdef CONFIG_DEVETH int ethernet_init(const struct eth_config *conf); int pico_eth_start(void); #else # define ethernet_init(x) ((-ENOENT)) # define pico_eth_start() ((-ENOENT)) #endif #endif ================================================ FILE: kernel/drivers/exti.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: danielinux, DarkVegetableMatter * */ #include "frosted.h" #include "device.h" #include #include "ioctl.h" #include #include #include #include #include "gpio.h" #include "exti.h" struct dev_exti { int exti; /* Exti index in the dev_exti[] array */ uint32_t base; /* GPIO base */ uint16_t pin; /* GPIO pin */ uint8_t trigger; /* EXTI trigger type */ void (* exti_isr)(void *); /* ISR */ void *exti_isr_arg; }; #define MAX_EXTIS 24 static struct dev_exti *DEV_EXTI[MAX_EXTIS]; void exti_isr(uint32_t exti_base, uint32_t exti_idx) { struct dev_exti *dev = DEV_EXTI[exti_idx]; exti_reset_request(exti_base); if (dev && dev->exti_isr) { dev->exti_isr(dev->exti_isr_arg); } } void exti0_isr(void) { exti_isr(EXTI0, 0); } void exti1_isr(void) { exti_isr(EXTI1, 1); } void exti2_isr(void) { exti_isr(EXTI2, 2); } void exti3_isr(void) { exti_isr(EXTI3, 3); } void exti4_isr(void) { exti_isr(EXTI4, 4); } void exti9_5_isr(void) { if(exti_get_flag_status(EXTI5)) exti_isr(EXTI5, 5); if(exti_get_flag_status(EXTI6)) exti_isr(EXTI6, 6); if(exti_get_flag_status(EXTI7)) exti_isr(EXTI7, 7); if(exti_get_flag_status(EXTI8)) exti_isr(EXTI8, 8); if(exti_get_flag_status(EXTI9)) exti_isr(EXTI9, 9); } void exti15_10_isr(void) { if(exti_get_flag_status(EXTI10)) exti_isr(EXTI10, 10); if(exti_get_flag_status(EXTI11)) exti_isr(EXTI11, 11); if(exti_get_flag_status(EXTI12)) exti_isr(EXTI12, 12); if(exti_get_flag_status(EXTI13)) exti_isr(EXTI13, 13); if(exti_get_flag_status(EXTI14)) exti_isr(EXTI14, 14); if(exti_get_flag_status(EXTI15)) exti_isr(EXTI15, 15); } static uint32_t exti_base(uint16_t pin) { switch(pin) { case GPIO0: return EXTI0; case GPIO1: return EXTI1; case GPIO2: return EXTI2; case GPIO3: return EXTI3; case GPIO4: return EXTI4; case GPIO5: return EXTI5; case GPIO6: return EXTI6; case GPIO7: return EXTI7; case GPIO8: return EXTI8; case GPIO9: return EXTI9; case GPIO10: return EXTI10; case GPIO11: return EXTI11; case GPIO12: return EXTI12; case GPIO13: return EXTI13; case GPIO14: return EXTI14; case GPIO15: return EXTI15; } return (uint32_t)(-1); } static int gpio_id(uint16_t pin) { switch(pin) { case GPIO0: return 0; case GPIO1: return 1; case GPIO2: return 2; case GPIO3: return 3; case GPIO4: return 4; case GPIO5: return 5; case GPIO6: return 6; case GPIO7: return 7; case GPIO8: return 8; case GPIO9: return 9; case GPIO10: return 10; case GPIO11: return 11; case GPIO12: return 12; case GPIO13: return 13; case GPIO14: return 14; case GPIO15: return 15; } return -1; } int exti_register(uint32_t base, uint16_t pin, uint8_t trigger, void (*isr)(void *), void *isr_arg) { uint32_t exti = exti_base(pin); struct dev_exti *e; int idx = gpio_id(pin); if (idx < 0) return -EINVAL; if (DEV_EXTI[idx] != NULL) return -EEXIST; e = kalloc(sizeof(struct dev_exti)); if (!e) return -ENOMEM; e->base = base; e->pin = pin; e->trigger = trigger; e->exti_isr = isr; e->exti_isr_arg = isr_arg; exti_select_source(exti, base); exti_set_trigger(exti, trigger); DEV_EXTI[idx] = e; return idx; } void exti_unregister(int idx) { if(DEV_EXTI[idx]) { kfree(DEV_EXTI[idx]); DEV_EXTI[idx] = NULL; } } int exti_enable(int idx, int enable) { if (DEV_EXTI[idx]) { if(enable) exti_enable_request(exti_base(idx)); else exti_disable_request(exti_base(idx)); return 0; } } void exti_init(void) { int i; uint32_t exti_irq; rcc_periph_clock_enable(RCC_SYSCFG); for(i=0; i < MAX_EXTIS; i++) { DEV_EXTI[i] = NULL; } nvic_enable_irq(NVIC_EXTI0_IRQ); nvic_enable_irq(NVIC_EXTI1_IRQ); nvic_enable_irq(NVIC_EXTI2_IRQ); nvic_enable_irq(NVIC_EXTI3_IRQ); nvic_enable_irq(NVIC_EXTI4_IRQ); nvic_enable_irq(NVIC_EXTI9_5_IRQ); nvic_enable_irq(NVIC_EXTI15_10_IRQ); } ================================================ FILE: kernel/drivers/exti.h ================================================ #ifndef INC_STM32F4EXTI #define INC_STM32F4EXTI #include #include int exti_register(uint32_t base, uint16_t pin, uint8_t trigger, void (*isr)(void *), void *isr_arg); void exti_unregister(int pin); int exti_enable(int idx, int enable); void exti_init(void); #endif ================================================ FILE: kernel/drivers/fbcon.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include #include "poll.h" #include "framebuffer.h" #include "fonts.h" static uint32_t fbcon_l, fbcon_h; static uint32_t screen_rows, screen_cols; #define COLOR_DEFAULT 15 /* White */ struct dev_fbcon { struct device *dev; uint16_t sid; uint16_t size_x; uint16_t size_y; uint16_t cursor; uint8_t color; uint8_t escape; unsigned char *buffer; unsigned char *colormap; unsigned char *screen; }; static int devfbcon_write(struct fnode *fno, const void *buf, unsigned int len); static int devfbcon_read(struct fnode *fno, void *buf, unsigned int len); static int devfbcon_poll(struct fnode *fno, uint16_t events, uint16_t *revents); static void devfbcon_tty_attach(struct fnode *fno, int pid); static int devfbcon_seek(struct fnode *fno, int off, int whence); extern const uint32_t xterm_cmap[256]; static struct module mod_devfbcon = { .family = FAMILY_FILE, .name = "fbcon", .ops.open = device_open, .ops.read = devfbcon_read, .ops.poll = devfbcon_poll, .ops.write = devfbcon_write, .ops.seek = devfbcon_seek, .ops.tty_attach = devfbcon_tty_attach, }; static void devfbcon_tty_attach(struct fnode *fno, int pid) { struct dev_fbcon *fbcon = (struct dev_fbcon *)FNO_MOD_PRIV(fno, &mod_devfbcon); if (fbcon->sid != pid) { //kprintf("/dev/%s active job pid: %d\r\n", fno->fname, pid); fbcon->sid = pid; } } static void render_row(struct dev_fbcon *fbcon, int row) { int i, j, l; unsigned char fc; const unsigned char *fcl; uint8_t fc_color = COLOR_DEFAULT; int screen_off; for (i = 0; i < fbcon_l; i++) { /* Each char ... i = column */ fc = fbcon->buffer[row * fbcon_l + i]; /* fc = char to render */ fc_color = fbcon->colormap[row * fbcon_l + i];/* fc_color: char color */ fcl = fb_font[fc]; /* fcl = font rendering, 8 bytes. */ for (l = 0; l < FONT_HEIGHT; l++) { /* screen lines 0..FONT_HEIGHT */ for (j = 0; j < FONT_WIDTH; j++) { /* each pixel in screen line */ int right_shift = (FONT_HEIGHT - 1) - j; screen_off = ((row * FONT_HEIGHT + l) * screen_cols) + (i * FONT_WIDTH) + j; fbcon->screen[screen_off] = ((fcl[l] & (1 << (7 - j))))?fc_color:0; } } } } static void render_screen(struct dev_fbcon *fbcon) { int i; for (i = 0; i < fbcon_h; i++) render_row(fbcon, i); } static void scroll(struct dev_fbcon *fbcon) { unsigned char *dest = fbcon->buffer; unsigned char *src = fbcon->buffer + fbcon_l; unsigned char *c_dest = fbcon->colormap; unsigned char *c_src = fbcon->colormap + fbcon_l; int i; for (i = 0; i < fbcon_h; i++) { memcpy(dest, src, fbcon_l); dest += fbcon_l; src += fbcon_l; memcpy(c_dest, c_src, fbcon_l); c_dest += fbcon_l; c_src += fbcon_l; } fbcon->cursor = fbcon_l * (fbcon_h - 1); memset(fbcon->buffer + fbcon->cursor, 0, fbcon_l); memset(fbcon->colormap + fbcon->cursor, COLOR_DEFAULT, fbcon_l); } static int devfbcon_write(struct fnode *fno, const void *buf, unsigned int len) { int i, j; struct dev_fbcon *fbcon = (struct dev_fbcon *)FNO_MOD_PRIV(fno, &mod_devfbcon); const uint8_t *cbuf = buf; for (i = 0; i < len; i++) { int p = 0, t = 0; if ((fbcon->cursor) >= (fbcon_l * fbcon_h)) { scroll(fbcon); } if (fbcon->escape == 0x1b) { if (cbuf[i] == '[') fbcon->escape = '['; else { fbcon->color = cbuf[i]; fbcon->escape = 0; } continue; } if (fbcon->escape == '[') { if (cbuf[i] == 'H') { fbcon->cursor = 0; } if (cbuf[i] == 'J') { for (j = fbcon->cursor; j < (fbcon_l * fbcon_h); j++) { fbcon->buffer[j] = 0x20; } } fbcon->escape = 0; continue; } // TODO fbcon->color = cbuf[i]; switch(cbuf[i]) { case '\r': fbcon->cursor -= (fbcon->cursor % fbcon_l); break; /* LF */ case '\n': fbcon->cursor += fbcon_l; break; /* FF */ case 0x0c: memset(fbcon->buffer, 0, fbcon_l * fbcon_h); fbcon->cursor = 0; break; /* TAB */ case '\t': t = fbcon->cursor % 4; if (t == 0) t = 4; for (p = 0; p < t; p++) fbcon->buffer[fbcon->cursor + p] = 0x20; fbcon->cursor += t; break; /* BS */ case 0x08: if (fbcon->cursor > 0) { fbcon->cursor--; fbcon->buffer[fbcon->cursor] = 0x20; fbcon->colormap[fbcon->cursor] = COLOR_DEFAULT; } break; /* DEL */ case 0x7f: fbcon->buffer[fbcon->cursor] = 0x20; fbcon->colormap[fbcon->cursor] = COLOR_DEFAULT; break; /* ESC */ case 0x1b: fbcon->escape = 0x1b; break; /* Printable char */ default: fbcon->colormap[fbcon->cursor] = fbcon->color; fbcon->buffer[fbcon->cursor++] = cbuf[i]; } } render_screen(fbcon); return len; } static int devfbcon_read(struct fnode *fno, void *buf, unsigned int len) { return -EINVAL; } static int devfbcon_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { return 1; } static int devfbcon_seek(struct fnode *fno, int off, int whence) { int new_off; struct dev_fbcon *fbcon = (struct dev_fbcon *)FNO_MOD_PRIV(fno, &mod_devfbcon); switch(whence) { case SEEK_CUR: new_off = fbcon->cursor + off; break; case SEEK_SET: new_off = off; break; case SEEK_END: new_off = fbcon_l * fbcon_h + off; break; default: return -EINVAL; } if (new_off < 0) new_off = 0; if (new_off > fbcon_l * fbcon_h) { new_off = fbcon_l * fbcon_h; } fbcon->cursor = new_off; return 0; } const char frosted_banner[] = "\r\n~~~ Welcome to Frosted! ~~~\r\n"; const char fbcon_banner[] = "\r\nConsole framebuffer enabled.\r\n"; static const unsigned char color[2] = { 0x1b, 13 }; static const unsigned char white[2] = { 0x1b, 15 }; int fbcon_init(uint32_t cols, uint32_t rows) { struct fnode *devfs = fno_search("/dev"); struct dev_fbcon *fbcon = kalloc(sizeof(struct dev_fbcon)); struct fnode *fno_fbcon; if (!fbcon) return -1; memset(fbcon, 0, sizeof(struct dev_fbcon)); screen_cols = cols; screen_rows = rows; fbcon_l = screen_cols / FONT_WIDTH; fbcon_h = screen_rows / FONT_HEIGHT; fbcon->buffer = u_malloc(fbcon_l * fbcon_h); if (!fbcon->buffer) { kfree(fbcon); return -1; } fbcon->colormap = u_malloc(fbcon_l * fbcon_h); if (!fbcon->colormap) { kfree(fbcon->buffer); kfree(fbcon); return -1; } if (devfs == NULL) { kfree(fbcon->colormap); kfree(fbcon->buffer); kfree(fbcon); return -1; } memset(fbcon->buffer, 0, (fbcon_l * fbcon_h)); memset(fbcon->colormap, COLOR_DEFAULT, (fbcon_l * fbcon_h)); register_module(&mod_devfbcon); fno_fbcon = fno_create(&mod_devfbcon, "fbcon", devfs); fno_fbcon->priv = fbcon; fbcon->size_x = fbcon_l; fbcon->size_y = fbcon_h; fbcon->screen = framebuffer_get(); fbcon->color = COLOR_DEFAULT; framebuffer_setcmap(xterm_cmap); /* Test */ devfbcon_write(fno_fbcon, color, 2); devfbcon_write(fno_fbcon, frosted_banner, strlen(frosted_banner)); devfbcon_write(fno_fbcon, white, 2); devfbcon_write(fno_fbcon, fbcon_banner, strlen(fbcon_banner)); return 0; } ================================================ FILE: kernel/drivers/fbcon.h ================================================ #ifndef FBCON_INCLUDED #define FBCON_INCLUDED #include #include "frosted.h" #ifdef CONFIG_DEVFBCON /* kernel init */ int fbcon_init(uint32_t cols, uint32_t rows); #else # define fbcon_init(...) ((-ENOENT)) #endif #endif ================================================ FILE: kernel/drivers/fonts.h ================================================ #ifndef INCLUDE_FONT_DEFINITION #define INCLUDE_FONT_DEFINITION #ifdef CONFIG_FONT_7x6 # define FONT_HEIGHT 7 # define FONT_WIDTH 6 #endif #ifdef CONFIG_FONT_8x8 # define FONT_HEIGHT 8 # define FONT_WIDTH 8 #endif extern const unsigned char fb_font[256][FONT_HEIGHT]; #endif ================================================ FILE: kernel/drivers/fortuna.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Alexander Wood, brabo * */ #include "frosted.h" #include "device.h" #include "crypto/misc.h" #include "crypto/aes.h" #include "crypto/sha256.h" #include "fortuna.h" #include #include /* Fortuna architecture defines */ #define FORTUNA_POOL_COUNT 1 #define FORTUNA_MINIMUM_RESEED_MS 100 #define FORTUNA_MINIMUM_RESEED_ENTR 1 #define FORTUNA_MAX_REQUEST_BYTES 1048576 struct fortuna_counter { uint8_t values[16]; /* Fortuna requires a 128-bit counter */ }; /* Internal generator state */ struct fortuna_generator_state { /* Fortuna internals */ uint8_t *key; /* 32 byte key */ struct fortuna_counter *counter; Sha256 *pool; unsigned int last_reseed_time; /* AES and SHA internal stuff */ Aes *aes; Sha256 *sha; }; struct fortuna_generator_state fortuna_generator = {}; /* Internal helper functions */ static int fortuna_extract_seed(uint8_t *seed_buffer, int buffer_size); static int fortuna_reseed(uint8_t *seed, uint8_t seed_size); static int fortuna_generate_block(uint8_t *buffer, int buffer_size); static inline void fortuna_init_counter(struct fortuna_counter *counter) { int i; for (i = 0; i < 16; i++) { counter->values[i] = 0; } } static inline void fortuna_increment_counter(struct fortuna_counter *counter) { int i; for (i = 0; i < 16; i++) { if (counter->values[i] < 0xFF) { /* Not at maximum value */ counter->values[i]++; return; /* Only return once we've found one not ready to overflow */ } else { counter->values[i] = 0; } } } static int fortuna_counter_is_zero(struct fortuna_counter *counter) { int i; for (i = 0; i < 16; i++) { if (counter->values[i] != 0) { return 0; } } return 1; /* None of the individual values are non-zero, so... */ } /* Prepare a seed from the selected pools. Helper function for re-seeding. */ static int fortuna_extract_seed(uint8_t *seed_buffer, int buffer_size) { int i = 0; int hashes_added = 0; for (i = 0; i < FORTUNA_POOL_COUNT; i++) { if (((i % 8) == 0) || (fortuna_generator.counter->values[0] & (1 << ((i - 1) % 8)))) { /* Use nth pool every (2^n)th reseed (so p1 every other time, p2 every 4th... */ if ((hashes_added + 1) * FORTUNA_HASH_SIZE <= buffer_size) { /* Extract final hash for given pool, and put in appropriate part of seed buffer */ wc_Sha256Final(&(fortuna_generator.pool[i]), seed_buffer + (FORTUNA_HASH_SIZE * hashes_added)); hashes_added++; } else { /* Buffer not big enough */ return 0; } } } return (hashes_added * FORTUNA_HASH_SIZE); /* Actual size of seed */ } /* Re-seed the generator. Called when enough data has been used from the current 'run' */ static int fortuna_reseed(uint8_t *seed, uint8_t seed_size) { uint8_t *sha_input = NULL; sha_input = (uint8_t *)kalloc(seed_size + FORTUNA_ENCRYPT_KEY_SIZE); /* Seed size + 256b of current SHA hash key */ if (NULL == sha_input) { /* Failed to alloc, don't increment counter */ return 0; } else { memcpy(sha_input, fortuna_generator.key, FORTUNA_ENCRYPT_KEY_SIZE); /* Current key */ memcpy(sha_input + FORTUNA_ENCRYPT_KEY_SIZE, seed, seed_size); /* New seed */ } wc_InitSha256(fortuna_generator.sha); wc_Sha256Update(fortuna_generator.sha, sha_input, seed_size + 32); wc_Sha256Final(fortuna_generator.sha, fortuna_generator.key); fortuna_increment_counter(fortuna_generator.counter); kfree(sha_input); return 1; } /* Generate blocks of random data. Underlying function used by the user-callable random data functions. */ static int fortuna_generate_block(uint8_t *buffer, int buffer_size) { uint8_t encrypt_iv[FORTUNA_ENCRYPT_IV_SIZE] = { 0 }; /* Can't use ECB mode and combine it with our external counter, so doing it this way */ /* Run encryption block */ if (!fortuna_counter_is_zero(fortuna_generator.counter)) { /* Refuse if not seeded */ if (buffer_size >= FORTUNA_ENCRYPT_BLOCK_SIZE) { wc_AesSetKey(fortuna_generator.aes, fortuna_generator.key, FORTUNA_ENCRYPT_KEY_SIZE, encrypt_iv, AES_ENCRYPTION); wc_AesCbcEncrypt(fortuna_generator.aes, buffer, (const byte *)fortuna_generator.counter, FORTUNA_ENCRYPT_IV_SIZE); fortuna_increment_counter(fortuna_generator.counter); return 1; /* Done succesfully */ } /* Buffer size smaller than block size! */ return 0; } else { /* Not seeded, cannot produce anything! */ return 0; } } /* Public Fortuna functions */ /* Sets up the generator */ int fortuna_init(void) { int i = 0; fortuna_generator.key = kalloc(sizeof(uint8_t) * FORTUNA_ENCRYPT_KEY_SIZE); fortuna_generator.pool = kalloc(sizeof(Sha256) * FORTUNA_POOL_COUNT); /* n pools of strings; in practice, hashes iteratively updated */ fortuna_generator.counter = kalloc(sizeof(struct fortuna_counter)); fortuna_generator.aes = kalloc(sizeof(Aes)); fortuna_generator.sha = kalloc(sizeof(Sha256)); if (NULL == fortuna_generator.key || NULL == fortuna_generator.pool || NULL == fortuna_generator.aes || NULL == fortuna_generator.sha) { return -1; /* Failed to allocate memory! */ } /* Set counter to 0 (also indicates unseeded state) */ fortuna_init_counter(fortuna_generator.counter); for (i = 0; i < FORTUNA_POOL_COUNT; i++) { wc_InitSha256(&(fortuna_generator.pool[i])); /* TODO right? What does this look like in assembly? */ } return 0; } /* Add some entropy to a given pool TODO why need source IDs? */ void fortuna_accu(int source, int pool, uint8_t *data, int data_size) { /* To be safe, but should avoid needing to do this, as it'll favour lower pools... */ pool = pool % FORTUNA_POOL_COUNT; /* Add the new entropy data to the specified pool */ wc_Sha256Update(&(fortuna_generator.pool[pool]), data, data_size); } /* Get some random bytes from the generator. */ int fortuna_get_bytes(uint8_t *buffer, int count) { int remaining_bytes = 0; uint8_t *block_buffer = 0; uint8_t *seed_buffer = 0; int blocks_done = 0; int seed_size = 0; if ((count > 0) && (count < (2 * 1024 * 1024))) { // probably we need to initialize and update fortuna_generator.last_reseed_time? if ((jiffies - fortuna_generator.last_reseed_time >= FORTUNA_MINIMUM_RESEED_MS) && (1 >= FORTUNA_MINIMUM_RESEED_ENTR)) { /* FIXME to check 'size' of pool 0 */ seed_buffer = kalloc(sizeof(uint8_t) * FORTUNA_POOL_COUNT * FORTUNA_HASH_SIZE); /* Assume that we use every pool hash... */ if (NULL == seed_buffer) { return 0; } seed_size = fortuna_extract_seed(seed_buffer, (sizeof(uint8_t) * FORTUNA_POOL_COUNT * FORTUNA_HASH_SIZE)); fortuna_reseed(seed_buffer, seed_size); kfree(seed_buffer); } /* Get random blocks until we have our data. */ for (remaining_bytes = count; remaining_bytes > 0; remaining_bytes -= FORTUNA_ENCRYPT_BLOCK_SIZE) { if (remaining_bytes / FORTUNA_ENCRYPT_BLOCK_SIZE > 0) { /* At least one full block remaining? Can copy directly without overflowing. */ fortuna_generate_block(buffer + (FORTUNA_ENCRYPT_BLOCK_SIZE * blocks_done++), FORTUNA_ENCRYPT_BLOCK_SIZE); /* TODO check! */ } else { /* This'll only be necessary for the last block, and only if requested byte count != multiple of block size */ block_buffer = kalloc(FORTUNA_ENCRYPT_BLOCK_SIZE); if (NULL != block_buffer) { fortuna_generate_block(block_buffer, FORTUNA_ENCRYPT_BLOCK_SIZE); /* Copy required part of block to output */ memcpy(buffer + (blocks_done * FORTUNA_ENCRYPT_BLOCK_SIZE), block_buffer, remaining_bytes); kfree(block_buffer); } else { return 0; } } } return 1; } else { /* Not allowed to produce more than 1MiB of data at once */ return 0; } } void fortuna_shutdown(void) { /* Don't just PICO_FREE them, otherwise generator internals still available in RAM! */ /* If we're going to set it to something, might as well be 10101010, in case there're any weird electrical effects making it easy to detect was-1s or was-0s or something */ memset(fortuna_generator.key, 0x55, (sizeof(uint8_t) * 32)); memset(fortuna_generator.counter, 0x55, (sizeof(struct fortuna_counter))); memset(fortuna_generator.pool, 0x55, (sizeof(Sha256) * FORTUNA_POOL_COUNT)); memset(fortuna_generator.aes, 0x55, (sizeof(Aes))); memset(fortuna_generator.sha, 0x55, (sizeof(Sha256))); kfree(fortuna_generator.key); kfree(fortuna_generator.counter); kfree(fortuna_generator.pool); kfree(fortuna_generator.aes); kfree(fortuna_generator.sha); } ================================================ FILE: kernel/drivers/framebuffer.h ================================================ #ifndef FRAMEBUFFER_INCLUDED #define FRAMEBUFFER_INCLUDED #include #include "frosted.h" #include struct fb_ops; struct fb_info { struct fb_var_screeninfo var; /* Current var */ //struct fb_fix_screeninfo fix; /* Current fix */ struct fb_videomode *mode; /* current mode */ //struct backlight_device *bl_dev; struct fb_ops *fbops; struct device *dev; /* This is this fb device */ uint8_t *screen_buffer; /* Framebuffer address */ }; struct fb_ops { /* open/release and usage marking */ int (*fb_open)(struct fb_info *info); int (*fb_release)(struct fb_info *info); /* checks var and eventually tweaks it to something supported, * DO NOT MODIFY PAR */ int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); /* set the video mode according to info->var */ int (*fb_set_par)(struct fb_info *info); /* set color registers in batch */ int (*fb_setcmap)(uint32_t *cmap, struct fb_info *info); /* blank display */ int (*fb_blank)(struct fb_info *info); /* Draws a rectangle */ //void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); /* Copy data from area to another */ //void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); /* Draws a image to the display */ //void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); /* Draws cursor */ //int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); /* Rotates the display */ //void (*fb_rotate)(struct fb_info *info, int angle); /* perform fb specific ioctl (optional) */ int (*fb_ioctl)(struct fb_info *info, unsigned int cmd, unsigned long arg); /* teardown any resources to do with this framebuffer */ void (*fb_destroy)(struct fb_info *info); }; #ifdef CONFIG_DEVFRAMEBUFFER /* low-level drivers must call this register function first */ int register_framebuffer(struct fb_info *fb_info); /* Higher level drivers may access fb screen directly */ unsigned char *framebuffer_get(void); int framebuffer_setcmap(uint32_t *cmap); /* kernel init */ int fb_init(void); #else # define register_framebuffer(...) ((-ENOENT)) # define fb_init() ((-ENOENT)) #endif #endif ================================================ FILE: kernel/drivers/frand.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: brabo * */ #include "frosted.h" #include "device.h" #include "frand.h" #include "fortuna.h" #include "rng.h" #include #include #if defined(STM32F2) || defined(STM32F4) || defined(STM32F7) # include "unicore-mx/stm32/rng.h" #endif #define MAX_FRANDS (1) extern uint32_t req; static struct frand_info *frand[MAX_FRANDS] = { 0 }; static int frand_open(const char *path, int flags); static int frand_read(struct fnode *fno, void *buf, unsigned int len); static struct module mod_devfrand = { .family = FAMILY_FILE, .name = "frand", .ops.open = frand_open, .ops.read = frand_read, }; static int frand_open(const char *path, int flags) { struct fnode *f = fno_search(path); if (!f) return -1; return device_open(path, flags); } static int frand_read(struct fnode *fno, void *buf, unsigned int len) { struct frand_info *frand; if (len == 0) return len; frand = (struct frand_info *)FNO_MOD_PRIV(fno, &mod_devfrand); if (!frand) return -1; // mutex_lock(fb->dev->mutex); fortuna_get_bytes(buf, len); req += len; rng_enable_interrupt(); //mutex_unlock(fb->dev->mutex); return len; } static int frand_fno_init(struct fnode *dev, struct frand_info *frand) { static int num_frand = 0; char name[7] = "frand"; if (!frand) return -1; name[6] = '0' + num_frand++; frand->dev = device_fno_init(&mod_devfrand, name, dev, FL_TTY, frand); return 0; } void frand_init(struct fnode *dev) { /* Ony one FRAND supported for now */ frand_fno_init(dev, frand[0]); } /* Register a low-level frand driver */ int register_frand(struct frand_info *frand_info) { if (!frand_info) return -1; if (!frand_info->frandops) return -1; if (frand_info->frandops->frand_open) frand_info->frandops->frand_open(frand_info); frand[0] = frand_info; register_module(&mod_devfrand); fortuna_init(); return 0; } ================================================ FILE: kernel/drivers/ft5336.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include #include "cirbuf.h" #include "dma.h" #include "cirbuf.h" #include "i2c.h" #define FT5336_I2C_ADDR (0x70) #define MAX_W (480) #define MAX_H (272) #define FT5336_MODE (0x00) #define FT5336_GESTURE_ID (0x01) #define FT5336_TOUCHDATA (0x02) # define TD_PRESS (0x00) # define TD_RELEASE (0x01) # define TD_CONTACT (0x02) #define FT5336_P1_XH (0x03) #define FT5336_P1_YH (0x05) #define FT5336_G_MODE (0xA4) #define FT5336_G_MODE_INTERRUPT (0x01) #define FT5336_CHIP_ID (0xA8) #define FT5336_CHIP_ID_VAL (0x51) /* Single device supported in this driver. */ #define ST_OFF 0 #define ST_RDY 1 #define ST_ON 2 struct dev_ts { struct i2c_slave i2c; struct device *dev; uint8_t i2c_data; int state; } Ts; /* Module description */ int ft5336_read(struct fnode *fno, void *buf, unsigned int len) { return 0; } static struct module mod_devts = { .family = FAMILY_FILE, .name = "ts", .ops.open = device_open, .ops.read = ft5336_read }; static void ft5336_task(void *arg) { (void)arg; uint8_t val; if (i2c_kthread_read(&Ts.i2c, FT5336_CHIP_ID, &val, 1) > 0) { if (val != FT5336_CHIP_ID_VAL) return 0; /* kthread terminated. */ } val = FT5336_G_MODE_INTERRUPT; i2c_kthread_write(&Ts.i2c, FT5336_G_MODE, &val, 1); } int ft5336_init(uint32_t bus) { int i; struct fnode *devdir = fno_search("/dev"); if (!devdir) return -ENOENT; memset(&Ts, 0, sizeof(struct dev_ts)); Ts.dev = device_fno_init(&mod_devts, "ts", devdir, 0, &Ts); /* Populate i2c_slave struct */ Ts.i2c.bus = bus; Ts.i2c.address = FT5336_I2C_ADDR; kthread_create(ft5336_task, NULL); return 0; } ================================================ FILE: kernel/drivers/gpio.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include "gpio.h" #include #include "ioctl.h" #include "poll.h" #include "sys/frosted-io.h" #if defined(STM32F4) || defined(STM32F7) #include #include #include static inline uint32_t ARCH_GPIO_BASE(int x) { switch(x) { case 1: return GPIOA; case 2: return GPIOB; case 3: return GPIOC; case 4: return GPIOD; case 5: return GPIOE; case 6: return GPIOF; case 7: return GPIOG; case 8: return GPIOH; case 9: return GPIOI; case 10: return GPIOJ; case 11: return GPIOK; default: return 0; } } #define ARCH_GPIO_PIN(X) (1 << X) #define ARCH_GPIO_BASE_MAX 31 #define ARCH_GPIO_PIN_MAX 15 #include "exti.h" #endif #ifdef STM32F7 #include #include #include #endif #if defined(NRF51) || defined(NRF52) #include static inline uint32_t ARCH_GPIO_BASE(int x) { return GPIO_BASE; } #define ARCH_GPIO_PIN(X) (1 << X) #define ARCH_GPIO_BASE_MAX 1 #define ARCH_GPIO_PIN_MAX 31 int exti_register(uint32_t base, uint16_t pin, uint8_t trigger, void (*isr)(void *), void *isr_arg) { } void exti_unregister(int pin) { } int exti_enable(int idx, int enable) { } void exti_init(void) { } #endif #ifdef LPC17XX #include #include #include #include static inline uint32_t ARCH_GPIO_BASE(int x) { switch(x) { case 1: return GPIO1; case 2: return GPIO2; case 3: return GPIO3; case 4: return GPIO4; default: return 0; } } #define ARCH_GPIO_PIN(X) (1 << X) #define ARCH_GPIO_BASE_MAX 4 #define ARCH_GPIO_PIN_MAX 32 #endif #ifdef PYBOARD # define LED0 "gpio_1_13" # define LED1 "gpio_1_14" # define LED2 "gpio_1_15" # define LED3 "gpio_1_4" #elif defined (STM32F7) # define LED0 "gpio_9_1" # define LED1 "" # define LED2 "" # define LED3 "" #elif defined (STM32F4) # if defined (F429DISCO) # define LED0 "gpio_6_13" # define LED1 "gpio_6_14" # else # define LED0 "gpio_3_12" # define LED1 "gpio_3_13" #endif # define LED2 "gpio_3_14" # define LED3 "gpio_3_15" #elif defined (LPC17XX) #if 0 /*LPCXpresso 1769 */ # define LED0 "/dev/gpio_0_22" # define LED1 "/dev/null" # define LED2 "/dev/null" # define LED3 "/dev/null" #else /* mbed 1768 */ # define LED0 "gpio_1_18" # define LED1 "gpio_1_20" # define LED2 "gpio_1_21" # define LED3 "gpio_1_23" #endif #else # define LED0 "null" # define LED1 "null" # define LED2 "null" # define LED3 "null" #endif #include "gpio.h" struct dev_gpio *Gpio_list = NULL; struct dev_gpio *Gpio_list_tail = NULL; static void gpio_list_add(struct dev_gpio *pio) { pio->next = NULL; if (!Gpio_list) { Gpio_list = pio; Gpio_list_tail = pio; } else { Gpio_list_tail->next = pio; Gpio_list_tail = pio; } } static struct dev_gpio *gpio_list_find(uint32_t base, uint32_t pin) { struct dev_gpio *cur = Gpio_list; while(cur) { if ((cur->base == base) && (cur->pin == pin)) return cur; cur = cur->next; } return NULL; } static void gpio_list_del(struct dev_gpio *old) { struct dev_gpio *cur = Gpio_list; struct dev_gpio *last = NULL; while(cur) { if (cur == old) { if (last == NULL) Gpio_list = cur->next; else last->next = cur->next; if (Gpio_list_tail == cur) Gpio_list_tail = last; return; } last = cur; cur = cur->next; } } int gpio_list_len(void) { int len = 0; struct dev_gpio *l = Gpio_list; while(l) { len++; l = l->next; } return len; } static int devgpio_write(struct fnode *fno, const void *buf, unsigned int len); static int devgpio_ioctl(struct fnode *fno, const uint32_t cmd, void *arg); static int devgpio_read (struct fnode *fno, void *buf, unsigned int len); static int devgpio_poll (struct fnode *fno, uint16_t events, uint16_t *revents); static int devgpio_close (struct fnode *fno); static int devgpiomx_ioctl(struct fnode * fno, const uint32_t cmd, void *arg); static struct module mod_devgpio = { .family = FAMILY_FILE, .name = "gpio", .ops.open = device_open, .ops.read = devgpio_read, .ops.poll = devgpio_poll, .ops.write = devgpio_write, .ops.ioctl = devgpio_ioctl, .ops.close = devgpio_close, }; static struct module mod_devgpio_mx = { .family = FAMILY_FILE, .name = "gpio-mx", .ops.ioctl = devgpiomx_ioctl, }; /****************/ /* HW specifics */ /****************/ /* LM3S */ #ifdef LM3S #endif /* STM32 */ #if defined(STM32F4) || defined(STM32F7) #define GPIO_CLOCK_ENABLE(P) switch(P){ \ case GPIOA:rcc_periph_clock_enable(RCC_GPIOA); break; \ case GPIOB:rcc_periph_clock_enable(RCC_GPIOB); break; \ case GPIOC:rcc_periph_clock_enable(RCC_GPIOC); break; \ case GPIOD:rcc_periph_clock_enable(RCC_GPIOD); break; \ case GPIOE:rcc_periph_clock_enable(RCC_GPIOE); break; \ case GPIOF:rcc_periph_clock_enable(RCC_GPIOF); break; \ case GPIOG:rcc_periph_clock_enable(RCC_GPIOG); break; \ case GPIOH:rcc_periph_clock_enable(RCC_GPIOH); break; \ case GPIOI:rcc_periph_clock_enable(RCC_GPIOI); break; \ case GPIOJ:rcc_periph_clock_enable(RCC_GPIOJ); break; \ case GPIOK:rcc_periph_clock_enable(RCC_GPIOK); break; \ } #define SET_INPUT(P, D, I) gpio_mode_setup(P, GPIO_MODE_INPUT, D, I); #define SET_OUTPUT(P, I, O, S) gpio_mode_setup(P, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, I); \ gpio_set_output_options(P, O, S, I); #define SET_AF(P, M, A, I, O, S) gpio_mode_setup(P, M, GPIO_PUPD_NONE, I); \ gpio_set_output_options(P, O, S, I); \ gpio_set_af(P, A, I); #endif /* NRF */ #if defined(NRF51) || defined(NRF52) #define GPIO_CLOCK_ENABLE(C) #define SET_INPUT(P, D, I) gpio_mode_setup(P, GPIO_MODE_INPUT, D, I); #define SET_OUTPUT(P, I, O, S) gpio_mode_setup(P, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, I); #endif /* LPC */ #ifdef LPC17XX #define GPIO_CLOCK_ENABLE(C) pwr_enable_peripherals(PWR_PCONP_GPIO); #define SET_INPUT(P, D, I) gpio_mode_setup(P, GPIO_MODE_INPUT, D, I); \ gpio_set_af(P, GPIO_AF0, I); #define SET_OUTPUT(P, I, O, S) gpio_mode_setup(P, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, I); \ gpio_set_af(P, GPIO_AF0, I); #define SET_AF(P, M, A, I, O, S) gpio_mode_setup(P, M, GPIO_PUPD_NONE, I); \ gpio_set_af(P, A, I); void eint_isr(uint32_t exti_base) { /* What next? */ exti_clear_flag(exti_base); } void eint0_isr(void) { eint_isr(EXTI0); } void eint1_isr(void) { eint_isr(EXTI1); } void eint2_isr(void) { eint_isr(EXTI2); } void eint3_isr(void) { eint_isr(EXTI3); } #endif static void gpio_isr(void *arg) { struct dev_gpio *gpio = arg; if (gpio->trigger) exti_enable(gpio->exti_idx, 0); if (gpio->dev->task != NULL) { task_resume(gpio->dev->task); } } static int gpio_set_trigger(struct dev_gpio *gpio, uint32_t trigger) { uint32_t val = gpio_get(gpio->base, gpio->pin); gpio->trigger = (uint8_t) trigger; RESET_TRIGGER_WAITING(gpio); if (trigger == GPIO_TRIGGER_TOGGLE) { if (val) SET_TRIGGER_WAITING(gpio, GPIO_TRIGGER_FALL); else SET_TRIGGER_WAITING(gpio, GPIO_TRIGGER_RAISE); } else { SET_TRIGGER_WAITING(gpio, trigger); } if (trigger) return exti_register(gpio->base, gpio->pin, gpio->trigger, gpio_isr, gpio); else return 0; } static int devgpiomx_ioctl(struct fnode * fno, const uint32_t cmd, void *arg) { struct dev_gpiomx *gpiomx; struct gpio_req *req = arg; struct gpio_config addr = { }; if ((req->base == 0) || (req->pin == 0)) return -EINVAL; if ((req->base > ARCH_GPIO_BASE_MAX) || (req->pin > ARCH_GPIO_PIN_MAX)) return -EINVAL; addr.base = ARCH_GPIO_BASE(req->base); addr.pin = ARCH_GPIO_PIN(req->pin); addr.pullupdown = GPIO_PUPD_NONE; if (cmd == IOCTL_GPIOMX_CREATE) { if (gpio_list_find(addr.base, addr.pin)) return -EEXIST; addr.name = req->name; gpio_create(&mod_devgpio, &addr ); return 0; } if (cmd == IOCTL_GPIOMX_DESTROY) { return 0; } return -EINVAL; } static int devgpio_write(struct fnode * fno, const void *buf, unsigned int len) { struct dev_gpio *gpio; char *arg = (char *)buf; gpio = (struct dev_gpio *)FNO_MOD_PRIV(fno, &mod_devgpio); if(!gpio) return -1; if (arg[0] == '1') { gpio_set(gpio->base, gpio->pin); return 1; } else if (arg[0] == '0') { gpio_clear(gpio->base, gpio->pin); return 1; } else { return -1; } } static int devgpio_ioctl(struct fnode * fno, const uint32_t cmd, void *arg) { struct dev_gpio *gpio; gpio = (struct dev_gpio *)FNO_MOD_PRIV(fno, &mod_devgpio); if(!gpio) return -EEXIST; /* (protected GPIOs cannot be reconfigured from userspace) */ if (IS_PROTECTED(gpio)) { return -EPERM; } if (cmd == IOCTL_GPIO_ENABLE) { return 0; } if (cmd == IOCTL_GPIO_DISABLE) { return 0; } if (cmd == IOCTL_GPIO_SET_INPUT) { SET_INPUT(gpio->base, GPIO_PUPD_NONE, gpio->pin); return 0; } if (cmd == IOCTL_GPIO_SET_OUTPUT) { SET_OUTPUT(gpio->base, gpio->pin, gpio->optype, gpio->speed); return 0; } if (cmd == IOCTL_GPIO_SET_PULLUPDOWN) { /* Setting pullup/down implies an input */ SET_INPUT(gpio->base, *((uint32_t*)arg), gpio->pin); return 0; } #ifdef GPIO_MODE_AF if (cmd == IOCTL_GPIO_SET_ALT_FUNC) { gpio_set_af(gpio->base, *((uint32_t*)arg), gpio->pin); return 0; } #endif if (cmd == IOCTL_GPIO_SET_TRIGGER) { uint32_t trigger = *((uint32_t *)arg); if (trigger > GPIO_TRIGGER_TOGGLE) { gpio->trigger = 0; return -EINVAL; } gpio->exti_idx = gpio_set_trigger(gpio, trigger); return 0; } return -EINVAL; } static int devgpio_read(struct fnode * fno, void *buf, unsigned int len) { int out; struct dev_gpio *gpio; char *ptr = (char *)buf; uint8_t val = 0; gpio = (struct dev_gpio *)FNO_MOD_PRIV(fno, &mod_devgpio); if(!gpio) return -1; /* GPIO: get current value */ val = gpio_get(gpio->base, gpio->pin); if (gpio->trigger) { if ((gpio->dev->task) && (gpio->dev->task != this_task())) { return -EBUSY; } gpio->dev->task = this_task(); if ((gpio->trigger == GPIO_TRIGGER_NONE) || (val && (gpio->trigger == GPIO_TRIGGER_RAISE)) || (!val && (gpio->trigger == GPIO_TRIGGER_FALL))) { /* Unlock immediately */ *((uint8_t*)buf) = val ? '1':'0'; gpio->dev->task = NULL; return 1; } else if (gpio->trigger == GPIO_TRIGGER_TOGGLE) { if (TRIGGER_WAITING(gpio) == val) { *((uint8_t*)buf) = val ? '1':'0'; RESET_TRIGGER_WAITING(gpio); SET_TRIGGER_WAITING(gpio, (val) ? GPIO_TRIGGER_FALL : GPIO_TRIGGER_RAISE); gpio->dev->task = NULL; return 1; } } task_suspend(); exti_enable(gpio->exti_idx, 1); return SYS_CALL_AGAIN; } else { *((uint8_t*)buf) = val ? '1':'0'; return 1; } } static int devgpio_poll(struct fnode * fno, uint16_t events, uint16_t *revents) { int ret = 0; struct dev_gpio *gpio = (struct dev_gpio *)FNO_MOD_PRIV(fno, &mod_devgpio); if(!gpio) return -EEXIST; if (events & POLLOUT) { *revents |= POLLOUT; ret = 1; } if (events == POLLIN) { uint8_t val; if (gpio->trigger) { if ((gpio->dev->task) && (gpio->dev->task != this_task())) { return -EBUSY; } gpio->dev->task = this_task(); val = gpio_get(gpio->base, gpio->pin); if ((val && (gpio->trigger == GPIO_TRIGGER_RAISE)) || (!val && (gpio->trigger == GPIO_TRIGGER_FALL))) { ret = 1; *revents |= POLLIN; } else if ((gpio->trigger == GPIO_TRIGGER_TOGGLE) && (TRIGGER_WAITING(gpio) == val)) { ret = 1; *revents |= POLLIN; } } else { ret = 1; *revents |= POLLIN; } } return ret; } static void gpio_fno_init(struct dev_gpio *g, const char *name) { struct fnode *devfs = fno_search("/dev"); if (!devfs) return; g->dev = device_fno_init(&mod_devgpio, name, devfs, FL_RDWR, g); g->base = g->base; g->pin = g->pin; if (strcmp(name, LED0) == 0) { char gpio_name[32] = "/dev/"; strcat(gpio_name, LED0); vfs_symlink(gpio_name, "/dev/led0"); } if (strcmp(name, LED1) == 0) { char gpio_name[32] = "/dev/"; strcat(gpio_name, LED1); vfs_symlink(gpio_name, "/dev/led1"); } if (strcmp(name, LED2) == 0) { char gpio_name[32] = "/dev/"; strcat(gpio_name, LED2); vfs_symlink(gpio_name, "/dev/led2"); } if (strcmp(name, LED3) == 0) { char gpio_name[32] = "/dev/"; strcat(gpio_name, LED3); vfs_symlink(gpio_name, "/dev/led3"); } } int gpio_create(struct module *mod, const struct gpio_config *gpio_config) { struct dev_gpio *gpio; if(gpio_config->base == 0) return -EINVAL; gpio = kalloc(sizeof(struct dev_gpio)); if (!gpio) return -ENOMEM; memset(gpio, 0, sizeof(struct gpio_config)); gpio->base = gpio_config->base; gpio->pin = gpio_config->pin; gpio->mode = gpio_config->mode; gpio->af = gpio_config->af; gpio->speed = gpio_config->speed; gpio->optype = gpio_config->optype; gpio->pullupdown = gpio_config->pullupdown; gpio->trigger = GPIO_TRIGGER_NONE; if (gpio_config->name) { gpio_fno_init(gpio, gpio_config->name); } if (mod) gpio->owner = mod; else gpio->owner = &mod_devgpio; if (gpio->owner != &mod_devgpio) { gpio->flags |= GPIO_FL_PROTECTED; } else { gpio->flags &= ~GPIO_FL_PROTECTED; } GPIO_CLOCK_ENABLE(gpio_config->base); switch(gpio_config->mode) { case GPIO_MODE_INPUT: SET_INPUT(gpio_config->base, gpio_config->pullupdown, gpio_config->pin); break; case GPIO_MODE_OUTPUT: SET_OUTPUT(gpio_config->base, gpio_config->pin, gpio_config->optype, gpio_config->speed); break; #ifdef GPIO_MODE_AF case GPIO_MODE_AF: SET_AF(gpio_config->base, GPIO_MODE_AF, gpio_config->af, gpio_config->pin, gpio_config->optype, gpio_config->speed); break; #endif case GPIO_MODE_ANALOG: gpio_mode_setup(gpio_config->base, gpio_config->mode, GPIO_PUPD_NONE, gpio_config->pin); break; } if (gpio_config->trigger > 0) { gpio->exti_idx = gpio_set_trigger(gpio, gpio_config->trigger); } gpio_list_add(gpio); return 0; } int gpio_init(void) { static struct device *gpiomx_dev = NULL; struct fnode *devfs = fno_search("/dev"); if (!devfs) return -ENOENT; gpiomx_dev = device_fno_init(&mod_devgpio_mx, "gpiomx", devfs, FL_RDWR, &mod_devgpio_mx); register_module(&mod_devgpio); register_module(&mod_devgpio_mx); return 0; } static int devgpio_close(struct fnode *fno) { struct dev_gpio *gpio = (struct dev_gpio *)FNO_MOD_PRIV(fno, &mod_devgpio); if (gpio) { gpio->dev->task = NULL; } return 0; } ================================================ FILE: kernel/drivers/gpio.h ================================================ #ifndef INC_GPIO #define INC_GPIO #include "frosted.h" #include "sys/frosted-io.h" #if defined(STM32F4) || defined(STM32F7) #include #endif struct gpio_config { uint32_t base; uint32_t pin; uint32_t mode; uint8_t pullupdown; uint8_t speed; uint8_t optype; uint8_t af; uint32_t trigger; const char* name; }; #define GPIO_FL_PROTECTED (0x10) #define SET_TRIGGER_WAITING(x,t) x->flags|=t #define RESET_TRIGGER_WAITING(x) x->flags&=0xFFFFFFF0 #define TRIGGER_WAITING(x) (((x->flags & 0x0F) == GPIO_TRIGGER_RAISE)?1:0) #define IS_PROTECTED(x) ((x->flags & GPIO_FL_PROTECTED) == GPIO_FL_PROTECTED) struct dev_gpio { struct device *dev; struct module *owner; /* Module that registered the gpio */ uint32_t mode; uint32_t af; uint32_t base; uint32_t pin; uint8_t trigger; int exti_idx; unsigned int flags; uint32_t optype; uint32_t speed; uint8_t pullupdown; struct dev_gpio *next; }; extern struct dev_gpio *Gpio_list; int gpio_init(void); int gpio_list_len(void); int gpio_create(struct module *mod, const struct gpio_config *gpio_config); #endif ================================================ FILE: kernel/drivers/i2c.h ================================================ #ifndef INC_I2C #define INC_I2C #include "dma.h" #include "gpio.h" struct i2c_config { int idx; uint32_t base; uint32_t ev_irq; uint32_t er_irq; uint32_t rcc; uint32_t clock_speed; uint32_t fast_mode; uint32_t rise_time; uint32_t bus_clk_frequency; uint32_t clock_f; uint32_t dma_rcc; struct dma_config tx_dma; struct dma_config rx_dma; struct gpio_config pio_scl; struct gpio_config pio_sda; }; struct i2c_slave { int bus; uint8_t address; void (*isr_tx)(struct i2c_slave *); void (*isr_rx)(struct i2c_slave *); void *priv; }; int i2c_create(const struct i2c_config *i2c_config); int i2c_init_read(struct i2c_slave *sl, uint8_t reg, uint8_t *buf, uint32_t len); int i2c_init_write(struct i2c_slave *sl, uint8_t reg, const uint8_t *buf, uint32_t len); int i2c_kthread_read(struct i2c_slave *sl, uint8_t reg, uint8_t *buf, uint32_t len); int i2c_kthread_write(struct i2c_slave *sl, uint8_t reg, const uint8_t *buf, uint32_t len); #endif ================================================ FILE: kernel/drivers/ili9341.c ================================================ /* Includes ------------------------------------------------------------------*/ #include #include "malloc.h" #include "framebuffer.h" #include #include #include #include #include "gpio.h" #include "spi.h" /* ILI9341 LCD screen ... */ #define ILI9341_WIDTH ((uint16_t)240) /* LCD PIXEL WIDTH */ #define ILI9341_HEIGHT ((uint16_t)320) /* LCD PIXEL HEIGHT */ #define ILI9341_HSYNC ((uint16_t)10) /* Horizontal synchronization */ #define ILI9341_HBP ((uint16_t)20) /* Horizontal back porch */ #define ILI9341_HFP ((uint16_t)10) /* Horizontal front porch */ #define ILI9341_VSYNC ((uint16_t)2) /* Vertical synchronization */ #define ILI9341_VBP ((uint16_t)2) /* Vertical back porch */ #define ILI9341_VFP ((uint16_t)4) /* Vertical front porch */ //#define ILI9341_FREQUENCY_DIVIDER 5 /* LCD Frequency divider */ //#define REFRESH_RATE 70 /* Hz */ #define FB_WIDTH ILI9341_WIDTH #define FB_HEIGTH ILI9341_HEIGHT //#define FB_BPP (16) /* hardcoded RGB565 - 16 bits per pixel */ #define FB_BPP (16) /* hardcoded CLUT256 - 8 bit per pixel */ #define SET_WRITE_SINGLE_CMD(x) (x & (~(0xC0))) /* Private function prototypes -----------------------------------------------*/ static void ltdc_config(void); static void ltdc_pinmux(void); static void ltdc_clock(void); static int ltdc_config_layer(struct fb_info *fb); struct dev_ili9341 { struct spi_slave sl; /* First argument, for inheritance */ struct device * dev; const struct gpio_config *pio_cs; }; struct ili0341_ctrl_reg { uint8_t reg; uint8_t data; }; static struct dev_ili9341 ILI9341; static struct module mod_ltdc = { .family = FAMILY_FILE, .name = "lcd-controller", }; /* Function to write a register to ILI9341 through SPI */ static void ili9341_write(uint8_t data) { /* set CS low */ gpio_clear(ILI9341.pio_cs->base, ILI9341.pio_cs->pin); //spi_xfer(SPI5, SET_WRITE_SINGLE_CMD(reg)); spi_xfer(SPI5, data); /* set CS high */ gpio_set(ILI9341.pio_cs->base, ILI9341.pio_cs->pin); } /* Private functions ---------------------------------------------------------*/ static void ltdc_destroy(struct fb_info *fb) { // TODO: disable framebuffer if (fb && fb->screen_buffer) f_free((void *)fb->screen_buffer); } static int ltdc_config_layer(struct fb_info *fb) { uint32_t format = 0; /* TODO: move to check / set var */ fb->var.xres = FB_WIDTH; fb->var.yres = FB_HEIGTH; fb->var.bits_per_pixel = FB_BPP; //fb->var.pixel_format = FB_PF_RGB565; fb->var.pixel_format = FB_PF_ARGB8888; fb->var.smem_len = fb->var.xres * fb->var.yres * (fb->var.bits_per_pixel/8); fb->var.type = FB_TYPE_PIXELMAP; /* Allocate framebuffer memory */ fb->screen_buffer = u_malloc(fb->smem_len); if (!fb->screen_buffer) { return -1; } fb->smem_start = fb->screen_buffer; /* Windowing configuration */ ltdc_setup_windowing(LTDC_LAYER_2, fb->var.xres, fb->var.xres); /* Specifies the pixel format */ switch (fb->var.pixel_format) { case FB_PF_RGB565: format = LTDC_LxPFCR_RGB565; break; case FB_PF_ARGB8888: format = LTDC_LxPFCR_ARGB8888; break; case FB_PF_CMAP256: format = LTDC_LxPFCR_L8; break; default: format = LTDC_LxPFCR_RGB565; break; } ltdc_set_pixel_format(LTDC_LAYER_2, format); /* Default color values */ ltdc_set_default_colors(LTDC_LAYER_2, 0, 0, 0, 0); /* Constant alpha */ ltdc_set_constant_alpha(LTDC_LAYER_2, 255); /* Blending factors */ ltdc_set_blending_factors(LTDC_LAYER_2, LTDC_LxBFCR_BF1_CONST_ALPHA, LTDC_LxBFCR_BF2_CONST_ALPHA); /* Framebuffer memory address */ ltdc_set_fbuffer_address(LTDC_LAYER_2, (uint32_t)fb->screen_buffer); /* Configures the color frame buffer pitch in byte */ ltdc_set_fb_line_length(LTDC_LAYER_2, fb->var.xres * (fb->var.bits_per_pixel/8), fb->var.xres * (fb->var.bits_per_pixel/8)); /* Configures the frame buffer line number */ ltdc_set_fb_line_count(LTDC_LAYER_2, fb->var.yres); /* Enable layer 1 */ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE); /* Sets the Reload type */ ltdc_reload(LTDC_SRCR_VBR); ltdc_ctrl_enable(LTDC_GCR_LTDC_ENABLE); return 0; } /** * @brief LCD Configuration. * @note This function Configure tha LTDC peripheral : * 1) Configure the Pixel Clock for the LCD * 2) Configure the LTDC Timing and Polarity * 3) Configure the LTDC Layer 1 : * - The frame buffer is located at FLASH memory * - The Layer size configuration : 480x272 * @retval * None */ static void ltdc_config(void) { /* LTDC Initialization */ ltdc_ctrl_disable(LTDC_GCR_HSPOL_ACTIVE_HIGH); /* Active Low Horizontal Sync */ ltdc_ctrl_disable(LTDC_GCR_VSPOL_ACTIVE_HIGH); /* Active Low Vertical Sync */ ltdc_ctrl_disable(LTDC_GCR_DEPOL_ACTIVE_HIGH); /* Active Low Date Enable */ ltdc_ctrl_disable(LTDC_GCR_PCPOL_ACTIVE_HIGH); /* Active Low Pixel Clock */ /* Configure the LTDC */ ltdc_set_tft_sync_timings(ILI9341_HSYNC, ILI9341_VSYNC, ILI9341_HBP, ILI9341_VBP, ILI9341_WIDTH, ILI9341_HEIGHT, ILI9341_HFP, ILI9341_VFP); ltdc_ctrl_enable(LTDC_GCR_PCPOL_ACTIVE_HIGH); /* Active Low Pixel Clock */ ltdc_set_background_color(0, 0, 0); // LTDC_IER = LTDC_IER_RRIE; // nvic_enable_irq(NVIC_LCD_TFT_IRQ); //ltdc_ctrl_enable(LTDC_GCR_LTDC_ENABLE); } static void ltdc_clock(void) { /* * The datasheet says (Figure 16, page 151): * The LCD-TFT clock comes from PLLSAI. * PLLSRC selects either HSI or HSE. * PLLSAI's input clock is either HSI or HSE divided by PLLM. * PLLSAI's PLLLCDCLK output is the input * PLLSAIN / PLLSAIR. * LCD-TFT clock is PLLLCDCLK divided by PLLSAIDIVR. * * PLLSRC and PLLM are in the RCC_PLLCFGR register. * PLLSAIN and PLLSAIR are in RCC_PLLSAICFGR. * PLLSAIDIVR is in RCC_DCKCFGR; * * In our case, * PLLSRC already selected HSE, which is 8 MHz. * PLLM is already set to 8. 8 MHz / 8 = 1 MHz. * We set PLLSAIN = 192 and PLLSAIR = 4. 1 MHz * 192 / 4 = 48 MHz. * We set PLLSAIDIVR to 8. 48 MHz / 8 = 6 MHz. * So the LCD-TFT pixel clock is 6 MHz. * * The number of clocks per frame is * (VSYNC + VBP + LCD_HEIGHT + VFP) * (HSYNC + HBP + LCD_WIDTH + HFP) = * (2 + 2 + 320 + 4) * (10 + 20 + 240 + 10) = 91840. * * So the refresh frequency is 6 MHz / 91840 ~= 65.6 Hz. */ /* Disable PLLSAI */ RCC_CR &= ~RCC_CR_PLLSAION; while((RCC_CR & (RCC_CR_PLLSAIRDY))) {}; uint32_t sain = 192; uint32_t saiq = (RCC_PLLSAICFGR >> RCC_PLLSAICFGR_PLLSAIQ_SHIFT) & RCC_PLLSAICFGR_PLLSAIQ_MASK; uint32_t sair = 4; RCC_PLLSAICFGR = (sain << RCC_PLLSAICFGR_PLLSAIN_SHIFT | saiq << RCC_PLLSAICFGR_PLLSAIQ_SHIFT | sair << RCC_PLLSAICFGR_PLLSAIR_SHIFT); RCC_DCKCFGR |= RCC_DCKCFGR_PLLSAIDIVR_DIVR_8; RCC_CR |= RCC_CR_PLLSAION; while(!(RCC_CR & (RCC_CR_PLLSAIRDY))) {}; RCC_APB2ENR |= RCC_APB2ENR_LTDCEN; } static int ltdc_blank(struct fb_info *fb) { uint32_t pixels = (fb->var.xres * fb->var.yres * (fb->var.bits_per_pixel/8)); memset((void *)fb->screen_buffer, 0x0, pixels); } static void ltdc_screen_on(void) { /* Assert display enable LCD_DISP pin */ gpio_set(GPIOF, GPIO10); /* Assert backlight LCD_BL_CTRL pin */ //gpio_set(GPIOD, GPIO13); } void ltdc_enable_clut(void) { /* Disable LTDC color lookup table by setting CLUTEN bit */ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_CLUT_ENABLE); /* Sets the Reload type */ ltdc_reload(LTDC_SRCR_IMR); } /* Only L8 CLUTs supported for now */ void ltdc_config_clut(uint32_t *CLUT, uint32_t size) { uint32_t i = 0; for(i = 0; (i < size); i++) { /* Specifies the C-LUT address and RGB value */ LTDC_LxCLUTWR(LTDC_LAYER_2) = ((i << 24) | ((uint32_t)(*CLUT) & 0xFF) | ((uint32_t)(*CLUT) & 0xFF00) | ((uint32_t)(*CLUT) & 0xFF0000)); CLUT++; } } int ltdc_set_cmap(uint32_t *cmap, struct fb_info *info) { //ltdc_config_clut(cmap, 256); //ltdc_enable_clut(); return 0; } static int ltdc_open(struct fb_info *info) { /* init LCD */ } static const struct fb_ops ltdc_fbops = { .fb_open = ltdc_open, .fb_destroy = ltdc_destroy, .fb_blank = ltdc_blank, .fb_setcmap = ltdc_set_cmap}; static struct fb_info ltdc_info = { .fbops = (struct fb_ops *)<dc_fbops, }; static void lcd_pinmux(void) { int i; struct gpio_config g = { .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_PP, .pullupdown = GPIO_PUPD_NONE }; /* Enable the LTDC Clock */ rcc_periph_clock_enable(RCC_LTDC); /* PA3 */ g.base = GPIOA; g.pin = GPIO3; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PA6 */ g.base = GPIOA; g.pin = GPIO6; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PA11 */ g.base = GPIOA; g.pin = GPIO11; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PA12 */ g.base = GPIOA; g.pin = GPIO12; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PB0 */ g.base = GPIOB; g.pin = GPIO0; g.af = GPIO_AF9; gpio_create(&mod_ltdc, &g); /* PB1 */ g.base = GPIOB; g.pin = GPIO1; g.af = GPIO_AF9; gpio_create(&mod_ltdc, &g); /* PC7 */ g.base = GPIOC; g.pin = GPIO7; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PC10 */ g.base = GPIOC; g.pin = GPIO10; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PD3 */ g.base = GPIOD; g.pin = GPIO3; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PD6 */ g.base = GPIOD; g.pin = GPIO6; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PF10 */ g.base = GPIOF; g.pin = GPIO10; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PG6 */ g.base = GPIOG; g.pin = GPIO6; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PG10 */ g.base = GPIOG; g.pin = GPIO10; g.af = GPIO_AF9; gpio_create(&mod_ltdc, &g); /* PG11 */ g.base = GPIOG; g.pin = GPIO11; g.af = GPIO_AF11; gpio_create(&mod_ltdc, &g); /* PG12 */ g.base = GPIOG; g.pin = GPIO12; g.af = GPIO_AF9; gpio_create(&mod_ltdc, &g); /* PB8:PB11*/ for (i = 8; i < 12; i++) { g.base = GPIOB; g.pin = (1 << i); g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); } /* PG7 */ g.base = GPIOG; g.pin = GPIO7; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PC6 */ g.base = GPIOC; g.pin = GPIO6; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PA4 */ g.base = GPIOA; g.pin = GPIO4; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PC2 */ g.base = GPIOC; g.pin = GPIO2; g.mode = GPIO_MODE_OUTPUT; gpio_create(&mod_ltdc, &g); /* PD12 */ g.base = GPIOD; g.pin = GPIO12; gpio_create(&mod_ltdc, &g); /* PD11 */ g.base = GPIOD; g.pin = GPIO11; gpio_create(&mod_ltdc, &g); /* PD13 */ g.base = GPIOD; g.pin = GPIO13; gpio_create(&mod_ltdc, &g); /* PF7 */ g.base = GPIOF; g.pin = GPIO7; gpio_create(&mod_ltdc, &g); /* PF9 */ g.base = GPIOF; g.pin = GPIO9; gpio_create(&mod_ltdc, &g); /* LCD_DISP control PC2 (enable) */ g.base = GPIOC; g.pin = GPIO2; gpio_create(&mod_ltdc, &g); /* LCD_BL control PD13 (output) */ g.base = GPIOD; g.pin = GPIO13; gpio_create(&mod_ltdc, &g); ltdc_screen_on(); } /* * void lcd_command(cmd, delay, args, arg_ptr) * * All singing all dancing 'do a command' feature. Basically it * sends a command, and if args are present it sets 'data' and * sends those along too. */ static void lcd_command(uint8_t cmd, int delay, int n_args, const uint8_t *args) { //uint32_t timeout; int i, now; //gpio_clear(ILI9341.pio_cs->base, ILI9341.pio_cs->pin); //gpio_clear(GPIOC, GPIO2); /* Select the LCD */ //rx_pend++; ili9341_write(cmd); /* We need to wait until it is sent, if we turn on the Data * line too soon, it ends up confusing the display to thinking * its a data transfer, as it samples the D/CX line on the last * bit sent. */ now = jiffies; //while (now + 10 > jiffies) {}; //for (timeout = 0; (timeout < 1000) && (rx_pend); timeout++) { // continue; //} //rx_pend = 0; /* sometimes, at 10Mhz we miss this */ if (n_args) { gpio_set(GPIOD, GPIO13); /* Set the D/CX pin */ for (i = 0; i < n_args; i++) { //rx_pend++; ili9341_write(*(args+i)); } /* This wait so that we don't pull CS too soon after * sending the last byte of data. */ //for (timeout = 0; (timeout < 1000) && (rx_pend); timeout++) { // continue; //} now = jiffies; //while (now + 10 > jiffies) {}; } //gpio_set(ILI9341.pio_cs->base, ILI9341.pio_cs->pin); //gpio_set(GPIOC, GPIO2); /* Turn off chip select */ gpio_clear(GPIOD, GPIO13); /* always reset D/CX */ if (delay) { now = jiffies; //while (now + 50 > jiffies) {}; //msleep(delay); /* wait, if called for */ } } /* Notes on the less obvious ILI9341 commands: */ /* * ILI9341 datasheet, pp 46-49: * * RCM[1:0} = 0b10 command 0xb0 * DPI[2:0] = 0b110 command 0x3a * RIM = 0 command 0xf6 * PCDIV = ???? command 0xB6 * * Pp 239-240: * external fosc = DOTCLK / (2 * (PCDIV + 1)) * * ("Cube" is how the STM32F4Cube demo software sets the register. * "Chuck" is ChuckM's lcd-serial demo, first revision.) * * Command 0x3A: COLMOD: Pixel Format Set LCD_PIXEL_FORMAT * Reset Cube Chuck * DPI[2:0] 110 (18 bit/pix) 110 101 (16 bit/pix) * DBI[2:0] 110 (18 bit/pix) 110 101 (16 bit/pix) * * Command 0xB0: RGB Interface Signal LCD_RGB_INTERFACE * Reset Cube * Bypass: 0 (direct) 1 (memory) * RCM[1:0] 10 10 * VSPL 0 (low) 0 * HSPL 0 (low) 0 * DPL 0 (rising) 1 (falling) * EPL 1 (low) 0 (high) * * Command 0xB6: Display Function Control LCD_DFC * Reset Cube 0A A7 27 04 * PTG[1:0] 10 10 * PT[1:0] 10 10 * REV 1 1 * GS 0 0 * SS 0 (S1->S720) 1 (S720->S1) * SM 0 0 * ISC[3:0] 0010 (5 frames) 0111 (15 frames) * NL[5:0] 100111 100111 * PCDIV[5:0] ? 000100 * S720->S1 moves the origin from the lower left corner to lower right * (viewing the board so the silkscreen is upright) * * Command 0xF6: Interface Control LCD_INTERFACE * Reset Cube 01 00 06 * MY_EOR 0 0 * MX_EOR 0 0 * MV_EOR 0 0 * BGR_EOR 0 0 * WEMODE 1 (wrap) 1 * EPF[1:0] 00 00 * MDT[1:0] 00 00 * ENDIAN 0 (MSB first) 0 * DM[1:0] 00 (int clk) 01 (RGB ifc) * RM 0 (sys ifc) 1 (RGB ifc) * RIM 0 (1 xfr/pix) 0 */ /* ILI9341 command definitions */ /* Regulative[sic] Command Set */ #define ILI_NOP 0x00 #define ILI_RESET 0x01 #define ILI_RD_DID 0x04 #define ILI_RD_STS 0x09 #define ILI_RD_PWR_MODE 0x0a #define ILI_RD_MADCTL 0x0b #define ILI_RD_PXL_FMT 0x0c #define ILI_PD_IMG_FMT 0x0d #define ILI_RD_SIG_MODE 0x0e #define ILI_RD_DIAG_RSLT 0x0f #define ILI_ENTER_SLEEP 0x10 #define ILI_SLEEP_OUT 0x11 #define ILI_PARTIAL_ON 0x12 #define ILI_NORMAL_MODE_ON 0x13 #define ILI_INVERSE_ON 0x20 #define ILI_INVERSE_OFF 0x21 #define ILI_GAMMA_SET 0x26 #define ILI_DISP_OFF 0x28 #define ILI_DISP_ON 0x29 #define ILI_CAS 0x2a #define ILI_PAS 0x2b #define ILI_MEM_WRITE 0x2c #define ILI_COLOR_SET 0x2d #define ILI_MEM_READ 0x2e #define ILI_PARTIAL_AREA 0x30 #define ILI_VERT_SCROLL_DEF 0x33 #define ILI_TEAR_EFF_OFF 0x34 #define ILI_TEAR_EFF_ON 0x35 #define ILI_MEM_ACC_CTL 0x36 #define ILI_V_SCROLL_START 0x37 #define ILI_IDLE_OFF 0x38 #define ILI_IDLE_ON 0x39 #define ILI_PIX_FMT_SET 0x3a #define ILI_WR_MEM_CONT 0x3c #define ILI_RD_MEM_CONT 0x3e #define ILI_SET_TEAR_LINE 0x44 #define ILI_GET_SCANLINE 0x45 #define ILI_WR_BRIGHTNESS 0x51 #define ILI_RD_BRIGHTNESS 0x52 #define ILI_WR_CTRL 0x53 #define ILI_RD_CTRL 0x54 #define ILI_WR_CABC 0x55 #define ILI_RD_CABC 0x56 #define ILI_WR_CABC_MIN 0x5e #define ILI_RD_CABC_MAX 0x5f #define ILI_RD_ID1 0xda #define ILI_RD_ID2 0xdb #define ILI_RD_ID3 0xdc /* Extended Command Set */ #define ILI_RGB_IFC_CTL 0xb0 #define ILI_FRM_CTL_NORM 0xb1 #define ILI_FRM_CTL_IDLE 0xb2 #define ILI_FRM_CTL_PART 0xb3 #define ILI_INVERSE_CTL 0xb4 #define ILI_PORCH_CTL 0xb5 #define ILI_FUNC_CTL 0xb6 #define ILI_ENTRY_MODE_SET 0xb7 #define ILI_BL_CTL_1 0xb8 #define ILI_BL_CTL_2 0xb9 #define ILI_BL_CTL_3 0xba #define ILI_BL_CTL_4 0xbb #define ILI_BL_CTL_5 0xbc #define ILI_BL_CTL_7 0xbe #define ILI_BL_CTL_8 0xbf #define ILI_PWR_CTL_1 0xc0 #define ILI_PWR_CTL_2 0xc1 #define ILI_VCOM_CTL_1 0xc5 #define ILI_VCOM_CTL_2 0xc7 #define ILI_NV_MEM_WR 0xd0 #define ILI_NV_MEM_PROT_KEY 0xd1 #define ILI_NV_MEM_STATUS_RD 0xd2 #define ILI_RD_ID4 0xd3 #define ILI_POS_GAMMA 0xe0 #define ILI_NEG_GAMMA 0xe1 #define ILI_GAMMA_CTL_1 0xe2 #define ILI_GAMMA_CTL_2 0xe3 #define ILI_IFC_CTL 0xf6 /* * This structure defines the sequence of commands to send * to the Display in order to initialize it. The AdaFruit * folks do something similar, it helps when debugging the * initialization sequence for the display. */ #define MAX_INLINE_ARGS (sizeof(uint8_t *)) struct tft_command { uint16_t delay; /* If you need a delay after */ uint8_t cmd; /* command to send */ uint8_t n_args; /* How many arguments it has */ union { uint8_t args[MAX_INLINE_ARGS]; /* The first four arguments */ const uint8_t *aptr; /* More than four arguemnts */ }; }; static const uint8_t pos_gamma_args[] = { 0x0F, 0x29, 0x24, 0x0C, 0x0E, 0x09, 0x4E, 0x78, 0x3C, 0x09, 0x13, 0x05, 0x17, 0x11, 0x00 }; static const uint8_t neg_gamma_args[] = { 0x00, 0x16, 0x1B, 0x04, 0x11, 0x07, 0x31, 0x33, 0x42, 0x05, 0x0C, 0x0A, 0x28, 0x2F, 0x0F }; /* * These are the commands we're going to send to the * display to initialize it. We send them all, in sequence * with occasional delays. Commands that require data bytes * as arguments, indicate how many bytes to pull out the * above array to include. * * The sequence was pieced together from the ST Micro demo * code, the data sheet, and other sources on the web. */ const struct tft_command initialization[] = { { 0, ILI_PWR_CTL_1, 1, .args = { 0x10 } }, { 0, ILI_PWR_CTL_2, 1, .args = { 0x10 } }, { 0, ILI_VCOM_CTL_1, 2, .args = { 0x45, 0x15 } }, { 0, ILI_VCOM_CTL_2, 1, .args = { 0x90 } }, { 0, ILI_MEM_ACC_CTL, 1, .args = { 0x08 } }, { 0, ILI_RGB_IFC_CTL, 1, .args = { 0xc0 } }, { 0, ILI_IFC_CTL, 3, .args = { 0x01, 0x00, 0x06 } }, { 0, ILI_GAMMA_SET, 1, .args = { 0x01 } }, { 0, ILI_POS_GAMMA, 15, .aptr = pos_gamma_args }, { 0, ILI_NEG_GAMMA, 15, .aptr = neg_gamma_args }, { +5, ILI_SLEEP_OUT, 0, .args = {} }, { 0, ILI_DISP_ON, 0, .args = {} }, }; static void initialize_display(const struct tft_command cmds[], size_t cmd_count) { size_t i; for (i = 0; i < cmd_count; i++) { uint8_t arg_count = cmds[i].n_args; const uint8_t *args = cmds[i].args; if (arg_count > MAX_INLINE_ARGS) { args = cmds[i].aptr; } lcd_command(cmds[i].cmd, cmds[i].delay, arg_count, args); } } struct gpio_config ili9341_pio = { .base=GPIOC, .pin=GPIO2, .mode=GPIO_MODE_OUTPUT, .pullupdown=GPIO_PUPD_PULLUP }; static void ili9341_init(void) { memset(&ILI9341, 0, sizeof(struct dev_ili9341)); /* Populate spi_slave struct */ ILI9341.sl.bus = 5; //ILI9341.sl.isr = ili9341_isr; ILI9341.pio_cs = &ili9341_pio; gpio_create(&mod_ltdc, &ili9341_pio); gpio_set(ILI9341.pio_cs->base, ILI9341.pio_cs->pin); /* Set up the display */ initialize_display(initialization, sizeof(initialization) / sizeof(initialization[0])); } /* DRIVER INIT */ void ltdc_init(void) { lcd_pinmux(); ltdc_clock(); ltdc_config(); /* Configure LCD : Only one layer is used */ ltdc_config_layer(<dc_info); ili9341_init(); register_framebuffer(<dc_info); register_module(&mod_ltdc); } ================================================ FILE: kernel/drivers/l3gd20.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include #include "ioctl.h" #include "l3gd20.h" #include "gpio.h" #include "exti.h" #include #include "stm32f4_dma.h" #include "stm32f4_spi.h" typedef enum { L3GD20_IDLE, L3GD20_READ, L3GD20_WRITE, L3GD20_PENDING, L3GD20_READING }L3GD20_MODE; struct dev_l3gd20 { struct device * dev; struct fnode *spi_fnode; struct fnode *cs_fnode; struct fnode *int_1_fnode; struct fnode *int_2_fnode; L3GD20_MODE mode; }; struct l3gd20_ctrl_reg { uint8_t reg; uint8_t data; }; #define MAX_L3GD20S 1 static struct dev_l3gd20 dev_l3gd20 = { }; static int devl3gd20_read(struct fnode *fno, void *buf, unsigned int len); static int devl3gd20_ioctl(struct fnode * fno, const uint32_t cmd, void *arg); static int devl3gd20_close(struct fnode *fno); static struct module mod_devl3gd20 = { .family = FAMILY_FILE, .name = "l3gd20", .ops.open = device_open, .ops.read = devl3gd20_read, .ops.ioctl = devl3gd20_ioctl, .ops.close = devl3gd20_close, }; static void completion(void * arg) { dev_l3gd20.cs_fnode->owner->ops.write(dev_l3gd20.cs_fnode, "1", 1); if (dev_l3gd20.dev->task != NULL) task_resume(dev_l3gd20.dev->task); } static void int1_callback(void *arg) { (void)arg; } static void int2_callback(void *arg) { (void)arg; dev_l3gd20.cs_fnode->owner->ops.write(dev_l3gd20.cs_fnode, "1", 1); if (dev_l3gd20.dev->task != NULL) task_resume(dev_l3gd20.dev->task); } static int devl3gd20_ioctl(struct fnode * fno, const uint32_t cmd, void *arg) { struct dev_l3gd20 *l3gd20 = FNO_MOD_PRIV(fno, &mod_devl3gd20); struct l3gd20_ctrl_reg * ctrl = (struct l3gd20_ctrl_reg *) arg; static uint8_t ioctl_ibuffer[2]; static uint8_t ioctl_obuffer[2]; if (!l3gd20) return -1; if(l3gd20->mode == L3GD20_IDLE) { ioctl_obuffer[0] = ctrl->reg; if(cmd == IOCTL_L3GD20_READ_CTRL_REG) { ioctl_obuffer[0] |= 0x80; ioctl_obuffer[1] = 0; l3gd20->mode = L3GD20_READ; } else { ioctl_obuffer[1] = ctrl->data; l3gd20->mode = L3GD20_WRITE; } l3gd20->dev->task = this_task(); task_suspend(); l3gd20->cs_fnode->owner->ops.write(l3gd20->cs_fnode, "0", 1); devspi_xfer(l3gd20->spi_fnode, completion, l3gd20, ioctl_obuffer, ioctl_ibuffer, 2); return SYS_CALL_AGAIN; } if(l3gd20->mode == L3GD20_READ) { ctrl->data = ioctl_ibuffer[1]; } l3gd20->mode = L3GD20_IDLE; return 0; } static int devl3gd20_read(struct fnode *fno, void *buf, unsigned int len) { const struct dev_spi *spi; struct dev_l3gd20 *l3gd20 = FNO_MOD_PRIV(fno, &mod_devl3gd20); static uint8_t rd_ibuffer[7]; static uint8_t rd_obuffer[7]; if (len <= 0) return len; if (!l3gd20) return -1; /* First read is a fake just to get the DRDY IRQ going - what a bloody awful gyro*/ if(l3gd20->mode == L3GD20_IDLE) { exti_enable(1, 1); l3gd20->mode = L3GD20_PENDING; rd_obuffer[0] = 0xE8; l3gd20->dev->task = this_task(); task_suspend(); l3gd20->cs_fnode->owner->ops.write(l3gd20->cs_fnode, "0", 1); devspi_xfer(l3gd20->spi_fnode, completion, l3gd20, rd_obuffer, rd_ibuffer, 7); return SYS_CALL_AGAIN; } else if(l3gd20->mode == L3GD20_PENDING) { l3gd20->mode = L3GD20_READING; rd_obuffer[0] = 0xE8; l3gd20->dev->task = this_task(); task_suspend(); l3gd20->cs_fnode->owner->ops.write(l3gd20->cs_fnode, "0", 1); devspi_xfer(l3gd20->spi_fnode, completion, l3gd20, rd_obuffer, rd_ibuffer, 7); return SYS_CALL_AGAIN; } else if(l3gd20->mode == L3GD20_READING) { if(len > 6) len = 6; exti_enable(1, 0); memcpy(buf, &rd_ibuffer[1], len); l3gd20->mode = L3GD20_PENDING; } return len; } static int devl3gd20_close(struct fnode *fno) { struct dev_l3gd20 *l3gd20; l3gd20 = FNO_MOD_PRIV(fno, &mod_devl3gd20); if (!l3gd20) return -1; l3gd20->mode = L3GD20_IDLE; exti_enable(1, 0); return 0; } static void l3gd20_fno_init(struct fnode *dev, uint32_t n, const struct l3gd20_addr * addr) { struct dev_l3gd20 *l = &dev_l3gd20; l->dev = device_fno_init(&mod_devl3gd20, "/dev/gyro", dev, FL_RDWR, l); l->spi_fnode = fno_search(addr->spi_name); l->cs_fnode = fno_search(addr->spi_cs_name); l->cs_fnode->owner->ops.write(l->cs_fnode, "1", 1); l->mode = L3GD20_IDLE; } void l3gd20_init(struct fnode * dev, const struct l3gd20_addr l3gd20_addr) { int i = 0; l3gd20_fno_init(dev, i, &l3gd20_addr); exti_register(l3gd20_addr.pio1_base, l3gd20_addr.pio1_pin, EXTI_TRIGGER_RISING, int1_callback, NULL); exti_register(l3gd20_addr.pio2_base, l3gd20_addr.pio2_pin, EXTI_TRIGGER_RISING, int2_callback, NULL); register_module(&mod_devl3gd20); } ================================================ FILE: kernel/drivers/l3gd20.h ================================================ #ifndef INC_L3GD20 #define INC_L3GD20 struct l3gd20_addr { const char * name; const char * spi_name; const char * spi_cs_name; uint32_t pio1_base; uint32_t pio1_pin; uint32_t pio2_base; uint32_t pio2_pin; }; void l3gd20_init(struct fnode *dev, const struct l3gd20_addr l3gd20_addr); #endif ================================================ FILE: kernel/drivers/lis3dsh.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include #include "ioctl.h" #include "gpio.h" #include "exti.h" #include "dma.h" #include "spi.h" #include /* LIS3DSH registers addresses */ #define ADD_REG_WHO_AM_I 0x0F #define ADD_REG_CTRL_4 0x20 #define ADD_REG_OUT_X_L 0x28 #define ADD_REG_OUT_X_H 0x29 #define ADD_REG_OUT_Y_L 0x2A #define ADD_REG_OUT_Y_H 0x2B #define ADD_REG_OUT_Z_L 0x2C #define ADD_REG_OUT_Z_H 0x2D /* WHO AM I register default value */ #define UC_WHO_AM_I_DEFAULT_VALUE 0x3F /* ADD_REG_CTRL_4 register configuration value: * X,Y,Z axis enabled and 400Hz of output data rate */ #define UC_ADD_REG_CTRL_4_CFG_OFF 0x00 #define UC_ADD_REG_CTRL_4_CFG_3_125HZ ((0x10) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_6_25HZ ((0x20) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_12_5HZ ((0x30) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_25HZ ((0x40) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_50HZ ((0x50) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_3_100HZ ((0x60) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_3_400HZ ((0x70) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_3_800HZ ((0x80) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_3_1600HZ ((0x90) | (0x07)) #define UC_ADD_REG_CTRL_4_CFG_VALUE_DEFAULT UC_ADD_REG_CTRL_4_CFG_25HZ /* Sensitivity for 2G range [mg/digit] */ #define SENS_2G_RANGE_MG_PER_DIGIT ((float)0.06) /* LED threshold value in mg */ #define LED_TH_MG (1000) /* 1000mg (1G) */ /* set read single command. Attention: command must be 0x3F at most */ #define SET_READ_SINGLE_CMD(x) (x | 0x80) /* set read multiple command. Attention: command must be 0x3F at most */ #define SET_READ_MULTI_CMD(x) (x | 0xC0) /* set write single command. Attention: command must be 0x3F at most */ #define SET_WRITE_SINGLE_CMD(x) (x & (~(0xC0))) /* set write multiple command. Attention: command must be 0x3F at most */ #define SET_WRITE_MULTI_CMD(x) (x & (~(0x80)) \ x |= 0x40) struct dev_lis3dsh { struct spi_slave sl; /* First argument, for inheritance */ struct device * dev; const struct gpio_config *pio_cs; }; struct lis3dsh_ctrl_reg { uint8_t reg; uint8_t data; }; static struct dev_lis3dsh LIS3DSH; static int devlis3dsh_open(const char *path, int flags); static int devlis3dsh_read(struct fnode *fno, void *buf, unsigned int len); static int devlis3dsh_close(struct fnode *fno); static struct module mod_devlis3dsh = { .family = FAMILY_FILE, .name = "lis3dsh", .ops.open = devlis3dsh_open, .ops.read = devlis3dsh_read, .ops.close = devlis3dsh_close, }; /* Function to write a register to LIS3DSH through SPI */ static void lis3dsh_write_reg(int reg, int data) { /* set CS low */ gpio_clear(LIS3DSH.pio_cs->base, LIS3DSH.pio_cs->pin); spi_xfer(SPI1, SET_WRITE_SINGLE_CMD(reg)); spi_xfer(SPI1, data); /* set CS high */ gpio_set(LIS3DSH.pio_cs->base, LIS3DSH.pio_cs->pin); } /* Function to read a register from LIS3DSH through SPI */ static int lis3dsh_read_reg(int reg) { int reg_value; /* set CS low */ gpio_clear(LIS3DSH.pio_cs->base, LIS3DSH.pio_cs->pin); reg_value = spi_xfer(SPI1, SET_READ_SINGLE_CMD(reg)); reg_value = spi_xfer(SPI1, 0xFF); /* set CS high */ gpio_set(LIS3DSH.pio_cs->base, LIS3DSH.pio_cs->pin); return reg_value; } static int devlis3dsh_open(const char *path, int flags) { struct fnode *f = fno_search(path); volatile int int_reg_value; if (!f) return -1; /* get WHO AM I value */ int_reg_value = lis3dsh_read_reg(ADD_REG_WHO_AM_I); /* if WHO AM I value is the expected one */ if (int_reg_value == UC_WHO_AM_I_DEFAULT_VALUE) { /* set output data rate to 400 Hz and enable X,Y,Z axis */ lis3dsh_write_reg(ADD_REG_CTRL_4, UC_ADD_REG_CTRL_4_CFG_VALUE_DEFAULT); /* verify written value */ int_reg_value = lis3dsh_read_reg(ADD_REG_CTRL_4); /* if written value is different */ if (int_reg_value != UC_ADD_REG_CTRL_4_CFG_VALUE_DEFAULT) { return -EIO; } } else { return -EIO; } return task_filedesc_add(f); } static int devlis3dsh_read(struct fnode *fno, void *buf, unsigned int len) { struct dev_lis3dsh *lis3dsh = FNO_MOD_PRIV(fno, &mod_devlis3dsh); uint8_t reg_base = ADD_REG_OUT_X_L; uint8_t i; volatile int int_reg_value; if (len < 6) return len; if (!lis3dsh) return -1; for (i = 0; i < 6; i++) { ((uint8_t*)buf)[i] = lis3dsh_read_reg(reg_base + i); } return 6; } static int devlis3dsh_close(struct fnode *fno) { struct dev_lis3dsh *lis3dsh; lis3dsh = FNO_MOD_PRIV(fno, &mod_devlis3dsh); if (!lis3dsh) return -1; return 0; } static void lis3dsh_isr(struct spi_slave *sl) { struct dev_lis3dsh *lis = (struct dev_lis3dsh *)sl; task_resume(lis->dev->task); } int lis3dsh_init(uint8_t bus, const struct gpio_config *lis3dsh_cs) { struct fnode *devfs; memset(&LIS3DSH, 0, sizeof(struct dev_lis3dsh)); devfs = fno_search("/dev"); if (!devfs) return -EFAULT; LIS3DSH.dev = device_fno_init(&mod_devlis3dsh, "ins", devfs, FL_RDONLY, &LIS3DSH); if (!LIS3DSH.dev) return -EFAULT; /* Populate spi_slave struct */ LIS3DSH.sl.bus = bus; LIS3DSH.sl.isr = lis3dsh_isr; LIS3DSH.pio_cs = lis3dsh_cs; register_module(&mod_devlis3dsh); gpio_create(&mod_devlis3dsh, lis3dsh_cs); gpio_set(LIS3DSH.pio_cs->base, LIS3DSH.pio_cs->pin); return 0; } ================================================ FILE: kernel/drivers/lis3dsh.h ================================================ #ifndef LIS3DSH_INC #define LIS3DSH_INC # ifdef CONFIG_DEVLIS3DSH int lis3dsh_init(uint8_t bus, const struct gpio_config *lis3dsh_cs); # else # define lis3dsh_init(...) (0) # endif #endif ================================================ FILE: kernel/drivers/lm3s_eth.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Maxime Vincent * */ #include #include "frosted.h" #include "gpio.h" #include "eth.h" #include #include #include #include #include "unicore-mx/cm3/nvic.h" #define dbg(...) #define ETH_MAX_FRAME (1524) /* Round to multiple of 4 bytes! */ #define ETH_IRQ_PRIO (1) #define ETH_IRQMASK_RX (1) /* Interrupt Mask for RXINT (bit 0) */ /* FIXME: Put in board config */ #define BOARD_PHY_RMII /* Whether the board uses RMII or MII */ #define BOARD_phy_addr PHY_LAN8710A_ID /* The PHY ID to be detected on one of the PHY addresses */ /* Some known PHY-identifiers */ #define PHY_KSZ8021_ID 0x00221556 #define PHY_KS8721_ID 0x00221610 #define PHY_DP83848I_ID 0x20005C90 #define PHY_LAN8710A_ID 0x0007C0F1 #define PHY_DM9161_ID 0x0181B8A0 #define PHY_AM79C875_ID 0x00225540 #define PHY_STE101P_ID 0x00061C50 struct dev_eth { struct pico_device dev; uint32_t rx_prod; uint32_t rx_cons; uint8_t mac_addr[6]; uint8_t phy_addr; }; static struct module mod_eth = { .family = FAMILY_DEV, .name = "ethernet", }; static struct dev_eth * dev_eth = NULL; static const uint8_t default_mac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; static uint8_t temp_rx_buf[ETH_MAX_FRAME]; static int eth_poll(struct pico_device *dev, int loop_score) { uint32_t rx_len = 0; while (eth_rx(temp_rx_buf, &rx_len, ETH_MAX_FRAME) && (loop_score > 0)) { pico_stack_recv(dev, temp_rx_buf, rx_len); rx_len = 0; loop_score--; } return loop_score; } static int eth_send(struct pico_device *dev, void * buf, int len) { if (eth_tx(buf, len)) return len; else return 0; } int pico_eth_start(void) { const char ipstr[] = CONFIG_ETH_DEFAULT_IP; const char nmstr[] = CONFIG_ETH_DEFAULT_NM; const char gwstr[] = CONFIG_ETH_DEFAULT_GW; struct pico_ip4 default_ip, default_nm, default_gw, zero; zero.addr = 0U; pico_string_to_ipv4(ipstr, &default_ip.addr); pico_string_to_ipv4(nmstr, &default_nm.addr); pico_string_to_ipv4(gwstr, &default_gw.addr); dev_eth = kalloc(sizeof(struct dev_eth)); if (!dev_eth) return -1; memset(dev_eth, 0, sizeof(struct dev_eth)); /* set pico function pointers */ dev_eth->dev.poll = eth_poll; dev_eth->dev.send = eth_send; if (pico_device_init(&dev_eth->dev,"eth0", default_mac) < 0) { kfree(dev_eth); return -1; } /* Set address/netmask */ pico_ipv4_link_add(&dev_eth->dev, default_ip, default_nm); /* Set default gateway */ if (default_gw.addr) pico_ipv4_route_add(zero, zero, default_gw, 1, NULL); /* Enabling required interrupt sources.*/ eth_start(); return 0; } void eth_isr(void) { eth_irq_ack_pending(ETH_IRQMASK_RX); frosted_tcpip_wakeup(); } /* HW initialization */ int ethernet_init(const struct eth_config *conf) { (void)conf; eth_init(0, ETH_CLK_50MHZ); /* does a phy_reset */ nvic_enable_irq(NVIC_ETH_IRQ); eth_irq_enable(ETH_IRQMASK_RX); eth_set_mac((uint8_t*)default_mac); return 0; } ================================================ FILE: kernel/drivers/lsm303dlhc.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include #include "ioctl.h" #include "lsm303dlhc.h" #include "gpio.h" #include "exti.h" #include "dma.h" #include "i2c.h" #define LSM303_I2C_INS_ADDR 0x30 #define LSM303_I2C_COMPASS_ADDR 0x3C enum lsm303_state { LSM303_STATE_DISABLED = 0, LSM303_STATE_IDLE, LSM303_STATE_BUSY, LSM303_STATE_RX_RDY }; struct dev_lsm303dlhc { struct i2c_slave i2c; /* As first argument, so isr callbacks will use this as arg */ struct device * dev; enum lsm303_state state; union dev_lsm303dlhc_data { uint8_t data[6]; struct __attribute__((packed)) ins_data_xyz { int16_t x; int16_t y; int16_t z; } xyz; } ins_data; } INS; static int devlsm303dlhc_read(struct fnode *fno, void *buf, unsigned int len); static int devlsm303dlhc_close(struct fnode *fno); static struct module mod_devlsm303dlhc = { .family = FAMILY_FILE, .name = "lsm303dlhc", .ops.open = device_open, .ops.read = devlsm303dlhc_read, .ops.close = devlsm303dlhc_close, }; /* I2C operation callbacks, executed in IRQ context, and with I2C mutex held. */ static void isr_tx(struct i2c_slave * arg) { struct dev_lsm303dlhc *lsm303dlhc = (struct dev_lsm303dlhc *) arg; switch (lsm303dlhc->state) { case LSM303_STATE_DISABLED: lsm303dlhc->state = LSM303_STATE_IDLE; task_resume(lsm303dlhc->dev->task); break; case LSM303_STATE_IDLE: lsm303dlhc->state = LSM303_STATE_DISABLED; break; } } static void isr_rx(struct i2c_slave * arg) { struct dev_lsm303dlhc *lsm303dlhc = (struct dev_lsm303dlhc *) arg; lsm303dlhc->state = LSM303_STATE_RX_RDY; if (lsm303dlhc->dev->task != NULL) task_resume(lsm303dlhc->dev->task); } static void int1_callback(void *arg) { (void*)arg; } static void int2_callback(void *arg) { (void*)arg; } static void drdy_callback(void *arg) { (void*)arg; } #define CTRL_REG1_A (0x20) #define OUT_X_L_A (0x28) static int devlsm303dlhc_read(struct fnode *fno, void *buf, unsigned int len) { struct dev_lsm303dlhc *lsm303dlhc = FNO_MOD_PRIV(fno, &mod_devlsm303dlhc); uint8_t val; if (!lsm303dlhc) return -EINVAL; if (len == 0) return -EINVAL; switch (lsm303dlhc->state) { case LSM303_STATE_DISABLED: lsm303dlhc->dev->task = this_task(); val = 0x27; /* PM=001, DR=00, XYZ=111 */ i2c_init_write(&lsm303dlhc->i2c, CTRL_REG1_A, &val, 1); task_suspend(); return SYS_CALL_AGAIN; case LSM303_STATE_IDLE: lsm303dlhc->dev->task = this_task(); i2c_init_write(&lsm303dlhc->i2c, OUT_X_L_A, lsm303dlhc->ins_data.data, 6); task_suspend(); return SYS_CALL_AGAIN; case LSM303_STATE_RX_RDY: if (len > 6) len = 6; memcpy(buf, lsm303dlhc->ins_data.data, len); lsm303dlhc->state = LSM303_STATE_IDLE; val = 0x07; /* PM=000, DR=00, XYZ=111 */ i2c_init_write(&lsm303dlhc->i2c, CTRL_REG1_A, &val, 1); return len; } } static int devlsm303dlhc_close(struct fnode *fno) { struct dev_lsm303dlhc *lsm303dlhc = FNO_MOD_PRIV(fno, &mod_devlsm303dlhc); uint8_t val = 0x07; /* PM=000, DR=00, XYZ=111 */ lsm303dlhc->state = LSM303_STATE_IDLE; i2c_init_write(&lsm303dlhc->i2c, CTRL_REG1_A, &val, 1); return 0; } int lsm303dlhc_init(int bus) { struct fnode *devfs; memset(&INS, 0, sizeof(struct dev_lsm303dlhc)); devfs = fno_search("/dev"); if (!devfs) return -EFAULT; INS.dev = device_fno_init(&mod_devlsm303dlhc, "ins", devfs, FL_RDONLY, &INS); if (!INS.dev) return -EFAULT; /* Populate i2c_slave struct */ INS.i2c.bus = bus; INS.i2c.address = LSM303_I2C_INS_ADDR; INS.i2c.isr_tx = isr_tx; INS.i2c.isr_rx = isr_rx; register_module(&mod_devlsm303dlhc); return 0; } ================================================ FILE: kernel/drivers/lsm303dlhc.h ================================================ #ifndef INC_LSM303DLHC #define INC_LSM303DLHC struct lsm303dlhc_addr { const char * name; const char * i2c_name; uint32_t pio1_base; uint32_t pio2_base; uint32_t drdy_base; uint32_t pio1_pin; uint32_t pio2_pin; uint32_t drdy_pin; uint8_t address; uint8_t drdy_address; }; int lsm303dlhc_init(int bus); #endif ================================================ FILE: kernel/drivers/ltdc.h ================================================ #ifndef INC_LTDC #define INC_LTDC #ifdef CONFIG_LTDC int ltdc_init(void); #else # define ltdc_init() ((-ENOENT)) #endif #endif ================================================ FILE: kernel/drivers/mccog21.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include #include "cirbuf.h" #include "dma.h" #include "cirbuf.h" #include "i2c.h" #define MCCOG21_I2C_ADDR (0x7c) #define MCC0G21_CLEAR_DISPLAY (0x01) #define MCC0G21_RETURN_HOME (0x01) #define MCC0G21_ENTRY_MODE (0x04) # define MCC0G21_ENTRY_MODE_INCREMENT (0x02) # define MCC0G21_ENTRY_MODE_DECREMENT (0x00) # define MCC0G21_ENTRY_SHIFT_ON (0x01) # define MCC0G21_ENTRY_SHIFT_OFF (0x00) #define MCC0G21_ONOFF (0x08) # define MCC0G21_DISPLAY_ON (1 << 2) # define MCC0G21_CURSOR_ON (1 << 1) # define MCC0G21_CURSOR_BLINK (1 << 0) #define MCC0G21_SHIFT (0x10) #define MCC0G21_OSC_FREQ (0x10) # define MCC0G21_OSC_FREQ_192HZ (0x04) #define MCC0G21_FSET (0x20) # define MCC0G21_FSET_8BIT (1 << 4) # define MCC0G21_FSET_TWOLINES (1 << 3) # define MCC0G21_FSET_DOUBLEH (1 << 2) # define MCC0G21_FSET_EXTEND (1 << 0) #define MCC0G21_CGRAM_SELECT (0x40) #define MCC0G21_DDRAM_SELECT (0x80) #define MCC0G21_CONTRAST_HI (0x50) #define MCC0G21_FOLLOWER (0x60) # define MCC0G21_FOLLOWER_5V (0x0C) #define MCC0G21_CONTRAST_LO (0x70) #define MCC0G21_COMMAND_PREFIX (0x00) #define MCC0G21_DATA_PREFIX (0x40) struct dev_disp { struct i2c_slave i2c; struct device *dev; char buf[80]; uint8_t functions; volatile int update; } Disp; static void mccog21_clear(void) { uint8_t cmd = MCC0G21_CLEAR_DISPLAY; int r; kthread_sleep_ms(400); do { r = i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); } while (r != 1); kthread_sleep_ms(800); } /* Module description */ int mccog21_read(struct fnode *fno, void *buf, unsigned int len) { if (len > 80) len = 80; if (len > 0) memcpy(buf, Disp.buf, len); return len; } int mccog21_write(struct fnode *fno, const void *buf, unsigned int len) { memset(Disp.buf, 0, 80); if (len > 80) len = 80; if (len > 0) memcpy(Disp.buf, buf, len); Disp.update = 1; return len; } static struct module mod_devdisp = { .family = FAMILY_FILE, .name = "lcd", .ops.open = device_open, .ops.read = mccog21_read, .ops.write= mccog21_write }; static uint8_t cmd; static void mccog21_task(void *arg) { (void)arg; int i; int r; kthread_sleep_ms(80); /* Wait 40ms until VDD stabilizes */ /* Mode = 8 bit, two lines */ Disp.functions = MCC0G21_FSET_8BIT | MCC0G21_FSET_TWOLINES; cmd = MCC0G21_FSET | Disp.functions; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); /* Mode = 8 bit, two lines */ Disp.functions = MCC0G21_FSET_8BIT | MCC0G21_FSET_TWOLINES; cmd = MCC0G21_FSET | Disp.functions; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); /* Switch to extended mode */ cmd = MCC0G21_FSET | Disp.functions | MCC0G21_FSET_EXTEND; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); /* Oscillator */ cmd = MCC0G21_OSC_FREQ | MCC0G21_OSC_FREQ_192HZ; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); kthread_sleep_ms(200); /* Follower circuit off */ cmd = MCC0G21_FOLLOWER | MCC0G21_FOLLOWER_5V; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); kthread_sleep_ms(200); /* Switch to normal mode */ cmd = MCC0G21_FSET | Disp.functions; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); /* Power on */ cmd = MCC0G21_ONOFF | MCC0G21_DISPLAY_ON; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); mccog21_clear(); cmd = MCC0G21_RETURN_HOME;; do { r = i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); } while (r != 1); kthread_sleep_ms(800); cmd = MCC0G21_ENTRY_MODE | MCC0G21_ENTRY_MODE_INCREMENT; do { r = i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); } while (r != 1); /* Switch to extended mode */ cmd = MCC0G21_FSET | Disp.functions | MCC0G21_FSET_EXTEND; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); /* Set contrast */ cmd = MCC0G21_CONTRAST_HI | 0x02; do { r = i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); } while (r < 1); /* Switch to normal mode */ cmd = MCC0G21_FSET | Disp.functions; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); while(1<2) { if (Disp.update) { cmd = MCC0G21_RETURN_HOME;; r = i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); kthread_sleep_ms(80); cmd = MCC0G21_DDRAM_SELECT; i2c_kthread_write(&Disp.i2c, MCC0G21_COMMAND_PREFIX, &cmd, 1); for (i = 0; i < 80; i++) { if (Disp.buf[i] == 0) break; i2c_kthread_write(&Disp.i2c, MCC0G21_DATA_PREFIX, &Disp.buf[i], 1); } Disp.update = 0; } kthread_yield(); } } int mccog21_init(uint32_t bus) { int i; struct fnode *devdir = fno_search("/dev"); if (!devdir) return -ENOENT; memset(&Disp, 0, sizeof(struct dev_disp)); Disp.dev = device_fno_init(&mod_devdisp, "lcd", devdir, 0, &Disp); /* Populate i2c_slave struct */ Disp.i2c.bus = bus; Disp.i2c.address = MCCOG21_I2C_ADDR; strcpy(Disp.buf, "Frosted"); Disp.update = 1; kthread_create(mccog21_task, NULL); return 0; } ================================================ FILE: kernel/drivers/null.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "string.h" static struct fnode *devnull; static struct fnode *devzero; static int devnull_read(struct fnode *fno, void *buf, unsigned int len) { if (fno == devnull) return -EPERM; if (len <= 0) return len; memset(buf, 0, sizeof(len)); return (int)len; } static int devnull_write(struct fnode *fno, const void *buf, unsigned int len) { if (fno == devzero) return -EPERM; if (len <= 0) return len; return len; } static int devnull_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { return 1; } static int devnull_open(const char *path, int flags) { struct fnode *f = fno_search(path); return task_filedesc_add(f); } static struct module mod_devnull = { }; void devnull_init(struct fnode *dev) { strcpy(mod_devnull.name,"devnull"); mod_devnull.family = FAMILY_FILE; mod_devnull.ops.open = devnull_open; mod_devnull.ops.read = devnull_read; mod_devnull.ops.poll = devnull_poll; mod_devnull.ops.write = devnull_write; devnull = fno_create_wronly(&mod_devnull, "null", dev); devnull->flags |= FL_TTY; devzero = fno_create_rdonly(&mod_devnull, "zero", dev); devzero->flags |= FL_TTY; register_module(&mod_devnull); } ================================================ FILE: kernel/drivers/pty.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include "poll.h" #include "cirbuf.h" #include #define PTS_BUFSIZE (256) static struct devptmx { struct device *dev; uint16_t pty_idx; struct fnode PTMX_ROOT; } PTMX; struct devpty { struct fnode *fno; struct devpts *slave; struct task *task; uint16_t idx; uint16_t creator_pid; int sid; }; struct devpts { struct device *dev; struct task *task; struct devpty *master; struct cirbuf *miso, *mosi; int sid; }; int ptmx_open(const char *path, int flags); int pty_open(const char *path, int flags); static int pty_read(struct fnode *fno, void *buf, unsigned int len); static int pty_poll(struct fnode *fno, uint16_t events, uint16_t *revents); static int pty_write(struct fnode *fno, const void *buf, unsigned int len); static void pty_tty_attach(struct fnode *fno, int pid); static int pty_close(struct fnode *fno); static int pts_read(struct fnode *fno, void *buf, unsigned int len); static int pts_poll(struct fnode *fno, uint16_t events, uint16_t *revents); static int pts_write(struct fnode *fno, const void *buf, unsigned int len); static void pts_tty_attach(struct fnode *fno, int pid); static int pts_close(struct fnode *fno); static struct module mod_ptmx = { .family = FAMILY_DEV, .name = "ptmx", .ops.open = ptmx_open, }; static struct module mod_devpty = { .family = FAMILY_DEV, .name = "pty", .ops.open = pty_open, .ops.read = pty_read, .ops.poll = pty_poll, .ops.write = pty_write, .ops.tty_attach = pty_tty_attach, .ops.close = pty_close }; static struct module mod_devpts = { .family = FAMILY_DEV, .name = "pts", .ops.open = device_open, .ops.read = pts_read, .ops.poll = pts_poll, .ops.write = pts_write, .ops.tty_attach = pts_tty_attach }; static int pts_create(void) { int idx = PTMX.pty_idx++; struct devpts *pts; struct devpty *pty = kalloc(sizeof(struct devpty)); char name[3]; if (!pty) return -ENOMEM; pts = kalloc(sizeof(struct devpts)); if (!pts) { kfree(pty); return -ENOMEM; } if (idx < 10) { name[0] = '0' + idx; name[1] = '\0'; } else { name[0] = '0' + idx / 10; name[1] = '0' + (idx % 10); name[2] = '\0'; } pts->miso = cirbuf_create(PTS_BUFSIZE); pts->mosi = cirbuf_create(PTS_BUFSIZE); pts->dev = device_fno_init(&mod_devpts, name, fno_search("/dev/pts"), FL_TTY, pts); pts->master = pty; pty->idx = idx; pty->fno = fno_create(&mod_devpty, "", &PTMX.PTMX_ROOT); pty->fno->flags |= FL_TTY; pty->fno->priv = pty; pty->slave = pts; pty->task = NULL; pts->task = NULL; pty->sid = -1; pts->sid = -1; pty->creator_pid = this_task_getpid(); return task_filedesc_add(pty->fno); } static void ptmx_create(void) { char name[5] = "ptmx"; struct fnode *devfs = fno_search("/dev"); if (!devfs) return; fno_mkdir(&mod_devpts, "pts", devfs); PTMX.dev = device_fno_init(&mod_ptmx, name, devfs, FL_TTY, &PTMX); PTMX.pty_idx = 0; memset(&PTMX.PTMX_ROOT, 0, sizeof(struct fnode)); } int ptmx_init(void) { ptmx_create(); return 0; } int pty_open(const char *path, int flags) { return -EINVAL; } int ptmx_open(const char *path, int flags) { struct fnode *f = fno_search(path); struct fnode *master, *slave; if (f != PTMX.dev->fno) return -EINVAL; return pts_create(); } static int pty_read(struct fnode *fno, void *buf, unsigned int len) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = -EINVAL; if (len == 0) return 0; pty = (struct devpty *)FNO_MOD_PRIV(fno, &mod_devpty); if (pty) pts = pty->slave; if (pts) { mutex_lock(pts->dev->mutex); if (pts->master != pty) ret = -EPIPE; if (cirbuf_bytesinuse(pts->miso) > 0) { ret = cirbuf_readbytes(pts->miso, buf, len); if ((ret > 0) && pts->task) task_resume(pts->task); } else { pty->task = this_task(); task_suspend(); ret = SYS_CALL_AGAIN; } mutex_unlock(pts->dev->mutex); } return ret; } static int pty_write(struct fnode *fno, const void *buf, unsigned int len) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = -EINVAL; pty = (struct devpty *)FNO_MOD_PRIV(fno, &mod_devpty); if (pty) pts = pty->slave; if (pts) { mutex_lock(pts->dev->mutex); if (pts->master != pty) ret = -EPIPE; if (cirbuf_bytesfree(pts->mosi) > 0) { ret = cirbuf_writebytes(pts->mosi, buf, len); if ((ret > 0) && pts->task) task_resume(pts->task); } else { pty->task = this_task(); task_suspend(); ret = SYS_CALL_AGAIN; } mutex_unlock(pts->dev->mutex); } return ret; } static int pty_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = 0; pty = (struct devpty *)FNO_MOD_PRIV(fno, &mod_devpty); if (!pty) return -EINVAL; if (pty) pts = pty->slave; if (!pts) return -EPIPE; mutex_lock(pts->dev->mutex); if (pts->master != pty) ret = -EPIPE; if ((events & POLLOUT) && (cirbuf_bytesfree(pts->mosi) > 0)) { *revents |= POLLOUT; ret = 1; } if ((events & POLLIN) && (cirbuf_bytesinuse(pts->miso) > 0)) { *revents |= POLLIN; ret = 1; } if (ret == 0) { pty->task = this_task(); } mutex_unlock(pts->dev->mutex); return ret; } static void pty_tty_attach(struct fnode *fno, int pid) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = 0; pty = (struct devpty *)FNO_MOD_PRIV(fno, &mod_devpty); if (pty->sid != pid) { pty->sid = pid; } } static int pty_close(struct fnode *fno) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = 0; pty = (struct devpty *)FNO_MOD_PRIV(fno, &mod_devpty); if (!pty) return -1; pts = pty->slave; if (!pts) return -1; if (this_task_getpid() == pty->creator_pid) { mutex_lock(pts->dev->mutex); fno_unlink(pts->dev->fno); pty->fno->priv = NULL; pts->dev->fno->priv = NULL; kfree(pty); pts->master = NULL; mutex_unlock(pts->dev->mutex); kfree(pts); } return 0; } int pts_open(const char *path, int flags) { struct fnode *f = fno_search(path); struct fnode *master, *slave; if (f != PTMX.dev->fno) return -EINVAL; return pts_create(); } static int pts_read(struct fnode *fno, void *buf, unsigned int len) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = -EINVAL; if (len == 0) return 0; pts = (struct devpts *)FNO_MOD_PRIV(fno, &mod_devpts); if (!pts) goto out; mutex_lock(pts->dev->mutex); pty = pts->master; if (!pty) { ret = -EPIPE; goto out; } if (cirbuf_bytesinuse(pts->mosi) > 0) { ret = cirbuf_readbytes(pts->mosi, buf, len); if ((ret > 0) && pty->task) task_resume(pty->task); } else { pts->task = this_task(); task_suspend(); ret = SYS_CALL_AGAIN; } out: mutex_unlock(pts->dev->mutex); return ret; } static int pts_write(struct fnode *fno, const void *buf, unsigned int len) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = -EINVAL; pts = (struct devpts *)FNO_MOD_PRIV(fno, &mod_devpts); if (!pts) goto out; mutex_lock(pts->dev->mutex); pty = pts->master; if (!pty) { ret = -EPIPE; goto out; } if (cirbuf_bytesfree(pts->miso) > 0) { ret = cirbuf_writebytes(pts->miso, buf, len); if ((ret > 0) && pty->task) task_resume(pty->task); } else { pts->task = this_task(); task_suspend(); ret = SYS_CALL_AGAIN; } out: mutex_unlock(pts->dev->mutex); return ret; } static int pts_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { struct devpty *pty = NULL; struct devpts *pts = NULL; int ret = -EINVAL; pts = (struct devpts *)FNO_MOD_PRIV(fno, &mod_devpts); if (!pts) goto out; mutex_lock(pts->dev->mutex); pty = pts->master; if (!pty) { ret = -EPIPE; goto out; } ret = 0; if ((events & POLLOUT) && (cirbuf_bytesfree(pts->miso) > 0)) { *revents |= POLLOUT; ret = 1; } if ((events & POLLIN) && (cirbuf_bytesinuse(pts->mosi) > 0)) { *revents |= POLLIN; ret = 1; } if (ret == 0) { pts->task = this_task(); } out: mutex_unlock(pts->dev->mutex); return ret; } static void pts_tty_attach(struct fnode *fno, int pid) { struct devpts *pts = NULL; int ret = 0; pts = (struct devpts *)FNO_MOD_PRIV(fno, &mod_devpts); if (pts->sid != pid) { pts->sid = pid; } } int sys_ptsname_hdlr(int fd, char *buf, size_t buflen) { struct devpty *pty = NULL; struct devpts *pts = NULL; struct fnode *fno = task_filedesc_get(fd); size_t pathlen = strlen("/dev/pts/"); if (fd < 0 || !buf) return -EINVAL; if (task_ptr_valid(buf)) return -EACCES; if (buflen < pathlen + 3) return -EINVAL; pty = (struct devpty *)FNO_MOD_PRIV(fno, &mod_devpty); if (!pty) return -ENOTTY; strcpy(buf, "/dev/pts/"); if (pty->idx > 9) { buf[pathlen++] = pty->idx / 10; } buf[pathlen++] = pty->idx % 10; buf[pathlen] = '\0'; return 0; } ================================================ FILE: kernel/drivers/pty.h ================================================ #ifndef PTY_H_INCLUDED #define PTY_H_INCLUDED #ifndef CONFIG_PTY_UNIX # define ptmx_init() do{}while(0) #else int ptmx_init(void); #endif #endif ================================================ FILE: kernel/drivers/rng.h ================================================ #ifndef RNG_INC #define RNG_INC #include "frosted.h" #ifdef CONFIG_RNG int rng_init(void); int rng_create(uint32_t base, uint32_t rcc); #else #define rng_init() (-ENOENT) #define rng_create(...) (-ENOENT) #endif #endif ================================================ FILE: kernel/drivers/sdio.h ================================================ #ifndef INC_SDIO #define INC_SDIO #include "frosted.h" #include "gpio.h" struct sdio_config { uint32_t *base; uint32_t devidx; uint32_t *rcc_reg; uint32_t rcc_en; uint32_t *rcc_rst_reg; uint32_t rcc_rst; struct gpio_config pio_dat0, pio_dat1, pio_dat2, pio_dat3; struct gpio_config pio_clk, pio_cmd; int card_detect_supported; struct gpio_config pio_cd; }; #ifdef CONFIG_SDIO int sdio_init(struct sdio_config *conf); #else #define sdio_init(x) (-ENOENT) #endif #endif ================================================ FILE: kernel/drivers/sdram.h ================================================ #ifndef INC_SDRAM #define INC_SDRAM #if defined CONFIG_SDRAM int sdram_init(void); #else #define sdram_init() (-ENOENT) #endif #endif ================================================ FILE: kernel/drivers/socket_in.c ================================================ #include "frosted.h" #include "socket_in.h" #include #include #include #include #include #include static struct module mod_socket_in; struct frosted_inet_socket { struct fnode *node; struct pico_socket *sock; struct task *task; int fd; uint16_t events; uint16_t revents; int bytes; }; #define SOCK_BLOCKING(s) (((s->node->flags & O_NONBLOCK) == 0)) static int sock_check_fd(int fd, struct fnode **fno) { *fno = task_filedesc_get(fd); if (!fno) return -1; if (fd < 0) return -1; if ((*fno)->owner != &mod_socket_in) return -1; return 0; } static int sock_poll(struct fnode *f, uint16_t events, uint16_t *revents) { struct frosted_inet_socket *s; s = (struct frosted_inet_socket *)f->priv; if (s->revents & PICO_SOCK_EV_CLOSE) *revents |= POLLHUP; if (s->revents & PICO_SOCK_EV_FIN) *revents |= POLLERR; if (s->revents & PICO_SOCK_EV_CONN) *revents |= POLLIN; if (s->revents & PICO_SOCK_EV_RD) *revents |= POLLIN; if (s->revents & PICO_SOCK_EV_WR) *revents |= POLLOUT; if ((*revents) & (POLLHUP | POLLERR) != 0) { return 1; } if ((events & *revents) != 0) return 1; s->events |= events; s->task = this_task(); return 0; } static struct frosted_inet_socket *fd_inet(int fd) { struct fnode *fno; struct frosted_inet_socket *s; if (sock_check_fd(fd, &fno) != 0) return NULL; s = (struct frosted_inet_socket *)fno->priv; return s; } static struct frosted_inet_socket *pico_inet(struct pico_socket *s) { if (!s || !s->priv) return NULL; return (struct frosted_inet_socket *)(s->priv); } static void pico_socket_event(uint16_t ev, struct pico_socket *sock) { struct frosted_inet_socket *s; s = pico_inet(sock); if (!s) { return; } s->revents |= ev; if ((s->revents & s->events) != 0) { task_resume(s->task); s->events = 0; } } static int sock_close(struct fnode *fno) { struct frosted_inet_socket *s; int ret = -1; if (mem_lock() < 0) return SYS_CALL_AGAIN; if (!fno) { ret = -1; goto out; } s = (struct frosted_inet_socket *)fno->priv; if (!s) { ret = -1; goto out; } if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } pico_socket_close(s->sock); pico_unlock(); kfree((struct fnode *)s->node); kfree(s); ret = 0; out: mem_unlock(); return ret; } static struct frosted_inet_socket *inet_socket_new(uint32_t flags) { struct frosted_inet_socket *s; s = kcalloc(sizeof(struct frosted_inet_socket), 1); if (!s) return NULL; s->node = kcalloc(sizeof(struct fnode), 1); if (!s->node) { kfree(s); return NULL; } s->node->flags = FL_RDWR | flags; return s; } static int sock_socket(int domain, int type_flags, int protocol) { int fd = -1; struct frosted_inet_socket *s; int type = type_flags & 0xFFFF; uint32_t fnode_flags = ((uint32_t)type_flags) & 0xFFFF0000u; int ret = -1; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = inet_socket_new(fnode_flags); if (!s) { ret = -ENOMEM; goto out; } if (domain != PICO_PROTO_IPV4) domain = PICO_PROTO_IPV4; if (type == 1) type = PICO_PROTO_TCP; if (type == 2) { if ((protocol == 0) || (protocol == IPPROTO_UDP)) { type = PICO_PROTO_UDP; } else if (protocol == IPPROTO_ICMP) { type = PICO_PROTO_ICMP4; } else { kfree((struct fnode *)s->node); kfree(s); return -EPROTONOSUPPORT; } } if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } s->sock = pico_socket_open(domain, type, pico_socket_event); if (s) s->sock->priv = s; pico_unlock(); if (!s->sock) { kfree((struct fnode *)s->node); kfree(s); ret = 0 - pico_err; goto out; } s->node->owner = &mod_socket_in; s->node->priv = s; s->fd = task_filedesc_add(s->node); if (s->fd >= 0) task_fd_setmask(s->fd, O_RDWR); ret = s->fd; out: mem_unlock(); return ret; } static int sock_recvfrom(int fd, void *buf, unsigned int len, int flags, struct sockaddr *addr, unsigned int *addrlen) { struct frosted_inet_socket *s; int ret; uint16_t port; struct pico_ip4 paddr; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(fd); if (!s) return -EINVAL; while (s->bytes < len) { if ((addr) && ((*addrlen) > 0)) { if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } ret = pico_socket_recvfrom(s->sock, buf + s->bytes, len - s->bytes, &paddr, &port); pico_unlock(); } else { if (pico_trylock() < 0) { return SYS_CALL_AGAIN; } ret = pico_socket_read(s->sock, buf + s->bytes, len - s->bytes); pico_unlock(); } if (ret < 0) { ret = 0 - pico_err; goto out; } if (ret == 0) { s->revents &= (~PICO_SOCK_EV_RD); if (SOCK_BLOCKING(s)) { s->events = PICO_SOCK_EV_RD; s->task = this_task(); task_suspend(); ret = SYS_CALL_AGAIN; goto out; } break; } s->bytes += ret; if (s->bytes > 0) break; } if (addr) { ((struct sockaddr_in *)addr)->sin_family = AF_INET; ((struct sockaddr_in *)addr)->sin_port = port; ((struct sockaddr_in *)addr)->sin_addr.s_addr = paddr.addr; } ret = s->bytes; s->bytes = 0; s->events &= (~PICO_SOCK_EV_RD); s->revents &= (~PICO_SOCK_EV_RD); if ((ret == 0) && !SOCK_BLOCKING(s)) { ret = -EAGAIN; } out: mem_unlock(); return ret; } static int sock_sendto(int fd, const void *buf, unsigned int len, int flags, struct sockaddr *addr, unsigned int addrlen) { struct frosted_inet_socket *s; uint16_t port; struct pico_ip4 paddr; int ret; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(fd); if (!s) { ret = -EINVAL; goto out; } while (len > s->bytes) { if ((addr) && (addrlen >0)) { if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } paddr.addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; port = ((struct sockaddr_in *)addr)->sin_port; ret = pico_socket_sendto(s->sock, buf + s->bytes, len - s->bytes, &paddr, port); pico_unlock(); } else { if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } ret = pico_socket_write(s->sock, buf + s->bytes, len - s->bytes); pico_unlock(); } if (ret == 0) { s->revents &= (~PICO_SOCK_EV_WR); if (SOCK_BLOCKING(s)) { s->events = PICO_SOCK_EV_WR; s->task = this_task(); task_suspend(); ret = SYS_CALL_AGAIN; goto out; } } if (ret < 0) { ret = (0 - pico_err); goto out; } s->bytes += ret; if ((s->sock->proto->proto_number) == PICO_PROTO_UDP && (s->bytes > 0)) break; } ret = s->bytes; s->bytes = 0; s->events &= (~PICO_SOCK_EV_WR); if ((ret == 0) && !SOCK_BLOCKING(s)) { ret = -EAGAIN; } out: mem_unlock(); return ret; } static int sock_bind(int fd, struct sockaddr *addr, unsigned int addrlen) { struct frosted_inet_socket *s; union pico_address paddr; uint16_t port; int ret; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(fd); if (!s) { ret = -EINVAL; goto out; } paddr.ip4.addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; port = ((struct sockaddr_in *)addr)->sin_port; if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } ret = pico_socket_bind(s->sock, &paddr, &port); pico_unlock(); if (ret == 0) { ((struct sockaddr_in *)addr)->sin_port = port; } else { ret = 0 - pico_err; } out: mem_unlock(); return ret; } static int sock_accept(int fd, struct sockaddr *addr, unsigned int *addrlen) { struct frosted_inet_socket *l, *s; struct pico_socket *cli; union pico_address paddr; uint16_t port; struct sockaddr_in *s_in = (struct sockaddr_in *)addr; int ret = -1; if (mem_lock() < 0) return SYS_CALL_AGAIN; l = fd_inet(fd); if (!l) { ret = -EINVAL; goto out; } l->events = PICO_SOCK_EV_CONN; if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } cli = pico_socket_accept(l->sock, &paddr, &port); pico_unlock(); if ((cli == NULL) && (pico_err != PICO_ERR_EAGAIN)) { ret = 0 - pico_err; goto out; } l->revents &= (~PICO_SOCK_EV_CONN); if (cli) { s = inet_socket_new(0); if (!s) { if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } pico_socket_close(cli); pico_unlock(); ret = -ENOMEM; goto out; } s->sock = cli; s->node->owner = &mod_socket_in; s->node->priv = s; s->sock->priv = s; s->fd = task_filedesc_add(s->node); if (s->fd >= 0) task_fd_setmask(s->fd, O_RDWR); if (s_in) { s_in->sin_family = AF_INET; s_in->sin_port = port; s_in->sin_addr.s_addr = paddr.ip4.addr; } ret = s->fd; goto out; } else { if (SOCK_BLOCKING(l)) { l->task = this_task(); task_suspend(); ret = SYS_CALL_AGAIN; } else { ret = -EAGAIN; } } out: mem_unlock(); return ret; } static int sock_connect(int fd, struct sockaddr *addr, unsigned int addrlen) { struct frosted_inet_socket *s; union pico_address paddr; uint16_t port; int ret = -1; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(fd); if (!s) { ret = -EINVAL; goto out; } s->events = PICO_SOCK_EV_CONN; if ((s->revents & PICO_SOCK_EV_CONN) == 0) { paddr.ip4.addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; port = ((struct sockaddr_in *)addr)->sin_port; if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } ret = pico_socket_connect(s->sock, &paddr, port); pico_unlock(); if (SOCK_BLOCKING(s)) { s->task = this_task(); ret = SYS_CALL_AGAIN; } else { ret = -EAGAIN; } goto out; } /* SOCK_EV_CONN received. Successfully connected. */ ret = 0; s->events &= (~PICO_SOCK_EV_CONN); s->revents &= ~(PICO_SOCK_EV_CONN | PICO_SOCK_EV_RD); out: mem_unlock(); return ret; } static int sock_listen(int fd, int backlog) { struct frosted_inet_socket *s; int ret; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(fd); if (!s) { ret = -EINVAL; goto out; } if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } ret = pico_socket_listen(s->sock, backlog); pico_unlock(); s->events |= PICO_SOCK_EV_CONN; out: mem_unlock(); return ret; } static int sock_shutdown(int fd, uint16_t how) { struct frosted_inet_socket *s; int ret; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(fd); if (!s) { ret = -EINVAL; goto out; } if (pico_trylock() < 0) { ret = SYS_CALL_AGAIN; goto out; } ret = pico_socket_shutdown(s->sock, how); pico_unlock(); out: mem_unlock(); return ret; } static int sock_io_setflags(struct pico_device *dev, struct ifreq *ifr) { unsigned int flags = ifr->ifr_flags; if ((flags & IFF_UP) == 0) pico_device_destroy(dev); return 0; } static int sock_io_setaddr(struct pico_device *dev, struct ifreq *ifr) { struct pico_ipv4_link *l; const struct pico_ip4 NM24 = {.addr = long_be(0xFFFFFF00)}; struct sockaddr_in *if_addr = ((struct sockaddr_in *) &ifr->ifr_addr); struct pico_ip4 dev_addr = {}; l = pico_ipv4_link_by_dev(dev); if (l) { pico_ipv4_link_del(dev, l->address); } dev_addr.addr = if_addr->sin_addr.s_addr; return pico_ipv4_link_add(dev, dev_addr, NM24); } static int sock_io_setnetmask(struct pico_device *dev, struct ifreq *ifr) { struct pico_ipv4_link *l; struct sockaddr_in *if_nmask = ((struct sockaddr_in *) &ifr->ifr_netmask); struct pico_ip4 dev_addr = {}; struct pico_ip4 dev_nm = {}; l = pico_ipv4_link_by_dev(dev); if (!l) return -ENOTCONN; dev_addr.addr = l->address.addr; pico_ipv4_link_del(dev, l->address); dev_nm.addr = if_nmask->sin_addr.s_addr; return pico_ipv4_link_add(dev, dev_addr, dev_nm); } static int sock_io_getflags(struct pico_device *dev, struct ifreq *ifr) { memset(ifr, 0, sizeof(struct ifreq)); strncpy(ifr->ifr_name, dev->name, IFNAMSIZ); ifr->ifr_flags = IFF_UP|IFF_RUNNING|IFF_MULTICAST|IFF_BROADCAST; return 0; } static int sock_io_getaddr(struct pico_device *dev, struct ifreq *ifr) { struct pico_ipv4_link *l; struct sockaddr_in *if_addr = ((struct sockaddr_in *) &ifr->ifr_addr); memset(ifr, 0, sizeof(struct ifreq)); strncpy(ifr->ifr_name, dev->name, IFNAMSIZ); l = pico_ipv4_link_by_dev(dev); if (!l) return 0; ifr->ifr_flags = IFF_UP|IFF_RUNNING|IFF_MULTICAST|IFF_BROADCAST; memset(if_addr, 0, sizeof(struct sockaddr_in)); if_addr->sin_family = AF_INET; if_addr->sin_addr.s_addr = l->address.addr; return 0; } static int sock_io_gethwaddr(struct pico_device *dev, struct ifreq *eth) { if (!dev->eth) return -EPROTONOSUPPORT; /* TODO memset(eth, 0, sizeof(struct ifreq)); strncpy(eth->ifr_name, dev->name, IFNAMSIZ); eth->ifr_flags = IFF_UP|IFF_RUNNING|IFF_MULTICAST|IFF_BROADCAST; eth->ifr_hwaddr.sa_family = ARPHRD_ETHER; memcpy (ð->ifr_hwaddr.sa_data, dev->eth, 6); */ return 0; } static int sock_io_getbcast(struct pico_device *dev, struct ifreq *ifr) { struct pico_ipv4_link *l; struct sockaddr_in *if_addr = ((struct sockaddr_in *) &ifr->ifr_broadaddr); memset(if_addr, 0, sizeof(struct sockaddr_in)); if_addr->sin_addr.s_addr = 0xFFFFFFFF; l = pico_ipv4_link_by_dev(dev); if (!l) return 0; if_addr->sin_family = AF_INET; if_addr->sin_addr.s_addr = (l->address.addr & l->netmask.addr) | (~l->netmask.addr); return 0; } static int sock_io_getnmask(struct pico_device *dev, struct ifreq *ifr) { struct pico_ipv4_link *l; struct sockaddr_in *if_nmask = ((struct sockaddr_in *) &ifr->ifr_netmask); l = pico_ipv4_link_by_dev(dev); memset(if_nmask, 0, sizeof(struct sockaddr_in)); if (!l) return 0; if_nmask->sin_family = AF_INET; if_nmask->sin_addr.s_addr = l->netmask.addr; return 0; } static int sock_io_addroute(struct rtentry *rte) { struct pico_ip4 a, g, n; struct pico_ipv4_link *link = NULL; int flags = 1; struct pico_device *dev; dev = pico_get_device((char *)rte->rt_dev); if (dev) link = pico_ipv4_link_by_dev(dev); memcpy(&a, &((struct sockaddr_in *)(&rte->rt_dst))->sin_addr.s_addr, sizeof(struct pico_ip4)); memcpy(&g, &((struct sockaddr_in *)(&rte->rt_gateway))->sin_addr.s_addr, sizeof(struct pico_ip4)); memcpy(&n, &((struct sockaddr_in *)(&rte->rt_genmask))->sin_addr.s_addr, sizeof(struct pico_ip4)); a.addr &= n.addr; if (n.addr == 0) flags +=2; if (rte->rt_metric <= 0) rte->rt_metric = 1; if (pico_ipv4_route_add(a, n, g, rte->rt_metric, link) < 0) return 0 - pico_err; return 0; } static int sock_io_delroute(struct rtentry *rte) { struct pico_ip4 a, g, n; int flags = 1; memcpy(&a, &((struct sockaddr_in *)(&rte->rt_dst))->sin_addr.s_addr, sizeof(struct pico_ip4)); memcpy(&n, &((struct sockaddr_in *)(&rte->rt_genmask))->sin_addr.s_addr, sizeof(struct pico_ip4)); a.addr &= n.addr; if (n.addr == 0) flags +=2; if (rte->rt_metric <= 0) rte->rt_metric = 1; if (pico_ipv4_route_del(a, n, rte->rt_metric) < 0) return 0 - pico_err; return 0; } static int sock_io_ethtool(struct pico_device *dev, struct ifreq *ifr) { return 0; } static int sock_ioctl(struct fnode *fno, const uint32_t cmd, void *arg) { struct frosted_inet_socket *s; struct ifreq *ifr; struct pico_device *dev; int ret = -ENOENT; if (!fno || !arg) return -EINVAL; if (mem_lock() < 0) return SYS_CALL_AGAIN; /* Check for route commands */ if (cmd == SIOCADDRT) { struct rtentry *rte = (struct rtentry *)arg; ret = sock_io_addroute(rte); } else if (cmd == SIOCDELRT) { struct rtentry *rte = (struct rtentry *)arg; ret = sock_io_delroute(rte); } else { /* Check for interface-related ioctl */ ifr = (struct ifreq *)arg; dev = pico_get_device(ifr->ifr_name); if (!dev) ret = -ENOENT; else { switch(cmd) { case SIOCSIFFLAGS: ret = sock_io_setflags(dev, ifr); break; case SIOCSIFADDR: ret = sock_io_setaddr(dev, ifr); break; case SIOCSIFNETMASK: ret = sock_io_setnetmask(dev, ifr); break; case SIOCGIFFLAGS: ret = sock_io_getflags(dev, ifr); break; case SIOCGIFADDR: ret = sock_io_getaddr(dev, ifr); break; case SIOCGIFHWADDR: ret = sock_io_gethwaddr(dev, ifr); break; case SIOCGIFBRDADDR: ret = sock_io_getbcast(dev, ifr); break; case SIOCGIFNETMASK: ret = sock_io_getnmask(dev, ifr); break; case SIOCETHTOOL: ret = sock_io_ethtool(dev, ifr); break; default: ret = -ENOSYS; } } } mem_unlock(); return ret; } /* /sys/net hooks */ #define MAX_DEVNET_BUF 64 static int sysfs_net_dev_read(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; static int off; static char *txt; int i; struct pico_device *dev; struct pico_tree_node *index = NULL; const char iface_banner[] = "Interface | \r\n"; uint32_t cur_off = task_fd_get_off(fno); if (mem_lock() < 0) return SYS_CALL_AGAIN; sysfs_lock(); if (cur_off == 0) { txt = kcalloc(MAX_DEVNET_BUF, 1); off = 0; if (!txt) { len = -1; goto out; } strcpy(txt, iface_banner); off += strlen(iface_banner); pico_tree_foreach(index, &Device_tree){ dev = index->keyValue; strcat(txt, dev->name); off += strlen(dev->name); txt[off++] = '\r'; txt[off++] = '\n'; } } cur_off = task_fd_get_off(fno); if (off == cur_off) { kfree(txt); len = -1; goto out; } if (len > (off - cur_off)) { len = off - cur_off; } memcpy(res, txt + cur_off, len); cur_off += len; task_fd_set_off(fno, cur_off); out: sysfs_unlock(); mem_unlock(); return len; } #define MAX_SYSFS_BUFFER 512 int sysfs_net_route_list(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; static char *mem_txt; struct pico_ipv4_route *r; struct pico_tree_node *index = NULL; char dest[16]; char mask[16]; char gw[16]; char metric[5]; static int off; int i; uint32_t cur_off = task_fd_get_off(fno); if (mem_lock() < 0) return SYS_CALL_AGAIN; if (cur_off == 0) { const char route_banner[] = "Kernel IP routing table\r\nDestination Gateway Genmask Flags Metric Iface \r\n"; sysfs_lock(); mem_txt = kalloc(MAX_SYSFS_BUFFER); if (!mem_txt) return -1; off = 0; strcpy(mem_txt + off, route_banner); off += strlen(route_banner); pico_tree_foreach(index, &Routes){ r = index->keyValue; /* Destination */ pico_ipv4_to_string(dest, r->dest.addr); strcpy(mem_txt + off, dest); off+=strlen(dest); mem_txt[off++] = '\t'; if (strlen(dest) < 8) mem_txt[off++] = '\t'; /* Gateway */ pico_ipv4_to_string(gw, r->gateway.addr); strcpy(mem_txt + off, gw); off+=strlen(gw); mem_txt[off++] = '\t'; if (strlen(gw) < 8) mem_txt[off++] = '\t'; /* Genmask */ pico_ipv4_to_string(mask, r->netmask.addr); strcpy(mem_txt + off, mask); off+=strlen(mask); mem_txt[off++] = '\t'; if (strlen(mask) < 8) mem_txt[off++] = '\t'; /* Flags */ mem_txt[off++] = 'U'; if (r->netmask.addr == 0) mem_txt[off++] = 'G'; mem_txt[off++] = '\t'; /* Metric */ ul_to_str(r->metric, metric); strcpy(mem_txt + off, metric); off += strlen(metric); mem_txt[off++] = '\t'; /* Iface */ strcpy(mem_txt + off, r->link->dev->name); off+=strlen(r->link->dev->name); /* EOL */ mem_txt[off++] = '\r'; mem_txt[off++] = '\n'; } } cur_off = task_fd_get_off(fno); if (off == cur_off) { kfree(mem_txt); sysfs_unlock(); mem_unlock(); return -1; } if (len > (off - cur_off)) { len = off - cur_off; } memcpy(res, mem_txt + cur_off, len); cur_off += len; task_fd_set_off(fno,cur_off); sysfs_unlock(); mem_unlock(); return len; } static int sock_getsockopt(int sd, int level, int optname, void *optval, unsigned int *optlen) { struct frosted_inet_socket *s; int ret; if (mem_lock() < 0) return SYS_CALL_AGAIN; if (*optlen < sizeof(int)) { ret = -EFAULT; goto out; } s = fd_inet(sd); if (!s) { ret = -EINVAL; goto out; } ret = pico_socket_getoption(s->sock, optname, optval); if (ret < 0) ret = 0 - pico_err; else *optlen = sizeof(int); out: mem_unlock(); return ret; } static int sock_setsockopt(int sd, int level, int optname, void *optval, unsigned int optlen) { struct frosted_inet_socket *s; int ret; if (optlen < sizeof(int)) return -EFAULT; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(sd); if (!s) { ret = -EINVAL; } else { ret = pico_socket_setoption(s->sock, optname, optval); if (ret < 0) ret = 0 - pico_err; } mem_unlock(); return ret; } static int sock_getsockname(int sd, struct sockaddr *_addr, unsigned int *addrlen) { struct pico_ip4 ip4a; struct frosted_inet_socket *s; struct sockaddr_in *addr = (struct sockaddr_in *)_addr; int r; uint16_t port, proto; int ret = -1; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(sd); if (!s) { ret = -EINVAL; goto out; } if (*addrlen < sizeof(struct sockaddr_in)) { ret = -ENOBUFS; goto out; } r = pico_socket_getname(s->sock, &ip4a, &port, &proto); if (r < 0) { ret = 0 - pico_err; goto out; } if (proto != PICO_PROTO_IPV4) { ret = -ENOENT; goto out; } memset(addr, 0, *addrlen); *addrlen = sizeof(struct sockaddr_in); addr->sin_family = AF_INET; addr->sin_port = port; addr->sin_addr.s_addr = ip4a.addr; ret = 0; out: mem_unlock(); return ret; } static int sock_getpeername(int sd, struct sockaddr *_addr, unsigned int *addrlen) { struct pico_ip4 ip4a; struct frosted_inet_socket *s; struct sockaddr_in *addr = (struct sockaddr_in *)_addr; int r; uint16_t port, proto; int ret = -1; if (mem_lock() < 0) return SYS_CALL_AGAIN; s = fd_inet(sd); if (!s) { ret = -EINVAL; goto out; } if (*addrlen < sizeof(struct sockaddr_in)) { ret = -ENOBUFS; goto out; } r = pico_socket_getpeername(s->sock, &ip4a, &port, &proto); if (r < 0) { ret = 0 - pico_err; goto out; } if (proto != PICO_PROTO_IPV4) { ret = -ENOTCONN; goto out; } memset(addr, 0, *addrlen); *addrlen = sizeof(struct sockaddr_in); addr->sin_family = AF_INET; addr->sin_port = port; addr->sin_addr.s_addr = ip4a.addr; ret = 0; out: mem_unlock(); return ret; } static int sysfs_no_op(struct sysfs_fnode *sfs, void *buf, int len) { return -1; } void socket_in_init(void) { mod_socket_in.family = FAMILY_INET; strcpy(mod_socket_in.name,"picotcp"); mod_socket_in.ops.poll = sock_poll; mod_socket_in.ops.close = sock_close; mod_socket_in.ops.socket = sock_socket; mod_socket_in.ops.connect = sock_connect; mod_socket_in.ops.accept = sock_accept; mod_socket_in.ops.bind = sock_bind; mod_socket_in.ops.listen = sock_listen; mod_socket_in.ops.recvfrom = sock_recvfrom; mod_socket_in.ops.sendto = sock_sendto; mod_socket_in.ops.shutdown = sock_shutdown; mod_socket_in.ops.ioctl = sock_ioctl; mod_socket_in.ops.getsockopt = sock_getsockopt; mod_socket_in.ops.setsockopt = sock_setsockopt; mod_socket_in.ops.getsockname = sock_getsockname; mod_socket_in.ops.getpeername = sock_getpeername; register_module(&mod_socket_in); register_addr_family(&mod_socket_in, FAMILY_INET); /* Register /sys/net/dev */ sysfs_register("dev", "/sys/net", sysfs_net_dev_read, NULL); /* Register /sys/net/route */ sysfs_register("route", "/sys/net", sysfs_net_route_list, NULL); } ================================================ FILE: kernel/drivers/socket_in.h ================================================ /********************************************************************* PicoTCP. Copyright (c) 2013 TASS Belgium NV. Some rights reserved. See LICENSE and COPYING for usage. Do not redistribute without a written permission by the Copyright holders. Author: Maxime Vincent, Daniele Lacamera *********************************************************************/ #ifndef FROSTED_IN_SOCKETS_H_ #define FROSTED_IN_SOCKETS_H_ #include #include #ifdef CONFIG_PICOTCP #include "pico_defines.h" #include "pico_constants.h" #include "pico_config.h" #include "pico_stack.h" #include "pico_icmp4.h" #include "pico_stack.h" #include "pico_ipv4.h" #include "pico_ipv6.h" #include "pico_dns_client.h" #include "pico_socket.h" #endif #define SOCKSIZE 16 #define SOCKSIZE6 28 struct pico_bsd_endpoint; extern void *picoLock; extern void *pico_signal_tick; typedef int socklen_t; #define AF_INET (2) #define AF_INET6 (10) #define SOL_SOCKET (0x80) #define IP_MULTICAST_LOOP (PICO_IP_MULTICAST_LOOP) #define IP_MULTICAST_TTL (PICO_IP_MULTICAST_TTL) #define IP_MULTICAST_IF (PICO_IP_MULTICAST_IF) #define IP_ADD_MEMBERSHIP (PICO_IP_ADD_MEMBERSHIP) #define IP_DROP_MEMBERSHIP (PICO_IP_DROP_MEMBERSHIP) #define SO_RCVBUF (PICO_SOCKET_OPT_RCVBUF) #define SO_SNDBUF (PICO_SOCKET_OPT_SNDBUF) #define TCP_NODELAY (PICO_TCP_NODELAY) #define TCP_KEEPCNT (PICO_SOCKET_OPT_KEEPCNT) #define TCP_KEEPIDLE (PICO_SOCKET_OPT_KEEPIDLE) #define TCP_KEEPINTVL (PICO_SOCKET_OPT_KEEPINTVL) #define TCP_LINGER (PICO_SOCKET_OPT_LINGER) #define SO_ERROR (4103) #define SO_REUSEADDR (2) #define IPPROTO_ICMP (1) #define IPPROTO_UDP (17) #define sockopt_get_name(x) ((x)) #define INET_ADDRSTRLEN (16) #define INET6_ADDRSTRLEN (46) struct in_addr { uint32_t s_addr; }; #define INADDR_ANY ((uint32_t)0U) struct in6_addr { uint8_t s6_addr[16]; }; struct __attribute__((packed)) sockaddr_in { uint16_t sin_family; uint16_t sin_port; struct in_addr sin_addr; uint8_t _pad[SOCKSIZE - 8]; }; struct __attribute__((packed)) sockaddr_in6 { uint16_t sin6_family; uint16_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; uint32_t sin6_scope_id; }; struct __attribute__((packed)) sockaddr_storage { uint16_t ss_family; uint8_t _pad[(SOCKSIZE6 - sizeof(uint16_t))]; }; /* getaddrinfo */ struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; char *ai_canonname; struct sockaddr *ai_addr; struct addrinfo *ai_next; }; /* hostent */ struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses */ }; #define h_addr h_addr_list[0] /* for backward compatibility */ /* fd_set */ #ifndef FD_SETSIZE #define FD_SETSIZE 64 /* 64 files max, 1 bit per file -> 64bits = 8 bytes */ #endif struct pico_fd_set_s { uint8_t fds_bits[FD_SETSIZE/8]; }; typedef struct pico_fd_set_s pico_fd_set; #ifndef fd_set #define fd_set pico_fd_set #endif //typedef void sigset_t; #define PICO_FD_SET(n, p) ((p)->fds_bits[(n)/8] |= (1u << ((n) % 8))) #define PICO_FD_CLR(n, p) ((p)->fds_bits[(n)/8] &= ~(1u << ((n) % 8))) #define PICO_FD_ISSET(n, p) ((p)->fds_bits[(n)/8] & (1u << ((n) % 8))) #define PICO_FD_ZERO(p) do{memset((p)->fds_bits, 0, sizeof(struct pico_fd_set_s));}while(0) /* Not socket related */ #ifndef __time_t_defined typedef pico_time time_t; #define __time_t_defined #endif #if !defined _TIME_H && !defined _TIMEVAL_DEFINED && !defined _STRUCT_TIMEVAL struct timeval { time_t tv_sec; time_t tv_usec; }; #if !defined __timespec_defined && !defined _SYS__TIMESPEC_H_ struct timespec { long tv_sec; long tv_nsec; }; #endif struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of DST correction */ }; #define _TIMEVAL_DEFINED #endif #ifndef SO_REUSEPORT #define SO_REUSEPORT (15) #endif #ifndef O_NONBLOCK #define O_NONBLOCK 0x4000 #endif #ifndef _SYS_POLL_H #define POLLIN 0x001 /* There is data to read. */ #define POLLPRI 0x002 /* There is urgent data to read. */ #define POLLOUT 0x004 /* Writing now will not block. */ #define POLLRDNORM 0x040 /* Normal data may be read. */ #define POLLRDBAND 0x080 /* Priority data may be read. */ #define POLLWRNORM 0x100 /* Writing now will not block. */ #define POLLWRBAND 0x200 /* Priority data may be written. */ #define POLLMSG 0x400 #define POLLREMOVE 0x1000 #define POLLRDHUP 0x2000 #define POLLERR 0x008 /* Error condition. */ #define POLLHUP 0x010 /* Hung up. */ #define POLLNVAL 0x020 /* Invalid polling request. */ typedef unsigned long int nfds_t; struct pollfd { int fd; uint16_t events; uint16_t revents; }; #endif void pico_lock(void); void pico_unlock(void); void socket_in_init(void); #endif /* PICO_BSD_SOCKETS_H_ */ ================================================ FILE: kernel/drivers/socket_un.c ================================================ #include "frosted.h" #include static struct module mod_socket_un; struct fnode FNO_SOCKUN_STUB = { .owner = &mod_socket_un }; static int sock_check_fd(int fd, struct fnode **fno) { *fno = task_filedesc_get(fd); if (!fno) return -1; if (fd < 0) return -1; if ((*fno)->owner != &mod_socket_un) return -1; return 0; } static int sock_poll(int fd, uint16_t events, uint16_t *revents) { *revents = events; return 1; } static int sock_close(int fd) { struct fnode *fno; if (sock_check_fd(fd, &fno)) return -1; kprintf("## Closed UNIX socket!\n"); /* TODO */ return 0; } int sock_socket(int domain, int type, int protocol) { int fd = -1; kprintf("## Opened UNIX socket!\n"); fd = task_filedesc_add(&FNO_SOCKUN_STUB); return fd; } int sock_recvfrom(int fd, void *buf, unsigned int len, int flags, struct sockaddr *addr, unsigned int *addrlen) { return -1; } int sock_sendto(int fd, const void *buf, unsigned int len, int flags, struct sockaddr *addr, unsigned int addrlen) { return -1; } int sock_bind(int fd, struct sockaddr *addr, unsigned int addrlen) { return -1; } int sock_accept(int fd, struct sockaddr *addr, unsigned int *addrlen) { return -1; } int sock_connect(int fd, struct sockaddr *addr, unsigned int addrlen) { return -1; } int sock_listen(int fd, int backlog) { return -1; } int sock_shutdown(int fd, uint16_t how) { return -1; } void socket_un_init(void) { mod_socket_un.family = FAMILY_UNIX; strcpy(mod_socket_un.name,"un"); mod_socket_un.ops.poll = sock_poll; mod_socket_un.ops.close = sock_close; mod_socket_un.ops.socket = sock_socket; mod_socket_un.ops.connect = sock_connect; mod_socket_un.ops.accept = sock_accept; mod_socket_un.ops.bind = sock_bind; mod_socket_un.ops.listen = sock_listen; mod_socket_un.ops.recvfrom = sock_recvfrom; mod_socket_un.ops.sendto = sock_sendto; mod_socket_un.ops.shutdown = sock_shutdown; register_module(&mod_socket_un); register_addr_family(&mod_socket_un, FAMILY_UNIX); } ================================================ FILE: kernel/drivers/spi.h ================================================ #ifndef INC_SPI #define INC_SPI #include "dma.h" #include "gpio.h" struct spi_config { int idx; uint32_t base; uint32_t irq; uint32_t rcc; uint32_t baudrate; uint8_t polarity; uint8_t phase; uint8_t rx_only; uint8_t bidir_mode; uint16_t dff_16; uint8_t enable_software_slave_management; uint8_t send_msb_first; /* DMA Config */ uint32_t dma_rcc; struct dma_config tx_dma; struct dma_config rx_dma; /* Pin muxing */ struct gpio_config pio_sck; struct gpio_config pio_miso; struct gpio_config pio_mosi; struct gpio_config pio_nss; }; struct spi_slave { uint8_t bus; void (*isr)(struct spi_slave *); void *priv; }; int devspi_create(const struct spi_config *spi_config); int devspi_xfer(struct spi_slave *spi, const char *obuf, char *ibuf, unsigned int len); #endif ================================================ FILE: kernel/drivers/stm32_dma.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include #include "cirbuf.h" #include #include "dma.h" void init_dma(const struct dma_config * dma, uint32_t ptr, uint32_t len) { dma_stream_reset(dma->base, dma->stream); dma_set_transfer_mode(dma->base, dma->stream, dma->dirn); dma_set_priority(dma->base, dma->stream, dma->prio); dma_set_peripheral_address(dma->base, dma->stream, dma->paddr); dma_disable_peripheral_increment_mode(dma->base, dma->stream); dma_set_peripheral_size(dma->base, dma->stream, dma->psize); dma_enable_memory_increment_mode(dma->base, dma->stream); dma_set_memory_size(dma->base, dma->stream, dma->msize); dma_enable_direct_mode(dma->base, dma->stream); dma_set_dma_flow_control(dma->base, dma->stream); dma_channel_select(dma->base,dma->stream,dma->channel); dma_set_memory_address(dma->base, dma->stream, ptr); dma_set_number_of_data(dma->base, dma->stream, len); dma_enable_stream(dma->base, dma->stream); } ================================================ FILE: kernel/drivers/stm32_eth.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Maxime Vincent * */ #include #include "frosted.h" #include "gpio.h" #include "eth.h" #include #include #include #include #include #include #include #include "unicore-mx/cm3/nvic.h" #define dbg(...) #define ETH_MAX_FRAME (1524) /* Round to multiple of 4 bytes! */ #define ETH_IRQ_PRIO (1) /* FIXME: Put in board config */ #define BOARD_PHY_RMII /* Whether the board uses RMII or MII */ #define BOARD_phy_addr PHY_LAN8710A_ID /* The PHY ID to be detected on one of the PHY addresses */ /* Some known PHY-identifiers */ #define PHY_KSZ8021_ID 0x00221556 #define PHY_KS8721_ID 0x00221610 #define PHY_DP83848I_ID 0x20005C90 #define PHY_LAN8710A_ID 0x0007C0F1 #define PHY_DM9161_ID 0x0181B8A0 #define PHY_AM79C875_ID 0x00225540 #define PHY_STE101P_ID 0x00061C50 struct dev_eth { struct pico_device dev; uint32_t rx_prod; uint32_t rx_cons; uint8_t mac_addr[6]; uint8_t phy_addr; }; static struct module mod_eth = { .family = FAMILY_DEV, .name = "ethernet", }; static struct dev_eth * dev_eth_stm = NULL; static uint8_t eth_rx_buf[ETH_MAX_FRAME]; #ifdef STM32F4 static const uint8_t default_mac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54}; #else static const uint8_t default_mac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x57}; #endif static uint32_t eth_smi_get_phy_divider(void) { uint32_t hclk = rcc_ahb_frequency; #if defined(STM32F4) || defined(STM32F7) /* CSR Clock above 200 MHz */ if (hclk >= 200000000) return ETH_MACMIIAR_CR_HCLK_DIV_124; /* CSR Clock between 150-168 MHz */ if (hclk >= 150000000) return ETH_MACMIIAR_CR_HCLK_DIV_102; #endif /* CSR Clock between 100-150 MHz */ if (hclk >= 100000000) return ETH_MACMIIAR_CR_HCLK_DIV_62; /* CSR Clock between 60-100 MHz */ if (hclk >= 60000000) return ETH_MACMIIAR_CR_HCLK_DIV_42; /* CSR Clock between 35-60 MHz */ if (hclk >= 35000000) return ETH_MACMIIAR_CR_HCLK_DIV_26; /* CSR Clock between 20-35 MHz */ if (hclk >= 20000000) return ETH_MACMIIAR_CR_HCLK_DIV_16; dbg("STM32_HCLK below minimum frequency for ETH operations (20MHz)\n"); return 0; } static int8_t find_phy(uint32_t clk_div) { uint32_t phy; for (phy = 0; phy < 31; phy++) { ETH_MACMIIDR = (phy << 6) | clk_div; if ( (eth_smi_read(phy, PHY_REG_ID1) == (BOARD_phy_addr >> 16)) && ((eth_smi_read(phy, PHY_REG_ID2) & 0xFFF0) == (BOARD_phy_addr & 0xFFF0)) ) return (int8_t)phy; } /* PHY not detected */ return -1; } static int stm_eth_poll(struct pico_device *dev, int loop_score) { uint32_t rx_len = 0; /* Possible optimization: * add eth_rx_peek, then dynamically alloc + zerocopy */ while ((loop_score > 0) && eth_rx(eth_rx_buf, &rx_len, ETH_MAX_FRAME)) { pico_stack_recv(dev, eth_rx_buf, rx_len); rx_len = 0; loop_score--; } return loop_score; } static int stm_eth_send(struct pico_device *dev, void * buf, int len) { if (len > ETH_MAX_FRAME) len = ETH_MAX_FRAME; if (eth_tx(buf, len)) return len; else return 0; } /* link state -> 0 == DOWN, 1 == UP */ static int stm_eth_link_state(struct pico_device *dev) { struct dev_eth *stm = (struct dev_eth *)dev; /* test link state */ if (phy_link_isup(stm->phy_addr)) return 1; else return 0; } /** * Description: Low level MAC initialization. * Parameters: phy_addr Pointer a phy_addr variable * clk_div Phy Clock Divider */ static int mac_init(uint8_t * phy_addr, uint32_t clk_div) { int8_t phy_detect; /* Enable SYSCFG clock */ rcc_periph_clock_enable(RCC_SYSCFG); /* MAC clocks stopped to configure RMII .*/ rcc_periph_clock_disable(RCC_ETHMAC); rcc_periph_clock_disable(RCC_ETHMACTX); rcc_periph_clock_disable(RCC_ETHMACRX); /* XXX FIXME */ #define SYSCFG_PMC_MII_RMII_SEL ((uint32_t)0x00800000) /*!phy_addr, clk_div); /* DMA soft-reset */ ETH_DMABMR |= ETH_DMABMR_SR; while(ETH_DMABMR & ETH_DMABMR_SR) {}; eth_init(phy_addr, clk_div); /* does a phy_reset */ eth_set_mac((uint8_t*)default_mac); /* Initialize descriptors */ /* sizes must be multiple of 4 bytes! buffer must be 4 byte aligned */ descriptors = kalloc(2 * 2 * ETH_MAX_FRAME + 2 * 16); /* size of buffers + size of descriptors */ if (!descriptors) return; eth_desc_init(descriptors, 2, 2, ETH_MAX_FRAME, ETH_MAX_FRAME, false); /* set pico function pointers */ dev_eth_stm->dev.poll = stm_eth_poll; dev_eth_stm->dev.send = stm_eth_send; dev_eth_stm->dev.link_state = stm_eth_link_state; if (pico_device_init(&dev_eth_stm->dev,"eth0", default_mac) < 0) { kfree(dev_eth_stm); return; } /* Set address/netmask */ pico_ipv4_link_add(&dev_eth_stm->dev, default_ip, default_nm); /* Set default gateway */ if (default_gw.addr) pico_ipv4_route_add(zero, zero, default_gw, 1, NULL); /* Enabling required interrupt sources.*/ eth_irq_ack_pending(ETH_DMASR); eth_irq_disable(0xFFFF); /* Disable all */ eth_irq_enable(ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE); nvic_set_priority(NVIC_ETH_IRQ, ETH_IRQ_PRIO); nvic_enable_irq(NVIC_ETH_IRQ); eth_start(); } /* HW initialization */ static struct eth_config init_defer_eth_config; static void ethernet_init_deferred(uint32_t t, void *arg) { unsigned int i; (void)t; struct eth_config *conf = (struct eth_config *)arg; /* Create MII pins */ for (i = 0; i < conf->n_pio_mii; i++) gpio_create(&mod_eth, &(conf->pio_mii[i])); /* Create PHY reset pin, if needed */ if (conf->has_phy_reset) { gpio_create(&mod_eth, &conf->pio_phy_reset); /* Reset PHY */ gpio_clear(conf->pio_phy_reset.base, conf->pio_phy_reset.pin); gpio_set(conf->pio_phy_reset.base, conf->pio_phy_reset.pin); } } int pico_eth_start(void) { ktimer_add(100, ethernet_init_deferred, &init_defer_eth_config); ktimer_add(300, pico_eth_start_deferred, NULL); return 0; } int ethernet_init(const struct eth_config *conf) { memcpy(&init_defer_eth_config, conf, sizeof(struct eth_config)); return 0; } void eth_isr(void) { uint32_t bits = ETH_DMASR; /* Clear all bits */ eth_irq_ack_pending(ETH_DMASR); if (bits & ETH_DMASR_RS) { /* Receive Status bit set */ dev_eth_stm->rx_prod++; } } ================================================ FILE: kernel/drivers/stm32_i2c.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include #include #include "unicore-mx/stm32/i2c.h" #include #include #include "device.h" #include #include "cirbuf.h" #include "dma.h" #include "i2c.h" #include "locks.h" /* Dummy module, for gpio claiming only. */ static struct module mod_i2c = { .family = FAMILY_DEV, .name = "i2c" }; enum i2c_state { I2C_STATE_READY, I2C_STATE_ADDRESS, I2C_STATE_REGISTER, I2C_STATE_READ, I2C_STATE_READ_ADDRESS, I2C_STATE_READ_DATA, I2C_STATE_DATA, I2C_STATE_DMA_COMPLETE, I2C_STATE_BTF, I2C_STATE_ERROR, I2C_STATE_MAX }; enum i2c_ev { I2C_EV_START, I2C_EV_TIMEOUT, I2C_EV_MASTER_MODE_SELECT, I2C_EV_MASTER_MODE_ADDRESS10, I2C_EV_MASTER_TRANSMITTER_MODE_SELECTED, I2C_EV_MASTER_RECEIVER_MODE_SELECTED, I2C_EV_DMA_COMPLETE_TX, I2C_EV_DMA_COMPLETE_RX, I2C_EV_BTF, I2C_EV_TXE, I2C_EV_MAX }; struct dev_i2c { struct device * dev; uint32_t base; void (*isr)(struct i2c_slave *sl); struct i2c_slave *sl; uint32_t ev_irq; uint32_t er_irq; uint8_t slv_register; const struct dma_config * tx_dma_config; const struct dma_config * rx_dma_config; mutex_t *mutex; uint8_t dirn; uint8_t kthread_transfer_complete; volatile enum i2c_state state; }; #define MAX_I2CS 4 static struct dev_i2c *DEV_I2C[MAX_I2CS] = { }; static void state_machine(struct dev_i2c *i2c, enum i2c_ev ev); /***************************** MASTER_MODE_SELECT SR2: BUSY|MSL SR1: SB MASTER_MODE_ADDRESS10 SR2: BUSY|MSL SR1: ADD10 MASTER_TRANSMITTER_MODE_SELECTED SR2: BUSY|MSL|TRA SR1: TXE|ADDR MASTER_RECEIVER_MODE_SELECTED SR2: BUSY|MSL SR1: ADDR *****************************/ static void i2c_ev(struct dev_i2c * i2c) { uint32_t sr1 = I2C_SR1(i2c->base); uint32_t sr2 = I2C_SR2(i2c->base); /* MASTER_MODE_SELECT */ if ((sr1 & (I2C_SR1_SB)) == (I2C_SR1_SB)) state_machine(i2c, I2C_EV_MASTER_MODE_SELECT); /* MASTER_MODE_ADDRESS10 */ else if((((sr1 & (I2C_SR1_ADD10)) == (I2C_SR1_ADD10)) && (sr2 & (I2C_SR2_BUSY | I2C_SR2_MSL)) == (I2C_SR2_BUSY | I2C_SR2_MSL)) ) state_machine(i2c, I2C_EV_MASTER_MODE_ADDRESS10); /* MASTER_TRANSMITTER_MODE_SELECTED */ else if((((sr1 & (I2C_SR1_TxE | I2C_SR1_ADDR)) == (I2C_SR1_TxE | I2C_SR1_ADDR)) && (sr2 & (I2C_SR2_BUSY | I2C_SR2_MSL | I2C_SR2_TRA)) == (I2C_SR2_BUSY | I2C_SR2_MSL | I2C_SR2_TRA)) ) state_machine(i2c, I2C_EV_MASTER_TRANSMITTER_MODE_SELECTED); /* MASTER_RECEIVER_MODE_SELECTED */ else if(//((sr1 & (I2C_SR1_ADDR)) == (I2C_SR1_ADDR)) && ((sr2 &(I2C_SR2_BUSY | I2C_SR2_MSL)) == (I2C_SR2_BUSY | I2C_SR2_MSL)) ) state_machine(i2c, I2C_EV_MASTER_RECEIVER_MODE_SELECTED); /* TxE / BTF */ if( (sr1 & (I2C_SR1_TxE)) == (I2C_SR1_TxE) ) state_machine(i2c, I2C_EV_TXE); if( (sr1 & (I2C_SR1_BTF)) == (I2C_SR1_BTF) ) state_machine(i2c, I2C_EV_BTF); } static void restart_state_machine(struct dev_i2c *i2c); /***************************** BERR I2C_SR1_BERR AF I2C_SR1_AF OVR I2C_SR1_OVR PECERR I2C_SR1_PECERR TIMEOUT I2C_SR1_TIMEOUT SMBALERT I2C_SR1_SMBALERT *****************************/ static void i2c_er(struct dev_i2c * i2c) { volatile uint32_t er; if (!i2c) return; er = I2C_SR1(i2c->base); if(er & (I2C_SR1_TIMEOUT) == (I2C_SR1_TIMEOUT)) state_machine(i2c, I2C_EV_TIMEOUT); else { i2c_send_stop(i2c->base); i2c_peripheral_disable(i2c->base); restart_state_machine(i2c); i2c->kthread_transfer_complete++; } } static void i2c_rx_dma_complete(struct dev_i2c * i2c) { if (!i2c) return; state_machine(i2c, I2C_EV_DMA_COMPLETE_RX); } static void i2c_tx_dma_complete(struct dev_i2c * i2c) { if (!i2c) return; state_machine(i2c, I2C_EV_DMA_COMPLETE_TX); } #ifdef CONFIG_I2C1 void i2c1_ev_isr(void) { i2c_ev(DEV_I2C[1]); } void i2c1_er_isr(void) { i2c_er(DEV_I2C[1]); } void dma1_stream5_isr() { dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_LISR_TCIF0); i2c_rx_dma_complete(DEV_I2C[1]); } void dma1_stream6_isr() { dma_clear_interrupt_flags(DMA1, DMA_STREAM6, DMA_LISR_TCIF0); i2c_tx_dma_complete(DEV_I2C[1]); } #endif #ifdef CONFIG_I2C3 void i2c3_ev_isr(void) { i2c_ev(DEV_I2C[3]); } void i2c3_er_isr(void) { i2c_er(DEV_I2C[3]); } void dma1_stream2_isr() { dma_clear_interrupt_flags(DMA1, DMA_STREAM2, DMA_LISR_TCIF0); i2c_rx_dma_complete(DEV_I2C[3]); } void dma1_stream4_isr() { dma_clear_interrupt_flags(DMA1, DMA_STREAM4, DMA_LISR_TCIF0); i2c_tx_dma_complete(DEV_I2C[3]); } #endif static void restart_state_machine(struct dev_i2c *i2c) { mutex_unlock(i2c->mutex); i2c_peripheral_enable(i2c->base); i2c->state = I2C_STATE_READY; } static void state_machine(struct dev_i2c *i2c, enum i2c_ev ev) { volatile uint16_t cr1; volatile uint16_t cr2; switch(i2c->state) { case I2C_STATE_READY: if (ev == I2C_EV_START) { i2c_peripheral_enable(i2c->base); i2c_enable_interrupt(i2c->base, I2C_CR2_ITEVTEN | I2C_CR2_ITERREN); i2c->state = I2C_STATE_ADDRESS; i2c_set_dma_last_transfer(i2c->base); i2c_send_start(i2c->base); } break; case I2C_STATE_ADDRESS: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_MASTER_MODE_SELECT: i2c->state = I2C_STATE_REGISTER; i2c_send_7bit_address(i2c->base, i2c->sl->address >> 1, 0); break; } break; case I2C_STATE_REGISTER: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_MASTER_TRANSMITTER_MODE_SELECTED: case I2C_EV_MASTER_RECEIVER_MODE_SELECTED: if(i2c->dirn) { i2c->state = I2C_STATE_READ; } else { i2c->state = I2C_STATE_DATA; } I2C_DR(i2c->base) = i2c->slv_register; break; } break; case I2C_STATE_READ: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_TXE: i2c->state = I2C_STATE_READ_ADDRESS; i2c_send_start(i2c->base); break; } break; case I2C_STATE_READ_ADDRESS: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_MASTER_MODE_SELECT: i2c->state = I2C_STATE_READ_DATA; i2c_send_7bit_address(i2c->base, i2c->sl->address >> 1, 1); break; } break; case I2C_STATE_READ_DATA: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_MASTER_RECEIVER_MODE_SELECTED: i2c_peripheral_enable(i2c->base); i2c->state = I2C_STATE_DMA_COMPLETE; i2c_enable_dma(i2c->base); break; } break; case I2C_STATE_DATA: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_TXE: i2c->state = I2C_STATE_DMA_COMPLETE; i2c_enable_dma(i2c->base); break; } break; case I2C_STATE_DMA_COMPLETE: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_DMA_COMPLETE_RX: i2c->kthread_transfer_complete++; i2c_disable_dma(i2c->base); i2c_send_stop(i2c->base); i2c_peripheral_disable(i2c->base); i2c->isr(i2c->sl); restart_state_machine(i2c); break; case I2C_EV_DMA_COMPLETE_TX: i2c_disable_dma(i2c->base); i2c->state = I2C_STATE_BTF; break; } break; case I2C_STATE_BTF: switch(ev) { case I2C_EV_TIMEOUT: restart_state_machine(i2c); break; case I2C_EV_TXE: case I2C_EV_BTF: i2c->kthread_transfer_complete++; i2c_disable_dma(i2c->base); i2c_send_stop(i2c->base); i2c_peripheral_disable(i2c->base); i2c->isr(i2c->sl); restart_state_machine(i2c); break; } break; case I2C_STATE_ERROR: restart_state_machine(i2c); break; } } static void isr_kthread(struct i2c_slave *sl) { struct dev_i2c *i2c; i2c = DEV_I2C[sl->bus]; if (!i2c) return; } int i2c_kthread_read(struct i2c_slave *sl, uint8_t reg, uint8_t *buf, uint32_t len) { struct dev_i2c *i2c; if (len <= 0) return len; i2c = DEV_I2C[sl->bus]; if (!i2c) return -ENOENT; mutex_lock(i2c->mutex); i2c->dirn = 1; i2c->slv_register = reg; i2c->isr = isr_kthread; i2c->sl = sl; i2c->kthread_transfer_complete = 0; init_dma(i2c->rx_dma_config, (uint32_t)buf, len); dma_enable_transfer_complete_interrupt(i2c->rx_dma_config->base, i2c->rx_dma_config->stream); nvic_set_priority(i2c->rx_dma_config->irq, 1); nvic_enable_irq(i2c->rx_dma_config->irq); state_machine(i2c, I2C_EV_START); while(i2c->kthread_transfer_complete == 0) kthread_yield(); kthread_sleep_ms(10); return len; } int i2c_kthread_write(struct i2c_slave *sl, uint8_t reg, const uint8_t *buf, uint32_t len) { struct dev_i2c *i2c; if (len <= 0) return len; i2c = DEV_I2C[sl->bus]; if (!i2c) return -ENOENT; mutex_lock(i2c->mutex); i2c->dirn = 0; i2c->slv_register = reg; i2c->isr = isr_kthread; i2c->sl = sl; init_dma(i2c->tx_dma_config, (uint32_t)buf, len); dma_enable_transfer_complete_interrupt(i2c->tx_dma_config->base, i2c->tx_dma_config->stream); nvic_set_priority(i2c->tx_dma_config->irq, 1); nvic_enable_irq(i2c->tx_dma_config->irq); state_machine(i2c, I2C_EV_START); while(i2c->kthread_transfer_complete == 0) kthread_yield(); kthread_sleep_ms(10); return len; } int i2c_init_read(struct i2c_slave *sl, uint8_t reg, uint8_t *buf, uint32_t len) { struct dev_i2c *i2c; if (len <= 0) return len; i2c = DEV_I2C[sl->bus]; if (!i2c) return -ENOENT; if (mutex_trylock(i2c->mutex) < 0) return -EBUSY; i2c->dirn = 1; i2c->slv_register = reg; i2c->isr = sl->isr_rx; i2c->sl = sl; init_dma(i2c->rx_dma_config, (uint32_t)buf, len); dma_enable_transfer_complete_interrupt(i2c->rx_dma_config->base, i2c->rx_dma_config->stream); nvic_set_priority(i2c->rx_dma_config->irq, 1); nvic_enable_irq(i2c->rx_dma_config->irq); state_machine(i2c, I2C_EV_START); return 0; } int i2c_init_write(struct i2c_slave *sl, uint8_t reg, const uint8_t *buf, uint32_t len) { struct dev_i2c *i2c; if (len <= 0) return len; i2c = DEV_I2C[sl->bus]; if (!i2c) return -ENOENT; if (mutex_trylock(i2c->mutex) < 0) return -EBUSY; i2c->dirn = 0; i2c->slv_register = reg; i2c->isr = sl->isr_tx; i2c->sl = sl; init_dma(i2c->tx_dma_config, (uint32_t)buf, len); dma_enable_transfer_complete_interrupt(i2c->tx_dma_config->base, i2c->tx_dma_config->stream); nvic_set_priority(i2c->tx_dma_config->irq, 1); nvic_enable_irq(i2c->tx_dma_config->irq); state_machine(i2c, I2C_EV_START); return 0; } static int i2c_fno_init(const struct i2c_config *conf, struct dev_i2c *i) { struct fnode *devfs = fno_search("/dev"); char name[5] = "i2cX"; if (!devfs) return -EFAULT; name[3] = '0' + conf->idx; } int i2c_create(const struct i2c_config *conf) { struct dev_i2c *i2c = NULL; if (!conf) return -EINVAL; if (conf->base == 0) return -EINVAL; if ((conf->idx < 0) || (conf->idx > MAX_I2CS)) return -EINVAL; i2c = kalloc(sizeof(struct dev_i2c)); if (!i2c) return -ENOMEM; /* Claim pins for SDA/SCL */ gpio_create(&mod_i2c, &conf->pio_sda); gpio_create(&mod_i2c, &conf->pio_scl); /* Erase i2c content */ memset(i2c, 0, sizeof(struct dev_i2c)); /* Enable clocks */ rcc_periph_clock_enable(conf->rcc); rcc_periph_clock_enable(conf->dma_rcc); /* Startup routine */ i2c_peripheral_disable(conf->base); i2c_reset(conf->base); i2c_set_speed(conf->base, 0); //i2c_nack_current(conf->base); i2c_disable_ack(conf->base); i2c_clear_stop(conf->base); i2c_peripheral_enable(conf->base); /* Set up device struct */ i2c->base = conf->base; i2c->ev_irq = conf->ev_irq; i2c->er_irq = conf->er_irq; i2c->tx_dma_config = &conf->tx_dma; i2c->rx_dma_config = &conf->rx_dma; i2c->state = I2C_STATE_READY; i2c->mutex = mutex_init(); /* Store address in the DEV_I2C array. */ DEV_I2C[conf->idx] = i2c; /* Enable interrupts */ nvic_set_priority(conf->ev_irq, 1); nvic_enable_irq(conf->ev_irq); nvic_set_priority(conf->er_irq, 1); nvic_enable_irq(conf->er_irq); return 0; } ================================================ FILE: kernel/drivers/stm32_lowpower.c ================================================ #include "frosted.h" #include "unicore-mx/cm3/nvic.h" #include "unicore-mx/cm3/systick.h" #include "unicore-mx/cm3/scb.h" #include #include #include #include #include #include #include #include #define WFE() __asm__ volatile ("wfe") #if CONFIG_SYS_CLOCK == 48000000 # define STM32_CLOCK RCC_CLOCK_3V3_48MHZ #elif CONFIG_SYS_CLOCK == 84000000 # define STM32_CLOCK RCC_CLOCK_3V3_84MHZ #elif CONFIG_SYS_CLOCK == 100000000 # define STM32_CLOCK RCC_CLOCK_3V3_100MHZ #elif CONFIG_SYS_CLOCK == 120000000 # define STM32_CLOCK RCC_CLOCK_3V3_120MHZ #elif CONFIG_SYS_CLOCK == 168000000 # define STM32_CLOCK RCC_CLOCK_3V3_168MHZ #else # error No valid clock speed selected #endif int lowpower_init(void) { rcc_periph_clock_enable(RCC_PWR); rcc_periph_clock_enable(RCC_RTC); /* Disable write protection in the backup range */ PWR_CR |= PWR_CR_DBP; rtc_unlock(); nvic_clear_pending_irq(NVIC_RTC_WKUP_IRQ); nvic_disable_irq(NVIC_RTC_WKUP_IRQ); RTC_ISR &= ~RTC_ISR_WUTF; RTC_CR &= ~(RTC_CR_WUTIE | RTC_CR_WUTE); rtc_lock(); return 0; } int lowpower_sleep(int stdby, uint32_t interval) { uint32_t rtc_wup; uint32_t err; if (interval < 1) return -1; rtc_wup = (interval * 2048) - 1; irq_off(); rcc_periph_clock_enable(RCC_PWR); rcc_periph_clock_enable(RCC_RTC); /* Disable write protection in the backup range */ pwr_disable_backup_domain_write_protect(); /* Enable RTC */ RCC_BDCR |= RCC_BDCR_RTCEN; #ifndef CONFIG_LSE32K /* Enable LSI */ rcc_osc_on(RCC_LSI); rcc_wait_for_osc_ready(RCC_LSI); /* Select LSI as RTC clock source */ RCC_BDCR &= ~RCC_BDCR_RTCSEL_MASK << RCC_BDCR_RTCSEL_SHIFT; RCC_BDCR |= RCC_BDCR_RTCSEL_LSI << RCC_BDCR_RTCSEL_SHIFT; #else /* Enable LSE */ rcc_osc_bypass_disable(RCC_LSE); rcc_osc_on(RCC_LSE); rcc_wait_for_osc_ready(RCC_LSE); /* Select LSE as RTC clock source */ RCC_BDCR &= ~RCC_BDCR_RTCSEL_MASK << RCC_BDCR_RTCSEL_SHIFT; RCC_BDCR |= RCC_BDCR_RTCSEL_LSE << RCC_BDCR_RTCSEL_SHIFT; #endif /* Set up watchdog timer */ rtc_unlock(); rtc_enable_wakeup_timer(); rtc_set_wakeup_time((interval - 1), RTC_CR_WUCLKSEL_SPRE); rtc_lock(); systick_counter_disable(); systick_interrupt_disable(); SCB_SCR |= SCB_SCR_SEVEONPEND; SCB_SCR |= SCB_SCR_SLEEPDEEP; if (stdby) { pwr_clear_wakeup_flag(); pwr_clear_standby_flag(); pwr_set_standby_mode(); } else { pwr_clear_wakeup_flag(); pwr_voltage_regulator_low_power_in_stop(); PWR_CR |= PWR_CR_FPDS; } irq_on(); WFE(); WFE(); SCB_SCR &= ~SCB_SCR_SLEEPDEEP; pwr_clear_wakeup_flag(); #ifdef CLOCK_12MHZ rcc_clock_setup_hse_3v3(&rcc_hse_12mhz_3v3[STM32_CLOCK]); #else rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[STM32_CLOCK]); #endif systick_interrupt_enable(); systick_counter_enable(); rcc_periph_clock_enable(RCC_PWR); rcc_periph_clock_enable(RCC_RTC); nvic_enable_irq(NVIC_RTC_WKUP_IRQ); /* Disable write protection in the backup range */ pwr_disable_backup_domain_write_protect(); /* Disable RTC */ RCC_BDCR &= ~RCC_BDCR_RTCEN; jiffies += interval * 1000; return 0; } void rtc_wkup_isr(void) { /* Enable RTC */ RCC_BDCR |= RCC_BDCR_RTCEN; rtc_unlock(); nvic_clear_pending_irq(NVIC_RTC_WKUP_IRQ); nvic_disable_irq(NVIC_RTC_WKUP_IRQ); RTC_ISR &= ~RTC_ISR_WUTF; RTC_CR &= ~(RTC_CR_WUTIE | RTC_CR_WUTE); rtc_lock(); } ================================================ FILE: kernel/drivers/stm32_rng.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: brabo * */ #include "frosted.h" #include "device.h" #if defined(CONFIG_FRAND) # include "frand.h" # include "fortuna.h" # include "crypto/sha256.h" #endif #include #include "rng.h" #include #include #include #include #define CLOCK_ENABLE(C) rcc_periph_clock_enable(C); struct dev_rng { struct device *dev; uint32_t base; uint32_t *random; }; #define MAX_RNGS 1 #if defined(CONFIG_FRAND) uint32_t req; #endif static struct dev_rng DEV_RNG[MAX_RNGS]; #if defined(CONFIG_RNG) static int devrng_read(struct fnode *fno, void *buf, unsigned int len); #endif static struct module mod_devrng = { .family = FAMILY_FILE, #if defined(CONFIG_RNG) .name = "urandom", .ops.open = device_open, .ops.read = devrng_read, #endif }; #if defined(CONFIG_RNG) static int devrng_read(struct fnode *fno, void *buf, unsigned int len) { struct dev_rng *rng; int i; uint32_t tmp; if (len == 0) return len; rng = (struct dev_rng *)FNO_MOD_PRIV(fno, &mod_devrng); if (!rng) return -1; mutex_lock(rng->dev->mutex); uint32_t error_bits = 0; error_bits = RNG_SR_SEIS | RNG_SR_CEIS | RNG_SR_SECS | RNG_SR_CECS; for (i = 0; i < len; i+=4) { uint32_t *rnd_dst = (uint32_t *)((uint8_t *)buf + i); if (((RNG_SR & error_bits) != 0) || ((RNG_SR & RNG_SR_DRDY) != 1)) { rng->random = (uint32_t *)buf; rng_enable_interrupt(); rng->dev->task = this_task(); mutex_unlock(rng->dev->mutex); task_suspend(); return SYS_CALL_AGAIN; } rng_get_random(rnd_dst); } if (i < len) { rng_get_random(&tmp); memcpy(buf + i, &tmp, len - i); } mutex_unlock(rng->dev->mutex); return len; } #endif void rng_isr(void) { struct dev_rng *rng = &DEV_RNG[0]; uint32_t error_bits = 0; error_bits = RNG_SR_SEIS | RNG_SR_CEIS | RNG_SR_SECS | RNG_SR_CECS; if ((RNG_SR & RNG_SR_SEIS) != 0) { if ((RNG_SR & RNG_SR_DRDY) == 1) { uint32_t dummy; rng_get_random(&dummy); } rng_disable(); rng_enable(); RNG_SR &= ~RNG_SR_SEIS; } if ((RNG_SR & RNG_SR_CEIS) != 0) { rcc_periph_reset_pulse(RST_RNG); rng_disable(); rng_enable(); RNG_SR &= ~RNG_SR_CEIS; } if (((RNG_SR & error_bits) == 0) && ((RNG_SR & RNG_SR_DRDY) == 1)) { uint32_t random; rng_get_random(&random); #if defined(CONFIG_FRAND) fortuna_accu(0, 0, (uint8_t *)&random, 4); if (req == 0) { rng_disable_interrupt(); } else { req--; } #else memcpy(rng->random, &random, 4); rng_disable_interrupt(); task_resume(rng->dev->task); #endif } } #if defined(CONFIG_RNG) int rng_create(uint32_t base, uint32_t rcc) { static uint32_t id = 0; struct dev_rng *r = &DEV_RNG[id]; struct fnode *devfs; CLOCK_ENABLE(rcc); devfs = fno_search("/dev"); if (!devfs) return -ENOENT; r->dev = device_fno_init(&mod_devrng, mod_devrng.name, devfs, FL_RDONLY, r); r->base = base; rng_enable(); return id++; } #endif #if defined(CONFIG_FRAND) static const struct frand_ops rng_frandops = { }; static struct frand_info rng_info = { .frandops = (struct frand_ops *)&rng_frandops }; #endif int rng_init(void) { register_module(&mod_devrng); #if defined(CONFIG_FRAND) register_frand(&rng_info); req = FORTUNA_ENCRYPT_KEY_SIZE * ((SHA256_DIGEST_SIZE / sizeof(word32)) * (SHA256_BLOCK_SIZE / sizeof(word32))); rng_enable_interrupt(); #endif return 0; } ================================================ FILE: kernel/drivers/stm32_sdio.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Original Author: Chuck M. (see https://github.com/ChuckM/stm32f4-sdio-driver/) * Re-adapted for frosted by: Daniele Lacamera * * Permission to release under the terms of GPLv2 are granted by the * copyright holders. * */ /* * SDIO Bus Driver layer. This code sends commands and drives * the SDIO peripheral on the STM32F4xx, there is a layer above * this, the SD Card driver, which uses this driver to talk to * SD Cards. The SPI driver can also talk to SD Cards, hence the * split at this layer. * * Note that the simple implementation for the SDIO driver runs * in a 'polled' mode. This is easier to explain and debug and * sufficient for the first few projects. A more sophisticated * version with DMA and interrupts will follow. * * * */ #include #include #include #include #include #include "stm32_sdio.h" #include "frosted.h" #include "device.h" #include "sdio.h" #define MAX_SDIOS 1 /* Frosted device driver hook */ static struct module mod_sdio; static struct dev_sd *DEV_SD[MAX_SDIOS] = { }; /* * Some Global defines, collected here. */ /* * Not defined by default */ #ifndef NULL #define NULL (void *)(0x00000000) #endif /* * Helper defines to pull out various bit fields of the CSD for * the size calculation. */ #define SDIO_CSD_VERSION(x) stm32_sdio_bit_slice(x->csd, 128, 127, 126) #define SDIO_CSD1_CSIZE_MULT(x) stm32_sdio_bit_slice(x->csd, 128, 49, 47) #define SDIO_CSD1_RBLKLEN(x) stm32_sdio_bit_slice(x->csd, 128, 83, 80) #define SDIO_CSD1_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 73, 62) #define SDIO_CSD2_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 69, 48) /* * Conveniently swaps the bytes in a long around * used by the SCR code. */ #define byte_swap(val) \ asm("rev %[swap], %[swap]" : [swap] "=r" (val) : "0" (val)); /* * sdio_bus * * Set the bus width and the clock speed for the * SDIO bus. * * Returns 0 on success * -1 illegal bit specification * -2 illegal clock specification */ int stm32_sdio_bus(struct dev_sd *sd, int bits, enum SDIO_CLOCK_DIV freq) { int clkreg = 0; switch (bits) { case 1: clkreg |= SDIO_CLKCR_WIDBUS_1; break; case 4: clkreg |= SDIO_CLKCR_WIDBUS_4; break; default: return -1; } switch (freq) { case SDIO_24MHZ: break; case SDIO_16MHZ: clkreg |= 1; break; case SDIO_12MHZ: clkreg |= 2; break; case SDIO_8MHZ: clkreg |= 8; break; case SDIO_4MHZ: clkreg |= 10; break; case SDIO_1MHZ: clkreg |= 46; break; case SDIO_400KHZ: clkreg |= 118; break; default: return -2; } clkreg |= SDIO_CLKCR_CLKEN; SDIO_CLKCR(sd->base) = clkreg; return 0; } /* * Reset the state of the SDIO bus and peripheral. This code tries * to reset the bus *AND* the card if one is plugged in. The bus * can be reset by software but the card is reset by powering it down. * * The SDIO_POWER_STATE tells the code which state to leave the bus in, * powered up or powered down. * * If the state is POWER_ON, then the bus is reset to 400Khz, 1 bit wide * which is what he spec requires. Once the type and capabilities of the * card have been determined, it can be upgraded. */ void stm32_sdio_reset(struct dev_sd *sd, enum SDIO_POWER_STATE state) { /* Step 1 power off the interface */ SDIO_POWER(sd->base) = SDIO_POWER_PWRCTRL_PWROFF; /* reset the SDIO peripheral interface */ rcc_peripheral_reset(sd->rcc_rst_reg, sd->rcc_rst); rcc_peripheral_clear_reset(sd->rcc_rst_reg, sd->rcc_rst); if (state == SDIO_POWER_ON) { SDIO_POWER(sd->base) = SDIO_POWER_PWRCTRL_PWRON; stm32_sdio_bus(sd, 1, SDIO_400KHZ); // required by the spec } } /* * The error message catalog. */ static const char *__sdio_error_msgs[] = { "Success", "Command Timeout", // -1 "Command CRC Failure", // -2 "Soft Timeout (No Response)", // -3 "Data CRC Failure", // -4 "RX FIFO Overrun", // -5 "TX FIFO Underrun", // -6 "Unsupported Card" // -7 }; #define SDIO_ESUCCESS 0 #define SDIO_ECTIMEOUT -1 #define SDIO_ECCRCFAIL -2 #define SDIO_ENORESP -3 #define SDIO_EDCRCFAIL -4 #define SDIO_ERXOVERR -5 #define SDIO_ETXUNDER -6 #define SDIO_EBADCARD -7 #define SDIO_EUNKNOWN -8 /* * Return a text string description of the error code. */ const char * stm32_sdio_errmsg(int err) { return (err <= SDIO_EUNKNOWN) ? (const char *) "Unknown Error" : __sdio_error_msgs[0-err]; } /* * stm32_sdio_bit_slice - helper function * * A number of the things the SDIO returns are in bit * fields. This code is designed to slice out a range * of bits and return them as a value (up to 32 bits * worth). */ uint32_t stm32_sdio_bit_slice(uint32_t a[], int bits, int msb, int lsb) { uint32_t t; int i; if (((msb >= bits) || (msb < 0)) || (lsb > msb) || ((lsb < 0) || (lsb >= bits))) { kprintf("Bad Slice values.\r\n"); return 0; } t = 0; for (i = msb; i > lsb; i--) { t |= (a[((bits-1) - i)/32] >> (i % 32)) & 0x1; t <<= 1; } t |= (a[((bits-1) - lsb)/32] >> (lsb % 32)) & 0x1; return t; } /* * A convienence define. These are the flags we care about when * sending a command. During command processing SDIO_STA_CMDACT * will be set. */ #define COMMAND_FLAGS (SDIO_STA_CMDSENT |\ SDIO_STA_CCRCFAIL |\ SDIO_STA_CMDREND |\ SDIO_STA_CTIMEOUT) /* * Send a command over the SDIO bus. * Passed a command (8 bit value) and an argument (32 bit value) * This command figures out if the command will return a short (32 bit) * or long (64 bit) response. It is up to the calling program to pull * data from the long response commands. * Passed: * cmd - Command to execute * arg - Argument to pass to the command * buf - pointer to a long aligned buffer if data * len - expected length of buffer (in bytes) */ int stm32_sdio_command(struct dev_sd *sd, uint32_t cmd, uint32_t arg) { uint32_t tmp_val; int error = 0; tmp_val = SDIO_CMD(sd->base) & ~0x7ff; // Read pre-existing state tmp_val |= (cmd & SDIO_CMD_CMDINDEX_MSK); // Put the Command in tmp_val |= SDIO_CMD_CPSMEN; // We'll be running CPSM switch(cmd) { case 0: tmp_val |= SDIO_CMD_WAITRESP_NO_0; break; case 2: case 9: tmp_val |= SDIO_CMD_WAITRESP_LONG; break; default: tmp_val |= SDIO_CMD_WAITRESP_SHORT; // the common case break; } /* If a data transaction is in progress, wait for it to finish */ while ((cmd != 12) & (SDIO_STA(sd->base) & (SDIO_STA_RXACT | SDIO_STA_TXACT)));; /* * EXECUTE: * o Reset all status bits * o Put ARG into SDIO ARG * o reset the error indicator * o Enable all interrupts. * o Do the command */ SDIO_ICR(sd->base) = 0x7ff; // Reset everything that isn't bolted down. SDIO_ARG(sd->base) = arg; SDIO_CMD(sd->base) = tmp_val; /* * In a polled mode we should be able to just read the status bits * directly. */ tmp_val = 0; do { tmp_val |= (SDIO_STA(sd->base) & 0x7ff); } while ((SDIO_STA(sd->base) & SDIO_STA_CMDACT) || (! tmp_val));; SDIO_ICR(sd->base) = tmp_val; /* * Compute the error here. Which can be one of * -- Success (either CMDSENT or CMDREND depending on response) * -- Timeout (based on CTIMEOUT) * -- No Response (based on no response in the time alloted) * -- CRC Error (based on CCRCFAIL) */ if (! tmp_val) { error = SDIO_ENORESP; } else if (tmp_val & SDIO_STA_CCRCFAIL) { error = SDIO_ECCRCFAIL; } else if (tmp_val & (SDIO_STA_CMDREND | SDIO_STA_CMDSENT)) { error = SDIO_ESUCCESS; } else if (tmp_val & SDIO_STA_CTIMEOUT) { error = SDIO_ECTIMEOUT; } else { error = SDIO_EUNKNOWN; } return error; } /* our static data buffer we use for data movement commands */ static uint32_t data_buf[129]; static int data_len; /* * Helper function - sdio_select * * This function "selects" a card using CMD7, note that if * you select card 0 that deselects the card (RCA is not allowed * to be 0) */ static int sdio_select(struct dev_sd *sd, int rca) { int err; err = stm32_sdio_command(sd, 7, rca << 16); if ((rca == 0) && (err == SDIO_ECTIMEOUT)) { return 0; // "cheat" a timeout selecting 0 is a successful deselect } return err; } /* * Helper function - sdio_scr * * Unlike the CID and CSD functions this function transfers data * so it needs to use the DPSM. * * Note that data over the wire is byte swapped so we swap it back * to "fix" it. * * Note when this return 0 the first two longs in the data_buf are * the SCR register. */ static int sdio_scr(struct dev_sd *sd, SDIO_CARD c) { int err; uint32_t tmp_reg; int ndx; /* Select the card */ err = sdio_select(sd, c->rca); if (! err) { /* Set the Block Size */ err = stm32_sdio_command(sd, 16, 8); if (! err) { /* APPCMD (our RCA) */ err = stm32_sdio_command(sd, 55, c->rca << 16); if (! err) { SDIO_ICR(sd->base) = 0xFFFFFFFF; /* Clear all status flags */ SDIO_DTIMER(sd->base) = 0xffffffff; SDIO_DLEN(sd->base) = 8; SDIO_DCTRL(sd->base) = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN; /* ACMD51 - Send SCR */ err = stm32_sdio_command(sd, 51, 0); if (! err) { data_len = 0; do { tmp_reg = SDIO_STA(sd->base); if (tmp_reg & SDIO_STA_RXDAVL) { data_buf[data_len++] = SDIO_FIFO(sd->base); } } while (tmp_reg & SDIO_STA_RXACT); if ((tmp_reg & SDIO_STA_DBCKEND) == 0) { if (tmp_reg & SDIO_STA_DCRCFAIL) { err = SDIO_EDCRCFAIL; } else if (tmp_reg & SDIO_STA_RXOVERR) { err = SDIO_ERXOVERR; } else { err = SDIO_EUNKNOWN; // XXX: unknown error } } if (! err) { for (ndx = 0; ndx < 2; ndx++) { byte_swap(data_buf[ndx]); c->scr[ndx] = data_buf[ndx]; } } } } } } (void) sdio_select(sd, 0); if (err) kprintf("[SDIO] %s\n", stm32_sdio_errmsg(err)); return err; } /* * Read a Block from our Card * * NB: There is a possibly useless test in this code, during the read * phase it allows that the SDIO card might try to send more than 512 * bytes (128 32 bit longs) and allows it to do so, constantly over * writing the last long in the just-in-case-over-long-by-1 data buffer. * To compromise the system you would need a borked or custom crafted * sdio card which did that. */ int sdio_block_read(struct fnode *fno, void *_buf, uint32_t lba, int offset, int count) { int err; uint32_t tmp_reg; uint32_t addr = lba; uint8_t *t; int ndx, bdx = 0; struct dev_sd *sd; SDIO_CARD c; uint8_t *buf = _buf; sd = (struct dev_sd *)FNO_MOD_PRIV(fno, &mod_sdio); if (!sd) return -1; c = sd->card; if (! SDIO_CARD_CCS(c)) { addr = lba * 512; // non HC cards use byte address } err = sdio_select(sd, c->rca); if (! err) { err = stm32_sdio_command(sd, 16, 512); if (!err) { SDIO_DTIMER(sd->base) = 0xffffffff; SDIO_DLEN(sd->base) = 512; SDIO_DCTRL(sd->base) = SDIO_DCTRL_DBLOCKSIZE_9 | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN; err = stm32_sdio_command(sd, 17, addr); if (! err) { data_len = 0; do { tmp_reg = SDIO_STA(sd->base); if (tmp_reg & SDIO_STA_RXDAVL) { data_buf[data_len] = SDIO_FIFO(sd->base); if (data_len < 128) { ++data_len; } } } while (tmp_reg & SDIO_STA_RXACT); if ((tmp_reg & SDIO_STA_DBCKEND) == 0) { if (tmp_reg & SDIO_STA_DCRCFAIL) { err = SDIO_EDCRCFAIL; } else if (tmp_reg & SDIO_STA_RXOVERR) { err = SDIO_ERXOVERR; } else { err = SDIO_EUNKNOWN; // Unknown Error! } } else { t = (uint8_t *)(data_buf); /* copy out to the user buffer */ for (ndx = offset; ndx < (offset + count); ndx ++) { buf[bdx++] = t[ndx]; } } } } } // deselect the card (void) sdio_select(sd, 0); if (err) kprintf("[SDIO] %s\n", stm32_sdio_errmsg(err)); return err; } /* * Write a Block from our Card */ //int //sdio_block_write(SDIO_CARD c, uint32_t lba, uint8_t *buf) { int sdio_block_write(struct fnode *fno, void *_buf, uint32_t lba, int offset, int count) { int err; uint32_t tmp_reg; uint32_t addr = lba; uint8_t *t; int ndx; struct dev_sd *sd; SDIO_CARD c; uint8_t *buf = _buf; sd = (struct dev_sd *)FNO_MOD_PRIV(fno, &mod_sdio); if (!sd) return -1; c = sd->card; if (! SDIO_CARD_CCS(c)) { addr = lba * 512; // non HC cards use byte address } /* * Copy buffer to our word aligned buffer. Nominally you * can just use the passed in buffer and cast it to a * uint32_t * but that can cause issues if it isn't * aligned. */ t = (uint8_t *)(data_buf); for (ndx = 0; ndx < 512; ndx ++) { *t = *buf; buf++; t++; } err = sdio_select(sd, c->rca); if (! err) { /* Set Block Size to 512 */ err = stm32_sdio_command(sd, 16, 512); if (!err) { SDIO_DTIMER(sd->base) = 0xffffffff; SDIO_DLEN(sd->base) = 512; SDIO_DCTRL(sd->base) = SDIO_DCTRL_DBLOCKSIZE_9 | SDIO_DCTRL_DTEN; err = stm32_sdio_command(sd, 24, addr + offset); if (! err) { data_len = 0; do { tmp_reg = SDIO_STA(sd->base); if (tmp_reg & SDIO_STA_TXFIFOHE) { SDIO_FIFO(sd->base) = data_buf[data_len]; if (data_len < 128) { ++data_len; } } } while (tmp_reg & SDIO_STA_TXACT); if ((tmp_reg & SDIO_STA_DBCKEND) == 0) { if (tmp_reg & SDIO_STA_DCRCFAIL) { err = SDIO_EDCRCFAIL; } else if (tmp_reg & SDIO_STA_TXUNDERR) { err = SDIO_ETXUNDER; } else { err = SDIO_EUNKNOWN; // Unknown Error! } } } } } // deselect the card (void) sdio_select(sd, 0); if (err) kprintf("[SDIO] %s\n", stm32_sdio_errmsg(err)); return err; } /* * sdio-status - Get Card Status page * * This function fetches the SD Card Status page and * copies it into the CARD structure. */ /* int sdio_status(SDIO_CARD c) { uint32_t tmp_reg; int ndx; int err; err = sdio_select(c->rca); if (! err) { err = stm32_sdio_command(16, 64); if (! err) { err = stm32_sdio_command(55, c->rca << 16); if (! err) { SDIO_DTIMER = 0xffffffff; SDIO_DLEN = 64; SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_6 | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN; */ /* ACMD13 - Send Status Reg */ /* err = stm32_sdio_command(13, 0); if (! err) { data_len = 0; do { tmp_reg = SDIO_STA; if (tmp_reg & SDIO_STA_RXDAVL) { data_buf[data_len] = SDIO_FIFO; if (data_len < 128) { ++data_len; } } } while (tmp_reg & SDIO_STA_RXACT); if ((tmp_reg & SDIO_STA_DBCKEND) == 0) { if (tmp_reg & SDIO_STA_DCRCFAIL) { err = SDIO_EDCRCFAIL; } else if (tmp_reg & SDIO_STA_RXOVERR) { err = SDIO_ERXOVERR; } else { err = SDIO_EUNKNOWN; // Unknown Error! } } else { for (ndx = 0; ndx < 16; ndx++) { byte_swap(data_buf[ndx]); c->status[ndx] = data_buf[ndx]; } } (void) sdio_select(0); } } } } if (err) kprintf("[SDIO] %s\n", stm32_sdio_errmsg(err)); return err; } */ static struct SDIO_CARD_DATA __sdio_card_data; #define MAX_RETRIES 5 /* * stm32_sdio_open - Prepare to use SDIO card * * This function resets the SDIO bus and identifies the * card (if any) that is plugged in. If there is no card * present, or an error in figuring out what the card is * (for example its an old MMC card) the function returns * NULL. If it fails and you have logging enabled you can * look at the last few commands sent. */ SDIO_CARD stm32_sdio_open(struct dev_sd *sd) { int err; int i; uint8_t *t; uint32_t tmp_reg; SDIO_CARD res = &__sdio_card_data; // basically bset(0, __sdio_card_data) t = (uint8_t *) &__sdio_card_data; for (i = 0; i < (int) sizeof(__sdio_card_data); i++) { *t++ = 0; } stm32_sdio_reset(sd, SDIO_POWER_ON); err = stm32_sdio_command(sd, 0, 0); if (!err) { err = stm32_sdio_command(sd, 8, 0x1aa); if (!err) { // Woot! We support CMD8 so we're a v2 card at least */ tmp_reg = SDIO_RESP1(sd->base); __sdio_card_data.props = 1; i = 0; err = stm32_sdio_command(sd, 5, 0); if (! err) { // It is an SDIO card which is unsupported! err = SDIO_EBADCARD; return NULL; } do { err = stm32_sdio_command(sd, 55, 0); // broadcast ACMD if (err) { break; // try again } // Testing Card Busy, Voltage match, and capacity err = stm32_sdio_command(sd, 41, 0xc0100000); if (err != -2) { // Expect CCRCFAIL here break; // try again } tmp_reg = SDIO_RESP1(sd->base); // what did the card send? if ((tmp_reg & 0x80000000) == 0) { continue; // still powering up } res->ocr = tmp_reg; // Ok OCR is valid break; } while (++i < MAX_RETRIES); if (res->ocr) { err = stm32_sdio_command(sd, 2, 0); if (! err) { res->cid[0] = SDIO_RESP1(sd->base); res->cid[1] = SDIO_RESP2(sd->base); res->cid[2] = SDIO_RESP3(sd->base); res->cid[3] = SDIO_RESP4(sd->base); err = stm32_sdio_command(sd, 3, 0); // get the RCA if (! err) { tmp_reg = SDIO_RESP1(sd->base); res->rca = (tmp_reg >> 16) & 0xffff; if (! res->rca) { /* * If the card says '0' tell it to pick * we assume this will work because the * previous send RCA worked and the card * should be in the ident state if it is * functioning correctly. */ (void) stm32_sdio_command(sd, 3, 0); // try again tmp_reg = SDIO_RESP1(sd->base); res->rca = (tmp_reg >> 16) & 0xffff; } err = stm32_sdio_command(sd, 9, res->rca << 16); if (! err) { res->csd[0] = SDIO_RESP1(sd->base); res->csd[1] = SDIO_RESP2(sd->base); res->csd[2] = SDIO_RESP3(sd->base); res->csd[3] = SDIO_RESP4(sd->base); err = sdio_scr(sd, res); // Capture the SCR if (! err) { /* All SD Cards support 4 bit bus and 24Mhz */ err = sdio_select(sd, res->rca); if (! err) { err = stm32_sdio_command(sd, 55, res->rca << 16); if (! err) { err = stm32_sdio_command(sd, 6, 2); if (! err) { //XXX stm32_sdio_bus(4, SDIO_24MHZ); //Seems we have speed issues for now... stm32_sdio_bus(sd, 4, SDIO_12MHZ); (void) sdio_select(sd, 0); } } } } } } } } } } /* Compute the size of the card based on fields in the CSD * block. There are two kinds, V1 or V2. * In the V1 Case : * Size = 1<size = 0; switch (SDIO_CSD_VERSION(res)) { case 0: tmp_reg = ((1 << (SDIO_CSD1_CSIZE_MULT(res) + 2)) * ( 1 << SDIO_CSD1_RBLKLEN(res))) >> 9; res->size = tmp_reg * (SDIO_CSD1_CSIZE(res) + 1); break; case 1: res->size = (SDIO_CSD2_CSIZE(res)+1) << 10; break; default: res->size = 0; // Bug if its not CSD V1 or V2 } } if (err) kprintf("[SDIO] %s\n", stm32_sdio_errmsg(err)); return (err == 0) ? res : NULL; } static void stm32_sdio_card_detect(void *arg) { struct dev_sd *sd = DEV_SD[0]; struct fnode *dev = arg; sd->card = stm32_sdio_open(DEV_SD[0]); if (!sd->card) { return; } kprintf("Found SD card in microSD slot.\r\n"); } /* * Set up the GPIO pins and peripheral clocks for the SDIO * system. The code should probably take an option card detect * pin, at the moment it uses the one used by the Embest board. */ static void sdio_hw_init(struct sdio_config *conf) { /* Enable clocks for SDIO and DMA2 */ gpio_create(&mod_sdio, &conf->pio_dat0); gpio_create(&mod_sdio, &conf->pio_dat1); gpio_create(&mod_sdio, &conf->pio_dat2); gpio_create(&mod_sdio, &conf->pio_dat3); gpio_create(&mod_sdio, &conf->pio_clk); gpio_create(&mod_sdio, &conf->pio_cmd); if (conf->card_detect_supported) gpio_create(&mod_sdio, &conf->pio_cd); rcc_peripheral_enable_clock(conf->rcc_reg, conf->rcc_en); } int sdio_init(struct sdio_config *conf) { SDIO_CARD card; struct fnode *devfs; /* Initialize sdio RCC and pins */ sdio_hw_init(conf); devfs = fno_search("/dev"); if (!devfs) return -ENOENT; struct dev_sd *sd; sd = kalloc(sizeof(struct dev_sd)); if (!sd) return -ENOMEM; char name[4] = "sd0"; memset(sd, 0, sizeof (struct dev_sd)); sd->base = conf->base; sd->rcc_rst_reg = conf->rcc_rst_reg; sd->rcc_rst = conf->rcc_rst; sd->dev = device_fno_init(&mod_sdio, name, devfs, FL_BLK, sd); DEV_SD[conf->devidx] = sd; memset(&mod_sdio, 0, sizeof(mod_sdio)); kprintf("Successfully initialized SDIO module.\r\n"); strcpy(mod_sdio.name,"sdio"); //mod_sdio.ops.close = sdio_close; mod_sdio.ops.block_read = sdio_block_read; mod_sdio.ops.block_write = sdio_block_write; register_module(&mod_sdio); tasklet_add(stm32_sdio_card_detect, devfs); return 0; } ================================================ FILE: kernel/drivers/stm32_sdio.h ================================================ #include "frosted.h" /* this define lets the init code know that you are using a GPIO as a card * detect pin */ #define SDIO_HAS_CARD_DETECT enum SDIO_CLOCK_DIV { SDIO_24MHZ = 0, SDIO_16MHZ, SDIO_12MHZ, SDIO_8MHZ, SDIO_4MHZ, SDIO_1MHZ, SDIO_400KHZ }; enum SDIO_POWER_STATE { SDIO_POWER_ON, SDIO_POWER_OFF }; #define SDIO_CARD_CCS(c) (((c)->ocr & 0x40000000) != 0) #define SDIO_CARD_UHS2(c) (((c)->ocr & 0x40000000) != 0) #define SDIO_CARD_LVOK(c) (((c)->ocr & 0x01000000) != 0) typedef struct SDIO_CARD_DATA { uint32_t props; uint32_t ocr; uint32_t cid[4]; uint32_t csd[4]; uint32_t scr[2]; uint32_t status[16]; uint32_t size; uint16_t rca; } * SDIO_CARD; struct dev_sd { struct device *dev; uint32_t base; uint32_t *rcc_rst_reg; uint32_t rcc_rst; SDIO_CARD card; }; int stm32_sdio_bus(struct dev_sd *sd, int bits, enum SDIO_CLOCK_DIV freq); int stm32_sdio_init(void); void stm32_sdio_reset(struct dev_sd *sd, enum SDIO_POWER_STATE state); SDIO_CARD stm32_sdio_open(struct dev_sd *sd); int stm32_sdio_command(struct dev_sd *sd, uint32_t cmd, uint32_t arg); int stm32_sdio_readblock(SDIO_CARD, uint32_t lba, uint8_t *buf); int stm32_sdio_writeblock(SDIO_CARD, uint32_t lba, uint8_t *buf); //int stm32_sdio_status(SDIO_CARD); void stm32_sdio_print_log(int console, int number_of_entries); const char *stm32_sdio_errmsg(int err); uint32_t stm32_sdio_bit_slice(uint32_t a[], int bits, int msb, int lsb); /* API for sd_bus clock setting */ enum SD_CLOCK_DIV { CLOCK_24MHZ = 0, CLOCK_16MHZ, CLOCK_12MHZ, CLOCK_8MHZ, CLOCK_4MHZ, CLOCK_1MHZ, CLOCK_400KHZ }; //int stm32_sd_bus(int bits, enum SD_CLOCK_DIV freq); ================================================ FILE: kernel/drivers/stm32_spi.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include #include #include "unicore-mx/stm32/spi.h" #include #include #include "device.h" #include #include "cirbuf.h" #include "dma.h" #include "spi.h" #include "locks.h" /* Dummy module, for gpio claiming only. */ static struct module mod_spi = { .family = FAMILY_DEV, .name = "spi" }; struct dev_spi { struct device * dev; uint32_t base; uint32_t irq; void (*isr)(struct spi_slave *sl); struct spi_slave *sl; const struct dma_config * tx_dma_config; const struct dma_config * rx_dma_config; mutex_t *mutex; }; #define MAX_SPIS 4 static struct dev_spi *DEV_SPI[MAX_SPIS] = { }; static void spi_rx_dma_complete(struct spi_slave * sl) { struct dev_spi *spi; if (!sl) return; spi = DEV_SPI[sl->bus]; if (!spi) return; if (spi->isr) spi->isr(sl); } #ifdef CONFIG_SPI_1 void spi_isr(void) { } void dma2_stream2_isr() { dma_clear_interrupt_flags(DMA1, DMA_STREAM0, DMA_LISR_TCIF0); spi_rx_dma_complete(DEV_SPI[1]->sl); spi_disable(DEV_SPI[1]->base); mutex_unlock(DEV_SPI[1]->mutex); } void dma2_stream3_isr() { dma_clear_interrupt_flags(DMA1, DMA_STREAM6, DMA_LISR_TCIF0); } #endif int devspi_xfer(struct spi_slave *sl, const char *obuf, char *ibuf, unsigned int len) { struct dev_spi *spi; int i; if (len <= 0) return len; spi = DEV_SPI[sl->bus]; if (!spi) return -EINVAL; mutex_lock(spi->mutex); spi_reset(spi->base); spi->sl = sl; //init_dma(spi->tx_dma_config, (uint32_t)obuf, len); //init_dma(spi->rx_dma_config, (uint32_t)ibuf, len); //dma_enable_transfer_complete_interrupt(spi->rx_dma_config->base, spi->rx_dma_config->stream); //nvic_set_priority(spi->rx_dma_config->irq, 1); //nvic_enable_irq(spi->rx_dma_config->irq); spi_enable(spi->base); //spi_enable_rx_dma(spi->base); //spi_enable_tx_dma(spi->base); for(i = 0; i < len; i++) { spi_send(spi->base, (uint16_t)obuf[i]); } return len; } int devspi_create(const struct spi_config *conf) { struct dev_spi *spi = NULL; if (!conf) return -EINVAL; if (conf->base == 0) return -EINVAL; if ((conf->idx < 0) || (conf->idx > MAX_SPIS)) return -EINVAL; spi = kalloc(sizeof(struct dev_spi)); if (!spi) return -ENOMEM; /* Claim pins for SCK/MOSI/MISO */ gpio_create(&mod_spi, &conf->pio_sck); gpio_create(&mod_spi, &conf->pio_mosi); gpio_create(&mod_spi, &conf->pio_miso); /* Erase spi content */ memset(spi, 0, sizeof(struct dev_spi)); /* Enable clocks */ rcc_periph_clock_enable(conf->rcc); rcc_periph_clock_enable(conf->dma_rcc); /* Startup routine */ //spi_disable(conf->base); /**********************************/ /* reset SPI1 */ spi_reset(conf->base); /* init SPI1 master */ spi_init_master(conf->base, SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); /* enable SPI1 first */ spi_enable(conf->base); /**********************************/ #if 0 spi_set_master_mode(conf->base); spi_set_baudrate_prescaler(conf->base, SPI_CR1_BR_FPCLK_DIV_256); /* TODO: Calculate prescaler from baudrate */ if(conf->polarity == 0) spi_set_clock_polarity_0(conf->base); else spi_set_clock_polarity_1(conf->base); if(conf->phase == 0) spi_set_clock_phase_0(conf->base); else spi_set_clock_phase_1(conf->base); if(conf->rx_only == 0) spi_set_full_duplex_mode(conf->base); else spi_set_receive_only_mode(conf->base); if(conf->bidir_mode == 0) spi_set_unidirectional_mode(conf->base); else spi_set_bidirectional_mode(conf->base); if(conf->dff_16) spi_set_dff_16bit(conf->base); else spi_set_dff_8bit(conf->base); if(conf->enable_software_slave_management) spi_enable_software_slave_management(conf->base); else spi_disable_software_slave_management(conf->base); if(conf->send_msb_first) spi_send_msb_first(conf->base); else spi_send_lsb_first(conf->base); spi_set_nss_high(conf->base); #endif /* Set up device struct */ spi->base = conf->base; spi->irq = conf->irq; //spi->tx_dma_config = &conf->tx_dma; //spi->rx_dma_config = &conf->rx_dma; spi->mutex = mutex_init(); /* Store address in the DEV_SPI array. */ DEV_SPI[conf->idx] = spi; /* Enable interrupts */ //nvic_set_priority(conf->irq, 1); //nvic_enable_irq(conf->irq); return 0; } ================================================ FILE: kernel/drivers/stm32_usb.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include "usb.h" #include "gpio.h" #include "usb/usbh_drivers.h" #include #include #include #include #include #include #include static struct module mod_usb_guest = { .family = FAMILY_DEV, .name = "usb-otg-guest", }; static struct module mod_usb_host = { .family = FAMILY_DEV, .name = "usb-otg-host", }; /* Device: High-speed backend config */ static const usbd_backend_config hs_dev_backend_config = { .ep_count = 9, .priv_mem = 4096, .speed = USBH_SPEED_HIGH, .feature = USBH_PHY_EXT }; /* Host: High-speed backend config */ static const usbh_backend_config hs_host_backend_config = { .chan_count = 12, .priv_mem = 4096, .speed = USBH_SPEED_HIGH, /* VBUS_EXT = PHY IC drive VBUS */ .feature = USBH_PHY_EXT | USBH_VBUS_EXT }; static struct usbd_device *_usbd_dev = NULL; static usbh_host *_usbh_host = NULL; void otg_fs_isr(void) { if (_usbd_dev) usbd_poll(_usbd_dev, 0); } void otg_hs_isr(void) { if (_usbd_dev) usbd_poll(_usbd_dev, 0); } static void kthread_usbhost(void *arg) { (void)arg; volatile uint32_t last = jiffies; while(1) { if (last != jiffies) { usbh_poll(_usbh_host, (jiffies - last) * 1000); last = jiffies; } //kthread_yield(); } } int usbdev_start(usbd_device **usbd_dev, unsigned int dev, const struct usbd_info *info) { if (_usbd_dev) return -EBUSY; if (dev == USB_DEV_FS) { _usbd_dev = usbd_init(USBD_STM32_OTG_FS, NULL, info); nvic_enable_irq(NVIC_OTG_FS_IRQ); } else { _usbd_dev = usbd_init(USBD_STM32_OTG_HS, &hs_dev_backend_config, info); nvic_enable_irq(NVIC_OTG_HS_IRQ); } *usbd_dev = _usbd_dev; return 0; } #ifdef CONFIG_USBHOST struct usb_host_driver { struct module *owner; usb_host_driver_probe_callback probe; struct usb_host_driver *next; }; struct usb_host_claim { struct module *owner; /* Reason of call: * - Device disconnected * - Configuration change * - Interface released */ usb_host_interface_removed_callback removed; usbh_device *device; /* Interface number */ uint8_t bInterfaceNumber; struct usb_host_claim *next; }; static struct usb_host_driver *HOST_DRIVER_LIST = NULL; static struct usb_host_claim *HOST_CLAIM_LIST = NULL; int usb_host_driver_register(struct module *owner, usb_host_driver_probe_callback probe) { if (!probe) { return -EINVAL; } struct usb_host_driver *driver = kalloc(sizeof(struct usb_host_driver)); if (!driver) { return -ENOMEM; } driver->probe = probe; driver->next = HOST_DRIVER_LIST; HOST_DRIVER_LIST = driver; return 0; } /** * Check weather the interface has already been claimed * @param dev Device (USB Host) * @param bInterfaceNumber Interface number * @return true on claimed, false on still open for claiming */ bool interface_claimed(usbh_device *dev, uint8_t bInterfaceNumber) { const struct usb_host_claim *claim; for (claim = HOST_CLAIM_LIST; claim; claim = claim->next) { if (claim->device == dev && claim->bInterfaceNumber == bInterfaceNumber) { return true; } } return false; } /** * Claim the USB Host device interface. * @param owner Owner * @param dev USB Host device * @param bInterfaceNumber Interface number * @param removed Callback when removed. * @return 0 on success * @return -EBUSY Interface already claimed * @return -EINVAL Invalid value passed * @note Make sure @a bInterfaceNumber is a valid interface number * for the device and currently selected configuration. * @note Driver need to manually SET_INTEFACE */ int usb_host_claim_interface(struct module *owner, usbh_device *dev, uint8_t bInterfaceNumber, usb_host_interface_removed_callback removed) { if (!dev || !removed) { return -EINVAL; } if (interface_claimed(dev, bInterfaceNumber)) { return -EBUSY; } struct usb_host_claim *claim = kalloc(sizeof(struct usb_host_claim)); if (!claim) { return -ENOMEM; } claim->owner = owner; claim->removed = removed; claim->bInterfaceNumber = bInterfaceNumber; claim->next = HOST_CLAIM_LIST; HOST_CLAIM_LIST = claim; return 0; } /** * Release a previously claimed interface * @param dev USB Host - device * @param bInterfaceNumber Interface number * @return 0 success * @return -EINVAL Invalid argument * @return -ENOENT No such entry */ int usb_host_release_interface(usbh_device *dev, uint8_t bInterfaceNumber) { struct usb_host_claim *claim = HOST_CLAIM_LIST, *tmp, *prev = NULL; if (!dev) { return -EINVAL; } while (claim != NULL) { if (claim->device != dev) { prev = claim; claim = claim->next; continue; } /* Update link */ if (prev == NULL) { /* First item */ HOST_CLAIM_LIST = claim->next; } else { prev->next = claim->next; } /* Goto next entry */ tmp = claim; claim = claim->next; /* Remove the item */ tmp->removed(tmp->device, tmp->bInterfaceNumber); kfree(tmp); return 0; } return -ENOENT; } /** * USB Host - device disconnected. * Remove any claimed interface from the list for the given device * @param dev USB Host device */ static void host_dev_disconnected_callback(usbh_device *dev) { struct usb_host_claim *claim = HOST_CLAIM_LIST, *tmp, *prev = NULL; while (claim != NULL) { if (claim->device != dev) { prev = claim; claim = claim->next; continue; } /* Update link */ if (prev == NULL) { /* First item */ HOST_CLAIM_LIST = claim->next; } else { prev->next = claim->next; } /* Goto next entry */ tmp = claim; claim = claim->next; /* Remove the item */ tmp->removed(tmp->device, tmp->bInterfaceNumber); kfree(tmp); } } static uint8_t buf_dev_desc[18]; static uint8_t buf_config_desc[128]; static void host_set_config_callback(const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { (void) urb_id; const struct usb_host_driver *usb; const struct usb_device_descriptor *dev_desc = (void *) buf_dev_desc; const struct usb_config_descriptor *config_desc = (void *) buf_config_desc; if (status != USBH_SUCCESS) { return; } /* Let each driver probe the configuration descriptor and * react accordingly */ for (usb = HOST_DRIVER_LIST; usb; usb = usb->next) { usb->probe(transfer->device, dev_desc, config_desc); } } static void host_config_desc_read_callback(const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { (void) urb_id; const struct usb_config_descriptor *cfg = transfer->data; if (status != USBH_SUCCESS) { return; } if (!transfer->transferred || cfg->bLength < 4) { /* Descriptor too small */ return; } if (cfg->wTotalLength > transfer->transferred) { /* Descriptor too long to be read in one shot */ return; } /* The descriptor look good. SET_CONFIGURATION before probing */ usbh_ctrlreq_set_config(transfer->device, cfg->bConfigurationValue, host_set_config_callback); } static void host_dev_desc_read_callback(const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { const struct usb_device_descriptor *desc = transfer->data; (void) urb_id; if (status != USBH_SUCCESS) { return; } if (!desc->bNumConfigurations) { return; } /* Read the index=0 configuration descriptor */ usbh_ctrlreq_read_desc(transfer->device, USB_DT_CONFIGURATION, 0, buf_config_desc, sizeof(buf_config_desc), host_config_desc_read_callback); } static void host_dev_connected_callback(usbh_device *dev) { usbh_device_register_disconnected_callback(dev, host_dev_disconnected_callback); usbh_ctrlreq_read_desc(dev, USB_DT_DEVICE, 0, buf_dev_desc, sizeof(buf_dev_desc), host_dev_desc_read_callback); } static void usbhost_start(void) { if (_usbh_host) return ; #ifdef CONFIG_USBFSHOST _usbh_host = usbh_init(USBH_STM32_OTG_FS, NULL); usbh_register_connected_callback(_usbh_host, host_dev_connected_callback); nvic_enable_irq(NVIC_OTG_FS_IRQ); #else /* CONFIG_USBFSHOST */ _usbh_host = usbh_init(USBH_STM32_OTG_HS, &hs_host_backend_config); usbh_register_connected_callback(_usbh_host, host_dev_connected_callback); nvic_enable_irq(NVIC_OTG_HS_IRQ); #endif /* CONFIG_USBFSHOST */ usbh_drivers_init(); kthread_create(kthread_usbhost, NULL); } #endif /* CONFIG_USBHOST */ int usb_init(struct usb_config *conf) { struct module *mod = &mod_usb_guest; if (conf->otg_mode == USB_MODE_HOST) { mod = &mod_usb_host; if (conf->dev_type == USB_DEV_FS) { gpio_create(mod, &conf->pio.fs->pio_phy); gpio_clear(conf->pio.fs->pio_phy.base, conf->pio.fs->pio_phy.pin); } } if (conf->dev_type == USB_DEV_FS) { gpio_create(mod, &conf->pio.fs->pio_vbus); gpio_create(mod, &conf->pio.fs->pio_dm); gpio_create(mod, &conf->pio.fs->pio_dp); gpio_create(mod, &conf->pio.fs->pio_phy); } else if (conf->dev_type == USB_DEV_HS) { int i = 0; gpio_create(mod, &conf->pio.hs->ulpi_clk); for (i = 0; i < 8; i++) gpio_create(mod, &conf->pio.hs->ulpi_data[i]); gpio_create(mod, &conf->pio.hs->ulpi_step); gpio_create(mod, &conf->pio.hs->ulpi_dir); gpio_create(mod, &conf->pio.hs->ulpi_next); } else { return -1; } #ifdef CONFIG_USBHOST if (conf->otg_mode == USB_MODE_HOST) { usbhost_start(); } #endif return 0; } ================================================ FILE: kernel/drivers/stm32f4_adc.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include #include "ioctl.h" #include "dma.h" #include "adc.h" #ifdef STM32F4 #include #include #include #include # define CLOCK_ENABLE(C) rcc_periph_clock_enable(C); #endif struct dev_adc{ struct device * dev; uint32_t base; uint32_t irq; uint8_t channel_array[NUM_ADC_CHANNELS]; uint8_t num_channels; int conversion_done; uint16_t samples[NUM_ADC_CHANNELS]; const struct dma_config * dma_config; }; #define MAX_ADCS 1 static struct dev_adc DEV_ADC[MAX_ADCS]; static int devadc_read(struct fnode * fno, void *buf, unsigned int len); static struct module mod_devadc = { .family = FAMILY_FILE, .name = "adc", .ops.open = device_open, .ops.read = devadc_read, }; void dma2_stream0_isr() { struct dev_adc * adc = &DEV_ADC[0]; if((DMA2_LISR & DMA_LISR_TCIF0) != 0) { dma_clear_interrupt_flags(DMA2, DMA_STREAM0, DMA_LISR_TCIF0); adc_disable_dma(adc->base); adc->conversion_done = 1; if (adc->dev->task != NULL) task_resume(adc->dev->task); } } static int devadc_read(struct fnode *fno, void *buf, unsigned int len) { int i; struct dev_adc *adc; if (len <= 0) return len; adc = (struct dev_adc *)FNO_MOD_PRIV(fno, &mod_devadc); if (!adc) return -1; mutex_lock(adc->dev->mutex); if (adc->conversion_done == 0) { adc_enable_dma(adc->base); adc_start_conversion_regular(adc->base); adc->dev->task = this_task(); task_suspend(); mutex_unlock(adc->dev->mutex); return SYS_CALL_AGAIN; } if(len > (adc->num_channels * 2)) { len = adc->num_channels * 2; } memcpy(buf, adc->samples, len); adc->conversion_done = 0; mutex_unlock(adc->dev->mutex); return len; } static void adc_fno_init(struct fnode *dev, uint32_t n, const struct adc_config * addr) { struct dev_adc *a = &DEV_ADC[n]; char name[6] = "adc"; name[4] = '0' + (char)n; name[5] = '\0'; a->dev = device_fno_init(&mod_devadc, name, dev, FL_RDONLY, a); a->base = addr->base; memcpy(a->channel_array, addr->channel_array, NUM_ADC_CHANNELS); a->num_channels = addr->num_channels; a->conversion_done = 0; } void adc_init(const struct adc_config adc_configs[], int num_adcs) { int i; struct fnode *dev = fno_search("/dev"); if (!dev) return; for (i = 0; i < num_adcs; i++) { if (adc_configs[i].base == 0) continue; adc_fno_init(dev, i, &adc_configs[i]); CLOCK_ENABLE(adc_configs[i].rcc); CLOCK_ENABLE(adc_configs[i].dma_rcc); init_dma(&adc_configs[i].dma, (uint32_t) DEV_ADC[i].samples, adc_configs[i].num_channels); dma_enable_circular_mode(adc_configs[i].dma.base, adc_configs[i].dma.stream); dma_enable_transfer_complete_interrupt(adc_configs[i].dma.base, adc_configs[i].dma.stream); nvic_set_priority(adc_configs[i].dma.irq, 1); nvic_enable_irq(adc_configs[i].dma.irq); adc_set_resolution(adc_configs[i].dma.base, ADC_CR1_RES_12BIT); adc_power_off(adc_configs[i].base); adc_disable_external_trigger_regular(adc_configs[i].base); adc_set_sample_time_on_all_channels(adc_configs[i].base, ADC_SMPR_SMP_480CYC); adc_set_regular_sequence(adc_configs[i].base, adc_configs[i].num_channels, adc_configs[i].channel_array); adc_enable_scan_mode(adc_configs[i].base); adc_set_single_conversion_mode(adc_configs[i].base); adc_eoc_after_each(adc_configs[i].base); adc_set_dma_terminate(adc_configs[i].base); adc_set_right_aligned(adc_configs[i].base); adc_power_on(adc_configs[i].base); } } ================================================ FILE: kernel/drivers/stm32f4_dsp.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include #include "cirbuf.h" #include "dma.h" #include "cirbuf.h" #include #include #include #include #include #include #define DSP_BUFSIZ 512 #define DSP_IDLE 0 #define DSP_BUSY 1 /* Single device supported in this driver. */ struct dev_dsp { struct device *dev; volatile int written; int transfer_size; int chunk_size; int state; uint8_t *outb; } Dsp; /* Module description */ int dsp_read(struct fnode *fno, void *buf, unsigned int len); int dsp_write(struct fnode *fno, const void *buf, unsigned int len); static struct module mod_devdsp = { .family = FAMILY_FILE, .name = "dsp", .ops.open = device_open, .ops.write = dsp_write, .ops.read = dsp_read }; int dsp_read(struct fnode *fno, void *buf, unsigned int len) { /* ADC not attached yet */ return -EBUSY; } static void dsp_xmit(void) { uint32_t size = DSP_BUFSIZ; Dsp.state = DSP_BUSY; if ((Dsp.transfer_size - Dsp.written ) < size) size = Dsp.transfer_size - Dsp.written; Dsp.chunk_size = size; /* Start DMA transfer of waveform */ dac_trigger_enable(CHANNEL_1); dac_set_trigger_source(DAC_CR_TSEL1_T2); dac_dma_enable(CHANNEL_1); dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t) (Dsp.outb + Dsp.written)); dma_set_number_of_data(DMA1, DMA_STREAM5, size); dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5); dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_7); dma_enable_stream(DMA1, DMA_STREAM5); } int dsp_write(struct fnode *fno, const void *buf, unsigned int len) { struct dev_dsp *dsp; int space; dsp = (struct dev_dsp *)FNO_MOD_PRIV(fno, &mod_devdsp); if (dsp == NULL) return -1; mutex_lock(dsp->dev->mutex); if (!dsp->outb) { dsp->outb = kalloc(len); if (!dsp->outb) { return -ENOMEM; } dsp->written = 0; dsp->transfer_size = len; memcpy(dsp->outb, buf, len); dsp_xmit(); } if (dsp->written < len) { dsp->dev->task = this_task(); mutex_unlock(dsp->dev->mutex); task_suspend(); return SYS_CALL_AGAIN; } kfree(dsp->outb); dsp->outb = NULL; mutex_unlock(dsp->dev->mutex); return dsp->written; } /* IRQ Handler */ void dma1_stream5_isr(void) { if (dma_get_interrupt_flag(DMA1, DMA_STREAM5, DMA_TCIF)) { if (Dsp.written < Dsp.transfer_size) Dsp.written += Dsp.chunk_size; dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF); dma_disable_stream(DMA1, DMA_STREAM5); dac_trigger_disable(CHANNEL_1); dac_dma_disable(CHANNEL_1); if (Dsp.written >= Dsp.transfer_size) { if (Dsp.dev->task) task_resume(Dsp.dev->task); } else { dsp_xmit(); } } } /* Initialization functions */ #define PERIOD (5200) static void timer_setup(void) { /* Enable TIM2 clock. */ rcc_periph_clock_enable(RCC_TIM2); timer_reset(TIM2); /* Timer global mode: - No divider, Alignment edge, Direction up */ timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); timer_continuous_mode(TIM2); timer_set_period(TIM2, PERIOD); timer_disable_oc_output(TIM2, TIM_OC2 | TIM_OC3 | TIM_OC4); timer_enable_oc_output(TIM2, TIM_OC1); timer_disable_oc_clear(TIM2, TIM_OC1); timer_disable_oc_preload(TIM2, TIM_OC1); timer_set_oc_slow_mode(TIM2, TIM_OC1); timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_TOGGLE); timer_set_oc_value(TIM2, TIM_OC1, 500); timer_disable_preload(TIM2); /* Set the timer trigger output (for the DAC) to the channel 1 output * compare */ timer_set_master_mode(TIM2, TIM_CR2_MMS_COMPARE_OC1REF); timer_enable_counter(TIM2); } static void dsp_dma_setup(void) { /* DAC channel 1 uses DMA controller 1 Stream 5 Channel 7. */ /* Enable DMA1 clock and IRQ */ rcc_periph_clock_enable(RCC_DMA1); nvic_set_priority(NVIC_DMA1_STREAM5_IRQ, 1); nvic_enable_irq(NVIC_DMA1_STREAM5_IRQ); dma_stream_reset(DMA1, DMA_STREAM5); dma_set_priority(DMA1, DMA_STREAM5, DMA_SxCR_PL_LOW); dma_set_memory_size(DMA1, DMA_STREAM5, DMA_SxCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_STREAM5, DMA_SxCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_STREAM5); dma_enable_circular_mode(DMA1, DMA_STREAM5); dma_set_transfer_mode(DMA1, DMA_STREAM5, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); /* The register to target is the DAC1 8-bit right justified data register */ dma_set_peripheral_address(DMA1, DMA_STREAM5, (uint32_t) &DAC_DHR8R1); } static void dsp_hw_init(data_channel c) { /* Set DAC GPIO pin to analog mode */ rcc_periph_clock_enable(RCC_GPIOC); gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4); timer_setup(); /* Set up DAC */ rcc_periph_clock_enable(RCC_DAC); dac_enable(c); } int dsp_init(void) { int i; struct fnode *devdir = fno_search("/dev"); if (!devdir) return -ENOENT; memset(&Dsp, 0, sizeof(struct dev_dsp)); Dsp.dev = device_fno_init(&mod_devdsp, "dsp", devdir, 0, &Dsp); dsp_hw_init(CHANNEL_1); dsp_dma_setup(); return 0; } ================================================ FILE: kernel/drivers/stm32f4_sdram.c ================================================ /* * This file is part of the unicore-mx project. * * Copyright (C) 2014 Chuck McManis * Copyright (C) 2016 Maxime Vincent * * 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 . */ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * Maxime Vincent * Chuck McManis * Daniele Lacamera * * */ #include #include #include #include #include "frosted.h" #define SDRAM_BASE_ADDRESS ((uint8_t *)(0xD0000000)) /* * This is just syntactic sugar but it helps, all of these * GPIO pins get configured in exactly the same way. */ static struct { uint32_t gpio; uint16_t pins; } sdram_pins[6] = { {GPIOB, GPIO5 | GPIO6 }, {GPIOC, GPIO0 }, {GPIOD, GPIO0 | GPIO1 | GPIO8 | GPIO9 | GPIO10 | GPIO14 | GPIO15}, {GPIOE, GPIO0 | GPIO1 | GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15 }, {GPIOF, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15 }, {GPIOG, GPIO0 | GPIO1 | GPIO4 | GPIO5 | GPIO8 | GPIO15} }; static struct sdram_timing timing = { .trcd = 2, /* RCD Delay */ .trp = 2, /* RP Delay */ .twr = 2, /* Write Recovery Time */ .trc = 7, /* Row Cycle Delay */ .tras = 4, /* Self Refresh Time */ .txsr = 7, /* Exit Self Refresh Time */ .tmrd = 2, /* Load to Active Delay */ }; /* * Initialize the SD RAM controller. */ void sdram_init(void) { int i; uint32_t cr_tmp, tr_tmp; /* control, timing registers */ /* * First all the GPIO pins that end up as SDRAM pins */ rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); rcc_periph_clock_enable(RCC_GPIOD); rcc_periph_clock_enable(RCC_GPIOE); rcc_periph_clock_enable(RCC_GPIOF); rcc_periph_clock_enable(RCC_GPIOG); for (i = 0; i < 6; i++) { gpio_mode_setup(sdram_pins[i].gpio, GPIO_MODE_AF, GPIO_PUPD_NONE, sdram_pins[i].pins); gpio_set_output_options(sdram_pins[i].gpio, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, sdram_pins[i].pins); gpio_set_af(sdram_pins[i].gpio, GPIO_AF12, sdram_pins[i].pins); } /* Enable the SDRAM Controller */ #if 1 rcc_periph_clock_enable(RCC_FSMC); #else rcc_peripheral_enable_clock(&RCC_AHB3ENR, RCC_AHB3ENR_FMCEN); #endif /* Note the STM32F429-DISCO board has the ram attached to bank 2 */ /* Timing parameters computed for a 168Mhz clock */ /* These parameters are specific to the SDRAM chip on the board */ cr_tmp = FMC_SDCR_RPIPE_1CLK; cr_tmp |= FMC_SDCR_SDCLK_2HCLK; cr_tmp |= FMC_SDCR_CAS_3CYC; cr_tmp |= FMC_SDCR_NB4; cr_tmp |= FMC_SDCR_MWID_16b; cr_tmp |= FMC_SDCR_NR_12; cr_tmp |= FMC_SDCR_NC_8; /* We're programming BANK 2, but per the manual some of the parameters * only work in CR1 and TR1 so we pull those off and put them in the * right place. */ FMC_SDCR1 |= (cr_tmp & FMC_SDCR_DNC_MASK); FMC_SDCR2 = cr_tmp; tr_tmp = sdram_timing(&timing); FMC_SDTR1 |= (tr_tmp & FMC_SDTR_DNC_MASK); FMC_SDTR2 = tr_tmp; /* Now start up the Controller per the manual * - Clock config enable * - PALL state * - set auto refresh * - Load the Mode Register */ sdram_command(SDRAM_BANK2, SDRAM_CLK_CONF, 1, 0); //milli_sleep(1); /* sleep at least 100uS */ sdram_command(SDRAM_BANK2, SDRAM_PALL, 1, 0); sdram_command(SDRAM_BANK2, SDRAM_AUTO_REFRESH, 4, 0); tr_tmp = SDRAM_MODE_BURST_LENGTH_2 | SDRAM_MODE_BURST_TYPE_SEQUENTIAL | SDRAM_MODE_CAS_LATENCY_3 | SDRAM_MODE_OPERATING_MODE_STANDARD | SDRAM_MODE_WRITEBURST_MODE_SINGLE; sdram_command(SDRAM_BANK2, SDRAM_LOAD_MODE, 1, tr_tmp); /* * set the refresh counter to insure we kick off an * auto refresh often enough to prevent data loss. */ FMC_SDRTR = 683; /* and Poof! a 8 megabytes of ram shows up in the address space */ } ================================================ FILE: kernel/drivers/stm32f7_ltdc.c ================================================ /* Includes ------------------------------------------------------------------*/ #include #include "malloc.h" #include "framebuffer.h" #include #include #include #include "gpio.h" /* STM32F7-Discovery screen ... */ #define RK043FN48H_WIDTH ((uint16_t)480) /* LCD PIXEL WIDTH */ #define RK043FN48H_HEIGHT ((uint16_t)272) /* LCD PIXEL HEIGHT */ #define RK043FN48H_HSYNC ((uint16_t)41) /* Horizontal synchronization */ #define RK043FN48H_HBP ((uint16_t)13) /* Horizontal back porch */ #define RK043FN48H_HFP ((uint16_t)32) /* Horizontal front porch */ #define RK043FN48H_VSYNC ((uint16_t)10) /* Vertical synchronization */ #define RK043FN48H_VBP ((uint16_t)2) /* Vertical back porch */ #define RK043FN48H_VFP ((uint16_t)2) /* Vertical front porch */ #define RK043FN48H_FREQUENCY_DIVIDER 5 /* LCD Frequency divider */ #define FB_WIDTH RK043FN48H_WIDTH #define FB_HEIGTH RK043FN48H_HEIGHT //#define FB_BPP (16) /* hardcoded RGB565 - 16 bits per pixel */ #define FB_BPP (8) /* hardcoded CLUT256 - 8 bit per pixel */ /* Private function prototypes -----------------------------------------------*/ static void ltdc_config(void); static void ltdc_pinmux(void); static void ltdc_clock(void); static int ltdc_config_layer(struct fb_info *fb); static struct module mod_ltdc = { .family = FAMILY_FILE, .name = "lcd-controller", }; /* Private functions ---------------------------------------------------------*/ static void ltdc_destroy(struct fb_info *fb) { // TODO: disable framebuffer if (fb && fb->screen_buffer) f_free((void *)fb->screen_buffer); } static int ltdc_config_layer(struct fb_info *fb) { uint32_t format = 0; fb->var.xres = FB_WIDTH; fb->var.yres = FB_HEIGTH; fb->var.bits_per_pixel = FB_BPP; //fb->var.pixel_format = FB_PF_RGB565; fb->var.pixel_format = FB_PF_CMAP256; fb->var.smem_len = fb->var.xres * fb->var.yres * (fb->var.bits_per_pixel/8); fb->var.type = FB_TYPE_PIXELMAP; /* Allocate framebuffer memory */ fb->screen_buffer = u_malloc(fb->var.smem_len); if (!fb->screen_buffer) { return -1; } fb->var.smem_start = fb->screen_buffer; /* Windowing configuration */ ltdc_setup_windowing(LTDC_LAYER_2, fb->var.xres, fb->var.xres); /* Specifies the pixel format */ switch (fb->var.pixel_format) { case FB_PF_RGB565: format = LTDC_LxPFCR_RGB565; break; case FB_PF_CMAP256: format = LTDC_LxPFCR_L8; break; default: format = LTDC_LxPFCR_RGB565; break; } ltdc_set_pixel_format(LTDC_LAYER_2, format); /* Default color values */ ltdc_set_default_colors(LTDC_LAYER_2, 0, 0, 0, 0); /* Constant alpha */ ltdc_set_constant_alpha(LTDC_LAYER_2, 255); /* Blending factors */ ltdc_set_blending_factors(LTDC_LAYER_2, LTDC_LxBFCR_BF1_CONST_ALPHA, LTDC_LxBFCR_BF2_CONST_ALPHA); /* Framebuffer memory address */ ltdc_set_fbuffer_address(LTDC_LAYER_2, (uint32_t)fb->screen_buffer); /* Configures the color frame buffer pitch in byte */ ltdc_set_fb_line_length(LTDC_LAYER_2, fb->var.xres * (fb->var.bits_per_pixel/8), fb->var.xres * (fb->var.bits_per_pixel/8)); /* Configures the frame buffer line number */ ltdc_set_fb_line_count(LTDC_LAYER_2, fb->var.yres); /* Enable layer 1 */ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE); /* Sets the Reload type */ ltdc_reload(LTDC_SRCR_IMR); return 0; } /** * @brief LCD Configuration. * @note This function Configure tha LTDC peripheral : * 1) Configure the Pixel Clock for the LCD * 2) Configure the LTDC Timing and Polarity * 3) Configure the LTDC Layer 1 : * - The frame buffer is located at FLASH memory * - The Layer size configuration : 480x272 * @retval * None */ static void ltdc_config(void) { /* LTDC Initialization */ ltdc_ctrl_disable(LTDC_GCR_HSPOL_ACTIVE_HIGH); /* Active Low Horizontal Sync */ ltdc_ctrl_disable(LTDC_GCR_VSPOL_ACTIVE_HIGH); /* Active Low Vertical Sync */ ltdc_ctrl_disable(LTDC_GCR_DEPOL_ACTIVE_HIGH); /* Active Low Date Enable */ ltdc_ctrl_disable(LTDC_GCR_PCPOL_ACTIVE_HIGH); /* Active Low Pixel Clock */ /* Configure the LTDC */ ltdc_set_tft_sync_timings(RK043FN48H_HSYNC, RK043FN48H_VSYNC, RK043FN48H_HBP, RK043FN48H_VBP, RK043FN48H_WIDTH, RK043FN48H_HEIGHT, RK043FN48H_HFP, RK043FN48H_VFP); ltdc_set_background_color(0, 0, 0); ltdc_ctrl_enable(LTDC_GCR_LTDC_ENABLE); } static void ltdc_clock(void) { /* LCD clock configuration */ /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */ /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/5 = 38.4 Mhz */ /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_4 = 38.4/4 = 9.6Mhz */ /* Disable PLLSAI */ RCC_CR &= ~RCC_CR_PLLSAION; while((RCC_CR & (RCC_CR_PLLSAIRDY))) {}; /* N and R are needed, * P and Q are not needed for LTDC */ RCC_PLLSAICFGR &= ~RCC_PLLSAICFGR_PLLSAIN_MASK; RCC_PLLSAICFGR |= 192 << RCC_PLLSAICFGR_PLLSAIN_SHIFT; RCC_PLLSAICFGR &= ~RCC_PLLSAICFGR_PLLSAIR_MASK; RCC_PLLSAICFGR |= 5 << RCC_PLLSAICFGR_PLLSAIR_SHIFT; RCC_DCKCFGR1 &= ~RCC_DCKCFGR1_PLLSAIDIVR_MASK; RCC_DCKCFGR1 |= RCC_DCKCFGR1_PLLSAIDIVR_DIVR_4; /* Enable PLLSAI */ RCC_CR |= RCC_CR_PLLSAION; while(!(RCC_CR & (RCC_CR_PLLSAIRDY))) {}; } static int ltdc_blank(struct fb_info *fb) { uint32_t pixels = (fb->var.xres * fb->var.yres * (fb->var.bits_per_pixel/8)); memset((void *)fb->screen_buffer, 0x0, pixels); } static void ltdc_screen_on(void) { /* Assert display enable LCD_DISP pin */ gpio_set(GPIOI, GPIO12); /* Assert backlight LCD_BL_CTRL pin */ gpio_set(GPIOK, GPIO3); } void ltdc_enable_clut(void) { /* Disable LTDC color lookup table by setting CLUTEN bit */ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_CLUT_ENABLE); /* Sets the Reload type */ ltdc_reload(LTDC_SRCR_IMR); } /* Only L8 CLUTs supported for now */ void ltdc_config_clut(uint32_t *CLUT, uint32_t size) { uint32_t i = 0; for(i = 0; (i < size); i++) { /* Specifies the C-LUT address and RGB value */ LTDC_LxCLUTWR(LTDC_LAYER_2) = ((i << 24) | ((uint32_t)(*CLUT) & 0xFF) | ((uint32_t)(*CLUT) & 0xFF00) | ((uint32_t)(*CLUT) & 0xFF0000)); CLUT++; } } int ltdc_set_cmap(uint32_t *cmap, struct fb_info *info) { ltdc_config_clut(cmap, 256); ltdc_enable_clut(); return 0; } static int ltdc_open(struct fb_info *info) { /* init LCD */ } static const struct fb_ops ltdc_fbops = { .fb_open = ltdc_open, .fb_destroy = ltdc_destroy, .fb_blank = ltdc_blank, .fb_setcmap = ltdc_set_cmap}; static struct fb_info ltdc_info = { .fbops = (struct fb_ops *)<dc_fbops, }; static void lcd_pinmux(void) { int i; struct gpio_config g = { .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown = GPIO_PUPD_NONE }; /* Enable the LTDC Clock */ rcc_periph_clock_enable(RCC_LTDC); /* PE4 */ g.base = GPIOE; g.pin = GPIO4; g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); /* PG12 */ g.base = GPIOG; g.pin = GPIO12; g.af = GPIO_AF9; gpio_create(&mod_ltdc, &g); /* LTDC PI8:PI10*/ for (i = 8; i < 11; i++) { g.base = GPIOI; g.pin = (1 << i); g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); } /* LTDC PI14:PI15 */ for (i = 14; i < 16; i++) { g.base = GPIOI; g.pin = (1 << i); g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); } /* LTDC PJ0:PJ15 (excl. PJ12) */ for (i = 0; i < 16; i++) { if (i != 12) { g.base = GPIOJ; g.pin = (1 << i); g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); } } /* LTDC PK0:PK7 (excl. PK3) */ for (i = 0; i < 8; i++) { if (i != 3) { g.base = GPIOK; g.pin = (1 << i); g.af = GPIO_AF14; gpio_create(&mod_ltdc, &g); } } /* LCD_DISP control PI12 (output) */ g.base = GPIOI; g.pin = GPIO12; g.mode = GPIO_MODE_OUTPUT; g.name = "display"; gpio_create(NULL, &g); /* LCD_BL control PK3 (output) */ g.base = GPIOK; g.pin = GPIO3; g.mode = GPIO_MODE_OUTPUT; g.name = "backlight"; gpio_create(NULL, &g); ltdc_screen_on(); } /* DRIVER INIT */ void ltdc_init(void) { lcd_pinmux(); ltdc_clock(); ltdc_config(); /* Configure LCD : Only one layer is used */ ltdc_config_layer(<dc_info); register_framebuffer(<dc_info); register_module(&mod_ltdc); } ================================================ FILE: kernel/drivers/stm32f7_sdram.c ================================================ /* * This file is part of the unicore-mx project. * * Copyright (C) 2014 Chuck McManis * Copyright (C) 2016 Maxime Vincent * * 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 . */ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * Maxime Vincent * Chuck McManis * Daniele Lacamera * * */ #include #include #include #include #include "frosted.h" #define SDRAM_BASE_ADDRESS ((uint8_t *)(0xC0000000)) /* * This is just syntactic sugar but it helps, all of these * GPIO pins get configured in exactly the same way. */ static const struct { uint32_t gpio; uint16_t pins; } sdram_pins[6] = { {GPIOC, GPIO3 }, {GPIOD, GPIO0 | GPIO1 | GPIO3 | GPIO8 | GPIO9 | GPIO10 | GPIO14 | GPIO15}, {GPIOE, GPIO0 | GPIO1 | GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15 }, {GPIOF, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15 }, {GPIOG, GPIO0 | GPIO1 | GPIO4 | GPIO5 | GPIO8 | GPIO15}, {GPIOH, GPIO3 | GPIO5 } }; static struct sdram_timing timing = { .trcd = 2, /* RCD Delay */ .trp = 2, /* RP Delay */ .twr = 2, /* Write Recovery Time */ .trc = 7, /* Row Cycle Delay */ .tras = 4, /* Self Refresh Time */ .txsr = 7, /* Exit Self Refresh Time */ .tmrd = 2, /* Load to Active Delay */ }; /* * Initialize the SD RAM controller. */ void sdram_init(void) { int i, now; uint32_t cr_tmp, tr_tmp; /* control, timing registers */ /* * First all the GPIO pins that end up as SDRAM pins */ rcc_periph_clock_enable(RCC_GPIOC); rcc_periph_clock_enable(RCC_GPIOD); rcc_periph_clock_enable(RCC_GPIOE); rcc_periph_clock_enable(RCC_GPIOF); rcc_periph_clock_enable(RCC_GPIOG); rcc_periph_clock_enable(RCC_GPIOH); for (i = 0; i < 6; i++) { gpio_mode_setup(sdram_pins[i].gpio, GPIO_MODE_AF, GPIO_PUPD_NONE, sdram_pins[i].pins); gpio_set_output_options(sdram_pins[i].gpio, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, sdram_pins[i].pins); gpio_set_af(sdram_pins[i].gpio, GPIO_AF12, sdram_pins[i].pins); } /* Enable the SDRAM Controller */ #if 1 rcc_periph_clock_enable(RCC_FMC); #else rcc_peripheral_enable_clock(&RCC_AHB3ENR, RCC_AHB3ENR_FMCEN); #endif /* Note the STM32F746G-DISCO board has the ram attached to bank 1 */ /* Timing parameters computed for a ~200 MHz clock */ /* These parameters are specific to the SDRAM chip on the board */ cr_tmp = FMC_SDCR_RPIPE_NONE; cr_tmp |= FMC_SDCR_SDCLK_2HCLK; cr_tmp |= FMC_SDCR_CAS_2CYC; cr_tmp |= FMC_SDCR_NB4; cr_tmp |= FMC_SDCR_MWID_16b; cr_tmp |= FMC_SDCR_NR_12; cr_tmp |= FMC_SDCR_NC_8; /* We're programming BANK 1 * Per the manual some of the parameters only work in CR1 and TR1 * So when using BANK2: we need pull those off and put them in the right place. * FMC_SDCR1 |= (cr_tmp); // & FMC_SDCR_DNC_MASK); * FMC_SDCR2 = cr_tmp; */ FMC_SDCR1 = (cr_tmp); tr_tmp = sdram_timing(&timing); FMC_SDTR1 = (tr_tmp); /* Now start up the Controller per the manual * - Clock config enable * - PALL state * - set auto refresh * - Load the Mode Register */ sdram_command(SDRAM_BANK1, SDRAM_CLK_CONF, 1, 0); /* sleep at least 100uS */ now = jiffies; //while (now + 2 > jiffies) {}; sdram_command(SDRAM_BANK1, SDRAM_PALL, 1, 0); sdram_command(SDRAM_BANK1, SDRAM_AUTO_REFRESH, 8, 0); tr_tmp = SDRAM_MODE_BURST_LENGTH_1 | SDRAM_MODE_BURST_TYPE_SEQUENTIAL | SDRAM_MODE_CAS_LATENCY_2 | SDRAM_MODE_OPERATING_MODE_STANDARD | SDRAM_MODE_WRITEBURST_MODE_SINGLE; sdram_command(SDRAM_BANK1, SDRAM_LOAD_MODE, 1, tr_tmp); /* * set the refresh counter to insure we kick off an * auto refresh often enough to prevent data loss. */ FMC_SDRTR = ((uint32_t)0x0603); /* SDRAM refresh counter (100Mhz SD clock) */ /* and Poof! a 8 megabytes of ram shows up in the address space */ /* Disable write protection */ FMC_SDCR1 &= ~FMC_SDCR_WP_ENABLE; } ================================================ FILE: kernel/drivers/stmpe811.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: brabo * */ #include "frosted.h" #include "device.h" #include #include "ioctl.h" #include "stmpe811.h" #include "gpio.h" #include "exti.h" #include "dma.h" #include "i2c.h" #define STMPE811_I2C_ADDR 0x82 #define STMPE811_CHIP_ID 0x00 /* STMPE811 Device identification */ /* Registers */ #define STMPE811_CHIP_ID 0x00 /* STMPE811 Device identification */ #define STMPE811_ID_VER 0x02 /* STMPE811 Revision number */ #define STMPE811_SYS_CTRL1 0x03 /* Reset control */ #define STMPE811_SYS_CTRL2 0x04 /* Clock control */ #define STMPE811_SPI_CFG 0x08 /* SPI interface configuration */ #define STMPE811_INT_CTRL 0x09 /* Interrupt control register */ #define STMPE811_INT_EN 0x0A /* Interrupt enable register */ #define STMPE811_INT_STA 0x0B /* Interrupt status register */ #define STMPE811_GPIO_EN 0x0C /* GPIO interrupt enable register */ #define STMPE811_GPIO_INT_STA 0x0D /* GPIO interrupt status register */ #define STMPE811_ADC_INT_EN 0x0E /* ADC interrupt enable register */ #define STMPE811_ADC_INT_STA 0x0F /* ADC interface status register */ #define STMPE811_GPIO_SET_PIN 0x10 /* GPIO set pin register */ #define STMPE811_GPIO_CLR_PIN 0x11 /* GPIO clear pin register */ #define STMPE811_MP_STA 0x12 /* GPIO monitor pin state register */ #define STMPE811_GPIO_DIR 0x13 /* GPIO direction register */ #define STMPE811_GPIO_ED 0x14 /* GPIO edge detect register */ #define STMPE811_GPIO_RE 0x15 /* GPIO rising edge register */ #define STMPE811_GPIO_FE 0x16 /* GPIO falling edge register */ #define STMPE811_GPIO_AF 0x17 /* Alternate function register */ #define STMPE811_ADC_CTRL1 0x20 /* ADC control */ #define STMPE811_ADC_CTRL2 0x21 /* ADC control */ #define STMPE811_ADC_CAPT 0x22 /* To initiate ADC data acquisition */ #define STMPE811_ADC_DATA_CHO 0x30 /* ADC channel 0 */ #define STMPE811_ADC_DATA_CH1 0x32 /* ADC channel 1 */ #define STMPE811_ADC_DATA_CH2 0x34 /* ADC channel 2 */ #define STMPE811_ADC_DATA_CH3 0x36 /* ADC channel 3 */ #define STMPE811_ADC_DATA_CH4 0x38 /* ADC channel 4 */ #define STMPE811_ADC_DATA_CH5 0x3A /* ADC channel 5 */ #define STMPE811_ADC_DATA_CH6 0x3C /* ADC channel 6 */ #define STMPE811_ADC_DATA_CH7 0x3E /* ADC channel 7 */ #define STMPE811_TSC_CTRL 0x40 /* 4-wire tsc setup */ #define STMPE811_TSC_CFG 0x41 /* Tsc configuration */ #define STMPE811_WDW_TR_X 0x42 /* Window setup for top right X */ #define STMPE811_WDW_TR_Y 0x44 /* Window setup for top right Y */ #define STMPE811_WDW_BL_X 0x46 /* Window setup for bottom left X */ #define STMPE811_WDW_BL_Y 0x48 /* Window setup for bottom left Y */ #define STMPE811_FIFO_TH 0x4A /* FIFO level to generate interrupt */ #define STMPE811_FIFO_STA 0x4B /* Current status of FIFO */ #define STMPE811_FIFO_SIZE 0x4C /* Current filled level of FIFO */ #define STMPE811_TSC_DATA_X 0x4D /* Data port for tsc data access */ #define STMPE811_TSC_DATA_Y 0x4F /* Data port for tsc data access */ #define STMPE811_TSC_DATA_Z 0x51 /* Data port for tsc data access */ #define STMPE811_TSC_DATA_XYZ 0x52 /* Data port for tsc data access */ #define STMPE811_TSC_FRACTION_Z 0x56 /* Touchscreen controller FRACTION_Z */ #define STMPE811_TSC_DATA 0x57 /* Data port for tsc data access */ #define STMPE811_TSC_I_DRIVE 0x58 /* Touchscreen controller drivel */ #define STMPE811_TSC_SHIELD 0x59 /* Touchscreen controller shield */ #define STMPE811_TEMP_CTRL 0x60 /* Temperature sensor setup */ #define STMPE811_TEMP_DATA 0x61 /* Temperature data access port */ #define STMPE811_TEMP_TH 0x62 /* Threshold for temp controlled int */ #define STMPE811_SYS_CTRL2_ADC_OFF (1 << 0) #define STMPE811_SYS_CTRL2_TSC_OFF (1 << 1) #define STMPE811_SYS_CTRL2_GPIO_OFF (1 << 2) #define STMPE811_SYS_CTRL2_TS_OFF (1 << 3) #define STMPE811_TEMP_CTRL_EN (1 << 0) #define STMPE811_TEMP_CTRL_ACQ (1 << 1) #define STMPE811_TEMP_DATA_MSB_MASK 0x03 #define STMPE811_TSC_CTRL_EN (1 << 0) #define STMPE811_INT_EN_TOUCH_DET (1 << 0) #define STMPE811_INT_EN_FIFO_TH (1 << 1) #define STMPE811_INT_EN_FIFO_OFLOW (1 << 2) #define STMPE811_INT_EN_FIFO_FULL (1 << 3) #define STMPE811_INT_EN_FIFO_EMPTY (1 << 4) #define STMPE811_INT_EN_TEMP_SENS (1 << 5) #define STMPE811_INT_EN_ADC (1 << 6) #define STMPE811_INT_EN_GPIO (1 << 7) #define STMPE811_SYS_CTRL1_SOFT_RESET (1 << 1) #define STMPE811_FIFO_STA_TOUCH_DET (1 << 0) #define STMPE811_INT_CTRL_GLOBAL_INT (1 << 0) enum stmpe811_state { STMPE811_STATE_IDLE = 0, STMPE811_STATE_BUSY, STMPE811_STATE_TX_RDY, STMPE811_STATE_RX_RDY, STMPE811_STATE_RDY, STMPE811_STATE_RD, STMPE811_STATE_INIT, }; enum insta { STMPE811_INIT_1, STMPE811_INIT_2, STMPE811_INIT_3, STMPE811_INIT_4, STMPE811_INIT_5, STMPE811_INIT_6, STMPE811_INIT_7, STMPE811_INIT_8, STMPE811_INIT_9, STMPE811_INIT_10, STMPE811_INIT_11, STMPE811_INIT_12, STMPE811_INIT_13, STMPE811_INIT_14, STMPE811_INIT_15, STMPE811_INIT_16, STMPE811_INIT_17, STMPE811_INIT_18, STMPE811_INIT_19, STMPE811_INIT_20, STMPE811_INIT_21, STMPE811_INIT_22, STMPE811_INIT_23, STMPE811_INIT_24, STMPE811_INIT_25, STMPE811_INIT_26, STMPE811_INIT_27, STMPE811_INIT_28, STMPE811_INIT_29, STMPE811_INIT_30, STMPE811_INIT_31, STMPE811_INIT_32, STMPE811_INIT_33, STMPE811_INIT_34, STMPE811_INIT_35, STMPE811_INIT_36, STMPE811_INIT_37, STMPE811_INIT_38, STMPE811_INIT_39, STMPE811_INIT_40, STMPE811_INIT_41, STMPE811_INIT_42, STMPE811_INIT_43, STMPE811_INIT_44, STMPE811_INIT_45, STMPE811_INIT_46, STMPE811_INIT_47, STMPE811_INIT_48, STMPE811_INIT_49, STMPE811_INIT_50, STMPE811_INIT_51, STMPE811_INIT_52, STMPE811_INIT_53, STMPE811_INIT_54, STMPE811_INIT_55, STMPE811_INIT_56, STMPE811_INIT_57, }; struct dev_stmpe811 { struct i2c_slave i2c; /* As first argument, so isr callbacks will use this as arg */ struct device *dev; unsigned int flags; int eidx; enum stmpe811_state state; volatile uint16_t cnt; } TS; static int devstmpe811_read(struct fnode *fno, void *buf, unsigned int len); static int devstmpe811_close(struct fnode *fno); static int stmpe811_fno_init(struct dev_stmpe811 *s); static struct module mod_devstmpe811 = { .family = FAMILY_FILE, .name = "stmpe811", .ops.open = device_open, .ops.read = devstmpe811_read, .ops.close = devstmpe811_close, }; static uint8_t buffer; static void *sys_ctrl1_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; i2c_init_read(&stmpe811->i2c, STMPE811_SYS_CTRL1, &buffer, 1); } static void *set_softreset(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= STMPE811_SYS_CTRL1_SOFT_RESET; i2c_init_write(&stmpe811->i2c, STMPE811_SYS_CTRL1, &buffer, 1); } static void *unset_softreset(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer &= ~STMPE811_SYS_CTRL1_SOFT_RESET; i2c_init_write(&stmpe811->i2c, STMPE811_SYS_CTRL1, &buffer, 1); } static void *sys_ctrl2_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; i2c_init_read(&stmpe811->i2c, STMPE811_SYS_CTRL2, &buffer, 1); } static void *ts_off(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = STMPE811_SYS_CTRL2_TS_OFF; i2c_init_write(&stmpe811->i2c, STMPE811_SYS_CTRL2, &buffer, 1); } static void *gpio_off(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= STMPE811_SYS_CTRL2_GPIO_OFF; i2c_init_write(&stmpe811->i2c, STMPE811_SYS_CTRL2, &buffer, 1); } static void *int_en_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; i2c_init_read(&stmpe811->i2c, STMPE811_INT_EN, &buffer, 1); } static void *enable_fifo_oflow(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = STMPE811_INT_EN_FIFO_OFLOW; i2c_init_write(&stmpe811->i2c, STMPE811_INT_EN, &buffer, 1); } static void *enable_fifo_th(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= STMPE811_INT_EN_FIFO_TH; i2c_init_write(&stmpe811->i2c, STMPE811_INT_EN, &buffer, 1); } static void *enable_fifo_touch_det(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= STMPE811_INT_EN_TOUCH_DET; i2c_init_write(&stmpe811->i2c, STMPE811_INT_EN, &buffer, 1); } static void *adc_ctrl1_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_ADC_CTRL1, &buffer, 1); } static void *set_adc_sample(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; /* set to 80 cycles */ buffer |= 0x40; i2c_init_write(&stmpe811->i2c, STMPE811_ADC_CTRL1, &buffer, 1); } static void *set_adc_res(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; /* set adc resolution to 12(?) bit */ buffer |= 0x08; i2c_init_write(&stmpe811->i2c, STMPE811_ADC_CTRL1, &buffer, 1); } static void *adc_ctrl2_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_ADC_CTRL2, &buffer, 1); } static void *set_adc_freq(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; /* set adc clock speed to 3.25 MHz */ buffer |= 0x01; i2c_init_write(&stmpe811->i2c, STMPE811_ADC_CTRL2, &buffer, 1); } static void *gpio_af_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_GPIO_AF, &buffer, 1); } static void *set_gpio_af(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_write(&stmpe811->i2c, STMPE811_GPIO_AF, &buffer, 1); } static void *tsc_cfg_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_TSC_CFG, &buffer, 1); } static void *set_tsc(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x9A; i2c_init_write(&stmpe811->i2c, STMPE811_TSC_CFG, &buffer, 1); } static void *fifo_th_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_FIFO_TH, &buffer, 1); } static void *set_fifo_th(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x01; i2c_init_write(&stmpe811->i2c, STMPE811_FIFO_TH, &buffer, 1); } static void *fifo_sta_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_FIFO_STA, &buffer, 1); } static void *set_fifo_sta_touchdet(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= STMPE811_FIFO_STA_TOUCH_DET; i2c_init_write(&stmpe811->i2c, STMPE811_FIFO_STA, &buffer, 1); } static void *unset_fifo_sta_touchdet(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer &= ~STMPE811_FIFO_STA_TOUCH_DET; i2c_init_write(&stmpe811->i2c, STMPE811_FIFO_STA, &buffer, 1); } static void *tsc_fracz_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_TSC_FRACTION_Z, &buffer, 1); } static void *set_tsc_fracz(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= 0x07; i2c_init_write(&stmpe811->i2c, STMPE811_TSC_FRACTION_Z, &buffer, 1); } static void *tsc_idrive_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_TSC_I_DRIVE, &buffer, 1); } static void *set_tsc_idrive(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= 0x01; i2c_init_write(&stmpe811->i2c, STMPE811_TSC_I_DRIVE, &buffer, 1); } static void *tsc_on(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer &= ~STMPE811_SYS_CTRL2_TSC_OFF; i2c_init_write(&stmpe811->i2c, STMPE811_SYS_CTRL2, &buffer, 1); } static void *tsc_ctrl_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_TSC_CTRL, &buffer, 1); } static void *enable_tsc(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= STMPE811_TSC_CTRL_EN; i2c_init_write(&stmpe811->i2c, STMPE811_TSC_CTRL, &buffer, 1); } static void *int_sta_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_INT_STA, &buffer, 1); } static void *set_int_sta_tsc_en(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0xFF; i2c_init_write(&stmpe811->i2c, STMPE811_INT_STA, &buffer, 1); } static void *int_ctrl_r(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer = 0x00; i2c_init_read(&stmpe811->i2c, STMPE811_INT_CTRL, &buffer, 1); } static void *set_int_ctrl_global_en(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer |= STMPE811_INT_CTRL_GLOBAL_INT; i2c_init_write(&stmpe811->i2c, STMPE811_INT_CTRL, &buffer, 1); } static void *gpio_on(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; buffer &= ~STMPE811_SYS_CTRL2_GPIO_OFF; i2c_init_write(&stmpe811->i2c, STMPE811_SYS_CTRL2, &buffer, 1); } static void *init_end(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; i2c_init_read(&stmpe811->i2c, STMPE811_SYS_CTRL2, &buffer, 1); stmpe811_fno_init(stmpe811); register_module(&mod_devstmpe811); stmpe811->cnt = 0; stmpe811->state = STMPE811_STATE_IDLE; } struct ts_init { enum insta state; int (*init)(struct dev_stmpe811 *stmpe811); }; static const struct ts_init ts_init[] = { { STMPE811_INIT_1, sys_ctrl1_r }, { STMPE811_INIT_2, set_softreset }, { STMPE811_INIT_3, unset_softreset }, { STMPE811_INIT_4, sys_ctrl2_r }, { STMPE811_INIT_5, ts_off }, { STMPE811_INIT_6, gpio_off }, { STMPE811_INIT_7, sys_ctrl2_r }, { STMPE811_INIT_8, int_en_r }, { STMPE811_INIT_9, enable_fifo_oflow }, { STMPE811_INIT_10, enable_fifo_th }, { STMPE811_INIT_11, enable_fifo_touch_det }, { STMPE811_INIT_12, int_en_r }, { STMPE811_INIT_13, adc_ctrl1_r }, { STMPE811_INIT_14, set_adc_sample }, { STMPE811_INIT_15, set_adc_res }, { STMPE811_INIT_16, adc_ctrl1_r }, { STMPE811_INIT_17, adc_ctrl2_r }, { STMPE811_INIT_18, set_adc_freq }, { STMPE811_INIT_19, adc_ctrl2_r }, { STMPE811_INIT_20, gpio_af_r }, { STMPE811_INIT_21, set_gpio_af }, { STMPE811_INIT_22, gpio_af_r }, { STMPE811_INIT_23, tsc_cfg_r }, { STMPE811_INIT_24, set_tsc }, { STMPE811_INIT_25, tsc_cfg_r }, { STMPE811_INIT_26, fifo_th_r }, { STMPE811_INIT_27, set_fifo_th }, { STMPE811_INIT_28, fifo_th_r }, { STMPE811_INIT_29, fifo_sta_r }, { STMPE811_INIT_30, set_fifo_sta_touchdet }, { STMPE811_INIT_31, unset_fifo_sta_touchdet }, { STMPE811_INIT_32, fifo_sta_r }, { STMPE811_INIT_33, tsc_fracz_r }, { STMPE811_INIT_34, set_tsc_fracz }, { STMPE811_INIT_35, tsc_fracz_r }, { STMPE811_INIT_36, tsc_idrive_r }, { STMPE811_INIT_37, set_tsc_idrive }, { STMPE811_INIT_38, tsc_idrive_r }, { STMPE811_INIT_39, sys_ctrl2_r }, { STMPE811_INIT_40, tsc_on }, { STMPE811_INIT_41, sys_ctrl2_r }, { STMPE811_INIT_42, tsc_ctrl_r }, { STMPE811_INIT_43, enable_tsc }, { STMPE811_INIT_44, tsc_ctrl_r }, { STMPE811_INIT_45, int_sta_r }, { STMPE811_INIT_46, set_int_sta_tsc_en }, { STMPE811_INIT_47, int_sta_r }, { STMPE811_INIT_48, int_ctrl_r }, { STMPE811_INIT_49, set_int_ctrl_global_en }, { STMPE811_INIT_50, int_ctrl_r }, { STMPE811_INIT_51, sys_ctrl2_r }, { STMPE811_INIT_52, gpio_on }, { STMPE811_INIT_53, sys_ctrl2_r }, { STMPE811_INIT_54, init_end }, }; static uint32_t xy; static void *ts_read_touch(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; i2c_init_read(&stmpe811->i2c, STMPE811_TSC_CTRL, &buffer, 1); } static void *ts_read_x_0(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; if ((buffer & 0x80) == 0) { /* no touch, return 0xFFFFFFFF throuhg xy */ xy = 0xFFFFFFFF; exti_enable(stmpe811->eidx, 0); stmpe811->state = STMPE811_STATE_RDY; stmpe811->cnt = 0; if (stmpe811->dev->task) { task_resume(stmpe811->dev->task); } } else { i2c_init_read(&stmpe811->i2c, STMPE811_TSC_DATA_X, &buffer, 1); } } static void *ts_read_x_1(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; xy = buffer; i2c_init_read(&stmpe811->i2c, (STMPE811_TSC_DATA_X + 1), &buffer, 1); } static void *ts_read_y_0(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; xy |= (buffer << 8); i2c_init_read(&stmpe811->i2c, STMPE811_TSC_DATA_Y, &buffer, 1); } static void *ts_read_y_1(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; xy |= (buffer << 16); i2c_init_read(&stmpe811->i2c, (STMPE811_TSC_DATA_Y + 1), &buffer, 1); } static void *ts_read_end(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; xy |= (buffer << 24); exti_enable(stmpe811->eidx, 0); stmpe811->state = STMPE811_STATE_RDY; if (stmpe811->dev->task> 0) { task_resume(stmpe811->dev->task); } } enum ts_read_state { TS_READ_TOUCH, TS_READ_X_0, TS_READ_X_1, TS_READ_Y_0, TS_READ_Y_1, }; struct ts_read { enum ts_read_state state; int (*call)(struct dev_stmpe811 *stmpe811); }; static const struct ts_read ts_read[] = { { TS_READ_X_0, ts_read_x_0 }, { TS_READ_X_0, ts_read_x_0 }, { TS_READ_X_1, ts_read_x_1 }, { TS_READ_Y_0, ts_read_y_0 }, { TS_READ_Y_1, ts_read_y_1 }, }; /* I2C operation callbacks, executed in IRQ context, and with I2C mutex held. */ static void stmpe811_tx_isr(struct i2c_slave *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; if (stmpe811->state == STMPE811_STATE_INIT) { void (*next_f)(void *) = ts_init[stmpe811->cnt++].init; tasklet_add(next_f, stmpe811); } } static void stmpe811_rx_isr(struct i2c_slave *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; if (stmpe811->state == STMPE811_STATE_INIT) { void (*next_f)(void *) = ts_init[stmpe811->cnt++].init; tasklet_add(next_f, stmpe811); } if (stmpe811->state == STMPE811_STATE_RD) { void (*next_f)(void *) = ts_read[stmpe811->cnt++].call; tasklet_add(next_f, stmpe811); } } static void ts_isr(void *arg) { struct dev_stmpe811 *stmpe811 = (struct dev_stmpe811 *)arg; stmpe811->state = STMPE811_STATE_BUSY; i2c_init_read(&stmpe811->i2c, STMPE811_TSC_DATA_X, &buffer, 1); } static int devstmpe811_read(struct fnode *fno, void *buf, unsigned int len) { struct dev_stmpe811 *stmpe811; if (len == 0) return len; if (len != 4) return -EINVAL; stmpe811 = (struct dev_stmpe811 *)FNO_MOD_PRIV(fno, &mod_devstmpe811); if (!stmpe811) return EINVAL; if (stmpe811->state == STMPE811_STATE_IDLE) { if ((stmpe811->dev->task) && (stmpe811->dev->task != this_task())) { return -EBUSY; } stmpe811->dev->task = this_task(); task_suspend(); exti_enable(stmpe811->eidx, 1); return SYS_CALL_AGAIN; } else if (stmpe811->state == STMPE811_STATE_RDY) { memcpy(buf, &xy, 4); stmpe811->dev->task = 0; stmpe811->state = STMPE811_STATE_IDLE; return sizeof(uint32_t); } } static int devstmpe811_close(struct fnode *fno) { return 0; } static int stmpe811_fno_init(struct dev_stmpe811 *s) { static int num_ts = 0; char name[4] = "ts"; struct fnode *devfs = fno_search("/dev"); if (!devfs) return -ENOENT; name[2] = '0' + num_ts++; s->dev = device_fno_init(&mod_devstmpe811, name, devfs, FL_RDONLY, s); s->dev->task = NULL; return 0; } int stmpe811_init(struct ts_config *ts) { struct dev_stmpe811 *stmpe811; stmpe811 = &TS; memset(stmpe811, 0, sizeof(struct dev_stmpe811)); gpio_create(&mod_devstmpe811, &ts->gpio); stmpe811->eidx = exti_register(ts->gpio.base, ts->gpio.pin, GPIO_TRIGGER_RAISE, ts_isr, &ts->gpio); /* Populate i2c_slave struct */ stmpe811->i2c.bus = ts->bus; stmpe811->i2c.address = STMPE811_I2C_ADDR; stmpe811->i2c.isr_tx = stmpe811_tx_isr; stmpe811->i2c.isr_rx = stmpe811_rx_isr; stmpe811->state = STMPE811_STATE_INIT; stmpe811->cnt = 0; i2c_init_read(&stmpe811->i2c, (STMPE811_CHIP_ID + 1), &buffer, 1); return 0; } ================================================ FILE: kernel/drivers/stmpe811.h ================================================ #ifndef INC_STMPE811 #define INC_STMPE811 #include "gpio.h" struct ts_config { struct gpio_config gpio; uint8_t bus; }; int stmpe811_init(struct ts_config *ts); #endif ================================================ FILE: kernel/drivers/tty_console.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include #include "framebuffer.h" #define KBD_PATH "/dev/kbd0" #define FBCON_PATH "/dev/fbcon" #define KBD_MOD "usbkbd" #define FBCON_MOD "fbcon" static struct tty_console { struct device *dev; struct fnode *kbd; struct fnode *fbcon; struct module *mod_kbd; struct module *mod_fbcon; uint16_t pid; } TTY; static int tty_read(struct fnode *fno, void *buf, unsigned int len); static int tty_poll(struct fnode *fno, uint16_t events, uint16_t *revents); static int tty_write(struct fnode *fno, const void *buf, unsigned int len); static int tty_seek(struct fnode *fno, int off, int whence); static void tty_attach(struct fnode *fno, int pid); static struct module mod_ttycon = { .family = FAMILY_DEV, .name = "tty", .ops.open = device_open, .ops.read = tty_read, .ops.poll = tty_poll, .ops.write = tty_write, .ops.seek = tty_seek, .ops.tty_attach = tty_attach }; static void devfile_create(void) { char name[5] = "tty"; struct fnode *devfs = fno_search("/dev"); if (!devfs) return; TTY.dev = device_fno_init(&mod_ttycon, name, devfs, FL_TTY, &TTY); } int tty_console_init(void) { TTY.mod_kbd = module_search(KBD_MOD); TTY.mod_fbcon = module_search(FBCON_MOD); if(!TTY.mod_kbd || !TTY.mod_fbcon) return -1; TTY.kbd = fno_search(KBD_PATH); TTY.fbcon = fno_search(FBCON_PATH); devfile_create(); return 0; } static void tty_send_break(void *arg) { int *pid = (int *)(arg); if (pid) task_kill(*pid, 2); } static int tty_read(struct fnode *fno, void *buf, unsigned int len) { int ret, i; if (!TTY.kbd) TTY.kbd = fno_search(KBD_PATH); if (!TTY.kbd) return 0; ret = TTY.mod_kbd->ops.read(TTY.kbd, buf, len); if (TTY.pid > 1) { for (i = 0; i < ret; i++) { if (((uint8_t *)buf)[i] == 0x03) /* Ctrl + c*/ tasklet_add(tty_send_break, &TTY.pid); } } return ret; } static int tty_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { if (!TTY.kbd) TTY.kbd = fno_search(KBD_PATH); if (!TTY.kbd) return 0; return TTY.mod_kbd->ops.poll(TTY.kbd, events, revents); } static int tty_write(struct fnode *fno, const void *buf, unsigned int len) { if (!TTY.fbcon) TTY.fbcon = fno_search(FBCON_PATH); return TTY.mod_fbcon->ops.write(TTY.fbcon, buf, len); } static int tty_seek(struct fnode *fno, int off, int whence) { if (!TTY.fbcon) TTY.fbcon = fno_search(FBCON_PATH); if (!TTY.fbcon) return -ENOENT; return TTY.mod_fbcon->ops.seek(TTY.fbcon, off, whence); } static void tty_attach(struct fnode *fno, int pid) { if (!TTY.fbcon) TTY.fbcon = fno_search(FBCON_PATH); if (!TTY.fbcon) return; TTY.mod_fbcon->ops.tty_attach(TTY.fbcon, pid); TTY.pid = pid; } ================================================ FILE: kernel/drivers/tty_console.h ================================================ #ifndef INC_TTY_CONSOLE #define INC_TTY_CONSOLE #include "frosted.h" #ifdef CONFIG_DEVTTY_CONSOLE int tty_console_init(void); #else #define tty_console_init() (-ENOENT) #endif #endif ================================================ FILE: kernel/drivers/uart.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "device.h" #include "cirbuf.h" #include #include "uart_dev.h" #include "uart.h" #include "poll.h" #include "unicore-mx/cm3/nvic.h" #ifdef LM3S # include "unicore-mx/lm3s/usart.h" # define CLOCK_ENABLE(C) # define USART_SR_RXNE USART_IC_RX # define USART_SR_TXE USART_IC_TX static inline uint32_t get_interrupt_source(uint32_t base) { return USART_RIS(base); } #endif #ifdef STM32F4 # include "unicore-mx/stm32/usart.h" # include "unicore-mx/stm32/rcc.h" # define CLOCK_ENABLE(C) rcc_periph_clock_enable(C); # define usart_clear_rx_interrupt(x) do{}while(0) # define usart_clear_tx_interrupt(x) do{}while(0) static inline uint32_t get_interrupt_source(uint32_t base) { return USART_SR(base); } #endif #ifdef STM32F7 # include "unicore-mx/stm32/usart.h" # include "unicore-mx/stm32/rcc.h" # define CLOCK_ENABLE(C) rcc_periph_clock_enable(C); static inline uint32_t get_interrupt_source(uint32_t base) { uint32_t flag_set = USART_ISR(base); uint32_t ret =0; if (flag_set & USART_ISR_TXE) ret |= USART_SR_TXE; if ((flag_set != 0) && USART_ISR_RXNE) ret |= USART_SR_RXNE; return ret; } #endif #ifdef LPC17XX # include "unicore-mx/lpc17xx/uart.h" # include "unicore-mx/lpc17xx/pwr.h" # define CLOCK_ENABLE(C) pwr_enable_peripherals(C) static inline uint32_t get_interrupt_source(uint32_t base) { return UART_IIR(base); } #endif #if defined(NRF51) || defined(NRF52) # include "unicore-mx/nrf/uart.h" # define CLOCK_ENABLE(C) do{} while(0) # define usart_enable uart_enable # define usart_set_baudrate uart_set_baudrate # define usart_set_databits(x, y) do {} while(0) # define usart_set_stopbits(x, y) do {} while(0) # define usart_set_parity uart_set_parity # define usart_set_flow_control uart_set_flow_control # define usart_set_mode(x, y) do {} while(0) # define usart_enable_rx_interrupt(x) do { \ uart_enable_interrupts(x, UART_INTEN_RXDRDY); \ uart_start_rx(x); \ } while(0) # define usart_disable_rx_interrupt(x) do { \ uart_disable_interrupts(x, UART_INTEN_RXDRDY); \ uart_stop_rx(x); \ } while(0) # define usart_enable_tx_interrupt(x) do { \ uart_enable_interrupts(x, UART_INTEN_TXDRDY); \ uart_start_tx(x); \ } while(0) # define usart_disable_tx_interrupt(x) do { \ uart_disable_interrupts(x, UART_INTEN_TXDRDY); \ uart_stop_tx(x); \ } while(0) # define usart_clear_tx_interrupt(x) uart_clear_events(UART_EVENT_TXDRDY(x)) # define usart_clear_rx_interrupt(x) uart_clear_events(UART_EVENT_RXDRDY(x)) # define usart_is_send_ready(x) UART_EVENT_CTS(x) # define usart_is_recv_ready(x) 1 # define usart_send uart_send # define usart_recv uart_recv # define USART_SR_RXNE 1 # define USART_SR_TXE 2 static inline uint32_t get_interrupt_source(uint32_t base) { if(UART_EVENT_TXDRDY(base)) return USART_SR_TXE; if(UART_EVENT_RXDRDY(base)) return USART_SR_RXNE; } #endif struct dev_uart { struct device * dev; uint32_t base; struct cirbuf *inbuf; struct cirbuf *outbuf; uint16_t sid; uint8_t *w_start; uint8_t *w_end; }; #define MAX_UARTS 8 static struct dev_uart *DEV_UART[MAX_UARTS] = { }; static int devuart_write(struct fnode *fno, const void *buf, unsigned int len); static int devuart_read(struct fnode *fno, void *buf, unsigned int len); static int devuart_poll(struct fnode *fno, uint16_t events, uint16_t *revents); static void devuart_tty_attach(struct fnode *fno, int pid); static struct module mod_devuart = { .family = FAMILY_FILE, .name = "uart", .ops.open = device_open, .ops.read = devuart_read, .ops.poll = devuart_poll, .ops.write = devuart_write, .ops.tty_attach = devuart_tty_attach, }; static void uart_send_break(void *arg) { int *pid = (int *)(arg); if (pid) task_kill(*pid, 2); } static void devuart_tty_attach(struct fnode *fno, int pid) { struct dev_uart *uart = (struct dev_uart *)FNO_MOD_PRIV(fno, &mod_devuart); if (uart->sid != pid) { //kprintf("/dev/%s active job pid: %d\r\n", fno->fname, pid); uart->sid = pid; } } void uart_isr(struct dev_uart *uart) { uint32_t req; if (!uart) return; req = get_interrupt_source(uart->base); /* TX interrupt */ if (req & USART_SR_TXE) { usart_clear_tx_interrupt(uart->base); // if (this_task() != NULL) /* cannot spinlock in ISR! */ // mutex_lock(uart->dev->mutex); /* Are there bytes left to be written? */ if (cirbuf_bytesinuse(uart->outbuf)) { uint8_t outbyte; cirbuf_readbyte(uart->outbuf, &outbyte); usart_send(uart->base, (uint16_t)(outbyte)); } else { usart_disable_tx_interrupt(uart->base); /* If a process is attached, resume the process */ if (uart->dev->task != NULL) task_resume(uart->dev->task); } // mutex_unlock(uart->dev->mutex); } /* RX interrupt */ if (req & USART_SR_RXNE) { usart_clear_rx_interrupt(uart->base); /* if data available */ if (usart_is_recv_ready(uart->base)) { char byte = (char)(usart_recv(uart->base) & 0xFF); /* Intercept ^C */ if (byte == 3) { if (uart->sid > 1) { tasklet_add(uart_send_break, &uart->sid); } return; } /* read data into circular buffer */ cirbuf_writebyte(uart->inbuf, byte); } /* If a process is attached, resume the process */ if (uart->dev->task != NULL) task_resume(uart->dev->task); } } void uart0_isr(void) { uart_isr(DEV_UART[0]); } void uart1_isr(void) { uart_isr(DEV_UART[1]); } void uart2_isr(void) { uart_isr(DEV_UART[2]); } #ifdef USART0 void usart0_isr(void) { uart_isr(DEV_UART[0]); } #endif #ifdef USART1 void usart1_isr(void) { uart_isr(DEV_UART[1]); } #endif #ifdef USART2 void usart2_isr(void) { uart_isr(DEV_UART[2]); } #endif #ifdef USART3 void usart3_isr(void) { uart_isr(DEV_UART[3]); } #endif #ifdef USART6 void usart6_isr(void) { uart_isr(DEV_UART[6]); } #endif static int devuart_write(struct fnode *fno, const void *buf, unsigned int len) { int i; char *ch = (char *)buf; struct dev_uart *uart; uart = (struct dev_uart *)FNO_MOD_PRIV(fno, &mod_devuart); if (!uart) return -1; mutex_lock(uart->dev->mutex); if (cirbuf_bytesinuse(uart->outbuf) && usart_is_send_ready(uart->base)) { char c; cirbuf_readbyte(uart->outbuf, &c); usart_send(uart->base, (uint16_t) c); usart_enable_tx_interrupt(uart->base); } if (!cirbuf_bytesfree(uart->outbuf)) { mutex_unlock(uart->dev->mutex); task_preempt(); return SYS_CALL_AGAIN; } if (len <= 0) return len; if (uart->w_start == NULL) { uart->w_start = (uint8_t *)buf; uart->w_end = ((uint8_t *)buf) + len; } else { /* previous transmit not finished, do not update w_start */ } /* write to circular output buffer */ uart->w_start += cirbuf_writebytes(uart->outbuf, uart->w_start, uart->w_end - uart->w_start); if (usart_is_send_ready(uart->base)) { char c; cirbuf_readbyte(uart->outbuf, &c); usart_send(uart->base, (uint16_t) c); usart_enable_tx_interrupt(uart->base); } if (cirbuf_bytesinuse(uart->outbuf) == 0) { mutex_unlock(uart->dev->mutex); usart_disable_tx_interrupt(uart->base); uart->w_start = NULL; uart->w_end = NULL; return len; } if (uart->w_start < uart->w_end) { uart->dev->task = this_task(); mutex_unlock(uart->dev->mutex); task_suspend(); return SYS_CALL_AGAIN; } mutex_unlock(uart->dev->mutex); uart->w_start = NULL; uart->w_end = NULL; return len; } static int devuart_read(struct fnode *fno, void *buf, unsigned int len) { int out; volatile int len_available; char *ptr = (char *)buf; struct dev_uart *uart; if (len <= 0) return len; uart = (struct dev_uart *)FNO_MOD_PRIV(fno, &mod_devuart); if (!uart) return -1; mutex_lock(uart->dev->mutex); usart_disable_rx_interrupt(uart->base); len_available = cirbuf_bytesinuse(uart->inbuf); if (len_available <= 0) { uart->dev->task = this_task(); task_suspend(); mutex_unlock(uart->dev->mutex); out = SYS_CALL_AGAIN; goto again; } if (len_available < len) len = len_available; for(out = 0; out < len; out++) { /* read data */ if (cirbuf_readbyte(uart->inbuf, ptr) != 0) break; ptr++; } again: usart_enable_rx_interrupt(uart->base); mutex_unlock(uart->dev->mutex); return out; } static int devuart_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { int ret = 0; struct dev_uart *uart; uart = (struct dev_uart *)FNO_MOD_PRIV(fno, &mod_devuart); if (!uart) return -1; uart->dev->task = this_task(); mutex_lock(uart->dev->mutex); usart_disable_rx_interrupt(uart->base); if ((events & POLLOUT) && (cirbuf_bytesfree(uart->outbuf) > 0)) { *revents |= POLLOUT; ret = 1; } if ((events == POLLIN) && (cirbuf_bytesinuse(uart->inbuf) > 0)) { *revents |= POLLIN; ret = 1; } usart_enable_rx_interrupt(uart->base); mutex_unlock(uart->dev->mutex); return ret; } static int uart_fno_init(const struct uart_config * addr) { static int num_ttys = 0; char name[6] = "ttyS"; struct fnode *devfs = fno_search("/dev"); struct dev_uart *u; if (!devfs) return -ENOENT; u = kalloc(sizeof(struct dev_uart)); if (!u) return -ENOMEM; memset(u, 0, sizeof(struct dev_uart)); name[4] = '0' + num_ttys++; u->base = addr->base; u->dev = device_fno_init(&mod_devuart, name, devfs, FL_TTY, u); u->inbuf = cirbuf_create(256); u->outbuf = cirbuf_create(256); u->dev->task = NULL; DEV_UART[addr->devidx] = u; return 0; } int uart_create(const struct uart_config *uart) { if (uart->base == 0) return -EINVAL; gpio_create(&mod_devuart, &uart->pio_rx); gpio_create(&mod_devuart, &uart->pio_tx); #if defined(NRF51) || defined(NRF52) if(!uart->flow) { uart_set_pins(uart->base, uart->pio_rx.pin, uart->pio_tx.pin, UART_PSEL_OFF, UART_PSEL_OFF); } else { uart_set_pins(uart->base, uart->pio_rx.pin, uart->pio_tx.pin, uart->pio_cts.pin, uart->pio_rts.pin); } #endif uart_fno_init(uart); CLOCK_ENABLE(uart->rcc); usart_enable_rx_interrupt(uart->base); usart_set_baudrate(uart->base, uart->baudrate); usart_set_databits(uart->base, uart->data_bits); usart_set_stopbits(uart->base, uart->stop_bits); usart_set_mode(uart->base, USART_MODE_TX_RX); usart_set_parity(uart->base, uart->parity); usart_set_flow_control(uart->base, uart->flow); #ifdef STM32F7 USART_CR1(uart->base) &= ~(USART_CR1_TCIE); #endif usart_enable_rx_interrupt(uart->base); nvic_enable_irq(uart->irq); usart_enable(uart->base); } int uart_init(void) { register_module(&mod_devuart); return 0; } ================================================ FILE: kernel/drivers/uart.h ================================================ #ifndef INC_UART #define INC_UART #include "frosted.h" #include "gpio.h" /* TX, RX, RTS, CTS, CK*/ #define MAX_UART_PINS 5 struct uart_config { uint8_t devidx; uint32_t base; uint32_t irq; uint32_t rcc; uint32_t baudrate; uint8_t stop_bits; uint8_t data_bits; uint8_t parity; uint8_t flow; struct gpio_config pio_rx; struct gpio_config pio_tx; struct gpio_config pio_cts; struct gpio_config pio_rts; }; #ifdef CONFIG_DEVUART int uart_init(void); int uart_create(const struct uart_config *cfg); #else #define uart_init() (-ENOENT) #define uart_create(x) (-ENOENT) #endif #endif ================================================ FILE: kernel/drivers/uart_dev.h ================================================ #ifndef UART_DEV_INCLUDE /* <--- keep the same name for guard across archs for compile-time sanity */ #define UART_DEV_INCLUDE #define UART_FR_RXFE (0x10) #define UART_FR_TXFF (0x20) #ifdef STELLARIS #define UART_IM_RXIM (0x10) #else #define UART_IM_RXIM (0x10) #endif #define UART_IC_RXIC (0x10) #define UART_DR(baseaddr) (*(uint32_t *)(baseaddr)) #define UART_IR(baseaddr) (*(((uint32_t *)(baseaddr)) + 1)) #define UART_FR(baseaddr) (*(((uint32_t *)(baseaddr))+(0x18>>2))) #define UART_IC(baseaddr) (*(((uint32_t *)(baseaddr))+(0x44>>2))) #define UART_IM(baseaddr) (*(((uint32_t *)(baseaddr))+(0x38>>2))) #define UART_RXREG UART_DR #define UART_TXREG UART_DR static inline char uart_rx(uint32_t *base) { char byte = UART_RXREG(base); return byte; } static inline int uart_poll_rx(uint32_t *base) { return (!(UART_FR(base) & UART_FR_RXFE)); } static inline void uart_enter_irq(uint32_t *base) { UART_IC(base) = UART_IC_RXIC; } /* static inline void uart_init(uint32_t *base) { UART_IR(base) = 0; UART_IM(base) = UART_IM_RXIM; } */ static inline void uart_tx(uint32_t *base, char c) { UART_TXREG(base) = c; } #endif ================================================ FILE: kernel/drivers/usb/usb_kbd.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include "usb.h" #include "cirbuf.h" #include "poll.h" #include #include #include #define CLASS_HID 0x03 #define SUBCLASS_HID_BOOT 0x01 #define PROTOCOL_HID_KEYBOARD 0x01 #define KBD_BUF_SIZE 128 #define KBD_FIFO_SIZE 16 /* Special keys */ #define CAPS_LOCK 0x39 #define SHIFT_L 0x02 #define SHIFT_R 0x20 #define CTRL_L 0x01 #define CTRL_R 0x10 #define ESC 0x1B #define BS 0x08 #define DEL 0x7F const char map_num[10][2] = { {'1', '!'}, {'2', '@'}, {'3', '#'}, {'4', '$'}, {'5', '%'}, {'6', '^'}, {'7', '&'}, {'8', '*'}, {'9', '('}, {'0', ')'} }; const char map_others[17][2] = { {'\n', '\r'}, {ESC, ESC}, {BS, DEL}, {'\t','\t'}, {' ', ' '}, {'-', '_'}, {'=', '+'}, {'[', '{'}, {']', '}'}, {'\\', '|'}, {0, 0}, {';', ':'}, {'\'', '"'}, {'`', '~'}, {',', '<'}, {'.', '>'}, {'/', '?'}, }; const char map_arrows[4] = { 'C', 'D', 'B', 'A' }; #ifndef FALL_THROUGH #define FALL_THROUGH do{}while(0) #endif static int kbd_read(struct fnode *fno, void *buf, unsigned int len); static int kbd_poll(struct fnode *fno, uint16_t events, uint16_t *revents); static int kbd_ioctl(struct fnode *fno, const uint32_t cmd, void *arg); static void usb_kbd_disconnect(struct usbh_device *dev, uint8_t bInterfaceNumber); static struct module mod_usbkbd = { .family = FAMILY_DEV, .name = "usbkbd", .ops.open = device_open, .ops.read = kbd_read, .ops.ioctl = kbd_ioctl, .ops.poll = kbd_poll, }; /* Only support one keyboard for now. * Extend this to an array or list to * claim multiple keyboards. */ static struct keyboard { struct device *dev; uint8_t iface_num, iface_altset, ep_number, ep_size, ep_interval; uint8_t buf[KBD_BUF_SIZE]; struct cirbuf *cfifo; int caps_lock; uint8_t mode; } KBD; static void kbd_data_in(const uint8_t *data, unsigned len) { char mod = 0; int i; char shift; char c; int special = 0; int escape = 0; if (KBD.mode == K_RAW) { cirbuf_writebytes(KBD.cfifo, data, len); return; } if (len <= 0) return; mod = data[0]; for (i = 0; i < len -2; i++) { uint8_t u = data[i + 2]; c = '\0'; if (u == CAPS_LOCK) { KBD.caps_lock = !KBD.caps_lock; continue; } if ((mod & SHIFT_L) || (mod & SHIFT_R)) { shift = (KBD.caps_lock)?'a':'A'; special = 1; } else { shift = (KBD.caps_lock)?'A':'a'; special = 0; } /* Intercept CTRL */ if ((mod & CTRL_L) || (mod & CTRL_R)) { if (u == 0x06) /* CTRL + C */ c = 0x03; continue; } /* Letters */ if ((u >= 4) && (u <= 0x1d)) c = (u - 4) + shift; /* Numbers and co. */ else if ((u >= 0x1e) && (u <= 0x27)) c = map_num[u - 0x1e][special]; /* Other printable symbols */ else if ((u >= 0x28) && (u <= 0x38)) c = map_others[u - 0x28][special]; /* Arrow keys */ if ((u >= 0x4f) && (u <= 0x52)) { escape = 1; c = map_arrows[u - 0x4f]; } /* load result in buffer */ if (c) { mutex_lock(KBD.dev->mutex); if (escape) { cirbuf_writebyte(KBD.cfifo, ESC); cirbuf_writebyte(KBD.cfifo, '['); } cirbuf_writebyte(KBD.cfifo, c); task_resume(KBD.dev->task); mutex_unlock(KBD.dev->mutex); } } } static void endpoint_read_cb (const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { (void) urb_id; /* TODO: add a default for unexpected error. Delete device. */ switch (status) { case USBH_SUCCESS: kbd_data_in(transfer->data, transfer->transferred); FALL_THROUGH; case USBH_ERR_TIMEOUT: FALL_THROUGH; case USBH_ERR_IO: /* resubmit! */ usbh_transfer_submit(transfer); break; } } static void read_data_from_keyboard(usbh_device *dev) { usbh_transfer ep_transfer = { .device = dev, .ep_type = USBH_EP_INTERRUPT, .ep_addr = KBD.ep_number, .ep_size = KBD.ep_size, .interval = KBD.ep_interval, .data = KBD.buf, .length = KBD.ep_size, .flags = USBH_FLAG_NONE, .timeout = 250, .callback = endpoint_read_cb, }; usbh_transfer_submit(&ep_transfer); } static void devfile_create(void) { char name[5] = "kbd0"; struct fnode *devfs = fno_search("/dev"); if (!devfs) return; KBD.dev = device_fno_init(&mod_usbkbd, name, devfs, FL_TTY, &KBD); } static void after_set_idle(const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { (void) urb_id; (void) status; read_data_from_keyboard(transfer->device); } static void after_set_protocol_boot(const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { (void) urb_id; if (status != USBH_SUCCESS) { return; } usbh_hid_set_idle(transfer->device, 0, 0, KBD.iface_num, after_set_idle); } static void after_interface_set(const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { (void) urb_id; (void) status; usbh_hid_set_protocol(transfer->device, USB_REQ_HID_PROTOCOL_BOOT, KBD.iface_num, after_set_protocol_boot); } static void after_config_set(const usbh_transfer *transfer, usbh_transfer_status status, usbh_urb_id urb_id) { (void) urb_id; if (status != USBH_SUCCESS) { return; } usbh_ctrlreq_set_interface(transfer->device, KBD.iface_num, KBD.iface_altset, after_interface_set); } static void usb_kbd_probe( struct usbh_device *dev, const struct usb_device_descriptor *ddesc, const struct usb_config_descriptor *cfg) { uint8_t class = ddesc->bDeviceClass; uint8_t subclass = ddesc->bDeviceSubClass; uint8_t protocol = ddesc->bDeviceProtocol; int ifnum = -1; uint8_t *ptr = ((uint8_t *)cfg) + cfg->bLength; int len = cfg->wTotalLength - cfg->bLength; struct usb_interface_descriptor *iface_interest = NULL; struct usb_endpoint_descriptor *ep_interest = NULL; /* Check device configurations */ if (ddesc->bNumConfigurations < 1) return; /* Check class, subclass, protocol for direct claim */ if ((class == CLASS_HID) || (subclass == SUBCLASS_HID_BOOT) || (protocol == PROTOCOL_HID_KEYBOARD)) { /* TODO: claim */ return; } if (cfg->bLength < 4) { /* Descriptor is too small. */ return; } while (len > 0) { switch (ptr[1]) { case USB_DT_INTERFACE: { struct usb_interface_descriptor *iface = (struct usb_interface_descriptor *)ptr; if (iface->bInterfaceClass == CLASS_HID && iface->bInterfaceSubClass == SUBCLASS_HID_BOOT && iface->bInterfaceProtocol == PROTOCOL_HID_KEYBOARD && iface->bNumEndpoints) { iface_interest = iface; } ep_interest = NULL; } break; case USB_DT_ENDPOINT: { struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor *)ptr; if (iface_interest == NULL) { break; } if ((ep->bmAttributes & USB_ENDPOINT_ATTR_TYPE) == USB_ENDPOINT_ATTR_INTERRUPT && (ep->bEndpointAddress & 0x80)) { ep_interest = ep; } } break; } /* end switch/case */ if ((iface_interest != NULL) && (ep_interest != NULL)) { break; } ptr += ptr[0]; len -= ptr[0]; } if ((iface_interest == NULL) || (ep_interest == NULL)) { return; } KBD.iface_num = iface_interest->bInterfaceNumber; KBD.iface_altset = iface_interest->bAlternateSetting; KBD.ep_number = ep_interest->bEndpointAddress; KBD.ep_size = ep_interest->wMaxPacketSize; KBD.ep_interval = ep_interest->bInterval; if (usb_host_claim_interface(&mod_usbkbd, dev, KBD.iface_num, usb_kbd_disconnect) < 0) { /* Failed to claim interface. */ return; } usbh_ctrlreq_set_config(dev, cfg->bConfigurationValue, after_config_set); KBD.cfifo = cirbuf_create(KBD_FIFO_SIZE); devfile_create(); } static void usb_kbd_disconnect(struct usbh_device *dev, uint8_t bInterfaceNumber) { /* TODO: delete char device. */ return; } void usb_kbd_init(void) { KBD.mode = K_XLATE; register_module(&mod_usbkbd); usb_host_driver_register(&mod_usbkbd, usb_kbd_probe); } static int kbd_read(struct fnode *fno, void *buf, unsigned int len) { int ret = 0; char *cbuf = (char *)buf; if (len == 0) return 0; KBD.dev->task = this_task(); mutex_lock(KBD.dev->mutex); if (cirbuf_bytesinuse(KBD.cfifo) > 0) { ret = cirbuf_readbytes(KBD.cfifo, buf, len); } else { task_suspend(); ret = SYS_CALL_AGAIN; } mutex_unlock(KBD.dev->mutex); return ret; } static int kbd_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { int ret = 0; KBD.dev->task = this_task(); mutex_lock(KBD.dev->mutex); if ((events == POLLIN) && (cirbuf_bytesinuse(KBD.cfifo) > 0)) { *revents |= POLLIN; ret = 1; } mutex_unlock(KBD.dev->mutex); return ret; } static int kbd_ioctl(struct fnode *fno, const uint32_t cmd, void *arg) { if (cmd == KDSKBMODE) { mutex_lock(KBD.dev->mutex); uint32_t *mode = (uint32_t *)arg; uint8_t newmode = (*mode) & 0xFF; uint8_t c; if (newmode != KBD.mode) { while(cirbuf_bytesinuse(KBD.cfifo) > 0) cirbuf_readbyte(KBD.cfifo, &c); KBD.mode = newmode; } mutex_unlock(KBD.dev->mutex); } else { return -EINVAL; } } ================================================ FILE: kernel/drivers/usb/usbh_drivers.h ================================================ #include "frosted.h" #include "device.h" #ifndef USBH_DRIVERS_H #define USBH_DRIVERS_H /* Put your driver initalizers here */ extern void usb_kbd_init(void); static inline void usbh_drivers_init(void) { #ifdef CONFIG_DEV_USBH_KBD usb_kbd_init(); #endif } #endif ================================================ FILE: kernel/drivers/usb.h ================================================ #ifndef INC_USB #define INC_USB #include "frosted.h" #include "gpio.h" #include #include #include #include #include #define USB_DEV_FS 0 #define USB_DEV_HS 1 #define USB_MODE_GUEST 1 #define USB_MODE_HOST 2 typedef void (*usb_host_driver_probe_callback)( struct usbh_device *dev, const struct usb_device_descriptor *device_desc, const struct usb_config_descriptor *config_desc); typedef void (*usb_host_interface_removed_callback)( struct usbh_device *dev, uint8_t bInterfaceNumber); int usb_host_driver_register(struct module *owner, usb_host_driver_probe_callback probe); int usb_host_claim_interface(struct module *owner, usbh_device *dev, uint8_t bInterfaceNumber, usb_host_interface_removed_callback removed); int usb_host_release_interface(usbh_device *dev, uint8_t bInterfaceNumber); struct usb_pio_config_fs { struct gpio_config pio_vbus; struct gpio_config pio_dm; struct gpio_config pio_dp; struct gpio_config pio_phy; }; struct usb_pio_config_hs { struct gpio_config ulpi_data[8]; struct gpio_config ulpi_clk; struct gpio_config ulpi_dir; struct gpio_config ulpi_next; struct gpio_config ulpi_step; }; struct usb_config { unsigned int dev_type; unsigned int otg_mode; union usb_pio_config { struct usb_pio_config_fs *fs; struct usb_pio_config_hs *hs; } pio; }; #ifdef CONFIG_DEVUSB int usb_init(struct usb_config *conf); int usbdev_start(usbd_device **_usbd_dev, unsigned int dev, const struct usbd_info *info); #else # define usb_init(x) ((-ENOENT)) # define usbdev_start(...) ((-ENOENT)) #endif #ifdef CONFIG_DEV_USBETH int usb_ethernet_init(unsigned int dev); #else # define usb_ethernet_init(x) ((-ENOENT)) #endif #endif ================================================ FILE: kernel/drivers/xadow_LED_5x7.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "device.h" #include #include "cirbuf.h" #include "dma.h" #include "cirbuf.h" #include "i2c.h" #define XADOW_LED_I2C_ADDR (0x21 << 1) #define DISP_CHAR_5X7 0x80 #define DISP_STRING 0x81 #define SET_DISP_ORIENTATION 0x82 #define POWER_DOWN 0x83 #define DISP_PIC 0x84 #define DISP_DATA 0x85 struct dev_matrix { struct i2c_slave i2c; struct device *dev; uint8_t i2c_data; uint8_t buf[20]; int update; } Matrix; static struct task *kt = NULL; /* Module description */ static int xadow_led_read(struct fnode *fno, void *buf, unsigned int len) { return 0; } static int xadow_led_write(struct fnode *fno, const void *buf, unsigned int len) { memset(Matrix.buf, 0, 20); if (len > 17) len = 17; Matrix.buf[0] = len; if (len > 0) { memcpy(Matrix.buf + 1, buf, len); } Matrix.buf[len + 1] = 0; Matrix.buf[len + 2] = 120; Matrix.update = len + 3; return len; } static void xadow_led_task(void *arg) { (void)arg; int r; Matrix.update = 0; while(1<2) { if (Matrix.update) { r = i2c_kthread_write(&Matrix.i2c, DISP_STRING, Matrix.buf, Matrix.update); Matrix.update = 0; } kthread_yield(); } } static int xadow_led_open(const char *path, int flags) { struct fnode *f = fno_search(path); if (!f) return -1; kt = kthread_create(xadow_led_task, NULL); return task_filedesc_add(f); } static int xadow_led_close(struct fnode *f) { if (kt) { kthread_cancel(kt); kt = NULL; } return 0; } static struct module mod_devmatrix = { .family = FAMILY_FILE, .name = "matrix", .ops.open = xadow_led_open, .ops.read = xadow_led_read, .ops.write = xadow_led_write, .ops.close = xadow_led_close }; int xadow_led_init(uint32_t bus) { int i; struct fnode *devdir = fno_search("/dev"); if (!devdir) return -ENOENT; memset(&Matrix, 0, sizeof(struct dev_matrix)); Matrix.dev = device_fno_init(&mod_devmatrix, "matrix", devdir, 0, &Matrix); /* Populate i2c_slave struct */ Matrix.i2c.bus = bus; Matrix.i2c.address = XADOW_LED_I2C_ADDR; //kthread_create(xadow_led_task, NULL); return 0; } ================================================ FILE: kernel/fonts/cga_8x8.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * * Automatically generated using CGA 8x8 font by EPTO * */ const unsigned char fb_font[256][8] = { { //Ascii 0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 1 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, }, { //Ascii 2 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, }, { //Ascii 3 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, }, { //Ascii 4 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, }, { //Ascii 5 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0xD6, 0x10, 0x38, }, { //Ascii 6 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x10, 0x38, }, { //Ascii 7 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, }, { //Ascii 8 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, }, { //Ascii 9 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, }, { //Ascii 10 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, }, { //Ascii 11 0x0F, 0x03, 0x05, 0x7D, 0x84, 0x84, 0x84, 0x78, }, { //Ascii 12 0x3C, 0x42, 0x42, 0x42, 0x3C, 0x18, 0x7E, 0x18, }, { //Ascii 13 0x3F, 0x21, 0x3F, 0x20, 0x20, 0x60, 0xE0, 0xC0, }, { //Ascii 14 0x3F, 0x21, 0x3F, 0x21, 0x23, 0x67, 0xE6, 0xC0, }, { //Ascii 15 0x18, 0xDB, 0x3C, 0xE7, 0xE7, 0x3C, 0xDB, 0x18, }, { //Ascii 16 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, }, { //Ascii 17 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, }, { //Ascii 18 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, }, { //Ascii 19 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x24, 0x00, }, { //Ascii 20 0x7F, 0x92, 0x92, 0x72, 0x12, 0x12, 0x12, 0x00, }, { //Ascii 21 0x3E, 0x63, 0x38, 0x44, 0x44, 0x38, 0xCC, 0x78, }, { //Ascii 22 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, }, { //Ascii 23 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, }, { //Ascii 24 0x10, 0x38, 0x7C, 0x54, 0x10, 0x10, 0x10, 0x00, }, { //Ascii 25 0x10, 0x10, 0x10, 0x54, 0x7C, 0x38, 0x10, 0x00, }, { //Ascii 26 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, }, { //Ascii 27 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, }, { //Ascii 28 0x00, 0x00, 0x40, 0x40, 0x40, 0x7E, 0x00, 0x00, }, { //Ascii 29 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, }, { //Ascii 30 0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, }, { //Ascii 31 0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, }, { //Ascii 32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 33 0x10, 0x38, 0x38, 0x10, 0x10, 0x00, 0x10, 0x00, }, { //Ascii 34 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 35 0x24, 0x24, 0x7E, 0x24, 0x7E, 0x24, 0x24, 0x00, }, { //Ascii 36 0x18, 0x3E, 0x40, 0x3C, 0x02, 0x7C, 0x18, 0x00, }, { //Ascii 37 0x00, 0x62, 0x64, 0x08, 0x10, 0x26, 0x46, 0x00, }, { //Ascii 38 0x30, 0x48, 0x30, 0x56, 0x88, 0x88, 0x76, 0x00, }, { //Ascii 39 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 40 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00, }, { //Ascii 41 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, }, { //Ascii 42 0x00, 0x44, 0x38, 0xFE, 0x38, 0x44, 0x00, 0x00, }, { //Ascii 43 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, }, { //Ascii 44 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, }, { //Ascii 45 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 46 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, }, { //Ascii 47 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, }, { //Ascii 48 0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00, }, { //Ascii 49 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x7C, 0x00, }, { //Ascii 50 0x3C, 0x42, 0x02, 0x0C, 0x30, 0x42, 0x7E, 0x00, }, { //Ascii 51 0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00, }, { //Ascii 52 0x08, 0x18, 0x28, 0x48, 0xFE, 0x08, 0x1C, 0x00, }, { //Ascii 53 0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00, }, { //Ascii 54 0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 55 0x7E, 0x42, 0x04, 0x08, 0x10, 0x10, 0x10, 0x00, }, { //Ascii 56 0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 57 0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00, }, { //Ascii 58 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, }, { //Ascii 59 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, }, { //Ascii 60 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, }, { //Ascii 61 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, }, { //Ascii 62 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, }, { //Ascii 63 0x3C, 0x42, 0x02, 0x04, 0x08, 0x00, 0x08, 0x00, }, { //Ascii 64 0x3C, 0x42, 0x5E, 0x52, 0x5E, 0x40, 0x3C, 0x00, }, { //Ascii 65 0x18, 0x24, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x00, }, { //Ascii 66 0x7C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x7C, 0x00, }, { //Ascii 67 0x1C, 0x22, 0x40, 0x40, 0x40, 0x22, 0x1C, 0x00, }, { //Ascii 68 0x78, 0x24, 0x22, 0x22, 0x22, 0x24, 0x78, 0x00, }, { //Ascii 69 0x7E, 0x22, 0x28, 0x38, 0x28, 0x22, 0x7E, 0x00, }, { //Ascii 70 0x7E, 0x22, 0x28, 0x38, 0x28, 0x20, 0x70, 0x00, }, { //Ascii 71 0x1C, 0x22, 0x40, 0x40, 0x4E, 0x22, 0x1E, 0x00, }, { //Ascii 72 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00, }, { //Ascii 73 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, }, { //Ascii 74 0x0E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00, }, { //Ascii 75 0x62, 0x24, 0x28, 0x30, 0x28, 0x24, 0x63, 0x00, }, { //Ascii 76 0x70, 0x20, 0x20, 0x20, 0x20, 0x22, 0x7E, 0x00, }, { //Ascii 77 0x63, 0x55, 0x49, 0x41, 0x41, 0x41, 0x41, 0x00, }, { //Ascii 78 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x42, 0x00, }, { //Ascii 79 0x18, 0x24, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, }, { //Ascii 80 0x7C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x70, 0x00, }, { //Ascii 81 0x3C, 0x42, 0x42, 0x42, 0x4A, 0x3C, 0x03, 0x00, }, { //Ascii 82 0x7C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x72, 0x00, }, { //Ascii 83 0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00, }, { //Ascii 84 0x7F, 0x49, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, }, { //Ascii 85 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 86 0x41, 0x41, 0x41, 0x41, 0x22, 0x14, 0x08, 0x00, }, { //Ascii 87 0x41, 0x41, 0x41, 0x49, 0x49, 0x49, 0x36, 0x00, }, { //Ascii 88 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00, }, { //Ascii 89 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x1C, 0x00, }, { //Ascii 90 0x7F, 0x42, 0x04, 0x08, 0x10, 0x21, 0x7F, 0x00, }, { //Ascii 91 0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0x78, 0x00, }, { //Ascii 92 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, }, { //Ascii 93 0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00, }, { //Ascii 94 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, }, { //Ascii 96 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 97 0x00, 0x00, 0x3C, 0x02, 0x3E, 0x42, 0x3F, 0x00, }, { //Ascii 98 0x60, 0x20, 0x20, 0x2E, 0x31, 0x31, 0x2E, 0x00, }, { //Ascii 99 0x00, 0x00, 0x3C, 0x42, 0x40, 0x42, 0x3C, 0x00, }, { //Ascii 100 0x06, 0x02, 0x02, 0x3A, 0x46, 0x46, 0x3B, 0x00, }, { //Ascii 101 0x00, 0x00, 0x3C, 0x42, 0x7E, 0x40, 0x3C, 0x00, }, { //Ascii 102 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x38, 0x00, }, { //Ascii 103 0x00, 0x00, 0x3D, 0x42, 0x42, 0x3E, 0x02, 0x7C, }, { //Ascii 104 0x60, 0x20, 0x2C, 0x32, 0x22, 0x22, 0x62, 0x00, }, { //Ascii 105 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, }, { //Ascii 106 0x02, 0x00, 0x06, 0x02, 0x02, 0x42, 0x42, 0x3C, }, { //Ascii 107 0x60, 0x20, 0x24, 0x28, 0x30, 0x28, 0x26, 0x00, }, { //Ascii 108 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, }, { //Ascii 109 0x00, 0x00, 0x76, 0x49, 0x49, 0x49, 0x49, 0x00, }, { //Ascii 110 0x00, 0x00, 0x5C, 0x62, 0x42, 0x42, 0x42, 0x00, }, { //Ascii 111 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 112 0x00, 0x00, 0x6C, 0x32, 0x32, 0x2C, 0x20, 0x70, }, { //Ascii 113 0x00, 0x00, 0x36, 0x4C, 0x4C, 0x34, 0x04, 0x0E, }, { //Ascii 114 0x00, 0x00, 0x6C, 0x32, 0x22, 0x20, 0x70, 0x00, }, { //Ascii 115 0x00, 0x00, 0x3E, 0x40, 0x3C, 0x02, 0x7C, 0x00, }, { //Ascii 116 0x10, 0x10, 0x7C, 0x10, 0x10, 0x12, 0x0C, 0x00, }, { //Ascii 117 0x00, 0x00, 0x42, 0x42, 0x42, 0x46, 0x3A, 0x00, }, { //Ascii 118 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x00, }, { //Ascii 119 0x00, 0x00, 0x41, 0x49, 0x49, 0x49, 0x36, 0x00, }, { //Ascii 120 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, }, { //Ascii 121 0x00, 0x00, 0x42, 0x42, 0x42, 0x3E, 0x02, 0x7C, }, { //Ascii 122 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, }, { //Ascii 123 0x0C, 0x10, 0x10, 0x60, 0x10, 0x10, 0x0C, 0x00, }, { //Ascii 124 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, }, { //Ascii 125 0x30, 0x08, 0x08, 0x06, 0x08, 0x08, 0x30, 0x00, }, { //Ascii 126 0x32, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 127 0x00, 0x08, 0x14, 0x22, 0x41, 0x41, 0x7F, 0x00, }, { //Ascii 128 0x3C, 0x42, 0x40, 0x42, 0x3C, 0x0C, 0x02, 0x3C, }, { //Ascii 129 0x00, 0x44, 0x00, 0x44, 0x44, 0x44, 0x3E, 0x00, }, { //Ascii 130 0x0C, 0x00, 0x3C, 0x42, 0x7E, 0x40, 0x3C, 0x00, }, { //Ascii 131 0x3C, 0x42, 0x38, 0x04, 0x3C, 0x44, 0x3E, 0x00, }, { //Ascii 132 0x42, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3E, 0x00, }, { //Ascii 133 0x30, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3E, 0x00, }, { //Ascii 134 0x10, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3E, 0x00, }, { //Ascii 135 0x00, 0x00, 0x3C, 0x40, 0x40, 0x3C, 0x06, 0x1C, }, { //Ascii 136 0x3C, 0x42, 0x3C, 0x42, 0x7E, 0x40, 0x3C, 0x00, }, { //Ascii 137 0x42, 0x00, 0x3C, 0x42, 0x7E, 0x40, 0x3C, 0x00, }, { //Ascii 138 0x30, 0x00, 0x3C, 0x42, 0x7E, 0x40, 0x3C, 0x00, }, { //Ascii 139 0x24, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, }, { //Ascii 140 0x7C, 0x82, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, }, { //Ascii 141 0x30, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, }, { //Ascii 142 0x42, 0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x00, }, { //Ascii 143 0x18, 0x18, 0x00, 0x3C, 0x42, 0x7E, 0x42, 0x00, }, { //Ascii 144 0x0C, 0x00, 0x7C, 0x20, 0x38, 0x20, 0x7C, 0x00, }, { //Ascii 145 0x00, 0x00, 0x33, 0x0C, 0x3F, 0x44, 0x3B, 0x00, }, { //Ascii 146 0x1F, 0x24, 0x44, 0x7F, 0x44, 0x44, 0x47, 0x00, }, { //Ascii 147 0x18, 0x24, 0x00, 0x3C, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 148 0x00, 0x42, 0x00, 0x3C, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 149 0x20, 0x10, 0x00, 0x3C, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 150 0x18, 0x24, 0x00, 0x42, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 151 0x20, 0x10, 0x00, 0x42, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 152 0x00, 0x42, 0x00, 0x42, 0x42, 0x3E, 0x02, 0x3C, }, { //Ascii 153 0x42, 0x18, 0x24, 0x42, 0x42, 0x24, 0x18, 0x00, }, { //Ascii 154 0x42, 0x00, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 155 0x08, 0x08, 0x3E, 0x40, 0x40, 0x3E, 0x08, 0x08, }, { //Ascii 156 0x18, 0x24, 0x20, 0x70, 0x20, 0x42, 0x7C, 0x00, }, { //Ascii 157 0x44, 0x28, 0x7C, 0x10, 0x7C, 0x10, 0x10, 0x00, }, { //Ascii 158 0xF8, 0x4C, 0x78, 0x44, 0x4F, 0x44, 0x45, 0xE6, }, { //Ascii 159 0x1C, 0x12, 0x10, 0x7C, 0x10, 0x10, 0x90, 0x60, }, { //Ascii 160 0x0C, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3E, 0x00, }, { //Ascii 161 0x0C, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, }, { //Ascii 162 0x04, 0x08, 0x00, 0x3C, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 163 0x00, 0x04, 0x08, 0x42, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 164 0x32, 0x4C, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x00, }, { //Ascii 165 0x34, 0x4C, 0x00, 0x62, 0x52, 0x4A, 0x46, 0x00, }, { //Ascii 166 0x3C, 0x44, 0x44, 0x3E, 0x00, 0x7E, 0x00, 0x00, }, { //Ascii 167 0x38, 0x44, 0x44, 0x38, 0x00, 0x7C, 0x00, 0x00, }, { //Ascii 168 0x10, 0x00, 0x10, 0x20, 0x40, 0x42, 0x3C, 0x00, }, { //Ascii 169 0x00, 0x00, 0x00, 0x7E, 0x40, 0x40, 0x00, 0x00, }, { //Ascii 170 0x00, 0x00, 0x00, 0x7E, 0x02, 0x02, 0x00, 0x00, }, { //Ascii 171 0x42, 0xC4, 0x48, 0xF6, 0x29, 0x43, 0x8C, 0x1F, }, { //Ascii 172 0x42, 0xC4, 0x4A, 0xF6, 0x2A, 0x5F, 0x82, 0x02, }, { //Ascii 173 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, }, { //Ascii 174 0x00, 0x12, 0x24, 0x48, 0x24, 0x12, 0x00, 0x00, }, { //Ascii 175 0x00, 0x48, 0x24, 0x12, 0x24, 0x48, 0x00, 0x00, }, { //Ascii 176 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, }, { //Ascii 177 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, }, { //Ascii 178 0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE, }, { //Ascii 179 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, { //Ascii 180 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x10, 0x10, }, { //Ascii 181 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0x10, }, { //Ascii 182 0x14, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x14, 0x14, }, { //Ascii 183 0x00, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x14, 0x14, }, { //Ascii 184 0x00, 0x00, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0x10, }, { //Ascii 185 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x14, 0x14, 0x14, }, { //Ascii 186 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, }, { //Ascii 187 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x14, }, { //Ascii 188 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x00, 0x00, 0x00, }, { //Ascii 189 0x14, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x00, 0x00, }, { //Ascii 190 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x00, }, { //Ascii 191 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0x10, 0x10, }, { //Ascii 192 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, }, { //Ascii 193 0x10, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x00, 0x00, }, { //Ascii 194 0x00, 0x00, 0x00, 0x00, 0xFF, 0x10, 0x10, 0x10, }, { //Ascii 195 0x10, 0x10, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10, }, { //Ascii 196 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, }, { //Ascii 197 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, }, { //Ascii 198 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x10, 0x10, 0x10, }, { //Ascii 199 0x14, 0x14, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14, }, { //Ascii 200 0x14, 0x14, 0x17, 0x10, 0x1F, 0x00, 0x00, 0x00, }, { //Ascii 201 0x00, 0x00, 0x1F, 0x10, 0x17, 0x14, 0x14, 0x14, }, { //Ascii 202 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, }, { //Ascii 203 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14, 0x14, }, { //Ascii 204 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14, 0x14, }, { //Ascii 205 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, }, { //Ascii 206 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, }, { //Ascii 207 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, }, { //Ascii 208 0x14, 0x14, 0x14, 0x14, 0xFF, 0x00, 0x00, 0x00, }, { //Ascii 209 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0x10, }, { //Ascii 210 0x00, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x14, 0x14, }, { //Ascii 211 0x14, 0x14, 0x14, 0x14, 0x1F, 0x00, 0x00, 0x00, }, { //Ascii 212 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00, }, { //Ascii 213 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x10, 0x10, 0x10, }, { //Ascii 214 0x00, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x14, 0x14, }, { //Ascii 215 0x14, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x14, 0x14, }, { //Ascii 216 0x10, 0x10, 0xFF, 0x10, 0xFF, 0x10, 0x10, 0x10, }, { //Ascii 217 0x10, 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, }, { //Ascii 218 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, }, { //Ascii 219 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, { //Ascii 220 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, }, { //Ascii 221 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, }, { //Ascii 222 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, }, { //Ascii 223 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 224 0x00, 0x00, 0x31, 0x4A, 0x44, 0x4A, 0x31, 0x00, }, { //Ascii 225 0x00, 0x3C, 0x42, 0x7C, 0x42, 0x7C, 0x40, 0x40, }, { //Ascii 226 0x00, 0x7E, 0x42, 0x40, 0x40, 0x40, 0x40, 0x00, }, { //Ascii 227 0x00, 0x3F, 0x54, 0x14, 0x14, 0x14, 0x14, 0x00, }, { //Ascii 228 0x7E, 0x42, 0x20, 0x18, 0x20, 0x42, 0x7E, 0x00, }, { //Ascii 229 0x00, 0x00, 0x3E, 0x48, 0x48, 0x48, 0x30, 0x00, }, { //Ascii 230 0x00, 0x44, 0x44, 0x44, 0x7A, 0x40, 0x40, 0x80, }, { //Ascii 231 0x00, 0x33, 0x4C, 0x08, 0x08, 0x08, 0x08, 0x00, }, { //Ascii 232 0x7C, 0x10, 0x38, 0x44, 0x44, 0x38, 0x10, 0x7C, }, { //Ascii 233 0x18, 0x24, 0x42, 0x7E, 0x42, 0x24, 0x18, 0x00, }, { //Ascii 234 0x18, 0x24, 0x42, 0x42, 0x24, 0x24, 0x66, 0x00, }, { //Ascii 235 0x1C, 0x20, 0x18, 0x3C, 0x42, 0x42, 0x3C, 0x00, }, { //Ascii 236 0x00, 0x62, 0x95, 0x89, 0x95, 0x62, 0x00, 0x00, }, { //Ascii 237 0x02, 0x04, 0x3C, 0x4A, 0x52, 0x3C, 0x40, 0x80, }, { //Ascii 238 0x0C, 0x10, 0x20, 0x3C, 0x20, 0x10, 0x0C, 0x00, }, { //Ascii 239 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, }, { //Ascii 240 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, }, { //Ascii 241 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00, }, { //Ascii 242 0x10, 0x08, 0x04, 0x08, 0x10, 0x00, 0x7E, 0x00, }, { //Ascii 243 0x08, 0x10, 0x20, 0x10, 0x08, 0x00, 0x7E, 0x00, }, { //Ascii 244 0x0C, 0x12, 0x12, 0x10, 0x10, 0x10, 0x10, 0x10, }, { //Ascii 245 0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x90, 0x60, }, { //Ascii 246 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, }, { //Ascii 247 0x00, 0x32, 0x4C, 0x00, 0x32, 0x4C, 0x00, 0x00, }, { //Ascii 248 0x30, 0x48, 0x48, 0x30, 0x00, 0x00, 0x00, 0x00, }, { //Ascii 249 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, }, { //Ascii 250 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, }, { //Ascii 251 0x0F, 0x08, 0x08, 0x08, 0x08, 0xC8, 0x28, 0x18, }, { //Ascii 252 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, }, { //Ascii 253 0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00, }, { //Ascii 254 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, }, { //Ascii 255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, }; ================================================ FILE: kernel/fonts/palette_256_xterm.c ================================================ #include const uint32_t xterm_cmap[256] = { 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xC0C0C0, 0x808080, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF, 0x000000, 0x00005F, 0x000087, 0x0000AF, 0x0000D7, 0x0000FF, 0x005F00, 0x005F5F, 0x005F87, 0x005FAF, 0x005FD7, 0x005FFF, 0x008700, 0x00875F, 0x008787, 0x0087AF, 0x0087D7, 0x0087FF, 0x00AF00, 0x00AF5F, 0x00AF87, 0x00AFAF, 0x00AFD7, 0x00AFFF, 0x00D700, 0x00D75F, 0x00D787, 0x00D7AF, 0x00D7D7, 0x00D7FF, 0x00FF00, 0x00FF5F, 0x00FF87, 0x00FFAF, 0x00FFD7, 0x00FFFF, 0x5F0000, 0x5F005F, 0x5F0087, 0x5F00AF, 0x5F00D7, 0x5F00FF, 0x5F5F00, 0x5F5F5F, 0x5F5F87, 0x5F5FAF, 0x5F5FD7, 0x5F5FFF, 0x5F8700, 0x5F875F, 0x5F8787, 0x5F87AF, 0x5F87D7, 0x5F87FF, 0x5FAF00, 0x5FAF5F, 0x5FAF87, 0x5FAFAF, 0x5FAFD7, 0x5FAFFF, 0x5FD700, 0x5FD75F, 0x5FD787, 0x5FD7AF, 0x5FD7D7, 0x5FD7FF, 0x5FFF00, 0x5FFF5F, 0x5FFF87, 0x5FFFAF, 0x5FFFD7, 0x5FFFFF, 0x870000, 0x87005F, 0x870087, 0x8700AF, 0x8700D7, 0x8700FF, 0x875F00, 0x875F5F, 0x875F87, 0x875FAF, 0x875FD7, 0x875FFF, 0x878700, 0x87875F, 0x878787, 0x8787AF, 0x8787D7, 0x8787FF, 0x87AF00, 0x87AF5F, 0x87AF87, 0x87AFAF, 0x87AFD7, 0x87AFFF, 0x87D700, 0x87D75F, 0x87D787, 0x87D7AF, 0x87D7D7, 0x87D7FF, 0x87FF00, 0x87FF5F, 0x87FF87, 0x87FFAF, 0x87FFD7, 0x87FFFF, 0xAF0000, 0xAF005F, 0xAF0087, 0xAF00AF, 0xAF00D7, 0xAF00FF, 0xAF5F00, 0xAF5F5F, 0xAF5F87, 0xAF5FAF, 0xAF5FD7, 0xAF5FFF, 0xAF8700, 0xAF875F, 0xAF8787, 0xAF87AF, 0xAF87D7, 0xAF87FF, 0xAFAF00, 0xAFAF5F, 0xAFAF87, 0xAFAFAF, 0xAFAFD7, 0xAFAFFF, 0xAFD700, 0xAFD75F, 0xAFD787, 0xAFD7AF, 0xAFD7D7, 0xAFD7FF, 0xAFFF00, 0xAFFF5F, 0xAFFF87, 0xAFFFAF, 0xAFFFD7, 0xAFFFFF, 0xD70000, 0xD7005F, 0xD70087, 0xD700AF, 0xD700D7, 0xD700FF, 0xD75F00, 0xD75F5F, 0xD75F87, 0xD75FAF, 0xD75FD7, 0xD75FFF, 0xD78700, 0xD7875F, 0xD78787, 0xD787AF, 0xD787D7, 0xD787FF, 0xD7AF00, 0xD7AF5F, 0xD7AF87, 0xD7AFAF, 0xD7AFD7, 0xD7AFFF, 0xD7D700, 0xD7D75F, 0xD7D787, 0xD7D7AF, 0xD7D7D7, 0xD7D7FF, 0xD7FF00, 0xD7FF5F, 0xD7FF87, 0xD7FFAF, 0xD7FFD7, 0xD7FFFF, 0xFF0000, 0xFF005F, 0xFF0087, 0xFF00AF, 0xFF00D7, 0xFF00FF, 0xFF5F00, 0xFF5F5F, 0xFF5F87, 0xFF5FAF, 0xFF5FD7, 0xFF5FFF, 0xFF8700, 0xFF875F, 0xFF8787, 0xFF87AF, 0xFF87D7, 0xFF87FF, 0xFFAF00, 0xFFAF5F, 0xFFAF87, 0xFFAFAF, 0xFFAFD7, 0xFFAFFF, 0xFFD700, 0xFFD75F, 0xFFD787, 0xFFD7AF, 0xFFD7D7, 0xFFD7FF, 0xFFFF00, 0xFFFF5F, 0xFFFF87, 0xFFFFAF, 0xFFFFD7, 0xFFFFFF, 0x080808, 0x121212, 0x1C1C1C, 0x262626, 0x303030, 0x3A3A3A, 0x444444, 0x4E4E4E, 0x585858, 0x626262, 0x6C6C6C, 0x767676, 0x808080, 0x8A8A8A, 0x949494, 0x9E9E9E, 0xA8A8A8, 0xB2B2B2, 0xBCBCBC, 0xC6C6C6, 0xD0D0D0, 0xDADADA, 0xE4E4E4, 0xEEEEEE }; ================================================ FILE: kernel/fonts/piccolo_7x6.c ================================================ const unsigned long font_height = 7; const unsigned long font_width = 6; const unsigned char fb_font[256][7] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20}, {0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00}, {0x50, 0x50, 0xf8, 0x50, 0xf8, 0x50, 0x50}, {0x20, 0x78, 0xa0, 0x70, 0x28, 0xf0, 0x20}, {0xc0, 0xc8, 0x10, 0x20, 0x40, 0x98, 0x18}, {0x40, 0xa0, 0xa0, 0x40, 0xa8, 0x90, 0x68}, {0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00}, {0x20, 0x40, 0x80, 0x80, 0x80, 0x40, 0x20}, {0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20}, {0x20, 0xa8, 0x70, 0x20, 0x70, 0xa8, 0x20}, {0x00, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40}, {0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}, {0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, {0x70, 0x88, 0x98, 0xa8, 0xc8, 0x88, 0x70}, {0x20, 0x60, 0x20, 0x20, 0x20, 0x20, 0x70}, {0x70, 0x88, 0x08, 0x30, 0x40, 0x80, 0xf8}, {0xf8, 0x08, 0x10, 0x30, 0x08, 0x88, 0x70}, {0x10, 0x30, 0x50, 0x90, 0xf8, 0x10, 0x10}, {0xf8, 0x80, 0xf0, 0x08, 0x08, 0x88, 0x70}, {0x38, 0x40, 0x80, 0xf0, 0x88, 0x88, 0x70}, {0xf8, 0x08, 0x10, 0x20, 0x40, 0x40, 0x40}, {0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70}, {0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0xe0}, {0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00}, {0x00, 0x00, 0x20, 0x00, 0x20, 0x20, 0x40}, {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10}, {0x00, 0x00, 0xf8, 0x00, 0xf8, 0x00, 0x00}, {0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40}, {0x70, 0x88, 0x10, 0x20, 0x20, 0x00, 0x20}, {0x70, 0x88, 0xa8, 0xb8, 0xb0, 0x80, 0x78}, {0x20, 0x50, 0x88, 0x88, 0xf8, 0x88, 0x88}, {0xf0, 0x88, 0x88, 0xf0, 0x88, 0x88, 0xf0}, {0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70}, {0xf0, 0x88, 0x88, 0x88, 0x88, 0x88, 0xf0}, {0xf8, 0x80, 0x80, 0xf0, 0x80, 0x80, 0xf8}, {0xf8, 0x80, 0x80, 0xf0, 0x80, 0x80, 0x80}, {0x78, 0x80, 0x80, 0x80, 0x98, 0x88, 0x78}, {0x88, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x88}, {0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70}, {0x08, 0x08, 0x08, 0x08, 0x08, 0x88, 0x70}, {0x88, 0x90, 0xa0, 0xc0, 0xa0, 0x90, 0x88}, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xf8}, {0x88, 0xd8, 0xa8, 0xa8, 0x88, 0x88, 0x88}, {0x88, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x88}, {0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70}, {0xf0, 0x88, 0x88, 0xf0, 0x80, 0x80, 0x80}, {0x70, 0x88, 0x88, 0x88, 0xa8, 0x90, 0x68}, {0xf0, 0x88, 0x88, 0xf0, 0xa0, 0x90, 0x88}, {0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70}, {0xf8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70}, {0x88, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20}, {0x88, 0x88, 0x88, 0xa8, 0xa8, 0xd8, 0x88}, {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88}, {0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20}, {0xf8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xf8}, {0xf8, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf8}, {0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00}, {0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8}, {0x00, 0x00, 0x20, 0x50, 0x88, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8}, {0x40, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x68, 0x98, 0x88, 0x98, 0x68}, {0x80, 0x80, 0xb0, 0xc8, 0x88, 0xc8, 0xb0}, {0x00, 0x00, 0x38, 0x40, 0x40, 0x40, 0x38}, {0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68}, {0x00, 0x00, 0x70, 0x88, 0xf8, 0x80, 0x70}, {0x10, 0x20, 0x20, 0x70, 0x20, 0x20, 0x20}, {0x00, 0x00, 0x68, 0x98, 0x88, 0x78, 0x08}, {0x80, 0x80, 0xf0, 0x88, 0x88, 0x88, 0x88}, {0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70}, {0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10}, {0x80, 0x80, 0x90, 0xa0, 0xe0, 0x90, 0x88}, {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70}, {0x00, 0x00, 0xd8, 0xa4, 0xa4, 0xa4, 0xa4}, {0x00, 0x00, 0xf0, 0x88, 0x88, 0x88, 0x88}, {0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70}, {0x00, 0x00, 0xb0, 0xc8, 0x88, 0xc8, 0xb0}, {0x00, 0x00, 0x68, 0x98, 0x88, 0x98, 0x68}, {0x00, 0x00, 0xb0, 0xc0, 0x80, 0x80, 0x80}, {0x00, 0x00, 0x78, 0x80, 0x70, 0x08, 0xf0}, {0x20, 0x20, 0xf8, 0x20, 0x20, 0x20, 0x20}, {0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 0x78}, {0x00, 0x00, 0x88, 0x88, 0x50, 0x50, 0x20}, {0x00, 0x00, 0xa4, 0xa4, 0xa4, 0xa4, 0x58}, {0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88}, {0x00, 0x00, 0x48, 0x48, 0x48, 0x78, 0x08}, {0x00, 0x00, 0xf8, 0x10, 0x20, 0x40, 0xf8}, {0x18, 0x20, 0x20, 0x40, 0x20, 0x20, 0x18}, {0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20}, {0xc0, 0x20, 0x20, 0x10, 0x20, 0x20, 0xc0}, {0x00, 0x00, 0x08, 0x70, 0x80, 0x00, 0x00}, {0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }; ================================================ FILE: kernel/fortuna.h ================================================ #ifndef FORTUNA_H_ #define FORTUNA_H_ #include #include #include /* Defines for hash and encryption algorithms */ #define FORTUNA_HASH_SIZE 32 #define FORTUNA_ENCRYPT_IV_SIZE 16 #define FORTUNA_ENCRYPT_KEY_SIZE 32 #define FORTUNA_ENCRYPT_BLOCK_SIZE 16 int fortuna_init(void); void fortuna_accu(int source, int pool, uint8_t *data, int data_size); /* Get random stuff! */ int fortuna_get_bytes(uint8_t *buffer, int count); /* Shut down the generator securely if it is no longer needed */ void fortuna_shutdown(void); #endif /* FORTUNA_H_ */ ================================================ FILE: kernel/fpb.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "fpb.h" #include #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) #define FPB_NUM_CODE2_OFF 12 #define FPB_NUM_LIT_MASK_OFF 8 #define FPB_NUM_CODE1_OFF 4 #define DBG_DHCSR MMIO32(0xE000EDF0) #define DBG_DEMCR MMIO32(0xE000EDFC) #define DBG_DHCSR_KEY ((0xA0 << 24) | (0x5F << 16)) #define DBG_DHCSR_HALT (1 << 1) #define DBG_DHCSR_STEP (1 << 2) #define DBG_DEMCR_MON_STEP (1 << 18) #define DBG_DEMCR_MON_PEND (1 << 17) #define DBG_DEMCR_MON_EN (1 << 16) #define FPB_REPLACE_LO (1 << 30) #define FPB_REPLACE_HI (2 << 30) #define FPB_REPLACE_BOTH (3 << 30) struct bkpt { int pid; void *b; }; struct bkpt bkpt[8]; void debug_monitor_handler(void) { int pid; kprintf("TRAP!\r\n"); /* Exit debug state */ task_hit_breakpoint(this_task()); DBG_DHCSR = DBG_DHCSR_KEY; } int fpb_setbrk(int pid, void *bpoint, int n) { int i; if (n < 0) { for (i = 0; i < 8; i++) { if (bkpt[i].pid == 0) { n = i; break; } } } if (n < 0) return -1; bkpt[n].pid = pid; bkpt[n].b = bpoint; if ((uint32_t)bpoint & 0x01) return -1; if ((uint32_t)bpoint & 0x02) FPB_COMP[n] = FPB_COMP_ENABLE | (((uint32_t)bpoint) & (0x1FFFFFFC)) | FPB_REPLACE_HI; else FPB_COMP[n] = FPB_COMP_ENABLE | (((uint32_t)bpoint) & (0x1FFFFFFC)) | FPB_REPLACE_LO; return n; } int fpb_delbrk(int n) { bkpt[n].pid = 0; FPB_COMP[n] = 0; } int fpb_init(void) { if (FPB_CTRL == 0x0) { return -1; } if (FPB_COMP[0] == 0x0) { return -1; } /* Enable Debug Monitor Exception */ DBG_DEMCR = DBG_DEMCR_MON_EN; FPB_CTRL = FPB_CTRL_ENABLE | FPB_CTRL_KEY | (1 << FPB_NUM_CODE2_OFF) | (2 << FPB_NUM_LIT_MASK_OFF); nvic_enable_irq(DEBUG_MONITOR_IRQ); } #endif ================================================ FILE: kernel/fpb.h ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #ifndef FROSTED_FPB_INC #define FROSTED_FPB_INC #include "frosted.h" /* Those defined only on ARMv7 and above */ #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) #include int fpb_init(void); int fpb_setbrk(int pid, void *bpoint, int n); int fpb_delbrk(int n); #endif #endif ================================================ FILE: kernel/framebuffer.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "device.h" #include "framebuffer.h" #include #include #ifdef STM32F7 # include "unicore-mx/stm32/ltdc.h" #endif #define MAX_FBS (1) static struct fb_info *fb[MAX_FBS] = { 0 }; static int fb_write(struct fnode *fno, const void *buf, unsigned int len); static int fb_read(struct fnode *fno, void *buf, unsigned int len); static int fb_open(const char *path, int flags); static int fb_seek(struct fnode *fno, int off, int whence); static int fb_ioctl(struct fnode * fno, const uint32_t cmd, void *arg); static struct module mod_devfb = { .family = FAMILY_FILE, .name = "framebuffer", .ops.open = fb_open, .ops.read = fb_read, .ops.write = fb_write, .ops.seek = fb_seek, .ops.ioctl = fb_ioctl, }; static int fb_open(const char *path, int flags) { struct fnode *f = fno_search(path); if (!f) return -1; return device_open(path, flags); } static int fb_write(struct fnode *fno, const void *buf, unsigned int len) { int len_left; struct fb_info *fb; uint32_t off; if (len == 0) return len; fb = (struct fb_info *)FNO_MOD_PRIV(fno, &mod_devfb); if (!fb) return -1; //mutex_lock(fb->dev->mutex); off = task_fd_get_off(fno); len_left = fno->size - off; if (len > len_left) len = len_left; if (!len) return 0; /* write to framebuffer memory */ memcpy((void *)((uint8_t *)fb->screen_buffer + off) , buf, len); off += len; task_fd_set_off(fno, off); //mutex_unlock(fb->dev->mutex); return len; } static int fb_read(struct fnode *fno, void *buf, unsigned int len) { int len_left; struct fb_info *fb; uint32_t off; off = task_fd_get_off(fno); if (len == 0) return len; len_left = fno->size - off; if (len > len_left) len = len_left; if (!len) return 0; fb = (struct fb_info *)FNO_MOD_PRIV(fno, &mod_devfb); if (!fb) return -1; // mutex_lock(fb->dev->mutex); //XXX: max len = MAX_FB_SIZE; memcpy(buf, (void *)((uint8_t *)fb->screen_buffer + off), len); off += len; task_fd_set_off(fno, off); //mutex_unlock(fb->dev->mutex); return len; } static int fb_seek(struct fnode *fno, int off, int whence) { struct fb_info *fb; int new_off; switch(whence) { case SEEK_CUR: new_off = task_fd_get_off(fno) + off; break; case SEEK_SET: new_off = off; break; case SEEK_END: new_off = fno->size + off; break; default: return -1; } if (new_off < 0) new_off = 0; if (new_off > fno->size) { return -1; } task_fd_set_off(fno, new_off); return new_off; } static int fb_fno_init(struct fnode *dev, struct fb_info * fb) { static int num_fb = 0; char name[4] = "fb"; if (!fb) return -1; name[2] = '0' + num_fb++; fb->dev = device_fno_init(&mod_devfb, name, dev, FL_TTY, fb); fb->dev->fno->size = fb->var.yres * fb->var.xres * fb->var.bits_per_pixel; return 0; } static int fb_ioctl(struct fnode * fno, const uint32_t cmd, void *arg) { struct fb_info * fb = (struct fb_info *)FNO_MOD_PRIV(fno, &mod_devfb); if (!fb) return -1; (void)arg; if (cmd == IOCTL_FB_GETCMAP) { return 0; } if (cmd == IOCTL_FB_PUTCMAP) { return fb->fbops->fb_setcmap((uint32_t *)arg, fb); } if (cmd == IOCTL_FB_GET_FSCREENINFO) { struct fb_fix_screeninfo *fbi = (struct fb_fix_screeninfo *)arg; if (!arg) return -1; memcpy(arg, &fb->var, sizeof(struct fb_fix_screeninfo)); return 0; } return -1; } unsigned char *framebuffer_get(void) { return fb[0]->screen_buffer; } int framebuffer_setcmap(uint32_t *ptr) { return fb[0]->fbops->fb_setcmap(ptr, fb[0]); } /* Register a low-level framebuffer driver */ int register_framebuffer(struct fb_info *fb_info) { struct fnode *devfs = fno_search("/dev"); if (!fb_info) return -1; /* Ony one FB supported for now */ fb_fno_init(devfs, fb_info); if (!fb_info->fbops) return -1; if (fb_info->fbops->fb_open) fb_info->fbops->fb_open(fb_info); if (fb_info->fbops->fb_blank) fb_info->fbops->fb_blank(fb_info); fb[0] = fb_info; register_module(&mod_devfb); return 0; } ================================================ FILE: kernel/frand.h ================================================ #ifndef FRAND_H_ #define FRAND_H_ #include #include #include #include "frosted.h" struct frand_ops; struct frand_info { struct frand_ops *frandops; struct device *dev; /* This is this frand device */ }; struct frand_ops { /* open/release and usage marking */ int (*frand_open)(struct frand_info *info); }; /* For setting up the generator and feeding entropy */ /* low-level drivers must call this register function first */ int register_frand(struct frand_info *frand_info); /* kernel init */ void frand_init(struct fnode *dev); #endif /* FRAND_H_ */ ================================================ FILE: kernel/frosted.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include #include "kprintf.h" #include "bflt.h" #include "null.h" #include "xipfs.h" #include "vfs.h" #include "gpio.h" #include "uart.h" #include "rng.h" #include "sdram.h" #include "socket_in.h" #include "fatfs.h" #include "framebuffer.h" #include "ltdc.h" #include "fbcon.h" #include "usb.h" #include "eth.h" #include "exti.h" #include "pty.h" #include "lowpower.h" #include "unicore-mx/cm3/systick.h" #include "libopencmsis/core_cm3.h" #include "tty_console.h" #ifdef CONFIG_PICOTCP # include "pico_stack.h" #endif #ifdef CONFIG_PICOTCP_LOOP struct pico_device *pico_loop_create(void); #else # define pico_loop_create() NULL #endif #define IDLE() while(1){do{}while(0);} static int tcpip_timer_pending = 0; /* The following needs to be defined by * the application code */ void (*init)(void *arg) = (void (*)(void*))(FLASH_ORIGIN + APPS_ORIGIN); void simple_hard_fault_handler(void) { #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) volatile uint32_t hfsr = SCB_HFSR; //volatile uint32_t bfsr = SCB_BFSR; volatile uint32_t afsr = SCB_AFSR; volatile uint32_t bfar = SCB_BFAR; //volatile uint32_t ufsr = SCB_UFSR; volatile uint32_t mmfar = SCB_MMFAR; #endif while(1); } #ifdef CONFIG_HARDFAULT_DBG volatile unsigned long stacked_r0 ; volatile unsigned long stacked_r1 ; volatile unsigned long stacked_r2 ; volatile unsigned long stacked_r3 ; volatile unsigned long stacked_r12 ; volatile unsigned long stacked_lr ; volatile unsigned long stacked_pc ; volatile unsigned long stacked_psr ; volatile unsigned long _CFSR ; volatile unsigned long _HFSR ; volatile unsigned long _DFSR ; volatile unsigned long _AFSR ; volatile unsigned long _BFAR ; volatile unsigned long _MMAR ; void hardfault_handler_dbg(unsigned long *hardfault_args){ stacked_r0 = ((unsigned long)hardfault_args[0]) ; stacked_r1 = ((unsigned long)hardfault_args[1]) ; stacked_r2 = ((unsigned long)hardfault_args[2]) ; stacked_r3 = ((unsigned long)hardfault_args[3]) ; stacked_r12 = ((unsigned long)hardfault_args[4]) ; stacked_lr = ((unsigned long)hardfault_args[5]) ; stacked_pc = ((unsigned long)hardfault_args[6]) ; stacked_psr = ((unsigned long)hardfault_args[7]) ; // Configurable Fault Status Register // Consists of MMSR, BFSR and UFSR _CFSR = (*((volatile unsigned long *)(0xE000ED28))) ; // Hard Fault Status Register _HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ; // Debug Fault Status Register _DFSR = (*((volatile unsigned long *)(0xE000ED30))) ; // Auxiliary Fault Status Register _AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ; // Read the Fault Address Registers. These may not contain valid values. // Check BFARVALID/MMARVALID to see if they are valid values // MemManage Fault Address Register _MMAR = (*((volatile unsigned long *)(0xE000ED34))) ; // Bus Fault Address Register _BFAR = (*((volatile unsigned long *)(0xE000ED38))) ; __asm("BKPT #0") ; // Break into the debugger } #else void hardfault_handler_dbg(unsigned long *sp) { __asm("BKPT #0") ; // Break into the debugger } #endif __attribute__((naked)) void hard_fault_handler(void) { __asm("MOVS R0, #4 \n" "MOVS R1, LR \n" "TST R0, R1 \n" "BEQ _MSP \n" "MRS R0, PSP \n" "B hardfault_handler_dbg \n" "_MSP:" "MRS R0, MSP \n" "B hardfault_handler_dbg \n" ); } void mem_manage_handler(void) { # define ARM_CFSR (*(volatile uint32_t *)(0xE000ED28)) # define ARM_MMFAR (*(volatile uint32_t *)(0xE000ED34)) volatile uint32_t address = 0xFFFFFFFF; volatile uint32_t instruction = 0xFFFFFFFF; uint32_t *top_stack; if ((ARM_CFSR & 0x80)!= 0) { address = ARM_MMFAR; asm volatile ("mrs %0, psp" : "=r" (top_stack)); instruction = *(top_stack - 1); } if (task_segfault(address, instruction, MEMFAULT_ACCESS) < 0) while(1); } void bus_fault_handler(void) { while(1); } void usage_fault_handler(void) { while(1); } static void hw_init(void) { gpio_init(); exti_init(); uart_init(); ptmx_init(); rng_init(); sdram_init(); machine_init(); lowpower_init(); SysTick_Config(CONFIG_SYS_CLOCK / 1000); } int frosted_init(void) { extern void * _k__syscall__; int xip_mounted; /* ktimers must be enabled before systick */ ktimer_init(); kernel_task_init(); #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) fpb_init(); #endif vfs_init(); devnull_init(fno_search("/dev")); /* Set up system */ hw_init(); mpu_init(); syscalls_init(); memfs_init(); xipfs_init(); sysfs_init(); fatfs_init(); ltdc_init(); fbcon_init( 480, 272); tty_console_init(); vfs_mount(NULL, "/tmp", "memfs", 0, NULL); xip_mounted = vfs_mount((char *)init, "/bin", "xipfs", 0, NULL); vfs_mount(NULL, "/sys", "sysfs", 0, NULL); klog_init(); #ifdef UNIX socket_un_init(); #endif return xip_mounted; } static void ktimer_tcpip(uint32_t time, void *arg); #ifdef CONFIG_PICOTCP void frosted_tcpip_wakeup(void) { } #endif static const char init_path[] = "/bin/init"; static const char *const init_args[2] = { init_path, NULL }; #ifdef CONFIG_USBHOST struct usbh_host *USBHost = NULL; #endif void frosted_kernel(int xipfs_mounted) { struct vfs_info *vfsi = NULL; if (xipfs_mounted == 0) { struct fnode *fno = fno_search(init_path); void * memptr; size_t mem_size; size_t stack_size; uint32_t got_loc; if (!fno) { /* PANIC: Unable to find /bin/init */ while(1 < 2); } if (fno->owner && fno->owner->ops.exe) { vfsi = fno->owner->ops.exe(fno, (void *)init_args); task_create(vfsi, (void *)init_args, NICE_DEFAULT); } } else { IDLE(); } #ifdef CONFIG_PICOTCP pico_stack_init(); socket_in_init(); pico_lock_init(); /* Network devices initialization */ usb_ethernet_init(USB_DEV_FS); pico_loop_create(); pico_eth_start(); #endif frosted_scheduler_on(); while(1) { check_tasklets(); #ifdef CONFIG_PICOTCP if (pico_trylock_kernel() == 0) { pico_stack_tick(); pico_unlock(); } #endif asm volatile ("wfe"); //__WFI(); } } /* OS entry point */ void main(void) { int xipfs_mounted; xipfs_mounted = frosted_init(); frosted_kernel(xipfs_mounted); /* never returns */ } ================================================ FILE: kernel/frosted.h ================================================ #ifndef FROSTED_INCLUDED_H #define FROSTED_INCLUDED_H #define KERNEL #include "frosted_api.h" #include "malloc.h" #include "interrupts.h" #include "string.h" #include "errno.h" #include "vfs.h" #include "kprintf.h" #include "mpu.h" #define TASK_IDLE 0 #define TASK_RUNNABLE 1 #define TASK_RUNNING 2 #define TASK_WAITING 3 #define TASK_FORKED 4 #define TASK_STOPPED 5 #define TASK_ZOMBIE 0x66 #define TASK_OVER 0xFF #define MEMFAULT_ACCESS 0x00 #define MEMFAULT_DOUBLEFREE 0x01 //#define DEBUG #include #include #include /* Types */ struct task; struct fnode; struct semaphore; struct termios; typedef struct semaphore sem_t; typedef struct semaphore mutex_t; typedef uint32_t sigset_t; /* generics */ volatile unsigned int jiffies; volatile unsigned int rt_offset; volatile int _syscall_retval; /* Mach-specific initialization */ int machine_init(void); /* Systick & co. */ int _clock_interval; void SysTick_Hook(void); int SysTick_Interval(unsigned long interval); void SysTick_on(void); void SysTick_off(void); int SysTick_interval(unsigned long interval); void ktimer_init(void); int fpb_init(void); struct ktimer; int ktimer_add(uint32_t count, void (*handler)(uint32_t, void *), void *arg); int ktimer_del(int tid); void ktimer_cancel(struct ktimer *t); /* FS initializers */ void memfs_init(void); struct sysfs_fnode { struct fnode *fnode; int (*do_read)(struct sysfs_fnode *sfs, void *buf, int len); int (*do_write)(struct sysfs_fnode *sfs, const void *buf, int len); }; void sysfs_init(void); /* Scheduler */ #define NICE_DEFAULT (0) #define NICE_RT (0 - 20) #define NICE_MAX (20) /* Called by boot code. * Set system NVIC priorities and start systick. */ void frosted_scheduler_on(void); /* Forced preemption */ void task_preempt(void); void task_preempt_all(void); /* Execute/terminate a process. */ int scheduler_exec(struct vfs_info *v, void *args); int task_create(struct vfs_info *vfsi, void *arg, unsigned int prio); int task_kill(int pid, int signal); /* Getter functions. XXX refactor to thread id XXX */ char * scheduler_task_name(int pid); int scheduler_task_state(int pid); unsigned scheduler_stack_used(int pid); int scheduler_get_nice(int pid); /* Get the task object for the current task */ struct task *this_task(void); uint16_t this_task_getpid(void); /* Resume target task */ void task_resume(struct task *t); void task_resume_lock(struct task *t); void task_wakeup(struct task *t); /* Called by FPB when a task hits a breakpoint */ void task_hit_breakpoint(struct task *t); /* Functions targeting the Current (Running) task * */ int task_in_syscall(void); int task_running(void); int task_filedesc_add(struct fnode *f); int task_fd_setmask(int fd, uint32_t mask); uint32_t task_fd_getmask(int fd); uint32_t task_fd_set_flags(int fd, uint32_t flags); uint32_t task_fd_get_flags(int fd); uint32_t task_fd_set_off(struct fnode *fno, uint32_t off); uint32_t task_fd_get_off(struct fnode *fno); struct fnode *task_filedesc_get(int fd); int task_segfault(uint32_t addr, uint32_t instr, int flags); int task_fd_readable(int fd); int task_fd_writable(int fd); int task_filedesc_del(int fd); void task_suspend(void); /* Validate userspace pointers passed in the syscalls. */ int task_ptr_valid(const void *ptr); /* Slice off one unit from the task current run time */ int task_timeslice(void); struct fnode *task_getcwd(void); void task_chdir(struct fnode *f); /* Naming is not nice, implications of renaming is refactoring */ void sleepy_task_wakeup(uint32_t now, void *arg); /* Manage timer IDs */ int task_get_timer_id(void); void task_set_timer_id(int id); /* Semaphores */ int sem_wait(sem_t *s, struct timespec *t); int sem_trywait(sem_t *s); int sem_post(sem_t *s); int sem_init(sem_t *s, int val); int sem_destroy(sem_t *s); /* Mutexen */ int mutex_lock(mutex_t *s); int mutex_trylock(mutex_t *s); int mutex_unlock(mutex_t *s); mutex_t *mutex_init(); void mutex_destroy(mutex_t *s); #define schedule() *((uint32_t volatile *)0xE000ED04) = 0x10000000 /* Timers */ int Timer_on(unsigned int n); /* Tasklets */ void tasklet_add(void (*exe)(void*), void *arg); void check_tasklets(void); /* Kthreads */ struct task *kthread_create(void (routine)(void *), void *arg); void kthread_sleep_ms(uint32_t ms); void task_yield(void); void kthread_yield(void); int kthread_cancel(struct task *t); /* Modules */ struct module *MODS; int register_module(struct module *m); int unregister_module(struct module *m); struct module *module_search(char *name); /* System */ int sys_register_handler(uint32_t n, int (*_sys_c)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)); int syscall(uint32_t syscall_nr, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5); void syscalls_init(void); int task_is_interrupted(void); #define SYS_CALL_AGAIN_VAL (-1024) //#define SYS_CALL_AGAIN (task_is_interrupted()?(-EINTR):(SYS_CALL_AGAIN_VAL)) #define SYS_CALL_AGAIN SYS_CALL_AGAIN_VAL /* VFS */ void vfs_init(void); int fno_fullpath(struct fnode *f, char *dst, int len); void fno_use(struct fnode *f); #define FL_RDONLY 0x01 #define FL_WRONLY 0x02 #define FL_RDWR (FL_RDONLY | FL_WRONLY) #define FL_DIR 0x04 #define FL_INUSE 0x08 #define FL_TTY 0x10 #define FL_BLK 0x20 #define FL_EXEC 0x40 #define FL_LINK 0x80 #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #ifndef F_DUPFD #define F_DUPFD 0 #endif #ifndef F_GETFD #define F_GETFD 1 #endif #ifndef F_SETFD #define F_SETFD 2 #endif #ifndef F_GETFL #define F_GETFL 3 #endif #ifndef F_SETFL #define F_SETFL 4 #endif struct fnode { struct module *owner; char *fname; char *linkname; uint32_t flags; struct fnode *parent; struct fnode *children; void *priv; uint32_t dir_ptr; uint32_t size; int32_t usage_count; struct fnode *next; }; #define FNO_MOD_PRIV(fno,mod) (((fno == NULL)?NULL:((mod != fno->owner)?NULL:(fno->priv)))) #define FNO_BLOCKING(f) ((f->flags & O_NONBLOCK) == 0) struct mountpoint { struct fnode *target; struct mountpoint *next; }; struct fnode *fno_create(struct module *owner, const char *name, struct fnode *parent); struct fnode *fno_create_rdonly(struct module *owner, const char *name, struct fnode *parent); struct fnode *fno_create_wronly(struct module *owner, const char *name, struct fnode *parent); struct fnode *fno_mkdir(struct module *owner, const char *name, struct fnode *parent); void fno_unlink(struct fnode *fno); struct fnode *fno_search(const char *path); int vfs_symlink(char *file, char *link); /* Modules (for files/sockets) */ int register_addr_family(struct module *m, uint16_t family); #define FAMILY_UNIX 0x0001 #define FAMILY_INET 0x0002 #define FAMILY_DEV 0x0DEF #define FAMILY_FILE 0xFFFF #define MODNAME_SIZE 32 struct module { uint16_t family; char name[MODNAME_SIZE]; /* If this is a filesystem related module, it should probably define these */ int (*mount)(char *source, char *target, uint32_t flags, void *arg); int (*umount)(char *target, uint32_t flags); int (*mount_info)(struct fnode *fno, char *buf, int size); struct module_operations { /* Common module operations */ int (*read) (struct fnode *fno, void *buf, unsigned int len); int (*write)(struct fnode *fno, const void *buf, unsigned int len); int (*poll) (struct fnode *fno, uint16_t events, uint16_t *revents); int (*close)(struct fnode *fno); int (*ioctl)(struct fnode *fno, const uint32_t cmd, void *arg); /* Files only (NULL == socket) */ int (*open)(const char *path, int flags); int (*seek)(struct fnode *fno, int offset, int whence); int (*creat)(struct fnode *fno); int (*unlink)(struct fnode *fno); int (*truncate)(struct fnode *fno, unsigned int size); void * (*exe)(struct fnode *fno, void *arg); /* Sockets only (NULL == file) */ int (*socket)(int domain, int type, int protocol); int (*recvfrom)(int fd, void *buf, unsigned int len, int flags, struct sockaddr *addr, unsigned int *addrlen); int (*sendto)(int fd, const void *buf, unsigned int len, int flags, struct sockaddr *addr, unsigned int addrlen); int (*bind)(int fd, struct sockaddr *addr, unsigned int addrlen); int (*accept)(int fd, struct sockaddr *addr, unsigned int *addrlen); int (*connect)(int fd, struct sockaddr *addr, unsigned int addrlen); int (*listen)(int fd, int backlog); int (*shutdown)(int fd, uint16_t how); int (*setsockopt)(int sd, int level, int optname, void *optval, unsigned int optlen); int (*getsockopt)(int sd, int level, int optname, void *optval, unsigned int *optlen); int (*getsockname)(int fd, struct sockaddr *addr, unsigned int *addrlen); int (*getpeername)(int fd, struct sockaddr *addr, unsigned int *addrlen); /* Terminal operations */ void (*tty_attach)(struct fnode *fno, int pid); int (*tty_getsid)(struct fnode *fno); int (*tcsetattr)(int td, int opts, const struct termios *tp); int (*tcgetattr)(int td, struct termios *tp); /* Block device operations */ int (*block_read)(struct fnode *fno, void *buf, uint32_t sector, int offset, int count); int (*block_write)(struct fnode *fno, const void *buf, uint32_t sector, int offset, int count); } ops; struct module *next; }; void task_run(void); void kernel_task_init(void); #define kalloc(x) f_malloc(MEM_KERNEL,x) #define task_space_alloc(x) f_malloc(MEM_TASK, x) #define kcalloc(x,y) f_calloc(MEM_KERNEL,x,y) #define krealloc(x,y) f_realloc(MEM_KERNEL,x,y) #define kfree f_free #define task_space_free f_free #define F_MALLOC_OVERHEAD 24 int mem_lock(void); int mem_trylock(void); void mem_unlock(void); uint32_t mem_stats_frag(int pool); int fmalloc_owner(const void *ptr); int fmalloc_chown(const void *ptr, uint16_t pid); /* Helper defined by sysfs.c */ int ul_to_str(unsigned long n, char *s); int sysfs_register(char *name, char *dir, int (*do_read)(struct sysfs_fnode *sfs, void *buf, int len), int (*do_write)(struct sysfs_fnode *sfs, const void *buf, int len) ); void sysfs_lock(void); void sysfs_unlock(void); void frosted_tcpip_wakeup(void); void pico_lock_init(void); int pico_trylock_kernel(void); void pico_lock(void); int pico_trylock(void); void pico_unlock(void); void frost(uint32_t interval); void defrost(void); #endif /* BSP_INCLUDED_H */ ================================================ FILE: kernel/fs/fatfs.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * Authors: brabo * */ #include #include "string.h" #include "frosted.h" static struct module mod_fatfs = { }; struct fatfs_disk { struct fnode *blockdev; struct fnode *mountpoint; struct fatfs *fs; }; struct fatfs_priv { uint32_t sclust; uint32_t cclust; uint32_t sect; uint32_t off; uint32_t dirsect; struct fatfs_disk *fsd; uint32_t *fat; uint32_t flags; }; struct fatfs { int fd; uint8_t win[512]; uint32_t bsect; uint8_t type; uint16_t bps; uint8_t spc; uint32_t database; uint32_t fatbase; uint32_t dirbase; uint32_t n_fatent; uint32_t nclusts; uint8_t mounted; }; struct fatfs_dir { uint8_t *fn; uint32_t sclust; uint32_t cclust; uint32_t sect; uint32_t off; uint32_t dirsect; uint32_t attr; uint32_t fsize; }; #ifdef CONFIG_FAT32 # define FATFS_FAT32 1 #endif #ifndef FATFS_FAT32 # define FATFS_FAT32 0 #endif /* Macro proxies for disk operations */ #define disk_read(f,b,s,o,l) f->blockdev->owner->ops.block_read(f->blockdev,b,s,o,l) #define disk_write(f,b,s,o,l) f->blockdev->owner->ops.block_write(f->blockdev,b,s,o,l) /* BIOS Parameter Block */ #define BPB_BPS 11 #define BPB_SPC 13 #define BPB_RSVD_SEC 14 #define BPB_NUMFATS 16 #define BPB_ROOTENTS 17 #define BPB_TOTSEC16 19 #define BPB_FATSz16 22 #define BPB_TOTSEC32 32 #define BPB_FATSz32 36 #define BPB_ROOTCLUS 44 /* Boot sector */ #define BS_JMPBOOT 0 #define BS_FSTYPE 54 #define BS_FSTYPE32 82 #define BS_MBR 446 #define BS_BS 454 #define BS_55AA 510 #define DEFBPS 512 #define FAT_SIG 0xAA55 /* Directory entries */ #define DIR_NAME 0 #define DIR_ATTR 11 #define DIR_SCLUST_HI 20 #define DIR_SCLUST_LO 26 #define DIR_FSIZE 28 #define AM_DIR 0x10 #define FAT12 1 #define FAT16 2 #define FAT32 3 #define EOC32 0x0FFFFFF8 #define DDEM 0xE5 #define PATHN_MAX 256 #define SFN_MAX 12 /* Entry sizes in bytes */ #define FATENT_SIZE 4 #define DIRENT_SIZE 0x20 #define LD_WORD(ptr) (uint16_t)(*(uint16_t *)(ptr)) #define LD_DWORD(ptr) (uint32_t)(*(uint32_t *)(ptr)) #define CLUST2SECT(f, c) (((c - 2) * f->spc + f->database)) int fatfs_truncate(struct fnode *fno, unsigned int len); static void st_word(uint8_t *ptr, uint16_t val) /* Store a 2-byte word in little-endian */ { *ptr++ = (uint8_t)val; val >>= 8; *ptr++ = (uint8_t)val; } static void st_dword(uint8_t *ptr, uint32_t val) /* Store a 4-byte word in little-endian */ { *ptr++ = (uint8_t)val; val >>= 8; *ptr++ = (uint8_t)val; val >>= 8; *ptr++ = (uint8_t)val; val >>= 8; *ptr++ = (uint8_t)val; } static int check_fs(struct fatfs_disk *fsd) { if (!fsd) return -EINVAL; struct fatfs *fs = fsd->fs; if (LD_WORD(fs->win + BS_55AA) != FAT_SIG) { return -ENOMEDIUM; } if (fs->win[BS_JMPBOOT] == 0xE9 || (fs->win[BS_JMPBOOT] == 0xEB && fs->win[BS_JMPBOOT + 2] == 0x90)) { if ((LD_DWORD(fs->win + BS_FSTYPE32) == 0x33544146) && (*(fs->win + BS_FSTYPE32 + 4) == '2')) { fs->type = FAT32; return 0; } } return -EMEDIUMTYPE; } int get_fat(struct fatfs_disk *fsd, int clust) { if (!fsd) return -EINVAL; struct fatfs *fs = fsd->fs; if (clust < 2 || clust >= fs->n_fatent) { /* Range check */ return -EINVAL; } switch(fs->type) { case FAT12: break; case FAT16: break; case FAT32: if (disk_read(fsd, fs->win, (fs->fatbase + (clust / (fs->bps / FATENT_SIZE))), 0, fs->bps) < 0) break; return (LD_DWORD(fs->win + ((clust * FATENT_SIZE) & (fs->bps - 1))) & 0x0FFFFFFF); } return -EMEDIUMTYPE; } int set_fat(struct fatfs_disk *fsd, uint32_t clust, uint32_t val) { if (!fsd) return -EINVAL; struct fatfs *fs = fsd->fs; if (clust < 2 || clust >= fs->n_fatent) { /* Range check */ return -EINVAL; } switch(fs->type) { case FAT12: break; case FAT16: break; case FAT32: if (disk_read(fsd, fs->win, (fs->fatbase + (clust / (fs->bps / FATENT_SIZE))), 0, fs->bps) < 0) break; st_dword((fs->win + ((clust * FATENT_SIZE) & (fs->bps - 1))), (uint32_t)(val & 0x0FFFFFFF)); disk_write(fsd, fs->win, (fs->fatbase + (clust / (fs->bps / FATENT_SIZE))), 0, fs->bps); return 0; } return -EMEDIUMTYPE; } static int get_clust(struct fatfs *fs, uint8_t *dir) { if (!fs || !dir) return -EINVAL; int clst = 0; if (fs->type == FAT32) { clst = LD_WORD(dir + DIR_SCLUST_HI); clst <<= 16; } clst |= LD_WORD(dir + DIR_SCLUST_LO); return clst; } int set_clust(struct fatfs *fs, uint8_t *dir, uint32_t clust) { if (!fs || !dir) return -EINVAL; if (fs->type == FAT32) { st_word((dir + DIR_SCLUST_HI), (clust >> 16)); } st_word((dir + DIR_SCLUST_LO), (clust & 0xFFFF)); return 0; } static int walk_fat(struct fatfs_disk *fsd) { if (!fsd) return -EINVAL; int fat; int clust = 2; while (2 > 1) { fat = get_fat(fsd, clust); if (!fat) break; clust++; } return clust; } static int init_fat(struct fatfs_disk *fsd) { if (!fsd) return -EINVAL; struct fatfs *fs = fsd->fs; int clust = walk_fat(fsd); st_dword((fs->win + ((clust * FATENT_SIZE) & (fs->bps - 1))), 0x0FFFFFFF); disk_write(fsd, fs->win, (fs->fatbase + (clust / (fs->bps / FATENT_SIZE))), 0, fs->bps); return clust; } static int dir_rewind(struct fatfs *fs, struct fatfs_dir *dj) { if (!fs || !dj) return -EINVAL; if (dj->cclust == 1 || dj->cclust >= fs->n_fatent) return -EINVAL; if (!dj->cclust) dj->sect = fs->dirbase; else dj->sect = CLUST2SECT(fs, dj->cclust); dj->off = 0 - DIRENT_SIZE; return 0; } static int dir_read(struct fatfs_disk *fsd, struct fatfs_dir *dj) { if (!fsd || !dj) return -EINVAL; struct fatfs *fs = fsd->fs; dj->off += DIRENT_SIZE; if (dj->off >= fs->bps) { dj->sect++; dj->off = 0; } disk_read(fsd, fs->win, (dj->sect), 0, fs->bps); /* have to check cluster borders! */ while (2 > 1) { uint8_t *off = fs->win + dj->off; if (!*off) /* Free FAT entry, no more FAT entries! */ return -2; if (off[0] == DDEM) { dj->off += DIRENT_SIZE; continue; } if (*(off + DIR_ATTR) & 0x0F) { /* LFN entry */ dj->off += DIRENT_SIZE; continue; } int i; char *p = dj->fn; memset(dj->fn, 0x00, (SFN_MAX + 1)); char c; for (i = 0; i < 8; i++) { /* Copy file name body */ c = off[i]; if (c == ' ') break; if (c == 0x05) c = 0xE5; *p++ = c; } if (off[8] != ' ') { /* Copy file name extension */ *p++ = '.'; for (i = 8; i < 11; i++) { c = off[i]; if (c == ' ') break; *p++ = c; } } dj->attr = *(off + DIR_ATTR); dj->sclust = get_clust(fs, off); dj->fsize = LD_DWORD(off + DIR_FSIZE); dj->dirsect = dj->sect; break; } return 0; } static int add_dir(struct fatfs *fs, struct fatfs_dir *dj, char *name) { if (!fs || !dj || !name) return -EINVAL; int nlen = strlen(name); if (nlen > SFN_MAX) return -ENAMETOOLONG; memset((fs->win + dj->off), 0, DIRENT_SIZE); memset((fs->win + dj->off), ' ', 11); int len = 0; while (len < nlen) { *(fs->win + dj->off + len) = name[len++]; } *(fs->win + dj->off + DIR_ATTR) = DIRENT_SIZE; st_dword((fs->win + dj->off + DIR_FSIZE), 0); dj->dirsect = dj->sect; return 0; } static char *relative_path(struct fatfs_disk *f, char *abs) { if (!f || !abs) return NULL; return (abs + strlen(f->mountpoint->fname) + 1); } static void fatfs_populate(struct fatfs_disk *f, char *path, uint32_t clust) { if (!f || !path) return; char fbuf[SFN_MAX + 1]; struct fatfs_priv *priv; struct fatfs_dir dj; struct fnode *parent; char fpath[PATHN_MAX]; fno_fullpath(f->mountpoint, fpath, PATHN_MAX); if (path && strlen(path) > 0) { if (path[0] != '/') strcat(fpath, "/"); strcat(fpath, path); } parent = fno_search(fpath); parent->priv = (void *)kalloc(sizeof(struct fatfs_priv)); ((struct fatfs_priv *)parent->priv)->fsd = f; dj.fn = fbuf; dj.cclust = clust; dj.sclust = clust; dj.off = 0 - DIRENT_SIZE; dir_rewind(f->fs, &dj); while(dir_read(f, &dj) == 0) { if (!strncmp(dj.fn, ".", 2) || !strncmp(dj.fn, "..", 3)) continue; struct fnode *newdir; if (dj.attr & AM_DIR) newdir = fno_mkdir(&mod_fatfs, dj.fn, parent); else newdir = fno_create(&mod_fatfs, dj.fn, parent); if (!newdir) continue; newdir->priv = (void *)kalloc(sizeof(struct fatfs_priv)); if (!newdir->priv) { fno_unlink(newdir); continue; } priv = newdir->priv; priv->sclust = dj.sclust; priv->cclust = dj.cclust; priv->sect = dj.sect; priv->fsd = f; priv->off = dj.off; priv->dirsect = dj.dirsect; newdir->size = dj.fsize; int i = 0; uint32_t nclust = newdir->size / (f->fs->spc * f->fs->bps); priv->fat = kcalloc(sizeof (uint32_t), nclust + 1); uint32_t tmpclust = priv->sclust; priv->fat[i++] = tmpclust; while (nclust > 0) { priv->fat[i] = get_fat(f, tmpclust); tmpclust = priv->fat[i++]; nclust--; } if (dj.attr & AM_DIR) { char fullpath[PATHN_MAX]; strncpy(fullpath, fpath, PATHN_MAX); strcat(fullpath, "/"); strcat(fullpath, dj.fn); path = relative_path(f, fullpath); fatfs_populate(f, path, get_clust(f->fs, (f->fs->win + dj.off))); } } } int fatfs_mount(char *source, char *tgt, uint32_t flags, void *arg) { if (!source || !tgt) return -EINVAL; struct fnode *tgt_dir = NULL; struct fnode *src_dev = NULL; struct fatfs_disk *fsd; tgt_dir = fno_search(tgt); src_dev = fno_search(source); if (!tgt_dir) return -ENOENT; if ((tgt_dir->flags & FL_DIR) == 0) return -ENOTDIR; if (!src_dev || !(src_dev ->owner) || ((src_dev->flags & FL_BLK) == 0)) { /* Invalid block device. */ return -ENOENT; } /* Initialize file system to disk association */ fsd = kcalloc(sizeof(struct fatfs_disk), 1); if (!fsd) return -ENOMEM; /* Associate the disk device */ fsd->blockdev = src_dev; /* Associate a newly created fat filesystem */ fsd->fs = kcalloc(sizeof(struct fatfs), 1); if (!fsd->fs) { kfree(fsd); return -ENOMEM; } struct fatfs *fs = fsd->fs; /* do we still need this?? */ fs->mounted = 0; /* Associate the mount point */ fsd->mountpoint = tgt_dir; tgt_dir->owner = &mod_fatfs; fs->bsect = 0; disk_read(fsd, fs->win, fs->bsect, 0, DEFBPS); if (check_fs(fsd) == -EMEDIUMTYPE) { fs->bsect = LD_WORD(fs->win + BS_BS); disk_read(fsd, fs->win, fs->bsect, 0, DEFBPS); if (check_fs(fsd) < 0) { goto fail; } } uint8_t num_fats = 0; uint16_t root_ents = 0, rsvd_sec = 0; uint32_t root_secs = 0, fatsz = 0, totsec = 0, datasec = 0; fs->bps = LD_WORD(fs->win + BPB_BPS); fs->spc = fs->win[BPB_SPC]; root_ents = LD_WORD(fs->win + BPB_ROOTENTS); root_secs = ((root_ents * 32) + (fs->bps -1)) / fs->bps; fatsz = LD_WORD(fs->win + BPB_FATSz16); if (!fatsz) fatsz = LD_DWORD(fs->win + BPB_FATSz32); num_fats = fs->win[BPB_NUMFATS]; rsvd_sec = LD_WORD(fs->win + BPB_RSVD_SEC); fs->database = rsvd_sec + (num_fats * fatsz) + root_secs; fs->database += fs->bsect; totsec = LD_WORD(fs->win + BPB_TOTSEC16); if (!totsec) totsec = LD_DWORD(fs->win + BPB_TOTSEC32); datasec = totsec - (rsvd_sec + (num_fats * fatsz) + root_secs); fs->nclusts = datasec / fs->spc; fs->fatbase = rsvd_sec + fs->bsect; fs->dirbase = CLUST2SECT(fs, LD_DWORD(fs->win + BPB_ROOTCLUS)); /* FAT type determination */ if (fs->nclusts < 4085) fs->type = FAT12; else if (fs->nclusts < 65525) fs->type = FAT16; else fs->type = FAT32; fs->n_fatent = fs->nclusts + 2; fatfs_populate(fsd, "", 0); fs->mounted = 1; return 0; fail: kfree(fsd->fs); kfree(fsd); return -ENOMEDIUM; } int fatfs_open(const char *path, int flags) { struct fnode *fno = fno_search(path); struct fatfs_priv *priv = (struct fatfs_priv *)fno->priv; int ret; if (!path) return -EINVAL; fno = fno_search(path); if (!fno) return -ENOENT; priv = (struct fatfs_priv *)fno->priv; priv->flags = flags; if (flags & O_TRUNC) { fatfs_truncate(fno, 0); } ret = task_filedesc_add(fno); return ret; } static int dir_find(struct fatfs_disk *fsd, struct fatfs_dir *dj, char *path) { if (!fsd || !dj || !path) return -EINVAL; while (dir_read(fsd, dj) == 0) { if (!strncmp(dj->fn, path, SFN_MAX)) { dj->off; uint32_t fat = get_fat(fsd, dj->sclust); dj->sect = CLUST2SECT(fsd->fs, dj->sclust); dj->cclust = dj->sclust; return 0; } } return -ENOENT; } static int follow_path(struct fatfs_disk *fsd, struct fatfs_dir *dj, char *path) { if (!fsd || !dj || !path) return -EINVAL; int res; if (!strncmp(path, "/mnt", 4)) path += 4; while (*path == ' ') path++; if (*path == '/') path++; dj->cclust = 0; res = dir_rewind(fsd->fs, dj); if (*path < ' ') { dj->off = 0 - DIRENT_SIZE; return res; } dj->off = 0 - DIRENT_SIZE; do { char tpath[SFN_MAX + 1]; char *tpathp = tpath; while ((*path != '/') && (*path != ' ') && (*path != 0x00)) { *tpathp++ = *path++; } *tpathp = 0x00; res = dir_find(fsd, dj, tpath); if (*path == '/') path++; } while ((*path != ' ') && (*path != 0x00)); return res; } int fatfs_creat(struct fnode *fno) { if (!fno || !fno->parent || !fno->parent->priv) return -EINVAL; if (!((struct fatfs_priv *)fno->parent->priv)->fsd->fs->mounted) return -EINVAL; struct fatfs_dir dj; char fbuf[SFN_MAX + 1]; char *path = kalloc(PATHN_MAX * sizeof (char)); fno_fullpath(fno, path, PATHN_MAX); struct fatfs_priv *priv = (struct fatfs_priv *)fno->priv; if (!priv) { priv = (void *)kalloc(sizeof (struct fatfs_priv)); priv->fsd = ((struct fatfs_priv *)fno->parent->priv)->fsd; } struct fatfs *fs = priv->fsd->fs; struct fatfs_disk *fsd = priv->fsd; fno->priv = priv; dj.fn = fbuf; dj.off = 0 - DIRENT_SIZE; uint32_t clust = init_fat(fsd); follow_path(fsd, &dj, path); while ((*path != ' ') && (*path != 0x00)) path++; while (*path != '/') path--; path++; int ret = add_dir(fs, &dj, path); set_clust(fs, (fs->win + dj.off), clust); disk_write(fsd, fs->win, dj.sect, 0, fs->bps); priv->sclust = priv->cclust = clust; priv->fat = kcalloc(3, sizeof (uint32_t)); priv->fat[0] = priv->sclust; priv->sect = CLUST2SECT(fs, priv->cclust); priv->off = dj.off; fno->size = 0; priv->dirsect = dj.dirsect; return 0; } int fatfs_read(struct fnode *fno, void *buf, unsigned int len) { if (!fno || !fno->priv) return -EINVAL; struct fatfs_priv *priv = (struct fatfs_priv *)fno->priv; struct fatfs_disk *fsd = priv->fsd; struct fatfs *fs = fsd->fs; int r_len = 0, sect = 0, off = 0, clust = 0; uint32_t cur_off = task_fd_get_off(fno); off = cur_off; sect = off / fs->bps; off = off & (fs->bps - 1); clust = sect / fs->spc; sect = sect & (fs->spc - 1); priv->cclust = priv->fat[clust]; priv->sect = CLUST2SECT(fs, priv->cclust); while ((r_len < len) && (cur_off < fno->size)) { int r = len - r_len; if (r > fs->bps) r = fs->bps; if ((r == fs->bps) && off > 0) r -= off; if (cur_off + r > fno->size) r = fno->size - cur_off; /* XXX: use returned value, maybe lower level returned less.. */ disk_read(fsd, ((uint8_t *)buf + r_len), (priv->sect + sect), off, r); r_len += r; off += r; cur_off += r; task_fd_set_off(fno, cur_off); if ((r_len < len) && (off == fs->bps) && (cur_off < fno->size)) { sect++; if ((sect) >= fs->spc) { clust++; priv->cclust = priv->fat[clust]; priv->sect = CLUST2SECT(fs, priv->cclust); sect = 0; } } off = 0; } return r_len; } int fatfs_write(struct fnode *fno, const void *buf, unsigned int len) { if (!fno || !fno->priv) return -EINVAL; struct fatfs_priv *priv = (struct fatfs_priv *)fno->priv; struct fatfs_disk *fsd = priv->fsd; struct fatfs *fs = fsd->fs; uint32_t cur_off; int w_len = 0, sect = 0, clust = 0, off = 0; cur_off = task_fd_get_off(fno); if (priv->flags & O_APPEND) { off = fno->size; cur_off = off; } else { off = cur_off; } task_fd_set_off(fno, cur_off); sect = off / fs->bps; off = off & (fs->bps - 1); clust = sect / fs->spc; sect = sect & (fs->spc - 1); priv->cclust = priv->fat[clust]; priv->sect = CLUST2SECT(fs, priv->cclust); while (w_len < len) { int r = len - w_len; if (r > fs->bps) r = fs->bps; if ((r == fs->bps) && off > 0) r -= off; disk_write(fsd, ((uint8_t *)buf) + w_len, (priv->sect + sect), off, r); w_len += r; off += r; cur_off += r; task_fd_set_off(fno, cur_off); if ((w_len < len) && (off == fs->bps)) { sect++; if ((sect) >= fs->spc) { clust++; sect = 0; if (cur_off <= fno->size) { priv->cclust = priv->fat[clust]; } else { uint32_t tempclust = priv->cclust; priv->cclust = init_fat(fsd); uint32_t *tmp = krealloc(priv->fat, ((sizeof (uint32_t)) * (clust + 1))); if (!tmp) return -EAGAIN; priv->fat = tmp; priv->fat[clust] = priv->cclust; set_fat(fsd, tempclust, priv->cclust); } priv->sect = CLUST2SECT(fs, priv->cclust); } } off = 0; } if (cur_off > fno->size) { fno->size = cur_off; disk_read(fsd, fs->win, priv->dirsect, 0, fs->bps); st_dword((fs->win + priv->off + DIR_FSIZE), (uint32_t)fno->size); disk_write(fsd, fs->win, priv->dirsect, 0, fs->bps); } return w_len; } int fatfs_seek(struct fnode *fno, int off, int whence) { int new_off; if (!fno) return -EINVAL; switch (whence) { case SEEK_CUR: new_off = task_fd_get_off(fno) + off; break; case SEEK_SET: new_off = off; break; case SEEK_END: new_off = fno->size + off; break; default: return -EINVAL; } if (new_off < 0) new_off = 0; if (new_off > fno->size) return -ESPIPE; task_fd_set_off(fno, new_off); return new_off; } int fatfs_truncate(struct fnode *fno, unsigned int len) { if (!fno) return -EINVAL; int new_size; new_size = len; if (new_size < 0) new_size = 0; if (new_size > fno->size) return -ESPIPE; fno->size = new_size; return 0; } int fatfs_unlink(struct fnode *fno) { if (!fno || !fno->priv) return -EINVAL; struct fatfs_priv *priv = (struct fatfs_priv *)fno->priv; struct fatfs_disk *fsd = priv->fsd; struct fatfs *fs = fsd->fs; disk_read(fsd, fs->win, priv->dirsect, 0, fs->bps); fs->win[priv->off] = DDEM; disk_write(fsd, fs->win, priv->dirsect, 0, fs->bps); } int fatfs_close(struct fnode *fno) { if (!fno) return -EINVAL; return 0; } int fatfs_init(void) { mod_fatfs.family = FAMILY_FILE; strcpy(mod_fatfs.name,"fatfs"); mod_fatfs.mount = fatfs_mount; mod_fatfs.ops.open = fatfs_open; mod_fatfs.ops.creat = fatfs_creat; mod_fatfs.ops.read = fatfs_read; mod_fatfs.ops.write = fatfs_write; mod_fatfs.ops.seek = fatfs_seek; mod_fatfs.ops.truncate = fatfs_truncate; mod_fatfs.ops.close = fatfs_close; mod_fatfs.ops.unlink = fatfs_unlink; register_module(&mod_fatfs); return 0; } ================================================ FILE: kernel/fs/fatfs.h ================================================ #include "frosted.h" #ifndef FATFS_INC #define FATFS_INC #ifdef CONFIG_FATFS int fatfs_init(void); #else #define fatfs_init() ((-ENOENT)) #endif #endif ================================================ FILE: kernel/fs/memfs.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "string.h" static struct module mod_memfs; struct memfs_fnode { struct fnode *fnode; uint8_t *content; }; static int memfs_read(struct fnode *fno, void *buf, unsigned int len) { struct memfs_fnode *mfno; uint32_t off; if (len <= 0) return len; mfno = FNO_MOD_PRIV(fno, &mod_memfs); if (!mfno) return -ENOENT; off = task_fd_get_off(fno); if (fno->size <= off) return 0; if (len > (fno->size - off)) len = fno->size - off; memcpy(buf, mfno->content + off, len); off+=len; task_fd_set_off(fno, off); return len; } static int memfs_write(struct fnode *fno, const void *buf, unsigned int len) { struct memfs_fnode *mfno; uint32_t off; if (len <= 0) return len; mfno = FNO_MOD_PRIV(fno, &mod_memfs); if (!mfno) return -ENOENT; off = task_fd_get_off(fno); if (fno->size < (off+len)) { mfno->content = krealloc(mfno->content, off + len); } if (!mfno->content) return -ENOMEM; memcpy(mfno->content + off, buf, len); off += len; if (fno->size < off) fno->size = off; task_fd_set_off(fno, off); return len; } static int memfs_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { *revents = events; return 1; } static int memfs_seek(struct fnode *fno, int off, int whence) { struct memfs_fnode *mfno; int new_off; mfno = FNO_MOD_PRIV(fno, &mod_memfs); if (!mfno) return -1; switch(whence) { case SEEK_CUR: new_off = task_fd_get_off(fno) + off; break; case SEEK_SET: new_off = off; break; case SEEK_END: new_off = fno->size + off; break; default: return -EINVAL; } if (new_off < 0) new_off = 0; if (new_off > fno->size) { mfno->content = krealloc(mfno->content, new_off); memset(mfno->content + fno->size, 0, new_off - fno->size); fno->size = new_off; } task_fd_set_off(fno, new_off); return new_off; } static int memfs_close(struct fnode *fno) { struct memfs_fnode *mfno; mfno = FNO_MOD_PRIV(fno, &mod_memfs); if (!mfno) return -1; return 0; } static int memfs_creat(struct fnode *fno) { struct memfs_fnode *mfs = kalloc(sizeof(struct memfs_fnode)); if (mfs) { mfs->fnode = fno; mfs->content = NULL; fno->priv = mfs; return 0; } return -1; } static int memfs_unlink(struct fnode *fno) { struct memfs_fnode *mfno; if (!fno) return -ENOENT; mfno = fno->priv; if (mfno && mfno->content) kfree(mfno->content); kfree(mfno); return 0; } static int memfs_truncate(struct fnode *fno, unsigned int newsize) { struct memfs_fnode *mfno; if (!fno) return -ENOENT; mfno = fno->priv; if (mfno) { if (fno->size <= newsize) { /* Nothing to do here. */ return 0; } if (newsize == 0) { fno->size = 0; kfree(mfno->content); mfno->content = NULL; } else { mfno->content = krealloc(mfno->content, newsize); fno->size = newsize; } return 0; } return -EFAULT; } static int memfs_mount(char *source, char *tgt, uint32_t flags, void *arg) { struct fnode *tgt_dir = NULL; /* Source must be NULL */ if (source) return -1; /* Target must be a valid dir */ if (!tgt) return -1; tgt_dir = fno_search(tgt); if (!tgt_dir || ((tgt_dir->flags & FL_DIR) == 0)) { /* Not a valid mountpoint. */ return -1; } /* TODO: Check empty dir if (tgt_dir->children) { return -1; } */ tgt_dir->owner = &mod_memfs; return 0; } void memfs_init(void) { mod_memfs.family = FAMILY_FILE; strcpy(mod_memfs.name,"memfs"); mod_memfs.mount = memfs_mount; mod_memfs.ops.read = memfs_read; mod_memfs.ops.poll = memfs_poll; mod_memfs.ops.write = memfs_write; mod_memfs.ops.seek = memfs_seek; mod_memfs.ops.creat = memfs_creat; mod_memfs.ops.unlink = memfs_unlink; mod_memfs.ops.close = memfs_close; mod_memfs.ops.truncate = memfs_truncate; register_module(&mod_memfs); } ================================================ FILE: kernel/fs/sysfs.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "string.h" #include "scheduler.h" #include "gpio.h" #include "lowpower.h" #define MAX_SYSFS_BUFFER 1024 static struct fnode *sysfs; static struct module mod_sysfs; static mutex_t *sysfs_mutex = NULL; extern struct mountpoint *MTAB; extern struct f_malloc_stats f_malloc_stats[5]; void sysfs_lock(void) { if (sysfs_mutex) mutex_lock(sysfs_mutex); } void sysfs_unlock(void) { if (sysfs_mutex) mutex_unlock(sysfs_mutex); } static int sysfs_read(struct fnode *fno, void *buf, unsigned int len) { struct sysfs_fnode *mfno; if (len <= 0) return len; mfno = FNO_MOD_PRIV(fno, &mod_sysfs); if (!mfno) return -1; if (mfno->do_read) { return mfno->do_read(mfno, buf, len); } return -1; } static int sysfs_write(struct fnode *fno, const void *buf, unsigned int len) { struct sysfs_fnode *mfno; if (len <= 0) return len; mfno = FNO_MOD_PRIV(fno, &mod_sysfs); if (!mfno) return -1; if (mfno->do_write) { return mfno->do_write(mfno, buf, len); } return -1; } static int sysfs_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { *revents = events; return 1; } static int sysfs_close(struct fnode *fno) { struct sysfs_fnode *mfno; mfno = FNO_MOD_PRIV(fno, &mod_sysfs); if (!mfno) return -1; return 0; } int ul_to_str(unsigned long n, char *s) { int maxlen = 10; int i; int q = 1; if (n == 0) { s[0] = '0'; s[1] = '\0'; return 1; } for (i = 0; i <= maxlen; i++) { if ((n / q) == 0) break; q*=10; } q /= 10; s[i] = '\0'; maxlen = i; for (i = 0; i < maxlen; i++) { int c; c = (n / q); s[i] = '0' + c; n -= (c * q); q /= 10; } return maxlen; } int nice_to_str(int8_t n, char *s) { int i = 0; if (n == 0) { s[0] = '0'; s[1] = '\n'; return 1; } if (n == NICE_RT) { s[0] = 'R'; s[1] = 'T'; s[2] = '\0'; return 2; } if (n < 0) { s[i++] = '-'; n = 0 - n; } if (n > 20) { s[0] = 'E'; s[1] = 'R'; s[2] = 'R'; s[3] = '\0'; return 3; } if (n >= 10) { s[i++] = (n / 10) + '0'; } s[i++] = (n % 10) + '0'; s[i++] = '\0'; return (i - 1); } int sysfs_time_read(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; uint32_t off = task_fd_get_off(fno); if (off > 0) return -1; off += ul_to_str(jiffies, res); res[off++] = '\r'; res[off++] = '\n'; res[off] = '\0'; task_fd_set_off(fno, off); return off; } static uint32_t strtou32(const char *ptr) { long long val = 0; while(*ptr) { int v = *ptr; if ('0' <= v && v <= '9') v -= '0'; val = val * 10 + v; ptr++; } return val; } static int sysfs_suspend_write(struct sysfs_fnode *sfs, const void *buf, int len) { uint32_t interval = strtou32(buf); if (len >= 1 && interval >= 1) lowpower_sleep(0, interval); return len; } static int sysfs_standby_write(struct sysfs_fnode *sfs, const void *buf, int len) { uint32_t interval = strtou32(buf); if (len >= 1 && interval >= 1) lowpower_sleep(1, interval); return len; } static int gpio_basename(const uint32_t base, char *name) { switch(base) { #if defined(STM32F4) || defined(STM32F7) case GPIOA: strcpy(name,"GPIOA"); return 5; case GPIOB: strcpy(name,"GPIOB"); return 5; case GPIOC: strcpy(name,"GPIOC"); return 5; case GPIOD: strcpy(name,"GPIOD"); return 5; case GPIOE: strcpy(name,"GPIOE"); return 5; case GPIOF: strcpy(name,"GPIOF"); return 5; case GPIOG: strcpy(name,"GPIOG"); return 5; case GPIOH: strcpy(name,"GPIOH"); return 5; case GPIOI: strcpy(name,"GPIOI"); return 5; case GPIOJ: strcpy(name,"GPIOJ"); return 5; case GPIOK: strcpy(name,"GPIOK"); return 5; #endif default: strcpy(name,"N/A"); return 3; } } #if defined(STM32F4) || defined(STM32F7) int sysfs_pins_read(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; static char *txt; static uint32_t off; int i; int stack_used; char *name; int p_state; int nice; const char legend[]="Base\tPin\tMode\tDrive\tSpeed\tTrigger\tOwner\r\n"; struct dev_gpio *g = Gpio_list; uint32_t pin_n = 0; uint32_t cur_off = task_fd_get_off(fno); if (cur_off == 0) { mutex_lock(sysfs_mutex); txt = kalloc((1 + gpio_list_len()) * 80); if (!txt) return -1; off = 0; strcpy(txt, legend); off += strlen(legend); while (g) { /* Base */ off += gpio_basename(g->base, txt + off); txt[off++] = '\t'; /* Pin */ pin_n = 0; while ((1 << pin_n) != g->pin) pin_n ++; off += ul_to_str(pin_n, txt + off); txt[off++] = '\t'; /* Mode */ switch (g->mode) { case GPIO_MODE_OUTPUT: txt[off++] = 'O'; txt[off++] = 'U'; txt[off++] = 'T'; break; case GPIO_MODE_INPUT: txt[off++] = 'I'; txt[off++] = 'N'; break; case GPIO_MODE_ANALOG: txt[off++] = 'A'; txt[off++] = 'N'; txt[off++] = 'A'; txt[off++] = 'L'; txt[off++] = 'O'; txt[off++] = 'G'; break; case GPIO_MODE_AF: txt[off++] = 'A'; txt[off++] = 'L'; txt[off++] = 'T'; off += ul_to_str(g->af, txt + off); break; } txt[off++] = '\t'; /* Drive */ if (g->optype == GPIO_OTYPE_OD) { txt[off++] = 'O'; txt[off++] = 'D'; txt[off++] = 'r'; txt[off++] = 'a'; txt[off++] = 'i'; txt[off++] = 'n'; } else { switch(g->pullupdown) { case GPIO_PUPD_PULLUP: txt[off++] = 'P'; txt[off++] = 'u'; txt[off++] = 'l'; txt[off++] = 'l'; txt[off++] = 'U'; txt[off++] = 'p'; break; case GPIO_PUPD_PULLDOWN: txt[off++] = 'P'; txt[off++] = 'u'; txt[off++] = 'l'; txt[off++] = 'l'; txt[off++] = 'D'; txt[off++] = 'w'; break; default: txt[off++] = 'N'; txt[off++] = 'o'; txt[off++] = 'n'; txt[off++] = 'e'; break; } } txt[off++] = '\t'; /* Speed */ /* FIXME: if you want to see output speed. */ txt[off++] = '-'; txt[off++] = '\t'; /* Trigger */ switch (g->trigger) { case GPIO_TRIGGER_RAISE: txt[off++] = 'R'; txt[off++] = 'a'; txt[off++] = 'i'; txt[off++] = 's'; txt[off++] = 'e'; break; case GPIO_TRIGGER_FALL: txt[off++] = 'F'; txt[off++] = 'a'; txt[off++] = 'l'; txt[off++] = 'l'; break; case GPIO_TRIGGER_TOGGLE: txt[off++] = 'T'; txt[off++] = 'o'; txt[off++] = 'g'; txt[off++] = 'g'; txt[off++] = 'l'; txt[off++] = 'e'; break; default: txt[off++] = 'N'; txt[off++] = 'o'; txt[off++] = 'n'; txt[off++] = 'e'; break; } txt[off++] = '\t'; /* Owner's name */ strcpy(txt + off, g->owner->name); off += strlen(g->owner->name); txt[off++] = '\r'; txt[off++] = '\n'; g = g->next; } txt[off++] = '\0'; } cur_off = task_fd_get_off(fno); if (off == cur_off) { kfree(txt); mutex_unlock(sysfs_mutex); return -1; } if (len > (off - cur_off)) { len = off - cur_off; } memcpy(res, txt + cur_off, len); task_fd_set_off(fno, cur_off + len); return len; } #endif int sysfs_tasks_read(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; static char *task_txt; static uint32_t off; int i; int stack_used; char *name; int p_state; int nice; const char legend[]="pid\tstate\tstack\theap\tnice\tname\r\n"; uint32_t cur_off = task_fd_get_off(fno); if (cur_off == 0) { mutex_lock(sysfs_mutex); task_txt = kalloc(MAX_SYSFS_BUFFER); if (!task_txt) return -1; off = 0; strcpy(task_txt, legend); off += strlen(legend); for (i = 1; i <= 0xFFFF; i++) { p_state = scheduler_task_state(i); if ((p_state != TASK_IDLE) && (p_state != TASK_OVER)) { off += ul_to_str(i, task_txt + off); task_txt[off++] = '\t'; if (p_state == TASK_RUNNABLE) task_txt[off++] = 'r'; if (p_state == TASK_RUNNING) task_txt[off++] = 'R'; if (p_state == TASK_WAITING) task_txt[off++] = 'W'; if (p_state == TASK_FORKED) task_txt[off++] = 'F'; if (p_state == TASK_ZOMBIE) task_txt[off++] = 'Z'; if (p_state == TASK_STOPPED) task_txt[off++] = 'S'; task_txt[off++] = '\t'; stack_used = scheduler_stack_used(i); off += ul_to_str(stack_used, task_txt + off); task_txt[off++] = '\t'; stack_used = f_proc_heap_count(i); off += ul_to_str(stack_used, task_txt + off); task_txt[off++] = '\t'; nice = scheduler_get_nice(i); off += nice_to_str(nice, task_txt + off); task_txt[off++] = '\t'; name = scheduler_task_name(i); if (name) { strcpy(&task_txt[off], name); off += strlen(name); } task_txt[off++] = '\r'; task_txt[off++] = '\n'; } } task_txt[off++] = '\0'; } cur_off = task_fd_get_off(fno); if (off == cur_off) { kfree(task_txt); mutex_unlock(sysfs_mutex); return -1; } if (len > (off - cur_off)) { len = off - cur_off; } memcpy(res, task_txt + cur_off, len); cur_off += len; task_fd_set_off(fno, cur_off); return len; } #define NPOOLS 5 int sysfs_mem_read(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; static char *mem_txt; static int off; int i; int stack_used; int p_state; uint32_t cur_off = task_fd_get_off(fno); if (cur_off == 0) { const char mem_stat_banner[NPOOLS][50] = {"\r\nKernel memory statistics\r\n", "\r\n\nUser memory statistics\r\n", "\r\n\nTask space statistics\r\n", "\r\n\nTCP/IP space statistics\r\n", "\r\n\nExtra mem space statistics\r\n", }; const char malloc_banner[] = "\tObjects in use: "; const char mem_banner[] = "\tMemory in use: "; const char frags_banner[] = "\tReserved: "; int i; mutex_lock(sysfs_mutex); mem_txt = kalloc(MAX_SYSFS_BUFFER); if (!mem_txt) return -1; off = 0; for (i = 0; i < NPOOLS; i++) { unsigned long allocated = f_malloc_stats[i].malloc_calls - f_malloc_stats[i].free_calls; strcpy(mem_txt + off, mem_stat_banner[i]); off += strlen(mem_stat_banner[i]); strcpy(mem_txt + off, malloc_banner); off += strlen(malloc_banner); off += ul_to_str(allocated, mem_txt + off); *(mem_txt + off) = '\r'; off++; *(mem_txt + off) = '\n'; off++; strcpy(mem_txt + off, mem_banner); off += strlen(mem_banner); off += ul_to_str(f_malloc_stats[i].mem_allocated, mem_txt + off); *(mem_txt + off) = ' '; off++; *(mem_txt + off) = 'B'; off++; *(mem_txt + off) = '\r'; off++; *(mem_txt + off) = '\n'; off++; strcpy(mem_txt + off, frags_banner); off += strlen(frags_banner); off += ul_to_str(mem_stats_frag(i), mem_txt + off); *(mem_txt + off) = ' '; off++; *(mem_txt + off) = 'B'; off++; *(mem_txt + off) = '\r'; off++; *(mem_txt + off) = '\n'; off++; } if (off > 0) mem_txt[off++] = '\0'; } cur_off = task_fd_get_off(fno); if (off == cur_off) { kfree(mem_txt); mutex_unlock(sysfs_mutex); return -1; } if (len > (off - cur_off)) { len = off - cur_off; } memcpy(res, mem_txt + cur_off, len); cur_off += len; task_fd_set_off(fno, cur_off); return len; } int sysfs_modules_read(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; static char *mem_txt; static int off; int i; int stack_used; int p_state; struct module *m = MODS; uint32_t cur_off = task_fd_get_off(fno); if (cur_off == 0) { const char mod_banner[] = "Loaded modules:\r\n"; mutex_lock(sysfs_mutex); mem_txt = kalloc(MAX_SYSFS_BUFFER); if (!mem_txt) return -1; off = 0; strcpy(mem_txt + off, mod_banner); off += strlen(mod_banner); while (m) { strcpy(mem_txt + off, m->name); off += strlen(m->name); *(mem_txt + (off++)) = '\r'; *(mem_txt + (off++)) = '\n'; m = m->next; } } cur_off = task_fd_get_off(fno); if (off == cur_off) { kfree(mem_txt); mutex_unlock(sysfs_mutex); return -1; } if (len > (off - cur_off)) { len = off - cur_off; } memcpy(res, mem_txt + cur_off, len); cur_off += len; task_fd_set_off(fno,cur_off); return len; } int sysfs_mtab_read(struct sysfs_fnode *sfs, void *buf, int len) { char *res = (char *)buf; struct fnode *fno = sfs->fnode; static char *mem_txt; static int off; int i; int stack_used; int p_state; struct mountpoint *m = MTAB; int l = 0; uint32_t cur_off = task_fd_get_off(fno); if (cur_off == 0) { const char mtab_banner[] = "Mountpoint\tDriver\t\tInfo\r\n--------------------------------------\r\n"; mutex_lock(sysfs_mutex); mem_txt = kalloc(MAX_SYSFS_BUFFER); if (!mem_txt) return -1; off = 0; strcpy(mem_txt + off, mtab_banner); off += strlen(mtab_banner); while (m) { l = fno_fullpath(m->target, mem_txt + off, MAX_SYSFS_BUFFER - off); if (l > 0) off += l; *(mem_txt + (off++)) = '\t'; *(mem_txt + (off++)) = '\t'; if (m->target->owner) { strcpy(mem_txt + off, m->target->owner->name); off += strlen(m->target->owner->name); } *(mem_txt + (off++)) = '\t'; *(mem_txt + (off++)) = '\t'; l = 0; if (m->target->owner->mount_info) { l = m->target->owner->mount_info(m->target, mem_txt + off, MAX_SYSFS_BUFFER - off); } if (l > 0) { off += l; } else { strcpy(mem_txt + off, "None"); off += 4; } *(mem_txt + (off++)) = '\r'; *(mem_txt + (off++)) = '\n'; m = m->next; } *(mem_txt + (off++)) = '\r'; *(mem_txt + (off++)) = '\n'; } cur_off = task_fd_get_off(fno); if (off == cur_off) { kfree(mem_txt); mutex_unlock(sysfs_mutex); return -1; } if (len > (off - cur_off)) { len = off - cur_off; } memcpy(res, mem_txt + cur_off, len); cur_off += len; task_fd_set_off(fno,cur_off); return len; } int sysfs_no_write(struct sysfs_fnode *sfs, const void *buf, int len) { return -1; } int sysfs_no_read(struct sysfs_fnode *sfs, void *buf, int len) { return 0; } int sysfs_register(char *name, char *dir, int (*do_read)(struct sysfs_fnode *sfs, void *buf, int len), int (*do_write)(struct sysfs_fnode *sfs, const void *buf, int len) ) { struct fnode *fno = fno_create(&mod_sysfs, name, fno_search(dir)); struct sysfs_fnode *mfs; if (!fno) return -1; mfs = kalloc(sizeof(struct sysfs_fnode)); if (mfs) { mfs->fnode = fno; fno->priv = mfs; mfs->do_read = do_read; mfs->do_write = do_write; return 0; } return -1; } static int sysfs_mount(char *source, char *tgt, uint32_t flags, void *args) { struct fnode *tgt_dir = NULL; /* Source must be NULL */ if (source) return -1; /* Target must be a valid dir */ if (!tgt) return -1; tgt_dir = fno_search(tgt); if (!tgt_dir || ((tgt_dir->flags & FL_DIR) == 0)) { /* Not a valid mountpoint. */ return -1; } /* TODO: check empty dir if (tgt_dir->children) { return -1; } */ tgt_dir->owner = &mod_sysfs; sysfs_register("time", "/sys", sysfs_time_read, sysfs_no_write); sysfs_register("tasks","/sys", sysfs_tasks_read, sysfs_no_write); sysfs_register("mem", "/sys", sysfs_mem_read, sysfs_no_write); sysfs_register("modules", "/sys", sysfs_modules_read, sysfs_no_write); sysfs_register("mtab", "/sys", sysfs_mtab_read, sysfs_no_write); #if defined(STM32F4) || defined(STM32F7) sysfs_register("pins", "/sys", sysfs_pins_read, sysfs_no_write); #endif #ifdef CONFIG_LOWPOWER sysfs_register("suspend","/sys/power", sysfs_no_read, sysfs_suspend_write); sysfs_register("standby","/sys/power", sysfs_no_read, sysfs_standby_write); #endif return 0; } void sysfs_init(void) { mod_sysfs.family = FAMILY_FILE; strcpy(mod_sysfs.name, "sysfs"); mod_sysfs.mount = sysfs_mount; mod_sysfs.ops.read = sysfs_read; mod_sysfs.ops.poll = sysfs_poll; mod_sysfs.ops.write = sysfs_write; mod_sysfs.ops.close = sysfs_close; sysfs = fno_search("/sys"); fno_mkdir(&mod_sysfs, "net", sysfs); fno_mkdir(&mod_sysfs, "power", sysfs); register_module(&mod_sysfs); sysfs_mutex = mutex_init(); } ================================================ FILE: kernel/fs/xipfs.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include #include "bflt.h" #include "kprintf.h" #include "sys/fs/xipfs.h" #include "vfs.h" #define GDB_PATH "frosted-userland/gdb/" static struct fnode *xipfs; static struct module mod_xipfs; struct xipfs_fnode { struct fnode *fnode; void (*init)(void *); }; #define SECTOR_SIZE (512) static int xipfs_read(struct fnode *fno, void *buf, unsigned int len) { struct xipfs_fnode *xfno; uint32_t off = task_fd_get_off(fno); if (len <= 0) return len; xfno = FNO_MOD_PRIV(fno, &mod_xipfs); if (!xfno) return -1; if (fno->size <= (off)) return -1; if (len > (fno->size - off)) len = fno->size - off; memcpy(buf, ((char *)xfno->init) + off, len); off += len; task_fd_set_off(fno,off); return len; } static int xipfs_block_read(struct fnode *fno, void *buf, uint32_t sector, int offset, int count) { uint32_t off = sector * SECTOR_SIZE + offset; task_fd_set_off(fno,off); if (off > fno->size) { task_fd_set_off(fno,0); return -1; } if (xipfs_read(fno, buf, count) == count) return 0; return -1; } static int xipfs_write(struct fnode *fno, const void *buf, unsigned int len) { return -1; /* Cannot write! */ } static int xipfs_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { return -1; } static int xipfs_seek(struct fnode *fno, int off, int whence) { return -1; } static int xipfs_close(struct fnode *fno) { return 0; } static int xipfs_creat(struct fnode *fno) { return -1; } static void *xipfs_exe(struct fnode *fno, void *arg) { struct xipfs_fnode *xip = (struct xipfs_fnode *)fno->priv; void *reloc_text, *reloc_data, *reloc_bss; size_t stack_size; void *init = NULL; struct vfs_info *vfsi = NULL; if (!xip) return NULL; vfsi = f_calloc(MEM_KERNEL, 1u, sizeof(struct vfs_info)); if (!vfsi) return NULL; /* note: xip->init is bFLT load address! */ if (bflt_load((uint8_t*)xip->init, &reloc_text, &reloc_data, &reloc_bss, &init, &stack_size, (uint32_t *)&vfsi->pic, &vfsi->text_size, &vfsi->data_size)) { kprintf("xipfs: bFLT loading failed.\n"); return NULL; } kprintf("xipfs: GDB: add-symbol-file %s%s.gdb 0x%p -s .data 0x%p -s .bss 0x%p\n", GDB_PATH, fno->fname, reloc_text, reloc_data, reloc_bss); vfsi->type = VFS_TYPE_BFLT; vfsi->allocated = reloc_data; vfsi->init = init; return (void*)vfsi; } static int xipfs_unlink(struct fnode *fno) { return -1; /* Cannot unlink */ } static int xip_add(const char *name, const void (*init), uint32_t size) { struct xipfs_fnode *xip = kalloc(sizeof(struct xipfs_fnode)); if (!xip) return -1; xip->fnode = fno_create(&mod_xipfs, name, fno_search("/bin")); if (!xip->fnode) { kfree(xip); return -1; } xip->fnode->priv = xip; /* Make executable */ xip->fnode->flags |= FL_EXEC; xip->fnode->size = size; xip->init = init; return 0; } static int xipfs_parse_blob(const uint8_t *blob) { const struct xipfs_fat *fat = (const struct xipfs_fat *)blob; const struct xipfs_fhdr *f; int i, offset; if (!fat) return -1; offset = sizeof(struct xipfs_fat); for (i = 0; i < fat->fs_files; i++) { f = (const struct xipfs_fhdr *) (blob + offset); if ((f->magic != XIPFS_MAGIC) && (f->magic != XIPFS_MAGIC_ICELINK)) return -1; if (f->magic == XIPFS_MAGIC) { xip_add(f->name, f->payload, f->len); offset += f->len + sizeof(struct xipfs_fhdr); } else { char fullname[64] = "/bin/"; strcpy(fullname + 5, f->name); vfs_symlink("/bin/icebox", fullname); offset += sizeof(struct xipfs_fhdr); } while ((offset % 4) != 0) offset++; } return 0; } static int xipfs_mount(char *source, char *tgt, uint32_t flags, void *arg) { struct fnode *tgt_dir = NULL; /* Source must NOT be NULL */ if (!source) return -1; /* Target must be a valid dir */ if (!tgt) return -1; tgt_dir = fno_search(tgt); if (!tgt_dir || ((tgt_dir->flags & FL_DIR) == 0)) { /* Not a valid mountpoint. */ return -1; } tgt_dir->owner = &mod_xipfs; if (xipfs_parse_blob((uint8_t *)source) < 0) return -1; return 0; } void xipfs_init(void) { mod_xipfs.family = FAMILY_FILE; mod_xipfs.mount = xipfs_mount; strcpy(mod_xipfs.name,"xipfs"); mod_xipfs.ops.read = xipfs_read; mod_xipfs.ops.poll = xipfs_poll; mod_xipfs.ops.write = xipfs_write; mod_xipfs.ops.seek = xipfs_seek; mod_xipfs.ops.creat = xipfs_creat; mod_xipfs.ops.unlink = xipfs_unlink; mod_xipfs.ops.close = xipfs_close; mod_xipfs.ops.exe = xipfs_exe; mod_xipfs.ops.block_read = xipfs_block_read; register_module(&mod_xipfs); } ================================================ FILE: kernel/fs/xipfs.h ================================================ #ifndef XIPFS_INCLUDED #define XIPFS_INCLUDED #define XIPFS_MAGIC 0xC519FF55 #include struct xipfs_fat { uint32_t fs_magic; uint32_t fs_size; uint32_t fs_files; uint32_t timestamp; }; struct xipfs_fhdr { uint32_t magic; char name[56]; uint32_t len; uint8_t payload[0]; }; void xipfs_init(void); #endif ================================================ FILE: kernel/getaddrinfo.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "drivers/socket_in.h" #ifndef CONFIG_DNS_CLIENT int sys_getaddrinfo_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) { return -ENOSYS; } int sys_freeaddrinfo_hdlr(uint32_t arg1) { return -ENOSYS; } #else #define DNSQUERY_IDLE 0 #define DNSQUERY_OK 1 #define DNSQUERY_IN_PROGRESS 2 #define DNSQUERY_FAIL 0xFF struct dnsquery_cookie { char *node; struct addrinfo *res; struct task *task; uint8_t state; }; struct waiting_task { struct task *task; struct waiting_task *next; }; static uint16_t get_port(char *service) { int i; int f = 1; uint16_t p = 0; if (!service) return 0; for (i = strlen(service) - 1; i >= 0; i--) { if (service[i] < '0' || service[i] > '9') return 0; p += (service[i] - '0') * f; f *= 10; } return p; } static struct dnsquery_cookie ck4 = { NULL, 0, DNSQUERY_IDLE }; static struct dnsquery_cookie ck6 = { NULL, 0, DNSQUERY_IDLE }; static struct waiting_task *waiting_list = NULL; static int dns_is_busy(void) { if (ck4.state == DNSQUERY_IN_PROGRESS) return 1; #ifdef CONFIG_IPV6 if (ck6.state == DNSQUERY_IN_PROGRESS) return 1; #endif return 0; } static int add_to_waiting_list(void) { struct waiting_task *wt = kalloc(sizeof(struct waiting_task)); if (!wt) return -1; wt->next = waiting_list; wt->task = this_task(); return 0; } #ifdef CONFIG_IPV6 static void dns_ip6_cb(char *ip, void *arg) { if (ip) { new = u_calloc(1, sizeof(struct addrinfo)); if (!new) { ck6.state= DNSQUERY_FAIL; task_resume(ck6.task); return; } new->ai_family = AF_INET6; new->ai_addr = u_calloc(1, sizeof(struct sockaddr_in6)); if (!new->ai_addr) { f_free(new); ck6.state = DNSQUERY_FAIL; task_resume(ck6.task); return; } new->ai_addrlen = sizeof(struct sockaddr_in6); pico_string_to_ipv6(ip, (((struct sockaddr_in6*)(new->ai_addr))->sin6_addr.s6_addr)); ((struct sockaddr_in6*)(new->ai_addr))->sin6_family = AF_INET6; new->ai_next = ck6.res; ck6.res = new; ck6.state = DNSQUERY_OK; } else { /* No ip given, but still callback was called: timeout! */ ck6.state = DNSQUERY_FAIL; } task_resume(ck6.task); } #endif static void dns_ip4_cb(char *ip, void *arg) { struct addrinfo *new; if (ip) { new = u_calloc(1, sizeof(struct addrinfo)); if (!new) { ck4.state = DNSQUERY_FAIL; task_resume(ck4.task); return; } new->ai_family = AF_INET; new->ai_addr = u_calloc(1, sizeof(struct sockaddr_in)); if (!new->ai_addr) { f_free(new); ck4.state = DNSQUERY_FAIL; task_resume(ck4.task); return; } new->ai_addrlen = sizeof(struct sockaddr_in); pico_string_to_ipv4(ip, &(((struct sockaddr_in*)new->ai_addr)->sin_addr.s_addr)); ((struct sockaddr_in*)(new->ai_addr))->sin_family = AF_INET; new->ai_next = ck4.res; ck4.res = new; ck4.state = DNSQUERY_OK; } else { /* No ip given, but still callback was called: timeout! */ ck4.state = DNSQUERY_FAIL; } task_resume(ck4.task); } static void dns_idle(void) { struct waiting_task *wt; ck6.state = DNSQUERY_IDLE; ck4.state = DNSQUERY_IDLE; while(waiting_list) { wt = waiting_list; task_resume(wt->task); waiting_list = wt->next; kfree(wt); } } static int pico_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct sockaddr_in sa4; struct sockaddr_in6 sa6; (void)service; /* If an IP address was passed in the string, resolve immediately */ #ifdef CONFIG_IPV6 if (pico_string_to_ipv6(node, sa6.sin6_addr.s6_addr) == 0) { struct addrinfo *ai = u_calloc(1, sizeof(struct addrinfo)); if (!ai) return -ENOMEM; ai->ai_family = AF_INET6; ai->ai_addr = u_calloc(1, sizeof(struct sockaddr_in6)); ai->ai_addrlen = sizeof(struct sockaddr_in6); ai->ai_next = NULL; sa6.sin6_family = AF_INET6; sa6.sin6_port = short_be(get_port(service)); memcpy(ai->ai_addr, &sa6, sizeof(struct sockaddr_in6)); *res = ai; return 0; } #endif if (pico_string_to_ipv4(node, &sa4.sin_addr.s_addr) == 0) { struct addrinfo *ai = u_calloc(1, sizeof(struct addrinfo)); if (!ai) return -ENOMEM; ai->ai_family = AF_INET; ai->ai_addr = u_calloc(1, sizeof(struct sockaddr_in)); ai->ai_addrlen = sizeof(struct sockaddr_in); ai->ai_next = NULL; sa4.sin_family = AF_INET; sa4.sin_port = short_be(get_port(service)); memcpy(ai->ai_addr, &sa4, sizeof(struct sockaddr_in)); *res = ai; return 0; } /* If an operation is in progress, block until it's over */ if (dns_is_busy()) { if (add_to_waiting_list() < 0) return -ENOMEM; task_suspend(); return SYS_CALL_AGAIN; } /* Check if it's the resumed call, and the address has been resolved. */ #ifdef CONFIG_IPV6 if ((ck6.state == DNSQUERY_OK) && (ck6.node == node)) { *res = ck6.res; dns_idle(); return 0; } if ((ck6.state == DNSQUERY_FAIL) && (ck4.node == node)) { dns_idle(); return 0 - pico_err; } #endif if ((ck4.state == DNSQUERY_OK) && (ck4.node == node)) { *res = ck4.res; dns_idle(); return 0; } if ((ck4.state == DNSQUERY_FAIL) && (ck4.node == node)) { dns_idle(); return 0 - pico_err; } #ifdef CONFIG_IPV6 if (!hints || (hints->ai_family == AF_INET6)) { ck6.state = DNSQUERY_IN_PROGRESS; ck6.node = node; ck6.res = NULL; ck6.task = this_task(); if (pico_dns_client_getaddr6(node, dns_ip6_cb, NULL) < 0) { dns_idle(); return 0 - pico_err; } } #endif if (!hints || (hints->ai_family == AF_INET)) { ck4.state = DNSQUERY_IN_PROGRESS; ck4.node = node; ck4.res = NULL; ck4.task = this_task(); if (pico_dns_client_getaddr(node, dns_ip4_cb, NULL) < 0) { dns_idle(); return 0 - pico_err; } } task_suspend(); return SYS_CALL_AGAIN; } static int pico_freeaddrinfo(struct addrinfo *res) { struct addrinfo *cur = res; struct addrinfo *nxt; while(cur) { if (cur->ai_addr) f_free(cur->ai_addr); nxt = cur->ai_next; f_free(cur); cur = nxt; } return 0; } int sys_getaddrinfo_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) { if (task_ptr_valid(arg1) || task_ptr_valid(arg2) || task_ptr_valid(arg3) || task_ptr_valid(arg4)) return -EACCES; return pico_getaddrinfo((const char *)arg1, (const char *)arg2, (struct addrinfo *)arg3, (struct addrinfo **)arg4); } int sys_freeaddrinfo_hdlr(uint32_t arg1) { if (task_ptr_valid(arg1)) return -EACCES; return pico_freeaddrinfo((struct addrinfo *)arg1); } #endif ================================================ FILE: kernel/hardfault_debug.c ================================================ /** * HardFault_HandlerAsm: * Alternative Hard Fault handler to help debug the reason for a fault. * To use, edit the vector table to reference this function in the HardFault vector * This code is suitable for Cortex-M3 and Cortex-M0 cores */ void HardFault_HandlerC(unsigned long *hardfault_args); // Use the 'naked' attribute so that C stacking is not used. __attribute__((naked)) void HardFault_Handler(void) { /* * Get the appropriate stack pointer, depending on our mode, * and use it as the parameter to the C handler. This function * will never return */ __asm("TST LR, #4 \n" "ITE EQ \n" "MRSEQ R0, MSP \n" "MRSNE R0, PSP \n" "B HardFault_HandlerC \n" ); } // Use the 'naked' attribute so that C stacking is not used. __attribute__((naked)) void UsageFault_Handler(void) { /* * Get the appropriate stack pointer, depending on our mode, * and use it as the parameter to the C handler. This function * will never return */ __asm("TST LR, #4 \n" "ITE EQ \n" "MRSEQ R0, MSP \n" "MRSNE R0, PSP \n" "B HardFault_HandlerC \n" ); } /** * HardFaultHandler_C: * This is called from the HardFault_HandlerAsm with a pointer the Fault stack * as the parameter. We can then read the values from the stack and place them * into local variables for ease of reading. * We then read the various Fault Status and Address Registers to help decode * cause of the fault. * The function ends with a BKPT instruction to force control back into the debugger */ volatile unsigned long stacked_r0 ; volatile unsigned long stacked_r1 ; volatile unsigned long stacked_r2 ; volatile unsigned long stacked_r3 ; volatile unsigned long stacked_r12 ; volatile unsigned long stacked_lr ; volatile unsigned long stacked_pc ; volatile unsigned long stacked_psr ; volatile unsigned long _CFSR ; volatile unsigned long _HFSR ; volatile unsigned long _DFSR ; volatile unsigned long _AFSR ; volatile unsigned long _BFAR ; volatile unsigned long _MMAR ; void HardFault_HandlerC(unsigned long *hardfault_args){ stacked_r0 = ((unsigned long)hardfault_args[0]) ; stacked_r1 = ((unsigned long)hardfault_args[1]) ; stacked_r2 = ((unsigned long)hardfault_args[2]) ; stacked_r3 = ((unsigned long)hardfault_args[3]) ; stacked_r12 = ((unsigned long)hardfault_args[4]) ; stacked_lr = ((unsigned long)hardfault_args[5]) ; stacked_pc = ((unsigned long)hardfault_args[6]) ; stacked_psr = ((unsigned long)hardfault_args[7]) ; // Configurable Fault Status Register // Consists of MMSR, BFSR and UFSR _CFSR = (*((volatile unsigned long *)(0xE000ED28))) ; // Hard Fault Status Register _HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ; // Debug Fault Status Register _DFSR = (*((volatile unsigned long *)(0xE000ED30))) ; // Auxiliary Fault Status Register _AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ; // Read the Fault Address Registers. These may not contain valid values. // Check BFARVALID/MMARVALID to see if they are valid values // MemManage Fault Address Register _MMAR = (*((volatile unsigned long *)(0xE000ED34))) ; // Bus Fault Address Register _BFAR = (*((volatile unsigned long *)(0xE000ED38))) ; __asm("BKPT #0") ; // Break into the debugger } ================================================ FILE: kernel/heap.h ================================================ #include #include #include #define DECLARE_HEAP(type, orderby) \ struct heap_element_##type { \ uint32_t id; \ type data; \ }; \ struct heap_##type { \ uint32_t size; \ uint32_t n; \ uint32_t last_id; \ struct heap_element_##type *top; \ }; \ typedef struct heap_##type heap_##type; \ static uint32_t _heap_idx_count = 0; \ static inline int heap_insert(struct heap_##type *heap, type *el) \ { \ int i; \ struct heap_element_##type etmp; \ memcpy(&etmp.data, el, sizeof(type)); \ if (++heap->n >= heap->size) { \ heap->top = krealloc(heap->top, \ (heap->n + 1) * sizeof(struct heap_element_##type)); \ if (!heap->top) { \ heap->n--; \ return -1; \ } \ heap->size++; \ } \ etmp.id = heap->last_id++; \ if ((heap->last_id & 0x80000000U) != 0) \ heap->last_id = 0; /* Wrap around */ \ if (heap->n == 1) { \ memcpy(&heap->top[1], &etmp, sizeof(struct heap_element_##type)); \ return (int)etmp.id; \ } \ for (i = heap->n; ((i > 1) && \ (heap->top[i / 2].data.orderby > el->orderby)); i /= 2) { \ memcpy(&heap->top[i], &heap->top[i / 2], sizeof(struct heap_element_##type)); \ } \ memcpy(&heap->top[i], &etmp, sizeof(struct heap_element_##type)); \ return (int)etmp.id; \ } \ static inline int heap_peek(struct heap_##type *heap, type *first) \ { \ type *ptr = NULL; \ struct heap_element_##type *last; \ int i, child, ret; \ if(heap->n == 0) { \ return -1; \ } \ memcpy(first, &heap->top[1].data, sizeof(type)); \ last = &heap->top[heap->n--]; \ for(i = 1; (i * 2) <= heap->n; i = child) { \ child = 2 * i; \ if ((child != heap->n) && \ (heap->top[child + 1]).data.orderby \ < (heap->top[child]).data.orderby) \ child++; \ if (last->data.orderby > \ heap->top[child].data.orderby) \ memcpy(&heap->top[i], &heap->top[child], \ sizeof(struct heap_element_##type)); \ else \ break; \ } \ memcpy(&heap->top[i], last, sizeof(struct heap_element_##type)); \ return 0; \ } \ static inline int heap_delete(struct heap_##type *heap, int id) \ { \ int found = 0; \ int i, child; \ struct heap_element_##type *last, temp; \ if (heap->n == 0) { \ return -1; \ } \ for (i = 1; i <= heap->n; i++) { \ if (heap->top[i].id == id) { \ found = i; \ break; \ } \ } \ if (!found) { \ return -1; \ } \ if (found == 1) { \ (void)heap_peek(heap, &temp.data); \ return 0; \ } \ if (found == heap->n) { \ heap->n--; \ return 0; \ } \ last = &heap->top[heap->n--]; \ memcpy(&heap->top[found], last, sizeof(struct heap_element_##type)); \ for(i = found; i < heap->n; i++) { \ if (heap->top[i].data.orderby > heap->top[i + 1].data.orderby) { \ memcpy(&temp, &heap->top[i], sizeof(struct heap_element_##type)); \ memcpy(&heap->top[i], &heap->top[i+1], sizeof(struct heap_element_##type)); \ memcpy(&heap->top[i+1], &temp, sizeof(struct heap_element_##type)); \ } \ } \ return 0; \ } \ static inline type *heap_first(heap_##type *heap) \ { \ if (heap->n == 0) \ return NULL; \ return &heap->top[1].data; \ } \ static inline heap_##type *heap_init(void) \ { \ heap_##type *p = kcalloc(1, sizeof(heap_##type)); \ return p; \ } \ static inline void heap_destroy(heap_##type *h) \ { \ kfree(h->top); \ kfree(h); \ } ================================================ FILE: kernel/interrupts.h ================================================ #ifndef FROSTED_INTERRUPTS_H #define FROSTED_INTERRUPTS_H extern void __set_BASEPRI(int); #ifdef DEBUG static void irq_off(void) { } static void irq_on(void) { } static void irq_setmask(void) { } static void irq_clearmask(void) { } #else /* Inline kernel utils */ static inline void irq_setmask(void) { __set_BASEPRI(3); } static inline void irq_clearmask(void) { __set_BASEPRI(0u); } static inline void irq_off(void) { asm volatile ("cpsid i \n"); } static inline void irq_on(void) { asm volatile ("cpsie i \n"); } #endif #endif /* FROSTED_INTERRUPTS_H */ ================================================ FILE: kernel/kprintf.c ================================================ /* * frosted - printf() library function * Based on Georges Menie's printf - Copyright 2001, 2002 Georges Menie (www.menie.org) stdarg version contributed by Christian Ettinger Originally released under LGPL2+. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2, as published by the Free Software Foundation. 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "frosted.h" #include "errno.h" #include "cirbuf.h" #include "poll.h" #include "device.h" #include #ifdef CONFIG_KLOG struct dev_klog { struct fnode *fno; struct cirbuf *buf; int used; struct task *task; }; static struct dev_klog klog; static int klog_open(const char *path, int flags) { if (klog.used) return -EBUSY; klog.used++; return task_filedesc_add(fno_search("/dev/klog")); } static int klog_close(struct fnode *f) { (void)f; klog.used = 0; return 0; } static int klog_read(struct fnode *fno, void *buf, unsigned int len) { int ret; if (len == 0) return len; if (!buf) return -EINVAL; ret = cirbuf_readbytes(klog.buf, buf, len); if (ret <= 0) { klog.task = this_task(); task_suspend(); return SYS_CALL_AGAIN; } return ret; } static int klog_poll(struct fnode *fno, uint16_t events, uint16_t *revents) { if (events != POLLIN) return 0; if (cirbuf_bytesinuse(klog.buf) > 0) { *revents = POLLIN; return 1; } return 0; } static struct module mod_klog = { .family = FAMILY_DEV, .name = "klog", .ops.open = klog_open, .ops.read = klog_read, .ops.poll = klog_poll, .ops.close = klog_close }; static void printchar(char **str, int c) { if (str) { **str = c; ++(*str); } else { if (cirbuf_bytesfree(klog.buf)) { cirbuf_writebyte(klog.buf, c); if (klog.task != NULL) task_resume(klog.task); } } } #define PAD_RIGHT 1 #define PAD_ZERO 2 static int prints(char **out, const char *string, int width, int pad) { int pc = 0, padchar = ' '; if (width > 0) { int len = 0; const char *ptr; for (ptr = string; *ptr; ++ptr) ++len; if (len >= width) width = 0; else width -= len; if (pad & PAD_ZERO) padchar = '0'; } if (!(pad & PAD_RIGHT)) { for ( ; width > 0; --width) { printchar (out, padchar); ++pc; } } for ( ; *string ; ++string) { printchar (out, *string); ++pc; } for ( ; width > 0; --width) { printchar (out, padchar); ++pc; } return pc; } /* the following should be enough for 32 bit int */ #define PRINT_BUF_LEN 12 static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase) { char print_buf[PRINT_BUF_LEN]; char *s; int t, neg = 0, pc = 0; unsigned int u = i; if (i == 0) { print_buf[0] = '0'; print_buf[1] = '\0'; return prints (out, print_buf, width, pad); } if (sg && b == 10 && i < 0) { neg = 1; u = -i; } s = print_buf + PRINT_BUF_LEN-1; *s = '\0'; while (u) { t = u % b; if( t >= 10 ) t += letbase - '0' - 10; *--s = t + '0'; u /= b; } if (neg) { if( width && (pad & PAD_ZERO) ) { printchar (out, '-'); ++pc; --width; } else { *--s = '-'; } } return pc + prints (out, s, width, pad); } static int print(char **out, const char *format, va_list args ) { int width, pad; int pc = 0; char scr[2]; for (; *format != 0; ++format) { if (*format == '%') { ++format; width = pad = 0; if (*format == '\0') break; if (*format == '%') goto out; if (*format == '-') { ++format; pad = PAD_RIGHT; } while ((*format == 'h') || (*format == 'l')) ++format; while (*format == '0') { ++format; pad |= PAD_ZERO; } for ( ; *format >= '0' && *format <= '9'; ++format) { width *= 10; width += *format - '0'; } if( *format == 's' ) { register char *s = (char *)va_arg( args, int ); pc += prints (out, s?s:"(null)", width, pad); continue; } if( *format == 'd' ) { pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a'); continue; } if( *format == 'x' || *format == 'p') { pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a'); continue; } if( *format == 'X' ) { pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A'); continue; } if( *format == 'u' ) { pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a'); continue; } if( *format == 'c' ) { scr[0] = (char)va_arg( args, int ); scr[1] = '\0'; pc += prints(out, scr, width, pad); continue; } } else { out: printchar (out, *format); ++pc; } } if (out) **out = '\0'; va_end( args ); return pc; } static mutex_t *klog_lock; int kprintf(const char *format, ...) { va_list args; int ret; if (cirbuf_bytesfree(klog.buf)) { if (mutex_trylock(klog_lock) < 0) return 0; va_start(args, format); ret = print(0, format, args); mutex_unlock(klog_lock); return ret; } return 0; } int ksprintf(char *out, const char *format, ...) { va_list args; va_start( args, format ); return print( &out, format, args ); } int klog_init(void) { klog.fno = fno_create_rdonly(&mod_klog, "klog", fno_search("/dev")); if (klog.fno == NULL) { return -1; } klog.buf = cirbuf_create(CONFIG_KLOG_SIZE); klog.used = 0; klog.task = NULL; klog_lock = mutex_init(); return 0; } #endif ================================================ FILE: kernel/kprintf.h ================================================ #ifndef KPRINTF_H #define KPRINTF_H #ifdef CONFIG_KLOG int klog_init(void); int ksprintf(char *out, const char *format, ...); int kprintf(const char *format, ...); #else # define klog_init() (0) # define kprintf #endif #endif ================================================ FILE: kernel/lm3s/Kconfig ================================================ if ARCH_LM3S choice prompt "MCU" default LM3S6965 config ARCH_LM3S6965 bool "LM3S6965" select FLASH_SIZE_256KB select RAM_SIZE_64KB config ARCH_LM3SVIRT bool "LM3S-VIRTUAL" select FLASH_SIZE_1MB select RAM_SIZE_256KB endchoice endif ================================================ FILE: kernel/lm3s/lm3s.c ================================================ ================================================ FILE: kernel/lm3s/lm3s.ld.in ================================================ /****************************************************************************** * * standalone.ld - Linker script for applications using startup.c * *****************************************************************************/ ENTRY(reset_handler) MEMORY { FLASH (rx) : ORIGIN = __FLASH_ORIGIN, LENGTH = __KFLASHMEM_SIZE SRAM (rwx) : ORIGIN = __RAM1_BASE, LENGTH = __KRAMMEM_SIZE SRAM_USER (rwx) : ORIGIN = (__RAM1_BASE + __KRAMMEM_SIZE), LENGTH = (__RAM1_SIZE - __KRAMMEM_SIZE) } __StackTop = ORIGIN(SRAM) + LENGTH(SRAM) - 4; SECTIONS { .text : { KEEP(*(.vectors)) *(.text*) *(.rodata*) } > FLASH /* C++ Static constructors/destructors, also used for __attribute__ * ((constructor)) and the likes */ .preinit_array : { . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; } > FLASH .init_array : { . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; } > FLASH .fini_array : { . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; } > FLASH .data : { _etext = LOADADDR(.data); _data = .; *(vtable) *(.data*) _edata = .; } > SRAM AT > FLASH _data_loadaddr = LOADADDR(.data); .bss : { _bss = .; *(.bss*) *(COMMON) . = ALIGN(32 / 8); _ebss = .; PROVIDE (end = .); } > SRAM .heap : { /* heap starts after BSS */ PROVIDE(_heap_start = _ebss ); } > SRAM } PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM)); PROVIDE(_user_heap_start = ORIGIN(SRAM_USER)); PROVIDE(_user_heap_end = ORIGIN(SRAM_USER) + LENGTH(SRAM_USER)); ================================================ FILE: kernel/lm3s/lm3s6965evb.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/lm3s/usart.h" #include "unicore-mx/lm3s/nvic.h" #include "eth.h" #ifdef CONFIG_DEVUART #include "uart.h" #endif /* TODO: Move to unicore-mx when implemented */ int exti_init(void) { return 0; } int exti_enable(void) { return 0; } int exti_register(void) { return 0; } int gpio_init(void) { return 0; } int gpio_create(struct module *mod, const struct gpio_config *gpio_config) { return 0; } void usart_set_baudrate(uint32_t usart, uint32_t baud) { /* TODO */ (void)usart; (void)baud; } void usart_set_databits(uint32_t usart, int bits) { /* TODO */ (void)usart; (void)bits; } void usart_set_stopbits(uint32_t usart, enum usart_stopbits sb) { /* TODO */ (void)usart; (void)sb; } void usart_set_parity(uint32_t usart, enum usart_parity par) { /* TODO */ (void)usart; (void)par; } void usart_set_mode(uint32_t usart, enum usart_mode mode) { /* TODO */ (void)usart; (void)mode; } void usart_set_flow_control(uint32_t usart, enum usart_flowcontrol fc) { /* TODO */ (void)usart; (void)fc; } void usart_enable(uint32_t usart) { (void)usart; } void usart_disable(uint32_t usart) { (void)usart; } static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_0 { .base = USART0_BASE, .irq = NVIC_UART0_IRQ, }, #endif #ifdef CONFIG_USART_1 { .base = USART1_BASE, .irq = NVIC_UART1_IRQ, }, #endif #ifdef CONFIG_USART_2 { .base = USART2_BASE, .irq = NVIC_UART2_IRQ, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) int machine_init(void) { int i; rcc_clock_setup_in_xtal_8mhz_out_50mhz(); for (i = 0; i < NUM_UARTS; i++) uart_create(&(uart_configs[i])); ethernet_init(NULL); return 0; } ================================================ FILE: kernel/locks.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent, brabo * */ #include "frosted.h" #include "locks.h" #include #define SIGN_MUTEX (0xCAFEC0C0) #define SIGN_SEMAP (0xCAFECAFE) extern int _mutex_lock(void *); extern int _mutex_unlock(void *); extern int _sem_wait(void *); extern int _sem_post(void *); /* Semaphore: internal functions */ static void _add_listener(sem_t *s) { int i; struct task *t = this_task(); if (s->last >= 0) { if (t == s->listener[s->last]) return; } for (i = s->last + 1; i < s->listeners; i++) { if (s->listener[i] == NULL) { s->listener[i] = t; s->last = i; return; } } for (i = 0; i < s->last; i++) { if (s->listener[i] == NULL) { s->listener[i] = t; s->last = i; return; } } } static void _del_listener(sem_t *s) { int i; struct task *t = this_task(); for (i = 0; i < s->listeners; i++) { if (s->listener[i] == t) { s->listener[i] = NULL; return; } } } static int sem_spinwait(sem_t *s) { if (!s) return -EINVAL; while (_sem_wait(s) != 0) { /* spin ... */ } return 0; } /* Semaphore: API */ int sem_trywait(sem_t *s) { if (!s) return -EINVAL; if(_sem_wait(s) != 0) return -EAGAIN; return 0; } int sem_wait(sem_t *s, struct timespec *timeout) { if (this_task() == NULL) return sem_spinwait(s); if (!s) return -EINVAL; if(_sem_wait(s) != 0) { if (timeout) { long time_left = (timeout->tv_sec * 1000) + (timeout->tv_nsec / 1000 / 1000) - jiffies; if ((time_left > 0) && (task_get_timer_id() < 0)) { task_set_timer_id(ktimer_add(time_left, sleepy_task_wakeup, NULL)); } else { if (time_left < 0) { return -ETIMEDOUT; } return SYS_CALL_AGAIN; } } _add_listener(s); task_suspend(); return SYS_CALL_AGAIN; } _del_listener(s); return 0; } int sem_post(sem_t *s) { if (!s) return -EINVAL; if (_sem_post(s) > 0) { int i; for(i = s->last+1; i < s->listeners; i++) { struct task *t = s->listener[i]; if (t) { task_resume_lock(t); s->listener[i] = NULL; } } for(i = 0; i <= s->last; i++) { struct task *t = s->listener[i]; if (t) { task_resume_lock(t); s->listener[i] = NULL; } } } return 0; } int sem_destroy(sem_t *sem) { if (sem->listener) kfree(sem->listener); kfree(sem); return 0; } int sem_init(sem_t *s, int val) { int i; s->signature = SIGN_SEMAP; s->value = val; s->listeners = 8; s->last = -1; s->listener = kalloc(sizeof(struct task *) * (s->listeners + 1)); for (i = 0; i < s->listeners; i++) s->listener[i] = NULL; return 0; } /* Semaphore: Syscalls */ int sys_sem_init_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { if (task_ptr_valid((sem_t *)arg1)) { return -EACCES; } struct semaphore *s = (struct semaphore *)arg1; if (!s) return -EACCES; return sem_init((sem_t *)arg1, arg2); } int sys_sem_post_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct semaphore *s = (struct semaphore *)arg1; if (!s || s->signature != SIGN_SEMAP) return -EACCES; return sem_post((sem_t *)arg1); } int sys_sem_wait_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct semaphore *s = (struct semaphore *)arg1; if (!s || s->signature != SIGN_SEMAP) return -EACCES; return sem_wait((sem_t *)arg1, (struct timespec *)arg2); } int sys_sem_trywait_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct semaphore *s = (struct semaphore *)arg1; if (!s || s->signature != SIGN_SEMAP) return -EACCES; return sem_trywait((sem_t *)arg1); } int sys_sem_destroy_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct semaphore *s = (struct semaphore *)arg1; if (!s || s->signature != SIGN_SEMAP) return -EACCES; return sem_destroy((sem_t *)arg1); } int suspend_on_sem_wait(sem_t *s) { int ret; if (!s) return -EINVAL; ret = _sem_wait(s); if (ret != 0) { _add_listener(s); return EAGAIN; } return 0; } /* Mutex: API */ mutex_t *mutex_init() { mutex_t *s = kalloc(sizeof(mutex_t)); if (s) { int i; s->signature = SIGN_MUTEX; s->value = 1; /* Unlocked. */ s->listeners = 8; s->last = -1; s->listener = kalloc(sizeof(struct task *) * (s->listeners + 1)); for (i = 0; i < s->listeners; i++) s->listener[i] = NULL; } return s; } void mutex_destroy(mutex_t *s) { if (s->listener) kfree(s->listener); kfree(s); } static int mutex_spinlock(mutex_t *s) { if (!s) return -EINVAL; while (_mutex_lock(s) != 0) { /* spin... */ } return 0; } int mutex_trylock(mutex_t *s) { if (!s) return -EINVAL; if(_mutex_lock(s) != 0) return -EAGAIN; return 0; } int mutex_lock(mutex_t *s) { if (this_task() == NULL) return mutex_spinlock(s); if (!s) return -EINVAL; if(_mutex_lock(s) != 0) { _add_listener(s); task_suspend(); return SYS_CALL_AGAIN; } _del_listener(s); return 0; } int mutex_unlock(mutex_t *s) { if (!s) return -EINVAL; if (_mutex_unlock(s) == 0) { int i; for(i = s->last+1; i < s->listeners; i++) { struct task *t = s->listener[i]; if (t) { task_resume_lock(t); s->listener[i] = NULL; return 0; } } for(i = 0; i <= s->last; i++) { struct task *t = s->listener[i]; if (t) { task_resume_lock(t); s->listener[i] = NULL; return 0; } } return 0; } return -EAGAIN; } int suspend_on_mutex_lock(mutex_t *s) { int ret; if (!s) return -EINVAL; ret = _mutex_lock(s); if (ret != 0) { _add_listener(s); return EAGAIN; } return 0; } /* Mutex: Syscalls */ int sys_mutex_init_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return (int)mutex_init(arg1); } int sys_mutex_lock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct semaphore *s = (struct semaphore *)arg1; if (!s || s->signature != SIGN_MUTEX) return -EACCES; return mutex_lock((mutex_t *)arg1); } int sys_mutex_unlock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct semaphore *s = (struct semaphore *)arg1; if (!s || s->signature != SIGN_MUTEX) return -EACCES; return mutex_unlock((mutex_t *)arg1); } int sys_mutex_destroy_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct semaphore *s = (struct semaphore *)arg1; if (!s || s->signature != SIGN_MUTEX) return -EACCES; return sem_destroy((sem_t *)arg1); /* Same as semaphore */ } ================================================ FILE: kernel/locks.h ================================================ #include "frosted.h" /* Structures */ struct semaphore { int value; uint32_t signature; int listeners; int last; struct task **listener; }; int suspend_on_sem_wait(sem_t *s); int suspend_on_mutex_lock(mutex_t *s); ================================================ FILE: kernel/lowpower.h ================================================ #ifndef LOWPOWER_H_INC #define LOWPOWER_H_INC #include #ifndef CONFIG_LOWPOWER # define lowpower_init() (-1) # define lowpower_sleep(x,y) (-1) #else int lowpower_init(void); int lowpower_sleep(int stdby, uint32_t interval); #endif #endif ================================================ FILE: kernel/lpc17xx/Kconfig ================================================ if ARCH_LPC17XX choice prompt "MCU" default ARCH_LPC1768 config ARCH_LPC1763 bool "LPC1763" select FLASH_SIZE_256KB select RAM_SIZE_32KB select CLK_100MHZ config ARCH_LPC1764 bool "LPC1764" select FLASH_SIZE_128KB select RAM_SIZE_16KB select CLK_100MHZ config ARCH_LPC1765 bool "LPC1765" select FLASH_SIZE_256KB select RAM_SIZE_32KB select CLK_100MHZ config ARCH_LPC1766 bool "LPC1766" select FLASH_SIZE_256KB select RAM_SIZE_32KB select CLK_100MHZ config ARCH_LPC1767 bool "LPC1767" select FLASH_SIZE_512KB select RAM_SIZE_32KB select CLK_100MHZ config ARCH_LPC1768 bool "LPC1768" select FLASH_SIZE_512KB select RAM_SIZE_32KB select CLK_100MHZ config ARCH_LPC1769 bool "LPC1769" select FLASH_SIZE_512KB select RAM_SIZE_32KB endchoice endif ================================================ FILE: kernel/lpc17xx/lpc1768mbed.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include #include #include #include #include "gpio.h" #include "uart.h" #if CONFIG_SYS_CLOCK == 100000000 const uint32_t clock_96MHZ = CLOCK_96MHZ; #else #error No valid clock speed selected for lpc1768mbed #endif static const struct gpio_config Leds[] = { {.base=GPIO1, .pin=GPIOPIN18, .mode=GPIO_MODE_OUTPUT, .name="led0", /* .exti=1, .trigger=EXTI_TRIGGER_RISING */}, {.base=GPIO1, .pin=GPIOPIN20, .mode=GPIO_MODE_OUTPUT, .name="led1", /* .exti=1, .trigger=EXTI_TRIGGER_RISING */}, {.base=GPIO1, .pin=GPIOPIN21, .mode=GPIO_MODE_OUTPUT, .name="led2", /* .exti=1, .trigger=EXTI_TRIGGER_RISING */}, {.base=GPIO1, .pin=GPIOPIN23, .mode=GPIO_MODE_OUTPUT, .name="led3", /* .exti=1, .trigger=EXTI_TRIGGER_RISING */}, }; #define NUM_LEDS (sizeof(Leds) / sizeof(struct gpio_config)) static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_0 { .devidx = 0, .base = UART0_BASE, .irq = NVIC_UART0_IRQ, .rcc = PWR_PCONP_UART0, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO0, .pin=GPIOPIN3,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO0, .pin=GPIOPIN2,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .name=NULL,}, }, #endif #ifdef CONFIG_USART_1 { .devidx = 1, .base = UART1_BASE, .irq = NVIC_UART1_IRQ, .rcc = PWR_PCONP_UART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO2, .pin=GPIOPIN1,.mode=GPIO_MODE_AF,.af=GPIO_AF2, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO2, .pin=GPIOPIN0,.mode=GPIO_MODE_AF,.af=GPIO_AF2, .name=NULL,}, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = UART2_BASE, .irq = NVIC_UART2_IRQ, .rcc = PWR_PCONP_UART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO0, .pin=GPIOPIN11,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO0, .pin=GPIOPIN10,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .name=NULL,}, }, #endif #ifdef CONFIG_USART_3 { .devidx = 3, .base = UART3_BASE, .irq = NVIC_UART3_IRQ, .rcc = PWR_PCONP_UART3, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO0, .pin=GPIOPIN26,.mode=GPIO_MODE_AF,.af=GPIO_AF3, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO0, .pin=GPIOPIN25,.mode=GPIO_MODE_AF,.af=GPIO_AF3, .name=NULL,}, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) /* TODO: Move to unicore-mx when implemented */ void usart_set_baudrate(uint32_t usart, uint32_t baud) { /* TODO */ (void)usart; (void)baud; } void usart_set_databits(uint32_t usart, int bits) { /* TODO */ (void)usart; (void)bits; } void usart_set_stopbits(uint32_t usart, enum usart_stopbits sb) { /* TODO */ (void)usart; (void)sb; } void usart_set_parity(uint32_t usart, enum usart_parity par) { /* TODO */ (void)usart; (void)par; } void usart_set_mode(uint32_t usart, enum usart_mode mode) { /* TODO */ (void)usart; (void)mode; } void usart_set_flow_control(uint32_t usart, enum usart_flowcontrol fc) { /* TODO */ (void)usart; (void)fc; } /* TODO: Move to unicore-mx when implemented */ int exti_init(void) { return 0; } int exti_enable(void) { return 0; } int exti_register(void) { return 0; } void usart_enable(uint32_t usart) { (void)usart; } void usart_disable(uint32_t usart) { (void)usart; } int machine_init(void) { int i; clock_setup(&clock_scale[clock_96MHZ]); /* Leds */ for (i = 0; i < 4; i++) { gpio_create(NULL, &Leds[i]); } /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } return 0; } ================================================ FILE: kernel/lpc17xx/lpc1769xpresso.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include #include #include #include #include "gpio.h" #include "uart.h" static const struct gpio_config Leds[] = { {.base=GPIO0, .pin=GPIOPIN22, .mode=GPIO_MODE_OUTPUT, .name="led0" }, }; #define NUM_LEDS (sizeof(Leds) / sizeof(struct gpio_config)) static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_0 { .devidx = 0, .base = UART0_BASE, .irq = NVIC_UART0_IRQ, .rcc = PWR_PCONP_UART0, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO0, .pin=GPIOPIN3,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO0, .pin=GPIOPIN2,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .name=NULL,}, }, #endif #ifdef CONFIG_USART_1 { .devidx = 1, .base = UART1_BASE, .irq = NVIC_UART1_IRQ, .rcc = PWR_PCONP_UART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO0, .pin=GPIOPIN16,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO0, .pin=GPIOPIN15,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .name=NULL,}, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = UART2_BASE, .irq = NVIC_UART2_IRQ, .rcc = PWR_PCONP_UART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO0, .pin=GPIOPIN11,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO0, .pin=GPIOPIN10,.mode=GPIO_MODE_AF,.af=GPIO_AF1, .name=NULL,}, }, #endif #ifdef CONFIG_USART_3 { .devidx = 3, .base = UART3_BASE, .irq = NVIC_UART3_IRQ, .rcc = PWR_PCONP_UART3, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIO0, .pin=GPIOPIN1,.mode=GPIO_MODE_AF,.af=GPIO_AF2, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIO0, .pin=GPIOPIN0,.mode=GPIO_MODE_AF,.af=GPIO_AF2, .name=NULL,}, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) /* TODO: Move to unicore-mx when implemented */ void usart_set_baudrate(uint32_t usart, uint32_t baud) { /* TODO */ (void)usart; (void)baud; } void usart_set_databits(uint32_t usart, int bits) { /* TODO */ (void)usart; (void)bits; } void usart_set_stopbits(uint32_t usart, enum usart_stopbits sb) { /* TODO */ (void)usart; (void)sb; } void usart_set_parity(uint32_t usart, enum usart_parity par) { /* TODO */ (void)usart; (void)par; } void usart_set_mode(uint32_t usart, enum usart_mode mode) { /* TODO */ (void)usart; (void)mode; } void usart_set_flow_control(uint32_t usart, enum usart_flowcontrol fc) { /* TODO */ (void)usart; (void)fc; } /* TODO: Move to unicore-mx when implemented */ int exti_init(void) { return 0; } int exti_enable(void) { return 0; } int exti_register(void) { return 0; } void usart_enable(uint32_t usart) { (void)usart; } void usart_disable(uint32_t usart) { (void)usart; } int machine_init(void) { int i; clock_setup(&clock_scale[CLOCK_120MHZ]); /* Leds */ gpio_create(NULL, &Leds[0]); /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } return 0; } ================================================ FILE: kernel/lpc17xx/lpc17xx.ld.in ================================================ MEMORY { FLASH (rx) : ORIGIN = __FLASH_ORIGIN, LENGTH = __KFLASHMEM_SIZE SRAM (rwx) : ORIGIN = __RAM1_BASE, LENGTH = __KRAMMEM_SIZE SRAM_USER (rwx) : ORIGIN = __RAM2_BASE, LENGTH = __RAM2_SIZE SRAM_EXTRA(rwx) : ORIGIN = __RAM3_BASE, LENGTH = __RAM3_SIZE } /* Enforce emmition of the vector table. */ EXTERN (vector_table) /* Define the entry point of the output file. */ ENTRY(reset_handler) SECTIONS { .text : { KEEP(*(.vectors)) *(.text*) *(.rodata*) } > FLASH /* C++ Static constructors/destructors, also used for __attribute__ * ((constructor)) and the likes */ .preinit_array : { . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; } > FLASH .init_array : { . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; } > FLASH .fini_array : { . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; } > FLASH .data : { _etext = LOADADDR(.data); _data = .; *(vtable) *(.data*) _edata = .; } > SRAM AT > FLASH _data_loadaddr = LOADADDR(.data); .bss : { _bss = .; *(.bss*) *(COMMON) . = ALIGN(32 / 8); _ebss = .; PROVIDE (end = .); } > SRAM .heap : { /* heap starts after BSS */ PROVIDE(_heap_start = _ebss ); } > SRAM } PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM)); PROVIDE(_user_heap_start = ORIGIN(SRAM_USER)); PROVIDE(_user_heap_end = ORIGIN(SRAM_USER) + LENGTH(SRAM_USER)); PROVIDE(_extra_heap_start = ORIGIN(SRAM_EXTRA)); PROVIDE(_extra_heap_end = ORIGIN(SRAM_EXTRA) + LENGTH(SRAM_EXTRA)); ================================================ FILE: kernel/lpc17xx.h ================================================ #ifndef INC_LPC17CC #define INC_LPC17CC #ifdef CONFIG_DEVUART #include "uart.h" #endif #ifdef CONFIG_DEVUART void uart_init(struct fnode * dev, const struct uart_addr uart_addrs[], int num_uarts); #endif #endif ================================================ FILE: kernel/malloc.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include #include #include #include "malloc.h" #include "scheduler.h" #include "frosted.h" #include "locks.h" /*------------------*/ /* Defines */ /*------------------*/ #define F_MALLOC_MAGIC (0xDECEA5ED) #if defined __linux__ || defined _WIN32 /* test application */ #define dbg_malloc printf #else #define dbg_malloc(...) do{}while(0) #endif #define F_IN_USE 0x20 #define in_use(x) (((x->flags) & F_IN_USE) == F_IN_USE) #define block_valid(b) ((b) && (b->magic == F_MALLOC_MAGIC)) static void blk_rearrange(void *arg); static inline int MEMPOOL(int x) { #ifdef CONFIG_TCPIP_MEMPOOL if (x == MEM_TCPIP) return 3; #endif if (x == MEM_EXTRA) return 4; if (x == MEM_TASK) return 2; if (x == MEM_USER) return 1; return 0; } /*------------------*/ /* Structures */ /*------------------*/ struct f_malloc_block { uint32_t magic; /* magic fingerprint */ struct f_malloc_block * prev; /* previous block */ struct f_malloc_block * next; /* next, or last block? */ size_t size; /* malloc size excluding this block - next block is adjacent, if !last_block */ uint32_t flags; int pid; }; /*------------------*/ /* Local variables */ /*------------------*/ static struct f_malloc_block *malloc_entry[5] = {NULL, NULL, NULL, NULL, NULL}; /* Globals */ struct f_malloc_stats f_malloc_stats[5] = {}; /* Mlock is a special lock, so initialization is made static */ static struct task *_m_listeners[16] = {}; static struct semaphore _mlock = { .signature = 0xCAFEC0C0, .value = 1, .listeners=16, .last=-1, .listener=_m_listeners}; static mutex_t * const mlock = (mutex_t *)(&_mlock); #define KMEM_SIZE (CONFIG_KRAM_SIZE << 10) /*------------------*/ /* Local functions */ /*------------------*/ /* merges two blocks * returns: pointer to the merged block */ static struct f_malloc_block * merge_blocks(struct f_malloc_block * first, struct f_malloc_block * second) { struct f_malloc_block *temp; if (first > second) { temp = first; first = second; second = temp; } /* new size = sum of sizes + overhead */ first->size = first->size + sizeof(struct f_malloc_block) + second->size; /* first block's next pointer should now point the second blocks next pointer */ first->next = second->next; /* third block's prev pointer should now point to the first block, instead of the second */ if (second->next) second->next->prev = first; return first; } /* split a block in two. * blk: block to be split * size: size of the first block * return: NULL on failure, otherwise pointer to the new free block (second block) * NOTE: the second block will be put in the free-blocks pool, with the remaining size */ static struct f_malloc_block * split_block(struct f_malloc_block * blk, size_t size) { size_t free_size; struct f_malloc_block * free_blk; /* does it fit? */ if ((blk->size - sizeof(struct f_malloc_block)) <= size) return NULL; /* shrink the block to requested size */ free_size = blk->size - sizeof(struct f_malloc_block) - size; blk->size = size; /* create new block */ free_blk = (struct f_malloc_block *)(((uint8_t *)blk) + sizeof(struct f_malloc_block) + blk->size); free_blk->prev = blk; free_blk->next = blk->next; blk->next = free_blk; free_blk->magic = F_MALLOC_MAGIC; free_blk->size = free_size; free_blk->flags = 0u; return free_blk; } static int block_fits(struct f_malloc_block *blk, size_t size, int flags) { uint32_t baddr = (uint32_t)blk; uint32_t reqsize = size + sizeof(struct f_malloc_block); if (!blk) return 0; if (!block_valid(blk)) return 0; if (in_use(blk)) return 0; if (size > blk->size) return 0; return 1; } static struct f_malloc_block * f_find_best_fit(int flags, size_t size, struct f_malloc_block ** last) { struct f_malloc_block *found = NULL, *blk = malloc_entry[MEMPOOL(flags)]; /* See if we can find a free block that fits */ while (blk) /* last entry will break the loop */ { *last = blk; /* last travelled node */ if (block_fits(blk, size, flags)) { /* found a fit - is it better than a possible previously found block? */ if ((!found) || (blk->size < found->size)) found = blk; } if ((blk->next) && (!block_valid(blk->next))) blk->next = NULL; /* travel next block */ blk = blk->next; } return found; } static unsigned char * heap_end_kernel; static unsigned char * heap_stack; static unsigned char * heap_end_user; static unsigned char * heap_end_extra; static unsigned char * heap_limit_user; static unsigned char * heap_limit_kernel; static unsigned char * heap_limit_extra; #ifdef CONFIG_TCPIP_MEMPOOL static char * heap_end_tcpip = (char *)CONFIG_TCPIP_MEMPOOL; #else static char * heap_end_tcpip = NULL; #endif static void * f_sbrk(int flags, int incr) { extern char end; /* Set by linker */ extern char _stack; /* Set by linker */ extern char _user_heap_start; /* Set by linker */ extern char _user_heap_end; /* Set by linker */ #ifdef CONFIG_SDRAM extern char _external_heap_start; /* Set by linker */ extern char _external_heap_end; /* Set by linker */ #endif #ifdef CONFIG_SRAM_EXTRA extern char _extra_heap_start; /* Set by linker */ extern char _extra_heap_end; /* Set by linker */ #endif const char * heap_stack_high = &_stack; char * prev_heap_end; /* Set initial heap addresses */ if (heap_end_kernel == 0) { /* kernel memory */ heap_end_kernel = &end; heap_limit_kernel = &end + KMEM_SIZE; #ifdef CONFIG_SRAM_EXTRA /* extra memory */ heap_end_extra = &_extra_heap_start; heap_limit_extra = &_extra_heap_end; #endif #ifdef CONFIG_SDRAM /* user memory = external ram*/ heap_end_user = &_external_heap_start; /* Start at beginning of heap */ heap_limit_user = &_external_heap_end; #else /* user memory */ heap_end_user = &_user_heap_start; /* Start at beginning of heap */ heap_limit_user = &_user_heap_end; #endif /* task/stack memory */ heap_stack = &_stack - CONFIG_TASK_STACK_SIZE; } int mem_pool = MEMPOOL(flags); if (mem_pool == MEMPOOL(MEM_USER)) { if (!heap_end_user) return (void *)(0 - 1); /* Do not over-commit */ if ((heap_end_user + incr) >= heap_limit_user) return (void *)(0 - 1); prev_heap_end = heap_end_user; heap_end_user += incr; memset(prev_heap_end, 0, incr); } else if (mem_pool == MEMPOOL(MEM_TASK)) { if ((heap_stack - incr) < heap_end_kernel) return (void *)(0 - 1); heap_stack -= incr; prev_heap_end = heap_stack; #ifdef CONFIG_SRAM_EXTRA } else if (mem_pool == MEMPOOL(MEM_EXTRA)) { if (!heap_end_extra) return (void *)(0 - 1); /* Do not over-commit */ if ((heap_end_extra + incr) >= heap_limit_extra) return (void *)(0 - 1); prev_heap_end = heap_end_extra; heap_end_extra += incr; memset(prev_heap_end, 0, incr); #endif #ifdef CONFIG_TCPIP_MEMPOOL } else if (mem_pool == MEMPOOL(MEM_TCPIP)) { if (!heap_end_tcpip) return (void *)(0 - 1); prev_heap_end = heap_end_tcpip; heap_end_tcpip += incr; #endif } else { if (((heap_end_kernel + incr) >= heap_limit_kernel) || ((heap_end_kernel + incr) > heap_stack)) return (void*)(0 - 1); prev_heap_end = heap_end_kernel; heap_end_kernel += incr; } return (void *) prev_heap_end; } static void f_compact(struct f_malloc_block *blk) { if (!blk->prev) return; blk->prev->next = NULL; int mem_pool = MEMPOOL(blk->flags); if (mem_pool == MEMPOOL(MEM_USER)) { heap_end_user -= (blk->size + sizeof(struct f_malloc_block)); } else if (mem_pool == MEMPOOL(MEM_EXTRA)) { heap_end_extra -= (blk->size + sizeof(struct f_malloc_block)); } else if (mem_pool == MEMPOOL(MEM_TASK)) { heap_stack += (blk->size + sizeof(struct f_malloc_block)); #ifdef CONFIG_TCPIP_MEMPOOL } else if (mem_pool == MEMPOOL(MEM_TCPIP)) { heap_end_tcpip -= (blk->size + sizeof(struct f_malloc_block)); #endif } else { heap_end_kernel -= (blk->size + sizeof(struct f_malloc_block)); } } /*------------------*/ /* Public functions */ /*------------------*/ void * f_calloc(int flags, size_t num, size_t size) { void * ptr = f_malloc(flags, num * size); if (ptr) memset(ptr, 0, num * size); return ptr; } void * u_calloc(size_t num, size_t size) { void *addr; addr = f_calloc(MEM_USER, num, size); #ifdef CONFIG_SRAM_EXTRA if (!addr) addr = f_calloc(MEM_EXTRA, num, size); #endif return addr; } void * f_realloc(int flags, void* ptr, size_t size) { void * out = NULL; struct f_malloc_block * blk = NULL; /* size zero and valid ptr -> act as regular free() */ if (!size && ptr) goto realloc_free; if (ptr) blk = (struct f_malloc_block *)(((uint8_t*)ptr) - sizeof(struct f_malloc_block)); if (!ptr) { /* f ptr is not valid, act as regular malloc() */ out = f_malloc(flags, size); } else if (blk && block_valid(blk)) { size_t new_size, copy_size; if (!in_use(blk)) { task_segfault((uint32_t)ptr, 0, MEMFAULT_ACCESS); } /* If requested size is the same as current, do nothing. */ if (blk->size == size) return ptr; else if (size > blk->size) { /* Grow to requested size by copying the content */ new_size = size; copy_size = blk->size; } else { /* Shrink (Ignore for now) */ return ptr; } out = f_malloc(flags, new_size); if (!out) { return NULL; } memcpy(out, ptr, copy_size); } realloc_free: if (ptr) { struct f_malloc_block * blk; blk = (struct f_malloc_block *)((uint8_t *)ptr - sizeof(struct f_malloc_block)); f_free(ptr); blk_rearrange(blk); } return out; } void *u_realloc(void *ptr, size_t size) { void *addr; addr = f_realloc(MEM_USER, ptr, size); #ifdef CONFIG_SRAM_EXTRA if (!addr) addr = f_realloc(MEM_EXTRA, ptr, size); #endif return addr; } static void f_proc_heap_free_pool(int pid, int mempool) { struct f_malloc_block *blk = malloc_entry[MEMPOOL(mempool)]; while (blk) { if (!block_valid(blk)) while(1); /* corrupt block! */ if ((blk->pid == pid) && in_use(blk)) { f_free(blk); blk_rearrange(blk); } blk = blk->next; } } void f_proc_heap_free(int pid) { f_proc_heap_free_pool(pid, MEM_USER); f_proc_heap_free_pool(pid, MEM_EXTRA); } uint32_t f_proc_heap_count_pool(int pid, int mempool) { struct f_malloc_block *blk = malloc_entry[MEMPOOL(mempool)]; uint32_t size = 0; while (blk) { if ((blk->pid == pid) && in_use(blk)) { size += blk->size; } blk = blk->next; } return size; } uint32_t f_proc_heap_count(int pid) { uint32_t size = f_proc_heap_count_pool(pid, MEM_USER); size += f_proc_heap_count_pool(pid, MEM_EXTRA); return size; } void * u_malloc(size_t size) { void *addr; addr = f_malloc(MEM_USER, size); #ifdef CONFIG_SRAM_EXTRA if (!addr) addr = f_malloc(MEM_EXTRA, size); #endif return addr; } void * f_malloc(int flags, size_t size) { struct f_malloc_block * blk = NULL, *last = NULL; void *ret = NULL; while((size % 4) != 0) { size++; } /* kernelspace calls: pid=0 (kernel, kthreads */ if (this_task_getpid() == 0) { /* kernel receives a null (no blocking) */ if (this_task() == NULL) { if (mutex_trylock(mlock) < 0) return NULL; } else { /* ktrheads can block. */ mutex_lock(mlock); } } /* Userspace calls acquire mlock in the syscall handler. */ /* Travel the linked list for first fit */ blk = f_find_best_fit(flags, size, &last); if (blk) { dbg_malloc("Found best fit!\n"); /* * if ((flags & MEM_USER) && blk->next && ((uint8_t *)blk + 24 + blk->size != (uint8_t *)blk->next)) * while(1);; */ /* first fit found, now split it if it's much bigger than needed */ if (2 * (size + sizeof(struct f_malloc_block)) < blk->size) { dbg_malloc("Splitting blocks, since requested size [%d] << best fit block size [%d]!\n", size, blk->size); split_block(blk, size); } } else { /* No first fit found: ask for new memory */ blk = (struct f_malloc_block *)f_sbrk(flags, size + sizeof(struct f_malloc_block)); // can OS give us more memory? if ((long)blk == -1) { ret = NULL; goto out; } /* first call -> set entrypoint */ if (malloc_entry[MEMPOOL(flags)] == NULL) { malloc_entry[MEMPOOL(flags)] = blk; blk->prev = NULL; } blk->magic = F_MALLOC_MAGIC; blk->size = size; blk->next = NULL; /* Newly allocated memory is always last in the linked list */ /* Link this entry to the previous last entry */ if (last) { // assert(last->next == NULL); last->next = blk; } blk->prev = last; } /* destination found, fill in meta-data */ blk->flags = F_IN_USE | flags; if (flags & MEM_USER) blk->pid = this_task_getpid(); else blk->pid = 0; /* update stats */ f_malloc_stats[MEMPOOL(flags)].malloc_calls++; f_malloc_stats[MEMPOOL(flags)].objects_allocated++; f_malloc_stats[MEMPOOL(flags)].mem_allocated += ((uint32_t)blk->size + sizeof(struct f_malloc_block)); ret = (void *)(((uint8_t *)blk) + sizeof(struct f_malloc_block)); // pointer to newly allocated mem out: /* Userspace calls release mlock in the syscall handler. */ if (this_task_getpid() == 0) { mutex_unlock(mlock); } if (ret && (flags & MEM_TASK)) { memset(ret, 0x55, size); } return ret; } static void blk_rearrange(void *arg) { struct f_malloc_block *blk = arg; /* Merge adjecent free blocks (consecutive blocks are always adjacent) */ if ((blk->prev) && (!in_use(blk->prev))) { blk = merge_blocks(blk->prev, blk); } if ((blk->next) && (!in_use(blk->next))) { blk = merge_blocks(blk, blk->next); } if (!blk->next) f_compact(blk); } void f_free(void * ptr) { struct f_malloc_block * blk; int pid = this_task_getpid(); blk = (struct f_malloc_block *)((uint8_t *)ptr - sizeof(struct f_malloc_block)); if (!ptr) { return; } if (block_valid(blk)) { if (!in_use(blk)) { task_segfault((uint32_t)ptr, 0, MEMFAULT_DOUBLEFREE); } blk->flags &= ~F_IN_USE; /* stats */ f_malloc_stats[MEMPOOL(blk->flags)].free_calls++; f_malloc_stats[MEMPOOL(blk->flags)].objects_allocated--; f_malloc_stats[MEMPOOL(blk->flags)].mem_allocated -= (uint32_t)blk->size + sizeof(struct f_malloc_block); } else { dbg_malloc("FREE ERR: %p is not a valid allocated pointer!\n", blk); } } /* Some statistic helpers */ uint32_t mem_stats_frag(int pool) { uint32_t frag_size = 0u; struct f_malloc_block *blk; mutex_lock(mlock); blk = malloc_entry[pool]; while (blk) { if (!in_use(blk)) frag_size += blk->size + sizeof(struct f_malloc_block); blk = blk->next; } mutex_unlock(mlock); return frag_size; } static int fmalloc_check_block_owner(int pool, const uint8_t *ptr) { struct f_malloc_block *blk; int ret = -1; blk = malloc_entry[MEMPOOL(pool)]; while(blk) { uint8_t *mem_start = (uint8_t *)blk + sizeof(struct f_malloc_block); uint8_t *mem_end = mem_start + blk->size; if ( (ptr >= mem_start) && (ptr < mem_end) ) { if (block_valid(blk) && in_use(blk)) ret = blk->pid; else ret = -1; break; } blk = blk->next; } return ret; } int fmalloc_owner(const void *_ptr) { int ret = fmalloc_check_block_owner(MEM_USER, (uint8_t *)_ptr); #ifdef CONFIG_SRAM_EXTRA if (ret == -1) ret = fmalloc_check_block_owner(MEM_EXTRA, (uint8_t *)_ptr); #endif return ret; } int fmalloc_chown(const void *ptr, uint16_t pid) { struct f_malloc_block *blk = (struct f_malloc_block *) ( ((uint8_t *)ptr) - sizeof(struct f_malloc_block)); if (block_valid(blk)) blk->pid = pid; } int mem_trylock(void) { return mutex_trylock(mlock); } int mem_lock(void) { return suspend_on_mutex_lock(mlock); } void mem_unlock(void) { mutex_unlock(mlock); } /* Syscalls back-end (for userspace memory call handling) */ void *sys_malloc_hdlr(int size) { void *addr; if (mem_lock() < 0) return (void *)SYS_CALL_AGAIN; addr = u_malloc(size); mem_unlock(); return addr; } int sys_free_hdlr(void *addr) { struct f_malloc_block * blk; if ((task_ptr_valid(addr) != 0) || (addr == NULL)) return -1; blk = (struct f_malloc_block *)((uint8_t *)addr - sizeof(struct f_malloc_block)); if (mem_lock() < 0) return SYS_CALL_AGAIN; f_free(addr); blk_rearrange(blk); mem_unlock(); return 0; } void *sys_calloc_hdlr(int n, int size) { void *addr; if (mem_lock() < 0) return (void *)SYS_CALL_AGAIN; addr = u_calloc(n, size); mem_unlock(); return addr; } void *sys_realloc_hdlr(void *addr, int size) { void *naddr; if (mem_lock() < 0) return (void *)SYS_CALL_AGAIN; naddr = u_realloc(addr, size); mem_unlock(); return naddr; } /*------------------*/ /* Test functions */ /*------------------*/ #if defined __linux__ || defined _WIN32 /* test application */ int task_segfault(uint32_t mem, uint32_t inst, int flags) { dbg_malloc("Memory violation\n"); exit(1); } void print_malloc_stats(void) { dbg_malloc("\n=== FROSTED MALLOC STATS ===\n"); dbg_malloc("--> malloc calls: %d\n", f_malloc_stats[0].malloc_calls); dbg_malloc("--> free calls: %d\n", f_malloc_stats[0].free_calls); dbg_malloc("--> objects allocated: %d\n", f_malloc_stats[0].objects_allocated); dbg_malloc("--> memory allocated: %d\n", f_malloc_stats[0].mem_allocated); dbg_malloc("=== FROSTED MALLOC STATS ===\n\n"); } void print_malloc_entries(void) { struct f_malloc_block *blk = malloc_entry[0]; uint32_t i = 0; /* See if we can find a free block that fits */ while (blk) /* last entry will break the loop */ { dbg_malloc(">>> Entry #%d: \n", i); dbg_malloc(" Address (blk) %p \n", blk); dbg_malloc(" Address (usr) %p \n", ((uint8_t*)blk) + sizeof(struct f_malloc_block)); dbg_malloc(" Prev: %p \n", blk->prev); dbg_malloc(" Next: %p \n", blk->next); dbg_malloc(" Size (usr) %d \n", blk->size); dbg_malloc(" Flags: %08x \n", blk->flags); dbg_malloc(" Magic: 0x%08x \n", blk->magic); i++; blk = blk->next; } } int main(int argc, char ** argv) { void * test10 = f_malloc(0, 10); void * test200 = f_malloc(0, 200); void * test100 = NULL; dbg_malloc("test10: %p\n", test10); dbg_malloc("test200: %p\n", test200); f_free(test10); print_malloc_stats(); print_malloc_entries(); dbg_malloc("\nTrying to re-use freed memory + allocate more\n"); test10 = f_malloc(0, 10); // this should re-use exisiting entry test100 = f_malloc(0, 100); // this should alloc more memory through sbrk print_malloc_stats(); print_malloc_entries(); dbg_malloc("\nFreeing all of the memory\n"); f_free(test10); f_free(test200); f_free(test100); print_malloc_stats(); print_malloc_entries(); dbg_malloc("Trying to re-use freed memory\n"); test100 = f_malloc(0, 100); // this should re-use memory in the freed pool print_malloc_stats(); print_malloc_entries(); f_free(test100); dbg_malloc("Allocating more memory\n"); test10 = f_malloc(0, 10); test200 = f_malloc(0, 200); print_malloc_stats(); print_malloc_entries(); f_free(test10); f_free(test200); dbg_malloc("Test Realloc \n"); test10 = f_malloc(0,10); test100 = f_malloc(0,110); test200 = f_malloc(0,1); if (!test10 || !test100 || !test200) { dbg_malloc("malloc failed!\n"); exit(1); } print_malloc_stats(); print_malloc_entries(); test10 = f_realloc(0, test10, 210); test100 = f_realloc(0, test100, 2010); test200 = f_realloc(0, test200, 2); if (!test10 || !test100 || !test200) { dbg_malloc("realloc failed!\n"); exit(1); } print_malloc_stats(); print_malloc_entries(); dbg_malloc("\nFreeing all of the memory\n"); f_free(test10); f_free(test200); f_free(test100); print_malloc_stats(); print_malloc_entries(); return 0; } #endif ================================================ FILE: kernel/malloc.h ================================================ #ifndef _FROSTED_MALLOC_H #define _FROSTED_MALLOC_H #include "string.h" #include "stdint.h" #define MEM_KERNEL 0 #define MEM_USER 1 #define MEM_TASK 2 #define MEM_EXTRA 9 #ifdef CONFIG_TCPIP_MEMPOOL # define MEM_TCPIP 4 # define MEM_OWNER_MASK 7 #else # define MEM_TCPIP MEM_KERNEL # define MEM_OWNER_MASK 3 #endif struct f_malloc_stats { uint32_t malloc_calls; uint32_t free_calls; uint32_t objects_allocated; uint32_t mem_allocated; }; void * u_malloc(size_t size); void * f_malloc(int flags, size_t size); void * f_calloc(int flags, size_t num, size_t size); void* f_realloc(int flags, void* ptr, size_t size); void f_free(void * ptr); /* Free up heap of a specific pid */ void f_proc_heap_free(int pid); /* Get heap usage for specific pid */ uint32_t f_proc_heap_count(int pid); #endif /* _FROSTED_MALLOC_H */ ================================================ FILE: kernel/module.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" struct address_family { struct module *mod; uint16_t family; struct address_family *next; }; struct module *MODS = NULL; struct address_family *AF = NULL; int register_module(struct module *m) { m->next = MODS; MODS = m; return 0; } int unregister_module(struct module *m) { struct module *cur = MODS; while (cur) { /*XXX*/ cur = cur->next; } } struct module *module_search(char *name) { struct module *m = MODS; while(m) { if (strcmp(m->name, name) == 0) return m; m = m->next; } return NULL; } static struct module *af_to_module(uint16_t family) { struct address_family *af = AF; while (af) { if (af->family == family) return af->mod; af = af->next; } return NULL; } int register_addr_family(struct module *m, uint16_t family) { struct address_family *af; if (af_to_module(family)) return -1; /* Another module already claimed this AF */ af = kalloc(sizeof(struct address_family)); if (!af) return -1; af->family = family; af->mod = m; af->next = AF; AF = af; return 0; } int sys_read_hdlr(int fd, void *buf, int len) { struct fnode *fno = task_filedesc_get(fd); if (!task_fd_readable(fd)) return -EPERM; if (task_ptr_valid(buf)) return -EACCES; if (fno && fno->owner->ops.read) { return fno->owner->ops.read(fno, buf, len); } else if (fno->owner && fno->owner->ops.recvfrom) { return fno->owner->ops.recvfrom(fd, buf, len, 0, NULL, NULL); } return -ENOENT; } int sys_write_hdlr(int fd, void *buf, int len) { struct fnode *fno = task_filedesc_get(fd); if (!task_fd_writable(fd)) return -EPERM; if (task_ptr_valid(buf)) return -EACCES; if (!fno) return -ENOENT; if (fno->owner && fno->owner->ops.write) { return fno->owner->ops.write(fno, buf, len); } else if (fno->owner && fno->owner->ops.sendto) { return fno->owner->ops.sendto(fd, buf, len, 0, NULL, 0); } return -EOPNOTSUPP; } int sys_socket_hdlr(int family, int type, int proto) { struct module *m = af_to_module(family); if(!m || !(m->ops.socket)) return -EOPNOTSUPP; return m->ops.socket(family, type, proto); } int sys_bind_hdlr(int sd, struct sockaddr_env *se) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(se)) return -EACCES; if (fno && fno->owner && fno->owner->ops.bind) { return fno->owner->ops.bind(sd, se->se_addr, se->se_len); } return -EINVAL; } int sys_listen_hdlr(int sd, unsigned int backlog) { struct fnode *fno = task_filedesc_get(sd); if (fno && fno->owner && fno->owner->ops.listen) { return fno->owner->ops.listen(sd, backlog); } return -EINVAL; } int sys_connect_hdlr(int sd, struct sockaddr_env *se) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(se)) return -EACCES; if (fno && fno->owner && fno->owner->ops.connect) { return fno->owner->ops.connect(sd, se->se_addr, se->se_len); } return -EINVAL; } int sys_accept_hdlr(int sd, struct sockaddr_env *se) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(se)) return -EACCES; if (fno && fno->owner && fno->owner->ops.accept) { if (se) return fno->owner->ops.accept(sd, se->se_addr, &(se->se_len)); else return fno->owner->ops.accept(sd, NULL, NULL); } return -EINVAL; } int sys_recvfrom_hdlr(int sd, void *buf, int len, int flags, struct sockaddr_env *se) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(buf)) return -EACCES; if (fno && fno->owner && fno->owner->ops.recvfrom) { if (se) { if (task_ptr_valid(se)) return -EACCES; return fno->owner->ops.recvfrom(sd, buf, len, flags, se->se_addr, &(se->se_len)); } else return fno->owner->ops.recvfrom(sd, buf, len, flags, NULL, NULL); } return -EINVAL; } int sys_sendto_hdlr(int sd, const void *buf, int len, int flags, struct sockaddr_env *se ) { struct fnode *fno = task_filedesc_get(sd); if (fno && fno->owner && fno->owner->ops.sendto) { if (se) { if (task_ptr_valid(buf)) return -EACCES; return fno->owner->ops.sendto(sd, buf, len, flags, se->se_addr, se->se_len); } else return fno->owner->ops.sendto(sd, buf, len, flags, NULL, 0); } return -EINVAL; } int sys_shutdown_hdlr(int sd, int how) { struct fnode *fno = task_filedesc_get(sd); if (fno && fno->owner && fno->owner->ops.shutdown) { return fno->owner->ops.shutdown(sd, how); } return -EINVAL; } int sys_setsockopt_hdlr(int sd, int level, int optname, void *optval, unsigned int optlen) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(optval)) return -EACCES; if (fno && fno->owner && fno->owner->ops.setsockopt) { return fno->owner->ops.setsockopt(sd, level, optname, optval, optlen); } return -EINVAL; } int sys_getsockopt_hdlr(int sd, int level, int optname, void *optval, unsigned int *optlen) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(optval)) return -EACCES; if (task_ptr_valid(optlen)) return -EACCES; if (fno && fno->owner && fno->owner->ops.getsockopt) { return fno->owner->ops.getsockopt(sd, level, optname, optval, optlen); } return -EINVAL; } int sys_getsockname_hdlr(int sd, struct sockaddr_env *se) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(se)) return -EACCES; if (fno && fno->owner && fno->owner->ops.getsockname) { return fno->owner->ops.getsockname(sd, se->se_addr, &(se->se_len)); } return -EINVAL; } int sys_getpeername_hdlr(int sd, struct sockaddr_env *se) { struct fnode *fno = task_filedesc_get(sd); if (task_ptr_valid(se)) return -EACCES; if (fno && fno->owner && fno->owner->ops.getpeername) { return fno->owner->ops.getpeername(sd, se->se_addr, &(se->se_len)); } return -EINVAL; } ================================================ FILE: kernel/mpu.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: * */ #include "frosted.h" #include "cm3/mpu.h" #include "libopencmsis/core_cm3.h" #ifdef CONFIG_MPU #define MPUSIZE_1K (0x09 << 1) #define MPUSIZE_2K (0x0a << 1) #define MPUSIZE_4K (0x0b << 1) #define MPUSIZE_8K (0x0c << 1) #define MPUSIZE_16K (0x0d << 1) #define MPUSIZE_32K (0x0e << 1) #define MPUSIZE_64K (0x0f << 1) #define MPUSIZE_128K (0x10 << 1) #define MPUSIZE_256K (0x11 << 1) #define MPUSIZE_512K (0x12 << 1) #define MPUSIZE_1M (0x13 << 1) #define MPUSIZE_2M (0x14 << 1) #define MPUSIZE_4M (0x15 << 1) #define MPUSIZE_8M (0x16 << 1) #define MPUSIZE_16M (0x17 << 1) #define MPUSIZE_32M (0x18 << 1) #define MPUSIZE_64M (0x19 << 1) #define MPUSIZE_128M (0x1a << 1) #define MPUSIZE_256M (0x1b << 1) #define MPUSIZE_512M (0x1c << 1) #define MPUSIZE_1G (0x1d << 1) #define MPUSIZE_2G (0x1e << 1) #define MPUSIZE_4G (0x1f << 1) #define MPUSIZE_ERR (0xFFFFFFFFu) #define FLASH_START (0x00000000) #define RAM_START (0x20000000) #define DEV_START (0x40000000) #define EXTRAM_START (0xC0000000) #define EXTFLASH_START (0x80000000) #define EXTDEV_START (0xA0000000) #define REG_START (0xE0000000) uint32_t mpu_size(uint32_t size) { switch(size) { case (1 * 1024): return MPUSIZE_1K; case (2 * 1024): return MPUSIZE_2K; case (4 * 1024): return MPUSIZE_4K; case (8 * 1024): return MPUSIZE_8K; case (16 * 1024): return MPUSIZE_16K; case (32 * 1024): return MPUSIZE_32K; case (64 * 1024): return MPUSIZE_64K; case (128 * 1024): return MPUSIZE_128K; case (256 * 1024): return MPUSIZE_256K; case (512 * 1024): return MPUSIZE_512K; case (1 * 1024 * 1024): return MPUSIZE_1M; case (2 * 1024 * 1024): return MPUSIZE_2M; case (4 * 1024 * 1024): return MPUSIZE_4M; case (8 * 1024 * 1024): return MPUSIZE_8M; default: return MPUSIZE_ERR; } } static uint32_t mpu_bits = 0; int mpu_present(void) { mpu_bits = MPU_TYPE; if (mpu_bits != 0) return 1; return 0; } int mpu_enable(void) { if (!mpu_bits) return -1; MPU_CTRL = MPU_CTRL_ENABLE; //| MPU_CTRL_PRIVDEFENA; return 0; } int mpu_disable(void) { if (!mpu_bits) return -1; MPU_CTRL = 0; return 0; } static void mpu_select(uint32_t region) { MPU_RNR = region; } static void mpu_setattr(int region, uint32_t attr) { mpu_select(region); MPU_RASR = attr; } static void mpu_setaddr(int region, uint32_t addr) { mpu_select(region); MPU_RBAR = addr; } void mpu_init(void) { if (!mpu_present()) return; /* User area: prio 0, from start */ mpu_setaddr(0, 0); /* Userspace memory block 0x00000000 (1G) - Internal flash is an exception of this */ mpu_setattr(0, MPUSIZE_1G | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB | MPU_RASR_ATTR_AP_PRW_URW); mpu_setaddr(1, EXTRAM_START); /* External RAM bank 0x60000000 (512M) */ mpu_setattr(1, MPUSIZE_512M | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB | MPU_RASR_ATTR_AP_PRW_URW); /* Read-only sectors */ mpu_setaddr(2, FLASH_START); /* Internal Flash 0x00000000 - 0x0FFFFFFF (256M) */ mpu_setattr(2, MPUSIZE_256M | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB | MPU_RASR_ATTR_AP_PRO_URO); /* System (No user access) */ mpu_setaddr(3, RAM_START); /* Kernel memory 0x20000000 (CONFIG_KRAM_SIZE KB) */ mpu_setattr(3, mpu_size(CONFIG_KRAM_SIZE << 10) | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB | MPU_RASR_ATTR_AP_PRW_UNO); /* Priority 4 reserved for task stack exception in kernel memory */ mpu_setaddr(5, DEV_START); /* Peripherals 0x40000000 (512MB)*/ mpu_setattr(5, MPUSIZE_1G | MPU_RASR_ENABLE | MPU_RASR_ATTR_S | MPU_RASR_ATTR_B | MPU_RASR_ATTR_AP_PRW_UNO); mpu_setaddr(6, EXTDEV_START); /* External Peripherals 0xA0000000 (1GB) */ mpu_setattr(6, MPUSIZE_1G | MPU_RASR_ENABLE | MPU_RASR_ATTR_S | MPU_RASR_ATTR_B | MPU_RASR_ATTR_AP_PRW_UNO); mpu_setaddr(7, REG_START); /* System Level 0xE0000000 (256MB) */ mpu_setattr(7, MPUSIZE_256M | MPU_RASR_ENABLE | MPU_RASR_ATTR_S | MPU_RASR_ATTR_B | MPU_RASR_ATTR_AP_PRW_UNO); #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; #endif mpu_enable(); } void mpu_task_on(void *stack) { mpu_disable(); mpu_setaddr(4, (int)(stack + 20)); mpu_setattr(4, mpu_size(CONFIG_TASK_STACK_SIZE) | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB | MPU_RASR_ATTR_AP_PRW_URW); mpu_enable(); } #endif ================================================ FILE: kernel/mpu.h ================================================ #ifndef FROSTED_MPU_H #define FROSTED_MPU_H #ifdef CONFIG_MPU void mpu_init(void); void mpu_task_on(void *stack); #else # define mpu_init() do{}while(0) # define mpu_task_on(x) do{}while(0) #endif #endif ================================================ FILE: kernel/mutex.S ================================================ .syntax unified /* Lock function. * On success, return 0. * On failure, return -1 (Locked, try again later). */ .global _mutex_lock _mutex_lock: #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) LDREX r1, [r0] #elif defined(__ARCH_V6M__) CPSID i LDR r1, [r0] #endif CMP r1, #0 // Test if mutex holds the value 0 BEQ _mutex_lock_fail // If it does, return 0 SUBS r1, #1 // If not, decrement temporary copy #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) STREX r2, r1, [r0] // Attempt Store-Exclusive CMP r2, #0 // Check if Store-Exclusive succeeded BNE _mutex_lock // If Store-Exclusive failed, retry from start DMB // Required before accessing protected resource #elif defined(__ARM_ARCH_6M__) STR r1, [r0] CPSIE i #endif MOVS r0, #0 // Successfully locked. BX lr _mutex_lock_fail: #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) DMB MOV r0, #-1 // Already locked! #elif defined(__ARM_ARCH_6M__) CPSIE i MOVS r2, #0 // Already locked! MVNS r0, r2 #endif BX lr /* Unlock mutex. * On success, return 0. * On failure, return -1 (Already unlocked!). */ .global _mutex_unlock _mutex_unlock: #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) LDREX r1, [r0] #elif defined(__ARM_ARCH_6M__) CPSID i LDR r1, [r0] #endif CMP r1, #0 // Test if mutex holds the value 0 BNE _mutex_unlock_fail // If it does not, it's already locked! ADDS r1, #1 // Increment temporary copy #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) STREX r2, r1, [r0] // Attempt Store-Exclusive CMP r2, #0 // Check if Store-Exclusive succeeded BNE _mutex_unlock // Store failed - retry immediately DMB // Required before releasing protected resource #elif defined(__ARM_ARCH_6M__) STR r1, [r0] CPSIE i #endif MOVS r0, #0 // Successfully unlocked. BX lr _mutex_unlock_fail: #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) DMB MOV r0, #-1 // Already locked! #elif defined(__ARM_ARCH_6M__) CPSIE i MOVS r2, #0 // Already locked! MVNS r0, r2 #endif BX lr ================================================ FILE: kernel/net/Kconfig ================================================ if PICOTCP menu "picoTCP configuration" config CONFIG_PICOTCP_IPV4 bool "Support for IP version 4" default y config CONFIG_PICOTCP_IPV6 bool "Support for IP version 6" default n config CONFIG_PICOTCP_TCP bool "Support for TCP" default y config CONFIG_PICOTCP_UDP bool "Support for UDP" default y config CONFIG_PICOTCP_DNS bool "Support for DNS client" default y config CONFIG_PICOTCP_MCAST bool "Support for Multicast" default n config CONFIG_PICOTCP_NAT bool "Support for NAT" default n config CONFIG_PICOTCP_IPFILTER bool "Support for IP Filter" default n config CONFIG_PICOTCP_LOOP bool "Support for loopback device" default y config CONFIG_PICOTCP_DEBUG bool "Activate debugging symbols" default n endmenu endif ================================================ FILE: kernel/net/if.h ================================================ /* * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if.h 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/net/if.h,v 1.71 2002/03/19 21:54:16 alfred Exp $ */ #ifndef _NET_IF_H_ #define _NET_IF_H_ #include "frosted_api.h" struct ifnet; /* * Length of interface external name, including terminating '\0'. * Note: this is the same size as a generic device's external name. */ #define IFNAMSIZ 16 #define IF_NAMESIZE IFNAMSIZ #define IF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */ /* * Structure describing information about an interface * which may be of interest to management entities. */ struct if_data { /* generic interface information */ u_char ifi_type; /* ethernet, tokenring, etc */ u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ u_char ifi_addrlen; /* media address length */ u_char ifi_hdrlen; /* media header length */ u_char ifi_recvquota; /* polling quota for receive intrs */ u_char ifi_xmitquota; /* polling quota for xmit intrs */ u_long ifi_mtu; /* maximum transmission unit */ u_long ifi_metric; /* routing metric (external only) */ u_long ifi_baudrate; /* linespeed */ /* volatile statistics */ u_long ifi_ipackets; /* packets received on interface */ u_long ifi_ierrors; /* input errors on interface */ u_long ifi_opackets; /* packets sent on interface */ u_long ifi_oerrors; /* output errors on interface */ u_long ifi_collisions; /* collisions on csma interfaces */ u_long ifi_ibytes; /* total number of octets received */ u_long ifi_obytes; /* total number of octets sent */ u_long ifi_imcasts; /* packets received via multicast */ u_long ifi_omcasts; /* packets sent via multicast */ u_long ifi_iqdrops; /* dropped on input, this interface */ u_long ifi_noproto; /* destined for unsupported protocol */ u_long ifi_hwassist; /* HW offload capabilities */ u_long ifi_unused; /* XXX was ifi_xmittiming */ struct timeval ifi_lastchange; /* time of last administrative change */ }; #define IFF_UP 0x1 /* interface is up */ #define IFF_BROADCAST 0x2 /* broadcast address valid */ #define IFF_DEBUG 0x4 /* turn on debugging */ #define IFF_LOOPBACK 0x8 /* is a loopback net */ #define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */ #define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ #define IFF_RUNNING 0x40 /* resources allocated */ #define IFF_NOARP 0x80 /* no address resolution protocol */ #define IFF_PROMISC 0x100 /* receive all packets */ #define IFF_ALLMULTI 0x200 /* receive all multicast packets */ #define IFF_OACTIVE 0x400 /* transmission in progress */ #define IFF_SIMPLEX 0x800 /* can't hear own transmissions */ #define IFF_LINK0 0x1000 /* per link layer defined bit */ #define IFF_LINK1 0x2000 /* per link layer defined bit */ #define IFF_LINK2 0x4000 /* per link layer defined bit */ #define IFF_ALTPHYS IFF_LINK2 /* use alternate physical connection */ #define IFF_MULTICAST 0x8000 /* supports multicast */ /* * The following flag(s) ought to go in if_flags, but we cannot change * struct ifnet because of binary compatibility, so we store them in * if_ipending, which is not used so far. * If possible, make sure the value is not conflicting with other * IFF flags, so we have an easier time when we want to merge them. */ #define IFF_POLLING 0x10000 /* Interface is in polling mode. */ /* flags set internally only: */ #define IFF_CANTCHANGE \ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\ IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_NOTRAILERS) /* Capabilities that interfaces can advertise. */ #define IFCAP_RXCSUM 0x0001 /* can offload checksum on RX */ #define IFCAP_TXCSUM 0x0002 /* can offload checksum on TX */ #define IFCAP_NETCONS 0x0004 /* can be a network console */ #define IFCAP_HWCSUM (IFCAP_RXCSUM | IFCAP_TXCSUM) #define IFQ_MAXLEN 50 #define IFNET_SLOWHZ 1 /* granularity is 1 second */ /* * Message format for use in obtaining information about interfaces * from getkerninfo and the routing socket */ struct if_msghdr { u_short ifm_msglen; /* to skip over non-understood messages */ u_char ifm_version; /* future binary compatibility */ u_char ifm_type; /* message type */ int ifm_addrs; /* like rtm_addrs */ int ifm_flags; /* value of if_flags */ u_short ifm_index; /* index for associated ifp */ struct if_data ifm_data;/* statistics and other data about if */ }; /* * Message format for use in obtaining information about interface addresses * from getkerninfo and the routing socket */ struct ifa_msghdr { u_short ifam_msglen; /* to skip over non-understood messages */ u_char ifam_version; /* future binary compatibility */ u_char ifam_type; /* message type */ int ifam_addrs; /* like rtm_addrs */ int ifam_flags; /* value of ifa_flags */ u_short ifam_index; /* index for associated ifp */ int ifam_metric; /* value of ifa_metric */ }; /* * Message format for use in obtaining information about multicast addresses * from the routing socket */ struct ifma_msghdr { u_short ifmam_msglen; /* to skip over non-understood messages */ u_char ifmam_version; /* future binary compatibility */ u_char ifmam_type; /* message type */ int ifmam_addrs; /* like rtm_addrs */ int ifmam_flags; /* value of ifa_flags */ u_short ifmam_index; /* index for associated ifp */ }; /* * Message format announcing the arrival or departure of a network interface. */ struct if_announcemsghdr { u_short ifan_msglen; /* to skip over non-understood messages */ u_char ifan_version; /* future binary compatibility */ u_char ifan_type; /* message type */ u_short ifan_index; /* index for associated ifp */ char ifan_name[IFNAMSIZ]; /* if name, e.g. "en0" */ u_short ifan_what; /* what type of announcement */ }; #define IFAN_ARRIVAL 0 /* interface arrival */ #define IFAN_DEPARTURE 1 /* interface departure */ /* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The * remainder may be interface specific. */ struct ifreq { char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short ifru_flags[2]; short ifru_index; int ifru_metric; int ifru_mtu; int ifru_phys; int ifru_media; caddr_t ifru_data; int ifru_cap[2]; } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ #define ifr_flags ifr_ifru.ifru_flags[0] /* flags */ #define ifr_prevflags ifr_ifru.ifru_flags[1] /* flags */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define ifr_phys ifr_ifru.ifru_phys /* physical wire */ #define ifr_media ifr_ifru.ifru_media /* physical media */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ #define ifr_reqcap ifr_ifru.ifru_cap[0] /* requested capabilities */ #define ifr_curcap ifr_ifru.ifru_cap[1] /* current capabilities */ #define ifr_index ifr_ifru.ifru_index /* interface index */ }; struct ifaliasreq { char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ struct sockaddr ifra_addr; struct sockaddr ifra_broadaddr; struct sockaddr ifra_mask; }; struct ifmediareq { char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ int ifm_current; /* current media options */ int ifm_mask; /* don't care mask */ int ifm_status; /* media status */ int ifm_active; /* active options */ int ifm_count; /* # entries in ifm_ulist array */ int *ifm_ulist; /* media words */ }; /* * Structure used to retrieve aux status data from interfaces. * Kernel suppliers to this interface should respect the formatting * needed by ifconfig(8): each line starts with a TAB and ends with * a newline. The canonical example to copy and paste is in if_tun.c. */ #define IFSTATMAX 800 /* 10 lines of text */ struct ifstat { char ifs_name[IFNAMSIZ]; /* if name, e.g. "en0" */ char ascii[IFSTATMAX + 1]; }; /* * Structure used in SIOCGIFCONF request. * Used to retrieve interface configuration * for machine (useful for programs which * must know all networks accessible). */ struct ifconf { int ifc_len; /* size of associated buffer */ union { caddr_t ifcu_buf; struct ifreq *ifcu_req; } ifc_ifcu; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ }; /* * Structure for SIOC[AGD]LIFADDR */ struct if_laddrreq { char iflr_name[IFNAMSIZ]; u_int flags; #define IFLR_PREFIX 0x8000 /* in: prefix given out: kernel fills id */ u_int prefixlen; /* in/out */ struct sockaddr_storage addr; /* in/out */ struct sockaddr_storage dstaddr; /* out */ }; #ifdef _KERNEL #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_IFADDR); MALLOC_DECLARE(M_IFMADDR); #endif #endif #ifndef _KERNEL struct if_nameindex { u_int if_index; /* 1, 2, ... */ char *if_name; /* null terminated name: "le0", ... */ }; __BEGIN_DECLS u_int if_nametoindex(const char *); char *if_indextoname(u_int, char *); struct if_nameindex *if_nameindex(void); void if_freenameindex(struct if_nameindex *); __END_DECLS #endif #ifdef _KERNEL struct thread; /* XXX - this should go away soon. */ #include #endif #endif /* !_NET_IF_H_ */ ================================================ FILE: kernel/net/pico_lock.c ================================================ #include "frosted.h" #include "locks.h" static mutex_t *picotcp_lock = NULL; void pico_lock_init(void) { if (!picotcp_lock) picotcp_lock = mutex_init(); } void pico_lock(void) { if (picotcp_lock) mutex_lock(picotcp_lock); } int pico_trylock(void) { if(picotcp_lock) return suspend_on_mutex_lock(picotcp_lock); else return 0; } int pico_trylock_kernel(void) { if (!picotcp_lock) return -EAGAIN; return mutex_trylock(picotcp_lock); } void pico_unlock(void) { if (picotcp_lock) { mutex_unlock(picotcp_lock); } } ================================================ FILE: kernel/net/route.h ================================================ #ifndef NET_ROUTE_H #define NET_ROUTE_H #include #include struct rtentry { unsigned long int rt_pad1; struct sockaddr rt_dst; struct sockaddr rt_gateway; struct sockaddr rt_genmask; unsigned short int rt_flags; short int rt_pad2; unsigned long int rt_pad3; unsigned char rt_tos; unsigned char rt_class; short int rt_pad4[sizeof(long)/2-1]; short int rt_metric; char *rt_dev; unsigned long int rt_mtu; unsigned long int rt_window; unsigned short int rt_irtt; }; #define rt_mss rt_mtu struct in6_rtmsg { struct in6_addr rtmsg_dst; struct in6_addr rtmsg_src; struct in6_addr rtmsg_gateway; uint32_t rtmsg_type; uint16_t rtmsg_dst_len; uint16_t rtmsg_src_len; uint32_t rtmsg_metric; unsigned long int rtmsg_info; uint32_t rtmsg_flags; int rtmsg_ifindex; }; #define RTF_UP 0x0001 #define RTF_GATEWAY 0x0002 #define RTF_HOST 0x0004 #define RTF_REINSTATE 0x0008 #define RTF_DYNAMIC 0x0010 #define RTF_MODIFIED 0x0020 #define RTF_MTU 0x0040 #define RTF_MSS RTF_MTU #define RTF_WINDOW 0x0080 #define RTF_IRTT 0x0100 #define RTF_REJECT 0x0200 #define RTF_STATIC 0x0400 #define RTF_XRESOLVE 0x0800 #define RTF_NOFORWARD 0x1000 #define RTF_THROW 0x2000 #define RTF_NOPMTUDISC 0x4000 #define RTF_DEFAULT 0x00010000 #define RTF_ALLONLINK 0x00020000 #define RTF_ADDRCONF 0x00040000 #define RTF_LINKRT 0x00100000 #define RTF_NONEXTHOP 0x00200000 #define RTF_CACHE 0x01000000 #define RTF_FLOW 0x02000000 #define RTF_POLICY 0x04000000 #define RTCF_VALVE 0x00200000 #define RTCF_MASQ 0x00400000 #define RTCF_NAT 0x00800000 #define RTCF_DOREDIRECT 0x01000000 #define RTCF_LOG 0x02000000 #define RTCF_DIRECTSRC 0x04000000 #define RTF_LOCAL 0x80000000 #define RTF_INTERFACE 0x40000000 #define RTF_MULTICAST 0x20000000 #define RTF_BROADCAST 0x10000000 #define RTF_NAT 0x08000000 #define RTF_ADDRCLASSMASK 0xF8000000 #define RT_ADDRCLASS(flags) ((uint32_t) flags >> 23) #define RT_TOS(tos) ((tos) & IPTOS_TOS_MASK) #define RT_LOCALADDR(flags) ((flags & RTF_ADDRCLASSMASK) \ == (RTF_LOCAL|RTF_INTERFACE)) #define RT_CLASS_UNSPEC 0 #define RT_CLASS_DEFAULT 253 #define RT_CLASS_MAIN 254 #define RT_CLASS_LOCAL 255 #define RT_CLASS_MAX 255 #define RTMSG_ACK NLMSG_ACK #define RTMSG_OVERRUN NLMSG_OVERRUN #define RTMSG_NEWDEVICE 0x11 #define RTMSG_DELDEVICE 0x12 #define RTMSG_NEWROUTE 0x21 #define RTMSG_DELROUTE 0x22 #define RTMSG_NEWRULE 0x31 #define RTMSG_DELRULE 0x32 #define RTMSG_CONTROL 0x40 #define RTMSG_AR_FAILED 0x51 #endif ================================================ FILE: kernel/nrf51/Kconfig ================================================ if ARCH_NRF51 choice prompt "MCU" default ARCH_NRF51822_QFAC config ARCH_NRF51822_QFAA bool "NRF51822_QFAA 256KB/16KB" select FLASH_SIZE_256KB select RAM_SIZE_16KB select ARCH_NRF51822 config ARCH_NRF51822_QFAB bool "NRF51822_QFAB 128KB/16KB" select FLASH_SIZE_128KB select RAM_SIZE_16KB select ARCH_NRF51822 config ARCH_NRF51822_CEAA bool "NRF51822_CEAA 256KB/16KB" select FLASH_SIZE_256KB select RAM_SIZE_16KB select ARCH_NRF51822 config ARCH_NRF51822_QFAC bool "NRF51822_QFAC 256KB/32KB" select FLASH_SIZE_256KB select RAM_SIZE_32KB select ARCH_NRF51822 config ARCH_NRF51822_CDAB bool "NRF51822_CDAB 128KB/16KB" select FLASH_SIZE_128KB select RAM_SIZE_16KB select ARCH_NRF51822 config ARCH_NRF51822_CEAA bool "NRF51822_CEAA 256KB/16KB" select FLASH_SIZE_256KB select RAM_SIZE_16KB select ARCH_NRF51822 config ARCH_NRF51822_CFAC bool "NRF51822_CFAC 256KB/32KB" select FLASH_SIZE_256KB select RAM_SIZE_32KB select ARCH_NRF51822 config ARCH_NRF51822_CTAC bool "NRF51822_CTAC 256KB/32KB" select FLASH_SIZE_256KB select RAM_SIZE_32KB select ARCH_NRF51822 config ARCH_NRF51822_CTAA bool "NRF51822_CTAA 256KB/16KB" select FLASH_SIZE_256KB select RAM_SIZE_16KB select ARCH_NRF51822 config ARCH_NRF51822_WFAC bool "NRF51822_WFAC 256KB/32KB" select FLASH_SIZE_256KB select RAM_SIZE_32KB select ARCH_NRF51822 endchoice endif ================================================ FILE: kernel/nrf51/blenanov1_5.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Roel Postelmans * */ #include "frosted.h" #include "unicore-mx/nrf/51/uart.h" #include #include "gpio.h" #include "uart.h" static const struct gpio_config Led0 = { .base=GPIO, .pin=GPIO19, .mode=GPIO_DIR_OUTPUT, .name="led0" }; static const struct uart_config uart_configs[] = { #ifdef CONFIG_DEVUART #ifdef CONFIG_UART_0 { .devidx = 0, .base = UART0, .irq = NVIC_UART0_IRQ, .baudrate = UART_BAUD_115200, .stop_bits = 1, .data_bits = 8, .parity = 0, .flow = 0, .pio_tx = { .base=GPIO, .pin=GPIO9, .mode=GPIO_MODE_INPUT, }, .pio_rx = { .base=GPIO, .pin=GPIO11, .mode=GPIO_MODE_OUTPUT, .pullupdown=GPIO_PUPD_NONE, }, }, #endif #endif }; int machine_init(void) { gpio_create(NULL, &Led0); uart_create(&uart_configs[0]); return 0; } ================================================ FILE: kernel/nrf51/nrf51.ld.in ================================================ MEMORY { FLASH (rx) : ORIGIN = __FLASH_ORIGIN, LENGTH = __KFLASHMEM_SIZE SRAM (rwx) : ORIGIN = __RAM1_BASE, LENGTH = __KRAMMEM_SIZE SRAM_USER (rwx) : ORIGIN = (__RAM1_BASE + __KRAMMEM_SIZE), LENGTH = (__RAM1_SIZE - __KRAMMEM_SIZE) } /* Enforce emmition of the vector table. */ EXTERN (vector_table) /* Define the entry point of the output file. */ ENTRY(reset_handler) SECTIONS { .text : { KEEP(*(.vectors)) *(.text*) *(.rodata*) } > FLASH /* C++ Static constructors/destructors, also used for __attribute__ * ((constructor)) and the likes */ .preinit_array : { . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; } > FLASH .init_array : { . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; } > FLASH .fini_array : { . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; } > FLASH .data : { _etext = LOADADDR(.data); _data = .; *(vtable) *(.data*) _edata = .; } > SRAM AT > FLASH _data_loadaddr = LOADADDR(.data); .bss : { _bss = .; *(.bss*) *(COMMON) . = ALIGN(32 / 8); _ebss = .; PROVIDE (end = .); } > SRAM .heap : { /* heap starts after BSS */ PROVIDE(_heap_start = _ebss ); } > SRAM } PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM)); PROVIDE(_user_heap_start = ORIGIN(SRAM_USER)); PROVIDE(_user_heap_end = ORIGIN(SRAM_USER) + LENGTH(SRAM_USER)); ================================================ FILE: kernel/nrf52/Kconfig ================================================ if ARCH_NRF52 choice prompt "MCU" default ARCH_NRF52832 config ARCH_NRF52840 bool "NRF52840 1MB/512KB" select FLASH_SIZE_1MB select RAM_SIZE_512KB config ARCH_NRF52832 bool "NRF52832 512KB/64KB" select FLASH_SIZE_512KB select RAM_SIZE_64KB config ARCH_NRF52810 bool "NRF52810 192KB/24KB" select FLASH_SIZE_192KB select RAM_SIZE_24KB endchoice endif ================================================ FILE: kernel/nrf52/blenanov2_0.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Roel Postelmans * */ #include "frosted.h" #include "unicore-mx/nrf/52/uart.h" #include #include "gpio.h" #include "uart.h" static const struct gpio_config Led0 = { .base=GPIO, .pin=GPIO11, .mode=GPIO_DIR_OUTPUT, .name="led0" }; static const struct uart_config uart_configs[] = { #ifdef CONFIG_DEVUART #ifdef CONFIG_UART_0 { .devidx = 0, .base = UART0, .irq = NVIC_UART0_IRQ, .baudrate = UART_BAUD_115200, .stop_bits = 1, .data_bits = 8, .parity = 0, .flow = 0, .pio_tx = { .base=GPIO, .pin=GPIO29, .mode=GPIO_MODE_OUTPUT, }, .pio_rx = { .base=GPIO, .pin=GPIO30, .mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, }, }, #endif #endif }; int machine_init(void) { gpio_create(NULL, &Led0); uart_create(&uart_configs[0]); return 0; } ================================================ FILE: kernel/nrf52/nrf52.ld.in ================================================ MEMORY { FLASH (rx) : ORIGIN = __FLASH_ORIGIN, LENGTH = __KFLASHMEM_SIZE SRAM (rwx) : ORIGIN = __RAM1_BASE, LENGTH = __KRAMMEM_SIZE SRAM_USER (rwx) : ORIGIN = (__RAM1_BASE + __KRAMMEM_SIZE), LENGTH = (__RAM1_SIZE - __KRAMMEM_SIZE) } /* Enforce emmition of the vector table. */ EXTERN (vector_table) /* Define the entry point of the output file. */ ENTRY(reset_handler) SECTIONS { .text : { KEEP(*(.vectors)) *(.text*) *(.rodata*) } > FLASH /* C++ Static constructors/destructors, also used for __attribute__ * ((constructor)) and the likes */ .preinit_array : { . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; } > FLASH .init_array : { . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; } > FLASH .fini_array : { . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; } > FLASH .data : { _etext = LOADADDR(.data); _data = .; *(vtable) *(.data*) _edata = .; } > SRAM AT > FLASH _data_loadaddr = LOADADDR(.data); .bss : { _bss = .; *(.bss*) *(COMMON) . = ALIGN(32 / 8); _ebss = .; PROVIDE (end = .); } > SRAM .heap : { /* heap starts after BSS */ PROVIDE(_heap_start = _ebss ); } > SRAM } PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM)); PROVIDE(_user_heap_start = ORIGIN(SRAM_USER)); PROVIDE(_user_heap_end = ORIGIN(SRAM_USER) + LENGTH(SRAM_USER)); ================================================ FILE: kernel/null.h ================================================ #ifndef INC_NULL #define INC_NULL void devnull_init(struct fnode *dev); #endif ================================================ FILE: kernel/pico_port.h ================================================ #ifndef PICO_PORT_FROSTED_INCLUDED #define PICO_PORT_FROSTED_INCLUDED #define PICO_SUPPORT_MUTEX #ifdef FROSTED #include "frosted.h" #include "string.h" #include "malloc.h" #include "locks.h" #include "kprintf.h" #define pico_free(x) f_free(x) #define pico_zalloc(x) f_calloc(MEM_TCPIP, x, 1) static void *pico_mutex_init(void) { return mutex_init(); } static void pico_mutex_lock(void *m) { mutex_lock((mutex_t *)m); } static void pico_mutex_unlock(void *m) { mutex_unlock((mutex_t *)m); } static void pico_mutex_deinit(void *m) { mutex_destroy((mutex_t *)m); } #define dbg kprintf static inline pico_time PICO_TIME_MS() { return jiffies; } static inline pico_time PICO_TIME() { return jiffies / 1000; } static inline void PICO_IDLE(void) { } #else #error "file pico_port.h included, but no FROSTED define." #endif #endif ================================================ FILE: kernel/pipe.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera * */ #include "frosted.h" #include "scheduler.h" #include "cirbuf.h" #include "string.h" #include "sys/termios.h" #include "poll.h" #ifdef CONFIG_PIPE #define PIPE_BUFSIZE 64 static struct module mod_pipe; struct pipe_priv { struct fnode *fno_r; struct fnode *fno_w; struct task *task_r; struct task *task_w; int w_off; struct cirbuf *cb; }; static struct fnode PIPE_ROOT = { }; int sys_pipe2_hdlr(int paddr, int flags) { int *pfd = (int*)paddr; struct fnode *rd, *wr; struct pipe_priv *pp; if (task_ptr_valid(pfd)) return -EACCES; pp = kalloc(sizeof (struct pipe_priv)); if (!pp) { return -ENOMEM; } rd = fno_create(&mod_pipe, "", &PIPE_ROOT); if (!rd) { goto fail_rd; } wr = fno_create(&mod_pipe, "", &PIPE_ROOT); if (!wr) { goto fail_wr; } pfd[0] = task_filedesc_add(rd); pfd[1] = task_filedesc_add(wr); if (pfd[0] < 0 || pfd[1] < 0) { goto fail_all; } task_fd_setmask(pfd[0], O_RDONLY); task_fd_setmask(pfd[1], O_WRONLY); rd->priv = pp; wr->priv = pp; pp->fno_r = rd; pp->fno_w = wr; pp->task_r = NULL; pp->task_w = NULL; pp->w_off = 0; pp->cb = cirbuf_create(PIPE_BUFSIZE); if (!pp->cb) { goto fail_all; } return 0; fail_all: fno_unlink(wr); fail_wr: fno_unlink(rd); fail_rd: kfree(pp); return -ENOMEM; } static int pipe_poll(struct fnode *f, uint16_t events, uint16_t *revents) { struct pipe_priv *pp; if (f->owner != &mod_pipe) return -EINVAL; pp = (struct pipe_priv *)f->priv; if (!pp) { return -EINVAL; } if (f == pp->fno_w) { if(pp->fno_r == 0) { *revents |= POLLHUP; return 1; } else if ((events & POLLOUT) && (cirbuf_bytesfree(pp->cb) > 0)) { *revents = POLLOUT; return 1; } } if ((f == pp->fno_r) && (events & POLLIN) && (cirbuf_bytesinuse(pp->cb) > 0)) { *revents |= POLLIN; return 1; } return 0; } static int pipe_close(struct fnode *f) { struct pipe_priv *pp; struct task *t; t = this_task(); if (!f) return -EINVAL; if (f->owner != &mod_pipe) return -EINVAL; pp = (struct pipe_priv *)f->priv; if (!pp) return -EINVAL; if (f == pp->fno_r) { pp->fno_r = NULL; fno_unlink(f); if ((pp->task_w != t) && (pp->task_w != NULL)) { task_resume(pp->task_w); } } if (f == pp->fno_w) { pp->fno_w = NULL; fno_unlink(f); if ((pp->task_r != t) && (pp->task_r != NULL)) { task_resume(pp->task_r); } } if ((!pp->fno_w) && (!pp->fno_r)) kfree(pp); return 0; } static int pipe_read(struct fnode *f, void *buf, unsigned int len) { struct pipe_priv *pp; int out, len_available; uint8_t *ptr = buf; if (f->owner != &mod_pipe) return -EINVAL; pp = (struct pipe_priv *)f->priv; if (!pp) return -EINVAL; if (pp->fno_r != f) return -EPERM; len_available = cirbuf_bytesinuse(pp->cb); if (len_available <= 0) { if (FNO_BLOCKING(f)) { pp->task_r = this_task(); task_suspend(); return SYS_CALL_AGAIN; } else { return -EWOULDBLOCK; } } for(out = 0; out < len; out++) { /* read data */ if (cirbuf_readbyte(pp->cb, ptr) != 0) break; ptr++; } pp->task_r = 0; return out; } static int pipe_write(struct fnode *f, const void *buf, unsigned int len) { struct pipe_priv *pp; int out, len_available; const uint8_t *ptr = buf; if (f->owner != &mod_pipe) return -EINVAL; pp = (struct pipe_priv *)f->priv; if (!pp) return -EINVAL; if (pp->fno_w != f) return -EPERM; out = pp->w_off; len_available = cirbuf_bytesfree(pp->cb); if (len_available > (len - out)) len_available = (len - out); for(; out < len_available; out++) { /* write data */ if (cirbuf_writebyte(pp->cb, *(ptr + out)) != 0) break; } if (out < len) { if (FNO_BLOCKING(f)) { pp->task_w = this_task(); pp->w_off = out; task_suspend(); return SYS_CALL_AGAIN; } else { if (out == 0) return -EWOULDBLOCK; } } pp->w_off = 0; pp->task_w = NULL; return out; } void sys_pipe_init(void) { mod_pipe.family = FAMILY_DEV; strcpy(mod_pipe.name,"pipe"); mod_pipe.ops.poll = pipe_poll; mod_pipe.ops.close = pipe_close; mod_pipe.ops.read = pipe_read; mod_pipe.ops.write = pipe_write; register_module(&mod_pipe); } #else # define sys_pipe_init() do{}while(0) int sys_pipe2_hdlr(int paddr, int flags) { return -ENOSYS; } #endif ================================================ FILE: kernel/scheduler.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent, Antonio Cardace, brabo * */ #include "frosted.h" #include "sys/frosted.h" #include "string.h" /* flibc string.h */ #include "signal.h" #include "kprintf.h" #include "sys/wait.h" #include "vfs.h" #include "sys/pthread.h" #include "fpb.h" #include "poll.h" #include "lowpower.h" #include "sys/user.h" #define __inl inline #define __naked __attribute__((naked)) /* Full kernel space separation */ #define RUN_HANDLER (0xfffffff1u) #define MSP "msp" #define PSP "psp" #define RUN_KERNEL (0xfffffff9u) #define RUN_USER (0xfffffffdu) #define SV_CALL_SIGRETURN 0xFFFFFFF8 #define STACK_THRESHOLD 64 /* TOP to Bottom: EXTRA | NVIC | T_EXTRA | T_NVIC */ volatile struct extra_stack_frame *cur_extra; volatile struct nvic_stack_frame *cur_nvic; volatile struct extra_stack_frame *tramp_extra; volatile struct nvic_stack_frame *tramp_nvic; volatile struct extra_stack_frame *extra_usr; int task_ptr_valid(const void *ptr); #ifdef CONFIG_SYSCALL_TRACE #define STRACE_SIZE 10 struct strace { int pid; int n; uint32_t sp; }; volatile struct strace Strace[STRACE_SIZE]; volatile int StraceTop = 0; #endif #ifdef CONFIG_EXTENDED_MEMFAULT static char _my_x_str[11] = ""; static char *x_str(uint32_t x) { int i; uint8_t val; _my_x_str[0] = '0'; _my_x_str[1] = 'x'; for (i = 0; i < 8; i++) { val = (((x >> ((7 - i) << 2)) & 0x0000000F)); if (val < 10) _my_x_str[i + 2] = val + '0'; else _my_x_str[i + 2] = (val - 10) + 'A'; } _my_x_str[10] = 0; return _my_x_str; } static char _my_pid_str[6]; static char *pid_str(uint16_t p) { int i = 0; if (p >= 10000) { _my_pid_str[i++] = (p / 10000) + '0'; p = p % 10000; } if (i > 0 || p >= 1000) { _my_pid_str[i++] = (p / 1000) + '0'; p = p % 1000; } if (i > 0 || p >= 100) { _my_pid_str[i++] = (p / 100) + '0'; p = p % 100; } if (i > 0 || p >= 10) { _my_pid_str[i++] = (p / 10) + '0'; p = p % 10; } _my_pid_str[i++] = p + '0'; _my_pid_str[i] = 0; return _my_pid_str; } #endif /* Array of syscalls */ static void *sys_syscall_handlers[_SYSCALLS_NR] = { }; int sys_register_handler(uint32_t n, int (*_sys_c)(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5)) { if (n >= _SYSCALLS_NR) return -1; /* Attempting to register non-existing syscall */ if (sys_syscall_handlers[n] != NULL) return -1; /* Syscall already registered */ sys_syscall_handlers[n] = _sys_c; return 0; } #define MAX_TASKS 16 #define BASE_TIMESLICE (20) #define TIMESLICE(x) ((BASE_TIMESLICE) - ((x)->tb.nice >> 1)) #define SCHEDULER_STACK_SIZE \ ((CONFIG_TASK_STACK_SIZE - sizeof(struct task_block)) - F_MALLOC_OVERHEAD) #define INIT_SCHEDULER_STACK_SIZE (256) struct __attribute__((packed)) nvic_stack_frame { uint32_t r0; uint32_t r1; uint32_t r2; uint32_t r3; uint32_t r12; uint32_t lr; uint32_t pc; uint32_t psr; #if (__CORTEX_M == 4) /* CORTEX-M4 saves FPU frame as well */ uint32_t s0; uint32_t s1; uint32_t s2; uint32_t s3; uint32_t s4; uint32_t s5; uint32_t s6; uint32_t s7; uint32_t s8; uint32_t s9; uint32_t s10; uint32_t s11; uint32_t s12; uint32_t s13; uint32_t s14; uint32_t s15; uint32_t fpscr; uint32_t dummy; #endif }; /* In order to keep the code efficient, the stack layout of armv6 and armv7 do NOT match! */ struct __attribute__((packed)) extra_stack_frame { #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) uint32_t r4; uint32_t r5; uint32_t r6; uint32_t r7; uint32_t r8; uint32_t r9; uint32_t r10; uint32_t r11; #elif defined(__ARM_ARCH_6M__) uint32_t r8; uint32_t r9; uint32_t r10; uint32_t r11; uint32_t r4; uint32_t r5; uint32_t r6; uint32_t r7; #endif }; #define NVIC_FRAME_SIZE ((sizeof(struct nvic_stack_frame))) #define EXTRA_FRAME_SIZE ((sizeof(struct extra_stack_frame))) static void *_top_stack; #define TASK_FLAG_VFORK 0x01 #define TASK_FLAG_IN_SYSCALL 0x02 #define TASK_FLAG_SIGNALED 0x04 #define TASK_FLAG_INTR 0x40 #define TASK_FLAG_SYSCALL_STOP 0x80 /* thread related */ #define TASK_FLAG_DETACHED 0x0100 #define TASK_FLAG_CANCELABLE 0x0200 #define TASK_FLAG_PENDING_CANC 0x0400 /* Timer expired */ #define TASK_FLAG_TIMEOUT 0x0800 struct filedesc { struct fnode *fno; uint32_t off; uint32_t mask; uint32_t flags; }; struct filedesc_table { uint32_t n_files; uint32_t usage_count; struct filedesc *fdesc; }; struct task_handler { int signo; void (*hdlr)(int); uint32_t mask; struct task_handler *next; }; #ifdef CONFIG_PTHREADS struct thread_group { struct task **threads; uint16_t active_threads; uint16_t n_threads; uint16_t max_tid; pthread_key_t max_key; }; #else struct thread_group { uint32_t _off; }; #endif static void destroy_thread_group(struct thread_group *group, uint16_t tid); struct __attribute__((packed)) task_block { /* Watch out for alignment here * (try to pack togehter smaller fields) * */ void (*start)(void *); void *arg; uint16_t flags; uint8_t state; int8_t nice; uint16_t timeslice; uint16_t pid; uint16_t ppid; uint16_t tid; uint16_t joiner_thread_tid; uint16_t _padding; struct thread_group *tgroup; struct task *tracer; int exitval; struct fnode *cwd; struct task_handler *sighdlr; sigset_t sigmask; sigset_t sigpend; struct filedesc_table *filedesc_table; void *sp; void *osp; void *cur_stack; struct task *next; struct vfs_info *vfsi; int timer_id; uint32_t *specifics; uint32_t n_specifics; }; struct __attribute__((packed)) task { struct task_block tb; uint32_t stack[SCHEDULER_STACK_SIZE / 4]; }; static struct task struct_task_kernel; static struct task *const kernel = (struct task *)(&struct_task_kernel); static int number_of_tasks = 0; static void tasklist_add(struct task **list, struct task *el) { el->tb.next = *list; *list = el; } static int tasklist_del(struct task **list, struct task *togo) { struct task *t = *list; struct task *p = NULL; while (t) { if (t == togo) { if (p == NULL) *list = t->tb.next; else p->tb.next = t->tb.next; return 0; } p = t; t = t->tb.next; } return -1; } static int tasklist_len(struct task **list) { struct task *t = *list; struct task *p = NULL; int len = 0; while (t) { len++; t = t->tb.next; } return len; } static struct task *tasklist_get(struct task **list, uint16_t pid) { struct task *t = *list; while (t) { if ((t->tb.pid == pid) && (t->tb.tid == 1)) return t; t = t->tb.next; } return NULL; } static struct task *tasks_running = NULL; static struct task *tasks_idling = NULL; void task_resume(struct task *t); void task_resume_lock(struct task *t); void task_stop(struct task *t); void task_continue(struct task *t); void task_terminate(struct task *t); static void task_suspend_to(int newstate); void task_deliver_sigchld(void *arg); void task_deliver_sigtrap(void *arg); static void ftable_destroy(struct task *t); static void idling_to_running(struct task *t) { if (tasklist_del(&tasks_idling, t) == 0) tasklist_add(&tasks_running, t); } static void running_to_idling(struct task *t) { if ((t->tb.pid < 1) && (t->tb.tid <= 1)) return; if (tasklist_del(&tasks_running, t) == 0) tasklist_add(&tasks_idling, t); } static int task_filedesc_del_from_task(struct task *t, int fd); /* Catch-all destroy functions for processes and threads. * * Single point of deallocation for all the memory related * to task management. */ static void task_destroy(void *arg) { struct task *t = arg; int i; struct filedesc_table *ft; struct thread_group *grp; if (!t) return; tasklist_del(&tasks_running, t); tasklist_del(&tasks_idling, t); #ifdef CONFIG_PTHREADS grp = t->tb.tgroup; if ((grp) && (grp->active_threads > 0)) { /* if single sub-thread being destroyed, delete from * the group->threads array, so the position can * be reused. * * We never get here after a destroy_thread_group() * that has been called by the leader, because t->group * has been set to NULL. */ for (i = 0; i < grp->n_threads; i++) { if (grp->threads[i] == t) { grp->threads[i] = NULL; } } } else { /* Last (or the one) thread in group being destroyed. Free resources. */ if (grp) destroy_thread_group(grp, t->tb.tid); /* Get rid of allocated arguments */ if (t->tb.arg) { char **arg = (char **)(t->tb.arg); i = 0; while (arg[i]) { f_free(arg[i]); i++; } } f_free(t->tb.arg); /* Close files & Destroy the file table */ ft = t->tb.filedesc_table; for (i = 0; (ft) && (i < ft->n_files); i++) { task_filedesc_del_from_task(t, i); } ftable_destroy(t); /* free allocated VFS mem, e.g. by bflt_load */ if (t->tb.vfsi) { // kprintf("Freeing VFS type %d allocated pointer 0x%p\r\n", // t->tb.vfsi->type, t->tb.vfsi->allocated); if ((t->tb.vfsi->type == VFS_TYPE_BFLT) && (t->tb.vfsi->allocated)) f_free(t->tb.vfsi->allocated); f_free(t->tb.vfsi); } /* free pre-allocated thread space */ if (grp) { kfree(grp->threads); kfree(grp); t->tb.tgroup = NULL; } /* Remove heap allocations spawned by this pid. */ f_proc_heap_free(t->tb.pid); } /* Free any pthread-specific key value */ if (t->tb.specifics) kfree(t->tb.specifics); #else /* Get rid of allocated arguments */ if (t->tb.arg) { char **arg = (char **)(t->tb.arg); i = 0; while (arg[i]) { f_free(arg[i]); i++; } } f_free(t->tb.arg); /* Close files & Destroy the file table */ ft = t->tb.filedesc_table; for (i = 0; (ft) && (i < ft->n_files); i++) { task_filedesc_del_from_task(t, i); } ftable_destroy(t); /* free allocated VFS mem, e.g. by bflt_load */ if (t->tb.vfsi) { // kprintf("Freeing VFS type %d allocated pointer 0x%p\r\n", // t->tb.vfsi->type, t->tb.vfsi->allocated); if ((t->tb.vfsi->type == VFS_TYPE_BFLT) && (t->tb.vfsi->allocated)) f_free(t->tb.vfsi->allocated); f_free(t->tb.vfsi); } /* Remove heap allocations spawned by this pid. */ f_proc_heap_free(t->tb.pid); #endif /* Get rid of stack space allocation, timer. */ if (t->tb.timer_id >= 0) ktimer_del(t->tb.timer_id); task_space_free(t); number_of_tasks--; } static struct task *_cur_task = NULL; static struct task *forced_task = NULL; static __inl int in_kernel(void) { return ((_cur_task->tb.pid == 0) && (_cur_task->tb.tid <= 1)); } struct task *this_task(void) { /* External modules like locks.c expect this to * return NULL when in kernel */ if (in_kernel()) return NULL; return _cur_task; } int task_get_timer_id(void) { return _cur_task->tb.timer_id; } void task_set_timer_id(int id) { _cur_task->tb.timer_id = id; } int task_in_syscall(void) { return ((_cur_task->tb.flags & TASK_FLAG_IN_SYSCALL) == TASK_FLAG_IN_SYSCALL); } static int next_pid(void) { static unsigned int next_available = 0; uint16_t ret = (uint16_t)((next_available)&0xFFFF); next_available++; if (next_available > 0xFFFF) { next_available = 2; } while (tasklist_get(&tasks_idling, next_available) || tasklist_get(&tasks_running, next_available)) next_available++; return ret; } /********************************/ /* Handling of file descriptors */ /********************************/ /********************************/ /********************************/ /**/ /**/ /**/ static struct filedesc_table *ftable_create(struct task *t) { struct filedesc_table *ft = t->tb.filedesc_table; if (ft) return ft; ft = kcalloc(sizeof(struct filedesc_table), 1); if (!ft) return NULL; ft->usage_count = 1; t->tb.filedesc_table = ft; return ft; } static void ftable_destroy(struct task *t) { struct filedesc_table *ft = t->tb.filedesc_table; if (ft) { if (--ft->usage_count == 0) { if (ft->fdesc) kfree(ft->fdesc); kfree(ft); } } t->tb.filedesc_table = NULL; } static int task_filedesc_add_to_task(struct task *t, struct fnode *f) { int i; void *re; struct filedesc_table *ft = t->tb.filedesc_table; if (!t || !f) return -EINVAL; if (!ft) ft = ftable_create(t); for (i = 0; i < ft->n_files; i++) { if (ft->fdesc[i].fno == NULL) { f->usage_count++; ft->fdesc[i].fno = f; return i; } } ft->n_files++; re = (void *)krealloc(ft->fdesc, ft->n_files * sizeof(struct filedesc)); if (!re) return -1; ft->fdesc = re; memset(&(ft->fdesc[ft->n_files - 1]), 0, sizeof(struct filedesc)); ft->fdesc[ft->n_files - 1].fno = f; if (f->flags & FL_TTY) { struct module *mod = f->owner; if (mod && mod->ops.tty_attach) { mod->ops.tty_attach(f, t->tb.pid); } } f->usage_count++; return ft->n_files - 1; } int task_filedesc_add(struct fnode *f) { return task_filedesc_add_to_task(_cur_task, f); } static int task_filedesc_del_from_task(struct task *t, int fd) { struct fnode *fno; struct filedesc_table *ft; if (!t) return -EINVAL; ft = t->tb.filedesc_table; fno = ft->fdesc[fd].fno; if (!fno) return -ENOENT; /* Reattach controlling tty to parent task */ if ((fno->flags & FL_TTY) && ((ft->fdesc[fd].mask & O_NOCTTY) == 0)) { struct module *mod = fno->owner; if (mod && mod->ops.tty_attach) { mod->ops.tty_attach(fno, t->tb.ppid); } } /* If this was the last user of the file, close it. */ fno->usage_count--; if (fno->usage_count <= 0) { if (fno->owner && fno->owner->ops.close) fno->owner->ops.close(fno); } ft->fdesc[fd].fno = NULL; } int task_filedesc_del(int fd) { return task_filedesc_del_from_task(_cur_task, fd); } int task_fd_setmask(int fd, uint32_t mask) { struct filedesc_table *ft; struct fnode *fno; ft = _cur_task->tb.filedesc_table; if (!ft) return -EINVAL; if (fd < 0 || fd > ft->n_files) return -ENOENT; fno = ft->fdesc[fd].fno; if (!fno) return -ENOENT; if ((mask & O_ACCMODE) != O_RDONLY) { if ((fno->flags & FL_WRONLY) == 0) return -EPERM; } ft->fdesc[fd].mask = mask; return 0; } uint32_t task_fd_getmask(int fd) { struct filedesc_table *ft; ft = _cur_task->tb.filedesc_table; if (fd < 0 || fd > ft->n_files) return 0; if (ft->fdesc[fd].fno) return ft->fdesc[fd].mask; return 0; } uint32_t task_fd_set_flags(int fd, uint32_t flags) { struct filedesc_table *ft; struct fnode *fno; ft = _cur_task->tb.filedesc_table; if (!ft) return -EINVAL; if (fd < 0 || fd > ft->n_files) return -ENOENT; fno = ft->fdesc[fd].fno; if (!fno) return -ENOENT; ft->fdesc[fd].flags = flags; return 0; } uint32_t task_fd_get_flags(int fd) { struct fnode *fno; struct filedesc_table *ft; struct filedesc *fdesc; ft = _cur_task->tb.filedesc_table; if (!ft) return -EINVAL; if (fd < 0 || fd > ft->n_files) return -ENOENT; fdesc = &ft->fdesc[fd]; if (!fdesc) return -ENOENT; return fdesc->flags; } uint32_t task_fd_set_off(struct fnode *fno, uint32_t off) { struct filedesc_table *ft; struct filedesc *fdesc; int fd; int found = 0; ft = _cur_task->tb.filedesc_table; if (!ft) return 0; /* Set offset to all instances of the file in the ft */ for (fd = 0; fd < ft->n_files; fd++) { if (ft->fdesc[fd].fno == fno) { ft->fdesc[fd].off = off; found++; } } if (found) return off; return 0; } uint32_t task_fd_get_off(struct fnode *fno) { struct filedesc_table *ft; struct filedesc *fdesc; int fd; ft = _cur_task->tb.filedesc_table; if (!ft) return 0; for (fd = 0; fd < ft->n_files; fd++) { if (ft->fdesc[fd].fno == fno) return ft->fdesc[fd].off; } return 0; } struct fnode *task_filedesc_get(int fd) { struct task *t = _cur_task; struct filedesc_table *ft; if (!t) return NULL; ft = t->tb.filedesc_table; if (!ft) return NULL; if (fd < 0) return NULL; if (fd >= ft->n_files) return NULL; if ((ft->n_files - 1) < fd) return NULL; if (ft->fdesc[fd].fno == NULL) return NULL; return ft->fdesc[fd].fno; } int task_fd_readable(int fd) { if (!task_filedesc_get(fd)) return 0; return 1; } int task_fd_writable(int fd) { if (!task_filedesc_get(fd)) return 0; if ((_cur_task->tb.filedesc_table->fdesc[fd].mask & O_ACCMODE) == O_RDONLY) return 0; return 1; } int sys_dup_hdlr(int fd) { struct task *t = _cur_task; struct fnode *f = task_filedesc_get(fd); int newfd = -1; if (!f) return -1; newfd = task_filedesc_add(f); if (newfd >= 0) _cur_task->tb.filedesc_table->fdesc[newfd].mask = _cur_task->tb.filedesc_table->fdesc[fd].mask; return newfd; } int sys_dup2_hdlr(int fd, int newfd) { struct task *t = _cur_task; struct fnode *f = task_filedesc_get(fd); struct filedesc_table *ft = t->tb.filedesc_table; if (!ft) return -1; if (newfd < 0) return -1; if (newfd == fd) return -1; if (!f) return -1; /* TODO: create empty fnodes up until newfd */ if (newfd >= ft->n_files) return -1; if (ft->fdesc[newfd].fno != NULL) task_filedesc_del(newfd); ft->fdesc[newfd].fno = f; return newfd; } /********************************/ /* Signals */ /********************************/ /********************************/ /********************************/ /**/ /**/ /**/ #ifdef CONFIG_SIGNALS static void sig_trampoline(struct task *t, struct task_handler *h, int signo); int sys_kill_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5); static int catch_signal(struct task *t, int signo, sigset_t orig_mask) { int i; struct task_handler *sighdlr; struct task_handler *h = NULL; if (!t || (t->tb.pid < 1)) return -EINVAL; if ((t->tb.state == TASK_ZOMBIE) || (t->tb.state == TASK_OVER) || (t->tb.state == TASK_FORKED)) return -ESRCH; if (((1 << signo) & t->tb.sigmask) && (h->hdlr != SIG_IGN)) { /* Signal is blocked via t->tb.sigmask */ t->tb.sigpend |= (1 << signo); return 0; } /* If process is being traced, deliver SIGTRAP to tracer */ if (t->tb.tracer != NULL) { tasklet_add(task_deliver_sigtrap, t->tb.tracer); } /* Reset signal, if pending, as it's going to be handled. */ t->tb.sigpend &= ~(1 << signo); sighdlr = t->tb.sighdlr; while (sighdlr) { if (signo == sighdlr->signo) h = sighdlr; sighdlr = sighdlr->next; } if ((h) && (signo != SIGKILL) && (signo != SIGSEGV)) { /* Handler is present */ if ((h->hdlr == NULL) || (h->hdlr == SIG_IGN)) return 0; if (_cur_task == t) { h->hdlr(signo); } else { sig_trampoline(t, h, signo); } } else { /* Handler not present: SIG_DFL */ if (signo == SIGSTOP) { task_stop(t); } else if (signo == SIGCHLD) { task_resume(t); } else if (signo == SIGCONT) { /* If not in stopped state, SIGCONT is ignored. */ task_continue(t); } else { task_terminate(t); } } return 0; } static void check_pending_signals(struct task *t) { int i; t->tb.sigpend &= ~(t->tb.sigmask); while (t->tb.sigpend != 0u) { for (i = 1; i < SIGMAX; i++) { if ((1 << i) & t->tb.sigpend) catch_signal(t, i, t->tb.sigmask); } } } static int add_handler(struct task *t, int signo, void (*hdlr)(int), uint32_t mask) { struct task_handler *sighdlr; if (!t || (t->tb.pid < 1)) return -EINVAL; sighdlr = kalloc(sizeof(struct task_handler)); if (!sighdlr) return -ENOMEM; sighdlr->signo = signo; sighdlr->hdlr = hdlr; sighdlr->mask = mask; sighdlr->next = t->tb.sighdlr; t->tb.sighdlr = sighdlr; check_pending_signals(t); return 0; } static int del_handler(struct task *t, int signo) { struct task_handler *sighdlr; struct task_handler *prev = NULL; if (!t || (t->tb.pid < 1)) return -EINVAL; sighdlr = t->tb.sighdlr; while (sighdlr) { if (sighdlr->signo == signo) { if (prev == NULL) { t->tb.sighdlr = sighdlr->next; } else { prev->next = sighdlr->next; } kfree(sighdlr); check_pending_signals(t); return 0; } prev = sighdlr; sighdlr = sighdlr->next; } return -ESRCH; } static void sig_hdlr_return(uint32_t arg) { /* XXX: In order to use per-sigaction sa_mask, we need to set * t->tb.sigmask in the catch, and restore it here. */ /* call special svc with n = SV_CALL_SIGRETURN */ asm volatile("mov r0, %0" ::"r"(SV_CALL_SIGRETURN)); asm volatile("svc 0\n"); // asm volatile ("pop {r4-r11}\n"); } static void sig_trampoline(struct task *t, struct task_handler *h, int signo) { cur_extra = t->tb.sp + NVIC_FRAME_SIZE + EXTRA_FRAME_SIZE; cur_nvic = t->tb.sp + EXTRA_FRAME_SIZE; tramp_extra = t->tb.sp - EXTRA_FRAME_SIZE; tramp_nvic = t->tb.sp - (EXTRA_FRAME_SIZE + NVIC_FRAME_SIZE); extra_usr = t->tb.sp; /* Save stack pointer for later */ memcpy((void *)t->tb.sp, (void *)cur_extra, EXTRA_FRAME_SIZE); t->tb.osp = t->tb.sp; /* Copy the EXTRA_FRAME into the trampoline extra, to preserve R9 for * userspace relocations etc. */ memcpy((void *)tramp_extra, (void *)cur_extra, EXTRA_FRAME_SIZE); memset((void *)tramp_nvic, 0, NVIC_FRAME_SIZE); tramp_nvic->pc = (uint32_t)h->hdlr; tramp_nvic->lr = (uint32_t)sig_hdlr_return; tramp_nvic->r0 = (uint32_t)signo; tramp_nvic->psr = cur_nvic->psr; t->tb.sp = (t->tb.osp - (EXTRA_FRAME_SIZE + NVIC_FRAME_SIZE)); t->tb.sp -= EXTRA_FRAME_SIZE; memcpy((void *)t->tb.sp, (void *)cur_extra, EXTRA_FRAME_SIZE); t->tb.flags |= TASK_FLAG_SIGNALED; task_resume(t); } #else #define check_pending_signals(...) do{}while(0) #define add_handler(...) (0) #define del_handler(...) (0) #define sig_hdlr_return NULL static int catch_signal(struct task *t, int signo, sigset_t orig_mask) { (void)orig_mask; if (signo != SIGCHLD) task_terminate(t); return 0; } #endif void task_resume(struct task *t); void task_resume_lock(struct task *t); void task_stop(struct task *t); void task_continue(struct task *t); int sys_sigaction_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct sigaction *sa = (struct sigaction *)arg2; struct sigaction *sa_old = (struct sigaction *)arg3; struct task_handler *sighdlr; if (sa && task_ptr_valid(sa)) return -EACCES; if (sa_old && task_ptr_valid(sa_old)) return -EACCES; if (_cur_task->tb.pid < 1) return -EINVAL; if (arg1 >= SIGMAX || arg1 < 1) return -EINVAL; /* Populating sa_old */ if (sa_old) { sighdlr = _cur_task->tb.sighdlr; while (sighdlr) { if (arg1 == sighdlr->signo) break; sighdlr = sighdlr->next; } if (sighdlr) { sa_old->sa_mask = (sigset_t)sighdlr->mask; sa_old->sa_handler = sighdlr->hdlr; } else { sa_old->sa_mask = (sigset_t)0u; sa_old->sa_handler = SIG_DFL; } sa_old->sa_flags = 0; sa_old->sa_restorer = NULL; } if (sa) add_handler(_cur_task, arg1, sa->sa_handler, sa->sa_mask); return 0; } int sys_sigprocmask_hdlr(int how, const sigset_t *set, sigset_t *oldset) { if (set && ((how != SIG_SETMASK) && (how != SIG_BLOCK) && (how != SIG_UNBLOCK))) return -EINVAL; if (!set && !oldset) return -EINVAL; if (oldset) { if (task_ptr_valid(oldset)) return -EACCES; *oldset = _cur_task->tb.sigmask; } if (set) { if (task_ptr_valid(set)) return -EACCES; if (how == SIG_SETMASK) _cur_task->tb.sigmask = *set; else if (how == SIG_BLOCK) _cur_task->tb.sigmask |= *set; else _cur_task->tb.sigmask &= ~(*set); check_pending_signals(_cur_task); } return 0; } int sys_sigsuspend_hdlr(const sigset_t *mask) { uint32_t orig_mask = _cur_task->tb.sigmask; if (!mask) return -EINVAL; if (task_ptr_valid(mask)) return -EACCES; _cur_task->tb.sigmask = ~(*mask); task_suspend(); _cur_task->tb.sigmask = orig_mask; /* Success. */ return -EINTR; } /********************************/ /* working dir */ /********************************/ /********************************/ /********************************/ /**/ /**/ /**/ struct fnode *task_getcwd(void) { return _cur_task->tb.cwd; } void task_chdir(struct fnode *f) { _cur_task->tb.cwd = f; } static __inl void *msp_read(void) { void *ret = NULL; asm volatile("mrs %0, msp" : "=r"(ret)); return ret; } static __inl void *psp_read(void) { void *ret = NULL; asm volatile("mrs %0, psp" : "=r"(ret)); return ret; } int scheduler_ntasks(void) { return number_of_tasks; } int scheduler_task_state(int pid) { struct task *t = tasklist_get(&tasks_running, pid); if (!t) t = tasklist_get(&tasks_idling, pid); if (t) return t->tb.state; else return TASK_OVER; } int scheduler_can_sleep(void) { if (tasklist_len(&tasks_running) == 1) return 1; else return 0; } unsigned scheduler_stack_used(int pid) { struct task *t = tasklist_get(&tasks_running, pid); if (!t) t = tasklist_get(&tasks_idling, pid); if (t) return SCHEDULER_STACK_SIZE - ((char *)t->tb.sp - (char *)t->tb.cur_stack); else return 0; } char *scheduler_task_name(int pid) { struct task *t = tasklist_get(&tasks_running, pid); if (!t) t = tasklist_get(&tasks_idling, pid); if (t) { char **argv = t->tb.arg; if (argv) return argv[0]; } else return NULL; } static uint16_t scheduler_get_cur_pid(void) { if (!_cur_task) return 0; return _cur_task->tb.pid; } uint16_t this_task_getpid(void) { return scheduler_get_cur_pid(); } int task_running(void) { return (_cur_task->tb.state == TASK_RUNNING); } int task_timeslice(void) { return (--_cur_task->tb.timeslice); } void task_end(void) { /* We have to set the stack pointer because we jumped here * after setting lr to task_end into the NVIC_FRAME and there * we were using the sp of the task's parent */ asm volatile("msr " PSP ", %0" ::"r"(_cur_task->tb.sp)); /* here we need to be in a irqoff context because we are dealing with the scheduler data structures, otherwise we could produce dead code after callling running_to_idling */ irq_off(); running_to_idling(_cur_task); _cur_task->tb.state = TASK_ZOMBIE; asm volatile("mov %0, r0" : "=r"(_cur_task->tb.exitval)); irq_on(); while (1) { task_suspend_to(TASK_ZOMBIE); } } /********************************/ /* Task creation */ /*** vfork() / exec() ***/ /********************************/ /********************************/ /**/ /**/ /**/ static void task_resume_vfork(struct task *t); /* Duplicate exec() args into the new process address space. */ static void *task_pass_args(void *_args) { char **args = (char **)_args; char **new = NULL; int i = 0, n = 0; if (!_args) return NULL; while (args[n] != NULL) { n++; } new = u_malloc((n + 1) * (sizeof(char *))); if (!new) return NULL; new[n] = NULL; for (i = 0; i < n; i++) { size_t l = strlen(args[i]); if (l > 0) { new[i] = u_malloc(l + 1); if (!new[i]) break; memcpy(new[i], args[i], l + 1); } } return new; } static void task_create_real(struct task *new, struct vfs_info *vfsi, void *arg, unsigned int nice) { struct nvic_stack_frame *nvic_frame; struct extra_stack_frame *extra_frame; uint8_t *sp; if (nice < NICE_RT) nice = NICE_RT; if (nice > NICE_MAX) nice = NICE_MAX; new->tb.start = vfsi->init; new->tb.arg = task_pass_args(arg); new->tb.timeslice = TIMESLICE(new); new->tb.state = TASK_RUNNABLE; new->tb.sighdlr = NULL; new->tb.sigpend = 0; new->tb.sigmask = 0; new->tb.tracer = NULL; new->tb.timer_id = -1; new->tb.specifics = NULL; new->tb.n_specifics = 0; if ((new->tb.flags &TASK_FLAG_VFORK) != 0) { struct task *pt = tasklist_get(&tasks_idling, new->tb.ppid); if (!pt) pt = tasklist_get(&tasks_running, new->tb.ppid); if (pt) { /* Restore parent's stack */ memcpy((void *)pt->tb.cur_stack, (void *)&new->stack, SCHEDULER_STACK_SIZE); task_resume_vfork(pt); } new->tb.flags &= (~TASK_FLAG_VFORK); } /* stack memory */ sp = (((uint8_t *)(&new->stack)) + SCHEDULER_STACK_SIZE - NVIC_FRAME_SIZE); new->tb.cur_stack = &new->stack; /* Change relocated section ownership */ fmalloc_chown((void *)vfsi->pic, new->tb.pid); /* Stack frame is at the end of the stack space, the NVIC_FRAME is required for context-switching */ nvic_frame = (struct nvic_stack_frame *)sp; memset(nvic_frame, 0, NVIC_FRAME_SIZE); nvic_frame->r0 = (uint32_t) new->tb.arg; nvic_frame->pc = (uint32_t) new->tb.start; nvic_frame->lr = (uint32_t)task_end; nvic_frame->psr = 0x01000000u; /* The EXTRA_FRAME is needed in order to save/restore the task context when servicing PendSV exceptions */ sp -= EXTRA_FRAME_SIZE; extra_frame = (struct extra_stack_frame *)sp; extra_frame->r9 = new->tb.vfsi->pic; new->tb.sp = (uint32_t *)sp; } int task_create(struct vfs_info *vfsi, void *arg, unsigned int nice) { struct task *new; int i; struct filedesc_table *ft; new = task_space_alloc(sizeof(struct task)); if (!new) { return -ENOMEM; } memset(&new->tb, 0, sizeof(struct task_block)); new->tb.pid = next_pid(); new->tb.tid = 1; new->tb.tgroup = NULL; new->tb.ppid = scheduler_get_cur_pid(); new->tb.nice = nice; new->tb.filedesc_table = NULL; new->tb.flags = 0; new->tb.cwd = fno_search("/"); new->tb.vfsi = vfsi; new->tb.tracer = NULL; ft = _cur_task->tb.filedesc_table; /* Inherit cwd, file descriptors from parent */ if (new->tb.ppid > 1) { /* Start from parent #2 */ new->tb.cwd = task_getcwd(); for (i = 0; (ft) && (i < ft->n_files); i++) { task_filedesc_add_to_task(new, ft->fdesc[i].fno); new->tb.filedesc_table->fdesc[i].mask = ft->fdesc[i].mask; } } new->tb.next = NULL; tasklist_add(&tasks_running, new); number_of_tasks++; task_create_real(new, vfsi, arg, nice); new->tb.state = TASK_RUNNABLE; return new->tb.pid; } int scheduler_exec(struct vfs_info *vfsi, void *args) { struct task *t = _cur_task; t->tb.vfsi = vfsi; task_create_real(t, vfsi, (void *)args, t->tb.nice); asm volatile("msr " PSP ", %0" ::"r"(_cur_task->tb.sp)); t->tb.state = TASK_RUNNING; mpu_task_on((void *)(((uint32_t)t->tb.cur_stack) - (sizeof(struct task_block) + F_MALLOC_OVERHEAD))); return 0; } int sys_vfork_hdlr(void) { struct task *new; int i; uint32_t sp_off = (uint8_t *)_cur_task->tb.sp - (uint8_t *)_cur_task->tb.cur_stack; uint32_t vpid; struct filedesc_table *ft = _cur_task->tb.filedesc_table; if (_cur_task->tb.tid != 1) { /* Prohibit vfork() from a thread */ return -ENOSYS; } new = task_space_alloc(sizeof(struct task)); if (!new) { return -ENOMEM; } memset(&new->tb, 0, sizeof(struct task_block)); vpid = next_pid(); new->tb.pid = vpid; new->tb.tid = 1; new->tb.tgroup = NULL; new->tb.ppid = scheduler_get_cur_pid(); new->tb.nice = _cur_task->tb.nice; new->tb.filedesc_table = NULL; new->tb.arg = NULL; new->tb.vfsi = NULL; new->tb.flags = TASK_FLAG_VFORK; new->tb.cwd = task_getcwd(); new->tb.timer_id = -1; new->tb.specifics = NULL; new->tb.n_specifics = 0; /* Inherit cwd, file descriptors from parent */ if (new->tb.ppid > 1) { /* Start from parent #2 */ for (i = 0; (ft) && (i < ft->n_files); i++) { task_filedesc_add_to_task(new, ft->fdesc[i].fno); new->tb.filedesc_table->fdesc[i].mask = ft->fdesc[i].mask; } /* Inherit signal mask */ new->tb.sigmask = _cur_task->tb.sigmask; } new->tb.next = NULL; tasklist_add(&tasks_running, new); number_of_tasks++; /* Set parent's vfork retval by writing on stacked r0 */ *((uint32_t *)(_cur_task->tb.sp + EXTRA_FRAME_SIZE)) = vpid; /* Copy parent's stack in own stack space, but don't use it: * sp remains in the parent's pool. * This will be restored upon exit/exec */ memcpy(&new->stack, _cur_task->tb.cur_stack, SCHEDULER_STACK_SIZE); if (new != _cur_task) { new->tb.sp = _cur_task->tb.sp; new->tb.cur_stack = _cur_task->tb.cur_stack; new->tb.state = TASK_RUNNABLE; } /* Vfork: Caller task suspends until child calls exec or exits */ asm volatile("msr " PSP ", %0" ::"r"(new->tb.sp)); task_suspend_to(TASK_FORKED); return vpid; } /********************************/ /* POSIX threads */ /********************************/ /********************************/ /********************************/ /**/ /**/ /**/ #ifdef CONFIG_PTHREADS static struct task *pthread_get_task(int pid, int tid) { struct task *t = NULL; struct task *leader = NULL; struct thread_group *group = NULL; int i; leader = tasklist_get(&tasks_running, pid); if (!leader) leader = tasklist_get(&tasks_idling, pid); if (!leader) return NULL; if (tid == 1) return leader; group = leader->tb.tgroup; if (!group || !group->threads || group->n_threads < 2) return NULL; for (i = 0; i < group->n_threads; i++) { t = group->threads[i]; if (t->tb.tid == tid) { if (t->tb.state == TASK_OVER) return NULL; return t; } } return NULL; } static int pthread_add(struct task *cur, struct task *new) { int i; struct thread_group *group = cur->tb.tgroup; struct task **old_tgroup; if (!group) { group = kcalloc(sizeof(struct thread_group), 1); if (!group) return -ENOMEM; group->threads = kcalloc(sizeof(struct task *), 2); if (!group->threads) { kfree(group); return -ENOMEM; } cur->tb.tgroup = group; new->tb.tgroup = group; group->threads[0] = cur; group->threads[1] = new; group->n_threads = 2; group->max_tid = 2; group->active_threads = 2; return 2; } for (i = 0; i < group->n_threads; i++) { if (group->threads[i] == NULL) { group->threads[i] = new; new->tb.tgroup = group; new->tb.tid = ++group->max_tid; group->active_threads++; return new->tb.tid; } } ++group->n_threads; old_tgroup = group->threads; group->threads = krealloc(group->threads, sizeof(struct task *) * group->n_threads); if (!group->threads) { group->threads = old_tgroup; --group->n_threads; return -ENOMEM; } group->threads[group->n_threads - 1] = new; new->tb.tgroup = group; new->tb.tid = ++group->max_tid; group->active_threads++; return new->tb.tid; } static __inl int pthread_destroy_task(struct task *t) { struct task *t_joiner; running_to_idling(t); if (t->tb.tid > 1 && (t->tb.flags & TASK_FLAG_DETACHED) == TASK_FLAG_DETACHED) { t->tb.state = TASK_OVER; tasklet_add(task_destroy, t); return TASK_OVER; } else { t->tb.state = TASK_ZOMBIE; if (t->tb.tid > 1 && t->tb.joiner_thread_tid) { t_joiner = pthread_get_task(t->tb.pid, t->tb.joiner_thread_tid); if (t_joiner) task_resume(t_joiner); } return TASK_ZOMBIE; } } static void pthread_end(void) { /* We have to set the stack pointer because we jumped here * after setting lr to pthread_end into the NVIC_FRAME and there * we were using the sp of the thread's parent */ asm volatile("msr " PSP ", %0" ::"r"(_cur_task->tb.sp)); int thread_state; /* storing thread return value */ asm volatile("mov %0, r0" : "=r"(_cur_task->tb.exitval)); irq_off(); thread_state = pthread_destroy_task(_cur_task); _cur_task->tb.tgroup->active_threads--; irq_on(); while (1) { task_suspend_to(thread_state); } } /* Finalize thread creation, code shared by pthreads/kthreads. */ static inline void thread_create(struct task *new, void (*start_routine)(void *), void *arg) { struct nvic_stack_frame *nvic_frame; struct extra_stack_frame *extra_frame; uint8_t *sp; new->tb.joiner_thread_tid = 0; new->tb.start = start_routine; new->tb.arg = arg; new->tb.next = NULL; tasklist_add(&tasks_running, new); number_of_tasks++; new->tb.timeslice = TIMESLICE(new); new->tb.state = TASK_RUNNABLE; sp = (((uint8_t *)(&new->stack)) + SCHEDULER_STACK_SIZE - NVIC_FRAME_SIZE); new->tb.cur_stack = &new->stack; /* Stack frame is at the end of the stack space */ nvic_frame = (struct nvic_stack_frame *)sp; memset(nvic_frame, 0, NVIC_FRAME_SIZE); nvic_frame->r0 = (uint32_t) new->tb.arg; nvic_frame->pc = (uint32_t) new->tb.start; nvic_frame->lr = (uint32_t)pthread_end; nvic_frame->psr = 0x01000000u; sp -= EXTRA_FRAME_SIZE; extra_frame = (struct extra_stack_frame *)sp; extra_frame->r9 = new->tb.vfsi->pic; new->tb.sp = (uint32_t *)sp; } /* Pthread create handler. Call be like: * int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * *(*start_routine) (void *), void *arg) */ int sys_pthread_create_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { pthread_t *thread = (pthread_t *)arg1; pthread_attr_t *attr = (pthread_attr_t *)arg2; void (*start_routine)(void *) = (void (*)(void *))arg3; void *arg = (void *)arg4; (void)arg5; struct task *new; int i; struct filedesc_table *ft = _cur_task->tb.filedesc_table; if (!thread || (task_ptr_valid(thread) < 0) || (task_ptr_valid(attr) < 0)) return -EINVAL; new = task_space_alloc(sizeof(struct task)); if (!new) { return -ENOMEM; } memset(&new->tb, 0, sizeof(struct task_block)); new->tb.tid = pthread_add(_cur_task, new); if (new->tb.tid < 0) { task_space_free(new); return -ENOMEM; } if (attr && *attr == PTHREAD_CREATE_DETACHED) new->tb.flags = TASK_FLAG_DETACHED | TASK_FLAG_CANCELABLE; else new->tb.flags = TASK_FLAG_CANCELABLE; new->tb.pid = _cur_task->tb.pid; new->tb.ppid = _cur_task->tb.ppid; new->tb.nice = _cur_task->tb.nice; new->tb.filedesc_table = _cur_task->tb.filedesc_table; new->tb.vfsi = _cur_task->tb.vfsi; new->tb.cwd = task_getcwd(); new->tb.sigmask = _cur_task->tb.sigmask; new->tb.sighdlr = _cur_task->tb.sighdlr; new->tb.tracer = NULL; new->tb.timer_id = -1; new->tb.n_specifics = _cur_task->tb.n_specifics; if (new->tb.n_specifics > 0) { new->tb.specifics = kalloc(new->tb.n_specifics * (sizeof(pthread_key_t))); if (new->tb.specifics) { memcpy(new->tb.specifics, _cur_task->tb.specifics, new->tb.n_specifics * (sizeof(pthread_key_t))); } else { new->tb.n_specifics = 0; } } thread_create(new, start_routine, arg); *thread = ((new->tb.pid << 16) | (new->tb.tid & 0xFFFF)); return 0; } int sys_pthread_kill_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { pthread_t thread = (pthread_t )arg1; int sig = (int)arg2; struct task *t; if (!thread) return -EINVAL; t = pthread_get_task((thread & 0xFFFF0000) >> 16, (thread & 0xFFFF)); if (!t) return -ESRCH; pthread_destroy_task(t); while(t == this_task()) { task_preempt(); } } struct task *kthread_create(void(routine)(void *), void *arg) { struct task *new = task_space_alloc(sizeof(struct task)); void (*start_routine)(void *) = (void (*)(void *))routine; if (!new) { return NULL; } irq_off(); memset(&new->tb, 0, sizeof(struct task_block)); new->tb.tid = pthread_add(kernel, new); if (new->tb.tid < 0) { task_space_free(new); return NULL; } new->tb.flags = TASK_FLAG_DETACHED | TASK_FLAG_CANCELABLE; new->tb.pid = 0; new->tb.ppid = 0; new->tb.nice = NICE_DEFAULT; new->tb.filedesc_table = NULL; new->tb.vfsi = NULL; new->tb.cwd = NULL; thread_create(new, start_routine, arg); irq_on(); return new; } int kthread_cancel(struct task *t) { if (!t || (t->tb.pid != 0) || (t->tb.tid <= 1)) return -1; irq_off(); if (tasklist_del(&tasks_running, t) == 0) tasklist_add(&tasks_idling, t); t->tb.state = TASK_OVER; tasklet_add(task_destroy, t); irq_on(); return 0; } int sys_pthread_exit_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { _cur_task->tb.exitval = arg1; pthread_destroy_task(_cur_task); /* deliver SIGCHLD if this is the last thread */ if (_cur_task->tb.tgroup->active_threads == 1) tasklet_add(task_deliver_sigchld, ((void *)(int)_cur_task->tb.ppid)); else _cur_task->tb.tgroup->active_threads--; } int sys_pthread_join_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { pthread_t thread = (pthread_t)arg1; void **retval = (void **)arg2; struct task *to_join; if (task_ptr_valid((void *)retval) < 0) return -EINVAL; to_join = pthread_get_task((thread & 0xFFFF0000) >> 16, (thread & 0xFFFF)); if (!to_join) return -ESRCH; if ((to_join->tb.flags & TASK_FLAG_DETACHED) == TASK_FLAG_DETACHED) return -EINVAL; if (to_join == _cur_task || _cur_task->tb.joiner_thread_tid == to_join->tb.tid) return -EDEADLK; if (to_join->tb.joiner_thread_tid && to_join->tb.joiner_thread_tid != _cur_task->tb.tid) { return -EINVAL; } to_join->tb.joiner_thread_tid = _cur_task->tb.tid; if (to_join->tb.state != TASK_ZOMBIE) { task_suspend(); return SYS_CALL_AGAIN; } if (retval) *retval = (void *)to_join->tb.exitval; to_join->tb.state = TASK_OVER; tasklet_add(task_destroy, to_join); return 0; } int sys_pthread_detach_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { pthread_t thread = (pthread_t)arg1; struct task *t = pthread_get_task((thread & 0xFFFF0000) >> 16, (thread & 0xFFFF)); if (!t) return -ESRCH; t->tb.flags |= TASK_FLAG_DETACHED; return 0; } int sys_pthread_setcancelstate_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { int state = arg1; int *oldstate = (int *)arg2; struct task *t_joiner; if (task_ptr_valid((void *)oldstate) < 0) return -EINVAL; if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) return -EINVAL; if (oldstate) { if ((_cur_task->tb.flags & TASK_FLAG_CANCELABLE) == TASK_FLAG_CANCELABLE) *oldstate = PTHREAD_CANCEL_ENABLE; else *oldstate = PTHREAD_CANCEL_DISABLE; } if (state == PTHREAD_CANCEL_ENABLE) { _cur_task->tb.flags |= TASK_FLAG_CANCELABLE; if ((_cur_task->tb.flags & TASK_FLAG_PENDING_CANC) == TASK_FLAG_PENDING_CANC) { running_to_idling(_cur_task); if ((_cur_task->tb.flags & TASK_FLAG_DETACHED) == TASK_FLAG_DETACHED) { _cur_task->tb.state = TASK_OVER; tasklet_add(task_destroy, _cur_task); } else { _cur_task->tb.state = TASK_ZOMBIE; _cur_task->tb.exitval = PTHREAD_CANCELED; if (_cur_task->tb.joiner_thread_tid) { t_joiner = pthread_get_task( _cur_task->tb.pid, _cur_task->tb.joiner_thread_tid); if (t_joiner) task_resume(t_joiner); } } } } else _cur_task->tb.flags &= ~TASK_FLAG_CANCELABLE; return 0; } int sys_pthread_cancel_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { pthread_t thread = (pthread_t)arg1; struct task *t = pthread_get_task((thread & 0xFFFF0000) >> 16, (thread & 0xFFFF)); struct task *t_joiner; if (t) { if ((t->tb.flags & TASK_FLAG_CANCELABLE) == TASK_FLAG_CANCELABLE) { running_to_idling(t); if ((t->tb.flags & TASK_FLAG_DETACHED) == TASK_FLAG_DETACHED) { t->tb.state = TASK_OVER; tasklet_add(task_destroy, t); } else { t->tb.state = TASK_ZOMBIE; t->tb.exitval = PTHREAD_CANCELED; if (t->tb.joiner_thread_tid) { t_joiner = pthread_get_task(t->tb.pid, t->tb.joiner_thread_tid); if (t_joiner) task_resume(t_joiner); } } } else { t->tb.flags |= TASK_FLAG_PENDING_CANC; } return 0; } return -ESRCH; } int sys_pthread_self_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { pthread_t thread; thread = (_cur_task->tb.pid << 16) | (_cur_task->tb.tid & 0xFFFF); return (int)thread; } int sys_pthread_mutex_init_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { mutex_t **mutex = (mutex_t **)arg1; if (!mutex || (task_ptr_valid((void *)mutex) < 0)) return -EPERM; else *mutex = mutex_init(); if (!(*mutex)) return -ENOMEM; return 0; } int sys_pthread_mutex_destroy_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { mutex_t *mutex = (mutex_t *)arg1; if (mutex) mutex_destroy(mutex); else return -EINVAL; return 0; } int sys_pthread_mutex_lock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { mutex_t **mutex = (mutex_t **)arg1; if (!mutex) return -EINVAL; /* the mutex has to be initialized first if it's NULL*/ if (!(*mutex)) { *mutex = mutex_init(); if (!(*mutex)) return -EAGAIN; } return mutex_lock(*mutex); } int sys_pthread_mutex_trylock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { mutex_t **mutex = (mutex_t **)arg1; if (!mutex) return -EINVAL; /* the mutex has to be initialized first if it's NULL*/ if (!(*mutex)) { *mutex = mutex_init(); if (!(*mutex)) return -EAGAIN; } return mutex_trylock(*mutex); } int sys_pthread_mutex_unlock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { mutex_t *mutex = (mutex_t *)arg1; if (!mutex) return -EINVAL; return mutex_unlock(mutex); } int sys_pthread_key_create_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct task *t = this_task(); void *newarray = krealloc(t->tb.specifics, sizeof(pthread_key_t) * (t->tb.n_specifics + 1)); pthread_key_t *key = (pthread_key_t *)arg1; if (newarray) { t->tb.specifics = newarray; *key = t->tb.n_specifics; t->tb.n_specifics++; } return 0; } int sys_pthread_setspecific_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct task *t = this_task(); pthread_key_t key = (pthread_key_t)arg1; if (key < 0 || key >= t->tb.n_specifics) return -EINVAL; t->tb.specifics[key] = (uint32_t)arg2; return 0; } int sys_pthread_getspecific_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { struct task *t = this_task(); pthread_key_t key = (pthread_key_t)arg1; if (key < 0 || key >= t->tb.n_specifics) return -EINVAL; (*(uint32_t*)arg2) = t->tb.specifics[key]; return 0; } #else /* if !CONFIG_PTHREADS */ int sys_pthread_create_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_exit_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_join_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_detach_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_cancel_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_self_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_setcancelstate_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_mutex_init_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_mutex_destroy_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_mutex_lock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_mutex_trylock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_mutex_unlock_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_kill_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_key_create_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_setspecific_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } int sys_pthread_getspecific_hdlr(int arg1, int arg2, int arg3, int arg4, int arg5) { return -EOPNOTSUPP; } #endif /* CONFIG_PTHREADS */ /********************************/ /* Task switching */ /********************************/ /********************************/ /********************************/ /**/ /**/ /**/ /* In order to keep the code efficient, the stack layout of armv6 and armv7 do NOT match! */ static __naked void save_kernel_context(void) { asm volatile("mrs r0, " MSP " "); #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) asm volatile("stmdb r0!, {r4-r11} "); #elif defined(__ARM_ARCH_6M__) asm volatile("sub r0,#0x10"); asm volatile("stm r0!,{r4-R7}"); // Save r4-r7 asm volatile("mov r4,r8"); asm volatile("mov r5,r9"); asm volatile("mov r6,r10"); asm volatile("mov r7,r11"); asm volatile("sub r0,#0x20"); asm volatile("stm r0!,{r4-R7}"); // Save r8-r11 asm volatile("sub r0,#0x10"); #endif asm volatile("msr " MSP ", r0 "); asm volatile("isb"); asm volatile("bx lr "); } static __naked void save_task_context(void) { asm volatile("mrs r0, " PSP " "); #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) asm volatile("stmdb r0!, {r4-r11} "); #elif defined(__ARM_ARCH_6M__) asm volatile("sub r0,#0x10"); asm volatile("stm r0!,{r4-R7}"); // Save r4-r7 asm volatile("mov r4,r8"); asm volatile("mov r5,r9"); asm volatile("mov r6,r10"); asm volatile("mov r7,r11"); asm volatile("sub r0,#0x20"); asm volatile("stm r0!,{r4-R7}"); // Save r8-r11 asm volatile("sub r0,#0x10"); #endif asm volatile("msr " PSP ", r0 "); asm volatile("isb"); asm volatile("bx lr "); } static uint32_t runnable = RUN_HANDLER; static __naked void restore_kernel_context(void) { asm volatile("mrs r0, " MSP " "); #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) asm volatile("ldmfd r0!, {r4-r11} "); #elif defined(__ARM_ARCH_6M__) asm volatile("ldm r0!,{r4-r7}"); asm volatile("mov r8,r4"); asm volatile("mov r9,r5"); asm volatile("mov r10,r6"); asm volatile("mov r11,r7"); asm volatile("ldm r0!,{r4-r7}"); #endif asm volatile("msr " MSP ", r0"); asm volatile("isb"); asm volatile("bx lr "); } static __naked void restore_task_context(void) { asm volatile("mrs r0, " PSP " "); #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) asm volatile("ldmfd r0!, {r4-r11} "); #elif defined(__ARM_ARCH_6M__) asm volatile("ldm r0!,{r4-r7}"); asm volatile("mov r8,r4"); asm volatile("mov r9,r5"); asm volatile("mov r10,r6"); asm volatile("mov r11,r7"); asm volatile("ldm r0!,{r4-r7}"); #endif asm volatile("msr " PSP ", r0 "); asm volatile("isb"); asm volatile("bx lr "); } static __inl void task_switch(void) { int i; struct task *t; if (forced_task) { _cur_task = forced_task; forced_task = NULL; return; } t = _cur_task; /* Checks that the _cur_task hasn't left the "task_running" list. * If it's not in the valid state, revert task-switching to the head of * task_running */ if (((t->tb.state != TASK_RUNNING) && (t->tb.state != TASK_RUNNABLE)) || (t->tb.next == NULL)) t = tasks_running; else t = t->tb.next; t->tb.timeslice = TIMESLICE(t); t->tb.state = TASK_RUNNING; _cur_task = t; } #pragma GCC push_options #pragma GCC optimize ("O0") /* C ABI cannot mess with the stack, we will */ void __naked pend_sv_handler(void) { asm volatile("cpsid i"); /* save current context on current stack */ if (in_kernel()) { save_kernel_context(); asm volatile("mrs %0, " MSP "" : "=r"(_top_stack)); } else { save_task_context(); asm volatile("mrs %0, " PSP "" : "=r"(_top_stack)); } asm volatile("isb"); /* save current SP to TCB */ _cur_task->tb.sp = _top_stack; if (_cur_task->tb.state == TASK_RUNNING) _cur_task->tb.state = TASK_RUNNABLE; /* choose next task */ // if ((_cur_task->tb.flags & TASK_FLAG_SIGNALED) == 0) task_switch(); /* if switching to a signaled task, adjust sp */ // if ((_cur_task->tb.flags & (TASK_FLAG_IN_SYSCALL | // TASK_FLAG_SIGNALED)) == ((TASK_FLAG_SIGNALED))) { // _cur_task->tb.sp += 32; // } if (((int)(_cur_task->tb.sp) - (int)(&_cur_task->stack)) < STACK_THRESHOLD) { kprintf("PendSV: Process %d is running out of stack space!\n", _cur_task->tb.pid); } /* write new stack pointer and restore context */ if (in_kernel()) { asm volatile("msr " MSP ", %0" ::"r"(_cur_task->tb.sp)); asm volatile("isb"); restore_kernel_context(); runnable = RUN_KERNEL; } else { mpu_task_on((void *)(((uint32_t)_cur_task->tb.cur_stack) - (sizeof(struct task_block) + F_MALLOC_OVERHEAD))); asm volatile("msr " PSP ", %0" ::"r"(_cur_task->tb.sp)); asm volatile("isb"); restore_task_context(); runnable = RUN_USER; } #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) /* Set control bit for non-kernel threads */ if (_cur_task->tb.pid != 0) { asm volatile("msr CONTROL, %0" ::"r"(0x01)); } else { asm volatile("msr CONTROL, %0" ::"r"(0x00)); } asm volatile("isb"); #endif /* Set return value selected by the restore procedure; RUN_KERNEL/RUN_USER are special values which inform the CPU we are returning from an exception handler, after detecting such a value the processor pops the correct stack frame (NVIC_FRAME) and jumps to the program counter stored into it, thus resuming task execution. */ asm volatile("mov lr, %0" ::"r"(runnable)); asm volatile("cpsie i"); /* return (function is naked) */ asm volatile("bx lr \n"); } #pragma GCC pop_options void kernel_task_init(void) { /* task0 = kernel */ irq_off(); kernel->tb.sp = msp_read(); // SP needs to be current SP kernel->tb.pid = next_pid(); kernel->tb.tid = 1; kernel->tb.tgroup = NULL; kernel->tb.ppid = scheduler_get_cur_pid(); kernel->tb.nice = NICE_DEFAULT; kernel->tb.start = NULL; kernel->tb.arg = NULL; kernel->tb.timer_id = -1; kernel->tb.filedesc_table = NULL; kernel->tb.timeslice = TIMESLICE(kernel); kernel->tb.state = TASK_RUNNABLE; kernel->tb.cwd = fno_search("/"); kernel->tb.state = TASK_RUNNABLE; kernel->tb.next = NULL; tasklist_add(&tasks_running, kernel); irq_on(); /* Set kernel as current task */ _cur_task = kernel; } static void task_suspend_to(int newstate) { /* Refuse to suspend on main kernel thread. */ if ((_cur_task->tb.pid < 1) && (_cur_task->tb.tid < 2)) return; running_to_idling(_cur_task); if (_cur_task->tb.state == TASK_RUNNABLE || _cur_task->tb.state == TASK_RUNNING) { _cur_task->tb.timeslice = 0; } _cur_task->tb.state = newstate; schedule(); } void task_suspend(void) { return task_suspend_to(TASK_WAITING); } void task_stop(struct task *t) { if (!t) return; if (t->tb.state == TASK_RUNNABLE || t->tb.state == TASK_RUNNING) { t->tb.timeslice = 0; } t->tb.state = TASK_STOPPED; running_to_idling(t); schedule(); } void task_hit_breakpoint(struct task *t) { if (t->tb.tracer) { task_stop(t); task_resume(t->tb.tracer); } } void task_preempt(void) { _cur_task->tb.timeslice = 0; schedule(); } void task_preempt_all(void) { struct task *t = tasks_running; while (t) { if (t->tb.pid != 0) t->tb.timeslice = 0; t = t->tb.next; } schedule(); } static void task_resume_real(struct task *t, int lock) { if (!t) return; if (t->tb.state == TASK_WAITING) { idling_to_running(t); t->tb.state = TASK_RUNNABLE; } if (!lock && (t->tb.nice == NICE_RT)) { forced_task = t; task_preempt_all(); } } void task_resume_lock(struct task *t) { task_resume_real(t, 1); } void task_resume(struct task *t) { task_resume_real(t, 0); } void task_wakeup(struct task *t) { task_preempt_all(); t->tb.timeslice = TIMESLICE(t); task_resume(t); } void task_continue(struct task *t) { if ((t) && (t->tb.state == TASK_STOPPED)) { idling_to_running(t); t->tb.state = TASK_RUNNABLE; } } static void task_resume_vfork(struct task *t) { if ((t) && t->tb.state == TASK_FORKED) { idling_to_running(t); t->tb.state = TASK_RUNNABLE; } } void task_deliver_sigchld(void *arg) { struct task *t = (struct task *)arg; if (t) task_kill(t->tb.pid, SIGCHLD); } void task_deliver_sigtrap(void *arg) { struct task *t = (struct task *)arg; if (t) task_kill(t->tb.pid, SIGTRAP); } static void destroy_thread_group(struct thread_group *group, uint16_t tid) { #ifdef CONFIG_PTHREADS int i; /* Destroy the entire thread family */ for (i = 0; i < group->n_threads; i++) { if (group->threads[i] != NULL) { struct task *th = group->threads[i]; if (th->tb.tid != tid) { running_to_idling(th); th->tb.state = TASK_OVER; kfree(th->tb.tgroup->threads); kfree(th->tb.tgroup); th->tb.tgroup = NULL; tasklet_add(task_destroy, th); } } } #endif } void task_terminate(struct task *t) { int i; if (t) { running_to_idling(t); t->tb.state = TASK_ZOMBIE; t->tb.timeslice = 0; if (t->tb.ppid > 0) { struct task *pt = tasklist_get(&tasks_idling, t->tb.ppid); if (!pt) pt = tasklist_get(&tasks_running, t->tb.ppid); if (t->tb.flags & TASK_FLAG_VFORK) { /* Restore parent's stack */ if (pt) { memcpy((void *)pt->tb.cur_stack, (void *)&_cur_task->stack, SCHEDULER_STACK_SIZE); t->tb.flags &= ~TASK_FLAG_VFORK; } task_resume_vfork(t); } if (!pt || (pt->tb.state == TASK_ZOMBIE) || (pt->tb.state == TASK_OVER)) { /* Parent task is not there anymore. Init tries to adopt orphan child. */ t->tb.ppid = 1; pt = tasklist_get(&tasks_running, 1); if (!pt) pt = tasklist_get(&tasks_idling, 1); } if (pt) tasklet_add(task_deliver_sigchld, pt); task_preempt(); } } } int scheduler_get_nice(int pid) { struct task *t; t = tasklist_get(&tasks_running, pid); if (!t) t = tasklist_get(&tasks_idling, pid); if (!t) return 0; return (int)t->tb.nice; } int sys_getpid_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { if (!_cur_task) return 0; return _cur_task->tb.pid; } int sys_getppid_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { if (!_cur_task) return 0; return _cur_task->tb.ppid; } void sleepy_task_wakeup(uint32_t now, void *arg) { struct task *t = (struct task *)arg; t->tb.timer_id = -1; t->tb.flags |= TASK_FLAG_TIMEOUT; if (t->tb.state == TASK_WAITING) task_resume(t); } int sys_sleep_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { uint32_t timeout = jiffies + arg1; if (arg1 < 0) return -EINVAL; if ((_cur_task->tb.flags & TASK_FLAG_TIMEOUT) != 0) { _cur_task->tb.flags &= (~TASK_FLAG_TIMEOUT); if (_cur_task->tb.timer_id >= 0) { ktimer_del(_cur_task->tb.timer_id); _cur_task->tb.timer_id = -1; } return 0; } _cur_task->tb.timer_id = ktimer_add(arg1, sleepy_task_wakeup, this_task()); task_suspend(); return SYS_CALL_AGAIN; } void kthread_sleep_ms(uint32_t ms) { unsigned dl = jiffies + ms; while(dl > jiffies) { kthread_yield(); } } void alarm_task(uint32_t now, void *arg) { struct task *t = (struct task *)arg; if (t) { t->tb.timer_id = -1; task_kill(t->tb.pid, SIGALRM); } } int sys_alarm_hdlr(uint32_t arg1) { if (arg1 < 0) return -EINVAL; int ret = 0; if (_cur_task->tb.timer_id >= 0) { ktimer_del(_cur_task->tb.timer_id); ret = 1; } _cur_task->tb.timer_id = ktimer_add((arg1 * 1000), alarm_task, this_task()); return ret; } int sys_ualarm_hdlr(uint32_t arg1, uint32_t arg2) { if (arg1 < 0) return -EINVAL; int ret = 0; if (_cur_task->tb.timer_id >= 0) { ktimer_del(_cur_task->tb.timer_id); ret = 1; } _cur_task->tb.timer_id = ktimer_add(((arg1 / 1000) + 1), alarm_task, this_task()); return ret; } void task_yield(void) { _cur_task->tb.timeslice = 0; schedule(); } void __naked kthread_yield(void) { struct task *t = _cur_task; if (!t || (t->tb.pid != 0) || (t->tb.tid < 2)) return; _cur_task->tb.timeslice = 0; schedule(); /* return (function is naked) */ asm volatile("bx lr"); } int sys_sched_yield_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { task_yield(); return 0; }; int sys_poll_hdlr(uint32_t arg1, uint32_t arg2, int arg3) { struct pollfd *pfd = (struct pollfd *)arg1; int i, n = (int)arg2; uint32_t timeout; int endless = 0; int ret = 0; struct fnode *f; if (task_ptr_valid((void *)arg1)) return -EACCES; if (arg3 < 0) { endless = 1; } if ((_cur_task->tb.flags & TASK_FLAG_TIMEOUT) != 0) { _cur_task->tb.flags &= (~TASK_FLAG_TIMEOUT); return 0; } if ((_cur_task->tb.flags & TASK_FLAG_TIMEOUT) == 0) timeout = jiffies + arg3; else timeout = jiffies; while (endless || (jiffies <= timeout)) { for (i = 0; i < n; i++) { f = task_filedesc_get(pfd[i].fd); if (!f || !f->owner || !f->owner->ops.poll) { return -EOPNOTSUPP; } pfd[i].revents = 0; ret += f->owner->ops.poll(f, pfd[i].events, &pfd[i].revents); } if (ret > 0) { if (this_task()->tb.timer_id >= 0) { ktimer_del(this_task()->tb.timer_id); this_task()->tb.timer_id = -1; } _cur_task->tb.flags &= (~TASK_FLAG_TIMEOUT); return ret; } if (!endless && (this_task()->tb.timer_id < 0)) { this_task()->tb.timer_id = ktimer_add(timeout - jiffies, sleepy_task_wakeup, this_task()); } task_suspend(); return SYS_CALL_AGAIN; } if (_cur_task->tb.timer_id >= 0) { ktimer_del(_cur_task->tb.timer_id); _cur_task->tb.timer_id = -1; } return 0; } int sys_waitpid_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3) { int *status = (int *)arg2; struct task *t = NULL; int pid = (int)arg1; int options = (int)arg3; if (status && task_ptr_valid(status)) return -EACCES; if (pid == 0) return -EINVAL; if (pid < -1) return -ENOSYS; if (pid != -1) { t = tasklist_get(&tasks_running, pid); /* Check if pid is running, but it's not a child */ if (t) { if (t->tb.ppid != _cur_task->tb.ppid) return -ESRCH; else { if ((options & WNOHANG) != 0) return 0; task_suspend(); return SYS_CALL_AGAIN; } } t = tasklist_get(&tasks_idling, pid); if (!t || (t->tb.ppid != _cur_task->tb.pid)) return -ESRCH; if (t->tb.state == TASK_ZOMBIE) goto child_found; if (t->tb.state == TASK_STOPPED) { /* TODO: set status */ return pid; } if (options & WNOHANG) return 0; task_suspend(); return SYS_CALL_AGAIN; } /* wait for all (pid = -1) */ t = tasks_idling; while (t) { if ((t->tb.state == TASK_STOPPED) && (t->tb.ppid == _cur_task->tb.pid)) { /* TODO: set status */ return pid; } if ((t->tb.state == TASK_ZOMBIE) && (t->tb.ppid == _cur_task->tb.pid)) goto child_found; t = t->tb.next; } if (options & WNOHANG) return 0; task_suspend(); return SYS_CALL_AGAIN; child_found: if (arg2) { *((int *)arg2) = t->tb.exitval; } pid = t->tb.pid; /* if this is a thread this is the last active one because it sent a SIGCHLD */ #ifdef CONFIG_PTHREADS if (t->tb.tgroup) t->tb.tgroup->active_threads = 0; #endif tasklet_add(task_destroy, t); t->tb.state = TASK_OVER; return pid; } enum __ptrace_request { PTRACE_TRACEME = 0, PTRACE_PEEKTEXT = 1, PTRACE_PEEKDATA = 2, PTRACE_PEEKUSER = 3, PTRACE_POKETEXT = 4, PTRACE_POKEDATA = 5, PTRACE_POKEUSER = 6, PTRACE_CONT = 7, PTRACE_KILL = 8, PTRACE_SINGLESTEP = 9, PTRACE_GETREGS = 12, PTRACE_SETREGS = 13, PTRACE_ATTACH = 16, PTRACE_DETACH = 17, PTRACE_SYSCALL = 24, PTRACE_SEIZE = 0x4206 }; int ptrace_getregs(struct task *t, struct user *u) { struct extra_stack_frame *cur_extra = t->tb.sp + NVIC_FRAME_SIZE + EXTRA_FRAME_SIZE; struct nvic_stack_frame *cur_nvic = t->tb.sp + EXTRA_FRAME_SIZE; memcpy(&u->regs[0], cur_nvic, (4 * sizeof(uint32_t))); /* r0 - r3 */ memcpy(&u->regs[4], cur_extra, (8 * sizeof(uint32_t))); /* r4 - r11 */ u->regs[12] = cur_nvic->r12; u->regs[13] = (uint32_t)(t->tb.sp); u->regs[14] = cur_nvic->lr; u->regs[15] = cur_nvic->pc; u->regs[16] = cur_nvic->psr; if (t->tb.vfsi) { u->tsize = t->tb.vfsi->text_size; u->dsize = t->tb.vfsi->data_size; u->start_code = (uint32_t)t->tb.vfsi->init; } u->ssize = CONFIG_TASK_STACK_SIZE; u->start_stack = (uint32_t)(t->tb.cur_stack); u->signal = 0; u->magic = 0xd0ab1e50; return 0; } int ptrace_peekuser(struct task *t, uint32_t addr) { struct user u; if (ptrace_getregs(t, &u) == 0) return *(int *)(((char *)(&u)) + addr); else return -1; } int ptrace_pokeuser(struct task *t, uint32_t addr, uint32_t data) { uint32_t *cur_extra = t->tb.sp + NVIC_FRAME_SIZE + EXTRA_FRAME_SIZE; uint32_t *cur_nvic = t->tb.sp + EXTRA_FRAME_SIZE; int pos = addr / 4; if (addr > (16 * sizeof(uint32_t))) return -1; if ((addr % 4) != 0) return -1; if (pos < 4) { cur_nvic[pos] = data; return 0; } if (pos < 12) { cur_extra[pos - 4] = data; return 0; } if (pos == 12) { cur_nvic[4] = data; return 0; } /* Breakpoints */ #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) if ((pos > 56) && (pos < 64)) { pos -= 56; if (data == 0) return fpb_delbrk(pos); return fpb_setbrk(t->tb.pid, (void *)data, pos); } #endif return -1; } int ptrace_setregs(struct task *t, uint32_t *regs) { int i; for (i = 0; i < 13; i++) { ptrace_pokeuser(t, i * 4, regs[i]); } return 0; } int sys_ptrace_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { (void)arg5; enum __ptrace_request request = arg1; uint32_t pid = arg2; void *addr = (void *)arg3; void *data = (void *)arg4; struct task *tracee = NULL; /* Prepare tracee based on pid */ tracee = tasklist_get(&tasks_idling, pid); if (!tracee) tracee = tasklist_get(&tasks_running, pid); if (!tracee) { return -1; } switch (request) { case PTRACE_TRACEME: _cur_task->tb.tracer = _cur_task; break; case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: return *((uint32_t *)addr); case PTRACE_PEEKUSER: return ptrace_peekuser(tracee, (uint32_t)addr); case PTRACE_POKETEXT: case PTRACE_POKEDATA: break; case PTRACE_POKEUSER: return ptrace_pokeuser(tracee, (uint32_t)addr, (uint32_t)data); case PTRACE_CONT: if (!tracee) return -1; if (tracee->tb.tracer != _cur_task) return -1; task_continue(tracee); return 0; case PTRACE_KILL: if (!tracee) return -1; if (tracee->tb.tracer != _cur_task) return -1; task_kill(pid, SIGKILL); return 0; case PTRACE_SINGLESTEP: { struct user u; ptrace_getregs(tracee, &u); #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) if (fpb_setbrk(pid, (void *)((u.regs[15]) / 2 * 2 + 2), 0) >= 0) { task_continue(tracee); return 0; } else #endif return -1; } case PTRACE_GETREGS: return ptrace_getregs(tracee, (struct user *)data); break; case PTRACE_SETREGS: return ptrace_setregs(tracee, (uint32_t *)data); break; case PTRACE_ATTACH: case PTRACE_SEIZE: if (!tracee) return -1; tracee->tb.tracer = _cur_task; if (request == PTRACE_ATTACH) { task_stop(tracee); } return 0; case PTRACE_DETACH: if (!tracee) return -1; if (tracee->tb.tracer != _cur_task) return -1; tracee->tb.tracer = NULL; task_continue(tracee); return 0; case PTRACE_SYSCALL: if (!tracee) return -1; if (tracee->tb.tracer != _cur_task) return -1; tracee->tb.flags |= TASK_FLAG_SYSCALL_STOP; return 0; } return -1; } int sys_setpriority_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { int pid = arg2; int nice = (int)arg3; struct task *t = tasklist_get(&tasks_idling, pid); if (!t) t = tasklist_get(&tasks_running, pid); if (arg1 != 0) /* ONLY PRIO_PROCESS IS VALID */ return -EINVAL; if (!t) return -ESRCH; t->tb.nice = nice; return 0; } int sys_getpriority_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { int pid = arg2; struct task *t = tasklist_get(&tasks_idling, pid); if (!t) t = tasklist_get(&tasks_running, pid); if (arg1 != 0) /* ONLY PRIO_PROCESS IS VALID */ return -EINVAL; if (!t) return -ESRCH; return (int)t->tb.nice; } int sys_kill_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { struct task *t = tasklist_get(&tasks_idling, arg1); if (!t) t = tasklist_get(&tasks_running, arg1); if (!t) return -ESRCH; return catch_signal(t, arg2, t->tb.sigmask); } int task_kill(int pid, int signal) { if (pid > 0) { return sys_kill_hdlr(pid, signal, 0, 0, 0); } } int sys_exit_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg) { _cur_task->tb.exitval = (int)arg1; task_terminate(_cur_task); } int sys_setsid_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg) { int i; struct filedesc_table *ft = _cur_task->tb.filedesc_table; if (!ft) return -1; for (i = 0; (ft) && (i < ft->n_files); i++) { if (ft->fdesc[i].fno != NULL) { struct fnode *fno = ft->fdesc[i].fno; if ((fno->flags & FL_TTY) && ((ft->fdesc[i].mask & O_NOCTTY) == 0)) { struct module *mod = fno->owner; if (mod && mod->ops.tty_attach) { mod->ops.tty_attach(fno, _cur_task->tb.ppid); ft->fdesc[i].mask |= O_NOCTTY; return 0; } } } } } int task_segfault(uint32_t address, uint32_t instruction, int flags) { struct filedesc_table *ft; if (in_kernel()) return -1; if (_cur_task->tb.state == TASK_ZOMBIE) return 0; ft = _cur_task->tb.filedesc_table; if (ft && (ft->n_files > 2) && ft->fdesc[2].fno->owner->ops.write) { #ifdef CONFIG_EXTENDED_MEMFAULT char segv_msg[128] = "Memory fault: process (pid="; strcat(segv_msg, pid_str(_cur_task->tb.pid)); if (flags == MEMFAULT_ACCESS) { strcat(segv_msg, ") attempted access to memory at "); strcat(segv_msg, x_str(address)); } if (flags == MEMFAULT_DOUBLEFREE) { strcat(segv_msg, ") attempted double free"); } strcat(segv_msg, ". Killed.\r\n"); #else char segv_msg[] = ">_< -- Segfault -- >_<"; #endif ft->fdesc[2].fno->owner->ops.write(ft->fdesc[2].fno, segv_msg, strlen(segv_msg)); } task_terminate(_cur_task); return 0; } int task_ptr_valid(const void *ptr) { struct task *t; uint8_t *stack_start = (uint8_t *)_cur_task->tb.cur_stack; uint8_t *stack_end = stack_start + SCHEDULER_STACK_SIZE; if (!ptr) return 0; /* NULL is a permitted value */ if (_cur_task->tb.pid == 0) return 0; /* Kernel mode */ if (((uint8_t *)ptr >= stack_start) && ((uint8_t *)ptr < stack_end)) return 0; /* In the process own's stack */ if (fmalloc_owner(ptr) == _cur_task->tb.pid) return 0; /* In the process own's heap */ t = tasklist_get(&tasks_idling, _cur_task->tb.ppid); if (t && (t->tb.state == TASK_FORKED)) { /* execution after fork(), parent memory allowed. */ if (fmalloc_owner(ptr) == _cur_task->tb.ppid) return 0; /* In the process parent's heap */ } return -1; } #pragma GCC push_options #pragma GCC optimize ("O0") struct nvic_stack_frame *n_stack = NULL; static uint32_t *a0 = NULL; static uint32_t *a1 = NULL; static uint32_t *a2 = NULL; static uint32_t *a3 = NULL; static uint32_t *a4 = NULL; static uint32_t *a5 = NULL; int __naked sv_call_handler(void) { irq_off(); save_task_context(); asm volatile("mrs %0, " PSP "" : "=r"(_top_stack)); /* save current SP to TCB */ _cur_task->tb.sp = _top_stack; /* Get function arguments */ n_stack = (struct nvic_stack_frame *)(_cur_task->tb.sp + NVIC_FRAME_SIZE); a0 = &n_stack->r0; a1 = &n_stack->r1; a2 = &n_stack->r2; a3 = &n_stack->r3; a4 = (uint32_t *)((uint8_t *)_cur_task->tb.sp + (EXTRA_FRAME_SIZE + NVIC_FRAME_SIZE + 8*4)); a5 = (uint32_t *)((uint8_t *)_cur_task->tb.sp + (EXTRA_FRAME_SIZE + NVIC_FRAME_SIZE + 8*4 + 4)); if (*a0 == SV_CALL_SIGRETURN) { uint32_t *syscall_retval = (uint32_t *)(_cur_task->tb.osp + EXTRA_FRAME_SIZE); _cur_task->tb.sp = _cur_task->tb.osp; _cur_task->tb.flags &= (~(TASK_FLAG_SIGNALED)); if (*syscall_retval == SYS_CALL_AGAIN_VAL) { *syscall_retval = -EINTR; } irq_on(); goto return_from_syscall; } if (*a0 >= _SYSCALLS_NR) { restore_task_context(); irq_on(); return -1; } if (sys_syscall_handlers[*a0] == NULL) { restore_task_context(); irq_on(); return -1; } #ifdef CONFIG_SYSCALL_TRACE Strace[StraceTop].n = n; Strace[StraceTop].pid = _cur_task->tb.pid; Strace[StraceTop].sp = (uint32_t)_top_stack; StraceTop++; if (StraceTop > 9) StraceTop = 0; #endif /* Execute syscall */ int (*call)(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) = NULL; _cur_task->tb.flags |= TASK_FLAG_IN_SYSCALL; call = sys_syscall_handlers[*a0]; if (!call) { irq_on(); goto return_from_syscall; } call(*a1, *a2, *a3, *a4, *a5); /* Exec does not have a return value, and will use r0 as args for main()*/ if (call != sys_syscall_handlers[SYS_EXEC]) asm volatile( "mov %0, r0" : "=r"(*((uint32_t *)(_cur_task->tb.sp + EXTRA_FRAME_SIZE)))); /* out of syscall */ _cur_task->tb.flags &= (~TASK_FLAG_IN_SYSCALL); irq_on(); if (_cur_task->tb.state != TASK_RUNNING) { task_switch(); } return_from_syscall: /* write new stack pointer and restore context */ if (in_kernel()) { asm volatile("msr " MSP ", %0" ::"r"(_cur_task->tb.sp)); asm volatile("isb"); restore_kernel_context(); runnable = RUN_KERNEL; } else { mpu_task_on((void *)(((uint32_t)_cur_task->tb.cur_stack) - (sizeof(struct task_block) + F_MALLOC_OVERHEAD))); asm volatile("msr " PSP ", %0" ::"r"(_cur_task->tb.sp)); asm volatile("isb"); restore_task_context(); runnable = RUN_USER; } /* Set control bit for non-kernel threads */ if (_cur_task->tb.pid != 0) { asm volatile("msr CONTROL, %0" ::"r"(0x01)); } else { asm volatile("msr CONTROL, %0" ::"r"(0x00)); } asm volatile("isb"); /* Set return value selected by the restore procedure */ asm volatile("mov lr, %0" ::"r"(runnable)); /* return (function is naked) */ asm volatile("bx lr"); } #pragma GCC pop_options ================================================ FILE: kernel/scheduler.h ================================================ #ifndef INCLUDED_SCHEDULER_H #define INCLUDED_SCHEDULER_H #include "vfs.h" #endif ================================================ FILE: kernel/semaphore.S ================================================ .syntax unified /* Try to decrease the semaphore. * On success, return 0. * On failure, return -1 (sem == 0, try again later). */ .global _sem_wait _sem_wait: #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) LDREX r1, [r0] #elif defined(__ARM_ARCH_6M__) CPSID i LDR r1, [r0] #endif CMP r1, #0 // Test if semaphore holds the value 0 BEQ _sem_wait_fail // If it does, return 0 SUBS r1, #1 // If not, decrement temporary copy #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) STREX r2, r1, [r0] // Attempt Store-Exclusive CMP r2, #0 // Check if Store-Exclusive succeeded BNE _sem_wait // If Store-Exclusive failed, retry from start DMB // Required before accessing protected resource #elif defined(__ARM_ARCH_6M__) STR r1, [r0] CPSIE i #endif MOVS r0, #0 // Successfully acquired. BX lr _sem_wait_fail: #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) DMB MOV r0, #-1 // Already locked! #elif defined(__ARM_ARCH_6M__) CPSIE i MOVS r2, #0 // Already locked! MVNS r0, r2 #endif BX lr /* Increase the semaphore value. * If the value was 0, return 1 (send a signal to the listeners) * If a non-zero semaphore is incremented, return 0. (do not signal). */ .global _sem_post _sem_post: #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) LDREX r1, [r0] #elif defined(__ARM_ARCH_6M__) CPSID i LDR r1, [r0] #endif ADDS r1, #1 // Increment temporary copy #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) STREX r2, r1, [r0] // Attempt Store-Exclusive CMP r2, #0 // Check if Store-Exclusive succeeded BNE _sem_post // Store failed - retry immediately #elif defined(__ARM_ARCH_6M__) STR r1, [r0] CPSIE i #endif CMP r0, #1 // Store successful - test if incremented from zero DMB // Required before releasing protected resource BGE _sem_signal_up // If initial value was 0, signal update MOVS r0, #0 BX lr _sem_signal_up: MOVS r0, #1 // Semaphore was 0, send a signal to listeners. BX lr ================================================ FILE: kernel/stm32f4/Kconfig ================================================ if ARCH_STM32F4 choice prompt "MCU" default ARCH_STM32F407_XG config ARCH_STM32F401_XB bool "STM32F401xB 128KB" select FLASH_SIZE_128KB select RAM_SIZE_64KB select ARCH_STM32F401 config ARCH_STM32F401_XC bool "STM32F401xC 256KB" select FLASH_SIZE_256KB select RAM_SIZE_64KB select ARCH_STM32F401 config ARCH_STM32F401_XD bool "STM32F401xD 384KB" select FLASH_SIZE_384KB select RAM_SIZE_96KB select ARCH_STM32F401 config ARCH_STM32F401_XE bool "STM32F401xE 512KB" select FLASH_SIZE_512KB select RAM_SIZE_96KB select ARCH_STM32F401 config ARCH_STM32F405_XG bool "STM32F405xG 1MB" select FLASH_SIZE_1MB select RAM_SIZE_192KB select ARCH_STM32F405 config ARCH_STM32F405_XE bool "STM32F407xE 512KB" select FLASH_SIZE_512KB select RAM_SIZE_192KB select ARCH_STM32F405 config ARCH_STM32F407_XG bool "STM32F407xG 1MB" select FLASH_SIZE_1MB select RAM_SIZE_192KB select ARCH_STM32F407 config ARCH_STM32F407_XE bool "STM32F407xE 512KB" select FLASH_SIZE_512KB select RAM_SIZE_192KB select ARCH_STM32F407 config ARCH_STM32F411_XE bool "STM32F411xE 512KB" select FLASH_SIZE_512KB select RAM_SIZE_128KB select ARCH_STM32F411 config ARCH_STM32F411_XC bool "STM32F411xC 256KB" select FLASH_SIZE_256KB select RAM_SIZE_128KB select ARCH_STM32F411 config ARCH_STM32F429_XE bool "STM32F429xE 512KB" select FLASH_SIZE_512KB select RAM_SIZE_256KB select ARCH_STM32F429 config ARCH_STM32F429_XG bool "STM32F429xG 1MB" select FLASH_SIZE_1MB select RAM_SIZE_256KB select ARCH_STM32F429 config ARCH_STM32F429_XI bool "STM32F429xI 2MB" select FLASH_SIZE_2MB select RAM_SIZE_256KB select ARCH_STM32F429 config ARCH_STM32F446_ZE bool "STM32F446ZE 512KB" select FLASH_SIZE_512KB select RAM_SIZE_128KB select ARCH_STM32F446 endchoice endif ================================================ FILE: kernel/stm32f4/stm32f4.ld.in ================================================ MEMORY { FLASH (rx) : ORIGIN = __FLASH_ORIGIN, LENGTH = __KFLASHMEM_SIZE SRAM (rwx) : ORIGIN = __RAM1_BASE, LENGTH = __KRAMMEM_SIZE SRAM_USER (rwx) : ORIGIN = (__RAM1_BASE + __KRAMMEM_SIZE), LENGTH = (__RAM1_SIZE - __KRAMMEM_SIZE) SRAM_EXTRA (rwx) : ORIGIN = __RAM2_BASE, LENGTH = __RAM2_SIZE SDRAM_USER(rwx) : ORIGIN = __SDRAM_BASE, LENGTH = __SDRAM_SIZE } /* Enforce emmition of the vector table. */ EXTERN (vector_table) /* Define the entry point of the output file. */ ENTRY(reset_handler) SECTIONS { .text : { KEEP(*(.vectors)) *(.text*) *(.rodata*) } > FLASH /* C++ Static constructors/destructors, also used for __attribute__ * ((constructor)) and the likes */ .preinit_array : { . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; } > FLASH .init_array : { . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; } > FLASH .fini_array : { . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; } > FLASH .data : { _etext = LOADADDR(.data); _data = .; *(vtable) *(.data*) _edata = .; } > SRAM AT > FLASH _data_loadaddr = LOADADDR(.data); .bss : { _bss = .; *(.bss*) *(COMMON) . = ALIGN(32 / 8); _ebss = .; PROVIDE (end = .); } > SRAM .heap : { /* heap starts after BSS */ PROVIDE(_heap_start = _ebss ); } > SRAM } PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM)); PROVIDE(_user_heap_start = ORIGIN(SRAM_USER)); PROVIDE(_user_heap_end = ORIGIN(SRAM_USER) + LENGTH(SRAM_USER)); PROVIDE(_extra_heap_start = ORIGIN(SRAM_EXTRA)); PROVIDE(_extra_heap_end = ORIGIN(SRAM_EXTRA) + LENGTH(SRAM_EXTRA)); PROVIDE(_external_heap_start = ORIGIN(SDRAM_USER)); PROVIDE(_external_heap_end = ORIGIN(SDRAM_USER) + LENGTH(SDRAM_USER)); ================================================ FILE: kernel/stm32f4/stm32f407discovery.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include #include #include #include #include #include #include #include #include "unicore-mx/stm32/spi.h" #include "drivers/stm32_sdio.h" #include "uart.h" #include "gpio.h" #include "sdio.h" #include "dsp.h" #include "rng.h" #include "usb.h" #include "eth.h" #include "i2c.h" #include "spi.h" #include "dsp.h" #include "dma.h" #include "drivers/lis3dsh.h" extern int xadow_led_init(uint32_t bus); #if CONFIG_SYS_CLOCK == 48000000 # define STM32_CLOCK RCC_CLOCK_3V3_48MHZ #elif CONFIG_SYS_CLOCK == 84000000 # define STM32_CLOCK RCC_CLOCK_3V3_84MHZ #elif CONFIG_SYS_CLOCK == 100000000 # define STM32_CLOCK RCC_CLOCK_3V3_100MHZ #elif CONFIG_SYS_CLOCK == 120000000 # define STM32_CLOCK RCC_CLOCK_3V3_120MHZ #elif CONFIG_SYS_CLOCK == 168000000 # define STM32_CLOCK RCC_CLOCK_3V3_168MHZ #else # error No valid clock speed selected #endif static const struct gpio_config Led[4] = { { .base=GPIOD, .pin=GPIO12,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0" }, { .base=GPIOD, .pin=GPIO13,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led1" }, { .base=GPIOD, .pin=GPIO14,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led2" }, { .base=GPIOD, .pin=GPIO15,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led3" }, }; static const struct gpio_config Button = { .base=GPIOA, .pin=GPIO0, .mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .name="button" }; static struct usb_pio_config_fs pio_fs = { .pio_vbus = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dm = { .base=GPIOA, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dp = { .base=GPIOA, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, } }; static struct usb_config usb_guest = { .dev_type = USB_DEV_FS, .otg_mode = USB_MODE_GUEST, .pio.fs = &pio_fs }; const struct gpio_config stm32eth_mii_pins[] = { {.base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDIO {.base=GPIOC, .pin=GPIO1, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDC {.base=GPIOA, .pin=GPIO1, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII REF CLK {.base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII CRS DV {.base=GPIOB, .pin=GPIO10,.mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXER {.base=GPIOC, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD0 {.base=GPIOC, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD1 {.base=GPIOB, .pin=GPIO11,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXEN {.base=GPIOB, .pin=GPIO12,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD0 {.base=GPIOB, .pin=GPIO13,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD1 }; static const struct eth_config eth_config = { .pio_mii = stm32eth_mii_pins, .n_pio_mii = 10, .pio_phy_reset = { .base=GPIOE, .pin=GPIO2, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .has_phy_reset = 1 }; static const struct i2c_config i2c_configs[] = { #ifdef CONFIG_I2C1 { .idx = 1, .base = I2C1, .ev_irq = NVIC_I2C1_EV_IRQ, .er_irq = NVIC_I2C1_ER_IRQ, .rcc = RCC_I2C1, .dma_rcc = RCC_DMA1, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM6, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM6_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM5, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM5_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOB, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, .pio_sda = { .base=GPIOB, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, }, #endif }; #define NUM_I2CS (sizeof(i2c_configs) / sizeof(struct i2c_config)) static const struct spi_config spi_configs[] = { #ifdef CONFIG_SPI_1 { .idx = 1, .base = SPI1, .irq = NVIC_SPI1_IRQ, .rcc = RCC_SPI1, .baudrate = 0, /* TODO: SPI baudrate */ .polarity = 1, .phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, .tx_dma = { .base = DMA2, .stream = DMA_STREAM3, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = 0, }, .rx_dma = { .base = DMA2, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = NVIC_DMA2_STREAM2_IRQ, }, .dma_rcc = RCC_DMA1, .pio_sck = { .base=GPIOA, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_mosi = { .base=GPIOA, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_miso = { .base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, }, #endif #ifdef CONFIG_SPI_3 { .idx = 3, .base = SPI1, .irq = NVIC_SPI3_IRQ, .rcc = RCC_SPI3, .baudrate = 0, /* TODO: SPI baudrate */ .polarity = 1, .phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, .tx_dma = { .base = DMA1, .stream = DMA_STREAM5, .channel = DMA_SxCR_CHSEL_0, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI3), .irq = 0, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_0, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI3), .irq = NVIC_DMA1_STREAM0_IRQ, }, .dma_rcc = RCC_DMA1, .pio_sck = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_mosi = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_miso = { .base=GPIOC, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_nss = { .base=GPIOA, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, }, #endif }; #define NUM_SPIS (sizeof(spi_configs) / sizeof(struct spi_config)) static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_3 { .devidx = 3, .base = USART3, .irq = NVIC_USART3_IRQ, .rcc = RCC_USART3, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOD, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOD, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOC, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) /* Setup GPIO Pins for SDIO: PC8 - PC11 - DAT0 thru DAT3 PC12 - CLK PD2 - CMD */ struct sdio_config sdio_conf = { .devidx = 0, .base = SDIO_BASE, .rcc_reg = (uint32_t *)&RCC_APB2ENR, .rcc_en = RCC_APB2ENR_SDIOEN, .rcc_rst_reg = (uint32_t *)&RCC_APB2RSTR, .rcc_rst = RCC_APB2RSTR_SDIORST, .card_detect_supported = 0, .pio_dat0 = { .base=GPIOC, .pin=GPIO8, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .af = GPIO_AF12, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat1 = { .base=GPIOC, .pin=GPIO9, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat2 = { .base=GPIOC, .pin=GPIO10, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat3 = { .base=GPIOC, .pin=GPIO11, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_clk = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cmd = { .base=GPIOD, .pin=GPIO2, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, }; struct gpio_config lis3dsh_pio = { .base=GPIOE, .pin=GPIO3, .mode=GPIO_MODE_OUTPUT, .pullupdown=GPIO_PUPD_PULLUP }; int machine_init(void) { int i; /* Clock */ rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[STM32_CLOCK]); /* Leds */ for (i = 0; i < 4; i++) { gpio_create(NULL, &Led[i]); } /* Button */ gpio_create(NULL, &Button); /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } /* I2Cs */ for (i = 0; i < NUM_I2CS; i++) { i2c_create(&i2c_configs[i]); } /* SPIs */ for (i = 0; i < NUM_SPIS; i++) { devspi_create(&spi_configs[i]); } lis3dsh_init(1, &lis3dsh_pio); rng_create(1, RCC_RNG); sdio_conf.rcc_reg = (uint32_t *)&RCC_APB2ENR; sdio_conf.rcc_en = RCC_APB2ENR_SDIOEN; sdio_init(&sdio_conf); usb_init(&usb_guest); ethernet_init(ð_config); dsp_init(); #ifdef CONFIG_DEVMCCOG21 mccog21_init(1); #endif #ifdef CONFIG_DEVXALED5X7 xadow_led_init(1); #endif #ifdef CONFIG_DEVCS43L22 cs43l22_init(1); #endif return 0; } ================================================ FILE: kernel/stm32f4/stm32f407diymore.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include #include #include #include #include #include #include #include #include "unicore-mx/stm32/spi.h" #include "drivers/stm32_sdio.h" #include "uart.h" #include "gpio.h" #include "sdio.h" #include "dsp.h" #include "rng.h" #include "usb.h" #include "eth.h" #include "i2c.h" #include "spi.h" #include "dsp.h" #include "dma.h" #include "drivers/lis3dsh.h" extern int xadow_led_init(uint32_t bus); #if CONFIG_SYS_CLOCK == 48000000 # define STM32_CLOCK RCC_CLOCK_3V3_48MHZ #elif CONFIG_SYS_CLOCK == 84000000 # define STM32_CLOCK RCC_CLOCK_3V3_84MHZ #elif CONFIG_SYS_CLOCK == 100000000 # define STM32_CLOCK RCC_CLOCK_3V3_100MHZ #elif CONFIG_SYS_CLOCK == 120000000 # define STM32_CLOCK RCC_CLOCK_3V3_120MHZ #elif CONFIG_SYS_CLOCK == 168000000 # define STM32_CLOCK RCC_CLOCK_3V3_168MHZ #else # error No valid clock speed selected #endif static const struct gpio_config Led = { .base=GPIOE, .pin=GPIO0,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP, .name="led0" }; static const struct gpio_config Button = { .base=GPIOD, .pin=GPIO15, .mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .name="button" }; static struct usb_pio_config_fs pio_fs = { .pio_vbus = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dm = { .base=GPIOA, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dp = { .base=GPIOA, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, } }; static struct usb_config usb_guest = { .dev_type = USB_DEV_FS, .otg_mode = USB_MODE_GUEST, .pio.fs = &pio_fs }; static const struct i2c_config i2c_configs[] = { #ifdef CONFIG_I2C1 { .idx = 1, .base = I2C1, .ev_irq = NVIC_I2C1_EV_IRQ, .er_irq = NVIC_I2C1_ER_IRQ, .rcc = RCC_I2C1, .dma_rcc = RCC_DMA1, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM6, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM6_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM5, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM5_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOB, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, .pio_sda = { .base=GPIOB, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, }, #endif }; #define NUM_I2CS (sizeof(i2c_configs) / sizeof(struct i2c_config)) static const struct spi_config spi_configs[] = { #ifdef CONFIG_SPI_1 { .idx = 1, .base = SPI1, .irq = NVIC_SPI1_IRQ, .rcc = RCC_SPI1, .baudrate = 0, /* TODO: SPI baudrate */ .polarity = 1, .phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, .tx_dma = { .base = DMA2, .stream = DMA_STREAM3, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = 0, }, .rx_dma = { .base = DMA2, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = NVIC_DMA2_STREAM2_IRQ, }, .dma_rcc = RCC_DMA1, .pio_sck = { .base=GPIOA, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_mosi = { .base=GPIOA, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_miso = { .base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, }, #endif #ifdef CONFIG_SPI_3 { .idx = 3, .base = SPI1, .irq = NVIC_SPI3_IRQ, .rcc = RCC_SPI3, .baudrate = 0, /* TODO: SPI baudrate */ .polarity = 1, .phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, .tx_dma = { .base = DMA1, .stream = DMA_STREAM5, .channel = DMA_SxCR_CHSEL_0, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI3), .irq = 0, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_0, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI3), .irq = NVIC_DMA1_STREAM0_IRQ, }, .dma_rcc = RCC_DMA1, .pio_sck = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_mosi = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_miso = { .base=GPIOC, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_nss = { .base=GPIOA, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, }, #endif }; #define NUM_SPIS (sizeof(spi_configs) / sizeof(struct spi_config)) static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) int machine_init(void) { int i; /* Clock */ rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[STM32_CLOCK]); /* Leds */ gpio_create(NULL, &Led); /* Button */ gpio_create(NULL, &Button); /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } /* I2Cs */ for (i = 0; i < NUM_I2CS; i++) { i2c_create(&i2c_configs[i]); } usb_init(&usb_guest); return 0; } ================================================ FILE: kernel/stm32f4/stm32f411nucleo.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include #include #include #include #include #include #include #include "unicore-mx/stm32/spi.h" #include "uart.h" #include "gpio.h" #include "dsp.h" #include "rng.h" #include "usb.h" #include "i2c.h" #include "dma.h" #include "spi.h" #include "drivers/lis3dsh.h" extern int xadow_led_init(uint32_t bus); #if CONFIG_SYS_CLOCK == 48000000 # define STM32_CLOCK RCC_CLOCK_3V3_48MHZ #elif CONFIG_SYS_CLOCK == 84000000 # define STM32_CLOCK RCC_CLOCK_3V3_84MHZ #elif CONFIG_SYS_CLOCK == 100000000 # define STM32_CLOCK RCC_CLOCK_3V3_100MHZ #elif CONFIG_SYS_CLOCK == 120000000 # define STM32_CLOCK RCC_CLOCK_3V3_120MHZ #elif CONFIG_SYS_CLOCK == 168000000 # define STM32_CLOCK RCC_CLOCK_3V3_168MHZ #else # error No valid clock speed selected #endif static const struct gpio_config Led = { .base=GPIOA, .pin=GPIO5,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0" }; static const struct gpio_config Button = { .base=GPIOC, .pin=GPIO13, .mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .name="button" }; static struct usb_pio_config_fs pio_fs = { .pio_vbus = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dm = { .base=GPIOA, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dp = { .base=GPIOA, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, } }; static struct usb_config usb_guest = { .dev_type = USB_DEV_FS, .otg_mode = USB_MODE_GUEST, .pio.fs = &pio_fs }; static const struct i2c_config i2c_configs[] = { #ifdef CONFIG_I2C1 { .idx = 1, .base = I2C1, .ev_irq = NVIC_I2C1_EV_IRQ, .er_irq = NVIC_I2C1_ER_IRQ, .rcc = RCC_I2C1, .dma_rcc = RCC_DMA2, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM6, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM6_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM0_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOB, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, .pio_sda = { .base=GPIOB, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_I2C2 { .idx = 1, .base = I2C2, .ev_irq = NVIC_I2C2_EV_IRQ, .er_irq = NVIC_I2C2_ER_IRQ, .rcc = RCC_I2C2, .dma_rcc = RCC_DMA1, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM7, .channel = DMA_SxCR_CHSEL_7, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C2), .irq = NVIC_DMA1_STREAM7_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_7, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C2), .irq = NVIC_DMA1_STREAM7_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOB, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, .pio_sda = { .base=GPIOB, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF9, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_I2C3 { .idx = 2, .base = I2C3, .ev_irq = NVIC_I2C2_EV_IRQ, .er_irq = NVIC_I2C2_ER_IRQ, .rcc = RCC_I2C2, .dma_rcc = RCC_DMA1, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM7, .channel = DMA_SxCR_CHSEL_7, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C2), .irq = NVIC_DMA1_STREAM7_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_7, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C2), .irq = NVIC_DMA1_STREAM7_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOA, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, .pio_sda = { .base=GPIOC, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, }, #endif }; #define NUM_I2CS (sizeof(i2c_configs) / sizeof(struct i2c_config)) static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOC, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) static const struct spi_config spi_configs[] = { #ifdef CONFIG_SPI_1 { .idx = 1, .base = SPI1, .irq = NVIC_SPI1_IRQ, .rcc = RCC_SPI1, .baudrate = 0, /* TODO: SPI baudrate */ .polarity = 1, .phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, .tx_dma = { .base = DMA2, .stream = DMA_STREAM3, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = 0, }, .rx_dma = { .base = DMA2, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = NVIC_DMA2_STREAM2_IRQ, }, .dma_rcc = RCC_DMA1, .pio_sck = { .base=GPIOA, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_mosi = { .base=GPIOA, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_miso = { .base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, }, #endif #ifdef CONFIG_SPI_3 { .idx = 3, .base = SPI1, .irq = NVIC_SPI3_IRQ, .rcc = RCC_SPI3, .baudrate = 0, /* TODO: SPI baudrate */ .polarity = 1, .phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, .tx_dma = { .base = DMA1, .stream = DMA_STREAM5, .channel = DMA_SxCR_CHSEL_0, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI3), .irq = 0, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_0, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI3), .irq = NVIC_DMA1_STREAM0_IRQ, }, .dma_rcc = RCC_DMA1, .pio_sck = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_mosi = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_miso = { .base=GPIOC, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_nss = { .base=GPIOA, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF6, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, }, #endif }; #define NUM_SPIS (sizeof(spi_configs) / sizeof(struct spi_config)) int machine_init(void) { int i; /* Clock */ #ifdef CLOCK_12MHZ rcc_clock_setup_hse_3v3(&rcc_hse_12mhz_3v3[STM32_CLOCK]); #else rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[STM32_CLOCK]); #endif /* Leds */ for (i = 0; i < 4; i++) { gpio_create(NULL, &Led); } /* Button */ gpio_create(NULL, &Button); /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } /* I2Cs */ for (i = 0; i < NUM_I2CS; i++) { i2c_create(&i2c_configs[i]); } /* SPIs */ for (i = 0; i < NUM_SPIS; i++) { devspi_create(&spi_configs[i]); } rng_create(1, RCC_RNG); usb_init(&usb_guest); #ifdef CONFIG_DEVMCCOG21 mccog21_init(1); #endif #ifdef CONFIG_DEVXALED5X7 xadow_led_init(1); #endif return 0; } ================================================ FILE: kernel/stm32f4/stm32f429discovery.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent, brabo * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include "unicore-mx/stm32/usart.h" #include "unicore-mx/cm3/nvic.h" #include #include #include #include #include "gpio.h" #include "stmpe811.h" #include "uart.h" #include "rng.h" #include "i2c.h" #include "spi.h" #if CONFIG_SYS_CLOCK == 48000000 # define STM32_CLOCK RCC_CLOCK_3V3_48MHZ #elif CONFIG_SYS_CLOCK == 84000000 # define STM32_CLOCK RCC_CLOCK_3V3_84MHZ #elif CONFIG_SYS_CLOCK == 120000000 # define STM32_CLOCK RCC_CLOCK_3V3_120MHZ #elif CONFIG_SYS_CLOCK == 168000000 # define STM32_CLOCK RCC_CLOCK_3V3_168MHZ #else # error No valid clock speed selected #endif static const struct gpio_config Led0 = { .base=GPIOG, .pin=GPIO13, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0" }; static const struct gpio_config Led1 = { .base=GPIOG, .pin=GPIO14, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led1" }; static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) static const struct i2c_config i2c_configs[] = { #ifdef CONFIG_I2C3 { .idx = 3, .base = I2C3, .ev_irq = NVIC_I2C3_EV_IRQ, .er_irq = NVIC_I2C3_ER_IRQ, .rcc = RCC_I2C3, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM4, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C3), .irq = NVIC_DMA1_STREAM4_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C3), .irq = NVIC_DMA1_STREAM2_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOA, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP }, .pio_sda = { .base=GPIOC, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP }, }, #endif }; #define NUM_I2CS (sizeof(i2c_configs) / sizeof(struct i2c_config)) static const struct spi_config spi_configs[] = { #ifdef CONFIG_SPI_5 { .idx = 1, .base = SPI5, .irq = NVIC_SPI5_IRQ, .rcc = RCC_SPI5, .baudrate = 0, /* TODO: SPI baudrate */ .polarity = 1, .phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, .tx_dma = { .base = DMA2, .stream = DMA_STREAM4, .channel = DMA_SxCR_CHSEL_2, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI5), .irq = 0, }, .rx_dma = { .base = DMA2, .stream = DMA_STREAM3, .channel = DMA_SxCR_CHSEL_2, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI5), .irq = NVIC_DMA2_STREAM3_IRQ, }, .dma_rcc = RCC_DMA1, .pio_sck = { .base=GPIOF, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, .pio_mosi = { .base=GPIOF, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF5, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ, }, }, #endif }; #define NUM_SPIS (sizeof(spi_configs) / sizeof(struct spi_config)) #ifdef CONFIG_DEVSTMPE811 static const struct ts_config ts_conf = { { .base=GPIOA, .pin=GPIO15, .mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, .af=GPIO_AF15, }, .bus=3, }; #endif int machine_init(void) { int i; rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[STM32_CLOCK]); gpio_create(NULL, &Led0); gpio_create(NULL, &Led1); /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } /* I2Cs */ for (i = 0; i < NUM_I2CS; i++) { i2c_create(&i2c_configs[i]); } /* SPIs */ for (i = 0; i < NUM_SPIS; i++) { devspi_create(&spi_configs[i]); } #ifdef CONFIG_DEVSTMPE811 stmpe811_init(&ts_conf); #endif rng_create(1, RCC_RNG); return 0; } ================================================ FILE: kernel/stm32f4/stm32f446nucleo.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include "unicore-mx/stm32/usart.h" #include "unicore-mx/cm3/nvic.h" #include "drivers/stm32_sdio.h" #ifdef CONFIG_DEVUART #include "uart.h" #endif #include "dsp.h" #include #include "gpio.h" #include "rng.h" static const struct gpio_addr gpio_addrs[] = { {.base=GPIOD, .pin=GPIO12,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="gpio_3_12"}, {.base=GPIOD, .pin=GPIO13,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="gpio_3_13"}, {.base=GPIOD, .pin=GPIO14,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="gpio_3_14"}, {.base=GPIOD, .pin=GPIO15,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="gpio_3_15"}, {.base=GPIOA, .pin=GPIO0,.mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .name="gpio_0_0"}, #ifdef CONFIG_DEVUART #ifdef CONFIG_USART_1 {.base=GPIOA, .pin=GPIO9,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, {.base=GPIOA, .pin=GPIO10,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name=NULL,}, #endif #ifdef CONFIG_USART_2 {.base=GPIOA, .pin=GPIO2,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, {.base=GPIOA, .pin=GPIO3,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name=NULL,}, #endif #ifdef CONFIG_USART_3 {.base=GPIOD, .pin=GPIO8,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, {.base=GPIOD, .pin=GPIO9,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name=NULL,}, #endif #ifdef CONFIG_USART_6 {.base=GPIOC, .pin=GPIO6,.mode=GPIO_MODE_AF,.af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, {.base=GPIOC, .pin=GPIO7,.mode=GPIO_MODE_AF,.af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name=NULL,}, #endif #endif #ifdef CONFIG_STM32F4USB {.base=GPIOA, .pin=GPIO9,.mode=GPIO_MODE_AF,.af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOA, .pin=GPIO11,.mode=GPIO_MODE_AF,.af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOA, .pin=GPIO12,.mode=GPIO_MODE_AF,.af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, #endif #ifdef CONFIG_DEVSTMETH {.base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11, .name=NULL}, // MDIO {.base=GPIOC, .pin=GPIO1, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11, .name=NULL}, // MDC {.base=GPIOA, .pin=GPIO1, .mode=GPIO_MODE_AF, .af=GPIO_AF11, .name=NULL}, // RMII REF CLK {.base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF11, .name=NULL}, // RMII CRS DV {.base=GPIOB, .pin=GPIO10,.mode=GPIO_MODE_AF, .af=GPIO_AF11, .name=NULL}, // RMII RXER {.base=GPIOC, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF11, .name=NULL}, // RMII RXD0 {.base=GPIOC, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF11, .name=NULL}, // RMII RXD1 {.base=GPIOB, .pin=GPIO11,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11, .name=NULL}, // RMII TXEN {.base=GPIOB, .pin=GPIO12,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11, .name=NULL}, // RMII TXD0 {.base=GPIOB, .pin=GPIO13,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11, .name=NULL}, // RMII TXD1 {.base=GPIOE, .pin=GPIO2, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name=NULL, .pullupdown=GPIO_PUPD_PULLUP}, // PHY RESET #endif }; #define NUM_GPIOS (sizeof(gpio_addrs) / sizeof(struct gpio_addr)) #ifdef CONFIG_DEVUART static const struct uart_addr uart_addrs[] = { #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, }, #endif #ifdef CONFIG_USART_3 { .devidx = 3, .base = USART3, .irq = NVIC_USART3_IRQ, .rcc = RCC_USART3, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, }, #endif }; #define NUM_UARTS (sizeof(uart_addrs) / sizeof(struct uart_addr)) #endif #ifdef CONFIG_RNG #include "stm32_rng.h" static const struct rng_addr rng_addrs[] = { { .devidx = 1, .base = 1, .rcc = RCC_RNG, }, }; #define NUM_RNGS (sizeof(rng_addrs) / sizeof(struct rng_addr)) #endif /* Setup GPIO Pins for SDIO: PC8 - PC11 - DAT0 thru DAT3 PC12 - CLK PD2 - CMD */ struct sdio_config sdio_conf = { .devidx = 0, .base = SDIO_BASE, .rcc_reg = (uint32_t *)&RCC_APB2ENR, .rcc_en = RCC_APB2ENR_SDIOEN, .rcc_rst_reg = (uint32_t *)&RCC_APB2RSTR, .rcc_rst = RCC_APB2RSTR_SDIORST, .card_detect_supported = 1, .pio_dat0 = { .base=GPIOC, .pin=GPIO8, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .af = GPIO_AF12, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat1 = { .base=GPIOC, .pin=GPIO9, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat2 = { .base=GPIOC, .pin=GPIO10, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat3 = { .base=GPIOC, .pin=GPIO11, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_clk = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cmd = { .base=GPIOD, .pin=GPIO2, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cd = { .base=GPIOB, .pin=GPIO15, .mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_PULLUP } }; void machine_init(struct fnode * dev) { # if CONFIG_SYS_CLOCK == 48000000 rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_48MHZ]); # elif CONFIG_SYS_CLOCK == 84000000 rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_84MHZ]); # elif CONFIG_SYS_CLOCK == 120000000 rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ]); # elif CONFIG_SYS_CLOCK == 168000000 rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]); # elif CONFIG_SYS_CLOCK == 180000000 rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_180MHZ]); # else #error No valid clock speed selected #endif gpio_init(dev, gpio_addrs, NUM_GPIOS); #ifdef CONFIG_DEVUART uart_init(dev, uart_addrs, NUM_UARTS); #endif rng_init(dev, rng_addrs, NUM_RNGS); sdio_init(&sdio_conf); #ifdef CONFIG_DSP dsp_init(dev); #endif #ifdef CONFIG_DEVSTMETH gpio_clear(GPIOE,GPIO2); /* Clear ETH nRESET pin */ gpio_set(GPIOE,GPIO2); /* Set ETH nRESET pin */ #endif } ================================================ FILE: kernel/stm32f4/stm32f4x1discovery.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include "unicore-mx/cm3/nvic.h" #include #include "unicore-mx/stm32/usart.h" #include #include #include #include #include #include "uart.h" #include "gpio.h" #include "adc.h" #if CONFIG_SYS_CLOCK == 48000000 static const uint32_t rcc_clock = RCC_CLOCK_3V3_48MHZ; #elif CONFIG_SYS_CLOCK == 84000000 static const uint32_t rcc_clock = RCC_CLOCK_3V3_84MHZ; #else # error No valid clock speed selected for STM32F4x1 Discovery #endif static const struct gpio_config Leds[] = { {.base=GPIOD, .pin=GPIO12,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0"}, {.base=GPIOD, .pin=GPIO13,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led1"}, {.base=GPIOD, .pin=GPIO14,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led2"}, {.base=GPIOD, .pin=GPIO15,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led3"}, }; static const struct gpio_config Button = {.base=GPIOA, .pin=GPIO0,.mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, .name=NULL}; #ifdef CONFIG_DEVUART static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIOA, .pin=GPIO9,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIOA, .pin=GPIO10,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name=NULL,}, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIOA, .pin=GPIO2,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIOA, .pin=GPIO3,.mode=GPIO_MODE_AF,.af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name=NULL,}, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = {.base=GPIOC, .pin=GPIO6,.mode=GPIO_MODE_AF,.af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, .pio_tx = {.base=GPIOC, .pin=GPIO7,.mode=GPIO_MODE_AF,.af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name=NULL,}, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) #endif /* TODO */ #if 0 #ifdef CONFIG_DEVI2C #ifdef CONFIG_I2C_1 {.base=GPIOB, .pin=GPIO6,.mode=GPIO_MODE_AF,.af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP, .name=NULL,}, {.base=GPIOB, .pin=GPIO9,.mode=GPIO_MODE_AF,.af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP, .name=NULL,}, #ifdef CONFIG_DEVLSM303DLHC /* Depends on I2C_1 : DRDY - PE2 Int1 - E4 Int2 - E5 */ {.base=GPIOE, .pin=GPIO2,.mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOE, .pin=GPIO4,.mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOE, .pin=GPIO5,.mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, #endif #endif #endif #ifdef CONFIG_DEVSPI #ifdef CONFIG_SPI_1 /* SCK - PA5 MISO - PA6 MOSI - */ {.base=GPIOA, .pin=GPIO5,.mode=GPIO_MODE_AF,.af=GPIO_AF5, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, {.base=GPIOA, .pin=GPIO6,.mode=GPIO_MODE_AF,.af=GPIO_AF5, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, {.base=GPIOA, .pin=GPIO7,.mode=GPIO_MODE_AF,.af=GPIO_AF5, .pullupdown=GPIO_PUPD_NONE, .name=NULL,}, #ifdef CONFIG_DEVL3GD20 /* Depends on SPI_1 : CS - PE3 INT1 - PE0 INT2 - PE1 */ {.base=GPIOE, .pin=GPIO3,.mode=GPIO_MODE_OUTPUT, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, .name="l3gd20_cs"}, {.base=GPIOE, .pin=GPIO0,.mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOE, .pin=GPIO1,.mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, #endif #endif #endif #ifdef CONFIG_DEVADC {.base=GPIOA, .pin=GPIO1,.mode=GPIO_MODE_ANALOG, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOB, .pin=GPIO0,.mode=GPIO_MODE_ANALOG, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOB, .pin=GPIO1,.mode=GPIO_MODE_ANALOG, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, #endif #ifdef CONFIG_STM32F4USB {.base=GPIOA, .pin=GPIO9,.mode=GPIO_MODE_AF,.af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOA, .pin=GPIO11,.mode=GPIO_MODE_AF,.af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, {.base=GPIOA, .pin=GPIO12,.mode=GPIO_MODE_AF,.af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .name=NULL}, #endif }; #ifdef CONFIG_DEVSPI static const struct spi_addr spi_addrs[] = { #ifdef CONFIG_SPI_1 { .base = SPI1, .irq = NVIC_SPI1_IRQ, .rcc = RCC_SPI1, /* Move this to the upper driver */ .baudrate_prescaler = SPI_CR1_BR_FPCLK_DIV_256, .clock_pol = 1, .clock_phase = 1, .rx_only = 0, .bidir_mode = 0, .dff_16 = 0, .enable_software_slave_management = 1, .send_msb_first = 1, /* End move */ .name = "spi1", .tx_dma = { .base = DMA2, .stream = DMA_STREAM3, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = 0, }, .rx_dma = { .base = DMA2, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &SPI_DR(SPI1), .irq = NVIC_DMA2_STREAM2_IRQ, }, .dma_rcc = RCC_DMA2, }, #endif }; #define NUM_SPIS (sizeof(spi_addrs) / sizeof(struct spi_addr)) #endif #ifdef CONFIG_DEVI2C static const struct i2c_addr i2c_addrs[] = { #ifdef CONFIG_I2C_1 { .base = I2C1, .ev_irq = NVIC_I2C1_EV_IRQ, .er_irq = NVIC_I2C1_ER_IRQ, .rcc = RCC_I2C1, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .name = "i2c1", .tx_dma = { .base = DMA1, .stream = DMA_STREAM6, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM6_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM0_IRQ, }, .dma_rcc = RCC_DMA1, }, #endif }; #define NUM_I2CS (sizeof(i2c_addrs) / sizeof(struct i2c_addr)) #endif #ifdef CONFIG_DEVADC static const struct adc_config adc_configs[] = { { .base = ADC1, .irq = NVIC_ADC_IRQ, .rcc = RCC_ADC1, .name = "adc", .channel_array = {1, 8, 9}, /*ADC_IN1,8,9 on PA1, PB0, PB1 */ .num_channels = 3, /* Use DMA to fetch sample data */ .dma = { .base = DMA2, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_16BIT, .msize = DMA_SxCR_MSIZE_16BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_HIGH, .paddr = (uint32_t) &ADC_DR(ADC1), .irq = NVIC_DMA2_STREAM0_IRQ, }, .dma_rcc = RCC_DMA2, } }; #define NUM_ADC (sizeof(adc_configs)/sizeof(struct adc_config)) #endif #ifdef CONFIG_DEVLSM303DLHC #include "drivers/lsm303dlhc.h" static const struct lsm303dlhc_addr lsm303dlhc_addr = { .name = "l3gd20", .i2c_name = "/dev/i2c1", .pio1_base = GPIOE, .pio2_base = GPIOE, .drdy_base = GPIOE, .pio1_pin = GPIO4, .pio2_pin = GPIO5, .drdy_pin = GPIO2, .address = 0x32, .drdy_address = 0x3C }; #endif #ifdef CONFIG_DEVL3GD20 #include "drivers/l3gd20.h" static const struct l3gd20_addr l3gd20_addr = { .name = "l3gd20", .spi_name = "/dev/spi1", .spi_cs_name = "/dev/l3gd20_cs", .pio1_base = GPIOE, .pio2_base = GPIOE, .pio1_pin = GPIO0, .pio2_pin = GPIO1, }; #endif #endif int machine_init(void) { int i; /* Clock */ rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[rcc_clock]); /* Button */ gpio_create(NULL, &Button); /* Leds */ for (i = 0; i < 4; i++) { gpio_create(NULL, &Leds[i]); } /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } return 0; /* TODO: port to new pinmux */ #if 0 #ifdef CONFIG_DEVSPI spi_init(dev, spi_addrs, NUM_SPIS); #ifdef CONFIG_DEVL3GD20 l3gd20_init(dev, l3gd20_addrs, NUM_L3GD20); #endif #endif #ifdef CONFIG_DEVI2C i2c_init(dev, i2c_addrs, NUM_I2CS); #ifdef CONFIG_DEVLSM303DLHC lsm303dlhc_init(dev, lsm303dlhc_addrs, NUM_LSM303DLHC); #endif #endif #ifdef CONFIG_DEVADC adc_init(adc_configs, NUM_ADC); #endif #ifdef CONFIG_DEVLSM303DLHC lsm303dlhc_init(dev, lsm303dlhc_addr); #endif #ifdef CONFIG_DEVL3GD20 l3gd20_init(dev, l3gd20_addr); #endif #endif } ================================================ FILE: kernel/stm32f4/stm32f4xxpyboard.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include #include #include #include #include #include #include #include #include "unicore-mx/stm32/spi.h" #include "drivers/stm32_sdio.h" #include "uart.h" #include "gpio.h" #include "sdio.h" #include "dsp.h" #include "rng.h" #include "usb.h" #include "i2c.h" #include "dma.h" #include "drivers/lis3dsh.h" extern int xadow_led_init(uint32_t bus); #if CONFIG_SYS_CLOCK == 48000000 # define STM32_CLOCK RCC_CLOCK_3V3_48MHZ #elif CONFIG_SYS_CLOCK == 84000000 # define STM32_CLOCK RCC_CLOCK_3V3_84MHZ #elif CONFIG_SYS_CLOCK == 100000000 # define STM32_CLOCK RCC_CLOCK_3V3_100MHZ #elif CONFIG_SYS_CLOCK == 120000000 # define STM32_CLOCK RCC_CLOCK_3V3_120MHZ #elif CONFIG_SYS_CLOCK == 168000000 # define STM32_CLOCK RCC_CLOCK_3V3_168MHZ #else # error No valid clock speed selected #endif static const struct gpio_config Led[4] = { { .base=GPIOA, .pin=GPIO13,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0" }, { .base=GPIOA, .pin=GPIO14,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led1" }, { .base=GPIOA, .pin=GPIO15,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led2" }, { .base=GPIOB, .pin=GPIO4,.mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led3" }, }; static const struct gpio_config Button = { .base=GPIOB, .pin=GPIO3, .mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .name="button" }; static struct usb_pio_config_fs pio_fs = { .pio_vbus = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dm = { .base=GPIOA, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dp = { .base=GPIOA, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, } }; static struct usb_config usb_guest = { .dev_type = USB_DEV_FS, .otg_mode = USB_MODE_GUEST, .pio.fs = &pio_fs }; static const struct i2c_config i2c_configs[] = { #ifdef CONFIG_I2C1 { .idx = 1, .base = I2C1, .ev_irq = NVIC_I2C1_EV_IRQ, .er_irq = NVIC_I2C1_ER_IRQ, .rcc = RCC_I2C1, .dma_rcc = RCC_DMA2, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM6, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM6_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM0_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOB, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, .pio_sda = { .base=GPIOB, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_I2C2 { .idx = 1, .base = I2C2, .ev_irq = NVIC_I2C2_EV_IRQ, .er_irq = NVIC_I2C2_ER_IRQ, .rcc = RCC_I2C2, .dma_rcc = RCC_DMA1, .clock_f = I2C_CR2_FREQ_36MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .tx_dma = { .base = DMA1, .stream = DMA_STREAM7, .channel = DMA_SxCR_CHSEL_7, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C2), .irq = NVIC_DMA1_STREAM7_IRQ, }, .rx_dma = { .base = DMA1, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_7, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C2), .irq = NVIC_DMA1_STREAM7_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOB, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, .pio_sda = { .base=GPIOB, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown = GPIO_PUPD_NONE }, }, #endif }; #define NUM_I2CS (sizeof(i2c_configs) / sizeof(struct i2c_config)) static const struct uart_config uart_configs[] = { #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOB, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOB, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_3 { .devidx = 3, .base = USART3, .irq = NVIC_USART3_IRQ, .rcc = RCC_USART3, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOB, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOB, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_4 { .devidx = 4, .base = USART4, .irq = NVIC_USART4_IRQ, .rcc = RCC_USART4, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOA, .pin=GPIO1, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOA, .pin=GPIO0, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_rx = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE, }, .pio_tx = { .base=GPIOC, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, }, #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) /* Setup GPIO Pins for SDIO: PC8 - PC11 - DAT0 thru DAT3 PC12 - CLK PD2 - CMD */ struct sdio_config sdio_conf = { .devidx = 0, .base = SDIO_BASE, .rcc_reg = (uint32_t *)&RCC_APB2ENR, .rcc_en = RCC_APB2ENR_SDIOEN, .rcc_rst_reg = (uint32_t *)&RCC_APB2RSTR, .rcc_rst = RCC_APB2RSTR_SDIORST, .card_detect_supported = 1, .pio_dat0 = { .base=GPIOC, .pin=GPIO8, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .af = GPIO_AF12, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat1 = { .base=GPIOC, .pin=GPIO9, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat2 = { .base=GPIOC, .pin=GPIO10, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat3 = { .base=GPIOC, .pin=GPIO11, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_clk = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cmd = { .base=GPIOD, .pin=GPIO2, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cd = { .base=GPIOA, .pin=GPIO8, .mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_PULLUP } }; int machine_init(void) { int i; /* Clock */ #ifdef CLOCK_12MHZ rcc_clock_setup_hse_3v3(&rcc_hse_12mhz_3v3[STM32_CLOCK]); #else rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[STM32_CLOCK]); #endif /* Leds */ for (i = 0; i < 4; i++) { gpio_create(NULL, &Led[i]); } /* Button */ gpio_create(NULL, &Button); /* Uarts */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } /* I2Cs */ for (i = 0; i < NUM_I2CS; i++) { i2c_create(&i2c_configs[i]); } rng_create(1, RCC_RNG); sdio_init(&sdio_conf); usb_init(&usb_guest); #ifdef CONFIG_DEVMCCOG21 mccog21_init(1); #endif #ifdef CONFIG_DEVXALED5X7 xadow_led_init(1); #endif return 0; } ================================================ FILE: kernel/stm32f7/Kconfig ================================================ if ARCH_STM32F7 choice prompt "MCU" default ARCH_STM32F746_NG config ARCH_STM32F746_NG bool "STM32F746NG 1MB" select FLASH_SIZE_1MB select RAM_SIZE_320KB select ARCH_STM32F746 config ARCH_STM32F769_NI bool "STM32F769NI 2MB" select FLASH_SIZE_2MB select RAM_SIZE_368KB select ARCH_STM32F769 endchoice endif ================================================ FILE: kernel/stm32f7/stm32f7.ld.in ================================================ MEMORY { FLASH (rx) : ORIGIN = __FLASH_ORIGIN, LENGTH = __KFLASHMEM_SIZE SRAM (rwx) : ORIGIN = __RAM1_BASE, LENGTH = __KRAMMEM_SIZE SRAM_USER (rwx) : ORIGIN = (__RAM1_BASE + __KRAMMEM_SIZE), LENGTH = (__RAM1_SIZE - __KRAMMEM_SIZE) SDRAM_USER(rwx) : ORIGIN = __SDRAM_BASE, LENGTH = __SDRAM_SIZE } /* Enforce emmition of the vector table. */ EXTERN (vector_table) /* Define the entry point of the output file. */ ENTRY(reset_handler) SECTIONS { .text : { KEEP(*(.vectors)) *(.text*) *(.rodata*) } > FLASH /* C++ Static constructors/destructors, also used for __attribute__ * ((constructor)) and the likes */ .preinit_array : { . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; } > FLASH .init_array : { . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; } > FLASH .fini_array : { . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; } > FLASH .data : { _etext = LOADADDR(.data); _data = .; *(vtable) *(.data*) _edata = .; } > SRAM AT > FLASH _data_loadaddr = LOADADDR(.data); .bss : { _bss = .; *(.bss*) *(COMMON) . = ALIGN(32 / 8); _ebss = .; PROVIDE (end = .); } > SRAM .heap : { /* heap starts after BSS */ PROVIDE(_heap_start = _ebss ); } > SRAM } PROVIDE(_stack = ORIGIN(SRAM) + LENGTH(SRAM)); PROVIDE(_user_heap_start = ORIGIN(SRAM_USER)); PROVIDE(_user_heap_end = ORIGIN(SRAM_USER) + LENGTH(SRAM_USER)); PROVIDE(_external_heap_start = ORIGIN(SDRAM_USER)); PROVIDE(_external_heap_end = ORIGIN(SDRAM_USER) + LENGTH(SDRAM_USER)); PROVIDE(_extra_heap_start = ORIGIN(SDRAM_USER)); PROVIDE(_extra_heap_end = ORIGIN(SDRAM_USER) + LENGTH(SDRAM_USER)); ================================================ FILE: kernel/stm32f7/stm32f746discovery.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include #include #include #include #include #if CONFIG_SYS_CLOCK == 216000000 #else #error No valid clock speed selected for STM32F729 Discovery #endif #include "gpio.h" #include "uart.h" #include "rng.h" #include "sdram.h" #include "sdio.h" #include "framebuffer.h" #include "ltdc.h" #include "usb.h" #include "eth.h" #include "i2c.h" #include "tty_console.h" static const struct gpio_config gpio_led0 = { .base=GPIOI, .pin=GPIO1, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0" }; static const struct gpio_config gpio_button = { .base=GPIOI, .pin=GPIO11, .mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP, .name="button" }; static const struct uart_config uart_configs[] = { #ifdef CONFIG_DEVUART #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOB, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOC, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE }, }, #endif #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) /* Setup GPIO Pins for SDIO: PC8 - PC11 - DAT0 thru DAT3 PC12 - CLK PD2 - CMD */ struct sdio_config sdio_conf = { .devidx = 0, .base = (uint32_t *)SDIO_BASE, .rcc_reg = (uint32_t *)&RCC_APB2ENR, .rcc_en = RCC_APB2ENR_SDMMC1EN, .rcc_rst_reg = (uint32_t *)&RCC_APB2RSTR, .rcc_rst = RCC_APB2RSTR_SDMMC1RST, .card_detect_supported = 1, .pio_dat0 = { .base=GPIOC, .pin=GPIO8, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .af = GPIO_AF12, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat1 = { .base=GPIOC, .pin=GPIO9, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat2 = { .base=GPIOC, .pin=GPIO10, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat3 = { .base=GPIOC, .pin=GPIO11, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_clk = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cmd = { .base=GPIOD, .pin=GPIO2, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cd = { .base=GPIOC, .pin=GPIO13, .mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_PULLUP } }; struct gpio_config stm32eth_mii_pins[] = { {.base=GPIOA, .pin=GPIO1, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII REF CLK {.base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDIO {.base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII CRS DV {.base=GPIOG, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXER {.base=GPIOG, .pin=GPIO11,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXEN {.base=GPIOG, .pin=GPIO13,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD0 {.base=GPIOG, .pin=GPIO14,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD1 {.base=GPIOC, .pin=GPIO1, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDC {.base=GPIOC, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD0 {.base=GPIOC, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD1 }; static struct eth_config eth_config = { .pio_mii = stm32eth_mii_pins, .n_pio_mii = sizeof(stm32eth_mii_pins)/sizeof(struct gpio_config), .pio_phy_reset = {}, .has_phy_reset = 0 }; static struct usb_pio_config_fs pio_usbfs = { .pio_vbus = { .base=GPIOA, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dm = { .base=GPIOA, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dp = { .base=GPIOA, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_phy = { .base = GPIOD, .pin = GPIO5, .mode=GPIO_MODE_OUTPUT, .pullupdown = GPIO_PUPD_NONE } }; static struct usb_pio_config_hs pio_usbhs = { .ulpi_data = { { .base=GPIOA, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, { .base=GPIOB, .pin=GPIO0, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE , .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, { .base=GPIOB, .pin=GPIO1, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE , .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, { .base=GPIOB, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, { .base=GPIOB, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, { .base=GPIOB, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, { .base=GPIOB, .pin=GPIO13, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, { .base=GPIOB, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE , .optype=GPIO_OTYPE_PP, .speed=GPIO_OSPEED_100MHZ}, }, .ulpi_clk = { .base=GPIOA, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .speed=GPIO_OSPEED_100MHZ}, .ulpi_dir = { .base=GPIOC, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .speed=GPIO_OSPEED_100MHZ}, .ulpi_next = { .base=GPIOH, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .speed=GPIO_OSPEED_100MHZ}, .ulpi_step = { .base=GPIOC, .pin=GPIO0, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_NONE, .speed=GPIO_OSPEED_100MHZ} }; static struct usb_config usb_fs_guest = { .dev_type = USB_DEV_FS, .otg_mode = USB_MODE_GUEST, .pio.fs = &pio_usbfs }; static struct usb_config usb_hs_guest = { .dev_type = USB_DEV_HS, .otg_mode = USB_MODE_GUEST, .pio.hs = &pio_usbhs }; static struct usb_config usb_hs_host = { .dev_type = USB_DEV_HS, .otg_mode = USB_MODE_HOST, .pio.hs = &pio_usbhs }; /** I2C: * Touchscreen: * INT = PI13 * CLK = PI14 * R0 = PI15 * SCL = PH7 * SDA = PH8 * VSYNC = PI10 * HSYNC = PI11 * Address = 01110000 */ static const struct i2c_config i2c_configs[] = { #ifdef CONFIG_I2C1 { .idx = 1, .base = I2C1, .ev_irq = NVIC_I2C1_EV_IRQ, .er_irq = NVIC_I2C1_ER_IRQ, .rcc = RCC_I2C1, .clock_f = I2C_CR2_FREQ_42MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .rx_dma = { .base = DMA1, .stream = DMA_STREAM0, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM0_IRQ, }, .tx_dma = { .base = DMA1, .stream = DMA_STREAM6, .channel = DMA_SxCR_CHSEL_1, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C1), .irq = NVIC_DMA1_STREAM6_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOB, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP }, .pio_sda = { .base=GPIOB, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP }, }, #endif #ifdef CONFIG_I2C3 { .idx = 3, .base = I2C3, .ev_irq = NVIC_I2C3_EV_IRQ, .er_irq = NVIC_I2C3_ER_IRQ, .rcc = RCC_I2C3, .clock_f = I2C_CR2_FREQ_42MHZ, .fast_mode = 1, .rise_time = 11, .bus_clk_frequency = 10, .rx_dma = { .base = DMA1, .stream = DMA_STREAM2, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, .prio = DMA_SxCR_PL_VERY_HIGH, .paddr = (uint32_t) &I2C_DR(I2C3), .irq = NVIC_DMA1_STREAM2_IRQ, }, .tx_dma = { .base = DMA1, .stream = DMA_STREAM4, .channel = DMA_SxCR_CHSEL_3, .psize = DMA_SxCR_PSIZE_8BIT, .msize = DMA_SxCR_MSIZE_8BIT, .dirn = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, .prio = DMA_SxCR_PL_MEDIUM, .paddr = (uint32_t) &I2C_DR(I2C3), .irq = NVIC_DMA1_STREAM4_IRQ, }, .dma_rcc = RCC_DMA1, .pio_scl = { .base=GPIOH, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP }, .pio_sda = { .base=GPIOH, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF4, .speed=GPIO_OSPEED_50MHZ, .optype=GPIO_OTYPE_OD, .pullupdown=GPIO_PUPD_PULLUP }, }, #endif }; #define NUM_I2CS (sizeof(i2c_configs) / sizeof(struct i2c_config)) extern int ft5336_init(uint32_t); extern int mccog21_init(uint32_t); int machine_init(void) { int i = 0; rcc_clock_setup_hse_3v3(&rcc_hse_25mhz_3v3); usb_init(&usb_hs_host); gpio_create(NULL, &gpio_led0); gpio_create(NULL, &gpio_button); /* UARTS */ for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } /* I2Cs */ for (i = 0; i < NUM_I2CS; i++) { i2c_create(&i2c_configs[i]); } rng_create(1, RCC_RNG); sdio_init(&sdio_conf); /* Initialize USB OTG guest in full-speed mode */ //usb_init(&usb_fs_guest); ethernet_init(ð_config); #ifdef CONFIG_DEVMCCOG21 mccog21_init(1); #endif #ifdef CONFIG_DEVFT5336 ft5336_init(3); /* FT5336 touch screen on I2C-3 */ #endif return 0; } ================================================ FILE: kernel/stm32f7/stm32f746nucleo-144.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include #include #include #if CONFIG_SYS_CLOCK == 216000000 #else #error No valid clock speed selected for STM32F729 Discovery #endif #include "gpio.h" #include "uart.h" #include "rng.h" #include "sdram.h" #include "sdio.h" #include "framebuffer.h" #include "ltdc.h" #include "usb.h" #include "eth.h" static const struct gpio_config gpio_led0 = { .base=GPIOB, .pin=GPIO0, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0" }; static const struct gpio_config gpio_led1 = { .base=GPIOB, .pin=GPIO7, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led1" }; static const struct gpio_config gpio_led2 = { .base=GPIOB, .pin=GPIO14, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led2" }; static const struct gpio_config gpio_button = { .base=GPIOI, .pin=GPIO11, .mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP, .name="button" }; static const struct uart_config uart_configs[] = { #ifdef CONFIG_DEVUART #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOD, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOD, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_USART_3 { .devidx = 3, .base = USART3, .irq = NVIC_USART3_IRQ, .rcc = RCC_USART3, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOD, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOD, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOG, .pin=GPIO14, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOG, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE }, }, #endif #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) /* Setup GPIO Pins for SDIO: PC8 - PC11 - DAT0 thru DAT3 PC12 - CLK PD2 - CMD */ struct sdio_config sdio_conf = { .devidx = 0, .base = SDIO_BASE, .rcc_reg = (uint32_t *)&RCC_APB2ENR, .rcc_en = RCC_APB2ENR_SDMMC1EN, .rcc_rst_reg = (uint32_t *)&RCC_APB2RSTR, .rcc_rst = RCC_APB2RSTR_SDMMC1RST, .card_detect_supported = 0, .pio_dat0 = { .base=GPIOC, .pin=GPIO8, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .af = GPIO_AF12, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat1 = { .base=GPIOC, .pin=GPIO9, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat2 = { .base=GPIOC, .pin=GPIO10, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat3 = { .base=GPIOC, .pin=GPIO11, .af = GPIO_AF12, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_clk = { .base=GPIOC, .pin=GPIO12, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cmd = { .base=GPIOD, .pin=GPIO2, .mode=GPIO_MODE_AF, .af = GPIO_AF12, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, }; struct gpio_config stm32eth_mii_pins[] = { {.base=GPIOA, .pin=GPIO1, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII REF CLK {.base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDIO {.base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII CRS DV //{.base=GPIOB, .pin=GPIO10,.mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXER --> Not connected? {.base=GPIOG, .pin=GPIO11,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXEN {.base=GPIOG, .pin=GPIO13,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD0 {.base=GPIOB, .pin=GPIO13,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD1 {.base=GPIOC, .pin=GPIO1, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDC {.base=GPIOC, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD0 {.base=GPIOC, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD1 }; static struct eth_config eth_config = { .pio_mii = stm32eth_mii_pins, .n_pio_mii = 10, .pio_phy_reset = { .base=GPIOE, .pin=GPIO2, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, }, .has_phy_reset = 1 }; static struct usb_pio_config_fs pio_usbfs = { .pio_vbus = { .base=GPIOA, .pin=GPIO8, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dm = { .base=GPIOA, .pin=GPIO11, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, }, .pio_dp = { .base=GPIOA, .pin=GPIO12, .mode=GPIO_MODE_AF, .af=GPIO_AF10, .pullupdown=GPIO_PUPD_NONE, } }; static struct usb_config usb_guest = { .dev_type = USB_DEV_FS, .otg_mode = USB_MODE_GUEST, .pio.fs = &pio_usbfs }; int machine_init(void) { int i = 0; rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3); gpio_create(NULL, &gpio_led0); gpio_create(NULL, &gpio_led1); gpio_create(NULL, &gpio_led2); // gpio_create(NULL, &gpio_button); for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } rng_create(1, RCC_RNG); sdio_conf.rcc_reg = (uint32_t *)&RCC_APB2ENR; sdio_conf.rcc_en = RCC_APB2ENR_SDMMC1EN; sdio_init(&sdio_conf); usb_init(&usb_guest); ethernet_init(ð_config); return 0; } ================================================ FILE: kernel/stm32f7/stm32f769discovery.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #include #include #include #include #if CONFIG_SYS_CLOCK == 216000000 #else #error No valid clock speed selected for STM32F729 Discovery #endif #include "gpio.h" #include "uart.h" #include "rng.h" #include "sdram.h" #include "sdio.h" #include "framebuffer.h" #include "ltdc.h" #include "usb.h" #include "eth.h" static const struct gpio_config gpio_led[2] = { { .base=GPIOJ, .pin=GPIO13, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led0" }, { .base=GPIOJ, .pin=GPIO5, .mode=GPIO_MODE_OUTPUT, .optype=GPIO_OTYPE_PP, .name="led1" }, }; static const struct gpio_config gpio_button = { .base=GPIOA, .pin=GPIO0, .mode=GPIO_MODE_INPUT, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP, .name="button" }; static const struct uart_config uart_configs[] = { #ifdef CONFIG_DEVUART #ifdef CONFIG_USART_1 { .devidx = 1, .base = USART1, .irq = NVIC_USART1_IRQ, .rcc = RCC_USART1, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOA, .pin=GPIO10, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOA, .pin=GPIO9, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_USART_2 { .devidx = 2, .base = USART2, .irq = NVIC_USART2_IRQ, .rcc = RCC_USART2, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOA, .pin=GPIO3, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .af=GPIO_AF7, .pullupdown=GPIO_PUPD_NONE }, }, #endif #ifdef CONFIG_USART_6 { .devidx = 6, .base = USART6, .irq = NVIC_USART6_IRQ, .rcc = RCC_USART6, .baudrate = 115200, .stop_bits = USART_STOPBITS_1, .data_bits = 8, .parity = USART_PARITY_NONE, .flow = USART_FLOWCONTROL_NONE, .pio_tx = { .base=GPIOC, .pin=GPIO6, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .speed=GPIO_OSPEED_25MHZ, .optype=GPIO_OTYPE_PP, }, .pio_rx = { .base=GPIOC, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF8, .pullupdown=GPIO_PUPD_NONE }, }, #endif #endif }; #define NUM_UARTS (sizeof(uart_configs) / sizeof(struct uart_config)) struct sdio_config sdio_conf = { .devidx = 0, .base = SDIO2_BASE, .rcc_reg = (uint32_t *)&RCC_APB2ENR, .rcc_en = RCC_APB2ENR_SDMMC2EN, .rcc_rst_reg = (uint32_t *)&RCC_APB2RSTR, .rcc_rst = RCC_APB2RSTR_SDMMC2RST, .card_detect_supported = 1, .pio_dat0 = { .base=GPIOG, .pin=GPIO9, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .af = GPIO_AF11, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat1 = { .base=GPIOG, .pin=GPIO10, .mode=GPIO_MODE_AF, .af = GPIO_AF11, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat2 = { .base=GPIOB, .pin=GPIO3, .af = GPIO_AF10, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_dat3 = { .base=GPIOB, .pin=GPIO4, .af = GPIO_AF10, .mode=GPIO_MODE_AF, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_clk = { .base=GPIOD, .pin=GPIO6, .mode=GPIO_MODE_AF, .af = GPIO_AF11, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cmd = { .base=GPIOD, .pin=GPIO7, .mode=GPIO_MODE_AF, .af = GPIO_AF11, .speed=GPIO_OSPEED_100MHZ, .optype=GPIO_OTYPE_PP, .pullupdown=GPIO_PUPD_PULLUP }, .pio_cd = { .base=GPIOI, .pin=GPIO15, .mode=GPIO_MODE_INPUT, .pullupdown=GPIO_PUPD_PULLUP }, }; struct gpio_config stm32eth_mii_pins[] = { {.base=GPIOA, .pin=GPIO1, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII REF CLK {.base=GPIOA, .pin=GPIO2, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDIO {.base=GPIOA, .pin=GPIO7, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII CRS DV {.base=GPIOD, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXER {.base=GPIOG, .pin=GPIO11,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXEN {.base=GPIOG, .pin=GPIO13,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD0 {.base=GPIOG, .pin=GPIO14,.mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // RMII TXD1 {.base=GPIOC, .pin=GPIO1, .mode=GPIO_MODE_AF, .optype=GPIO_OTYPE_PP, .af=GPIO_AF11}, // MDC {.base=GPIOC, .pin=GPIO4, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD0 {.base=GPIOC, .pin=GPIO5, .mode=GPIO_MODE_AF, .af=GPIO_AF11}, // RMII RXD1 }; static struct eth_config eth_config = { .pio_mii = stm32eth_mii_pins, .n_pio_mii = sizeof(stm32eth_mii_pins)/sizeof(struct gpio_config), .pio_phy_reset = {}, .has_phy_reset = 0 }; /* TODO: HS pios */ /* static struct usb_config usb_guest = { .dev_type = USB_DEV_HS, .otg_mode = USB_MODE_GUEST, }; */ int machine_init(void) { int i = 0; rcc_clock_setup_hse_3v3(&rcc_hse_25mhz_3v3); gpio_create(NULL, &gpio_led[0]); gpio_create(NULL, &gpio_led[1]); gpio_create(NULL, &gpio_button); for (i = 0; i < NUM_UARTS; i++) { uart_create(&uart_configs[i]); } rng_create(1, RCC_RNG); sdio_init(&sdio_conf); //usb_init(&usb_guest); ethernet_init(ð_config); return 0; } ================================================ FILE: kernel/string.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent, brabo * */ #include #include void *memset(void *s, int c, size_t n) { unsigned char *d = (unsigned char *)s; while (n--) { *d++ = (unsigned char)c; } return s; } char *strcat(char *dest, const char *src) { int i = 0; int j = strlen(dest); for (i = 0; i < strlen(src); i++) { dest[j++] = src[i]; } dest[j] = '\0'; return dest; } int strcmp(const char *s1, const char *s2) { int diff = 0; while (!diff && *s1) { diff = (int)*s1 - (int)*s2; s1++; s2++; } return diff; } int strcasecmp(const char *s1, const char *s2) { int diff = 0; while (!diff && *s1) { diff = (int)*s1 - (int)*s2; if ((diff == 'A' - 'a') || (diff == 'a' - 'A')) diff = 0; s1++; s2++; } return diff; } size_t strlen(const char *s) { int i = 0; while (s[i] != 0) i++; return i; } char *strncat(char *dest, const char *src, size_t n) { int i = 0; int j = strlen(dest); for (i = 0; i < strlen(src); i++) { if (j >= (n - 1)) { break; } dest[j++] = src[i]; } dest[j] = '\0'; return dest; } int strncmp(const char *s1, const char *s2, size_t n) { int diff = 0; while (n > 0) { diff = (unsigned char)*s1 - (unsigned char)*s2; if (diff || !*s1) break; s1++; s2++; n--; } return diff; } void *memcpy(void *dst, const void *src, size_t n) { int i; const char *s = (const char *)src; char *d = (char *)dst; for (i = 0; i < n; i++) { d[i] = s[i]; } return dst; } char *strncpy(char *dst, const char *src, size_t n) { int i; for (i = 0; i < n; i++) { dst[i] = src[i]; if (src[i] == '\0') break; } return dst; } char *strcpy(char *dst, const char *src) { int i = 0; while(1 < 2) { dst[i] = src[i]; if (src[i] == '\0') break; i++; } return dst; } int memcmp(const void *_s1, const void *_s2, size_t n) { int diff = 0; const unsigned char *s1 = (const unsigned char *)_s1; const unsigned char *s2 = (const unsigned char *)_s2; while (!diff && n) { diff = (int)*s1 - (int)*s2; s1++; s2++; n--; } return diff; } ================================================ FILE: kernel/string.h ================================================ #ifndef FLIBC_STRING_H #define FLIBC_STRING_H #include extern void * memset(void *s, int c, size_t n); extern void *memcpy(void *dst, const void *src, size_t n); extern int memcmp(const void *s1, const void *s2, size_t n); extern int strcmp(const char *s1, const char *s2); extern int strncmp(const char *s1, const char *s2, size_t n); extern char *strcat(char *dest, const char *src); extern char *strncat(char *dest, const char *src, size_t n); extern size_t strlen(const char *s); extern char *strcpy(char *dst, const char *src); char *strncpy(char *dst, const char *src, size_t n); #endif /* FLIBC_STRING_H */ ================================================ FILE: kernel/sys.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "sys/frosted.h" #include "sys/frosted-io.h" #include "sys/reboot.h" #include "lowpower.h" #include #include #ifndef CLOCK_MONOTONIC # define CLOCK_MONOTONIC (4) #endif struct timeval_kernel { /* Assuming newlib time_t is long */ long tv_sec; long tv_usec; }; #ifdef CONFIG_LOWPOWER int sys_suspend_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { if (arg1 > 0) { lowpower_sleep(0, arg1); } return 0; } int sys_standby_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { if (arg1 > 0) { lowpower_sleep(1, arg1); } return 0; } #else int sys_suspend_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { return -ENOSYS; } int sys_standby_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { return -ENOSYS; } #endif #ifndef CONFIG_PTY_UNIX int sys_ptsname_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { return -ENOSYS; } #endif int sys_test_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { return (arg1 + (arg2 << 8)); } int sys_thread_create_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { /* Deprecated. */ return -1; } int sys_thread_join_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { /* Deprecated. */ return -1; } int sys_execb_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { /* Deprecated. */ return -1; } int sys_clock_gettime_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { if (arg2) { struct timeval_kernel *now = (struct timeval_kernel *)arg2; if ((clockid_t)arg1 == CLOCK_MONOTONIC) { now->tv_sec = jiffies / 1000; now->tv_usec = (jiffies % 1000) * 1000; } else if ((clockid_t)arg1 == CLOCK_REALTIME) { now->tv_sec = rt_offset + (jiffies / 1000); now->tv_usec = ((jiffies % 1000) * 1000) * 1000; } } return 0; } int sys_clock_settime_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { if ((clockid_t)arg1 == CLOCK_MONOTONIC) { return -EPERM; } if (arg2 && ((clockid_t)arg1 == CLOCK_REALTIME)) { struct timeval_kernel *now = (struct timeval_kernel *)arg2; unsigned int temp = now->tv_sec; temp = temp + (now->tv_usec / 1000 / 1000); rt_offset = temp - (jiffies / 1000); } return 0; } int sys_reboot_hdlr(uint32_t fadeoff, int cmd, uint32_t interval) { if (fadeoff != SYS_FROSTED_FADEOFF) return -EINVAL; switch(cmd) { case RB_REBOOT: scb_reset_system(); /* Never returns. */ break; case RB_STANDBY: lowpower_sleep(1, interval); break; case RB_SUSPEND: lowpower_sleep(0, interval); return 0; default: return -ENOENT; } return -EFAULT; } struct utsname { char sysname[16]; /* Operating system name (e.g., "Frosted") */ char nodename[16]; /* Name within network */ char release[16]; /* Operating system release (e.g., "16.03") */ char version[16]; /* Operating system version (e.g., "16") */ char machine[16]; /* Hardware identifier */ char domainname[16]; /* NIS or YP domain name */ }; const struct utsname uts_frosted = { "Frosted", "frosted", "16.03", "16", "arm", "local"}; int sys_uname_hdlr( uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { struct utsname *uts = (struct utsname *)arg1; if (!arg1) return -EFAULT; if (task_ptr_valid(uts)) return -EACCES; memcpy(uts, &uts_frosted, sizeof(struct utsname)); return 0; } ================================================ FILE: kernel/syscall_table_gen.py ================================================ #!/usr/bin/python2 # # # # Add your syscalls here # # Syntax: [ "name", number_of_args, "name_of_kernelspace_handler" ] ####### ##### ### # syscalls = [ ["sleep", 2, "sys_sleep_hdlr"], ["ptsname", 3, "sys_ptsname_hdlr"], ["getpid", 0, "sys_getpid_hdlr"], ["getppid", 0, "sys_getppid_hdlr"], ["open", 3, "sys_open_hdlr"], ["close", 1, "sys_close_hdlr"], ["read", 3, "sys_read_hdlr"], ["write", 3, "sys_write_hdlr"], ["seek", 3, "sys_seek_hdlr"], ["mkdir", 2, "sys_mkdir_hdlr"], ["unlink", 1, "sys_unlink_hdlr"], ["malloc", 1, "sys_malloc_hdlr"], ["free", 1, "sys_free_hdlr"], ["calloc", 2, "sys_calloc_hdlr"], ["realloc", 2, "sys_realloc_hdlr"], ["opendir", 1, "sys_opendir_hdlr"], ["readdir", 2, "sys_readdir_hdlr"], ["closedir",1, "sys_closedir_hdlr"], ["stat", 2, "sys_stat_hdlr"], ["poll", 3, "sys_poll_hdlr"], ["ioctl", 3, "sys_ioctl_hdlr"], ["link", 2, "sys_link_hdlr"], ["chdir", 1, "sys_chdir_hdlr"], ["getcwd", 2, "sys_getcwd_hdlr"], ["sem_init", 2, "sys_sem_init_hdlr"], ["sem_post", 1, "sys_sem_post_hdlr"], ["sem_wait", 2, "sys_sem_wait_hdlr"], ["sem_trywait", 1, "sys_sem_trywait_hdlr"], ["sem_destroy", 1, "sys_sem_destroy_hdlr"], ["mutex_init", 0, "sys_mutex_init_hdlr"], ["mutex_unlock", 1, "sys_mutex_unlock_hdlr"], ["mutex_lock", 1, "sys_mutex_lock_hdlr"], ["mutex_destroy", 1, "sys_mutex_destroy_hdlr"], ["socket", 3, "sys_socket_hdlr"], ["bind", 2, "sys_bind_hdlr"], ["accept", 2, "sys_accept_hdlr"], ["connect", 2, "sys_connect_hdlr"], ["listen", 2, "sys_listen_hdlr"], ["sendto", 5, "sys_sendto_hdlr"], ["recvfrom", 5, "sys_recvfrom_hdlr"], ["setsockopt", 5, "sys_setsockopt_hdlr"], ["getsockopt", 5, "sys_getsockopt_hdlr"], ["shutdown", 2, "sys_shutdown_hdlr"], ["dup", 1, "sys_dup_hdlr"], ["dup2", 2, "sys_dup2_hdlr"], ["mount", 5, "sys_mount_hdlr"], ["umount", 2, "sys_umount_hdlr"], ["kill", 2, "sys_kill_hdlr"], ["isatty", 1, "sys_isatty_hdlr"], ["exec", 2, "sys_exec_hdlr"], ["ttyname_r", 3, "sys_ttyname_hdlr"], ["exit", 1, "sys_exit_hdlr"], ["tcsetattr", 3, "sys_tcsetattr_hdlr"], ["tcgetattr", 2, "sys_tcgetattr_hdlr"], ["tcsendbreak", 2, "sys_tcsendbreak_hdlr"], ["pipe2", 2, "sys_pipe2_hdlr"], ["sigaction", 3, "sys_sigaction_hdlr"], ["sigprocmask", 3, "sys_sigprocmask_hdlr"], ["sigsuspend", 1, "sys_sigsuspend_hdlr"], ["vfork", 0, "sys_vfork_hdlr"], ["waitpid", 3, "sys_waitpid_hdlr"], ["lstat", 2, "sys_lstat_hdlr"], ["uname", 1, "sys_uname_hdlr"], ["getaddrinfo", 4, "sys_getaddrinfo_hdlr"], ["freeaddrinfo", 1, "sys_freeaddrinfo_hdlr"], ["fstat", 2, "sys_fstat_hdlr"], ["getsockname", 2, "sys_getsockname_hdlr"], ["getpeername", 2, "sys_getpeername_hdlr"], ["readlink", 3, "sys_readlink_hdlr"], ["fcntl", 3, "sys_fcntl_hdlr"], ["setsid", 0, "sys_setsid_hdlr"], ["ptrace", 4, "sys_ptrace_hdlr"], ["reboot", 3, "sys_reboot_hdlr"], ["getpriority", 2, "sys_getpriority_hdlr"], ["setpriority", 3, "sys_setpriority_hdlr"], ["ftruncate", 2, "sys_ftruncate_hdlr"], ["truncate", 2, "sys_truncate_hdlr"], ["pthread_create", 4, "sys_pthread_create_hdlr"], ["pthread_exit", 1, "sys_pthread_exit_hdlr"], ["pthread_join", 2, "sys_pthread_join_hdlr"], ["pthread_detach", 1, "sys_pthread_detach_hdlr"], ["pthread_cancel", 1, "sys_pthread_cancel_hdlr"], ["pthread_self", 0, "sys_pthread_self_hdlr"], ["pthread_setcancelstate", 2, "sys_pthread_setcancelstate_hdlr"], ["sched_yield", 0, "sys_sched_yield_hdlr"], ["pthread_mutex_init", 2, "sys_pthread_mutex_init_hdlr"], ["pthread_mutex_destroy", 1, "sys_pthread_mutex_destroy_hdlr"], ["pthread_mutex_lock", 1, "sys_pthread_mutex_lock_hdlr"], ["pthread_mutex_trylock", 1, "sys_pthread_mutex_trylock_hdlr"], ["pthread_mutex_unlock", 1, "sys_pthread_mutex_unlock_hdlr"], ["pthread_kill", 2, "sys_pthread_kill_hdlr"], ["clock_settime", 2, "sys_clock_settime_hdlr"], ["clock_gettime", 2, "sys_clock_gettime_hdlr"], ["pthread_key_create", 2, "sys_pthread_key_create_hdlr"], ["pthread_setspecific", 2, "sys_pthread_setspecific_hdlr"], ["pthread_getspecific", 2, "sys_pthread_getspecific_hdlr"], ["alarm", 1, "sys_alarm_hdlr"], ["ualarm", 2, "sys_ualarm_hdlr"], ] # ### ##### ####### ################################################################# hdr = open("kernel/frosted-headers/include/sys/frosted.h", "w") usercode = open("kernel/frosted-headers/sys/frosted_syscalls.c", "w") code = open("kernel/syscall_table.c", "w") hdr.write("/* The file frosted.h is auto generated. DO NOT EDIT, CHANGES WILL BE LOST. */\n/* If you want to add syscalls, use syscall_table_gen.py */\n\n") usercode.write("/* The file frosted_syscalls.c is auto generated. DO NOT EDIT, CHANGES WILL BE LOST. */\n/* If you want to add syscalls, use syscall_table_gen.py */\n\n#include \n#include \"sys/frosted.h\"\n") code.write("/* The file syscall_table.c is auto generated. DO NOT EDIT, CHANGES WILL BE LOST. */\n/* If you want to add syscalls, use syscall_table_gen.py */\n\n#include \"frosted.h\"\n#include \"sys/frosted.h\"\n") for n in range(len(syscalls)): name = syscalls[n][0] hdr.write("#define SYS_%s \t\t\t(%d)\n" % (name.upper(), n)) hdr.write("#define _SYSCALLS_NR (%d) /* We have %d syscalls! */\n" % (len(syscalls), len(syscalls))) for n in range(len(syscalls)): name = syscalls[n][0] tp = syscalls[n][1] usercode.write( "/* Syscall: %s(%d arguments) */\n" % (name, tp)) if (tp == 0): usercode.write( "int sys_%s(void){\n" % name) usercode.write( " return syscall(SYS_%s, 0, 0, 0, 0, 0); \n" % name.upper()) usercode.write( "}\n") usercode.write("\n") if (tp == 1): usercode.write( "int sys_%s(uint32_t arg1){\n" % name) usercode.write( " return syscall(SYS_%s, arg1, 0, 0, 0, 0); \n" % name.upper()) usercode.write( "}\n") usercode.write("\n") if (tp == 2): usercode.write( "int sys_%s(uint32_t arg1, uint32_t arg2){\n" % name) usercode.write( " return syscall(SYS_%s, arg1, arg2, 0, 0, 0); \n" % name.upper()) usercode.write( "}\n") usercode.write("\n") if (tp == 3): usercode.write( "int sys_%s(uint32_t arg1, uint32_t arg2, uint32_t arg3){\n" % name) usercode.write( " return syscall(SYS_%s, arg1, arg2, arg3, 0, 0); \n" % name.upper()) usercode.write( "}\n") usercode.write("\n") if (tp == 4): usercode.write( "int sys_%s(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4){\n" % name) usercode.write( " return syscall(SYS_%s, arg1, arg2, arg3, arg4, 0); \n" % name.upper()) usercode.write( "}\n") usercode.write("\n") if (tp == 5): usercode.write( "int sys_%s(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5){\n" % name) usercode.write( " return syscall(SYS_%s, arg1, arg2, arg3, arg4, arg5); \n" % name.upper()) usercode.write( "}\n") usercode.write("\n") usercode.close() code.write("/* External handlers (defined elsewhere) : */ \n") for n in range(len(syscalls)): name = syscalls[n][0] call = syscalls[n][2] code.write( "extern int %s(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);\n" % call) code.write("\n") code.write("void syscalls_init(void) {\n") for n in range(len(syscalls)): call = syscalls[n][2] code.write( "\tsys_register_handler(%d, %s);\n" % (n, call) ); code.write("}\n") code.close() ================================================ FILE: kernel/syscall_vector.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include /* Syscall table Vector array */ extern int sys_setclock( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_sleep( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_suspend( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_thread_create( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_thread_join( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_test( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_getpid( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_getppid( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_open( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_close( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_read( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_write( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_seek( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_mkdir( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_unlink( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_gettimeofday( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_malloc( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_mem_init( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_free( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_calloc( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_realloc( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_opendir( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_readdir( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_closedir( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_stat( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_poll( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_ioctl( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_link( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_chdir( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_getcwd( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_sem_init( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_sem_post( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_sem_wait( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_sem_destroy( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_mutex_init( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_mutex_unlock( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_mutex_lock( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_mutex_destroy( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_socket( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_bind( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_accept( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_connect( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_listen( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_sendto( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_recvfrom( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_setsockopt( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_getsockopt( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_shutdown( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_dup( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_dup2( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_mount( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_umount( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_kill( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_isatty( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_exec( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_ttyname_r( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_exit( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_tcsetattr( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_tcgetattr( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_tcsendbreak( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); extern int sys_pipe2( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ); int __attribute__((used,section(".syscall_vector"))) (* const _k__syscall__[61])( uint32_t, uint32_t, uint32_t, uint32_t, uint32_t ) = { sys_setclock, sys_sleep, sys_suspend, sys_thread_create, sys_thread_join, sys_test, sys_getpid, sys_getppid, sys_open, sys_close, sys_read, sys_write, sys_seek, sys_mkdir, sys_unlink, sys_gettimeofday, sys_malloc, sys_mem_init, sys_free, sys_calloc, sys_realloc, sys_opendir, sys_readdir, sys_closedir, sys_stat, sys_poll, sys_ioctl, sys_link, sys_chdir, sys_getcwd, sys_sem_init, sys_sem_post, sys_sem_wait, sys_sem_destroy, sys_mutex_init, sys_mutex_unlock, sys_mutex_lock, sys_mutex_destroy, sys_socket, sys_bind, sys_accept, sys_connect, sys_listen, sys_sendto, sys_recvfrom, sys_setsockopt, sys_getsockopt, sys_shutdown, sys_dup, sys_dup2, sys_mount, sys_umount, sys_kill, sys_isatty, sys_exec, sys_ttyname_r, sys_exit, sys_tcsetattr, sys_tcgetattr, sys_tcsendbreak, sys_pipe2 }; ================================================ FILE: kernel/systick.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "heap.h" #include "lowpower.h" #include "unicore-mx/cm3/nvic.h" #include "unicore-mx/cm3/systick.h" #include "unicore-mx/cm3/scb.h" #define SEV() asm volatile ("sev") #ifdef NRF51 #include "unicore-mx/nrf/51/ostick.h" #endif volatile unsigned int jiffies = 0u; volatile unsigned int _n_int = 0u; volatile int ktimer_check_pending = 0; volatile int sleep_mode = 0; static int _sched_active = 0; void frosted_scheduler_on(void) { nvic_set_priority(NVIC_PENDSV_IRQ, 2); nvic_set_priority(NVIC_SV_CALL_IRQ, 1); #ifdef CUSTOM_SYSTICK ostick_init(1, &sys_tick_handler); ostick_start(); #else nvic_set_priority(NVIC_SYSTICK_IRQ, 0); nvic_enable_irq(NVIC_SYSTICK_IRQ); systick_counter_enable(); systick_interrupt_enable(); #endif _sched_active = 1; } void frosted_scheduler_off(void) { _sched_active = 0; } void __attribute__((weak)) SysTick_Hook(void) { } typedef struct ktimer { uint32_t expire_time; void *arg; void (*handler)(uint32_t time, void *arg); } ktimer; DECLARE_HEAP(ktimer, expire_time); static struct heap_ktimer *ktimer_list = NULL; /* Init function */ void ktimer_init(void) { ktimer_list = heap_init(); } /* Add kernel timer */ int ktimer_add(uint32_t count, void (*handler)(uint32_t, void *), void *arg) { struct ktimer t; int ret; memset(&t, 0, sizeof(t)); t.expire_time = jiffies + count; t.handler = handler; t.arg = arg; if (!task_in_syscall()) irq_off(); ret = heap_insert(ktimer_list, &t); if (!task_in_syscall()) irq_on(); return ret; } /* Delete kernel timer */ int ktimer_del(int tid) { int ret; if (tid < 0) return -1; if (!task_in_syscall()) irq_off(); ret = heap_delete(ktimer_list, tid); if (!task_in_syscall()) irq_on(); return ret; } static inline int ktimer_expired(void) { struct ktimer *t; return ((ktimer_list) && (ktimer_list->n > 0) && (t = heap_first(ktimer_list)) && (t->expire_time < jiffies)); } /* Tasklet that checks expired timers */ static void ktimers_check_tasklet(void *arg) { struct ktimer *t; struct ktimer t_previous; int next_t; uint32_t this_timeslice; next_t = -1; if ((ktimer_list) && (ktimer_list->n > 0)) { irq_off(); t = heap_first(ktimer_list); irq_on(); while ((t) && (t->expire_time < jiffies)) { if (t->handler) { t->handler(jiffies, t->arg); } irq_off(); heap_peek(ktimer_list, &t_previous); t = heap_first(ktimer_list); irq_on(); } next_t = (t->expire_time - jiffies); } ktimer_check_pending = 0; } void sys_tick_handler(void) { uint32_t next_timer = 0; volatile uint32_t reload = systick_get_reload(); uint32_t this_timeslice; SysTick_Hook(); jiffies ++; _n_int++; if (ktimer_expired()) { task_preempt_all(); goto end; } if (_sched_active && ((task_timeslice() == 0) || (!task_running()))) { schedule(); (void)next_timer; } end: if (!ktimer_check_pending) { ktimer_check_pending++; tasklet_add(ktimers_check_tasklet, NULL); } } ================================================ FILE: kernel/tasklet.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "unicore-mx/cm3/systick.h" #define MAX_TASKLETS 64 struct tasklet { void (*exe)(void *); void *arg; }; static struct tasklet tasklet_array[MAX_TASKLETS]; uint32_t n_tasklets = 0; uint32_t max_tasklets = 0; void tasklet_add(void (*exe)(void*), void *arg) { int i; if (!task_in_syscall()) irq_off(); for (i = 0; i < MAX_TASKLETS; i++) { if (!tasklet_array[i].exe) { tasklet_array[i].exe = exe; tasklet_array[i].arg = arg; n_tasklets++; if (n_tasklets > max_tasklets) max_tasklets = n_tasklets; if (!task_in_syscall()) irq_on(); return; } } while(1) { /* Too many tasklets. */; } } void check_tasklets(void) { int i; if (n_tasklets == 0) return; irq_off(); for (i = 0; i < MAX_TASKLETS; i++) { if (tasklet_array[i].exe) { tasklet_array[i].exe(tasklet_array[i].arg); tasklet_array[i].exe = NULL; tasklet_array[i].arg = NULL; n_tasklets--; } } irq_on(); } ================================================ FILE: kernel/term.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include #include static struct module *get_term_mod(int td) { struct fnode *f = task_filedesc_get(td); if (f) return f->owner; return NULL; } int sys_tcgetattr_hdlr(int arg1, int arg2) { struct termios *t = (struct termios *)arg2; struct module *m; if (task_ptr_valid(t)) return -EACCES; m = get_term_mod(arg1); if (m && m->ops.tcgetattr) return m->ops.tcgetattr(arg1, t); else return -EOPNOTSUPP; } int sys_tcsetattr_hdlr(int arg1, int arg2, int arg3) { const struct termios *t = (const struct termios *)arg3; struct module *m; if (task_ptr_valid(t)) return -EACCES; m = get_term_mod(arg1); if (m && m->ops.tcsetattr) return m->ops.tcsetattr(arg1, arg2, t); else return -EOPNOTSUPP; } int sys_tcsendbreak_hdlr(int arg1, int arg2) { /* TODO: send SIGINT to self. */ return -EOPNOTSUPP; } ================================================ FILE: kernel/vfs.c ================================================ /* * This file is part of frosted. * * frosted is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * * frosted 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 frosted. If not, see . * * Authors: Daniele Lacamera, Maxime Vincent * */ #include "frosted.h" #include "vfs.h" #include "string.h" #include "scheduler.h" #include "sys/stat.h" #define O_MODE(o) ((o & O_ACCMODE)) #define O_BLOCKING(f) ((f->flags & O_NONBLOCK) == 0) struct mountpoint *MTAB = NULL; /* ROOT entity ("/") *. */ static struct fnode FNO_ROOT = { }; static void basename_r(const char *path, char *res) { char *p; strncpy(res, path, strlen(path) + 1); p = res + strlen(res) - 1; while (p >= res) { if (*p == '/') { *p = '\0'; break; } p--; } if (strlen(res) == 0) { res[0] = '/'; res[1] = '\0'; } } static char *filename(char *path) { int len = strlen(path); char *p = path + len - 1; while (p >= path) { if (*p == '/') return (p + 1); p--; } return path; } static struct fnode *_fno_search(const char *path, struct fnode *dir, int follow); static int _fno_fullpath(struct fnode *f, char *dst, char **p, int len) { int nlen; if (!f) return -EINVAL; if ((f->flags & FL_LINK) == FL_LINK) { f = _fno_search(f->linkname, &FNO_ROOT, 1); } if (f == &FNO_ROOT) { *p = dst + 1; dst[0] = '/'; dst[1] = '\0'; return 0; } if (!*p) { if (!f->parent) return -EINVAL; // what to do, how is this possible? _fno_fullpath(f->parent, dst, p, len); } nlen = strlen(f->fname); if (nlen + (*p - dst) > (len -1)) return -ENAMETOOLONG; memcpy(*p, f->fname, nlen); *p += nlen; *(*p) = '/'; *p += 1; *(*p + 1) = '\0'; return 0; } int fno_fullpath(struct fnode *f, char *dst, int len) { char *p = NULL; int ret; ret = _fno_fullpath(f, dst, &p, len); if (ret == 0) { int nlen = strlen(dst); if (nlen > 1) { /* Remove trailing "/" */ dst[--nlen] = '\0'; while (dst[nlen - 1] == '/') { dst[nlen - 1] = '\0'; nlen--; } } return nlen; } return -ENOENT; } static int path_abs(char *src, char *dst, int len) { struct fnode *f = task_getcwd(); if (src[0] == '/') strncpy(dst, src, len); else { if (fno_fullpath(f, dst, len) > 0) { while (dst[strlen(dst) - 1] == '/') dst[strlen(dst) - 1] = '\0'; strncat(dst, "/", len); strncat(dst, src, len); return 0; } } return 0; } static struct fnode *fno_create_file(char *path) { char *base = kalloc(strlen(path) + 1); struct module *owner = NULL; struct fnode *parent; struct fnode *f = NULL; if (!base) return NULL; basename_r(path, base); parent = fno_search(base); kfree(base); if (!parent) return NULL; if ((parent->flags & FL_DIR) == 0) return NULL; if (parent) { owner = parent->owner; } f = fno_create(owner, filename(path), parent); if (f) f->flags = 0; return f; } static struct fnode *fno_link(char *src, char *dst) { struct fnode *file; struct fnode *link; int file_name_len; char p_src[MAX_FILE]; char p_dst[MAX_FILE]; path_abs(src, p_src, MAX_FILE); path_abs(dst, p_dst, MAX_FILE); file = fno_search(p_src); if (!file) return NULL; link = fno_create_file(p_dst); if (!link) return NULL; file_name_len = strlen(p_src); link->flags |= FL_LINK; link->linkname = kalloc(file_name_len + 1); if (!link->linkname) { fno_unlink(link); return NULL; } strncpy(link->linkname, p_src, file_name_len + 1); return link; } int vfs_symlink(char *file, char *link) { if (fno_link(file, link) != NULL) return 0; else return -EINVAL; } static void mkdir_links(struct fnode *fno) { char path[MAX_FILE], selfl[MAX_FILE], parentl[MAX_FILE], path_basename[MAX_FILE]; fno_fullpath(fno, path, MAX_FILE -4); strcpy(selfl, path); strcpy(parentl, path); strcat(selfl, "/."); strcat(parentl, "/.."); if (fno) { fno_link(path, selfl); basename_r(path, path_basename); fno_link(path_basename, parentl); } } static struct fnode *fno_create_dir(char *path, uint32_t flags) { struct fnode *fno = fno_create_file(path); if (fno) { fno->flags |= (FL_DIR | flags); } mkdir_links(fno); return fno; } static const char *path_walk(const char *path) { const char *p = path; if (*p == '/') { while(*p == '/') p++; return p; } while ((*p != '\0') && (*p != '/')) p++; if (*p == '/') p++; if (*p == '\0') return NULL; return p; } /* Returns: * 0 = if path does not match * 1 = if path is in the right dir, need to walk more * 2 = if path is found! */ static int path_check(const char *path, const char *dirname) { int i = 0; for (i = 0; dirname[i]; i++) { if (path[i] != dirname[i]) return 0; } if (path[i] == '\0') return 2; if (path[i] == '/') return 1; if (i > 0 && (path[i - 1] == '/' && dirname[i - 1] == '/')) return 1; return 0; } static struct fnode *_fno_search(const char *path, struct fnode *dir, int follow) { struct fnode *cur; char link[MAX_FILE]; int check = 0; if (dir == NULL) return NULL; check = path_check(path, dir->fname); /* Does not match, try another item */ if (check == 0) { if (!dir->next) return NULL; return _fno_search(path, dir->next, follow); } /* Item is found! */ if (check == 2) { /* If it's a symlink, restart check */ if (follow && ((dir->flags & FL_LINK) == FL_LINK)) { return _fno_search(dir->linkname, &FNO_ROOT, 1); } return dir; } /* path is correct, need to walk more */ if( (dir->flags & FL_LINK ) == FL_LINK ){ /* passing through a symlink */ strcpy( link, dir->linkname ); strcat( link, "/" ); strcat( link, path_walk(path)); return _fno_search( link, &FNO_ROOT, follow ); } return _fno_search(path_walk(path), dir->children, follow); } struct fnode *fno_search(const char *_path) { int i, len; struct fnode *fno = NULL; char *path = NULL; if (!_path) return NULL; len = strlen(_path); if (!len) return NULL; path = kcalloc(len + 1, 1); if (!path) return NULL; memcpy(path, _path, len + 1); i = len - 1; while (i > 0) { if (path[i] == '/') path[i] = '\0'; else break; --i; } if (strlen(path) > 0) { fno = _fno_search(path, &FNO_ROOT, 1); } kfree(path); return fno; } struct fnode *fno_search_nofollow(const char *path) { return _fno_search(path, &FNO_ROOT, 0); } static struct fnode *_fno_create(struct module *owner, const char *name, struct fnode *parent) { struct fnode *fno = kcalloc(sizeof(struct fnode), 1); int nlen = strlen(name); if (!fno) return NULL; fno->fname = kalloc(nlen + 1); if (!fno->fname){ kfree(fno); return NULL; } memcpy(fno->fname, name, nlen + 1); if (!parent) { parent = &FNO_ROOT; } fno->parent = parent; fno->next = fno->parent->children; fno->parent->children = fno; fno->children = NULL; fno->owner = owner; return fno; } struct fnode *fno_create(struct module *owner, const char *name, struct fnode *parent) { struct fnode *fno = _fno_create(owner, name, parent); if (fno && parent && parent->owner && parent->owner->ops.creat) parent->owner->ops.creat(fno); fno->flags |= FL_RDWR; return fno; } struct fnode *fno_create_wronly(struct module *owner, const char *name, struct fnode *parent) { struct fnode *fno = _fno_create(owner, name, parent); if (fno && parent && parent->owner && parent->owner->ops.creat) parent->owner->ops.creat(fno); fno->flags = FL_WRONLY; return fno; } struct fnode *fno_create_rdonly(struct module *owner, const char *name, struct fnode *parent) { struct fnode *fno = _fno_create(owner, name, parent); if (fno && parent && parent->owner && parent->owner->ops.creat) parent->owner->ops.creat(fno); fno->flags = FL_RDONLY; return fno; } struct fnode *fno_mkdir(struct module *owner, const char *name, struct fnode *parent) { struct fnode *fno = _fno_create(owner, name, parent); fno->flags |= (FL_DIR | FL_RDWR); if (parent && parent->owner && parent->owner->ops.creat) parent->owner->ops.creat(fno); mkdir_links(fno); return fno; } void fno_unlink(struct fnode *fno) { struct fnode *dir; if (!fno) return; dir = fno->parent; if (fno && fno->owner && fno->owner->ops.unlink) fno->owner->ops.unlink(fno); if (!fno) return; if (dir) { struct fnode *child = dir->children; while (child) { if (child == fno) { dir->children = fno->next; break; } if (child->next == fno) { child->next = fno->next; break; } child = child->next; } } kfree(fno->fname); kfree(fno); } int sys_readlink_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { char *path = (char*)arg1; char *buf = (char*)arg2; size_t size = (size_t)arg3; int len; char abs_p[MAX_FILE]; struct fnode *fno; if(!buf) return -EINVAL; if (task_ptr_valid(buf) || task_ptr_valid(path)) return -EACCES; path_abs(path, abs_p, MAX_FILE); fno = fno_search_nofollow(abs_p); if(!fno) return -ENOENT; else if (fno->flags & FL_LINK) strncpy(buf, fno->linkname, size); else return -EINVAL; len = strlen(fno->linkname); return len < size ? len : size; } int sys_exec_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { char *path = (char *)arg1; char *arg = (char *)arg2; struct fnode *f; struct vfs_info *vfsi = NULL; if (task_ptr_valid(arg) || task_ptr_valid(path)) return -EACCES; f = fno_search(path); if (f && f->owner && (f->flags & FL_EXEC) && f->owner->ops.exe) { vfsi = (struct vfs_info *)f->owner->ops.exe(f, arg); if (vfsi) scheduler_exec(vfsi, arg); } return -EINVAL; } int sys_open_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { char *rel_path = (char *)arg1; struct fnode *f; uint32_t flags = arg2; char path[MAX_FILE]; int ret; if (task_ptr_valid(rel_path)) return -EACCES; path_abs(rel_path, path, MAX_FILE); f = fno_search(path); if (f && f->owner && f->owner->ops.open) { if ((O_MODE(flags) != O_RDONLY) && ((f->flags & FL_WRONLY)== 0)) return -EPERM; ret = f->owner->ops.open(path, flags); if (ret >= 0) { task_fd_setmask(ret, flags); task_fd_set_flags(ret, flags); task_fd_set_off(f, 0); } return ret; } if ((flags & O_CREAT) == 0) { f = fno_search(path); } else { if ((O_MODE(flags)) == O_RDONLY) return -EPERM; f = fno_search(path); if (flags & O_EXCL) { if (f != NULL) return -EEXIST; } if (f && (flags & O_TRUNC)) { if (f) { fno_unlink(f); f = NULL; } } if (!f) f = fno_create_file(path); /* TODO: Parse arg3 & 0x1c0 for permissions */ if (f) { f->flags |= FL_RDWR; if (f && f->owner && f->owner->ops.open) { if ((O_MODE(flags) != O_RDONLY) && ((f->flags & FL_WRONLY)== 0)) return -EPERM; ret = f->owner->ops.open(path, flags); if (ret >= 0) { task_fd_setmask(ret, flags); task_fd_set_flags(ret, flags); task_fd_set_off(f, 0); } return ret; } } } if (f == NULL) return -ENOENT; if (f->flags & FL_INUSE) return -EBUSY; if (f->flags & FL_DIR) return -EISDIR; ret = task_filedesc_add(f); task_fd_setmask(ret, flags); task_fd_set_flags(ret,flags); task_fd_set_off(f, 0); if (flags & O_APPEND) task_fd_set_off(f, f->size); return ret; } int sys_close_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { struct fnode *f = task_filedesc_get(arg1); if (f != NULL) { if (f->owner->ops.close) { f->owner->ops.close(f); } task_filedesc_del(arg1); return 0; } return -EINVAL; } int sys_seek_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { struct fnode *fno = task_filedesc_get(arg1); if (!fno) return -EINVAL; if (fno->owner->ops.seek) { return fno->owner->ops.seek(fno, arg2, arg3); } else return -EOPNOTSUPP; } int sys_ioctl_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { struct fnode *fno = task_filedesc_get(arg1); if (!fno) return -EINVAL; if (fno->owner->ops.ioctl) { fno->owner->ops.ioctl(fno, (uint32_t)arg2, (void *)arg3); } else return -EOPNOTSUPP; } int sys_link_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { struct fnode *fno; if (task_ptr_valid((void*)arg1) || task_ptr_valid((void*)arg2)) return -EACCES; fno = fno_link((char*)arg1, (char *)arg2); if (fno) return 0; else return -EINVAL; } int sys_mkdir_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { char *path = (char *)arg1; char abs_p[MAX_FILE]; struct fnode *f; if (task_ptr_valid(path)) return -EACCES; path_abs(path, abs_p, MAX_FILE); if (fno_create_dir(abs_p, arg2)) return 0; return -ENOENT; } int sys_unlink_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { char *path = (char *)arg1; char abs_p[MAX_FILE]; struct fnode *f; if (task_ptr_valid(path)) return -EACCES; path_abs(path, abs_p, MAX_FILE); f = fno_search_nofollow(abs_p); /* Don't follow symlink */ if (f) { fno_unlink(f); return 0; } return -ENOENT; } int sys_opendir_hdlr(uint32_t arg1) { struct fnode *fno; if (task_ptr_valid((void*)arg1)) return -EACCES; fno = fno_search((char *)arg1); if (fno && (fno->flags & FL_DIR)) { if (fno->flags & FL_INUSE) return (int)NULL; /* XXX EBUSY */ /* Use .off to store current readdir ptr */ fno->dir_ptr = (int)fno->children; fno->flags |= FL_INUSE; return (int)fno; } else { return (int)NULL; } } int sys_readdir_hdlr(uint32_t arg1, uint32_t arg2) { struct fnode *fno; struct fnode *next; struct dirent *ep; fno = (struct fnode *)arg1; ep = (struct dirent *)arg2; if (task_ptr_valid(ep)) return -EACCES; next = (struct fnode *)fno->dir_ptr; if (!fno || !ep) return -ENOENT; if (!next) { return -1; } fno->dir_ptr = (int)next->next; ep->d_ino = 0; /* TODO: populate with inode? */ strncpy(ep->d_name, next->fname, 256); return 0; } int sys_closedir_hdlr(uint32_t arg1) { struct fnode *fno = (struct fnode *)arg1; fno->dir_ptr = 0; fno->flags &= ~(FL_INUSE); return 0; } static int stat_hdlr(char *path, struct stat *st) { char abs_p[MAX_FILE]; struct fnode *fno; path_abs(path, abs_p, MAX_FILE); fno = fno_search_nofollow(abs_p); if (!fno) return -ENOENT; if (fno->flags & FL_DIR) { st->st_mode = S_IFDIR; st->st_size = 0; } else if (fno->flags & FL_TTY) { st->st_mode = S_IFCHR; st->st_size = 0; } else if (fno->flags & FL_BLK) { st->st_mode = S_IFBLK; st->st_size = 0; } else if (fno->flags & FL_LINK) { return stat_hdlr(fno->linkname, st); /* Stat follows symlink */ } else { st->st_mode = S_IFREG; st->st_size = fno->size; } if (fno->flags & FL_EXEC) { st->st_mode |= P_EXEC; } return 0; } int sys_stat_hdlr(char *arg1, struct stat *arg2) { char *path = arg1; struct stat *st = arg2; if (task_ptr_valid(path) || task_ptr_valid(st)) return -EACCES; return stat_hdlr(path, st); } int sys_fstat_hdlr(uint32_t arg1, struct stat *arg2) { struct stat *st = arg2; struct fnode *fno = task_filedesc_get(arg1); if (!fno) return -ENOENT; if (task_ptr_valid(st)) return -EACCES; if (fno->flags & FL_DIR) { st->st_mode = S_IFDIR; st->st_size = 0; } else if (fno->flags & FL_LINK) { return stat_hdlr(fno->linkname, st); /* Stat follows symlink */ } else { st->st_mode = S_IFREG; st->st_size = fno->size; } if (fno->flags & FL_EXEC) { st->st_mode |= P_EXEC; } return 0; } int sys_lstat_hdlr(char *arg1, struct stat *arg2) { char *path = arg1; struct stat *st = arg2; char abs_p[MAX_FILE]; struct fnode *fno; if (task_ptr_valid(st) || task_ptr_valid(path)) return -EACCES; path_abs(path, abs_p, MAX_FILE); fno = fno_search_nofollow(abs_p); if (!fno) return -ENOENT; if (fno->flags & FL_DIR) { st->st_mode = S_IFDIR; st->st_size = 0; } else if (fno->flags & FL_TTY) { st->st_mode = S_IFCHR; st->st_size = 0; } else if (fno->flags & FL_BLK) { st->st_mode = S_IFBLK; st->st_size = 0; } else if (fno->flags & FL_LINK) { st->st_mode = S_IFLNK; /* lstat gives info about the link itself */ st->st_size = 0; } else { st->st_mode = S_IFREG; st->st_size = fno->size; } if (fno->flags & FL_EXEC) { st->st_mode |= P_EXEC; } return 0; } int vfs_truncate(struct fnode *fno, unsigned size) { if (!fno) return -ENOENT; if ((fno->flags & FL_WRONLY) == 0) return -EPERM; if (!fno->owner || !fno->owner->ops.truncate) return -EOPNOTSUPP; return fno->owner->ops.truncate(fno, size); } int sys_ftruncate_hdlr(uint32_t arg1, unsigned arg2) { struct fnode *fno = task_filedesc_get(arg1); return vfs_truncate(fno, arg2); } int sys_truncate_hdlr(char *arg1, unsigned arg2) { char abs_p[MAX_FILE]; struct fnode *fno; if (task_ptr_valid((void*)arg1)) return -EACCES; path_abs(arg1, abs_p, MAX_FILE); fno = fno_search(abs_p); return vfs_truncate(fno, arg2); } int sys_chdir_hdlr(char *arg1) { char *path = arg1; char abs_p[MAX_FILE]; struct fnode *f; if (task_ptr_valid(path)) return -EACCES; path_abs(path, abs_p, MAX_FILE); f = fno_search(abs_p); if (!f || (!(f->flags & FL_DIR))) return -ENOTDIR; task_chdir(f); return 0; } int sys_isatty_hdlr(uint32_t arg1) { struct fnode *f = task_filedesc_get(arg1); if (f && f->flags & FL_TTY) return 1; return 0; } int sys_ttyname_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3) { struct fnode *f = task_filedesc_get(arg1); if (task_ptr_valid((void*)arg2)) return -EACCES; if (f && f->flags & FL_TTY) { strncpy((char *)arg2, f->fname, arg3); return 0; } return -EBADF; } int sys_getcwd_hdlr(uint32_t arg1, uint32_t arg2) { char *path = (char *)arg1; int len = (int)arg2; if (task_ptr_valid(path)) return -EACCES; if (fno_fullpath(task_getcwd(), path, len) > 0) return arg1; return 0; } void __attribute__((weak)) devnull_init(struct fnode *dev) { } void __attribute__((weak)) memfs_init(void) { } void __attribute__((weak)) xipfs_init(void) { } void __attribute__((weak)) sysfs_init(void) { } void __attribute__((weak)) fatfs_init(void) { } void __attribute__((weak)) devgpio_init(struct fnode *dev) { } void __attribute__((weak)) devuart_init(struct fnode *dev) { } void __attribute__((weak)) devspi_init(struct fnode *dev) { } int vfs_mount(char *source, char *target, char *module, uint32_t flags, void *args) { struct module *m; if (!module || !target) return -ENOMEDIUM; m = module_search(module); if (!m || !m->mount) return -EOPNOTSUPP; if (m->mount(source, target, flags, args) == 0) { struct mountpoint *mp = kalloc(sizeof(struct mountpoint)); if (mp) { mp->target = fno_search(target); mp->next = MTAB; MTAB = mp; } return 0; } return -ENOENT; } int vfs_umount(char *target, uint32_t flags) { struct fnode *f; int ret; struct mountpoint *mp = MTAB, *prev = NULL; if (!target) return -ENOENT; f = fno_search(target); if (!f || !f->owner || !f->owner->umount) return -ENOMEDIUM; ret = f->owner->umount(target, flags); if (ret < 0) return ret; while (mp) { if (mp->target == f) { if (!prev) { MTAB = mp->next; break; } else { prev->next = mp; } kfree(mp); } prev = mp; mp = mp->next; } return 0; } int sys_mount_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { char *source = (char *)arg1; char *target = (char *)arg2; char *module = (char *)arg3; uint32_t flags = arg4; void *args = (void*)arg5; if (task_ptr_valid((void*)arg1) || task_ptr_valid((void*)arg2)|| task_ptr_valid((void*)arg3)|| (arg5 && task_ptr_valid((void*)arg5))) return -EACCES; return vfs_mount(source, target, module, flags, args); } int sys_umount_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5) { if (task_ptr_valid((void*)arg1)) return -EACCES; char *target = (char *)arg1; uint32_t flags = arg2; return vfs_umount(target, flags); } int sys_fcntl_hdlr(uint32_t arg1, uint32_t arg2, uint32_t arg3) { int fd = arg1; int cmd = arg2; uint32_t fl_set = arg3; struct fnode *f = task_filedesc_get(arg1); if (!f) { return -EINVAL; } if (cmd == F_SETFL) { f->flags |= fl_set; } else if (cmd == F_GETFL) { return f->flags; } return 0; } void vfs_init(void) { struct fnode *dev = NULL; /* Initialize "/" */ FNO_ROOT.owner = NULL; FNO_ROOT.fname = "/"; FNO_ROOT.parent = &FNO_ROOT; FNO_ROOT.children = NULL; FNO_ROOT.next = NULL ; FNO_ROOT.flags = FL_DIR | FL_RDWR; /* Init "/dev" dir */ fno_mkdir(NULL, "dev", NULL); /* Init "/sys" dir */ fno_mkdir(NULL, "sys", NULL); /* Init "/tmp" dir */ fno_mkdir(NULL, "tmp", NULL); /* Init "/bin" dir */ fno_mkdir(NULL, "bin", NULL); /* Init "/mnt" dir */ fno_mkdir(NULL, "mnt", NULL); } ================================================ FILE: kernel/vfs.h ================================================ #ifndef INC_VFS #define INC_VFS #define VFS_TYPE_BIN (0) /* flat binary */ #define VFS_TYPE_BFLT (1) /* bFLT binary */ struct vfs_info { int type; int pic; void (*init)(void *); void * allocated; uint32_t text_size; uint32_t data_size; }; #endif /* INC_VFS */ ================================================ FILE: qemu.gdbinit ================================================ tar ext :3333 layout src file kernel.elf stepi focus c ================================================ FILE: rules/arch.mk ================================================ ###### STACK SIZE ####### ifeq ($(TASK_STACK_SIZE_1K),y) TASK_STACK_SIZE=1024 endif ifeq ($(TASK_STACK_SIZE_2K),y) TASK_STACK_SIZE=2048 endif ifeq ($(TASK_STACK_SIZE_4K),y) TASK_STACK_SIZE=4096 endif ifeq ($(TASK_STACK_SIZE_8K),y) TASK_STACK_SIZE=8192 endif ######################### #Target flags CROSS_COMPILE?=arm-frosted-eabi- CC:=$(CROSS_COMPILE)gcc AS:=$(CROSS_COMPILE)as AR:=$(CROSS_COMPILE)ar CFLAGS+=-mthumb -mlittle-endian -mthumb-interwork -DCORE_M3 -fno-builtin -ffreestanding -DSYS_CLOCK=$(SYS_CLOCK) -DCORTEX_M3 -DFROSTED CFLAGS+=-Ikernel/unicore-mx/include -Ikernel -Iinclude -Ikernel/drivers -I. -Ikernel/frosted-headers/include PREFIX:=$(PWD)/build LDFLAGS:=-Wl,-gc-sections -nostartfiles -L$(PREFIX)/lib CFLAGS+=-mthumb -mlittle-endian -mthumb-interwork CFLAGS+=-DCORE_M3 -DBOARD_$(BOARD) -D$(ARCH) -mcpu=$(MCPU) CFLAGS+=-DCONFIG_KMEM_SIZE=$(KMEM_SIZE) CFLAGS+=-DCONFIG_TASK_STACK_SIZE=$(TASK_STACK_SIZE) # KERNEL DEBUG CFLAGS-$(KLOG)+=-DCONFIG_KLOG CFLAGS+=-DCONFIG_KLOG_SIZE=$(KLOG_SIZE) CFLAGS-$(HARDFAULT_DBG)+=-DCONFIG_HARDFAULT_DBG CFLAGS-$(MEMFAULT_DBG)+=-DCONFIG_EXTENDED_MEMFAULT CFLAGS-$(STRACE)+=-DCONFIG_SYSCALL_TRACE #PTHREADS CFLAGS-$(PTHREADS)+=-DCONFIG_PTHREADS # IPC CFLAGS-$(PIPE)+=-DCONFIG_PIPE CFLAGS-$(SIGNALS)+=-DCONFIG_SIGNALS #MPU CFLAGS-$(MPU)+=-DCONFIG_MPU #GCC Optimizations CFLAGS-$(GDB_CFLAG)+=-ggdb3 CFLAGS-$(OPTIMIZE_NONE)+=-O0 CFLAGS-$(OPTIMIZE_SIZE)+=-Os CFLAGS-$(OPTIMIZE_PERF)+=-O3 CFLAGS+=$(CFLAGS-y) #Include paths CFLAGS+=-Ikernel -Iinclude -I. -Ikernel/unicore-mx/include/unicore-mx -Ikernel/unicore-mx/include #Freestanding options CFLAGS+=-fno-builtin CFLAGS+=-ffreestanding CFLAGS+=-nostdlib ASFLAGS+=-mthumb -mlittle-endian -mthumb-interwork -ggdb -mcpu=$(MCPU) ================================================ FILE: rules/config.mk ================================================ #Common code used to read the .config RAM1_SIZE=0 #KiB RAM2_SIZE=0 #KiB RAM3_SIZE=0 #KiB SDRAM_SIZE=0 #B ifeq ($(RAM_SIZE_368KB),y) RAM1_SIZE=368 endif ifeq ($(RAM_SIZE_320KB),y) RAM1_SIZE=320 endif ifeq ($(RAM_SIZE_256KB),y) RAM1_SIZE=256 endif ifeq ($(RAM_SIZE_192KB),y) RAM1_SIZE=192 endif ifeq ($(RAM_SIZE_128KB),y) RAM1_SIZE=128 endif ifeq ($(RAM_SIZE_96KB),y) RAM1_SIZE=96 endif ifeq ($(RAM_SIZE_64KB),y) RAM1_SIZE=64 endif ifeq ($(RAM_SIZE_32KB),y) RAM1_SIZE=32 endif ifeq ($(RAM_SIZE_24KB),y) RAM1_SIZE=24 endif ifeq ($(RAM_SIZE_16KB),y) RAM1_SIZE=16 endif ifeq ($(ARCH_LPC17XX),y) CPU=cortex-m BOARD=lpc17xx FLASH_ORIGIN=0x00000000 RAM1_BASE=0x10000000 RAM2_BASE=0x2007C000 RAM3_BASE=0x20080000 RAM2_SIZE=16 RAM3_SIZE=16 ARCH=LPC17XX MCPU=cortex-m3 CFLAGS+=-DLPC17XX -DCONFIG_SRAM_EXTRA UNICOREMX_TARGET=lpc17xx endif ifeq ($(ARCH_LM3S),y) CPU=cortex-m BOARD=lm3s FLASH_ORIGIN=0x00000000 RAM1_BASE=0x20000000 SYS_CLOCK=50000000 ARCH=LM3S CFLAGS+=-DLM3S MCPU=cortex-m3 UNICOREMX_TARGET=lm3s endif ifeq ($(ARCH_NRF51),y) CPU=cortex-m BOARD=nrf51 FLASH_ORIGIN=0x00000000 RAM1_BASE=0x20000000 RAM1_SIZE=32 SYS_CLOCK=16000000 ARCH=NRF51 MCPU=cortex-m0 CFLAGS+=-DNRF51 -lgcc -DCUSTOM_SYSTICK UNICOREMX_TARGET=nrf/51 endif ifeq ($(ARCH_NRF52),y) CPU=cortex-m BOARD=nrf52 FLASH_ORIGIN=0x00000000 RAM1_BASE=0x20000000 RAM1_SIZE=64 SYS_CLOCK=84000000 ARCH=NRF52 MCPU=cortex-m4 CFLAGS+=-DNRF52 UNICOREMX_TARGET=nrf/52 endif ifeq ($(ARCH_STM32F4),y) CPU=cortex-m BOARD=stm32f4 FLASH_ORIGIN=0x08000000 RAM1_BASE=0x20000000 RAM1_SIZE=128 RAM2_BASE=0x10000000 RAM2_SIZE=64 SDRAM_BASE=0xD0000000 SDRAM_SIZE=0x800000 CFLAGS+=-DSTM32F4 -mfloat-abi=soft -DCONFIG_SRAM_EXTRA MCPU=cortex-m4 ARCH=STM32F4 OPENCM3FLAGS=FP_FLAGS="-mfloat-abi=soft" UNICOREMX_TARGET=stm32/f4 endif ifeq ($(ARCH_STM32F7),y) CPU=cortex-m BOARD=stm32f7 FLASH_ORIGIN=0x08000000 RAM1_BASE=0x20000000 SDRAM_BASE=0xC0000000 SDRAM_SIZE=0x800000 CFLAGS+=-DSTM32F7 -mfloat-abi=soft -DCONFIG_SRAM_EXTRA MCPU=cortex-m4 ARCH=STM32F7 OPENCM3FLAGS=FP_FLAGS="-mfloat-abi=soft" UNICOREMX_TARGET=stm32/f7 endif ifeq ($(MACH_STM32F405Pyboard),y) CFLAGS+=-DPYBOARD endif ifeq ($(MACH_STM32F429Discovery),y) CFLAGS+=-DF429DISCO endif ifeq ($(FLASH_SIZE_2MB),y) FLASH_SIZE=2048 endif ifeq ($(FLASH_SIZE_1MB),y) FLASH_SIZE=1024 endif ifeq ($(FLASH_SIZE_512KB),y) FLASH_SIZE=512 endif ifeq ($(FLASH_SIZE_384KB),y) FLASH_SIZE=384 endif ifeq ($(FLASH_SIZE_256KB),y) FLASH_SIZE=256 endif ifeq ($(FLASH_SIZE_192KB),y) FLASH_SIZE=192 endif ifeq ($(FLASH_SIZE_128KB),y) FLASH_SIZE=128 endif ifeq ($(CLK_48MHZ),y) SYS_CLOCK=48000000 endif ifeq ($(CLK_84MHZ),y) SYS_CLOCK=84000000 endif ifeq ($(CLK_100MHZ),y) SYS_CLOCK=100000000 endif ifeq ($(CLK_120MHZ),y) SYS_CLOCK=120000000 endif ifeq ($(CLK_168MHZ),y) SYS_CLOCK=168000000 endif ifeq ($(CLK_180MHZ),y) SYS_CLOCK=180000000 endif ifeq ($(CLK_216MHZ),y) SYS_CLOCK=216000000 endif #USARTs ifeq ($(USART_0),y) CFLAGS+=-DCONFIG_USART_0 endif ifeq ($(USART_1),y) CFLAGS+=-DCONFIG_USART_1 endif ifeq ($(USART_2),y) CFLAGS+=-DCONFIG_USART_2 endif ifeq ($(USART_3),y) CFLAGS+=-DCONFIG_USART_3 endif ifeq ($(USART_4),y) CFLAGS+=-DCONFIG_USART_4 endif ifeq ($(USART_6),y) CFLAGS+=-DCONFIG_USART_6 endif #UARTs ifeq ($(UART_0),y) CFLAGS+=-DCONFIG_UART_0 endif ifeq ($(UART_1),y) CFLAGS+=-DCONFIG_UART_1 endif ifeq ($(UART_2),y) CFLAGS+=-DCONFIG_UART_2 endif ifeq ($(UART_3),y) CFLAGS+=-DCONFIG_UART_3 endif ifeq ($(UART_4),y) CFLAGS+=-DCONFIG_UART_4 endif #SPIs ifeq ($(SPI_1),y) CFLAGS+=-DCONFIG_SPI_1 endif ifeq ($(SPI_2),y) CFLAGS+=-DCONFIG_SPI_2 endif ifeq ($(SPI_3),y) CFLAGS+=-DCONFIG_SPI_3 endif ifeq ($(SPI_4),y) CFLAGS+=-DCONFIG_SPI_4 endif ifeq ($(SPI_5),y) CFLAGS+=-DCONFIG_SPI_5 endif ifeq ($(SPI_6),y) CFLAGS+=-DCONFIG_SPI_6 endif #RNG ifeq ($(DEVRNG),y) CFLAGS+=-DCONFIG_RNG endif #FRAND ifeq ($(DEVFRAND),y) CFLAGS+=-DCONFIG_FRAND endif #I2Cs ifeq ($(I2C1),y) CFLAGS+=-DCONFIG_I2C1 endif ifeq ($(I2C2),y) CFLAGS+=-DCONFIG_I2C2 endif ifeq ($(I2C3),y) CFLAGS+=-DCONFIG_I2C3 endif #LOWPOWER ifeq ($(LOWPOWER),y) CFLAGS+=-DCONFIG_LOWPOWER endif #PICOTCP ifeq ($(PICOTCP),y) CFLAGS+=-DCONFIG_PICOTCP endif APPS_ORIGIN=$$(( $(KFLASHMEM_SIZE) * 1024)) CFLAGS+=-DFLASH_ORIGIN=$(FLASH_ORIGIN) CFLAGS+=-DAPPS_ORIGIN=$(APPS_ORIGIN) CFLAGS+=-DCONFIG_KRAM_SIZE=$(KRAMMEM_SIZE) CFLAGS+=-DCONFIG_SYS_CLOCK=$(SYS_CLOCK) ================================================ FILE: rules/picotcp.mk ================================================ ifeq ($(TCPIP_MEMPOOL_YN),y) MEMPOOL+=-DCONFIG_TCPIP_MEMPOOL=$(CONFIG_TCPIP_MEMPOOL) endif ifeq ($(PICOTCP),y) CFLAGS+=-DCONFIG_PICOTCP -I$(PREFIX)/include -Ikernel/net/socket -nostdlib PICO_OPTIONS=CROSS_COMPILE=arm-frosted-eabi- ARCH=cortexm3 RTOS=1 PREFIX=$(PREFIX) \ DHCP_CLIENT=0 DHCP_SERVER=0 MDNS=0 DNS_SD=0 \ OLSR=0 SLAACV4=0 SNTP_CLIENT=0 PPP=0 TFTP=0 \ AODV=0 \ SIXLOWPAN=0 PICO_LIB:=$(PREFIX)/lib/libpicotcp.a ifneq ($(CONFIG_PICOTCP_DEBUG),y) PICO_OPTIONS+=DEBUG=0 endif ifneq ($(CONFIG_PICOTCP_LOOP),y) PICO_OPTIONS+=DEVLOOP=0 endif ifneq ($(CONFIG_PICOTCP_IPV6),y) PICO_OPTIONS+=IPV6=0 else CFLAGS-y:=CONFIG_IPV6=1 endif ifneq ($(CONFIG_PICOTCP_IPV4),y) PICO_OPTIONS+=IPV4=0 endif ifneq ($(CONFIG_PICOTCP_TCP),y) PICO_OPTIONS+=TCP=0 endif ifneq ($(CONFIG_PICOTCP_UDP),y) PICO_OPTIONS+=UDP=0 endif ifneq ($(CONFIG_PICOTCP_DNS),y) PICO_OPTIONS+=DNS_CLIENT=0 else CFLAGS-$(PICOTCP)+=-DCONFIG_DNS_CLIENT=1 endif ifneq ($(CONFIG_PICOTCP_MCAST),y) PICO_OPTIONS+=MCAST=0 endif ifneq ($(CONFIG_PICOTCP_NAT),y) PICO_OPTIONS+=NAT=0 endif ifneq ($(CONFIG_PICOTCP_IPFILTER),y) PICO_OPTIONS+=IPFILTER=0 endif ifeq ($(LOWPOWER),y) PICO_OPTIONS+=TICKLESS=1 endif PICO_OPTIONS+=EXTRA_CFLAGS="-DFROSTED -I$(PWD)/kernel -I$(PWD)/include -nostdlib -DPICO_PORT_CUSTOM $(MEMPOOL)" BUILD_PICO=make -C kernel/net/picotcp $(PICO_OPTIONS) endif ================================================ FILE: rules/userspace.mk ================================================ USERSPACE=frosted-userland ================================================ FILE: scripts/frosted-dev-setup ================================================ #!/usr/bin/env bash printf "\nSetting up Frosted dev env..."; path="$(pwd)"; cd ~; mkdir frosted-dev; cd frosted-dev; sudo apt-get install build-essential cmake libusb-1.0 libusb-1.0.0-dev git screen wget http://archive.trexotech.com:8081/arm-frosted-eabi-latest.tar.bz2; tar xjf arm-frosted-eabi-latest.tar.bz2; export PATH="$(pwd)/arm-frosted-eabi/bin:$PATH"; git clone https://github.com/texane/stlink.git; cd stlink; mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=Debug ..; make; cd ..; sudo cp etc/udev/rules.d/*.rules /etc/udev/rules.d/; sudo udevadm control --reload-rules; sudo udevadm trigger; export PATH="$(pwd)/build:$PATH"; cd "$path"; git submodule init; git submodule update; cd frosted-userland; git submodule init; git submodule update; printf " OK!\n\nFrosted dev env setup in ~/frosted-dev\n\n"; ================================================ FILE: scripts/frosted-qemu-setup ================================================ #!/usr/bin/env bash if [[ $- != *i* ]]; then echo "You should dot me in" >&2; exit 1; fi printf "\nSetting up Frosted qemu env...\n\n"; path="$(pwd)"; cd ~; mkdir frosted-qemu cd frosted-qemu; sudo apt-get install build-essential cmake libusb-1.0 libusb-1.0.0-dev git screen; wget http://archive.trexotech.com:8081/arm-frosted-eabi-latest.tar.bz2; tar xjf arm-frosted-eabi-latest.tar.bz2; export PATH="$(pwd)/arm-frosted-eabi/bin:$PATH"; sudo apt-get build-dep qemu; git clone git://github.com/insane-adding-machines/qemu.git; cd qemu; ./configure --prefix="$(pwd)/../qemu-bin" --target-list=arm-softmmu; make; sudo make install; sudo chmod u+s "$(pwd)/../qemu-bin/libexec/qemu-bridge-helper"; cd ..; export PATH="$(pwd)/qemu-bin/bin:$PATH"; sudo mkdir qemu-bin/etc; sudo mkdir qemu-bin/etc/qemu; printf "allow br0\n" | sudo tee qemu-bin/etc/qemu/bridge.conf; cd "$path"; git submodule init; git submodule update; cd frosted-userland; git submodule init; git submodule update; cd ..; printf "\nFrosted qemu env setup in ~/frosted-qemu\n\n"; printf "For adding the env path autmatically, update your PATH with:\n"; printf "$HOME/frosted-qemu/arm-frosted-eabi/bin\n"; printf "$HOME/frosted-qemu/qemu-bin/bin\n\n"; ================================================ FILE: xipfs.h ================================================ #ifndef XIPFS_NULL #define XIPFS_NULL void xipfs_init(void); #endif