2003-08-02 10:38:50

by Flameeyes

[permalink] [raw]
Subject: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi,
This is the fourth version of my patch for use LIRC drivers under
2.5/2.6 kernels.

As usual, you can find it at
http://flameeyes.web.ctonet.it/lirc/patch-lirc-20030802.diff.bz2

I changed the naming scheme, because I tried and the patch applies also
in earliers and (probably) futures kernels, and call it only
"patch-lirc.diff" will confuse about the versions. I think a datestamp
is the best choice for now.

This version includes minor changes, but an important one, Koos Vriezen
sent me another fixes for lirc_serial driver (thanks, at the moment I
haven't a serial device, and the electronic shops are closed, so I can't
test it directly).
Also I removed the .Makefile.swp present in the last patch (I forgot to
close KVim before do the diff).

This is also the first patch I post to the official lirc mailing list,
HTH other lirc users that want to pass to 2.5/2.6 kernels.

--
Flameeyes <[email protected]>


2003-08-07 21:45:20

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> This is the fourth version of my patch for use LIRC drivers under
> 2.5/2.6 kernels.
>
> As usual, you can find it at
> http://flameeyes.web.ctonet.it/lirc/patch-lirc-20030802.diff.bz2
>
> I changed the naming scheme, because I tried and the patch applies also
> in earliers and (probably) futures kernels, and call it only
> "patch-lirc.diff" will confuse about the versions. I think a datestamp
> is the best choice for now.

If you want to get this applied to the official tree (I hope you want
;-), you probably should start with smaller patch. I killed all
drivers but lirc_gpio, to make patch smaller/easier to check.

Its now small enough to inline, and that's good.

Few questions:

* What does "For now don't try to use as static version" comment in
lirc_gpio mean. Does it only work as a module?

* This looks like it should be integrated with drivers/input. After
all remote control is just a strange keyboard. What are reasons that
can't be done?
Pavel


--- linux/drivers/char/Kconfig 2003-06-15 22:42:37.000000000 +0200
+++ linux-lirc/drivers/char/Kconfig 2003-08-07 22:53:49.000000000 +0200
@@ -591,6 +591,7 @@

source "drivers/i2c/Kconfig"

+source "drivers/char/lirc/Kconfig"

menu "Mice"

--- linux/drivers/char/Makefile 2003-06-15 22:42:37.000000000 +0200
+++ linux-lirc/drivers/char/Makefile 2003-08-07 22:53:49.000000000 +0200
@@ -7,7 +7,7 @@
#
FONTMAPFILE = cp437.uni

-obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o
+obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o lirc/

obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o keyboard.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
--- linux/drivers/char/lirc/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-lirc/drivers/char/lirc/Kconfig 2003-08-07 22:57:49.000000000 +0200
@@ -0,0 +1,22 @@
+# LIRC http://lirc.sf.net/
+# Kernel patch by Flameeyes <[email protected]>
+# Check for new patch at http://flameeyes.web.ctonet.it/
+#
+# Thanks to Koos Vriezen <[email protected]> for the Homebrew support
+
+menu "Linux InfraRed Controller"
+
+config LIRC_SUPPORT
+ bool "Linux InfraRed Controller"
+
+ config LIRC_MAX_DEV
+ int "Maximum LIRC devices"
+ default "2"
+ depends on LIRC_SUPPORT
+
+ config LIRC_GPIO
+ tristate "GPIO Driver"
+ depends on LIRC_SUPPORT && VIDEO_BT848
+
+endmenu
+
--- linux/drivers/char/lirc/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-lirc/drivers/char/lirc/Makefile 2003-08-07 22:57:56.000000000 +0200
@@ -0,0 +1,6 @@
+#
+# Makefile for the lirc drivers
+#
+
+obj-$(CONFIG_LIRC_SUPPORT) += lirc_dev.o
+obj-$(CONFIG_LIRC_GPIO) += lirc_gpio.o
--- linux/drivers/char/lirc/lirc_dev.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-lirc/drivers/char/lirc/lirc_dev.c 2003-08-07 22:53:49.000000000 +0200
@@ -0,0 +1,718 @@
+/*
+ * LIRC base driver
+ *
+ * (L) by Artur Lipowski <[email protected]>
+ *
+ * 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.
+ *
+ * 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
+ *
+ * $Id: lirc_dev.c,v 1.25 2003/05/04 09:31:28 ranty Exp $
+ *
+ */
+
+#include <linux/version.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/init.h>
+
+#include <linux/lirc.h>
+
+#include "lirc_dev.h"
+
+static int debug = 0;
+
+MODULE_PARM(debug,"i");
+
+#define IRCTL_DEV_NAME "BaseRemoteCtl"
+#define SUCCESS 0
+#define NOPLUG -1
+#define dprintk if (debug) printk
+
+#define LOGHEAD "lirc_dev (%s[%d]): "
+
+struct irctl
+{
+ struct lirc_plugin p;
+ int open;
+
+ struct lirc_buffer *buf;
+
+ int tpid;
+ struct semaphore *t_notify;
+ struct semaphore *t_notify2;
+ int shutdown;
+ long jiffies_to_wait;
+};
+
+DECLARE_MUTEX(plugin_lock);
+
+static struct irctl irctls[CONFIG_LIRC_MAX_DEV];
+static struct file_operations fops;
+
+
+/* helper function
+ * initializes the irctl structure
+ */
+static inline void init_irctl(struct irctl *ir)
+{
+ memset(&ir->p, 0, sizeof(struct lirc_plugin));
+ ir->p.minor = NOPLUG;
+
+ ir->tpid = -1;
+ ir->t_notify = NULL;
+ ir->t_notify2 = NULL;
+ ir->shutdown = 0;
+ ir->jiffies_to_wait = 0;
+
+ ir->open = 0;
+}
+
+
+/* helper function
+ * reads key codes from plugin and puts them into buffer
+ * buffer free space is checked and locking performed
+ * returns 0 on success
+ */
+
+inline static int add_to_buf(struct irctl *ir)
+{
+ unsigned char buf[BUFLEN];
+ unsigned int i;
+
+ if (lirc_buffer_full(ir->buf)) {
+ dprintk(LOGHEAD "buffer overflow\n",
+ ir->p.name, ir->p.minor);
+ return -EOVERFLOW;
+ }
+
+ for (i=0; i < ir->buf->chunk_size; i++) {
+ if (ir->p.get_key(ir->p.data, &buf[i], i)) {
+ return -ENODATA;
+ }
+ dprintk(LOGHEAD "remote code (0x%x) now in buffer\n",
+ ir->p.name, ir->p.minor, buf[i]);
+ }
+
+ /* here is the only point at which we add key codes to the buffer */
+ lirc_buffer_write_1(ir->buf, buf);
+
+ return SUCCESS;
+}
+
+/* main function of the polling thread
+ */
+static int lirc_thread(void *irctl)
+{
+ struct irctl *ir = irctl;
+
+ lock_kernel();
+
+ /* This thread doesn't need any user-level access,
+ * so get rid of all our resources
+ */
+ exit_mm(current);
+ exit_files(current);
+ exit_fs(current);
+ current->session = 1;
+ current->pgrp = 1;
+ current->euid = 0;
+ current->tty = NULL;
+ sigfillset(&current->blocked);
+
+ strcpy(current->comm, "lirc_dev");
+
+ unlock_kernel();
+
+ if (ir->t_notify != NULL) {
+ up(ir->t_notify);
+ }
+
+ dprintk(LOGHEAD "poll thread started\n", ir->p.name, ir->p.minor);
+
+ do {
+ if (ir->open) {
+ if (ir->jiffies_to_wait) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(ir->jiffies_to_wait);
+ } else {
+ interruptible_sleep_on(ir->p.get_queue(ir->p.data));
+ }
+ if (ir->shutdown) {
+ break;
+ }
+ if (!add_to_buf(ir)) {
+ wake_up_interruptible(&ir->buf->wait_poll);
+ }
+ } else {
+ /* if device not opened so we can sleep half a second */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/2);
+ }
+ } while (!ir->shutdown);
+
+ if (ir->t_notify2 != NULL) {
+ down(ir->t_notify2);
+ }
+
+ ir->tpid = -1;
+ if (ir->t_notify != NULL) {
+ up(ir->t_notify);
+ }
+
+ dprintk(LOGHEAD "poll thread ended\n", ir->p.name, ir->p.minor);
+
+ return 0;
+}
+
+/*
+ *
+ */
+int lirc_register_plugin(struct lirc_plugin *p)
+{
+ struct irctl *ir;
+ int minor;
+ int bytes_in_key;
+ DECLARE_MUTEX_LOCKED(tn);
+
+ if (!p) {
+ printk("lirc_dev: lirc_register_plugin:"
+ "plugin pointer must be not NULL!\n");
+ return -EBADRQC;
+ }
+
+ if (CONFIG_LIRC_MAX_DEV <= p->minor) {
+ printk("lirc_dev: lirc_register_plugin:"
+ "\" minor\" must be beetween 0 and %d (%d)!\n",
+ CONFIG_LIRC_MAX_DEV-1, p->minor);
+ return -EBADRQC;
+ }
+
+ if (1 > p->code_length || (BUFLEN*8) < p->code_length) {
+ printk("lirc_dev: lirc_register_plugin:"
+ "code length in bits for minor (%d) "
+ "must be less than %d!\n",
+ p->minor, BUFLEN*8);
+ return -EBADRQC;
+ }
+
+ printk("lirc_dev: lirc_register_plugin:"
+ "sample_rate: %d\n",p->sample_rate);
+ if (p->sample_rate) {
+ if (2 > p->sample_rate || 50 < p->sample_rate) {
+ printk("lirc_dev: lirc_register_plugin:"
+ "sample_rate must be beetween 2 and 50!\n");
+ return -EBADRQC;
+ }
+ } else if (!(p->fops && p->fops->read)
+ && !p->get_queue && !p->rbuf) {
+ printk("lirc_dev: lirc_register_plugin:"
+ "fops->read, get_queue and rbuf cannot all be NULL!\n");
+ return -EBADRQC;
+ } else if (!p->rbuf) {
+ if (!(p->fops && p->fops->read && p->fops->poll)
+ || (!p->fops->ioctl && !p->ioctl)) {
+ printk("lirc_dev: lirc_register_plugin:"
+ "neither read, poll nor ioctl can be NULL!\n");
+ return -EBADRQC;
+ }
+ }
+
+ down_interruptible(&plugin_lock);
+
+ minor = p->minor;
+
+ if (0 > minor) {
+ /* find first free slot for plugin */
+ for (minor=0; minor<CONFIG_LIRC_MAX_DEV; minor++)
+ if (irctls[minor].p.minor == NOPLUG)
+ break;
+ if (CONFIG_LIRC_MAX_DEV == minor) {
+ printk("lirc_dev: lirc_register_plugin: "
+ "no free slots for plugins!\n");
+ up(&plugin_lock);
+ return -ENOMEM;
+ }
+ } else if (irctls[minor].p.minor != NOPLUG) {
+ printk("lirc_dev: lirc_register_plugin:"
+ "minor (%d) just registerd!\n", minor);
+ up(&plugin_lock);
+ return -EBUSY;
+ }
+
+ ir = &irctls[minor];
+
+ if (p->sample_rate) {
+ ir->jiffies_to_wait = HZ / p->sample_rate;
+ } else {
+ /* it means - wait for externeal event in task queue */
+ ir->jiffies_to_wait = 0;
+ }
+
+ /* some safety check 8-) */
+ p->name[sizeof(p->name)-1] = '\0';
+
+ bytes_in_key = p->code_length/8 + (p->code_length%8 ? 1 : 0);
+
+ if (p->rbuf) {
+ ir->buf = p->rbuf;
+ } else {
+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ lirc_buffer_init(ir->buf, bytes_in_key, BUFLEN/bytes_in_key);
+ }
+
+ if (p->features==0)
+ p->features = (p->code_length > 8) ?
+ LIRC_CAN_REC_LIRCCODE : LIRC_CAN_REC_CODE;
+
+ ir->p = *p;
+ ir->p.minor = minor;
+
+ if(p->sample_rate || p->get_queue) {
+ /* try to fire up polling thread */
+ ir->t_notify = &tn;
+ ir->tpid = kernel_thread(lirc_thread, (void*)ir, 0);
+ if (ir->tpid < 0) {
+ up(&plugin_lock);
+ printk("lirc_dev: lirc_register_plugin:"
+ "cannot run poll thread for minor = %d\n",
+ p->minor);
+ return -ECHILD;
+ }
+ down(&tn);
+ ir->t_notify = NULL;
+ }
+ up(&plugin_lock);
+
+ try_module_get(THIS_MODULE);
+
+ dprintk("lirc_dev: plugin %s registered at minor number = %d\n",
+ ir->p.name, ir->p.minor);
+
+ return minor;
+}
+
+/*
+ *
+ */
+int lirc_unregister_plugin(int minor)
+{
+ struct irctl *ir;
+ DECLARE_MUTEX_LOCKED(tn);
+ DECLARE_MUTEX_LOCKED(tn2);
+
+ if (minor < 0 || minor >= CONFIG_LIRC_MAX_DEV) {
+ printk("lirc_dev: lirc_unregister_plugin:"
+ "\" minor\" must be beetween 0 and %d!\n",
+ CONFIG_LIRC_MAX_DEV-1);
+ return -EBADRQC;
+ }
+
+ ir = &irctls[minor];
+
+ down_interruptible(&plugin_lock);
+
+ if (ir->p.minor != minor) {
+ printk("lirc_dev: lirc_unregister_plugin:"
+ "minor (%d) device not registered!", minor);
+ up(&plugin_lock);
+ return -ENOENT;
+ }
+
+ if (ir->open) {
+ printk("lirc_dev: lirc_unregister_plugin:"
+ "plugin %s[%d] in use!", ir->p.name, ir->p.minor);
+ up(&plugin_lock);
+ return -EBUSY;
+ }
+
+ /* end up polling thread */
+ if (ir->tpid >= 0) {
+ ir->t_notify = &tn;
+ ir->t_notify2 = &tn2;
+ ir->shutdown = 1;
+ {
+ struct task_struct *p;
+
+ p = find_task_by_pid(ir->tpid);
+ wake_up_process(p);
+ }
+ up(&tn2);
+ down(&tn);
+ ir->t_notify = NULL;
+ ir->t_notify2 = NULL;
+ }
+
+ dprintk("lirc_dev: plugin %s unregistered from minor number = %d\n",
+ ir->p.name, ir->p.minor);
+
+ if (ir->buf != ir->p.rbuf){
+ lirc_buffer_free(ir->buf);
+ kfree(ir->buf);
+ }
+ ir->buf = NULL;
+ init_irctl(ir);
+ up(&plugin_lock);
+
+ module_put(THIS_MODULE);
+
+ return SUCCESS;
+}
+
+/*
+ *
+ */
+static int irctl_open(struct inode *inode, struct file *file)
+{
+ struct irctl *ir;
+ int retval;
+
+ if (MINOR(inode->i_rdev.value) >= CONFIG_LIRC_MAX_DEV) {
+ dprintk("lirc_dev [%d]: open result = -ENODEV\n",
+ MINOR(inode->i_rdev.value));
+ return -ENODEV;
+ }
+
+ ir = &irctls[MINOR(inode->i_rdev.value)];
+
+ dprintk(LOGHEAD "open called\n", ir->p.name, ir->p.minor);
+
+ /* if the plugin has an open function use it instead */
+ if(ir->p.fops && ir->p.fops->open)
+ return ir->p.fops->open(inode, file);
+
+ down_interruptible(&plugin_lock);
+
+ if (ir->p.minor == NOPLUG) {
+ up(&plugin_lock);
+ dprintk(LOGHEAD "open result = -ENODEV\n",
+ ir->p.name, ir->p.minor);
+ return -ENODEV;
+ }
+
+ if (ir->open) {
+ up(&plugin_lock);
+ dprintk(LOGHEAD "open result = -EBUSY\n",
+ ir->p.name, ir->p.minor);
+ return -EBUSY;
+ }
+
+ /* there is no need for locking here because ir->open is 0
+ * and lirc_thread isn't using buffer
+ * plugins which use irq's should allocate them on set_use_inc,
+ * so there should be no problem with those either.
+ */
+ ir->buf->head = ir->buf->tail;
+ ir->buf->fill = 0;
+
+ ++ir->open;
+ retval = ir->p.set_use_inc(ir->p.data);
+
+ up(&plugin_lock);
+
+ if (retval != SUCCESS) {
+ --ir->open;
+ return retval;
+ }
+
+ dprintk(LOGHEAD "open result = %d\n", ir->p.name, ir->p.minor, SUCCESS);
+
+ return SUCCESS;
+}
+
+/*
+ *
+ */
+static int irctl_close(struct inode *inode, struct file *file)
+{
+ struct irctl *ir = &irctls[MINOR(inode->i_rdev.value)];
+
+ dprintk(LOGHEAD "close called\n", ir->p.name, ir->p.minor);
+
+ /* if the plugin has a close function use it instead */
+ if(ir->p.fops && ir->p.fops->release)
+ return ir->p.fops->release(inode, file);
+
+ down_interruptible(&plugin_lock);
+
+ --ir->open;
+ ir->p.set_use_dec(ir->p.data);
+
+ up(&plugin_lock);
+
+ return SUCCESS;
+}
+
+/*
+ *
+ */
+static unsigned int irctl_poll(struct file *file, poll_table *wait)
+{
+ struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev.value)];
+
+ dprintk(LOGHEAD "poll called\n", ir->p.name, ir->p.minor);
+
+ /* if the plugin has a poll function use it instead */
+ if(ir->p.fops && ir->p.fops->poll)
+ return ir->p.fops->poll(file, wait);
+
+ poll_wait(file, &ir->buf->wait_poll, wait);
+
+ dprintk(LOGHEAD "poll result = %s\n",
+ ir->p.name, ir->p.minor,
+ lirc_buffer_empty(ir->buf) ? "0" : "POLLIN|POLLRDNORM");
+
+ return lirc_buffer_empty(ir->buf) ? 0 : (POLLIN|POLLRDNORM);
+}
+
+/*
+ *
+ */
+static int irctl_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned long mode;
+ int result;
+ struct irctl *ir = &irctls[MINOR(inode->i_rdev.value)];
+
+ dprintk(LOGHEAD "poll called (%u)\n",
+ ir->p.name, ir->p.minor, cmd);
+
+ /* if the plugin has a ioctl function use it instead */
+ if(ir->p.fops && ir->p.fops->ioctl)
+ return ir->p.fops->ioctl(inode, file, cmd, arg);
+
+ if (ir->p.minor == NOPLUG) {
+ dprintk(LOGHEAD "ioctl result = -ENODEV\n",
+ ir->p.name, ir->p.minor);
+ return -ENODEV;
+ }
+
+ /* Give the plugin a chance to handle the ioctl */
+ if(ir->p.ioctl){
+ result = ir->p.ioctl(inode, file, cmd, arg);
+ if (result != -ENOIOCTLCMD)
+ return result;
+ }
+ /* The plugin can't handle cmd */
+ result = SUCCESS;
+
+ switch(cmd)
+ {
+ case LIRC_GET_FEATURES:
+ result = put_user(ir->p.features, (unsigned long*)arg);
+ break;
+ case LIRC_GET_REC_MODE:
+ if(!(ir->p.features&LIRC_CAN_REC_MASK))
+ return(-ENOSYS);
+
+ result = put_user(LIRC_REC2MODE
+ (ir->p.features&LIRC_CAN_REC_MASK),
+ (unsigned long*)arg);
+ break;
+ case LIRC_SET_REC_MODE:
+ if(!(ir->p.features&LIRC_CAN_REC_MASK))
+ return(-ENOSYS);
+
+ result = get_user(mode, (unsigned long*)arg);
+ if(!result && !(LIRC_MODE2REC(mode) & ir->p.features)) {
+ result = -EINVAL;
+ }
+ /* FIXME: We should actually set the mode somehow
+ * but for now, lirc_serial doesn't support mode changin
+ * eighter */
+ break;
+ case LIRC_GET_LENGTH:
+ result = put_user((unsigned long)ir->p.code_length,
+ (unsigned long *)arg);
+ break;
+ default:
+ result = -ENOIOCTLCMD;
+ }
+
+ dprintk(LOGHEAD "ioctl result = %d\n",
+ ir->p.name, ir->p.minor, result);
+
+ return result;
+}
+
+/*
+ *
+ */
+static ssize_t irctl_read(struct file *file,
+ char *buffer,
+ size_t length,
+ loff_t *ppos)
+{
+ struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev.value)];
+ unsigned char buf[ir->buf->chunk_size];
+ int ret=0, written=0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dprintk(LOGHEAD "read called\n", ir->p.name, ir->p.minor);
+
+ /* if the plugin has a specific read function use it instead */
+ if(ir->p.fops && ir->p.fops->read)
+ return ir->p.fops->read(file, buffer, length, ppos);
+
+ if (length % ir->buf->chunk_size) {
+ dprintk(LOGHEAD "read result = -EINVAL\n",
+ ir->p.name, ir->p.minor);
+ return -EINVAL;
+ }
+
+ /* we add ourselves to the task queue before buffer check
+ * to avoid losing scan code (in case when queue is awaken somewhere
+ * beetwen while condition checking and scheduling)
+ */
+ add_wait_queue(&ir->buf->wait_poll, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ /* while we did't provide 'length' bytes, device is opened in blocking
+ * mode and 'copy_to_user' is happy, wait for data.
+ */
+ while (written < length && ret == 0) {
+ if (lirc_buffer_empty(ir->buf)) {
+ /* According to the read(2) man page, 'written' can be
+ * returned as less than 'length', instead of blocking
+ * again, returning -EWOULDBLOCK, or returning
+ * -ERESTARTSYS */
+ if (written) break;
+ if (file->f_flags & O_NONBLOCK) {
+ dprintk(LOGHEAD "read result = -EWOULDBLOCK\n",
+ ir->p.name, ir->p.minor);
+ remove_wait_queue(&ir->buf->wait_poll, &wait);
+ current->state = TASK_RUNNING;
+ return -EWOULDBLOCK;
+ }
+ if (signal_pending(current)) {
+ dprintk(LOGHEAD "read result = -ERESTARTSYS\n",
+ ir->p.name, ir->p.minor);
+ remove_wait_queue(&ir->buf->wait_poll, &wait);
+ current->state = TASK_RUNNING;
+ return -ERESTARTSYS;
+ }
+ schedule();
+ current->state = TASK_INTERRUPTIBLE;
+ } else {
+ lirc_buffer_read_1(ir->buf, buf);
+ ret = copy_to_user((void *)buffer+written, buf,
+ ir->buf->chunk_size);
+ written += ir->buf->chunk_size;
+ }
+ }
+
+ remove_wait_queue(&ir->buf->wait_poll, &wait);
+ current->state = TASK_RUNNING;
+
+ dprintk(LOGHEAD "read result = %s (%d)\n",
+ ir->p.name, ir->p.minor, ret ? "-EFAULT" : "OK", ret);
+
+ return ret ? -EFAULT : written;
+}
+
+static ssize_t irctl_write(struct file *file, const char *buffer,
+ size_t length, loff_t * ppos)
+{
+ struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev.value)];
+
+ dprintk(LOGHEAD "read called\n", ir->p.name, ir->p.minor);
+
+ /* if the plugin has a specific read function use it instead */
+ if(ir->p.fops && ir->p.fops->write)
+ return ir->p.fops->write(file, buffer, length, ppos);
+
+ return -EINVAL;
+}
+
+
+static struct file_operations fops = {
+ read: irctl_read,
+ write: irctl_write,
+ poll: irctl_poll,
+ ioctl: irctl_ioctl,
+ open: irctl_open,
+ release: irctl_close
+};
+
+static int __init lirc_dev_init(void)
+{
+ int i;
+
+ for (i=0; i < CONFIG_LIRC_MAX_DEV; ++i) {
+ init_irctl(&irctls[i]);
+ }
+
+ i = register_chrdev(IRCTL_DEV_MAJOR,
+ IRCTL_DEV_NAME,
+ &fops);
+
+ if (i < 0) {
+ printk ("lirc_dev: device registration failed with %d\n", i);
+ return i;
+ }
+
+ printk("lirc_dev: IR Remote Control driver registered, at major %d \n",
+ IRCTL_DEV_MAJOR);
+
+ return SUCCESS;
+}
+
+static void __exit lirc_dev_exit(void)
+{
+ int ret;
+
+ ret = unregister_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME);
+
+ if (0 > ret){
+ printk("lirc_dev: error in module_unregister_chrdev: %d\n",
+ ret);
+ } else {
+ dprintk("lirc_dev: module successfully unloaded\n");
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* For now dont try to use it as a static version ! */
+
+MODULE_DESCRIPTION("LIRC base driver module");
+MODULE_AUTHOR("Artur Lipowski");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(lirc_register_plugin);
+EXPORT_SYMBOL(lirc_unregister_plugin);
+
+module_init(lirc_dev_init);
+module_exit(lirc_dev_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
--- linux/drivers/char/lirc/lirc_dev.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-lirc/drivers/char/lirc/lirc_dev.h 2003-08-07 22:53:49.000000000 +0200
@@ -0,0 +1,206 @@
+/*
+ * LIRC base driver
+ *
+ * (L) by Artur Lipowski <[email protected]>
+ * This code is licensed under GNU GPL
+ *
+ * $Id: lirc_dev.h,v 1.11 2003/05/02 18:56:44 ranty Exp $
+ *
+ */
+
+#ifndef _LINUX_LIRC_DEV_H
+#define _LINUX_LIRC_DEV_H
+
+#define BUFLEN 16
+
+//#define LIRC_BUFF_POWER_OF_2
+#ifdef LIRC_BUFF_POWER_OF_2
+#define mod(n, div) ((n) & ((div) -1))
+#else
+#define mod(n, div) ((n) % (div))
+#endif
+#include <linux/slab.h>
+#include <linux/fs.h>
+struct lirc_buffer
+{
+ wait_queue_head_t wait_poll;
+ spinlock_t lock;
+
+ unsigned char *data;
+ unsigned int chunk_size;
+ unsigned int size; /* in chunks */
+ unsigned int fill; /* in chunks */
+ int head, tail; /* in chunks */
+ /* Using chunks instead of bytes pretends to simplify boundary checking
+ * And should allow for some performance fine tunning later */
+};
+static inline int lirc_buffer_init(struct lirc_buffer *buf,
+ unsigned int chunk_size,
+ unsigned int size)
+{
+ /* Adjusting size to the next power of 2 would allow for
+ * inconditional LIRC_BUFF_POWER_OF_2 optimization */
+ init_waitqueue_head(&buf->wait_poll);
+ spin_lock_init(&buf->lock);
+ buf->head = buf->tail = buf->fill = 0;
+ buf->chunk_size = chunk_size;
+ buf->size = size;
+ buf->data = kmalloc(size*chunk_size, GFP_KERNEL);
+ if (buf->data == NULL)
+ return -1;
+ memset(buf->data, 0, size*chunk_size);
+ return 0;
+}
+static inline void lirc_buffer_free(struct lirc_buffer *buf)
+{
+ kfree(buf->data);
+ buf->data = NULL;
+ buf->head = buf->tail = buf->fill = 0;
+ buf->chunk_size = 0;
+ buf->size = 0;
+}
+static inline int lirc_buffer_full(struct lirc_buffer *buf)
+{
+ return (buf->fill >= buf->size);
+}
+static inline int lirc_buffer_empty(struct lirc_buffer *buf)
+{
+ return !(buf->fill);
+}
+extern inline void lirc_buffer_lock(struct lirc_buffer *buf, unsigned long *flags)
+{
+ spin_lock_irqsave(&buf->lock, *flags);
+}
+extern inline void lirc_buffer_unlock(struct lirc_buffer *buf, unsigned long *flags)
+{
+ spin_unlock_irqrestore(&buf->lock, *flags);
+}
+static inline void _lirc_buffer_remove_1(struct lirc_buffer *buf)
+{
+ buf->head = mod(buf->head+1, buf->size);
+ buf->fill -= 1;
+}
+static inline void lirc_buffer_remove_1(struct lirc_buffer *buf)
+{
+ unsigned long flags;
+ lirc_buffer_lock(buf, &flags);
+ _lirc_buffer_remove_1(buf);
+ lirc_buffer_unlock(buf, &flags);
+}
+static inline void _lirc_buffer_read_1(struct lirc_buffer *buf,
+ unsigned char *dest)
+{
+ memcpy(dest, &buf->data[buf->head*buf->chunk_size], buf->chunk_size);
+ buf->head = mod(buf->head+1, buf->size);
+ buf->fill -= 1;
+}
+static inline void lirc_buffer_read_1(struct lirc_buffer *buf,
+ unsigned char *dest)
+{
+ unsigned long flags;
+ lirc_buffer_lock(buf, &flags);
+ _lirc_buffer_read_1(buf, dest);
+ lirc_buffer_unlock(buf, &flags);
+}
+static inline void _lirc_buffer_write_1(struct lirc_buffer *buf,
+ unsigned char *orig)
+{
+ memcpy(&buf->data[buf->tail*buf->chunk_size], orig, buf->chunk_size);
+ buf->tail = mod(buf->tail+1, buf->size);
+ buf->fill++;
+}
+static inline void lirc_buffer_write_1(struct lirc_buffer *buf,
+ unsigned char *orig)
+{
+ unsigned long flags;
+ lirc_buffer_lock(buf, &flags);
+ _lirc_buffer_write_1(buf, orig);
+ lirc_buffer_unlock(buf, &flags);
+}
+
+struct lirc_plugin
+{
+ char name[40];
+ int minor;
+ int code_length;
+ int sample_rate;
+ unsigned long features;
+ void* data;
+ int (*get_key) (void* data, unsigned char* key, int key_no);
+ wait_queue_head_t* (*get_queue) (void* data);
+ struct lirc_buffer *rbuf;
+ int (*set_use_inc) (void* data);
+ void (*set_use_dec) (void* data);
+ int (*ioctl) (struct inode *,struct file *,unsigned int, unsigned long);
+ struct file_operations *fops;
+};
+/* name:
+ * this string will be used for logs
+ *
+ * minor:
+ * indicates minor device (/dev/lircd) number for registered plugin
+ * if caller fills it with negative value, then the first free minor
+ * number will be used (if available)
+ *
+ * code_length:
+ * length ofthe remote control key code expressed in bits
+ * if code_length > 8 then many bytes are returned through the device read
+ * in such situation get_key should return key code values starting
+ * from most significant byte (device read will preseve this order)
+ * in addition if code_length > 8 then get_key will be called
+ * several (ceil(code_length/8)) times in one pool pass (or after task queue
+ * awake) key_no parameter denotes number of the requested byte (0 means first
+ * byte)
+ *
+ * sample_rate:
+ * sample_rate equal to 0 means that no pooling will be performed and get_key
+ * will be triggered by external events (through task queue returned by
+ * get_queue)
+ *
+ * data:
+ * it may point to any plugin data and this pointer will be passed to all
+ * callback functions
+ *
+ * get_key:
+ * get_key will be called after specified period of the time or triggered by the
+ * external event, this behavior depends on value of the sample_rate
+ * this function will be called in user context
+ *
+ * get_queue:
+ * this callback should return a pointer to the task queue which will be used
+ * for external event waiting
+ *
+ * rbuf:
+ * if not NULL, it will be used as a read buffer, you will have to write to
+ * the buffer by other means, like irq's (see also lirc_serial.c).
+ *
+ * set_use_inc:
+ * set_use_inc will be called after device is opened
+ *
+ * set_use_dec:
+ * set_use_dec will be called after device is closed
+ *
+ * ioctl:
+ * Some ioctl's can be directly handled by lirc_dev but will be forwared here
+ * if not NULL and only handled if it returns -ENOIOCTLCMD (see also
+ * lirc_serial.c).
+ *
+ * fops:
+ * file_operations for drivers which don't fit the current plugin model.
+ */
+
+
+/* following functions can be called ONLY from user context
+ *
+ * returns negative value on error or minor number
+ * of the registered device if success
+ * contens of the structure pointed by p is copied
+ */
+extern int lirc_register_plugin(struct lirc_plugin *p);
+
+/* returns negative value on error or 0 if success
+*/
+extern int lirc_unregister_plugin(int minor);
+
+
+#endif
--- linux/drivers/char/lirc/lirc_gpio.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-lirc/drivers/char/lirc/lirc_gpio.c 2003-08-07 22:53:49.000000000 +0200
@@ -0,0 +1,548 @@
+/*
+ * Remote control driver for the TV-card
+ * key codes are obtained from GPIO port
+ *
+ * (L) by Artur Lipowski <[email protected]>
+ * patch for the AverMedia by Santiago Garcia Mantinan <[email protected]>
+ * and Christoph Bartelmus <[email protected]>
+ * patch for the BestBuy by Miguel Angel Alvarez <[email protected]>
+ * patch for the Winfast TV2000 by Juan Toledo
+ * <[email protected]>
+ * patch for the I-O Data GV-BCTV5/PCI by Jens C. Rasmussen
+ * <[email protected]>
+ *
+ * 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.
+ *
+ * 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
+ *
+ * $Id: lirc_gpio.c,v 1.30 2003/06/07 22:00:10 lirc Exp $
+ *
+ */
+
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include "../../media/video/bttv.h"
+#include "../../media/video/bttvp.h"
+
+#include "lirc_dev.h"
+
+static int debug = 0;
+static int card = 0;
+static int minor = -1;
+static int bttv_id = BTTV_UNKNOWN;
+static unsigned long gpio_mask = 0;
+static unsigned long gpio_enable = 0;
+static unsigned long gpio_lock_mask = 0;
+static unsigned long gpio_xor_mask = 0;
+static unsigned int soft_gap = 0;
+static unsigned char sample_rate = 10;
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(card,"i");
+MODULE_PARM(minor,"i");
+MODULE_PARM(gpio_mask,"l");
+MODULE_PARM(gpio_lock_mask,"l");
+MODULE_PARM(gpio_xor_mask,"l");
+MODULE_PARM(soft_gap,"i");
+MODULE_PARM(sample_rate,"b");
+MODULE_PARM(bttv_id,"i");
+
+#undef dprintk
+#define dprintk if (debug) printk
+
+struct rcv_info {
+ int bttv_id;
+ int card_id;
+ unsigned long gpio_mask;
+ unsigned long gpio_enable;
+ unsigned long gpio_lock_mask;
+ unsigned long gpio_xor_mask;
+ unsigned int soft_gap;
+ unsigned char sample_rate;
+ unsigned char code_length;
+};
+
+static struct rcv_info rcv_infos[] = {
+ {BTTV_UNKNOWN, 0, 0, 0, 0, 0, 0, 1, 0},
+#ifdef BTTV_PXELVWPLTVPAK
+ {BTTV_PXELVWPLTVPAK, 0, 0x00003e00, 0, 0x0010000, 0, 0, 15, 0},
+#endif
+ {BTTV_PXELVWPLTVPRO, 0, 0x00001f00, 0, 0x0008000, 0, 500, 12, 32},
+#ifdef BTTV_PV_BT878P_9B
+ {BTTV_PV_BT878P_9B, 0, 0x00001f00, 0, 0x0008000, 0, 500, 12, 32},
+#endif
+ {BTTV_AVERMEDIA, 0, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32},
+ {BTTV_AVPHONE98, 0x00011461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000, 0, 10, 0}, /*mapped to Capture98*/
+ {BTTV_AVERMEDIA98, 0x00021461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000, 0, 10, 0}, /*mapped to Capture98*/
+ {BTTV_AVPHONE98, 0x00031461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* is this one correct? */
+ {BTTV_AVERMEDIA98, 0x00041461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* work-around for VDOMATE */
+ {BTTV_AVERMEDIA98, 0x03001461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* reported by Danijel Korzinek, AVerTV GOw/FM */
+ {BTTV_AVERMEDIA98, 0x00000000, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ {BTTV_CHRONOS_VS2, 0, 0x000000f8, 0, 0x0000100, 0, 0, 20, 0},
+ /* CPH031 and CPH033 cards (?) */
+ /* MIRO was just a work-around */
+ {BTTV_MIRO, 0, 0x00001f00, 0, 0x0004000, 0, 0, 10, 32},
+ {BTTV_DYNALINK, 0, 0x00001f00, 0, 0x0004000, 0, 0, 10, 32},
+ {BTTV_WINVIEW_601, 0, 0x00001f00, 0, 0x0004000, 0, 0, 0, 32},
+#ifdef BTTV_KWORLD
+ {BTTV_KWORLD, 0, 0x00007f00, 0, 0x0004000, 0, 0, 12, 32},
+#endif
+ /* just a guess */
+ {BTTV_MAGICTVIEW061, 0, 0x0028e000, 0, 0x0020000, 0, 0, 20, 32},
+ {BTTV_MAGICTVIEW063, 0, 0x0028e000, 0, 0x0020000, 0, 0, 20, 32},
+ {BTTV_PHOEBE_TVMAS, 0, 0x0028e000, 0, 0x0020000, 0, 0, 20, 32},
+#ifdef BTTV_BESTBUY_EASYTV2
+ {BTTV_BESTBUY_EASYTV, 0, 0x00007F00, 0, 0x0004000, 0, 0, 10, 8},
+ {BTTV_BESTBUY_EASYTV2, 0, 0x00007F00, 0, 0x0008000, 0, 0, 10, 8},
+#endif
+ /* lock_mask probably also 0x100, or maybe it is 0x0 for all others !?! */
+ {BTTV_FLYVIDEO, 0, 0x000000f8, 0, 0, 0, 0, 0, 42},
+ {BTTV_FLYVIDEO_98, 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 42},
+ {BTTV_TYPHOON_TVIEW, 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 42},
+#ifdef BTTV_FLYVIDEO_98FM
+ /* [email protected] */
+ {BTTV_FLYVIDEO_98FM, 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 42},
+#endif
+ /* The Leadtek WinFast TV 2000 XP card (id 0x6606107d) uses an
+ * extra gpio bit compared to the original TV 2000 card (id
+ * 0x217d6606); as the bttv-0.7.100 driver does not
+ * distinguish between the two cards, we enable the extra bit
+ * based on the card id: */
+ {BTTV_WINFAST2000, 0x6606107d, 0x000008f8, 0, 0x0000100, 0, 0, 0, 32},
+ /* default: */
+ {BTTV_WINFAST2000, 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 32},
+#ifdef BTTV_GVBCTV5PCI
+ {BTTV_GVBCTV5PCI, 0, 0x00f0b000, 0, 0, 0, 0, 20, 8},
+#endif
+};
+
+static unsigned char code_length = 0;
+static unsigned char code_bytes = 1;
+
+#define MAX_BYTES 8
+
+#define SUCCESS 0
+#define LOGHEAD "lirc_gpio (%d): "
+
+/* how many bits GPIO value can be shifted right before processing
+ * it is computed from the value of gpio_mask_parameter
+ */
+static unsigned char gpio_pre_shift = 0;
+
+
+static inline int reverse(int data, int bits)
+{
+ int i;
+ int c;
+
+ for (c=0,i=0; i<bits; i++) {
+ c |= (((data & (1<<i)) ? 1:0)) << (bits-1-i);
+ }
+
+ return c;
+}
+
+static int build_key(unsigned long gpio_val, unsigned char codes[MAX_BYTES])
+{
+ unsigned long mask = gpio_mask;
+ unsigned char shift = 0;
+
+ dprintk(LOGHEAD "gpio_val is %lx\n",card,(unsigned long) gpio_val);
+
+ gpio_val ^= gpio_xor_mask;
+
+ if (gpio_lock_mask && (gpio_val & gpio_lock_mask)) {
+ return -EBUSY;
+ }
+
+ switch (bttv_id)
+ {
+ case BTTV_AVERMEDIA98:
+ if (bttv_write_gpio(card, gpio_enable, gpio_enable)) {
+ dprintk(LOGHEAD "cannot write to GPIO\n", card);
+ return -EIO;
+ }
+ if (bttv_read_gpio(card, &gpio_val)) {
+ dprintk(LOGHEAD "cannot read GPIO\n", card);
+ return -EIO;
+ }
+ if (bttv_write_gpio(card, gpio_enable, 0)) {
+ dprintk(LOGHEAD "cannot write to GPIO\n", card);
+ return -EIO;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* extract bits from "raw" GPIO value using gpio_mask */
+ codes[0] = 0;
+ gpio_val >>= gpio_pre_shift;
+ while (mask) {
+ if (mask & 1u) {
+ codes[0] |= (gpio_val & 1u) << shift++;
+ }
+ mask >>= 1;
+ gpio_val >>= 1;
+ }
+
+ dprintk(LOGHEAD "code is %lx\n",card,(unsigned long) codes[0]);
+ switch (bttv_id)
+ {
+ case BTTV_AVERMEDIA:
+ codes[2] = (codes[0]<<2)&0xff;
+ codes[3] = (~codes[2])&0xff;
+ codes[0] = 0x02;
+ codes[1] = 0xFD;
+ break;
+ case BTTV_AVPHONE98:
+ codes[2] = ((codes[0]&(~0x1))<<2)&0xff;
+ codes[3] = (~codes[2])&0xff;
+ if (codes[0]&0x1) {
+ codes[0] = 0xc0;
+ codes[1] = 0x3f;
+ } else {
+ codes[0] = 0x40;
+ codes[1] = 0xbf;
+ }
+ break;
+ case BTTV_AVERMEDIA98:
+ break;
+ case BTTV_FLYVIDEO:
+ case BTTV_FLYVIDEO_98:
+ case BTTV_TYPHOON_TVIEW:
+#ifdef BTTV_FLYVIDEO_98FM
+ case BTTV_FLYVIDEO_98FM:
+#endif
+ codes[4]=codes[0]<<3;
+ codes[5]=((~codes[4])&0xff);
+
+ codes[0]=0x00;
+ codes[1]=0x1A;
+ codes[2]=0x1F;
+ codes[3]=0x2F;
+ break;
+ case BTTV_MAGICTVIEW061:
+ case BTTV_MAGICTVIEW063:
+ case BTTV_PHOEBE_TVMAS:
+ codes[0] = (codes[0]&0x01)
+ |((codes[0]&0x02)<<1)
+ |((codes[0]&0x04)<<2)
+ |((codes[0]&0x08)>>2)
+ |((codes[0]&0x10)>>1);
+ /* FALLTHROUGH */
+ case BTTV_MIRO:
+ case BTTV_DYNALINK:
+ case BTTV_PXELVWPLTVPRO:
+#ifdef BTTV_PV_BT878P_9B
+ case BTTV_PV_BT878P_9B:
+#endif
+#ifdef BTTV_KWORLD
+ case BTTV_KWORLD:
+#endif
+ codes[2] = reverse(codes[0],8);
+ codes[3] = (~codes[2])&0xff;
+ codes[0] = 0x61;
+ codes[1] = 0xD6;
+ break;
+#if 0
+ /* derived from e-tech config file */
+ /* 26 + 16 bits */
+ /* won't apply it until it's confirmed with a fly98 */
+ case BTTV_FLYVIDEO_98:
+ case BTTV_FLYVIDEO_98FM:
+ codes[4]=codes[0]<<3;
+ codes[5]=(~codes[4])&0xff;
+
+ codes[0]=0x00;
+ codes[1]=0x1A;
+ codes[2]=0x1F;
+ codes[3]=0x2F;
+ break;
+#endif
+ case BTTV_WINFAST2000:
+ case BTTV_WINVIEW_601:
+ codes[2] = reverse(codes[0],8);
+ codes[3] = (~codes[2])&0xff;
+ codes[0] = 0xC0;
+ codes[1] = 0x3F;
+ break;
+ default:
+ break;
+ }
+
+ return SUCCESS;
+}
+
+static int get_key(void* data, unsigned char *key, int key_no)
+{
+ static unsigned long next_time = 0;
+ static unsigned char codes[MAX_BYTES];
+ unsigned long code = 0;
+ unsigned char cur_codes[MAX_BYTES];
+
+ if (key_no > 0) {
+ if (code_bytes < 2 || key_no >= code_bytes) {
+ dprintk(LOGHEAD "something wrong in get_key\n", card);
+ return -EBADRQC;
+ }
+ *key = codes[key_no];
+ return SUCCESS;
+ }
+
+ if (bttv_read_gpio(card, &code)) {
+ dprintk(LOGHEAD "cannot read GPIO\n", card);
+ return -EIO;
+ }
+
+ if (build_key(code, cur_codes)) {
+ return -EFAULT;
+ }
+
+ if (soft_gap) {
+ if (!memcmp(codes, cur_codes, code_bytes) &&
+ jiffies < next_time) {
+ return -EAGAIN;
+ }
+ next_time = jiffies + soft_gap;
+ }
+
+ memcpy(codes, cur_codes, code_bytes);
+
+ *key = codes[0];
+
+ return SUCCESS;
+}
+
+static int set_use_inc(void* data)
+{
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static void set_use_dec(void* data)
+{
+ module_put(THIS_MODULE);
+}
+
+static wait_queue_head_t* get_queue(void* data)
+{
+ return bttv_get_gpio_queue(card);
+}
+
+static struct lirc_plugin plugin = {
+ .name = "lirc_gpio ",
+ .get_key = get_key,
+ .get_queue = get_queue,
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+};
+
+/*
+ *
+ */
+int gpio_remote_init(void)
+{
+ int ret;
+ unsigned int mask;
+
+ /* "normalize" gpio_mask
+ * this means shift it right until first bit is set
+ */
+ while (!(gpio_mask & 1u)) {
+ gpio_pre_shift++;
+ gpio_mask >>= 1;
+ }
+
+ if (code_length) {
+ plugin.code_length = code_length;
+ } else {
+ /* calculate scan code length in bits if needed */
+ plugin.code_length = 1;
+ mask = gpio_mask >> 1;
+ while (mask) {
+ if (mask & 1u) {
+ plugin.code_length++;
+ }
+ mask >>= 1;
+ }
+ }
+
+ code_bytes = (plugin.code_length/8) + (plugin.code_length%8 ? 1 : 0);
+ if (MAX_BYTES < code_bytes) {
+ printk (LOGHEAD "scan code too long (%d bytes)\n",
+ minor, code_bytes);
+ return -EBADRQC;
+ }
+
+ if (gpio_enable) {
+ if(bttv_gpio_enable(card, gpio_enable, gpio_enable)) {
+ printk(LOGHEAD "gpio_enable failure\n", minor);
+ return -EIO;
+ }
+ }
+
+
+ /* translate ms to jiffies */
+ soft_gap = (soft_gap*HZ) / 1000;
+
+ plugin.minor = minor;
+ plugin.sample_rate = sample_rate;
+
+ ret = lirc_register_plugin(&plugin);
+
+ if (0 > ret) {
+ printk (LOGHEAD "device registration failed with %d\n",
+ minor, ret);
+ return ret;
+ }
+
+ minor = ret;
+ printk(LOGHEAD "driver registered\n", minor);
+
+ return SUCCESS;
+}
+
+static int __init lirc_gpio_init(void)
+{
+ int type,cardid,card_type;
+
+ if (CONFIG_LIRC_MAX_DEV < minor) {
+ printk("lirc_gpio: parameter minor (%d) must be less than %d!\n",
+ minor, CONFIG_LIRC_MAX_DEV-1);
+ return -EBADRQC;
+ }
+
+ request_module("bttv");
+
+ /* if gpio_mask not zero then use module parameters
+ * instead of autodetecting TV card
+ */
+ if (gpio_mask) {
+ if (sample_rate!=0 && (2 > sample_rate || 50 < sample_rate)) {
+ printk(LOGHEAD "parameter sample_rate "
+ "must be beetween 2 and 50!\n", minor);
+ return -EBADRQC;
+ }
+
+ if (sample_rate!=0 && soft_gap &&
+ ((2000/sample_rate) > soft_gap || 1000 < soft_gap)) {
+ printk(LOGHEAD "parameter soft_gap "
+ "must be beetween %d and 1000!\n",
+ minor, 2000/sample_rate);
+ return -EBADRQC;
+ }
+ } else {
+ if(bttv_get_cardinfo(card,&type,&cardid)==-1) {
+ printk(LOGHEAD "could not get card type\n", minor);
+ }
+ printk(LOGHEAD "card type 0x%x, id 0x%x\n",minor,
+ type,cardid);
+
+ if (type == BTTV_UNKNOWN) {
+ printk(LOGHEAD "cannot detect TV card nr %d!\n",
+ minor, card);
+ return -EBADRQC;
+ }
+ for (card_type = 1;
+ card_type < sizeof(rcv_infos)/sizeof(struct rcv_info);
+ card_type++) {
+ if (rcv_infos[card_type].bttv_id == type &&
+ (rcv_infos[card_type].card_id == 0 ||
+ rcv_infos[card_type].card_id == cardid)) {
+ bttv_id = rcv_infos[card_type].bttv_id;
+ gpio_mask = rcv_infos[card_type].gpio_mask;
+ gpio_enable = rcv_infos[card_type].gpio_enable;
+ gpio_lock_mask = rcv_infos[card_type].gpio_lock_mask;
+ gpio_xor_mask = rcv_infos[card_type].gpio_xor_mask;
+ soft_gap = rcv_infos[card_type].soft_gap;
+ sample_rate = rcv_infos[card_type].sample_rate;
+ code_length = rcv_infos[card_type].code_length;
+ break;
+ }
+ }
+ if (type==BTTV_AVPHONE98 && cardid==0x00011461) {
+ bttv_id = BTTV_AVERMEDIA98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x00041461) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x03001461) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x00000000) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (card_type == sizeof(rcv_infos)/sizeof(struct rcv_info)) {
+ printk(LOGHEAD "TV card type %x not supported!\n",
+ minor, type);
+ return -EBADRQC;
+ }
+ }
+
+ request_module("lirc_dev");
+
+ return gpio_remote_init();
+}
+
+void __exit lirc_gpio_exit(void)
+{
+ int ret;
+
+ ret = lirc_unregister_plugin(minor);
+
+ if (0 > ret) {
+ printk(LOGHEAD "error in lirc_unregister_minor: %d\n"
+ "Trying again...\n",
+ minor, ret);
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ);
+
+ ret = lirc_unregister_plugin(minor);
+
+ if (0 > ret) {
+ printk(LOGHEAD "error in lirc_unregister_minor: %d!!!\n",
+ minor, ret);
+ return;
+ }
+ }
+
+ dprintk(LOGHEAD "module successfully unloaded\n", minor);
+}
+/* Dont try to use it as a static version ! */
+
+MODULE_DESCRIPTION("Driver module for remote control (data from bt848 GPIO port)");
+MODULE_AUTHOR("Artur Lipowski");
+MODULE_LICENSE("GPL");
+
+module_init(lirc_gpio_init);
+module_exit(lirc_gpio_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
--- linux/include/linux/lirc.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-lirc/include/linux/lirc.h 2003-08-07 22:53:49.000000000 +0200
@@ -0,0 +1,103 @@
+/* $Id: lirc.h,v 5.8 2003/01/26 12:57:59 lirc Exp $ */
+
+#ifndef _LINUX_LIRC_H
+#define _LINUX_LIRC_H
+
+#if defined (__linux__)
+#include <asm/types.h>
+#include <linux/ioctl.h>
+#else
+#include <sys/types.h>
+typedef u_int32_t __u32;
+#endif
+
+#define PULSE_BIT 0x01000000
+#define PULSE_MASK 0x00FFFFFF
+
+typedef int lirc_t;
+
+/*
+ * lirc compatible hardware features
+ */
+
+
+#define LIRC_MODE2SEND(x) (x)
+#define LIRC_SEND2MODE(x) (x)
+#define LIRC_MODE2REC(x) ((x) << 16)
+#define LIRC_REC2MODE(x) ((x) >> 16)
+
+#define LIRC_MODE_RAW 0x00000001
+#define LIRC_MODE_PULSE 0x00000002
+#define LIRC_MODE_MODE2 0x00000004
+#define LIRC_MODE_CODE 0x00000008
+#define LIRC_MODE_LIRCCODE 0x00000010
+#define LIRC_MODE_STRING 0x00000020
+
+
+#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW)
+#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE)
+#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2)
+#define LIRC_CAN_SEND_CODE LIRC_MODE2SEND(LIRC_MODE_CODE)
+#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
+#define LIRC_CAN_SEND_STRING LIRC_MODE2SEND(LIRC_MODE_STRING)
+
+#define LIRC_CAN_SEND_MASK 0x0000003f
+
+#define LIRC_CAN_SET_SEND_CARRIER 0x00000100
+#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200
+
+#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW)
+#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE)
+#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2)
+#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE)
+#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
+#define LIRC_CAN_REC_STRING LIRC_MODE2REC(LIRC_MODE_STRING)
+
+#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
+
+#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16)
+#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
+
+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
+#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000
+
+
+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
+
+/*
+ * IOCTL commands for lirc driver
+ */
+
+#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32)
+
+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32)
+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32)
+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32)
+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32)
+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32)
+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32)
+
+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32)
+
+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32)
+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32)
+/* Note: these can reset the according pulse_width */
+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32)
+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32)
+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32)
+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32)
+
+/* to set a range use
+ LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
+ lower bound first and later
+ LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound */
+
+#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32)
+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32)
+
+#define DEV_LIRC "lirc"
+#define IRCTL_DEV_MAJOR 61
+
+#endif


