Quantcast

Add support for newer ENE0100 devices

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Add support for newer ENE0100 devices

maximlevitsky (Bugzilla)
Hi,

It turns out I have an older revision of ENE KB3924
The following patch adds initial support for ENE KB3926B/KB3926C
(at least this is how they call it in windows driver)


Most of code is untested, except for KB3926C with standard input,
thanks to Giuseppe Bilotta.

Also chip detection logic is improved.

patch against CVS.

Best regards,
        Maxim Levitsky


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH] Add support for newer ENE0100 devices

maximlevitsky (Bugzilla)
>From ec72b4f052317cef8ec88e5c356a5cdb2b6814e2 Mon Sep 17 00:00:00 2001
From: Maxim Levitsky <[hidden email]>
Date: Thu, 20 Aug 2009 09:37:40 +0300
Subject: [PATCH] Add support for newer ENE0100 devices
 (KB3926C, KB3926D)

Support for learning mode, and for devices that use
unused fan input as IR input is untested

Groundwork for transmitting is there, but it isn't yet
implemented, and untested.

Learning mode should be enabled using some sort of ioctl,
currently only enabled if module param is set

Thanks for Giuseppe Bilotta <[hidden email]>
For lot of help for getting this driver to work on KB3926C

Signed-off-by: Maxim Levitsky <[hidden email]>
---
 drivers/lirc_ene0100/lirc_ene0100.c |  363 +++++++++++++++++++++++++++--------
 drivers/lirc_ene0100/lirc_ene0100.h |  151 ++++++++++-----
 2 files changed, 386 insertions(+), 128 deletions(-)

diff --git a/drivers/lirc_ene0100/lirc_ene0100.c b/drivers/lirc_ene0100/lirc_ene0100.c
index 4ffa0b5..6caaa16 100644
--- a/drivers/lirc_ene0100/lirc_ene0100.c
+++ b/drivers/lirc_ene0100/lirc_ene0100.c
@@ -19,7 +19,6 @@
  * USA
  */
 
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pnp.h>
@@ -33,94 +32,287 @@
 
 static int sample_period = 75;
 static int enable_idle = 1;
+static int enable_learning;
 
 static void ene_set_idle(struct ene_device *dev, int idle);
+static void ene_set_inputs(struct ene_device *dev, int enable);
 
 /* read a hardware register */
 static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg)
 {
- outb(reg >> 8   , dev->hw_io + ENE_ADDR_HI);
- outb(reg & 0xFF , dev->hw_io + ENE_ADDR_LO);
+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
  return inb(dev->hw_io + ENE_IO);
 }
 
 /* write a hardware register */
 static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value)
 {
- outb(reg >> 8   , dev->hw_io + ENE_ADDR_HI);
- outb(reg & 0xFF , dev->hw_io + ENE_ADDR_LO);
+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
  outb(value, dev->hw_io + ENE_IO);
 }
 
 /* change specific bits in hardware register */
 static void ene_hw_write_reg_mask(struct ene_device *dev,
- u16 reg, u8 value, u8 mask)
+  u16 reg, u8 value, u8 mask)
 {
  u8 regvalue;
 
- outb(reg >> 8   , dev->hw_io + ENE_ADDR_HI);
- outb(reg & 0xFF , dev->hw_io + ENE_ADDR_LO);
+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
 
  regvalue = inb(dev->hw_io + ENE_IO) & ~mask;
  regvalue |= (value & mask);
  outb(regvalue, dev->hw_io + ENE_IO);
 }
 
-
-/* which half of hardware buffer we read now ?*/
-static int hw_get_buf_pointer(struct ene_device *dev)
+/* read irq status and ack it */
+static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer)
 {
- return 4 * (ene_hw_read_reg(dev, ENE_FW_BUFFER_POINTER)
- & ENE_FW_BUFFER_POINTER_HIGH);
-}
+ u8 irq_status;
+ u8 fw_flags1, fw_flags2;
 
+ fw_flags2 = ene_hw_read_reg(dev, ENE_FW2);
 
