diff options
Diffstat (limited to 'drivers/media/rc')
54 files changed, 4074 insertions, 1164 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 370e16e07867..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. @@ -389,4 +409,21 @@ config IR_SUNXI To compile this driver as a module, choose M here: the module will be called sunxi-ir. +config IR_SERIAL + tristate "Homebrew Serial Port Receiver" + depends on RC_CORE + ---help--- + Say Y if you want to use Homebrew Serial Port Receivers and + Transceivers. + + To compile this driver as a module, choose M here: the module will + be called serial-ir. + +config IR_SERIAL_TRANSMITTER + bool "Serial Port Transmitter" + default y + depends on IR_SERIAL + ---help--- + Serial Port Transmitter support + endif #RC_DEVICES diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 379a5c0f1379..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 @@ -37,3 +38,5 @@ obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o 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 9f5b59706741..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 @@ -527,8 +523,7 @@ static void ati_remote_input_report(struct urb *urb) remote_num = (data[3] >> 4) & 0x0f; if (channel_mask & (1 << (remote_num + 1))) { dbginfo(&ati_remote->interface->dev, - "Masked input from channel 0x%02x: data %02x, " - "mask= 0x%02lx\n", + "Masked input from channel 0x%02x: data %02x, mask= 0x%02lx\n", remote_num, data[2], channel_mask); return; } @@ -765,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"; @@ -852,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 d1c61cd035f6..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; @@ -1210,8 +1204,7 @@ MODULE_PARM_DESC(txsim, MODULE_DEVICE_TABLE(pnp, ene_ids); MODULE_DESCRIPTION - ("Infrared input driver for KB3926B/C/D/E/F " - "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port"); + ("Infrared input driver for KB3926B/C/D/E/F (aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port"); MODULE_AUTHOR("Maxim Levitsky"); MODULE_LICENSE("GPL"); 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 bd7b3bdb1a88..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 @@ -104,11 +99,7 @@ static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 of /* read val from cir config register */ static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset) { - u8 val; - - val = inb(fintek->cir_addr + offset); - - return val; + return inb(fintek->cir_addr + offset); } /* dump current cir register contents */ @@ -496,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; @@ -538,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 86cc70fe2534..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}, {} }; @@ -441,13 +460,11 @@ MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); /* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */ static int display_type; module_param(display_type, int, S_IRUGO); -MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " - "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); +MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, 1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); static int pad_stabilize = 1; module_param(pad_stabilize, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD " - "presses in arrow key mode. 0=disable, 1=enable (default)."); +MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD presses in arrow key mode. 0=disable, 1=enable (default)."); /* * In certain use cases, mouse mode isn't really helpful, and could actually @@ -455,14 +472,12 @@ MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD " */ static bool nomouse; module_param(nomouse, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is " - "open. 0=don't disable, 1=disable. (default: don't disable)"); +MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is open. 0=don't disable, 1=disable. (default: don't disable)"); /* threshold at which a pad push registers as an arrow key in kbd mode */ static int pad_thresh; module_param(pad_thresh, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an " - "arrow key in kbd mode (default: 28)"); +MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an arrow key in kbd mode (default: 28)"); static void free_imon_context(struct imon_context *ictx) @@ -611,7 +626,7 @@ static int send_packet(struct imon_context *ictx) ictx->tx_urb->actual_length = 0; } - init_completion(&ictx->tx.finished); + reinit_completion(&ictx->tx.finished); ictx->tx.busy = true; smp_rmb(); /* ensure later readers know we're busy */ @@ -785,9 +800,7 @@ static ssize_t show_associate_remote(struct device *d, else strcpy(buf, "closed\n"); - dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for " - "instructions on how to associate your iMON 2.4G DT/LT " - "remote\n"); + dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n"); mutex_unlock(&ictx->lock); return strlen(buf); } @@ -1115,8 +1128,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; if (*rc_type && !(*rc_type & rc->allowed_protocols)) - dev_warn(dev, "Looks like you're trying to use an IR protocol " - "this device does not support\n"); + dev_warn(dev, "Looks like you're trying to use an IR protocol this device does not support\n"); if (*rc_type & RC_BIT_RC6_MCE) { dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); @@ -1129,8 +1141,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) /* ir_proto_packet[0] = 0x00; // already the default */ *rc_type = RC_BIT_OTHER; } else { - dev_warn(dev, "Unsupported IR protocol specified, overriding " - "to iMON IR protocol\n"); + dev_warn(dev, "Unsupported IR protocol specified, overriding to iMON IR protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ @@ -1585,15 +1596,97 @@ 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; - int i; u64 scancode; int press_type = 0; int msec; @@ -1664,10 +1757,8 @@ static void imon_incoming_packet(struct imon_context *ictx, } if (debug) { - printk(KERN_INFO "intf%d decoded packet: ", intf); - for (i = 0; i < len; ++i) - printk("%02x ", buf[i]); - printk("\n"); + printk(KERN_INFO "intf%d decoded packet: %*ph\n", + intf, len, buf); } press_type = imon_parse_press_type(ictx, buf, ktype); @@ -1722,8 +1813,8 @@ static void imon_incoming_packet(struct imon_context *ictx, not_input_data: if (len != 8) { - dev_warn(dev, "imon %s: invalid incoming packet " - "size (len = %d, intf%d)\n", __func__, len, intf); + dev_warn(dev, "imon %s: invalid incoming packet size (len = %d, intf%d)\n", + __func__, len, intf); return; } @@ -1772,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: @@ -1813,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: @@ -1879,8 +1976,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) allowed_protos = RC_BIT_RC6_MCE; break; default: - dev_info(ictx->dev, "Unknown 0xffdc device, " - "defaulting to VFD and iMON IR"); + dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; /* We don't know which one it is, allow user to set the * RC6 one from userspace if OTHER wasn't correct. */ @@ -1922,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; @@ -1937,8 +2036,8 @@ static void imon_set_display_type(struct imon_context *ictx) ictx->display_supported = false; else ictx->display_supported = true; - dev_info(ictx->dev, "%s: overriding display type to %d via " - "modparam\n", __func__, display_type); + dev_info(ictx->dev, "%s: overriding display type to %d via modparam\n", + __func__, display_type); } ictx->display_type = configured_display_type; @@ -1951,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; @@ -1969,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; @@ -1988,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; @@ -2159,8 +2263,8 @@ static bool imon_find_endpoints(struct imon_context *ictx, if (!display_ep_found) { tx_control = true; display_ep_found = true; - dev_dbg(ictx->dev, "%s: device uses control endpoint, not " - "interface OUT endpoint\n", __func__); + dev_dbg(ictx->dev, "%s: device uses control endpoint, not interface OUT endpoint\n", + __func__); } /* @@ -2228,6 +2332,8 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf, ictx->tx_urb = tx_urb; ictx->rf_device = false; + init_completion(&ictx->tx.finished); + ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); @@ -2369,8 +2475,8 @@ static void imon_init_display(struct imon_context *ictx, /* set up sysfs entry for built-in clock */ ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group); if (ret) - dev_err(ictx->dev, "Could not create display sysfs " - "entries(%d)", ret); + dev_err(ictx->dev, "Could not create display sysfs entries(%d)", + ret); if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) ret = usb_register_dev(intf, &imon_lcd_class); @@ -2378,8 +2484,7 @@ static void imon_init_display(struct imon_context *ictx, ret = usb_register_dev(intf, &imon_vfd_class); if (ret) /* Not a fatal error, so ignore */ - dev_info(ictx->dev, "could not get a minor number for " - "display\n"); + dev_info(ictx->dev, "could not get a minor number for display\n"); } @@ -2459,8 +2564,8 @@ static int imon_probe(struct usb_interface *interface, mutex_unlock(&ictx->lock); } - dev_info(dev, "iMON device (%04x:%04x, intf%d) on " - "usb<%d:%d> initialized\n", vendor, product, ifnum, + dev_info(dev, "iMON device (%04x:%04x, intf%d) on usb<%d:%d> initialized\n", + vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum); mutex_unlock(&driver_lock); @@ -2504,7 +2609,7 @@ static void imon_disconnect(struct usb_interface *interface) /* Abort ongoing write */ if (ictx->tx.busy) { usb_kill_urb(ictx->tx_urb); - complete_all(&ictx->tx.finished); + complete(&ictx->tx.finished); } if (ifnum == 0) { diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index d0549fba711c..50951f686852 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -75,15 +75,22 @@ static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) { u32 val; - regmap_read(dev->regmap, IR_CLK, &val); - if (on) { - val &= ~IR_CLK_RESET; - val |= IR_CLK_ENABLE; + if (dev->regmap) { + regmap_read(dev->regmap, IR_CLK, &val); + if (on) { + val &= ~IR_CLK_RESET; + val |= IR_CLK_ENABLE; + } else { + val &= ~IR_CLK_ENABLE; + val |= IR_CLK_RESET; + } + regmap_write(dev->regmap, IR_CLK, val); } else { - val &= ~IR_CLK_ENABLE; - val |= IR_CLK_RESET; + if (on) + clk_prepare_enable(dev->clock); + else + clk_disable_unprepare(dev->clock); } - regmap_write(dev->regmap, IR_CLK, val); } static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv) @@ -207,8 +214,8 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) priv->regmap = syscon_regmap_lookup_by_phandle(node, "hisilicon,power-syscon"); if (IS_ERR(priv->regmap)) { - dev_err(dev, "no power-reg\n"); - return -EINVAL; + dev_info(dev, "no power-reg\n"); + priv->regmap = NULL; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -222,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; @@ -235,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 82fb6f2ca011..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,225 +82,134 @@ 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(); - } while (hrtimer_get_expires_tv64(timer) < now.tv64); + } while (hrtimer_get_expires_tv64(timer) < now); 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 7331e5e7c497..520bb77dcb62 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -56,7 +56,8 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct sanyo_dec *data = &dev->raw->sanyo; u32 scancode; - u8 address, command, not_command; + u16 address; + u8 command, not_command; if (!is_timing_event(ev)) { if (ev.reset) { @@ -175,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 0f301903aa6f..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. * @@ -55,14 +50,12 @@ MODULE_PARM_DESC(debug, "Enable debugging output"); /* low limit for RX carrier freq, Hz, 0 for no RX demodulation */ static int rx_low_carrier_freq; module_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, " - "0 for no RX demodulation"); +MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, 0 for no RX demodulation"); /* high limit for RX carrier freq, Hz, 0 for no RX demodulation */ static int rx_high_carrier_freq; module_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, " - "Hz, 0 for no RX demodulation"); +MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, Hz, 0 for no RX demodulation"); /* override tx carrier frequency */ static int tx_carrier_freq; @@ -263,6 +256,8 @@ static void ite_set_carrier_params(struct ite_dev *dev) if (allowance > ITE_RXDCR_MAX) allowance = ITE_RXDCR_MAX; + + use_demodulator = true; } } @@ -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; @@ -1484,8 +1479,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) { model_no = model_number; - ite_pr(KERN_NOTICE, "The model has been fixed by a module " - "parameter."); + ite_pr(KERN_NOTICE, "The model has been fixed by a module parameter."); } ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model); @@ -1562,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 91f9bb87ce68..1688893a65bb 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -13,17 +13,13 @@ * 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 #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> +#include <linux/sched/signal.h> #include <linux/errno.h> #include <linux/ioctl.h> #include <linux/fs.h> @@ -150,9 +146,6 @@ static const struct file_operations lirc_dev_fops = { .write = lirc_dev_fop_write, .poll = lirc_dev_fop_poll, .unlocked_ioctl = lirc_dev_fop_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_dev_fop_ioctl, -#endif .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, .llseek = noop_llseek, @@ -160,19 +153,19 @@ static const struct file_operations lirc_dev_fops = { static int lirc_cdev_add(struct irctl *ir) { - int retval = -ENOMEM; struct lirc_driver *d = &ir->d; struct cdev *cdev; + int retval; - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + cdev = cdev_alloc(); if (!cdev) - goto err_out; + return -ENOMEM; if (d->fops) { - cdev_init(cdev, d->fops); + cdev->ops = d->fops; cdev->owner = d->owner; } else { - cdev_init(cdev, &lirc_dev_fops); + cdev->ops = &lirc_dev_fops; cdev->owner = THIS_MODULE; } retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); @@ -180,17 +173,15 @@ static int lirc_cdev_add(struct irctl *ir) goto err_out; retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); - if (retval) { - kobject_put(&cdev->kobj); + if (retval) goto err_out; - } ir->cdev = cdev; return 0; err_out: - kfree(cdev); + cdev_del(cdev); return retval; } @@ -420,7 +411,6 @@ int lirc_unregister_driver(int minor) } else { lirc_irctl_cleanup(ir); cdev_del(cdev); - kfree(cdev); kfree(ir); irctls[minor] = NULL; } @@ -446,6 +436,8 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) return -ERESTARTSYS; ir = irctls[iminor(inode)]; + mutex_unlock(&lirc_dev_lock); + if (!ir) { retval = -ENODEV; goto error; @@ -478,7 +470,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) @@ -486,8 +478,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) } error: - mutex_unlock(&lirc_dev_lock); - nonseekable_open(inode, file); return retval; @@ -521,7 +511,6 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) lirc_irctl_cleanup(ir); cdev_del(cdev); irctls[ir->d.minor] = NULL; - kfree(cdev); kfree(ir); } @@ -589,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; } @@ -599,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; } @@ -658,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); @@ -684,7 +676,6 @@ ssize_t lirc_dev_fop_read(struct file *file, * between while condition checking and scheduling) */ add_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_INTERRUPTIBLE); /* * while we didn't provide 'length' bytes, device is opened in blocking @@ -709,19 +700,19 @@ ssize_t lirc_dev_fop_read(struct file *file, } mutex_unlock(&ir->irctl_lock); - schedule(); set_current_state(TASK_INTERRUPTIBLE); + schedule(); + set_current_state(TASK_RUNNING); if (mutex_lock_interruptible(&ir->irctl_lock)) { ret = -ERESTARTSYS; remove_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_RUNNING); goto out_unlocked; } if (!ir->attached) { ret = -ENODEV; - break; + goto out_locked; } } else { lirc_buffer_read(ir->buf, buf); @@ -735,7 +726,6 @@ ssize_t lirc_dev_fop_read(struct file *file, } remove_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_RUNNING); out_locked: mutex_unlock(&ir->irctl_lock); diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 4f8c7effdcee..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> @@ -153,15 +149,6 @@ #define MCE_COMMAND_IRDATA 0x80 #define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ -/* general constants */ -#define SEND_FLAG_IN_PROGRESS 1 -#define SEND_FLAG_COMPLETE 2 -#define RECV_FLAG_IN_PROGRESS 3 -#define RECV_FLAG_COMPLETE 4 - -#define MCEUSB_RX 1 -#define MCEUSB_TX 2 - #define VENDOR_PHILIPS 0x0471 #define VENDOR_SMK 0x0609 #define VENDOR_TATUNG 0x1460 @@ -422,7 +409,6 @@ struct mceusb_dev { struct rc_dev *rc; /* optional features we can enable */ - bool carrier_report_enabled; bool learning_enabled; /* core device bits */ @@ -455,7 +441,6 @@ struct mceusb_dev { } flags; /* transmit support */ - int send_flags; u32 carrier; unsigned char tx_mask; @@ -604,9 +589,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; case MCE_RSP_EQWAKEVERSION: if (!out) - dev_dbg(dev, "Wake version, proto: 0x%02x, " - "payload: 0x%02x, address: 0x%02x, " - "version: 0x%02x", + dev_dbg(dev, "Wake version, proto: 0x%02x, payload: 0x%02x, address: 0x%02x, version: 0x%02x", data1, data2, data3, data4); break; case MCE_RSP_GETPORTSTATUS: @@ -740,52 +723,40 @@ static void mce_async_callback(struct urb *urb) /* request incoming or send outgoing usb packet - used to initialize remote */ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, - int size, int urb_type) + int size) { int res, pipe; struct urb *async_urb; struct device *dev = ir->dev; unsigned char *async_buf; - if (urb_type == MCEUSB_TX) { - async_urb = usb_alloc_urb(0, GFP_KERNEL); - if (unlikely(!async_urb)) { - dev_err(dev, "Error, couldn't allocate urb!\n"); - return; - } - - async_buf = kzalloc(size, GFP_KERNEL); - if (!async_buf) { - dev_err(dev, "Error, couldn't allocate buf!\n"); - usb_free_urb(async_urb); - return; - } - - /* outbound data */ - if (usb_endpoint_xfer_int(ir->usb_ep_out)) { - pipe = usb_sndintpipe(ir->usbdev, - ir->usb_ep_out->bEndpointAddress); - usb_fill_int_urb(async_urb, ir->usbdev, pipe, async_buf, - size, mce_async_callback, ir, - ir->usb_ep_out->bInterval); - } else { - pipe = usb_sndbulkpipe(ir->usbdev, - ir->usb_ep_out->bEndpointAddress); - usb_fill_bulk_urb(async_urb, ir->usbdev, pipe, - async_buf, size, mce_async_callback, - ir); - } - memcpy(async_buf, data, size); + async_urb = usb_alloc_urb(0, GFP_KERNEL); + if (unlikely(!async_urb)) { + dev_err(dev, "Error, couldn't allocate urb!\n"); + return; + } - } else if (urb_type == MCEUSB_RX) { - /* standard request */ - async_urb = ir->urb_in; - ir->send_flags = RECV_FLAG_IN_PROGRESS; + async_buf = kmalloc(size, GFP_KERNEL); + if (!async_buf) { + usb_free_urb(async_urb); + return; + } + /* outbound data */ + if (usb_endpoint_xfer_int(ir->usb_ep_out)) { + pipe = usb_sndintpipe(ir->usbdev, + ir->usb_ep_out->bEndpointAddress); + usb_fill_int_urb(async_urb, ir->usbdev, pipe, async_buf, + size, mce_async_callback, ir, + ir->usb_ep_out->bInterval); } else { - dev_err(dev, "Error! Unknown urb type %d\n", urb_type); - return; + pipe = usb_sndbulkpipe(ir->usbdev, + ir->usb_ep_out->bEndpointAddress); + usb_fill_bulk_urb(async_urb, ir->usbdev, pipe, + async_buf, size, mce_async_callback, + ir); } + memcpy(async_buf, data, size); dev_dbg(dev, "receive request called (size=%#x)", size); @@ -806,19 +777,14 @@ static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) if (ir->need_reset) { ir->need_reset = false; - mce_request_packet(ir, DEVICE_RESUME, rsize, MCEUSB_TX); + mce_request_packet(ir, DEVICE_RESUME, rsize); msleep(10); } - mce_request_packet(ir, data, size, MCEUSB_TX); + mce_request_packet(ir, data, size); msleep(10); } -static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) -{ - mce_request_packet(ir, NULL, size, MCEUSB_RX); -} - /* Send data out the IR blaster port(s) */ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { @@ -920,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) { @@ -934,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; } } @@ -1062,7 +1028,6 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) static void mceusb_dev_recv(struct urb *urb) { struct mceusb_dev *ir; - int buf_len; if (!urb) return; @@ -1073,18 +1038,10 @@ static void mceusb_dev_recv(struct urb *urb) return; } - buf_len = urb->actual_length; - - if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { - ir->send_flags = SEND_FLAG_COMPLETE; - dev_dbg(ir->dev, "setup answer received %d bytes\n", - buf_len); - } - switch (urb->status) { /* success */ case 0: - mceusb_process_ir_data(ir, buf_len); + mceusb_process_ir_data(ir, urb->actual_length); break; case -ECONNRESET: @@ -1220,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; @@ -1240,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; @@ -1285,7 +1241,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *ep_in = NULL; struct usb_endpoint_descriptor *ep_out = NULL; struct mceusb_dev *ir = NULL; - int pipe, maxp, i; + int pipe, maxp, i, res; char buf[63], name[128] = ""; enum mceusb_model_type model = id->driver_info; bool is_gen3; @@ -1388,7 +1344,9 @@ static int mceusb_dev_probe(struct usb_interface *intf, /* flush buffers on the device */ dev_dbg(&intf->dev, "Flushing receive buffers\n"); - mce_flush_rx_buffer(ir, maxp); + res = usb_submit_urb(ir->urb_in, GFP_KERNEL); + if (res) + dev_err(&intf->dev, "failed to flush buffers: %d\n", res); /* figure out which firmware/emulator version this hardware has */ mceusb_get_emulator_version(ir); @@ -1423,6 +1381,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, /* Error-handling path */ rc_dev_fail: usb_put_dev(ir->usbdev); + usb_kill_urb(ir->urb_in); usb_free_urb(ir->urb_in); urb_in_alloc_fail: usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 003fff07ade2..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; @@ -218,6 +217,7 @@ static const struct of_device_id meson_ir_match[] = { { .compatible = "amlogic,meson-gxbb-ir" }, { }, }; +MODULE_DEVICE_TABLE(of, meson_ir_match); static struct platform_driver meson_ir_driver = { .probe = meson_ir_probe, 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 04fedaa75612..ec4b25bd2ec2 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 @@ -48,6 +43,11 @@ static const struct nvt_chip nvt_chips[] = { { "NCT6779D", NVT_6779D }, }; +static inline struct device *nvt_get_dev(const struct nvt_dev *nvt) +{ + return nvt->rdev->dev.parent; +} + static inline bool is_w83667hg(struct nvt_dev *nvt) { return nvt->chip_ver == NVT_W83667HG; @@ -171,6 +171,42 @@ 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; + unsigned long flags; + int i; + + /* 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); + + 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_irqrestore(&nvt->lock, flags); +} + static ssize_t wakeup_data_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -182,7 +218,7 @@ static ssize_t wakeup_data_show(struct device *dev, ssize_t buf_len = 0; int i; - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); fifo_len = min(fifo_len, WAKEUP_MAX_SIZE); @@ -199,7 +235,7 @@ static ssize_t wakeup_data_show(struct device *dev, } buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n"); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); return buf_len; } @@ -209,9 +245,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; @@ -240,27 +274,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->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->nvt_lock, flags); + nvt_write_wakeup_codes(rc_dev, wake_buf, count); ret = len; out: @@ -385,6 +399,7 @@ static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id) /* detect hardware features */ static int nvt_hw_detect(struct nvt_dev *nvt) { + struct device *dev = nvt_get_dev(nvt); const char *chip_name; int chip_id; @@ -405,8 +420,7 @@ static int nvt_hw_detect(struct nvt_dev *nvt) chip_id = nvt->chip_major << 8 | nvt->chip_minor; if (chip_id == NVT_INVALID) { - dev_err(&nvt->pdev->dev, - "No device found on either EFM port\n"); + dev_err(dev, "No device found on either EFM port\n"); return -ENODEV; } @@ -414,12 +428,11 @@ static int nvt_hw_detect(struct nvt_dev *nvt) /* warn, but still let the driver load, if we don't know this chip */ if (!chip_name) - dev_warn(&nvt->pdev->dev, + dev_warn(dev, "unknown chip, id: 0x%02x 0x%02x, it may not work...", nvt->chip_major, nvt->chip_minor); else - dev_info(&nvt->pdev->dev, - "found %s or compatible: chip id: 0x%02x 0x%02x", + dev_info(dev, "found %s or compatible: chip id: 0x%02x 0x%02x", chip_name, nvt->chip_major, nvt->chip_minor); return 0; @@ -586,7 +599,7 @@ static void nvt_enable_wake(struct nvt_dev *nvt) nvt_efm_disable(nvt); - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | @@ -595,11 +608,11 @@ static void nvt_enable_wake(struct nvt_dev *nvt) nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); } #if 0 /* Currently unused */ -/* rx carrier detect only works in learning mode, must be called w/nvt_lock */ +/* rx carrier detect only works in learning mode, must be called w/lock */ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) { u32 count, carrier, duration = 0; @@ -616,7 +629,7 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) duration *= SAMPLE_PERIOD; if (!count || !duration) { - dev_notice(&nvt->pdev->dev, + dev_notice(nvt_get_dev(nvt), "Unable to determine carrier! (c:%u, d:%u)", count, duration); return 0; @@ -658,6 +671,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 * @@ -684,7 +753,7 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) u8 iren; int ret; - spin_lock_irqsave(&nvt->tx.lock, flags); + spin_lock_irqsave(&nvt->lock, flags); ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n); nvt->tx.buf_count = (ret * sizeof(unsigned)); @@ -708,13 +777,13 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) for (i = 0; i < 9; i++) nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO); - spin_unlock_irqrestore(&nvt->tx.lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST); - spin_lock_irqsave(&nvt->tx.lock, flags); + spin_lock_irqsave(&nvt->lock, flags); nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->tx.lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* restore enabled interrupts to prior state */ nvt_cir_reg_write(nvt, iren, CIR_IREN); @@ -781,7 +850,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) { - dev_warn(&nvt->pdev->dev, "RX FIFO overrun detected, flushing data!"); + dev_warn(nvt_get_dev(nvt), "RX FIFO overrun detected, flushing data!"); nvt->pkts = 0; nvt_clear_cir_fifo(nvt); @@ -828,14 +897,7 @@ static void nvt_cir_log_irqs(u8 status, u8 iren) static bool nvt_cir_tx_inactive(struct nvt_dev *nvt) { - unsigned long flags; - u8 tx_state; - - spin_lock_irqsave(&nvt->tx.lock, flags); - tx_state = nvt->tx.tx_state; - spin_unlock_irqrestore(&nvt->tx.lock, flags); - - return tx_state == ST_TX_NONE; + return nvt->tx.tx_state == ST_TX_NONE; } /* interrupt service routine for incoming and outgoing CIR data */ @@ -843,11 +905,10 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) { struct nvt_dev *nvt = data; u8 status, iren; - unsigned long flags; nvt_dbg_verbose("%s firing", __func__); - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock(&nvt->lock); /* * Get IR Status register contents. Write 1 to ack/clear @@ -869,7 +930,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) * logical device is being disabled. */ if (status == 0xff && iren == 0xff) { - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock(&nvt->lock); nvt_dbg_verbose("Spurious interrupt detected"); return IRQ_HANDLED; } @@ -878,7 +939,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) * status bit whether the related interrupt source is enabled */ if (!(status & iren)) { - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock(&nvt->lock); nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); return IRQ_NONE; } @@ -898,8 +959,6 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) nvt_get_rx_ir_data(nvt); } - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - if (status & CIR_IRSTS_TE) nvt_clear_tx_fifo(nvt); @@ -907,8 +966,6 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) unsigned int pos, count; u8 tmp; - spin_lock_irqsave(&nvt->tx.lock, flags); - pos = nvt->tx.cur_buf_num; count = nvt->tx.buf_count; @@ -921,20 +978,17 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) tmp = nvt_cir_reg_read(nvt, CIR_IREN); nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN); } - - spin_unlock_irqrestore(&nvt->tx.lock, flags); - } if (status & CIR_IRSTS_TFU) { - spin_lock_irqsave(&nvt->tx.lock, flags); if (nvt->tx.tx_state == ST_TX_REPLY) { nvt->tx.tx_state = ST_TX_REQUEST; wake_up(&nvt->tx.queue); } - spin_unlock_irqrestore(&nvt->tx.lock, flags); } + spin_unlock(&nvt->lock); + nvt_dbg_verbose("%s done", __func__); return IRQ_HANDLED; } @@ -943,7 +997,7 @@ static void nvt_disable_cir(struct nvt_dev *nvt) { unsigned long flags; - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); /* disable CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); @@ -958,7 +1012,7 @@ static void nvt_disable_cir(struct nvt_dev *nvt) nvt_clear_cir_fifo(nvt); nvt_clear_tx_fifo(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* disable the CIR logical device */ nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); @@ -969,7 +1023,7 @@ static int nvt_open(struct rc_dev *dev) struct nvt_dev *nvt = dev->priv; unsigned long flags; - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); /* set function enable flags */ nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | @@ -982,7 +1036,7 @@ static int nvt_open(struct rc_dev *dev) /* enable interrupts */ nvt_set_cir_iren(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* enable the CIR logical device */ nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); @@ -1002,40 +1056,41 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) { struct nvt_dev *nvt; struct rc_dev *rdev; - int ret = -ENOMEM; + int ret; nvt = devm_kzalloc(&pdev->dev, sizeof(struct nvt_dev), GFP_KERNEL); if (!nvt) - return ret; + return -ENOMEM; /* input device for IR remote (and tx) */ - rdev = rc_allocate_device(); - if (!rdev) - goto exit_free_dev_rdev; + nvt->rdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); + if (!nvt->rdev) + return -ENOMEM; + rdev = nvt->rdev; - ret = -ENODEV; /* activate pnp device */ - if (pnp_activate_dev(pdev) < 0) { + ret = pnp_activate_dev(pdev); + if (ret) { dev_err(&pdev->dev, "Could not activate PNP device!\n"); - goto exit_free_dev_rdev; + return ret; } /* validate pnp resources */ if (!pnp_port_valid(pdev, 0) || pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); - goto exit_free_dev_rdev; + return -EINVAL; } if (!pnp_irq_valid(pdev, 0)) { dev_err(&pdev->dev, "PNP IRQ not valid!\n"); - goto exit_free_dev_rdev; + return -EINVAL; } if (!pnp_port_valid(pdev, 1) || pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) { dev_err(&pdev->dev, "Wake PNP Port not valid!\n"); - goto exit_free_dev_rdev; + return -EINVAL; } nvt->cir_addr = pnp_port_start(pdev, 0); @@ -1046,17 +1101,15 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) nvt->cr_efir = CR_EFIR; nvt->cr_efdr = CR_EFDR; - spin_lock_init(&nvt->nvt_lock); - spin_lock_init(&nvt->tx.lock); + spin_lock_init(&nvt->lock); pnp_set_drvdata(pdev, nvt); - nvt->pdev = pdev; init_waitqueue_head(&nvt->tx.queue); ret = nvt_hw_detect(nvt); if (ret) - goto exit_free_dev_rdev; + return ret; /* Initialize CIR & CIR Wake Logical Devices */ nvt_efm_enable(nvt); @@ -1073,19 +1126,20 @@ 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; rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2; rdev->input_id.product = nvt->chip_major; rdev->input_id.version = nvt->chip_minor; - rdev->dev.parent = &pdev->dev; rdev->driver_name = NVT_DRIVER_NAME; rdev->map_name = RC_MAP_RC6_MCE; rdev->timeout = MS_TO_NS(100); @@ -1097,29 +1151,27 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* tx bits */ rdev->tx_resolution = XYZ; #endif - nvt->rdev = rdev; - - ret = rc_register_device(rdev); + ret = devm_rc_register_device(&pdev->dev, rdev); if (ret) - goto exit_free_dev_rdev; + return ret; - ret = -EBUSY; /* now claim resources */ if (!devm_request_region(&pdev->dev, nvt->cir_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto exit_unregister_device; + return -EBUSY; - if (devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr, - IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt)) - goto exit_unregister_device; + ret = devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr, + IRQF_SHARED, NVT_DRIVER_NAME, nvt); + if (ret) + return ret; if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME "-wake")) - goto exit_unregister_device; + return -EBUSY; ret = device_create_file(&rdev->dev, &dev_attr_wakeup_data); if (ret) - goto exit_unregister_device; + return ret; device_init_wakeup(&pdev->dev, true); @@ -1130,14 +1182,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) } return 0; - -exit_unregister_device: - rc_unregister_device(rdev); - rdev = NULL; -exit_free_dev_rdev: - rc_free_device(rdev); - - return ret; } static void nvt_remove(struct pnp_dev *pdev) @@ -1150,8 +1194,6 @@ static void nvt_remove(struct pnp_dev *pdev) /* enable CIR Wake (for IR power-on) */ nvt_enable_wake(nvt); - - rc_unregister_device(nvt->rdev); } static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) @@ -1161,16 +1203,14 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) nvt_dbg("%s called", __func__); - spin_lock_irqsave(&nvt->tx.lock, flags); - nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->tx.lock, flags); + spin_lock_irqsave(&nvt->lock, flags); - spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt->tx.tx_state = ST_TX_NONE; /* disable all CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* disable cir logical dev */ nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index acf735fc7170..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> @@ -78,17 +73,15 @@ struct nvt_chip { }; struct nvt_dev { - struct pnp_dev *pdev; struct rc_dev *rdev; - spinlock_t nvt_lock; + spinlock_t lock; /* for rx */ u8 buf[RX_BUF_LEN]; unsigned int pkts; struct { - spinlock_t lock; u8 buf[TX_BUF_LEN]; unsigned int buf_count; unsigned int cur_buf_num; 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 205ecc602e34..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 */ @@ -26,8 +25,7 @@ static LIST_HEAD(ir_raw_client_list); /* Used to handle IR raw handler extensions */ static DEFINE_MUTEX(ir_raw_handler_lock); static LIST_HEAD(ir_raw_handler_list); -static DEFINE_MUTEX(available_protocols_lock); -static u64 available_protocols; +static atomic64_t available_protocols = ATOMIC64_INIT(0); static int ir_raw_event_thread(void *data) { @@ -35,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; @@ -219,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); @@ -234,11 +222,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle); u64 ir_raw_get_allowed_protocols(void) { - u64 protocols; - mutex_lock(&available_protocols_lock); - protocols = available_protocols; - mutex_unlock(&available_protocols_lock); - return protocols; + return atomic64_read(&available_protocols); } static int change_protocol(struct rc_dev *dev, u64 *rc_type) @@ -251,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 */ @@ -274,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); @@ -331,9 +564,7 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) if (ir_raw_handler->raw_register) list_for_each_entry(raw, &ir_raw_client_list, list) ir_raw_handler->raw_register(raw->dev); - mutex_lock(&available_protocols_lock); - available_protocols |= ir_raw_handler->protocols; - mutex_unlock(&available_protocols_lock); + atomic64_or(ir_raw_handler->protocols, &available_protocols); mutex_unlock(&ir_raw_handler_lock); return 0; @@ -352,9 +583,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) if (ir_raw_handler->raw_unregister) ir_raw_handler->raw_unregister(raw->dev); } - mutex_lock(&available_protocols_lock); - available_protocols &= ~protocols; - mutex_unlock(&available_protocols_lock); + atomic64_andnot(protocols, &available_protocols); mutex_unlock(&ir_raw_handler_lock); } EXPORT_SYMBOL(ir_raw_handler_unregister); 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 d9c1f2ff7119..d84533699668 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -12,6 +12,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <media/rc-core.h> #include <linux/atomic.h> #include <linux/spinlock.h> @@ -66,7 +68,7 @@ struct rc_map *rc_map_get(const char *name) if (!map) { int rc = request_module("%s", name); if (rc < 0) { - printk(KERN_ERR "Couldn't load IR keymap %s\n", name); + pr_err("Couldn't load IR keymap %s\n", name); return NULL; } msleep(20); /* Give some time for IR to register */ @@ -75,7 +77,7 @@ struct rc_map *rc_map_get(const char *name) } #endif if (!map) { - printk(KERN_ERR "IR keymap %s not found\n", name); + pr_err("IR keymap %s not found\n", name); return NULL; } @@ -159,6 +161,7 @@ static void ir_free_table(struct rc_map *rc_map) { rc_map->size = 0; kfree(rc_map->name); + rc_map->name = NULL; kfree(rc_map->scan); rc_map->scan = NULL; } @@ -660,8 +663,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, dev->last_toggle = toggle; dev->last_keycode = keycode; - IR_dprintk(1, "%s: key down event, " - "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", + IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", dev->input_name, keycode, protocol, scancode); input_report_key(dev->input_dev, keycode, 1); @@ -722,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; @@ -794,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" }, @@ -828,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), \ @@ -858,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. * @@ -875,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; @@ -889,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); @@ -995,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; @@ -1028,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; @@ -1056,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; @@ -1071,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; } @@ -1098,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); @@ -1121,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); } } @@ -1219,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) @@ -1234,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; } @@ -1253,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; @@ -1270,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); @@ -1299,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, @@ -1313,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, }; @@ -1321,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, @@ -1343,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, }; @@ -1355,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; @@ -1363,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; } @@ -1403,16 +1630,42 @@ void rc_free_device(struct rc_dev *dev) } EXPORT_SYMBOL_GPL(rc_free_device); -int rc_register_device(struct rc_dev *dev) +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, + enum rc_driver_type type) +{ + struct rc_dev **dr, *rc; + + dr = devres_alloc(devm_rc_alloc_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return NULL; + + rc = rc_allocate_device(type); + if (!rc) { + devres_free(dr); + return NULL; + } + + rc->dev.parent = dev; + rc->managed_alloc = true; + *dr = rc; + devres_add(dev, dr); + + return rc; +} +EXPORT_SYMBOL_GPL(devm_rc_allocate_device); + +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; + u64 rc_type; - if (!dev || !dev->map_name) + if (!dev->map_name) return -EINVAL; rc_map = rc_map_get(dev->map_name); @@ -1421,6 +1674,22 @@ 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; + + rc_type = BIT_ULL(rc_map->rc_type); + + if (dev->change_protocol) { + rc = dev->change_protocol(dev, &rc_type); + if (rc < 0) + goto out_table; + dev->enabled_protocols = rc_type; + } + + if (dev->driver_type == RC_DRIVER_IR_RAW) + ir_raw_load_modules(&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); @@ -1430,6 +1699,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; @@ -1440,89 +1764,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 || + 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; + goto out_dev; } - if (dev->change_protocol) { - u64 rc_type = (1ll << rc_map->rc_type); - rc = dev->change_protocol(dev, &rc_type); - if (rc < 0) + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { + rc = rc_setup_rx_device(dev); + if (rc) goto out_raw; - dev->enabled_protocols = rc_type; } /* 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); + ir_raw_event_unregister(dev); out_dev: device_del(&dev->dev); out_unlock: @@ -1531,6 +1817,33 @@ out_unlock: } EXPORT_SYMBOL_GPL(rc_register_device); +static void devm_rc_release(struct device *dev, void *res) +{ + rc_unregister_device(*(struct rc_dev **)res); +} + +int devm_rc_register_device(struct device *parent, struct rc_dev *dev) +{ + struct rc_dev **dr; + int ret; + + dr = devres_alloc(devm_rc_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + ret = rc_register_device(dev); + if (ret) { + devres_free(dr); + return ret; + } + + *dr = dev; + devres_add(parent, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_rc_register_device); + void rc_unregister_device(struct rc_dev *dev) { if (!dev) @@ -1541,18 +1854,14 @@ 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); ida_simple_remove(&rc_ida, dev->minor); - rc_free_device(dev); + if (!dev->managed_alloc) + rc_free_device(dev); } EXPORT_SYMBOL_GPL(rc_unregister_device); @@ -1565,7 +1874,7 @@ static int __init rc_core_init(void) { int rc = class_register(&rc_class); if (rc) { - printk(KERN_ERR "rc_core: unable to register rc class\n"); + pr_err("rc_core: unable to register rc class\n"); return rc; } diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 05ba47bc0b61..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> @@ -81,6 +77,8 @@ #define RR3_RC_DET_ENABLE 0xbb /* Stop capture with the RC receiver */ #define RR3_RC_DET_DISABLE 0xbc +/* Start capture with the wideband receiver */ +#define RR3_MODSIG_CAPTURE 0xb2 /* Return the status of RC detector capture */ #define RR3_RC_DET_STATUS 0xbd /* Reset redrat */ @@ -105,11 +103,13 @@ #define RR3_CLK_PER_COUNT 12 /* (RR3_CLK / RR3_CLK_PER_COUNT) */ #define RR3_CLK_CONV_FACTOR 2000000 -/* USB bulk-in IR data endpoint address */ -#define RR3_BULK_IN_EP_ADDR 0x82 +/* USB bulk-in wideband IR data endpoint address */ +#define RR3_WIDE_IN_EP_ADDR 0x81 +/* USB bulk-in narrowband IR data endpoint address */ +#define RR3_NARROW_IN_EP_ADDR 0x82 /* Size of the fixed-length portion of the signal */ -#define RR3_DRIVER_MAXLENS 128 +#define RR3_DRIVER_MAXLENS 255 #define RR3_MAX_SIG_SIZE 512 #define RR3_TIME_UNIT 50 #define RR3_END_OF_SIGNAL 0x7f @@ -207,15 +207,22 @@ struct redrat3_dev { struct urb *flash_urb; u8 flash_in_buf; + /* learning */ + bool wideband; + struct usb_ctrlrequest learn_control; + struct urb *learn_urb; + u8 learn_buf; + /* save off the usb device pointer */ struct usb_device *udev; /* the receive endpoint */ - struct usb_endpoint_descriptor *ep_in; + struct usb_endpoint_descriptor *ep_narrow; /* the buffer to receive data */ void *bulk_in_buf; /* urb used to read ir data */ - struct urb *read_urb; + struct urb *narrow_urb; + struct urb *wide_urb; /* the send endpoint */ struct usb_endpoint_descriptor *ep_out; @@ -236,23 +243,6 @@ struct redrat3_dev { char phys[64]; }; -/* - * redrat3_issue_async - * - * Issues an async read to the ir data in port.. - * sets the callback to be redrat3_handle_async - */ -static void redrat3_issue_async(struct redrat3_dev *rr3) -{ - int res; - - res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); - if (res) - dev_dbg(rr3->dev, - "%s: receive request FAILED! (res %d, len %d)\n", - __func__, res, rr3->read_urb->transfer_buffer_length); -} - static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) { if (!rr3->transmitting && (code != 0x40)) @@ -265,8 +255,7 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) /* Codes 0x20 through 0x2f are IR Firmware Errors */ case 0x20: - pr_cont("Initial signal pulse not long enough " - "to measure carrier frequency\n"); + pr_cont("Initial signal pulse not long enough to measure carrier frequency\n"); break; case 0x21: pr_cont("Not enough length values allocated for signal\n"); @@ -278,18 +267,15 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) pr_cont("Too many signal repeats\n"); break; case 0x28: - pr_cont("Insufficient memory available for IR signal " - "data memory allocation\n"); + pr_cont("Insufficient memory available for IR signal data memory allocation\n"); break; case 0x29: - pr_cont("Insufficient memory available " - "for IrDa signal data memory allocation\n"); + pr_cont("Insufficient memory available for IrDa signal data memory allocation\n"); break; /* Codes 0x30 through 0x3f are USB Firmware Errors */ case 0x30: - pr_cont("Insufficient memory available for bulk " - "transfer structure\n"); + pr_cont("Insufficient memory available for bulk transfer structure\n"); break; /* @@ -301,8 +287,7 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) pr_cont("Signal capture has been terminated\n"); break; case 0x41: - pr_cont("Attempt to set/get and unknown signal I/O " - "algorithm parameter\n"); + pr_cont("Attempt to set/get and unknown signal I/O algorithm parameter\n"); break; case 0x42: pr_cont("Signal capture already started\n"); @@ -368,15 +353,18 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) unsigned int i, sig_size, single_len, offset, val; u32 mod_freq; - if (!rr3) { - pr_err("%s called with no context!\n", __func__); - return; - } - dev = rr3->dev; mod_freq = redrat3_val_to_mod_freq(&rr3->irdata); dev_dbg(dev, "Got mod_freq of %u\n", mod_freq); + if (mod_freq && rr3->wideband) { + DEFINE_IR_RAW_EVENT(ev); + + ev.carrier_report = 1; + ev.carrier = mod_freq; + + ir_raw_event_store(rr3->rc, &ev); + } /* process each rr3 encoded byte into an int */ sig_size = be16_to_cpu(rr3->irdata.sig_size); @@ -459,19 +447,31 @@ static int redrat3_enable_detector(struct redrat3_dev *rr3) return -EIO; } - redrat3_issue_async(rr3); + ret = usb_submit_urb(rr3->narrow_urb, GFP_KERNEL); + if (ret) { + dev_err(rr3->dev, "narrow band urb failed: %d", ret); + return ret; + } - return 0; + ret = usb_submit_urb(rr3->wide_urb, GFP_KERNEL); + if (ret) + dev_err(rr3->dev, "wide band urb failed: %d", ret); + + return ret; } static inline void redrat3_delete(struct redrat3_dev *rr3, struct usb_device *udev) { - usb_kill_urb(rr3->read_urb); + usb_kill_urb(rr3->narrow_urb); + usb_kill_urb(rr3->wide_urb); usb_kill_urb(rr3->flash_urb); - usb_free_urb(rr3->read_urb); + usb_kill_urb(rr3->learn_urb); + usb_free_urb(rr3->narrow_urb); + usb_free_urb(rr3->wide_urb); usb_free_urb(rr3->flash_urb); - usb_free_coherent(udev, le16_to_cpu(rr3->ep_in->wMaxPacketSize), + usb_free_urb(rr3->learn_urb); + usb_free_coherent(udev, le16_to_cpu(rr3->ep_narrow->wMaxPacketSize), rr3->bulk_in_buf, rr3->dma_in); kfree(rr3); @@ -485,10 +485,8 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3) len = sizeof(*tmp); tmp = kzalloc(len, GFP_KERNEL); - if (!tmp) { - dev_warn(rr3->dev, "Memory allocation faillure\n"); + if (!tmp) return timeout; - } pipe = usb_rcvctrlpipe(rr3->udev, 0); ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM, @@ -543,16 +541,14 @@ static void redrat3_reset(struct redrat3_dev *rr3) struct device *dev = rr3->dev; int rc, rxpipe, txpipe; u8 *val; - int len = sizeof(u8); + size_t const len = sizeof(*val); rxpipe = usb_rcvctrlpipe(udev, 0); txpipe = usb_sndctrlpipe(udev, 0); val = kmalloc(len, GFP_KERNEL); - if (!val) { - dev_err(dev, "Memory allocation failure\n"); + if (!val) return; - } *val = 0x01; rc = usb_control_msg(udev, rxpipe, RR3_RESET, @@ -590,14 +586,12 @@ static void redrat3_reset(struct redrat3_dev *rr3) static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) { - int rc = 0; + int rc; char *buffer; - buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL); - if (!buffer) { - dev_err(rr3->dev, "Memory allocation failure\n"); + buffer = kcalloc(RR3_FW_VERSION_LEN + 1, sizeof(*buffer), GFP_KERNEL); + if (!buffer) return; - } rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0), RR3_FW_VERSION, @@ -704,25 +698,25 @@ out: /* callback function from USB when async USB request has completed */ static void redrat3_handle_async(struct urb *urb) { - struct redrat3_dev *rr3; + struct redrat3_dev *rr3 = urb->context; int ret; - if (!urb) - return; - - rr3 = urb->context; - if (!rr3) { - pr_err("%s called with invalid context!\n", __func__); - usb_unlink_urb(urb); - return; - } - switch (urb->status) { case 0: ret = redrat3_get_ir_data(rr3, urb->actual_length); + if (!ret && rr3->wideband && !rr3->learn_urb->hcpriv) { + ret = usb_submit_urb(rr3->learn_urb, GFP_ATOMIC); + if (ret) + dev_err(rr3->dev, "Failed to submit learning urb: %d", + ret); + } + if (!ret) { /* no error, prepare to read more */ - redrat3_issue_async(rr3); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + dev_err(rr3->dev, "Failed to resubmit urb: %d", + ret); } break; @@ -785,11 +779,11 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, /* rr3 will disable rc detector on transmit */ rr3->transmitting = true; - sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL); - if (!sample_lens) { - ret = -ENOMEM; - goto out; - } + sample_lens = kcalloc(RR3_DRIVER_MAXLENS, + sizeof(*sample_lens), + GFP_KERNEL); + if (!sample_lens) + return -ENOMEM; irdata = kzalloc(sizeof(*irdata), GFP_KERNEL); if (!irdata) { @@ -857,8 +851,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, ret = count; out: - kfree(sample_lens); kfree(irdata); + kfree(sample_lens); rr3->transmitting = false; /* rr3 re-enables rc detector because it was enabled before */ @@ -882,6 +876,42 @@ static void redrat3_brightness_set(struct led_classdev *led_dev, enum } } +static int redrat3_wideband_receiver(struct rc_dev *rcdev, int enable) +{ + struct redrat3_dev *rr3 = rcdev->priv; + int ret = 0; + + rr3->wideband = enable != 0; + + if (enable) { + ret = usb_submit_urb(rr3->learn_urb, GFP_KERNEL); + if (ret) + dev_err(rr3->dev, "Failed to submit learning urb: %d", + ret); + } + + return ret; +} + +static void redrat3_learn_complete(struct urb *urb) +{ + struct redrat3_dev *rr3 = urb->context; + + switch (urb->status) { + case 0: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + usb_unlink_urb(urb); + return; + case -EPIPE: + default: + dev_err(rr3->dev, "Error: learn urb status = %d", urb->status); + break; + } +} + static void redrat3_led_complete(struct urb *urb) { struct redrat3_dev *rr3 = urb->context; @@ -908,19 +938,16 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) { struct device *dev = rr3->dev; struct rc_dev *rc; - int ret = -ENODEV; + int ret; u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct); - rc = rc_allocate_device(); - if (!rc) { - dev_err(dev, "remote input dev allocation failed\n"); - goto out; - } + rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rc) + return NULL; - snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s " - "Infrared Remote Transceiver (%04x:%04x)", - prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "", - le16_to_cpu(rr3->udev->descriptor.idVendor), prod); + snprintf(rr3->name, sizeof(rr3->name), + "RedRat3%s Infrared Remote Transceiver", + prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : ""); usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys)); @@ -929,14 +956,14 @@ 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)); rc->s_timeout = redrat3_set_timeout; rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; + rc->s_carrier_report = redrat3_wideband_receiver; rc->driver_name = DRIVER_NAME; rc->rx_resolution = US_TO_NS(2); rc->map_name = RC_MAP_HAUPPAUGE; @@ -962,7 +989,8 @@ static int redrat3_dev_probe(struct usb_interface *intf, struct usb_host_interface *uhi; struct redrat3_dev *rr3; struct usb_endpoint_descriptor *ep; - struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_narrow = NULL; + struct usb_endpoint_descriptor *ep_wide = NULL; struct usb_endpoint_descriptor *ep_out = NULL; u8 addr, attrs; int pipe, i; @@ -976,15 +1004,16 @@ static int redrat3_dev_probe(struct usb_interface *intf, addr = ep->bEndpointAddress; attrs = ep->bmAttributes; - if ((ep_in == NULL) && - ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && + if (((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { dev_dbg(dev, "found bulk-in endpoint at 0x%02x\n", ep->bEndpointAddress); - /* data comes in on 0x82, 0x81 is for other data... */ - if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR) - ep_in = ep; + /* data comes in on 0x82, 0x81 is for learning */ + if (ep->bEndpointAddress == RR3_NARROW_IN_EP_ADDR) + ep_narrow = ep; + if (ep->bEndpointAddress == RR3_WIDE_IN_EP_ADDR) + ep_wide = ep; } if ((ep_out == NULL) && @@ -997,68 +1026,76 @@ static int redrat3_dev_probe(struct usb_interface *intf, } } - if (!ep_in || !ep_out) { - dev_err(dev, "Couldn't find both in and out endpoints\n"); + if (!ep_narrow || !ep_out || !ep_wide) { + dev_err(dev, "Couldn't find all endpoints\n"); retval = -ENODEV; goto no_endpoints; } /* allocate memory for our device state and initialize it */ rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL); - if (rr3 == NULL) { - dev_err(dev, "Memory allocation failure\n"); + if (!rr3) goto no_endpoints; - } rr3->dev = &intf->dev; + rr3->ep_narrow = ep_narrow; + rr3->ep_out = ep_out; + rr3->udev = udev; /* set up bulk-in endpoint */ - rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rr3->read_urb) - goto error; + rr3->narrow_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->narrow_urb) + goto redrat_free; - rr3->ep_in = ep_in; - rr3->bulk_in_buf = usb_alloc_coherent(udev, - le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in); - if (!rr3->bulk_in_buf) { - dev_err(dev, "Read buffer allocation failure\n"); - goto error; - } - - pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); - usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf, - le16_to_cpu(ep_in->wMaxPacketSize), redrat3_handle_async, rr3); - rr3->read_urb->transfer_dma = rr3->dma_in; - rr3->read_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + rr3->wide_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->wide_urb) + goto redrat_free; - rr3->ep_out = ep_out; - rr3->udev = udev; + rr3->bulk_in_buf = usb_alloc_coherent(udev, + le16_to_cpu(ep_narrow->wMaxPacketSize), + GFP_KERNEL, &rr3->dma_in); + if (!rr3->bulk_in_buf) + goto redrat_free; + + pipe = usb_rcvbulkpipe(udev, ep_narrow->bEndpointAddress); + usb_fill_bulk_urb(rr3->narrow_urb, udev, pipe, rr3->bulk_in_buf, + le16_to_cpu(ep_narrow->wMaxPacketSize), + redrat3_handle_async, rr3); + rr3->narrow_urb->transfer_dma = rr3->dma_in; + rr3->narrow_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + pipe = usb_rcvbulkpipe(udev, ep_wide->bEndpointAddress); + usb_fill_bulk_urb(rr3->wide_urb, udev, pipe, rr3->bulk_in_buf, + le16_to_cpu(ep_narrow->wMaxPacketSize), + redrat3_handle_async, rr3); + rr3->wide_urb->transfer_dma = rr3->dma_in; + rr3->wide_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; redrat3_reset(rr3); redrat3_get_firmware_rev(rr3); - /* might be all we need to do? */ - retval = redrat3_enable_detector(rr3); - if (retval < 0) - goto error; - /* default.. will get overridden by any sends with a freq defined */ rr3->carrier = 38000; - /* led control */ - rr3->led.name = "redrat3:red:feedback"; - rr3->led.default_trigger = "rc-feedback"; - rr3->led.brightness_set = redrat3_brightness_set; - retval = led_classdev_register(&intf->dev, &rr3->led); - if (retval) - goto error; - atomic_set(&rr3->flash, 0); rr3->flash_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rr3->flash_urb) { - retval = -ENOMEM; - goto led_free_error; - } + if (!rr3->flash_urb) + goto redrat_free; + + /* learn urb */ + rr3->learn_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->learn_urb) + goto redrat_free; + + /* setup packet is 'c0 b2 0000 0000 0001' */ + rr3->learn_control.bRequestType = 0xc0; + rr3->learn_control.bRequest = RR3_MODSIG_CAPTURE; + rr3->learn_control.wLength = cpu_to_le16(1); + + usb_fill_control_urb(rr3->learn_urb, udev, usb_rcvctrlpipe(udev, 0), + (unsigned char *)&rr3->learn_control, + &rr3->learn_buf, sizeof(rr3->learn_buf), + redrat3_learn_complete, rr3); /* setup packet is 'c0 b9 0000 0000 0001' */ rr3->flash_control.bRequestType = 0xc0; @@ -1070,25 +1107,36 @@ static int redrat3_dev_probe(struct usb_interface *intf, &rr3->flash_in_buf, sizeof(rr3->flash_in_buf), redrat3_led_complete, rr3); + /* led control */ + rr3->led.name = "redrat3:red:feedback"; + rr3->led.default_trigger = "rc-feedback"; + rr3->led.brightness_set = redrat3_brightness_set; + retval = led_classdev_register(&intf->dev, &rr3->led); + if (retval) + goto redrat_free; + rr3->rc = redrat3_init_rc_dev(rr3); if (!rr3->rc) { retval = -ENOMEM; - goto led_free_error; + goto led_free; } + /* might be all we need to do? */ + retval = redrat3_enable_detector(rr3); + if (retval < 0) + goto led_free; + /* we can register the device now, as it is ready */ usb_set_intfdata(intf, rr3); return 0; -led_free_error: +led_free: led_classdev_unregister(&rr3->led); -error: +redrat_free: redrat3_delete(rr3, rr3->udev); no_endpoints: - dev_err(dev, "%s: retval = %x", __func__, retval); - return retval; } @@ -1097,9 +1145,6 @@ static void redrat3_dev_disconnect(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); struct redrat3_dev *rr3 = usb_get_intfdata(intf); - if (!rr3) - return; - usb_set_intfdata(intf, NULL); rc_unregister_device(rr3->rc); led_classdev_unregister(&rr3->led); @@ -1111,7 +1156,8 @@ static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) struct redrat3_dev *rr3 = usb_get_intfdata(intf); led_classdev_suspend(&rr3->led); - usb_kill_urb(rr3->read_urb); + usb_kill_urb(rr3->narrow_urb); + usb_kill_urb(rr3->wide_urb); usb_kill_urb(rr3->flash_urb); return 0; } @@ -1120,7 +1166,9 @@ static int redrat3_dev_resume(struct usb_interface *intf) { struct redrat3_dev *rr3 = usb_get_intfdata(intf); - if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC)) + if (usb_submit_urb(rr3->narrow_urb, GFP_ATOMIC)) + return -EIO; + if (usb_submit_urb(rr3->wide_urb, GFP_ATOMIC)) return -EIO; led_classdev_resume(&rr3->led); return 0; diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c new file mode 100644 index 000000000000..41b54e40176c --- /dev/null +++ b/drivers/media/rc/serial_ir.c @@ -0,0 +1,866 @@ +/* + * serial_ir.c + * + * serial_ir - Device driver that records pulse- and pause-lengths + * (space-lengths) between DDCD event on a serial port. + * + * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de> + * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu> + * Copyright (C) 1998 Ben Pfaff <blp@gnu.org> + * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de> + * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support) + * Copyright (C) 2016 Sean Young <sean@mess.org> (port to rc-core) + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/serial_reg.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <media/rc-core.h> + +struct serial_ir_hw { + int signal_pin; + int signal_pin_change; + u8 on; + u8 off; + unsigned set_send_carrier:1; + unsigned set_duty_cycle:1; + void (*send_pulse)(unsigned int length, ktime_t edge); + void (*send_space)(void); + spinlock_t lock; +}; + +#define IR_HOMEBREW 0 +#define IR_IRDEO 1 +#define IR_IRDEO_REMOTE 2 +#define IR_ANIMAX 3 +#define IR_IGOR 4 + +/* module parameters */ +static int type; +static int io; +static int irq; +static bool iommap; +static int ioshift; +static bool softcarrier = true; +static bool share_irq; +static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ +static bool txsense; /* 0 = active high, 1 = active low */ + +/* forward declarations */ +static void send_pulse_irdeo(unsigned int length, ktime_t edge); +static void send_space_irdeo(void); +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +static void send_pulse_homebrew(unsigned int length, ktime_t edge); +static void send_space_homebrew(void); +#endif + +static struct serial_ir_hw hardware[] = { + [IR_HOMEBREW] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_HOMEBREW].lock), + .signal_pin = UART_MSR_DCD, + .signal_pin_change = UART_MSR_DDCD, + .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), + .off = (UART_MCR_RTS | UART_MCR_OUT2), +#ifdef CONFIG_IR_SERIAL_TRANSMITTER + .send_pulse = send_pulse_homebrew, + .send_space = send_space_homebrew, + .set_send_carrier = true, + .set_duty_cycle = true, +#endif + }, + + [IR_IRDEO] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO].lock), + .signal_pin = UART_MSR_DSR, + .signal_pin_change = UART_MSR_DDSR, + .on = UART_MCR_OUT2, + .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + .send_pulse = send_pulse_irdeo, + .send_space = send_space_irdeo, + .set_duty_cycle = true, + }, + + [IR_IRDEO_REMOTE] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO_REMOTE].lock), + .signal_pin = UART_MSR_DSR, + .signal_pin_change = UART_MSR_DDSR, + .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + .send_pulse = send_pulse_irdeo, + .send_space = send_space_irdeo, + .set_duty_cycle = true, + }, + + [IR_ANIMAX] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_ANIMAX].lock), + .signal_pin = UART_MSR_DCD, + .signal_pin_change = UART_MSR_DDCD, + .on = 0, + .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + }, + + [IR_IGOR] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IGOR].lock), + .signal_pin = UART_MSR_DSR, + .signal_pin_change = UART_MSR_DDSR, + .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), + .off = (UART_MCR_RTS | UART_MCR_OUT2), +#ifdef CONFIG_IR_SERIAL_TRANSMITTER + .send_pulse = send_pulse_homebrew, + .send_space = send_space_homebrew, + .set_send_carrier = true, + .set_duty_cycle = true, +#endif + }, +}; + +#define RS_ISR_PASS_LIMIT 256 + +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; + + unsigned int pulse_width, space_width; +}; + +static struct serial_ir serial_ir; + +/* fetch serial input packet (1 byte) from register offset */ +static u8 sinp(int offset) +{ + if (iommap) + /* the register is memory-mapped */ + offset <<= ioshift; + + return inb(io + offset); +} + +/* write serial output packet (1 byte) of value to register offset */ +static void soutp(int offset, u8 value) +{ + if (iommap) + /* the register is memory-mapped */ + offset <<= ioshift; + + outb(value, io + offset); +} + +static void on(void) +{ + if (txsense) + soutp(UART_MCR, hardware[type].off); + else + soutp(UART_MCR, hardware[type].on); +} + +static void off(void) +{ + if (txsense) + soutp(UART_MCR, hardware[type].on); + else + soutp(UART_MCR, hardware[type].off); +} + +static void init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ + serial_ir.duty_cycle = new_duty_cycle; + serial_ir.freq = new_freq; + + serial_ir.pulse_width = DIV_ROUND_CLOSEST( + new_duty_cycle * NSEC_PER_SEC, new_freq * 100l); + serial_ir.space_width = DIV_ROUND_CLOSEST( + (100l - new_duty_cycle) * NSEC_PER_SEC, new_freq * 100l); +} + +static void send_pulse_irdeo(unsigned int length, ktime_t target) +{ + long rawbits; + int i; + unsigned char output; + unsigned char chunk, shifted; + + /* how many bits have to be sent ? */ + rawbits = length * 1152 / 10000; + if (serial_ir.duty_cycle > 50) + chunk = 3; + else + chunk = 1; + for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { + shifted = chunk << (i * 3); + shifted >>= 1; + output &= (~shifted); + i++; + if (i == 3) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_THRE)) + ; + output = 0x7f; + i = 0; + } + } + if (i != 0) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_TEMT)) + ; + } +} + +static void send_space_irdeo(void) +{ +} + +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +static void send_pulse_homebrew_softcarrier(unsigned int length, ktime_t edge) +{ + ktime_t now, target = ktime_add_us(edge, length); + /* + * delta should never exceed 4 seconds and on m68k + * ndelay(s64) does not compile; so use s32 rather than s64. + */ + s32 delta; + + for (;;) { + now = ktime_get(); + if (ktime_compare(now, target) >= 0) + break; + on(); + edge = ktime_add_ns(edge, serial_ir.pulse_width); + delta = ktime_to_ns(ktime_sub(edge, now)); + if (delta > 0) + ndelay(delta); + now = ktime_get(); + off(); + if (ktime_compare(now, target) >= 0) + break; + edge = ktime_add_ns(edge, serial_ir.space_width); + delta = ktime_to_ns(ktime_sub(edge, now)); + if (delta > 0) + ndelay(delta); + } +} + +static void send_pulse_homebrew(unsigned int length, ktime_t edge) +{ + if (softcarrier) + send_pulse_homebrew_softcarrier(length, edge); + else + on(); +} + +static void send_space_homebrew(void) +{ + off(); +} +#endif + +static void frbwrite(unsigned int l, bool is_pulse) +{ + /* simple noise filter */ + static unsigned int ptr, pulse, space; + DEFINE_IR_RAW_EVENT(ev); + + if (ptr > 0 && is_pulse) { + pulse += l; + if (pulse > 250000) { + ev.duration = space; + ev.pulse = false; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ev.duration = pulse; + ev.pulse = true; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ptr = 0; + pulse = 0; + } + return; + } + if (!is_pulse) { + if (ptr == 0) { + if (l > 20000000) { + space = l; + ptr++; + return; + } + } else { + if (l > 20000000) { + space += pulse; + if (space > IR_MAX_DURATION) + space = IR_MAX_DURATION; + space += l; + if (space > IR_MAX_DURATION) + space = IR_MAX_DURATION; + pulse = 0; + return; + } + + ev.duration = space; + ev.pulse = false; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ev.duration = pulse; + ev.pulse = true; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ptr = 0; + pulse = 0; + } + } + + ev.duration = l; + ev.pulse = is_pulse; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); +} + +static irqreturn_t serial_ir_irq_handler(int i, void *blah) +{ + ktime_t kt; + int counter, dcd; + u8 status; + ktime_t delkt; + unsigned int data; + static int last_dcd = -1; + + if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { + /* not our interrupt */ + return IRQ_NONE; + } + + counter = 0; + do { + counter++; + status = sinp(UART_MSR); + if (counter > RS_ISR_PASS_LIMIT) { + dev_err(&serial_ir.pdev->dev, "Trapped in interrupt"); + break; + } + if ((status & hardware[type].signal_pin_change) && + sense != -1) { + /* get current time */ + kt = ktime_get(); + + /* + * The driver needs to know if your receiver is + * active high or active low, or the space/pulse + * sense could be inverted. + */ + + /* calc time since last interrupt in nanoseconds */ + dcd = (status & hardware[type].signal_pin) ? 1 : 0; + + if (dcd == last_dcd) { + dev_err(&serial_ir.pdev->dev, + "ignoring spike: %d %d %lldns %lldns\n", + dcd, sense, ktime_to_ns(kt), + ktime_to_ns(serial_ir.lastkt)); + continue; + } + + delkt = ktime_sub(kt, serial_ir.lastkt); + if (ktime_compare(delkt, ktime_set(15, 0)) > 0) { + data = IR_MAX_DURATION; /* really long time */ + if (!(dcd ^ sense)) { + /* sanity check */ + dev_err(&serial_ir.pdev->dev, + "dcd unexpected: %d %d %lldns %lldns\n", + dcd, sense, ktime_to_ns(kt), + ktime_to_ns(serial_ir.lastkt)); + /* + * detecting pulse while this + * MUST be a space! + */ + sense = sense ? 0 : 1; + } + } else { + data = ktime_to_ns(delkt); + } + frbwrite(data, !(dcd ^ sense)); + serial_ir.lastkt = kt; + last_dcd = dcd; + } + } 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; +} + +static int hardware_init_port(void) +{ + u8 scratch, scratch2, scratch3; + + /* + * This is a simple port existence test, borrowed from the autoconfig + * function in drivers/tty/serial/8250/8250_port.c + */ + scratch = sinp(UART_IER); + soutp(UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + scratch2 = sinp(UART_IER) & 0x0f; + soutp(UART_IER, 0x0f); +#ifdef __i386__ + outb(0x00, 0x080); +#endif + scratch3 = sinp(UART_IER) & 0x0f; + soutp(UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0f) { + /* we fail, there's nothing here */ + pr_err("port existence test failed, cannot continue\n"); + return -ENODEV; + } + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + /* Set line for power source */ + off(); + + /* Clear registers again to be sure. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + switch (type) { + case IR_IRDEO: + case IR_IRDEO_REMOTE: + /* setup port to 7N1 @ 115200 Baud */ + /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ + + /* Set DLAB 1. */ + soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); + /* Set divisor to 1 => 115200 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 1); + /* Set DLAB 0 + 7N1 */ + soutp(UART_LCR, UART_LCR_WLEN7); + /* THR interrupt already disabled at this point */ + break; + default: + break; + } + + 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); +} + +/* Needed by serial_ir_probe() */ +static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + unsigned int count); +static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle); +static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier); +static int serial_ir_open(struct rc_dev *rcdev); +static void serial_ir_close(struct rc_dev *rcdev); + +static int serial_ir_probe(struct platform_device *dev) +{ + struct rc_dev *rcdev; + int i, nlow, nhigh, result; + + rcdev = devm_rc_allocate_device(&dev->dev, RC_DRIVER_IR_RAW); + if (!rcdev) + return -ENOMEM; + + if (hardware[type].send_pulse && hardware[type].send_space) + rcdev->tx_ir = serial_ir_tx; + if (hardware[type].set_send_carrier) + rcdev->s_tx_carrier = serial_ir_tx_carrier; + if (hardware[type].set_duty_cycle) + rcdev->s_tx_duty_cycle = serial_ir_tx_duty_cycle; + + switch (type) { + case IR_HOMEBREW: + rcdev->input_name = "Serial IR type home-brew"; + break; + case IR_IRDEO: + rcdev->input_name = "Serial IR type IRdeo"; + break; + case IR_IRDEO_REMOTE: + rcdev->input_name = "Serial IR type IRdeo remote"; + break; + case IR_ANIMAX: + rcdev->input_name = "Serial IR type AnimaX"; + break; + case IR_IGOR: + rcdev->input_name = "Serial IR type IgorPlug"; + break; + } + + rcdev->input_phys = KBUILD_MODNAME "/input0"; + rcdev->input_id.bustype = BUS_HOST; + rcdev->input_id.vendor = 0x0001; + rcdev->input_id.product = 0x0001; + rcdev->input_id.version = 0x0100; + rcdev->open = serial_ir_open; + rcdev->close = serial_ir_close; + rcdev->dev.parent = &serial_ir.pdev->dev; + 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; + + setup_timer(&serial_ir.timeout_timer, serial_ir_timeout, + (unsigned long)&serial_ir); + + result = devm_request_irq(&dev->dev, irq, serial_ir_irq_handler, + share_irq ? IRQF_SHARED : 0, + KBUILD_MODNAME, &hardware); + if (result < 0) { + if (result == -EBUSY) + dev_err(&dev->dev, "IRQ %d busy\n", irq); + else if (result == -EINVAL) + dev_err(&dev->dev, "Bad irq number or handler\n"); + return result; + } + + /* Reserve io region. */ + if ((iommap && + (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift, + KBUILD_MODNAME) == NULL)) || + (!iommap && (devm_request_region(&dev->dev, io, 8, + KBUILD_MODNAME) == NULL))) { + dev_err(&dev->dev, "port %04x already in use\n", io); + dev_warn(&dev->dev, "use 'setserial /dev/ttySX uart none'\n"); + dev_warn(&dev->dev, + "or compile the serial port driver as module and\n"); + dev_warn(&dev->dev, "make sure this module is loaded first\n"); + return -EBUSY; + } + + result = hardware_init_port(); + if (result < 0) + return result; + + /* Initialize pulse/space widths */ + init_timing_params(50, 38000); + + /* If pin is high, then this must be an active low receiver. */ + if (sense == -1) { + /* wait 1/2 sec for the power supply */ + msleep(500); + + /* + * probe 9 times every 0.04s, collect "votes" for + * active high/low + */ + nlow = 0; + nhigh = 0; + for (i = 0; i < 9; i++) { + if (sinp(UART_MSR) & hardware[type].signal_pin) + nlow++; + else + nhigh++; + msleep(40); + } + sense = nlow >= nhigh ? 1 : 0; + dev_info(&dev->dev, "auto-detected active %s receiver\n", + sense ? "low" : "high"); + } else + dev_info(&dev->dev, "Manually using active %s receiver\n", + sense ? "low" : "high"); + + dev_dbg(&dev->dev, "Interrupt %d, port %04x obtained\n", irq, io); + + return devm_rc_register_device(&dev->dev, rcdev); +} + +static int serial_ir_open(struct rc_dev *rcdev) +{ + unsigned long flags; + + /* initialize timestamp */ + serial_ir.lastkt = ktime_get(); + + spin_lock_irqsave(&hardware[type].lock, flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); + + spin_unlock_irqrestore(&hardware[type].lock, flags); + + return 0; +} + +static void serial_ir_close(struct rc_dev *rcdev) +{ + unsigned long flags; + + spin_lock_irqsave(&hardware[type].lock, flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); + spin_unlock_irqrestore(&hardware[type].lock, flags); +} + +static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + unsigned int count) +{ + unsigned long flags; + ktime_t edge; + s64 delta; + int i; + + spin_lock_irqsave(&hardware[type].lock, flags); + if (type == IR_IRDEO) { + /* DTR, RTS down */ + on(); + } + + edge = ktime_get(); + for (i = 0; i < count; i++) { + if (i % 2) + hardware[type].send_space(); + else + hardware[type].send_pulse(txbuf[i], edge); + + edge = ktime_add_us(edge, txbuf[i]); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 25) { + spin_unlock_irqrestore(&hardware[type].lock, flags); + usleep_range(delta - 25, delta + 25); + spin_lock_irqsave(&hardware[type].lock, flags); + } else if (delta > 0) { + udelay(delta); + } + } + off(); + spin_unlock_irqrestore(&hardware[type].lock, flags); + return count; +} + +static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle) +{ + init_timing_params(cycle, serial_ir.freq); + return 0; +} + +static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + if (carrier > 500000 || carrier < 20000) + return -EINVAL; + + init_timing_params(serial_ir.duty_cycle, carrier); + return 0; +} + +static int serial_ir_suspend(struct platform_device *dev, + pm_message_t state) +{ + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* Disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + return 0; +} + +static int serial_ir_resume(struct platform_device *dev) +{ + unsigned long flags; + int result; + + result = hardware_init_port(); + if (result < 0) + return result; + + spin_lock_irqsave(&hardware[type].lock, flags); + /* Enable Interrupt */ + serial_ir.lastkt = ktime_get(); + soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); + off(); + + spin_unlock_irqrestore(&hardware[type].lock, flags); + + return 0; +} + +static struct platform_driver serial_ir_driver = { + .probe = serial_ir_probe, + .suspend = serial_ir_suspend, + .resume = serial_ir_resume, + .driver = { + .name = "serial_ir", + }, +}; + +static int __init serial_ir_init(void) +{ + int result; + + result = platform_driver_register(&serial_ir_driver); + if (result) + return result; + + serial_ir.pdev = platform_device_alloc("serial_ir", 0); + if (!serial_ir.pdev) { + result = -ENOMEM; + goto exit_driver_unregister; + } + + result = platform_device_add(serial_ir.pdev); + if (result) + goto exit_device_put; + + return 0; + +exit_device_put: + platform_device_put(serial_ir.pdev); +exit_driver_unregister: + platform_driver_unregister(&serial_ir_driver); + return result; +} + +static void serial_ir_exit(void) +{ + platform_device_unregister(serial_ir.pdev); + platform_driver_unregister(&serial_ir_driver); +} + +static int __init serial_ir_init_module(void) +{ + int result; + + switch (type) { + case IR_HOMEBREW: + case IR_IRDEO: + case IR_IRDEO_REMOTE: + case IR_ANIMAX: + case IR_IGOR: + /* if nothing specified, use ttyS0/com1 and irq 4 */ + io = io ? io : 0x3f8; + irq = irq ? irq : 4; + break; + default: + return -EINVAL; + } + if (!softcarrier) { + switch (type) { + case IR_HOMEBREW: + case IR_IGOR: + hardware[type].set_send_carrier = false; + hardware[type].set_duty_cycle = false; + break; + } + } + + /* make sure sense is either -1, 0, or 1 */ + if (sense != -1) + sense = !!sense; + + result = serial_ir_init(); + if (!result) + return 0; + + serial_ir_exit(); + return result; +} + +static void __exit serial_ir_exit_module(void) +{ + del_timer_sync(&serial_ir.timeout_timer); + serial_ir_exit(); +} + +module_init(serial_ir_init_module); +module_exit(serial_ir_exit_module); + +MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); +MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus, Andrei Tanas"); +MODULE_LICENSE("GPL"); + +module_param(type, int, 0444); +MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo, 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug"); + +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); + +/* some architectures (e.g. intel xscale) have memory mapped registers */ +module_param(iommap, bool, 0444); +MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); + +/* + * some architectures (e.g. intel xscale) align the 8bit serial registers + * on 32bit word boundaries. + * See linux-kernel/drivers/tty/serial/8250/8250.c serial_in()/out() + */ +module_param(ioshift, int, 0444); +MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); + +module_param(irq, int, 0444); +MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); + +module_param(share_irq, bool, 0444); +MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); + +module_param(sense, int, 0444); +MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit (0 = active high, 1 = active low )"); + +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +module_param(txsense, bool, 0444); +MODULE_PARM_DESC(txsense, "Sense of transmitter circuit (0 = active high, 1 = active low )"); +#endif + +module_param(softcarrier, bool, 0444); +MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); 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 4004260a7c69..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,14 +287,13 @@ 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; } - snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared " - "Receiver (%04x:%04x)", + snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared Receiver (%04x:%04x)", le16_to_cpu(sz->usbdev->descriptor.idVendor), le16_to_cpu(sz->usbdev->descriptor.idProduct)); usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys)); @@ -309,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; @@ -364,15 +358,15 @@ static int streamzap_probe(struct usb_interface *intf, sz->endpoint = &(iface_host->endpoint[0].desc); if (!usb_endpoint_dir_in(sz->endpoint)) { - dev_err(&intf->dev, "%s: endpoint doesn't match input device " - "02%02x\n", __func__, sz->endpoint->bEndpointAddress); + dev_err(&intf->dev, "%s: endpoint doesn't match input device 02%02x\n", + __func__, sz->endpoint->bEndpointAddress); retval = -ENODEV; goto free_sz; } if (!usb_endpoint_xfer_int(sz->endpoint)) { - dev_err(&intf->dev, "%s: endpoint attributes don't match xfer " - "02%02x\n", __func__, sz->endpoint->bmAttributes); + dev_err(&intf->dev, "%s: endpoint attributes don't match xfer 02%02x\n", + __func__, sz->endpoint->bmAttributes); retval = -ENODEV; goto free_sz; } 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 95ae60e659a1..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,11 +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"); @@ -238,16 +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)"); - - /***************************************************************************** * @@ -660,7 +640,7 @@ wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count) unsigned i; unsigned long flags; - buf = kmalloc(count * sizeof(*b), GFP_KERNEL); + buf = kmalloc_array(count, sizeof(*b), GFP_KERNEL); if (!buf) return -ENOMEM; @@ -698,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; @@ -857,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 */ @@ -877,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) { @@ -889,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); @@ -1050,8 +1050,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) goto exit_free_data; } - dev_dbg(&device->dev, "Found device " - "(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", + dev_dbg(&device->dev, "Found device (w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", data->wbase, data->ebase, data->sbase, data->irq); data->led.name = "cir::activity"; @@ -1062,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"; @@ -1086,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) @@ -1188,7 +1194,7 @@ static const struct pnp_device_id wbcir_ids[] = { MODULE_DEVICE_TABLE(pnp, wbcir_ids); static struct pnp_driver wbcir_driver = { - .name = WBCIR_NAME, + .name = DRVNAME, .id_table = wbcir_ids, .probe = wbcir_probe, .remove = wbcir_remove, @@ -1202,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"); |