nfctool: Add firmware download command
authorThierry Escande <thierry.escande@linux.intel.com>
Mon, 9 Sep 2013 16:27:08 +0000 (18:27 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Tue, 10 Sep 2013 13:57:26 +0000 (15:57 +0200)
This adds a command line option (--fw-download or -w) to start firmware
download process on the specified device with the passed firmware
filename.

e.g. nfctool -d nfc0 --fw-download fw_filename

tools/nfctool/main.c
tools/nfctool/netlink.c
tools/nfctool/netlink.h
tools/nfctool/nfctool.h

index 8527dd7..a139237 100644 (file)
@@ -30,6 +30,8 @@
 #include <sys/socket.h>
 #include <glib.h>
 
+#include <netlink/genl/genl.h>
+
 #include <near/nfc_copy.h>
 
 #include "nfctool.h"
@@ -152,6 +154,49 @@ static int nfctool_set_powered(bool powered)
        return err;
 }
 
+static int nfctool_fw_download_cb(guint8 cmd, guint32 adapter_idx,
+                                 gpointer data)
+{
+       int err;
+       gchar *fw_filename;
+       struct nlattr **nl_attr = data;
+
+       if (nl_attr[NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS] != NULL)
+               err = nla_get_u32(nl_attr[NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS]);
+       else
+               err = -ENOTSUP;
+
+       if (nl_attr[NFC_ATTR_FIRMWARE_NAME] != NULL)
+               fw_filename = nla_get_string(nl_attr[NFC_ATTR_FIRMWARE_NAME]);
+       else
+               fw_filename = "UNKNOWN";
+
+       printf("Firmware download operation for %s terminated with status %s\n",
+              fw_filename, err ? strerror(-err) : "OK");
+
+       nfctool_quit(false);
+
+       return 0;
+}
+
+static int nfctool_fw_download(gchar *fw_filename)
+{
+       struct nfc_adapter *adapter;
+       int err;
+
+       adapter = adapter_get(opts.adapter_idx);
+       if (!adapter)
+               return -ENODEV;
+
+       nl_add_event_handler(NFC_CMD_FW_DOWNLOAD, nfctool_fw_download_cb);
+
+       err = nl_fw_download(adapter, fw_filename);
+       if (err)
+               print_error("Firmware download failed: %s", strerror(-err));
+
+       return err;
+}
+
 static int nfctool_dep_link_up_cb(guint8 cmd, guint32 idx, gpointer data)
 {
        struct nfc_adapter *adapter;
@@ -508,6 +553,8 @@ static GOptionEntry option_entries[] = {
          "enable device", NULL },
        { "disable", '0', 0, G_OPTION_ARG_NONE, &opts.disable_dev,
          "disable device", NULL },
+       { "fw-download", 'w', 0, G_OPTION_ARG_STRING, &opts.fw_filename,
+         "Put the device in firmware download mode", "fw_filename" },
        { "set-param", 's', 0, G_OPTION_ARG_CALLBACK, opt_parse_set_param_arg,
          "set lto, rw, and/or miux parameters", "lto=150,rw=1,miux=100" },
        { "snl", 'k', 0, G_OPTION_ARG_CALLBACK, &opt_parse_snl_arg,
@@ -580,8 +627,8 @@ static int nfctool_options_parse(int argc, char **argv)
        if (opts.poll)
                opts.enable_dev = true;
 
-       opts.need_netlink = opts.list || opts.poll ||
-                           opts.set_param || opts.snl;
+       opts.need_netlink = opts.list || opts.poll || opts.set_param ||
+                           opts.snl || opts.fw_filename;
 
        if (!opts.need_netlink && !opts.sniff) {
                printf("%s", g_option_context_get_help(context, TRUE, NULL));
@@ -590,7 +637,7 @@ static int nfctool_options_parse(int argc, char **argv)
        }
 
        if ((opts.poll || opts.set_param || opts.sniff || opts.snl ||
-           opts.enable_dev || opts.disable_dev) &&
+           opts.enable_dev || opts.disable_dev || opts.fw_filename) &&
            opts.adapter_idx == INVALID_ADAPTER_IDX) {
                print_error("Please specify a device with -d nfcX option");
 
@@ -628,6 +675,9 @@ static void nfctool_options_cleanup(void)
        if (opts.pcap_filename)
                g_free(opts.pcap_filename);
 
+       if (opts.fw_filename != NULL)
+               g_free(opts.fw_filename);
+
        g_slist_free_full(opts.snl_list, g_free);
 }
 
@@ -666,6 +716,14 @@ int main(int argc, char **argv)
                        goto exit_err;
        }
 
+       if (opts.fw_filename) {
+               err = nfctool_fw_download(opts.fw_filename);
+               if (err)
+                       goto exit_err;
+
+               goto start_loop;
+       }
+
        if (opts.sniff) {
                err = sniffer_init();
                if (err)
@@ -703,7 +761,8 @@ int main(int argc, char **argv)
        if (opts.snl)
                nfctool_snl();
 
-       if (opts.poll || opts.sniff || opts.snl)
+start_loop:
+       if (opts.poll || opts.sniff || opts.snl || opts.fw_filename)
                nfctool_main_loop_start();
 
 done:
index c4b620c..112b3cb 100644 (file)
@@ -703,6 +703,40 @@ static int nl_nfc_send_sdres_event(guint32 idx, struct nlattr *sdres_attr,
        return err;
 }
 
+int nl_fw_download(struct nfc_adapter *adapter, gchar *fw_filename)
+{
+       struct nl_msg *msg;
+       void *hdr;
+       int err;
+
+       DBG("");
+
+       if (nfc_state == NULL || nfc_state->nfc_id < 0)
+               return -ENODEV;
+
+       msg = nlmsg_alloc();
+       if (msg == NULL)
+               return -ENOMEM;
+
+       err = -EINVAL;
+
+       hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, nfc_state->nfc_id, 0,
+                         NLM_F_REQUEST, NFC_CMD_FW_DOWNLOAD, NFC_GENL_VERSION);
+       if (hdr == NULL)
+               goto nla_put_failure;
+
+       NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, adapter->idx);
+
+       NLA_PUT_STRING(msg, NFC_ATTR_FIRMWARE_NAME, fw_filename);
+
+       err = nl_send_msg(nfc_state->event_sock, msg, NULL, NULL);
+
+nla_put_failure:
+       nlmsg_free(msg);
+
+       return err;
+}
+
 static int nl_nfc_event_cb(struct nl_msg *n, void *arg)
 {
        guint32 idx = INVALID_ADAPTER_IDX;
index ce51910..21a9f5b 100644 (file)
@@ -48,4 +48,6 @@ int nl_send_sdreq(struct nfc_adapter *adapter, GSList *uris);
 
 int nl_set_powered(struct nfc_adapter *adapter, bool powered);
 
+int nl_fw_download(struct nfc_adapter *adapter, gchar *fw_filename);
+
 #endif /* __NETLINK_H */
index 7c93210..da3c965 100644 (file)
@@ -67,6 +67,7 @@ struct nfctool_options {
        guint32 adapter_idx;
        bool enable_dev;
        bool disable_dev;
+       gchar *fw_filename;
        bool set_param;
        gint32 lto;
        gint32 rw;