-/* read irq status and ack it */
-static int ene_hw_irq_status(struct ene_device *dev)
-{
- u8 irq_status = ene_hw_read_reg(dev, ENE_IRQ_STATUS);
+ if (buffer_pointer)
+ *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH);
 
- if (!irq_status & ENE_IRQ_STATUS_IR)
+ if (dev->hw_revision < ENE_HW_C) {
+ irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS);
+
+ if (!irq_status & ENEB_IRQ_STATUS_IR)
+ return 0;
+ ene_hw_write_reg(dev, ENEB_IRQ_STATUS,
+ irq_status & ~ENEB_IRQ_STATUS_IR);
+
+ /* rev B support only recieving */
+ return ENE_IRQ_RX;
+ }
+
+ irq_status = ene_hw_read_reg(dev, ENEC_IRQ);
+
+ if (!irq_status && ENEC_IRQ_STATUS)
  return 0;
 
- ene_hw_write_reg(dev, ENE_IRQ_STATUS, irq_status & ~ENE_IRQ_STATUS_IR);
- return 1;
+ /* original driver does that twise - a workaround? */
+ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+
+ /* clear unknown flag in F8F9 */
+ if (fw_flags2 & ENE_FW2_IRQ_CLR)
+ ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR);
+
+ /* check if this is a TX interrupt */
+ fw_flags1 = ene_hw_read_reg(dev, ENE_FW1);
+
+ if (fw_flags1 & ENE_FW1_TXIRQ) {
+ ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+ return ENE_IRQ_TX;
+ } else
+ return ENE_IRQ_RX;
 }
 
+static int ene_hw_detect(struct ene_device *dev)
+{
+ u8 chip_major, chip_minor;
+ u8 hw_revision, old_ver;
+ u8 tmp;
+ u8 fw_capabilities;
+
+ tmp = ene_hw_read_reg(dev, ENE_HW_UNK);
+ ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR);
+
+ chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR);
+ chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR);
+
+ ene_hw_write_reg(dev, ENE_HW_UNK, tmp);
+ hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION);
+ old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD);
+
+ if (hw_revision == 0xFF) {
+ printk(KERN_ERR ENE_DRIVER_NAME ": "
+       "invalid chip ID, probably hardware is absent\n");
+ return -ENODEV;
+ }
+
+ if (chip_major == 0x33) {
+ printk(KERN_NOTICE ENE_DRIVER_NAME ": "
+       "chips 0x33xx aren't supported yet\n");
+ return -ENODEV;
+ }
+
+ if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
+ dev->hw_revision = ENE_HW_C;
+ printk(KERN_WARNING ENE_DRIVER_NAME ": "
+       "KB3926C detected, driver support is not complete!\n");
+
+ } else if (old_ver == 0x24 && hw_revision == 0xC0) {
+ dev->hw_revision = ENE_HW_B;
+
+ printk(KERN_NOTICE ENE_DRIVER_NAME ": "
+       "KB3926B/KB3924 detected\n");
+ } else {
+ dev->hw_revision = ENE_HW_D;
+
+ printk(KERN_WARNING ENE_DRIVER_NAME ": "
+       "unknown ENE chip detected, assuming KB3926D\n");
+ }
+
+ printk(KERN_NOTICE ENE_DRIVER_NAME ": "
+       "chip is 0x%02x%02x - 0x%02x, 0x%02x\n",
+       chip_major, chip_minor, old_ver, hw_revision);
+
+ /* detect features hardware supports */
+
+ if (dev->hw_revision < ENE_HW_C)
+ return 0;
+
+ fw_capabilities = ene_hw_read_reg(dev, ENE_FW2);
+
+ dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN;
+ dev->hw_learning_capable = fw_capabilities & ENE_FW2_LEARNING;
+
+ dev->hw_fan_as_normal_input = dev->hw_learning_capable &&
+    fw_capabilities & ENE_FW2_FAN_AS_NRML_IN;
+
+ printk(KERN_NOTICE ENE_DRIVER_NAME ": hardware features:\n");
+ printk(KERN_NOTICE ENE_DRIVER_NAME
+       ": learning %s, gpio40_learn %s, fan_in %s\n",
+       dev->hw_learning_capable ? "on" : "off",
+       dev->hw_gpio40_learning ? "on" : "off",
+       dev->hw_fan_as_normal_input ? "on" : "off");
+ return 0;
+}
 
 /* hardware initialization */
 static int ene_hw_init(void *data)
 {
+ u8 reg_value;
  struct ene_device *dev = (struct ene_device *)data;
  dev->in_use = 1;
 
- ene_hw_write_reg(dev, ENE_IRQ, dev->irq << 1);
- ene_hw_write_reg(dev, ENE_ADC_UNK2, 0x00);
- ene_hw_write_reg(dev, ENE_ADC_SAMPLE_PERIOD, sample_period);
- ene_hw_write_reg(dev, ENE_ADC_UNK1, 0x07);
- ene_hw_write_reg(dev, ENE_UNK1, 0x01);
- ene_hw_write_reg_mask(dev, ENE_FW_SETTINGS, ENE_FW_ENABLE | ENE_FW_IRQ,
- ENE_FW_ENABLE | ENE_FW_IRQ);
+ if (dev->hw_revision < ENE_HW_C) {
+ ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+ ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
+ } else {
+ reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0;
+ reg_value |= ENEC_IRQ_UNK_EN;
+ reg_value &= ~ENEC_IRQ_STATUS;
+ reg_value |= (dev->irq & ENEC_IRQ_MASK);
+ ene_hw_write_reg(dev, ENEC_IRQ, reg_value);
+ ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63);
+ }
+
+ ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00);
+
+ if (!dev->hw_learning_capable && enable_learning) {
+ printk(KERN_ERR ENE_DRIVER_NAME ": "
+       "Device doesn't support wide band reciever\n");
+ enable_learning = 0;
+ }
+
+ ene_set_inputs(dev, enable_learning);
+
+ /* set sampling period */
+ ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period);
 
  /* ack any pending irqs - just in case */
