include src/phone/Makefile
include src/target/Makefile
+include src/function/Makefile
include src/driver/Makefile
+BINPATH = $(CONFIG_PLATFORM_BIN_PATH):$(PATH)
+
#
# Dependencies for generated include files
# TODO: Solve cyclic dependencies on non-generated file
#
include/config.h: .config
- ( cat $< ; for m in $(metavars-y) ; do echo $$m ; done ) | sed -e '/^#/d' -e 's/^\([A-Z0-9_]*\)=\(.*\)/#define \1 \2/' > $@
- for i in $(includes-y) ; do echo "#include \"../$$i\"" >> $@ ; done
+ ( cat $< ; for m in $(metavars-y) ; do echo $$m ; done ) | sed -e '/^#/d' -e 's/^\([A-Za-z0-9_]*\)=\(.*\)/#define \1 \2/' > $@
+ for i in $(includes-y) ; do echo "#include <$$i>" >> $@ ; done
.PHONY += configincludes
configincludes: include/config.h
# rule is that all API calls between the two halves must be
# documented in doc/top2bottom.*
#
-bin/firmerware.bin: bin/firmerware.elf
- strip -s -o $@ $<
-
-bin/firmerware.elf: bin/top.o bin/bottom.o
- gcc -MD -o $@ bin/top.o bin/bottom.o
- @echo
- @echo "*** Compilation succesful"
- @echo
- @size bin/firmerware.elf
bin/top-kernel.o: $(objs-top-kernel-y)
- ld -r -o $@ $(objs-top-kernel-y)
+ PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-kernel-y)
bin/top-net.o: $(objs-top-net-y)
- ld -r -o $@ $(objs-top-net-y)
+ PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-net-y)
bin/top-phone.o: $(objs-top-phone-y)
- ld -r -o $@ $(objs-top-phone-y)
+ PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-phone-y)
-bin/top.o: bin/top-kernel.o bin/top-net.o bin/top-phone.o
- ld -r -o $@ bin/top-kernel.o bin/top-net.o bin/top-phone.o
+# bin/top.o: bin/top-kernel.o bin/top-net.o bin/top-phone.o
+# $(LD) $(LDFLAGS) -r -o $@ bin/top-kernel.o bin/top-net.o bin/top-phone.o
+bin/top.o: $(objs-top-y)
+ PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-y)
bin/bottom.o: $(objs-bottom-y)
- ld -r -o $@ $(objs-bottom-y)
-
-#
-# General compiler rule
-# TODO: Use -Wall and remove silencing-up overrides
-# gcc -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -fno-builtin -MD -c -Iinclude -ggdb3 -o $@ $<
-#
-%.o: %.c
- gcc -fno-builtin -MD -c -Iinclude -ggdb3 -o $@ $<
+ PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-bottom-y)
#
# Create a "tags" file for easy Vim navigation
#
-tags:
+tags: src/net/6bed4.c
ctags $(objs-top-kernel-y:.o=.c) $(objs-top-net-y:.o=.c) $(objs-top-phone-y:.o=.c) $(objs-bottom-y:.o=.c) include/0cpm/*.h include/config.h
.PHONY += clean
clean:
- rm -f $(objs-top-kernel-y)
- rm -f $(objs-top-net-y)
- rm -f $(objs-top-phone-y)
+ rm -f $(objs-top-y) $(objs-top-n) $(objs-top-)
+ # rm -f $(objs-top-net-y)
+ # rm -f $(objs-top-phone-y)
rm -f $(objs-bottom-y)
- rm -f $(objs-top-kernel-y:.o=.d)
- rm -f $(objs-top-net-y:.o=.d)
- rm -f $(objs-top-phone-y:.o=.d)
+ rm -f $(objs-top-y:.o=.d) $(objs-top-n:.o=.d) $(objs-top-:.o=.d)
+ # rm -f $(objs-top-kernel-y:.o=.d)
+ # rm -f $(objs-top-net-y:.o=.d)
+ # rm -f $(objs-top-phone-y:.o=.d)
rm -f $(objs-bottom-y:.o=.d)
rm -f bin/top-kernel.o bin/top-net.o bin/top-phone.o
rm -f bin/top.o bin/bottom.o
in the end. After gaining some experience, it is good to have a good
look at:
-* Pointers are cast back and forth to uint32_t values. This makes the
- code unsuitable for 64-bit architectures and, much more of a problem,
- for 16-bit architectures such as 16-bit digital signal processors.
-
-* Parsing and checksumming is not sufficiently paranoid. The current
- netinput code assumes proper behaviour from its networking partners.
- That is not a proper assumption for an internetworking device :-)
- Specifically, no effort has been done to check the packet size where
- indices and offsets are applied. Before this is handled, the code
- MUST NOT be released as anything but alpha.
-
-* The use of BPF-style commands in netinput.c -- it can be made fairly
- compact if matched up with machine commands, but is it really more
- efficient than an optimising C compiler? If the difference is
- negligable, then this code should go, even if it brings advantages
- on some platforms. The style is then simply "too inventive".
-
* The mem[] array is untyped, calling for lots of cast commands. This
is not handy, and a result of the BPF-style architecture for netinput.
(The original idea was to do the entire processing in that style, but
--- /dev/null
+i2cp: i2cp.c
+ gcc -o i2cp i2cp.c
--- /dev/null
+/* i2cp.c -- EEPROM read/write over i2c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/i2c-dev.h>
+
+
+#define INTERPAGE_WAIT_MS 5
+#define PAGESIZE_BYTES 128
+
+
+int main (int argc, char *argv []) {
+
+ uint32_t size = ~0L;
+ uint32_t address = 0;
+
+ if (argc != 3) {
+ fprintf (stderr, "Usage: %s image.bin /dev/i2c-N\n or: %s /dev/i2c-N image.bin\n", argv [0], argv [0]);
+ exit (1);
+ }
+
+ struct stat stin;
+ if (stat (argv [1], &stin) == -1) {
+ perror ("Failed to stat input");
+ exit (1);
+ }
+ if (stin.st_rdev == 0) {
+ if (stin.st_size >= 8 * 65536) {
+ fprintf (stderr, "Input image exceeds maximum possible\n");
+ exit (1);
+ } else {
+ size = stin.st_size;
+ }
+ }
+
+ struct stat stout;
+ if (stat (argv [2], &stout) == -1) {
+ perror ("Failed to stat output");
+ exit (1);
+ }
+ if (stout.st_rdev == 0) {
+ if (stout.st_size >= 8 * 65536) {
+ fprintf (stderr, "Output image exceeds maximum possible\n");
+ exit (1);
+ } else if (size == (uint32_t) ~0L) {
+ size = stout.st_size;
+ }
+ }
+
+
+ int fin = open (argv [1], O_RDWR);
+ if (fin < 0) {
+ perror ("Failed to read input");
+ exit (1);
+ }
+ int fout = open (argv [2], O_RDWR);
+ if (fout < 0) {
+ perror ("Failed to access output");
+ exit (1);
+ }
+
+ if (stin.st_rdev) {
+ ioctl (fin, I2C_TIMEOUT, 1);
+ ioctl (fin, I2C_RETRIES, 2);
+ }
+ if (stout.st_rdev) {
+ ioctl (fout, I2C_TIMEOUT, 1);
+ ioctl (fout, I2C_RETRIES, 2);
+ }
+
+ while (address < size) {
+ uint8_t buf [2 + PAGESIZE_BYTES];
+ buf [0] = (address & 0x0000ff00) >> 8;
+ buf [1] = (address & 0x000000ff);
+ if ((address & 0x0000ffff) == 0x000000) {
+ uint8_t slave = address >> 16;
+ slave &= 0x07;
+ slave += 0x50;
+ if (stin.st_rdev) {
+ if (ioctl (fin, I2C_SLAVE, slave) == -1) {
+ perror ("Failed to set input slave address");
+ exit (1);
+ }
+ }
+ if (stout.st_rdev) {
+ if (ioctl (fout, I2C_SLAVE, slave) == -1) {
+ perror ("Failed to set output slave address");
+ exit (1);
+ }
+ }
+ }
+ if (stin.st_rdev) {
+ write (fin, buf, 2);
+ }
+ int rdlen = read (fin, buf+2, (size-address) >= PAGESIZE_BYTES? PAGESIZE_BYTES: size-address);
+ if (rdlen >= 0) {
+ if (rdlen == 0) {
+ break;
+ }
+ if (stout.st_rdev) {
+ if (write (fout, buf, 2 + rdlen) < 2 + rdlen) {
+ perror ("Failed to write to i2c");
+ }
+ } else {
+ if (write (fout, buf+2, rdlen) < rdlen) {
+ perror ("Failed to write to file");
+ }
+ }
+ } else {
+ perror ("Failed to read");
+ exit (1);
+ }
+ address += rdlen;
+ usleep (INTERPAGE_WAIT_MS * 1000);
+ }
+
+ close (fin);
+ close (fout);
+ return 0;
+}
--- /dev/null
+======================================
+Porting 0cpm Firmerware to a new Phone
+======================================
+
+.. contents::
+
+This manual describes the steps to port the 0cpm Firmerware to
+a new phone.
+
+
+Notes for hardware manufacturers
+================================
+
+**Welcome!**
+We are delighted about any hardware manufacturer who chooses
+to use this firmware on their own phones. We believe that the
+best of worlds comes from dedicated hardware manufacturers who
+use firmware from dedicated software manufacturers. We also
+believe that open source gives a great economic boost, as it
+enables sharing between parties that would not usually work
+together. But as things go, this is a two-sided story; this
+software is not only grab-and-run, but it also obliges you to
+share back with the community. In the end, your skills at
+hardware design and marketing are what will set you apart.
+
+**License:**
+Please read the ``LICENSE`` file carefully. Using this software,
+or even parts of it, makes it apply to you and your work.
+The obligations imposed by the license are all related to keeping
+your firmware open and modifiable to its users:
+
+* you must supply source code in all versions sold
+* you must include a toolchain for building the code
+* you must inform your users about all this
+
+We are quite willing to include your source code changes into the
+main repository for this project, as long as you are mindful about
+the structure of the project; specifically, the separation between
+top and bottom halves is vital. The top half is for generic logic
+and the bottom half is for driving the actual hardware; these should
+never be mixed and a generic (but possibly evolving) API should be
+used between the two layers.
+
+**Functions:**
+Note that this firmware can do more than just support SIP
+telephony. It can be built to fulfil functions that are very
+useful to various applications:
+
+* SIP phone, simulating analog phones plus *much* more
+* SIP doorbell, a hotline phone that dials out as soon as it is switched on
+* SIP alarm clock, answering wakeup calls and playing their sounds
+* bootloader, a small tool to access the flash over TFTP
+* development/test functions to test drivers one by one
+
+The responsibilities from the license only apply to the portions
+of the firmware that you are using; for instance, you could use
+the bootloader from this project with your own non-phone application
+and only have to release source code and access to the bootloader.
+
+
+Notes for organisations using phones
+====================================
+
+Phones usually represent quite a bit of value to companies using
+them, so it is not optimal to discard them solely on account of
+their firmware. This project defines new firmware, and aims it
+to run on as many platforms as possible.
+
+If you are interested in reusing your phone with modern, free
+software, you could consider finding a hacker or nerd to reverse
+engineer the phone, and put in this newer firmware. If successful,
+the phones can be tweaked to do exactly what they are supposed to
+do, by simply changing the firmware and uploading it to all
+phones in use.
+
+The process of reverse engineering is difficult, and not all the
+required information is available for all phones, so it may not
+be possible in general. If you decide to walk this path, you
+probably should invest a little in analysing whether it is
+possible at all before taking the plunge and handing out the
+assignment to actually reverse-engineer your phones.
+
+As such changes and modifications would be sold to you, all
+results from the project would be donated back to this project.
+This means that you will be doing many people a favour, and that
+need not be an anonymous act either!
+
+
+Materials needed
+================
+
+Make sure you have a reasonable kit of electronics equipment
+on hand:
+
+* screwdrivers, pliers
+* multimeter that beeps if it finds a contact
+* glass scraper with a handle
+* soldering iron and related tools
+* wires, jumpers, access to all sorts of electronics parts
+* Linux PC (Windows might work as a sub-optimal substitute)
+* useful if available: oscilloscope, logic analyser
+
+The multimeter should be sensitive enough to measure through
+a device without damaging it. Its beep is very helpful because
+it allows you to drag one pin over the many pins of a large chip
+to find the connection to another point in the circuit.
+
+
+Understanding your hardware
+===========================
+
+This section is mainly of interest to reverse engineers.
+
+
+Identifying devices
+-------------------
+
+Some manufacturers "protect" the identity of a chip with a layer
+of paint. That is a good sign; it probably means that the chip
+is generic, and good documentation and toolchains may well be
+available for it.
+
+Paint on chips can be scraped off with a glass scraper. Look for
+one with a handle to give you more control. Use the flat surface
+of the chip and drive the scraper through, almost as if you are
+removing snow from a sidewalk. It may take you some practice to
+really get handy doing this; just remember to err on the safe side
+as your could also cut into the chip with the scraper.
+
+The elements usually found in a phone are:
+
+* A major chip, usually a system-on-chip (SoC) which embeds a
+ processor with timers, I/O pin drivers, serial ports and so on.
+
+ Although a family of devices usually sticks to a particular SoC,
+ it seems that every manufacturer has their own. Silly but true.
+
+* An ethernet chip. If the phone has two external LAN connectors,
+ it will also include a switch. Depending on the phone, it may
+ hold two ethernet interfaces (which is rare and silly), one
+ ethernet interface and a switch, or a combination of those.
+
+ By far the most common chip used is an RTL8019AS. Since this is
+ a 10 Mb/s device, it is usually combined with a 100 Mb/s switch
+ so the outside connectors are faster.
+
+* RAM chip(s). These used to be static RAM but even here the DRAM
+ chips are taking over. These are silly chips, because they are
+ the only type of memory that suffers from amnesia; still, they
+ are the most compact and usually offer more bits on an area.
+
+* Flash chip(s). These come in NAND and NOR flavours, referring to
+ block- and byte-addressed varieties, respectively. The NOR flash
+ is common, because it enables running programs straight from the
+ flash memory. For that reason, they commonly use 70 ns chips.
+
+* A codec chip. These are a bit like embedded sound cards; they can
+ be accessed over a protocol like SPI to interact with microphones,
+ speakers and so on. They usually include analog electronics such
+ as amplifiers.
+
+Don't forget to check the PCB's bottom; there may be components on
+both sides!
+
+
+Fetch documentation
+-------------------
+
+Given that all devices on the board are identified, lookup their
+documentation. A web search with the serial numbers on the chips
+usually does wonders, although these search terms are also being
+used to attract people wanting to purchase them to trading sites.
+Adding a term like GND or Vcc may help.
+
+If you cannot find all documentation for forward engineering, it
+may become difficult to port to this platform. You could try
+contacting the vendor of the chips for information, but only if
+they haven't published it online. Most hardware vendors are
+keen on seeing open source projects develop around their chips.
+
+You may be able to locate drivers for peripheral chips in kernels
+like Linux' -- this may actually help you to drivers for such
+chips that were obtained by reverse engineering such chips when
+they were used in PCs. The hardware used in phones is not nearly
+as modern as that used in PCs so the odds to this are good.
+
+Save everything found in a ``datasheet`` directory for your porting
+project; you will want to refer to it very often, and you don't want
+to have to repeat your search. Also, it will be easier to share
+what you found if you store it like that.
+
+
+Find a toolchain
+----------------
+
+Based on the SoC chip used, look for a toolchain. The documentation
+will probably tell you what kind of processor is embedded, and you
+may find an open source toolchain (like gcc_, llvm_, gas) or one
+provided by the hardware manufacturer.
+
+You really could confront the hardware vendor with it if you wanted
+to use their platform compiler for an open source project. Most
+like open source, and have used it for long as consumers; they may
+also see the advantage of their hardware being supported by an open
+source phone application, especially if they realise that competitors
+do have support for it. VoIP is currently a cut-throat market.
+
+.. _gcc : http://gcc.gnu.org/install/specific.html
+
+.. _gas : http://sourceware.org/binutils/docs/as/index.html
+
+.. _llvm : http://llvm.org/
+
+
+
+Gaining control
+===============
+
+Most chips provide a number of ways through which you can gain control.
+Most circuit boards will actually have jumper positions for soldering-on
+a connector that can hold such controls.
+
+Study the chip documentation for the SoC at hand for ways of getting in,
+and see if those are wired to the jumper positions on your board.
+Various forms of access exist in practice.
+
+
+Serial
+------
+
+Serial interfaces usually have 3 or 4 pins; GND, RxD, TxD and
+sometimes an extra Vcc pin. The level of these interfaces is
+usually 3V3, so you will need a converter for this; you could
+use a cable intended for a suitable phone (I use one suitable
+for Siemens MC60 phones).
+
+If you do this a lot, you will like to have an
+`autobaud interface`_ to the RS-232 port.
+
+.. _`autobaud interface` : http://spritesmods.com/?art=autobaud&page=1
+
+Once attached, you want to try using an application like
+``minicom`` to figure out the baudrate and see if a proper
+console pops up. It may give you good information about the
+kind of device that is running on the phone. It may even
+give you a root prompt.
+
+Look for bootloaders; if you are lucky, you will be using an
+openly documented bootloader that explains how to install new
+firmware after something like a TFTP download.
+
+A question to always ask yourself is how users could do such things
+without soldering. Is there a webbed interface that lets you do
+the same as the serial bootloader? It may be worth to try to save
+the current firmware first, so you can go back and test such things.
+
+
+JTAG
+----
+
+JTAG access is ideal if you can get it; it will give you direct
+control over the bus, so you can probe keys and see on your PC
+what it does to your bus, and you could steer selected pins to
+see if and how they influence LEDs and the display. Most
+importantly though, it could let you upload and download flash
+contents without *any* support from the chip. In other words,
+once you have JTAG working, you have full control over your phone.
+
+The Joint Testing Action Group defined an interface named JTAG_
+which clocks bits in and out of a chip; these bits can represent
+internal state, but the only standardised part reflects on the
+external pins of a chip. A so-called `boundary scan`_ meanst that
+these new external pin values are clocked in while the old ones
+are being clocked out, one by one in a sequence.
+
+.. _JTAG : http://en.wikipedia.org/wiki/Jtag
+
+.. _`boundary scan` : http://en.wikipedia.org/wiki/Boundary_scan
+
+The boundary scan interface is specified in a special file that
+is usually available from SoC manufacturers; look for BSDL or
+BSD downloads.
+
+Tools like UrJTAG_ and OpenOCD_ can help with these boundary
+scans, although JTAG often involves tweaking and takes some
+keen attention. But once you got it working, you should be
+ready to go.
+
+Of the two tools, UrJTAG is older and not as actively developed
+as OpenOCD is. OpenOCD has a very clear structure, making it
+very easy to work on; but it cannot currently process BSDL
+yet (I am working on that, as a matter of fact) which is possible
+with UrJTAG. One problem with BSDL is that the syntax is not
+public (sigh!) so parsers, as is the case with UrJTAG, may not
+successfully process all BSDL files around.
+
+.. _UrJTAG : http://urjtag.org/
+
+.. _OpenOCD : http://openocd.berlios.de/web/
+
+
+Bootloader
+----------
+
+Some chips have built-in bootloaders that can download code over
+a more-or-less standard interface, like serial, I2C or SPI. This
+may take a bit of soldering, but it is actually a very good way
+to control your device because it does not need to replace the
+contents of your phone's flash memory.
+
+Depending on the bootloader, you would need to setup a suitable
+access for code from your PC to the booting device. For instance,
+Texas Instruments' TMS320VC55xx devices can boot from I2C EEPROMs
+attached to the right pins; you could setup an interface to match
+Linux' ``i2c-parport`` interface as documented in the
+``Documentation/i2c/busses/i2c-parport`` file in the kernel sources.
+
+
+Vendor-specific
+---------------
+
+Vendors sometimes develop their own connectors for development and
+debugging. Although these certaintly give a lot of control, some
+are very expensive. Usually, cheaper alternatives are available
+if you have enough determination.
+
+
+
+Mapping your hardware
+=====================
+
+You should figure out how all the buttons, LEDs and LCD connections
+are wired in your phone. It is not important to know each resistor
+and capacitor in the path, but be aware that your multimeter may not
+beep if it finds a connection through a buffering resistor. Also,
+you may have to figure out how to measure through driving transistors.
+
+Even if you need to be mindful of such analog helper components,
+what you are looking for is a map of the logic connections between
+your SoC and the I/O facilities of your phone. This may involve
+flipflops selected by certain addresses, a scanning matrix for the
+keyboard, and so on.
+
+You will also want to find out how the chip-select lines of the
+various chips on your board are triggered. This will help to
+establish where Flash, RAM and so on are located in the memory
+map of your SoC.
+
+Finally, find out how the codec and/or the microphones and speakers
+are driven. This will determine how you should drive sound.
+
+
+Actually porting the 0cpm firmerware
+====================================
+
+Creating a port of the firmware should take minimal effort; that is,
+all that was possible to guide you in a generic sense has been done
+in the firmerware.
+
+Save all the binary intermediate results if they work, as well as any
+intermediate forms such as ELF or COFF files and source; if everything
+breaks down it is good to be able to reconstruct earlier results and
+decide whether the problem is related to hardware or your firmware.
+This could have stopped me from going insane, if only I had realised
+it in time ``;-)``
+
+
+Extend the configuration
+------------------------
+
+TODO
+
+
+Build 1: Basic I/O
+------------------
+
+In ``make menuconfig``, select the firmware function ``Test switch / light``
+that will toggle the message light that is usually present on phones
+in response to the hook contact.
+
+To build this, you would normally have to write simple I/O facilities.
+You would need to read the hook contact to implement
+``bottom_phone_is_offhook()`` and you would need to output a bit for
+``bottom_led_set()``. If you care to play with it, update the file
+``src/function/develtest/switch2led.c`` but be sure to recover the original
+before you submit your owrk.
+
+If this works, you know that you have full control over the device,
+and that you have a working toolchain going all the way into the
+phone. *Congratulations!*
+
+
+Build 2: Timers and interrupts
+------------------------------
+
+In ``make menuconfig``, select the firmware function ``Test timer interrupts``
+that will setup a timer and respond to interrupts every 0,5 second by
+togging the message LED.
+
+To build this, you would normally have to write a timer setup and
+interrupt service routine to handle ``bottom_time()`` and
+``bottom_set_timer_set()`` --do not forget to return the old setting for
+the latter-- in addition to the previously written ``bottom_led_set()``
+function. If you care to play with it, edit
+``src/function/develtest/timer2led.c`` but be sure to recover the original
+before you submit your work.
+
+If this works, you are handling interrupts and you can do time calculations
+as well as setup timers. The complexities of timer queues and interrupt
+handling is further arranged in the top half.
+
+
+Build 3: Keys and display
+-------------------------
+
+In ``make menuconfig``, select the firmware function ``Test keyboard / display``
+that will scan the keyboard and write its findings to the display.
+
+TODO: To build this, you would normally have to write a timer setup and
+interrupt service routine to handle ``bottom_time()`` and
+``bottom_set_timer_set()`` --do not forget to return the old setting for
+the latter-- in addition to the previously written ``bottom_led_set()``
+function. If you care to play with it, edit
+``src/function/develtest/keys2display.c`` but be sure to recover the original
+before you submit your work.
+
+If this works, you are able to scan keys and write texts on the display.
+
+
+Build 4: Networked console
+--------------------------
+
+In ``make menuconfig``, select the firmware function ``Test network``
+that will provide an LLC-based console over ethernet.
+
+TODO: To build this, you would normally have to write a timer setup and
+interrupt service routine to handle ``bottom_time()`` and
+``bottom_set_timer_set()`` --do not forget to return the old setting for
+the latter-- in addition to the previously written ``bottom_led_set()``
+function. If you care to play with it, edit
+``src/function/develtest/keys2display.c`` but be sure to recover the original
+before you submit your work.
+
+If this works, you are able to use the network; your next build would
+be the bootloader, which is the first real application that goes beyond
+developer toys.
+
+
+Build 5: Bootloader
+-------------------
+
+This is the first firmware function that actually reflects a useful
+application. The bootloader sets up an IP4 local address using IP4LL,
+and at that address runs a TFTP server that reveals the contents of
+flash memory. While the bootloader is active, it will support LAN
+access to the flash memory, even for writing. Your best bet would be
+to first download the entire contents of flash, of course.
+
+Note that the bootloader will only run as long as the phone is off-hook;
+if it is on-hook during boot, it will skip to the actual application.
+Given that development machines are usually open, the horn is usually
+not on the hook; whereas in an office situation, a reboot would usually
+be performed with the phone on-hook and so the bootloader would be
+skipped. This also rules out various abuse patterns.
+
+
+Build 6: SIP phone / doorbell / alarm clock
+-------------------------------------------
+
+You can now select the firmware functions that you are really after.
+
+TODO: top_main() can return to invoke "next boot option" cyclically
+TODO: bool bottom_phone_is_offhook (void);
+TODO: TIME_MSEC, TIME_SEC, TIME_MIN, TIME_HOUR, TIME_DAY
+TODO: TIME_BEFORE(a,b)
+
----------------------------------------------
Kernel API between Phone Bottom and Top Halves
----------------------------------------------
#define LED_IDX_LINEKEYS 0
-#if HAS_LED_LINEKEYS
+#if HAVE_LED_LINEKEYS
# define LED_IDX_GENERIC (LED_IDX_LINEKEYS+NUM_LINEKEYS)
#else
# define LED_IDX_GENERIC LED_IDX_LINEKEYS
#endif
-#if HAS_LED_GENERIC
-# define LED_IDX_MESSAGE (LED_IDX_GENERIC+HAS_KBD_GENERIC)
+#if HAVE_LED_GENERIC
+# define LED_IDX_MESSAGE (LED_IDX_GENERIC+HAVE_KBD_GENERIC)
#else
# define LED_IDX_MESSAGE LED_IDX_GENERIC
#endif
-#if HAS_LED_MESSAGE
-# define LED_IDX_MUTE (LED_IDX_GENERIC+1)
+#if HAVE_LED_MESSAGE
+# define LED_IDX_MUTE (LED_IDX_MESSAGE+1)
#else
-# define LED_IDX_MUTE LED_IDX_GENERIC
+# define LED_IDX_MUTE LED_IDX_MESSAGE
#endif
-#if HAS_LED_MUTE
+#if HAVE_LED_MUTE
# define LED_IDX_HANDSET (LED_IDX_MUTE+1)
#else
# define LED_IDX_HANDSET LED_IDX_MUTE
#endif
-#if HAS_LED_HANDSET
+#if HAVE_LED_HANDSET
# define LED_IDX_HEADSET (LED_IDX_HANDSET+1)
#else
# define LED_IDX_HEADSET LED_IDX_HANDSET
#endif
-#if HAS_LED_HEADSET
+#if HAVE_LED_HEADSET
# define LED_IDX_SPEAKERPHONE (LED_IDX_HEADSET+1)
#else
# define LED_IDX_SPEAKERPHONE LED_IDX_HEADSET
#endif
-#if HAS_LED_SPEAKERPHONE
+#if HAVE_LED_SPEAKERPHONE
# define LED_IDX_BACKLIGHT (LED_IDX_SPEAKERPHONE+1)
#else
# define LED_IDX_BACKLIGHT LED_IDX_SPEAKERPHONE
#endif
-#if HAS_LED_BACKLIGHT
+#if HAVE_LED_BACKLIGHT
# define LED_IDX_COUNT (LED_IDX_BACKLIGHT+1)
#else
# define LED_IDX_COUNT LED_IDX_BACKLIGHT
* NONE for no flashing at all.
*/
typedef timing_t led_flashtime_t;
-#define LED_FLASHTIME_NONE ((led_flashtime_t) ( 0 * TIME_MSEC))
-#define LED_FLASHTIME_FAST ((led_flashtime_t) ( 500 * TIME_MSEC))
-#define LED_FLASHTIME_MEDIUM ((led_flashtime_t) (1000 * TIME_MSEC))
-#define LED_FLASHTIME_SLOW ((led_flashtime_t) (2000 * TIME_MSEC))
+#define LED_FLASHTIME_NONE ((led_flashtime_t) (TIME_MSEC(0) ))
+#define LED_FLASHTIME_FAST ((led_flashtime_t) (TIME_MSEC(500) ))
+#define LED_FLASHTIME_MEDIUM ((led_flashtime_t) (TIME_MSEC(1000)))
+#define LED_FLASHTIME_SLOW ((led_flashtime_t) (TIME_MSEC(2000)))
/* Top-half operations to manipulate LED states */
* }
*/
-#define BPF_BEGIN(fname) uint32_t fname (uint8_t *P, uint32_t L, uint32_t *M) { register uint32_t A, X=htonl ((uint32_t) P), S; register int k;
+#define BPF_BEGIN(fname) intptr_t fname (uint8_t *P, uint32_t L, uint32_t *M) { register uint32_t A, X=htonl ((uint32_t) P), S; register int k;
#define BPF_LABEL(l) l:
#define BPF_END() }
#define BPF_TAIL(fname) return (fname) (P, L, M);
MEM_IP4_DST,
MEM_ETHER_SRC,
MEM_ETHER_DST,
- MEM_UDP4_PORTS,
- MEM_UDP6_PORTS,
+ MEM_UDP4_SRC_PORT,
+ MEM_UDP4_DST_PORT,
+ MEM_UDP6_SRC_PORT,
+ MEM_UDP6_DST_PORT,
MEM_VLAN_ID,
MEM_BINDING6,
MEM_IP6_DST,
void netcore_bootstrap_shutdown (void);
uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
+uint8_t *net_arp_query (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
uint8_t *net_dhcp4 (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
/* The bottom defines a few useful things:
* typedef uint..._t timing_t;
- * #define TIME_MSEC ...
- * #define TIME_SEC ...
+ * #define TIME_MSEC(x) ...
+ * #define TIME_SEC(x) ...
+ * #define TIME_BEOFRE(x,y) ...
* The former can be used as a parameter without pointers;
* the TIME_xxx define such periods in terms of that time.
*/
--- /dev/null
+/* Grandstream-specific definitions, split up per model where needed */
+
+#ifndef HEADER_GRANDSTREAM
+#define HEADER_GRANDSTREAM
+
+/* Settings for Budgetone devices */
+#if defined CONFIG_TARGET_GRANDSTREAM_BT20x || defined CONFIG_TARGET_GRANDSTREAM_BT10x
+#define HAVE_LED_MESSAGE 1
+#define HAVE_LED_BACKLIGHT 1
+#endif
+
+
+#endif
+
--- /dev/null
+
+#include <stdint.h>
+
+typedef uint64_t timing_t;
+
+#define TIMER_NULL 0
+
+#define TIME_MSEC(x) ((x))
+#define TIME_SEC(x) ((x)*1000)
+#define TIME_MIN(x) ((x)*1000*60)
+#define TIME_HOUR(x) ((x)*1000*60*60)
+#define TIME_DAY(x) ((x)*1000*60*60*24)
--- /dev/null
+/*
+ * tic55x bottom support definitions
+ *
+ * Below:
+ * - definitions for this architecture to service the top half
+ * - definitions to bind bottom half files together
+ *
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+/* The timer is the top 32-bit half of timer0 */
+typedef uint32_t timing_t;
+#define TIME_BEFORE(x,y) (((x)-(y)) >> 31)
+
+#define TIMER_NULL 0
+
+#define TIME_MSEC(x) ((x))
+#define TIME_SEC(x) ((x)*1000)
+#define TIME_MIN(x) ((x)*1000*60)
+#define TIME_HOUR(x) ((x)*1000*60*60)
+#define TIME_DAY(x) ((x)*1000*60*60*24)
+
+
+/* Critical region definitions */
+#define bottom_critical_region_begin() _disable_interrupts()
+#define bottom_critical_region_end() _enable_interrupts()
+
+
+/* Following definitions are only available if BOTTOM is defined */
+
+
+#ifdef BOTTOM
+
+/* Interrupt Enable Registers (memory-mapped) */
+extern volatile uint16_t IER0, IER1;
+asm ("_IER0 .set 0x0000");
+asm ("_IER1 .set 0x0045");
+extern volatile uint16_t IFR0, IFR1;
+asm ("_IFR0 .set 0x0001");
+asm ("_IFR1 .set 0x0046");
+
+#define REGBIT_IER0_TINT0 4
+#define REGBIT_IER1_TINT1 6
+
+extern volatile uint16_t IVPD, IVPH;
+asm ("_IVPD .set 0x0049");
+asm ("_IVPH .set 0x004a");
+
+void setup_interrupts (void);
+
+/* General Purpose I/O registers */
+extern volatile uint16_t ioport IODIR, IODATA;
+asm ("_IODIR .set 0x3400");
+asm ("_IODATA .set 0x3401");
+
+/* Pin Control Registers for McBSP0, McBSP1 */
+extern volatile uint16_t ioport PCR0, PCR1;
+asm ("_PCR0 .set 0x2812");
+asm ("_PCR1 .set 0x2c12");
+
+#define REGBIT_PCR_DXSTAT 5
+#define REGBIT_PCR_RIOEN 12
+#define REGBIT_PCR_XIOEN 13
+
+/* Timer0/1 configuration registers */
+extern volatile uint16_t ioport GPTCLK_0;
+extern volatile uint16_t ioport GPTCNT1_0, GPTCNT2_0, GPTCNT3_0, GPTCNT4_0;
+extern volatile uint16_t ioport GPTPRD1_0, GPTPRD2_0, GPTPRD3_0, GPTPRD4_0;
+extern volatile uint16_t ioport GPTCTL1_0, GPTCTL2_0, GPTGCTL1_0;
+asm ("_GPTCLK_0 .set 0x1003");
+asm ("_GPTCNT1_0 .set 0x1008");
+asm ("_GPTCNT2_0 .set 0x1009");
+asm ("_GPTCNT3_0 .set 0x100a");
+asm ("_GPTCNT4_0 .set 0x100b");
+asm ("_GPTPRD1_0 .set 0x100c");
+asm ("_GPTPRD2_0 .set 0x100d");
+asm ("_GPTPRD3_0 .set 0x100e");
+asm ("_GPTPRD4_0 .set 0x100f");
+asm ("_GPTCTL1_0 .set 0x1010");
+asm ("_GPTCTL2_0 .set 0x1011");
+asm ("_GPTGCTL1_0 .set 0x1012");
+
+extern volatile uint16_t ioport GPTCLK_1;
+extern volatile uint16_t ioport GPTCNT1_1, GPTCNT2_1, GPTCNT3_1, GPTCNT4_1;
+extern volatile uint16_t ioport GPTPRD1_1, GPTPRD2_1, GPTPRD3_1, GPTPRD4_1;
+extern volatile uint16_t ioport GPTCTL1_1, GPTCTL2_1, GPTGCTL1_1;
+asm ("_GPTCLK_1 .set 0x2403");
+asm ("_GPTCNT1_1 .set 0x2408");
+asm ("_GPTCNT2_1 .set 0x2409");
+asm ("_GPTCNT3_1 .set 0x240a");
+asm ("_GPTCNT4_1 .set 0x240b");
+asm ("_GPTPRD1_1 .set 0x240c");
+asm ("_GPTPRD2_1 .set 0x240d");
+asm ("_GPTPRD3_1 .set 0x240e");
+asm ("_GPTPRD4_1 .set 0x240f");
+asm ("_GPTCTL1_1 .set 0x2410");
+asm ("_GPTCTL2_1 .set 0x2411");
+asm ("_GPTGCTL1_1 .set 0x2412");
+
+#define REGVAL_GCTL_TIMMODE_DUAL32CHAINED 0x0c
+#define REGVAL_GCTL_TIM12RS 0x01
+#define REGVAL_GCTL_TIM34RS 0x02
+
+#define REGVAL_CTL12_ENAMODE_MASK 0xc0
+#define REGVAL_CTL12_ENAMODE_ONETIME 0x40
+#define REGVAL_CTL12_ENAMODE_CONTINUOUS 0x80
+#define REGVAL_CTL12_CP 0x08
+#define REGVAL_CTL12_TSTAT 0x01
+
+
+/* Idle mode configuration parameters */
+extern volatile uint16_t ioport ICR, PICR;
+asm ("_ICR .set 0x0001");
+asm ("_PICR .set 0x9400");
+
+#define REGBIT_ICR_CLKEI 9
+#define REGBIT_ICR_IPORTI 8
+#define REGBIT_ICR_MPORTI 7
+#define REGBIT_ICR_XPORTI 6
+#define REGBIT_ICR_EMIFI 5
+#define REGBIT_ICR_CLKI 4
+#define REGBIT_ICR_PERI 3
+#define REGBIT_ICR_ICACHEI 2
+#define REGBIT_ICR_MPI 1
+#define REGBIT_ICR_CPUI 0
+
+#define REGBIT_PICR_MISC 13
+#define REGBIT_PICR_EMIF 12
+#define REGBIT_PICR_BIOST 11
+#define REGBIT_PICR_WDT 10
+#define REGBIT_PICR_PIO 9
+#define REGBIT_PICR_URT 8
+#define REGBIT_PICR_I2C 7
+#define REGBIT_PICR_ID 6
+#define REGBIT_PICR_IO 6
+#define REGBIT_PICR_SP1 3
+#define REGBIT_PICR_SP0 2
+#define REGBIT_PICR_TIM1 1
+#define REGBIT_PICR_TIM0 0
+
+
+#endif
--- /dev/null
+/* Backup for unsupportive compiles */
+
+typedef enum {
+ false = 0,
+ true = 1
+} bool;
--- /dev/null
+==============================================
+README for source directory of 0cpm firmerware
+==============================================
+
+kernel Mainly holds the entrance routines top_xxx
+
+net Protocols, checksums, packet construction/interpretation
+
+phone Telephony logic, user experience
+
+target Platform definitions, platform being make + model
+
+driver Drivers for specific chips in the design
+
+objs-bottom-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += src/driver/tic55x/grandstream-bt20x.o
+
+#TODO: replace rts55.lib with bootstrapping in src/driver/tic55x/trampoline.o
+
+objs-bottom-$(CONFIG_PLATFORM_TIC55x) += src/driver/tic55x/int.o src/driver/tic55x/timer.o src/driver/tic55x/isrmap.o #NOPE# src/driver/tic55x/gpio.o #TODO#
+
+metavars-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += SYSCLK1_TO_MS_DIVIDER=4096
--- /dev/null
+/* GPIO driver for tic55x */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+void tic55x_output_set (uint16_t regaddr, uint16_t regval) {
+ * ( (ioport uint16_t *) regaddr) = regval;
+}
+
+uint16_t tic55x_input_get (uint16_t regaddr) {
+ return * ( (uint16_t *) regaddr);
+}
+
+void tic55x_output_set_bit (uint16_t regaddr, uint8_t regbit, bool value) {
+ if (value) {
+ * ( (ioport uint16_t *) regaddr) |= 1 << regbit ;
+ } else {
+ * ( (ioport uint16_t *) regaddr) &= ~( 1 << regbit);
+ }
+}
+
+bool tic55x_input_get_bit (uint16_t regaddr, uint8_t regbit) {
+ uint16_t value = * (ioport uint16_t *) regaddr;
+ return (value & (1 << regbit)) ? true: false;
+}
--- /dev/null
+/* Grandstream BT20x driver as an extension to the tic55x driver */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+
+/* Bottom-half operations to manipulate LED states */
+void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
+ switch (ledidx) {
+ case LED_IDX_MESSAGE:
+ //TODO: Figure out which pin -- incorrectly change backlight
+ case LED_IDX_BACKLIGHT:
+ // Set bit DXSTAT=5 in PCR=0x2812 to 1/0
+ if (col != 0) {
+ PCR0 |= 1 << REGBIT_PCR_DXSTAT ;
+ } else {
+ PCR0 &= ~ ( 1 << REGBIT_PCR_DXSTAT );
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* See if the phone (actually, the horn) is offhook */
+bool bottom_phone_is_offhook (void) {
+ // The hook switch is attached to GPIO pin 5
+ // return ! tic55x_input_get_bit (REGADDR_IODATA, 5);
+ return (IODATA & (1 << 5)) != 0;
+}
+
+
+/* Setup the connectivity of the TIC55x as used on Grandstream BT20x */
+void main (void) {
+ led_colour_t led = LED_STABLE_ON;
+ bottom_critical_region_begin (); // _disable_interrupts ();
+ IER0 = IER1 = 0x0000;
+ tic55x_setup_timers ();
+ tic55x_setup_interrupts ();
+ //TODO// IER0 = 0xdefc;
+ //TODO// IER1 = 0x00ff;
+ IER0 = (1 << REGBIT_IER0_TINT0);
+ PCR0 = (1 << REGBIT_PCR_XIOEN) | (1 << REGBIT_PCR_RIOEN);
+ while (true) {
+ uint32_t ctr;
+ bottom_led_set (LED_IDX_MESSAGE, led);
+ for (ctr=6500000; ctr>0; ctr--) { ; }
+ led ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+ }
+ top_main ();
+}
+
--- /dev/null
+/* tic55x interrupt handling */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+
+
+/* This flag is set by every interrupt that calls a top_XXX function.
+ * It indicates that the top *may* have new work to do. This is used
+ * to establish whether the bottom can go to sleep, as part of a
+ * two-phase sleep protocol: bottom_sleep_prepare() clears this flag,
+ * then the top checks if any work is pending at that time, and then
+ * bottom_sleep_commit() is called. The latter will fall through
+ * immediately if the flag has been set meanwhile, as the top may
+ * have missed incoming work.
+ */
+bool tic55x_top_has_been_interrupted;
+
+
+#if 0
+void bottom_sleep_prepare (void) {
+ tic55x_top_has_been_interrupted = false;
+}
+
+void bottom_sleep_commit (sleep_depth_t depth) {
+ bottom_critical_region_begin ();
+ if (!tic55x_top_has_been_interrupted) {
+ if (depth == SLEEP_HIBERNATE) {
+ // Hibernate: Idle CPU and most I/O
+ ICR = (1 << REGBIT_ICR_CPUI) | (1 << REGBIT_ICR_ICACHEI) | (1 << REGBIT_ICR_MPI) | (1 << REGBIT_ICR_PERI);
+ PICR = (1 << REGBIT_PICR_MISC) | (1 << REGBIT_PICR_BIOST) | (1 << REGBIT_PICR_WDT) | (1 << REGBIT_PICR_URT) | (1 << REGBIT_PICR_I2C) | (1 << REGBIT_PICR_SP1) | (1 << REGBIT_PICR_SP0);
+ } else {
+ // Snooze: Idle CPU but nothing more
+ ICR = 1 << REGBIT_ICR_CPUI;
+ }
+ asm (" IDLE");
+ }
+ bottom_critical_region_end ();
+}
+#endif
+
+interrupt void tic55x_no_isr (void) {
+#if 0
+ /* No action */ ;
+#endif
+}
+
+
+// TODO -- probably do this in the trampoline code?
+void tic55x_setup_interrupts (void) {
+ // extern uint32_t interrupt_table;
+ // IVPD = (uint16_t) (((uint32_t) interrupt_table) >> 8);
+ asm (
+" .ref isrmap0, isrmap1\n"
+" mov #(isrmap0 >> 8), mmap(_IVPD)\n"
+" mov #(isrmap1 >> 8), mmap(_IVPH)\n"
+);
+}
+
--- /dev/null
+ ; Create a subsection with interrupt service routine vectors
+ .sect ".isrmap"
+
+ .align 256
+ .vli_off
+
+ .def isrmap0
+ .def isrmap1
+
+ .ref _c_int00
+ .ref _tic55x_no_isr
+ .ref _tic55x_tint0_isr
+
+_tic55x_bootld .set 0xff8000
+
+isrmap0:
+resetvect .ivec _c_int00, NO_RETA
+nmi .ivec _tic55x_no_isr
+int0 .ivec _tic55x_no_isr
+int2 .ivec _tic55x_no_isr
+tint0 .ivec _tic55x_tint0_isr
+rint0 .ivec _tic55x_no_isr
+rint1 .ivec _tic55x_no_isr
+xint1 .ivec _tic55x_no_isr
+lckint .ivec _tic55x_no_isr
+dmac1 .ivec _tic55x_no_isr
+dspint .ivec _tic55x_no_isr
+int3 .ivec _tic55x_no_isr
+uart .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+dmac4 .ivec _tic55x_no_isr
+dmac5 .ivec _tic55x_no_isr
+int1 .ivec _tic55x_no_isr
+xint0 .ivec _tic55x_no_isr
+dmac0 .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+dmac2 .ivec _tic55x_no_isr
+dmac3 .ivec _tic55x_no_isr
+tint1 .ivec _tic55x_no_isr
+iic .ivec _tic55x_no_isr
+berr .ivec _tic55x_no_isr
+dlog .ivec _tic55x_no_isr
+rtos .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+
+isrmap1:
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+ .ivec _tic55x_no_isr
+
+ .sect ".text"
+ .vli_on
+
--- /dev/null
+/* General timer management.
+ *
+ * The tic55x has multiple 64-bit timers, we'll use timer0 and timer1.
+ *
+ * Since a timer can either be set to fire or continue to count,
+ * but not both, we'll need two timers:
+ *
+ * - timer0 counts until the next time-based interrupt
+ * - timer1 counts the time since the system started
+ *
+ * The reason for assigning the timers like this? timer0 has a higher
+ * interrupt level than, say, uart. That helps to get more accuracy
+ * from a realtime system.
+ *
+ * The tic55x timers are 64-bit, and can be split in two halves.
+ *
+ * The first half (CNT4:CNT3 and PRD4:PRD3) is used as a prescale-counter,
+ * to reduce the crystal clock frequency to a 1 ms pace. This is chained
+ * to the second half (CNT2:CNT1), which then forms the actual timer used
+ * by the 0cpm firmerware.
+ *
+ * The actual 2:1 timer1 is a 32-bit counter that counts round and round
+ * in circles, without ever causing an interrupt. The actual 2:1 timer0
+ * is set to the next interrupt time, and causes an interrupt when it is
+ * reached. This setting is based on the requested interrupt time and
+ * the value in timer1 at the time of the request.
+ *
+ * The top half takes care of setting up timer queues to implement a more
+ * general timing discipline, processing interrupts at such timeouts.
+ *
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
+
+
+/* Global variables */
+
+static timing_t current_timer = 0;
+
+
+/* Read the current time from timer1's top part. Be careful about
+ * timer increments between the two word reads.
+ *
+ * The tic55x copies timer registers to shadow registers to ensure
+ * that all values are in sync; the code need not verify that.
+ */
+timing_t bottom_time (void) {
+ uint16_t cnt1 = GPTCNT1_1;
+ uint16_t cnt2 = GPTCNT2_1;
+ return (((timing_t) cnt2) << 16) | ((timing_t) cnt1);
+}
+
+
+/* Setup a new timing for the following timer interrupt. If one is
+ * currently underway, disable it so it will not spark new interrupts
+ * after this function returns.
+ */
+timing_t bottom_timer_set (timing_t tim) {
+ timing_t intval, previous;
+ /* First of all, reset timer0 so it can be configured */
+ GPTGCTL1_0 &= ~ ( REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS );
+ IFR0 = (1 << REGBIT_IER0_TINT0);
+ previous = current_timer;
+ current_timer = tim;
+ /* Poll the running timer1 */
+ // tim = bottom_time () + TIME_MSEC(1500);
+ intval = tim - bottom_time ();
+// intval = intval & 0x0000ffff;
+ if ((intval == 0) || (intval >> 31)) {
+ /* Cause interrupt right now, do not run the timer */
+ top_timer_expiration (tim);
+ current_timer = 0;
+bottom_led_set (0, 1);
+{ uint32_t ctr = 6500000; while (ctr > 0) ctr--; }
+bottom_led_set (0, 0);
+{ uint32_t ctr = 6500000; while (ctr > 0) ctr--; }
+ return previous;
+ }
+ /* Setup counter value and period */
+ GPTCNT3_0 = GPTCNT3_1; /* also copies GPTCNT4_1 to shadow register */
+ GPTCNT4_0 = GPTCNT4_1; /* retrieve shadow register for GPTCNT4_1 */
+ GPTCNT2_0 =
+ GPTCNT1_0 = 0x0000;
+ GPTPRD2_0 = (uint16_t) (intval >> 16 );
+ GPTPRD1_0 = (uint16_t) intval ; //(intval & 0xffff);
+ /* Finally, enable timer1 so it can cause interrupts */
+ GPTGCTL1_0 |= REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS;
+bottom_led_set (0, 1);
+{ uint32_t ctr = 650000; while (ctr > 0) ctr--; }
+bottom_led_set (0, 0);
+{ uint32_t ctr = 650000; while (ctr > 0) ctr--; }
+ return previous;
+}
+
+
+/* Timer interrupt handler for timer0 expiration */
+interrupt void tic55x_tint0_isr (void) {
+#if 0
+ extern bool tic55x_top_has_been_interrupted;
+ timing_t now = bottom_time ();
+ current_timer = 0;
+ top_timer_expiration (now);
+ tic55x_top_has_been_interrupted = true;
+#endif
+}
+
+
+/* Setup timers and the corresponding interrupts for timer0/timer1
+ */
+void tic55x_setup_timers (void) {
+ /* Be sure that the timers are reset, so they can be configured */
+ GPTGCTL1_0 =
+ GPTGCTL1_1 = 0;
+ /* Let the lower half of timer0/timer1 count once per ms */
+ GPTPRD4_0 =
+ GPTPRD4_1 = (uint16_t) ((SYSCLK1_TO_MS_DIVIDER-1) >> 16);
+ GPTPRD3_0 =
+ GPTPRD3_1 = (uint16_t) ((SYSCLK1_TO_MS_DIVIDER-1) & 0xffff);
+ /* Let the upper half of timer1 count with a 2^32 period */
+ GPTPRD2_1 =
+ GPTPRD1_1 = 0xffff;
+ /* Let timer1 run entirely free; let timer0 lower half run free */
+ GPTCTL1_0 = REGVAL_CTL12_ENAMODE_ONETIME;
+ GPTCTL1_1 = REGVAL_CTL12_ENAMODE_CONTINUOUS;
+ GPTGCTL1_0 = REGVAL_GCTL_TIMMODE_DUAL32CHAINED;
+ GPTGCTL1_1 = REGVAL_GCTL_TIMMODE_DUAL32CHAINED | REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS;
+ /* Clear, then permit interrupts from timer0 */
+ IFR0 = (1 << REGBIT_IER0_TINT0);
+}
+
--- /dev/null
+/* LED simulation support -- print them in tabbed columns
+ *
+ * Descriptions below are all restricted to 7 chars or less, so they
+ * can be printed with a '\t' in between.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdlib.h>
+
+#include <config.h>
+
+#include <0cpm/led.h>
+
+
+char *led_colours_2 [] = { "off", "green" };
+char *led_colours_3 [] = { "off", "green", "red" };
+
+struct led_descript {
+ char *name;
+ char **states;
+ char *current;
+};
+
+/*
+ * LED descriptive structure, following the structure of led.h
+ */
+struct led_descript num2descr [] = {
+#if HAVE_LED_LINEKEYS
+# if NUM_LINEKEYS >= 1
+ { "line1", led_colours_3, NULL, },
+# endif
+# if NUM_LINEKEYS >= 2
+ { "line2", led_colours_3, NULL, },
+# endif
+# if NUM_LINEKEYS >= 3
+ { "line3", led_colours_3, NULL, },
+# endif
+# if NUM_LINEKEYS >= 4
+ { "line4", led_colours_3, NULL, },
+# endif
+# if NUM_LINEKEYS >= 5
+ { "line5", led_colours_3, NULL, },
+# endif
+# if NUM_LINEKEYS >= 6
+ { "line6", led_colours_3, NULL, },
+# endif
+# if NUM_LINEKEYS >= 7
+# error "Please define additional line LEDs in ledsimu.c"
+# endif
+#endif
+#if HAVE_LED_GENERIC
+# error "Please define generic LEDs in ledsimu.c"
+#endif
+#if HAVE_LED_MESSAGE
+ { "vmail", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_MUTE
+ { "mute", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_HANDSET
+ { "handset", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_HEADSET
+ { "headset", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_SPEAKERPHONE
+ { "speaker", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_BACKLIGHT
+ { "display", led_colours_2, NULL, },
+#endif
+};
+
+
+void bottom_led_set (led_idx_t lednum, led_colour_t col) {
+ int i;
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ static headctr = 0;
+ if (headctr++ % 20 == 0) {
+ for (i = 0; i < LED_IDX_COUNT; i++) {
+ printf ("\t%s", num2descr [i].name);
+ }
+ printf ("\n");
+ }
+ printf ("%3d.%03d", tv.tv_sec, tv.tv_usec / 1000);
+ char capscol [8];
+ char *colnm = num2descr [lednum].states [col];
+ for (i = 0; i < 7; i++) {
+ if (colnm [i] == 0) {
+ break;
+ }
+ capscol [i] = toupper (colnm [i]);
+ }
+ capscol [i] = '\0';
+ for (i = 0; i < LED_IDX_COUNT; i++) {
+ if (i == lednum) {
+ colnm = capscol;
+ } else if (num2descr [lednum].current != NULL) {
+ colnm = num2descr [lednum].current;
+ } else {
+ colnm = "UNSET";
+ }
+ printf ("\t%s", colnm);
+ }
+ printf ("\n");
+}
return NULL;
}
+uint8_t *net_arp_query (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
+ printf ("Received: ARP Query\n");
+ return NULL;
+}
+
uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
printf ("Received: RTP\n");
return NULL;
* Environment simulation functions
*/
-void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
- char *colmap [] = { "off", "green", "red" };
- printf ("LED #%d switches to colour #%d (%s)\n",
- ledidx, col, (col < 3)? colmap [col]: "out-of-range");
-}
-
timing_t bottom_time (void) {
struct timeval now;
timing_t retval;
--- /dev/null
+# Function for the target image
+
+menu "Firmerware functions"
+
+choice
+ prompt "Functionality to build"
+ default MAINFUNCTION_SIP_PHONE
+
+source "src/function/Kconfig.devel"
+
+config MAINFUNCTION_SIP_PHONE
+ bool "SIP phone over IPv6"
+ help
+ This is the main target for the 0cpm firmerware. It implements
+ SIP phone functionality over IPv6. Included are facilities to
+ obtain IPv6 connectivity on all networks.
+
+
+config MAINFUNCTION_SIP_DOORBELL
+ bool "SIP doorbell"
+ help
+ This is an alternative main target for the 0cpm firmerware.
+ It implements a doorbell that is switched off until a button
+ is pressed. As soon as the device boots, it will dial out to
+ a predefined number on a predefined server.
+
+ This is not quite the same as a phone configured as a hotline.
+ Such a phone would always be switched on, even though normal
+ use would not include calling to the device. So, to save
+ energy, the doorbell application assumes that a phone is
+ switched off when not in use. The device will keep itself
+ switched on until it is done with its task.
+
+
+config MAINFUNCTION_SIP_ALARMCLOCK
+ bool "SIP alarm clock"
+ help
+ This is an alternate main target for the 0cpm firmerware.
+ It implements an alarm clock that does not ring the phone,
+ but rather picks up immediately and plays whatever sound
+ is sent to it. It is imagined that a network service would
+ wake up all those souls who have a hard time hearing a
+ rooster nearby.
+
+ To furhter implement the logic of an alarm clock, use of the
+ hook contact will make it speak out the current time. There
+ is a facility for a button that will set the alarm to go a
+ predefined number of hours after it was pressed. You might
+ go as far as to wire that to your bed!
+
+
+config MAINFUNCTION_BOOTLOADER
+ bool "Bootloader"
+ help
+ Some phones have less RAM than Flash on board. On such phones,
+ stability improves with the installation of a small bootloader
+ that is smaller than RAM. More in general, it helps to upgrade
+ the firmerware under tight local control.
+
+ The bootloader is initiated after a power cycle if (and as long as)
+ the horn is off-hook. This is not usually the case, so normally
+ the bootloader is skipped quickly.
+
+ While the bootloader is active, all nonvolatile partitions are
+ made available over TFTP for reading and writing. To aid in
+ automation, the bootloader will push the availability of this
+ TFTP service out over DNS-SD and mDNS, although it will not
+ continue to function as a general DNS-SD server.
+
+ The bootloader does not run over IPv6 and is only routed locally;
+ to that end, it acquires an IP4LL "zeroconfig" IP address. These
+ addresses are not intended to be routed, and are not welcome on
+ the general Internet infrastructure. This means that bootloader
+ image functions are protected from remote attacks.
+
+endchoice
+
+config FUNCTION_DEVEL_NETCONSOLE
+ bool "LAN-based console"
+ default y if DEVEL=y
+ default n if DEVEL=n
+ help
+ Direct console traffic for the main application to the network.
+
+ The protocol used for this network console is Logical Link Control.
+ This is an ethernet-level protocol, so it will only work locally.
+
+ This console can also be selected as a main function for the
+ image being built, to test network connectivity.
+
+ TODO: ports
+
+ This facility is normally only of use during development.
+
+config FUNCTION_FIRMWARE_UPGRADES
+ bool "Support firmware upgrades"
+ depends on MAINFUNCTION_SIP_PHONE
+ default n
+ help
+ It is possible, though not strictly required, to support
+ the download and installation of new firmware. As normal
+ IP addresses are used, this is not as safe as the upgrades
+ that are included in the dedicated bootloader main function.
+
+ If the upgrade fails, the phone will need to be upgraded
+ through the bootloader, if it has one.
+
+ Do not select this option without considering its implications.
+
+config FUNCTION_FIRMWARE_UPGRADES_BOOTLOADER
+ bool "Support bootloader upgrades (DANGEROUS)"
+ depends on FUNCTION_FIRMWARE_UPGRADES
+ default n
+ help
+ This is a dangerous facility!
+
+ Complete remote control over a phone is only possible if all
+ firmware, including even its bootloader, can be upgraded from
+ a remote site. This option enables that facility.
+
+ Note that this facility makes the phone rather vulnerable.
+ Anyone with access to the phone's TFTP service will be able
+ to upload new firmware to replace it. You do want to have a
+ tightly controlled firewall to avoid this from being abused.
+
+ TODO: a polling TFTP client may in fact be better?
+
+endmenu
--- /dev/null
+# Development functions
+
+config MAINFUNCTION_DEVEL_GPIO
+ bool "Test switch / light"
+ depends on DEVEL
+ help
+ This is the simplest possible test program, which can be useful
+ to ensure control over a device during reverse engineering.
+
+ The application continuously scans the hook. It makes the message
+ LED burn while the phone is off-hook.
+
+config MAINFUNCTION_DEVEL_TIMER
+ bool "Test timer interrupts"
+ depends on DEVEL
+ help
+ This is a very simple test program. It makes the message LED
+ flash with a 1 second period and a 50% duty cycle. It can be
+ used to develop timer drivers.
+
+config MAINFUNCTION_DEVEL_KEYBOARD
+ bool "Test keyboard / display"
+ depends on DEVEL
+ help
+ This test processes input from the keyboard, and shows it on
+ the display, as well as printing it to the platform's console,
+ if any.
+
+config MAINFUNCTION_DEVEL_NETWORK
+ bool "Test network"
+ depends on DEVEL
+ select FUNCTION_DEVEL_NETCONSOLE
+ help
+ Run a networked console. In addition to the usual console
+ functions, respond to any text sent by mapping it to uppercase.
+
+ The details of the networked console are described under the
+ add-on function for this console, one menu level up.
+
--- /dev/null
+# Function-dependent construction of top-objs list
+
+#
+# Actual targets and their constituent object files
+#
+objs-top-$(CONFIG_MAINFUNCTION_SIP_PHONE) += src/function/sip6phone.o bin/top-kernel.o bin/top-net.o bin/top-phone.o
+
+objs-top-$(CONFIG_MAINFUNCTION_BOOTLOADER) += src/function/bootload.o bin/top-kernel.o bin/top-simplenet.o function
+
+#
+# Test targets, useful during reverse engineering and forward development
+#
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_GPIO) += src/function/develtest/switch2led.o
+
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_TIMER) += src/function/develtest/timer2led.o
+
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_KEYBOARD) += src/function/develtest/keys2display.o
+
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_NETCONSOLE) += src/function/develtest/netconsole.o
+
--- /dev/null
+/* bootloader -- TFTP on top of IP4LL to reveal flash contents */
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/net.h>
+
+
+/* Bootloader IPv4 acquisition -- through IP4LL */
+void bootloader_net_ip4ll (void) {
+ "TODO: code this function";
+}
+
+
+/* Bootloader announcement of TFTP service -- as DNS-SD, over mDNS */
+void bootloader_announce_tftp (void) {
+ "TODO: code this function";
+}
+
+
+/* Bootloader network handling -- dealing with TFTP, ICMP and ARP */
+void bootloader_handle_net (void) {
+ "TODO: code this function";
+}
+
+
+/* Bootloader main program. This usually starts before the real app.
+ *
+ * This ends as soon as possible, once the phone is placed on-hook.
+ * As a result, a normal phone reboot (with the phone on-hook) will
+ * immediately skip bootloading and advance to the actual payload.
+ * Also, if a phone is rebooted off-hook and behaves "funny", the
+ * user will quickly learn to place the horn back on the hook.
+ * In development situations, the horn is usually off-hook as a
+ * result of the phone being taken apart. How practical!
+ */
+void top_main (void) {
+ if (bottom_phone_is_offhook ()) {
+ bootloader_net_ip4ll ();
+ bootloader_announce_tftp ();
+ while (bottom_phone_is_offhook ()) {
+ bootloader_handle_net ();
+ }
+ }
+}
--- /dev/null
+/* keys2display.c -- capture keys and show them on the display */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+void top_main (void) {
+ bottom_critical_region_end ();
+ while (true) {
+ TODO: KEYBOARD AND DISPLAY DRIVING CODE
+ }
+}
+
--- /dev/null
+/* netconsole.c -- run a console over LLC over ethernet */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+void top_main (void) {
+ bottom_critical_region_end ();
+ while (true) {
+ TODO: CONSOLE DRIVER OVER LLC
+ }
+}
+
--- /dev/null
+/* switch2led.c -- simple test where hook contact drives message led */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+
+#define complete_top_main top_main
+
+
+void top_timer_expiration (timing_t when) { ; }
+
+
+void simpler_top_main (void) {
+ while (true) {
+ uint16_t ctr;
+ ctr = 65000;
+ while (ctr > 0) {
+ ctr--;
+ }
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+ ctr = 65000;
+ while (ctr > 0) {
+ ctr--;
+ }
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+ }
+}
+
+
+void complete_top_main (void) {
+ while (true) {
+ if (bottom_phone_is_offhook ()) {
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+ } else {
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+ }
+ }
+}
+
--- /dev/null
+/* timer2led.c -- simple test where a timer toggles a LED (T=1s, D=50%) */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+
+#define complete_top_main top_main
+
+
+void doesitcount_top_main (void) {
+ uint16_t ctr;
+ timing_t lastcaught = bottom_time ();
+ led_colour_t nextstate = LED_STABLE_OFF;
+ while (true) {
+ if (lastcaught != bottom_time ()) {
+ lastcaught = bottom_time ();
+ nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+ bottom_led_set (LED_IDX_MESSAGE, nextstate);
+ ctr = 65000;
+ while (ctr > 0) {
+ ctr--;
+ }
+ }
+ }
+}
+
+
+void noirq_top_main (void) {
+ led_colour_t nextstate = LED_STABLE_OFF;
+ timing_t nextirq = bottom_time ();
+ while (true) {
+ if (TIME_BEFORE (nextirq, bottom_time ())) {
+ nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+ bottom_led_set (LED_IDX_MESSAGE, nextstate);
+ // nextirq = bottom_time () + TIME_MSEC(500);
+ nextirq += TIME_MSEC(500);
+ }
+ }
+}
+
+
+void irqpolling_top_main (void) {
+ timing_t nextirq;
+redo:
+ nextirq = bottom_time () + TIME_MSEC(1500);
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+ bottom_timer_set (nextirq);
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+ while (true) {
+#ifdef INCLUDE_BOTTOM_IRQ_ACCESS_HALFWAY_DEVELOPMENT_HACK
+ if ("irq_flag_is_set") {
+ "clear_irq_flag";
+ bottom_timer_expiration (bottom_time () + TIME_MSEC(1500));
+ }
+#else
+ if ((GPTCNT1_0==0) && (GPTCNT2_0==0)) {
+ IFR0 = (1 << REGBIT_IER0_TINT0);
+ // bottom_timer_expiration (bottom_time () + TIME_MSEC(1500));
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+ goto done;
+ } else {
+ uint16_t ctr;
+ uint16_t ctr1a, ctr1b;
+ ctr1a = GPTCNT1_0;
+ ctr1b = GPTCNT2_0;
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+ ctr = 65000;
+ while (ctr > 0) {
+ ctr--;
+ }
+ if ((ctr1a != GPTCNT1_0) || (ctr1b != GPTCNT2_0)) {
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+ ctr = 65000;
+ while (ctr > 0) {
+ ctr--;
+ }
+ }
+ }
+#endif
+ }
+done:
+while (!bottom_phone_is_offhook ()) {
+ ;
+}
+while (bottom_phone_is_offhook ()) {
+ ;
+}
+goto redo;
+}
+
+
+volatile bool busy = false;
+
+void top_timer_expiration (timing_t exptime) {
+ uint16_t ctr;
+ // static led_colour_t nextstate = LED_STABLE_OFF;
+ // nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+ // bottom_led_set (LED_IDX_MESSAGE, nextstate);
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+ // ctr = 65000;
+ // while (ctr > 0) {
+ // ctr--;
+ // }
+ //ULTIMATELY// nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+ //ULTIMATELY// bottom_led_set (LED_IDX_MESSAGE, nextstate);
+ // bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+ // bottom_timer_set (exptime + TIME_MSEC(1500));
+}
+
+void complete_top_main (void) {
+ timing_t nextirq;
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+ nextirq = bottom_time () + TIME_MSEC(1500);
+ busy = true;
+ // bottom_timer_set (nextirq);
+ // bottom_critical_region_end ();
+ while (true) {
+ if (busy) {
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+ } else {
+ bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+ }
+ }
+}
+
--- /dev/null
+
+
+/* The main operational loop for the CPU. Try to run code, and when
+ * nothing remains to be done, stop to wait for interrupts.
+ */
+void top_main (void) {
+ // TODO: init ();
+ netdb_initialise ();
+ // TODO: cpu_add_closure (X);
+ // TODO: cpu_add_closure (Y);
+ // TODO: cpu_add_closure (Z);
+ bottom_critical_region_end ();
+ top_network_online (); // TODO: Should be called from bottom!
+ while (true) {
+ jobhopper ();
+ bottom_sleep_prepare ();
+ if (cur_prio == CPU_PRIO_ZERO) {
+ bottom_sleep_commit (SLEEP_SNOOZE);
+ }
+ }
+}
+
printf ("Jobhopper ends.\n");
}
-
-/* The main operational loop for the CPU. Try to run code, and when
- * nothing remains to be done, stop to wait for interrupts.
- */
-void top_main (void) {
- // TODO: init ();
- netdb_initialise ();
- // TODO: cpu_add_closure (X);
- // TODO: cpu_add_closure (Y);
- // TODO: cpu_add_closure (Z);
- bottom_critical_region_end ();
- top_network_online (); // TODO: Should be called from bottom!
- while (true) {
- jobhopper ();
- bottom_sleep_prepare ();
- if (cur_prio == CPU_PRIO_ZERO) {
- bottom_sleep_commit (SLEEP_SNOOZE);
- }
- }
-}
-
}
}
switch (boot_state) {
+ case NCS_DHCPV4: // A few LAN DHCPv4 attempts
+ if (!have_ipv4 ()) {
+ get_dhcp4_lease ();
+ delay = TIME_MSEC(5000);
+ break;
+ }
+ boot_state = NCS_6BED4;
+ boot_retries = 2;
+ // Continue into NCS_6BED4 for 6bed4 autoconf
case NCS_6BED4: // A few 6BED4 attempts over IPv4
if (!have_ipv6 ()) {
ip6binding [0].ip4binding = &ip4binding [0];
return true;
}
solicit_router ();
- delay = 500 * TIME_MSEC;
+ delay = TIME_MSEC(500);
break;
case NCS_DHCPV6: // A few LAN DHCPv6 attempts
if (have_ipv6 ()) {
return true;
}
get_dhcp6_lease ();
- delay = 1000 * TIME_MSEC;
- break;
- case NCS_DHCPV4: // A few LAN DHCPv4 attempts
- if (have_ipv4 ()) {
- return true;
- }
- get_dhcp4_lease ();
- delay = 5000 * TIME_MSEC;
+ delay = TIME_MSEC(1000);
break;
case NCS_ONLINE: // Stable online performance
return true;
case NCS_OFFLINE: // Await top_network_online()
break;
case NCS_PANIC: // Not able to bootstrap anything
- // delay = 15 * 60 * TIME_MSEC;
+ // delay = TIME_MIN(15);
// break;
return true;
default:
#include <stdint.h>
#include <stdbool.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
#include <netinet/icmp6.h>
+#include <netinet/ether.h>
+#include <net/if_arp.h>
#include <config.h>
*/
-/* Declare an efficient network packet analysis function:
+
+/* Analyse incoming network packets.
*
- * intptr_t netinput (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
- * ...possibly assembly...
- * }
+ * This is one big switch statement that returns how to
+ * process a packet, or NULL if it is to be dropped.
+ * Instead of proper nesting, which would be a bit
+ * overzealously indented and therefore confusing, a
+ * less structured approach is used, with portions of
+ * the function analysing particular headers and jumping
+ * at such parts of the function with a goto statement.
+ * Surely goto is bad structure, but some situations
+ * really call for it -- like this one.
*
- * TODO: Check lengths
- * TODO: Verify checksums
+ * The utility functions below _can_ be overridden in
+ * config.h to benefit from the more specific knowledge
+ * for specifically known targets.
*/
-BPF_BEGIN(netinput)
-
- return NULL; //TODO// Early bail-out
-
- STX_MEM (MEM_ETHER_HEAD) // Store the ethernet header
- LDW_LEN ()
- ADD_REX ()
- STW_MEM (MEM_ALL_DONE)
-
-// IN: ETHER frame at X
-// OUT: ARP, IP4, IP6 frame at X=M[0]
-//
-// netin_ETHER ldw #14
-// add x
-// tax
-// ldh [x-2]
-// jeq #8100h, .1, .2 ; 802.1Q tag? => step 4 bytes
-// .1 ldw #4
-// add x
-// tax
-// ldh [x-2]
-// .2 stx M[0]
-// jeq #86DDh, netin_IP6_sel, .3
-// .3 jeq #0800h, netin_IP4_sel, .4
-// .4 jeq #0806h, netin_ARP_sel, netin_DROP
-
- LDW_LIT (14)
- ADD_REX ()
- LDX_ACC ()
- LDH_IDX (-2)
- JNE_LIT (0x8100, _ether_1)
- LDW_LIT (4)
- ADD_REX ()
- LDX_ACC ()
- LDH_IDX (-2)
-BPF_LABEL (_ether_1)
- STX_MEM (MEM_ETHER_PLOAD)
- JEQ_LIT (0x86dd, netin_IP6_sel)
- JEQ_LIT (0x0800, netin_IP4_sel)
- JEQ_LIT (0x0806, netin_ARP_sel)
- JMP_ALW (netin_DROP)
-
-
-// IN: ARP frame at X=M[0]
-// RET: ARP fn with frame in M[0], IPv4 src addr in M[1], IPv4 dst addr in M[2]
-//
-// netin_ARP_sel ldh [x+2] ; protocol type
-// jeq #0800h, .1, netin_DROP ; check IPv4
-// .1 ld [x+4] ; hwalen, protalen, cmd
-// stx M[0]
-// jeq #06040001, netin_ARPREQ, .2
-// .2 jeq #06040002, netin_ARPREPLY, netin_DROP
-// netin_ARPREQ return #net_arp_request
-// netin_ARPREPLY return #net_arp_reply
-
-BPF_LABEL(netin_ARP_sel)
- STX_MEM (MEM_ARP_HEAD)
- LDH_IDX (2)
- JNE_LIT (0x0800, netin_DROP)
- LDW_IDX (4)
- JEQ_LIT (0x06040001, netin_ARPREQ)
- JEQ_LIT (0x06040002, netin_ARPREPLY)
- JMP_ALW (netin_DROP)
-BPF_LABEL(netin_ARPREPLY)
- LDW_IDX (14)
- STW_MEM (MEM_IP4_SRC)
- LDW_IDX (24)
- STW_MEM (MEM_IP4_DST)
- RET_LIT (net_arp_reply)
-BPF_LABEL(netin_ARPREQ)
- LDW_IDX (14)
- STW_MEM (MEM_IP4_SRC)
- LDW_IDX (24)
- STW_MEM (MEM_IP4_DST)
- RET_LIT (netreply_arp_query)
-
-
-// IN: IP4 frame at X=M[0]
-// OUT: UDP4, ICMP4 at X+20=M[3]; M[1]=src.IP4, M[2]=dst.IP4
-// Assumption: No IPv4 option headers
-//
-// netin_IP4_sel ldb [x] ; version/headerlen
-// jeq #45h, .1, netin_DROP
-// .1 ld [x+12] ; src.IP4
-// st M[1]
-// ld [x+16] ; dst.IP4
-// st M[2]
-// ldx #20
-// add x
-// st M[3] ; IP4 payload address
-// tax
-// ldb [x-20+9] ; payload protocol
-// jeq #17, netin_UDP4_sel, .2
-// .2 jeq #1, netin_ICMP4_sel, netin_DROP
-
-BPF_LABEL(netin_IP4_sel)
- STX_MEM (MEM_IP4_HEAD)
- LDB_IDX (0)
- JNE_LIT (0x0045, netin_DROP)
- LDW_IDX (12)
- STW_MEM (MEM_IP4_SRC)
- LDW_IDX (16)
- STW_MEM (MEM_IP4_DST)
- LDW_LIT (20)
- ADD_REX ()
- STW_MEM (MEM_IP4_PLOAD)
- LDX_ACC ()
- LDB_IDX (-20+9)
- JEQ_LIT (17, netin_UDP4_sel)
- JEQ_LIT (1, netin_ICMP4_sel)
- JMP_ALW (netin_DROP)
-
-
-// IN: ICMP4 frame at X=M[3]
-// OUT: TODO
-//
-// netin_ICMP4_sel TODO
-
-BPF_LABEL(netin_ICMP4_sel)
- STX_MEM (MEM_ICMP4_HEAD)
- LDH_IDX (0) // type/code
- JEQ_LIT (8 << 8, netin_ICMP4_ping)
- RET_LIT (0)
-
-BPF_LABEL(netin_ICMP4_ping)
- RET_LIT (netreply_icmp4_echo_req)
-
-// IN: UDP4 frame at X=M[3]
-// OUT: 6BED4, DHCP4 at X+20+8=M[5]; M[4]=src.PORT|dst.PORT
-//
-// netin_UDP4_sel ld #8
-// add x
-// st M[5]
-// ld [x] ; src.PORT|dst.PORT
-// st M[4]
-// jeq #0e450e45h, netin_6BED4_sel, .1
-// .1 jeq #4344h, netin_DHCP4_sel, .2
-// .2 and #ffff0000h
-// jeq #00350000h, netin_DNS_sel, netin_DROP
-
-BPF_LABEL(netin_UDP4_sel)
- STX_MEM (MEM_UDP4_HEAD)
- LDW_LIT (8)
- ADD_REX ()
- LDX_ACC ()
- STX_MEM (MEM_UDP4_PLOAD)
- LDW_IDX (-8)
- STW_MEM (MEM_UDP4_PORTS)
- JEQ_LIT (0x0e450e45, netin_6BED4_sel)
- JEQ_LIT (0x00430044, netin_DHCP4_sel)
- AND_LIT (0xffff0000)
- JEQ_LIT (0x00350000, netin_DNS_sel)
- JMP_ALW (netin_DROP)
-
-
-// IN: DHCP4 frame at X=M[5]
-// OUT: Returns one of netreply_dhcp4_offer, netdb_dhcp4_ack, netdb_dhcp4_nak
-
-BPF_LABEL(netin_DHCP4_sel)
- STX_MEM (MEM_DHCP4_HEAD)
- LDW_LIT (236 + 4)
- ADD_REX ()
- LDX_ACC ()
- LDW_IDX (-4) // Magic cookie check
- JNE_LIT (0x63825363, netin_DROP)
-BPF_LABEL(netin_DHCP4_optparse)
- LDB_IDX (0)
- JEQ_LIT (255, netin_DROP)
- JEQ_LIT (0, netin_DHCP4_padding)
- JNE_LIT (53, netin_DHCP4_optskip)
- LDB_IDX (2)
- JEQ_LIT (2, netin_DHCP4_offer)
- JEQ_LIT (5, netin_DHCP4_ack)
- JEQ_LIT (6, netin_DHCP4_nak)
- JMP_ALW (netin_DROP) // Including for my b'casted DHCP4 discover
-BPF_LABEL(netin_DHCP4_padding)
- LDW_LIT (1)
- ADD_REX ()
- LDX_ACC ()
- JMP_ALW (netin_DHCP4_optparse)
-BPF_LABEL(netin_DHCP4_optskip)
- AND_LIT (0xff)
- ADD_LIT (2)
- ADD_REX ()
- LDX_ACC ()
- JMP_ALW (netin_DHCP4_optparse)
-BPF_LABEL(netin_DHCP4_offer)
- RET_LIT (netreply_dhcp4_offer)
-BPF_LABEL(netin_DHCP4_ack)
- RET_LIT (netdb_dhcp4_ack)
-BPF_LABEL(netin_DHCP4_nak)
- RET_LIT (netdb_dhcp4_nak)
-
-
-// IN: 6BED4 frame at X=M[5]
-// OUT: IP6 at X=M[6]
-// Note: M[1]=src.IP, M[2]=dst.IP, M[3]=IP4, M[4]=src.PORT|dst.PORT all nonzero
-//
-// netin_6BED4_sel ldx M[5] ; decapsulate IP6 package
-// jmp netin_IP6_sel_anysrc
-
-BPF_LABEL(netin_6BED4_sel)
- STX_MEM (MEM_UDP4_PLOAD)
- STX_MEM (MEM_6BED4_PLOAD)
- JMP_ALW (netin_IP6_sel_anysrc)
-
-
-// IN: IP6 frame at X
-// OUT: IP6 frame at X=M[6], UDP6 or ICMP6 at X+40
-//
-// netin_IP6_sel ld #0
-// st M[1] ; no src.IP4
-// st M[2] ; no dst.IP4
-// st M[3] ; no IP4 payload
-// st M[4] ; no UDP4 src.PORT|dst.PORT
-// netin_IP6sel__anysrc stx M[6] ; IP6 frame
-// ldb [x+0] ; version/trafficclass
-// and #f0h ; version/0
-// jeq #60h, .1, netin_DROP
-// .1 ldb [x+6] ; next header
-// jeq #17, netin_UDP6_sel, .2
-// .2 jeq #58, netin_ICMP6_sel, netin_DROP
-
-BPF_LABEL(netin_IP6_sel)
-#if 0
- LDW_LIT (0)
- STW_MEM (MEM_IP4_SRC)
- STW_MEM (MEM_IP4_DST)
- STW_MEM (MEM_IP4_PLOAD)
- STW_MEM (MEM_UDP4_PLOAD)
+#define forward(t) here += sizeof (t); fromhere -= sizeof (t);
+#define store(i, t) if (fromhere < sizeof (t)) return NULL; mem [i] = (t *) here;
+#define store_forward(i, t) store(i,t) forward(t)
+#ifndef get08
+# define get08(o) (here [o])
+#endif
+#ifndef get16
+# define get16(o) ((here [o] << 8) | here [o+1])
+#endif
+#ifndef get32
+# define get32(o) ((here [o] << 24) | (here [o+1] << 16) | (here [o+2] << 8) | here [o+3])
#endif
-BPF_LABEL(netin_IP6_sel_anysrc)
- STX_MEM (MEM_IP6_HEAD)
- LDB_LIT (40)
- ADD_REX ()
- LDX_ACC ()
- STX_MEM (MEM_IP6_PLOAD)
- LDB_IDX (-40)
- AND_LIT (0xf0)
- JNE_LIT (0x60, netin_DROP)
- LDB_IDX (-40+6)
- JEQ_LIT (17, netin_UDP6_sel)
- JEQ_LIT (58, netin_ICMP6_sel)
- JMP_ALW (netin_DROP)
-
-
-// IN: ICMP6 at X
-// OUT: TODO
-//
-// netin_ICMP6_sel: switch between alternative message types
-
-BPF_LABEL(netin_ICMP6_sel)
- STX_MEM (MEM_ICMP6_HEAD)
- LDH_IDX (0) // Fetch type, code
- // Ignore ND_ROUTER_SOLICIT << 8, netin_ICMP6_ROUTER_SOLICIT
- JEQ_LIT (ND_ROUTER_ADVERT << 8, netin_ICMP6_ROUTER_ADVERT)
- JEQ_LIT (ND_NEIGHBOR_SOLICIT << 8, netin_ICMP6_NEIGHBOUR_SOLICIT)
- JEQ_LIT (ND_NEIGHBOR_ADVERT << 8, netin_ICMP6_NEIGHBOUR_ADVERT)
- //TODO//JEQ_LIT (ND_REDIRECT << 8, netin_ICMP6_REDIRECT)
- JEQ_LIT (ICMP6_ECHO_REQUEST << 8, netin_ICMP6_ECHO_REQUEST)
- JEQ_LIT (ICMP6_ECHO_REPLY << 8, netin_ICMP6_ECHO_REPLY)
- JMP_ALW (netin_DROP)
-
-BPF_LABEL(netin_ICMP6_ROUTER_ADVERT)
- RET_LIT (netdb_router_advertised)
-
-// ND Neighbour Solicitation:
-// If aimed at me, respond automatically with Neigbour Advertisement
-BPF_LABEL(netin_ICMP6_NEIGHBOUR_SOLICIT)
- RET_LIT (netreply_icmp6_ngb_disc)
-
-BPF_LABEL(netin_ICMP6_NEIGHBOUR_ADVERT)
- RET_LIT (netdb_neighbour_advertised)
-
-BPF_LABEL(netin_ICMP6_ECHO_REQUEST)
- RET_LIT (netreply_icmp6_echo_req)
-
-BPF_LABEL(netin_ICMP6_ECHO_REPLY)
- JMP_ALW (netin_DROP) // TODO: Process if it is used for tests?
-
-
-// IN: UDP6 at X
-// OUT: RTP, RTCP, SIP, DHCP6, DNS, DNS_SD at X=M[8]; M[7]=src.PORT|dst.PORT
-// Note: RTP/RTCP is located at ports 8192..65535
-//
-// netin_UDP6_sel ld #48
-// add x
-// st M[8]
-// tax
-// ld [x-8+0] ; src.PORT|dst.PORT
-// jset #0000e000h, .1, .3 ; RTP/RTCP or other?
-// .1 jset #00000001h, netin_RTCP_sel, netin_RTP_sel
-// .2 jeq #02230222h, netin_DHCP6_sel, .3
-// .3 and #0000ffffh ; dst.PORT
-// jeq #5060, netin_SIP_sel, .4
-// .4 jeq #5353, netin_DNS_SD_sel, .5
-// .5 jeq #53, netin_DNS_sel, netin_DROP
-
-BPF_LABEL(netin_UDP6_sel)
- STX_MEM (MEM_UDP6_HEAD)
- LDW_LIT (8)
- ADD_REX ()
- STW_MEM (MEM_UDP6_PLOAD)
- LDX_ACC ()
- LDW_IDX (-8+0)
- STW_MEM (MEM_UDP6_PORTS)
- JMZ_LIT (0x0000e000, _UDP6_2)
- JMZ_LIT (0x00000001, netin_RTCP_sel)
- JMP_ALW (netin_RTP_sel)
-BPF_LABEL(_UDP6_2)
- AND_LIT (0x0000ffff)
- JEQ_LIT (546, netin_DHCP6_sel)
- JEQ_LIT (5060, netin_SIP_sel)
- JEQ_LIT (5353, netin_DNS_SD_sel)
- JEQ_LIT (53, netin_DNS_sel)
- JMP_ALW (netin_DROP)
-
-
-// IN: RTP at M[8]=X
-// OUT: net_rtp
-//
-// netin_RTP_sel return #net_rtp
-
-BPF_LABEL(netin_RTP_sel)
- STX_MEM (MEM_RTP_HEAD)
- RET_LIT (net_rtp)
-
-
-// IN: RTCP at M[8]=X
-// OUT: net_rtcp
-//
-// netin_RTCP_sel return #net_rtcp
-
-BPF_LABEL(netin_RTCP_sel)
- STX_MEM (MEM_RTCP_HEAD)
- RET_LIT (net_rtcp)
-
-
-// IN: SIP at M[8]=X
-// OUT: net_sip
-//
-// netin_SIP_sel return #net_sip
-
-BPF_LABEL(netin_SIP_sel)
- STX_MEM (MEM_SIP_HEAD)
- RET_LIT (net_sip)
-
-
-// IN: DHCP6 at M[8]=X
-// OUT: TODO
-
-BPF_LABEL(netin_DHCP6_sel)
- STX_MEM (MEM_DHCP6_HEAD)
- LDB_IDX (0)
- JEQ_LIT (2, netin_DHCP6_advertise)
- JEQ_LIT (7, netin_DHCP6_reply)
- JNE_LIT (10, netin_DROP)
-BPF_LABEL(netin_DHCP6_reconfigure)
- RET_LIT (netdb_dhcp6_reconfigure)
-BPF_LABEL(netin_DHCP6_reply)
- RET_LIT (netdb_dhcp6_reply)
-BPF_LABEL(netin_DHCP6_advertise)
- RET_LIT (netreply_dhcp6_advertise)
-
-
-// IN: DNS at M[8]=X
-// OUT: TODO
-
-BPF_LABEL(netin_DNS_sel)
- STX_MEM (MEM_DNS_HEAD)
- RET_LIT (0)
-
-
-// IN: DNS_SD at M[8]=X
-// OUT: TODO: Nogal wat gegokt over hoe MDNS/DNS_SD werkt
-//
-// netin_DNS_SD_sel ldh [x+2]
-// jset #8000h, .resp, .query
-//
-// .resp jset #0203h, .resp.ko, .resp.ok ; TC or RC!=OK
-// .resp.ko return #net_mdns_resp_error
-// .resp.ok jset #0400h, .resp.dyn, .resp.std
-// .resp.dyn return #net_mdns_resp_dyn
-// .resp.std return #net_mdns_resp_std
-//
-// .query xor #2000h ; std query flag
-// jset #3c00h, .query.ko, .query.ok
-// .query.ko return #net_mdns_query_error
-// .query.ok return #net_mdns_query_ok
-
-BPF_LABEL(netin_DNS_SD_sel)
- STX_MEM (MEM_DNSSD_HEAD)
- LDH_IDX (2)
- JMZ_LIT (0x8000, _DNS_query)
- JMZ_LIT (0x0203, _DNS_resp_ok)
- RET_LIT (net_mdns_resp_error)
-BPF_LABEL(_DNS_resp_ok)
- JMZ_LIT (0x0400, _DNS_resp_std)
- RET_LIT (net_mdns_resp_dyn)
-BPF_LABEL(_DNS_resp_std)
- RET_LIT (net_mdns_resp_std)
-
-BPF_LABEL(_DNS_query)
- XOR_LIT (0x2000)
- JMZ_LIT (0x3c00, _DNS_query_ok)
- RET_LIT (net_mdns_query_error)
-BPF_LABEL(_DNS_query_ok)
- RET_LIT (net_mdns_query_ok)
-
-
-// Note: Return a panic result, intending to cause a silent frame drop.
-// No explicitly communicated error message should jump here, only
-// frames that match no known pattern should end up here.
-//
-// netin_DROP return #0 ; request frame drop
-
-BPF_LABEL(netin_DROP)
- RET_LIT (0)
-
-
-// End of the BPF-styled assembly code
-//
-BPF_END()
+intptr_t netinput (uint8_t *pkt, uint16_t pktlen, intptr_t *mem) {
+
+ register uint8_t *here = pkt;
+ register uint16_t fromhere = pktlen;
+
+ //
+ // Store the end of the entire packet
+ mem [MEM_ALL_DONE] = &pkt [pktlen];
+
+ //
+ // Store the ethernet header
+ uint16_t ethertp = get16 (12);
+ if (ethertp == 0x8100) {
+ struct ethhdrplus { struct ethhdr std; uint8_t ext8021q [4]; };
+ store_forward (MEM_ETHER_HEAD, struct ethhdrplus);
+ ethertp = get16 (16);
+ } else {
+ store_forward (MEM_ETHER_HEAD, struct ethhdr);
+ }
+ //
+ // Jump, depending on the ethernet type
+ switch (ethertp) {
+ case 0x86dd: goto netin_IP6_sel;
+ case 0x0800: goto netin_IP4_sel;
+ case 0x0806: goto netin_ARP_sel;
+ default: return NULL;
+ }
+
+ //
+ // Accept ARP reply and query messages translating IPv4 to MAC
+ uint16_t arpproto;
+netin_ARP_sel:
+ arpproto = get16 (2);
+ if (arpproto != 0x0800) return NULL;
+ store (MEM_ARP_HEAD, struct arphdr);
+ mem [MEM_IP4_SRC] = get32 (14);
+ mem [MEM_IP4_DST] = get32 (24);
+ uint32_t arpdetails = get32 (4);
+ //
+ // Decide what to return based on the ARP header contents
+ switch (arpdetails) {
+ case 0x06040001: return net_arp_reply;
+ case 0x06040002: return net_arp_query;
+ default: return NULL;
+ }
+
+ //
+ // Decide what IPv4 protocol has come in
+netin_IP4_sel:
+ store (MEM_IP4_HEAD, struct iphdr);
+ if (get08 (0) != 0x45) return NULL;
+ mem [MEM_IP4_SRC] = get32 (12);
+ mem [MEM_IP4_DST] = get32 (15);
+ uint8_t ip4_ptype = get08 (9);
+ forward (struct iphdr);
+ mem [MEM_IP4_PLOAD] = here;
+ //
+ // Jump to a handler for the payload type
+ switch (ip4_ptype) {
+ case 17: goto netin_UDP4_sel;
+ case 1: goto netin_ICMP4_sel;
+ default: return NULL;
+ }
+
+ //
+ // Decide how to handle ICMP4
+ uint16_t icmp4_type_code;
+netin_ICMP4_sel:
+ icmp4_type_code = get16 (0);
+ switch (icmp4_type_code) {
+ case 8 << 8: return netreply_icmp4_echo_req;
+ default: return NULL;
+ }
+
+ //
+ // Decide how to handle UDP4
+netin_UDP4_sel:
+ store (MEM_UDP4_HEAD, struct udphdr);
+ uint16_t udp4_src = mem [MEM_UDP4_SRC_PORT] = get16 (0);
+ uint16_t udp4_dst = mem [MEM_UDP4_DST_PORT] = get16 (2);
+ forward (struct udphdr);
+ mem [MEM_UDP4_PLOAD] = here;
+ //
+ // Choose a handler based on port
+ if (udp4_src == 3653) goto netin_6BED4_sel;
+ if ((udp4_src == 67) && (udp4_dst == 68)) goto netin_DHCP4_sel;
+ if (udp4_dst == 53) goto netin_DNS_sel;
+ return NULL;
+
+ //
+ // Handle incoming DHCP4 traffic
+netin_DHCP4_sel:
+ store (MEM_DHCP4_HEAD, uint8_t);
+ if (fromhere < 236 + 4) return NULL;
+ uint32_t dhcp4_magic_cookie = get32 (236);
+ if (dhcp4_magic_cookie != 0x63825363) return NULL; // TODO: BOOTP?
+ here += 236 + 4;
+ fromhere -= 236 + 4;
+ //
+ // Parse DHCP4 options
+ while (true) {
+ uint8_t dhcp4_option = get08 (0);
+ if (dhcp4_option != 0) {
+ if (2 + get08 (1) > fromhere) {
+ return NULL;
+ }
+ }
+ switch (dhcp4_option) {
+ case 255: // Termination, not run into an offer
+ return NULL;
+ case 0: // Padding
+ here++;
+ continue;
+ case 53: // DHCP4_offer
+ switch (get08 (2)) {
+ case 2: return netreply_dhcp4_offer;
+ case 5: return netdb_dhcp4_ack;
+ case 6: return netdb_dhcp4_nak;
+ default: return NULL;
+ }
+ default:
+ here += 2 + here [1];
+ break;
+ }
+ }
+
+ //
+ // Handling 6BED4 tunnelled traffic
+netin_6BED4_sel:
+ mem [MEM_6BED4_PLOAD] = mem [MEM_UDP4_PLOAD];
+ // Code follows immediately below: goto netin_IP6_sel;
+
+ //
+ // Handle incoming IP6 traffic
+netin_IP6_sel:
+ if ((get08 (0) & 0xf0) != 0x60) return NULL;
+ store (MEM_IP6_HEAD, struct ip6_hdr);
+ uint8_t ip6_nxthdr = get08 (6);
+ forward (struct ip6_hdr);
+ store (MEM_IP6_PLOAD, uint8_t);
+ //
+ // Choose a handler based on the next header
+ switch (ip6_nxthdr) {
+ case 17: goto netin_UDP6_sel;
+ case 58: goto netin_ICMP6_sel;
+ default: return NULL;
+ }
+
+ //
+ // Hande incoming ICMP6 traffic
+netin_ICMP6_sel:
+ store (MEM_ICMP6_HEAD, struct icmp6_hdr);
+ uint16_t icmp6_type_code = get16 (0);
+ switch (icmp6_type_code) {
+ case ND_ROUTER_ADVERT << 8: return (fromhere < 16)? NULL: netdb_router_advertised;
+ case ND_NEIGHBOR_SOLICIT << 8: return (fromhere < 24)? NULL: netreply_icmp6_ngb_disc;
+ case ND_NEIGHBOR_ADVERT << 8: return (fromhere < 24)? NULL: netdb_neighbour_advertised;
+ case ND_REDIRECT << 8: return (fromhere < 40)? NULL: NULL; /* TODO */
+ case ICMP6_ECHO_REQUEST << 8: return (fromhere < 8)? NULL: netreply_icmp6_echo_req;
+ case ICMP6_ECHO_REPLY << 8: return (fromhere < 8)? NULL: NULL; /* Future option */
+ default: return NULL;
+ }
+
+ //
+ // Decide how to handle incoming UDP6 traffic
+netin_UDP6_sel:
+ store (MEM_UDP6_HEAD, struct udphdr);
+ mem [MEM_UDP6_PLOAD] = here + sizeof (struct udphdr);
+ uint16_t udp6_src = mem [MEM_UDP6_SRC_PORT] = get16 (0);
+ uint16_t udp6_dst = mem [MEM_UDP6_DST_PORT] = get16 (2);
+ here += sizeof (struct udphdr);
+ //
+ // Port mapping:
+ // udp6_dst >= 0x4000 are RTP (even ports) or RTCP (odd ports)
+ // udp6_dst == 546 is DHCP6
+ // udp6_dst == 5060 is SIP
+ // udp6_dst == 5353 is DNS-SD
+ // udp6_dst == 53 is DNS
+ if (udp6_dst >= 0x4000) {
+ if (udp6_dst & 0x0001) {
+ mem [MEM_RTP_HEAD] = here;
+ return net_rtp;
+ } else {
+ return net_rtcp;
+ }
+ } else if (udp6_dst == 5060) {
+ mem [MEM_SIP_HEAD] = here;
+ return net_sip;
+ } else if (udp6_dst == 5353) {
+ goto netin_DNSSD_sel;
+ } else if (udp6_dst == 53) {
+ goto netin_DNS_sel;
+ } else if (udp6_dst == 546) {
+ goto netin_DHCP6_sel;
+ } else {
+ return NULL;
+ }
+
+
+netin_DHCP6_sel:
+ store (MEM_DHCP6_HEAD, uint8_t);
+ uint8_t dhcp6_tag = *here;
+ switch (dhcp6_tag) {
+ case 2: return netreply_dhcp6_advertise;
+ case 7: return netdb_dhcp6_reply;
+ case 10: return netdb_dhcp6_reconfigure;
+ default: return NULL;
+ }
+
+netin_DNS_sel:
+ store (MEM_DNS_HEAD, uint8_t);
+ return NULL; // TODO: Actually, split/process DNS
+
+netin_DNSSD_sel:
+ store (MEM_DNSSD_HEAD, uint8_t);
+ uint16_t dnssd_flags = get16 (2);
+ if (dnssd_flags & 0x8000) {
+ // Response
+ if (dnssd_flags & 0x0203) {
+ return net_mdns_resp_error;
+ } else if (dnssd_flags & 0x0400) {
+ return net_mdns_resp_dyn;
+ } else {
+ return net_mdns_query_ok;
+ }
+ } else {
+ // Query
+ if ((dnssd_flags ^ 0x2000) & 0x3c00) {
+ return net_mdns_query_error;
+ } else {
+ return net_mdns_query_ok;
+ }
+ }
+
+ // Finally, a catchall that rejects anything that makes it to here
+ return NULL;
+}
ip4out->frag_off = htons (0x4000); // Don't fragment
ip4out->saddr = ip4in->daddr;
ip4out->daddr = ip4in->saddr;
- mem [MEM_IP4_HEAD] = (uint32_t) ip4out;
+ mem [MEM_IP4_HEAD] = (uintptr_t) ip4out;
return &pout [sizeof (struct iphdr)];
}
uint8_t *netreply_udp4 (uint8_t *pout, intptr_t *mem) {
pout = netreply_ip4 (pout, mem);
struct udphdr *udp = (struct udphdr *) pout;
- udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
- udp->dest = htons (mem [MEM_UDP4_PORTS] >> 16);
+ udp->source = htons (mem [MEM_UDP4_DST_PORT]);
+ udp->dest = htons (mem [MEM_UDP4_SRC_PORT]);
mem [MEM_UDP4_HEAD] = (intptr_t) udp;
return &pout [sizeof (struct udphdr)];
}
mem [MEM_IP4_SRC] = htonl (ip4_6bed4);
pout = netreply_ip4 (pout, mem);
struct udphdr *udp = (struct udphdr *) pout;
- udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
+ udp->source = htons (mem [MEM_UDP4_DST_PORT]);
udp->dest = htons (3653);
mem [MEM_6BED4_PLOAD] =
mem [MEM_UDP4_HEAD] = (intptr_t) udp;
uint8_t *netreply_udp6 (uint8_t *pout, intptr_t *mem) {
pout = netreply_ip6 (pout, mem);
struct udphdr *udp = (struct udphdr *) pout;
- udp->source = htons (mem [MEM_UDP6_PORTS] & 0xffff);
- udp->dest = htons (mem [MEM_UDP6_PORTS] >> 16);
+ udp->source = htons (mem [MEM_UDP6_DST_PORT]);
+ udp->dest = htons (mem [MEM_UDP6_SRC_PORT]);
mem [MEM_UDP6_HEAD] = (intptr_t) udp;
return &pout [sizeof (struct udphdr)];
}
// TODO: Setup MEM_ETHER_DST with router's address
pout = netsend_ip4 (pout, mem);
struct udphdr *udp = (struct udphdr *) pout;
- udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
- udp->dest = htons (mem [MEM_UDP4_PORTS] >> 16);
+ udp->source = htons (mem [MEM_UDP4_SRC_PORT]);
+ udp->dest = htons (mem [MEM_UDP4_DST_PORT]);
mem [MEM_UDP4_HEAD] = (intptr_t) udp;
return &pout [sizeof (struct udphdr)];
}
// TODO: Setup MEM_ETHER_DST with router's address
pout = netsend_ip6 (pout, mem);
struct udphdr *udp = (struct udphdr *) pout;
- udp->source = htons (mem [MEM_UDP6_PORTS] & 0xffff);
- udp->dest = htons (mem [MEM_UDP6_PORTS] >> 16);
+ udp->source = htons (mem [MEM_UDP6_SRC_PORT]);
+ udp->dest = htons (mem [MEM_UDP6_DST_PORT]);
mem [MEM_UDP6_HEAD] = (intptr_t) udp;
return &pout [sizeof (struct udphdr)];
}
/* Send a DHCPv4 DISCOVER packet to initiatie IPv4 LAN configuration.
*/
uint8_t *netsend_dhcp4_discover (uint8_t *pout, intptr_t *mem) {
- mem [MEM_UDP4_PORTS] = 0x00430044;
+ mem [MEM_UDP4_SRC_PORT] = 68;
+ mem [MEM_UDP4_DST_PORT] = 67;
mem [MEM_IP4_DST] = 0xffffffff;
mem [MEM_ETHER_DST] = (intptr_t) ether_broadcast;
pout = netsend_udp4 (pout, mem);
/* Send a DHCPv6 SOLICIT packet to initiatie native IPv6 configuration.
*/
uint8_t *netsend_dhcp6_solicit (uint8_t *pout, intptr_t *mem) {
- mem [MEM_UDP6_PORTS] = 0x02230222;
+ mem [MEM_UDP6_SRC_PORT] = 546;
+ mem [MEM_UDP6_DST_PORT] = 547;
mem [MEM_BINDING6] = (intptr_t) binding_linklocal;
mem [MEM_IP6_DST] = (intptr_t) ip6_multicast_all_dhcp6_servers;
mem [MEM_ETHER_DST] = (intptr_t) ether_multicast_all_dhcp6_servers;
* time and then fall asleep.
*/
void zero_start (void) {
- timer_start (&zero_sleeptimer, 60 * TIME_SEC, zero_timeout);
+ timer_start (&zero_sleeptimer, TIME_MIN(1), zero_timeout);
}
#
-mainmenu "Configuration for firmly.0cpm SIP telephony"
+mainmenu "Configure 0cpm Firmerware for SIP telephony"
-choice
- prompt "Target platform"
- default TARGET_LINUX_RAWSOCK
+# 0. Meta configuration
+source "src/target/Kconfig.meta"
-config TARGET_AVM_FRITZBOX
- depends on TODO_IMPLEMENT_FIRST
- bool "AVM Fritz!Box"
- help
- Depending on the model, AVM Fritz!Box can use any of a variety
- of telephony chips. The firmware will build a program that
- can be incorporated into Freetz (see http://freetz.org/ for
- details).
+# 1. Brand selection
+source "src/target/Kconfig.brand"
-# config TARGET_GRANDSTREAM_HANDYTONE
-# config TARGET_GRANDSTREAM_BUDGETONE
-# config TARGET_GRANDSTREAM_GXP
+# 2. Model within brand
+source "src/target/Kconfig.model"
-# config TARGET_LINKSYS_SPA3000
-# config TARGET_LINKSYS_SPA9xx
-
-config TARGET_LINUX_RAWSOCK
- depends on TODO_IMPLEMENT_FIRST
- bool "Linux desktop"
- select TARGET_POSIX_RAWSOCK
- help
- This is a platform intended to run on the same platform as
- used for building. It is built on a raw socket, so it does
- not require IPv6 support in the kernel. It will obtain its
- own network leases, so it should be tested for non-interference
- if any other software is run on the same platform.
-
- Once built, run the command src/target/rawsock/firmly0cpm.bin
- on your current platform. It will configure itself automatically.
-
- TODO: sound devices? keyboard? display?
-
- TODO: Demo entry. Not implemented yet.
-
-config TARGET_LINUX_TUNTEST
- bool "Linux tunnel device"
- help
- Test and demonstration target intended for development.
-
- This creates a tunnel interface behind which the firmly.0cpm
- firmware is working. You can route/bridge/filter/simulate
- the surrounding network in any way you like.
-
- Once built, run the command src/target/tuntest/firmly0cpm.bin
- on your current platform. It will configure itself automatically.
-
- TODO: sound devices? keyboard? display?
-
-config TARGET_SIEMENS_GIGASET
- depends on TODO_IMPLEMENT_FIRST
- bool "Siemens Gigaset xnnnIP"
- help
- The Siemens Gigaset platform has DECT/SIP phones with numbers
- like C470IP or A580IP. Important in this is the "IP" postfix.
- There has been a short-lived clone from Target, the DIP450.
-
- The platforms contain LGPL-licensed software so they permit
- uploading new firmware from their web interface.
-
- Once built, upload src/target/gigaset/firmly0cpm.bin to a
- webserver and set the firmware location in your phone to the
- proper URL to migrate to the new platform.
-
- TODO: Demo entry. Not implemented yet.
-
-config TARGET_SMC_WSP100_DSP200
- depends on TODO_IMPLEMENT_FIRST
- bool "SMC WSP100, WSKP100, DSP200"
- help
- This covers the wireless models WSP100 and WSKP100, as well
- as the table model DSP200. The WSKP100 is a special version
- that runs Skype, not SIP. The space in these devices varies.
-
- This DSP200 seems to resist configuration with any common SIP
- telephony service. You can revive the phone by compiling the
- firmly.0cpm platform for it.
-
- Once built, install by ...TODO...
-
- TODO: Demo entry. Not implemented yet.
-
-endchoice
+# 3. Hardware platform for model
+source "src/target/Kconfig.platform"
+# 4. Intended functionality
+source "src/function/Kconfig"
source "src/net/Kconfig"
source "src/phone/Kconfig"
--- /dev/null
+# Manufacturers / brands
+
+choice
+ prompt "1. Hardware manufacturer"
+ default TARGET_GRANDSTREAM
+
+config TARGET_GRANDSTREAM
+ bool "Grandstream"
+ help
+ Grandstream phones, shown on http://www.grandstream.com/
+ are built around Texas Instruments' DSP processor ranges
+ TMS320VC5401 and TMS320VC5501. You would have to scratch
+ paint off of the DSP before being able to read that, but
+ given the model it is possible to establish the target.
+
+ Reverse engineering information is available on
+ http://devel.0cpm.org/reverse/grandstream/
+
+config TARGET_POSIX
+ bool "POSIX platforms"
+ help
+ Not all firmware runs as a standalone image. Several run
+ on top of POSIX-compliant platforms like Linux.
+ Select this target to include those platforms.
+
+config TARGET_APPLE
+ bool "Apple"
+ depends on UNIMPLEMENTED
+ help
+ The Apple platforms run on top of Darwin, their own brand of
+ FreeBSD. This target sets up potential Apple targets.
+
+config TARGET_SIPURA
+ bool "Sipura/Linksys/Cisco SPA"
+ depends on UNIMPLEMENTED
+ help
+
+config TARGET_FRITZBOX
+ bool "AVM Fritz!Box"
+ depends on UNIMPLEMENTED
+ help
+ Depending on the model, AVM Fritz!Box can use any of a variety
+ of telephony chips. The firmware will build a program that
+ can be incorporated into Freetz (see http://freetz.org/ for
+ details).
+
+config TARGET_GIGASET
+ bool "Siemens Gigaset xnnnIP"
+ depends on UNIMPLEMENTED
+ help
+ The Siemens Gigaset platform has DECT/SIP phones with numbers
+ like C470IP or A580IP. Important in this is the "IP" postfix.
+ There has been a short-lived clone from Target, the DIP450.
+
+ The platforms contain LGPL-licensed software so they permit
+ uploading new firmware from their web interface.
+
+ Once built, upload src/target/gigaset/firmly0cpm.bin to a
+ webserver and set the firmware location in your phone to the
+ proper URL to migrate to the new platform.
+
+ TODO: Demo entry. Not implemented yet.
+
+endchoice
+
--- /dev/null
+# Siemens/Gigaset phone models
+
+choice
+ prompt "2. Siemens Gigaset phone models"
+ depends on TARGET_GIGASET
+ default TARGET_GIGASET_A580IP
+
+config TARGET_GIGASET_CHAGALL
+ bool "Gigaset A580IP, C470IP, xxxIP"
+ select PLATFORM_ARM
+ select PLATFORM_ARM_BLUEBIRD
+ help
+ Siemens Gigaset is a platform for DECT in general. The models
+ that end in "IP" are the ones that implement SIP functionality.
+
+endchoice
--- /dev/null
+# Grandstream phone models
+
+choice
+ prompt "2. Grandstream phone models"
+ depends on TARGET_GRANDSTREAM
+ default TARGET_GRANDSTREAM_BT20x
+
+config TARGET_GRANDSTREAM_BT10x
+ bool "Budgetone 100, 101, 102"
+ select PLATFORM_TIC54x
+ help
+ Budgetone is the entry-level speaker phone from Grandstream.
+ The older models were numbered 10x, the newer ones are 20x.
+ These older models have one or two 10 Mbps ethernet jacks.
+
+ They look like simple phones, with no line selection facilities
+ beyond a simple flash button. They do however have buttons for
+ conferences and call transfer and hold.
+
+config TARGET_GRANDSTREAM_BT20x
+ bool "Budgetone 200, 201"
+ select PLATFORM_TIC54x
+ help
+ Budgetone is the entry-level speaker phone from Grandstream.
+ The older models were numbered 10x, the newer ones are 20x.
+ These newer models have one or two 100 Mbps ethernet jacks.
+
+ They look like simple phones, with no line selection facilities
+ beyond a simple flash button. They do however have buttons for
+ conferences and call transfer and hold.
+
+config TARGET_GRANDSTREAM_GXP20xx
+ bool "GXP 2000, 2010, 2020"
+ depends on UNIMPLEMENTED
+ select PLATFORM_TIC55x
+
+endchoice
+
--- /dev/null
+# Meta-configuration
+
+menu "0. Configuration meta parameters"
+
+config DEVEL
+ bool "Show development build options"
+ default n
+ select FUNCTION_DEVEL_NETCONSOLE
+ help
+ Aside from production builds, there are various intermediate
+ settings that are helpful while reverse engineering, testing
+ and debugging. This option shows those additional builds.
+
+ A few examples of added facilities: very basic programs that
+ basic I/O (hook contact, LED, that sort of thing) without
+ assuming a network driver; network driver testing; and of
+ course debugging output to a platform's console interface.
+
+ Select this option if you are developing on the 0cpm firmerware.
+
+config UNIMPLEMENTED
+ bool "Include incomplete build options"
+ depends on DEVEL
+ default n
+ help
+ This option selects platforms and options whose development
+ has not yet been completed.
+
+ Select this option while developing on such incomplete code.
+ It is possible to checkin such code as long as the Kconfig
+ options include "depends on UNIMPLEMENTED"
+
+config PLATFORM_PREFIX
+ string "Toolchain prefix directory"
+ default ""
+
+config PLATFORM_BIN_PATH
+ string "Path to toolchain binaries"
+ default "$PLATFORM_PREFIX/bin"
+
+config PLATFORM_LIB_PATH
+ string "Path to toolchain libraries"
+ default "$PLATFORM_PREFIX/include"
+
+config PLATFORM_INCLUDE_PATH
+ string "Path to toolchain include files"
+ default "$PLATFORM_PREFIX/include"
+
+endmenu
+
--- /dev/null
+# Model selection (includes with a separate setup for each brand)
+
+source "src/target/Kconfig.posix"
+source "src/target/Kconfig.grandstream"
+source "src/target/Kconfig.gigaset"
+#TODO# source "src/target/Kconfig.fritzbox"
+#TODO# source "src/target/Kconfig.sipura"
+source "src/target/Kconfig.smc"
+
--- /dev/null
+# Platform-specific settings (platforms are usually a SoC or CPU type)
+
+choice
+ prompt "3. Hardware platform (SoC/CPU/DSP class)"
+
+config PLATFORM_LOCAL
+ bool "Local POSIX system"
+ depends on TARGET_POSIX
+ default y
+
+config PLATFORM_TIC54x
+ bool "tic54x"
+ depends on TARGET_GRANDSTREAM_BT10x
+ default y
+
+config PLATFORM_TIC55x
+ bool "tic55x"
+ depends on TARGET_GRANDSTREAM_BT20x || TARGET_GRANDSTREAM_GXP20xx
+ default y
+
+endchoice
--- /dev/null
+# POSIX-based target platforms
+
+choice
+ prompt "2. POSIX-based phone targets"
+ depends on TARGET_POSIX
+ default TARGET_LINUX_RAWSOCK
+
+config TARGET_LINUX_RAWSOCK
+ bool "Linux desktop"
+ depends on UNIMPLEMENTED
+ select TARGET_POSIX_RAWSOCK
+ help
+ This is a platform intended to run on the same platform as
+ used for building. It is built on a raw socket, so it does
+ not require IPv6 support in the kernel. It will obtain its
+ own network leases, so it should be tested for non-interference
+ if any other software is run on the same platform.
+
+ Once built, run the command src/target/rawsock/firmly0cpm.bin
+ on your current platform. It will configure itself automatically.
+
+ TODO: sound devices? keyboard? display?
+
+ TODO: Demo entry. Not implemented yet.
+
+config TARGET_LINUX_TUNTEST
+ bool "Linux tunnel device"
+ depends on DEVEL
+ help
+ Test and demonstration target intended for development.
+
+ This creates a tunnel interface behind which the firmly.0cpm
+ firmware is working. You can route/bridge/filter/simulate
+ the surrounding network in any way you like.
+
+ Once built, run the command src/target/tuntest/firmly0cpm.bin
+ on your current platform. It will configure itself automatically.
+
+ TODO: sound devices? keyboard? display?
+
+endchoice
--- /dev/null
+# SMC phone models -- quite a variety because they sell prototypes as products
+
+choice
+ prompt "2. SMC phone models"
+ depends on TARGET_SMC
+ default TARGET_SMC_DSP20x
+
+config TARGET_SMC_DSP20x
+ bool "SMC DSP200"
+ select PLATFORM_CM5000LF
+ help
+ The SMC DSP200 and DSP205 models are actually prototypes from
+ CrystalMedia, the fabless producer of the CM5000LF SoC in
+ these phones. Strange as that may sound, the phones are
+ actually more powerful than quite a few others.
+
+ The firmware in the phones is notoriously hard to configure.
+ But it does include testing code, which allows for a lot of
+ control. The 4-line serial interface runs at 57600 8N1 and
+ the pins are [3V3], TxD, RxD, GND.
+
+ After building the firmware image, it can be uploaded over
+ this serial link. First, select ic.img by pressing Enter
+ over the link in the first 3 seconds after testing RAM.
+ Then use the Download User Program option.
+
+ Future versions of this firmware are probably going to
+ look as firmware updates: a gzipped fcodec.out, gzipped
+ ic.img and gzipped user program named voip.img, all
+ attached. Finally, a CRC-32 checksum over all those,
+ appended as 8 uppercase hex characters. Interestingly,
+ the GPL may require the rest to be recoded for that to
+ be distributable.
+
+endchoice
# Sort each target's object files into objs-bottom-y or objs-bottom-n:
#
-objs-bottom-$(CONFIG_TARGET_LINUX_TUNTEST) += src/driver/util/linuxtuntest.o
+objs-bottom-$(CONFIG_TARGET_LINUX_TUNTEST) += src/driver/util/linuxtuntest.o src/driver/util/ledsimu.o
metavars-$(CONFIG_TARGET_LINUX_TUNTEST) += HAVE_NET_LEADER=4
-includes-$(CONFIG_TARGET_LINUX_TUNTEST) += src/driver/util/linuxtuntest.h
+includes-$(CONFIG_TARGET_LINUX_TUNTEST) += bottom/linuxtuntest.h
+
+#
+# Platform-dependent specifics
+#
+ifdef CONFIG_PLATFORM_LOCAL
+include src/target/Makefile.local
+endif
+
+ifdef CONFIG_PLATFORM_TIC54x
+include src/target/Makefile.tic54x
+endif
+
+ifdef CONFIG_PLATFORM_TIC55x
+include src/target/Makefile.tic55x
+endif
+
/* The maximum number of supported handset */
-#define HAS_HANDSETS 1
+#define HAVE_HANDSETS 1
/* Keyboard settings */
#undef DETECTS_DTMF
-#define HAS_KBD_STARHASH 1
-#define HAS_KBD_ABCD 0
-#define HAS_KBD_FLASH 0
-#define HAS_KBD_LINES 6
-#define HAS_KBD_SOFT_FUNCTION 4
-#ifndef HAS_KBD_SIDECARS
-# define HAS_KBD_SIDECARS 0
+#define HAVE_KBD_STARHASH 1
+#define HAVE_KBD_ABCD 0
+#define HAVE_KBD_FLASH 0
+#define HAVE_KBD_LINES 6
+#define HAVE_KBD_SOFT_FUNCTION 4
+#ifndef HAVE_KBD_SIDECARS
+# define HAVE_KBD_SIDECARS 0
#endif
-#define HAS_KBD_GENERIC ((HAS_KBD_SIDECARS)*32)
-#define HAS_KBD_VOICEMAIL 1
-#define HAS_KBD_MENU 1
-#define HAS_KBD_UPDOWN 1
-#define HAS_KBD_LEFTRIGHT 1
-#define HAS_KBD_MUTE 1
-#define HAS_KBD_CONFERENCE 0
-#define HAS_KBD_HOLD 1
-#define HAS_KBD_TRANSFER 0
-#define HAS_KBD_PHONEBOOK 0
-#define HAS_KBD_VOLUPDOWN 1
-#define HAS_KBD_HEADSET 1
-#define HAS_KBD_SPEAKER 1
-#define HAS_KBD_HEADSET 1
-#define HAS_KBD_MISSEDCALLS 0
-#define HAS_KBD_REDIAL 0
+#define HAVE_KBD_GENERIC ((HAVE_KBD_SIDECARS)*32)
+#define HAVE_KBD_VOICEMAIL 1
+#define HAVE_KBD_MENU 1
+#define HAVE_KBD_OK 0
+#define HAVE_KBD_ENTER 0
+#define HAVE_KBD_UPDOWN 1
+#define HAVE_KBD_LEFTRIGHT 1
+#define HAVE_KBD_MUTE 1
+#define HAVE_KBD_CONFERENCE 0
+#define HAVE_KBD_HOLD 1
+#define HAVE_KBD_TRANSFER 0
+#define HAVE_KBD_PHONEBOOK 0
+#define HAVE_KBD_VOLUPDOWN 1
+#define HAVE_KBD_HEADSET 1
+#define HAVE_KBD_SPEAKER 1
+#define HAVE_KBD_HANDSET 1
+#define HAVE_KBD_MISSEDCALLS 0
+#define HAVE_KBD_REDIAL 0
/* Light settings */
-#define HAS_LED_MESSAGE 1
-#define HAS_LED_LINEKEYS 1
-#define HAS_LED_GENERIC 1
-#define HAS_LED_MUTE 1
-#define HAS_LED_HANDSET 1
-#define HAS_LED_HEADSET 1
-#define HAS_LED_SPEAKERPHONE 1
-#define HAS_LED_BACKLIGHT 1
+#define HAVE_LED_MESSAGE 1
+#define HAVE_LED_LINEKEYS 1
+#define HAVE_LED_GENERIC 1
+#define HAVE_LED_MUTE 1
+#define HAVE_LED_HANDSET 1
+#define HAVE_LED_HEADSET 1
+#define HAVE_LED_SPEAKERPHONE 1
+#define HAVE_LED_BACKLIGHT 1
/* Display settings */
/* Sound settings */
-#define HAS_HANDSET 1
-#define HAS_HEADSET 1
-#define HAS_SPEAKER_MIKE 1
+#define HAVE_HANDSET 1
+#define HAVE_HEADSET 1
+#define HAVE_SPEAKER_MIKE 1
/* Line settings */
/* Account settings */
/* Media settings */
-#define HAS_MEDIA_VOICE 1
-#define HAS_MEDIA_VIDEO 0
-#define HAS_MEDIA_URI 0
-#define HAS_MEDIA_IMAGE 1
+#define HAVE_MEDIA_VOICE 1
+#define HAVE_MEDIA_VIDEO 0
+#define HAVE_MEDIA_URI 0
+#define HAVE_MEDIA_IMAGE 1
--- /dev/null
+/*
+ * http://devel.0cpm.org/ -- Open source SIP telephony firmware.
+ *
+ * Device-specific includes for Linksys SPA962
+ */
+
+
+/* The maximum number of supported handset */
+#define HAVE_HANDSETS 1
+
+/* Keyboard settings */
+#undef DETECTS_DTMF
+#define HAVE_KBD_STARHASH 1
+#define HAVE_KBD_ABCD 0
+#define HAVE_KBD_FLASH 0
+#define HAVE_KBD_LINES 0
+#define HAVE_KBD_SOFT_FUNCTION 0
+#define HAVE_KBD_GENERIC 0
+#define HAVE_KBD_VOICEMAIL 1
+#define HAVE_KBD_MENU 1
+#define HAVE_KBD_OK 0
+#define HAVE_KBD_ENTER 1
+#define HAVE_KBD_UPDOWN 1
+#define HAVE_KBD_LEFTRIGHT 1
+#define HAVE_KBD_MUTE 0
+#define HAVE_KBD_CONFERENCE 1
+#define HAVE_KBD_HOLD 1
+#define HAVE_KBD_TRANSFER 1
+#define HAVE_KBD_PHONEBOOK 0
+#define HAVE_KBD_VOLUPDOWN 1
+#define HAVE_KBD_HEADSET 0
+#define HAVE_KBD_SPEAKER 1
+#define HAVE_KBD_HANDSET 0
+#define HAVE_KBD_MISSEDCALLS 0
+#define HAVE_KBD_REDIAL 1
+
+/* Light settings */
+#define HAVE_LED_MESSAGE 1
+#define HAVE_LED_LINEKEYS 0
+#define HAVE_LED_GENERIC 0
+#define HAVE_LED_MUTE 0
+#define HAVE_LED_HANDSET 0
+#define HAVE_LED_HEADSET 0
+#define HAVE_LED_SPEAKERPHONE 0
+#define HAVE_LED_BACKLIGHT 1
+
+/* Display settings */
+
+/* Sound settings */
+#define HAVE_HANDSET 1
+#define HAVE_HEADSET 0
+#define HAVE_SPEAKER_MIKE 1
+
+/* Line settings */
+
+/* Account settings */
+
+/* Media settings */
+#define HAVE_MEDIA_VOICE 1
+#define HAVE_MEDIA_VIDEO 0
+#define HAVE_MEDIA_URI 0
+#define HAVE_MEDIA_IMAGE 0
+
+