From patchwork Sat Jul 31 14:59:22 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 116198 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 o6VG7kTa027084 for ; Sat, 31 Jul 2010 16:08:34 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756332Ab0GaPAW (ORCPT ); Sat, 31 Jul 2010 11:00:22 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:55010 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756052Ab0GaO7x (ORCPT ); Sat, 31 Jul 2010 10:59:53 -0400 Received: by mail-bw0-f46.google.com with SMTP id 1so870874bwz.19 for ; Sat, 31 Jul 2010 07:59:52 -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=fmmTDJymBV46HxKMLfMXQLlP2+8EAFC2v6i0fJF9liM=; b=Nsqtf9Xv+WIMrxVuFlR+FXwpx08uo2K1XYuiRLrINuf6WP2yYBzQfCd9sGOUYPcMQM 97WpOFg52qrnFru63+91m2u/Ig3nn6lJFNu75rEMAZa3c345+7do+hHAoLrbxltkVypw ApHFe5189C/UOCOkmJugUZdGUIrybmWB6ItHE= 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=ioY0Lyt4e4cFDDVbpYWmWbzQYR3B5qmjBBgnBLMXpBckKj+elthnsmctDUZA9KOoKs O2DSm8REaQPKZx5owp7CRlDuQdLLwtcth8NsRvVZTnvDlnPg5KCFheVChzbYHbYVE7Cf Tlc6cx0fSZDgxVBtqLMRZ3uX+xysgJz3ym3O0= Received: by 10.204.73.130 with SMTP id q2mr2239676bkj.137.1280588391320; Sat, 31 Jul 2010 07:59:51 -0700 (PDT) Received: from localhost.localdomain (IGLD-84-228-252-15.inter.net.il [84.228.252.15]) by mx.google.com with ESMTPS id a9sm2445428bky.23.2010.07.31.07.59.49 (version=SSLv3 cipher=RC4-MD5); Sat, 31 Jul 2010 07:59:50 -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 09/13] IR: add helper function for hardware with small o/b buffer. Date: Sat, 31 Jul 2010 17:59:22 +0300 Message-Id: <1280588366-26101-10-git-send-email-maximlevitsky@gmail.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1280588366-26101-1-git-send-email-maximlevitsky@gmail.com> References: <1280588366-26101-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]); Sat, 31 Jul 2010 16:08:47 +0000 (UTC) diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h index be68172..8053e3b 100644 --- a/drivers/media/IR/ir-core-priv.h +++ b/drivers/media/IR/ir-core-priv.h @@ -41,6 +41,7 @@ struct ir_raw_event_ctrl { /* raw decoder state follows */ struct ir_raw_event prev_ev; + struct ir_raw_event this_ev; struct nec_dec { int state; unsigned count; 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 d0c18db..43094e7 100644 --- a/drivers/media/IR/ir-raw-event.c +++ b/drivers/media/IR/ir-raw-event.c @@ -140,6 +140,90 @@ 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) works + * in similiar manner to ir_raw_event_store_edge. + * 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 (!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->this_ev.duration) { + raw->this_ev = *ev; + } else if (ev->pulse == raw->this_ev.pulse) { + raw->this_ev.duration += ev->duration; + } else { + ir_raw_event_store(input_dev, &raw->this_ev); + raw->this_ev = *ev; + } + + /* Enter idle mode if nessesary */ + if (!ev->pulse && ir->props->timeout && + raw->this_ev.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->this_ev.pulse); + + raw->this_ev.duration = + min(raw->this_ev.duration + delta, + (u64)IR_MAX_DURATION); + + ir_raw_event_store(input_dev, &raw->this_ev); + + if (raw->this_ev.duration == IR_MAX_DURATION) + ir_raw_event_reset(input_dev); + + raw->this_ev.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 197d05a..a781045 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; + + u32 timeout; + u32 min_timeout; + u32 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; @@ -148,6 +161,10 @@ 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 };