- ene_hw_irq_status(dev);
+ ene_hw_irq_status(dev, NULL);
 
  /* enter idle mode */
  ene_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);
+
  /* clear stats */
  dev->sample = 0;
  return 0;
 }
 
+/* this enables gpio40 signal, used if connected to wide band input*/
+static void ene_enable_gpio40(struct ene_device *dev, int enable)
+{
+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ?
+      0 : ENE_CIR_CONF2_GPIO40DIS,
+      ENE_CIR_CONF2_GPIO40DIS);
+}
+
+/* this enables the classic sampler */
+static void ene_enable_normal_recieve(struct ene_device *dev, int enable)
+{
+ ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0);
+}
+
+/* this enables recieve via fan input */
+static void ene_enable_fan_recieve(struct ene_device *dev, int enable)
+{
+ if (!enable)
+ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0);
+ else {
+ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+ ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
+ }
+
+ dev->fan_input_inuse = enable;
+}
+
+/* determine which input to use*/
+static void ene_set_inputs(struct ene_device *dev, int learning_enable)
+{
+ ene_enable_normal_recieve(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 */
+ if (!dev->hw_learning_capable) {
+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+ return;
+ }
+
+ /* enable learning mode */
+ if (learning_enable) {
+ ene_enable_gpio40(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);
+
+ /* disable learning mode */
+ } else {
+ if (dev->hw_fan_as_normal_input) {
+ ene_enable_fan_recieve(dev, 1);
+ ene_enable_normal_recieve(dev, 0);
+ } else
+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+ }
+
+ /* set few additional settings for this mode */
+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ?
+      ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1);
+
+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ?
+      ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2);
+}
+
 /* deinitialization */
 static void ene_hw_deinit(void *data)
 {
  struct ene_device *dev = (struct ene_device *)data;
 
+ /* disable samplers */
+ ene_enable_normal_recieve(dev, 0);
+
+ if (dev->hw_fan_as_normal_input)
+ ene_enable_fan_recieve(dev, 0);
+
  /* disable hardware IRQ and firmware flag */
- ene_hw_write_reg_mask(dev, ENE_FW_SETTINGS, 0,
- ENE_FW_ENABLE | ENE_FW_IRQ);
+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ);
 
  ene_set_idle(dev, 1);
  dev->in_use = 0;