--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-08 09:21:05

by Flameeyes

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Thu, 2003-08-07 at 23:43, Pavel Machek wrote:
> If you want to get this applied to the official tree (I hope you want
> ;-), you probably should start with smaller patch. I killed all
> drivers but lirc_gpio, to make patch smaller/easier to check.
I sent to Alan Cox the "light" patch, but the "main" patch atm I think
it's best to remain the "full" one, for tests.

> * What does "For now don't try to use as static version" comment in
> lirc_gpio mean. Does it only work as a module?
I'm not the author of the drivers, I only took them from the lirc cvs,
and make them compile under 2.5/6 series kernel.
AFAICS it should work also in-kernel, but I can't try because I can't
set bttv in-kernel, my card isn't autodetected. (Also, bttv author
suggest to don't compile bttv in-kernel, so depending on bttv, this
driver should be compiled as a module too).

> * This looks like it should be integrated with drivers/input. After
> all remote control is just a strange keyboard. What are reasons that
> can't be done?
This is a port of the drivers from lirc project (http://lirc.sf.net/),
I'm not going to rewrite it, also because the support for lirc in user
software is present in many programs, like xine, xawdecode, xmms (with
plugin) and so on.
The lirc_client library is simple and flexible, and the project is
consolidated, i don't see the need to change it, also because can be a
problem for backport in the 2.4 kernels.
--
Flameeyes <[email protected]>

2003-08-08 23:17:54

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > * This looks like it should be integrated with drivers/input. After
> > all remote control is just a strange keyboard. What are reasons that
> > can't be done?
> This is a port of the drivers from lirc project (http://lirc.sf.net/),
> I'm not going to rewrite it, also because the support for lirc in user
> software is present in many programs, like xine, xawdecode, xmms (with
> plugin) and so on.
> The lirc_client library is simple and flexible, and the project is
> consolidated, i don't see the need to change it, also because can be a
> problem for backport in the 2.4 kernels.

I know about lirc project, and I'd like to see it merged, but if lirc
uses wrong interface, it is unsuitable for the kernel.

Motivation for having same code for infrared controls and normal
keyboards: normal keyboards tend to have "play"/"stop"/"vol+"/"vol-"
keys these days; certainly HP omnibook xe3 has them. It would be nice
to handle them in an uniform way.

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-09 17:17:45

by columbus

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

Pavel Machek "[email protected]" wrote:

[...]
>>> * This looks like it should be integrated with drivers/input. After
>>> all remote control is just a strange keyboard. What are reasons that
>>> can't be done?

Because for most drivers the decoding is done in user space by the lircd
daemon.

[...]
> I know about lirc project, and I'd like to see it merged, but if lirc
> uses wrong interface, it is unsuitable for the kernel.

Is it the wrong interface?

> Motivation for having same code for infrared controls and normal
> keyboards: normal keyboards tend to have "play"/"stop"/"vol+"/"vol-"
> keys these days; certainly HP omnibook xe3 has them. It would be nice
> to handle them in an uniform way.

No problem. Feed these keys to lircd. Voila: uniform interface to all
applications.

There already is a patch for exactly that here:
http://sourceforge.net/tracker/
index.php?func=detail&aid=670000&group_id=5444&atid=305444

I didn't have the time yet to have a closer look at this patch.

Christoph

2003-08-09 19:14:43

by Flameeyes

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Thu, 2003-08-07 at 23:43, Pavel Machek wrote:
> * What does "For now don't try to use as static version" comment in
> lirc_gpio mean. Does it only work as a module?
Ok i've tested it out. If i'll build in-kernel bttv and pass to kernel
the parameters for the card, lirc_gpio is checked before the bttv itself
and result in an error.
It need to be built as a module, always.

--
Flameeyes <[email protected]>

2003-08-11 11:11:17

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > This is the fourth version of my patch for use LIRC drivers under
> > 2.5/2.6 kernels.
> >
> > As usual, you can find it at
> > http://flameeyes.web.ctonet.it/lirc/patch-lirc-20030802.diff.bz2
> >
> > I changed the naming scheme, because I tried and the patch applies also
> > in earliers and (probably) futures kernels, and call it only
> > "patch-lirc.diff" will confuse about the versions. I think a datestamp
> > is the best choice for now.
>
> If you want to get this applied to the official tree (I hope you want
> ;-), you probably should start with smaller patch. I killed all
> drivers but lirc_gpio, to make patch smaller/easier to check.
>
> Its now small enough to inline, and that's good.
>
> Few questions:
>
> * What does "For now don't try to use as static version" comment in
> lirc_gpio mean. Does it only work as a module?

Here's fix for that particular uglyness. I tested lirc_gpio and it
actually works here. Good. Please apply this,

Pavel
--- linux-lirc/drivers/char/lirc/lirc_gpio.c.ofic 2003-08-10 23:44:28.000000000 +0200
+++ linux-lirc/drivers/char/lirc/lirc_gpio.c 2003-08-10 23:45:02.000000000 +0200
@@ -530,13 +530,16 @@

dprintk(LOGHEAD "module successfully unloaded\n", minor);
}
-/* Dont try to use it as a static version ! */

MODULE_DESCRIPTION("Driver module for remote control (data from bt848 GPIO port)");
MODULE_AUTHOR("Artur Lipowski");
MODULE_LICENSE("GPL");

+#ifdef MODULE
module_init(lirc_gpio_init);
+#else
+late_initcall(lirc_gpio_init);
+#endif
module_exit(lirc_gpio_exit);

/*

--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 12:48:44

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> >>> * This looks like it should be integrated with drivers/input. After
> >>> all remote control is just a strange keyboard. What are reasons that
> >>> can't be done?
>
> Because for most drivers the decoding is done in user space by the lircd
> daemon.

I see that for drivers like lirc_serial and lirc_paralel lircd setup
makes sense, but trying to fit lirc_gpio into that model only
complicates things as far as I can see.

> [...]
> > I know about lirc project, and I'd like to see it merged, but if lirc
> > uses wrong interface, it is unsuitable for the kernel.
>
> Is it the wrong interface?

I believe it is wrong interface for lirc_gpio at least. (I took
detailed look at that one -- I have the hw). It is probably right
interface for serial/paralel homebrew hardware, but I'd expect that to
be less and less common these days...

> > Motivation for having same code for infrared controls and normal
> > keyboards: normal keyboards tend to have "play"/"stop"/"vol+"/"vol-"
> > keys these days; certainly HP omnibook xe3 has them. It would be nice
> > to handle them in an uniform way.
>
> No problem. Feed these keys to lircd. Voila: uniform interface to all
> applications.

There should be no need for additional daemon when input layer works
as well...

I converted lirc_gpio into input/ layer (and killed support for
hardware I do not have; sorry but it was essential to keep code
small). Ported driver looks like this; I believe it looks better than
old code. Patch is here.

[input layer still lacks few keys, like "AUTOSCAN" key, but I guess
that can be fixed easily. Also driver still needs some cleanups...].

Pavel

--- clean/drivers/input/keyboard/Makefile 2003-03-27 10:40:00.000000000 +0100
+++ linux/drivers/input/keyboard/Makefile 2003-08-11 01:04:21.000000000 +0200
@@ -11,3 +11,4 @@
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o
+obj-y += bttv_remote.o
Binary files /dev/null and linux/drivers/input/keyboard/atkbd.o differ
--- clean/drivers/input/keyboard/bttv_avermedia.c 2003-08-11 14:06:22.000000000 +0200
+++ linux/drivers/input/keyboard/bttv_avermedia.c 2003-08-11 14:26:23.000000000 +0200
@@ -0,0 +1,49 @@
+/* Copyright 2003 Pavel Machek <[email protected]>, distribute under GPLv2.
+ *
+ * Translation codes for controller that came with TVPhone98w/VCR. It has
+ * only one label "AVerMedia" on it.
+ */
+
+int
+decode_bttv_avermedia(long code)
+{
+ switch (code) {
+ case 0x8577c0: return KEY_TUNER;
+ case 0x4577c0: return KEY_TV;
+ case 0xc577c0: return KEY_EJECTCD; /* Unmarked on my controller */
+ case 0x577c0: return KEY_POWER;
+ case 0xa577c0: return KEY_KP1;
+ case 0x6577c0: return KEY_KP2;
+ case 0xe577c0: return KEY_KP3;
+ case 0x2577c0: return KEY_VIDEO;
+ case 0x9577c0: return KEY_KP4;
+ case 0x5577c0: return KEY_KP5;
+ case 0xd577c0: return KEY_KP6;
+ case 0x1577c0: return KEY_AUDIO;
+ case 0xb577c0: return KEY_KP7;
+ case 0x7577c0: return KEY_KP8;
+ case 0xf577c0: return KEY_KP9;
+ case 0x3577c0: return KEY_ZOOM;
+ case 0x8d77c0: return KEY_KP0;
+ case 0x4d77c0: return KEY_CYCLEWINDOWS; /* DISPLAY/L */
+ case 0xcd77c0: return KEY_AGAIN; /* LOOP/R */
+ case 0xd77c0: return KEY_INFO; /* preview */
+ case 0xad77c0: return KEY_SEARCH; /* autoscan */
+ case 0x6d77c0: return KEY_BREAK; /* freeze */
+ case 0xed77c0: return KEY_PVR; /* capture */
+ case 0x2d77c0: return KEY_MUTE;
+ case 0x9d77c0: return KEY_RECORD;
+ case 0x5d77c0: return KEY_PAUSE;
+ case 0xdd77c0: return KEY_STOP;
+ case 0x1d77c0: return KEY_PLAY;
+ case 0xbd77c0: return KEY_RED;
+ case 0x7d77c0: return KEY_VOLUMEDOWN;
+ case 0xfd77c0: return KEY_VOLUMEUP;
+ case 0x3d77c0: return KEY_GREEN;
+ case 0x85f7c0: return KEY_YELLOW;
+ case 0x45f7c0: return KEY_CHANNELDOWN;
+ case 0xc5f7c0: return KEY_CHANNELUP;
+ case 0x5f7c0: return KEY_BLUE;
+ default: printk("bttv_avermedia: unknown code %lx\n", code);
+ }
+}
--- clean/drivers/input/keyboard/bttv_remote.c 2003-08-11 00:55:34.000000000 +0200
+++ linux/drivers/input/keyboard/bttv_remote.c 2003-08-11 14:31:00.000000000 +0200
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2003 Pavel Machek
+ *
+ * (L) by Artur Lipowski <[email protected]>
+ * patch for the AverMedia by Santiago Garcia Mantinan <[email protected]>
+ * and Christoph Bartelmus <[email protected]>
+ * patch for the BestBuy by Miguel Angel Alvarez <[email protected]>
+ * patch for the Winfast TV2000 by Juan Toledo
+ * <[email protected]>
+ * patch for the I-O Data GV-BCTV5/PCI by Jens C. Rasmussen
+ * <[email protected]>
+ */
+
+/*
+ * Driver for bttv cards.
+ */
+
+/*
+ * 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.
+ *
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <[email protected]>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include "../../media/video/bttv.h"
+#include "../../media/video/bttvp.h"
+#include "bttv_avermedia.c"
+
+MODULE_AUTHOR("Pavel Machek <[email protected]>");
+MODULE_DESCRIPTION("BTTV infrared remote control");
+MODULE_LICENSE("GPL");
+
+static struct input_dev gpio_dev;
+
+static char *gpio_name = "BTTV remote control";
+static char *gpio_phys = "bttv/input0";
+
+static unsigned short gpio_keycode[KEY_MAX];
+
+struct rcv_info {
+ int bttv_id;
+ int card_id;
+ unsigned long gpio_mask;
+ unsigned long gpio_enable;
+ unsigned long gpio_lock_mask;
+ unsigned long gpio_xor_mask;
+ unsigned int soft_gap;
+ unsigned char sample_rate;
+ unsigned char code_length;
+};
+
+static struct rcv_info rcv_infos[] = {
+ {BTTV_UNKNOWN, 0, 0, 0, 0, 0, 0, 1, 0},
+ {BTTV_AVERMEDIA, 0, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32},
+ {BTTV_AVPHONE98, 0x00011461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000, 0, 10, 0}, /*mapped to Capture98*/
+ {BTTV_AVERMEDIA98, 0x00021461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000, 0, 10, 0}, /*mapped to Capture98*/
+ {BTTV_AVPHONE98, 0x00031461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* is this one correct? */
+ {BTTV_AVERMEDIA98, 0x00041461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* work-around for VDOMATE */
+ {BTTV_AVERMEDIA98, 0x03001461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* reported by Danijel Korzinek, AVerTV GOw/FM */
+ {BTTV_AVERMEDIA98, 0x00000000, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+};
+
+static int debug = 0;
+static int card = 0;
+static int minor = -1;
+static int bttv_id = BTTV_UNKNOWN;
+static unsigned long gpio_mask = 0;
+static unsigned long gpio_enable = 0;
+static unsigned long gpio_lock_mask = 0;
+static unsigned long gpio_xor_mask = 0;
+static unsigned int soft_gap = 0;
+static unsigned char sample_rate = 10;
+
+static unsigned char code_length = 0;
+static unsigned char code_bytes = 1;
+
+#define MAX_BYTES 8
+
+#define SUCCESS 0
+#define LOGHEAD "lirc_gpio (%d): "
+
+/* how many bits GPIO value can be shifted right before processing
+ * it is computed from the value of gpio_mask_parameter
+ */
+static unsigned char gpio_pre_shift = 0;
+
+static int build_key(unsigned long gpio_val, unsigned char codes[MAX_BYTES])
+{
+ unsigned long mask = gpio_mask;
+ unsigned char shift = 0;
+
+ dprintk(LOGHEAD "gpio_val is %lx\n",card,(unsigned long) gpio_val);
+
+ gpio_val ^= gpio_xor_mask;
+
+ if (gpio_lock_mask && (gpio_val & gpio_lock_mask)) {
+ return -EBUSY;
+ }
+
+ switch (bttv_id)
+ {
+ case BTTV_AVERMEDIA98:
+ if (bttv_write_gpio(card, gpio_enable, gpio_enable)) {
+ dprintk(LOGHEAD "cannot write to GPIO\n", card);
+ return -EIO;
+ }
+ if (bttv_read_gpio(card, &gpio_val)) {
+ dprintk(LOGHEAD "cannot read GPIO\n", card);
+ return -EIO;
+ }
+ if (bttv_write_gpio(card, gpio_enable, 0)) {
+ dprintk(LOGHEAD "cannot write to GPIO\n", card);
+ return -EIO;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* extract bits from "raw" GPIO value using gpio_mask */
+ codes[0] = 0;
+ gpio_val >>= gpio_pre_shift;
+ while (mask) {
+ if (mask & 1u) {
+ codes[0] |= (gpio_val & 1u) << shift++;
+ }
+ mask >>= 1;
+ gpio_val >>= 1;
+ }
+
+ dprintk(LOGHEAD "code is %lx\n",card,(unsigned long) codes[0]);
+ switch (bttv_id)
+ {
+ case BTTV_AVERMEDIA:
+ codes[2] = (codes[0]<<2)&0xff;
+ codes[3] = (~codes[2])&0xff;
+ codes[0] = 0x02;
+ codes[1] = 0xFD;
+ break;
+ case BTTV_AVPHONE98:
+ codes[2] = ((codes[0]&(~0x1))<<2)&0xff;
+ codes[3] = (~codes[2])&0xff;
+ if (codes[0]&0x1) {
+ codes[0] = 0xc0;
+ codes[1] = 0x3f;
+ } else {
+ codes[0] = 0x40;
+ codes[1] = 0xbf;
+ }
+ break;
+ case BTTV_AVERMEDIA98:
+ break;
+ default:
+ break;
+ }
+
+ return SUCCESS;
+}
+
+static void poll_me(void)
+{
+ static unsigned long next_time = 0;
+ static unsigned char codes[MAX_BYTES];
+ unsigned long code = 0;
+ unsigned char cur_codes[MAX_BYTES];
+
+ if (bttv_read_gpio(card, &code)) {
+ dprintk(LOGHEAD "cannot read GPIO\n", card);
+ return -EIO;
+ }
+
+ if (build_key(code, cur_codes)) {
+ return -EFAULT;
+ }
+
+ if (soft_gap) {
+ if (!memcmp(codes, cur_codes, code_bytes) &&
+ jiffies < next_time) {
+ return -EAGAIN;
+ }
+ next_time = jiffies + soft_gap;
+ }
+
+ memcpy(codes, cur_codes, code_bytes);
+
+ printk("Key %lx was pressed\n", code);
+ input_report_key(&gpio_dev, decode_bttv_avermedia(code), 1);
+ input_report_key(&gpio_dev, decode_bttv_avermedia(code), 0);
+ input_sync(&gpio_dev);
+ return 0;
+}
+
+/* main function of the polling thread
+ */
+static int lirc_thread(void *unused)
+{
+ lock_kernel();
+
+ /* This thread doesn't need any user-level access,
+ * so get rid of all our resources
+ */
+ exit_mm(current);
+ exit_files(current);
+ exit_fs(current);
+ current->session = 1;
+ current->pgrp = 1;
+ current->euid = 0;
+ current->tty = NULL;
+ sigfillset(&current->blocked);
+
+ strcpy(current->comm, "lirc_dev");
+
+ unlock_kernel();
+
+ do {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/5);
+ poll_me();
+ } while (1);
+ return 0;
+}
+
+int gpio_remote_init(void)
+{
+ int ret;
+ unsigned int mask;
+
+ /* "normalize" gpio_mask
+ * this means shift it right until first bit is set
+ */
+ while (!(gpio_mask & 1u)) {
+ gpio_pre_shift++;
+ gpio_mask >>= 1;
+ }
+
+ if (gpio_enable) {
+ if(bttv_gpio_enable(card, gpio_enable, gpio_enable)) {
+ printk(LOGHEAD "gpio_enable failure\n", minor);
+ return -EIO;
+ }
+ }
+
+ /* translate ms to jiffies */
+ soft_gap = (soft_gap*HZ) / 1000;
+
+#if 0
+ plugin.minor = minor;
+ plugin.sample_rate = sample_rate;
+#endif
+
+ return 0;
+}
+
+static int __init gpio_init(void)
+{
+ int i;
+ int type,cardid,card_type;
+
+ request_module("bttv");
+
+ if(bttv_get_cardinfo(card,&type,&cardid)==-1) {
+ printk(LOGHEAD "could not get card type\n", minor);
+ }
+ printk(LOGHEAD "card type 0x%x, id 0x%x\n",minor,
+ type,cardid);
+
+ if (type == BTTV_UNKNOWN) {
+ printk(LOGHEAD "cannot detect TV card nr %d!\n",
+ minor, card);
+ return -EBADRQC;
+ }
+ for (card_type = 1;
+ card_type < sizeof(rcv_infos)/sizeof(struct rcv_info);
+ card_type++) {
+ if (rcv_infos[card_type].bttv_id == type &&
+ (rcv_infos[card_type].card_id == 0 ||
+ rcv_infos[card_type].card_id == cardid)) {
+ bttv_id = rcv_infos[card_type].bttv_id;
+ gpio_mask = rcv_infos[card_type].gpio_mask;
+ gpio_enable = rcv_infos[card_type].gpio_enable;
+ gpio_lock_mask = rcv_infos[card_type].gpio_lock_mask;
+ gpio_xor_mask = rcv_infos[card_type].gpio_xor_mask;
+ soft_gap = rcv_infos[card_type].soft_gap;
+ sample_rate = rcv_infos[card_type].sample_rate;
+ code_length = rcv_infos[card_type].code_length;
+ break;
+ }
+ if (type==BTTV_AVPHONE98 && cardid==0x00011461) {
+ bttv_id = BTTV_AVERMEDIA98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x00041461) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x03001461) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x00000000) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (card_type == sizeof(rcv_infos)/sizeof(struct rcv_info)) {
+ printk(LOGHEAD "TV card type %x not supported!\n",
+ minor, type);
+ return -EBADRQC;
+ }
+ }
+
+ if (gpio_remote_init())
+ return -EIO;
+
+ init_input_dev(&gpio_dev);
+
+ for (i=0; i<KEY_MAX; i++)
+ gpio_keycode[i] = i;
+ gpio_dev.evbit[0] = BIT(EV_KEY);
+ gpio_dev.keycode = gpio_keycode;
+ gpio_dev.keycodesize = sizeof(unsigned short);
+ gpio_dev.keycodemax = KEY_MAX;
+
+ for (i = 0; i < 0x78; i++)
+ if (gpio_keycode[i])
+ set_bit(gpio_keycode[i], gpio_dev.keybit);
+
+ gpio_dev.name = gpio_name;
+ gpio_dev.phys = gpio_phys;
+ gpio_dev.id.bustype = BUS_AMIGA;
+ gpio_dev.id.vendor = 0x1234;
+ gpio_dev.id.product = 0x5678;
+ gpio_dev.id.version = 0x90ab;
+
+ input_register_device(&gpio_dev);
+ kernel_thread(lirc_thread, NULL, 0);
+
+ printk(KERN_INFO "input: %s\n", gpio_name);
+
+ return 0;
+}
+
+static void __exit gpio_exit(void)
+{
+ input_unregister_device(&gpio_dev);
+}
+
+late_initcall(gpio_init);
+module_exit(gpio_exit);

--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 13:10:40

by Flameeyes

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, 2003-08-11 at 14:47, Pavel Machek wrote:
> I converted lirc_gpio into input/ layer (and killed support for
> hardware I do not have; sorry but it was essential to keep code
> small). Ported driver looks like this; I believe it looks better than
> old code. Patch is here.
You can here see the problem... not all tv cards use the same remote,
the switch doesn't work with my remote for example, so we have 2
possibilities:

a) hardcode all the possible remotes adding these as new one come up,
this is a big work in the kernel source, and also we lost compatibility
with remotes that use the same frequency of the ones with the tv card,
and that now can be used.

b) create an userspace utility that read the input layer for codes an
then translates them in user-definable commands. This is what lircd do
now...

IMHO, the solution used now is the more flexible of the two.
--
Flameeyes <[email protected]>

2003-08-11 13:15:03

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

Here's updated "bttv_remote.c" patch. This time with config option.

Pavel

--- /usr/src/tmp/linux/drivers/input/keyboard/Kconfig 2003-08-10 21:22:48.000000000 +0200
+++ /usr/src/linux/drivers/input/keyboard/Kconfig 2003-08-11 14:51:53.000000000 +0200
@@ -99,6 +99,11 @@

This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
- The module will be called xtkbd.o. If you want to compile it as a
+ The module will be called 98kbd. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.

+config KEYBOARD_BTTV
+ tristate "BTTV remote control support"
+ depends on INPUT && INPUT_KEYBOARD
+ help
+ Say Y here if you want remote control on your bttv card to work.
--- /usr/src/tmp/linux/drivers/input/keyboard/Makefile 2003-03-27 10:40:00.000000000 +0100
+++ /usr/src/linux/drivers/input/keyboard/Makefile 2003-08-11 14:52:08.000000000 +0200
@@ -11,3 +11,4 @@
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o
+obj-$(CONFIG_KEYBOARD_BTTV) += bttv_remote.o
--- /usr/src/tmp/linux/drivers/input/keyboard/bttv_avermedia.c 2003-08-11 14:06:22.000000000 +0200
+++ /usr/src/linux/drivers/input/keyboard/bttv_avermedia.c 2003-08-11 14:26:23.000000000 +0200
@@ -0,0 +1,49 @@
+/* Copyright 2003 Pavel Machek <[email protected]>, distribute under GPLv2.
+ *
+ * Translation codes for controller that came with TVPhone98w/VCR. It has
+ * only one label "AVerMedia" on it.
+ */
+
+int
+decode_bttv_avermedia(long code)
+{
+ switch (code) {
+ case 0x8577c0: return KEY_TUNER;
+ case 0x4577c0: return KEY_TV;
+ case 0xc577c0: return KEY_EJECTCD; /* Unmarked on my controller */
+ case 0x577c0: return KEY_POWER;
+ case 0xa577c0: return KEY_KP1;
+ case 0x6577c0: return KEY_KP2;
+ case 0xe577c0: return KEY_KP3;
+ case 0x2577c0: return KEY_VIDEO;
+ case 0x9577c0: return KEY_KP4;
+ case 0x5577c0: return KEY_KP5;
+ case 0xd577c0: return KEY_KP6;
+ case 0x1577c0: return KEY_AUDIO;
+ case 0xb577c0: return KEY_KP7;
+ case 0x7577c0: return KEY_KP8;
+ case 0xf577c0: return KEY_KP9;
+ case 0x3577c0: return KEY_ZOOM;
+ case 0x8d77c0: return KEY_KP0;
+ case 0x4d77c0: return KEY_CYCLEWINDOWS; /* DISPLAY/L */
+ case 0xcd77c0: return KEY_AGAIN; /* LOOP/R */
+ case 0xd77c0: return KEY_INFO; /* preview */
+ case 0xad77c0: return KEY_SEARCH; /* autoscan */
+ case 0x6d77c0: return KEY_BREAK; /* freeze */
+ case 0xed77c0: return KEY_PVR; /* capture */
+ case 0x2d77c0: return KEY_MUTE;
+ case 0x9d77c0: return KEY_RECORD;
+ case 0x5d77c0: return KEY_PAUSE;
+ case 0xdd77c0: return KEY_STOP;
+ case 0x1d77c0: return KEY_PLAY;
+ case 0xbd77c0: return KEY_RED;
+ case 0x7d77c0: return KEY_VOLUMEDOWN;
+ case 0xfd77c0: return KEY_VOLUMEUP;
+ case 0x3d77c0: return KEY_GREEN;
+ case 0x85f7c0: return KEY_YELLOW;
+ case 0x45f7c0: return KEY_CHANNELDOWN;
+ case 0xc5f7c0: return KEY_CHANNELUP;
+ case 0x5f7c0: return KEY_BLUE;
+ default: printk("bttv_avermedia: unknown code %lx\n", code);
+ }
+}
--- /usr/src/tmp/linux/drivers/input/keyboard/bttv_remote.c 2003-08-11 00:55:34.000000000 +0200
+++ /usr/src/linux/drivers/input/keyboard/bttv_remote.c 2003-08-11 15:02:22.000000000 +0200
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2003 Pavel Machek
+ *
+ * (L) by Artur Lipowski <[email protected]>
+ * patch for the AverMedia by Santiago Garcia Mantinan <[email protected]>
+ * and Christoph Bartelmus <[email protected]>
+ * patch for the BestBuy by Miguel Angel Alvarez <[email protected]>
+ * patch for the Winfast TV2000 by Juan Toledo
+ * <[email protected]>
+ * patch for the I-O Data GV-BCTV5/PCI by Jens C. Rasmussen
+ * <[email protected]>
+ */
+
+/*
+ * Driver for bttv cards.
+ */
+
+/*
+ * 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.
+ *
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <[email protected]>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include "../../media/video/bttv.h"
+#include "../../media/video/bttvp.h"
+#include "bttv_avermedia.c"
+
+MODULE_AUTHOR("Pavel Machek <[email protected]>");
+MODULE_DESCRIPTION("BTTV infrared remote control");
+MODULE_LICENSE("GPL");
+
+static struct input_dev gpio_dev;
+
+static char *gpio_name = "BTTV remote control";
+static char *gpio_phys = "bttv/input0";
+
+static unsigned short gpio_keycode[KEY_MAX];
+
+struct rcv_info {
+ int bttv_id;
+ int card_id;
+ unsigned long gpio_mask;
+ unsigned long gpio_enable;
+ unsigned long gpio_lock_mask;
+ unsigned long gpio_xor_mask;
+ unsigned int soft_gap;
+ unsigned char sample_rate;
+ unsigned char code_length;
+};
+
+static struct rcv_info rcv_infos[] = {
+ {BTTV_UNKNOWN, 0, 0, 0, 0, 0, 0, 1, 0},
+ {BTTV_AVERMEDIA, 0, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32},
+ {BTTV_AVPHONE98, 0x00011461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000, 0, 10, 0}, /*mapped to Capture98*/
+ {BTTV_AVERMEDIA98, 0x00021461, 0x003b8000, 0x00004000, 0x0800000, 0x00800000, 0, 10, 0}, /*mapped to Capture98*/
+ {BTTV_AVPHONE98, 0x00031461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* is this one correct? */
+ {BTTV_AVERMEDIA98, 0x00041461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* work-around for VDOMATE */
+ {BTTV_AVERMEDIA98, 0x03001461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+ /* reported by Danijel Korzinek, AVerTV GOw/FM */
+ {BTTV_AVERMEDIA98, 0x00000000, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, /*mapped to Phone98*/
+};
+
+static int debug = 0;
+static int card = 0;
+static int minor = -1;
+static int bttv_id = BTTV_UNKNOWN;
+static unsigned long gpio_mask = 0;
+static unsigned long gpio_enable = 0;
+static unsigned long gpio_lock_mask = 0;
+static unsigned long gpio_xor_mask = 0;
+static unsigned int soft_gap = 0;
+static unsigned char sample_rate = 10;
+
+static unsigned char code_length = 0;
+static unsigned char code_bytes = 1;
+
+#define MAX_BYTES 8
+
+#define SUCCESS 0
+#define LOGHEAD "lirc_gpio (%d): "
+
+/* how many bits GPIO value can be shifted right before processing
+ * it is computed from the value of gpio_mask_parameter
+ */
+static unsigned char gpio_pre_shift = 0;
+
+static int build_key(unsigned long gpio_val, unsigned char codes[MAX_BYTES])
+{
+ unsigned long mask = gpio_mask;
+ unsigned char shift = 0;
+
+ dprintk(LOGHEAD "gpio_val is %lx\n",card,(unsigned long) gpio_val);
+
+ gpio_val ^= gpio_xor_mask;
+
+ if (gpio_lock_mask && (gpio_val & gpio_lock_mask)) {
+ return -EBUSY;
+ }
+
+ switch (bttv_id)
+ {
+ case BTTV_AVERMEDIA98:
+ if (bttv_write_gpio(card, gpio_enable, gpio_enable)) {
+ dprintk(LOGHEAD "cannot write to GPIO\n", card);
+ return -EIO;
+ }
+ if (bttv_read_gpio(card, &gpio_val)) {
+ dprintk(LOGHEAD "cannot read GPIO\n", card);
+ return -EIO;
+ }
+ if (bttv_write_gpio(card, gpio_enable, 0)) {
+ dprintk(LOGHEAD "cannot write to GPIO\n", card);
+ return -EIO;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* extract bits from "raw" GPIO value using gpio_mask */
+ codes[0] = 0;
+ gpio_val >>= gpio_pre_shift;
+ while (mask) {
+ if (mask & 1u) {
+ codes[0] |= (gpio_val & 1u) << shift++;
+ }
+ mask >>= 1;
+ gpio_val >>= 1;
+ }
+
+ dprintk(LOGHEAD "code is %lx\n",card,(unsigned long) codes[0]);
+ switch (bttv_id)
+ {
+ case BTTV_AVERMEDIA:
+ codes[2] = (codes[0]<<2)&0xff;
+ codes[3] = (~codes[2])&0xff;
+ codes[0] = 0x02;
+ codes[1] = 0xFD;
+ break;
+ case BTTV_AVPHONE98:
+ codes[2] = ((codes[0]&(~0x1))<<2)&0xff;
+ codes[3] = (~codes[2])&0xff;
+ if (codes[0]&0x1) {
+ codes[0] = 0xc0;
+ codes[1] = 0x3f;
+ } else {
+ codes[0] = 0x40;
+ codes[1] = 0xbf;
+ }
+ break;
+ case BTTV_AVERMEDIA98:
+ break;
+ default:
+ break;
+ }
+
+ return SUCCESS;
+}
+
+static void poll_me(void)
+{
+ static unsigned long next_time = 0;
+ static unsigned char codes[MAX_BYTES];
+ unsigned long code = 0;
+ unsigned char cur_codes[MAX_BYTES];
+
+ if (bttv_read_gpio(card, &code)) {
+ dprintk(LOGHEAD "cannot read GPIO\n", card);
+ return -EIO;
+ }
+
+ if (build_key(code, cur_codes)) {
+ return -EFAULT;
+ }
+
+ if (soft_gap) {
+ if (!memcmp(codes, cur_codes, code_bytes) &&
+ jiffies < next_time) {
+ return -EAGAIN;
+ }
+ next_time = jiffies + soft_gap;
+ }
+
+ memcpy(codes, cur_codes, code_bytes);
+
+ input_report_key(&gpio_dev, decode_bttv_avermedia(code), 1);
+ input_report_key(&gpio_dev, decode_bttv_avermedia(code), 0);
+ input_sync(&gpio_dev);
+ return 0;
+}
+
+/* main function of the polling thread
+ */
+static int lirc_thread(void *unused)
+{
+ daemonize("bttv_remote_poller");
+ do {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+ poll_me();
+ } while (1);
+ return 0;
+}
+
+int gpio_remote_init(void)
+{
+ int ret;
+ unsigned int mask;
+
+ /* "normalize" gpio_mask
+ * this means shift it right until first bit is set
+ */
+ while (!(gpio_mask & 1u)) {
+ gpio_pre_shift++;
+ gpio_mask >>= 1;
+ }
+
+ if (gpio_enable) {
+ if(bttv_gpio_enable(card, gpio_enable, gpio_enable)) {
+ printk(LOGHEAD "gpio_enable failure\n", minor);
+ return -EIO;
+ }
+ }
+
+ /* translate ms to jiffies */
+ soft_gap = (soft_gap*HZ) / 1000;
+ return 0;
+}
+
+static int __init gpio_init(void)
+{
+ int i;
+ int type,cardid,card_type;
+
+ request_module("bttv");
+
+ if(bttv_get_cardinfo(card,&type,&cardid)==-1) {
+ printk(LOGHEAD "could not get card type\n", minor);
+ }
+ printk(LOGHEAD "card type 0x%x, id 0x%x\n",minor, type, cardid);
+
+ if (type == BTTV_UNKNOWN) {
+ printk(LOGHEAD "cannot detect TV card nr %d!\n",
+ minor, card);
+ return -EBADRQC;
+ }
+ for (card_type = 1;
+ card_type < sizeof(rcv_infos)/sizeof(struct rcv_info);
+ card_type++) {
+ if (rcv_infos[card_type].bttv_id == type &&
+ (rcv_infos[card_type].card_id == 0 ||
+ rcv_infos[card_type].card_id == cardid)) {
+ bttv_id = rcv_infos[card_type].bttv_id;
+ gpio_mask = rcv_infos[card_type].gpio_mask;
+ gpio_enable = rcv_infos[card_type].gpio_enable;
+ gpio_lock_mask = rcv_infos[card_type].gpio_lock_mask;
+ gpio_xor_mask = rcv_infos[card_type].gpio_xor_mask;
+ soft_gap = rcv_infos[card_type].soft_gap;
+ sample_rate = rcv_infos[card_type].sample_rate;
+ code_length = rcv_infos[card_type].code_length;
+ break;
+ }
+ if (type==BTTV_AVPHONE98 && cardid==0x00011461) {
+ bttv_id = BTTV_AVERMEDIA98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x00041461) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x03001461) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (type==BTTV_AVERMEDIA98 && cardid==0x00000000) {
+ bttv_id = BTTV_AVPHONE98;
+ }
+ if (card_type == sizeof(rcv_infos)/sizeof(struct rcv_info)) {
+ printk(LOGHEAD "TV card type %x not supported!\n",
+ minor, type);
+ return -EBADRQC;
+ }
+ }
+
+ if (gpio_remote_init())
+ return -EIO;
+
+ init_input_dev(&gpio_dev);
+
+ for (i=0; i<KEY_MAX; i++)
+ gpio_keycode[i] = i;
+ gpio_dev.evbit[0] = BIT(EV_KEY);
+ gpio_dev.keycode = gpio_keycode;
+ gpio_dev.keycodesize = sizeof(unsigned short);
+ gpio_dev.keycodemax = KEY_MAX;
+
+ for (i = 0; i < 0x78; i++)
+ if (gpio_keycode[i])
+ set_bit(gpio_keycode[i], gpio_dev.keybit);
+
+ gpio_dev.name = gpio_name;
+ gpio_dev.phys = gpio_phys;
+ gpio_dev.id.bustype = BUS_AMIGA;
+ gpio_dev.id.vendor = 0x1234;
+ gpio_dev.id.product = 0x5678;
+ gpio_dev.id.version = 0x90ab;
+
+ input_register_device(&gpio_dev);
+ kernel_thread(lirc_thread, NULL, 0);
+
+ printk(KERN_INFO "input: %s\n", gpio_name);
+ return 0;
+}
+
+static void __exit gpio_exit(void)
+{
+ input_unregister_device(&gpio_dev);
+}
+
+late_initcall(gpio_init);
+module_exit(gpio_exit);

--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 14:47:36

by Herbert Poetzl

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, Aug 11, 2003 at 03:11:07PM +0200, Flameeyes wrote:
> On Mon, 2003-08-11 at 14:47, Pavel Machek wrote:
> > I converted lirc_gpio into input/ layer (and killed support for
> > hardware I do not have; sorry but it was essential to keep code
> > small). Ported driver looks like this; I believe it looks better than
> > old code. Patch is here.
> You can here see the problem... not all tv cards use the same remote,
> the switch doesn't work with my remote for example, so we have 2
> possibilities:
>
> a) hardcode all the possible remotes adding these as new one come up,
> this is a big work in the kernel source, and also we lost compatibility
> with remotes that use the same frequency of the ones with the tv card,
> and that now can be used.
>
> b) create an userspace utility that read the input layer for codes an
> then translates them in user-definable commands. This is what lircd do
> now...

what about

c) hardcode the basic decoding and use a mapping table
which can be configure from userspace ...
(like dvbs haupauge or xmodmap)

best,
Herbert

> IMHO, the solution used now is the more flexible of the two.
> --
> Flameeyes <[email protected]>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2003-08-11 15:42:10

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > > I converted lirc_gpio into input/ layer (and killed support for
> > > hardware I do not have; sorry but it was essential to keep code
> > > small). Ported driver looks like this; I believe it looks better than
> > > old code. Patch is here.
> > You can here see the problem... not all tv cards use the same remote,
> > the switch doesn't work with my remote for example, so we have 2
> > possibilities:
> >
> > a) hardcode all the possible remotes adding these as new one come up,
> > this is a big work in the kernel source, and also we lost compatibility
> > with remotes that use the same frequency of the ones with the tv card,
> > and that now can be used.
> >
> > b) create an userspace utility that read the input layer for codes an
> > then translates them in user-definable commands. This is what lircd do
> > now...
>
> what about
>
> c) hardcode the basic decoding and use a mapping table
> which can be configure from userspace ...
> (like dvbs haupauge or xmodmap)

