summaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/Kconfig8
-rw-r--r--drivers/media/rc/ati_remote.c3
-rw-r--r--drivers/media/rc/iguanair.c1
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.c4
-rw-r--r--drivers/media/rc/imon.c2
-rw-r--r--drivers/media/rc/ir-lirc-codec.c37
-rw-r--r--drivers/media/rc/ir-spi.c11
-rw-r--r--drivers/media/rc/lirc_dev.c254
-rw-r--r--drivers/media/rc/mceusb.c158
-rw-r--r--drivers/media/rc/meson-ir.c89
-rw-r--r--drivers/media/rc/rc-core-priv.h2
-rw-r--r--drivers/media/rc/rc-ir-raw.c43
-rw-r--r--drivers/media/rc/rc-main.c160
-rw-r--r--drivers/media/rc/sir_ir.c100
14 files changed, 372 insertions, 500 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index e422f3d56f76..5e83b76495f7 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -169,11 +169,11 @@ config IR_HIX5HD2
tristate "Hisilicon hix5hd2 IR remote control"
depends on RC_CORE
help
- Say Y here if you want to use hisilicon hix5hd2 remote control.
- To compile this driver as a module, choose M here: the module will be
- called ir-hix5hd2.
+ Say Y here if you want to use hisilicon hix5hd2 remote control.
+ To compile this driver as a module, choose M here: the module will be
+ called ir-hix5hd2.
- If you're not sure, select N here
+ If you're not sure, select N here
config IR_IMON
tristate "SoundGraph iMON Receiver and Display"
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 9cf3e69de16a..a4c6ad4f67c1 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -904,9 +904,6 @@ static int ati_remote_probe(struct usb_interface *interface,
if (err)
goto exit_kill_urbs;
- /* use our delay for rc_dev */
- ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay;
-
/* Set up and register mouse input device */
if (mouse) {
input_dev = input_allocate_device();
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index ccf24fd7ec1b..8711a7ff55cc 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -113,6 +113,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
break;
case CMD_TX_OVERFLOW:
ir->tx_overflow = true;
+ /* fall through */
case CMD_RECEIVER_OFF:
case CMD_RECEIVER_ON:
case CMD_SEND:
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 431d33b36fb0..8d1439622533 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -702,10 +702,6 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
{
struct rc_dev *rdev = priv->hw.rdev;
- spin_lock_irq(&rdev->rc_map.lock);
- rdev->rc_map.rc_type = __ffs64(proto);
- spin_unlock_irq(&rdev->rc_map.lock);
-
mutex_lock(&rdev->lock);
rdev->enabled_protocols = proto;
rdev->allowed_wakeup_protocols = proto;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 3489010601b5..bd76534a2749 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1722,7 +1722,7 @@ static void imon_incoming_scancode(struct imon_context *ictx,
if (kc == KEY_KEYBOARD && !ictx->release_code) {
ictx->last_keycode = kc;
if (!nomouse) {
- ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
+ ictx->pad_mouse = !ictx->pad_mouse;
dev_dbg(dev, "toggling to %s mode\n",
ictx->pad_mouse ? "mouse" : "keyboard");
spin_unlock_irqrestore(&ictx->kc_lock, flags);
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index de85f1d7ce43..a30af91710fe 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -327,16 +327,6 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
return ret;
}
-static int ir_lirc_open(void *data)
-{
- return 0;
-}
-
-static void ir_lirc_close(void *data)
-{
- return;
-}
-
static const struct file_operations lirc_fops = {
.owner = THIS_MODULE,
.write = ir_lirc_transmit_ir,
@@ -354,7 +344,6 @@ static const struct file_operations lirc_fops = {
static int ir_lirc_register(struct rc_dev *dev)
{
struct lirc_driver *drv;
- struct lirc_buffer *rbuf;
int rc = -ENOMEM;
unsigned long features = 0;
@@ -362,19 +351,12 @@ static int ir_lirc_register(struct rc_dev *dev)
if (!drv)
return rc;
- rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
- if (!rbuf)
- goto rbuf_alloc_failed;
-
- rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
- if (rc)
- goto rbuf_init_failed;
-
if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
features |= LIRC_CAN_REC_MODE2;
if (dev->rx_resolution)
features |= LIRC_CAN_GET_REC_RESOLUTION;
}
+
if (dev->tx_ir) {
features |= LIRC_CAN_SEND_PULSE;
if (dev->s_tx_mask)
@@ -403,10 +385,10 @@ static int ir_lirc_register(struct rc_dev *dev)
drv->minor = -1;
drv->features = features;
drv->data = &dev->raw->lirc;
- drv->rbuf = rbuf;
- drv->set_use_inc = &ir_lirc_open;
- drv->set_use_dec = &ir_lirc_close;
+ drv->rbuf = NULL;
drv->code_length = sizeof(struct ir_raw_event) * 8;
+ drv->chunk_size = sizeof(int);
+ drv->buffer_size = LIRCBUF_SIZE;
drv->fops = &lirc_fops;
drv->dev = &dev->dev;
drv->rdev = dev;
@@ -415,19 +397,15 @@ static int ir_lirc_register(struct rc_dev *dev)
drv->minor = lirc_register_driver(drv);
if (drv->minor < 0) {
rc = -ENODEV;
- goto lirc_register_failed;
+ goto out;
}
dev->raw->lirc.drv = drv;
dev->raw->lirc.dev = dev;
return 0;
-lirc_register_failed:
-rbuf_init_failed:
- kfree(rbuf);
-rbuf_alloc_failed:
+out:
kfree(drv);
-
return rc;
}
@@ -436,9 +414,8 @@ static int ir_lirc_unregister(struct rc_dev *dev)
struct lirc_codec *lirc = &dev->raw->lirc;
lirc_unregister_driver(lirc->drv->minor);
- lirc_buffer_free(lirc->drv->rbuf);
- kfree(lirc->drv->rbuf);
kfree(lirc->drv);
+ lirc->drv = NULL;
return 0;
}
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
index c8863f36686a..7e383b3fedd5 100644
--- a/drivers/media/rc/ir-spi.c
+++ b/drivers/media/rc/ir-spi.c
@@ -57,10 +57,13 @@ static int ir_spi_tx(struct rc_dev *dev,
/* convert the pulse/space signal to raw binary signal */
for (i = 0; i < count; i++) {
+ unsigned int periods;
int j;
- u16 val = ((i + 1) % 2) ? idata->pulse : idata->space;
+ u16 val;
- if (len + buffer[i] >= IR_SPI_MAX_BUFSIZE)
+ periods = DIV_ROUND_CLOSEST(buffer[i] * idata->freq, 1000000);
+
+ if (len + periods >= IR_SPI_MAX_BUFSIZE)
return -EINVAL;
/*
@@ -69,13 +72,13 @@ static int ir_spi_tx(struct rc_dev *dev,
* contain a space duration.
*/
val = (i % 2) ? idata->space : idata->pulse;
- for (j = 0; j < buffer[i]; j++)
+ for (j = 0; j < periods; j++)
idata->tx_buf[len++] = val;
}
memset(&xfer, 0, sizeof(xfer));
- xfer.speed_hz = idata->freq;
+ xfer.speed_hz = idata->freq * 16;
xfer.len = len * sizeof(*idata->tx_buf);
xfer.tx_buf = idata->tx_buf;
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 8d60c9f00df9..db1e7b70c998 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -18,18 +18,10 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/sched/signal.h>
-#include <linux/errno.h>
#include <linux/ioctl.h>
-#include <linux/fs.h>
#include <linux/poll.h>
-#include <linux/completion.h>
#include <linux/mutex.h>
-#include <linux/wait.h>
-#include <linux/unistd.h>
-#include <linux/kthread.h>
-#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/cdev.h>
@@ -37,9 +29,6 @@
#include <media/lirc.h>
#include <media/lirc_dev.h>
-static bool debug;
-
-#define IRCTL_DEV_NAME "BaseRemoteCtl"
#define NOPLUG -1
#define LOGHEAD "lirc_dev (%s[%d]): "
@@ -52,13 +41,11 @@ struct irctl {
struct mutex irctl_lock;
struct lirc_buffer *buf;
+ bool buf_internal;
unsigned int chunk_size;
struct device dev;
struct cdev cdev;
-
- struct task_struct *task;
- long jiffies_to_wait;
};
static DEFINE_MUTEX(lirc_dev_lock);
@@ -68,22 +55,11 @@ static struct irctl *irctls[MAX_IRCTL_DEVICES];
/* Only used for sysfs but defined to void otherwise */
static struct class *lirc_class;
-/* helper function
- * initializes the irctl structure
- */
-static void lirc_irctl_init(struct irctl *ir)
-{
- mutex_init(&ir->irctl_lock);
- ir->d.minor = NOPLUG;
-}
-
static void lirc_release(struct device *ld)
{
struct irctl *ir = container_of(ld, struct irctl, dev);
- put_device(ir->dev.parent);
-
- if (ir->buf != ir->d.rbuf) {
+ if (ir->buf_internal) {
lirc_buffer_free(ir->buf);
kfree(ir->buf);
}
@@ -94,93 +70,6 @@ static void lirc_release(struct device *ld)
kfree(ir);
}
-/* helper function
- * reads key codes from driver and puts them into buffer
- * returns 0 on success
- */
-static int lirc_add_to_buf(struct irctl *ir)
-{
- int res;
- int got_data = -1;
-
- if (!ir->d.add_to_buf)
- return 0;
-
- /*
- * service the device as long as it is returning
- * data and we have space
- */
- do {
- got_data++;
- res = ir->d.add_to_buf(ir->d.data, ir->buf);
- } while (!res);
-
- if (res == -ENODEV)
- kthread_stop(ir->task);
-
- return got_data ? 0 : res;
-}
-
-/* main function of the polling thread
- */
-static int lirc_thread(void *irctl)
-{
- struct irctl *ir = irctl;
-
- do {
- if (ir->open) {
- if (ir->jiffies_to_wait) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(ir->jiffies_to_wait);
- }
- if (kthread_should_stop())
- break;
- if (!lirc_add_to_buf(ir))
- wake_up_interruptible(&ir->buf->wait_poll);
- } else {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
- } while (!kthread_should_stop());
-
- return 0;
-}
-
-
-static const struct file_operations lirc_dev_fops = {
- .owner = THIS_MODULE,
- .read = lirc_dev_fop_read,
- .write = lirc_dev_fop_write,
- .poll = lirc_dev_fop_poll,
- .unlocked_ioctl = lirc_dev_fop_ioctl,
- .open = lirc_dev_fop_open,
- .release = lirc_dev_fop_close,
- .llseek = noop_llseek,
-};
-
-static int lirc_cdev_add(struct irctl *ir)
-{
- struct lirc_driver *d = &ir->d;
- struct cdev *cdev;
- int retval;
-
- cdev = &ir->cdev;
-
- if (d->fops) {
- cdev_init(cdev, d->fops);
- cdev->owner = d->owner;
- } else {
- cdev_init(cdev, &lirc_dev_fops);
- cdev->owner = THIS_MODULE;
- }
- retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
- if (retval)
- return retval;
-
- cdev->kobj.parent = &ir->dev.kobj;
- return cdev_add(cdev, ir->dev.devt, 1);
-}
-
static int lirc_allocate_buffer(struct irctl *ir)
{
int err = 0;
@@ -189,8 +78,6 @@ static int lirc_allocate_buffer(struct irctl *ir)
unsigned int buffer_size;
struct lirc_driver *d = &ir->d;
- mutex_lock(&lirc_dev_lock);
-
bytes_in_key = BITS_TO_LONGS(d->code_length) +
(d->code_length % 8 ? 1 : 0);
buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
@@ -198,6 +85,7 @@ static int lirc_allocate_buffer(struct irctl *ir)
if (d->rbuf) {
ir->buf = d->rbuf;
+ ir->buf_internal = false;
} else {
ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
if (!ir->buf) {
@@ -208,18 +96,20 @@ static int lirc_allocate_buffer(struct irctl *ir)
err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
if (err) {
kfree(ir->buf);
+ ir->buf = NULL;
goto out;
}
+
+ ir->buf_internal = true;
+ d->rbuf = ir->buf;
}
ir->chunk_size = ir->buf->chunk_size;
out:
- mutex_unlock(&lirc_dev_lock);
-
return err;
}
-static int lirc_allocate_driver(struct lirc_driver *d)
+int lirc_register_driver(struct lirc_driver *d)
{
struct irctl *ir;
int minor;
@@ -235,6 +125,11 @@ static int lirc_allocate_driver(struct lirc_driver *d)
return -EINVAL;
}
+ if (!d->fops) {
+ pr_err("fops pointer not filled in!\n");
+ return -EINVAL;
+ }
+
if (d->minor >= MAX_IRCTL_DEVICES) {
dev_err(d->dev, "minor must be between 0 and %d!\n",
MAX_IRCTL_DEVICES - 1);
@@ -247,18 +142,8 @@ static int lirc_allocate_driver(struct lirc_driver *d)
return -EBADRQC;
}
- if (d->sample_rate) {
- if (2 > d->sample_rate || HZ < d->sample_rate) {
- dev_err(d->dev, "invalid %d sample rate\n",
- d->sample_rate);
- return -EBADRQC;
- }
- if (!d->add_to_buf) {
- dev_err(d->dev, "add_to_buf not set\n");
- return -EBADRQC;
- }
- } else if (!d->rbuf && !(d->fops && d->fops->read &&
- d->fops->poll && d->fops->unlocked_ioctl)) {
+ if (!d->rbuf && !(d->fops && d->fops->read &&
+ d->fops->poll && d->fops->unlocked_ioctl)) {
dev_err(d->dev, "undefined read, poll, ioctl\n");
return -EBADRQC;
}
@@ -288,7 +173,8 @@ static int lirc_allocate_driver(struct lirc_driver *d)
err = -ENOMEM;
goto out_lock;
}
- lirc_irctl_init(ir);
+
+ mutex_init(&ir->irctl_lock);
irctls[minor] = ir;
d->minor = minor;
@@ -300,32 +186,29 @@ static int lirc_allocate_driver(struct lirc_driver *d)
ir->d = *d;
+ if (LIRC_CAN_REC(d->features)) {
+ err = lirc_allocate_buffer(irctls[minor]);
+ if (err) {
+ kfree(ir);
+ goto out_lock;
+ }
+ d->rbuf = ir->buf;
+ }
+
+ device_initialize(&ir->dev);
ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor);
ir->dev.class = lirc_class;
ir->dev.parent = d->dev;
ir->dev.release = lirc_release;
dev_set_name(&ir->dev, "lirc%d", ir->d.minor);
- device_initialize(&ir->dev);
- if (d->sample_rate) {
- ir->jiffies_to_wait = HZ / d->sample_rate;
+ cdev_init(&ir->cdev, d->fops);
+ ir->cdev.owner = ir->d.owner;
+ ir->cdev.kobj.parent = &ir->dev.kobj;
- /* try to fire up polling thread */
- ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev");
- if (IS_ERR(ir->task)) {
- dev_err(d->dev, "cannot run thread for minor = %d\n",
- d->minor);
- err = -ECHILD;
- goto out_sysfs;
- }
- } else {
- /* it means - wait for external event in task queue */
- ir->jiffies_to_wait = 0;
- }
-
- err = lirc_cdev_add(ir);
+ err = cdev_add(&ir->cdev, ir->dev.devt, 1);
if (err)
- goto out_sysfs;
+ goto out_free_dev;
ir->attached = 1;
@@ -335,37 +218,20 @@ static int lirc_allocate_driver(struct lirc_driver *d)
mutex_unlock(&lirc_dev_lock);
- get_device(ir->dev.parent);
-
dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
ir->d.name, ir->d.minor);
+
return minor;
+
out_cdev:
cdev_del(&ir->cdev);
-out_sysfs:
+out_free_dev:
put_device(&ir->dev);
out_lock:
mutex_unlock(&lirc_dev_lock);
return err;
}
-
-int lirc_register_driver(struct lirc_driver *d)
-{
- int minor, err = 0;
-
- minor = lirc_allocate_driver(d);
- if (minor < 0)
- return minor;
-
- if (LIRC_CAN_REC(d->features)) {
- err = lirc_allocate_buffer(irctls[minor]);
- if (err)
- lirc_unregister_driver(minor);
- }
-
- return err ? err : minor;
-}
EXPORT_SYMBOL(lirc_register_driver);
int lirc_unregister_driver(int minor)
@@ -393,10 +259,6 @@ int lirc_unregister_driver(int minor)
return -ENOENT;
}
- /* end up polling thread */
- if (ir->task)
- kthread_stop(ir->task);
-
dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
ir->d.name, ir->d.minor);
@@ -407,12 +269,6 @@ int lirc_unregister_driver(int minor)
wake_up_interruptible(&ir->buf->wait_poll);
}
- mutex_lock(&ir->irctl_lock);
-
- if (ir->d.set_use_dec)
- ir->d.set_use_dec(ir->d.data);
-
- mutex_unlock(&ir->irctl_lock);
mutex_unlock(&lirc_dev_lock);
device_del(&ir->dev);
@@ -462,17 +318,10 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
goto error;
}
+ if (ir->buf)
+ lirc_buffer_clear(ir->buf);
+
ir->open++;
- if (ir->d.set_use_inc)
- retval = ir->d.set_use_inc(ir->d.data);
- if (retval) {
- ir->open--;
- } else {
- if (ir->buf)
- lirc_buffer_clear(ir->buf);
- if (ir->task)
- wake_up_process(ir->task);
- }
error:
nonseekable_open(inode, file);
@@ -497,8 +346,6 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
rc_close(ir->d.rdev);
ir->open--;
- if (ir->d.set_use_dec)
- ir->d.set_use_dec(ir->d.data);
if (!ret)
mutex_unlock(&lirc_dev_lock);
@@ -517,7 +364,7 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
}
if (!ir->attached)
- return POLLERR;
+ return POLLHUP | POLLERR;
if (ir->buf) {
poll_wait(file, &ir->buf->wait_poll, wait);
@@ -729,24 +576,6 @@ void *lirc_get_pdata(struct file *file)
EXPORT_SYMBOL(lirc_get_pdata);
-ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
- size_t length, loff_t *ppos)
-{
- struct irctl *ir = irctls[iminor(file_inode(file))];
-
- if (!ir) {
- pr_err("called with invalid irctl\n");
- return -ENODEV;
- }
-
- if (!ir->attached)
- return -ENODEV;
-
- return -EINVAL;
-}
-EXPORT_SYMBOL(lirc_dev_fop_write);
-
-
static int __init lirc_dev_init(void)
{
int retval;
@@ -758,7 +587,7 @@ static int __init lirc_dev_init(void)
}
retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
- IRCTL_DEV_NAME);
+ "BaseRemoteCtl");
if (retval) {
class_destroy(lirc_class);
pr_err("alloc_chrdev_region failed\n");
@@ -784,6 +613,3 @@ module_exit(lirc_dev_exit);
MODULE_DESCRIPTION("LIRC base driver module");
MODULE_AUTHOR("Artur Lipowski");
MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 93b16fe3ab38..eb130694bbb8 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -36,18 +36,18 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <linux/pm_wakeup.h>
#include <media/rc-core.h>
-#define DRIVER_VERSION "1.92"
+#define DRIVER_VERSION "1.93"
#define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \
"device driver"
#define DRIVER_NAME "mceusb"
-#define USB_BUFLEN 32 /* USB reception buffer length */
#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
@@ -417,7 +417,9 @@ struct mceusb_dev {
/* usb */
struct usb_device *usbdev;
struct urb *urb_in;
+ unsigned int pipe_in;
struct usb_endpoint_descriptor *usb_ep_out;
+ unsigned int pipe_out;
/* buffers and dma */
unsigned char *buf_in;
@@ -454,6 +456,16 @@ struct mceusb_dev {
u8 num_rxports; /* number of receive sensors */
u8 txports_cabled; /* bitmask of transmitters with cable */
u8 rxports_active; /* bitmask of active receive sensors */
+
+ /*
+ * support for async error handler mceusb_deferred_kevent()
+ * where usb_clear_halt(), usb_reset_configuration(),
+ * usb_reset_device(), etc. must be done in process context
+ */
+ struct work_struct kevent;
+ unsigned long kevent_flags;
+# define EVENT_TX_HALT 0
+# define EVENT_RX_HALT 1
};
/* MCE Device Command Strings, generally a port and command pair */
@@ -527,7 +539,7 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd)
}
static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
- int offset, int len, bool out)
+ int buf_len, int offset, int len, bool out)
{
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
char *inout;
@@ -544,7 +556,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
return;
dev_dbg(dev, "%cx data: %*ph (length=%d)",
- (out ? 't' : 'r'), min(len, USB_BUFLEN), buf, len);
+ (out ? 't' : 'r'),
+ min(len, buf_len - offset), buf + offset, len);
inout = out ? "Request" : "Got";
@@ -686,6 +699,21 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
#endif
}
+/*
+ * Schedule work that can't be done in interrupt handlers
+ * (mceusb_dev_recv() and mce_async_callback()) nor tasklets.
+ * Invokes mceusb_deferred_kevent() for recovering from
+ * error events specified by the kevent bit field.
+ */
+static void mceusb_defer_kevent(struct mceusb_dev *ir, int kevent)
+{
+ set_bit(kevent, &ir->kevent_flags);
+ if (!schedule_work(&ir->kevent))
+ dev_err(ir->dev, "kevent %d may have been dropped", kevent);
+ else
+ dev_dbg(ir->dev, "kevent %d scheduled", kevent);
+}
+
static void mce_async_callback(struct urb *urb)
{
struct mceusb_dev *ir;
@@ -701,7 +729,8 @@ static void mce_async_callback(struct urb *urb)
case 0:
len = urb->actual_length;
- mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
+ mceusb_dev_printdata(ir, urb->transfer_buffer, len,
+ 0, len, true);
break;
case -ECONNRESET:
@@ -711,6 +740,11 @@ static void mce_async_callback(struct urb *urb)
break;
case -EPIPE:
+ dev_err(ir->dev, "Error: request urb status = %d (TX HALT)",
+ urb->status);
+ mceusb_defer_kevent(ir, EVENT_TX_HALT);
+ break;
+
default:
dev_err(ir->dev, "Error: request urb status = %d", urb->status);
break;
@@ -721,18 +755,18 @@ static void mce_async_callback(struct urb *urb)
usb_free_urb(urb);
}
-/* request incoming or send outgoing usb packet - used to initialize remote */
+/* request outgoing (send) usb packet - used to initialize remote */
static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
int size)
{
- int res, pipe;
+ int res;
struct urb *async_urb;
struct device *dev = ir->dev;
unsigned char *async_buf;
async_urb = usb_alloc_urb(0, GFP_KERNEL);
if (unlikely(!async_urb)) {
- dev_err(dev, "Error, couldn't allocate urb!\n");
+ dev_err(dev, "Error, couldn't allocate urb!");
return;
}
@@ -743,32 +777,26 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
}
/* 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,
+ if (usb_endpoint_xfer_int(ir->usb_ep_out))
+ usb_fill_int_urb(async_urb, ir->usbdev, ir->pipe_out,
+ 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);
+ else
+ usb_fill_bulk_urb(async_urb, ir->usbdev, ir->pipe_out,
+ async_buf, size, mce_async_callback, ir);
- dev_dbg(dev, "receive request called (size=%#x)", size);
+ memcpy(async_buf, data, size);
- async_urb->transfer_buffer_length = size;
- async_urb->dev = ir->usbdev;
+ dev_dbg(dev, "send request called (size=%#x)", size);
res = usb_submit_urb(async_urb, GFP_ATOMIC);
if (res) {
- dev_err(dev, "receive request FAILED! (res=%d)", res);
+ dev_err(dev, "send request FAILED! (res=%d)", res);
+ kfree(async_buf);
+ usb_free_urb(async_urb);
return;
}
- dev_dbg(dev, "receive request complete (res=%d)", res);
+ dev_dbg(dev, "send request complete (res=%d)", res);
}
static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
@@ -974,7 +1002,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
switch (ir->parser_state) {
case SUBCMD:
ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]);
- mceusb_dev_printdata(ir, ir->buf_in, i - 1,
+ mceusb_dev_printdata(ir, ir->buf_in, buf_len, i - 1,
ir->rem + 2, false);
mceusb_handle_command(ir, i);
ir->parser_state = CMD_DATA;
@@ -986,7 +1014,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
* US_TO_NS(MCE_TIME_UNIT);
- dev_dbg(ir->dev, "Storing %s with duration %d",
+ dev_dbg(ir->dev, "Storing %s with duration %u",
rawir.pulse ? "pulse" : "space",
rawir.duration);
@@ -1007,7 +1035,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
continue;
}
ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
- mceusb_dev_printdata(ir, ir->buf_in,
+ mceusb_dev_printdata(ir, ir->buf_in, buf_len,
i, ir->rem + 1, false);
if (ir->rem)
ir->parser_state = PARSE_IRDATA;
@@ -1052,6 +1080,11 @@ static void mceusb_dev_recv(struct urb *urb)
return;
case -EPIPE:
+ dev_err(ir->dev, "Error: urb status = %d (RX HALT)",
+ urb->status);
+ mceusb_defer_kevent(ir, EVENT_RX_HALT);
+ return;
+
default:
dev_err(ir->dev, "Error: urb status = %d", urb->status);
break;
@@ -1170,6 +1203,45 @@ static void mceusb_flash_led(struct mceusb_dev *ir)
mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
}
+/*
+ * Workqueue function
+ * for resetting or recovering device after occurrence of error events
+ * specified in ir->kevent bit field.
+ * Function runs (via schedule_work()) in non-interrupt context, for
+ * calls here (such as usb_clear_halt()) requiring non-interrupt context.
+ */
+static void mceusb_deferred_kevent(struct work_struct *work)
+{
+ struct mceusb_dev *ir =
+ container_of(work, struct mceusb_dev, kevent);
+ int status;
+
+ if (test_bit(EVENT_RX_HALT, &ir->kevent_flags)) {
+ usb_unlink_urb(ir->urb_in);
+ status = usb_clear_halt(ir->usbdev, ir->pipe_in);
+ if (status < 0) {
+ dev_err(ir->dev, "rx clear halt error %d",
+ status);
+ }
+ clear_bit(EVENT_RX_HALT, &ir->kevent_flags);
+ if (status == 0) {
+ status = usb_submit_urb(ir->urb_in, GFP_KERNEL);
+ if (status < 0) {
+ dev_err(ir->dev,
+ "rx unhalt submit urb error %d",
+ status);
+ }
+ }
+ }
+
+ if (test_bit(EVENT_TX_HALT, &ir->kevent_flags)) {
+ status = usb_clear_halt(ir->usbdev, ir->pipe_out);
+ if (status < 0)
+ dev_err(ir->dev, "tx clear halt error %d", status);
+ clear_bit(EVENT_TX_HALT, &ir->kevent_flags);
+ }
+}
+
static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
{
struct usb_device *udev = ir->usbdev;
@@ -1303,6 +1375,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
if (!ir)
goto mem_alloc_fail;
+ ir->pipe_in = pipe;
ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in);
if (!ir->buf_in)
goto buf_in_alloc_fail;
@@ -1321,6 +1394,12 @@ static int mceusb_dev_probe(struct usb_interface *intf,
/* Saving usb interface data for use by the transmitter routine */
ir->usb_ep_out = ep_out;
+ if (usb_endpoint_xfer_int(ep_out))
+ ir->pipe_out = usb_sndintpipe(ir->usbdev,
+ ep_out->bEndpointAddress);
+ else
+ ir->pipe_out = usb_sndbulkpipe(ir->usbdev,
+ ep_out->bEndpointAddress);
if (dev->descriptor.iManufacturer
&& usb_string(dev, dev->descriptor.iManufacturer,
@@ -1332,21 +1411,32 @@ static int mceusb_dev_probe(struct usb_interface *intf,
snprintf(name + strlen(name), sizeof(name) - strlen(name),
" %s", buf);
+ /*
+ * Initialize async USB error handler before registering
+ * or activating any mceusb RX and TX functions
+ */
+ INIT_WORK(&ir->kevent, mceusb_deferred_kevent);
+
ir->rc = mceusb_init_rc_dev(ir);
if (!ir->rc)
goto rc_dev_fail;
/* wire up inbound data handler */
- usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
- mceusb_dev_recv, ir, ep_in->bInterval);
+ if (usb_endpoint_xfer_int(ep_in))
+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+ mceusb_dev_recv, ir, ep_in->bInterval);
+ else
+ usb_fill_bulk_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+ mceusb_dev_recv, ir);
+
ir->urb_in->transfer_dma = ir->dma_in;
ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* flush buffers on the device */
- dev_dbg(&intf->dev, "Flushing receive buffers\n");
+ dev_dbg(&intf->dev, "Flushing receive buffers");
res = usb_submit_urb(ir->urb_in, GFP_KERNEL);
if (res)
- dev_err(&intf->dev, "failed to flush buffers: %d\n", res);
+ dev_err(&intf->dev, "failed to flush buffers: %d", res);
/* figure out which firmware/emulator version this hardware has */
mceusb_get_emulator_version(ir);
@@ -1380,6 +1470,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
/* Error-handling path */
rc_dev_fail:
+ cancel_work_sync(&ir->kevent);
usb_put_dev(ir->usbdev);
usb_kill_urb(ir->urb_in);
usb_free_urb(ir->urb_in);
@@ -1405,6 +1496,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf)
return;
ir->usbdev = NULL;
+ cancel_work_sync(&ir->kevent);
rc_unregister_device(ir->rc);
usb_kill_urb(ir->urb_in);
usb_free_urb(ir->urb_in);
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index 5576dbd6b1a4..65566d569cb1 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -19,6 +19,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+#include <linux/bitfield.h>
#include <media/rc-core.h>
@@ -36,7 +37,7 @@
/* only available on Meson 8b and newer */
#define IR_DEC_REG2 0x20
-#define REG0_RATE_MASK (BIT(11) - 1)
+#define REG0_RATE_MASK GENMASK(11, 0)
#define DECODE_MODE_NEC 0x0
#define DECODE_MODE_RAW 0x2
@@ -49,14 +50,13 @@
#define REG2_MODE_MASK GENMASK(3, 0)
#define REG2_MODE_SHIFT 0
-#define REG1_TIME_IV_SHIFT 16
-#define REG1_TIME_IV_MASK ((BIT(13) - 1) << REG1_TIME_IV_SHIFT)
+#define REG1_TIME_IV_MASK GENMASK(28, 16)
-#define REG1_IRQSEL_MASK (BIT(2) | BIT(3))
-#define REG1_IRQSEL_NEC_MODE (0 << 2)
-#define REG1_IRQSEL_RISE_FALL (1 << 2)
-#define REG1_IRQSEL_FALL (2 << 2)
-#define REG1_IRQSEL_RISE (3 << 2)
+#define REG1_IRQSEL_MASK GENMASK(3, 2)
+#define REG1_IRQSEL_NEC_MODE 0
+#define REG1_IRQSEL_RISE_FALL 1
+#define REG1_IRQSEL_FALL 2
+#define REG1_IRQSEL_RISE 3
#define REG1_RESET BIT(0)
#define REG1_ENABLE BIT(15)
@@ -68,7 +68,6 @@
struct meson_ir {
void __iomem *reg;
struct rc_dev *rc;
- int irq;
spinlock_t lock;
};
@@ -86,18 +85,19 @@ static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg,
static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
{
struct meson_ir *ir = dev_id;
- u32 duration;
+ u32 duration, status;
DEFINE_IR_RAW_EVENT(rawir);
spin_lock(&ir->lock);
- duration = readl(ir->reg + IR_DEC_REG1);
- duration = (duration & REG1_TIME_IV_MASK) >> REG1_TIME_IV_SHIFT;
+ duration = readl_relaxed(ir->reg + IR_DEC_REG1);
+ duration = FIELD_GET(REG1_TIME_IV_MASK, duration);
rawir.duration = US_TO_NS(duration * MESON_TRATE);
- rawir.pulse = !!(readl(ir->reg + IR_DEC_STATUS) & STATUS_IR_DEC_IN);
+ status = readl_relaxed(ir->reg + IR_DEC_STATUS);
+ rawir.pulse = !!(status & STATUS_IR_DEC_IN);
- ir_raw_event_store_with_filter(ir->rc, &rawir);
+ ir_raw_event_store(ir->rc, &rawir);
ir_raw_event_handle(ir->rc);
spin_unlock(&ir->lock);
@@ -112,7 +112,7 @@ static int meson_ir_probe(struct platform_device *pdev)
struct resource *res;
const char *map_name;
struct meson_ir *ir;
- int ret;
+ int irq, ret;
ir = devm_kzalloc(dev, sizeof(struct meson_ir), GFP_KERNEL);
if (!ir)
@@ -125,13 +125,13 @@ static int meson_ir_probe(struct platform_device *pdev)
return PTR_ERR(ir->reg);
}
- ir->irq = platform_get_irq(pdev, 0);
- if (ir->irq < 0) {
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
dev_err(dev, "no irq resource\n");
- return ir->irq;
+ return irq;
}
- ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+ ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
if (!ir->rc) {
dev_err(dev, "failed to allocate rc device\n");
return -ENOMEM;
@@ -143,7 +143,6 @@ static int meson_ir_probe(struct platform_device *pdev)
ir->rc->input_id.bustype = BUS_HOST;
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->allowed_protocols = RC_BIT_ALL_IR_DECODER;
ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
ir->rc->timeout = MS_TO_NS(200);
@@ -152,16 +151,16 @@ static int meson_ir_probe(struct platform_device *pdev)
spin_lock_init(&ir->lock);
platform_set_drvdata(pdev, ir);
- ret = rc_register_device(ir->rc);
+ ret = devm_rc_register_device(dev, ir->rc);
if (ret) {
dev_err(dev, "failed to register rc device\n");
- goto out_free;
+ return ret;
}
- ret = devm_request_irq(dev, ir->irq, meson_ir_irq, 0, "ir-meson", ir);
+ ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir);
if (ret) {
dev_err(dev, "failed to request irq\n");
- goto out_unreg;
+ return ret;
}
/* Reset the decoder */
@@ -171,29 +170,22 @@ static int meson_ir_probe(struct platform_device *pdev)
/* Set general operation mode (= raw/software decoding) */
if (of_device_is_compatible(node, "amlogic,meson6-ir"))
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK,
- DECODE_MODE_RAW << REG1_MODE_SHIFT);
+ FIELD_PREP(REG1_MODE_MASK, DECODE_MODE_RAW));
else
meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK,
- DECODE_MODE_RAW << REG2_MODE_SHIFT);
+ FIELD_PREP(REG2_MODE_MASK, DECODE_MODE_RAW));
/* Set rate */
meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1);
/* IRQ on rising and falling edges */
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_IRQSEL_MASK,
- REG1_IRQSEL_RISE_FALL);
+ FIELD_PREP(REG1_IRQSEL_MASK, REG1_IRQSEL_RISE_FALL));
/* Enable the decoder */
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, REG1_ENABLE);
dev_info(dev, "receiver initialized\n");
return 0;
-out_unreg:
- rc_unregister_device(ir->rc);
- ir->rc = NULL;
-out_free:
- rc_free_device(ir->rc);
-
- return ret;
}
static int meson_ir_remove(struct platform_device *pdev)
@@ -206,11 +198,35 @@ static int meson_ir_remove(struct platform_device *pdev)
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0);
spin_unlock_irqrestore(&ir->lock, flags);
- rc_unregister_device(ir->rc);
-
return 0;
}
+static void meson_ir_shutdown(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct meson_ir *ir = platform_get_drvdata(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ir->lock, flags);
+
+ /*
+ * Set operation mode to NEC/hardware decoding to give
+ * bootloader a chance to power the system back on
+ */
+ if (of_device_is_compatible(node, "amlogic,meson6-ir"))
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK,
+ DECODE_MODE_NEC << REG1_MODE_SHIFT);
+ else
+ meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK,
+ DECODE_MODE_NEC << REG2_MODE_SHIFT);
+
+ /* Set rate to default value */
+ meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, 0x13);
+
+ spin_unlock_irqrestore(&ir->lock, flags);
+}
+
static const struct of_device_id meson_ir_match[] = {
{ .compatible = "amlogic,meson6-ir" },
{ .compatible = "amlogic,meson8b-ir" },
@@ -222,6 +238,7 @@ MODULE_DEVICE_TABLE(of, meson_ir_match);
static struct platform_driver meson_ir_driver = {
.probe = meson_ir_probe,
.remove = meson_ir_remove,
+ .shutdown = meson_ir_shutdown,
.driver = {
.name = DRIVER_NAME,
.of_match_table = meson_ir_match,
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 0455b273c2fc..b3e7cac2c3ee 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -263,7 +263,9 @@ int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max,
* Routines from rc-raw.c to be used internally and by decoders
*/
u64 ir_raw_get_allowed_protocols(void);
+int ir_raw_event_prepare(struct rc_dev *dev);
int ir_raw_event_register(struct rc_dev *dev);
+void ir_raw_event_free(struct rc_dev *dev);
void ir_raw_event_unregister(struct rc_dev *dev);
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 90f66dc7c0d7..b6d256f03847 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -211,7 +211,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
*/
void ir_raw_event_handle(struct rc_dev *dev)
{
- if (!dev->raw)
+ if (!dev->raw || !dev->raw->thread)
return;
wake_up_process(dev->raw->thread);
@@ -486,14 +486,18 @@ EXPORT_SYMBOL(ir_raw_encode_scancode);
/*
* Used to (un)register raw event clients
*/
-int ir_raw_event_register(struct rc_dev *dev)
+int ir_raw_event_prepare(struct rc_dev *dev)
{
- int rc;
- struct ir_raw_handler *handler;
+ static bool raw_init; /* 'false' default value, raw decoders loaded? */
if (!dev)
return -EINVAL;
+ if (!raw_init) {
+ request_module("ir-lirc-codec");
+ raw_init = true;
+ }
+
dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
if (!dev->raw)
return -ENOMEM;
@@ -502,18 +506,26 @@ int ir_raw_event_register(struct rc_dev *dev)
dev->change_protocol = change_protocol;
INIT_KFIFO(dev->raw->kfifo);
+ return 0;
+}
+
+int ir_raw_event_register(struct rc_dev *dev)
+{
+ struct ir_raw_handler *handler;
+ struct task_struct *thread;
+
/*
* 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);
+ 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(thread))
+ return PTR_ERR(thread);
+
+ dev->raw->thread = thread;
}
mutex_lock(&ir_raw_handler_lock);
@@ -524,11 +536,15 @@ int ir_raw_event_register(struct rc_dev *dev)
mutex_unlock(&ir_raw_handler_lock);
return 0;
+}
+
+void ir_raw_event_free(struct rc_dev *dev)
+{
+ if (!dev)
+ return;
-out:
kfree(dev->raw);
dev->raw = NULL;
- return rc;
}
void ir_raw_event_unregister(struct rc_dev *dev)
@@ -547,8 +563,7 @@ void ir_raw_event_unregister(struct rc_dev *dev)
handler->raw_unregister(dev);
mutex_unlock(&ir_raw_handler_lock);
- kfree(dev->raw);
- dev->raw = NULL;
+ ir_raw_event_free(dev);
}
/*
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 6ec73357fa47..a9eba0013525 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -15,7 +15,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <media/rc-core.h>
-#include <linux/atomic.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/input.h>
@@ -934,8 +933,8 @@ static bool lirc_is_present(void)
* It returns the protocol names of supported protocols.
* Enabled protocols are printed in brackets.
*
- * dev->lock is taken to guard against races between device
- * registration, store_protocols and show_protocols.
+ * dev->lock is taken to guard against races between
+ * store_protocols and show_protocols.
*/
static ssize_t show_protocols(struct device *device,
struct device_attribute *mattr, char *buf)
@@ -945,13 +944,6 @@ static ssize_t show_protocols(struct device *device,
char *tmp = buf;
int i;
- /* Device is being removed */
- if (!dev)
- return -EINVAL;
-
- if (!atomic_read(&dev->initialized))
- return -ERESTARTSYS;
-
mutex_lock(&dev->lock);
enabled = dev->enabled_protocols;
@@ -1106,8 +1098,8 @@ static void ir_raw_load_modules(u64 *protocols)
* See parse_protocol_change() for the valid commands.
* 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.
+ * dev->lock is taken to guard against races between
+ * store_protocols and show_protocols.
*/
static ssize_t store_protocols(struct device *device,
struct device_attribute *mattr,
@@ -1119,13 +1111,6 @@ static ssize_t store_protocols(struct device *device,
u64 old_protocols, new_protocols;
ssize_t rc;
- /* Device is being removed */
- if (!dev)
- return -EINVAL;
-
- if (!atomic_read(&dev->initialized))
- return -ERESTARTSYS;
-
IR_dprintk(1, "Normal protocol change requested\n");
current_protocols = &dev->enabled_protocols;
filter = &dev->scancode_filter;
@@ -1200,7 +1185,7 @@ out:
* Bits of the filter value corresponding to set bits in the filter mask are
* compared against input scancodes and non-matching scancodes are discarded.
*
- * dev->lock is taken to guard against races between device registration,
+ * dev->lock is taken to guard against races between
* store_filter and show_filter.
*/
static ssize_t show_filter(struct device *device,
@@ -1212,13 +1197,6 @@ static ssize_t show_filter(struct device *device,
struct rc_scancode_filter *filter;
u32 val;
- /* Device is being removed */
- if (!dev)
- return -EINVAL;
-
- if (!atomic_read(&dev->initialized))
- return -ERESTARTSYS;
-
mutex_lock(&dev->lock);
if (fattr->type == RC_FILTER_NORMAL)
@@ -1251,7 +1229,7 @@ static ssize_t show_filter(struct device *device,
* Bits of the filter value corresponding to set bits in the filter mask are
* compared against input scancodes and non-matching scancodes are discarded.
*
- * dev->lock is taken to guard against races between device registration,
+ * dev->lock is taken to guard against races between
* store_filter and show_filter.
*/
static ssize_t store_filter(struct device *device,
@@ -1265,13 +1243,6 @@ static ssize_t store_filter(struct device *device,
unsigned long val;
int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
- /* Device is being removed */
- if (!dev)
- return -EINVAL;
-
- if (!atomic_read(&dev->initialized))
- return -ERESTARTSYS;
-
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
@@ -1372,8 +1343,8 @@ static const char * const proto_variant_names[] = {
* 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.
+ * dev->lock is taken to guard against races between
+ * store_wakeup_protocols and show_wakeup_protocols.
*/
static ssize_t show_wakeup_protocols(struct device *device,
struct device_attribute *mattr,
@@ -1385,13 +1356,6 @@ static ssize_t show_wakeup_protocols(struct device *device,
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;
@@ -1431,8 +1395,8 @@ static ssize_t show_wakeup_protocols(struct device *device,
* 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.
+ * dev->lock is taken to guard against races between
+ * store_wakeup_protocols and show_wakeup_protocols.
*/
static ssize_t store_wakeup_protocols(struct device *device,
struct device_attribute *mattr,
@@ -1444,13 +1408,6 @@ static ssize_t store_wakeup_protocols(struct device *device,
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;
@@ -1663,7 +1620,7 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_rc_allocate_device);
-static int rc_setup_rx_device(struct rc_dev *dev)
+static int rc_prepare_rx_device(struct rc_dev *dev)
{
int rc;
struct rc_map *rc_map;
@@ -1703,6 +1660,28 @@ static int rc_setup_rx_device(struct rc_dev *dev)
if (dev->close)
dev->input_dev->close = ir_close;
+ 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;
+
+ return 0;
+
+out_table:
+ ir_free_table(&dev->rc_map);
+
+ return rc;
+}
+
+static int rc_setup_rx_device(struct rc_dev *dev)
+{
+ int rc;
+
+ /* rc_open will be called here */
+ rc = input_register_device(dev->input_dev);
+ if (rc)
+ return rc;
+
/*
* Default delay of 250ms is too short for some protocols, especially
* since the timeout is currently set to 250ms. Increase it to 500ms,
@@ -1718,38 +1697,24 @@ static int rc_setup_rx_device(struct rc_dev *dev)
*/
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)
+ if (!dev)
return;
- ir_free_table(&dev->rc_map);
+ if (dev->input_dev) {
+ input_unregister_device(dev->input_dev);
+ dev->input_dev = NULL;
+ }
- input_unregister_device(dev->input_dev);
- dev->input_dev = NULL;
+ ir_free_table(&dev->rc_map);
}
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;
@@ -1765,7 +1730,6 @@ int rc_register_device(struct rc_dev *dev)
dev->minor = minor;
dev_set_name(&dev->dev, "rc%u", dev->minor);
dev_set_drvdata(&dev->dev, dev);
- atomic_set(&dev->initialized, 0);
dev->dev.groups = dev->sysfs_groups;
if (dev->driver_type != RC_DRIVER_IR_RAW_TX)
@@ -1776,34 +1740,40 @@ int rc_register_device(struct rc_dev *dev)
dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
dev->sysfs_groups[attr++] = NULL;
+ if (dev->driver_type == RC_DRIVER_IR_RAW ||
+ dev->driver_type == RC_DRIVER_IR_RAW_TX) {
+ rc = ir_raw_event_prepare(dev);
+ if (rc < 0)
+ goto out_minor;
+ }
+
+ if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
+ rc = rc_prepare_rx_device(dev);
+ if (rc)
+ goto out_raw;
+ }
+
rc = device_add(&dev->dev);
if (rc)
- goto out_unlock;
+ goto out_rx_free;
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 ||
- 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_dev;
- }
-
if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
rc = rc_setup_rx_device(dev);
if (rc)
- goto out_raw;
+ goto out_dev;
}
- /* Allow the RC sysfs nodes to be accessible */
- atomic_set(&dev->initialized, 1);
+ if (dev->driver_type == RC_DRIVER_IR_RAW ||
+ dev->driver_type == RC_DRIVER_IR_RAW_TX) {
+ rc = ir_raw_event_register(dev);
+ if (rc < 0)
+ goto out_rx;
+ }
IR_dprintk(1, "Registered rc%u (driver: %s)\n",
dev->minor,
@@ -1811,11 +1781,15 @@ int rc_register_device(struct rc_dev *dev)
return 0;
-out_raw:
- ir_raw_event_unregister(dev);
+out_rx:
+ rc_free_rx_device(dev);
out_dev:
device_del(&dev->dev);
-out_unlock:
+out_rx_free:
+ ir_free_table(&dev->rc_map);
+out_raw:
+ ir_raw_event_free(dev);
+out_minor:
ida_simple_remove(&rc_ida, minor);
return rc;
}
diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c
index e12ec50bf0bf..20234ba0b318 100644
--- a/drivers/media/rc/sir_ir.c
+++ b/drivers/media/rc/sir_ir.c
@@ -53,16 +53,13 @@ static DEFINE_SPINLOCK(hardware_lock);
/* Communication with user-space */
static void add_read_queue(int flag, unsigned long val);
-static int init_chrdev(void);
/* Hardware */
static irqreturn_t sir_interrupt(int irq, void *dev_id);
static void send_space(unsigned long len);
static void send_pulse(unsigned long len);
-static int init_hardware(void);
+static void init_hardware(void);
static void drop_hardware(void);
/* Initialisation */
-static int init_port(void);
-static void drop_port(void);
static inline unsigned int sinp(int offset)
{
@@ -122,28 +119,6 @@ static void add_read_queue(int flag, unsigned long val)
ir_raw_event_store_with_filter(rcdev, &ev);
}
-static int init_chrdev(void)
-{
- rcdev = devm_rc_allocate_device(&sir_ir_dev->dev, RC_DRIVER_IR_RAW);
- if (!rcdev)
- return -ENOMEM;
-
- rcdev->input_name = "SIR IrDA port";
- 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->tx_ir = sir_tx_ir;
- rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
- rcdev->driver_name = KBUILD_MODNAME;
- rcdev->map_name = RC_MAP_RC6_MCE;
- rcdev->timeout = IR_DEFAULT_TIMEOUT;
- rcdev->dev.parent = &sir_ir_dev->dev;
-
- return devm_rc_register_device(&sir_ir_dev->dev, rcdev);
-}
-
/* SECTION: Hardware */
static void sir_timeout(unsigned long data)
{
@@ -183,9 +158,15 @@ static irqreturn_t sir_interrupt(int irq, void *dev_id)
static unsigned long delt;
unsigned long deltintr;
unsigned long flags;
+ int counter = 0;
int iir, lsr;
while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) {
+ if (++counter > 256) {
+ dev_err(&sir_ir_dev->dev, "Trapped in interrupt");
+ break;
+ }
+
switch (iir & UART_IIR_ID) { /* FIXME toto treba preriedit */
case UART_IIR_MSI:
(void)inb(io + UART_MSR);
@@ -282,7 +263,7 @@ static void send_pulse(unsigned long len)
}
}
-static int init_hardware(void)
+static void init_hardware(void)
{
unsigned long flags;
@@ -304,7 +285,6 @@ static int init_hardware(void)
/* turn on UART */
outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, io + UART_MCR);
spin_unlock_irqrestore(&hardware_lock, flags);
- return 0;
}
static void drop_hardware(void)
@@ -320,61 +300,55 @@ static void drop_hardware(void)
}
/* SECTION: Initialisation */
-
-static int init_port(void)
+static int sir_ir_probe(struct platform_device *dev)
{
int retval;
+ rcdev = devm_rc_allocate_device(&sir_ir_dev->dev, RC_DRIVER_IR_RAW);
+ if (!rcdev)
+ return -ENOMEM;
+
+ rcdev->input_name = "SIR IrDA port";
+ 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->tx_ir = sir_tx_ir;
+ rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
+ rcdev->driver_name = KBUILD_MODNAME;
+ rcdev->map_name = RC_MAP_RC6_MCE;
+ rcdev->timeout = IR_DEFAULT_TIMEOUT;
+ rcdev->dev.parent = &sir_ir_dev->dev;
+
setup_timer(&timerlist, sir_timeout, 0);
/* get I/O port access and IRQ line */
- if (!request_region(io, 8, KBUILD_MODNAME)) {
+ if (!devm_request_region(&sir_ir_dev->dev, io, 8, KBUILD_MODNAME)) {
pr_err("i/o port 0x%.4x already in use.\n", io);
return -EBUSY;
}
- retval = request_irq(irq, sir_interrupt, 0,
- KBUILD_MODNAME, NULL);
+ retval = devm_request_irq(&sir_ir_dev->dev, irq, sir_interrupt, 0,
+ KBUILD_MODNAME, NULL);
if (retval < 0) {
- release_region(io, 8);
pr_err("IRQ %d already in use.\n", irq);
return retval;
}
pr_info("I/O port 0x%.4x, IRQ %d.\n", io, irq);
- return 0;
-}
-
-static void drop_port(void)
-{
- free_irq(irq, NULL);
- del_timer_sync(&timerlist);
- release_region(io, 8);
-}
-
-static int init_sir_ir(void)
-{
- int retval;
-
- retval = init_port();
+ retval = devm_rc_register_device(&sir_ir_dev->dev, rcdev);
if (retval < 0)
return retval;
- init_hardware();
- return 0;
-}
-
-static int sir_ir_probe(struct platform_device *dev)
-{
- int retval;
- retval = init_chrdev();
- if (retval < 0)
- return retval;
+ init_hardware();
- return init_sir_ir();
+ return 0;
}
static int sir_ir_remove(struct platform_device *dev)
{
+ drop_hardware();
+ del_timer_sync(&timerlist);
return 0;
}
@@ -415,8 +389,6 @@ pdev_alloc_fail:
static void __exit sir_ir_exit(void)
{
- drop_hardware();
- drop_port();
platform_device_unregister(sir_ir_dev);
platform_driver_unregister(&sir_ir_driver);
}
@@ -428,10 +400,10 @@ MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports");
MODULE_AUTHOR("Milan Pikula");
MODULE_LICENSE("GPL");
-module_param(io, int, 0444);
+module_param_hw(io, int, ioport, 0444);
MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
-module_param(irq, int, 0444);
+module_param_hw(irq, int, irq, 0444);
MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
module_param(threshold, int, 0444);