@@ -135,7 +327,7 @@ static void send_sample(struct ene_device *dev)
  value |= PULSE_BIT;
 
  if (!lirc_buffer_full(dev->lirc_driver->rbuf)) {
- lirc_buffer_write(dev->lirc_driver->rbuf, (void *) &value);
+ lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value);
  wake_up(&dev->lirc_driver->rbuf->wait_poll);
  }
  dev->sample = 0;
@@ -158,14 +350,13 @@ static void update_sample(struct ene_device *dev, int sample)
 static void ene_set_idle(struct ene_device *dev, int idle)
 {
  struct timeval now;
+ int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C);
 
- ene_hw_write_reg_mask(dev, ENE_ADC_SAMPLE_PERIOD,
- idle && enable_idle ? 0 : ENE_ADC_SAMPLE_OVERFLOW,
- ENE_ADC_SAMPLE_OVERFLOW);
-
+ ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD,
+      disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW,
+      ENE_CIR_SAMPLE_OVERFLOW);
  dev->idle = idle;
 
-
  /* remember when we have entered the idle mode */
  if (idle) {
  do_gettimeofday(&dev->gap_start);
@@ -179,15 +370,14 @@ static void ene_set_idle(struct ene_device *dev, int idle)
  dev->sample = space(PULSE_MASK);
  else
  dev->sample = dev->sample +
- space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec))
- + space(now.tv_usec - dev->gap_start.tv_usec);
+    space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec))
+    + space(now.tv_usec - dev->gap_start.tv_usec);
 
  if (abs(dev->sample) > PULSE_MASK)
  dev->sample = space(PULSE_MASK);
  send_sample(dev);
 }
 
-
 /* interrupt handler */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
 static irqreturn_t ene_hw_irq(int irq, void *data)
