From patchwork Wed Jul 28 23:40:52 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 114959 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 o6SNfYF3007146 for ; Wed, 28 Jul 2010 23:41:34 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756724Ab0G1Xla (ORCPT ); Wed, 28 Jul 2010 19:41:30 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:56704 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751459Ab0G1XlT (ORCPT ); Wed, 28 Jul 2010 19:41:19 -0400 Received: by mail-bw0-f46.google.com with SMTP id 1so18022bwz.19 for ; Wed, 28 Jul 2010 16:41:18 -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=FfmmWmETbMVCtFOMUFYwQCRndL7T6nVAbsmuUK+uKLU=; b=lk38t2d4ZEQKz339E9/YQkAn6roUPu4SbOxHFIkQXqKCLGLYy85Yy+6o1CZqG37anQ w6DafT7HLglp3O7aqETYPL6jJ2XwWHRW532mQeoNKt7uzHY1VwX+8ukkjs/L/5ecbR4A /7FZGkjZS+B9jPxKOv5v1n3+HjMyHU9/b49UQ= 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=xg/RCO3C55RnFsPkOxdJw/9G1vXug/an8a5CyencdB+JCmvYWBBM/wZo2tfQsYJiH4 iO358dIAYLNnGWQm9wPQQDz3gYcEXvnRiwt9tG9MTthjHToV8pkyFJG838ZqapXVpczF B4mT1MVpAI2rm84aETZG1JrRiVmqZFahjjyhs= Received: by 10.204.79.199 with SMTP id q7mr8003448bkk.76.1280360478291; Wed, 28 Jul 2010 16:41:18 -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.15 (version=SSLv3 cipher=RC4-MD5); Wed, 28 Jul 2010 16:41:17 -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 9/9] IR: Port ene driver to new IR subsystem and enable it. Date: Thu, 29 Jul 2010 02:40:52 +0300 Message-Id: <1280360452-8852-10-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:35 +0000 (UTC) diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig index fc48a3f..3f62bf9 100644 --- a/drivers/media/IR/Kconfig +++ b/drivers/media/IR/Kconfig @@ -105,4 +105,18 @@ config IR_MCEUSB To compile this driver as a module, choose M here: the module will be called mceusb. +config IR_ENE + tristate "ENE eHome Receiver/Transciever (pnp id: ENE0100/ENE02xxx)" + depends on PNP + depends on IR_CORE + ---help--- + Say Y here to enable support for integrated infrared receiver + /transciever made by ENE. + + You can see if you have it by looking at lspnp output. + Output should include ENE0100 ENE0200 or something similiar. + + To compile this driver as a module, choose M here: the + module will be called ene_ir. + endif #IR_CORE diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile index 2ae4f3a..3262a68 100644 --- a/drivers/media/IR/Makefile +++ b/drivers/media/IR/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o # stand-alone IR receivers/transmitters obj-$(CONFIG_IR_IMON) += imon.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o +obj-$(CONFIG_IR_ENE) += ene_ir.o diff --git a/drivers/media/IR/ene_ir.c b/drivers/media/IR/ene_ir.c index 9d11caf..8b88dbd 100644 --- a/drivers/media/IR/ene_ir.c +++ b/drivers/media/IR/ene_ir.c @@ -1,5 +1,5 @@ /* - * driver for ENE KB3926 B/C/D CIR (also known as ENE0100/ENE0200/ENE0201) + * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX) * * Copyright (C) 2010 Maxim Levitsky * @@ -25,20 +25,21 @@ #include #include #include -#include -#include "lirc_ene0100.h" +#include +#include +#include +#include +#include "ene_ir.h" static int sample_period = -1; static int enable_idle = 1; -static int enable_duty_carrier; +static int error_adjustment = 4; static int input = 1; static int debug; static int txsim; -static void ene_rx_set_idle(struct ene_device *dev, int idle); static int ene_irq_status(struct ene_device *dev); -static void ene_send_sample(struct ene_device *dev, unsigned long sample); /* read a hardware register */ static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) @@ -160,7 +161,7 @@ static int ene_hw_detect(struct ene_device *dev) } /* this enables/disables IR input via gpio40*/ -static void ene_enable_gpio40_recieve(struct ene_device *dev, int enable) +static void ene_enable_gpio40_receive(struct ene_device *dev, int enable) { ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ? 0 : ENE_CIR_CONF2_GPIO40DIS, @@ -168,13 +169,13 @@ static void ene_enable_gpio40_recieve(struct ene_device *dev, int enable) } /* this enables/disables IR via standard input */ -static void ene_enable_normal_recieve(struct ene_device *dev, int enable) +static void ene_enable_normal_receive(struct ene_device *dev, int enable) { ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0); } /* this enables/disables IR input via unused fan tachtometer input */ -static void ene_enable_fan_recieve(struct ene_device *dev, int enable) +static void ene_enable_fan_receive(struct ene_device *dev, int enable) { if (!enable) ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); @@ -186,7 +187,7 @@ static void ene_enable_fan_recieve(struct ene_device *dev, int enable) } -/* Sense current recieved carrier */ +/* Sense current received carrier */ static int ene_rx_sense_carrier(struct ene_device *dev) { int period = ene_hw_read_reg(dev, ENE_RX_CARRIER); @@ -209,37 +210,37 @@ static int ene_rx_sense_carrier(struct ene_device *dev) /* determine which input to use*/ static void ene_rx_set_inputs(struct ene_device *dev) { - int learning_mode = dev->learning_enabled || dev->rx_carrier_sense; + int learning_mode = dev->learning_enabled; - ene_dbg("RX: setup reciever, learning mode = %d", learning_mode); + ene_dbg("RX: setup receiver, learning mode = %d", learning_mode); - ene_enable_normal_recieve(dev, 1); + ene_enable_normal_receive(dev, 1); /* old hardware doesn't support learning mode for sure */ if (dev->hw_revision <= ENE_HW_B) return; - /* reciever not learning capable, still set gpio40 correctly */ + /* receiver not learning capable, still set gpio40 correctly */ if (!dev->hw_learning_and_tx_capable) { - ene_enable_gpio40_recieve(dev, !dev->hw_gpio40_learning); + ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning); return; } /* enable learning mode */ if (learning_mode) { - ene_enable_gpio40_recieve(dev, dev->hw_gpio40_learning); + ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning); /* fan input is not used for learning */ if (dev->hw_fan_as_normal_input) - ene_enable_fan_recieve(dev, 0); + ene_enable_fan_receive(dev, 0); /* disable learning mode */ } else { if (dev->hw_fan_as_normal_input) { - ene_enable_fan_recieve(dev, 1); - ene_enable_normal_recieve(dev, 0); + ene_enable_fan_receive(dev, 1); + ene_enable_normal_receive(dev, 0); } else - ene_enable_gpio40_recieve(dev, + ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning); } @@ -249,6 +250,16 @@ static void ene_rx_set_inputs(struct ene_device *dev) ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ? ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); + + if (dev->rx_fan_input_inuse) { + dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000; + + dev->props->timeout = + ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000; + } else { + dev->props->rx_resolution = sample_period * 1000; + dev->props->timeout = ENE_MAXGAP * 1000; + } } /* Enable the device for receive */ @@ -277,147 +288,33 @@ static void ene_rx_enable(struct ene_device *dev) /* ack any pending irqs - just in case */ ene_irq_status(dev); - /* enter idle mode */ - ene_rx_set_idle(dev, 1); - /* enable firmware bits */ ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ, ENE_FW1_ENABLE | ENE_FW1_IRQ); + + /* enter idle mode */ + ir_raw_event_set_idle(dev->idev, 1); + ir_raw_event_reset(dev->idev); + } -/* Disable the device reciever */ +/* Disable the device receiver */ static void ene_rx_disable(struct ene_device *dev) { /* disable inputs */ - ene_enable_normal_recieve(dev, 0); + ene_enable_normal_receive(dev, 0); if (dev->hw_fan_as_normal_input) - ene_enable_fan_recieve(dev, 0); + ene_enable_fan_receive(dev, 0); /* disable hardware IRQ and firmware flag */ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); - ene_rx_set_idle(dev, 1); -} - -/* send current sample to the user */ -static void ene_rx_flush(struct ene_device *dev, int timeout) -{ - unsigned long value; - - value = dev->rx_sample_pulse ? LIRC_PULSE(dev->rx_sample) : - LIRC_SPACE(dev->rx_sample); - ene_send_sample(dev, value); - dev->rx_sample = 0; - dev->rx_sample_pulse = 0; + ir_raw_event_set_idle(dev->idev, 1); + ir_raw_event_reset(dev->idev); } -/* recieve new sample and process it */ -static void ene_rx_sample(struct ene_device *dev, int sample, int is_pulse) -{ - ene_dbg("RX: sample %8d (%s)", sample, is_pulse ? "pulse" : "space"); - - /* ignore spaces in idle mode, can get them on revC */ - /* also ignore a space in front of first pulse */ - if (dev->rx_idle && !is_pulse) - return; - - /* get out of idle mode now */ - if (dev->rx_idle) - ene_rx_set_idle(dev, 0); - - if (!dev->rx_sample) { - dev->rx_sample = sample; - dev->rx_sample_pulse = is_pulse; - } else if (is_pulse == dev->rx_sample_pulse) - dev->rx_sample += sample; - else { - ene_rx_flush(dev, 0); - dev->rx_sample = sample; - dev->rx_sample_pulse = is_pulse; - } - - if (is_pulse) - return; - - /* overflow sample from fan input recieved, enable idle mode */ - if (dev->rx_fan_input_inuse && - sample == ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN) { - ene_rx_set_idle(dev, 1); - return; - } - - if (!dev->rx_fan_input_inuse) { - /* Report timeout if enabled */ - if (dev->rx_timeout && dev->rx_send_timeout_packet && - !dev->rx_timeout_sent && - dev->rx_sample > dev->rx_timeout) { - ene_dbg("RX: sending timeout sample"); - ene_send_sample(dev, LIRC_TIMEOUT(dev->rx_sample)); - dev->rx_timeout_sent = 1; - } - - /* too large sample accumulated via normal input. - note that on revC, hardware idle mode turns on automaticly, - so max gap should be less that the gap after which - hw stops sending samples */ - if (dev->rx_sample > ENE_MAXGAP) { - ene_rx_set_idle(dev, 1); - return; - } - } -} - -/* enable or disable idle mode */ -static void ene_rx_set_idle(struct ene_device *dev, int idle) -{ - struct timeval now; - int disable_sampler = 0; - - - /* Also put hardware sampler in 'idle' mode on revB*/ - /* revC and higher do that automaticly (firmware does?) */ - if ((dev->hw_revision < ENE_HW_C) && enable_idle) - if (idle) - disable_sampler = 1; - - ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, - disable_sampler ? 0 : ENE_CIR_SAMPLE_OVERFLOW, - ENE_CIR_SAMPLE_OVERFLOW); - dev->rx_idle = idle; - - /* remember when we have entered the idle mode */ - if (idle) { - ene_dbg("RX: going into idle mode"); - do_gettimeofday(&dev->rx_gap_start); - return; - } - - ene_dbg("RX: back from idle mode"); - - /* send the gap between keypresses now */ - do_gettimeofday(&now); - - if (dev->rx_sample_pulse) { - ene_dbg("RX: somehow we recieved a pulse before idle mode???"); - return; - } - - /* manually calculate and recieve the gap between keypresses */ - if (now.tv_sec - dev->rx_gap_start.tv_sec > 16) - dev->rx_sample = LIRC_SPACE(LIRC_VALUE_MASK); - else - dev->rx_sample += - 1000000ull * (now.tv_sec - dev->rx_gap_start.tv_sec) - + now.tv_usec - dev->rx_gap_start.tv_usec; - - if (dev->rx_sample > LIRC_SPACE(LIRC_VALUE_MASK)) - dev->rx_sample = LIRC_SPACE(LIRC_VALUE_MASK); - - ene_rx_flush(dev, 0); - dev->rx_timeout_sent = 0; -} /* prepare transmission */ static void ene_tx_prepare(struct ene_device *dev) @@ -436,6 +333,8 @@ static void ene_tx_prepare(struct ene_device *dev) /* Set carrier */ if (dev->tx_period) { + /* NOTE: duty cycle handling is just a guess, it might + not be aviable. Default values were tested */ int tx_period_in500ns = dev->tx_period * 2; int tx_pulse_width_in_500ns = @@ -459,7 +358,6 @@ static void ene_tx_prepare(struct ene_device *dev) conf1 &= ~ENE_CIR_CONF1_TX_CARR; ene_hw_write_reg(dev, ENE_CIR_CONF1, conf1); - dev->tx_underway = 1; } @@ -467,11 +365,11 @@ static void ene_tx_prepare(struct ene_device *dev) static void ene_tx_complete(struct ene_device *dev) { ene_hw_write_reg(dev, ENE_CIR_CONF1, dev->saved_conf1); - dev->tx_underway = 0; + dev->tx_buffer = NULL; } /* set transmit mask */ -static void ene_tx_set_transmiter_mask(struct ene_device *dev) +static void ene_tx_hw_set_transmiter_mask(struct ene_device *dev) { u8 txport1 = ene_hw_read_reg(dev, ENE_TX_PORT1) & ~ENE_TX_PORT1_EN; u8 txport2 = ene_hw_read_reg(dev, ENE_TX_PORT2) & ~ENE_TX_PORT2_EN; @@ -492,8 +390,8 @@ static void ene_tx_sample(struct ene_device *dev) u8 raw_tx; u32 sample; - if (!dev->tx_underway) { - ene_dbg("TX: attempt to transmit while hw isn't setup"); + if (!dev->tx_buffer) { + ene_dbg("TX: attempt to transmit NULL buffer"); return; } @@ -623,6 +521,7 @@ static irqreturn_t ene_isr(int irq, void *data) int carrier = 0; irqreturn_t retval = IRQ_NONE; struct ene_device *dev = (struct ene_device *)data; + struct ir_raw_event ev; spin_lock_irqsave(&dev->hw_lock, flags); @@ -646,12 +545,13 @@ static irqreturn_t ene_isr(int irq, void *data) goto unlock; - if ((debug && dev->learning_enabled) || dev->rx_carrier_sense) + if (dev->learning_enabled) carrier = ene_rx_sense_carrier(dev); - - if (dev->rx_carrier_sense && carrier) - ene_send_sample(dev, LIRC_FREQUENCY(carrier)); - +#if 0 + /* TODO */ + if (dev->learning_enabled && carrier) + ir_raw_event_report_frequency(dev->idev, carrier); +#endif for (i = 0; i < ENE_SAMPLES_SIZE; i++) { hw_value = ene_hw_read_reg(dev, @@ -672,13 +572,25 @@ static irqreturn_t ene_isr(int irq, void *data) pulse = !(hw_value & ENE_SAMPLE_SPC_MASK); hw_value &= ENE_SAMPLE_VALUE_MASK; hw_sample = hw_value * sample_period; + + if (error_adjustment && error_adjustment < 100) { + hw_sample *= (100 - error_adjustment); + hw_sample /= 100; + } } /* no more data */ if (!(hw_value)) break; - ene_rx_sample(dev, hw_sample, pulse); + ene_dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); + + + ev.duration = hw_sample * 1000; + ev.pulse = pulse; + ir_raw_event_store_with_filter(dev->idev, &ev); } + + ir_raw_event_handle(dev->idev); unlock: spin_unlock_irqrestore(&dev->hw_lock, flags); return retval; @@ -687,8 +599,6 @@ unlock: /* Initialize default settings */ static void ene_setup_settings(struct ene_device *dev) { - dev->rx_send_timeout_packet = 0; - dev->rx_timeout = ENE_MAXGAP; dev->tx_period = 32; dev->tx_duty_cycle = 25; /*%*/ dev->transmitter_mask = 3; @@ -698,11 +608,7 @@ static void ene_setup_settings(struct ene_device *dev) dev->learning_enabled = (input == 2 && dev->hw_learning_and_tx_capable); - /* Clear accumulated sample bufer */ - dev->rx_sample = 0; - dev->rx_sample_pulse = 0; dev->rx_pointer = -1; - dev->rx_carrier_sense = 0; } @@ -732,144 +638,97 @@ static void ene_close(void *data) spin_unlock_irqrestore(&dev->hw_lock, flags); } -/* outside interface for settings */ -static int ene_ioctl(struct inode *node, struct file *file, - unsigned int cmd, unsigned long arg) +/* outside interface: set transmitter mask */ +static int ene_set_tx_mask(void *data, u32 tx_mask) { - int lvalue = 0, retval, tmp; + struct ene_device *dev = (struct ene_device *)data; unsigned long flags; - struct ene_device *dev = lirc_get_pdata(file); - - - switch (cmd) { - case LIRC_SET_SEND_CARRIER: - case LIRC_SET_SEND_DUTY_CYCLE: - case LIRC_SET_TRANSMITTER_MASK: - case LIRC_SET_MEASURE_CARRIER_MODE: - case LIRC_SET_REC_CARRIER: - /* All these aren't possible without this */ - if (!dev->hw_learning_and_tx_capable) - return -ENOSYS; - /* Fall through */ - case LIRC_SET_REC_TIMEOUT: - case LIRC_SET_REC_TIMEOUT_REPORTS: - retval = get_user(lvalue, (unsigned int *) arg); - if (retval) - return retval; + ene_dbg("TX: attempt to set transmitter mask %02x", tx_mask); + + /* invalid txmask */ + if (!tx_mask || tx_mask & ~0x3) { + ene_dbg("TX: invalid mask"); + /* return count of transmitters */ + return 2; } - switch (cmd) { - case LIRC_SET_SEND_CARRIER: - ene_dbg("TX: attempt to set tx carrier to %d kHz", lvalue); - tmp = 1000000 / lvalue; /* (1 / freq) (* # usec in 1 sec) */ + spin_lock_irqsave(&dev->hw_lock, flags); + dev->transmitter_mask = tx_mask; + spin_unlock_irqrestore(&dev->hw_lock, flags); + return 0; +} - if (tmp && (tmp > ENE_TX_PERIOD_MAX || - tmp < ENE_TX_PERIOD_MIN)) { +/* outside interface : set tx carrier */ +static int ene_set_tx_carrier(void *data, u32 carrier) +{ + struct ene_device *dev = (struct ene_device *)data; + unsigned long flags; + u32 period = 1000000 / carrier; /* (1 / freq) (* # usec in 1 sec) */ - ene_dbg("TX: out of range %d-%d carrier, " - "falling back to 32 kHz", - 1000 / ENE_TX_PERIOD_MIN, - 1000 / ENE_TX_PERIOD_MAX); + ene_dbg("TX: attempt to set tx carrier to %d kHz", carrier); - tmp = 32; /* this is just a coincidence!!! */ - } - ene_dbg("TX: set carrier to %d kHz", lvalue); + if (period && (period > ENE_TX_PERIOD_MAX || + period < ENE_TX_PERIOD_MIN)) { - spin_lock_irqsave(&dev->hw_lock, flags); - dev->tx_period = tmp; - spin_unlock_irqrestore(&dev->hw_lock, flags); - break; - case LIRC_SET_SEND_DUTY_CYCLE: - ene_dbg("TX: attempt to set duty cycle to %d%%", lvalue); + ene_dbg("TX: out of range %d-%d carrier, " + "falling back to 32 kHz", + 1000 / ENE_TX_PERIOD_MIN, + 1000 / ENE_TX_PERIOD_MAX); - if ((lvalue >= 100) || (lvalue <= 0)) { - retval = -EINVAL; - break; - } - spin_lock_irqsave(&dev->hw_lock, flags); - dev->tx_duty_cycle = lvalue; - spin_unlock_irqrestore(&dev->hw_lock, flags); - break; - case LIRC_SET_TRANSMITTER_MASK: - ene_dbg("TX: attempt to set transmitter mask %02x", lvalue); - - /* invalid txmask */ - if (!lvalue || lvalue & ~0x3) { - ene_dbg("TX: invalid mask"); - /* this supposed to return num of transmitters */ - retval = 2; - break; - } - spin_lock_irqsave(&dev->hw_lock, flags); - dev->transmitter_mask = lvalue; - spin_unlock_irqrestore(&dev->hw_lock, flags); - break; - case LIRC_SET_REC_CARRIER: - tmp = (lvalue > ENE_NORMAL_RX_HI || lvalue < ENE_NORMAL_RX_LOW); - - if (tmp != dev->learning_enabled) { - spin_lock_irqsave(&dev->hw_lock, flags); - dev->learning_enabled = tmp; - ene_rx_set_inputs(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); - } - break; - case LIRC_SET_REC_TIMEOUT: - spin_lock_irqsave(&dev->hw_lock, flags); - dev->rx_timeout = lvalue; - spin_unlock_irqrestore(&dev->hw_lock, flags); - ene_dbg("RX: set rx report timeout to %d", dev->rx_timeout); - break; - case LIRC_SET_REC_TIMEOUT_REPORTS: - spin_lock_irqsave(&dev->hw_lock, flags); - dev->rx_send_timeout_packet = lvalue; - spin_unlock_irqrestore(&dev->hw_lock, flags); - ene_dbg("RX: %sable timeout reports", - dev->rx_send_timeout_packet ? "en" : "dis"); - break; - case LIRC_SET_MEASURE_CARRIER_MODE: - if (dev->rx_carrier_sense == lvalue) - break; - spin_lock_irqsave(&dev->hw_lock, flags); - dev->rx_carrier_sense = lvalue; - ene_rx_set_inputs(dev); - spin_unlock_irqrestore(&dev->hw_lock, flags); - break; - case LIRC_GET_REC_RESOLUTION: - tmp = dev->rx_fan_input_inuse ? - ENE_SAMPLE_PERIOD_FAN : sample_period; - retval = put_user(tmp, (unsigned long *) arg); - break; - default: - retval = -ENOIOCTLCMD; - break; + period = 32; /* this is just a coincidence!!! */ } + ene_dbg("TX: set carrier to %d kHz", carrier); - return retval; + spin_lock_irqsave(&dev->hw_lock, flags); + dev->tx_period = period; + spin_unlock_irqrestore(&dev->hw_lock, flags); + return 0; } -/* outside interface: transmit */ -static ssize_t ene_transmit(struct file *file, const char *buf, - size_t n, loff_t *ppos) + +/* outside interface: enable learning mode */ +static int ene_set_learning_mode(void *data, int enable) { - struct ene_device *dev = lirc_get_pdata(file); + struct ene_device *dev = (struct ene_device *)data; unsigned long flags; + if (enable == dev->learning_enabled) + return 0; - if (!dev) - return -EFAULT; + spin_lock_irqsave(&dev->hw_lock, flags); + dev->learning_enabled = enable; + ene_rx_set_inputs(dev); + spin_unlock_irqrestore(&dev->hw_lock, flags); + return 0; +} - if (!dev->hw_learning_and_tx_capable) - return -ENODEV; +/* outside interface: set rec carrier */ +static int ene_set_rec_carrier(void *data, u32 min, u32 max) +{ + struct ene_device *dev = (struct ene_device *)data; + ene_set_learning_mode(dev, + max > ENE_NORMAL_RX_HI || min < ENE_NORMAL_RX_LOW); + return 0; +} - if (n % sizeof(int)) - return -EINVAL; +/* outside interface: enable or disable idle mode */ +static void ene_rx_set_idle(void *data, int idle) +{ + struct ene_device *dev = (struct ene_device *)data; + ene_dbg("%sabling idle mode", idle ? "en" : "dis"); - if (n > ENE_TXBUF_SIZE * sizeof(int)) - return -ENOMEM; + ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, + (enable_idle && idle) ? 0 : ENE_CIR_SAMPLE_OVERFLOW, + ENE_CIR_SAMPLE_OVERFLOW); +} - if (copy_from_user(dev->tx_buffer, buf, n)) - return -EFAULT; +/* outside interface: transmit */ +static int ene_transmit(void *data, int *buf, u32 n) +{ + struct ene_device *dev = (struct ene_device *)data; + unsigned long flags; + + dev->tx_buffer = buf; dev->tx_len = n / sizeof(int); dev->tx_pos = 0; dev->tx_reg = 0; @@ -881,7 +740,7 @@ static ssize_t ene_transmit(struct file *file, const char *buf, spin_lock_irqsave(&dev->hw_lock, flags); - ene_tx_set_transmiter_mask(dev); + ene_tx_hw_set_transmiter_mask(dev); ene_tx_prepare(dev); /* Transmit first two samples */ @@ -897,80 +756,35 @@ static ssize_t ene_transmit(struct file *file, const char *buf, spin_unlock_irqrestore(&dev->hw_lock, flags); } else ene_dbg("TX: done"); - return n; } -/* Sends one sample to the user */ -static void ene_send_sample(struct ene_device *dev, unsigned long sample) -{ - if (!lirc_buffer_full(dev->lirc_driver->rbuf)) { - lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&sample); - wake_up(&dev->lirc_driver->rbuf->wait_poll); - } -} - -static const struct file_operations ene_fops = { - .owner = THIS_MODULE, - .write = ene_transmit, - .ioctl = ene_ioctl, -}; - -/* main load function */ -static int ene_probe(struct pnp_dev *pnp_dev, - const struct pnp_device_id *dev_id) +/* probe entry */ +static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) { - struct ene_device *dev; - struct lirc_driver *lirc_driver; int error = -ENOMEM; + struct ir_dev_props *ir_props; + struct input_dev *input_dev; + struct ene_device *dev; + /* allocate memory */ + input_dev = input_allocate_device(); + ir_props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); - if (!dev) - goto err1; - - dev->pnp_dev = pnp_dev; - pnp_set_drvdata(pnp_dev, dev); - - /* prepare lirc interface */ - error = -ENOMEM; - lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); - - if (!lirc_driver) - goto err2; - - dev->lirc_driver = lirc_driver; - - strcpy(lirc_driver->name, ENE_DRIVER_NAME); - lirc_driver->minor = -1; - lirc_driver->code_length = sizeof(int) * 8; - lirc_driver->features = LIRC_CAN_REC_MODE2 | - LIRC_CAN_GET_REC_RESOLUTION | - LIRC_CAN_SET_REC_TIMEOUT; - lirc_driver->data = dev; - lirc_driver->set_use_inc = ene_open; - lirc_driver->set_use_dec = ene_close; - lirc_driver->dev = &pnp_dev->dev; - lirc_driver->owner = THIS_MODULE; - lirc_driver->fops = &ene_fops; - lirc_driver->min_timeout = ENE_MINGAP; - lirc_driver->max_timeout = ENE_MAXGAP; - lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - - if (!lirc_driver->rbuf) - goto err3; - - if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 512)) - goto err4; + if (!input_dev || !ir_props || !dev) + goto error; /* validate resources */ + error = -ENODEV; + if (!pnp_port_valid(pnp_dev, 0) || pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) - goto err5; + goto error; if (!pnp_irq_valid(pnp_dev, 0)) - goto err5; + goto error; dev->hw_io = pnp_port_start(pnp_dev, 0); dev->irq = pnp_irq(pnp_dev, 0); @@ -979,16 +793,19 @@ static int ene_probe(struct pnp_dev *pnp_dev, /* claim the resources */ error = -EBUSY; if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) - goto err5; + goto error; if (request_irq(dev->irq, ene_isr, IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) - goto err6; + goto error; + + pnp_set_drvdata(pnp_dev, dev); + dev->pnp_dev = pnp_dev; /* detect hardware version and features */ error = ene_hw_detect(dev); if (error) - goto err7; + goto error; ene_setup_settings(dev); @@ -1000,19 +817,21 @@ static int ene_probe(struct pnp_dev *pnp_dev, "Simulation of TX activated\n"); } - if (dev->hw_learning_and_tx_capable) { - lirc_driver->features |= LIRC_CAN_SEND_PULSE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_SET_TRANSMITTER_MASK; + ir_props->driver_type = RC_DRIVER_IR_RAW; + ir_props->allowed_protos = IR_TYPE_ALL; + ir_props->priv = dev; + ir_props->open = ene_open; + ir_props->close = ene_close; + ir_props->min_timeout = ENE_MINGAP * 1000; + ir_props->max_timeout = ENE_MAXGAP * 1000; + ir_props->timeout = ENE_MAXGAP * 1000; - if (enable_duty_carrier) - lirc_driver->features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; + if (dev->hw_revision == ENE_HW_B) + ir_props->s_idle = ene_rx_set_idle; - if (input == 0) - lirc_driver->features |= LIRC_CAN_SET_REC_CARRIER; - init_completion(&dev->tx_complete); - } + dev->props = ir_props; + dev->idev = input_dev; /* don't allow too short/long sample periods */ if (sample_period < 5 || sample_period > 0x7F) @@ -1029,29 +848,49 @@ static int ene_probe(struct pnp_dev *pnp_dev, sample_period = 75; } + ir_props->rx_resolution = sample_period * 1000; + + if (dev->hw_learning_and_tx_capable) { + + ir_props->s_learning_mode = ene_set_learning_mode; + + if (input == 0) + ir_props->s_rx_carrier_range = ene_set_rec_carrier; + + init_completion(&dev->tx_complete); + ir_props->tx_ir = ene_transmit; + ir_props->s_tx_mask = ene_set_tx_mask; + ir_props->s_tx_carrier = ene_set_tx_carrier; + ir_props->tx_resolution = ENE_TX_SMPL_PERIOD * 1000; + } + + device_set_wakeup_capable(&pnp_dev->dev, 1); device_set_wakeup_enable(&pnp_dev->dev, 1); + if (dev->hw_learning_and_tx_capable) + input_dev->name = "ENE eHome Infrared Remote Transceiver"; + else + input_dev->name = "ENE eHome Infrared Remote Receiver"; + + error = -ENODEV; - if (lirc_register_driver(lirc_driver)) - goto err7; + if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props, + ENE_DRIVER_NAME)) + goto error; + ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); return 0; - -err7: - free_irq(dev->irq, dev); -err6: - release_region(dev->hw_io, ENE_MAX_IO); -err5: - lirc_buffer_free(lirc_driver->rbuf); -err4: - kfree(lirc_driver->rbuf); -err3: - kfree(lirc_driver); -err2: +error: + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->hw_io) + release_region(dev->hw_io, ENE_MAX_IO); + + input_free_device(input_dev); + kfree(ir_props); kfree(dev); -err1: return error; } @@ -1067,9 +906,8 @@ static void ene_remove(struct pnp_dev *pnp_dev) free_irq(dev->irq, dev); release_region(dev->hw_io, ENE_MAX_IO); - lirc_unregister_driver(dev->lirc_driver->minor); - lirc_buffer_free(dev->lirc_driver->rbuf); - kfree(dev->lirc_driver); + ir_input_unregister(dev->idev); + kfree(dev->props); kfree(dev); } @@ -1160,13 +998,18 @@ module_param(txsim, bool, S_IRUGO); MODULE_PARM_DESC(txsim, "Simulate TX features on unsupported hardware (dangerous)"); -module_param(enable_duty_carrier, bool, S_IRUGO); -MODULE_PARM_DESC(enable_duty_carrier, - "Enable a code that might allow to to set TX carrier duty cycle"); + +module_param(error_adjustment, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(error_adjustment, + "Correct incoming samples by error_adjustment percent\n" + "A default value of 4% seems to help with signal decoding"); + + + MODULE_DEVICE_TABLE(pnp, ene_ids); MODULE_DESCRIPTION - ("LIRC driver for KB3926B/KB3926C/KB3926D " + ("Infrared input driver for KB3926B/KB3926C/KB3926D " "(aka ENE0100/ENE0200/ENE0201) CIR port"); MODULE_AUTHOR("Maxim Levitsky"); diff --git a/drivers/media/IR/ene_ir.h b/drivers/media/IR/ene_ir.h index 06453a8..63e5138 100644 --- a/drivers/media/IR/ene_ir.h +++ b/drivers/media/IR/ene_ir.h @@ -1,5 +1,5 @@ /* - * driver for ENE KB3926 B/C/D CIR (also known as ENE0100/ENE0200/ENE0201) + * driver for ENE KB3926 B/C/D CIR (also known as ENE0XXX) * * Copyright (C) 2010 Maxim Levitsky * @@ -19,8 +19,7 @@ * USA */ #include -#include -#include + /* hardware address */ #define ENE_STATUS 0 /* hardware status - unused */ @@ -62,7 +61,7 @@ /* transmitter ports */ #define ENE_TX_PORT2 0xFC01 /* this enables one or both */ #define ENE_TX_PORT2_EN 0x20 /* TX ports */ -#define ENE_TX_PORT1 0xFC08 +#define ENE_TX_PORT1 0xFC08 #define ENE_TX_PORT1_EN 0x02 /* IRQ registers block (for revision B) */ @@ -88,7 +87,7 @@ #define ENE_CIR_CONF1 0xFEC0 #define ENE_CIR_CONF1_TX_CLEAR 0x01 /* clear that on revC */ /* while transmitting */ -#define ENE_CIR_CONF1_RX_ON 0x07 /* normal reciever enabled */ +#define ENE_CIR_CONF1_RX_ON 0x07 /* normal receiver enabled */ #define ENE_CIR_CONF1_LEARN1 0x08 /* enabled on learning mode */ #define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ #define ENE_CIR_CONF1_TX_CARR 0x80 /* send TX carrier or not */ @@ -112,7 +111,7 @@ /* Unknown TX setting - TX sample period ??? */ #define ENE_TX_UNK1 0xFECB /* set to 0x63 */ -/* Current recieved carrier period */ +/* Current received carrier period */ #define ENE_RX_CARRIER 0xFECC /* RX period (500 ns) */ #define ENE_RX_CARRIER_VALID 0x80 /* Register content valid */ @@ -162,8 +161,7 @@ /******************************************************************************/ -#define ENE_DRIVER_NAME "enecir" -#define ENE_TXBUF_SIZE (500 * sizeof(int)) /* 500 samples (arbitary) */ +#define ENE_DRIVER_NAME "ene_ir" #define ENE_IRQ_RX 1 #define ENE_IRQ_TX 2 @@ -188,7 +186,8 @@ struct ene_device { struct pnp_dev *pnp_dev; - struct lirc_driver *lirc_driver; + struct input_dev *idev; + struct ir_dev_props *props; int in_use; /* hw IO settings */ @@ -209,31 +208,20 @@ struct ene_device { u8 saved_conf1; /* saved FEC0 reg */ int learning_enabled; /* learning input enabled */ - /* RX sample handling */ - int rx_sample; /* current recieved sample */ - int rx_sample_pulse; /* recieved sample is pulse */ - int rx_idle; /* idle mode for RX activated */ - struct timeval rx_gap_start; /* time of start of idle */ - int rx_timeout; /* time in ms of RX timeout */ - int rx_send_timeout_packet; /* do we send RX timeout */ - int rx_timeout_sent; /* we sent the timeout packet */ - int rx_carrier_sense; /* sense carrier */ - /* TX sample handling */ unsigned int tx_sample; /* current sample for TX */ int tx_sample_pulse; /* current sample is pulse */ /* TX buffer */ - int tx_buffer[ENE_TXBUF_SIZE]; /* input samples buffer*/ + int *tx_buffer; /* input samples buffer*/ int tx_pos; /* position in that bufer */ int tx_len; /* current len of tx buffer */ - int tx_underway; /* TX is under way*/ int tx_done; /* done transmitting */ /* one more sample pending*/ struct completion tx_complete; /* TX completion */ struct timer_list tx_sim_timer; - /*TX settings */ + /*settings */ int tx_period; int tx_duty_cycle; int transmitter_mask;