Acceptable, too; but I'd like remotes to work out-of-the-box, without
any config.

Of course, if you have homemade serial receiver, you should still be
able to use it, but in such case lircd solution is acceptable.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 15:38:51

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > I converted lirc_gpio into input/ layer (and killed support for
> > hardware I do not have; sorry but it was essential to keep code
> > small). Ported driver looks like this; I believe it looks better than
> > old code. Patch is here.
> You can here see the problem... not all tv cards use the same remote,
> the switch doesn't work with my remote for example, so we have 2
> possibilities:
>
> a) hardcode all the possible remotes adding these as new one come up,
> this is a big work in the kernel source, and also we lost compatibility
> with remotes that use the same frequency of the ones with the tv card,
> and that now can be used.

I guess a) is okay. There are not *so* many remote controls out there.

I loose a tiny bit of flexibility: if I take DAV remote that happens
to almost work with bttv, I was able to use most of its keys with
lircd, but kernel module will not permit me to do that.

I guess thats okay; if I want decoder-that-decodes-anything, I need
one that connects to serial port and has non-trivial configuration.

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 15:50:24

by Flameeyes

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, 2003-08-11 at 17:38, Pavel Machek wrote:
> I guess a) is okay. There are not *so* many remote controls out there.
I think more than one per card model. Other Kworld Card have different
remote than mine, as you can see on my homepage, my lircd.conf isn't one
of the ones in lirc remotes list.