@@ -195,41 +385,67 @@ static irqreturn_t ene_hw_irq(int irq, void *data)
 static irqreturn_t ene_hw_irq(int irq, void *data, struct pt_regs *regs)
 #endif
 {
- u16 hw_address;
- u8 hw_value;
+ u16 hw_value;
  int i, hw_sample;
  int space;
+ int buffer_pointer;
+ int irq_status;
 
  struct ene_device *dev = (struct ene_device *)data;
+ irq_status = ene_hw_irq_status(dev, &buffer_pointer);
 
- if (!ene_hw_irq_status(dev))
+ if (!irq_status)
  return IRQ_NONE;
 
- hw_address = ENE_SAMPLE_BUFFER + hw_get_buf_pointer(dev);
+ /* TODO: only RX for now */
+ if (irq_status == ENE_IRQ_TX)
+ return IRQ_HANDLED;
+
+ for (i = 0; i < ENE_SAMPLES_SIZE; i++) {
 
- for (i = 0 ; i < ENE_SAMPLES_SIZE ; i++) {
+ hw_value = ene_hw_read_reg(dev,
+   ENE_SAMPLE_BUFFER + buffer_pointer +
+   i);
 
- hw_value = ene_hw_read_reg(dev, hw_address + i);
- space = hw_value & ENE_SAMPLE_LOW_MASK;
- hw_value &= ~ENE_SAMPLE_LOW_MASK;
+ if (dev->fan_input_inuse) {
+ /* read high part of the sample */
+ hw_value |= ene_hw_read_reg(dev,
+    ENE_SAMPLE_BUFFER_FAN +
+    buffer_pointer + i) << 8;
+
+ /* test for _space_ bit */
+ space = !(hw_value & 0x8000);
+
+ /* clear space bit, and other unused bits */
+ hw_value &= 0x0FFF;
+
+ /* TODO: determine correct sample period for fan
+   input - can we change it? */
+
+ hw_sample = hw_value * 50;
+
+ } else {
+ space = hw_value & ENE_SAMPLE_LOW_MASK;
+ hw_value &= ~ENE_SAMPLE_LOW_MASK;
+ hw_sample = hw_value * sample_period;
+ }
 
  /* no more data */
  if (!(hw_value))
  break;
 
- /* calculate hw sample */
- hw_sample = hw_value * sample_period;
-
  if (space)
  hw_sample *= -1;
 
  /* overflow sample recieved, handle it */
- if (space && hw_value == ENE_SAMPLE_OVERFLOW) {
+ /* TODO: does fan input have same overflows? */
+
+ if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) {
 
- if (dev->idle && !enable_idle)
+ if (dev->idle)
  continue;
 
- if (abs(dev->sample) <= ENE_MAXGAP)
+ if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP)
  update_sample(dev, hw_sample);
  else
  ene_set_idle(dev, 1);
@@ -237,8 +453,8 @@ static irqreturn_t ene_hw_irq(int irq, void *data, struct pt_regs *regs)
  continue;
  }
 
- if (dev->idle) {
- /* normal first sample recieved*/
+ /* normal first sample recieved */
+ if (!dev->fan_input_inuse && dev->idle) {
  ene_set_idle(dev, 0);
 
  /* discard first recieved value, its random
@@ -249,7 +465,6 @@ static irqreturn_t ene_hw_irq(int irq, void *data, struct pt_regs *regs)
  if (!enable_idle)
  continue;
  }
-
  update_sample(dev, hw_sample);
  send_sample(dev);
  }
@@ -257,7 +472,7 @@ static irqreturn_t ene_hw_irq(int irq, void *data, struct pt_regs *regs)
 }
 
 static int ene_probe(struct pnp_dev *pnp_dev,
- const struct pnp_device_id *dev_id)
+     const struct pnp_device_id *dev_id)
 {
  struct resource *res;
  struct ene_device *dev;
@@ -272,7 +487,6 @@ static int ene_probe(struct pnp_dev *pnp_dev,
  dev->pnp_dev = pnp_dev;
  pnp_set_drvdata(pnp_dev, dev);
 
-
  /* validate and read resources */
  error = -ENODEV;
  res = pnp_get_resource(pnp_dev, IORESOURCE_IO, 0);
@@ -314,8 +528,7 @@ static int ene_probe(struct pnp_dev *pnp_dev,
  if (!lirc_driver->rbuf)
  goto err3;
 
- if (lirc_buffer_init(lirc_driver->rbuf,
- sizeof(int), sizeof(int) * 256))
+ if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256))
  goto err4;
 
  error = -ENODEV;
@@ -331,14 +544,10 @@ static int ene_probe(struct pnp_dev *pnp_dev,
  IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev))
  goto err7;
 
-
  /* check firmware version */
- error = -ENODEV;
- if (ene_hw_read_reg(dev, ENE_FW_VERSION) != ENE_FW_VER_SUPP) {
- printk(KERN_WARNING ENE_DRIVER_NAME ": "
-       "unsupported firmware found, aborting\n");
+ error = ene_hw_detect(dev);
+ if (error)
  goto err8;
- }
 
  printk(KERN_NOTICE ENE_DRIVER_NAME ": "
        "driver has been succesfully loaded\n");
@@ -362,7 +571,6 @@ err1:
  return error;
 }
 
-
 static void ene_remove(struct pnp_dev *pnp_dev)
 {
  struct ene_device *dev = pnp_get_drvdata(pnp_dev);
@@ -375,12 +583,11 @@ static void ene_remove(struct pnp_dev *pnp_dev)
  kfree(dev);
 }
 
-
 #ifdef CONFIG_PM
 static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
 {
  struct ene_device *dev = pnp_get_drvdata(pnp_dev);
- ene_hw_write_reg_mask(dev, ENE_FW_SETTINGS, ENE_FW_WAKE, ENE_FW_WAKE);
+ ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE);
  return 0;
 }
 
@@ -390,15 +597,15 @@ static int ene_resume(struct pnp_dev *pnp_dev)
  if (dev->in_use)
  ene_hw_init(dev);
 
