diff options
Diffstat (limited to 'drivers/media/rc')
54 files changed, 2795 insertions, 768 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 629e8ca15ab3..d1d3fd00ed89 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -235,6 +235,17 @@ config IR_MESON To compile this driver as a module, choose M here: the module will be called meson-ir. +config IR_MTK + tristate "Mediatek IR remote receiver" + depends on RC_CORE + depends on ARCH_MEDIATEK || COMPILE_TEST + ---help--- + Say Y if you want to use the IR remote receiver available + on Mediatek SoCs. + + To compile this driver as a module, choose M here: the + module will be called mtk-cir. + config IR_NUVOTON tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" depends on PNP @@ -261,6 +272,15 @@ config IR_REDRAT3 To compile this driver as a module, choose M here: the module will be called redrat3. +config IR_SPI + tristate "SPI connected IR LED" + depends on SPI && LIRC + ---help--- + Say Y if you want to use an IR LED connected through SPI bus. + + To compile this driver as a module, choose M here: the module will be + called ir-spi. + config IR_STREAMZAP tristate "Streamzap PC Remote IR Receiver" depends on USB_ARCH_HAS_HCD @@ -336,7 +356,7 @@ config IR_TTUSBIR config IR_RX51 tristate "Nokia N900 IR transmitter diode" - depends on OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS && LIRC + depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE ---help--- Say Y or M here if you want to enable support for the IR transmitter diode built in the Nokia N900 (RX51) device. diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 3a984ee301e2..679aa0af85cd 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o obj-$(CONFIG_IR_ENE) += ene_ir.o obj-$(CONFIG_IR_REDRAT3) += redrat3.o obj-$(CONFIG_IR_RX51) += ir-rx51.o +obj-$(CONFIG_IR_SPI) += ir-spi.o obj-$(CONFIG_IR_STREAMZAP) += streamzap.o obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o @@ -38,3 +39,4 @@ obj-$(CONFIG_RC_ST) += st_rc.o obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o obj-$(CONFIG_IR_IMG) += img-ir/ obj-$(CONFIG_IR_SERIAL) += serial_ir.o +obj-$(CONFIG_IR_MTK) += mtk-cir.o diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 0884b7dc0e71..9cf3e69de16a 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -36,10 +36,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Hardware & software notes @@ -764,7 +760,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) struct rc_dev *rdev = ati_remote->rdev; rdev->priv = ati_remote; - rdev->driver_type = RC_DRIVER_SCANCODE; rdev->allowed_protocols = RC_BIT_OTHER; rdev->driver_name = "ati_remote"; @@ -851,7 +846,7 @@ static int ati_remote_probe(struct usb_interface *interface, } ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); - rc_dev = rc_allocate_device(); + rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE); if (!ati_remote || !rc_dev) goto exit_free_dev_rdev; diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index bd5512e64aea..60da963f40dc 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -13,11 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * * Special thanks to: * Sami R. <maesesami@gmail.com> for lot of help in debugging and therefore * bringing to life support for transmission & learning mode. @@ -1012,7 +1007,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* allocate memory */ dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); - rdev = rc_allocate_device(); + rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!dev || !rdev) goto exit_free_dev_rdev; @@ -1058,8 +1053,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (!dev->hw_learning_and_tx_capable) learning_mode_force = false; - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protocols = RC_BIT_ALL; + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; rdev->priv = dev; rdev->open = ene_open; rdev->close = ene_close; diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h index a7911e3b9bc0..494646b2a284 100644 --- a/drivers/media/rc/ene_ir.h +++ b/drivers/media/rc/ene_ir.h @@ -12,11 +12,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include <linux/spinlock.h> diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index ecab69ea3d51..0d3562712f27 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -16,11 +16,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -492,7 +487,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id return ret; /* input device for IR remote (and tx) */ - rdev = rc_allocate_device(); + rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rdev) goto exit_free_dev_rdev; @@ -534,8 +529,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* Set up the rc device */ rdev->priv = fintek; - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protocols = RC_BIT_ALL; + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; rdev->open = fintek_open; rdev->close = fintek_close; rdev->input_name = FINTEK_DESCRIPTION; diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h index b698f3d2ced9..ac34a774d018 100644 --- a/drivers/media/rc/fintek-cir.h +++ b/drivers/media/rc/fintek-cir.h @@ -16,11 +16,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include <linux/spinlock.h> diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 5b63b1f15cb1..4a4895e4d599 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -143,14 +143,13 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) if (!gpio_dev) return -ENOMEM; - rcdev = rc_allocate_device(); + rcdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rcdev) { rc = -ENOMEM; goto err_allocate_device; } rcdev->priv = gpio_dev; - rcdev->driver_type = RC_DRIVER_IR_RAW; rcdev->input_name = GPIO_IR_DEVICE_NAME; rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0"; rcdev->input_id.bustype = BUS_HOST; @@ -165,7 +164,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) if (pdata->allowed_protos) rcdev->allowed_protocols = pdata->allowed_protos; else - rcdev->allowed_protocols = RC_BIT_ALL; + rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY; gpio_dev->rcdev = rcdev; diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index 5cf983be07a2..0f0ed4ea4d06 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -190,7 +190,7 @@ static int igorplugusb_probe(struct usb_interface *intf, usb_make_path(udev, ir->phys, sizeof(ir->phys)); - rc = rc_allocate_device(); + rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rc) goto fail; @@ -198,13 +198,12 @@ static int igorplugusb_probe(struct usb_interface *intf, rc->input_phys = ir->phys; usb_to_input_id(udev, &rc->input_id); rc->dev.parent = &intf->dev; - rc->driver_type = RC_DRIVER_IR_RAW; /* * This device can only store 36 pulses + spaces, which is not enough * for the NEC protocol and many others. */ - rc->allowed_protocols = RC_BIT_ALL & ~(RC_BIT_NEC | RC_BIT_NECX | - RC_BIT_NEC32 | RC_BIT_RC6_6A_20 | + rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC | + RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO); diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 5f634545ddd8..ccf24fd7ec1b 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/device.h> @@ -431,7 +427,7 @@ static int iguanair_probe(struct usb_interface *intf, struct usb_host_interface *idesc; ir = kzalloc(sizeof(*ir), GFP_KERNEL); - rc = rc_allocate_device(); + rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!ir || !rc) { ret = -ENOMEM; goto out; @@ -494,8 +490,7 @@ static int iguanair_probe(struct usb_interface *intf, rc->input_phys = ir->phys; usb_to_input_id(ir->udev, &rc->input_id); rc->dev.parent = &intf->dev; - rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protocols = RC_BIT_ALL; + rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; rc->priv = ir; rc->open = iguanair_open; rc->close = iguanair_close; @@ -504,7 +499,9 @@ static int iguanair_probe(struct usb_interface *intf, rc->tx_ir = iguanair_tx; rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_RC6_MCE; - rc->timeout = MS_TO_NS(100); + rc->min_timeout = 1; + rc->timeout = IR_DEFAULT_TIMEOUT; + rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; rc->rx_resolution = RX_RESOLUTION; iguanair_set_tx_carrier(rc, 38000); diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 7bb71bc9f534..431d33b36fb0 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -488,7 +488,15 @@ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type, /* convert scancode filter to raw filter */ filter.minlen = 0; filter.maxlen = ~0; - ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols); + if (type == RC_FILTER_NORMAL) { + /* guess scancode from protocol */ + ret = hw->decoder->filter(sc_filter, &filter, + dev->enabled_protocols); + } else { + /* for wakeup user provided exact protocol variant */ + ret = hw->decoder->filter(sc_filter, &filter, + 1ULL << dev->wakeup_protocol); + } if (ret) goto unlock; dev_dbg(priv->dev, "IR raw %sfilter=%016llx & %016llx\n", @@ -581,6 +589,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, /* clear the wakeup scancode filter */ rdev->scancode_wakeup_filter.data = 0; rdev->scancode_wakeup_filter.mask = 0; + rdev->wakeup_protocol = RC_TYPE_UNKNOWN; /* clear raw filters */ _img_ir_set_filter(priv, NULL); @@ -685,7 +694,6 @@ success: if (!hw->decoder || !hw->decoder->filter) wakeup_protocols = 0; rdev->allowed_wakeup_protocols = wakeup_protocols; - rdev->enabled_wakeup_protocols = wakeup_protocols; return 0; } @@ -701,7 +709,6 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto) mutex_lock(&rdev->lock); rdev->enabled_protocols = proto; rdev->allowed_wakeup_protocols = proto; - rdev->enabled_wakeup_protocols = proto; mutex_unlock(&rdev->lock); } @@ -1071,7 +1078,7 @@ int img_ir_probe_hw(struct img_ir_priv *priv) } /* Allocate hardware decoder */ - hw->rdev = rdev = rc_allocate_device(); + hw->rdev = rdev = rc_allocate_device(RC_DRIVER_SCANCODE); if (!rdev) { dev_err(priv->dev, "cannot allocate input device\n"); error = -ENOMEM; diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c index 09314933ea08..044fd42b22a0 100644 --- a/drivers/media/rc/img-ir/img-ir-nec.c +++ b/drivers/media/rc/img-ir/img-ir-nec.c @@ -11,6 +11,7 @@ #include "img-ir-hw.h" #include <linux/bitrev.h> +#include <linux/log2.h> /* Convert NEC data to a scancode */ static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols, @@ -62,7 +63,23 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in, data = in->data & 0xff; data_m = in->mask & 0xff; - if ((in->data | in->mask) & 0xff000000) { + protocols &= RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; + + /* + * If only one bit is set, we were requested to do an exact + * protocol. This should be the case for wakeup filters; for + * normal filters, guess the protocol from the scancode. + */ + if (!is_power_of_2(protocols)) { + if ((in->data | in->mask) & 0xff000000) + protocols = RC_BIT_NEC32; + else if ((in->data | in->mask) & 0x00ff0000) + protocols = RC_BIT_NECX; + else + protocols = RC_BIT_NEC; + } + + if (protocols == RC_BIT_NEC32) { /* 32-bit NEC (used by Apple and TiVo remotes) */ /* scan encoding: as transmitted, MSBit = first received bit */ addr = bitrev8(in->data >> 24); @@ -73,7 +90,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in, data_m = bitrev8(in->mask >> 8); data_inv = bitrev8(in->data >> 0); data_inv_m = bitrev8(in->mask >> 0); - } else if ((in->data | in->mask) & 0x00ff0000) { + } else if (protocols == RC_BIT_NECX) { /* Extended NEC */ /* scan encoding AAaaDD */ addr = (in->data >> 16) & 0xff; diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c index 33f37ed87ad2..8d2f8e2006e7 100644 --- a/drivers/media/rc/img-ir/img-ir-raw.c +++ b/drivers/media/rc/img-ir/img-ir-raw.c @@ -110,7 +110,7 @@ int img_ir_probe_raw(struct img_ir_priv *priv) setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv); /* Allocate raw decoder */ - raw->rdev = rdev = rc_allocate_device(); + raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rdev) { dev_err(priv->dev, "cannot allocate raw input device\n"); return -ENOMEM; @@ -118,7 +118,6 @@ int img_ir_probe_raw(struct img_ir_priv *priv) rdev->priv = priv; rdev->map_name = RC_MAP_EMPTY; rdev->input_name = "IMG Infrared Decoder Raw"; - rdev->driver_type = RC_DRIVER_IR_RAW; /* Register raw decoder */ error = rc_register_device(rdev); diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c index 7f7375f82ed6..3fcba271a419 100644 --- a/drivers/media/rc/img-ir/img-ir-sony.c +++ b/drivers/media/rc/img-ir/img-ir-sony.c @@ -68,19 +68,29 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in, func = (in->data >> 0) & 0x7f; func_m = (in->mask >> 0) & 0x7f; - if (subdev & subdev_m) { + protocols &= RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20; + + /* + * If only one bit is set, we were requested to do an exact + * protocol. This should be the case for wakeup filters; for + * normal filters, guess the protocol from the scancode. + */ + if (!is_power_of_2(protocols)) { + if (subdev & subdev_m) + protocols = RC_BIT_SONY20; + else if (dev & dev_m & 0xe0) + protocols = RC_BIT_SONY15; + else + protocols = RC_BIT_SONY12; + } + + if (protocols == RC_BIT_SONY20) { /* can't encode subdev and higher device bits */ if (dev & dev_m & 0xe0) return -EINVAL; - /* subdevice (extended) bits only in 20 bit encoding */ - if (!(protocols & RC_BIT_SONY20)) - return -EINVAL; len = 20; dev_m &= 0x1f; - } else if (dev & dev_m & 0xe0) { - /* upper device bits only in 15 bit encoding */ - if (!(protocols & RC_BIT_SONY15)) - return -EINVAL; + } else if (protocols == RC_BIT_SONY15) { len = 15; subdev_m = 0; } else { diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 0785a24af8fc..89823d24a384 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -20,10 +20,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ @@ -96,6 +92,7 @@ struct imon_usb_dev_descr { __u16 flags; #define IMON_NO_FLAGS 0 #define IMON_NEED_20MS_PKT_DELAY 1 +#define IMON_IR_RAW 2 struct imon_panel_key_table key_table[]; }; @@ -126,6 +123,12 @@ struct imon_context { unsigned char usb_tx_buf[8]; unsigned int send_packet_delay; + struct rx_data { + int count; /* length of 0 or 1 sequence */ + int prev_bit; /* logic level of sequence */ + int initial_space; /* initial space flag */ + } rx; + struct tx_t { unsigned char data_buf[35]; /* user data buffer */ struct completion finished; /* wait for write to finish */ @@ -328,6 +331,10 @@ static const struct imon_usb_dev_descr imon_DH102 = { } }; +static const struct imon_usb_dev_descr imon_ir_raw = { + .flags = IMON_IR_RAW, +}; + /* * USB Device ID for iMON USB Control Boards * @@ -411,6 +418,18 @@ static struct usb_device_id imon_usb_id_table[] = { /* device specifics unknown */ { USB_DEVICE(0x15c2, 0x0046), .driver_info = (unsigned long)&imon_default_table}, + /* TriGem iMON (IR only) -- TG_iMON.inf */ + { USB_DEVICE(0x0aa8, 0x8001), + .driver_info = (unsigned long)&imon_ir_raw}, + /* SoundGraph iMON (IR only) -- sg_imon.inf */ + { USB_DEVICE(0x04e8, 0xff30), + .driver_info = (unsigned long)&imon_ir_raw}, + /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ + { USB_DEVICE(0x0aa8, 0xffda), + .driver_info = (unsigned long)&imon_ir_raw}, + /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ + { USB_DEVICE(0x15c2, 0xffda), + .driver_info = (unsigned long)&imon_ir_raw}, {} }; @@ -1577,11 +1596,94 @@ static int imon_parse_press_type(struct imon_context *ictx, /** * Process the incoming packet */ -static void imon_incoming_packet(struct imon_context *ictx, +/** + * Convert bit count to time duration (in us) and submit + * the value to lirc_dev. + */ +static void submit_data(struct imon_context *context) +{ + DEFINE_IR_RAW_EVENT(ev); + + ev.pulse = context->rx.prev_bit; + ev.duration = US_TO_NS(context->rx.count * BIT_DURATION); + ir_raw_event_store_with_filter(context->rdev, &ev); +} + +/** + * Process the incoming packet + */ +static void imon_incoming_ir_raw(struct imon_context *context, struct urb *urb, int intf) { int len = urb->actual_length; unsigned char *buf = urb->transfer_buffer; + struct device *dev = context->dev; + int octet, bit; + unsigned char mask; + + if (len != 8) { + dev_warn(dev, "imon %s: invalid incoming packet size (len = %d, intf%d)\n", + __func__, len, intf); + return; + } + + if (debug) + dev_info(dev, "raw packet: %*ph\n", len, buf); + /* + * Translate received data to pulse and space lengths. + * Received data is active low, i.e. pulses are 0 and + * spaces are 1. + * + * My original algorithm was essentially similar to + * Changwoo Ryu's with the exception that he switched + * the incoming bits to active high and also fed an + * initial space to LIRC at the start of a new sequence + * if the previous bit was a pulse. + * + * I've decided to adopt his algorithm. + */ + + if (buf[7] == 1 && context->rx.initial_space) { + /* LIRC requires a leading space */ + context->rx.prev_bit = 0; + context->rx.count = 4; + submit_data(context); + context->rx.count = 0; + } + + for (octet = 0; octet < 5; ++octet) { + mask = 0x80; + for (bit = 0; bit < 8; ++bit) { + int curr_bit = !(buf[octet] & mask); + + if (curr_bit != context->rx.prev_bit) { + if (context->rx.count) { + submit_data(context); + context->rx.count = 0; + } + context->rx.prev_bit = curr_bit; + } + ++context->rx.count; + mask >>= 1; + } + } + + if (buf[7] == 10) { + if (context->rx.count) { + submit_data(context); + context->rx.count = 0; + } + context->rx.initial_space = context->rx.prev_bit; + } + + ir_raw_event_handle(context->rdev); +} + +static void imon_incoming_scancode(struct imon_context *ictx, + struct urb *urb, int intf) +{ + int len = urb->actual_length; + unsigned char *buf = urb->transfer_buffer; struct device *dev = ictx->dev; unsigned long flags; u32 kc; @@ -1761,7 +1863,10 @@ static void usb_rx_callback_intf0(struct urb *urb) break; case 0: - imon_incoming_packet(ictx, urb, intfnum); + if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW) + imon_incoming_ir_raw(ictx, urb, intfnum); + else + imon_incoming_scancode(ictx, urb, intfnum); break; default: @@ -1802,7 +1907,10 @@ static void usb_rx_callback_intf1(struct urb *urb) break; case 0: - imon_incoming_packet(ictx, urb, intfnum); + if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW) + imon_incoming_ir_raw(ictx, urb, intfnum); + else + imon_incoming_scancode(ictx, urb, intfnum); break; default: @@ -1910,11 +2018,14 @@ static void imon_set_display_type(struct imon_context *ictx) case 0x0041: case 0x0042: case 0x0043: + case 0x8001: + case 0xff30: configured_display_type = IMON_DISPLAY_TYPE_NONE; ictx->display_supported = false; break; case 0x0036: case 0x0044: + case 0xffda: default: configured_display_type = IMON_DISPLAY_TYPE_VFD; break; @@ -1939,7 +2050,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88 }; - rdev = rc_allocate_device(); + rdev = rc_allocate_device(ictx->dev_descr->flags & IMON_IR_RAW ? + RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE); if (!rdev) { dev_err(ictx->dev, "remote control dev allocation failed\n"); goto out; @@ -1957,8 +2069,11 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->dev.parent = ictx->dev; rdev->priv = ictx; - rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */ + if (ictx->dev_descr->flags & IMON_IR_RAW) + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + else + /* iMON PAD or MCE */ + rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -1976,7 +2091,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) imon_set_display_type(ictx); - if (ictx->rc_type == RC_BIT_RC6_MCE) + if (ictx->rc_type == RC_BIT_RC6_MCE || + ictx->dev_descr->flags & IMON_IR_RAW) rdev->map_name = RC_MAP_IMON_MCE; else rdev->map_name = RC_MAP_IMON_PAD; diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index d26907e684dc..50951f686852 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -229,7 +229,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) return priv->irq; } - rdev = rc_allocate_device(); + rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rdev) return -ENOMEM; @@ -242,8 +242,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) clk_prepare_enable(priv->clock); priv->rate = clk_get_rate(priv->clock); - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protocols = RC_BIT_ALL; + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; rdev->priv = priv; rdev->open = hix5hd2_ir_open; rdev->close = hix5hd2_ir_close; diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 182402f7b4d1..674bf156edcb 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -170,9 +170,48 @@ out: return -EINVAL; } +static const struct ir_raw_timings_pd ir_jvc_timings = { + .header_pulse = JVC_HEADER_PULSE, + .header_space = JVC_HEADER_SPACE, + .bit_pulse = JVC_BIT_PULSE, + .bit_space[0] = JVC_BIT_0_SPACE, + .bit_space[1] = JVC_BIT_1_SPACE, + .trailer_pulse = JVC_TRAILER_PULSE, + .trailer_space = JVC_TRAILER_SPACE, + .msb_first = 1, +}; + +/** + * ir_jvc_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_jvc_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int ret; + u32 raw = (bitrev8((scancode >> 8) & 0xff) << 8) | + (bitrev8((scancode >> 0) & 0xff) << 0); + + ret = ir_raw_gen_pd(&e, max, &ir_jvc_timings, JVC_NBITS, raw); + if (ret < 0) + return ret; + + return e - events; +} + static struct ir_raw_handler jvc_handler = { .protocols = RC_BIT_JVC, .decode = ir_jvc_decode, + .encode = ir_jvc_encode, }; static int __init ir_jvc_decode_init(void) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index c3277308a70b..8517d5153fcf 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -204,11 +204,17 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, /* legacy support */ case LIRC_GET_SEND_MODE: - val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; + if (!dev->tx_ir) + return -ENOTTY; + + val = LIRC_MODE_PULSE; break; case LIRC_SET_SEND_MODE: - if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) + if (!dev->tx_ir) + return -ENOTTY; + + if (val != LIRC_MODE_PULSE) return -EINVAL; return 0; @@ -273,7 +279,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, case LIRC_GET_MIN_TIMEOUT: if (!dev->max_timeout) return -ENOSYS; - val = dev->min_timeout / 1000; + val = DIV_ROUND_UP(dev->min_timeout, 1000); break; case LIRC_GET_MAX_TIMEOUT: @@ -341,7 +347,7 @@ static int ir_lirc_register(struct rc_dev *dev) struct lirc_driver *drv; struct lirc_buffer *rbuf; int rc = -ENOMEM; - unsigned long features; + unsigned long features = 0; drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); if (!drv) @@ -355,7 +361,8 @@ static int ir_lirc_register(struct rc_dev *dev) if (rc) goto rbuf_init_failed; - features = LIRC_CAN_REC_MODE2; + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) + features |= LIRC_CAN_REC_MODE2; if (dev->tx_ir) { features |= LIRC_CAN_SEND_PULSE; if (dev->s_tx_mask) diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index d80986251ee0..5226d510e847 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -71,7 +71,7 @@ static unsigned char kbd_keycodes[256] = { KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, - KEY_RESERVED, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, + KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 2a9d155548ab..3ce850314dca 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -170,7 +170,10 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) if (send_32bits) { /* NEC transport, but modified protocol, used by at * least Apple and TiVo remotes */ - scancode = data->bits; + scancode = not_address << 24 | + address << 16 | + not_command << 8 | + command; IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); rc_type = RC_TYPE_NEC32; } else if ((address ^ not_address) != 0xff) { @@ -201,9 +204,90 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) return -EINVAL; } +/** + * ir_nec_scancode_to_raw() - encode an NEC scancode ready for modulation. + * @protocol: specific protocol to use + * @scancode: a single NEC scancode. + * @raw: raw data to be modulated. + */ +static u32 ir_nec_scancode_to_raw(enum rc_type protocol, u32 scancode) +{ + unsigned int addr, addr_inv, data, data_inv; + + data = scancode & 0xff; + + if (protocol == RC_TYPE_NEC32) { + /* 32-bit NEC (used by Apple and TiVo remotes) */ + /* scan encoding: aaAAddDD */ + addr_inv = (scancode >> 24) & 0xff; + addr = (scancode >> 16) & 0xff; + data_inv = (scancode >> 8) & 0xff; + } else if (protocol == RC_TYPE_NECX) { + /* Extended NEC */ + /* scan encoding AAaaDD */ + addr = (scancode >> 16) & 0xff; + addr_inv = (scancode >> 8) & 0xff; + data_inv = data ^ 0xff; + } else { + /* Normal NEC */ + /* scan encoding: AADD */ + addr = (scancode >> 8) & 0xff; + addr_inv = addr ^ 0xff; + data_inv = data ^ 0xff; + } + + /* raw encoding: ddDDaaAA */ + return data_inv << 24 | + data << 16 | + addr_inv << 8 | + addr; +} + +static const struct ir_raw_timings_pd ir_nec_timings = { + .header_pulse = NEC_HEADER_PULSE, + .header_space = NEC_HEADER_SPACE, + .bit_pulse = NEC_BIT_PULSE, + .bit_space[0] = NEC_BIT_0_SPACE, + .bit_space[1] = NEC_BIT_1_SPACE, + .trailer_pulse = NEC_TRAILER_PULSE, + .trailer_space = NEC_TRAILER_SPACE, + .msb_first = 0, +}; + +/** + * ir_nec_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_nec_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int ret; + u32 raw; + + /* Convert a NEC scancode to raw NEC data */ + raw = ir_nec_scancode_to_raw(protocol, scancode); + + /* Modulate the raw data using a pulse distance modulation */ + ret = ir_raw_gen_pd(&e, max, &ir_nec_timings, NEC_NBITS, raw); + if (ret < 0) + return ret; + + return e - events; +} + static struct ir_raw_handler nec_handler = { .protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32, .decode = ir_nec_decode, + .encode = ir_nec_encode, }; static int __init ir_nec_decode_init(void) diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index a0fd4e6b2155..fcfedf95def7 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -124,7 +124,7 @@ again: if (data->is_rc5x && data->count == RC5X_NBITS) { /* RC5X */ u8 xdata, command, system; - if (!(dev->enabled_protocols & RC_BIT_RC5X)) { + if (!(dev->enabled_protocols & RC_BIT_RC5X_20)) { data->state = STATE_INACTIVE; return 0; } @@ -132,9 +132,9 @@ again: command = (data->bits & 0x00FC0) >> 6; system = (data->bits & 0x1F000) >> 12; toggle = (data->bits & 0x20000) ? 1 : 0; - command += (data->bits & 0x01000) ? 0 : 0x40; + command += (data->bits & 0x40000) ? 0 : 0x40; scancode = system << 16 | command << 8 | xdata; - protocol = RC_TYPE_RC5X; + protocol = RC_TYPE_RC5X_20; } else if (!data->is_rc5x && data->count == RC5_NBITS) { /* RC5 */ @@ -181,9 +181,106 @@ out: return -EINVAL; } +static const struct ir_raw_timings_manchester ir_rc5_timings = { + .leader = RC5_UNIT, + .pulse_space_start = 0, + .clock = RC5_UNIT, + .trailer_space = RC5_UNIT * 10, +}; + +static const struct ir_raw_timings_manchester ir_rc5x_timings[2] = { + { + .leader = RC5_UNIT, + .pulse_space_start = 0, + .clock = RC5_UNIT, + .trailer_space = RC5X_SPACE, + }, + { + .clock = RC5_UNIT, + .trailer_space = RC5_UNIT * 10, + }, +}; + +static const struct ir_raw_timings_manchester ir_rc5_sz_timings = { + .leader = RC5_UNIT, + .pulse_space_start = 0, + .clock = RC5_UNIT, + .trailer_space = RC5_UNIT * 10, +}; + +/** + * ir_rc5_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol variant to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + * -EINVAL if the scancode is ambiguous or invalid. + */ +static int ir_rc5_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + int ret; + struct ir_raw_event *e = events; + unsigned int data, xdata, command, commandx, system, pre_space_data; + + /* Detect protocol and convert scancode to raw data */ + if (protocol == RC_TYPE_RC5) { + /* decode scancode */ + command = (scancode & 0x003f) >> 0; + commandx = (scancode & 0x0040) >> 6; + system = (scancode & 0x1f00) >> 8; + /* encode data */ + data = !commandx << 12 | system << 6 | command; + + /* Modulate the data */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings, + RC5_NBITS, data); + if (ret < 0) + return ret; + } else if (protocol == RC_TYPE_RC5X_20) { + /* decode scancode */ + xdata = (scancode & 0x00003f) >> 0; + command = (scancode & 0x003f00) >> 8; + commandx = !(scancode & 0x004000); + system = (scancode & 0x1f0000) >> 16; + + /* encode data */ + data = commandx << 18 | system << 12 | command << 6 | xdata; + + /* Modulate the data */ + pre_space_data = data >> (RC5X_NBITS - CHECK_RC5X_NBITS); + ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0], + CHECK_RC5X_NBITS, pre_space_data); + if (ret < 0) + return ret; + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc5x_timings[1], + RC5X_NBITS - CHECK_RC5X_NBITS, + data); + if (ret < 0) + return ret; + } else if (protocol == RC_TYPE_RC5_SZ) { + /* RC5-SZ scancode is raw enough for Manchester as it is */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings, + RC5_SZ_NBITS, scancode & 0x2fff); + if (ret < 0) + return ret; + } else { + return -EINVAL; + } + + return e - events; +} + static struct ir_raw_handler rc5_handler = { - .protocols = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ, + .protocols = RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ, .decode = ir_rc5_decode, + .encode = ir_rc5_encode, }; static int __init ir_rc5_decode_init(void) diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 5cc54c967a80..6fe2268dada0 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -286,11 +286,128 @@ out: return -EINVAL; } +static const struct ir_raw_timings_manchester ir_rc6_timings[4] = { + { + .leader = RC6_PREFIX_PULSE, + .pulse_space_start = 0, + .clock = RC6_UNIT, + .invert = 1, + .trailer_space = RC6_PREFIX_SPACE, + }, + { + .clock = RC6_UNIT, + .invert = 1, + }, + { + .clock = RC6_UNIT * 2, + .invert = 1, + }, + { + .clock = RC6_UNIT, + .invert = 1, + .trailer_space = RC6_SUFFIX_SPACE, + }, +}; + +/** + * ir_rc6_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + * -EINVAL if the scancode is ambiguous or invalid. + */ +static int ir_rc6_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + int ret; + struct ir_raw_event *e = events; + + if (protocol == RC_TYPE_RC6_0) { + /* Modulate the preamble */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0); + if (ret < 0) + return ret; + + /* Modulate the header (Start Bit & Mode-0) */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[1], + RC6_HEADER_NBITS, (1 << 3)); + if (ret < 0) + return ret; + + /* Modulate Trailer Bit */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[2], 1, 0); + if (ret < 0) + return ret; + + /* Modulate rest of the data */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[3], RC6_0_NBITS, + scancode); + if (ret < 0) + return ret; + + } else { + int bits; + + switch (protocol) { + case RC_TYPE_RC6_MCE: + case RC_TYPE_RC6_6A_32: + bits = 32; + break; + case RC_TYPE_RC6_6A_24: + bits = 24; + break; + case RC_TYPE_RC6_6A_20: + bits = 20; + break; + default: + return -EINVAL; + } + + /* Modulate the preamble */ + ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0); + if (ret < 0) + return ret; + + /* Modulate the header (Start Bit & Header-version 6 */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[1], + RC6_HEADER_NBITS, (1 << 3 | 6)); + if (ret < 0) + return ret; + + /* Modulate Trailer Bit */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[2], 1, 0); + if (ret < 0) + return ret; + + /* Modulate rest of the data */ + ret = ir_raw_gen_manchester(&e, max - (e - events), + &ir_rc6_timings[3], + bits, + scancode); + if (ret < 0) + return ret; + } + + return e - events; +} + static struct ir_raw_handler rc6_handler = { .protocols = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE, .decode = ir_rc6_decode, + .encode = ir_rc6_encode, }; static int __init ir_rc6_decode_init(void) diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index e6efa8c267a0..49265f02e772 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -15,32 +15,23 @@ */ #include <linux/clk.h> #include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/uaccess.h> #include <linux/platform_device.h> -#include <linux/sched.h> #include <linux/wait.h> #include <linux/pwm.h> #include <linux/of.h> #include <linux/hrtimer.h> -#include <media/lirc.h> -#include <media/lirc_dev.h> +#include <media/rc-core.h> #include <linux/platform_data/media/ir-rx51.h> -#define LIRC_RX51_DRIVER_FEATURES (LIRC_CAN_SET_SEND_DUTY_CYCLE | \ - LIRC_CAN_SET_SEND_CARRIER | \ - LIRC_CAN_SEND_PULSE) - -#define DRIVER_NAME "lirc_rx51" - #define WBUF_LEN 256 -struct lirc_rx51 { +struct ir_rx51 { + struct rc_dev *rcdev; struct pwm_device *pwm; struct hrtimer timer; struct device *dev; - struct lirc_rx51_platform_data *pdata; + struct ir_rx51_platform_data *pdata; wait_queue_head_t wqueue; unsigned int freq; /* carrier frequency */ @@ -50,38 +41,37 @@ struct lirc_rx51 { unsigned long device_is_open; }; -static inline void lirc_rx51_on(struct lirc_rx51 *lirc_rx51) +static inline void ir_rx51_on(struct ir_rx51 *ir_rx51) { - pwm_enable(lirc_rx51->pwm); + pwm_enable(ir_rx51->pwm); } -static inline void lirc_rx51_off(struct lirc_rx51 *lirc_rx51) +static inline void ir_rx51_off(struct ir_rx51 *ir_rx51) { - pwm_disable(lirc_rx51->pwm); + pwm_disable(ir_rx51->pwm); } -static int init_timing_params(struct lirc_rx51 *lirc_rx51) +static int init_timing_params(struct ir_rx51 *ir_rx51) { - struct pwm_device *pwm = lirc_rx51->pwm; - int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, lirc_rx51->freq); + struct pwm_device *pwm = ir_rx51->pwm; + int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, ir_rx51->freq); - duty = DIV_ROUND_CLOSEST(lirc_rx51->duty_cycle * period, 100); + duty = DIV_ROUND_CLOSEST(ir_rx51->duty_cycle * period, 100); pwm_config(pwm, duty, period); return 0; } -static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer) +static enum hrtimer_restart ir_rx51_timer_cb(struct hrtimer *timer) { - struct lirc_rx51 *lirc_rx51 = - container_of(timer, struct lirc_rx51, timer); + struct ir_rx51 *ir_rx51 = container_of(timer, struct ir_rx51, timer); ktime_t now; - if (lirc_rx51->wbuf_index < 0) { - dev_err_ratelimited(lirc_rx51->dev, - "BUG wbuf_index has value of %i\n", - lirc_rx51->wbuf_index); + if (ir_rx51->wbuf_index < 0) { + dev_err_ratelimited(ir_rx51->dev, + "BUG wbuf_index has value of %i\n", + ir_rx51->wbuf_index); goto end; } @@ -92,20 +82,20 @@ static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer) do { u64 ns; - if (lirc_rx51->wbuf_index >= WBUF_LEN) + if (ir_rx51->wbuf_index >= WBUF_LEN) goto end; - if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1) + if (ir_rx51->wbuf[ir_rx51->wbuf_index] == -1) goto end; - if (lirc_rx51->wbuf_index % 2) - lirc_rx51_off(lirc_rx51); + if (ir_rx51->wbuf_index % 2) + ir_rx51_off(ir_rx51); else - lirc_rx51_on(lirc_rx51); + ir_rx51_on(ir_rx51); - ns = 1000 * lirc_rx51->wbuf[lirc_rx51->wbuf_index]; + ns = US_TO_NS(ir_rx51->wbuf[ir_rx51->wbuf_index]); hrtimer_add_expires_ns(timer, ns); - lirc_rx51->wbuf_index++; + ir_rx51->wbuf_index++; now = timer->base->get_time(); @@ -114,203 +104,112 @@ static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer) return HRTIMER_RESTART; end: /* Stop TX here */ - lirc_rx51_off(lirc_rx51); - lirc_rx51->wbuf_index = -1; + ir_rx51_off(ir_rx51); + ir_rx51->wbuf_index = -1; - wake_up_interruptible(&lirc_rx51->wqueue); + wake_up_interruptible(&ir_rx51->wqueue); return HRTIMER_NORESTART; } -static ssize_t lirc_rx51_write(struct file *file, const char *buf, - size_t n, loff_t *ppos) +static int ir_rx51_tx(struct rc_dev *dev, unsigned int *buffer, + unsigned int count) { - int count, i; - struct lirc_rx51 *lirc_rx51 = file->private_data; + struct ir_rx51 *ir_rx51 = dev->priv; - if (n % sizeof(int)) + if (count > WBUF_LEN) return -EINVAL; - count = n / sizeof(int); - if ((count > WBUF_LEN) || (count % 2 == 0)) - return -EINVAL; + memcpy(ir_rx51->wbuf, buffer, count * sizeof(unsigned int)); /* Wait any pending transfers to finish */ - wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0); - - if (copy_from_user(lirc_rx51->wbuf, buf, n)) - return -EFAULT; - - /* Sanity check the input pulses */ - for (i = 0; i < count; i++) - if (lirc_rx51->wbuf[i] < 0) - return -EINVAL; + wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0); - init_timing_params(lirc_rx51); + init_timing_params(ir_rx51); if (count < WBUF_LEN) - lirc_rx51->wbuf[count] = -1; /* Insert termination mark */ + ir_rx51->wbuf[count] = -1; /* Insert termination mark */ /* * Adjust latency requirements so the device doesn't go in too * deep sleep states */ - lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, 50); + ir_rx51->pdata->set_max_mpu_wakeup_lat(ir_rx51->dev, 50); - lirc_rx51_on(lirc_rx51); - lirc_rx51->wbuf_index = 1; - hrtimer_start(&lirc_rx51->timer, - ns_to_ktime(1000 * lirc_rx51->wbuf[0]), + ir_rx51_on(ir_rx51); + ir_rx51->wbuf_index = 1; + hrtimer_start(&ir_rx51->timer, + ns_to_ktime(US_TO_NS(ir_rx51->wbuf[0])), HRTIMER_MODE_REL); /* * Don't return back to the userspace until the transfer has * finished */ - wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0); + wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0); /* We can sleep again */ - lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, -1); + ir_rx51->pdata->set_max_mpu_wakeup_lat(ir_rx51->dev, -1); - return n; + return count; } -static long lirc_rx51_ioctl(struct file *filep, - unsigned int cmd, unsigned long arg) +static int ir_rx51_open(struct rc_dev *dev) { - int result; - unsigned long value; - unsigned int ivalue; - struct lirc_rx51 *lirc_rx51 = filep->private_data; - - switch (cmd) { - case LIRC_GET_SEND_MODE: - result = put_user(LIRC_MODE_PULSE, (unsigned long *)arg); - if (result) - return result; - break; - - case LIRC_SET_SEND_MODE: - result = get_user(value, (unsigned long *)arg); - if (result) - return result; - - /* only LIRC_MODE_PULSE supported */ - if (value != LIRC_MODE_PULSE) - return -ENOSYS; - break; - - case LIRC_GET_REC_MODE: - result = put_user(0, (unsigned long *) arg); - if (result) - return result; - break; - - case LIRC_GET_LENGTH: - return -ENOSYS; - break; - - case LIRC_SET_SEND_DUTY_CYCLE: - result = get_user(ivalue, (unsigned int *) arg); - if (result) - return result; - - if (ivalue <= 0 || ivalue > 100) { - dev_err(lirc_rx51->dev, ": invalid duty cycle %d\n", - ivalue); - return -EINVAL; - } - - lirc_rx51->duty_cycle = ivalue; - break; - - case LIRC_SET_SEND_CARRIER: - result = get_user(ivalue, (unsigned int *) arg); - if (result) - return result; - - if (ivalue > 500000 || ivalue < 20000) { - dev_err(lirc_rx51->dev, ": invalid carrier freq %d\n", - ivalue); - return -EINVAL; - } - - lirc_rx51->freq = ivalue; - break; - - case LIRC_GET_FEATURES: - result = put_user(LIRC_RX51_DRIVER_FEATURES, - (unsigned long *) arg); - if (result) - return result; - break; - - default: - return -ENOIOCTLCMD; - } - - return 0; -} + struct ir_rx51 *ir_rx51 = dev->priv; -static int lirc_rx51_open(struct inode *inode, struct file *file) -{ - struct lirc_rx51 *lirc_rx51 = lirc_get_pdata(file); - BUG_ON(!lirc_rx51); - - file->private_data = lirc_rx51; - - if (test_and_set_bit(1, &lirc_rx51->device_is_open)) + if (test_and_set_bit(1, &ir_rx51->device_is_open)) return -EBUSY; - lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL); - if (IS_ERR(lirc_rx51->pwm)) { - int res = PTR_ERR(lirc_rx51->pwm); + ir_rx51->pwm = pwm_get(ir_rx51->dev, NULL); + if (IS_ERR(ir_rx51->pwm)) { + int res = PTR_ERR(ir_rx51->pwm); - dev_err(lirc_rx51->dev, "pwm_get failed: %d\n", res); + dev_err(ir_rx51->dev, "pwm_get failed: %d\n", res); return res; } return 0; } -static int lirc_rx51_release(struct inode *inode, struct file *file) +static void ir_rx51_release(struct rc_dev *dev) { - struct lirc_rx51 *lirc_rx51 = file->private_data; - - hrtimer_cancel(&lirc_rx51->timer); - lirc_rx51_off(lirc_rx51); - pwm_put(lirc_rx51->pwm); + struct ir_rx51 *ir_rx51 = dev->priv; - clear_bit(1, &lirc_rx51->device_is_open); + hrtimer_cancel(&ir_rx51->timer); + ir_rx51_off(ir_rx51); + pwm_put(ir_rx51->pwm); - return 0; + clear_bit(1, &ir_rx51->device_is_open); } -static struct lirc_rx51 lirc_rx51 = { +static struct ir_rx51 ir_rx51 = { .duty_cycle = 50, .wbuf_index = -1, }; -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .write = lirc_rx51_write, - .unlocked_ioctl = lirc_rx51_ioctl, - .read = lirc_dev_fop_read, - .poll = lirc_dev_fop_poll, - .open = lirc_rx51_open, - .release = lirc_rx51_release, -}; +static int ir_rx51_set_duty_cycle(struct rc_dev *dev, u32 duty) +{ + struct ir_rx51 *ir_rx51 = dev->priv; -static struct lirc_driver lirc_rx51_driver = { - .name = DRIVER_NAME, - .minor = -1, - .code_length = 1, - .data = &lirc_rx51, - .fops = &lirc_fops, - .owner = THIS_MODULE, -}; + ir_rx51->duty_cycle = duty; + + return 0; +} + +static int ir_rx51_set_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct ir_rx51 *ir_rx51 = dev->priv; + + if (carrier > 500000 || carrier < 20000) + return -EINVAL; + + ir_rx51->freq = carrier; + + return 0; +} #ifdef CONFIG_PM -static int lirc_rx51_suspend(struct platform_device *dev, pm_message_t state) +static int ir_rx51_suspend(struct platform_device *dev, pm_message_t state) { /* * In case the device is still open, do not suspend. Normally @@ -320,34 +219,34 @@ static int lirc_rx51_suspend(struct platform_device *dev, pm_message_t state) * were in a middle of a transmit. Thus, we defer any suspend * actions until transmit has completed. */ - if (test_and_set_bit(1, &lirc_rx51.device_is_open)) + if (test_and_set_bit(1, &ir_rx51.device_is_open)) return -EAGAIN; - clear_bit(1, &lirc_rx51.device_is_open); + clear_bit(1, &ir_rx51.device_is_open); return 0; } -static int lirc_rx51_resume(struct platform_device *dev) +static int ir_rx51_resume(struct platform_device *dev) { return 0; } #else -#define lirc_rx51_suspend NULL -#define lirc_rx51_resume NULL +#define ir_rx51_suspend NULL +#define ir_rx51_resume NULL #endif /* CONFIG_PM */ -static int lirc_rx51_probe(struct platform_device *dev) +static int ir_rx51_probe(struct platform_device *dev) { struct pwm_device *pwm; + struct rc_dev *rcdev; - lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES; - lirc_rx51.pdata = dev->dev.platform_data; + ir_rx51.pdata = dev->dev.platform_data; - if (!lirc_rx51.pdata) { + if (!ir_rx51.pdata) { dev_err(&dev->dev, "Platform Data is missing\n"); return -ENXIO; } @@ -362,51 +261,56 @@ static int lirc_rx51_probe(struct platform_device *dev) } /* Use default, in case userspace does not set the carrier */ - lirc_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC); + ir_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC); pwm_put(pwm); - hrtimer_init(&lirc_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - lirc_rx51.timer.function = lirc_rx51_timer_cb; + hrtimer_init(&ir_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ir_rx51.timer.function = ir_rx51_timer_cb; - lirc_rx51.dev = &dev->dev; - lirc_rx51_driver.dev = &dev->dev; - lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver); - init_waitqueue_head(&lirc_rx51.wqueue); + ir_rx51.dev = &dev->dev; - if (lirc_rx51_driver.minor < 0) { - dev_err(lirc_rx51.dev, ": lirc_register_driver failed: %d\n", - lirc_rx51_driver.minor); - return lirc_rx51_driver.minor; - } + rcdev = devm_rc_allocate_device(&dev->dev, RC_DRIVER_IR_RAW_TX); + if (!rcdev) + return -ENOMEM; - return 0; + rcdev->priv = &ir_rx51; + rcdev->open = ir_rx51_open; + rcdev->close = ir_rx51_release; + rcdev->tx_ir = ir_rx51_tx; + rcdev->s_tx_duty_cycle = ir_rx51_set_duty_cycle; + rcdev->s_tx_carrier = ir_rx51_set_tx_carrier; + rcdev->driver_name = KBUILD_MODNAME; + + ir_rx51.rcdev = rcdev; + + return devm_rc_register_device(&dev->dev, ir_rx51.rcdev); } -static int lirc_rx51_remove(struct platform_device *dev) +static int ir_rx51_remove(struct platform_device *dev) { - return lirc_unregister_driver(lirc_rx51_driver.minor); + return 0; } -static const struct of_device_id lirc_rx51_match[] = { +static const struct of_device_id ir_rx51_match[] = { { .compatible = "nokia,n900-ir", }, {}, }; -MODULE_DEVICE_TABLE(of, lirc_rx51_match); +MODULE_DEVICE_TABLE(of, ir_rx51_match); -struct platform_driver lirc_rx51_platform_driver = { - .probe = lirc_rx51_probe, - .remove = lirc_rx51_remove, - .suspend = lirc_rx51_suspend, - .resume = lirc_rx51_resume, +static struct platform_driver ir_rx51_platform_driver = { + .probe = ir_rx51_probe, + .remove = ir_rx51_remove, + .suspend = ir_rx51_suspend, + .resume = ir_rx51_resume, .driver = { - .name = DRIVER_NAME, - .of_match_table = of_match_ptr(lirc_rx51_match), + .name = KBUILD_MODNAME, + .of_match_table = of_match_ptr(ir_rx51_match), }, }; -module_platform_driver(lirc_rx51_platform_driver); +module_platform_driver(ir_rx51_platform_driver); -MODULE_DESCRIPTION("LIRC TX driver for Nokia RX51"); +MODULE_DESCRIPTION("IR TX driver for Nokia RX51"); MODULE_AUTHOR("Nokia Corporation"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index b07d9caebeb1..520bb77dcb62 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -176,9 +176,52 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) return -EINVAL; } +static const struct ir_raw_timings_pd ir_sanyo_timings = { + .header_pulse = SANYO_HEADER_PULSE, + .header_space = SANYO_HEADER_SPACE, + .bit_pulse = SANYO_BIT_PULSE, + .bit_space[0] = SANYO_BIT_0_SPACE, + .bit_space[1] = SANYO_BIT_1_SPACE, + .trailer_pulse = SANYO_TRAILER_PULSE, + .trailer_space = SANYO_TRAILER_SPACE, + .msb_first = 1, +}; + +/** + * ir_sanyo_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_sanyo_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int ret; + u64 raw; + + raw = ((u64)(bitrev16(scancode >> 8) & 0xfff8) << (8 + 8 + 13 - 3)) | + ((u64)(bitrev16(~scancode >> 8) & 0xfff8) << (8 + 8 + 0 - 3)) | + ((bitrev8(scancode) & 0xff) << 8) | + (bitrev8(~scancode) & 0xff); + + ret = ir_raw_gen_pd(&e, max, &ir_sanyo_timings, SANYO_NBITS, raw); + if (ret < 0) + return ret; + + return e - events; +} + static struct ir_raw_handler sanyo_handler = { .protocols = RC_BIT_SANYO, .decode = ir_sanyo_decode, + .encode = ir_sanyo_encode, }; static int __init ir_sanyo_decode_init(void) diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index 317677f06f2c..b47e89e2c1bd 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -173,9 +173,59 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) return -EINVAL; } +static const struct ir_raw_timings_pd ir_sharp_timings = { + .header_pulse = 0, + .header_space = 0, + .bit_pulse = SHARP_BIT_PULSE, + .bit_space[0] = SHARP_BIT_0_PERIOD, + .bit_space[1] = SHARP_BIT_1_PERIOD, + .trailer_pulse = SHARP_BIT_PULSE, + .trailer_space = SHARP_ECHO_SPACE, + .msb_first = 1, +}; + +/** + * ir_sharp_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_sharp_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int ret; + u32 raw; + + raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) | + bitrev8(scancode); + ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS, + (raw << 2) | 2); + if (ret < 0) + return ret; + + max -= ret; + + raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) | + bitrev8(~scancode); + ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS, + (raw << 2) | 1); + if (ret < 0) + return ret; + + return e - events; +} + static struct ir_raw_handler sharp_handler = { .protocols = RC_BIT_SHARP, .decode = ir_sharp_decode, + .encode = ir_sharp_encode, }; static int __init ir_sharp_decode_init(void) diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index baa972c76e0e..355fa8198f5a 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -169,9 +169,57 @@ finish_state_machine: return 0; } +static const struct ir_raw_timings_pl ir_sony_timings = { + .header_pulse = SONY_HEADER_PULSE, + .bit_space = SONY_BIT_SPACE, + .bit_pulse[0] = SONY_BIT_0_PULSE, + .bit_pulse[1] = SONY_BIT_1_PULSE, + .trailer_space = SONY_TRAILER_SPACE + SONY_BIT_SPACE, + .msb_first = 0, +}; + +/** + * ir_sony_encode() - Encode a scancode as a stream of raw events + * + * @protocol: protocol to encode + * @scancode: scancode to encode + * @events: array of raw ir events to write into + * @max: maximum size of @events + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + */ +static int ir_sony_encode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + u32 raw, len; + int ret; + + if (protocol == RC_TYPE_SONY12) { + raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9); + len = 12; + } else if (protocol == RC_TYPE_SONY15) { + raw = (scancode & 0x7f) | ((scancode & 0xff0000) >> 9); + len = 15; + } else { + raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9) | + ((scancode & 0xff00) << 4); + len = 20; + } + + ret = ir_raw_gen_pl(&e, max, &ir_sony_timings, len, raw); + if (ret < 0) + return ret; + + return e - events; +} + static struct ir_raw_handler sony_handler = { .protocols = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20, .decode = ir_sony_decode, + .encode = ir_sony_encode, }; static int __init ir_sony_decode_init(void) diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c new file mode 100644 index 000000000000..c8863f36686a --- /dev/null +++ b/drivers/media/rc/ir-spi.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Author: Andi Shyti <andi.shyti@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * SPI driven IR LED device driver + */ + +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <media/rc-core.h> + +#define IR_SPI_DRIVER_NAME "ir-spi" + +/* pulse value for different duty cycles */ +#define IR_SPI_PULSE_DC_50 0xff00 +#define IR_SPI_PULSE_DC_60 0xfc00 +#define IR_SPI_PULSE_DC_70 0xf800 +#define IR_SPI_PULSE_DC_75 0xf000 +#define IR_SPI_PULSE_DC_80 0xc000 +#define IR_SPI_PULSE_DC_90 0x8000 + +#define IR_SPI_DEFAULT_FREQUENCY 38000 +#define IR_SPI_BIT_PER_WORD 8 +#define IR_SPI_MAX_BUFSIZE 4096 + +struct ir_spi_data { + u32 freq; + u8 duty_cycle; + bool negated; + + u16 tx_buf[IR_SPI_MAX_BUFSIZE]; + u16 pulse; + u16 space; + + struct rc_dev *rc; + struct spi_device *spi; + struct regulator *regulator; +}; + +static int ir_spi_tx(struct rc_dev *dev, + unsigned int *buffer, unsigned int count) +{ + int i; + int ret; + unsigned int len = 0; + struct ir_spi_data *idata = dev->priv; + struct spi_transfer xfer; + + /* convert the pulse/space signal to raw binary signal */ + for (i = 0; i < count; i++) { + int j; + u16 val = ((i + 1) % 2) ? idata->pulse : idata->space; + + if (len + buffer[i] >= IR_SPI_MAX_BUFSIZE) + return -EINVAL; + + /* + * the first value in buffer is a pulse, so that 0, 2, 4, ... + * contain a pulse duration. On the contrary, 1, 3, 5, ... + * contain a space duration. + */ + val = (i % 2) ? idata->space : idata->pulse; + for (j = 0; j < buffer[i]; j++) + idata->tx_buf[len++] = val; + } + + memset(&xfer, 0, sizeof(xfer)); + + xfer.speed_hz = idata->freq; + xfer.len = len * sizeof(*idata->tx_buf); + xfer.tx_buf = idata->tx_buf; + + ret = regulator_enable(idata->regulator); + if (ret) + return ret; + + ret = spi_sync_transfer(idata->spi, &xfer, 1); + if (ret) + dev_err(&idata->spi->dev, "unable to deliver the signal\n"); + + regulator_disable(idata->regulator); + + return ret ? ret : count; +} + +static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct ir_spi_data *idata = dev->priv; + + if (!carrier) + return -EINVAL; + + idata->freq = carrier; + + return 0; +} + +static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) +{ + struct ir_spi_data *idata = dev->priv; + + if (duty_cycle >= 90) + idata->pulse = IR_SPI_PULSE_DC_90; + else if (duty_cycle >= 80) + idata->pulse = IR_SPI_PULSE_DC_80; + else if (duty_cycle >= 75) + idata->pulse = IR_SPI_PULSE_DC_75; + else if (duty_cycle >= 70) + idata->pulse = IR_SPI_PULSE_DC_70; + else if (duty_cycle >= 60) + idata->pulse = IR_SPI_PULSE_DC_60; + else + idata->pulse = IR_SPI_PULSE_DC_50; + + if (idata->negated) { + idata->pulse = ~idata->pulse; + idata->space = 0xffff; + } else { + idata->space = 0; + } + + return 0; +} + +static int ir_spi_probe(struct spi_device *spi) +{ + int ret; + u8 dc; + struct ir_spi_data *idata; + + idata = devm_kzalloc(&spi->dev, sizeof(*idata), GFP_KERNEL); + if (!idata) + return -ENOMEM; + + idata->regulator = devm_regulator_get(&spi->dev, "irda_regulator"); + if (IS_ERR(idata->regulator)) + return PTR_ERR(idata->regulator); + + idata->rc = devm_rc_allocate_device(&spi->dev, RC_DRIVER_IR_RAW_TX); + if (!idata->rc) + return -ENOMEM; + + idata->rc->tx_ir = ir_spi_tx; + idata->rc->s_tx_carrier = ir_spi_set_tx_carrier; + idata->rc->s_tx_duty_cycle = ir_spi_set_duty_cycle; + idata->rc->driver_name = IR_SPI_DRIVER_NAME; + idata->rc->priv = idata; + idata->spi = spi; + + idata->negated = of_property_read_bool(spi->dev.of_node, + "led-active-low"); + ret = of_property_read_u8(spi->dev.of_node, "duty-cycle", &dc); + if (ret) + dc = 50; + + /* ir_spi_set_duty_cycle cannot fail, + * it returns int to be compatible with the + * rc->s_tx_duty_cycle function + */ + ir_spi_set_duty_cycle(idata->rc, dc); + + idata->freq = IR_SPI_DEFAULT_FREQUENCY; + + return devm_rc_register_device(&spi->dev, idata->rc); +} + +static int ir_spi_remove(struct spi_device *spi) +{ + return 0; +} + +static const struct of_device_id ir_spi_of_match[] = { + { .compatible = "ir-spi-led" }, + {}, +}; + +static struct spi_driver ir_spi_driver = { + .probe = ir_spi_probe, + .remove = ir_spi_remove, + .driver = { + .name = IR_SPI_DRIVER_NAME, + .of_match_table = ir_spi_of_match, + }, +}; + +module_spi_driver(ir_spi_driver); + +MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>"); +MODULE_DESCRIPTION("SPI IR LED"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 367b28bed627..e9e4befbbebb 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -13,11 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * * Inspired by the original lirc_it87 and lirc_ite8709 drivers, on top of the * skeleton provided by the nuvoton-cir driver. * @@ -1470,7 +1465,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id return ret; /* input device for IR remote (and tx) */ - rdev = rc_allocate_device(); + rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rdev) goto exit_free_dev_rdev; itdev->rdev = rdev; @@ -1561,8 +1556,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* set up ir-core props */ rdev->priv = itdev; - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protocols = RC_BIT_ALL; + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; rdev->open = ite_open; rdev->close = ite_close; rdev->s_idle = ite_s_idle; diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h index aa899a0b9750..0e8ebc880d1f 100644 --- a/drivers/media/rc/ite-cir.h +++ b/drivers/media/rc/ite-cir.h @@ -12,11 +12,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. */ /* platform driver name to register */ diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index d7b13fae1267..ffe9e612f8d6 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-cec.o \ rc-cinergy-1400.o \ rc-cinergy.o \ + rc-d680-dmb.o \ rc-delock-61959.o \ rc-dib0700-nec.o \ rc-dib0700-rc5.o \ @@ -31,6 +32,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-dntv-live-dvbt-pro.o \ rc-dtt200u.o \ rc-dvbsky.o \ + rc-dvico-mce.o \ + rc-dvico-portable.o \ rc-em-terratec.o \ rc-encore-enltv2.o \ rc-encore-enltv.o \ @@ -41,6 +44,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-flyvideo.o \ rc-fusionhdtv-mce.o \ rc-gadmei-rm008z.o \ + rc-geekbox.o \ rc-genius-tvgo-a11mce.o \ rc-gotview7135.o \ rc-imon-mce.o \ diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c new file mode 100644 index 000000000000..bb5745d29d8a --- /dev/null +++ b/drivers/media/rc/keymaps/rc-d680-dmb.c @@ -0,0 +1,75 @@ +/* + * keymap imported from cxusb.c + * + * Copyright (C) 2016 Sean Young + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table rc_map_d680_dmb_table[] = { + { 0x0038, KEY_SWITCHVIDEOMODE }, /* TV/AV */ + { 0x080c, KEY_ZOOM }, + { 0x0800, KEY_0 }, + { 0x0001, KEY_1 }, + { 0x0802, KEY_2 }, + { 0x0003, KEY_3 }, + { 0x0804, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0806, KEY_6 }, + { 0x0007, KEY_7 }, + { 0x0808, KEY_8 }, + { 0x0009, KEY_9 }, + { 0x000a, KEY_MUTE }, + { 0x0829, KEY_BACK }, + { 0x0012, KEY_CHANNELUP }, + { 0x0813, KEY_CHANNELDOWN }, + { 0x002b, KEY_VOLUMEUP }, + { 0x082c, KEY_VOLUMEDOWN }, + { 0x0020, KEY_UP }, + { 0x0821, KEY_DOWN }, + { 0x0011, KEY_LEFT }, + { 0x0810, KEY_RIGHT }, + { 0x000d, KEY_OK }, + { 0x081f, KEY_RECORD }, + { 0x0017, KEY_PLAYPAUSE }, + { 0x0816, KEY_PLAYPAUSE }, + { 0x000b, KEY_STOP }, + { 0x0827, KEY_FASTFORWARD }, + { 0x0026, KEY_REWIND }, + { 0x081e, KEY_UNKNOWN }, /* Time Shift */ + { 0x000e, KEY_UNKNOWN }, /* Snapshot */ + { 0x082d, KEY_UNKNOWN }, /* Mouse Cursor */ + { 0x000f, KEY_UNKNOWN }, /* Minimize/Maximize */ + { 0x0814, KEY_SHUFFLE }, /* Shuffle */ + { 0x0025, KEY_POWER }, +}; + +static struct rc_map_list d680_dmb_map = { + .map = { + .scan = rc_map_d680_dmb_table, + .size = ARRAY_SIZE(rc_map_d680_dmb_table), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_D680_DMB, + } +}; + +static int __init init_rc_map_d680_dmb(void) +{ + return rc_map_register(&d680_dmb_map); +} + +static void __exit exit_rc_map_d680_dmb(void) +{ + rc_map_unregister(&d680_dmb_map); +} + +module_init(init_rc_map_d680_dmb) +module_exit(exit_rc_map_d680_dmb) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c new file mode 100644 index 000000000000..e5f098c50235 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c @@ -0,0 +1,85 @@ +/* + * keymap imported from cxusb.c + * + * Copyright (C) 2016 Sean Young + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table rc_map_dvico_mce_table[] = { + { 0xfe02, KEY_TV }, + { 0xfe0e, KEY_MP3 }, + { 0xfe1a, KEY_DVD }, + { 0xfe1e, KEY_FAVORITES }, + { 0xfe16, KEY_SETUP }, + { 0xfe46, KEY_POWER2 }, + { 0xfe0a, KEY_EPG }, + { 0xfe49, KEY_BACK }, + { 0xfe4d, KEY_MENU }, + { 0xfe51, KEY_UP }, + { 0xfe5b, KEY_LEFT }, + { 0xfe5f, KEY_RIGHT }, + { 0xfe53, KEY_DOWN }, + { 0xfe5e, KEY_OK }, + { 0xfe59, KEY_INFO }, + { 0xfe55, KEY_TAB }, + { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */ + { 0xfe12, KEY_NEXTSONG }, /* Skip */ + { 0xfe42, KEY_ENTER }, /* Windows/Start */ + { 0xfe15, KEY_VOLUMEUP }, + { 0xfe05, KEY_VOLUMEDOWN }, + { 0xfe11, KEY_CHANNELUP }, + { 0xfe09, KEY_CHANNELDOWN }, + { 0xfe52, KEY_CAMERA }, + { 0xfe5a, KEY_TUNER }, /* Live */ + { 0xfe19, KEY_OPEN }, + { 0xfe0b, KEY_1 }, + { 0xfe17, KEY_2 }, + { 0xfe1b, KEY_3 }, + { 0xfe07, KEY_4 }, + { 0xfe50, KEY_5 }, + { 0xfe54, KEY_6 }, + { 0xfe48, KEY_7 }, + { 0xfe4c, KEY_8 }, + { 0xfe58, KEY_9 }, + { 0xfe13, KEY_ANGLE }, /* Aspect */ + { 0xfe03, KEY_0 }, + { 0xfe1f, KEY_ZOOM }, + { 0xfe43, KEY_REWIND }, + { 0xfe47, KEY_PLAYPAUSE }, + { 0xfe4f, KEY_FASTFORWARD }, + { 0xfe57, KEY_MUTE }, + { 0xfe0d, KEY_STOP }, + { 0xfe01, KEY_RECORD }, + { 0xfe4e, KEY_POWER }, +}; + +static struct rc_map_list dvico_mce_map = { + .map = { + .scan = rc_map_dvico_mce_table, + .size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DVICO_MCE, + } +}; + +static int __init init_rc_map_dvico_mce(void) +{ + return rc_map_register(&dvico_mce_map); +} + +static void __exit exit_rc_map_dvico_mce(void) +{ + rc_map_unregister(&dvico_mce_map); +} + +module_init(init_rc_map_dvico_mce) +module_exit(exit_rc_map_dvico_mce) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c new file mode 100644 index 000000000000..94ceeee94b3f --- /dev/null +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c @@ -0,0 +1,76 @@ +/* + * keymap imported from cxusb.c + * + * Copyright (C) 2016 Sean Young + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table rc_map_dvico_portable_table[] = { + { 0xfc02, KEY_SETUP }, /* Profile */ + { 0xfc43, KEY_POWER2 }, + { 0xfc06, KEY_EPG }, + { 0xfc5a, KEY_BACK }, + { 0xfc05, KEY_MENU }, + { 0xfc47, KEY_INFO }, + { 0xfc01, KEY_TAB }, + { 0xfc42, KEY_PREVIOUSSONG },/* Replay */ + { 0xfc49, KEY_VOLUMEUP }, + { 0xfc09, KEY_VOLUMEDOWN }, + { 0xfc54, KEY_CHANNELUP }, + { 0xfc0b, KEY_CHANNELDOWN }, + { 0xfc16, KEY_CAMERA }, + { 0xfc40, KEY_TUNER }, /* ATV/DTV */ + { 0xfc45, KEY_OPEN }, + { 0xfc19, KEY_1 }, + { 0xfc18, KEY_2 }, + { 0xfc1b, KEY_3 }, + { 0xfc1a, KEY_4 }, + { 0xfc58, KEY_5 }, + { 0xfc59, KEY_6 }, + { 0xfc15, KEY_7 }, + { 0xfc14, KEY_8 }, + { 0xfc17, KEY_9 }, + { 0xfc44, KEY_ANGLE }, /* Aspect */ + { 0xfc55, KEY_0 }, + { 0xfc07, KEY_ZOOM }, + { 0xfc0a, KEY_REWIND }, + { 0xfc08, KEY_PLAYPAUSE }, + { 0xfc4b, KEY_FASTFORWARD }, + { 0xfc5b, KEY_MUTE }, + { 0xfc04, KEY_STOP }, + { 0xfc56, KEY_RECORD }, + { 0xfc57, KEY_POWER }, + { 0xfc41, KEY_UNKNOWN }, /* INPUT */ + { 0xfc00, KEY_UNKNOWN }, /* HD */ +}; + +static struct rc_map_list dvico_portable_map = { + .map = { + .scan = rc_map_dvico_portable_table, + .size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DVICO_PORTABLE, + } +}; + +static int __init init_rc_map_dvico_portable(void) +{ + return rc_map_register(&dvico_portable_map); +} + +static void __exit exit_rc_map_dvico_portable(void) +{ + rc_map_unregister(&dvico_portable_map); +} + +module_init(init_rc_map_dvico_portable) +module_exit(exit_rc_map_dvico_portable) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); diff --git a/drivers/media/rc/keymaps/rc-geekbox.c b/drivers/media/rc/keymaps/rc-geekbox.c new file mode 100644 index 000000000000..affc4c481888 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-geekbox.c @@ -0,0 +1,55 @@ +/* + * Keytable for the GeekBox remote controller + * + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <media/rc-map.h> +#include <linux/module.h> + +static struct rc_map_table geekbox[] = { + { 0x01, KEY_BACK }, + { 0x02, KEY_DOWN }, + { 0x03, KEY_UP }, + { 0x07, KEY_OK }, + { 0x0b, KEY_VOLUMEUP }, + { 0x0e, KEY_LEFT }, + { 0x13, KEY_MENU }, + { 0x14, KEY_POWER }, + { 0x1a, KEY_RIGHT }, + { 0x48, KEY_HOME }, + { 0x58, KEY_VOLUMEDOWN }, + { 0x5c, KEY_SCREEN }, +}; + +static struct rc_map_list geekbox_map = { + .map = { + .scan = geekbox, + .size = ARRAY_SIZE(geekbox), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_GEEKBOX, + } +}; + +static int __init init_rc_map_geekbox(void) +{ + return rc_map_register(&geekbox_map); +} + +static void __exit exit_rc_map_geekbox(void) +{ + rc_map_unregister(&geekbox_map); +} + +module_init(init_rc_map_geekbox) +module_exit(exit_rc_map_geekbox) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index ef4006fe4de0..5be567506bcd 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -86,6 +86,7 @@ static struct rc_map_table rc6_mce[] = { { 0x800f045e, KEY_BLUE }, { 0x800f0465, KEY_POWER2 }, /* TV Power */ + { 0x800f0469, KEY_MESSENGER }, { 0x800f046e, KEY_PLAYPAUSE }, { 0x800f046f, KEY_PLAYER }, /* Start media application (NEW) */ diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c index f9733bb289d6..02c9c243c060 100644 --- a/drivers/media/rc/keymaps/rc-technisat-usb2.c +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -13,10 +13,6 @@ * License, or (at your option) any later version. * * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c index 454e06295692..5cc1b456e329 100644 --- a/drivers/media/rc/keymaps/rc-tivo.c +++ b/drivers/media/rc/keymaps/rc-tivo.c @@ -15,62 +15,62 @@ * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle, * which also ships with a TiVo-branded IR transceiver, supported by the mceusb * driver. Note that the remote uses an NEC-ish protocol, but instead of having - * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the + * a command/not_command pair, it has a vendor ID of 0x3085, but some keys, the * NEC extended checksums do pass, so the table presently has the intended * values and the checksum-passed versions for those keys. */ static struct rc_map_table tivo[] = { - { 0xa10c900f, KEY_MEDIA }, /* TiVo Button */ - { 0xa10c0807, KEY_POWER2 }, /* TV Power */ - { 0xa10c8807, KEY_TV }, /* Live TV/Swap */ - { 0xa10c2c03, KEY_VIDEO_NEXT }, /* TV Input */ - { 0xa10cc807, KEY_INFO }, - { 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */ + { 0x3085f009, KEY_MEDIA }, /* TiVo Button */ + { 0x3085e010, KEY_POWER2 }, /* TV Power */ + { 0x3085e011, KEY_TV }, /* Live TV/Swap */ + { 0x3085c034, KEY_VIDEO_NEXT }, /* TV Input */ + { 0x3085e013, KEY_INFO }, + { 0x3085a05f, KEY_CYCLEWINDOWS }, /* Window */ { 0x0085305f, KEY_CYCLEWINDOWS }, - { 0xa10c6c03, KEY_EPG }, /* Guide */ + { 0x3085c036, KEY_EPG }, /* Guide */ - { 0xa10c2807, KEY_UP }, - { 0xa10c6807, KEY_DOWN }, - { 0xa10ce807, KEY_LEFT }, - { 0xa10ca807, KEY_RIGHT }, + { 0x3085e014, KEY_UP }, + { 0x3085e016, KEY_DOWN }, + { 0x3085e017, KEY_LEFT }, + { 0x3085e015, KEY_RIGHT }, - { 0xa10c1807, KEY_SCROLLDOWN }, /* Red Thumbs Down */ - { 0xa10c9807, KEY_SELECT }, - { 0xa10c5807, KEY_SCROLLUP }, /* Green Thumbs Up */ + { 0x3085e018, KEY_SCROLLDOWN }, /* Red Thumbs Down */ + { 0x3085e019, KEY_SELECT }, + { 0x3085e01a, KEY_SCROLLUP }, /* Green Thumbs Up */ - { 0xa10c3807, KEY_VOLUMEUP }, - { 0xa10cb807, KEY_VOLUMEDOWN }, - { 0xa10cd807, KEY_MUTE }, - { 0xa10c040b, KEY_RECORD }, - { 0xa10c7807, KEY_CHANNELUP }, - { 0xa10cf807, KEY_CHANNELDOWN }, + { 0x3085e01c, KEY_VOLUMEUP }, + { 0x3085e01d, KEY_VOLUMEDOWN }, + { 0x3085e01b, KEY_MUTE }, + { 0x3085d020, KEY_RECORD }, + { 0x3085e01e, KEY_CHANNELUP }, + { 0x3085e01f, KEY_CHANNELDOWN }, { 0x0085301f, KEY_CHANNELDOWN }, - { 0xa10c840b, KEY_PLAY }, - { 0xa10cc40b, KEY_PAUSE }, - { 0xa10ca40b, KEY_SLOW }, - { 0xa10c440b, KEY_REWIND }, - { 0xa10c240b, KEY_FASTFORWARD }, - { 0xa10c640b, KEY_PREVIOUS }, - { 0xa10ce40b, KEY_NEXT }, /* ->| */ + { 0x3085d021, KEY_PLAY }, + { 0x3085d023, KEY_PAUSE }, + { 0x3085d025, KEY_SLOW }, + { 0x3085d022, KEY_REWIND }, + { 0x3085d024, KEY_FASTFORWARD }, + { 0x3085d026, KEY_PREVIOUS }, + { 0x3085d027, KEY_NEXT }, /* ->| */ - { 0xa10c220d, KEY_ZOOM }, /* Aspect */ - { 0xa10c120d, KEY_STOP }, - { 0xa10c520d, KEY_DVD }, /* DVD Menu */ + { 0x3085b044, KEY_ZOOM }, /* Aspect */ + { 0x3085b048, KEY_STOP }, + { 0x3085b04a, KEY_DVD }, /* DVD Menu */ - { 0xa10c140b, KEY_NUMERIC_1 }, - { 0xa10c940b, KEY_NUMERIC_2 }, - { 0xa10c540b, KEY_NUMERIC_3 }, - { 0xa10cd40b, KEY_NUMERIC_4 }, - { 0xa10c340b, KEY_NUMERIC_5 }, - { 0xa10cb40b, KEY_NUMERIC_6 }, - { 0xa10c740b, KEY_NUMERIC_7 }, - { 0xa10cf40b, KEY_NUMERIC_8 }, + { 0x3085d028, KEY_NUMERIC_1 }, + { 0x3085d029, KEY_NUMERIC_2 }, + { 0x3085d02a, KEY_NUMERIC_3 }, + { 0x3085d02b, KEY_NUMERIC_4 }, + { 0x3085d02c, KEY_NUMERIC_5 }, + { 0x3085d02d, KEY_NUMERIC_6 }, + { 0x3085d02e, KEY_NUMERIC_7 }, + { 0x3085d02f, KEY_NUMERIC_8 }, { 0x0085302f, KEY_NUMERIC_8 }, - { 0xa10c0c03, KEY_NUMERIC_9 }, - { 0xa10c8c03, KEY_NUMERIC_0 }, - { 0xa10ccc03, KEY_ENTER }, - { 0xa10c4c03, KEY_CLEAR }, + { 0x3085c030, KEY_NUMERIC_9 }, + { 0x3085c031, KEY_NUMERIC_0 }, + { 0x3085c033, KEY_ENTER }, + { 0x3085c032, KEY_CLEAR }, }; static struct rc_map_list tivo_map = { diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 3854809e8531..a54ca531d8ef 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -13,10 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -472,7 +468,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) if (retval) { module_put(cdev->owner); ir->open--; - } else { + } else if (ir->buf) { lirc_buffer_clear(ir->buf); } if (ir->task) @@ -582,7 +578,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) result = put_user(ir->d.features, (__u32 __user *)arg); break; case LIRC_GET_REC_MODE: - if (LIRC_CAN_REC(ir->d.features)) { + if (!LIRC_CAN_REC(ir->d.features)) { result = -ENOTTY; break; } @@ -592,7 +588,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) (__u32 __user *)arg); break; case LIRC_SET_REC_MODE: - if (LIRC_CAN_REC(ir->d.features)) { + if (!LIRC_CAN_REC(ir->d.features)) { result = -ENOTTY; break; } @@ -651,6 +647,9 @@ ssize_t lirc_dev_fop_read(struct file *file, return -ENODEV; } + if (!LIRC_CAN_REC(ir->d.features)) + return -EINVAL; + dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); buf = kzalloc(ir->chunk_size, GFP_KERNEL); diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 9bf69179eee0..238d8eaf7d94 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -31,10 +31,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <linux/device.h> @@ -890,7 +886,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) cmdbuf[3] = MCE_IRDATA_TRAILER; dev_dbg(ir->dev, "disabling carrier modulation"); mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); - return carrier; + return 0; } for (prescaler = 0; prescaler < 4; ++prescaler) { @@ -904,7 +900,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) /* Transmit new carrier to mce device */ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); - return carrier; + return 0; } } @@ -1181,7 +1177,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) struct rc_dev *rc; int ret; - rc = rc_allocate_device(); + rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rc) { dev_err(dev, "remote dev allocation failed"); goto out; @@ -1201,8 +1197,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) usb_to_input_id(ir->usbdev, &rc->input_id); rc->dev.parent = dev; rc->priv = ir; - rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protocols = RC_BIT_ALL; + rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; rc->timeout = MS_TO_NS(100); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 7eb3f4f1ddcd..5576dbd6b1a4 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -131,7 +131,7 @@ static int meson_ir_probe(struct platform_device *pdev) return ir->irq; } - ir->rc = rc_allocate_device(); + ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!ir->rc) { dev_err(dev, "failed to allocate rc device\n"); return -ENOMEM; @@ -144,8 +144,7 @@ static int meson_ir_probe(struct platform_device *pdev) map_name = of_get_property(node, "linux,rc-map-name", NULL); ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY; ir->rc->dev.parent = dev; - ir->rc->driver_type = RC_DRIVER_IR_RAW; - ir->rc->allowed_protocols = RC_BIT_ALL; + ir->rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; ir->rc->rx_resolution = US_TO_NS(MESON_TRATE); ir->rc->timeout = MS_TO_NS(200); ir->rc->driver_name = DRIVER_NAME; diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c new file mode 100644 index 000000000000..f1e164e441e8 --- /dev/null +++ b/drivers/media/rc/mtk-cir.c @@ -0,0 +1,335 @@ +/* + * Driver for Mediatek IR Receiver Controller + * + * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/reset.h> +#include <media/rc-core.h> + +#define MTK_IR_DEV KBUILD_MODNAME + +/* Register to enable PWM and IR */ +#define MTK_CONFIG_HIGH_REG 0x0c +/* Enable IR pulse width detection */ +#define MTK_PWM_EN BIT(13) +/* Enable IR hardware function */ +#define MTK_IR_EN BIT(0) + +/* Register to setting sample period */ +#define MTK_CONFIG_LOW_REG 0x10 +/* Field to set sample period */ +#define CHK_PERIOD DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, \ + MTK_IR_CLK_PERIOD) +#define MTK_CHK_PERIOD (((CHK_PERIOD) << 8) & (GENMASK(20, 8))) +#define MTK_CHK_PERIOD_MASK (GENMASK(20, 8)) + +/* Register to clear state of state machine */ +#define MTK_IRCLR_REG 0x20 +/* Bit to restart IR receiving */ +#define MTK_IRCLR BIT(0) + +/* Register containing pulse width data */ +#define MTK_CHKDATA_REG(i) (0x88 + 4 * (i)) +#define MTK_WIDTH_MASK (GENMASK(7, 0)) + +/* Register to enable IR interrupt */ +#define MTK_IRINT_EN_REG 0xcc +/* Bit to enable interrupt */ +#define MTK_IRINT_EN BIT(0) + +/* Register to ack IR interrupt */ +#define MTK_IRINT_CLR_REG 0xd0 +/* Bit to clear interrupt status */ +#define MTK_IRINT_CLR BIT(0) + +/* Maximum count of samples */ +#define MTK_MAX_SAMPLES 0xff +/* Indicate the end of IR message */ +#define MTK_IR_END(v, p) ((v) == MTK_MAX_SAMPLES && (p) == 0) +/* Number of registers to record the pulse width */ +#define MTK_CHKDATA_SZ 17 +/* Source clock frequency */ +#define MTK_IR_BASE_CLK 273000000 +/* Frequency after IR internal divider */ +#define MTK_IR_CLK_FREQ (MTK_IR_BASE_CLK / 4) +/* Period for MTK_IR_CLK in ns*/ +#define MTK_IR_CLK_PERIOD DIV_ROUND_CLOSEST(1000000000ul, \ + MTK_IR_CLK_FREQ) +/* Sample period in ns */ +#define MTK_IR_SAMPLE (MTK_IR_CLK_PERIOD * 0xc00) + +/* + * struct mtk_ir - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer + * @rc: The rc instrance + * @irq: The IRQ that we are using + * @base: The mapped register i/o base + * @clk: The clock that we are using + */ +struct mtk_ir { + struct device *dev; + struct rc_dev *rc; + void __iomem *base; + int irq; + struct clk *clk; +}; + +static void mtk_w32_mask(struct mtk_ir *ir, u32 val, u32 mask, unsigned int reg) +{ + u32 tmp; + + tmp = __raw_readl(ir->base + reg); + tmp = (tmp & ~mask) | val; + __raw_writel(tmp, ir->base + reg); +} + +static void mtk_w32(struct mtk_ir *ir, u32 val, unsigned int reg) +{ + __raw_writel(val, ir->base + reg); +} + +static u32 mtk_r32(struct mtk_ir *ir, unsigned int reg) +{ + return __raw_readl(ir->base + reg); +} + +static inline void mtk_irq_disable(struct mtk_ir *ir, u32 mask) +{ + u32 val; + + val = mtk_r32(ir, MTK_IRINT_EN_REG); + mtk_w32(ir, val & ~mask, MTK_IRINT_EN_REG); +} + +static inline void mtk_irq_enable(struct mtk_ir *ir, u32 mask) +{ + u32 val; + + val = mtk_r32(ir, MTK_IRINT_EN_REG); + mtk_w32(ir, val | mask, MTK_IRINT_EN_REG); +} + +static irqreturn_t mtk_ir_irq(int irqno, void *dev_id) +{ + struct mtk_ir *ir = dev_id; + u8 wid = 0; + u32 i, j, val; + DEFINE_IR_RAW_EVENT(rawir); + + /* + * Reset decoder state machine explicitly is required + * because 1) the longest duration for space MTK IR hardware + * could record is not safely long. e.g 12ms if rx resolution + * is 46us by default. There is still the risk to satisfying + * every decoder to reset themselves through long enough + * trailing spaces and 2) the IRQ handler guarantees that + * start of IR message is always contained in and starting + * from register MTK_CHKDATA_REG(0). + */ + ir_raw_event_reset(ir->rc); + + /* First message must be pulse */ + rawir.pulse = false; + + /* Handle all pulse and space IR controller captures */ + for (i = 0 ; i < MTK_CHKDATA_SZ ; i++) { + val = mtk_r32(ir, MTK_CHKDATA_REG(i)); + dev_dbg(ir->dev, "@reg%d=0x%08x\n", i, val); + + for (j = 0 ; j < 4 ; j++) { + wid = (val & (MTK_WIDTH_MASK << j * 8)) >> j * 8; + rawir.pulse = !rawir.pulse; + rawir.duration = wid * (MTK_IR_SAMPLE + 1); + ir_raw_event_store_with_filter(ir->rc, &rawir); + } + } + + /* + * The maximum number of edges the IR controller can + * hold is MTK_CHKDATA_SZ * 4. So if received IR messages + * is over the limit, the last incomplete IR message would + * be appended trailing space and still would be sent into + * ir-rc-raw to decode. That helps it is possible that it + * has enough information to decode a scancode even if the + * trailing end of the message is missing. + */ + if (!MTK_IR_END(wid, rawir.pulse)) { + rawir.pulse = false; + rawir.duration = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1); + ir_raw_event_store_with_filter(ir->rc, &rawir); + } + + ir_raw_event_handle(ir->rc); + + /* + * Restart controller for the next receive that would + * clear up all CHKDATA registers + */ + mtk_w32_mask(ir, 0x1, MTK_IRCLR, MTK_IRCLR_REG); + + /* Clear interrupt status */ + mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, MTK_IRINT_CLR_REG); + + return IRQ_HANDLED; +} + +static int mtk_ir_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dn = dev->of_node; + struct resource *res; + struct mtk_ir *ir; + u32 val; + int ret = 0; + const char *map_name; + + ir = devm_kzalloc(dev, sizeof(struct mtk_ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + ir->dev = dev; + + if (!of_device_is_compatible(dn, "mediatek,mt7623-cir")) + return -ENODEV; + + ir->clk = devm_clk_get(dev, "clk"); + if (IS_ERR(ir->clk)) { + dev_err(dev, "failed to get a ir clock.\n"); + return PTR_ERR(ir->clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ir->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ir->base)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(ir->base); + } + + ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); + if (!ir->rc) { + dev_err(dev, "failed to allocate device\n"); + return -ENOMEM; + } + + ir->rc->priv = ir; + ir->rc->input_name = MTK_IR_DEV; + ir->rc->input_phys = MTK_IR_DEV "/input0"; + ir->rc->input_id.bustype = BUS_HOST; + ir->rc->input_id.vendor = 0x0001; + ir->rc->input_id.product = 0x0001; + ir->rc->input_id.version = 0x0001; + map_name = of_get_property(dn, "linux,rc-map-name", NULL); + ir->rc->map_name = map_name ?: RC_MAP_EMPTY; + ir->rc->dev.parent = dev; + ir->rc->driver_name = MTK_IR_DEV; + ir->rc->allowed_protocols = RC_BIT_ALL; + ir->rc->rx_resolution = MTK_IR_SAMPLE; + ir->rc->timeout = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1); + + ret = devm_rc_register_device(dev, ir->rc); + if (ret) { + dev_err(dev, "failed to register rc device\n"); + return ret; + } + + platform_set_drvdata(pdev, ir); + + ir->irq = platform_get_irq(pdev, 0); + if (ir->irq < 0) { + dev_err(dev, "no irq resource\n"); + return -ENODEV; + } + + /* + * Enable interrupt after proper hardware + * setup and IRQ handler registration + */ + if (clk_prepare_enable(ir->clk)) { + dev_err(dev, "try to enable ir_clk failed\n"); + ret = -EINVAL; + goto exit_clkdisable_clk; + } + + mtk_irq_disable(ir, MTK_IRINT_EN); + + ret = devm_request_irq(dev, ir->irq, mtk_ir_irq, 0, MTK_IR_DEV, ir); + if (ret) { + dev_err(dev, "failed request irq\n"); + goto exit_clkdisable_clk; + } + + /* Enable IR and PWM */ + val = mtk_r32(ir, MTK_CONFIG_HIGH_REG); + val |= MTK_PWM_EN | MTK_IR_EN; + mtk_w32(ir, val, MTK_CONFIG_HIGH_REG); + + /* Setting sample period */ + mtk_w32_mask(ir, MTK_CHK_PERIOD, MTK_CHK_PERIOD_MASK, + MTK_CONFIG_LOW_REG); + + mtk_irq_enable(ir, MTK_IRINT_EN); + + dev_info(dev, "Initialized MT7623 IR driver, sample period = %luus\n", + DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, 1000)); + + return 0; + +exit_clkdisable_clk: + clk_disable_unprepare(ir->clk); + + return ret; +} + +static int mtk_ir_remove(struct platform_device *pdev) +{ + struct mtk_ir *ir = platform_get_drvdata(pdev); + + /* + * Avoid contention between remove handler and + * IRQ handler so that disabling IR interrupt and + * waiting for pending IRQ handler to complete + */ + mtk_irq_disable(ir, MTK_IRINT_EN); + synchronize_irq(ir->irq); + + clk_disable_unprepare(ir->clk); + + return 0; +} + +static const struct of_device_id mtk_ir_match[] = { + { .compatible = "mediatek,mt7623-cir" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_ir_match); + +static struct platform_driver mtk_ir_driver = { + .probe = mtk_ir_probe, + .remove = mtk_ir_remove, + .driver = { + .name = MTK_IR_DEV, + .of_match_table = mtk_ir_match, + }, +}; + +module_platform_driver(mtk_ir_driver); + +MODULE_DESCRIPTION("Mediatek IR Receiver Controller Driver"); +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 4b78c891eb77..b109f8246b96 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -18,11 +18,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -176,6 +171,41 @@ static void nvt_set_ioaddr(struct nvt_dev *nvt, unsigned long *ioaddr) } } +static void nvt_write_wakeup_codes(struct rc_dev *dev, + const u8 *wbuf, int count) +{ + u8 tolerance, config; + struct nvt_dev *nvt = dev->priv; + int i; + + /* hardcode the tolerance to 10% */ + tolerance = DIV_ROUND_UP(count, 10); + + spin_lock(&nvt->lock); + + nvt_clear_cir_wake_fifo(nvt); + nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP); + nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL); + + config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); + + /* enable writes to wake fifo */ + nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1, + CIR_WAKE_IRCON); + + if (count) + pr_info("Wake samples (%d) =", count); + else + pr_info("Wake sample fifo cleared"); + + for (i = 0; i < count; i++) + nvt_cir_wake_reg_write(nvt, wbuf[i], CIR_WAKE_WR_FIFO_DATA); + + nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON); + + spin_unlock(&nvt->lock); +} + static ssize_t wakeup_data_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -214,9 +244,7 @@ static ssize_t wakeup_data_store(struct device *dev, const char *buf, size_t len) { struct rc_dev *rc_dev = to_rc_dev(dev); - struct nvt_dev *nvt = rc_dev->priv; - unsigned long flags; - u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE]; + u8 wake_buf[WAKEUP_MAX_SIZE]; char **argv; int i, count; unsigned int val; @@ -245,27 +273,7 @@ static ssize_t wakeup_data_store(struct device *dev, wake_buf[i] |= BUF_PULSE_BIT; } - /* hardcode the tolerance to 10% */ - tolerance = DIV_ROUND_UP(count, 10); - - spin_lock_irqsave(&nvt->lock, flags); - - nvt_clear_cir_wake_fifo(nvt); - nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP); - nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL); - - config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); - - /* enable writes to wake fifo */ - nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1, - CIR_WAKE_IRCON); - - for (i = 0; i < count; i++) - nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA); - - nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON); - - spin_unlock_irqrestore(&nvt->lock, flags); + nvt_write_wakeup_codes(rc_dev, wake_buf, count); ret = len; out: @@ -662,6 +670,62 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) return 0; } +static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev, + struct rc_scancode_filter *sc_filter) +{ + u8 buf_val; + int i, ret, count; + unsigned int val; + struct ir_raw_event *raw; + u8 wake_buf[WAKEUP_MAX_SIZE]; + bool complete; + + /* Require mask to be set */ + if (!sc_filter->mask) + return 0; + + raw = kmalloc_array(WAKEUP_MAX_SIZE, sizeof(*raw), GFP_KERNEL); + if (!raw) + return -ENOMEM; + + ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc_filter->data, + raw, WAKEUP_MAX_SIZE); + complete = (ret != -ENOBUFS); + if (!complete) + ret = WAKEUP_MAX_SIZE; + else if (ret < 0) + goto out_raw; + + /* Inspect the ir samples */ + for (i = 0, count = 0; i < ret && count < WAKEUP_MAX_SIZE; ++i) { + /* NS to US */ + val = DIV_ROUND_UP(raw[i].duration, 1000L) / SAMPLE_PERIOD; + + /* Split too large values into several smaller ones */ + while (val > 0 && count < WAKEUP_MAX_SIZE) { + /* 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; + + wake_buf[count] = buf_val; + val -= buf_val; + if ((raw[i]).pulse) + wake_buf[count] |= BUF_PULSE_BIT; + count++; + } + } + + nvt_write_wakeup_codes(dev, wake_buf, count); + ret = 0; +out_raw: + kfree(raw); + + return ret; +} + /* * nvt_tx_ir * @@ -998,7 +1062,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) return -ENOMEM; /* input device for IR remote (and tx) */ - nvt->rdev = devm_rc_allocate_device(&pdev->dev); + nvt->rdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); if (!nvt->rdev) return -ENOMEM; rdev = nvt->rdev; @@ -1061,12 +1125,14 @@ 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->allowed_protocols = RC_BIT_ALL; + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER; + rdev->encode_wakeup = true; rdev->open = nvt_open; rdev->close = nvt_close; rdev->tx_ir = nvt_tx_ir; rdev->s_tx_carrier = nvt_set_tx_carrier; + rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_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 c41c5765e1d2..88a29df38a57 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -18,11 +18,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include <linux/spinlock.h> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 585d5e52118d..a70a5c557434 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -20,7 +20,6 @@ #define MAX_IR_EVENT_SIZE 512 #include <linux/slab.h> -#include <linux/spinlock.h> #include <media/rc-core.h> struct ir_raw_handler { @@ -28,6 +27,8 @@ struct ir_raw_handler { u64 protocols; /* which are handled by this handler */ int (*decode)(struct rc_dev *dev, struct ir_raw_event event); + int (*encode)(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max); /* These two should only be used by the lirc decoder */ int (*raw_register)(struct rc_dev *dev); @@ -37,7 +38,6 @@ struct ir_raw_handler { struct ir_raw_event_ctrl { struct list_head list; /* to keep track of raw clients */ struct task_struct *thread; - spinlock_t lock; /* fifo for the pulse/space durations */ DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE); ktime_t last_event; /* when last event occurred */ @@ -154,6 +154,111 @@ static inline bool is_timing_event(struct ir_raw_event ev) #define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) #define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") +/* functions for IR encoders */ + +static inline void init_ir_raw_event_duration(struct ir_raw_event *ev, + unsigned int pulse, + u32 duration) +{ + init_ir_raw_event(ev); + ev->duration = duration; + ev->pulse = pulse; +} + +/** + * struct ir_raw_timings_manchester - Manchester coding timings + * @leader: duration of leader pulse (if any) 0 if continuing + * existing signal (see @pulse_space_start) + * @pulse_space_start: 1 for starting with pulse (0 for starting with space) + * @clock: duration of each pulse/space in ns + * @invert: if set clock logic is inverted + * (0 = space + pulse, 1 = pulse + space) + * @trailer_space: duration of trailer space in ns + */ +struct ir_raw_timings_manchester { + unsigned int leader; + unsigned int pulse_space_start:1; + unsigned int clock; + unsigned int invert:1; + unsigned int trailer_space; +}; + +int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_manchester *timings, + unsigned int n, unsigned int data); + +/** + * ir_raw_gen_pulse_space() - generate pulse and space raw events. + * @ev: Pointer to pointer to next free raw event. + * Will be incremented for each raw event written. + * @max: Pointer to number of raw events available in buffer. + * Will be decremented for each raw event written. + * @pulse_width: Width of pulse in ns. + * @space_width: Width of space in ns. + * + * Returns: 0 on success. + * -ENOBUFS if there isn't enough buffer space to write both raw + * events. In this case @max events will have been written. + */ +static inline int ir_raw_gen_pulse_space(struct ir_raw_event **ev, + unsigned int *max, + unsigned int pulse_width, + unsigned int space_width) +{ + if (!*max) + return -ENOBUFS; + init_ir_raw_event_duration((*ev)++, 1, pulse_width); + if (!--*max) + return -ENOBUFS; + init_ir_raw_event_duration((*ev)++, 0, space_width); + --*max; + return 0; +} + +/** + * struct ir_raw_timings_pd - pulse-distance modulation timings + * @header_pulse: duration of header pulse in ns (0 for none) + * @header_space: duration of header space in ns + * @bit_pulse: duration of bit pulse in ns + * @bit_space: duration of bit space (for logic 0 and 1) in ns + * @trailer_pulse: duration of trailer pulse in ns + * @trailer_space: duration of trailer space in ns + * @msb_first: 1 if most significant bit is sent first + */ +struct ir_raw_timings_pd { + unsigned int header_pulse; + unsigned int header_space; + unsigned int bit_pulse; + unsigned int bit_space[2]; + unsigned int trailer_pulse; + unsigned int trailer_space; + unsigned int msb_first:1; +}; + +int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_pd *timings, + unsigned int n, u64 data); + +/** + * struct ir_raw_timings_pl - pulse-length modulation timings + * @header_pulse: duration of header pulse in ns (0 for none) + * @bit_space: duration of bit space in ns + * @bit_pulse: duration of bit pulse (for logic 0 and 1) in ns + * @trailer_space: duration of trailer space in ns + * @msb_first: 1 if most significant bit is sent first + */ +struct ir_raw_timings_pl { + unsigned int header_pulse; + unsigned int bit_space; + unsigned int bit_pulse[2]; + unsigned int trailer_space; + unsigned int msb_first:1; +}; + +int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_pl *timings, + unsigned int n, u64 data); + /* * Routines from rc-raw.c to be used internally and by decoders */ diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 1c42a9f2f290..7fa84b64a2ae 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -17,7 +17,6 @@ #include <linux/mutex.h> #include <linux/kmod.h> #include <linux/sched.h> -#include <linux/freezer.h> #include "rc-core-priv.h" /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ @@ -34,32 +33,26 @@ static int ir_raw_event_thread(void *data) struct ir_raw_handler *handler; struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; - while (!kthread_should_stop()) { - - spin_lock_irq(&raw->lock); - - if (!kfifo_len(&raw->kfifo)) { - set_current_state(TASK_INTERRUPTIBLE); - - if (kthread_should_stop()) - set_current_state(TASK_RUNNING); - - spin_unlock_irq(&raw->lock); - schedule(); - continue; + while (1) { + mutex_lock(&ir_raw_handler_lock); + while (kfifo_out(&raw->kfifo, &ev, 1)) { + list_for_each_entry(handler, &ir_raw_handler_list, list) + if (raw->dev->enabled_protocols & + handler->protocols || !handler->protocols) + handler->decode(raw->dev, ev); + raw->prev_ev = ev; } + mutex_unlock(&ir_raw_handler_lock); - if(!kfifo_out(&raw->kfifo, &ev, 1)) - dev_err(&raw->dev->dev, "IR event FIFO is empty!\n"); - spin_unlock_irq(&raw->lock); + set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&ir_raw_handler_lock); - list_for_each_entry(handler, &ir_raw_handler_list, list) - if (raw->dev->enabled_protocols & handler->protocols || - !handler->protocols) - handler->decode(raw->dev, ev); - raw->prev_ev = ev; - mutex_unlock(&ir_raw_handler_lock); + if (kthread_should_stop()) { + __set_current_state(TASK_RUNNING); + break; + } else if (!kfifo_is_empty(&raw->kfifo)) + set_current_state(TASK_RUNNING); + + schedule(); } return 0; @@ -218,14 +211,10 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); */ void ir_raw_event_handle(struct rc_dev *dev) { - unsigned long flags; - if (!dev->raw) return; - spin_lock_irqsave(&dev->raw->lock, flags); wake_up_process(dev->raw->thread); - spin_unlock_irqrestore(&dev->raw->lock, flags); } EXPORT_SYMBOL_GPL(ir_raw_event_handle); @@ -246,10 +235,254 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols) { mutex_lock(&dev->lock); dev->enabled_protocols &= ~protocols; - dev->enabled_wakeup_protocols &= ~protocols; mutex_unlock(&dev->lock); } +/** + * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation. + * @ev: Pointer to pointer to next free event. *@ev is incremented for + * each raw event filled. + * @max: Maximum number of raw events to fill. + * @timings: Manchester modulation timings. + * @n: Number of bits of data. + * @data: Data bits to encode. + * + * Encodes the @n least significant bits of @data using Manchester (bi-phase) + * modulation with the timing characteristics described by @timings, writing up + * to @max raw IR events using the *@ev pointer. + * + * Returns: 0 on success. + * -ENOBUFS if there isn't enough space in the array to fit the + * full encoded data. In this case all @max events will have been + * written. + */ +int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_manchester *timings, + unsigned int n, unsigned int data) +{ + bool need_pulse; + unsigned int i; + int ret = -ENOBUFS; + + i = 1 << (n - 1); + + if (timings->leader) { + if (!max--) + return ret; + if (timings->pulse_space_start) { + init_ir_raw_event_duration((*ev)++, 1, timings->leader); + + if (!max--) + return ret; + init_ir_raw_event_duration((*ev), 0, timings->leader); + } else { + init_ir_raw_event_duration((*ev), 1, timings->leader); + } + i >>= 1; + } else { + /* continue existing signal */ + --(*ev); + } + /* from here on *ev will point to the last event rather than the next */ + + while (n && i > 0) { + need_pulse = !(data & i); + if (timings->invert) + need_pulse = !need_pulse; + if (need_pulse == !!(*ev)->pulse) { + (*ev)->duration += timings->clock; + } else { + if (!max--) + goto nobufs; + init_ir_raw_event_duration(++(*ev), need_pulse, + timings->clock); + } + + if (!max--) + goto nobufs; + init_ir_raw_event_duration(++(*ev), !need_pulse, + timings->clock); + i >>= 1; + } + + if (timings->trailer_space) { + if (!(*ev)->pulse) + (*ev)->duration += timings->trailer_space; + else if (!max--) + goto nobufs; + else + init_ir_raw_event_duration(++(*ev), 0, + timings->trailer_space); + } + + ret = 0; +nobufs: + /* point to the next event rather than last event before returning */ + ++(*ev); + return ret; +} +EXPORT_SYMBOL(ir_raw_gen_manchester); + +/** + * ir_raw_gen_pd() - Encode data to raw events with pulse-distance modulation. + * @ev: Pointer to pointer to next free event. *@ev is incremented for + * each raw event filled. + * @max: Maximum number of raw events to fill. + * @timings: Pulse distance modulation timings. + * @n: Number of bits of data. + * @data: Data bits to encode. + * + * Encodes the @n least significant bits of @data using pulse-distance + * modulation with the timing characteristics described by @timings, writing up + * to @max raw IR events using the *@ev pointer. + * + * Returns: 0 on success. + * -ENOBUFS if there isn't enough space in the array to fit the + * full encoded data. In this case all @max events will have been + * written. + */ +int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_pd *timings, + unsigned int n, u64 data) +{ + int i; + int ret; + unsigned int space; + + if (timings->header_pulse) { + ret = ir_raw_gen_pulse_space(ev, &max, timings->header_pulse, + timings->header_space); + if (ret) + return ret; + } + + if (timings->msb_first) { + for (i = n - 1; i >= 0; --i) { + space = timings->bit_space[(data >> i) & 1]; + ret = ir_raw_gen_pulse_space(ev, &max, + timings->bit_pulse, + space); + if (ret) + return ret; + } + } else { + for (i = 0; i < n; ++i, data >>= 1) { + space = timings->bit_space[data & 1]; + ret = ir_raw_gen_pulse_space(ev, &max, + timings->bit_pulse, + space); + if (ret) + return ret; + } + } + + ret = ir_raw_gen_pulse_space(ev, &max, timings->trailer_pulse, + timings->trailer_space); + return ret; +} +EXPORT_SYMBOL(ir_raw_gen_pd); + +/** + * ir_raw_gen_pl() - Encode data to raw events with pulse-length modulation. + * @ev: Pointer to pointer to next free event. *@ev is incremented for + * each raw event filled. + * @max: Maximum number of raw events to fill. + * @timings: Pulse distance modulation timings. + * @n: Number of bits of data. + * @data: Data bits to encode. + * + * Encodes the @n least significant bits of @data using space-distance + * modulation with the timing characteristics described by @timings, writing up + * to @max raw IR events using the *@ev pointer. + * + * Returns: 0 on success. + * -ENOBUFS if there isn't enough space in the array to fit the + * full encoded data. In this case all @max events will have been + * written. + */ +int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max, + const struct ir_raw_timings_pl *timings, + unsigned int n, u64 data) +{ + int i; + int ret = -ENOBUFS; + unsigned int pulse; + + if (!max--) + return ret; + + init_ir_raw_event_duration((*ev)++, 1, timings->header_pulse); + + if (timings->msb_first) { + for (i = n - 1; i >= 0; --i) { + if (!max--) + return ret; + init_ir_raw_event_duration((*ev)++, 0, + timings->bit_space); + if (!max--) + return ret; + pulse = timings->bit_pulse[(data >> i) & 1]; + init_ir_raw_event_duration((*ev)++, 1, pulse); + } + } else { + for (i = 0; i < n; ++i, data >>= 1) { + if (!max--) + return ret; + init_ir_raw_event_duration((*ev)++, 0, + timings->bit_space); + if (!max--) + return ret; + pulse = timings->bit_pulse[data & 1]; + init_ir_raw_event_duration((*ev)++, 1, pulse); + } + } + + if (!max--) + return ret; + + init_ir_raw_event_duration((*ev)++, 0, timings->trailer_space); + + return 0; +} +EXPORT_SYMBOL(ir_raw_gen_pl); + +/** + * ir_raw_encode_scancode() - Encode a scancode as raw events + * + * @protocol: protocol + * @scancode: scancode filter describing a single scancode + * @events: array of raw events to write into + * @max: max number of raw events + * + * Attempts to encode the scancode as raw events. + * + * Returns: The number of events written. + * -ENOBUFS if there isn't enough space in the array to fit the + * encoding. In this case all @max events will have been written. + * -EINVAL if the scancode is ambiguous or invalid, or if no + * compatible encoder was found. + */ +int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_handler *handler; + int ret = -EINVAL; + u64 mask = 1ULL << protocol; + + mutex_lock(&ir_raw_handler_lock); + list_for_each_entry(handler, &ir_raw_handler_list, list) { + if (handler->protocols & mask && handler->encode) { + ret = handler->encode(protocol, scancode, events, max); + if (ret >= 0 || ret == -ENOBUFS) + break; + } + } + mutex_unlock(&ir_raw_handler_lock); + + return ret; +} +EXPORT_SYMBOL(ir_raw_encode_scancode); + /* * Used to (un)register raw event clients */ @@ -269,13 +502,18 @@ int ir_raw_event_register(struct rc_dev *dev) dev->change_protocol = change_protocol; INIT_KFIFO(dev->raw->kfifo); - spin_lock_init(&dev->raw->lock); - dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, - "rc%u", dev->minor); + /* + * raw transmitters do not need any event registration + * because the event is coming from userspace + */ + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { + dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, + "rc%u", dev->minor); - if (IS_ERR(dev->raw->thread)) { - rc = PTR_ERR(dev->raw->thread); - goto out; + if (IS_ERR(dev->raw->thread)) { + rc = PTR_ERR(dev->raw->thread); + goto out; + } } mutex_lock(&ir_raw_handler_lock); diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 63dace8198b0..62195af24fbe 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -17,15 +17,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <linux/device.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/slab.h> #include <media/rc-core.h> #define DRIVER_NAME "rc-loopback" @@ -176,12 +173,47 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable) return 0; } +static int loop_set_wakeup_filter(struct rc_dev *dev, + struct rc_scancode_filter *sc) +{ + static const unsigned int max = 512; + struct ir_raw_event *raw; + int ret; + int i; + + /* fine to disable filter */ + if (!sc->mask) + return 0; + + /* encode the specified filter and loop it back */ + raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL); + if (!raw) + return -ENOMEM; + + ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc->data, raw, max); + /* still loop back the partial raw IR even if it's incomplete */ + if (ret == -ENOBUFS) + ret = max; + if (ret >= 0) { + /* do the loopback */ + for (i = 0; i < ret; ++i) + ir_raw_event_store(dev, &raw[i]); + ir_raw_event_handle(dev); + + ret = 0; + } + + kfree(raw); + + return ret; +} + static int __init loop_init(void) { struct rc_dev *rc; int ret; - rc = rc_allocate_device(); + rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rc) { printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n"); return -ENOMEM; @@ -194,8 +226,9 @@ static int __init loop_init(void) rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_EMPTY; rc->priv = &loopdev; - rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protocols = RC_BIT_ALL; + rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rc->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER; + rc->encode_wakeup = true; rc->timeout = 100 * 1000 * 1000; /* 100 ms */ rc->min_timeout = 1; rc->max_timeout = UINT_MAX; @@ -209,6 +242,7 @@ static int __init loop_init(void) rc->s_idle = loop_set_idle; rc->s_learning_mode = loop_set_learning_mode; rc->s_carrier_report = loop_set_carrier_report; + rc->s_wakeup_filter = loop_set_wakeup_filter; loopdev.txmask = RXMASK_REGULAR; loopdev.txcarrier = 36000; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index dedaf38c5ff6..2424946740e6 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -724,6 +724,72 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, } EXPORT_SYMBOL_GPL(rc_keydown_notimeout); +/** + * rc_validate_filter() - checks that the scancode and mask are valid and + * provides sensible defaults + * @dev: the struct rc_dev descriptor of the device + * @filter: the scancode and mask + * @return: 0 or -EINVAL if the filter is not valid + */ +static int rc_validate_filter(struct rc_dev *dev, + struct rc_scancode_filter *filter) +{ + static u32 masks[] = { + [RC_TYPE_RC5] = 0x1f7f, + [RC_TYPE_RC5X_20] = 0x1f7f3f, + [RC_TYPE_RC5_SZ] = 0x2fff, + [RC_TYPE_SONY12] = 0x1f007f, + [RC_TYPE_SONY15] = 0xff007f, + [RC_TYPE_SONY20] = 0x1fff7f, + [RC_TYPE_JVC] = 0xffff, + [RC_TYPE_NEC] = 0xffff, + [RC_TYPE_NECX] = 0xffffff, + [RC_TYPE_NEC32] = 0xffffffff, + [RC_TYPE_SANYO] = 0x1fffff, + [RC_TYPE_RC6_0] = 0xffff, + [RC_TYPE_RC6_6A_20] = 0xfffff, + [RC_TYPE_RC6_6A_24] = 0xffffff, + [RC_TYPE_RC6_6A_32] = 0xffffffff, + [RC_TYPE_RC6_MCE] = 0xffff7fff, + [RC_TYPE_SHARP] = 0x1fff, + }; + u32 s = filter->data; + enum rc_type protocol = dev->wakeup_protocol; + + switch (protocol) { + case RC_TYPE_NECX: + if ((((s >> 16) ^ ~(s >> 8)) & 0xff) == 0) + return -EINVAL; + break; + case RC_TYPE_NEC32: + if ((((s >> 24) ^ ~(s >> 16)) & 0xff) == 0) + return -EINVAL; + break; + case RC_TYPE_RC6_MCE: + if ((s & 0xffff0000) != 0x800f0000) + return -EINVAL; + break; + case RC_TYPE_RC6_6A_32: + if ((s & 0xffff0000) == 0x800f0000) + return -EINVAL; + break; + default: + break; + } + + filter->data &= masks[protocol]; + filter->mask &= masks[protocol]; + + /* + * If we have to raw encode the IR for wakeup, we cannot have a mask + */ + if (dev->encode_wakeup && + filter->mask != 0 && filter->mask != masks[protocol]) + return -EINVAL; + + return 0; +} + int rc_open(struct rc_dev *rdev) { int rval = 0; @@ -796,7 +862,7 @@ static const struct { { RC_BIT_OTHER, "other", NULL }, { RC_BIT_UNKNOWN, "unknown", NULL }, { RC_BIT_RC5 | - RC_BIT_RC5X, "rc-5", "ir-rc5-decoder" }, + RC_BIT_RC5X_20, "rc-5", "ir-rc5-decoder" }, { RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32, "nec", "ir-nec-decoder" }, @@ -830,11 +896,6 @@ struct rc_filter_attribute { }; #define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr) -#define RC_PROTO_ATTR(_name, _mode, _show, _store, _type) \ - struct rc_filter_attribute dev_attr_##_name = { \ - .attr = __ATTR(_name, _mode, _show, _store), \ - .type = (_type), \ - } #define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \ struct rc_filter_attribute dev_attr_##_name = { \ .attr = __ATTR(_name, _mode, _show, _store), \ @@ -860,13 +921,13 @@ static bool lirc_is_present(void) } /** - * show_protocols() - shows the current/wakeup IR protocol(s) + * show_protocols() - shows the current IR protocol(s) * @device: the device descriptor * @mattr: the device attribute struct * @buf: a pointer to the output buffer * * This routine is a callback routine for input read the IR protocol type(s). - * it is trigged by reading /sys/class/rc/rc?/[wakeup_]protocols. + * it is trigged by reading /sys/class/rc/rc?/protocols. * It returns the protocol names of supported protocols. * Enabled protocols are printed in brackets. * @@ -877,7 +938,6 @@ static ssize_t show_protocols(struct device *device, struct device_attribute *mattr, char *buf) { struct rc_dev *dev = to_rc_dev(device); - struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); u64 allowed, enabled; char *tmp = buf; int i; @@ -891,15 +951,10 @@ static ssize_t show_protocols(struct device *device, mutex_lock(&dev->lock); - if (fattr->type == RC_FILTER_NORMAL) { - enabled = dev->enabled_protocols; - allowed = dev->allowed_protocols; - if (dev->raw && !allowed) - allowed = ir_raw_get_allowed_protocols(); - } else { - enabled = dev->enabled_wakeup_protocols; - allowed = dev->allowed_wakeup_protocols; - } + enabled = dev->enabled_protocols; + allowed = dev->allowed_protocols; + if (dev->raw && !allowed) + allowed = ir_raw_get_allowed_protocols(); mutex_unlock(&dev->lock); @@ -997,7 +1052,6 @@ static int parse_protocol_change(u64 *protocols, const char *buf) } static void ir_raw_load_modules(u64 *protocols) - { u64 available; int i, ret; @@ -1030,8 +1084,7 @@ static void ir_raw_load_modules(u64 *protocols) if (!(*protocols & proto_names[i].type & ~available)) continue; - pr_err("Loaded IR protocol module %s, \ - but protocol %s still not available\n", + pr_err("Loaded IR protocol module %s, but protocol %s still not available\n", proto_names[i].module_name, proto_names[i].name); *protocols &= ~proto_names[i].type; @@ -1058,11 +1111,8 @@ static ssize_t store_protocols(struct device *device, const char *buf, size_t len) { struct rc_dev *dev = to_rc_dev(device); - struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); u64 *current_protocols; - int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); struct rc_scancode_filter *filter; - int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); u64 old_protocols, new_protocols; ssize_t rc; @@ -1073,21 +1123,11 @@ static ssize_t store_protocols(struct device *device, if (!atomic_read(&dev->initialized)) return -ERESTARTSYS; - if (fattr->type == RC_FILTER_NORMAL) { - IR_dprintk(1, "Normal protocol change requested\n"); - current_protocols = &dev->enabled_protocols; - change_protocol = dev->change_protocol; - filter = &dev->scancode_filter; - set_filter = dev->s_filter; - } else { - IR_dprintk(1, "Wakeup protocol change requested\n"); - current_protocols = &dev->enabled_wakeup_protocols; - change_protocol = dev->change_wakeup_protocol; - filter = &dev->scancode_wakeup_filter; - set_filter = dev->s_wakeup_filter; - } + IR_dprintk(1, "Normal protocol change requested\n"); + current_protocols = &dev->enabled_protocols; + filter = &dev->scancode_filter; - if (!change_protocol) { + if (!dev->change_protocol) { IR_dprintk(1, "Protocol switching not supported\n"); return -EINVAL; } @@ -1100,7 +1140,7 @@ static ssize_t store_protocols(struct device *device, if (rc < 0) goto out; - rc = change_protocol(dev, &new_protocols); + rc = dev->change_protocol(dev, &new_protocols); if (rc < 0) { IR_dprintk(1, "Error setting protocols to 0x%llx\n", (long long)new_protocols); @@ -1123,16 +1163,16 @@ static ssize_t store_protocols(struct device *device, * Try setting the same filter with the new protocol (if any). * Fall back to clearing the filter. */ - if (set_filter && filter->mask) { + if (dev->s_filter && filter->mask) { if (new_protocols) - rc = set_filter(dev, filter); + rc = dev->s_filter(dev, filter); else rc = -1; if (rc < 0) { filter->data = 0; filter->mask = 0; - set_filter(dev, filter); + dev->s_filter(dev, filter); } } @@ -1221,7 +1261,6 @@ static ssize_t store_filter(struct device *device, int ret; unsigned long val; int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); - u64 *enabled_protocols; /* Device is being removed */ if (!dev) @@ -1236,11 +1275,9 @@ static ssize_t store_filter(struct device *device, if (fattr->type == RC_FILTER_NORMAL) { set_filter = dev->s_filter; - enabled_protocols = &dev->enabled_protocols; filter = &dev->scancode_filter; } else { set_filter = dev->s_wakeup_filter; - enabled_protocols = &dev->enabled_wakeup_protocols; filter = &dev->scancode_wakeup_filter; } @@ -1255,7 +1292,22 @@ static ssize_t store_filter(struct device *device, else new_filter.data = val; - if (!*enabled_protocols && val) { + if (fattr->type == RC_FILTER_WAKEUP) { + /* + * Refuse to set a filter unless a protocol is enabled + * and the filter is valid for that protocol + */ + if (dev->wakeup_protocol != RC_TYPE_UNKNOWN) + ret = rc_validate_filter(dev, &new_filter); + else + ret = -EINVAL; + + if (ret != 0) + goto unlock; + } + + if (fattr->type == RC_FILTER_NORMAL && !dev->enabled_protocols && + val) { /* refuse to set a filter unless a protocol is enabled */ ret = -EINVAL; goto unlock; @@ -1272,6 +1324,182 @@ unlock: return (ret < 0) ? ret : len; } +/* + * This is the list of all variants of all protocols, which is used by + * the wakeup_protocols sysfs entry. In the protocols sysfs entry some + * some protocols are grouped together (e.g. nec = nec + necx + nec32). + * + * For wakeup we need to know the exact protocol variant so the hardware + * can be programmed exactly what to expect. + */ +static const char * const proto_variant_names[] = { + [RC_TYPE_UNKNOWN] = "unknown", + [RC_TYPE_OTHER] = "other", + [RC_TYPE_RC5] = "rc-5", + [RC_TYPE_RC5X_20] = "rc-5x-20", + [RC_TYPE_RC5_SZ] = "rc-5-sz", + [RC_TYPE_JVC] = "jvc", + [RC_TYPE_SONY12] = "sony-12", + [RC_TYPE_SONY15] = "sony-15", + [RC_TYPE_SONY20] = "sony-20", + [RC_TYPE_NEC] = "nec", + [RC_TYPE_NECX] = "nec-x", + [RC_TYPE_NEC32] = "nec-32", + [RC_TYPE_SANYO] = "sanyo", + [RC_TYPE_MCE_KBD] = "mce_kbd", + [RC_TYPE_RC6_0] = "rc-6-0", + [RC_TYPE_RC6_6A_20] = "rc-6-6a-20", + [RC_TYPE_RC6_6A_24] = "rc-6-6a-24", + [RC_TYPE_RC6_6A_32] = "rc-6-6a-32", + [RC_TYPE_RC6_MCE] = "rc-6-mce", + [RC_TYPE_SHARP] = "sharp", + [RC_TYPE_XMP] = "xmp", + [RC_TYPE_CEC] = "cec", +}; + +/** + * show_wakeup_protocols() - shows the wakeup IR protocol + * @device: the device descriptor + * @mattr: the device attribute struct + * @buf: a pointer to the output buffer + * + * This routine is a callback routine for input read the IR protocol type(s). + * it is trigged by reading /sys/class/rc/rc?/wakeup_protocols. + * It returns the protocol names of supported protocols. + * The enabled protocols are printed in brackets. + * + * dev->lock is taken to guard against races between device + * registration, store_protocols and show_protocols. + */ +static ssize_t show_wakeup_protocols(struct device *device, + struct device_attribute *mattr, + char *buf) +{ + struct rc_dev *dev = to_rc_dev(device); + u64 allowed; + enum rc_type enabled; + char *tmp = buf; + int i; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + if (!atomic_read(&dev->initialized)) + return -ERESTARTSYS; + + mutex_lock(&dev->lock); + + allowed = dev->allowed_wakeup_protocols; + enabled = dev->wakeup_protocol; + + mutex_unlock(&dev->lock); + + IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n", + __func__, (long long)allowed, enabled); + + for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) { + if (allowed & (1ULL << i)) { + if (i == enabled) + tmp += sprintf(tmp, "[%s] ", + proto_variant_names[i]); + else + tmp += sprintf(tmp, "%s ", + proto_variant_names[i]); + } + } + + if (tmp != buf) + tmp--; + *tmp = '\n'; + + return tmp + 1 - buf; +} + +/** + * store_wakeup_protocols() - changes the wakeup IR protocol(s) + * @device: the device descriptor + * @mattr: the device attribute struct + * @buf: a pointer to the input buffer + * @len: length of the input buffer + * + * This routine is for changing the IR protocol type. + * It is trigged by writing to /sys/class/rc/rc?/wakeup_protocols. + * Returns @len on success or a negative error code. + * + * dev->lock is taken to guard against races between device + * registration, store_protocols and show_protocols. + */ +static ssize_t store_wakeup_protocols(struct device *device, + struct device_attribute *mattr, + const char *buf, size_t len) +{ + struct rc_dev *dev = to_rc_dev(device); + enum rc_type protocol; + ssize_t rc; + u64 allowed; + int i; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + if (!atomic_read(&dev->initialized)) + return -ERESTARTSYS; + + mutex_lock(&dev->lock); + + allowed = dev->allowed_wakeup_protocols; + + if (sysfs_streq(buf, "none")) { + protocol = RC_TYPE_UNKNOWN; + } else { + for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) { + if ((allowed & (1ULL << i)) && + sysfs_streq(buf, proto_variant_names[i])) { + protocol = i; + break; + } + } + + if (i == ARRAY_SIZE(proto_variant_names)) { + rc = -EINVAL; + goto out; + } + + if (dev->encode_wakeup) { + u64 mask = 1ULL << protocol; + + ir_raw_load_modules(&mask); + if (!mask) { + rc = -EINVAL; + goto out; + } + } + } + + if (dev->wakeup_protocol != protocol) { + dev->wakeup_protocol = protocol; + IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol); + + if (protocol == RC_TYPE_RC6_MCE) + dev->scancode_wakeup_filter.data = 0x800f0000; + else + dev->scancode_wakeup_filter.data = 0; + dev->scancode_wakeup_filter.mask = 0; + + rc = dev->s_wakeup_filter(dev, &dev->scancode_wakeup_filter); + if (rc == 0) + rc = len; + } else { + rc = len; + } + +out: + mutex_unlock(&dev->lock); + return rc; +} + static void rc_dev_release(struct device *device) { struct rc_dev *dev = to_rc_dev(device); @@ -1301,10 +1529,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) /* * Static device attribute struct with the sysfs attributes for IR's */ -static RC_PROTO_ATTR(protocols, S_IRUGO | S_IWUSR, - show_protocols, store_protocols, RC_FILTER_NORMAL); -static RC_PROTO_ATTR(wakeup_protocols, S_IRUGO | S_IWUSR, - show_protocols, store_protocols, RC_FILTER_WAKEUP); +static DEVICE_ATTR(protocols, 0644, show_protocols, store_protocols); +static DEVICE_ATTR(wakeup_protocols, 0644, show_wakeup_protocols, + store_wakeup_protocols); static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR, show_filter, store_filter, RC_FILTER_NORMAL, false); static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR, @@ -1315,7 +1542,7 @@ static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR, show_filter, store_filter, RC_FILTER_WAKEUP, true); static struct attribute *rc_dev_protocol_attrs[] = { - &dev_attr_protocols.attr.attr, + &dev_attr_protocols.attr, NULL, }; @@ -1323,15 +1550,6 @@ static struct attribute_group rc_dev_protocol_attr_grp = { .attrs = rc_dev_protocol_attrs, }; -static struct attribute *rc_dev_wakeup_protocol_attrs[] = { - &dev_attr_wakeup_protocols.attr.attr, - NULL, -}; - -static struct attribute_group rc_dev_wakeup_protocol_attr_grp = { - .attrs = rc_dev_wakeup_protocol_attrs, -}; - static struct attribute *rc_dev_filter_attrs[] = { &dev_attr_filter.attr.attr, &dev_attr_filter_mask.attr.attr, @@ -1345,6 +1563,7 @@ static struct attribute_group rc_dev_filter_attr_grp = { static struct attribute *rc_dev_wakeup_filter_attrs[] = { &dev_attr_wakeup_filter.attr.attr, &dev_attr_wakeup_filter_mask.attr.attr, + &dev_attr_wakeup_protocols.attr, NULL, }; @@ -1357,7 +1576,7 @@ static struct device_type rc_dev_type = { .uevent = rc_dev_uevent, }; -struct rc_dev *rc_allocate_device(void) +struct rc_dev *rc_allocate_device(enum rc_driver_type type) { struct rc_dev *dev; @@ -1365,25 +1584,31 @@ struct rc_dev *rc_allocate_device(void) if (!dev) return NULL; - dev->input_dev = input_allocate_device(); - if (!dev->input_dev) { - kfree(dev); - return NULL; - } + if (type != RC_DRIVER_IR_RAW_TX) { + dev->input_dev = input_allocate_device(); + if (!dev->input_dev) { + kfree(dev); + return NULL; + } - dev->input_dev->getkeycode = ir_getkeycode; - dev->input_dev->setkeycode = ir_setkeycode; - input_set_drvdata(dev->input_dev, dev); + dev->input_dev->getkeycode = ir_getkeycode; + dev->input_dev->setkeycode = ir_setkeycode; + input_set_drvdata(dev->input_dev, dev); - spin_lock_init(&dev->rc_map.lock); - spin_lock_init(&dev->keylock); + setup_timer(&dev->timer_keyup, ir_timer_keyup, + (unsigned long)dev); + + spin_lock_init(&dev->rc_map.lock); + spin_lock_init(&dev->keylock); + } mutex_init(&dev->lock); - setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev); dev->dev.type = &rc_dev_type; dev->dev.class = &rc_class; device_initialize(&dev->dev); + dev->driver_type = type; + __module_get(THIS_MODULE); return dev; } @@ -1410,7 +1635,8 @@ static void devm_rc_alloc_release(struct device *dev, void *res) rc_free_device(*(struct rc_dev **)res); } -struct rc_dev *devm_rc_allocate_device(struct device *dev) +struct rc_dev *devm_rc_allocate_device(struct device *dev, + enum rc_driver_type type) { struct rc_dev **dr, *rc; @@ -1418,7 +1644,7 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev) if (!dr) return NULL; - rc = rc_allocate_device(); + rc = rc_allocate_device(type); if (!rc) { devres_free(dr); return NULL; @@ -1433,16 +1659,12 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev) } EXPORT_SYMBOL_GPL(devm_rc_allocate_device); -int rc_register_device(struct rc_dev *dev) +static int rc_setup_rx_device(struct rc_dev *dev) { - static bool raw_init = false; /* raw decoders loaded? */ - struct rc_map *rc_map; - const char *path; - int attr = 0; - int minor; int rc; + struct rc_map *rc_map; - if (!dev || !dev->map_name) + if (!dev->map_name) return -EINVAL; rc_map = rc_map_get(dev->map_name); @@ -1451,6 +1673,19 @@ int rc_register_device(struct rc_dev *dev) if (!rc_map || !rc_map->scan || rc_map->size == 0) return -EINVAL; + rc = ir_setkeytable(dev, rc_map); + if (rc) + return rc; + + if (dev->change_protocol) { + u64 rc_type = (1ll << rc_map->rc_type); + + rc = dev->change_protocol(dev, &rc_type); + if (rc < 0) + goto out_table; + dev->enabled_protocols = rc_type; + } + set_bit(EV_KEY, dev->input_dev->evbit); set_bit(EV_REP, dev->input_dev->evbit); set_bit(EV_MSC, dev->input_dev->evbit); @@ -1460,6 +1695,61 @@ int rc_register_device(struct rc_dev *dev) if (dev->close) dev->input_dev->close = ir_close; + /* + * Default delay of 250ms is too short for some protocols, especially + * since the timeout is currently set to 250ms. Increase it to 500ms, + * to avoid wrong repetition of the keycodes. Note that this must be + * set after the call to input_register_device(). + */ + dev->input_dev->rep[REP_DELAY] = 500; + + /* + * As a repeat event on protocols like RC-5 and NEC take as long as + * 110/114ms, using 33ms as a repeat period is not the right thing + * to do. + */ + dev->input_dev->rep[REP_PERIOD] = 125; + + dev->input_dev->dev.parent = &dev->dev; + memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id)); + dev->input_dev->phys = dev->input_phys; + dev->input_dev->name = dev->input_name; + + /* rc_open will be called here */ + rc = input_register_device(dev->input_dev); + if (rc) + goto out_table; + + return 0; + +out_table: + ir_free_table(&dev->rc_map); + + return rc; +} + +static void rc_free_rx_device(struct rc_dev *dev) +{ + if (!dev || dev->driver_type == RC_DRIVER_IR_RAW_TX) + return; + + ir_free_table(&dev->rc_map); + + input_unregister_device(dev->input_dev); + dev->input_dev = NULL; +} + +int rc_register_device(struct rc_dev *dev) +{ + static bool raw_init; /* 'false' default value, raw decoders loaded? */ + const char *path; + int attr = 0; + int minor; + int rc; + + if (!dev) + return -EINVAL; + minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL); if (minor < 0) return minor; @@ -1470,89 +1760,51 @@ int rc_register_device(struct rc_dev *dev) atomic_set(&dev->initialized, 0); dev->dev.groups = dev->sysfs_groups; - dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) + dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; if (dev->s_filter) dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp; if (dev->s_wakeup_filter) dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp; - if (dev->change_wakeup_protocol) - dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp; dev->sysfs_groups[attr++] = NULL; rc = device_add(&dev->dev); if (rc) goto out_unlock; - rc = ir_setkeytable(dev, rc_map); - if (rc) - goto out_dev; - - dev->input_dev->dev.parent = &dev->dev; - memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id)); - dev->input_dev->phys = dev->input_phys; - dev->input_dev->name = dev->input_name; - - rc = input_register_device(dev->input_dev); - if (rc) - goto out_table; - - /* - * Default delay of 250ms is too short for some protocols, especially - * since the timeout is currently set to 250ms. Increase it to 500ms, - * to avoid wrong repetition of the keycodes. Note that this must be - * set after the call to input_register_device(). - */ - dev->input_dev->rep[REP_DELAY] = 500; - - /* - * As a repeat event on protocols like RC-5 and NEC take as long as - * 110/114ms, using 33ms as a repeat period is not the right thing - * to do. - */ - dev->input_dev->rep[REP_PERIOD] = 125; - path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); dev_info(&dev->dev, "%s as %s\n", dev->input_name ?: "Unspecified device", path ?: "N/A"); kfree(path); - if (dev->driver_type == RC_DRIVER_IR_RAW) { + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { + rc = rc_setup_rx_device(dev); + if (rc) + goto out_dev; + } + + if (dev->driver_type == RC_DRIVER_IR_RAW || + dev->driver_type == RC_DRIVER_IR_RAW_TX) { if (!raw_init) { request_module_nowait("ir-lirc-codec"); raw_init = true; } rc = ir_raw_event_register(dev); if (rc < 0) - goto out_input; - } - - if (dev->change_protocol) { - u64 rc_type = (1ll << rc_map->rc_type); - rc = dev->change_protocol(dev, &rc_type); - if (rc < 0) - goto out_raw; - dev->enabled_protocols = rc_type; + goto out_rx; } /* Allow the RC sysfs nodes to be accessible */ atomic_set(&dev->initialized, 1); - IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", + IR_dprintk(1, "Registered rc%u (driver: %s)\n", dev->minor, - dev->driver_name ? dev->driver_name : "unknown", - rc_map->name ? rc_map->name : "unknown", - dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); + dev->driver_name ? dev->driver_name : "unknown"); return 0; -out_raw: - if (dev->driver_type == RC_DRIVER_IR_RAW) - ir_raw_event_unregister(dev); -out_input: - input_unregister_device(dev->input_dev); - dev->input_dev = NULL; -out_table: - ir_free_table(&dev->rc_map); +out_rx: + rc_free_rx_device(dev); out_dev: device_del(&dev->dev); out_unlock: @@ -1598,12 +1850,7 @@ void rc_unregister_device(struct rc_dev *dev) if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); - /* Freeing the table should also call the stop callback */ - ir_free_table(&dev->rc_map); - IR_dprintk(1, "Freed keycode table\n"); - - input_unregister_device(dev->input_dev); - dev->input_dev = NULL; + rc_free_rx_device(dev); device_del(&dev->dev); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 2784f5dae398..56d43be2756b 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -39,10 +39,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <asm/unaligned.h> @@ -945,7 +941,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) int ret; u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct); - rc = rc_allocate_device(); + rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rc) return NULL; @@ -960,8 +956,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) usb_to_input_id(rr3->udev, &rc->input_id); rc->dev.parent = dev; rc->priv = rr3; - rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protocols = RC_BIT_ALL; + rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); rc->timeout = US_TO_NS(redrat3_get_timeout(rr3)); diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index 436bd58b5f05..923fb2299553 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -137,6 +137,7 @@ struct serial_ir { ktime_t lastkt; struct rc_dev *rcdev; struct platform_device *pdev; + struct timer_list timeout_timer; unsigned int freq; unsigned int duty_cycle; @@ -395,9 +396,14 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah) frbwrite(data, !(dcd ^ sense)); serial_ir.lastkt = kt; last_dcd = dcd; - ir_raw_event_handle(serial_ir.rcdev); } } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ + + mod_timer(&serial_ir.timeout_timer, + jiffies + nsecs_to_jiffies(serial_ir.rcdev->timeout)); + + ir_raw_event_handle(serial_ir.rcdev); + return IRQ_HANDLED; } @@ -471,6 +477,16 @@ static int hardware_init_port(void) return 0; } +static void serial_ir_timeout(unsigned long arg) +{ + DEFINE_IR_RAW_EVENT(ev); + + ev.timeout = true; + ev.duration = serial_ir.rcdev->timeout; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ir_raw_event_handle(serial_ir.rcdev); +} + static int serial_ir_probe(struct platform_device *dev) { int i, nlow, nhigh, result; @@ -500,6 +516,9 @@ static int serial_ir_probe(struct platform_device *dev) return -EBUSY; } + setup_timer(&serial_ir.timeout_timer, serial_ir_timeout, + (unsigned long)&serial_ir); + result = hardware_init_port(); if (result < 0) return result; @@ -738,7 +757,7 @@ static int __init serial_ir_init_module(void) if (result) return result; - rcdev = devm_rc_allocate_device(&serial_ir.pdev->dev); + rcdev = devm_rc_allocate_device(&serial_ir.pdev->dev, RC_DRIVER_IR_RAW); if (!rcdev) { result = -ENOMEM; goto serial_cleanup; @@ -777,11 +796,12 @@ static int __init serial_ir_init_module(void) rcdev->open = serial_ir_open; rcdev->close = serial_ir_close; rcdev->dev.parent = &serial_ir.pdev->dev; - rcdev->driver_type = RC_DRIVER_IR_RAW; - rcdev->allowed_protocols = RC_BIT_ALL; + rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; rcdev->driver_name = KBUILD_MODNAME; rcdev->map_name = RC_MAP_RC6_MCE; + rcdev->min_timeout = 1; rcdev->timeout = IR_DEFAULT_TIMEOUT; + rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; rcdev->rx_resolution = 250000; serial_ir.rcdev = rcdev; @@ -797,6 +817,7 @@ serial_cleanup: static void __exit serial_ir_exit_module(void) { + del_timer_sync(&serial_ir.timeout_timer); rc_unregister_device(serial_ir.rcdev); serial_ir_exit(); } diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 1fa0c9d1c508..f0d7190e3919 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -235,7 +235,7 @@ static int st_rc_probe(struct platform_device *pdev) if (!rc_dev) return -ENOMEM; - rdev = rc_allocate_device(); + rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rdev) return -ENOMEM; @@ -290,8 +290,7 @@ static int st_rc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rc_dev); st_rc_hardware_init(rc_dev); - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protocols = RC_BIT_ALL; + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; /* rx sampling rate is 10Mhz */ rdev->rx_resolution = 100; rdev->timeout = US_TO_NS(MAX_SYMB_TIME); diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 53f9b0af358a..b09c45abb5f3 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -25,10 +25,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/device.h> @@ -291,7 +287,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) struct device *dev = sz->dev; int ret; - rdev = rc_allocate_device(); + rdev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rdev) { dev_err(dev, "remote dev allocation failed\n"); goto out; @@ -308,8 +304,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) usb_to_input_id(sz->usbdev, &rdev->input_id); rdev->dev.parent = dev; rdev->priv = sz; - rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protocols = RC_BIT_ALL; + rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; rdev->driver_name = DRIVER_NAME; rdev->map_name = RC_MAP_STREAMZAP; diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index eaadc081760a..25b006167810 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -212,7 +212,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) goto exit_clkdisable_clk; } - ir->rc = rc_allocate_device(); + ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!ir->rc) { dev_err(dev, "failed to allocate device\n"); ret = -ENOMEM; @@ -229,8 +229,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL); ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY; ir->rc->dev.parent = dev; - ir->rc->driver_type = RC_DRIVER_IR_RAW; - ir->rc->allowed_protocols = RC_BIT_ALL; + ir->rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; ir->rc->rx_resolution = SUNXI_IR_SAMPLE; ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT); ir->rc->driver_name = SUNXI_IR_DEV; diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index bc214e2b3a36..23be7702e2df 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/module.h> @@ -205,7 +201,7 @@ static int ttusbir_probe(struct usb_interface *intf, int altsetting = -1; tt = kzalloc(sizeof(*tt), GFP_KERNEL); - rc = rc_allocate_device(); + rc = rc_allocate_device(RC_DRIVER_IR_RAW); if (!tt || !rc) { ret = -ENOMEM; goto out; @@ -317,12 +313,14 @@ static int ttusbir_probe(struct usb_interface *intf, rc->input_phys = tt->phys; usb_to_input_id(tt->udev, &rc->input_id); rc->dev.parent = &intf->dev; - rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protocols = RC_BIT_ALL; + rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; rc->priv = tt; rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_TT_1500; - rc->timeout = MS_TO_NS(100); + rc->min_timeout = 1; + rc->timeout = IR_DEFAULT_TIMEOUT; + rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; + /* * The precision is NS_PER_BIT, but since every 8th bit can be * overwritten with garbage the accuracy is at best 2 * NS_PER_BIT. diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 78491ed48d92..dc1c8305ad23 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -34,10 +34,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -194,7 +190,6 @@ enum wbcir_txstate { #define WBCIR_NAME "Winbond CIR" #define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ #define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ -#define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ #define WAKEUP_IOMEM_LEN 0x10 /* Wake-Up I/O Reg Len */ #define EHFUNC_IOMEM_LEN 0x10 /* Enhanced Func I/O Reg Len */ #define SP_IOMEM_LEN 0x08 /* Serial Port 3 (IR) Reg Len */ @@ -225,10 +220,6 @@ struct wbcir_data { u32 txcarrier; }; -static enum wbcir_protocol protocol = IR_PROTOCOL_RC6; -module_param(protocol, uint, 0444); -MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command (0 = RC5, 1 = NEC, 2 = RC6A, default)"); - static bool invert; /* default = 0 */ module_param(invert, bool, 0444); MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); @@ -237,15 +228,6 @@ static bool txandrx; /* default = 0 */ module_param(txandrx, bool, 0444); MODULE_PARM_DESC(txandrx, "Allow simultaneous TX and RX"); -static unsigned int wake_sc = 0x800F040C; -module_param(wake_sc, uint, 0644); -MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command"); - -static unsigned int wake_rc6mode = 6; -module_param(wake_rc6mode, uint, 0644); -MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command (0 = 0, 6 = 6A, default)"); - - /***************************************************************************** * @@ -696,138 +678,153 @@ wbcir_shutdown(struct pnp_dev *device) { struct device *dev = &device->dev; struct wbcir_data *data = pnp_get_drvdata(device); + struct rc_dev *rc = data->dev; bool do_wake = true; u8 match[11]; u8 mask[11]; u8 rc6_csl = 0; + u8 proto; + u32 wake_sc = rc->scancode_wakeup_filter.data; + u32 mask_sc = rc->scancode_wakeup_filter.mask; int i; memset(match, 0, sizeof(match)); memset(mask, 0, sizeof(mask)); - if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) { + if (!mask_sc || !device_may_wakeup(dev)) { do_wake = false; goto finish; } - switch (protocol) { - case IR_PROTOCOL_RC5: - if (wake_sc > 0xFFF) { - do_wake = false; - dev_err(dev, "RC5 - Invalid wake scancode\n"); - break; - } - + switch (rc->wakeup_protocol) { + case RC_TYPE_RC5: /* Mask = 13 bits, ex toggle */ - mask[0] = 0xFF; - mask[1] = 0x17; + mask[0] = (mask_sc & 0x003f); + mask[0] |= (mask_sc & 0x0300) >> 2; + mask[1] = (mask_sc & 0x1c00) >> 10; + if (mask_sc & 0x0040) /* 2nd start bit */ + match[1] |= 0x10; - match[0] = (wake_sc & 0x003F); /* 6 command bits */ - match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */ - match[1] = (wake_sc & 0x0E00) >> 9; /* 3 address bits */ - if (!(wake_sc & 0x0040)) /* 2nd start bit */ + match[0] = (wake_sc & 0x003F); /* 6 command bits */ + match[0] |= (wake_sc & 0x0300) >> 2; /* 2 address bits */ + match[1] = (wake_sc & 0x1c00) >> 10; /* 3 address bits */ + if (!(wake_sc & 0x0040)) /* 2nd start bit */ match[1] |= 0x10; + proto = IR_PROTOCOL_RC5; break; - case IR_PROTOCOL_NEC: - if (wake_sc > 0xFFFFFF) { - do_wake = false; - dev_err(dev, "NEC - Invalid wake scancode\n"); - break; - } + case RC_TYPE_NEC: + mask[1] = bitrev8(mask_sc); + mask[0] = mask[1]; + mask[3] = bitrev8(mask_sc >> 8); + mask[2] = mask[3]; - mask[0] = mask[1] = mask[2] = mask[3] = 0xFF; - - match[1] = bitrev8((wake_sc & 0xFF)); + match[1] = bitrev8(wake_sc); match[0] = ~match[1]; + match[3] = bitrev8(wake_sc >> 8); + match[2] = ~match[3]; - match[3] = bitrev8((wake_sc & 0xFF00) >> 8); - if (wake_sc > 0xFFFF) - match[2] = bitrev8((wake_sc & 0xFF0000) >> 16); - else - match[2] = ~match[3]; + proto = IR_PROTOCOL_NEC; + break; + + case RC_TYPE_NECX: + mask[1] = bitrev8(mask_sc); + mask[0] = mask[1]; + mask[2] = bitrev8(mask_sc >> 8); + mask[3] = bitrev8(mask_sc >> 16); + match[1] = bitrev8(wake_sc); + match[0] = ~match[1]; + match[2] = bitrev8(wake_sc >> 8); + match[3] = bitrev8(wake_sc >> 16); + + proto = IR_PROTOCOL_NEC; break; - case IR_PROTOCOL_RC6: + case RC_TYPE_NEC32: + mask[0] = bitrev8(mask_sc); + mask[1] = bitrev8(mask_sc >> 8); + mask[2] = bitrev8(mask_sc >> 16); + mask[3] = bitrev8(mask_sc >> 24); - if (wake_rc6mode == 0) { - if (wake_sc > 0xFFFF) { - do_wake = false; - dev_err(dev, "RC6 - Invalid wake scancode\n"); - break; - } + match[0] = bitrev8(wake_sc); + match[1] = bitrev8(wake_sc >> 8); + match[2] = bitrev8(wake_sc >> 16); + match[3] = bitrev8(wake_sc >> 24); - /* Command */ - match[0] = wbcir_to_rc6cells(wake_sc >> 0); - mask[0] = 0xFF; - match[1] = wbcir_to_rc6cells(wake_sc >> 4); - mask[1] = 0xFF; - - /* Address */ - match[2] = wbcir_to_rc6cells(wake_sc >> 8); - mask[2] = 0xFF; - match[3] = wbcir_to_rc6cells(wake_sc >> 12); - mask[3] = 0xFF; - - /* Header */ - match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */ - mask[4] = 0xF0; - match[5] = 0x09; /* start bit = 1, mode2 = 0 */ - mask[5] = 0x0F; - - rc6_csl = 44; - - } else if (wake_rc6mode == 6) { - i = 0; - - /* Command */ - match[i] = wbcir_to_rc6cells(wake_sc >> 0); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 4); - mask[i++] = 0xFF; - - /* Address + Toggle */ - match[i] = wbcir_to_rc6cells(wake_sc >> 8); - mask[i++] = 0xFF; - match[i] = wbcir_to_rc6cells(wake_sc >> 12); - mask[i++] = 0x3F; - - /* Customer bits 7 - 0 */ - match[i] = wbcir_to_rc6cells(wake_sc >> 16); - mask[i++] = 0xFF; + proto = IR_PROTOCOL_NEC; + break; + + case RC_TYPE_RC6_0: + /* Command */ + match[0] = wbcir_to_rc6cells(wake_sc >> 0); + mask[0] = wbcir_to_rc6cells(mask_sc >> 0); + match[1] = wbcir_to_rc6cells(wake_sc >> 4); + mask[1] = wbcir_to_rc6cells(mask_sc >> 4); + + /* Address */ + match[2] = wbcir_to_rc6cells(wake_sc >> 8); + mask[2] = wbcir_to_rc6cells(mask_sc >> 8); + match[3] = wbcir_to_rc6cells(wake_sc >> 12); + mask[3] = wbcir_to_rc6cells(mask_sc >> 12); + + /* Header */ + match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */ + mask[4] = 0xF0; + match[5] = 0x09; /* start bit = 1, mode2 = 0 */ + mask[5] = 0x0F; + + rc6_csl = 44; + proto = IR_PROTOCOL_RC6; + break; + + case RC_TYPE_RC6_6A_24: + case RC_TYPE_RC6_6A_32: + case RC_TYPE_RC6_MCE: + i = 0; + + /* Command */ + match[i] = wbcir_to_rc6cells(wake_sc >> 0); + mask[i++] = wbcir_to_rc6cells(mask_sc >> 0); + match[i] = wbcir_to_rc6cells(wake_sc >> 4); + mask[i++] = wbcir_to_rc6cells(mask_sc >> 4); + + /* Address + Toggle */ + match[i] = wbcir_to_rc6cells(wake_sc >> 8); + mask[i++] = wbcir_to_rc6cells(mask_sc >> 8); + match[i] = wbcir_to_rc6cells(wake_sc >> 12); + mask[i++] = wbcir_to_rc6cells(mask_sc >> 12); + + /* Customer bits 7 - 0 */ + match[i] = wbcir_to_rc6cells(wake_sc >> 16); + mask[i++] = wbcir_to_rc6cells(mask_sc >> 16); + + if (rc->wakeup_protocol == RC_TYPE_RC6_6A_20) { + rc6_csl = 52; + } else { match[i] = wbcir_to_rc6cells(wake_sc >> 20); - mask[i++] = 0xFF; + mask[i++] = wbcir_to_rc6cells(mask_sc >> 20); - if (wake_sc & 0x80000000) { + if (rc->wakeup_protocol == RC_TYPE_RC6_6A_24) { + rc6_csl = 60; + } else { /* Customer range bit and bits 15 - 8 */ match[i] = wbcir_to_rc6cells(wake_sc >> 24); - mask[i++] = 0xFF; + mask[i++] = wbcir_to_rc6cells(mask_sc >> 24); match[i] = wbcir_to_rc6cells(wake_sc >> 28); - mask[i++] = 0xFF; + mask[i++] = wbcir_to_rc6cells(mask_sc >> 28); rc6_csl = 76; - } else if (wake_sc <= 0x007FFFFF) { - rc6_csl = 60; - } else { - do_wake = false; - dev_err(dev, "RC6 - Invalid wake scancode\n"); - break; } - - /* Header */ - match[i] = 0x93; /* mode1 = mode0 = 1, submode = 0 */ - mask[i++] = 0xFF; - match[i] = 0x0A; /* start bit = 1, mode2 = 1 */ - mask[i++] = 0x0F; - - } else { - do_wake = false; - dev_err(dev, "RC6 - Invalid wake mode\n"); } + /* Header */ + match[i] = 0x93; /* mode1 = mode0 = 1, submode = 0 */ + mask[i++] = 0xFF; + match[i] = 0x0A; /* start bit = 1, mode2 = 1 */ + mask[i++] = 0x0F; + proto = IR_PROTOCOL_RC6; break; - default: do_wake = false; break; @@ -855,7 +852,8 @@ finish: wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07); /* Set CEIR_EN */ - wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01); + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, + (proto << 4) | 0x01, 0x31); } else { /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */ @@ -875,6 +873,15 @@ finish: disable_irq(data->irq); } +/* + * Wakeup handling is done on shutdown. + */ +static int +wbcir_set_wakeup_filter(struct rc_dev *rc, struct rc_scancode_filter *filter) +{ + return 0; +} + static int wbcir_suspend(struct pnp_dev *device, pm_message_t state) { @@ -887,16 +894,11 @@ wbcir_suspend(struct pnp_dev *device, pm_message_t state) static void wbcir_init_hw(struct wbcir_data *data) { - u8 tmp; - /* Disable interrupts */ wbcir_set_irqmask(data, WBCIR_IRQ_NONE); - /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */ - tmp = protocol << 4; - if (invert) - tmp |= 0x08; - outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL); + /* Set RX_INV, Clear CEIR_EN (needed for the led) */ + wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, invert ? 8 : 0, 0x09); /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17); @@ -1059,13 +1061,12 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) if (err) goto exit_free_data; - data->dev = rc_allocate_device(); + data->dev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!data->dev) { err = -ENOMEM; goto exit_unregister_led; } - data->dev->driver_type = RC_DRIVER_IR_RAW; data->dev->driver_name = DRVNAME; data->dev->input_name = WBCIR_NAME; data->dev->input_phys = "wbcir/cir0"; @@ -1083,7 +1084,15 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->dev.parent = &device->dev; data->dev->timeout = MS_TO_NS(100); data->dev->rx_resolution = US_TO_NS(2); - data->dev->allowed_protocols = RC_BIT_ALL; + data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX | + RC_BIT_NEC32 | RC_BIT_RC5 | RC_BIT_RC6_0 | + RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | + RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE; + data->dev->wakeup_protocol = RC_TYPE_RC6_MCE; + data->dev->scancode_wakeup_filter.data = 0x800f040c; + data->dev->scancode_wakeup_filter.mask = 0xffff7fff; + data->dev->s_wakeup_filter = wbcir_set_wakeup_filter; err = rc_register_device(data->dev); if (err) @@ -1199,15 +1208,6 @@ wbcir_init(void) { int ret; - switch (protocol) { - case IR_PROTOCOL_RC5: - case IR_PROTOCOL_NEC: - case IR_PROTOCOL_RC6: - break; - default: - pr_err("Invalid power-on protocol\n"); - } - ret = pnp_register_driver(&wbcir_driver); if (ret) pr_err("Unable to register driver\n"); |