Merge branch 'master' into radar
authorChristian Lamparter <chunkeey@googlemail.com>
Tue, 25 Aug 2015 21:21:21 +0000 (23:21 +0200)
committerChristian Lamparter <chunkeey@googlemail.com>
Tue, 25 Aug 2015 21:27:42 +0000 (23:27 +0200)
1  2 
carlfw/CMakeLists.txt
carlfw/Kconfig
carlfw/include/carl9170.h
carlfw/include/fwdsc.h
carlfw/include/timer.h
carlfw/src/fw.c
carlfw/src/main.c
include/pattern.h
include/shared/fwdesc.h
tools/src/fwinfo.c
tools/src/fwprepare.c

diff --combined carlfw/CMakeLists.txt
index cacccd984184fad79fce5772ad1f61afa1b94188,02c80bf138badd45cb9611e1eddb5b4f5a806869..1ca09610374bf7632bb04671d07e0976db0c68d1
@@@ -17,7 -17,7 +17,7 @@@ set(CARLFW_CFLAGS "${CARLFW_CFLAGS_DEF
  include_directories (../include/linux ../include/shared ../include include)
  
  set(carl9170_main_src src/main.c src/wlan.c src/wlanrx.c src/wlantx.c
 -                    src/fw.c src/gpio.c src/timer.c
 +                    src/fw.c src/gpio.c src/timer.c src/pattern_generator.c
                      src/uart.c src/dma.c src/hostif.c src/reboot.S
                      src/printf.c src/rf.c src/cam.c src/wol.c)
  
@@@ -42,21 -42,21 +42,21 @@@ set_target_properties(carl9170.elf PROP
  add_custom_target(firmware ALL)
  
  add_custom_command(
-       SOURCE carl9170.elf
+       DEPENDS carl9170.elf
        COMMAND ${OBJCOPY}
        ARGS --strip-unneeded -O binary -R .sram -R .eeprom -R .fwdsc carl9170.elf carl9170.bin
        TARGET firmware
        OUTPUTS carl9170.bin)
  
  add_custom_command(
-       SOURCE carl9170.elf
+       DEPENDS carl9170.elf
        COMMAND ${OBJCOPY}
        ARGS --strip-unneeded -O binary -j .fwdsc carl9170.elf carl9170.dsc
        TARGET firmware
        OUTPUTS carl9170.dsc)
  
  add_custom_command(
-       SOURCE firmware
+       DEPENDS firmware
        TARGET firmware
        COMMAND cat
        ARGS "carl9170.bin" "carl9170.dsc" > "carl9170.fw"
diff --combined carlfw/Kconfig
index 16129739b79f73370cff3432ffe45e2fa631ce41,46eb1bb87399f5ba4250d43d71a5d05daa9412fe..8583903665b5392a7d1d0f120a87d2867f6c5310
@@@ -85,16 -85,6 +85,16 @@@ config CARL9170FW_EXPERIMENTA
        def_bool y
        prompt "Experimental Features"
  
 +config CARL9170FW_PATTERN_GENERATOR
 +      def_bool n
 +      prompt "Pattern generator"
 +      depends on CARL9170FW_EXPERIMENTAL
 +      ---help---
 +       With this option enabled, the firmware can generate random
 +       transmission pattern that might fool a reciever to believe
 +       that there is an active radar on the channel.
 +       Note: sadly, no SDR here.
 +
  config CARL9170FW_WOL_OPTION
        def_bool n
        prompt "Wakeup on WLAN"
@@@ -148,9 -138,19 +148,19 @@@ config CARL9170FW_NOISY_MAC_RESE
        prompt "Notify MAC RESET events"
        depends on CARL9170FW_FW_MAC_RESET
  
+ config CARL9170FW_80MHZ_CLOCK
+       def_bool n
+       prompt "Allow 80/88MHz clock for HT40"
+       depends on CARL9170FW_EXPERIMENTAL
+       ---help---
+        The SoC can run up to 80/88MHz in HT40 mode. This improves
+        throughput and timing accuracy over the 40/44MHz clock.
+        However some devices don't have heat shields and they with
+        this option enabled, they become unstable under load.
  config CARL9170FW_BROKEN_FEATURES
        def_bool n
-       prompt "Broken Featurs"
+       prompt "Broken Features"
  
  config CARL9170FW_DEBUG
        def_bool n
index d12bb98ca171a0297369665ae07635fe4ec562ac,6e8a3e16b722c972da05af1ff6e5109cc4ea7b52..d17b8963a4f01a24d7f474310146940e21ca28d3
@@@ -16,8 -16,7 +16,7 @@@
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License along
-  * with this program; if not, write to the Free Software Foundation, Inc.,
-  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+  * with this program; If not, see <http://www.gnu.org/licenses/>.
   */
  
  #ifndef __CARL9170FW_CARL9170_H
@@@ -140,12 -139,6 +139,12 @@@ struct firmware_context_struct 
                             queued_ba;
  
                unsigned int queued_bar;
 +
 +#if defined(CONFIG_CARL9170FW_PATTERN_GENERATOR)
 +              unsigned int soft_pattern,
 +                           pattern_last,
 +                           pattern_index;
 +#endif /* CONFIG_CARL9170FW_PATTERN_GENERATOR */
        } wlan;
  
        struct {
diff --combined carlfw/include/fwdsc.h
index 2e1d1ddd82fc4e23cbd33f54d15a4b365ff7f83d,de6d9d520b41a32253d888b42fec4b9191b05a71..ce9ae8fc9fe11472b9b97b4d5e27f12e32334b08
@@@ -16,8 -16,7 +16,7 @@@
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License along
-  * with this program; if not, write to the Free Software Foundation, Inc.,
-  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+  * with this program; If not, see <http://www.gnu.org/licenses/>.
   */
  
  #ifndef __CARL9170FW_FWDSC_H
@@@ -35,9 -34,6 +34,9 @@@ struct carl9170_firmware_descriptor 
        struct carl9170fw_wol_desc  wol;
  #endif /* CONFIG_CARL9170FW_WOL */
        struct carl9170fw_motd_desc motd;
 +#if defined(CONFIG_CARL9170FW_PATTERN_GENERATOR)
 +      struct carl9170fw_pattern_desc pattern;
 +#endif /* CONFIG_CARL9170FW_PATTERN_GENERATOR */
        struct carl9170fw_dbg_desc  dbg;
        struct carl9170fw_last_desc last;
  } __packed;
diff --combined carlfw/include/timer.h
index d9eee7a328555e25d09ad46334bd7c9266a41f9e,43d6f2ece5afbf8a79360caf28a9fd9a42c63ca6..f15e6fbdca33ef10ba596b96d8aad86383a82cf9
@@@ -19,8 -19,7 +19,7 @@@
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License along
-  * with this program; if not, write to the Free Software Foundation, Inc.,
-  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+  * with this program; If not, see <http://www.gnu.org/licenses/>.
   */
  
  #ifndef __CARL9170FW_TIMER_H
@@@ -50,11 -49,6 +49,11 @@@ static inline __inline bool is_after_ms
        return ((get_clock_counter() - t0) / 1000) > (msecs * fw.ticks_per_usec);
  }
  
 +static inline __inline bool is_after_usecs(const uint32_t t0, const uint32_t usecs)
 +{
 +      return ((get_clock_counter() - t0)) > (usecs * fw.ticks_per_usec);
 +}
 +
  /*
   * Note: Be careful with [u]delay. They won't service the
   * hardware watchdog timer. It might trigger if you
diff --combined carlfw/src/fw.c
index a98b735086bfaeeab18e8b43f48e19992098dda1,7ba152e7bea8004b911bf704c17d5c274da0d576..85a03fed99234b4275e7c661fc14148c97c80829
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License along
-  * with this program; if not, write to the Free Software Foundation, Inc.,
-  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+  * with this program; If not, see <http://www.gnu.org/licenses/>.
   */
  #include "carl9170.h"
  #include "fwdsc.h"
 +#include "pattern_generator.h"
  
  #define FILL(small, big, more...)                                     \
        .small = {                                                      \
@@@ -32,7 -30,7 +31,7 @@@
                more                                                    \
        }
  
- const struct carl9170_firmware_descriptor __section(fwdsc) __visible carl9170fw_desc = {
+ const struct carl9170_firmware_descriptor __in_section(fwdsc) __visible carl9170fw_desc = {
        FILL(otus, OTUS,
             .feature_set = cpu_to_le32(BIT(CARL9170FW_DUMMY_FEATURE) |
                                        BIT(CARL9170FW_USB_RESP_EP2) |
@@@ -41,6 -39,7 +40,7 @@@
                                        BIT(CARL9170FW_HW_COUNTERS) |
                                        BIT(CARL9170FW_RX_BA_FILTER) |
                                        BIT(CARL9170FW_USB_INIT_FIRMWARE) |
+                                       BIT(CARL9170FW_HAS_WREGB_CMD) |
  #ifdef CONFIG_CARL9170FW_USB_UP_STREAM
                                        BIT(CARL9170FW_USB_UP_STREAM) |
  #endif /* CONFIG_CARL9170FW_USB_UP_STREAM */
@@@ -65,9 -64,6 +65,9 @@@
  #ifdef CONFIG_CARL9170FW_WOL
                                        BIT(CARL9170FW_WOL) |
  #endif /* CONFIG_CARL9170FW_WOL */
 +#if defined(CONFIG_CARL9170FW_PATTERN_GENERATOR)
 +                                      BIT(CARL9170FW_PATTERN_GENERATOR) |
 +#endif /* CONFIG_CARL9170FW_PATTERN_GENERATOR */
                                        (0)),
  
             .miniboot_size = cpu_to_le16(0),
@@@ -93,6 -89,7 +93,6 @@@
        ),
  #endif /* CONFIG_CARL9170FW_WOL */
  
 -
        FILL(motd, MOTD,
             .fw_year_month_day = cpu_to_le32(
                        CARL9170FW_SET_DAY(CARL9170FW_VERSION_DAY) +
             .desc = "Community AR9170 Linux",
             .release = CARL9170FW_VERSION_GIT),
  
 +#if defined(CONFIG_CARL9170FW_PATTERN_GENERATOR)
 +      FILL(pattern, PATTERN,
 +           .soft_pattern = cpu_to_le32(&fw.wlan.soft_pattern),
 +           .num_patterns = __CARL9170FW_NUM_PATTERNS,
 +           .patterns = { /* filled by the fwprepare tool */ },
 +      ),
 +#endif /* CONFIG_CARL9170FW_RADAR */
 +
        FILL(dbg, DBG,
             .bogoclock_addr = cpu_to_le32(0),
             .counter_addr = cpu_to_le32(&fw.counter),
diff --combined carlfw/src/main.c
index b24d905f5eba04f1de8b51ac3cf3f0f3048e5393,8c13bf8988c87bb7f748c5b6240bedf4d119716d..8cb5fc13986a9d2af967d107faba3912453b51c1
@@@ -19,8 -19,7 +19,7 @@@
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License along
-  * with this program; if not, write to the Free Software Foundation, Inc.,
-  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+  * with this program; If not, see <http://www.gnu.org/licenses/>.
   */
  
  #include "carl9170.h"
@@@ -31,7 -30,6 +30,7 @@@
  #include "wl.h"
  #include "rf.h"
  #include "usb.h"
 +#include "pattern_generator.h"
  
  #define AR9170_WATCH_DOG_TIMER                   0x100
  
@@@ -126,8 -124,6 +125,8 @@@ static void __noreturn main_loop(void
                handle_timer();
  
                tally_update();
 +
 +              pattern_generator();
        }
  }
  
   * we put _start() there with the linker script carl9170.lds.
   */
  
- void __section(boot) __noreturn __visible start(void)
+ void __in_section(boot) __noreturn __visible start(void)
  {
        clock_set(AHB_40MHZ_OSC, true);
  
diff --combined include/pattern.h
index ba9e88fde6025639d895eacb54e78be14c1a7d65,0000000000000000000000000000000000000000..9f06923cf796baea9531a7cff0a8ea8de9f60697
mode 100644,000000..100644
--- /dev/null
@@@ -1,156 -1,0 +1,156 @@@
-               .pulse_pattern = 0xa7438080,
-               .pulse_mode    = 0x5f01,
 +/*
 + * carl9170 firmware - used by the ar9170 wireless device
 + *
 + * Pattern pulse definitions
 + *
 + * Copyright 2012 Christian Lamparter <chunkeey@googlemail.com>
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +
 +#ifndef __CARL9170FW_PATTERN_H
 +#define __CARL9170FW_PATTERN_H
 +
 +#include "types.h"
 +#include "compiler.h"
 +#include "fwdesc.h"
 +
 +enum PATTERN_TYPE {
 +      NO_PATTERN = 0,
 +      ONE_KHZ,
 +      TEN_KHZ,
 +
 +      ONE_TWO_KHZ,
 +
 +      FCC1,
 +      FCC4,
 +
 +      ETSIFIXED,
 +
 +      /* keep last */
 +      __CARL9170FW_NUM_PATTERNS
 +};
 +
 +struct pattern_pulse_info {
 +      unsigned int pulse_width;
 +      unsigned int pulse_interval;
 +      uint32_t     pulse_pattern;
 +      uint32_t     pulse_mode;
 +};
 +
 +struct pattern_info {
 +      unsigned int pulses;
 +      const struct pattern_pulse_info *pattern;
 +};
 +
 +static const struct pattern_pulse_info pattern_NO_PATTERN[0] = {  };
 +static const struct pattern_pulse_info pattern_ONE_KHZ[] = {
 +      {
 +              .pulse_width = 1,
 +              .pulse_interval = 1000,
-               .pulse_pattern = 0x436f0001,
-               .pulse_mode    = 0x5f01,
++              .pulse_pattern = 0xaa55,
++              .pulse_mode    = 0x17f01,
 +      },
 +};
 +
 +static const struct pattern_pulse_info pattern_TEN_KHZ[] = {
 +      {
 +              .pulse_width = 1,
 +              .pulse_interval = 100,
-               .pulse_pattern = 0xa7438080,
-               .pulse_mode    = 0x5f01,
++              .pulse_pattern = 0xaa55,
++              .pulse_mode    = 0x17f01,
 +      },
 +};
 +
 +static const struct pattern_pulse_info pattern_ONE_TWO_KHZ[] = {
 +      {
 +              .pulse_width = 1,
 +              .pulse_interval = 1000,
-               .pulse_pattern = 0xa7431001,
-               .pulse_mode    = 0x5f01,
++              .pulse_pattern = 0xaa55,
++              .pulse_mode    = 0x17f01,
 +      },
 +
 +      {
 +              .pulse_width = 10,
 +              .pulse_interval = 500,
-               .pulse_pattern = 0xa7438080,
-               .pulse_mode    = 0x5f01,
++              .pulse_pattern = 0xaa55,
++              .pulse_mode    = 0x17f01,
 +      },
 +};
 +
 +/*
 + * Data taken from:
 + * <http://linuxwireless.org/en/developers/DFS>
 + */
 +
 +/* FCC Test Signal 1 - 1us pulse, 1428 us interval */
 +static const struct pattern_pulse_info pattern_FCC1[] = {
 +      {
 +              .pulse_width = 1,
 +              .pulse_interval = 1428,
-               .pulse_pattern = 0xf3128008,
-               .pulse_mode    = 0x5f01,
++              .pulse_pattern = 0xaa55,
++              .pulse_mode    = 0x17f01,
 +      },
 +};
 +
 +/* FCC Test Signal 4 - 11-20us pulse, 200-500 us interval */
 +static const struct pattern_pulse_info pattern_FCC4[] = {
 +      {
 +              .pulse_width = 11,
 +              .pulse_interval = 200,
-               .pulse_pattern = 0x8a5f8080,
-               .pulse_mode    = 0x5f01,
++              .pulse_pattern = 0xaa55,
++              .pulse_mode    = 0x7f01,
 +      },
 +};
 +
 +/* ETSI Test Signal 1 (Fixed) - 1us Pulse, 750 us interval */
 +static const struct pattern_pulse_info pattern_ETSIFIXED[] = {
 +      {
 +              .pulse_width = 1,
 +              .pulse_interval = 750,
++              .pulse_pattern = 0xaa55,
++              .pulse_mode    = 0x7f01,
 +      },
 +};
 +
 +
 +#define ADD_RADAR(name) [name] = { .pulses = ARRAY_SIZE(pattern_## name), .pattern = pattern_## name }
 +
 +static const struct pattern_info patterns[__CARL9170FW_NUM_PATTERNS] = {
 +      ADD_RADAR(NO_PATTERN),
 +      ADD_RADAR(ONE_KHZ),
 +      ADD_RADAR(TEN_KHZ),
 +      ADD_RADAR(ONE_TWO_KHZ),
 +      ADD_RADAR(FCC1),
 +      ADD_RADAR(FCC4),
 +      ADD_RADAR(ETSIFIXED),
 +};
 +
 +#define MAP_ENTRY(idx) [idx] = { .index = idx, .name = # idx , }
 +#define NAMED_MAP_ENTRY(idx, named) [idx] = {.index = idx, .name = named, }
 +
 +static const struct carl9170fw_pattern_map_entry pattern_names[__CARL9170FW_NUM_PATTERNS] = {
 +      MAP_ENTRY(NO_PATTERN),
 +      MAP_ENTRY(ONE_KHZ),
 +      MAP_ENTRY(TEN_KHZ),
 +      MAP_ENTRY(ONE_TWO_KHZ),
 +
 +      MAP_ENTRY(FCC1),
 +      MAP_ENTRY(FCC4),
 +
 +      MAP_ENTRY(ETSIFIXED),
 +};
 +
 +#endif /* __CARL9170FW_PATTERN_H */
diff --combined include/shared/fwdesc.h
index 424a4e7fe7ce57e6cb501fab80e8a809039534f4,a88d07b3628b59b15892ee189c3d4d4dd708bb56..10327a7a591c7146182310c34378150c30469477
@@@ -78,12 -78,12 +78,15 @@@ enum carl9170fw_feature_list 
        /* HW (ANI, CCA, MIB) tally counters */
        CARL9170FW_HW_COUNTERS,
  
 +      /* Pattern generator */
 +      CARL9170FW_PATTERN_GENERATOR,
 +
        /* Firmware will pass BA when BARs are queued */
        CARL9170FW_RX_BA_FILTER,
  
+       /* Firmware has support to write a byte at a time  */
+       CARL9170FW_HAS_WREGB_CMD,
        /* KEEP LAST */
        __CARL9170FW_FEATURE_NUM
  };
@@@ -95,7 -95,6 +98,7 @@@
  #define CHK_MAGIC     "CHK\0"
  #define TXSQ_MAGIC    "TXSQ"
  #define WOL_MAGIC     "WOL\0"
 +#define PATTERN_MAGIC "RDR\0"
  #define LAST_MAGIC    "LAST"
  
  #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31)
@@@ -180,24 -179,6 +183,24 @@@ struct carl9170fw_dbg_desc 
  #define CARL9170FW_DBG_DESC_SIZE                      \
        (sizeof(struct carl9170fw_dbg_desc))
  
 +#define CARL9170FW_PATTERN_MAP_NAME_LEN                       15
 +struct carl9170fw_pattern_map_entry {
 +      u8 index;
 +      char name[CARL9170FW_PATTERN_MAP_NAME_LEN];
 +} __packed;
 +
 +#define CARL9170FW_PATTERN_DESC_MIN_VER                       1
 +#define CARL9170FW_PATTERN_DESC_CUR_VER                       1
 +struct carl9170fw_pattern_desc {
 +      struct carl9170fw_desc_head head;
 +
 +      __le32 soft_pattern;
 +      __le32 num_patterns;
 +      struct carl9170fw_pattern_map_entry patterns[0];
 +} __packed;
 +#define CARL9170FW_PATTERN_DESC_SIZE                  \
 +      (sizeof(struct carl9170fw_pattern_desc))
 +
  #define CARL9170FW_CHK_DESC_MIN_VER                   1
  #define CARL9170FW_CHK_DESC_CUR_VER                   2
  struct carl9170fw_chk_desc {
diff --combined tools/src/fwinfo.c
index 354704142a2f86b98e91e2d4f3745aeb11fb09a2,229f0e5335d4bf8525d8fa635fda04ec6ed31b54..cd5466cb3e958ad518366fd55d7a3cfd6d577c35
@@@ -69,7 -69,7 +69,8 @@@ static const struct feature_list known_
        CHECK_FOR_FEATURE(CARL9170FW_FIXED_5GHZ_PSM),
        CHECK_FOR_FEATURE(CARL9170FW_HW_COUNTERS),
        CHECK_FOR_FEATURE(CARL9170FW_RX_BA_FILTER),
+       CHECK_FOR_FEATURE(CARL9170FW_HAS_WREGB_CMD),
 +      CHECK_FOR_FEATURE(CARL9170FW_PATTERN_GENERATOR),
  };
  
  static void check_feature_list(const struct carl9170fw_desc_head *head,
@@@ -208,25 -208,6 +209,25 @@@ static void show_chk_desc(const struct 
                le32_to_cpu(chk->fw_crc32));
  }
  
 +static void show_pattern_desc(const struct carl9170fw_desc_head *head,
 +                        struct carlfw *fw __unused)
 +{
 +      const struct carl9170fw_pattern_desc *pattern = (const void *) head;
 +      const struct carl9170fw_pattern_map_entry *map = pattern->patterns;
 +      int map_entries = (head->length - sizeof(*pattern)) / sizeof(*map);
 +      int i;
 +
 +      fprintf(stdout, "\tPattern index register: %08x\n",
 +              le32_to_cpu(pattern->soft_pattern));
 +      fprintf(stdout, "\tNumber of supported patterns: %08x\n",
 +              le32_to_cpu(pattern->num_patterns));
 +
 +      for (i = 0; i < map_entries; i++) {
 +              fprintf(stdout, "\t\tindex:0x%x, description:%s\n",
 +                      map[i].index, map[i].name);
 +      }
 +}
 +
  static void show_last_desc(const struct carl9170fw_desc_head *head,
                           struct carlfw *fw __unused)
  
@@@ -257,7 -238,6 +258,7 @@@ static const struct 
        ADD_HANDLER(FIX, show_fix_desc),
        ADD_HANDLER(CHK, show_chk_desc),
        ADD_HANDLER(WOL, show_wol_desc),
 +      ADD_HANDLER(PATTERN, show_pattern_desc),
        ADD_HANDLER(LAST, show_last_desc),
  };
  
diff --combined tools/src/fwprepare.c
index 7bf35424bb3747b2324c4c54d75722d4e9a87b67,0000000000000000000000000000000000000000..f022874c1d1689c1d0635ee975ec06a11a094be7
mode 100644,000000..100644
--- /dev/null
@@@ -1,158 -1,0 +1,158 @@@
- #include "pattern.h"
 +/*
 + * Copyright 2012 Christian Lamparter <chunkeey@googlemail.com>
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation version 2 of the License.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <error.h>
 +#include <string.h>
 +#include <errno.h>
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <unistd.h>
++#include <ctype.h>
 +
- #include "compiler.h"
 +#include "carlfw.h"
++#include "pattern.h"
 +
 +
 +static void checksum_help(void)
 +{
 +      fprintf(stderr, "Usage:\n");
 +      fprintf(stderr, "\tfwprepare FW-FILE\n");
 +
 +      fprintf(stderr, "\nDescription:\n");
 +      fprintf(stderr, "\tThis simple utility prepares the firmware "
 +                      "for release.\n");
 +
 +      fprintf(stderr, "\nParameteres:\n");
 +      fprintf(stderr, "\t 'FW-FILE'   = firmware name\n");
 +      fprintf(stderr, "\n");
 +}
 +
 +static int add_patterns(struct carlfw *fw) {
 +      const struct carl9170fw_otus_desc *otus_desc = NULL;
 +      struct carl9170fw_pattern_desc *pattern_desc = NULL;
 +      int to_add;
 +
 +      otus_desc = carlfw_find_desc(fw, (uint8_t *) OTUS_MAGIC,
 +                                   sizeof(*otus_desc),
 +                                   CARL9170FW_OTUS_DESC_CUR_VER);
 +      if (!otus_desc) {
 +              fprintf(stderr, "No OTUS descriptor found\n");
 +              return -1;
 +      }
 +
 +      if (!carl9170fw_supports(otus_desc->feature_set, CARL9170FW_PATTERN_GENERATOR)) {
 +              return 0;
 +      }
 +
 +      pattern_desc = carlfw_find_desc(fw, (uint8_t *) PATTERN_MAGIC,
 +                                    sizeof(*pattern_desc),
 +                                    CARL9170FW_PATTERN_DESC_CUR_VER);
 +
 +      if (!pattern_desc) {
 +              fprintf(stderr, "Firmware has the pattern generator feature set, but "
 +                      "can't find a valid pattern descriptor\n");
 +              return 0;
 +      }
 +
 +      to_add = pattern_desc->num_patterns -
 +               ((pattern_desc->head.length - sizeof(*pattern_desc)) /
 +               sizeof(struct carl9170fw_pattern_map_entry));
 +      if (to_add == 0) {
 +              /* been there, done that */
 +              return 0;
 +      }
 +
 +      if (to_add == __CARL9170FW_NUM_PATTERNS) {
 +              struct carl9170fw_pattern_desc *tmp;
 +              unsigned int len, map_len;
 +
 +              map_len = sizeof(struct carl9170fw_pattern_map_entry) * to_add;
 +              len = sizeof(*tmp) + map_len;
 +              tmp = malloc(len);
 +              if (!tmp)
 +                      return -ENOMEM;
 +
 +              pattern_desc = carlfw_desc_mod_len(fw, &pattern_desc->head, map_len);
 +              if (IS_ERR_OR_NULL(pattern_desc))
 +                      return (int) PTR_ERR(pattern_desc);
 +
 +              memcpy(&pattern_desc->patterns, pattern_names, map_len);
 +              return 0;
 +      } else {
 +              fprintf(stderr, "No idea, what you just did. But congrats: you broke it!");
 +              return -EINVAL;
 +      }
 +}
 +
 +static int add_checksums(struct carlfw __unused *fw)
 +{
 +      /*
 +       * No magic here, The checksum descriptor is added/update
 +       * automatically in a subroutine of carlfw_store().
 +       */
 +      return 0;
 +}
 +
 +int main(int argc, char *args[])
 +{
 +      struct carlfw *fw = NULL;
 +      int err = 0;
 +
 +      if (argc != 2) {
 +              err = -EINVAL;
 +              goto out;
 +      }
 +
 +      fw = carlfw_load(args[1]);
 +      if (IS_ERR_OR_NULL(fw)) {
 +              err = PTR_ERR(fw);
 +              fprintf(stderr, "Failed to open file \"%s\" (%d).\n",
 +                      args[1], err);
 +              goto out;
 +      }
 +
 +      err = add_patterns(fw);
 +      if (err)
 +              goto out;
 +
 +      err = add_checksums(fw);
 +      if (err)
 +              goto out;
 +
 +      err = carlfw_store(fw);
 +      if (err) {
 +              fprintf(stderr, "Failed to apply checksum (%d).\n", err);
 +              goto out;
 +      }
 +
 +out:
 +      switch (err) {
 +      case 0:
 +              fprintf(stdout, "firmware was prepared successfully.\n");
 +              break;
 +      case -EINVAL:
 +              checksum_help();
 +              break;
 +      default:
 +              break;
 +      }
 +
 +      carlfw_release(fw);
 +      return err ? EXIT_FAILURE : EXIT_SUCCESS;
 +}