From patchwork Wed Jul 28 15:14:06 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 3926 Return-path: Envelope-to: mchehab@infradead.org Delivery-date: Wed, 28 Jul 2010 15:14:41 +0000 Received: from bombadil.infradead.org [18.85.46.34] by pedra with IMAP (fetchmail-6.3.17) for (single-drop); Wed, 28 Jul 2010 12:19:52 -0300 (BRT) Received: from vger.kernel.org ([209.132.180.67]) by bombadil.infradead.org with esmtp (Exim 4.72 #1 (Red Hat Linux)) id 1Oe8LB-0001aw-5J; Wed, 28 Jul 2010 15:14:41 +0000 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754914Ab0G1POi (ORCPT + 1 other); Wed, 28 Jul 2010 11:14:38 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:59260 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751665Ab0G1POh (ORCPT ); Wed, 28 Jul 2010 11:14:37 -0400 Received: by mail-bw0-f46.google.com with SMTP id 1so4014228bwz.19 for ; Wed, 28 Jul 2010 08:14:36 -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=NZ/YJREtI2pkLd0jw7z+mLQteMQ3BuNfKfL74f+/Sj4=; b=DGVn4YAMbwfy8ghTsGtsDXwffKq9rUWnlQv84iE5sKb30tSl5lQZ/YowZZbHT5Zhnn knNXuxhY3ERO1uTAqiQDRG8+qG35hw9nlU+BD6/gTiskGKHe4z3fK4GON+w/n5sacY4V BjV0G4Qn7bXvmScV5KD1WZ+Omi+hqgj4xtkbk= 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=P+4xu0d90nU4up3dYybTOCnU/Svqy4AyUR/4F2zCKFl6LBxuS5MWdGsJyHW6ZMwxXM DOPgZCGoK8gbsB4AJU1OXdH+OpPgpjkUNxNlMd7mni4p+/agDWY5KMjO1/SMxwDs1Rf+ LugZ6TLSUPrryQH0OsAJ85weDFQbCGMpkhmEg= Received: by 10.204.152.8 with SMTP id e8mr8262833bkw.2.1280330076142; Wed, 28 Jul 2010 08:14:36 -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 bq20sm4855282bkb.16.2010.07.28.08.14.32 (version=SSLv3 cipher=RC4-MD5); Wed, 28 Jul 2010 08:14:34 -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 , Maxim Levitsky Subject: [PATCH 4/9] IR: add helper functions for ir input devices that send ir timing data in small chunks, and alternation between pulses and spaces isn't guaranteed. Date: Wed, 28 Jul 2010 18:14:06 +0300 Message-Id: <1280330051-27732-5-git-send-email-maximlevitsky@gmail.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1280330051-27732-1-git-send-email-maximlevitsky@gmail.com> References: <1280330051-27732-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 Signed-off-by: Maxim Levitsky Acked-by: Jarod Wilson --- drivers/media/IR/ir-core-priv.h | 1 + drivers/media/IR/ir-keytable.c | 2 +- drivers/media/IR/ir-raw-event.c | 86 +++++++++++++++++++++++++++++++++++++++ include/media/ir-core.h | 24 +++++++++- 4 files changed, 109 insertions(+), 4 deletions(-) diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h index 8ce80e4..3eafdb7 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..53ce966 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 */ + int 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 };