> I guess thats okay; if I want decoder-that-decodes-anything, I need
> one that connects to serial port and has non-trivial configuration.
But I can't take a new tv card, plug it into my machine, start up,
configure the remote, and use xine.

Also, from user apps dev view, I think is more difficult to check for
input events knowing that every remote has different buttons, instead of
configure the .lircrc and use lirc_client for receive directly
software-commands.

We can drop /dev/lirc*, and use input events with received codes, but I
think that lircd is still needed to translate them into userland
commands...
--
Flameeyes <[email protected]>

2003-08-11 16:38:50

by Gerd Knorr

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Gna, why the heck the lirc-list archive on sf.net is broken *right
now*? Subscribed for now ...

> We can drop /dev/lirc*, and use input events with received codes, but I
> think that lircd is still needed to translate them into userland
> commands...

That translation isn't done by lircd, but by the lirc_client library.
This is no reason for keeping lircd as event dispatcher, the input layer
would do equally well (with liblirc_client picking up events from
/dev/input/event<x> instead of lircd).

Gerd

--
sigfault

2003-08-11 17:39:32

by Johannes Stezenbach

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Pavel Machek wrote:
>
> > a) hardcode all the possible remotes adding these as new one come up,
> > this is a big work in the kernel source, and also we lost compatibility
> > with remotes that use the same frequency of the ones with the tv card,
> > and that now can be used.
>
> I guess a) is okay. There are not *so* many remote controls out there.

