From patchwork Wed Jul 28 23:40:47 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 114954 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o6SNfMPr007053 for ; Wed, 28 Jul 2010 23:41:28 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756715Ab0G1XlY (ORCPT ); Wed, 28 Jul 2010 19:41:24 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:52198 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754878Ab0G1XlM (ORCPT ); Wed, 28 Jul 2010 19:41:12 -0400 Received: by mail-bw0-f46.google.com with SMTP id 1so18052bwz.19 for ; Wed, 28 Jul 2010 16:41:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=J2ack+6FbomsvkACrcuN6kjBHjkWiAGGTrNX15bIn68=; b=fEQsr7wvt9Xkwk1jIGWnFqvtKD8pCWHvbMPXQQ5vcdUJ0ApGEi82WqfQsLESXde3lQ 4ua9wC4hTKMRQ82u14h2S6H0s4VY1qWciH/LvgIYtTXQ8VUEktG4vVFByVIZl34GJeUX hrAIlJItF+XyqboOSWJmcK97bsL+9iSBalkto= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=k4T9oHoVmm05CrXvlpG3fn5VB3Gxk6fZ4t0cNvcw0YiKdIYYHG7zaY3wDwF08IEMHk 2pVaKgyP6jnJmneXCFz8/x7EQJw0Tlr/45zAQVJz6rL3j3oGJwUNr+3iFvbxUSz4tkoO RbGyWhZXsoQm83NDviFIu0fROBBxnHEb+znZI= Received: by 10.204.10.140 with SMTP id p12mr8385469bkp.58.1280360466090; Wed, 28 Jul 2010 16:41:06 -0700 (PDT) Received: from localhost.localdomain (IGLD-84-229-112-176.inter.net.il [84.229.112.176]) by mx.google.com with ESMTPS id bq20sm104935bkb.16.2010.07.28.16.41.04 (version=SSLv3 cipher=RC4-MD5); Wed, 28 Jul 2010 16:41:05 -0700 (PDT) From: Maxim Levitsky To: lirc-list@lists.sourceforge.net Cc: Jarod Wilson , linux-input@vger.kernel.org, linux-media@vger.kernel.org, Mauro Carvalho Chehab , Christoph Bartelmus , Maxim Levitsky Subject: [PATCH 4/9] IR: add helper function for hardware with small o/b buffer. Date: Thu, 29 Jul 2010 02:40:47 +0300 Message-Id: <1280360452-8852-5-git-send-email-maximlevitsky@gmail.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1280360452-8852-1-git-send-email-maximlevitsky@gmail.com> References: <1280360452-8852-1-git-send-email-maximlevitsky@gmail.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 28 Jul 2010 23:41:28 +0000 (UTC) diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h index dc26e2b..d6ec4fe 100644 --- a/drivers/media/IR/ir-core-priv.h +++ b/drivers/media/IR/ir-core-priv.h @@ -36,6 +36,7 @@ struct ir_raw_event_ctrl { struct kfifo kfifo; /* fifo for the pulse/space durations */ ktime_t last_event; /* when last event occurred */ enum raw_event_type last_type; /* last event type */ + struct ir_raw_event current_sample; /* sample that is not yet pushed to fifo */ struct input_dev *input_dev; /* pointer to the parent input_dev */ u64 enabled_protocols; /* enabled raw protocol decoders */ diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c index 94a8577..34b9c07 100644 --- a/drivers/media/IR/ir-keytable.c +++ b/drivers/media/IR/ir-keytable.c @@ -428,7 +428,7 @@ static void ir_close(struct input_dev *input_dev) */ int __ir_input_register(struct input_dev *input_dev, const struct ir_scancode_table *rc_tab, - const struct ir_dev_props *props, + struct ir_dev_props *props, const char *driver_name) { struct ir_input_dev *ir_dev; diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c index c6a80b3..bdf2ed8 100644 --- a/drivers/media/IR/ir-raw-event.c +++ b/drivers/media/IR/ir-raw-event.c @@ -129,6 +129,92 @@ int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type typ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); /** + * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing + * @input_dev: the struct input_dev device descriptor + * @type: the type of the event that has occurred + * + * This routine (which may be called from an interrupt context) is used to + * store the beginning of an ir pulse or space (or the start/end of ir + * reception) for the raw ir decoding state machines.\ + * This routine is intended for devices with limited internal buffer + * It automerges samples of same type, and handles timeouts + */ +int ir_raw_event_store_with_filter(struct input_dev *input_dev, + struct ir_raw_event *ev) +{ + struct ir_input_dev *ir = input_get_drvdata(input_dev); + struct ir_raw_event_ctrl *raw = ir->raw; + + if (!ir->raw || !ir->props) + return -EINVAL; + + /* Ignore spaces in idle mode */ + if (ir->idle && !ev->pulse) + return 0; + else if (ir->idle) + ir_raw_event_set_idle(input_dev, 0); + + if (!raw->current_sample.duration) { + raw->current_sample = *ev; + } else if (ev->pulse == raw->current_sample.pulse) { + raw->current_sample.duration += ev->duration; + } else { + ir_raw_event_store(input_dev, &raw->current_sample); + raw->current_sample = *ev; + } + + /* Enter idle mode if nessesary */ + if (!ev->pulse && ir->props->timeout && + raw->current_sample.duration >= ir->props->timeout) + ir_raw_event_set_idle(input_dev, 1); + return 0; +} +EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); + + +void ir_raw_event_set_idle(struct input_dev *input_dev, int idle) +{ + struct ir_input_dev *ir = input_get_drvdata(input_dev); + struct ir_raw_event_ctrl *raw = ir->raw; + ktime_t now; + u64 delta; + + if (!ir->props) + return; + + if (!ir->raw) + goto out; + + if (idle) { + IR_dprintk(2, "enter idle mode\n"); + raw->last_event = ktime_get(); + } else { + IR_dprintk(2, "exit idle mode\n"); + + now = ktime_get(); + delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event)); + + WARN_ON(raw->current_sample.pulse); + + raw->current_sample.duration = + min(raw->current_sample.duration + delta, + (u64)IR_MAX_DURATION); + + ir_raw_event_store(input_dev, &raw->current_sample); + + if (raw->current_sample.duration == IR_MAX_DURATION) + ir_raw_event_reset(input_dev); + + raw->current_sample.duration = 0; + } +out: + if (ir->props->s_idle) + ir->props->s_idle(ir->props->priv, idle); + ir->idle = idle; +} +EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); + +/** * ir_raw_event_handle() - schedules the decoding of stored ir data * @input_dev: the struct input_dev device descriptor * diff --git a/include/media/ir-core.h b/include/media/ir-core.h index 513e60d..e895054 100644 --- a/include/media/ir-core.h +++ b/include/media/ir-core.h @@ -41,6 +41,9 @@ enum rc_driver_type { * anything with it. Yet, as the same keycode table can be used with other * devices, a mask is provided to allow its usage. Drivers should generally * leave this field in blank + * @timeout: optional time after which device stops sending data + * @min_timeout: minimum timeout supported by device + * @max_timeout: maximum timeout supported by device * @priv: driver-specific data, to be used on the callbacks * @change_protocol: allow changing the protocol used on hardware decoders * @open: callback to allow drivers to enable polling/irq when IR input device @@ -50,11 +53,19 @@ enum rc_driver_type { * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs) * @s_tx_carrier: set transmit carrier frequency * @tx_ir: transmit IR + * @s_idle: optional: enable/disable hardware idle mode, upon which, + device doesn't interrupt host untill it sees IR data */ struct ir_dev_props { enum rc_driver_type driver_type; unsigned long allowed_protos; u32 scanmask; + + u64 timeout; + u64 min_timeout; + u64 max_timeout; + + void *priv; int (*change_protocol)(void *priv, u64 ir_type); int (*open)(void *priv); @@ -62,6 +73,7 @@ struct ir_dev_props { int (*s_tx_mask)(void *priv, u32 mask); int (*s_tx_carrier)(void *priv, u32 carrier); int (*tx_ir)(void *priv, int *txbuf, u32 n); + void (*s_idle) (void *priv, int enable); }; struct ir_input_dev { @@ -69,9 +81,10 @@ struct ir_input_dev { char *driver_name; /* Name of the driver module */ struct ir_scancode_table rc_tab; /* scan/key table */ unsigned long devno; /* device number */ - const struct ir_dev_props *props; /* Device properties */ + struct ir_dev_props *props; /* Device properties */ struct ir_raw_event_ctrl *raw; /* for raw pulse/space events */ struct input_dev *input_dev; /* the input device associated with this device */ + bool idle; /* key info - needed by IR keycode handlers */ spinlock_t keylock; /* protects the below members */ @@ -95,12 +108,12 @@ enum raw_event_type { /* From ir-keytable.c */ int __ir_input_register(struct input_dev *dev, const struct ir_scancode_table *ir_codes, - const struct ir_dev_props *props, + struct ir_dev_props *props, const char *driver_name); static inline int ir_input_register(struct input_dev *dev, const char *map_name, - const struct ir_dev_props *props, + struct ir_dev_props *props, const char *driver_name) { struct ir_scancode_table *ir_codes; struct ir_input_dev *ir_dev; @@ -144,6 +157,11 @@ struct ir_raw_event { void ir_raw_event_handle(struct input_dev *input_dev); int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev); int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type); +int ir_raw_event_store_with_filter(struct input_dev *input_dev, + struct ir_raw_event *ev); + +void ir_raw_event_set_idle(struct input_dev *input_dev, int idle); + static inline void ir_raw_event_reset(struct input_dev *input_dev) { struct ir_raw_event ev = { .pulse = false, .duration = 0 };