- ene_hw_write_reg_mask(dev, ENE_FW_SETTINGS, 0, ENE_FW_WAKE);
+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE);
  return 0;
 }
 
 #endif
 
 static const struct pnp_device_id ene_ids[] = {
- { .id = "ENE0100", },
- { },
+ {.id = "ENE0100",},
+ {},
 };
 
 static struct pnp_driver ene_driver = {
@@ -430,18 +637,20 @@ static void ene_exit(void)
  pnp_unregister_driver(&ene_driver);
 }
 
-
 module_param(sample_period, int, S_IRUGO);
 MODULE_PARM_DESC(sample_period, "Hardware sample period (75 us default)");
 
 module_param(enable_idle, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(enable_idle,
-"Enables turning off signal sampling after long inactivity time; "
-"if disabled might help detecting input signal (default: enabled)");
+ "Enables turning off signal sampling after long inactivity time; "
+ "if disabled might help detecting input signal (default: enabled)");
 
+module_param(enable_learning, bool, S_IRUGO);
+MODULE_PARM_DESC(enable_learning, "Use wide band reciever");
 
 MODULE_DEVICE_TABLE(pnp, ene_ids);
-MODULE_DESCRIPTION("LIRC driver for KB3924/ENE0100 CIR port");
+MODULE_DESCRIPTION
+    ("LIRC driver for KB3924/KB3926C/KB3926D (aka ENE0100) CIR port");
 MODULE_AUTHOR("Maxim Levitsky");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/lirc_ene0100/lirc_ene0100.h b/drivers/lirc_ene0100/lirc_ene0100.h
index 9d3f6e8..7f862f1 100644
--- a/drivers/lirc_ene0100/lirc_ene0100.h
+++ b/drivers/lirc_ene0100/lirc_ene0100.h
@@ -23,68 +23,111 @@
 #include "drivers/lirc.h"
 #include "drivers/lirc_dev/lirc_dev.h"
 
-
 /* hardware address */
 #define ENE_STATUS 0 /* hardware status - unused */
 #define ENE_ADDR_HI 1 /* hi byte of register address */
 #define ENE_ADDR_LO 2 /* low byte of register address */
 #define ENE_IO 3 /* read/write window */
-#define ENE_MAX_IO 3
-
+#define ENE_MAX_IO 4
 
 /* 8 bytes of samples, divided in 2 halfs*/