That's not true, unless you just count the remotes that come packaged
with the TV cards. But you might be able to buy all-in-one type
remote controls which work with the TV card's IR receiver (it's also
possible to connect a different IR-sensor to the TV card's IR input).
It would be nice to be able to configure the keys then.

drivers/media/dvb/ttpci/av7110_ir.c does it this way (default map
for Hauppauge, loadable keymaps in linuxtv.org CVS).

Johannes

2003-08-11 17:59:15

by Johannes Stezenbach

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Gerd Knorr wrote:
>
> > We can drop /dev/lirc*, and use input events with received codes, but I
> > think that lircd is still needed to translate them into userland
> > commands...
>
> That translation isn't done by lircd, but by the lirc_client library.
> This is no reason for keeping lircd as event dispatcher, the input layer
> would do equally well (with liblirc_client picking up events from
> /dev/input/event<x> instead of lircd).

IMHO there's one problem:

If a remote control has e.g. a "1" key this doesn't mean that a user
wants a "1" to be written into your editor while editing source code.
The "1" key on a remote control simply has a differnt _meaning_ than
the "1" key on your keyboard -- depending of course on what the user
thinks this key should mean.

- users should be able to prevent remote keys from being fed into
the normal keyboard input queue; non lirc aware programs should
not recieve these events
(OTOH, if you use an IR keyboard...)
- IR events should reach the applications independant of X keyboard
focus (well, maybe; the user should be able to decide)

