From: Olivier Stoltz Douchet Date: Tue, 10 Jan 2012 14:23:44 +0000 (+0100) Subject: [PORT FROM R2] hsi_ffl_tty.c: adding some /sys/module interface to manage modem reset X-Git-Tag: 2.1b_release~1560 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=985d22feb54fe3a6763ef3ad0c4d3e8becc2d95d;p=kernel%2Fkernel-mfld-blackbay.git [PORT FROM R2] hsi_ffl_tty.c: adding some /sys/module interface to manage modem reset BZ: 19623 This patch is adding two sysFS interfaces aimed at managing modem reset and TTY interface hang-up: - /sys/module/hsi_ffl_tty/parameters/reset_modem for resetting the modem and querying its reset status; - /sys/module/hsi_ffl_tty/parameters/hangup_reasons for accessing and clearing hang-up reasons. The /sys/module/hsi_ffl_tty/parameters/reset_modem interface is exporting some decimal data consisting of a bitfield of 1 bit per TTY interface (bit 0 for ttyIFX0, bit 1 for ttyIFX1...) where: - when written to 1 is resetting the corresponding modem (the one attached to the TTY interface); - when read to 1 is signalling that the corresponding modem is still resetting, as it did not successfully managed any TX or RX transaction. The /sys/module/hsi_ffl_tty/parameters/hangup_reasons interface is exporting some decimal data consisting of a bitfield of 1 nibble (4-bits) per TTY interface (bit0 to 3 for ttyIFX0, bit 4 to 7 for ttyIFX1...) where: - when read is getting the last hangup reasons of the considered TTY interface (bit 0 for TX timeout, bit 1 for modem reset and bit 2 for modem core dump); - when written is clearing the given hangup reasons of the considered TTY interface (bit 0 to clear TX timeout, bit 1 for modem reset and bit 2 for modem core dump). This last interface is different from the related IOCTL, which is working in a read-to-clear mode. This is no longer the case with this sysFS interface where the read data shall be written back to clear the hangup reasons. A correct management would be: 1. read /sys/module/hsi_ffl_tty/parameters/hangup_reasons, 2. write back the read value to acknowledge those hangup reasons and then, 3. perform whatever is necessary to manage the hangup reasons. See the functions header descriptions for more information regarding those new interfaces. Change-Id: I82647742ce6292950cb5216593611146c151c533 Signed-off-by: Olivier Stoltz Douchet Reviewed-on: http://android.intel.com:8080/31415 Reviewed-by: Predon, Frederic Reviewed-by: Lebsir, SamiX Tested-by: Lebsir, SamiX Reviewed-by: Lucas, GuillaumeX Reviewed-by: buildbot Tested-by: buildbot --- diff --git a/drivers/hsi/clients/hsi_ffl_tty.c b/drivers/hsi/clients/hsi_ffl_tty.c index 75545c1..cd1a026 100644 --- a/drivers/hsi/clients/hsi_ffl_tty.c +++ b/drivers/hsi/clients/hsi_ffl_tty.c @@ -44,6 +44,7 @@ #include #include #include +#include #define DRVNAME "hsi-ffl" #define TTYNAME "tty"CONFIG_HSI_FFL_TTY_NAME @@ -315,12 +316,12 @@ static struct workqueue_struct *ffl_forwarding_wq; */ /** - * modem_power - activity required to bring up modem + * do_modem_power - activity required to bring up modem * @hsi: HSI controller * * Toggle gpios required to bring up modem power and start modem. */ -static void modem_power(struct ffl_ctx *ctx) +static void do_modem_power(struct ffl_ctx *ctx) { struct hsi_client *cl = ctx->client; struct hsi_mid_platform_data *pd = cl->device.platform_data; @@ -334,12 +335,12 @@ static void modem_power(struct ffl_ctx *ctx) } /** - * modem_reset - activity required to reset modem + * do_modem_reset - activity required to reset modem * @hsi: HSI controller * * Toggle gpios required to reset modem. */ -static void modem_reset(struct ffl_ctx *ctx) +static void do_modem_reset(struct ffl_ctx *ctx) { struct hsi_client *cl = ctx->client; struct hsi_mid_platform_data *pd = cl->device.platform_data; @@ -2805,7 +2806,8 @@ static int ffl_tty_ioctl(struct tty_struct *tty, pr_debug("IO ctrl: %s(%d) reset modem\n", current->comm, current->pid); pr_debug("reset modem\n"); - modem_reset(ctx); + do_modem_reset(ctx); + do_modem_power(ctx); break; case FFL_TTY_MODEM_STATE: @@ -2831,6 +2833,156 @@ static int ffl_tty_ioctl(struct tty_struct *tty, return 0; } +/** + * reset_modem - modem reset command function + * @val: a reference to the string where the modem reset query is given + * @kp: an unused reference to the kernel parameter + * + * This call back function is resetting each and every one of the modem having + * a bit set in the /sys/module/hsi_ffl_tty/parameters/reset_modem sysFS file. + * + * The query value is actually a bit field of 1 bit per modem stating if the + * modem shall be reset or not. For instance, a query value of 0x1 means that + * the modem of ttyIFX0 will be reset. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) +static int reset_modem(const char *val, struct kernel_param *kp) +#else +static int reset_modem(const char *val, const struct kernel_param *kp) +#endif +{ + unsigned long reset_request; + struct ffl_ctx *ctx; + int i; + + if (strict_strtoul(val, 16, &reset_request) < 0) + return -EINVAL; + + for (i = 0; i < FFL_TTY_MAX_LINES; i++) { + ctx = ffl_drv.ctx[i]; + if ((ctx != NULL) && (reset_request & (1<reset.ongoing << i); + } + + return sprintf(val, "%d", reset_ongoing); +} + +/** + * clear_hangup_reasons - clearing all hangup reasons + * @val: a reference to the string where the hangup reasons clear query is given + * @kp: an unused reference to the kernel parameter + * + * This call back function is clearing each and every one of the hangup reasons + * having a nibble set in the /sys/module/hsi_ffl_tty/parameters/hangup_reasons + * sysFS file. + * + * The query value is actually a nibble field of 1 bit per modem interface + * stating what the modem hangup reasons shall be reset or not. For instance, a + * query value of 0x5 means that the TX timeout and modem core dump hangup + * reasons of ttyIFX0 shall be reset. + * + * It is then advised to write down the same value as the one read on the + * /sys/module/hsi_ffl_tty/parameters/hangup_reasons sysFS file to only clear + * the hangup reasons that have been detected. Otherwise, to clear each and + * every reason inconditionnaly a nibble of 0xF per TTY interface shall be used. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) +static int clear_hangup_reasons(const char *val, struct kernel_param *kp) +#else +static int clear_hangup_reasons(const char *val, const struct kernel_param *kp) +#endif +{ + unsigned long hangup_reasons, flags; + struct ffl_ctx *ctx; + int i, mask; + + if (strict_strtoul(val, 16, &hangup_reasons) < 0) + return -EINVAL; + + for (i = 0; i < FFL_TTY_MAX_LINES; i++) { + ctx = ffl_drv.ctx[i]; + mask = (hangup_reasons >> (4*i)) & 0xF; + if ((ctx != NULL) && (mask)) { + spin_lock_irqsave(&ctx->tx.lock, flags); + ctx->hangup.last_cause &= ~mask; + ctx->hangup.cause &= ~mask; + spin_unlock_irqrestore(&ctx->tx.lock, flags); + } + } + + return 0; +} + +/** + * hangup_reasons - modem hangup reasons module parameter callback function + * @val: a reference to the string where the hangup reasons are returned + * @kp: an unused reference to the kernel parameter + * + * This call back function is exporting all hangup reasons of each and every + * TTY interface when reading /sys/module/hsi_ffl_tty/parameters/hangup_reasons. + * + * The returned value is actually a nibble field of 4-bit per modem stating if + * the TTY interface has hang up and why it has hangup. For instance, a + * returned value of 5 is meaning that ttyIFX0 interface hang up because of + * both a TX timeout and a modem core dump. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) +static int hangup_reasons(char *val, struct kernel_param *kp) +#else +static int hangup_reasons(char *val, const struct kernel_param *kp) +#endif +{ + unsigned long flags, hangup_reasons = 0; + struct ffl_ctx *ctx; + int i; + + for (i = 0; i < FFL_TTY_MAX_LINES; i++) { + ctx = ffl_drv.ctx[i]; + if (ctx) { + spin_lock_irqsave(&ctx->tx.lock, flags); + hangup_reasons |= + (ctx->hangup.last_cause << (i*4)) | + (ctx->hangup.cause << (i*4)); + spin_unlock_irqrestore(&ctx->tx.lock, flags); + } + } + + return sprintf(val, "%d", hangup_reasons); +} + /* * Modem reset interrupt service routine */ @@ -3265,7 +3417,7 @@ static int ffl_reset_ctx_init(struct ffl_reset_ctx *ctx_reset, init_waitqueue_head(&ctx_reset->modem_awake_event); #endif - modem_power(ctx); + do_modem_power(ctx); return 0; @@ -3789,6 +3941,32 @@ static void __exit ffl_driver_exit(void) module_exit(ffl_driver_exit); /* + * Module parameters to manage the modem status through sysfs + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + +module_param_call(reset_modem, reset_modem, is_modem_reset, NULL, 0644); +module_param_call(hangup_reasons, clear_hangup_reasons, hangup_reasons, + NULL, 0644); + +#else + +static struct kernel_param_ops reset_modem_ops = { + .set = reset_modem, + .get = is_modem_reset, +}; +module_param_cb(reset_modem, &reset_modem_ops, NULL, 0644); + +static struct kernel_param_ops hangup_reasons_ops = { + .set = clear_hangup_reasons, + .get = hangup_reasons, +}; +module_param_cb(hangup_reasons, &hangup_reasons_ops, NULL, 0644); + +#endif + +/* * Module information */ MODULE_AUTHOR("Olivier Stoltz Douchet ");