-#define ENE_SAMPLE_BUFFER 0xF8F0
-#define ENE_SAMPLE_LOW_MASK (1 << 7)
-#define ENE_SAMPLE_VALUE_MASK 0x7F
-#define ENE_SAMPLE_OVERFLOW 0x7F
-#define ENE_SAMPLES_SIZE 4
-
-
-/* firmware settings */
-#define ENE_FW_SETTINGS 0xF8F8
-#define ENE_FW_ENABLE (1 << 0) /* enable fw processing */
-#define ENE_FW_WAKE (1 << 6) /* enable wake from S3 */
-#define ENE_FW_IRQ (1 << 7) /* enable interrupt */
-
-
-/* buffer pointer, tells which half of ENE_SAMPLE_BUFFER to read */
-#define ENE_FW_BUFFER_POINTER 0xF8F9
-#define ENE_FW_BUFFER_POINTER_HIGH (1 << 0)
-
-
-/* IRQ registers block */
-#define ENE_IRQ 0xFD09 /* IRQ number */
-#define ENE_UNK1 0xFD17   /* unknown setting = 1 */
-#define ENE_IRQ_STATUS 0xFD80   /* irq status */
-#define ENE_IRQ_STATUS_IR (1 << 5) /* IR irq */
-
-
-/* ADC settings */
-#define ENE_ADC_UNK1 0xFEC0 /* unknown setting = 7 */
-#define ENE_ADC_UNK2 0xFEC1   /* unknown setting = 0 */
-#define ENE_ADC_SAMPLE_PERIOD 0xFEC8   /* sample period in us */
-#define ENE_ADC_SAMPLE_OVERFLOW (1 << 7) /* interrupt on
-    overflows if set */
-
-/* fimware version */
-#define ENE_FW_VERSION 0xFF00
-#define ENE_FW_VER_SUPP 0xC0
-
+#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */
+#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* fan input sample buffer */
+
+#define ENE_SAMPLE_LOW_MASK (1 << 7)
+#define ENE_SAMPLE_VALUE_MASK 0x7F
+#define ENE_SAMPLE_OVERFLOW 0x7F
+#define ENE_SAMPLES_SIZE 4
+
+/* first firmware register */
+#define ENE_FW1 0xF8F8
+#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */
+#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */
+#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */
+#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */
+
+/* second firmware register */
+#define ENE_FW2 0xF8F9
+#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */
+#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */
+#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */
+ /* learning input */
+#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */
+#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning */
+
+/* fan as input settings - only if learning capable */
+#define ENE_FAN_AS_IN1 0xFE30   /* fan init reg 1 */
+#define ENE_FAN_AS_IN1_EN -51 /* this smells like sample period */
+#define ENE_FAN_AS_IN2 0xFE31
+#define ENE_FAN_AS_IN2_EN 3
+
+/* IRQ registers block (for revision B) */
+#define ENEB_IRQ 0xFD09 /* IRQ number */
+#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */
+#define ENEB_IRQ_STATUS 0xFD80 /* irq status */
+#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */
+
+/* IRQ registers block for revision C+ */
+#define ENEC_IRQ 0xFE9B /* new irq settings register */
+#define ENEC_IRQ_MASK 0x0F /* irq number mask */
+#define ENEC_IRQ_UNK_EN (1 << 4) /* always enabled */
+#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */
+
+/* CIR block settings */
+#define ENE_CIR_CONF1 0xFEC0
+#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */
+#define ENE_CIR_CONF1_LEARN1 (1 << 3) /*enabled on learning mode */
+#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */
+#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */
+
+#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */
+#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */
+#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */
+
+#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */
+#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */
+
+/* transmitter - not implemented yet */
+/* rev C and higher */
+
+#define ENE_TX_SETTING1 0xFC01 /* TODO: figure out these */
+#define ENE_TX_SETTING1_EN (1 << 5)
+#define ENE_TX_SETTING2 0xFC08
+#define ENE_TX_SETTING2_EN (1 << 1)
+
+#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */
+#define ENE_TX_UNK1 0xFECB /* = 0x63 */
+
+#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */
+#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */
+#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */
+
+/* Hardware versions */
+#define ENE_HW_VERSION 0xFF00 /* hardware revision */
+#define ENE_HW_UNK 0xFF1D
+#define ENE_HW_UNK_CLR (1 << 2)
+#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */
+#define ENE_HW_VER_MINOR 0xFF1F
+#define ENE_HW_VER_OLD 0xFD00
 
 #define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0))
 
-#define ENE_DRIVER_NAME "enecir"
+#define ENE_DRIVER_NAME "enecir"
+#define ENE_MAXGAP 250000 /* this is amount of
+   time we wait before
+   turning the
+   sampler, chosen
+   arbitry */
 
-#define ENE_MAXGAP 250000 /* this is the amount
-   of time we wait
-   before turning off
-   the sampler, chosen
-   to be higher than
-   standard gap
-   values */
+#define space(len) (-(len)) /* add a space */
 
-#define space(len) (-(len))   /* add a space */
+/* software defines */
+#define ENE_IRQ_RX 1
+#define ENE_IRQ_TX 2
 
