Modem HSI Flashing protocol driver
authorFaouaz TENOUTIT <faouazx.tenoutit@intel.com>
Mon, 2 Apr 2012 14:42:33 +0000 (16:42 +0200)
committerbuildbot <buildbot@intel.com>
Fri, 13 Apr 2012 09:20:27 +0000 (02:20 -0700)
BZ: 31184

Implementation of Modem HSI flashing protocol driver

Faouaz TENOUTIT <faouazx.tenoutit@intel.com>

Change-Id: Iec2d7c370931a60cb5db07fbafb45859ec9fd1f2
Signed-off-by: Faouaz TENOUTIT <faouazx.tenoutit@intel.com>
Reviewed-on: http://android.intel.com:8080/42147
Reviewed-by: Stoltz-douchet, OlivierX <olivierx.stoltz-douchet@intel.com>
Reviewed-by: Pillet, VincentX <vincentx.pillet@intel.com>
Reviewed-by: Roulliere, Pierre <pierre.roulliere@intel.com>
Reviewed-by: Predon, Frederic <frederic.predon@intel.com>
Reviewed-by: Lebsir, SamiX <samix.lebsir@intel.com>
Tested-by: Lebsir, SamiX <samix.lebsir@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
arch/x86/configs/i386_ctp_defconfig
drivers/hsi/clients/Kconfig
drivers/hsi/clients/Makefile
drivers/hsi/clients/dlp_ctrl.c
drivers/hsi/clients/dlp_debug.c
drivers/hsi/clients/dlp_flash.c [new file with mode: 0644]
drivers/hsi/clients/dlp_main.c
drivers/hsi/clients/dlp_main.h
drivers/hsi/clients/dlp_net.c
drivers/hsi/clients/dlp_tty.c
include/linux/hsi/hsi_dlp.h

index 9b588de..92af8cc 100644 (file)
@@ -1387,11 +1387,12 @@ CONFIG_HSI_ARASAN_CONFIG=y
 # CONFIG_HSI_CHAR is not set
 # CONFIG_HSI_FFL_TTY is not set
 CONFIG_HSI_DLP=y
-CONFIG_HSI_DLP_TTY_NAME="IFX"
+CONFIG_HSI_DLP_IPC_TTY_NAME="IFX"
 CONFIG_HSI_DLP_TTY_STATS=y
 CONFIG_HSI_DLP_NET_NAME="rmnet"
 CONFIG_HSI_DLP_FRAME_LENGTH=4096
 CONFIG_HSI_DLP_HEADER_LENGTH=4
+CONFIG_HSI_FLASHING_DEV_NAME="IFX"
 
 
 #
index 0286951..6301362 100644 (file)
@@ -118,8 +118,22 @@ config HSI_DLP_IPC_TTY_NAME
        string "Base name for the IPC TTY"
        default "IFX"
        help
-         Sets the base name for the TTY associated to this eDLP modem protocol
+         Sets the base name for the TTY associated to this IMC modem protocol
          for LTE.
+         The base name will be appended to the tty interface used by the HSI
+         eDLP protocol.
+
+         If unsure, use the default value.
+
+config HSI_FLASHING_DEV_NAME
+       string "Base name for the Boot/Flashing driver"
+       default "IFX"
+       help
+         Sets the base name for the char device associated to this IMC Boot/Flashing protocol
+         The base name will be appended to the char device interface used by the HSI
+         flashing protocol
+
+         If unsure, use the default value.
 
 config HSI_DLP_TTY_STATS
        bool "Statistics to assess the performance of the protocol (TTY)"
@@ -137,6 +151,10 @@ config HSI_DLP_NET_NAME
        help
          Sets the base name for the NETWORK interfaces associated to this IMC
          modem protocol for LTE.
+         The base name will be exported by the network interface used by the HSI
+         eDLP protocol
+
+         If unsure, use the default value.
 
 config HSI_DLP_PDU_LENGTH
        int "Fixed frame length"
index a800e26..c7ed3a7 100644 (file)
@@ -10,4 +10,4 @@ obj-$(CONFIG_HSI_CHAR)                += hsi_char.o
 obj-$(CONFIG_HSI_CMT_SPEECH)   += cmt_speech.o
 obj-$(CONFIG_HSI_FFL_TTY)      += hsi_ffl_tty.o
 obj-$(CONFIG_HSI_DLP)          += hsi_dlp.o
-hsi_dlp-objs := dlp_main.o dlp_ctrl.o dlp_tty.o dlp_net.o dlp_debug.o
+hsi_dlp-objs := dlp_flash.o dlp_main.o dlp_ctrl.o dlp_tty.o dlp_net.o dlp_debug.o
index 480ca9c..fe51302 100644 (file)
 
 #define DLP_ECHO_CMD_CHECKSUM  0xACAFFE
 