With the current input subsystem, the only possiblity is lircd
grabbing the remote events with EVIOCGRAB, and passing them
on to the applications.


Johannes

2003-08-11 18:21:50

by Gerd Hoffmann

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

> I converted lirc_gpio into input/ layer (and killed support for
> hardware I do not have; sorry but it was essential to keep code
> small). Ported driver looks like this; I believe it looks better than
> old code. Patch is here.

And IMHO it will be even better if it is linked directly into the bttv
driver and bttv itself registers as input device. All the complicated
probing using the functions exported by bttv will go away. The whole
construct is only needed because lirc isn't part of the standard
kernel ...

Gerd

2003-08-11 18:43:11

by Gerd Hoffmann

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

> c) hardcode the basic decoding and use a mapping table
> which can be configure from userspace ...
> (like dvbs haupauge or xmodmap)

Should be possible using the existing interfaces for keyboard maps,
/dev/input/event<x> even has ioctls for that (EVIOC{GS}KEYCODE).
The dvb folks already do that as far I know.

Gerd

--
sigfault

2003-08-11 19:01:14

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > > a) hardcode all the possible remotes adding these as new one come up,
> > > this is a big work in the kernel source, and also we lost compatibility
> > > with remotes that use the same frequency of the ones with the tv card,
> > > and that now can be used.
> >
> > I guess a) is okay. There are not *so* many remote controls out there.
>
> That's not true, unless you just count the remotes that come packaged
> with the TV cards. But you might be able to buy all-in-one type
> remote controls which work with the TV card's IR receiver (it's also
> possible to connect a different IR-sensor to the TV card's IR input).
> It would be nice to be able to configure the keys then.