+#define  ENE_HW_B 1 /* 3926B/3924 */
+#define  ENE_HW_C 2 /* 3926C */
+#define  ENE_HW_D 3 /* 3926D+ */
 
 struct ene_device {
  struct pnp_dev *pnp_dev;
@@ -94,11 +137,17 @@ struct ene_device {
  unsigned long hw_io;
  int irq;
 
+ int hw_revision; /* hardware revision */
+ int hw_learning_capable; /* learning capable */
+ int hw_gpio40_learning; /* gpio40 is learning */
+ int hw_fan_as_normal_input; /* fan input is used as regular input */
+
  /* device data */
  int idle;
+ int fan_input_inuse;
+
  int sample;
  int in_use;
-
+
  struct timeval gap_start;
 };
-
--
1.6.0.4




------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Add support for newer ENE0100 devices

maximlevitsky (Bugzilla)
In reply to this post by maximlevitsky (Bugzilla)
On Thu, 2009-08-20 at 10:12 +0300, Maxim Levitsky wrote:

> Hi,
>
> It turns out I have an older revision of ENE KB3924
> The following patch adds initial support for ENE KB3926B/KB3926C
> (at least this is how they call it in windows driver)
>
>
> Most of code is untested, except for KB3926C with standard input,
> thanks to Giuseppe Bilotta.
>
> Also chip detection logic is improved.
>
> patch against CVS.
>
> Best regards,
> Maxim Levitsky
>
ah, got a list bounce, due to 'message too big'
here, attached compressed version

Best regards,
        Maxim Levitsky


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july

0001-Add-support-for-newer-ENE0100-devices.patch.gz (9K) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Add support for newer ENE0100 devices

Giuseppe Bilotta-4
On Thu, Aug 20, 2009 at 9:18 AM, Maxim Levitsky<[hidden email]> wrote:
> On Thu, 2009-08-20 at 10:12 +0300, Maxim Levitsky wrote:
>
> ah, got a list bounce, due to 'message too big'
> here, attached compressed version

It seems that the patch does not apply cleanly against the latest CVS.
I removed the files, did a cvs up -d, and then tried applying your
patch, but there seem to be a few conflicts. Which CVS revision is it
against?

--
Giuseppe "Oblomov" Bilotta

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Add support for newer ENE0100 devices

Giuseppe Bilotta-4
On Thu, Aug 20, 2009 at 11:20 AM, Giuseppe
Bilotta<[hidden email]> wrote:

> On Thu, Aug 20, 2009 at 9:18 AM, Maxim Levitsky<[hidden email]> wrote:
>> On Thu, 2009-08-20 at 10:12 +0300, Maxim Levitsky wrote:
>>
>> ah, got a list bounce, due to 'message too big'
>> here, attached compressed version
>
> It seems that the patch does not apply cleanly against the latest CVS.
> I removed the files, did a cvs up -d, and then tried applying your
> patch, but there seem to be a few conflicts. Which CVS revision is it
> against?

My bad, I somehow mangled the patch when downloading it. Sorry for the noise.

--
Giuseppe "Oblomov" Bilotta

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH v2] Add support for newer ENE0100 devices (KB3926C, KB3926D)

maximlevitsky (Bugzilla)
In reply to this post by maximlevitsky (Bugzilla)
This is slightly updated version of this patch.
I finally figured out that on my system is actually KB2426B
So I updated descriptions, also few fixes for fan input mode, etc.

Best regards,
        Maxim Levisky

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july

0001-Add-support-for-newer-ENE0100-devices-KB3926C-KB39.patch.gz (9K) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2] Add support for newer ENE0100 devices (KB3926C, KB3926D)

maximlevitsky (Bugzilla)
On Thu, 2009-08-20 at 15:25 +0300, Maxim Levitsky wrote:
> This is slightly updated version of this patch.
> I finally figured out that on my system is actually KB2426B
3926B
> So I updated descriptions, also few fixes for fan input mode, etc.
>
> Best regards,
> Maxim Levisky


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH v3] Add support for newer ENE0100 devices (KB3926C, KB3926D)

maximlevitsky (Bugzilla)
In reply to this post by maximlevitsky (Bugzilla)
This is third version of this patch
Some small documentation updates, pretty much now I have documented
everything.

Best regards,
        Maxim Levitsky



------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july

0001-Add-support-for-newer-ENE0100-devices-KB3926C-KB39.patch.gz (10K) Download Attachment
Loading...