-#define DLP_CTRL_CMD_TO_STR(id)                                                                \
-       (id == DLP_CMD_BREAK            ? "BREAK":                                      \
-       (id == DLP_CMD_ECHO                     ? "ECHO":                                       \
-       (id == DLP_CMD_NOP)                     ? "NOP":                                        \
-       (id == DLP_CMD_CONF_CH)         ? "CONF_CH":                            \
-       (id == DLP_CMD_OPEN_CONN)       ? "OPEN_CONN":                          \
-       (id == DLP_CMD_CANCEL_CONN) ? "CANCEL_CONN":                    \
-       (id == DLP_CMD_ACK)                     ? "ACK":                                        \
-       (id == DLP_CMD_NACK)            ? "NACK":                                       \
-       (id == DLP_CMD_OPEN_CONN_OCTET)  ? "OPEN_CONN_OCTET":   \
+#define DLP_CTRL_CMD_TO_STR(id) \
+       (id == DLP_CMD_BREAK            ? "BREAK" :     \
+       (id == DLP_CMD_ECHO                     ? "ECHO" : \
+       (id == DLP_CMD_NOP)                     ? "NOP" : \
+       (id == DLP_CMD_CONF_CH)         ? "CONF_CH" : \
+       (id == DLP_CMD_OPEN_CONN)       ? "OPEN_CONN" : \
+       (id == DLP_CMD_CANCEL_CONN) ? "CANCEL_CONN" : \
+       (id == DLP_CMD_ACK)                     ? "ACK" : \
+       (id == DLP_CMD_NACK)            ? "NACK" : \
+       (id == DLP_CMD_OPEN_CONN_OCTET)  ? "OPEN_CONN_OCTET" : \
        (id == DLP_CMD_CREDITS)         ? "CREDITS" : "UNKNOWN"))
 
-#define DLP_CTRL_CTX   dlp_drv.channels[DLP_CHANNEL_CTRL]->ch_data
+#define DLP_CTRL_CTX   (dlp_drv.channels[DLP_CHANNEL_CTRL]->ch_data)
 
 /* DLP commands list */
 #define DLP_CMD_BREAK                          0x0
@@ -113,11 +113,12 @@ enum {
 };
 
 /* Modem cold boot management */
-#define V1P35CNT_W             0x0E0           /* PMIC reg to power off the modem */
-#define V1P35_OFF              4
-#define V1P35_ON               6
+#define V1P35CNT_W     0x0E0           /* PMIC reg to power off the modem */
+#define V1P35_OFF      4
+#define V1P35_ON       6
+
 #define COLD_BOOT_DELAY_OFF    20000   /* 20 ms (use of usleep_range) */
-#define COLD_BOOT_DELAY_ON     10000   /* 10 ms (use of usleep_range) */
+#define COLD_BOOT_DELAY_ON     10000   /* 10 ms (use of usleep_range) */
 
 /* Delays for powering up/resetting the modem */
 #define DLP_DURATION_ON1       60      /* ON1 pulse delay: 60 us */
@@ -216,14 +217,14 @@ static irqreturn_t dlp_ctrl_coredump_it(int irq, void *data)
 
        PROLOG();
 
-       CRITICAL("Modem CORE_DUMP 0x%x", gpio_get_value(ctrl_ctx->gpio_fcdp_rb));
+       CRITICAL("Modem CORE_DUMP 0x%x",
+                       gpio_get_value(ctrl_ctx->gpio_fcdp_rb));
 
        /* Call registered channels */
        for (i = 0; i < DLP_CHANNEL_COUNT; i++) {
                ch_ctx = dlp_drv.channels[i];
-               if (ch_ctx && ch_ctx->modem_coredump_cb) {
+               if (ch_ctx && ch_ctx->modem_coredump_cb)
                        ch_ctx->modem_coredump_cb(ch_ctx);
-               }
        }
 
        EPILOG();
@@ -262,9 +263,8 @@ static irqreturn_t dlp_ctrl_reset_it(int irq, void *data)
                ch_ctx = dlp_drv.channels[i];
                if (ch_ctx) {
                        /* Call any register callback */
-                       if (ch_ctx->modem_reset_cb) {
+                       if (ch_ctx->modem_reset_cb)
                                ch_ctx->modem_reset_cb(ch_ctx);
-                       }
 
                        /* Reset the credits value */
                        ch_ctx->credits = 0;
@@ -280,8 +280,9 @@ out:
  *
  *
  */
-static int dlp_ctrl_free_gpios(struct dlp_channel *ch_ctx,
-                                                               struct device *dev)
+static int
+dlp_ctrl_free_gpios(struct dlp_channel *ch_ctx,
+                                       struct device *dev)
 {
        struct dlp_ctrl_context *ctrl_ctx = ch_ctx->ch_data;
 
@@ -310,21 +311,20 @@ static int dlp_ctrl_free_gpios(struct dlp_channel *ch_ctx,
 *
 * @return
 */
-static inline int dlp_ctrl_configure_gpio(int gpio,
-                                                                               int direction,
-                                                                               int value,
-                                                                               const char *desc)
+static inline int
+dlp_ctrl_configure_gpio(int gpio,
+                                               int direction,
+                                               int value,
+                                               const char *desc)
 {
        int ret;
 
        ret = gpio_request(gpio, "ifxHSIModem");
 
-       if (direction) {
+       if (direction)
                ret += gpio_direction_output(gpio, value);
-       }
-       else {
+       else
                ret += gpio_direction_input(gpio);
-       }
 
        if (ret) {
                CRITICAL("Unable to configure GPIO%d (%s)",
@@ -336,8 +336,18 @@ static inline int dlp_ctrl_configure_gpio(int gpio,
        return ret;
 }
 
-static int dlp_ctrl_setup_irq_gpio(struct dlp_channel *ch_ctx,
-                                                                   struct device *dev)
+/*
+* @brief This function is:
+*      - requesting all needed gpios
+*      - requesting all needed irqs
+*      - registering irqs callbacks
+*
+* @param ch_ctx : Channel context
+* @param dev : Device driver info
+*/
+static int
+dlp_ctrl_setup_irq_gpio(struct dlp_channel *ch_ctx,
+                                               struct device *dev)
 {
        int ret;
        struct dlp_ctrl_context *ctrl_ctx = ch_ctx->ch_data;
@@ -345,22 +355,22 @@ static int dlp_ctrl_setup_irq_gpio(struct dlp_channel *ch_ctx,
        PROLOG();
 
        /* Configure the RESET_BB gpio */
-       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_mdm_rst_bbn, 1, 1, "RST_BB");
-       if (ret) {
+       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_mdm_rst_bbn,
+                       1, 1, "RST_BB");
+       if (ret)
                goto free_ctx4;
-       }
 
        /* Configure the ON gpio */
-       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_mdm_pwr_on, 1, 1, "ON");
-       if (ret) {
+       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_mdm_pwr_on,
+                       1, 1, "ON");
+       if (ret)
                goto free_ctx3;
-       }
 
        /* Configure the RESET_OUT gpio & irq */
-       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_mdm_rst_out, 0, 0, "RST_OUT");
-       if (ret) {
+       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_mdm_rst_out,
+                       0, 0, "RST_OUT");
+       if (ret)
                goto free_ctx2;
-       }
 
        ctrl_ctx->reset.rst_irq = gpio_to_irq(ctrl_ctx->gpio_mdm_rst_out);
        if (ctrl_ctx->reset.rst_irq < 0) {
@@ -381,10 +391,10 @@ static int dlp_ctrl_setup_irq_gpio(struct dlp_channel *ch_ctx,
        }
 
        /* Configure the CORE_DUMP gpio & irq */
-       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_fcdp_rb, 0, 0, "CORE_DUMP");
-       if (ret) {
+       ret = dlp_ctrl_configure_gpio(ctrl_ctx->gpio_fcdp_rb,
+                       0, 0, "CORE_DUMP");
+       if (ret)
                goto free_all;
-       }
 
        ctrl_ctx->reset.cd_irq = gpio_to_irq(ctrl_ctx->gpio_fcdp_rb);
        if (ctrl_ctx->reset.cd_irq < 0) {
@@ -452,8 +462,8 @@ static struct dlp_command *dlp_ctrl_cmd_alloc(struct dlp_channel *ch_ctx,
                                              unsigned char param2,
                                              unsigned char param3)
 {
-       int flags = in_interrupt()? GFP_ATOMIC : GFP_KERNEL;
        struct dlp_command *dlp_cmd;
+       int flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 
        /* Allocate DLP command */
        dlp_cmd = kmalloc(sizeof(struct dlp_command), flags);
@@ -480,8 +490,7 @@ out:
  */
 static inline void dlp_ctrl_cmd_free(struct dlp_command *dlp_cmd)
 {
-       if (dlp_cmd)
-               kfree(dlp_cmd);
+       kfree(dlp_cmd);
 }
 
 /*
@@ -584,7 +593,7 @@ static void dlp_ctrl_complete_rx(struct hsi_msg *msg)
        hsi_channel = params.channel;
        if ((hsi_channel < 0) || (hsi_channel >= DLP_CHANNEL_COUNT)) {
                CRITICAL("CREDITS: Invalid channel id (%d)", hsi_channel);
-               BUG_ON(1);      /* FIXME: We have BIGGGGGG pb (To be removed ?) */
+               BUG_ON(1); /* FIXME: We have BIGGGGGG issue */
                goto out;
        }
 
@@ -602,9 +611,8 @@ static void dlp_ctrl_complete_rx(struct hsi_msg *msg)
                        spin_unlock_irqrestore(&ch_ctx->lock, flags);
 
                        /* Credits available ==> Notify the channel */
-                       if (ch_ctx->credits_available_cb) {
+                       if (ch_ctx->credits_available_cb)
                                ch_ctx->credits_available_cb(ch_ctx);
-                       }
 
                        PTRACE_NO_FUNC("New CREDITS value: %d (+%d)\n", ret,
                                       params.data3);
@@ -619,10 +627,11 @@ static void dlp_ctrl_complete_rx(struct hsi_msg *msg)
 
                        /* Check the requested PDU size */
                        if (ch_ctx->pdu_size != ret) {
-                               CRITICAL
-                                   ("Unexpected PDU size: %d => Expected: %d (ch: %d)",
-                                    ret, ch_ctx->pdu_size,
-                                    ch_ctx->hsi_channel);
+                               CRITICAL("Unexpected PDU size: %d => "
+                                               "Expected: %d (ch: %d)",
+                                               ret,
+                                               ch_ctx->pdu_size,
+                                               ch_ctx->hsi_channel);
 
                                response = DLP_CMD_NACK;
                        }
@@ -965,8 +974,7 @@ static void dlp_ctrl_ipc_readiness(struct work_struct *work)
                        /* Set the modem state */
                        dlp_ctrl_set_modem_readiness(1);
                }
-       }
-       while (ret);
+       } while (ret);
 
        EPILOG();
 }
@@ -1011,7 +1019,7 @@ void dlp_ctrl_modem_reset(struct dlp_channel *ch_ctx)
 *
 * @param ch_ctx: IPC CTRL channel
 */
-static void dlp_ctrl_modem_power(struct dlp_channel *ch_ctx)
+void dlp_ctrl_modem_power(struct dlp_channel *ch_ctx)
 {
        struct dlp_channel *ctrl_ch = dlp_drv.channels[DLP_CHANNEL_CTRL];
        struct dlp_ctrl_context *ctrl_ctx = ctrl_ch->ch_data;
@@ -1139,7 +1147,8 @@ struct dlp_channel *dlp_ctrl_ctx_create(unsigned int index, struct device *dev)
        }
 
        /* Create a workqueue to check the modem readiness */
-       ctrl_ctx->readiness_wq = create_singlethread_workqueue(DRVNAME "-mdmreadiness");
+       ctrl_ctx->readiness_wq = create_singlethread_workqueue(
+                       DRVNAME "-mdmreadiness");
        if (!ctrl_ctx->readiness_wq) {
                CRITICAL("Unable to create modem readiness workqueue");
                goto free_ctx;
@@ -1173,9 +1182,8 @@ struct dlp_channel *dlp_ctrl_ctx_create(unsigned int index, struct device *dev)
        ctrl_ctx->gpio_fcdp_rb     = pd->gpio_fcdp_rb;
 
        ret = dlp_ctrl_setup_irq_gpio(ch_ctx, dev);
-       if (ret) {
+       if (ret)
                goto free_ctx;
-       }
 
        /* Set ch_ctx, not yet done in the probe */
        dlp_drv.channels[DLP_CHANNEL_CTRL] = ch_ctx;
@@ -1309,20 +1317,17 @@ int dlp_ctrl_close_channel(struct dlp_channel *ch_ctx)
 */
 static int do_modem_reset(const char *val, struct kernel_param *kp)
 {
-       unsigned long reset_request;
+       long do_reset;
 
        PROLOG();
 
-       if (strict_strtoul(val, 16, &reset_request) < 0) {
+       if (strict_strtol(val, 16, &do_reset) < 0) {
                EPILOG();
                return -EINVAL;
        }
 
-       if (reset_request) {
-               struct dlp_channel *ch_ctx = dlp_drv.channels[DLP_CHANNEL_CTRL];
-
-               dlp_ctrl_modem_reset(ch_ctx);
-       }
+       if (do_reset)
+               dlp_ctrl_modem_reset(dlp_drv.channels[DLP_CHANNEL_CTRL]);
 
        EPILOG();
        return 0;
@@ -1343,6 +1348,33 @@ static int get_modem_reset(char *val, struct kernel_param *kp)
 }
 
 /*
+* @brief Modem reset module_param set function
+*      - This function is performing a modem reset
+*
+* @param val
+* @param kp
+*
+* @return 0
+*/
+static int do_modem_power(const char *val, struct kernel_param *kp)
+{
+       long do_power;
+
+       PROLOG();
+
+       if (strict_strtol(val, 16, &do_power) < 0) {
+               EPILOG();
+               return -EINVAL;
+       }
+
+       if (do_power)
+               dlp_ctrl_modem_power(dlp_drv.channels[DLP_CHANNEL_CTRL]);
+
+       EPILOG();
+       return 0;
+}
+
+/*
  * Modem cold reset sysfs entries
  *
  * To do a modem cold reset we have to:
@@ -1436,11 +1468,11 @@ static int dp_modem_cold_reset(const char *val, struct kernel_param *kp)
 */
 static int clear_hangup_reasons(const char *val, struct kernel_param *kp)
 {
-       unsigned long reasons_to_clear;
+       long reasons_to_clear;
 
        PROLOG();
 
-       if (strict_strtoul(val, 16, &reasons_to_clear) < 0)
+       if (strict_strtol(val, 16, &reasons_to_clear) < 0)
                return -EINVAL;
 
        if (reasons_to_clear) {
@@ -1479,6 +1511,7 @@ static int get_hangup_reasons(char *val, struct kernel_param *kp)
 
 module_param_call(cold_reset_modem, dp_modem_cold_reset, NULL, NULL, 0644);
 module_param_call(reset_modem, do_modem_reset, get_modem_reset, NULL, 0644);
+module_param_call(power_modem, do_modem_power, NULL, NULL, 0644);
 module_param_call(hangup_reasons, clear_hangup_reasons, get_hangup_reasons,
                  NULL, 0644);
 
index bc2f7ba..63db9f8 100644 (file)
@@ -47,7 +47,7 @@ void dlp_dbg_dump_data_as_byte(unsigned char *data,
        int i;
 
        if (should_dump)
-               printk("-----\n");
+               printk(KERN_DEBUG "-----\n");
        else if (is_rx)
                PRINT_RX("-----\n");
        else
@@ -55,7 +55,7 @@ void dlp_dbg_dump_data_as_byte(unsigned char *data,
 
        for (i = 0; i < nb_bytes; i++) {
                if (should_dump)
-                       printk("%02X ", data[i]);
+                       printk(KERN_DEBUG "%02X ", data[i]);
                else if (is_rx)
                        PRINT_RX("%02X ", data[i]);
                else
@@ -75,7 +75,7 @@ void dlp_dbg_dump_data_as_byte(unsigned char *data,
        /* Previous line was less than "bytes_per_line" */
        if ((i & (bytes_per_line - 1)) != 0) {
                if (should_dump)
-                       printk("\n");
+                       printk(KERN_DEBUG "\n");
                else if (is_rx)
                        PRINT_RX("\n");
                else
@@ -83,7 +83,7 @@ void dlp_dbg_dump_data_as_byte(unsigned char *data,
        }
 
        if (should_dump)
-               printk("-----\n");
+               printk(KERN_DEBUG "-----\n");
        else if (is_rx)
                PRINT_RX("-----\n");
        else
@@ -97,7 +97,7 @@ void dlp_dbg_dump_data_as_word(unsigned int *data,
        int i;
 
        if (should_dump)
-               printk("-----\n");
+               printk(KERN_DEBUG "-----\n");
        else if (is_rx)
                PRINT_RX("-----\n");
        else
@@ -105,7 +105,7 @@ void dlp_dbg_dump_data_as_word(unsigned int *data,
 
        for (i = 0; i < nb_words; i++) {
                if (should_dump)
-                       printk("%08X ", data[i]);
+                       printk(KERN_DEBUG "%08X ", data[i]);
                else if (is_rx)
                        PRINT_RX("%08X ", data[i]);
                else
@@ -125,7 +125,7 @@ void dlp_dbg_dump_data_as_word(unsigned int *data,
        /* Previous line was less than "words_per_line" */
        if ((i & (words_per_line - 1)) != 0) {
                if (should_dump)
-                       printk("\n");
+                       printk(KERN_DEBUG "\n");
                else if (is_rx)
                        PRINT_RX("\n");
                else
@@ -133,7 +133,7 @@ void dlp_dbg_dump_data_as_word(unsigned int *data,
        }
 
        if (should_dump)
-               printk("-----\n");
+               printk(KERN_DEBUG "-----\n");
        else if (is_rx)
                PRINT_RX("-----\n");
        else
@@ -167,15 +167,14 @@ void dlp_dbg_dump_pdu(struct hsi_msg *pdu,
        is_rx = (pdu->ttype == HSI_MSG_READ);
 
        if (is_rx)
-               PRINT_RX("RX PDU (0x%p): \n", pdu);
+               PRINT_RX("RX PDU (0x%p):\n", pdu);
        else
-               PRINT_TX("TX PDU (0x%p): \n", pdu);
+               PRINT_TX("TX PDU (0x%p):\n", pdu);
 
        /* Check the PDU signature */
        data = sg_virt(sg);
-       if (!dlp_pdu_header_valid(pdu)) {
+       if (!dlp_pdu_header_valid(pdu))
                is_corrupted = 1;
-       }
 
        for (i = 0; i < pdu->sgt.nents; i++) {
                data = sg_virt(sg);
@@ -186,9 +185,8 @@ void dlp_dbg_dump_pdu(struct hsi_msg *pdu,
                        if (dumped >= items_to_dump) {
                                break;
                        } else {
-                               if ((len + dumped) > items_to_dump) {
+                               if ((len + dumped) > items_to_dump)
                                        len = items_to_dump - dumped;
-                               }
                        }
                } else {
                        len = items_to_dump - dumped;
diff --git a/drivers/hsi/clients/dlp_flash.c b/drivers/hsi/clients/dlp_flash.c
new file mode 100644 (file)
index 0000000..404b1d9
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * dlp_flash.c
+ *
+ * Intel Mobile Communication protocol driver for modem boot/flashing:
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * Contact: Faouaz Tenoutit <faouazx.tenoutit@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/hsi/hsi.h>
+#include <linux/uaccess.h>
+
+#include "dlp_main.h"
+
+
+#define DEBUG_TAG 0x8
+#define DEBUG_VAR dlp_drv.debug
+
+
+#define FLASHING_DEVNAME       "tty"CONFIG_HSI_FLASHING_DEV_NAME
+
+/* Number of RX msg to push
+ * if the controller FIFO
+ */
+#define DLP_FLASH_NB_RX_MSG 10
+
+
+/*
+ * struct flashing_driver - HSI Modem flashing driver protocol
+ *
+ * @lock: spinlock to serialise access to the driver information
+ * @major: char device major number
+ * @tdev: char device type dev
+ * @dev: char device
+ * @cdev: char device
+ * @class: char device class
+ * @opened: This flasg is used to allow only ONE instance of this driver
+ * @read_wq: Read/Poll/Select wait event
+ * @rx_msgs: RX messages queue
+ * @ch_ctx: Flashing Channel context
+ * @reset_done: Flag used to reset the modem when sending the first TX data
+*/
+struct dlp_flash_ctx {
+       /* Char device registration */
+       int major;
+       dev_t tdev;
+       struct device *dev;
+       struct cdev cdev;
+       struct class *class;
+
+       /* Used to prevent multiple access to device */
+       unsigned int opened;
+
+       /* A waitqueue for poll/read operations */
+       wait_queue_head_t read_wq;
+
+       /* RX msg queue */
+       struct list_head rx_msgs;
+
+       struct dlp_channel *ch_ctx;
+       int reset_done;
+};
+
+
+/*
+ *
+ */
+static void dlp_flash_complete_rx(struct hsi_msg *msg);
+
+
+/*
+* @brief
+*
+* @param flash_ctx
+* @param value
+*/
+static inline void dlp_flash_set_opened(struct dlp_channel *ch_ctx,
+               int value)
+{
+       unsigned long flags;
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+
+       spin_lock_irqsave(&ch_ctx->lock, flags);
+
+       /* Set the open flag */
+       flash_ctx->opened = value;
+
+       /* Set the reset_done flag */
+       flash_ctx->reset_done = !value;
+
+       spin_unlock_irqrestore(&ch_ctx->lock, flags);
+}
+
+/*
+* @brief
+*
+* @param flash_ctx
+* @param value
+*/
+static inline int dlp_flash_get_opened(struct dlp_channel *ch_ctx)
+{
+       int opened;
+       unsigned long flags;
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+
+       /* Set the open flag */
+       spin_lock_irqsave(&ch_ctx->lock, flags);
+       opened = flash_ctx->opened;
+       spin_unlock_irqrestore(&ch_ctx->lock, flags);
+
+       return opened;
+}
+
+/*
+* @brief
+*
+* @param msg
+*/
+static inline void dlp_flash_free_msg(struct hsi_msg *msg)
+{
+       /* Delete the received msg */
+       dlp_pdu_free(msg, msg->sgt.sgl->length);
+}
+
+/*
+* @brief
+*
+* @param msg
+*/
+static void dlp_flash_msg_destruct(struct hsi_msg *msg)
+{
+       PROLOG("msg:0x%p", msg);
+
+       /* Delete the received msg */
+       dlp_flash_free_msg(msg);
+
+       EPILOG();
+}
+
+/*
+ * Push RX pdu on channel 0
+ *
+ */
+static int dlp_flash_push_rx_pdu(struct dlp_channel *ch_ctx)
+{
+       int ret;
+       struct hsi_msg *rx_msg;
+
+       PROLOG();
+
+       /* Allocate a new RX msg */
+       rx_msg = dlp_pdu_alloc(ch_ctx->hsi_channel,
+                              HSI_MSG_READ,
+                              DLP_FLASH_PDU_SIZE,
+                              1,
+                              ch_ctx,
+                              dlp_flash_complete_rx, dlp_flash_msg_destruct);
+
+       if (!rx_msg) {
+               CRITICAL("dlp_pdu_alloc(RX) failed");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* Send the RX HSI msg */
+       ret = hsi_async(rx_msg->cl, rx_msg);
+       if (ret) {
+               CRITICAL("hsi_async() failed, ret:%d", ret);
+               ret = -EIO;
+               goto free_msg;
+       }
+
+       EPILOG();
+       return 0;
+
+free_msg:
+       /* Free the msg */
+       dlp_pdu_free(rx_msg, DLP_CTRL_PDU_SIZE);
+
+out:
+       EPILOG();
+       return ret;
+}
+
+/*
+* @brief Insert the provided msg at the begining (head) of the list
+*
+* @param ch_ctx
+* @param msg
+*/
+static void dlp_boot_rx_queue_head(struct dlp_channel *ch_ctx,
+                                       struct hsi_msg *msg)
+{
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       unsigned long flags;
+
+       /* Add at the begining of the list */
+       spin_lock_irqsave(&ch_ctx->lock, flags);
+       list_add(&msg->link, &flash_ctx->rx_msgs);
+       spin_unlock_irqrestore(&ch_ctx->lock, flags);
+}
+
+/*
+* @brief Insert the provided msg at the end (tail) of the list
+*
+* @param ch_ctx
+* @param msg
+*/
+static void dlp_boot_rx_queue_tail(struct dlp_channel *ch_ctx,
+                                       struct hsi_msg *msg)
+{
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       unsigned long flags;
+
+       /* Add at the end of the list */
+       spin_lock_irqsave(&ch_ctx->lock, flags);
+       list_add_tail(&msg->link, &flash_ctx->rx_msgs);
+       spin_unlock_irqrestore(&ch_ctx->lock, flags);
+}
+
+/*
+* @brief Remove & return the first list item (return NULL if empty)
+*
+* @param ch_ctx
+* @param msg
+*/
+static struct hsi_msg *dlp_boot_rx_dequeue(struct dlp_channel *ch_ctx)
+{
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       struct hsi_msg *msg = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ch_ctx->lock, flags);
+
+       if (!list_empty(&flash_ctx->rx_msgs)) {
+               /* Get the fist list item (head) */
+               msg = list_entry(flash_ctx->rx_msgs.next, struct hsi_msg, link);
+
+               /* Remove the item from the list */
+               list_del_init(&msg->link);
+       }
+
+       spin_unlock_irqrestore(&ch_ctx->lock, flags);
+       return msg;
+}
+
+
+/*
+* @brief
+*
+* @param msg
+*/
+static void dlp_flash_complete_tx(struct hsi_msg *msg)
+{
+       PROLOG("msg:0x%p", msg);
+
+       /* Delete the received msg */
+       dlp_flash_free_msg(msg);
+
+       EPILOG();
+}
+
+/*
+* @brief
+*
+* @param msg
+*/
+static void dlp_flash_complete_rx(struct hsi_msg *msg)
+{
+       struct dlp_channel *ch_ctx = msg->context;
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       int ret;
+
+       PROLOG("msg:0x%p, actual_len:%d, pdu_len:%d", msg,
+                       msg->actual_len, msg->sgt.sgl->length);
+
+       if (msg->status != HSI_STATUS_COMPLETED) {
+               CRITICAL("Invalid msg status: %d (ignored)", msg->status);
+
+               /* Push again the RX msg */
+               ret = hsi_async(msg->cl, msg);
+               if (ret) {
+                       CRITICAL("hsi_async() failed, ret:%d ==> "
+                                       "FIFO will be empty", ret);
+
+                       /* Delete the received msg */
+                       dlp_flash_free_msg(msg);
+               }
+       } else {
+               /* Add the received msg to the RX queue */
+               dlp_boot_rx_queue_tail(ch_ctx, msg);
+
+               /* Wakeup any waiting clients for read/poll */
+               wake_up_interruptible(&flash_ctx->read_wq);
+       }
+
+       EPILOG();
+}
+
+
+/*
+ * Called when a process tries to open the device file
+ */
+static int dlp_flash_dev_open(struct inode *inode, struct file *filp)
+{
+       int ret = 0;
+       struct dlp_channel *ch_ctx = DLP_CHANNEL_CTX(DLP_CHANNEL_FLASH);
+
+       PROLOG("flags:0x%x", filp->f_flags);
+
+       /* Only ONE instance of this device can be opened */
+       if (dlp_flash_get_opened(ch_ctx)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* Save private data for futur use */
+       filp->private_data = ch_ctx;
+
+       /* Set the open flag */
+       dlp_flash_set_opened(ch_ctx, 1);
+
+       /* Push RX PDUs */
+       for (ret = DLP_FLASH_NB_RX_MSG; ret; ret--)
+               dlp_flash_push_rx_pdu(ch_ctx);
+
+out:
+       EPILOG();
+       return ret;
+}
+
+/*
+ * Called when a process closes the device file.
+ */
+static int dlp_flash_dev_close(struct inode *inode, struct file *filp)
+{
+       struct dlp_channel *ch_ctx = filp->private_data;
+
+       PROLOG();
+
+       /* Set the open flag */
+       dlp_flash_set_opened(ch_ctx, 0);
+
+       EPILOG();
+       return 0;
+}
+
+/*
+ * Called when a process, which already opened the dev file, attempts to
+ * read from it.
+ */
+static ssize_t dlp_flash_dev_read(struct file *filp,
+                          char __user *data,
+                          size_t count,
+                          loff_t *ppos)
+{
+       struct dlp_channel *ch_ctx = filp->private_data;
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       struct hsi_msg *msg;
+       int ret, to_copy, copied, available;
+       unsigned long flags;
+
+       PROLOG("count:%d", count);
+
+       /* Have some data to read ? */
+       spin_lock_irqsave(&ch_ctx->lock, flags);
+       ret = list_empty(&flash_ctx->rx_msgs);
+       spin_unlock_irqrestore(&ch_ctx->lock, flags);
+
+       /* List empty ? */
+       if (ret) {
+               /* Descriptor opened in Non-Blocking mode ? */
+               if (filp->f_flags & O_NONBLOCK) {
+                       copied = -EWOULDBLOCK;
+                       goto out;
+               } else {
+                       ret = wait_event_interruptible(flash_ctx->read_wq, 0);
+
+                       PDEBUG("Wake up !");
+                       if (ret) {
+                               copied = -EINTR;
+                               goto out;
+                       }
+               }
+       }
+
+       copied = 0;
+       available = count;
+
+       /* Parse RX msgs queue */
+       while ((msg = dlp_boot_rx_dequeue(ch_ctx))) {
+               /* Check if we have enough of space in the user buffer */
+               to_copy = MIN(msg->actual_len, available);
+               if ((copied + to_copy) > available) {
+                       /* Put the msg back in the RX queue */
+                       dlp_boot_rx_queue_head(ch_ctx, msg);
+
+                       /* Copy done (The user buffer is full) */
+                       break;
+               }
+
+               /* Copy data to the user buffer */
+               ret = copy_to_user(data+copied, sg_virt(msg->sgt.sgl), to_copy);
+               if (ret) {
+                       CRITICAL("Uanble to copy data to the user buffer");
+
+                       /* Put the msg back in the RX queue */
+                       dlp_boot_rx_queue_head(ch_ctx, msg);
+
+                       /* Stop copying */
+                       break;
+               }
+
+               copied += to_copy;
+               available -= to_copy;
+
+               /* Data read => Queue the RX msg */
+               /* Push again the RX msg */
+               ret = hsi_async(msg->cl, msg);
+               if (ret) {
+                       CRITICAL("hsi_async() failed, ret:%d ==> "
+                                       "FIFO will be empty", ret);
+
+                       /* Delete the received msg */
+                       dlp_flash_free_msg(msg);
+               }
+       }
+
+       /* Update the position */
+       (*ppos) += copied;
+
+out:
+       EPILOG("bytes_read:%d, pos: %d", copied, (unsigned int)(*ppos));
+       return copied;
+}
+
+/*
+ * Called when a process writes to dev file
+ */
+static ssize_t dlp_flash_dev_write(struct file *filp,
+               const char __user *data,
+               size_t count,
+               loff_t *ppos)
+{
+       int ret;
+       struct dlp_channel *ch_ctx = filp->private_data;
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       struct hsi_msg *tx_msg = NULL;
+
+       PROLOG("count: %d", count);
+
+       /* A modem reset is need only the FIST write */
+       if (!flash_ctx->reset_done) {
+               flash_ctx->reset_done = 1;
+               dlp_ctrl_modem_reset(ch_ctx);
+       }
+
+       /* Allocate a new TX msg */
+       tx_msg = dlp_pdu_alloc(DLP_CHANNEL_CTRL,
+                              HSI_MSG_WRITE,
+                              count,
+                              1,
+                              ch_ctx,
+                              dlp_flash_complete_tx, dlp_flash_msg_destruct);
+
+       if (!tx_msg) {
+               CRITICAL("dlp_pdu_alloc(TX, len: %d) failed", count);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* Copy the user data */
+       memcpy(sg_virt(tx_msg->sgt.sgl), data, count);
+
+       /* Send the TX HSI msg */
+       ret = hsi_async(tx_msg->cl, tx_msg);
+       if (ret) {
+               CRITICAL("hsi_async(TX) failed (ret:%d)", ret);
+               ret = -EIO;
+               goto free_tx;
+       }
+
+       ret = count;
+       EPILOG();
+       return ret;
+
+free_tx:
+       dlp_flash_free_msg(tx_msg);
+
+out:
+       EPILOG();
+       return ret;
+}
+
+
+/*
+* @brief
+*
+* @param filp
+* @param wait
+*
+* @return
+*/
+static unsigned int dlp_flash_dev_poll(struct file *filp,
+               struct poll_table_struct *pt)
+{
+       struct dlp_channel *ch_ctx = filp->private_data;
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       unsigned long flags;
+       unsigned int ret = 0;
+
+       PROLOG();
+
+       poll_wait(filp, &flash_ctx->read_wq, pt);
+
+       /* Have some data to read ? */
+       spin_lock_irqsave(&ch_ctx->lock, flags);
+       if (!list_empty(&flash_ctx->rx_msgs))
+               ret = POLLIN | POLLRDNORM;
+       spin_unlock_irqrestore(&ch_ctx->lock, flags);
+
+       EPILOG("0x%d", ret);
+       return ret;
+}
+
+
+/*
+* Device driver file operations
+*/
+static const struct file_operations dlp_flash_ops = {
+       .open   = dlp_flash_dev_open,
+       .read   = dlp_flash_dev_read,
+       .write  = dlp_flash_dev_write,
+       .poll   = dlp_flash_dev_poll,
+       .release = dlp_flash_dev_close
+};
+
+/*
+* @brief
+*
+* @param index
+* @param dev
+*
+* @return
+*/
+struct dlp_channel *dlp_flash_ctx_create(unsigned int index, struct device *dev)
+{
+       int ret;
+       struct hsi_client *client = to_hsi_client(dev);
+       struct dlp_channel *ch_ctx;
+       struct dlp_flash_ctx *flash_ctx;
+
+       PROLOG();
+
+       /* Allocate channel struct data */
+       ch_ctx = kzalloc(sizeof(struct dlp_channel), GFP_KERNEL);
+       if (!ch_ctx) {
+               CRITICAL("Unable to allocate memory (ch_ctx)");
+               goto out;
+       }
+
+       /* Allocate the context private data */
+       flash_ctx = kzalloc(sizeof(struct dlp_flash_ctx), GFP_KERNEL);
+       if (!flash_ctx) {
+               CRITICAL("Unable to allocate memory (flash_ctx)");
+               goto free_ch;
+       }
+
+       /* Save params */
+       ch_ctx->ch_data = flash_ctx;
+       ch_ctx->hsi_channel = 0;
+       ch_ctx->pdu_size = DLP_FLASH_PDU_SIZE;
+       ch_ctx->rx.config = client->rx_cfg;
+       ch_ctx->tx.config = client->tx_cfg;
+
+       spin_lock_init(&ch_ctx->lock);
+       init_waitqueue_head(&flash_ctx->read_wq);
+       flash_ctx->ch_ctx = ch_ctx;
+       INIT_LIST_HEAD(&flash_ctx->rx_msgs);
+
+       /* Init the RX/TX contexts */
+       dlp_xfer_ctx_init(ch_ctx, &ch_ctx->tx,
+                         0, 0, 0, NULL, HSI_MSG_WRITE);
+
+       dlp_xfer_ctx_init(ch_ctx, &ch_ctx->rx,
+                         0, 0, 0, NULL, HSI_MSG_READ);
+
+       /* Register the device */
+       ret = alloc_chrdev_region(&flash_ctx->tdev, 0, 1, FLASHING_DEVNAME);
+       if (ret) {
+               CRITICAL("Unable to allocate the device (err: %d)", ret);
+               goto free_ctx;
+       }
+
+       flash_ctx->major = MAJOR(flash_ctx->tdev);
+       cdev_init(&flash_ctx->cdev, &dlp_flash_ops);
+       flash_ctx->cdev.owner = THIS_MODULE;
+
+       ret = cdev_add(&flash_ctx->cdev, flash_ctx->tdev, 1);
+       if (ret) {
+               CRITICAL("Unable to register the device (err: %d)", ret);
+               goto unreg_reg;
+       }
+
+       flash_ctx->class = class_create(THIS_MODULE, DRVNAME);
+       if (IS_ERR(flash_ctx->class))
+               goto del_cdev;
+
+       flash_ctx->dev = device_create(flash_ctx->class,
+                       NULL,
+                       flash_ctx->tdev,
+                       NULL, FLASHING_DEVNAME"%d", DLP_TTY_DEV_NUM);
+       if (IS_ERR(flash_ctx->dev)) {
+               CRITICAL("Unable to create the device (err: %ld)",
+                               PTR_ERR(flash_ctx->dev));
+               goto del_class;
+       }
+
+       EPILOG();
+       return ch_ctx;
+
+del_class:
+       class_destroy(flash_ctx->class);
+
+del_cdev:
+       cdev_del(&flash_ctx->cdev);
+
+unreg_reg:
+       unregister_chrdev_region(flash_ctx->tdev, 1);
+
+free_ctx:
+       kfree(flash_ctx);
+
+free_ch:
+       kfree(ch_ctx);
+
+out:
+       EPILOG("Failed");
+       return NULL;
+}
+
+/*
+* @brief
+*
+* @param ch_ctx
+*
+* @return
+*/
+int dlp_flash_ctx_delete(struct dlp_channel *ch_ctx)
+{
+       struct dlp_flash_ctx *flash_ctx = ch_ctx->ch_data;
+       int ret = 0;
+
+       PROLOG();
+
+       /* Unregister the device */
+       cdev_del(&flash_ctx->cdev);
+       unregister_chrdev_region(flash_ctx->tdev, 1);
+       class_destroy(flash_ctx->class);
+
+       /* Free the BOOT/FLASHING context */
+       kfree(flash_ctx);
+
+       /* Free the ch_ctx */
+       kfree(ch_ctx);
+
+       EPILOG();
+       return ret;
+}
+
+static int dlp_flash_set_flashing_mode(const char *val, struct kernel_param *kp)
+{
+       long value;
+
+       if (strict_strtol(val, 16, &value) < 0)
+               return -EINVAL;
+
+       PROLOG();
+
+       dlp_set_flashing_mode(value);
+
+       EPILOG();
+       return 0;
+}
+
+module_param_call(set_flashing_mode, dlp_flash_set_flashing_mode,
+               NULL, NULL, 0644);
+
index f7419ed..8aeb20e 100644 (file)
@@ -190,7 +190,7 @@ void dlp_pdu_dump(struct hsi_msg *pdu, int as_string)
 void *dlp_buffer_alloc(unsigned int buff_size, dma_addr_t * dma_addr)
 {
        void *buff;
-       int flags = in_interrupt()? GFP_ATOMIC : GFP_KERNEL;
+       int flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 
        if (dlp_drv.is_dma_capable) {
                buff = dma_alloc_coherent(dlp_drv.controller,
@@ -253,7 +253,7 @@ struct hsi_msg *dlp_pdu_alloc(unsigned int hsi_channel,
 {
        struct hsi_msg *new;
        void *buffer;
-       int flags = in_interrupt()? GFP_ATOMIC : GFP_KERNEL;
+       int flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 
        PROLOG("%d, %s, size:%d",
               hsi_channel,
@@ -446,8 +446,7 @@ unsigned int dlp_pdu_get_offset(struct hsi_msg *pdu)
 inline unsigned int dlp_pdu_get_length(struct hsi_msg *pdu)
 {
        u32 *header = (u32 *)(sg_virt(pdu->sgt.sgl));
-
-       return (header[2] & 0x3FFFF);
+       return header[2] & 0x3FFFF;
 }
 
 
@@ -468,10 +467,14 @@ void dlp_pdu_update(struct dlp_channel *ch_ctx, struct hsi_msg *pdu)
        if ((!pdu->break_frame) && (pdu->status == HSI_STATUS_COMPLETED)) {
                pdu->actual_len = dlp_pdu_get_length(pdu);
        } else {
-               CRITICAL
-                   ("Invalid RX pdu (0x%p) status [status: %d, break_frame: %d,"
-                    " actual_len: %d", pdu, pdu->status, pdu->break_frame,
-                    pdu->actual_len);
+               CRITICAL("Invalid RX pdu (0x%p)"
+                               " status [status: %d,"
+                               " break_frame: %d,"
+                               " actual_len: %d",
+                               pdu,
+                               pdu->status,
+                               pdu->break_frame,
+                               pdu->actual_len);
 
                pdu->actual_len = 1;
        }
@@ -520,7 +523,7 @@ inline unsigned int dlp_pdu_room_in(struct hsi_msg *pdu)
 {
        unsigned int used_len = pdu->actual_len + DLP_TTY_HEADER_LENGTH;
 
-       return (pdu->sgt.sgl->length - used_len);
+       return pdu->sgt.sgl->length - used_len;
 }
 
 /**
@@ -565,9 +568,9 @@ static void dlp_pdu_destructor(struct hsi_msg *pdu)
  * Returns the current state of the requested TX or RX context.
  */
 static inline __must_check
-    unsigned int _dlp_ctx_get_state(struct dlp_xfer_ctx *xfer_ctx)
+unsigned int _dlp_ctx_get_state(struct dlp_xfer_ctx *xfer_ctx)
 {
-       return (xfer_ctx->state & DLP_GLOBAL_STATE_MASK);
+       return xfer_ctx->state & DLP_GLOBAL_STATE_MASK;
 }
 
 /**
@@ -602,7 +605,7 @@ static inline __must_check int dlp_ctx_is_state(struct dlp_xfer_ctx *xfer_ctx,
  * This version adds the spinlock guarding
  */
 inline __must_check
-    unsigned int dlp_ctx_get_state(struct dlp_xfer_ctx *xfer_ctx)
+unsigned int dlp_ctx_get_state(struct dlp_xfer_ctx *xfer_ctx)
 {
        unsigned int state;
        unsigned long flags;
@@ -765,7 +768,7 @@ void dlp_ctx_update_status(struct dlp_xfer_ctx *xfer_ctx)
 
                sg = pdu->sgt.sgl;
 
-               // FIXME: To be removed !!!
+               /* FIXME: To be removed !!! */
                sg->length = xfer_ctx->payload_len + DLP_TTY_HEADER_LENGTH;
 
                read_unlock_irqrestore(&xfer_ctx->lock, flags);
@@ -841,16 +844,15 @@ static inline void dlp_ctx_update_state(struct dlp_xfer_ctx *xfer_ctx)
  * Returns a reference to the last pdu of this FIFO or NULL if the FIFO is
  * empty.
  */
-inline __must_check
-    struct hsi_msg *dlp_fifo_tail(struct dlp_xfer_ctx *xfer_ctx,
-                                 struct list_head *fifo)
+inline __must_check struct hsi_msg *
+dlp_fifo_tail(struct dlp_xfer_ctx *xfer_ctx,
+                       struct list_head *fifo)
 {
        struct hsi_msg *pdu = NULL;
 
        /* Empty ? */
-       if (! list_empty(fifo)) {
+       if (!list_empty(fifo))
                pdu = list_entry(fifo->prev, struct hsi_msg, link);
-       }
 
        return pdu;
 }
@@ -920,7 +922,7 @@ struct hsi_msg *dlp_fifo_wait_pop(struct dlp_xfer_ctx *xfer_ctx)
        /* Remove the pdu from the list */
        list_del_init(&pdu->link);
 
-       xfer_ctx->wait_len --;
+       xfer_ctx->wait_len--;
        xfer_ctx->buffered -= pdu->actual_len;
 
 out:
@@ -1011,9 +1013,8 @@ void dlp_pop_wait_push_ctrl(struct dlp_xfer_ctx *xfer_ctx,
        if (!pdu)
                goto out;
 
-       if (check_pdu) {
+       if (check_pdu)
                ok = !pdu->break_frame;
-       }
 
        if (ok) {
                /* Note that no error is returned upon transfer failure,
@@ -1213,8 +1214,8 @@ int dlp_hsi_controller_push(struct dlp_xfer_ctx *xfer_ctx, struct hsi_msg *pdu)
 
        /* Dump the PDU */
        if (pdu->ttype == HSI_MSG_WRITE) {
-               dlp_pdu_dump(pdu, 0);
-               /* dlp_dbg_dump_pdu(pdu, 16, 160, 0); */
+               /* dlp_pdu_dump(pdu, 0);
+               dlp_dbg_dump_pdu(pdu, 16, 160, 0); */
        }
 
        err = hsi_async(pdu->cl, pdu);
@@ -1399,8 +1400,7 @@ inline void dlp_hsi_port_unclaim(void)
  */
 static void dlp_hsi_start_rx_cb(struct hsi_client *cl)
 {
-       // FIXME: only ch_ctx[1]
-       struct dlp_channel *ch_ctx = (struct dlp_channel *)hsi_client_drvdata(cl);
+       struct dlp_channel *ch_ctx = hsi_client_drvdata(cl);
        struct dlp_xfer_ctx *xfer_ctx = &ch_ctx->rx;
 
        PROLOG();
@@ -1419,8 +1419,7 @@ static void dlp_hsi_start_rx_cb(struct hsi_client *cl)
  */
 static void dlp_hsi_stop_rx_cb(struct hsi_client *cl)
 {
-       // FIXME: only ch_ctx[1]
-       struct dlp_channel *ch_ctx = (struct dlp_channel *)hsi_client_drvdata(cl);
+       struct dlp_channel *ch_ctx = hsi_client_drvdata(cl);
        struct dlp_xfer_ctx *xfer_ctx = &ch_ctx->rx;
 
        PROLOG();
@@ -1436,7 +1435,8 @@ static void dlp_hsi_stop_rx_cb(struct hsi_client *cl)
 * @param start_rx_cb : Start RX callback backup function
 * @param stop_rx_cb : Stop RX callback backup function
 */
-void dlp_save_rx_callbacks(hsi_client_cb *start_rx_cb, hsi_client_cb *stop_rx_cb)
+void dlp_save_rx_callbacks(hsi_client_cb *start_rx_cb,
+               hsi_client_cb *stop_rx_cb)
 {
        PROLOG();
 
@@ -1457,7 +1457,8 @@ void dlp_save_rx_callbacks(hsi_client_cb *start_rx_cb, hsi_client_cb *stop_rx_cb
 * @param start_rx_cb : Start RX callback to set
 * @param stop_rx_cb : Stop RX callback to set
 */
-void dlp_restore_rx_callbacks(hsi_client_cb *start_rx_cb, hsi_client_cb *stop_rx_cb)
+void dlp_restore_rx_callbacks(hsi_client_cb *start_rx_cb,
+               hsi_client_cb *stop_rx_cb)
 {
        PROLOG();
 
@@ -1472,6 +1473,51 @@ void dlp_restore_rx_callbacks(hsi_client_cb *start_rx_cb, hsi_client_cb *stop_rx
        EPILOG();
 }
 
+/*
+* @brief This function will:
+*       - Release the HSI client
+*       - Update the HSI client configuration (Use IPC/Flashing config)
+*       - Claim the HSI client again
+*
+* @param value : ON/OFF to activate/deactivate the flashing mode
+*/
+int dlp_set_flashing_mode(int value)
+{
+       int ret;
+
+       PROLOG();
+
+       /* Release the HSI controller */
+       dlp_hsi_port_unclaim();
+
+       /* Flush everything */
+       hsi_flush(dlp_drv.client);
+
+       if (value) {
+               /* Set the Boot/Flashing configs */
+               dlp_drv.client->tx_cfg = dlp_drv.flash_tx_cfg;
+               dlp_drv.client->rx_cfg = dlp_drv.flash_rx_cfg;
+
+               /* Disable the IPC RX start/stop cb */
+               dlp_save_rx_callbacks(&dlp_drv.start_rx_cb,
+                               &dlp_drv.stop_rx_cb);
+       } else {
+               /* Set IPC configs */
+               dlp_drv.client->tx_cfg = dlp_drv.ipc_tx_cfg;
+               dlp_drv.client->rx_cfg = dlp_drv.ipc_rx_cfg;
+
+               /* Restore the IPC RX start/stop cb */
+               dlp_restore_rx_callbacks(&dlp_drv.start_rx_cb,
+                               &dlp_drv.stop_rx_cb);
+       }
+
+       /* Claim the HSI port (to use for IPC) */
+       ret = dlp_hsi_port_claim();
+
+       EPILOG();
+       return ret;
+}
+
 /**
  * dlp_increase_pdus_pool - background work aimed at creating new pdus
  * @work: a reference to the work context
@@ -1508,7 +1554,8 @@ static void dlp_increase_pdus_pool(struct work_struct *work)
                while (!new) {
                        ++retry;
                        if (retry == DLP_PDU_ALLOC_RETRY_MAX_CNT) {
-                               CRITICAL("Cannot allocate a pdu after %d retries...", retry);
+                               CRITICAL("Cannot allocate a pdu after "
+                                               "%d retries...", retry);
                                retry = 0;
                        }
 
@@ -1556,8 +1603,8 @@ static void dlp_increase_pdus_pool(struct work_struct *work)
 * @param data : Timeout callback user data
 */
 void dlp_hangup_ctx_init(struct dlp_channel *ch_ctx,
-               void (* work_func)(struct work_struct *work),
-               void (* timeout_func)(unsigned long int param),
+               void (*work_func)(struct work_struct *work),
+               void (*timeout_func)(unsigned long int param),
                void *data)
 {
        PROLOG();
@@ -1594,7 +1641,7 @@ void dlp_hangup_ctx_deinit(struct dlp_channel *ch_ctx)
        write_unlock_irqrestore(&xfer_ctx->lock, flags);
 
        /* No need to wait for the end of the calling work! */
-       if (! is_hunging_up) {
+       if (!is_hunging_up) {
                if (del_timer_sync(&ch_ctx->hangup.timer))
                        cancel_work_sync(&ch_ctx->hangup.work);
                else
@@ -1706,7 +1753,8 @@ static void dlp_driver_cleanup(void)
                dlp_tty_ctx_delete,             /* TTY  */
                dlp_net_ctx_delete,             /* NET  */
                dlp_net_ctx_delete,             /* NET  */
-               dlp_net_ctx_delete};    /* NET  */
+               dlp_net_ctx_delete,             /* NET  */
+               dlp_flash_ctx_delete};  /* BOOT/FLASHING  */
 
        PROLOG();
 
@@ -1747,7 +1795,8 @@ static int __init dlp_driver_probe(struct device *dev)
                dlp_tty_ctx_create,             /* TTY  */
                dlp_net_ctx_create,             /* NET  */
                dlp_net_ctx_create,             /* NET  */
-               dlp_net_ctx_create};    /* NET  */
+               dlp_net_ctx_create,             /* NET  */
+               dlp_flash_ctx_create};  /* BOOT/FLASHING */
 
        PROLOG();
 
@@ -1758,9 +1807,8 @@ static int __init dlp_driver_probe(struct device *dev)
        spin_lock_init(&dlp_drv.lock);
 
        /* Warn if no DMA capability */
-       if (!dlp_drv.is_dma_capable) {
+       if (!dlp_drv.is_dma_capable)
                WARNING("HSI device is not DMA capable");
-       }
 
        /* Save IPC controller configs */
        dlp_drv.ipc_rx_cfg = client->rx_cfg;
@@ -1774,18 +1822,14 @@ static int __init dlp_driver_probe(struct device *dev)
        dlp_drv.flash_rx_cfg.channels = 1;
        dlp_drv.flash_tx_cfg.channels = 1;
 
-       /* FIXME: Claim the HSI port */
-       ret = dlp_hsi_port_claim();
-       if (ret) {
-               goto out;
-       }
+       /* Start in IPC mode */
+       dlp_set_flashing_mode(0);
 
        /* Create DLP contexts */
        for (i = 0; i < DLP_CHANNEL_COUNT; i++) {
                dlp_drv.channels[i] = create_funcs[i] (i, dev);
-               if (!dlp_drv.channels[i]) {
+               if (!dlp_drv.channels[i])
                        goto cleanup;
-               }
        }
 
        /*  */
@@ -1796,8 +1840,8 @@ static int __init dlp_driver_probe(struct device *dev)
        hsi_client_set_drvdata(client, dlp_drv.channels[DLP_CHANNEL_TTY]);
 
        /* Create /proc/hsi-dlp */
-       // FIXME: Will be removed
-       //if (dlp_drv.debug)
+       /* FIXME: Will be removed */
+       /*if (dlp_drv.debug) */
        {
                proc_create_data(DRVNAME, S_IRUGO, NULL, &dlp_proc_ops, NULL);
        }
@@ -1808,7 +1852,6 @@ static int __init dlp_driver_probe(struct device *dev)
 cleanup:
        dlp_driver_cleanup();
 
-out:
        EPILOG("%d", ret);
        return ret;
 }
@@ -1944,4 +1987,4 @@ MODULE_AUTHOR("Olivier Stoltz Douchet <olivierx.stoltz-douchet@intel.com>");
 MODULE_AUTHOR("Faouaz Tenoutit <faouazx.tenoutit@intel.com>");
 MODULE_DESCRIPTION("LTE protocol driver over HSI for IMC modems");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("1.1-HSI-LTE");
+MODULE_VERSION("1.2-HSI-LTE");
index d1ea950..b1b9034 100644 (file)
 /* Compute the TX and RX, FIFO depth from the buffering requirements */
 /* For optimal performances the DLP_HSI_TX_CTRL_FIFO size shall be set to 2 at
  * least to allow back-to-back transfers. */
-#define DLP_TX_MAX_LEN ((DLP_MIN_TX_BUFFERING+DLP_PAYLOAD_LENGTH-1)/DLP_PAYLOAD_LENGTH)
-#define DLP_RX_MAX_LEN ((DLP_MIN_RX_BUFFERING+DLP_PAYLOAD_LENGTH-1)/DLP_PAYLOAD_LENGTH)
+#define DLP_TX_MAX_LEN ((DLP_MIN_TX_BUFFERING+DLP_PAYLOAD_LENGTH-1) \
+               /DLP_PAYLOAD_LENGTH)
+
+#define DLP_RX_MAX_LEN ((DLP_MIN_RX_BUFFERING+DLP_PAYLOAD_LENGTH-1) \
+               /DLP_PAYLOAD_LENGTH)
 
 #define DLP_HSI_TX_CTRL_FIFO   2
 #define DLP_HSI_TX_WAIT_FIFO   max(DLP_TX_MAX_LEN-DLP_HSI_TX_CTRL_FIFO, 1)
@@ -91,6 +94,9 @@
 /* PDU size for CTRL channel */
 #define DLP_CTRL_PDU_SIZE      4       /* 4 Bytes */
 
+/* PDU size for Flashing channel */
+#define DLP_FLASH_PDU_SIZE     4       /* 4 Bytes */
+
 /* Alignment params */
 #define DLP_PACKET_ALIGN_AP            16
 #define DLP_PACKET_ALIGN_CP            16
 #define DLP_HDR_COMPLETE_PACKET         (0x3 << 29)
 
 #ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
 /*
+ * Number of /dev/tty exported for IPC
+ * Currently only one is used (/dev/ttyIFX0)
+ */
+#define DLP_TTY_DEV_NUM 1
+
+
+/*
  * Get a ref to the given channel context
  */
 #define DLP_CHANNEL_CTX(hsi_ch) dlp_drv.channels[hsi_ch]
@@ -136,6 +149,7 @@ enum {
        DLP_CHANNEL_NET2,       /* HSI Channel 3 */
        DLP_CHANNEL_NET3,       /* HSI Channel 4 */
 
+       DLP_CHANNEL_FLASH,      /* HSI Channel 0 */
        DLP_CHANNEL_COUNT
 };
 
@@ -146,12 +160,12 @@ enum {
 /*
  * HSI transfer complete callback prototype
  */
-typedef void (*xfer_complete_cb) (struct hsi_msg * pdu);
+typedef void (*xfer_complete_cb) (struct hsi_msg *pdu);
 
 /*
  * HSI client start/stop RX callback prototype
  */
-typedef void (*hsi_client_cb) (struct hsi_client * cl);
+typedef void (*hsi_client_cb) (struct hsi_client *cl);
 
 /**
  * struct dlp_xfer_ctx - TX/RX transfer context
@@ -256,11 +270,11 @@ struct dlp_channel {
        struct dlp_hangup_ctx hangup;
 
        /* Reset & Coredump callbacks */
-       void (*modem_coredump_cb) (struct dlp_channel * ch_ctx);
-       void (*modem_reset_cb) (struct dlp_channel * ch_ctx);
+       void (*modem_coredump_cb) (struct dlp_channel *ch_ctx);
+       void (*modem_reset_cb) (struct dlp_channel *ch_ctx);
 
        /* Credits callback */
-       void (*credits_available_cb) (struct dlp_channel * ch_ctx);
+       void (*credits_available_cb) (struct dlp_channel *ch_ctx);
 
        /* Channel sepecific data */
        void *ch_data;
@@ -280,6 +294,8 @@ struct dlp_channel {
  * @ipc_xx_cfg: HSI client configuration (Used for IPC RX)
  * @flash_tx_cfg: HSI client configuration (Used for Boot/Flashing TX)
  * @flash_rx_cfg: HSI client configuration (Used for Boot/Flashing RX)
+ * @start_rx_cb: HSI client start RX callback
+ * @stop_rx_cb: HSI client stop RX callback
  *
  * @debug: Debug variable
  */
@@ -300,6 +316,10 @@ struct dlp_driver {
        int modem_ready;
        spinlock_t lock;
 
+       /* RX start/stop callbacks */
+       hsi_client_cb start_rx_cb;
+       hsi_client_cb stop_rx_cb;
+
        /* Modem boot/flashing */
        struct hsi_config ipc_tx_cfg;
        struct hsi_config ipc_rx_cfg;
@@ -307,6 +327,9 @@ struct dlp_driver {
        struct hsi_config flash_tx_cfg;
        struct hsi_config flash_rx_cfg;
 
+       /* Platform data */
+
+
        /* Debug variables */
        int debug;
 };
@@ -315,16 +338,23 @@ struct dlp_driver {
  * Context alloc/free function proptype
  */
 typedef struct dlp_channel *(*dlp_context_create) (unsigned int index,
-                                                  struct device * dev);
+                                                  struct device *dev);
 
-typedef int (*dlp_context_delete) (struct dlp_channel * ch_ctx);
+typedef int (*dlp_context_delete) (struct dlp_channel *ch_ctx);
+
+/****************************************************************************
+ *
+ * IPC/FLASH switching
+ *
+ ***************************************************************************/
+int dlp_set_flashing_mode(int on_off);
 
 /****************************************************************************
  *
  * PDU handling
  *
  ***************************************************************************/
-void *dlp_buffer_alloc(unsigned int buff_size, dma_addr_t * dma_addr);
+void *dlp_buffer_alloc(unsigned int buff_size, dma_addr_t *dma_addr);
 
 void dlp_buffer_free(void *buff, dma_addr_t dma_addr, unsigned int buff_size);
 
@@ -358,7 +388,7 @@ unsigned int dlp_pdu_get_offset(struct hsi_msg *pdu);
 inline unsigned int dlp_pdu_room_in(struct hsi_msg *pdu);
 
 inline __attribute_const__
-    unsigned char *dlp_pdu_data_ptr(struct hsi_msg *pdu, unsigned int offset);
+unsigned char *dlp_pdu_data_ptr(struct hsi_msg *pdu, unsigned int offset);
 
 /****************************************************************************
  *
@@ -366,7 +396,7 @@ inline __attribute_const__
  *
  ***************************************************************************/
 inline __must_check
-    unsigned int dlp_ctx_get_state(struct dlp_xfer_ctx *xfer_ctx);
+unsigned int dlp_ctx_get_state(struct dlp_xfer_ctx *xfer_ctx);
 
 inline void dlp_ctx_set_state(struct dlp_xfer_ctx *xfer_ctx,
                              unsigned int state);
@@ -394,7 +424,7 @@ void dlp_ctx_update_status(struct dlp_xfer_ctx *xfer_ctx);
  *
  ***************************************************************************/
 inline __must_check
-    struct hsi_msg *dlp_fifo_tail(struct dlp_xfer_ctx *xfer_ctx,
+struct hsi_msg *dlp_fifo_tail(struct dlp_xfer_ctx *xfer_ctx,
                                  struct list_head *fifo);
 
 inline void _dlp_fifo_pdu_push(struct hsi_msg *pdu, struct list_head *fifo);
@@ -462,8 +492,8 @@ void dlp_restore_rx_callbacks(hsi_client_cb *start_rx_cb,
  ***************************************************************************/
 
 void dlp_hangup_ctx_init(struct dlp_channel *ch_ctx,
-               void (* work_func)(struct work_struct *work),
-               void (* timeout_func)(unsigned long int param),
+               void (*work_func)(struct work_struct *work),
+               void (*timeout_func)(unsigned long int param),
                void *data);
 
 void dlp_hangup_ctx_deinit(struct dlp_channel *ch_ctx);
@@ -501,6 +531,8 @@ int dlp_ctrl_ctx_delete(struct dlp_channel *ch_ctx);
 
 void dlp_ctrl_modem_reset(struct dlp_channel *ch_ctx);
 
+void dlp_ctrl_modem_power(struct dlp_channel *ch_ctx);
+
 inline int dlp_ctrl_get_reset_ongoing(void);
 
 inline void dlp_ctrl_set_reset_ongoing(int ongoing);
@@ -536,6 +568,16 @@ int dlp_net_ctx_delete(struct dlp_channel *ch_ctx);
 
 /****************************************************************************
  *
+ * Boot/Flashing channel exported functions
+ *
+ ***************************************************************************/
+struct dlp_channel *dlp_flash_ctx_create(unsigned int index,
+               struct device *dev);
+
+int dlp_flash_ctx_delete(struct dlp_channel *ch_ctx);
+
+/****************************************************************************
+ *
  * Global variables
  *
  ***************************************************************************/
index a508ded..deca9de 100644 (file)
@@ -193,7 +193,7 @@ static void dlp_net_complete_tx(struct hsi_msg *pdu)
        dev_kfree_skb(msg_param->skb);
 
        /* Dump the PDU */
-       // dlp_pdu_dump(pdu, 1);
+       /* dlp_pdu_dump(pdu, 1); */
 
        /* Update statistics */
        net_ctx->ndev->stats.tx_bytes += pdu->actual_len;
@@ -276,7 +276,8 @@ static void dlp_net_complete_rx(struct hsi_msg *pdu)
                     data_addr, offset, data_size);
 
                /* Dump the first 160 bytes */
-               // dlp_dbg_dump_data_as_byte(data_addr, MIN(data_size, 160), 16, 0);
+               /* dlp_dbg_dump_data_as_byte(data_addr,
+                               MIN(data_size, 160), 16, 0); */
 
                /*
                 * The packet has been retrieved from the transmission
@@ -284,9 +285,8 @@ static void dlp_net_complete_rx(struct hsi_msg *pdu)
                 */
                skb = netdev_alloc_skb_ip_align(net_ctx->ndev, data_size);
                if (!skb) {
-                       CRITICAL
-                           ("No more memory (data_size: %d) - packet dropped\n",
-                            data_size);
+                       CRITICAL("No more memory (data_size: %d)"
+                                  " - packet dropped\n", data_size);
 
                        net_ctx->ndev->stats.rx_dropped++;
                        goto out;
@@ -301,7 +301,8 @@ static void dlp_net_complete_rx(struct hsi_msg *pdu)
                skb->ip_summed = CHECKSUM_UNNECESSARY;  /* don't check it */
 
                /* Dump the first 160 bytes */
-               //dlp_dbg_dump_data_as_byte(skb->data, MIN(skb->len, 160), 16, 0);
+               /* dlp_dbg_dump_data_as_byte(skb->data,
+                               MIN(skb->len, 160), 16, 0);*/
 
                /* Push received packet up to the IP networking stack */
                ret = netif_rx(skb);
@@ -317,8 +318,7 @@ static void dlp_net_complete_rx(struct hsi_msg *pdu)
                        net_ctx->ndev->stats.rx_bytes += data_size;
                        net_ctx->ndev->stats.rx_packets++;
                }
-       }
-       while (more_packets);
+       } while (more_packets);
 
        ret = 0;
 
@@ -377,13 +377,12 @@ int dlp_net_open(struct net_device *dev)
        PROLOG("%s, hsi_ch:%d", dev->name, ch_ctx->hsi_channel);
 
        /* Check the modem readiness */
-       if (! dlp_ctrl_modem_is_ready()) {
+       if (!dlp_ctrl_modem_is_ready()) {
                CRITICAL("Unale to open NETWORK IF (Modem NOT ready) !");
                ret = -EBUSY;
                goto out;
        }
 
-       // FIXME: To be removed (done in dlp_net_ctx_create)
        ret = dlp_ctrl_open_channel(ch_ctx);
        if (ret) {
                CRITICAL("dlp_ctrl_open_channel() failed !");
@@ -424,12 +423,8 @@ int dlp_net_stop(struct net_device *dev)
                netif_stop_queue(dev);
 
        ret = dlp_ctrl_close_channel(ch_ctx);
-       if (ret) {
+       if (ret)
                CRITICAL("dlp_ctrl_close_channel() failed !");
-       }
-
-       /* FIXME : Will flush everything */
-       // hsi_flush(dlp_drv.client);
 
        /* RX */
        del_timer_sync(&rx_ctx->timer);
@@ -486,14 +481,12 @@ static int dlp_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        /* Dump the first 160 bytes */
-       // dlp_dbg_dump_data_as_byte(skb->data, MIN(skb->len, 160), 16);
+       /* dlp_dbg_dump_data_as_byte(skb->data, MIN(skb->len, 160), 16); */
 
        if (skb->len < ETH_ZLEN) {
-               // WARNING("Padding received packet (too small size: %d)", skb->len);
-
-               if (skb_padto(skb, ETH_ZLEN)) {
+               /* WARNING("Padding received packet (size: %d)", skb->len); */
+               if (skb_padto(skb, ETH_ZLEN))
                        return NETDEV_TX_OK;
-               }
        }
 
        /* Set msg params */
@@ -504,46 +497,14 @@ static int dlp_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Save the timestamp */
        dev->trans_start = jiffies;
 
-       /* Set the IP header */
-#if 0                          // FIXME : Check if it is V4/6
-       struct iphdr *iph;
-
-       iph = ip_hdr(skb);
-       iph->check = 0;
-
-       {
-               unsigned int saddr, daddr;
-               char *s, *d;
-
-#define        BYTE(b) (((int)b)&0xff)
-
-               saddr = htonl(iph->saddr);
-               daddr = htonl(iph->daddr);
-
-               s = (char *)&saddr;
-               d = (char *)&daddr;
-
-               PDEBUG("\n\tver: 0x%x, ihl: 0x%x, tos: 0x%x, tot_len: %d\n"
-                      "\tid : 0x%x, frag_off: 0x%x\n"
-                      "\tttl: 0x%x, protocol: 0x%x, check: 0x%x\n"
-                      "\tsaddr: [%u.%u.%u.%u]\n"
-                      "\tdaddr: [%u.%u.%u.%u]\n",
-                      iph->version, iph->ihl, iph->tos, ntohs(iph->tot_len),
-                      ntohs(iph->id), ntohs(iph->frag_off),
-                      iph->ttl, iph->protocol, iph->check,
-                      BYTE(s[3]), BYTE(s[2]), BYTE(s[1]), BYTE(s[0]),
-                      BYTE(d[3]), BYTE(d[2]), BYTE(d[1]), BYTE(d[0]));
-       }
-
-       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-#endif
-
        /* Compute the number of needed padding entries */
        nb_padding = 1;
        if (skb_has_frag_list(skb)) {
                for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       align_size = IS_ALIGNED(skb_shinfo(skb)->frags[i].size,
+                                               DLP_PACKET_ALIGN_CP);
                        /* Size aligned ? */
-                       nb_padding += (IS_ALIGNED(skb_shinfo(skb)->frags[i].size,DLP_PACKET_ALIGN_CP) ? 0 : 1);
+                       nb_padding += (align_size ? 0 : 1);
                }
        }
 
@@ -614,7 +575,7 @@ static int dlp_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                /* Set the size */
                ptr++;
-               (*ptr) = (DLP_HDR_NO_MORE_DESC | DLP_HDR_COMPLETE_PACKET | skb_len);
+               (*ptr) = (DLP_HDR_NO_MORE_DESC|DLP_HDR_COMPLETE_PACKET|skb_len);
                (*ptr) += DLP_HDR_SPACE_CP;
 
                /* Set the packet SG entry */
@@ -650,8 +611,7 @@ static int dlp_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        /* Update the offset value */
                        offset += skb_len + DLP_HDR_SPACE_CP;
                }
-       }
-       while (i < nb_packets);
+       } while (i < nb_packets);
 
        /* Write the padding entry (Check 4 bytes alignment) */
        /*---------------------------------------------------*/
@@ -666,33 +626,6 @@ static int dlp_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        PRINT_TX("TX: Entry %d (Padding): offset: 0x%x, size:0x%x\n", i, offset,
                 padding_len);
 
-#if  0
-       /* */
-       u32 first_len, first_mapping;
-       int frag, first_entry = entry;
-
-       BUG_ON(1);
-
-       /* give this initial chunk to the */
-       first_len = skb_headlen(skb);
-       first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len,
-                                      DMA_TO_DEVICE);
-       entry = NEXT_TX(entry);
-
-       for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
-               skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
-               u32 len, mapping, this_txflags;
-
-               len = this_frag->size;
-               mapping = dma_map_page(hp->dma_dev, this_frag->page,
-                                      this_frag->page_offset, len,
-                                      DMA_TO_DEVICE);
-               // Process
-
-               entry = NEXT_TX(entry);
-       }
-#endif
-
        ret = dlp_hsi_controller_push(&ch_ctx->tx, new);
        if (ret) {
                ret = NETDEV_TX_BUSY;
@@ -765,10 +698,10 @@ void dlp_net_dev_setup(struct net_device *dev)
        dev->watchdog_timeo = DLP_NET_TX_DELAY;
 
        /* fill in the other fields */
-//  dev->features = NETIF_F_SG | NETIF_F_NO_CSUM; // FIXME: wget is KO
+       /*  dev->features = NETIF_F_SG | NETIF_F_NO_CSUM; FIXME: wget is KO */
 
        dev->type = ARPHRD_NONE;
-       dev->mtu = DLP_NET_PDU_SIZE;    // FIXME: check wget crash
+       dev->mtu = DLP_NET_PDU_SIZE;    /* FIXME: check wget crash */
        dev->tx_queue_len = 10;
        dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
 
@@ -858,15 +791,6 @@ struct dlp_channel *dlp_net_ctx_create(unsigned int index, struct device *dev)
                          DLP_HSI_RX_WAIT_FIFO, DLP_HSI_RX_CTRL_FIFO,
                          dlp_net_complete_rx, HSI_MSG_READ);
 
-       /* Open the HSI channel */
-#if 0 /* FIXME : to be activated when the modem boot time is optimized */
-       ret = dlp_ctrl_open_channel(ch_ctx);
-       if (ret) {
-             CRITICAL("dlp_ctrl_open_channel() failed !");
-             goto free_dev;
-       }
-#endif
-
        /* Allocate RX FIFOs in background */
        queue_work(dlp_drv.recycle_wq, &ch_ctx->rx.increase_pool);
 
@@ -896,14 +820,6 @@ int dlp_net_ctx_delete(struct dlp_channel *ch_ctx)
        dlp_xfer_ctx_clear(&ch_ctx->rx);
        dlp_xfer_ctx_clear(&ch_ctx->tx);
 
-#if 0 /* FIXME : Not supported by the modem */
-       /* Release the HSI channel */
-       ret = dlp_ctrl_send_cancel_conn_cmd(ch_ctx);
-       if (ret) {
-             CRITICAL("dlp_ctrl_send_cancel_conn_cmd() failed !");
-       }
-#endif
-
        /* Free the padding buffer */
        dlp_buffer_free(net_ctx->net_padd,
                        net_ctx->net_padd_dma, DLP_NET_PDU_SIZE);
index 3ce11d4..5d0ccd6 100644 (file)
@@ -127,21 +127,21 @@ static void dlp_tty_mdm_reset_cb(struct dlp_channel *ch_ctx)
 
 /**
  * dlp_tty_pdu_data_ptr - helper function for getting the actual virtual address of
- *                                     a pdu data, taking into account the header offset
+ *     a pdu data, taking into account the header offset
+ *
  * @pdu: a reference to the considered pdu
  * @offset: an offset to add to the current virtual address of the pdu data
  *
  * Returns the virtual base address of the actual pdu data
  */
 inline __attribute_const__
-    unsigned char *dlp_tty_pdu_data_ptr(struct hsi_msg *pdu, unsigned int offset)
+unsigned char *dlp_tty_pdu_data_ptr(struct hsi_msg *pdu, unsigned int offset)
 {
        u32 *addr = sg_virt(pdu->sgt.sgl);
 
        /* Skip the Signature (+2) & Start address (+2) */
        addr += 4;
-
-       return (((unsigned char *)addr) + offset);
+       return ((unsigned char *)addr) + offset;
 }
 
 /**
@@ -205,8 +205,8 @@ static void dlp_tty_wakeup(struct dlp_channel *ch_ctx)
  *     - Pushing as much data as possible to the TTY interface
  *  - Recycling pdus that have been fully forwarded
  *  - Kicking a TTY insert
- *  - Restart delayed job if some data is remaining in the waiting FIFO or if the
- *    controller FIFO is not full yet.
+ *  - Restart delayed job if some data is remaining in the waiting FIFO
+ *       or if the controller FIFO is not full yet.
  */
 static void _dlp_forward_tty(struct tty_struct *tty,
                            struct dlp_xfer_ctx *xfer_ctx)
@@ -292,8 +292,9 @@ free_pdu:
 
 no_more_tty_insert:
        if (do_push) {
-               /* Schedule a flip since called from complete_rx() in an interrupt
-               * context instead of tty_flip_buffer_push() */
+               /* Schedule a flip since called from complete_rx()
+                * in an interrupt context instead of
+                * tty_flip_buffer_push() */
                tty_schedule_flip(tty);
        }
 
@@ -393,7 +394,7 @@ static void dlp_tty_complete_tx(struct hsi_msg *pdu)
        dlp_ctrl_set_reset_ongoing(0);
 
        /* Dump the PDU */
-       // dlp_pdu_dump(pdu, 1);
+       /* dlp_pdu_dump(pdu, 1); */
 
        /* Recycle or Free the pdu */
        write_lock_irqsave(&xfer_ctx->lock, flags);
@@ -595,7 +596,6 @@ static int dlp_tty_port_activate(struct tty_port *port, struct tty_struct *tty)
        dlp_ctx_update_status(rx_ctx);
 
        /* Configure the DLP channel */
-       // FIXME: To be removed (should be done in dlp_tty_ctx_create)
        if (tty->count == 1) {
                ret = dlp_ctrl_open_channel(ch_ctx);
                if (ret) {
@@ -643,9 +643,6 @@ static void dlp_tty_port_shutdown(struct tty_port *port)
 
        del_timer_sync(&ch_ctx->hangup.timer);
 
-       // FIXME: FTE
-       // hsi_flush(dlp_drv.client);
-
        /* RX */
        del_timer(&rx_ctx->timer);
        dlp_tty_rx_fifo_wait_recycle(rx_ctx);
@@ -660,9 +657,8 @@ static void dlp_tty_port_shutdown(struct tty_port *port)
 
        /* Close the HSI channel */
        ret = dlp_ctrl_close_channel(ch_ctx);
-       if (ret) {
+       if (ret)
                CRITICAL("dlp_ctrl_close_channel() failed !");
-       }
 
        PDEBUG("tty port shut down");
        EPILOG();
@@ -686,7 +682,7 @@ static int dlp_tty_open(struct tty_struct *tty, struct file *filp)
        PROLOG();
 
        /* Check the modem readiness */
-       if (! dlp_ctrl_modem_is_ready()) {
+       if (!dlp_ctrl_modem_is_ready()) {
                CRITICAL("Unale to open TTY (Modem NOT ready) !");
                ret = -EBUSY;
                goto out;
@@ -900,19 +896,16 @@ int dlp_tty_do_write(struct dlp_xfer_ctx *xfer_ctx, unsigned char *buf,
                }
        }
 
-       if (!pdu) {
+       if (!pdu)
                goto out;
-       }
 
        pdu->status = HSI_STATUS_PENDING;
        /* Do a start TX on new frames only and after having marked
         * the current frame as pending, e.g. don't touch ! */
-       if (offset == 0) {
+       if (offset == 0)
                dlp_hsi_start_tx(xfer_ctx);
-       }
-       else {
+       else
                dlp_ctx_set_flag(xfer_ctx, TX_TTY_WRITE_PENDING_BIT);
-       }
 
        copied = min(avail, len);
        updated_actual_len = pdu->actual_len + copied;
@@ -1375,7 +1368,6 @@ static int dlp_tty_ioctl(struct tty_struct *tty,
 #endif
 
        case HSI_DLP_MODEM_RESET:
-               WARNING("Modem reset requested");
                dlp_ctrl_modem_reset(ch_ctx);
                break;
 
@@ -1393,6 +1385,10 @@ static int dlp_tty_ioctl(struct tty_struct *tty,
                return ret;
                break;
 
+       case HSI_DLP_SET_FLASHING_MODE:
+               ret = dlp_set_flashing_mode(arg);
+               break;
+
        default:
                return -ENOIOCTLCMD;
        }
@@ -1486,7 +1482,7 @@ struct dlp_channel *dlp_tty_ctx_create(unsigned int index, struct device *dev)
        new_drv->driver_name = DRVNAME;
        new_drv->name = IPC_TTYNAME;
        new_drv->minor_start = 0;
-       new_drv->num = 1;
+       new_drv->num = DLP_TTY_DEV_NUM;
        new_drv->type = TTY_DRIVER_TYPE_SERIAL;
        new_drv->subtype = SERIAL_TYPE_NORMAL;
        new_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
index 48ca169..49de0f4 100644 (file)
@@ -264,7 +264,10 @@ struct hsi_dlp_stats {
  */
 #define HSI_DLP_NET_RESET_TX_STATS             _IOW(HSI_DLP_MAGIC, 41, unsigned int)
 
-
+/*
+ * HSI_DLP_SET_FLASHING_MODE   - Activate/Deactivate the flashing mode
+ */
+#define HSI_DLP_SET_FLASHING_MODE      _IOW(HSI_DLP_MAGIC, 42, unsigned int)
 
 #endif /* _HSI_DLP_H */