Message ID | 1394838259-14260-10-git-send-email-james@albanarts.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 15 March 2014 01:04, James Hogan <james@albanarts.com> wrote: > From: Antti Seppälä <a.seppala@gmail.com> > > Nuvoton-cir utilizes the encoding capabilities of rc-core to convert > scancodes from user space to pulse/space format understood by the > underlying hardware. > > Converted samples are then written to the wakeup fifo along with other > necessary configuration to enable wake up functionality. > > Signed-off-by: Antti Seppälä <a.seppala@gmail.com> > Signed-off-by: James Hogan <james@albanarts.com> > Cc: Mauro Carvalho Chehab <m.chehab@samsung.com> > Cc: Jarod Wilson <jarod@redhat.com> > Cc: Wei Yongjun <yongjun_wei@trendmicro.com.cn> > Cc: Hans Verkuil <hans.verkuil@cisco.com> > --- > Please note this patch is only build tested. > > Changes in v2 (James Hogan): > - Handle new -ENOBUFS when IR encoding buffer isn't long enough and > reduce buffer size to the size of the wake fifo so that time isn't > wasted processing encoded IR events that will be discarded. Also only > discard the last event if the encoded data is complete. > - Change reference to rc_dev::enabled_protocols to > enabled_protocols[type] since it has been converted to an array. > - Fix IR encoding buffer loop condition to be i < ret rather than i <= > ret. The return value of ir_raw_encode_scancode is the number of > events rather than the last event. > - Set encode_wakeup so that the set of allowed wakeup protocols matches > the set of raw IR encoders. > --- > drivers/media/rc/nuvoton-cir.c | 123 +++++++++++++++++++++++++++++++++++++++++ > drivers/media/rc/nuvoton-cir.h | 1 + > include/media/rc-core.h | 1 + > 3 files changed, 125 insertions(+) > > diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c > index d244e1a..ec8f4fc 100644 > --- a/drivers/media/rc/nuvoton-cir.c > +++ b/drivers/media/rc/nuvoton-cir.c > @@ -527,6 +527,127 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) > return 0; > } > > +static int nvt_write_wakeup_codes(struct rc_dev *dev, > + const u8 *wakeup_sample_buf, int count) > +{ > + int i = 0; > + u8 reg, reg_learn_mode; > + unsigned long flags; > + struct nvt_dev *nvt = dev->priv; > + > + nvt_dbg_wake("writing wakeup samples"); > + > + reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); > + reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0; > + reg_learn_mode |= CIR_WAKE_IRCON_MODE1; > + > + /* Lock the learn area to prevent racing with wake-isr */ > + spin_lock_irqsave(&nvt->nvt_lock, flags); > + > + /* Enable fifo writes */ > + nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON); > + > + /* Clear cir wake rx fifo */ > + nvt_clear_cir_wake_fifo(nvt); > + > + if (count > WAKE_FIFO_LEN) { > + nvt_dbg_wake("HW FIFO too small for all wake samples"); > + count = WAKE_FIFO_LEN; > + } Now that the encoders support partial encoding the above check against WAKE_FIFO_LEN never triggers and can be removed. > + > + if (count) > + pr_info("Wake samples (%d) =", count); > + else > + pr_info("Wake sample fifo cleared"); > + > + /* Write wake samples to fifo */ > + for (i = 0; i < count; i++) { > + pr_cont(" %02x", wakeup_sample_buf[i]); > + nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i], > + CIR_WAKE_WR_FIFO_DATA); > + } > + pr_cont("\n"); > + > + /* Switch cir to wakeup mode and disable fifo writing */ > + nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON); > + > + /* Set number of bytes needed for wake */ > + nvt_cir_wake_reg_write(nvt, count ? count : > + CIR_WAKE_FIFO_CMP_BYTES, > + CIR_WAKE_FIFO_CMP_DEEP); > + > + spin_unlock_irqrestore(&nvt->nvt_lock, flags); > + > + return 0; > +} > + > +static int nvt_ir_raw_set_filter(struct rc_dev *dev, enum rc_filter_type type, > + struct rc_scancode_filter *sc_filter) > +{ > + u8 *reg_buf; > + u8 buf_val; > + int i, ret, count; > + unsigned int val; > + struct ir_raw_event *raw; > + bool complete; > + > + /* Other types are not valid for nuvoton */ > + if (type != RC_FILTER_WAKEUP) > + return -EINVAL; > + > + /* Require both mask and data to be set before actually committing */ > + if (!sc_filter->mask || !sc_filter->data) > + return 0; > + > + raw = kmalloc(WAKE_FIFO_LEN * sizeof(*raw), GFP_KERNEL); > + if (!raw) > + return -ENOMEM; > + > + ret = ir_raw_encode_scancode(dev->enabled_protocols[type], sc_filter, > + raw, WAKE_FIFO_LEN); > + complete = (ret != -ENOBUFS); > + if (!complete) > + ret = WAKE_FIFO_LEN; > + else if (ret < 0) > + goto out_raw; > + > + reg_buf = kmalloc(sizeof(*reg_buf) * WAKE_FIFO_LEN, GFP_KERNEL); > + if (!reg_buf) { > + ret = -ENOMEM; > + goto out_raw; > + } > + > + /* Inspect the ir samples */ > + for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) { > + val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD; > + > + /* Split too large values into several smaller ones */ > + while (val > 0 && count < WAKE_FIFO_LEN) { > + > + /* Skip last value for better comparison tolerance */ > + if (complete && i == ret - 1 && val < BUF_LEN_MASK) > + break; > + > + /* Clamp values to BUF_LEN_MASK at most */ > + buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val; > + > + reg_buf[count] = buf_val; > + val -= buf_val; > + if ((raw[i]).pulse) > + reg_buf[count] |= BUF_PULSE_BIT; > + count++; > + } > + } > + > + ret = nvt_write_wakeup_codes(dev, reg_buf, count); > + > + kfree(reg_buf); > +out_raw: > + kfree(raw); > + > + return ret; > +} > + > /* > * nvt_tx_ir > * > @@ -1044,11 +1165,13 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) > /* Set up the rc device */ > rdev->priv = nvt; > rdev->driver_type = RC_DRIVER_IR_RAW; > + rdev->encode_wakeup = true; > rc_set_allowed_protocols(rdev, RC_BIT_ALL); > rdev->open = nvt_open; > rdev->close = nvt_close; > rdev->tx_ir = nvt_tx_ir; > rdev->s_tx_carrier = nvt_set_tx_carrier; > + rdev->s_filter = nvt_ir_raw_set_filter; > rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; > rdev->input_phys = "nuvoton/cir0"; > rdev->input_id.bustype = BUS_HOST; > diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h > index e1cf23c..9d0e161 100644 > --- a/drivers/media/rc/nuvoton-cir.h > +++ b/drivers/media/rc/nuvoton-cir.h > @@ -63,6 +63,7 @@ static int debug; > */ > #define TX_BUF_LEN 256 > #define RX_BUF_LEN 32 > +#define WAKE_FIFO_LEN 67 > > struct nvt_dev { > struct pnp_dev *pdev; > diff --git a/include/media/rc-core.h b/include/media/rc-core.h > index 2d81d6c..80177da 100644 > --- a/include/media/rc-core.h > +++ b/include/media/rc-core.h > @@ -271,6 +271,7 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev) > #define US_TO_NS(usec) ((usec) * 1000) > #define MS_TO_US(msec) ((msec) * 1000) > #define MS_TO_NS(msec) ((msec) * 1000 * 1000) > +#define NS_TO_US(nsec) DIV_ROUND_UP(nsec, 1000L) > > void ir_raw_event_handle(struct rc_dev *dev); > int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); > -- > 1.8.3.2 > -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Sunday 16 March 2014 10:39:39 Antti Seppälä wrote: > > +static int nvt_write_wakeup_codes(struct rc_dev *dev, > > + const u8 *wakeup_sample_buf, int count) > > +{ > > + int i = 0; > > + u8 reg, reg_learn_mode; > > + unsigned long flags; > > + struct nvt_dev *nvt = dev->priv; > > + > > + nvt_dbg_wake("writing wakeup samples"); > > + > > + reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); > > + reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0; > > + reg_learn_mode |= CIR_WAKE_IRCON_MODE1; > > + > > + /* Lock the learn area to prevent racing with wake-isr */ > > + spin_lock_irqsave(&nvt->nvt_lock, flags); > > + > > + /* Enable fifo writes */ > > + nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON); > > + > > + /* Clear cir wake rx fifo */ > > + nvt_clear_cir_wake_fifo(nvt); > > + > > + if (count > WAKE_FIFO_LEN) { > > + nvt_dbg_wake("HW FIFO too small for all wake samples"); > > + count = WAKE_FIFO_LEN; > > + } > > Now that the encoders support partial encoding the above check against > WAKE_FIFO_LEN never triggers and can be removed. Yep, good point Thanks James
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index d244e1a..ec8f4fc 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -527,6 +527,127 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) return 0; } +static int nvt_write_wakeup_codes(struct rc_dev *dev, + const u8 *wakeup_sample_buf, int count) +{ + int i = 0; + u8 reg, reg_learn_mode; + unsigned long flags; + struct nvt_dev *nvt = dev->priv; + + nvt_dbg_wake("writing wakeup samples"); + + reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); + reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0; + reg_learn_mode |= CIR_WAKE_IRCON_MODE1; + + /* Lock the learn area to prevent racing with wake-isr */ + spin_lock_irqsave(&nvt->nvt_lock, flags); + + /* Enable fifo writes */ + nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON); + + /* Clear cir wake rx fifo */ + nvt_clear_cir_wake_fifo(nvt); + + if (count > WAKE_FIFO_LEN) { + nvt_dbg_wake("HW FIFO too small for all wake samples"); + count = WAKE_FIFO_LEN; + } + + if (count) + pr_info("Wake samples (%d) =", count); + else + pr_info("Wake sample fifo cleared"); + + /* Write wake samples to fifo */ + for (i = 0; i < count; i++) { + pr_cont(" %02x", wakeup_sample_buf[i]); + nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i], + CIR_WAKE_WR_FIFO_DATA); + } + pr_cont("\n"); + + /* Switch cir to wakeup mode and disable fifo writing */ + nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON); + + /* Set number of bytes needed for wake */ + nvt_cir_wake_reg_write(nvt, count ? count : + CIR_WAKE_FIFO_CMP_BYTES, + CIR_WAKE_FIFO_CMP_DEEP); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + return 0; +} + +static int nvt_ir_raw_set_filter(struct rc_dev *dev, enum rc_filter_type type, + struct rc_scancode_filter *sc_filter) +{ + u8 *reg_buf; + u8 buf_val; + int i, ret, count; + unsigned int val; + struct ir_raw_event *raw; + bool complete; + + /* Other types are not valid for nuvoton */ + if (type != RC_FILTER_WAKEUP) + return -EINVAL; + + /* Require both mask and data to be set before actually committing */ + if (!sc_filter->mask || !sc_filter->data) + return 0; + + raw = kmalloc(WAKE_FIFO_LEN * sizeof(*raw), GFP_KERNEL); + if (!raw) + return -ENOMEM; + + ret = ir_raw_encode_scancode(dev->enabled_protocols[type], sc_filter, + raw, WAKE_FIFO_LEN); + complete = (ret != -ENOBUFS); + if (!complete) + ret = WAKE_FIFO_LEN; + else if (ret < 0) + goto out_raw; + + reg_buf = kmalloc(sizeof(*reg_buf) * WAKE_FIFO_LEN, GFP_KERNEL); + if (!reg_buf) { + ret = -ENOMEM; + goto out_raw; + } + + /* Inspect the ir samples */ + for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) { + val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD; + + /* Split too large values into several smaller ones */ + while (val > 0 && count < WAKE_FIFO_LEN) { + + /* Skip last value for better comparison tolerance */ + if (complete && i == ret - 1 && val < BUF_LEN_MASK) + break; + + /* Clamp values to BUF_LEN_MASK at most */ + buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val; + + reg_buf[count] = buf_val; + val -= buf_val; + if ((raw[i]).pulse) + reg_buf[count] |= BUF_PULSE_BIT; + count++; + } + } + + ret = nvt_write_wakeup_codes(dev, reg_buf, count); + + kfree(reg_buf); +out_raw: + kfree(raw); + + return ret; +} + /* * nvt_tx_ir * @@ -1044,11 +1165,13 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* Set up the rc device */ rdev->priv = nvt; rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->encode_wakeup = true; rc_set_allowed_protocols(rdev, RC_BIT_ALL); rdev->open = nvt_open; rdev->close = nvt_close; rdev->tx_ir = nvt_tx_ir; rdev->s_tx_carrier = nvt_set_tx_carrier; + rdev->s_filter = nvt_ir_raw_set_filter; rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; rdev->input_phys = "nuvoton/cir0"; rdev->input_id.bustype = BUS_HOST; diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index e1cf23c..9d0e161 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -63,6 +63,7 @@ static int debug; */ #define TX_BUF_LEN 256 #define RX_BUF_LEN 32 +#define WAKE_FIFO_LEN 67 struct nvt_dev { struct pnp_dev *pdev; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 2d81d6c..80177da 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -271,6 +271,7 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev) #define US_TO_NS(usec) ((usec) * 1000) #define MS_TO_US(msec) ((msec) * 1000) #define MS_TO_NS(msec) ((msec) * 1000 * 1000) +#define NS_TO_US(nsec) DIV_ROUND_UP(nsec, 1000L) void ir_raw_event_handle(struct rc_dev *dev); int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);