Yes, it would be nice, but it should work by default...

> drivers/media/dvb/ttpci/av7110_ir.c does it this way (default map
> for Hauppauge, loadable keymaps in linuxtv.org CVS).

...like this. That driver actually looks pretty nice. I started my
driver with cp amikbd.c, copying av7110_ir would be *way* better.

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 19:02:20

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > I converted lirc_gpio into input/ layer (and killed support for
> > hardware I do not have; sorry but it was essential to keep code
> > small). Ported driver looks like this; I believe it looks better than
> > old code. Patch is here.
>
> And IMHO it will be even better if it is linked directly into the bttv
> driver and bttv itself registers as input device. All the complicated
> probing using the functions exported by bttv will go away. The whole
> construct is only needed because lirc isn't part of the standard
> kernel ...

Yes, that might be even better. I'd like to have ir drivers at one
place, but if theres enough advantage the other way...
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 19:02:19

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, Aug 11, 2003 at 07:56:42PM +0200, Johannes Stezenbach wrote:
> Gerd Knorr wrote:
> >
> > > We can drop /dev/lirc*, and use input events with received codes, but I
> > > think that lircd is still needed to translate them into userland
> > > commands...
> >
> > That translation isn't done by lircd, but by the lirc_client library.
> > This is no reason for keeping lircd as event dispatcher, the input layer
> > would do equally well (with liblirc_client picking up events from
> > /dev/input/event<x> instead of lircd).
>
> IMHO there's one problem:
>
> If a remote control has e.g. a "1" key this doesn't mean that a user
> wants a "1" to be written into your editor while editing source code.
> The "1" key on a remote control simply has a differnt _meaning_ than
> the "1" key on your keyboard -- depending of course on what the user
> thinks this key should mean.

That's what BTN_1 is for. ;)

> - users should be able to prevent remote keys from being fed into
> the normal keyboard input queue; non lirc aware programs should
> not recieve these events
> (OTOH, if you use an IR keyboard...)

Yes, the console needs to be configurable in that respect. Its something
that needs to be fixed.

> - IR events should reach the applications independant of X keyboard
> focus (well, maybe; the user should be able to decide)
>
> With the current input subsystem, the only possiblity is lircd
> grabbing the remote events with EVIOCGRAB, and passing them
> on to the applications.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-08-11 19:21:02

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > > > We can drop /dev/lirc*, and use input events with received codes, but I
> > > > think that lircd is still needed to translate them into userland
> > > > commands...
> > >
> > > That translation isn't done by lircd, but by the lirc_client library.
> > > This is no reason for keeping lircd as event dispatcher, the input layer
> > > would do equally well (with liblirc_client picking up events from
> > > /dev/input/event<x> instead of lircd).
> >
> > IMHO there's one problem:
> >
> > If a remote control has e.g. a "1" key this doesn't mean that a user
> > wants a "1" to be written into your editor while editing source code.
> > The "1" key on a remote control simply has a differnt _meaning_ than
> > the "1" key on your keyboard -- depending of course on what the user
> > thinks this key should mean.
>
> That's what BTN_1 is for. ;)

Ahha, I thought BTN_1 would be first mouse button ;-). Will fix that.

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 18:59:08

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > > We can drop /dev/lirc*, and use input events with received codes, but I
> > > think that lircd is still needed to translate them into userland
> > > commands...
> >
> > That translation isn't done by lircd, but by the lirc_client library.
> > This is no reason for keeping lircd as event dispatcher, the input layer
> > would do equally well (with liblirc_client picking up events from
> > /dev/input/event<x> instead of lircd).
>
> IMHO there's one problem:
>
> If a remote control has e.g. a "1" key this doesn't mean that a user
> wants a "1" to be written into your editor while editing source code.
> The "1" key on a remote control simply has a differnt _meaning_ than
> the "1" key on your keyboard -- depending of course on what the user
> thinks this key should mean.

That only means that the key on remote should be labeled
"KEY_PROGRAM1" not "KEY_1".

> - users should be able to prevent remote keys from being fed into
> the normal keyboard input queue; non lirc aware programs should
> not recieve these events
> (OTOH, if you use an IR keyboard...)

This is same as multimedia keys on PS/2 keyboards.

> - IR events should reach the applications independant of X keyboard
> focus (well, maybe; the user should be able to decide)

Again this is the same as multimedia keys on PS/2 keyboards. It may
need to be solved, but we'd have to solve that anyway.

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 19:25:46

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > If a remote control has e.g. a "1" key this doesn't mean that a user
> > wants a "1" to be written into your editor while editing source code.
> > The "1" key on a remote control simply has a differnt _meaning_ than
> > the "1" key on your keyboard -- depending of course on what the user
> > thinks this key should mean.
>
> That's what BTN_1 is for. ;)

Perhaps comment about this should be added to input.h?

--- clean/include/linux/input.h 2003-06-24 12:28:05.000000000 +0200
+++ linux/include/linux/input.h 2003-08-11 21:17:46.000000000 +0200
@@ -338,6 +338,7 @@

#define KEY_UNKNOWN 240

+/* This is for keys 0..9 on remote control etc. */
#define BTN_MISC 0x100
#define BTN_0 0x100
#define BTN_1 0x101


I still miss few descriptions... On avermedia remote control there are
buttons labeled as "preview", "autoscan", "freeze", "capture" and few
keys without label (5 of them :-(). I mapped that somehow, but it
might not be ideal:

case 0xc577c0: return KEY_EJECTCD; /* Unmarked on my controller */
case 0xd77c0: return KEY_INFO; /* preview */
case 0xad77c0: return KEY_SEARCH; /* autoscan */
case 0x6d77c0: return KEY_BREAK; /* freeze */
case 0xed77c0: return KEY_PVR; /* capture */

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 19:37:27

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, Aug 11, 2003 at 09:17:10PM +0200, Pavel Machek wrote:

> > > > > We can drop /dev/lirc*, and use input events with received codes, but I
> > > > > think that lircd is still needed to translate them into userland
> > > > > commands...
> > > >
> > > > That translation isn't done by lircd, but by the lirc_client library.
> > > > This is no reason for keeping lircd as event dispatcher, the input layer
> > > > would do equally well (with liblirc_client picking up events from
> > > > /dev/input/event<x> instead of lircd).
> > >
> > > IMHO there's one problem:
> > >
> > > If a remote control has e.g. a "1" key this doesn't mean that a user
> > > wants a "1" to be written into your editor while editing source code.
> > > The "1" key on a remote control simply has a differnt _meaning_ than
> > > the "1" key on your keyboard -- depending of course on what the user
> > > thinks this key should mean.
> >
> > That's what BTN_1 is for. ;)
>
> Ahha, I thought BTN_1 would be first mouse button ;-). Will fix that.

No, that'd be BTN_LEFT.

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-08-11 19:33:44

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > I guess a) is okay. There are not *so* many remote controls out there.
> I think more than one per card model. Other Kworld Card have different
> remote than mine, as you can see on my homepage, my lircd.conf isn't one
> of the ones in lirc remotes list.
>
> > I guess thats okay; if I want decoder-that-decodes-anything, I need
> > one that connects to serial port and has non-trivial configuration.
> But I can't take a new tv card, plug it into my machine, start up,
> configure the remote, and use xine.

I actually want to "Take a new tv card, plug it into machine, start
up, use xine", without configuring remote ;-).

> Also, from user apps dev view, I think is more difficult to check for
> input events knowing that every remote has different buttons, instead of
> configure the .lircrc and use lirc_client for receive directly
> software-commands.

I think the right way is for application to just use buttons it knows
about. We already have some multimedia buttons on keyboard and some
more on remote...

> We can drop /dev/lirc*, and use input events with received codes, but I
> think that lircd is still needed to translate them into userland
> commands...

I believe we should be able to make it work without lircd, but input
events with received codes is still better than current situation.

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 19:42:11

by Gerd Hoffmann

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, Aug 11, 2003 at 08:59:14PM +0200, Pavel Machek wrote:
> Hi!
>
> Yes, that might be even better. I'd like to have ir drivers at one
> place, but if theres enough advantage the other way...

Yes, there is: I can just put the IR info into the card database.
The poll thread can go away, instead I can hook gpio readouts into the
IRQ handler. Probing is just one or two lines in bttv-cards.c, ...

I'll have a look at this tomorrow.

Gerd

--
sigfault

2003-08-11 19:57:06

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > > > IMHO there's one problem:
> > > >
> > > > If a remote control has e.g. a "1" key this doesn't mean that a user
> > > > wants a "1" to be written into your editor while editing source code.
> > > > The "1" key on a remote control simply has a differnt _meaning_ than
> > > > the "1" key on your keyboard -- depending of course on what the user
> > > > thinks this key should mean.
> > >
> > > That's what BTN_1 is for. ;)
> >
> > Ahha, I thought BTN_1 would be first mouse button ;-). Will fix that.
>
> No, that'd be BTN_LEFT.

Okay, then what about this:

The control has keypad labeled 0..9 and at the same time it has arrows
on it (its meant for mouse emulation). Then it has keys DISPLAY/L, and
LOOP/R. If I mark DISPLAY/L as BTN_LEFT, will it be the "right thing"
(tm)?

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 20:05:38

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

Hi!

> > Yes, that might be even better. I'd like to have ir drivers at one
> > place, but if theres enough advantage the other way...
>
> Yes, there is: I can just put the IR info into the card database.
> The poll thread can go away, instead I can hook gpio readouts into the
> IRQ handler. Probing is just one or two lines in bttv-cards.c, ...

Well, that looks really nice!

Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]

2003-08-11 19:59:36

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, 11 Aug 2003 21:34:01 +0200, Vojtech Pavlik said:
> On Mon, Aug 11, 2003 at 09:17:10PM +0200, Pavel Machek wrote:
> > Ahha, I thought BTN_1 would be first mouse button ;-). Will fix that.
> No, that'd be BTN_LEFT.

Urp. My mouse has 7 buttons (ok, 5, one of which is a scrollwheel and
generates 3 different events). Which left button do you mean? ;)

http://www.microsoft.com/catalog/display.asp?subid=22&site=10561

Fortunately for the coders, it doesn't come in a wireless version yet. ;)


Attachments:
(No filename) (226.00 B)

2003-08-11 20:01:01

by Flameeyes

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, 2003-08-11 at 20:52, Pavel Machek wrote:
> I actually want to "Take a new tv card, plug it into machine, start
> up, use xine", without configuring remote ;-).
Flexibility or easy to use?
We can make a compromise: add some "default" configurations to the
software, so after it's installed, we can probably use our remote
correctly, but permit to anyone to change them.
Building them directly into the kernel deny you to do the thing you
said, I know that some cards with the same name of mine uses another
remote, if we check in the kernel the remote to use for this card, half
of these are unusable.
We must be able to change the method they use...
For example I use 1...9 buttons of my remote in xine as dvd-menu
selectors up/down left/right...

> I think the right way is for application to just use buttons it knows
> about. We already have some multimedia buttons on keyboard and some
> more on remote...
This make the rely to the hardware, and I think an userspace application
(say: a radio card software) that rely on multimedia keyboards need to
know every button of these.
Also, my ps2 keyboard has some extra buttons, but they're broken in the
2.5/2.6 kernel series.

> I believe we should be able to make it work without lircd, but input
> events with received codes is still better than current situation.
sincerely, I think about this after my first try to port lirc to 2.5,
because I wasn't able to compile lircd daemon, but I didn't [don't] know
the kernel as well as it's needed to change this.


Please also note that right now a lot of applications uses lirc_client
library, or have plugins for lirc (installed on my system, for example,
xmms, xine, xawdecode, zapping), lost this compatibility is a big
problem.
--
Flameeyes <[email protected]>

2003-08-11 20:13:53

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, Aug 11, 2003 at 03:59:29PM -0400, [email protected] wrote:

> On Mon, 11 Aug 2003 21:34:01 +0200, Vojtech Pavlik said:
> > On Mon, Aug 11, 2003 at 09:17:10PM +0200, Pavel Machek wrote:
> > > Ahha, I thought BTN_1 would be first mouse button ;-). Will fix that.
> > No, that'd be BTN_LEFT.
>
> Urp. My mouse has 7 buttons (ok, 5, one of which is a scrollwheel and
> generates 3 different events). Which left button do you mean? ;)

For mouse, there is BTN_LEFT, BTN_RIGHT, BTN_MIDDLE (the three original
buttons) and BTN_SIDE and BTN_EXTRA for two more (your five). Then there
is REL_WHEEL and REL_HWHEEL for two scrollwheels on it. Satisfied?

> http://www.microsoft.com/catalog/display.asp?subid=22&site=10561
> Fortunately for the coders, it doesn't come in a wireless version yet. ;)

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-08-14 15:22:56

by Dennis Björklund

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Mon, 11 Aug 2003, Gerd Knorr wrote:

> This is no reason for keeping lircd as event dispatcher, the input layer
> would do equally well (with liblirc_client picking up events from
> /dev/input/event<x> instead of lircd).

Would this allow you to have one reciever and different remote controles
(used for different programs in the end)?

You don't want both remotes map button 1 to the same BTN_1 or whatever
symbol is used.

--
/Dennis

2003-08-14 16:05:47

by Gerd Knorr

[permalink] [raw]
Subject: Re: [PATCH] lirc for 2.5/2.6 kernels - 20030802

On Thu, Aug 14, 2003 at 05:22:27PM +0200, Dennis Bj?rklund wrote:
> On Mon, 11 Aug 2003, Gerd Knorr wrote:
>
> Would this allow you to have one reciever and different remote controles
> (used for different programs in the end)?

If the two remote controls send different codes it should be possible to
map them to different "keys" and disturgish them that way.

Gerd

--
sigfault